]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-for-linus-2.6
authorLinus Torvalds <torvalds@g5.osdl.org>
Thu, 8 Sep 2005 00:31:27 +0000 (17:31 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Thu, 8 Sep 2005 00:31:27 +0000 (17:31 -0700)
2893 files changed:
Documentation/DocBook/mcabook.tmpl
Documentation/IPMI.txt
Documentation/RCU/NMI-RCU.txt [new file with mode: 0644]
Documentation/cdrom/sonycd535
Documentation/cpusets.txt
Documentation/crypto/api-intro.txt
Documentation/dcdbas.txt [new file with mode: 0644]
Documentation/dell_rbu.txt [new file with mode: 0644]
Documentation/dvb/bt8xx.txt
Documentation/exception.txt
Documentation/feature-removal-schedule.txt
Documentation/filesystems/proc.txt
Documentation/filesystems/relayfs.txt [new file with mode: 0644]
Documentation/filesystems/sysfs.txt
Documentation/hwmon/lm78
Documentation/hwmon/w83792d [new file with mode: 0644]
Documentation/i2c/chips/max6875
Documentation/i2c/functionality
Documentation/i2c/porting-clients
Documentation/i2c/writing-clients
Documentation/i386/boot.txt
Documentation/kbuild/makefiles.txt
Documentation/kernel-parameters.txt
Documentation/networking/README.ipw2100 [new file with mode: 0644]
Documentation/networking/README.ipw2200 [new file with mode: 0644]
Documentation/networking/cxgb.txt [new file with mode: 0644]
Documentation/networking/phy.txt [new file with mode: 0644]
Documentation/power/swsusp-dmcrypt.txt [new file with mode: 0644]
Documentation/power/swsusp.txt
Documentation/power/video.txt
Documentation/serial/driver
Documentation/sonypi.txt
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
Documentation/vm/locking
Documentation/watchdog/watchdog-api.txt
MAINTAINERS
Makefile
arch/alpha/Kconfig
arch/alpha/kernel/signal.c
arch/alpha/kernel/time.c
arch/arm/Kconfig
arch/arm/boot/compressed/head-sharpsl.S
arch/arm/common/Kconfig
arch/arm/common/Makefile
arch/arm/common/gic.c [new file with mode: 0644]
arch/arm/common/locomo.c
arch/arm/common/sa1111.c
arch/arm/common/scoop.c
arch/arm/configs/omap_h2_1610_defconfig
arch/arm/kernel/calls.S
arch/arm/kernel/ecard.c
arch/arm/kernel/entry-common.S
arch/arm/kernel/irq.c
arch/arm/kernel/signal.c
arch/arm/kernel/smp.c
arch/arm/kernel/sys_arm.c
arch/arm/kernel/time.c
arch/arm/mach-footbridge/Kconfig
arch/arm/mach-footbridge/isa-irq.c
arch/arm/mach-h720x/common.c
arch/arm/mach-h720x/cpu-h7202.c
arch/arm/mach-imx/irq.c
arch/arm/mach-integrator/integrator_cp.c
arch/arm/mach-iop3xx/iop321-time.c
arch/arm/mach-iop3xx/iop331-time.c
arch/arm/mach-ixp2000/core.c
arch/arm/mach-ixp2000/ixdp2x00.c
arch/arm/mach-ixp2000/ixdp2x01.c
arch/arm/mach-ixp4xx/common.c
arch/arm/mach-ixp4xx/coyote-pci.c
arch/arm/mach-ixp4xx/coyote-setup.c
arch/arm/mach-ixp4xx/gtwx5715-pci.c
arch/arm/mach-ixp4xx/gtwx5715-setup.c
arch/arm/mach-ixp4xx/ixdp425-pci.c
arch/arm/mach-ixp4xx/ixdp425-setup.c
arch/arm/mach-ixp4xx/ixdpg425-pci.c
arch/arm/mach-lh7a40x/common.h
arch/arm/mach-omap1/fpga.c
arch/arm/mach-omap1/irq.c
arch/arm/mach-pxa/Makefile
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/corgi_lcd.c [new file with mode: 0644]
arch/arm/mach-pxa/irq.c
arch/arm/mach-pxa/lubbock.c
arch/arm/mach-pxa/mainstone.c
arch/arm/mach-pxa/poodle.c
arch/arm/mach-pxa/time.c
arch/arm/mach-s3c2410/Kconfig
arch/arm/mach-s3c2410/Makefile
arch/arm/mach-s3c2410/bast-irq.c
arch/arm/mach-s3c2410/clock.c
arch/arm/mach-s3c2410/irq.c
arch/arm/mach-s3c2410/mach-anubis.c [new file with mode: 0644]
arch/arm/mach-s3c2410/mach-n30.c
arch/arm/mach-s3c2410/pm-simtec.c
arch/arm/mach-s3c2410/pm.c
arch/arm/mach-s3c2410/s3c2440-clock.c
arch/arm/mach-s3c2410/s3c2440-irq.c
arch/arm/mach-s3c2410/time.c
arch/arm/mach-sa1100/assabet.c
arch/arm/mach-sa1100/cerf.c
arch/arm/mach-sa1100/generic.c
arch/arm/mach-sa1100/generic.h
arch/arm/mach-sa1100/irq.c
arch/arm/mach-sa1100/lart.c
arch/arm/mach-sa1100/neponset.c
arch/arm/mach-sa1100/shannon.c
arch/arm/mach-sa1100/simpad.c
arch/arm/mach-sa1100/time.c
arch/arm/mach-versatile/core.c
arch/arm/mm/alignment.c
arch/arm/mm/mm-armv.c
arch/arm/mm/proc-arm6_7.S
arch/arm/plat-omap/Kconfig
arch/arm/plat-omap/Makefile
arch/arm/plat-omap/clock.c
arch/arm/plat-omap/common.c
arch/arm/plat-omap/dma.c
arch/arm/plat-omap/dmtimer.c [new file with mode: 0644]
arch/arm/plat-omap/gpio.c
arch/arm/plat-omap/mcbsp.c
arch/arm/plat-omap/mux.c
arch/arm/plat-omap/ocpi.c
arch/arm/plat-omap/pm.c
arch/arm/plat-omap/sleep.S
arch/arm/plat-omap/sram-fn.S [new file with mode: 0644]
arch/arm/plat-omap/sram.c [new file with mode: 0644]
arch/arm/plat-omap/sram.h [new file with mode: 0644]
arch/arm/plat-omap/usb.c
arch/arm26/Kconfig
arch/arm26/Makefile
arch/arm26/kernel/signal.c
arch/arm26/kernel/time.c
arch/cris/Kconfig.debug
arch/cris/arch-v10/kernel/signal.c
arch/cris/arch-v10/kernel/time.c
arch/cris/arch-v32/kernel/signal.c
arch/cris/kernel/time.c
arch/frv/kernel/frv_ksyms.c
arch/frv/kernel/signal.c
arch/frv/kernel/time.c
arch/h8300/kernel/signal.c
arch/h8300/kernel/time.c
arch/i386/Kconfig
arch/i386/boot/setup.S
arch/i386/boot/tools/build.c
arch/i386/kernel/Makefile
arch/i386/kernel/acpi/boot.c
arch/i386/kernel/cpu/common.c
arch/i386/kernel/cpu/cpufreq/longhaul.c
arch/i386/kernel/cpu/cyrix.c
arch/i386/kernel/cpu/intel.c
arch/i386/kernel/cpu/intel_cacheinfo.c
arch/i386/kernel/cpu/mtrr/main.c
arch/i386/kernel/crash.c
arch/i386/kernel/dmi_scan.c
arch/i386/kernel/doublefault.c
arch/i386/kernel/efi.c
arch/i386/kernel/entry.S
arch/i386/kernel/head.S
arch/i386/kernel/i8237.c [new file with mode: 0644]
arch/i386/kernel/io_apic.c
arch/i386/kernel/ioport.c
arch/i386/kernel/kprobes.c
arch/i386/kernel/ldt.c
arch/i386/kernel/machine_kexec.c
arch/i386/kernel/microcode.c
arch/i386/kernel/mpparse.c
arch/i386/kernel/msr.c
arch/i386/kernel/nmi.c
arch/i386/kernel/process.c
arch/i386/kernel/ptrace.c
arch/i386/kernel/reboot.c
arch/i386/kernel/semaphore.c
arch/i386/kernel/setup.c
arch/i386/kernel/signal.c
arch/i386/kernel/smp.c
arch/i386/kernel/smpboot.c
arch/i386/kernel/time.c
arch/i386/kernel/timers/timer_hpet.c
arch/i386/kernel/timers/timer_pit.c
arch/i386/kernel/timers/timer_pm.c
arch/i386/kernel/timers/timer_tsc.c
arch/i386/kernel/traps.c
arch/i386/kernel/vm86.c
arch/i386/kernel/vmlinux.lds.S
arch/i386/kernel/vsyscall-sigreturn.S
arch/i386/mach-default/topology.c
arch/i386/mach-es7000/es7000.h
arch/i386/mach-es7000/es7000plat.c
arch/i386/mach-generic/bigsmp.c
arch/i386/mach-generic/probe.c
arch/i386/mach-voyager/voyager_basic.c
arch/i386/mach-voyager/voyager_smp.c
arch/i386/math-emu/get_address.c
arch/i386/mm/discontig.c
arch/i386/mm/fault.c
arch/i386/mm/hugetlbpage.c
arch/i386/mm/init.c
arch/i386/mm/pageattr.c
arch/i386/mm/pgtable.c
arch/i386/oprofile/init.c
arch/i386/oprofile/nmi_int.c
arch/i386/oprofile/nmi_timer_int.c
arch/i386/pci/common.c
arch/i386/pci/i386.c
arch/i386/power/cpu.c
arch/ia64/Kconfig
arch/ia64/hp/sim/boot/fw-emu.c
arch/ia64/hp/sim/simserial.c
arch/ia64/ia32/ia32_entry.S
arch/ia64/ia32/ia32_signal.c
arch/ia64/ia32/sys_ia32.c
arch/ia64/kernel/Makefile
arch/ia64/kernel/cpufreq/Kconfig [new file with mode: 0644]
arch/ia64/kernel/cpufreq/Makefile [new file with mode: 0644]
arch/ia64/kernel/cpufreq/acpi-cpufreq.c [new file with mode: 0644]
arch/ia64/kernel/domain.c [deleted file]
arch/ia64/kernel/irq.c
arch/ia64/kernel/jprobes.S
arch/ia64/kernel/kprobes.c
arch/ia64/kernel/signal.c
arch/ia64/kernel/sys_ia64.c
arch/ia64/kernel/traps.c
arch/ia64/kernel/uncached.c
arch/ia64/kernel/vmlinux.lds.S
arch/ia64/lib/Makefile
arch/ia64/lib/flush.S
arch/ia64/lib/swiotlb.c
arch/ia64/mm/fault.c
arch/ia64/mm/hugetlbpage.c
arch/ia64/pci/pci.c
arch/ia64/sn/include/tio.h
arch/ia64/sn/include/xtalk/hubdev.h
arch/ia64/sn/kernel/bte.c
arch/ia64/sn/kernel/huberror.c
arch/ia64/sn/kernel/io_init.c
arch/ia64/sn/kernel/irq.c
arch/ia64/sn/kernel/setup.c
arch/ia64/sn/kernel/sn2/ptc_deadlock.S
arch/ia64/sn/kernel/sn2/sn2_smp.c
arch/ia64/sn/kernel/sn2/sn_hwperf.c
arch/ia64/sn/kernel/sn2/sn_proc_fs.c
arch/ia64/sn/kernel/sn2/timer_interrupt.c
arch/ia64/sn/kernel/tiocx.c
arch/ia64/sn/pci/Makefile
arch/ia64/sn/pci/pcibr/pcibr_dma.c
arch/ia64/sn/pci/pcibr/pcibr_provider.c
arch/ia64/sn/pci/tioca_provider.c
arch/ia64/sn/pci/tioce_provider.c [new file with mode: 0644]
arch/m32r/kernel/signal.c
arch/m32r/kernel/time.c
arch/m68k/Kconfig
arch/m68k/bvme6000/rtc.c
arch/m68k/kernel/m68k_ksyms.c
arch/m68k/kernel/ptrace.c
arch/m68k/kernel/time.c
arch/m68k/lib/Makefile
arch/m68k/lib/memcmp.c [deleted file]
arch/m68k/lib/memcpy.c [deleted file]
arch/m68k/lib/memset.c [deleted file]
arch/m68k/lib/string.c [new file with mode: 0644]
arch/m68k/mm/Makefile
arch/m68k/mm/cache.c [new file with mode: 0644]
arch/m68k/mm/memory.c
arch/m68k/mvme16x/rtc.c
arch/m68knommu/Kconfig
arch/m68knommu/Makefile
arch/m68knommu/defconfig
arch/m68knommu/kernel/setup.c
arch/m68knommu/kernel/signal.c
arch/m68knommu/kernel/time.c
arch/m68knommu/kernel/traps.c
arch/m68knommu/kernel/vmlinux.lds.S
arch/m68knommu/platform/523x/config.c [new file with mode: 0644]
arch/m68knommu/platform/5307/head.S
arch/m68knommu/platform/68328/entry.S
arch/m68knommu/platform/68360/entry.S
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/au1000/common/pci.c
arch/mips/au1000/common/setup.c
arch/mips/au1000/common/time.c
arch/mips/au1000/csb250/board_setup.c
arch/mips/au1000/csb250/init.c
arch/mips/au1000/db1x00/init.c
arch/mips/au1000/hydrogen3/init.c
arch/mips/au1000/pb1000/board_setup.c
arch/mips/au1000/xxs1500/board_setup.c
arch/mips/au1000/xxs1500/init.c
arch/mips/au1000/xxs1500/irqmap.c
arch/mips/configs/atlas_defconfig
arch/mips/configs/capcella_defconfig
arch/mips/configs/cobalt_defconfig
arch/mips/configs/db1000_defconfig
arch/mips/configs/db1100_defconfig
arch/mips/configs/db1500_defconfig
arch/mips/configs/db1550_defconfig
arch/mips/configs/ddb5476_defconfig
arch/mips/configs/ddb5477_defconfig
arch/mips/configs/decstation_defconfig
arch/mips/configs/e55_defconfig
arch/mips/configs/ev64120_defconfig
arch/mips/configs/ev96100_defconfig
arch/mips/configs/ip22_defconfig
arch/mips/configs/ip27_defconfig
arch/mips/configs/ip32_defconfig
arch/mips/configs/it8172_defconfig
arch/mips/configs/ivr_defconfig
arch/mips/configs/jaguar-atx_defconfig
arch/mips/configs/jmr3927_defconfig
arch/mips/configs/lasat200_defconfig
arch/mips/configs/malta_defconfig
arch/mips/configs/mpc30x_defconfig
arch/mips/configs/ocelot_3_defconfig
arch/mips/configs/ocelot_c_defconfig
arch/mips/configs/ocelot_defconfig
arch/mips/configs/ocelot_g_defconfig
arch/mips/configs/pb1100_defconfig
arch/mips/configs/pb1500_defconfig
arch/mips/configs/pb1550_defconfig
arch/mips/configs/qemu_defconfig [moved from arch/mips/configs/osprey_defconfig with 66% similarity]
arch/mips/configs/rm200_defconfig
arch/mips/configs/sb1250-swarm_defconfig
arch/mips/configs/sead_defconfig
arch/mips/configs/tb0226_defconfig
arch/mips/configs/tb0229_defconfig
arch/mips/configs/workpad_defconfig
arch/mips/configs/yosemite_defconfig
arch/mips/ddb5xxx/ddb5477/irq.c
arch/mips/ddb5xxx/ddb5477/setup.c
arch/mips/dec/ecc-berr.c
arch/mips/dec/int-handler.S
arch/mips/dec/prom/Makefile
arch/mips/defconfig
arch/mips/ite-boards/generic/it8172_setup.c
arch/mips/ite-boards/generic/time.c
arch/mips/kernel/Makefile
arch/mips/kernel/binfmt_elfn32.c
arch/mips/kernel/binfmt_elfo32.c
arch/mips/kernel/cpu-bugs64.c
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/gdb-low.S
arch/mips/kernel/gdb-stub.c
arch/mips/kernel/genex.S
arch/mips/kernel/head.S
arch/mips/kernel/ioctl32.c
arch/mips/kernel/irixsig.c
arch/mips/kernel/irq.c
arch/mips/kernel/linux32.c
arch/mips/kernel/mips_ksyms.c
arch/mips/kernel/process.c
arch/mips/kernel/ptrace.c
arch/mips/kernel/r2300_switch.S
arch/mips/kernel/r4k_fpu.S
arch/mips/kernel/r4k_switch.S
arch/mips/kernel/setup.c
arch/mips/kernel/signal.c
arch/mips/kernel/signal32.c
arch/mips/kernel/sysirix.c
arch/mips/kernel/time.c
arch/mips/kernel/traps.c
arch/mips/kernel/unaligned.c
arch/mips/kernel/vmlinux.lds.S
arch/mips/lasat/at93c.c
arch/mips/lasat/at93c.h
arch/mips/lasat/ds1603.c
arch/mips/lasat/ds1603.h
arch/mips/lasat/image/Makefile
arch/mips/lasat/image/head.S
arch/mips/lasat/interrupt.c
arch/mips/lasat/lasat_board.c
arch/mips/lasat/picvue.c
arch/mips/lasat/picvue.h
arch/mips/lasat/picvue_proc.c
arch/mips/lasat/prom.c
arch/mips/lasat/reset.c
arch/mips/lasat/setup.c
arch/mips/lasat/sysctl.c
arch/mips/lib-32/Makefile
arch/mips/lib-64/Makefile
arch/mips/lib/memcpy.S
arch/mips/math-emu/cp1emu.c
arch/mips/math-emu/kernel_linkage.c
arch/mips/mips-boards/atlas/atlas_int.c
arch/mips/mips-boards/generic/init.c
arch/mips/mips-boards/generic/time.c
arch/mips/mips-boards/malta/malta_setup.c
arch/mips/mm/Makefile
arch/mips/mm/c-r4k.c
arch/mips/mm/c-sb1.c
arch/mips/mm/cerr-sb1.c
arch/mips/mm/dma-noncoherent.c
arch/mips/mm/init.c
arch/mips/mm/pg-sb1.c
arch/mips/mm/tlbex.c
arch/mips/momentum/jaguar_atx/int-handler.S
arch/mips/momentum/jaguar_atx/prom.c
arch/mips/momentum/jaguar_atx/reset.c
arch/mips/momentum/jaguar_atx/setup.c
arch/mips/momentum/ocelot_3/prom.c
arch/mips/momentum/ocelot_c/int-handler.S
arch/mips/momentum/ocelot_c/ocelot_c_fpga.h
arch/mips/momentum/ocelot_c/prom.c
arch/mips/momentum/ocelot_c/reset.c
arch/mips/momentum/ocelot_c/setup.c
arch/mips/pci/fixup-ddb5074.c
arch/mips/pci/fixup-ddb5477.c
arch/mips/pci/fixup-malta.c
arch/mips/pci/fixup-rbtx4927.c
arch/mips/pci/fixup-sni.c
arch/mips/pci/fixup-tb0219.c
arch/mips/pci/ops-ddb5477.c
arch/mips/pci/ops-tx4927.c
arch/mips/pci/pci-ddb5477.c
arch/mips/pci/pci-ip32.c
arch/mips/pci/pci.c
arch/mips/pmc-sierra/yosemite/atmel_read_eeprom.c
arch/mips/pmc-sierra/yosemite/atmel_read_eeprom.h
arch/mips/qemu/Makefile [new file with mode: 0644]
arch/mips/qemu/q-firmware.c [new file with mode: 0644]
arch/mips/qemu/q-int.S [new file with mode: 0644]
arch/mips/qemu/q-irq.c [new file with mode: 0644]
arch/mips/qemu/q-mem.c [new file with mode: 0644]
arch/mips/qemu/q-setup.c [new file with mode: 0644]
arch/mips/sgi-ip22/ip22-eisa.c
arch/mips/sgi-ip22/ip22-hpc.c
arch/mips/sgi-ip22/ip22-int.c
arch/mips/sgi-ip22/ip22-nvram.c
arch/mips/sgi-ip22/ip22-reset.c
arch/mips/sgi-ip22/ip22-time.c
arch/mips/sgi-ip27/ip27-memory.c
arch/mips/sgi-ip27/ip27-timer.c
arch/mips/sgi-ip32/ip32-reset.c
arch/mips/sibyte/cfe/cfe_error.h
arch/mips/sibyte/cfe/console.c
arch/mips/sibyte/cfe/setup.c
arch/mips/sibyte/cfe/smp.c
arch/mips/sibyte/sb1250/bus_watcher.c
arch/mips/sibyte/sb1250/irq.c
arch/mips/sibyte/swarm/rtc_m41t81.c
arch/mips/sibyte/swarm/setup.c
arch/mips/sni/irq.c
arch/mips/sni/setup.c
arch/mips/tx4927/common/tx4927_irq_handler.S
arch/mips/tx4927/common/tx4927_setup.c
arch/mips/tx4927/toshiba_rbtx4927/Makefile
arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
arch/mips/vr4181/common/Makefile [deleted file]
arch/mips/vr4181/common/int_handler.S [deleted file]
arch/mips/vr4181/common/irq.c [deleted file]
arch/mips/vr4181/common/serial.c [deleted file]
arch/mips/vr4181/common/time.c [deleted file]
arch/mips/vr4181/osprey/Makefile [deleted file]
arch/mips/vr4181/osprey/dbg_io.c [deleted file]
arch/mips/vr4181/osprey/prom.c [deleted file]
arch/mips/vr4181/osprey/reset.c [deleted file]
arch/mips/vr4181/osprey/setup.c [deleted file]
arch/mips/vr41xx/casio-e55/setup.c
arch/mips/vr41xx/common/Makefile
arch/mips/vr41xx/common/icu.c
arch/mips/vr41xx/common/int-handler.S
arch/mips/vr41xx/common/irq.c [new file with mode: 0644]
arch/mips/vr41xx/common/type.c [moved from arch/mips/vr41xx/tanbac-tb0226/setup.c with 85% similarity]
arch/mips/vr41xx/common/vrc4173.c
arch/mips/vr41xx/ibm-workpad/setup.c
arch/mips/vr41xx/nec-cmbvr4133/init.c
arch/mips/vr41xx/tanbac-tb0226/Makefile [deleted file]
arch/mips/vr41xx/tanbac-tb0229/Makefile [deleted file]
arch/mips/vr41xx/tanbac-tb0229/setup.c [deleted file]
arch/mips/vr41xx/victor-mpc30x/Makefile [deleted file]
arch/mips/vr41xx/victor-mpc30x/setup.c [deleted file]
arch/mips/vr41xx/zao-capcella/Makefile [deleted file]
arch/mips/vr41xx/zao-capcella/setup.c [deleted file]
arch/parisc/Kconfig
arch/parisc/kernel/signal.c
arch/parisc/kernel/time.c
arch/ppc/Kconfig
arch/ppc/Kconfig.debug
arch/ppc/Makefile
arch/ppc/boot/simple/Makefile
arch/ppc/boot/simple/embed_config.c
arch/ppc/boot/simple/head.S
arch/ppc/boot/simple/misc-cpci690.c
arch/ppc/boot/simple/misc-ev64360.c [new file with mode: 0644]
arch/ppc/boot/simple/misc-katana.c
arch/ppc/boot/simple/misc-mv64x60.c
arch/ppc/boot/simple/mv64x60_tty.c
arch/ppc/boot/utils/addRamDisk.c [deleted file]
arch/ppc/configs/SM850_defconfig [deleted file]
arch/ppc/configs/SPD823TS_defconfig [deleted file]
arch/ppc/configs/adir_defconfig [deleted file]
arch/ppc/configs/ash_defconfig [deleted file]
arch/ppc/configs/beech_defconfig [deleted file]
arch/ppc/configs/cedar_defconfig [deleted file]
arch/ppc/configs/cpci690_defconfig
arch/ppc/configs/ev64360_defconfig [moved from arch/ppc/configs/k2_defconfig with 53% similarity]
arch/ppc/configs/katana_defconfig
arch/ppc/configs/mcpn765_defconfig [deleted file]
arch/ppc/configs/menf1_defconfig [deleted file]
arch/ppc/configs/mpc8560_ads_defconfig
arch/ppc/configs/oak_defconfig [deleted file]
arch/ppc/configs/pcore_defconfig [deleted file]
arch/ppc/configs/rainier_defconfig [deleted file]
arch/ppc/configs/redwood_defconfig [deleted file]
arch/ppc/kernel/cpu_setup_6xx.S
arch/ppc/kernel/cputable.c
arch/ppc/kernel/find_name.c [deleted file]
arch/ppc/kernel/head_44x.S
arch/ppc/kernel/head_4xx.S
arch/ppc/kernel/head_fsl_booke.S
arch/ppc/kernel/l2cr.S
arch/ppc/kernel/ppc_ksyms.c
arch/ppc/kernel/setup.c
arch/ppc/kernel/signal.c
arch/ppc/kernel/time.c
arch/ppc/kernel/traps.c
arch/ppc/mm/init.c
arch/ppc/platforms/4xx/Kconfig
arch/ppc/platforms/4xx/Makefile
arch/ppc/platforms/4xx/ash.c [deleted file]
arch/ppc/platforms/4xx/ash.h [deleted file]
arch/ppc/platforms/4xx/bamboo.c
arch/ppc/platforms/4xx/bamboo.h
arch/ppc/platforms/4xx/ebony.c
arch/ppc/platforms/4xx/ibm405ep.c
arch/ppc/platforms/4xx/ibm405gp.c
arch/ppc/platforms/4xx/ibm405gpr.c
arch/ppc/platforms/4xx/ibm440ep.c
arch/ppc/platforms/4xx/ibm440gp.c
arch/ppc/platforms/4xx/ibm440gx.c
arch/ppc/platforms/4xx/ibm440sp.c
arch/ppc/platforms/4xx/ibmnp405h.c
arch/ppc/platforms/4xx/ibmstb4.c
arch/ppc/platforms/4xx/ibmstb4.h
arch/ppc/platforms/4xx/luan.c
arch/ppc/platforms/4xx/luan.h
arch/ppc/platforms/4xx/oak.c [deleted file]
arch/ppc/platforms/4xx/oak.h [deleted file]
arch/ppc/platforms/4xx/oak_setup.h [deleted file]
arch/ppc/platforms/4xx/ocotea.c
arch/ppc/platforms/4xx/redwood5.c
arch/ppc/platforms/83xx/mpc834x_sys.c
arch/ppc/platforms/83xx/mpc834x_sys.h
arch/ppc/platforms/Makefile
arch/ppc/platforms/adir.h [deleted file]
arch/ppc/platforms/adir_pci.c [deleted file]
arch/ppc/platforms/adir_pic.c [deleted file]
arch/ppc/platforms/adir_setup.c [deleted file]
arch/ppc/platforms/cpci690.c
arch/ppc/platforms/cpci690.h
arch/ppc/platforms/ev64360.c [new file with mode: 0644]
arch/ppc/platforms/ev64360.h [new file with mode: 0644]
arch/ppc/platforms/k2.c [deleted file]
arch/ppc/platforms/k2.h [deleted file]
arch/ppc/platforms/katana.c
arch/ppc/platforms/katana.h
arch/ppc/platforms/mcpn765.c [deleted file]
arch/ppc/platforms/mcpn765.h [deleted file]
arch/ppc/platforms/pcore.c [deleted file]
arch/ppc/platforms/pcore.h [deleted file]
arch/ppc/platforms/pmac_pic.c
arch/ppc/platforms/spd8xx.h [deleted file]
arch/ppc/platforms/tqm8xx.h
arch/ppc/syslib/Makefile
arch/ppc/syslib/m8xx_setup.c
arch/ppc/syslib/mv64360_pic.c
arch/ppc/syslib/mv64x60.c
arch/ppc/syslib/ocp.c
arch/ppc/syslib/of_device.c
arch/ppc/syslib/open_pic.c
arch/ppc/syslib/ppc4xx_setup.c
arch/ppc/syslib/ppc83xx_pci.h [new file with mode: 0644]
arch/ppc/syslib/ppc83xx_setup.c
arch/ppc/syslib/ppc83xx_setup.h
arch/ppc/syslib/ppc_sys.c
arch/ppc/syslib/pq2_devices.c [new file with mode: 0644]
arch/ppc/syslib/pq2_sys.c [new file with mode: 0644]
arch/ppc64/Kconfig
arch/ppc64/Kconfig.debug
arch/ppc64/Makefile
arch/ppc64/boot/Makefile
arch/ppc64/boot/addnote.c
arch/ppc64/boot/crt0.S
arch/ppc64/boot/div64.S
arch/ppc64/boot/elf.h [new file with mode: 0644]
arch/ppc64/boot/main.c
arch/ppc64/boot/page.h [new file with mode: 0644]
arch/ppc64/boot/ppc32-types.h [deleted file]
arch/ppc64/boot/ppc_asm.h [new file with mode: 0644]
arch/ppc64/boot/prom.c
arch/ppc64/boot/prom.h [new file with mode: 0644]
arch/ppc64/boot/stdio.h [new file with mode: 0644]
arch/ppc64/boot/string.S
arch/ppc64/boot/string.h [new file with mode: 0644]
arch/ppc64/boot/zlib.c
arch/ppc64/configs/g5_defconfig
arch/ppc64/configs/iSeries_defconfig
arch/ppc64/configs/maple_defconfig
arch/ppc64/configs/pSeries_defconfig
arch/ppc64/defconfig
arch/ppc64/kernel/LparData.c
arch/ppc64/kernel/Makefile
arch/ppc64/kernel/asm-offsets.c
arch/ppc64/kernel/btext.c
arch/ppc64/kernel/cputable.c
arch/ppc64/kernel/entry.S
arch/ppc64/kernel/firmware.c [new file with mode: 0644]
arch/ppc64/kernel/head.S
arch/ppc64/kernel/iSeries_htab.c
arch/ppc64/kernel/iSeries_setup.c
arch/ppc64/kernel/iSeries_vio.c [new file with mode: 0644]
arch/ppc64/kernel/kprobes.c
arch/ppc64/kernel/lmb.c
arch/ppc64/kernel/lparcfg.c
arch/ppc64/kernel/maple_setup.c
arch/ppc64/kernel/misc.S
arch/ppc64/kernel/of_device.c
arch/ppc64/kernel/pSeries_iommu.c
arch/ppc64/kernel/pSeries_lpar.c
arch/ppc64/kernel/pSeries_reconfig.c
arch/ppc64/kernel/pSeries_setup.c
arch/ppc64/kernel/pSeries_smp.c
arch/ppc64/kernel/pSeries_vio.c [new file with mode: 0644]
arch/ppc64/kernel/pacaData.c
arch/ppc64/kernel/pmac_setup.c
arch/ppc64/kernel/pmc.c
arch/ppc64/kernel/process.c
arch/ppc64/kernel/prom.c
arch/ppc64/kernel/prom_init.c
arch/ppc64/kernel/rtas_pci.c
arch/ppc64/kernel/rtasd.c
arch/ppc64/kernel/rtc.c
arch/ppc64/kernel/scanlog.c
arch/ppc64/kernel/setup.c
arch/ppc64/kernel/signal.c
arch/ppc64/kernel/signal32.c
arch/ppc64/kernel/sys_ppc32.c
arch/ppc64/kernel/sysfs.c
arch/ppc64/kernel/time.c
arch/ppc64/kernel/traps.c
arch/ppc64/kernel/udbg.c
arch/ppc64/kernel/udbg_16550.c [new file with mode: 0644]
arch/ppc64/kernel/udbg_scc.c [new file with mode: 0644]
arch/ppc64/kernel/vio.c
arch/ppc64/kernel/vmlinux.lds.S
arch/ppc64/mm/fault.c
arch/ppc64/mm/hash_low.S
arch/ppc64/mm/hash_native.c
arch/ppc64/mm/hash_utils.c
arch/ppc64/mm/hugetlbpage.c
arch/ppc64/mm/imalloc.c
arch/ppc64/mm/init.c
arch/ppc64/mm/numa.c
arch/ppc64/mm/slb.c
arch/ppc64/mm/slb_low.S
arch/ppc64/mm/tlb.c
arch/ppc64/oprofile/common.c
arch/ppc64/oprofile/op_model_power4.c
arch/ppc64/oprofile/op_model_rs64.c
arch/ppc64/xmon/start.c
arch/ppc64/xmon/xmon.c
arch/s390/kernel/compat_signal.c
arch/s390/kernel/debug.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/signal.c
arch/s390/kernel/time.c
arch/s390/mm/fault.c
arch/sh/Kconfig
arch/sh/kernel/signal.c
arch/sh/kernel/time.c
arch/sh64/Kconfig
arch/sh64/kernel/signal.c
arch/sh64/kernel/time.c
arch/sparc/Kconfig
arch/sparc/kernel/pcic.c
arch/sparc/kernel/setup.c
arch/sparc/kernel/signal.c
arch/sparc/kernel/sparc_ksyms.c
arch/sparc/kernel/tick14.c
arch/sparc/kernel/time.c
arch/sparc/mm/fault.c
arch/sparc/mm/generic.c
arch/sparc/mm/init.c
arch/sparc64/Kconfig
arch/sparc64/kernel/entry.S
arch/sparc64/kernel/head.S
arch/sparc64/kernel/kprobes.c
arch/sparc64/kernel/pci.c
arch/sparc64/kernel/pci_iommu.c
arch/sparc64/kernel/process.c
arch/sparc64/kernel/rtrap.S
arch/sparc64/kernel/sbus.c
arch/sparc64/kernel/setup.c
arch/sparc64/kernel/signal.c
arch/sparc64/kernel/signal32.c
arch/sparc64/kernel/smp.c
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/kernel/sunos_ioctl32.c
arch/sparc64/kernel/sys_sparc32.c
arch/sparc64/kernel/time.c
arch/sparc64/kernel/traps.c
arch/sparc64/kernel/ttable.S
arch/sparc64/kernel/unaligned.c
arch/sparc64/kernel/vmlinux.lds.S
arch/sparc64/kernel/winfixup.S
arch/sparc64/lib/Makefile
arch/sparc64/lib/PeeCeeI.c
arch/sparc64/lib/copy_page.S
arch/sparc64/lib/debuglocks.c
arch/sparc64/lib/mb.S [new file with mode: 0644]
arch/sparc64/mm/fault.c
arch/sparc64/mm/generic.c
arch/sparc64/mm/init.c
arch/sparc64/mm/ultra.S
arch/sparc64/solaris/misc.c
arch/um/Kconfig
arch/um/Kconfig.char [moved from arch/um/Kconfig_char with 100% similarity]
arch/um/Kconfig.debug
arch/um/Kconfig.i386 [moved from arch/um/Kconfig_i386 with 93% similarity]
arch/um/Kconfig.net [moved from arch/um/Kconfig_net with 98% similarity]
arch/um/Kconfig.scsi [moved from arch/um/Kconfig_scsi with 100% similarity]
arch/um/Kconfig.x86_64 [moved from arch/um/Kconfig_x86_64 with 83% similarity]
arch/um/Makefile
arch/um/Makefile-i386
arch/um/Makefile-x86_64
arch/um/drivers/Makefile
arch/um/drivers/chan_user.c
arch/um/drivers/ubd_kern.c
arch/um/include/aio.h [new file with mode: 0644]
arch/um/include/common-offsets.h
arch/um/include/init.h
arch/um/include/irq_kern.h
arch/um/include/os.h
arch/um/include/syscall.h [new file with mode: 0644]
arch/um/include/syscall_user.h [deleted file]
arch/um/include/sysdep-i386/syscalls.h
arch/um/include/sysdep-x86_64/ptrace.h
arch/um/include/sysdep-x86_64/syscalls.h
arch/um/include/tlb.h
arch/um/include/um_uaccess.h
arch/um/include/user_util.h
arch/um/kernel/Makefile
arch/um/kernel/irq.c
arch/um/kernel/ksyms.c
arch/um/kernel/main.c
arch/um/kernel/mem.c
arch/um/kernel/signal_kern.c
arch/um/kernel/skas/Makefile
arch/um/kernel/skas/include/mmu-skas.h
arch/um/kernel/skas/include/skas.h
arch/um/kernel/skas/mem_user.c
arch/um/kernel/skas/mmu.c
arch/um/kernel/skas/process.c
arch/um/kernel/skas/process_kern.c
arch/um/kernel/skas/syscall.c [new file with mode: 0644]
arch/um/kernel/skas/syscall_kern.c [deleted file]
arch/um/kernel/skas/syscall_user.c [deleted file]
arch/um/kernel/skas/tlb.c
arch/um/kernel/syscall.c [new file with mode: 0644]
arch/um/kernel/syscall_user.c [deleted file]
arch/um/kernel/tlb.c
arch/um/kernel/trap_kern.c
arch/um/kernel/trap_user.c
arch/um/kernel/tt/syscall_kern.c
arch/um/kernel/tt/syscall_user.c
arch/um/kernel/tt/tlb.c
arch/um/kernel/um_arch.c
arch/um/os-Linux/Makefile
arch/um/os-Linux/aio.c [new file with mode: 0644]
arch/um/os-Linux/elf_aux.c
arch/um/os-Linux/process.c
arch/um/os-Linux/start_up.c [moved from arch/um/kernel/process.c with 61% similarity]
arch/um/os-Linux/tt.c [new file with mode: 0644]
arch/um/scripts/Makefile.unmap
arch/um/sys-i386/Makefile
arch/um/sys-i386/kernel-offsets.c
arch/um/sys-i386/signal.c
arch/um/sys-i386/stub.S
arch/um/sys-i386/stub_segv.c
arch/um/sys-x86_64/Makefile
arch/um/sys-x86_64/kernel-offsets.c
arch/um/sys-x86_64/signal.c
arch/um/sys-x86_64/stub.S
arch/um/sys-x86_64/stub_segv.c
arch/v850/configs/rte-ma1-cb_defconfig
arch/v850/configs/rte-me2-cb_defconfig
arch/v850/configs/sim_defconfig
arch/v850/kernel/setup.c
arch/v850/kernel/signal.c
arch/v850/kernel/time.c
arch/x86_64/Kconfig
arch/x86_64/boot/setup.S
arch/x86_64/boot/tools/build.c
arch/x86_64/ia32/ia32entry.S
arch/x86_64/ia32/sys_ia32.c
arch/x86_64/kernel/Makefile
arch/x86_64/kernel/e820.c
arch/x86_64/kernel/entry.S
arch/x86_64/kernel/genapic.c
arch/x86_64/kernel/genapic_cluster.c
arch/x86_64/kernel/io_apic.c
arch/x86_64/kernel/kprobes.c
arch/x86_64/kernel/nmi.c
arch/x86_64/kernel/process.c
arch/x86_64/kernel/setup.c
arch/x86_64/kernel/setup64.c
arch/x86_64/kernel/signal.c
arch/x86_64/kernel/smpboot.c
arch/x86_64/kernel/time.c
arch/x86_64/kernel/traps.c
arch/x86_64/kernel/vmlinux.lds.S
arch/x86_64/mm/fault.c
arch/x86_64/mm/numa.c
arch/xtensa/kernel/signal.c
arch/xtensa/kernel/time.c
crypto/Kconfig
crypto/api.c
crypto/cipher.c
crypto/internal.h
crypto/tcrypt.c
crypto/tcrypt.h
crypto/tea.c
drivers/Kconfig
drivers/Makefile
drivers/atm/ambassador.c
drivers/atm/atmtcp.c
drivers/atm/eni.c
drivers/atm/firestream.c
drivers/atm/fore200e.c
drivers/atm/he.c
drivers/atm/horizon.c
drivers/atm/idt77252.c
drivers/atm/lanai.c
drivers/atm/nicstar.c
drivers/atm/nicstar.h
drivers/atm/zatm.c
drivers/base/bus.c
drivers/base/class.c
drivers/base/core.c
drivers/base/dd.c
drivers/base/firmware_class.c
drivers/base/node.c
drivers/base/power/resume.c
drivers/base/power/runtime.c
drivers/base/power/suspend.c
drivers/base/power/sysfs.c
drivers/base/sys.c
drivers/block/Kconfig
drivers/block/aoe/aoedev.c
drivers/block/aoe/aoenet.c
drivers/block/cfq-iosched.c
drivers/block/cryptoloop.c
drivers/block/deadline-iosched.c
drivers/block/floppy.c
drivers/block/genhd.c
drivers/block/ll_rw_blk.c
drivers/block/viodasd.c
drivers/bluetooth/bfusb.c
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bpa10x.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/dtl1_cs.c
drivers/bluetooth/hci_bcsp.c
drivers/bluetooth/hci_h4.c
drivers/bluetooth/hci_ldisc.c
drivers/bluetooth/hci_usb.c
drivers/bluetooth/hci_vhci.c
drivers/bluetooth/hci_vhci.h [deleted file]
drivers/cdrom/viocd.c
drivers/char/Kconfig
drivers/char/digi1.h
drivers/char/digiFep1.h
drivers/char/drm/Kconfig
drivers/char/drm/Makefile
drivers/char/drm/drm.h
drivers/char/drm/drmP.h
drivers/char/drm/drm_agpsupport.c
drivers/char/drm/drm_bufs.c
drivers/char/drm/drm_context.c
drivers/char/drm/drm_drv.c
drivers/char/drm/drm_fops.c
drivers/char/drm/drm_ioctl.c
drivers/char/drm/drm_memory.c
drivers/char/drm/drm_pci.c
drivers/char/drm/drm_pciids.h
drivers/char/drm/drm_proc.c
drivers/char/drm/drm_scatter.c
drivers/char/drm/drm_stub.c
drivers/char/drm/drm_sysfs.c
drivers/char/drm/drm_vm.c
drivers/char/drm/ffb_drv.c
drivers/char/drm/gamma_context.h [deleted file]
drivers/char/drm/gamma_dma.c [deleted file]
drivers/char/drm/gamma_drm.h [deleted file]
drivers/char/drm/gamma_drv.c [deleted file]
drivers/char/drm/gamma_drv.h [deleted file]
drivers/char/drm/gamma_lists.h [deleted file]
drivers/char/drm/gamma_lock.h [deleted file]
drivers/char/drm/gamma_old_dma.h [deleted file]
drivers/char/drm/i810_dma.c
drivers/char/drm/i810_drv.c
drivers/char/drm/i810_drv.h
drivers/char/drm/i830_dma.c
drivers/char/drm/i830_drv.c
drivers/char/drm/i830_drv.h
drivers/char/drm/i915_dma.c
drivers/char/drm/i915_drv.c
drivers/char/drm/i915_drv.h
drivers/char/drm/mga_dma.c
drivers/char/drm/mga_drm.h
drivers/char/drm/mga_drv.c
drivers/char/drm/mga_drv.h
drivers/char/drm/mga_ioc32.c
drivers/char/drm/mga_irq.c
drivers/char/drm/mga_state.c
drivers/char/drm/mga_warp.c
drivers/char/drm/r128_cce.c
drivers/char/drm/r128_drm.h
drivers/char/drm/r300_cmdbuf.c [new file with mode: 0644]
drivers/char/drm/r300_reg.h [new file with mode: 0644]
drivers/char/drm/radeon_cp.c
drivers/char/drm/radeon_drm.h
drivers/char/drm/radeon_drv.c
drivers/char/drm/radeon_drv.h
drivers/char/drm/radeon_state.c
drivers/char/drm/savage_bci.c [new file with mode: 0644]
drivers/char/drm/savage_drm.h [new file with mode: 0644]
drivers/char/drm/savage_drv.c [new file with mode: 0644]
drivers/char/drm/savage_drv.h [new file with mode: 0644]
drivers/char/drm/savage_state.c [new file with mode: 0644]
drivers/char/epca.c
drivers/char/epca.h
drivers/char/hpet.c
drivers/char/hvc_vio.c
drivers/char/hvcs.c
drivers/char/ipmi/ipmi_bt_sm.c
drivers/char/ipmi/ipmi_devintf.c
drivers/char/ipmi/ipmi_kcs_sm.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_poweroff.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/ipmi/ipmi_smic_sm.c
drivers/char/ipmi/ipmi_watchdog.c
drivers/char/mbcs.c
drivers/char/mem.c
drivers/char/misc.c
drivers/char/moxa.c
drivers/char/mwave/mwavedd.c
drivers/char/mxser.c
drivers/char/random.c
drivers/char/rtc.c
drivers/char/snsc_event.c
drivers/char/sonypi.c
drivers/char/tpm/tpm_atmel.c
drivers/char/tpm/tpm_infineon.c
drivers/char/tty_io.c
drivers/char/viotape.c
drivers/char/vt.c
drivers/char/watchdog/Kconfig
drivers/char/watchdog/Makefile
drivers/char/watchdog/booke_wdt.c [new file with mode: 0644]
drivers/char/watchdog/ixp2000_wdt.c
drivers/char/watchdog/ixp4xx_wdt.c
drivers/char/watchdog/s3c2410_wdt.c
drivers/char/watchdog/scx200_wdt.c
drivers/char/watchdog/softdog.c
drivers/char/watchdog/w83627hf_wdt.c
drivers/firmware/Kconfig
drivers/firmware/Makefile
drivers/firmware/dcdbas.c [new file with mode: 0644]
drivers/firmware/dcdbas.h [new file with mode: 0644]
drivers/firmware/dell_rbu.c [new file with mode: 0644]
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/adm1021.c
drivers/hwmon/adm1025.c
drivers/hwmon/adm1026.c
drivers/hwmon/adm1031.c
drivers/hwmon/adm9240.c
drivers/hwmon/asb100.c
drivers/hwmon/atxp1.c
drivers/hwmon/ds1621.c
drivers/hwmon/fscher.c
drivers/hwmon/fscpos.c
drivers/hwmon/gl518sm.c
drivers/hwmon/gl520sm.c
drivers/hwmon/hwmon-vid.c [new file with mode: 0644]
drivers/hwmon/hwmon.c [new file with mode: 0644]
drivers/hwmon/it87.c
drivers/hwmon/lm63.c
drivers/hwmon/lm75.c
drivers/hwmon/lm75.h
drivers/hwmon/lm77.c
drivers/hwmon/lm78.c
drivers/hwmon/lm80.c
drivers/hwmon/lm83.c
drivers/hwmon/lm85.c
drivers/hwmon/lm87.c
drivers/hwmon/lm90.c
drivers/hwmon/lm92.c
drivers/hwmon/max1619.c
drivers/hwmon/pc87360.c
drivers/hwmon/sis5595.c
drivers/hwmon/smsc47b397.c
drivers/hwmon/smsc47m1.c
drivers/hwmon/via686a.c
drivers/hwmon/w83627ehf.c
drivers/hwmon/w83627hf.c
drivers/hwmon/w83781d.c
drivers/hwmon/w83792d.c [new file with mode: 0644]
drivers/hwmon/w83l785ts.c
drivers/i2c/Makefile
drivers/i2c/algos/i2c-algo-bit.c
drivers/i2c/algos/i2c-algo-ite.c
drivers/i2c/algos/i2c-algo-pca.c
drivers/i2c/algos/i2c-algo-pcf.c
drivers/i2c/algos/i2c-algo-sgi.c
drivers/i2c/algos/i2c-algo-sibyte.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-ali1535.c
drivers/i2c/busses/i2c-ali1563.c
drivers/i2c/busses/i2c-ali15x3.c
drivers/i2c/busses/i2c-amd756.c
drivers/i2c/busses/i2c-amd8111.c
drivers/i2c/busses/i2c-au1550.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-ibm_iic.c
drivers/i2c/busses/i2c-iop3xx.c
drivers/i2c/busses/i2c-isa.c
drivers/i2c/busses/i2c-keywest.c
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/busses/i2c-mv64xxx.c
drivers/i2c/busses/i2c-nforce2.c
drivers/i2c/busses/i2c-piix4.c
drivers/i2c/busses/i2c-s3c2410.c
drivers/i2c/busses/i2c-sis5595.c
drivers/i2c/busses/i2c-sis630.c
drivers/i2c/busses/i2c-sis96x.c
drivers/i2c/busses/i2c-stub.c
drivers/i2c/busses/i2c-viapro.c
drivers/i2c/busses/scx200_acb.c
drivers/i2c/chips/Kconfig
drivers/i2c/chips/ds1337.c
drivers/i2c/chips/ds1374.c
drivers/i2c/chips/eeprom.c
drivers/i2c/chips/isp1301_omap.c
drivers/i2c/chips/m41t00.c
drivers/i2c/chips/max6875.c
drivers/i2c/chips/pca9539.c
drivers/i2c/chips/pcf8574.c
drivers/i2c/chips/pcf8591.c
drivers/i2c/chips/rtc8564.c
drivers/i2c/i2c-core.c
drivers/i2c/i2c-dev.c
drivers/i2c/i2c-sensor-detect.c [deleted file]
drivers/i2c/i2c-sensor-vid.c [deleted file]
drivers/ide/ide-io.c
drivers/ide/ide.c
drivers/ide/pci/sc1200.c
drivers/ide/ppc/pmac.c
drivers/ieee1394/ieee1394_core.c
drivers/ieee1394/nodemgr.c
drivers/ieee1394/pcilynx.c
drivers/infiniband/core/Makefile
drivers/infiniband/core/agent.c
drivers/infiniband/core/agent_priv.h
drivers/infiniband/core/cache.c
drivers/infiniband/core/cm.c
drivers/infiniband/core/cm_msgs.h
drivers/infiniband/core/core_priv.h
drivers/infiniband/core/device.c
drivers/infiniband/core/fmr_pool.c
drivers/infiniband/core/mad.c
drivers/infiniband/core/mad_priv.h
drivers/infiniband/core/mad_rmpp.c
drivers/infiniband/core/packer.c
drivers/infiniband/core/sa_query.c
drivers/infiniband/core/smi.c
drivers/infiniband/core/sysfs.c
drivers/infiniband/core/ucm.c
drivers/infiniband/core/ucm.h
drivers/infiniband/core/ud_header.c
drivers/infiniband/core/user_mad.c
drivers/infiniband/core/uverbs.h
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/uverbs_main.c
drivers/infiniband/core/uverbs_mem.c
drivers/infiniband/core/verbs.c
drivers/infiniband/hw/mthca/Makefile
drivers/infiniband/hw/mthca/mthca_allocator.c
drivers/infiniband/hw/mthca/mthca_av.c
drivers/infiniband/hw/mthca/mthca_cmd.c
drivers/infiniband/hw/mthca/mthca_cmd.h
drivers/infiniband/hw/mthca/mthca_config_reg.h
drivers/infiniband/hw/mthca/mthca_cq.c
drivers/infiniband/hw/mthca/mthca_dev.h
drivers/infiniband/hw/mthca/mthca_doorbell.h
drivers/infiniband/hw/mthca/mthca_eq.c
drivers/infiniband/hw/mthca/mthca_mad.c
drivers/infiniband/hw/mthca/mthca_main.c
drivers/infiniband/hw/mthca/mthca_mcg.c
drivers/infiniband/hw/mthca/mthca_memfree.c
drivers/infiniband/hw/mthca/mthca_memfree.h
drivers/infiniband/hw/mthca/mthca_mr.c
drivers/infiniband/hw/mthca/mthca_pd.c
drivers/infiniband/hw/mthca/mthca_profile.c
drivers/infiniband/hw/mthca/mthca_profile.h
drivers/infiniband/hw/mthca/mthca_provider.c
drivers/infiniband/hw/mthca/mthca_provider.h
drivers/infiniband/hw/mthca/mthca_qp.c
drivers/infiniband/hw/mthca/mthca_srq.c [new file with mode: 0644]
drivers/infiniband/hw/mthca/mthca_user.h
drivers/infiniband/hw/mthca/mthca_wqe.h [new file with mode: 0644]
drivers/infiniband/ulp/ipoib/Makefile
drivers/infiniband/ulp/ipoib/ipoib.h
drivers/infiniband/ulp/ipoib/ipoib_fs.c
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/ipoib/ipoib_multicast.c
drivers/infiniband/ulp/ipoib/ipoib_verbs.c
drivers/infiniband/ulp/ipoib/ipoib_vlan.c
drivers/input/evdev.c
drivers/input/gameport/emu10k1-gp.c
drivers/input/gameport/fm801-gp.c
drivers/input/gameport/ns558.c
drivers/input/input.c
drivers/input/joystick/a3d.c
drivers/input/joystick/adi.c
drivers/input/joystick/analog.c
drivers/input/joystick/cobra.c
drivers/input/joystick/db9.c
drivers/input/joystick/gamecon.c
drivers/input/joystick/gf2k.c
drivers/input/joystick/grip.c
drivers/input/joystick/grip_mp.c
drivers/input/joystick/guillemot.c
drivers/input/joystick/interact.c
drivers/input/joystick/sidewinder.c
drivers/input/joystick/tmdc.c
drivers/input/joystick/turbografx.c
drivers/input/keyboard/corgikbd.c
drivers/input/mouse/psmouse-base.c
drivers/input/serio/serport.c
drivers/input/touchscreen/corgi_ts.c
drivers/isdn/act2000/capi.c
drivers/isdn/hisax/hisax.h
drivers/isdn/i4l/isdn_net.c
drivers/isdn/i4l/isdn_ppp.c
drivers/isdn/i4l/isdn_v110.c
drivers/macintosh/mediabay.c
drivers/macintosh/via-pmu.c
drivers/md/dm-crypt.c
drivers/md/dm-io.c
drivers/md/dm.c
drivers/media/common/saa7146_i2c.c
drivers/media/dvb/b2c2/flexcop-i2c.c
drivers/media/dvb/bt8xx/Kconfig
drivers/media/dvb/cinergyT2/cinergyT2.c
drivers/media/dvb/dvb-usb/cxusb.c
drivers/media/dvb/dvb-usb/dibusb-common.c
drivers/media/dvb/dvb-usb/digitv.c
drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
drivers/media/dvb/frontends/lgdt330x.c
drivers/media/dvb/frontends/tda80xx.c
drivers/media/dvb/pluto2/pluto2.c
drivers/media/dvb/ttpci/Kconfig
drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/adv7170.c
drivers/media/video/adv7175.c
drivers/media/video/bt819.c
drivers/media/video/bt832.c
drivers/media/video/bt856.c
drivers/media/video/bttv-driver.c
drivers/media/video/bttv-i2c.c
drivers/media/video/cx88/cx88-i2c.c
drivers/media/video/indycam.c [new file with mode: 0644]
drivers/media/video/indycam.h [new file with mode: 0644]
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/meye.c
drivers/media/video/msp3400.c
drivers/media/video/ovcamchip/ov6x20.c
drivers/media/video/ovcamchip/ov6x30.c
drivers/media/video/ovcamchip/ovcamchip_core.c
drivers/media/video/saa7110.c
drivers/media/video/saa7111.c
drivers/media/video/saa7114.c
drivers/media/video/saa7134/saa6752hs.c
drivers/media/video/saa7134/saa7134-i2c.c
drivers/media/video/saa7185.c
drivers/media/video/saa7191.c [new file with mode: 0644]
drivers/media/video/saa7191.h [new file with mode: 0644]
drivers/media/video/tda7432.c
drivers/media/video/tda9840.c
drivers/media/video/tda9875.c
drivers/media/video/tda9887.c
drivers/media/video/tea6415c.c
drivers/media/video/tea6420.c
drivers/media/video/tuner-3036.c
drivers/media/video/tuner-core.c
drivers/media/video/tvaudio.c
drivers/media/video/tveeprom.c
drivers/media/video/tvmixer.c
drivers/media/video/vino.c
drivers/media/video/vino.h
drivers/media/video/vpx3220.c
drivers/media/video/zoran_card.c
drivers/mfd/Kconfig [new file with mode: 0644]
drivers/mfd/Makefile [new file with mode: 0644]
drivers/mfd/mcp-core.c [new file with mode: 0644]
drivers/mfd/mcp-sa11x0.c [new file with mode: 0644]
drivers/mfd/mcp.h [new file with mode: 0644]
drivers/misc/ibmasm/uart.c
drivers/mmc/mmc.c
drivers/mmc/mmc.h
drivers/mmc/mmc_block.c
drivers/mmc/mmc_sysfs.c
drivers/mmc/mmci.c
drivers/mmc/pxamci.c
drivers/mmc/wbsd.c
drivers/mmc/wbsd.h
drivers/mtd/nand/nand_base.c
drivers/net/3c59x.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/Space.c
drivers/net/ac3200.c
drivers/net/arcnet/arcnet.c
drivers/net/atarilance.c
drivers/net/bnx2.c
drivers/net/bnx2.h
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_3ad.h
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bonding.h
drivers/net/chelsio/Makefile [new file with mode: 0644]
drivers/net/chelsio/common.h [new file with mode: 0644]
drivers/net/chelsio/cphy.h [new file with mode: 0644]
drivers/net/chelsio/cpl5_cmd.h [new file with mode: 0644]
drivers/net/chelsio/cxgb2.c [new file with mode: 0644]
drivers/net/chelsio/elmer0.h [new file with mode: 0644]
drivers/net/chelsio/espi.c [new file with mode: 0644]
drivers/net/chelsio/espi.h [new file with mode: 0644]
drivers/net/chelsio/gmac.h [new file with mode: 0644]
drivers/net/chelsio/mv88x201x.c [new file with mode: 0644]
drivers/net/chelsio/pm3393.c [new file with mode: 0644]
drivers/net/chelsio/regs.h [new file with mode: 0644]
drivers/net/chelsio/sge.c [new file with mode: 0644]
drivers/net/chelsio/sge.h [new file with mode: 0644]
drivers/net/chelsio/subr.c [new file with mode: 0644]
drivers/net/chelsio/suni1x10gexp_regs.h [new file with mode: 0644]
drivers/net/dm9000.c
drivers/net/e100.c
drivers/net/e1000/e1000_hw.h
drivers/net/e1000/e1000_main.c
drivers/net/eepro100.c
drivers/net/forcedeth.c
drivers/net/hamachi.c
drivers/net/hamradio/Kconfig
drivers/net/hamradio/baycom_epp.c
drivers/net/hamradio/baycom_par.c
drivers/net/hamradio/baycom_ser_fdx.c
drivers/net/hamradio/baycom_ser_hdx.c
drivers/net/hamradio/bpqether.c
drivers/net/hamradio/mkiss.c
drivers/net/ibmveth.c
drivers/net/irda/smsc-ircc2.c
drivers/net/irda/smsc-ircc2.h
drivers/net/irda/vlsi_ir.c
drivers/net/iseries_veth.c
drivers/net/iseries_veth.h [deleted file]
drivers/net/ixgb/ixgb.h
drivers/net/ixgb/ixgb_ee.c
drivers/net/ixgb/ixgb_ethtool.c
drivers/net/ixgb/ixgb_hw.h
drivers/net/ixgb/ixgb_main.c
drivers/net/jazzsonic.c
drivers/net/loopback.c
drivers/net/macsonic.c
drivers/net/mv643xx_eth.c
drivers/net/mv643xx_eth.h
drivers/net/ne3210.c
drivers/net/pci-skeleton.c
drivers/net/pcmcia/fmvj18x_cs.c
drivers/net/phy/Kconfig [new file with mode: 0644]
drivers/net/phy/Makefile [new file with mode: 0644]
drivers/net/phy/cicada.c [new file with mode: 0644]
drivers/net/phy/davicom.c [new file with mode: 0644]
drivers/net/phy/lxt.c [new file with mode: 0644]
drivers/net/phy/marvell.c [new file with mode: 0644]
drivers/net/phy/mdio_bus.c [new file with mode: 0644]
drivers/net/phy/phy.c [new file with mode: 0644]
drivers/net/phy/phy_device.c [new file with mode: 0644]
drivers/net/phy/qsemi.c [new file with mode: 0644]
drivers/net/ppp_generic.c
drivers/net/pppoe.c
drivers/net/r8169.c
drivers/net/rrunner.c
drivers/net/s2io-regs.h
drivers/net/s2io.c
drivers/net/s2io.h
drivers/net/shaper.c
drivers/net/sis190.c [new file with mode: 0644]
drivers/net/skge.c
drivers/net/skge.h
drivers/net/smc-ultra.c
drivers/net/smc91x.h
drivers/net/sonic.c
drivers/net/sonic.h
drivers/net/spider_net.c [new file with mode: 0644]
drivers/net/spider_net.h [new file with mode: 0644]
drivers/net/spider_net_ethtool.c [new file with mode: 0644]
drivers/net/sun3lance.c
drivers/net/sungem.c
drivers/net/sungem.h
drivers/net/tg3.c
drivers/net/tg3.h
drivers/net/tokenring/Kconfig
drivers/net/tokenring/abyss.c
drivers/net/tokenring/madgemc.c
drivers/net/tokenring/proteon.c
drivers/net/tokenring/skisa.c
drivers/net/tokenring/tms380tr.c
drivers/net/tokenring/tms380tr.h
drivers/net/tokenring/tmspci.c
drivers/net/tulip/Kconfig
drivers/net/tulip/Makefile
drivers/net/tulip/de2104x.c
drivers/net/tulip/media.c
drivers/net/tulip/timer.c
drivers/net/tulip/tulip.h
drivers/net/tulip/tulip_core.c
drivers/net/tulip/uli526x.c [new file with mode: 0644]
drivers/net/tun.c
drivers/net/wan/cycx_drv.c
drivers/net/wan/hdlc_generic.c
drivers/net/wan/lapbether.c
drivers/net/wan/sdla_fr.c
drivers/net/wan/syncppp.c
drivers/net/wireless/Kconfig
drivers/net/wireless/Makefile
drivers/net/wireless/airo.c
drivers/net/wireless/atmel.c
drivers/net/wireless/hostap/Kconfig [new file with mode: 0644]
drivers/net/wireless/hostap/Makefile [new file with mode: 0644]
drivers/net/wireless/hostap/hostap.c [new file with mode: 0644]
drivers/net/wireless/hostap/hostap.h [new file with mode: 0644]
drivers/net/wireless/hostap/hostap_80211.h [new file with mode: 0644]
drivers/net/wireless/hostap/hostap_80211_rx.c [new file with mode: 0644]
drivers/net/wireless/hostap/hostap_80211_tx.c [new file with mode: 0644]
drivers/net/wireless/hostap/hostap_ap.c [new file with mode: 0644]
drivers/net/wireless/hostap/hostap_ap.h [new file with mode: 0644]
drivers/net/wireless/hostap/hostap_common.h [new file with mode: 0644]
drivers/net/wireless/hostap/hostap_config.h [new file with mode: 0644]
drivers/net/wireless/hostap/hostap_cs.c [new file with mode: 0644]
drivers/net/wireless/hostap/hostap_download.c [new file with mode: 0644]
drivers/net/wireless/hostap/hostap_hw.c [new file with mode: 0644]
drivers/net/wireless/hostap/hostap_info.c [new file with mode: 0644]
drivers/net/wireless/hostap/hostap_ioctl.c [new file with mode: 0644]
drivers/net/wireless/hostap/hostap_pci.c [new file with mode: 0644]
drivers/net/wireless/hostap/hostap_plx.c [new file with mode: 0644]
drivers/net/wireless/hostap/hostap_proc.c [new file with mode: 0644]
drivers/net/wireless/hostap/hostap_wlan.h [new file with mode: 0644]
drivers/net/wireless/ieee802_11.h [deleted file]
drivers/net/wireless/ipw2100.c [new file with mode: 0644]
drivers/net/wireless/ipw2100.h [new file with mode: 0644]
drivers/net/wireless/ipw2200.c [new file with mode: 0644]
drivers/net/wireless/ipw2200.h [new file with mode: 0644]
drivers/net/wireless/netwave_cs.c
drivers/net/wireless/orinoco.c
drivers/net/wireless/orinoco_cs.c
drivers/net/wireless/orinoco_nortel.c [new file with mode: 0644]
drivers/net/wireless/orinoco_pci.c
drivers/net/wireless/prism54/isl_ioctl.c
drivers/net/wireless/prism54/islpci_dev.c
drivers/net/wireless/prism54/islpci_hotplug.c
drivers/net/wireless/ray_cs.c
drivers/net/wireless/ray_cs.h
drivers/net/wireless/spectrum_cs.c [new file with mode: 0644]
drivers/net/wireless/strip.c
drivers/net/wireless/wavelan_cs.c
drivers/net/wireless/wavelan_cs.h
drivers/net/wireless/wavelan_cs.p.h
drivers/net/wireless/wl3501.h
drivers/net/wireless/wl3501_cs.c
drivers/parport/parport_pc.c
drivers/parport/parport_serial.c
drivers/pci/msi.c
drivers/pci/msi.h
drivers/pci/pci.c
drivers/pci/quirks.c
drivers/pci/rom.c
drivers/pci/setup-bus.c
drivers/pcmcia/pxa2xx_base.c
drivers/pcmcia/pxa2xx_mainstone.c
drivers/pcmcia/pxa2xx_sharpsl.c
drivers/pcmcia/sa1100_generic.c
drivers/pcmcia/sa1111_generic.c
drivers/pcmcia/sa11xx_base.c
drivers/pcmcia/topic.h
drivers/pcmcia/yenta_socket.c
drivers/pcmcia/yenta_socket.h
drivers/pnp/card.c
drivers/pnp/driver.c
drivers/pnp/isapnp/core.c
drivers/pnp/manager.c
drivers/pnp/pnpacpi/core.c
drivers/pnp/pnpacpi/pnpacpi.h
drivers/pnp/pnpacpi/rsparser.c
drivers/pnp/pnpbios/core.c
drivers/pnp/pnpbios/pnpbios.h
drivers/pnp/pnpbios/proc.c
drivers/pnp/pnpbios/rsparser.c
drivers/pnp/quirks.c
drivers/pnp/support.c
drivers/s390/block/Kconfig
drivers/s390/block/dasd.c
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_diag.h
drivers/s390/block/dasd_genhd.c
drivers/s390/block/dasd_int.h
drivers/s390/block/dasd_ioctl.c
drivers/s390/block/dasd_proc.c
drivers/s390/char/raw3270.c
drivers/s390/cio/cio.c
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_ops.c
drivers/s390/cio/ioasm.h
drivers/s390/crypto/z90common.h
drivers/s390/crypto/z90hardware.c
drivers/s390/crypto/z90main.c
drivers/s390/net/claw.c
drivers/s390/s390mach.c
drivers/s390/scsi/zfcp_aux.c
drivers/s390/scsi/zfcp_ccw.c
drivers/s390/scsi/zfcp_sysfs_port.c
drivers/sbus/char/Kconfig
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/NCR5380.c
drivers/scsi/NCR53c406a.c
drivers/scsi/ahci.c
drivers/scsi/ata_piix.c
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/ibmvscsi/rpa_vscsi.c
drivers/scsi/libata-core.c
drivers/scsi/libata-scsi.c
drivers/scsi/libata.h
drivers/scsi/mesh.c
drivers/scsi/sata_mv.c [new file with mode: 0644]
drivers/scsi/sata_nv.c
drivers/scsi/sata_promise.c
drivers/scsi/sata_promise.h
drivers/scsi/sata_qstor.c
drivers/scsi/sata_sil.c
drivers/scsi/sata_sis.c
drivers/scsi/sata_svw.c
drivers/scsi/sata_sx4.c
drivers/scsi/sata_uli.c
drivers/scsi/sata_via.c
drivers/scsi/sata_vsc.c
drivers/serial/21285.c
drivers/serial/68328serial.c
drivers/serial/68360serial.c
drivers/serial/8250.c
drivers/serial/8250.h
drivers/serial/8250_pci.c
drivers/serial/Kconfig
drivers/serial/amba-pl010.c
drivers/serial/amba-pl011.c
drivers/serial/au1x00_uart.c
drivers/serial/clps711x.c
drivers/serial/cpm_uart/cpm_uart_core.c
drivers/serial/cpm_uart/cpm_uart_cpm2.c
drivers/serial/crisv10.c
drivers/serial/dz.c
drivers/serial/icom.c
drivers/serial/imx.c
drivers/serial/ioc4_serial.c
drivers/serial/ip22zilog.c
drivers/serial/jsm/jsm_tty.c
drivers/serial/m32r_sio.c
drivers/serial/mcfserial.c
drivers/serial/mpc52xx_uart.c
drivers/serial/mpsc.c
drivers/serial/mux.c
drivers/serial/pmac_zilog.c
drivers/serial/pxa.c
drivers/serial/s3c2410.c
drivers/serial/sa1100.c
drivers/serial/serial_core.c
drivers/serial/serial_lh7a40x.c
drivers/serial/serial_txx9.c
drivers/serial/sh-sci.c
drivers/serial/sn_console.c
drivers/serial/sunsab.c
drivers/serial/sunsu.c
drivers/serial/sunzilog.c
drivers/serial/uart00.c
drivers/serial/v850e_uart.c
drivers/serial/vr41xx_siu.c
drivers/usb/atm/usbatm.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/usb.c
drivers/usb/host/ehci-dbg.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/isp116x-hcd.c
drivers/usb/host/ohci-dbg.c
drivers/usb/host/sl811-hcd.c
drivers/usb/input/acecad.c
drivers/usb/input/itmtouch.c
drivers/usb/input/pid.c
drivers/usb/media/w9968cf.c
drivers/usb/misc/usbtest.c
drivers/usb/net/Makefile
drivers/usb/net/usbnet.c
drivers/usb/net/zd1201.c
drivers/video/aty/aty128fb.c
drivers/video/aty/atyfb_base.c
drivers/video/aty/radeon_i2c.c
drivers/video/aty/radeon_pm.c
drivers/video/backlight/Makefile
drivers/video/backlight/locomolcd.c [new file with mode: 0644]
drivers/video/chipsfb.c
drivers/video/i810/i810_main.c
drivers/video/matrox/matroxfb_maven.c
drivers/video/nvidia/nv_i2c.c
drivers/video/pmag-aa-fb.c
drivers/video/pmag-ba-fb.c
drivers/video/pmagb-b-fb.c
drivers/video/q40fb.c
drivers/video/riva/rivafb-i2c.c
drivers/video/s1d13xxxfb.c
drivers/video/savage/savagefb-i2c.c
drivers/video/savage/savagefb_driver.c
drivers/video/w100fb.c
drivers/video/w100fb.h
drivers/w1/w1_int.c
drivers/w1/w1_netlink.c
fs/Kconfig
fs/Makefile
fs/adfs/adfs.h
fs/aio.c
fs/binfmt_flat.c
fs/bio.c
fs/buffer.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/compat.c
fs/cramfs/inode.c
fs/devpts/Makefile
fs/devpts/inode.c
fs/devpts/xattr_security.c [deleted file]
fs/ext2/super.c
fs/ext3/super.c
fs/fat/dir.c
fs/file_table.c
fs/freevxfs/vxfs_super.c
fs/hfs/bnode.c
fs/hfs/catalog.c
fs/hfs/dir.c
fs/hfs/hfs.h
fs/hfs/hfs_fs.h
fs/hfs/inode.c
fs/hfs/mdb.c
fs/hfs/super.c
fs/hfs/trans.c
fs/hfsplus/bnode.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/options.c
fs/hfsplus/super.c
fs/hostfs/hostfs.h
fs/inode.c
fs/inotify.c
fs/jbd/checkpoint.c
fs/jbd/commit.c
fs/jbd/journal.c
fs/jbd/revoke.c
fs/jbd/transaction.c
fs/jffs/inode-v23.c
fs/jffs2/file.c
fs/jfs/jfs_filsys.h
fs/jfs/namei.c
fs/jfs/super.c
fs/namei.c
fs/namespace.c
fs/nfsd/export.c
fs/nfsd/nfs4idmap.c
fs/nfsd/nfs4recover.c
fs/open.c
fs/pipe.c
fs/proc/base.c
fs/proc/generic.c
fs/proc/task_mmu.c
fs/read_write.c
fs/reiserfs/journal.c
fs/relayfs/Makefile [new file with mode: 0644]
fs/relayfs/buffers.c [new file with mode: 0644]
fs/relayfs/buffers.h [new file with mode: 0644]
fs/relayfs/inode.c [new file with mode: 0644]
fs/relayfs/relay.c [new file with mode: 0644]
fs/relayfs/relay.h [new file with mode: 0644]
fs/smbfs/sock.c
fs/ufs/balloc.c
fs/ufs/ialloc.c
fs/ufs/truncate.c
fs/umsdos/notes [deleted file]
fs/xattr.c
fs/xfs/Makefile
fs/xfs/Makefile-linux-2.6 [new file with mode: 0644]
fs/xfs/linux-2.6/kmem.c
fs/xfs/linux-2.6/kmem.h
fs/xfs/linux-2.6/spin.h
fs/xfs/linux-2.6/xfs_aops.c
fs/xfs/linux-2.6/xfs_aops.h [new file with mode: 0644]
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_buf.h
fs/xfs/linux-2.6/xfs_file.c
fs/xfs/linux-2.6/xfs_ioctl.c
fs/xfs/linux-2.6/xfs_ioctl32.c
fs/xfs/linux-2.6/xfs_iops.c
fs/xfs/linux-2.6/xfs_linux.h
fs/xfs/linux-2.6/xfs_lrw.c
fs/xfs/linux-2.6/xfs_lrw.h
fs/xfs/linux-2.6/xfs_super.c
fs/xfs/linux-2.6/xfs_vfs.c
fs/xfs/linux-2.6/xfs_vfs.h
fs/xfs/linux-2.6/xfs_vnode.c
fs/xfs/linux-2.6/xfs_vnode.h
fs/xfs/quota/Makefile [new file with mode: 0644]
fs/xfs/quota/Makefile-linux-2.6 [new file with mode: 0644]
fs/xfs/quota/xfs_dquot.c
fs/xfs/quota/xfs_dquot.h
fs/xfs/quota/xfs_dquot_item.c
fs/xfs/quota/xfs_qm.c
fs/xfs/quota/xfs_qm.h
fs/xfs/quota/xfs_qm_bhv.c
fs/xfs/quota/xfs_qm_syscalls.c
fs/xfs/support/debug.c
fs/xfs/xfs_acl.c
fs/xfs/xfs_bmap.c
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_dmapi.h
fs/xfs/xfs_extfree_item.c
fs/xfs/xfs_iget.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode_item.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_log.c
fs/xfs/xfs_log.h
fs/xfs/xfs_log_priv.h
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_qmops.c
fs/xfs/xfs_quota.h
fs/xfs/xfs_trans.c
fs/xfs/xfs_trans.h
fs/xfs/xfs_trans_ail.c
fs/xfs/xfs_trans_buf.c
fs/xfs/xfs_vfsops.c
fs/xfs/xfs_vnodeops.c
include/asm-alpha/auxvec.h [new file with mode: 0644]
include/asm-alpha/elf.h
include/asm-alpha/fcntl.h
include/asm-alpha/futex.h [new file with mode: 0644]
include/asm-alpha/hdreg.h [deleted file]
include/asm-alpha/page.h
include/asm-alpha/socket.h
include/asm-alpha/types.h
include/asm-alpha/uaccess.h
include/asm-arm/arch-ixp4xx/io.h
include/asm-arm/arch-ixp4xx/platform.h
include/asm-arm/arch-omap/board-h4.h
include/asm-arm/arch-omap/board-innovator.h
include/asm-arm/arch-omap/board-perseus2.h
include/asm-arm/arch-omap/board-voiceblue.h
include/asm-arm/arch-omap/board.h
include/asm-arm/arch-omap/cpu.h
include/asm-arm/arch-omap/debug-macro.S
include/asm-arm/arch-omap/dma.h
include/asm-arm/arch-omap/dmtimer.h [new file with mode: 0644]
include/asm-arm/arch-omap/dsp.h [new file with mode: 0644]
include/asm-arm/arch-omap/dsp_common.h [new file with mode: 0644]
include/asm-arm/arch-omap/entry-macro.S
include/asm-arm/arch-omap/gpio.h
include/asm-arm/arch-omap/hardware.h
include/asm-arm/arch-omap/io.h
include/asm-arm/arch-omap/irqs.h
include/asm-arm/arch-omap/memory.h
include/asm-arm/arch-omap/mtd-xip.h [new file with mode: 0644]
include/asm-arm/arch-omap/mux.h
include/asm-arm/arch-omap/omap1510.h
include/asm-arm/arch-omap/omap16xx.h
include/asm-arm/arch-omap/omap24xx.h [new file with mode: 0644]
include/asm-arm/arch-omap/omap730.h
include/asm-arm/arch-omap/pm.h
include/asm-arm/arch-omap/serial.h [new file with mode: 0644]
include/asm-arm/arch-omap/uncompress.h
include/asm-arm/arch-pxa/corgi.h
include/asm-arm/arch-pxa/mmc.h
include/asm-arm/arch-pxa/pxa-regs.h
include/asm-arm/arch-s3c2410/anubis-cpld.h [new file with mode: 0644]
include/asm-arm/arch-s3c2410/anubis-irq.h [new file with mode: 0644]
include/asm-arm/arch-s3c2410/anubis-map.h [new file with mode: 0644]
include/asm-arm/arch-s3c2410/regs-clock.h
include/asm-arm/arch-sa1100/mcp.h [new file with mode: 0644]
include/asm-arm/auxvec.h [new file with mode: 0644]
include/asm-arm/fcntl.h
include/asm-arm/futex.h [new file with mode: 0644]
include/asm-arm/hardware/gic.h [new file with mode: 0644]
include/asm-arm/hardware/scoop.h
include/asm-arm/hdreg.h [deleted file]
include/asm-arm/mach/irq.h
include/asm-arm/mach/time.h
include/asm-arm/page.h
include/asm-arm/socket.h
include/asm-arm/types.h
include/asm-arm/uaccess.h
include/asm-arm/unistd.h
include/asm-arm26/auxvec.h [new file with mode: 0644]
include/asm-arm26/fcntl.h
include/asm-arm26/futex.h [new file with mode: 0644]
include/asm-arm26/hdreg.h [deleted file]
include/asm-arm26/page.h
include/asm-arm26/socket.h
include/asm-arm26/types.h
include/asm-arm26/uaccess.h
include/asm-cris/auxvec.h [new file with mode: 0644]
include/asm-cris/fcntl.h
include/asm-cris/futex.h [new file with mode: 0644]
include/asm-cris/irq.h
include/asm-cris/page.h
include/asm-cris/socket.h
include/asm-cris/types.h
include/asm-cris/uaccess.h
include/asm-frv/auxvec.h [new file with mode: 0644]
include/asm-frv/fcntl.h
include/asm-frv/futex.h [new file with mode: 0644]
include/asm-frv/page.h
include/asm-frv/socket.h
include/asm-frv/types.h
include/asm-frv/uaccess.h
include/asm-generic/fcntl.h [new file with mode: 0644]
include/asm-generic/hdreg.h [deleted file]
include/asm-generic/page.h [new file with mode: 0644]
include/asm-generic/pgtable.h
include/asm-generic/sections.h
include/asm-generic/unaligned.h
include/asm-generic/vmlinux.lds.h
include/asm-h8300/auxvec.h [new file with mode: 0644]
include/asm-h8300/fcntl.h
include/asm-h8300/futex.h [new file with mode: 0644]
include/asm-h8300/hdreg.h [deleted file]
include/asm-h8300/page.h
include/asm-h8300/socket.h
include/asm-h8300/types.h
include/asm-h8300/uaccess.h
include/asm-i386/agp.h
include/asm-i386/apicdef.h
include/asm-i386/auxvec.h [new file with mode: 0644]
include/asm-i386/bugs.h
include/asm-i386/checksum.h
include/asm-i386/desc.h
include/asm-i386/elf.h
include/asm-i386/fcntl.h
include/asm-i386/futex.h [new file with mode: 0644]
include/asm-i386/hdreg.h [deleted file]
include/asm-i386/kdebug.h
include/asm-i386/mach-es7000/mach_mpparse.h
include/asm-i386/mach-generic/mach_apic.h
include/asm-i386/mpspec.h
include/asm-i386/msr.h
include/asm-i386/page.h
include/asm-i386/pgtable-3level.h
include/asm-i386/pgtable.h
include/asm-i386/processor.h
include/asm-i386/ptrace.h
include/asm-i386/setup.h
include/asm-i386/smp.h
include/asm-i386/socket.h
include/asm-i386/system.h
include/asm-i386/thread_info.h
include/asm-i386/timer.h
include/asm-i386/types.h
include/asm-i386/uaccess.h
include/asm-i386/xor.h
include/asm-ia64/acpi.h
include/asm-ia64/auxvec.h [new file with mode: 0644]
include/asm-ia64/compat.h
include/asm-ia64/elf.h
include/asm-ia64/fcntl.h
include/asm-ia64/futex.h [new file with mode: 0644]
include/asm-ia64/hdreg.h [deleted file]
include/asm-ia64/hw_irq.h
include/asm-ia64/io.h
include/asm-ia64/irq.h
include/asm-ia64/kprobes.h
include/asm-ia64/mmu.h
include/asm-ia64/mmu_context.h
include/asm-ia64/page.h
include/asm-ia64/pal.h
include/asm-ia64/pgtable.h
include/asm-ia64/processor.h
include/asm-ia64/rwsem.h
include/asm-ia64/sn/addrs.h
include/asm-ia64/sn/geo.h
include/asm-ia64/sn/intr.h
include/asm-ia64/sn/nodepda.h
include/asm-ia64/sn/pcibus_provider_defs.h
include/asm-ia64/sn/pda.h
include/asm-ia64/sn/sn2/sn_hwperf.h
include/asm-ia64/sn/sn_sal.h
include/asm-ia64/sn/tioce.h [new file with mode: 0644]
include/asm-ia64/sn/tioce_provider.h [new file with mode: 0644]
include/asm-ia64/socket.h
include/asm-ia64/spinlock.h
include/asm-ia64/system.h
include/asm-ia64/topology.h
include/asm-ia64/types.h
include/asm-ia64/uaccess.h
include/asm-m32r/auxvec.h [new file with mode: 0644]
include/asm-m32r/checksum.h
include/asm-m32r/fcntl.h
include/asm-m32r/futex.h [new file with mode: 0644]
include/asm-m32r/hdreg.h [deleted file]
include/asm-m32r/page.h
include/asm-m32r/socket.h
include/asm-m32r/types.h
include/asm-m32r/uaccess.h
include/asm-m68k/auxvec.h [new file with mode: 0644]
include/asm-m68k/cacheflush.h
include/asm-m68k/fcntl.h
include/asm-m68k/futex.h [new file with mode: 0644]
include/asm-m68k/hdreg.h [deleted file]
include/asm-m68k/page.h
include/asm-m68k/socket.h
include/asm-m68k/string.h
include/asm-m68k/types.h
include/asm-m68k/uaccess.h
include/asm-m68knommu/auxvec.h [new file with mode: 0644]
include/asm-m68knommu/futex.h [new file with mode: 0644]
include/asm-m68knommu/hdreg.h [deleted file]
include/asm-m68knommu/page.h
include/asm-m68knommu/uaccess.h
include/asm-mips/a.out.h
include/asm-mips/addrspace.h
include/asm-mips/asmmacro.h
include/asm-mips/atomic.h
include/asm-mips/auxvec.h [new file with mode: 0644]
include/asm-mips/bitops.h
include/asm-mips/bugs.h
include/asm-mips/checksum.h
include/asm-mips/compat.h
include/asm-mips/cpu-features.h
include/asm-mips/ddb5xxx/ddb5477.h
include/asm-mips/dec/prom.h
include/asm-mips/delay.h
include/asm-mips/elf.h
include/asm-mips/fcntl.h
include/asm-mips/fpregdef.h
include/asm-mips/fpu.h
include/asm-mips/futex.h [new file with mode: 0644]
include/asm-mips/hdreg.h [deleted file]
include/asm-mips/hp-lj/asic.h [deleted file]
include/asm-mips/ip32/mace.h
include/asm-mips/lasat/serial.h
include/asm-mips/local.h
include/asm-mips/mach-au1x00/au1000.h
include/asm-mips/mach-db1x00/db1x00.h
include/asm-mips/mach-generic/spaces.h
include/asm-mips/mach-ip22/spaces.h
include/asm-mips/mach-ip32/cpu-feature-overrides.h
include/asm-mips/mach-jazz/floppy.h
include/asm-mips/mach-pb1x00/pb1500.h
include/asm-mips/mach-qemu/cpu-feature-overrides.h [new file with mode: 0644]
include/asm-mips/mach-qemu/param.h [new file with mode: 0644]
include/asm-mips/mach-vr41xx/timex.h [deleted file]
include/asm-mips/mmu_context.h
include/asm-mips/module.h
include/asm-mips/msgbuf.h
include/asm-mips/paccess.h
include/asm-mips/page.h
include/asm-mips/pci.h
include/asm-mips/pgalloc.h
include/asm-mips/pgtable.h
include/asm-mips/processor.h
include/asm-mips/ptrace.h
include/asm-mips/qemu.h [new file with mode: 0644]
include/asm-mips/r4kcache.h
include/asm-mips/reg.h
include/asm-mips/resource.h
include/asm-mips/rtc.h
include/asm-mips/sgi/gio.h
include/asm-mips/sgi/hpc3.h
include/asm-mips/sgi/ioc.h
include/asm-mips/sgi/ip22.h
include/asm-mips/sgi/mc.h
include/asm-mips/sgiarcs.h
include/asm-mips/sibyte/carmel.h
include/asm-mips/sibyte/sb1250_defs.h
include/asm-mips/sibyte/sb1250_dma.h
include/asm-mips/sibyte/sb1250_genbus.h
include/asm-mips/sibyte/sb1250_int.h
include/asm-mips/sibyte/sb1250_l2c.h
include/asm-mips/sibyte/sb1250_ldt.h
include/asm-mips/sibyte/sb1250_mac.h
include/asm-mips/sibyte/sb1250_mc.h
include/asm-mips/sibyte/sb1250_regs.h
include/asm-mips/sibyte/sb1250_scd.h
include/asm-mips/sibyte/sb1250_smbus.h
include/asm-mips/sibyte/sb1250_syncser.h
include/asm-mips/sibyte/sb1250_uart.h
include/asm-mips/sigcontext.h
include/asm-mips/siginfo.h
include/asm-mips/sim.h
include/asm-mips/socket.h
include/asm-mips/stackframe.h
include/asm-mips/statfs.h
include/asm-mips/string.h
include/asm-mips/system.h
include/asm-mips/thread_info.h
include/asm-mips/titan_dep.h
include/asm-mips/tx4927/tx4927.h
include/asm-mips/tx4927/tx4927_pci.h
include/asm-mips/types.h
include/asm-mips/uaccess.h
include/asm-mips/unistd.h
include/asm-mips/vr4181/irq.h [deleted file]
include/asm-mips/vr4181/vr4181.h [deleted file]
include/asm-mips/vr41xx/vr41xx.h
include/asm-mips/vr41xx/vrc4173.h
include/asm-mips/war.h
include/asm-mips/xxs1500.h
include/asm-parisc/auxvec.h [new file with mode: 0644]
include/asm-parisc/compat.h
include/asm-parisc/fcntl.h
include/asm-parisc/futex.h [new file with mode: 0644]
include/asm-parisc/hdreg.h [deleted file]
include/asm-parisc/irq.h
include/asm-parisc/page.h
include/asm-parisc/socket.h
include/asm-parisc/types.h
include/asm-parisc/uaccess.h
include/asm-powerpc/8253pit.h [moved from include/asm-ppc/8253pit.h with 74% similarity]
include/asm-powerpc/agp.h [moved from include/asm-ppc/agp.h with 100% similarity]
include/asm-powerpc/bugs.h [moved from include/asm-ppc64/shmparam.h with 56% similarity]
include/asm-powerpc/cputime.h [new file with mode: 0644]
include/asm-powerpc/div64.h [moved from include/asm-ppc/div64.h with 100% similarity]
include/asm-powerpc/emergency-restart.h [new file with mode: 0644]
include/asm-powerpc/errno.h [moved from include/asm-ppc/errno.h with 100% similarity]
include/asm-powerpc/fcntl.h [new file with mode: 0644]
include/asm-powerpc/ioctl.h [moved from include/asm-ppc/ioctl.h with 100% similarity]
include/asm-powerpc/ioctls.h [moved from include/asm-ppc/ioctls.h with 100% similarity]
include/asm-powerpc/ipc.h [moved from include/asm-ppc/ipc.h with 100% similarity]
include/asm-powerpc/linkage.h [moved from include/asm-ppc/linkage.h with 100% similarity]
include/asm-powerpc/local.h [moved from include/asm-ppc64/local.h with 100% similarity]
include/asm-powerpc/mc146818rtc.h [moved from include/asm-ppc64/mc146818rtc.h with 84% similarity]
include/asm-powerpc/mman.h [moved from include/asm-ppc64/mman.h with 96% similarity]
include/asm-powerpc/module.h [new file with mode: 0644]
include/asm-powerpc/namei.h [moved from include/asm-ppc/namei.h with 100% similarity]
include/asm-powerpc/percpu.h [new file with mode: 0644]
include/asm-powerpc/poll.h [moved from include/asm-ppc/poll.h with 100% similarity]
include/asm-powerpc/resource.h [new file with mode: 0644]
include/asm-powerpc/sembuf.h [moved from include/asm-ppc64/sembuf.h with 62% similarity]
include/asm-powerpc/shmbuf.h [moved from include/asm-ppc64/shmbuf.h with 72% similarity]
include/asm-powerpc/shmparam.h [moved from include/asm-ppc/shmparam.h with 100% similarity]
include/asm-powerpc/siginfo.h [moved from include/asm-ppc64/siginfo.h with 56% similarity]
include/asm-powerpc/socket.h [moved from include/asm-ppc64/socket.h with 85% similarity]
include/asm-powerpc/sockios.h [moved from include/asm-ppc64/sockios.h with 83% similarity]
include/asm-powerpc/string.h [moved from include/asm-ppc/string.h with 100% similarity]
include/asm-powerpc/termbits.h [moved from include/asm-ppc64/termbits.h with 97% similarity]
include/asm-powerpc/termios.h [moved from include/asm-ppc64/termios.h with 98% similarity]
include/asm-powerpc/unaligned.h [moved from include/asm-ppc/unaligned.h with 100% similarity]
include/asm-powerpc/xor.h [moved from include/asm-ppc/xor.h with 100% similarity]
include/asm-ppc/auxvec.h [new file with mode: 0644]
include/asm-ppc/bugs.h [deleted file]
include/asm-ppc/cputime.h [deleted file]
include/asm-ppc/dma-mapping.h
include/asm-ppc/elf.h
include/asm-ppc/emergency-restart.h [deleted file]
include/asm-ppc/fcntl.h [deleted file]
include/asm-ppc/futex.h [new file with mode: 0644]
include/asm-ppc/hdreg.h [deleted file]
include/asm-ppc/ibm4xx.h
include/asm-ppc/ibm_ocp.h
include/asm-ppc/irq.h
include/asm-ppc/kmap_types.h
include/asm-ppc/local.h [deleted file]
include/asm-ppc/mc146818rtc.h [deleted file]
include/asm-ppc/mman.h [deleted file]
include/asm-ppc/module.h [deleted file]
include/asm-ppc/mpc8260.h
include/asm-ppc/mpc8xx.h
include/asm-ppc/mv64x60.h
include/asm-ppc/mv64x60_defs.h
include/asm-ppc/param.h
include/asm-ppc/percpu.h [deleted file]
include/asm-ppc/pmac_feature.h
include/asm-ppc/ppc_sys.h
include/asm-ppc/resource.h [deleted file]
include/asm-ppc/sembuf.h [deleted file]
include/asm-ppc/serial.h
include/asm-ppc/shmbuf.h [deleted file]
include/asm-ppc/siginfo.h [deleted file]
include/asm-ppc/socket.h [deleted file]
include/asm-ppc/sockios.h [deleted file]
include/asm-ppc/system.h
include/asm-ppc/termbits.h [deleted file]
include/asm-ppc/termios.h [deleted file]
include/asm-ppc/types.h
include/asm-ppc/uaccess.h
include/asm-ppc64/8253pit.h [deleted file]
include/asm-ppc64/abs_addr.h
include/asm-ppc64/agp.h [deleted file]
include/asm-ppc64/auxvec.h [new file with mode: 0644]
include/asm-ppc64/bugs.h [deleted file]
include/asm-ppc64/compat.h
include/asm-ppc64/cputable.h
include/asm-ppc64/cputime.h [deleted file]
include/asm-ppc64/div64.h [deleted file]
include/asm-ppc64/elf.h
include/asm-ppc64/emergency-restart.h [deleted file]
include/asm-ppc64/errno.h [deleted file]
include/asm-ppc64/fcntl.h [deleted file]
include/asm-ppc64/firmware.h [new file with mode: 0644]
include/asm-ppc64/futex.h [new file with mode: 0644]
include/asm-ppc64/hdreg.h [deleted file]
include/asm-ppc64/imalloc.h
include/asm-ppc64/ioctl.h [deleted file]
include/asm-ppc64/ioctls.h [deleted file]
include/asm-ppc64/iommu.h
include/asm-ppc64/ipc.h [deleted file]
include/asm-ppc64/irq.h
include/asm-ppc64/kprobes.h
include/asm-ppc64/linkage.h [deleted file]
include/asm-ppc64/lmb.h
include/asm-ppc64/lppaca.h
include/asm-ppc64/machdep.h
include/asm-ppc64/memory.h
include/asm-ppc64/mmu.h
include/asm-ppc64/module.h [deleted file]
include/asm-ppc64/naca.h
include/asm-ppc64/namei.h [deleted file]
include/asm-ppc64/oprofile_impl.h [moved from arch/ppc64/oprofile/op_impl.h with 95% similarity]
include/asm-ppc64/page.h
include/asm-ppc64/param.h
include/asm-ppc64/percpu.h [deleted file]
include/asm-ppc64/pgalloc.h
include/asm-ppc64/pgtable.h
include/asm-ppc64/pmc.h
include/asm-ppc64/poll.h [deleted file]
include/asm-ppc64/processor.h
include/asm-ppc64/prom.h
include/asm-ppc64/resource.h [deleted file]
include/asm-ppc64/string.h [deleted file]
include/asm-ppc64/system.h
include/asm-ppc64/types.h
include/asm-ppc64/uaccess.h
include/asm-ppc64/udbg.h
include/asm-ppc64/unaligned.h [deleted file]
include/asm-ppc64/vio.h
include/asm-ppc64/xor.h [deleted file]
include/asm-s390/auxvec.h [new file with mode: 0644]
include/asm-s390/compat.h
include/asm-s390/debug.h
include/asm-s390/fcntl.h
include/asm-s390/futex.h [new file with mode: 0644]
include/asm-s390/lowcore.h
include/asm-s390/page.h
include/asm-s390/socket.h
include/asm-s390/spinlock.h
include/asm-s390/types.h
include/asm-s390/uaccess.h
include/asm-sh/auxvec.h [new file with mode: 0644]
include/asm-sh/fcntl.h
include/asm-sh/futex.h [new file with mode: 0644]
include/asm-sh/hdreg.h [deleted file]
include/asm-sh/page.h
include/asm-sh/socket.h
include/asm-sh/types.h
include/asm-sh/uaccess.h
include/asm-sh64/auxvec.h [new file with mode: 0644]
include/asm-sh64/fcntl.h
include/asm-sh64/futex.h [new file with mode: 0644]
include/asm-sh64/hdreg.h [deleted file]
include/asm-sh64/page.h
include/asm-sh64/types.h
include/asm-sh64/uaccess.h
include/asm-sparc/auxvec.h [new file with mode: 0644]
include/asm-sparc/fcntl.h
include/asm-sparc/futex.h [new file with mode: 0644]
include/asm-sparc/hdreg.h [deleted file]
include/asm-sparc/page.h
include/asm-sparc/pgtable.h
include/asm-sparc/processor.h
include/asm-sparc/segment.h [deleted file]
include/asm-sparc/socket.h
include/asm-sparc/system.h
include/asm-sparc/types.h
include/asm-sparc/uaccess.h
include/asm-sparc64/atomic.h
include/asm-sparc64/auxvec.h [new file with mode: 0644]
include/asm-sparc64/bitops.h
include/asm-sparc64/compat.h
include/asm-sparc64/cpudata.h
include/asm-sparc64/fcntl.h
include/asm-sparc64/futex.h [new file with mode: 0644]
include/asm-sparc64/hardirq.h
include/asm-sparc64/hdreg.h [deleted file]
include/asm-sparc64/io.h
include/asm-sparc64/page.h
include/asm-sparc64/pgtable.h
include/asm-sparc64/processor.h
include/asm-sparc64/segment.h [deleted file]
include/asm-sparc64/sfafsr.h [new file with mode: 0644]
include/asm-sparc64/socket.h
include/asm-sparc64/spinlock.h
include/asm-sparc64/system.h
include/asm-sparc64/types.h
include/asm-sparc64/uaccess.h
include/asm-um/auxvec.h [new file with mode: 0644]
include/asm-um/futex.h [new file with mode: 0644]
include/asm-um/hdreg.h [deleted file]
include/asm-um/mmu_context.h
include/asm-um/page.h
include/asm-um/pgalloc.h
include/asm-um/pgtable-2level.h
include/asm-um/pgtable-3level.h
include/asm-um/pgtable.h
include/asm-v850/auxvec.h [new file with mode: 0644]
include/asm-v850/fcntl.h
include/asm-v850/futex.h [new file with mode: 0644]
include/asm-v850/page.h
include/asm-v850/socket.h
include/asm-v850/types.h
include/asm-v850/uaccess.h
include/asm-x86_64/auxvec.h [new file with mode: 0644]
include/asm-x86_64/checksum.h
include/asm-x86_64/compat.h
include/asm-x86_64/fcntl.h
include/asm-x86_64/futex.h [new file with mode: 0644]
include/asm-x86_64/hdreg.h [deleted file]
include/asm-x86_64/page.h
include/asm-x86_64/pgtable.h
include/asm-x86_64/processor.h
include/asm-x86_64/socket.h
include/asm-x86_64/types.h
include/asm-x86_64/uaccess.h
include/asm-xtensa/atomic.h
include/asm-xtensa/auxvec.h [new file with mode: 0644]
include/asm-xtensa/checksum.h
include/asm-xtensa/delay.h
include/asm-xtensa/fcntl.h
include/asm-xtensa/hdreg.h [deleted file]
include/asm-xtensa/io.h
include/asm-xtensa/mmu_context.h
include/asm-xtensa/page.h
include/asm-xtensa/page.h.n [deleted file]
include/asm-xtensa/pci.h
include/asm-xtensa/pgtable.h
include/asm-xtensa/semaphore.h
include/asm-xtensa/socket.h
include/asm-xtensa/string.h
include/asm-xtensa/system.h
include/asm-xtensa/tlbflush.h
include/asm-xtensa/types.h
include/asm-xtensa/uaccess.h
include/linux/8250_pci.h
include/linux/ata.h
include/linux/auxvec.h [new file with mode: 0644]
include/linux/bio.h
include/linux/capability.h
include/linux/compat.h
include/linux/cpu.h
include/linux/cpuset.h
include/linux/crypto.h
include/linux/dcache.h
include/linux/dccp.h [new file with mode: 0644]
include/linux/dmi.h
include/linux/efi.h
include/linux/elf.h
include/linux/etherdevice.h
include/linux/ethtool.h
include/linux/ext2_fs.h
include/linux/ext3_fs.h
include/linux/firmware.h
include/linux/fs.h
include/linux/futex.h
include/linux/gfp.h
include/linux/hippidevice.h
include/linux/hugetlb.h
include/linux/hwmon-sysfs.h
include/linux/hwmon-vid.h [new file with mode: 0644]
include/linux/hwmon.h [new file with mode: 0644]
include/linux/i2c-id.h
include/linux/i2c-isa.h [new file with mode: 0644]
include/linux/i2c-sensor.h [deleted file]
include/linux/i2c-vid.h [deleted file]
include/linux/i2c.h
include/linux/if_ether.h
include/linux/if_fc.h
include/linux/if_fddi.h
include/linux/if_frad.h
include/linux/if_hippi.h
include/linux/if_tr.h
include/linux/if_tun.h
include/linux/if_vlan.h
include/linux/igmp.h
include/linux/in.h
include/linux/inet_diag.h [new file with mode: 0644]
include/linux/inotify.h
include/linux/input.h
include/linux/ioctl32.h
include/linux/ip.h
include/linux/ipmi.h
include/linux/ipv6.h
include/linux/irq.h
include/linux/isdn.h
include/linux/jbd.h
include/linux/klist.h
include/linux/kprobes.h
include/linux/libata.h
include/linux/linkage.h
include/linux/list.h
include/linux/mempolicy.h
include/linux/mii.h
include/linux/mmc/card.h
include/linux/mmc/host.h
include/linux/mmc/mmc.h
include/linux/mmc/protocol.h
include/linux/mmzone.h
include/linux/mod_devicetable.h
include/linux/msg.h
include/linux/mv643xx.h
include/linux/net.h
include/linux/netdevice.h
include/linux/netfilter.h
include/linux/netfilter/nfnetlink.h [new file with mode: 0644]
include/linux/netfilter/nfnetlink_conntrack.h [new file with mode: 0644]
include/linux/netfilter/nfnetlink_log.h [new file with mode: 0644]
include/linux/netfilter/nfnetlink_queue.h [new file with mode: 0644]
include/linux/netfilter_decnet.h
include/linux/netfilter_ipv4.h
include/linux/netfilter_ipv4/ip_conntrack.h
include/linux/netfilter_ipv4/ip_conntrack_core.h
include/linux/netfilter_ipv4/ip_conntrack_helper.h
include/linux/netfilter_ipv4/ip_conntrack_protocol.h
include/linux/netfilter_ipv4/ip_logging.h [deleted file]
include/linux/netfilter_ipv4/ip_nat_protocol.h
include/linux/netfilter_ipv4/ip_nat_rule.h
include/linux/netfilter_ipv4/ip_tables.h
include/linux/netfilter_ipv4/ipt_LOG.h
include/linux/netfilter_ipv4/ipt_NFQUEUE.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ipt_TTL.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ipt_connbytes.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ipt_dccp.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ipt_string.h [new file with mode: 0644]
include/linux/netfilter_ipv6.h
include/linux/netfilter_ipv6/ip6_logging.h [deleted file]
include/linux/netfilter_ipv6/ip6_tables.h
include/linux/netfilter_ipv6/ip6t_HL.h [new file with mode: 0644]
include/linux/netfilter_ipv6/ip6t_LOG.h
include/linux/netfilter_ipv6/ip6t_REJECT.h [new file with mode: 0644]
include/linux/netlink.h
include/linux/page-flags.h
include/linux/pci_ids.h
include/linux/phy.h [new file with mode: 0644]
include/linux/pipe_fs_i.h
include/linux/pm.h
include/linux/pnp.h
include/linux/ptrace.h
include/linux/random.h
include/linux/relayfs_fs.h [new file with mode: 0644]
include/linux/rtnetlink.h
include/linux/sched.h
include/linux/security.h
include/linux/selinux_netlink.h
include/linux/sem.h
include/linux/serial.h
include/linux/serialP.h
include/linux/serial_8250.h
include/linux/serial_core.h
include/linux/skbuff.h
include/linux/slab.h
include/linux/socket.h
include/linux/sonypi.h
include/linux/sound.h
include/linux/sunrpc/cache.h
include/linux/swap.h
include/linux/swapops.h
include/linux/sysctl.h
include/linux/tcp.h
include/linux/tcp_diag.h [deleted file]
include/linux/time.h
include/linux/timex.h
include/linux/topology.h
include/linux/types.h
include/linux/vmalloc.h
include/linux/wireless.h
include/linux/xfrm.h
include/media/id.h
include/net/act_api.h
include/net/addrconf.h
include/net/af_unix.h
include/net/arp.h
include/net/ax25.h
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/rfcomm.h
include/net/datalink.h
include/net/dn.h
include/net/icmp.h
include/net/ieee80211.h
include/net/ieee80211_crypt.h [new file with mode: 0644]
include/net/inet6_hashtables.h [new file with mode: 0644]
include/net/inet_common.h
include/net/inet_connection_sock.h [new file with mode: 0644]
include/net/inet_hashtables.h [new file with mode: 0644]
include/net/inet_timewait_sock.h [new file with mode: 0644]
include/net/ip.h
include/net/ip6_route.h
include/net/ip_fib.h
include/net/ip_vs.h
include/net/ipv6.h
include/net/irda/irlan_filter.h
include/net/iw_handler.h
include/net/llc.h
include/net/neighbour.h
include/net/p8022.h
include/net/pkt_cls.h
include/net/psnap.h
include/net/raw.h
include/net/rawv6.h
include/net/request_sock.h
include/net/route.h
include/net/sctp/constants.h
include/net/sock.h
include/net/tcp.h
include/net/tcp_ecn.h
include/net/tcp_states.h [new file with mode: 0644]
include/net/udp.h
include/net/x25.h
include/net/x25device.h
include/net/xfrm.h
include/rdma/ib_cache.h [moved from drivers/infiniband/include/ib_cache.h with 96% similarity]
include/rdma/ib_cm.h [moved from drivers/infiniband/include/ib_cm.h with 88% similarity]
include/rdma/ib_fmr_pool.h [moved from drivers/infiniband/include/ib_fmr_pool.h with 99% similarity]
include/rdma/ib_mad.h [moved from drivers/infiniband/include/ib_mad.h with 98% similarity]
include/rdma/ib_pack.h [moved from drivers/infiniband/include/ib_pack.h with 99% similarity]
include/rdma/ib_sa.h [moved from drivers/infiniband/include/ib_sa.h with 98% similarity]
include/rdma/ib_smi.h [moved from drivers/infiniband/include/ib_smi.h with 95% similarity]
include/rdma/ib_user_cm.h [moved from drivers/infiniband/include/ib_user_cm.h with 95% similarity]
include/rdma/ib_user_mad.h [moved from drivers/infiniband/include/ib_user_mad.h with 97% similarity]
include/rdma/ib_user_verbs.h [moved from drivers/infiniband/include/ib_user_verbs.h with 92% similarity]
include/rdma/ib_verbs.h [moved from drivers/infiniband/include/ib_verbs.h with 91% similarity]
include/sound/ac97_codec.h
include/sound/ad1816a.h
include/sound/asound.h
include/sound/core.h
include/sound/cs46xx.h
include/sound/emu10k1.h
include/sound/gus.h
include/sound/pcm.h
include/sound/version.h
include/sound/ymfpci.h
include/video/pmag-ba-fb.h
include/video/pmagb-b-fb.h
include/video/w100fb.h
init/Kconfig
init/Makefile
init/do_mounts.c
init/main.c
ipc/compat.c
ipc/msg.c
ipc/sem.c
ipc/shm.c
ipc/util.c
ipc/util.h
kernel/Makefile
kernel/acct.c
kernel/audit.c
kernel/cpuset.c
kernel/fork.c
kernel/futex.c
kernel/intermodule.c
kernel/irq/handle.c
kernel/irq/manage.c
kernel/irq/proc.c
kernel/kprobes.c
kernel/module.c
kernel/params.c
kernel/posix-timers.c
kernel/power/Kconfig
kernel/power/disk.c
kernel/power/main.c
kernel/power/pm.c
kernel/power/process.c
kernel/power/swsusp.c
kernel/printk.c
kernel/ptrace.c
kernel/resource.c
kernel/sched.c
kernel/signal.c
kernel/softlockup.c [new file with mode: 0644]
kernel/sys.c
kernel/sysctl.c
kernel/timer.c
kernel/workqueue.c
lib/Kconfig
lib/Kconfig.debug
lib/Makefile
lib/klist.c
lib/kobject_uevent.c
lib/radix-tree.c
lib/semaphore-sleepers.c [moved from arch/x86_64/kernel/semaphore.c with 94% similarity]
lib/ts_bm.c [new file with mode: 0644]
mm/Kconfig
mm/filemap.c
mm/hugetlb.c
mm/madvise.c
mm/memory.c
mm/mempolicy.c
mm/mmap.c
mm/mremap.c
mm/oom_kill.c
mm/page_alloc.c
mm/readahead.c
mm/rmap.c
mm/shmem.c
mm/slab.c
mm/sparse.c
mm/swap_state.c
mm/swapfile.c
mm/vmalloc.c
mm/vmscan.c
net/802/fc.c
net/802/fddi.c
net/802/hippi.c
net/802/p8022.c
net/802/p8023.c
net/802/psnap.c
net/802/sysctl_net_802.c
net/8021q/vlan.h
net/8021q/vlan_dev.c
net/Kconfig
net/Makefile
net/appletalk/aarp.c
net/appletalk/ddp.c
net/atm/ioctl.c
net/atm/ipcommon.c
net/ax25/af_ax25.c
net/ax25/ax25_addr.c
net/ax25/ax25_ds_in.c
net/ax25/ax25_ds_timer.c
net/ax25/ax25_in.c
net/ax25/ax25_route.c
net/ax25/ax25_std_in.c
net/ax25/ax25_std_timer.c
net/ax25/ax25_subr.c
net/ax25/ax25_uid.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sock.c
net/bluetooth/l2cap.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/rfcomm/tty.c
net/bluetooth/sco.c
net/bridge/br_fdb.c
net/bridge/netfilter/ebt_mark.c
net/bridge/netfilter/ebt_ulog.c
net/core/Makefile
net/core/datagram.c
net/core/dev.c
net/core/ethtool.c
net/core/filter.c
net/core/flow.c
net/core/neighbour.c
net/core/netfilter.c [deleted file]
net/core/request_sock.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/core/sysctl_net_core.c
net/core/utils.c
net/core/wireless.c
net/dccp/Kconfig [new file with mode: 0644]
net/dccp/Makefile [new file with mode: 0644]
net/dccp/ccid.c [new file with mode: 0644]
net/dccp/ccid.h [new file with mode: 0644]
net/dccp/ccids/Kconfig [new file with mode: 0644]
net/dccp/ccids/Makefile [new file with mode: 0644]
net/dccp/ccids/ccid3.c [new file with mode: 0644]
net/dccp/ccids/ccid3.h [new file with mode: 0644]
net/dccp/ccids/lib/Makefile [new file with mode: 0644]
net/dccp/ccids/lib/loss_interval.c [new file with mode: 0644]
net/dccp/ccids/lib/loss_interval.h [new file with mode: 0644]
net/dccp/ccids/lib/packet_history.c [new file with mode: 0644]
net/dccp/ccids/lib/packet_history.h [new file with mode: 0644]
net/dccp/ccids/lib/tfrc.h [new file with mode: 0644]
net/dccp/ccids/lib/tfrc_equation.c [new file with mode: 0644]
net/dccp/dccp.h [new file with mode: 0644]
net/dccp/diag.c [new file with mode: 0644]
net/dccp/input.c [new file with mode: 0644]
net/dccp/ipv4.c [new file with mode: 0644]
net/dccp/minisocks.c [new file with mode: 0644]
net/dccp/options.c [new file with mode: 0644]
net/dccp/output.c [new file with mode: 0644]
net/dccp/proto.c [new file with mode: 0644]
net/dccp/timer.c [new file with mode: 0644]
net/decnet/af_decnet.c
net/decnet/dn_dev.c
net/decnet/dn_nsp_in.c
net/decnet/dn_nsp_out.c
net/decnet/dn_route.c
net/decnet/dn_table.c
net/decnet/netfilter/dn_rtmsg.c
net/econet/af_econet.c
net/ethernet/eth.c
net/ethernet/sysctl_net_ether.c
net/ieee80211/Kconfig [new file with mode: 0644]
net/ieee80211/Makefile [new file with mode: 0644]
net/ieee80211/ieee80211_crypt.c [new file with mode: 0644]
net/ieee80211/ieee80211_crypt_ccmp.c [new file with mode: 0644]
net/ieee80211/ieee80211_crypt_tkip.c [new file with mode: 0644]
net/ieee80211/ieee80211_crypt_wep.c [new file with mode: 0644]
net/ieee80211/ieee80211_module.c [new file with mode: 0644]
net/ieee80211/ieee80211_rx.c [new file with mode: 0644]
net/ieee80211/ieee80211_tx.c [new file with mode: 0644]
net/ieee80211/ieee80211_wx.c [new file with mode: 0644]
net/ipv4/Kconfig
net/ipv4/Makefile
net/ipv4/af_inet.c
net/ipv4/ah4.c
net/ipv4/arp.c
net/ipv4/datagram.c
net/ipv4/devinet.c
net/ipv4/esp4.c
net/ipv4/fib_frontend.c
net/ipv4/fib_hash.c
net/ipv4/fib_lookup.h
net/ipv4/fib_semantics.c
net/ipv4/fib_trie.c
net/ipv4/icmp.c
net/ipv4/igmp.c
net/ipv4/inet_connection_sock.c [new file with mode: 0644]
net/ipv4/inet_diag.c [new file with mode: 0644]
net/ipv4/inet_hashtables.c [new file with mode: 0644]
net/ipv4/inet_timewait_sock.c [new file with mode: 0644]
net/ipv4/inetpeer.c
net/ipv4/ip_forward.c
net/ipv4/ip_fragment.c
net/ipv4/ip_input.c
net/ipv4/ip_options.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/ipcomp.c
net/ipv4/ipconfig.c
net/ipv4/ipmr.c
net/ipv4/ipvs/ip_vs_app.c
net/ipv4/ipvs/ip_vs_conn.c
net/ipv4/ipvs/ip_vs_core.c
net/ipv4/ipvs/ip_vs_ctl.c
net/ipv4/ipvs/ip_vs_lblc.c
net/ipv4/ipvs/ip_vs_lblcr.c
net/ipv4/ipvs/ip_vs_proto_tcp.c
net/ipv4/ipvs/ip_vs_xmit.c
net/ipv4/multipath_drr.c
net/ipv4/netfilter.c [new file with mode: 0644]
net/ipv4/netfilter/Kconfig
net/ipv4/netfilter/Makefile
net/ipv4/netfilter/ip_conntrack_amanda.c
net/ipv4/netfilter/ip_conntrack_core.c
net/ipv4/netfilter/ip_conntrack_ftp.c
net/ipv4/netfilter/ip_conntrack_irc.c
net/ipv4/netfilter/ip_conntrack_netbios_ns.c [new file with mode: 0644]
net/ipv4/netfilter/ip_conntrack_netlink.c [new file with mode: 0644]
net/ipv4/netfilter/ip_conntrack_proto_icmp.c
net/ipv4/netfilter/ip_conntrack_proto_sctp.c
net/ipv4/netfilter/ip_conntrack_proto_tcp.c
net/ipv4/netfilter/ip_conntrack_proto_udp.c
net/ipv4/netfilter/ip_conntrack_standalone.c
net/ipv4/netfilter/ip_conntrack_tftp.c
net/ipv4/netfilter/ip_nat_core.c
net/ipv4/netfilter/ip_nat_helper.c
net/ipv4/netfilter/ip_nat_proto_icmp.c
net/ipv4/netfilter/ip_nat_proto_tcp.c
net/ipv4/netfilter/ip_nat_proto_udp.c
net/ipv4/netfilter/ip_nat_proto_unknown.c
net/ipv4/netfilter/ip_nat_rule.c
net/ipv4/netfilter/ip_nat_snmp_basic.c
net/ipv4/netfilter/ip_nat_standalone.c
net/ipv4/netfilter/ip_queue.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/ipt_CLASSIFY.c
net/ipv4/netfilter/ipt_CLUSTERIP.c
net/ipv4/netfilter/ipt_CONNMARK.c
net/ipv4/netfilter/ipt_DSCP.c
net/ipv4/netfilter/ipt_ECN.c
net/ipv4/netfilter/ipt_LOG.c
net/ipv4/netfilter/ipt_MARK.c
net/ipv4/netfilter/ipt_MASQUERADE.c
net/ipv4/netfilter/ipt_NETMAP.c
net/ipv4/netfilter/ipt_NFQUEUE.c [new file with mode: 0644]
net/ipv4/netfilter/ipt_REJECT.c
net/ipv4/netfilter/ipt_TCPMSS.c
net/ipv4/netfilter/ipt_TOS.c
net/ipv4/netfilter/ipt_TTL.c [new file with mode: 0644]
net/ipv4/netfilter/ipt_ULOG.c
net/ipv4/netfilter/ipt_connbytes.c [new file with mode: 0644]
net/ipv4/netfilter/ipt_connmark.c
net/ipv4/netfilter/ipt_dccp.c [new file with mode: 0644]
net/ipv4/netfilter/ipt_hashlimit.c
net/ipv4/netfilter/ipt_mark.c
net/ipv4/netfilter/ipt_owner.c
net/ipv4/netfilter/ipt_string.c [new file with mode: 0644]
net/ipv4/proc.c
net/ipv4/protocol.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/syncookies.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_bic.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_diag.c
net/ipv4/tcp_highspeed.c
net/ipv4/tcp_htcp.c
net/ipv4/tcp_hybla.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_output.c
net/ipv4/tcp_scalable.c
net/ipv4/tcp_timer.c
net/ipv4/tcp_vegas.c
net/ipv4/tcp_westwood.c
net/ipv4/udp.c
net/ipv4/xfrm4_state.c
net/ipv6/Makefile
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/ah6.c
net/ipv6/datagram.c
net/ipv6/esp6.c
net/ipv6/exthdrs.c
net/ipv6/icmp.c
net/ipv6/inet6_hashtables.c [new file with mode: 0644]
net/ipv6/ip6_fib.c
net/ipv6/ip6_input.c
net/ipv6/ip6_output.c
net/ipv6/ipcomp6.c
net/ipv6/ipv6_sockglue.c
net/ipv6/ipv6_syms.c
net/ipv6/ndisc.c
net/ipv6/netfilter.c [new file with mode: 0644]
net/ipv6/netfilter/Kconfig
net/ipv6/netfilter/Makefile
net/ipv6/netfilter/ip6_queue.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/netfilter/ip6t_HL.c [new file with mode: 0644]
net/ipv6/netfilter/ip6t_LOG.c
net/ipv6/netfilter/ip6t_MARK.c
net/ipv6/netfilter/ip6t_NFQUEUE.c [new file with mode: 0644]
net/ipv6/netfilter/ip6t_REJECT.c [new file with mode: 0644]
net/ipv6/netfilter/ip6t_owner.c
net/ipv6/raw.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/sysctl_net_ipv6.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipv6/xfrm6_tunnel.c
net/ipx/af_ipx.c
net/ipx/ipx_proc.c
net/irda/af_irda.c
net/irda/irlan/irlan_filter.c
net/irda/irlap_frame.c
net/irda/irlmp.c
net/irda/irmod.c
net/irda/irnet/irnet.h
net/irda/irnet/irnet_ppp.c
net/irda/irqueue.c
net/irda/qos.c
net/lapb/lapb_subr.c
net/llc/af_llc.c
net/llc/llc_conn.c
net/llc/llc_core.c
net/llc/llc_if.c
net/llc/llc_input.c
net/llc/llc_sap.c
net/netfilter/Kconfig [new file with mode: 0644]
net/netfilter/Makefile [new file with mode: 0644]
net/netfilter/core.c [new file with mode: 0644]
net/netfilter/nf_internals.h [new file with mode: 0644]
net/netfilter/nf_log.c [new file with mode: 0644]
net/netfilter/nf_queue.c [new file with mode: 0644]
net/netfilter/nf_sockopt.c [new file with mode: 0644]
net/netfilter/nfnetlink.c [new file with mode: 0644]
net/netfilter/nfnetlink_log.c [new file with mode: 0644]
net/netfilter/nfnetlink_queue.c [new file with mode: 0644]
net/netlink/af_netlink.c
net/netrom/af_netrom.c
net/netrom/nr_dev.c
net/netrom/nr_in.c
net/netrom/nr_route.c
net/netrom/nr_subr.c
net/netrom/nr_timer.c
net/packet/af_packet.c
net/rose/af_rose.c
net/rose/rose_in.c
net/rose/rose_route.c
net/rose/rose_subr.c
net/rose/rose_timer.c
net/rxrpc/transport.c
net/sched/Kconfig
net/sched/act_api.c
net/sched/cls_api.c
net/sched/gact.c
net/sched/ipt.c
net/sched/mirred.c
net/sched/pedit.c
net/sched/police.c
net/sched/sch_api.c
net/sched/sch_generic.c
net/sched/simple.c
net/sctp/endpointola.c
net/sctp/input.c
net/sctp/ipv6.c
net/sctp/protocol.c
net/sctp/sm_make_chunk.c
net/sctp/socket.c
net/sctp/sysctl.c
net/sctp/ulpqueue.c
net/socket.c
net/sunrpc/auth_gss/gss_krb5_crypto.c
net/sunrpc/auth_gss/gss_krb5_mech.c
net/sunrpc/auth_gss/gss_spkm3_mech.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/cache.c
net/sunrpc/rpc_pipe.c
net/sunrpc/sched.c
net/sunrpc/stats.c
net/sunrpc/sunrpc_syms.c
net/sunrpc/svcauth.c
net/sunrpc/svcauth_unix.c
net/sunrpc/svcsock.c
net/sysctl_net.c
net/unix/af_unix.c
net/unix/garbage.c
net/unix/sysctl_net_unix.c
net/wanrouter/af_wanpipe.c
net/x25/af_x25.c
net/x25/x25_dev.c
net/x25/x25_in.c
net/x25/x25_subr.c
net/x25/x25_timer.c
net/xfrm/xfrm_input.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_user.c
scripts/Kbuild.include [new file with mode: 0644]
scripts/Makefile.build
scripts/Makefile.clean
scripts/Makefile.host
scripts/Makefile.lib
scripts/Makefile.modinst
scripts/Makefile.modpost
scripts/conmakehash.c
scripts/kallsyms.c
scripts/kconfig/Makefile
scripts/kconfig/kxgettext.c
scripts/kconfig/lkc.h
scripts/kconfig/menu.c
scripts/kconfig/zconf.tab.c_shipped
scripts/kconfig/zconf.y
scripts/kernel-doc
scripts/lxdialog/dialog.h
scripts/lxdialog/inputbox.c
scripts/mkcompile_h
scripts/mod/file2alias.c
scripts/mod/sumversion.c
scripts/package/Makefile
scripts/package/builddeb
scripts/package/buildtar [new file with mode: 0644]
scripts/package/mkspec
scripts/reference_discarded.pl
scripts/reference_init.pl
scripts/setlocalversion [new file with mode: 0644]
scripts/ver_linux
security/seclvl.c
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/include/security.h
security/selinux/netlink.c
security/selinux/nlmsgtab.c
security/selinux/ss/avtab.c
security/selinux/ss/avtab.h
security/selinux/ss/conditional.c
security/selinux/ss/ebitmap.c
security/selinux/ss/ebitmap.h
security/selinux/ss/mls.c
security/selinux/ss/policydb.c
security/selinux/ss/policydb.h
security/selinux/ss/services.c
sound/arm/Makefile
sound/arm/aaci.c
sound/arm/aaci.h
sound/arm/pxa2xx-ac97.c
sound/core/memalloc.c
sound/core/memory.c
sound/core/oss/pcm_oss.c
sound/core/pcm_compat.c
sound/core/pcm_lib.c
sound/core/pcm_native.c
sound/core/sound_oss.c
sound/core/timer.c
sound/drivers/vx/vx_mixer.c
sound/drivers/vx/vx_pcm.c
sound/isa/Kconfig
sound/isa/ad1816a/ad1816a.c
sound/isa/ad1816a/ad1816a_lib.c
sound/isa/ad1848/ad1848_lib.c
sound/isa/cmi8330.c
sound/isa/cs423x/cs4231_lib.c
sound/isa/gus/gus_io.c
sound/isa/opl3sa2.c
sound/isa/sb/sb16_main.c
sound/oss/os.h
sound/pci/Kconfig
sound/pci/ac97/Makefile
sound/pci/ac97/ac97_bus.c [new file with mode: 0644]
sound/pci/ac97/ac97_codec.c
sound/pci/ac97/ac97_patch.c
sound/pci/ac97/ac97_patch.h
sound/pci/ali5451/ali5451.c
sound/pci/atiixp.c
sound/pci/au88x0/au88x0_pcm.c
sound/pci/ca0106/ca0106_main.c
sound/pci/ca0106/ca0106_mixer.c
sound/pci/cmipci.c
sound/pci/cs46xx/cs46xx.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1_main.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/emu10k1/emufx.c
sound/pci/emu10k1/emumixer.c
sound/pci/emu10k1/emupcm.c
sound/pci/ens1370.c
sound/pci/fm801.c
sound/pci/hda/Makefile
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_patch.h
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_si3054.c [new file with mode: 0644]
sound/pci/ice1712/delta.c
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1724.c
sound/pci/intel8x0.c
sound/pci/korg1212/korg1212.c
sound/pci/nm256/nm256.c
sound/pci/rme32.c
sound/pci/rme96.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/pci/rme9652/rme9652.c
sound/pci/trident/trident_main.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/ymfpci/ymfpci_main.c
sound/pcmcia/vx/vxpocket.c
sound/sound_core.c
sound/synth/emux/emux_synth.c
sound/usb/usbaudio.c
sound/usb/usbmidi.c
sound/usb/usx2y/usx2yhwdeppcm.c
usr/Kconfig [new file with mode: 0644]
usr/Makefile

index 4367f4642f3df8f9836673f69fb92bf480ace525..42a760cd7467a422142f5f2ea83c3072fcf08481 100644 (file)
@@ -96,7 +96,7 @@
 
   <chapter id="pubfunctions">
      <title>Public Functions Provided</title>
-!Earch/i386/kernel/mca.c
+!Edrivers/mca/mca-legacy.c
   </chapter>
 
   <chapter id="dmafunctions">
index 84d3d4d10c175943a86f12bd735694be19529eb7..bf1cf98d2a275b878d9e32378028b52d01ae8048 100644 (file)
@@ -605,12 +605,13 @@ is in the ipmi_poweroff module.  When the system requests a powerdown,
 it will send the proper IPMI commands to do this.  This is supported on
 several platforms.
 
-There is a module parameter named "poweroff_control" that may either be zero
-(do a power down) or 2 (do a power cycle, power the system off, then power
-it on in a few seconds).  Setting ipmi_poweroff.poweroff_control=x will do
-the same thing on the kernel command line.  The parameter is also available
-via the proc filesystem in /proc/ipmi/poweroff_control.  Note that if the
-system does not support power cycling, it will always to the power off.
+There is a module parameter named "poweroff_powercycle" that may
+either be zero (do a power down) or non-zero (do a power cycle, power
+the system off, then power it on in a few seconds).  Setting
+ipmi_poweroff.poweroff_control=x will do the same thing on the kernel
+command line.  The parameter is also available via the proc filesystem
+in /proc/sys/dev/ipmi/poweroff_powercycle.  Note that if the system
+does not support power cycling, it will always do the power off.
 
 Note that if you have ACPI enabled, the system will prefer using ACPI to
 power off.
diff --git a/Documentation/RCU/NMI-RCU.txt b/Documentation/RCU/NMI-RCU.txt
new file mode 100644 (file)
index 0000000..d0634a5
--- /dev/null
@@ -0,0 +1,112 @@
+Using RCU to Protect Dynamic NMI Handlers
+
+
+Although RCU is usually used to protect read-mostly data structures,
+it is possible to use RCU to provide dynamic non-maskable interrupt
+handlers, as well as dynamic irq handlers.  This document describes
+how to do this, drawing loosely from Zwane Mwaikambo's NMI-timer
+work in "arch/i386/oprofile/nmi_timer_int.c" and in
+"arch/i386/kernel/traps.c".
+
+The relevant pieces of code are listed below, each followed by a
+brief explanation.
+
+       static int dummy_nmi_callback(struct pt_regs *regs, int cpu)
+       {
+               return 0;
+       }
+
+The dummy_nmi_callback() function is a "dummy" NMI handler that does
+nothing, but returns zero, thus saying that it did nothing, allowing
+the NMI handler to take the default machine-specific action.
+
+       static nmi_callback_t nmi_callback = dummy_nmi_callback;
+
+This nmi_callback variable is a global function pointer to the current
+NMI handler.
+
+       fastcall void do_nmi(struct pt_regs * regs, long error_code)
+       {
+               int cpu;
+
+               nmi_enter();
+
+               cpu = smp_processor_id();
+               ++nmi_count(cpu);
+
+               if (!rcu_dereference(nmi_callback)(regs, cpu))
+                       default_do_nmi(regs);
+
+               nmi_exit();
+       }
+
+The do_nmi() function processes each NMI.  It first disables preemption
+in the same way that a hardware irq would, then increments the per-CPU
+count of NMIs.  It then invokes the NMI handler stored in the nmi_callback
+function pointer.  If this handler returns zero, do_nmi() invokes the
+default_do_nmi() function to handle a machine-specific NMI.  Finally,
+preemption is restored.
+
+Strictly speaking, rcu_dereference() is not needed, since this code runs
+only on i386, which does not need rcu_dereference() anyway.  However,
+it is a good documentation aid, particularly for anyone attempting to
+do something similar on Alpha.
+
+Quick Quiz:  Why might the rcu_dereference() be necessary on Alpha,
+            given that the code referenced by the pointer is read-only?
+
+
+Back to the discussion of NMI and RCU...
+
+       void set_nmi_callback(nmi_callback_t callback)
+       {
+               rcu_assign_pointer(nmi_callback, callback);
+       }
+
+The set_nmi_callback() function registers an NMI handler.  Note that any
+data that is to be used by the callback must be initialized up -before-
+the call to set_nmi_callback().  On architectures that do not order
+writes, the rcu_assign_pointer() ensures that the NMI handler sees the
+initialized values.
+
+       void unset_nmi_callback(void)
+       {
+               rcu_assign_pointer(nmi_callback, dummy_nmi_callback);
+       }
+
+This function unregisters an NMI handler, restoring the original
+dummy_nmi_handler().  However, there may well be an NMI handler
+currently executing on some other CPU.  We therefore cannot free
+up any data structures used by the old NMI handler until execution
+of it completes on all other CPUs.
+
+One way to accomplish this is via synchronize_sched(), perhaps as
+follows:
+
+       unset_nmi_callback();
+       synchronize_sched();
+       kfree(my_nmi_data);
+
+This works because synchronize_sched() blocks until all CPUs complete
+any preemption-disabled segments of code that they were executing.
+Since NMI handlers disable preemption, synchronize_sched() is guaranteed
+not to return until all ongoing NMI handlers exit.  It is therefore safe
+to free up the handler's data as soon as synchronize_sched() returns.
+
+
+Answer to Quick Quiz
+
+       Why might the rcu_dereference() be necessary on Alpha, given
+       that the code referenced by the pointer is read-only?
+
+       Answer: The caller to set_nmi_callback() might well have
+               initialized some data that is to be used by the
+               new NMI handler.  In this case, the rcu_dereference()
+               would be needed, because otherwise a CPU that received
+               an NMI just after the new handler was set might see
+               the pointer to the new NMI handler, but the old
+               pre-initialized version of the handler's data.
+
+               More important, the rcu_dereference() makes it clear
+               to someone reading the code that the pointer is being
+               protected by RCU.
index 59581a4b302af8573bfb31487ecaff50ff292905..b81e109970aa837d66e01d298c76c1f5e298c6f5 100644 (file)
@@ -68,7 +68,8 @@ it a better device citizen.  Further thanks to Joel Katz
 Porfiri Claudio <C.Porfiri@nisms.tei.ericsson.se> for patches
 to make the driver work with the older CDU-510/515 series, and
 Heiko Eissfeldt <heiko@colossus.escape.de> for pointing out that
-the verify_area() checks were ignoring the results of said checks.
+the verify_area() checks were ignoring the results of said checks
+(note: verify_area() has since been replaced by access_ok()).
 
 (Acknowledgments from Ron Jeppesen in the 0.3 release:)
 Thanks to Corey Minyard who wrote the original CDU-31A driver on which
index ad944c06031294cc35265d82ecf2a8fcc12586de..47f4114fbf545459efbdad232392d93357eb6968 100644 (file)
@@ -60,6 +60,18 @@ all of the cpus in the system. This removes any overhead due to
 load balancing code trying to pull tasks outside of the cpu exclusive
 cpuset only to be prevented by the tasks' cpus_allowed mask.
 
+A cpuset that is mem_exclusive restricts kernel allocations for
+page, buffer and other data commonly shared by the kernel across
+multiple users.  All cpusets, whether mem_exclusive or not, restrict
+allocations of memory for user space.  This enables configuring a
+system so that several independent jobs can share common kernel
+data, such as file system pages, while isolating each jobs user
+allocation in its own cpuset.  To do this, construct a large
+mem_exclusive cpuset to hold all the jobs, and construct child,
+non-mem_exclusive cpusets for each individual job.  Only a small
+amount of typical kernel memory, such as requests from interrupt
+handlers, is allowed to be taken outside even a mem_exclusive cpuset.
+
 User level code may create and destroy cpusets by name in the cpuset
 virtual file system, manage the attributes and permissions of these
 cpusets and which CPUs and Memory Nodes are assigned to each cpuset,
index a2d5b490077298e1b4d365eee679aaf7f877c727..74dffc68ff9f79f9c25409c791f8aaaf7f3188f3 100644 (file)
@@ -223,6 +223,7 @@ CAST5 algorithm contributors:
 
 TEA/XTEA algorithm contributors:
   Aaron Grothe
+  Michael Ringe
 
 Khazad algorithm contributors:
   Aaron Grothe
diff --git a/Documentation/dcdbas.txt b/Documentation/dcdbas.txt
new file mode 100644 (file)
index 0000000..e1c52e2
--- /dev/null
@@ -0,0 +1,91 @@
+Overview
+
+The Dell Systems Management Base Driver provides a sysfs interface for
+systems management software such as Dell OpenManage to perform system
+management interrupts and host control actions (system power cycle or
+power off after OS shutdown) on certain Dell systems.
+
+Dell OpenManage requires this driver on the following Dell PowerEdge systems:
+300, 1300, 1400, 400SC, 500SC, 1500SC, 1550, 600SC, 1600SC, 650, 1655MC,
+700, and 750.  Other Dell software such as the open source libsmbios project
+is expected to make use of this driver, and it may include the use of this
+driver on other Dell systems.
+
+The Dell libsmbios project aims towards providing access to as much BIOS
+information as possible.  See http://linux.dell.com/libsmbios/main/ for
+more information about the libsmbios project.
+
+
+System Management Interrupt
+
+On some Dell systems, systems management software must access certain
+management information via a system management interrupt (SMI).  The SMI data
+buffer must reside in 32-bit address space, and the physical address of the
+buffer is required for the SMI.  The driver maintains the memory required for
+the SMI and provides a way for the application to generate the SMI.
+The driver creates the following sysfs entries for systems management
+software to perform these system management interrupts:
+
+/sys/devices/platform/dcdbas/smi_data
+/sys/devices/platform/dcdbas/smi_data_buf_phys_addr
+/sys/devices/platform/dcdbas/smi_data_buf_size
+/sys/devices/platform/dcdbas/smi_request
+
+Systems management software must perform the following steps to execute
+a SMI using this driver:
+
+1) Lock smi_data.
+2) Write system management command to smi_data.
+3) Write "1" to smi_request to generate a calling interface SMI or
+   "2" to generate a raw SMI.
+4) Read system management command response from smi_data.
+5) Unlock smi_data.
+
+
+Host Control Action
+
+Dell OpenManage supports a host control feature that allows the administrator
+to perform a power cycle or power off of the system after the OS has finished
+shutting down.  On some Dell systems, this host control feature requires that
+a driver perform a SMI after the OS has finished shutting down.
+
+The driver creates the following sysfs entries for systems management software
+to schedule the driver to perform a power cycle or power off host control
+action after the system has finished shutting down:
+
+/sys/devices/platform/dcdbas/host_control_action
+/sys/devices/platform/dcdbas/host_control_smi_type
+/sys/devices/platform/dcdbas/host_control_on_shutdown
+
+Dell OpenManage performs the following steps to execute a power cycle or
+power off host control action using this driver:
+
+1) Write host control action to be performed to host_control_action.
+2) Write type of SMI that driver needs to perform to host_control_smi_type.
+3) Write "1" to host_control_on_shutdown to enable host control action.
+4) Initiate OS shutdown.
+   (Driver will perform host control SMI when it is notified that the OS
+   has finished shutting down.)
+
+
+Host Control SMI Type
+
+The following table shows the value to write to host_control_smi_type to
+perform a power cycle or power off host control action:
+
+PowerEdge System    Host Control SMI Type
+----------------    ---------------------
+      300             HC_SMITYPE_TYPE1
+     1300             HC_SMITYPE_TYPE1
+     1400             HC_SMITYPE_TYPE2
+      500SC           HC_SMITYPE_TYPE2
+     1500SC           HC_SMITYPE_TYPE2
+     1550             HC_SMITYPE_TYPE2
+      600SC           HC_SMITYPE_TYPE2
+     1600SC           HC_SMITYPE_TYPE2
+      650             HC_SMITYPE_TYPE2
+     1655MC           HC_SMITYPE_TYPE2
+      700             HC_SMITYPE_TYPE3
+      750             HC_SMITYPE_TYPE3
+
+
diff --git a/Documentation/dell_rbu.txt b/Documentation/dell_rbu.txt
new file mode 100644 (file)
index 0000000..bcfa5c3
--- /dev/null
@@ -0,0 +1,74 @@
+Purpose:
+Demonstrate the usage of the new open sourced rbu (Remote BIOS Update) driver
+for updating BIOS images on Dell servers and desktops.
+
+Scope:
+This document discusses the functionality of the rbu driver only.
+It does not cover the support needed from aplications to enable the BIOS to
+update itself with the image downloaded in to the memory.
+
+Overview:
+This driver works with Dell OpenManage or Dell Update Packages for updating
+the BIOS on Dell servers (starting from servers sold since 1999), desktops
+and notebooks (starting from those sold in 2005).
+Please go to  http://support.dell.com register and you can find info on
+OpenManage and Dell Update packages (DUP).
+
+Dell_RBU driver supports BIOS update using the monilothic image and packetized
+image methods. In case of moniolithic the driver allocates a contiguous chunk
+of physical pages having the BIOS image. In case of packetized the app
+using the driver breaks the image in to packets of fixed sizes and the driver
+would place each packet in contiguous physical memory. The driver also
+maintains a link list of packets for reading them back.
+If the dell_rbu driver is unloaded all the allocated memory is freed.
+
+The rbu driver needs to have an application which will inform the BIOS to
+enable the update in the next system reboot.
+
+The user should not unload the rbu driver after downloading the BIOS image
+or updating.
+
+The driver load creates the following directories under the /sys file system.
+/sys/class/firmware/dell_rbu/loading
+/sys/class/firmware/dell_rbu/data
+/sys/devices/platform/dell_rbu/image_type
+/sys/devices/platform/dell_rbu/data
+
+The driver supports two types of update mechanism; monolithic and packetized.
+These update mechanism depends upon the BIOS currently running on the system.
+Most of the Dell systems support a monolithic update where the BIOS image is
+copied to a single contiguous block of physical memory.
+In case of packet mechanism the single memory can be broken in smaller chuks
+of contiguous memory and the BIOS image is scattered in these packets.
+
+By default the driver uses monolithic memory for the update type. This can be
+changed to contiguous during the driver load time by specifying the load
+parameter image_type=packet.  This can also be changed later as below
+echo packet > /sys/devices/platform/dell_rbu/image_type
+
+Do the steps below to download the BIOS image.
+1) echo 1 > /sys/class/firmware/dell_rbu/loading
+2) cp bios_image.hdr /sys/class/firmware/dell_rbu/data
+3) echo 0 > /sys/class/firmware/dell_rbu/loading
+
+The /sys/class/firmware/dell_rbu/ entries will remain till the following is
+done.
+echo -1 > /sys/class/firmware/dell_rbu/loading
+
+Until this step is completed the drivr cannot be unloaded.
+
+Also the driver provides /sys/devices/platform/dell_rbu/data readonly file to
+read back the image downloaded. This is useful in case of packet update
+mechanism where the above steps 1,2,3 will repeated for every packet.
+By reading the /sys/devices/platform/dell_rbu/data file all packet data
+downloaded can be verified in a single file.
+The packets are arranged in this file one after the other in a FIFO order.
+
+NOTE:
+This driver requires a patch for firmware_class.c which has the addition
+of request_firmware_nowait_nohotplug function to wortk
+Also after updating the BIOS image an user mdoe application neeeds to execute
+code which message the BIOS update request to the BIOS. So on the next reboot
+the BIOS knows about the new image downloaded and it updates it self.
+Also don't unload the rbu drive if the image has to be updated.
+
index e6b8d05bc08d1b3d95c213a29023fbdd73802ff7..4b8c326c6aac91fcd0d04db82b12114850376c52 100644 (file)
@@ -16,7 +16,7 @@ Enable the following options:
 "Device drivers" => "Multimedia devices"
  => "Video For Linux" => "BT848 Video For Linux"
 "Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
- => "DVB for Linux" "DVB Core Support" "Nebula/Pinnacle PCTV/TwinHan PCI Cards"
+ => "DVB for Linux" "DVB Core Support" "BT8xx based PCI cards"
 
 3) Loading Modules, described by two approaches
 ===============================================
index f1d436993eb156831f50a4ab32619f79929dbc02..3cb39ade290eae9d3e3046cfb04fe340e601d5b9 100644 (file)
@@ -7,7 +7,7 @@ To protect itself the kernel has to verify this address.
 
 In older versions of Linux this was done with the 
 int verify_area(int type, const void * addr, unsigned long size) 
-function.
+function (which has since been replaced by access_ok()).
 
 This function verified that the memory area starting at address 
 addr and of size size was accessible for the operation specified 
index 8b1430b4665571d613dd1f85c6a4e4e22d387755..2e0a01b21fe040503243c963a65f8411e795961b 100644 (file)
@@ -51,14 +51,6 @@ Who: Adrian Bunk <bunk@stusta.de>
 
 ---------------------------
 
-What:  register_ioctl32_conversion() / unregister_ioctl32_conversion()
-When:  April 2005
-Why:   Replaced by ->compat_ioctl in file_operations and other method
-       vecors.
-Who:   Andi Kleen <ak@muc.de>, Christoph Hellwig <hch@lst.de>
-
----------------------------
-
 What:  RCU API moves to EXPORT_SYMBOL_GPL
 When:  April 2006
 Files: include/linux/rcupdate.h, kernel/rcupdate.c
@@ -74,14 +66,6 @@ Who: Paul E. McKenney <paulmck@us.ibm.com>
 
 ---------------------------
 
-What:  remove verify_area()
-When:  July 2006
-Files: Various uaccess.h headers.
-Why:   Deprecated and redundant. access_ok() should be used instead.
-Who:   Jesper Juhl <juhl-lkml@dif.dk>
-
----------------------------
-
 What:  IEEE1394 Audio and Music Data Transmission Protocol driver,
        Connection Management Procedures driver
 When:  November 2005
@@ -102,16 +86,6 @@ Who:        Jody McIntyre <scjody@steamballoon.com>
 
 ---------------------------
 
-What:  register_serial/unregister_serial
-When:  September 2005
-Why:   This interface does not allow serial ports to be registered against
-       a struct device, and as such does not allow correct power management
-       of such ports.  8250-based ports should use serial8250_register_port
-       and serial8250_unregister_port, or platform devices instead.
-Who:   Russell King <rmk@arm.linux.org.uk>
-
----------------------------
-
 What:  i2c sysfs name change: in1_ref, vid deprecated in favour of cpu0_vid
 When:  November 2005
 Files: drivers/i2c/chips/adm1025.c, drivers/i2c/chips/adm1026.c
@@ -135,3 +109,15 @@ Why:       With the 16-bit PCMCIA subsystem now behaving (almost) like a
        pcmciautils package available at
        http://kernel.org/pub/linux/utils/kernel/pcmcia/
 Who:   Dominik Brodowski <linux@brodo.de>
+
+---------------------------
+
+What:  ip_queue and ip6_queue (old ipv4-only and ipv6-only netfilter queue)
+When:  December 2005
+Why:   This interface has been obsoleted by the new layer3-independent
+       "nfnetlink_queue".  The Kernel interface is compatible, so the old
+       ip[6]tables "QUEUE" targets still work and will transparently handle
+       all packets into nfnetlink queue number 0.  Userspace users will have
+       to link against API-compatible library on top of libnfnetlink_queue 
+       instead of the current 'libipq'.
+Who:   Harald Welte <laforge@netfilter.org>
index 6c98f2bd421e79f5a84a7a3c72e51b2ac398abc7..5024ba7a592c065820216ecf21ee862355170d41 100644 (file)
@@ -133,6 +133,7 @@ Table 1-1: Process specific entries in /proc
  statm   Process memory status information              
  status  Process status in human readable form          
  wchan   If CONFIG_KALLSYMS is set, a pre-decoded wchan
+ smaps  Extension based on maps, presenting the rss size for each mapped file
 ..............................................................................
 
 For example, to get the status information of a process, all you have to do is
diff --git a/Documentation/filesystems/relayfs.txt b/Documentation/filesystems/relayfs.txt
new file mode 100644 (file)
index 0000000..d24e1b0
--- /dev/null
@@ -0,0 +1,362 @@
+
+relayfs - a high-speed data relay filesystem
+============================================
+
+relayfs is a filesystem designed to provide an efficient mechanism for
+tools and facilities to relay large and potentially sustained streams
+of data from kernel space to user space.
+
+The main abstraction of relayfs is the 'channel'.  A channel consists
+of a set of per-cpu kernel buffers each represented by a file in the
+relayfs filesystem.  Kernel clients write into a channel using
+efficient write functions which automatically log to the current cpu's
+channel buffer.  User space applications mmap() the per-cpu files and
+retrieve the data as it becomes available.
+
+The format of the data logged into the channel buffers is completely
+up to the relayfs client; relayfs does however provide hooks which
+allow clients to impose some stucture on the buffer data.  Nor does
+relayfs implement any form of data filtering - this also is left to
+the client.  The purpose is to keep relayfs as simple as possible.
+
+This document provides an overview of the relayfs API.  The details of
+the function parameters are documented along with the functions in the
+filesystem code - please see that for details.
+
+Semantics
+=========
+
+Each relayfs channel has one buffer per CPU, each buffer has one or
+more sub-buffers. Messages are written to the first sub-buffer until
+it is too full to contain a new message, in which case it it is
+written to the next (if available).  Messages are never split across
+sub-buffers.  At this point, userspace can be notified so it empties
+the first sub-buffer, while the kernel continues writing to the next.
+
+When notified that a sub-buffer is full, the kernel knows how many
+bytes of it are padding i.e. unused.  Userspace can use this knowledge
+to copy only valid data.
+
+After copying it, userspace can notify the kernel that a sub-buffer
+has been consumed.
+
+relayfs can operate in a mode where it will overwrite data not yet
+collected by userspace, and not wait for it to consume it.
+
+relayfs itself does not provide for communication of such data between
+userspace and kernel, allowing the kernel side to remain simple and not
+impose a single interface on userspace. It does provide a separate
+helper though, described below.
+
+klog, relay-app & librelay
+==========================
+
+relayfs itself is ready to use, but to make things easier, two
+additional systems are provided.  klog is a simple wrapper to make
+writing formatted text or raw data to a channel simpler, regardless of
+whether a channel to write into exists or not, or whether relayfs is
+compiled into the kernel or is configured as a module.  relay-app is
+the kernel counterpart of userspace librelay.c, combined these two
+files provide glue to easily stream data to disk, without having to
+bother with housekeeping.  klog and relay-app can be used together,
+with klog providing high-level logging functions to the kernel and
+relay-app taking care of kernel-user control and disk-logging chores.
+
+It is possible to use relayfs without relay-app & librelay, but you'll
+have to implement communication between userspace and kernel, allowing
+both to convey the state of buffers (full, empty, amount of padding).
+
+klog, relay-app and librelay can be found in the relay-apps tarball on
+http://relayfs.sourceforge.net
+
+The relayfs user space API
+==========================
+
+relayfs implements basic file operations for user space access to
+relayfs channel buffer data.  Here are the file operations that are
+available and some comments regarding their behavior:
+
+open()  enables user to open an _existing_ buffer.
+
+mmap()  results in channel buffer being mapped into the caller's
+        memory space. Note that you can't do a partial mmap - you must
+        map the entire file, which is NRBUF * SUBBUFSIZE.
+
+read()  read the contents of a channel buffer.  The bytes read are
+        'consumed' by the reader i.e. they won't be available again
+        to subsequent reads.  If the channel is being used in
+        no-overwrite mode (the default), it can be read at any time
+        even if there's an active kernel writer.  If the channel is
+        being used in overwrite mode and there are active channel
+        writers, results may be unpredictable - users should make
+        sure that all logging to the channel has ended before using
+        read() with overwrite mode.
+
+poll()  POLLIN/POLLRDNORM/POLLERR supported.  User applications are
+        notified when sub-buffer boundaries are crossed.
+
+close() decrements the channel buffer's refcount.  When the refcount
+       reaches 0 i.e. when no process or kernel client has the buffer
+       open, the channel buffer is freed.
+
+
+In order for a user application to make use of relayfs files, the
+relayfs filesystem must be mounted.  For example,
+
+       mount -t relayfs relayfs /mnt/relay
+
+NOTE:  relayfs doesn't need to be mounted for kernel clients to create
+       or use channels - it only needs to be mounted when user space
+       applications need access to the buffer data.
+
+
+The relayfs kernel API
+======================
+
+Here's a summary of the API relayfs provides to in-kernel clients:
+
+
+  channel management functions:
+
+    relay_open(base_filename, parent, subbuf_size, n_subbufs,
+               callbacks)
+    relay_close(chan)
+    relay_flush(chan)
+    relay_reset(chan)
+    relayfs_create_dir(name, parent)
+    relayfs_remove_dir(dentry)
+
+  channel management typically called on instigation of userspace:
+
+    relay_subbufs_consumed(chan, cpu, subbufs_consumed)
+
+  write functions:
+
+    relay_write(chan, data, length)
+    __relay_write(chan, data, length)
+    relay_reserve(chan, length)
+
+  callbacks:
+
+    subbuf_start(buf, subbuf, prev_subbuf, prev_padding)
+    buf_mapped(buf, filp)
+    buf_unmapped(buf, filp)
+
+  helper functions:
+
+    relay_buf_full(buf)
+    subbuf_start_reserve(buf, length)
+
+
+Creating a channel
+------------------
+
+relay_open() is used to create a channel, along with its per-cpu
+channel buffers.  Each channel buffer will have an associated file
+created for it in the relayfs filesystem, which can be opened and
+mmapped from user space if desired.  The files are named
+basename0...basenameN-1 where N is the number of online cpus, and by
+default will be created in the root of the filesystem.  If you want a
+directory structure to contain your relayfs files, you can create it
+with relayfs_create_dir() and pass the parent directory to
+relay_open().  Clients are responsible for cleaning up any directory
+structure they create when the channel is closed - use
+relayfs_remove_dir() for that.
+
+The total size of each per-cpu buffer is calculated by multiplying the
+number of sub-buffers by the sub-buffer size passed into relay_open().
+The idea behind sub-buffers is that they're basically an extension of
+double-buffering to N buffers, and they also allow applications to
+easily implement random-access-on-buffer-boundary schemes, which can
+be important for some high-volume applications.  The number and size
+of sub-buffers is completely dependent on the application and even for
+the same application, different conditions will warrant different
+values for these parameters at different times.  Typically, the right
+values to use are best decided after some experimentation; in general,
+though, it's safe to assume that having only 1 sub-buffer is a bad
+idea - you're guaranteed to either overwrite data or lose events
+depending on the channel mode being used.
+
+Channel 'modes'
+---------------
+
+relayfs channels can be used in either of two modes - 'overwrite' or
+'no-overwrite'.  The mode is entirely determined by the implementation
+of the subbuf_start() callback, as described below.  In 'overwrite'
+mode, also known as 'flight recorder' mode, writes continuously cycle
+around the buffer and will never fail, but will unconditionally
+overwrite old data regardless of whether it's actually been consumed.
+In no-overwrite mode, writes will fail i.e. data will be lost, if the
+number of unconsumed sub-buffers equals the total number of
+sub-buffers in the channel.  It should be clear that if there is no
+consumer or if the consumer can't consume sub-buffers fast enought,
+data will be lost in either case; the only difference is whether data
+is lost from the beginning or the end of a buffer.
+
+As explained above, a relayfs channel is made of up one or more
+per-cpu channel buffers, each implemented as a circular buffer
+subdivided into one or more sub-buffers.  Messages are written into
+the current sub-buffer of the channel's current per-cpu buffer via the
+write functions described below.  Whenever a message can't fit into
+the current sub-buffer, because there's no room left for it, the
+client is notified via the subbuf_start() callback that a switch to a
+new sub-buffer is about to occur.  The client uses this callback to 1)
+initialize the next sub-buffer if appropriate 2) finalize the previous
+sub-buffer if appropriate and 3) return a boolean value indicating
+whether or not to actually go ahead with the sub-buffer switch.
+
+To implement 'no-overwrite' mode, the userspace client would provide
+an implementation of the subbuf_start() callback something like the
+following:
+
+static int subbuf_start(struct rchan_buf *buf,
+                        void *subbuf,
+                       void *prev_subbuf,
+                       unsigned int prev_padding)
+{
+       if (prev_subbuf)
+               *((unsigned *)prev_subbuf) = prev_padding;
+
+       if (relay_buf_full(buf))
+               return 0;
+
+       subbuf_start_reserve(buf, sizeof(unsigned int));
+
+       return 1;
+}
+
+If the current buffer is full i.e. all sub-buffers remain unconsumed,
+the callback returns 0 to indicate that the buffer switch should not
+occur yet i.e. until the consumer has had a chance to read the current
+set of ready sub-buffers.  For the relay_buf_full() function to make
+sense, the consumer is reponsible for notifying relayfs when
+sub-buffers have been consumed via relay_subbufs_consumed().  Any
+subsequent attempts to write into the buffer will again invoke the
+subbuf_start() callback with the same parameters; only when the
+consumer has consumed one or more of the ready sub-buffers will
+relay_buf_full() return 0, in which case the buffer switch can
+continue.
+
+The implementation of the subbuf_start() callback for 'overwrite' mode
+would be very similar:
+
+static int subbuf_start(struct rchan_buf *buf,
+                        void *subbuf,
+                       void *prev_subbuf,
+                       unsigned int prev_padding)
+{
+       if (prev_subbuf)
+               *((unsigned *)prev_subbuf) = prev_padding;
+
+       subbuf_start_reserve(buf, sizeof(unsigned int));
+
+       return 1;
+}
+
+In this case, the relay_buf_full() check is meaningless and the
+callback always returns 1, causing the buffer switch to occur
+unconditionally.  It's also meaningless for the client to use the
+relay_subbufs_consumed() function in this mode, as it's never
+consulted.
+
+The default subbuf_start() implementation, used if the client doesn't
+define any callbacks, or doesn't define the subbuf_start() callback,
+implements the simplest possible 'no-overwrite' mode i.e. it does
+nothing but return 0.
+
+Header information can be reserved at the beginning of each sub-buffer
+by calling the subbuf_start_reserve() helper function from within the
+subbuf_start() callback.  This reserved area can be used to store
+whatever information the client wants.  In the example above, room is
+reserved in each sub-buffer to store the padding count for that
+sub-buffer.  This is filled in for the previous sub-buffer in the
+subbuf_start() implementation; the padding value for the previous
+sub-buffer is passed into the subbuf_start() callback along with a
+pointer to the previous sub-buffer, since the padding value isn't
+known until a sub-buffer is filled.  The subbuf_start() callback is
+also called for the first sub-buffer when the channel is opened, to
+give the client a chance to reserve space in it.  In this case the
+previous sub-buffer pointer passed into the callback will be NULL, so
+the client should check the value of the prev_subbuf pointer before
+writing into the previous sub-buffer.
+
+Writing to a channel
+--------------------
+
+kernel clients write data into the current cpu's channel buffer using
+relay_write() or __relay_write().  relay_write() is the main logging
+function - it uses local_irqsave() to protect the buffer and should be
+used if you might be logging from interrupt context.  If you know
+you'll never be logging from interrupt context, you can use
+__relay_write(), which only disables preemption.  These functions
+don't return a value, so you can't determine whether or not they
+failed - the assumption is that you wouldn't want to check a return
+value in the fast logging path anyway, and that they'll always succeed
+unless the buffer is full and no-overwrite mode is being used, in
+which case you can detect a failed write in the subbuf_start()
+callback by calling the relay_buf_full() helper function.
+
+relay_reserve() is used to reserve a slot in a channel buffer which
+can be written to later.  This would typically be used in applications
+that need to write directly into a channel buffer without having to
+stage data in a temporary buffer beforehand.  Because the actual write
+may not happen immediately after the slot is reserved, applications
+using relay_reserve() can keep a count of the number of bytes actually
+written, either in space reserved in the sub-buffers themselves or as
+a separate array.  See the 'reserve' example in the relay-apps tarball
+at http://relayfs.sourceforge.net for an example of how this can be
+done.  Because the write is under control of the client and is
+separated from the reserve, relay_reserve() doesn't protect the buffer
+at all - it's up to the client to provide the appropriate
+synchronization when using relay_reserve().
+
+Closing a channel
+-----------------
+
+The client calls relay_close() when it's finished using the channel.
+The channel and its associated buffers are destroyed when there are no
+longer any references to any of the channel buffers.  relay_flush()
+forces a sub-buffer switch on all the channel buffers, and can be used
+to finalize and process the last sub-buffers before the channel is
+closed.
+
+Misc
+----
+
+Some applications may want to keep a channel around and re-use it
+rather than open and close a new channel for each use.  relay_reset()
+can be used for this purpose - it resets a channel to its initial
+state without reallocating channel buffer memory or destroying
+existing mappings.  It should however only be called when it's safe to
+do so i.e. when the channel isn't currently being written to.
+
+Finally, there are a couple of utility callbacks that can be used for
+different purposes.  buf_mapped() is called whenever a channel buffer
+is mmapped from user space and buf_unmapped() is called when it's
+unmapped.  The client can use this notification to trigger actions
+within the kernel application, such as enabling/disabling logging to
+the channel.
+
+
+Resources
+=========
+
+For news, example code, mailing list, etc. see the relayfs homepage:
+
+    http://relayfs.sourceforge.net
+
+
+Credits
+=======
+
+The ideas and specs for relayfs came about as a result of discussions
+on tracing involving the following:
+
+Michel Dagenais                <michel.dagenais@polymtl.ca>
+Richard Moore          <richardj_moore@uk.ibm.com>
+Bob Wisniewski         <bob@watson.ibm.com>
+Karim Yaghmour         <karim@opersys.com>
+Tom Zanussi            <zanussi@us.ibm.com>
+
+Also thanks to Hubertus Franke for a lot of useful suggestions and bug
+reports.
index dc276598a65a3784c4dd7d41470c41f288db9529..c8bce82ddcacdf22e6a7190c204faf154821a619 100644 (file)
@@ -90,7 +90,7 @@ void device_remove_file(struct device *, struct device_attribute *);
 
 It also defines this helper for defining device attributes: 
 
-#define DEVICE_ATTR(_name,_mode,_show,_store)      \
+#define DEVICE_ATTR(_name, _mode, _show, _store)      \
 struct device_attribute dev_attr_##_name = {            \
         .attr = {.name  = __stringify(_name) , .mode   = _mode },      \
         .show   = _show,                                \
@@ -99,14 +99,14 @@ struct device_attribute dev_attr_##_name = {            \
 
 For example, declaring
 
-static DEVICE_ATTR(foo,0644,show_foo,store_foo);
+static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo);
 
 is equivalent to doing:
 
 static struct device_attribute dev_attr_foo = {
        .attr   = {
                .name = "foo",
-               .mode = 0644,
+               .mode = S_IWUSR | S_IRUGO,
        },
        .show = show_foo,
        .store = store_foo,
@@ -121,8 +121,8 @@ set of sysfs operations for forwarding read and write calls to the
 show and store methods of the attribute owners. 
 
 struct sysfs_ops {
-        ssize_t (*show)(struct kobject *, struct attribute *,char *);
-        ssize_t (*store)(struct kobject *,struct attribute *,const char *);
+        ssize_t (*show)(struct kobject *, struct attribute *, char *);
+        ssize_t (*store)(struct kobject *, struct attribute *, const char *);
 };
 
 [ Subsystems should have already defined a struct kobj_type as a
@@ -137,7 +137,7 @@ calls the associated methods.
 
 To illustrate:
 
-#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr)
+#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
 #define to_dev(d) container_of(d, struct device, kobj)
 
 static ssize_t
@@ -148,7 +148,7 @@ dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
         ssize_t ret = 0;
 
         if (dev_attr->show)
-                ret = dev_attr->show(dev,buf);
+                ret = dev_attr->show(dev, buf);
         return ret;
 }
 
@@ -216,16 +216,16 @@ A very simple (and naive) implementation of a device attribute is:
 
 static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
 {
-        return sprintf(buf,"%s\n",dev->name);
+       return snprintf(buf, PAGE_SIZE, "%s\n", dev->name);
 }
 
 static ssize_t store_name(struct device * dev, const char * buf)
 {
-       sscanf(buf,"%20s",dev->name);
-       return strlen(buf);
+       sscanf(buf, "%20s", dev->name);
+       return strnlen(buf, PAGE_SIZE);
 }
 
-static DEVICE_ATTR(name,S_IRUGO,show_name,store_name);
+static DEVICE_ATTR(name, S_IRUGO, show_name, store_name);
 
 
 (Note that the real implementation doesn't allow userspace to set the 
@@ -290,7 +290,7 @@ struct device_attribute {
 
 Declaring:
 
-DEVICE_ATTR(_name,_str,_mode,_show,_store);
+DEVICE_ATTR(_name, _str, _mode, _show, _store);
 
 Creation/Removal:
 
@@ -310,7 +310,7 @@ struct bus_attribute {
 
 Declaring:
 
-BUS_ATTR(_name,_mode,_show,_store)
+BUS_ATTR(_name, _mode, _show, _store)
 
 Creation/Removal:
 
@@ -331,7 +331,7 @@ struct driver_attribute {
 
 Declaring:
 
-DRIVER_ATTR(_name,_mode,_show,_store)
+DRIVER_ATTR(_name, _mode, _show, _store)
 
 Creation/Removal:
 
index 357086ed7f64e5307506c225f6c3e46db155f932..fd5dc7a19f0e73361ebafb37141071eae77b9c14 100644 (file)
@@ -2,16 +2,11 @@ Kernel driver lm78
 ==================
 
 Supported chips:
-  * National Semiconductor LM78
+  * National Semiconductor LM78 / LM78-J
     Prefix: 'lm78'
     Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
     Datasheet: Publicly available at the National Semiconductor website
                http://www.national.com/
-  * National Semiconductor LM78-J
-    Prefix: 'lm78-j'
-    Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
-    Datasheet: Publicly available at the National Semiconductor website
-               http://www.national.com/
   * National Semiconductor LM79
     Prefix: 'lm79'
     Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
diff --git a/Documentation/hwmon/w83792d b/Documentation/hwmon/w83792d
new file mode 100644 (file)
index 0000000..8171c28
--- /dev/null
@@ -0,0 +1,174 @@
+Kernel driver w83792d
+=====================
+
+Supported chips:
+  * Winbond W83792D
+    Prefix: 'w83792d'
+    Addresses scanned: I2C 0x2c - 0x2f
+    Datasheet: http://www.winbond.com.tw/E-WINBONDHTM/partner/PDFresult.asp?Pname=1035
+
+Author: Chunhao Huang
+Contact: DZShen <DZShen@Winbond.com.tw>
+
+
+Module Parameters
+-----------------
+
+* init int
+  (default 1)
+  Use 'init=0' to bypass initializing the chip.
+  Try this if your computer crashes when you load the module.
+
+* force_subclients=bus,caddr,saddr,saddr
+  This is used to force the i2c addresses for subclients of
+  a certain chip. Example usage is `force_subclients=0,0x2f,0x4a,0x4b'
+  to force the subclients of chip 0x2f on bus 0 to i2c addresses
+  0x4a and 0x4b.
+
+
+Description
+-----------
+
+This driver implements support for the Winbond W83792AD/D.
+
+Detection of the chip can sometimes be foiled because it can be in an
+internal state that allows no clean access (Bank with ID register is not
+currently selected). If you know the address of the chip, use a 'force'
+parameter; this will put it into a more well-behaved state first.
+
+The driver implements three temperature sensors, seven fan rotation speed
+sensors, nine voltage sensors, and two automatic fan regulation
+strategies called: Smart Fan I (Thermal Cruise mode) and Smart Fan II.
+Automatic fan control mode is possible only for fan1-fan3. Fan4-fan7 can run
+synchronized with selected fan (fan1-fan3). This functionality and manual PWM
+control for fan4-fan7 is not yet implemented.
+
+Temperatures are measured in degrees Celsius and measurement resolution is 1
+degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
+the temperature gets higher than the Overtemperature Shutdown value; it stays
+on until the temperature falls below the Hysteresis value.
+
+Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
+triggered if the rotation speed has dropped below a programmable limit. Fan
+readings can be divided by a programmable divider (1, 2, 4, 8, 16, 32, 64 or
+128) to give the readings more range or accuracy.
+
+Voltage sensors (also known as IN sensors) report their values in millivolts.
+An alarm is triggered if the voltage has crossed a programmable minimum
+or maximum limit.
+
+Alarms are provided as output from "realtime status register". Following bits
+are defined:
+
+bit - alarm on:
+0  - in0
+1  - in1
+2  - temp1
+3  - temp2
+4  - temp3
+5  - fan1
+6  - fan2
+7  - fan3
+8  - in2
+9  - in3
+10 - in4
+11 - in5
+12 - in6
+13 - VID change
+14 - chassis
+15 - fan7
+16 - tart1
+17 - tart2
+18 - tart3
+19 - in7
+20 - in8
+21 - fan4
+22 - fan5
+23 - fan6
+
+Tart will be asserted while target temperature cannot be achieved after 3 minutes
+of full speed rotation of corresponding fan.
+
+In addition to the alarms described above, there is a CHAS alarm on the chips
+which triggers if your computer case is open (This one is latched, contrary
+to realtime alarms).
+
+The chips only update values each 3 seconds; reading them more often will
+do no harm, but will return 'old' values.
+
+
+W83792D PROBLEMS
+----------------
+Known problems:
+       - This driver is only for Winbond W83792D C version device, there
+         are also some motherboards with B version W83792D device. The
+         calculation method to in6-in7(measured value, limits) is a little
+         different between C and B version. C or B version can be identified
+         by CR[0x49h].
+       - The function of vid and vrm has not been finished, because I'm NOT
+         very familiar with them. Adding support is welcome.
+       - The function of chassis open detection needs more tests.
+       - If you have ASUS server board and chip was not found: Then you will
+         need to upgrade to latest (or beta) BIOS. If it does not help please
+         contact us.
+
+Fan control
+-----------
+
+Manual mode
+-----------
+
+Works as expected. You just need to specify desired PWM/DC value (fan speed)
+in appropriate pwm# file.
+
+Thermal cruise
+--------------
+
+In this mode, W83792D provides the Smart Fan system to automatically control
+fan speed to keep the temperatures of CPU and the system within specific
+range. At first a wanted temperature and interval must be set. This is done
+via thermal_cruise# file. The tolerance# file serves to create T +- tolerance
+interval. The fan speed will be lowered as long as the current temperature
+remains below the thermal_cruise# +- tolerance# value. Once the temperature
+exceeds the high limit (T+tolerance), the fan will be turned on with a
+specific speed set by pwm# and automatically controlled its PWM duty cycle
+with the temperature varying. Three conditions may occur:
+
+(1) If the temperature still exceeds the high limit, PWM duty
+cycle will increase slowly.
+
+(2) If the temperature goes below the high limit, but still above the low
+limit (T-tolerance), the fan speed will be fixed at the current speed because
+the temperature is in the target range.
+
+(3) If the temperature goes below the low limit, PWM duty cycle will decrease
+slowly to 0 or a preset stop value until the temperature exceeds the low
+limit. (The preset stop value handling is not yet implemented in driver)
+
+Smart Fan II
+------------
+
+W83792D also provides a special mode for fan. Four temperature points are
+available. When related temperature sensors detects the temperature in preset
+temperature region (sf2_point@_fan# +- tolerance#) it will cause fans to run
+on programmed value from sf2_level@_fan#. You need to set four temperatures
+for each fan.
+
+
+/sys files
+----------
+
+pwm[1-3] - this file stores PWM duty cycle or DC value (fan speed) in range:
+       0 (stop) to 255 (full)
+pwm[1-3]_enable - this file controls mode of fan/temperature control:
+            * 0 Disabled
+            * 1 Manual mode
+            * 2 Smart Fan II
+            * 3 Thermal Cruise
+pwm[1-3]_mode - Select PWM of DC mode
+            * 0 DC
+            * 1 PWM
+thermal_cruise[1-3] - Selects the desired temperature for cruise (degC)
+tolerance[1-3] - Value in degrees of Celsius (degC) for +- T
+sf2_point[1-4]_fan[1-3] - four temperature points for each fan for Smart Fan II
+sf2_level[1-3]_fan[1-3] - three PWM/DC levels for each fan for Smart Fan II
index b02002898a09cebd411dbed0c38ba7aeecb69919..96fec562a8e9020fc92a5d8c1de5676bda953cf8 100644 (file)
@@ -4,22 +4,13 @@ Kernel driver max6875
 Supported chips:
   * Maxim MAX6874, MAX6875
     Prefix: 'max6875'
-    Addresses scanned: 0x50, 0x52
+    Addresses scanned: None (see below)
     Datasheet:
         http://pdfserv.maxim-ic.com/en/ds/MAX6874-MAX6875.pdf
 
 Author: Ben Gardner <bgardner@wabtec.com>
 
 
-Module Parameters
------------------
-
-* allow_write int
-  Set to non-zero to enable write permission:
-  *0: Read only
-   1: Read and write
-
-
 Description
 -----------
 
@@ -33,34 +24,85 @@ registers.
 
 The Maxim MAX6874 is a similar, mostly compatible device, with more intputs
 and outputs:
-
              vin     gpi    vout
 MAX6874        6       4       8
 MAX6875        4       3       5
 
-MAX6874 chips can have four different addresses (as opposed to only two for
-the MAX6875). The additional addresses (0x54 and 0x56) are not probed by
-this driver by default, but the probe module parameter can be used if
-needed.
-
-See the datasheet for details on how to program the EEPROM.
+See the datasheet for more information.
 
 
 Sysfs entries
 -------------
 
-eeprom_user   - 512 bytes of user-defined EEPROM space. Only writable if
-                allow_write was set and register 0x43 is 0.
-
-eeprom_config - 70 bytes of config EEPROM. Note that changes will not get
-                loaded into register space until a power cycle or device reset.
-
-reg_config    - 70 bytes of register space. Any changes take affect immediately.
+eeprom        - 512 bytes of user-defined EEPROM space.
 
 
 General Remarks
 ---------------
 
-A typical application will require that the EEPROMs be programmed once and
-never altered afterwards.
+Valid addresses for the MAX6875 are 0x50 and 0x52.
+Valid addresses for the MAX6874 are 0x50, 0x52, 0x54 and 0x56.
+The driver does not probe any address, so you must force the address.
+
+Example:
+$ modprobe max6875 force=0,0x50
+
+The MAX6874/MAX6875 ignores address bit 0, so this driver attaches to multiple
+addresses.  For example, for address 0x50, it also reserves 0x51.
+The even-address instance is called 'max6875', the odd one is 'max6875 subclient'.
+
+
+Programming the chip using i2c-dev
+----------------------------------
+
+Use the i2c-dev interface to access and program the chips.
+Reads and writes are performed differently depending on the address range.
+
+The configuration registers are at addresses 0x00 - 0x45.
+Use i2c_smbus_write_byte_data() to write a register and
+i2c_smbus_read_byte_data() to read a register.
+The command is the register number.
+
+Examples:
+To write a 1 to register 0x45:
+  i2c_smbus_write_byte_data(fd, 0x45, 1);
+
+To read register 0x45:
+  value = i2c_smbus_read_byte_data(fd, 0x45);
+
+
+The configuration EEPROM is at addresses 0x8000 - 0x8045.
+The user EEPROM is at addresses 0x8100 - 0x82ff.
+
+Use i2c_smbus_write_word_data() to write a byte to EEPROM.
+
+The command is the upper byte of the address: 0x80, 0x81, or 0x82.
+The data word is the lower part of the address or'd with data << 8.
+  cmd = address >> 8;
+  val = (address & 0xff) | (data << 8);
+
+Example:
+To write 0x5a to address 0x8003:
+  i2c_smbus_write_word_data(fd, 0x80, 0x5a03);
+
+
+Reading data from the EEPROM is a little more complicated.
+Use i2c_smbus_write_byte_data() to set the read address and then
+i2c_smbus_read_byte() or i2c_smbus_read_i2c_block_data() to read the data.
+
+Example:
+To read data starting at offset 0x8100, first set the address:
+  i2c_smbus_write_byte_data(fd, 0x81, 0x00);
+
+And then read the data
+  value = i2c_smbus_read_byte(fd);
+
+  or
+
+  count = i2c_smbus_read_i2c_block_data(fd, 0x84, buffer);
+
+The block read should read 16 bytes.
+0x84 is the block read command.
+
+See the datasheet for more details.
 
index 8a78a95ae04e25d2aae7d05f6ef91068bccf307f..41ffefbdc60c488e339162454d16043591006f2c 100644 (file)
@@ -115,7 +115,7 @@ CHECKING THROUGH /DEV
 If you try to access an adapter from a userspace program, you will have
 to use the /dev interface. You will still have to check whether the
 functionality you need is supported, of course. This is done using
-the I2C_FUNCS ioctl. An example, adapted from the lm_sensors i2c_detect
+the I2C_FUNCS ioctl. An example, adapted from the lm_sensors i2cdetect
 program, is below:
 
   int file;
index a7adbdd9ea8a51aa46298cd48bdd566b1f9566d3..4849dfd6961c7d2ed2d21eb5e7a65cf72cf0b755 100644 (file)
@@ -1,4 +1,4 @@
-Revision 4, 2004-03-30
+Revision 5, 2005-07-29
 Jean Delvare <khali@linux-fr.org>
 Greg KH <greg@kroah.com>
 
@@ -17,20 +17,22 @@ yours for best results.
 
 Technical changes:
 
-* [Includes] Get rid of "version.h". Replace <linux/i2c-proc.h> with
-  <linux/i2c-sensor.h>. Includes typically look like that:
+* [Includes] Get rid of "version.h" and <linux/i2c-proc.h>.
+  Includes typically look like that:
   #include <linux/module.h>
   #include <linux/init.h>
   #include <linux/slab.h>
   #include <linux/i2c.h>
-  #include <linux/i2c-sensor.h>
-  #include <linux/i2c-vid.h>   /* if you need VRM support */
+  #include <linux/hwmon.h>     /* for hardware monitoring drivers */
+  #include <linux/hwmon-sysfs.h>
+  #include <linux/hwmon-vid.h> /* if you need VRM support */
   #include <asm/io.h>          /* if you have I/O operations */
   Please respect this inclusion order. Some extra headers may be
   required for a given driver (e.g. "lm75.h").
 
-* [Addresses] SENSORS_I2C_END becomes I2C_CLIENT_END, SENSORS_ISA_END
-  becomes I2C_CLIENT_ISA_END.
+* [Addresses] SENSORS_I2C_END becomes I2C_CLIENT_END, ISA addresses
+  are no more handled by the i2c core.
+  SENSORS_INSMOD_<n> becomes I2C_CLIENT_INSMOD_<n>.
 
 * [Client data] Get rid of sysctl_id. Try using standard names for
   register values (for example, temp_os becomes temp_max). You're
@@ -66,13 +68,15 @@ Technical changes:
   if (!(adapter->class & I2C_CLASS_HWMON))
           return 0;
   ISA-only drivers of course don't need this.
+  Call i2c_probe() instead of i2c_detect().
 
 * [Detect] As mentioned earlier, the flags parameter is gone.
   The type_name and client_name strings are replaced by a single
   name string, which will be filled with a lowercase, short string
   (typically the driver name, e.g. "lm75").
   In i2c-only drivers, drop the i2c_is_isa_adapter check, it's
-  useless.
+  useless. Same for isa-only drivers, as the test would always be
+  true. Only hybrid drivers (which are quite rare) still need it.
   The errorN labels are reduced to the number needed. If that number
   is 2 (i2c-only drivers), it is advised that the labels are named
   exit and exit_free. For i2c+isa drivers, labels should be named
@@ -86,6 +90,8 @@ Technical changes:
   device_create_file. Move the driver initialization before any
   sysfs file creation.
   Drop client->id.
+  Drop any 24RF08 corruption prevention you find, as this is now done
+  at the i2c-core level, and doing it twice voids it.
 
 * [Init] Limits must not be set by the driver (can be done later in
   user-space). Chip should not be reset default (although a module
@@ -93,7 +99,8 @@ Technical changes:
   limited to the strictly necessary steps.
 
 * [Detach] Get rid of data, remove the call to
-  i2c_deregister_entry.
+  i2c_deregister_entry. Do not log an error message if
+  i2c_detach_client fails, as i2c-core will now do it for you.
 
 * [Update] Don't access client->data directly, use
   i2c_get_clientdata(client) instead.
index 91664be91ffcd692d62e3602fa8f1b3f9a27f381..077275722a7ccce46cfb1c12e04ed3abe688bd1b 100644 (file)
@@ -148,15 +148,15 @@ are defined in i2c.h to help you support them, as well as a generic
 detection algorithm.
 
 You do not have to use this parameter interface; but don't try to use
-function i2c_probe() (or i2c_detect()) if you don't.
+function i2c_probe() if you don't.
 
 NOTE: If you want to write a `sensors' driver, the interface is slightly
       different! See below.
 
 
 
-Probing classes (i2c)
----------------------
+Probing classes
+---------------
 
 All parameters are given as lists of unsigned 16-bit integers. Lists are
 terminated by I2C_CLIENT_END.
@@ -171,12 +171,18 @@ The following lists are used internally:
    ignore: insmod parameter.
      A list of pairs. The first value is a bus number (-1 for any I2C bus), 
      the second is the I2C address. These addresses are never probed. 
-     This parameter overrules 'normal' and 'probe', but not the 'force' lists.
+     This parameter overrules the 'normal_i2c' list only.
    force: insmod parameter. 
      A list of pairs. The first value is a bus number (-1 for any I2C bus),
      the second is the I2C address. A device is blindly assumed to be on
      the given address, no probing is done. 
 
+Additionally, kind-specific force lists may optionally be defined if
+the driver supports several chip kinds. They are grouped in a
+NULL-terminated list of pointers named forces, those first element if the
+generic force list mentioned above. Each additional list correspond to an
+insmod parameter of the form force_<kind>.
+
 Fortunately, as a module writer, you just have to define the `normal_i2c' 
 parameter. The complete declaration could look like this:
 
@@ -186,66 +192,17 @@ parameter. The complete declaration could look like this:
 
   /* Magic definition of all other variables and things */
   I2C_CLIENT_INSMOD;
+  /* Or, if your driver supports, say, 2 kind of devices: */
+  I2C_CLIENT_INSMOD_2(foo, bar);
+
+If you use the multi-kind form, an enum will be defined for you:
+  enum chips { any_chip, foo, bar, ... }
+You can then (and certainly should) use it in the driver code.
 
 Note that you *have* to call the defined variable `normal_i2c',
 without any prefix!
 
 
-Probing classes (sensors)
--------------------------
-
-If you write a `sensors' driver, you use a slightly different interface.
-As well as I2C addresses, we have to cope with ISA addresses. Also, we
-use a enum of chip types. Don't forget to include `sensors.h'.
-
-The following lists are used internally. They are all lists of integers.
-
-   normal_i2c: filled in by the module writer. Terminated by SENSORS_I2C_END.
-     A list of I2C addresses which should normally be examined.
-   normal_isa: filled in by the module writer. Terminated by SENSORS_ISA_END.
-     A list of ISA addresses which should normally be examined.
-   probe: insmod parameter. Initialize this list with SENSORS_I2C_END values.
-     A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for
-     the ISA bus, -1 for any I2C bus), the second is the address. These
-     addresses are also probed, as if they were in the 'normal' list.
-   ignore: insmod parameter. Initialize this list with SENSORS_I2C_END values.
-     A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for
-     the ISA bus, -1 for any I2C bus), the second is the I2C address. These
-     addresses are never probed. This parameter overrules 'normal' and 
-     'probe', but not the 'force' lists.
-
-Also used is a list of pointers to sensors_force_data structures:
-   force_data: insmod parameters. A list, ending with an element of which
-     the force field is NULL.
-     Each element contains the type of chip and a list of pairs.
-     The first value is a bus number (SENSORS_ISA_BUS for the ISA bus, 
-     -1 for any I2C bus), the second is the address. 
-     These are automatically translated to insmod variables of the form
-     force_foo.
-
-So we have a generic insmod variabled `force', and chip-specific variables
-`force_CHIPNAME'.
-
-Fortunately, as a module writer, you just have to define the `normal_i2c' 
-and `normal_isa' parameters, and define what chip names are used. 
-The complete declaration could look like this:
-  /* Scan i2c addresses 0x37, and 0x48 to 0x4f */
-  static unsigned short normal_i2c[] = { 0x37, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
-                                         0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
-  /* Scan ISA address 0x290 */
-  static unsigned int normal_isa[] = {0x0290,SENSORS_ISA_END};
-
-  /* Define chips foo and bar, as well as all module parameters and things */
-  SENSORS_INSMOD_2(foo,bar);
-
-If you have one chip, you use macro SENSORS_INSMOD_1(chip), if you have 2
-you use macro SENSORS_INSMOD_2(chip1,chip2), etc. If you do not want to
-bother with chip types, you can use SENSORS_INSMOD_0.
-
-A enum is automatically defined as follows:
-  enum chips { any_chip, chip1, chip2, ... }
-
-
 Attaching to an adapter
 -----------------------
 
@@ -264,17 +221,10 @@ detected at a specific address, another callback is called.
     return i2c_probe(adapter,&addr_data,&foo_detect_client);
   }
 
-For `sensors' drivers, use the i2c_detect function instead:
-  
-  int foo_attach_adapter(struct i2c_adapter *adapter)
-  { 
-    return i2c_detect(adapter,&addr_data,&foo_detect_client);
-  }
-
 Remember, structure `addr_data' is defined by the macros explained above,
 so you do not have to define it yourself.
 
-The i2c_probe or i2c_detect function will call the foo_detect_client
+The i2c_probe function will call the foo_detect_client
 function only for those i2c addresses that actually have a device on
 them (unless a `force' parameter was used). In addition, addresses that
 are already in use (by some other registered client) are skipped.
@@ -283,19 +233,18 @@ are already in use (by some other registered client) are skipped.
 The detect client function
 --------------------------
 
-The detect client function is called by i2c_probe or i2c_detect.
-The `kind' parameter contains 0 if this call is due to a `force'
-parameter, and -1 otherwise (for i2c_detect, it contains 0 if
-this call is due to the generic `force' parameter, and the chip type
-number if it is due to a specific `force' parameter).
+The detect client function is called by i2c_probe. The `kind' parameter
+contains -1 for a probed detection, 0 for a forced detection, or a positive
+number for a forced detection with a chip type forced.
 
 Below, some things are only needed if this is a `sensors' driver. Those
 parts are between /* SENSORS ONLY START */ and /* SENSORS ONLY END */
 markers. 
 
-This function should only return an error (any value != 0) if there is
-some reason why no more detection should be done anymore. If the
-detection just fails for this address, return 0.
+Returning an error different from -ENODEV in a detect function will cause
+the detection to stop: other addresses and adapters won't be scanned.
+This should only be done on fatal or internal errors, such as a memory
+shortage or i2c_attach_client failing.
 
 For now, you can ignore the `flags' parameter. It is there for future use.
 
@@ -320,11 +269,10 @@ For now, you can ignore the `flags' parameter. It is there for future use.
     const char *type_name = "";
     int is_isa = i2c_is_isa_adapter(adapter);
 
-    if (is_isa) {
+    /* Do this only if the chip can additionally be found on the ISA bus
+       (hybrid chip). */
 
-      /* If this client can't be on the ISA bus at all, we can stop now
-         (call `goto ERROR0'). But for kicks, we will assume it is all
-         right. */
+    if (is_isa) {
 
       /* Discard immediately if this ISA range is already used */
       if (check_region(address,FOO_EXTENT))
@@ -495,15 +443,13 @@ much simpler than the attachment code, fortunately!
     /* SENSORS ONLY END */
 
     /* Try to detach the client from i2c space */
-    if ((err = i2c_detach_client(client))) {
-      printk("foo.o: Client deregistration failed, client not detached.\n");
+    if ((err = i2c_detach_client(client)))
       return err;
-    }
 
-    /* SENSORS ONLY START */
+    /* HYBRID SENSORS CHIP ONLY START */
     if i2c_is_isa_client(client)
       release_region(client->addr,LM78_EXTENT);
-    /* SENSORS ONLY END */
+    /* HYBRID SENSORS CHIP ONLY END */
 
     kfree(client); /* Frees client data too, if allocated at the same time */
     return 0;
index 1c48f0eba6fb79121c08dc95a6a9b05441f9f0e8..10312bebe55de0b063e59b28f2781a7f7001f8b4 100644 (file)
@@ -2,7 +2,7 @@
                     ----------------------------
 
                    H. Peter Anvin <hpa@zytor.com>
-                       Last update 2002-01-01
+                       Last update 2005-09-02
 
 On the i386 platform, the Linux kernel uses a rather complicated boot
 convention.  This has evolved partially due to historical aspects, as
@@ -34,6 +34,8 @@ Protocol 2.02:        (Kernel 2.4.0-test3-pre3) New command line protocol.
 Protocol 2.03: (Kernel 2.4.18-pre1) Explicitly makes the highest possible
                initrd address available to the bootloader.
 
+Protocol 2.04: (Kernel 2.6.14) Extend the syssize field to four bytes.
+
 
 **** MEMORY LAYOUT
 
@@ -103,10 +105,9 @@ The header looks like:
 Offset Proto   Name            Meaning
 /Size
 
-01F1/1 ALL     setup_sects     The size of the setup in sectors
+01F1/1 ALL(1   setup_sects     The size of the setup in sectors
 01F2/2 ALL     root_flags      If set, the root is mounted readonly
-01F4/2 ALL     syssize         DO NOT USE - for bootsect.S use only
-01F6/2 ALL     swap_dev        DO NOT USE - obsolete
+01F4/4 2.04+(2 syssize         The size of the 32-bit code in 16-byte paras
 01F8/2 ALL     ram_size        DO NOT USE - for bootsect.S use only
 01FA/2 ALL     vid_mode        Video mode control
 01FC/2 ALL     root_dev        Default root device number
@@ -129,8 +130,12 @@ Offset     Proto   Name            Meaning
 0228/4 2.02+   cmd_line_ptr    32-bit pointer to the kernel command line
 022C/4 2.03+   initrd_addr_max Highest legal initrd address
 
-For backwards compatibility, if the setup_sects field contains 0, the
-real value is 4.
+(1) For backwards compatibility, if the setup_sects field contains 0, the
+    real value is 4.
+
+(2) For boot protocol prior to 2.04, the upper two bytes of the syssize
+    field are unusable, which means the size of a bzImage kernel
+    cannot be determined.
 
 If the "HdrS" (0x53726448) magic number is not found at offset 0x202,
 the boot protocol version is "old".  Loading an old kernel, the
@@ -230,12 +235,16 @@ loader to communicate with the kernel.  Some of its options are also
 relevant to the boot loader itself, see "special command line options"
 below.
 
-The kernel command line is a null-terminated string up to 255
-characters long, plus the final null.
+The kernel command line is a null-terminated string currently up to
+255 characters long, plus the final null.  A string that is too long
+will be automatically truncated by the kernel, a boot loader may allow
+a longer command line to be passed to permit future kernels to extend
+this limit.
 
 If the boot protocol version is 2.02 or later, the address of the
 kernel command line is given by the header field cmd_line_ptr (see
-above.)
+above.)  This address can be anywhere between the end of the setup
+heap and 0xA0000.
 
 If the protocol version is *not* 2.02 or higher, the kernel
 command line is entered using the following protocol:
@@ -255,7 +264,7 @@ command line is entered using the following protocol:
 **** SAMPLE BOOT CONFIGURATION
 
 As a sample configuration, assume the following layout of the real
-mode segment:
+mode segment (this is a typical, and recommended layout):
 
        0x0000-0x7FFF   Real mode kernel
        0x8000-0x8FFF   Stack and heap
@@ -312,9 +321,9 @@ Such a boot loader should enter the following fields in the header:
 
 **** LOADING THE REST OF THE KERNEL
 
-The non-real-mode kernel starts at offset (setup_sects+1)*512 in the
-kernel file (again, if setup_sects == 0 the real value is 4.)  It
-should be loaded at address 0x10000 for Image/zImage kernels and
+The 32-bit (non-real-mode) kernel starts at offset (setup_sects+1)*512
+in the kernel file (again, if setup_sects == 0 the real value is 4.)
+It should be loaded at address 0x10000 for Image/zImage kernels and
 0x100000 for bzImage kernels.
 
 The kernel is a bzImage kernel if the protocol >= 2.00 and the 0x01
index 2616a58a5a4b829a3fb951e305cf6af37aee4cfa..9a1586590d827fcb11943247362c527dbe419105 100644 (file)
@@ -872,7 +872,13 @@ When kbuild executes the following steps are followed (roughly):
        Assignments to $(targets) are without $(obj)/ prefix.
        if_changed may be used in conjunction with custom commands as
        defined in 6.7 "Custom kbuild commands".
+
        Note: It is a typical mistake to forget the FORCE prerequisite.
+       Another common pitfall is that whitespace is sometimes
+       significant; for instance, the below will fail (note the extra space
+       after the comma):
+               target: source(s) FORCE
+       #WRONG!#        $(call if_changed, ld/objcopy/gzip)
 
     ld
        Link target. Often LDFLAGS_$@ is used to set specific options to ld.
index 3d5cd7a09b2fc1aa56b6c197ee8d35df7116ec4d..d2f0c67ba1fb01e419966178138629048d2202bb 100644 (file)
@@ -1174,6 +1174,11 @@ running once the system is up.
                        New name for the ramdisk parameter.
                        See Documentation/ramdisk.txt.
 
+       rdinit=         [KNL]
+                       Format: <full_path>
+                       Run specified binary instead of /init from the ramdisk,
+                       used for early userspace startup. See initrd.
+
        reboot=         [BUGS=IA-32,BUGS=ARM,BUGS=IA-64] Rebooting mode
                        Format: <reboot_mode>[,<reboot_mode2>[,...]]
                        See arch/*/kernel/reboot.c.
diff --git a/Documentation/networking/README.ipw2100 b/Documentation/networking/README.ipw2100
new file mode 100644 (file)
index 0000000..2046948
--- /dev/null
@@ -0,0 +1,246 @@
+
+===========================
+Intel(R) PRO/Wireless 2100 Network Connection Driver for Linux
+README.ipw2100
+
+March 14, 2005
+
+===========================
+Index
+---------------------------
+0. Introduction
+1. Release 1.1.0 Current Features
+2. Command Line Parameters
+3. Sysfs Helper Files
+4. Radio Kill Switch
+5. Dynamic Firmware
+6. Power Management
+7. Support
+8. License
+
+
+===========================
+0. Introduction
+------------ -----   -----       ----       ---       --         -     
+
+This document provides a brief overview of the features supported by the 
+IPW2100 driver project.  The main project website, where the latest 
+development version of the driver can be found, is:
+
+       http://ipw2100.sourceforge.net
+
+There you can find the not only the latest releases, but also information about
+potential fixes and patches, as well as links to the development mailing list
+for the driver project.
+
+
+===========================
+1. Release 1.1.0 Current Supported Features
+---------------------------     
+- Managed (BSS) and Ad-Hoc (IBSS)
+- WEP (shared key and open)
+- Wireless Tools support 
+- 802.1x (tested with XSupplicant 1.0.1)
+
+Enabled (but not supported) features:
+- Monitor/RFMon mode
+- WPA/WPA2
+
+The distinction between officially supported and enabled is a reflection
+on the amount of validation and interoperability testing that has been
+performed on a given feature.
+
+
+===========================
+2. Command Line Parameters
+---------------------------     
+
+If the driver is built as a module, the following optional parameters are used
+by entering them on the command line with the modprobe command using this
+syntax:
+
+       modprobe ipw2100 [<option>=<VAL1><,VAL2>...]
+
+For example, to disable the radio on driver loading, enter:
+
+       modprobe ipw2100 disable=1
+
+The ipw2100 driver supports the following module parameters:
+
+Name           Value           Example:
+debug          0x0-0xffffffff  debug=1024
+mode           0,1,2           mode=1   /* AdHoc */
+channel                int             channel=3 /* Only valid in AdHoc or Monitor */
+associate      boolean         associate=0 /* Do NOT auto associate */
+disable                boolean         disable=1 /* Do not power the HW */
+
+
+===========================
+3. Sysfs Helper Files
+---------------------------     
+
+There are several ways to control the behavior of the driver.  Many of the 
+general capabilities are exposed through the Wireless Tools (iwconfig).  There
+are a few capabilities that are exposed through entries in the Linux Sysfs.
+
+
+----- Driver Level ------
+For the driver level files, look in /sys/bus/pci/drivers/ipw2100/
+
+  debug_level  
+       
+       This controls the same global as the 'debug' module parameter.  For 
+        information on the various debugging levels available, run the 'dvals'
+       script found in the driver source directory.
+
+       NOTE:  'debug_level' is only enabled if CONFIG_IPW2100_DEBUG is turn
+              on.
+
+----- Device Level ------
+For the device level files look in
+       
+       /sys/bus/pci/drivers/ipw2100/{PCI-ID}/
+
+For example:
+       /sys/bus/pci/drivers/ipw2100/0000:02:01.0
+
+For the device level files, see /sys/bus/pci/drivers/ipw2100:
+
+  rf_kill
+       read - 
+       0 = RF kill not enabled (radio on)
+       1 = SW based RF kill active (radio off)
+       2 = HW based RF kill active (radio off)
+       3 = Both HW and SW RF kill active (radio off)
+       write -
+       0 = If SW based RF kill active, turn the radio back on
+       1 = If radio is on, activate SW based RF kill
+
+       NOTE: If you enable the SW based RF kill and then toggle the HW
+       based RF kill from ON -> OFF -> ON, the radio will NOT come back on
+
+
+===========================
+4. Radio Kill Switch
+---------------------------
+Most laptops provide the ability for the user to physically disable the radio.
+Some vendors have implemented this as a physical switch that requires no
+software to turn the radio off and on.  On other laptops, however, the switch
+is controlled through a button being pressed and a software driver then making
+calls to turn the radio off and on.  This is referred to as a "software based
+RF kill switch"
+
+See the Sysfs helper file 'rf_kill' for determining the state of the RF switch
+on your system.
+
+
+===========================
+5. Dynamic Firmware
+---------------------------     
+As the firmware is licensed under a restricted use license, it can not be 
+included within the kernel sources.  To enable the IPW2100 you will need a 
+firmware image to load into the wireless NIC's processors.
+
+You can obtain these images from <http://ipw2100.sf.net/firmware.php>.
+
+See INSTALL for instructions on installing the firmware.
+
+
+===========================
+6. Power Management
+---------------------------     
+The IPW2100 supports the configuration of the Power Save Protocol 
+through a private wireless extension interface.  The IPW2100 supports 
+the following different modes:
+
+       off     No power management.  Radio is always on.
+       on      Automatic power management
+       1-5     Different levels of power management.  The higher the 
+               number the greater the power savings, but with an impact to 
+               packet latencies. 
+
+Power management works by powering down the radio after a certain 
+interval of time has passed where no packets are passed through the 
+radio.  Once powered down, the radio remains in that state for a given 
+period of time.  For higher power savings, the interval between last 
+packet processed to sleep is shorter and the sleep period is longer.
+
+When the radio is asleep, the access point sending data to the station 
+must buffer packets at the AP until the station wakes up and requests 
+any buffered packets.  If you have an AP that does not correctly support 
+the PSP protocol you may experience packet loss or very poor performance 
+while power management is enabled.  If this is the case, you will need 
+to try and find a firmware update for your AP, or disable power 
+management (via `iwconfig eth1 power off`)
+
+To configure the power level on the IPW2100 you use a combination of 
+iwconfig and iwpriv.  iwconfig is used to turn power management on, off, 
+and set it to auto.
+
+       iwconfig eth1 power off    Disables radio power down
+       iwconfig eth1 power on     Enables radio power management to 
+                                  last set level (defaults to AUTO)
+       iwpriv eth1 set_power 0    Sets power level to AUTO and enables 
+                                  power management if not previously 
+                                  enabled.
+       iwpriv eth1 set_power 1-5  Set the power level as specified, 
+                                  enabling power management if not 
+                                  previously enabled.
+
+You can view the current power level setting via:
+       
+       iwpriv eth1 get_power
+
+It will return the current period or timeout that is configured as a string
+in the form of xxxx/yyyy (z) where xxxx is the timeout interval (amount of
+time after packet processing), yyyy is the period to sleep (amount of time to 
+wait before powering the radio and querying the access point for buffered
+packets), and z is the 'power level'.  If power management is turned off the
+xxxx/yyyy will be replaced with 'off' -- the level reported will be the active
+level if `iwconfig eth1 power on` is invoked.
+
+
+===========================
+7. Support
+---------------------------     
+
+For general development information and support,
+go to:
+       
+    http://ipw2100.sf.net/
+
+The ipw2100 1.1.0 driver and firmware can be downloaded from:  
+
+    http://support.intel.com
+
+For installation support on the ipw2100 1.1.0 driver on Linux kernels 
+2.6.8 or greater, email support is available from:  
+
+    http://supportmail.intel.com
+
+===========================
+8. License
+---------------------------     
+
+  Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License (version 2) as 
+  published by the Free Software Foundation.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  License Contact Information:
+  James P. Ketrenos <ipw2100-admin@linux.intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
diff --git a/Documentation/networking/README.ipw2200 b/Documentation/networking/README.ipw2200
new file mode 100644 (file)
index 0000000..6916080
--- /dev/null
@@ -0,0 +1,300 @@
+
+Intel(R) PRO/Wireless 2915ABG Driver for Linux in support of:
+
+Intel(R) PRO/Wireless 2200BG Network Connection 
+Intel(R) PRO/Wireless 2915ABG Network Connection 
+
+Note: The Intel(R) PRO/Wireless 2915ABG Driver for Linux and Intel(R) 
+PRO/Wireless 2200BG Driver for Linux is a unified driver that works on 
+both hardware adapters listed above. In this document the Intel(R) 
+PRO/Wireless 2915ABG Driver for Linux will be used to reference the 
+unified driver.
+
+Copyright (C) 2004-2005, Intel Corporation
+
+README.ipw2200
+
+Version: 1.0.0
+Date   : January 31, 2005
+
+
+Index
+-----------------------------------------------
+1.   Introduction
+1.1. Overview of features
+1.2. Module parameters
+1.3. Wireless Extension Private Methods
+1.4. Sysfs Helper Files
+2.   About the Version Numbers
+3.   Support
+4.   License
+
+
+1.   Introduction
+-----------------------------------------------
+The following sections attempt to provide a brief introduction to using 
+the Intel(R) PRO/Wireless 2915ABG Driver for Linux.
+
+This document is not meant to be a comprehensive manual on 
+understanding or using wireless technologies, but should be sufficient 
+to get you moving without wires on Linux.
+
+For information on building and installing the driver, see the INSTALL
+file.
+
+
+1.1. Overview of Features
+-----------------------------------------------
+The current release (1.0.0) supports the following features:
+
++ BSS mode (Infrastructure, Managed)
++ IBSS mode (Ad-Hoc)
++ WEP (OPEN and SHARED KEY mode)
++ 802.1x EAP via wpa_supplicant and xsupplicant
++ Wireless Extension support 
++ Full B and G rate support (2200 and 2915)
++ Full A rate support (2915 only)
++ Transmit power control
++ S state support (ACPI suspend/resume)
++ long/short preamble support
+
+
+
+1.2. Command Line Parameters
+-----------------------------------------------
+
+Like many modules used in the Linux kernel, the Intel(R) PRO/Wireless 
+2915ABG Driver for Linux allows certain configuration options to be 
+provided as module parameters.  The most common way to specify a module 
+parameter is via the command line.  
+
+The general form is:
+
+% modprobe ipw2200 parameter=value
+
+Where the supported parameter are:
+
+  associate
+       Set to 0 to disable the auto scan-and-associate functionality of the
+       driver.  If disabled, the driver will not attempt to scan 
+       for and associate to a network until it has been configured with 
+       one or more properties for the target network, for example configuring 
+       the network SSID.  Default is 1 (auto-associate)
+       
+       Example: % modprobe ipw2200 associate=0
+
+  auto_create
+       Set to 0 to disable the auto creation of an Ad-Hoc network 
+       matching the channel and network name parameters provided.  
+       Default is 1.
+
+  channel
+       channel number for association.  The normal method for setting
+        the channel would be to use the standard wireless tools
+        (i.e. `iwconfig eth1 channel 10`), but it is useful sometimes
+       to set this while debugging.  Channel 0 means 'ANY'
+
+  debug
+       If using a debug build, this is used to control the amount of debug
+       info is logged.  See the 'dval' and 'load' script for more info on
+       how to use this (the dval and load scripts are provided as part 
+       of the ipw2200 development snapshot releases available from the 
+       SourceForge project at http://ipw2200.sf.net)
+
+  mode
+       Can be used to set the default mode of the adapter.  
+       0 = Managed, 1 = Ad-Hoc
+
+
+1.3. Wireless Extension Private Methods
+-----------------------------------------------
+
+As an interface designed to handle generic hardware, there are certain 
+capabilities not exposed through the normal Wireless Tool interface.  As 
+such, a provision is provided for a driver to declare custom, or 
+private, methods.  The Intel(R) PRO/Wireless 2915ABG Driver for Linux 
+defines several of these to configure various settings.
+
+The general form of using the private wireless methods is:
+
+       % iwpriv $IFNAME method parameters
+
+Where $IFNAME is the interface name the device is registered with 
+(typically eth1, customized via one of the various network interface
+name managers, such as ifrename)
+
+The supported private methods are:
+
+  get_mode
+       Can be used to report out which IEEE mode the driver is 
+       configured to support.  Example:
+       
+       % iwpriv eth1 get_mode
+       eth1    get_mode:802.11bg (6)
+
+  set_mode
+       Can be used to configure which IEEE mode the driver will 
+       support.  
+
+       Usage:
+       % iwpriv eth1 set_mode {mode}
+       Where {mode} is a number in the range 1-7:
+       1       802.11a (2915 only)
+       2       802.11b
+       3       802.11ab (2915 only)
+       4       802.11g 
+       5       802.11ag (2915 only)
+       6       802.11bg
+       7       802.11abg (2915 only)
+
+  get_preamble
+       Can be used to report configuration of preamble length.
+
+  set_preamble
+       Can be used to set the configuration of preamble length:
+
+       Usage:
+       % iwpriv eth1 set_preamble {mode}
+       Where {mode} is one of:
+       1       Long preamble only
+       0       Auto (long or short based on connection)
+       
+
+1.4. Sysfs Helper Files:
+-----------------------------------------------
+
+The Linux kernel provides a pseudo file system that can be used to 
+access various components of the operating system.  The Intel(R) 
+PRO/Wireless 2915ABG Driver for Linux exposes several configuration 
+parameters through this mechanism.
+
+An entry in the sysfs can support reading and/or writing.  You can 
+typically query the contents of a sysfs entry through the use of cat, 
+and can set the contents via echo.  For example:
+
+% cat /sys/bus/pci/drivers/ipw2200/debug_level
+
+Will report the current debug level of the driver's logging subsystem 
+(only available if CONFIG_IPW_DEBUG was configured when the driver was 
+built).
+
+You can set the debug level via:
+
+% echo $VALUE > /sys/bus/pci/drivers/ipw2200/debug_level
+
+Where $VALUE would be a number in the case of this sysfs entry.  The 
+input to sysfs files does not have to be a number.  For example, the 
+firmware loader used by hotplug utilizes sysfs entries for transferring 
+the firmware image from user space into the driver.
+
+The Intel(R) PRO/Wireless 2915ABG Driver for Linux exposes sysfs entries 
+at two levels -- driver level, which apply to all instances of the 
+driver (in the event that there are more than one device installed) and 
+device level, which applies only to the single specific instance.
+
+
+1.4.1 Driver Level Sysfs Helper Files
+-----------------------------------------------
+
+For the driver level files, look in /sys/bus/pci/drivers/ipw2200/
+
+  debug_level  
+       
+       This controls the same global as the 'debug' module parameter
+
+
+1.4.2 Device Level Sysfs Helper Files
+-----------------------------------------------
+
+For the device level files, look in
+       
+       /sys/bus/pci/drivers/ipw2200/{PCI-ID}/
+
+For example:
+       /sys/bus/pci/drivers/ipw2200/0000:02:01.0
+
+For the device level files, see /sys/bus/pci/[drivers/ipw2200:
+
+  rf_kill
+       read - 
+       0 = RF kill not enabled (radio on)
+       1 = SW based RF kill active (radio off)
+       2 = HW based RF kill active (radio off)
+       3 = Both HW and SW RF kill active (radio off)
+       write -
+       0 = If SW based RF kill active, turn the radio back on
+       1 = If radio is on, activate SW based RF kill
+
+       NOTE: If you enable the SW based RF kill and then toggle the HW
+       based RF kill from ON -> OFF -> ON, the radio will NOT come back on
+       
+  ucode 
+       read-only access to the ucode version number
+
+
+2.   About the Version Numbers
+-----------------------------------------------
+
+Due to the nature of open source development projects, there are 
+frequently changes being incorporated that have not gone through 
+a complete validation process.  These changes are incorporated into 
+development snapshot releases.
+
+Releases are numbered with a three level scheme: 
+
+       major.minor.development
+
+Any version where the 'development' portion is 0 (for example
+1.0.0, 1.1.0, etc.) indicates a stable version that will be made 
+available for kernel inclusion.
+
+Any version where the 'development' portion is not a 0 (for
+example 1.0.1, 1.1.5, etc.) indicates a development version that is
+being made available for testing and cutting edge users.  The stability 
+and functionality of the development releases are not know.  We make
+efforts to try and keep all snapshots reasonably stable, but due to the
+frequency of their release, and the desire to get those releases 
+available as quickly as possible, unknown anomalies should be expected.
+
+The major version number will be incremented when significant changes
+are made to the driver.  Currently, there are no major changes planned.
+
+
+3.  Support
+-----------------------------------------------
+
+For installation support of the 1.0.0 version, you can contact 
+http://supportmail.intel.com, or you can use the open source project 
+support.
+
+For general information and support, go to:
+       
+    http://ipw2200.sf.net/
+
+
+4.  License
+-----------------------------------------------
+
+  Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License version 2 as 
+  published by the Free Software Foundation.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  James P. Ketrenos <ipw2100-admin@linux.intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+
diff --git a/Documentation/networking/cxgb.txt b/Documentation/networking/cxgb.txt
new file mode 100644 (file)
index 0000000..7632463
--- /dev/null
@@ -0,0 +1,352 @@
+                 Chelsio N210 10Gb Ethernet Network Controller
+
+                         Driver Release Notes for Linux
+
+                                 Version 2.1.1
+
+                                 June 20, 2005
+
+CONTENTS
+========
+ INTRODUCTION
+ FEATURES
+ PERFORMANCE
+ DRIVER MESSAGES
+ KNOWN ISSUES
+ SUPPORT
+
+
+INTRODUCTION
+============
+
+ This document describes the Linux driver for Chelsio 10Gb Ethernet Network
+ Controller. This driver supports the Chelsio N210 NIC and is backward
+ compatible with the Chelsio N110 model 10Gb NICs.
+
+
+FEATURES
+========
+
+ Adaptive Interrupts (adaptive-rx)
+ ---------------------------------
+
+  This feature provides an adaptive algorithm that adjusts the interrupt
+  coalescing parameters, allowing the driver to dynamically adapt the latency
+  settings to achieve the highest performance during various types of network
+  load.
+
+  The interface used to control this feature is ethtool. Please see the
+  ethtool manpage for additional usage information.
+
+  By default, adaptive-rx is disabled.
+  To enable adaptive-rx:
+
+      ethtool -C <interface> adaptive-rx on
+
+  To disable adaptive-rx, use ethtool:
+
+      ethtool -C <interface> adaptive-rx off
+
+  After disabling adaptive-rx, the timer latency value will be set to 50us.
+  You may set the timer latency after disabling adaptive-rx:
+
+      ethtool -C <interface> rx-usecs <microseconds>
+
+  An example to set the timer latency value to 100us on eth0:
+
+      ethtool -C eth0 rx-usecs 100
+
+  You may also provide a timer latency value while disabling adpative-rx:
+
+      ethtool -C <interface> adaptive-rx off rx-usecs <microseconds>
+
+  If adaptive-rx is disabled and a timer latency value is specified, the timer
+  will be set to the specified value until changed by the user or until
+  adaptive-rx is enabled.
+
+  To view the status of the adaptive-rx and timer latency values:
+
+      ethtool -c <interface>
+
+
+ TCP Segmentation Offloading (TSO) Support
+ -----------------------------------------
+
+  This feature, also known as "large send", enables a system's protocol stack
+  to offload portions of outbound TCP processing to a network interface card
+  thereby reducing system CPU utilization and enhancing performance.
+
+  The interface used to control this feature is ethtool version 1.8 or higher.
+  Please see the ethtool manpage for additional usage information.
+
+  By default, TSO is enabled.
+  To disable TSO:
+
+      ethtool -K <interface> tso off
+
+  To enable TSO:
+
+      ethtool -K <interface> tso on
+
+  To view the status of TSO:
+
+      ethtool -k <interface>
+
+
+PERFORMANCE
+===========
+
+ The following information is provided as an example of how to change system
+ parameters for "performance tuning" an what value to use. You may or may not
+ want to change these system parameters, depending on your server/workstation
+ application. Doing so is not warranted in any way by Chelsio Communications,
+ and is done at "YOUR OWN RISK". Chelsio will not be held responsible for loss
+ of data or damage to equipment.
+
+ Your distribution may have a different way of doing things, or you may prefer
+ a different method. These commands are shown only to provide an example of
+ what to do and are by no means definitive.
+
+ Making any of the following system changes will only last until you reboot
+ your system. You may want to write a script that runs at boot-up which
+ includes the optimal settings for your system.
+
+  Setting PCI Latency Timer:
+      setpci -d 1425:* 0x0c.l=0x0000F800
+
+  Disabling TCP timestamp:
+      sysctl -w net.ipv4.tcp_timestamps=0
+
+  Disabling SACK:
+      sysctl -w net.ipv4.tcp_sack=0
+
+  Setting large number of incoming connection requests:
+      sysctl -w net.ipv4.tcp_max_syn_backlog=3000
+
+  Setting maximum receive socket buffer size:
+      sysctl -w net.core.rmem_max=1024000
+
+  Setting maximum send socket buffer size:
+      sysctl -w net.core.wmem_max=1024000
+
+  Set smp_affinity (on a multiprocessor system) to a single CPU:
+      echo 1 > /proc/irq/<interrupt_number>/smp_affinity
+
+  Setting default receive socket buffer size:
+      sysctl -w net.core.rmem_default=524287
+
+  Setting default send socket buffer size:
+      sysctl -w net.core.wmem_default=524287
+
+  Setting maximum option memory buffers:
+      sysctl -w net.core.optmem_max=524287
+
+  Setting maximum backlog (# of unprocessed packets before kernel drops):
+      sysctl -w net.core.netdev_max_backlog=300000
+
+  Setting TCP read buffers (min/default/max):
+      sysctl -w net.ipv4.tcp_rmem="10000000 10000000 10000000"
+
+  Setting TCP write buffers (min/pressure/max):
+      sysctl -w net.ipv4.tcp_wmem="10000000 10000000 10000000"
+
+  Setting TCP buffer space (min/pressure/max):
+      sysctl -w net.ipv4.tcp_mem="10000000 10000000 10000000"
+
+  TCP window size for single connections:
+   The receive buffer (RX_WINDOW) size must be at least as large as the
+   Bandwidth-Delay Product of the communication link between the sender and
+   receiver. Due to the variations of RTT, you may want to increase the buffer
+   size up to 2 times the Bandwidth-Delay Product. Reference page 289 of
+   "TCP/IP Illustrated, Volume 1, The Protocols" by W. Richard Stevens.
+   At 10Gb speeds, use the following formula:
+       RX_WINDOW >= 1.25MBytes * RTT(in milliseconds)
+       Example for RTT with 100us: RX_WINDOW = (1,250,000 * 0.1) = 125,000
+   RX_WINDOW sizes of 256KB - 512KB should be sufficient.
+   Setting the min, max, and default receive buffer (RX_WINDOW) size:
+       sysctl -w net.ipv4.tcp_rmem="<min> <default> <max>"
+
+  TCP window size for multiple connections:
+   The receive buffer (RX_WINDOW) size may be calculated the same as single
+   connections, but should be divided by the number of connections. The
+   smaller window prevents congestion and facilitates better pacing,
+   especially if/when MAC level flow control does not work well or when it is
+   not supported on the machine. Experimentation may be necessary to attain
+   the correct value. This method is provided as a starting point fot the
+   correct receive buffer size.
+   Setting the min, max, and default receive buffer (RX_WINDOW) size is
+   performed in the same manner as single connection.
+
+
+DRIVER MESSAGES
+===============
+
+ The following messages are the most common messages logged by syslog. These
+ may be found in /var/log/messages.
+
+  Driver up:
+     Chelsio Network Driver - version 2.1.1
+
+  NIC detected:
+     eth#: Chelsio N210 1x10GBaseX NIC (rev #), PCIX 133MHz/64-bit
+
+  Link up:
+     eth#: link is up at 10 Gbps, full duplex
+
+  Link down:
+     eth#: link is down
+
+
+KNOWN ISSUES
+============
+
+ These issues have been identified during testing. The following information
+ is provided as a workaround to the problem. In some cases, this problem is
+ inherent to Linux or to a particular Linux Distribution and/or hardware
+ platform.
+
+  1. Large number of TCP retransmits on a multiprocessor (SMP) system.
+
+      On a system with multiple CPUs, the interrupt (IRQ) for the network
+      controller may be bound to more than one CPU. This will cause TCP
+      retransmits if the packet data were to be split across different CPUs
+      and re-assembled in a different order than expected.
+
+      To eliminate the TCP retransmits, set smp_affinity on the particular
+      interrupt to a single CPU. You can locate the interrupt (IRQ) used on
+      the N110/N210 by using ifconfig:
+          ifconfig <dev_name> | grep Interrupt
+      Set the smp_affinity to a single CPU:
+          echo 1 > /proc/irq/<interrupt_number>/smp_affinity
+
+      It is highly suggested that you do not run the irqbalance daemon on your
+      system, as this will change any smp_affinity setting you have applied.
+      The irqbalance daemon runs on a 10 second interval and binds interrupts
+      to the least loaded CPU determined by the daemon. To disable this daemon:
+          chkconfig --level 2345 irqbalance off
+
+      By default, some Linux distributions enable the kernel feature,
+      irqbalance, which performs the same function as the daemon. To disable
+      this feature, add the following line to your bootloader:
+          noirqbalance
+
+          Example using the Grub bootloader:
+              title Red Hat Enterprise Linux AS (2.4.21-27.ELsmp)
+              root (hd0,0)
+              kernel /vmlinuz-2.4.21-27.ELsmp ro root=/dev/hda3 noirqbalance
+              initrd /initrd-2.4.21-27.ELsmp.img
+
+  2. After running insmod, the driver is loaded and the incorrect network
+     interface is brought up without running ifup.
+
+      When using 2.4.x kernels, including RHEL kernels, the Linux kernel
+      invokes a script named "hotplug". This script is primarily used to
+      automatically bring up USB devices when they are plugged in, however,
+      the script also attempts to automatically bring up a network interface
+      after loading the kernel module. The hotplug script does this by scanning
+      the ifcfg-eth# config files in /etc/sysconfig/network-scripts, looking
+      for HWADDR=<mac_address>.
+
+      If the hotplug script does not find the HWADDRR within any of the
+      ifcfg-eth# files, it will bring up the device with the next available
+      interface name. If this interface is already configured for a different
+      network card, your new interface will have incorrect IP address and
+      network settings.
+
+      To solve this issue, you can add the HWADDR=<mac_address> key to the
+      interface config file of your network controller.
+
+      To disable this "hotplug" feature, you may add the driver (module name)
+      to the "blacklist" file located in /etc/hotplug. It has been noted that
+      this does not work for network devices because the net.agent script
+      does not use the blacklist file. Simply remove, or rename, the net.agent
+      script located in /etc/hotplug to disable this feature.
+
+  3. Transport Protocol (TP) hangs when running heavy multi-connection traffic
+     on an AMD Opteron system with HyperTransport PCI-X Tunnel chipset.
+
+      If your AMD Opteron system uses the AMD-8131 HyperTransport PCI-X Tunnel
+      chipset, you may experience the "133-Mhz Mode Split Completion Data
+      Corruption" bug identified by AMD while using a 133Mhz PCI-X card on the
+      bus PCI-X bus.
+
+      AMD states, "Under highly specific conditions, the AMD-8131 PCI-X Tunnel
+      can provide stale data via split completion cycles to a PCI-X card that
+      is operating at 133 Mhz", causing data corruption.
+
+      AMD's provides three workarounds for this problem, however, Chelsio
+      recommends the first option for best performance with this bug:
+
+        For 133Mhz secondary bus operation, limit the transaction length and
+        the number of outstanding transactions, via BIOS configuration
+        programming of the PCI-X card, to the following:
+
+           Data Length (bytes): 1k
+           Total allowed outstanding transactions: 2
+
+      Please refer to AMD 8131-HT/PCI-X Errata 26310 Rev 3.08 August 2004,
+      section 56, "133-MHz Mode Split Completion Data Corruption" for more
+      details with this bug and workarounds suggested by AMD.
+
+      It may be possible to work outside AMD's recommended PCI-X settings, try
+      increasing the Data Length to 2k bytes for increased performance. If you
+      have issues with these settings, please revert to the "safe" settings
+      and duplicate the problem before submitting a bug or asking for support.
+
+      NOTE: The default setting on most systems is 8 outstanding transactions
+            and 2k bytes data length.
+
+  4. On multiprocessor systems, it has been noted that an application which
+     is handling 10Gb networking can switch between CPUs causing degraded
+     and/or unstable performance.
+
+      If running on an SMP system and taking performance measurements, it
+      is suggested you either run the latest netperf-2.4.0+ or use a binding
+      tool such as Tim Hockin's procstate utilities (runon)
+      <http://www.hockin.org/~thockin/procstate/>.
+
+      Binding netserver and netperf (or other applications) to particular
+      CPUs will have a significant difference in performance measurements.
+      You may need to experiment which CPU to bind the application to in
+      order to achieve the best performance for your system.
+
+      If you are developing an application designed for 10Gb networking,
+      please keep in mind you may want to look at kernel functions
+      sched_setaffinity & sched_getaffinity to bind your application.
+
+      If you are just running user-space applications such as ftp, telnet,
+      etc., you may want to try the runon tool provided by Tim Hockin's
+      procstate utility. You could also try binding the interface to a
+      particular CPU: runon 0 ifup eth0
+
+
+SUPPORT
+=======
+
+ If you have problems with the software or hardware, please contact our
+ customer support team via email at support@chelsio.com or check our website
+ at http://www.chelsio.com
+
+===============================================================================
+
+ Chelsio Communications
+ 370 San Aleso Ave.
+ Suite 100
+ Sunnyvale, CA 94085
+ http://www.chelsio.com
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License, version 2, as
+published by the Free Software Foundation.
+
+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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+ Copyright (c) 2003-2005 Chelsio Communications. All rights reserved.
+
+===============================================================================
diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt
new file mode 100644 (file)
index 0000000..29ccae4
--- /dev/null
@@ -0,0 +1,288 @@
+
+-------
+PHY Abstraction Layer
+(Updated 2005-07-21)
+
+Purpose
+
+ Most network devices consist of set of registers which provide an interface
+ to a MAC layer, which communicates with the physical connection through a
+ PHY.  The PHY concerns itself with negotiating link parameters with the link
+ partner on the other side of the network connection (typically, an ethernet
+ cable), and provides a register interface to allow drivers to determine what
+ settings were chosen, and to configure what settings are allowed.
+
+ While these devices are distinct from the network devices, and conform to a
+ standard layout for the registers, it has been common practice to integrate
+ the PHY management code with the network driver.  This has resulted in large
+ amounts of redundant code.  Also, on embedded systems with multiple (and
+ sometimes quite different) ethernet controllers connected to the same 
+ management bus, it is difficult to ensure safe use of the bus.
+
+ Since the PHYs are devices, and the management busses through which they are
+ accessed are, in fact, busses, the PHY Abstraction Layer treats them as such.
+ In doing so, it has these goals:
+
+   1) Increase code-reuse
+   2) Increase overall code-maintainability
+   3) Speed development time for new network drivers, and for new systems
+ Basically, this layer is meant to provide an interface to PHY devices which
+ allows network driver writers to write as little code as possible, while
+ still providing a full feature set.
+
+The MDIO bus
+
+ Most network devices are connected to a PHY by means of a management bus.
+ Different devices use different busses (though some share common interfaces).
+ In order to take advantage of the PAL, each bus interface needs to be
+ registered as a distinct device.
+
+ 1) read and write functions must be implemented.  Their prototypes are:
+
+     int write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
+     int read(struct mii_bus *bus, int mii_id, int regnum);
+
+   mii_id is the address on the bus for the PHY, and regnum is the register
+   number.  These functions are guaranteed not to be called from interrupt
+   time, so it is safe for them to block, waiting for an interrupt to signal
+   the operation is complete
+ 2) A reset function is necessary.  This is used to return the bus to an
+   initialized state.
+
+ 3) A probe function is needed.  This function should set up anything the bus
+   driver needs, setup the mii_bus structure, and register with the PAL using
+   mdiobus_register.  Similarly, there's a remove function to undo all of
+   that (use mdiobus_unregister).
+ 4) Like any driver, the device_driver structure must be configured, and init
+   exit functions are used to register the driver.
+
+ 5) The bus must also be declared somewhere as a device, and registered.
+
+ As an example for how one driver implemented an mdio bus driver, see
+ drivers/net/gianfar_mii.c and arch/ppc/syslib/mpc85xx_devices.c
+
+Connecting to a PHY
+
+ Sometime during startup, the network driver needs to establish a connection
+ between the PHY device, and the network device.  At this time, the PHY's bus
+ and drivers need to all have been loaded, so it is ready for the connection.
+ At this point, there are several ways to connect to the PHY:
+
+ 1) The PAL handles everything, and only calls the network driver when
+   the link state changes, so it can react.
+
+ 2) The PAL handles everything except interrupts (usually because the
+   controller has the interrupt registers).
+
+ 3) The PAL handles everything, but checks in with the driver every second,
+   allowing the network driver to react first to any changes before the PAL
+   does.
+ 4) The PAL serves only as a library of functions, with the network device
+   manually calling functions to update status, and configure the PHY
+
+
+Letting the PHY Abstraction Layer do Everything
+
+ If you choose option 1 (The hope is that every driver can, but to still be
+ useful to drivers that can't), connecting to the PHY is simple:
+
+ First, you need a function to react to changes in the link state.  This
+ function follows this protocol:
+
+   static void adjust_link(struct net_device *dev);
+ Next, you need to know the device name of the PHY connected to this device. 
+ The name will look something like, "phy0:0", where the first number is the
+ bus id, and the second is the PHY's address on that bus.
+ Now, to connect, just call this function:
+   phydev = phy_connect(dev, phy_name, &adjust_link, flags);
+
+ phydev is a pointer to the phy_device structure which represents the PHY.  If
+ phy_connect is successful, it will return the pointer.  dev, here, is the
+ pointer to your net_device.  Once done, this function will have started the
+ PHY's software state machine, and registered for the PHY's interrupt, if it
+ has one.  The phydev structure will be populated with information about the
+ current state, though the PHY will not yet be truly operational at this
+ point.
+
+ flags is a u32 which can optionally contain phy-specific flags.
+ This is useful if the system has put hardware restrictions on
+ the PHY/controller, of which the PHY needs to be aware.
+
+ Now just make sure that phydev->supported and phydev->advertising have any
+ values pruned from them which don't make sense for your controller (a 10/100
+ controller may be connected to a gigabit capable PHY, so you would need to
+ mask off SUPPORTED_1000baseT*).  See include/linux/ethtool.h for definitions
+ for these bitfields. Note that you should not SET any bits, or the PHY may
+ get put into an unsupported state.
+
+ Lastly, once the controller is ready to handle network traffic, you call
+ phy_start(phydev).  This tells the PAL that you are ready, and configures the
+ PHY to connect to the network.  If you want to handle your own interrupts,
+ just set phydev->irq to PHY_IGNORE_INTERRUPT before you call phy_start.
+ Similarly, if you don't want to use interrupts, set phydev->irq to PHY_POLL.
+
+ When you want to disconnect from the network (even if just briefly), you call
+ phy_stop(phydev).
+
+Keeping Close Tabs on the PAL
+
+ It is possible that the PAL's built-in state machine needs a little help to
+ keep your network device and the PHY properly in sync.  If so, you can
+ register a helper function when connecting to the PHY, which will be called
+ every second before the state machine reacts to any changes.  To do this, you
+ need to manually call phy_attach() and phy_prepare_link(), and then call
+ phy_start_machine() with the second argument set to point to your special
+ handler.
+
+ Currently there are no examples of how to use this functionality, and testing
+ on it has been limited because the author does not have any drivers which use
+ it (they all use option 1).  So Caveat Emptor.
+
+Doing it all yourself
+
+ There's a remote chance that the PAL's built-in state machine cannot track
+ the complex interactions between the PHY and your network device.  If this is
+ so, you can simply call phy_attach(), and not call phy_start_machine or
+ phy_prepare_link().  This will mean that phydev->state is entirely yours to
+ handle (phy_start and phy_stop toggle between some of the states, so you
+ might need to avoid them).
+
+ An effort has been made to make sure that useful functionality can be
+ accessed without the state-machine running, and most of these functions are
+ descended from functions which did not interact with a complex state-machine.
+ However, again, no effort has been made so far to test running without the
+ state machine, so tryer beware.
+
+ Here is a brief rundown of the functions:
+
+ int phy_read(struct phy_device *phydev, u16 regnum);
+ int phy_write(struct phy_device *phydev, u16 regnum, u16 val);
+
+   Simple read/write primitives.  They invoke the bus's read/write function
+   pointers.
+
+ void phy_print_status(struct phy_device *phydev);
+   A convenience function to print out the PHY status neatly.
+
+ int phy_clear_interrupt(struct phy_device *phydev);
+ int phy_config_interrupt(struct phy_device *phydev, u32 interrupts);
+   
+   Clear the PHY's interrupt, and configure which ones are allowed,
+   respectively.  Currently only supports all on, or all off.
+ int phy_enable_interrupts(struct phy_device *phydev);
+ int phy_disable_interrupts(struct phy_device *phydev);
+
+   Functions which enable/disable PHY interrupts, clearing them
+   before and after, respectively.
+
+ int phy_start_interrupts(struct phy_device *phydev);
+ int phy_stop_interrupts(struct phy_device *phydev);
+
+   Requests the IRQ for the PHY interrupts, then enables them for
+   start, or disables then frees them for stop.
+
+ struct phy_device * phy_attach(struct net_device *dev, const char *phy_id,
+                u32 flags);
+
+   Attaches a network device to a particular PHY, binding the PHY to a generic
+   driver if none was found during bus initialization.  Passes in
+   any phy-specific flags as needed.
+
+ int phy_start_aneg(struct phy_device *phydev);
+   
+   Using variables inside the phydev structure, either configures advertising
+   and resets autonegotiation, or disables autonegotiation, and configures
+   forced settings.
+
+ static inline int phy_read_status(struct phy_device *phydev);
+
+   Fills the phydev structure with up-to-date information about the current
+   settings in the PHY.
+
+ void phy_sanitize_settings(struct phy_device *phydev)
+   
+   Resolves differences between currently desired settings, and
+   supported settings for the given PHY device.  Does not make
+   the changes in the hardware, though.
+
+ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
+ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
+
+   Ethtool convenience functions.
+
+ int phy_mii_ioctl(struct phy_device *phydev,
+                 struct mii_ioctl_data *mii_data, int cmd);
+
+   The MII ioctl.  Note that this function will completely screw up the state
+   machine if you write registers like BMCR, BMSR, ADVERTISE, etc.  Best to
+   use this only to write registers which are not standard, and don't set off
+   a renegotiation.
+
+
+PHY Device Drivers
+
+ With the PHY Abstraction Layer, adding support for new PHYs is
+ quite easy.  In some cases, no work is required at all!  However,
+ many PHYs require a little hand-holding to get up-and-running.
+
+Generic PHY driver
+
+ If the desired PHY doesn't have any errata, quirks, or special
+ features you want to support, then it may be best to not add
+ support, and let the PHY Abstraction Layer's Generic PHY Driver
+ do all of the work.  
+
+Writing a PHY driver
+
+ If you do need to write a PHY driver, the first thing to do is
+ make sure it can be matched with an appropriate PHY device.
+ This is done during bus initialization by reading the device's
+ UID (stored in registers 2 and 3), then comparing it to each
+ driver's phy_id field by ANDing it with each driver's
+ phy_id_mask field.  Also, it needs a name.  Here's an example:
+
+   static struct phy_driver dm9161_driver = {
+         .phy_id         = 0x0181b880,
+        .name           = "Davicom DM9161E",
+        .phy_id_mask    = 0x0ffffff0,
+        ...
+   }
+
+ Next, you need to specify what features (speed, duplex, autoneg,
+ etc) your PHY device and driver support.  Most PHYs support
+ PHY_BASIC_FEATURES, but you can look in include/mii.h for other
+ features.
+
+ Each driver consists of a number of function pointers:
+
+   config_init: configures PHY into a sane state after a reset.
+     For instance, a Davicom PHY requires descrambling disabled.
+   probe: Does any setup needed by the driver
+   suspend/resume: power management
+   config_aneg: Changes the speed/duplex/negotiation settings
+   read_status: Reads the current speed/duplex/negotiation settings
+   ack_interrupt: Clear a pending interrupt
+   config_intr: Enable or disable interrupts
+   remove: Does any driver take-down
+
+ Of these, only config_aneg and read_status are required to be
+ assigned by the driver code.  The rest are optional.  Also, it is
+ preferred to use the generic phy driver's versions of these two
+ functions if at all possible: genphy_read_status and
+ genphy_config_aneg.  If this is not possible, it is likely that
+ you only need to perform some actions before and after invoking
+ these functions, and so your functions will wrap the generic
+ ones.
+
+ Feel free to look at the Marvell, Cicada, and Davicom drivers in
+ drivers/net/phy/ for examples (the lxt and qsemi drivers have
+ not been tested as of this writing)
diff --git a/Documentation/power/swsusp-dmcrypt.txt b/Documentation/power/swsusp-dmcrypt.txt
new file mode 100644 (file)
index 0000000..59931b4
--- /dev/null
@@ -0,0 +1,138 @@
+Author: Andreas Steinmetz <ast@domdv.de>
+
+
+How to use dm-crypt and swsusp together:
+========================================
+
+Some prerequisites:
+You know how dm-crypt works. If not, visit the following web page:
+http://www.saout.de/misc/dm-crypt/
+You have read Documentation/power/swsusp.txt and understand it.
+You did read Documentation/initrd.txt and know how an initrd works.
+You know how to create or how to modify an initrd.
+
+Now your system is properly set up, your disk is encrypted except for
+the swap device(s) and the boot partition which may contain a mini
+system for crypto setup and/or rescue purposes. You may even have
+an initrd that does your current crypto setup already.
+
+At this point you want to encrypt your swap, too. Still you want to
+be able to suspend using swsusp. This, however, means that you
+have to be able to either enter a passphrase or that you read
+the key(s) from an external device like a pcmcia flash disk
+or an usb stick prior to resume. So you need an initrd, that sets
+up dm-crypt and then asks swsusp to resume from the encrypted
+swap device.
+
+The most important thing is that you set up dm-crypt in such
+a way that the swap device you suspend to/resume from has
+always the same major/minor within the initrd as well as
+within your running system. The easiest way to achieve this is
+to always set up this swap device first with dmsetup, so that
+it will always look like the following:
+
+brw-------  1 root root 254, 0 Jul 28 13:37 /dev/mapper/swap0
+
+Now set up your kernel to use /dev/mapper/swap0 as the default
+resume partition, so your kernel .config contains:
+
+CONFIG_PM_STD_PARTITION="/dev/mapper/swap0"
+
+Prepare your boot loader to use the initrd you will create or
+modify. For lilo the simplest setup looks like the following
+lines:
+
+image=/boot/vmlinuz
+initrd=/boot/initrd.gz
+label=linux
+append="root=/dev/ram0 init=/linuxrc rw"
+
+Finally you need to create or modify your initrd. Lets assume
+you create an initrd that reads the required dm-crypt setup
+from a pcmcia flash disk card. The card is formatted with an ext2
+fs which resides on /dev/hde1 when the card is inserted. The
+card contains at least the encrypted swap setup in a file
+named "swapkey". /etc/fstab of your initrd contains something
+like the following:
+
+/dev/hda1   /mnt    ext3      ro                            0 0
+none        /proc   proc      defaults,noatime,nodiratime   0 0
+none        /sys    sysfs     defaults,noatime,nodiratime   0 0
+
+/dev/hda1 contains an unencrypted mini system that sets up all
+of your crypto devices, again by reading the setup from the
+pcmcia flash disk. What follows now is a /linuxrc for your
+initrd that allows you to resume from encrypted swap and that
+continues boot with your mini system on /dev/hda1 if resume
+does not happen:
+
+#!/bin/sh
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+mount /proc
+mount /sys
+mapped=0
+noresume=`grep -c noresume /proc/cmdline`
+if [ "$*" != "" ]
+then
+  noresume=1
+fi
+dmesg -n 1
+/sbin/cardmgr -q
+for i in 1 2 3 4 5 6 7 8 9 0
+do
+  if [ -f /proc/ide/hde/media ]
+  then
+    usleep 500000
+    mount -t ext2 -o ro /dev/hde1 /mnt
+    if [ -f /mnt/swapkey ]
+    then
+      dmsetup create swap0 /mnt/swapkey > /dev/null 2>&1 && mapped=1
+    fi
+    umount /mnt
+    break
+  fi
+  usleep 500000
+done
+killproc /sbin/cardmgr
+dmesg -n 6
+if [ $mapped = 1 ]
+then
+  if [ $noresume != 0 ]
+  then
+    mkswap /dev/mapper/swap0 > /dev/null 2>&1
+  fi
+  echo 254:0 > /sys/power/resume
+  dmsetup remove swap0
+fi
+umount /sys
+mount /mnt
+umount /proc
+cd /mnt
+pivot_root . mnt
+mount /proc
+umount -l /mnt
+umount /proc
+exec chroot . /sbin/init $* < dev/console > dev/console 2>&1
+
+Please don't mind the weird loop above, busybox's msh doesn't know
+the let statement. Now, what is happening in the script?
+First we have to decide if we want to try to resume, or not.
+We will not resume if booting with "noresume" or any parameters
+for init like "single" or "emergency" as boot parameters.
+
+Then we need to set up dmcrypt with the setup data from the
+pcmcia flash disk. If this succeeds we need to reset the swap
+device if we don't want to resume. The line "echo 254:0 > /sys/power/resume"
+then attempts to resume from the first device mapper device.
+Note that it is important to set the device in /sys/power/resume,
+regardless if resuming or not, otherwise later suspend will fail.
+If resume starts, script execution terminates here.
+
+Otherwise we just remove the encrypted swap device and leave it to the
+mini system on /dev/hda1 to set the whole crypto up (it is up to
+you to modify this to your taste).
+
+What then follows is the well known process to change the root
+file system and continue booting from there. I prefer to unmount
+the initrd prior to continue booting but it is up to you to modify
+this.
index 7a6b7896645942d69815ee3b37594618367a9069..b0d50840788ebf80fd478ac9db3e8ef841716e26 100644 (file)
@@ -1,22 +1,20 @@
-From kernel/suspend.c:
+Some warnings, first.
 
  * BIG FAT WARNING *********************************************************
  *
- * If you have unsupported (*) devices using DMA...
- *                             ...say goodbye to your data.
- *
  * If you touch anything on disk between suspend and resume...
  *                             ...kiss your data goodbye.
  *
- * If your disk driver does not support suspend... (IDE does)
- *                             ...you'd better find out how to get along
- *                                without your data.
- *
- * If you change kernel command line between suspend and resume...
- *                             ...prepare for nasty fsck or worse.
+ * If you do resume from initrd after your filesystems are mounted...
+ *                             ...bye bye root partition.
+ *                     [this is actually same case as above]
  *
- * If you change your hardware while system is suspended...
- *                             ...well, it was not good idea.
+ * If you have unsupported (*) devices using DMA, you may have some
+ * problems. If your disk driver does not support suspend... (IDE does),
+ * it may cause some problems, too. If you change kernel command line
+ * between suspend and resume, it may do something wrong. If you change
+ * your hardware while system is suspended... well, it was not good idea;
+ * but it will probably only crash.
  *
  * (*) suspend/resume support is needed to make it safe.
 
@@ -30,6 +28,13 @@ echo shutdown > /sys/power/disk; echo disk > /sys/power/state
 echo platform > /sys/power/disk; echo disk > /sys/power/state
 
 
+Encrypted suspend image:
+------------------------
+If you want to store your suspend image encrypted with a temporary
+key to prevent data gathering after resume you must compile
+crypto and the aes algorithm into the kernel - modules won't work
+as they cannot be loaded at resume time.
+
 
 Article about goals and implementation of Software Suspend for Linux
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -85,11 +90,6 @@ resume.
 You have your server on UPS. Power died, and UPS is indicating 30
 seconds to failure. What do you do? Suspend to disk.
 
-Ethernet card in your server died. You want to replace it. Your
-server is not hotplug capable. What do you do? Suspend to disk,
-replace ethernet card, resume. If you are fast your users will not
-even see broken connections.
-
 
 Q: Maybe I'm missing something, but why don't the regular I/O paths work?
 
@@ -117,31 +117,6 @@ Q: Does linux support ACPI S4?
 
 A: Yes. That's what echo platform > /sys/power/disk does.
 
-Q: My machine doesn't work with ACPI. How can I use swsusp than ?
-
-A: Do a reboot() syscall with right parameters. Warning: glibc gets in
-its way, so check with strace:
-
-reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, 0xd000fce2)
-
-(Thanks to Peter Osterlund:)
-
-#include <unistd.h>
-#include <syscall.h>
-
-#define LINUX_REBOOT_MAGIC1     0xfee1dead
-#define LINUX_REBOOT_MAGIC2     672274793
-#define LINUX_REBOOT_CMD_SW_SUSPEND     0xD000FCE2
-
-int main()
-{
-    syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
-            LINUX_REBOOT_CMD_SW_SUSPEND, 0);
-    return 0;
-}
-
-Also /sys/ interface should be still present.
-
 Q: What is 'suspend2'?
 
 A: suspend2 is 'Software Suspend 2', a forked implementation of
@@ -311,3 +286,46 @@ As a rule of thumb use encrypted swap to protect your data while your
 system is shut down or suspended. Additionally use the encrypted
 suspend image to prevent sensitive data from being stolen after
 resume.
+
+Q: Why can't we suspend to a swap file?
+
+A: Because accessing swap file needs the filesystem mounted, and
+filesystem might do something wrong (like replaying the journal)
+during mount.
+
+There are few ways to get that fixed:
+
+1) Probably could be solved by modifying every filesystem to support
+some kind of "really read-only!" option. Patches welcome.
+
+2) suspend2 gets around that by storing absolute positions in on-disk
+image (and blocksize), with resume parameter pointing directly to
+suspend header.
+
+Q: Is there a maximum system RAM size that is supported by swsusp?
+
+A: It should work okay with highmem.
+
+Q: Does swsusp (to disk) use only one swap partition or can it use
+multiple swap partitions (aggregate them into one logical space)?
+
+A: Only one swap partition, sorry.
+
+Q: If my application(s) causes lots of memory & swap space to be used
+(over half of the total system RAM), is it correct that it is likely
+to be useless to try to suspend to disk while that app is running?
+
+A: No, it should work okay, as long as your app does not mlock()
+it. Just prepare big enough swap partition.
+
+Q: What information is usefull for debugging suspend-to-disk problems?
+
+A: Well, last messages on the screen are always useful. If something
+is broken, it is usually some kernel driver, therefore trying with as
+little as possible modules loaded helps a lot. I also prefer people to
+suspend from console, preferably without X running. Booting with
+init=/bin/bash, then swapon and starting suspend sequence manually
+usually does the trick. Then it is good idea to try with latest
+vanilla kernel.
+
+
index 7a4a5036d123515d0aced385ab21b427a3de3089..526d6dd267ea8e38f319c30de9f6accf2967327f 100644 (file)
@@ -46,6 +46,12 @@ There are a few types of systems where video works after S3 resume:
   POSTing bios works. Ole Rohne has patch to do just that at
   http://dev.gentoo.org/~marineam/patch-radeonfb-2.6.11-rc2-mm2.
 
+(8) on some systems, you can use the video_post utility mentioned here:
+  http://bugzilla.kernel.org/show_bug.cgi?id=3670. Do echo 3 > /sys/power/state
+  && /usr/sbin/video_post - which will initialize the display in console mode.
+  If  you are in X, you can switch to a virtual terminal and back to X using
+  CTRL+ALT+F1 - CTRL+ALT+F7 to get the display working in graphical mode again.
+
 Now, if you pass acpi_sleep=something, and it does not work with your
 bios, you'll get a hard crash during resume. Be careful. Also it is
 safest to do your experiments with plain old VGA console. The vesafb
@@ -64,7 +70,8 @@ Model                           hack (or "how to do it")
 ------------------------------------------------------------------------------
 Acer Aspire 1406LC             ole's late BIOS init (7), turn off DRI
 Acer TM 242FX                  vbetool (6)
-Acer TM C300                    vga=normal (only suspend on console, not in X), vbetool (6)
+Acer TM C110                   video_post (8)
+Acer TM C300                    vga=normal (only suspend on console, not in X), vbetool (6) or video_post (8)
 Acer TM 4052LCi                        s3_bios (2)
 Acer TM 636Lci                 s3_bios vga=normal (2)
 Acer TM 650 (Radeon M7)                vga=normal plus boot-radeon (5) gets text console back
@@ -113,6 +120,7 @@ IBM ThinkPad T42p (2373-GTG)        s3_bios (2)
 IBM TP X20                     ??? (*)
 IBM TP X30                     s3_bios (2)
 IBM TP X31 / Type 2672-XXH      none (1), use radeontool (http://fdd.com/software/radeon/) to turn off backlight.
+IBM TP X32                     none (1), but backlight is on and video is trashed after long suspend
 IBM Thinkpad X40 Type 2371-7JG  s3_bios,s3_mode (4)
 Medion MD4220                  ??? (*)
 Samsung P35                    vbetool needed (6)
index ac7eabbf662aaf9d83814debb4f39d0c79043faf..87856d3cfb67fbcd16baf475c262c909f862cbb1 100644 (file)
@@ -111,24 +111,17 @@ hardware.
        Interrupts: locally disabled.
        This call must not sleep
 
-  stop_tx(port,tty_stop)
+  stop_tx(port)
        Stop transmitting characters.  This might be due to the CTS
        line becoming inactive or the tty layer indicating we want
-       to stop transmission.
-
-       tty_stop: 1 if this call is due to the TTY layer issuing a
-                 TTY stop to the driver (equiv to rs_stop).
+       to stop transmission due to an XOFF character.
 
        Locking: port->lock taken.
        Interrupts: locally disabled.
        This call must not sleep
 
-  start_tx(port,tty_start)
-       start transmitting characters.  (incidentally, nonempty will
-       always be nonzero, and shouldn't be used - it will be dropped).
-
-       tty_start: 1 if this call was due to the TTY layer issuing
-                  a TTY start to the driver (equiv to rs_start)
+  start_tx(port)
+       start transmitting characters.
 
        Locking: port->lock taken.
        Interrupts: locally disabled.
index 0f3b2405d09edf30c1f0251ce4c7e51d63e960f1..c1237a9255055635475552c519f8199303789c8e 100644 (file)
@@ -99,6 +99,7 @@ statically linked into the kernel). Those options are:
                                SONYPI_MEYE_MASK                0x0400
                                SONYPI_MEMORYSTICK_MASK         0x0800
                                SONYPI_BATTERY_MASK             0x1000
+                               SONYPI_WIRELESS_MASK            0x2000
 
        useinput:       if set (which is the default) two input devices are
                        created, one which interprets the jogdial events as
@@ -137,6 +138,15 @@ Bugs:
          speed handling etc). Use ACPI instead of APM if it works on your
          laptop.
 
+       - sonypi lacks the ability to distinguish between certain key
+         events on some models.
+
+       - some models with the nvidia card (geforce go 6200 tc) uses a
+         different way to adjust the backlighting of the screen. There
+         is a userspace utility to adjust the brightness on those models,
+         which can be downloaded from
+         http://www.acc.umu.se/~erikw/program/smartdimmer-0.1.tar.bz2
+
        - since all development was done by reverse engineering, there is
          _absolutely no guarantee_ that this driver will not crash your
          laptop. Permanently.
index a18ecb92b356798513d417b609ea3952c573f9cc..5c49ba07e709625516952f4d1147f0ae61464a37 100644 (file)
@@ -132,6 +132,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     mpu_irq    - IRQ # for MPU-401 UART (PnP setup)
     dma1       - first DMA # for AD1816A chip (PnP setup)
     dma2       - second DMA # for AD1816A chip (PnP setup)
+    clockfreq   - Clock frequency for AD1816A chip (default = 0, 33000Hz)
     
     Module supports up to 8 cards, autoprobe and PnP.
     
index db0b7d2dc477cfc01aa0bc10282c850e0c10ae9f..0475478c2484c90c3b14b6c74a4a8efe8fa4941b 100644 (file)
@@ -3422,10 +3422,17 @@ struct _snd_pcm_runtime {
 
       <para>
         The <structfield>iface</structfield> field specifies the type of
-      the control,
-      <constant>SNDRV_CTL_ELEM_IFACE_XXX</constant>. There are
-      <constant>MIXER</constant>, <constant>PCM</constant>,
-      <constant>CARD</constant>, etc.
+      the control, <constant>SNDRV_CTL_ELEM_IFACE_XXX</constant>, which
+      is usually <constant>MIXER</constant>.
+      Use <constant>CARD</constant> for global controls that are not
+      logically part of the mixer.
+      If the control is closely associated with some specific device on
+      the sound card, use <constant>HWDEP</constant>,
+      <constant>PCM</constant>, <constant>RAWMIDI</constant>,
+      <constant>TIMER</constant>, or <constant>SEQUENCER</constant>, and
+      specify the device number with the
+      <structfield>device</structfield> and
+      <structfield>subdevice</structfield> fields.
       </para>
 
       <para>
index c3ef09ae3bb114f484247389776415ce401ed405..f366fa956179505cc602ff79f90adc83f95f7a77 100644 (file)
@@ -83,19 +83,18 @@ single address space optimization, so that the zap_page_range (from
 vmtruncate) does not lose sending ipi's to cloned threads that might 
 be spawned underneath it and go to user mode to drag in pte's into tlbs.
 
-swap_list_lock/swap_device_lock
--------------------------------
+swap_lock
+--------------
 The swap devices are chained in priority order from the "swap_list" header. 
 The "swap_list" is used for the round-robin swaphandle allocation strategy.
 The #free swaphandles is maintained in "nr_swap_pages". These two together
-are protected by the swap_list_lock. 
+are protected by the swap_lock.
 
-The swap_device_lock, which is per swap device, protects the reference 
-counts on the corresponding swaphandles, maintained in the "swap_map"
-array, and the "highest_bit" and "lowest_bit" fields.
+The swap_lock also protects all the device reference counts on the
+corresponding swaphandles, maintained in the "swap_map" array, and the
+"highest_bit" and "lowest_bit" fields.
 
-Both of these are spinlocks, and are never acquired from intr level. The
-locking hierarchy is swap_list_lock -> swap_device_lock.
+The swap_lock is a spinlock, and is never acquired from intr level.
 
 To prevent races between swap space deletion or async readahead swapins
 deciding whether a swap handle is being used, ie worthy of being read in
index 28388aa700c67d62d604aed064a14d463f6d1906..c5beb548cfc42b781fd825ff9345f411f087897d 100644 (file)
@@ -228,6 +228,26 @@ advantechwdt.c -- Advantech Single Board Computer
        The GETSTATUS call returns if the device is open or not.
        [FIXME -- silliness again?]
        
+booke_wdt.c -- PowerPC BookE Watchdog Timer
+
+       Timeout default varies according to frequency, supports
+       SETTIMEOUT
+
+       Watchdog can not be turned off, CONFIG_WATCHDOG_NOWAYOUT
+       does not make sense
+
+       GETSUPPORT returns the watchdog_info struct, and
+       GETSTATUS returns the supported options. GETBOOTSTATUS
+       returns a 1 if the last reset was caused by the
+       watchdog and a 0 otherwise. This watchdog can not be
+       disabled once it has been started. The wdt_period kernel
+       parameter selects which bit of the time base changing
+       from 0->1 will trigger the watchdog exception. Changing
+       the timeout from the ioctl calls will change the
+       wdt_period as defined above. Finally if you would like to
+       replace the default Watchdog Handler you can implement the
+       WatchdogHandler() function in your own code.
+
 eurotechwdt.c -- Eurotech CPU-1220/1410
 
        The timeout can be set using the SETTIMEOUT ioctl and defaults
index fb0da63621cd0f087bad4ed4cdf27f775291204f..8e4e829210708b741327b1f3aeefd032bdd3dd6c 100644 (file)
@@ -202,13 +202,6 @@ P: Colin Leroy
 M:     colin@colino.net
 S:     Maintained
 
-ADVANSYS SCSI DRIVER
-P:     Bob Frey
-M:     linux@advansys.com
-W:     http://www.advansys.com/linux.html
-L:     linux-scsi@vger.kernel.org
-S:     Maintained
-
 AEDSP16 DRIVER
 P:     Riccardo Facchetti
 M:     fizban@tin.it
@@ -696,6 +689,11 @@ M: dz@debian.org
 W:     http://www.debian.org/~dz/i8k/
 S:     Maintained
 
+DELL SYSTEMS MANAGEMENT BASE DRIVER (dcdbas)
+P:     Doug Warzecha
+M:     Douglas_Warzecha@dell.com
+S:     Maintained
+
 DEVICE-MAPPER
 P:     Alasdair Kergon
 L:     dm-devel@redhat.com
@@ -886,7 +884,7 @@ S:  Maintained
 
 FILESYSTEMS (VFS and infrastructure)
 P:     Alexander Viro
-M:     viro@parcelfarce.linux.theplanet.co.uk
+M:     viro@zeniv.linux.org.uk
 S:     Maintained
 
 FIRMWARE LOADER (request_firmware)
@@ -940,6 +938,13 @@ M: khc@pm.waw.pl
 W:     http://www.kernel.org/pub/linux/utils/net/hdlc/
 S:     Maintained
 
+HARDWARE MONITORING
+P:     Jean Delvare
+M:     khali@linux-fr.org
+L:     lm-sensors@lm-sensors.org
+W:     http://www.lm-sensors.nu/
+S:     Maintained
+
 HARMONY SOUND DRIVER
 P:     Kyle McMartin
 M:     kyle@parisc-linux.org
@@ -998,6 +1003,13 @@ M:        mike.miller@hp.com
 L:     iss_storagedev@hp.com
 S:     Supported
  
+HOST AP DRIVER
+P:     Jouni Malinen
+M:     jkmaline@cc.hut.fi
+L:     hostap@shmoo.com
+W:     http://hostap.epitest.fi/
+S:     Maintained
+
 HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
 P:     Jaroslav Kysela
 M:     perex@suse.cz
@@ -1014,7 +1026,7 @@ P:        William Irwin
 M:     wli@holomorphy.com
 S:     Maintained
 
-I2C AND SENSORS DRIVERS
+I2C SUBSYSTEM
 P:     Greg Kroah-Hartman
 M:     greg@kroah.com
 P:     Jean Delvare
@@ -1960,7 +1972,6 @@ S:        Supported
 
 ROCKETPORT DRIVER
 P:     Comtrol Corp.
-M:     support@comtrol.com
 W:     http://www.comtrol.com
 S:     Maintained
 
@@ -2099,6 +2110,12 @@ M:       support@simtec.co.uk
 W:     http://www.simtec.co.uk/products/EB2410ITX/
 S:     Supported
 
+SIS 190 ETHERNET DRIVER
+P:     Francois Romieu
+M:     romieu@fr.zoreil.com
+L:     netdev@vger.kernel.org
+S:     Maintained
+
 SIS 5513 IDE CONTROLLER DRIVER
 P:     Lionel Bouton
 M:     Lionel.Bouton@inet6.fr
@@ -2644,11 +2661,6 @@ S:       Maintained
 UCLINUX (AND M68KNOMMU)
 P:     Greg Ungerer
 M:     gerg@uclinux.org
-M:     gerg@snapgear.com
-P:     David McCullough
-M:     davidm@snapgear.com
-P:     D. Jeff Dionne (created first uClinux port)
-M:     jeff@uclinux.org
 W:     http://www.uclinux.org/
 L:     uclinux-dev@uclinux.org  (subscribers-only)
 S:     Maintained
index 300f61f6f6a25f52d44c5bee024f8cf57e8f3d66..63e5c9f0bc7ad9776a4f9a33e07600b0085c5672 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 13
-EXTRAVERSION =-rc7
-NAME=Woozy Numbat
+EXTRAVERSION =
+NAME=Affluent Albatross
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
@@ -109,10 +109,9 @@ $(if $(KBUILD_OUTPUT),, \
 .PHONY: $(MAKECMDGOALS)
 
 $(filter-out _all,$(MAKECMDGOALS)) _all:
-       $(if $(KBUILD_VERBOSE:1=),@)$(MAKE) -C $(KBUILD_OUTPUT)         \
-       KBUILD_SRC=$(CURDIR)         KBUILD_VERBOSE=$(KBUILD_VERBOSE)   \
-       KBUILD_CHECK=$(KBUILD_CHECK) KBUILD_EXTMOD="$(KBUILD_EXTMOD)"   \
-        -f $(CURDIR)/Makefile $@
+       $(if $(KBUILD_VERBOSE:1=),@)$(MAKE) -C $(KBUILD_OUTPUT) \
+       KBUILD_SRC=$(CURDIR) \
+       KBUILD_EXTMOD="$(KBUILD_EXTMOD)" -f $(CURDIR)/Makefile $@
 
 # Leave processing to above invocation of make
 skip-makefile := 1
@@ -233,7 +232,7 @@ ifeq ($(MAKECMDGOALS),)
   KBUILD_MODULES := 1
 endif
 
-export KBUILD_MODULES KBUILD_BUILTIN KBUILD_VERBOSE
+export KBUILD_MODULES KBUILD_BUILTIN
 export KBUILD_CHECKSRC KBUILD_SRC KBUILD_EXTMOD
 
 # Beautify output
@@ -309,6 +308,9 @@ cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh \
 # Look for make include files relative to root of kernel src
 MAKEFLAGS += --include-dir=$(srctree)
 
+# We need some generic definitions
+include  $(srctree)/scripts/Kbuild.include
+
 # For maximum performance (+ possibly random breakage, uncomment
 # the following)
 
@@ -348,7 +350,7 @@ LINUXINCLUDE    := -Iinclude \
 
 CPPFLAGS        := -D__KERNEL__ $(LINUXINCLUDE)
 
-CFLAGS                 := -Wall -Wstrict-prototypes -Wno-trigraphs \
+CFLAGS                 := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
                   -fno-strict-aliasing -fno-common \
                   -ffreestanding
 AFLAGS         := -D__ASSEMBLY__
@@ -367,15 +369,10 @@ export AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
 # even be read-only.
 export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_versions
 
-# The temporary file to save gcc -MD generated dependencies must not
-# contain a comma
-comma := ,
-depfile = $(subst $(comma),_,$(@D)/.$(@F).d)
-
 # Files to ignore in find ... statements
 
-RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc \) -prune -o
-RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS --exclude .pc
+RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc -o -name .hg \) -prune -o
+RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS --exclude .pc --exclude .hg
 
 # ===========================================================================
 # Rules shared between *config targets and build targets
@@ -551,6 +548,26 @@ export KBUILD_IMAGE ?= vmlinux
 # images. Default is /boot, but you can set it to other values
 export INSTALL_PATH ?= /boot
 
+# If CONFIG_LOCALVERSION_AUTO is set, we automatically perform some tests
+# and try to determine if the current source tree is a release tree, of any sort,
+# or if is a pure development tree.
+#
+# A 'release tree' is any tree with a git TAG associated
+# with it.  The primary goal of this is to make it safe for a native
+# git/CVS/SVN user to build a release tree (i.e, 2.6.9) and also to
+# continue developing against the current Linus tree, without having the Linus
+# tree overwrite the 2.6.9 tree when installed.
+#
+# Currently, only git is supported.
+# Other SCMs can edit scripts/setlocalversion and add the appropriate
+# checks as needed.
+
+
+ifdef CONFIG_LOCALVERSION_AUTO
+       localversion-auto := $(shell $(PERL) $(srctree)/scripts/setlocalversion $(srctree))
+       LOCALVERSION := $(LOCALVERSION)$(localversion-auto)
+endif
+
 #
 # INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory
 # relocations required by build roots.  This is not defined in the
@@ -691,8 +708,10 @@ endef
 
 # Update vmlinux version before link
 # Use + in front of this rule to silent warning about make -j1
+# First command is ':' to allow us to use + in front of this rule
 cmd_ksym_ld = $(cmd_vmlinux__)
 define rule_ksym_ld
+       : 
        +$(call cmd,vmlinux_version)
        $(call cmd,vmlinux__)
        $(Q)echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd
@@ -722,6 +741,16 @@ quiet_cmd_kallsyms = KSYM    $@
 # Needs to visit scripts/ before $(KALLSYMS) can be used.
 $(KALLSYMS): scripts ;
 
+# Generate some data for debugging strange kallsyms problems
+debug_kallsyms: .tmp_map$(last_kallsyms)
+
+.tmp_map%: .tmp_vmlinux% FORCE
+       ($(OBJDUMP) -h $< | $(AWK) '/^ +[0-9]/{print $$4 " 0 " $$2}'; $(NM) $<) | sort > $@
+
+.tmp_map3: .tmp_map2
+
+.tmp_map2: .tmp_map1
+
 endif # ifdef CONFIG_KALLSYMS
 
 # vmlinux image - including updated kernel symbols
@@ -757,7 +786,7 @@ $(vmlinux-dirs): prepare-all scripts
 prepare2:
 ifneq ($(KBUILD_SRC),)
        @echo '  Using $(srctree) as source for kernel'
-       $(Q)if [ -h $(srctree)/include/asm -o -f $(srctree)/.config ]; then \
+       $(Q)if [ -f $(srctree)/.config ]; then \
                echo "  $(srctree) is not clean, please run 'make mrproper'";\
                echo "  in the '$(srctree)' directory.";\
                /bin/false; \
@@ -769,7 +798,8 @@ endif
 # prepare1 creates a makefile if using a separate output directory
 prepare1: prepare2 outputmakefile
 
-prepare0: prepare1 include/linux/version.h include/asm include/config/MARKER
+prepare0: prepare1 include/linux/version.h include/asm \
+                   include/config/MARKER
 ifneq ($(KBUILD_MODULES),)
        $(Q)rm -rf $(MODVERDIR)
        $(Q)mkdir -p $(MODVERDIR)
@@ -875,7 +905,7 @@ modules_install: _modinst_ _modinst_post
 
 .PHONY: _modinst_
 _modinst_:
-       @if [ -z "`$(DEPMOD) -V | grep module-init-tools`" ]; then \
+       @if [ -z "`$(DEPMOD) -V 2>/dev/null | grep module-init-tools`" ]; then \
                echo "Warning: you may need to install module-init-tools"; \
                echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt";\
                sleep 1; \
@@ -1159,37 +1189,49 @@ else
 __srctree = $(srctree)/
 endif
 
+ALLSOURCE_ARCHS := $(ARCH)
+
 define all-sources
        ( find $(__srctree) $(RCS_FIND_IGNORE) \
               \( -name include -o -name arch \) -prune -o \
               -name '*.[chS]' -print; \
-         find $(__srctree)arch/$(ARCH) $(RCS_FIND_IGNORE) \
-              -name '*.[chS]' -print; \
+         for ARCH in $(ALLSOURCE_ARCHS) ; do \
+              find $(__srctree)arch/$${ARCH} $(RCS_FIND_IGNORE) \
+                   -name '*.[chS]' -print; \
+         done ; \
          find $(__srctree)security/selinux/include $(RCS_FIND_IGNORE) \
               -name '*.[chS]' -print; \
          find $(__srctree)include $(RCS_FIND_IGNORE) \
               \( -name config -o -name 'asm-*' \) -prune \
               -o -name '*.[chS]' -print; \
-         find $(__srctree)include/asm-$(ARCH) $(RCS_FIND_IGNORE) \
-              -name '*.[chS]' -print; \
+         for ARCH in $(ALLSOURCE_ARCHS) ; do \
+              find $(__srctree)include/asm-$${ARCH} $(RCS_FIND_IGNORE) \
+                   -name '*.[chS]' -print; \
+         done ; \
          find $(__srctree)include/asm-generic $(RCS_FIND_IGNORE) \
               -name '*.[chS]' -print )
 endef
 
 quiet_cmd_cscope-file = FILELST cscope.files
-      cmd_cscope-file = $(all-sources) > cscope.files
+      cmd_cscope-file = (echo \-k; echo \-q; $(all-sources)) > cscope.files
 
 quiet_cmd_cscope = MAKE    cscope.out
-      cmd_cscope = cscope -k -b -q
+      cmd_cscope = cscope -b
 
 cscope: FORCE
        $(call cmd,cscope-file)
        $(call cmd,cscope)
 
 quiet_cmd_TAGS = MAKE   $@
-cmd_TAGS = $(all-sources) | etags -
+define cmd_TAGS
+       rm -f $@; \
+       ETAGSF=`etags --version | grep -i exuberant >/dev/null && echo "-I __initdata,__exitdata,EXPORT_SYMBOL,EXPORT_SYMBOL_GPL --extra=+f"`; \
+       $(all-sources) | xargs etags $$ETAGSF -a
+endef
+
+TAGS: FORCE
+       $(call cmd,TAGS)
 
-#      Exuberant ctags works better with -I
 
 quiet_cmd_tags = MAKE   $@
 define cmd_tags
@@ -1198,9 +1240,6 @@ define cmd_tags
        $(all-sources) | xargs ctags $$CTAGSF -a
 endef
 
-TAGS: FORCE
-       $(call cmd,TAGS)
-
 tags: FORCE
        $(call cmd,tags)
 
@@ -1268,82 +1307,11 @@ ifneq ($(cmd_files),)
   include $(cmd_files)
 endif
 
-# Execute command and generate cmd file
-if_changed = $(if $(strip $? \
-                         $(filter-out $(cmd_$(1)),$(cmd_$@))\
-                         $(filter-out $(cmd_$@),$(cmd_$(1)))),\
-       @set -e; \
-       $(if $($(quiet)cmd_$(1)),echo '  $(subst ','\'',$($(quiet)cmd_$(1)))';) \
-       $(cmd_$(1)); \
-       echo 'cmd_$@ := $(subst $$,$$$$,$(subst ','\'',$(cmd_$(1))))' > $(@D)/.$(@F).cmd)
-
-
-# execute the command and also postprocess generated .d dependencies
-# file
-if_changed_dep = $(if $(strip $? $(filter-out FORCE $(wildcard $^),$^)\
-                         $(filter-out $(cmd_$(1)),$(cmd_$@))\
-                         $(filter-out $(cmd_$@),$(cmd_$(1)))),\
-       $(Q)set -e; \
-       $(if $($(quiet)cmd_$(1)),echo '  $(subst ','\'',$($(quiet)cmd_$(1)))';) \
-       $(cmd_$(1)); \
-       scripts/basic/fixdep $(depfile) $@ '$(subst $$,$$$$,$(subst ','\'',$(cmd_$(1))))' > $(@D)/.$(@F).tmp; \
-       rm -f $(depfile); \
-       mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd)
-
-# Usage: $(call if_changed_rule,foo)
-# will check if $(cmd_foo) changed, or any of the prequisites changed,
-# and if so will execute $(rule_foo)
-
-if_changed_rule = $(if $(strip $? \
-                              $(filter-out $(cmd_$(1)),$(cmd_$(@F)))\
-                              $(filter-out $(cmd_$(@F)),$(cmd_$(1)))),\
-                      $(Q)$(rule_$(1)))
-
-# If quiet is set, only print short version of command
-
-cmd = @$(if $($(quiet)cmd_$(1)),echo '  $($(quiet)cmd_$(1))' &&) $(cmd_$(1))
-
-# filechk is used to check if the content of a generated file is updated.
-# Sample usage:
-# define filechk_sample
-#      echo $KERNELRELEASE
-# endef
-# version.h : Makefile
-#      $(call filechk,sample)
-# The rule defined shall write to stdout the content of the new file.
-# The existing file will be compared with the new one.
-# - If no file exist it is created
-# - If the content differ the new file is used
-# - If they are equal no change, and no timestamp update
-
-define filechk
-       @set -e;                                \
-       echo '  CHK     $@';                    \
-       mkdir -p $(dir $@);                     \
-       $(filechk_$(1)) < $< > $@.tmp;          \
-       if [ -r $@ ] && cmp -s $@ $@.tmp; then  \
-               rm -f $@.tmp;                   \
-       else                                    \
-               echo '  UPD     $@';            \
-               mv -f $@.tmp $@;                \
-       fi
-endef
-
-# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=dir
-# Usage:
-# $(Q)$(MAKE) $(build)=dir
-build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
-
 # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj=dir
 # Usage:
 # $(Q)$(MAKE) $(clean)=dir
 clean := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.clean obj
 
-#      $(call descend,<dir>,<target>)
-#      Recursively call a sub-make in <dir> with target <target>
-# Usage is deprecated, because make does not see this as an invocation of make.
-descend =$(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj=$(1) $(2)
-
 endif  # skip-makefile
 
 FORCE:
index 189d5eababa8d15708e15e354e0eb372d5e7fad1..786491f9ceb2c072ae6108615211b1bf3d95306c 100644 (file)
@@ -479,6 +479,9 @@ config EISA
        depends on ALPHA_GENERIC || ALPHA_JENSEN || ALPHA_ALCOR || ALPHA_MIKASA || ALPHA_SABLE || ALPHA_LYNX || ALPHA_NORITAKE || ALPHA_RAWHIDE
        default y
 
+config ARCH_MAY_HAVE_PC_FDC
+       def_bool y
+
 config SMP
        bool "Symmetric multi-processing support"
        depends on ALPHA_SABLE || ALPHA_LYNX || ALPHA_RAWHIDE || ALPHA_DP264 || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_GENERIC || ALPHA_SHARK || ALPHA_MARVEL
index 08fe8071a7f8fde380e1fa7338fef07ab8925ef5..2e45e8604e325454e87681321c862e57b19b1355 100644 (file)
@@ -566,13 +566,12 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
        if (ka->sa.sa_flags & SA_RESETHAND)
                ka->sa.sa_handler = SIG_DFL;
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER)) 
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 static inline void
index 8226c5cd788ccb142c3676727fb06161cc5cc574..67be50b7d80afba730e18746ad8e8ac63acc6068 100644 (file)
@@ -149,7 +149,7 @@ irqreturn_t timer_interrupt(int irq, void *dev, struct pt_regs * regs)
         * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
         * called as close as possible to 500 ms before the new second starts.
         */
-       if ((time_status & STA_UNSYNC) == 0
+       if (ntp_synced()
            && xtime.tv_sec > state.last_rtc_update + 660
            && xtime.tv_nsec >= 500000 - ((unsigned) TICK_SIZE) / 2
            && xtime.tv_nsec <= 500000 + ((unsigned) TICK_SIZE) / 2) {
@@ -502,10 +502,7 @@ do_settimeofday(struct timespec *tv)
        set_normalized_timespec(&xtime, sec, nsec);
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
 
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
index c65c6eb9810d84b05267470cadfbf2efc9b0e682..0f2899b4159dfb4f12c4cc2d69f411dd9d88e0af 100644 (file)
@@ -64,6 +64,9 @@ config GENERIC_CALIBRATE_DELAY
 config GENERIC_BUST_SPINLOCK
        bool
 
+config ARCH_MAY_HAVE_PC_FDC
+       bool
+
 config GENERIC_ISA_DMA
        bool
 
@@ -150,6 +153,7 @@ config ARCH_RPC
        select ARCH_ACORN
        select FIQ
        select TIMER_ACORN
+       select ARCH_MAY_HAVE_PC_FDC
        help
          On the Acorn Risc-PC, Linux can support the internal IDE disk and
          CD-ROM interface, serial and parallel port, and the floppy drive.
@@ -365,8 +369,8 @@ config NO_IDLE_HZ
 
          Please note that dynamic tick may affect the accuracy of
          timekeeping on some platforms depending on the implementation.
-         Currently at least OMAP platform is known to have accurate
-         timekeeping with dynamic tick.
+         Currently at least OMAP, PXA2xx and SA11x0 platforms are known
+         to have accurate timekeeping with dynamic tick.
 
 config ARCH_DISCONTIGMEM_ENABLE
        bool
@@ -635,10 +639,6 @@ config PM
          and the Battery Powered Linux mini-HOWTO, available from
          <http://www.tldp.org/docs.html#howto>.
 
-         Note that, even if you say N here, Linux on the x86 architecture
-         will issue the hlt instruction if nothing is to be done, thereby
-         sending the processor to sleep and saving power.
-
 config APM
        tristate "Advanced Power Management Emulation"
        depends on PM
@@ -650,12 +650,6 @@ config APM
          battery status information, and user-space programs will receive
          notification of APM "events" (e.g. battery status change).
 
-         If you select "Y" here, you can disable actual use of the APM
-         BIOS by passing the "apm=off" option to the kernel at boot time.
-
-         Note that the APM support is almost completely disabled for
-         machines with more than one CPU.
-
          In order to use APM, you will need supporting software. For location
          and more information, read <file:Documentation/pm.txt> and the
          Battery Powered Linux mini-HOWTO, available from
@@ -665,39 +659,12 @@ config APM
          manpage ("man 8 hdparm") for that), and it doesn't turn off
          VESA-compliant "green" monitors.
 
-         This driver does not support the TI 4000M TravelMate and the ACER
-         486/DX4/75 because they don't have compliant BIOSes. Many "green"
-         desktop machines also don't have compliant BIOSes, and this driver
-         may cause those machines to panic during the boot phase.
-
          Generally, if you don't have a battery in your machine, there isn't
          much point in using this driver and you should say N. If you get
          random kernel OOPSes or reboots that don't seem to be related to
          anything, try disabling/enabling this option (or disabling/enabling
          APM in your BIOS).
 
-         Some other things you should try when experiencing seemingly random,
-         "weird" problems:
-
-         1) make sure that you have enough swap space and that it is
-         enabled.
-         2) pass the "no-hlt" option to the kernel
-         3) switch on floating point emulation in the kernel and pass
-         the "no387" option to the kernel
-         4) pass the "floppy=nodma" option to the kernel
-         5) pass the "mem=4M" option to the kernel (thereby disabling
-         all but the first 4 MB of RAM)
-         6) make sure that the CPU is not over clocked.
-         7) read the sig11 FAQ at <http://www.bitwizard.nl/sig11/>
-         8) disable the cache from your BIOS settings
-         9) install a fan for the video card or exchange video RAM
-         10) install a better fan for the CPU
-         11) exchange RAM chips
-         12) exchange the motherboard.
-
-         To compile this driver as a module, choose M here: the
-         module will be called apm.
-
 endmenu
 
 source "net/Kconfig"
@@ -752,6 +719,8 @@ source "drivers/hwmon/Kconfig"
 
 source "drivers/misc/Kconfig"
 
+source "drivers/mfd/Kconfig"
+
 source "drivers/media/Kconfig"
 
 source "drivers/video/Kconfig"
index d6bf8a2b090d833f6c16e5fa2e81d89c490497c2..59ad69640d6bde4e26cb8b41279ca32aa1b47c65 100644 (file)
@@ -7,7 +7,8 @@
  * so we have to figure out the machine for ourselves...
  *
  * Support for Poodle, Corgi (SL-C700), Shepherd (SL-C750)
- * and Husky (SL-C760).
+ * Husky (SL-C760), Tosa (SL-C6000), Spitz (SL-C3000),
+ * Akita (SL-C1000) and Borzoi (SL-C3100).
  *
  */
 
 
 __SharpSL_start:
 
+/* Check for TC6393 - if found we have a Tosa */
+       ldr     r7, .TOSAID
+       mov     r1, #0x10000000         @ Base address of TC6393 chip
+       mov     r6, #0x03
+       ldrh    r3, [r1, #8]            @ Load TC6393XB Revison: This is 0x0003
+       cmp     r6, r3
+       beq     .SHARPEND               @ Success -> tosa
+
+/* Check for pxa270 - if found, branch */
+       mrc p15, 0, r4, c0, c0          @ Get Processor ID
+       and     r4, r4, #0xffffff00
+       ldr     r3, .PXA270ID
+       cmp     r4, r3
+       beq     .PXA270
+
+/* Check for w100 - if not found we have a Poodle */
        ldr     r1, .W100ADDR           @ Base address of w100 chip + regs offset
 
        mov r6, #0x31                   @ Load Magic Init value
@@ -30,7 +47,7 @@ __SharpSL_start:
        mov r5, #0x3000
 .W100LOOP:
        subs r5, r5, #1
-    bne .W100LOOP
+       bne .W100LOOP
        mov r6, #0x30                   @ Load 2nd Magic Init value
        str     r6, [r1, #0x280]        @ to SCRATCH_UMSK
 
@@ -40,45 +57,52 @@ __SharpSL_start:
        cmp     r6, r3
        bne     .SHARPEND                       @ We have no w100 - Poodle
 
-       mrc p15, 0, r6, c0, c0  @ Get Processor ID
-       and     r6, r6, #0xffffff00
+/* Check for pxa250 - if found we have a Corgi */
        ldr     r7, .CORGIID
        ldr     r3, .PXA255ID
-       cmp     r6, r3
+       cmp     r4, r3
        blo     .SHARPEND                       @ We have a PXA250 - Corgi
 
-       mov     r1, #0x0c000000         @ Base address of NAND chip
-       ldrb    r3, [r1, #24]   @ Load FLASHCTL
-       bic     r3, r3, #0x11           @ SET NCE
-       orr     r3, r3, #0x0a           @ SET CLR + FLWP
-       strb    r3, [r1, #24]   @ Save to FLASHCTL
-       mov     r2, #0x90               @ Command "readid"
-       strb    r2, [r1, #20]   @ Save to FLASHIO
-       bic     r3, r3, #2                      @ CLR CLE
-       orr     r3, r3, #4                      @ SET ALE
-       strb    r3, [r1, #24]   @ Save to FLASHCTL
-       mov             r2, #0                  @ Address 0x00
-       strb    r2, [r1, #20]   @ Save to FLASHIO
-       bic     r3, r3, #4                      @ CLR ALE
-       strb    r3, [r1, #24]   @ Save to FLASHCTL
-.SHARP1:
-       ldrb    r3, [r1, #24]   @ Load FLASHCTL
-       tst     r3, #32                         @ Is chip ready?
-       beq     .SHARP1
-       ldrb    r2, [r1, #20]   @ NAND Manufacturer ID
-       ldrb    r3, [r1, #20]   @ NAND Chip ID
+/* Check for 64MiB flash - if found we have a Shepherd */
+       bl      get_flash_ids
        ldr     r7, .SHEPHERDID
        cmp     r3, #0x76                       @ 64MiB flash
        beq     .SHARPEND                       @ We have Shepherd
+
+/* Must be a Husky */
        ldr     r7, .HUSKYID            @ Must be Husky
        b .SHARPEND
 
+.PXA270:
+/* Check for 16MiB flash - if found we have Spitz */
+       bl      get_flash_ids
+       ldr     r7, .SPITZID
+       cmp     r3, #0x73                       @ 16MiB flash
+       beq     .SHARPEND                       @ We have Spitz
+
+/* Check for a second SCOOP chip - if found we have Borzoi */
+       ldr     r1, .SCOOP2ADDR
+       ldr     r7, .BORZOIID
+       mov     r6, #0x0140
+       strh    r6, [r1]
+       ldrh    r6, [r1]
+       cmp     r6, #0x0140
+       beq     .SHARPEND                       @ We have Borzoi
+
+/* Must be Akita */
+       ldr     r7, .AKITAID
+       b       .SHARPEND                       @ We have Borzoi
+
 .PXA255ID:
        .word   0x69052d00              @ PXA255 Processor ID
+.PXA270ID:
+       .word   0x69054100              @ PXA270 Processor ID
 .W100ID:
        .word   0x57411002              @ w100 Chip ID
 .W100ADDR:
        .word   0x08010000              @ w100 Chip ID Reg Address
+.SCOOP2ADDR:
+       .word   0x08800040
 .POODLEID:
        .word   MACH_TYPE_POODLE
 .CORGIID:
@@ -87,6 +111,41 @@ __SharpSL_start:
        .word   MACH_TYPE_SHEPHERD
 .HUSKYID:
        .word   MACH_TYPE_HUSKY
-.SHARPEND:
+.TOSAID:
+       .word   MACH_TYPE_TOSA
+.SPITZID:
+       .word   MACH_TYPE_SPITZ
+.AKITAID:
+       .word   MACH_TYPE_AKITA
+.BORZOIID:
+       .word   MACH_TYPE_BORZOI
 
+/*
+ * Return: r2 - NAND Manufacturer ID
+ *         r3 - NAND Chip ID
+ * Corrupts: r1
+ */
+get_flash_ids:
+       mov     r1, #0x0c000000         @ Base address of NAND chip
+       ldrb    r3, [r1, #24]           @ Load FLASHCTL
+       bic     r3, r3, #0x11           @ SET NCE
+       orr     r3, r3, #0x0a           @ SET CLR + FLWP
+       strb    r3, [r1, #24]           @ Save to FLASHCTL
+       mov     r2, #0x90               @ Command "readid"
+       strb    r2, [r1, #20]           @ Save to FLASHIO
+       bic     r3, r3, #2              @ CLR CLE
+       orr     r3, r3, #4              @ SET ALE
+       strb    r3, [r1, #24]           @ Save to FLASHCTL
+       mov     r2, #0                  @ Address 0x00
+       strb    r2, [r1, #20]           @ Save to FLASHIO
+       bic     r3, r3, #4              @ CLR ALE
+       strb    r3, [r1, #24]           @ Save to FLASHCTL
+.fids1:
+       ldrb    r3, [r1, #24]           @ Load FLASHCTL
+       tst     r3, #32                 @ Is chip ready?
+       beq     .fids1
+       ldrb    r2, [r1, #20]           @ NAND Manufacturer ID
+       ldrb    r3, [r1, #20]           @ NAND Chip ID
+       mov     pc, lr
 
+.SHARPEND:
index 692af6b5e8ff259d1455e816edf92ec186229a7a..666ba393575b8d7800b5b8a14d4e5ce1466932bc 100644 (file)
@@ -1,6 +1,9 @@
 config ICST525
        bool
 
+config ARM_GIC
+       bool
+
 config ICST307
        bool
 
index 11f20a43ee3aa81c8c605512b2d5398361478026..a87886564b19e0b9c33798cdae6947114e0e5947 100644 (file)
@@ -4,6 +4,7 @@
 
 obj-y                          += rtctime.o
 obj-$(CONFIG_ARM_AMBA)         += amba.o
+obj-$(CONFIG_ARM_GIC)          += gic.o
 obj-$(CONFIG_ICST525)          += icst525.o
 obj-$(CONFIG_ICST307)          += icst307.o
 obj-$(CONFIG_SA1111)           += sa1111.o
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
new file mode 100644 (file)
index 0000000..d749907
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ *  linux/arch/arm/common/gic.c
+ *
+ *  Copyright (C) 2002 ARM Limited, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Interrupt architecture for the GIC:
+ *
+ * o There is one Interrupt Distributor, which receives interrupts
+ *   from system devices and sends them to the Interrupt Controllers.
+ *
+ * o There is one CPU Interface per CPU, which sends interrupts sent
+ *   by the Distributor, and interrupts generated locally, to the
+ *   associated CPU.
+ *
+ * Note that IRQs 0-31 are special - they are local to each CPU.
+ * As such, the enable set/clear, pending set/clear and active bit
+ * registers are banked per-cpu for these sources.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/smp.h>
+#include <linux/cpumask.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mach/irq.h>
+#include <asm/hardware/gic.h>
+
+static void __iomem *gic_dist_base;
+static void __iomem *gic_cpu_base;
+
+/*
+ * Routines to acknowledge, disable and enable interrupts
+ *
+ * Linux assumes that when we're done with an interrupt we need to
+ * unmask it, in the same way we need to unmask an interrupt when
+ * we first enable it.
+ *
+ * The GIC has a seperate notion of "end of interrupt" to re-enable
+ * an interrupt after handling, in order to support hardware
+ * prioritisation.
+ *
+ * We can make the GIC behave in the way that Linux expects by making
+ * our "acknowledge" routine disable the interrupt, then mark it as
+ * complete.
+ */
+static void gic_ack_irq(unsigned int irq)
+{
+       u32 mask = 1 << (irq % 32);
+       writel(mask, gic_dist_base + GIC_DIST_ENABLE_CLEAR + (irq / 32) * 4);
+       writel(irq, gic_cpu_base + GIC_CPU_EOI);
+}
+
+static void gic_mask_irq(unsigned int irq)
+{
+       u32 mask = 1 << (irq % 32);
+       writel(mask, gic_dist_base + GIC_DIST_ENABLE_CLEAR + (irq / 32) * 4);
+}
+
+static void gic_unmask_irq(unsigned int irq)
+{
+       u32 mask = 1 << (irq % 32);
+       writel(mask, gic_dist_base + GIC_DIST_ENABLE_SET + (irq / 32) * 4);
+}
+
+static void gic_set_cpu(struct irqdesc *desc, unsigned int irq, unsigned int cpu)
+{
+       void __iomem *reg = gic_dist_base + GIC_DIST_TARGET + (irq & ~3);
+       unsigned int shift = (irq % 4) * 8;
+       u32 val;
+
+       val = readl(reg) & ~(0xff << shift);
+       val |= 1 << (cpu + shift);
+       writel(val, reg);
+}
+
+static struct irqchip gic_chip = {
+       .ack            = gic_ack_irq,
+       .mask           = gic_mask_irq,
+       .unmask         = gic_unmask_irq,
+#ifdef CONFIG_SMP
+       .set_cpu        = gic_set_cpu,
+#endif
+};
+
+void __init gic_dist_init(void __iomem *base)
+{
+       unsigned int max_irq, i;
+       u32 cpumask = 1 << smp_processor_id();
+
+       cpumask |= cpumask << 8;
+       cpumask |= cpumask << 16;
+
+       gic_dist_base = base;
+
+       writel(0, base + GIC_DIST_CTRL);
+
+       /*
+        * Find out how many interrupts are supported.
+        */
+       max_irq = readl(base + GIC_DIST_CTR) & 0x1f;
+       max_irq = (max_irq + 1) * 32;
+
+       /*
+        * The GIC only supports up to 1020 interrupt sources.
+        * Limit this to either the architected maximum, or the
+        * platform maximum.
+        */
+       if (max_irq > max(1020, NR_IRQS))
+               max_irq = max(1020, NR_IRQS);
+
+       /*
+        * Set all global interrupts to be level triggered, active low.
+        */
+       for (i = 32; i < max_irq; i += 16)
+               writel(0, base + GIC_DIST_CONFIG + i * 4 / 16);
+
+       /*
+        * Set all global interrupts to this CPU only.
+        */
+       for (i = 32; i < max_irq; i += 4)
+               writel(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
+
+       /*
+        * Set priority on all interrupts.
+        */
+       for (i = 0; i < max_irq; i += 4)
+               writel(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
+
+       /*
+        * Disable all interrupts.
+        */
+       for (i = 0; i < max_irq; i += 32)
+               writel(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
+
+       /*
+        * Setup the Linux IRQ subsystem.
+        */
+       for (i = 29; i < max_irq; i++) {
+               set_irq_chip(i, &gic_chip);
+               set_irq_handler(i, do_level_IRQ);
+               set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+       }
+
+       writel(1, base + GIC_DIST_CTRL);
+}
+
+void __cpuinit gic_cpu_init(void __iomem *base)
+{
+       gic_cpu_base = base;
+       writel(0xf0, base + GIC_CPU_PRIMASK);
+       writel(1, base + GIC_CPU_CTRL);
+}
+
+#ifdef CONFIG_SMP
+void gic_raise_softirq(cpumask_t cpumask, unsigned int irq)
+{
+       unsigned long map = *cpus_addr(cpumask);
+
+       writel(map << 16 | irq, gic_dist_base + GIC_DIST_SOFTINT);
+}
+#endif
index 41f12658c8b47a2862605b39ed78fbdb6c8a55e5..51f430cc2fbf5b7a08bcfed5bc6dee1e97fb1435 100644 (file)
@@ -177,7 +177,7 @@ static void locomo_handler(unsigned int irq, struct irqdesc *desc,
                d = irq_desc + irq;
                for (i = 0; i <= 3; i++, d++, irq++) {
                        if (req & (0x0100 << i)) {
-                               d->handle(irq, d, regs);
+                               desc_handle_irq(irq, d, regs);
                        }
 
                }
@@ -220,7 +220,7 @@ static void locomo_key_handler(unsigned int irq, struct irqdesc *desc,
 
        if (locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC) & 0x0001) {
                d = irq_desc + LOCOMO_IRQ_KEY_START;
-               d->handle(LOCOMO_IRQ_KEY_START, d, regs);
+               desc_handle_irq(LOCOMO_IRQ_KEY_START, d, regs);
        }
 }
 
@@ -273,7 +273,7 @@ static void locomo_gpio_handler(unsigned int irq, struct irqdesc *desc,
                d = irq_desc + LOCOMO_IRQ_GPIO_START;
                for (i = 0; i <= 15; i++, irq++, d++) {
                        if (req & (0x0001 << i)) {
-                               d->handle(irq, d, regs);
+                               desc_handle_irq(irq, d, regs);
                        }
                }
        }
@@ -328,7 +328,7 @@ static void locomo_lt_handler(unsigned int irq, struct irqdesc *desc,
 
        if (locomo_readl(mapbase + LOCOMO_LTINT) & 0x0001) {
                d = irq_desc + LOCOMO_IRQ_LT_START;
-               d->handle(LOCOMO_IRQ_LT_START, d, regs);
+               desc_handle_irq(LOCOMO_IRQ_LT_START, d, regs);
        }
 }
 
@@ -379,7 +379,7 @@ static void locomo_spi_handler(unsigned int irq, struct irqdesc *desc,
 
                for (i = 0; i <= 3; i++, irq++, d++) {
                        if (req & (0x0001 << i)) {
-                               d->handle(irq, d, regs);
+                               desc_handle_irq(irq, d, regs);
                        }
                }
        }
@@ -651,15 +651,15 @@ __locomo_probe(struct device *me, struct resource *mem, int irq)
        return ret;
 }
 
-static void __locomo_remove(struct locomo *lchip)
+static int locomo_remove_child(struct device *dev, void *data)
 {
-       struct list_head *l, *n;
-
-       list_for_each_safe(l, n, &lchip->dev->children) {
-               struct device *d = list_to_dev(l);
+       device_unregister(dev);
+       return 0;
+} 
 
-               device_unregister(d);
-       }
+static void __locomo_remove(struct locomo *lchip)
+{
+       device_for_each_child(lchip->dev, NULL, locomo_remove_child);
 
        if (lchip->irq != NO_IRQ) {
                set_irq_chained_handler(lchip->irq, NULL);
index 38c2eb667eb9909bd0db0667d6b7461bc4c38c57..1a47fbf9cbbc939a9f8f484c5c89301752000cc5 100644 (file)
@@ -268,8 +268,8 @@ static struct irqchip sa1111_low_chip = {
        .mask           = sa1111_mask_lowirq,
        .unmask         = sa1111_unmask_lowirq,
        .retrigger      = sa1111_retrigger_lowirq,
-       .type           = sa1111_type_lowirq,
-       .wake           = sa1111_wake_lowirq,
+       .set_type       = sa1111_type_lowirq,
+       .set_wake       = sa1111_wake_lowirq,
 };
 
 static void sa1111_mask_highirq(unsigned int irq)
@@ -364,8 +364,8 @@ static struct irqchip sa1111_high_chip = {
        .mask           = sa1111_mask_highirq,
        .unmask         = sa1111_unmask_highirq,
        .retrigger      = sa1111_retrigger_highirq,
-       .type           = sa1111_type_highirq,
-       .wake           = sa1111_wake_highirq,
+       .set_type       = sa1111_type_highirq,
+       .set_wake       = sa1111_wake_highirq,
 };
 
 static void sa1111_setup_irq(struct sa1111 *sachip)
index cfd0d3e550d9ef6d1af15982862904283130eed2..688a595598c8a5cdc7b42a9b55a2b5ffe1868a17 100644 (file)
 
 #define SCOOP_REG(d,adr) (*(volatile unsigned short*)(d +(adr)))
 
+/* PCMCIA to Scoop linkage structures for pxa2xx_sharpsl.c
+   There is no easy way to link multiple scoop devices into one
+   single entity for the pxa2xx_pcmcia device */
+int scoop_num;
+struct scoop_pcmcia_dev *scoop_devs;
+
 struct  scoop_dev {
        void  *base;
        spinlock_t scoop_lock;
index 24955263b0968b06b17809bb363da489bf667b48..4198677cd394c81cebbd5eb068e82fb4fc02e9fa 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.13-rc2
-# Fri Jul  8 04:49:34 2005
+# Linux kernel version: 2.6.13
+# Mon Sep  5 18:07:12 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
@@ -102,9 +102,11 @@ CONFIG_OMAP_MUX_WARNINGS=y
 # CONFIG_OMAP_MPU_TIMER is not set
 CONFIG_OMAP_32K_TIMER=y
 CONFIG_OMAP_32K_TIMER_HZ=128
+# CONFIG_OMAP_DM_TIMER is not set
 CONFIG_OMAP_LL_DEBUG_UART1=y
 # CONFIG_OMAP_LL_DEBUG_UART2 is not set
 # CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
 
 #
 # OMAP Core Type
@@ -166,7 +168,6 @@ CONFIG_ISA_DMA_API=y
 #
 # Kernel Features
 #
-# CONFIG_SMP is not set
 CONFIG_PREEMPT=y
 CONFIG_NO_IDLE_HZ=y
 # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
@@ -230,91 +231,82 @@ CONFIG_PM=y
 # CONFIG_APM is not set
 
 #
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-
-#
-# Memory Technology Devices (MTD)
+# Networking
 #
-CONFIG_MTD=y
-CONFIG_MTD_DEBUG=y
-CONFIG_MTD_DEBUG_VERBOSE=3
-# CONFIG_MTD_CONCAT is not set
-CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_REDBOOT_PARTS is not set
-CONFIG_MTD_CMDLINE_PARTS=y
-# CONFIG_MTD_AFS_PARTS is not set
+CONFIG_NET=y
 
 #
-# User Modules And Translation Layers
+# Networking options
 #
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-# CONFIG_FTL is not set
-# CONFIG_NFTL is not set
-# CONFIG_INFTL is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
 
 #
-# RAM/ROM/Flash chip drivers
+# SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_MTD_CFI=y
-# CONFIG_MTD_JEDECPROBE is not set
-CONFIG_MTD_GEN_PROBE=y
-# CONFIG_MTD_CFI_ADV_OPTIONS is not set
-CONFIG_MTD_MAP_BANK_WIDTH_1=y
-CONFIG_MTD_MAP_BANK_WIDTH_2=y
-CONFIG_MTD_MAP_BANK_WIDTH_4=y
-# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
-CONFIG_MTD_CFI_I1=y
-CONFIG_MTD_CFI_I2=y
-# CONFIG_MTD_CFI_I4 is not set
-# CONFIG_MTD_CFI_I8 is not set
-CONFIG_MTD_CFI_INTELEXT=y
-# CONFIG_MTD_CFI_AMDSTD is not set
-# CONFIG_MTD_CFI_STAA is not set
-CONFIG_MTD_CFI_UTIL=y
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_XIP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
-# Mapping drivers for chip access
+# Network testing
 #
-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_ARM_INTEGRATOR is not set
-# CONFIG_MTD_EDB7312 is not set
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 
 #
-# Self-contained MTD device drivers
+# Device Drivers
 #
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_PHRAM is not set
-# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD is not set
-# CONFIG_MTD_BLOCK2MTD is not set
 
 #
-# Disk-On-Chip Device Drivers
+# Generic Driver Options
 #
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
-# NAND Flash Device Drivers
+# Memory Technology Devices (MTD)
 #
-# CONFIG_MTD_NAND is not set
+# CONFIG_MTD is not set
 
 #
 # Parallel port support
@@ -403,72 +395,8 @@ CONFIG_SCSI_PROC_FS=y
 #
 
 #
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
+# Network device support
 #
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
@@ -518,6 +446,8 @@ CONFIG_SLIP_COMPRESSED=y
 # CONFIG_SLIP_MODE_SLIP6 is not set
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
@@ -615,77 +545,15 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 #
 # I2C support
 #
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-
-#
-# I2C Algorithms
-#
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-# CONFIG_I2C_ALGOPCA is not set
-
-#
-# I2C Hardware Bus support
-#
-# CONFIG_I2C_ISA is not set
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_STUB is not set
-# CONFIG_I2C_PCA_ISA is not set
+# CONFIG_I2C is not set
+# CONFIG_I2C_SENSOR is not set
+CONFIG_ISP1301_OMAP=y
 
 #
-# Hardware Sensors Chip support
+# Hardware Monitoring support
 #
-# CONFIG_I2C_SENSOR is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_ADM1025 is not set
-# CONFIG_SENSORS_ADM1026 is not set
-# CONFIG_SENSORS_ADM1031 is not set
-# CONFIG_SENSORS_ADM9240 is not set
-# CONFIG_SENSORS_ASB100 is not set
-# CONFIG_SENSORS_ATXP1 is not set
-# CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_FSCHER is not set
-# CONFIG_SENSORS_FSCPOS is not set
-# CONFIG_SENSORS_GL518SM is not set
-# CONFIG_SENSORS_GL520SM is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM63 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM77 is not set
-# CONFIG_SENSORS_LM78 is not set
-# CONFIG_SENSORS_LM80 is not set
-# CONFIG_SENSORS_LM83 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_LM87 is not set
-# CONFIG_SENSORS_LM90 is not set
-# CONFIG_SENSORS_LM92 is not set
-# CONFIG_SENSORS_MAX1619 is not set
-# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_SENSORS_W83L785TS is not set
-# CONFIG_SENSORS_W83627HF is not set
-# CONFIG_SENSORS_W83627EHF is not set
-
-#
-# Other I2C Chip support
-#
-# CONFIG_SENSORS_DS1337 is not set
-# CONFIG_SENSORS_DS1374 is not set
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_RTC8564 is not set
-CONFIG_ISP1301_OMAP=y
-CONFIG_TPS65010=y
-# CONFIG_SENSORS_MAX6875 is not set
-# CONFIG_I2C_DEBUG_CORE is not set
-# CONFIG_I2C_DEBUG_ALGO is not set
-# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
 # Misc devices
@@ -756,15 +624,9 @@ CONFIG_SOUND=y
 # Open Sound System
 #
 CONFIG_SOUND_PRIME=y
-# CONFIG_SOUND_BT878 is not set
-# CONFIG_SOUND_FUSION is not set
-# CONFIG_SOUND_CS4281 is not set
-# CONFIG_SOUND_SONICVIBES is not set
-# CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
 # CONFIG_SOUND_OSS is not set
-# CONFIG_SOUND_TVMIXER is not set
 # CONFIG_SOUND_AD1980 is not set
 
 #
@@ -810,6 +672,7 @@ CONFIG_EXT2_FS=y
 # 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
@@ -817,6 +680,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
@@ -857,15 +721,6 @@ CONFIG_RAMFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_FS_DEBUG=2
-# CONFIG_JFFS2_FS_NAND is not set
-# CONFIG_JFFS2_FS_NOR_ECC is not set
-# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
-CONFIG_JFFS2_ZLIB=y
-CONFIG_JFFS2_RTIME=y
-# CONFIG_JFFS2_RUBIN is not set
 CONFIG_CRAMFS=y
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -1007,4 +862,3 @@ CONFIG_CRYPTO_DES=y
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=y
index 2b6b4c786e654c125cfa62b750337bc5894b9731..db07ce42b3b2c6873f9b767389ae766d0f89ad6f 100644 (file)
@@ -284,7 +284,7 @@ __syscall_start:
                .long   sys_fstatfs64
                .long   sys_tgkill
                .long   sys_utimes
-/* 270 */      .long   sys_fadvise64_64
+/* 270 */      .long   sys_arm_fadvise64_64_wrapper
                .long   sys_pciconfig_iobase
                .long   sys_pciconfig_read
                .long   sys_pciconfig_write
index 6540db6913381f4474d12594c6a84376d53724dd..dceb826bd216ece20e0e8399eaf785fc7d5cbde3 100644 (file)
@@ -585,7 +585,7 @@ ecard_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
 
                if (pending) {
                        struct irqdesc *d = irq_desc + ec->irq;
-                       d->handle(ec->irq, d, regs);
+                       desc_handle_irq(ec->irq, d, regs);
                        called ++;
                }
        }
@@ -632,7 +632,7 @@ ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *reg
                         * Serial cards should go in 0/1, ethernet/scsi in 2/3
                         * otherwise you will lose serial data at high speeds!
                         */
-                       d->handle(ec->irq, d, regs);
+                       desc_handle_irq(ec->irq, d, regs);
                } else {
                        printk(KERN_WARNING "card%d: interrupt from unclaimed "
                               "card???\n", slot);
index 3f8d0e3aefabf71c6bf82783024a72c39988974f..6281d488ac975d225aa10f536b5849db1b528956 100644 (file)
@@ -265,6 +265,10 @@ sys_futex_wrapper:
                str     r5, [sp, #4]            @ push sixth arg
                b       sys_futex
 
+sys_arm_fadvise64_64_wrapper:
+               str     r5, [sp, #4]            @ push r5 to stack
+               b       sys_arm_fadvise64_64
+
 /*
  * Note: off_4k (r5) is always units of 4K.  If we can't do the requested
  * offset, we return EINVAL.
index 395137a8fad276ce20cb250d58920f7c12fac501..3284118f356b90c8ae1ec7320d71ce143d704220 100644 (file)
@@ -207,8 +207,8 @@ void enable_irq_wake(unsigned int irq)
        unsigned long flags;
 
        spin_lock_irqsave(&irq_controller_lock, flags);
-       if (desc->chip->wake)
-               desc->chip->wake(irq, 1);
+       if (desc->chip->set_wake)
+               desc->chip->set_wake(irq, 1);
        spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 EXPORT_SYMBOL(enable_irq_wake);
@@ -219,8 +219,8 @@ void disable_irq_wake(unsigned int irq)
        unsigned long flags;
 
        spin_lock_irqsave(&irq_controller_lock, flags);
-       if (desc->chip->wake)
-               desc->chip->wake(irq, 0);
+       if (desc->chip->set_wake)
+               desc->chip->set_wake(irq, 0);
        spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 EXPORT_SYMBOL(disable_irq_wake);
@@ -517,7 +517,7 @@ static void do_pending_irqs(struct pt_regs *regs)
                list_for_each_safe(l, n, &head) {
                        desc = list_entry(l, struct irqdesc, pend);
                        list_del_init(&desc->pend);
-                       desc->handle(desc - irq_desc, desc, regs);
+                       desc_handle_irq(desc - irq_desc, desc, regs);
                }
 
                /*
@@ -545,7 +545,7 @@ asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
 
        irq_enter();
        spin_lock(&irq_controller_lock);
-       desc->handle(irq, desc, regs);
+       desc_handle_irq(irq, desc, regs);
 
        /*
         * Now re-run any pending interrupts.
@@ -624,9 +624,9 @@ int set_irq_type(unsigned int irq, unsigned int type)
        }
 
        desc = irq_desc + irq;
-       if (desc->chip->type) {
+       if (desc->chip->set_type) {
                spin_lock_irqsave(&irq_controller_lock, flags);
-               ret = desc->chip->type(irq, type);
+               ret = desc->chip->set_type(irq, type);
                spin_unlock_irqrestore(&irq_controller_lock, flags);
        }
 
@@ -846,8 +846,8 @@ unsigned long probe_irq_on(void)
 
                irq_desc[i].probing = 1;
                irq_desc[i].triggered = 0;
-               if (irq_desc[i].chip->type)
-                       irq_desc[i].chip->type(i, IRQT_PROBE);
+               if (irq_desc[i].chip->set_type)
+                       irq_desc[i].chip->set_type(i, IRQT_PROBE);
                irq_desc[i].chip->unmask(i);
                irqs += 1;
        }
index 5e435e42dacdef45d87173527d60759aa7af083f..a94d75fef598b90bc1a65d32dc017bfa184c0059 100644 (file)
@@ -658,11 +658,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
        /*
         * Block the signal if we were unsuccessful.
         */
-       if (ret != 0 || !(ka->sa.sa_flags & SA_NODEFER)) {
+       if (ret != 0) {
                spin_lock_irq(&tsk->sighand->siglock);
                sigorsets(&tsk->blocked, &tsk->blocked,
                          &ka->sa.sa_mask);
-               sigaddset(&tsk->blocked, sig);
+               if (!(ka->sa.sa_flags & SA_NODEFER))
+                       sigaddset(&tsk->blocked, sig);
                recalc_sigpending();
                spin_unlock_irq(&tsk->sighand->siglock);
        }
index b2085735a2baf1833c90ab1ad9c237d58e869e28..826164945747523fa93712d9d0575051b511ccb7 100644 (file)
@@ -110,7 +110,7 @@ int __cpuinit __cpu_up(unsigned int cpu)
         * We need to tell the secondary core where to find
         * its stack and the page tables.
         */
-       secondary_data.stack = (void *)idle->thread_info + THREAD_SIZE - 8;
+       secondary_data.stack = (void *)idle->thread_info + THREAD_START_SP;
        secondary_data.pgdir = virt_to_phys(pgd);
        wmb();
 
index f897ce2ccf0d358cc79a6493b23d1cf33d91a05a..42629ff84f5a8864787c1d862f001e47a3000765 100644 (file)
@@ -311,3 +311,13 @@ long execve(const char *filename, char **argv, char **envp)
        return ret;
 }
 EXPORT_SYMBOL(execve);
+
+/*
+ * Since loff_t is a 64 bit type we avoid a lot of ABI hastle
+ * with a different argument ordering.
+ */
+asmlinkage long sys_arm_fadvise64_64(int fd, int advice,
+                                    loff_t offset, loff_t len)
+{
+       return sys_fadvise64_64(fd, offset, len, advice);
+}
index 1b7fcd50c3e25c8a208bc3347dc55dc7d0605e1e..69449a818dccecd78ac290032124c9998e746d4a 100644 (file)
@@ -102,7 +102,7 @@ static unsigned long next_rtc_update;
  */
 static inline void do_set_rtc(void)
 {
-       if (time_status & STA_UNSYNC || set_rtc == NULL)
+       if (!ntp_synced() || set_rtc == NULL)
                return;
 
        if (next_rtc_update &&
@@ -292,10 +292,7 @@ int do_settimeofday(struct timespec *tv)
        set_normalized_timespec(&xtime, sec, nsec);
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
        return 0;
@@ -433,10 +430,12 @@ void timer_dyn_reprogram(void)
 {
        struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
 
-       write_seqlock(&xtime_lock);
-       if (dyn_tick->state & DYN_TICK_ENABLED)
-               dyn_tick->reprogram(next_timer_interrupt() - jiffies);
-       write_sequnlock(&xtime_lock);
+       if (dyn_tick) {
+               write_seqlock(&xtime_lock);
+               if (dyn_tick->state & DYN_TICK_ENABLED)
+                       dyn_tick->reprogram(next_timer_interrupt() - jiffies);
+               write_sequnlock(&xtime_lock);
+       }
 }
 
 static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
index 324d9edeec38f3e1dc70cff7248705e0837429ea..bdd257921cfbe639cd0adfb8c30c4febd79487cc 100644 (file)
@@ -87,6 +87,7 @@ config FOOTBRIDGE_ADDIN
 
 # EBSA285 board in either host or addin mode
 config ARCH_EBSA285
+       select ARCH_MAY_HAVE_PC_FDC
        bool
 
 endif
index b21016070ea304a07e0ae0a2741f4162c2872537..e1c43b331d64d357ece5282be3929cd136bfe026 100644 (file)
@@ -95,7 +95,7 @@ isa_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
        }
 
        desc = irq_desc + isa_irq;
-       desc->handle(isa_irq, desc, regs);
+       desc_handle_irq(isa_irq, desc, regs);
 }
 
 static struct irqaction irq_cascade = { .handler = no_action, .name = "cascade", };
index 96aa3af70d86ce484220b44cbc996450c568dec1..5110e2e65ddd3176a78c4880daaec219d4eae138 100644 (file)
@@ -108,7 +108,7 @@ h720x_gpio_handler(unsigned int mask, unsigned int irq,
        while (mask) {
                if (mask & 1) {
                        IRQDBG("handling irq %d\n", irq);
-                       desc->handle(irq, desc, regs);
+                       desc_handle_irq(irq, desc, regs);
                }
                irq++;
                desc++;
index 593b6a2a30e1d5e8c2aa05ded41c8cbf1bd1284b..4b3199319e68b4c988f4f24edff2ded120405f24 100644 (file)
@@ -126,7 +126,7 @@ h7202_timerx_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
        desc = irq_desc + irq;
        while (mask) {
                if (mask & 1)
-                       desc->handle(irq, desc, regs);
+                       desc_handle_irq(irq, desc, regs);
                irq++;
                desc++;
                mask >>= 1;
index 0c2713426dfd608faa86ca834e00b1c4c9e7fe58..eeb8a6d4a3999c1f9f605588ab0852e0b4b88621 100644 (file)
@@ -152,7 +152,7 @@ imx_gpio_handler(unsigned int mask, unsigned int irq,
        while (mask) {
                if (mask & 1) {
                        DEBUG_IRQ("handling irq %d\n", irq);
-                       desc->handle(irq, desc, regs);
+                       desc_handle_irq(irq, desc, regs);
                }
                irq++;
                desc++;
@@ -214,7 +214,7 @@ static struct irqchip imx_gpio_chip = {
        .ack = imx_gpio_ack_irq,
        .mask = imx_gpio_mask_irq,
        .unmask = imx_gpio_unmask_irq,
-       .type = imx_gpio_irq_type,
+       .set_type = imx_gpio_irq_type,
 };
 
 void __init
index 569f328c479db0c4d30e468dd2772f3a9775b78a..2be5c03ab87f858c07168e646396566b8fef3106 100644 (file)
@@ -170,7 +170,7 @@ sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
                irq += IRQ_SIC_START;
 
                desc = irq_desc + irq;
-               desc->handle(irq, desc, regs);
+               desc_handle_irq(irq, desc, regs);
        } while (status);
 }
 
index d53af16695023d16f7867b74c35b56c2dfa952cc..0039793b694a20cd63da8930386a5ba3c6cbf9d1 100644 (file)
@@ -60,7 +60,7 @@ static unsigned long iop321_gettimeoffset(void)
        /*
         * Now convert them to usec.
         */
-       usec = (unsigned long)(elapsed * (tick_nsec / 1000)) / LATCH;
+       usec = (unsigned long)(elapsed / (CLOCK_TICK_RATE/1000000));
 
        return usec;
 }
index 1a6d9d661e4b8ee851ef0867be104309eebe917f..8eddfac7e2b046450d74a6074837b9f73e0fff1b 100644 (file)
@@ -58,7 +58,7 @@ static unsigned long iop331_gettimeoffset(void)
        /*
         * Now convert them to usec.
         */
-       usec = (unsigned long)(elapsed * (tick_nsec / 1000)) / LATCH;
+       usec = (unsigned long)(elapsed / (CLOCK_TICK_RATE/1000000));
 
        return usec;
 }
index 45b18658499f8e8c984bb105682ef4031fb174b3..098c817a7fb82a8e6fc7f38c24757ec620f6e47e 100644 (file)
@@ -317,7 +317,7 @@ static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc, str
        for (i = 0; i <= 7; i++) {
                if (status & (1<<i)) {
                        desc = irq_desc + i + IRQ_IXP2000_GPIO0;
-                       desc->handle(i + IRQ_IXP2000_GPIO0, desc, regs);
+                       desc_handle_irq(i + IRQ_IXP2000_GPIO0, desc, regs);
                }
        }
 }
@@ -380,10 +380,10 @@ static void ixp2000_GPIO_irq_unmask(unsigned int irq)
 }
 
 static struct irqchip ixp2000_GPIO_irq_chip = {
-       .type   = ixp2000_GPIO_irq_type,
-       .ack    = ixp2000_GPIO_irq_mask_ack,
-       .mask   = ixp2000_GPIO_irq_mask,
-       .unmask = ixp2000_GPIO_irq_unmask
+       .ack            = ixp2000_GPIO_irq_mask_ack,
+       .mask           = ixp2000_GPIO_irq_mask,
+       .unmask         = ixp2000_GPIO_irq_unmask,
+       .set_type       = ixp2000_GPIO_irq_type,
 };
 
 static void ixp2000_pci_irq_mask(unsigned int irq)
index a43369ad876ca57cc27ab0732053ccb5d13417a1..63ba0191aa6572c5ee98db13713cd62096f2aed7 100644 (file)
@@ -133,7 +133,7 @@ static void ixdp2x00_irq_handler(unsigned int irq, struct irqdesc *desc, struct
                        struct irqdesc *cpld_desc;
                        int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
                        cpld_desc = irq_desc + cpld_irq;
-                       cpld_desc->handle(cpld_irq, cpld_desc, regs);
+                       desc_handle_irq(cpld_irq, cpld_desc, regs);
                }
        }
 
index 43447dad165759affb4ddcdd22e108c0cdefd187..7a51099212877c94efef75908be49c37e312ecdf 100644 (file)
@@ -82,7 +82,7 @@ static void ixdp2x01_irq_handler(unsigned int irq, struct irqdesc *desc, struct
                        struct irqdesc *cpld_desc;
                        int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
                        cpld_desc = irq_desc + cpld_irq;
-                       cpld_desc->handle(cpld_irq, cpld_desc, regs);
+                       desc_handle_irq(cpld_irq, cpld_desc, regs);
                }
        }
 
index 04490a9f8f6ecfc2158d8b21ec3aa096b888e1f2..52ad11328e961225465a6e461b5aa8d564039a45 100644 (file)
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
 
-enum ixp4xx_irq_type {
-       IXP4XX_IRQ_LEVEL, IXP4XX_IRQ_EDGE
-};
-static void ixp4xx_config_irq(unsigned irq, enum ixp4xx_irq_type type);
-
-/*************************************************************************
- * GPIO acces functions
- *************************************************************************/
-
-/*
- * Configure GPIO line for input, interrupt, or output operation
- *
- * TODO: Enable/disable the irq_desc based on interrupt or output mode.
- * TODO: Should these be named ixp4xx_gpio_?
- */
-void gpio_line_config(u8 line, u32 style)
-{
-       static const int gpio2irq[] = {
-               6, 7, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29
-       };
-       u32 enable;
-       volatile u32 *int_reg;
-       u32 int_style;
-       enum ixp4xx_irq_type irq_type;
-
-       enable = *IXP4XX_GPIO_GPOER;
-
-       if (style & IXP4XX_GPIO_OUT) {
-               enable &= ~((1) << line);
-       } else if (style & IXP4XX_GPIO_IN) {
-               enable |= ((1) << line);
-
-               switch (style & IXP4XX_GPIO_INTSTYLE_MASK)
-               {
-               case (IXP4XX_GPIO_ACTIVE_HIGH):
-                       int_style = IXP4XX_GPIO_STYLE_ACTIVE_HIGH;
-                       irq_type = IXP4XX_IRQ_LEVEL;
-                       break;
-               case (IXP4XX_GPIO_ACTIVE_LOW):
-                       int_style = IXP4XX_GPIO_STYLE_ACTIVE_LOW;
-                       irq_type = IXP4XX_IRQ_LEVEL;
-                       break;
-               case (IXP4XX_GPIO_RISING_EDGE):
-                       int_style = IXP4XX_GPIO_STYLE_RISING_EDGE;
-                       irq_type = IXP4XX_IRQ_EDGE;
-                       break;
-               case (IXP4XX_GPIO_FALLING_EDGE):
-                       int_style = IXP4XX_GPIO_STYLE_FALLING_EDGE;
-                       irq_type = IXP4XX_IRQ_EDGE;
-                       break;
-               case (IXP4XX_GPIO_TRANSITIONAL):
-                       int_style = IXP4XX_GPIO_STYLE_TRANSITIONAL;
-                       irq_type = IXP4XX_IRQ_EDGE;
-                       break;
-               default:
-                       int_style = IXP4XX_GPIO_STYLE_ACTIVE_HIGH;
-                       irq_type = IXP4XX_IRQ_LEVEL;
-                       break;
-               }
-
-               if (style & IXP4XX_GPIO_INTSTYLE_MASK)
-                       ixp4xx_config_irq(gpio2irq[line], irq_type);
-
-               if (line >= 8) {        /* pins 8-15 */ 
-                       line -= 8;
-                       int_reg = IXP4XX_GPIO_GPIT2R;
-               }
-               else {                  /* pins 0-7 */
-                       int_reg = IXP4XX_GPIO_GPIT1R;
-               }
-
-               /* Clear the style for the appropriate pin */
-               *int_reg &= ~(IXP4XX_GPIO_STYLE_CLEAR << 
-                               (line * IXP4XX_GPIO_STYLE_SIZE));
-
-               /* Set the new style */
-               *int_reg |= (int_style << (line * IXP4XX_GPIO_STYLE_SIZE));
-       }
-
-       *IXP4XX_GPIO_GPOER = enable;
-}
-
-EXPORT_SYMBOL(gpio_line_config);
-
 /*************************************************************************
  * IXP4xx chipset I/O mapping
  *************************************************************************/
@@ -165,6 +81,69 @@ void __init ixp4xx_map_io(void)
  *       (be it PCI or something else) configures that GPIO line
  *       as an IRQ.
  **************************************************************************/
+enum ixp4xx_irq_type {
+       IXP4XX_IRQ_LEVEL, IXP4XX_IRQ_EDGE
+};
+
+static void ixp4xx_config_irq(unsigned irq, enum ixp4xx_irq_type type);
+
+/*
+ * IRQ -> GPIO mapping table
+ */
+static int irq2gpio[32] = {
+       -1, -1, -1, -1, -1, -1,  0,  1,
+       -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1,  2,  3,  4,  5,  6,
+        7,  8,  9, 10, 11, 12, -1, -1,
+};
+
+static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type)
+{
+       int line = irq2gpio[irq];
+       u32 int_style;
+       enum ixp4xx_irq_type irq_type;
+       volatile u32 *int_reg;
+
+       /*
+        * Only for GPIO IRQs
+        */
+       if (line < 0)
+               return -EINVAL;
+
+       if (type & IRQT_BOTHEDGE) {
+               int_style = IXP4XX_GPIO_STYLE_TRANSITIONAL;
+               irq_type = IXP4XX_IRQ_EDGE;
+       } else  if (type & IRQT_RISING) {
+               int_style = IXP4XX_GPIO_STYLE_RISING_EDGE;
+               irq_type = IXP4XX_IRQ_EDGE;
+       } else if (type & IRQT_FALLING) {
+               int_style = IXP4XX_GPIO_STYLE_FALLING_EDGE;
+               irq_type = IXP4XX_IRQ_EDGE;
+       } else if (type & IRQT_HIGH) {
+               int_style = IXP4XX_GPIO_STYLE_ACTIVE_HIGH;
+               irq_type = IXP4XX_IRQ_LEVEL;
+       } else if (type & IRQT_LOW) {
+               int_style = IXP4XX_GPIO_STYLE_ACTIVE_LOW;
+               irq_type = IXP4XX_IRQ_LEVEL;
+       }
+
+       ixp4xx_config_irq(irq, irq_type);
+
+       if (line >= 8) {        /* pins 8-15 */
+               line -= 8;
+               int_reg = IXP4XX_GPIO_GPIT2R;
+       } else {                /* pins 0-7 */
+               int_reg = IXP4XX_GPIO_GPIT1R;
+       }
+
+       /* Clear the style for the appropriate pin */
+       *int_reg &= ~(IXP4XX_GPIO_STYLE_CLEAR <<
+                       (line * IXP4XX_GPIO_STYLE_SIZE));
+
+       /* Set the new style */
+       *int_reg |= (int_style << (line * IXP4XX_GPIO_STYLE_SIZE));
+}
+
 static void ixp4xx_irq_mask(unsigned int irq)
 {
        if (cpu_is_ixp46x() && irq >= 32)
@@ -183,12 +162,6 @@ static void ixp4xx_irq_unmask(unsigned int irq)
 
 static void ixp4xx_irq_ack(unsigned int irq)
 {
-       static int irq2gpio[32] = {
-               -1, -1, -1, -1, -1, -1,  0,  1,
-               -1, -1, -1, -1, -1, -1, -1, -1,
-               -1, -1, -1,  2,  3,  4,  5,  6,
-                7,  8,  9, 10, 11, 12, -1, -1,
-       };
        int line = (irq < 32) ? irq2gpio[irq] : -1;
 
        if (line >= 0)
@@ -206,15 +179,17 @@ static void ixp4xx_irq_level_unmask(unsigned int irq)
 }
 
 static struct irqchip ixp4xx_irq_level_chip = {
-       .ack    = ixp4xx_irq_mask,
-       .mask   = ixp4xx_irq_mask,
-       .unmask = ixp4xx_irq_level_unmask,
+       .ack            = ixp4xx_irq_mask,
+       .mask           = ixp4xx_irq_mask,
+       .unmask         = ixp4xx_irq_level_unmask,
+       .set_type       = ixp4xx_set_irq_type,
 };
 
 static struct irqchip ixp4xx_irq_edge_chip = {
-       .ack    = ixp4xx_irq_ack,
-       .mask   = ixp4xx_irq_mask,
-       .unmask = ixp4xx_irq_unmask,
+       .ack            = ixp4xx_irq_ack,
+       .mask           = ixp4xx_irq_mask,
+       .unmask         = ixp4xx_irq_unmask,
+       .set_type       = ixp4xx_set_irq_type,
 };
 
 static void ixp4xx_config_irq(unsigned irq, enum ixp4xx_irq_type type)
index afafb42ae12951c8a96bc615328bee61a5565b07..60de8a94cff5f828cf93840d0d80cff53cc395da 100644 (file)
@@ -30,11 +30,8 @@ extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys);
 
 void __init coyote_pci_preinit(void)
 {
-       gpio_line_config(COYOTE_PCI_SLOT0_PIN,
-                       IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
-
-       gpio_line_config(COYOTE_PCI_SLOT1_PIN,
-                       IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
+       set_irq_type(IRQ_COYOTE_PCI_SLOT0, IRQT_LOW);
+       set_irq_type(IRQ_COYOTE_PCI_SLOT1, IRQT_LOW);
 
        gpio_line_isr_clear(COYOTE_PCI_SLOT0_PIN);
        gpio_line_isr_clear(COYOTE_PCI_SLOT1_PIN);
index 411ea999619055a7b0e73bd3678ecd9ad8806989..8b2f25322452b2c449ca02296128075e4a09918e 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 
-void __init coyote_map_io(void)
-{
-       ixp4xx_map_io();
-}
-
 static struct flash_platform_data coyote_flash_data = {
        .map_name       = "cfi_probe",
        .width          = 2,
@@ -107,7 +102,7 @@ MACHINE_START(ADI_COYOTE, "ADI Engineering Coyote")
        .phys_ram       = PHYS_OFFSET,
        .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
        .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
-       .map_io         = coyote_map_io,
+       .map_io         = ixp4xx_map_io,
        .init_irq       = ixp4xx_init_irq,
        .timer          = &ixp4xx_timer,
        .boot_params    = 0x0100,
@@ -125,7 +120,7 @@ MACHINE_START(IXDPG425, "Intel IXDPG425")
        .phys_ram       = PHYS_OFFSET,
        .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
        .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
-       .map_io         = coyote_map_io,
+       .map_io         = ixp4xx_map_io,
        .init_irq       = ixp4xx_init_irq,
        .timer          = &ixp4xx_timer,
        .boot_params    = 0x0100,
index b18035824e3e386c59a38b2c5d6e6db321fe6258..a66484b63d36b12b0dccd06770b3b3a9d2931a7a 100644 (file)
@@ -35,26 +35,20 @@ extern void ixp4xx_pci_preinit(void);
 extern int ixp4xx_setup(int nr, struct pci_sys_data *sys);
 extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys);
 
-        /*
-        * The exact GPIO pins and IRQs are defined in arch-ixp4xx/gtwx5715.h
-        * Slot 0 isn't actually populated with a card connector but
-        * we initialize it anyway in case a future version has the
-        * slot populated or someone with good soldering skills has
-        * some free time.
-        */
-
-
-static void gtwx5715_init_gpio(u8 pin, u32 style)
-{
-       gpio_line_config(pin, style | IXP4XX_GPIO_ACTIVE_LOW);
-
-       if (style & IXP4XX_GPIO_IN) gpio_line_isr_clear(pin);
-}
 
+/*
+ * The exact GPIO pins and IRQs are defined in arch-ixp4xx/gtwx5715.h
+ * Slot 0 isn't actually populated with a card connector but
+ * we initialize it anyway in case a future version has the
+ * slot populated or someone with good soldering skills has
+ * some free time.
+ */
 void __init gtwx5715_pci_preinit(void)
 {
-       gtwx5715_init_gpio(GTWX5715_PCI_SLOT0_INTA_GPIO,        IXP4XX_GPIO_IN);
-       gtwx5715_init_gpio(GTWX5715_PCI_SLOT1_INTA_GPIO,        IXP4XX_GPIO_IN);
+       set_irq_type(GTWX5715_PCI_SLOT0_INTA_IRQ, IRQT_LOW);
+       set_irq_type(GTWX5715_PCI_SLOT0_INTB_IRQ, IRQT_LOW);
+       set_irq_type(GTWX5715_PCI_SLOT1_INTA_IRQ, IRQT_LOW);
+       set_irq_type(GTWX5715_PCI_SLOT1_INTB_IRQ, IRQT_LOW);
 
        ixp4xx_pci_preinit();
 }
index 333459d6aa464bb5394fd46783e9b6690b6ed4aa..3fd92c5cbaa83e21566595aab80090a93dcdd192 100644 (file)
@@ -101,12 +101,6 @@ static struct platform_device gtwx5715_uart_device = {
        .resource       = gtwx5715_uart_resources,
 };
 
-
-void __init gtwx5715_map_io(void)
-{
-       ixp4xx_map_io();
-}
-
 static struct flash_platform_data gtwx5715_flash_data = {
        .map_name       = "cfi_probe",
        .width          = 2,
@@ -144,7 +138,7 @@ MACHINE_START(GTWX5715, "Gemtek GTWX5715 (Linksys WRV54G)")
        .phys_ram       = PHYS_OFFSET,
        .phys_io        = IXP4XX_UART2_BASE_PHYS,
        .io_pg_offst    = ((IXP4XX_UART2_BASE_VIRT) >> 18) & 0xfffc,
-       .map_io         = gtwx5715_map_io,
+       .map_io         = ixp4xx_map_io,
        .init_irq       = ixp4xx_init_irq,
        .timer          = &ixp4xx_timer,
        .boot_params    = 0x0100,
index c2ab9ebb5980cac5d68f1e57f68973461b36e1fa..f9a1d3e7d6922d30c6226690d06162facec746b2 100644 (file)
 
 void __init ixdp425_pci_preinit(void)
 {
-       gpio_line_config(IXDP425_PCI_INTA_PIN,
-                               IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
-       gpio_line_config(IXDP425_PCI_INTB_PIN, 
-                               IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
-       gpio_line_config(IXDP425_PCI_INTC_PIN, 
-                               IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
-       gpio_line_config(IXDP425_PCI_INTD_PIN, 
-                               IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
+       set_irq_type(IRQ_IXDP425_PCI_INTA, IRQT_LOW);
+       set_irq_type(IRQ_IXDP425_PCI_INTB, IRQT_LOW);
+       set_irq_type(IRQ_IXDP425_PCI_INTC, IRQT_LOW);
+       set_irq_type(IRQ_IXDP425_PCI_INTD, IRQT_LOW);
 
        gpio_line_isr_clear(IXDP425_PCI_INTA_PIN);
        gpio_line_isr_clear(IXDP425_PCI_INTB_PIN);
index fa0646c8693b096c7c1ee6b6a16dc3074bff2679..6c14ff3c23a04706df50f9f8ad38e5179994e21b 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 
-void __init ixdp425_map_io(void) 
-{
-       ixp4xx_map_io();
-}
-
 static struct flash_platform_data ixdp425_flash_data = {
        .map_name       = "cfi_probe",
        .width          = 2,
@@ -133,7 +128,7 @@ MACHINE_START(IXDP425, "Intel IXDP425 Development Platform")
        .phys_ram       = PHYS_OFFSET,
        .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
        .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
-       .map_io         = ixdp425_map_io,
+       .map_io         = ixp4xx_map_io,
        .init_irq       = ixp4xx_init_irq,
        .timer          = &ixp4xx_timer,
        .boot_params    = 0x0100,
@@ -145,7 +140,7 @@ MACHINE_START(IXDP465, "Intel IXDP465 Development Platform")
        .phys_ram       = PHYS_OFFSET,
        .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
        .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
-       .map_io         = ixdp425_map_io,
+       .map_io         = ixp4xx_map_io,
        .init_irq       = ixp4xx_init_irq,
        .timer          = &ixp4xx_timer,
        .boot_params    = 0x0100,
@@ -157,7 +152,7 @@ MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform")
        .phys_ram       = PHYS_OFFSET,
        .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
        .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
-       .map_io         = ixdp425_map_io,
+       .map_io         = ixp4xx_map_io,
        .init_irq       = ixp4xx_init_irq,
        .timer          = &ixp4xx_timer,
        .boot_params    = 0x0100,
@@ -176,7 +171,7 @@ MACHINE_START(AVILA, "Gateworks Avila Network Platform")
        .phys_ram       = PHYS_OFFSET,
        .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
        .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
-       .map_io         = ixdp425_map_io,
+       .map_io         = ixp4xx_map_io,
        .init_irq       = ixp4xx_init_irq,
        .timer          = &ixp4xx_timer,
        .boot_params    = 0x0100,
index ce4563f006766b411a8758005b782c8752faed2c..fe5e7660de1d5e855594b45a6fdaf7cd4c152655 100644 (file)
@@ -29,8 +29,8 @@ extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys);
 
 void __init ixdpg425_pci_preinit(void)
 {
-       gpio_line_config(6, IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
-       gpio_line_config(7, IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
+       set_irq_type(IRQ_IXP4XX_GPIO6, IRQT_LOW);
+       set_irq_type(IRQ_IXP4XX_GPIO7, IRQT_LOW);
 
        gpio_line_isr_clear(6);
        gpio_line_isr_clear(7);
index beda7c2602fbe37bdeec9b1800d2b00acc6d0850..578a52461fdbc3c5670acdbc9b3d79bb4f8112eb 100644 (file)
@@ -13,4 +13,4 @@ extern struct sys_timer lh7a40x_timer;
 extern void lh7a400_init_irq (void);
 extern void lh7a404_init_irq (void);
 
-#define IRQ_DISPATCH(irq) irq_desc[irq].handle ((irq), &irq_desc[irq], regs)
+#define IRQ_DISPATCH(irq) desc_handle_irq((irq),(irq_desc + irq), regs)
index 7c08f6c2e1d0bc38d0864fb724349de0abcc41ec..c12a7833562570a4e88497c85b5381f3dd0ad080 100644 (file)
@@ -102,7 +102,7 @@ void innovator_fpga_IRQ_demux(unsigned int irq, struct irqdesc *desc,
             fpga_irq++, stat >>= 1) {
                if (stat & 1) {
                        d = irq_desc + fpga_irq;
-                       d->handle(fpga_irq, d, regs);
+                       desc_handle_irq(fpga_irq, d, regs);
                }
        }
 }
index a11b6d807352ccf93add9b87dae0069f204d6bc3..afd5d67e4ae73625e25a88bcf93ef79b34323602 100644 (file)
@@ -165,10 +165,10 @@ static struct omap_irq_bank omap1610_irq_banks[] = {
 #endif
 
 static struct irqchip omap_irq_chip = {
-       .ack    = omap_mask_ack_irq,
-       .mask   = omap_mask_irq,
-       .unmask = omap_unmask_irq,
-       .wake   = omap_wake_irq,
+       .ack            = omap_mask_ack_irq,
+       .mask           = omap_mask_irq,
+       .unmask         = omap_unmask_irq,
+       .set_wake       = omap_wake_irq,
 };
 
 void __init omap_init_irq(void)
index efc2f657184edaf0245863b8782510985f28eb00..33dae99ec2d843290105013226519a47e3a50daf 100644 (file)
@@ -11,7 +11,7 @@ obj-$(CONFIG_PXA27x) += pxa27x.o
 obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
 obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o
 obj-$(CONFIG_ARCH_PXA_IDP) += idp.o
-obj-$(CONFIG_PXA_SHARP_C7xx)   += corgi.o corgi_ssp.o ssp.o
+obj-$(CONFIG_PXA_SHARP_C7xx)   += corgi.o corgi_ssp.o corgi_lcd.o ssp.o
 obj-$(CONFIG_MACH_POODLE)      += poodle.o
 
 # Support for blinky lights
index 86b862f56e7e9ad046f0c374e156bb95eb990418..29185acdd9e1ea7e6eb7a8f9182e18bac37f35b1 100644 (file)
@@ -39,7 +39,6 @@
 
 #include <asm/mach/sharpsl_param.h>
 #include <asm/hardware/scoop.h>
-#include <video/w100fb.h>
 
 #include "generic.h"
 
@@ -60,6 +59,15 @@ static struct scoop_config corgi_scoop_setup = {
        .io_out         = CORGI_SCOOP_IO_OUT,
 };
 
+static struct scoop_pcmcia_dev corgi_pcmcia_scoop[] = {
+{
+       .dev        = &corgiscoop_device.dev,
+       .irq        = CORGI_IRQ_GPIO_CF_IRQ,
+       .cd_irq     = CORGI_IRQ_GPIO_CF_CD,
+       .cd_irq_str = "PCMCIA0 CD",
+},
+};
+
 struct platform_device corgiscoop_device = {
        .name           = "sharp-scoop",
        .id             = -1,
@@ -78,7 +86,7 @@ struct platform_device corgiscoop_device = {
  * also use scoop functions and this makes the power up/down order
  * work correctly.
  */
-static struct platform_device corgissp_device = {
+struct platform_device corgissp_device = {
        .name           = "corgi-ssp",
        .dev            = {
                .parent = &corgiscoop_device.dev,
@@ -88,41 +96,33 @@ static struct platform_device corgissp_device = {
 
 
 /*
- * Corgi w100 Frame Buffer Device
+ * Corgi Backlight Device
  */
-static struct w100fb_mach_info corgi_fb_info = {
-       .w100fb_ssp_send        = corgi_ssp_lcdtg_send,
-       .comadj                         = -1,
-       .phadadj                        = -1,
-};
-
-static struct resource corgi_fb_resources[] = {
-       [0] = {
-               .start          = 0x08000000,
-               .end            = 0x08ffffff,
-               .flags          = IORESOURCE_MEM,
+static struct platform_device corgibl_device = {
+       .name           = "corgi-bl",
+       .dev            = {
+               .parent = &corgifb_device.dev,
        },
+       .id             = -1,
 };
 
-static struct platform_device corgifb_device = {
-       .name           = "w100fb",
+
+/*
+ * Corgi Keyboard Device
+ */
+static struct platform_device corgikbd_device = {
+       .name           = "corgi-keyboard",
        .id             = -1,
-       .dev            = {
-               .platform_data  = &corgi_fb_info,
-               .parent = &corgissp_device.dev,
-       },
-       .num_resources  = ARRAY_SIZE(corgi_fb_resources),
-       .resource       = corgi_fb_resources,
 };
 
 
 /*
- * Corgi Backlight Device
+ * Corgi Touch Screen Device
  */
-static struct platform_device corgibl_device = {
-       .name           = "corgi-bl",
+static struct platform_device corgits_device = {
+       .name           = "corgi-ts",
        .dev            = {
-               .parent = &corgifb_device.dev,
+               .parent = &corgissp_device.dev,
        },
        .id             = -1,
 };
@@ -190,6 +190,11 @@ static void corgi_mci_setpower(struct device *dev, unsigned int vdd)
        }
 }
 
+static int corgi_mci_get_ro(struct device *dev)
+{
+       return GPLR(CORGI_GPIO_nSD_WP) & GPIO_bit(CORGI_GPIO_nSD_WP);
+}
+
 static void corgi_mci_exit(struct device *dev, void *data)
 {
        free_irq(CORGI_IRQ_GPIO_nSD_DETECT, data);
@@ -199,11 +204,13 @@ static void corgi_mci_exit(struct device *dev, void *data)
 static struct pxamci_platform_data corgi_mci_platform_data = {
        .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
        .init           = corgi_mci_init,
+       .get_ro         = corgi_mci_get_ro,
        .setpower       = corgi_mci_setpower,
        .exit           = corgi_mci_exit,
 };
 
 
+
 /*
  * USB Device Controller
  */
@@ -229,18 +236,20 @@ static struct platform_device *devices[] __initdata = {
        &corgiscoop_device,
        &corgissp_device,
        &corgifb_device,
+       &corgikbd_device,
        &corgibl_device,
+       &corgits_device,
 };
 
 static void __init corgi_init(void)
 {
-       corgi_fb_info.comadj=sharpsl_param.comadj;
-       corgi_fb_info.phadadj=sharpsl_param.phadadj;
-
        pxa_gpio_mode(CORGI_GPIO_USB_PULLUP | GPIO_OUT);
        pxa_set_udc_info(&udc_info);
        pxa_set_mci_info(&corgi_mci_platform_data);
 
+       scoop_num = 1;
+       scoop_devs = &corgi_pcmcia_scoop[0];
+
        platform_add_devices(devices, ARRAY_SIZE(devices));
 }
 
diff --git a/arch/arm/mach-pxa/corgi_lcd.c b/arch/arm/mach-pxa/corgi_lcd.c
new file mode 100644 (file)
index 0000000..deac29c
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * linux/drivers/video/w100fb.c
+ *
+ * Corgi LCD Specific Code for ATI Imageon w100 (Wallaby)
+ *
+ * Copyright (C) 2005 Richard Purdie
+ *
+ * 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/delay.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <asm/arch/corgi.h>
+#include <asm/mach/sharpsl_param.h>
+#include <video/w100fb.h>
+
+/* Register Addresses */
+#define RESCTL_ADRS     0x00
+#define PHACTRL_ADRS    0x01
+#define DUTYCTRL_ADRS   0x02
+#define POWERREG0_ADRS  0x03
+#define POWERREG1_ADRS  0x04
+#define GPOR3_ADRS      0x05
+#define PICTRL_ADRS     0x06
+#define POLCTRL_ADRS    0x07
+
+/* Resgister Bit Definitions */
+#define RESCTL_QVGA     0x01
+#define RESCTL_VGA      0x00
+
+#define POWER1_VW_ON    0x01  /* VW Supply FET ON */
+#define POWER1_GVSS_ON  0x02  /* GVSS(-8V) Power Supply ON */
+#define POWER1_VDD_ON   0x04  /* VDD(8V),SVSS(-4V) Power Supply ON */
+
+#define POWER1_VW_OFF   0x00  /* VW Supply FET OFF */
+#define POWER1_GVSS_OFF 0x00  /* GVSS(-8V) Power Supply OFF */
+#define POWER1_VDD_OFF  0x00  /* VDD(8V),SVSS(-4V) Power Supply OFF */
+
+#define POWER0_COM_DCLK 0x01  /* COM Voltage DC Bias DAC Serial Data Clock */
+#define POWER0_COM_DOUT 0x02  /* COM Voltage DC Bias DAC Serial Data Out */
+#define POWER0_DAC_ON   0x04  /* DAC Power Supply ON */
+#define POWER0_COM_ON   0x08  /* COM Powewr Supply ON */
+#define POWER0_VCC5_ON  0x10  /* VCC5 Power Supply ON */
+
+#define POWER0_DAC_OFF  0x00  /* DAC Power Supply OFF */
+#define POWER0_COM_OFF  0x00  /* COM Powewr Supply OFF */
+#define POWER0_VCC5_OFF 0x00  /* VCC5 Power Supply OFF */
+
+#define PICTRL_INIT_STATE      0x01
+#define PICTRL_INIOFF          0x02
+#define PICTRL_POWER_DOWN      0x04
+#define PICTRL_COM_SIGNAL_OFF  0x08
+#define PICTRL_DAC_SIGNAL_OFF  0x10
+
+#define POLCTRL_SYNC_POL_FALL  0x01
+#define POLCTRL_EN_POL_FALL    0x02
+#define POLCTRL_DATA_POL_FALL  0x04
+#define POLCTRL_SYNC_ACT_H     0x08
+#define POLCTRL_EN_ACT_L       0x10
+
+#define POLCTRL_SYNC_POL_RISE  0x00
+#define POLCTRL_EN_POL_RISE    0x00
+#define POLCTRL_DATA_POL_RISE  0x00
+#define POLCTRL_SYNC_ACT_L     0x00
+#define POLCTRL_EN_ACT_H       0x00
+
+#define PHACTRL_PHASE_MANUAL   0x01
+#define DEFAULT_PHAD_QVGA     (9)
+#define DEFAULT_COMADJ        (125)
+
+/*
+ * This is only a psuedo I2C interface. We can't use the standard kernel
+ * routines as the interface is write only. We just assume the data is acked...
+ */
+static void lcdtg_ssp_i2c_send(u8 data)
+{
+       corgi_ssp_lcdtg_send(POWERREG0_ADRS, data);
+       udelay(10);
+}
+
+static void lcdtg_i2c_send_bit(u8 data)
+{
+       lcdtg_ssp_i2c_send(data);
+       lcdtg_ssp_i2c_send(data | POWER0_COM_DCLK);
+       lcdtg_ssp_i2c_send(data);
+}
+
+static void lcdtg_i2c_send_start(u8 base)
+{
+       lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK | POWER0_COM_DOUT);
+       lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK);
+       lcdtg_ssp_i2c_send(base);
+}
+
+static void lcdtg_i2c_send_stop(u8 base)
+{
+       lcdtg_ssp_i2c_send(base);
+       lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK);
+       lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK | POWER0_COM_DOUT);
+}
+
+static void lcdtg_i2c_send_byte(u8 base, u8 data)
+{
+       int i;
+       for (i = 0; i < 8; i++) {
+               if (data & 0x80)
+                       lcdtg_i2c_send_bit(base | POWER0_COM_DOUT);
+               else
+                       lcdtg_i2c_send_bit(base);
+               data <<= 1;
+       }
+}
+
+static void lcdtg_i2c_wait_ack(u8 base)
+{
+       lcdtg_i2c_send_bit(base);
+}
+
+static void lcdtg_set_common_voltage(u8 base_data, u8 data)
+{
+       /* Set Common Voltage to M62332FP via I2C */
+       lcdtg_i2c_send_start(base_data);
+       lcdtg_i2c_send_byte(base_data, 0x9c);
+       lcdtg_i2c_wait_ack(base_data);
+       lcdtg_i2c_send_byte(base_data, 0x00);
+       lcdtg_i2c_wait_ack(base_data);
+       lcdtg_i2c_send_byte(base_data, data);
+       lcdtg_i2c_wait_ack(base_data);
+       lcdtg_i2c_send_stop(base_data);
+}
+
+/* Set Phase Adjuct */
+static void lcdtg_set_phadadj(struct w100fb_par *par)
+{
+       int adj;
+       switch(par->xres) {
+               case 480:
+               case 640:
+                       /* Setting for VGA */
+                       adj = sharpsl_param.phadadj;
+                       if (adj < 0) {
+                               adj = PHACTRL_PHASE_MANUAL;
+                       } else {
+                               adj = ((adj & 0x0f) << 1) | PHACTRL_PHASE_MANUAL;
+                       }
+                       break;
+               case 240:
+               case 320:
+               default:
+                       /* Setting for QVGA */
+                       adj = (DEFAULT_PHAD_QVGA << 1) | PHACTRL_PHASE_MANUAL;
+                       break;
+       }
+
+       corgi_ssp_lcdtg_send(PHACTRL_ADRS, adj);
+}
+
+static int lcd_inited;
+
+static void lcdtg_hw_init(struct w100fb_par *par)
+{
+       if (!lcd_inited) {
+               int comadj;
+
+               /* Initialize Internal Logic & Port */
+               corgi_ssp_lcdtg_send(PICTRL_ADRS, PICTRL_POWER_DOWN | PICTRL_INIOFF | PICTRL_INIT_STATE
+                               | PICTRL_COM_SIGNAL_OFF | PICTRL_DAC_SIGNAL_OFF);
+
+               corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_OFF
+                               | POWER0_COM_OFF | POWER0_VCC5_OFF);
+
+               corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF);
+
+               /* VDD(+8V), SVSS(-4V) ON */
+               corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON);
+               mdelay(3);
+
+               /* DAC ON */
+               corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON
+                               | POWER0_COM_OFF | POWER0_VCC5_OFF);
+
+               /* INIB = H, INI = L  */
+               /* PICTL[0] = H , PICTL[1] = PICTL[2] = PICTL[4] = L */
+               corgi_ssp_lcdtg_send(PICTRL_ADRS, PICTRL_INIT_STATE | PICTRL_COM_SIGNAL_OFF);
+
+               /* Set Common Voltage */
+               comadj = sharpsl_param.comadj;
+               if (comadj < 0)
+                       comadj = DEFAULT_COMADJ;
+               lcdtg_set_common_voltage((POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF), comadj);
+
+               /* VCC5 ON, DAC ON */
+               corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON |
+                               POWER0_COM_OFF | POWER0_VCC5_ON);
+
+               /* GVSS(-8V) ON, VDD ON */
+               corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON);
+               mdelay(2);
+
+               /* COM SIGNAL ON (PICTL[3] = L) */
+               corgi_ssp_lcdtg_send(PICTRL_ADRS, PICTRL_INIT_STATE);
+
+               /* COM ON, DAC ON, VCC5_ON */
+               corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON
+                               | POWER0_COM_ON | POWER0_VCC5_ON);
+
+               /* VW ON, GVSS ON, VDD ON */
+               corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_ON | POWER1_GVSS_ON | POWER1_VDD_ON);
+
+               /* Signals output enable */
+               corgi_ssp_lcdtg_send(PICTRL_ADRS, 0);
+
+               /* Set Phase Adjuct */
+               lcdtg_set_phadadj(par);
+
+               /* Initialize for Input Signals from ATI */
+               corgi_ssp_lcdtg_send(POLCTRL_ADRS, POLCTRL_SYNC_POL_RISE | POLCTRL_EN_POL_RISE
+                               | POLCTRL_DATA_POL_RISE | POLCTRL_SYNC_ACT_L | POLCTRL_EN_ACT_H);
+               udelay(1000);
+
+               lcd_inited=1;
+       } else {
+               lcdtg_set_phadadj(par);
+       }
+
+       switch(par->xres) {
+               case 480:
+               case 640:
+                       /* Set Lcd Resolution (VGA) */
+                       corgi_ssp_lcdtg_send(RESCTL_ADRS, RESCTL_VGA);
+                       break;
+               case 240:
+               case 320:
+               default:
+                       /* Set Lcd Resolution (QVGA) */
+                       corgi_ssp_lcdtg_send(RESCTL_ADRS, RESCTL_QVGA);
+                       break;
+       }
+}
+
+static void lcdtg_suspend(struct w100fb_par *par)
+{
+       /* 60Hz x 2 frame = 16.7msec x 2 = 33.4 msec */
+       mdelay(34);
+
+       /* (1)VW OFF */
+       corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON);
+
+       /* (2)COM OFF */
+       corgi_ssp_lcdtg_send(PICTRL_ADRS, PICTRL_COM_SIGNAL_OFF);
+       corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON);
+
+       /* (3)Set Common Voltage Bias 0V */
+       lcdtg_set_common_voltage(POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON, 0);
+
+       /* (4)GVSS OFF */
+       corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON);
+
+       /* (5)VCC5 OFF */
+       corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF);
+
+       /* (6)Set PDWN, INIOFF, DACOFF */
+       corgi_ssp_lcdtg_send(PICTRL_ADRS, PICTRL_INIOFF | PICTRL_DAC_SIGNAL_OFF |
+                       PICTRL_POWER_DOWN | PICTRL_COM_SIGNAL_OFF);
+
+       /* (7)DAC OFF */
+       corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_DAC_OFF | POWER0_COM_OFF | POWER0_VCC5_OFF);
+
+       /* (8)VDD OFF */
+       corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF);
+
+       lcd_inited = 0;
+}
+
+static struct w100_tg_info corgi_lcdtg_info = {
+       .change=lcdtg_hw_init,
+       .suspend=lcdtg_suspend,
+       .resume=lcdtg_hw_init,
+};
+
+/*
+ * Corgi w100 Frame Buffer Device
+ */
+
+static struct w100_mem_info corgi_fb_mem = {
+       .ext_cntl          = 0x00040003,
+       .sdram_mode_reg    = 0x00650021,
+       .ext_timing_cntl   = 0x10002a4a,
+       .io_cntl           = 0x7ff87012,
+       .size              = 0x1fffff,
+};
+
+static struct w100_gen_regs corgi_fb_regs = {
+       .lcd_format    = 0x00000003,
+       .lcdd_cntl1    = 0x01CC0000,
+       .lcdd_cntl2    = 0x0003FFFF,
+       .genlcd_cntl1  = 0x00FFFF0D,
+       .genlcd_cntl2  = 0x003F3003,
+       .genlcd_cntl3  = 0x000102aa,
+};
+
+static struct w100_gpio_regs corgi_fb_gpio = {
+       .init_data1   = 0x000000bf,
+       .init_data2   = 0x00000000,
+       .gpio_dir1    = 0x00000000,
+       .gpio_oe1     = 0x03c0feff,
+       .gpio_dir2    = 0x00000000,
+       .gpio_oe2     = 0x00000000,
+};
+
+static struct w100_mode corgi_fb_modes[] = {
+{
+       .xres            = 480,
+       .yres            = 640,
+       .left_margin     = 0x56,
+       .right_margin    = 0x55,
+       .upper_margin    = 0x03,
+       .lower_margin    = 0x00,
+       .crtc_ss         = 0x82360056,
+       .crtc_ls         = 0xA0280000,
+       .crtc_gs         = 0x80280028,
+       .crtc_vpos_gs    = 0x02830002,
+       .crtc_rev        = 0x00400008,
+       .crtc_dclk       = 0xA0000000,
+       .crtc_gclk       = 0x8015010F,
+       .crtc_goe        = 0x80100110,
+       .crtc_ps1_active = 0x41060010,
+       .pll_freq        = 75,
+       .fast_pll_freq   = 100,
+       .sysclk_src      = CLK_SRC_PLL,
+       .sysclk_divider  = 0,
+       .pixclk_src      = CLK_SRC_PLL,
+       .pixclk_divider  = 2,
+       .pixclk_divider_rotated = 6,
+},{
+       .xres            = 240,
+       .yres            = 320,
+       .left_margin     = 0x27,
+       .right_margin    = 0x2e,
+       .upper_margin    = 0x01,
+       .lower_margin    = 0x00,
+       .crtc_ss         = 0x81170027,
+       .crtc_ls         = 0xA0140000,
+       .crtc_gs         = 0xC0140014,
+       .crtc_vpos_gs    = 0x00010141,
+       .crtc_rev        = 0x00400008,
+       .crtc_dclk       = 0xA0000000,
+       .crtc_gclk       = 0x8015010F,
+       .crtc_goe        = 0x80100110,
+       .crtc_ps1_active = 0x41060010,
+       .pll_freq        = 0,
+       .fast_pll_freq   = 0,
+       .sysclk_src      = CLK_SRC_XTAL,
+       .sysclk_divider  = 0,
+       .pixclk_src      = CLK_SRC_XTAL,
+       .pixclk_divider  = 1,
+       .pixclk_divider_rotated = 1,
+},
+
+};
+
+static struct w100fb_mach_info corgi_fb_info = {
+       .tg         = &corgi_lcdtg_info,
+       .init_mode  = INIT_MODE_ROTATED,
+       .mem        = &corgi_fb_mem,
+       .regs       = &corgi_fb_regs,
+       .modelist   = &corgi_fb_modes[0],
+       .num_modes  = 2,
+       .gpio       = &corgi_fb_gpio,
+       .xtal_freq  = 12500000,
+       .xtal_dbl   = 0,
+};
+
+static struct resource corgi_fb_resources[] = {
+       [0] = {
+               .start   = 0x08000000,
+               .end     = 0x08ffffff,
+               .flags   = IORESOURCE_MEM,
+       },
+};
+
+struct platform_device corgifb_device = {
+       .name           = "w100fb",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(corgi_fb_resources),
+       .resource       = corgi_fb_resources,
+       .dev            = {
+               .platform_data = &corgi_fb_info,
+               .parent = &corgissp_device.dev,
+       },
+
+};
index f3cac43124a51627acdd3f7ce86ca404f0d747ca..539b596005fc266b2c49f8d0edfa22d7758b1b13 100644 (file)
@@ -133,7 +133,7 @@ static struct irqchip pxa_low_gpio_chip = {
        .ack            = pxa_ack_low_gpio,
        .mask           = pxa_mask_low_irq,
        .unmask         = pxa_unmask_low_irq,
-       .type           = pxa_gpio_irq_type,
+       .set_type       = pxa_gpio_irq_type,
 };
 
 /*
@@ -157,7 +157,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc,
                        mask >>= 2;
                        do {
                                if (mask & 1)
-                                       desc->handle(irq, desc, regs);
+                                       desc_handle_irq(irq, desc, regs);
                                irq++;
                                desc++;
                                mask >>= 1;
@@ -172,7 +172,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc,
                        desc = irq_desc + irq;
                        do {
                                if (mask & 1)
-                                       desc->handle(irq, desc, regs);
+                                       desc_handle_irq(irq, desc, regs);
                                irq++;
                                desc++;
                                mask >>= 1;
@@ -187,7 +187,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc,
                        desc = irq_desc + irq;
                        do {
                                if (mask & 1)
-                                       desc->handle(irq, desc, regs);
+                                       desc_handle_irq(irq, desc, regs);
                                irq++;
                                desc++;
                                mask >>= 1;
@@ -203,7 +203,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc,
                        desc = irq_desc + irq;
                        do {
                                if (mask & 1)
-                                       desc->handle(irq, desc, regs);
+                                       desc_handle_irq(irq, desc, regs);
                                irq++;
                                desc++;
                                mask >>= 1;
@@ -241,7 +241,7 @@ static struct irqchip pxa_muxed_gpio_chip = {
        .ack            = pxa_ack_muxed_gpio,
        .mask           = pxa_mask_muxed_gpio,
        .unmask         = pxa_unmask_muxed_gpio,
-       .type           = pxa_gpio_irq_type,
+       .set_type       = pxa_gpio_irq_type,
 };
 
 
index 6309853b59bef49deafd753b6166ceea032e7d8e..923f6eb774c0c80a7e54a5bc7b9cfc45730437f7 100644 (file)
@@ -84,7 +84,7 @@ static void lubbock_irq_handler(unsigned int irq, struct irqdesc *desc,
                if (likely(pending)) {
                        irq = LUBBOCK_IRQ(0) + __ffs(pending);
                        desc = irq_desc + irq;
-                       desc->handle(irq, desc, regs);
+                       desc_handle_irq(irq, desc, regs);
                }
                pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
        } while (pending);
index 827b7b5a5be84438e2f3ceb55c6603198dfee23e..85fdb5b1470a140faa2e5b6a1d9fd02612ac337d 100644 (file)
@@ -72,7 +72,7 @@ static void mainstone_irq_handler(unsigned int irq, struct irqdesc *desc,
                if (likely(pending)) {
                        irq = MAINSTONE_IRQ(0) + __ffs(pending);
                        desc = irq_desc + irq;
-                       desc->handle(irq, desc, regs);
+                       desc_handle_irq(irq, desc, regs);
                }
                pending = MST_INTSETCLR & mainstone_irq_enabled;
        } while (pending);
index 0e4f6fab100a5456cb2d4bef67aa7ea5e7eb3109..47cfb8bb8318abc4812f7ca56a6a339c0645a3da 100644 (file)
@@ -62,6 +62,15 @@ struct platform_device poodle_scoop_device = {
        .resource       = poodle_scoop_resources,
 };
 
+static struct scoop_pcmcia_dev poodle_pcmcia_scoop[] = {
+{
+       .dev        = &poodle_scoop_device.dev,
+       .irq        = POODLE_IRQ_GPIO_CF_IRQ,
+       .cd_irq     = POODLE_IRQ_GPIO_CF_CD,
+       .cd_irq_str = "PCMCIA0 CD",
+},
+};
+
 
 /* LoCoMo device */
 static struct resource locomo_resources[] = {
@@ -147,6 +156,9 @@ static void __init poodle_init(void)
 
        set_pxa_fb_info(&poodle_fb_info);
 
+       scoop_num = 1;
+       scoop_devs = &poodle_pcmcia_scoop[0];
+
        ret = platform_add_devices(devices, ARRAY_SIZE(devices));
        if (ret) {
                printk(KERN_WARNING "poodle: Unable to register LoCoMo device\n");
index 6e5202154f911321a82e53e0b93d716726b57d5e..7dad3f1465e076028954b1f18169ed8b82b2502e 100644 (file)
@@ -70,6 +70,11 @@ static unsigned long pxa_gettimeoffset (void)
        return usec;
 }
 
+#ifdef CONFIG_NO_IDLE_HZ
+static unsigned long initial_match;
+static int match_posponed;
+#endif
+
 static irqreturn_t
 pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -77,11 +82,19 @@ pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
        write_seqlock(&xtime_lock);
 
+#ifdef CONFIG_NO_IDLE_HZ
+       if (match_posponed) {
+               match_posponed = 0;
+               OSMR0 = initial_match;
+       }
+#endif
+
        /* Loop until we get ahead of the free running timer.
         * This ensures an exact clock tick count and time accuracy.
-        * IRQs are disabled inside the loop to ensure coherence between
-        * lost_ticks (updated in do_timer()) and the match reg value, so we
-        * can use do_gettimeofday() from interrupt handlers.
+        * Since IRQs are disabled at this point, coherence between
+        * lost_ticks(updated in do_timer()) and the match reg value is
+        * ensured, hence we can use do_gettimeofday() from interrupt
+        * handlers.
         *
         * HACK ALERT: it seems that the PXA timer regs aren't updated right
         * away in all cases when a write occurs.  We therefore compare with
@@ -126,6 +139,42 @@ static void __init pxa_timer_init(void)
        OSCR = 0;               /* initialize free-running timer, force first match */
 }
 
+#ifdef CONFIG_NO_IDLE_HZ
+static int pxa_dyn_tick_enable_disable(void)
+{
+       /* nothing to do */
+       return 0;
+}
+
+static void pxa_dyn_tick_reprogram(unsigned long ticks)
+{
+       if (ticks > 1) {
+               initial_match = OSMR0;
+               OSMR0 = initial_match + ticks * LATCH;
+               match_posponed = 1;
+       }
+}
+
+static irqreturn_t
+pxa_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+       if (match_posponed) {
+               match_posponed = 0;
+               OSMR0 = initial_match;
+               if ( (signed long)(initial_match - OSCR) <= 8 )
+                       return pxa_timer_interrupt(irq, dev_id, regs);
+       }
+       return IRQ_NONE;
+}
+
+static struct dyn_tick_timer pxa_dyn_tick = {
+       .enable         = pxa_dyn_tick_enable_disable,
+       .disable        = pxa_dyn_tick_enable_disable,
+       .reprogram      = pxa_dyn_tick_reprogram,
+       .handler        = pxa_dyn_tick_handler,
+};
+#endif
+
 #ifdef CONFIG_PM
 static unsigned long osmr[4], oier;
 
@@ -161,4 +210,7 @@ struct sys_timer pxa_timer = {
        .suspend        = pxa_timer_suspend,
        .resume         = pxa_timer_resume,
        .offset         = pxa_gettimeoffset,
+#ifdef CONFIG_NO_IDLE_HZ
+       .dyn_tick       = &pxa_dyn_tick,
+#endif
 };
index d4d03d0daaecdecc053b0cb04c033a20f5189d2d..06807c6ee68aa7d4cc15d22c674e31a32c80285a 100644 (file)
@@ -2,6 +2,13 @@ if ARCH_S3C2410
 
 menu "S3C24XX Implementations"
 
+config MACH_ANUBIS
+       bool "Simtec Electronics ANUBIS"
+       select CPU_S3C2440
+       help
+         Say Y gere if you are using the Simtec Electronics ANUBIS
+         development system
+
 config ARCH_BAST
        bool "Simtec Electronics BAST (EB2410ITX)"
        select CPU_S3C2410
@@ -11,6 +18,14 @@ config ARCH_BAST
 
          Product page: <http://www.simtec.co.uk/products/EB2410ITX/>.
 
+config BAST_PC104_IRQ
+       bool "BAST PC104 IRQ support"
+       depends on ARCH_BAST
+       default y
+       help
+         Say Y here to enable the PC104 IRQ routing on the
+         Simtec BAST (EB2410ITX)
+
 config ARCH_H1940
        bool "IPAQ H1940"
        select CPU_S3C2410
index 55ed7c7e57dabc091c9f6dd5c28f8bfa3ffd9b3b..b4f1e051c768a4dc06d583cdc52da5445e9fb190 100644 (file)
@@ -26,8 +26,13 @@ obj-$(CONFIG_CPU_S3C2440)  += s3c2440.o s3c2440-dsc.o
 obj-$(CONFIG_CPU_S3C2440)  += s3c2440-irq.o
 obj-$(CONFIG_CPU_S3C2440)  += s3c2440-clock.o
 
+# bast extras
+
+obj-$(CONFIG_BAST_PC104_IRQ)   += bast-irq.o
+
 # machine specific support
 
+obj-$(CONFIG_MACH_ANUBIS)      += mach-anubis.o
 obj-$(CONFIG_ARCH_BAST)                += mach-bast.o usb-simtec.o
 obj-$(CONFIG_ARCH_H1940)       += mach-h1940.o
 obj-$(CONFIG_MACH_N30)         += mach-n30.o
index 5e5bbe893cbb7f61fc620896b3a50c0164fdd71e..fbbeb05530061eaf24089f3e62acea6d078edad7 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s3c2410/bast-irq.c
  *
- * Copyright (c) 2004 Simtec Electronics
+ * Copyright (c) 2003,2005 Simtec Electronics
  *   Ben Dooks <ben@simtec.co.uk>
  *
  * http://www.simtec.co.uk/products/EB2410ITX/
@@ -21,7 +21,8 @@
  *
  * Modifications:
  *     08-Jan-2003 BJD  Moved from central IRQ code
- */
+ *     21-Aug-2005 BJD  Fixed missing code and compile errors
+*/
 
 
 #include <linux/init.h>
 #include <linux/ptrace.h>
 #include <linux/sysdev.h>
 
+#include <asm/mach-types.h>
+
 #include <asm/hardware.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
 #include <asm/mach/irq.h>
-#include <asm/hardware/s3c2410/irq.h>
+
+#include <asm/arch/regs-irq.h>
+#include <asm/arch/bast-map.h>
+#include <asm/arch/bast-irq.h>
+
+#include "irq.h"
 
 #if 0
 #include <asm/debug-ll.h>
@@ -79,15 +87,15 @@ bast_pc104_mask(unsigned int irqno)
        temp = __raw_readb(BAST_VA_PC104_IRQMASK);
        temp &= ~bast_pc104_irqmasks[irqno];
        __raw_writeb(temp, BAST_VA_PC104_IRQMASK);
-
-       if (temp == 0)
-               bast_extint_mask(IRQ_ISA);
 }
 
 static void
-bast_pc104_ack(unsigned int irqno)
+bast_pc104_maskack(unsigned int irqno)
 {
-       bast_extint_ack(IRQ_ISA);
+       struct irqdesc *desc = irq_desc + IRQ_ISA;
+
+       bast_pc104_mask(irqno);
+       desc->chip->ack(IRQ_ISA);
 }
 
 static void
@@ -98,14 +106,12 @@ bast_pc104_unmask(unsigned int irqno)
        temp = __raw_readb(BAST_VA_PC104_IRQMASK);
        temp |= bast_pc104_irqmasks[irqno];
        __raw_writeb(temp, BAST_VA_PC104_IRQMASK);
-
-       bast_extint_unmask(IRQ_ISA);
 }
 
-static struct bast_pc104_chip = {
+static struct irqchip  bast_pc104_chip = {
        .mask        = bast_pc104_mask,
        .unmask      = bast_pc104_unmask,
-       .ack         = bast_pc104_ack
+       .ack         = bast_pc104_maskack
 };
 
 static void
@@ -119,14 +125,49 @@ bast_irq_pc104_demux(unsigned int irq,
 
        stat = __raw_readb(BAST_VA_PC104_IRQREQ) & 0xf;
 
-       for (i = 0; i < 4 && stat != 0; i++) {
-               if (stat & 1) {
-                       irqno = bast_pc104_irqs[i];
-                       desc = irq_desc + irqno;
+       if (unlikely(stat == 0)) {
+               /* ack if we get an irq with nothing (ie, startup) */
+
+               desc = irq_desc + IRQ_ISA;
+               desc->chip->ack(IRQ_ISA);
+       } else {
+               /* handle the IRQ */
+
+               for (i = 0; stat != 0; i++, stat >>= 1) {
+                       if (stat & 1) {
+                               irqno = bast_pc104_irqs[i];
 
-                       desc->handle(irqno, desc, regs);
+                               desc_handle_irq(irqno, irq_desc + irqno, regs);
+                       }
                }
+       }
+}
 
-               stat >>= 1;
+static __init int bast_irq_init(void)
+{
+       unsigned int i;
+
+       if (machine_is_bast()) {
+               printk(KERN_INFO "BAST PC104 IRQ routing, (c) 2005 Simtec Electronics\n");
+
+               /* zap all the IRQs */
+
+               __raw_writeb(0x0, BAST_VA_PC104_IRQMASK);
+
+               set_irq_chained_handler(IRQ_ISA, bast_irq_pc104_demux);
+
+               /* reigster our IRQs */
+
+               for (i = 0; i < 4; i++) {
+                       unsigned int irqno = bast_pc104_irqs[i];
+
+                       set_irq_chip(irqno, &bast_pc104_chip);
+                       set_irq_handler(irqno, do_level_IRQ);
+                       set_irq_flags(irqno, IRQF_VALID);
+               }
        }
+
+       return 0;
 }
+
+arch_initcall(bast_irq_init);
index 9a66050e887d0e99db09d53d1ab91bda120f6353..f59608268751f6769a920c49b73b75fa8ab1fce4 100644 (file)
@@ -388,6 +388,7 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
                                unsigned long hclk,
                                unsigned long pclk)
 {
+       unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
        struct clk *clkp = init_clocks;
        int ptr;
        int ret;
@@ -446,5 +447,13 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
                }
        }
 
+       /* show the clock-slow value */
+
+       printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n",
+              print_mhz(xtal / ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))),
+              (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast",
+              (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
+              (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
+
        return 0;
 }
index 973a5fe6769c515d87c6f409b36223fdd93d05a6..66d8c068e940b9436693361f7bdd5dc5f941bc6e 100644 (file)
@@ -184,14 +184,14 @@ struct irqchip s3c_irq_level_chip = {
        .ack       = s3c_irq_maskack,
        .mask      = s3c_irq_mask,
        .unmask    = s3c_irq_unmask,
-       .wake      = s3c_irq_wake
+       .set_wake          = s3c_irq_wake
 };
 
 static struct irqchip s3c_irq_chip = {
        .ack       = s3c_irq_ack,
        .mask      = s3c_irq_mask,
        .unmask    = s3c_irq_unmask,
-       .wake      = s3c_irq_wake
+       .set_wake          = s3c_irq_wake
 };
 
 /* S3C2410_EINTMASK
@@ -350,16 +350,16 @@ static struct irqchip s3c_irqext_chip = {
        .mask       = s3c_irqext_mask,
        .unmask     = s3c_irqext_unmask,
        .ack        = s3c_irqext_ack,
-       .type       = s3c_irqext_type,
-       .wake       = s3c_irqext_wake
+       .set_type    = s3c_irqext_type,
+       .set_wake    = s3c_irqext_wake
 };
 
 static struct irqchip s3c_irq_eint0t4 = {
        .ack       = s3c_irq_ack,
        .mask      = s3c_irq_mask,
        .unmask    = s3c_irq_unmask,
-       .wake      = s3c_irq_wake,
-       .type      = s3c_irqext_type,
+       .set_wake  = s3c_irq_wake,
+       .set_type  = s3c_irqext_type,
 };
 
 /* mask values for the parent registers for each of the interrupt types */
@@ -496,11 +496,11 @@ static void s3c_irq_demux_adc(unsigned int irq,
        if (subsrc != 0) {
                if (subsrc & 1) {
                        mydesc = irq_desc + IRQ_TC;
-                       mydesc->handle( IRQ_TC, mydesc, regs);
+                       desc_handle_irq(IRQ_TC, mydesc, regs);
                }
                if (subsrc & 2) {
                        mydesc = irq_desc + IRQ_ADC;
-                       mydesc->handle(IRQ_ADC, mydesc, regs);
+                       desc_handle_irq(IRQ_ADC, mydesc, regs);
                }
        }
 }
@@ -529,17 +529,17 @@ static void s3c_irq_demux_uart(unsigned int start,
                desc = irq_desc + start;
 
                if (subsrc & 1)
-                       desc->handle(start, desc, regs);
+                       desc_handle_irq(start, desc, regs);
 
                desc++;
 
                if (subsrc & 2)
-                       desc->handle(start+1, desc, regs);
+                       desc_handle_irq(start+1, desc, regs);
 
                desc++;
 
                if (subsrc & 4)
-                       desc->handle(start+2, desc, regs);
+                       desc_handle_irq(start+2, desc, regs);
        }
 }
 
diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2410/mach-anubis.c
new file mode 100644 (file)
index 0000000..f87aa0b
--- /dev/null
@@ -0,0 +1,270 @@
+/* linux/arch/arm/mach-s3c2410/mach-anubis.c
+ *
+ * Copyright (c) 2003-2005 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Modifications:
+ *     02-May-2005 BJD  Copied from mach-bast.c
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/anubis-map.h>
+#include <asm/arch/anubis-irq.h>
+#include <asm/arch/anubis-cpld.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-mem.h>
+#include <asm/arch/regs-lcd.h>
+#include <asm/arch/nand.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include "clock.h"
+#include "devs.h"
+#include "cpu.h"
+
+#define COPYRIGHT ", (c) 2005 Simtec Electronics"
+
+static struct map_desc anubis_iodesc[] __initdata = {
+  /* ISA IO areas */
+
+  { (u32)S3C24XX_VA_ISA_BYTE, 0x0,        SZ_16M, MT_DEVICE },
+  { (u32)S3C24XX_VA_ISA_WORD, 0x0,        SZ_16M, MT_DEVICE },
+
+  /* we could possibly compress the next set down into a set of smaller tables
+   * pagetables, but that would mean using an L2 section, and it still means
+   * we cannot actually feed the same register to an LDR due to 16K spacing
+   */
+
+  /* CPLD control registers */
+
+  { (u32)ANUBIS_VA_CTRL1,      ANUBIS_PA_CTRL1,        SZ_4K, MT_DEVICE },
+  { (u32)ANUBIS_VA_CTRL2,      ANUBIS_PA_CTRL2,        SZ_4K, MT_DEVICE },
+
+  /* IDE drives */
+
+  { (u32)ANUBIS_IDEPRI,                S3C2410_CS3,            SZ_1M, MT_DEVICE },
+  { (u32)ANUBIS_IDEPRIAUX,     S3C2410_CS3+(1<<26),    SZ_1M, MT_DEVICE },
+
+  { (u32)ANUBIS_IDESEC,                S3C2410_CS4,            SZ_1M, MT_DEVICE },
+  { (u32)ANUBIS_IDESECAUX,     S3C2410_CS4+(1<<26),    SZ_1M, MT_DEVICE },
+};
+
+#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c24xx_uart_clksrc anubis_serial_clocks[] = {
+       [0] = {
+               .name           = "uclk",
+               .divisor        = 1,
+               .min_baud       = 0,
+               .max_baud       = 0,
+       },
+       [1] = {
+               .name           = "pclk",
+               .divisor        = 1,
+               .min_baud       = 0,
+               .max_baud       = 0.
+       }
+};
+
+
+static struct s3c2410_uartcfg anubis_uartcfgs[] = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+               .clocks      = anubis_serial_clocks,
+               .clocks_size = ARRAY_SIZE(anubis_serial_clocks)
+       },
+       [1] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+               .clocks      = anubis_serial_clocks,
+               .clocks_size = ARRAY_SIZE(anubis_serial_clocks)
+       },
+};
+
+/* NAND Flash on Anubis board */
+
+static int external_map[]   = { 2 };
+static int chip0_map[]      = { 0 };
+static int chip1_map[]      = { 1 };
+
+struct mtd_partition anubis_default_nand_part[] = {
+       [0] = {
+               .name   = "Boot Agent",
+               .size   = SZ_16K,
+               .offset = 0
+       },
+       [1] = {
+               .name   = "/boot",
+               .size   = SZ_4M - SZ_16K,
+               .offset = SZ_16K,
+       },
+       [2] = {
+               .name   = "user1",
+               .offset = SZ_4M,
+               .size   = SZ_32M - SZ_4M,
+       },
+       [3] = {
+               .name   = "user2",
+               .offset = SZ_32M,
+               .size   = MTDPART_SIZ_FULL,
+       }
+};
+
+/* the Anubis has 3 selectable slots for nand-flash, the two
+ * on-board chip areas, as well as the external slot.
+ *
+ * Note, there is no current hot-plug support for the External
+ * socket.
+*/
+
+static struct s3c2410_nand_set anubis_nand_sets[] = {
+       [1] = {
+               .name           = "External",
+               .nr_chips       = 1,
+               .nr_map         = external_map,
+               .nr_partitions  = ARRAY_SIZE(anubis_default_nand_part),
+               .partitions     = anubis_default_nand_part
+       },
+       [0] = {
+               .name           = "chip0",
+               .nr_chips       = 1,
+               .nr_map         = chip0_map,
+               .nr_partitions  = ARRAY_SIZE(anubis_default_nand_part),
+               .partitions     = anubis_default_nand_part
+       },
+       [2] = {
+               .name           = "chip1",
+               .nr_chips       = 1,
+               .nr_map         = chip1_map,
+               .nr_partitions  = ARRAY_SIZE(anubis_default_nand_part),
+               .partitions     = anubis_default_nand_part
+       },
+};
+
+static void anubis_nand_select(struct s3c2410_nand_set *set, int slot)
+{
+       unsigned int tmp;
+
+       slot = set->nr_map[slot] & 3;
+
+       pr_debug("anubis_nand: selecting slot %d (set %p,%p)\n",
+                slot, set, set->nr_map);
+
+       tmp = __raw_readb(ANUBIS_VA_CTRL1);
+       tmp &= ~ANUBIS_CTRL1_NANDSEL;
+       tmp |= slot;
+
+       pr_debug("anubis_nand: ctrl1 now %02x\n", tmp);
+
+       __raw_writeb(tmp, ANUBIS_VA_CTRL1);
+}
+
+static struct s3c2410_platform_nand anubis_nand_info = {
+       .tacls          = 25,
+       .twrph0         = 80,
+       .twrph1         = 80,
+       .nr_sets        = ARRAY_SIZE(anubis_nand_sets),
+       .sets           = anubis_nand_sets,
+       .select_chip    = anubis_nand_select,
+};
+
+
+/* Standard Anubis devices */
+
+static struct platform_device *anubis_devices[] __initdata = {
+       &s3c_device_usb,
+       &s3c_device_wdt,
+       &s3c_device_adc,
+       &s3c_device_i2c,
+       &s3c_device_rtc,
+       &s3c_device_nand,
+};
+
+static struct clk *anubis_clocks[] = {
+       &s3c24xx_dclk0,
+       &s3c24xx_dclk1,
+       &s3c24xx_clkout0,
+       &s3c24xx_clkout1,
+       &s3c24xx_uclk,
+};
+
+static struct s3c24xx_board anubis_board __initdata = {
+       .devices       = anubis_devices,
+       .devices_count = ARRAY_SIZE(anubis_devices),
+       .clocks        = anubis_clocks,
+       .clocks_count  = ARRAY_SIZE(anubis_clocks)
+};
+
+void __init anubis_map_io(void)
+{
+       /* initialise the clocks */
+
+       s3c24xx_dclk0.parent = NULL;
+       s3c24xx_dclk0.rate   = 12*1000*1000;
+
+       s3c24xx_dclk1.parent = NULL;
+       s3c24xx_dclk1.rate   = 24*1000*1000;
+
+       s3c24xx_clkout0.parent  = &s3c24xx_dclk0;
+       s3c24xx_clkout1.parent  = &s3c24xx_dclk1;
+
+       s3c24xx_uclk.parent  = &s3c24xx_clkout1;
+
+       s3c_device_nand.dev.platform_data = &anubis_nand_info;
+
+       s3c24xx_init_io(anubis_iodesc, ARRAY_SIZE(anubis_iodesc));
+       s3c24xx_init_clocks(0);
+       s3c24xx_init_uarts(anubis_uartcfgs, ARRAY_SIZE(anubis_uartcfgs));
+       s3c24xx_set_board(&anubis_board);
+
+       /* ensure that the GPIO is setup */
+       s3c2410_gpio_setpin(S3C2410_GPA0, 1);
+}
+
+MACHINE_START(ANUBIS, "Simtec-Anubis")
+       /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
+       .phys_ram       = S3C2410_SDRAM_PA,
+       .phys_io        = S3C2410_PA_UART,
+       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
+       .boot_params    = S3C2410_SDRAM_PA + 0x100,
+       .map_io         = anubis_map_io,
+       .init_irq       = s3c24xx_init_irq,
+       .timer          = &s3c24xx_timer,
+MACHINE_END
index 79044d9bce38c281644c70a94a5ffd58348dcbda..66bf5bb2b3db2a2b18120379e098496a2700decc 100644 (file)
@@ -110,34 +110,24 @@ void __init n30_init_irq(void)
        s3c24xx_init_irq();
 }
 
-
-static int n30_usbstart_thread(void *unused)
-{
-       /* Turn off suspend on both USB ports, and switch the
-        * selectable USB port to USB device mode. */
-       writel(readl(S3C2410_MISCCR) & ~0x00003008, S3C2410_MISCCR);
-
-       /* Turn off the D+ pull up for 3 seconds so that the USB host
-        * at the other end will do a rescan of the USB bus.  */
-       s3c2410_gpio_setpin(S3C2410_GPB3, 0);
-
-       msleep_interruptible(3*HZ);
-
-       s3c2410_gpio_setpin(S3C2410_GPB3, 1);
-
-       return 0;
-}
-
+/* GPB3 is the line that controls the pull-up for the USB D+ line */
 
 void __init n30_init(void)
 {
        s3c_device_i2c.dev.platform_data = &n30_i2ccfg;
 
-       kthread_run(n30_usbstart_thread, NULL, "n30_usbstart");
+       /* Turn off suspend on both USB ports, and switch the
+        * selectable USB port to USB device mode. */
+
+       s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
+                             S3C2410_MISCCR_USBSUSPND0 |
+                             S3C2410_MISCCR_USBSUSPND1, 0x0);
 }
 
 MACHINE_START(N30, "Acer-N30")
-       /* Maintainer: Christer Weinigel <christer@weinigel.se>, Ben Dooks <ben-linux@fluff.org> */
+       /* Maintainer: Christer Weinigel <christer@weinigel.se>,
+                               Ben Dooks <ben-linux@fluff.org>
+       */
        .phys_ram       = S3C2410_SDRAM_PA,
        .phys_io        = S3C2410_PA_UART,
        .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
index 2cb798832223ad9d69c9c0c7feed90f3d48dbc70..4c7ccef6c207d0d2ba67349445324c1b87c2974a 100644 (file)
@@ -48,7 +48,7 @@ static __init int pm_simtec_init(void)
 
        /* check which machine we are running on */
 
-       if (!machine_is_bast() && !machine_is_vr1000())
+       if (!machine_is_bast() && !machine_is_vr1000() && !machine_is_anubis())
                return 0;
 
        printk(KERN_INFO "Simtec Board Power Manangement" COPYRIGHT "\n");
index 13a48ee7748434814fc5b325a24a61d52b8dafe7..fe57d966a34d126b62194950ea10882f6c3a20fc 100644 (file)
@@ -585,14 +585,16 @@ static int s3c2410_pm_enter(suspend_state_t state)
 
        s3c2410_pm_check_store();
 
-       // need to make some form of time-delta
-
        /* send the cpu to sleep... */
 
        __raw_writel(0x00, S3C2410_CLKCON);  /* turn off clocks over sleep */
 
        s3c2410_cpu_suspend(regs_save);
 
+       /* restore the cpu state */
+
+       cpu_init();
+
        /* unset the return-from-sleep flag, to ensure reset */
 
        tmp = __raw_readl(S3C2410_GSTATUS2);
index b018a1f680cef41c83b461f1a0b28c4203b91dc0..c67e0979aec38476635be1f2a9e990079c4c6082 100644 (file)
@@ -68,6 +68,7 @@ static struct clk s3c2440_clk_ac97 = {
 static int s3c2440_clk_add(struct sys_device *sysdev)
 {
        unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
+       unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
        struct clk *clk_h;
        struct clk *clk_p;
        struct clk *clk_xtal;
@@ -80,8 +81,9 @@ static int s3c2440_clk_add(struct sys_device *sysdev)
 
        s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal->rate);
 
-       printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz\n",
-              print_mhz(s3c2440_clk_upll.rate));
+       printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz, DVS %s\n",
+              print_mhz(s3c2440_clk_upll.rate),
+              (camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off");
 
        clk_p = clk_get(NULL, "pclk");
        clk_h = clk_get(NULL, "hclk");
index 7cb9912242a3964b66c3e686bb5688595c3e4e5c..278d0044c85d7c3315e46363094c3c125bb85dfe 100644 (file)
@@ -64,11 +64,11 @@ static void s3c_irq_demux_wdtac97(unsigned int irq,
        if (subsrc != 0) {
                if (subsrc & 1) {
                        mydesc = irq_desc + IRQ_S3C2440_WDT;
-                       mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs);
+                       desc_handle_irq(IRQ_S3C2440_WDT, mydesc, regs);
                }
                if (subsrc & 2) {
                        mydesc = irq_desc + IRQ_S3C2440_AC97;
-                       mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs);
+                       desc_handle_irq(IRQ_S3C2440_AC97, mydesc, regs);
                }
        }
 }
@@ -122,11 +122,11 @@ static void s3c_irq_demux_cam(unsigned int irq,
        if (subsrc != 0) {
                if (subsrc & 1) {
                        mydesc = irq_desc + IRQ_S3C2440_CAM_C;
-                       mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs);
+                       desc_handle_irq(IRQ_S3C2440_CAM_C, mydesc, regs);
                }
                if (subsrc & 2) {
                        mydesc = irq_desc + IRQ_S3C2440_CAM_P;
-                       mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs);
+                       desc_handle_irq(IRQ_S3C2440_CAM_P, mydesc, regs);
                }
        }
 }
index 765a3a9ae032581b7f6c97217807fb8bc9cdc014..c0acfb2ad790a711c877afda5195be642288f690 100644 (file)
@@ -164,7 +164,7 @@ static void s3c2410_timer_setup (void)
 
        /* configure the system for whichever machine is in use */
 
-       if (machine_is_bast() || machine_is_vr1000()) {
+       if (machine_is_bast() || machine_is_vr1000() || machine_is_anubis()) {
                /* timer is at 12MHz, scaler is 1 */
                timer_usec_ticks = timer_mask_usec_ticks(1, 12000000);
                tcnt = 12000000 / HZ;
index 4d4d303ee3a8003bdbd4e5f48a8a04480fadfd1e..24687f511bf53c9bf74ee4d55a332a61a690f162 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
 #include <asm/arch/assabet.h>
+#include <asm/arch/mcp.h>
 
 #include "generic.h"
 
@@ -198,6 +199,11 @@ static struct irda_platform_data assabet_irda_data = {
        .set_speed      = assabet_irda_set_speed,
 };
 
+static struct mcp_plat_data assabet_mcp_data = {
+       .mccr0          = MCCR0_ADM,
+       .sclk_rate      = 11981000,
+};
+
 static void __init assabet_init(void)
 {
        /*
@@ -246,6 +252,7 @@ static void __init assabet_init(void)
        sa11x0_set_flash_data(&assabet_flash_data, assabet_flash_resources,
                              ARRAY_SIZE(assabet_flash_resources));
        sa11x0_set_irda_data(&assabet_irda_data);
+       sa11x0_set_mcp_data(&assabet_mcp_data);
 }
 
 /*
index 0aa918e24c3123c26caa928a7683aa4e5d45bf9d..9484be7dc671a0ada6bb834ea480b48b73ff6863 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/mach/serial_sa1100.h>
 
 #include <asm/arch/cerf.h>
+#include <asm/arch/mcp.h>
 #include "generic.h"
 
 static struct resource cerfuart2_resources[] = {
@@ -116,10 +117,16 @@ static void __init cerf_map_io(void)
        GPDR |= CERF_GPIO_CF_RESET;
 }
 
+static struct mcp_plat_data cerf_mcp_data = {
+       .mccr0          = MCCR0_ADM,
+       .sclk_rate      = 11981000,
+};
+
 static void __init cerf_init(void)
 {
        platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices));
        sa11x0_set_flash_data(&cerf_flash_data, &cerf_flash_resource, 1);
+       sa11x0_set_mcp_data(&cerf_mcp_data);
 }
 
 MACHINE_START(CERF, "Intrinsyc CerfBoard/CerfCube")
index 95ae217be1bc06a485d29764c1507f6d50eac9a9..3f1e358455e51578ca01f16d6cde1a3141fbfb50 100644 (file)
@@ -221,6 +221,11 @@ static struct platform_device sa11x0mcp_device = {
        .resource       = sa11x0mcp_resources,
 };
 
+void sa11x0_set_mcp_data(struct mcp_plat_data *data)
+{
+       sa11x0mcp_device.dev.platform_data = data;
+}
+
 static struct resource sa11x0ssp_resources[] = {
        [0] = {
                .start  = 0x80070000,
index bfe41da9923e35b0b427058485e05749c454f2a1..279e3afa3c393bd8b25b4f01c47abd00ffb40d57 100644 (file)
@@ -34,5 +34,8 @@ struct resource;
 extern void sa11x0_set_flash_data(struct flash_platform_data *flash,
                                  struct resource *res, int nr);
 
+struct sa11x0_ssp_plat_ops;
+extern void sa11x0_set_ssp_data(struct sa11x0_ssp_plat_ops *ops);
+
 struct irda_platform_data;
 void sa11x0_set_irda_data(struct irda_platform_data *irda);
index 66a929cb7bc5ba5549e670552c104bf08f14039b..c131a5201b5ba885ba9448381cfaab27ab345634 100644 (file)
@@ -98,8 +98,8 @@ static struct irqchip sa1100_low_gpio_chip = {
        .ack            = sa1100_low_gpio_ack,
        .mask           = sa1100_low_gpio_mask,
        .unmask         = sa1100_low_gpio_unmask,
-       .type           = sa1100_gpio_type,
-       .wake           = sa1100_low_gpio_wake,
+       .set_type       = sa1100_gpio_type,
+       .set_wake       = sa1100_low_gpio_wake,
 };
 
 /*
@@ -126,7 +126,7 @@ sa1100_high_gpio_handler(unsigned int irq, struct irqdesc *desc,
                mask >>= 11;
                do {
                        if (mask & 1)
-                               desc->handle(irq, desc, regs);
+                               desc_handle_irq(irq, desc, regs);
                        mask >>= 1;
                        irq++;
                        desc++;
@@ -181,8 +181,8 @@ static struct irqchip sa1100_high_gpio_chip = {
        .ack            = sa1100_high_gpio_ack,
        .mask           = sa1100_high_gpio_mask,
        .unmask         = sa1100_high_gpio_unmask,
-       .type           = sa1100_gpio_type,
-       .wake           = sa1100_high_gpio_wake,
+       .set_type       = sa1100_gpio_type,
+       .set_wake       = sa1100_high_gpio_wake,
 };
 
 /*
index 870b488aeda44323172400c76bfd2e1274fbf9a8..ed6744d480aff0f04e2b1bd6a1f742b1e01d3b23 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
+#include <asm/arch/mcp.h>
 
 #include "generic.h"
 
 
 #warning "include/asm/arch-sa1100/ide.h needs fixing for lart"
 
+static struct mcp_plat_data lart_mcp_data = {
+       .mccr0          = MCCR0_ADM,
+       .sclk_rate      = 11981000,
+};
+
+static void __init lart_init(void)
+{
+       sa11x0_set_mcp_data(&lart_mcp_data);
+}
+
 static struct map_desc lart_io_desc[] __initdata = {
  /* virtual     physical    length      type */
   { 0xe8000000, 0x00000000, 0x00400000, MT_DEVICE }, /* main flash memory */
@@ -47,5 +58,6 @@ MACHINE_START(LART, "LART")
        .boot_params    = 0xc0000100,
        .map_io         = lart_map_io,
        .init_irq       = sa1100_init_irq,
+       .init_machine   = lart_init,
        .timer          = &sa1100_timer,
 MACHINE_END
index 1405383463ea7503f940980c93c6dbb83adbe64d..fc061641b7be083cb44d89e33fa22c3826e9c272 100644 (file)
@@ -61,12 +61,12 @@ neponset_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *reg
 
                        if (irr & IRR_ETHERNET) {
                                d = irq_desc + IRQ_NEPONSET_SMC9196;
-                               d->handle(IRQ_NEPONSET_SMC9196, d, regs);
+                               desc_handle_irq(IRQ_NEPONSET_SMC9196, d, regs);
                        }
 
                        if (irr & IRR_USAR) {
                                d = irq_desc + IRQ_NEPONSET_USAR;
-                               d->handle(IRQ_NEPONSET_USAR, d, regs);
+                               desc_handle_irq(IRQ_NEPONSET_USAR, d, regs);
                        }
 
                        desc->chip->unmask(irq);
@@ -74,7 +74,7 @@ neponset_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *reg
 
                if (irr & IRR_SA1111) {
                        d = irq_desc + IRQ_NEPONSET_SA1111;
-                       d->handle(IRQ_NEPONSET_SA1111, d, regs);
+                       desc_handle_irq(IRQ_NEPONSET_SA1111, d, regs);
                }
        }
 }
index 43a00359fcdddf9e8d0186702112ae98659f9921..7482288278d96acf17323a5612aa2791ab771d4c 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
+#include <asm/arch/mcp.h>
 #include <asm/arch/shannon.h>
 
 #include "generic.h"
@@ -52,9 +53,15 @@ static struct resource shannon_flash_resource = {
        .flags          = IORESOURCE_MEM,
 };
 
+static struct mcp_plat_data shannon_mcp_data = {
+       .mccr0          = MCCR0_ADM,
+       .sclk_rate      = 11981000,
+};
+
 static void __init shannon_init(void)
 {
        sa11x0_set_flash_data(&shannon_flash_data, &shannon_flash_resource, 1);
+       sa11x0_set_mcp_data(&shannon_mcp_data);
 }
 
 static void __init shannon_map_io(void)
index 77978586b1268d955e2fa58fdaab475a2408ee0c..07f6d5fd7bb0a0108f149d8323073012dfe0a9d2 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
+#include <asm/arch/mcp.h>
 #include <asm/arch/simpad.h>
 
 #include <linux/serial_core.h>
@@ -123,6 +124,11 @@ static struct resource simpad_flash_resources [] = {
        }
 };
 
+static struct mcp_plat_data simpad_mcp_data = {
+       .mccr0          = MCCR0_ADM,
+       .sclk_rate      = 11981000,
+};
+
 
 
 static void __init simpad_map_io(void)
@@ -157,6 +163,7 @@ static void __init simpad_map_io(void)
 
        sa11x0_set_flash_data(&simpad_flash_data, simpad_flash_resources,
                              ARRAY_SIZE(simpad_flash_resources));
+       sa11x0_set_mcp_data(&simpad_mcp_data);
 }
 
 static void simpad_power_off(void)
index 0eeb3616ffea739652f8221504da7a1548374171..47e0420623fc25083a486f74887bff522260108b 100644 (file)
@@ -70,15 +70,11 @@ static unsigned long sa1100_gettimeoffset (void)
        return usec;
 }
 
-/*
- * We will be entered with IRQs enabled.
- *
- * Loop until we get ahead of the free running timer.
- * This ensures an exact clock tick count and time accuracy.
- * IRQs are disabled inside the loop to ensure coherence between
- * lost_ticks (updated in do_timer()) and the match reg value, so we
- * can use do_gettimeofday() from interrupt handlers.
- */
+#ifdef CONFIG_NO_IDLE_HZ
+static unsigned long initial_match;
+static int match_posponed;
+#endif
+
 static irqreturn_t
 sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -86,6 +82,21 @@ sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
        write_seqlock(&xtime_lock);
 
+#ifdef CONFIG_NO_IDLE_HZ
+       if (match_posponed) {
+               match_posponed = 0;
+               OSMR0 = initial_match;
+       }
+#endif
+
+       /*
+        * Loop until we get ahead of the free running timer.
+        * This ensures an exact clock tick count and time accuracy.
+        * Since IRQs are disabled at this point, coherence between
+        * lost_ticks(updated in do_timer()) and the match reg value is
+        * ensured, hence we can use do_gettimeofday() from interrupt
+        * handlers.
+        */
        do {
                timer_tick(regs);
                OSSR = OSSR_M0;  /* Clear match on timer 0 */
@@ -120,6 +131,42 @@ static void __init sa1100_timer_init(void)
        OSCR = 0;               /* initialize free-running timer, force first match */
 }
 
+#ifdef CONFIG_NO_IDLE_HZ
+static int sa1100_dyn_tick_enable_disable(void)
+{
+       /* nothing to do */
+       return 0;
+}
+
+static void sa1100_dyn_tick_reprogram(unsigned long ticks)
+{
+       if (ticks > 1) {
+               initial_match = OSMR0;
+               OSMR0 = initial_match + ticks * LATCH;
+               match_posponed = 1;
+       }
+}
+
+static irqreturn_t
+sa1100_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+       if (match_posponed) {
+               match_posponed = 0;
+               OSMR0 = initial_match;
+               if ((signed long)(initial_match - OSCR) <= 0)
+                       return sa1100_timer_interrupt(irq, dev_id, regs);
+       }
+       return IRQ_NONE;
+}
+
+static struct dyn_tick_timer sa1100_dyn_tick = {
+       .enable         = sa1100_dyn_tick_enable_disable,
+       .disable        = sa1100_dyn_tick_enable_disable,
+       .reprogram      = sa1100_dyn_tick_reprogram,
+       .handler        = sa1100_dyn_tick_handler,
+};
+#endif
+
 #ifdef CONFIG_PM
 unsigned long osmr[4], oier;
 
@@ -156,4 +203,7 @@ struct sys_timer sa1100_timer = {
        .suspend        = sa1100_timer_suspend,
        .resume         = sa1100_timer_resume,
        .offset         = sa1100_gettimeoffset,
+#ifdef CONFIG_NO_IDLE_HZ
+       .dyn_tick       = &sa1100_dyn_tick,
+#endif
 };
index f01c0f8a2bb369ccb7dfb47dc5ea75c13443d0b9..3c8862fde51ad18a362713f821757b1cba4a3903 100644 (file)
@@ -108,7 +108,7 @@ sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
                irq += IRQ_SIC_START;
 
                desc = irq_desc + irq;
-               desc->handle(irq, desc, regs);
+               desc_handle_irq(irq, desc, regs);
        } while (status);
 }
 
index 81f4a8a2d34b2c7af8c93074ca8f0c443fb80bc2..4b39d867ac14ef5e4ced59cd5ba3c6157e6427de 100644 (file)
@@ -45,7 +45,7 @@
 
 #define LDST_P_EQ_U(i) ((((i) ^ ((i) >> 1)) & (1 << 23)) == 0)
 
-#define LDSTH_I_BIT(i) (i & (1 << 22))         /* half-word immed      */
+#define LDSTHD_I_BIT(i)        (i & (1 << 22))         /* double/half-word immed */
 #define LDM_S_BIT(i)   (i & (1 << 22))         /* write CPSR from SPSR */
 
 #define RN_BITS(i)     ((i >> 16) & 15)        /* Rn                   */
@@ -68,6 +68,7 @@ static unsigned long ai_sys;
 static unsigned long ai_skipped;
 static unsigned long ai_half;
 static unsigned long ai_word;
+static unsigned long ai_dword;
 static unsigned long ai_multi;
 static int ai_usermode;
 
@@ -93,6 +94,8 @@ proc_alignment_read(char *page, char **start, off_t off, int count, int *eof,
        p += sprintf(p, "Skipped:\t%lu\n", ai_skipped);
        p += sprintf(p, "Half:\t\t%lu\n", ai_half);
        p += sprintf(p, "Word:\t\t%lu\n", ai_word);
+       if (cpu_architecture() >= CPU_ARCH_ARMv5TE)
+               p += sprintf(p, "DWord:\t\t%lu\n", ai_dword);
        p += sprintf(p, "Multi:\t\t%lu\n", ai_multi);
        p += sprintf(p, "User faults:\t%i (%s)\n", ai_usermode,
                        usermode_action[ai_usermode]);
@@ -283,12 +286,6 @@ do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *r
 {
        unsigned int rd = RD_BITS(instr);
 
-       if ((instr & 0x01f00ff0) == 0x01000090)
-               goto swp;
-
-       if ((instr & 0x90) != 0x90 || (instr & 0x60) == 0)
-               goto bad;
-
        ai_half += 1;
 
        if (user_mode(regs))
@@ -323,10 +320,47 @@ do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *r
 
        return TYPE_LDST;
 
- swp:
-       printk(KERN_ERR "Alignment trap: not handling swp instruction\n");
- bad:
-       return TYPE_ERROR;
+ fault:
+       return TYPE_FAULT;
+}
+
+static int
+do_alignment_ldrdstrd(unsigned long addr, unsigned long instr,
+                     struct pt_regs *regs)
+{
+       unsigned int rd = RD_BITS(instr);
+
+       ai_dword += 1;
+
+       if (user_mode(regs))
+               goto user;
+
+       if ((instr & 0xf0) == 0xd0) {
+               unsigned long val;
+               get32_unaligned_check(val, addr);
+               regs->uregs[rd] = val;
+               get32_unaligned_check(val, addr+4);
+               regs->uregs[rd+1] = val;
+       } else {
+               put32_unaligned_check(regs->uregs[rd], addr);
+               put32_unaligned_check(regs->uregs[rd+1], addr+4);
+       }
+
+       return TYPE_LDST;
+
+ user:
+       if ((instr & 0xf0) == 0xd0) {
+               unsigned long val;
+               get32t_unaligned_check(val, addr);
+               regs->uregs[rd] = val;
+               get32t_unaligned_check(val, addr+4);
+               regs->uregs[rd+1] = val;
+       } else {
+               put32t_unaligned_check(regs->uregs[rd], addr);
+               put32t_unaligned_check(regs->uregs[rd+1], addr+4);
+       }
+
+       return TYPE_LDST;
 
  fault:
        return TYPE_FAULT;
@@ -617,12 +651,20 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        regs->ARM_pc += thumb_mode(regs) ? 2 : 4;
 
        switch (CODING_BITS(instr)) {
-       case 0x00000000:        /* ldrh or strh */
-               if (LDSTH_I_BIT(instr))
+       case 0x00000000:        /* 3.13.4 load/store instruction extensions */
+               if (LDSTHD_I_BIT(instr))
                        offset.un = (instr & 0xf00) >> 4 | (instr & 15);
                else
                        offset.un = regs->uregs[RM_BITS(instr)];
-               handler = do_alignment_ldrhstrh;
+
+               if ((instr & 0x000000f0) == 0x000000b0 || /* LDRH, STRH */
+                   (instr & 0x001000f0) == 0x001000f0)   /* LDRSH */
+                       handler = do_alignment_ldrhstrh;
+               else if ((instr & 0x001000f0) == 0x000000d0 || /* LDRD */
+                        (instr & 0x001000f0) == 0x000000f0)   /* STRD */
+                       handler = do_alignment_ldrdstrd;
+               else
+                       goto bad;
                break;
 
        case 0x04000000:        /* ldr or str immediate */
index 3c655c54e23131b10cbf33d3d1fb1fe4a81d52be..d125a3dc061c8fb5efb27ceed11ce731ddafe4a5 100644 (file)
@@ -275,11 +275,9 @@ alloc_init_supersection(unsigned long virt, unsigned long phys, int prot)
        int i;
 
        for (i = 0; i < 16; i += 1) {
-               alloc_init_section(virt, phys & SUPERSECTION_MASK,
-                                  prot | PMD_SECT_SUPER);
+               alloc_init_section(virt, phys, prot | PMD_SECT_SUPER);
 
                virt += (PGDIR_SIZE / 2);
-               phys += (PGDIR_SIZE / 2);
        }
 }
 
@@ -297,14 +295,10 @@ alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pg
        pte_t *ptep;
 
        if (pmd_none(*pmdp)) {
-               unsigned long pmdval;
                ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE *
                                               sizeof(pte_t));
 
-               pmdval = __pa(ptep) | prot_l1;
-               pmdp[0] = __pmd(pmdval);
-               pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
-               flush_pmd_entry(pmdp);
+               __pmd_populate(pmdp, __pa(ptep) | prot_l1);
        }
        ptep = pte_offset_kernel(pmdp, virt);
 
@@ -459,7 +453,7 @@ static void __init build_mem_type_table(void)
 
        for (i = 0; i < 16; i++) {
                unsigned long v = pgprot_val(protection_map[i]);
-               v &= (~(PTE_BUFFERABLE|PTE_CACHEABLE)) | user_pgprot;
+               v = (v & ~(PTE_BUFFERABLE|PTE_CACHEABLE)) | user_pgprot;
                protection_map[i] = __pgprot(v);
        }
 
@@ -583,23 +577,23 @@ static void __init create_mapping(struct map_desc *md)
  */
 void setup_mm_for_reboot(char mode)
 {
-       unsigned long pmdval;
+       unsigned long base_pmdval;
        pgd_t *pgd;
-       pmd_t *pmd;
        int i;
-       int cpu_arch = cpu_architecture();
 
        if (current->mm && current->mm->pgd)
                pgd = current->mm->pgd;
        else
                pgd = init_mm.pgd;
 
-       for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++) {
-               pmdval = (i << PGDIR_SHIFT) |
-                        PMD_SECT_AP_WRITE | PMD_SECT_AP_READ |
-                        PMD_TYPE_SECT;
-               if (cpu_arch <= CPU_ARCH_ARMv5TEJ)
-                       pmdval |= PMD_BIT4;
+       base_pmdval = PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | PMD_TYPE_SECT;
+       if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ)
+               base_pmdval |= PMD_BIT4;
+
+       for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++, pgd++) {
+               unsigned long pmdval = (i << PGDIR_SHIFT) | base_pmdval;
+               pmd_t *pmd;
+
                pmd = pmd_off(pgd, i << PGDIR_SHIFT);
                pmd[0] = __pmd(pmdval);
                pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
index 0ee214b824ff2a9cffd5d136180e76a61fb9d197..189ef6a71ba102b49b66b2414a96d470332e3f46 100644 (file)
@@ -38,8 +38,8 @@ ENTRY(cpu_arm7_data_abort)
        mrc     p15, 0, r1, c5, c0, 0           @ get FSR
        mrc     p15, 0, r0, c6, c0, 0           @ get FAR
        ldr     r8, [r0]                        @ read arm instruction
-       tst     r8, #1 << 20                    @ L = 1 -> write?
-       orreq   r1, r1, #1 <<                 @ yes.
+       tst     r8, #1 << 20                    @ L = 0 -> write?
+       orreq   r1, r1, #1 << 11                @ yes.
        and     r7, r8, #15 << 24
        add     pc, pc, r7, lsr #22             @ Now branch to the relevant processing routine
        nop
@@ -71,8 +71,8 @@ ENTRY(cpu_arm6_data_abort)
        mrc     p15, 0, r1, c5, c0, 0           @ get FSR
        mrc     p15, 0, r0, c6, c0, 0           @ get FAR
        ldr     r8, [r2]                        @ read arm instruction
-       tst     r8, #1 << 20                    @ L = 1 -> write?
-       orreq   r1, r1, #1 <<                 @ yes.
+       tst     r8, #1 << 20                    @ L = 0 -> write?
+       orreq   r1, r1, #1 << 11                @ yes.
        and     r7, r8, #14 << 24
        teq     r7, #8 << 24                    @ was it ldm/stm
        movne   pc, lr
index 345365852f8cb999ed4f4ae5fec549236058d0d4..9693e9b4ffd1e70b024803b251b8a3629b5f41f9 100644 (file)
@@ -91,6 +91,13 @@ config OMAP_32K_TIMER_HZ
          Kernel internal timer frequency should be a divisor of 32768,
          such as 64 or 128.
 
+config OMAP_DM_TIMER
+       bool "Use dual-mode timer"
+       default n
+       depends on ARCH_OMAP16XX
+       help
+        Select this option if you want to use OMAP Dual-Mode timers.
+
 choice
        prompt "Low-level debug console UART"
        depends on ARCH_OMAP
@@ -107,6 +114,15 @@ config OMAP_LL_DEBUG_UART3
 
 endchoice
 
+config OMAP_SERIAL_WAKE
+       bool "Enable wake-up events for serial ports"
+       depends OMAP_MUX
+       default y
+       help
+         Select this option if you want to have your system wake up
+         to data on the serial RX line. This allows you to wake the
+         system from serial console.
+
 endmenu
 
 endif
index 531e11af54d4b6c5e2b7b21859bb41bef463e143..7e144f9cad1c3104c05cce4068fc3d7550ed9c45 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 # Common support
-obj-y := common.o dma.o clock.o mux.o gpio.o mcbsp.o usb.o
+obj-y := common.o sram.o sram-fn.o clock.o dma.o mux.o gpio.o mcbsp.o usb.o
 obj-m :=
 obj-n :=
 obj-  :=
@@ -15,3 +15,5 @@ obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
 obj-$(CONFIG_PM) += pm.o sleep.o
 
 obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
+obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
+
index 59d91b3262ba0f3a0540a5c7ddb9f79f9bd73d44..52a58b2da2882553121810e75ba9aa1d168674b0 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/arch/usb.h>
 
 #include "clock.h"
+#include "sram.h"
 
 static LIST_HEAD(clocks);
 static DECLARE_MUTEX(clocks_sem);
@@ -141,7 +142,7 @@ static struct clk arm_ck = {
 static struct clk armper_ck = {
        .name           = "armper_ck",
        .parent         = &ck_dpll1,
-       .flags          = CLOCK_IN_OMAP730 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                          RATE_CKCTL,
        .enable_reg     = ARM_IDLECT2,
        .enable_bit     = EN_PERCK,
@@ -385,7 +386,8 @@ static struct clk uart2_ck = {
        .name           = "uart2_ck",
        /* Direct from ULPD, no parent */
        .rate           = 12000000,
-       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT |
+                         ALWAYS_ENABLED,
        .enable_reg     = MOD_CONF_CTRL_0,
        .enable_bit     = 30,   /* Chooses between 12MHz and 48MHz */
        .set_rate       = &set_uart_rate,
@@ -443,6 +445,15 @@ static struct clk usb_hhc_ck16xx = {
        .enable_bit     = 8 /* UHOST_EN */,
 };
 
+static struct clk usb_dc_ck = {
+       .name           = "usb_dc_ck",
+       /* Direct from ULPD, no parent */
+       .rate           = 48000000,
+       .flags          = CLOCK_IN_OMAP16XX | RATE_FIXED,
+       .enable_reg     = SOFT_REQ_REG,
+       .enable_bit     = 4,
+};
+
 static struct clk mclk_1510 = {
        .name           = "mclk",
        /* Direct from ULPD, no parent. May be enabled by ext hardware. */
@@ -552,6 +563,7 @@ static struct clk *  onchip_clks[] = {
        &uart3_16xx,
        &usb_clko,
        &usb_hhc_ck1510, &usb_hhc_ck16xx,
+       &usb_dc_ck,
        &mclk_1510,  &mclk_16xx,
        &bclk_1510,  &bclk_16xx,
        &mmc1_ck,
@@ -946,14 +958,13 @@ static int select_table_rate(struct clk *  clk, unsigned long rate)
        if (!ptr->rate)
                return -EINVAL;
 
-       if (!ptr->rate)
-               return -EINVAL;
+       /*
+        * In most cases we should not need to reprogram DPLL.
+        * Reprogramming the DPLL is tricky, it must be done from SRAM.
+        */
+       omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val);
 
-       if (unlikely(ck_dpll1.rate == 0)) {
-               omap_writew(ptr->dpllctl_val, DPLL_CTL);
-               ck_dpll1.rate = ptr->pll_rate;
-       }
-       omap_writew(ptr->ckctl_val, ARM_CKCTL);
+       ck_dpll1.rate = ptr->pll_rate;
        propagate_rate(&ck_dpll1);
        return 0;
 }
@@ -1224,9 +1235,11 @@ int __init clk_init(void)
 #endif
        /* Cache rates for clocks connected to ck_ref (not dpll1) */
        propagate_rate(&ck_ref);
-       printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld.%01ld/%ld/%ld MHz\n",
+       printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): "
+               "%ld.%01ld/%ld.%01ld/%ld.%01ld MHz\n",
               ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10,
-              ck_dpll1.rate, arm_ck.rate);
+              ck_dpll1.rate / 1000000, (ck_dpll1.rate / 100000) % 10,
+              arm_ck.rate / 1000000, (arm_ck.rate / 100000) % 10);
 
 #ifdef CONFIG_MACH_OMAP_PERSEUS2
        /* Select slicer output as OMAP input clock */
@@ -1271,7 +1284,9 @@ static int __init omap_late_clk_reset(void)
        struct clk *p;
        __u32 regval32;
 
-       omap_writew(0, SOFT_REQ_REG);
+       /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */
+       regval32 = omap_readw(SOFT_REQ_REG) & (1 << 4);
+       omap_writew(regval32, SOFT_REQ_REG);
        omap_writew(0, SOFT_REQ_REG2);
 
        list_for_each_entry(p, &clocks, node) {
index ea967a8f6ce52716a8292dcdf1f5fcf890e27d99..6cb20aea7f518b22dbd9b25a6d93cc6ac93fd1ff 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/hardware/clock.h>
 #include <asm/io.h>
 #include <asm/mach-types.h>
+#include <asm/setup.h>
 
 #include <asm/arch/board.h>
 #include <asm/arch/mux.h>
 
 #define NO_LENGTH_CHECK 0xffffffff
 
-extern int omap_bootloader_tag_len;
-extern u8 omap_bootloader_tag[];
+unsigned char omap_bootloader_tag[512];
+int omap_bootloader_tag_len;
 
 struct omap_board_config_kernel *omap_board_config;
-int omap_board_config_size = 0;
+int omap_board_config_size;
 
 static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
 {
index c0a5c2fa42bdf0784038e21fe14455c97e74b880..da7b6514565884e894d82f729ee38274d63ae46d 100644 (file)
@@ -425,7 +425,7 @@ static int dma_handle_ch(int ch)
                dma_chan[ch + 6].saved_csr = csr >> 7;
                csr &= 0x7f;
        }
-       if (!csr)
+       if ((csr & 0x3f) == 0)
                return 0;
        if (unlikely(dma_chan[ch].dev_id == -1)) {
                printk(KERN_WARNING "Spurious interrupt from DMA channel %d (CSR %04x)\n",
@@ -890,11 +890,11 @@ void omap_enable_lcd_dma(void)
        w |= 1 << 8;
        omap_writew(w, OMAP1610_DMA_LCD_CTRL);
 
+       lcd_dma.active = 1;
+
        w = omap_readw(OMAP1610_DMA_LCD_CCR);
        w |= 1 << 7;
        omap_writew(w, OMAP1610_DMA_LCD_CCR);
-
-       lcd_dma.active = 1;
 }
 
 void omap_setup_lcd_dma(void)
@@ -965,8 +965,8 @@ void omap_clear_dma(int lch)
  */
 dma_addr_t omap_get_dma_src_pos(int lch)
 {
-       return (dma_addr_t) (OMAP_DMA_CSSA_L(lch) |
-                            (OMAP_DMA_CSSA_U(lch) << 16));
+       return (dma_addr_t) (omap_readw(OMAP_DMA_CSSA_L(lch)) |
+       (omap_readw(OMAP_DMA_CSSA_U(lch)) << 16));
 }
 
 /*
@@ -979,8 +979,18 @@ dma_addr_t omap_get_dma_src_pos(int lch)
  */
 dma_addr_t omap_get_dma_dst_pos(int lch)
 {
-       return (dma_addr_t) (OMAP_DMA_CDSA_L(lch) |
-                            (OMAP_DMA_CDSA_U(lch) << 16));
+       return (dma_addr_t) (omap_readw(OMAP_DMA_CDSA_L(lch)) |
+       (omap_readw(OMAP_DMA_CDSA_U(lch)) << 16));
+}
+
+/*
+ * Returns current source transfer counting for the given DMA channel.
+ * Can be used to monitor the progress of a transfer inside a  block.
+ * It must be called with disabled interrupts.
+ */
+int omap_get_dma_src_addr_counter(int lch)
+{
+       return (dma_addr_t) omap_readw(OMAP_DMA_CSAC(lch));
 }
 
 int omap_dma_running(void)
@@ -1076,6 +1086,7 @@ arch_initcall(omap_init_dma);
 
 EXPORT_SYMBOL(omap_get_dma_src_pos);
 EXPORT_SYMBOL(omap_get_dma_dst_pos);
+EXPORT_SYMBOL(omap_get_dma_src_addr_counter);
 EXPORT_SYMBOL(omap_clear_dma);
 EXPORT_SYMBOL(omap_set_dma_priority);
 EXPORT_SYMBOL(omap_request_dma);
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
new file mode 100644 (file)
index 0000000..a1468d7
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * linux/arch/arm/plat-omap/dmtimer.c
+ *
+ * OMAP Dual-Mode Timers
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/dmtimer.h>
+#include <asm/io.h>
+#include <asm/arch/irqs.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+
+#define OMAP_TIMER_COUNT               8
+
+#define OMAP_TIMER_ID_REG              0x00
+#define OMAP_TIMER_OCP_CFG_REG         0x10
+#define OMAP_TIMER_SYS_STAT_REG                0x14
+#define OMAP_TIMER_STAT_REG            0x18
+#define OMAP_TIMER_INT_EN_REG          0x1c
+#define OMAP_TIMER_WAKEUP_EN_REG       0x20
+#define OMAP_TIMER_CTRL_REG            0x24
+#define OMAP_TIMER_COUNTER_REG         0x28
+#define OMAP_TIMER_LOAD_REG            0x2c
+#define OMAP_TIMER_TRIGGER_REG         0x30
+#define OMAP_TIMER_WRITE_PEND_REG      0x34
+#define OMAP_TIMER_MATCH_REG           0x38
+#define OMAP_TIMER_CAPTURE_REG         0x3c
+#define OMAP_TIMER_IF_CTRL_REG         0x40
+
+
+static struct dmtimer_info_struct {
+       struct list_head        unused_timers;
+       struct list_head        reserved_timers;
+} dm_timer_info;
+
+static struct omap_dm_timer dm_timers[] = {
+       { .base=0xfffb1400, .irq=INT_1610_GPTIMER1 },
+       { .base=0xfffb1c00, .irq=INT_1610_GPTIMER2 },
+       { .base=0xfffb2400, .irq=INT_1610_GPTIMER3 },
+       { .base=0xfffb2c00, .irq=INT_1610_GPTIMER4 },
+       { .base=0xfffb3400, .irq=INT_1610_GPTIMER5 },
+       { .base=0xfffb3c00, .irq=INT_1610_GPTIMER6 },
+       { .base=0xfffb4400, .irq=INT_1610_GPTIMER7 },
+       { .base=0xfffb4c00, .irq=INT_1610_GPTIMER8 },
+       { .base=0x0 },
+};
+
+
+static spinlock_t dm_timer_lock;
+
+
+inline void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value)
+{
+       omap_writel(value, timer->base + reg);
+       while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG))
+               ;
+}
+
+u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg)
+{
+       return omap_readl(timer->base + reg);
+}
+
+int omap_dm_timers_active(void)
+{
+       struct omap_dm_timer *timer;
+
+       for (timer = &dm_timers[0]; timer->base; ++timer)
+               if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
+                   OMAP_TIMER_CTRL_ST)
+                       return 1;
+
+       return 0;
+}
+
+
+void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
+{
+       int n = (timer - dm_timers) << 1;
+       u32 l;
+
+       l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
+       l |= source << n;
+       omap_writel(l, MOD_CONF_CTRL_1);
+}
+
+
+static void omap_dm_timer_reset(struct omap_dm_timer *timer)
+{
+       /* Reset and set posted mode */
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, 0x02);
+
+       omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_ARMXOR);
+}
+
+
+
+struct omap_dm_timer * omap_dm_timer_request(void)
+{
+       struct omap_dm_timer *timer = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dm_timer_lock, flags);
+       if (!list_empty(&dm_timer_info.unused_timers)) {
+               timer = (struct omap_dm_timer *)
+                               dm_timer_info.unused_timers.next;
+               list_move_tail((struct list_head *)timer,
+                               &dm_timer_info.reserved_timers);
+       }
+       spin_unlock_irqrestore(&dm_timer_lock, flags);
+
+       return timer;
+}
+
+
+void omap_dm_timer_free(struct omap_dm_timer *timer)
+{
+       unsigned long flags;
+
+       omap_dm_timer_reset(timer);
+
+       spin_lock_irqsave(&dm_timer_lock, flags);
+       list_move_tail((struct list_head *)timer, &dm_timer_info.unused_timers);
+       spin_unlock_irqrestore(&dm_timer_lock, flags);
+}
+
+void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
+                               unsigned int value)
+{
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value);
+}
+
+unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
+{
+       return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
+}
+
+void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
+{
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value);
+}
+
+void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer)
+{
+       u32 l;
+       l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+       l |= OMAP_TIMER_CTRL_AR;
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+}
+
+void omap_dm_timer_trigger(struct omap_dm_timer *timer)
+{
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 1);
+}
+
+void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value)
+{
+       u32 l;
+
+       l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+       l |= value & 0x3;
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+}
+
+void omap_dm_timer_start(struct omap_dm_timer *timer)
+{
+       u32 l;
+
+       l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+       l |= OMAP_TIMER_CTRL_ST;
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+}
+
+void omap_dm_timer_stop(struct omap_dm_timer *timer)
+{
+       u32 l;
+
+       l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+       l &= ~0x1;
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+}
+
+unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
+{
+       return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);
+}
+
+void omap_dm_timer_reset_counter(struct omap_dm_timer *timer)
+{
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 0);
+}
+
+void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load)
+{
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
+}
+
+void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match)
+{
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
+}
+
+void omap_dm_timer_enable_compare(struct omap_dm_timer *timer)
+{
+       u32 l;
+
+       l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+       l |= OMAP_TIMER_CTRL_CE;
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+}
+
+
+static inline void __dm_timer_init(void)
+{
+       struct omap_dm_timer *timer;
+
+       spin_lock_init(&dm_timer_lock);
+       INIT_LIST_HEAD(&dm_timer_info.unused_timers);
+       INIT_LIST_HEAD(&dm_timer_info.reserved_timers);
+
+       timer = &dm_timers[0];
+       while (timer->base) {
+               list_add_tail((struct list_head *)timer, &dm_timer_info.unused_timers);
+               omap_dm_timer_reset(timer);
+               timer++;
+       }
+}
+
+static int __init omap_dm_timer_init(void)
+{
+       if (cpu_is_omap16xx())
+               __dm_timer_init();
+       return 0;
+}
+
+arch_initcall(omap_dm_timer_init);
index 1c85b4e536c2e005b25f2249113bec4e60d97a5c..55059a24ad419da31fbc026f5345a9db386ee9fc 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Support functions for OMAP GPIO
  *
- * Copyright (C) 2003 Nokia Corporation
+ * Copyright (C) 2003-2005 Nokia Corporation
  * Written by Juha Yrjölä <juha.yrjola@nokia.com>
  *
  * This program is free software; you can redistribute it and/or modify
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/ptrace.h>
+#include <linux/sysdev.h>
+#include <linux/err.h>
 
 #include <asm/hardware.h>
+#include <asm/hardware/clock.h>
 #include <asm/irq.h>
 #include <asm/arch/irqs.h>
 #include <asm/arch/gpio.h>
@@ -29,7 +32,7 @@
 /*
  * OMAP1510 GPIO registers
  */
-#define OMAP1510_GPIO_BASE             0xfffce000
+#define OMAP1510_GPIO_BASE             (void __iomem *)0xfffce000
 #define OMAP1510_GPIO_DATA_INPUT       0x00
 #define OMAP1510_GPIO_DATA_OUTPUT      0x04
 #define OMAP1510_GPIO_DIR_CONTROL      0x08
 /*
  * OMAP1610 specific GPIO registers
  */
-#define OMAP1610_GPIO1_BASE            0xfffbe400
-#define OMAP1610_GPIO2_BASE            0xfffbec00
-#define OMAP1610_GPIO3_BASE            0xfffbb400
-#define OMAP1610_GPIO4_BASE            0xfffbbc00
+#define OMAP1610_GPIO1_BASE            (void __iomem *)0xfffbe400
+#define OMAP1610_GPIO2_BASE            (void __iomem *)0xfffbec00
+#define OMAP1610_GPIO3_BASE            (void __iomem *)0xfffbb400
+#define OMAP1610_GPIO4_BASE            (void __iomem *)0xfffbbc00
 #define OMAP1610_GPIO_REVISION         0x0000
 #define OMAP1610_GPIO_SYSCONFIG                0x0010
 #define OMAP1610_GPIO_SYSSTATUS                0x0014
 #define OMAP1610_GPIO_IRQSTATUS1       0x0018
 #define OMAP1610_GPIO_IRQENABLE1       0x001c
+#define OMAP1610_GPIO_WAKEUPENABLE     0x0028
 #define OMAP1610_GPIO_DATAIN           0x002c
 #define OMAP1610_GPIO_DATAOUT          0x0030
 #define OMAP1610_GPIO_DIRECTION                0x0034
 #define OMAP1610_GPIO_EDGE_CTRL1       0x0038
 #define OMAP1610_GPIO_EDGE_CTRL2       0x003c
 #define OMAP1610_GPIO_CLEAR_IRQENABLE1 0x009c
+#define OMAP1610_GPIO_CLEAR_WAKEUPENA  0x00a8
 #define OMAP1610_GPIO_CLEAR_DATAOUT    0x00b0
 #define OMAP1610_GPIO_SET_IRQENABLE1   0x00dc
+#define OMAP1610_GPIO_SET_WAKEUPENA    0x00e8
 #define OMAP1610_GPIO_SET_DATAOUT      0x00f0
 
 /*
  * OMAP730 specific GPIO registers
  */
-#define OMAP730_GPIO1_BASE             0xfffbc000
-#define OMAP730_GPIO2_BASE             0xfffbc800
-#define OMAP730_GPIO3_BASE             0xfffbd000
-#define OMAP730_GPIO4_BASE             0xfffbd800
-#define OMAP730_GPIO5_BASE             0xfffbe000
-#define OMAP730_GPIO6_BASE             0xfffbe800
+#define OMAP730_GPIO1_BASE             (void __iomem *)0xfffbc000
+#define OMAP730_GPIO2_BASE             (void __iomem *)0xfffbc800
+#define OMAP730_GPIO3_BASE             (void __iomem *)0xfffbd000
+#define OMAP730_GPIO4_BASE             (void __iomem *)0xfffbd800
+#define OMAP730_GPIO5_BASE             (void __iomem *)0xfffbe000
+#define OMAP730_GPIO6_BASE             (void __iomem *)0xfffbe800
 #define OMAP730_GPIO_DATA_INPUT                0x00
 #define OMAP730_GPIO_DATA_OUTPUT       0x04
 #define OMAP730_GPIO_DIR_CONTROL       0x08
 #define OMAP730_GPIO_INT_MASK          0x10
 #define OMAP730_GPIO_INT_STATUS                0x14
 
+/*
+ * omap24xx specific GPIO registers
+ */
+#define OMAP24XX_GPIO1_BASE            (void __iomem *)0x48018000
+#define OMAP24XX_GPIO2_BASE            (void __iomem *)0x4801a000
+#define OMAP24XX_GPIO3_BASE            (void __iomem *)0x4801c000
+#define OMAP24XX_GPIO4_BASE            (void __iomem *)0x4801e000
+#define OMAP24XX_GPIO_REVISION         0x0000
+#define OMAP24XX_GPIO_SYSCONFIG                0x0010
+#define OMAP24XX_GPIO_SYSSTATUS                0x0014
+#define OMAP24XX_GPIO_IRQSTATUS1       0x0018
+#define OMAP24XX_GPIO_IRQENABLE1       0x001c
+#define OMAP24XX_GPIO_CTRL             0x0030
+#define OMAP24XX_GPIO_OE               0x0034
+#define OMAP24XX_GPIO_DATAIN           0x0038
+#define OMAP24XX_GPIO_DATAOUT          0x003c
+#define OMAP24XX_GPIO_LEVELDETECT0     0x0040
+#define OMAP24XX_GPIO_LEVELDETECT1     0x0044
+#define OMAP24XX_GPIO_RISINGDETECT     0x0048
+#define OMAP24XX_GPIO_FALLINGDETECT    0x004c
+#define OMAP24XX_GPIO_CLEARIRQENABLE1  0x0060
+#define OMAP24XX_GPIO_SETIRQENABLE1    0x0064
+#define OMAP24XX_GPIO_CLEARWKUENA      0x0080
+#define OMAP24XX_GPIO_SETWKUENA                0x0084
+#define OMAP24XX_GPIO_CLEARDATAOUT     0x0090
+#define OMAP24XX_GPIO_SETDATAOUT       0x0094
+
 #define OMAP_MPUIO_MASK                (~OMAP_MAX_GPIO_LINES & 0xff)
 
 struct gpio_bank {
-       u32 base;
+       void __iomem *base;
        u16 irq;
        u16 virtual_irq_start;
-       u8 method;
+       int method;
        u32 reserved_map;
+       u32 suspend_wakeup;
+       u32 saved_wakeup;
        spinlock_t lock;
 };
 
@@ -93,8 +128,9 @@ struct gpio_bank {
 #define METHOD_GPIO_1510       1
 #define METHOD_GPIO_1610       2
 #define METHOD_GPIO_730                3
+#define METHOD_GPIO_24XX       4
 
-#if defined(CONFIG_ARCH_OMAP16XX)
+#ifdef CONFIG_ARCH_OMAP16XX
 static struct gpio_bank gpio_bank_1610[5] = {
        { OMAP_MPUIO_BASE,     INT_MPUIO,           IH_MPUIO_BASE,     METHOD_MPUIO},
        { OMAP1610_GPIO1_BASE, INT_GPIO_BANK1,      IH_GPIO_BASE,      METHOD_GPIO_1610 },
@@ -123,6 +159,15 @@ static struct gpio_bank gpio_bank_730[7] = {
 };
 #endif
 
+#ifdef CONFIG_ARCH_OMAP24XX
+static struct gpio_bank gpio_bank_24xx[4] = {
+       { OMAP24XX_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE,       METHOD_GPIO_24XX },
+       { OMAP24XX_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32,  METHOD_GPIO_24XX },
+       { OMAP24XX_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64,  METHOD_GPIO_24XX },
+       { OMAP24XX_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96,  METHOD_GPIO_24XX },
+};
+#endif
+
 static struct gpio_bank *gpio_bank;
 static int gpio_bank_count;
 
@@ -149,14 +194,23 @@ static inline struct gpio_bank *get_gpio_bank(int gpio)
                return &gpio_bank[1 + (gpio >> 5)];
        }
 #endif
+#ifdef CONFIG_ARCH_OMAP24XX
+       if (cpu_is_omap24xx())
+               return &gpio_bank[gpio >> 5];
+#endif
 }
 
 static inline int get_gpio_index(int gpio)
 {
+#ifdef CONFIG_ARCH_OMAP730
        if (cpu_is_omap730())
                return gpio & 0x1f;
-       else
-               return gpio & 0x0f;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+       if (cpu_is_omap24xx())
+               return gpio & 0x1f;
+#endif
+       return gpio & 0x0f;
 }
 
 static inline int gpio_valid(int gpio)
@@ -179,6 +233,10 @@ static inline int gpio_valid(int gpio)
 #ifdef CONFIG_ARCH_OMAP730
        if (cpu_is_omap730() && gpio < 192)
                return 0;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+       if (cpu_is_omap24xx() && gpio < 128)
+               return 0;
 #endif
        return -1;
 }
@@ -195,7 +253,7 @@ static int check_gpio(int gpio)
 
 static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
 {
-       u32 reg = bank->base;
+       void __iomem *reg = bank->base;
        u32 l;
 
        switch (bank->method) {
@@ -211,6 +269,9 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
        case METHOD_GPIO_730:
                reg += OMAP730_GPIO_DIR_CONTROL;
                break;
+       case METHOD_GPIO_24XX:
+               reg += OMAP24XX_GPIO_OE;
+               break;
        }
        l = __raw_readl(reg);
        if (is_input)
@@ -234,7 +295,7 @@ void omap_set_gpio_direction(int gpio, int is_input)
 
 static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
 {
-       u32 reg = bank->base;
+       void __iomem *reg = bank->base;
        u32 l = 0;
 
        switch (bank->method) {
@@ -269,6 +330,13 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
                else
                        l &= ~(1 << gpio);
                break;
+       case METHOD_GPIO_24XX:
+               if (enable)
+                       reg += OMAP24XX_GPIO_SETDATAOUT;
+               else
+                       reg += OMAP24XX_GPIO_CLEARDATAOUT;
+               l = 1 << gpio;
+               break;
        default:
                BUG();
                return;
@@ -291,7 +359,7 @@ void omap_set_gpio_dataout(int gpio, int enable)
 int omap_get_gpio_datain(int gpio)
 {
        struct gpio_bank *bank;
-       u32 reg;
+       void __iomem *reg;
 
        if (check_gpio(gpio) < 0)
                return -1;
@@ -310,109 +378,132 @@ int omap_get_gpio_datain(int gpio)
        case METHOD_GPIO_730:
                reg += OMAP730_GPIO_DATA_INPUT;
                break;
+       case METHOD_GPIO_24XX:
+               reg += OMAP24XX_GPIO_DATAIN;
+               break;
        default:
                BUG();
                return -1;
        }
-       return (__raw_readl(reg) & (1 << get_gpio_index(gpio))) != 0;
+       return (__raw_readl(reg)
+                       & (1 << get_gpio_index(gpio))) != 0;
 }
 
-static void _set_gpio_edge_ctrl(struct gpio_bank *bank, int gpio, int edge)
+#define MOD_REG_BIT(reg, bit_mask, set)        \
+do {   \
+       int l = __raw_readl(base + reg); \
+       if (set) l |= bit_mask; \
+       else l &= ~bit_mask; \
+       __raw_writel(l, base + reg); \
+} while(0)
+
+static inline void set_24xx_gpio_triggering(void __iomem *base, int gpio, int trigger)
 {
-       u32 reg = bank->base;
-       u32 l;
+       u32 gpio_bit = 1 << gpio;
+
+       MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit,
+               trigger & IRQT_LOW);
+       MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT1, gpio_bit,
+               trigger & IRQT_HIGH);
+       MOD_REG_BIT(OMAP24XX_GPIO_RISINGDETECT, gpio_bit,
+               trigger & IRQT_RISING);
+       MOD_REG_BIT(OMAP24XX_GPIO_FALLINGDETECT, gpio_bit,
+               trigger & IRQT_FALLING);
+       /* FIXME: Possibly do 'set_irq_handler(j, do_level_IRQ)' if only level
+        * triggering requested. */
+}
+
+static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
+{
+       void __iomem *reg = bank->base;
+       u32 l = 0;
 
        switch (bank->method) {
        case METHOD_MPUIO:
                reg += OMAP_MPUIO_GPIO_INT_EDGE;
                l = __raw_readl(reg);
-               if (edge == OMAP_GPIO_RISING_EDGE)
+               if (trigger == IRQT_RISING)
                        l |= 1 << gpio;
-               else
+               else if (trigger == IRQT_FALLING)
                        l &= ~(1 << gpio);
-               __raw_writel(l, reg);
+               else
+                       goto bad;
                break;
        case METHOD_GPIO_1510:
                reg += OMAP1510_GPIO_INT_CONTROL;
                l = __raw_readl(reg);
-               if (edge == OMAP_GPIO_RISING_EDGE)
+               if (trigger == IRQT_RISING)
                        l |= 1 << gpio;
-               else
+               else if (trigger == IRQT_FALLING)
                        l &= ~(1 << gpio);
-               __raw_writel(l, reg);
+               else
+                       goto bad;
                break;
        case METHOD_GPIO_1610:
-               edge &= 0x03;
                if (gpio & 0x08)
                        reg += OMAP1610_GPIO_EDGE_CTRL2;
                else
                        reg += OMAP1610_GPIO_EDGE_CTRL1;
                gpio &= 0x07;
+               /* We allow only edge triggering, i.e. two lowest bits */
+               if (trigger & ~IRQT_BOTHEDGE)
+                       BUG();
+               /* NOTE: knows __IRQT_{FAL,RIS}EDGE match OMAP hardware */
+               trigger &= 0x03;
                l = __raw_readl(reg);
                l &= ~(3 << (gpio << 1));
-               l |= edge << (gpio << 1);
-               __raw_writel(l, reg);
+               l |= trigger << (gpio << 1);
                break;
        case METHOD_GPIO_730:
                reg += OMAP730_GPIO_INT_CONTROL;
                l = __raw_readl(reg);
-               if (edge == OMAP_GPIO_RISING_EDGE)
+               if (trigger == IRQT_RISING)
                        l |= 1 << gpio;
-               else
+               else if (trigger == IRQT_FALLING)
                        l &= ~(1 << gpio);
-               __raw_writel(l, reg);
+               else
+                       goto bad;
+               break;
+       case METHOD_GPIO_24XX:
+               set_24xx_gpio_triggering(reg, gpio, trigger);
                break;
        default:
                BUG();
-               return;
+               goto bad;
        }
+       __raw_writel(l, reg);
+       return 0;
+bad:
+       return -EINVAL;
 }
 
-void omap_set_gpio_edge_ctrl(int gpio, int edge)
+static int gpio_irq_type(unsigned irq, unsigned type)
 {
        struct gpio_bank *bank;
+       unsigned gpio;
+       int retval;
+
+       if (irq > IH_MPUIO_BASE)
+               gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
+       else
+               gpio = irq - IH_GPIO_BASE;
 
        if (check_gpio(gpio) < 0)
-               return;
+               return -EINVAL;
+
+       if (type & (__IRQT_LOWLVL|__IRQT_HIGHLVL|IRQT_PROBE))
+               return -EINVAL;
+
        bank = get_gpio_bank(gpio);
        spin_lock(&bank->lock);
-       _set_gpio_edge_ctrl(bank, get_gpio_index(gpio), edge);
+       retval = _set_gpio_triggering(bank, get_gpio_index(gpio), type);
        spin_unlock(&bank->lock);
-}
-
-
-static int _get_gpio_edge_ctrl(struct gpio_bank *bank, int gpio)
-{
-       u32 reg = bank->base, l;
-
-       switch (bank->method) {
-       case METHOD_MPUIO:
-               l = __raw_readl(reg + OMAP_MPUIO_GPIO_INT_EDGE);
-               return (l & (1 << gpio)) ?
-                       OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE;
-       case METHOD_GPIO_1510:
-               l = __raw_readl(reg + OMAP1510_GPIO_INT_CONTROL);
-               return (l & (1 << gpio)) ?
-                       OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE;
-       case METHOD_GPIO_1610:
-               if (gpio & 0x08)
-                       reg += OMAP1610_GPIO_EDGE_CTRL2;
-               else
-                       reg += OMAP1610_GPIO_EDGE_CTRL1;
-               return (__raw_readl(reg) >> ((gpio & 0x07) << 1)) & 0x03;
-       case METHOD_GPIO_730:
-               l = __raw_readl(reg + OMAP730_GPIO_INT_CONTROL);
-               return (l & (1 << gpio)) ?
-                       OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE;
-       default:
-               BUG();
-               return -1;
-       }
+       return retval;
 }
 
 static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
 {
-       u32 reg = bank->base;
+       void __iomem *reg = bank->base;
 
        switch (bank->method) {
        case METHOD_MPUIO:
@@ -428,6 +519,9 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
        case METHOD_GPIO_730:
                reg += OMAP730_GPIO_INT_STATUS;
                break;
+       case METHOD_GPIO_24XX:
+               reg += OMAP24XX_GPIO_IRQSTATUS1;
+               break;
        default:
                BUG();
                return;
@@ -442,7 +536,7 @@ static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio)
 
 static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enable)
 {
-       u32 reg = bank->base;
+       void __iomem *reg = bank->base;
        u32 l;
 
        switch (bank->method) {
@@ -477,6 +571,13 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab
                else
                        l |= gpio_mask;
                break;
+       case METHOD_GPIO_24XX:
+               if (enable)
+                       reg += OMAP24XX_GPIO_SETIRQENABLE1;
+               else
+                       reg += OMAP24XX_GPIO_CLEARIRQENABLE1;
+               l = gpio_mask;
+               break;
        default:
                BUG();
                return;
@@ -489,6 +590,50 @@ static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int ena
        _enable_gpio_irqbank(bank, 1 << get_gpio_index(gpio), enable);
 }
 
+/*
+ * Note that ENAWAKEUP needs to be enabled in GPIO_SYSCONFIG register.
+ * 1510 does not seem to have a wake-up register. If JTAG is connected
+ * to the target, system will wake up always on GPIO events. While
+ * system is running all registered GPIO interrupts need to have wake-up
+ * enabled. When system is suspended, only selected GPIO interrupts need
+ * to have wake-up enabled.
+ */
+static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
+{
+       switch (bank->method) {
+       case METHOD_GPIO_1610:
+       case METHOD_GPIO_24XX:
+               spin_lock(&bank->lock);
+               if (enable)
+                       bank->suspend_wakeup |= (1 << gpio);
+               else
+                       bank->suspend_wakeup &= ~(1 << gpio);
+               spin_unlock(&bank->lock);
+               return 0;
+       default:
+               printk(KERN_ERR "Can't enable GPIO wakeup for method %i\n",
+                      bank->method);
+               return -EINVAL;
+       }
+}
+
+/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
+static int gpio_wake_enable(unsigned int irq, unsigned int enable)
+{
+       unsigned int gpio = irq - IH_GPIO_BASE;
+       struct gpio_bank *bank;
+       int retval;
+
+       if (check_gpio(gpio) < 0)
+               return -ENODEV;
+       bank = get_gpio_bank(gpio);
+       spin_lock(&bank->lock);
+       retval = _set_gpio_wakeup(bank, get_gpio_index(gpio), enable);
+       spin_unlock(&bank->lock);
+
+       return retval;
+}
+
 int omap_request_gpio(int gpio)
 {
        struct gpio_bank *bank;
@@ -505,14 +650,32 @@ int omap_request_gpio(int gpio)
                return -1;
        }
        bank->reserved_map |= (1 << get_gpio_index(gpio));
+
+       /* Set trigger to none. You need to enable the trigger after request_irq */
+       _set_gpio_triggering(bank, get_gpio_index(gpio), IRQT_NOEDGE);
+
 #ifdef CONFIG_ARCH_OMAP1510
        if (bank->method == METHOD_GPIO_1510) {
-               u32 reg;
+               void __iomem *reg;
 
-               /* Claim the pin for the ARM */
+               /* Claim the pin for MPU */
                reg = bank->base + OMAP1510_GPIO_PIN_CONTROL;
                __raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg);
        }
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
+       if (bank->method == METHOD_GPIO_1610) {
+               /* Enable wake-up during idle for dynamic tick */
+               void __iomem *reg = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
+               __raw_writel(1 << get_gpio_index(gpio), reg);
+       }
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+       if (bank->method == METHOD_GPIO_24XX) {
+               /* Enable wake-up during idle for dynamic tick */
+               void __iomem *reg = bank->base + OMAP24XX_GPIO_SETWKUENA;
+               __raw_writel(1 << get_gpio_index(gpio), reg);
+       }
 #endif
        spin_unlock(&bank->lock);
 
@@ -533,6 +696,20 @@ void omap_free_gpio(int gpio)
                spin_unlock(&bank->lock);
                return;
        }
+#ifdef CONFIG_ARCH_OMAP16XX
+       if (bank->method == METHOD_GPIO_1610) {
+               /* Disable wake-up during idle for dynamic tick */
+               void __iomem *reg = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
+               __raw_writel(1 << get_gpio_index(gpio), reg);
+       }
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+       if (bank->method == METHOD_GPIO_24XX) {
+               /* Disable wake-up during idle for dynamic tick */
+               void __iomem *reg = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
+               __raw_writel(1 << get_gpio_index(gpio), reg);
+       }
+#endif
        bank->reserved_map &= ~(1 << get_gpio_index(gpio));
        _set_gpio_direction(bank, get_gpio_index(gpio), 1);
        _set_gpio_irqenable(bank, gpio, 0);
@@ -552,7 +729,7 @@ void omap_free_gpio(int gpio)
 static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc,
                             struct pt_regs *regs)
 {
-       u32 isr_reg = 0;
+       void __iomem *isr_reg = NULL;
        u32 isr;
        unsigned int gpio_irq;
        struct gpio_bank *bank;
@@ -574,24 +751,30 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc,
        if (bank->method == METHOD_GPIO_730)
                isr_reg = bank->base + OMAP730_GPIO_INT_STATUS;
 #endif
+#ifdef CONFIG_ARCH_OMAP24XX
+       if (bank->method == METHOD_GPIO_24XX)
+               isr_reg = bank->base + OMAP24XX_GPIO_IRQSTATUS1;
+#endif
 
-       isr = __raw_readl(isr_reg);
-       _enable_gpio_irqbank(bank, isr, 0);
-       _clear_gpio_irqbank(bank, isr);
-       _enable_gpio_irqbank(bank, isr, 1);
-       desc->chip->unmask(irq);
-
-       if (unlikely(!isr))
-               return;
-
-       gpio_irq = bank->virtual_irq_start;
-       for (; isr != 0; isr >>= 1, gpio_irq++) {
-               struct irqdesc *d;
-               if (!(isr & 1))
-                       continue;
-               d = irq_desc + gpio_irq;
-               d->handle(gpio_irq, d, regs);
-       }
+       while(1) {
+               isr = __raw_readl(isr_reg);
+               _enable_gpio_irqbank(bank, isr, 0);
+               _clear_gpio_irqbank(bank, isr);
+               _enable_gpio_irqbank(bank, isr, 1);
+               desc->chip->unmask(irq);
+
+               if (!isr)
+                       break;
+
+               gpio_irq = bank->virtual_irq_start;
+               for (; isr != 0; isr >>= 1, gpio_irq++) {
+                       struct irqdesc *d;
+                       if (!(isr & 1))
+                               continue;
+                       d = irq_desc + gpio_irq;
+                       desc_handle_irq(gpio_irq, d, regs);
+               }
+        }
 }
 
 static void gpio_ack_irq(unsigned int irq)
@@ -613,14 +796,10 @@ static void gpio_mask_irq(unsigned int irq)
 static void gpio_unmask_irq(unsigned int irq)
 {
        unsigned int gpio = irq - IH_GPIO_BASE;
+       unsigned int gpio_idx = get_gpio_index(gpio);
        struct gpio_bank *bank = get_gpio_bank(gpio);
 
-       if (_get_gpio_edge_ctrl(bank, get_gpio_index(gpio)) == OMAP_GPIO_NO_EDGE) {
-               printk(KERN_ERR "OMAP GPIO %d: trying to enable GPIO IRQ while no edge is set\n",
-                      gpio);
-               _set_gpio_edge_ctrl(bank, get_gpio_index(gpio), OMAP_GPIO_RISING_EDGE);
-       }
-       _set_gpio_irqenable(bank, gpio, 1);
+       _set_gpio_irqenable(bank, gpio_idx, 1);
 }
 
 static void mpuio_ack_irq(unsigned int irq)
@@ -645,9 +824,11 @@ static void mpuio_unmask_irq(unsigned int irq)
 }
 
 static struct irqchip gpio_irq_chip = {
-       .ack    = gpio_ack_irq,
-       .mask   = gpio_mask_irq,
-       .unmask = gpio_unmask_irq,
+       .ack            = gpio_ack_irq,
+       .mask           = gpio_mask_irq,
+       .unmask         = gpio_unmask_irq,
+       .set_type       = gpio_irq_type,
+       .set_wake       = gpio_wake_enable,
 };
 
 static struct irqchip mpuio_irq_chip = {
@@ -657,6 +838,7 @@ static struct irqchip mpuio_irq_chip = {
 };
 
 static int initialized = 0;
+static struct clk * gpio_ck = NULL;
 
 static int __init _omap_gpio_init(void)
 {
@@ -665,6 +847,14 @@ static int __init _omap_gpio_init(void)
 
        initialized = 1;
 
+       if (cpu_is_omap1510()) {
+               gpio_ck = clk_get(NULL, "arm_gpio_ck");
+               if (IS_ERR(gpio_ck))
+                       printk("Could not get arm_gpio_ck\n");
+               else
+                       clk_use(gpio_ck);
+       }
+
 #ifdef CONFIG_ARCH_OMAP1510
        if (cpu_is_omap1510()) {
                printk(KERN_INFO "OMAP1510 GPIO hardware\n");
@@ -674,7 +864,7 @@ static int __init _omap_gpio_init(void)
 #endif
 #if defined(CONFIG_ARCH_OMAP16XX)
        if (cpu_is_omap16xx()) {
-               int rev;
+               u32 rev;
 
                gpio_bank_count = 5;
                gpio_bank = gpio_bank_1610;
@@ -689,6 +879,17 @@ static int __init _omap_gpio_init(void)
                gpio_bank_count = 7;
                gpio_bank = gpio_bank_730;
        }
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+       if (cpu_is_omap24xx()) {
+               int rev;
+
+               gpio_bank_count = 4;
+               gpio_bank = gpio_bank_24xx;
+               rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
+               printk(KERN_INFO "OMAP24xx GPIO hardware version %d.%d\n",
+                       (rev >> 4) & 0x0f, rev & 0x0f);
+       }
 #endif
        for (i = 0; i < gpio_bank_count; i++) {
                int j, gpio_count = 16;
@@ -710,6 +911,7 @@ static int __init _omap_gpio_init(void)
                if (bank->method == METHOD_GPIO_1610) {
                        __raw_writew(0x0000, bank->base + OMAP1610_GPIO_IRQENABLE1);
                        __raw_writew(0xffff, bank->base + OMAP1610_GPIO_IRQSTATUS1);
+                       __raw_writew(0x0014, bank->base + OMAP1610_GPIO_SYSCONFIG);
                }
 #endif
 #ifdef CONFIG_ARCH_OMAP730
@@ -719,6 +921,14 @@ static int __init _omap_gpio_init(void)
 
                        gpio_count = 32; /* 730 has 32-bit GPIOs */
                }
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+               if (bank->method == METHOD_GPIO_24XX) {
+                       __raw_writel(0x00000000, bank->base + OMAP24XX_GPIO_IRQENABLE1);
+                       __raw_writel(0xffffffff, bank->base + OMAP24XX_GPIO_IRQSTATUS1);
+
+                       gpio_count = 32;
+               }
 #endif
                for (j = bank->virtual_irq_start;
                     j < bank->virtual_irq_start + gpio_count; j++) {
@@ -735,12 +945,97 @@ static int __init _omap_gpio_init(void)
 
        /* Enable system clock for GPIO module.
         * The CAM_CLK_CTRL *is* really the right place. */
-       if (cpu_is_omap1610() || cpu_is_omap1710())
+       if (cpu_is_omap16xx())
                omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, ULPD_CAM_CLK_CTRL);
 
        return 0;
 }
 
+#if defined (CONFIG_ARCH_OMAP16XX) || defined (CONFIG_ARCH_OMAP24XX)
+static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg)
+{
+       int i;
+
+       if (!cpu_is_omap24xx() && !cpu_is_omap16xx())
+               return 0;
+
+       for (i = 0; i < gpio_bank_count; i++) {
+               struct gpio_bank *bank = &gpio_bank[i];
+               void __iomem *wake_status;
+               void __iomem *wake_clear;
+               void __iomem *wake_set;
+
+               switch (bank->method) {
+               case METHOD_GPIO_1610:
+                       wake_status = bank->base + OMAP1610_GPIO_WAKEUPENABLE;
+                       wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
+                       wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
+                       break;
+               case METHOD_GPIO_24XX:
+                       wake_status = bank->base + OMAP24XX_GPIO_SETWKUENA;
+                       wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
+                       wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
+                       break;
+               default:
+                       continue;
+               }
+
+               spin_lock(&bank->lock);
+               bank->saved_wakeup = __raw_readl(wake_status);
+               __raw_writel(0xffffffff, wake_clear);
+               __raw_writel(bank->suspend_wakeup, wake_set);
+               spin_unlock(&bank->lock);
+       }
+
+       return 0;
+}
+
+static int omap_gpio_resume(struct sys_device *dev)
+{
+       int i;
+
+       if (!cpu_is_omap24xx() && !cpu_is_omap16xx())
+               return 0;
+
+       for (i = 0; i < gpio_bank_count; i++) {
+               struct gpio_bank *bank = &gpio_bank[i];
+               void __iomem *wake_clear;
+               void __iomem *wake_set;
+
+               switch (bank->method) {
+               case METHOD_GPIO_1610:
+                       wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
+                       wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
+                       break;
+               case METHOD_GPIO_24XX:
+                       wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
+                       wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
+                       break;
+               default:
+                       continue;
+               }
+
+               spin_lock(&bank->lock);
+               __raw_writel(0xffffffff, wake_clear);
+               __raw_writel(bank->saved_wakeup, wake_set);
+               spin_unlock(&bank->lock);
+       }
+
+       return 0;
+}
+
+static struct sysdev_class omap_gpio_sysclass = {
+       set_kset_name("gpio"),
+       .suspend        = omap_gpio_suspend,
+       .resume         = omap_gpio_resume,
+};
+
+static struct sys_device omap_gpio_device = {
+       .id             = 0,
+       .cls            = &omap_gpio_sysclass,
+};
+#endif
+
 /*
  * This may get called early from board specific init
  */
@@ -752,11 +1047,30 @@ int omap_gpio_init(void)
                return 0;
 }
 
+static int __init omap_gpio_sysinit(void)
+{
+       int ret = 0;
+
+       if (!initialized)
+               ret = _omap_gpio_init();
+
+#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX)
+       if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
+               if (ret == 0) {
+                       ret = sysdev_class_register(&omap_gpio_sysclass);
+                       if (ret == 0)
+                               ret = sysdev_register(&omap_gpio_device);
+               }
+       }
+#endif
+
+       return ret;
+}
+
 EXPORT_SYMBOL(omap_request_gpio);
 EXPORT_SYMBOL(omap_free_gpio);
 EXPORT_SYMBOL(omap_set_gpio_direction);
 EXPORT_SYMBOL(omap_set_gpio_dataout);
 EXPORT_SYMBOL(omap_get_gpio_datain);
-EXPORT_SYMBOL(omap_set_gpio_edge_ctrl);
 
-arch_initcall(omap_gpio_init);
+arch_initcall(omap_gpio_sysinit);
index 43567d5edddb409124466110e91300743addb0a6..9c9b7df3faf6d2fe15315899cda29e8d43a8466e 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/arch/dma.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/irqs.h>
+#include <asm/arch/dsp_common.h>
 #include <asm/arch/mcbsp.h>
 
 #include <asm/hardware/clock.h>
@@ -187,9 +188,6 @@ static int omap_mcbsp_check(unsigned int id)
        return -1;
 }
 
-#define EN_XORPCK              1
-#define DSP_RSTCT2              0xe1008014
-
 static void omap_mcbsp_dsp_request(void)
 {
        if (cpu_is_omap1510() || cpu_is_omap16xx()) {
@@ -198,6 +196,11 @@ static void omap_mcbsp_dsp_request(void)
 
                /* enable 12MHz clock to mcbsp 1 & 3 */
                clk_use(mcbsp_dspxor_ck);
+
+               /*
+                * DSP external peripheral reset
+                * FIXME: This should be moved to dsp code
+                */
                __raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1 << 1,
                             DSP_RSTCT2);
        }
index ea7b955b9c819f05df337590529143ae982cc74b..64482040f89e9a7c0da908cd0bb8429b4ac5e274 100644 (file)
@@ -48,6 +48,9 @@ omap_cfg_reg(const reg_cfg_t reg_cfg)
                pull_orig = 0, pull = 0;
        unsigned int mask, warn = 0;
 
+       if (cpu_is_omap7xx())
+               return 0;
+
        if (reg_cfg > ARRAY_SIZE(reg_cfg_table)) {
                printk(KERN_ERR "MUX: reg_cfg %d\n", reg_cfg);
                return -EINVAL;
index 2ede2ee8cae420ecf4b5a24593e572058c942929..1fb16f9edfd58ba552ddb0bee7f6487e0fb6d5fd 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
index e6536b16c385b16aabc3a46303a00d668b482239..e15c6c1ddec954775b68ac623738885675da04d4 100644 (file)
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
 #include <linux/pm.h>
+#include <linux/interrupt.h>
 
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <asm/mach/time.h>
-#include <asm/mach-types.h>
+#include <asm/mach/irq.h>
 
-#include <asm/arch/omap16xx.h>
+#include <asm/mach-types.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/tc.h>
 #include <asm/arch/pm.h>
 #include <asm/arch/mux.h>
-#include <asm/arch/tc.h>
 #include <asm/arch/tps65010.h>
+#include <asm/arch/dsp_common.h>
 
 #include "clock.h"
+#include "sram.h"
 
 static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
 static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
 static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE];
 static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
 
+static void (*omap_sram_idle)(void) = NULL;
+static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
+
 /*
  * Let's power down on idle, but only if we are really
  * idle, because once we start down the path of
@@ -65,7 +73,6 @@ static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
  */
 void omap_pm_idle(void)
 {
-       int (*func_ptr)(void) = 0;
        unsigned int mask32 = 0;
 
        /*
@@ -83,6 +90,13 @@ void omap_pm_idle(void)
        }
        mask32 = omap_readl(ARM_SYSST);
 
+       /*
+        * Prevent the ULPD from entering low power state by setting
+        * POWER_CTRL_REG:4 = 0
+        */
+       omap_writew(omap_readw(ULPD_POWER_CTRL) &
+                   ~ULPD_DEEP_SLEEP_TRANSITION_EN, ULPD_POWER_CTRL);
+
        /*
         * Since an interrupt may set up a timer, we don't want to
         * reprogram the hardware timer with interrupts enabled.
@@ -92,18 +106,9 @@ void omap_pm_idle(void)
 
        if ((mask32 & DSP_IDLE) == 0) {
                __asm__ volatile ("mcr  p15, 0, r0, c7, c0, 4");
-       } else {
-
-               if (cpu_is_omap1510()) {
-                       func_ptr = (void *)(OMAP1510_SRAM_IDLE_SUSPEND);
-               } else if (cpu_is_omap1610() || cpu_is_omap1710()) {
-                       func_ptr = (void *)(OMAP1610_SRAM_IDLE_SUSPEND);
-               } else if (cpu_is_omap5912()) {
-                       func_ptr = (void *)(OMAP5912_SRAM_IDLE_SUSPEND);
-               }
+       } else
+               omap_sram_idle();
 
-               func_ptr();
-       }
        local_fiq_enable();
        local_irq_enable();
 }
@@ -115,58 +120,55 @@ void omap_pm_idle(void)
  */
 static void omap_pm_wakeup_setup(void)
 {
-       /*
-        * Enable ARM XOR clock and release peripheral from reset by
-        * writing 1 to PER_EN bit in ARM_RSTCT2, this is required
-        * for UART configuration to use UART2 to wake up.
-        */
-
-       omap_writel(omap_readl(ARM_IDLECT2) | ENABLE_XORCLK, ARM_IDLECT2);
-       omap_writel(omap_readl(ARM_RSTCT2) | PER_EN, ARM_RSTCT2);
-       omap_writew(MODEM_32K_EN, ULPD_CLOCK_CTRL);
+       u32 level1_wake = OMAP_IRQ_BIT(INT_IH2_IRQ);
+       u32 level2_wake = OMAP_IRQ_BIT(INT_UART2) | OMAP_IRQ_BIT(INT_KEYBOARD);
 
        /*
-        * Turn off all interrupts except L1-2nd level cascade,
-        * and the L2 wakeup interrupts: keypad and UART2.
+        * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade,
+        * and the L2 wakeup interrupts: keypad and UART2. Note that the
+        * drivers must still separately call omap_set_gpio_wakeup() to
+        * wake up to a GPIO interrupt.
         */
+       if (cpu_is_omap1510() || cpu_is_omap16xx())
+               level1_wake |= OMAP_IRQ_BIT(INT_GPIO_BANK1);
+       else if (cpu_is_omap730())
+               level1_wake |= OMAP_IRQ_BIT(INT_730_GPIO_BANK1);
 
-       omap_writel(~IRQ_LEVEL2, OMAP_IH1_MIR);
+       omap_writel(~level1_wake, OMAP_IH1_MIR);
 
-       if (cpu_is_omap1510()) {
-               omap_writel(~(IRQ_UART2 | IRQ_KEYBOARD),  OMAP_IH2_MIR);
-       }
+       if (cpu_is_omap1510())
+               omap_writel(~level2_wake,  OMAP_IH2_MIR);
 
+       /* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */
        if (cpu_is_omap16xx()) {
-               omap_writel(~(IRQ_UART2 | IRQ_KEYBOARD), OMAP_IH2_0_MIR);
-
-               omap_writel(~0x0, OMAP_IH2_1_MIR);
+               omap_writel(~level2_wake, OMAP_IH2_0_MIR);
+               omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ), OMAP_IH2_1_MIR);
                omap_writel(~0x0, OMAP_IH2_2_MIR);
                omap_writel(~0x0, OMAP_IH2_3_MIR);
        }
 
-       /*  New IRQ agreement */
+       /*  New IRQ agreement, recalculate in cascade order */
+       omap_writel(1, OMAP_IH2_CONTROL);
        omap_writel(1, OMAP_IH1_CONTROL);
-
-       /* external PULL to down, bit 22 = 0 */
-       omap_writel(omap_readl(PULL_DWN_CTRL_2) & ~(1<<22), PULL_DWN_CTRL_2);
 }
 
 void omap_pm_suspend(void)
 {
-       unsigned int mask32 = 0;
        unsigned long arg0 = 0, arg1 = 0;
-       int (*func_ptr)(unsigned short, unsigned short) = 0;
-       unsigned short save_dsp_idlect2;
 
-       printk("PM: OMAP%x is entering deep sleep now ...\n", system_rev);
+       printk("PM: OMAP%x is trying to enter deep sleep...\n", system_rev);
+
+       omap_serial_wake_trigger(1);
 
        if (machine_is_omap_osk()) {
                /* Stop LED1 (D9) blink */
                tps65010_set_led(LED1, OFF);
        }
 
+       omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG);
+
        /*
-        * Step 1: turn off interrupts
+        * Step 1: turn off interrupts (FIXME: NOTE: already disabled)
         */
 
        local_irq_disable();
@@ -207,6 +209,8 @@ void omap_pm_suspend(void)
        ARM_SAVE(ARM_CKCTL);
        ARM_SAVE(ARM_IDLECT1);
        ARM_SAVE(ARM_IDLECT2);
+       if (!(cpu_is_omap1510()))
+               ARM_SAVE(ARM_IDLECT3);
        ARM_SAVE(ARM_EWUPCT);
        ARM_SAVE(ARM_RSTCT1);
        ARM_SAVE(ARM_RSTCT2);
@@ -214,42 +218,12 @@ void omap_pm_suspend(void)
        ULPD_SAVE(ULPD_CLOCK_CTRL);
        ULPD_SAVE(ULPD_STATUS_REQ);
 
-       /*
-        * Step 3: LOW_PWR signal enabling
-        *
-        * Allow the LOW_PWR signal to be visible on MPUIO5 ball.
-        */
-       if (cpu_is_omap1510()) {
-               /* POWER_CTRL_REG = 0x1 (LOW_POWER is available) */
-               omap_writew(omap_readw(ULPD_POWER_CTRL) |
-                           OMAP1510_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
-       } else if (cpu_is_omap16xx()) {
-               /* POWER_CTRL_REG = 0x1 (LOW_POWER is available) */
-               omap_writew(omap_readw(ULPD_POWER_CTRL) |
-                           OMAP1610_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
-       }
-
-       /* configure LOW_PWR pin */
-       omap_cfg_reg(T20_1610_LOW_PWR);
+       /* (Step 3 removed - we now allow deep sleep by default) */
 
        /*
         * Step 4: OMAP DSP Shutdown
         */
 
-       /* Set DSP_RST = 1 and DSP_EN = 0, put DSP block into reset */
-       omap_writel((omap_readl(ARM_RSTCT1) | DSP_RST) & ~DSP_ENABLE,
-                   ARM_RSTCT1);
-
-       /* Set DSP boot mode to DSP-IDLE, DSP_BOOT_MODE = 0x2 */
-        omap_writel(DSP_IDLE_MODE, MPUI_DSP_BOOT_CONFIG);
-
-       /* Set EN_DSPCK = 0, stop DSP block clock */
-       omap_writel(omap_readl(ARM_CKCTL) & ~DSP_CLOCK_ENABLE, ARM_CKCTL);
-
-       /* Stop any DSP domain clocks */
-       omap_writel(omap_readl(ARM_IDLECT2) | (1<<EN_APICK), ARM_IDLECT2);
-       save_dsp_idlect2 = __raw_readw(DSP_IDLECT2);
-       __raw_writew(0, DSP_IDLECT2);
 
        /*
         * Step 5: Wakeup Event Setup
@@ -258,24 +232,9 @@ void omap_pm_suspend(void)
        omap_pm_wakeup_setup();
 
        /*
-        * Step 6a: ARM and Traffic controller shutdown
-        *
-        * Step 6 starts here with clock and watchdog disable
+        * Step 6: ARM and Traffic controller shutdown
         */
 
-       /* stop clocks */
-       mask32 = omap_readl(ARM_IDLECT2);
-       mask32 &= ~(1<<EN_WDTCK);  /* bit 0 -> 0 (WDT clock) */
-       mask32 |=  (1<<EN_XORPCK); /* bit 1 -> 1 (XORPCK clock) */
-       mask32 &= ~(1<<EN_PERCK);  /* bit 2 -> 0 (MPUPER_CK clock) */
-       mask32 &= ~(1<<EN_LCDCK);  /* bit 3 -> 0 (LCDC clock) */
-       mask32 &= ~(1<<EN_LBCK);   /* bit 4 -> 0 (local bus clock) */
-       mask32 |=  (1<<EN_APICK);  /* bit 6 -> 1 (MPUI clock) */
-       mask32 &= ~(1<<EN_TIMCK);  /* bit 7 -> 0 (MPU timer clock) */
-       mask32 &= ~(1<<DMACK_REQ); /* bit 8 -> 0 (DMAC clock) */
-       mask32 &= ~(1<<EN_GPIOCK); /* bit 9 -> 0 (GPIO clock) */
-       omap_writel(mask32, ARM_IDLECT2);
-
        /* disable ARM watchdog */
        omap_writel(0x00F5, OMAP_WDT_TIMER_MODE);
        omap_writel(0x00A0, OMAP_WDT_TIMER_MODE);
@@ -295,47 +254,24 @@ void omap_pm_suspend(void)
        arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1];
        arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2];
 
-       if (cpu_is_omap1510()) {
-               func_ptr = (void *)(OMAP1510_SRAM_API_SUSPEND);
-       } else if (cpu_is_omap1610() || cpu_is_omap1710()) {
-               func_ptr = (void *)(OMAP1610_SRAM_API_SUSPEND);
-       } else if (cpu_is_omap5912()) {
-               func_ptr = (void *)(OMAP5912_SRAM_API_SUSPEND);
-       }
-
        /*
         * Step 6c: ARM and Traffic controller shutdown
         *
         * Jump to assembly code. The processor will stay there
         * until wake up.
         */
-
-        func_ptr(arg0, arg1);
+        omap_sram_suspend(arg0, arg1);
 
        /*
         * If we are here, processor is woken up!
         */
 
-       if (cpu_is_omap1510()) {
-               /* POWER_CTRL_REG = 0x0 (LOW_POWER is disabled) */
-               omap_writew(omap_readw(ULPD_POWER_CTRL) &
-                           ~OMAP1510_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
-       } else if (cpu_is_omap16xx()) {
-               /* POWER_CTRL_REG = 0x0 (LOW_POWER is disabled) */
-               omap_writew(omap_readw(ULPD_POWER_CTRL) &
-                           ~OMAP1610_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
-       }
-
-
-       /* Restore DSP clocks */
-       omap_writel(omap_readl(ARM_IDLECT2) | (1<<EN_APICK), ARM_IDLECT2);
-       __raw_writew(save_dsp_idlect2, DSP_IDLECT2);
-       ARM_RESTORE(ARM_IDLECT2);
-
        /*
         * Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did
         */
 
+       if (!(cpu_is_omap1510()))
+               ARM_RESTORE(ARM_IDLECT3);
        ARM_RESTORE(ARM_CKCTL);
        ARM_RESTORE(ARM_EWUPCT);
        ARM_RESTORE(ARM_RSTCT1);
@@ -366,6 +302,8 @@ void omap_pm_suspend(void)
                MPUI1610_RESTORE(OMAP_IH2_3_MIR);
        }
 
+       omap_writew(0, ULPD_SOFT_DISABLE_REQ_REG);
+
        /*
         * Reenable interrupts
         */
@@ -373,6 +311,8 @@ void omap_pm_suspend(void)
        local_irq_enable();
        local_fiq_enable();
 
+       omap_serial_wake_trigger(0);
+
        printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev);
 
        if (machine_is_omap_osk()) {
@@ -401,6 +341,8 @@ static int omap_pm_read_proc(
        ARM_SAVE(ARM_CKCTL);
        ARM_SAVE(ARM_IDLECT1);
        ARM_SAVE(ARM_IDLECT2);
+       if (!(cpu_is_omap1510()))
+               ARM_SAVE(ARM_IDLECT3);
        ARM_SAVE(ARM_EWUPCT);
        ARM_SAVE(ARM_RSTCT1);
        ARM_SAVE(ARM_RSTCT2);
@@ -436,6 +378,7 @@ static int omap_pm_read_proc(
                   "ARM_CKCTL_REG:            0x%-8x     \n"
                   "ARM_IDLECT1_REG:          0x%-8x     \n"
                   "ARM_IDLECT2_REG:          0x%-8x     \n"
+                  "ARM_IDLECT3_REG:          0x%-8x     \n"
                   "ARM_EWUPCT_REG:           0x%-8x     \n"
                   "ARM_RSTCT1_REG:           0x%-8x     \n"
                   "ARM_RSTCT2_REG:           0x%-8x     \n"
@@ -449,6 +392,7 @@ static int omap_pm_read_proc(
                   ARM_SHOW(ARM_CKCTL),
                   ARM_SHOW(ARM_IDLECT1),
                   ARM_SHOW(ARM_IDLECT2),
+                  ARM_SHOW(ARM_IDLECT3),
                   ARM_SHOW(ARM_EWUPCT),
                   ARM_SHOW(ARM_RSTCT1),
                   ARM_SHOW(ARM_RSTCT2),
@@ -507,7 +451,7 @@ static void omap_pm_init_proc(void)
 
        entry = create_proc_read_entry("driver/omap_pm",
                                       S_IWUSR | S_IRUGO, NULL,
-                                      omap_pm_read_proc, 0);
+          omap_pm_read_proc, NULL);
 }
 
 #endif /* DEBUG && CONFIG_PROC_FS */
@@ -580,7 +524,21 @@ static int omap_pm_finish(suspend_state_t state)
 }
 
 
-struct pm_ops omap_pm_ops ={
+static irqreturn_t  omap_wakeup_interrupt(int  irq, void *  dev,
+                                    struct pt_regs *  regs)
+{
+       return IRQ_HANDLED;
+}
+
+static struct irqaction omap_wakeup_irq = {
+       .name           = "peripheral wakeup",
+       .flags          = SA_INTERRUPT,
+       .handler        = omap_wakeup_interrupt
+};
+
+
+
+static struct pm_ops omap_pm_ops ={
        .pm_disk_mode = 0,
         .prepare        = omap_pm_prepare,
         .enter          = omap_pm_enter,
@@ -590,42 +548,61 @@ struct pm_ops omap_pm_ops ={
 static int __init omap_pm_init(void)
 {
        printk("Power Management for TI OMAP.\n");
-       pm_idle = omap_pm_idle;
        /*
         * We copy the assembler sleep/wakeup routines to SRAM.
         * These routines need to be in SRAM as that's the only
         * memory the MPU can see when it wakes up.
         */
-
-#ifdef CONFIG_ARCH_OMAP1510
        if (cpu_is_omap1510()) {
-               memcpy((void *)OMAP1510_SRAM_IDLE_SUSPEND,
-                      omap1510_idle_loop_suspend,
-                      omap1510_idle_loop_suspend_sz);
-               memcpy((void *)OMAP1510_SRAM_API_SUSPEND, omap1510_cpu_suspend,
-                      omap1510_cpu_suspend_sz);
-       } else
-#endif
-       if (cpu_is_omap1610() || cpu_is_omap1710()) {
-               memcpy((void *)OMAP1610_SRAM_IDLE_SUSPEND,
-                      omap1610_idle_loop_suspend,
-                      omap1610_idle_loop_suspend_sz);
-               memcpy((void *)OMAP1610_SRAM_API_SUSPEND, omap1610_cpu_suspend,
-                      omap1610_cpu_suspend_sz);
-       } else if (cpu_is_omap5912()) {
-               memcpy((void *)OMAP5912_SRAM_IDLE_SUSPEND,
-                      omap1610_idle_loop_suspend,
-                      omap1610_idle_loop_suspend_sz);
-               memcpy((void *)OMAP5912_SRAM_API_SUSPEND, omap1610_cpu_suspend,
-                      omap1610_cpu_suspend_sz);
+               omap_sram_idle = omap_sram_push(omap1510_idle_loop_suspend,
+                                               omap1510_idle_loop_suspend_sz);
+               omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend,
+                                                  omap1510_cpu_suspend_sz);
+       } else if (cpu_is_omap16xx()) {
+               omap_sram_idle = omap_sram_push(omap1610_idle_loop_suspend,
+                                               omap1610_idle_loop_suspend_sz);
+               omap_sram_suspend = omap_sram_push(omap1610_cpu_suspend,
+                                                  omap1610_cpu_suspend_sz);
        }
 
+       if (omap_sram_idle == NULL || omap_sram_suspend == NULL) {
+               printk(KERN_ERR "PM not initialized: Missing SRAM support\n");
+               return -ENODEV;
+       }
+
+       pm_idle = omap_pm_idle;
+
+       setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq);
+#if 0
+       /* --- BEGIN BOARD-DEPENDENT CODE --- */
+       /* Sleepx mask direction */
+       omap_writew((omap_readw(0xfffb5008) & ~2), 0xfffb5008);
+       /* Unmask sleepx signal */
+       omap_writew((omap_readw(0xfffb5004) & ~2), 0xfffb5004);
+       /* --- END BOARD-DEPENDENT CODE --- */
+#endif
+
+       /* Program new power ramp-up time
+        * (0 for most boards since we don't lower voltage when in deep sleep)
+        */
+       omap_writew(ULPD_SETUP_ANALOG_CELL_3_VAL, ULPD_SETUP_ANALOG_CELL_3);
+
+       /* Setup ULPD POWER_CTRL_REG - enter deep sleep whenever possible */
+       omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL);
+
+       /* Configure IDLECT3 */
+       if (cpu_is_omap16xx())
+               omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3);
+
        pm_set_ops(&omap_pm_ops);
 
 #if defined(DEBUG) && defined(CONFIG_PROC_FS)
        omap_pm_init_proc();
 #endif
 
+       /* configure LOW_PWR pin */
+       omap_cfg_reg(T20_1610_LOW_PWR);
+
        return 0;
 }
 __initcall(omap_pm_init);
index 279490ce772b16bc9e47cd20718fe8e10ffc69ce..9f745836f6aac97e8b76e8e61c9b516d3d4bf388 100644 (file)
@@ -66,7 +66,7 @@ ENTRY(omap1510_idle_loop_suspend)
        @ get ARM_IDLECT2 into r2
        ldrh    r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
        mov     r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
-       orr     r5,r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
+       orr     r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
        strh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
 
        @ request ARM idle
@@ -76,7 +76,7 @@ ENTRY(omap1510_idle_loop_suspend)
        strh    r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
 
        mov     r5, #IDLE_WAIT_CYCLES & 0xff
-       orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00
+       orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00
 l_1510:        subs    r5, r5, #1
        bne     l_1510
 /*
@@ -96,7 +96,7 @@ l_1510:       subs    r5, r5, #1
        strh    r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
        strh    r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
 
-       ldmfd   sp!, {r0 - r12, pc}     @ restore regs and return
+       ldmfd   sp!, {r0 - r12, pc}             @ restore regs and return
 
 ENTRY(omap1510_idle_loop_suspend_sz)
        .word   . - omap1510_idle_loop_suspend
@@ -115,8 +115,8 @@ ENTRY(omap1610_idle_loop_suspend)
        @ turn off clock domains
        @ get ARM_IDLECT2 into r2
        ldrh    r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
-       mov     r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff
-       orr     r5,r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff00
+       mov     r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff
+       orr     r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00
        strh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
 
        @ request ARM idle
@@ -126,7 +126,7 @@ ENTRY(omap1610_idle_loop_suspend)
        strh    r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
 
        mov     r5, #IDLE_WAIT_CYCLES & 0xff
-       orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00
+       orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00
 l_1610:        subs    r5, r5, #1
        bne     l_1610
 /*
@@ -146,7 +146,7 @@ l_1610:     subs    r5, r5, #1
        strh    r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
        strh    r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
 
-       ldmfd   sp!, {r0 - r12, pc}     @ restore regs and return
+       ldmfd   sp!, {r0 - r12, pc}             @ restore regs and return
 
 ENTRY(omap1610_idle_loop_suspend_sz)
        .word   . - omap1610_idle_loop_suspend
@@ -208,7 +208,7 @@ ENTRY(omap1510_cpu_suspend)
 
        @ turn off clock domains
        mov     r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
-       orr     r5,r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
+       orr     r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
        strh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
 
        @ request ARM idle
@@ -217,7 +217,7 @@ ENTRY(omap1510_cpu_suspend)
        strh    r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
 
        mov     r5, #IDLE_WAIT_CYCLES & 0xff
-       orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00
+       orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00
 l_1510_2:
        subs    r5, r5, #1
        bne     l_1510_2
@@ -237,7 +237,7 @@ l_1510_2:
        strh    r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
 
        @ restore regs and return
-       ldmfd   sp!, {r0 - r12, pc}
+       ldmfd   sp!, {r0 - r12, pc}
 
 ENTRY(omap1510_cpu_suspend_sz)
        .word   . - omap1510_cpu_suspend
@@ -249,21 +249,26 @@ ENTRY(omap1610_cpu_suspend)
        @ save registers on stack
        stmfd   sp!, {r0 - r12, lr}
 
+       @ Drain write cache
+       mov     r4, #0
+       mcr     p15, 0, r0, c7, c10, 4
+       nop
+
        @ load base address of Traffic Controller
-       mov     r4, #TCMIF_ASM_BASE & 0xff000000
-       orr     r4, r4, #TCMIF_ASM_BASE & 0x00ff0000
-       orr     r4, r4, #TCMIF_ASM_BASE & 0x0000ff00
+       mov     r6, #TCMIF_ASM_BASE & 0xff000000
+       orr     r6, r6, #TCMIF_ASM_BASE & 0x00ff0000
+       orr     r6, r6, #TCMIF_ASM_BASE & 0x0000ff00
 
        @ prepare to put SDRAM into self-refresh manually
-       ldr     r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
-       orr     r5, r5, #SELF_REFRESH_MODE & 0xff000000
-       orr     r5, r5, #SELF_REFRESH_MODE & 0x000000ff
-       str     r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+       ldr     r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+       orr     r9, r7, #SELF_REFRESH_MODE & 0xff000000
+       orr     r9, r9, #SELF_REFRESH_MODE & 0x000000ff
+       str     r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
 
        @ prepare to put EMIFS to Sleep
-       ldr     r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
-       orr     r5, r5, #IDLE_EMIFS_REQUEST & 0xff
-       str     r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+       ldr     r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+       orr     r9, r8, #IDLE_EMIFS_REQUEST & 0xff
+       str     r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
 
        @ load base address of ARM_IDLECT1 and ARM_IDLECT2
        mov     r4, #CLKGEN_REG_ASM_BASE & 0xff000000
@@ -271,26 +276,22 @@ ENTRY(omap1610_cpu_suspend)
        orr     r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
 
        @ turn off clock domains
-       mov     r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff
-       orr     r5,r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff00
-       strh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
-
-       @ work around errata of OMAP1610/5912. Enable (!) peripheral
-       @ clock to let the chip go into deep sleep
-       ldrh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
-       orr     r5,r5, #EN_PERCK_BIT & 0xff
+       @ do not disable PERCK (0x04)
+       mov     r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff
+       orr     r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00
        strh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
 
        @ request ARM idle
-       mov     r3, #OMAP1610_DEEP_SLEEP_REQUEST & 0xff
-       orr     r3, r3, #OMAP1610_DEEP_SLEEP_REQUEST & 0xff00
+       mov     r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff
+       orr     r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00
        strh    r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
 
-       mov     r5, #IDLE_WAIT_CYCLES & 0xff
-       orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00
-l_1610_2:
-       subs    r5, r5, #1
-       bne     l_1610_2
+       @ disable instruction cache
+       mrc     p15, 0, r9, c1, c0, 0
+       bic     r2, r9, #0x1000
+       mcr     p15, 0, r2, c1, c0, 0
+       nop
+
 /*
  * Let's wait for the next wake up event to wake us up. r0 can't be
  * used here because r0 holds ARM_IDLECT1
@@ -301,13 +302,21 @@ l_1610_2:
  * omap1610_cpu_suspend()'s resume point.
  *
  * It will just start executing here, so we'll restore stuff from the
- * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
+ * stack.
  */
+       @ re-enable Icache
+       mcr     p15, 0, r9, c1, c0, 0
+
+       @ reset the ARM_IDLECT1 and ARM_IDLECT2.
        strh    r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
        strh    r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
 
+       @ Restore EMIFF controls
+       str     r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+       str     r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+
        @ restore regs and return
-       ldmfd   sp!, {r0 - r12, pc}
+       ldmfd   sp!, {r0 - r12, pc}
 
 ENTRY(omap1610_cpu_suspend_sz)
        .word   . - omap1610_cpu_suspend
diff --git a/arch/arm/plat-omap/sram-fn.S b/arch/arm/plat-omap/sram-fn.S
new file mode 100644 (file)
index 0000000..4bea369
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * linux/arch/arm/plat-omap/sram.S
+ *
+ * Functions that need to be run in internal SRAM
+ *
+ * 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/config.h>
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/arch/io.h>
+#include <asm/arch/hardware.h>
+
+       .text
+
+/*
+ * Reprograms ULPD and CKCTL.
+ */
+ENTRY(sram_reprogram_clock)
+       stmfd   sp!, {r0 - r12, lr}             @ save registers on stack
+
+       mov     r2, #IO_ADDRESS(DPLL_CTL) & 0xff000000
+       orr     r2, r2, #IO_ADDRESS(DPLL_CTL) & 0x00ff0000
+       orr     r2, r2, #IO_ADDRESS(DPLL_CTL) & 0x0000ff00
+
+       mov     r3, #IO_ADDRESS(ARM_CKCTL) & 0xff000000
+       orr     r3, r3, #IO_ADDRESS(ARM_CKCTL) & 0x00ff0000
+       orr     r3, r3, #IO_ADDRESS(ARM_CKCTL) & 0x0000ff00
+
+       tst     r0, #1 << 4                     @ want lock mode?
+       beq     newck                           @ nope
+       bic     r0, r0, #1 << 4                 @ else clear lock bit
+       strh    r0, [r2]                        @ set dpll into bypass mode
+       orr     r0, r0, #1 << 4                 @ set lock bit again
+
+newck:
+       strh    r1, [r3]                        @ write new ckctl value
+       strh    r0, [r2]                        @ write new dpll value
+
+       mov     r4, #0x0700                     @ let the clocks settle
+       orr     r4, r4, #0x00ff
+delay: sub     r4, r4, #1
+       cmp     r4, #0
+       bne     delay
+
+lock:  ldrh    r4, [r2], #0                    @ read back dpll value
+       tst     r0, #1 << 4                     @ want lock mode?
+       beq     out                             @ nope
+       tst     r4, #1 << 0                     @ dpll rate locked?
+       beq     lock                            @ try again
+
+out:
+       ldmfd   sp!, {r0 - r12, pc}             @ restore regs and return
+ENTRY(sram_reprogram_clock_sz)
+       .word   . - sram_reprogram_clock
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
new file mode 100644 (file)
index 0000000..7719a40
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * linux/arch/arm/plat-omap/sram.c
+ *
+ * OMAP SRAM detection and management
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Written by Tony Lindgren <tony@atomide.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/mach/map.h>
+#include <asm/io.h>
+#include <asm/cacheflush.h>
+
+#include "sram.h"
+
+#define OMAP1_SRAM_BASE                0xd0000000
+#define OMAP1_SRAM_START       0x20000000
+#define SRAM_BOOTLOADER_SZ     0x80
+
+static unsigned long omap_sram_base;
+static unsigned long omap_sram_size;
+static unsigned long omap_sram_ceil;
+
+/*
+ * The amount of SRAM depends on the core type:
+ * 730 = 200K, 1510 = 512K, 5912 = 256K, 1610 = 16K, 1710 = 16K
+ * Note that we cannot try to test for SRAM here because writes
+ * to secure SRAM will hang the system. Also the SRAM is not
+ * yet mapped at this point.
+ */
+void __init omap_detect_sram(void)
+{
+       omap_sram_base = OMAP1_SRAM_BASE;
+
+       if (cpu_is_omap730())
+               omap_sram_size = 0x32000;
+       else if (cpu_is_omap1510())
+               omap_sram_size = 0x80000;
+       else if (cpu_is_omap1610() || cpu_is_omap1621() || cpu_is_omap1710())
+               omap_sram_size = 0x4000;
+       else if (cpu_is_omap1611())
+               omap_sram_size = 0x3e800;
+       else {
+               printk(KERN_ERR "Could not detect SRAM size\n");
+               omap_sram_size = 0x4000;
+       }
+
+       printk(KERN_INFO "SRAM size: 0x%lx\n", omap_sram_size);
+       omap_sram_ceil = omap_sram_base + omap_sram_size;
+}
+
+static struct map_desc omap_sram_io_desc[] __initdata = {
+       { OMAP1_SRAM_BASE, OMAP1_SRAM_START, 0, MT_DEVICE }
+};
+
+/*
+ * In order to use last 2kB of SRAM on 1611b, we must round the size
+ * up to multiple of PAGE_SIZE. We cannot use ioremap for SRAM, as
+ * clock init needs SRAM early.
+ */
+void __init omap_map_sram(void)
+{
+       if (omap_sram_size == 0)
+               return;
+
+       omap_sram_io_desc[0].length = (omap_sram_size + PAGE_SIZE-1)/PAGE_SIZE;
+       omap_sram_io_desc[0].length *= PAGE_SIZE;
+       iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc));
+
+       /*
+        * Looks like we need to preserve some bootloader code at the
+        * beginning of SRAM for jumping to flash for reboot to work...
+        */
+       memset((void *)omap_sram_base + SRAM_BOOTLOADER_SZ, 0,
+              omap_sram_size - SRAM_BOOTLOADER_SZ);
+}
+
+static void (*_omap_sram_reprogram_clock)(u32 dpllctl, u32 ckctl) = NULL;
+
+void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl)
+{
+       if (_omap_sram_reprogram_clock == NULL)
+               panic("Cannot use SRAM");
+
+       return _omap_sram_reprogram_clock(dpllctl, ckctl);
+}
+
+void * omap_sram_push(void * start, unsigned long size)
+{
+       if (size > (omap_sram_ceil - (omap_sram_base + SRAM_BOOTLOADER_SZ))) {
+               printk(KERN_ERR "Not enough space in SRAM\n");
+               return NULL;
+       }
+       omap_sram_ceil -= size;
+       omap_sram_ceil &= ~0x3;
+       memcpy((void *)omap_sram_ceil, start, size);
+
+       return (void *)omap_sram_ceil;
+}
+
+void __init omap_sram_init(void)
+{
+       omap_detect_sram();
+       omap_map_sram();
+       _omap_sram_reprogram_clock = omap_sram_push(sram_reprogram_clock,
+                                                   sram_reprogram_clock_sz);
+}
diff --git a/arch/arm/plat-omap/sram.h b/arch/arm/plat-omap/sram.h
new file mode 100644 (file)
index 0000000..71984ef
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * linux/arch/arm/plat-omap/sram.h
+ *
+ * Interface for functions that need to be run in internal SRAM
+ *
+ * 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 __ARCH_ARM_OMAP_SRAM_H
+#define __ARCH_ARM_OMAP_SRAM_H
+
+extern void * omap_sram_push(void * start, unsigned long size);
+extern void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl);
+
+/* Do not use these */
+extern void sram_reprogram_clock(u32 ckctl, u32 dpllctl);
+extern unsigned long sram_reprogram_clock_sz;
+
+#endif
index 25bc4a8dd763d8c7f7e10c8fa8fb6ef6baf3fa9d..98f1c76f86606f039dad4501651f371f7056f099 100644 (file)
@@ -41,6 +41,7 @@
 
 /* These routines should handle the standard chip-specific modes
  * for usb0/1/2 ports, covering basic mux and transceiver setup.
+ * Call omap_usb_init() once, from INIT_MACHINE().
  *
  * Some board-*.c files will need to set up additional mux options,
  * like for suspend handling, vbus sensing, GPIOs, and the D+ pullup.
index 1f0373267306c20738862141b4dc8f5bd3173bb0..1f00b3d03a076a9a9f70a694198c42e96d9277ba 100644 (file)
@@ -55,6 +55,10 @@ config GENERIC_BUST_SPINLOCK
 config GENERIC_ISA_DMA
        bool
 
+config ARCH_MAY_HAVE_PC_FDC
+       bool
+       default y
+
 source "init/Kconfig"
 
 
index ada8985530a592a147378f7c97fd39e6882e9e60..e9cb8ef4f3fbdf0ae44197e9db145d506f28226a 100644 (file)
@@ -17,10 +17,6 @@ ifeq ($(CONFIG_FRAME_POINTER),y)
 CFLAGS         +=-fno-omit-frame-pointer -mno-sched-prolog
 endif
 
-ifeq ($(CONFIG_DEBUG_INFO),y)
-CFLAGS         +=-g
-endif
-
 CFLAGS_BOOT    :=-mapcs-26 -mcpu=arm3 -msoft-float -Uarm
 CFLAGS         +=-mapcs-26 -mcpu=arm3 -msoft-float -Uarm
 AFLAGS         +=-mapcs-26 -mcpu=arm3 -msoft-float
index 356d9809cc0bb5ad4ba011025889061a92d711ea..ce2055bdc9ee82c342e35f63ca98835d66c9715b 100644 (file)
@@ -454,14 +454,13 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
                if (ka->sa.sa_flags & SA_ONESHOT)
                        ka->sa.sa_handler = SIG_DFL;
 
-               if (!(ka->sa.sa_flags & SA_NODEFER)) {
-                       spin_lock_irq(&tsk->sighand->siglock);
-                       sigorsets(&tsk->blocked, &tsk->blocked,
-                                 &ka->sa.sa_mask);
+               spin_lock_irq(&tsk->sighand->siglock);
+               sigorsets(&tsk->blocked, &tsk->blocked,
+                         &ka->sa.sa_mask);
+               if (!(ka->sa.sa_flags & SA_NODEFER))
                        sigaddset(&tsk->blocked, sig);
-                       recalc_sigpending();
-                       spin_unlock_irq(&tsk->sighand->siglock);
-               }
+               recalc_sigpending();
+               spin_unlock_irq(&tsk->sighand->siglock);
                return;
        }
 
index 549a6b2e177ef4ca666bfd4355d9b21d7b2dafe8..e66aedd02fad7c2eccf15259efb97c162e3dec5a 100644 (file)
@@ -114,7 +114,7 @@ static unsigned long next_rtc_update;
  */
 static inline void do_set_rtc(void)
 {
-       if (time_status & STA_UNSYNC || set_rtc == NULL)
+       if (!ntp_synced() || set_rtc == NULL)
                return;
 
 //FIXME - timespec.tv_sec is a time_t not unsigned long
@@ -189,10 +189,7 @@ int do_settimeofday(struct timespec *tv)
 
        xtime.tv_sec = tv->tv_sec;
        xtime.tv_nsec = tv->tv_nsec;
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
        return 0;
index cd72324935c45cd1c01c74b88880352cbc5a5b78..0a1d62a23614884b82d8af1bef6d06f127fb629c 100644 (file)
@@ -5,10 +5,13 @@ config PROFILING
        bool "Kernel profiling support"
 
 config SYSTEM_PROFILER
-        bool "System profiling support"
+       bool "System profiling support"
+
+source "lib/Kconfig.debug"
 
 config ETRAX_KGDB
        bool "Use kernel GDB debugger"
+       depends on DEBUG_KERNEL
        ---help---
          The CRIS version of gdb can be used to remotely debug a running
          Linux kernel via the serial debug port.  Provided you have gdb-cris
@@ -22,25 +25,11 @@ config ETRAX_KGDB
          this option is turned on!
 
 
-config DEBUG_INFO
-        bool "Compile the kernel with debug info"
-        help
-          If you say Y here the resulting kernel image will include
-          debugging info resulting in a larger kernel image.
-          Say Y here only if you plan to use gdb to debug the kernel.
-          If you don't debug the kernel, you can say N.
-
-config FRAME_POINTER
-        bool "Compile the kernel with frame pointers"
-        help
-          If you say Y here the resulting kernel image will be slightly larger
-          and slower, but it will give very useful debugging information.
-          If you don't debug the kernel, you can say N, but we may not be able
-          to solve problems without frame pointers.
-
 config DEBUG_NMI_OOPS
-       bool "NMI causes oops printout"
-       help
-         If the system locks up without any debug information you can say Y
-         here to make it possible to dump an OOPS with an external NMI.
+       bool "NMI causes oops printout"
+       depends on DEBUG_KERNEL
+       help
+         If the system locks up without any debug information you can say Y
+         here to make it possible to dump an OOPS with an external NMI.
+
 endmenu
index 85e0032e664ffcf93e489841d4ba19ee3746e42a..693771961f859f788c4eec80bbea21df85ecf1e7 100644 (file)
@@ -517,13 +517,12 @@ handle_signal(int canrestart, unsigned long sig,
        if (ka->sa.sa_flags & SA_ONESHOT)
                ka->sa.sa_handler = SIG_DFL;
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
index 6b7b4e0802e3ac23991abd09fcfbf9312cf274f8..dc3dfe9b4a1aa64f09a8b35a3947d8b32e1346ec 100644 (file)
@@ -240,7 +240,7 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
         * The division here is not time critical since it will run once in 
         * 11 minutes
         */
-       if ((time_status & STA_UNSYNC) == 0 &&
+       if (ntp_synced() &&
            xtime.tv_sec > last_rtc_update + 660 &&
            (xtime.tv_nsec / 1000) >= 500000 - (tick_nsec / 1000) / 2 &&
            (xtime.tv_nsec / 1000) <= 500000 + (tick_nsec / 1000) / 2) {
index fb4c79d5b76b028840c5cf665e6807b27a86f475..0a3614dab88701b2827e26ce5858c94bf824852e 100644 (file)
@@ -568,13 +568,12 @@ handle_signal(int canrestart, unsigned long sig,
        if (ka->sa.sa_flags & SA_ONESHOT)
                ka->sa.sa_handler = SIG_DFL;
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
index fa2d4323da2592deef3bd5652110d953e7696850..a2d99b4aedcda34f22a5c1ec10fc4f3250050b0c 100644 (file)
@@ -114,10 +114,7 @@ int do_settimeofday(struct timespec *tv)
        set_normalized_timespec(&xtime, sec, nsec);
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
        return 0;
index 62cfbd9b4f98d6f2f62c79743cc085557e8af5e2..1a76d52471902975401703d0bcb3d107fc787238 100644 (file)
@@ -71,7 +71,6 @@ EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memcmp);
 EXPORT_SYMBOL(memscan);
 EXPORT_SYMBOL(memmove);
-EXPORT_SYMBOL(strtok);
 
 EXPORT_SYMBOL(get_wchan);
 
index 36a2dffc8ebd953618a70a4f365b23ce3349ea3f..d4ccc0728dfe4b97ac7065f4b0fe344e72320873 100644 (file)
@@ -506,13 +506,12 @@ static void handle_signal(unsigned long sig, siginfo_t *info,
        else
                setup_frame(sig, ka, oldset, regs);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked, sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 } /* end handle_signal() */
 
 /*****************************************************************************/
index 075db6644694b460b6428ce41223cc2c546dabbc..8d6558b00e44fe86128e03922e4a402ac18fee8b 100644 (file)
@@ -85,7 +85,7 @@ static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
         * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
         * called as close as possible to 500 ms before the new second starts.
         */
-       if ((time_status & STA_UNSYNC) == 0 &&
+       if (ntp_synced() &&
            xtime.tv_sec > last_rtc_update + 660 &&
            (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
            (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2
@@ -216,10 +216,7 @@ int do_settimeofday(struct timespec *tv)
        set_normalized_timespec(&xtime, sec, nsec);
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
        return 0;
index 5aab87eae1f941f8373d8ea1db5882ced9b447d0..f13d5e82d4b977065727d88ce45be4f0904c7dbb 100644 (file)
@@ -488,13 +488,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
        else
                setup_frame(sig, ka, oldset, regs);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
index 8a600218334dfcaba3501a34e9e09d0c40f6395a..af8c5d2057dd56ed6fa30257cd9ab2cd5c521bcb 100644 (file)
@@ -116,10 +116,7 @@ int do_settimeofday(struct timespec *tv)
 
        xtime.tv_sec = tv->tv_sec;
        xtime.tv_nsec = tv->tv_nsec;
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
        return 0;
index 619d843ba231492dfb7100d32734ea711c391e7c..5d51b38bd70d2d0bdc86ed14ee613e3f4786c993 100644 (file)
@@ -14,6 +14,10 @@ config X86
          486, 586, Pentiums, and various instruction-set-compatible chips by
          AMD, Cyrix, and others.
 
+config SEMAPHORE_SLEEPERS
+       bool
+       default y
+
 config MMU
        bool
        default y
@@ -33,6 +37,10 @@ config GENERIC_IOMAP
        bool
        default y
 
+config ARCH_MAY_HAVE_PC_FDC
+       bool
+       default y
+
 source "init/Kconfig"
 
 menu "Processor type and features"
@@ -754,6 +762,7 @@ config NUMA
        depends on SMP && HIGHMEM64G && (X86_NUMAQ || X86_GENERICARCH || (X86_SUMMIT && ACPI))
        default n if X86_PC
        default y if (X86_NUMAQ || X86_SUMMIT)
+       select SPARSEMEM_STATIC
 
 # Need comments to help the hapless user trying to turn on NUMA support
 comment "NUMA (NUMA-Q) requires SMP, 64GB highmem support"
@@ -1313,6 +1322,11 @@ config GENERIC_IRQ_PROBE
        bool
        default y
 
+config GENERIC_PENDING_IRQ
+       bool
+       depends on GENERIC_HARDIRQS && SMP
+       default y
+
 config X86_SMP
        bool
        depends on SMP && !X86_VOYAGER
index 8cb420f40c58f106972d5ec830e8cd382378470c..ca668d9df16411c29d2928d230c32b99a129104f 100644 (file)
@@ -82,7 +82,7 @@ start:
 # This is the setup header, and it must start at %cs:2 (old 0x9020:2)
 
                .ascii  "HdrS"          # header signature
-               .word   0x0203          # header version number (>= 0x0105)
+               .word   0x0204          # header version number (>= 0x0105)
                                        # or else old loadlin-1.5 will fail)
 realmode_swtch:        .word   0, 0            # default_switch, SETUPSEG
 start_sys_seg: .word   SYSSEG
index 6835f6d47c31e8f5913a670c6bd7bdd57f1e7b7c..05798419a6a93f25be4f347d2eea5e6f04e5ddf6 100644 (file)
@@ -177,7 +177,9 @@ int main(int argc, char ** argv)
                die("Output: seek failed");
        buf[0] = (sys_size & 0xff);
        buf[1] = ((sys_size >> 8) & 0xff);
-       if (write(1, buf, 2) != 2)
+       buf[2] = ((sys_size >> 16) & 0xff);
+       buf[3] = ((sys_size >> 24) & 0xff);
+       if (write(1, buf, 4) != 4)
                die("Write of image length failed");
 
        return 0;                                           /* Everything is OK */
index 4cc83b322b362dc85739cc42e8df6b955bc7da7e..64682a0edacf5c54490fe5928c1ce716f82be522 100644 (file)
@@ -7,7 +7,7 @@ extra-y := head.o init_task.o vmlinux.lds
 obj-y  := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
                ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \
                pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \
-               doublefault.o quirks.o
+               doublefault.o quirks.o i8237.o
 
 obj-y                          += cpu/
 obj-y                          += timers/
index b7808a89d94507fd41abf6c24bd471d5d9099209..34ee500c26e59a4a992dd6c89dbb5cd68ae3bd92 100644 (file)
@@ -833,6 +833,9 @@ acpi_process_madt(void)
                if (!error) {
                        acpi_lapic = 1;
 
+#ifdef CONFIG_X86_GENERICARCH
+                       generic_bigsmp_probe();
+#endif
                        /*
                         * Parse MADT IO-APIC entries
                         */
index 4553ffd94b1f9f2a645e75ba6982e80c40543cd0..46ce9b248f5510088ca7fd1765fcfdd86ea44bd9 100644 (file)
@@ -613,8 +613,8 @@ void __devinit cpu_init(void)
        memcpy(thread->tls_array, &per_cpu(cpu_gdt_table, cpu),
                GDT_ENTRY_TLS_ENTRIES * 8);
 
-       __asm__ __volatile__("lgdt %0" : : "m" (cpu_gdt_descr[cpu]));
-       __asm__ __volatile__("lidt %0" : : "m" (idt_descr));
+       load_gdt(&cpu_gdt_descr[cpu]);
+       load_idt(&idt_descr);
 
        /*
         * Delete NT
@@ -642,12 +642,12 @@ void __devinit cpu_init(void)
        asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs");
 
        /* Clear all 6 debug registers: */
-
-#define CD(register) set_debugreg(0, register)
-
-       CD(0); CD(1); CD(2); CD(3); /* no db4 and db5 */; CD(6); CD(7);
-
-#undef CD
+       set_debugreg(0, 0);
+       set_debugreg(0, 1);
+       set_debugreg(0, 2);
+       set_debugreg(0, 3);
+       set_debugreg(0, 6);
+       set_debugreg(0, 7);
 
        /*
         * Force FPU initialization:
index 04e3563da4fea19e2a7f0c2c0e0053855cda67f1..bf02b5026e6238ea13ff4743d856ecc5b9be5206 100644 (file)
@@ -64,8 +64,6 @@ static int dont_scale_voltage;
 #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg)
 
 
-#define __hlt()     __asm__ __volatile__("hlt": : :"memory")
-
 /* Clock ratios multiplied by 10 */
 static int clock_ratio[32];
 static int eblcr_table[32];
@@ -168,11 +166,9 @@ static void do_powersaver(union msr_longhaul *longhaul,
        outb(0xFE,0x21);        /* TMR0 only */
        outb(0xFF,0x80);        /* delay */
 
-       local_irq_enable();
-
-       __hlt();
+       safe_halt();
        wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
-       __hlt();
+       halt();
 
        local_irq_disable();
 
@@ -251,9 +247,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
                bcr2.bits.CLOCKMUL = clock_ratio_index;
                local_irq_disable();
                wrmsrl (MSR_VIA_BCR2, bcr2.val);
-               local_irq_enable();
-
-               __hlt();
+               safe_halt();
 
                /* Disable software clock multiplier */
                rdmsrl (MSR_VIA_BCR2, bcr2.val);
index ba4b01138c8f62d9a01c5b3f2d10549f3edc54c5..ff87cc22b323aee87165e19be9688bc300dcc978 100644 (file)
@@ -132,11 +132,7 @@ static void __init set_cx86_memwb(void)
        setCx86(CX86_CCR2, getCx86(CX86_CCR2) & ~0x04);
        /* set 'Not Write-through' */
        cr0 = 0x20000000;
-       __asm__("movl %%cr0,%%eax\n\t"
-               "orl %0,%%eax\n\t"
-               "movl %%eax,%%cr0\n"
-               : : "r" (cr0)
-               :"ax");
+       write_cr0(read_cr0() | cr0);
        /* CCR2 bit 2: lock NW bit and set WT1 */
        setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x14 );
 }
index a2c33c1a46c5c9a620c3d33c5372ead800120a44..43601de0f6331415aaa8b19594112a3de080ae4f 100644 (file)
@@ -82,16 +82,13 @@ static void __devinit Intel_errata_workarounds(struct cpuinfo_x86 *c)
  */
 static int __devinit num_cpu_cores(struct cpuinfo_x86 *c)
 {
-       unsigned int eax;
+       unsigned int eax, ebx, ecx, edx;
 
        if (c->cpuid_level < 4)
                return 1;
 
-       __asm__("cpuid"
-               : "=a" (eax)
-               : "0" (4), "c" (0)
-               : "bx", "dx");
-
+       /* Intel has a non-standard dependency on %ecx for this CPUID level. */
+       cpuid_count(4, 0, &eax, &ebx, &ecx, &edx);
        if (eax & 0x1f)
                return ((eax >> 26) + 1);
        else
index 6c55b50cf048af7bef9df49bb78b6daa8b71c4ac..9e0d5f83cb9f63879b59b06683449d97923e4ce9 100644 (file)
@@ -305,6 +305,9 @@ static void __devinit cache_shared_cpu_map_setup(unsigned int cpu, int index)
 {
        struct _cpuid4_info     *this_leaf;
        unsigned long num_threads_sharing;
+#ifdef CONFIG_X86_HT
+       struct cpuinfo_x86 *c = cpu_data + cpu;
+#endif
 
        this_leaf = CPUID4_INFO_IDX(cpu, index);
        num_threads_sharing = 1 + this_leaf->eax.split.num_threads_sharing;
@@ -314,10 +317,12 @@ static void __devinit cache_shared_cpu_map_setup(unsigned int cpu, int index)
 #ifdef CONFIG_X86_HT
        else if (num_threads_sharing == smp_num_siblings)
                this_leaf->shared_cpu_map = cpu_sibling_map[cpu];
-#endif
+       else if (num_threads_sharing == (c->x86_num_cores * smp_num_siblings))
+               this_leaf->shared_cpu_map = cpu_core_map[cpu];
        else
-               printk(KERN_INFO "Number of CPUs sharing cache didn't match "
+               printk(KERN_DEBUG "Number of CPUs sharing cache didn't match "
                                "any known set of CPUs\n");
+#endif
 }
 #else
 static void __init cache_shared_cpu_map_setup(unsigned int cpu, int index) {}
index 764cac64e21191310d198e3bd590564e6939d76f..dd4ebd6af7e4cc5e014dff4ab72a3a1ac2650619 100644 (file)
@@ -561,7 +561,7 @@ struct mtrr_value {
 
 static struct mtrr_value * mtrr_state;
 
-static int mtrr_save(struct sys_device * sysdev, u32 state)
+static int mtrr_save(struct sys_device * sysdev, pm_message_t state)
 {
        int i;
        int size = num_var_ranges * sizeof(struct mtrr_value);
index e5fab12f79261a7856d298ac92765d1efa4d075b..913be77bb8446569d99175f0ff6556567bea531b 100644 (file)
@@ -153,7 +153,7 @@ static int crash_nmi_callback(struct pt_regs *regs, int cpu)
        disable_local_APIC();
        atomic_dec(&waiting_for_crash_ipi);
        /* Assume hlt works */
-       __asm__("hlt");
+       halt();
        for(;;);
 
        return 1;
index a3cdf894302b0d5fe48ecfcd1581be41d99c8932..58516e2ac1728fb4cbeb31e7dae8e23d237f5e27 100644 (file)
@@ -6,32 +6,28 @@
 #include <linux/bootmem.h>
 
 
-struct dmi_header {
-       u8 type;
-       u8 length;
-       u16 handle;
-};
-
-#undef DMI_DEBUG
-
-#ifdef DMI_DEBUG
-#define dmi_printk(x) printk x
-#else
-#define dmi_printk(x)
-#endif
-
 static char * __init dmi_string(struct dmi_header *dm, u8 s)
 {
        u8 *bp = ((u8 *) dm) + dm->length;
+       char *str = "";
 
-       if (!s)
-               return "";
-       s--;
-       while (s > 0 && *bp) {
-               bp += strlen(bp) + 1;
+       if (s) {
                s--;
-       }
-       return bp;
+               while (s > 0 && *bp) {
+                       bp += strlen(bp) + 1;
+                       s--;
+               }
+
+               if (*bp != 0) {
+                       str = alloc_bootmem(strlen(bp) + 1);
+                       if (str != NULL)
+                               strcpy(str, bp);
+                       else
+                               printk(KERN_ERR "dmi_string: out of memory.\n");
+               }
+       }
+
+       return str;
 }
 
 /*
@@ -84,69 +80,76 @@ static int __init dmi_checksum(u8 *buf)
        return sum == 0;
 }
 
-static int __init dmi_iterate(void (*decode)(struct dmi_header *))
+static char *dmi_ident[DMI_STRING_MAX];
+static LIST_HEAD(dmi_devices);
+
+/*
+ *     Save a DMI string
+ */
+static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
 {
-       u8 buf[15];
-       char __iomem *p, *q;
+       char *p, *d = (char*) dm;
 
-       /*
-        * no iounmap() for that ioremap(); it would be a no-op, but it's
-        * so early in setup that sucker gets confused into doing what
-        * it shouldn't if we actually call it.
-        */
-       p = ioremap(0xF0000, 0x10000);
+       if (dmi_ident[slot])
+               return;
+
+       p = dmi_string(dm, d[string]);
        if (p == NULL)
-               return -1;
+               return;
 
-       for (q = p; q < p + 0x10000; q += 16) {
-               memcpy_fromio(buf, q, 15);
-               if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
-                       u16 num = (buf[13] << 8) | buf[12];
-                       u16 len = (buf[7] << 8) | buf[6];
-                       u32 base = (buf[11] << 24) | (buf[10] << 16) |
-                                  (buf[9] << 8) | buf[8];
+       dmi_ident[slot] = p;
+}
 
-                       /*
-                        * DMI version 0.0 means that the real version is taken from
-                        * the SMBIOS version, which we don't know at this point.
-                        */
-                       if (buf[14] != 0)
-                               printk(KERN_INFO "DMI %d.%d present.\n",
-                                       buf[14] >> 4, buf[14] & 0xF);
-                       else
-                               printk(KERN_INFO "DMI present.\n");
+static void __init dmi_save_devices(struct dmi_header *dm)
+{
+       int i, count = (dm->length - sizeof(struct dmi_header)) / 2;
+       struct dmi_device *dev;
+
+       for (i = 0; i < count; i++) {
+               char *d = ((char *) dm) + (i * 2);
 
-                       dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n",
-                               num, len));
-                       dmi_printk((KERN_INFO "DMI table at 0x%08X.\n", base));
+               /* Skip disabled device */
+               if ((*d & 0x80) == 0)
+                       continue;
 
-                       if (dmi_table(base,len, num, decode) == 0)
-                               return 0;
+               dev = alloc_bootmem(sizeof(*dev));
+               if (!dev) {
+                       printk(KERN_ERR "dmi_save_devices: out of memory.\n");
+                       break;
                }
+
+               dev->type = *d++ & 0x7f;
+               dev->name = dmi_string(dm, *d);
+               dev->device_data = NULL;
+
+               list_add(&dev->list, &dmi_devices);
        }
-       return -1;
 }
 
-static char *dmi_ident[DMI_STRING_MAX];
-
-/*
- *     Save a DMI string
- */
-static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
+static void __init dmi_save_ipmi_device(struct dmi_header *dm)
 {
-       char *d = (char*)dm;
-       char *p = dmi_string(dm, d[string]);
+       struct dmi_device *dev;
+       void * data;
 
-       if (p == NULL || *p == 0)
+       data = alloc_bootmem(dm->length);
+       if (data == NULL) {
+               printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n");
                return;
-       if (dmi_ident[slot])
+       }
+
+       memcpy(data, dm, dm->length);
+
+       dev = alloc_bootmem(sizeof(*dev));
+       if (!dev) {
+               printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n");
                return;
+       }
 
-       dmi_ident[slot] = alloc_bootmem(strlen(p) + 1);
-       if(dmi_ident[slot])
-               strcpy(dmi_ident[slot], p);
-       else
-               printk(KERN_ERR "dmi_save_ident: out of memory.\n");
+       dev->type = DMI_DEV_TYPE_IPMI;
+       dev->name = "IPMI controller";
+       dev->device_data = data;
+
+       list_add(&dev->list, &dmi_devices);
 }
 
 /*
@@ -156,42 +159,69 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
  */
 static void __init dmi_decode(struct dmi_header *dm)
 {
-       u8 *data __attribute__((__unused__)) = (u8 *)dm;
-       
        switch(dm->type) {
-       case  0:
-               dmi_printk(("BIOS Vendor: %s\n", dmi_string(dm, data[4])));
+       case 0:         /* BIOS Information */
                dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
-               dmi_printk(("BIOS Version: %s\n", dmi_string(dm, data[5])));
                dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
-               dmi_printk(("BIOS Release: %s\n", dmi_string(dm, data[8])));
                dmi_save_ident(dm, DMI_BIOS_DATE, 8);
                break;
-       case 1:
-               dmi_printk(("System Vendor: %s\n", dmi_string(dm, data[4])));
+       case 1:         /* System Information */
                dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
-               dmi_printk(("Product Name: %s\n", dmi_string(dm, data[5])));
                dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
-               dmi_printk(("Version: %s\n", dmi_string(dm, data[6])));
                dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
-               dmi_printk(("Serial Number: %s\n", dmi_string(dm, data[7])));
                dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7);
                break;
-       case 2:
-               dmi_printk(("Board Vendor: %s\n", dmi_string(dm, data[4])));
+       case 2:         /* Base Board Information */
                dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
-               dmi_printk(("Board Name: %s\n", dmi_string(dm, data[5])));
                dmi_save_ident(dm, DMI_BOARD_NAME, 5);
-               dmi_printk(("Board Version: %s\n", dmi_string(dm, data[6])));
                dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
                break;
+       case 10:        /* Onboard Devices Information */
+               dmi_save_devices(dm);
+               break;
+       case 38:        /* IPMI Device Information */
+               dmi_save_ipmi_device(dm);
        }
 }
 
 void __init dmi_scan_machine(void)
 {
-       if (dmi_iterate(dmi_decode))
-               printk(KERN_INFO "DMI not present.\n");
+       u8 buf[15];
+       char __iomem *p, *q;
+
+       /*
+        * no iounmap() for that ioremap(); it would be a no-op, but it's
+        * so early in setup that sucker gets confused into doing what
+        * it shouldn't if we actually call it.
+        */
+       p = ioremap(0xF0000, 0x10000);
+       if (p == NULL)
+               goto out;
+
+       for (q = p; q < p + 0x10000; q += 16) {
+               memcpy_fromio(buf, q, 15);
+               if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
+                       u16 num = (buf[13] << 8) | buf[12];
+                       u16 len = (buf[7] << 8) | buf[6];
+                       u32 base = (buf[11] << 24) | (buf[10] << 16) |
+                                  (buf[9] << 8) | buf[8];
+
+                       /*
+                        * DMI version 0.0 means that the real version is taken from
+                        * the SMBIOS version, which we don't know at this point.
+                        */
+                       if (buf[14] != 0)
+                               printk(KERN_INFO "DMI %d.%d present.\n",
+                                       buf[14] >> 4, buf[14] & 0xF);
+                       else
+                               printk(KERN_INFO "DMI present.\n");
+
+                       if (dmi_table(base,len, num, dmi_decode) == 0)
+                               return;
+               }
+       }
+
+out:   printk(KERN_INFO "DMI not present.\n");
 }
 
 
@@ -218,9 +248,9 @@ int dmi_check_system(struct dmi_system_id *list)
                        /* No match */
                        goto fail;
                }
+               count++;
                if (d->callback && d->callback(d))
                        break;
-               count++;
 fail:          d++;
        }
 
@@ -240,3 +270,32 @@ char *dmi_get_system_info(int field)
        return dmi_ident[field];
 }
 EXPORT_SYMBOL(dmi_get_system_info);
+
+/**
+ *     dmi_find_device - find onboard device by type/name
+ *     @type: device type or %DMI_DEV_TYPE_ANY to match all device types
+ *     @desc: device name string or %NULL to match all
+ *     @from: previous device found in search, or %NULL for new search.
+ *
+ *     Iterates through the list of known onboard devices. If a device is
+ *     found with a matching @vendor and @device, a pointer to its device
+ *     structure is returned.  Otherwise, %NULL is returned.
+ *     A new search is initiated by passing %NULL to the @from argument.
+ *     If @from is not %NULL, searches continue from next device.
+ */
+struct dmi_device * dmi_find_device(int type, const char *name,
+                                   struct dmi_device *from)
+{
+       struct list_head *d, *head = from ? &from->list : &dmi_devices;
+
+       for(d = head->next; d != &dmi_devices; d = d->next) {
+               struct dmi_device *dev = list_entry(d, struct dmi_device, list);
+
+               if (((type == DMI_DEV_TYPE_ANY) || (dev->type == type)) &&
+                   ((name == NULL) || (strcmp(dev->name, name) == 0)))
+                       return dev;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL(dmi_find_device);
index 789af3e9fb1fff597529ea62a80fc81a9fa2cc6c..5edb1d379add9d24bd353e2ade6c176d0a3cdca5 100644 (file)
@@ -20,7 +20,7 @@ static void doublefault_fn(void)
        struct Xgt_desc_struct gdt_desc = {0, 0};
        unsigned long gdt, tss;
 
-       __asm__ __volatile__("sgdt %0": "=m" (gdt_desc): :"memory");
+       store_gdt(&gdt_desc);
        gdt = gdt_desc.address;
 
        printk("double fault, gdt at %08lx [%d bytes]\n", gdt, gdt_desc.size);
index 385883ea8c199d1008d0db050e1c71ec32ce64ec..ecad519fd395f6a17607c65737713f5aca26c3d3 100644 (file)
@@ -79,7 +79,7 @@ static void efi_call_phys_prelog(void)
         * directory. If I have PSE, I just need to duplicate one entry in
         * page directory.
         */
-       __asm__ __volatile__("movl %%cr4, %0":"=r"(cr4));
+       cr4 = read_cr4();
 
        if (cr4 & X86_CR4_PSE) {
                efi_bak_pg_dir_pointer[0].pgd =
@@ -104,8 +104,7 @@ static void efi_call_phys_prelog(void)
        local_flush_tlb();
 
        cpu_gdt_descr[0].address = __pa(cpu_gdt_descr[0].address);
-       __asm__ __volatile__("lgdt %0":"=m"
-                           (*(struct Xgt_desc_struct *) __pa(&cpu_gdt_descr[0])));
+       load_gdt((struct Xgt_desc_struct *) __pa(&cpu_gdt_descr[0]));
 }
 
 static void efi_call_phys_epilog(void)
@@ -114,8 +113,8 @@ static void efi_call_phys_epilog(void)
 
        cpu_gdt_descr[0].address =
                (unsigned long) __va(cpu_gdt_descr[0].address);
-       __asm__ __volatile__("lgdt %0":"=m"(cpu_gdt_descr));
-       __asm__ __volatile__("movl %%cr4, %0":"=r"(cr4));
+       load_gdt(&cpu_gdt_descr[0]);
+       cr4 = read_cr4();
 
        if (cr4 & X86_CR4_PSE) {
                swapper_pg_dir[pgd_index(0)].pgd =
@@ -233,22 +232,23 @@ void __init efi_map_memmap(void)
 {
        memmap.map = NULL;
 
-       memmap.map = (efi_memory_desc_t *)
-               bt_ioremap((unsigned long) memmap.phys_map,
-                       (memmap.nr_map * sizeof(efi_memory_desc_t)));
-
+       memmap.map = bt_ioremap((unsigned long) memmap.phys_map,
+                       (memmap.nr_map * memmap.desc_size));
        if (memmap.map == NULL)
                printk(KERN_ERR PFX "Could not remap the EFI memmap!\n");
+
+       memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
 }
 
 #if EFI_DEBUG
 static void __init print_efi_memmap(void)
 {
        efi_memory_desc_t *md;
+       void *p;
        int i;
 
-       for (i = 0; i < memmap.nr_map; i++) {
-               md = &memmap.map[i];
+       for (p = memmap.map, i = 0; p < memmap.map_end; p += memmap.desc_size, i++) {
+               md = p;
                printk(KERN_INFO "mem%02u: type=%u, attr=0x%llx, "
                        "range=[0x%016llx-0x%016llx) (%lluMB)\n",
                        i, md->type, md->attribute, md->phys_addr,
@@ -271,10 +271,10 @@ void efi_memmap_walk(efi_freemem_callback_t callback, void *arg)
        } prev, curr;
        efi_memory_desc_t *md;
        unsigned long start, end;
-       int i;
+       void *p;
 
-       for (i = 0; i < memmap.nr_map; i++) {
-               md = &memmap.map[i];
+       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+               md = p;
 
                if ((md->num_pages == 0) || (!is_available_memory(md)))
                        continue;
@@ -325,6 +325,7 @@ void __init efi_init(void)
        memmap.phys_map = EFI_MEMMAP;
        memmap.nr_map = EFI_MEMMAP_SIZE/EFI_MEMDESC_SIZE;
        memmap.desc_version = EFI_MEMDESC_VERSION;
+       memmap.desc_size = EFI_MEMDESC_SIZE;
 
        efi.systab = (efi_system_table_t *)
                boot_ioremap((unsigned long) efi_phys.systab,
@@ -428,22 +429,30 @@ void __init efi_init(void)
                printk(KERN_ERR PFX "Could not map the runtime service table!\n");
 
        /* Map the EFI memory map for use until paging_init() */
-
-       memmap.map = (efi_memory_desc_t *)
-               boot_ioremap((unsigned long) EFI_MEMMAP, EFI_MEMMAP_SIZE);
-
+       memmap.map = boot_ioremap((unsigned long) EFI_MEMMAP, EFI_MEMMAP_SIZE);
        if (memmap.map == NULL)
                printk(KERN_ERR PFX "Could not map the EFI memory map!\n");
 
-       if (EFI_MEMDESC_SIZE != sizeof(efi_memory_desc_t)) {
-               printk(KERN_WARNING PFX "Warning! Kernel-defined memdesc doesn't "
-                          "match the one from EFI!\n");
-       }
+       memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
+
 #if EFI_DEBUG
        print_efi_memmap();
 #endif
 }
 
+static inline void __init check_range_for_systab(efi_memory_desc_t *md)
+{
+       if (((unsigned long)md->phys_addr <= (unsigned long)efi_phys.systab) &&
+               ((unsigned long)efi_phys.systab < md->phys_addr +
+               ((unsigned long)md->num_pages << EFI_PAGE_SHIFT))) {
+               unsigned long addr;
+
+               addr = md->virt_addr - md->phys_addr +
+                       (unsigned long)efi_phys.systab;
+               efi.systab = (efi_system_table_t *)addr;
+       }
+}
+
 /*
  * This function will switch the EFI runtime services to virtual mode.
  * Essentially, look through the EFI memmap and map every region that
@@ -457,43 +466,32 @@ void __init efi_enter_virtual_mode(void)
 {
        efi_memory_desc_t *md;
        efi_status_t status;
-       int i;
+       void *p;
 
        efi.systab = NULL;
 
-       for (i = 0; i < memmap.nr_map; i++) {
-               md = &memmap.map[i];
+       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+               md = p;
 
-               if (md->attribute & EFI_MEMORY_RUNTIME) {
-                       md->virt_addr =
-                               (unsigned long)ioremap(md->phys_addr,
-                                       md->num_pages << EFI_PAGE_SHIFT);
-                       if (!(unsigned long)md->virt_addr) {
-                               printk(KERN_ERR PFX "ioremap of 0x%lX failed\n",
-                                       (unsigned long)md->phys_addr);
-                       }
+               if (!(md->attribute & EFI_MEMORY_RUNTIME))
+                       continue;
 
-                       if (((unsigned long)md->phys_addr <=
-                                       (unsigned long)efi_phys.systab) &&
-                               ((unsigned long)efi_phys.systab <
-                                       md->phys_addr +
-                                       ((unsigned long)md->num_pages <<
-                                               EFI_PAGE_SHIFT))) {
-                               unsigned long addr;
-
-                               addr = md->virt_addr - md->phys_addr +
-                                               (unsigned long)efi_phys.systab;
-                               efi.systab = (efi_system_table_t *)addr;
-                       }
+               md->virt_addr = (unsigned long)ioremap(md->phys_addr,
+                       md->num_pages << EFI_PAGE_SHIFT);
+               if (!(unsigned long)md->virt_addr) {
+                       printk(KERN_ERR PFX "ioremap of 0x%lX failed\n",
+                               (unsigned long)md->phys_addr);
                }
+               /* update the virtual address of the EFI system table */
+               check_range_for_systab(md);
        }
 
        if (!efi.systab)
                BUG();
 
        status = phys_efi_set_virtual_address_map(
-                       sizeof(efi_memory_desc_t) * memmap.nr_map,
-                       sizeof(efi_memory_desc_t),
+                       memmap.desc_size * memmap.nr_map,
+                       memmap.desc_size,
                        memmap.desc_version,
                        memmap.phys_map);
 
@@ -533,10 +531,10 @@ efi_initialize_iomem_resources(struct resource *code_resource,
 {
        struct resource *res;
        efi_memory_desc_t *md;
-       int i;
+       void *p;
 
-       for (i = 0; i < memmap.nr_map; i++) {
-               md = &memmap.map[i];
+       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+               md = p;
 
                if ((md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) >
                    0x100000000ULL)
@@ -613,10 +611,10 @@ efi_initialize_iomem_resources(struct resource *code_resource,
 u32 efi_mem_type(unsigned long phys_addr)
 {
        efi_memory_desc_t *md;
-       int i;
+       void *p;
 
-       for (i = 0; i < memmap.nr_map; i++) {
-               md = &memmap.map[i];
+       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+               md = p;
                if ((md->phys_addr <= phys_addr) && (phys_addr <
                        (md->phys_addr + (md-> num_pages << EFI_PAGE_SHIFT)) ))
                        return md->type;
@@ -627,10 +625,10 @@ u32 efi_mem_type(unsigned long phys_addr)
 u64 efi_mem_attributes(unsigned long phys_addr)
 {
        efi_memory_desc_t *md;
-       int i;
+       void *p;
 
-       for (i = 0; i < memmap.nr_map; i++) {
-               md = &memmap.map[i];
+       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+               md = p;
                if ((md->phys_addr <= phys_addr) && (phys_addr <
                        (md->phys_addr + (md-> num_pages << EFI_PAGE_SHIFT)) ))
                        return md->attribute;
index a991d4e5edd247c962b49d5d288d052183b7c138..3aad03839660de38dd8c24361ecbd6814de5eb52 100644 (file)
@@ -203,7 +203,7 @@ sysenter_past_esp:
        GET_THREAD_INFO(%ebp)
 
        /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
-       testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(%ebp)
+       testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
        jnz syscall_trace_entry
        cmpl $(nr_syscalls), %eax
        jae syscall_badsys
@@ -226,9 +226,9 @@ ENTRY(system_call)
        pushl %eax                      # save orig_eax
        SAVE_ALL
        GET_THREAD_INFO(%ebp)
-                                       # system call tracing in operation
+                                       # system call tracing in operation / emulation
        /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
-       testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(%ebp)
+       testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
        jnz syscall_trace_entry
        cmpl $(nr_syscalls), %eax
        jae syscall_badsys
@@ -338,6 +338,9 @@ syscall_trace_entry:
        movl %esp, %eax
        xorl %edx,%edx
        call do_syscall_trace
+       cmpl $0, %eax
+       jne resume_userspace            # ret != 0 -> running under PTRACE_SYSEMU,
+                                       # so must skip actual syscall
        movl ORIG_EAX(%esp), %eax
        cmpl $(nr_syscalls), %eax
        jnae syscall_call
@@ -504,7 +507,7 @@ label:                                              \
        pushl $__KERNEL_CS;                     \
        pushl $sysenter_past_esp
 
-ENTRY(debug)
+KPROBE_ENTRY(debug)
        cmpl $sysenter_entry,(%esp)
        jne debug_stack_correct
        FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn)
@@ -515,7 +518,7 @@ debug_stack_correct:
        movl %esp,%eax                  # pt_regs pointer
        call do_debug
        jmp ret_from_exception
-
+       .previous .text
 /*
  * NMI is doubly nasty. It can happen _while_ we're handling
  * a debug fault, and the debug fault hasn't yet been able to
@@ -588,13 +591,14 @@ nmi_16bit_stack:
        .long 1b,iret_exc
 .previous
 
-ENTRY(int3)
+KPROBE_ENTRY(int3)
        pushl $-1                       # mark this as an int
        SAVE_ALL
        xorl %edx,%edx          # zero error code
        movl %esp,%eax          # pt_regs pointer
        call do_int3
        jmp ret_from_exception
+       .previous .text
 
 ENTRY(overflow)
        pushl $0
@@ -628,17 +632,19 @@ ENTRY(stack_segment)
        pushl $do_stack_segment
        jmp error_code
 
-ENTRY(general_protection)
+KPROBE_ENTRY(general_protection)
        pushl $do_general_protection
        jmp error_code
+       .previous .text
 
 ENTRY(alignment_check)
        pushl $do_alignment_check
        jmp error_code
 
-ENTRY(page_fault)
+KPROBE_ENTRY(page_fault)
        pushl $do_page_fault
        jmp error_code
+       .previous .text
 
 #ifdef CONFIG_X86_MCE
 ENTRY(machine_check)
index 4477bb107098c2863ee85a0ef8a27374147ca494..0480ca9e9e577a989d96e71e012b8b6e4f8e0c1d 100644 (file)
@@ -77,6 +77,32 @@ ENTRY(startup_32)
        subl %edi,%ecx
        shrl $2,%ecx
        rep ; stosl
+/*
+ * Copy bootup parameters out of the way.
+ * Note: %esi still has the pointer to the real-mode data.
+ * With the kexec as boot loader, parameter segment might be loaded beyond
+ * kernel image and might not even be addressable by early boot page tables.
+ * (kexec on panic case). Hence copy out the parameters before initializing
+ * page tables.
+ */
+       movl $(boot_params - __PAGE_OFFSET),%edi
+       movl $(PARAM_SIZE/4),%ecx
+       cld
+       rep
+       movsl
+       movl boot_params - __PAGE_OFFSET + NEW_CL_POINTER,%esi
+       andl %esi,%esi
+       jnz 2f                  # New command line protocol
+       cmpw $(OLD_CL_MAGIC),OLD_CL_MAGIC_ADDR
+       jne 1f
+       movzwl OLD_CL_OFFSET,%esi
+       addl $(OLD_CL_BASE_ADDR),%esi
+2:
+       movl $(saved_command_line - __PAGE_OFFSET),%edi
+       movl $(COMMAND_LINE_SIZE/4),%ecx
+       rep
+       movsl
+1:
 
 /*
  * Initialize page tables.  This creates a PDE and a set of page
@@ -214,28 +240,6 @@ ENTRY(startup_32_smp)
  */
        call setup_idt
 
-/*
- * Copy bootup parameters out of the way.
- * Note: %esi still has the pointer to the real-mode data.
- */
-       movl $boot_params,%edi
-       movl $(PARAM_SIZE/4),%ecx
-       cld
-       rep
-       movsl
-       movl boot_params+NEW_CL_POINTER,%esi
-       andl %esi,%esi
-       jnz 2f                  # New command line protocol
-       cmpw $(OLD_CL_MAGIC),OLD_CL_MAGIC_ADDR
-       jne 1f
-       movzwl OLD_CL_OFFSET,%esi
-       addl $(OLD_CL_BASE_ADDR),%esi
-2:
-       movl $saved_command_line,%edi
-       movl $(COMMAND_LINE_SIZE/4),%ecx
-       rep
-       movsl
-1:
 checkCPUtype:
 
        movl $-1,X86_CPUID              #  -1 for no CPUID initially
diff --git a/arch/i386/kernel/i8237.c b/arch/i386/kernel/i8237.c
new file mode 100644 (file)
index 0000000..c36d1c0
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * i8237.c: 8237A DMA controller suspend functions.
+ *
+ * Written by Pierre Ossman, 2005.
+ */
+
+#include <linux/init.h>
+#include <linux/sysdev.h>
+
+#include <asm/dma.h>
+
+/*
+ * This module just handles suspend/resume issues with the
+ * 8237A DMA controller (used for ISA and LPC).
+ * Allocation is handled in kernel/dma.c and normal usage is
+ * in asm/dma.h.
+ */
+
+static int i8237A_resume(struct sys_device *dev)
+{
+       unsigned long flags;
+       int i;
+
+       flags = claim_dma_lock();
+
+       dma_outb(DMA1_RESET_REG, 0);
+       dma_outb(DMA2_RESET_REG, 0);
+
+       for (i = 0;i < 8;i++) {
+               set_dma_addr(i, 0x000000);
+               /* DMA count is a bit weird so this is not 0 */
+               set_dma_count(i, 1);
+       }
+
+       /* Enable cascade DMA or channel 0-3 won't work */
+       enable_dma(4);
+
+       release_dma_lock(flags);
+
+       return 0;
+}
+
+static int i8237A_suspend(struct sys_device *dev, pm_message_t state)
+{
+       return 0;
+}
+
+static struct sysdev_class i8237_sysdev_class = {
+       set_kset_name("i8237"),
+       .suspend = i8237A_suspend,
+       .resume = i8237A_resume,
+};
+
+static struct sys_device device_i8237A = {
+       .id     = 0,
+       .cls    = &i8237_sysdev_class,
+};
+
+static int __init i8237A_init_sysfs(void)
+{
+       int error = sysdev_class_register(&i8237_sysdev_class);
+       if (!error)
+               error = sysdev_register(&device_i8237A);
+       return error;
+}
+
+device_initcall(i8237A_init_sysfs);
index 6578f40bd5012a0af9385d889f8a6cd37a6546a9..0e727e6da5c981743f66bf4fdf74a925f0482b7f 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/acpi.h>
 #include <linux/module.h>
 #include <linux/sysdev.h>
+
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/desc.h>
@@ -77,7 +78,7 @@ static struct irq_pin_list {
        int apic, pin, next;
 } irq_2_pin[PIN_MAP_SIZE];
 
-int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
+int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
 #ifdef CONFIG_PCI_MSI
 #define vector_to_irq(vector)  \
        (platform_legacy_irq(vector) ? vector : vector_irq[vector])
@@ -222,13 +223,21 @@ static void clear_IO_APIC (void)
                        clear_IO_APIC_pin(apic, pin);
 }
 
+#ifdef CONFIG_SMP
 static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
 {
        unsigned long flags;
        int pin;
        struct irq_pin_list *entry = irq_2_pin + irq;
        unsigned int apicid_value;
+       cpumask_t tmp;
        
+       cpus_and(tmp, cpumask, cpu_online_map);
+       if (cpus_empty(tmp))
+               tmp = TARGET_CPUS;
+
+       cpus_and(cpumask, tmp, CPU_MASK_ALL);
+
        apicid_value = cpu_mask_to_apicid(cpumask);
        /* Prepare to do the io_apic_write */
        apicid_value = apicid_value << 24;
@@ -242,6 +251,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
                        break;
                entry = irq_2_pin + entry->next;
        }
+       set_irq_info(irq, cpumask);
        spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
@@ -259,7 +269,6 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
 #  define Dprintk(x...) 
 # endif
 
-cpumask_t __cacheline_aligned pending_irq_balance_cpumask[NR_IRQS];
 
 #define IRQBALANCE_CHECK_ARCH -999
 static int irqbalance_disabled = IRQBALANCE_CHECK_ARCH;
@@ -328,12 +337,7 @@ static inline void balance_irq(int cpu, int irq)
        cpus_and(allowed_mask, cpu_online_map, irq_affinity[irq]);
        new_cpu = move(cpu, allowed_mask, now, 1);
        if (cpu != new_cpu) {
-               irq_desc_t *desc = irq_desc + irq;
-               unsigned long flags;
-
-               spin_lock_irqsave(&desc->lock, flags);
-               pending_irq_balance_cpumask[irq] = cpumask_of_cpu(new_cpu);
-               spin_unlock_irqrestore(&desc->lock, flags);
+               set_pending_irq(irq, cpumask_of_cpu(new_cpu));
        }
 }
 
@@ -528,16 +532,12 @@ tryanotherirq:
        cpus_and(tmp, target_cpu_mask, allowed_mask);
 
        if (!cpus_empty(tmp)) {
-               irq_desc_t *desc = irq_desc + selected_irq;
-               unsigned long flags;
 
                Dprintk("irq = %d moved to cpu = %d\n",
                                selected_irq, min_loaded);
                /* mark for change destination */
-               spin_lock_irqsave(&desc->lock, flags);
-               pending_irq_balance_cpumask[selected_irq] =
-                                       cpumask_of_cpu(min_loaded);
-               spin_unlock_irqrestore(&desc->lock, flags);
+               set_pending_irq(selected_irq, cpumask_of_cpu(min_loaded));
+
                /* Since we made a change, come back sooner to 
                 * check for more variation.
                 */
@@ -568,7 +568,8 @@ 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_balance_cpumask[i] = cpumask_of_cpu(0);
+               pending_irq_cpumask[i] = cpumask_of_cpu(0);
+               set_pending_irq(i, cpumask_of_cpu(0));
        }
 
        for ( ; ; ) {
@@ -647,20 +648,9 @@ int __init irqbalance_disable(char *str)
 
 __setup("noirqbalance", irqbalance_disable);
 
-static inline void move_irq(int irq)
-{
-       /* note - we hold the desc->lock */
-       if (unlikely(!cpus_empty(pending_irq_balance_cpumask[irq]))) {
-               set_ioapic_affinity_irq(irq, pending_irq_balance_cpumask[irq]);
-               cpus_clear(pending_irq_balance_cpumask[irq]);
-       }
-}
-
 late_initcall(balanced_irq_init);
-
-#else /* !CONFIG_IRQBALANCE */
-static inline void move_irq(int irq) { }
 #endif /* CONFIG_IRQBALANCE */
+#endif /* CONFIG_SMP */
 
 #ifndef CONFIG_SMP
 void fastcall send_IPI_self(int vector)
@@ -820,6 +810,7 @@ EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
  * we need to reprogram the ioredtbls to cater for the cpus which have come online
  * so mask in all cases should simply be TARGET_CPUS
  */
+#ifdef CONFIG_SMP
 void __init setup_ioapic_dest(void)
 {
        int pin, ioapic, irq, irq_entry;
@@ -838,6 +829,7 @@ void __init setup_ioapic_dest(void)
 
        }
 }
+#endif
 
 /*
  * EISA Edge/Level control register, ELCR
@@ -1127,7 +1119,7 @@ static inline int IO_APIC_irq_trigger(int irq)
 }
 
 /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
-u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
+u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
 
 int assign_irq_vector(int irq)
 {
@@ -1249,6 +1241,7 @@ static void __init setup_IO_APIC_irqs(void)
                spin_lock_irqsave(&ioapic_lock, flags);
                io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
                io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
+               set_native_irq_info(irq, TARGET_CPUS);
                spin_unlock_irqrestore(&ioapic_lock, flags);
        }
        }
@@ -1944,6 +1937,7 @@ static void ack_edge_ioapic_vector(unsigned int vector)
 {
        int irq = vector_to_irq(vector);
 
+       move_irq(vector);
        ack_edge_ioapic_irq(irq);
 }
 
@@ -1958,6 +1952,7 @@ static void end_level_ioapic_vector (unsigned int vector)
 {
        int irq = vector_to_irq(vector);
 
+       move_irq(vector);
        end_level_ioapic_irq(irq);
 }
 
@@ -1975,14 +1970,17 @@ static void unmask_IO_APIC_vector (unsigned int vector)
        unmask_IO_APIC_irq(irq);
 }
 
+#ifdef CONFIG_SMP
 static void set_ioapic_affinity_vector (unsigned int vector,
                                        cpumask_t cpu_mask)
 {
        int irq = vector_to_irq(vector);
 
+       set_native_irq_info(vector, cpu_mask);
        set_ioapic_affinity_irq(irq, cpu_mask);
 }
 #endif
+#endif
 
 /*
  * Level and edge triggered IO-APIC interrupts need different handling,
@@ -1992,7 +1990,7 @@ static void set_ioapic_affinity_vector (unsigned int vector,
  * edge-triggered handler, without risking IRQ storms and other ugly
  * races.
  */
-static struct hw_interrupt_type ioapic_edge_type = {
+static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
        .typename       = "IO-APIC-edge",
        .startup        = startup_edge_ioapic,
        .shutdown       = shutdown_edge_ioapic,
@@ -2000,10 +1998,12 @@ static struct hw_interrupt_type ioapic_edge_type = {
        .disable        = disable_edge_ioapic,
        .ack            = ack_edge_ioapic,
        .end            = end_edge_ioapic,
+#ifdef CONFIG_SMP
        .set_affinity   = set_ioapic_affinity,
+#endif
 };
 
-static struct hw_interrupt_type ioapic_level_type = {
+static struct hw_interrupt_type ioapic_level_type __read_mostly = {
        .typename       = "IO-APIC-level",
        .startup        = startup_level_ioapic,
        .shutdown       = shutdown_level_ioapic,
@@ -2011,7 +2011,9 @@ static struct hw_interrupt_type ioapic_level_type = {
        .disable        = disable_level_ioapic,
        .ack            = mask_and_ack_level_ioapic,
        .end            = end_level_ioapic,
+#ifdef CONFIG_SMP
        .set_affinity   = set_ioapic_affinity,
+#endif
 };
 
 static inline void init_IO_APIC_traps(void)
@@ -2074,7 +2076,7 @@ static void ack_lapic_irq (unsigned int irq)
 
 static void end_lapic_irq (unsigned int i) { /* nothing */ }
 
-static struct hw_interrupt_type lapic_irq_type = {
+static struct hw_interrupt_type lapic_irq_type __read_mostly = {
        .typename       = "local-APIC-edge",
        .startup        = NULL, /* startup_irq() not used for IRQ0 */
        .shutdown       = NULL, /* shutdown_irq() not used for IRQ0 */
@@ -2569,6 +2571,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a
        spin_lock_irqsave(&ioapic_lock, flags);
        io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1));
        io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0));
+       set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS);
        spin_unlock_irqrestore(&ioapic_lock, flags);
 
        return 0;
index 8b25160393c1f557d99f60f6ccab11d487b25a4b..f2b37654777f522af8231e14a6520a572dcb9cfb 100644 (file)
@@ -132,6 +132,7 @@ asmlinkage long sys_iopl(unsigned long unused)
        volatile struct pt_regs * regs = (struct pt_regs *) &unused;
        unsigned int level = regs->ebx;
        unsigned int old = (regs->eflags >> 12) & 3;
+       struct thread_struct *t = &current->thread;
 
        if (level > 3)
                return -EINVAL;
@@ -140,8 +141,8 @@ asmlinkage long sys_iopl(unsigned long unused)
                if (!capable(CAP_SYS_RAWIO))
                        return -EPERM;
        }
-       regs->eflags = (regs->eflags &~ 0x3000UL) | (level << 12);
-       /* Make sure we return the long way (not sysenter) */
-       set_thread_flag(TIF_IRET);
+       t->iopl = level << 12;
+       regs->eflags = (regs->eflags & ~X86_EFLAGS_IOPL) | t->iopl;
+       set_iopl_mask(t->iopl);
        return 0;
 }
index a6d8c45961d3ccb33503f38535802d3a7e022afc..6345b430b105fd913c1fdca36768910e2f7fd580 100644 (file)
@@ -62,32 +62,32 @@ static inline int is_IF_modifier(kprobe_opcode_t opcode)
        return 0;
 }
 
-int arch_prepare_kprobe(struct kprobe *p)
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
 {
        return 0;
 }
 
-void arch_copy_kprobe(struct kprobe *p)
+void __kprobes arch_copy_kprobe(struct kprobe *p)
 {
        memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
        p->opcode = *p->addr;
 }
 
-void arch_arm_kprobe(struct kprobe *p)
+void __kprobes arch_arm_kprobe(struct kprobe *p)
 {
        *p->addr = BREAKPOINT_INSTRUCTION;
        flush_icache_range((unsigned long) p->addr,
                           (unsigned long) p->addr + sizeof(kprobe_opcode_t));
 }
 
-void arch_disarm_kprobe(struct kprobe *p)
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
 {
        *p->addr = p->opcode;
        flush_icache_range((unsigned long) p->addr,
                           (unsigned long) p->addr + sizeof(kprobe_opcode_t));
 }
 
-void arch_remove_kprobe(struct kprobe *p)
+void __kprobes arch_remove_kprobe(struct kprobe *p)
 {
 }
 
@@ -127,7 +127,8 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
                regs->eip = (unsigned long)&p->ainsn.insn;
 }
 
-void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
+void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+                                     struct pt_regs *regs)
 {
        unsigned long *sara = (unsigned long *)&regs->esp;
         struct kretprobe_instance *ri;
@@ -150,7 +151,7 @@ void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
  * Interrupts are disabled on entry as trap3 is an interrupt gate and they
  * remain disabled thorough out this function.
  */
-static int kprobe_handler(struct pt_regs *regs)
+static int __kprobes kprobe_handler(struct pt_regs *regs)
 {
        struct kprobe *p;
        int ret = 0;
@@ -176,7 +177,8 @@ static int kprobe_handler(struct pt_regs *regs)
                   Disarm the probe we just hit, and ignore it. */
                p = get_kprobe(addr);
                if (p) {
-                       if (kprobe_status == KPROBE_HIT_SS) {
+                       if (kprobe_status == KPROBE_HIT_SS &&
+                               *p->ainsn.insn == BREAKPOINT_INSTRUCTION) {
                                regs->eflags &= ~TF_MASK;
                                regs->eflags |= kprobe_saved_eflags;
                                unlock_kprobes();
@@ -220,7 +222,10 @@ static int kprobe_handler(struct pt_regs *regs)
                         * either a probepoint or a debugger breakpoint
                         * at this address.  In either case, no further
                         * handling of this interrupt is appropriate.
+                        * Back up over the (now missing) int3 and run
+                        * the original instruction.
                         */
+                       regs->eip -= sizeof(kprobe_opcode_t);
                        ret = 1;
                }
                /* Not one of ours: let kernel handle it */
@@ -259,7 +264,7 @@ no_kprobe:
 /*
  * Called when we hit the probe point at kretprobe_trampoline
  */
-int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 {
         struct kretprobe_instance *ri = NULL;
         struct hlist_head *head;
@@ -338,7 +343,7 @@ int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
  * that is atop the stack is the address following the copied instruction.
  * We need to make it the address following the original instruction.
  */
-static void resume_execution(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
 {
        unsigned long *tos = (unsigned long *)&regs->esp;
        unsigned long next_eip = 0;
@@ -444,8 +449,8 @@ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
 /*
  * Wrapper routine to for handling exceptions.
  */
-int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
-                            void *data)
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+                                      unsigned long val, void *data)
 {
        struct die_args *args = (struct die_args *)data;
        switch (val) {
@@ -473,7 +478,7 @@ int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
        return NOTIFY_DONE;
 }
 
-int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 {
        struct jprobe *jp = container_of(p, struct jprobe, kp);
        unsigned long addr;
@@ -495,7 +500,7 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
        return 1;
 }
 
-void jprobe_return(void)
+void __kprobes jprobe_return(void)
 {
        preempt_enable_no_resched();
        asm volatile ("       xchgl   %%ebx,%%esp     \n"
@@ -506,7 +511,7 @@ void jprobe_return(void)
                      (jprobe_saved_esp):"memory");
 }
 
-int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 {
        u8 *addr = (u8 *) (regs->eip - 1);
        unsigned long stack_addr = (unsigned long)jprobe_saved_esp;
index bb50afbee921cbbe19a4b4fb331e5505f12bd5f4..fe1ffa55587d483668d0f19adda973df7ea57190 100644 (file)
@@ -177,7 +177,7 @@ static int read_default_ldt(void __user * ptr, unsigned long bytecount)
 static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
 {
        struct mm_struct * mm = current->mm;
-       __u32 entry_1, entry_2, *lp;
+       __u32 entry_1, entry_2;
        int error;
        struct user_desc ldt_info;
 
@@ -205,8 +205,6 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
                        goto out_unlock;
        }
 
-       lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.ldt);
-
        /* Allow LDTs to be cleared by the user. */
        if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
                if (oldmode || LDT_empty(&ldt_info)) {
@@ -223,8 +221,7 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
 
        /* Install the new entry ...  */
 install:
-       *lp     = entry_1;
-       *(lp+1) = entry_2;
+       write_ldt_entry(mm->context.ldt, ldt_info.entry_number, entry_1, entry_2);
        error = 0;
 
 out_unlock:
index cb699a2aa1f84a915c8a1105fe66f19548adec10..a912fed4848273381ce5d0d3025dc81a1c7deff4 100644 (file)
 #include <asm/apic.h>
 #include <asm/cpufeature.h>
 #include <asm/desc.h>
-
-static inline unsigned long read_cr3(void)
-{
-       unsigned long cr3;
-       asm volatile("movl %%cr3,%0": "=r"(cr3));
-       return cr3;
-}
+#include <asm/system.h>
 
 #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
 
@@ -99,10 +93,7 @@ static void set_idt(void *newidt, __u16 limit)
        curidt.size    = limit;
        curidt.address = (unsigned long)newidt;
 
-       __asm__ __volatile__ (
-               "lidtl %0\n"
-               : : "m" (curidt)
-               );
+       load_idt(&curidt);
 };
 
 
@@ -114,10 +105,7 @@ static void set_gdt(void *newgdt, __u16 limit)
        curgdt.size    = limit;
        curgdt.address = (unsigned long)newgdt;
 
-       __asm__ __volatile__ (
-               "lgdtl %0\n"
-               : : "m" (curgdt)
-               );
+       load_gdt(&curgdt);
 };
 
 static void load_segments(void)
index a77c612aad003fc66a637d87bd091ddafd114208..165f13158c60c188a63ddd22530b9bf2bc160108 100644 (file)
@@ -164,7 +164,8 @@ static void collect_cpu_info (void *unused)
        }
 
        wrmsr(MSR_IA32_UCODE_REV, 0, 0);
-       __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
+       /* see notes above for revision 1.07.  Apparent chip bug */
+       serialize_cpu();
        /* get the current revision from MSR 0x8B */
        rdmsr(MSR_IA32_UCODE_REV, val[0], uci->rev);
        pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n",
@@ -377,7 +378,9 @@ static void do_update_one (void * unused)
                (unsigned long) uci->mc->bits >> 16 >> 16);
        wrmsr(MSR_IA32_UCODE_REV, 0, 0);
 
-       __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
+       /* see notes above for revision 1.07.  Apparent chip bug */
+       serialize_cpu();
+
        /* get the current revision from MSR 0x8B */
        rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
 
index ce838abb27d8b48ab23d06a191766b0e2f9c7272..5d0b9a8fc43dc1e1b1f1da28b560b24c5552abca 100644 (file)
@@ -65,6 +65,8 @@ int nr_ioapics;
 int pic_mode;
 unsigned long mp_lapic_addr;
 
+unsigned int def_to_bigsmp = 0;
+
 /* Processor that is doing the boot up */
 unsigned int boot_cpu_physical_apicid = -1U;
 /* Internal processor count */
@@ -120,7 +122,7 @@ static int MP_valid_apicid(int apicid, int version)
 
 static void __init MP_processor_info (struct mpc_config_processor *m)
 {
-       int ver, apicid;
+       int ver, apicid, cpu, found_bsp = 0;
        physid_mask_t tmp;
        
        if (!(m->mpc_cpuflag & CPU_ENABLED))
@@ -179,6 +181,7 @@ static void __init MP_processor_info (struct mpc_config_processor *m)
        if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
                Dprintk("    Bootup CPU\n");
                boot_cpu_physical_apicid = m->mpc_apicid;
+               found_bsp = 1;
        }
 
        if (num_processors >= NR_CPUS) {
@@ -202,6 +205,11 @@ static void __init MP_processor_info (struct mpc_config_processor *m)
                return;
        }
 
+       if (found_bsp)
+               cpu = 0;
+       else
+               cpu = num_processors - 1;
+       cpu_set(cpu, cpu_possible_map);
        tmp = apicid_to_cpu_present(apicid);
        physids_or(phys_cpu_present_map, phys_cpu_present_map, tmp);
        
@@ -213,6 +221,13 @@ static void __init MP_processor_info (struct mpc_config_processor *m)
                ver = 0x10;
        }
        apic_version[m->mpc_apicid] = ver;
+       if ((num_processors > 8) &&
+           APIC_XAPIC(ver) &&
+           (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL))
+               def_to_bigsmp = 1;
+       else
+               def_to_bigsmp = 0;
+
        bios_cpu_apicid[num_processors - 1] = m->mpc_apicid;
 }
 
index b2f03c39a6fed5eebcd381776ae0948e3f280d4a..03100d6fc5d6304522553d82d73f51b33f3e3f60 100644 (file)
 
 static struct class *msr_class;
 
-/* Note: "err" is handled in a funny way below.  Otherwise one version
-   of gcc or another breaks. */
-
 static inline int wrmsr_eio(u32 reg, u32 eax, u32 edx)
 {
        int err;
 
-       asm volatile ("1:       wrmsr\n"
-                     "2:\n"
-                     ".section .fixup,\"ax\"\n"
-                     "3:       movl %4,%0\n"
-                     " jmp 2b\n"
-                     ".previous\n"
-                     ".section __ex_table,\"a\"\n"
-                     " .align 4\n" "   .long 1b,3b\n" ".previous":"=&bDS" (err)
-                     :"a"(eax), "d"(edx), "c"(reg), "i"(-EIO), "0"(0));
-
+       err = wrmsr_safe(reg, eax, edx);
+       if (err)
+               err = -EIO;
        return err;
 }
 
@@ -70,18 +60,9 @@ static inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx)
 {
        int err;
 
-       asm volatile ("1:       rdmsr\n"
-                     "2:\n"
-                     ".section .fixup,\"ax\"\n"
-                     "3:       movl %4,%0\n"
-                     " jmp 2b\n"
-                     ".previous\n"
-                     ".section __ex_table,\"a\"\n"
-                     " .align 4\n"
-                     " .long 1b,3b\n"
-                     ".previous":"=&bDS" (err), "=a"(*eax), "=d"(*edx)
-                     :"c"(reg), "i"(-EIO), "0"(0));
-
+       err = rdmsr_safe(reg, eax, edx);
+       if (err)
+               err = -EIO;
        return err;
 }
 
index 8c242bb1ef4571685cebeb2c11c0160a92bc9695..0178457db72130b54d3170dfd8150742b8addfe1 100644 (file)
@@ -478,6 +478,11 @@ void touch_nmi_watchdog (void)
         */
        for (i = 0; i < NR_CPUS; i++)
                alert_counter[i] = 0;
+
+       /*
+        * Tickle the softlockup detector too:
+        */
+       touch_softlockup_watchdog();
 }
 
 extern void die_nmi(struct pt_regs *, const char *msg);
@@ -501,8 +506,11 @@ void nmi_watchdog_tick (struct pt_regs * regs)
                 */
                alert_counter[cpu]++;
                if (alert_counter[cpu] == 5*nmi_hz)
+                       /*
+                        * die_nmi will return ONLY if NOTIFY_STOP happens..
+                        */
                        die_nmi(regs, "NMI Watchdog detected LOCKUP");
-       } else {
+
                last_irq_sums[cpu] = sum;
                alert_counter[cpu] = 0;
        }
index e3f362e8af5b33e194ac5b7bad3a9ec294f0a030..b45cbf93d4391b49411cfdaecf7c1e084e184c33 100644 (file)
@@ -164,7 +164,7 @@ static inline void play_dead(void)
         */
        local_irq_disable();
        while (1)
-               __asm__ __volatile__("hlt":::"memory");
+               halt();
 }
 #else
 static inline void play_dead(void)
@@ -313,16 +313,12 @@ void show_regs(struct pt_regs * regs)
        printk(" DS: %04x ES: %04x\n",
                0xffff & regs->xds,0xffff & regs->xes);
 
-       __asm__("movl %%cr0, %0": "=r" (cr0));
-       __asm__("movl %%cr2, %0": "=r" (cr2));
-       __asm__("movl %%cr3, %0": "=r" (cr3));
-       /* This could fault if %cr4 does not exist */
-       __asm__("1: movl %%cr4, %0              \n"
-               "2:                             \n"
-               ".section __ex_table,\"a\"      \n"
-               ".long 1b,2b                    \n"
-               ".previous                      \n"
-               : "=r" (cr4): "0" (0));
+       cr0 = read_cr0();
+       cr2 = read_cr2();
+       cr3 = read_cr3();
+       if (current_cpu_data.x86 > 4) {
+               cr4 = read_cr4();
+       }
        printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4);
        show_trace(NULL, &regs->esp);
 }
@@ -682,21 +678,26 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
        __unlazy_fpu(prev_p);
 
        /*
-        * Reload esp0, LDT and the page table pointer:
+        * Reload esp0.
         */
        load_esp0(tss, next);
 
        /*
-        * Load the per-thread Thread-Local Storage descriptor.
+        * Save away %fs and %gs. No need to save %es and %ds, as
+        * those are always kernel segments while inside the kernel.
+        * Doing this before setting the new TLS descriptors avoids
+        * the situation where we temporarily have non-reloadable
+        * segments in %fs and %gs.  This could be an issue if the
+        * NMI handler ever used %fs or %gs (it does not today), or
+        * if the kernel is running inside of a hypervisor layer.
         */
-       load_TLS(next, cpu);
+       savesegment(fs, prev->fs);
+       savesegment(gs, prev->gs);
 
        /*
-        * Save away %fs and %gs. No need to save %es and %ds, as
-        * those are always kernel segments while inside the kernel.
+        * Load the per-thread Thread-Local Storage descriptor.
         */
-       asm volatile("mov %%fs,%0":"=m" (prev->fs));
-       asm volatile("mov %%gs,%0":"=m" (prev->gs));
+       load_TLS(next, cpu);
 
        /*
         * Restore %fs and %gs if needed.
@@ -710,6 +711,12 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
        if (prev->gs | next->gs)
                loadsegment(gs, next->gs);
 
+       /*
+        * Restore IOPL if needed.
+        */
+       if (unlikely(prev->iopl != next->iopl))
+               set_iopl_mask(next->iopl);
+
        /*
         * Now maybe reload the debug registers
         */
index 0da59b42843cffebc8d104d09376b734cb4ca948..340980203b095f9cda5113c14369799815dad1e5 100644 (file)
@@ -271,6 +271,8 @@ static void clear_singlestep(struct task_struct *child)
 void ptrace_disable(struct task_struct *child)
 { 
        clear_singlestep(child);
+       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+       clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
 }
 
 /*
@@ -509,15 +511,20 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                  }
                  break;
 
+       case PTRACE_SYSEMU: /* continue and stop at next syscall, which will not be executed */
        case PTRACE_SYSCALL:    /* continue and stop at next (return from) syscall */
        case PTRACE_CONT:       /* restart after signal. */
                ret = -EIO;
                if (!valid_signal(data))
                        break;
-               if (request == PTRACE_SYSCALL) {
+               if (request == PTRACE_SYSEMU) {
+                       set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+               } else if (request == PTRACE_SYSCALL) {
                        set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               }
-               else {
+                       clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+               } else {
+                       clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
                        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
                }
                child->exit_code = data;
@@ -542,10 +549,17 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                wake_up_process(child);
                break;
 
+       case PTRACE_SYSEMU_SINGLESTEP: /* Same as SYSEMU, but singlestep if not syscall */
        case PTRACE_SINGLESTEP: /* set the trap flag. */
                ret = -EIO;
                if (!valid_signal(data))
                        break;
+
+               if (request == PTRACE_SYSEMU_SINGLESTEP)
+                       set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+               else
+                       clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+
                clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
                set_singlestep(child);
                child->exit_code = data;
@@ -678,26 +692,52 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
  * - triggered by current->work.syscall_trace
  */
 __attribute__((regparm(3)))
-void do_syscall_trace(struct pt_regs *regs, int entryexit)
+int do_syscall_trace(struct pt_regs *regs, int entryexit)
 {
+       int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU), ret = 0;
+       /* With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP for syscall
+        * interception. */
+       int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP);
+
        /* do the secure computing check first */
        secure_computing(regs->orig_eax);
 
-       if (unlikely(current->audit_context) && entryexit)
-               audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
+       if (unlikely(current->audit_context)) {
+               if (entryexit)
+                       audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
+               /* Debug traps, when using PTRACE_SINGLESTEP, must be sent only
+                * on the syscall exit path. Normally, when TIF_SYSCALL_AUDIT is
+                * not used, entry.S will call us only on syscall exit, not
+                * entry; so when TIF_SYSCALL_AUDIT is used we must avoid
+                * calling send_sigtrap() on syscall entry.
+                *
+                * Note that when PTRACE_SYSEMU_SINGLESTEP is used,
+                * is_singlestep is false, despite his name, so we will still do
+                * the correct thing.
+                */
+               else if (is_singlestep)
+                       goto out;
+       }
 
        if (!(current->ptrace & PT_PTRACED))
                goto out;
 
+       /* If a process stops on the 1st tracepoint with SYSCALL_TRACE
+        * and then is resumed with SYSEMU_SINGLESTEP, it will come in
+        * here. We have to check this and return */
+       if (is_sysemu && entryexit)
+               return 0;
+
        /* Fake a debug trap */
-       if (test_thread_flag(TIF_SINGLESTEP))
+       if (is_singlestep)
                send_sigtrap(current, regs, 0);
 
-       if (!test_thread_flag(TIF_SYSCALL_TRACE))
+       if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu)
                goto out;
 
        /* the 0x80 provides a way for the tracing parent to distinguish
           between a syscall stop and SIGTRAP delivery */
+       /* Note that the debugger could change the result of test_thread_flag!*/
        ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
 
        /*
@@ -709,9 +749,16 @@ void do_syscall_trace(struct pt_regs *regs, int entryexit)
                send_sig(current->exit_code, current, 1);
                current->exit_code = 0;
        }
+       ret = is_sysemu;
  out:
        if (unlikely(current->audit_context) && !entryexit)
                audit_syscall_entry(current, AUDIT_ARCH_I386, regs->orig_eax,
                                    regs->ebx, regs->ecx, regs->edx, regs->esi);
+       if (ret == 0)
+               return 0;
 
+       regs->orig_eax = -1; /* force skip of syscall restarting */
+       if (unlikely(current->audit_context))
+               audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
+       return 1;
 }
index c71fef31dc4797d891f10c5d8d257bbf11d73df7..1cbb9c0f47040d9eb430e738f81871ff18aeacee 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/dmi.h>
 #include <asm/uaccess.h>
 #include <asm/apic.h>
+#include <asm/desc.h>
 #include "mach_reboot.h"
 #include <linux/reboot_fixups.h>
 
@@ -242,13 +243,13 @@ void machine_real_restart(unsigned char *code, int length)
 
        /* Set up the IDT for real mode. */
 
-       __asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt));
+       load_idt(&real_mode_idt);
 
        /* Set up a GDT from which we can load segment descriptors for real
           mode.  The GDT is not used in real mode; it is just needed here to
           prepare the descriptors. */
 
-       __asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt));
+       load_gdt(&real_mode_gdt);
 
        /* Load the data segment registers, and thus the descriptors ready for
           real mode.  The base address of each segment is 0x100, 16 times the
@@ -316,7 +317,7 @@ void machine_emergency_restart(void)
        if (!reboot_thru_bios) {
                if (efi_enabled) {
                        efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, NULL);
-                       __asm__ __volatile__("lidt %0": :"m" (no_idt));
+                       load_idt(&no_idt);
                        __asm__ __volatile__("int3");
                }
                /* rebooting needs to touch the page at absolute addr 0 */
@@ -325,7 +326,7 @@ void machine_emergency_restart(void)
                        mach_reboot_fixups(); /* for board specific fixups */
                        mach_reboot();
                        /* That didn't work - force a triple fault.. */
-                       __asm__ __volatile__("lidt %0": :"m" (no_idt));
+                       load_idt(&no_idt);
                        __asm__ __volatile__("int3");
                }
        }
index 469f496e55c0f56787929fa1c387572097c9ddc8..7455ab6439438bca2722b0df63f823a93ccc032f 100644 (file)
  * rw semaphores implemented November 1999 by Benjamin LaHaise <bcrl@kvack.org>
  */
 #include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/err.h>
-#include <linux/init.h>
 #include <asm/semaphore.h>
 
-/*
- * Semaphores are implemented using a two-way counter:
- * The "count" variable is decremented for each process
- * that tries to acquire the semaphore, while the "sleeping"
- * variable is a count of such acquires.
- *
- * Notably, the inline "up()" and "down()" functions can
- * efficiently test if they need to do any extra work (up
- * needs to do something only if count was negative before
- * the increment operation.
- *
- * "sleeping" and the contention routine ordering is protected
- * by the spinlock in the semaphore's waitqueue head.
- *
- * Note that these functions are only called when there is
- * contention on the lock, and as such all this is the
- * "non-critical" part of the whole semaphore business. The
- * critical part is the inline stuff in <asm/semaphore.h>
- * where we want to avoid any extra jumps and calls.
- */
-
-/*
- * Logic:
- *  - only on a boundary condition do we need to care. When we go
- *    from a negative count to a non-negative, we wake people up.
- *  - when we go from a non-negative count to a negative do we
- *    (a) synchronize with the "sleeper" count and (b) make sure
- *    that we're on the wakeup list before we synchronize so that
- *    we cannot lose wakeup events.
- */
-
-static fastcall void __attribute_used__  __up(struct semaphore *sem)
-{
-       wake_up(&sem->wait);
-}
-
-static fastcall void __attribute_used__ __sched __down(struct semaphore * sem)
-{
-       struct task_struct *tsk = current;
-       DECLARE_WAITQUEUE(wait, tsk);
-       unsigned long flags;
-
-       tsk->state = TASK_UNINTERRUPTIBLE;
-       spin_lock_irqsave(&sem->wait.lock, flags);
-       add_wait_queue_exclusive_locked(&sem->wait, &wait);
-
-       sem->sleepers++;
-       for (;;) {
-               int sleepers = sem->sleepers;
-
-               /*
-                * Add "everybody else" into it. They aren't
-                * playing, because we own the spinlock in
-                * the wait_queue_head.
-                */
-               if (!atomic_add_negative(sleepers - 1, &sem->count)) {
-                       sem->sleepers = 0;
-                       break;
-               }
-               sem->sleepers = 1;      /* us - see -1 above */
-               spin_unlock_irqrestore(&sem->wait.lock, flags);
-
-               schedule();
-
-               spin_lock_irqsave(&sem->wait.lock, flags);
-               tsk->state = TASK_UNINTERRUPTIBLE;
-       }
-       remove_wait_queue_locked(&sem->wait, &wait);
-       wake_up_locked(&sem->wait);
-       spin_unlock_irqrestore(&sem->wait.lock, flags);
-       tsk->state = TASK_RUNNING;
-}
-
-static fastcall int __attribute_used__ __sched __down_interruptible(struct semaphore * sem)
-{
-       int retval = 0;
-       struct task_struct *tsk = current;
-       DECLARE_WAITQUEUE(wait, tsk);
-       unsigned long flags;
-
-       tsk->state = TASK_INTERRUPTIBLE;
-       spin_lock_irqsave(&sem->wait.lock, flags);
-       add_wait_queue_exclusive_locked(&sem->wait, &wait);
-
-       sem->sleepers++;
-       for (;;) {
-               int sleepers = sem->sleepers;
-
-               /*
-                * With signals pending, this turns into
-                * the trylock failure case - we won't be
-                * sleeping, and we* can't get the lock as
-                * it has contention. Just correct the count
-                * and exit.
-                */
-               if (signal_pending(current)) {
-                       retval = -EINTR;
-                       sem->sleepers = 0;
-                       atomic_add(sleepers, &sem->count);
-                       break;
-               }
-
-               /*
-                * Add "everybody else" into it. They aren't
-                * playing, because we own the spinlock in
-                * wait_queue_head. The "-1" is because we're
-                * still hoping to get the semaphore.
-                */
-               if (!atomic_add_negative(sleepers - 1, &sem->count)) {
-                       sem->sleepers = 0;
-                       break;
-               }
-               sem->sleepers = 1;      /* us - see -1 above */
-               spin_unlock_irqrestore(&sem->wait.lock, flags);
-
-               schedule();
-
-               spin_lock_irqsave(&sem->wait.lock, flags);
-               tsk->state = TASK_INTERRUPTIBLE;
-       }
-       remove_wait_queue_locked(&sem->wait, &wait);
-       wake_up_locked(&sem->wait);
-       spin_unlock_irqrestore(&sem->wait.lock, flags);
-
-       tsk->state = TASK_RUNNING;
-       return retval;
-}
-
-/*
- * Trylock failed - make sure we correct for
- * having decremented the count.
- *
- * We could have done the trylock with a
- * single "cmpxchg" without failure cases,
- * but then it wouldn't work on a 386.
- */
-static fastcall int __attribute_used__ __down_trylock(struct semaphore * sem)
-{
-       int sleepers;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sem->wait.lock, flags);
-       sleepers = sem->sleepers + 1;
-       sem->sleepers = 0;
-
-       /*
-        * Add "everybody else" and us into it. They aren't
-        * playing, because we own the spinlock in the
-        * wait_queue_head.
-        */
-       if (!atomic_add_negative(sleepers, &sem->count)) {
-               wake_up_locked(&sem->wait);
-       }
-
-       spin_unlock_irqrestore(&sem->wait.lock, flags);
-       return 1;
-}
-
-
 /*
  * The semaphore operations have a special calling sequence that
  * allow us to do a simpler in-line version of them. These routines
index af4de58cab543362bb19d8e31c85006cd7c17e9d..e29fd5aeaf8e4fa9dfa5f73281e17b7079c153f9 100644 (file)
@@ -82,7 +82,7 @@ EXPORT_SYMBOL(efi_enabled);
 /* cpu data as detected by the assembly code in head.S */
 struct cpuinfo_x86 new_cpu_data __initdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
 /* common cpu data for all cpus */
-struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
+struct cpuinfo_x86 boot_cpu_data __read_mostly = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
 EXPORT_SYMBOL(boot_cpu_data);
 
 unsigned long mmu_cr4_features;
@@ -370,12 +370,16 @@ static void __init limit_regions(unsigned long long size)
        int i;
 
        if (efi_enabled) {
-               for (i = 0; i < memmap.nr_map; i++) {
-                       current_addr = memmap.map[i].phys_addr +
-                                      (memmap.map[i].num_pages << 12);
-                       if (memmap.map[i].type == EFI_CONVENTIONAL_MEMORY) {
+               efi_memory_desc_t *md;
+               void *p;
+
+               for (p = memmap.map, i = 0; p < memmap.map_end;
+                       p += memmap.desc_size, i++) {
+                       md = p;
+                       current_addr = md->phys_addr + (md->num_pages << 12);
+                       if (md->type == EFI_CONVENTIONAL_MEMORY) {
                                if (current_addr >= size) {
-                                       memmap.map[i].num_pages -=
+                                       md->num_pages -=
                                                (((current_addr-size) + PAGE_SIZE-1) >> PAGE_SHIFT);
                                        memmap.nr_map = i + 1;
                                        return;
@@ -1581,8 +1585,14 @@ void __init setup_arch(char **cmdline_p)
         */
        acpi_boot_table_init();
        acpi_boot_init();
-#endif
 
+#if defined(CONFIG_SMP) && defined(CONFIG_X86_PC)
+       if (def_to_bigsmp)
+               printk(KERN_WARNING "More than 8 CPUs detected and "
+                       "CONFIG_X86_PC cannot handle it.\nUse "
+                       "CONFIG_X86_GENERICARCH or CONFIG_X86_BIGSMP.\n");
+#endif
+#endif
 #ifdef CONFIG_X86_LOCAL_APIC
        if (smp_found_config)
                get_smp_config();
index 89ef7adc63a4be19611f57b580fddf46259dbd73..61eb0c8a6e47dc9763c8f78d85f3aa3e7be40456 100644 (file)
@@ -278,9 +278,9 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
        int tmp, err = 0;
 
        tmp = 0;
-       __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
+       savesegment(gs, tmp);
        err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
-       __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
+       savesegment(fs, tmp);
        err |= __put_user(tmp, (unsigned int __user *)&sc->fs);
 
        err |= __put_user(regs->xes, (unsigned int __user *)&sc->es);
@@ -577,10 +577,11 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
        else
                ret = setup_frame(sig, ka, oldset, regs);
 
-       if (ret && !(ka->sa.sa_flags & SA_NODEFER)) {
+       if (ret) {
                spin_lock_irq(&current->sighand->siglock);
                sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-               sigaddset(&current->blocked,sig);
+               if (!(ka->sa.sa_flags & SA_NODEFER))
+                       sigaddset(&current->blocked,sig);
                recalc_sigpending();
                spin_unlock_irq(&current->sighand->siglock);
        }
@@ -603,7 +604,9 @@ int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset)
         * We want the common case to go fast, which
         * is why we may in certain cases get here from
         * kernel mode. Just return without doing anything
-        * if so.
+        * if so.  vm86 regs switched out by assembly code
+        * before reaching here, so testing against kernel
+        * CS suffices.
         */
        if (!user_mode(regs))
                return 1;
index cec4bde67161254106267d6c6e4715aaeea93a3a..48b55db3680f3eaac2b1a67274343677ceb1a32d 100644 (file)
@@ -576,7 +576,7 @@ static void stop_this_cpu (void * dummy)
        local_irq_disable();
        disable_local_APIC();
        if (cpu_data[smp_processor_id()].hlt_works_ok)
-               for(;;) __asm__("hlt");
+               for(;;) halt();
        for (;;);
 }
 
index 8ac8e9fd5614fa10237dc58fa6620d52cff8e5e3..5e4893d2b9f272b4c1120f3812cebef501f4164f 100644 (file)
@@ -88,6 +88,8 @@ EXPORT_SYMBOL(cpu_online_map);
 cpumask_t cpu_callin_map;
 cpumask_t cpu_callout_map;
 EXPORT_SYMBOL(cpu_callout_map);
+cpumask_t cpu_possible_map;
+EXPORT_SYMBOL(cpu_possible_map);
 static cpumask_t smp_commenced_mask;
 
 /* TSC's upper 32 bits can't be written in eariler CPU (before prescott), there
@@ -1017,8 +1019,8 @@ int __devinit smp_prepare_cpu(int cpu)
        tsc_sync_disabled = 1;
 
        /* init low mem mapping */
-       memcpy(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
-                       sizeof(swapper_pg_dir[0]) * KERNEL_PGD_PTRS);
+       clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+                       KERNEL_PGD_PTRS);
        flush_tlb_all();
        schedule_work(&task);
        wait_for_completion(&done);
@@ -1265,6 +1267,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_present_map);
+       cpu_set(smp_processor_id(), cpu_possible_map);
        per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
 }
 
index 0ee9dee8af06280c85ba403208cacc237da08b43..eefea7c5500893bd47e9d9485f7111ae34cd76e1 100644 (file)
@@ -194,10 +194,7 @@ int do_settimeofday(struct timespec *tv)
        set_normalized_timespec(&xtime, sec, nsec);
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
        return 0;
@@ -252,8 +249,7 @@ EXPORT_SYMBOL(profile_pc);
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
-static inline void do_timer_interrupt(int irq, void *dev_id,
-                                       struct pt_regs *regs)
+static inline void do_timer_interrupt(int irq, struct pt_regs *regs)
 {
 #ifdef CONFIG_X86_IO_APIC
        if (timer_ack) {
@@ -307,7 +303,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
        cur_timer->mark_offset();
  
-       do_timer_interrupt(irq, NULL, regs);
+       do_timer_interrupt(irq, regs);
 
        write_sequnlock(&xtime_lock);
        return IRQ_HANDLED;
@@ -348,7 +344,7 @@ static void sync_cmos_clock(unsigned long dummy)
         * This code is run on a timer.  If the clock is set, that timer
         * may not expire at the correct time.  Thus, we adjust...
         */
-       if ((time_status & STA_UNSYNC) != 0)
+       if (!ntp_synced())
                /*
                 * Not synced, exit, do not restart a timer (if one is
                 * running, let it run out).
@@ -383,6 +379,7 @@ void notify_arch_cmos_timer(void)
 
 static long clock_cmos_diff, sleep_start;
 
+static struct timer_opts *last_timer;
 static int timer_suspend(struct sys_device *dev, pm_message_t state)
 {
        /*
@@ -391,6 +388,10 @@ static int timer_suspend(struct sys_device *dev, pm_message_t state)
        clock_cmos_diff = -get_cmos_time();
        clock_cmos_diff += get_seconds();
        sleep_start = get_cmos_time();
+       last_timer = cur_timer;
+       cur_timer = &timer_none;
+       if (last_timer->suspend)
+               last_timer->suspend(state);
        return 0;
 }
 
@@ -404,6 +405,7 @@ static int timer_resume(struct sys_device *dev)
        if (is_hpet_enabled())
                hpet_reenable();
 #endif
+       setup_pit_timer();
        sec = get_cmos_time() + clock_cmos_diff;
        sleep_length = (get_cmos_time() - sleep_start) * HZ;
        write_seqlock_irqsave(&xtime_lock, flags);
@@ -412,6 +414,11 @@ static int timer_resume(struct sys_device *dev)
        write_sequnlock_irqrestore(&xtime_lock, flags);
        jiffies += sleep_length;
        wall_jiffies += sleep_length;
+       if (last_timer->resume)
+               last_timer->resume();
+       cur_timer = last_timer;
+       last_timer = NULL;
+       touch_softlockup_watchdog();
        return 0;
 }
 
index ef8dac5dd33b103bbc5f8c6f5c9b7ce52bfe4582..d973a8b681fd5256d75212e77e43131141e07641 100644 (file)
@@ -18,8 +18,8 @@
 #include "mach_timer.h"
 #include <asm/hpet.h>
 
-static unsigned long __read_mostly hpet_usec_quotient; /* convert hpet clks to usec */
-static unsigned long tsc_hpet_quotient;                /* convert tsc to hpet clks */
+static unsigned long hpet_usec_quotient __read_mostly; /* convert hpet clks to usec */
+static unsigned long tsc_hpet_quotient __read_mostly;  /* convert tsc to hpet clks */
 static unsigned long hpet_last;        /* hpet counter value at last tick*/
 static unsigned long last_tsc_low;     /* lsb 32 bits of Time Stamp Counter */
 static unsigned long last_tsc_high;    /* msb 32 bits of Time Stamp Counter */
@@ -136,6 +136,8 @@ static void delay_hpet(unsigned long loops)
        } while ((hpet_end - hpet_start) < (loops));
 }
 
+static struct timer_opts timer_hpet;
+
 static int __init init_hpet(char* override)
 {
        unsigned long result, remain;
@@ -163,6 +165,8 @@ static int __init init_hpet(char* override)
                        }
                        set_cyc2ns_scale(cpu_khz/1000);
                }
+               /* set this only when cpu_has_tsc */
+               timer_hpet.read_timer = read_timer_tsc;
        }
 
        /*
@@ -177,6 +181,19 @@ static int __init init_hpet(char* override)
        return 0;
 }
 
+static int hpet_resume(void)
+{
+       write_seqlock(&monotonic_lock);
+       /* Assume this is the last mark offset time */
+       rdtsc(last_tsc_low, last_tsc_high);
+
+       if (hpet_use_timer)
+               hpet_last = hpet_readl(HPET_T0_CMP) - hpet_tick;
+       else
+               hpet_last = hpet_readl(HPET_COUNTER);
+       write_sequnlock(&monotonic_lock);
+       return 0;
+}
 /************************************************************/
 
 /* tsc timer_opts struct */
@@ -186,7 +203,7 @@ static struct timer_opts timer_hpet __read_mostly = {
        .get_offset =           get_offset_hpet,
        .monotonic_clock =      monotonic_clock_hpet,
        .delay =                delay_hpet,
-       .read_timer =           read_timer_tsc,
+       .resume =               hpet_resume,
 };
 
 struct init_timer_opts __initdata timer_hpet_init = {
index 06de036a820c23d63395e559ac9db1f5daedc2a3..eddb640382342db9b2cee7483d228d0648a64e00 100644 (file)
@@ -175,30 +175,3 @@ void setup_pit_timer(void)
        outb(LATCH >> 8 , PIT_CH0);     /* MSB */
        spin_unlock_irqrestore(&i8253_lock, flags);
 }
-
-static int timer_resume(struct sys_device *dev)
-{
-       setup_pit_timer();
-       return 0;
-}
-
-static struct sysdev_class timer_sysclass = {
-       set_kset_name("timer_pit"),
-       .resume = timer_resume,
-};
-
-static struct sys_device device_timer = {
-       .id     = 0,
-       .cls    = &timer_sysclass,
-};
-
-static int __init init_timer_sysfs(void)
-{
-       int error = sysdev_class_register(&timer_sysclass);
-       if (!error)
-               error = sysdev_register(&device_timer);
-       return error;
-}
-
-device_initcall(init_timer_sysfs);
-
index 4ef20e66349862ebe383c5e371a3c1bbe2abbff8..264edaaac315b3e75c0781cb0a016e275151dc67 100644 (file)
@@ -186,6 +186,14 @@ static void mark_offset_pmtmr(void)
        }
 }
 
+static int pmtmr_resume(void)
+{
+       write_seqlock(&monotonic_lock);
+       /* Assume this is the last mark offset time */
+       offset_tick = read_pmtmr();
+       write_sequnlock(&monotonic_lock);
+       return 0;
+}
 
 static unsigned long long monotonic_clock_pmtmr(void)
 {
@@ -247,6 +255,7 @@ static struct timer_opts timer_pmtmr = {
        .monotonic_clock        = monotonic_clock_pmtmr,
        .delay                  = delay_pmtmr,
        .read_timer             = read_timer_tsc,
+       .resume                 = pmtmr_resume,
 };
 
 struct init_timer_opts __initdata timer_pmtmr_init = {
index 8f4e4d5bc560d58138f24ab514902f18a175bd57..6dd470cc9f72a2e6e71264c988112bd1ef11e2a7 100644 (file)
@@ -543,6 +543,19 @@ static int __init init_tsc(char* override)
        return -ENODEV;
 }
 
+static int tsc_resume(void)
+{
+       write_seqlock(&monotonic_lock);
+       /* Assume this is the last mark offset time */
+       rdtsc(last_tsc_low, last_tsc_high);
+#ifdef CONFIG_HPET_TIMER
+       if (is_hpet_enabled() && hpet_use_timer)
+               hpet_last = hpet_readl(HPET_COUNTER);
+#endif
+       write_sequnlock(&monotonic_lock);
+       return 0;
+}
+
 #ifndef CONFIG_X86_TSC
 /* disable flag for tsc.  Takes effect by clearing the TSC cpu flag
  * in cpu/common.c */
@@ -573,6 +586,7 @@ static struct timer_opts timer_tsc = {
        .monotonic_clock = monotonic_clock_tsc,
        .delay = delay_tsc,
        .read_timer = read_timer_tsc,
+       .resume = tsc_resume,
 };
 
 struct init_timer_opts __initdata timer_tsc_init = {
index cd2d5d5514fe0ffcdf78cadfbabdf5863ede040c..09a58cb6daa7050e018496a127458241f2fa0e30 100644 (file)
@@ -210,7 +210,7 @@ void show_registers(struct pt_regs *regs)
        unsigned short ss;
 
        esp = (unsigned long) (&regs->esp);
-       ss = __KERNEL_DS;
+       savesegment(ss, ss);
        if (user_mode(regs)) {
                in_kernel = 0;
                esp = regs->esp;
@@ -267,9 +267,6 @@ static void handle_BUG(struct pt_regs *regs)
        char c;
        unsigned long eip;
 
-       if (user_mode(regs))
-               goto no_bug;            /* Not in kernel */
-
        eip = regs->eip;
 
        if (eip < PAGE_OFFSET)
@@ -366,8 +363,9 @@ static inline void die_if_kernel(const char * str, struct pt_regs * regs, long e
                die(str, regs, err);
 }
 
-static void do_trap(int trapnr, int signr, char *str, int vm86,
-                          struct pt_regs * regs, long error_code, siginfo_t *info)
+static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86,
+                             struct pt_regs * regs, long error_code,
+                             siginfo_t *info)
 {
        struct task_struct *tsk = current;
        tsk->thread.error_code = error_code;
@@ -463,7 +461,8 @@ DO_ERROR(12, SIGBUS,  "stack segment", stack_segment)
 DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
 DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0)
 
-fastcall void do_general_protection(struct pt_regs * regs, long error_code)
+fastcall void __kprobes do_general_protection(struct pt_regs * regs,
+                                             long error_code)
 {
        int cpu = get_cpu();
        struct tss_struct *tss = &per_cpu(init_tss, cpu);
@@ -568,6 +567,10 @@ static DEFINE_SPINLOCK(nmi_print_lock);
 
 void die_nmi (struct pt_regs *regs, const char *msg)
 {
+       if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 0, SIGINT) ==
+           NOTIFY_STOP)
+               return;
+
        spin_lock(&nmi_print_lock);
        /*
        * We are in trouble anyway, lets at least try
@@ -656,7 +659,7 @@ fastcall void do_nmi(struct pt_regs * regs, long error_code)
 
        ++nmi_count(cpu);
 
-       if (!nmi_callback(regs, cpu))
+       if (!rcu_dereference(nmi_callback)(regs, cpu))
                default_do_nmi(regs);
 
        nmi_exit();
@@ -664,7 +667,7 @@ fastcall void do_nmi(struct pt_regs * regs, long error_code)
 
 void set_nmi_callback(nmi_callback_t callback)
 {
-       nmi_callback = callback;
+       rcu_assign_pointer(nmi_callback, callback);
 }
 EXPORT_SYMBOL_GPL(set_nmi_callback);
 
@@ -675,7 +678,7 @@ void unset_nmi_callback(void)
 EXPORT_SYMBOL_GPL(unset_nmi_callback);
 
 #ifdef CONFIG_KPROBES
-fastcall void do_int3(struct pt_regs *regs, long error_code)
+fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code)
 {
        if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
                        == NOTIFY_STOP)
@@ -709,7 +712,7 @@ fastcall void do_int3(struct pt_regs *regs, long error_code)
  * find every occurrence of the TF bit that could be saved away even
  * by user code)
  */
-fastcall void do_debug(struct pt_regs * regs, long error_code)
+fastcall void __kprobes do_debug(struct pt_regs * regs, long error_code)
 {
        unsigned int condition;
        struct task_struct *tsk = current;
@@ -1008,7 +1011,7 @@ void __init trap_init_f00f_bug(void)
         * it uses the read-only mapped virtual address.
         */
        idt_descr.address = fix_to_virt(FIX_F00F_IDT);
-       __asm__ __volatile__("lidt %0" : : "m" (idt_descr));
+       load_idt(&idt_descr);
 }
 #endif
 
index ec0f68ce68860c5b7e15e6158a79afbd5e93c3a5..16b485009622a578e274c260cf975b3fd1a77f0e 100644 (file)
@@ -294,8 +294,8 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk
  */
        info->regs32->eax = 0;
        tsk->thread.saved_esp0 = tsk->thread.esp0;
-       asm volatile("mov %%fs,%0":"=m" (tsk->thread.saved_fs));
-       asm volatile("mov %%gs,%0":"=m" (tsk->thread.saved_gs));
+       savesegment(fs, tsk->thread.saved_fs);
+       savesegment(gs, tsk->thread.saved_gs);
 
        tss = &per_cpu(init_tss, get_cpu());
        tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
@@ -542,7 +542,7 @@ void handle_vm86_fault(struct kernel_vm86_regs * regs, long error_code)
        unsigned char opcode;
        unsigned char __user *csp;
        unsigned char __user *ssp;
-       unsigned short ip, sp;
+       unsigned short ip, sp, orig_flags;
        int data32, pref_done;
 
 #define CHECK_IF_IN_TRAP \
@@ -551,8 +551,12 @@ void handle_vm86_fault(struct kernel_vm86_regs * regs, long error_code)
 #define VM86_FAULT_RETURN do { \
        if (VMPI.force_return_for_pic  && (VEFLAGS & (IF_MASK | VIF_MASK))) \
                return_to_32bit(regs, VM86_PICRETURN); \
+       if (orig_flags & TF_MASK) \
+               handle_vm86_trap(regs, 0, 1); \
        return; } while (0)
 
+       orig_flags = *(unsigned short *)&regs->eflags;
+
        csp = (unsigned char __user *) (regs->cs << 4);
        ssp = (unsigned char __user *) (regs->ss << 4);
        sp = SP(regs);
index 761972f8cb6c86dadf1ed297d2ea12a6ae234977..13b9c62cbbb45ce1d95357a1784afea6f8e3db89 100644 (file)
@@ -22,6 +22,7 @@ SECTIONS
        *(.text)
        SCHED_TEXT
        LOCK_TEXT
+       KPROBES_TEXT
        *(.fixup)
        *(.gnu.warning)
        } = 0x9090
index c8fcf75b9be33fbf35f6b36311fae25d47d8be1d..68afa50dd7cf79bf0d5eb021115c59e03fee692f 100644 (file)
@@ -15,7 +15,7 @@
 */
 
        .text
-       .org    __kernel_vsyscall+32
+       .org __kernel_vsyscall+32,0x90
        .globl __kernel_sigreturn
        .type __kernel_sigreturn,@function
 __kernel_sigreturn:
@@ -35,6 +35,7 @@ __kernel_rt_sigreturn:
        int $0x80
 .LEND_rt_sigreturn:
        .size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn
+       .balign 32
        .previous
 
        .section .eh_frame,"a",@progbits
index 23395fff35d16e59dcade164354dc0045ee95d1f..b64314069e785636a2375ed44c354bd717dd91fb 100644 (file)
@@ -76,7 +76,7 @@ static int __init topology_init(void)
        for_each_online_node(i)
                arch_register_node(i);
 
-       for_each_cpu(i)
+       for_each_present_cpu(i)
                arch_register_cpu(i);
        return 0;
 }
@@ -87,7 +87,7 @@ static int __init topology_init(void)
 {
        int i;
 
-       for_each_cpu(i)
+       for_each_present_cpu(i)
                arch_register_cpu(i);
        return 0;
 }
index 70691f0c4ce28a8ae5cd9b6fb7fa517c5d6ba509..898ed905e1195638c9e39594d0cd5495bd1a3d59 100644 (file)
@@ -104,7 +104,8 @@ struct mip_reg {
 #define        MIP_SW_APIC             0x1020b
 #define        MIP_FUNC(VALUE)         (VALUE & 0xff)
 
-extern int parse_unisys_oem (char *oemptr, int oem_entries);
-extern int find_unisys_acpi_oem_table(unsigned long *oem_addr, int *length);
+extern int parse_unisys_oem (char *oemptr);
+extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
+extern void setup_unisys ();
 extern int es7000_start_cpu(int cpu, unsigned long eip);
 extern void es7000_sw_apic(void);
index d5936d500479f235c89c11e51c431dd0ffaef819..2000bdca2fc2cc3a93a9c9393012bd5db707d91d 100644 (file)
@@ -75,12 +75,29 @@ es7000_rename_gsi(int ioapic, int gsi)
 
 #endif // (CONFIG_X86_IO_APIC) && (CONFIG_ACPI_INTERPRETER || CONFIG_ACPI_BOOT)
 
+void __init
+setup_unisys ()
+{
+       /*
+        * Determine the generation of the ES7000 currently running.
+        *
+        * es7000_plat = 1 if the machine is a 5xx ES7000 box
+        * es7000_plat = 2 if the machine is a x86_64 ES7000 box
+        *
+        */
+       if (!(boot_cpu_data.x86 <= 15 && boot_cpu_data.x86_model <= 2))
+               es7000_plat = 2;
+       else
+               es7000_plat = 1;
+       ioapic_renumber_irq = es7000_rename_gsi;
+}
+
 /*
  * Parse the OEM Table
  */
 
 int __init
-parse_unisys_oem (char *oemptr, int oem_entries)
+parse_unisys_oem (char *oemptr)
 {
        int                     i;
        int                     success = 0;
@@ -95,7 +112,7 @@ parse_unisys_oem (char *oemptr, int oem_entries)
 
        tp += 8;
 
-       for (i=0; i <= oem_entries; i++) {
+       for (i=0; i <= 6; i++) {
                type = *tp++;
                size = *tp++;
                tp -= 2;
@@ -130,34 +147,18 @@ parse_unisys_oem (char *oemptr, int oem_entries)
                default:
                        break;
                }
-               if (i == 6) break;
                tp += size;
        }
 
        if (success < 2) {
                es7000_plat = 0;
-       } else {
-               printk("\nEnabling ES7000 specific features...\n");
-               /*
-                * Determine the generation of the ES7000 currently running.
-                *
-                * es7000_plat = 0 if the machine is NOT a Unisys ES7000 box
-                * es7000_plat = 1 if the machine is a 5xx ES7000 box
-                * es7000_plat = 2 if the machine is a x86_64 ES7000 box
-                *
-                */
-               if (!(boot_cpu_data.x86 <= 15 && boot_cpu_data.x86_model <= 2))
-                       es7000_plat = 2;
-               else
-                       es7000_plat = 1;
-
-               ioapic_renumber_irq = es7000_rename_gsi;
-       }
+       } else
+               setup_unisys();
        return es7000_plat;
 }
 
 int __init
-find_unisys_acpi_oem_table(unsigned long *oem_addr, int *length)
+find_unisys_acpi_oem_table(unsigned long *oem_addr)
 {
        struct acpi_table_rsdp          *rsdp = NULL;
        unsigned long                   rsdp_phys = 0;
@@ -201,13 +202,11 @@ find_unisys_acpi_oem_table(unsigned long *oem_addr, int *length)
                                acpi_table_print(header, sdt.entry[i].pa);
                                t = (struct oem_table *) __acpi_map_table(sdt.entry[i].pa, header->length);
                                addr = (void *) __acpi_map_table(t->OEMTableAddr, t->OEMTableSize);
-                               *length = header->length;
                                *oem_addr = (unsigned long) addr;
                                return 0;
                        }
                }
        }
-       Dprintk("ES7000: did not find Unisys ACPI OEM table!\n");
        return -1;
 }
 
index 25883b44f6253f092b4eab9a67cc61c822e0401e..037b2af1a1f4972a0940f723d1fa39310b4e1dfd 100644 (file)
@@ -47,7 +47,10 @@ static struct dmi_system_id __initdata bigsmp_dmi_table[] = {
 
 static __init int probe_bigsmp(void)
 { 
-       dmi_check_system(bigsmp_dmi_table);
+       if (def_to_bigsmp)
+               dmi_bigsmp = 1;
+       else
+               dmi_check_system(bigsmp_dmi_table);
        return dmi_bigsmp; 
 } 
 
index 5497c65a8790bfd0175564aed83b7129f5f5ceb2..cea5b3ce4b5766c9747294090542e4eb063b75eb 100644 (file)
@@ -30,6 +30,25 @@ struct genapic *apic_probe[] __initdata = {
        NULL,
 };
 
+static int cmdline_apic;
+
+void __init generic_bigsmp_probe(void)
+{
+       /*
+        * This routine is used to switch to bigsmp mode when
+        * - There is no apic= option specified by the user
+        * - generic_apic_probe() has choosen apic_default as the sub_arch
+        * - we find more than 8 CPUs in acpi LAPIC listing with xAPIC support
+        */
+
+       if (!cmdline_apic && genapic == &apic_default)
+               if (apic_bigsmp.probe()) {
+                       genapic = &apic_bigsmp;
+                       printk(KERN_INFO "Overriding APIC driver with %s\n",
+                              genapic->name);
+               }
+}
+
 void __init generic_apic_probe(char *command_line) 
 { 
        char *s;
@@ -52,6 +71,7 @@ void __init generic_apic_probe(char *command_line)
                if (!changed)
                        printk(KERN_ERR "Unknown genapic `%s' specified.\n", s);
                *p = old;
+               cmdline_apic = changed;
        } 
        for (i = 0; !changed && apic_probe[i]; i++) { 
                if (apic_probe[i]->probe()) {
index c6384061328a5d72acaed91f216c26fef86a8c91..cc69875d979b9445b3ebcc0549906656ee3f2767 100644 (file)
@@ -234,10 +234,9 @@ voyager_power_off(void)
 #endif
        }
        /* and wait for it to happen */
-       for(;;) {
-               __asm("cli");
-               __asm("hlt");
-       }
+       local_irq_disable();
+       for(;;)
+               halt();
 }
 
 /* copied from process.c */
@@ -278,10 +277,9 @@ machine_restart(char *cmd)
                outb(basebd | 0x08, VOYAGER_MC_SETUP);
                outb(0x02, catbase + 0x21);
        }
-       for(;;) {
-               asm("cli");
-               asm("hlt");
-       }
+       local_irq_disable();
+       for(;;)
+               halt();
 }
 
 void
index 0e1f4208b07ce46ecc8d883dc3f2121fb07f5c92..46b0cf4a31e006fc6002569ae3eac4b7a5478a6a 100644 (file)
@@ -242,6 +242,8 @@ static cpumask_t smp_commenced_mask = CPU_MASK_NONE;
 cpumask_t cpu_callin_map = CPU_MASK_NONE;
 cpumask_t cpu_callout_map = CPU_MASK_NONE;
 EXPORT_SYMBOL(cpu_callout_map);
+cpumask_t cpu_possible_map = CPU_MASK_ALL;
+EXPORT_SYMBOL(cpu_possible_map);
 
 /* The per processor IRQ masks (these are usually kept in sync) */
 static __u16 vic_irq_mask[NR_CPUS] __cacheline_aligned;
@@ -1015,7 +1017,7 @@ smp_stop_cpu_function(void *dummy)
        cpu_clear(smp_processor_id(), cpu_online_map);
        local_irq_disable();
        for(;;)
-              __asm__("hlt");
+               halt();
 }
 
 static DEFINE_SPINLOCK(call_lock);
@@ -1910,6 +1912,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);
 }
 
 int __devinit
index 91175738e94808a8aa5a988f1fe5183211fa58ca..9819b705efa422af8c3f1ee5652fa0649f606811 100644 (file)
@@ -155,7 +155,6 @@ static long pm_address(u_char FPU_modrm, u_char segment,
 { 
   struct desc_struct descriptor;
   unsigned long base_address, limit, address, seg_top;
-  unsigned short selector;
 
   segment--;
 
@@ -173,17 +172,11 @@ static long pm_address(u_char FPU_modrm, u_char segment,
       /* fs and gs aren't used by the kernel, so they still have their
         user-space values. */
     case PREFIX_FS_-1:
-      /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register
-        in the assembler statement. */
-
-      __asm__("mov %%fs,%0":"=r" (selector));
-      addr->selector = selector;
+      /* N.B. - movl %seg, mem is a 2 byte write regardless of prefix */
+      savesegment(fs, addr->selector);
       break;
     case PREFIX_GS_-1:
-      /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register
-        in the assembler statement. */
-      __asm__("mov %%gs,%0":"=r" (selector));
-      addr->selector = selector;
+      savesegment(gs, addr->selector);
       break;
     default:
       addr->selector = PM_REG_(segment);
index 6711ce3f6916ad3601b33d4ba5a2d694f2bd2989..244d8ec66be2a473361bf00d81e81ba53cdf9fe0 100644 (file)
@@ -37,7 +37,7 @@
 #include <asm/mmzone.h>
 #include <bios_ebda.h>
 
-struct pglist_data *node_data[MAX_NUMNODES];
+struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
 EXPORT_SYMBOL(node_data);
 bootmem_data_t node0_bdata;
 
@@ -49,8 +49,8 @@ bootmem_data_t node0_bdata;
  * 2) node_start_pfn   - the starting page frame number for a node
  * 3) node_end_pfn     - the ending page fram number for a node
  */
-unsigned long node_start_pfn[MAX_NUMNODES];
-unsigned long node_end_pfn[MAX_NUMNODES];
+unsigned long node_start_pfn[MAX_NUMNODES] __read_mostly;
+unsigned long node_end_pfn[MAX_NUMNODES] __read_mostly;
 
 
 #ifdef CONFIG_DISCONTIGMEM
@@ -66,7 +66,7 @@ unsigned long node_end_pfn[MAX_NUMNODES];
  *     physnode_map[4-7] = 1;
  *     physnode_map[8- ] = -1;
  */
-s8 physnode_map[MAX_ELEMENTS] = { [0 ... (MAX_ELEMENTS - 1)] = -1};
+s8 physnode_map[MAX_ELEMENTS] __read_mostly = { [0 ... (MAX_ELEMENTS - 1)] = -1};
 EXPORT_SYMBOL(physnode_map);
 
 void memory_present(int nid, unsigned long start, unsigned long end)
index 8e90339d6eaaa18c96a5292c53f6590235804764..9edd4485b91eafd6396affe5649c92d00b8666ae 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/vt_kern.h>             /* For unblank_screen() */
 #include <linux/highmem.h>
 #include <linux/module.h>
+#include <linux/kprobes.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -199,6 +200,18 @@ static inline int is_prefetch(struct pt_regs *regs, unsigned long addr,
        return 0;
 } 
 
+static noinline void force_sig_info_fault(int si_signo, int si_code,
+       unsigned long address, struct task_struct *tsk)
+{
+       siginfo_t info;
+
+       info.si_signo = si_signo;
+       info.si_errno = 0;
+       info.si_code = si_code;
+       info.si_addr = (void __user *)address;
+       force_sig_info(si_signo, &info, tsk);
+}
+
 fastcall void do_invalid_op(struct pt_regs *, unsigned long);
 
 /*
@@ -211,18 +224,18 @@ fastcall void do_invalid_op(struct pt_regs *, unsigned long);
  *     bit 1 == 0 means read, 1 means write
  *     bit 2 == 0 means kernel, 1 means user-mode
  */
-fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code)
+fastcall void __kprobes do_page_fault(struct pt_regs *regs,
+                                     unsigned long error_code)
 {
        struct task_struct *tsk;
        struct mm_struct *mm;
        struct vm_area_struct * vma;
        unsigned long address;
        unsigned long page;
-       int write;
-       siginfo_t info;
+       int write, si_code;
 
        /* get the address */
-       __asm__("movl %%cr2,%0":"=r" (address));
+        address = read_cr2();
 
        if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
                                        SIGSEGV) == NOTIFY_STOP)
@@ -233,7 +246,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code)
 
        tsk = current;
 
-       info.si_code = SEGV_MAPERR;
+       si_code = SEGV_MAPERR;
 
        /*
         * We fault-in kernel-space virtual memory on-demand. The
@@ -313,7 +326,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code)
  * we can handle it..
  */
 good_area:
-       info.si_code = SEGV_ACCERR;
+       si_code = SEGV_ACCERR;
        write = 0;
        switch (error_code & 3) {
                default:        /* 3: write, present */
@@ -387,11 +400,7 @@ bad_area_nosemaphore:
                /* Kernel addresses are always protection faults */
                tsk->thread.error_code = error_code | (address >= TASK_SIZE);
                tsk->thread.trap_no = 14;
-               info.si_signo = SIGSEGV;
-               info.si_errno = 0;
-               /* info.si_code has been set above */
-               info.si_addr = (void __user *)address;
-               force_sig_info(SIGSEGV, &info, tsk);
+               force_sig_info_fault(SIGSEGV, si_code, address, tsk);
                return;
        }
 
@@ -446,7 +455,7 @@ no_context:
        printk(" at virtual address %08lx\n",address);
        printk(KERN_ALERT " printing eip:\n");
        printk("%08lx\n", regs->eip);
-       asm("movl %%cr3,%0":"=r" (page));
+       page = read_cr3();
        page = ((unsigned long *) __va(page))[address >> 22];
        printk(KERN_ALERT "*pde = %08lx\n", page);
        /*
@@ -500,11 +509,7 @@ do_sigbus:
        tsk->thread.cr2 = address;
        tsk->thread.error_code = error_code;
        tsk->thread.trap_no = 14;
-       info.si_signo = SIGBUS;
-       info.si_errno = 0;
-       info.si_code = BUS_ADRERR;
-       info.si_addr = (void __user *)address;
-       force_sig_info(SIGBUS, &info, tsk);
+       force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk);
        return;
 
 vmalloc_fault:
@@ -523,7 +528,7 @@ vmalloc_fault:
                pmd_t *pmd, *pmd_k;
                pte_t *pte_k;
 
-               asm("movl %%cr3,%0":"=r" (pgd_paddr));
+               pgd_paddr = read_cr3();
                pgd = index + (pgd_t *)__va(pgd_paddr);
                pgd_k = init_mm.pgd + index;
 
index 3b099f32b9487a054db420509ad25591ea0d06eb..d524127c9afc3b2f92b3e5ad6b3dbce20bec42f7 100644 (file)
@@ -22,12 +22,15 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
 {
        pgd_t *pgd;
        pud_t *pud;
-       pmd_t *pmd = NULL;
+       pte_t *pte = NULL;
 
        pgd = pgd_offset(mm, addr);
        pud = pud_alloc(mm, pgd, addr);
-       pmd = pmd_alloc(mm, pud, addr);
-       return (pte_t *) pmd;
+       if (pud)
+               pte = (pte_t *) pmd_alloc(mm, pud, addr);
+       BUG_ON(pte && !pte_none(*pte) && !pte_huge(*pte));
+
+       return pte;
 }
 
 pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
@@ -37,8 +40,11 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
        pmd_t *pmd = NULL;
 
        pgd = pgd_offset(mm, addr);
-       pud = pud_offset(pgd, addr);
-       pmd = pmd_offset(pud, addr);
+       if (pgd_present(*pgd)) {
+               pud = pud_offset(pgd, addr);
+               if (pud_present(*pud))
+                       pmd = pmd_offset(pud, addr);
+       }
        return (pte_t *) pmd;
 }
 
@@ -118,17 +124,6 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address,
 }
 #endif
 
-void hugetlb_clean_stale_pgtable(pte_t *pte)
-{
-       pmd_t *pmd = (pmd_t *) pte;
-       struct page *page;
-
-       page = pmd_page(*pmd);
-       pmd_clear(pmd);
-       dec_page_state(nr_page_table_pages);
-       page_cache_release(page);
-}
-
 /* x86_64 also uses this file */
 
 #ifdef HAVE_ARCH_HUGETLB_UNMAPPED_AREA
index 12216b52e28bf9b50060c509060fea3057fb298e..2ebaf75f732e92e8e901ea408e490718794b8821 100644 (file)
@@ -198,9 +198,10 @@ int page_is_ram(unsigned long pagenr)
 
        if (efi_enabled) {
                efi_memory_desc_t *md;
+               void *p;
 
-               for (i = 0; i < memmap.nr_map; i++) {
-                       md = &memmap.map[i];
+               for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+                       md = p;
                        if (!is_available_memory(md))
                                continue;
                        addr = (md->phys_addr+PAGE_SIZE-1) >> PAGE_SHIFT;
@@ -348,7 +349,7 @@ static void __init pagetable_init (void)
         * All user-space mappings are explicitly cleared after
         * SMP startup.
         */
-       pgd_base[0] = pgd_base[USER_PTRS_PER_PGD];
+       set_pgd(&pgd_base[0], pgd_base[USER_PTRS_PER_PGD]);
 #endif
 }
 
@@ -392,7 +393,7 @@ void zap_low_mappings (void)
 }
 
 static int disable_nx __initdata = 0;
-u64 __supported_pte_mask = ~_PAGE_NX;
+u64 __supported_pte_mask __read_mostly = ~_PAGE_NX;
 
 /*
  * noexec = on|off
index cb3da6baa704208d4faf2977d411190d9a2aa88f..f600fc244f0284e67261e394de644705a67eb744 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 #include <asm/tlbflush.h>
+#include <asm/pgalloc.h>
 
 static DEFINE_SPINLOCK(cpa_lock);
 static struct list_head df_list = LIST_HEAD_INIT(df_list);
@@ -52,8 +53,8 @@ static struct page *split_large_page(unsigned long address, pgprot_t prot)
        addr = address & LARGE_PAGE_MASK; 
        pbase = (pte_t *)page_address(base);
        for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) {
-               pbase[i] = pfn_pte(addr >> PAGE_SHIFT, 
-                                  addr == address ? prot : PAGE_KERNEL);
+               set_pte(&pbase[i], pfn_pte(addr >> PAGE_SHIFT,
+                                          addr == address ? prot : PAGE_KERNEL));
        }
        return base;
 } 
@@ -62,7 +63,7 @@ static void flush_kernel_map(void *dummy)
 { 
        /* Could use CLFLUSH here if the CPU supports it (Hammer,P4) */
        if (boot_cpu_data.x86_model >= 4) 
-               asm volatile("wbinvd":::"memory"); 
+               wbinvd();
        /* Flush all to work around Errata in early athlons regarding 
         * large page flushing. 
         */
index bd2f7afc7a2a5d6726b14a35bdf48492bf4730a1..dcdce2c6c53239ad1ba747319ea6aecefa6d7a1a 100644 (file)
@@ -207,19 +207,19 @@ void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused)
 {
        unsigned long flags;
 
-       if (PTRS_PER_PMD == 1)
+       if (PTRS_PER_PMD == 1) {
+               memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
                spin_lock_irqsave(&pgd_lock, flags);
+       }
 
-       memcpy((pgd_t *)pgd + USER_PTRS_PER_PGD,
+       clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
                        swapper_pg_dir + USER_PTRS_PER_PGD,
-                       (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
-
+                       KERNEL_PGD_PTRS);
        if (PTRS_PER_PMD > 1)
                return;
 
        pgd_list_add(pgd);
        spin_unlock_irqrestore(&pgd_lock, flags);
-       memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
 }
 
 /* never called when PTRS_PER_PMD > 1 */
index c90332de582b9a213c5aa91a0557c3ce93179567..5341d481d92fb789e4432abc69eb14fbc268036a 100644 (file)
@@ -15,9 +15,9 @@
  * with the NMI mode driver.
  */
  
-extern int nmi_init(struct oprofile_operations * ops);
-extern int nmi_timer_init(struct oprofile_operations * ops);
-extern void nmi_exit(void);
+extern int op_nmi_init(struct oprofile_operations * ops);
+extern int op_nmi_timer_init(struct oprofile_operations * ops);
+extern void op_nmi_exit(void);
 extern void x86_backtrace(struct pt_regs * const regs, unsigned int depth);
 
 
@@ -28,11 +28,11 @@ int __init oprofile_arch_init(struct oprofile_operations * ops)
        ret = -ENODEV;
 
 #ifdef CONFIG_X86_LOCAL_APIC
-       ret = nmi_init(ops);
+       ret = op_nmi_init(ops);
 #endif
 #ifdef CONFIG_X86_IO_APIC
        if (ret < 0)
-               ret = nmi_timer_init(ops);
+               ret = op_nmi_timer_init(ops);
 #endif
        ops->backtrace = x86_backtrace;
 
@@ -43,6 +43,6 @@ int __init oprofile_arch_init(struct oprofile_operations * ops)
 void oprofile_arch_exit(void)
 {
 #ifdef CONFIG_X86_LOCAL_APIC
-       nmi_exit();
+       op_nmi_exit();
 #endif
 }
index 255e4702d185e363558c5064751ae7be9f9c20c0..0493e8b8ec49266618b155fb3490f02854dc70db 100644 (file)
@@ -355,7 +355,7 @@ static int __init ppro_init(char ** cpu_type)
 /* in order to get driverfs right */
 static int using_nmi;
 
-int __init nmi_init(struct oprofile_operations *ops)
+int __init op_nmi_init(struct oprofile_operations *ops)
 {
        __u8 vendor = boot_cpu_data.x86_vendor;
        __u8 family = boot_cpu_data.x86;
@@ -420,7 +420,7 @@ int __init nmi_init(struct oprofile_operations *ops)
 }
 
 
-void nmi_exit(void)
+void op_nmi_exit(void)
 {
        if (using_nmi)
                exit_driverfs();
index c58d0c14f2744a0ae524f07d3f73089d9486e049..ad93cdd55d63bf20f20b8bf4ad7ab0329910017b 100644 (file)
@@ -40,7 +40,7 @@ static void timer_stop(void)
 }
 
 
-int __init nmi_timer_init(struct oprofile_operations * ops)
+int __init op_nmi_timer_init(struct oprofile_operations * ops)
 {
        extern int nmi_active;
 
index ade5bc57c34ceffc54c0e1f3a79f52879bc062e9..c96bea14b98f51301c0ec5a2be83d6142a1b646c 100644 (file)
@@ -165,7 +165,6 @@ static int __init pcibios_init(void)
        if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
                pcibios_sort();
 #endif
-       pci_assign_unassigned_resources();
        return 0;
 }
 
index 93a364c82150cddbe8886f8fc35d026120ae0e75..3cc480998a47d4000013cd093aeb0e26b7a5d2ff 100644 (file)
@@ -170,43 +170,26 @@ static void __init pcibios_allocate_resources(int pass)
 static int __init pcibios_assign_resources(void)
 {
        struct pci_dev *dev = NULL;
-       int idx;
-       struct resource *r;
-
-       for_each_pci_dev(dev) {
-               int class = dev->class >> 8;
-
-               /* Don't touch classless devices and host bridges */
-               if (!class || class == PCI_CLASS_BRIDGE_HOST)
-                       continue;
-
-               for(idx=0; idx<6; idx++) {
-                       r = &dev->resource[idx];
-
-                       /*
-                        *  Don't touch IDE controllers and I/O ports of video cards!
-                        */
-                       if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
-                           (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
-                               continue;
-
-                       /*
-                        *  We shall assign a new address to this resource, either because
-                        *  the BIOS forgot to do so or because we have decided the old
-                        *  address was unusable for some reason.
-                        */
-                       if (!r->start && r->end)
-                               pci_assign_resource(dev, idx);
-               }
+       struct resource *r, *pr;
 
-               if (pci_probe & PCI_ASSIGN_ROMS) {
+       if (!(pci_probe & PCI_ASSIGN_ROMS)) {
+               /* Try to use BIOS settings for ROMs, otherwise let
+                  pci_assign_unassigned_resources() allocate the new
+                  addresses. */
+               for_each_pci_dev(dev) {
                        r = &dev->resource[PCI_ROM_RESOURCE];
-                       r->end -= r->start;
-                       r->start = 0;
-                       if (r->end)
-                               pci_assign_resource(dev, PCI_ROM_RESOURCE);
+                       if (!r->flags || !r->start)
+                               continue;
+                       pr = pci_find_parent_resource(dev, r);
+                       if (!pr || request_resource(pr, r) < 0) {
+                               r->end -= r->start;
+                               r->start = 0;
+                       }
                }
        }
+
+       pci_assign_unassigned_resources();
+
        return 0;
 }
 
index c547c1af6fa1a86ea8e25f4dd62332c3f3302faa..7b0b9ad848e58eb9a723c16c87af4b1eb0aaa566 100644 (file)
@@ -42,25 +42,25 @@ void __save_processor_state(struct saved_context *ctxt)
        /*
         * descriptor tables
         */
-       asm volatile ("sgdt %0" : "=m" (ctxt->gdt_limit));
-       asm volatile ("sidt %0" : "=m" (ctxt->idt_limit));
-       asm volatile ("str %0"  : "=m" (ctxt->tr));
+       store_gdt(&ctxt->gdt_limit);
+       store_idt(&ctxt->idt_limit);
+       store_tr(ctxt->tr);
 
        /*
         * segment registers
         */
-       asm volatile ("movw %%es, %0" : "=m" (ctxt->es));
-       asm volatile ("movw %%fs, %0" : "=m" (ctxt->fs));
-       asm volatile ("movw %%gs, %0" : "=m" (ctxt->gs));
-       asm volatile ("movw %%ss, %0" : "=m" (ctxt->ss));
+       savesegment(es, ctxt->es);
+       savesegment(fs, ctxt->fs);
+       savesegment(gs, ctxt->gs);
+       savesegment(ss, ctxt->ss);
 
        /*
         * control registers 
         */
-       asm volatile ("movl %%cr0, %0" : "=r" (ctxt->cr0));
-       asm volatile ("movl %%cr2, %0" : "=r" (ctxt->cr2));
-       asm volatile ("movl %%cr3, %0" : "=r" (ctxt->cr3));
-       asm volatile ("movl %%cr4, %0" : "=r" (ctxt->cr4));
+       ctxt->cr0 = read_cr0();
+       ctxt->cr2 = read_cr2();
+       ctxt->cr3 = read_cr3();
+       ctxt->cr4 = read_cr4();
 }
 
 void save_processor_state(void)
@@ -84,7 +84,6 @@ static void fix_processor_context(void)
        struct tss_struct * t = &per_cpu(init_tss, cpu);
 
        set_tss_desc(cpu,t);    /* This just modifies memory; should not be necessary. But... This is necessary, because 386 hardware has concept of busy TSS or some similar stupidity. */
-        per_cpu(cpu_gdt_table, cpu)[GDT_ENTRY_TSS].b &= 0xfffffdff;
 
        load_TR_desc();                         /* This does ltr */
        load_LDT(&current->active_mm->context); /* This does lldt */
@@ -109,25 +108,25 @@ void __restore_processor_state(struct saved_context *ctxt)
        /*
         * control registers
         */
-       asm volatile ("movl %0, %%cr4" :: "r" (ctxt->cr4));
-       asm volatile ("movl %0, %%cr3" :: "r" (ctxt->cr3));
-       asm volatile ("movl %0, %%cr2" :: "r" (ctxt->cr2));
-       asm volatile ("movl %0, %%cr0" :: "r" (ctxt->cr0));
+       write_cr4(ctxt->cr4);
+       write_cr3(ctxt->cr3);
+       write_cr2(ctxt->cr2);
+       write_cr2(ctxt->cr0);
 
        /*
         * now restore the descriptor tables to their proper values
         * ltr is done i fix_processor_context().
         */
-       asm volatile ("lgdt %0" :: "m" (ctxt->gdt_limit));
-       asm volatile ("lidt %0" :: "m" (ctxt->idt_limit));
+       load_gdt(&ctxt->gdt_limit);
+       load_idt(&ctxt->idt_limit);
 
        /*
         * segment registers
         */
-       asm volatile ("movw %0, %%es" :: "r" (ctxt->es));
-       asm volatile ("movw %0, %%fs" :: "r" (ctxt->fs));
-       asm volatile ("movw %0, %%gs" :: "r" (ctxt->gs));
-       asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss));
+       loadsegment(es, ctxt->es);
+       loadsegment(fs, ctxt->fs);
+       loadsegment(gs, ctxt->gs);
+       loadsegment(ss, ctxt->ss);
 
        /*
         * sysenter MSRs
index 80988136f26d7dec0791f62c1df59eca73af35ea..17b5dbf8c311909faa9a1871da94868e89bbb547 100644 (file)
@@ -383,6 +383,12 @@ source "drivers/acpi/Kconfig"
 
 endif
 
+if PM
+
+source "arch/ia64/kernel/cpufreq/Kconfig"
+
+endif
+
 endmenu
 
 if !IA64_HP_SIM
@@ -428,6 +434,11 @@ config GENERIC_IRQ_PROBE
        bool
        default y
 
+config GENERIC_PENDING_IRQ
+       bool
+       depends on GENERIC_HARDIRQS && SMP
+       default y
+
 source "arch/ia64/hp/sim/Kconfig"
 
 source "arch/ia64/oprofile/Kconfig"
index 5c46928e3dc655739bf0081ce19f503848930054..30fdfb1d0a53e3d08c9f817eaf34a0bd7b9a78f3 100644 (file)
@@ -237,17 +237,6 @@ sal_emulator (long index, unsigned long in1, unsigned long in2,
        return ((struct sal_ret_values) {status, r9, r10, r11});
 }
 
-
-/*
- * This is here to work around a bug in egcs-1.1.1b that causes the
- * compiler to crash (seems like a bug in the new alias analysis code.
- */
-void *
-id (long addr)
-{
-       return (void *) addr;
-}
-
 struct ia64_boot_param *
 sys_fw_init (const char *args, int arglen)
 {
index 7dcb8582ae0d6c0b5cc8384485034585899b7a57..b42ec37be51c317911e1037d85718a9b95fdc045 100644 (file)
@@ -130,7 +130,7 @@ static void rs_stop(struct tty_struct *tty)
 
 static void rs_start(struct tty_struct *tty)
 {
-#if SIMSERIAL_DEBUG
+#ifdef SIMSERIAL_DEBUG
        printk("rs_start: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n",
                tty->stopped, tty->hw_stopped, tty->flow_stopped);
 #endif
index 829a6d80711c13827ecd5fe74d19f0ce4732a1dc..0708edb06cc4da8190f76eb4e16e1bafcb2e6833 100644 (file)
@@ -215,7 +215,7 @@ ia32_syscall_table:
        data8 sys32_fork
        data8 sys_read
        data8 sys_write
-       data8 sys32_open          /* 5 */
+       data8 compat_sys_open     /* 5 */
        data8 sys_close
        data8 sys32_waitpid
        data8 sys_creat
index ebb89be2aa2dba5acbcaf7773414ff7ca51a1b87..aa891c9bc9b67ac268970391f49122f37af4b22a 100644 (file)
@@ -29,7 +29,6 @@
 #include <asm/uaccess.h>
 #include <asm/rse.h>
 #include <asm/sigcontext.h>
-#include <asm/segment.h>
 
 #include "ia32priv.h"
 
index c1e20d65dd6cb4688391f928f43445aea644b66b..e29a8a55486a5e35fdc8eac3a2bb0acefc5cb062 100644 (file)
@@ -2359,37 +2359,6 @@ sys32_brk (unsigned int brk)
        return ret;
 }
 
-/*
- * Exactly like fs/open.c:sys_open(), except that it doesn't set the O_LARGEFILE flag.
- */
-asmlinkage long
-sys32_open (const char __user * filename, int flags, int mode)
-{
-       char * tmp;
-       int fd, error;
-
-       tmp = getname(filename);
-       fd = PTR_ERR(tmp);
-       if (!IS_ERR(tmp)) {
-               fd = get_unused_fd();
-               if (fd >= 0) {
-                       struct file *f = filp_open(tmp, flags, mode);
-                       error = PTR_ERR(f);
-                       if (IS_ERR(f))
-                               goto out_error;
-                       fd_install(fd, f);
-               }
-out:
-               putname(tmp);
-       }
-       return fd;
-
-out_error:
-       put_unused_fd(fd);
-       fd = error;
-       goto out;
-}
-
 /* Structure for ia32 emulation on ia64 */
 struct epoll_event32
 {
index e1fb68ddec26328f5ea7f19ce099628fea81b664..307514f7a2826207fc5e8da881f64c61c7f8a06c 100644 (file)
@@ -16,10 +16,11 @@ obj-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += acpi-ext.o
 obj-$(CONFIG_IA64_PALINFO)     += palinfo.o
 obj-$(CONFIG_IOSAPIC)          += iosapic.o
 obj-$(CONFIG_MODULES)          += module.o
-obj-$(CONFIG_SMP)              += smp.o smpboot.o domain.o
+obj-$(CONFIG_SMP)              += smp.o smpboot.o
 obj-$(CONFIG_NUMA)             += numa.o
 obj-$(CONFIG_PERFMON)          += perfmon_default_smpl.o
 obj-$(CONFIG_IA64_CYCLONE)     += cyclone.o
+obj-$(CONFIG_CPU_FREQ)         += cpufreq/
 obj-$(CONFIG_IA64_MCA_RECOVERY)        += mca_recovery.o
 obj-$(CONFIG_KPROBES)          += kprobes.o jprobes.o
 obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR)  += uncached.o
diff --git a/arch/ia64/kernel/cpufreq/Kconfig b/arch/ia64/kernel/cpufreq/Kconfig
new file mode 100644 (file)
index 0000000..2d9d527
--- /dev/null
@@ -0,0 +1,29 @@
+
+#
+# CPU Frequency scaling
+#
+
+menu "CPU Frequency scaling"
+
+source "drivers/cpufreq/Kconfig"
+
+if CPU_FREQ
+
+comment "CPUFreq processor drivers"
+
+config IA64_ACPI_CPUFREQ
+       tristate "ACPI Processor P-States driver"
+       select CPU_FREQ_TABLE
+       depends on ACPI_PROCESSOR
+       help
+       This driver adds a CPUFreq driver which utilizes the ACPI
+       Processor Performance States.
+
+       For details, take a look at <file:Documentation/cpu-freq/>.
+
+       If in doubt, say N.
+
+endif   # CPU_FREQ
+
+endmenu
+
diff --git a/arch/ia64/kernel/cpufreq/Makefile b/arch/ia64/kernel/cpufreq/Makefile
new file mode 100644 (file)
index 0000000..f748d34
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_IA64_ACPI_CPUFREQ)                += acpi-cpufreq.o
diff --git a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
new file mode 100644 (file)
index 0000000..da4d5cf
--- /dev/null
@@ -0,0 +1,499 @@
+/*
+ * arch/ia64/kernel/cpufreq/acpi-cpufreq.c
+ * This file provides the ACPI based P-state support. This
+ * module works with generic cpufreq infrastructure. Most of
+ * the code is based on i386 version
+ * (arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c)
+ *
+ * Copyright (C) 2005 Intel Corp
+ *      Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/pal.h>
+
+#include <linux/acpi.h>
+#include <acpi/processor.h>
+
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg)
+
+MODULE_AUTHOR("Venkatesh Pallipadi");
+MODULE_DESCRIPTION("ACPI Processor P-States Driver");
+MODULE_LICENSE("GPL");
+
+
+struct cpufreq_acpi_io {
+       struct acpi_processor_performance       acpi_data;
+       struct cpufreq_frequency_table          *freq_table;
+       unsigned int                            resume;
+};
+
+static struct cpufreq_acpi_io  *acpi_io_data[NR_CPUS];
+
+static struct cpufreq_driver acpi_cpufreq_driver;
+
+
+static int
+processor_set_pstate (
+       u32     value)
+{
+       s64 retval;
+
+       dprintk("processor_set_pstate\n");
+
+       retval = ia64_pal_set_pstate((u64)value);
+
+       if (retval) {
+               dprintk("Failed to set freq to 0x%x, with error 0x%x\n",
+                       value, retval);
+               return -ENODEV;
+       }
+       return (int)retval;
+}
+
+
+static int
+processor_get_pstate (
+       u32     *value)
+{
+       u64     pstate_index = 0;
+       s64     retval;
+
+       dprintk("processor_get_pstate\n");
+
+       retval = ia64_pal_get_pstate(&pstate_index);
+       *value = (u32) pstate_index;
+
+       if (retval)
+               dprintk("Failed to get current freq with "
+                       "error 0x%x, idx 0x%x\n", retval, *value);
+
+       return (int)retval;
+}
+
+
+/* To be used only after data->acpi_data is initialized */
+static unsigned
+extract_clock (
+       struct cpufreq_acpi_io *data,
+       unsigned value,
+       unsigned int cpu)
+{
+       unsigned long i;
+
+       dprintk("extract_clock\n");
+
+       for (i = 0; i < data->acpi_data.state_count; i++) {
+               if (value >= data->acpi_data.states[i].control)
+                       return data->acpi_data.states[i].core_frequency;
+       }
+       return data->acpi_data.states[i-1].core_frequency;
+}
+
+
+static unsigned int
+processor_get_freq (
+       struct cpufreq_acpi_io  *data,
+       unsigned int            cpu)
+{
+       int                     ret = 0;
+       u32                     value = 0;
+       cpumask_t               saved_mask;
+       unsigned long           clock_freq;
+
+       dprintk("processor_get_freq\n");
+
+       saved_mask = current->cpus_allowed;
+       set_cpus_allowed(current, cpumask_of_cpu(cpu));
+       if (smp_processor_id() != cpu) {
+               ret = -EAGAIN;
+               goto migrate_end;
+       }
+
+       /*
+        * processor_get_pstate gets the average frequency since the
+        * last get. So, do two PAL_get_freq()...
+        */
+       ret = processor_get_pstate(&value);
+       ret = processor_get_pstate(&value);
+
+       if (ret) {
+               set_cpus_allowed(current, saved_mask);
+               printk(KERN_WARNING "get performance failed with error %d\n",
+                      ret);
+               ret = -EAGAIN;
+               goto migrate_end;
+       }
+       clock_freq = extract_clock(data, value, cpu);
+       ret = (clock_freq*1000);
+
+migrate_end:
+       set_cpus_allowed(current, saved_mask);
+       return ret;
+}
+
+
+static int
+processor_set_freq (
+       struct cpufreq_acpi_io  *data,
+       unsigned int            cpu,
+       int                     state)
+{
+       int                     ret = 0;
+       u32                     value = 0;
+       struct cpufreq_freqs    cpufreq_freqs;
+       cpumask_t               saved_mask;
+       int                     retval;
+
+       dprintk("processor_set_freq\n");
+
+       saved_mask = current->cpus_allowed;
+       set_cpus_allowed(current, cpumask_of_cpu(cpu));
+       if (smp_processor_id() != cpu) {
+               retval = -EAGAIN;
+               goto migrate_end;
+       }
+
+       if (state == data->acpi_data.state) {
+               if (unlikely(data->resume)) {
+                       dprintk("Called after resume, resetting to P%d\n", state);
+                       data->resume = 0;
+               } else {
+                       dprintk("Already at target state (P%d)\n", state);
+                       retval = 0;
+                       goto migrate_end;
+               }
+       }
+
+       dprintk("Transitioning from P%d to P%d\n",
+               data->acpi_data.state, state);
+
+       /* cpufreq frequency struct */
+       cpufreq_freqs.cpu = cpu;
+       cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency;
+       cpufreq_freqs.new = data->freq_table[state].frequency;
+
+       /* notify cpufreq */
+       cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
+
+       /*
+        * First we write the target state's 'control' value to the
+        * control_register.
+        */
+
+       value = (u32) data->acpi_data.states[state].control;
+
+       dprintk("Transitioning to state: 0x%08x\n", value);
+
+       ret = processor_set_pstate(value);
+       if (ret) {
+               unsigned int tmp = cpufreq_freqs.new;
+               cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
+               cpufreq_freqs.new = cpufreq_freqs.old;
+               cpufreq_freqs.old = tmp;
+               cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
+               cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
+               printk(KERN_WARNING "Transition failed with error %d\n", ret);
+               retval = -ENODEV;
+               goto migrate_end;
+       }
+
+       cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
+
+       data->acpi_data.state = state;
+
+       retval = 0;
+
+migrate_end:
+       set_cpus_allowed(current, saved_mask);
+       return (retval);
+}
+
+
+static unsigned int
+acpi_cpufreq_get (
+       unsigned int            cpu)
+{
+       struct cpufreq_acpi_io *data = acpi_io_data[cpu];
+
+       dprintk("acpi_cpufreq_get\n");
+
+       return processor_get_freq(data, cpu);
+}
+
+
+static int
+acpi_cpufreq_target (
+       struct cpufreq_policy   *policy,
+       unsigned int target_freq,
+       unsigned int relation)
+{
+       struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
+       unsigned int next_state = 0;
+       unsigned int result = 0;
+
+       dprintk("acpi_cpufreq_setpolicy\n");
+
+       result = cpufreq_frequency_table_target(policy,
+                       data->freq_table, target_freq, relation, &next_state);
+       if (result)
+               return (result);
+
+       result = processor_set_freq(data, policy->cpu, next_state);
+
+       return (result);
+}
+
+
+static int
+acpi_cpufreq_verify (
+       struct cpufreq_policy   *policy)
+{
+       unsigned int result = 0;
+       struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
+
+       dprintk("acpi_cpufreq_verify\n");
+
+       result = cpufreq_frequency_table_verify(policy,
+                       data->freq_table);
+
+       return (result);
+}
+
+
+/*
+ * processor_init_pdc - let BIOS know about the SMP capabilities
+ * of this driver
+ * @perf: processor-specific acpi_io_data struct
+ * @cpu: CPU being initialized
+ *
+ * To avoid issues with legacy OSes, some BIOSes require to be informed of
+ * the SMP capabilities of OS P-state driver. Here we set the bits in _PDC
+ * accordingly. Actual call to _PDC is done in driver/acpi/processor.c
+ */
+static void
+processor_init_pdc (
+               struct acpi_processor_performance *perf,
+               unsigned int cpu,
+               struct acpi_object_list *obj_list
+               )
+{
+       union acpi_object *obj;
+       u32 *buf;
+
+       dprintk("processor_init_pdc\n");
+
+       perf->pdc = NULL;
+       /* Initialize pdc. It will be used later. */
+       if (!obj_list)
+               return;
+
+       if (!(obj_list->count && obj_list->pointer))
+               return;
+
+       obj = obj_list->pointer;
+       if ((obj->buffer.length == 12) && obj->buffer.pointer) {
+               buf = (u32 *)obj->buffer.pointer;
+                       buf[0] = ACPI_PDC_REVISION_ID;
+                       buf[1] = 1;
+                       buf[2] = ACPI_PDC_EST_CAPABILITY_SMP;
+               perf->pdc = obj_list;
+       }
+       return;
+}
+
+
+static int
+acpi_cpufreq_cpu_init (
+       struct cpufreq_policy   *policy)
+{
+       unsigned int            i;
+       unsigned int            cpu = policy->cpu;
+       struct cpufreq_acpi_io  *data;
+       unsigned int            result = 0;
+
+       union acpi_object               arg0 = {ACPI_TYPE_BUFFER};
+       u32                             arg0_buf[3];
+       struct acpi_object_list         arg_list = {1, &arg0};
+
+       dprintk("acpi_cpufreq_cpu_init\n");
+       /* setup arg_list for _PDC settings */
+        arg0.buffer.length = 12;
+        arg0.buffer.pointer = (u8 *) arg0_buf;
+
+       data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
+       if (!data)
+               return (-ENOMEM);
+
+       memset(data, 0, sizeof(struct cpufreq_acpi_io));
+
+       acpi_io_data[cpu] = data;
+
+       processor_init_pdc(&data->acpi_data, cpu, &arg_list);
+       result = acpi_processor_register_performance(&data->acpi_data, cpu);
+       data->acpi_data.pdc = NULL;
+
+       if (result)
+               goto err_free;
+
+       /* capability check */
+       if (data->acpi_data.state_count <= 1) {
+               dprintk("No P-States\n");
+               result = -ENODEV;
+               goto err_unreg;
+       }
+
+       if ((data->acpi_data.control_register.space_id !=
+                                       ACPI_ADR_SPACE_FIXED_HARDWARE) ||
+           (data->acpi_data.status_register.space_id !=
+                                       ACPI_ADR_SPACE_FIXED_HARDWARE)) {
+               dprintk("Unsupported address space [%d, %d]\n",
+                       (u32) (data->acpi_data.control_register.space_id),
+                       (u32) (data->acpi_data.status_register.space_id));
+               result = -ENODEV;
+               goto err_unreg;
+       }
+
+       /* alloc freq_table */
+       data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) *
+                                  (data->acpi_data.state_count + 1),
+                                  GFP_KERNEL);
+       if (!data->freq_table) {
+               result = -ENOMEM;
+               goto err_unreg;
+       }
+
+       /* detect transition latency */
+       policy->cpuinfo.transition_latency = 0;
+       for (i=0; i<data->acpi_data.state_count; i++) {
+               if ((data->acpi_data.states[i].transition_latency * 1000) >
+                   policy->cpuinfo.transition_latency) {
+                       policy->cpuinfo.transition_latency =
+                           data->acpi_data.states[i].transition_latency * 1000;
+               }
+       }
+       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+       policy->cur = processor_get_freq(data, policy->cpu);
+
+       /* table init */
+       for (i = 0; i <= data->acpi_data.state_count; i++)
+       {
+               data->freq_table[i].index = i;
+               if (i < data->acpi_data.state_count) {
+                       data->freq_table[i].frequency =
+                             data->acpi_data.states[i].core_frequency * 1000;
+               } else {
+                       data->freq_table[i].frequency = CPUFREQ_TABLE_END;
+               }
+       }
+
+       result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table);
+       if (result) {
+               goto err_freqfree;
+       }
+
+       /* notify BIOS that we exist */
+       acpi_processor_notify_smm(THIS_MODULE);
+
+       printk(KERN_INFO "acpi-cpufreq: CPU%u - ACPI performance management "
+              "activated.\n", cpu);
+
+       for (i = 0; i < data->acpi_data.state_count; i++)
+               dprintk("     %cP%d: %d MHz, %d mW, %d uS, %d uS, 0x%x 0x%x\n",
+                       (i == data->acpi_data.state?'*':' '), i,
+                       (u32) data->acpi_data.states[i].core_frequency,
+                       (u32) data->acpi_data.states[i].power,
+                       (u32) data->acpi_data.states[i].transition_latency,
+                       (u32) data->acpi_data.states[i].bus_master_latency,
+                       (u32) data->acpi_data.states[i].status,
+                       (u32) data->acpi_data.states[i].control);
+
+       cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu);
+
+       /* the first call to ->target() should result in us actually
+        * writing something to the appropriate registers. */
+       data->resume = 1;
+
+       return (result);
+
+ err_freqfree:
+       kfree(data->freq_table);
+ err_unreg:
+       acpi_processor_unregister_performance(&data->acpi_data, cpu);
+ err_free:
+       kfree(data);
+       acpi_io_data[cpu] = NULL;
+
+       return (result);
+}
+
+
+static int
+acpi_cpufreq_cpu_exit (
+       struct cpufreq_policy   *policy)
+{
+       struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
+
+       dprintk("acpi_cpufreq_cpu_exit\n");
+
+       if (data) {
+               cpufreq_frequency_table_put_attr(policy->cpu);
+               acpi_io_data[policy->cpu] = NULL;
+               acpi_processor_unregister_performance(&data->acpi_data,
+                                                     policy->cpu);
+               kfree(data);
+       }
+
+       return (0);
+}
+
+
+static struct freq_attr* acpi_cpufreq_attr[] = {
+       &cpufreq_freq_attr_scaling_available_freqs,
+       NULL,
+};
+
+
+static struct cpufreq_driver acpi_cpufreq_driver = {
+       .verify         = acpi_cpufreq_verify,
+       .target         = acpi_cpufreq_target,
+       .get            = acpi_cpufreq_get,
+       .init           = acpi_cpufreq_cpu_init,
+       .exit           = acpi_cpufreq_cpu_exit,
+       .name           = "acpi-cpufreq",
+       .owner          = THIS_MODULE,
+       .attr           = acpi_cpufreq_attr,
+};
+
+
+static int __init
+acpi_cpufreq_init (void)
+{
+       dprintk("acpi_cpufreq_init\n");
+
+       return cpufreq_register_driver(&acpi_cpufreq_driver);
+}
+
+
+static void __exit
+acpi_cpufreq_exit (void)
+{
+       dprintk("acpi_cpufreq_exit\n");
+
+       cpufreq_unregister_driver(&acpi_cpufreq_driver);
+       return;
+}
+
+
+late_initcall(acpi_cpufreq_init);
+module_exit(acpi_cpufreq_exit);
+
diff --git a/arch/ia64/kernel/domain.c b/arch/ia64/kernel/domain.c
deleted file mode 100644 (file)
index bbb8efe..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * arch/ia64/kernel/domain.c
- * Architecture specific sched-domains builder.
- *
- * Copyright (C) 2004 Jesse Barnes
- * Copyright (C) 2004 Silicon Graphics, Inc.
- */
-
-#include <linux/sched.h>
-#include <linux/percpu.h>
-#include <linux/slab.h>
-#include <linux/cpumask.h>
-#include <linux/init.h>
-#include <linux/topology.h>
-#include <linux/nodemask.h>
-
-#define SD_NODES_PER_DOMAIN 16
-
-#ifdef CONFIG_NUMA
-/**
- * find_next_best_node - find the next node to include in a sched_domain
- * @node: node whose sched_domain we're building
- * @used_nodes: nodes already in the sched_domain
- *
- * Find the next node to include in a given scheduling domain.  Simply
- * finds the closest node not already in the @used_nodes map.
- *
- * Should use nodemask_t.
- */
-static int find_next_best_node(int node, unsigned long *used_nodes)
-{
-       int i, n, val, min_val, best_node = 0;
-
-       min_val = INT_MAX;
-
-       for (i = 0; i < MAX_NUMNODES; i++) {
-               /* Start at @node */
-               n = (node + i) % MAX_NUMNODES;
-
-               if (!nr_cpus_node(n))
-                       continue;
-
-               /* Skip already used nodes */
-               if (test_bit(n, used_nodes))
-                       continue;
-
-               /* Simple min distance search */
-               val = node_distance(node, n);
-
-               if (val < min_val) {
-                       min_val = val;
-                       best_node = n;
-               }
-       }
-
-       set_bit(best_node, used_nodes);
-       return best_node;
-}
-
-/**
- * sched_domain_node_span - get a cpumask for a node's sched_domain
- * @node: node whose cpumask we're constructing
- * @size: number of nodes to include in this span
- *
- * Given a node, construct a good cpumask for its sched_domain to span.  It
- * should be one that prevents unnecessary balancing, but also spreads tasks
- * out optimally.
- */
-static cpumask_t sched_domain_node_span(int node)
-{
-       int i;
-       cpumask_t span, nodemask;
-       DECLARE_BITMAP(used_nodes, MAX_NUMNODES);
-
-       cpus_clear(span);
-       bitmap_zero(used_nodes, MAX_NUMNODES);
-
-       nodemask = node_to_cpumask(node);
-       cpus_or(span, span, nodemask);
-       set_bit(node, used_nodes);
-
-       for (i = 1; i < SD_NODES_PER_DOMAIN; i++) {
-               int next_node = find_next_best_node(node, used_nodes);
-               nodemask = node_to_cpumask(next_node);
-               cpus_or(span, span, nodemask);
-       }
-
-       return span;
-}
-#endif
-
-/*
- * At the moment, CONFIG_SCHED_SMT is never defined, but leave it in so we
- * can switch it on easily if needed.
- */
-#ifdef CONFIG_SCHED_SMT
-static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
-static struct sched_group sched_group_cpus[NR_CPUS];
-static int cpu_to_cpu_group(int cpu)
-{
-       return cpu;
-}
-#endif
-
-static DEFINE_PER_CPU(struct sched_domain, phys_domains);
-static struct sched_group sched_group_phys[NR_CPUS];
-static int cpu_to_phys_group(int cpu)
-{
-#ifdef CONFIG_SCHED_SMT
-       return first_cpu(cpu_sibling_map[cpu]);
-#else
-       return cpu;
-#endif
-}
-
-#ifdef CONFIG_NUMA
-/*
- * The init_sched_build_groups can't handle what we want to do with node
- * groups, so roll our own. Now each node has its own list of groups which
- * gets dynamically allocated.
- */
-static DEFINE_PER_CPU(struct sched_domain, node_domains);
-static struct sched_group *sched_group_nodes[MAX_NUMNODES];
-
-static DEFINE_PER_CPU(struct sched_domain, allnodes_domains);
-static struct sched_group sched_group_allnodes[MAX_NUMNODES];
-
-static int cpu_to_allnodes_group(int cpu)
-{
-       return cpu_to_node(cpu);
-}
-#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)
-{
-       int i;
-
-       /*
-        * Set up domains for cpus specified by the cpu_map.
-        */
-       for_each_cpu_mask(i, *cpu_map) {
-               int group;
-               struct sched_domain *sd = NULL, *p;
-               cpumask_t nodemask = node_to_cpumask(cpu_to_node(i));
-
-               cpus_and(nodemask, nodemask, *cpu_map);
-
-#ifdef CONFIG_NUMA
-               if (num_online_cpus()
-                               > SD_NODES_PER_DOMAIN*cpus_weight(nodemask)) {
-                       sd = &per_cpu(allnodes_domains, i);
-                       *sd = SD_ALLNODES_INIT;
-                       sd->span = *cpu_map;
-                       group = cpu_to_allnodes_group(i);
-                       sd->groups = &sched_group_allnodes[group];
-                       p = sd;
-               } else
-                       p = NULL;
-
-               sd = &per_cpu(node_domains, i);
-               *sd = SD_NODE_INIT;
-               sd->span = sched_domain_node_span(cpu_to_node(i));
-               sd->parent = p;
-               cpus_and(sd->span, sd->span, *cpu_map);
-#endif
-
-               p = sd;
-               sd = &per_cpu(phys_domains, i);
-               group = cpu_to_phys_group(i);
-               *sd = SD_CPU_INIT;
-               sd->span = nodemask;
-               sd->parent = p;
-               sd->groups = &sched_group_phys[group];
-
-#ifdef CONFIG_SCHED_SMT
-               p = sd;
-               sd = &per_cpu(cpu_domains, i);
-               group = cpu_to_cpu_group(i);
-               *sd = SD_SIBLING_INIT;
-               sd->span = cpu_sibling_map[i];
-               cpus_and(sd->span, sd->span, *cpu_map);
-               sd->parent = p;
-               sd->groups = &sched_group_cpus[group];
-#endif
-       }
-
-#ifdef CONFIG_SCHED_SMT
-       /* Set up CPU (sibling) groups */
-       for_each_cpu_mask(i, *cpu_map) {
-               cpumask_t this_sibling_map = cpu_sibling_map[i];
-               cpus_and(this_sibling_map, this_sibling_map, *cpu_map);
-               if (i != first_cpu(this_sibling_map))
-                       continue;
-
-               init_sched_build_groups(sched_group_cpus, this_sibling_map,
-                                               &cpu_to_cpu_group);
-       }
-#endif
-
-       /* Set up physical groups */
-       for (i = 0; i < MAX_NUMNODES; i++) {
-               cpumask_t nodemask = node_to_cpumask(i);
-
-               cpus_and(nodemask, nodemask, *cpu_map);
-               if (cpus_empty(nodemask))
-                       continue;
-
-               init_sched_build_groups(sched_group_phys, nodemask,
-                                               &cpu_to_phys_group);
-       }
-
-#ifdef CONFIG_NUMA
-       init_sched_build_groups(sched_group_allnodes, *cpu_map,
-                               &cpu_to_allnodes_group);
-
-       for (i = 0; i < MAX_NUMNODES; i++) {
-               /* Set up node groups */
-               struct sched_group *sg, *prev;
-               cpumask_t nodemask = node_to_cpumask(i);
-               cpumask_t domainspan;
-               cpumask_t covered = CPU_MASK_NONE;
-               int j;
-
-               cpus_and(nodemask, nodemask, *cpu_map);
-               if (cpus_empty(nodemask))
-                       continue;
-
-               domainspan = sched_domain_node_span(i);
-               cpus_and(domainspan, domainspan, *cpu_map);
-
-               sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL);
-               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;
-               cpus_or(covered, covered, nodemask);
-               prev = sg;
-
-               for (j = 0; j < MAX_NUMNODES; j++) {
-                       cpumask_t tmp, notcovered;
-                       int n = (i + j) % MAX_NUMNODES;
-
-                       cpus_complement(notcovered, covered);
-                       cpus_and(tmp, notcovered, *cpu_map);
-                       cpus_and(tmp, tmp, domainspan);
-                       if (cpus_empty(tmp))
-                               break;
-
-                       nodemask = node_to_cpumask(n);
-                       cpus_and(tmp, tmp, nodemask);
-                       if (cpus_empty(tmp))
-                               continue;
-
-                       sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL);
-                       if (!sg) {
-                               printk(KERN_WARNING
-                               "Can not alloc domain group for node %d\n", j);
-                               break;
-                       }
-                       sg->cpu_power = 0;
-                       sg->cpumask = tmp;
-                       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 */
-       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;
-#endif
-
-               sd = &per_cpu(phys_domains, i);
-               power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
-                               (cpus_weight(sd->groups->cpumask)-1) / 10;
-               sd->groups->cpu_power = power;
-
-#ifdef CONFIG_NUMA
-               sd = &per_cpu(allnodes_domains, i);
-               if (sd->groups) {
-                       power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
-                               (cpus_weight(sd->groups->cpumask)-1) / 10;
-                       sd->groups->cpu_power = power;
-               }
-#endif
-       }
-
-#ifdef CONFIG_NUMA
-       for (i = 0; i < MAX_NUMNODES; i++) {
-               struct sched_group *sg = sched_group_nodes[i];
-               int j;
-
-               if (sg == NULL)
-                       continue;
-next_sg:
-               for_each_cpu_mask(j, sg->cpumask) {
-                       struct sched_domain *sd;
-                       int power;
-
-                       sd = &per_cpu(phys_domains, j);
-                       if (j != first_cpu(sd->groups->cpumask)) {
-                               /*
-                                * Only add "power" once for each
-                                * physical package.
-                                */
-                               continue;
-                       }
-                       power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
-                               (cpus_weight(sd->groups->cpumask)-1) / 10;
-
-                       sg->cpu_power += power;
-               }
-               sg = sg->next;
-               if (sg != sched_group_nodes[i])
-                       goto next_sg;
-       }
-#endif
-
-       /* Attach the domains */
-       for_each_cpu_mask(i, *cpu_map) {
-               struct sched_domain *sd;
-#ifdef CONFIG_SCHED_SMT
-               sd = &per_cpu(cpu_domains, i);
-#else
-               sd = &per_cpu(phys_domains, i);
-#endif
-               cpu_attach_domain(sd, i);
-       }
-}
-/*
- * Set up scheduler domains and groups.  Callers must hold the hotplug lock.
- */
-void arch_init_sched_domains(const cpumask_t *cpu_map)
-{
-       cpumask_t cpu_default_map;
-
-       /*
-        * Setup mask for cpus without special case scheduling requirements.
-        * For now this just excludes isolated cpus, but could be used to
-        * exclude other special cases in the future.
-        */
-       cpus_andnot(cpu_default_map, *cpu_map, cpu_isolated_map);
-
-       build_sched_domains(&cpu_default_map);
-}
-
-void arch_destroy_sched_domains(const cpumask_t *cpu_map)
-{
-#ifdef CONFIG_NUMA
-       int i;
-       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;
-               sched_group_nodes[i] = NULL;
-       }
-#endif
-}
-
index 28f2aadc38d00ed2318be5690648b563d9044776..205d980282612e8a4f41ccd97858df3ac5da5dde 100644 (file)
@@ -91,23 +91,8 @@ skip:
 }
 
 #ifdef CONFIG_SMP
-/*
- * This is updated when the user sets irq affinity via /proc
- */
-static cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS];
-static unsigned long pending_irq_redir[BITS_TO_LONGS(NR_IRQS)];
-
 static char irq_redir [NR_IRQS]; // = { [0 ... NR_IRQS-1] = 1 };
 
-/*
- * Arch specific routine for deferred write to iosapic rte to reprogram
- * intr destination.
- */
-void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
-{
-       pending_irq_cpumask[irq] = mask_val;
-}
-
 void set_irq_affinity_info (unsigned int irq, int hwid, int redir)
 {
        cpumask_t mask = CPU_MASK_NONE;
@@ -116,32 +101,10 @@ void set_irq_affinity_info (unsigned int irq, int hwid, int redir)
 
        if (irq < NR_IRQS) {
                irq_affinity[irq] = mask;
+               set_irq_info(irq, mask);
                irq_redir[irq] = (char) (redir & 0xff);
        }
 }
-
-
-void move_irq(int irq)
-{
-       /* note - we hold desc->lock */
-       cpumask_t tmp;
-       irq_desc_t *desc = irq_descp(irq);
-       int redir = test_bit(irq, pending_irq_redir);
-
-       if (unlikely(!desc->handler->set_affinity))
-               return;
-
-       if (!cpus_empty(pending_irq_cpumask[irq])) {
-               cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map);
-               if (unlikely(!cpus_empty(tmp))) {
-                       desc->handler->set_affinity(irq | (redir ? IA64_IRQ_REDIRECTED : 0),
-                                                   pending_irq_cpumask[irq]);
-               }
-               cpus_clear(pending_irq_cpumask[irq]);
-       }
-}
-
-
 #endif /* CONFIG_SMP */
 
 #ifdef CONFIG_HOTPLUG_CPU
index b7fa3ccd2b0f7ca124836866284a8762d67207ac..2323377e36950ee236a662bcddada08c2f423d45 100644 (file)
@@ -49,6 +49,7 @@
        /*
         * void jprobe_break(void)
         */
+       .section .kprobes.text, "ax"
 ENTRY(jprobe_break)
        break.m 0x80300
 END(jprobe_break)
index 884f5cd27d8a656856a46342f616d4a198ec25c6..471086b808a4b942781aa19abe940fb08dc8533b 100644 (file)
@@ -87,12 +87,25 @@ static enum instruction_type bundle_encoding[32][3] = {
  * is IP relative instruction and update the kprobe
  * inst flag accordingly
  */
-static void update_kprobe_inst_flag(uint template, uint  slot, uint major_opcode,
-       unsigned long kprobe_inst, struct kprobe *p)
+static void __kprobes update_kprobe_inst_flag(uint template, uint  slot,
+                                             uint major_opcode,
+                                             unsigned long kprobe_inst,
+                                             struct kprobe *p)
 {
        p->ainsn.inst_flag = 0;
        p->ainsn.target_br_reg = 0;
 
+       /* Check for Break instruction
+        * Bits 37:40 Major opcode to be zero
+        * Bits 27:32 X6 to be zero
+        * Bits 32:35 X3 to be zero
+        */
+       if ((!major_opcode) && (!((kprobe_inst >> 27) & 0x1FF)) ) {
+               /* is a break instruction */
+               p->ainsn.inst_flag |= INST_FLAG_BREAK_INST;
+               return;
+       }
+
        if (bundle_encoding[template][slot] == B) {
                switch (major_opcode) {
                  case INDIRECT_CALL_OPCODE:
@@ -126,8 +139,10 @@ static void update_kprobe_inst_flag(uint template, uint  slot, uint major_opcode
  * Returns 0 if supported
  * Returns -EINVAL if unsupported
  */
-static int unsupported_inst(uint template, uint  slot, uint major_opcode,
-       unsigned long kprobe_inst, struct kprobe *p)
+static int __kprobes unsupported_inst(uint template, uint  slot,
+                                     uint major_opcode,
+                                     unsigned long kprobe_inst,
+                                     struct kprobe *p)
 {
        unsigned long addr = (unsigned long)p->addr;
 
@@ -168,8 +183,9 @@ static int unsupported_inst(uint template, uint  slot, uint major_opcode,
  * on which we are inserting kprobe is cmp instruction
  * with ctype as unc.
  */
-static uint is_cmp_ctype_unc_inst(uint template, uint slot, uint major_opcode,
-unsigned long kprobe_inst)
+static uint __kprobes is_cmp_ctype_unc_inst(uint template, uint slot,
+                                           uint major_opcode,
+                                           unsigned long kprobe_inst)
 {
        cmp_inst_t cmp_inst;
        uint ctype_unc = 0;
@@ -201,8 +217,10 @@ out:
  * In this function we override the bundle with
  * the break instruction at the given slot.
  */
-static void prepare_break_inst(uint template, uint  slot, uint major_opcode,
-       unsigned long kprobe_inst, struct kprobe *p)
+static void __kprobes prepare_break_inst(uint template, uint  slot,
+                                        uint major_opcode,
+                                        unsigned long kprobe_inst,
+                                        struct kprobe *p)
 {
        unsigned long break_inst = BREAK_INST;
        bundle_t *bundle = &p->ainsn.insn.bundle;
@@ -271,7 +289,8 @@ static inline int in_ivt_functions(unsigned long addr)
                && addr < (unsigned long)__end_ivt_text);
 }
 
-static int valid_kprobe_addr(int template, int slot, unsigned long addr)
+static int __kprobes valid_kprobe_addr(int template, int slot,
+                                      unsigned long addr)
 {
        if ((slot > 2) || ((bundle_encoding[template][1] == L) && slot > 1)) {
                printk(KERN_WARNING "Attempting to insert unaligned kprobe "
@@ -323,7 +342,7 @@ static void kretprobe_trampoline(void)
  *    - cleanup by marking the instance as unused
  *    - long jump back to the original return address
  */
-int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 {
        struct kretprobe_instance *ri = NULL;
        struct hlist_head *head;
@@ -381,7 +400,8 @@ int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
         return 1;
 }
 
-void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
+void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+                                     struct pt_regs *regs)
 {
        struct kretprobe_instance *ri;
 
@@ -399,7 +419,7 @@ void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
        }
 }
 
-int arch_prepare_kprobe(struct kprobe *p)
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
 {
        unsigned long addr = (unsigned long) p->addr;
        unsigned long *kprobe_addr = (unsigned long *)(addr & ~0xFULL);
@@ -430,7 +450,7 @@ int arch_prepare_kprobe(struct kprobe *p)
        return 0;
 }
 
-void arch_arm_kprobe(struct kprobe *p)
+void __kprobes arch_arm_kprobe(struct kprobe *p)
 {
        unsigned long addr = (unsigned long)p->addr;
        unsigned long arm_addr = addr & ~0xFULL;
@@ -439,7 +459,7 @@ void arch_arm_kprobe(struct kprobe *p)
        flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t));
 }
 
-void arch_disarm_kprobe(struct kprobe *p)
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
 {
        unsigned long addr = (unsigned long)p->addr;
        unsigned long arm_addr = addr & ~0xFULL;
@@ -449,7 +469,7 @@ void arch_disarm_kprobe(struct kprobe *p)
        flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t));
 }
 
-void arch_remove_kprobe(struct kprobe *p)
+void __kprobes arch_remove_kprobe(struct kprobe *p)
 {
 }
 
@@ -461,7 +481,7 @@ void arch_remove_kprobe(struct kprobe *p)
  * to original stack address, handle the case where we need to fixup the
  * relative IP address and/or fixup branch register.
  */
-static void resume_execution(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
 {
        unsigned long bundle_addr = ((unsigned long) (&p->opcode.bundle)) & ~0xFULL;
        unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL;
@@ -528,13 +548,16 @@ turn_ss_off:
        ia64_psr(regs)->ss = 0;
 }
 
-static void prepare_ss(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes prepare_ss(struct kprobe *p, struct pt_regs *regs)
 {
        unsigned long bundle_addr = (unsigned long) &p->opcode.bundle;
        unsigned long slot = (unsigned long)p->addr & 0xf;
 
-       /* Update instruction pointer (IIP) and slot number (IPSR.ri) */
-       regs->cr_iip = bundle_addr & ~0xFULL;
+       /* single step inline if break instruction */
+       if (p->ainsn.inst_flag == INST_FLAG_BREAK_INST)
+               regs->cr_iip = (unsigned long)p->addr & ~0xFULL;
+       else
+               regs->cr_iip = bundle_addr & ~0xFULL;
 
        if (slot > 2)
                slot = 0;
@@ -545,7 +568,39 @@ static void prepare_ss(struct kprobe *p, struct pt_regs *regs)
        ia64_psr(regs)->ss = 1;
 }
 
-static int pre_kprobes_handler(struct die_args *args)
+static int __kprobes is_ia64_break_inst(struct pt_regs *regs)
+{
+       unsigned int slot = ia64_psr(regs)->ri;
+       unsigned int template, major_opcode;
+       unsigned long kprobe_inst;
+       unsigned long *kprobe_addr = (unsigned long *)regs->cr_iip;
+       bundle_t bundle;
+
+       memcpy(&bundle, kprobe_addr, sizeof(bundle_t));
+       template = bundle.quad0.template;
+
+       /* Move to slot 2, if bundle is MLX type and kprobe slot is 1 */
+       if (slot == 1 && bundle_encoding[template][1] == L)
+               slot++;
+
+       /* Get Kprobe probe instruction at given slot*/
+       get_kprobe_inst(&bundle, slot, &kprobe_inst, &major_opcode);
+
+       /* For break instruction,
+        * Bits 37:40 Major opcode to be zero
+        * Bits 27:32 X6 to be zero
+        * Bits 32:35 X3 to be zero
+        */
+       if (major_opcode || ((kprobe_inst >> 27) & 0x1FF) ) {
+               /* Not a break instruction */
+               return 0;
+       }
+
+       /* Is a break instruction */
+       return 1;
+}
+
+static int __kprobes pre_kprobes_handler(struct die_args *args)
 {
        struct kprobe *p;
        int ret = 0;
@@ -558,7 +613,9 @@ static int pre_kprobes_handler(struct die_args *args)
        if (kprobe_running()) {
                p = get_kprobe(addr);
                if (p) {
-                       if (kprobe_status == KPROBE_HIT_SS) {
+                       if ( (kprobe_status == KPROBE_HIT_SS) &&
+                            (p->ainsn.inst_flag == INST_FLAG_BREAK_INST)) {
+                               ia64_psr(regs)->ss = 0;
                                unlock_kprobes();
                                goto no_kprobe;
                        }
@@ -592,6 +649,19 @@ static int pre_kprobes_handler(struct die_args *args)
        p = get_kprobe(addr);
        if (!p) {
                unlock_kprobes();
+               if (!is_ia64_break_inst(regs)) {
+                       /*
+                        * The breakpoint instruction was removed right
+                        * after we hit it.  Another cpu has removed
+                        * either a probepoint or a debugger breakpoint
+                        * at this address.  In either case, no further
+                        * handling of this interrupt is appropriate.
+                        */
+                       ret = 1;
+
+               }
+
+               /* Not one of our break, let kernel handle it */
                goto no_kprobe;
        }
 
@@ -616,7 +686,7 @@ no_kprobe:
        return ret;
 }
 
-static int post_kprobes_handler(struct pt_regs *regs)
+static int __kprobes post_kprobes_handler(struct pt_regs *regs)
 {
        if (!kprobe_running())
                return 0;
@@ -641,7 +711,7 @@ out:
        return 1;
 }
 
-static int kprobes_fault_handler(struct pt_regs *regs, int trapnr)
+static int __kprobes kprobes_fault_handler(struct pt_regs *regs, int trapnr)
 {
        if (!kprobe_running())
                return 0;
@@ -659,8 +729,8 @@ static int kprobes_fault_handler(struct pt_regs *regs, int trapnr)
        return 0;
 }
 
-int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
-                            void *data)
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+                                      unsigned long val, void *data)
 {
        struct die_args *args = (struct die_args *)data;
        switch(val) {
@@ -681,7 +751,7 @@ int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
        return NOTIFY_DONE;
 }
 
-int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 {
        struct jprobe *jp = container_of(p, struct jprobe, kp);
        unsigned long addr = ((struct fnptr *)(jp->entry))->ip;
@@ -703,7 +773,7 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
        return 1;
 }
 
-int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 {
        *regs = jprobe_saved_regs;
        return 1;
index b8a0a7d257a9b3f427561faadb6d98eaf7b4648f..774f34b675cfdb3c688e2831b4fb599d1081b2ae 100644 (file)
@@ -467,15 +467,12 @@ handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigse
                if (!setup_frame(sig, ka, info, oldset, scr))
                        return 0;
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               {
-                       sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
-                       sigaddset(&current->blocked, sig);
-                       recalc_sigpending();
-               }
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
+               sigaddset(&current->blocked, sig);
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
        return 1;
 }
 
index 770fab37928ee9e4c3870b8875473f7a53d1213b..f2dbcd1db0d4dc99b3baca0d0b677c3ed788a58c 100644 (file)
@@ -35,7 +35,7 @@ arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len
                return -ENOMEM;
 
 #ifdef CONFIG_HUGETLB_PAGE
-       if (REGION_NUMBER(addr) == REGION_HPAGE)
+       if (REGION_NUMBER(addr) == RGN_HPAGE)
                addr = 0;
 #endif
        if (!addr)
index 4440c8343fa4303df0dbc658954d9d3cebc1ab8d..f970359e7edf2fbb67117695c2f7b1a25f86b4d0 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/vt_kern.h>             /* For unblank_screen() */
 #include <linux/module.h>       /* for EXPORT_SYMBOL */
 #include <linux/hardirq.h>
+#include <linux/kprobes.h>
 
 #include <asm/fpswa.h>
 #include <asm/ia32.h>
@@ -122,7 +123,7 @@ die_if_kernel (char *str, struct pt_regs *regs, long err)
 }
 
 void
-ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
+__kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
 {
        siginfo_t siginfo;
        int sig, code;
@@ -444,7 +445,7 @@ ia64_illegal_op_fault (unsigned long ec, long arg1, long arg2, long arg3,
        return rv;
 }
 
-void
+void __kprobes
 ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
            unsigned long iim, unsigned long itir, long arg5, long arg6,
            long arg7, struct pt_regs regs)
index 490dfc9ab47ffd51bd02167047e7dcb3a9de5041..4e9d06c48a8ba40c3cb70d39e352efa793f26f48 100644 (file)
@@ -184,7 +184,7 @@ uncached_free_page(unsigned long maddr)
 {
        int node;
 
-       node = nasid_to_cnodeid(NASID_GET(maddr));
+       node = paddr_to_nid(maddr - __IA64_UNCACHED_OFFSET);
 
        dprintk(KERN_DEBUG "uncached_free_page(%lx) on node %i\n", maddr, node);
 
@@ -217,7 +217,7 @@ uncached_build_memmap(unsigned long start, unsigned long end, void *arg)
 
        memset((char *)vstart, 0, length);
 
-       node = nasid_to_cnodeid(NASID_GET(start));
+       node = paddr_to_nid(start);
 
        for (; vstart < vend ; vstart += PAGE_SIZE) {
                dprintk(KERN_INFO "sticking %lx into the pool!\n", vstart);
index a676e79e0681bb183986e3036e6484f8878c4e70..30d8564e96032bd9b7cc9735721457627db9ff7d 100644 (file)
@@ -48,6 +48,7 @@ SECTIONS
        *(.text)
        SCHED_TEXT
        LOCK_TEXT
+       KPROBES_TEXT
        *(.gnu.linkonce.t*)
     }
   .text2 : AT(ADDR(.text2) - LOAD_OFFSET)
index 1902c3c2ef923f57ff19b9550cd34bb75ce7a4bb..799407e7726f2a9c54f301ce50f71c253f514174 100644 (file)
@@ -6,7 +6,7 @@ obj-y := io.o
 
 lib-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o                 \
        __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o                   \
-       bitop.o checksum.o clear_page.o csum_partial_copy.o copy_page.o \
+       bitop.o checksum.o clear_page.o csum_partial_copy.o             \
        clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o   \
        flush.o ip_fast_csum.o do_csum.o                                \
        memset.o strlen.o swiotlb.o
index 3e2cfa2c6d39436d29f0c05e8f8cb1611fe76560..2a0d27f2f21bdd200df5c62a010e4673bc314abd 100644 (file)
@@ -20,6 +20,7 @@
         *
         *      Note: "in0" and "in1" are preserved for debugging purposes.
         */
+       .section .kprobes.text,"ax"
 GLOBAL_ENTRY(flush_icache_range)
 
        .prologue
index ab7b3ad99a7fa9f9c87c78474ee7fda27d3f01b0..dbc0b3e449c5fe7ad8e81c284d00c85b0bf600fe 100644 (file)
@@ -93,8 +93,7 @@ static int __init
 setup_io_tlb_npages(char *str)
 {
        if (isdigit(*str)) {
-               io_tlb_nslabs = simple_strtoul(str, &str, 0) <<
-                       (PAGE_SHIFT - IO_TLB_SHIFT);
+               io_tlb_nslabs = simple_strtoul(str, &str, 0);
                /* avoid tail segment of size < IO_TLB_SEGSIZE */
                io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
        }
@@ -117,7 +116,7 @@ swiotlb_init_with_default_size (size_t default_size)
        unsigned long i;
 
        if (!io_tlb_nslabs) {
-               io_tlb_nslabs = (default_size >> PAGE_SHIFT);
+               io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
                io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
        }
 
index ff62551eb3a125765463768adaec354107200b47..24614869e866ed7f2bd653d1cdc577d4aa02ce89 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/mm.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
+#include <linux/kprobes.h>
 
 #include <asm/pgtable.h>
 #include <asm/processor.h>
@@ -76,7 +77,7 @@ mapped_kernel_page_is_present (unsigned long address)
        return pte_present(pte);
 }
 
-void
+void __kprobes
 ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs)
 {
        int signal = SIGSEGV, code = SEGV_MAPERR;
index e0a776a3044c89f5614de6e2284c6a338cda6170..2d13889d0a9915da645b074ecbef1f8a0b56d116 100644 (file)
@@ -76,7 +76,7 @@ int is_aligned_hugepage_range(unsigned long addr, unsigned long len)
                return -EINVAL;
        if (addr & ~HPAGE_MASK)
                return -EINVAL;
-       if (REGION_NUMBER(addr) != REGION_HPAGE)
+       if (REGION_NUMBER(addr) != RGN_HPAGE)
                return -EINVAL;
 
        return 0;
@@ -87,7 +87,7 @@ struct page *follow_huge_addr(struct mm_struct *mm, unsigned long addr, int writ
        struct page *page;
        pte_t *ptep;
 
-       if (REGION_NUMBER(addr) != REGION_HPAGE)
+       if (REGION_NUMBER(addr) != RGN_HPAGE)
                return ERR_PTR(-EINVAL);
 
        ptep = huge_pte_offset(mm, addr);
@@ -142,8 +142,8 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, u
                return -ENOMEM;
        if (len & ~HPAGE_MASK)
                return -EINVAL;
-       /* This code assumes that REGION_HPAGE != 0. */
-       if ((REGION_NUMBER(addr) != REGION_HPAGE) || (addr & (HPAGE_SIZE - 1)))
+       /* This code assumes that RGN_HPAGE != 0. */
+       if ((REGION_NUMBER(addr) != RGN_HPAGE) || (addr & (HPAGE_SIZE - 1)))
                addr = HPAGE_REGION_BASE;
        else
                addr = ALIGN(addr, HPAGE_SIZE);
index f9472c50ab4298a072fd25cfca6743ff69122b91..9977c122e9fa2c1a314e2d90fb5260dba87b0cb7 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <asm/machvec.h>
 #include <asm/page.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/sal.h>
index 0139124dd54a66935124494ff4cff213f0452d89..6b2e7b75eb19136cee3f7f5943667c55ee75da90 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_IA64_SN_TIO_H
 #define TIO_ITTE_VALID_MASK    0x1
 #define TIO_ITTE_VALID_SHIFT   16
 
+#define TIO_ITTE_WIDGET(itte) \
+       (((itte) >> TIO_ITTE_WIDGET_SHIFT) & TIO_ITTE_WIDGET_MASK)
+#define TIO_ITTE_VALID(itte) \
+       (((itte) >> TIO_ITTE_VALID_SHIFT) & TIO_ITTE_VALID_MASK)
 
 #define TIO_ITTE_PUT(nasid, bigwin, widget, addr, valid) \
         REMOTE_HUB_S((nasid), TIO_ITTE(bigwin), \
index 580a1c0403a73c373c60cf34cc59f985bb5a16f0..71c2b271b4c687daabd4e886023fe85dacfeeb94 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_XTALK_HUBDEV_H
 #define _ASM_IA64_SN_XTALK_HUBDEV_H
@@ -16,6 +16,9 @@
 #define IIO_ITTE_WIDGET_MASK    ((1<<IIO_ITTE_WIDGET_BITS)-1)
 #define IIO_ITTE_WIDGET_SHIFT   8
 
+#define IIO_ITTE_WIDGET(itte)  \
+       (((itte) >> IIO_ITTE_WIDGET_SHIFT) & IIO_ITTE_WIDGET_MASK)
+
 /*
  * Use the top big window as a surrogate for the first small window
  */
@@ -34,7 +37,8 @@ struct sn_flush_device_list {
        unsigned long sfdl_force_int_addr;
        unsigned long sfdl_flush_value;
        volatile unsigned long *sfdl_flush_addr;
-       uint64_t sfdl_persistent_busnum;
+       uint32_t sfdl_persistent_busnum;
+       uint32_t sfdl_persistent_segment;
        struct pcibus_info *sfdl_pcibus_info;
        spinlock_t sfdl_flush_lock;
 };
@@ -58,7 +62,8 @@ struct hubdev_info {
 
        void                            *hdi_nodepda;
        void                            *hdi_node_vertex;
-       void                            *hdi_xtalk_vertex;
+       uint32_t                        max_segment_number;
+       uint32_t                        max_pcibus_number;
 };
 
 extern void hubdev_init_node(nodepda_t *, cnodeid_t);
index 647deae9bfcd57c3fef46b03d7f47912f6c985b1..45854c637e9ca035f2d16dac86da2698ec300030 100644 (file)
 
 /* two interfaces on two btes */
 #define MAX_INTERFACES_TO_TRY          4
+#define MAX_NODES_TO_TRY               2
 
 static struct bteinfo_s *bte_if_on_node(nasid_t nasid, int interface)
 {
        nodepda_t *tmp_nodepda;
 
+       if (nasid_to_cnodeid(nasid) == -1)
+               return (struct bteinfo_s *)NULL;;
+
        tmp_nodepda = NODEPDA(nasid_to_cnodeid(nasid));
        return &tmp_nodepda->bte_if[interface];
 
 }
 
+static inline void bte_start_transfer(struct bteinfo_s *bte, u64 len, u64 mode)
+{
+       if (is_shub2()) {
+               BTE_CTRL_STORE(bte, (IBLS_BUSY | ((len) | (mode) << 24)));
+       } else {
+               BTE_LNSTAT_STORE(bte, len);
+               BTE_CTRL_STORE(bte, mode);
+       }
+}
+
 /************************************************************************
  * Block Transfer Engine copy related functions.
  *
@@ -67,13 +81,15 @@ bte_result_t bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification)
 {
        u64 transfer_size;
        u64 transfer_stat;
+       u64 notif_phys_addr;
        struct bteinfo_s *bte;
        bte_result_t bte_status;
        unsigned long irq_flags;
        unsigned long itc_end = 0;
-       struct bteinfo_s *btes_to_try[MAX_INTERFACES_TO_TRY];
-       int bte_if_index;
-       int bte_pri, bte_sec;
+       int nasid_to_try[MAX_NODES_TO_TRY];
+       int my_nasid = get_nasid();
+       int bte_if_index, nasid_index;
+       int bte_first, btes_per_node = BTES_PER_NODE;
 
        BTE_PRINTK(("bte_copy(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%p)\n",
                    src, dest, len, mode, notification));
@@ -86,36 +102,26 @@ bte_result_t bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification)
                 (src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK));
        BUG_ON(!(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT)));
 
-       /* CPU 0 (per node) tries bte0 first, CPU 1 try bte1 first */
-       if (cpuid_to_subnode(smp_processor_id()) == 0) {
-               bte_pri = 0;
-               bte_sec = 1;
-       } else {
-               bte_pri = 1;
-               bte_sec = 0;
-       }
+       /*
+        * Start with interface corresponding to cpu number
+        */
+       bte_first = raw_smp_processor_id() % btes_per_node;
 
        if (mode & BTE_USE_DEST) {
                /* try remote then local */
-               btes_to_try[0] = bte_if_on_node(NASID_GET(dest), bte_pri);
-               btes_to_try[1] = bte_if_on_node(NASID_GET(dest), bte_sec);
+               nasid_to_try[0] = NASID_GET(dest);
                if (mode & BTE_USE_ANY) {
-                       btes_to_try[2] = bte_if_on_node(get_nasid(), bte_pri);
-                       btes_to_try[3] = bte_if_on_node(get_nasid(), bte_sec);
+                       nasid_to_try[1] = my_nasid;
                } else {
-                       btes_to_try[2] = NULL;
-                       btes_to_try[3] = NULL;
+                       nasid_to_try[1] = (int)NULL;
                }
        } else {
                /* try local then remote */
-               btes_to_try[0] = bte_if_on_node(get_nasid(), bte_pri);
-               btes_to_try[1] = bte_if_on_node(get_nasid(), bte_sec);
+               nasid_to_try[0] = my_nasid;
                if (mode & BTE_USE_ANY) {
-                       btes_to_try[2] = bte_if_on_node(NASID_GET(dest), bte_pri);
-                       btes_to_try[3] = bte_if_on_node(NASID_GET(dest), bte_sec);
+                       nasid_to_try[1] = NASID_GET(dest);
                } else {
-                       btes_to_try[2] = NULL;
-                       btes_to_try[3] = NULL;
+                       nasid_to_try[1] = (int)NULL;
                }
        }
 
@@ -123,11 +129,12 @@ retry_bteop:
        do {
                local_irq_save(irq_flags);
 
-               bte_if_index = 0;
+               bte_if_index = bte_first;
+               nasid_index = 0;
 
                /* Attempt to lock one of the BTE interfaces. */
-               while (bte_if_index < MAX_INTERFACES_TO_TRY) {
-                       bte = btes_to_try[bte_if_index++];
+               while (nasid_index < MAX_NODES_TO_TRY) {
+                       bte = bte_if_on_node(nasid_to_try[nasid_index],bte_if_index);
 
                        if (bte == NULL) {
                                continue;
@@ -143,6 +150,15 @@ retry_bteop:
                                        break;
                                }
                        }
+
+                       bte_if_index = (bte_if_index + 1) % btes_per_node; /* Next interface */
+                       if (bte_if_index == bte_first) {
+                               /*
+                                * We've tried all interfaces on this node
+                                */
+                               nasid_index++;
+                       }
+
                        bte = NULL;
                }
 
@@ -169,7 +185,13 @@ retry_bteop:
 
        /* Initialize the notification to a known value. */
        *bte->most_rcnt_na = BTE_WORD_BUSY;
+       notif_phys_addr = TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na));
 
+       if (is_shub2()) {
+               src = SH2_TIO_PHYS_TO_DMA(src);
+               dest = SH2_TIO_PHYS_TO_DMA(dest);
+               notif_phys_addr = SH2_TIO_PHYS_TO_DMA(notif_phys_addr);
+       }
        /* Set the source and destination registers */
        BTE_PRINTKV(("IBSA = 0x%lx)\n", (TO_PHYS(src))));
        BTE_SRC_STORE(bte, TO_PHYS(src));
@@ -177,14 +199,12 @@ retry_bteop:
        BTE_DEST_STORE(bte, TO_PHYS(dest));
 
        /* Set the notification register */
-       BTE_PRINTKV(("IBNA = 0x%lx)\n",
-                    TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na))));
-       BTE_NOTIF_STORE(bte,
-                       TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na)));
+       BTE_PRINTKV(("IBNA = 0x%lx)\n", notif_phys_addr));
+       BTE_NOTIF_STORE(bte, notif_phys_addr);
 
        /* Initiate the transfer */
        BTE_PRINTK(("IBCT = 0x%lx)\n", BTE_VALID_MODE(mode)));
-       BTE_START_TRANSFER(bte, transfer_size, BTE_VALID_MODE(mode));
+       bte_start_transfer(bte, transfer_size, BTE_VALID_MODE(mode));
 
        itc_end = ia64_get_itc() + (40000000 * local_cpu_data->cyc_per_usec);
 
@@ -195,6 +215,7 @@ retry_bteop:
        }
 
        while ((transfer_stat = *bte->most_rcnt_na) == BTE_WORD_BUSY) {
+               cpu_relax();
                if (ia64_get_itc() > itc_end) {
                        BTE_PRINTK(("BTE timeout nasid 0x%x bte%d IBLS = 0x%lx na 0x%lx\n",
                                NASID_GET(bte->bte_base_addr), bte->bte_num,
index 5c39b43ba3c029604103bb1757dbe3d5db1faa5c..5c5eb01c50f02b53f97513eda0e1e65e3daa2c00 100644 (file)
@@ -76,7 +76,7 @@ void hubiio_crb_free(struct hubdev_info *hubdev_info, int crbnum)
         */
        REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICDR, (IIO_ICDR_PND | crbnum));
        while (REMOTE_HUB_L(hubdev_info->hdi_nasid, IIO_ICDR) & IIO_ICDR_PND)
-               udelay(1);
+               cpu_relax();
 
 }
 
index 414cdf2e3c965e124223833a1ed036783e4c4392..906622d9f933374931b07a570c91fa17f7bcd41d 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/sn/simulator.h>
 #include <asm/sn/sn_sal.h>
 #include <asm/sn/tioca_provider.h>
+#include <asm/sn/tioce_provider.h>
 #include "xtalk/hubdev.h"
 #include "xtalk/xwidgetdev.h"
 
@@ -44,6 +45,9 @@ int sn_ioif_inited = 0;               /* SN I/O infrastructure initialized? */
 
 struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES];      /* indexed by asic type */
 
+static int max_segment_number = 0; /* Default highest segment number */
+static int max_pcibus_number = 255; /* Default highest pci bus number */
+
 /*
  * Hooks and struct for unsupported pci providers
  */
@@ -157,13 +161,28 @@ static void sn_fixup_ionodes(void)
        uint64_t nasid;
        int i, widget;
 
+       /*
+        * Get SGI Specific HUB chipset information.
+        * Inform Prom that this kernel can support domain bus numbering.
+        */
        for (i = 0; i < numionodes; i++) {
                hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo);
                nasid = cnodeid_to_nasid(i);
+               hubdev->max_segment_number = 0xffffffff;
+               hubdev->max_pcibus_number = 0xff;
                status = sal_get_hubdev_info(nasid, (uint64_t) __pa(hubdev));
                if (status)
                        continue;
 
+               /* Save the largest Domain and pcibus numbers found. */
+               if (hubdev->max_segment_number) {
+                       /*
+                        * Dealing with a Prom that supports segments.
+                        */
+                       max_segment_number = hubdev->max_segment_number;
+                       max_pcibus_number = hubdev->max_pcibus_number;
+               }
+
                /* Attach the error interrupt handlers */
                if (nasid & 1)
                        ice_error_init(hubdev);
@@ -230,7 +249,7 @@ void sn_pci_unfixup_slot(struct pci_dev *dev)
 void sn_pci_fixup_slot(struct pci_dev *dev)
 {
        int idx;
-       int segment = 0;
+       int segment = pci_domain_nr(dev->bus);
        int status = 0;
        struct pcibus_bussoft *bs;
        struct pci_bus *host_pci_bus;
@@ -283,9 +302,9 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
         * PCI host_pci_dev struct and set up host bus linkages
         */
 
-       bus_no = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32;
+       bus_no = (SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32) & 0xff;
        devfn = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle & 0xffffffff;
-       host_pci_bus = pci_find_bus(pci_domain_nr(dev->bus), bus_no);
+       host_pci_bus = pci_find_bus(segment, bus_no);
        host_pci_dev = pci_get_slot(host_pci_bus, devfn);
 
        SN_PCIDEV_INFO(dev)->host_pci_dev = host_pci_dev;
@@ -333,6 +352,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
        prom_bussoft_ptr = __va(prom_bussoft_ptr);
 
        controller = kcalloc(1,sizeof(struct pci_controller), GFP_KERNEL);
+       controller->segment = segment;
        if (!controller)
                BUG();
 
@@ -390,7 +410,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
        if (controller->node >= num_online_nodes()) {
                struct pcibus_bussoft *b = SN_PCIBUS_BUSSOFT(bus);
 
-               printk(KERN_WARNING "Device ASIC=%u XID=%u PBUSNUM=%lu"
+               printk(KERN_WARNING "Device ASIC=%u XID=%u PBUSNUM=%u"
                                    "L_IO=%lx L_MEM=%lx BASE=%lx\n",
                        b->bs_asic_type, b->bs_xid, b->bs_persist_busnum,
                        b->bs_legacy_io, b->bs_legacy_mem, b->bs_base);
@@ -411,7 +431,7 @@ void sn_bus_store_sysdata(struct pci_dev *dev)
 {
        struct sysdata_el *element;
 
-       element = kcalloc(1, sizeof(struct sysdata_el), GFP_KERNEL);
+       element = kzalloc(sizeof(struct sysdata_el), GFP_KERNEL);
        if (!element) {
                dev_dbg(dev, "%s: out of memory!\n", __FUNCTION__);
                return;
@@ -445,6 +465,7 @@ sn_sysdata_free_start:
 static int __init sn_pci_init(void)
 {
        int i = 0;
+       int j = 0;
        struct pci_dev *pci_dev = NULL;
        extern void sn_init_cpei_timer(void);
 #ifdef CONFIG_PROC_FS
@@ -464,6 +485,7 @@ static int __init sn_pci_init(void)
 
        pcibr_init_provider();
        tioca_init_provider();
+       tioce_init_provider();
 
        /*
         * This is needed to avoid bounce limit checks in the blk layer
@@ -479,8 +501,9 @@ static int __init sn_pci_init(void)
 #endif
 
        /* busses are not known yet ... */
-       for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
-               sn_pci_controller_fixup(0, i, NULL);
+       for (i = 0; i <= max_segment_number; i++)
+               for (j = 0; j <= max_pcibus_number; j++)
+                       sn_pci_controller_fixup(i, j, NULL);
 
        /*
         * Generic Linux PCI Layer has created the pci_bus and pci_dev 
index 84d276a14ecb178d696d239f0758efaff251ee47..9fc74631ba8aa92568a8fed1e27c0a202e00f92f 100644 (file)
@@ -5,7 +5,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
 #include <linux/irq.h>
@@ -76,16 +76,14 @@ static void sn_enable_irq(unsigned int irq)
 
 static void sn_ack_irq(unsigned int irq)
 {
-       uint64_t event_occurred, mask = 0;
-       int nasid;
+       u64 event_occurred, mask = 0;
 
        irq = irq & 0xff;
-       nasid = get_nasid();
        event_occurred =
-           HUB_L((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED));
+           HUB_L((u64*)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED));
        mask = event_occurred & SH_ALL_INT_MASK;
-       HUB_S((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED_ALIAS),
-                mask);
+       HUB_S((u64*)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS),
+             mask);
        __set_bit(irq, (volatile void *)pda->sn_in_service_ivecs);
 
        move_irq(irq);
@@ -93,15 +91,12 @@ static void sn_ack_irq(unsigned int irq)
 
 static void sn_end_irq(unsigned int irq)
 {
-       int nasid;
        int ivec;
-       uint64_t event_occurred;
+       u64 event_occurred;
 
        ivec = irq & 0xff;
        if (ivec == SGI_UART_VECTOR) {
-               nasid = get_nasid();
-               event_occurred = HUB_L((uint64_t *) GLOBAL_MMR_ADDR
-                                      (nasid, SH_EVENT_OCCURRED));
+               event_occurred = HUB_L((u64*)LOCAL_MMR_ADDR (SH_EVENT_OCCURRED));
                /* If the UART bit is set here, we may have received an
                 * interrupt from the UART that the driver missed.  To
                 * make sure, we IPI ourselves to force us to look again.
@@ -132,6 +127,7 @@ static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
                int local_widget, status;
                nasid_t local_nasid;
                struct sn_irq_info *new_irq_info;
+               struct sn_pcibus_provider *pci_provider;
 
                new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
                if (new_irq_info == NULL)
@@ -171,8 +167,9 @@ static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
                new_irq_info->irq_cpuid = cpuid;
                register_intr_pda(new_irq_info);
 
-               if (IS_PCI_BRIDGE_ASIC(new_irq_info->irq_bridge_type))
-                       pcibr_change_devices_irq(new_irq_info);
+               pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];
+               if (pci_provider && pci_provider->target_interrupt)
+                       (pci_provider->target_interrupt)(new_irq_info);
 
                spin_lock(&sn_irq_info_lock);
                list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
@@ -317,6 +314,16 @@ void sn_irq_unfixup(struct pci_dev *pci_dev)
        pci_dev_put(pci_dev);
 }
 
+static inline void
+sn_call_force_intr_provider(struct sn_irq_info *sn_irq_info)
+{
+       struct sn_pcibus_provider *pci_provider;
+
+       pci_provider = sn_pci_provider[sn_irq_info->irq_bridge_type];
+       if (pci_provider && pci_provider->force_interrupt)
+               (*pci_provider->force_interrupt)(sn_irq_info);
+}
+
 static void force_interrupt(int irq)
 {
        struct sn_irq_info *sn_irq_info;
@@ -325,11 +332,9 @@ static void force_interrupt(int irq)
                return;
 
        rcu_read_lock();
-       list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[irq], list) {
-               if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) &&
-                   (sn_irq_info->irq_bridge != NULL))
-                       pcibr_force_interrupt(sn_irq_info);
-       }
+       list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[irq], list)
+               sn_call_force_intr_provider(sn_irq_info);
+
        rcu_read_unlock();
 }
 
@@ -351,6 +356,14 @@ static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info)
        struct pcidev_info *pcidev_info;
        struct pcibus_info *pcibus_info;
 
+       /*
+        * Bridge types attached to TIO (anything but PIC) do not need this WAR
+        * since they do not target Shub II interrupt registers.  If that
+        * ever changes, this check needs to accomodate.
+        */
+       if (sn_irq_info->irq_bridge_type != PCIIO_ASIC_TYPE_PIC)
+               return;
+
        pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
        if (!pcidev_info)
                return;
@@ -377,16 +390,12 @@ static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info)
                break;
        }
        if (!test_bit(irr_bit, &irr_reg)) {
-               if (!test_bit(irq, pda->sn_soft_irr)) {
-                       if (!test_bit(irq, pda->sn_in_service_ivecs)) {
-                               regval &= 0xff;
-                               if (sn_irq_info->irq_int_bit & regval &
-                                   sn_irq_info->irq_last_intr) {
-                                       regval &=
-                                           ~(sn_irq_info->
-                                             irq_int_bit & regval);
-                                       pcibr_force_interrupt(sn_irq_info);
-                               }
+               if (!test_bit(irq, pda->sn_in_service_ivecs)) {
+                       regval &= 0xff;
+                       if (sn_irq_info->irq_int_bit & regval &
+                           sn_irq_info->irq_last_intr) {
+                               regval &= ~(sn_irq_info->irq_int_bit & regval);
+                               sn_call_force_intr_provider(sn_irq_info);
                        }
                }
        }
@@ -404,13 +413,7 @@ void sn_lb_int_war_check(void)
        rcu_read_lock();
        for (i = pda->sn_first_irq; i <= pda->sn_last_irq; i++) {
                list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[i], list) {
-                       /*
-                        * Only call for PCI bridges that are fully
-                        * initialized.
-                        */
-                       if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) &&
-                           (sn_irq_info->irq_bridge != NULL))
-                               sn_check_intr(i, sn_irq_info);
+                       sn_check_intr(i, sn_irq_info);
                }
        }
        rcu_read_unlock();
index 7c7fe441d62371ec513365bd89814397e0888b2e..a594aca959e6e141eb83a8769887f9199dc8b42a 100644 (file)
@@ -80,8 +80,6 @@ EXPORT_PER_CPU_SYMBOL(__sn_cnodeid_to_nasid);
 DEFINE_PER_CPU(struct nodepda_s *, __sn_nodepda);
 EXPORT_PER_CPU_SYMBOL(__sn_nodepda);
 
-partid_t sn_partid = -1;
-EXPORT_SYMBOL(sn_partid);
 char sn_system_serial_number_string[128];
 EXPORT_SYMBOL(sn_system_serial_number_string);
 u64 sn_partition_serial_number;
@@ -403,6 +401,7 @@ static void __init sn_init_pdas(char **cmdline_p)
                memset(nodepdaindr[cnode], 0, sizeof(nodepda_t));
                memset(nodepdaindr[cnode]->phys_cpuid, -1,
                    sizeof(nodepdaindr[cnode]->phys_cpuid));
+               spin_lock_init(&nodepdaindr[cnode]->ptc_lock);
        }
 
        /*
@@ -532,8 +531,8 @@ void __init sn_cpu_init(void)
         */
        {
                u64 pio1[] = {SH1_PIO_WRITE_STATUS_0, 0, SH1_PIO_WRITE_STATUS_1, 0};
-               u64 pio2[] = {SH2_PIO_WRITE_STATUS_0, SH2_PIO_WRITE_STATUS_1,
-                       SH2_PIO_WRITE_STATUS_2, SH2_PIO_WRITE_STATUS_3};
+               u64 pio2[] = {SH2_PIO_WRITE_STATUS_0, SH2_PIO_WRITE_STATUS_2,
+                       SH2_PIO_WRITE_STATUS_1, SH2_PIO_WRITE_STATUS_3};
                u64 *pio;
                pio = is_shub1() ? pio1 : pio2;
                pda->pio_write_status_addr = (volatile unsigned long *) LOCAL_MMR_ADDR(pio[slice]);
index 96cb71d156820f9b33df9a07ea5049afe3bc77b9..3fa95065a4460e618a4cb4d4e1979ed830fc6cee 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <asm/types.h>
@@ -11,7 +11,7 @@
 
 #define DEADLOCKBIT    SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT
 #define WRITECOUNTMASK SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK
-#define ALIAS_OFFSET   (SH1_PIO_WRITE_STATUS_0_ALIAS-SH1_PIO_WRITE_STATUS_0)
+#define ALIAS_OFFSET   8
 
 
        .global sn2_ptc_deadlock_recovery_core
@@ -36,13 +36,15 @@ sn2_ptc_deadlock_recovery_core:
        extr.u  piowcphy=piowc,0,61;;   // Convert piowc to uncached physical address
        dep     piowcphy=-1,piowcphy,63,1
        movl    mask=WRITECOUNTMASK
+       mov     r8=r0
 
 1:
        add     scr2=ALIAS_OFFSET,piowc // Address of WRITE_STATUS alias register 
-       mov     scr1=7;;                // Clear DEADLOCK, WRITE_ERROR, MULTI_WRITE_ERROR
-       st8.rel [scr2]=scr1;;
+       ;;
+       ld8.acq scr1=[scr2];;
 
 5:     ld8.acq scr1=[piowc];;          // Wait for PIOs to complete.
+       hint    @pause
        and     scr2=scr1,mask;;        // mask of writecount bits
        cmp.ne  p6,p0=zeroval,scr2
 (p6)   br.cond.sptk 5b
@@ -57,6 +59,7 @@ sn2_ptc_deadlock_recovery_core:
        st8.rel [ptc0]=data0            // Write PTC0 & wait for completion.
 
 5:     ld8.acq scr1=[piowcphy];;       // Wait for PIOs to complete.
+       hint    @pause
        and     scr2=scr1,mask;;        // mask of writecount bits
        cmp.ne  p6,p0=zeroval,scr2
 (p6)   br.cond.sptk 5b;;
@@ -67,6 +70,7 @@ sn2_ptc_deadlock_recovery_core:
 (p7)   st8.rel [ptc1]=data1;;          // Now write PTC1.
 
 5:     ld8.acq scr1=[piowcphy];;       // Wait for PIOs to complete.
+       hint    @pause
        and     scr2=scr1,mask;;        // mask of writecount bits
        cmp.ne  p6,p0=zeroval,scr2
 (p6)   br.cond.sptk 5b
@@ -77,6 +81,7 @@ sn2_ptc_deadlock_recovery_core:
        srlz.i;;
        ////////////// END   PHYSICAL MODE ////////////////////
 
+(p8)   add     r8=1,r8
 (p8)   br.cond.spnt 1b;;               // Repeat if DEADLOCK occurred.
 
        br.ret.sptk     rp
index 7af05a7ac743a2416774ef75245f51b0d0b203a4..0a4ee50c302f94750f6c9f8876970e58b19d8b0e 100644 (file)
@@ -5,7 +5,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/init.h>
@@ -20,6 +20,8 @@
 #include <linux/module.h>
 #include <linux/bitops.h>
 #include <linux/nodemask.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 
 #include <asm/processor.h>
 #include <asm/irq.h>
 #include <asm/sn/nodepda.h>
 #include <asm/sn/rw_mmr.h>
 
-void sn2_ptc_deadlock_recovery(volatile unsigned long *, unsigned long data0, 
-       volatile unsigned long *, unsigned long data1);
+DEFINE_PER_CPU(struct ptc_stats, ptcstats);
+DECLARE_PER_CPU(struct ptc_stats, ptcstats);
 
 static  __cacheline_aligned DEFINE_SPINLOCK(sn2_global_ptc_lock);
 
-static unsigned long sn2_ptc_deadlock_count;
+void sn2_ptc_deadlock_recovery(short *, short, int, volatile unsigned long *, unsigned long data0,
+       volatile unsigned long *, unsigned long data1);
+
+#ifdef DEBUG_PTC
+/*
+ * ptctest:
+ *
+ *     xyz - 3 digit hex number:
+ *             x - Force PTC purges to use shub:
+ *                     0 - no force
+ *                     1 - force
+ *             y - interupt enable
+ *                     0 - disable interrupts
+ *                     1 - leave interuupts enabled
+ *             z - type of lock:
+ *                     0 - global lock
+ *                     1 - node local lock
+ *                     2 - no lock
+ *
+ *     Note: on shub1, only ptctest == 0 is supported. Don't try other values!
+ */
+
+static unsigned int sn2_ptctest = 0;
+
+static int __init ptc_test(char *str)
+{
+       get_option(&str, &sn2_ptctest);
+       return 1;
+}
+__setup("ptctest=", ptc_test);
+
+static inline int ptc_lock(unsigned long *flagp)
+{
+       unsigned long opt = sn2_ptctest & 255;
+
+       switch (opt) {
+       case 0x00:
+               spin_lock_irqsave(&sn2_global_ptc_lock, *flagp);
+               break;
+       case 0x01:
+               spin_lock_irqsave(&sn_nodepda->ptc_lock, *flagp);
+               break;
+       case 0x02:
+               local_irq_save(*flagp);
+               break;
+       case 0x10:
+               spin_lock(&sn2_global_ptc_lock);
+               break;
+       case 0x11:
+               spin_lock(&sn_nodepda->ptc_lock);
+               break;
+       case 0x12:
+               break;
+       default:
+               BUG();
+       }
+       return opt;
+}
+
+static inline void ptc_unlock(unsigned long flags, int opt)
+{
+       switch (opt) {
+       case 0x00:
+               spin_unlock_irqrestore(&sn2_global_ptc_lock, flags);
+               break;
+       case 0x01:
+               spin_unlock_irqrestore(&sn_nodepda->ptc_lock, flags);
+               break;
+       case 0x02:
+               local_irq_restore(flags);
+               break;
+       case 0x10:
+               spin_unlock(&sn2_global_ptc_lock);
+               break;
+       case 0x11:
+               spin_unlock(&sn_nodepda->ptc_lock);
+               break;
+       case 0x12:
+               break;
+       default:
+               BUG();
+       }
+}
+#else
+
+#define sn2_ptctest    0
+
+static inline int ptc_lock(unsigned long *flagp)
+{
+       spin_lock_irqsave(&sn2_global_ptc_lock, *flagp);
+       return 0;
+}
+
+static inline void ptc_unlock(unsigned long flags, int opt)
+{
+       spin_unlock_irqrestore(&sn2_global_ptc_lock, flags);
+}
+#endif
+
+struct ptc_stats {
+       unsigned long ptc_l;
+       unsigned long change_rid;
+       unsigned long shub_ptc_flushes;
+       unsigned long nodes_flushed;
+       unsigned long deadlocks;
+       unsigned long lock_itc_clocks;
+       unsigned long shub_itc_clocks;
+       unsigned long shub_itc_clocks_max;
+};
 
 static inline unsigned long wait_piowc(void)
 {
@@ -89,9 +199,9 @@ void
 sn2_global_tlb_purge(unsigned long start, unsigned long end,
                     unsigned long nbits)
 {
-       int i, shub1, cnode, mynasid, cpu, lcpu = 0, nasid, flushed = 0;
+       int i, opt, shub1, cnode, mynasid, cpu, lcpu = 0, nasid, flushed = 0;
        volatile unsigned long *ptc0, *ptc1;
-       unsigned long flags = 0, data0 = 0, data1 = 0;
+       unsigned long itc, itc2, flags, data0 = 0, data1 = 0;
        struct mm_struct *mm = current->active_mm;
        short nasids[MAX_NUMNODES], nix;
        nodemask_t nodes_flushed;
@@ -114,16 +224,19 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end,
                        start += (1UL << nbits);
                } while (start < end);
                ia64_srlz_i();
+               __get_cpu_var(ptcstats).ptc_l++;
                preempt_enable();
                return;
        }
 
        if (atomic_read(&mm->mm_users) == 1) {
                flush_tlb_mm(mm);
+               __get_cpu_var(ptcstats).change_rid++;
                preempt_enable();
                return;
        }
 
+       itc = ia64_get_itc();
        nix = 0;
        for_each_node_mask(cnode, nodes_flushed)
                nasids[nix++] = cnodeid_to_nasid(cnode);
@@ -148,7 +261,12 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end,
 
        mynasid = get_nasid();
 
-       spin_lock_irqsave(&sn2_global_ptc_lock, flags);
+       itc = ia64_get_itc();
+       opt = ptc_lock(&flags);
+       itc2 = ia64_get_itc();
+       __get_cpu_var(ptcstats).lock_itc_clocks += itc2 - itc;
+       __get_cpu_var(ptcstats).shub_ptc_flushes++;
+       __get_cpu_var(ptcstats).nodes_flushed += nix;
 
        do {
                if (shub1)
@@ -157,7 +275,7 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end,
                        data0 = (data0 & ~SH2_PTC_ADDR_MASK) | (start & SH2_PTC_ADDR_MASK);
                for (i = 0; i < nix; i++) {
                        nasid = nasids[i];
-                       if (unlikely(nasid == mynasid)) {
+                       if ((!(sn2_ptctest & 3)) && unlikely(nasid == mynasid)) {
                                ia64_ptcga(start, nbits << 2);
                                ia64_srlz_i();
                        } else {
@@ -169,18 +287,22 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end,
                                flushed = 1;
                        }
                }
-
                if (flushed
                    && (wait_piowc() &
-                       SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK)) {
-                       sn2_ptc_deadlock_recovery(ptc0, data0, ptc1, data1);
+                               (SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK))) {
+                       sn2_ptc_deadlock_recovery(nasids, nix, mynasid, ptc0, data0, ptc1, data1);
                }
 
                start += (1UL << nbits);
 
        } while (start < end);
 
-       spin_unlock_irqrestore(&sn2_global_ptc_lock, flags);
+       itc2 = ia64_get_itc() - itc2;
+       __get_cpu_var(ptcstats).shub_itc_clocks += itc2;
+       if (itc2 > __get_cpu_var(ptcstats).shub_itc_clocks_max)
+               __get_cpu_var(ptcstats).shub_itc_clocks_max = itc2;
+
+       ptc_unlock(flags, opt);
 
        preempt_enable();
 }
@@ -192,31 +314,29 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end,
  * TLB flush transaction.  The recovery sequence is somewhat tricky & is
  * coded in assembly language.
  */
-void sn2_ptc_deadlock_recovery(volatile unsigned long *ptc0, unsigned long data0,
+void sn2_ptc_deadlock_recovery(short *nasids, short nix, int mynasid, volatile unsigned long *ptc0, unsigned long data0,
        volatile unsigned long *ptc1, unsigned long data1)
 {
        extern void sn2_ptc_deadlock_recovery_core(volatile unsigned long *, unsigned long,
                volatile unsigned long *, unsigned long, volatile unsigned long *, unsigned long);
-       int cnode, mycnode, nasid;
-       volatile unsigned long *piows;
-       volatile unsigned long zeroval;
+       short nasid, i;
+       unsigned long *piows, zeroval;
 
-       sn2_ptc_deadlock_count++;
+       __get_cpu_var(ptcstats).deadlocks++;
 
-       piows = pda->pio_write_status_addr;
+       piows = (unsigned long *) pda->pio_write_status_addr;
        zeroval = pda->pio_write_status_val;
 
-       mycnode = numa_node_id();
-
-       for_each_online_node(cnode) {
-               if (is_headless_node(cnode) || cnode == mycnode)
+       for (i=0; i < nix; i++) {
+               nasid = nasids[i];
+               if (!(sn2_ptctest & 3) && nasid == mynasid)
                        continue;
-               nasid = cnodeid_to_nasid(cnode);
                ptc0 = CHANGE_NASID(nasid, ptc0);
                if (ptc1)
                        ptc1 = CHANGE_NASID(nasid, ptc1);
                sn2_ptc_deadlock_recovery_core(ptc0, data0, ptc1, data1, piows, zeroval);
        }
+
 }
 
 /**
@@ -293,3 +413,93 @@ void sn2_send_IPI(int cpuid, int vector, int delivery_mode, int redirect)
 
        sn_send_IPI_phys(nasid, physid, vector, delivery_mode);
 }
+
+#ifdef CONFIG_PROC_FS
+
+#define PTC_BASENAME   "sgi_sn/ptc_statistics"
+
+static void *sn2_ptc_seq_start(struct seq_file *file, loff_t * offset)
+{
+       if (*offset < NR_CPUS)
+               return offset;
+       return NULL;
+}
+
+static void *sn2_ptc_seq_next(struct seq_file *file, void *data, loff_t * offset)
+{
+       (*offset)++;
+       if (*offset < NR_CPUS)
+               return offset;
+       return NULL;
+}
+
+static void sn2_ptc_seq_stop(struct seq_file *file, void *data)
+{
+}
+
+static int sn2_ptc_seq_show(struct seq_file *file, void *data)
+{
+       struct ptc_stats *stat;
+       int cpu;
+
+       cpu = *(loff_t *) data;
+
+       if (!cpu) {
+               seq_printf(file, "# ptc_l change_rid shub_ptc_flushes shub_nodes_flushed deadlocks lock_nsec shub_nsec shub_nsec_max\n");
+               seq_printf(file, "# ptctest %d\n", sn2_ptctest);
+       }
+
+       if (cpu < NR_CPUS && cpu_online(cpu)) {
+               stat = &per_cpu(ptcstats, cpu);
+               seq_printf(file, "cpu %d %ld %ld %ld %ld %ld %ld %ld %ld\n", cpu, stat->ptc_l,
+                               stat->change_rid, stat->shub_ptc_flushes, stat->nodes_flushed,
+                               stat->deadlocks,
+                               1000 * stat->lock_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec,
+                               1000 * stat->shub_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec,
+                               1000 * stat->shub_itc_clocks_max / per_cpu(cpu_info, cpu).cyc_per_usec);
+       }
+
+       return 0;
+}
+
+static struct seq_operations sn2_ptc_seq_ops = {
+       .start = sn2_ptc_seq_start,
+       .next = sn2_ptc_seq_next,
+       .stop = sn2_ptc_seq_stop,
+       .show = sn2_ptc_seq_show
+};
+
+int sn2_ptc_proc_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &sn2_ptc_seq_ops);
+}
+
+static struct file_operations proc_sn2_ptc_operations = {
+       .open = sn2_ptc_proc_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static struct proc_dir_entry *proc_sn2_ptc;
+
+static int __init sn2_ptc_init(void)
+{
+       if (!(proc_sn2_ptc = create_proc_entry(PTC_BASENAME, 0444, NULL))) {
+               printk(KERN_ERR "unable to create %s proc entry", PTC_BASENAME);
+               return -EINVAL;
+       }
+       proc_sn2_ptc->proc_fops = &proc_sn2_ptc_operations;
+       spin_lock_init(&sn2_global_ptc_lock);
+       return 0;
+}
+
+static void __exit sn2_ptc_exit(void)
+{
+       remove_proc_entry(PTC_BASENAME, NULL);
+}
+
+module_init(sn2_ptc_init);
+module_exit(sn2_ptc_exit);
+#endif /* CONFIG_PROC_FS */
+
index 833e700fdac93e4ada8c663c8c182b4d899cf05b..0513aacac8c13898a8e7edf57cfe9530b13e553d 100644 (file)
@@ -36,7 +36,6 @@
 #include <asm/topology.h>
 #include <asm/smp.h>
 #include <asm/semaphore.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <asm/sal.h>
 #include <asm/sn/io.h>
@@ -59,7 +58,7 @@ static int sn_hwperf_enum_objects(int *nobj, struct sn_hwperf_object_info **ret)
        struct sn_hwperf_object_info *objbuf = NULL;
 
        if ((e = sn_hwperf_init()) < 0) {
-               printk("sn_hwperf_init failed: err %d\n", e);
+               printk(KERN_ERR "sn_hwperf_init failed: err %d\n", e);
                goto out;
        }
 
@@ -111,7 +110,7 @@ static int sn_hwperf_geoid_to_cnode(char *location)
        if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab))
                return -1;
 
-       for (cnode = 0; cnode < numionodes; cnode++) {
+       for_each_node(cnode) {
                geoid = cnodeid_get_geoid(cnode);
                module_id = geo_module(geoid);
                this_rack = MODULE_GET_RACK(module_id);
@@ -124,11 +123,13 @@ static int sn_hwperf_geoid_to_cnode(char *location)
                }
        }
 
-       return cnode < numionodes ? cnode : -1;
+       return node_possible(cnode) ? cnode : -1;
 }
 
 static int sn_hwperf_obj_to_cnode(struct sn_hwperf_object_info * obj)
 {
+       if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj))
+               BUG();
        if (!obj->sn_hwp_this_part)
                return -1;
        return sn_hwperf_geoid_to_cnode(obj->location);
@@ -174,31 +175,199 @@ static const char *sn_hwperf_get_slabname(struct sn_hwperf_object_info *obj,
        return slabname;
 }
 
-static void print_pci_topology(struct seq_file *s,
-       struct sn_hwperf_object_info *obj, int *ordinal,
-       u64 rack, u64 bay, u64 slot, u64 slab)
+static void print_pci_topology(struct seq_file *s)
+{
+       char *p;
+       size_t sz;
+       int e;
+
+       for (sz = PAGE_SIZE; sz < 16 * PAGE_SIZE; sz += PAGE_SIZE) {
+               if (!(p = (char *)kmalloc(sz, GFP_KERNEL)))
+                       break;
+               e = ia64_sn_ioif_get_pci_topology(__pa(p), sz);
+               if (e == SALRET_OK)
+                       seq_puts(s, p);
+               kfree(p);
+               if (e == SALRET_OK || e == SALRET_NOT_IMPLEMENTED)
+                       break;
+       }
+}
+
+static inline int sn_hwperf_has_cpus(cnodeid_t node)
+{
+       return node_online(node) && nr_cpus_node(node);
+}
+
+static inline int sn_hwperf_has_mem(cnodeid_t node)
+{
+       return node_online(node) && NODE_DATA(node)->node_present_pages;
+}
+
+static struct sn_hwperf_object_info *
+sn_hwperf_findobj_id(struct sn_hwperf_object_info *objbuf,
+       int nobj, int id)
 {
-       char *p1;
-       char *p2;
-       char *pg;
-
-       if (!(pg = (char *)get_zeroed_page(GFP_KERNEL)))
-               return; /* ignore */
-       if (ia64_sn_ioif_get_pci_topology(rack, bay, slot, slab,
-               __pa(pg), PAGE_SIZE) == SN_HWPERF_OP_OK) {
-               for (p1=pg; *p1 && p1 < pg + PAGE_SIZE;) {
-                       if (!(p2 = strchr(p1, '\n')))
+       int i;
+       struct sn_hwperf_object_info *p = objbuf;
+
+       for (i=0; i < nobj; i++, p++) {
+               if (p->id == id)
+                       return p;
+       }
+
+       return NULL;
+
+}
+
+static int sn_hwperf_get_nearest_node_objdata(struct sn_hwperf_object_info *objbuf,
+       int nobj, cnodeid_t node, cnodeid_t *near_mem_node, cnodeid_t *near_cpu_node)
+{
+       int e;
+       struct sn_hwperf_object_info *nodeobj = NULL;
+       struct sn_hwperf_object_info *op;
+       struct sn_hwperf_object_info *dest;
+       struct sn_hwperf_object_info *router;
+       struct sn_hwperf_port_info ptdata[16];
+       int sz, i, j;
+       cnodeid_t c;
+       int found_mem = 0;
+       int found_cpu = 0;
+
+       if (!node_possible(node))
+               return -EINVAL;
+
+       if (sn_hwperf_has_cpus(node)) {
+               if (near_cpu_node)
+                       *near_cpu_node = node;
+               found_cpu++;
+       }
+
+       if (sn_hwperf_has_mem(node)) {
+               if (near_mem_node)
+                       *near_mem_node = node;
+               found_mem++;
+       }
+
+       if (found_cpu && found_mem)
+               return 0; /* trivially successful */
+
+       /* find the argument node object */
+       for (i=0, op=objbuf; i < nobj; i++, op++) {
+               if (!SN_HWPERF_IS_NODE(op) && !SN_HWPERF_IS_IONODE(op))
+                       continue;
+               if (node == sn_hwperf_obj_to_cnode(op)) {
+                       nodeobj = op;
+                       break;
+               }
+       }
+       if (!nodeobj) {
+               e = -ENOENT;
+               goto err;
+       }
+
+       /* get it's interconnect topology */
+       sz = op->ports * sizeof(struct sn_hwperf_port_info);
+       if (sz > sizeof(ptdata))
+               BUG();
+       e = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
+                             SN_HWPERF_ENUM_PORTS, nodeobj->id, sz,
+                             (u64)&ptdata, 0, 0, NULL);
+       if (e != SN_HWPERF_OP_OK) {
+               e = -EINVAL;
+               goto err;
+       }
+
+       /* find nearest node with cpus and nearest memory */
+       for (router=NULL, j=0; j < op->ports; j++) {
+               dest = sn_hwperf_findobj_id(objbuf, nobj, ptdata[j].conn_id);
+               if (!dest || SN_HWPERF_FOREIGN(dest) ||
+                   !SN_HWPERF_IS_NODE(dest) || SN_HWPERF_IS_IONODE(dest)) {
+                       continue;
+               }
+               c = sn_hwperf_obj_to_cnode(dest);
+               if (!found_cpu && sn_hwperf_has_cpus(c)) {
+                       if (near_cpu_node)
+                               *near_cpu_node = c;
+                       found_cpu++;
+               }
+               if (!found_mem && sn_hwperf_has_mem(c)) {
+                       if (near_mem_node)
+                               *near_mem_node = c;
+                       found_mem++;
+               }
+               if (SN_HWPERF_IS_ROUTER(dest))
+                       router = dest;
+       }
+
+       if (router && (!found_cpu || !found_mem)) {
+               /* search for a node connected to the same router */
+               sz = router->ports * sizeof(struct sn_hwperf_port_info);
+               if (sz > sizeof(ptdata))
+                       BUG();
+               e = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
+                                     SN_HWPERF_ENUM_PORTS, router->id, sz,
+                                     (u64)&ptdata, 0, 0, NULL);
+               if (e != SN_HWPERF_OP_OK) {
+                       e = -EINVAL;
+                       goto err;
+               }
+               for (j=0; j < router->ports; j++) {
+                       dest = sn_hwperf_findobj_id(objbuf, nobj,
+                               ptdata[j].conn_id);
+                       if (!dest || dest->id == node ||
+                           SN_HWPERF_FOREIGN(dest) ||
+                           !SN_HWPERF_IS_NODE(dest) ||
+                           SN_HWPERF_IS_IONODE(dest)) {
+                               continue;
+                       }
+                       c = sn_hwperf_obj_to_cnode(dest);
+                       if (!found_cpu && sn_hwperf_has_cpus(c)) {
+                               if (near_cpu_node)
+                                       *near_cpu_node = c;
+                               found_cpu++;
+                       }
+                       if (!found_mem && sn_hwperf_has_mem(c)) {
+                               if (near_mem_node)
+                                       *near_mem_node = c;
+                               found_mem++;
+                       }
+                       if (found_cpu && found_mem)
+                               break;
+               }
+       }
+
+       if (!found_cpu || !found_mem) {
+               /* resort to _any_ node with CPUs and memory */
+               for (i=0, op=objbuf; i < nobj; i++, op++) {
+                       if (SN_HWPERF_FOREIGN(op) ||
+                           SN_HWPERF_IS_IONODE(op) ||
+                           !SN_HWPERF_IS_NODE(op)) {
+                               continue;
+                       }
+                       c = sn_hwperf_obj_to_cnode(op);
+                       if (!found_cpu && sn_hwperf_has_cpus(c)) {
+                               if (near_cpu_node)
+                                       *near_cpu_node = c;
+                               found_cpu++;
+                       }
+                       if (!found_mem && sn_hwperf_has_mem(c)) {
+                               if (near_mem_node)
+                                       *near_mem_node = c;
+                               found_mem++;
+                       }
+                       if (found_cpu && found_mem)
                                break;
-                       *p2 = '\0';
-                       seq_printf(s, "pcibus %d %s-%s\n",
-                               *ordinal, obj->location, p1);
-                       (*ordinal)++;
-                       p1 = p2 + 1;
                }
        }
-       free_page((unsigned long)pg);
+
+       if (!found_cpu || !found_mem)
+               e = -ENODATA;
+
+err:
+       return e;
 }
 
+
 static int sn_topology_show(struct seq_file *s, void *d)
 {
        int sz;
@@ -215,7 +384,6 @@ static int sn_topology_show(struct seq_file *s, void *d)
        struct sn_hwperf_object_info *p;
        struct sn_hwperf_object_info *obj = d;  /* this object */
        struct sn_hwperf_object_info *objs = s->private; /* all objects */
-       int rack, bay, slot, slab;
        u8 shubtype;
        u8 system_size;
        u8 sharing_size;
@@ -225,7 +393,6 @@ static int sn_topology_show(struct seq_file *s, void *d)
        u8 region_size;
        u16 nasid_mask;
        int nasid_msb;
-       int pci_bus_ordinal = 0;
 
        if (obj == objs) {
                seq_printf(s, "# sn_topology version 2\n");
@@ -253,6 +420,8 @@ static int sn_topology_show(struct seq_file *s, void *d)
                        shubtype ? "shub2" : "shub1", 
                        (u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift,
                        system_size, sharing_size, coher, region_size);
+
+               print_pci_topology(s);
        }
 
        if (SN_HWPERF_FOREIGN(obj)) {
@@ -272,11 +441,24 @@ static int sn_topology_show(struct seq_file *s, void *d)
        if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj))
                seq_putc(s, '\n');
        else {
+               cnodeid_t near_mem = -1;
+               cnodeid_t near_cpu = -1;
+
                seq_printf(s, ", nasid 0x%x", cnodeid_to_nasid(ordinal));
-               for (i=0; i < numionodes; i++) {
-                       seq_printf(s, i ? ":%d" : ", dist %d",
-                               node_distance(ordinal, i));
+
+               if (sn_hwperf_get_nearest_node_objdata(objs, sn_hwperf_obj_cnt,
+                       ordinal, &near_mem, &near_cpu) == 0) {
+                       seq_printf(s, ", near_mem_nodeid %d, near_cpu_nodeid %d",
+                               near_mem, near_cpu);
+               }
+
+               if (!SN_HWPERF_IS_IONODE(obj)) {
+                       for_each_online_node(i) {
+                               seq_printf(s, i ? ":%d" : ", dist %d",
+                                       node_distance(ordinal, i));
+                       }
                }
+
                seq_putc(s, '\n');
 
                /*
@@ -300,17 +482,6 @@ static int sn_topology_show(struct seq_file *s, void *d)
                                seq_putc(s, '\n');
                        }
                }
-
-               /*
-                * PCI busses attached to this node, if any
-                */
-               if (sn_hwperf_location_to_bpos(obj->location,
-                       &rack, &bay, &slot, &slab)) {
-                       /* export pci bus info */
-                       print_pci_topology(s, obj, &pci_bus_ordinal,
-                               rack, bay, slot, slab);
-
-               }
        }
 
        if (obj->ports) {
@@ -572,6 +743,8 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg)
                if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) {
                        memset(p, 0, a.sz);
                        for (i = 0; i < nobj; i++) {
+                               if (!SN_HWPERF_IS_NODE(objs + i))
+                                       continue;
                                node = sn_hwperf_obj_to_cnode(objs + i);
                                for_each_online_cpu(j) {
                                        if (node != cpu_to_node(j))
@@ -598,7 +771,7 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg)
 
        case SN_HWPERF_GET_NODE_NASID:
                if (a.sz != sizeof(u64) ||
-                  (node = a.arg) < 0 || node >= numionodes) {
+                  (node = a.arg) < 0 || !node_possible(node)) {
                        r = -EINVAL;
                        goto error;
                }
@@ -627,6 +800,14 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg)
                                vfree(objs);
                                goto error;
                        }
+
+                       if (!SN_HWPERF_IS_NODE(objs + i) &&
+                           !SN_HWPERF_IS_IONODE(objs + i)) {
+                               r = -ENOENT;
+                               vfree(objs);
+                               goto error;
+                       }
+
                        *(u64 *)p = (u64)sn_hwperf_obj_to_cnode(objs + i);
                        vfree(objs);
                }
@@ -692,6 +873,7 @@ static int sn_hwperf_init(void)
 
        /* single threaded, once-only initialization */
        down(&sn_hwperf_init_mutex);
+
        if (sn_hwperf_salheap) {
                up(&sn_hwperf_init_mutex);
                return e;
@@ -742,19 +924,6 @@ out:
                sn_hwperf_salheap = NULL;
                sn_hwperf_obj_cnt = 0;
        }
-
-       if (!e) {
-               /*
-                * Register a dynamic misc device for ioctl. Platforms
-                * supporting hotplug will create /dev/sn_hwperf, else
-                * user can to look up the minor number in /proc/misc.
-                */
-               if ((e = misc_register(&sn_hwperf_dev)) != 0) {
-                       printk(KERN_ERR "sn_hwperf_init: misc register "
-                              "for \"sn_hwperf\" failed, err %d\n", e);
-               }
-       }
-
        up(&sn_hwperf_init_mutex);
        return e;
 }
@@ -782,3 +951,41 @@ int sn_topology_release(struct inode *inode, struct file *file)
        vfree(seq->private);
        return seq_release(inode, file);
 }
+
+int sn_hwperf_get_nearest_node(cnodeid_t node,
+       cnodeid_t *near_mem_node, cnodeid_t *near_cpu_node)
+{
+       int e;
+       int nobj;
+       struct sn_hwperf_object_info *objbuf;
+
+       if ((e = sn_hwperf_enum_objects(&nobj, &objbuf)) == 0) {
+               e = sn_hwperf_get_nearest_node_objdata(objbuf, nobj,
+                       node, near_mem_node, near_cpu_node);
+               vfree(objbuf);
+       }
+
+       return e;
+}
+
+static int __devinit sn_hwperf_misc_register_init(void)
+{
+       int e;
+
+       sn_hwperf_init();
+
+       /*
+        * Register a dynamic misc device for hwperf ioctls. Platforms
+        * supporting hotplug will create /dev/sn_hwperf, else user
+        * can to look up the minor number in /proc/misc.
+        */
+       if ((e = misc_register(&sn_hwperf_dev)) != 0) {
+               printk(KERN_ERR "sn_hwperf_misc_register_init: failed to "
+               "register misc device for \"%s\"\n", sn_hwperf_dev.name);
+       }
+
+       return e;
+}
+
+device_initcall(sn_hwperf_misc_register_init); /* after misc_init() */
+EXPORT_SYMBOL(sn_hwperf_get_nearest_node);
index 6a80fca807b9c59119ca08367da12e1d7ceca651..51bf82720d994188faf55a74b68888908f78c3e1 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved.
  */
 #include <linux/config.h>
 #include <asm/uaccess.h>
@@ -15,7 +15,7 @@
 
 static int partition_id_show(struct seq_file *s, void *p)
 {
-       seq_printf(s, "%d\n", sn_local_partid());
+       seq_printf(s, "%d\n", sn_partition_id);
        return 0;
 }
 
index cde7375390b0db4e4160ffaaf44d6bc44dfb0763..adf5db2e2afeb4e2742457b40c062e0546e42972 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *
  *
- * Copyright (c) 2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2005 Silicon Graphics, Inc.  All Rights Reserved.
  * 
  * This program is free software; you can redistribute it and/or modify it 
  * under the terms of version 2 of the GNU General Public License 
@@ -50,14 +50,16 @@ void sn_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                             LED_CPU_HEARTBEAT, LED_CPU_HEARTBEAT);
        }
 
-       if (enable_shub_wars_1_1()) {
-               /* Bugfix code for SHUB 1.1 */
-               if (pda->pio_shub_war_cam_addr)
-                       *pda->pio_shub_war_cam_addr = 0x8000000000000010UL;
+       if (is_shub1()) {
+               if (enable_shub_wars_1_1()) {
+                       /* Bugfix code for SHUB 1.1 */
+                       if (pda->pio_shub_war_cam_addr)
+                               *pda->pio_shub_war_cam_addr = 0x8000000000000010UL;
+               }
+               if (pda->sn_lb_int_war_ticks == 0)
+                       sn_lb_int_war_check();
+               pda->sn_lb_int_war_ticks++;
+               if (pda->sn_lb_int_war_ticks >= SN_LB_INT_WAR_INTERVAL)
+                       pda->sn_lb_int_war_ticks = 0;
        }
-       if (pda->sn_lb_int_war_ticks == 0)
-               sn_lb_int_war_check();
-       pda->sn_lb_int_war_ticks++;
-       if (pda->sn_lb_int_war_ticks >= SN_LB_INT_WAR_INTERVAL)
-               pda->sn_lb_int_war_ticks = 0;
 }
index 254fe15c064b705ab5575cda49634a3c45ab5735..b45db5133f55062abda30bc36b194e3ff8f2012f 100644 (file)
@@ -191,7 +191,7 @@ cx_device_register(nasid_t nasid, int part_num, int mfg_num,
 {
        struct cx_dev *cx_dev;
 
-       cx_dev = kcalloc(1, sizeof(struct cx_dev), GFP_KERNEL);
+       cx_dev = kzalloc(sizeof(struct cx_dev), GFP_KERNEL);
        DBG("cx_dev= 0x%p\n", cx_dev);
        if (cx_dev == NULL)
                return -ENOMEM;
index 2f915bce25f9e6734040ccb0611b2236acac12ee..321576b1b425f8916858c875058326148216fa8f 100644 (file)
@@ -7,4 +7,4 @@
 #
 # Makefile for the sn pci general routines.
 
-obj-y := pci_dma.o tioca_provider.o pcibr/ 
+obj-y := pci_dma.o tioca_provider.o tioce_provider.o pcibr/
index b058dc2a0b9d3dfb7a17fe73f2ae35f72266ebd3..34093476e9652fc03938edeadeddb4596d439d34 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2001-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2001-2005 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/types.h>
@@ -215,8 +215,8 @@ void sn_dma_flush(uint64_t addr)
        int is_tio;
        int wid_num;
        int i, j;
-       int bwin;
        uint64_t flags;
+       uint64_t itte;
        struct hubdev_info *hubinfo;
        volatile struct sn_flush_device_list *p;
        struct sn_flush_nasid_entry *flush_nasid_list;
@@ -233,31 +233,36 @@ void sn_dma_flush(uint64_t addr)
        if (!hubinfo) {
                BUG();
        }
-       is_tio = (nasid & 1);
-       if (is_tio) {
-               wid_num = TIO_SWIN_WIDGETNUM(addr);
-               bwin = TIO_BWIN_WINDOWNUM(addr);
-       } else {
-               wid_num = SWIN_WIDGETNUM(addr);
-               bwin = BWIN_WINDOWNUM(addr);
-       }
 
        flush_nasid_list = &hubinfo->hdi_flush_nasid_list;
        if (flush_nasid_list->widget_p == NULL)
                return;
-       if (bwin > 0) {
-               uint64_t itte = flush_nasid_list->iio_itte[bwin];
 
-               if (is_tio) {
-                       wid_num = (itte >> TIO_ITTE_WIDGET_SHIFT) &
-                           TIO_ITTE_WIDGET_MASK;
-               } else {
-                       wid_num = (itte >> IIO_ITTE_WIDGET_SHIFT) &
-                           IIO_ITTE_WIDGET_MASK;
-               }
+       is_tio = (nasid & 1);
+       if (is_tio) {
+               int itte_index;
+
+               if (TIO_HWIN(addr))
+                       itte_index = 0;
+               else if (TIO_BWIN_WINDOWNUM(addr))
+                       itte_index = TIO_BWIN_WINDOWNUM(addr);
+               else
+                       itte_index = -1;
+
+               if (itte_index >= 0) {
+                       itte = flush_nasid_list->iio_itte[itte_index];
+                       if (! TIO_ITTE_VALID(itte))
+                               return;
+                       wid_num = TIO_ITTE_WIDGET(itte);
+               } else
+                       wid_num = TIO_SWIN_WIDGETNUM(addr);
+       } else {
+               if (BWIN_WINDOWNUM(addr)) {
+                       itte = flush_nasid_list->iio_itte[BWIN_WINDOWNUM(addr)];
+                       wid_num = IIO_ITTE_WIDGET(itte);
+               } else
+                       wid_num = SWIN_WIDGETNUM(addr);
        }
-       if (flush_nasid_list->widget_p == NULL)
-               return;
        if (flush_nasid_list->widget_p[wid_num] == NULL)
                return;
        p = &flush_nasid_list->widget_p[wid_num][0];
@@ -283,10 +288,16 @@ void sn_dma_flush(uint64_t addr)
        /*
         * For TIOCP use the Device(x) Write Request Buffer Flush Bridge
         * register since it ensures the data has entered the coherence
-        * domain, unlike PIC
+        * domain, unlike PIC.
         */
        if (is_tio) {
-               uint32_t tio_id = REMOTE_HUB_L(nasid, TIO_NODE_ID);
+               /*
+                * Note:  devices behind TIOCE should never be matched in the
+                * above code, and so the following code is PIC/CP centric.
+                * If CE ever needs the sn_dma_flush mechanism, we will have
+                * to account for that here and in tioce_bus_fixup().
+                */
+               uint32_t tio_id = HUB_L(TIO_IOSPACE_ADDR(nasid, TIO_NODE_ID));
                uint32_t revnum = XWIDGET_PART_REV_NUM(tio_id);
 
                /* TIOCP BRINGUP WAR (PV907516): Don't write buffer flush reg */
@@ -306,7 +317,8 @@ void sn_dma_flush(uint64_t addr)
                *(volatile uint32_t *)(p->sfdl_force_int_addr) = 1;
 
                /* wait for the interrupt to come back. */
-               while (*(p->sfdl_flush_addr) != 0x10f) ;
+               while (*(p->sfdl_flush_addr) != 0x10f)
+                       cpu_relax();
 
                /* okay, everything is synched up. */
                spin_unlock_irqrestore((spinlock_t *)&p->sfdl_flush_lock, flags);
index b95e928636a1bb6c4417e23381b9bfd27992c6fc..7b03b8084ffc441d90d3725e601816f6b856d741 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/sn/pcibus_provider_defs.h>
 #include <asm/sn/pcidev.h>
 #include <asm/sn/sn_sal.h>
+#include <asm/sn/sn2/sn_hwperf.h>
 #include "xtalk/xwidgetdev.h"
 #include "xtalk/hubdev.h"
 
@@ -60,7 +61,7 @@ static int sal_pcibr_error_interrupt(struct pcibus_info *soft)
        ret_stuff.status = 0;
        ret_stuff.v0 = 0;
 
-       segment = 0;
+       segment = soft->pbi_buscommon.bs_persist_segment;
        busnum = soft->pbi_buscommon.bs_persist_busnum;
        SAL_CALL_NOLOCK(ret_stuff,
                        (u64) SN_SAL_IOIF_ERROR_INTERRUPT,
@@ -88,6 +89,7 @@ void *
 pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller)
 {
        int nasid, cnode, j;
+       cnodeid_t near_cnode;
        struct hubdev_info *hubdev_info;
        struct pcibus_info *soft;
        struct sn_flush_device_list *sn_flush_device_list;
@@ -115,7 +117,7 @@ pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
        /*
         * register the bridge's error interrupt handler
         */
-       if (request_irq(SGI_PCIBR_ERROR, (void *)pcibr_error_intr_handler,
+       if (request_irq(SGI_PCIASIC_ERROR, (void *)pcibr_error_intr_handler,
                        SA_SHIRQ, "PCIBR error", (void *)(soft))) {
                printk(KERN_WARNING
                       "pcibr cannot allocate interrupt for error handler\n");
@@ -142,9 +144,12 @@ pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
                             j++, sn_flush_device_list++) {
                                if (sn_flush_device_list->sfdl_slot == -1)
                                        continue;
-                               if (sn_flush_device_list->
-                                   sfdl_persistent_busnum ==
-                                   soft->pbi_buscommon.bs_persist_busnum)
+                               if ((sn_flush_device_list->
+                                    sfdl_persistent_segment ==
+                                    soft->pbi_buscommon.bs_persist_segment) &&
+                                    (sn_flush_device_list->
+                                    sfdl_persistent_busnum ==
+                                    soft->pbi_buscommon.bs_persist_busnum))
                                        sn_flush_device_list->sfdl_pcibus_info =
                                            soft;
                        }
@@ -158,12 +163,18 @@ pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
        memset(soft->pbi_int_ate_resource.ate, 0,
               (soft->pbi_int_ate_size * sizeof(uint64_t)));
 
-       if (prom_bussoft->bs_asic_type == PCIIO_ASIC_TYPE_TIOCP)
-               /*
-                * TIO PCI Bridge with no closest node information.
-                * FIXME: Find another way to determine the closest node
-                */
-               controller->node = -1;
+       if (prom_bussoft->bs_asic_type == PCIIO_ASIC_TYPE_TIOCP) {
+               /* TIO PCI Bridge: find nearest node with CPUs */
+               int e = sn_hwperf_get_nearest_node(cnode, NULL, &near_cnode);
+
+               if (e < 0) {
+                       near_cnode = (cnodeid_t)-1; /* use any node */
+                       printk(KERN_WARNING "pcibr_bus_fixup: failed to find "
+                               "near node with CPUs to TIO node %d, err=%d\n",
+                               cnode, e);
+               }
+               controller->node = near_cnode;
+       }
        else
                controller->node = cnode;
        return soft;
@@ -175,6 +186,9 @@ void pcibr_force_interrupt(struct sn_irq_info *sn_irq_info)
        struct pcibus_info *pcibus_info;
        int bit = sn_irq_info->irq_int_bit;
 
+       if (! sn_irq_info->irq_bridge)
+               return;
+
        pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
        if (pcidev_info) {
                pcibus_info =
@@ -184,7 +198,7 @@ void pcibr_force_interrupt(struct sn_irq_info *sn_irq_info)
        }
 }
 
-void pcibr_change_devices_irq(struct sn_irq_info *sn_irq_info)
+void pcibr_target_interrupt(struct sn_irq_info *sn_irq_info)
 {
        struct pcidev_info *pcidev_info;
        struct pcibus_info *pcibus_info;
@@ -219,6 +233,8 @@ struct sn_pcibus_provider pcibr_provider = {
        .dma_map_consistent = pcibr_dma_map_consistent,
        .dma_unmap = pcibr_dma_unmap,
        .bus_fixup = pcibr_bus_fixup,
+       .force_interrupt = pcibr_force_interrupt,
+       .target_interrupt = pcibr_target_interrupt
 };
 
 int
index 5d76a758146597d45d822474789223db97dcb4bc..19bced34d5f1f1e79998fb11917053c91567ad1f 100644 (file)
@@ -148,7 +148,7 @@ tioca_gart_init(struct tioca_kernel *tioca_kern)
        tioca_kern->ca_pcigart_entries =
            tioca_kern->ca_pciap_size / tioca_kern->ca_ap_pagesize;
        tioca_kern->ca_pcigart_pagemap =
-           kcalloc(1, tioca_kern->ca_pcigart_entries / 8, GFP_KERNEL);
+           kzalloc(tioca_kern->ca_pcigart_entries / 8, GFP_KERNEL);
        if (!tioca_kern->ca_pcigart_pagemap) {
                free_pages((unsigned long)tioca_kern->ca_gart,
                           get_order(tioca_kern->ca_gart_size));
@@ -392,7 +392,7 @@ tioca_dma_mapped(struct pci_dev *pdev, uint64_t paddr, size_t req_size)
         * allocate a map struct
         */
 
-       ca_dmamap = kcalloc(1, sizeof(struct tioca_dmamap), GFP_ATOMIC);
+       ca_dmamap = kzalloc(sizeof(struct tioca_dmamap), GFP_ATOMIC);
        if (!ca_dmamap)
                goto map_return;
 
@@ -559,7 +559,7 @@ tioca_error_intr_handler(int irq, void *arg, struct pt_regs *pt)
        ret_stuff.status = 0;
        ret_stuff.v0 = 0;
 
-       segment = 0;
+       segment = soft->ca_common.bs_persist_segment;
        busnum = soft->ca_common.bs_persist_busnum;
 
        SAL_CALL_NOLOCK(ret_stuff,
@@ -600,7 +600,7 @@ tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
         * Allocate kernel bus soft and copy from prom.
         */
 
-       tioca_common = kcalloc(1, sizeof(struct tioca_common), GFP_KERNEL);
+       tioca_common = kzalloc(sizeof(struct tioca_common), GFP_KERNEL);
        if (!tioca_common)
                return NULL;
 
@@ -609,7 +609,7 @@ tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
 
        /* init kernel-private area */
 
-       tioca_kern = kcalloc(1, sizeof(struct tioca_kernel), GFP_KERNEL);
+       tioca_kern = kzalloc(sizeof(struct tioca_kernel), GFP_KERNEL);
        if (!tioca_kern) {
                kfree(tioca_common);
                return NULL;
@@ -622,7 +622,8 @@ tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
            nasid_to_cnodeid(tioca_common->ca_closest_nasid);
        tioca_common->ca_kernel_private = (uint64_t) tioca_kern;
 
-       bus = pci_find_bus(0, tioca_common->ca_common.bs_persist_busnum);
+       bus = pci_find_bus(tioca_common->ca_common.bs_persist_segment,
+               tioca_common->ca_common.bs_persist_busnum);
        BUG_ON(!bus);
        tioca_kern->ca_devices = &bus->devices;
 
@@ -656,6 +657,8 @@ static struct sn_pcibus_provider tioca_pci_interfaces = {
        .dma_map_consistent = tioca_dma_map,
        .dma_unmap = tioca_dma_unmap,
        .bus_fixup = tioca_bus_fixup,
+       .force_interrupt = NULL,
+       .target_interrupt = NULL
 };
 
 /**
diff --git a/arch/ia64/sn/pci/tioce_provider.c b/arch/ia64/sn/pci/tioce_provider.c
new file mode 100644 (file)
index 0000000..8e75db2
--- /dev/null
@@ -0,0 +1,771 @@
+/*
+ * 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 (C) 2003-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/pcidev.h>
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/tioce_provider.h>
+
+/**
+ * Bus address ranges for the 5 flavors of TIOCE DMA
+ */
+
+#define TIOCE_D64_MIN  0x8000000000000000UL
+#define TIOCE_D64_MAX  0xffffffffffffffffUL
+#define TIOCE_D64_ADDR(a)      ((a) >= TIOCE_D64_MIN)
+
+#define TIOCE_D32_MIN  0x0000000080000000UL
+#define TIOCE_D32_MAX  0x00000000ffffffffUL
+#define TIOCE_D32_ADDR(a)      ((a) >= TIOCE_D32_MIN && (a) <= TIOCE_D32_MAX)
+
+#define TIOCE_M32_MIN  0x0000000000000000UL
+#define TIOCE_M32_MAX  0x000000007fffffffUL
+#define TIOCE_M32_ADDR(a)      ((a) >= TIOCE_M32_MIN && (a) <= TIOCE_M32_MAX)
+
+#define TIOCE_M40_MIN  0x0000004000000000UL
+#define TIOCE_M40_MAX  0x0000007fffffffffUL
+#define TIOCE_M40_ADDR(a)      ((a) >= TIOCE_M40_MIN && (a) <= TIOCE_M40_MAX)
+
+#define TIOCE_M40S_MIN 0x0000008000000000UL
+#define TIOCE_M40S_MAX 0x000000ffffffffffUL
+#define TIOCE_M40S_ADDR(a)     ((a) >= TIOCE_M40S_MIN && (a) <= TIOCE_M40S_MAX)
+
+/*
+ * ATE manipulation macros.
+ */
+
+#define ATE_PAGESHIFT(ps)      (__ffs(ps))
+#define ATE_PAGEMASK(ps)       ((ps)-1)
+
+#define ATE_PAGE(x, ps) ((x) >> ATE_PAGESHIFT(ps))
+#define ATE_NPAGES(start, len, pagesize) \
+       (ATE_PAGE((start)+(len)-1, pagesize) - ATE_PAGE(start, pagesize) + 1)
+
+#define ATE_VALID(ate) ((ate) & (1UL << 63))
+#define ATE_MAKE(addr, ps) (((addr) & ~ATE_PAGEMASK(ps)) | (1UL << 63))
+
+/*
+ * Flavors of ate-based mapping supported by tioce_alloc_map()
+ */
+
+#define TIOCE_ATE_M32  1
+#define TIOCE_ATE_M40  2
+#define TIOCE_ATE_M40S 3
+
+#define KB(x)  ((x) << 10)
+#define MB(x)  ((x) << 20)
+#define GB(x)  ((x) << 30)
+
+/**
+ * tioce_dma_d64 - create a DMA mapping using 64-bit direct mode
+ * @ct_addr: system coretalk address
+ *
+ * Map @ct_addr into 64-bit CE bus space.  No device context is necessary
+ * and no CE mapping are consumed.
+ *
+ * Bits 53:0 come from the coretalk address.  The remaining bits are set as
+ * follows:
+ *
+ * 63    - must be 1 to indicate d64 mode to CE hardware
+ * 62    - barrier bit ... controlled with tioce_dma_barrier()
+ * 61    - 0 since this is not an MSI transaction
+ * 60:54 - reserved, MBZ
+ */
+static uint64_t
+tioce_dma_d64(unsigned long ct_addr)
+{
+       uint64_t bus_addr;
+
+       bus_addr = ct_addr | (1UL << 63);
+
+       return bus_addr;
+}
+
+/**
+ * pcidev_to_tioce - return misc ce related pointers given a pci_dev
+ * @pci_dev: pci device context
+ * @base: ptr to store struct tioce_mmr * for the CE holding this device
+ * @kernel: ptr to store struct tioce_kernel * for the CE holding this device
+ * @port: ptr to store the CE port number that this device is on
+ *
+ * Return pointers to various CE-related structures for the CE upstream of
+ * @pci_dev.
+ */
+static inline void
+pcidev_to_tioce(struct pci_dev *pdev, struct tioce **base,
+               struct tioce_kernel **kernel, int *port)
+{
+       struct pcidev_info *pcidev_info;
+       struct tioce_common *ce_common;
+       struct tioce_kernel *ce_kernel;
+
+       pcidev_info = SN_PCIDEV_INFO(pdev);
+       ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info;
+       ce_kernel = (struct tioce_kernel *)ce_common->ce_kernel_private;
+
+       if (base)
+               *base = (struct tioce *)ce_common->ce_pcibus.bs_base;
+       if (kernel)
+               *kernel = ce_kernel;
+
+       /*
+        * we use port as a zero-based value internally, even though the
+        * documentation is 1-based.
+        */
+       if (port)
+               *port =
+                   (pdev->bus->number < ce_kernel->ce_port1_secondary) ? 0 : 1;
+}
+
+/**
+ * tioce_alloc_map - Given a coretalk address, map it to pcie bus address
+ * space using one of the various ATE-based address modes.
+ * @ce_kern: tioce context
+ * @type: map mode to use
+ * @port: 0-based port that the requesting device is downstream of
+ * @ct_addr: the coretalk address to map
+ * @len: number of bytes to map
+ *
+ * Given the addressing type, set up various paramaters that define the
+ * ATE pool to use.  Search for a contiguous block of entries to cover the
+ * length, and if enough resources exist, fill in the ATE's and construct a
+ * tioce_dmamap struct to track the mapping.
+ */
+static uint64_t
+tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port,
+               uint64_t ct_addr, int len)
+{
+       int i;
+       int j;
+       int first;
+       int last;
+       int entries;
+       int nates;
+       int pagesize;
+       uint64_t *ate_shadow;
+       uint64_t *ate_reg;
+       uint64_t addr;
+       struct tioce *ce_mmr;
+       uint64_t bus_base;
+       struct tioce_dmamap *map;
+
+       ce_mmr = (struct tioce *)ce_kern->ce_common->ce_pcibus.bs_base;
+
+       switch (type) {
+       case TIOCE_ATE_M32:
+               /*
+                * The first 64 entries of the ate3240 pool are dedicated to
+                * super-page (TIOCE_ATE_M40S) mode.
+                */
+               first = 64;
+               entries = TIOCE_NUM_M3240_ATES - 64;
+               ate_shadow = ce_kern->ce_ate3240_shadow;
+               ate_reg = ce_mmr->ce_ure_ate3240;
+               pagesize = ce_kern->ce_ate3240_pagesize;
+               bus_base = TIOCE_M32_MIN;
+               break;
+       case TIOCE_ATE_M40:
+               first = 0;
+               entries = TIOCE_NUM_M40_ATES;
+               ate_shadow = ce_kern->ce_ate40_shadow;
+               ate_reg = ce_mmr->ce_ure_ate40;
+               pagesize = MB(64);
+               bus_base = TIOCE_M40_MIN;
+               break;
+       case TIOCE_ATE_M40S:
+               /*
+                * ate3240 entries 0-31 are dedicated to port1 super-page
+                * mappings.  ate3240 entries 32-63 are dedicated to port2.
+                */
+               first = port * 32;
+               entries = 32;
+               ate_shadow = ce_kern->ce_ate3240_shadow;
+               ate_reg = ce_mmr->ce_ure_ate3240;
+               pagesize = GB(16);
+               bus_base = TIOCE_M40S_MIN;
+               break;
+       default:
+               return 0;
+       }
+
+       nates = ATE_NPAGES(ct_addr, len, pagesize);
+       if (nates > entries)
+               return 0;
+
+       last = first + entries - nates;
+       for (i = first; i <= last; i++) {
+               if (ATE_VALID(ate_shadow[i]))
+                       continue;
+
+               for (j = i; j < i + nates; j++)
+                       if (ATE_VALID(ate_shadow[j]))
+                               break;
+
+               if (j >= i + nates)
+                       break;
+       }
+
+       if (i > last)
+               return 0;
+
+       map = kcalloc(1, sizeof(struct tioce_dmamap), GFP_ATOMIC);
+       if (!map)
+               return 0;
+
+       addr = ct_addr;
+       for (j = 0; j < nates; j++) {
+               uint64_t ate;
+
+               ate = ATE_MAKE(addr, pagesize);
+               ate_shadow[i + j] = ate;
+               ate_reg[i + j] = ate;
+               addr += pagesize;
+       }
+
+       map->refcnt = 1;
+       map->nbytes = nates * pagesize;
+       map->ct_start = ct_addr & ~ATE_PAGEMASK(pagesize);
+       map->pci_start = bus_base + (i * pagesize);
+       map->ate_hw = &ate_reg[i];
+       map->ate_shadow = &ate_shadow[i];
+       map->ate_count = nates;
+
+       list_add(&map->ce_dmamap_list, &ce_kern->ce_dmamap_list);
+
+       return (map->pci_start + (ct_addr - map->ct_start));
+}
+
+/**
+ * tioce_dma_d32 - create a DMA mapping using 32-bit direct mode
+ * @pdev: linux pci_dev representing the function
+ * @paddr: system physical address
+ *
+ * Map @paddr into 32-bit bus space of the CE associated with @pcidev_info.
+ */
+static uint64_t
+tioce_dma_d32(struct pci_dev *pdev, uint64_t ct_addr)
+{
+       int dma_ok;
+       int port;
+       struct tioce *ce_mmr;
+       struct tioce_kernel *ce_kern;
+       uint64_t ct_upper;
+       uint64_t ct_lower;
+       dma_addr_t bus_addr;
+
+       ct_upper = ct_addr & ~0x3fffffffUL;
+       ct_lower = ct_addr & 0x3fffffffUL;
+
+       pcidev_to_tioce(pdev, &ce_mmr, &ce_kern, &port);
+
+       if (ce_kern->ce_port[port].dirmap_refcnt == 0) {
+               volatile uint64_t tmp;
+
+               ce_kern->ce_port[port].dirmap_shadow = ct_upper;
+               ce_mmr->ce_ure_dir_map[port] = ct_upper;
+               tmp = ce_mmr->ce_ure_dir_map[port];
+               dma_ok = 1;
+       } else
+               dma_ok = (ce_kern->ce_port[port].dirmap_shadow == ct_upper);
+
+       if (dma_ok) {
+               ce_kern->ce_port[port].dirmap_refcnt++;
+               bus_addr = TIOCE_D32_MIN + ct_lower;
+       } else
+               bus_addr = 0;
+
+       return bus_addr;
+}
+
+/**
+ * tioce_dma_barrier - swizzle a TIOCE bus address to include or exclude
+ * the barrier bit.
+ * @bus_addr:  bus address to swizzle
+ *
+ * Given a TIOCE bus address, set the appropriate bit to indicate barrier
+ * attributes.
+ */
+static uint64_t
+tioce_dma_barrier(uint64_t bus_addr, int on)
+{
+       uint64_t barrier_bit;
+
+       /* barrier not supported in M40/M40S mode */
+       if (TIOCE_M40_ADDR(bus_addr) || TIOCE_M40S_ADDR(bus_addr))
+               return bus_addr;
+
+       if (TIOCE_D64_ADDR(bus_addr))
+               barrier_bit = (1UL << 62);
+       else                    /* must be m32 or d32 */
+               barrier_bit = (1UL << 30);
+
+       return (on) ? (bus_addr | barrier_bit) : (bus_addr & ~barrier_bit);
+}
+
+/**
+ * tioce_dma_unmap - release CE mapping resources
+ * @pdev: linux pci_dev representing the function
+ * @bus_addr: bus address returned by an earlier tioce_dma_map
+ * @dir: mapping direction (unused)
+ *
+ * Locate mapping resources associated with @bus_addr and release them.
+ * For mappings created using the direct modes there are no resources
+ * to release.
+ */
+void
+tioce_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir)
+{
+       int i;
+       int port;
+       struct tioce_kernel *ce_kern;
+       struct tioce *ce_mmr;
+       unsigned long flags;
+
+       bus_addr = tioce_dma_barrier(bus_addr, 0);
+       pcidev_to_tioce(pdev, &ce_mmr, &ce_kern, &port);
+
+       /* nothing to do for D64 */
+
+       if (TIOCE_D64_ADDR(bus_addr))
+               return;
+
+       spin_lock_irqsave(&ce_kern->ce_lock, flags);
+
+       if (TIOCE_D32_ADDR(bus_addr)) {
+               if (--ce_kern->ce_port[port].dirmap_refcnt == 0) {
+                       ce_kern->ce_port[port].dirmap_shadow = 0;
+                       ce_mmr->ce_ure_dir_map[port] = 0;
+               }
+       } else {
+               struct tioce_dmamap *map;
+
+               list_for_each_entry(map, &ce_kern->ce_dmamap_list,
+                                   ce_dmamap_list) {
+                       uint64_t last;
+
+                       last = map->pci_start + map->nbytes - 1;
+                       if (bus_addr >= map->pci_start && bus_addr <= last)
+                               break;
+               }
+
+               if (&map->ce_dmamap_list == &ce_kern->ce_dmamap_list) {
+                       printk(KERN_WARNING
+                              "%s:  %s - no map found for bus_addr 0x%lx\n",
+                              __FUNCTION__, pci_name(pdev), bus_addr);
+               } else if (--map->refcnt == 0) {
+                       for (i = 0; i < map->ate_count; i++) {
+                               map->ate_shadow[i] = 0;
+                               map->ate_hw[i] = 0;
+                       }
+
+                       list_del(&map->ce_dmamap_list);
+                       kfree(map);
+               }
+       }
+
+       spin_unlock_irqrestore(&ce_kern->ce_lock, flags);
+}
+
+/**
+ * tioce_do_dma_map - map pages for PCI DMA
+ * @pdev: linux pci_dev representing the function
+ * @paddr: host physical address to map
+ * @byte_count: bytes to map
+ *
+ * This is the main wrapper for mapping host physical pages to CE PCI space.
+ * The mapping mode used is based on the device's dma_mask.
+ */
+static uint64_t
+tioce_do_dma_map(struct pci_dev *pdev, uint64_t paddr, size_t byte_count,
+                int barrier)
+{
+       unsigned long flags;
+       uint64_t ct_addr;
+       uint64_t mapaddr = 0;
+       struct tioce_kernel *ce_kern;
+       struct tioce_dmamap *map;
+       int port;
+       uint64_t dma_mask;
+
+       dma_mask = (barrier) ? pdev->dev.coherent_dma_mask : pdev->dma_mask;
+
+       /* cards must be able to address at least 31 bits */
+       if (dma_mask < 0x7fffffffUL)
+               return 0;
+
+       ct_addr = PHYS_TO_TIODMA(paddr);
+
+       /*
+        * If the device can generate 64 bit addresses, create a D64 map.
+        * Since this should never fail, bypass the rest of the checks.
+        */
+       if (dma_mask == ~0UL) {
+               mapaddr = tioce_dma_d64(ct_addr);
+               goto dma_map_done;
+       }
+
+       pcidev_to_tioce(pdev, NULL, &ce_kern, &port);
+
+       spin_lock_irqsave(&ce_kern->ce_lock, flags);
+
+       /*
+        * D64 didn't work ... See if we have an existing map that covers
+        * this address range.  Must account for devices dma_mask here since
+        * an existing map might have been done in a mode using more pci
+        * address bits than this device can support.
+        */
+       list_for_each_entry(map, &ce_kern->ce_dmamap_list, ce_dmamap_list) {
+               uint64_t last;
+
+               last = map->ct_start + map->nbytes - 1;
+               if (ct_addr >= map->ct_start &&
+                   ct_addr + byte_count - 1 <= last &&
+                   map->pci_start <= dma_mask) {
+                       map->refcnt++;
+                       mapaddr = map->pci_start + (ct_addr - map->ct_start);
+                       break;
+               }
+       }
+
+       /*
+        * If we don't have a map yet, and the card can generate 40
+        * bit addresses, try the M40/M40S modes.  Note these modes do not
+        * support a barrier bit, so if we need a consistent map these
+        * won't work.
+        */
+       if (!mapaddr && !barrier && dma_mask >= 0xffffffffffUL) {
+               /*
+                * We have two options for 40-bit mappings:  16GB "super" ATE's
+                * and 64MB "regular" ATE's.  We'll try both if needed for a
+                * given mapping but which one we try first depends on the
+                * size.  For requests >64MB, prefer to use a super page with
+                * regular as the fallback. Otherwise, try in the reverse order.
+                */
+
+               if (byte_count > MB(64)) {
+                       mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40S,
+                                                 port, ct_addr, byte_count);
+                       if (!mapaddr)
+                               mapaddr =
+                                   tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1,
+                                                   ct_addr, byte_count);
+               } else {
+                       mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1,
+                                                 ct_addr, byte_count);
+                       if (!mapaddr)
+                               mapaddr =
+                                   tioce_alloc_map(ce_kern, TIOCE_ATE_M40S,
+                                                   port, ct_addr, byte_count);
+               }
+       }
+
+       /*
+        * 32-bit direct is the next mode to try
+        */
+       if (!mapaddr && dma_mask >= 0xffffffffUL)
+               mapaddr = tioce_dma_d32(pdev, ct_addr);
+
+       /*
+        * Last resort, try 32-bit ATE-based map.
+        */
+       if (!mapaddr)
+               mapaddr =
+                   tioce_alloc_map(ce_kern, TIOCE_ATE_M32, -1, ct_addr,
+                                   byte_count);
+
+       spin_unlock_irqrestore(&ce_kern->ce_lock, flags);
+
+dma_map_done:
+       if (mapaddr & barrier)
+               mapaddr = tioce_dma_barrier(mapaddr, 1);
+
+       return mapaddr;
+}
+
+/**
+ * tioce_dma - standard pci dma map interface
+ * @pdev: pci device requesting the map
+ * @paddr: system physical address to map into pci space
+ * @byte_count: # bytes to map
+ *
+ * Simply call tioce_do_dma_map() to create a map with the barrier bit clear
+ * in the address.
+ */
+static uint64_t
+tioce_dma(struct pci_dev *pdev, uint64_t paddr, size_t byte_count)
+{
+       return tioce_do_dma_map(pdev, paddr, byte_count, 0);
+}
+
+/**
+ * tioce_dma_consistent - consistent pci dma map interface
+ * @pdev: pci device requesting the map
+ * @paddr: system physical address to map into pci space
+ * @byte_count: # bytes to map
+ *
+ * Simply call tioce_do_dma_map() to create a map with the barrier bit set
+ * in the address.
+ */ static uint64_t
+tioce_dma_consistent(struct pci_dev *pdev, uint64_t paddr, size_t byte_count)
+{
+       return tioce_do_dma_map(pdev, paddr, byte_count, 1);
+}
+
+/**
+ * tioce_error_intr_handler - SGI TIO CE error interrupt handler
+ * @irq: unused
+ * @arg: pointer to tioce_common struct for the given CE
+ * @pt: unused
+ *
+ * Handle a CE error interrupt.  Simply a wrapper around a SAL call which
+ * defers processing to the SGI prom.
+ */ static irqreturn_t
+tioce_error_intr_handler(int irq, void *arg, struct pt_regs *pt)
+{
+       struct tioce_common *soft = arg;
+       struct ia64_sal_retval ret_stuff;
+       ret_stuff.status = 0;
+       ret_stuff.v0 = 0;
+
+       SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_ERROR_INTERRUPT,
+                       soft->ce_pcibus.bs_persist_segment,
+                       soft->ce_pcibus.bs_persist_busnum, 0, 0, 0, 0, 0);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * tioce_kern_init - init kernel structures related to a given TIOCE
+ * @tioce_common: ptr to a cached tioce_common struct that originated in prom
+ */ static struct tioce_kernel *
+tioce_kern_init(struct tioce_common *tioce_common)
+{
+       int i;
+       uint32_t tmp;
+       struct tioce *tioce_mmr;
+       struct tioce_kernel *tioce_kern;
+
+       tioce_kern = kcalloc(1, sizeof(struct tioce_kernel), GFP_KERNEL);
+       if (!tioce_kern) {
+               return NULL;
+       }
+
+       tioce_kern->ce_common = tioce_common;
+       spin_lock_init(&tioce_kern->ce_lock);
+       INIT_LIST_HEAD(&tioce_kern->ce_dmamap_list);
+       tioce_common->ce_kernel_private = (uint64_t) tioce_kern;
+
+       /*
+        * Determine the secondary bus number of the port2 logical PPB.
+        * This is used to decide whether a given pci device resides on
+        * port1 or port2.  Note:  We don't have enough plumbing set up
+        * here to use pci_read_config_xxx() so use the raw_pci_ops vector.
+        */
+
+       raw_pci_ops->read(tioce_common->ce_pcibus.bs_persist_segment,
+                         tioce_common->ce_pcibus.bs_persist_busnum,
+                         PCI_DEVFN(2, 0), PCI_SECONDARY_BUS, 1, &tmp);
+       tioce_kern->ce_port1_secondary = (uint8_t) tmp;
+
+       /*
+        * Set PMU pagesize to the largest size available, and zero out
+        * the ate's.
+        */
+
+       tioce_mmr = (struct tioce *)tioce_common->ce_pcibus.bs_base;
+       tioce_mmr->ce_ure_page_map &= ~CE_URE_PAGESIZE_MASK;
+       tioce_mmr->ce_ure_page_map |= CE_URE_256K_PAGESIZE;
+       tioce_kern->ce_ate3240_pagesize = KB(256);
+
+       for (i = 0; i < TIOCE_NUM_M40_ATES; i++) {
+               tioce_kern->ce_ate40_shadow[i] = 0;
+               tioce_mmr->ce_ure_ate40[i] = 0;
+       }
+
+       for (i = 0; i < TIOCE_NUM_M3240_ATES; i++) {
+               tioce_kern->ce_ate3240_shadow[i] = 0;
+               tioce_mmr->ce_ure_ate3240[i] = 0;
+       }
+
+       return tioce_kern;
+}
+
+/**
+ * tioce_force_interrupt - implement altix force_interrupt() backend for CE
+ * @sn_irq_info: sn asic irq that we need an interrupt generated for
+ *
+ * Given an sn_irq_info struct, set the proper bit in ce_adm_force_int to
+ * force a secondary interrupt to be generated.  This is to work around an
+ * asic issue where there is a small window of opportunity for a legacy device
+ * interrupt to be lost.
+ */
+static void
+tioce_force_interrupt(struct sn_irq_info *sn_irq_info)
+{
+       struct pcidev_info *pcidev_info;
+       struct tioce_common *ce_common;
+       struct tioce *ce_mmr;
+       uint64_t force_int_val;
+
+       if (!sn_irq_info->irq_bridge)
+               return;
+
+       if (sn_irq_info->irq_bridge_type != PCIIO_ASIC_TYPE_TIOCE)
+               return;
+
+       pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
+       if (!pcidev_info)
+               return;
+
+       ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info;
+       ce_mmr = (struct tioce *)ce_common->ce_pcibus.bs_base;
+
+       /*
+        * irq_int_bit is originally set up by prom, and holds the interrupt
+        * bit shift (not mask) as defined by the bit definitions in the
+        * ce_adm_int mmr.  These shifts are not the same for the
+        * ce_adm_force_int register, so do an explicit mapping here to make
+        * things clearer.
+        */
+
+       switch (sn_irq_info->irq_int_bit) {
+       case CE_ADM_INT_PCIE_PORT1_DEV_A_SHFT:
+               force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_A_SHFT;
+               break;
+       case CE_ADM_INT_PCIE_PORT1_DEV_B_SHFT:
+               force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_B_SHFT;
+               break;
+       case CE_ADM_INT_PCIE_PORT1_DEV_C_SHFT:
+               force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_C_SHFT;
+               break;
+       case CE_ADM_INT_PCIE_PORT1_DEV_D_SHFT:
+               force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_D_SHFT;
+               break;
+       case CE_ADM_INT_PCIE_PORT2_DEV_A_SHFT:
+               force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_A_SHFT;
+               break;
+       case CE_ADM_INT_PCIE_PORT2_DEV_B_SHFT:
+               force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_B_SHFT;
+               break;
+       case CE_ADM_INT_PCIE_PORT2_DEV_C_SHFT:
+               force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_C_SHFT;
+               break;
+       case CE_ADM_INT_PCIE_PORT2_DEV_D_SHFT:
+               force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_D_SHFT;
+               break;
+       default:
+               return;
+       }
+       ce_mmr->ce_adm_force_int = force_int_val;
+}
+
+/**
+ * tioce_target_interrupt - implement set_irq_affinity for tioce resident
+ * functions.  Note:  only applies to line interrupts, not MSI's.
+ *
+ * @sn_irq_info: SN IRQ context
+ *
+ * Given an sn_irq_info, set the associated CE device's interrupt destination
+ * register.  Since the interrupt destination registers are on a per-ce-slot
+ * basis, this will retarget line interrupts for all functions downstream of
+ * the slot.
+ */
+static void
+tioce_target_interrupt(struct sn_irq_info *sn_irq_info)
+{
+       struct pcidev_info *pcidev_info;
+       struct tioce_common *ce_common;
+       struct tioce *ce_mmr;
+       int bit;
+
+       pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
+       if (!pcidev_info)
+               return;
+
+       ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info;
+       ce_mmr = (struct tioce *)ce_common->ce_pcibus.bs_base;
+
+       bit = sn_irq_info->irq_int_bit;
+
+       ce_mmr->ce_adm_int_mask |= (1UL << bit);
+       ce_mmr->ce_adm_int_dest[bit] =
+               ((uint64_t)sn_irq_info->irq_irq << INTR_VECTOR_SHFT) |
+                          sn_irq_info->irq_xtalkaddr;
+       ce_mmr->ce_adm_int_mask &= ~(1UL << bit);
+
+       tioce_force_interrupt(sn_irq_info);
+}
+
+/**
+ * tioce_bus_fixup - perform final PCI fixup for a TIO CE bus
+ * @prom_bussoft: Common prom/kernel struct representing the bus
+ *
+ * Replicates the tioce_common pointed to by @prom_bussoft in kernel
+ * space.  Allocates and initializes a kernel-only area for a given CE,
+ * and sets up an irq for handling CE error interrupts.
+ *
+ * On successful setup, returns the kernel version of tioce_common back to
+ * the caller.
+ */
+static void *
+tioce_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller)
+{
+       struct tioce_common *tioce_common;
+
+       /*
+        * Allocate kernel bus soft and copy from prom.
+        */
+
+       tioce_common = kcalloc(1, sizeof(struct tioce_common), GFP_KERNEL);
+       if (!tioce_common)
+               return NULL;
+
+       memcpy(tioce_common, prom_bussoft, sizeof(struct tioce_common));
+       tioce_common->ce_pcibus.bs_base |= __IA64_UNCACHED_OFFSET;
+
+       if (tioce_kern_init(tioce_common) == NULL) {
+               kfree(tioce_common);
+               return NULL;
+       }
+
+       if (request_irq(SGI_PCIASIC_ERROR,
+                       tioce_error_intr_handler,
+                       SA_SHIRQ, "TIOCE error", (void *)tioce_common))
+               printk(KERN_WARNING
+                      "%s:  Unable to get irq %d.  "
+                      "Error interrupts won't be routed for "
+                      "TIOCE bus %04x:%02x\n",
+                      __FUNCTION__, SGI_PCIASIC_ERROR,
+                      tioce_common->ce_pcibus.bs_persist_segment,
+                      tioce_common->ce_pcibus.bs_persist_busnum);
+
+       return tioce_common;
+}
+
+static struct sn_pcibus_provider tioce_pci_interfaces = {
+       .dma_map = tioce_dma,
+       .dma_map_consistent = tioce_dma_consistent,
+       .dma_unmap = tioce_dma_unmap,
+       .bus_fixup = tioce_bus_fixup,
+       .force_interrupt = tioce_force_interrupt,
+       .target_interrupt = tioce_target_interrupt
+};
+
+/**
+ * tioce_init_provider - init SN PCI provider ops for TIO CE
+ */
+int
+tioce_init_provider(void)
+{
+       sn_pci_provider[PCIIO_ASIC_TYPE_TIOCE] = &tioce_pci_interfaces;
+       return 0;
+}
index 5aef7e406ef5f2a0a74e90a334ee4a5ad2817ffd..71763f7a1d1989eb0cda8196694e07043a47ce52 100644 (file)
@@ -341,13 +341,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
        /* Set up the stack frame */
        setup_rt_frame(sig, ka, info, oldset, regs);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
index 8a2b77bc5749b50b01a45ef3c81b6d2c8870fc05..539c562cd54de57b04eb45f59ea5bea9fc3f0012 100644 (file)
@@ -171,10 +171,7 @@ int do_settimeofday(struct timespec *tv)
        set_normalized_timespec(&xtime, sec, nsec);
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
 
@@ -221,7 +218,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
         * called as close as possible to 500 ms before the new second starts.
         */
        write_seqlock(&xtime_lock);
-       if ((time_status & STA_UNSYNC) == 0
+       if (ntp_synced()
                && xtime.tv_sec > last_rtc_update + 660
                && (xtime.tv_nsec / 1000) >= 500000 - ((unsigned)TICK_SIZE) / 2
                && (xtime.tv_nsec / 1000) <= 500000 + ((unsigned)TICK_SIZE) / 2)
index 178c4a3fbb72c22229edeec9be348c6899a7bd95..ba960bbc8e6d41124dd9b706ce92f1d27be7b832 100644 (file)
@@ -25,6 +25,11 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default y
 
+config ARCH_MAY_HAVE_PC_FDC
+       bool
+       depends on Q40 || (BROKEN && SUN3X)
+       default y
+
 mainmenu "Linux/68k Kernel Configuration"
 
 source "init/Kconfig"
index c6b2a410bf9abaea143de4e52376dcf06d840909..eb63ca6ed94c591668bbc94c6861571e36da13f6 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/fcntl.h>
 #include <linux/init.h>
 #include <linux/poll.h>
+#include <linux/module.h>
 #include <linux/mc146818rtc.h> /* For struct rtc_time and ioctls, etc */
 #include <linux/smp_lock.h>
 #include <asm/bvme6000hw.h>
@@ -171,7 +172,7 @@ static struct miscdevice rtc_dev = {
        .fops =         &rtc_fops
 };
 
-int __init rtc_DP8570A_init(void)
+static int __init rtc_DP8570A_init(void)
 {
        if (!MACH_IS_BVME6000)
                return -ENODEV;
@@ -179,4 +180,4 @@ int __init rtc_DP8570A_init(void)
        printk(KERN_INFO "DP8570A Real Time Clock Driver v%s\n", RTC_VERSION);
        return misc_register(&rtc_dev);
 }
-
+module_init(rtc_DP8570A_init);
index fe837e31afbf39eeb1208a8488a066e1c90febaf..73e2f5e168ddd17706a22333303e3e6c486e872b 100644 (file)
@@ -74,10 +74,6 @@ EXPORT_SYMBOL(vme_brdtype);
 EXPORT_SYMBOL(__ashldi3);
 EXPORT_SYMBOL(__ashrdi3);
 EXPORT_SYMBOL(__lshrdi3);
-EXPORT_SYMBOL(memcpy);
-EXPORT_SYMBOL(memset);
-EXPORT_SYMBOL(memcmp);
-EXPORT_SYMBOL(memscan);
 EXPORT_SYMBOL(__muldi3);
 
 EXPORT_SYMBOL(__down_failed);
index f4e1e5eb8e1289a1c37a0dc4eed78568e9fae73b..8ed1b01a6a8742a7d44dad74f96bf11d7e395558 100644 (file)
@@ -95,7 +95,7 @@ static inline int put_reg(struct task_struct *task, int regno,
        if (regno == PT_USP)
                addr = &task->thread.usp;
        else if (regno < sizeof(regoff)/sizeof(regoff[0]))
-               addr = (unsigned long *) (task->thread.esp0 + regoff[regno]);
+               addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
        else
                return -1;
        *addr = data;
@@ -103,48 +103,56 @@ static inline int put_reg(struct task_struct *task, int regno,
 }
 
 /*
- * Called by kernel/ptrace.c when detaching..
- *
  * Make sure the single step bit is not set.
  */
-void ptrace_disable(struct task_struct *child)
+static inline void singlestep_disable(struct task_struct *child)
 {
-       unsigned long tmp;
-       /* make sure the single step bit is not set. */
-       tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
+       unsigned long tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
        put_reg(child, PT_SR, tmp);
        child->thread.work.delayed_trace = 0;
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       singlestep_disable(child);
        child->thread.work.syscall_trace = 0;
 }
 
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
        struct task_struct *child;
-       int ret;
+       unsigned long tmp;
+       int i, ret = 0;
 
        lock_kernel();
-       ret = -EPERM;
        if (request == PTRACE_TRACEME) {
                /* are we already being traced? */
-               if (current->ptrace & PT_PTRACED)
+               if (current->ptrace & PT_PTRACED) {
+                       ret = -EPERM;
                        goto out;
+               }
                /* set the ptrace bit in the process flags. */
                current->ptrace |= PT_PTRACED;
-               ret = 0;
                goto out;
        }
-       ret = -ESRCH;
        read_lock(&tasklist_lock);
        child = find_task_by_pid(pid);
        if (child)
                get_task_struct(child);
        read_unlock(&tasklist_lock);
-       if (!child)
+       if (unlikely(!child)) {
+               ret = -ESRCH;
                goto out;
+       }
 
-       ret = -EPERM;
-       if (pid == 1)           /* you may not mess with init */
+       /* you may not mess with init */
+       if (unlikely(pid == 1)) {
+               ret = -EPERM;
                goto out_tsk;
+       }
 
        if (request == PTRACE_ATTACH) {
                ret = ptrace_attach(child);
@@ -152,227 +160,171 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
        }
 
        ret = ptrace_check_attach(child, request == PTRACE_KILL);
-       if (ret < 0)
+       if (ret)
                goto out_tsk;
 
        switch (request) {
        /* when I and D space are separate, these will need to be fixed. */
-               case PTRACE_PEEKTEXT: /* read word at location addr. */
-               case PTRACE_PEEKDATA: {
-                       unsigned long tmp;
-                       int copied;
-
-                       copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
-                       ret = -EIO;
-                       if (copied != sizeof(tmp))
-                               break;
-                       ret = put_user(tmp,(unsigned long *) data);
-                       break;
-               }
+       case PTRACE_PEEKTEXT:   /* read word at location addr. */
+       case PTRACE_PEEKDATA:
+               i = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+               if (i != sizeof(tmp))
+                       goto out_eio;
+               ret = put_user(tmp, (unsigned long *)data);
+               break;
 
        /* read the word at location addr in the USER area. */
-               case PTRACE_PEEKUSR: {
-                       unsigned long tmp;
-
-                       ret = -EIO;
-                       if ((addr & 3) || addr < 0 ||
-                           addr > sizeof(struct user) - 3)
-                               break;
-
-                       tmp = 0;  /* Default return condition */
-                       addr = addr >> 2; /* temporary hack. */
-                       ret = -EIO;
-                       if (addr < 19) {
-                               tmp = get_reg(child, addr);
-                               if (addr == PT_SR)
-                                       tmp >>= 16;
-                       } else if (addr >= 21 && addr < 49) {
-                               tmp = child->thread.fp[addr - 21];
-#ifdef CONFIG_M68KFPU_EMU
-                               /* Convert internal fpu reg representation
-                                * into long double format
-                                */
-                               if (FPU_IS_EMU && (addr < 45) && !(addr % 3))
-                                       tmp = ((tmp & 0xffff0000) << 15) |
-                                             ((tmp & 0x0000ffff) << 16);
-#endif
-                       } else
-                               break;
-                       ret = put_user(tmp,(unsigned long *) data);
-                       break;
-               }
-
-      /* when I and D space are separate, this will have to be fixed. */
-               case PTRACE_POKETEXT: /* write the word at location addr. */
-               case PTRACE_POKEDATA:
-                       ret = 0;
-                       if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
-                               break;
-                       ret = -EIO;
-                       break;
-
-               case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-                       ret = -EIO;
-                       if ((addr & 3) || addr < 0 ||
-                           addr > sizeof(struct user) - 3)
-                               break;
-
-                       addr = addr >> 2; /* temporary hack. */
-
-                       if (addr == PT_SR) {
-                               data &= SR_MASK;
-                               data <<= 16;
-                               data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
-                       }
-                       if (addr < 19) {
-                               if (put_reg(child, addr, data))
-                                       break;
-                               ret = 0;
-                               break;
-                       }
-                       if (addr >= 21 && addr < 48)
-                       {
-#ifdef CONFIG_M68KFPU_EMU
-                               /* Convert long double format
-                                * into internal fpu reg representation
-                                */
-                               if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) {
-                                       data = (unsigned long)data << 15;
-                                       data = (data & 0xffff0000) |
-                                              ((data & 0x0000ffff) >> 1);
-                               }
-#endif
-                               child->thread.fp[addr - 21] = data;
-                               ret = 0;
-                       }
+       case PTRACE_PEEKUSR:
+               if (addr & 3)
+                       goto out_eio;
+               addr >>= 2;     /* temporary hack. */
+
+               if (addr >= 0 && addr < 19) {
+                       tmp = get_reg(child, addr);
+                       if (addr == PT_SR)
+                               tmp >>= 16;
+               } else if (addr >= 21 && addr < 49) {
+                       tmp = child->thread.fp[addr - 21];
+                       /* Convert internal fpu reg representation
+                        * into long double format
+                        */
+                       if (FPU_IS_EMU && (addr < 45) && !(addr % 3))
+                               tmp = ((tmp & 0xffff0000) << 15) |
+                                     ((tmp & 0x0000ffff) << 16);
+               } else
                        break;
-
-               case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
-               case PTRACE_CONT: { /* restart after signal. */
-                       long tmp;
-
-                       ret = -EIO;
-                       if (!valid_signal(data))
-                               break;
-                       if (request == PTRACE_SYSCALL) {
-                                       child->thread.work.syscall_trace = ~0;
-                       } else {
-                                       child->thread.work.syscall_trace = 0;
+               ret = put_user(tmp, (unsigned long *)data);
+               break;
+
+       /* when I and D space are separate, this will have to be fixed. */
+       case PTRACE_POKETEXT:   /* write the word at location addr. */
+       case PTRACE_POKEDATA:
+               if (access_process_vm(child, addr, &data, sizeof(data), 1) != sizeof(data))
+                       goto out_eio;
+               break;
+
+       case PTRACE_POKEUSR:    /* write the word at location addr in the USER area */
+               if (addr & 3)
+                       goto out_eio;
+               addr >>= 2;     /* temporary hack. */
+
+               if (addr == PT_SR) {
+                       data &= SR_MASK;
+                       data <<= 16;
+                       data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
+               } else if (addr >= 0 && addr < 19) {
+                       if (put_reg(child, addr, data))
+                               goto out_eio;
+               } else if (addr >= 21 && addr < 48) {
+                       /* Convert long double format
+                        * into internal fpu reg representation
+                        */
+                       if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) {
+                               data = (unsigned long)data << 15;
+                               data = (data & 0xffff0000) |
+                                      ((data & 0x0000ffff) >> 1);
                        }
-                       child->exit_code = data;
-                       /* make sure the single step bit is not set. */
-                       tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
-                       put_reg(child, PT_SR, tmp);
-                       child->thread.work.delayed_trace = 0;
-                       wake_up_process(child);
-                       ret = 0;
-                       break;
-               }
-
-/*
- * make the child exit.  Best I can do is send it a sigkill.
- * perhaps it should be put in the status that it wants to
- * exit.
- */
-               case PTRACE_KILL: {
-                       long tmp;
-
-                       ret = 0;
-                       if (child->exit_state == EXIT_ZOMBIE) /* already dead */
-                               break;
-                       child->exit_code = SIGKILL;
-       /* make sure the single step bit is not set. */
-                       tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
-                       put_reg(child, PT_SR, tmp);
-                       child->thread.work.delayed_trace = 0;
-                       wake_up_process(child);
-                       break;
-               }
-
-               case PTRACE_SINGLESTEP: {  /* set the trap flag. */
-                       long tmp;
-
-                       ret = -EIO;
-                       if (!valid_signal(data))
-                               break;
+                       child->thread.fp[addr - 21] = data;
+               } else
+                       goto out_eio;
+               break;
+
+       case PTRACE_SYSCALL:    /* continue and stop at next (return from) syscall */
+       case PTRACE_CONT:       /* restart after signal. */
+               if (!valid_signal(data))
+                       goto out_eio;
+
+               if (request == PTRACE_SYSCALL)
+                       child->thread.work.syscall_trace = ~0;
+               else
                        child->thread.work.syscall_trace = 0;
-                       tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
-                       put_reg(child, PT_SR, tmp);
-                       child->thread.work.delayed_trace = 1;
-
-                       child->exit_code = data;
-       /* give it a chance to run. */
-                       wake_up_process(child);
-                       ret = 0;
-                       break;
-               }
+               child->exit_code = data;
+               singlestep_disable(child);
+               wake_up_process(child);
+               break;
 
-               case PTRACE_DETACH:     /* detach a process that was attached. */
-                       ret = ptrace_detach(child, data);
+       /*
+        * make the child exit.  Best I can do is send it a sigkill.
+        * perhaps it should be put in the status that it wants to
+        * exit.
+        */
+       case PTRACE_KILL:
+               if (child->exit_state == EXIT_ZOMBIE) /* already dead */
                        break;
-
-               case PTRACE_GETREGS: { /* Get all gp regs from the child. */
-                       int i;
-                       unsigned long tmp;
-                       for (i = 0; i < 19; i++) {
-                           tmp = get_reg(child, i);
-                           if (i == PT_SR)
+               child->exit_code = SIGKILL;
+               singlestep_disable(child);
+               wake_up_process(child);
+               break;
+
+       case PTRACE_SINGLESTEP: /* set the trap flag. */
+               if (!valid_signal(data))
+                       goto out_eio;
+
+               child->thread.work.syscall_trace = 0;
+               tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
+               put_reg(child, PT_SR, tmp);
+               child->thread.work.delayed_trace = 1;
+
+               child->exit_code = data;
+               /* give it a chance to run. */
+               wake_up_process(child);
+               break;
+
+       case PTRACE_DETACH:     /* detach a process that was attached. */
+               ret = ptrace_detach(child, data);
+               break;
+
+       case PTRACE_GETREGS:    /* Get all gp regs from the child. */
+               for (i = 0; i < 19; i++) {
+                       tmp = get_reg(child, i);
+                       if (i == PT_SR)
                                tmp >>= 16;
-                           if (put_user(tmp, (unsigned long *) data)) {
-                               ret = -EFAULT;
+                       ret = put_user(tmp, (unsigned long *)data);
+                       if (ret)
                                break;
-                           }
-                           data += sizeof(long);
-                       }
-                       ret = 0;
-                       break;
+                       data += sizeof(long);
                }
+               break;
 
-               case PTRACE_SETREGS: { /* Set all gp regs in the child. */
-                       int i;
-                       unsigned long tmp;
-                       for (i = 0; i < 19; i++) {
-                           if (get_user(tmp, (unsigned long *) data)) {
-                               ret = -EFAULT;
+       case PTRACE_SETREGS:    /* Set all gp regs in the child. */
+               for (i = 0; i < 19; i++) {
+                       ret = get_user(tmp, (unsigned long *)data);
+                       if (ret)
                                break;
-                           }
-                           if (i == PT_SR) {
+                       if (i == PT_SR) {
                                tmp &= SR_MASK;
                                tmp <<= 16;
                                tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
-                           }
-                           put_reg(child, i, tmp);
-                           data += sizeof(long);
                        }
-                       ret = 0;
-                       break;
+                       put_reg(child, i, tmp);
+                       data += sizeof(long);
                }
-
-               case PTRACE_GETFPREGS: { /* Get the child FPU state. */
-                       ret = 0;
-                       if (copy_to_user((void *)data, &child->thread.fp,
-                                        sizeof(struct user_m68kfp_struct)))
-                               ret = -EFAULT;
-                       break;
-               }
-
-               case PTRACE_SETFPREGS: { /* Set the child FPU state. */
-                       ret = 0;
-                       if (copy_from_user(&child->thread.fp, (void *)data,
-                                          sizeof(struct user_m68kfp_struct)))
-                               ret = -EFAULT;
-                       break;
-               }
-
-               default:
-                       ret = ptrace_request(child, request, addr, data);
-                       break;
+               break;
+
+       case PTRACE_GETFPREGS:  /* Get the child FPU state. */
+               if (copy_to_user((void *)data, &child->thread.fp,
+                                sizeof(struct user_m68kfp_struct)))
+                       ret = -EFAULT;
+               break;
+
+       case PTRACE_SETFPREGS:  /* Set the child FPU state. */
+               if (copy_from_user(&child->thread.fp, (void *)data,
+                                  sizeof(struct user_m68kfp_struct)))
+                       ret = -EFAULT;
+               break;
+
+       default:
+               ret = ptrace_request(child, request, addr, data);
+               break;
        }
 out_tsk:
        put_task_struct(child);
 out:
        unlock_kernel();
        return ret;
+out_eio:
+       ret = -EIO;
+       goto out_tsk;
 }
 
 asmlinkage void syscall_trace(void)
index e47e19588525e47c1fb19edba8ae3621201e6d08..4ec95e3cb8748721ec6b37880d0a87aaf1b55f83 100644 (file)
@@ -166,10 +166,7 @@ int do_settimeofday(struct timespec *tv)
        set_normalized_timespec(&xtime, sec, nsec);
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
        return 0;
index 34b6dbc29c8570a7a5a8e61dc0000b02ba9a0447..ebe51a513817510677db666a4df59a862b7c08d8 100644 (file)
@@ -5,4 +5,4 @@
 EXTRA_AFLAGS := -traditional
 
 lib-y          := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
-                       checksum.o memcmp.o memcpy.o memset.o semaphore.o
+                       checksum.o string.o semaphore.o
diff --git a/arch/m68k/lib/memcmp.c b/arch/m68k/lib/memcmp.c
deleted file mode 100644 (file)
index f4796fe..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#include <linux/types.h>
-
-int memcmp(const void * cs,const void * ct,size_t count)
-{
-  const unsigned char *su1, *su2;
-
-  for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
-    if (*su1 != *su2)
-      return((*su1 < *su2) ? -1 : +1);
-  return(0);
-}
diff --git a/arch/m68k/lib/memcpy.c b/arch/m68k/lib/memcpy.c
deleted file mode 100644 (file)
index 73e1818..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-#include <linux/types.h>
-
-void * memcpy(void * to, const void * from, size_t n)
-{
-  void *xto = to;
-  size_t temp, temp1;
-
-  if (!n)
-    return xto;
-  if ((long) to & 1)
-    {
-      char *cto = to;
-      const char *cfrom = from;
-      *cto++ = *cfrom++;
-      to = cto;
-      from = cfrom;
-      n--;
-    }
-  if (n > 2 && (long) to & 2)
-    {
-      short *sto = to;
-      const short *sfrom = from;
-      *sto++ = *sfrom++;
-      to = sto;
-      from = sfrom;
-      n -= 2;
-    }
-  temp = n >> 2;
-  if (temp)
-    {
-      long *lto = to;
-      const long *lfrom = from;
-
-      __asm__ __volatile__("movel %2,%3\n\t"
-                          "andw  #7,%3\n\t"
-                          "lsrl  #3,%2\n\t"
-                          "negw  %3\n\t"
-                          "jmp   %%pc@(1f,%3:w:2)\n\t"
-                          "4:\t"
-                          "movel %0@+,%1@+\n\t"
-                          "movel %0@+,%1@+\n\t"
-                          "movel %0@+,%1@+\n\t"
-                          "movel %0@+,%1@+\n\t"
-                          "movel %0@+,%1@+\n\t"
-                          "movel %0@+,%1@+\n\t"
-                          "movel %0@+,%1@+\n\t"
-                          "movel %0@+,%1@+\n\t"
-                          "1:\t"
-                          "dbra  %2,4b\n\t"
-                          "clrw  %2\n\t"
-                          "subql #1,%2\n\t"
-                          "jpl   4b\n\t"
-                          : "=a" (lfrom), "=a" (lto), "=d" (temp),
-                          "=&d" (temp1)
-                          : "0" (lfrom), "1" (lto), "2" (temp)
-                          );
-      to = lto;
-      from = lfrom;
-    }
-  if (n & 2)
-    {
-      short *sto = to;
-      const short *sfrom = from;
-      *sto++ = *sfrom++;
-      to = sto;
-      from = sfrom;
-    }
-  if (n & 1)
-    {
-      char *cto = to;
-      const char *cfrom = from;
-      *cto = *cfrom;
-    }
-  return xto;
-}
diff --git a/arch/m68k/lib/memset.c b/arch/m68k/lib/memset.c
deleted file mode 100644 (file)
index d55fdb2..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#include <linux/types.h>
-
-void * memset(void * s, int c, size_t count)
-{
-  void *xs = s;
-  size_t temp, temp1;
-
-  if (!count)
-    return xs;
-  c &= 0xff;
-  c |= c << 8;
-  c |= c << 16;
-  if ((long) s & 1)
-    {
-      char *cs = s;
-      *cs++ = c;
-      s = cs;
-      count--;
-    }
-  if (count > 2 && (long) s & 2)
-    {
-      short *ss = s;
-      *ss++ = c;
-      s = ss;
-      count -= 2;
-    }
-  temp = count >> 2;
-  if (temp)
-    {
-      long *ls = s;
-
-      __asm__ __volatile__("movel %1,%2\n\t"
-                          "andw  #7,%2\n\t"
-                          "lsrl  #3,%1\n\t"
-                          "negw  %2\n\t"
-                          "jmp   %%pc@(2f,%2:w:2)\n\t"
-                          "1:\t"
-                          "movel %3,%0@+\n\t"
-                          "movel %3,%0@+\n\t"
-                          "movel %3,%0@+\n\t"
-                          "movel %3,%0@+\n\t"
-                          "movel %3,%0@+\n\t"
-                          "movel %3,%0@+\n\t"
-                          "movel %3,%0@+\n\t"
-                          "movel %3,%0@+\n\t"
-                          "2:\t"
-                          "dbra  %1,1b\n\t"
-                          "clrw  %1\n\t"
-                          "subql #1,%1\n\t"
-                          "jpl   1b\n\t"
-                          : "=a" (ls), "=d" (temp), "=&d" (temp1)
-                          : "d" (c), "0" (ls), "1" (temp)
-                          );
-      s = ls;
-    }
-  if (count & 2)
-    {
-      short *ss = s;
-      *ss++ = c;
-      s = ss;
-    }
-  if (count & 1)
-    {
-      char *cs = s;
-      *cs = c;
-    }
-  return xs;
-}
diff --git a/arch/m68k/lib/string.c b/arch/m68k/lib/string.c
new file mode 100644 (file)
index 0000000..b92b89e
--- /dev/null
@@ -0,0 +1,237 @@
+
+#include <linux/types.h>
+#include <linux/module.h>
+
+void *memset(void *s, int c, size_t count)
+{
+       void *xs = s;
+       size_t temp, temp1;
+
+       if (!count)
+               return xs;
+       c &= 0xff;
+       c |= c << 8;
+       c |= c << 16;
+       if ((long)s & 1) {
+               char *cs = s;
+               *cs++ = c;
+               s = cs;
+               count--;
+       }
+       if (count > 2 && (long)s & 2) {
+               short *ss = s;
+               *ss++ = c;
+               s = ss;
+               count -= 2;
+       }
+       temp = count >> 2;
+       if (temp) {
+               long *ls = s;
+
+               asm volatile (
+                       "       movel %1,%2\n"
+                       "       andw  #7,%2\n"
+                       "       lsrl  #3,%1\n"
+                       "       negw  %2\n"
+                       "       jmp   %%pc@(2f,%2:w:2)\n"
+                       "1:     movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "2:     dbra  %1,1b\n"
+                       "       clrw  %1\n"
+                       "       subql #1,%1\n"
+                       "       jpl   1b"
+                       : "=a" (ls), "=d" (temp), "=&d" (temp1)
+                       : "d" (c), "0" (ls), "1" (temp));
+               s = ls;
+       }
+       if (count & 2) {
+               short *ss = s;
+               *ss++ = c;
+               s = ss;
+       }
+       if (count & 1) {
+               char *cs = s;
+               *cs = c;
+       }
+       return xs;
+}
+EXPORT_SYMBOL(memset);
+
+void *memcpy(void *to, const void *from, size_t n)
+{
+       void *xto = to;
+       size_t temp, temp1;
+
+       if (!n)
+               return xto;
+       if ((long)to & 1) {
+               char *cto = to;
+               const char *cfrom = from;
+               *cto++ = *cfrom++;
+               to = cto;
+               from = cfrom;
+               n--;
+       }
+       if (n > 2 && (long)to & 2) {
+               short *sto = to;
+               const short *sfrom = from;
+               *sto++ = *sfrom++;
+               to = sto;
+               from = sfrom;
+               n -= 2;
+       }
+       temp = n >> 2;
+       if (temp) {
+               long *lto = to;
+               const long *lfrom = from;
+
+               asm volatile (
+                       "       movel %2,%3\n"
+                       "       andw  #7,%3\n"
+                       "       lsrl  #3,%2\n"
+                       "       negw  %3\n"
+                       "       jmp   %%pc@(1f,%3:w:2)\n"
+                       "4:     movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "1:     dbra  %2,4b\n"
+                       "       clrw  %2\n"
+                       "       subql #1,%2\n"
+                       "       jpl   4b"
+                       : "=a" (lfrom), "=a" (lto), "=d" (temp), "=&d" (temp1)
+                       : "0" (lfrom), "1" (lto), "2" (temp));
+               to = lto;
+               from = lfrom;
+       }
+       if (n & 2) {
+               short *sto = to;
+               const short *sfrom = from;
+               *sto++ = *sfrom++;
+               to = sto;
+               from = sfrom;
+       }
+       if (n & 1) {
+               char *cto = to;
+               const char *cfrom = from;
+               *cto = *cfrom;
+       }
+       return xto;
+}
+EXPORT_SYMBOL(memcpy);
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+       void *xdest = dest;
+       size_t temp;
+
+       if (!n)
+               return xdest;
+
+       if (dest < src) {
+               if ((long)dest & 1) {
+                       char *cdest = dest;
+                       const char *csrc = src;
+                       *cdest++ = *csrc++;
+                       dest = cdest;
+                       src = csrc;
+                       n--;
+               }
+               if (n > 2 && (long)dest & 2) {
+                       short *sdest = dest;
+                       const short *ssrc = src;
+                       *sdest++ = *ssrc++;
+                       dest = sdest;
+                       src = ssrc;
+                       n -= 2;
+               }
+               temp = n >> 2;
+               if (temp) {
+                       long *ldest = dest;
+                       const long *lsrc = src;
+                       temp--;
+                       do
+                               *ldest++ = *lsrc++;
+                       while (temp--);
+                       dest = ldest;
+                       src = lsrc;
+               }
+               if (n & 2) {
+                       short *sdest = dest;
+                       const short *ssrc = src;
+                       *sdest++ = *ssrc++;
+                       dest = sdest;
+                       src = ssrc;
+               }
+               if (n & 1) {
+                       char *cdest = dest;
+                       const char *csrc = src;
+                       *cdest = *csrc;
+               }
+       } else {
+               dest = (char *)dest + n;
+               src = (const char *)src + n;
+               if ((long)dest & 1) {
+                       char *cdest = dest;
+                       const char *csrc = src;
+                       *--cdest = *--csrc;
+                       dest = cdest;
+                       src = csrc;
+                       n--;
+               }
+               if (n > 2 && (long)dest & 2) {
+                       short *sdest = dest;
+                       const short *ssrc = src;
+                       *--sdest = *--ssrc;
+                       dest = sdest;
+                       src = ssrc;
+                       n -= 2;
+               }
+               temp = n >> 2;
+               if (temp) {
+                       long *ldest = dest;
+                       const long *lsrc = src;
+                       temp--;
+                       do
+                               *--ldest = *--lsrc;
+                       while (temp--);
+                       dest = ldest;
+                       src = lsrc;
+               }
+               if (n & 2) {
+                       short *sdest = dest;
+                       const short *ssrc = src;
+                       *--sdest = *--ssrc;
+                       dest = sdest;
+                       src = ssrc;
+               }
+               if (n & 1) {
+                       char *cdest = dest;
+                       const char *csrc = src;
+                       *--cdest = *--csrc;
+               }
+       }
+       return xdest;
+}
+EXPORT_SYMBOL(memmove);
+
+int memcmp(const void *cs, const void *ct, size_t count)
+{
+       const unsigned char *su1, *su2;
+
+       for (su1 = cs, su2 = ct; count > 0; ++su1, ++su2, count--)
+               if (*su1 != *su2)
+                       return *su1 < *su2 ? -1 : +1;
+       return 0;
+}
+EXPORT_SYMBOL(memcmp);
index 90f1c735c110d60b2fa6732d87a3d999ac9bd6d3..5eaa43c4cb3c81c02317ad162c5404ad76f96b81 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the linux m68k-specific parts of the memory manager.
 #
 
-obj-y          := init.o fault.o hwtest.o
+obj-y          := cache.o init.o fault.o hwtest.o
 
 obj-$(CONFIG_MMU_MOTOROLA)     += kmap.o memory.o motorola.o
 obj-$(CONFIG_MMU_SUN3)         += sun3kmap.o sun3mmu.o
diff --git a/arch/m68k/mm/cache.c b/arch/m68k/mm/cache.c
new file mode 100644 (file)
index 0000000..5437fff
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ *  linux/arch/m68k/mm/cache.c
+ *
+ *  Instruction cache handling
+ *
+ *  Copyright (C) 1995  Hamish Macdonald
+ */
+
+#include <linux/module.h>
+#include <asm/pgalloc.h>
+#include <asm/traps.h>
+
+
+static unsigned long virt_to_phys_slow(unsigned long vaddr)
+{
+       if (CPU_IS_060) {
+               unsigned long paddr;
+
+               /* The PLPAR instruction causes an access error if the translation
+                * is not possible. To catch this we use the same exception mechanism
+                * as for user space accesses in <asm/uaccess.h>. */
+               asm volatile (".chip 68060\n"
+                             "1: plpar (%0)\n"
+                             ".chip 68k\n"
+                             "2:\n"
+                             ".section .fixup,\"ax\"\n"
+                             "   .even\n"
+                             "3: sub.l %0,%0\n"
+                             "   jra 2b\n"
+                             ".previous\n"
+                             ".section __ex_table,\"a\"\n"
+                             "   .align 4\n"
+                             "   .long 1b,3b\n"
+                             ".previous"
+                             : "=a" (paddr)
+                             : "0" (vaddr));
+               return paddr;
+       } else if (CPU_IS_040) {
+               unsigned long mmusr;
+
+               asm volatile (".chip 68040\n\t"
+                             "ptestr (%1)\n\t"
+                             "movec %%mmusr, %0\n\t"
+                             ".chip 68k"
+                             : "=r" (mmusr)
+                             : "a" (vaddr));
+
+               if (mmusr & MMU_R_040)
+                       return (mmusr & PAGE_MASK) | (vaddr & ~PAGE_MASK);
+       } else {
+               unsigned short mmusr;
+               unsigned long *descaddr;
+
+               asm volatile ("ptestr %3,%2@,#7,%0\n\t"
+                             "pmove %%psr,%1@"
+                             : "=a&" (descaddr)
+                             : "a" (&mmusr), "a" (vaddr), "d" (get_fs().seg));
+               if (mmusr & (MMU_I|MMU_B|MMU_L))
+                       return 0;
+               descaddr = phys_to_virt((unsigned long)descaddr);
+               switch (mmusr & MMU_NUM) {
+               case 1:
+                       return (*descaddr & 0xfe000000) | (vaddr & 0x01ffffff);
+               case 2:
+                       return (*descaddr & 0xfffc0000) | (vaddr & 0x0003ffff);
+               case 3:
+                       return (*descaddr & PAGE_MASK) | (vaddr & ~PAGE_MASK);
+               }
+       }
+       return 0;
+}
+
+/* Push n pages at kernel virtual address and clear the icache */
+/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
+void flush_icache_range(unsigned long address, unsigned long endaddr)
+{
+
+       if (CPU_IS_040_OR_060) {
+               address &= PAGE_MASK;
+
+               do {
+                       asm volatile ("nop\n\t"
+                                     ".chip 68040\n\t"
+                                     "cpushp %%bc,(%0)\n\t"
+                                     ".chip 68k"
+                                     : : "a" (virt_to_phys_slow(address)));
+                       address += PAGE_SIZE;
+               } while (address < endaddr);
+       } else {
+               unsigned long tmp;
+               asm volatile ("movec %%cacr,%0\n\t"
+                             "orw %1,%0\n\t"
+                             "movec %0,%%cacr"
+                             : "=&d" (tmp)
+                             : "di" (FLUSH_I));
+       }
+}
+EXPORT_SYMBOL(flush_icache_range);
+
+void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
+                            unsigned long addr, int len)
+{
+       if (CPU_IS_040_OR_060) {
+               asm volatile ("nop\n\t"
+                             ".chip 68040\n\t"
+                             "cpushp %%bc,(%0)\n\t"
+                             ".chip 68k"
+                             : : "a" (page_to_phys(page)));
+       } else {
+               unsigned long tmp;
+               asm volatile ("movec %%cacr,%0\n\t"
+                             "orw %1,%0\n\t"
+                             "movec %0,%%cacr"
+                             : "=&d" (tmp)
+                             : "di" (FLUSH_I));
+       }
+}
+
index 1453a6013721f1ac7bed4bf111add6fffe63f51b..559942ce0e1e7bde2773ac90f5150dca5e542e5e 100644 (file)
@@ -354,110 +354,6 @@ void cache_push (unsigned long paddr, int len)
 #endif
 }
 
-static unsigned long virt_to_phys_slow(unsigned long vaddr)
-{
-       if (CPU_IS_060) {
-               mm_segment_t fs = get_fs();
-               unsigned long paddr;
-
-               set_fs(get_ds());
-
-               /* The PLPAR instruction causes an access error if the translation
-                * is not possible. To catch this we use the same exception mechanism
-                * as for user space accesses in <asm/uaccess.h>. */
-               asm volatile (".chip 68060\n"
-                             "1: plpar (%0)\n"
-                             ".chip 68k\n"
-                             "2:\n"
-                             ".section .fixup,\"ax\"\n"
-                             "   .even\n"
-                             "3: sub.l %0,%0\n"
-                             "   jra 2b\n"
-                             ".previous\n"
-                             ".section __ex_table,\"a\"\n"
-                             "   .align 4\n"
-                             "   .long 1b,3b\n"
-                             ".previous"
-                             : "=a" (paddr)
-                             : "0" (vaddr));
-               set_fs(fs);
-               return paddr;
-       } else if (CPU_IS_040) {
-               mm_segment_t fs = get_fs();
-               unsigned long mmusr;
-
-               set_fs(get_ds());
-
-               asm volatile (".chip 68040\n\t"
-                             "ptestr (%1)\n\t"
-                             "movec %%mmusr, %0\n\t"
-                             ".chip 68k"
-                             : "=r" (mmusr)
-                             : "a" (vaddr));
-               set_fs(fs);
-
-               if (mmusr & MMU_R_040)
-                       return (mmusr & PAGE_MASK) | (vaddr & ~PAGE_MASK);
-       } else {
-               unsigned short mmusr;
-               unsigned long *descaddr;
-
-               asm volatile ("ptestr #5,%2@,#7,%0\n\t"
-                             "pmove %%psr,%1@"
-                             : "=a&" (descaddr)
-                             : "a" (&mmusr), "a" (vaddr));
-               if (mmusr & (MMU_I|MMU_B|MMU_L))
-                       return 0;
-               descaddr = phys_to_virt((unsigned long)descaddr);
-               switch (mmusr & MMU_NUM) {
-               case 1:
-                       return (*descaddr & 0xfe000000) | (vaddr & 0x01ffffff);
-               case 2:
-                       return (*descaddr & 0xfffc0000) | (vaddr & 0x0003ffff);
-               case 3:
-                       return (*descaddr & PAGE_MASK) | (vaddr & ~PAGE_MASK);
-               }
-       }
-       return 0;
-}
-
-/* Push n pages at kernel virtual address and clear the icache */
-/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
-void flush_icache_range(unsigned long address, unsigned long endaddr)
-{
-       if (CPU_IS_040_OR_060) {
-               address &= PAGE_MASK;
-
-               if (address >= PAGE_OFFSET && address < (unsigned long)high_memory) {
-                       do {
-                               asm volatile ("nop\n\t"
-                                             ".chip 68040\n\t"
-                                             "cpushp %%bc,(%0)\n\t"
-                                             ".chip 68k"
-                                             : : "a" (virt_to_phys((void *)address)));
-                               address += PAGE_SIZE;
-                       } while (address < endaddr);
-               } else {
-                       do {
-                               asm volatile ("nop\n\t"
-                                             ".chip 68040\n\t"
-                                             "cpushp %%bc,(%0)\n\t"
-                                             ".chip 68k"
-                                             : : "a" (virt_to_phys_slow(address)));
-                               address += PAGE_SIZE;
-                       } while (address < endaddr);
-               }
-       } else {
-               unsigned long tmp;
-               asm volatile ("movec %%cacr,%0\n\t"
-                             "orw %1,%0\n\t"
-                             "movec %0,%%cacr"
-                             : "=&d" (tmp)
-                             : "di" (FLUSH_I));
-       }
-}
-
-
 #ifndef CONFIG_SINGLE_MEMORY_CHUNK
 int mm_end_of_chunk (unsigned long addr, int len)
 {
index 8a2425069088240e0e87031dd1c103108eca5eb7..7977eae50af27c2344bb432844493c1e8a8a2143 100644 (file)
@@ -161,7 +161,7 @@ static struct miscdevice rtc_dev=
        .fops =         &rtc_fops
 };
 
-int __init rtc_MK48T08_init(void)
+static int __init rtc_MK48T08_init(void)
 {
        if (!MACH_IS_MVME16x)
                return -ENODEV;
@@ -169,4 +169,4 @@ int __init rtc_MK48T08_init(void)
        printk(KERN_INFO "MK48T08 Real Time Clock Driver v%s\n", RTC_VERSION);
        return misc_register(&rtc_dev);
 }
-
+module_init(rtc_MK48T08_init);
index 117f183f0b43ce63d52f2f9537a7807b625edc71..8520df9cee6dd8c6cd9464b9d28bd23ee2292c83 100644 (file)
@@ -71,21 +71,31 @@ config M5206e
        help
          Motorola ColdFire 5206e processor support.
 
+config M523x
+       bool "MCF523x"
+       help
+         Freescale Coldfire 5230/1/2/4/5 processor support
+
 config M5249
        bool "MCF5249"
        help
          Motorola ColdFire 5249 processor support.
 
-config M527x
-       bool "MCF527x"
+config M5271
+       bool "MCF5271"
        help
-         Freescale (Motorola) ColdFire 5270/5271/5274/5275 processor support.
+         Freescale (Motorola) ColdFire 5270/5271 processor support.
 
 config M5272
        bool "MCF5272"
        help
          Motorola ColdFire 5272 processor support.
 
+config M5275
+       bool "MCF5275"
+       help
+         Freescale (Motorola) ColdFire 5274/5275 processor support.
+
 config M528x
        bool "MCF528x"
        help
@@ -103,9 +113,14 @@ config M5407
 
 endchoice
 
+config M527x
+       bool
+       depends on (M5271 || M5275)
+       default y
+
 config COLDFIRE
        bool
-       depends on (M5206 || M5206e || M5249 || M527x || M5272 || M528x || M5307 || M5407)
+       depends on (M5206 || M5206e || M523x || M5249 || M527x || M5272 || M528x || M5307 || M5407)
        default y
 
 choice
@@ -183,6 +198,11 @@ config CLOCK_60MHz
        help
          Select a 60MHz CPU clock frequency.
 
+config CLOCK_62_5MHz
+       bool "62.5MHz"
+       help
+         Select a 62.5MHz CPU clock frequency.
+
 config CLOCK_64MHz
        bool "64MHz"
        help
@@ -302,6 +322,12 @@ config ELITE
        help
          Support for the Motorola M5206eLITE board.
 
+config M5235EVB
+       bool "Freescale M5235EVB support"
+       depends on M523x
+       help
+         Support for the Freescale M5235EVB board.
+
 config M5249C3
        bool "Motorola M5249C3 board support"
        depends on M5249
@@ -310,13 +336,13 @@ config M5249C3
 
 config M5271EVB
        bool "Freescale (Motorola) M5271EVB board support"
-       depends on M527x
+       depends on M5271
        help
          Support for the Freescale (Motorola) M5271EVB board.
 
 config M5275EVB
        bool "Freescale (Motorola) M5275EVB board support"
-       depends on M527x
+       depends on M5275
        help
          Support for the Freescale (Motorola) M5275EVB board.
 
@@ -343,6 +369,12 @@ config COBRA5282
        depends on M528x
        help
          Support for the senTec COBRA5282 board.
+         
+config SOM5282EM
+       bool "EMAC.Inc SOM5282EM board support"
+       depends on M528x
+       help
+         Support for the EMAC.Inc SOM5282EM module.  
 
 config ARN5307
        bool "Arnewsh 5307 board support"
@@ -410,6 +442,12 @@ config CPU16B
        help
          Support for the SNEHA CPU16B board.
 
+config MOD5272
+       bool "Netburner MOD-5272 board support"
+       depends on M5272
+       help
+         Support for the Netburner MOD-5272 board.
+
 config ROMFS_FROM_ROM
        bool "  ROMFS image not RAM resident"
        depends on (NETtel || SNAPGEAR)
@@ -430,7 +468,7 @@ config ARNEWSH
 config MOTOROLA
        bool
        default y
-       depends on (M5206eC3 || M5249C3 || M5271EVB || M5272C3 || M5275EVB || M5282EVB || M5307C3 || M5407C3)
+       depends on (M5206eC3 || M5235EVB || M5249C3 || M5271EVB || M5272C3 || M5275EVB || M5282EVB || M5307C3 || M5407C3)
 
 config HW_FEITH
        bool
@@ -441,6 +479,11 @@ config senTec
        bool
        default y
        depends on (COBRA5272 || COBRA5282)
+       
+config EMAC_INC
+       bool
+       default y
+       depends on (SOM5282EM)
 
 config SNEHA
         bool
@@ -455,6 +498,15 @@ config LARGE_ALLOCS
          a lot of RAM, and you need to able to allocate very large
          contiguous chunks. If unsure, say N.
 
+config 4KSTACKS
+       bool "Use 4Kb for kernel stacks instead of 8Kb"
+       default y
+       help
+         If you say Y here the kernel will use a 4Kb stacksize for the
+         kernel stack attached to each process/thread. This facilitates
+         running more threads on a system and also reduces the pressure
+         on the VM subsystem for higher order allocations.
+
 choice
        prompt "RAM size"
        default AUTO
index a254aa9d49986eb2ff03137fa72bd96b99ba6949..7ce5e55b2401e40716faeaaf5fdacbe903cfea2f 100644 (file)
@@ -14,6 +14,7 @@ platform-$(CONFIG_M68VZ328)   := 68VZ328
 platform-$(CONFIG_M68360)      := 68360
 platform-$(CONFIG_M5206)       := 5206
 platform-$(CONFIG_M5206e)      := 5206e
+platform-$(CONFIG_M523x)       := 523x
 platform-$(CONFIG_M5249)       := 5249
 platform-$(CONFIG_M527x)       := 527x
 platform-$(CONFIG_M5272)       := 5272
@@ -29,6 +30,7 @@ board-$(CONFIG_UCQUICC)               := uCquicc
 board-$(CONFIG_DRAGEN2)                := de2
 board-$(CONFIG_ARNEWSH)                := ARNEWSH
 board-$(CONFIG_MOTOROLA)       := MOTOROLA
+board-$(CONFIG_M5235EVB)       := M5235EVB
 board-$(CONFIG_M5271EVB)       := M5271EVB
 board-$(CONFIG_M5275EVB)       := M5275EVB
 board-$(CONFIG_M5282EVB)       := M5282EVB
@@ -39,6 +41,7 @@ board-$(CONFIG_SECUREEDGEMP3) := MP3
 board-$(CONFIG_CLEOPATRA)      := CLEOPATRA
 board-$(CONFIG_senTec)         := senTec
 board-$(CONFIG_SNEHA)          := SNEHA
+board-$(CONFIG_MOD5272)                := MOD5272
 BOARD := $(board-y)
 
 model-$(CONFIG_RAMKERNEL)      := ram
@@ -53,6 +56,7 @@ MODEL := $(model-y)
 #
 cpuclass-$(CONFIG_M5206)       := 5307
 cpuclass-$(CONFIG_M5206e)      := 5307
+cpuclass-$(CONFIG_M523x)       := 5307
 cpuclass-$(CONFIG_M5249)       := 5307
 cpuclass-$(CONFIG_M527x)       := 5307
 cpuclass-$(CONFIG_M5272)       := 5307
@@ -76,6 +80,7 @@ export PLATFORM BOARD MODEL CPUCLASS
 #
 cflags-$(CONFIG_M5206)         := -m5200 -Wa,-S -Wa,-m5200
 cflags-$(CONFIG_M5206e)                := -m5200 -Wa,-S -Wa,-m5200
+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
@@ -109,7 +114,7 @@ libs-y      += arch/m68knommu/lib/
 prepare: include/asm-$(ARCH)/asm-offsets.h
 
 archclean:
-       $(call descend arch/$(ARCH)/boot, subdirclean)
+       $(Q)$(MAKE) $(clean)=arch/m68knommu/boot
 
 include/asm-$(ARCH)/asm-offsets.h: arch/$(ARCH)/kernel/asm-offsets.s \
                                   include/asm include/linux/version.h \
index e4bd31be966a285cdf897369279d96344aa6b44a..87f2d6587c56f56cf757b7ff7df2dc5f4e6291df 100644 (file)
@@ -1,24 +1,48 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.13-uc0
+# Wed Aug 31 15:03:26 2005
 #
+CONFIG_M68KNOMMU=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_CALIBRATE_DELAY=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
 #
-# CONFIG_SYSVIPC is not set
+CONFIG_LOCALVERSION=""
+# CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_SYSCTL is not set
-CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_KOBJECT_UEVENT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=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_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -34,9 +58,11 @@ CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_M68360 is not set
 # CONFIG_M5206 is not set
 # CONFIG_M5206e is not set
+# CONFIG_M523x is not set
 # CONFIG_M5249 is not set
-# CONFIG_M527x is not set
+# CONFIG_M5271 is not set
 CONFIG_M5272=y
+# CONFIG_M5275 is not set
 # CONFIG_M528x is not set
 # CONFIG_M5307 is not set
 # CONFIG_M5407 is not set
@@ -54,6 +80,8 @@ CONFIG_COLDFIRE=y
 # 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
@@ -65,13 +93,19 @@ CONFIG_CLOCK_66MHz=y
 # Platform
 #
 CONFIG_M5272C3=y
+# CONFIG_COBRA5272 is not set
+# CONFIG_CANCam is not set
+# CONFIG_SCALES is not set
 # CONFIG_NETtel is not set
+# CONFIG_CPU16B is not set
+# CONFIG_MOD5272 is not set
 CONFIG_MOTOROLA=y
 # CONFIG_LARGE_ALLOCS is not set
-# CONFIG_RAMAUTO is not set
+CONFIG_4KSTACKS=y
+CONFIG_RAMAUTO=y
 # CONFIG_RAM4MB is not set
 # CONFIG_RAM8MB is not set
-CONFIG_RAM16MB=y
+# CONFIG_RAM16MB is not set
 # CONFIG_RAM32MB is not set
 CONFIG_RAMAUTOBIT=y
 # CONFIG_RAM8BIT is not set
@@ -79,33 +113,117 @@ CONFIG_RAMAUTOBIT=y
 # CONFIG_RAM32BIT is not set
 CONFIG_RAMKERNEL=y
 # CONFIG_ROMKERNEL is not set
-# CONFIG_HIMEMKERNEL is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
 
 #
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
 #
 # CONFIG_PCI is not set
-# CONFIG_HOTPLUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
 
 #
 # Executable file formats
 #
-CONFIG_KCORE_AOUT=y
 CONFIG_BINFMT_FLAT=y
 # CONFIG_BINFMT_ZFLAT is not set
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
 
 #
 # Power management options
 #
 # CONFIG_PM is not set
 
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
 #
 # Memory Technology Devices (MTD)
 #
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
 # CONFIG_MTD_CMDLINE_PARTS is not set
 
@@ -116,35 +234,50 @@ CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
 
 #
 # RAM/ROM/Flash chip drivers
 #
 # CONFIG_MTD_CFI is not set
 # CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 CONFIG_MTD_RAM=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
 
 #
 # Self-contained MTD device drivers
 #
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
 #
-# CONFIG_MTD_DOC1000 is not set
 # CONFIG_MTD_DOC2000 is not set
 # CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
 
 #
 # NAND Flash Device Drivers
@@ -159,21 +292,32 @@ CONFIG_MTD_UCLINUX=y
 #
 # Plug and Play support
 #
-# CONFIG_PNP is not set
 
 #
 # 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
 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_BLK_DEV_BLKMEM is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
 
 #
-# ATA/IDE/MFM/RLL support
+# 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
+
+#
+# ATA/ATAPI/MFM/RLL support
 #
 # CONFIG_IDE is not set
 
@@ -190,249 +334,230 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 #
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
-# I2O device support
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_XFRM_USER is not set
-# CONFIG_IPV6 is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
+# IEEE 1394 (FireWire) support
 #
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
-# QoS and/or fair queueing
+# I2O device support
 #
-# CONFIG_NET_SCHED is not set
 
 #
-# Network testing
+# Network device support
 #
-# CONFIG_NET_PKTGEN is not set
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-# CONFIG_ETHERTAP 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
 
 #
 # Ethernet (1000 Mbit)
 #
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
 CONFIG_PPP=y
 # CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
 # CONFIG_PPP_ASYNC is not set
 # CONFIG_PPP_SYNC_TTY is not set
 # CONFIG_PPP_DEFLATE is not set
 # CONFIG_PPP_BSDCOMP is not set
 # CONFIG_PPPOE is not set
 # CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
-# Wireless LAN (non-hamradio)
+# ISDN subsystem
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_ISDN is not set
 
 #
-# Token Ring devices (depends on LLC=y)
+# Telephony Support
 #
-# CONFIG_SHAPER is not set
+# CONFIG_PHONE is not set
 
 #
-# Wan interfaces
+# Input device support
 #
-# CONFIG_WAN is not set
+# CONFIG_INPUT is not set
 
 #
-# Amateur Radio support
+# Hardware I/O ports
 #
-# CONFIG_HAMRADIO is not set
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
 
 #
-# IrDA (infrared) support
+# Character devices
 #
-# CONFIG_IRDA is not set
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_LEDMAN is not set
+# CONFIG_RESETSWITCH is not set
 
 #
-# ISDN subsystem
+# Serial drivers
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
-# Telephony Support
+# Non-8250 serial port support
 #
-# CONFIG_PHONE is not set
+CONFIG_SERIAL_COLDFIRE=y
+# CONFIG_UNIX98_PTYS is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 
 #
-# Input device support
+# IPMI
 #
-CONFIG_INPUT=y
+# CONFIG_IPMI_HANDLER is not set
 
 #
-# Userland interfaces
+# Watchdog Cards
 #
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
+# 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
 
 #
-# Input I/O drivers
+# Ftape, the floppy tape device driver
 #
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_RAW_DRIVER is not set
 
 #
-# Input Device Drivers
+# TPM devices
 #
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
+# CONFIG_MCF_QSPI is not set
+# CONFIG_M41T11M6 is not set
 
 #
-# Character devices
+# I2C support
 #
-# CONFIG_VT is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_RESETSWITCH is not set
+# CONFIG_I2C is not set
+# CONFIG_I2C_SENSOR is not set
 
 #
-# Serial drivers
+# Dallas's 1-wire bus
 #
-# CONFIG_SERIAL_8250 is not set
+# CONFIG_W1 is not set
 
 #
-# Non-8250 serial port support
+# Hardware Monitoring support
 #
-CONFIG_SERIAL_COLDFIRE=y
-# CONFIG_UNIX98_PTYS is not set
+# CONFIG_HWMON is not set
 
 #
-# I2C support
+# Misc devices
 #
-# CONFIG_I2C is not set
 
 #
-# I2C Hardware Sensors Mainboard support
+# Multimedia devices
 #
+# CONFIG_VIDEO_DEV is not set
 
 #
-# I2C Hardware Sensors Chip support
+# Digital Video Broadcasting Devices
 #
+# CONFIG_DVB is not set
 
 #
-# Mice
+# Graphics support
 #
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_FB is not set
 
 #
-# IPMI
+# SPI support
 #
-# CONFIG_IPMI_HANDLER is not set
+# CONFIG_SPI is not set
 
 #
-# Watchdog Cards
+# Sound
 #
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
+# CONFIG_SOUND is not set
 
 #
-# Ftape, the floppy tape device driver
+# USB support
 #
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
-# Multimedia devices
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+
+#
+# SN Devices
 #
-# CONFIG_VIDEO_DEV is not set
 
 #
 # File systems
 #
 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_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
+CONFIG_MAGIC_ROM_PTR=y
+# CONFIG_INOTIFY is not set
 # CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -445,15 +570,17 @@ CONFIG_ROMFS_FS=y
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
 # Pseudo filesystems
 #
 CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
+CONFIG_SYSFS=y
 # CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
 #
@@ -462,6 +589,7 @@ CONFIG_RAMFS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
@@ -479,12 +607,10 @@ CONFIG_RAMFS=y
 #
 # CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
-# CONFIG_EXPORTFS is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
@@ -494,30 +620,19 @@ CONFIG_RAMFS=y
 CONFIG_MSDOS_PARTITION=y
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-
-#
-# Bluetooth support
+# Native Language Support
 #
-# CONFIG_BT is not set
+# CONFIG_NLS is not set
 
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_FULLDEBUG is not set
-# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_HIGHPROFILE is not set
+# CONFIG_BOOTPARAM is not set
 # CONFIG_DUMPTOFLASH is not set
 # CONFIG_NO_KERNEL_MSG is not set
 # CONFIG_BDM_DISABLE is not set
@@ -525,6 +640,7 @@ CONFIG_MSDOS_PARTITION=y
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -532,7 +648,13 @@ CONFIG_MSDOS_PARTITION=y
 #
 # CONFIG_CRYPTO is not set
 
+#
+# Hardware crypto devices
+#
+
 #
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
 # CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
index 557238596dcb9bd14ad93e8f4c031296885d34db..a220345e9746d063ba2997ab3dc0544651b676e2 100644 (file)
@@ -6,7 +6,7 @@
  *  Copyleft  ()) 2000       James D. Schettine {james@telos-systems.com}
  *  Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
  *  Copyright (C) 1995       Hamish Macdonald
- *  Copyright (C) 2000       Lineo Inc. (www.lineo.com) 
+ *  Copyright (C) 2000       Lineo Inc. (www.lineo.com)
  *  Copyright (C) 2001              Lineo, Inc. <www.lineo.com>
  *
  *  68VZ328 Fixes/support    Evan Stawnyczy <e@lineo.ca>
@@ -23,6 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/fs.h>
 #include <linux/fb.h>
+#include <linux/module.h>
 #include <linux/console.h>
 #include <linux/genhd.h>
 #include <linux/errno.h>
@@ -45,6 +46,9 @@ unsigned long rom_length;
 unsigned long memory_start;
 unsigned long memory_end;
 
+EXPORT_SYMBOL(memory_start);
+EXPORT_SYMBOL(memory_end);
+
 char command_line[COMMAND_LINE_SIZE];
 
 /* setup some dummy routines */
@@ -103,15 +107,21 @@ void (*mach_power_off)( void ) = NULL;
 #if defined(CONFIG_M5206e)
        #define CPU "COLDFIRE(m5206e)"
 #endif
+#if defined(CONFIG_M523x)
+       #define CPU "COLDFIRE(m523x)"
+#endif
 #if defined(CONFIG_M5249)
        #define CPU "COLDFIRE(m5249)"
 #endif
-#if defined(CONFIG_M527x)
-       #define CPU "COLDFIRE(m5270/5271/5274/5275)"
+#if defined(CONFIG_M5271)
+       #define CPU "COLDFIRE(m5270/5271)"
 #endif
 #if defined(CONFIG_M5272)
        #define CPU "COLDFIRE(m5272)"
 #endif
+#if defined(CONFIG_M5275)
+       #define CPU "COLDFIRE(m5274/5275)"
+#endif
 #if defined(CONFIG_M528x)
        #define CPU "COLDFIRE(m5280/5282)"
 #endif
@@ -152,7 +162,7 @@ void setup_arch(char **cmdline_p)
        init_mm.start_code = (unsigned long) &_stext;
        init_mm.end_code = (unsigned long) &_etext;
        init_mm.end_data = (unsigned long) &_edata;
-       init_mm.brk = (unsigned long) 0; 
+       init_mm.brk = (unsigned long) 0;
 
        config_BSP(&command_line[0], sizeof(command_line));
 
@@ -171,7 +181,7 @@ void setup_arch(char **cmdline_p)
 #endif
 #ifdef CONFIG_ELITE
        printk(KERN_INFO "Modified for M5206eLITE by Rob Scott, rscott@mtrob.fdns.net\n");
-#endif  
+#endif
 #ifdef CONFIG_TELOS
        printk(KERN_INFO "Modified for Omnia ToolVox by James D. Schettine, james@telos-systems.com\n");
 #endif
@@ -200,6 +210,9 @@ void setup_arch(char **cmdline_p)
 #ifdef CONFIG_DRAGEN2
        printk(KERN_INFO "DragonEngine II board support by Georges Menie\n");
 #endif
+#ifdef CONFIG_M5235EVB
+       printk(KERN_INFO "Motorola M5235EVB support (C)2005 Syn-tech Systems, Inc. (Jate Sujjavanich)");
+#endif
 
 #ifdef DEBUG
        printk(KERN_DEBUG "KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x "
@@ -223,7 +236,7 @@ void setup_arch(char **cmdline_p)
        saved_command_line[COMMAND_LINE_SIZE-1] = 0;
 
 #ifdef DEBUG
-       if (strlen(*cmdline_p)) 
+       if (strlen(*cmdline_p))
                printk(KERN_DEBUG "Command line: '%s'\n", *cmdline_p);
 #endif
 
index 30dceb59a462078b6c09b3616dee2ef9ca46c75a..43a2726c0d0a4931070a55c1af124650ed872e58 100644 (file)
@@ -732,13 +732,12 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
        if (ka->sa.sa_flags & SA_ONESHOT)
                ka->sa.sa_handler = SIG_DFL;
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
index 5c3ca671627c19fdd82cb71e631801448be616c7..b17c1ecba966e103d36ad2f7108b4c28a16d2b1a 100644 (file)
@@ -68,7 +68,7 @@ static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
         * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
         * called as close as possible to 500 ms before the new second starts.
         */
-       if ((time_status & STA_UNSYNC) == 0 &&
+       if (ntp_synced() &&
            xtime.tv_sec > last_rtc_update + 660 &&
            (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
            (xtime.tv_nsec  / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
@@ -178,10 +178,7 @@ int do_settimeofday(struct timespec *tv)
        set_normalized_timespec(&xtime, sec, nsec);
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
        return 0;
index ad7dc6347f19092ec56f5fdf3a546ccda5a7836d..5bc06846286453e52f83a138244c07e5af1502e5 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/signal.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/a.out.h>
 #include <linux/user.h>
@@ -38,7 +39,7 @@
 #include <asm/machdep.h>
 #include <asm/siginfo.h>
 
-static char *vec_names[] = {
+static char const * const vec_names[] = {
        "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR",
        "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc",
        "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111",
@@ -106,17 +107,20 @@ asmlinkage void buserr_c(struct frame *fp)
 
 int kstack_depth_to_print = 48;
 
-void show_stack(struct task_struct *task, unsigned long *esp)
+void show_stack(struct task_struct *task, unsigned long *stack)
 {
-       unsigned long *stack, *endstack, addr;
+       unsigned long *endstack, addr;
        extern char _start, _etext;
        int i;
 
-       if (esp == NULL)
-               esp = (unsigned long *) &esp;
+       if (!stack) {
+               if (task)
+                       stack = (unsigned long *)task->thread.ksp;
+               else
+                       stack = (unsigned long *)&stack;
+       }
 
-       stack = esp;
-       addr = (unsigned long) esp;
+       addr = (unsigned long) stack;
        endstack = (unsigned long *) PAGE_ALIGN(addr);
 
        printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
@@ -306,6 +310,8 @@ void dump_stack(void)
        show_stack(current, &stack);
 }
 
+EXPORT_SYMBOL(dump_stack);
+
 #ifdef CONFIG_M68KFPU_EMU
 asmlinkage void fpemu_signal(int signal, int code, void *addr)
 {
index 31cb12892da5a58e73ee0fe1a720e84d03964309..47f06787190dfb14491db3cb2c06376471acd6e1 100644 (file)
  */
 #if defined(CONFIG_ELITE)
 #define        RAM_START       0x30020000
-#define        RAM_END         0xe0000
+#define        RAM_LENGTH      0xe0000
 #endif
 
 /*
 #if defined(CONFIG_M5206eC3) || defined(CONFIG_M5249C3) || \
     defined(CONFIG_M5272C3) || defined(CONFIG_M5307C3) || \
     defined(CONFIG_ARN5307) || defined(CONFIG_M5407C3) || \
-    defined(CONFIG_M5271EVB) || defined(CONFIG_M5275EVB)
+    defined(CONFIG_M5271EVB) || defined(CONFIG_M5275EVB) || \
+    defined(CONFIG_M5235EVB)
 #define        RAM_START       0x20000
 #define        RAM_LENGTH      0x3e0000
 #endif
 #define  RAM_LENGTH  0x3f0000
 #endif
 
+
+/*
+ *     The EMAC SoM-5282EM module.
+ */
+#if defined(CONFIG_SOM5282EM)
+#define  RAM_START   0x10000
+#define  RAM_LENGTH  0xff0000
+#endif
+
+
 /*
  *     These flash boot boards use all of ram for operation. Again the
  *     actual memory size is not important here, assume at least 4MiB.
 #endif
 
 /*
- *     Sneha Boards mimimun memmory
+ *     Sneha Boards mimimun memory
  *     The end of RAM will vary depending on how much ram is fitted,
  *     but this isn't important here, we assume at least 4MiB.
  */
 #define        RAM_LENGTH      0x3e0000
 #endif
 
+#if defined(CONFIG_MOD5272)
+#define RAM_START      0x02000000
+#define RAM_LENGTH     0x00800000
+#define RAMVEC_START   0x20000000
+#define RAMVEC_LENGTH  0x00000400
+#endif
 
 #if defined(CONFIG_RAMKERNEL)
 #define        TEXT            ram
diff --git a/arch/m68knommu/platform/523x/config.c b/arch/m68knommu/platform/523x/config.c
new file mode 100644 (file)
index 0000000..22767ce
--- /dev/null
@@ -0,0 +1,82 @@
+/***************************************************************************/
+
+/*
+ *     linux/arch/m68knommu/platform/523x/config.c
+ *
+ *     Sub-architcture dependant initialization code for the Freescale
+ *     523x CPUs.
+ *
+ *     Copyright (C) 1999-2005, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/dma.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfdma.h>
+
+/***************************************************************************/
+
+void coldfire_pit_tick(void);
+void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+unsigned long coldfire_pit_offset(void);
+void coldfire_trap_init(void);
+void coldfire_reset(void);
+
+/***************************************************************************/
+
+/*
+ *     DMA channel base address table.
+ */
+unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
+        MCF_MBAR + MCFDMA_BASE0,
+};
+
+unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+
+/***************************************************************************/
+
+void mcf_disableall(void)
+{
+       *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH)) = 0xffffffff;
+       *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL)) = 0xffffffff;
+}
+
+/***************************************************************************/
+
+void mcf_autovector(unsigned int vec)
+{
+       /* Everything is auto-vectored on the 5272 */
+}
+
+/***************************************************************************/
+
+void config_BSP(char *commandp, int size)
+{
+       mcf_disableall();
+
+#ifdef CONFIG_BOOTPARAM
+       strncpy(commandp, CONFIG_BOOTPARAM_STRING, size);
+       commandp[size-1] = 0;
+#else
+       memset(commandp, 0, size);
+#endif
+
+       mach_sched_init = coldfire_pit_init;
+       mach_tick = coldfire_pit_tick;
+       mach_gettimeoffset = coldfire_pit_offset;
+       mach_trap_init = coldfire_trap_init;
+       mach_reset = coldfire_reset;
+}
+
+/***************************************************************************/
index c7d7a395c4cc871e0d286dc73f0fe164eab0271c..7f4ba837901f6dfa74dd7e4cb2c64ee8f25f2316 100644 (file)
  *     Memory size exceptions for special cases. Some boards may be set
  *     for auto memory sizing, but we can't do it that way for some reason.
  *     For example the 5206eLITE board has static RAM, and auto-detecting
- *     the SDRAM will do you no good at all.
+ *     the SDRAM will do you no good at all. Same goes for the MOD5272.
  */
 #ifdef CONFIG_RAMAUTO
 #if defined(CONFIG_M5206eLITE)
-#define        MEM_SIZE        0x00100000              /* 1MiB default memory */
+#define        MEM_SIZE        0x00100000      /* 1MiB default memory */
+#endif
+#if defined(CONFIG_MOD5272)
+#define MEM_SIZE       0x00800000      /* 8MiB default memory */
 #endif
 #endif /* CONFIG_RAMAUTO */
 
+
 /*
  *     If we don't have a fixed memory size now, then lets build in code
  *     to auto detect the DRAM size. Obviously this is the prefered
 
 /*
  *     Most ColdFire boards have their DRAM starting at address 0.
- *     Notable exception is the 5206eLITE board.
+ *     Notable exception is the 5206eLITE board, another is the MOD5272.
  */
 #if defined(CONFIG_M5206eLITE)
 #define        MEM_BASE        0x30000000
 #endif
+#if defined(CONFIG_MOD5272)
+#define MEM_BASE       0x02000000
+#define VBR_BASE       0x20000000      /* vectors in SRAM */
+#endif
 
 #ifndef MEM_BASE
 #define        MEM_BASE        0x00000000      /* memory base at address 0 */
@@ -188,6 +196,7 @@ _start:
        movel   %a7,_rambase
 
        GET_MEM_SIZE                            /* macro code determines size */
+       addl    %a7,%d0
        movel   %d0,_ramend                     /* set end ram addr */
 
        /*
index 0f5d1fe8eb5fc99bc55e2496826c3129d8d4ca56..7d8990d784a2bf8f54ee63f39a2da0c9c6d752e5 100644 (file)
@@ -79,7 +79,7 @@ ENTRY(system_call)
        movel   %sp@(PT_ORIG_D0),%d0
 
        movel   %sp,%d1                 /* get thread_info pointer */
-       andl    #0xffffe000,%d1
+       andl    #-THREAD_SIZE,%d1
        movel   %d1,%a2
        btst    #TIF_SYSCALL_TRACE,%a2@(TI_FLAGS)
        jne     do_trace
@@ -105,7 +105,7 @@ Luser_return:
        andw    #ALLOWINT,%sr
 
        movel   %sp,%d1                 /* get thread_info pointer */
-       andl    #0xffffe000,%d1
+       andl    #-THREAD_SIZE,%d1
        movel   %d1,%a2
        move    %a2@(TI_FLAGS),%d1      /* thread_info->flags */
        andl    #_TIF_WORK_MASK,%d1
index f7bc80a60e0fe645ea6faa8a4e2cb6ceb5eb48f4..8ff48adf24abec4dbec33f1e8c395ff96ceaed1b 100644 (file)
@@ -96,7 +96,7 @@ Luser_return:
        andw    #ALLOWINT,%sr
 
        movel   %sp,%d1                 /* get thread_info pointer */
-       andl    #0xffffe000,%d1
+       andl    #-THREAD_SIZE,%d1
        movel   %d1,%a2
        move    %a2@(TI_FLAGS),%d1      /* thread_info->flags */
        andl    #_TIF_WORK_MASK,%d1
index 898de2df1fc761c35f67cb223d42e57110b9b45f..8d76eb1ff29169080b025ca5f0a7c153c6e4e72c 100644 (file)
@@ -4,27 +4,52 @@ config MIPS
        # Horrible source of confusion.  Die, die, die ...
        select EMBEDDED
 
-config MIPS64
-       bool "64-bit kernel"
-       help
-         Select this option if you want to build a 64-bit kernel.  You should
-         only select this option if you have hardware that actually has a
-         64-bit processor and if your application will actually benefit from
-         64-bit processing, otherwise say N.  You must say Y for kernels for
-         SGI IP27 (Origin 200 and 2000) and SGI IP32 (O2).  If in doubt say N.
-
-config 64BIT
-       def_bool MIPS64
-
-config MIPS32
+# shouldn't it be per-subarchitecture?
+config ARCH_MAY_HAVE_PC_FDC
        bool
-       depends on MIPS64 = 'n'
        default y
 
 mainmenu "Linux/MIPS Kernel Configuration"
 
 source "init/Kconfig"
 
+config SYS_SUPPORTS_32BIT_KERNEL
+       bool
+config SYS_SUPPORTS_64BIT_KERNEL
+       bool
+config CPU_SUPPORTS_32BIT_KERNEL
+       bool
+config CPU_SUPPORTS_64BIT_KERNEL
+       bool
+
+menu "Kernel type"
+
+choice
+
+       prompt "Kernel code model"
+       help
+         You should only select this option if you have a workload that
+         actually benefits from 64-bit processing or if your machine has
+         large memory.  You will only be presented a single option in this
+         menu if your system does not support both 32-bit and 64-bit kernels.
+
+config 32BIT
+       bool "32-bit kernel"
+       depends on CPU_SUPPORTS_32BIT_KERNEL && SYS_SUPPORTS_32BIT_KERNEL
+       select TRAD_SIGNALS
+       help
+         Select this option if you want to build a 32-bit kernel.
+
+config 64BIT
+       bool "64-bit kernel"
+       depends on CPU_SUPPORTS_64BIT_KERNEL && SYS_SUPPORTS_64BIT_KERNEL
+       help
+         Select this option if you want to build a 64-bit kernel.
+
+endchoice
+
+endmenu
+
 menu "Machine selection"
 
 config MACH_JAZZ
@@ -34,6 +59,8 @@ config MACH_JAZZ
        select GENERIC_ISA_DMA
        select I8259
        select ISA
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
        help
         This a family of machines based on the MIPS R4030 chipset which was
         used by several vendors to build RISC/os and Windows NT workstations.
@@ -71,7 +98,9 @@ config OLIVETTI_M700
          <http://www.linux-mips.org/>.
 
 config MACH_VR41XX
-       bool "Support for NEC VR41XX-based machines"
+       bool "Support for NEC VR4100 series based machines"
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
 
 config NEC_CMBVR4133
        bool "Support for NEC CMB-VR4133"
@@ -80,7 +109,6 @@ config NEC_CMBVR4133
        select DMA_NONCOHERENT
        select IRQ_CPU
        select HW_HAS_PCI
-       select PCI_VR41XX
 
 config ROCKHOPPER
        bool "Support for Rockhopper baseboard"
@@ -91,6 +119,7 @@ config ROCKHOPPER
 config CASIO_E55
        bool "Support for CASIO CASSIOPEIA E-10/15/55/65"
        depends on MACH_VR41XX
+       select CPU_LITTLE_ENDIAN
        select DMA_NONCOHERENT
        select IRQ_CPU
        select ISA
@@ -98,53 +127,54 @@ config CASIO_E55
 config IBM_WORKPAD
        bool "Support for IBM WorkPad z50"
        depends on MACH_VR41XX
+       select CPU_LITTLE_ENDIAN
        select DMA_NONCOHERENT
        select IRQ_CPU
        select ISA
 
-config TANBAC_TB0226
-       bool "Support for TANBAC TB0226 (Mbase)"
+config TANBAC_TB022X
+       bool "Support for TANBAC VR4131 multichip module and TANBAC VR4131DIMM"
        depends on MACH_VR41XX
+       select CPU_LITTLE_ENDIAN
        select DMA_NONCOHERENT
-       select HW_HAS_PCI
        select IRQ_CPU
+       select HW_HAS_PCI
        help
-         The TANBAC TB0226 (Mbase) is a MIPS-based platform manufactured by TANBAC.
-         Please refer to <http://www.tanbac.co.jp/> about Mbase.
+         The TANBAC VR4131 multichip module(TB0225) and
+         the TANBAC VR4131DIMM(TB0229) are MIPS-based platforms
+         manufactured by TANBAC.
+         Please refer to <http://www.tanbac.co.jp/>
+         about VR4131 multichip module and VR4131DIMM.
 
-config TANBAC_TB0229
-       bool "Support for TANBAC TB0229 (VR4131DIMM)"
-       depends on MACH_VR41XX
-       select DMA_NONCOHERENT
-       select HW_HAS_PCI
-       select IRQ_CPU
+config TANBAC_TB0226
+       bool "Support for TANBAC Mbase(TB0226)"
+       depends on TANBAC_TB022X
+       select GPIO_VR41XX
        help
-         The TANBAC TB0229 (VR4131DIMM) is a MIPS-based platform manufactured by TANBAC.
-         Please refer to <http://www.tanbac.co.jp/> about VR4131DIMM.
+         The TANBAC Mbase(TB0226) is a MIPS-based platform manufactured by TANBAC.
+         Please refer to <http://www.tanbac.co.jp/> about Mbase.
 
 config VICTOR_MPC30X
        bool "Support for Victor MP-C303/304"
+       depends on MACH_VR41XX
+       select CPU_LITTLE_ENDIAN
        select DMA_NONCOHERENT
-       select HW_HAS_PCI
        select IRQ_CPU
-       depends on MACH_VR41XX
+       select HW_HAS_PCI
 
 config ZAO_CAPCELLA
        bool "Support for ZAO Networks Capcella"
        depends on MACH_VR41XX
+       select CPU_LITTLE_ENDIAN
        select DMA_NONCOHERENT
-       select HW_HAS_PCI
        select IRQ_CPU
+       select HW_HAS_PCI
 
 config PCI_VR41XX
        bool "Add PCI control unit support of NEC VR4100 series"
-       depends on MACH_VR41XX && PCI
-
-config VRC4171
-       tristate "Add NEC VRC4171 companion chip support"
-       depends on MACH_VR41XX && ISA
-       ---help---
-         The NEC VRC4171/4171A is a companion chip for NEC VR4111/VR4121.
+       depends on MACH_VR41XX && HW_HAS_PCI
+       default y
+       select PCI
 
 config VRC4173
        tristate "Add NEC VRC4173 companion chip support"
@@ -154,25 +184,28 @@ config VRC4173
 
 config TOSHIBA_JMR3927
        bool "Support for Toshiba JMR-TX3927 board"
-       depends on MIPS32
        select DMA_NONCOHERENT
        select HW_HAS_PCI
        select SWAP_IO_SPACE
+       select SYS_SUPPORTS_32BIT_KERNEL
 
 config MIPS_COBALT
-       bool "Support for Cobalt Server (EXPERIMENTAL)"
+       bool "Support for Cobalt Server"
        depends on EXPERIMENTAL
        select DMA_NONCOHERENT
        select HW_HAS_PCI
        select I8259
        select IRQ_CPU
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
 
 config MACH_DECSTATION
        bool "Support for DECstations"
        select BOOT_ELF32
        select DMA_NONCOHERENT
        select IRQ_CPU
-       depends on MIPS32 || EXPERIMENTAL
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
        ---help---
          This enables support for DEC's MIPS based workstations.  For details
          see the Linux/MIPS FAQ on <http://www.linux-mips.org/> and the
@@ -194,6 +227,8 @@ config MIPS_EV64120
        select DMA_NONCOHERENT
        select HW_HAS_PCI
        select MIPS_GT64120
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
        help
          This is an evaluation board based on the Galileo GT-64120
          single-chip system controller that contains a MIPS R5000 compatible
@@ -214,6 +249,8 @@ config MIPS_EV96100
        select MIPS_GT96100
        select RM7000_CPU_SCACHE
        select SWAP_IO_SPACE
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
        help
          This is an evaluation board based on the Galileo GT-96100 LAN/WAN
          communications controllers containing a MIPS R5000 compatible core
@@ -224,6 +261,8 @@ config MIPS_IVR
        bool "Support for Globespan IVR board"
        select DMA_NONCOHERENT
        select HW_HAS_PCI
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
        help
          This is an evaluation board built by Globespan to showcase thir
          iVR (Internet Video Recorder) design. It utilizes a QED RM5231
@@ -237,6 +276,8 @@ config LASAT
        select HW_HAS_PCI
        select MIPS_GT64120
        select R5000_CPU_SCACHE
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
 
 config PICVUE
        tristate "PICVUE LCD display driver"
@@ -258,6 +299,8 @@ config MIPS_ITE8172
        bool "Support for ITE 8172G board"
        select DMA_NONCOHERENT
        select HW_HAS_PCI
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
        help
          Ths is an evaluation board made by ITE <http://www.ite.com.tw/>
          with ATX form factor that utilizes a MIPS R5000 to work with its
@@ -281,6 +324,8 @@ config MIPS_ATLAS
        select HW_HAS_PCI
        select MIPS_GT64120
        select SWAP_IO_SPACE
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
        help
          This enables support for the QED R5231-based MIPS Atlas evaluation
          board.
@@ -295,6 +340,8 @@ config MIPS_MALTA
        select I8259
        select MIPS_GT64120
        select SWAP_IO_SPACE
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
        help
          This enables support for the VR5000-based MIPS Malta evaluation
          board.
@@ -304,6 +351,8 @@ config MIPS_SEAD
        depends on EXPERIMENTAL
        select IRQ_CPU
        select DMA_NONCOHERENT
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
 
 config MOMENCO_OCELOT
        bool "Support for Momentum Ocelot board"
@@ -314,6 +363,8 @@ config MOMENCO_OCELOT
        select MIPS_GT64120
        select RM7000_CPU_SCACHE
        select SWAP_IO_SPACE
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
        help
          The Ocelot is a MIPS-based Single Board Computer (SBC) made by
          Momentum Computer <http://www.momenco.com/>.
@@ -327,6 +378,8 @@ config MOMENCO_OCELOT_G
        select PCI_MARVELL
        select RM7000_CPU_SCACHE
        select SWAP_IO_SPACE
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
        help
          The Ocelot is a MIPS-based Single Board Computer (SBC) made by
          Momentum Computer <http://www.momenco.com/>.
@@ -340,6 +393,8 @@ config MOMENCO_OCELOT_C
        select PCI_MARVELL
        select RM7000_CPU_SCACHE
        select SWAP_IO_SPACE
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
        help
          The Ocelot is a MIPS-based Single Board Computer (SBC) made by
          Momentum Computer <http://www.momenco.com/>.
@@ -355,6 +410,8 @@ config MOMENCO_OCELOT_3
        select PCI_MARVELL
        select RM7000_CPU_SCACHE
        select SWAP_IO_SPACE
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
        help
          The Ocelot-3 is based off Discovery III System Controller and
          PMC-Sierra Rm79000 core.
@@ -371,6 +428,8 @@ config MOMENCO_JAGUAR_ATX
        select PCI_MARVELL
        select RM7000_CPU_SCACHE
        select SWAP_IO_SPACE
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
        help
          The Jaguar ATX is a MIPS-based Single Board Computer (SBC) made by
          Momentum Computer <http://www.momenco.com/>.
@@ -390,6 +449,8 @@ config PMC_YOSEMITE
        select IRQ_CPU_RM7K
        select IRQ_CPU_RM9K
        select SWAP_IO_SPACE
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
        help
          Yosemite is an evaluation board for the RM9000x2 processor
          manufactured by PMC-Sierra
@@ -407,6 +468,8 @@ config DDB5074
        select IRQ_CPU
        select I8259
        select ISA
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
        help
          This enables support for the VR5000-based NEC DDB Vrc-5074
          evaluation board.
@@ -419,6 +482,8 @@ config DDB5476
        select IRQ_CPU
        select I8259
        select ISA
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
        help
          This enables support for the R5432-based NEC DDB Vrc-5476
          evaluation board.
@@ -433,6 +498,8 @@ config DDB5477
        select HW_HAS_PCI
        select I8259
        select IRQ_CPU
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
        help
          This enables support for the R5432-based NEC DDB Vrc-5477,
          or Rockhopper/SolutionGear boards with R5432/R5500 CPUs.
@@ -445,10 +512,23 @@ config DDB5477_BUS_FREQUENCY
        depends on DDB5477
        default 0
 
-config NEC_OSPREY
-       bool "Support for NEC Osprey board"
-       select DMA_NONCOHERENT
-       select IRQ_CPU
+config QEMU
+       bool "Support for Qemu"
+       select DMA_COHERENT
+       select GENERIC_ISA_DMA
+       select HAVE_STD_PC_SERIAL_PORT
+       select I8259
+       select ISA
+       select SWAP_IO_SPACE
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_BIG_ENDIAN
+       help
+        Qemu is a software emulator which among other architectures also
+        can simulate a MIPS32 4Kc system.  This patch adds support for the
+        system architecture that currently is being simulated by Qemu.  It
+        will eventually be removed again when Qemu has the capability to
+        simulate actual MIPS hardware platforms.  More information on Qemu
+        can be found at http://www.linux-mips.org/wiki/Qemu.
 
 config SGI_IP22
        bool "Support for SGI IP22 (Indy/Indigo2)"
@@ -459,6 +539,8 @@ config SGI_IP22
        select IP22_CPU_SCACHE
        select IRQ_CPU
        select SWAP_IO_SPACE
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
        help
          This are the SGI Indy, Challenge S and Indigo2, as well as certain
          OEM variants like the Tandem CMN B006S. To compile a Linux kernel
@@ -466,12 +548,12 @@ config SGI_IP22
 
 config SGI_IP27
        bool "Support for SGI IP27 (Origin200/2000)"
-       depends on MIPS64
        select ARC
        select ARC64
        select DMA_IP27
        select HW_HAS_PCI
        select PCI_DOMAINS
+       select SYS_SUPPORTS_64BIT_KERNEL
        help
          This are the SGI Origin 200, Origin 2000 and Onyx 2 Graphics
          workstations.  To compile a Linux kernel that runs on these, say Y
@@ -534,7 +616,7 @@ config REPLICATE_EXHANDLERS
 
 config SGI_IP32
        bool "Support for SGI IP32 (O2) (EXPERIMENTAL)"
-       depends on MIPS64 && EXPERIMENTAL
+       depends on EXPERIMENTAL
        select ARC
        select ARC32
        select BOOT_ELF32
@@ -544,12 +626,13 @@ config SGI_IP32
        select HW_HAS_PCI
        select R5000_CPU_SCACHE
        select RM7000_CPU_SCACHE
+       select SYS_SUPPORTS_64BIT_KERNEL
        help
          If you want this kernel to run on SGI O2 workstation, say Y here.
 
 config SOC_AU1X00
-       depends on MIPS32
        bool "Support for AMD/Alchemy Au1X00 SOCs"
+       select SYS_SUPPORTS_32BIT_KERNEL
 
 choice
        prompt "Au1X00 SOC Type"
@@ -661,6 +744,8 @@ config SIBYTE_SB1xxx_SOC
        select BOOT_ELF32
        select DMA_COHERENT
        select SWAP_IO_SPACE
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
 
 choice
        prompt "BCM1xxx SOC-based board"
@@ -880,6 +965,8 @@ config SNI_RM200_PCI
        select HW_HAS_PCI
        select I8259
        select ISA
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
        help
          The SNI RM200 PCI was a MIPS-based platform manufactured by Siemens
          Nixdorf Informationssysteme (SNI), parent company of Pyramid
@@ -888,13 +975,14 @@ config SNI_RM200_PCI
 
 config TOSHIBA_RBTX4927
        bool "Support for Toshiba TBTX49[23]7 board"
-       depends on MIPS32
        select DMA_NONCOHERENT
        select HAS_TXX9_SERIAL
        select HW_HAS_PCI
        select I8259
        select ISA
        select SWAP_IO_SPACE
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
        help
          This Toshiba board is based on the TX4927 processor. Say Y here to
          support this machine type
@@ -926,13 +1014,21 @@ config ARC
        depends on SNI_RM200_PCI || SGI_IP32 || SGI_IP27 || SGI_IP22 || MIPS_MAGNUM_4000 || OLIVETTI_M700 || ACER_PICA_61
        default y
 
-config DMA_COHERENT
+config DMA_COHERENT
+       bool
+
+config DMA_IP27
        bool
 
-config DMA_IP27
+config DMA_IP32
        bool
+       select DMA_NEED_PCI_MAP_STATE
 
-config DMA_NONCOHERENT
+config DMA_NONCOHERENT
+       bool
+       select DMA_NEED_PCI_MAP_STATE
+
+config DMA_NEED_PCI_MAP_STATE
        bool
 
 config EARLY_PRINTK
@@ -974,7 +1070,7 @@ config MIPS_DISABLE_OBSOLETE_IDE
 
 config CPU_LITTLE_ENDIAN
        bool "Generate little endian code"
-       default y if ACER_PICA_61 || CASIO_E55 || DDB5074 || DDB5476 || DDB5477 || MACH_DECSTATION || IBM_WORKPAD || LASAT || MIPS_COBALT || MIPS_ITE8172 || MIPS_IVR || SOC_AU1X00 || NEC_OSPREY || OLIVETTI_M700 || SNI_RM200_PCI || VICTOR_MPC30X || ZAO_CAPCELLA
+       default y if ACER_PICA_61 || CASIO_E55 || DDB5074 || DDB5476 || DDB5477 || MACH_DECSTATION || IBM_WORKPAD || LASAT || MIPS_COBALT || MIPS_ITE8172 || MIPS_IVR || SOC_AU1X00 || OLIVETTI_M700 || SNI_RM200_PCI || VICTOR_MPC30X || ZAO_CAPCELLA
        default n if MIPS_EV64120 || MIPS_EV96100 || MOMENCO_OCELOT || MOMENCO_OCELOT_G || SGI_IP22 || SGI_IP27 || SGI_IP32 || TOSHIBA_JMR3927
        help
          Some MIPS machines can be configured for either little or big endian
@@ -1091,11 +1187,6 @@ config ARC32
 config HAVE_STD_PC_SERIAL_PORT
        bool
 
-config VR4181
-       bool
-       depends on NEC_OSPREY
-       default y
-
 config ARC_CONSOLE
        bool "ARC console support"
        depends on SGI_IP22 || SNI_RM200_PCI
@@ -1145,13 +1236,16 @@ choice
 
 config CPU_MIPS32
        bool "MIPS32"
+       select CPU_SUPPORTS_32BIT_KERNEL
 
 config CPU_MIPS64
        bool "MIPS64"
+       select CPU_SUPPORTS_32BIT_KERNEL
+       select CPU_SUPPORTS_64BIT_KERNEL
 
 config CPU_R3000
        bool "R3000"
-       depends on MIPS32
+       select CPU_SUPPORTS_32BIT_KERNEL
        help
          Please make sure to pick the right CPU type. Linux/MIPS is not
          designed to be generic, i.e. Kernels compiled for R3000 CPUs will
@@ -1162,10 +1256,12 @@ config CPU_R3000
 
 config CPU_TX39XX
        bool "R39XX"
-       depends on MIPS32
+       select CPU_SUPPORTS_32BIT_KERNEL
 
 config CPU_VR41XX
        bool "R41xx"
+       select CPU_SUPPORTS_32BIT_KERNEL
+       select CPU_SUPPORTS_64BIT_KERNEL
        help
          The options selects support for the NEC VR41xx series of processors.
          Only choose this option if you have one of these processors as a
@@ -1174,20 +1270,28 @@ config CPU_VR41XX
 
 config CPU_R4300
        bool "R4300"
+       select CPU_SUPPORTS_32BIT_KERNEL
+       select CPU_SUPPORTS_64BIT_KERNEL
        help
          MIPS Technologies R4300-series processors.
 
 config CPU_R4X00
        bool "R4x00"
+       select CPU_SUPPORTS_32BIT_KERNEL
+       select CPU_SUPPORTS_64BIT_KERNEL
        help
          MIPS Technologies R4000-series processors other than 4300, including
          the R4000, R4400, R4600, and 4700.
 
 config CPU_TX49XX
        bool "R49XX"
+       select CPU_SUPPORTS_32BIT_KERNEL
+       select CPU_SUPPORTS_64BIT_KERNEL
 
 config CPU_R5000
        bool "R5000"
+       select CPU_SUPPORTS_32BIT_KERNEL
+       select CPU_SUPPORTS_64BIT_KERNEL
        help
          MIPS Technologies R5000-series processors other than the Nevada.
 
@@ -1196,36 +1300,48 @@ config CPU_R5432
 
 config CPU_R6000
        bool "R6000"
-       depends on MIPS32 && EXPERIMENTAL
+       depends on EXPERIMENTAL
+       select CPU_SUPPORTS_32BIT_KERNEL
        help
          MIPS Technologies R6000 and R6000A series processors.  Note these
          processors are extremly rare and the support for them is incomplete.
 
 config CPU_NEVADA
        bool "RM52xx"
+       select CPU_SUPPORTS_32BIT_KERNEL
+       select CPU_SUPPORTS_64BIT_KERNEL
        help
          QED / PMC-Sierra RM52xx-series ("Nevada") processors.
 
 config CPU_R8000
        bool "R8000"
-       depends on MIPS64 && EXPERIMENTAL
+       depends on EXPERIMENTAL
+       select CPU_SUPPORTS_64BIT_KERNEL
        help
          MIPS Technologies R8000 processors.  Note these processors are
          uncommon and the support for them is incomplete.
 
 config CPU_R10000
        bool "R10000"
+       select CPU_SUPPORTS_32BIT_KERNEL
+       select CPU_SUPPORTS_64BIT_KERNEL
        help
          MIPS Technologies R10000-series processors.
 
 config CPU_RM7000
        bool "RM7000"
+       select CPU_SUPPORTS_32BIT_KERNEL
+       select CPU_SUPPORTS_64BIT_KERNEL
 
 config CPU_RM9000
        bool "RM9000"
+       select CPU_SUPPORTS_32BIT_KERNEL
+       select CPU_SUPPORTS_64BIT_KERNEL
 
 config CPU_SB1
        bool "SB1"
+       select CPU_SUPPORTS_32BIT_KERNEL
+       select CPU_SUPPORTS_64BIT_KERNEL
 
 endchoice
 
@@ -1321,11 +1437,11 @@ config SB1_PASS_2_1_WORKAROUNDS
 
 config 64BIT_PHYS_ADDR
        bool "Support for 64-bit physical address space"
-       depends on (CPU_R4X00 || CPU_R5000 || CPU_RM7000 || CPU_RM9000 || CPU_R10000 || CPU_SB1 || CPU_MIPS32 || CPU_MIPS64) && MIPS32
+       depends on (CPU_R4X00 || CPU_R5000 || CPU_RM7000 || CPU_RM9000 || CPU_R10000 || CPU_SB1 || CPU_MIPS32 || CPU_MIPS64) && 32BIT
 
 config CPU_ADVANCED
        bool "Override CPU Options"
-       depends on MIPS32
+       depends on 32BIT
        help
          Saying yes here allows you to select support for various features
          your CPU may or may not have.  Most people should say N here.
@@ -1379,7 +1495,7 @@ config CPU_HAS_SYNC
 #
 config HIGHMEM
        bool "High Memory Support"
-       depends on MIPS32 && (CPU_R3000 || CPU_SB1 || CPU_R7000 || CPU_RM9000 || CPU_R10000) && !(MACH_DECSTATION || MOMENCO_JAGUAR_ATX)
+       depends on 32BIT && (CPU_R3000 || CPU_SB1 || CPU_R7000 || CPU_RM9000 || CPU_R10000) && !(MACH_DECSTATION || MOMENCO_JAGUAR_ATX)
 
 config ARCH_FLATMEM_ENABLE
        def_bool y
@@ -1439,7 +1555,7 @@ config RTC_DS1742
 
 config MIPS_INSANE_LARGE
        bool "Support for large 64-bit configurations"
-       depends on CPU_R10000 && MIPS64
+       depends on CPU_R10000 && 64BIT
        help
          MIPS R10000 does support a 44 bit / 16TB address space as opposed to
          previous 64-bit processors which only supported 40 bit / 1TB. If you
@@ -1540,11 +1656,11 @@ source "fs/Kconfig.binfmt"
 
 config TRAD_SIGNALS
        bool
-       default y if MIPS32
+       default y if 32BIT
 
 config BUILD_ELF64
        bool "Use 64-bit ELF format for building"
-       depends on MIPS64
+       depends on 64BIT
        help
          A 64-bit kernel is usually built using the 64-bit ELF binary object
          format as it's one that allows arbitrary 64-bit constructs.  For
@@ -1559,11 +1675,11 @@ config BUILD_ELF64
 
 config BINFMT_IRIX
        bool "Include IRIX binary compatibility"
-       depends on !CPU_LITTLE_ENDIAN && MIPS32 && BROKEN
+       depends on !CPU_LITTLE_ENDIAN && 32BIT && BROKEN
 
 config MIPS32_COMPAT
        bool "Kernel support for Linux/MIPS 32-bit binary compatibility"
-       depends on MIPS64
+       depends on 64BIT
        help
          Select this option if you want Linux/MIPS 32-bit binary
          compatibility. Since all software available for Linux/MIPS is
index bc1c44274a58a4f5e165d35384b1af13d08c8af1..b0fdaee8d8d95228a810f23ed680e7134022f4ee 100644 (file)
@@ -37,12 +37,12 @@ else
 64bit-emul             = elf64btsmip
 endif
 
-ifdef CONFIG_MIPS32
+ifdef CONFIG_32BIT
 gcc-abi                        = 32
 tool-prefix            = $(32bit-tool-prefix)
 UTS_MACHINE            := mips
 endif
-ifdef CONFIG_MIPS64
+ifdef CONFIG_64BIT
 gcc-abi                        = 64
 tool-prefix            = $(64bit-tool-prefix)
 UTS_MACHINE            := mips64
@@ -63,7 +63,7 @@ ld-emul                       = $(32bit-emul)
 vmlinux-32             = vmlinux
 vmlinux-64             = vmlinux.64
 
-cflags-$(CONFIG_MIPS64)        += $(call cc-option,-mno-explicit-relocs)
+cflags-$(CONFIG_64BIT) += $(call cc-option,-mno-explicit-relocs)
 endif
 
 #
@@ -177,7 +177,7 @@ cflags-$(CONFIG_CPU_MIPS64) += \
 
 cflags-$(CONFIG_CPU_R5000)     += \
                        $(call set_gccflags,r5000,mips4,r5000,mips4,mips2) \
-                       -Wa,--trap 
+                       -Wa,--trap
 
 cflags-$(CONFIG_CPU_R5432)     += \
                        $(call set_gccflags,r5400,mips4,r5000,mips4,mips2) \
@@ -423,6 +423,12 @@ core-$(CONFIG_PMC_YOSEMITE)        += arch/mips/pmc-sierra/yosemite/
 cflags-$(CONFIG_PMC_YOSEMITE)  += -Iinclude/asm-mips/mach-yosemite
 load-$(CONFIG_PMC_YOSEMITE)    += 0xffffffff80100000
 
+# Qemu simulating MIPS32 4Kc
+#
+core-$(CONFIG_QEMU)            += arch/mips/qemu/
+cflags-$(CONFIG_QEMU)          += -Iinclude/asm-mips/mach-qemu
+load-$(CONFIG_QEMU)            += 0xffffffff80010000
+
 #
 # Momentum Ocelot-3
 #
@@ -468,13 +474,6 @@ core-$(CONFIG_LASAT)               += arch/mips/lasat/
 cflags-$(CONFIG_LASAT)         += -Iinclude/asm-mips/mach-lasat
 load-$(CONFIG_LASAT)           += 0xffffffff80000000
 
-#
-# NEC Osprey (vr4181) board
-#
-core-$(CONFIG_NEC_OSPREY)      += arch/mips/vr4181/common/ \
-                                  arch/mips/vr4181/osprey/
-load-$(CONFIG_NEC_OSPREY)      += 0xffffffff80002000
-
 #
 # Common VR41xx
 #
@@ -490,13 +489,11 @@ load-$(CONFIG_NEC_CMBVR4133)      += 0xffffffff80100000
 #
 # ZAO Networks Capcella (VR4131)
 #
-core-$(CONFIG_ZAO_CAPCELLA)    += arch/mips/vr41xx/zao-capcella/
 load-$(CONFIG_ZAO_CAPCELLA)    += 0xffffffff80000000
 
 #
 # Victor MP-C303/304 (VR4122)
 #
-core-$(CONFIG_VICTOR_MPC30X)   += arch/mips/vr41xx/victor-mpc30x/
 load-$(CONFIG_VICTOR_MPC30X)   += 0xffffffff80001000
 
 #
@@ -512,16 +509,9 @@ core-$(CONFIG_CASIO_E55)   += arch/mips/vr41xx/casio-e55/
 load-$(CONFIG_CASIO_E55)       += 0xffffffff80004000
 
 #
-# TANBAC TB0226 Mbase (VR4131)
-#
-core-$(CONFIG_TANBAC_TB0226)   += arch/mips/vr41xx/tanbac-tb0226/
-load-$(CONFIG_TANBAC_TB0226)   += 0xffffffff80000000
-
-#
-# TANBAC TB0229 VR4131DIMM (VR4131)
+# TANBAC VR4131 multichip module(TB0225) and TANBAC VR4131DIMM(TB0229) (VR4131)
 #
-core-$(CONFIG_TANBAC_TB0229)   += arch/mips/vr41xx/tanbac-tb0229/
-load-$(CONFIG_TANBAC_TB0229)   += 0xffffffff80000000
+load-$(CONFIG_TANBAC_TB022X)   += 0xffffffff80000000
 
 #
 # SGI IP22 (Indy/Indigo2)
@@ -534,10 +524,10 @@ load-$(CONFIG_TANBAC_TB0229)      += 0xffffffff80000000
 #
 core-$(CONFIG_SGI_IP22)                += arch/mips/sgi-ip22/
 cflags-$(CONFIG_SGI_IP22)      += -Iinclude/asm-mips/mach-ip22
-ifdef CONFIG_MIPS32
+ifdef CONFIG_32BIT
 load-$(CONFIG_SGI_IP22)                += 0xffffffff88002000
 endif
-ifdef CONFIG_MIPS64
+ifdef CONFIG_64BIT
 load-$(CONFIG_SGI_IP22)                += 0xffffffff88004000
 endif
 
@@ -642,7 +632,7 @@ load-$(CONFIG_TOSHIBA_RBTX4927)     += 0xffffffff80020000
 cflags-y                       += -Iinclude/asm-mips/mach-generic
 drivers-$(CONFIG_PCI)          += arch/mips/pci/
 
-ifdef CONFIG_MIPS32
+ifdef CONFIG_32BIT
 ifdef CONFIG_CPU_LITTLE_ENDIAN
 JIFFIES                        = jiffies_64
 else
@@ -674,8 +664,8 @@ CPPFLAGS_vmlinux.lds := \
 head-y := arch/mips/kernel/head.o arch/mips/kernel/init_task.o
 
 libs-y                 += arch/mips/lib/
-libs-$(CONFIG_MIPS32)  += arch/mips/lib-32/
-libs-$(CONFIG_MIPS64)  += arch/mips/lib-64/
+libs-$(CONFIG_32BIT)   += arch/mips/lib-32/
+libs-$(CONFIG_64BIT)   += arch/mips/lib-64/
 
 core-y                 += arch/mips/kernel/ arch/mips/mm/ arch/mips/math-emu/
 
@@ -683,7 +673,7 @@ drivers-$(CONFIG_OPROFILE)  += arch/mips/oprofile/
 
 ifdef CONFIG_LASAT
 rom.bin rom.sw: vmlinux
-       $(call descend,arch/mips/lasat/image,$@)
+       $(Q)$(MAKE) $(build)=arch/mips/lasat/image $@
 endif
 
 #
@@ -730,7 +720,7 @@ archclean:
        @$(MAKE) $(clean)=arch/mips/boot
        @$(MAKE) $(clean)=arch/mips/lasat
 
-# Generate <asm/offset.h 
+# Generate <asm/offset.h
 #
 # The default rule is suffering from funny problems on MIPS so we using our
 # own ...
index 533721eef6ae3f36b580a2b4605c94d224143851..4e5a6e1a9a6ed1313baccf87b20d380702da3713 100644 (file)
 
 /* TBD */
 static struct resource pci_io_resource = {
-       "pci IO space", 
+       "pci IO space",
        (u32)PCI_IO_START,
        (u32)PCI_IO_END,
        IORESOURCE_IO
 };
 
 static struct resource pci_mem_resource = {
-       "pci memory space", 
+       "pci memory space",
        (u32)PCI_MEM_START,
        (u32)PCI_MEM_END,
        IORESOURCE_MEM
@@ -68,7 +68,7 @@ static unsigned long virt_io_addr;
 static int __init au1x_pci_setup(void)
 {
 #if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550)
-       virt_io_addr = (unsigned long)ioremap(Au1500_PCI_IO_START, 
+       virt_io_addr = (unsigned long)ioremap(Au1500_PCI_IO_START,
                        Au1500_PCI_IO_END - Au1500_PCI_IO_START + 1);
 
        if (!virt_io_addr) {
@@ -77,7 +77,7 @@ static int __init au1x_pci_setup(void)
        }
 
 #ifdef CONFIG_DMA_NONCOHERENT
-       /* 
+       /*
          *  Set the NC bit in controller for Au1500 pre-AC silicon
         */
        u32 prid = read_c0_prid();
index dbc8b1bda9637efd339ebd70c97d72c20b87e161..eff89e109ce69f8648a414c54ac82f73237b80f0 100644 (file)
@@ -97,7 +97,7 @@ static int __init au1x00_setup(void)
                argptr = prom_getcmdline();
                strcat(argptr, " console=ttyS0,115200");
        }
-#endif   
+#endif
 
 #ifdef CONFIG_FB_AU1100
     if ((argptr = strstr(argptr, "video=")) == NULL) {
index fe418f1620c3b62245352ed2259be0d086cf3bf0..57675b41480e89b99ffd179e9d66e03378ebfb8b 100644 (file)
@@ -281,7 +281,7 @@ unsigned long cal_r4koff(void)
                        cpu_speed = count * 2;
                }
 #else
-               cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * 
+               cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) *
                        AU1000_SRC_CLK;
                count = cpu_speed / 2;
 #endif
@@ -356,7 +356,7 @@ static unsigned long do_fast_cp0_gettimeoffset(void)
                : "hi", "lo", GCC_REG_ACCUM);
 
        /*
-        * Due to possible jiffies inconsistencies, we need to check 
+        * Due to possible jiffies inconsistencies, we need to check
         * the result so that we'll get a timer that is monotonic.
         */
        if (res >= USECS_PER_JIFFY)
@@ -375,8 +375,8 @@ static unsigned long do_fast_pm_gettimeoffset(void)
        au_sync();
        offset = pc0 - last_pc0;
        if (offset > 2*MATCH20_INC) {
-               printk("huge offset %x, last_pc0 %x last_match20 %x pc0 %x\n", 
-                               (unsigned)offset, (unsigned)last_pc0, 
+               printk("huge offset %x, last_pc0 %x last_match20 %x pc0 %x\n",
+                               (unsigned)offset, (unsigned)last_pc0,
                                (unsigned)last_match20, (unsigned)pc0);
        }
        offset = (unsigned long)((offset * 305) / 10);
@@ -394,11 +394,11 @@ void au1xxx_timer_setup(struct irqaction *irq)
        r4k_offset = cal_r4koff();
        printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
 
-       //est_freq = 2*r4k_offset*HZ;   
-       est_freq = r4k_offset*HZ;       
+       //est_freq = 2*r4k_offset*HZ;
+       est_freq = r4k_offset*HZ;
        est_freq += 5000;    /* round */
        est_freq -= est_freq%10000;
-       printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, 
+       printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
               (est_freq%1000000)*100/1000000);
        set_au1x00_speed(est_freq);
        set_au1x00_lcd_clock(); // program the LCD clock
index 90426eaffb23655e2b1ed7ab48f8784f1f218e85..1c55c5f59d759ba5704b2fee60c18bb36c73eb5a 100644 (file)
@@ -182,7 +182,7 @@ void __init board_setup(void)
        au_writel(0xf0000000, Au1500_PCI_MWMASK_DEV);
        au_writel(0, Au1500_PCI_MWBASE_REV_CCL);
        au_writel(0x02a00356, Au1500_PCI_STATCMD);
-       au_writel(0x00003c04, Au1500_PCI_HDRTYPE);      
+       au_writel(0x00003c04, Au1500_PCI_HDRTYPE);
        au_writel(0x00000008, Au1500_PCI_MBAR);
        au_sync();
 
@@ -216,7 +216,7 @@ csb250_pci_idsel(unsigned int devsel, int assert)
        unsigned int    gpio2_pins;
 
        retval = 1;
-       
+
        /* First, disable both selects, then assert the one requested.
        */
        au_writel(0xc000c000, GPIO2_OUTPUT);
index 4320057fc4391c0f25ca535d55e80a8bd13eeff0..bd99733abc0be21fd6a592adb4b7bc8d31c847b9 100644 (file)
@@ -81,7 +81,7 @@ int __init prom_init(int argc, char **argv, char **envp, int *prom_vec)
        csb_env[0] = env1;
 
        mips_machgroup = MACH_GROUP_ALCHEMY;
-       mips_machtype = MACH_CSB250;  
+       mips_machtype = MACH_CSB250;
 
        prom_init_cmdline();
        memsize_str = prom_getenv("memsize");
index 51eee94a5e824a0c82d4fd3b1ac7299a43ebc7c6..4b9d5e46edbbc42133fdbd268967c2ddc213adc0 100644 (file)
@@ -61,7 +61,7 @@ void __init prom_init(void)
        prom_envp = (char **) fw_arg2;
 
        mips_machgroup = MACH_GROUP_ALCHEMY;
-       mips_machtype = MACH_DB1000;    /* set the platform # */   
+       mips_machtype = MACH_DB1000;    /* set the platform # */
 
        prom_init_cmdline();
 
index eee4adf98711d7f7447e990e48f5418952f79bfd..8cc9879dd582261272135a2f2e68f8585b231aa5 100644 (file)
@@ -63,7 +63,7 @@ int __init prom_init(int argc, char **argv, char **envp, int *prom_vec)
        prom_envp = envp;
 
        mips_machgroup = MACH_GROUP_ALCHEMY;
-       mips_machtype = MACH_DB1000;    /* set the platform # */   
+       mips_machtype = MACH_DB1000;    /* set the platform # */
        prom_init_cmdline();
 
        memsize_str = prom_getenv("memsize");
index 2fa211b69329e8a05c080a929c8efcdb2f15f29f..0b4807dc9f44e3d93289f6091f495d750cef4051 100644 (file)
@@ -174,7 +174,7 @@ void __init board_setup(void)
        case 0x02: /* HB */
                break;
        default:  /* HC and newer */
-               /* Enable sys bus clock divider when IDLE state or no bus 
+               /* Enable sys bus clock divider when IDLE state or no bus
                   activity. */
                au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL);
                break;
index 9dadc82536f45f8ed49243a2ee462508db3dabd8..1e59433dfd66a3ace22f153268be5fa2d8a9084b 100644 (file)
@@ -49,7 +49,7 @@ void board_reset (void)
 void __init board_setup(void)
 {
        u32 pin_func;
-       
+
        // set multiple use pins (UART3/GPIO) to UART (it's used as UART too)
        pin_func = au_readl(SYS_PINFUNC) & (u32)(~SYS_PF_UR3);
        pin_func |= SYS_PF_UR3;
@@ -75,11 +75,11 @@ void __init board_setup(void)
        au_writel(1, GPIO2_ENABLE);
        /* gpio2 208/9/10/11 are inputs */
        au_writel((1<<8) | (1<<9) | (1<<10) | (1<<11), GPIO2_DIR);
-       
+
        /* turn off power */
        au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<14))|(1<<30), GPIO2_OUTPUT);
 #endif
-       
+
 
 #ifdef CONFIG_PCI
 #if defined(__MIPSEB__)
index 03f755291b519e61e2fd508e25693968fc1c7816..f1c76533b6fc8ea4b3ebff2f5b43b6276e98f9dd 100644 (file)
@@ -55,7 +55,7 @@ void __init prom_init(void)
        prom_envp = (char **) fw_arg2;
 
        mips_machgroup = MACH_GROUP_ALCHEMY;
-       mips_machtype = MACH_XXS1500;   /* set the platform # */   
+       mips_machtype = MACH_XXS1500;   /* set the platform # */
 
        prom_init_cmdline();
 
index 954800a0ab527401aa014eb3c8fdbb5442410622..52f2f7daeb0559bdfaab23050c0c159823b72c6e 100644 (file)
@@ -56,7 +56,7 @@ au1xxx_irq_map_t au1xxx_irq_map[] = {
        { AU1500_GPIO_207, INTC_INT_LOW_LEVEL, 0 },
 
        { AU1000_GPIO_0, INTC_INT_LOW_LEVEL, 0 },
-       { AU1000_GPIO_1, INTC_INT_LOW_LEVEL, 0 }, 
+       { AU1000_GPIO_1, INTC_INT_LOW_LEVEL, 0 },
        { AU1000_GPIO_2, INTC_INT_LOW_LEVEL, 0 },
        { AU1000_GPIO_3, INTC_INT_LOW_LEVEL, 0 },
        { AU1000_GPIO_4, INTC_INT_LOW_LEVEL, 0 }, /* CF interrupt */
index caad7ca27abd1a00f39002a982dc340546c30c90..3120a02b8670a5329728b13e9cd9a173c9fe2e69 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:00 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -88,6 +88,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_MIPS_BONITO64=y
 CONFIG_MIPS_MSC=y
 # CONFIG_CPU_LITTLE_ENDIAN is not set
index 1b7f8a702d06ed89a93ef9f6bd3c7c502a02e897..158e7165f4e32fe5bb645e5b8649dc110441eaf2 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:00 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -97,6 +97,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_IRQ_CPU=y
 CONFIG_MIPS_L1_CACHE_SHIFT=5
index 8861854561e589f0bc2a126349dc0e85fa20a282..4302c6f914f5048080944be60daaef39dd29dd81 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:00 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -82,6 +82,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_I8259=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_IRQ_CPU=y
index 19cac1bf4f017ab23f40053acee392d4b853ea75..962fc14b58c287a8644f758ee2bd7fe33b121c15 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:01 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -104,6 +104,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_MIPS_L1_CACHE_SHIFT=5
 
index 035ac95d197eee3063aa4290bc3c972635e9b3ee..6a528d479d70103e0ee50815b751f0ae54cf7d54 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:01 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -104,6 +104,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_MIPS_L1_CACHE_SHIFT=5
 
index c38c4ed18fe7cfffc15de92a434b88efecf1c029..fed6f2fab48be54265f2ab218e56132ada5103be 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:01 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
index ee81309ae3a5edc29ae8520251fa40c79a429a88..178c0ad1af750dfdf97925f5a749a11a38be3fb8 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:02 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
index d43ed57c4b4ea285e8a0610d2c04ec90995cbde0..70addc73f699600891cc9aebc1a352c5184762ef 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:02 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -82,6 +82,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_I8259=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_IRQ_CPU=y
index 5a032cdefd63050f7a8fcfc69276f86e7182481a..60292808b3841f6e621fa93b6b65b76e96228faa 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:02 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -83,6 +83,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_I8259=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_IRQ_CPU=y
index 32ada79da9d8875f1eaadbb405eef1e04b34345d..66ec1f41d122a96d3738e614904eca7cf0dd47c9 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:03 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -88,6 +88,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_IRQ_CPU=y
index 52074a2085fbc8ace1c4596f0081b846524c36b9..ba2ec01defb11efff11e7701aec4e0690a0a914e 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:03 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -96,6 +96,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_IRQ_CPU=y
 CONFIG_MIPS_L1_CACHE_SHIFT=5
index 360e842fd4be7f6af0cf203ff8e07d9fb266d0d5..17e87f70f602e731be20a77200cc14422d8ee555 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:03 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -89,6 +89,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 # CONFIG_CPU_LITTLE_ENDIAN is not set
 CONFIG_MIPS_GT64120=y
 # CONFIG_SYSCLK_75 is not set
index 657a9508d31a924898f1ee23d558e1b4399f83c6..9da4140eae002344b2a5695bae2d100882919893 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:03 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -88,6 +88,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 # CONFIG_CPU_LITTLE_ENDIAN is not set
 CONFIG_IRQ_CPU=y
 CONFIG_MIPS_GT64120=y
index 3fb102e6a7f7d0d26394fa1306d5212c533ab0c3..17fa5c4e3ad13849cd6d0a90a6d053ec3e3c2939 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:04 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -90,6 +90,7 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_ARC=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 # CONFIG_CPU_LITTLE_ENDIAN is not set
 CONFIG_IRQ_CPU=y
 CONFIG_SWAP_IO_SPACE=y
index b5bab3a42fc4e1e0329cf083503121fbdb004c4a..b2a67da1e031f0ac10582f9a7d39e3948cfcd192 100644 (file)
@@ -4,7 +4,7 @@
 # Wed Jan 26 02:49:04 2005
 #
 CONFIG_MIPS=y
-CONFIG_MIPS64=y
+CONFIG_64BIT=y
 CONFIG_64BIT=y
 
 #
index bdf1415475ff63e338b65cb6ad3b5a86303ffec7..b26e1173365ddd1291101d57aa25939307012dff 100644 (file)
@@ -4,7 +4,7 @@
 # Wed Jan 26 02:49:04 2005
 #
 CONFIG_MIPS=y
-CONFIG_MIPS64=y
+CONFIG_64BIT=y
 CONFIG_64BIT=y
 
 #
@@ -84,6 +84,7 @@ CONFIG_ARC=y
 CONFIG_DMA_IP32=y
 CONFIG_OWN_DMA=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 # CONFIG_CPU_LITTLE_ENDIAN is not set
 CONFIG_ARC32=y
 CONFIG_BOOT_ELF32=y
index 1ca7746388f0ef694ef8928ea321598294d6f4b9..08bd3ad64761712d8fa881cc4761609830eca540 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:05 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -90,6 +90,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_ITE_BOARD_GEN=y
 CONFIG_IT8172_CIR=y
index c6eef708be1e9bdaa16a20944cae80413ebe3e83..583ef5c5b1cd69137389b25d7c37b11aa647281b 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:05 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -89,6 +89,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_ITE_BOARD_GEN=y
 CONFIG_IT8172_CIR=y
index 757c4e88cc005641ca94997f198712297a21f281..8abb5a0c6c1219fd466e2d9ea681505e9e64da21 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:05 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -81,6 +81,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_LIMITED_DMA=y
 # CONFIG_CPU_LITTLE_ENDIAN is not set
 CONFIG_IRQ_CPU=y
index e5a613906554acaca581480a7a216809c538365f..da5d9ee2ecceb8e55680f6e474b826fffca7408d 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:06 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -82,6 +82,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 # CONFIG_CPU_LITTLE_ENDIAN is not set
 CONFIG_MIPS_TX3927=y
 CONFIG_SWAP_IO_SPACE=y
index 1e7697834e90fda20fcbbc5eeeb8af6bd4bae96a..8d600ae890f48e1cf4d3eb6ffc7783fa21550f02 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:06 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -92,6 +92,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_MIPS_NILE4=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_MIPS_GT64120=y
index 61fb9fb97e6e33793252f4effb9a87453803b973..79519ac5af4a8c71c7d45d8e6adf2df659fc2eb0 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:53:14 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -88,6 +88,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_GENERIC_ISA_DMA=y
 CONFIG_I8259=y
 CONFIG_MIPS_BONITO64=y
index 31b8f2ad73385dd9fadfc2545bfa47f4f199f029..0fea57ef18f2069b32bad99498201e2af8f15a06 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:07 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -97,6 +97,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_IRQ_CPU=y
 CONFIG_MIPS_L1_CACHE_SHIFT=5
index 2cce682fffcf66c54b57580d00f6cb013cec0ed3..b4cf97a732bc5ba566c736e5665486d3a61ca82e 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:07 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -89,6 +89,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 # CONFIG_CPU_LITTLE_ENDIAN is not set
 CONFIG_IRQ_CPU=y
 CONFIG_IRQ_CPU_RM7K=y
index 0cbf48a62e02078d1c8b7667238e8984abafae7f..a38903db85a071c55d532e218addd3d9478ff007 100644 (file)
@@ -4,7 +4,7 @@
 # Wed Jan 26 02:49:07 2005
 #
 CONFIG_MIPS=y
-CONFIG_MIPS64=y
+CONFIG_64BIT=y
 CONFIG_64BIT=y
 
 #
@@ -80,6 +80,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 # CONFIG_CPU_LITTLE_ENDIAN is not set
 CONFIG_IRQ_CPU=y
 CONFIG_IRQ_MV64340=y
index 4043950d360a9f1443f6647692a6147446809e8e..920d59b56a4efc456035f2e6841a5e99757d5535 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:08 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -82,6 +82,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 # CONFIG_CPU_LITTLE_ENDIAN is not set
 CONFIG_IRQ_CPU=y
 CONFIG_IRQ_CPU_RM7K=y
index 3870af4537adeac3bb45afedd00e470138c91eda..ef5ea50893d14a8f7b88311ab69c8fd9c745d4d9 100644 (file)
@@ -4,7 +4,7 @@
 # Wed Jan 26 02:49:08 2005
 #
 CONFIG_MIPS=y
-CONFIG_MIPS64=y
+CONFIG_64BIT=y
 CONFIG_64BIT=y
 
 #
@@ -80,6 +80,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 # CONFIG_CPU_LITTLE_ENDIAN is not set
 CONFIG_IRQ_CPU=y
 CONFIG_IRQ_CPU_RM7K=y
index 6cdabd550300bf45437b86f2f010d85c26959d0a..813e3a8b480bfc46d5e4cfb6623c0c798f97d4cd 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:08 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -104,6 +104,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_SWAP_IO_SPACE=y
 # CONFIG_AU1X00_USB_DEVICE is not set
index 2aebbd2e82b377608775760632b3c5d5ea92efd1..49e528340a396924c342b875d34e711635acf325 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:09 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
index 9e21edc28280df696451dba8d22c40e7effe94f1..8e426776c098e6295656a97a842236685a64a8ac 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:09 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
similarity index 66%
rename from arch/mips/configs/osprey_defconfig
rename to arch/mips/configs/qemu_defconfig
index 989cb9e7ae8367be0b7a2c6ad464f1675738d259..b6568e421b9980710ca20c7dc3fb49fcd5615755 100644 (file)
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc2
-# Wed Jan 26 02:49:08 2005
+# Linux kernel version: 2.6.13-rc6
+# Mon Aug  8 11:49:54 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
-# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
 
 #
 # Code maturity level options
 #
-CONFIG_EXPERIMENTAL=y
+# CONFIG_EXPERIMENTAL is not set
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
 #
 CONFIG_LOCALVERSION=""
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_SWAP is not set
+# CONFIG_SYSVIPC is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_SYSCTL is not set
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
+CONFIG_PRINTK=y
+# CONFIG_BUG is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_SHMEM=y
+# CONFIG_SHMEM is not set
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
-# CONFIG_TINY_SHMEM is not set
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=1
 
 #
 # Loadable module support
 #
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-CONFIG_KMOD=y
+# CONFIG_MODULES is not set
 
 #
 # Machine selection
 #
-# CONFIG_MACH_JAZZ is not set
-# CONFIG_MACH_VR41XX is not set
-# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
 # CONFIG_MIPS_COBALT is not set
 # CONFIG_MACH_DECSTATION is not set
 # CONFIG_MIPS_EV64120 is not set
 # CONFIG_MIPS_EV96100 is not set
 # CONFIG_MIPS_IVR is not set
-# CONFIG_LASAT is not set
 # CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
 # CONFIG_MIPS_ATLAS is not set
 # CONFIG_MIPS_MALTA is not set
 # CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
 # CONFIG_MOMENCO_OCELOT is not set
-# CONFIG_MOMENCO_OCELOT_G is not set
-# CONFIG_MOMENCO_OCELOT_C is not set
 # CONFIG_MOMENCO_OCELOT_3 is not set
-# CONFIG_MOMENCO_JAGUAR_ATX is not set
-# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
 # CONFIG_DDB5074 is not set
 # CONFIG_DDB5476 is not set
 # CONFIG_DDB5477 is not set
-CONFIG_NEC_OSPREY=y
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+CONFIG_QEMU=y
 # CONFIG_SGI_IP22 is not set
-# CONFIG_SOC_AU1X00 is not set
-# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
 # CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
-CONFIG_DMA_NONCOHERENT=y
-CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_IRQ_CPU=y
+CONFIG_DMA_COHERENT=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_I8259=y
+CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SWAP_IO_SPACE=y
 CONFIG_MIPS_L1_CACHE_SHIFT=5
-CONFIG_VR4181=y
+CONFIG_HAVE_STD_PC_SERIAL_PORT=y
 
 #
 # CPU selection
 #
-# CONFIG_CPU_MIPS32 is not set
-# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_MIPS32_R1 is not set
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-CONFIG_CPU_VR41XX=y
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
-# CONFIG_CPU_R4X00 is not set
+CONFIG_CPU_R4X00=y
 # CONFIG_CPU_TX49XX is not set
 # CONFIG_CPU_R5000 is not set
 # CONFIG_CPU_R5432 is not set
@@ -113,17 +138,36 @@ CONFIG_CPU_VR41XX=y
 # CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_RM9000 is not set
 # CONFIG_CPU_SB1 is not set
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
 CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_MIPS_MT is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
 # CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_LLDSCD=y
 CONFIG_CPU_HAS_SYNC=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
 # CONFIG_PREEMPT is not set
 
 #
 # Bus options (PCI, PCMCIA, EISA, ISA, TC)
 #
+CONFIG_ISA=y
 CONFIG_MMU=y
 
 #
@@ -131,10 +175,6 @@ CONFIG_MMU=y
 #
 # CONFIG_PCCARD is not set
 
-#
-# PC-card bridges
-#
-
 #
 # PCI Hotplug Support
 #
@@ -146,6 +186,56 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 CONFIG_TRAD_SIGNALS=y
 
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+
 #
 # Device Drivers
 #
@@ -154,7 +244,7 @@ CONFIG_TRAD_SIGNALS=y
 # Generic Driver Options
 #
 CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FW_LOADER is not set
 
 #
@@ -170,6 +260,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Plug and Play support
 #
+# CONFIG_PNP is not set
 
 #
 # Block devices
@@ -181,19 +272,16 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_BLK_DEV_RAM is not set
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_LBD is not set
-CONFIG_CDROM_PKTCDVD=m
-CONFIG_CDROM_PKTCDVD_BUFFERS=8
-# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+# CONFIG_CDROM_PKTCDVD is not set
 
 #
 # IO Schedulers
 #
 CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-CONFIG_ATA_OVER_ETH=m
+# 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
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -205,6 +293,11 @@ CONFIG_ATA_OVER_ETH=m
 #
 # CONFIG_SCSI is not set
 
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
 #
 # Multi-device support (RAID and LVM)
 #
@@ -213,6 +306,7 @@ CONFIG_ATA_OVER_ETH=m
 #
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -223,84 +317,41 @@ CONFIG_ATA_OVER_ETH=m
 #
 
 #
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
+# Network device support
 #
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK_DEV=y
-CONFIG_UNIX=y
-CONFIG_NET_KEY=y
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-CONFIG_INET_TUNNEL=m
-CONFIG_IP_TCPDIAG=m
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-CONFIG_XFRM=y
-CONFIG_XFRM_USER=m
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
 
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
+CONFIG_MII=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_ISA=y
+# CONFIG_E2100 is not set
+# CONFIG_EWRK3 is not set
+# CONFIG_EEXPRESS is not set
+# CONFIG_EEXPRESS_PRO is not set
+# CONFIG_HPLAN_PLUS is not set
+# CONFIG_HPLAN is not set
+# CONFIG_LP486E is not set
+# CONFIG_ETH16I is not set
+CONFIG_NE2000=y
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -313,6 +364,7 @@ CONFIG_NET_ETHERNET=y
 #
 # Token Ring devices
 #
+# CONFIG_TR is not set
 
 #
 # Wireless LAN (non-hamradio)
@@ -325,8 +377,8 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_WAN is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
@@ -346,27 +398,12 @@ CONFIG_INPUT=y
 #
 # Userland interfaces
 #
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_JOYDEV is not set
 # CONFIG_INPUT_TSDEV is not set
 # CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
 
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_LIBPS2 is not set
-CONFIG_SERIO_RAW=m
-
 #
 # Input Device Drivers
 #
@@ -376,6 +413,12 @@ CONFIG_SERIO_RAW=m
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
 #
 # Character devices
 #
@@ -397,9 +440,8 @@ CONFIG_SERIAL_8250_NR_UARTS=4
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
 
 #
 # IPMI
@@ -418,19 +460,28 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
+#
+# TPM devices
+#
+
 #
 # I2C support
 #
 # CONFIG_I2C is not set
+# CONFIG_I2C_SENSOR is not set
 
 #
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
 
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+
 #
 # Misc devices
 #
@@ -453,9 +504,9 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # Console display driver support
 #
-# CONFIG_VGA_CONSOLE is not set
+CONFIG_VGA_CONSOLE=y
+# CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -468,10 +519,6 @@ CONFIG_DUMMY_CONSOLE=y
 # CONFIG_USB_ARCH_HAS_HCD is not set
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
 #
 # USB Gadget Support
 #
@@ -487,20 +534,29 @@ CONFIG_DUMMY_CONSOLE=y
 #
 # CONFIG_INFINIBAND is not set
 
+#
+# SN Devices
+#
+
 #
 # File systems
 #
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS 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_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
 # CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
+# CONFIG_DNOTIFY is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -520,12 +576,8 @@ CONFIG_DNOTIFY=y
 #
 # Pseudo filesystems
 #
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS_XATTR=y
-CONFIG_DEVPTS_FS_SECURITY=y
+# CONFIG_PROC_FS is not set
+# CONFIG_SYSFS is not set
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
@@ -533,13 +585,7 @@ CONFIG_RAMFS=y
 #
 # Miscellaneous filesystems
 #
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
 # CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -551,23 +597,18 @@ CONFIG_RAMFS=y
 # Network File Systems
 #
 CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-CONFIG_NFSD=y
-# CONFIG_NFSD_V3 is not set
-# CONFIG_NFSD_TCP is not set
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
-CONFIG_EXPORTFS=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
 
 #
 # Partition Types
@@ -580,23 +621,19 @@ CONFIG_MSDOS_PARTITION=y
 #
 # CONFIG_NLS is not set
 
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
-
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 # CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
-CONFIG_CMDLINE="ip=bootp ether=46,0x03fe0300,eth0"
+CONFIG_CMDLINE="console=ttyS0 debug ip=172.20.0.2:172.20.0.1::255.255.0.0"
 
 #
 # Security options
 #
-CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -612,7 +649,7 @@ CONFIG_KEYS_DEBUG_PROC_KEYS=y
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
-# CONFIG_CRC32 is not set
-CONFIG_LIBCRC32C=m
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
index d0c85a4009d609f229c2ea336ceb43497c183d20..17d4fce6c4c6c297010309d3a3d241886a404645 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:09 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -91,6 +91,7 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_ARC=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_GENERIC_ISA_DMA=y
 CONFIG_I8259=y
 CONFIG_CPU_LITTLE_ENDIAN=y
index 84978b70714b5eb481b9dc6b5aa9e22d0b28093a..1dc935f3758264e4d2e9e56f4778d5b6249b94eb 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:10 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
index 7c718a429b04d00f3cc3f75c695e9c966e970b92..dd07e866b128e83adbddb3035b44748550f4b1ac 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:10 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -80,6 +80,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_IRQ_CPU=y
 CONFIG_MIPS_BOARDS_GEN=y
index e01727cd0fe904b069f90fe4a1f183105bc4a886..c9d3f83caf0f73dc964e70b707d982ac9e3b8725 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:12 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -95,6 +95,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_IRQ_CPU=y
 CONFIG_MIPS_L1_CACHE_SHIFT=5
index c6ba3de276145c765c18ec94eebc1a976f46cd9b..2cb669188aa9a4aed3b522a1d403014f0cf09c23 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:12 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -98,6 +98,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_IRQ_CPU=y
 CONFIG_MIPS_L1_CACHE_SHIFT=5
index 915c43b6e2d95c9b82feddf986f6991bbc40877c..16e07fca446f69cc99d7482dfb869888ff6b7948 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:12 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -96,6 +96,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_IRQ_CPU=y
 CONFIG_MIPS_L1_CACHE_SHIFT=5
index 562f2b8043ac4b25d49428b272f1cc0a6f2930f4..6d2290777ad7e6510d14aab7ac564a87f3c17185 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:49:13 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
index 5f027bfa4af8f9047cfa35cea667e88826c95c16..9ffe1a9142caef3e86c19faa03a4dd9906e94e6b 100644 (file)
@@ -76,7 +76,7 @@ set_pci_int_attr(u32 pci, u32 intn, u32 active, u32 trigger)
 extern void vrc5477_irq_init(u32 base);
 extern void mips_cpu_irq_init(u32 base);
 extern asmlinkage void ddb5477_handle_int(void);
-extern int setup_irq(unsigned int irq, struct irqaction *irqaction);  
+extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
 static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL };
 
 void __init arch_init_irq(void)
@@ -94,7 +94,7 @@ void __init arch_init_irq(void)
        /* setup PCI interrupt attributes */
        set_pci_int_attr(PCI0, INTA, ACTIVE_LOW, LEVEL_SENSE);
        set_pci_int_attr(PCI0, INTB, ACTIVE_LOW, LEVEL_SENSE);
-       if (mips_machtype == MACH_NEC_ROCKHOPPERII) 
+       if (mips_machtype == MACH_NEC_ROCKHOPPERII)
                set_pci_int_attr(PCI0, INTC, ACTIVE_HIGH, LEVEL_SENSE);
        else
                set_pci_int_attr(PCI0, INTC, ACTIVE_LOW, LEVEL_SENSE);
@@ -134,7 +134,7 @@ void __init arch_init_irq(void)
 
        /* setup cascade interrupts */
        setup_irq(VRC5477_IRQ_BASE + VRC5477_I8259_CASCADE, &irq_cascade);
-       setup_irq(CPU_IRQ_BASE + CPU_VRC5477_CASCADE, &irq_cascade);      
+       setup_irq(CPU_IRQ_BASE + CPU_VRC5477_CASCADE, &irq_cascade);
 
        /* hook up the first-level interrupt handler */
        set_except_vector(0, ddb5477_handle_int);
index 15c6e543b56f09b5788281235520ba095462a95d..d62f5a789b0544d62bae459910d539018446816e 100644 (file)
@@ -141,7 +141,7 @@ static void __init ddb_time_init(void)
 
        /* mips_hpt_frequency is 1/2 of the cpu core freq */
        i =  (read_c0_config() >> 28 ) & 7;
-       if ((current_cpu_data.cputype == CPU_R5432) && (i == 3)) 
+       if ((current_cpu_data.cputype == CPU_R5432) && (i == 3))
                i = 4;
        mips_hpt_frequency = bus_frequency*(i+4)/4;
 }
@@ -298,11 +298,11 @@ static void __init ddb5477_board_init(void)
 
        if (mips_machtype == MACH_NEC_ROCKHOPPER
           ||  mips_machtype == MACH_NEC_ROCKHOPPERII) {
-               /* Disable bus diagnostics. */ 
+               /* Disable bus diagnostics. */
                ddb_out32(DDB_PCICTL0_L, 0);
                ddb_out32(DDB_PCICTL0_H, 0);
                ddb_out32(DDB_PCICTL1_L, 0);
-               ddb_out32(DDB_PCICTL1_H, 0);         
+               ddb_out32(DDB_PCICTL1_H, 0);
        }
 
        if (mips_machtype == MACH_NEC_ROCKHOPPER) {
@@ -354,7 +354,7 @@ static void __init ddb5477_board_init(void)
                 */
                pci_write_config_byte(&dev_m1533, 0x58, 0x74);
 
-               /* 
+               /*
                 * positive decode (bit6 -0)
                 * enable IDE controler interrupt (bit 4 -1)
                 * setup SIRQ to point to IRQ 14 (bit 3:0 - 1101)
@@ -364,31 +364,31 @@ static void __init ddb5477_board_init(void)
                /* Setup M5229 registers */
                dev_m5229.bus = &bus;
                dev_m5229.sysdata = NULL;
-               dev_m5229.devfn = 4*8;          // slot 4 (AD15): M5229 IDE 
+               dev_m5229.devfn = 4*8;          // slot 4 (AD15): M5229 IDE
 
                /*
                 * enable IDE in the M5229 config register 0x50 (bit 0 - 1)
-                * M5229 IDSEL is addr:15; see above setting 
+                * M5229 IDSEL is addr:15; see above setting
                 */
                pci_read_config_byte(&dev_m5229, 0x50, &temp8);
                pci_write_config_byte(&dev_m5229, 0x50, temp8 | 0x1);
 
-               /* 
-                * enable bus master (bit 2)  and IO decoding  (bit 0) 
+               /*
+                * enable bus master (bit 2)  and IO decoding  (bit 0)
                 */
                pci_read_config_byte(&dev_m5229, 0x04, &temp8);
                pci_write_config_byte(&dev_m5229, 0x04, temp8 | 0x5);
 
                /*
                 * enable native, copied from arch/ppc/k2boot/head.S
-                * TODO - need volatile, need to be portable 
+                * TODO - need volatile, need to be portable
                 */
                pci_write_config_byte(&dev_m5229, 0x09, 0xef);
 
-               /* Set Primary Channel Command Block Timing */ 
+               /* Set Primary Channel Command Block Timing */
                pci_write_config_byte(&dev_m5229, 0x59, 0x31);
 
-               /* 
+               /*
                 * Enable primary channel 40-pin cable
                 * M5229 register 0x4a (bit 0)
                 */
index 133fb7c48e6c6f748804a5918552ba8458f75e3b..6dbce92eb0683c775a143069bffcb2ad1a9d83f6 100644 (file)
@@ -253,7 +253,7 @@ static inline void dec_kn03_be_init(void)
 
        kn0x_erraddr = (void *)(KN03_SLOT_BASE + IOASIC_ERRADDR);
        kn0x_chksyn = (void *)(KN03_SLOT_BASE + IOASIC_CHKSYN);
-                       
+
        /*
         * Set normal ECC detection and generation, enable ECC correction.
         * For KN05 we also need to make sure EE (?) is enabled in the MB.
index 3b379099321999b789643de2aa555206d640b883..c89768d5c4e55458dd79c797a5daedbbb577afc4 100644 (file)
                 */
                mfc0    t0,CP0_CAUSE            # get pending interrupts
                mfc0    t1,CP0_STATUS
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
                lw      t2,cpu_fpu_mask
 #endif
                andi    t0,ST0_IM               # CAUSE.CE may be non-zero!
 
                beqz    t0,spurious
 
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
                 and    t2,t0
                bnez    t2,fpu                  # handle FPU immediately
 #endif
@@ -271,7 +271,7 @@ handle_it:
                j       ret_from_irq
                 nop
 
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 fpu:
                j       handle_fpe_int
                 nop
index 373822ec2d8c28e512d6b7ae48f2fd018c143636..bcd0247b3a66731636ec6aad45733b793e6e40f3 100644 (file)
@@ -5,7 +5,7 @@
 
 lib-y                  += init.o memory.o cmdline.o identify.o console.o
 
-lib-$(CONFIG_MIPS32)   += locore.o
-lib-$(CONFIG_MIPS64)   += call_o32.o
+lib-$(CONFIG_32BIT)    += locore.o
+lib-$(CONFIG_64BIT)    += call_o32.o
 
 EXTRA_AFLAGS := $(CFLAGS)
index d55fe665926f06e10dc3c6b704b9bb0b08d23419..20f84b119b4c344067beda1809cf490ed360e35f 100644 (file)
@@ -4,9 +4,9 @@
 # Wed Jan 26 02:48:59 2005
 #
 CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
 # CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
 
 #
 # Code maturity level options
@@ -90,6 +90,7 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_ARC=y
 CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
 # CONFIG_CPU_LITTLE_ENDIAN is not set
 CONFIG_IRQ_CPU=y
 CONFIG_SWAP_IO_SPACE=y
index d808a67294b8cbc4fc1947ae1ed96e7ba0fe73e8..a5f6d84bc1813ae865c035ce09e2df14c2f6f370 100644 (file)
@@ -129,7 +129,7 @@ static void __init it8172_setup(void)
 
        /*
         * IO/MEM resources.
-        * 
+        *
         * revisit this area.
         */
        set_io_port_base(KSEG1);
index 30a6c0d5fc5094dee3af65abddb473b83cd457e4..f5d67ee21ac632f1e8c6a14a9d612f7de6273080 100644 (file)
@@ -72,7 +72,7 @@ static inline int rtc_dm_binary(void) { return saved_control & RTC_DM_BINARY; }
 static inline unsigned char
 bin_to_hw(unsigned char c)
 {
-       if (rtc_dm_binary()) 
+       if (rtc_dm_binary())
                return c;
        else
                return ((c/10) << 4) + (c%10);
@@ -91,9 +91,9 @@ hw_to_bin(unsigned char c)
 static inline unsigned char
 hour_bin_to_hw(unsigned char c)
 {
-       if (rtc_24h()) 
+       if (rtc_24h())
                return bin_to_hw(c);
-       if (c >= 12) 
+       if (c >= 12)
                return 0x80 | bin_to_hw((c==12)?12:c-12);  /* 12 is 12pm */
        else
                return bin_to_hw((c==0)?12:c);  /* 0 is 12 AM, not 0 am */
@@ -105,9 +105,9 @@ hour_hw_to_bin(unsigned char c)
        unsigned char tmp = hw_to_bin(c&0x3f);
        if (rtc_24h())
                return tmp;
-       if (c & 0x80) 
+       if (c & 0x80)
                return (tmp==12)?12:tmp+12;     /* 12pm is 12, not 24 */
-       else 
+       else
                return (tmp==12)?0:tmp;         /* 12am is 0 */
 }
 
@@ -145,7 +145,7 @@ static unsigned long __init cal_r4koff(void)
        return (mips_hpt_frequency / HZ);
 }
 
-static unsigned long 
+static unsigned long
 it8172_rtc_get_time(void)
 {
        unsigned int year, mon, day, hour, min, sec;
@@ -166,12 +166,12 @@ it8172_rtc_get_time(void)
        hour = hour_hw_to_bin(CMOS_READ(RTC_HOURS));
        day = hw_to_bin(CMOS_READ(RTC_DAY_OF_MONTH));
        mon = hw_to_bin(CMOS_READ(RTC_MONTH));
-       year = hw_to_bin(CMOS_READ(RTC_YEAR)) + 
+       year = hw_to_bin(CMOS_READ(RTC_YEAR)) +
                hw_to_bin(*rtc_century_reg) * 100;
 
        /* restore interrupts */
        local_irq_restore(flags);
-               
+
        return mktime(year, mon, day, hour, min, sec);
 }
 
index a0230ee0f7f4bbcba350dea796615597de92b3ae..d3303584fbd1f86789d1990c113039513712406f 100644 (file)
@@ -13,8 +13,8 @@ binfmt_irix-objs      := irixelf.o irixinv.o irixioctl.o irixsig.o    \
 
 ifdef CONFIG_MODULES
 obj-y                          += mips_ksyms.o module.o
-obj-$(CONFIG_MIPS32)           += module-elf32.o
-obj-$(CONFIG_MIPS64)           += module-elf64.o
+obj-$(CONFIG_32BIT)            += module-elf32.o
+obj-$(CONFIG_64BIT)            += module-elf64.o
 endif
 
 obj-$(CONFIG_CPU_R3000)                += r2300_fpu.o r2300_switch.o
@@ -45,8 +45,8 @@ obj-$(CONFIG_IRQ_CPU_RM7K)    += irq-rm7000.o
 obj-$(CONFIG_IRQ_CPU_RM9K)     += irq-rm9000.o
 obj-$(CONFIG_IRQ_MV64340)      += irq-mv6434x.o
 
-obj-$(CONFIG_MIPS32)           += scall32-o32.o
-obj-$(CONFIG_MIPS64)           += scall64-64.o
+obj-$(CONFIG_32BIT)            += scall32-o32.o
+obj-$(CONFIG_64BIT)            += scall64-64.o
 obj-$(CONFIG_BINFMT_IRIX)      += binfmt_irix.o
 obj-$(CONFIG_MIPS32_COMPAT)    += ioctl32.o linux32.o signal32.o
 obj-$(CONFIG_MIPS32_N32)       += binfmt_elfn32.o scall64-n32.o signal_n32.o
@@ -55,7 +55,7 @@ obj-$(CONFIG_MIPS32_O32)      += binfmt_elfo32.o scall64-o32.o ptrace32.o
 obj-$(CONFIG_KGDB)             += gdb-low.o gdb-stub.o
 obj-$(CONFIG_PROC_FS)          += proc.o
 
-obj-$(CONFIG_MIPS64)           += cpu-bugs64.o
+obj-$(CONFIG_64BIT)            += cpu-bugs64.o
 
 obj-$(CONFIG_GEN_RTC)          += genrtc.o
 
index ed47041f30306c2fe93125465bff104c30cb71c2..6b645fbb1ddcd800092a3cd555dca0cf4439b5b7 100644 (file)
@@ -103,7 +103,7 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value)
         * Convert jiffies to nanoseconds and seperate with
         * one divide.
         */
-       u64 nsec = (u64)jiffies * TICK_NSEC; 
+       u64 nsec = (u64)jiffies * TICK_NSEC;
        value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &value->tv_usec);
        value->tv_usec /= NSEC_PER_USEC;
 }
index ee21b18c37a8a08c36c8b160955903a111585e2f..b4075e99c452218d17a4e94834cf7dc12cc8b12d 100644 (file)
@@ -105,7 +105,7 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value)
         * Convert jiffies to nanoseconds and seperate with
         * one divide.
         */
-       u64 nsec = (u64)jiffies * TICK_NSEC; 
+       u64 nsec = (u64)jiffies * TICK_NSEC;
        value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &value->tv_usec);
        value->tv_usec /= NSEC_PER_USEC;
 }
index 11ebe5d4c446fe390406106a02f564b8a1588399..47a087b6c11ba881d33d2aa2d3aaf2ffce50374a 100644 (file)
@@ -137,7 +137,7 @@ static inline void check_mult_sh(void)
        for (i = 0; i < 8; i++)
                if (v1[i] != w[i])
                        bug = 1;
-               
+
        if (bug == 0) {
                printk("no.\n");
                return;
@@ -149,7 +149,7 @@ static inline void check_mult_sh(void)
        for (i = 0; i < 8; i++)
                if (v2[i] != w[i])
                        fix = 0;
-               
+
        if (fix == 1) {
                printk("yes.\n");
                return;
index 4bb84958231410b6b644f0fe9f692063dab872a5..7685f8baf3f022da8843c5ef1847966a5085765f 100644 (file)
@@ -229,15 +229,9 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
                break;
        case PRID_IMP_VR41XX:
                switch (c->processor_id & 0xf0) {
-#ifndef CONFIG_VR4181
                case PRID_REV_VR4111:
                        c->cputype = CPU_VR4111;
                        break;
-#else
-               case PRID_REV_VR4181:
-                       c->cputype = CPU_VR4181;
-                       break;
-#endif
                case PRID_REV_VR4121:
                        c->cputype = CPU_VR4121;
                        break;
index ece6ddaf7011e943615874d1405d9322e217ee74..512bedbfa7b9ef0a36629193c19eb6b9d56ce129 100644 (file)
 #include <asm/stackframe.h>
 #include <asm/gdb-stub.h>
 
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 #define DMFC0  mfc0
 #define DMTC0  mtc0
 #define LDC1   lwc1
 #define SDC1   lwc1
 #endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 #define DMFC0  dmfc0
 #define DMTC0  dmtc0
 #define LDC1   ldc1
index 269889302a27d786c101d6d2da754351607b91c3..d3fd1ab14274c25daeaa1fce41159f5b3a07d9d5 100644 (file)
@@ -687,8 +687,8 @@ void handle_exception (struct gdb_regs *regs)
         * acquire the big kgdb spinlock
         */
        if (!spin_trylock(&kgdb_lock)) {
-               /* 
-                * some other CPU has the lock, we should go back to 
+               /*
+                * some other CPU has the lock, we should go back to
                 * receive the gdb_wait IPC
                 */
                return;
@@ -703,7 +703,7 @@ void handle_exception (struct gdb_regs *regs)
                async_bp.addr = 0;
        }
 
-       /* 
+       /*
         * acquire the CPU spinlocks
         */
        for (i = num_online_cpus()-1; i >= 0; i--)
@@ -894,7 +894,7 @@ void handle_exception (struct gdb_regs *regs)
                        ptr = &input_buffer[1];
                        if (hexToLong(&ptr, &addr))
                                regs->cp0_epc = addr;
-         
+
                        goto exit_kgdb_exception;
                        break;
 
@@ -1001,7 +1001,7 @@ void breakpoint(void)
                return;
 
        __asm__ __volatile__(
-                       ".globl breakinst\n\t" 
+                       ".globl breakinst\n\t"
                        ".set\tnoreorder\n\t"
                        "nop\n"
                        "breakinst:\tbreak\n\t"
@@ -1014,7 +1014,7 @@ void breakpoint(void)
 void async_breakpoint(void)
 {
        __asm__ __volatile__(
-                       ".globl async_breakinst\n\t" 
+                       ".globl async_breakinst\n\t"
                        ".set\tnoreorder\n\t"
                        "nop\n"
                        "async_breakinst:\tbreak\n\t"
index a5b0a389b063a37d169fdb50bf9933c054b0ec1e..e7f6c1b9080622c3250aa4062e5598d1618cf1d8 100644 (file)
@@ -54,7 +54,7 @@ NESTED(except_vec3_generic, 0, sp)
 #endif
        mfc0    k1, CP0_CAUSE
        andi    k1, k1, 0x7c
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        dsll    k1, k1, 1
 #endif
        PTR_L   k0, exception_handlers(k1)
@@ -81,7 +81,7 @@ NESTED(except_vec3_r4000, 0, sp)
        beq     k1, k0, handle_vced
         li     k0, 14<<2
        beq     k1, k0, handle_vcei
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        dsll    k1, k1, 1
 #endif
        .set    pop
@@ -244,12 +244,12 @@ NESTED(nmi_handler, PT_SIZE, sp)
           start with an n and gas will believe \n is ok ...  */
        .macro  __BUILD_verbose nexception
        LONG_L  a1, PT_EPC(sp)
-#if CONFIG_MIPS32
+#ifdef CONFIG_32BIT
        PRINT("Got \nexception at %08lx\012")
-#endif 
-#if CONFIG_MIPS64
+#endif
+#ifdef CONFIG_64BIT
        PRINT("Got \nexception at %016lx\012")
-#endif 
+#endif
        .endm
 
        .macro  __BUILD_count exception
@@ -293,7 +293,7 @@ NESTED(nmi_handler, PT_SIZE, sp)
        BUILD_HANDLER mcheck mcheck cli verbose         /* #24 */
        BUILD_HANDLER reserved reserved sti verbose     /* others */
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 /* A temporary overflow handler used by check_daddi(). */
 
        __INIT
index a64e87d22014a40ffa9f4ef58c73c1dac4e8383d..2a1b45d66f047dbca7ed7ee05e232e459b8b7157 100644 (file)
        .endm
 
        .macro  setup_c0_status_pri
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        setup_c0_status ST0_KX 0
 #else
        setup_c0_status 0 0
        .endm
 
        .macro  setup_c0_status_sec
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        setup_c0_status ST0_KX ST0_BEV
 #else
        setup_c0_status 0 ST0_BEV
@@ -215,7 +215,7 @@ NESTED(smp_bootstrap, 16, sp)
         * slightly different layout ...
         */
        page    swapper_pg_dir, _PGD_ORDER
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        page    invalid_pmd_table, _PMD_ORDER
 #endif
        page    invalid_pte_table, _PTE_ORDER
index 519cd5d0aebb83b165dec61263e7b97a81485a75..c069719ff0d842a89c3d9b442cb4f5cd07147ee8 100644 (file)
@@ -27,7 +27,7 @@ long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 #include "compat_ioctl.c"
 
 typedef int (* ioctl32_handler_t)(unsigned int, unsigned int, unsigned long, struct file *);
-                                                                                
+
 #define COMPATIBLE_IOCTL(cmd)          HANDLE_IOCTL((cmd),sys_ioctl)
 #define HANDLE_IOCTL(cmd,handler)      { (cmd), (ioctl32_handler_t)(handler), NULL },
 #define IOCTL_TABLE_START \
index 40244782a8e54185d263de24729f83b135150096..4c114ae21793eb8a4fde93da5b8ba529c2222395 100644 (file)
@@ -155,13 +155,12 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info,
        else
                setup_irix_frame(ka, regs, sig, oldset);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs)
index 441157a1f994a4d07cf90ffc248a1e6dc71af5f3..7d93992e462c847deb025a798943b7f6f6eef78e 100644 (file)
@@ -77,7 +77,7 @@ int show_interrupts(struct seq_file *p, void *v)
        if (i < NR_IRQS) {
                spin_lock_irqsave(&irq_desc[i].lock, flags);
                action = irq_desc[i].action;
-               if (!action) 
+               if (!action)
                        goto skip;
                seq_printf(p, "%3d: ",i);
 #ifndef CONFIG_SMP
index 993abc868e54984253b9a10a0150762f34017e3e..ece4564919d8f76c077ccf8cdbb6c95545f8d468 100644 (file)
@@ -313,7 +313,7 @@ asmlinkage int sys32_sysinfo(struct sysinfo32 *info)
        struct sysinfo s;
        int ret, err;
        mm_segment_t old_fs = get_fs ();
-       
+
        set_fs (KERNEL_DS);
        ret = sys_sysinfo(&s);
        set_fs (old_fs);
@@ -546,21 +546,21 @@ struct msgbuf32 { s32 mtype; char mtext[1]; };
 struct ipc_perm32
 {
        key_t             key;
-        compat_uid_t  uid;
-        compat_gid_t  gid;
-        compat_uid_t  cuid;
-        compat_gid_t  cgid;
+        __compat_uid_t  uid;
+        __compat_gid_t  gid;
+        __compat_uid_t  cuid;
+        __compat_gid_t  cgid;
         compat_mode_t  mode;
         unsigned short  seq;
 };
 
 struct ipc64_perm32 {
        key_t key;
-       compat_uid_t uid;
-       compat_gid_t gid;
-       compat_uid_t cuid;
-       compat_gid_t cgid;
-       compat_mode_t   mode; 
+       __compat_uid_t uid;
+       __compat_gid_t gid;
+       __compat_uid_t cuid;
+       __compat_gid_t cgid;
+       compat_mode_t   mode;
        unsigned short  seq;
        unsigned short __pad1;
        unsigned int __unused1;
@@ -1334,17 +1334,17 @@ asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset,
        mm_segment_t old_fs = get_fs();
        int ret;
        off_t of;
-       
+
        if (offset && get_user(of, offset))
                return -EFAULT;
-               
+
        set_fs(KERNEL_DS);
        ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
        set_fs(old_fs);
-       
+
        if (offset && put_user(of, offset))
                return -EFAULT;
-               
+
        return ret;
 }
 
@@ -1362,11 +1362,11 @@ static unsigned char socketcall_nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
 #undef AL
 
 /*
- *     System call vectors. 
+ *     System call vectors.
  *
  *     Argument checking cleaned up. Saved 20% in size.
  *  This function doesn't need to set the kernel lock because
- *  it is set by the callees. 
+ *  it is set by the callees.
  */
 
 asmlinkage long sys32_socketcall(int call, unsigned int *args32)
@@ -1402,11 +1402,11 @@ asmlinkage long sys32_socketcall(int call, unsigned int *args32)
        /* copy_from_user should be SMP safe. */
        if (copy_from_user(a, args32, socketcall_nargs[call]))
                return -EFAULT;
-               
+
        a0=a[0];
        a1=a[1];
-       
-       switch(call) 
+
+       switch(call)
        {
                case SYS_SOCKET:
                        err = sys_socket(a0,a1,a[2]);
index eed29fc9dc823d3ce9af99a016c5d7c34b67607f..86e42c633f73a60e95a939a7433b18b89118dd1b 100644 (file)
@@ -35,7 +35,7 @@ EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(strcat);
 EXPORT_SYMBOL(strchr);
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 EXPORT_SYMBOL(strncmp);
 #endif
 EXPORT_SYMBOL(strlen);
index 6e70c42c20589f2a401033927dcc33273a1d017e..e4f2f80113876a5ac0d3312344852343973b8032 100644 (file)
@@ -70,7 +70,7 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
 
        /* New thread loses kernel privileges. */
        status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|KU_MASK);
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        status &= ~ST0_FR;
        status |= (current->thread.mflags & MF_32BIT_REGS) ? 0 : ST0_FR;
 #endif
@@ -236,10 +236,10 @@ static int __init get_frame_info(struct mips_frame_info *info, void *func)
                        break;
 
                if (
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
                    ip->i_format.opcode == sw_op &&
 #endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
                    ip->i_format.opcode == sd_op &&
 #endif
                    ip->i_format.rs == 29)
@@ -353,7 +353,7 @@ schedule_timeout_caller:
 
 out:
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        if (current->thread.mflags & MF_32BIT_REGS) /* Kludge for 32-bit ps  */
                pc &= 0xffffffffUL;
 #endif
index 92e70ca3bff9d60bb6bf51a660f75b09496d089c..0b571a5b4b83a7705a3a0d06ffd97de88432a866 100644 (file)
@@ -124,7 +124,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                        if (tsk_used_math(child)) {
                                fpureg_t *fregs = get_fpu_regs(child);
 
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
                                /*
                                 * The odd registers are actually the high
                                 * order bits of the values stored in the even
@@ -135,7 +135,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                                else
                                        tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff);
 #endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
                                tmp = fregs[addr - FPR_BASE];
 #endif
                        } else {
@@ -213,7 +213,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                                       sizeof(child->thread.fpu.hard));
                                child->thread.fpu.hard.fcr31 = 0;
                        }
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
                        /*
                         * The odd registers are actually the high order bits
                         * of the values stored in the even registers - unless
@@ -227,7 +227,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                                fregs[addr - FPR_BASE] |= data;
                        }
 #endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
                        fregs[addr - FPR_BASE] = data;
 #endif
                        break;
@@ -304,14 +304,14 @@ out:
 static inline int audit_arch(void)
 {
 #ifdef CONFIG_CPU_LITTLE_ENDIAN
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        if (!(current->thread.mflags & MF_32BIT_REGS))
                return AUDIT_ARCH_MIPSEL64;
 #endif /* MIPS64 */
        return AUDIT_ARCH_MIPSEL;
 
 #else /* big endian... */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        if (!(current->thread.mflags & MF_32BIT_REGS))
                return AUDIT_ARCH_MIPS64;
 #endif /* MIPS64 */
index 243e7b629af61f694b927f3004493e4d7a84d4f1..f10019640ee997847d1e7548cd4971efb5afd437 100644 (file)
@@ -35,7 +35,7 @@
 /*
  * FPU context is saved iff the process has used it's FPU in the current
  * time slice as indicated by TIF_USEDFPU.  In any case, the CU1 bit for user
- * space STATUS register should be 0, so that a process *always* starts its 
+ * space STATUS register should be 0, so that a process *always* starts its
  * userland with FPU disabled after each context switch.
  *
  * FPU will be enabled as soon as the process accesses FPU again, through
@@ -55,7 +55,7 @@ LEAF(resume)
        cpu_save_nonscratch a0
        sw      ra, THREAD_REG31(a0)
 
-       /* 
+       /*
         * check if we need to save FPU registers
         */
        lw      t3, TASK_THREAD_INFO(a0)
index ebb643d8d14c0812c6ec348cb29b56848b0c5ec3..aba665bcb3864e22b73c69f4ec7c94ae39199d29 100644 (file)
@@ -36,7 +36,7 @@
 LEAF(_save_fp_context)
        cfc1    t1, fcr31
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        /* Store the 16 odd double precision registers */
        EX      sdc1 $f1, SC_FPREGS+8(a0)
        EX      sdc1 $f3, SC_FPREGS+24(a0)
@@ -118,7 +118,7 @@ LEAF(_save_fp_context32)
  */
 LEAF(_restore_fp_context)
        EX      lw t0, SC_FPC_CSR(a0)
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        EX      ldc1 $f1, SC_FPREGS+8(a0)
        EX      ldc1 $f3, SC_FPREGS+24(a0)
        EX      ldc1 $f5, SC_FPREGS+40(a0)
index 1fc3b2eb12bd2d80de44b5f86c479a1487161360..e02b7722ccb8d1753e073bf85eb08b18849f7f8f 100644 (file)
@@ -33,7 +33,7 @@
 /*
  * FPU context is saved iff the process has used it's FPU in the current
  * time slice as indicated by _TIF_USEDFPU.  In any case, the CU1 bit for user
- * space STATUS register should be 0, so that a process *always* starts its 
+ * space STATUS register should be 0, so that a process *always* starts its
  * userland with FPU disabled after each context switch.
  *
  * FPU will be enabled as soon as the process accesses FPU again, through
  * Save a thread's fp context.
  */
 LEAF(_save_fp)
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        mfc0    t1, CP0_STATUS
 #endif
        fpu_save_double a0 t1 t0 t2             # clobbers t1
@@ -142,7 +142,7 @@ LEAF(_init_fpu)
 
        li      t1, -1                          # SNaN
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        sll     t0, t0, 5
        bgez    t0, 1f                          # 16 / 32 register mode?
 
@@ -164,7 +164,7 @@ LEAF(_init_fpu)
        dmtc1   t1, $f31
 1:
 #endif
-       
+
 #ifdef CONFIG_CPU_MIPS32
        mtc1    t1, $f0
        mtc1    t1, $f1
index 3a240e3e004c368c10cc86df391ac2fc2ceefdbe..12b531c295c40e352b4f88d42aadfbd2a38e0fec 100644 (file)
@@ -241,7 +241,7 @@ static inline int parse_rd_cmdline(unsigned long* rd_start, unsigned long* rd_en
        if (*tmp)
                strcat(command_line, tmp);
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        /* HACK: Guess if the sign extension was forgotten */
        if (start > 0x0000000080000000 && start < 0x00000000ffffffff)
                start |= 0xffffffff00000000;
@@ -446,7 +446,7 @@ static inline void resource_init(void)
 {
        int i;
 
-#if defined(CONFIG_MIPS64) && !defined(CONFIG_BUILD_ELF64)
+#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
        /*
         * The 64bit code in 32bit object format trick can't represent
         * 64bit wide relocations for linker script symbols.
index 65ee15396ffdefc52782ab24bd983baf08e90f30..0209c1dd1429a1c87a1da11a2f2ce1f14f705a30 100644 (file)
@@ -425,13 +425,12 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info,
                setup_frame(ka, regs, sig, oldset);
 #endif
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
index c1a69cf232f937e68cac85eaa8c47aec58d6650b..8ddfbd8d425a9532ea994ae519931a8067ea5af0 100644 (file)
@@ -558,7 +558,7 @@ static inline int setup_sigcontext32(struct pt_regs *regs,
        if (!used_math())
                goto out;
 
-       /* 
+       /*
         * Save FPU state to signal context.  Signal handler will "inherit"
         * current FPU state.
         */
@@ -751,13 +751,12 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info,
        else
                setup_frame(ka, regs, sig, oldset);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 int do_signal32(sigset_t *oldset, struct pt_regs *regs)
index f3bf0e43b8bb207ed0d50d4f01a14525509d2195..b4659546271789c6498967d40f81bb68e7283f83 100644 (file)
@@ -632,10 +632,7 @@ asmlinkage int irix_stime(int value)
        write_seqlock_irq(&xtime_lock);
        xtime.tv_sec = value;
        xtime.tv_nsec = 0;
-       time_adjust = 0;                        /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
        write_sequnlock_irq(&xtime_lock);
 
        return 0;
index 648c82292ed6c8ab8870b09902d694de87f211a1..0dd0df7a3b04af60f095e03bd33cd6db0c3adac9 100644 (file)
@@ -223,10 +223,7 @@ int do_settimeofday(struct timespec *tv)
        set_normalized_timespec(&xtime, sec, nsec);
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
-       time_adjust = 0;                        /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
 
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
@@ -442,7 +439,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
         * called as close as possible to 500 ms before the new second starts.
         */
        write_seqlock(&xtime_lock);
-       if ((time_status & STA_UNSYNC) == 0 &&
+       if (ntp_synced() &&
            xtime.tv_sec > last_rtc_update + 660 &&
            (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
            (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
index 56c36e42e0a69fb08a981b3882aa21d60db896b8..a53b1ed7b38625540bddb2af051015f617d6387c 100644 (file)
@@ -924,7 +924,7 @@ void __init per_cpu_trap_init(void)
         * flag that some firmware may have left set and the TS bit (for
         * IP27).  Set XX for ISA IV code to work.
         */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        status_set |= ST0_FR|ST0_KX|ST0_SX|ST0_UX;
 #endif
        if (current_cpu_data.isa_level == MIPS_CPU_ISA_IV)
index 3f24a1d45865bf1d85ddad15fc70797cea83fad3..36c5212e092887cd163720963a3af2590b20ef5a 100644 (file)
@@ -240,7 +240,7 @@ static inline int emulate_load_store_insn(struct pt_regs *regs,
                break;
 
        case lwu_op:
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
                /*
                 * A 32-bit kernel might be running on a 64-bit processor.  But
                 * if we're on a 32-bit processor and an i-cache incoherency
@@ -278,13 +278,13 @@ static inline int emulate_load_store_insn(struct pt_regs *regs,
                *newvalue = value;
                *regptr = &regs->regs[insn.i_format.rt];
                break;
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
 
                /* Cannot handle 64-bit instructions in 32-bit kernel */
                goto sigill;
 
        case ld_op:
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
                /*
                 * A 32-bit kernel might be running on a 64-bit processor.  But
                 * if we're on a 32-bit processor and an i-cache incoherency
@@ -320,7 +320,7 @@ static inline int emulate_load_store_insn(struct pt_regs *regs,
                *newvalue = value;
                *regptr = &regs->regs[insn.i_format.rt];
                break;
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
 
                /* Cannot handle 64-bit instructions in 32-bit kernel */
                goto sigill;
@@ -392,7 +392,7 @@ static inline int emulate_load_store_insn(struct pt_regs *regs,
                break;
 
        case sd_op:
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
                /*
                 * A 32-bit kernel might be running on a 64-bit processor.  But
                 * if we're on a 32-bit processor and an i-cache incoherency
@@ -428,7 +428,7 @@ static inline int emulate_load_store_insn(struct pt_regs *regs,
                if (res)
                        goto fault;
                break;
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
 
                /* Cannot handle 64-bit instructions in 32-bit kernel */
                goto sigill;
index e830d788c10653a066c1b6eb4693775625887593..482ac310c937dd55a651e903b744358933bc33ad 100644 (file)
@@ -15,7 +15,7 @@ SECTIONS
   /* This is the value for an Origin kernel, taken from an IRIX kernel.  */
   /* . = 0xc00000000001c000; */
 
-  /* Set the vaddr for the text segment to a value 
+  /* Set the vaddr for the text segment to a value
         >= 0xa800 0000 0001 9000 if no symmon is going to configured
         >= 0xa800 0000 0030 0000 otherwise  */
 
index f6add041ebec1a77dfcd33e3bf787d5e76641f2c..ca26e554615ee62bd99522106cd5f2cf9594034a 100644 (file)
@@ -1,7 +1,7 @@
-/* 
+/*
  * Atmel AT93C46 serial eeprom driver
  *
- * Brian Murphy <brian.murphy@eicon.com> 
+ * Brian Murphy <brian.murphy@eicon.com>
  *
  */
 #include <linux/kernel.h>
 
 struct at93c_defs *at93c;
 
-static void at93c_reg_write(u32 val) 
+static void at93c_reg_write(u32 val)
 {
        *at93c->reg = val;
 }
 
-static u32 at93c_reg_read(void) 
+static u32 at93c_reg_read(void)
 {
        u32 tmp = *at93c->reg;
        return tmp;
@@ -81,7 +81,7 @@ static u8 at93c_read_byte(void)
 }
 
 static void at93c_write_bits(u32 data, int size)
-{               
+{
        int i;
        int shift = size - 1;
        u32 mask = (1 << shift);
@@ -90,7 +90,7 @@ static void at93c_write_bits(u32 data, int size)
                at93c_write_databit((data & mask) >> shift);
                data <<= 1;
        }
-}       
+}
 
 static void at93c_init_op(void)
 {
@@ -104,8 +104,8 @@ static void at93c_end_op(void)
        lasat_ndelay(250);
 }
 
-static void at93c_wait(void) 
-{ 
+static void at93c_wait(void)
+{
        at93c_init_op();
        while (!at93c_read_databit())
                ;
index a912ac2171b0a642bd301d11d670410a4ae00341..cfe2f99b1d440884ab84f4da1e2bad8f989c3e48 100644 (file)
@@ -1,7 +1,7 @@
-/* 
+/*
  * Atmel AT93C46 serial eeprom driver
  *
- * Brian Murphy <brian.murphy@eicon.com> 
+ * Brian Murphy <brian.murphy@eicon.com>
  *
  */
 
index 7bbf6cf923c98f85f7a00e556558e2ccc64fe7a2..9d7812e03dcd9322f5410963e8a63398878d57d2 100644 (file)
@@ -1,7 +1,7 @@
-/* 
- * Dallas Semiconductors 1603 RTC driver 
+/*
+ * Dallas Semiconductors 1603 RTC driver
  *
- * Brian Murphy <brian@murphy.dk> 
+ * Brian Murphy <brian@murphy.dk>
  *
  */
 #include <linux/kernel.h>
 struct ds_defs *ds1603 = NULL;
 
 /* HW specific register functions */
-static void rtc_reg_write(unsigned long val) 
+static void rtc_reg_write(unsigned long val)
 {
        *ds1603->reg = val;
 }
 
-static unsigned long rtc_reg_read(void) 
+static unsigned long rtc_reg_read(void)
 {
        unsigned long tmp = *ds1603->reg;
        return tmp;
@@ -80,7 +80,7 @@ static unsigned int rtc_read_databit(void)
 {
        unsigned int data;
 
-       data = (rtc_datareg_read() & (1 << ds1603->data_read_shift)) 
+       data = (rtc_datareg_read() & (1 << ds1603->data_read_shift))
                >> ds1603->data_read_shift;
        rtc_cycle_clock(rtc_reg_read());
        return data;
index 55f3b0423c203969b87e2895f52a2137bdfbfa7e..c2e5c76a379dd188ad68ebcc2c7571128fe1a10d 100644 (file)
@@ -1,7 +1,7 @@
-/* 
- * Dallas Semiconductors 1603 RTC driver 
+/*
+ * Dallas Semiconductors 1603 RTC driver
  *
- * Brian Murphy <brian@murphy.dk> 
+ * Brian Murphy <brian@murphy.dk>
  *
  */
 #ifndef __DS1603_H
index 18b6430f11be1295697b470c0e0f3a05ecee5487..35ecd6483ef64b79de29b9e8a1c241ce90a3aa39 100644 (file)
@@ -21,7 +21,7 @@ LDSCRIPT= -L$(obj) -Tromscript.normal
 HEAD_DEFINES := -D_kernel_start=0x$(KERNEL_START) \
                -D_kernel_entry=0x$(KERNEL_ENTRY) \
                -D VERSION="\"$(Version)\"" \
-               -D TIMESTAMP=$(shell date +%s) 
+               -D TIMESTAMP=$(shell date +%s)
 
 $(obj)/head.o: $(obj)/head.S $(KERNEL_IMAGE)
        $(CC) -fno-pic $(HEAD_DEFINES) -I$(TOPDIR)/include -c -o $@ $<
index 426bd7de17bb998c1cbbb1a14f4bb9dd128d08ef..efb95f2609c2a1cb1a52e8b21a3ee2eae3f50566 100644 (file)
@@ -27,5 +27,5 @@ reldate:
        .word   TIMESTAMP
 
        .org    0x50
-release:       
+release:
        .string VERSION
index 1148a2d20aa752d9abf702ab1ffe0ad891754a72..c90da163944067f2dbb1aab17874708032d76337 100644 (file)
@@ -15,7 +15,7 @@
  *  with this program; if not, write to the Free Software Foundation, Inc.,
  *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  *
- * Routines for generic manipulation of the interrupts found on the 
+ * Routines for generic manipulation of the interrupts found on the
  * Lasat boards.
  */
 #include <linux/init.h>
@@ -101,7 +101,7 @@ static unsigned long get_int_status_100(void)
        return *lasat_int_status & *lasat_int_mask;
 }
 
-static unsigned long get_int_status_200(void) 
+static unsigned long get_int_status_200(void)
 {
        unsigned long int_status;
 
index 8c784bcf11118d3e96710581869029ba7b04835e..fc9b0e2a6be10d8bee0f2e8ce2fca3dc9c2bc854 100644 (file)
@@ -67,7 +67,7 @@ static void init_flash_sizes(void)
 
        if (mips_machtype == MACH_LASAT_100) {
                lasat_board_info.li_flash_base = 0x1e000000;
-               
+
                lb[LASAT_MTD_BOOTLOADER] = 0x1e400000;
 
                if (lasat_board_info.li_flash_size > 0x200000) {
@@ -103,7 +103,7 @@ int lasat_init_board_info(void)
        memset(&lasat_board_info, 0, sizeof(lasat_board_info));
 
        /* First read the EEPROM info */
-       EEPROMRead(0, (unsigned char *)&lasat_board_info.li_eeprom_info, 
+       EEPROMRead(0, (unsigned char *)&lasat_board_info.li_eeprom_info,
                   sizeof(struct lasat_eeprom_struct));
 
        /* Check the CRC */
@@ -188,7 +188,7 @@ int lasat_init_board_info(void)
        case 0x1:
                lasat_board_info.li_cpu_hz =
                        lasat_board_info.li_bus_hz +
-                       (lasat_board_info.li_bus_hz >> 1);      
+                       (lasat_board_info.li_bus_hz >> 1);
                break;
        case 0x2:
                lasat_board_info.li_cpu_hz =
@@ -271,7 +271,7 @@ void lasat_write_eeprom_info(void)
        lasat_board_info.li_eeprom_info.crc32 = crc;
 
        /* Write the EEPROM info */
-       EEPROMWrite(0, (unsigned char *)&lasat_board_info.li_eeprom_info, 
+       EEPROMWrite(0, (unsigned char *)&lasat_board_info.li_eeprom_info,
                    sizeof(struct lasat_eeprom_struct));
 }
 
index 5637cd153926cdc85f461dff16178b187aa0e156..9ae82c3ffb07d98f990808601e5a9517983e5777 100644 (file)
@@ -1,7 +1,7 @@
-/* 
+/*
  * Picvue PVC160206 display driver
  *
- * Brian Murphy <brian@murphy.dk> 
+ * Brian Murphy <brian@murphy.dk>
  *
  */
 #include <linux/kernel.h>
@@ -24,12 +24,12 @@ struct pvc_defs *picvue = NULL;
 
 DECLARE_MUTEX(pvc_sem);
 
-static void pvc_reg_write(u32 val) 
+static void pvc_reg_write(u32 val)
 {
        *picvue->reg = val;
 }
 
-static u32 pvc_reg_read(void) 
+static u32 pvc_reg_read(void)
 {
        u32 tmp = *picvue->reg;
        return tmp;
@@ -65,12 +65,12 @@ static u8 pvc_read_data(void)
 {
        u32 data = pvc_reg_read();
        u8 byte;
-       data |= picvue->rw; 
+       data |= picvue->rw;
        data &= ~picvue->rs;
        pvc_reg_write(data);
        ndelay(40);
        byte = pvc_read_byte(data);
-       data |= picvue->rs; 
+       data |= picvue->rs;
        pvc_reg_write(data);
        return byte;
 }
index 74a39039135db23c7a2a82ebca22d2c2f3e74bfb..2a96bf971897aa044f957d88bd7239ef53fa67f0 100644 (file)
@@ -1,7 +1,7 @@
-/* 
+/*
  * Picvue PVC160206 display driver
  *
- * Brian Murphy <brian.murphy@eicon.com> 
+ * Brian Murphy <brian.murphy@eicon.com>
  *
  */
 #include <asm/semaphore.h>
index eaa2b4625124a297057d1927c4fe6e76f2234356..cce7cddcdb084a37409913db23549ef13676012f 100644 (file)
@@ -1,7 +1,7 @@
-/* 
+/*
  * Picvue PVC160206 display driver
  *
- * Brian Murphy <brian.murphy@eicon.com> 
+ * Brian Murphy <brian.murphy@eicon.com>
  *
  */
 #include <linux/kernel.h>
@@ -51,10 +51,10 @@ static int pvc_proc_read_line(char *page, char **start,
         page += sprintf(page, "%s\n", pvc_lines[lineno]);
        up(&pvc_sem);
 
-        return page - origpage; 
+        return page - origpage;
 }
 
-static int pvc_proc_write_line(struct file *file, const char *buffer,            
+static int pvc_proc_write_line(struct file *file, const char *buffer,
                            unsigned long count, void *data)
 {
         int origcount = count;
@@ -119,7 +119,7 @@ static int pvc_proc_read_scroll(char *page, char **start,
         page += sprintf(page, "%d\n", scroll_dir * scroll_interval);
        up(&pvc_sem);
 
-        return page - origpage; 
+        return page - origpage;
 }
 
 
index ca62881c9e52e1142f8aecb9b40598b8eb6919df..88c7ab871ec44bbe0c4f7dae9a92ca5c58b36da7 100644 (file)
@@ -42,7 +42,7 @@ static void null_prom_putc(char c)
 /* these are functions provided by the bootloader */
 static void (* prom_putc)(char c) = null_prom_putc;
 void (* prom_printf)(const char * fmt, ...) = null_prom_printf;
-void (* prom_display)(const char *string, int pos, int clear) = 
+void (* prom_display)(const char *string, int pos, int clear) =
                null_prom_display;
 void (* prom_monitor)(void) = null_prom_monitor;
 
index 37e4912ee1c88baa861b17784a696d334b441ad8..8d7d7a454f9a4e6f439042422842fa87d313419b 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * Thomas Horsten <thh@lasat.com>
  * Copyright (C) 2000 LASAT Networks A/S.
  *
index e371ed5cbe347a0e2475e1ede66ab1e15c89a17c..f2604fab9a9961912d72102318a06a7f94522dcb 100644 (file)
@@ -105,7 +105,7 @@ static int lasat_panic_prom_monitor(struct notifier_block *this,
        return NOTIFY_DONE;
 }
 
-static struct notifier_block lasat_panic_block[] = 
+static struct notifier_block lasat_panic_block[] =
 {
        { lasat_panic_display, NULL, INT_MAX },
        { lasat_panic_prom_monitor, NULL, INT_MIN }
@@ -120,7 +120,7 @@ static void lasat_timer_setup(struct irqaction *irq)
 {
 
        write_c0_compare(
-               read_c0_count() + 
+               read_c0_count() +
                mips_hpt_frequency / HZ);
        change_c0_status(ST0_IM, IE_IRQ0 | IE_IRQ5);
 }
index 1c0cc620a43f865e5da1bbd84abe928aa45b773f..8ff43a1c1e99c43f8cbbf5f49310f448b5fc87b4 100644 (file)
 
 static DECLARE_MUTEX(lasat_info_sem);
 
-/* Strategy function to write EEPROM after changing string entry */ 
+/* Strategy function to write EEPROM after changing string entry */
 int sysctl_lasatstring(ctl_table *table, int *name, int nlen,
                void *oldval, size_t *oldlenp,
                void *newval, size_t newlen, void **context)
 {
        int r;
        down(&lasat_info_sem);
-       r = sysctl_string(table, name, 
+       r = sysctl_string(table, name,
                          nlen, oldval, oldlenp, newval, newlen, context);
        if (r < 0) {
                up(&lasat_info_sem);
@@ -74,7 +74,7 @@ int proc_dolasatstring(ctl_table *table, int write, struct file *filp,
        return 0;
 }
 
-/* proc function to write EEPROM after changing int entry */ 
+/* proc function to write EEPROM after changing int entry */
 int proc_dolasatint(ctl_table *table, int write, struct file *filp,
                       void *buffer, size_t *lenp, loff_t *ppos)
 {
@@ -93,7 +93,7 @@ int proc_dolasatint(ctl_table *table, int write, struct file *filp,
 static int rtctmp;
 
 #ifdef CONFIG_DS1603
-/* proc function to read/write RealTime Clock */ 
+/* proc function to read/write RealTime Clock */
 int proc_dolasatrtc(ctl_table *table, int write, struct file *filp,
                       void *buffer, size_t *lenp, loff_t *ppos)
 {
@@ -165,9 +165,9 @@ static char lasat_bcastaddr[16];
 void update_bcastaddr(void)
 {
        unsigned int ip;
-       
-       ip = (lasat_board_info.li_eeprom_info.ipaddr & 
-               lasat_board_info.li_eeprom_info.netmask) | 
+
+       ip = (lasat_board_info.li_eeprom_info.ipaddr &
+               lasat_board_info.li_eeprom_info.netmask) |
                ~lasat_board_info.li_eeprom_info.netmask;
 
        sprintf(lasat_bcastaddr, "%d.%d.%d.%d",
@@ -205,7 +205,7 @@ int proc_lasat_ip(ctl_table *table, int write, struct file *filp,
                                break;
                        len++;
                }
-               if (len >= sizeof(proc_lasat_ipbuf)-1) 
+               if (len >= sizeof(proc_lasat_ipbuf)-1)
                        len = sizeof(proc_lasat_ipbuf) - 1;
                if (copy_from_user(proc_lasat_ipbuf, buffer, len))
                {
@@ -249,8 +249,8 @@ int proc_lasat_ip(ctl_table *table, int write, struct file *filp,
 }
 #endif /* defined(CONFIG_INET) */
 
-static int sysctl_lasat_eeprom_value(ctl_table *table, int *name, int nlen, 
-                                    void *oldval, size_t *oldlenp, 
+static int sysctl_lasat_eeprom_value(ctl_table *table, int *name, int nlen,
+                                    void *oldval, size_t *oldlenp,
                                     void *newval, size_t newlen,
                                     void **context)
 {
@@ -293,7 +293,7 @@ int proc_lasat_eeprom_value(ctl_table *table, int write, struct file *filp,
                if (!strcmp(filp->f_dentry->d_name.name, "debugaccess"))
                        lasat_board_info.li_eeprom_info.debugaccess = lasat_board_info.li_debugaccess;
        }
-       lasat_write_eeprom_info();      
+       lasat_write_eeprom_info();
        up(&lasat_info_sem);
        return 0;
 }
@@ -316,8 +316,8 @@ static ctl_table lasat_table[] = {
         0644, NULL, &proc_lasat_ip, &sysctl_lasat_intvec},
        {LASAT_NETMASK, "netmask", &lasat_board_info.li_eeprom_info.netmask, sizeof(int),
         0644, NULL, &proc_lasat_ip, &sysctl_lasat_intvec},
-       {LASAT_BCAST, "bcastaddr", &lasat_bcastaddr, 
-               sizeof(lasat_bcastaddr), 0600, NULL, 
+       {LASAT_BCAST, "bcastaddr", &lasat_bcastaddr,
+               sizeof(lasat_bcastaddr), 0600, NULL,
                &proc_dostring, &sysctl_string},
 #endif
        {LASAT_PASSWORD, "passwd_hash", &lasat_board_info.li_eeprom_info.passwd_hash, sizeof(lasat_board_info.li_eeprom_info.passwd_hash),
index fd6a2bafdfcf270be8d13bf9eb812d12f20cc0cd..ad285786e74b341ea9a9e30192e9dbf625f1a96b 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for MIPS-specific library files..
 #
 
-lib-y  += csum_partial.o memset.o watch.o 
+lib-y  += csum_partial.o memset.o watch.o
 
 obj-$(CONFIG_CPU_MIPS32)       += dump_tlb.o
 obj-$(CONFIG_CPU_MIPS64)       += dump_tlb.o
index fd6a2bafdfcf270be8d13bf9eb812d12f20cc0cd..ad285786e74b341ea9a9e30192e9dbf625f1a96b 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for MIPS-specific library files..
 #
 
-lib-y  += csum_partial.o memset.o watch.o 
+lib-y  += csum_partial.o memset.o watch.o
 
 obj-$(CONFIG_CPU_MIPS32)       += dump_tlb.o
 obj-$(CONFIG_CPU_MIPS64)       += dump_tlb.o
index afa8eae18ff672aecc79e1febf02116b50e6c9fc..90ee8d43261f591d2f509bf10ae7c6981e6bc3b5 100644 (file)
@@ -79,7 +79,7 @@
 /*
  * Only on the 64-bit kernel we can made use of 64-bit registers.
  */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 #define USE_DOUBLE
 #endif
 
 #define NBYTES 8
 #define LOG_NBYTES 3
 
-/* 
+/*
  * As we are sharing code base with the mips32 tree (which use the o32 ABI
  * register definitions). We need to redefine the register definitions from
  * the n64 ABI register naming to the o32 ABI register naming.
 #define t5     $13
 #define t6     $14
 #define t7     $15
-       
+
 #else
 
 #define LOAD   lw
index 20a552be02ee400f82c461002fec46d869c18741..99c550632d44a541f29a7c70ee7052ae09869fa9 100644 (file)
@@ -320,7 +320,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx)
        case cop1_op:
                switch (MIPSInst_RS(ir)) {
 
-#if __mips64 && !defined(SINGLE_ONLY_FPU)
+#if defined(__mips64) && !defined(SINGLE_ONLY_FPU)
                case dmfc_op:
                        /* copregister fs -> gpr[rt] */
                        if (MIPSInst_RT(ir) != 0) {
@@ -805,7 +805,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,
                ieee754dp d;
                ieee754sp s;
                int w;
-#if __mips64
+#ifdef __mips64
                s64 l;
 #endif
        } rv;                   /* resulting value */
@@ -950,7 +950,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,
                }
 #endif /* __mips >= 2 */
 
-#if __mips64 && !defined(SINGLE_ONLY_FPU)
+#if defined(__mips64) && !defined(SINGLE_ONLY_FPU)
                case fcvtl_op:{
                        ieee754sp fs;
 
@@ -1125,7 +1125,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,
                }
 #endif
 
-#if __mips64 && !defined(SINGLE_ONLY_FPU)
+#if defined(__mips64) && !defined(SINGLE_ONLY_FPU)
                case fcvtl_op:{
                        ieee754dp fs;
 
@@ -1203,7 +1203,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,
                break;
        }
 
-#if __mips64 && !defined(SINGLE_ONLY_FPU)
+#if defined(__mips64) && !defined(SINGLE_ONLY_FPU)
        case l_fmt:{
                switch (MIPSInst_FUNC(ir)) {
                case fcvts_op:
@@ -1267,7 +1267,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,
        case w_fmt:
                SITOREG(rv.w, MIPSInst_FD(ir));
                break;
-#if __mips64 && !defined(SINGLE_ONLY_FPU)
+#if defined(__mips64) && !defined(SINGLE_ONLY_FPU)
        case l_fmt:
                DITOREG(rv.l, MIPSInst_FD(ir));
                break;
index 04397fec30fc487b8c75a5cd4a9b9a1e5f252064..4002f0cf79f3d443651761b54185b82ed5988c06 100644 (file)
@@ -86,7 +86,7 @@ int fpu_emulator_restore_context(struct sigcontext *sc)
        return err;
 }
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 /*
  * This is the o32 version
  */
index 8f1d875217a21241f5c5fd0c84441c2e783aeb43..19d4b0792460b6ba0be750f5f170690c12bdfb8a 100644 (file)
@@ -122,7 +122,7 @@ void __init arch_init_irq(void)
        int i;
 
        atlas_hw0_icregs = (struct atlas_ictrl_regs *)ioremap (ATLAS_ICTRL_REGS_BASE, sizeof(struct atlas_ictrl_regs *));
-       
+
        /*
         * Mask out all interrupt by writing "1" to all bit position in
         * the interrupt reset reg.
index 31caf0603a3f47dc42db6639e48c27c4d81f970d..311155d1d3ed6955303392c414df35068507528a 100644 (file)
@@ -200,7 +200,7 @@ void __init kgdb_config (void)
                        generic_putDebugChar = saa9730_putDebugChar;
                        generic_getDebugChar = saa9730_getDebugChar;
                }
-               else 
+               else
 #endif
                {
                        speed = rs_kgdb_hook(line, speed);
@@ -243,7 +243,7 @@ void __init prom_init(void)
        mips_revision_corid = MIPS_REVISION_CORID;
 
        if (mips_revision_corid == MIPS_REVISION_CORID_CORE_EMUL) {
-               if (BONITO_PCIDID == 0x0001df53 || 
+               if (BONITO_PCIDID == 0x0001df53 ||
                    BONITO_PCIDID == 0x0003df53)
                        mips_revision_corid = MIPS_REVISION_CORID_CORE_EMUL_BON;
                else
@@ -310,7 +310,7 @@ void __init prom_init(void)
        case MIPS_REVISION_CORID_CORE_MSC:
        case MIPS_REVISION_CORID_CORE_FPGA2:
        case MIPS_REVISION_CORID_CORE_EMUL_MSC:
-               _pcictrl_msc = (unsigned long)ioremap(MIPS_MSC01_PCI_REG_BASE, 0x2000); 
+               _pcictrl_msc = (unsigned long)ioremap(MIPS_MSC01_PCI_REG_BASE, 0x2000);
 
 #ifdef CONFIG_CPU_LITTLE_ENDIAN
                MSC_WRITE(MSC01_PCI_SWAP, MSC01_PCI_SWAP_NOSWAP);
index fe7fc17305a69193d23396d0800de698d4ceff20..16315444dd5acf489f04bbad6231cf0cc8d25201 100644 (file)
@@ -89,7 +89,7 @@ static unsigned int __init estimate_cpu_frequency(void)
         * really calculate the timer frequency
         * For now we hardwire the SEAD board frequency to 12MHz.
         */
-       
+
        if ((prid == (PRID_COMP_MIPS | PRID_IMP_20KC)) ||
            (prid == (PRID_COMP_MIPS | PRID_IMP_25KF)))
                count = 12000000;
index 3377e66de9eb350892f2c6bf9007c583b23672e3..df6db6419ae9906402398b575fc04389a8714862 100644 (file)
@@ -149,15 +149,15 @@ static int __init malta_setup(void)
                        argptr = prom_getcmdline();
                        if (strstr(argptr, "iobcuncached")) {
                                BONITO_PCICACHECTRL &= ~BONITO_PCICACHECTRL_IOBCCOH_EN;
-                               BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG & 
+                               BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG &
                                        ~(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED |
                                          BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
                                printk("Disabled Bonito IOBC coherency\n");
                        }
                        else {
                                BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_IOBCCOH_EN;
-                               BONITO_PCIMEMBASECFG |= 
-                                       (BONITO_PCIMEMBASECFG_MEMBASE0_CACHED | 
+                               BONITO_PCIMEMBASECFG |=
+                                       (BONITO_PCIMEMBASECFG_MEMBASE0_CACHED |
                                         BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
                                printk("Disabled Bonito IOBC coherency\n");
                        }
index f61e038b4440435b7c0cc3a64e7d6840a7f6f339..b56a0abdc3d4216efa3919737fc0d8da6474b04c 100644 (file)
@@ -5,8 +5,8 @@
 obj-y                          += cache.o extable.o fault.o init.o pgtable.o \
                                   tlbex.o tlbex-fault.o
 
-obj-$(CONFIG_MIPS32)           += ioremap.o pgtable-32.o
-obj-$(CONFIG_MIPS64)           += pgtable-64.o
+obj-$(CONFIG_32BIT)            += ioremap.o pgtable-32.o
+obj-$(CONFIG_64BIT)            += pgtable-64.o
 obj-$(CONFIG_HIGHMEM)          += highmem.o
 
 obj-$(CONFIG_CPU_MIPS32)       += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
index a03ebb2cba6775de0354da8c5ed4c27ab38a9fbc..5ea84bc98c6a3fd8058d04ae8b56646f28dacf60 100644 (file)
@@ -126,13 +126,13 @@ static inline void tx49_blast_icache32(void)
 
        CACHE32_UNROLL32_ALIGN2;
        /* I'm in even chunk.  blast odd chunks */
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
-               for (addr = start + 0x400; addr < end; addr += 0x400 * 2) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
+               for (addr = start + 0x400; addr < end; addr += 0x400 * 2)
                        cache32_unroll32(addr|ws,Index_Invalidate_I);
        CACHE32_UNROLL32_ALIGN;
        /* I'm in odd chunk.  blast even chunks */
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
-               for (addr = start; addr < end; addr += 0x400 * 2) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
+               for (addr = start; addr < end; addr += 0x400 * 2)
                        cache32_unroll32(addr|ws,Index_Invalidate_I);
 }
 
@@ -156,13 +156,13 @@ static inline void tx49_blast_icache32_page_indexed(unsigned long page)
 
        CACHE32_UNROLL32_ALIGN2;
        /* I'm in even chunk.  blast odd chunks */
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
-               for (addr = start + 0x400; addr < end; addr += 0x400 * 2) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
+               for (addr = start + 0x400; addr < end; addr += 0x400 * 2)
                        cache32_unroll32(addr|ws,Index_Invalidate_I);
        CACHE32_UNROLL32_ALIGN;
        /* I'm in odd chunk.  blast even chunks */
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
-               for (addr = start; addr < end; addr += 0x400 * 2) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
+               for (addr = start; addr < end; addr += 0x400 * 2)
                        cache32_unroll32(addr|ws,Index_Invalidate_I);
 }
 
@@ -723,10 +723,10 @@ static void local_r4k_flush_cache_sigtramp(void * arg)
                        ".set push\n\t"
                        ".set noat\n\t"
                        ".set mips3\n\t"
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
                        "la     $at,1f\n\t"
 #endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
                        "dla    $at,1f\n\t"
 #endif
                        "cache  %0,($at)\n\t"
index ab30afd63b3257ee80515a922cf8bd2dfe6f0c72..502f68c664b244d58ec71ca1ee7ee940b45c379d 100644 (file)
@@ -270,7 +270,7 @@ static void local_sb1_flush_icache_range(unsigned long start,
                __sb1_writeback_inv_dcache_all();
        else
                __sb1_writeback_inv_dcache_range(start, end);
-       
+
        /* Just flush the whole icache if the range is big enough */
        if ((end - start) > icache_range_cutoff)
                __sb1_flush_icache_all();
index 13d96d62764ef08f31108e3539287537aa127efc..7166ffe635021a4124e8e9556791fc9cafafedb2 100644 (file)
@@ -25,7 +25,7 @@
 #include <asm/sibyte/sb1250_regs.h>
 #include <asm/sibyte/sb1250_scd.h>
 #endif
+
 /* SB1 definitions */
 
 /* XXX should come from config1 XXX */
@@ -136,14 +136,14 @@ static inline void breakout_cerrd(unsigned int val)
 
 #ifndef CONFIG_SIBYTE_BUS_WATCHER
 
-static void check_bus_watcher(void)              
-{                               
+static void check_bus_watcher(void)
+{
        uint32_t status, l2_err, memio_err;
 
        /* Destructive read, clears register and interrupt */
        status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS));
        /* Bit 31 is always on, but there's no #define for that */
-       if (status & ~(1UL << 31)) {  
+       if (status & ~(1UL << 31)) {
                l2_err = csr_in32(IOADDR(A_BUS_L2_ERRORS));
                memio_err = csr_in32(IOADDR(A_BUS_MEM_IO_ERRORS));
                prom_printf("Bus watcher error counters: %08x %08x\n", l2_err, memio_err);
@@ -153,14 +153,14 @@ static void check_bus_watcher(void)
                       (int)(G_SCD_BERR_TID(status) >> 6),
                       (int)G_SCD_BERR_RID(status),
                       (int)G_SCD_BERR_DCODE(status));
-       } else {                
-               prom_printf("Bus watcher indicates no error\n"); 
-       }                       
-}                                       
-#else                                                    
-extern void check_bus_watcher(void);    
-#endif                                          
-                                
+       } else {
+               prom_printf("Bus watcher indicates no error\n");
+       }
+}
+#else
+extern void check_bus_watcher(void);
+#endif
+
 asmlinkage void sb1_cache_error(void)
 {
        uint64_t cerr_dpa;
index 9895e32b0fceca7d37899a096f62cd18d78f6c42..59e54f12212ecf86a41a22a4705936cdc3b6b2b2 100644 (file)
@@ -162,7 +162,7 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
 
        for (i = 0; i < nents; i++, sg++) {
                unsigned long addr;
+
                addr = (unsigned long) page_address(sg->page);
                if (addr)
                        __dma_sync(addr + sg->offset, sg->length, direction);
@@ -230,9 +230,9 @@ void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
        size_t size, enum dma_data_direction direction)
 {
        unsigned long addr;
+
        BUG_ON(direction == DMA_NONE);
+
        addr = dma_handle + PAGE_OFFSET;
        __dma_sync(addr, size, direction);
 }
@@ -282,9 +282,9 @@ void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
        enum dma_data_direction direction)
 {
        int i;
+
        BUG_ON(direction == DMA_NONE);
+
        /* Make sure that gcc doesn't leave the empty loop body.  */
        for (i = 0; i < nelems; i++, sg++)
                __dma_sync((unsigned long)page_address(sg->page),
index 9c9a271c8a3ae440748d89a22c464ea46444c46c..dc6830b10fab774fde2a19cdfbdc1b400df14ead 100644 (file)
@@ -96,7 +96,7 @@ static void __init kmap_init(void)
        kmap_prot = PAGE_KERNEL;
 }
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 static void __init fixrange_init(unsigned long start, unsigned long end,
        pgd_t *pgd_base)
 {
@@ -125,7 +125,7 @@ static void __init fixrange_init(unsigned long start, unsigned long end,
                j = 0;
        }
 }
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
 #endif /* CONFIG_HIGHMEM */
 
 #ifndef CONFIG_NEED_MULTIPLE_NODES
@@ -258,7 +258,7 @@ void __init mem_init(void)
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        /* Switch from KSEG0 to XKPHYS addresses */
        start = (unsigned long)phys_to_virt(CPHYSADDR(start));
        end = (unsigned long)phys_to_virt(CPHYSADDR(end));
@@ -286,7 +286,7 @@ void free_initmem(void)
 
        addr = (unsigned long) &__init_begin;
        while (addr < (unsigned long) &__init_end) {
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
                page = PAGE_OFFSET | CPHYSADDR(addr);
 #else
                page = addr;
index 59d131b5e536811917691bd12bf2b936c11a9f4c..1b6df7133c1e1bdcb72ffbcbdbd45d9f8bf92f07 100644 (file)
@@ -114,7 +114,7 @@ static inline void copy_page_cpu(void *to, void *from)
        "       pref    " SB1_PREF_STORE_STREAMED_HINT ",  -64(%1)\n"
        "       pref    " SB1_PREF_LOAD_STREAMED_HINT  ",  -32(%0)\n"
        "1:     pref    " SB1_PREF_STORE_STREAMED_HINT ",  -32(%1)\n"
-# ifdef CONFIG_MIPS64
+# ifdef CONFIG_64BIT
        "       ld      $8, -128(%0)    \n"  /* Block copy a cacheline */
        "       ld      $9, -120(%0)    \n"
        "       ld      $10, -112(%0)   \n"
@@ -148,7 +148,7 @@ static inline void copy_page_cpu(void *to, void *from)
        "       daddiu  %0, %0, -128    \n"
        "       daddiu  %1, %1, -128    \n"
 #endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        "       ld      $8, 0(%0)       \n"  /* Block copy a cacheline */
        "1:     ld      $9, 8(%0)       \n"
        "       ld      $10, 16(%0)     \n"
@@ -178,7 +178,7 @@ static inline void copy_page_cpu(void *to, void *from)
        "       daddiu  %0, %0, 32      \n"
        "       daddiu  %1, %1, 32      \n"
        "       bnel    %0, %2, 1b      \n"
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        "        ld     $8, 0(%0)       \n"
 #else
        "        lw     $2, 0(%0)       \n"
@@ -186,7 +186,7 @@ static inline void copy_page_cpu(void *to, void *from)
        "       .set    pop             \n"
        : "+r" (src), "+r" (dst)
        : "r" (end)
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        : "$8","$9","$10","$11","memory");
 #else
        : "$2","$3","$6","$7","$8","$9","$10","$11","memory");
@@ -198,7 +198,7 @@ static inline void copy_page_cpu(void *to, void *from)
 
 /*
  * Pad descriptors to cacheline, since each is exclusively owned by a
- * particular CPU. 
+ * particular CPU.
  */
 typedef struct dmadscr_s {
        u64 dscr_a;
index 87e229f4d3d5c354b5ce3d8acf5290f8a00c23bf..6569be3983c79fde6e950aa7823b294f89dedac5 100644 (file)
@@ -448,7 +448,7 @@ L_LA(_r3000_write_probe_fail)
 L_LA(_r3000_write_probe_ok)
 
 /* convenience macros for instructions */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 # define i_LW(buf, rs, rt, off) i_ld(buf, rs, rt, off)
 # define i_SW(buf, rs, rt, off) i_sd(buf, rs, rt, off)
 # define i_SLL(buf, rs, rt, sh) i_dsll(buf, rs, rt, sh)
@@ -486,7 +486,7 @@ L_LA(_r3000_write_probe_ok)
 #define i_ssnop(buf) i_sll(buf, 0, 0, 1)
 #define i_ehb(buf) i_sll(buf, 0, 0, 3)
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 static __init int __attribute__((unused)) in_compat_space_p(long addr)
 {
        /* Is this address in 32bit compat space? */
@@ -516,7 +516,7 @@ static __init int rel_lo(long val)
 
 static __init void i_LA_mostly(u32 **buf, unsigned int rs, long addr)
 {
-#if CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        if (!in_compat_space_p(addr)) {
                i_lui(buf, rs, rel_highest(addr));
                if (rel_higher(addr))
@@ -682,7 +682,7 @@ static void il_bgezl(u32 **p, struct reloc **r, unsigned int reg,
 #define C0_EPC         14
 #define C0_XCONTEXT    20
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 # define GET_CONTEXT(buf, reg) i_MFC0(buf, reg, C0_XCONTEXT)
 #else
 # define GET_CONTEXT(buf, reg) i_MFC0(buf, reg, C0_CONTEXT)
@@ -923,7 +923,7 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l,
        }
 }
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 /*
  * TMP and PTR are scratch.
  * TMP will be clobbered, PTR will hold the pmd entry.
@@ -1010,7 +1010,7 @@ build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r,
        }
 }
 
-#else /* !CONFIG_MIPS64 */
+#else /* !CONFIG_64BIT */
 
 /*
  * TMP and PTR are scratch.
@@ -1038,7 +1038,7 @@ build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
        i_addu(p, ptr, ptr, tmp); /* add in pgd offset */
 }
 
-#endif /* !CONFIG_MIPS64 */
+#endif /* !CONFIG_64BIT */
 
 static __init void build_adjust_context(u32 **p, unsigned int ctx)
 {
@@ -1159,7 +1159,7 @@ static void __init build_r4000_tlb_refill_handler(void)
                /* No need for i_nop */
        }
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */
 #else
        build_get_pgde32(&p, K0, K1); /* get pgd in K1 */
@@ -1171,7 +1171,7 @@ static void __init build_r4000_tlb_refill_handler(void)
        l_leave(&l, p);
        i_eret(&p); /* return from trap */
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        build_get_pgd_vmalloc64(&p, &l, &r, K0, K1);
 #endif
 
@@ -1182,7 +1182,7 @@ static void __init build_r4000_tlb_refill_handler(void)
         * need three, with the the second nop'ed and the third being
         * unused.
         */
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
        if ((p - tlb_handler) > 64)
                panic("TLB refill handler space exceeded");
 #else
@@ -1195,12 +1195,12 @@ static void __init build_r4000_tlb_refill_handler(void)
        /*
         * Now fold the handler in the TLB refill handler space.
         */
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
        f = final_handler;
        /* Simplest case, just copy the handler. */
        copy_handler(relocs, labels, tlb_handler, p, f);
        final_len = p - tlb_handler;
-#else /* CONFIG_MIPS64 */
+#else /* CONFIG_64BIT */
        f = final_handler + 32;
        if ((p - tlb_handler) <= 32) {
                /* Just copy the handler. */
@@ -1235,7 +1235,7 @@ static void __init build_r4000_tlb_refill_handler(void)
                copy_handler(relocs, labels, split, p, final_handler);
                final_len = (f - (final_handler + 32)) + (p - split);
        }
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
 
        resolve_relocs(relocs, labels);
        printk("Synthesized TLB refill handler (%u instructions).\n",
@@ -1605,7 +1605,7 @@ build_r4000_tlbchange_handler_head(u32 **p, struct label **l,
                                   struct reloc **r, unsigned int pte,
                                   unsigned int ptr)
 {
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        build_get_pmde64(p, l, r, pte, ptr); /* get pmd in ptr */
 #else
        build_get_pgde32(p, pte, ptr); /* get pgd in ptr */
@@ -1636,7 +1636,7 @@ build_r4000_tlbchange_handler_tail(u32 **p, struct label **l,
        l_leave(l, *p);
        i_eret(p); /* return from trap */
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        build_get_pgd_vmalloc64(p, l, r, tmp, ptr);
 #endif
 }
index 43fd5a58077c51ee63cd268eb0c496583f96c05f..55bc789733f2dcae18aab4f811aa816031c51a3d 100644 (file)
                SAVE_ALL
                CLI
                .set    at
-               mfc0    t0, CP0_CAUSE  
+               mfc0    t0, CP0_CAUSE
                mfc0    t2, CP0_STATUS
 
                and     t0, t2
-        
+
                andi    t1, t0, STATUSF_IP0     /* sw0 software interrupt */
                bnez    t1, ll_sw0_irq
                andi    t1, t0, STATUSF_IP1     /* sw1 software interrupt */
@@ -103,25 +103,25 @@ ll_pcia_irq:
                move    a1, sp
                jal     do_IRQ
                j       ret_from_irq
-       
+
 ll_pcib_irq:
                li      a0, 5
                move    a1, sp
                jal     do_IRQ
                j       ret_from_irq
-       
+
 ll_uart_irq:
                li      a0, 6
                move    a1, sp
                jal     do_IRQ
                j       ret_from_irq
-       
+
 ll_cputimer_irq:
                li      a0, 7
                move    a1, sp
                jal     ll_timer_interrupt
                j       ret_from_irq
-       
+
 ll_mv64340_decode_irq:
                move    a0, sp
                jal     ll_mv64340_irq
index fa5982ac0ac61db403e023e868bdce6e941ba8d0..14ae2e71358506b3364304cce3b7315774b3d7c1 100644 (file)
@@ -64,7 +64,7 @@ static u8 exchange_bit(u8 val, u8 cs)
 
        /* turn the clock off and read-strobe */
        JAGUAR_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);
-       
+
        /* return the data */
        return ((JAGUAR_FPGA_READ(EEPROM_MODE) >> 3) & 0x1);
 }
@@ -90,7 +90,7 @@ void get_mac(char dest[6])
 }
 #endif
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 
 unsigned long signext(unsigned long addr)
 {
@@ -143,7 +143,7 @@ char *arg64(unsigned long addrin, int arg_index)
 
        return p;
 }
-#endif  /* CONFIG_MIPS64 */
+#endif  /* CONFIG_64BIT */
 
 /* PMON passes arguments in C main() style */
 void __init prom_init(void)
@@ -158,7 +158,7 @@ void __init prom_init(void)
 //     ja_setup_console();     /* The very first thing.  */
 #endif
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        char *ptr;
 
        printk("Mips64 Jaguar-ATX\n");
@@ -201,7 +201,7 @@ void __init prom_init(void)
        }
        printk("arcs_cmdline: %s\n", arcs_cmdline);
 
-#else   /* CONFIG_MIPS64 */
+#else   /* CONFIG_64BIT */
        /* save the PROM vectors for debugging use */
        debug_vectors = cv;
 
@@ -226,7 +226,7 @@ void __init prom_init(void)
                }
                env++;
        }
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
        mips_machgroup = MACH_GROUP_MOMENCO;
        mips_machtype = MACH_MOMENCO_JAGUAR_ATX;
 
index 48039484cdf98ab85d95d29d466ff505ac66a2a9..c4236b1e59fa55b8d1b4ead6b51751903f82289e 100644 (file)
@@ -27,7 +27,7 @@
 void momenco_jaguar_restart(char *command)
 {
        /* base address of timekeeper portion of part */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        void *nvram = (void*) 0xfffffffffc807000;
 #else
        void *nvram = (void*) 0xfc807000;
index 30462e715066a469437b303775d1073230b1edc4..90288cf2b1e083556c8acb51ac2ea1b996a52f5d 100644 (file)
@@ -105,7 +105,7 @@ void __init bus_error_init(void) { /* nothing */ }
 
 static __init void wire_stupidity_into_tlb(void)
 {
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
        write_c0_wired(0);
        local_flush_tlb_all();
 
@@ -451,7 +451,7 @@ static int  __init momenco_jaguar_atx_setup(void)
 #ifdef GEMDEBUG_TRACEBUFFER
        {
          unsigned int tbControl;
-         tbControl = 
+         tbControl =
            0 << 26 |  /* post trigger delay 0 */
                    0x2 << 16 |         /* sequential trace mode */
            //      0x0 << 16 |         /* non-sequential trace mode */
index 89c17a0c0bedbbf6b68e750a5fe46a5ca7af5404..c4fa9c525faaa56fb476454c5fd78a79772f1994 100644 (file)
@@ -93,7 +93,7 @@ void get_mac(char dest[6])
 #endif
 
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 
 unsigned long signext(unsigned long addr)
 {
@@ -145,7 +145,7 @@ char *arg64(unsigned long addrin, int arg_index)
 
        return p;
 }
-#endif  /* CONFIG_MIPS64 */
+#endif  /* CONFIG_64BIT */
 
 void __init prom_init(void)
 {
@@ -155,7 +155,7 @@ void __init prom_init(void)
        struct callvectors *cv = (struct callvectors *) fw_arg3;
        int i;
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        char *ptr;
        printk("prom_init - MIPS64\n");
 
@@ -198,7 +198,7 @@ void __init prom_init(void)
        }
        printk("arcs_cmdline: %s\n", arcs_cmdline);
 
-#else   /* CONFIG_MIPS64 */
+#else   /* CONFIG_64BIT */
 
        /* save the PROM vectors for debugging use */
        debug_vectors = cv;
@@ -224,7 +224,7 @@ void __init prom_init(void)
                }
                env++;
        }
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
 
        mips_machgroup = MACH_GROUP_MOMENCO;
        mips_machtype = MACH_MOMENCO_OCELOT_3;
@@ -234,7 +234,7 @@ void __init prom_init(void)
        get_mac(prom_mac_addr_base);
 #endif
 
-#ifndef CONFIG_MIPS64
+#ifndef CONFIG_64BIT
        debug_vectors->printf("Booting Linux kernel...\n");
 #endif
 }
index 2f2430648abc075ca168647b90696b944426e47d..52349d9bf1be8f5b3d3a1238a8145ae90721a5dc 100644 (file)
                SAVE_ALL
                CLI
                .set    at
-               mfc0    t0, CP0_CAUSE  
+               mfc0    t0, CP0_CAUSE
                mfc0    t2, CP0_STATUS
 
                and     t0, t2
-        
+
                andi    t1, t0, STATUSF_IP0     /* sw0 software interrupt */
                bnez    t1, ll_sw0_irq
                andi    t1, t0, STATUSF_IP1     /* sw1 software interrupt */
@@ -83,7 +83,7 @@ ll_pmc_irq:
                move    a1, sp
                jal     do_IRQ
                j       ret_from_irq
-       
+
 ll_cpci_decode_irq:
                move    a0, sp
                jal     ll_cpci_irq
@@ -99,4 +99,4 @@ ll_cputimer_irq:
                move    a1, sp
                jal     do_IRQ
                j       ret_from_irq
-       
+
index a6cf7a7959b3566a9932257f3da5e31cf88d90a2..97fb77dad7235b58d9d873f1adceee69fd62a35a 100644 (file)
@@ -32,7 +32,7 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 #define OCELOT_C_CS0_ADDR       (0xfffffffffc000000)
 #else
 #define OCELOT_C_CS0_ADDR               (0xfc000000)
index 49ac302d8901b5b7a661fcb97643c580ae6b47c2..5b6809724b15efa987fa2880fa46047bc528af1b 100644 (file)
@@ -67,7 +67,7 @@ static u8 exchange_bit(u8 val, u8 cs)
 
        /* turn the clock off and read-strobe */
        OCELOT_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);
-       
+
        /* return the data */
        return ((OCELOT_FPGA_READ(EEPROM_MODE) >> 3) & 0x1);
 }
@@ -94,7 +94,7 @@ void get_mac(char dest[6])
 #endif
 
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 
 unsigned long signext(unsigned long addr)
 {
@@ -144,7 +144,7 @@ char *arg64(unsigned long addrin, int arg_index)
   p = (char *)get_arg(args, arg_index);
   return p;
 }
-#endif  /* CONFIG_MIPS64 */
+#endif  /* CONFIG_64BIT */
 
 
 void __init prom_init(void)
@@ -155,7 +155,7 @@ void __init prom_init(void)
        struct callvectors *cv = (struct callvectors *) fw_arg3;
        int i;
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        char *ptr;
 
        printk("prom_init - MIPS64\n");
@@ -197,7 +197,7 @@ void __init prom_init(void)
        }
        printk("arcs_cmdline: %s\n", arcs_cmdline);
 
-#else   /* CONFIG_MIPS64 */
+#else   /* CONFIG_64BIT */
        /* save the PROM vectors for debugging use */
        debug_vectors = cv;
 
@@ -222,7 +222,7 @@ void __init prom_init(void)
                }
                env++;
        }
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
 
        mips_machgroup = MACH_GROUP_MOMENCO;
        mips_machtype = MACH_MOMENCO_OCELOT_C;
@@ -232,7 +232,7 @@ void __init prom_init(void)
        get_mac(prom_mac_addr_base);
 #endif
 
-#ifndef CONFIG_MIPS64
+#ifndef CONFIG_64BIT
        debug_vectors->printf("Booting Linux kernel...\n");
 #endif
 }
index 1f2b4263cc8cb4753eb666b39d3c8e4631ddcdb8..6a2489f3b9a0f3648d7459d8c7e833e7e9bc41a5 100644 (file)
@@ -28,7 +28,7 @@ void momenco_ocelot_restart(char *command)
 {
        /* base address of timekeeper portion of part */
        void *nvram = (void *)
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
                0xfffffffffc807000;
 #else
                0xfc807000;
index 021c00e3c07c7934878ee878b476cc6a93661d21..844ddd06349b9d23f737eddf7df99ac11a76a484 100644 (file)
@@ -109,7 +109,7 @@ void PMON_v2_setup(void)
        */
   printk("PMON_v2_setup\n");
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        /* marvell and extra space */
        add_wired_entry(ENTRYLO(0xf4000000), ENTRYLO(0xf4010000), 0xfffffffff4000000, PM_64K);
        /* fpga, rtc, and uart */
@@ -134,7 +134,7 @@ void PMON_v2_setup(void)
 
 unsigned long m48t37y_get_time(void)
 {
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        unsigned char *rtc_base = (unsigned char*)0xfffffffffc800000;
 #else
        unsigned char* rtc_base = (unsigned char*)0xfc800000;
@@ -163,7 +163,7 @@ unsigned long m48t37y_get_time(void)
 
 int m48t37y_set_time(unsigned long sec)
 {
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        unsigned char* rtc_base = (unsigned char*)0xfffffffffc800000;
 #else
        unsigned char* rtc_base = (unsigned char*)0xfc800000;
@@ -342,7 +342,7 @@ static void __init momenco_ocelot_c_setup(void)
 
 early_initcall(momenco_ocelot_c_setup);
 
-#ifndef CONFIG_MIPS64
+#ifndef CONFIG_64BIT
 /* This needs to be one of the first initcalls, because no I/O port access
    can work before this */
 static int io_base_ioremap(void)
index b345e528a53c8bd1fb8534a2b8cb6c13ff7e1962..5a4a7c239c421220fc99e0284bbfcff95b965e39 100644 (file)
@@ -5,7 +5,7 @@ static void ddb5074_fixup(struct pci_dev *dev)
 {
        extern struct pci_dev *pci_pmu;
        u8 t8;
-                                                                
+
        pci_pmu = dev;  /* for LEDs D2 and D3 */
        /* Program the lines for LEDs D2 and D3 to output */
        pci_read_config_byte(dev, 0x7d, &t8);
index 6abdc88bab1e3fe14962403ae5fc6f03534286bc..2f1444e606542b4400747d34e1c10aad14c8f726 100644 (file)
@@ -65,7 +65,7 @@ static void ddb5477_amd_lance_fixup(struct pci_dev *dev)
        ioaddr = pci_resource_start(dev, 0);
 
        inw(ioaddr + PCNET32_WIO_RESET);        /* reset chip */
-                                                                                
+
        /* bcr_18 |= 0x0800 */
        outw(18, ioaddr + PCNET32_WIO_RAP);
        temp = inw(ioaddr + PCNET32_WIO_BDP);
index b9296d9942b3740e9e1a17f5f8a94fe30add7f35..bf2c41d1e9c53858601c8161204f022cc9fdb7c6 100644 (file)
@@ -56,7 +56,7 @@ static void __init malta_piix_func0_fixup(struct pci_dev *pdev)
                0,  0,  0,  3,
                4,  5,  6,  7,
                0,  9, 10, 11,
-               12, 0, 14, 15 
+               12, 0, 14, 15
        };
        int i;
 
index de4e443da208506a7e10945b401bbd08363f52ff..ceeb1860895ad67f5b57d817fd89885d7acf0978 100644 (file)
@@ -7,7 +7,7 @@
  * Author: MontaVista Software, Inc.
  *              ppopov@mvista.com or source@mvista.com
  *
- * Copyright (C) 2000-2001 Toshiba Corporation 
+ * Copyright (C) 2000-2001 Toshiba Corporation
  *
  * Copyright (C) 2004 MontaVista Software Inc.
  * Author: Manish Lachwani (mlachwani@mvista.com)
index c8ef01a017ccd8645d87e5b040ee9c974ad8c627..a176f2ca8656b1536db9f740c8de822d3340f265 100644 (file)
@@ -32,7 +32,7 @@
  * Device 4: Unused
  * Device 5: Slot 2
  * Device 6: Slot 3
- * Device 7: Slot 4    
+ * Device 7: Slot 4
  *
  * Documentation says the VGA is device 5 and device 3 is unused but that
  * seem to be a documentation error.  At least on my RM200C the Cirrus
index 850a900f0eb4eb8c8b8c6fcbfd581cb94890fb9b..bc55b06e190446655922d0203aa866777a69688c 100644 (file)
@@ -29,27 +29,12 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 
        switch (slot) {
        case 12:
-               vr41xx_set_irq_trigger(TB0219_PCI_SLOT1_PIN,
-                                      TRIGGER_LEVEL,
-                                      SIGNAL_THROUGH);
-               vr41xx_set_irq_level(TB0219_PCI_SLOT1_PIN,
-                                    LEVEL_LOW);
                irq = TB0219_PCI_SLOT1_IRQ;
                break;
        case 13:
-               vr41xx_set_irq_trigger(TB0219_PCI_SLOT2_PIN,
-                                      TRIGGER_LEVEL,
-                                      SIGNAL_THROUGH);
-               vr41xx_set_irq_level(TB0219_PCI_SLOT2_PIN,
-                                    LEVEL_LOW);
                irq = TB0219_PCI_SLOT2_IRQ;
                break;
        case 14:
-               vr41xx_set_irq_trigger(TB0219_PCI_SLOT3_PIN,
-                                      TRIGGER_LEVEL,
-                                      SIGNAL_THROUGH);
-               vr41xx_set_irq_level(TB0219_PCI_SLOT3_PIN,
-                                    LEVEL_LOW);
                irq = TB0219_PCI_SLOT3_IRQ;
                break;
        default:
index e955443fedf930f3a5f33df04eefa1dccec09a1e..0406b50a37d8d46c4f72219feed294fd97f7dea4 100644 (file)
@@ -127,7 +127,7 @@ static inline void ddb_close_config_base(struct pci_config_swap *swap)
 }
 
 static int read_config_dword(struct pci_config_swap *swap,
-                            struct pci_bus *bus, u32 devfn, u32 where, 
+                            struct pci_bus *bus, u32 devfn, u32 where,
                             u32 * val)
 {
        u32 bus_num, slot_num, func_num;
@@ -153,7 +153,7 @@ static int read_config_dword(struct pci_config_swap *swap,
 }
 
 static int read_config_word(struct pci_config_swap *swap,
-                           struct pci_bus *bus, u32 devfn, u32 where, 
+                           struct pci_bus *bus, u32 devfn, u32 where,
                            u16 * val)
 {
        int status;
index 2a9d7227fe87c98053aa076df91092ff56cb662c..7688b7711329364f48363ea13caaf27d81bcae94 100644 (file)
@@ -1,16 +1,16 @@
 /*
  * Copyright 2001 MontaVista Software Inc.
  * Author: MontaVista Software, Inc.
- *              ahennessy@mvista.com       
+ *              ahennessy@mvista.com
  *
- * Copyright (C) 2000-2001 Toshiba Corporation 
+ * Copyright (C) 2000-2001 Toshiba Corporation
  * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
  *
  * Based on arch/mips/ddb5xxx/ddb5477/pci_ops.c
  *
  *     Define the pci_ops for the Toshiba rbtx4927
  *
- * Much of the code is derived from the original DDB5074 port by 
+ * Much of the code is derived from the original DDB5074 port by
  * Geert Uytterhoeven <geert@sonycom.com>
  *
  * Copyright 2004 MontaVista Software Inc.
index 4ddd53eaf6568517d5baef7f4ee683a431a8eb2e..826d653184e576d1322c496d87a850102be309f6 100644 (file)
@@ -76,7 +76,7 @@ struct pci_controller ddb5477_io_controller = {
  */
 
 /*
- * irq mapping : device -> pci int # -> vrc4377 irq# , 
+ * irq mapping : device -> pci int # -> vrc4377 irq# ,
  * ddb5477 board manual page 4  and vrc5477 manual page 46
  */
 
@@ -137,9 +137,9 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
        unsigned char *slot_irq_map;
        unsigned char irq;
 
-       /* 
+       /*
         * We ignore the swizzled slot and pin values.  The original
-        * pci_fixup_irq() codes largely base irq number on the dev slot 
+        * pci_fixup_irq() codes largely base irq number on the dev slot
         * numbers because except for one case they are unique even
         * though there are multiple pci buses.
         */
@@ -160,7 +160,7 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 
        if (mips_machtype == MACH_NEC_ROCKHOPPERII) {
                /* hack to distinquish overlapping slot 20s, one
-                * on bus 0 (ALI USB on the M1535 on the backplane), 
+                * on bus 0 (ALI USB on the M1535 on the backplane),
                 * and one on bus 2 (NEC USB controller on the CPU board)
                 * Make the M1535 USB - ISA IRQ number 9.
                 */
index 1faeb034f06e45157b74ad283756b6b674999810..000dc6af6cd39310d0bd940f0c766fc96326090c 100644 (file)
@@ -84,7 +84,7 @@ static irqreturn_t macepci_error(int irq, void *dev, struct pt_regs *regs)
 
 
 extern struct pci_ops mace_pci_ops;
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 static struct resource mace_pci_mem_resource = {
        .name   = "SGI O2 PCI MEM",
        .start  = MACEPCI_HI_MEMORY,
index 8141dffac2411e8bd951f6777d08092d0e27feba..a8d499b0a36f1eca62d814d9477aba8becb734d8 100644 (file)
@@ -132,7 +132,7 @@ static int __init pcibios_init(void)
                hose->need_domain_info = need_domain_info;
                next_busno = bus->subordinate + 1;
                /* Don't allow 8-bit bus number overflow inside the hose -
-                  reserve some space for bridges. */ 
+                  reserve some space for bridges. */
                if (next_busno > 224) {
                        next_busno = 0;
                        need_domain_info = 1;
@@ -260,7 +260,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
                   (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
                pci_read_bridge_bases(bus);
                pcibios_fixup_device_resources(dev, bus);
-       } 
+       }
 
        for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
                struct pci_dev *dev = pci_dev_b(ln);
@@ -292,8 +292,25 @@ pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
        region->end = res->end - offset;
 }
 
+void __devinit
+pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+                       struct pci_bus_region *region)
+{
+       struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
+       unsigned long offset = 0;
+
+       if (res->flags & IORESOURCE_IO)
+               offset = hose->io_offset;
+       else if (res->flags & IORESOURCE_MEM)
+               offset = hose->mem_offset;
+
+       res->start = region->start + offset;
+       res->end = region->end + offset;
+}
+
 #ifdef CONFIG_HOTPLUG
 EXPORT_SYMBOL(pcibios_resource_to_bus);
+EXPORT_SYMBOL(pcibios_bus_to_resource);
 EXPORT_SYMBOL(PCIBIOS_MIN_IO);
 EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
 #endif
index b067988614c34ce6c871a26d2d10d23d8749d16e..97862f45496d76ce0aa72c349182b53b5a895811 100644 (file)
@@ -30,7 +30,7 @@
  *
  * This code reads the ATMEL 24CXX EEPROM. The PMC-Sierra Yosemite board uses the ATMEL
  * 24C32/24C64 which uses two byte addressing as compared to 24C16. Note that this program
- * uses the serial port like /dev/ttyS0, to communicate with the EEPROM. Hence, you are 
+ * uses the serial port like /dev/ttyS0, to communicate with the EEPROM. Hence, you are
  * expected to have a connectivity from the EEPROM to the serial port. This program does
  * __not__ communicate using the I2C protocol
  */
@@ -64,14 +64,14 @@ static void send_ack(void)
 static void send_byte(unsigned char byte)
 {
        int     i = 0;
-       
-       for (i = 7; i >= 0; i--) 
+
+       for (i = 7; i >= 0; i--)
                send_bit((byte >> i) & 0x01);
 }
-       
+
 static void send_start(void)
 {
-       sda_hi; 
+       sda_hi;
        delay(TXX);
        scl_hi;
        delay(TXX);
@@ -114,9 +114,9 @@ static unsigned char recv_byte(void) {
         int i;
         unsigned char byte=0;
 
-        for (i=7;i>=0;i--)                             
+        for (i=7;i>=0;i--)
                 byte |= (recv_bit() << i);
+
         return byte;
 }
 
index d27566d99ffca79ad597b06f8a1dcb1188045d74..c19f01a320450168e4ed98947fd8a6d9011aacbd 100644 (file)
@@ -27,7 +27,7 @@
  */
 
 /*
- * Header file for atmel_read_eeprom.c 
+ * Header file for atmel_read_eeprom.c
  */
 
 #include <linux/types.h>
@@ -46,7 +46,7 @@
 #define        DEFAULT_PORT    "/dev/ttyS0"    /* Port to open */
 #define        TXX             0               /* Dummy loop for spinning */
 
-#define        BLOCK_SEL       0x00            
+#define        BLOCK_SEL       0x00
 #define        SLAVE_ADDR      0xa0
 #define        READ_BIT        0x01
 #define        WRITE_BIT       0x00
diff --git a/arch/mips/qemu/Makefile b/arch/mips/qemu/Makefile
new file mode 100644 (file)
index 0000000..934944a
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for Qemu specific kernel interface routines under Linux.
+#
+
+obj-y          = q-firmware.o q-int.o q-irq.o q-mem.o q-setup.o
diff --git a/arch/mips/qemu/q-firmware.c b/arch/mips/qemu/q-firmware.c
new file mode 100644 (file)
index 0000000..5980f02
--- /dev/null
@@ -0,0 +1,7 @@
+#include <linux/init.h>
+#include <asm/bootinfo.h>
+
+void __init prom_init(void)
+{
+       add_memory_region(0x0<<20, 0x10<<20, BOOT_MEM_RAM);
+}
diff --git a/arch/mips/qemu/q-int.S b/arch/mips/qemu/q-int.S
new file mode 100644 (file)
index 0000000..6e3dfe5
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Qemu interrupt handler code.
+ *
+ * Copyright (C) 2005 by Ralf Baechle
+ */
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+       .align  5
+       NESTED(qemu_handle_int, PT_SIZE, sp)
+       SAVE_ALL
+       CLI
+       move    a0, sp
+       PTR_LA  ra, ret_from_irq
+       j       do_qemu_int
+       END(qemu_handle_int)
diff --git a/arch/mips/qemu/q-irq.c b/arch/mips/qemu/q-irq.c
new file mode 100644 (file)
index 0000000..2c4e070
--- /dev/null
@@ -0,0 +1,37 @@
+#include <linux/init.h>
+#include <linux/linkage.h>
+
+#include <asm/i8259.h>
+#include <asm/mipsregs.h>
+#include <asm/qemu.h>
+#include <asm/system.h>
+#include <asm/time.h>
+
+extern asmlinkage void qemu_handle_int(void);
+
+asmlinkage void do_qemu_int(struct pt_regs *regs)
+{
+       unsigned int pending = read_c0_status() & read_c0_cause();
+
+       if (pending & 0x8000) {
+               ll_timer_interrupt(Q_COUNT_COMPARE_IRQ, regs);
+               return;
+       }
+       if (pending & 0x0400) {
+               int irq = i8259_irq();
+
+               if (likely(irq >= 0))
+                       do_IRQ(irq, regs);
+
+               return;
+       }
+}
+
+void __init arch_init_irq(void)
+{
+       set_except_vector(0, qemu_handle_int);
+       mips_hpt_frequency = QEMU_C0_COUNTER_CLOCK;             /* 100MHz */
+
+       init_i8259_irqs();
+       set_c0_status(0x8400);
+}
diff --git a/arch/mips/qemu/q-mem.c b/arch/mips/qemu/q-mem.c
new file mode 100644 (file)
index 0000000..d174fac
--- /dev/null
@@ -0,0 +1,6 @@
+#include <linux/init.h>
+
+unsigned long __init prom_free_prom_memory(void)
+{
+       return 0UL;
+}
diff --git a/arch/mips/qemu/q-setup.c b/arch/mips/qemu/q-setup.c
new file mode 100644 (file)
index 0000000..1a80eee
--- /dev/null
@@ -0,0 +1,20 @@
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/time.h>
+
+#define QEMU_PORT_BASE 0xb4000000
+
+static void __init qemu_timer_setup(struct irqaction *irq)
+{
+       /* set the clock to 100 Hz */
+       outb_p(0x34,0x43);              /* binary, mode 2, LSB/MSB, ch 0 */
+       outb_p(LATCH & 0xff , 0x40);    /* LSB */
+       outb(LATCH >> 8 , 0x40);        /* MSB */
+       setup_irq(0, irq);
+}
+
+void __init plat_setup(void)
+{
+       set_io_port_base(QEMU_PORT_BASE);
+       board_timer_setup = qemu_timer_setup;
+}
index 0ab4abf65d58109845f6dca7afa7c6d0b386bfb1..fa0e719c5bd1c3d4c7032de57c05fe261fd54762 100644 (file)
@@ -242,7 +242,7 @@ int __init ip22_eisa_init(void)
        int i, c;
        char *str;
        u8 *slot_addr;
-       
+
        if (!(sgimc->systemid & SGIMC_SYSID_EPRESENT)) {
                printk(KERN_INFO "EISA: bus not present.\n");
                return 1;
index c0afeccb08c40d42c68afdadf9cb1410a04f0c1a..5c00cdd20d8e05196f421cec71a109de63e0d399 100644 (file)
@@ -49,7 +49,7 @@ void __init sgihpc_init(void)
                sgint = &sgioc->int3;
                system_type = "SGI Indy";
        }
-       
+
        sgi_ioc_reset = (SGIOC_RESET_PPORT | SGIOC_RESET_KBDMOUSE |
                         SGIOC_RESET_EISA | SGIOC_RESET_ISDN |
                         SGIOC_RESET_LC0OFF);
index ea2844d29e6ecca93dbfe898d3f003edd2d6812b..d16fb43b1a93ba745f2a9838247f7bd1f845f932 100644 (file)
@@ -28,7 +28,7 @@
 /* #define DEBUG_SGINT */
 
 /* So far nothing hangs here */
-#undef USE_LIO3_IRQ 
+#undef USE_LIO3_IRQ
 
 struct sgint_regs *sgint;
 
@@ -272,32 +272,32 @@ void indy_buserror_irq(struct pt_regs *regs)
        irq_exit();
 }
 
-static struct irqaction local0_cascade = { 
+static struct irqaction local0_cascade = {
        .handler        = no_action,
        .flags          = SA_INTERRUPT,
        .name           = "local0 cascade",
 };
 
-static struct irqaction local1_cascade = { 
+static struct irqaction local1_cascade = {
        .handler        = no_action,
        .flags          = SA_INTERRUPT,
        .name           = "local1 cascade",
 };
 
-static struct irqaction buserr = { 
+static struct irqaction buserr = {
        .handler        = no_action,
        .flags          = SA_INTERRUPT,
        .name           = "Bus Error",
 };
 
-static struct irqaction map0_cascade = { 
+static struct irqaction map0_cascade = {
        .handler        = no_action,
        .flags          = SA_INTERRUPT,
        .name           = "mapable0 cascade",
 };
 
 #ifdef USE_LIO3_IRQ
-static struct irqaction map1_cascade = { 
+static struct irqaction map1_cascade = {
        .handler        = no_action,
        .flags          = SA_INTERRUPT,
        .name           = "mapable1 cascade",
index de43e86fa17ce409db8a008da58b445281e07c8a..fd29fd407ae83da6db8022277ff294128b73b8f4 100644 (file)
@@ -39,7 +39,7 @@
        *ptr |= EEPROM_CSEL;    \
        *ptr |= EEPROM_ECLK; })
 
-               
+
 #define eeprom_cs_off(ptr) ({  \
        *ptr &= ~EEPROM_ECLK;   \
        *ptr &= ~EEPROM_CSEL;   \
@@ -50,7 +50,7 @@
 /*
  * clock in the nvram command and the register number. For the
  * national semiconductor nv ram chip the op code is 3 bits and
- * the address is 6/8 bits. 
+ * the address is 6/8 bits.
  */
 static inline void eeprom_cmd(volatile unsigned int *ctrl, unsigned cmd,
                              unsigned reg)
@@ -90,7 +90,7 @@ unsigned short ip22_eeprom_read(volatile unsigned int *ctrl, int reg)
                if (*ctrl & EEPROM_DATI)
                        res |= 1;
        }
-               
+
        eeprom_cs_off(ctrl);
 
        return res;
@@ -113,7 +113,7 @@ unsigned short ip22_nvram_read(int reg)
                reg <<= 1;
                tmp = hpc3c0->bbram[reg++] & 0xff;
                return (tmp << 8) | (hpc3c0->bbram[reg] & 0xff);
-       }               
+       }
 }
 
 EXPORT_SYMBOL(ip22_nvram_read);
index ed5c60adce6303737ffb2abd86ab3df3d082af39..214ffd2e98a332dad828755ea2f4da9619dee12c 100644 (file)
@@ -185,7 +185,7 @@ static irqreturn_t panel_int(int irq, void *dev_id, struct pt_regs *regs)
                add_timer(&debounce_timer);
        }
 
-       /* Power button was pressed 
+       /* Power button was pressed
         * ioc.ps page 22: "The Panel Register is called Power Control by Full
         * House. Only lowest 2 bits are used. Guiness uses upper four bits
         * for volume control". This is not true, all bits are pulled high
index 173f76805ea3d30d3928d235f756d5f587b978fe..df9b5694328a1801f0e04a9b403b0227622cb194 100644 (file)
@@ -126,7 +126,7 @@ static __init void indy_time_init(void)
        unsigned long r4k_ticks[3];
        unsigned long r4k_tick;
 
-       /* 
+       /*
         * Figure out the r4k offset, the algorithm is very simple and works in
         * _all_ cases as long as the 8254 counter register itself works ok (as
         * an interrupt driving timer it does not because of bug, this is why
index a160d04f7dbe05904f84f60a262ba3b3fbb287d1..ef20d9ac0ba3d0d39d7510c46f465d41ea041932 100644 (file)
@@ -538,7 +538,7 @@ void __init mem_init(void)
        for_each_online_node(node) {
                unsigned slot, numslots;
                struct page *end, *p;
-       
+
                /*
                 * This will free up the bootmem, ie, slot 0 memory.
                 */
index 8c1b96fffa764e8e3a4c9d7ea163c04d2a61620e..cddf1cedf007108daf8bfbb8f286656f7e48e196 100644 (file)
@@ -118,7 +118,7 @@ again:
         * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
         * called as close as possible to when a second starts.
         */
-       if ((time_status & STA_UNSYNC) == 0 &&
+       if (ntp_synced() &&
            xtime.tv_sec > last_rtc_update + 660 &&
            (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
            (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
index 281f090e48a4105cad5d75ba109a58ab98645ea9..88e1f52059ff6a45c1d461cffb42302377bbe4e2 100644 (file)
@@ -140,7 +140,7 @@ static irqreturn_t ip32_rtc_int(int irq, void *dev_id, struct pt_regs *regs)
 
        reg_c = CMOS_READ(RTC_INTR_FLAGS);
        if (!(reg_c & RTC_IRQF)) {
-               printk(KERN_WARNING 
+               printk(KERN_WARNING
                        "%s: RTC IRQ without RTC_IRQF\n", __FUNCTION__);
        }
        /* Wait until interrupt goes away */
index 77eb4935bfb4b0b6a08ab87331c1a456dd290209..975f00002cbe269ef399b3fafe32c4c934f4619c 100644 (file)
  */
 
 /*  *********************************************************************
-    *  
+    *
     *  Broadcom Common Firmware Environment (CFE)
-    *  
+    *
     *  Error codes                             File: cfe_error.h
-    *  
+    *
     *  CFE's global error code list is here.
-    *  
+    *
     *  Author:  Mitch Lichtenberg
-    *  
+    *
     ********************************************************************* */
 
 
index 53a5c1eb5611fa2943fe0cd9df118d0b5541504a..7721100d0275dd566c9aa67d1b5b1489beb00eed 100644 (file)
@@ -38,7 +38,7 @@ static void cfe_console_write(struct console *cons, const char *str,
                        last += written;
                } while (last < count);
        }
-                       
+
 }
 
 static int cfe_console_setup(struct console *cons, char *str)
index d6d0364fa7603a1a29e6be2371f54cd6174566ba..7a2c7a8510d421593d487233ea1834740fa0d9ed 100644 (file)
@@ -33,7 +33,7 @@
 #include "cfe_error.h"
 
 /* Max ram addressable in 32-bit segments */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 #define MAX_RAM_SIZE (~0ULL)
 #else
 #ifdef CONFIG_HIGHMEM
@@ -285,7 +285,7 @@ void __init prom_init(void)
                while (1) ;
        }
        cfe_init(cfe_handle, cfe_ept);
-       /* 
+       /*
         * Get the handle for (at least) prom_putchar, possibly for
         * boot console
         */
index 73392190d2b17f7851f0d5ee9d004e1e7679c9c9..e44ce1a9eea94e53da9c0628eb7765dce48ece47 100644 (file)
@@ -57,7 +57,7 @@ void __init prom_prepare_cpus(unsigned int max_cpus)
 void prom_boot_secondary(int cpu, struct task_struct *idle)
 {
        int retval;
-       
+
        retval = cfe_cpu_start(cpu_logical_map(cpu), &smp_bootstrap,
                               __KSTK_TOS(idle),
                               (unsigned long)idle->thread_info, 0);
index 182a16f42e2d746c86ba4abd83d71a868b82422d..1a97e3127aeb951fb199a981463fb1b3fe6da7f1 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
-/* 
+/*
  * The Bus Watcher monitors internal bus transactions and maintains
  * counts of transactions with error status, logging details and
  * causing one of several interrupts.  This driver provides a handler
@@ -155,7 +155,7 @@ static int bw_read_proc(char *page, char **start, off_t off,
 static void create_proc_decoder(struct bw_stats_struct *stats)
 {
        struct proc_dir_entry *ent;
-       
+
        ent = create_proc_read_entry("bus_watcher", S_IWUSR | S_IRUGO, NULL,
                                     bw_read_proc, stats);
        if (!ent) {
index 2728abbc94d29b6fb2ffc6986265b888e75c18d5..2725b263ccedaf7286c46506d67fac7088205ecc 100644 (file)
@@ -377,7 +377,7 @@ void __init arch_init_irq(void)
 
        /*
         * Note that the timer interrupts are also mapped, but this is
-        * done in sb1250_time_init().  Also, the profiling driver 
+        * done in sb1250_time_init().  Also, the profiling driver
         * does its own management of IP7.
         */
 
@@ -392,7 +392,7 @@ void __init arch_init_irq(void)
        if (kgdb_flag) {
                kgdb_irq = K_INT_UART_0 + kgdb_port;
 
-#ifdef CONFIG_SIBYTE_SB1250_DUART      
+#ifdef CONFIG_SIBYTE_SB1250_DUART
                sb1250_duart_present[kgdb_port] = 0;
 #endif
                /* Setup uart 1 settings, mapper */
index 0e633ee8d83cb79d78b1480768ef862572d0e978..a686bb716ec67e8b5061c9c975689bd6a502e6eb 100644 (file)
@@ -128,7 +128,7 @@ static int m41t81_write(uint8_t addr, int b)
                /* Clear error bit by writing a 1 */
                bus_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS));
                return -1;
-       } 
+       }
 
        /* read the same byte again to make sure it is written */
        bus_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_RD1BYTE,
@@ -136,7 +136,7 @@ static int m41t81_write(uint8_t addr, int b)
 
        while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
                ;
-       
+
        return 0;
 }
 
@@ -148,13 +148,13 @@ int m41t81_set_time(unsigned long t)
 
        /*
         * Note the write order matters as it ensures the correctness.
-        * When we write sec, 10th sec is clear.  It is reasonable to 
+        * When we write sec, 10th sec is clear.  It is reasonable to
         * believe we should finish writing min within a second.
         */
 
        tm.tm_sec = BIN2BCD(tm.tm_sec);
        m41t81_write(M41T81REG_SC, tm.tm_sec);
-       
+
        tm.tm_min = BIN2BCD(tm.tm_min);
        m41t81_write(M41T81REG_MN, tm.tm_min);
 
@@ -187,7 +187,7 @@ unsigned long m41t81_get_time(void)
 {
        unsigned int year, mon, day, hour, min, sec;
 
-       /* 
+       /*
         * min is valid if two reads of sec are the same.
         */
        for (;;) {
index 457aeb7be85830bce79ebc75b34b54d46d348f03..4daeaa413def7fe8367c76670172b746c6bec1e4 100644 (file)
@@ -73,7 +73,7 @@ int swarm_be_handler(struct pt_regs *regs, int is_fixup)
 {
        if (!is_fixup && (regs->cp0_cause & 4)) {
                /* Data bus error - print PA */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
                printk("DBE physical address: %010lx\n",
                       __read_64bit_c0_register($26, 1));
 #else
@@ -98,7 +98,7 @@ static int __init swarm_setup(void)
                rtc_get_time = xicor_get_time;
                rtc_set_time = xicor_set_time;
        }
+
        if (m41t81_probe()) {
                printk("swarm setup: M41T81 RTC detected.\n");
                rtc_get_time = m41t81_get_time;
index 62c760f14674a4d54611d9749654c0f733fadca3..141a310d74d80da02d6e470d7d3f0bc1c4237a63 100644 (file)
@@ -103,7 +103,7 @@ static unsigned int ls1bit8(unsigned int x)
 
 /*
  * hwint 1 deals with EISA and SCSI interrupts,
- * 
+ *
  * The EISA_INT bit in CSITPEND is high active, all others are low active.
  */
 void pciasic_hwint1(struct pt_regs *regs)
index 8f67cee4317bd17051daf8f8b582eda6426051c6..1b3f8a0903e10722de9dc67150289d79f7c74701 100644 (file)
@@ -111,7 +111,7 @@ static struct resource sni_mem_resource = {
  * The RM200/RM300 has a few holes in it's PCI/EISA memory address space used
  * for other purposes.  Be paranoid and allocate all of the before the PCI
  * code gets a chance to to map anything else there ...
- * 
+ *
  * This leaves the following areas available:
  *
  * 0x10000000 - 0x1009ffff (640kB) PCI/EISA/ISA Bus Memory
index ca123e28d1ef3630d00867b54fb5ada7f3c0448d..dd3ceda9d712f84cc6e828bd446556c9a76913b9 100644 (file)
                CLI
                .set    at
 
-               mfc0    t0, CP0_CAUSE  
+               mfc0    t0, CP0_CAUSE
                mfc0    t1, CP0_STATUS
                and     t0, t1
-        
+
                andi    t1, t0, STATUSF_IP7     /* cpu timer */
                bnez    t1, ll_ip7
-               
+
                /* IP6..IP3 multiplexed -- do not use */
 
                andi    t1, t0, STATUSF_IP2     /* tx4927 pic */
index 16bcbdc6d1cc7f0a182d4b390329040c84b0c2af..26d7c53612a88cf93aaa49cfb99cd7f8980f568a 100644 (file)
@@ -152,7 +152,7 @@ dump_cp0(char *key)
        print_cp0(key, 16, "CONFIG  ", read_c0_config());
        return;
 }
-       
+
 void print_pic(char *key, u32 reg, char *name)
 {
        printk("%s pic:0x%08x:%s=0x%08x\n", key, reg, name,
index 86ca4cf2d587490344e9cf9fd14dc6d88de2144e..c1a377a80a5d3de7d0069f3fb4e980476599fd2c 100644 (file)
@@ -1,5 +1,5 @@
-obj-y  += toshiba_rbtx4927_prom.o 
-obj-y  += toshiba_rbtx4927_setup.o 
-obj-y  += toshiba_rbtx4927_irq.o 
+obj-y  += toshiba_rbtx4927_prom.o
+obj-y  += toshiba_rbtx4927_setup.o
+obj-y  += toshiba_rbtx4927_irq.o
 
 EXTRA_AFLAGS := $(CFLAGS)
index fd5b433f83b762ceb12f606f93fbc7255081ab94..aee07ff2212a37bb1348a6a48d783dea94a8146e 100644 (file)
@@ -31,7 +31,7 @@
 
 
 /*
-IRQ  Device  
+IRQ  Device
 00   RBTX4927-ISA/00
 01   RBTX4927-ISA/01 PS2/Keyboard
 02   RBTX4927-ISA/02 Cascade RBTX4927-ISA (irqs 8-15)
@@ -52,15 +52,15 @@ IRQ  Device
 16   TX4927-CP0/00 Software 0
 17   TX4927-CP0/01 Software 1
 18   TX4927-CP0/02 Cascade TX4927-CP0
-19   TX4927-CP0/03 Multiplexed -- do not use 
-20   TX4927-CP0/04 Multiplexed -- do not use 
-21   TX4927-CP0/05 Multiplexed -- do not use 
-22   TX4927-CP0/06 Multiplexed -- do not use 
+19   TX4927-CP0/03 Multiplexed -- do not use
+20   TX4927-CP0/04 Multiplexed -- do not use
+21   TX4927-CP0/05 Multiplexed -- do not use
+22   TX4927-CP0/06 Multiplexed -- do not use
 23   TX4927-CP0/07 CPU TIMER
 
 24   TX4927-PIC/00
 25   TX4927-PIC/01
-26   TX4927-PIC/02  
+26   TX4927-PIC/02
 27   TX4927-PIC/03 Cascade RBTX4927-IOC
 28   TX4927-PIC/04
 29   TX4927-PIC/05 RBTX4927 RTL-8019AS ethernet
@@ -80,7 +80,7 @@ IRQ  Device
 43   TX4927-PIC/19
 44   TX4927-PIC/20
 45   TX4927-PIC/21
-46   TX4927-PIC/22 TX4927 PCI PCI-ERR 
+46   TX4927-PIC/22 TX4927 PCI PCI-ERR
 47   TX4927-PIC/23 TX4927 PCI PCI-PMA (not used)
 48   TX4927-PIC/24
 49   TX4927-PIC/25
@@ -100,7 +100,7 @@ IRQ  Device
 62 RBTX4927-IOC/06
 63 RBTX4927-IOC/07
 
-NOTES: 
+NOTES:
 SouthBridge/INTR is mapped to SouthBridge/A=PCI-B/#58
 SouthBridge/ISA/pin=0 no pci irq used by this device
 SouthBridge/IDE/pin=1 no pci irq used by this device, using INTR via ISA IRQ14
@@ -175,19 +175,19 @@ JP7 is not bus master -- do NOT use -- only 4 pci bus master's allowed -- SouthB
 static const u32 toshiba_rbtx4927_irq_debug_flag =
     (TOSHIBA_RBTX4927_IRQ_NONE | TOSHIBA_RBTX4927_IRQ_INFO |
      TOSHIBA_RBTX4927_IRQ_WARN | TOSHIBA_RBTX4927_IRQ_EROR
-//                                                 | TOSHIBA_RBTX4927_IRQ_IOC_INIT  
-//                                                 | TOSHIBA_RBTX4927_IRQ_IOC_STARTUP  
-//                                                 | TOSHIBA_RBTX4927_IRQ_IOC_SHUTDOWN  
-//                                                 | TOSHIBA_RBTX4927_IRQ_IOC_ENABLE  
-//                                                 | TOSHIBA_RBTX4927_IRQ_IOC_DISABLE  
-//                                                 | TOSHIBA_RBTX4927_IRQ_IOC_MASK  
-//                                                 | TOSHIBA_RBTX4927_IRQ_IOC_ENDIRQ  
-//                                                 | TOSHIBA_RBTX4927_IRQ_ISA_INIT  
-//                                                 | TOSHIBA_RBTX4927_IRQ_ISA_STARTUP  
-//                                                 | TOSHIBA_RBTX4927_IRQ_ISA_SHUTDOWN  
-//                                                 | TOSHIBA_RBTX4927_IRQ_ISA_ENABLE  
-//                                                 | TOSHIBA_RBTX4927_IRQ_ISA_DISABLE  
-//                                                 | TOSHIBA_RBTX4927_IRQ_ISA_MASK  
+//                                                 | TOSHIBA_RBTX4927_IRQ_IOC_INIT
+//                                                 | TOSHIBA_RBTX4927_IRQ_IOC_STARTUP
+//                                                 | TOSHIBA_RBTX4927_IRQ_IOC_SHUTDOWN
+//                                                 | TOSHIBA_RBTX4927_IRQ_IOC_ENABLE
+//                                                 | TOSHIBA_RBTX4927_IRQ_IOC_DISABLE
+//                                                 | TOSHIBA_RBTX4927_IRQ_IOC_MASK
+//                                                 | TOSHIBA_RBTX4927_IRQ_IOC_ENDIRQ
+//                                                 | TOSHIBA_RBTX4927_IRQ_ISA_INIT
+//                                                 | TOSHIBA_RBTX4927_IRQ_ISA_STARTUP
+//                                                 | TOSHIBA_RBTX4927_IRQ_ISA_SHUTDOWN
+//                                                 | TOSHIBA_RBTX4927_IRQ_ISA_ENABLE
+//                                                 | TOSHIBA_RBTX4927_IRQ_ISA_DISABLE
+//                                                 | TOSHIBA_RBTX4927_IRQ_ISA_MASK
 //                                                 | TOSHIBA_RBTX4927_IRQ_ISA_ENDIRQ
     );
 #endif
index 8724ea3ae04eff263e10146af7c50b7f464c38e6..fc0720599fd9d64ab4e4d12be4d317a9b37fcb98 100644 (file)
@@ -395,7 +395,7 @@ static int __init tx4927_pcibios_init(void)
                        /* enable secondary ide */
                        v08_43 |= 0x80;
 
-                       /* 
+                       /*
                         * !!! DO NOT REMOVE THIS COMMENT IT IS REQUIRED BY SMSC !!!
                         *
                         * This line of code is intended to provide the user with a work
diff --git a/arch/mips/vr4181/common/Makefile b/arch/mips/vr4181/common/Makefile
deleted file mode 100644 (file)
index f7587ca..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for common code of NEC vr4181 based boards
-#
-
-obj-y   := irq.o int_handler.o serial.o time.o
-
-EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/vr4181/common/int_handler.S b/arch/mips/vr4181/common/int_handler.S
deleted file mode 100644 (file)
index 2c041b8..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * arch/mips/vr4181/common/int_handler.S
- *
- * Adapted to the VR4181 and almost entirely rewritten:
- * Copyright (C) 1999 Bradley D. LaRonde and Michael Klar
- *
- * Clean up to conform to the new IRQ
- * Copyright (C) 2001 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- */
-
-#include <asm/asm.h>
-#include <asm/regdef.h>
-#include <asm/mipsregs.h>
-#include <asm/stackframe.h>
-
-#include <asm/vr4181/vr4181.h>
-
-/*
- * [jsun]
- * See include/asm/vr4181/irq.h for IRQ assignment and strategy.
- */
-
-       .text
-       .set    noreorder
-
-       .align  5
-       NESTED(vr4181_handle_irq, PT_SIZE, ra)
-
-       .set    noat
-       SAVE_ALL
-       CLI
-
-       .set    at
-       .set    noreorder
-
-       mfc0    t0, CP0_CAUSE
-       mfc0    t2, CP0_STATUS
-
-       and     t0, t2
-
-       /* we check IP3 first; it happens most frequently */
-       andi    t1, t0, STATUSF_IP3
-       bnez    t1, ll_cpu_ip3
-       andi    t1, t0, STATUSF_IP2
-       bnez    t1, ll_cpu_ip2
-       andi    t1, t0, STATUSF_IP7     /* cpu timer */
-       bnez    t1, ll_cputimer_irq
-       andi    t1, t0, STATUSF_IP4
-       bnez    t1, ll_cpu_ip4
-       andi    t1, t0, STATUSF_IP5
-       bnez    t1, ll_cpu_ip5
-       andi    t1, t0, STATUSF_IP6
-       bnez    t1, ll_cpu_ip6
-       andi    t1, t0, STATUSF_IP0     /* software int 0 */
-       bnez    t1, ll_cpu_ip0
-       andi    t1, t0, STATUSF_IP1     /* software int 1 */
-       bnez    t1, ll_cpu_ip1
-       nop
-
-       .set    reorder
-do_spurious:
-       j       spurious_interrupt
-
-/*
- * regular CPU irqs
- */
-ll_cputimer_irq:
-       li      a0, VR4181_IRQ_TIMER
-       move    a1, sp
-       jal     do_IRQ
-       j       ret_from_irq
-
-
-ll_cpu_ip0:
-       li      a0, VR4181_IRQ_SW1
-       move    a1, sp
-       jal     do_IRQ
-       j       ret_from_irq
-
-ll_cpu_ip1:
-       li      a0, VR4181_IRQ_SW2
-       move    a1, sp
-       jal     do_IRQ
-       j       ret_from_irq
-
-ll_cpu_ip3:
-       li      a0, VR4181_IRQ_INT1
-       move    a1, sp
-       jal     do_IRQ
-       j       ret_from_irq
-
-ll_cpu_ip4:
-       li      a0, VR4181_IRQ_INT2
-       move    a1, sp
-       jal     do_IRQ
-       j       ret_from_irq
-
-ll_cpu_ip5:
-       li      a0, VR4181_IRQ_INT3
-       move    a1, sp
-       jal     do_IRQ
-       j       ret_from_irq
-
-ll_cpu_ip6:
-       li      a0, VR4181_IRQ_INT4
-       move    a1, sp
-       jal     do_IRQ
-       j       ret_from_irq
-
-/*
- *  One of the sys irq has happend.
- *
- *  In the interest of speed, we first determine in the following order
- *  which 16-irq block have pending interrupts:
- *     sysint1 (16 sources, including cascading intrs from GPIO)
- *     sysint2
- *     gpio (16 intr sources)
- *
- *  Then we do binary search to find the exact interrupt source.
- */
-ll_cpu_ip2:
-
-       lui     t3,%hi(VR4181_SYSINT1REG)
-       lhu     t0,%lo(VR4181_SYSINT1REG)(t3)
-       lhu     t2,%lo(VR4181_MSYSINT1REG)(t3)
-       and     t0, 0xfffb              /* hack - remove RTC Long 1 intr */
-       and     t0, t2
-       beqz    t0, check_sysint2
-
-       /* check for GPIO interrupts */
-       andi    t1, t0, 0x0100
-       bnez    t1, check_gpio_int
-
-       /* so we have an interrupt in sysint1 which is not gpio int */
-       li      a0, VR4181_SYS_IRQ_BASE - 1
-       j       check_16
-
-check_sysint2:
-
-       lhu     t0,%lo(VR4181_SYSINT2REG)(t3)
-       lhu     t2,%lo(VR4181_MSYSINT2REG)(t3)
-       and     t0, 0xfffe              /* hack - remove RTC Long 2 intr */
-       and     t0, t2
-       li      a0, VR4181_SYS_IRQ_BASE + 16 - 1
-       j       check_16
-
-check_gpio_int:
-       lui     t3,%hi(VR4181_GPINTMSK)
-       lhu     t0,%lo(VR4181_GPINTMSK)(t3)
-       lhu     t2,%lo(VR4181_GPINTSTAT)(t3)
-       xori    t0, 0xffff                      /* why? reverse logic? */
-       and     t0, t2
-       li      a0, VR4181_GPIO_IRQ_BASE - 1
-       j       check_16
-
-/*
- *  When we reach check_16, we have 16-bit status in t0 and base irq number
- *  in a0.
- */
-check_16:
-       andi    t1, t0, 0xff
-       bnez    t1, check_8
-
-       srl     t0, 8
-       addi    a0, 8
-       j       check_8
-
-/*
- *  When we reach check_8, we have 8-bit status in t0 and base irq number
- *  in a0.
- */
-check_8:
-       andi    t1, t0, 0xf
-       bnez    t1, check_4
-
-       srl     t0, 4
-       addi    a0, 4
-       j       check_4
-
-/*
- *  When we reach check_4, we have 4-bit status in t0 and base irq number
- *  in a0.
- */
-check_4:
-       andi    t0, t0, 0xf
-       beqz    t0, do_spurious
-
-loop:
-       andi    t2, t0, 0x1
-       srl     t0, 1
-       addi    a0, 1
-       beqz    t2, loop
-
-found_it:
-       move    a1, sp
-       jal     do_IRQ
-
-       j       ret_from_irq
-
-       END(vr4181_handle_irq)
diff --git a/arch/mips/vr4181/common/irq.c b/arch/mips/vr4181/common/irq.c
deleted file mode 100644 (file)
index 2cdf77c..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2001 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
- *
- * linux/arch/mips/vr4181/common/irq.c
- *     Completely re-written to use the new irq.c
- *
- * Credits to Bradley D. LaRonde and Michael Klar for writing the original
- * irq.c file which was derived from the common irq.c file.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel_stat.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-
-#include <asm/irq.h>
-#include <asm/mipsregs.h>
-#include <asm/gdb-stub.h>
-
-#include <asm/vr4181/vr4181.h>
-
-/*
- * Strategy:
- *
- * We essentially have three irq controllers, CPU, system, and gpio.
- *
- * CPU irq controller is taken care by arch/mips/kernel/irq_cpu.c and
- * CONFIG_IRQ_CPU config option.
- *
- * We here provide sys_irq and gpio_irq controller code.
- */
-
-static int sys_irq_base;
-static int gpio_irq_base;
-
-/* ---------------------- sys irq ------------------------ */
-static void
-sys_irq_enable(unsigned int irq)
-{
-       irq -= sys_irq_base;
-       if (irq < 16) {
-               *VR4181_MSYSINT1REG |= (u16)(1 << irq);
-       } else {
-               irq -= 16;
-               *VR4181_MSYSINT2REG |= (u16)(1 << irq);
-       }
-}
-
-static void
-sys_irq_disable(unsigned int irq)
-{
-       irq -= sys_irq_base;
-       if (irq < 16) {
-               *VR4181_MSYSINT1REG &= ~((u16)(1 << irq));
-       } else {
-               irq -= 16;
-               *VR4181_MSYSINT2REG &= ~((u16)(1 << irq));
-       }
-
-}
-
-static unsigned int
-sys_irq_startup(unsigned int irq)
-{
-       sys_irq_enable(irq);
-       return 0;
-}
-
-#define sys_irq_shutdown       sys_irq_disable
-#define sys_irq_ack            sys_irq_disable
-
-static void
-sys_irq_end(unsigned int irq)
-{
-       if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
-               sys_irq_enable(irq);
-}
-
-static hw_irq_controller sys_irq_controller = {
-       "vr4181_sys_irq",
-       sys_irq_startup,
-       sys_irq_shutdown,
-       sys_irq_enable,
-       sys_irq_disable,
-       sys_irq_ack,
-       sys_irq_end,
-       NULL                    /* no affinity stuff for UP */
-};
-
-/* ---------------------- gpio irq ------------------------ */
-/* gpio irq lines use reverse logic */
-static void
-gpio_irq_enable(unsigned int irq)
-{
-       irq -= gpio_irq_base;
-       *VR4181_GPINTMSK &= ~((u16)(1 << irq));
-}
-
-static void
-gpio_irq_disable(unsigned int irq)
-{
-       irq -= gpio_irq_base;
-       *VR4181_GPINTMSK |= (u16)(1 << irq);
-}
-
-static unsigned int
-gpio_irq_startup(unsigned int irq)
-{
-       gpio_irq_enable(irq);
-
-       irq -= gpio_irq_base;
-       *VR4181_GPINTEN |= (u16)(1 << irq );
-
-       return 0;
-}
-
-static void
-gpio_irq_shutdown(unsigned int irq)
-{
-       gpio_irq_disable(irq);
-
-       irq -= gpio_irq_base;
-       *VR4181_GPINTEN &= ~((u16)(1 << irq ));
-}
-
-static void
-gpio_irq_ack(unsigned int irq)
-{
-       u16 irqtype;
-       u16 irqshift;
-
-       gpio_irq_disable(irq);
-
-       /* we clear interrupt if it is edge triggered */
-       irq -= gpio_irq_base;
-       if (irq < 8) {
-               irqtype = *VR4181_GPINTTYPL;
-               irqshift = 2 << (irq*2);
-       } else {
-               irqtype = *VR4181_GPINTTYPH;
-               irqshift = 2 << ((irq-8)*2);
-       }
-       if ( ! (irqtype & irqshift) ) {
-               *VR4181_GPINTSTAT = (u16) (1 << irq);
-       }
-}
-
-static void
-gpio_irq_end(unsigned int irq)
-{
-       if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
-               gpio_irq_enable(irq);
-}
-
-static hw_irq_controller gpio_irq_controller = {
-       "vr4181_gpio_irq",
-       gpio_irq_startup,
-       gpio_irq_shutdown,
-       gpio_irq_enable,
-       gpio_irq_disable,
-       gpio_irq_ack,
-       gpio_irq_end,
-       NULL                    /* no affinity stuff for UP */
-};
-
-/* ---------------------  IRQ init stuff ---------------------- */
-
-extern asmlinkage void vr4181_handle_irq(void);
-extern void breakpoint(void);
-extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
-extern void mips_cpu_irq_init(u32 irq_base);
-
-static struct irqaction cascade =
-       { no_action, SA_INTERRUPT, CPU_MASK_NONE, "cascade", NULL, NULL };
-static struct irqaction reserved =
-       { no_action, SA_INTERRUPT, CPU_MASK_NONE, "cascade", NULL, NULL };
-
-void __init arch_init_irq(void)
-{
-       int i;
-
-       set_except_vector(0, vr4181_handle_irq);
-
-       /* init CPU irqs */
-       mips_cpu_irq_init(VR4181_CPU_IRQ_BASE);
-
-       /* init sys irqs */
-       sys_irq_base = VR4181_SYS_IRQ_BASE;
-       for (i=sys_irq_base; i < sys_irq_base + VR4181_NUM_SYS_IRQ; i++) {
-               irq_desc[i].status = IRQ_DISABLED;
-               irq_desc[i].action = NULL;
-               irq_desc[i].depth = 1;
-               irq_desc[i].handler = &sys_irq_controller;
-       }
-
-       /* init gpio irqs */
-       gpio_irq_base = VR4181_GPIO_IRQ_BASE;
-       for (i=gpio_irq_base; i < gpio_irq_base + VR4181_NUM_GPIO_IRQ; i++) {
-               irq_desc[i].status = IRQ_DISABLED;
-               irq_desc[i].action = NULL;
-               irq_desc[i].depth = 1;
-               irq_desc[i].handler = &gpio_irq_controller;
-       }
-
-       /* Default all ICU IRQs to off ... */
-       *VR4181_MSYSINT1REG = 0;
-       *VR4181_MSYSINT2REG = 0;
-
-       /* We initialize the level 2 ICU registers to all bits disabled. */
-       *VR4181_MPIUINTREG = 0;
-       *VR4181_MAIUINTREG = 0;
-       *VR4181_MKIUINTREG = 0;
-
-       /* disable all GPIO intrs */
-       *VR4181_GPINTMSK = 0xffff;
-
-       /* vector handler.  What these do is register the IRQ as non-sharable */
-       setup_irq(VR4181_IRQ_INT0, &cascade);
-       setup_irq(VR4181_IRQ_GIU, &cascade);
-
-       /*
-        * RTC interrupts are interesting.  They have two destinations.
-        * One is at sys irq controller, and the other is at CPU IP3 and IP4.
-        * RTC timer is used as system timer.
-        * We enable them here, but timer routine will register later
-        * with CPU IP3/IP4.
-        */
-       setup_irq(VR4181_IRQ_RTCL1, &reserved);
-       setup_irq(VR4181_IRQ_RTCL2, &reserved);
-}
diff --git a/arch/mips/vr4181/common/serial.c b/arch/mips/vr4181/common/serial.c
deleted file mode 100644 (file)
index 3f62c62..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2001 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- *
- * arch/mips/vr4181/common/serial.c
- *     initialize serial port on vr4181.
- *
- * 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.
- *
- */
-
-/*
- * [jsun, 010925]
- * You need to make sure rs_table has at least one element in
- * drivers/char/serial.c file. There is no good way to do it right
- * now.         A workaround is to include CONFIG_SERIAL_MANY_PORTS in your
- * configure file, which would gives you 64 ports and wastes 11K ram.
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-
-#include <asm/vr4181/vr4181.h>
-
-void __init vr4181_init_serial(void)
-{
-       struct serial_struct s;
-
-       /* turn on UART clock */
-       *VR4181_CMUCLKMSK |= VR4181_CMUCLKMSK_MSKSIU;
-
-       /* clear memory */
-       memset(&s, 0, sizeof(s));
-
-       s.line = 0;                     /* we set the first one */
-       s.baud_base = 1152000;
-       s.irq = VR4181_IRQ_SIU;
-       s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; /* STD_COM_FLAGS */
-       s.iomem_base = (u8*)VR4181_SIURB;
-       s.iomem_reg_shift = 0;
-       s.io_type = SERIAL_IO_MEM;
-       if (early_serial_setup(&s) != 0) {
-               panic("vr4181_init_serial() failed!");
-       }
-}
-
diff --git a/arch/mips/vr4181/common/time.c b/arch/mips/vr4181/common/time.c
deleted file mode 100644 (file)
index 1781407..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- *
- * rtc and time ops for vr4181.         Part of code is drived from
- * linux-vr, originally written         by Bradley D. LaRonde & Michael Klar.
- *
- * 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/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/param.h>                       /* for HZ */
-#include <linux/time.h>
-#include <linux/interrupt.h>
-
-#include <asm/system.h>
-#include <asm/time.h>
-
-#include <asm/vr4181/vr4181.h>
-
-#define COUNTS_PER_JIFFY ((32768 + HZ/2) / HZ)
-
-/*
- * RTC ops
- */
-
-DEFINE_SPINLOCK(rtc_lock);
-
-/* per VR41xx docs, bad data can be read if between 2 counts */
-static inline unsigned short
-read_time_reg(volatile unsigned short *reg)
-{
-       unsigned short value;
-       do {
-               value = *reg;
-               barrier();
-       } while (value != *reg);
-       return value;
-}
-
-static unsigned long
-vr4181_rtc_get_time(void)
-{
-       unsigned short regh, regm, regl;
-
-       // why this crazy order, you ask?  to guarantee that neither m
-       // nor l wrap before all 3 read
-       do {
-               regm = read_time_reg(VR4181_ETIMEMREG);
-               barrier();
-               regh = read_time_reg(VR4181_ETIMEHREG);
-               barrier();
-               regl = read_time_reg(VR4181_ETIMELREG);
-       } while (regm != read_time_reg(VR4181_ETIMEMREG));
-       return ((regh << 17) | (regm << 1) | (regl >> 15));
-}
-
-static int
-vr4181_rtc_set_time(unsigned long timeval)
-{
-       unsigned short intreg;
-       unsigned long flags;
-
-       spin_lock_irqsave(&rtc_lock, flags);
-       intreg = *VR4181_RTCINTREG & 0x05;
-       barrier();
-       *VR4181_ETIMELREG = timeval << 15;
-       *VR4181_ETIMEMREG = timeval >> 1;
-       *VR4181_ETIMEHREG = timeval >> 17;
-       barrier();
-       // assume that any ints that just triggered are invalid, since the
-       // time value is written non-atomically in 3 separate regs
-       *VR4181_RTCINTREG = 0x05 ^ intreg;
-       spin_unlock_irqrestore(&rtc_lock, flags);
-
-       return 0;
-}
-
-
-/*
- * timer interrupt routine (wrapper)
- *
- * we need our own interrupt routine because we need to clear
- * RTC1 interrupt.
- */
-static void
-vr4181_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-       /* Clear the interrupt. */
-       *VR4181_RTCINTREG = 0x2;
-
-       /* call the generic one */
-       timer_interrupt(irq, dev_id, regs);
-}
-
-
-/*
- * vr4181_time_init:
- *
- * We pick the following choices:
- *   . we use elapsed timer as the RTC.         We set some reasonable init data since
- *     it does not persist across reset
- *   . we use RTC1 as the system timer interrupt source.
- *   . we use CPU counter for fast_gettimeoffset and we calivrate the cpu
- *     frequency.  In other words, we use calibrate_div64_gettimeoffset().
- *   . we use our own timer interrupt routine which clears the interrupt
- *     and then calls the generic high-level timer interrupt routine.
- *
- */
-
-extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
-
-static void
-vr4181_timer_setup(struct irqaction *irq)
-{
-       /* over-write the handler to be our own one */
-       irq->handler = vr4181_timer_interrupt;
-
-       /* sets up the frequency */
-       *VR4181_RTCL1LREG = COUNTS_PER_JIFFY;
-       *VR4181_RTCL1HREG = 0;
-
-       /* and ack any pending ints */
-       *VR4181_RTCINTREG = 0x2;
-
-       /* setup irqaction */
-       setup_irq(VR4181_IRQ_INT1, irq);
-
-}
-
-void
-vr4181_init_time(void)
-{
-       /* setup hookup functions */
-       rtc_get_time = vr4181_rtc_get_time;
-       rtc_set_time = vr4181_rtc_set_time;
-
-       board_timer_setup = vr4181_timer_setup;
-}
-
diff --git a/arch/mips/vr4181/osprey/Makefile b/arch/mips/vr4181/osprey/Makefile
deleted file mode 100644 (file)
index 34be057..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for common code of NEC Osprey board
-#
-
-obj-y   := setup.o prom.o reset.o
-
-obj-$(CONFIG_KGDB)     += dbg_io.o
diff --git a/arch/mips/vr4181/osprey/dbg_io.c b/arch/mips/vr4181/osprey/dbg_io.c
deleted file mode 100644 (file)
index 5e8a840..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * kgdb io functions for osprey.  We use the serial port on debug board.
- *
- * Copyright (C) 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- */
-
-/* ======================= CONFIG ======================== */
-
-/* [jsun] we use the second serial port for kdb */
-#define         BASE                    0xb7fffff0
-#define         MAX_BAUD                115200
-
-/* distance in bytes between two serial registers */
-#define         REG_OFFSET              1
-
-/*
- * 0 - kgdb does serial init
- * 1 - kgdb skip serial init
- */
-static int remoteDebugInitialized = 1;
-
-/*
- * the default baud rate *if* kgdb does serial init
- */
-#define                BAUD_DEFAULT            UART16550_BAUD_38400
-
-/* ======================= END OF CONFIG ======================== */
-
-typedef unsigned char uint8;
-typedef unsigned int uint32;
-
-#define         UART16550_BAUD_2400             2400
-#define         UART16550_BAUD_4800             4800
-#define         UART16550_BAUD_9600             9600
-#define         UART16550_BAUD_19200            19200
-#define         UART16550_BAUD_38400            38400
-#define         UART16550_BAUD_57600            57600
-#define         UART16550_BAUD_115200           115200
-
-#define         UART16550_PARITY_NONE           0
-#define         UART16550_PARITY_ODD            0x08
-#define         UART16550_PARITY_EVEN           0x18
-#define         UART16550_PARITY_MARK           0x28
-#define         UART16550_PARITY_SPACE          0x38
-
-#define         UART16550_DATA_5BIT             0x0
-#define         UART16550_DATA_6BIT             0x1
-#define         UART16550_DATA_7BIT             0x2
-#define         UART16550_DATA_8BIT             0x3
-
-#define         UART16550_STOP_1BIT             0x0
-#define         UART16550_STOP_2BIT             0x4
-
-/* register offset */
-#define         OFS_RCV_BUFFER          0
-#define         OFS_TRANS_HOLD          0
-#define         OFS_SEND_BUFFER         0
-#define         OFS_INTR_ENABLE         (1*REG_OFFSET)
-#define         OFS_INTR_ID             (2*REG_OFFSET)
-#define         OFS_DATA_FORMAT         (3*REG_OFFSET)
-#define         OFS_LINE_CONTROL        (3*REG_OFFSET)
-#define         OFS_MODEM_CONTROL       (4*REG_OFFSET)
-#define         OFS_RS232_OUTPUT        (4*REG_OFFSET)
-#define         OFS_LINE_STATUS         (5*REG_OFFSET)
-#define         OFS_MODEM_STATUS        (6*REG_OFFSET)
-#define         OFS_RS232_INPUT         (6*REG_OFFSET)
-#define         OFS_SCRATCH_PAD         (7*REG_OFFSET)
-
-#define         OFS_DIVISOR_LSB         (0*REG_OFFSET)
-#define         OFS_DIVISOR_MSB         (1*REG_OFFSET)
-
-
-/* memory-mapped read/write of the port */
-#define         UART16550_READ(y)    (*((volatile uint8*)(BASE + y)))
-#define         UART16550_WRITE(y, z)  ((*((volatile uint8*)(BASE + y))) = z)
-
-void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop)
-{
-        /* disable interrupts */
-        UART16550_WRITE(OFS_INTR_ENABLE, 0);
-
-        /* set up buad rate */
-        {
-                uint32 divisor;
-
-                /* set DIAB bit */
-                UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
-
-                /* set divisor */
-                divisor = MAX_BAUD / baud;
-                UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff);
-                UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8);
-
-                /* clear DIAB bit */
-                UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
-        }
-
-        /* set data format */
-        UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop);
-}
-
-
-uint8 getDebugChar(void)
-{
-        if (!remoteDebugInitialized) {
-                remoteDebugInitialized = 1;
-                debugInit(BAUD_DEFAULT,
-                          UART16550_DATA_8BIT,
-                          UART16550_PARITY_NONE, UART16550_STOP_1BIT);
-        }
-
-        while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0);
-        return UART16550_READ(OFS_RCV_BUFFER);
-}
-
-
-int putDebugChar(uint8 byte)
-{
-        if (!remoteDebugInitialized) {
-                remoteDebugInitialized = 1;
-                debugInit(BAUD_DEFAULT,
-                          UART16550_DATA_8BIT,
-                          UART16550_PARITY_NONE, UART16550_STOP_1BIT);
-        }
-
-        while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0);
-        UART16550_WRITE(OFS_SEND_BUFFER, byte);
-        return 1;
-}
diff --git a/arch/mips/vr4181/osprey/prom.c b/arch/mips/vr4181/osprey/prom.c
deleted file mode 100644 (file)
index af0d145..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- *
- * arch/mips/vr4181/osprey/prom.c
- *     prom code for osprey.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under  the terms of the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/bootmem.h>
-#include <asm/bootinfo.h>
-#include <asm/addrspace.h>
-
-const char *get_system_type(void)
-{
-       return "NEC_Vr41xx Osprey";
-}
-
-/*
- * [jsun] right now we assume it is the nec debug monitor, which does
- * not pass any arguments.
- */
-void __init prom_init(void)
-{
-       // cmdline is now set in default config
-       // strcpy(arcs_cmdline, "ip=bootp ");
-       // strcat(arcs_cmdline, "ether=46,0x03fe0300,eth0 ");
-       // strcpy(arcs_cmdline, "ether=0,0x0300,eth0 "
-       // strcat(arcs_cmdline, "video=vr4181fb:xres:240,yres:320,bpp:8 ");
-
-       mips_machgroup = MACH_GROUP_NEC_VR41XX;
-       mips_machtype = MACH_NEC_OSPREY;
-
-       /* 16MB fixed */
-       add_memory_region(0, 16 << 20, BOOT_MEM_RAM);
-}
-
-unsigned long __init prom_free_prom_memory(void)
-{
-       return 0;
-}
diff --git a/arch/mips/vr4181/osprey/reset.c b/arch/mips/vr4181/osprey/reset.c
deleted file mode 100644 (file)
index 036ae83..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.
- *
- * Copyright (C) 1997, 2001 Ralf Baechle
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <asm/io.h>
-#include <asm/cacheflush.h>
-#include <asm/processor.h>
-#include <asm/reboot.h>
-#include <asm/system.h>
-
-void nec_osprey_restart(char *command)
-{
-       set_c0_status(ST0_ERL);
-       change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
-       flush_cache_all();
-       write_c0_wired(0);
-       __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
-}
-
-void nec_osprey_halt(void)
-{
-       printk(KERN_NOTICE "\n** You can safely turn off the power\n");
-       while (1)
-               __asm__(".set\tmips3\n\t"
-                       "wait\n\t"
-                       ".set\tmips0");
-}
-
-void nec_osprey_power_off(void)
-{
-       nec_osprey_halt();
-}
diff --git a/arch/mips/vr4181/osprey/setup.c b/arch/mips/vr4181/osprey/setup.c
deleted file mode 100644 (file)
index 2ff7140..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * linux/arch/mips/vr4181/setup.c
- *
- * VR41xx setup routines
- *
- * Copyright (C) 1999 Bradley D. LaRonde
- * Copyright (C) 1999, 2000 Michael Klar
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- */
-
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <asm/reboot.h>
-#include <asm/vr4181/vr4181.h>
-#include <asm/io.h>
-
-
-extern void nec_osprey_restart(char* c);
-extern void nec_osprey_halt(void);
-extern void nec_osprey_power_off(void);
-
-extern void vr4181_init_serial(void);
-extern void vr4181_init_time(void);
-
-static void __init nec_osprey_setup(void)
-{
-       set_io_port_base(VR4181_PORT_BASE);
-       isa_slot_offset = VR4181_ISAMEM_BASE;
-
-       vr4181_init_serial();
-       vr4181_init_time();
-
-       _machine_restart = nec_osprey_restart;
-       _machine_halt = nec_osprey_halt;
-       _machine_power_off = nec_osprey_power_off;
-
-       /* setup resource limit */
-       ioport_resource.end = 0xffffffff;
-       iomem_resource.end = 0xffffffff;
-
-       /* [jsun] hack */
-       /*
-       printk("[jsun] hack to change external ISA control register, %x -> %x\n",
-               (*VR4181_XISACTL),
-               (*VR4181_XISACTL) | 0x2);
-       *VR4181_XISACTL |= 0x2;
-       */
-
-       // *VR4181_GPHIBSTH = 0x2000;
-       // *VR4181_GPMD0REG = 0x00c0;
-       // *VR4181_GPINTEN       = 1<<6;
-
-       /* [jsun] I believe this will get the interrupt type right
-        * for the ether port.
-        */
-       *VR4181_GPINTTYPL = 0x3000;
-}
-
-early_initcall(nec_osprey_setup);
index aa8605ab76ff251244c79ed0e5268635ba4993c6..d29201acc4f31cc72087f1013a2cf9198217c82e 100644 (file)
 #include <asm/io.h>
 #include <asm/vr41xx/e55.h>
 
-const char *get_system_type(void)
-{
-       return "CASIO CASSIOPEIA E-11/15/55/65";
-}
-
 static int __init casio_e55_setup(void)
 {
        set_io_port_base(IO_PORT_BASE);
index fa98ef3855bc73c663df5d752e2abb84be722366..9096302a7ecc1e79fed3a3a73f71d67241c07fce 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for common code of the NEC VR4100 series.
 #
 
-obj-y                          += bcu.o cmu.o icu.o init.o int-handler.o pmu.o
+obj-y                          += bcu.o cmu.o icu.o init.o int-handler.o irq.o pmu.o type.o
 obj-$(CONFIG_VRC4173)          += vrc4173.o
 
 EXTRA_AFLAGS := $(CFLAGS)
index c842661144cb9d6edb5ac1dae41f7bb62efd3e5f..0b73c5ab3c0c1ff968803097e3090bbd1c0a3de3 100644 (file)
@@ -3,8 +3,7 @@
  *
  *  Copyright (C) 2001-2002  MontaVista Software Inc.
  *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copyright (C) 2003-2004  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
- *  Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
+ *  Copyright (C) 2003-2005  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
  *
  *  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
@@ -31,7 +30,7 @@
  */
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/interrupt.h>
+#include <linux/ioport.h>
 #include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/smp.h>
 
 #include <asm/cpu.h>
 #include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/irq_cpu.h>
 #include <asm/vr41xx/vr41xx.h>
 
-extern asmlinkage void vr41xx_handle_interrupt(void);
-
-extern void init_vr41xx_giuint_irq(void);
-extern void giuint_irq_dispatch(struct pt_regs *regs);
-
-static uint32_t icu1_base;
-static uint32_t icu2_base;
-
-static struct irqaction icu_cascade = {
-       .handler        = no_action,
-       .mask           = CPU_MASK_NONE,
-       .name           = "cascade",
-};
+static void __iomem *icu1_base;
+static void __iomem *icu2_base;
 
 static unsigned char sysint1_assign[16] = {
        0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 static unsigned char sysint2_assign[16] = {
-       2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+       2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
-#define SYSINT1REG_TYPE1       KSEG1ADDR(0x0b000080)
-#define SYSINT2REG_TYPE1       KSEG1ADDR(0x0b000200)
+#define ICU1_TYPE1_BASE        0x0b000080UL
+#define ICU2_TYPE1_BASE        0x0b000200UL
 
-#define SYSINT1REG_TYPE2       KSEG1ADDR(0x0f000080)
-#define SYSINT2REG_TYPE2       KSEG1ADDR(0x0f0000a0)
+#define ICU1_TYPE2_BASE        0x0f000080UL
+#define ICU2_TYPE2_BASE        0x0f0000a0UL
+
+#define ICU1_SIZE      0x20
+#define ICU2_SIZE      0x1c
 
 #define SYSINT1REG     0x00
 #define PIUINTREG      0x02
@@ -106,61 +95,61 @@ static unsigned char sysint2_assign[16] = {
 #define SYSINT1_IRQ_TO_PIN(x)  ((x) - SYSINT1_IRQ_BASE)        /* Pin 0-15 */
 #define SYSINT2_IRQ_TO_PIN(x)  ((x) - SYSINT2_IRQ_BASE)        /* Pin 0-15 */
 
-#define read_icu1(offset)      readw(icu1_base + (offset))
-#define write_icu1(val, offset)        writew((val), icu1_base + (offset))
+#define INT_TO_IRQ(x)          ((x) + 2)       /* Int0-4 -> IRQ2-6 */
+
+#define icu1_read(offset)              readw(icu1_base + (offset))
+#define icu1_write(offset, value)      writew((value), icu1_base + (offset))
 
-#define read_icu2(offset)      readw(icu2_base + (offset))
-#define write_icu2(val, offset)        writew((val), icu2_base + (offset))
+#define icu2_read(offset)              readw(icu2_base + (offset))
+#define icu2_write(offset, value)      writew((value), icu2_base + (offset))
 
 #define INTASSIGN_MAX  4
 #define INTASSIGN_MASK 0x0007
 
-static inline uint16_t set_icu1(uint8_t offset, uint16_t set)
+static inline uint16_t icu1_set(uint8_t offset, uint16_t set)
 {
-       uint16_t res;
+       uint16_t data;
 
-       res = read_icu1(offset);
-       res |= set;
-       write_icu1(res, offset);
+       data = icu1_read(offset);
+       data |= set;
+       icu1_write(offset, data);
 
-       return res;
+       return data;
 }
 
-static inline uint16_t clear_icu1(uint8_t offset, uint16_t clear)
+static inline uint16_t icu1_clear(uint8_t offset, uint16_t clear)
 {
-       uint16_t res;
+       uint16_t data;
 
-       res = read_icu1(offset);
-       res &= ~clear;
-       write_icu1(res, offset);
+       data = icu1_read(offset);
+       data &= ~clear;
+       icu1_write(offset, data);
 
-       return res;
+       return data;
 }
 
-static inline uint16_t set_icu2(uint8_t offset, uint16_t set)
+static inline uint16_t icu2_set(uint8_t offset, uint16_t set)
 {
-       uint16_t res;
+       uint16_t data;
 
-       res = read_icu2(offset);
-       res |= set;
-       write_icu2(res, offset);
+       data = icu2_read(offset);
+       data |= set;
+       icu2_write(offset, data);
 
-       return res;
+       return data;
 }
 
-static inline uint16_t clear_icu2(uint8_t offset, uint16_t clear)
+static inline uint16_t icu2_clear(uint8_t offset, uint16_t clear)
 {
-       uint16_t res;
+       uint16_t data;
 
-       res = read_icu2(offset);
-       res &= ~clear;
-       write_icu2(res, offset);
+       data = icu2_read(offset);
+       data &= ~clear;
+       icu2_write(offset, data);
 
-       return res;
+       return data;
 }
 
-/*=======================================================================*/
-
 void vr41xx_enable_piuint(uint16_t mask)
 {
        irq_desc_t *desc = irq_desc + PIU_IRQ;
@@ -169,7 +158,7 @@ void vr41xx_enable_piuint(uint16_t mask)
        if (current_cpu_data.cputype == CPU_VR4111 ||
            current_cpu_data.cputype == CPU_VR4121) {
                spin_lock_irqsave(&desc->lock, flags);
-               set_icu1(MPIUINTREG, mask);
+               icu1_set(MPIUINTREG, mask);
                spin_unlock_irqrestore(&desc->lock, flags);
        }
 }
@@ -184,7 +173,7 @@ void vr41xx_disable_piuint(uint16_t mask)
        if (current_cpu_data.cputype == CPU_VR4111 ||
            current_cpu_data.cputype == CPU_VR4121) {
                spin_lock_irqsave(&desc->lock, flags);
-               clear_icu1(MPIUINTREG, mask);
+               icu1_clear(MPIUINTREG, mask);
                spin_unlock_irqrestore(&desc->lock, flags);
        }
 }
@@ -199,7 +188,7 @@ void vr41xx_enable_aiuint(uint16_t mask)
        if (current_cpu_data.cputype == CPU_VR4111 ||
            current_cpu_data.cputype == CPU_VR4121) {
                spin_lock_irqsave(&desc->lock, flags);
-               set_icu1(MAIUINTREG, mask);
+               icu1_set(MAIUINTREG, mask);
                spin_unlock_irqrestore(&desc->lock, flags);
        }
 }
@@ -214,7 +203,7 @@ void vr41xx_disable_aiuint(uint16_t mask)
        if (current_cpu_data.cputype == CPU_VR4111 ||
            current_cpu_data.cputype == CPU_VR4121) {
                spin_lock_irqsave(&desc->lock, flags);
-               clear_icu1(MAIUINTREG, mask);
+               icu1_clear(MAIUINTREG, mask);
                spin_unlock_irqrestore(&desc->lock, flags);
        }
 }
@@ -229,7 +218,7 @@ void vr41xx_enable_kiuint(uint16_t mask)
        if (current_cpu_data.cputype == CPU_VR4111 ||
            current_cpu_data.cputype == CPU_VR4121) {
                spin_lock_irqsave(&desc->lock, flags);
-               set_icu1(MKIUINTREG, mask);
+               icu1_set(MKIUINTREG, mask);
                spin_unlock_irqrestore(&desc->lock, flags);
        }
 }
@@ -244,7 +233,7 @@ void vr41xx_disable_kiuint(uint16_t mask)
        if (current_cpu_data.cputype == CPU_VR4111 ||
            current_cpu_data.cputype == CPU_VR4121) {
                spin_lock_irqsave(&desc->lock, flags);
-               clear_icu1(MKIUINTREG, mask);
+               icu1_clear(MKIUINTREG, mask);
                spin_unlock_irqrestore(&desc->lock, flags);
        }
 }
@@ -257,7 +246,7 @@ void vr41xx_enable_dsiuint(uint16_t mask)
        unsigned long flags;
 
        spin_lock_irqsave(&desc->lock, flags);
-       set_icu1(MDSIUINTREG, mask);
+       icu1_set(MDSIUINTREG, mask);
        spin_unlock_irqrestore(&desc->lock, flags);
 }
 
@@ -269,7 +258,7 @@ void vr41xx_disable_dsiuint(uint16_t mask)
        unsigned long flags;
 
        spin_lock_irqsave(&desc->lock, flags);
-       clear_icu1(MDSIUINTREG, mask);
+       icu1_clear(MDSIUINTREG, mask);
        spin_unlock_irqrestore(&desc->lock, flags);
 }
 
@@ -281,7 +270,7 @@ void vr41xx_enable_firint(uint16_t mask)
        unsigned long flags;
 
        spin_lock_irqsave(&desc->lock, flags);
-       set_icu2(MFIRINTREG, mask);
+       icu2_set(MFIRINTREG, mask);
        spin_unlock_irqrestore(&desc->lock, flags);
 }
 
@@ -293,7 +282,7 @@ void vr41xx_disable_firint(uint16_t mask)
        unsigned long flags;
 
        spin_lock_irqsave(&desc->lock, flags);
-       clear_icu2(MFIRINTREG, mask);
+       icu2_clear(MFIRINTREG, mask);
        spin_unlock_irqrestore(&desc->lock, flags);
 }
 
@@ -308,7 +297,7 @@ void vr41xx_enable_pciint(void)
            current_cpu_data.cputype == CPU_VR4131 ||
            current_cpu_data.cputype == CPU_VR4133) {
                spin_lock_irqsave(&desc->lock, flags);
-               write_icu2(PCIINT0, MPCIINTREG);
+               icu2_write(MPCIINTREG, PCIINT0);
                spin_unlock_irqrestore(&desc->lock, flags);
        }
 }
@@ -324,7 +313,7 @@ void vr41xx_disable_pciint(void)
            current_cpu_data.cputype == CPU_VR4131 ||
            current_cpu_data.cputype == CPU_VR4133) {
                spin_lock_irqsave(&desc->lock, flags);
-               write_icu2(0, MPCIINTREG);
+               icu2_write(MPCIINTREG, 0);
                spin_unlock_irqrestore(&desc->lock, flags);
        }
 }
@@ -340,7 +329,7 @@ void vr41xx_enable_scuint(void)
            current_cpu_data.cputype == CPU_VR4131 ||
            current_cpu_data.cputype == CPU_VR4133) {
                spin_lock_irqsave(&desc->lock, flags);
-               write_icu2(SCUINT0, MSCUINTREG);
+               icu2_write(MSCUINTREG, SCUINT0);
                spin_unlock_irqrestore(&desc->lock, flags);
        }
 }
@@ -356,7 +345,7 @@ void vr41xx_disable_scuint(void)
            current_cpu_data.cputype == CPU_VR4131 ||
            current_cpu_data.cputype == CPU_VR4133) {
                spin_lock_irqsave(&desc->lock, flags);
-               write_icu2(0, MSCUINTREG);
+               icu2_write(MSCUINTREG, 0);
                spin_unlock_irqrestore(&desc->lock, flags);
        }
 }
@@ -372,7 +361,7 @@ void vr41xx_enable_csiint(uint16_t mask)
            current_cpu_data.cputype == CPU_VR4131 ||
            current_cpu_data.cputype == CPU_VR4133) {
                spin_lock_irqsave(&desc->lock, flags);
-               set_icu2(MCSIINTREG, mask);
+               icu2_set(MCSIINTREG, mask);
                spin_unlock_irqrestore(&desc->lock, flags);
        }
 }
@@ -388,7 +377,7 @@ void vr41xx_disable_csiint(uint16_t mask)
            current_cpu_data.cputype == CPU_VR4131 ||
            current_cpu_data.cputype == CPU_VR4133) {
                spin_lock_irqsave(&desc->lock, flags);
-               clear_icu2(MCSIINTREG, mask);
+               icu2_clear(MCSIINTREG, mask);
                spin_unlock_irqrestore(&desc->lock, flags);
        }
 }
@@ -404,7 +393,7 @@ void vr41xx_enable_bcuint(void)
            current_cpu_data.cputype == CPU_VR4131 ||
            current_cpu_data.cputype == CPU_VR4133) {
                spin_lock_irqsave(&desc->lock, flags);
-               write_icu2(BCUINTR, MBCUINTREG);
+               icu2_write(MBCUINTREG, BCUINTR);
                spin_unlock_irqrestore(&desc->lock, flags);
        }
 }
@@ -420,30 +409,28 @@ void vr41xx_disable_bcuint(void)
            current_cpu_data.cputype == CPU_VR4131 ||
            current_cpu_data.cputype == CPU_VR4133) {
                spin_lock_irqsave(&desc->lock, flags);
-               write_icu2(0, MBCUINTREG);
+               icu2_write(MBCUINTREG, 0);
                spin_unlock_irqrestore(&desc->lock, flags);
        }
 }
 
 EXPORT_SYMBOL(vr41xx_disable_bcuint);
 
-/*=======================================================================*/
-
 static unsigned int startup_sysint1_irq(unsigned int irq)
 {
-       set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
+       icu1_set(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(irq));
 
        return 0; /* never anything pending */
 }
 
 static void shutdown_sysint1_irq(unsigned int irq)
 {
-       clear_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
+       icu1_clear(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(irq));
 }
 
 static void enable_sysint1_irq(unsigned int irq)
 {
-       set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
+       icu1_set(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(irq));
 }
 
 #define disable_sysint1_irq    shutdown_sysint1_irq
@@ -452,7 +439,7 @@ static void enable_sysint1_irq(unsigned int irq)
 static void end_sysint1_irq(unsigned int irq)
 {
        if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
-               set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
+               icu1_set(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(irq));
 }
 
 static struct hw_interrupt_type sysint1_irq_type = {
@@ -465,23 +452,21 @@ static struct hw_interrupt_type sysint1_irq_type = {
        .end            = end_sysint1_irq,
 };
 
-/*=======================================================================*/
-
 static unsigned int startup_sysint2_irq(unsigned int irq)
 {
-       set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
+       icu2_set(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(irq));
 
        return 0; /* never anything pending */
 }
 
 static void shutdown_sysint2_irq(unsigned int irq)
 {
-       clear_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
+       icu2_clear(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(irq));
 }
 
 static void enable_sysint2_irq(unsigned int irq)
 {
-       set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
+       icu2_set(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(irq));
 }
 
 #define disable_sysint2_irq    shutdown_sysint2_irq
@@ -490,7 +475,7 @@ static void enable_sysint2_irq(unsigned int irq)
 static void end_sysint2_irq(unsigned int irq)
 {
        if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
-               set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
+               icu2_set(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(irq));
 }
 
 static struct hw_interrupt_type sysint2_irq_type = {
@@ -503,8 +488,6 @@ static struct hw_interrupt_type sysint2_irq_type = {
        .end            = end_sysint2_irq,
 };
 
-/*=======================================================================*/
-
 static inline int set_sysint1_assign(unsigned int irq, unsigned char assign)
 {
        irq_desc_t *desc = irq_desc + irq;
@@ -515,8 +498,8 @@ static inline int set_sysint1_assign(unsigned int irq, unsigned char assign)
 
        spin_lock_irq(&desc->lock);
 
-       intassign0 = read_icu1(INTASSIGN0);
-       intassign1 = read_icu1(INTASSIGN1);
+       intassign0 = icu1_read(INTASSIGN0);
+       intassign1 = icu1_read(INTASSIGN1);
 
        switch (pin) {
        case 0:
@@ -556,8 +539,8 @@ static inline int set_sysint1_assign(unsigned int irq, unsigned char assign)
        }
 
        sysint1_assign[pin] = assign;
-       write_icu1(intassign0, INTASSIGN0);
-       write_icu1(intassign1, INTASSIGN1);
+       icu1_write(INTASSIGN0, intassign0);
+       icu1_write(INTASSIGN1, intassign1);
 
        spin_unlock_irq(&desc->lock);
 
@@ -574,8 +557,8 @@ static inline int set_sysint2_assign(unsigned int irq, unsigned char assign)
 
        spin_lock_irq(&desc->lock);
 
-       intassign2 = read_icu1(INTASSIGN2);
-       intassign3 = read_icu1(INTASSIGN3);
+       intassign2 = icu1_read(INTASSIGN2);
+       intassign3 = icu1_read(INTASSIGN3);
 
        switch (pin) {
        case 0:
@@ -623,8 +606,8 @@ static inline int set_sysint2_assign(unsigned int irq, unsigned char assign)
        }
 
        sysint2_assign[pin] = assign;
-       write_icu1(intassign2, INTASSIGN2);
-       write_icu1(intassign3, INTASSIGN3);
+       icu1_write(INTASSIGN2, intassign2);
+       icu1_write(INTASSIGN3, intassign3);
 
        spin_unlock_irq(&desc->lock);
 
@@ -651,88 +634,92 @@ int vr41xx_set_intassign(unsigned int irq, unsigned char intassign)
 
 EXPORT_SYMBOL(vr41xx_set_intassign);
 
-/*=======================================================================*/
-
-asmlinkage void irq_dispatch(unsigned char intnum, struct pt_regs *regs)
+static int icu_get_irq(unsigned int irq, struct pt_regs *regs)
 {
        uint16_t pend1, pend2;
        uint16_t mask1, mask2;
        int i;
 
-       pend1 = read_icu1(SYSINT1REG);
-       mask1 = read_icu1(MSYSINT1REG);
+       pend1 = icu1_read(SYSINT1REG);
+       mask1 = icu1_read(MSYSINT1REG);
 
-       pend2 = read_icu2(SYSINT2REG);
-       mask2 = read_icu2(MSYSINT2REG);
+       pend2 = icu2_read(SYSINT2REG);
+       mask2 = icu2_read(MSYSINT2REG);
 
        mask1 &= pend1;
        mask2 &= pend2;
 
        if (mask1) {
                for (i = 0; i < 16; i++) {
-                       if (intnum == sysint1_assign[i] &&
-                           (mask1 & ((uint16_t)1 << i))) {
-                               if (i == 8)
-                                       giuint_irq_dispatch(regs);
-                               else
-                                       do_IRQ(SYSINT1_IRQ(i), regs);
-                               return;
-                       }
+                       if (irq == INT_TO_IRQ(sysint1_assign[i]) && (mask1 & (1 << i)))
+                               return SYSINT1_IRQ(i);
                }
        }
 
        if (mask2) {
                for (i = 0; i < 16; i++) {
-                       if (intnum == sysint2_assign[i] &&
-                           (mask2 & ((uint16_t)1 << i))) {
-                               do_IRQ(SYSINT2_IRQ(i), regs);
-                               return;
-                       }
+                       if (irq == INT_TO_IRQ(sysint2_assign[i]) && (mask2 & (1 << i)))
+                               return SYSINT2_IRQ(i);
                }
        }
 
        printk(KERN_ERR "spurious ICU interrupt: %04x,%04x\n", pend1, pend2);
 
        atomic_inc(&irq_err_count);
-}
 
-/*=======================================================================*/
+       return -1;
+}
 
 static int __init vr41xx_icu_init(void)
 {
+       unsigned long icu1_start, icu2_start;
+       int i;
+
        switch (current_cpu_data.cputype) {
        case CPU_VR4111:
        case CPU_VR4121:
-               icu1_base = SYSINT1REG_TYPE1;
-               icu2_base = SYSINT2REG_TYPE1;
+               icu1_start = ICU1_TYPE1_BASE;
+               icu2_start = ICU2_TYPE1_BASE;
                break;
        case CPU_VR4122:
        case CPU_VR4131:
        case CPU_VR4133:
-               icu1_base = SYSINT1REG_TYPE2;
-               icu2_base = SYSINT2REG_TYPE2;
+               icu1_start = ICU1_TYPE2_BASE;
+               icu2_start = ICU2_TYPE2_BASE;
                break;
        default:
                printk(KERN_ERR "ICU: Unexpected CPU of NEC VR4100 series\n");
-               return -EINVAL;
+               return -ENODEV;
        }
 
-       write_icu1(0, MSYSINT1REG);
-       write_icu1(0xffff, MGIUINTLREG);
+       if (request_mem_region(icu1_start, ICU1_SIZE, "ICU") == NULL)
+               return -EBUSY;
 
-       write_icu2(0, MSYSINT2REG);
-       write_icu2(0xffff, MGIUINTHREG);
+       if (request_mem_region(icu2_start, ICU2_SIZE, "ICU") == NULL) {
+               release_mem_region(icu1_start, ICU1_SIZE);
+               return -EBUSY;
+       }
 
-       return 0;
-}
+       icu1_base = ioremap(icu1_start, ICU1_SIZE);
+       if (icu1_base == NULL) {
+               release_mem_region(icu1_start, ICU1_SIZE);
+               release_mem_region(icu2_start, ICU2_SIZE);
+               return -ENOMEM;
+       }
 
-early_initcall(vr41xx_icu_init);
+       icu2_base = ioremap(icu2_start, ICU2_SIZE);
+       if (icu2_base == NULL) {
+               iounmap(icu1_base);
+               release_mem_region(icu1_start, ICU1_SIZE);
+               release_mem_region(icu2_start, ICU2_SIZE);
+               return -ENOMEM;
+       }
 
-/*=======================================================================*/
+       icu1_write(MSYSINT1REG, 0);
+       icu1_write(MGIUINTLREG, 0xffff);
 
-static inline void init_vr41xx_icu_irq(void)
-{
-       int i;
+       icu2_write(MSYSINT2REG, 0);
+       icu2_write(MGIUINTHREG, 0xffff);
 
        for (i = SYSINT1_IRQ_BASE; i <= SYSINT1_IRQ_LAST; i++)
                irq_desc[i].handler = &sysint1_irq_type;
@@ -740,18 +727,13 @@ static inline void init_vr41xx_icu_irq(void)
        for (i = SYSINT2_IRQ_BASE; i <= SYSINT2_IRQ_LAST; i++)
                irq_desc[i].handler = &sysint2_irq_type;
 
-       setup_irq(INT0_CASCADE_IRQ, &icu_cascade);
-       setup_irq(INT1_CASCADE_IRQ, &icu_cascade);
-       setup_irq(INT2_CASCADE_IRQ, &icu_cascade);
-       setup_irq(INT3_CASCADE_IRQ, &icu_cascade);
-       setup_irq(INT4_CASCADE_IRQ, &icu_cascade);
-}
+       cascade_irq(INT0_IRQ, icu_get_irq);
+       cascade_irq(INT1_IRQ, icu_get_irq);
+       cascade_irq(INT2_IRQ, icu_get_irq);
+       cascade_irq(INT3_IRQ, icu_get_irq);
+       cascade_irq(INT4_IRQ, icu_get_irq);
 
-void __init arch_init_irq(void)
-{
-       mips_cpu_irq_init(MIPS_CPU_IRQ_BASE);
-       init_vr41xx_icu_irq();
-       init_vr41xx_giuint_irq();
-
-       set_except_vector(0, vr41xx_handle_interrupt);
+       return 0;
 }
+
+core_initcall(vr41xx_icu_init);
index 38ff89b505f21a44a96eaafb7dd70028ff43c795..272c13aee4fd1c7e0bffc10e01330b278c7fd330 100644 (file)
 
                andi    t1, t0, CAUSEF_IP3      # check for Int1
                bnez    t1, handle_int
-               li      a0, 1
+               li      a0, 3
 
                andi    t1, t0, CAUSEF_IP4      # check for Int2
                bnez    t1, handle_int
-               li      a0, 2
+               li      a0, 4
 
                andi    t1, t0, CAUSEF_IP5      # check for Int3
                bnez    t1, handle_int
-               li      a0, 3
+               li      a0, 5
 
                andi    t1, t0, CAUSEF_IP6      # check for Int4
                bnez    t1, handle_int
-               li      a0, 4
+               li      a0, 6
 
 1:
                andi    t1, t0, CAUSEF_IP2      # check for Int0
                bnez    t1, handle_int
-               li      a0, 0
+               li      a0, 2
 
                andi    t1, t0, CAUSEF_IP0      # check for IP0
                bnez    t1, handle_irq
diff --git a/arch/mips/vr41xx/common/irq.c b/arch/mips/vr41xx/common/irq.c
new file mode 100644 (file)
index 0000000..43b214d
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *  Interrupt handing routines for NEC VR4100 series.
+ *
+ *  Copyright (C) 2005  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/interrupt.h>
+#include <linux/module.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/system.h>
+#include <asm/vr41xx/vr41xx.h>
+
+typedef struct irq_cascade {
+       int (*get_irq)(unsigned int, struct pt_regs *);
+} irq_cascade_t;
+
+static irq_cascade_t irq_cascade[NR_IRQS] __cacheline_aligned;
+
+static struct irqaction cascade_irqaction = {
+       .handler        = no_action,
+       .mask           = CPU_MASK_NONE,
+       .name           = "cascade",
+};
+
+int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int, struct pt_regs *))
+{
+       int retval = 0;
+
+       if (irq >= NR_IRQS)
+               return -EINVAL;
+
+       if (irq_cascade[irq].get_irq != NULL)
+               free_irq(irq, NULL);
+
+       irq_cascade[irq].get_irq = get_irq;
+
+       if (get_irq != NULL) {
+               retval = setup_irq(irq, &cascade_irqaction);
+               if (retval < 0)
+                       irq_cascade[irq].get_irq = NULL;
+       }
+
+       return retval;
+}
+
+EXPORT_SYMBOL_GPL(cascade_irq);
+
+asmlinkage void irq_dispatch(unsigned int irq, struct pt_regs *regs)
+{
+       irq_cascade_t *cascade;
+       irq_desc_t *desc;
+
+       if (irq >= NR_IRQS) {
+               atomic_inc(&irq_err_count);
+               return;
+       }
+
+       cascade = irq_cascade + irq;
+       if (cascade->get_irq != NULL) {
+               unsigned int source_irq = irq;
+               desc = irq_desc + source_irq;
+               desc->handler->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);
+       } else
+               do_IRQ(irq, regs);
+}
+
+extern asmlinkage void vr41xx_handle_interrupt(void);
+
+void __init arch_init_irq(void)
+{
+       mips_cpu_irq_init(MIPS_CPU_IRQ_BASE);
+
+       set_except_vector(0, vr41xx_handle_interrupt);
+}
similarity index 85%
rename from arch/mips/vr41xx/tanbac-tb0226/setup.c
rename to arch/mips/vr41xx/common/type.c
index 60027e5dea25cc0df1038476752180e02c489d4d..bcb5f71b5026b77780d7e35add1c508e849e9510 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  setup.c, Setup for the TANBAC TB0226.
+ *  type.c, System type for NEC VR4100 series.
  *
- *  Copyright (C) 2002-2005  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *  Copyright (C) 2005  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
  *
  *  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
@@ -20,5 +20,5 @@
 
 const char *get_system_type(void)
 {
-       return "TANBAC TB0226";
+       return "NEC VR4100 series";
 }
index 5475dd72e2649becc41a73cd54718cb051946067..ba58764ef8ead5b0613fa13424caa50c336446c9 100644 (file)
@@ -476,7 +476,7 @@ static inline int vrc4173_icu_init(int cascade_irq)
 
        if (cascade_irq < GIU_IRQ(0) || cascade_irq > GIU_IRQ(15))
                return -EINVAL;
-       
+
        vrc4173_outw(0, VRC4173_MSYSINT1REG);
 
        vr41xx_set_irq_trigger(GIU_IRQ_TO_PIN(cascade_irq), TRIGGER_LEVEL, SIGNAL_THROUGH);
index cff44602d3d414f0fae2dad5ffe1af26a1d5e94c..e4b34ad6ea61ec8bf3e087fb02d51007403e9e41 100644 (file)
 #include <asm/io.h>
 #include <asm/vr41xx/workpad.h>
 
-const char *get_system_type(void)
-{
-       return "IBM WorkPad z50";
-}
-
 static int __init ibm_workpad_setup(void)
 {
        set_io_port_base(IO_PORT_BASE);
index 87f06b3f5a9cbf29a6ceb8a6eb496cd3937fcd67..be590edb0b83944b2c8dd7d083a83ec9dc2b6da6 100644 (file)
  * Manish Lachwani (mlachwani@mvista.com)
  */
 #include <linux/config.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-
-#include <asm/bootinfo.h>
 
 #ifdef CONFIG_ROCKHOPPER
 #include <asm/io.h>
 
 #define PCICONFDREG    0xaf000c14
 #define PCICONFAREG    0xaf000c18
-#endif
-
-const char *get_system_type(void)
-{
-       return "NEC CMB-VR4133";
-}
 
-#ifdef CONFIG_ROCKHOPPER
 void disable_pcnet(void)
 {
        u32 data;
diff --git a/arch/mips/vr41xx/tanbac-tb0226/Makefile b/arch/mips/vr41xx/tanbac-tb0226/Makefile
deleted file mode 100644 (file)
index 372f953..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the TANBAC TB0226 specific parts of the kernel
-#
-
-obj-y                  += setup.o
diff --git a/arch/mips/vr41xx/tanbac-tb0229/Makefile b/arch/mips/vr41xx/tanbac-tb0229/Makefile
deleted file mode 100644 (file)
index 9c6b864..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the TANBAC TB0229(VR4131DIMM) specific parts of the kernel
-#
-
-obj-y                          := setup.o
diff --git a/arch/mips/vr41xx/tanbac-tb0229/setup.c b/arch/mips/vr41xx/tanbac-tb0229/setup.c
deleted file mode 100644 (file)
index 5c1b757..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- *  setup.c, Setup for the TANBAC TB0229 (VR4131DIMM)
- *
- *  Copyright (C) 2002-2005  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
- *
- *  Modified for TANBAC TB0229:
- *  Copyright (C) 2003  Megasolution Inc.  <matsu@megasolution.jp>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-const char *get_system_type(void)
-{
-       return "TANBAC TB0229";
-}
diff --git a/arch/mips/vr41xx/victor-mpc30x/Makefile b/arch/mips/vr41xx/victor-mpc30x/Makefile
deleted file mode 100644 (file)
index a2e8086..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the Victor MP-C303/304 specific parts of the kernel
-#
-
-obj-y                  += setup.o
diff --git a/arch/mips/vr41xx/victor-mpc30x/setup.c b/arch/mips/vr41xx/victor-mpc30x/setup.c
deleted file mode 100644 (file)
index f591e36..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- *  setup.c, Setup for the Victor MP-C303/304.
- *
- *  Copyright (C) 2002-2005  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-const char *get_system_type(void)
-{
-       return "Victor MP-C303/304";
-}
diff --git a/arch/mips/vr41xx/zao-capcella/Makefile b/arch/mips/vr41xx/zao-capcella/Makefile
deleted file mode 100644 (file)
index cf42019..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the ZAO Networks Capcella  specific parts of the kernel
-#
-
-obj-y                  += setup.o
diff --git a/arch/mips/vr41xx/zao-capcella/setup.c b/arch/mips/vr41xx/zao-capcella/setup.c
deleted file mode 100644 (file)
index 17bade2..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- *  setup.c, Setup for the ZAO Networks Capcella.
- *
- *  Copyright (C) 2002-2005  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-const char *get_system_type(void)
-{
-       return "ZAO Networks Capcella";
-}
index 1c2d87435233ca911ff1d4773cf7268a0847e504..0b07922a2ac603e32451514a64a5250878389b5c 100644 (file)
@@ -49,6 +49,10 @@ config ISA_DMA_API
        bool
        default y
 
+config ARCH_MAY_HAVE_PC_FDC
+       bool
+       default y
+
 source "init/Kconfig"
 
 
index 9421bb98ea6398a369bc01e2811f55491ef065fc..55d71c15e1f7cebc25b68c9e9facb4c7fdfb69e4 100644 (file)
@@ -517,13 +517,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
        if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall))
                return 0;
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
        return 1;
 }
 
index 6cf7407344badb9c4a7841b94d98251ec6264e27..7ff67f8e9f8c019bd2132cef0e3cabf6768859d9 100644 (file)
@@ -188,10 +188,7 @@ do_settimeofday (struct timespec *tv)
                set_normalized_timespec(&xtime, sec, nsec);
                set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
-               time_adjust = 0;                /* stop active adjtime() */
-               time_status |= STA_UNSYNC;
-               time_maxerror = NTP_PHASE_LIMIT;
-               time_esterror = NTP_PHASE_LIMIT;
+               ntp_clear();
        }
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
index e6fa1d1cc03a210991b6b029cd9c6bb50106037e..6ab7e5ea5fcfd9e0ae748d83bde3f31f158fa25b 100644 (file)
@@ -47,6 +47,10 @@ config SCHED_NO_NO_OMIT_FRAME_POINTER
        bool
        default y
 
+config ARCH_MAY_HAVE_PC_FDC
+       bool
+       default y
+
 source "init/Kconfig"
 
 menu "Processor"
@@ -330,14 +334,6 @@ config RPXLITE
          End of life: end 2000 ?
          URL: see TQM850L
 
-         SPD823TS:
-         MPC823 based board used in the "Tele Server" product
-         Manufacturer: Speech Design, <http://www.speech-design.de/>
-         Date of Release: Mid 2000 (?)
-         End of life: -
-         URL: <http://www.speech-design.de/>
-         select "English", then "Teleteam Solutions", then "TeleServer"
-
          IVMS8:
          MPC860 based board used in the "Integrated Voice Mail System",
          Small Version (8 voice channels)
@@ -354,13 +350,6 @@ config RPXLITE
          End of life: -
          URL: <http://www.speech-design.de/>
 
-         SM850:
-         Service Module (based on TQM850L)
-         Manufacturer: Dependable Computer Systems, <http://www.decomsys.com/>
-         Date of Release: end 2000 (?)
-         End of life: mid 2001 (?)
-         URL: <http://www.tz-mikroelektronik.de/ServiceModule/index.html>
-
          HERMES:
          Hermes-Pro ISDN/LAN router with integrated 8 x hub
          Manufacturer: Multidata Gesellschaft fur Datentechnik und Informatik
@@ -464,13 +453,6 @@ config TQM860L
 config FPS850L
        bool "FPS850L"
 
-config SPD823TS
-       bool "SPD823TS"
-       help
-         Say Y here to support the Speech Design 823 Tele-Server from Speech
-         Design, released in 2000.  The manufacturer's website is at
-         <http://www.speech-design.de/>.
-
 config IVMS8
        bool "IVMS8"
        help
@@ -485,14 +467,6 @@ config IVML24
          from Speech Design, released March 2001.  The manufacturer's website
          is at <http://www.speech-design.de/>.
 
-config SM850
-       bool "SM850"
-       help
-         Say Y here to support the Service Module 850 from Dependable
-         Computer Systems, an SBC based on the TQM850L module by TQ
-         Components.  This board is no longer in production.  The
-         manufacturer's website is at <http://www.decomsys.com/>.
-
 config HERMES_PRO
        bool "HERMES"
 
@@ -525,6 +499,11 @@ config WINCEPT
          MPC821 PowerPC, introduced in 1998 and designed to be used in
          thin-client machines.  Say Y to support it directly.
 
+         Be aware that PCI buses can only function when SYS board is plugged
+         into the PIB (Platform IO Board) board from Freescale which provide
+         3 PCI slots.  The PIBs PCI initialization is the bootloader's
+         responsiblilty.
+
 endchoice
 
 choice
@@ -578,9 +557,6 @@ config CPCI690
        help
          Select CPCI690 if configuring a Force CPCI690 cPCI board.
 
-config PCORE
-       bool "Force-PowerCore"
-
 config POWERPMC250
        bool "Force-PowerPMC250"
 
@@ -613,9 +589,6 @@ config EV64260
 config LOPEC
        bool "Motorola-LoPEC"
 
-config MCPN765
-       bool "Motorola-MCPN765"
-
 config MVME5100
        bool "Motorola-MVME5100"
 
@@ -637,12 +610,6 @@ config SANDPOINT
 config RADSTONE_PPC7D
        bool "Radstone Technology PPC7D board"
 
-config ADIR
-       bool "SBS-Adirondack"
-
-config K2
-       bool "SBS-K2"
-
 config PAL4
        bool "SBS-Palomar4"
 
@@ -713,6 +680,11 @@ config MPC834x_SYS
        help
          This option enables support for the MPC 834x SYS evaluation board.
 
+config EV64360
+       bool "Marvell-EV64360BP"
+       help
+         Select EV64360 if configuring a Marvell EV64360BP Evaluation
+         platform.
 endchoice
 
 config PQ2ADS
@@ -722,7 +694,7 @@ config PQ2ADS
 
 config TQM8xxL
        bool
-       depends on 8xx && (TQM823L || TQM850L || FPS850L || TQM855L || TQM860L || SM850)
+       depends on 8xx && (TQM823L || TQM850L || FPS850L || TQM855L || TQM860L)
        default y
 
 config EMBEDDEDBOOT
@@ -796,15 +768,15 @@ config PPC_OF
 
 config PPC_GEN550
        bool
-       depends on SANDPOINT || MCPN765 || SPRUCE || PPLUS || PCORE || \
-               PRPMC750 || K2 || PRPMC800 || LOPEC || \
+       depends on SANDPOINT || SPRUCE || PPLUS || \
+               PRPMC750 || PRPMC800 || LOPEC || \
                (EV64260 && !SERIAL_MPSC) || CHESTNUT || RADSTONE_PPC7D || \
                83xx
        default y
 
 config FORCE
        bool
-       depends on 6xx && (PCORE || POWERPMC250)
+       depends on 6xx && POWERPMC250
        default y
 
 config GT64260
@@ -814,7 +786,7 @@ config GT64260
 
 config MV64360         # Really MV64360 & MV64460
        bool
-       depends on CHESTNUT || KATANA || RADSTONE_PPC7D || HDPU
+       depends on CHESTNUT || KATANA || RADSTONE_PPC7D || HDPU || EV64360
        default y
 
 config MV64X60
@@ -867,7 +839,7 @@ config EPIC_SERIAL_MODE
 
 config MPC10X_BRIDGE
        bool
-       depends on PCORE || POWERPMC250 || LOPEC || SANDPOINT
+       depends on POWERPMC250 || LOPEC || SANDPOINT
        default y
 
 config MPC10X_OPENPIC
@@ -886,10 +858,6 @@ config SANDPOINT_ENABLE_UART1
          If this option is enabled then the MPC824x processor will run
          in DUART mode instead of UART mode.
 
-config CPC710_DATA_GATHERING
-       bool "Enable CPC710 data gathering"
-       depends on K2
-
 config HARRIER_STORE_GATHERING
        bool "Enable Harrier store gathering"
        depends on HARRIER
@@ -1194,6 +1162,11 @@ config PCI_DOMAINS
        bool
        default PCI
 
+config MPC83xx_PCI2
+       bool "  Supprt for 2nd PCI host controller"
+       depends on PCI && MPC834x
+       default y if MPC834x_SYS
+
 config PCI_QSPAN
        bool "QSpan PCI"
        depends on !4xx && !CPM2 && 8xx
index e16c7710d4bef3442160e3d1886b7ac2690ba786..61653cb60c4e3f01f294f0dd04301446d5049a1d 100644 (file)
@@ -62,7 +62,8 @@ config BOOTX_TEXT
 
 config SERIAL_TEXT_DEBUG
        bool "Support for early boot texts over serial port"
-       depends on 4xx || GT64260 || LOPEC || PPLUS || PRPMC800 || PPC_GEN550 || PPC_MPC52xx
+       depends on 4xx || LOPEC || MV64X60 || PPLUS || PRPMC800 || \
+               PPC_GEN550 || PPC_MPC52xx
 
 config PPC_OCP
        bool
index f9b0d778dd82ee1d0ec03b2273f46511a51cdf4c..d1b6e6dcb50414af2ca4fe38ab3f463bd2a8ded5 100644 (file)
@@ -21,11 +21,13 @@ CC          := $(CC) -m32
 endif
 
 LDFLAGS_vmlinux        := -Ttext $(KERNELLOAD) -Bstatic
-CPPFLAGS       += -Iarch/$(ARCH)
+CPPFLAGS       += -Iarch/$(ARCH) -Iinclude3
 AFLAGS         += -Iarch/$(ARCH)
 CFLAGS         += -Iarch/$(ARCH) -msoft-float -pipe \
                -ffixed-r2 -mmultiple
 CPP            = $(CC) -E $(CFLAGS)
+# Temporary hack until we have migrated to asm-powerpc
+LINUXINCLUDE    += -Iinclude3
 
 CHECKFLAGS     += -D__powerpc__
 
@@ -101,6 +103,7 @@ endef
 
 archclean:
        $(Q)$(MAKE) $(clean)=arch/ppc/boot
+       $(Q)rm -rf include3
 
 prepare: include/asm-$(ARCH)/offsets.h checkbin
 
@@ -110,6 +113,12 @@ arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \
 include/asm-$(ARCH)/offsets.h: arch/$(ARCH)/kernel/asm-offsets.s
        $(call filechk,gen-asm-offsets)
 
+# Temporary hack until we have migrated to asm-powerpc
+include/asm: include3/asm
+include3/asm:
+       $(Q)if [ ! -d include3 ]; then mkdir -p include3; fi
+       $(Q)ln -fsn $(srctree)/include/asm-powerpc include3/asm
+
 # Use the file '.tmp_gas_check' for binutils tests, as gas won't output
 # to stdout and these checks are run even on install targets.
 TOUT   := .tmp_gas_check
index d4dc4fa79647e856fcd5a853dd0e41106cab9b02..b7bd8f61a4adaab4afb1fd4a5bda99693bfcbc55 100644 (file)
@@ -96,10 +96,6 @@ zimageinitrd-$(CONFIG_OCOTEA)                := zImage.initrd-TREE
 zimageinitrd-$(CONFIG_GEMINI)          := zImage.initrd-STRIPELF
          end-$(CONFIG_GEMINI)          := gemini
 
-     extra.o-$(CONFIG_K2)              := prepmap.o
-         end-$(CONFIG_K2)              := k2
-   cacheflag-$(CONFIG_K2)              := -include $(clear_L2_L3)
-
      extra.o-$(CONFIG_KATANA)          := misc-katana.o
          end-$(CONFIG_KATANA)          := katana
    cacheflag-$(CONFIG_KATANA)          := -include $(clear_L2_L3)
@@ -108,12 +104,15 @@ zimageinitrd-$(CONFIG_GEMINI)             := zImage.initrd-STRIPELF
          end-$(CONFIG_RADSTONE_PPC7D)  := radstone_ppc7d
    cacheflag-$(CONFIG_RADSTONE_PPC7D)  := -include $(clear_L2_L3)
 
+     extra.o-$(CONFIG_EV64360)          := misc-ev64360.o
+         end-$(CONFIG_EV64360)          := ev64360
+   cacheflag-$(CONFIG_EV64360)          := -include $(clear_L2_L3)
+
 # kconfig 'feature', only one of these will ever be 'y' at a time.
 # The rest will be unset.
-motorola := $(CONFIG_MCPN765)$(CONFIG_MVME5100)$(CONFIG_PRPMC750) \
+motorola := $(CONFIG_MVME5100)$(CONFIG_PRPMC750) \
 $(CONFIG_PRPMC800)$(CONFIG_LOPEC)$(CONFIG_PPLUS)
 motorola := $(strip $(motorola))
-pcore := $(CONFIG_PCORE)$(CONFIG_POWERPMC250)
 
       zimage-$(motorola)               := zImage-PPLUS
 zimageinitrd-$(motorola)               := zImage.initrd-PPLUS
@@ -123,12 +122,6 @@ zimageinitrd-$(motorola)           := zImage.initrd-PPLUS
      extra.o-$(CONFIG_PPLUS)           := prepmap.o
      extra.o-$(CONFIG_LOPEC)           := mpc10x_memory.o
 
-      zimage-$(pcore)                  := zImage-STRIPELF
-zimageinitrd-$(pcore)                  := zImage.initrd-STRIPELF
-     extra.o-$(pcore)                  := chrpmap.o
-         end-$(pcore)                  := pcore
-   cacheflag-$(pcore)                  := -include $(clear_L2_L3)
-
 # Really only valid if CONFIG_6xx=y
       zimage-$(CONFIG_PPC_PREP)                := zImage-PPLUS
 zimageinitrd-$(CONFIG_PPC_PREP)                := zImage.initrd-PPLUS
@@ -158,8 +151,6 @@ zimageinitrd-$(CONFIG_LITE5200)             := zImage.initrd-STRIPELF
 
 # This is a treeboot that needs init functions until the
 # boot rom is sorted out (i.e. this is short lived)
-extra-aflags-$(CONFIG_REDWOOD_4)       := -Wa,-m405
-extra.o-$(CONFIG_REDWOOD_4)            := rw4/rw4_init.o rw4/rw4_init_brd.o
 EXTRA_AFLAGS := $(extra-aflags-y)
 # head.o needs to get the cacheflags defined.
 AFLAGS_head.o                          += $(cacheflag-y)
index c342b47e763e526e469b869603d224226ba12919..491a691d10ccabb007b73f8b34de4dbc4f246f2e 100644 (file)
@@ -784,28 +784,12 @@ embed_config(bd_t ** bdp)
 #ifdef CONFIG_IBM_OPENBIOS
 /* This could possibly work for all treeboot roms.
 */
-#if defined(CONFIG_ASH) || defined(CONFIG_BEECH) || defined(CONFIG_BUBINGA)
+#if defined(CONFIG_BUBINGA)
 #define BOARD_INFO_VECTOR       0xFFF80B50 /* openbios 1.19 moved this vector down  - armin */
 #else
 #define BOARD_INFO_VECTOR      0xFFFE0B50
 #endif
 
-#ifdef CONFIG_BEECH
-static void
-get_board_info(bd_t **bdp)
-{
-       typedef void (*PFV)(bd_t *bd);
-       ((PFV)(*(unsigned long *)BOARD_INFO_VECTOR))(*bdp);
-       return;
-}
-
-void
-embed_config(bd_t **bdp)
-{
-        *bdp = &bdinfo;
-       get_board_info(bdp);
-}
-#else /* !CONFIG_BEECH */
 void
 embed_config(bd_t **bdp)
 {
@@ -860,7 +844,6 @@ embed_config(bd_t **bdp)
 #endif
        timebase_period_ns = 1000000000 / bd->bi_tbfreq;
 }
-#endif /* CONFIG_BEECH */
 #endif /* CONFIG_IBM_OPENBIOS */
 
 #ifdef CONFIG_EP405
@@ -943,39 +926,3 @@ embed_config(bd_t **bdp)
 #endif
 }
 #endif
-
-#ifdef CONFIG_RAINIER
-/* Rainier uses vxworks bootrom */
-void
-embed_config(bd_t **bdp)
-{
-       u_char  *cp;
-       int     i;
-       bd_t    *bd;
-       
-       bd = &bdinfo;
-       *bdp = bd;
-       
-       for(i=0;i<8192;i+=32) {
-               __asm__("dccci 0,%0" :: "r" (i));
-       }
-       __asm__("iccci 0,0");
-       __asm__("sync;isync");
-
-       /* init ram for parity */
-       memset(0, 0,0x400000);  /* Lo memory */
-
-
-       bd->bi_memsize   = (32 * 1024 * 1024) ;
-       bd->bi_intfreq = 133000000; //the internal clock is 133 MHz
-       bd->bi_busfreq   = 100000000;
-       bd->bi_pci_busfreq= 33000000;
-
-       cp = (u_char *)def_enet_addr;
-       for (i=0; i<6; i++) {
-               bd->bi_enetaddr[i] = *cp++;
-       }
-
-}
-#endif
-
index 524053202bb4844232c5f3a57809f1d00ffba39d..5e4adc298bf9cdaf4aa12e655413a84fa1cdf190 100644 (file)
@@ -120,15 +120,6 @@ haveOF:
        mtspr   SPRN_DER,r4
 #endif
 
-#ifdef CONFIG_REDWOOD_4
-       /* All of this Redwood 4 stuff will soon disappear when the
-        * boot rom is straightened out.
-        */
-       mr      r29, r3         /* Easier than changing the other code */
-       bl      HdwInit
-       mr      r3, r29
-#endif
-
 #if defined(CONFIG_MBX) || defined(CONFIG_RPX8260) || defined(CONFIG_PPC_PREP)
        mr      r4,r29  /* put the board info pointer where the relocate
                         * routine will find it
index ef08e86c9b25d398ddb2144bbeadcf4f2c4cd660..26860300fa090e9302570811475afad8ab768dc2 100644 (file)
  */
 
 #include <linux/types.h>
+#include <asm/io.h>
 #include <platforms/cpci690.h>
 
+#define        KB      (1024UL)
+#define        MB      (1024UL*KB)
+#define        GB      (1024UL*MB)
+
 extern u32 mv64x60_console_baud;
 extern u32 mv64x60_mpsc_clk_src;
 extern u32 mv64x60_mpsc_clk_freq;
 
+u32 mag = 0xffff;
+
+unsigned long
+get_mem_size(void)
+{
+       u32     size;
+
+       switch (in_8(((void __iomem *)CPCI690_BR_BASE + CPCI690_BR_MEM_CTLR))
+                       & 0x07) {
+       case 0x01:
+               size = 256*MB;
+               break;
+       case 0x02:
+               size = 512*MB;
+               break;
+       case 0x03:
+               size = 768*MB;
+               break;
+       case 0x04:
+               size = 1*GB;
+               break;
+       case 0x05:
+               size = 1*GB + 512*MB;
+               break;
+       case 0x06:
+               size = 2*GB;
+               break;
+       default:
+               size = 0;
+       }
+
+       return size;
+}
+
 void
 mv64x60_board_init(void __iomem *old_base, void __iomem *new_base)
 {
        mv64x60_console_baud = CPCI690_MPSC_BAUD;
        mv64x60_mpsc_clk_src = CPCI690_MPSC_CLK_SRC;
-       mv64x60_mpsc_clk_freq = CPCI690_BUS_FREQ;
+       mv64x60_mpsc_clk_freq =
+               (get_mem_size() >= (1*GB)) ? 100000000 : 133333333;
 }
diff --git a/arch/ppc/boot/simple/misc-ev64360.c b/arch/ppc/boot/simple/misc-ev64360.c
new file mode 100644 (file)
index 0000000..cd1ccf2
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * arch/ppc/boot/simple/misc-ev64360.c
+ * Copyright (C) 2005 Lee Nicks <allinux@gmail.com>
+ *
+ * Based on arch/ppc/boot/simple/misc-katana.c from:
+ * Mark A. Greer <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/mv64x60_defs.h>
+#include <platforms/ev64360.h>
+
+extern u32 mv64x60_console_baud;
+extern u32 mv64x60_mpsc_clk_src;
+extern u32 mv64x60_mpsc_clk_freq;
+
+/* Not in the kernel so won't include kernel.h to get its 'min' definition */
+#ifndef min
+#define        min(a,b)        (((a) < (b)) ? (a) : (b))
+#endif
+
+void
+mv64x60_board_init(void __iomem *old_base, void __iomem *new_base)
+{
+       mv64x60_console_baud  = EV64360_DEFAULT_BAUD;
+       mv64x60_mpsc_clk_src  = EV64360_MPSC_CLK_SRC;
+       mv64x60_mpsc_clk_freq = EV64360_MPSC_CLK_FREQ;
+}
index b6e1bb833157d0d6815c670dee9a29caf676fdfb..ec94a11bacac6d2320d9adbaaaf4d2ab874334d2 100644 (file)
@@ -26,6 +26,8 @@ extern u32 mv64x60_mpsc_clk_freq;
 #define        min(a,b)        (((a) < (b)) ? (a) : (b))
 #endif
 
+unsigned long mv64360_get_mem_size(void);
+
 void
 mv64x60_board_init(void __iomem *old_base, void __iomem *new_base)
 {
@@ -35,3 +37,9 @@ mv64x60_board_init(void __iomem *old_base, void __iomem *new_base)
                min(katana_bus_freq((void __iomem *)KATANA_CPLD_BASE),
                        MV64x60_TCLK_FREQ_MAX);
 }
+
+unsigned long
+get_mem_size(void)
+{
+       return mv64360_get_mem_size();
+}
index 7e88fc6d207d2b0dafdcdcba52429d4a8f3a52c4..258d4599fadc5b294322f9d3f11dcea4d3c7bff3 100644 (file)
 extern struct bi_record *decompress_kernel(unsigned long load_addr,
        int num_words, unsigned long cksum);
 
+
+u32 size_reg[MV64x60_CPU2MEM_WINDOWS] = {
+       MV64x60_CPU2MEM_0_SIZE, MV64x60_CPU2MEM_1_SIZE,
+       MV64x60_CPU2MEM_2_SIZE, MV64x60_CPU2MEM_3_SIZE
+};
+
+/* Read mem ctlr to get the amount of mem in system */
+unsigned long
+mv64360_get_mem_size(void)
+{
+       u32     enables, i, v;
+       u32     mem = 0;
+
+       enables = in_le32((void __iomem *)CONFIG_MV64X60_NEW_BASE +
+               MV64360_CPU_BAR_ENABLE) & 0xf;
+
+       for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++)
+               if (!(enables & (1<<i))) {
+                       v = in_le32((void __iomem *)CONFIG_MV64X60_NEW_BASE
+                               + size_reg[i]) & 0xffff;
+                       v = (v + 1) << 16;
+                       mem += v;
+               }
+
+       return mem;
+}
+
 void
 mv64x60_move_base(void __iomem *old_base, void __iomem *new_base)
 {
index 5b45eb46b669335482fd7354aeff34191a69eab8..b9c24d4c738bb56005c22226afa8cc33378cd9e7 100644 (file)
 #include <asm/mv64x60_defs.h>
 #include <mpsc_defs.h>
 
+#ifdef CONFIG_EV64360
+#include <platforms/ev64360.h>
+u32    mv64x60_console_baud = EV64360_DEFAULT_BAUD;
+u32    mv64x60_mpsc_clk_src = EV64360_MPSC_CLK_SRC; /* TCLK */
+u32    mv64x60_mpsc_clk_freq = EV64360_MPSC_CLK_FREQ;
+#else
 u32    mv64x60_console_baud = 9600;
 u32    mv64x60_mpsc_clk_src = 8; /* TCLK */
 u32    mv64x60_mpsc_clk_freq = 100000000;
+#endif
 
 extern void udelay(long);
 static void stop_dma(int chan);
diff --git a/arch/ppc/boot/utils/addRamDisk.c b/arch/ppc/boot/utils/addRamDisk.c
deleted file mode 100644 (file)
index 93400df..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <netinet/in.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
-
-#define ElfHeaderSize  (64 * 1024)
-#define ElfPages  (ElfHeaderSize / 4096)
-#define KERNELBASE (0xc0000000)
-
-void get4k(FILE *file, char *buf )
-{
-    unsigned j;
-    unsigned num = fread(buf, 1, 4096, file);
-    for (  j=num; j<4096; ++j )
-       buf[j] = 0;
-}
-
-void put4k(FILE *file, char *buf )
-{
-    fwrite(buf, 1, 4096, file);
-}
-
-void death(const char *msg, FILE *fdesc, const char *fname)
-{
-    printf(msg);
-    fclose(fdesc);
-    unlink(fname);
-    exit(1);
-}
-
-int main(int argc, char **argv)
-{
-    char inbuf[4096];
-    FILE *ramDisk = NULL;
-    FILE *inputVmlinux = NULL;
-    FILE *outputVmlinux = NULL;
-    unsigned i = 0;
-    u_int32_t ramFileLen = 0;
-    u_int32_t ramLen = 0;
-    u_int32_t roundR = 0;
-    u_int32_t kernelLen = 0;
-    u_int32_t actualKernelLen = 0;
-    u_int32_t round = 0;
-    u_int32_t roundedKernelLen = 0;
-    u_int32_t ramStartOffs = 0;
-    u_int32_t ramPages = 0;
-    u_int32_t roundedKernelPages = 0;
-    u_int32_t hvReleaseData = 0;
-    u_int32_t eyeCatcher = 0xc8a5d9c4;
-    u_int32_t naca = 0;
-    u_int32_t xRamDisk = 0;
-    u_int32_t xRamDiskSize = 0;
-    if ( argc < 2 ) {
-       printf("Name of RAM disk file missing.\n");
-       exit(1);
-    }
-
-    if ( argc < 3 ) {
-       printf("Name of vmlinux file missing.\n");
-       exit(1);
-    }
-
-    if ( argc < 4 ) {
-       printf("Name of vmlinux output file missing.\n");
-       exit(1);
-    }
-
-    ramDisk = fopen(argv[1], "r");
-    if ( ! ramDisk ) {
-       printf("RAM disk file \"%s\" failed to open.\n", argv[1]);
-       exit(1);
-    }
-    inputVmlinux = fopen(argv[2], "r");
-    if ( ! inputVmlinux ) {
-       printf("vmlinux file \"%s\" failed to open.\n", argv[2]);
-       exit(1);
-    }
-    outputVmlinux = fopen(argv[3], "w+");
-    if ( ! outputVmlinux ) {
-       printf("output vmlinux file \"%s\" failed to open.\n", argv[3]);
-       exit(1);
-    }
-    fseek(ramDisk, 0, SEEK_END);
-    ramFileLen = ftell(ramDisk);
-    fseek(ramDisk, 0, SEEK_SET);
-    printf("%s file size = %d\n", argv[1], ramFileLen);
-
-    ramLen = ramFileLen;
-
-    roundR = 4096 - (ramLen % 4096);
-    if ( roundR ) {
-       printf("Rounding RAM disk file up to a multiple of 4096, adding %d\n", roundR);
-       ramLen += roundR;
-    }
-
-    printf("Rounded RAM disk size is %d\n", ramLen);
-    fseek(inputVmlinux, 0, SEEK_END);
-    kernelLen = ftell(inputVmlinux);
-    fseek(inputVmlinux, 0, SEEK_SET);
-    printf("kernel file size = %d\n", kernelLen);
-    if ( kernelLen == 0 ) {
-       printf("You must have a linux kernel specified as argv[2]\n");
-       exit(1);
-    }
-
-    actualKernelLen = kernelLen - ElfHeaderSize;
-
-    printf("actual kernel length (minus ELF header) = %d\n", actualKernelLen);
-
-    round = actualKernelLen % 4096;
-    roundedKernelLen = actualKernelLen;
-    if ( round )
-       roundedKernelLen += (4096 - round);
-
-    printf("actual kernel length rounded up to a 4k multiple = %d\n", roundedKernelLen);
-
-    ramStartOffs = roundedKernelLen;
-    ramPages = ramLen / 4096;
-
-    printf("RAM disk pages to copy = %d\n", ramPages);
-
-    // Copy 64K ELF header
-      for (i=0; i<(ElfPages); ++i) {
-         get4k( inputVmlinux, inbuf );
-         put4k( outputVmlinux, inbuf );
-      }
-
-    roundedKernelPages = roundedKernelLen / 4096;
-
-    fseek(inputVmlinux, ElfHeaderSize, SEEK_SET);
-
-    for ( i=0; i<roundedKernelPages; ++i ) {
-       get4k( inputVmlinux, inbuf );
-       put4k( outputVmlinux, inbuf );
-    }
-
-    for ( i=0; i<ramPages; ++i ) {
-       get4k( ramDisk, inbuf );
-       put4k( outputVmlinux, inbuf );
-    }
-
-    /* Close the input files */
-    fclose(ramDisk);
-    fclose(inputVmlinux);
-    /* And flush the written output file */
-    fflush(outputVmlinux);
-
-    /* fseek to the hvReleaseData pointer */
-    fseek(outputVmlinux, ElfHeaderSize + 0x24, SEEK_SET);
-    if (fread(&hvReleaseData, 4, 1, outputVmlinux) != 1) {
-        death("Could not read hvReleaseData pointer\n", outputVmlinux, argv[3]);
-    }
-    hvReleaseData = ntohl(hvReleaseData); /* Convert to native int */
-    printf("hvReleaseData is at %08x\n", hvReleaseData);
-
-    /* fseek to the hvReleaseData */
-    fseek(outputVmlinux, ElfHeaderSize + hvReleaseData, SEEK_SET);
-    if (fread(inbuf, 0x40, 1, outputVmlinux) != 1) {
-        death("Could not read hvReleaseData\n", outputVmlinux, argv[3]);
-    }
-    /* Check hvReleaseData sanity */
-    if (memcmp(inbuf, &eyeCatcher, 4) != 0) {
-        death("hvReleaseData is invalid\n", outputVmlinux, argv[3]);
-    }
-    /* Get the naca pointer */
-    naca = ntohl(*((u_int32_t *) &inbuf[0x0c])) - KERNELBASE;
-    printf("naca is at %08x\n", naca);
-
-    /* fseek to the naca */
-    fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET);
-    if (fread(inbuf, 0x18, 1, outputVmlinux) != 1) {
-        death("Could not read naca\n", outputVmlinux, argv[3]);
-    }
-    xRamDisk = ntohl(*((u_int32_t *) &inbuf[0x0c]));
-    xRamDiskSize = ntohl(*((u_int32_t *) &inbuf[0x14]));
-    /* Make sure a RAM disk isn't already present */
-    if ((xRamDisk != 0) || (xRamDiskSize != 0)) {
-        death("RAM disk is already attached to this kernel\n", outputVmlinux, argv[3]);
-    }
-    /* Fill in the values */
-    *((u_int32_t *) &inbuf[0x0c]) = htonl(ramStartOffs);
-    *((u_int32_t *) &inbuf[0x14]) = htonl(ramPages);
-
-    /* Write out the new naca */
-    fflush(outputVmlinux);
-    fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET);
-    if (fwrite(inbuf, 0x18, 1, outputVmlinux) != 1) {
-        death("Could not write naca\n", outputVmlinux, argv[3]);
-    }
-    printf("RAM Disk of 0x%x pages size is attached to the kernel at offset 0x%08x\n",
-            ramPages, ramStartOffs);
-
-    /* Done */
-    fclose(outputVmlinux);
-    /* Set permission to executable */
-    chmod(argv[3], S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
-
-    return 0;
-}
-
diff --git a/arch/ppc/configs/SM850_defconfig b/arch/ppc/configs/SM850_defconfig
deleted file mode 100644 (file)
index 021884b..0000000
+++ /dev/null
@@ -1,522 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_PPC32=y
-# CONFIG_6xx is not set
-# CONFIG_40x is not set
-# CONFIG_POWER3 is not set
-CONFIG_8xx=y
-
-#
-# IBM 4xx options
-#
-CONFIG_EMBEDDEDBOOT=y
-CONFIG_SERIAL_CONSOLE=y
-CONFIG_NOT_COHERENT_CACHE=y
-# CONFIG_RPXLITE is not set
-# CONFIG_RPXCLASSIC is not set
-# CONFIG_BSEIP is not set
-# CONFIG_FADS is not set
-# CONFIG_TQM823L is not set
-# CONFIG_TQM850L is not set
-# CONFIG_TQM855L is not set
-# CONFIG_TQM860L is not set
-# CONFIG_FPS850L is not set
-# CONFIG_SPD823TS is not set
-# CONFIG_IVMS8 is not set
-# CONFIG_IVML24 is not set
-CONFIG_SM850=y
-# CONFIG_HERMES_PRO is not set
-# CONFIG_IP860 is not set
-# CONFIG_LWMON is not set
-# CONFIG_PCU_E is not set
-# CONFIG_CCM is not set
-# CONFIG_LANTEC is not set
-# CONFIG_MBX is not set
-# CONFIG_WINCEPT is not set
-CONFIG_TQM8xxL=y
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-CONFIG_MATH_EMULATION=y
-# CONFIG_CPU_FREQ is not set
-
-#
-# General setup
-#
-# CONFIG_HIGHMEM is not set
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
-# CONFIG_PCI_QSPAN is not set
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyCPM1"
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00400000
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_IPV6 is not set
-# CONFIG_XFRM_USER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
-# CONFIG_OAKNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices (depends on LLC=y)
-#
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Macintosh device drivers
-#
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_CPM=y
-CONFIG_SERIAL_CPM_CONSOLE=y
-# CONFIG_SERIAL_CPM_SCC1 is not set
-# CONFIG_SERIAL_CPM_SCC2 is not set
-# CONFIG_SERIAL_CPM_SCC3 is not set
-# CONFIG_SERIAL_CPM_SCC4 is not set
-CONFIG_SERIAL_CPM_SMC1=y
-CONFIG_SERIAL_CPM_SMC2=y
-CONFIG_SERIAL_CPM_ALT_SMC2=y
-CONFIG_UNIX98_PTYS=y
-# CONFIG_LEGACY_PTYS is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-# CONFIG_EXT2_FS is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-# CONFIG_MSDOS_PARTITION is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# MPC8xx CPM Options
-#
-CONFIG_SCC_ENET=y
-# CONFIG_SCC1_ENET is not set
-# CONFIG_SCC2_ENET is not set
-CONFIG_SCC3_ENET=y
-# CONFIG_FEC_ENET is not set
-CONFIG_ENET_BIG_BUFFERS=y
-
-#
-# Generic MPC8xx Options
-#
-CONFIG_8xx_COPYBACK=y
-CONFIG_8xx_CPU6=y
-# CONFIG_UCODE_PATCH is not set
-
-#
-# USB support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/SPD823TS_defconfig b/arch/ppc/configs/SPD823TS_defconfig
deleted file mode 100644 (file)
index ba60fea..0000000
+++ /dev/null
@@ -1,520 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_PPC32=y
-# CONFIG_6xx is not set
-# CONFIG_40x is not set
-# CONFIG_POWER3 is not set
-CONFIG_8xx=y
-
-#
-# IBM 4xx options
-#
-CONFIG_EMBEDDEDBOOT=y
-CONFIG_SERIAL_CONSOLE=y
-CONFIG_NOT_COHERENT_CACHE=y
-# CONFIG_RPXLITE is not set
-# CONFIG_RPXCLASSIC is not set
-# CONFIG_BSEIP is not set
-# CONFIG_FADS is not set
-# CONFIG_TQM823L is not set
-# CONFIG_TQM850L is not set
-# CONFIG_TQM855L is not set
-# CONFIG_TQM860L is not set
-# CONFIG_FPS850L is not set
-CONFIG_SPD823TS=y
-# CONFIG_IVMS8 is not set
-# CONFIG_IVML24 is not set
-# CONFIG_SM850 is not set
-# CONFIG_HERMES_PRO is not set
-# CONFIG_IP860 is not set
-# CONFIG_LWMON is not set
-# CONFIG_PCU_E is not set
-# CONFIG_CCM is not set
-# CONFIG_LANTEC is not set
-# CONFIG_MBX is not set
-# CONFIG_WINCEPT is not set
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-CONFIG_MATH_EMULATION=y
-# CONFIG_CPU_FREQ is not set
-
-#
-# General setup
-#
-# CONFIG_HIGHMEM is not set
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
-# CONFIG_PCI_QSPAN is not set
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-# CONFIG_CMDLINE_BOOL is not set
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00400000
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_IPV6 is not set
-# CONFIG_XFRM_USER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
-# CONFIG_OAKNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices (depends on LLC=y)
-#
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Macintosh device drivers
-#
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_CPM=y
-CONFIG_SERIAL_CPM_CONSOLE=y
-# CONFIG_SERIAL_CPM_SCC1 is not set
-# CONFIG_SERIAL_CPM_SCC2 is not set
-# CONFIG_SERIAL_CPM_SCC3 is not set
-# CONFIG_SERIAL_CPM_SCC4 is not set
-CONFIG_SERIAL_CPM_SMC1=y
-# CONFIG_SERIAL_CPM_SMC2 is not set
-CONFIG_SERIAL_CPM_ALT_SMC2=y
-CONFIG_UNIX98_PTYS=y
-# CONFIG_LEGACY_PTYS is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-# CONFIG_EXT2_FS is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-# CONFIG_MSDOS_PARTITION is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# MPC8xx CPM Options
-#
-CONFIG_SCC_ENET=y
-# CONFIG_SCC1_ENET is not set
-CONFIG_SCC2_ENET=y
-# CONFIG_SCC3_ENET is not set
-# CONFIG_FEC_ENET is not set
-CONFIG_ENET_BIG_BUFFERS=y
-
-#
-# Generic MPC8xx Options
-#
-CONFIG_8xx_COPYBACK=y
-# CONFIG_8xx_CPU6 is not set
-# CONFIG_UCODE_PATCH is not set
-
-#
-# USB support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/adir_defconfig b/arch/ppc/configs/adir_defconfig
deleted file mode 100644 (file)
index f20e653..0000000
+++ /dev/null
@@ -1,805 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_EMBEDDED is not set
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_6xx=y
-# CONFIG_40x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_8xx is not set
-
-#
-# IBM 4xx options
-#
-# CONFIG_8260 is not set
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_PPC_STD_MMU=y
-# CONFIG_PPC_MULTIPLATFORM is not set
-# CONFIG_APUS is not set
-# CONFIG_WILLOW_2 is not set
-# CONFIG_PCORE is not set
-# CONFIG_POWERPMC250 is not set
-# CONFIG_EV64260 is not set
-# CONFIG_SPRUCE is not set
-# CONFIG_LOPEC is not set
-# CONFIG_MCPN765 is not set
-# CONFIG_MVME5100 is not set
-# CONFIG_PPLUS is not set
-# CONFIG_PRPMC750 is not set
-# CONFIG_PRPMC800 is not set
-# CONFIG_SANDPOINT is not set
-CONFIG_ADIR=y
-# CONFIG_K2 is not set
-# CONFIG_PAL4 is not set
-# CONFIG_GEMINI is not set
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ALTIVEC is not set
-# CONFIG_TAU is not set
-# CONFIG_CPU_FREQ is not set
-
-#
-# General setup
-#
-# CONFIG_HIGHMEM is not set
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_PCI_LEGACY_PROC=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-CONFIG_PARPORT=y
-CONFIG_PARPORT_PC=y
-CONFIG_PARPORT_PC_CML1=y
-# CONFIG_PARPORT_SERIAL is not set
-CONFIG_PARPORT_PC_FIFO=y
-CONFIG_PARPORT_PC_SUPERIO=y
-# CONFIG_PARPORT_OTHER is not set
-CONFIG_PARPORT_1284=y
-# CONFIG_PPC601_SYNC_FIX is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="ip=on"
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00800000
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-CONFIG_BLK_DEV_FD=y
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-# CONFIG_CHR_DEV_OSST is not set
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_REPORT_LUNS is not set
-CONFIG_SCSI_CONSTANTS=y
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_PPA is not set
-# CONFIG_SCSI_IMM is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-CONFIG_SCSI_NCR53C8XX=y
-CONFIG_SCSI_SYM53C8XX=y
-CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=20
-# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
-# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_IP_NF_CONNTRACK=m
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_IRC=m
-CONFIG_IP_NF_TFTP=m
-CONFIG_IP_NF_AMANDA=m
-# CONFIG_IP_NF_QUEUE is not set
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
-CONFIG_IP_NF_MATCH_TOS=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
-CONFIG_IP_NF_MATCH_UNCLEAN=m
-CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_MIRROR=m
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_IP_NF_NAT_SNMP_BASIC=m
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-CONFIG_IP_NF_NAT_TFTP=m
-CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_MANGLE is not set
-# CONFIG_IP_NF_TARGET_LOG is not set
-# CONFIG_IP_NF_TARGET_ULOG is not set
-CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_XFRM_USER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_OAKNET is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 is not set
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_B44 is not set
-# CONFIG_DGRS is not set
-CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PIO is not set
-# CONFIG_E100 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices (depends on LLC=y)
-#
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Macintosh device drivers
-#
-
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_PRINTER is not set
-# CONFIG_PPDEV is not set
-# CONFIG_TIPAR is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-
-#
-# Miscellaneous USB options
-#
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_BANDWIDTH is not set
-CONFIG_USB_DYNAMIC_MINORS=y
-
-#
-# USB Host Controller Drivers
-#
-# CONFIG_USB_EHCI_HCD is not set
-CONFIG_USB_OHCI_HCD=y
-# CONFIG_USB_UHCI_HCD is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_BLUETOOTH_TTY is not set
-CONFIG_USB_ACM=m
-# CONFIG_USB_PRINTER is not set
-CONFIG_USB_STORAGE=m
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-CONFIG_USB_STORAGE_FREECOM=y
-# CONFIG_USB_STORAGE_ISD200 is not set
-CONFIG_USB_STORAGE_DPCM=y
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_SDDR55 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-CONFIG_USB_HID=m
-
-#
-# Input core support is needed for USB HID input layer or HIDBP support
-#
-CONFIG_USB_HIDDEV=y
-
-#
-# USB HID Boot Protocol drivers
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-# CONFIG_USB_DABUSB is not set
-
-#
-# Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-CONFIG_USB_SERIAL=m
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-CONFIG_USB_SERIAL_VISOR=m
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-CONFIG_USB_SERIAL_KEYSPAN=m
-# CONFIG_USB_SERIAL_KEYSPAN_MPR is not set
-CONFIG_USB_SERIAL_KEYSPAN_USA28=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-CONFIG_USB_SERIAL_KEYSPAN_USA19=y
-CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
-CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
-# CONFIG_USB_SERIAL_KEYSPAN_USA49WLC is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_KOBIL_SCT is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_SAFE is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-CONFIG_USB_EZUSB=y
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_TIGL is not set
-# CONFIG_USB_AUERSWALD is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_LCD is not set
-# CONFIG_USB_TEST is not set
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/ash_defconfig b/arch/ppc/configs/ash_defconfig
deleted file mode 100644 (file)
index c4a73cc..0000000
+++ /dev/null
@@ -1,666 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_GENERIC_NVRAM=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
-# CONFIG_IKCONFIG is not set
-CONFIG_EMBEDDED=y
-# CONFIG_KALLSYMS is not set
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Processor
-#
-# CONFIG_6xx is not set
-CONFIG_40x=y
-# CONFIG_44x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_POWER4 is not set
-# CONFIG_8xx is not set
-# CONFIG_MATH_EMULATION is not set
-# CONFIG_CPU_FREQ is not set
-CONFIG_4xx=y
-
-#
-# IBM 4xx options
-#
-CONFIG_ASH=y
-# CONFIG_CPCI405 is not set
-# CONFIG_EP405 is not set
-# CONFIG_EVB405EP is not set
-# CONFIG_OAK is not set
-# CONFIG_REDWOOD_5 is not set
-# CONFIG_REDWOOD_6 is not set
-# CONFIG_SYCAMORE is not set
-# CONFIG_WALNUT is not set
-CONFIG_NP405H=y
-CONFIG_IBM405_ERR77=y
-CONFIG_IBM405_ERR51=y
-CONFIG_IBM_OCP=y
-CONFIG_PPC_OCP=y
-CONFIG_IBM_OPENBIOS=y
-# CONFIG_PM is not set
-CONFIG_UART0_TTYS0=y
-# CONFIG_UART0_TTYS1 is not set
-CONFIG_NOT_COHERENT_CACHE=y
-
-#
-# Platform options
-#
-# CONFIG_PC_KEYBOARD is not set
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_HIGHMEM is not set
-CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="ip=on"
-
-#
-# Bus options
-#
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_PCI_LEGACY_PROC=y
-# CONFIG_PCI_NAMES is not set
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00400000
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_CARMEL is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_LBD is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Macintosh device drivers
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-# CONFIG_NET_ETHERNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SIS190 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-CONFIG_IBM_EMAC=y
-# CONFIG_IBM_EMAC_ERRMSG is not set
-CONFIG_IBM_EMAC_RXB=64
-CONFIG_IBM_EMAC_TXB=8
-CONFIG_IBM_EMAC_FGAP=8
-CONFIG_IBM_EMAC_SKBRES=0
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PCIPS2 is not set
-
-#
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_VSXXXAA is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-
-#
-# Watchdog Device Drivers
-#
-# CONFIG_SOFT_WATCHDOG is not set
-
-#
-# PCI-based Watchdog Cards
-#
-# CONFIG_PCIPCWATCHDOG is not set
-# CONFIG_WDTPCI is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-# CONFIG_I2C_CHARDEV is not set
-
-#
-# I2C Algorithms
-#
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-
-#
-# I2C Hardware Bus support
-#
-# CONFIG_I2C_ALI1535 is not set
-# CONFIG_I2C_ALI15X3 is not set
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
-# CONFIG_I2C_I801 is not set
-# CONFIG_I2C_I810 is not set
-# CONFIG_I2C_IBM_IIC is not set
-# CONFIG_I2C_ISA is not set
-# CONFIG_I2C_NFORCE2 is not set
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_PROSAVAGE is not set
-# CONFIG_I2C_SAVAGE4 is not set
-# CONFIG_SCx200_ACB is not set
-# CONFIG_I2C_SIS5595 is not set
-# CONFIG_I2C_SIS630 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_VIA is not set
-# CONFIG_I2C_VIAPRO is not set
-# CONFIG_I2C_VOODOO3 is not set
-
-#
-# Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_ASB100 is not set
-# CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_FSCHER is not set
-# CONFIG_SENSORS_GL518SM is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM78 is not set
-# CONFIG_SENSORS_LM80 is not set
-# CONFIG_SENSORS_LM83 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_LM90 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_SENSORS_W83L785TS is not set
-# CONFIG_SENSORS_W83627HF is not set
-
-#
-# Other I2C Chip support
-#
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_I2C_DEBUG_CORE is not set
-# CONFIG_I2C_DEBUG_ALGO is not set
-# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_I2C_DEBUG_CHIP is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR 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_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-# CONFIG_MSDOS_PARTITION is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# IBM 40x options
-#
-
-#
-# Library routines
-#
-CONFIG_CRC32=y
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
-CONFIG_OCP=y
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/beech_defconfig b/arch/ppc/configs/beech_defconfig
deleted file mode 100644 (file)
index 0bd671b..0000000
+++ /dev/null
@@ -1,615 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-CONFIG_PPC=y
-CONFIG_PPC32=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-# CONFIG_STANDALONE is not set
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_IKCONFIG is not set
-CONFIG_EMBEDDED=y
-# CONFIG_KALLSYMS is not set
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-CONFIG_MODVERSIONS=y
-CONFIG_KMOD=y
-
-#
-# Processor
-#
-# CONFIG_6xx is not set
-CONFIG_40x=y
-# CONFIG_44x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_POWER4 is not set
-# CONFIG_8xx is not set
-# CONFIG_MATH_EMULATION is not set
-# CONFIG_CPU_FREQ is not set
-CONFIG_4xx=y
-
-#
-# IBM 4xx options
-#
-# CONFIG_ASH is not set
-CONFIG_BEECH=y
-# CONFIG_CEDAR is not set
-# CONFIG_CPCI405 is not set
-# CONFIG_EP405 is not set
-# CONFIG_OAK is not set
-# CONFIG_REDWOOD_4 is not set
-# CONFIG_REDWOOD_5 is not set
-# CONFIG_REDWOOD_6 is not set
-# CONFIG_SYCAMORE is not set
-# CONFIG_TIVO is not set
-# CONFIG_WALNUT is not set
-CONFIG_IBM405_ERR77=y
-CONFIG_IBM405_ERR51=y
-CONFIG_IBM_OCP=y
-CONFIG_IBM_OPENBIOS=y
-CONFIG_405_DMA=y
-# CONFIG_PM is not set
-CONFIG_UART0_TTYS0=y
-# CONFIG_UART0_TTYS1 is not set
-CONFIG_NOT_COHERENT_CACHE=y
-
-#
-# Platform options
-#
-# CONFIG_PC_KEYBOARD is not set
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_HIGHMEM is not set
-CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_CMDLINE_BOOL is not set
-
-#
-# Bus options
-#
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00400000
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-CONFIG_MTD=y
-# CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_CONCAT is not set
-# CONFIG_MTD_REDBOOT_PARTS is not set
-# CONFIG_MTD_CMDLINE_PARTS is not set
-
-#
-# User Modules And Translation Layers
-#
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-# CONFIG_FTL is not set
-# CONFIG_NFTL is not set
-# CONFIG_INFTL is not set
-
-#
-# RAM/ROM/Flash chip drivers
-#
-CONFIG_MTD_CFI=y
-CONFIG_MTD_JEDECPROBE=y
-CONFIG_MTD_GEN_PROBE=y
-# CONFIG_MTD_CFI_ADV_OPTIONS is not set
-# CONFIG_MTD_CFI_INTELEXT is not set
-CONFIG_MTD_CFI_AMDSTD=y
-# CONFIG_MTD_CFI_STAA is not set
-# CONFIG_MTD_RAM is not set
-# 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_PHYSMAP is not set
-CONFIG_MTD_BEECH=y
-
-#
-# Self-contained MTD device drivers
-#
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD is not set
-
-#
-# Disk-On-Chip Device Drivers
-#
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOC2001PLUS is not set
-
-#
-# NAND Flash Device Drivers
-#
-# CONFIG_MTD_NAND is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_LBD is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
-# CONFIG_OAKNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-CONFIG_FB=y
-# CONFIG_FB_CT65550 is not set
-# CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_VGA16 is not set
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Logo configuration
-#
-# CONFIG_LOGO is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-
-#
-# Input Device Drivers
-#
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Macintosh device drivers
-#
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-# CONFIG_I2C_CHARDEV is not set
-
-#
-# I2C Algorithms
-#
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-
-#
-# I2C Hardware Bus support
-#
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
-CONFIG_I2C_IBM_IIC=y
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM78 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_W83781D is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR 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_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_DEVFS_FS=y
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Sound
-#
-CONFIG_SOUND=y
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
-
-#
-# Open Sound System
-#
-# CONFIG_SOUND_PRIME is not set
-
-#
-# IBM 40x options
-#
-
-#
-# USB support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
-CONFIG_OCP=y
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/cedar_defconfig b/arch/ppc/configs/cedar_defconfig
deleted file mode 100644 (file)
index 5de8288..0000000
+++ /dev/null
@@ -1,534 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_PPC32=y
-# CONFIG_6xx is not set
-CONFIG_40x=y
-# CONFIG_POWER3 is not set
-# CONFIG_8xx is not set
-CONFIG_4xx=y
-
-#
-# IBM 4xx options
-#
-# CONFIG_ASH is not set
-# CONFIG_BEECH is not set
-CONFIG_CEDAR=y
-# CONFIG_CPCI405 is not set
-# CONFIG_EP405 is not set
-# CONFIG_OAK is not set
-# CONFIG_REDWOOD_4 is not set
-# CONFIG_REDWOOD_5 is not set
-# CONFIG_REDWOOD_6 is not set
-# CONFIG_SYCAMORE is not set
-# CONFIG_TIVO is not set
-# CONFIG_WALNUT is not set
-CONFIG_IBM405_ERR77=y
-CONFIG_IBM405_ERR51=y
-CONFIG_IBM_OCP=y
-CONFIG_NP405L=y
-CONFIG_BIOS_FIXUP=y
-CONFIG_IBM_OPENBIOS=y
-# CONFIG_405_DMA is not set
-# CONFIG_PM is not set
-CONFIG_UART0_TTYS0=y
-# CONFIG_UART0_TTYS1 is not set
-CONFIG_NOT_COHERENT_CACHE=y
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_MATH_EMULATION is not set
-# CONFIG_CPU_FREQ is not set
-
-#
-# General setup
-#
-# CONFIG_HIGHMEM is not set
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
-# CONFIG_PC_KEYBOARD is not set
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-# CONFIG_CMDLINE_BOOL is not set
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00400000
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_IPV6 is not set
-# CONFIG_XFRM_USER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-# CONFIG_NET_ETHERNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices (depends on LLC=y)
-#
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Macintosh device drivers
-#
-
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-CONFIG_I2C_IBM_OCP_ALGO=y
-CONFIG_I2C_IBM_OCP_ADAP=y
-# CONFIG_I2C_CHARDEV is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-# CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_WDT is not set
-# CONFIG_WDTPCI is not set
-# CONFIG_PCWATCHDOG is not set
-# CONFIG_ACQUIRE_WDT is not set
-# CONFIG_ADVANTECH_WDT is not set
-# CONFIG_EUROTECH_WDT is not set
-# CONFIG_IB700_WDT is not set
-# CONFIG_MIXCOMWD is not set
-# CONFIG_SCx200_WDT is not set
-# CONFIG_60XX_WDT is not set
-# CONFIG_W83877F_WDT is not set
-# CONFIG_MACHZ_WDT is not set
-# CONFIG_SC520_WDT is not set
-# CONFIG_AMD7XX_TCO is not set
-# CONFIG_ALIM7101_WDT is not set
-# CONFIG_SC1200_WDT is not set
-# CONFIG_WAFER_WDT is not set
-# CONFIG_CPU5_WDT is not set
-# CONFIG_NVRAM is not set
-# CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR 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_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-# CONFIG_MSDOS_PARTITION is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# IBM 40x options
-#
-
-#
-# USB support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# Library routines
-#
-CONFIG_CRC32=y
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
-CONFIG_OCP=y
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
index 53948793d9af5e0f95a730e5c3026b7ba02491ab..ff3f7e02ab0fb6fb35aec0084944c385a236e87b 100644 (file)
@@ -1,15 +1,17 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-rc2
-# Fri Dec  3 15:56:10 2004
+# Linux kernel version: 2.6.13-mm1
+# Thu Sep  1 17:10:37 2005
 #
 CONFIG_MMU=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_PPC=y
 CONFIG_PPC32=y
 CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
 
 #
 # Code maturity level options
@@ -17,33 +19,38 @@ CONFIG_GENERIC_NVRAM=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
 #
 CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -65,38 +72,42 @@ CONFIG_6xx=y
 # CONFIG_POWER3 is not set
 # CONFIG_POWER4 is not set
 # CONFIG_8xx is not set
+# CONFIG_E200 is not set
 # CONFIG_E500 is not set
+CONFIG_PPC_FPU=y
 CONFIG_ALTIVEC=y
 # CONFIG_TAU is not set
+# CONFIG_KEXEC is not set
 # CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
 CONFIG_PPC_STD_MMU=y
 # CONFIG_NOT_COHERENT_CACHE is not set
 
+#
+# Performance-monitoring counters support
+#
+# CONFIG_PERFCTR is not set
+
 #
 # Platform options
 #
 # CONFIG_PPC_MULTIPLATFORM is not set
 # CONFIG_APUS is not set
 # CONFIG_KATANA is not set
-# CONFIG_DMV182 is not set
 # CONFIG_WILLOW is not set
 CONFIG_CPCI690=y
-# CONFIG_PCORE is not set
 # CONFIG_POWERPMC250 is not set
-# CONFIG_EV64260 is not set
-# CONFIG_DB64360 is not set
 # CONFIG_CHESTNUT is not set
 # CONFIG_SPRUCE is not set
+# CONFIG_HDPU is not set
+# CONFIG_EV64260 is not set
 # CONFIG_LOPEC is not set
-# CONFIG_MCPN765 is not set
 # CONFIG_MVME5100 is not set
 # CONFIG_PPLUS is not set
 # CONFIG_PRPMC750 is not set
 # CONFIG_PRPMC800 is not set
-# CONFIG_PRPMC880 is not set
 # CONFIG_SANDPOINT is not set
-# CONFIG_ADIR is not set
-# CONFIG_K2 is not set
+# CONFIG_RADSTONE_PPC7D is not set
 # CONFIG_PAL4 is not set
 # CONFIG_GEMINI is not set
 # CONFIG_EST8260 is not set
@@ -105,22 +116,41 @@ CONFIG_CPCI690=y
 # CONFIG_RPX8260 is not set
 # CONFIG_TQM8260 is not set
 # CONFIG_ADS8272 is not set
+# CONFIG_PQ2FADS is not set
 # CONFIG_LITE5200 is not set
+# CONFIG_MPC834x_SYS is not set
+# CONFIG_EV64360 is not set
+CONFIG_GT64260=y
+CONFIG_MV64X60=y
 
 #
 # Set bridge options
 #
 CONFIG_MV64X60_BASE=0xf1000000
 CONFIG_MV64X60_NEW_BASE=0xf1000000
-CONFIG_GT64260=y
-CONFIG_MV64X60=y
 # CONFIG_SMP is not set
+CONFIG_HIGHMEM=y
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
 # CONFIG_PREEMPT is not set
-# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=y
 CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyMM0,9600 ip=on"
+CONFIG_CMDLINE="console=ttyMM0 ip=on"
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
 
 #
 # Bus options
@@ -129,7 +159,11 @@ CONFIG_GENERIC_ISA_DMA=y
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
 CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
 
 #
 # Advanced setup
@@ -145,6 +179,76 @@ CONFIG_KERNEL_START=0xc0000000
 CONFIG_TASK_SIZE=0x80000000
 CONFIG_BOOT_LOAD=0x00800000
 
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
 #
 # Device Drivers
 #
@@ -154,6 +258,7 @@ CONFIG_BOOT_LOAD=0x00800000
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -177,6 +282,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
@@ -185,7 +291,6 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
 # CONFIG_CDROM_PKTCDVD is not set
 
@@ -196,6 +301,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -205,6 +311,7 @@ CONFIG_IOSCHED_CFQ=y
 #
 # SCSI device support
 #
+# CONFIG_RAID_ATTRS is not set
 # CONFIG_SCSI is not set
 
 #
@@ -215,6 +322,7 @@ CONFIG_IOSCHED_CFQ=y
 #
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -231,71 +339,8 @@ CONFIG_IOSCHED_CFQ=y
 #
 
 #
-# Networking support
+# Network device support
 #
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
@@ -307,6 +352,11 @@ CONFIG_NETDEVICES=y
 #
 # CONFIG_ARCNET is not set
 
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
 #
 # Ethernet (10 or 100Mbit)
 #
@@ -328,6 +378,7 @@ CONFIG_TULIP=y
 # CONFIG_DE4X5 is not set
 # CONFIG_WINBOND_840 is not set
 # CONFIG_DM9102 is not set
+# CONFIG_ULI526X is not set
 # CONFIG_HP100 is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
@@ -337,7 +388,6 @@ CONFIG_NET_PCI=y
 # CONFIG_FORCEDETH is not set
 # CONFIG_DGRS is not set
 CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PIO is not set
 # CONFIG_E100 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -360,13 +410,18 @@ CONFIG_EEPRO100=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
 
 #
 # Ethernet (10000 Mbit)
 #
+# CONFIG_CHELSIO_T1 is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 
@@ -390,6 +445,11 @@ CONFIG_EEPRO100=y
 # CONFIG_SLIP is not set
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
+# CONFIG_KGDBOE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
@@ -418,14 +478,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
 
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
 #
 # Input Device Drivers
 #
@@ -435,6 +487,12 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
 #
 # Character devices
 #
@@ -455,6 +513,7 @@ CONFIG_SERIAL_MPSC=y
 CONFIG_SERIAL_MPSC_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -482,6 +541,11 @@ CONFIG_GEN_RTC=y
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
 #
 # I2C support
 #
@@ -492,10 +556,21 @@ CONFIG_GEN_RTC=y
 #
 # CONFIG_W1 is not set
 
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
 #
 # Misc devices
 #
 
+#
+# Multimedia Capabilities Port drivers
+#
+
 #
 # Multimedia devices
 #
@@ -517,6 +592,11 @@ CONFIG_GEN_RTC=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 
+#
+# Speakup console speech
+#
+# CONFIG_SPEAKUP is not set
+
 #
 # Sound
 #
@@ -525,35 +605,59 @@ CONFIG_DUMMY_CONSOLE=y
 #
 # USB support
 #
-# CONFIG_USB is not set
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# USB Gadget Support
 #
+# CONFIG_USB_GADGET is not set
 
 #
-# USB Gadget Support
+# MMC/SD Card support
 #
-# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
 
 #
 # File systems
 #
 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_REISER4_FS 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 is not set
+CONFIG_INOTIFY=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
 
 #
 # CD-ROM/DVD Filesystems
@@ -574,20 +678,18 @@ CONFIG_DNOTIFY=y
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
-CONFIG_DEVFS_FS=y
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_RELAYFS_FS is not set
 
 #
 # Miscellaneous filesystems
 #
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
@@ -605,13 +707,14 @@ CONFIG_RAMFS=y
 #
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
 CONFIG_NFS_V4=y
 # CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 CONFIG_SUNRPC_GSS=y
 CONFIG_RPCSEC_GSS_KRB5=y
@@ -621,6 +724,7 @@ CONFIG_RPCSEC_GSS_KRB5=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
@@ -637,6 +741,7 @@ CONFIG_MSDOS_PARTITION=y
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 
@@ -648,7 +753,9 @@ CONFIG_CRC32=y
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 # CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_SERIAL_TEXT_DEBUG is not set
 
 #
@@ -669,6 +776,7 @@ CONFIG_CRYPTO_MD5=y
 # CONFIG_CRYPTO_SHA256 is not set
 # CONFIG_CRYPTO_SHA512 is not set
 # CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
 CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
@@ -684,3 +792,7 @@ CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
 # CONFIG_CRYPTO_CRC32C is not set
 # CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
similarity index 53%
rename from arch/ppc/configs/k2_defconfig
rename to arch/ppc/configs/ev64360_defconfig
index f10f5a6d2dae18e58621b9fe39c4deb22c7a8001..de9bbb791db98f3abac6706fd938f7b3a17d25ae 100644 (file)
@@ -1,52 +1,60 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.13-rc5
+# Fri Aug  5 15:18:23 2005
 #
 CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_PPC=y
 CONFIG_PPC32=y
 CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_POSIX_MQUEUE is not set
+CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
-CONFIG_EMBEDDED=y
+# CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
 #
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
+# CONFIG_MODULES is not set
 
 #
 # Processor
@@ -57,21 +65,33 @@ CONFIG_6xx=y
 # CONFIG_POWER3 is not set
 # CONFIG_POWER4 is not set
 # CONFIG_8xx is not set
-# CONFIG_ALTIVEC is not set
-# CONFIG_TAU is not set
+# CONFIG_E200 is not set
+# CONFIG_E500 is not set
+CONFIG_PPC_FPU=y
+CONFIG_ALTIVEC=y
+CONFIG_TAU=y
+# CONFIG_TAU_INT is not set
+# CONFIG_TAU_AVERAGE is not set
+# CONFIG_KEXEC is not set
 # CONFIG_CPU_FREQ is not set
+# CONFIG_PM is not set
 CONFIG_PPC_STD_MMU=y
+CONFIG_NOT_COHERENT_CACHE=y
 
 #
 # Platform options
 #
 # CONFIG_PPC_MULTIPLATFORM is not set
 # CONFIG_APUS is not set
+# CONFIG_KATANA is not set
 # CONFIG_WILLOW is not set
+# CONFIG_CPCI690 is not set
 # CONFIG_PCORE is not set
 # CONFIG_POWERPMC250 is not set
-# CONFIG_EV64260 is not set
+# CONFIG_CHESTNUT is not set
 # CONFIG_SPRUCE is not set
+# CONFIG_HDPU is not set
+# CONFIG_EV64260 is not set
 # CONFIG_LOPEC is not set
 # CONFIG_MCPN765 is not set
 # CONFIG_MVME5100 is not set
@@ -79,24 +99,51 @@ CONFIG_PPC_STD_MMU=y
 # CONFIG_PRPMC750 is not set
 # CONFIG_PRPMC800 is not set
 # CONFIG_SANDPOINT is not set
+# CONFIG_RADSTONE_PPC7D is not set
 # CONFIG_ADIR is not set
-CONFIG_K2=y
+# CONFIG_K2 is not set
 # CONFIG_PAL4 is not set
 # CONFIG_GEMINI is not set
 # CONFIG_EST8260 is not set
+# CONFIG_SBC82xx is not set
 # CONFIG_SBS8260 is not set
-# CONFIG_RPX6 is not set
+# CONFIG_RPX8260 is not set
 # CONFIG_TQM8260 is not set
-CONFIG_PPC_GEN550=y
-# CONFIG_CPC710_DATA_GATHERING is not set
+# CONFIG_ADS8272 is not set
+# CONFIG_PQ2FADS is not set
+# CONFIG_LITE5200 is not set
+# CONFIG_MPC834x_SYS is not set
+CONFIG_EV64360=y
+CONFIG_MV64360=y
+CONFIG_MV64X60=y
+
+#
+# Set bridge options
+#
+CONFIG_MV64X60_BASE=0xf1000000
+CONFIG_MV64X60_NEW_BASE=0xf1000000
 # CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
 # CONFIG_HIGHMEM is not set
-CONFIG_KERNEL_ELF=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_MISC=y
 CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="ip=on"
+CONFIG_CMDLINE="console=ttyMM0,115200 root=/dev/mtdblock1 rw rootfstype=jffs2"
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
 
 #
 # Bus options
@@ -108,19 +155,91 @@ CONFIG_PCI_DOMAINS=y
 # CONFIG_PCI_NAMES is not set
 
 #
-# Advanced setup
+# PCCARD (PCMCIA/CardBus) support
 #
-# CONFIG_ADVANCED_OPTIONS is not set
+# CONFIG_PCCARD is not set
 
 #
-# Default settings for advanced configuration options are used
+# Advanced setup
 #
+CONFIG_ADVANCED_OPTIONS=y
 CONFIG_HIGHMEM_START=0xfe000000
+# CONFIG_LOWMEM_SIZE_BOOL is not set
 CONFIG_LOWMEM_SIZE=0x30000000
+# CONFIG_KERNEL_START_BOOL is not set
 CONFIG_KERNEL_START=0xc0000000
+# CONFIG_TASK_SIZE_BOOL is not set
 CONFIG_TASK_SIZE=0x80000000
+# CONFIG_CONSISTENT_START_BOOL is not set
+CONFIG_CONSISTENT_START=0xff100000
+# CONFIG_CONSISTENT_SIZE_BOOL is not set
+CONFIG_CONSISTENT_SIZE=0x00200000
+# CONFIG_BOOT_LOAD_BOOL is not set
 CONFIG_BOOT_LOAD=0x00800000
 
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+
 #
 # Device Drivers
 #
@@ -128,11 +247,90 @@ CONFIG_BOOT_LOAD=0x00800000
 #
 # Generic Driver Options
 #
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
 #
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+# CONFIG_MTD_CFI_I1 is not set
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0xff000000
+CONFIG_MTD_PHYSMAP_LEN=0x01000000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=4
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+CONFIG_MTD_PHRAM=y
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
 
 #
 # Parallel port support
@@ -151,72 +349,32 @@ CONFIG_BOOT_LOAD=0x00800000
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_CARMEL is not set
+# CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
 #
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-# CONFIG_IDE_TASKFILE_IO is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_IDE_GENERIC is not set
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
-# CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_BLK_DEV_GENERIC is not set
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_SL82C105 is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
-CONFIG_BLK_DEV_ADMA=y
-# CONFIG_BLK_DEV_AEC62XX is not set
-CONFIG_BLK_DEV_ALI15X3=y
-# CONFIG_WDC_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5520 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_SC1200 is not set
-# CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIIMAGE is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
+# CONFIG_IDE is not set
 
 #
 # SCSI device support
@@ -248,122 +406,8 @@ CONFIG_BLK_DEV_IDEDMA=y
 #
 
 #
-# Networking support
-#
-CONFIG_NET=y
-
+# Network device support
 #
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-
-#
-# IP: Virtual Server Configuration
-#
-# CONFIG_IP_VS is not set
-# CONFIG_IPV6 is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_IP_NF_CONNTRACK=m
-CONFIG_IP_NF_FTP=m
-# CONFIG_IP_NF_IRC is not set
-# CONFIG_IP_NF_TFTP is not set
-# CONFIG_IP_NF_AMANDA is not set
-# CONFIG_IP_NF_QUEUE is not set
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
-# CONFIG_IP_NF_MATCH_IPRANGE is not set
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
-CONFIG_IP_NF_MATCH_TOS=m
-# CONFIG_IP_NF_MATCH_RECENT is not set
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-# CONFIG_IP_NF_MATCH_LENGTH is not set
-# CONFIG_IP_NF_MATCH_TTL is not set
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
-CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-# CONFIG_IP_NF_TARGET_NETMAP is not set
-# CONFIG_IP_NF_TARGET_SAME is not set
-# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
-CONFIG_IP_NF_NAT_FTP=m
-# CONFIG_IP_NF_MANGLE is not set
-# CONFIG_IP_NF_TARGET_LOG is not set
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-# CONFIG_IP_NF_ARP_MANGLE is not set
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IP_NF_RAW is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
@@ -378,38 +422,7 @@ CONFIG_NETDEVICES=y
 #
 # Ethernet (10 or 100Mbit)
 #
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_OAKNET is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 is not set
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_B44 is not set
-# CONFIG_FORCEDETH is not set
-# CONFIG_DGRS is not set
-CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PIO is not set
-# CONFIG_E100 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
+# CONFIG_NET_ETHERNET is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -421,8 +434,14 @@ CONFIG_EEPRO100=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
+# CONFIG_SKGE is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_MV643XX_ETH=y
+CONFIG_MV643XX_ETH_0=y
+# CONFIG_MV643XX_ETH_1 is not set
+# CONFIG_MV643XX_ETH_2 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -448,9 +467,10 @@ CONFIG_EEPRO100=y
 # CONFIG_HIPPI is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
-# CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
@@ -465,47 +485,59 @@ CONFIG_EEPRO100=y
 #
 # Input device support
 #
-# CONFIG_INPUT is not set
+CONFIG_INPUT=y
 
 #
 # Userland interfaces
 #
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
+# Input Device Drivers
 #
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
 
 #
-# Input Device Drivers
+# Hardware I/O ports
 #
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
 
 #
 # Character devices
 #
-# CONFIG_VT is not set
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
 # Serial drivers
 #
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=2
-# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
 # Non-8250 serial port support
 #
+CONFIG_SERIAL_MPSC=y
+CONFIG_SERIAL_MPSC_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -526,15 +558,31 @@ CONFIG_GEN_RTC=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_FTAPE is not set
 # CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
 #
 # I2C support
 #
 # CONFIG_I2C is not set
+# CONFIG_I2C_SENSOR is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
 # Misc devices
@@ -555,6 +603,12 @@ CONFIG_GEN_RTC=y
 #
 # CONFIG_FB is not set
 
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
 #
 # Sound
 #
@@ -563,6 +617,8 @@ CONFIG_GEN_RTC=y
 #
 # USB support
 #
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 # CONFIG_USB is not set
 
 #
@@ -570,19 +626,41 @@ CONFIG_GEN_RTC=y
 #
 # CONFIG_USB_GADGET is not set
 
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
 #
 # File systems
 #
 CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS 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_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -595,7 +673,8 @@ CONFIG_EXT2_FS=y
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
@@ -604,9 +683,9 @@ CONFIG_EXT2_FS=y
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -620,6 +699,14 @@ CONFIG_RAMFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -631,20 +718,22 @@ CONFIG_RAMFS=y
 # Network File Systems
 #
 CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
 # CONFIG_NFS_V4 is not set
 # CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
@@ -661,20 +750,35 @@ CONFIG_MSDOS_PARTITION=y
 #
 # Library routines
 #
-# CONFIG_CRC32 is not set
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
 
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 # CONFIG_DEBUG_KERNEL is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
+CONFIG_LOG_BUF_SHIFT=14
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
 # Cryptographic options
 #
 # CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
index f0b0d572015400442ef82b4f3cd163ae99444f84..0f3bb9af9c22bcf346a8559c7f11458cd22d9060 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11
-# Tue Mar  8 17:31:00 2005
+# Linux kernel version: 2.6.13-mm1
+# Thu Sep  1 17:16:03 2005
 #
 CONFIG_MMU=y
 CONFIG_GENERIC_HARDIRQS=y
@@ -11,6 +11,7 @@ CONFIG_HAVE_DEC_LOCK=y
 CONFIG_PPC=y
 CONFIG_PPC32=y
 CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
 
 #
 # Code maturity level options
@@ -18,28 +19,31 @@ CONFIG_GENERIC_NVRAM=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
 #
 CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
@@ -68,14 +72,22 @@ CONFIG_6xx=y
 # CONFIG_POWER3 is not set
 # CONFIG_POWER4 is not set
 # CONFIG_8xx is not set
+# CONFIG_E200 is not set
 # CONFIG_E500 is not set
+CONFIG_PPC_FPU=y
 CONFIG_ALTIVEC=y
 # CONFIG_TAU is not set
+# CONFIG_KEXEC is not set
 # CONFIG_CPU_FREQ is not set
-# CONFIG_83xx is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
 CONFIG_PPC_STD_MMU=y
 CONFIG_NOT_COHERENT_CACHE=y
 
+#
+# Performance-monitoring counters support
+#
+# CONFIG_PERFCTR is not set
+
 #
 # Platform options
 #
@@ -84,21 +96,18 @@ CONFIG_NOT_COHERENT_CACHE=y
 CONFIG_KATANA=y
 # CONFIG_WILLOW is not set
 # CONFIG_CPCI690 is not set
-# CONFIG_PCORE is not set
 # CONFIG_POWERPMC250 is not set
 # CONFIG_CHESTNUT is not set
 # CONFIG_SPRUCE is not set
+# CONFIG_HDPU is not set
 # CONFIG_EV64260 is not set
 # CONFIG_LOPEC is not set
-# CONFIG_MCPN765 is not set
 # CONFIG_MVME5100 is not set
 # CONFIG_PPLUS is not set
 # CONFIG_PRPMC750 is not set
 # CONFIG_PRPMC800 is not set
 # CONFIG_SANDPOINT is not set
 # CONFIG_RADSTONE_PPC7D is not set
-# CONFIG_ADIR is not set
-# CONFIG_K2 is not set
 # CONFIG_PAL4 is not set
 # CONFIG_GEMINI is not set
 # CONFIG_EST8260 is not set
@@ -109,6 +118,8 @@ CONFIG_KATANA=y
 # CONFIG_ADS8272 is not set
 # CONFIG_PQ2FADS is not set
 # CONFIG_LITE5200 is not set
+# CONFIG_MPC834x_SYS is not set
+# CONFIG_EV64360 is not set
 CONFIG_MV64360=y
 CONFIG_MV64X60=y
 
@@ -118,12 +129,28 @@ CONFIG_MV64X60=y
 CONFIG_MV64X60_BASE=0xf8100000
 CONFIG_MV64X60_NEW_BASE=0xf8100000
 # CONFIG_SMP is not set
+CONFIG_HIGHMEM=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
 # CONFIG_PREEMPT is not set
-# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=y
 CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyMM0,9600 ip=on"
+CONFIG_CMDLINE="console=ttyMM0 ip=on"
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
 
 #
 # Bus options
@@ -132,21 +159,17 @@ CONFIG_GENERIC_ISA_DMA=y
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
 CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
 
 #
 # PCCARD (PCMCIA/CardBus) support
 #
 # CONFIG_PCCARD is not set
 
-#
-# PC-card bridges
-#
-
 #
 # Advanced setup
 #
 CONFIG_ADVANCED_OPTIONS=y
+# CONFIG_HIGHMEM_START_BOOL is not set
 CONFIG_HIGHMEM_START=0xfe000000
 # CONFIG_LOWMEM_SIZE_BOOL is not set
 CONFIG_LOWMEM_SIZE=0x30000000
@@ -161,6 +184,76 @@ CONFIG_CONSISTENT_SIZE=0x00400000
 # CONFIG_BOOT_LOAD_BOOL is not set
 CONFIG_BOOT_LOAD=0x00800000
 
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
 #
 # Device Drivers
 #
@@ -177,8 +270,8 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
 # CONFIG_MTD_CMDLINE_PARTS is not set
 
@@ -212,6 +305,7 @@ CONFIG_MTD_MAP_BANK_WIDTH_4=y
 CONFIG_MTD_CFI_I2=y
 # CONFIG_MTD_CFI_I4 is not set
 # CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
 # CONFIG_MTD_CFI_STAA is not set
@@ -219,7 +313,6 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -229,6 +322,7 @@ CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_PHYSMAP_START=0xe0000000
 CONFIG_MTD_PHYSMAP_LEN=0x0
 CONFIG_MTD_PHYSMAP_BANKWIDTH=4
+# CONFIG_MTD_PLATRAM is not set
 
 #
 # Self-contained MTD device drivers
@@ -278,7 +372,6 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
 # CONFIG_CDROM_PKTCDVD is not set
 
@@ -299,6 +392,7 @@ CONFIG_IOSCHED_CFQ=y
 #
 # SCSI device support
 #
+# CONFIG_RAID_ATTRS is not set
 # CONFIG_SCSI is not set
 
 #
@@ -309,6 +403,7 @@ CONFIG_IOSCHED_CFQ=y
 #
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -325,71 +420,8 @@ CONFIG_IOSCHED_CFQ=y
 #
 
 #
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
+# Network device support
 #
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
@@ -401,6 +433,11 @@ CONFIG_NETDEVICES=y
 #
 # CONFIG_ARCNET is not set
 
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
 #
 # Ethernet (10 or 100Mbit)
 #
@@ -422,6 +459,7 @@ CONFIG_TULIP=y
 # CONFIG_DE4X5 is not set
 # CONFIG_WINBOND_840 is not set
 # CONFIG_DM9102 is not set
+# CONFIG_ULI526X is not set
 # CONFIG_HP100 is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
@@ -448,14 +486,19 @@ CONFIG_E100=y
 #
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
+CONFIG_E1000=y
+# CONFIG_E1000_NAPI is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
 CONFIG_MV643XX_ETH=y
 CONFIG_MV643XX_ETH_0=y
 CONFIG_MV643XX_ETH_1=y
@@ -464,6 +507,7 @@ CONFIG_MV643XX_ETH_2=y
 #
 # Ethernet (10000 Mbit)
 #
+# CONFIG_CHELSIO_T1 is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 
@@ -487,6 +531,11 @@ CONFIG_MV643XX_ETH_2=y
 # CONFIG_SLIP is not set
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
+# CONFIG_KGDBOE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
@@ -515,14 +564,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
 
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
 #
 # Input Device Drivers
 #
@@ -532,6 +573,12 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
 #
 # Character devices
 #
@@ -552,6 +599,7 @@ CONFIG_SERIAL_MPSC=y
 CONFIG_SERIAL_MPSC_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -579,6 +627,11 @@ CONFIG_GEN_RTC=y
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
 #
 # I2C support
 #
@@ -602,11 +655,10 @@ CONFIG_I2C_CHARDEV=y
 # CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
-# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_MPC is not set
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
 # CONFIG_SCx200_ACB is not set
@@ -621,14 +673,39 @@ CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MV64XXX=y
 
 #
-# Hardware Sensors Chip support
+# Miscellaneous I2C Chip support
 #
-# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+CONFIG_SENSORS_M41T00=y
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
 # CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
 # CONFIG_SENSORS_FSCPOS is not set
@@ -644,36 +721,26 @@ CONFIG_I2C_MV64XXX=y
 # CONFIG_SENSORS_LM85 is not set
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
 # CONFIG_SENSORS_W83L785TS is not set
 # CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
-# Other I2C Chip support
-#
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_RTC8564 is not set
-CONFIG_SENSORS_M41T00=y
-# CONFIG_I2C_DEBUG_CORE is not set
-# CONFIG_I2C_DEBUG_ALGO is not set
-# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_I2C_DEBUG_CHIP is not set
-
-#
-# Dallas's 1-wire bus
+# Misc devices
 #
-# CONFIG_W1 is not set
 
 #
-# Misc devices
+# Multimedia Capabilities Port drivers
 #
 
 #
@@ -697,6 +764,11 @@ CONFIG_SENSORS_M41T00=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 
+#
+# Speakup console speech
+#
+# CONFIG_SPEAKUP is not set
+
 #
 # Sound
 #
@@ -705,13 +777,9 @@ CONFIG_DUMMY_CONSOLE=y
 #
 # USB support
 #
-# CONFIG_USB is not set
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
+# CONFIG_USB is not set
 
 #
 # USB Gadget Support
@@ -728,26 +796,40 @@ CONFIG_USB_ARCH_HAS_OHCI=y
 #
 # CONFIG_INFINIBAND is not set
 
+#
+# SN Devices
+#
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
 #
 # File systems
 #
 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_REISER4_FS 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 is not set
+CONFIG_INOTIFY=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
 
 #
 # CD-ROM/DVD Filesystems
@@ -768,20 +850,18 @@ CONFIG_DNOTIFY=y
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
-CONFIG_DEVFS_FS=y
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_RELAYFS_FS is not set
 
 #
 # Miscellaneous filesystems
 #
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
@@ -801,12 +881,14 @@ CONFIG_RAMFS=y
 #
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
 # CONFIG_NFS_V4 is not set
 # CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -815,6 +897,7 @@ CONFIG_SUNRPC=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -831,6 +914,7 @@ CONFIG_MSDOS_PARTITION=y
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 
@@ -842,8 +926,10 @@ CONFIG_CRC32=y
 #
 # Kernel hacking
 #
-# CONFIG_DEBUG_KERNEL is not set
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SERIAL_TEXT_DEBUG is not set
 
 #
 # Security options
diff --git a/arch/ppc/configs/mcpn765_defconfig b/arch/ppc/configs/mcpn765_defconfig
deleted file mode 100644 (file)
index 899e89a..0000000
+++ /dev/null
@@ -1,579 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_GENERIC_NVRAM=y
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
-# CONFIG_IKCONFIG is not set
-CONFIG_EMBEDDED=y
-CONFIG_KALLSYMS=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_KMOD is not set
-
-#
-# Processor
-#
-CONFIG_6xx=y
-# CONFIG_40x is not set
-# CONFIG_44x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_POWER4 is not set
-# CONFIG_8xx is not set
-CONFIG_ALTIVEC=y
-# CONFIG_TAU is not set
-# CONFIG_CPU_FREQ is not set
-CONFIG_PPC_STD_MMU=y
-
-#
-# Platform options
-#
-# CONFIG_PPC_MULTIPLATFORM is not set
-# CONFIG_APUS is not set
-# CONFIG_WILLOW is not set
-# CONFIG_PCORE is not set
-# CONFIG_POWERPMC250 is not set
-# CONFIG_EV64260 is not set
-# CONFIG_SPRUCE is not set
-# CONFIG_LOPEC is not set
-CONFIG_MCPN765=y
-# CONFIG_MVME5100 is not set
-# CONFIG_PPLUS is not set
-# CONFIG_PRPMC750 is not set
-# CONFIG_PRPMC800 is not set
-# CONFIG_SANDPOINT is not set
-# CONFIG_ADIR is not set
-# CONFIG_K2 is not set
-# CONFIG_PAL4 is not set
-# CONFIG_GEMINI is not set
-# CONFIG_EST8260 is not set
-# CONFIG_SBS8260 is not set
-# CONFIG_RPX6 is not set
-# CONFIG_TQM8260 is not set
-CONFIG_PPC_GEN550=y
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-CONFIG_HIGHMEM=y
-CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="ip=on"
-
-#
-# Bus options
-#
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-# CONFIG_PCI_LEGACY_PROC is not set
-# CONFIG_PCI_NAMES is not set
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00800000
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_CARMEL is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_LBD is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_IDE_GENERIC is not set
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
-# CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_BLK_DEV_GENERIC is not set
-# CONFIG_BLK_DEV_SL82C105 is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
-CONFIG_BLK_DEV_ADMA=y
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_SC1200 is not set
-# CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIIMAGE is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-CONFIG_BLK_DEV_VIA82CXXX=y
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Macintosh device drivers
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_OAKNET is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-CONFIG_NET_TULIP=y
-CONFIG_TULIP=y
-# CONFIG_TULIP_MMIO is not set
-# CONFIG_TULIP_NAPI is not set
-# CONFIG_DE4X5 is not set
-# CONFIG_WINBOND_840 is not set
-# CONFIG_DM9102 is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_PCI is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_R8169 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR 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_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Library routines
-#
-CONFIG_CRC32=y
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/menf1_defconfig b/arch/ppc/configs/menf1_defconfig
deleted file mode 100644 (file)
index 321659b..0000000
+++ /dev/null
@@ -1,621 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_EMBEDDED is not set
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_6xx=y
-# CONFIG_40x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_8xx is not set
-
-#
-# IBM 4xx options
-#
-# CONFIG_8260 is not set
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_PPC_STD_MMU=y
-# CONFIG_PPC_MULTIPLATFORM is not set
-# CONFIG_APUS is not set
-# CONFIG_WILLOW_2 is not set
-# CONFIG_PCORE is not set
-# CONFIG_POWERPMC250 is not set
-# CONFIG_EV64260 is not set
-# CONFIG_SPRUCE is not set
-CONFIG_MENF1=y
-# CONFIG_LOPEC is not set
-# CONFIG_MCPN765 is not set
-# CONFIG_MVME5100 is not set
-# CONFIG_PPLUS is not set
-# CONFIG_PRPMC750 is not set
-# CONFIG_PRPMC800 is not set
-# CONFIG_SANDPOINT is not set
-# CONFIG_ADIR is not set
-# CONFIG_K2 is not set
-# CONFIG_PAL4 is not set
-# CONFIG_GEMINI is not set
-CONFIG_MPC10X_STORE_GATHERING=y
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ALTIVEC is not set
-# CONFIG_TAU is not set
-# CONFIG_CPU_FREQ is not set
-
-#
-# General setup
-#
-# CONFIG_HIGHMEM is not set
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_PCI_LEGACY_PROC is not set
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-# CONFIG_PPC601_SYNC_FIX is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="ip=on"
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00800000
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE is not set
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_IDEPCI is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_IP_NF_CONNTRACK=m
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_IRC=m
-# CONFIG_IP_NF_TFTP is not set
-# CONFIG_IP_NF_AMANDA is not set
-# CONFIG_IP_NF_QUEUE is not set
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
-CONFIG_IP_NF_MATCH_TOS=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
-CONFIG_IP_NF_MATCH_UNCLEAN=m
-CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_MIRROR=m
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-# CONFIG_IP_NF_MANGLE is not set
-# CONFIG_IP_NF_TARGET_LOG is not set
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_XFRM_USER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_OAKNET is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 is not set
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_B44 is not set
-# CONFIG_DGRS is not set
-# CONFIG_EEPRO100 is not set
-# CONFIG_E100 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices (depends on LLC=y)
-#
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Macintosh device drivers
-#
-
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
index 38a343c9056ad3ead368322966518796f58f1f8a..f834fb541ad50e4e8871a5a097c92c1ff6172da9 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc1
-# Thu Jan 20 01:24:56 2005
+# Linux kernel version: 2.6.13-rc6
+# Thu Aug 11 18:14:45 2005
 #
 CONFIG_MMU=y
 CONFIG_GENERIC_HARDIRQS=y
@@ -11,6 +11,7 @@ CONFIG_HAVE_DEC_LOCK=y
 CONFIG_PPC=y
 CONFIG_PPC32=y
 CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
 
 #
 # Code maturity level options
@@ -18,6 +19,7 @@ CONFIG_GENERIC_NVRAM=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -29,12 +31,14 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 # CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 # CONFIG_EPOLL is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@@ -44,6 +48,7 @@ CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -59,12 +64,16 @@ CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_POWER3 is not set
 # CONFIG_POWER4 is not set
 # CONFIG_8xx is not set
+# CONFIG_E200 is not set
 CONFIG_E500=y
 CONFIG_BOOKE=y
 CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
 CONFIG_SPE=y
 CONFIG_MATH_EMULATION=y
+# CONFIG_KEXEC is not set
 # CONFIG_CPU_FREQ is not set
+# CONFIG_PM is not set
 CONFIG_85xx=y
 CONFIG_PPC_INDIRECT_PCI_BE=y
 
@@ -72,9 +81,11 @@ CONFIG_PPC_INDIRECT_PCI_BE=y
 # Freescale 85xx options
 #
 # CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8548_CDS is not set
 # CONFIG_MPC8555_CDS is not set
 CONFIG_MPC8560_ADS=y
 # CONFIG_SBC8560 is not set
+# CONFIG_STX_GP3 is not set
 CONFIG_MPC8560=y
 
 #
@@ -83,11 +94,25 @@ CONFIG_MPC8560=y
 CONFIG_CPM2=y
 # CONFIG_PC_KEYBOARD is not set
 # CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
 # CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_CMDLINE_BOOL is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
 
 #
 # Bus options
@@ -102,10 +127,6 @@ CONFIG_PCI_NAMES=y
 #
 # CONFIG_PCCARD is not set
 
-#
-# PC-card bridges
-#
-
 #
 # Advanced setup
 #
@@ -120,6 +141,69 @@ CONFIG_KERNEL_START=0xc0000000
 CONFIG_TASK_SIZE=0x80000000
 CONFIG_BOOT_LOAD=0x00800000
 
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+
 #
 # Device Drivers
 #
@@ -193,6 +277,7 @@ CONFIG_IOSCHED_CFQ=y
 #
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -209,71 +294,8 @@ CONFIG_IOSCHED_CFQ=y
 #
 
 #
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
+# Network device support
 #
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
@@ -311,8 +333,10 @@ CONFIG_MII=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
+# CONFIG_SKGE is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
 CONFIG_GIANFAR=y
 CONFIG_GFAR_NAPI=y
 
@@ -342,6 +366,8 @@ CONFIG_GFAR_NAPI=y
 # CONFIG_SLIP is not set
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
@@ -367,14 +393,6 @@ CONFIG_INPUT=y
 # CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
 
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
 #
 # Input Device Drivers
 #
@@ -384,6 +402,12 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
 #
 # Character devices
 #
@@ -403,11 +427,12 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_SERIAL_CPM=y
 CONFIG_SERIAL_CPM_CONSOLE=y
 CONFIG_SERIAL_CPM_SCC1=y
-# CONFIG_SERIAL_CPM_SCC2 is not set
+CONFIG_SERIAL_CPM_SCC2=y
 # CONFIG_SERIAL_CPM_SCC3 is not set
-CONFIG_SERIAL_CPM_SCC4=y
+# CONFIG_SERIAL_CPM_SCC4 is not set
 # CONFIG_SERIAL_CPM_SMC1 is not set
 # CONFIG_SERIAL_CPM_SMC2 is not set
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -435,6 +460,11 @@ CONFIG_GEN_RTC=y
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
 #
 # I2C support
 #
@@ -458,11 +488,11 @@ CONFIG_I2C_CHARDEV=y
 # CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_ISA is not set
 CONFIG_I2C_MPC=y
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
 # CONFIG_SCx200_ACB is not set
@@ -473,19 +503,46 @@ CONFIG_I2C_MPC=y
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
 # CONFIG_I2C_PCA_ISA is not set
+# CONFIG_I2C_SENSOR is not set
 
 #
-# Hardware Sensors Chip support
+# Miscellaneous I2C Chip support
 #
-# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
 # CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
@@ -496,31 +553,18 @@ CONFIG_I2C_MPC=y
 # CONFIG_SENSORS_LM85 is not set
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
 # CONFIG_SENSORS_W83627HF is not set
-
-#
-# Other I2C Chip support
-#
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_RTC8564 is not set
-# CONFIG_I2C_DEBUG_CORE is not set
-# CONFIG_I2C_DEBUG_ALGO is not set
-# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_I2C_DEBUG_CHIP is not set
-
-#
-# Dallas's 1-wire bus
-#
-# CONFIG_W1 is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
 # Misc devices
@@ -540,7 +584,6 @@ CONFIG_I2C_MPC=y
 # Graphics support
 #
 # CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -550,13 +593,9 @@ CONFIG_I2C_MPC=y
 #
 # USB support
 #
-# CONFIG_USB is not set
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
+# CONFIG_USB is not set
 
 #
 # USB Gadget Support
@@ -573,11 +612,16 @@ CONFIG_USB_ARCH_HAS_OHCI=y
 #
 # CONFIG_INFINIBAND is not set
 
+#
+# SN Devices
+#
+
 #
 # File systems
 #
 CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
@@ -587,9 +631,15 @@ CONFIG_JBD=y
 CONFIG_FS_MBCACHE=y
 # 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_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
@@ -614,7 +664,6 @@ CONFIG_DNOTIFY=y
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_XATTR is not set
@@ -648,7 +697,7 @@ CONFIG_NFS_FS=y
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -700,7 +749,9 @@ CONFIG_CRC32=y
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 # CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_KGDB_CONSOLE is not set
 
 #
diff --git a/arch/ppc/configs/oak_defconfig b/arch/ppc/configs/oak_defconfig
deleted file mode 100644 (file)
index 366cc48..0000000
+++ /dev/null
@@ -1,485 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_PPC32=y
-# CONFIG_6xx is not set
-CONFIG_40x=y
-# CONFIG_POWER3 is not set
-# CONFIG_8xx is not set
-CONFIG_4xx=y
-
-#
-# IBM 4xx options
-#
-# CONFIG_ASH is not set
-# CONFIG_BEECH is not set
-# CONFIG_CEDAR is not set
-# CONFIG_CPCI405 is not set
-# CONFIG_EP405 is not set
-CONFIG_OAK=y
-# CONFIG_REDWOOD_4 is not set
-# CONFIG_REDWOOD_5 is not set
-# CONFIG_REDWOOD_6 is not set
-# CONFIG_SYCAMORE is not set
-# CONFIG_TIVO is not set
-# CONFIG_WALNUT is not set
-CONFIG_IBM405_ERR51=y
-CONFIG_403GCX=y
-# CONFIG_405_DMA is not set
-# CONFIG_PM is not set
-CONFIG_UART0_TTYS0=y
-# CONFIG_UART0_TTYS1 is not set
-CONFIG_NOT_COHERENT_CACHE=y
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_MATH_EMULATION is not set
-# CONFIG_CPU_FREQ is not set
-
-#
-# General setup
-#
-# CONFIG_HIGHMEM is not set
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
-# CONFIG_PC_KEYBOARD is not set
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-# CONFIG_CMDLINE_BOOL is not set
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00400000
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_IPV6 is not set
-# CONFIG_XFRM_USER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
-CONFIG_OAKNET=y
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices (depends on LLC=y)
-#
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Macintosh device drivers
-#
-
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR 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_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# IBM 40x options
-#
-
-#
-# USB support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/pcore_defconfig b/arch/ppc/configs/pcore_defconfig
deleted file mode 100644 (file)
index ed34405..0000000
+++ /dev/null
@@ -1,716 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_GENERIC_NVRAM=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
-# CONFIG_IKCONFIG is not set
-CONFIG_EMBEDDED=y
-CONFIG_KALLSYMS=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Processor
-#
-CONFIG_6xx=y
-# CONFIG_40x is not set
-# CONFIG_44x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_POWER4 is not set
-# CONFIG_8xx is not set
-CONFIG_ALTIVEC=y
-# CONFIG_TAU is not set
-# CONFIG_CPU_FREQ is not set
-CONFIG_PPC_STD_MMU=y
-
-#
-# Platform options
-#
-# CONFIG_PPC_MULTIPLATFORM is not set
-# CONFIG_APUS is not set
-# CONFIG_WILLOW is not set
-CONFIG_PCORE=y
-# CONFIG_POWERPMC250 is not set
-# CONFIG_EV64260 is not set
-# CONFIG_SPRUCE is not set
-# CONFIG_LOPEC is not set
-# CONFIG_MCPN765 is not set
-# CONFIG_MVME5100 is not set
-# CONFIG_PPLUS is not set
-# CONFIG_PRPMC750 is not set
-# CONFIG_PRPMC800 is not set
-# CONFIG_SANDPOINT is not set
-# CONFIG_ADIR is not set
-# CONFIG_K2 is not set
-# CONFIG_PAL4 is not set
-# CONFIG_GEMINI is not set
-# CONFIG_EST8260 is not set
-# CONFIG_SBS8260 is not set
-# CONFIG_RPX6 is not set
-# CONFIG_TQM8260 is not set
-CONFIG_PPC_GEN550=y
-CONFIG_FORCE=y
-# CONFIG_MPC10X_STORE_GATHERING is not set
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_HIGHMEM is not set
-CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="ip=on"
-
-#
-# Bus options
-#
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-# CONFIG_PCI_LEGACY_PROC is not set
-# CONFIG_PCI_NAMES is not set
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00800000
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_CARMEL is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_LBD is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-CONFIG_SCSI=y
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-CONFIG_BLK_DEV_SR=y
-# CONFIG_BLK_DEV_SR_VENDOR is not set
-# CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_REPORT_LUNS is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI Transport Attributes
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_IPS is not set
-# CONFIG_SCSI_INIA100 is not set
-CONFIG_SCSI_SYM53C8XX_2=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
-CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA6322 is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Macintosh device drivers
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-
-#
-# IP: Virtual Server Configuration
-#
-# CONFIG_IP_VS is not set
-# CONFIG_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_IP_NF_CONNTRACK=m
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_IRC=m
-# CONFIG_IP_NF_TFTP is not set
-# CONFIG_IP_NF_AMANDA is not set
-# CONFIG_IP_NF_QUEUE is not set
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
-# CONFIG_IP_NF_MATCH_IPRANGE is not set
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
-CONFIG_IP_NF_MATCH_TOS=m
-# CONFIG_IP_NF_MATCH_RECENT is not set
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
-CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-# CONFIG_IP_NF_TARGET_NETMAP is not set
-# CONFIG_IP_NF_TARGET_SAME is not set
-# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-# CONFIG_IP_NF_MANGLE is not set
-# CONFIG_IP_NF_TARGET_LOG is not set
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-# CONFIG_IP_NF_ARP_MANGLE is not set
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_OAKNET is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-CONFIG_NET_TULIP=y
-# CONFIG_DE2104X is not set
-CONFIG_TULIP=y
-# CONFIG_TULIP_MWI is not set
-# CONFIG_TULIP_MMIO is not set
-# CONFIG_TULIP_NAPI is not set
-# CONFIG_DE4X5 is not set
-# CONFIG_WINBOND_840 is not set
-# CONFIG_DM9102 is not set
-# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 is not set
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_B44 is not set
-# CONFIG_FORCEDETH is not set
-# CONFIG_DGRS is not set
-CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PIO is not set
-# CONFIG_E100 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SIS190 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=2
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Library routines
-#
-CONFIG_CRC32=y
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/rainier_defconfig b/arch/ppc/configs/rainier_defconfig
deleted file mode 100644 (file)
index 4d4fcdc..0000000
+++ /dev/null
@@ -1,599 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# General setup
-#
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-CONFIG_MODVERSIONS=y
-CONFIG_KMOD=y
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_PPC32=y
-# CONFIG_6xx is not set
-CONFIG_40x=y
-# CONFIG_POWER3 is not set
-# CONFIG_8xx is not set
-CONFIG_4xx=y
-
-#
-# IBM 4xx options
-#
-# CONFIG_ASH is not set
-# CONFIG_BEECH is not set
-# CONFIG_CEDAR is not set
-# CONFIG_CPCI405 is not set
-# CONFIG_EP405 is not set
-# CONFIG_OAK is not set
-# CONFIG_REDWOOD_4 is not set
-# CONFIG_REDWOOD_5 is not set
-# CONFIG_REDWOOD_6 is not set
-# CONFIG_SYCAMORE is not set
-# CONFIG_TIVO is not set
-CONFIG_WALNUT=y
-CONFIG_IBM405_ERR77=y
-CONFIG_IBM405_ERR51=y
-CONFIG_IBM_OCP=y
-CONFIG_BIOS_FIXUP=y
-CONFIG_405GP=y
-CONFIG_IBM_OPENBIOS=y
-CONFIG_405_DMA=y
-# CONFIG_PM is not set
-CONFIG_UART0_TTYS0=y
-# CONFIG_UART0_TTYS1 is not set
-CONFIG_NOT_COHERENT_CACHE=y
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_MATH_EMULATION is not set
-# CONFIG_CPU_FREQ is not set
-
-#
-# General setup
-#
-# CONFIG_HIGHMEM is not set
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-# CONFIG_PC_KEYBOARD is not set
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_PCI_LEGACY_PROC is not set
-CONFIG_PCI_NAMES=y
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-# CONFIG_CMDLINE_BOOL is not set
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00400000
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_NBD=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_IPV6 is not set
-# CONFIG_XFRM_USER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_OAKNET is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-CONFIG_PCNET32=y
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_B44 is not set
-# CONFIG_DGRS is not set
-CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PIO is not set
-# CONFIG_E100 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-CONFIG_PPP=y
-# CONFIG_PPP_MULTILINK is not set
-# CONFIG_PPP_FILTER is not set
-# CONFIG_PPP_ASYNC is not set
-# CONFIG_PPP_SYNC_TTY is not set
-# CONFIG_PPP_DEFLATE is not set
-# CONFIG_PPP_BSDCOMP is not set
-# CONFIG_PPPOE is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices (depends on LLC=y)
-#
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Macintosh device drivers
-#
-
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-# CONFIG_I2C_IBM_OCP_ALGO is not set
-CONFIG_I2C_CHARDEV=y
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-# CONFIG_I2C_ALI15X3 is not set
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
-# CONFIG_I2C_I801 is not set
-# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_VIAPRO is not set
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-CONFIG_BUSMOUSE=y
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-# CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_WDT is not set
-# CONFIG_WDTPCI is not set
-# CONFIG_PCWATCHDOG is not set
-# CONFIG_ACQUIRE_WDT is not set
-# CONFIG_ADVANTECH_WDT is not set
-# CONFIG_EUROTECH_WDT is not set
-# CONFIG_IB700_WDT is not set
-# CONFIG_MIXCOMWD is not set
-# CONFIG_SCx200_WDT is not set
-# CONFIG_60XX_WDT is not set
-# CONFIG_W83877F_WDT is not set
-# CONFIG_MACHZ_WDT is not set
-# CONFIG_SC520_WDT is not set
-# CONFIG_AMD7XX_TCO is not set
-# CONFIG_ALIM7101_WDT is not set
-# CONFIG_SC1200_WDT is not set
-# CONFIG_WAFER_WDT is not set
-# CONFIG_CPU5_WDT is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR 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_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-CONFIG_AUTOFS_FS=y
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-CONFIG_NFSD=y
-# CONFIG_NFSD_V3 is not set
-# CONFIG_NFSD_TCP is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_EXPORTFS=y
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# IBM 40x options
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
-CONFIG_OCP=y
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/redwood_defconfig b/arch/ppc/configs/redwood_defconfig
deleted file mode 100644 (file)
index 4aa348d..0000000
+++ /dev/null
@@ -1,540 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-CONFIG_PPC=y
-CONFIG_PPC32=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-# CONFIG_STANDALONE is not set
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_IKCONFIG is not set
-CONFIG_EMBEDDED=y
-# CONFIG_KALLSYMS is not set
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Processor
-#
-# CONFIG_6xx is not set
-CONFIG_40x=y
-# CONFIG_44x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_POWER4 is not set
-# CONFIG_8xx is not set
-# CONFIG_MATH_EMULATION is not set
-# CONFIG_CPU_FREQ is not set
-CONFIG_4xx=y
-
-#
-# IBM 4xx options
-#
-# CONFIG_ASH is not set
-# CONFIG_BEECH is not set
-# CONFIG_CEDAR is not set
-# CONFIG_CPCI405 is not set
-# CONFIG_EP405 is not set
-# CONFIG_OAK is not set
-CONFIG_REDWOOD_4=y
-# CONFIG_REDWOOD_5 is not set
-# CONFIG_REDWOOD_6 is not set
-# CONFIG_SYCAMORE is not set
-# CONFIG_TIVO is not set
-# CONFIG_WALNUT is not set
-CONFIG_IBM405_ERR77=y
-CONFIG_IBM405_ERR51=y
-CONFIG_IBM_OCP=y
-CONFIG_STB03xxx=y
-CONFIG_IBM_OPENBIOS=y
-# CONFIG_405_DMA is not set
-# CONFIG_PM is not set
-CONFIG_UART0_TTYS0=y
-# CONFIG_UART0_TTYS1 is not set
-# CONFIG_SERIAL_SICC is not set
-CONFIG_NOT_COHERENT_CACHE=y
-
-#
-# Platform options
-#
-# CONFIG_PC_KEYBOARD is not set
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_HIGHMEM is not set
-CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_CMDLINE_BOOL is not set
-
-#
-# Bus options
-#
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00400000
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_LBD is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-CONFIG_OAKNET=y
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-
-#
-# Input Device Drivers
-#
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Macintosh device drivers
-#
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-# CONFIG_I2C_CHARDEV is not set
-
-#
-# I2C Algorithms
-#
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-
-#
-# I2C Hardware Bus support
-#
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
-CONFIG_I2C_IBM_IIC=y
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM78 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_W83781D is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_TMPFS=y
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# IBM 40x options
-#
-
-#
-# USB support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# Library routines
-#
-CONFIG_CRC32=y
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-CONFIG_SERIAL_TEXT_DEBUG=y
-CONFIG_OCP=y
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
index 468721d9ebd214c1048f9b293f0fa3d9a56d807d..bd037caa40559e0e79409e7ac9d5a4130ee32afd 100644 (file)
@@ -249,8 +249,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_NO_DPM)
        sync
        isync
 
-       /* Enable L2 HW prefetch
+       /* Enable L2 HW prefetch, if L2 is enabled
         */
+       mfspr   r3,SPRN_L2CR
+       andis.  r3,r3,L2CR_L2E@h
+       beqlr
        mfspr   r3,SPRN_MSSCR0
        ori     r3,r3,3
        sync
@@ -324,6 +327,7 @@ _GLOBAL(__save_cpu_setup)
        cmplwi  cr4,r3,0x8002   /* 7457 */
        cmplwi  cr5,r3,0x8003   /* 7447A */
        cmplwi  cr6,r3,0x7000   /* 750FX */
+       cmplwi  cr7,r3,0x8004   /* 7448 */
        /* cr1 is 7400 || 7410 */
        cror    4*cr1+eq,4*cr1+eq,4*cr2+eq
        /* cr0 is 74xx */
@@ -331,6 +335,7 @@ _GLOBAL(__save_cpu_setup)
        cror    4*cr0+eq,4*cr0+eq,4*cr4+eq
        cror    4*cr0+eq,4*cr0+eq,4*cr1+eq
        cror    4*cr0+eq,4*cr0+eq,4*cr5+eq
+       cror    4*cr0+eq,4*cr0+eq,4*cr7+eq
        bne     1f
        /* Backup 74xx specific regs */
        mfspr   r4,SPRN_MSSCR0
@@ -393,6 +398,7 @@ _GLOBAL(__restore_cpu_setup)
        cmplwi  cr4,r3,0x8002   /* 7457 */
        cmplwi  cr5,r3,0x8003   /* 7447A */
        cmplwi  cr6,r3,0x7000   /* 750FX */
+       cmplwi  cr7,r3,0x8004   /* 7448 */
        /* cr1 is 7400 || 7410 */
        cror    4*cr1+eq,4*cr1+eq,4*cr2+eq
        /* cr0 is 74xx */
@@ -400,6 +406,7 @@ _GLOBAL(__restore_cpu_setup)
        cror    4*cr0+eq,4*cr0+eq,4*cr4+eq
        cror    4*cr0+eq,4*cr0+eq,4*cr1+eq
        cror    4*cr0+eq,4*cr0+eq,4*cr5+eq
+       cror    4*cr0+eq,4*cr0+eq,4*cr7+eq
        bne     2f
        /* Restore 74xx specific regs */
        lwz     r4,CS_MSSCR0(r5)
index 8a3d74f2531e840a3a31717cbee94e24ab530baf..546e1ea4cafa31a6bb126dfce2fdcbde2e3fe6d3 100644 (file)
@@ -198,10 +198,10 @@ struct cpu_spec   cpu_specs[] = {
                .num_pmcs               = 4,
                .cpu_setup              = __setup_cpu_750
        },
-       {       /* 745/755 */
-               .pvr_mask               = 0xfffff000,
-               .pvr_value              = 0x00083000,
-               .cpu_name               = "745/755",
+       {       /* 750CX (80100 and 8010x?) */
+               .pvr_mask               = 0xfffffff0,
+               .pvr_value              = 0x00080100,
+               .cpu_name               = "750CX",
                .cpu_features           = CPU_FTR_COMMON |
                        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE |
                        CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU |
@@ -210,11 +210,11 @@ struct cpu_spec   cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
-               .cpu_setup              = __setup_cpu_750
+               .cpu_setup              = __setup_cpu_750cx
        },
-       {       /* 750CX (80100 and 8010x?) */
+       {       /* 750CX (82201 and 82202) */
                .pvr_mask               = 0xfffffff0,
-               .pvr_value              = 0x00080100,
+               .pvr_value              = 0x00082200,
                .cpu_name               = "750CX",
                .cpu_features           = CPU_FTR_COMMON |
                        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE |
@@ -226,10 +226,10 @@ struct cpu_spec   cpu_specs[] = {
                .num_pmcs               = 4,
                .cpu_setup              = __setup_cpu_750cx
        },
-       {       /* 750CX (82201 and 82202) */
+       {       /* 750CXe (82214) */
                .pvr_mask               = 0xfffffff0,
-               .pvr_value              = 0x00082200,
-               .cpu_name               = "750CX",
+               .pvr_value              = 0x00082210,
+               .cpu_name               = "750CXe",
                .cpu_features           = CPU_FTR_COMMON |
                        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE |
                        CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU |
@@ -240,9 +240,9 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 4,
                .cpu_setup              = __setup_cpu_750cx
        },
-       {       /* 750CXe (82214) */
-               .pvr_mask               = 0xfffffff0,
-               .pvr_value              = 0x00082210,
+       {       /* 750CXe "Gekko" (83214) */
+               .pvr_mask               = 0xffffffff,
+               .pvr_value              = 0x00083214,
                .cpu_name               = "750CXe",
                .cpu_features           = CPU_FTR_COMMON |
                        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE |
@@ -254,6 +254,20 @@ struct cpu_spec    cpu_specs[] = {
                .num_pmcs               = 4,
                .cpu_setup              = __setup_cpu_750cx
        },
+       {       /* 745/755 */
+               .pvr_mask               = 0xfffff000,
+               .pvr_value              = 0x00083000,
+               .cpu_name               = "745/755",
+               .cpu_features           = CPU_FTR_COMMON |
+                       CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE |
+                       CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU |
+                       CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP,
+               .cpu_user_features      = COMMON_PPC,
+               .icache_bsize           = 32,
+               .dcache_bsize           = 32,
+               .num_pmcs               = 4,
+               .cpu_setup              = __setup_cpu_750
+       },
        {       /* 750FX rev 1.x */
                .pvr_mask               = 0xffffff00,
                .pvr_value              = 0x70000100,
@@ -536,6 +550,22 @@ struct cpu_spec    cpu_specs[] = {
                .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_745x
        },
+       {       /* 7448 */
+               .pvr_mask               = 0xffff0000,
+               .pvr_value              = 0x80040000,
+               .cpu_name               = "7448",
+               .cpu_features           = CPU_FTR_COMMON |
+                       CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
+                       CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR |
+                       CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE |
+                       CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR |
+                       CPU_FTR_HAS_HIGH_BATS | CPU_FTR_NEED_COHERENT,
+               .cpu_user_features      = COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP,
+               .icache_bsize           = 32,
+               .dcache_bsize           = 32,
+               .num_pmcs               = 6,
+               .cpu_setup              = __setup_cpu_745x
+       },
        {       /* 82xx (8240, 8245, 8260 are all 603e cores) */
                .pvr_mask               = 0x7fff0000,
                .pvr_value              = 0x00810000,
@@ -922,6 +952,26 @@ struct cpu_spec    cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
        },
+       { /* 440GX Rev. F */
+               .pvr_mask               = 0xf0000fff,
+               .pvr_value              = 0x50000894,
+               .cpu_name               = "440GX Rev. F",
+               .cpu_features           = CPU_FTR_SPLIT_ID_CACHE |
+                       CPU_FTR_USE_TB,
+               .cpu_user_features      = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+               .icache_bsize           = 32,
+               .dcache_bsize           = 32,
+       },
+       { /* 440SP Rev. A */
+               .pvr_mask               = 0xff000fff,
+               .pvr_value              = 0x53000891,
+               .cpu_name               = "440SP Rev. A",
+               .cpu_features           = CPU_FTR_SPLIT_ID_CACHE |
+                       CPU_FTR_USE_TB,
+               .cpu_user_features      = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+               .icache_bsize           = 32,
+               .dcache_bsize           = 32,
+       },
 #endif /* CONFIG_44x */
 #ifdef CONFIG_FSL_BOOKE
        {       /* e200z5 */
diff --git a/arch/ppc/kernel/find_name.c b/arch/ppc/kernel/find_name.c
deleted file mode 100644 (file)
index 3c0fa8e..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#include <stdio.h>
-#include <asm/page.h>
-#include <sys/mman.h>
-#include <strings.h>
-/*
- * Finds a given address in the System.map and prints it out
- * with its neighbors.  -- Cort
- */
-
-int main(int argc, char **argv)
-{
-       unsigned long addr, cmp, i;
-       FILE *f;
-       char s[256], last[256];
-       
-       if ( argc < 2 )
-       {
-               fprintf(stderr, "Usage: %s <address>\n", argv[0]);
-               return -1;
-       }
-
-       for ( i = 1 ; argv[i] ; i++ )
-       {
-               sscanf( argv[i], "%0lx", &addr );
-               /* adjust if addr is relative to kernelbase */
-               if ( addr < PAGE_OFFSET )
-                       addr += PAGE_OFFSET;
-               
-               if ( (f = fopen( "System.map", "r" )) == NULL )
-               {
-                       perror("fopen()\n");
-                       exit(-1);
-               }
-               
-               while ( !feof(f) )
-               {
-                       fgets(s, 255 , f);
-                       sscanf( s, "%0lx", &cmp );
-                       if ( addr < cmp )
-                               break;
-                       strcpy( last, s);
-               }
-               
-               printf( "%s%s", last, s );
-       }               
-       fclose(f);
-       return 0;
-}
index 69ff3a9961e8728d061e258c0b7121a0aa71e97c..9e68e32edb6065a25a9d90a2710ee1cd61b26c7b 100644 (file)
@@ -462,7 +462,11 @@ interrupt_base:
 
        /* Watchdog Timer Interrupt */
        /* TODO: Add watchdog support */
+#ifdef CONFIG_BOOKE_WDT
+       CRITICAL_EXCEPTION(0x1020, WatchdogTimer, WatchdogException)
+#else
        CRITICAL_EXCEPTION(0x1020, WatchdogTimer, UnknownException)
+#endif
 
        /* Data TLB Error Interrupt */
        START_EXCEPTION(DataTLBError)
index 23fb51819ba5128735dd7bb28edf5085c02b2da2..0a5e723d3be6c820fb116489824e1b963e5b2dcc 100644 (file)
@@ -448,7 +448,9 @@ label:
 
 /* 0x1020 - Watchdog Timer (WDT) Exception
 */
-
+#ifdef CONFIG_BOOKE_WDT
+       CRITICAL_EXCEPTION(0x1020, WDTException, WatchdogException)
+#else
        CRITICAL_EXCEPTION(0x1020, WDTException, UnknownException)
 #endif
 
index eb804b7a3cb21117fbbcf45769aabb3788d0d37c..4028f4c7d97893f0e6785c032f5f469282f30b72 100644 (file)
@@ -564,8 +564,11 @@ interrupt_base:
        EXCEPTION(0x3100, FixedIntervalTimer, UnknownException, EXC_XFER_EE)
 
        /* Watchdog Timer Interrupt */
-       /* TODO: Add watchdog support */
+#ifdef CONFIG_BOOKE_WDT
+       CRITICAL_EXCEPTION(0x3200, WatchdogTimer, WatchdogException)
+#else
        CRITICAL_EXCEPTION(0x3200, WatchdogTimer, UnknownException)
+#endif
 
        /* Data TLB Error Interrupt */
        START_EXCEPTION(DataTLBError)
index c39441048266f7ba918f3793f41fa8588267d309..861115249b3595fcadcb6319fef16e97de96c940 100644 (file)
@@ -156,6 +156,26 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
               The bit moved on the 7450.....
          ****/
 
+BEGIN_FTR_SECTION
+       /* Disable L2 prefetch on some 745x and try to ensure
+        * L2 prefetch engines are idle. As explained by errata
+        * text, we can't be sure they are, we just hope very hard
+        * that well be enough (sic !). At least I noticed Apple
+        * doesn't even bother doing the dcbf's here...
+        */
+       mfspr   r4,SPRN_MSSCR0
+       rlwinm  r4,r4,0,0,29
+       sync
+       mtspr   SPRN_MSSCR0,r4
+       sync
+       isync
+       lis     r4,KERNELBASE@h
+       dcbf    0,r4
+       dcbf    0,r4
+       dcbf    0,r4
+       dcbf    0,r4
+END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
+
        /* TODO: use HW flush assist when available */
 
        lis     r4,0x0002
@@ -230,7 +250,16 @@ END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
        oris    r3,r3,0x8000
        mtspr   SPRN_L2CR,r3
        sync
-
+       
+       /* Enable L2 HW prefetch on 744x/745x */
+BEGIN_FTR_SECTION
+       mfspr   r3,SPRN_MSSCR0
+       ori     r3,r3,3
+       sync
+       mtspr   SPRN_MSSCR0,r3
+       sync
+       isync
+END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
 4:
 
        /* Restore HID0[DPM] to whatever it was before */
index e7d40cc6c1b6fb266a5ab2fe49e72f7046193fc1..88f6bb7b6964ec6ab8ee47c8ab6e0bce7a1cc19b 100644 (file)
@@ -51,9 +51,6 @@
 #include <asm/commproc.h>
 #endif
 
-/* Tell string.h we don't want memcpy etc. as cpp defines */
-#define EXPORT_SYMTAB_STROPS
-
 extern void transfer_to_handler(void);
 extern void do_IRQ(struct pt_regs *regs);
 extern void MachineCheckException(struct pt_regs *regs);
@@ -263,6 +260,7 @@ EXPORT_SYMBOL(__ashrdi3);
 EXPORT_SYMBOL(__ashldi3);
 EXPORT_SYMBOL(__lshrdi3);
 EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(cacheable_memcpy);
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(memscan);
index 929e5d1cc7fea145ecffdd2e6968b929dde1ebd6..545cfd0fab59969e0c8c2a54de4d4e602cd643c9 100644 (file)
 #include <asm/xmon.h>
 #include <asm/ocp.h>
 
-#if defined(CONFIG_85xx) || defined(CONFIG_83xx) || defined(CONFIG_MPC10X_BRIDGE)
+#define USES_PPC_SYS (defined(CONFIG_85xx) || defined(CONFIG_83xx) || \
+                     defined(CONFIG_MPC10X_BRIDGE) || defined(CONFIG_8260) || \
+                     defined(CONFIG_PPC_MPC52xx))
+
+#if USES_PPC_SYS
 #include <asm/ppc_sys.h>
 #endif
 
@@ -241,7 +245,7 @@ int show_cpuinfo(struct seq_file *m, void *v)
        seq_printf(m, "bogomips\t: %lu.%02lu\n",
                   lpj / (500000/HZ), (lpj / (5000/HZ)) % 100);
 
-#if defined(CONFIG_85xx) || defined(CONFIG_83xx) || defined(CONFIG_MPC10X_BRIDGE)
+#if USES_PPC_SYS
        if (cur_ppc_sys_spec->ppc_sys_name)
                seq_printf(m, "chipset\t\t: %s\n",
                        cur_ppc_sys_spec->ppc_sys_name);
@@ -615,6 +619,26 @@ machine_init(unsigned long r3, unsigned long r4, unsigned long r5,
        if (ppc_md.progress)
                ppc_md.progress("id mach(): done", 0x200);
 }
+#ifdef CONFIG_BOOKE_WDT
+/* Checks wdt=x and wdt_period=xx command-line option */
+int __init early_parse_wdt(char *p)
+{
+       if (p && strncmp(p, "0", 1) != 0)
+              booke_wdt_enabled = 1;
+
+       return 0;
+}
+early_param("wdt", early_parse_wdt);
+
+int __init early_parse_wdt_period (char *p)
+{
+       if (p)
+               booke_wdt_period = simple_strtoul(p, NULL, 0);
+
+       return 0;
+}
+early_param("wdt_period", early_parse_wdt_period);
+#endif /* CONFIG_BOOKE_WDT */
 
 /* Checks "l2cr=xxxx" command-line option */
 int __init ppc_setup_l2cr(char *str)
index 8aaeb6f4e750249026e257b3e416604eb09c075f..2244bf91e593b1fd1ec13b596b4515e6c829987e 100644 (file)
@@ -759,13 +759,12 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
        else
                handle_signal(signr, &ka, &info, oldset, regs, newsp);
 
-       if (!(ka.sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka.sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka.sa.sa_mask);
+       if (!(ka.sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked, signr);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 
        return 1;
 }
index bf4ddca5e853b22f460a7d4f8b0a06e396ae406c..a3c5281a5d2d8c05e328a6fc5c83f10b9981193c 100644 (file)
@@ -169,7 +169,7 @@ void timer_interrupt(struct pt_regs * regs)
                 * We should have an rtc call that only sets the minutes and
                 * seconds like on Intel to avoid problems with non UTC clocks.
                 */
-               if ( ppc_md.set_rtc_time && (time_status & STA_UNSYNC) == 0 &&
+               if ( ppc_md.set_rtc_time && ntp_synced() &&
                     xtime.tv_sec - last_rtc_update >= 659 &&
                     abs((xtime.tv_nsec / 1000) - (1000000-1000000/HZ)) < 500000/HZ &&
                     jiffies - wall_jiffies == 1) {
@@ -271,10 +271,7 @@ int do_settimeofday(struct timespec *tv)
         */
        last_rtc_update = new_sec - 658;
 
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
        write_sequnlock_irqrestore(&xtime_lock, flags);
        clock_was_set();
        return 0;
index 9e6ae5696650259da8212b076ca441f145fd5dbb..d87423d1003a6c1de89d4880aff8aa17c889a1c9 100644 (file)
@@ -904,6 +904,25 @@ void SPEFloatingPointException(struct pt_regs *regs)
 }
 #endif
 
+#ifdef CONFIG_BOOKE_WDT
+/*
+ * Default handler for a Watchdog exception,
+ * spins until a reboot occurs
+ */
+void __attribute__ ((weak)) WatchdogHandler(struct pt_regs *regs)
+{
+       /* Generic WatchdogHandler, implement your own */
+       mtspr(SPRN_TCR, mfspr(SPRN_TCR)&(~TCR_WIE));
+       return;
+}
+
+void WatchdogException(struct pt_regs *regs)
+{
+       printk (KERN_EMERG "PowerPC Book-E Watchdog Exception\n");
+       WatchdogHandler(regs);
+}
+#endif
+
 void __init trap_init(void)
 {
 }
index 33ada72c73302900a8f34a1c69a9763eb59dd6be..f421a4b337f6a96caaafbbd18dc6e7e8c184a6ec 100644 (file)
@@ -560,9 +560,10 @@ void flush_dcache_page(struct page *page)
 void flush_dcache_icache_page(struct page *page)
 {
 #ifdef CONFIG_BOOKE
-       __flush_dcache_icache(kmap(page));
-       kunmap(page);
-#elif CONFIG_8xx
+       void *start = kmap_atomic(page, KM_PPC_SYNC_ICACHE);
+       __flush_dcache_icache(start);
+       kunmap_atomic(start, KM_PPC_SYNC_ICACHE);
+#elif defined(CONFIG_8xx)
        /* On 8xx there is no need to kmap since highmem is not supported */
        __flush_dcache_icache(page_address(page)); 
 #else
index 805dd98908a3cd4e90164f2e0c1cde80d0c8ef5e..76f4476cab44b7803b7a481fb9785a2d78b73027 100644 (file)
@@ -16,11 +16,6 @@ choice
        depends on 40x
        default WALNUT
 
-config ASH
-       bool "Ash"
-       help
-         This option enables support for the IBM NP405H evaluation board.
-
 config BUBINGA
        bool "Bubinga"
        select WANT_EARLY_SERIAL
@@ -37,11 +32,6 @@ config EP405
        help
          This option enables support for the EP405/EP405PC boards.
 
-config OAK
-       bool "Oak"
-       help
-         This option enables support for the IBM 403GCX evaluation board.
-
 config REDWOOD_5
        bool "Redwood-5"
        help
@@ -152,13 +142,13 @@ config IBM440EP_ERR42
 # All 405-based cores up until the 405GPR and 405EP have this errata.
 config IBM405_ERR77
        bool
-       depends on 40x && !403GCX && !405GPR
+       depends on 40x && !403GCX && !405GPR && !405EP
        default y
 
 # All 40x-based cores, up until the 405GPR and 405EP have this errata.
 config IBM405_ERR51
        bool
-       depends on 40x && !405GPR
+       depends on 40x && !405GPR && !405EP
        default y
 
 config BOOKE
@@ -186,6 +176,7 @@ config BIOS_FIXUP
        depends on BUBINGA || EP405 || SYCAMORE || WALNUT
        default y
 
+# OAK doesn't exist but wanted to keep this around for any future 403GCX boards
 config 403GCX
        bool
        depends OAK
index 844c3b5066e8b103f487b1cd14e5f8e0da554721..1dd6d7fd6a9a8b08b25203af8b12a82b48968fa9 100644 (file)
@@ -1,14 +1,12 @@
 #
 # Makefile for the PowerPC 4xx linux kernel.
 
-obj-$(CONFIG_ASH)              += ash.o
 obj-$(CONFIG_BAMBOO)           += bamboo.o
 obj-$(CONFIG_CPCI405)          += cpci405.o
 obj-$(CONFIG_EBONY)            += ebony.o
 obj-$(CONFIG_EP405)            += ep405.o
 obj-$(CONFIG_BUBINGA)          += bubinga.o
 obj-$(CONFIG_LUAN)             += luan.o
-obj-$(CONFIG_OAK)              += oak.o
 obj-$(CONFIG_OCOTEA)           += ocotea.o
 obj-$(CONFIG_REDWOOD_5)                += redwood5.o
 obj-$(CONFIG_REDWOOD_6)                += redwood6.o
diff --git a/arch/ppc/platforms/4xx/ash.c b/arch/ppc/platforms/4xx/ash.c
deleted file mode 100644 (file)
index ce29117..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * arch/ppc/platforms/4xx/ash.c
- *
- * Support for the IBM NP405H ash eval board
- *
- * Author: Armin Kuster <akuster@mvista.com>
- *
- * 2001-2002 (c) MontaVista, Software, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/pagemap.h>
-#include <linux/pci.h>
-
-#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
-#include <asm/io.h>
-#include <asm/ocp.h>
-#include <asm/ibm_ocp_pci.h>
-#include <asm/todc.h>
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-void *ash_rtc_base;
-
-/* Some IRQs unique to Walnut.
- * Used by the generic 405 PCI setup functions in ppc4xx_pci.c
- */
-int __init
-ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-       static char pci_irq_table[][4] =
-           /*
-            *      PCI IDSEL/INTPIN->INTLINE
-            *      A       B       C       D
-            */
-       {
-               {24, 24, 24, 24},       /* IDSEL 1 - PCI slot 1 */
-               {25, 25, 25, 25},       /* IDSEL 2 - PCI slot 2 */
-               {26, 26, 26, 26},       /* IDSEL 3 - PCI slot 3 */
-               {27, 27, 27, 27},       /* IDSEL 4 - PCI slot 4 */
-       };
-
-       const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
-       return PCI_IRQ_TABLE_LOOKUP;
-}
-
-void __init
-ash_setup_arch(void)
-{
-       ppc4xx_setup_arch();
-
-       ibm_ocp_set_emac(0, 3);
-
-#ifdef CONFIG_DEBUG_BRINGUP
-       int i;
-       printk("\n");
-       printk("machine\t: %s\n", PPC4xx_MACHINE_NAME);
-       printk("\n");
-       printk("bi_s_version\t %s\n", bip->bi_s_version);
-       printk("bi_r_version\t %s\n", bip->bi_r_version);
-       printk("bi_memsize\t 0x%8.8x\t %dMBytes\n", bip->bi_memsize,
-              bip->bi_memsize / (1024 * 1000));
-       for (i = 0; i < EMAC_NUMS; i++) {
-               printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", i,
-                      bip->bi_enetaddr[i][0], bip->bi_enetaddr[i][1],
-                      bip->bi_enetaddr[i][2], bip->bi_enetaddr[i][3],
-                      bip->bi_enetaddr[i][4], bip->bi_enetaddr[i][5]);
-       }
-       printk("bi_pci_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 0,
-              bip->bi_pci_enetaddr[0], bip->bi_pci_enetaddr[1],
-              bip->bi_pci_enetaddr[2], bip->bi_pci_enetaddr[3],
-              bip->bi_pci_enetaddr[4], bip->bi_pci_enetaddr[5]);
-
-       printk("bi_intfreq\t 0x%8.8x\t clock:\t %dMhz\n",
-              bip->bi_intfreq, bip->bi_intfreq / 1000000);
-
-       printk("bi_busfreq\t 0x%8.8x\t plb bus clock:\t %dMHz\n",
-              bip->bi_busfreq, bip->bi_busfreq / 1000000);
-       printk("bi_pci_busfreq\t 0x%8.8x\t pci bus clock:\t %dMHz\n",
-              bip->bi_pci_busfreq, bip->bi_pci_busfreq / 1000000);
-
-       printk("\n");
-#endif
-       /* RTC step for ash */
-       ash_rtc_base = (void *) ASH_RTC_VADDR;
-       TODC_INIT(TODC_TYPE_DS1743, ash_rtc_base, ash_rtc_base, ash_rtc_base,
-                 8);
-}
-
-void __init
-bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip)
-{
-       /*
-        * Expected PCI mapping:
-        *
-        *  PLB addr             PCI memory addr
-        *  ---------------------       ---------------------
-        *  0000'0000 - 7fff'ffff <---  0000'0000 - 7fff'ffff
-        *  8000'0000 - Bfff'ffff --->  8000'0000 - Bfff'ffff
-        *
-        *  PLB addr             PCI io addr
-        *  ---------------------       ---------------------
-        *  e800'0000 - e800'ffff --->  0000'0000 - 0001'0000
-        *
-        * The following code is simplified by assuming that the bootrom
-        * has been well behaved in following this mapping.
-        */
-
-#ifdef DEBUG
-       int i;
-
-       printk("ioremap PCLIO_BASE = 0x%x\n", pcip);
-       printk("PCI bridge regs before fixup \n");
-       for (i = 0; i <= 2; i++) {
-               printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
-               printk(" pmm%dla\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
-               printk(" pmm%dpcila\t0x%x\n", i,
-                      in_le32(&(pcip->pmm[i].pcila)));
-               printk(" pmm%dpciha\t0x%x\n", i,
-                      in_le32(&(pcip->pmm[i].pciha)));
-       }
-       printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
-       printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
-       printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
-       printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
-       for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
-               early_read_config_dword(hose, hose->first_busno,
-                                       PCI_FUNC(hose->first_busno), bar,
-                                       &bar_response);
-               DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
-                   hose->first_busno, PCI_SLOT(hose->first_busno),
-                   PCI_FUNC(hose->first_busno), bar, bar_response);
-       }
-
-#endif
-       if (ppc_md.progress)
-               ppc_md.progress("bios_fixup(): enter", 0x800);
-
-       /* added for IBM boot rom version 1.15 bios bar changes  -AK */
-
-       /* Disable region first */
-       out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
-       /* PLB starting addr, PCI: 0x80000000 */
-       out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
-       /* PCI start addr, 0x80000000 */
-       out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE);
-       /* 512MB range of PLB to PCI */
-       out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000);
-       /* Enable no pre-fetch, enable region */
-       out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff -
-                                               (PPC405_PCI_UPPER_MEM -
-                                                PPC405_PCI_MEM_BASE)) | 0x01));
-
-       /* Disable region one */
-       out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
-       out_le32((void *) &(pcip->pmm[1].la), 0x00000000);
-       out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000);
-       out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000);
-       out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
-
-       /* Disable region two */
-       out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
-       out_le32((void *) &(pcip->pmm[2].la), 0x00000000);
-       out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000);
-       out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000);
-       out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
-
-       /* Enable PTM1 and PTM2, mapped to PLB address 0. */
-
-       out_le32((void *) &(pcip->ptm1la), 0x00000000);
-       out_le32((void *) &(pcip->ptm1ms), 0x00000001);
-       out_le32((void *) &(pcip->ptm2la), 0x00000000);
-       out_le32((void *) &(pcip->ptm2ms), 0x00000001);
-
-       /* Write zero to PTM1 BAR. */
-
-       early_write_config_dword(hose, hose->first_busno,
-                                PCI_FUNC(hose->first_busno),
-                                PCI_BASE_ADDRESS_1,
-                                0x00000000);
-
-       /* Disable PTM2 (unused) */
-
-       out_le32((void *) &(pcip->ptm2la), 0x00000000);
-       out_le32((void *) &(pcip->ptm2ms), 0x00000000);
-
-       /* end work arround */
-       if (ppc_md.progress)
-               ppc_md.progress("bios_fixup(): done", 0x800);
-
-#ifdef DEBUG
-       printk("PCI bridge regs after fixup \n");
-       for (i = 0; i <= 2; i++) {
-               printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
-               printk(" pmm%dla\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
-               printk(" pmm%dpcila\t0x%x\n", i,
-                      in_le32(&(pcip->pmm[i].pcila)));
-               printk(" pmm%dpciha\t0x%x\n", i,
-                      in_le32(&(pcip->pmm[i].pciha)));
-       }
-       printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
-       printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
-       printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
-       printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
-
-       for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
-               early_read_config_dword(hose, hose->first_busno,
-                                       PCI_FUNC(hose->first_busno), bar,
-                                       &bar_response);
-               DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
-                   hose->first_busno, PCI_SLOT(hose->first_busno),
-                   PCI_FUNC(hose->first_busno), bar, bar_response);
-       }
-
-
-#endif
-}
-
-void __init
-ash_map_io(void)
-{
-       ppc4xx_map_io();
-       io_block_mapping(ASH_RTC_VADDR, ASH_RTC_PADDR, ASH_RTC_SIZE, _PAGE_IO);
-}
-
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
-             unsigned long r6, unsigned long r7)
-{
-       ppc4xx_init(r3, r4, r5, r6, r7);
-
-       ppc_md.setup_arch = ash_setup_arch;
-       ppc_md.setup_io_mappings = ash_map_io;
-
-#ifdef CONFIG_PPC_RTC
-       ppc_md.time_init = todc_time_init;
-       ppc_md.set_rtc_time = todc_set_rtc_time;
-       ppc_md.get_rtc_time = todc_get_rtc_time;
-       ppc_md.nvram_read_val = todc_direct_read_val;
-       ppc_md.nvram_write_val = todc_direct_write_val;
-#endif
-}
diff --git a/arch/ppc/platforms/4xx/ash.h b/arch/ppc/platforms/4xx/ash.h
deleted file mode 100644 (file)
index 5f7448e..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * arch/ppc/platforms/4xx/ash.h
- *
- * Macros, definitions, and data structures specific to the IBM PowerPC
- * Ash eval board.
- *
- * Author: Armin Kuster <akuster@mvista.com>
- *
- * 2000-2002 (c) MontaVista, Software, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_ASH_H__
-#define __ASM_ASH_H__
-#include <platforms/4xx/ibmnp405h.h>
-
-#ifndef __ASSEMBLY__
-/*
- * Data structure defining board information maintained by the boot
- * ROM on IBM's "Ash" evaluation board. An effort has been made to
- * keep the field names consistent with the 8xx 'bd_t' board info
- * structures.
- */
-
-typedef struct board_info {
-       unsigned char    bi_s_version[4];       /* Version of this structure */
-       unsigned char    bi_r_version[30];      /* Version of the IBM ROM */
-       unsigned int     bi_memsize;            /* DRAM installed, in bytes */
-       unsigned char    bi_enetaddr[4][6];     /* Local Ethernet MAC address */
-       unsigned char    bi_pci_enetaddr[6];
-       unsigned int     bi_intfreq;            /* Processor speed, in Hz */
-       unsigned int     bi_busfreq;            /* PLB Bus speed, in Hz */
-       unsigned int     bi_pci_busfreq;        /* PCI speed in Hz */
-} bd_t;
-
-/* Some 4xx parts use a different timebase frequency from the internal clock.
-*/
-#define bi_tbfreq bi_intfreq
-
-/* Memory map for the IBM "Ash" NP405H evaluation board.
- */
-
-extern  void *ash_rtc_base;
-#define ASH_RTC_PADDR          ((uint)0xf0000000)
-#define ASH_RTC_VADDR          ASH_RTC_PADDR
-#define ASH_RTC_SIZE           ((uint)8*1024)
-
-
-/* Early initialization address mapping for block_io.
- * Standard 405GP map.
- */
-#define PPC4xx_PCI_IO_PADDR    ((uint)PPC405_PCI_PHY_IO_BASE)
-#define PPC4xx_PCI_IO_VADDR    PPC4xx_PCI_IO_PADDR
-#define PPC4xx_PCI_IO_SIZE     ((uint)64*1024)
-#define PPC4xx_PCI_CFG_PADDR   ((uint)PPC405_PCI_CONFIG_ADDR)
-#define PPC4xx_PCI_CFG_VADDR   PPC4xx_PCI_CFG_PADDR
-#define PPC4xx_PCI_CFG_SIZE    ((uint)4*1024)
-#define PPC4xx_PCI_LCFG_PADDR  ((uint)0xef400000)
-#define PPC4xx_PCI_LCFG_VADDR  PPC4xx_PCI_LCFG_PADDR
-#define PPC4xx_PCI_LCFG_SIZE   ((uint)4*1024)
-#define PPC4xx_ONB_IO_PADDR    ((uint)0xef600000)
-#define PPC4xx_ONB_IO_VADDR    PPC4xx_ONB_IO_PADDR
-#define PPC4xx_ONB_IO_SIZE     ((uint)4*1024)
-
-#define NR_BOARD_IRQS 32
-
-#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK
-#define BASE_BAUD              201600
-#else
-#define BASE_BAUD              691200
-#endif
-
-#define PPC4xx_MACHINE_NAME "IBM NP405H Ash"
-
-extern char pci_irq_table[][4];
-
-
-#endif /* !__ASSEMBLY__ */
-#endif /* __ASM_ASH_H__ */
-#endif /* __KERNEL__ */
index f116787b0b76cc1dee4e0583a0681eceaa24e557..ac391d463d78af752e05b3dddff082e1604e6927 100644 (file)
 #include <syslib/gen550.h>
 #include <syslib/ibm440gx_common.h>
 
-/*
- * This is a horrible kludge, we eventually need to abstract this
- * generic PHY stuff, so the  standard phy mode defines can be
- * easily used from arch code.
- */
-#include "../../../../drivers/net/ibm_emac/ibm_emac_phy.h"
-
 bd_t __res;
 
 static struct ibm44x_clocks clocks __initdata;
@@ -123,33 +116,69 @@ bamboo_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
 
 static void __init bamboo_set_emacdata(void)
 {
-       unsigned char * selection1_base;
+       u8 * base_addr;
        struct ocp_def *def;
        struct ocp_func_emac_data *emacdata;
-       u8 selection1_val;
+       u8 val;
        int mode;
+       u32 excluded = 0;
 
-       selection1_base = ioremap64(BAMBOO_FPGA_SELECTION1_REG_ADDR, 16);
-       selection1_val = readb(selection1_base);
-       iounmap((void *) selection1_base);
-       if (BAMBOO_SEL_MII(selection1_val))
+       base_addr = ioremap64(BAMBOO_FPGA_SELECTION1_REG_ADDR, 16);
+       val = readb(base_addr);
+       iounmap((void *) base_addr);
+       if (BAMBOO_SEL_MII(val))
                mode = PHY_MODE_MII;
-       else if (BAMBOO_SEL_RMII(selection1_val))
+       else if (BAMBOO_SEL_RMII(val))
                mode = PHY_MODE_RMII;
        else
                mode = PHY_MODE_SMII;
 
-       /* Set mac_addr and phy mode for each EMAC */
+       /*
+        * SW2 on the Bamboo is used for ethernet configuration and is accessed
+        * via the CONFIG2 register in the FPGA.  If the ANEG pin is set,
+        * overwrite the supported features with the settings in SW2.
+        *
+        * This is used as a workaround for the improperly biased RJ-45 sockets
+        * on the Rev. 0 Bamboo.  By default only 10baseT is functional.
+        * Removing inductors L17 and L18 from the board allows 100baseT, but
+        * disables 10baseT.  The Rev. 1 has no such limitations.
+        */
+
+       base_addr = ioremap64(BAMBOO_FPGA_CONFIG2_REG_ADDR, 8);
+       val = readb(base_addr);
+       iounmap((void *) base_addr);
+       if (!BAMBOO_AUTONEGOTIATE(val)) {
+               excluded |= SUPPORTED_Autoneg;
+               if (BAMBOO_FORCE_100Mbps(val)) {
+                       excluded |= SUPPORTED_10baseT_Full;
+                       excluded |= SUPPORTED_10baseT_Half;
+                       if (BAMBOO_FULL_DUPLEX_EN(val))
+                               excluded |= SUPPORTED_100baseT_Half;
+                       else
+                               excluded |= SUPPORTED_100baseT_Full;
+               } else {
+                       excluded |= SUPPORTED_100baseT_Full;
+                       excluded |= SUPPORTED_100baseT_Half;
+                       if (BAMBOO_FULL_DUPLEX_EN(val))
+                               excluded |= SUPPORTED_10baseT_Half;
+                       else
+                               excluded |= SUPPORTED_10baseT_Full;
+               }
+       }
+
+       /* Set mac_addr, phy mode and unsupported phy features for each EMAC */
 
        def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, 0);
        emacdata = def->additions;
        memcpy(emacdata->mac_addr, __res.bi_enetaddr, 6);
        emacdata->phy_mode = mode;
+       emacdata->phy_feat_exc = excluded;
 
        def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, 1);
        emacdata = def->additions;
        memcpy(emacdata->mac_addr, __res.bi_enet1addr, 6);
        emacdata->phy_mode = mode;
+       emacdata->phy_feat_exc = excluded;
 }
 
 static int
index 63d7145041486f1a8206d8aafe57899cb26d4857..5c01928264941ad0a227c38e693a4facd7d4cfe8 100644 (file)
@@ -88,7 +88,7 @@
 #define STD_UART_OP(num)                                       \
        { 0, BASE_BAUD, 0, UART##num##_INT,                     \
                (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),        \
-               iomem_base: UART##num##_IO_BASE,                \
+               iomem_base: (void*)UART##num##_IO_BASE,         \
                io_type: SERIAL_IO_MEM},
 
 #define SERIAL_PORT_DFNS       \
index 509e69a095f0a43b2ff4069b7995f121bb76e77f..0fd3442f51310318ac15c1d954766854067b391e 100644 (file)
 #include <syslib/gen550.h>
 #include <syslib/ibm440gp_common.h>
 
-/*
- * This is a horrible kludge, we eventually need to abstract this
- * generic PHY stuff, so the  standard phy mode defines can be
- * easily used from arch code.
- */
-#include "../../../../drivers/net/ibm_emac/ibm_emac_phy.h"
-
 bd_t __res;
 
 static struct ibm44x_clocks clocks __initdata;
index 6d44567f4dd215ad6f2554eff26a2d84fc5ca25d..093b28d27a413dbe778be1b7d4b5384e2b94ff88 100644 (file)
@@ -33,6 +33,7 @@ static struct ocp_func_mal_data ibm405ep_mal0_def = {
        .txde_irq       = 13,           /* TX Descriptor Error IRQ */
        .rxde_irq       = 14,           /* RX Descriptor Error IRQ */
        .serr_irq       = 10,           /* MAL System Error IRQ    */
+       .dcr_base       = DCRN_MAL_BASE /* MAL0_CFG DCR number */
 };
 OCP_SYSFS_MAL_DATA()
 
index dfd7ef3ba5f81138fb960b8086ef81cc8614f78f..e5700469a6829092e643a840c7a8b99cb09c9849 100644 (file)
@@ -46,6 +46,7 @@ static struct ocp_func_mal_data ibm405gp_mal0_def = {
        .txde_irq       = 13,           /* TX Descriptor Error IRQ */
        .rxde_irq       = 14,           /* RX Descriptor Error IRQ */
        .serr_irq       = 10,           /* MAL System Error IRQ    */
+       .dcr_base       = DCRN_MAL_BASE /* MAL0_CFG DCR number */
 };
 OCP_SYSFS_MAL_DATA()
 
index 01c8ccbc7214460fe5b06e1905d5432cb16e1899..cd0d00d8e8ee51fb22e8df9619cf571835a977cc 100644 (file)
@@ -42,6 +42,7 @@ static struct ocp_func_mal_data ibm405gpr_mal0_def = {
        .txde_irq       = 13,           /* TX Descriptor Error IRQ */
        .rxde_irq       = 14,           /* RX Descriptor Error IRQ */
        .serr_irq       = 10,           /* MAL System Error IRQ    */
+       .dcr_base       = DCRN_MAL_BASE /* MAL0_CFG DCR number */
 };
 OCP_SYSFS_MAL_DATA()
 
index 284da01f1ffd64d1582461d72953744cbc8422e0..4712de8ff80fd3b750a7f54b9db95578be418c53 100644 (file)
@@ -53,6 +53,7 @@ static struct ocp_func_mal_data ibm440ep_mal0_def = {
        .txde_irq       = 33,           /* TX Descriptor Error IRQ */
        .rxde_irq       = 34,           /* RX Descriptor Error IRQ */
        .serr_irq       = 32,           /* MAL System Error IRQ    */
+       .dcr_base       = DCRN_MAL_BASE /* MAL0_CFG DCR number */
 };
 OCP_SYSFS_MAL_DATA()
 
index 27615ef8309ccf1230421840e00e7b3a7f3646ae..d926245e8b3ebf013e61b1da0831adea976b3018 100644 (file)
@@ -56,6 +56,7 @@ static struct ocp_func_mal_data ibm440gp_mal0_def = {
        .txde_irq       = 33,           /* TX Descriptor Error IRQ */
        .rxde_irq       = 34,           /* RX Descriptor Error IRQ */
        .serr_irq       = 32,           /* MAL System Error IRQ    */
+       .dcr_base       = DCRN_MAL_BASE /* MAL0_CFG DCR number */
 };
 OCP_SYSFS_MAL_DATA()
 
index 1f38f42835b461e6093e64f2f0f0f1970d857b77..956f45e4ef97287b08d1165d3c956834b24dc6f7 100644 (file)
@@ -84,6 +84,7 @@ static struct ocp_func_mal_data ibm440gx_mal0_def = {
        .txde_irq       = 33,           /* TX Descriptor Error IRQ */
        .rxde_irq       = 34,           /* RX Descriptor Error IRQ */
        .serr_irq       = 32,           /* MAL System Error IRQ    */
+       .dcr_base       = DCRN_MAL_BASE /* MAL0_CFG DCR number */
 };
 OCP_SYSFS_MAL_DATA()
 
index fa3e003a0db94b274b9190d3fcf8c22e9fad336c..feb17e41ef6951ae0c28902249893e4c0dcbe4e9 100644 (file)
@@ -43,6 +43,7 @@ static struct ocp_func_mal_data ibm440sp_mal0_def = {
        .txde_irq       = 34,           /* TX Descriptor Error IRQ */
        .rxde_irq       = 35,           /* RX Descriptor Error IRQ */
        .serr_irq       = 33,           /* MAL System Error IRQ    */
+       .dcr_base       = DCRN_MAL_BASE /* MAL0_CFG DCR number */
 };
 OCP_SYSFS_MAL_DATA()
 
index ecdc5be6ae28208cd718963b9a90478e5bda4a17..a477a78f4902956920bfb8d5985f861992e0229f 100644 (file)
@@ -34,7 +34,7 @@ static struct ocp_func_emac_data ibmnp405h_emac1_def = {
        .zmii_mux       = 1,            /* ZMII input of this EMAC */
        .mal_idx        = 0,            /* MAL device index */
        .mal_rx_chan    = 1,            /* MAL rx channel number */
-       .mal_tx_chan    = 1,            /* MAL tx channel number */
+       .mal_tx_chan    = 2,            /* MAL tx channel number */
        .wol_irq        = 41,           /* WOL interrupt number */
        .mdio_idx       = -1,           /* No shared MDIO */
        .tah_idx        = -1,           /* No TAH */
@@ -46,7 +46,7 @@ static struct ocp_func_emac_data ibmnp405h_emac2_def = {
        .zmii_mux       = 2,            /* ZMII input of this EMAC */
        .mal_idx        = 0,            /* MAL device index */
        .mal_rx_chan    = 2,            /* MAL rx channel number */
-       .mal_tx_chan    = 2,            /* MAL tx channel number */
+       .mal_tx_chan    = 4,            /* MAL tx channel number */
        .wol_irq        = 41,           /* WOL interrupt number */
        .mdio_idx       = -1,           /* No shared MDIO */
        .tah_idx        = -1,           /* No TAH */
@@ -58,7 +58,7 @@ static struct ocp_func_emac_data ibmnp405h_emac3_def = {
        .zmii_mux       = 3,            /* ZMII input of this EMAC */
        .mal_idx        = 0,            /* MAL device index */
        .mal_rx_chan    = 3,            /* MAL rx channel number */
-       .mal_tx_chan    = 3,            /* MAL tx channel number */
+       .mal_tx_chan    = 6,            /* MAL tx channel number */
        .wol_irq        = 41,           /* WOL interrupt number */
        .mdio_idx       = -1,           /* No shared MDIO */
        .tah_idx        = -1,           /* No TAH */
@@ -73,6 +73,7 @@ static struct ocp_func_mal_data ibmnp405h_mal0_def = {
        .txde_irq       = 46,           /* TX Descriptor Error IRQ */
        .rxde_irq       = 47,           /* RX Descriptor Error IRQ */
        .serr_irq       = 45,           /* MAL System Error IRQ    */
+       .dcr_base       = DCRN_MAL_BASE /* MAL0_CFG DCR number */
 };
 OCP_SYSFS_MAL_DATA()
 
index 874d16bab73c073b8c90688b1e68b41aca38054f..d90627b68faa5580516d0419fcac699fc3a5e3c8 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/init.h>
 #include <asm/ocp.h>
+#include <asm/ppc4xx_pic.h>
 #include <platforms/4xx/ibmstb4.h>
 
 static struct ocp_func_iic_data ibmstb4_iic0_def = {
@@ -72,12 +73,51 @@ struct ocp_def core_ocp[] __initdata = {
          .irq          = IDE0_IRQ,
          .pm           = OCP_CPM_NA,
        },
-       { .vendor       = OCP_VENDOR_IBM,
-         .function     = OCP_FUNC_USB,
-         .paddr        = USB0_BASE,
-         .irq          = USB0_IRQ,
-         .pm           = OCP_CPM_NA,
-       },
        { .vendor       = OCP_VENDOR_INVALID,
        }
 };
+
+/* Polarity and triggering settings for internal interrupt sources */
+struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[] __initdata = {
+       { .polarity     = 0x7fffff01,
+         .triggering   = 0x00000000,
+         .ext_irq_mask = 0x0000007e,   /* IRQ0 - IRQ5 */
+       }
+};
+
+static struct resource ohci_usb_resources[] = {
+       [0] = {
+               .start  = USB0_BASE,
+               .end    = USB0_BASE + USB0_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = USB0_IRQ,
+               .end    = USB0_IRQ,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static u64 dma_mask = 0xffffffffULL;
+
+static struct platform_device ohci_usb_device = {
+       .name           = "ppc-soc-ohci",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(ohci_usb_resources),
+       .resource       = ohci_usb_resources,
+       .dev            = {
+               .dma_mask = &dma_mask,
+               .coherent_dma_mask = 0xffffffffULL,
+       }
+};
+
+static struct platform_device *ibmstb4_devs[] __initdata = {
+       &ohci_usb_device,
+};
+
+static int __init
+ibmstb4_platform_add_devices(void)
+{
+       return platform_add_devices(ibmstb4_devs, ARRAY_SIZE(ibmstb4_devs));
+}
+arch_initcall(ibmstb4_platform_add_devices);
index bcb4b1ee71f2677b60375c2272c395f0563734ef..9f21d4c88a3d21a84d8b721b29315bbab49cc2b4 100644 (file)
@@ -73,9 +73,9 @@
 #define OPB0_BASE      0x40000000
 #define GPIO0_BASE     0x40060000
 
+#define USB0_BASE      0x40010000
+#define USB0_SIZE      0xA0
 #define USB0_IRQ       18
-#define USB0_BASE      STB04xxx_MAP_IO_ADDR(0x40010000)
-#define USB0_EXTENT 4096
 
 #define IIC_NUMS 2
 #define UART_NUMS      3
index 95359f748e7b4374fa5a0a8f4d51b950919fe79d..a38e6f9ef858ae78db73688c3a80b52d217303da 100644 (file)
 #include <syslib/ibm440gx_common.h>
 #include <syslib/ibm440sp_common.h>
 
-/*
- * This is a horrible kludge, we eventually need to abstract this
- * generic PHY stuff, so the  standard phy mode defines can be
- * easily used from arch code.
- */
-#include "../../../../drivers/net/ibm_emac/ibm_emac_phy.h"
-
 bd_t __res;
 
 static struct ibm44x_clocks clocks __initdata;
index 09b444c8781638a97d86cd9ded72e64b6d1872ff..bbe7d0766db8acde12b746af50e67c6d6e0f735a 100644 (file)
@@ -55,7 +55,7 @@
 #define STD_UART_OP(num)                                       \
        { 0, BASE_BAUD, 0, UART##num##_INT,                     \
                (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),        \
-               iomem_base: UART##num##_IO_BASE,                \
+               iomem_base: (void*)UART##num##_IO_BASE,         \
                io_type: SERIAL_IO_MEM},
 
 #define SERIAL_PORT_DFNS       \
diff --git a/arch/ppc/platforms/4xx/oak.c b/arch/ppc/platforms/4xx/oak.c
deleted file mode 100644 (file)
index fa25ee1..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- *
- *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: oak.c
- *
- *    Description:
- *      Architecture- / platform-specific boot-time initialization code for
- *      the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original
- *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
- *      <dan@net4x.com>.
- *
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/threads.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/initrd.h>
-#include <linux/irq.h>
-#include <linux/seq_file.h>
-
-#include <asm/board.h>
-#include <asm/machdep.h>
-#include <asm/page.h>
-#include <asm/bootinfo.h>
-#include <asm/ppc4xx_pic.h>
-#include <asm/time.h>
-
-#include "oak.h"
-
-/* Function Prototypes */
-
-extern void abort(void);
-
-/* Global Variables */
-
-unsigned char __res[sizeof(bd_t)];
-
-
-/*
- * void __init oak_init()
- *
- * Description:
- *   This routine...
- *
- * Input(s):
- *   r3 - Optional pointer to a board information structure.
- *   r4 - Optional pointer to the physical starting address of the init RAM
- *        disk.
- *   r5 - Optional pointer to the physical ending address of the init RAM
- *        disk.
- *   r6 - Optional pointer to the physical starting address of any kernel
- *        command-line parameters.
- *   r7 - Optional pointer to the physical ending address of any kernel
- *        command-line parameters.
- *
- * Output(s):
- *   N/A
- *
- * Returns:
- *   N/A
- *
- */
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
-             unsigned long r6, unsigned long r7)
-{
-       parse_bootinfo(find_bootinfo());
-
-       /*
-        * If we were passed in a board information, copy it into the
-        * residual data area.
-        */
-       if (r3) {
-               memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t));
-       }
-
-#if defined(CONFIG_BLK_DEV_INITRD)
-       /*
-        * If the init RAM disk has been configured in, and there's a valid
-        * starting address for it, set it up.
-        */
-       if (r4) {
-               initrd_start = r4 + KERNELBASE;
-               initrd_end = r5 + KERNELBASE;
-       }
-#endif /* CONFIG_BLK_DEV_INITRD */
-
-       /* Copy the kernel command line arguments to a safe place. */
-
-       if (r6) {
-               *(char *)(r7 + KERNELBASE) = 0;
-               strcpy(cmd_line, (char *)(r6 + KERNELBASE));
-       }
-
-       /* Initialize machine-dependency vectors */
-
-       ppc_md.setup_arch               = oak_setup_arch;
-       ppc_md.show_percpuinfo          = oak_show_percpuinfo;
-       ppc_md.irq_canonicalize         = NULL;
-       ppc_md.init_IRQ                 = ppc4xx_pic_init;
-       ppc_md.get_irq                  = NULL;  /* Set in ppc4xx_pic_init() */
-       ppc_md.init                     = NULL;
-
-       ppc_md.restart                  = oak_restart;
-       ppc_md.power_off                = oak_power_off;
-       ppc_md.halt                     = oak_halt;
-
-       ppc_md.time_init                = oak_time_init;
-       ppc_md.set_rtc_time             = oak_set_rtc_time;
-       ppc_md.get_rtc_time             = oak_get_rtc_time;
-       ppc_md.calibrate_decr           = oak_calibrate_decr;
-}
-
-/*
- * Document me.
- */
-void __init
-oak_setup_arch(void)
-{
-       /* XXX - Implement me */
-}
-
-/*
- * int oak_show_percpuinfo()
- *
- * Description:
- *   This routine pretty-prints the platform's internal CPU and bus clock
- *   frequencies into the buffer for usage in /proc/cpuinfo.
- *
- * Input(s):
- *  *buffer - Buffer into which CPU and bus clock frequencies are to be
- *            printed.
- *
- * Output(s):
- *  *buffer - Buffer with the CPU and bus clock frequencies.
- *
- * Returns:
- *   The number of bytes copied into 'buffer' if OK, otherwise zero or less
- *   on error.
- */
-int
-oak_show_percpuinfo(struct seq_file *m, int i)
-{
-       bd_t *bp = (bd_t *)__res;
-
-       seq_printf(m, "clock\t\t: %dMHz\n"
-                  "bus clock\t\t: %dMHz\n",
-                  bp->bi_intfreq / 1000000,
-                  bp->bi_busfreq / 1000000);
-
-       return 0;
-}
-
-/*
- * Document me.
- */
-void
-oak_restart(char *cmd)
-{
-       abort();
-}
-
-/*
- * Document me.
- */
-void
-oak_power_off(void)
-{
-       oak_restart(NULL);
-}
-
-/*
- * Document me.
- */
-void
-oak_halt(void)
-{
-       oak_restart(NULL);
-}
-
-/*
- * Document me.
- */
-long __init
-oak_time_init(void)
-{
-       /* XXX - Implement me */
-       return 0;
-}
-
-/*
- * Document me.
- */
-int __init
-oak_set_rtc_time(unsigned long time)
-{
-       /* XXX - Implement me */
-
-       return (0);
-}
-
-/*
- * Document me.
- */
-unsigned long __init
-oak_get_rtc_time(void)
-{
-       /* XXX - Implement me */
-
-       return (0);
-}
-
-/*
- * void __init oak_calibrate_decr()
- *
- * Description:
- *   This routine retrieves the internal processor frequency from the board
- *   information structure, sets up the kernel timer decrementer based on
- *   that value, enables the 403 programmable interval timer (PIT) and sets
- *   it up for auto-reload.
- *
- * Input(s):
- *   N/A
- *
- * Output(s):
- *   N/A
- *
- * Returns:
- *   N/A
- *
- */
-void __init
-oak_calibrate_decr(void)
-{
-       unsigned int freq;
-       bd_t *bip = (bd_t *)__res;
-
-       freq = bip->bi_intfreq;
-
-       decrementer_count = freq / HZ;
-       count_period_num = 1;
-       count_period_den = freq;
-
-       /* Enable the PIT and set auto-reload of its value */
-
-       mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
-
-       /* Clear any pending timer interrupts */
-
-       mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS);
-}
diff --git a/arch/ppc/platforms/4xx/oak.h b/arch/ppc/platforms/4xx/oak.h
deleted file mode 100644 (file)
index 1b86a4c..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- *
- *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: oak.h
- *
- *    Description:
- *     Macros, definitions, and data structures specific to the IBM PowerPC
- *      403G{A,B,C,CX} "Oak" evaluation board. Anything specific to the pro-
- *      cessor itself is defined elsewhere.
- *
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_OAK_H__
-#define __ASM_OAK_H__
-
-/* We have an IBM 403G{A,B,C,CX} core */
-#include <asm/ibm403.h>
-
-#define _IO_BASE       0
-#define _ISA_MEM_BASE  0
-#define PCI_DRAM_OFFSET        0
-
-/* Memory map for the "Oak" evaluation board */
-
-#define        PPC403SPU_IO_BASE       0x40000000      /* 403 On-chip serial port */
-#define        PPC403SPU_IO_SIZE       0x00000008
-#define        OAKSERIAL_IO_BASE       0x7E000000      /* NS16550DV serial port */
-#define        OAKSERIAL_IO_SIZE       0x00000008
-#define        OAKNET_IO_BASE          0xF4000000      /* NS83902AV Ethernet */
-#define        OAKNET_IO_SIZE          0x00000040
-#define        OAKPROM_IO_BASE         0xFFFE0000      /* AMD 29F010 Flash ROM */
-#define        OAKPROM_IO_SIZE         0x00020000
-
-
-/* Interrupt assignments fixed by the hardware implementation */
-
-/* This is annoying kbuild-2.4 problem. -- Tom */
-
-#define        PPC403SPU_RX_INT        4       /* AIC_INT4 */
-#define        PPC403SPU_TX_INT        5       /* AIC_INT5 */
-#define        OAKNET_INT              27      /* AIC_INT27 */
-#define        OAKSERIAL_INT           28      /* AIC_INT28 */
-
-#ifndef __ASSEMBLY__
-/*
- * Data structure defining board information maintained by the boot
- * ROM on IBM's "Oak" evaluation board. An effort has been made to
- * keep the field names consistent with the 8xx 'bd_t' board info
- * structures.
- */
-
-typedef struct board_info {
-       unsigned char    bi_s_version[4];       /* Version of this structure */
-       unsigned char    bi_r_version[30];      /* Version of the IBM ROM */
-       unsigned int     bi_memsize;            /* DRAM installed, in bytes */
-       unsigned char    bi_enetaddr[6];        /* Ethernet MAC address */
-       unsigned int     bi_intfreq;            /* Processor speed, in Hz */
-       unsigned int     bi_busfreq;            /* Bus speed, in Hz */
-} bd_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern void             oak_init(unsigned long r3,
-                                 unsigned long ird_start,
-                                 unsigned long ird_end,
-                                 unsigned long cline_start,
-                                 unsigned long cline_end);
-extern void             oak_setup_arch(void);
-extern int              oak_setup_residual(char *buffer);
-extern void             oak_init_IRQ(void);
-extern int              oak_get_irq(struct pt_regs *regs);
-extern void             oak_restart(char *cmd);
-extern void             oak_power_off(void);
-extern void             oak_halt(void);
-extern void             oak_time_init(void);
-extern int              oak_set_rtc_time(unsigned long now);
-extern unsigned long    oak_get_rtc_time(void);
-extern void             oak_calibrate_decr(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-/* Some 4xx parts use a different timebase frequency from the internal clock.
-*/
-#define bi_tbfreq bi_intfreq
-
-#define PPC4xx_MACHINE_NAME    "IBM Oak"
-
-#endif /* !__ASSEMBLY__ */
-#endif /* __ASM_OAK_H__ */
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/oak_setup.h b/arch/ppc/platforms/4xx/oak_setup.h
deleted file mode 100644 (file)
index 8648bd0..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- *
- *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: oak_setup.h
- *
- *    Description:
- *      Architecture- / platform-specific boot-time initialization code for
- *      the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original
- *      code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
- *      <dan@netx4.com>.
- *
- */
-
-#ifndef        __OAK_SETUP_H__
-#define        __OAK_SETUP_H__
-
-#include <asm/ptrace.h>
-#include <asm/board.h>
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern unsigned char    __res[sizeof(bd_t)];
-
-extern void             oak_init(unsigned long r3,
-                                 unsigned long ird_start,
-                                 unsigned long ird_end,
-                                 unsigned long cline_start,
-                                 unsigned long cline_end);
-extern void             oak_setup_arch(void);
-extern int              oak_setup_residual(char *buffer);
-extern void             oak_init_IRQ(void);
-extern int              oak_get_irq(struct pt_regs *regs);
-extern void             oak_restart(char *cmd);
-extern void             oak_power_off(void);
-extern void             oak_halt(void);
-extern void             oak_time_init(void);
-extern int              oak_set_rtc_time(unsigned long now);
-extern unsigned long    oak_get_rtc_time(void);
-extern void             oak_calibrate_decr(void);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __OAK_SETUP_H__ */
index 8fc34a3447694afc2ebb95c3f5d60357c29fbb7a..80028df1b445b422ece4a9edfc02186b8aced50e 100644 (file)
 #include <syslib/gen550.h>
 #include <syslib/ibm440gx_common.h>
 
-/*
- * This is a horrible kludge, we eventually need to abstract this
- * generic PHY stuff, so the  standard phy mode defines can be
- * easily used from arch code.
- */
-#include "../../../../drivers/net/ibm_emac/ibm_emac_phy.h"
-
 bd_t __res;
 
 static struct ibm44x_clocks clocks __initdata;
index 2f5e410afbc557534ed978a2d51f29595aafc35c..bee8b4ac8afd221ba6c2a1b566249cb934505897 100644 (file)
 #include <linux/ioport.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
+#include <asm/ppc4xx_pic.h>
+
+/*
+ * Define external IRQ senses and polarities.
+ */
+unsigned char ppc4xx_uic_ext_irq_cfg[] __initdata = {
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* Ext Int 0 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* Ext Int 1 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* Ext Int 2 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* Ext Int 3 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* Ext Int 4 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* Ext Int 5 */
+};
 
 static struct resource smc91x_resources[] = {
        [0] = {
index ddd04d4c1ea9ecb0b95413d6e51fc01b0856fe38..b38a851a64ecc2250a4b1dca23377083e703aeb4 100644 (file)
@@ -62,9 +62,29 @@ extern unsigned long total_memory;   /* in mm/init */
 unsigned char __res[sizeof (bd_t)];
 
 #ifdef CONFIG_PCI
-#error "PCI is not supported"
-/* NEED mpc83xx_map_irq & mpc83xx_exclude_device
-   see platforms/85xx/mpc85xx_ads_common.c */
+int
+mpc83xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+       static char pci_irq_table[][4] =
+           /*
+            *      PCI IDSEL/INTPIN->INTLINE
+            *       A      B      C      D
+            */
+       {
+               {PIRQA, PIRQB,  PIRQC,  PIRQD}, /* idsel 0x11 */
+               {PIRQC, PIRQD,  PIRQA,  PIRQB}, /* idsel 0x12 */
+               {PIRQD, PIRQA,  PIRQB,  PIRQC}  /* idsel 0x13 */
+       };
+
+       const long min_idsel = 0x11, max_idsel = 0x13, irqs_per_slot = 4;
+       return PCI_IRQ_TABLE_LOOKUP;
+}
+
+int
+mpc83xx_exclude_device(u_char bus, u_char devfn)
+{
+       return PCIBIOS_SUCCESSFUL;
+}
 #endif /* CONFIG_PCI */
 
 /* ************************************************************************
@@ -88,7 +108,7 @@ mpc834x_sys_setup_arch(void)
 
 #ifdef CONFIG_PCI
        /* setup PCI host bridges */
-       mpc83xx_sys_setup_hose();
+       mpc83xx_setup_hose();
 #endif
        mpc83xx_early_serial_map();
 
@@ -175,10 +195,17 @@ mpc834x_sys_init_IRQ(void)
                IRQ_SENSE_LEVEL,        /* EXT 1 */
                IRQ_SENSE_LEVEL,        /* EXT 2 */
                0,                      /* EXT 3 */
+#ifdef CONFIG_PCI
+               IRQ_SENSE_LEVEL,        /* EXT 4 */
+               IRQ_SENSE_LEVEL,        /* EXT 5 */
+               IRQ_SENSE_LEVEL,        /* EXT 6 */
+               IRQ_SENSE_LEVEL,        /* EXT 7 */
+#else
                0,                      /* EXT 4 */
                0,                      /* EXT 5 */
                0,                      /* EXT 6 */
                0,                      /* EXT 7 */
+#endif
        };
 
        ipic_init(binfo->bi_immr_base + 0x00700, 0, MPC83xx_IPIC_IRQ_OFFSET, senses, 8);
index a2f6e49d71512946ca5e89e2b7d7ca80fec0f8de..1584cd77a9ef35ecfccba2dd1bd891ec02b6abb9 100644 (file)
@@ -26,7 +26,7 @@
 #define VIRT_IMMRBAR           ((uint)0xfe000000)
 
 #define BCSR_PHYS_ADDR         ((uint)0xf8000000)
-#define BCSR_SIZE              ((uint)(32 * 1024))
+#define BCSR_SIZE              ((uint)(128 * 1024))
 
 #define BCSR_MISC_REG2_OFF     0x07
 #define BCSR_MISC_REG2_PORESET 0x01
 #define BCSR_MISC_REG3_OFF     0x08
 #define BCSR_MISC_REG3_CNFLOCK 0x80
 
-#ifdef CONFIG_PCI
-/* PCI interrupt controller */
-#define PIRQA        MPC83xx_IRQ_IRQ4
-#define PIRQB        MPC83xx_IRQ_IRQ5
-#define PIRQC        MPC83xx_IRQ_IRQ6
-#define PIRQD        MPC83xx_IRQ_IRQ7
-
-#define MPC834x_SYS_PCI1_LOWER_IO        0x00000000
-#define MPC834x_SYS_PCI1_UPPER_IO        0x00ffffff
-
-#define MPC834x_SYS_PCI1_LOWER_MEM       0x80000000
-#define MPC834x_SYS_PCI1_UPPER_MEM       0x9fffffff
-
-#define MPC834x_SYS_PCI1_IO_BASE         0xe2000000
-#define MPC834x_SYS_PCI1_MEM_OFFSET      0x00000000
-
-#define MPC834x_SYS_PCI1_IO_SIZE         0x01000000
-#endif /* CONFIG_PCI */
+#define PIRQA  MPC83xx_IRQ_EXT4
+#define PIRQB  MPC83xx_IRQ_EXT5
+#define PIRQC  MPC83xx_IRQ_EXT6
+#define PIRQD  MPC83xx_IRQ_EXT7
+
+#define MPC83xx_PCI1_LOWER_IO  0x00000000
+#define MPC83xx_PCI1_UPPER_IO  0x00ffffff
+#define MPC83xx_PCI1_LOWER_MEM 0x80000000
+#define MPC83xx_PCI1_UPPER_MEM 0x9fffffff
+#define MPC83xx_PCI1_IO_BASE   0xe2000000
+#define MPC83xx_PCI1_MEM_OFFSET        0x00000000
+#define MPC83xx_PCI1_IO_SIZE   0x01000000
+
+#define MPC83xx_PCI2_LOWER_IO  0x00000000
+#define MPC83xx_PCI2_UPPER_IO  0x00ffffff
+#define MPC83xx_PCI2_LOWER_MEM 0xa0000000
+#define MPC83xx_PCI2_UPPER_MEM 0xbfffffff
+#define MPC83xx_PCI2_IO_BASE   0xe3000000
+#define MPC83xx_PCI2_MEM_OFFSET        0x00000000
+#define MPC83xx_PCI2_IO_SIZE   0x01000000
 
 #endif                /* __MACH_MPC83XX_SYS_H__ */
index 5488a053f4155f2ab733ab8ce259668374341379..ff7452e5d8e511ef79f6e97a8eb38bc9b301ce6c 100644 (file)
@@ -21,22 +21,17 @@ obj-$(CONFIG_CPU_FREQ_PMAC) += pmac_cpufreq.o
 endif
 obj-$(CONFIG_PMAC_BACKLIGHT)   += pmac_backlight.o
 obj-$(CONFIG_PREP_RESIDUAL)    += residual.o
-obj-$(CONFIG_ADIR)             += adir_setup.o adir_pic.o adir_pci.o
 obj-$(CONFIG_PQ2ADS)           += pq2ads.o
 obj-$(CONFIG_TQM8260)          += tqm8260_setup.o
 obj-$(CONFIG_CPCI690)          += cpci690.o
 obj-$(CONFIG_EV64260)          += ev64260.o
 obj-$(CONFIG_CHESTNUT)         += chestnut.o
 obj-$(CONFIG_GEMINI)           += gemini_pci.o gemini_setup.o gemini_prom.o
-obj-$(CONFIG_K2)               += k2.o
 obj-$(CONFIG_LOPEC)            += lopec.o
 obj-$(CONFIG_KATANA)           += katana.o
 obj-$(CONFIG_HDPU)             += hdpu.o
-obj-$(CONFIG_MCPN765)          += mcpn765.o
-obj-$(CONFIG_MENF1)            += menf1_setup.o menf1_pci.o
 obj-$(CONFIG_MVME5100)         += mvme5100.o
 obj-$(CONFIG_PAL4)             += pal4_setup.o pal4_pci.o
-obj-$(CONFIG_PCORE)            += pcore.o
 obj-$(CONFIG_POWERPMC250)      += powerpmc250.o
 obj-$(CONFIG_PPLUS)            += pplus.o
 obj-$(CONFIG_PRPMC750)         += prpmc750.o
@@ -46,6 +41,7 @@ obj-$(CONFIG_SANDPOINT)               += sandpoint.o
 obj-$(CONFIG_SBC82xx)          += sbc82xx.o
 obj-$(CONFIG_SPRUCE)           += spruce.o
 obj-$(CONFIG_LITE5200)         += lite5200.o
+obj-$(CONFIG_EV64360)          += ev64360.o
 
 ifeq ($(CONFIG_SMP),y)
 obj-$(CONFIG_PPC_PMAC)         += pmac_smp.o
diff --git a/arch/ppc/platforms/adir.h b/arch/ppc/platforms/adir.h
deleted file mode 100644 (file)
index 13a748b..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * arch/ppc/platforms/adir.h
- *
- * Definitions for SBS Adirondack board support
- *
- * By Michael Sokolov <msokolov@ivan.Harhan.ORG>
- */
-
-#ifndef __PPC_PLATFORMS_ADIR_H
-#define __PPC_PLATFORMS_ADIR_H
-
-/*
- * SBS Adirondack definitions
- */
-
-/* PPC physical address space layout. We use the one set up by the firmware. */
-#define        ADIR_PCI32_MEM_BASE     0x80000000
-#define        ADIR_PCI32_MEM_SIZE     0x20000000
-#define        ADIR_PCI64_MEM_BASE     0xA0000000
-#define        ADIR_PCI64_MEM_SIZE     0x20000000
-#define        ADIR_PCI32_IO_BASE      0xC0000000
-#define        ADIR_PCI32_IO_SIZE      0x10000000
-#define        ADIR_PCI64_IO_BASE      0xD0000000
-#define        ADIR_PCI64_IO_SIZE      0x10000000
-#define        ADIR_PCI64_PHB          0xFF400000
-#define        ADIR_PCI32_PHB          0xFF500000
-
-#define ADIR_PCI64_CONFIG_ADDR (ADIR_PCI64_PHB + 0x000f8000)
-#define ADIR_PCI64_CONFIG_DATA (ADIR_PCI64_PHB + 0x000f8010)
-
-#define ADIR_PCI32_CONFIG_ADDR (ADIR_PCI32_PHB + 0x000f8000)
-#define ADIR_PCI32_CONFIG_DATA (ADIR_PCI32_PHB + 0x000f8010)
-
-/* System memory as seen from PCI */
-#define ADIR_PCI_SYS_MEM_BASE  0x80000000
-
-/* Static virtual mapping of PCI I/O */
-#define        ADIR_PCI32_VIRT_IO_BASE 0xFE000000
-#define        ADIR_PCI32_VIRT_IO_SIZE 0x01000000
-#define        ADIR_PCI64_VIRT_IO_BASE 0xFF000000
-#define        ADIR_PCI64_VIRT_IO_SIZE 0x01000000
-
-/* Registers */
-#define        ADIR_NVRAM_RTC_ADDR     0x74
-#define        ADIR_NVRAM_RTC_DATA     0x75
-
-#define        ADIR_BOARD_ID_REG       (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF0)
-#define        ADIR_CPLD1REV_REG       (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF1)
-#define        ADIR_CPLD2REV_REG       (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF2)
-#define        ADIR_FLASHCTL_REG       (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF3)
-#define        ADIR_CPC710_STAT_REG    (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF4)
-#define        ADIR_CLOCK_REG          (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF5)
-#define        ADIR_GPIO_REG           (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF8)
-#define        ADIR_MISC_REG           (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF9)
-#define        ADIR_LED_REG            (ADIR_PCI32_VIRT_IO_BASE + 0x08FFFA)
-
-#define        ADIR_CLOCK_REG_PD       0x10
-#define        ADIR_CLOCK_REG_SPREAD   0x08
-#define        ADIR_CLOCK_REG_SEL133   0x04
-#define        ADIR_CLOCK_REG_SEL1     0x02
-#define        ADIR_CLOCK_REG_SEL0     0x01
-
-#define        ADIR_PROCA_INT_MASK     (ADIR_PCI32_VIRT_IO_BASE + 0x0EFFF0)
-#define        ADIR_PROCB_INT_MASK     (ADIR_PCI32_VIRT_IO_BASE + 0x0EFFF2)
-#define        ADIR_PROCA_INT_STAT     (ADIR_PCI32_VIRT_IO_BASE + 0x0EFFF4)
-#define        ADIR_PROCB_INT_STAT     (ADIR_PCI32_VIRT_IO_BASE + 0x0EFFF6)
-
-/* Linux IRQ numbers */
-#define        ADIR_IRQ_NONE           -1
-#define        ADIR_IRQ_SERIAL2        3
-#define        ADIR_IRQ_SERIAL1        4
-#define        ADIR_IRQ_FDC            6
-#define        ADIR_IRQ_PARALLEL       7
-#define        ADIR_IRQ_VIA_AUDIO      10
-#define        ADIR_IRQ_VIA_USB        11
-#define        ADIR_IRQ_IDE0           14
-#define        ADIR_IRQ_IDE1           15
-#define        ADIR_IRQ_PCI0_INTA      16
-#define        ADIR_IRQ_PCI0_INTB      17
-#define        ADIR_IRQ_PCI0_INTC      18
-#define        ADIR_IRQ_PCI0_INTD      19
-#define        ADIR_IRQ_PCI1_INTA      20
-#define        ADIR_IRQ_PCI1_INTB      21
-#define        ADIR_IRQ_PCI1_INTC      22
-#define        ADIR_IRQ_PCI1_INTD      23
-#define        ADIR_IRQ_MBSCSI         24      /* motherboard SCSI */
-#define        ADIR_IRQ_MBETH1         25      /* motherboard Ethernet 1 */
-#define        ADIR_IRQ_MBETH0         26      /* motherboard Ethernet 0 */
-#define        ADIR_IRQ_CPC710_INT1    27
-#define        ADIR_IRQ_CPC710_INT2    28
-#define        ADIR_IRQ_VT82C686_NMI   29
-#define        ADIR_IRQ_VT82C686_INTR  30
-#define        ADIR_IRQ_INTERPROC      31
-
-#endif /* __PPC_PLATFORMS_ADIR_H */
diff --git a/arch/ppc/platforms/adir_pci.c b/arch/ppc/platforms/adir_pci.c
deleted file mode 100644 (file)
index f94ac53..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * arch/ppc/platforms/adir_pci.c
- *
- * PCI support for SBS Adirondack
- *
- * By Michael Sokolov <msokolov@ivan.Harhan.ORG>
- * based on the K2 version by Matt Porter <mporter@mvista.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
-
-#include <syslib/cpc710.h>
-#include "adir.h"
-
-#undef DEBUG
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif /* DEBUG */
-
-static inline int __init
-adir_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-#define        PCIIRQ(a,b,c,d) {ADIR_IRQ_##a,ADIR_IRQ_##b,ADIR_IRQ_##c,ADIR_IRQ_##d},
-       struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
-       /*
-        * The three PCI devices on the motherboard have dedicated lines to the
-        * CPLD interrupt controller, bypassing the standard PCI INTA-D and the
-        * PC interrupt controller. All other PCI devices (slots) have usual
-        * staggered INTA-D lines, resulting in 8 lines total (PCI0 INTA-D and
-        * PCI1 INTA-D). All 8 go to the CPLD interrupt controller. PCI0 INTA-D
-        * also go to the south bridge, so we have the option of taking them
-        * via the CPLD interrupt controller or via the south bridge 8259
-        * 8258 thingy. PCI1 INTA-D can only be taken via the CPLD interrupt
-        * controller. We take all PCI interrupts via the CPLD interrupt
-        * controller as recommended by SBS.
-        *
-        * We also have some monkey business with the PCI devices within the
-        * VT82C686B south bridge itself. This chip actually has 7 functions on
-        * its IDSEL. Function 0 is the actual south bridge, function 1 is IDE,
-        * and function 4 is some special stuff. The other 4 functions are just
-        * regular PCI devices bundled in the chip. 2 and 3 are USB UHCIs and 5
-        * and 6 are audio (not supported on the Adirondack).
-        *
-        * This is where the monkey business begins. PCI devices are supposed
-        * to signal normal PCI interrupts. But the 4 functions in question are
-        * located in the south bridge chip, which is designed with the
-        * assumption that it will be fielding PCI INTA-D interrupts rather
-        * than generating them. Here's what it does. Each of the functions in
-        * question routes its interrupt to one of the IRQs on the 8259 thingy.
-        * Which one? It looks at the Interrupt Line register in the PCI config
-        * space, even though the PCI spec says it's for BIOS/OS interaction
-        * only.
-        *
-        * How do we deal with this? We take these interrupts via 8259 IRQs as
-        * we have to. We return the desired IRQ numbers from this routine when
-        * called for the functions in question. The PCI scan code will then
-        * stick our return value into the Interrupt Line register in the PCI
-        * config space, and the interrupt will actually go there. We identify
-        * these functions within the south bridge IDSEL by their interrupt pin
-        * numbers, as the VT82C686B has 04 in the Interrupt Pin register for
-        * USB and 03 for audio.
-        */
-       if (!hose->index) {
-               static char pci_irq_table[][4] =
-               /*
-                *             PCI IDSEL/INTPIN->INTLINE
-                *             A          B          C          D
-                */
-               {
-    /* south bridge */ PCIIRQ(IDE0,      NONE,      VIA_AUDIO, VIA_USB)
-    /* Ethernet 0 */   PCIIRQ(MBETH0,    MBETH0,    MBETH0,    MBETH0)
-    /* PCI0 slot 1 */  PCIIRQ(PCI0_INTB, PCI0_INTC, PCI0_INTD, PCI0_INTA)
-    /* PCI0 slot 2 */  PCIIRQ(PCI0_INTC, PCI0_INTD, PCI0_INTA, PCI0_INTB)
-    /* PCI0 slot 3 */  PCIIRQ(PCI0_INTD, PCI0_INTA, PCI0_INTB, PCI0_INTC)
-               };
-               const long min_idsel = 3, max_idsel = 7, irqs_per_slot = 4;
-               return PCI_IRQ_TABLE_LOOKUP;
-       } else {
-               static char pci_irq_table[][4] =
-               /*
-                *             PCI IDSEL/INTPIN->INTLINE
-                *             A          B          C          D
-                */
-               {
-    /* Ethernet 1 */   PCIIRQ(MBETH1,    MBETH1,    MBETH1,    MBETH1)
-    /* SCSI */         PCIIRQ(MBSCSI,    MBSCSI,    MBSCSI,    MBSCSI)
-    /* PCI1 slot 1 */  PCIIRQ(PCI1_INTB, PCI1_INTC, PCI1_INTD, PCI1_INTA)
-    /* PCI1 slot 2 */  PCIIRQ(PCI1_INTC, PCI1_INTD, PCI1_INTA, PCI1_INTB)
-    /* PCI1 slot 3 */  PCIIRQ(PCI1_INTD, PCI1_INTA, PCI1_INTB, PCI1_INTC)
-               };
-               const long min_idsel = 3, max_idsel = 7, irqs_per_slot = 4;
-               return PCI_IRQ_TABLE_LOOKUP;
-       }
-#undef PCIIRQ
-}
-
-static void
-adir_pcibios_fixup_resources(struct pci_dev *dev)
-{
-       int i;
-
-       if ((dev->vendor == PCI_VENDOR_ID_IBM) &&
-                       (dev->device == PCI_DEVICE_ID_IBM_CPC710_PCI64))
-       {
-               DBG("Fixup CPC710 resources\n");
-               for (i=0; i<DEVICE_COUNT_RESOURCE; i++)
-               {
-                       dev->resource[i].start = 0;
-                       dev->resource[i].end = 0;
-               }
-       }
-}
-
-/*
- * CPC710 DD3 has an errata causing it to hang the system if a type 0 config
- * cycle is attempted on its PCI32 interface with a device number > 21.
- * CPC710's PCI bridges map device numbers 1 through 21 to AD11 through AD31.
- * Per the PCI spec it MUST accept all other device numbers and do nothing, and
- * software MUST scan all device numbers without assuming how IDSELs are
- * mapped. However, as the CPC710 DD3's errata causes such correct scanning
- * procedure to hang the system, we have no choice but to introduce this hack
- * of knowingly avoiding device numbers > 21 on PCI0,
- */
-static int
-adir_exclude_device(u_char bus, u_char devfn)
-{
-       if ((bus == 0) && (PCI_SLOT(devfn) > 21))
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       else
-               return PCIBIOS_SUCCESSFUL;
-}
-
-void adir_find_bridges(void)
-{
-       struct pci_controller *hose_a, *hose_b;
-
-       /* Setup PCI32 hose */
-       hose_a = pcibios_alloc_controller();
-       if (!hose_a)
-               return;
-
-       hose_a->first_busno = 0;
-       hose_a->last_busno = 0xff;
-       hose_a->pci_mem_offset = ADIR_PCI32_MEM_BASE;
-       hose_a->io_space.start = 0;
-       hose_a->io_space.end = ADIR_PCI32_VIRT_IO_SIZE - 1;
-       hose_a->mem_space.start = 0;
-       hose_a->mem_space.end = ADIR_PCI32_MEM_SIZE - 1;
-       hose_a->io_resource.start = 0;
-       hose_a->io_resource.end = ADIR_PCI32_VIRT_IO_SIZE - 1;
-       hose_a->io_resource.flags = IORESOURCE_IO;
-       hose_a->mem_resources[0].start = ADIR_PCI32_MEM_BASE;
-       hose_a->mem_resources[0].end = ADIR_PCI32_MEM_BASE +
-                                       ADIR_PCI32_MEM_SIZE - 1;
-       hose_a->mem_resources[0].flags = IORESOURCE_MEM;
-       hose_a->io_base_phys = ADIR_PCI32_IO_BASE;
-       hose_a->io_base_virt = (void *) ADIR_PCI32_VIRT_IO_BASE;
-
-       ppc_md.pci_exclude_device = adir_exclude_device;
-       setup_indirect_pci(hose_a, ADIR_PCI32_CONFIG_ADDR,
-                          ADIR_PCI32_CONFIG_DATA);
-
-       /* Initialize PCI32 bus registers */
-       early_write_config_byte(hose_a,
-                       hose_a->first_busno,
-                       PCI_DEVFN(0, 0),
-                       CPC710_BUS_NUMBER,
-                       hose_a->first_busno);
-       early_write_config_byte(hose_a,
-                       hose_a->first_busno,
-                       PCI_DEVFN(0, 0),
-                       CPC710_SUB_BUS_NUMBER,
-                       hose_a->last_busno);
-
-       hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
-
-       /* Write out correct max subordinate bus number for hose A */
-       early_write_config_byte(hose_a,
-                       hose_a->first_busno,
-                       PCI_DEVFN(0, 0),
-                       CPC710_SUB_BUS_NUMBER,
-                       hose_a->last_busno);
-
-       /* Setup PCI64 hose */
-       hose_b = pcibios_alloc_controller();
-       if (!hose_b)
-               return;
-
-       hose_b->first_busno = hose_a->last_busno + 1;
-       hose_b->last_busno = 0xff;
-       hose_b->pci_mem_offset = ADIR_PCI64_MEM_BASE;
-       hose_b->io_space.start = 0;
-       hose_b->io_space.end = ADIR_PCI64_VIRT_IO_SIZE - 1;
-       hose_b->mem_space.start = 0;
-       hose_b->mem_space.end = ADIR_PCI64_MEM_SIZE - 1;
-       hose_b->io_resource.start = 0;
-       hose_b->io_resource.end = ADIR_PCI64_VIRT_IO_SIZE - 1;
-       hose_b->io_resource.flags = IORESOURCE_IO;
-       hose_b->mem_resources[0].start = ADIR_PCI64_MEM_BASE;
-       hose_b->mem_resources[0].end = ADIR_PCI64_MEM_BASE +
-                                       ADIR_PCI64_MEM_SIZE - 1;
-       hose_b->mem_resources[0].flags = IORESOURCE_MEM;
-       hose_b->io_base_phys = ADIR_PCI64_IO_BASE;
-       hose_b->io_base_virt = (void *) ADIR_PCI64_VIRT_IO_BASE;
-
-       setup_indirect_pci(hose_b, ADIR_PCI64_CONFIG_ADDR,
-                          ADIR_PCI64_CONFIG_DATA);
-
-       /* Initialize PCI64 bus registers */
-       early_write_config_byte(hose_b,
-                       0,
-                       PCI_DEVFN(0, 0),
-                       CPC710_SUB_BUS_NUMBER,
-                       0xff);
-
-       early_write_config_byte(hose_b,
-                       0,
-                       PCI_DEVFN(0, 0),
-                       CPC710_BUS_NUMBER,
-                       hose_b->first_busno);
-
-       hose_b->last_busno = pciauto_bus_scan(hose_b,
-                       hose_b->first_busno);
-
-       /* Write out correct max subordinate bus number for hose B */
-       early_write_config_byte(hose_b,
-                       hose_b->first_busno,
-                       PCI_DEVFN(0, 0),
-                       CPC710_SUB_BUS_NUMBER,
-                       hose_b->last_busno);
-
-       ppc_md.pcibios_fixup = NULL;
-       ppc_md.pcibios_fixup_resources = adir_pcibios_fixup_resources;
-       ppc_md.pci_swizzle = common_swizzle;
-       ppc_md.pci_map_irq = adir_map_irq;
-}
diff --git a/arch/ppc/platforms/adir_pic.c b/arch/ppc/platforms/adir_pic.c
deleted file mode 100644 (file)
index 9947cba..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * arch/ppc/platforms/adir_pic.c
- *
- * Interrupt controller support for SBS Adirondack
- *
- * By Michael Sokolov <msokolov@ivan.Harhan.ORG>
- * based on the K2 and SCM versions by Matt Porter <mporter@mvista.com>
- */
-
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-
-#include <asm/io.h>
-#include <asm/i8259.h>
-#include "adir.h"
-
-static void adir_onboard_pic_enable(unsigned int irq);
-static void adir_onboard_pic_disable(unsigned int irq);
-
-__init static void
-adir_onboard_pic_init(void)
-{
-       volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK;
-
-       /* Disable all Adirondack onboard interrupts */
-       out_be16(maskreg, 0xFFFF);
-}
-
-static int
-adir_onboard_pic_get_irq(void)
-{
-       volatile u_short *statreg = (volatile u_short *) ADIR_PROCA_INT_STAT;
-       int irq;
-       u_short int_status, int_test;
-
-       int_status = in_be16(statreg);
-       for (irq = 0, int_test = 1; irq < 16; irq++, int_test <<= 1) {
-               if (int_status & int_test)
-                       break;
-       }
-
-       if (irq == 16)
-               return -1;
-
-       return (irq+16);
-}
-
-static void
-adir_onboard_pic_enable(unsigned int irq)
-{
-       volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK;
-
-       /* Change irq to Adirondack onboard native value */
-       irq -= 16;
-
-       /* Enable requested irq number */
-       out_be16(maskreg, in_be16(maskreg) & ~(1 << irq));
-}
-
-static void
-adir_onboard_pic_disable(unsigned int irq)
-{
-       volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK;
-
-       /* Change irq to Adirondack onboard native value */
-       irq -= 16;
-
-       /* Disable requested irq number */
-       out_be16(maskreg, in_be16(maskreg) | (1 << irq));
-}
-
-static struct hw_interrupt_type adir_onboard_pic = {
-       " ADIR PIC ",
-       NULL,
-       NULL,
-       adir_onboard_pic_enable,                /* unmask */
-       adir_onboard_pic_disable,               /* mask */
-       adir_onboard_pic_disable,               /* mask and ack */
-       NULL,
-       NULL
-};
-
-static struct irqaction noop_action = {
-       .handler        = no_action,
-       .flags          = SA_INTERRUPT,
-       .mask           = CPU_MASK_NONE,
-       .name           = "82c59 primary cascade",
-};
-
-/*
- * Linux interrupt values are assigned as follows:
- *
- *     0-15            VT82C686 8259 interrupts
- *     16-31           Adirondack CPLD interrupts
- */
-__init void
-adir_init_IRQ(void)
-{
-       int     i;
-
-       /* Initialize the cascaded 8259's on the VT82C686 */
-       for (i=0; i<16; i++)
-               irq_desc[i].handler = &i8259_pic;
-       i8259_init(NULL);
-
-       /* Initialize Adirondack CPLD PIC and enable 8259 interrupt cascade */
-       for (i=16; i<32; i++)
-               irq_desc[i].handler = &adir_onboard_pic;
-       adir_onboard_pic_init();
-
-       /* Enable 8259 interrupt cascade */
-       setup_irq(ADIR_IRQ_VT82C686_INTR, &noop_action);
-}
-
-int
-adir_get_irq(struct pt_regs *regs)
-{
-       int     irq;
-
-       if ((irq = adir_onboard_pic_get_irq()) < 0)
-               return irq;
-
-       if (irq == ADIR_IRQ_VT82C686_INTR)
-               irq = i8259_irq(regs);
-
-       return irq;
-}
diff --git a/arch/ppc/platforms/adir_setup.c b/arch/ppc/platforms/adir_setup.c
deleted file mode 100644 (file)
index 6a6754e..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * arch/ppc/platforms/adir_setup.c
- *
- * Board setup routines for SBS Adirondack
- *
- * By Michael Sokolov <msokolov@ivan.Harhan.ORG>
- * based on the K2 version by Matt Porter <mporter@mvista.com>
- */
-
-#include <linux/config.h>
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/reboot.h>
-#include <linux/pci.h>
-#include <linux/kdev_t.h>
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/initrd.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/seq_file.h>
-#include <linux/root_dev.h>
-
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/machdep.h>
-#include <asm/time.h>
-#include <asm/todc.h>
-#include <asm/bootinfo.h>
-
-#include "adir.h"
-
-extern void adir_init_IRQ(void);
-extern int adir_get_irq(struct pt_regs *);
-extern void adir_find_bridges(void);
-extern unsigned long loops_per_jiffy;
-
-static unsigned int cpu_750cx[16] = {
-       5, 15, 14, 0, 4, 13, 0, 9, 6, 11, 8, 10, 16, 12, 7, 0
-};
-
-static int
-adir_get_bus_speed(void)
-{
-       if (!(*((u_char *) ADIR_CLOCK_REG) & ADIR_CLOCK_REG_SEL133))
-               return 100000000;
-       else
-               return 133333333;
-}
-
-static int
-adir_get_cpu_speed(void)
-{
-       unsigned long hid1;
-       int cpu_speed;
-
-       hid1 = mfspr(SPRN_HID1) >> 28;
-
-       hid1 = cpu_750cx[hid1];
-
-       cpu_speed = adir_get_bus_speed()*hid1/2;
-       return cpu_speed;
-}
-
-static void __init
-adir_calibrate_decr(void)
-{
-       int freq, divisor = 4;
-
-       /* determine processor bus speed */
-       freq = adir_get_bus_speed();
-       tb_ticks_per_jiffy = freq / HZ / divisor;
-       tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
-}
-
-static int
-adir_show_cpuinfo(struct seq_file *m)
-{
-       seq_printf(m, "vendor\t\t: SBS\n");
-       seq_printf(m, "machine\t\t: Adirondack\n");
-       seq_printf(m, "cpu speed\t: %dMhz\n", adir_get_cpu_speed()/1000000);
-       seq_printf(m, "bus speed\t: %dMhz\n", adir_get_bus_speed()/1000000);
-       seq_printf(m, "memory type\t: SDRAM\n");
-
-       return 0;
-}
-
-extern char cmd_line[];
-
-TODC_ALLOC();
-
-static void __init
-adir_setup_arch(void)
-{
-       unsigned int cpu;
-
-       /* Setup TODC access */
-       TODC_INIT(TODC_TYPE_MC146818, ADIR_NVRAM_RTC_ADDR, 0,
-                 ADIR_NVRAM_RTC_DATA, 8);
-
-       /* init to some ~sane value until calibrate_delay() runs */
-        loops_per_jiffy = 50000000/HZ;
-
-       /* Setup PCI host bridges */
-        adir_find_bridges();
-
-#ifdef CONFIG_BLK_DEV_INITRD
-       if (initrd_start)
-               ROOT_DEV = Root_RAM0;
-       else
-#endif
-#ifdef CONFIG_ROOT_NFS
-               ROOT_DEV = Root_NFS;
-#else
-               ROOT_DEV = Root_SDA1;
-#endif
-
-       /* Identify the system */
-       printk("System Identification: SBS Adirondack - PowerPC 750CXe @ %d Mhz\n", adir_get_cpu_speed()/1000000);
-       printk("SBS Adirondack port (C) 2001 SBS Technologies, Inc.\n");
-
-       /* Identify the CPU manufacturer */
-       cpu = mfspr(SPRN_PVR);
-       printk("CPU manufacturer: IBM [rev=%04x]\n", (cpu & 0xffff));
-}
-
-static void
-adir_restart(char *cmd)
-{
-       local_irq_disable();
-       /* SRR0 has system reset vector, SRR1 has default MSR value */
-       /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
-       __asm__ __volatile__
-       ("lis   3,0xfff0\n\t"
-        "ori   3,3,0x0100\n\t"
-        "mtspr 26,3\n\t"
-        "li    3,0\n\t"
-        "mtspr 27,3\n\t"
-        "rfi\n\t");
-       for(;;);
-}
-
-static void
-adir_power_off(void)
-{
-       for(;;);
-}
-
-static void
-adir_halt(void)
-{
-       adir_restart(NULL);
-}
-
-static unsigned long __init
-adir_find_end_of_memory(void)
-{
-       return boot_mem_size;
-}
-
-static void __init
-adir_map_io(void)
-{
-       io_block_mapping(ADIR_PCI32_VIRT_IO_BASE, ADIR_PCI32_IO_BASE,
-                               ADIR_PCI32_VIRT_IO_SIZE, _PAGE_IO);
-       io_block_mapping(ADIR_PCI64_VIRT_IO_BASE, ADIR_PCI64_IO_BASE,
-                               ADIR_PCI64_VIRT_IO_SIZE, _PAGE_IO);
-}
-
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
-             unsigned long r6, unsigned long r7)
-{
-       /*
-        * On the Adirondack we use bi_recs and pass the pointer to them in R3.
-        */
-       parse_bootinfo((struct bi_record *) (r3 + KERNELBASE));
-
-       /* Remember, isa_io_base is virtual but isa_mem_base is physical! */
-       isa_io_base = ADIR_PCI32_VIRT_IO_BASE;
-       isa_mem_base = ADIR_PCI32_MEM_BASE;
-       pci_dram_offset = ADIR_PCI_SYS_MEM_BASE;
-
-       ppc_md.setup_arch = adir_setup_arch;
-       ppc_md.show_cpuinfo = adir_show_cpuinfo;
-       ppc_md.irq_canonicalize = NULL;
-       ppc_md.init_IRQ = adir_init_IRQ;
-       ppc_md.get_irq = adir_get_irq;
-       ppc_md.init = NULL;
-
-       ppc_md.find_end_of_memory = adir_find_end_of_memory;
-       ppc_md.setup_io_mappings = adir_map_io;
-
-       ppc_md.restart = adir_restart;
-       ppc_md.power_off = adir_power_off;
-       ppc_md.halt = adir_halt;
-
-       ppc_md.time_init = todc_time_init;
-       ppc_md.set_rtc_time = todc_set_rtc_time;
-       ppc_md.get_rtc_time = todc_get_rtc_time;
-       ppc_md.nvram_read_val = todc_mc146818_read_val;
-       ppc_md.nvram_write_val = todc_mc146818_write_val;
-       ppc_md.calibrate_decr = adir_calibrate_decr;
-}
index 507870c9a97a160e8852b7da45d57fb69b9518a9..f64ac2acb603e9b41d0b63a09d88c67df8d6ef40 100644 (file)
 #define SET_PCI_IDE_NATIVE
 
 static struct mv64x60_handle   bh;
-static u32 cpci690_br_base;
-
-static const unsigned int cpu_7xx[16] = { /* 7xx & 74xx (but not 745x) */
-       18, 15, 14, 2, 4, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0
-};
+static void __iomem *cpci690_br_base;
 
 TODC_ALLOC();
 
@@ -55,7 +51,7 @@ cpci690_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
                 *         A   B   C   D
                 */
                {
-                       { 90, 91, 88, 89}, /* IDSEL 30/20 - Sentinel */
+                       { 90, 91, 88, 89 }, /* IDSEL 30/20 - Sentinel */
                };
 
                const long min_idsel = 20, max_idsel = 20, irqs_per_slot = 4;
@@ -67,9 +63,9 @@ cpci690_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
                 *         A   B   C   D
                 */
                {
-                       { 93, 94, 95, 92}, /* IDSEL 28/18 - PMC slot 2 */
-                       {  0,  0,  0,  0}, /* IDSEL 29/19 - Not used */
-                       { 94, 95, 92, 93}, /* IDSEL 30/20 - PMC slot 1 */
+                       { 93, 94, 95, 92 }, /* IDSEL 28/18 - PMC slot 2 */
+                       {  0,  0,  0,  0 }, /* IDSEL 29/19 - Not used */
+                       { 94, 95, 92, 93 }, /* IDSEL 30/20 - PMC slot 1 */
                };
 
                const long min_idsel = 18, max_idsel = 20, irqs_per_slot = 4;
@@ -77,68 +73,29 @@ cpci690_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
        }
 }
 
-static int
-cpci690_get_cpu_speed(void)
-{
-       unsigned long   hid1;
+#define        GB      (1024UL * 1024UL * 1024UL)
 
-       hid1 = mfspr(SPRN_HID1) >> 28;
-       return CPCI690_BUS_FREQ * cpu_7xx[hid1]/2;
+static u32
+cpci690_get_bus_freq(void)
+{
+       if (boot_mem_size >= (1*GB)) /* bus speed based on mem size */
+               return 100000000;
+       else
+               return 133333333;
 }
 
-#define        KB      (1024UL)
-#define        MB      (1024UL * KB)
-#define        GB      (1024UL * MB)
+static const unsigned int cpu_750xx[32] = { /* 750FX & 750GX */
+        0,  0,  2,  2,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,/* 0-15*/
+       16, 17, 18, 19, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40,  0 /*16-31*/
+};
 
-unsigned long __init
-cpci690_find_end_of_memory(void)
+static int
+cpci690_get_cpu_freq(void)
 {
-       u32             mem_ctlr_size;
-       static u32      board_size;
-       static u8       first_time = 1;
-
-       if (first_time) {
-               /* Using cpci690_set_bat() mapping ==> virt addr == phys addr */
-               switch (in_8((u8 *) (cpci690_br_base +
-                       CPCI690_BR_MEM_CTLR)) & 0x07) {
-               case 0x01:
-                       board_size = 256*MB;
-                       break;
-               case 0x02:
-                       board_size = 512*MB;
-                       break;
-               case 0x03:
-                       board_size = 768*MB;
-                       break;
-               case 0x04:
-                       board_size = 1*GB;
-                       break;
-               case 0x05:
-                       board_size = 1*GB + 512*MB;
-                       break;
-               case 0x06:
-                       board_size = 2*GB;
-                       break;
-               default:
-                       board_size = 0xffffffff; /* use mem ctlr size */
-               } /* switch */
-
-               mem_ctlr_size =  mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE,
-                       MV64x60_TYPE_GT64260A);
-
-               /* Check that mem ctlr & board reg agree.  If not, pick MIN. */
-               if (board_size != mem_ctlr_size) {
-                       printk(KERN_WARNING "Board register & memory controller"
-                               "mem size disagree (board reg: 0x%lx, "
-                               "mem ctlr: 0x%lx)\n",
-                               (ulong)board_size, (ulong)mem_ctlr_size);
-                       board_size = min(board_size, mem_ctlr_size);
-               }
-
-               first_time = 0;
-       } /* if */
-
-       return board_size;
+       unsigned long   pll_cfg;
+
+       pll_cfg = (mfspr(SPRN_HID1) & 0xf8000000) >> 27;
+       return cpci690_get_bus_freq() * cpu_750xx[pll_cfg]/2;
 }
 
 static void __init
@@ -228,7 +185,7 @@ cpci690_setup_peripherals(void)
        mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN, CPCI690_BR_BASE,
                CPCI690_BR_SIZE, 0);
        bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN);
-       cpci690_br_base = (u32)ioremap(CPCI690_BR_BASE, CPCI690_BR_SIZE);
+       cpci690_br_base = ioremap(CPCI690_BR_BASE, CPCI690_BR_SIZE);
 
        mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN, CPCI690_TODC_BASE,
                CPCI690_TODC_SIZE, 0);
@@ -329,7 +286,7 @@ cpci690_fixup_mpsc_pdata(struct platform_device *pdev)
        pdata->max_idle = 40;
        pdata->default_baud = CPCI690_MPSC_BAUD;
        pdata->brg_clk_src = CPCI690_MPSC_CLK_SRC;
-       pdata->brg_clk_freq = CPCI690_BUS_FREQ;
+       pdata->brg_clk_freq = cpci690_get_bus_freq();
 }
 
 static int __init
@@ -365,7 +322,7 @@ cpci690_reset_board(void)
        u32     i = 10000;
 
        local_irq_disable();
-       out_8((u8 *)(cpci690_br_base + CPCI690_BR_SW_RESET), 0x11);
+       out_8((cpci690_br_base + CPCI690_BR_SW_RESET), 0x11);
 
        while (i != 0) i++;
        panic("restart failed\n");
@@ -394,10 +351,40 @@ cpci690_power_off(void)
 static int
 cpci690_show_cpuinfo(struct seq_file *m)
 {
+       char    *s;
+
+       seq_printf(m, "cpu MHz\t\t: %d\n",
+               (cpci690_get_cpu_freq() + 500000) / 1000000);
+       seq_printf(m, "bus MHz\t\t: %d\n",
+               (cpci690_get_bus_freq() + 500000) / 1000000);
        seq_printf(m, "vendor\t\t: " BOARD_VENDOR "\n");
        seq_printf(m, "machine\t\t: " BOARD_MACHINE "\n");
-       seq_printf(m, "cpu MHz\t\t: %d\n", cpci690_get_cpu_speed()/1000/1000);
-       seq_printf(m, "bus MHz\t\t: %d\n", CPCI690_BUS_FREQ/1000/1000);
+       seq_printf(m, "FPGA Revision\t: %d\n",
+               in_8(cpci690_br_base + CPCI690_BR_MEM_CTLR) >> 5);
+
+       switch(bh.type) {
+       case MV64x60_TYPE_GT64260A:
+               s = "gt64260a";
+               break;
+       case MV64x60_TYPE_GT64260B:
+               s = "gt64260b";
+               break;
+       case MV64x60_TYPE_MV64360:
+               s = "mv64360";
+               break;
+       case MV64x60_TYPE_MV64460:
+               s = "mv64460";
+               break;
+       default:
+               s = "Unknown";
+       }
+       seq_printf(m, "bridge type\t: %s\n", s);
+       seq_printf(m, "bridge rev\t: 0x%x\n", bh.rev);
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+       seq_printf(m, "coherency\t: %s\n", "off");
+#else
+       seq_printf(m, "coherency\t: %s\n", "on");
+#endif
 
        return 0;
 }
@@ -407,7 +394,7 @@ cpci690_calibrate_decr(void)
 {
        ulong freq;
 
-       freq = CPCI690_BUS_FREQ / 4;
+       freq = cpci690_get_bus_freq() / 4;
 
        printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n",
               freq/1000000, freq%1000000);
@@ -416,25 +403,12 @@ cpci690_calibrate_decr(void)
        tb_to_us = mulhwu_scale_factor(freq, 1000000);
 }
 
-static __inline__ void
-cpci690_set_bat(u32 addr, u32 size)
-{
-       addr &= 0xfffe0000;
-       size &= 0x1ffe0000;
-       size = ((size >> 17) - 1) << 2;
-
-       mb();
-       mtspr(SPRN_DBAT1U, addr | size | 0x2); /* Vs == 1; Vp == 0 */
-       mtspr(SPRN_DBAT1L, addr | 0x2a); /* WIMG bits == 0101; PP == r/w access */
-       mb();
-}
-
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_MPSC)
 static void __init
 cpci690_map_io(void)
 {
        io_block_mapping(CONFIG_MV64X60_NEW_BASE, CONFIG_MV64X60_NEW_BASE,
-               128 * KB, _PAGE_IO);
+               128 * 1024, _PAGE_IO);
 }
 #endif
 
@@ -442,14 +416,15 @@ void __init
 platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
              unsigned long r6, unsigned long r7)
 {
-#ifdef CONFIG_BLK_DEV_INITRD
-       initrd_start=initrd_end=0;
-       initrd_below_start_ok=0;
-#endif /* CONFIG_BLK_DEV_INITRD */
-
        parse_bootinfo(find_bootinfo());
 
-       loops_per_jiffy = cpci690_get_cpu_speed() / HZ;
+#ifdef CONFIG_BLK_DEV_INITRD
+       /* take care of initrd if we have one */
+       if (r4) {
+               initrd_start = r4 + KERNELBASE;
+               initrd_end = r5 + KERNELBASE;
+       }
+#endif /* CONFIG_BLK_DEV_INITRD */
 
        isa_mem_base = 0;
 
@@ -460,7 +435,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
        ppc_md.restart = cpci690_restart;
        ppc_md.power_off = cpci690_power_off;
        ppc_md.halt = cpci690_halt;
-       ppc_md.find_end_of_memory = cpci690_find_end_of_memory;
        ppc_md.time_init = todc_time_init;
        ppc_md.set_rtc_time = todc_set_rtc_time;
        ppc_md.get_rtc_time = todc_get_rtc_time;
@@ -468,22 +442,13 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
        ppc_md.nvram_write_val = todc_direct_write_val;
        ppc_md.calibrate_decr = cpci690_calibrate_decr;
 
-       /*
-        * Need to map in board regs (used by cpci690_find_end_of_memory())
-        * and the bridge's regs (used by progress);
-        */
-       cpci690_set_bat(CPCI690_BR_BASE, 32 * MB);
-       cpci690_br_base = CPCI690_BR_BASE;
-
-#ifdef CONFIG_SERIAL_TEXT_DEBUG
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_MPSC)
        ppc_md.setup_io_mappings = cpci690_map_io;
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
        ppc_md.progress = mv64x60_mpsc_progress;
        mv64x60_progress_init(CONFIG_MV64X60_NEW_BASE);
 #endif /* CONFIG_SERIAL_TEXT_DEBUG */
-#ifdef CONFIG_KGDB
-       ppc_md.setup_io_mappings = cpci690_map_io;
-       ppc_md.early_serial_map = cpci690_early_serial_map;
-#endif /* CONFIG_KGDB */
+#endif /* defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_MPSC) */
 
 #if defined(CONFIG_SERIAL_MPSC)
        platform_notify = cpci690_platform_notify;
index 36cd2673c7427a452e843f4c68ad17f79591afb2..49584c9cedf38bf30df283c4190e989eb376db04 100644 (file)
@@ -73,6 +73,4 @@ typedef struct board_info {
 #define        CPCI690_MPSC_BAUD                       9600
 #define        CPCI690_MPSC_CLK_SRC                    8 /* TCLK */
 
-#define        CPCI690_BUS_FREQ                        133333333
-
 #endif /* __PPC_PLATFORMS_CPCI690_H */
diff --git a/arch/ppc/platforms/ev64360.c b/arch/ppc/platforms/ev64360.c
new file mode 100644 (file)
index 0000000..9811a8a
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+ * arch/ppc/platforms/ev64360.c
+ *
+ * Board setup routines for the Marvell EV-64360-BP Evaluation Board.
+ *
+ * Author: Lee Nicks <allinux@gmail.com>
+ *
+ * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il
+ * Based on code done by - Mark A. Greer <mgreer@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/console.h>
+#include <linux/initrd.h>
+#include <linux/root_dev.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/bootmem.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mv643xx.h>
+#ifdef CONFIG_BOOTIMG
+#include <linux/bootimg.h>
+#endif
+#include <asm/page.h>
+#include <asm/time.h>
+#include <asm/smp.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/ppcboot.h>
+#include <asm/mv64x60.h>
+#include <platforms/ev64360.h>
+
+#define BOARD_VENDOR    "Marvell"
+#define BOARD_MACHINE   "EV-64360-BP"
+
+static struct          mv64x60_handle bh;
+static void __iomem    *sram_base;
+
+static u32             ev64360_flash_size_0;
+static u32             ev64360_flash_size_1;
+
+static u32             ev64360_bus_frequency;
+
+unsigned char  __res[sizeof(bd_t)];
+
+static int __init
+ev64360_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+       return 0;
+}
+
+static void __init
+ev64360_setup_bridge(void)
+{
+       struct mv64x60_setup_info si;
+       int i;
+
+       memset(&si, 0, sizeof(si));
+
+       si.phys_reg_base = CONFIG_MV64X60_NEW_BASE;
+
+       #ifdef CONFIG_PCI
+       si.pci_1.enable_bus = 1;
+       si.pci_1.pci_io.cpu_base = EV64360_PCI1_IO_START_PROC_ADDR;
+       si.pci_1.pci_io.pci_base_hi = 0;
+       si.pci_1.pci_io.pci_base_lo = EV64360_PCI1_IO_START_PCI_ADDR;
+       si.pci_1.pci_io.size = EV64360_PCI1_IO_SIZE;
+       si.pci_1.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE;
+       si.pci_1.pci_mem[0].cpu_base = EV64360_PCI1_MEM_START_PROC_ADDR;
+       si.pci_1.pci_mem[0].pci_base_hi = EV64360_PCI1_MEM_START_PCI_HI_ADDR;
+       si.pci_1.pci_mem[0].pci_base_lo = EV64360_PCI1_MEM_START_PCI_LO_ADDR;
+       si.pci_1.pci_mem[0].size = EV64360_PCI1_MEM_SIZE;
+       si.pci_1.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE;
+       si.pci_1.pci_cmd_bits = 0;
+       si.pci_1.latency_timer = 0x80;
+       #else
+       si.pci_0.enable_bus = 0;
+       si.pci_1.enable_bus = 0;
+       #endif
+
+       for (i = 0; i < MV64x60_CPU2MEM_WINDOWS; i++) {
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+               si.cpu_prot_options[i] = 0;
+               si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE;
+               si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE;
+               si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE;
+
+               si.pci_1.acc_cntl_options[i] =
+                   MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+                   MV64360_PCI_ACC_CNTL_SWAP_NONE |
+                   MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+                   MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+#else
+               si.cpu_prot_options[i] = 0;
+               si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE; /* errata */
+               si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE; /* errata */
+               si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE; /* errata */
+
+               si.pci_1.acc_cntl_options[i] =
+                   MV64360_PCI_ACC_CNTL_SNOOP_WB |
+                   MV64360_PCI_ACC_CNTL_SWAP_NONE |
+                   MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
+                   MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES;
+#endif
+       }
+
+       if (mv64x60_init(&bh, &si))
+               printk(KERN_WARNING "Bridge initialization failed.\n");
+
+       #ifdef CONFIG_PCI
+       pci_dram_offset = 0; /* sys mem at same addr on PCI & cpu bus */
+       ppc_md.pci_swizzle = common_swizzle;
+       ppc_md.pci_map_irq = ev64360_map_irq;
+       ppc_md.pci_exclude_device = mv64x60_pci_exclude_device;
+
+       mv64x60_set_bus(&bh, 1, 0);
+       bh.hose_b->first_busno = 0;
+       bh.hose_b->last_busno = 0xff;
+       #endif
+}
+
+/* Bridge & platform setup routines */
+void __init
+ev64360_intr_setup(void)
+{
+       /* MPP 8, 9, and 10 */
+       mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_1, 0xfff);
+
+       /*
+        * Define GPP 8,9,and 10 interrupt polarity as active low
+        * input signal and level triggered
+        */
+       mv64x60_set_bits(&bh, MV64x60_GPP_LEVEL_CNTL, 0x700);
+       mv64x60_clr_bits(&bh, MV64x60_GPP_IO_CNTL, 0x700);
+
+       /* Config GPP intr ctlr to respond to level trigger */
+       mv64x60_set_bits(&bh, MV64x60_COMM_ARBITER_CNTL, (1<<10));
+
+       /* Erranum FEr PCI-#8 */
+       mv64x60_clr_bits(&bh, MV64x60_PCI0_CMD, (1<<5) | (1<<9));
+       mv64x60_clr_bits(&bh, MV64x60_PCI1_CMD, (1<<5) | (1<<9));
+
+       /*
+        * Dismiss and then enable interrupt on GPP interrupt cause
+        * for CPU #0
+        */
+       mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, ~0x700);
+       mv64x60_set_bits(&bh, MV64x60_GPP_INTR_MASK, 0x700);
+
+       /*
+        * Dismiss and then enable interrupt on CPU #0 high cause reg
+        * BIT25 summarizes GPP interrupts 8-15
+        */
+       mv64x60_set_bits(&bh, MV64360_IC_CPU0_INTR_MASK_HI, (1<<25));
+}
+
+void __init
+ev64360_setup_peripherals(void)
+{
+       u32 base;
+
+       /* Set up window for boot CS */
+       mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN,
+                EV64360_BOOT_WINDOW_BASE, EV64360_BOOT_WINDOW_SIZE, 0);
+       bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);
+
+       /* We only use the 32-bit flash */
+       mv64x60_get_32bit_window(&bh, MV64x60_CPU2BOOT_WIN, &base,
+               &ev64360_flash_size_0);
+       ev64360_flash_size_1 = 0;
+
+       mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN,
+                EV64360_RTC_WINDOW_BASE, EV64360_RTC_WINDOW_SIZE, 0);
+       bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN);
+
+       mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN,
+                EV64360_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE, 0);
+       bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);
+       sram_base = ioremap(EV64360_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE);
+
+       /* Set up Enet->SRAM window */
+       mv64x60_set_32bit_window(&bh, MV64x60_ENET2MEM_4_WIN,
+               EV64360_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE, 0x2);
+       bh.ci->enable_window_32bit(&bh, MV64x60_ENET2MEM_4_WIN);
+
+       /* Give enet r/w access to memory region */
+       mv64x60_set_bits(&bh, MV64360_ENET2MEM_ACC_PROT_0, (0x3 << (4 << 1)));
+       mv64x60_set_bits(&bh, MV64360_ENET2MEM_ACC_PROT_1, (0x3 << (4 << 1)));
+       mv64x60_set_bits(&bh, MV64360_ENET2MEM_ACC_PROT_2, (0x3 << (4 << 1)));
+
+       mv64x60_clr_bits(&bh, MV64x60_PCI1_PCI_DECODE_CNTL, (1 << 3));
+       mv64x60_clr_bits(&bh, MV64x60_TIMR_CNTR_0_3_CNTL,
+                        ((1 << 0) | (1 << 8) | (1 << 16) | (1 << 24)));
+
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+       mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x00160000);
+#else
+       mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b2);
+#endif
+
+       /*
+        * Setting the SRAM to 0. Note that this generates parity errors on
+        * internal data path in SRAM since it's first time accessing it
+        * while after reset it's not configured.
+        */
+       memset(sram_base, 0, MV64360_SRAM_SIZE);
+
+       /* set up PCI interrupt controller */
+       ev64360_intr_setup();
+}
+
+static void __init
+ev64360_setup_arch(void)
+{
+       if (ppc_md.progress)
+               ppc_md.progress("ev64360_setup_arch: enter", 0);
+
+       set_tb(0, 0);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (initrd_start)
+               ROOT_DEV = Root_RAM0;
+       else
+#endif
+#ifdef   CONFIG_ROOT_NFS
+               ROOT_DEV = Root_NFS;
+#else
+               ROOT_DEV = Root_SDA2;
+#endif
+
+       /*
+        * Set up the L2CR register.
+        */
+       _set_L2CR(L2CR_L2E | L2CR_L2PE);
+
+       if (ppc_md.progress)
+               ppc_md.progress("ev64360_setup_arch: calling setup_bridge", 0);
+
+       ev64360_setup_bridge();
+       ev64360_setup_peripherals();
+       ev64360_bus_frequency = ev64360_bus_freq();
+
+       printk(KERN_INFO "%s %s port (C) 2005 Lee Nicks "
+               "(allinux@gmail.com)\n", BOARD_VENDOR, BOARD_MACHINE);
+       if (ppc_md.progress)
+               ppc_md.progress("ev64360_setup_arch: exit", 0);
+}
+
+/* Platform device data fixup routines. */
+#if defined(CONFIG_SERIAL_MPSC)
+static void __init
+ev64360_fixup_mpsc_pdata(struct platform_device *pdev)
+{
+       struct mpsc_pdata *pdata;
+
+       pdata = (struct mpsc_pdata *)pdev->dev.platform_data;
+
+       pdata->max_idle = 40;
+       pdata->default_baud = EV64360_DEFAULT_BAUD;
+       pdata->brg_clk_src = EV64360_MPSC_CLK_SRC;
+       /*
+        * TCLK (not SysCLk) is routed to BRG, then to the MPSC.  On most parts,
+        * TCLK == SysCLK but on 64460, they are separate pins.
+        * SysCLK can go up to 200 MHz but TCLK can only go up to 133 MHz.
+        */
+       pdata->brg_clk_freq = min(ev64360_bus_frequency, MV64x60_TCLK_FREQ_MAX);
+}
+#endif
+
+#if defined(CONFIG_MV643XX_ETH)
+static void __init
+ev64360_fixup_eth_pdata(struct platform_device *pdev)
+{
+       struct mv643xx_eth_platform_data *eth_pd;
+       static u16 phy_addr[] = {
+               EV64360_ETH0_PHY_ADDR,
+               EV64360_ETH1_PHY_ADDR,
+               EV64360_ETH2_PHY_ADDR,
+       };
+
+       eth_pd = pdev->dev.platform_data;
+       eth_pd->force_phy_addr = 1;
+       eth_pd->phy_addr = phy_addr[pdev->id];
+       eth_pd->tx_queue_size = EV64360_ETH_TX_QUEUE_SIZE;
+       eth_pd->rx_queue_size = EV64360_ETH_RX_QUEUE_SIZE;
+}
+#endif
+
+static int __init
+ev64360_platform_notify(struct device *dev)
+{
+       static struct {
+               char    *bus_id;
+               void    ((*rtn)(struct platform_device *pdev));
+       } dev_map[] = {
+#if defined(CONFIG_SERIAL_MPSC)
+               { MPSC_CTLR_NAME ".0", ev64360_fixup_mpsc_pdata },
+               { MPSC_CTLR_NAME ".1", ev64360_fixup_mpsc_pdata },
+#endif
+#if defined(CONFIG_MV643XX_ETH)
+               { MV643XX_ETH_NAME ".0", ev64360_fixup_eth_pdata },
+               { MV643XX_ETH_NAME ".1", ev64360_fixup_eth_pdata },
+               { MV643XX_ETH_NAME ".2", ev64360_fixup_eth_pdata },
+#endif
+       };
+       struct platform_device  *pdev;
+       int     i;
+
+       if (dev && dev->bus_id)
+               for (i=0; i<ARRAY_SIZE(dev_map); i++)
+                       if (!strncmp(dev->bus_id, dev_map[i].bus_id,
+                               BUS_ID_SIZE)) {
+
+                               pdev = container_of(dev,
+                                       struct platform_device, dev);
+                               dev_map[i].rtn(pdev);
+                       }
+
+       return 0;
+}
+
+#ifdef CONFIG_MTD_PHYSMAP
+
+#ifndef MB
+#define MB     (1 << 20)
+#endif
+
+/*
+ * MTD Layout.
+ *
+ * FLASH Amount:       0xff000000 - 0xffffffff
+ * -------------       -----------------------
+ * Reserved:           0xff000000 - 0xff03ffff
+ * JFFS2 file system:  0xff040000 - 0xffefffff
+ * U-boot:             0xfff00000 - 0xffffffff
+ */
+static int __init
+ev64360_setup_mtd(void)
+{
+       u32     size;
+       int     ptbl_entries;
+       static struct mtd_partition     *ptbl;
+
+       size = ev64360_flash_size_0 + ev64360_flash_size_1;
+       if (!size)
+               return -ENOMEM;
+
+       ptbl_entries = 3;
+
+       if ((ptbl = kmalloc(ptbl_entries * sizeof(struct mtd_partition),
+               GFP_KERNEL)) == NULL) {
+
+               printk(KERN_WARNING "Can't alloc MTD partition table\n");
+               return -ENOMEM;
+       }
+       memset(ptbl, 0, ptbl_entries * sizeof(struct mtd_partition));
+
+       ptbl[0].name = "reserved";
+       ptbl[0].offset = 0;
+       ptbl[0].size = EV64360_MTD_RESERVED_SIZE;
+       ptbl[1].name = "jffs2";
+       ptbl[1].offset = EV64360_MTD_RESERVED_SIZE;
+       ptbl[1].size = EV64360_MTD_JFFS2_SIZE;
+       ptbl[2].name = "U-BOOT";
+       ptbl[2].offset = EV64360_MTD_RESERVED_SIZE + EV64360_MTD_JFFS2_SIZE;
+       ptbl[2].size = EV64360_MTD_UBOOT_SIZE;
+
+       physmap_map.size = size;
+       physmap_set_partitions(ptbl, ptbl_entries);
+       return 0;
+}
+
+arch_initcall(ev64360_setup_mtd);
+#endif
+
+static void
+ev64360_restart(char *cmd)
+{
+       ulong   i = 0xffffffff;
+       volatile unsigned char * rtc_base = ioremap(EV64360_RTC_WINDOW_BASE,0x4000);
+
+       /* issue hard reset */
+       rtc_base[0xf] = 0x80;
+       rtc_base[0xc] = 0x00;
+       rtc_base[0xd] = 0x01;
+       rtc_base[0xf] = 0x83;
+
+       while (i-- > 0) ;
+       panic("restart failed\n");
+}
+
+static void
+ev64360_halt(void)
+{
+       while (1) ;
+       /* NOTREACHED */
+}
+
+static void
+ev64360_power_off(void)
+{
+       ev64360_halt();
+       /* NOTREACHED */
+}
+
+static int
+ev64360_show_cpuinfo(struct seq_file *m)
+{
+       seq_printf(m, "vendor\t\t: " BOARD_VENDOR "\n");
+       seq_printf(m, "machine\t\t: " BOARD_MACHINE "\n");
+       seq_printf(m, "bus speed\t: %dMHz\n", ev64360_bus_frequency/1000/1000);
+
+       return 0;
+}
+
+static void __init
+ev64360_calibrate_decr(void)
+{
+       u32 freq;
+
+       freq = ev64360_bus_frequency / 4;
+
+       printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n",
+              (long)freq / 1000000, (long)freq % 1000000);
+
+       tb_ticks_per_jiffy = freq / HZ;
+       tb_to_us = mulhwu_scale_factor(freq, 1000000);
+}
+
+unsigned long __init
+ev64360_find_end_of_memory(void)
+{
+       return mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE,
+               MV64x60_TYPE_MV64360);
+}
+
+static inline void
+ev64360_set_bat(void)
+{
+       mb();
+       mtspr(SPRN_DBAT2U, 0xf0001ffe);
+       mtspr(SPRN_DBAT2L, 0xf000002a);
+       mb();
+}
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE)
+static void __init
+ev64360_map_io(void)
+{
+       io_block_mapping(CONFIG_MV64X60_NEW_BASE, \
+                        CONFIG_MV64X60_NEW_BASE, \
+                        0x00020000, _PAGE_IO);
+}
+#endif
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+             unsigned long r6, unsigned long r7)
+{
+       parse_bootinfo(find_bootinfo());
+
+       /* ASSUMPTION:  If both r3 (bd_t pointer) and r6 (cmdline pointer)
+        * are non-zero, then we should use the board info from the bd_t
+        * structure and the cmdline pointed to by r6 instead of the
+        * information from birecs, if any.  Otherwise, use the information
+        * from birecs as discovered by the preceeding call to
+        * parse_bootinfo().  This rule should work with both PPCBoot, which
+        * uses a bd_t board info structure, and the kernel boot wrapper,
+        * which uses birecs.
+        */
+       if (r3 && r6) {
+               /* copy board info structure */
+               memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+               /* copy command line */
+               *(char *)(r7+KERNELBASE) = 0;
+               strcpy(cmd_line, (char *)(r6+KERNELBASE));
+       }
+       #ifdef CONFIG_ISA
+       isa_mem_base = 0;
+       #endif
+
+       ppc_md.setup_arch = ev64360_setup_arch;
+       ppc_md.show_cpuinfo = ev64360_show_cpuinfo;
+       ppc_md.init_IRQ = mv64360_init_irq;
+       ppc_md.get_irq = mv64360_get_irq;
+       ppc_md.restart = ev64360_restart;
+       ppc_md.power_off = ev64360_power_off;
+       ppc_md.halt = ev64360_halt;
+       ppc_md.find_end_of_memory = ev64360_find_end_of_memory;
+       ppc_md.calibrate_decr = ev64360_calibrate_decr;
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE)
+       ppc_md.setup_io_mappings = ev64360_map_io;
+       ppc_md.progress = mv64x60_mpsc_progress;
+       mv64x60_progress_init(CONFIG_MV64X60_NEW_BASE);
+#endif
+
+#if defined(CONFIG_SERIAL_MPSC) || defined(CONFIG_MV643XX_ETH)
+       platform_notify = ev64360_platform_notify;
+#endif
+
+       ev64360_set_bat(); /* Need for ev64360_find_end_of_memory and progress */
+}
diff --git a/arch/ppc/platforms/ev64360.h b/arch/ppc/platforms/ev64360.h
new file mode 100644 (file)
index 0000000..68eabe4
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * arch/ppc/platforms/ev64360.h
+ *
+ * Definitions for Marvell EV-64360-BP Evaluation Board.
+ *
+ * Author: Lee Nicks <allinux@gmail.com>
+ *
+ * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il
+ * Based on code done by Mark A. Greer <mgreer@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+/*
+ * The MV64360 has 2 PCI buses each with 1 window from the CPU bus to
+ * PCI I/O space and 4 windows from the CPU bus to PCI MEM space.
+ * We'll only use one PCI MEM window on each PCI bus.
+ *
+ * This is the CPU physical memory map (windows must be at least 64KB and start
+ * on a boundary that is a multiple of the window size):
+ *
+ *    0x42000000-0x4203ffff      - Internal SRAM
+ *    0xf1000000-0xf100ffff      - MV64360 Registers (CONFIG_MV64X60_NEW_BASE)
+ *    0xfc800000-0xfcffffff      - RTC
+ *    0xff000000-0xffffffff      - Boot window, 16 MB flash
+ *    0xc0000000-0xc3ffffff      - PCI I/O (second hose)
+ *    0x80000000-0xbfffffff      - PCI MEM (second hose)
+ */
+
+#ifndef __PPC_PLATFORMS_EV64360_H
+#define __PPC_PLATFORMS_EV64360_H
+
+/* CPU Physical Memory Map setup. */
+#define EV64360_BOOT_WINDOW_BASE               0xff000000
+#define EV64360_BOOT_WINDOW_SIZE               0x01000000 /* 16 MB */
+#define EV64360_INTERNAL_SRAM_BASE             0x42000000
+#define EV64360_RTC_WINDOW_BASE                        0xfc800000
+#define EV64360_RTC_WINDOW_SIZE                        0x00800000 /* 8 MB */
+
+#define EV64360_PCI1_MEM_START_PROC_ADDR       0x80000000
+#define EV64360_PCI1_MEM_START_PCI_HI_ADDR     0x00000000
+#define EV64360_PCI1_MEM_START_PCI_LO_ADDR     0x80000000
+#define EV64360_PCI1_MEM_SIZE                  0x40000000 /* 1 GB */
+#define EV64360_PCI1_IO_START_PROC_ADDR                0xc0000000
+#define EV64360_PCI1_IO_START_PCI_ADDR         0x00000000
+#define EV64360_PCI1_IO_SIZE                   0x04000000 /* 64 MB */
+
+#define        EV64360_DEFAULT_BAUD                    115200
+#define        EV64360_MPSC_CLK_SRC                    8         /* TCLK */
+#define EV64360_MPSC_CLK_FREQ                  133333333
+
+#define        EV64360_MTD_RESERVED_SIZE               0x40000
+#define EV64360_MTD_JFFS2_SIZE                 0xec0000
+#define EV64360_MTD_UBOOT_SIZE                 0x100000
+
+#define        EV64360_ETH0_PHY_ADDR                   8
+#define        EV64360_ETH1_PHY_ADDR                   9
+#define        EV64360_ETH2_PHY_ADDR                   10
+
+#define EV64360_ETH_TX_QUEUE_SIZE              800
+#define EV64360_ETH_RX_QUEUE_SIZE              400
+
+#define        EV64360_ETH_PORT_CONFIG_VALUE                   \
+       ETH_UNICAST_NORMAL_MODE                 |       \
+       ETH_DEFAULT_RX_QUEUE_0                  |       \
+       ETH_DEFAULT_RX_ARP_QUEUE_0              |       \
+       ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP         |       \
+       ETH_RECEIVE_BC_IF_IP                    |       \
+       ETH_RECEIVE_BC_IF_ARP                   |       \
+       ETH_CAPTURE_TCP_FRAMES_DIS              |       \
+       ETH_CAPTURE_UDP_FRAMES_DIS              |       \
+       ETH_DEFAULT_RX_TCP_QUEUE_0              |       \
+       ETH_DEFAULT_RX_UDP_QUEUE_0              |       \
+       ETH_DEFAULT_RX_BPDU_QUEUE_0
+
+#define        EV64360_ETH_PORT_CONFIG_EXTEND_VALUE            \
+       ETH_SPAN_BPDU_PACKETS_AS_NORMAL         |       \
+       ETH_PARTITION_DISABLE
+
+#define        GT_ETH_IPG_INT_RX(value)                        \
+       ((value & 0x3fff) << 8)
+
+#define        EV64360_ETH_PORT_SDMA_CONFIG_VALUE              \
+       ETH_RX_BURST_SIZE_4_64BIT               |       \
+       GT_ETH_IPG_INT_RX(0)                    |       \
+       ETH_TX_BURST_SIZE_4_64BIT
+
+#define        EV64360_ETH_PORT_SERIAL_CONTROL_VALUE           \
+       ETH_FORCE_LINK_PASS                     |       \
+       ETH_ENABLE_AUTO_NEG_FOR_DUPLX           |       \
+       ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL      |       \
+       ETH_ADV_SYMMETRIC_FLOW_CTRL             |       \
+       ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX       |       \
+       ETH_FORCE_BP_MODE_NO_JAM                |       \
+       BIT9                                    |       \
+       ETH_DO_NOT_FORCE_LINK_FAIL              |       \
+       ETH_RETRANSMIT_16_ATTEMPTS              |       \
+       ETH_ENABLE_AUTO_NEG_SPEED_GMII          |       \
+       ETH_DTE_ADV_0                           |       \
+       ETH_DISABLE_AUTO_NEG_BYPASS             |       \
+       ETH_AUTO_NEG_NO_CHANGE                  |       \
+       ETH_MAX_RX_PACKET_9700BYTE              |       \
+       ETH_CLR_EXT_LOOPBACK                    |       \
+       ETH_SET_FULL_DUPLEX_MODE                |       \
+       ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX
+
+static inline u32
+ev64360_bus_freq(void)
+{
+       return 133333333;
+}
+
+#endif /* __PPC_PLATFORMS_EV64360_H */
diff --git a/arch/ppc/platforms/k2.c b/arch/ppc/platforms/k2.c
deleted file mode 100644 (file)
index aacb438..0000000
+++ /dev/null
@@ -1,613 +0,0 @@
-/*
- * arch/ppc/platforms/k2.c
- *
- * Board setup routines for SBS K2
- *
- * Author: Matt Porter <mporter@mvista.com>
- *
- * Updated by: Randy Vinson <rvinson@mvista.com.
- *
- * 2001-2004 (c) MontaVista, Software, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/config.h>
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/reboot.h>
-#include <linux/pci.h>
-#include <linux/kdev_t.h>
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/initrd.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/irq.h>
-#include <linux/seq_file.h>
-#include <linux/root_dev.h>
-
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/machdep.h>
-#include <asm/time.h>
-#include <asm/i8259.h>
-#include <asm/todc.h>
-#include <asm/bootinfo.h>
-
-#include <syslib/cpc710.h>
-#include "k2.h"
-
-extern unsigned long loops_per_jiffy;
-extern void gen550_progress(char *, unsigned short);
-
-static unsigned int cpu_7xx[16] = {
-       0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0
-};
-static unsigned int cpu_6xx[16] = {
-       0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0
-};
-
-static inline int __init
-k2_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-       struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
-       /*
-        * Check our hose index.  If we are zero then we are on the
-        * local PCI hose, otherwise we are on the cPCI hose.
-        */
-       if (!hose->index) {
-               static char pci_irq_table[][4] =
-                       /*
-                        *      PCI IDSEL/INTPIN->INTLINE
-                        *      A       B       C       D
-                        */
-               {
-                       {1,     0,      0,      0},     /* Ethernet */
-                       {5,     5,      5,      5},     /* PMC Site 1 */
-                       {6,     6,      6,      6},     /* PMC Site 2 */
-                       {0,     0,      0,      0},     /* unused */
-                       {0,     0,      0,      0},     /* unused */
-                       {0,     0,      0,      0},     /* PCI-ISA Bridge */
-                       {0,     0,      0,      0},     /* unused */
-                       {0,     0,      0,      0},     /* unused */
-                       {0,     0,      0,      0},     /* unused */
-                       {0,     0,      0,      0},     /* unused */
-                       {0,     0,      0,      0},     /* unused */
-                       {0,     0,      0,      0},     /* unused */
-                       {0,     0,      0,      0},     /* unused */
-                       {0,     0,      0,      0},     /* unused */
-                       {15,    0,      0,      0},     /* M5229 IDE */
-               };
-               const long min_idsel = 3, max_idsel = 17, irqs_per_slot = 4;
-               return PCI_IRQ_TABLE_LOOKUP;
-       } else {
-               static char pci_irq_table[][4] =
-               /*
-                *      PCI IDSEL/INTPIN->INTLINE
-                *      A       B       C       D
-                */
-               {
-                       {10,    11,     12,     9},     /* cPCI slot 8 */
-                       {11,    12,     9,      10},    /* cPCI slot 7 */
-                       {12,    9,      10,     11},    /* cPCI slot 6 */
-                       {9,     10,     11,     12},    /* cPCI slot 5 */
-                       {10,    11,     12,     9},     /* cPCI slot 4 */
-                       {11,    12,     9,      10},    /* cPCI slot 3 */
-                       {12,    9,      10,     11},    /* cPCI slot 2 */
-               };
-               const long min_idsel = 15, max_idsel = 21, irqs_per_slot = 4;
-               return PCI_IRQ_TABLE_LOOKUP;
-       }
-}
-
-void k2_pcibios_fixup(void)
-{
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-       struct pci_dev *ide_dev;
-
-       /*
-        * Enable DMA support on hdc
-        */
-       ide_dev = pci_get_device(PCI_VENDOR_ID_AL,
-                                 PCI_DEVICE_ID_AL_M5229, NULL);
-
-       if (ide_dev) {
-
-               unsigned long ide_dma_base;
-
-               ide_dma_base = pci_resource_start(ide_dev, 4);
-               outb(0x00, ide_dma_base + 0x2);
-               outb(0x20, ide_dma_base + 0xa);
-               pci_dev_put(ide_dev);
-       }
-#endif
-}
-
-void k2_pcibios_fixup_resources(struct pci_dev *dev)
-{
-       int i;
-
-       if ((dev->vendor == PCI_VENDOR_ID_IBM) &&
-           (dev->device == PCI_DEVICE_ID_IBM_CPC710_PCI64)) {
-               pr_debug("Fixup CPC710 resources\n");
-               for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
-                       dev->resource[i].start = 0;
-                       dev->resource[i].end = 0;
-               }
-       }
-}
-
-void k2_setup_hoses(void)
-{
-       struct pci_controller *hose_a, *hose_b;
-
-       /*
-        * Reconfigure CPC710 memory map so
-        * we have some more PCI memory space.
-        */
-
-       /* Set FPHB mode */
-       __raw_writel(0x808000e0, PGCHP);        /* Set FPHB mode */
-
-       /* PCI32 mappings */
-       __raw_writel(0x00000000, K2_PCI32_BAR + PIBAR); /* PCI I/O base */
-       __raw_writel(0x00000000, K2_PCI32_BAR + PMBAR); /* PCI Mem base */
-       __raw_writel(0xf0000000, K2_PCI32_BAR + MSIZE); /* 256MB */
-       __raw_writel(0xfff00000, K2_PCI32_BAR + IOSIZE); /* 1MB */
-       __raw_writel(0xc0000000, K2_PCI32_BAR + SMBAR); /* Base@0xc0000000 */
-       __raw_writel(0x80000000, K2_PCI32_BAR + SIBAR); /* Base@0x80000000 */
-       __raw_writel(0x000000c0, K2_PCI32_BAR + PSSIZE); /* 1GB space */
-       __raw_writel(0x000000c0, K2_PCI32_BAR + PPSIZE); /* 1GB space */
-       __raw_writel(0x00000000, K2_PCI32_BAR + BARPS); /* Base@0x00000000 */
-       __raw_writel(0x00000000, K2_PCI32_BAR + BARPP); /* Base@0x00000000 */
-       __raw_writel(0x00000080, K2_PCI32_BAR + PSBAR); /* Base@0x80 */
-       __raw_writel(0x00000000, K2_PCI32_BAR + PPBAR);
-
-       __raw_writel(0xc0000000, K2_PCI32_BAR + BPMDLK);
-       __raw_writel(0xd0000000, K2_PCI32_BAR + TPMDLK);
-       __raw_writel(0x80000000, K2_PCI32_BAR + BIODLK);
-       __raw_writel(0x80100000, K2_PCI32_BAR + TIODLK);
-       __raw_writel(0xe0008000, K2_PCI32_BAR + DLKCTRL);
-       __raw_writel(0xffffffff, K2_PCI32_BAR + DLKDEV);
-
-       /* PCI64 mappings */
-       __raw_writel(0x00100000, K2_PCI64_BAR + PIBAR); /* PCI I/O base */
-       __raw_writel(0x10000000, K2_PCI64_BAR + PMBAR); /* PCI Mem base */
-       __raw_writel(0xf0000000, K2_PCI64_BAR + MSIZE); /* 256MB */
-       __raw_writel(0xfff00000, K2_PCI64_BAR + IOSIZE); /* 1MB */
-       __raw_writel(0xd0000000, K2_PCI64_BAR + SMBAR); /* Base@0xd0000000 */
-       __raw_writel(0x80100000, K2_PCI64_BAR + SIBAR); /* Base@0x80100000 */
-       __raw_writel(0x000000c0, K2_PCI64_BAR + PSSIZE); /* 1GB space */
-       __raw_writel(0x000000c0, K2_PCI64_BAR + PPSIZE); /* 1GB space */
-       __raw_writel(0x00000000, K2_PCI64_BAR + BARPS); /* Base@0x00000000 */
-       __raw_writel(0x00000000, K2_PCI64_BAR + BARPP); /* Base@0x00000000 */
-
-       /* Setup PCI32 hose */
-       hose_a = pcibios_alloc_controller();
-       if (!hose_a)
-               return;
-
-       hose_a->first_busno = 0;
-       hose_a->last_busno = 0xff;
-       hose_a->pci_mem_offset = K2_PCI32_MEM_BASE;
-
-       pci_init_resource(&hose_a->io_resource,
-                         K2_PCI32_LOWER_IO,
-                         K2_PCI32_UPPER_IO,
-                         IORESOURCE_IO, "PCI32 host bridge");
-
-       pci_init_resource(&hose_a->mem_resources[0],
-                         K2_PCI32_LOWER_MEM + K2_PCI32_MEM_BASE,
-                         K2_PCI32_UPPER_MEM + K2_PCI32_MEM_BASE,
-                         IORESOURCE_MEM, "PCI32 host bridge");
-
-       hose_a->io_space.start = K2_PCI32_LOWER_IO;
-       hose_a->io_space.end = K2_PCI32_UPPER_IO;
-       hose_a->mem_space.start = K2_PCI32_LOWER_MEM;
-       hose_a->mem_space.end = K2_PCI32_UPPER_MEM;
-       hose_a->io_base_virt = (void *)K2_ISA_IO_BASE;
-
-       setup_indirect_pci(hose_a, K2_PCI32_CONFIG_ADDR, K2_PCI32_CONFIG_DATA);
-
-       /* Initialize PCI32 bus registers */
-       early_write_config_byte(hose_a,
-                               hose_a->first_busno,
-                               PCI_DEVFN(0, 0),
-                               CPC710_BUS_NUMBER, hose_a->first_busno);
-
-       early_write_config_byte(hose_a,
-                               hose_a->first_busno,
-                               PCI_DEVFN(0, 0),
-                               CPC710_SUB_BUS_NUMBER, hose_a->last_busno);
-
-       /* Enable PCI interrupt polling */
-       early_write_config_byte(hose_a,
-                               hose_a->first_busno,
-                               PCI_DEVFN(8, 0), 0x45, 0x80);
-
-       /* Route polled PCI interrupts */
-       early_write_config_byte(hose_a,
-                               hose_a->first_busno,
-                               PCI_DEVFN(8, 0), 0x48, 0x58);
-
-       early_write_config_byte(hose_a,
-                               hose_a->first_busno,
-                               PCI_DEVFN(8, 0), 0x49, 0x07);
-
-       early_write_config_byte(hose_a,
-                               hose_a->first_busno,
-                               PCI_DEVFN(8, 0), 0x4a, 0x31);
-
-       early_write_config_byte(hose_a,
-                               hose_a->first_busno,
-                               PCI_DEVFN(8, 0), 0x4b, 0xb9);
-
-       /* route secondary IDE channel interrupt to IRQ 15 */
-       early_write_config_byte(hose_a,
-                               hose_a->first_busno,
-                               PCI_DEVFN(8, 0), 0x75, 0x0f);
-
-       /* enable IDE controller IDSEL */
-       early_write_config_byte(hose_a,
-                               hose_a->first_busno,
-                               PCI_DEVFN(8, 0), 0x58, 0x48);
-
-       /* Enable IDE function */
-       early_write_config_byte(hose_a,
-                               hose_a->first_busno,
-                               PCI_DEVFN(17, 0), 0x50, 0x03);
-
-       /* Set M5229 IDE controller to native mode */
-       early_write_config_byte(hose_a,
-                               hose_a->first_busno,
-                               PCI_DEVFN(17, 0), PCI_CLASS_PROG, 0xdf);
-
-       hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
-
-       /* Write out correct max subordinate bus number for hose A */
-       early_write_config_byte(hose_a,
-                               hose_a->first_busno,
-                               PCI_DEVFN(0, 0),
-                               CPC710_SUB_BUS_NUMBER, hose_a->last_busno);
-
-       /* Only setup PCI64 hose if we are in the system slot */
-       if (!(readb(K2_MISC_REG) & K2_SYS_SLOT_MASK)) {
-               /* Setup PCI64 hose */
-               hose_b = pcibios_alloc_controller();
-               if (!hose_b)
-                       return;
-
-               hose_b->first_busno = hose_a->last_busno + 1;
-               hose_b->last_busno = 0xff;
-
-               /* Reminder: quit changing the following, it is correct. */
-               hose_b->pci_mem_offset = K2_PCI32_MEM_BASE;
-
-               pci_init_resource(&hose_b->io_resource,
-                                 K2_PCI64_LOWER_IO,
-                                 K2_PCI64_UPPER_IO,
-                                 IORESOURCE_IO, "PCI64 host bridge");
-
-               pci_init_resource(&hose_b->mem_resources[0],
-                                 K2_PCI64_LOWER_MEM + K2_PCI32_MEM_BASE,
-                                 K2_PCI64_UPPER_MEM + K2_PCI32_MEM_BASE,
-                                 IORESOURCE_MEM, "PCI64 host bridge");
-
-               hose_b->io_space.start = K2_PCI64_LOWER_IO;
-               hose_b->io_space.end = K2_PCI64_UPPER_IO;
-               hose_b->mem_space.start = K2_PCI64_LOWER_MEM;
-               hose_b->mem_space.end = K2_PCI64_UPPER_MEM;
-               hose_b->io_base_virt = (void *)K2_ISA_IO_BASE;
-
-               setup_indirect_pci(hose_b,
-                                  K2_PCI64_CONFIG_ADDR, K2_PCI64_CONFIG_DATA);
-
-               /* Initialize PCI64 bus registers */
-               early_write_config_byte(hose_b,
-                                       0,
-                                       PCI_DEVFN(0, 0),
-                                       CPC710_SUB_BUS_NUMBER, 0xff);
-
-               early_write_config_byte(hose_b,
-                                       0,
-                                       PCI_DEVFN(0, 0),
-                                       CPC710_BUS_NUMBER, hose_b->first_busno);
-
-               hose_b->last_busno = pciauto_bus_scan(hose_b,
-                                                     hose_b->first_busno);
-
-               /* Write out correct max subordinate bus number for hose B */
-               early_write_config_byte(hose_b,
-                                       hose_b->first_busno,
-                                       PCI_DEVFN(0, 0),
-                                       CPC710_SUB_BUS_NUMBER,
-                                       hose_b->last_busno);
-
-               /* Configure PCI64 PSBAR */
-               early_write_config_dword(hose_b,
-                                        hose_b->first_busno,
-                                        PCI_DEVFN(0, 0),
-                                        PCI_BASE_ADDRESS_0,
-                                        K2_PCI64_SYS_MEM_BASE);
-       }
-
-       /* Configure i8259 level/edge settings */
-       outb(0x62, 0x4d0);
-       outb(0xde, 0x4d1);
-
-#ifdef CONFIG_CPC710_DATA_GATHERING
-       {
-               unsigned int tmp;
-               tmp = __raw_readl(ABCNTL);
-               /* Enable data gathering on both PCI interfaces */
-               __raw_writel(tmp | 0x05000000, ABCNTL);
-       }
-#endif
-
-       ppc_md.pcibios_fixup = k2_pcibios_fixup;
-       ppc_md.pcibios_fixup_resources = k2_pcibios_fixup_resources;
-       ppc_md.pci_swizzle = common_swizzle;
-       ppc_md.pci_map_irq = k2_map_irq;
-}
-
-static int k2_get_bus_speed(void)
-{
-       int bus_speed;
-       unsigned char board_id;
-
-       board_id = *(unsigned char *)K2_BOARD_ID_REG;
-
-       switch (K2_BUS_SPD(board_id)) {
-
-       case 0:
-       default:
-               bus_speed = 100000000;
-               break;
-
-       case 1:
-               bus_speed = 83333333;
-               break;
-
-       case 2:
-               bus_speed = 75000000;
-               break;
-
-       case 3:
-               bus_speed = 66666666;
-               break;
-       }
-       return bus_speed;
-}
-
-static int k2_get_cpu_speed(void)
-{
-       unsigned long hid1;
-       int cpu_speed;
-
-       hid1 = mfspr(SPRN_HID1) >> 28;
-
-       if ((mfspr(SPRN_PVR) >> 16) == 8)
-               hid1 = cpu_7xx[hid1];
-       else
-               hid1 = cpu_6xx[hid1];
-
-       cpu_speed = k2_get_bus_speed() * hid1 / 2;
-       return cpu_speed;
-}
-
-static void __init k2_calibrate_decr(void)
-{
-       int freq, divisor = 4;
-
-       /* determine processor bus speed */
-       freq = k2_get_bus_speed();
-       tb_ticks_per_jiffy = freq / HZ / divisor;
-       tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000);
-}
-
-static int k2_show_cpuinfo(struct seq_file *m)
-{
-       unsigned char k2_geo_bits, k2_system_slot;
-
-       seq_printf(m, "vendor\t\t: SBS\n");
-       seq_printf(m, "machine\t\t: K2\n");
-       seq_printf(m, "cpu speed\t: %dMhz\n", k2_get_cpu_speed() / 1000000);
-       seq_printf(m, "bus speed\t: %dMhz\n", k2_get_bus_speed() / 1000000);
-       seq_printf(m, "memory type\t: SDRAM\n");
-
-       k2_geo_bits = readb(K2_MSIZ_GEO_REG) & K2_GEO_ADR_MASK;
-       k2_system_slot = !(readb(K2_MISC_REG) & K2_SYS_SLOT_MASK);
-       seq_printf(m, "backplane\t: %s slot board",
-                  k2_system_slot ? "System" : "Non system");
-       seq_printf(m, "with geographical address %x\n", k2_geo_bits);
-
-       return 0;
-}
-
-TODC_ALLOC();
-
-static void __init k2_setup_arch(void)
-{
-       unsigned int cpu;
-
-       /* Setup TODC access */
-       TODC_INIT(TODC_TYPE_MK48T37, 0, 0,
-                 ioremap(K2_RTC_BASE_ADDRESS, K2_RTC_SIZE), 8);
-
-       /* init to some ~sane value until calibrate_delay() runs */
-       loops_per_jiffy = 50000000 / HZ;
-
-       /* make FLASH transactions higher priority than PCI to avoid deadlock */
-       __raw_writel(__raw_readl(SIOC1) | 0x80000000, SIOC1);
-
-       /* Set hardware to access FLASH page 2 */
-       __raw_writel(1 << 29, GPOUT);
-
-       /* Setup PCI host bridges */
-       k2_setup_hoses();
-
-#ifdef CONFIG_BLK_DEV_INITRD
-       if (initrd_start)
-               ROOT_DEV = Root_RAM0;
-       else
-#endif
-#ifdef CONFIG_ROOT_NFS
-               ROOT_DEV = Root_NFS;
-#else
-               ROOT_DEV = Root_HDC1;
-#endif
-
-       /* Identify the system */
-       printk(KERN_INFO "System Identification: SBS K2 - PowerPC 750 @ "
-                       "%d Mhz\n", k2_get_cpu_speed() / 1000000);
-       printk(KERN_INFO "Port by MontaVista Software, Inc. "
-                       "(source@mvista.com)\n");
-
-       /* Identify the CPU manufacturer */
-       cpu = PVR_REV(mfspr(SPRN_PVR));
-       printk(KERN_INFO "CPU manufacturer: %s [rev=%04x]\n",
-                       (cpu & (1 << 15)) ? "IBM" : "Motorola", cpu);
-}
-
-static void k2_restart(char *cmd)
-{
-       local_irq_disable();
-
-       /* Flip FLASH back to page 1 to access firmware image */
-       __raw_writel(0, GPOUT);
-
-       /* SRR0 has system reset vector, SRR1 has default MSR value */
-       /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
-       mtspr(SPRN_SRR0, 0xfff00100);
-       mtspr(SPRN_SRR1, 0);
-       __asm__ __volatile__("rfi\n\t");
-
-       /* not reached */
-       for (;;) ;
-}
-
-static void k2_power_off(void)
-{
-       for (;;) ;
-}
-
-static void k2_halt(void)
-{
-       k2_restart(NULL);
-}
-
-/*
- * Set BAT 3 to map PCI32 I/O space.
- */
-static __inline__ void k2_set_bat(void)
-{
-       /* wait for all outstanding memory accesses to complete */
-       mb();
-
-       /* setup DBATs */
-       mtspr(SPRN_DBAT2U, 0x80001ffe);
-       mtspr(SPRN_DBAT2L, 0x8000002a);
-       mtspr(SPRN_DBAT3U, 0xf0001ffe);
-       mtspr(SPRN_DBAT3L, 0xf000002a);
-
-       /* wait for updates */
-       mb();
-}
-
-static unsigned long __init k2_find_end_of_memory(void)
-{
-       unsigned long total;
-       unsigned char msize = 7;        /* Default to 128MB */
-
-       msize = K2_MEM_SIZE(readb(K2_MSIZ_GEO_REG));
-
-       switch (msize) {
-       case 2:
-               /*
-                * This will break without a lowered
-                * KERNELBASE or CONFIG_HIGHMEM on.
-                * It seems non 1GB builds exist yet,
-                * though.
-                */
-               total = K2_MEM_SIZE_1GB;
-               break;
-       case 3:
-       case 4:
-               total = K2_MEM_SIZE_512MB;
-               break;
-       case 5:
-       case 6:
-               total = K2_MEM_SIZE_256MB;
-               break;
-       case 7:
-               total = K2_MEM_SIZE_128MB;
-               break;
-       default:
-               printk
-                   ("K2: Invalid memory size detected, defaulting to 128MB\n");
-               total = K2_MEM_SIZE_128MB;
-               break;
-       }
-       return total;
-}
-
-static void __init k2_map_io(void)
-{
-       io_block_mapping(K2_PCI32_IO_BASE,
-                        K2_PCI32_IO_BASE, 0x00200000, _PAGE_IO);
-       io_block_mapping(0xff000000, 0xff000000, 0x01000000, _PAGE_IO);
-}
-
-static void __init k2_init_irq(void)
-{
-       int i;
-
-       for (i = 0; i < 16; i++)
-               irq_desc[i].handler = &i8259_pic;
-
-       i8259_init(0);
-}
-
-void __init platform_init(unsigned long r3, unsigned long r4,
-                         unsigned long r5, unsigned long r6, unsigned long r7)
-{
-       parse_bootinfo((struct bi_record *)(r3 + KERNELBASE));
-
-       k2_set_bat();
-
-       isa_io_base = K2_ISA_IO_BASE;
-       isa_mem_base = K2_ISA_MEM_BASE;
-       pci_dram_offset = K2_PCI32_SYS_MEM_BASE;
-
-       ppc_md.setup_arch = k2_setup_arch;
-       ppc_md.show_cpuinfo = k2_show_cpuinfo;
-       ppc_md.init_IRQ = k2_init_irq;
-       ppc_md.get_irq = i8259_irq;
-
-       ppc_md.find_end_of_memory = k2_find_end_of_memory;
-       ppc_md.setup_io_mappings = k2_map_io;
-
-       ppc_md.restart = k2_restart;
-       ppc_md.power_off = k2_power_off;
-       ppc_md.halt = k2_halt;
-
-       ppc_md.time_init = todc_time_init;
-       ppc_md.set_rtc_time = todc_set_rtc_time;
-       ppc_md.get_rtc_time = todc_get_rtc_time;
-       ppc_md.calibrate_decr = k2_calibrate_decr;
-
-       ppc_md.nvram_read_val = todc_direct_read_val;
-       ppc_md.nvram_write_val = todc_direct_write_val;
-
-#ifdef CONFIG_SERIAL_TEXT_DEBUG
-       ppc_md.progress = gen550_progress;
-#endif
-}
diff --git a/arch/ppc/platforms/k2.h b/arch/ppc/platforms/k2.h
deleted file mode 100644 (file)
index 78326ab..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * arch/ppc/platforms/k2.h
- *
- * Definitions for SBS K2 board support
- *
- * Author: Matt Porter <mporter@mvista.com>
- *
- * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef __PPC_PLATFORMS_K2_H
-#define __PPC_PLATFORMS_K2_H
-
-/*
- * SBS K2 definitions
- */
-
-#define        K2_PCI64_BAR            0xff400000
-#define        K2_PCI32_BAR            0xff500000
-
-#define K2_PCI64_CONFIG_ADDR   (K2_PCI64_BAR + 0x000f8000)
-#define K2_PCI64_CONFIG_DATA   (K2_PCI64_BAR + 0x000f8010)
-
-#define K2_PCI32_CONFIG_ADDR   (K2_PCI32_BAR + 0x000f8000)
-#define K2_PCI32_CONFIG_DATA   (K2_PCI32_BAR + 0x000f8010)
-
-#define K2_PCI64_MEM_BASE      0xd0000000
-#define K2_PCI64_IO_BASE       0x80100000
-
-#define K2_PCI32_MEM_BASE      0xc0000000
-#define K2_PCI32_IO_BASE       0x80000000
-
-#define K2_PCI32_SYS_MEM_BASE  0x80000000
-#define K2_PCI64_SYS_MEM_BASE  K2_PCI32_SYS_MEM_BASE
-
-#define K2_PCI32_LOWER_MEM     0x00000000
-#define K2_PCI32_UPPER_MEM     0x0fffffff
-#define K2_PCI32_LOWER_IO      0x00000000
-#define K2_PCI32_UPPER_IO      0x000fffff
-
-#define K2_PCI64_LOWER_MEM     0x10000000
-#define K2_PCI64_UPPER_MEM     0x1fffffff
-#define K2_PCI64_LOWER_IO      0x00100000
-#define        K2_PCI64_UPPER_IO       0x001fffff
-
-#define K2_ISA_IO_BASE         K2_PCI32_IO_BASE
-#define K2_ISA_MEM_BASE                K2_PCI32_MEM_BASE
-
-#define K2_BOARD_ID_REG                (K2_ISA_IO_BASE + 0x800)
-#define K2_MISC_REG            (K2_ISA_IO_BASE + 0x804)
-#define K2_MSIZ_GEO_REG                (K2_ISA_IO_BASE + 0x808)
-#define K2_HOT_SWAP_REG                (K2_ISA_IO_BASE + 0x80c)
-#define K2_PLD2_REG            (K2_ISA_IO_BASE + 0x80e)
-#define K2_PLD3_REG            (K2_ISA_IO_BASE + 0x80f)
-
-#define K2_BUS_SPD(board_id)   (board_id >> 2) & 3
-
-#define K2_RTC_BASE_OFFSET     0x90000
-#define K2_RTC_BASE_ADDRESS    (K2_PCI32_MEM_BASE + K2_RTC_BASE_OFFSET)
-#define K2_RTC_SIZE            0x8000
-
-#define K2_MEM_SIZE_MASK       0xe0
-#define K2_MEM_SIZE(size_reg)  (size_reg & K2_MEM_SIZE_MASK) >> 5
-#define        K2_MEM_SIZE_1GB         0x40000000
-#define K2_MEM_SIZE_512MB      0x20000000
-#define K2_MEM_SIZE_256MB      0x10000000
-#define K2_MEM_SIZE_128MB      0x08000000
-
-#define K2_L2CACHE_MASK                0x03    /* Mask for 2 L2 Cache bits */
-#define K2_L2CACHE_512KB       0x00    /* 512KB */
-#define K2_L2CACHE_256KB       0x01    /* 256KB */
-#define K2_L2CACHE_1MB         0x02    /* 1MB */
-#define K2_L2CACHE_NONE                0x03    /* None */
-
-#define K2_GEO_ADR_MASK                0x1f
-
-#define K2_SYS_SLOT_MASK       0x08
-
-#endif /* __PPC_PLATFORMS_K2_H */
index 169dbf6534b9d0aec791a1c235d7a10635e4851b..2b53afae0e9c2d7cfe8a01b66d792652c3e6d29d 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/bootimg.h>
 #endif
 #include <asm/io.h>
+#include <asm/unistd.h>
 #include <asm/page.h>
 #include <asm/time.h>
 #include <asm/smp.h>
 #include <asm/mv64x60.h>
 #include <platforms/katana.h>
 
-static struct          mv64x60_handle bh;
-static katana_id_t     katana_id;
-static void __iomem    *cpld_base;
-static void __iomem    *sram_base;
-
-static u32             katana_flash_size_0;
-static u32             katana_flash_size_1;
-
-static u32             katana_bus_frequency;
+static struct mv64x60_handle   bh;
+static katana_id_t             katana_id;
+static void __iomem            *cpld_base;
+static void __iomem            *sram_base;
+static u32                     katana_flash_size_0;
+static u32                     katana_flash_size_1;
+static u32                     katana_bus_frequency;
+static struct pci_controller   katana_hose_a;
 
 unsigned char  __res[sizeof(bd_t)];
 
@@ -71,8 +71,12 @@ katana_irq_lookup_750i(unsigned char idsel, unsigned char pin)
                        KATANA_PCI_INTA_IRQ_750i, KATANA_PCI_INTB_IRQ_750i },
                /* IDSEL 6 (T8110) */
                {KATANA_PCI_INTD_IRQ_750i, 0, 0, 0 },
+               /* IDSEL 7 (unused) */
+               {0, 0, 0, 0 },
+               /* IDSEL 8 (Intel 82544) (752i only but doesn't harm 750i) */
+               {KATANA_PCI_INTD_IRQ_750i, 0, 0, 0 },
        };
-       const long min_idsel = 4, max_idsel = 6, irqs_per_slot = 4;
+       const long min_idsel = 4, max_idsel = 8, irqs_per_slot = 4;
 
        return PCI_IRQ_TABLE_LOOKUP;
 }
@@ -148,7 +152,7 @@ katana_get_proc_num(void)
                        save_exclude = mv64x60_pci_exclude_bridge;
                        mv64x60_pci_exclude_bridge = 0;
 
-                       early_read_config_word(bh.hose_a, 0,
+                       early_read_config_word(bh.hose_b, 0,
                                PCI_DEVFN(0,0), PCI_DEVICE_ID, &val);
 
                        mv64x60_pci_exclude_bridge = save_exclude;
@@ -191,7 +195,8 @@ katana_setup_bridge(void)
        struct mv64x60_setup_info si;
        void __iomem *vaddr;
        int i;
-       u16 val;
+       u32 v;
+       u16 val, type;
        u8 save_exclude;
 
        /*
@@ -222,6 +227,20 @@ katana_setup_bridge(void)
                        PCI_DEVICE_ID, val);
        }
 
+       /*
+        * While we're in here, set the hotswap register correctly.
+        * Turn off blue LED; mask ENUM#, clear insertion & extraction bits.
+        */
+       early_read_config_dword(&hose, 0, PCI_DEVFN(0, 0),
+               MV64360_PCICFG_CPCI_HOTSWAP, &v);
+       v &= ~(1<<19);
+       v |= ((1<<17) | (1<<22) | (1<<23));
+       early_write_config_dword(&hose, 0, PCI_DEVFN(0, 0),
+               MV64360_PCICFG_CPCI_HOTSWAP, v);
+
+       /* While we're at it, grab the bridge type for later */
+       early_read_config_word(&hose, 0, PCI_DEVFN(0, 0), PCI_DEVICE_ID, &type);
+
        mv64x60_pci_exclude_bridge = save_exclude;
        iounmap(vaddr);
 
@@ -251,21 +270,23 @@ katana_setup_bridge(void)
                si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE;
 
                si.pci_1.acc_cntl_options[i] =
-                   MV64360_PCI_ACC_CNTL_SNOOP_NONE |
-                   MV64360_PCI_ACC_CNTL_SWAP_NONE |
-                   MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
-                   MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+                       MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+                       MV64360_PCI_ACC_CNTL_SWAP_NONE |
+                       MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+                       MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
 #else
                si.cpu_prot_options[i] = 0;
-               si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE; /* errata */
-               si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE; /* errata */
-               si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE; /* errata */
+               si.enet_options[i] = MV64360_ENET2MEM_SNOOP_WB;
+               si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_WB;
+               si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_WB;
 
                si.pci_1.acc_cntl_options[i] =
-                   MV64360_PCI_ACC_CNTL_SNOOP_WB |
-                   MV64360_PCI_ACC_CNTL_SWAP_NONE |
-                   MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
-                   MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES;
+                       MV64360_PCI_ACC_CNTL_SNOOP_WB |
+                       MV64360_PCI_ACC_CNTL_SWAP_NONE |
+                       MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
+                       ((type == PCI_DEVICE_ID_MARVELL_MV64360) ?
+                               MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES :
+                               MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES);
 #endif
        }
 
@@ -281,12 +302,26 @@ katana_setup_bridge(void)
        mv64x60_set_bus(&bh, 1, 0);
        bh.hose_b->first_busno = 0;
        bh.hose_b->last_busno = 0xff;
+
+       /*
+        * Need to access hotswap reg which is in the pci config area of the
+        * bridge's hose 0.  Note that pcibios_alloc_controller() can't be used
+        * to alloc hose_a b/c that would make hose 0 known to the generic
+        * pci code which we don't want.
+        */
+       bh.hose_a = &katana_hose_a;
+       setup_indirect_pci_nomap(bh.hose_a,
+               bh.v_base + MV64x60_PCI0_CONFIG_ADDR,
+               bh.v_base + MV64x60_PCI0_CONFIG_DATA);
 }
 
 /* Bridge & platform setup routines */
 void __init
 katana_intr_setup(void)
 {
+       if (bh.type == MV64x60_TYPE_MV64460) /* As per instns from Marvell */
+               mv64x60_clr_bits(&bh, MV64x60_CPU_MASTER_CNTL, 1 << 15);
+
        /* MPP 8, 9, and 10 */
        mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_1, 0xfff);
 
@@ -309,9 +344,16 @@ katana_intr_setup(void)
        /* Config GPP intr ctlr to respond to level trigger */
        mv64x60_set_bits(&bh, MV64x60_COMM_ARBITER_CNTL, (1<<10));
 
-       /* Erranum FEr PCI-#8 */
-       mv64x60_clr_bits(&bh, MV64x60_PCI0_CMD, (1<<5) | (1<<9));
-       mv64x60_clr_bits(&bh, MV64x60_PCI1_CMD, (1<<5) | (1<<9));
+       if (bh.type == MV64x60_TYPE_MV64360) {
+               /* Erratum FEr PCI-#9 */
+               mv64x60_clr_bits(&bh, MV64x60_PCI1_CMD,
+                               (1<<4) | (1<<5) | (1<<6) | (1<<7));
+               mv64x60_set_bits(&bh, MV64x60_PCI1_CMD, (1<<8) | (1<<9));
+       } else {
+               mv64x60_clr_bits(&bh, MV64x60_PCI1_CMD, (1<<6) | (1<<7));
+               mv64x60_set_bits(&bh, MV64x60_PCI1_CMD,
+                               (1<<4) | (1<<5) | (1<<8) | (1<<9));
+       }
 
        /*
         * Dismiss and then enable interrupt on GPP interrupt cause
@@ -473,17 +515,46 @@ katana_setup_arch(void)
                ppc_md.progress("katana_setup_arch: exit", 0);
 }
 
+void
+katana_fixup_resources(struct pci_dev *dev)
+{
+       u16     v16;
+
+       pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_LINE_SIZE>>2);
+
+       pci_read_config_word(dev, PCI_COMMAND, &v16);
+       v16 |= PCI_COMMAND_INVALIDATE | PCI_COMMAND_FAST_BACK;
+       pci_write_config_word(dev, PCI_COMMAND, v16);
+}
+
+static const unsigned int cpu_750xx[32] = { /* 750FX & 750GX */
+        0,  0,  2,  2,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,/* 0-15*/
+       16, 17, 18, 19, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40,  0 /*16-31*/
+};
+
+static int
+katana_get_cpu_freq(void)
+{
+       unsigned long   pll_cfg;
+
+       pll_cfg = (mfspr(SPRN_HID1) & 0xf8000000) >> 27;
+       return katana_bus_frequency * cpu_750xx[pll_cfg]/2;
+}
+
 /* Platform device data fixup routines. */
 #if defined(CONFIG_SERIAL_MPSC)
 static void __init
 katana_fixup_mpsc_pdata(struct platform_device *pdev)
 {
-       struct mpsc_pdata *pdata;
+       struct mpsc_pdata *pdata = (struct mpsc_pdata *)pdev->dev.platform_data;
+       bd_t *bdp = (bd_t *)__res;
 
-       pdata = (struct mpsc_pdata *)pdev->dev.platform_data;
+       if (bdp->bi_baudrate)
+               pdata->default_baud = bdp->bi_baudrate;
+       else
+               pdata->default_baud = KATANA_DEFAULT_BAUD;
 
        pdata->max_idle = 40;
-       pdata->default_baud = KATANA_DEFAULT_BAUD;
        pdata->brg_clk_src = KATANA_MPSC_CLK_SRC;
        /*
         * TCLK (not SysCLk) is routed to BRG, then to the MPSC.  On most parts,
@@ -513,6 +584,18 @@ katana_fixup_eth_pdata(struct platform_device *pdev)
 }
 #endif
 
+#if defined(CONFIG_SYSFS)
+static void __init
+katana_fixup_mv64xxx_pdata(struct platform_device *pdev)
+{
+       struct mv64xxx_pdata *pdata = (struct mv64xxx_pdata *)
+               pdev->dev.platform_data;
+
+       /* Katana supports the mv64xxx hotswap register */
+       pdata->hs_reg_valid = 1;
+}
+#endif
+
 static int __init
 katana_platform_notify(struct device *dev)
 {
@@ -528,6 +611,9 @@ katana_platform_notify(struct device *dev)
                { MV643XX_ETH_NAME ".0", katana_fixup_eth_pdata },
                { MV643XX_ETH_NAME ".1", katana_fixup_eth_pdata },
                { MV643XX_ETH_NAME ".2", katana_fixup_eth_pdata },
+#endif
+#if defined(CONFIG_SYSFS)
+               { MV64XXX_DEV_NAME ".0", katana_fixup_mv64xxx_pdata },
 #endif
        };
        struct platform_device  *pdev;
@@ -536,8 +622,7 @@ katana_platform_notify(struct device *dev)
        if (dev && dev->bus_id)
                for (i=0; i<ARRAY_SIZE(dev_map); i++)
                        if (!strncmp(dev->bus_id, dev_map[i].bus_id,
-                               BUS_ID_SIZE)) {
-
+                                       BUS_ID_SIZE)) {
                                pdev = container_of(dev,
                                        struct platform_device, dev);
                                dev_map[i].rtn(pdev);
@@ -578,8 +663,7 @@ katana_setup_mtd(void)
        ptbl_entries = (size >= (64*MB)) ? 6 : 4;
 
        if ((ptbl = kmalloc(ptbl_entries * sizeof(struct mtd_partition),
-               GFP_KERNEL)) == NULL) {
-
+                       GFP_KERNEL)) == NULL) {
                printk(KERN_WARNING "Can't alloc MTD partition table\n");
                return -ENOMEM;
        }
@@ -611,7 +695,6 @@ katana_setup_mtd(void)
        physmap_set_partitions(ptbl, ptbl_entries);
        return 0;
 }
-
 arch_initcall(katana_setup_mtd);
 #endif
 
@@ -632,7 +715,22 @@ katana_halt(void)
 {
        u8      v;
 
-       if (katana_id == KATANA_ID_752I) {
+       /* Turn on blue LED to indicate its okay to remove */
+       if (katana_id == KATANA_ID_750I) {
+               u32     v;
+               u8      save_exclude;
+
+               /* Set LOO bit in cPCI HotSwap reg of hose 0 to turn on LED. */
+               save_exclude = mv64x60_pci_exclude_bridge;
+               mv64x60_pci_exclude_bridge = 0;
+               early_read_config_dword(bh.hose_a, 0, PCI_DEVFN(0, 0),
+                       MV64360_PCICFG_CPCI_HOTSWAP, &v);
+               v &= 0xff;
+               v |= (1 << 19);
+               early_write_config_dword(bh.hose_a, 0, PCI_DEVFN(0, 0),
+                       MV64360_PCICFG_CPCI_HOTSWAP, v);
+               mv64x60_pci_exclude_bridge = save_exclude;
+       } else if (katana_id == KATANA_ID_752I) {
                   v = in_8(cpld_base + HSL_PLD_BASE + HSL_PLD_HOT_SWAP_OFF);
                   v |= HSL_PLD_HOT_SWAP_LED_BIT;
                   out_8(cpld_base + HSL_PLD_BASE + HSL_PLD_HOT_SWAP_OFF, v);
@@ -652,37 +750,65 @@ katana_power_off(void)
 static int
 katana_show_cpuinfo(struct seq_file *m)
 {
+       char    *s;
+
+       seq_printf(m, "cpu freq\t: %dMHz\n",
+               (katana_get_cpu_freq() + 500000) / 1000000);
+       seq_printf(m, "bus freq\t: %ldMHz\n",
+               ((long)katana_bus_frequency + 500000) / 1000000);
        seq_printf(m, "vendor\t\t: Artesyn Communication Products, LLC\n");
 
        seq_printf(m, "board\t\t: ");
-
        switch (katana_id) {
        case KATANA_ID_3750:
-               seq_printf(m, "Katana 3750\n");
+               seq_printf(m, "Katana 3750");
                break;
 
        case KATANA_ID_750I:
-               seq_printf(m, "Katana 750i\n");
+               seq_printf(m, "Katana 750i");
                break;
 
        case KATANA_ID_752I:
-               seq_printf(m, "Katana 752i\n");
+               seq_printf(m, "Katana 752i");
                break;
 
        default:
-               seq_printf(m, "Unknown\n");
+               seq_printf(m, "Unknown");
                break;
        }
-
-       seq_printf(m, "product ID\t: 0x%x\n",
+       seq_printf(m, " (product id: 0x%x)\n",
                   in_8(cpld_base + KATANA_CPLD_PRODUCT_ID));
+
+       seq_printf(m, "pci mode\t: %sMonarch\n",
+               katana_is_monarch()? "" : "Non-");
        seq_printf(m, "hardware rev\t: 0x%x\n",
                   in_8(cpld_base+KATANA_CPLD_HARDWARE_VER));
-       seq_printf(m, "PLD rev\t\t: 0x%x\n",
+       seq_printf(m, "pld rev\t\t: 0x%x\n",
                   in_8(cpld_base + KATANA_CPLD_PLD_VER));
-       seq_printf(m, "PLB freq\t: %ldMhz\n",
-               (long)katana_bus_frequency / 1000000);
-       seq_printf(m, "PCI\t\t: %sMonarch\n", katana_is_monarch()? "" : "Non-");
+
+       switch(bh.type) {
+       case MV64x60_TYPE_GT64260A:
+               s = "gt64260a";
+               break;
+       case MV64x60_TYPE_GT64260B:
+               s = "gt64260b";
+               break;
+       case MV64x60_TYPE_MV64360:
+               s = "mv64360";
+               break;
+       case MV64x60_TYPE_MV64460:
+               s = "mv64460";
+               break;
+       default:
+               s = "Unknown";
+       }
+       seq_printf(m, "bridge type\t: %s\n", s);
+       seq_printf(m, "bridge rev\t: 0x%x\n", bh.rev);
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+       seq_printf(m, "coherency\t: %s\n", "off");
+#else
+       seq_printf(m, "coherency\t: %s\n", "on");
+#endif
 
        return 0;
 }
@@ -701,11 +827,20 @@ katana_calibrate_decr(void)
        tb_to_us = mulhwu_scale_factor(freq, 1000000);
 }
 
+/*
+ * The katana supports both uImage and zImage.  If uImage, get the mem size
+ * from the bd info.  If zImage, the bootwrapper adds a BI_MEMSIZE entry in
+ * the bi_rec data which is sucked out and put into boot_mem_size by
+ * parse_bootinfo().  MMU_init() will then use the boot_mem_size for the mem
+ * size and not call this routine.  The only way this will fail is when a uImage
+ * is used but the fw doesn't pass in a valid bi_memsize.  This should never
+ * happen, though.
+ */
 unsigned long __init
 katana_find_end_of_memory(void)
 {
-       return mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE,
-               MV64x60_TYPE_MV64360);
+       bd_t *bdp = (bd_t *)__res;
+       return bdp->bi_memsize;
 }
 
 #if defined(CONFIG_I2C_MV64XXX) && defined(CONFIG_SENSORS_M41T00)
@@ -729,15 +864,6 @@ katana_rtc_hookup(void)
 late_initcall(katana_rtc_hookup);
 #endif
 
-static inline void
-katana_set_bat(void)
-{
-       mb();
-       mtspr(SPRN_DBAT2U, 0xf0001ffe);
-       mtspr(SPRN_DBAT2L, 0xf000002a);
-       mb();
-}
-
 #if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE)
 static void __init
 katana_map_io(void)
@@ -763,15 +889,24 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
         */
        if (r3 && r6) {
                /* copy board info structure */
-               memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+               memcpy((void *)__res, (void *)(r3+KERNELBASE), sizeof(bd_t));
                /* copy command line */
                *(char *)(r7+KERNELBASE) = 0;
                strcpy(cmd_line, (char *)(r6+KERNELBASE));
        }
 
+#ifdef CONFIG_BLK_DEV_INITRD
+       /* take care of initrd if we have one */
+       if (r4) {
+               initrd_start = r4 + KERNELBASE;
+               initrd_end = r5 + KERNELBASE;
+       }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
        isa_mem_base = 0;
 
        ppc_md.setup_arch = katana_setup_arch;
+       ppc_md.pcibios_fixup_resources = katana_fixup_resources;
        ppc_md.show_cpuinfo = katana_show_cpuinfo;
        ppc_md.init_IRQ = mv64360_init_irq;
        ppc_md.get_irq = mv64360_get_irq;
@@ -790,6 +925,4 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
 #if defined(CONFIG_SERIAL_MPSC) || defined(CONFIG_MV643XX_ETH)
        platform_notify = katana_platform_notify;
 #endif
-
-       katana_set_bat(); /* Need for katana_find_end_of_memory and progress */
 }
index b82ed81950f591e17676ea0e4513787cb66ad974..597257eff2ec5a2e6216cb99d717863ac66cb43b 100644 (file)
 #define KATANA_PCI1_IO_SIZE                     0x04000000 /* 64 MB */
 
 /* Board-specific IRQ info */
-#define  KATANA_PCI_INTA_IRQ_3750              64+8
-#define  KATANA_PCI_INTB_IRQ_3750              64+9
-#define  KATANA_PCI_INTC_IRQ_3750              64+10
-
-#define  KATANA_PCI_INTA_IRQ_750i              64+8
-#define  KATANA_PCI_INTB_IRQ_750i              64+9
-#define  KATANA_PCI_INTC_IRQ_750i              64+10
-#define  KATANA_PCI_INTD_IRQ_750i              64+14
+#define  KATANA_PCI_INTA_IRQ_3750              (64+8)
+#define  KATANA_PCI_INTB_IRQ_3750              (64+9)
+#define  KATANA_PCI_INTC_IRQ_3750              (64+10)
+
+#define  KATANA_PCI_INTA_IRQ_750i              (64+8)
+#define  KATANA_PCI_INTB_IRQ_750i              (64+9)
+#define  KATANA_PCI_INTC_IRQ_750i              (64+10)
+#define  KATANA_PCI_INTD_IRQ_750i              (64+14)
 
 #define KATANA_CPLD_RST_EVENT                  0x00000000
 #define KATANA_CPLD_RST_CMD                    0x00001000
diff --git a/arch/ppc/platforms/mcpn765.c b/arch/ppc/platforms/mcpn765.c
deleted file mode 100644 (file)
index e88d294..0000000
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * arch/ppc/platforms/mcpn765.c
- *
- * Board setup routines for the Motorola MCG MCPN765 cPCI Board.
- *
- * Author: Mark A. Greer
- *         mgreer@mvista.com
- *
- * Modified by Randy Vinson (rvinson@mvista.com)
- *
- * 2001-2002 (c) MontaVista, Software, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-/*
- * This file adds support for the Motorola MCG MCPN765.
- */
-#include <linux/config.h>
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/reboot.h>
-#include <linux/pci.h>
-#include <linux/kdev_t.h>
-#include <linux/major.h>
-#include <linux/initrd.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/irq.h>
-#include <linux/seq_file.h>
-#include <linux/root_dev.h>
-#include <linux/serial.h>
-#include <linux/tty.h> /* for linux/serial_core.h */
-#include <linux/serial_core.h>
-#include <linux/slab.h>
-
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/time.h>
-#include <asm/dma.h>
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/smp.h>
-#include <asm/open_pic.h>
-#include <asm/i8259.h>
-#include <asm/todc.h>
-#include <asm/pci-bridge.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/bootinfo.h>
-#include <asm/hawk.h>
-#include <asm/kgdb.h>
-
-#include "mcpn765.h"
-
-static u_char mcpn765_openpic_initsenses[] __initdata = {
-       (IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),/* 16: i8259 cascade */
-       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 17: COM1,2,3,4 */
-       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 18: Enet 1 (front) */
-       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 19: HAWK WDT XXXX */
-       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 20: 21554 bridge */
-       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 21: cPCI INTA# */
-       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 22: cPCI INTB# */
-       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 23: cPCI INTC# */
-       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 24: cPCI INTD# */
-       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 25: PMC1 INTA#,PMC2 INTB#*/
-       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 26: PMC1 INTB#,PMC2 INTC#*/
-       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 27: PMC1 INTC#,PMC2 INTD#*/
-       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 28: PMC1 INTD#,PMC2 INTA#*/
-       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 29: Enet 2 (J3) */
-       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 30: Abort Switch */
-       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 31: RTC Alarm */
-};
-
-extern void mcpn765_set_VIA_IDE_native(void);
-
-extern u_int openpic_irq(void);
-extern char cmd_line[];
-
-extern void gen550_progress(char *, unsigned short);
-extern void gen550_init(int, struct uart_port *);
-
-int use_of_interrupt_tree = 0;
-
-static void mcpn765_halt(void);
-
-TODC_ALLOC();
-
-/*
- * Motorola MCG MCPN765 interrupt routing.
- */
-static inline int
-mcpn765_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-       static char pci_irq_table[][4] =
-       /*
-        *      PCI IDSEL/INTPIN->INTLINE
-        *         A   B   C   D
-        */
-       {
-               { 14,  0,  0,  0 },     /* IDSEL 11 - have to manually set */
-               {  0,  0,  0,  0 },     /* IDSEL 12 - unused */
-               {  0,  0,  0,  0 },     /* IDSEL 13 - unused */
-               { 18,  0,  0,  0 },     /* IDSEL 14 - Enet 0 */
-               {  0,  0,  0,  0 },     /* IDSEL 15 - unused */
-               { 25, 26, 27, 28 },     /* IDSEL 16 - PMC Slot 1 */
-               { 28, 25, 26, 27 },     /* IDSEL 17 - PMC Slot 2 */
-               {  0,  0,  0,  0 },     /* IDSEL 18 - PMC 2B Connector XXXX */
-               { 29,  0,  0,  0 },     /* IDSEL 19 - Enet 1 */
-               { 20,  0,  0,  0 },     /* IDSEL 20 - 21554 cPCI bridge */
-       };
-
-       const long min_idsel = 11, max_idsel = 20, irqs_per_slot = 4;
-       return PCI_IRQ_TABLE_LOOKUP;
-}
-
-void __init
-mcpn765_set_VIA_IDE_legacy(void)
-{
-       unsigned short vend, dev;
-
-       early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_VENDOR_ID, &vend);
-       early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_DEVICE_ID, &dev);
-
-       if ((vend == PCI_VENDOR_ID_VIA) &&
-           (dev == PCI_DEVICE_ID_VIA_82C586_1)) {
-
-               unsigned char temp;
-
-               /* put back original "standard" port base addresses */
-               early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
-                                        PCI_BASE_ADDRESS_0, 0x1f1);
-               early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
-                                        PCI_BASE_ADDRESS_1, 0x3f5);
-               early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
-                                        PCI_BASE_ADDRESS_2, 0x171);
-               early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
-                                        PCI_BASE_ADDRESS_3, 0x375);
-               early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
-                                        PCI_BASE_ADDRESS_4, 0xcc01);
-
-               /* put into legacy mode */
-               early_read_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
-                                      &temp);
-               temp &= ~0x05;
-               early_write_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
-                                       temp);
-       }
-}
-
-void
-mcpn765_set_VIA_IDE_native(void)
-{
-       unsigned short vend, dev;
-
-       early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_VENDOR_ID, &vend);
-       early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_DEVICE_ID, &dev);
-
-       if ((vend == PCI_VENDOR_ID_VIA) &&
-           (dev == PCI_DEVICE_ID_VIA_82C586_1)) {
-
-               unsigned char temp;
-
-               /* put into native mode */
-               early_read_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
-                                      &temp);
-               temp |= 0x05;
-               early_write_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
-                                       temp);
-       }
-}
-
-/*
- * Initialize the VIA 82c586b.
- */
-static void __init
-mcpn765_setup_via_82c586b(void)
-{
-       struct pci_dev  *dev;
-       u_char          c;
-
-       if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
-                                  PCI_DEVICE_ID_VIA_82C586_0,
-                                  NULL)) == NULL) {
-               printk("No VIA ISA bridge found\n");
-               mcpn765_halt();
-               /* NOTREACHED */
-       }
-
-       /*
-        * If the firmware left the EISA 4d0/4d1 ports enabled, make sure
-        * IRQ 14 is set for edge.
-        */
-       pci_read_config_byte(dev, 0x47, &c);
-
-       if (c & (1<<5)) {
-               c = inb(0x4d1);
-               c &= ~(1<<6);
-               outb(c, 0x4d1);
-       }
-
-       /* Disable PNP IRQ routing since we use the Hawk's MPIC */
-       pci_write_config_dword(dev, 0x54, 0);
-       pci_write_config_byte(dev, 0x58, 0);
-
-       pci_dev_put(dev);
-       if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
-                                  PCI_DEVICE_ID_VIA_82C586_1,
-                                  NULL)) == NULL) {
-               printk("No VIA ISA bridge found\n");
-               mcpn765_halt();
-               /* NOTREACHED */
-       }
-
-       /*
-        * PPCBug doesn't set the enable bits for the IDE device.
-        * Turn them on now.
-        */
-       pci_read_config_byte(dev, 0x40, &c);
-       c |= 0x03;
-       pci_write_config_byte(dev, 0x40, c);
-       pci_dev_put(dev);
-
-       return;
-}
-
-void __init
-mcpn765_pcibios_fixup(void)
-{
-       /* Do MCPN765 board specific initialization.  */
-       mcpn765_setup_via_82c586b();
-}
-
-void __init
-mcpn765_find_bridges(void)
-{
-       struct pci_controller   *hose;
-
-       hose = pcibios_alloc_controller();
-
-       if (!hose)
-               return;
-
-       hose->first_busno = 0;
-       hose->last_busno = 0xff;
-       hose->pci_mem_offset = MCPN765_PCI_PHY_MEM_OFFSET;
-
-       pci_init_resource(&hose->io_resource,
-                       MCPN765_PCI_IO_START,
-                       MCPN765_PCI_IO_END,
-                       IORESOURCE_IO,
-                       "PCI host bridge");
-
-       pci_init_resource(&hose->mem_resources[0],
-                       MCPN765_PCI_MEM_START,
-                       MCPN765_PCI_MEM_END,
-                       IORESOURCE_MEM,
-                       "PCI host bridge");
-
-       hose->io_space.start = MCPN765_PCI_IO_START;
-       hose->io_space.end = MCPN765_PCI_IO_END;
-       hose->mem_space.start = MCPN765_PCI_MEM_START;
-       hose->mem_space.end = MCPN765_PCI_MEM_END - HAWK_MPIC_SIZE;
-
-       if (hawk_init(hose,
-                      MCPN765_HAWK_PPC_REG_BASE,
-                      MCPN765_PROC_PCI_MEM_START,
-                      MCPN765_PROC_PCI_MEM_END - HAWK_MPIC_SIZE,
-                      MCPN765_PROC_PCI_IO_START,
-                      MCPN765_PROC_PCI_IO_END,
-                      MCPN765_PCI_MEM_END - HAWK_MPIC_SIZE + 1) != 0) {
-               printk("Could not initialize HAWK bridge\n");
-       }
-
-       /* VIA IDE BAR decoders are only 16-bits wide. PCI Auto Config
-        * will reassign the bars outside of 16-bit I/O space, which will 
-        * "break" things. To prevent this, we'll set the IDE chip into
-        * legacy mode and seed the bars with their legacy addresses (in 16-bit
-        * I/O space). The Auto Config code will skip the IDE contoller in 
-        * legacy mode, so our bar values will stick.
-        */
-       mcpn765_set_VIA_IDE_legacy();
-
-       hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
-
-       /* Now that we've got 16-bit addresses in the bars, we can switch the
-        * IDE controller back into native mode so we can do "modern" resource
-        * and interrupt management.
-        */
-       mcpn765_set_VIA_IDE_native();
-
-       ppc_md.pcibios_fixup = mcpn765_pcibios_fixup;
-       ppc_md.pcibios_fixup_bus = NULL;
-       ppc_md.pci_swizzle = common_swizzle;
-       ppc_md.pci_map_irq = mcpn765_map_irq;
-
-       return;
-}
-static void __init
-mcpn765_setup_arch(void)
-{
-       struct pci_controller *hose;
-
-       if ( ppc_md.progress )
-               ppc_md.progress("mcpn765_setup_arch: enter", 0);
-
-       loops_per_jiffy = 50000000 / HZ;
-
-#ifdef CONFIG_BLK_DEV_INITRD
-       if (initrd_start)
-               ROOT_DEV = Root_RAM0;
-       else
-#endif
-#ifdef CONFIG_ROOT_NFS
-               ROOT_DEV = Root_NFS;
-#else
-               ROOT_DEV = Root_SDA2;
-#endif
-
-       if ( ppc_md.progress )
-               ppc_md.progress("mcpn765_setup_arch: find_bridges", 0);
-
-       /* Lookup PCI host bridges */
-       mcpn765_find_bridges();
-
-       hose = pci_bus_to_hose(0);
-       isa_io_base = (ulong)hose->io_base_virt;
-
-       TODC_INIT(TODC_TYPE_MK48T37,
-                 (MCPN765_PHYS_NVRAM_AS0 - isa_io_base),
-                 (MCPN765_PHYS_NVRAM_AS1 - isa_io_base),
-                 (MCPN765_PHYS_NVRAM_DATA - isa_io_base),
-                 8);
-
-       OpenPIC_InitSenses = mcpn765_openpic_initsenses;
-       OpenPIC_NumInitSenses = sizeof(mcpn765_openpic_initsenses);
-
-       printk("Motorola MCG MCPN765 cPCI Non-System Board\n");
-       printk("MCPN765 port (MontaVista Software, Inc. (source@mvista.com))\n");
-
-       if ( ppc_md.progress )
-               ppc_md.progress("mcpn765_setup_arch: exit", 0);
-
-       return;
-}
-
-static void __init
-mcpn765_init2(void)
-{
-
-       request_region(0x00,0x20,"dma1");
-       request_region(0x20,0x20,"pic1");
-       request_region(0x40,0x20,"timer");
-       request_region(0x80,0x10,"dma page reg");
-       request_region(0xa0,0x20,"pic2");
-       request_region(0xc0,0x20,"dma2");
-
-       return;
-}
-
-/*
- * Interrupt setup and service.
- * Have MPIC on HAWK and cascaded 8259s on VIA 82586 cascaded to MPIC.
- */
-static void __init
-mcpn765_init_IRQ(void)
-{
-       int i;
-
-       if ( ppc_md.progress )
-               ppc_md.progress("init_irq: enter", 0);
-
-       openpic_init(NUM_8259_INTERRUPTS);
-       openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
-                       i8259_irq);
-
-       for(i=0; i < NUM_8259_INTERRUPTS; i++)
-               irq_desc[i].handler = &i8259_pic;
-
-       i8259_init(0);
-
-       if ( ppc_md.progress )
-               ppc_md.progress("init_irq: exit", 0);
-
-       return;
-}
-
-static u32
-mcpn765_irq_canonicalize(u32 irq)
-{
-       if (irq == 2)
-               return 9;
-       else
-               return irq;
-}
-
-static unsigned long __init
-mcpn765_find_end_of_memory(void)
-{
-       return hawk_get_mem_size(MCPN765_HAWK_SMC_BASE);
-}
-
-static void __init
-mcpn765_map_io(void)
-{
-       io_block_mapping(0xfe800000, 0xfe800000, 0x00800000, _PAGE_IO);
-}
-
-static void
-mcpn765_reset_board(void)
-{
-       local_irq_disable();
-
-       /* set VIA IDE controller into native mode */
-       mcpn765_set_VIA_IDE_native();
-
-       /* Set exception prefix high - to the firmware */
-       _nmask_and_or_msr(0, MSR_IP);
-
-       out_8((u_char *)MCPN765_BOARD_MODRST_REG, 0x01);
-
-       return;
-}
-
-static void
-mcpn765_restart(char *cmd)
-{
-       volatile ulong  i = 10000000;
-
-       mcpn765_reset_board();
-
-       while (i-- > 0);
-       panic("restart failed\n");
-}
-
-static void
-mcpn765_power_off(void)
-{
-       mcpn765_halt();
-       /* NOTREACHED */
-}
-
-static void
-mcpn765_halt(void)
-{
-       local_irq_disable();
-       while (1);
-       /* NOTREACHED */
-}
-
-static int
-mcpn765_show_cpuinfo(struct seq_file *m)
-{
-       seq_printf(m, "vendor\t\t: Motorola MCG\n");
-       seq_printf(m, "machine\t\t: MCPN765\n");
-
-       return 0;
-}
-
-/*
- * Set BAT 3 to map 0xf0000000 to end of physical memory space.
- */
-static __inline__ void
-mcpn765_set_bat(void)
-{
-       mb();
-       mtspr(SPRN_DBAT1U, 0xfe8000fe);
-       mtspr(SPRN_DBAT1L, 0xfe80002a);
-       mb();
-}
-
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
-               unsigned long r6, unsigned long r7)
-{
-       parse_bootinfo(find_bootinfo());
-
-       /* Map in board regs, etc. */
-       mcpn765_set_bat();
-
-       isa_mem_base = MCPN765_ISA_MEM_BASE;
-       pci_dram_offset = MCPN765_PCI_DRAM_OFFSET;
-       ISA_DMA_THRESHOLD = 0x00ffffff;
-       DMA_MODE_READ = 0x44;
-       DMA_MODE_WRITE = 0x48;
-
-       ppc_md.setup_arch = mcpn765_setup_arch;
-       ppc_md.show_cpuinfo = mcpn765_show_cpuinfo;
-       ppc_md.irq_canonicalize = mcpn765_irq_canonicalize;
-       ppc_md.init_IRQ = mcpn765_init_IRQ;
-       ppc_md.get_irq = openpic_get_irq;
-       ppc_md.init = mcpn765_init2;
-
-       ppc_md.restart = mcpn765_restart;
-       ppc_md.power_off = mcpn765_power_off;
-       ppc_md.halt = mcpn765_halt;
-
-       ppc_md.find_end_of_memory = mcpn765_find_end_of_memory;
-       ppc_md.setup_io_mappings = mcpn765_map_io;
-
-       ppc_md.time_init = todc_time_init;
-       ppc_md.set_rtc_time = todc_set_rtc_time;
-       ppc_md.get_rtc_time = todc_get_rtc_time;
-       ppc_md.calibrate_decr = todc_calibrate_decr;
-
-       ppc_md.nvram_read_val = todc_m48txx_read_val;
-       ppc_md.nvram_write_val = todc_m48txx_write_val;
-
-       ppc_md.heartbeat = NULL;
-       ppc_md.heartbeat_reset = 0;
-       ppc_md.heartbeat_count = 0;
-
-#ifdef CONFIG_SERIAL_TEXT_DEBUG
-       ppc_md.progress = gen550_progress;
-#endif
-#ifdef CONFIG_KGDB
-       ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
-#endif
-
-       return;
-}
diff --git a/arch/ppc/platforms/mcpn765.h b/arch/ppc/platforms/mcpn765.h
deleted file mode 100644 (file)
index 4d35eca..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * arch/ppc/platforms/mcpn765.h
- *
- * Definitions for Motorola MCG MCPN765 cPCI Board.
- *
- * Author: Mark A. Greer
- *         mgreer@mvista.com
- *
- * 2001-2004 (c) MontaVista, Software, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-/*
- * From Processor to PCI:
- *   PCI Mem Space: 0x80000000 - 0xc0000000 -> 0x80000000 - 0xc0000000 (1 GB)
- *   PCI I/O Space: 0xfd800000 - 0xfe000000 -> 0x00000000 - 0x00800000 (8 MB)
- *     Note: Must skip 0xfe000000-0xfe400000 for CONFIG_HIGHMEM/PKMAP area
- *   MPIC in PCI Mem Space: 0xfe800000 - 0xfe830000 (not all used by MPIC)
- *
- * From PCI to Processor:
- *   System Memory: 0x00000000 -> 0x00000000
- */
-
-#ifndef __PPC_PLATFORMS_MCPN765_H
-#define __PPC_PLATFORMS_MCPN765_H
-#include <linux/config.h>
-
-/* PCI Memory space mapping info */
-#define        MCPN765_PCI_MEM_SIZE            0x40000000U
-#define MCPN765_PROC_PCI_MEM_START     0x80000000U
-#define MCPN765_PROC_PCI_MEM_END       (MCPN765_PROC_PCI_MEM_START +   \
-                                        MCPN765_PCI_MEM_SIZE - 1)
-#define MCPN765_PCI_MEM_START          0x80000000U
-#define MCPN765_PCI_MEM_END            (MCPN765_PCI_MEM_START +        \
-                                        MCPN765_PCI_MEM_SIZE - 1)
-
-/* PCI I/O space mapping info */
-#define        MCPN765_PCI_IO_SIZE             0x00800000U
-#define MCPN765_PROC_PCI_IO_START      0xfd800000U
-#define MCPN765_PROC_PCI_IO_END                (MCPN765_PROC_PCI_IO_START +    \
-                                        MCPN765_PCI_IO_SIZE - 1)
-#define MCPN765_PCI_IO_START           0x00000000U
-#define MCPN765_PCI_IO_END             (MCPN765_PCI_IO_START +         \
-                                        MCPN765_PCI_IO_SIZE - 1)
-
-/* System memory mapping info */
-#define MCPN765_PCI_DRAM_OFFSET                0x00000000U
-#define MCPN765_PCI_PHY_MEM_OFFSET     0x00000000U
-
-#define MCPN765_ISA_MEM_BASE           0x00000000U
-#define MCPN765_ISA_IO_BASE            MCPN765_PROC_PCI_IO_START
-
-/* Define base addresses for important sets of registers */
-#define MCPN765_HAWK_MPIC_BASE         0xfe800000U
-#define MCPN765_HAWK_SMC_BASE          0xfef80000U
-#define        MCPN765_HAWK_PPC_REG_BASE       0xfeff0000U
-
-/* Define MCPN765 board register addresses. */
-#define        MCPN765_BOARD_STATUS_REG        0xfef88080U
-#define        MCPN765_BOARD_MODFAIL_REG       0xfef88090U
-#define        MCPN765_BOARD_MODRST_REG        0xfef880a0U
-#define        MCPN765_BOARD_TBEN_REG          0xfef880c0U
-#define        MCPN765_BOARD_GEOGRAPHICAL_REG  0xfef880e8U
-#define        MCPN765_BOARD_EXT_FEATURE_REG   0xfef880f0U
-#define        MCPN765_BOARD_LAST_RESET_REG    0xfef880f8U
-
-/* Defines for UART */
-
-/* Define the UART base addresses */
-#define        MCPN765_SERIAL_1                0xfef88000
-#define        MCPN765_SERIAL_2                0xfef88200
-#define        MCPN765_SERIAL_3                0xfef88400
-#define        MCPN765_SERIAL_4                0xfef88600
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define RS_TABLE_SIZE  64
-#else
-#define RS_TABLE_SIZE  4
-#endif
-
-/* Rate for the 1.8432 Mhz clock for the onboard serial chip */
-#define BASE_BAUD      ( 1843200 / 16 )
-#define UART_CLK       1843200
-
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
-#endif
-
-/* All UART IRQ's are wire-OR'd to IRQ 17 */
-#define STD_SERIAL_PORT_DFNS \
-        { 0, BASE_BAUD, MCPN765_SERIAL_1, 17, STD_COM_FLAGS, /* ttyS0 */\
-               iomem_base: (u8 *)MCPN765_SERIAL_1,                     \
-               iomem_reg_shift: 4,                                     \
-               io_type: SERIAL_IO_MEM },                               \
-        { 0, BASE_BAUD, MCPN765_SERIAL_2, 17, STD_COM_FLAGS, /* ttyS1 */\
-               iomem_base: (u8 *)MCPN765_SERIAL_2,                     \
-               iomem_reg_shift: 4,                                     \
-               io_type: SERIAL_IO_MEM },                               \
-        { 0, BASE_BAUD, MCPN765_SERIAL_3, 17, STD_COM_FLAGS, /* ttyS2 */\
-               iomem_base: (u8 *)MCPN765_SERIAL_3,                     \
-               iomem_reg_shift: 4,                                     \
-               io_type: SERIAL_IO_MEM },                               \
-        { 0, BASE_BAUD, MCPN765_SERIAL_4, 17, STD_COM_FLAGS, /* ttyS3 */\
-               iomem_base: (u8 *)MCPN765_SERIAL_4,                     \
-               iomem_reg_shift: 4,                                     \
-               io_type: SERIAL_IO_MEM },
-
-#define SERIAL_PORT_DFNS \
-        STD_SERIAL_PORT_DFNS
-
-/* Define the NVRAM/RTC address strobe & data registers */
-#define MCPN765_PHYS_NVRAM_AS0          0xfef880c8U
-#define MCPN765_PHYS_NVRAM_AS1          0xfef880d0U
-#define MCPN765_PHYS_NVRAM_DATA         0xfef880d8U
-
-extern void mcpn765_find_bridges(void);
-
-#endif /* __PPC_PLATFORMS_MCPN765_H */
diff --git a/arch/ppc/platforms/pcore.c b/arch/ppc/platforms/pcore.c
deleted file mode 100644 (file)
index d719163..0000000
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * arch/ppc/platforms/pcore_setup.c
- *
- * Setup routines for Force PCORE boards
- *
- * Author: Matt Porter <mporter@mvista.com>
- *
- * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/config.h>
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/reboot.h>
-#include <linux/pci.h>
-#include <linux/kdev_t.h>
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/initrd.h>
-#include <linux/console.h>
-#include <linux/irq.h>
-#include <linux/seq_file.h>
-#include <linux/root_dev.h>
-
-#include <asm/io.h>
-#include <asm/machdep.h>
-#include <asm/time.h>
-#include <asm/i8259.h>
-#include <asm/mpc10x.h>
-#include <asm/todc.h>
-#include <asm/bootinfo.h>
-#include <asm/kgdb.h>
-
-#include "pcore.h"
-
-extern unsigned long loops_per_jiffy;
-
-static int board_type;
-
-static inline int __init
-pcore_6750_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-       static char pci_irq_table[][4] =
-       /*
-        *      PCI IDSEL/INTPIN->INTLINE
-        *      A       B       C       D
-        */
-       {
-               {9,     10,     11,     12},    /* IDSEL 24 - DEC 21554 */
-               {10,    0,      0,      0},     /* IDSEL 25 - DEC 21143 */
-               {11,    12,     9,      10},    /* IDSEL 26 - PMC I */
-               {12,    9,      10,     11},    /* IDSEL 27 - PMC II */
-               {0,     0,      0,      0},     /* IDSEL 28 - unused */
-               {0,     0,      9,      0},     /* IDSEL 29 - unused */
-               {0,     0,      0,      0},     /* IDSEL 30 - Winbond */
-               };
-       const long min_idsel = 24, max_idsel = 30, irqs_per_slot = 4;
-       return PCI_IRQ_TABLE_LOOKUP;
-};
-
-static inline int __init
-pcore_680_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-       static char pci_irq_table[][4] =
-       /*
-        *      PCI IDSEL/INTPIN->INTLINE
-        *      A       B       C       D
-        */
-       {
-               {9,     10,     11,     12},    /* IDSEL 24 - Sentinel */
-               {10,    0,      0,      0},     /* IDSEL 25 - i82559 #1 */
-               {11,    12,     9,      10},    /* IDSEL 26 - PMC I */
-               {12,    9,      10,     11},    /* IDSEL 27 - PMC II */
-               {9,     0,      0,      0},     /* IDSEL 28 - i82559 #2 */
-               {0,     0,      0,      0},     /* IDSEL 29 - unused */
-               {0,     0,      0,      0},     /* IDSEL 30 - Winbond */
-               };
-       const long min_idsel = 24, max_idsel = 30, irqs_per_slot = 4;
-       return PCI_IRQ_TABLE_LOOKUP;
-};
-
-void __init
-pcore_pcibios_fixup(void)
-{
-       struct pci_dev *dev;
-
-       if ((dev = pci_get_device(PCI_VENDOR_ID_WINBOND,
-                               PCI_DEVICE_ID_WINBOND_83C553,
-                               0)))
-       {
-               /* Reroute interrupts both IDE channels to 15 */
-               pci_write_config_byte(dev,
-                               PCORE_WINBOND_IDE_INT,
-                               0xff);
-
-               /* Route INTA-D to IRQ9-12, respectively */
-               pci_write_config_word(dev,
-                               PCORE_WINBOND_PCI_INT,
-                               0x9abc);
-
-               /*
-                * Set up 8259 edge/level triggering
-                */
-               outb(0x00, PCORE_WINBOND_PRI_EDG_LVL);
-               outb(0x1e, PCORE_WINBOND_SEC_EDG_LVL);
-               pci_dev_put(dev);
-       }
-}
-
-int __init
-pcore_find_bridges(void)
-{
-       struct pci_controller* hose;
-       int host_bridge, board_type;
-
-       hose = pcibios_alloc_controller();
-       if (!hose)
-               return 0;
-
-       mpc10x_bridge_init(hose,
-                       MPC10X_MEM_MAP_B,
-                       MPC10X_MEM_MAP_B,
-                       MPC10X_MAPB_EUMB_BASE);
-
-       /* Determine board type */
-       early_read_config_dword(hose,
-                       0,
-                       PCI_DEVFN(0,0),
-                       PCI_VENDOR_ID,
-                       &host_bridge);
-       if (host_bridge == MPC10X_BRIDGE_106)
-               board_type = PCORE_TYPE_6750;
-       else /* MPC10X_BRIDGE_107 */
-               board_type = PCORE_TYPE_680;
-
-       hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
-
-       ppc_md.pcibios_fixup = pcore_pcibios_fixup;
-       ppc_md.pci_swizzle = common_swizzle;
-
-       if (board_type == PCORE_TYPE_6750)
-               ppc_md.pci_map_irq = pcore_6750_map_irq;
-       else /* PCORE_TYPE_680 */
-               ppc_md.pci_map_irq = pcore_680_map_irq;
-
-       return board_type;
-}
-
-/* Dummy variable to satisfy mpc10x_common.o */
-void *OpenPIC_Addr;
-
-static int
-pcore_show_cpuinfo(struct seq_file *m)
-{
-       seq_printf(m, "vendor\t\t: Force Computers\n");
-
-       if (board_type == PCORE_TYPE_6750)
-               seq_printf(m, "machine\t\t: PowerCore 6750\n");
-       else /* PCORE_TYPE_680 */
-               seq_printf(m, "machine\t\t: PowerCore 680\n");
-
-       seq_printf(m, "L2\t\t: " );
-       if (board_type == PCORE_TYPE_6750)
-               switch (readb(PCORE_DCCR_REG) & PCORE_DCCR_L2_MASK)
-               {
-                       case PCORE_DCCR_L2_0KB:
-                               seq_printf(m, "nocache");
-                               break;
-                       case PCORE_DCCR_L2_256KB:
-                               seq_printf(m, "256KB");
-                               break;
-                       case PCORE_DCCR_L2_1MB:
-                               seq_printf(m, "1MB");
-                               break;
-                       case PCORE_DCCR_L2_512KB:
-                               seq_printf(m, "512KB");
-                               break;
-                       default:
-                               seq_printf(m, "error");
-                               break;
-               }
-       else /* PCORE_TYPE_680 */
-               switch (readb(PCORE_DCCR_REG) & PCORE_DCCR_L2_MASK)
-               {
-                       case PCORE_DCCR_L2_2MB:
-                               seq_printf(m, "2MB");
-                               break;
-                       case PCORE_DCCR_L2_256KB:
-                               seq_printf(m, "reserved");
-                               break;
-                       case PCORE_DCCR_L2_1MB:
-                               seq_printf(m, "1MB");
-                               break;
-                       case PCORE_DCCR_L2_512KB:
-                               seq_printf(m, "512KB");
-                               break;
-                       default:
-                               seq_printf(m, "error");
-                               break;
-               }
-
-       seq_printf(m, "\n");
-
-       return 0;
-}
-
-static void __init
-pcore_setup_arch(void)
-{
-       /* init to some ~sane value until calibrate_delay() runs */
-       loops_per_jiffy = 50000000/HZ;
-
-       /* Lookup PCI host bridges */
-       board_type = pcore_find_bridges();
-
-#ifdef CONFIG_BLK_DEV_INITRD
-       if (initrd_start)
-               ROOT_DEV = Root_RAM0;
-        else
-#endif
-#ifdef CONFIG_ROOT_NFS
-               ROOT_DEV = Root_NFS;
-#else
-               ROOT_DEV = Root_SDA2;
-#endif
-
-       printk(KERN_INFO "Force PowerCore ");
-       if (board_type == PCORE_TYPE_6750)
-               printk("6750\n");
-       else
-               printk("680\n");
-       printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
-       _set_L2CR(L2CR_L2E | _get_L2CR());
-
-}
-
-static void
-pcore_restart(char *cmd)
-{
-       local_irq_disable();
-       /* Hard reset */
-       writeb(0x11, 0xfe000332);
-       while(1);
-}
-
-static void
-pcore_halt(void)
-{
-       local_irq_disable();
-       /* Turn off user LEDs */
-       writeb(0x00, 0xfe000300);
-       while (1);
-}
-
-static void
-pcore_power_off(void)
-{
-       pcore_halt();
-}
-
-
-static void __init
-pcore_init_IRQ(void)
-{
-       int i;
-
-       for ( i = 0 ; i < 16 ; i++ )
-               irq_desc[i].handler = &i8259_pic;
-
-       i8259_init(0);
-}
-
-/*
- * Set BAT 3 to map 0xf0000000 to end of physical memory space.
- */
-static __inline__ void
-pcore_set_bat(void)
-{
-       mb();
-       mtspr(SPRN_DBAT3U, 0xf0001ffe);
-       mtspr(SPRN_DBAT3L, 0xfe80002a);
-       mb();
-
-}
-
-static unsigned long __init
-pcore_find_end_of_memory(void)
-{
-
-       return mpc10x_get_mem_size(MPC10X_MEM_MAP_B);
-}
-
-static void __init
-pcore_map_io(void)
-{
-       io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO);
-}
-
-TODC_ALLOC();
-
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
-               unsigned long r6, unsigned long r7)
-{
-       parse_bootinfo(find_bootinfo());
-
-       /* Cover I/O space with a BAT */
-       /* yuck, better hope your ram size is a power of 2  -- paulus */
-       pcore_set_bat();
-
-       isa_io_base = MPC10X_MAPB_ISA_IO_BASE;
-       isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE;
-       pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET;
-
-       ppc_md.setup_arch       = pcore_setup_arch;
-       ppc_md.show_cpuinfo     = pcore_show_cpuinfo;
-       ppc_md.init_IRQ         = pcore_init_IRQ;
-       ppc_md.get_irq          = i8259_irq;
-
-       ppc_md.find_end_of_memory = pcore_find_end_of_memory;
-       ppc_md.setup_io_mappings = pcore_map_io;
-
-       ppc_md.restart          = pcore_restart;
-       ppc_md.power_off        = pcore_power_off;
-       ppc_md.halt             = pcore_halt;
-
-       TODC_INIT(TODC_TYPE_MK48T59,
-                 PCORE_NVRAM_AS0,
-                 PCORE_NVRAM_AS1,
-                 PCORE_NVRAM_DATA,
-                 8);
-
-       ppc_md.time_init        = todc_time_init;
-       ppc_md.get_rtc_time     = todc_get_rtc_time;
-       ppc_md.set_rtc_time     = todc_set_rtc_time;
-       ppc_md.calibrate_decr   = todc_calibrate_decr;
-
-       ppc_md.nvram_read_val   = todc_m48txx_read_val;
-       ppc_md.nvram_write_val  = todc_m48txx_write_val;
-
-#ifdef CONFIG_SERIAL_TEXT_DEBUG
-       ppc_md.progress = gen550_progress;
-#endif
-#ifdef CONFIG_KGDB
-       ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
-#endif
-}
diff --git a/arch/ppc/platforms/pcore.h b/arch/ppc/platforms/pcore.h
deleted file mode 100644 (file)
index c6a26e7..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * arch/ppc/platforms/pcore.h
- *
- * Definitions for Force PowerCore board support
- *
- * Author: Matt Porter <mporter@mvista.com>
- *
- * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef __PPC_PLATFORMS_PCORE_H
-#define __PPC_PLATFORMS_PCORE_H
-
-#include <asm/mpc10x.h>
-
-#define PCORE_TYPE_6750                        1
-#define PCORE_TYPE_680                 2
-
-#define PCORE_NVRAM_AS0                        0x73
-#define PCORE_NVRAM_AS1                        0x75
-#define PCORE_NVRAM_DATA               0x77
-
-#define PCORE_DCCR_REG                 (MPC10X_MAPB_ISA_IO_BASE + 0x308)
-#define PCORE_DCCR_L2_MASK             0xc0
-#define PCORE_DCCR_L2_0KB              0x00
-#define PCORE_DCCR_L2_256KB            0x40
-#define PCORE_DCCR_L2_512KB            0xc0
-#define PCORE_DCCR_L2_1MB              0x80
-#define PCORE_DCCR_L2_2MB              0x00
-
-#define PCORE_WINBOND_IDE_INT          0x43
-#define PCORE_WINBOND_PCI_INT          0x44
-#define PCORE_WINBOND_PRI_EDG_LVL      0x4d0
-#define PCORE_WINBOND_SEC_EDG_LVL      0x4d1
-
-#endif /* __PPC_PLATFORMS_PCORE_H */
index 9f92e1bb7f346b00ea715354da8fbd87081a22fe..2ce058895e039438d70d5a0964bd111356c243e5 100644 (file)
@@ -619,7 +619,7 @@ not_found:
        return viaint;
 }
 
-static int pmacpic_suspend(struct sys_device *sysdev, u32 state)
+static int pmacpic_suspend(struct sys_device *sysdev, pm_message_t state)
 {
        int viaint = pmacpic_find_viaint();
 
diff --git a/arch/ppc/platforms/spd8xx.h b/arch/ppc/platforms/spd8xx.h
deleted file mode 100644 (file)
index ed48d14..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Speech Design SPD8xxTS board specific definitions
- *
- * Copyright (c) 2000,2001 Wolfgang Denk (wd@denx.de)
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_SPD8XX_H__
-#define __ASM_SPD8XX_H__
-
-#include <linux/config.h>
-
-#include <asm/ppcboot.h>
-
-#ifndef __ASSEMBLY__
-#define SPD_IMMR_BASE  0xFFF00000      /* phys. addr of IMMR */
-#define SPD_IMAP_SIZE  (64 * 1024)     /* size of mapped area */
-
-#define IMAP_ADDR      SPD_IMMR_BASE   /* physical base address of IMMR area */
-#define IMAP_SIZE      SPD_IMAP_SIZE   /* mapped size of IMMR area */
-
-#define PCMCIA_MEM_ADDR        ((uint)0xFE100000)
-#define PCMCIA_MEM_SIZE        ((uint)(64 * 1024))
-
-#define IDE0_INTERRUPT 10              /* = IRQ5 */
-#define IDE1_INTERRUPT 12              /* = IRQ6 */
-#define CPM_INTERRUPT  13              /* = SIU_LEVEL6 (was: SIU_LEVEL2) */
-
-/* override the default number of IDE hardware interfaces */
-#define MAX_HWIFS      2
-
-/*
- * Definitions for IDE0 Interface
- */
-#define IDE0_BASE_OFFSET               0x0000  /* Offset in PCMCIA memory */
-#define IDE0_DATA_REG_OFFSET           0x0000
-#define IDE0_ERROR_REG_OFFSET          0x0081
-#define IDE0_NSECTOR_REG_OFFSET                0x0082
-#define IDE0_SECTOR_REG_OFFSET         0x0083
-#define IDE0_LCYL_REG_OFFSET           0x0084
-#define IDE0_HCYL_REG_OFFSET           0x0085
-#define IDE0_SELECT_REG_OFFSET         0x0086
-#define IDE0_STATUS_REG_OFFSET         0x0087
-#define IDE0_CONTROL_REG_OFFSET                0x0106
-#define IDE0_IRQ_REG_OFFSET            0x000A  /* not used */
-
-/*
- * Definitions for IDE1 Interface
- */
-#define IDE1_BASE_OFFSET               0x0C00  /* Offset in PCMCIA memory */
-#define IDE1_DATA_REG_OFFSET           0x0000
-#define IDE1_ERROR_REG_OFFSET          0x0081
-#define IDE1_NSECTOR_REG_OFFSET                0x0082
-#define IDE1_SECTOR_REG_OFFSET         0x0083
-#define IDE1_LCYL_REG_OFFSET           0x0084
-#define IDE1_HCYL_REG_OFFSET           0x0085
-#define IDE1_SELECT_REG_OFFSET         0x0086
-#define IDE1_STATUS_REG_OFFSET         0x0087
-#define IDE1_CONTROL_REG_OFFSET                0x0106
-#define IDE1_IRQ_REG_OFFSET            0x000A  /* not used */
-
-/* CPM Ethernet through SCCx.
- *
- * Bits in parallel I/O port registers that have to be set/cleared
- * to configure the pins for SCC2 use.
- */
-#define PA_ENET_MDC    ((ushort)0x0001)        /* PA 15 !!! */
-#define PA_ENET_MDIO   ((ushort)0x0002)        /* PA 14 !!! */
-#define PA_ENET_RXD    ((ushort)0x0004)        /* PA 13 */
-#define PA_ENET_TXD    ((ushort)0x0008)        /* PA 12 */
-#define PA_ENET_RCLK   ((ushort)0x0200)        /* PA  6 */
-#define PA_ENET_TCLK   ((ushort)0x0400)        /* PA  5 */
-
-#define PB_ENET_TENA   ((uint)0x00002000)      /* PB 18 */
-
-#define PC_ENET_CLSN   ((ushort)0x0040)        /* PC  9 */
-#define PC_ENET_RENA   ((ushort)0x0080)        /* PC  8 */
-#define PC_ENET_RESET  ((ushort)0x0100)        /* PC  7 !!! */
-
-/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK2) to
- * SCC2.  Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero.
- */
-#define SICR_ENET_MASK ((uint)0x0000ff00)
-#define SICR_ENET_CLKRT        ((uint)0x00002E00)
-
-/* We don't use the 8259.
-*/
-#define NR_8259_INTS   0
-
-#endif /* !__ASSEMBLY__ */
-#endif /* __ASM_SPD8XX_H__ */
-#endif /* __KERNEL__ */
index 2150dc87b18f2cb607a1a223df8eeb2ba1428f0e..43ac064ebe5afca4099081157daa241d0b17b64c 100644 (file)
@@ -147,29 +147,6 @@ static __inline__ void ide_led(int on)
 #define SICR_ENET_CLKRT        ((uint)0x00002600)
 #endif /* CONFIG_FPS850L */
 
-/***  SM850  *********************************************************/
-
-/* The SM850 Service Module uses SCC2 for IrDA and SCC3 for Ethernet */
-
-#ifdef CONFIG_SM850
-#define PB_ENET_RXD    ((uint)0x00000004)      /* PB 29 */
-#define PB_ENET_TXD    ((uint)0x00000002)      /* PB 30 */
-#define PA_ENET_RCLK   ((ushort)0x0100)        /* PA  7 */
-#define PA_ENET_TCLK   ((ushort)0x0400)        /* PA  5 */
-
-#define PC_ENET_LBK    ((ushort)0x0008)        /* PC 12 */
-#define PC_ENET_TENA   ((ushort)0x0004)        /* PC 13 */
-
-#define PC_ENET_RENA   ((ushort)0x0800)        /* PC  4 */
-#define PC_ENET_CLSN   ((ushort)0x0400)        /* PC  5 */
-
-/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to
- * SCC3.  Also, make sure GR3 (bit 8) and SC3 (bit 9) are zero.
- */
-#define SICR_ENET_MASK ((uint)0x00FF0000)
-#define SICR_ENET_CLKRT        ((uint)0x00260000)
-#endif /* CONFIG_SM850 */
-
 /* We don't use the 8259.
 */
 #define NR_8259_INTS   0
index 220a65ab0a51f608089e7a49941aae852937a096..8b9b226005d125c0e130d8fb9f29a59cbf414a1a 100644 (file)
@@ -43,8 +43,6 @@ obj-$(CONFIG_PPC_PMAC)                += open_pic.o indirect_pci.o
 obj-$(CONFIG_POWER4)           += open_pic2.o
 obj-$(CONFIG_PPC_CHRP)         += open_pic.o indirect_pci.o i8259.o
 obj-$(CONFIG_PPC_PREP)         += open_pic.o indirect_pci.o i8259.o todc_time.o
-obj-$(CONFIG_ADIR)             += i8259.o indirect_pci.o pci_auto.o \
-                                       todc_time.o
 obj-$(CONFIG_BAMBOO)           += indirect_pci.o pci_auto.o todc_time.o
 obj-$(CONFIG_CPCI690)          += todc_time.o pci_auto.o
 obj-$(CONFIG_EBONY)            += indirect_pci.o pci_auto.o todc_time.o
@@ -52,16 +50,10 @@ obj-$(CONFIG_EV64260)               += todc_time.o pci_auto.o
 obj-$(CONFIG_CHESTNUT)         += mv64360_pic.o pci_auto.o
 obj-$(CONFIG_GEMINI)           += open_pic.o indirect_pci.o
 obj-$(CONFIG_GT64260)          += gt64260_pic.o
-obj-$(CONFIG_K2)               += i8259.o indirect_pci.o todc_time.o \
-                                       pci_auto.o
 obj-$(CONFIG_LOPEC)            += i8259.o pci_auto.o todc_time.o
 obj-$(CONFIG_HDPU)             += pci_auto.o
 obj-$(CONFIG_LUAN)             += indirect_pci.o pci_auto.o todc_time.o
 obj-$(CONFIG_KATANA)           += pci_auto.o
-obj-$(CONFIG_MCPN765)          += todc_time.o indirect_pci.o pci_auto.o \
-                                       open_pic.o i8259.o hawk_common.o
-obj-$(CONFIG_MENF1)            += todc_time.o i8259.o mpc10x_common.o \
-                                       pci_auto.o indirect_pci.o
 obj-$(CONFIG_MV64360)          += mv64360_pic.o
 obj-$(CONFIG_MV64X60)          += mv64x60.o mv64x60_win.o indirect_pci.o
 obj-$(CONFIG_MVME5100)         += open_pic.o todc_time.o indirect_pci.o \
@@ -69,7 +61,6 @@ obj-$(CONFIG_MVME5100)                += open_pic.o todc_time.o indirect_pci.o \
 obj-$(CONFIG_MVME5100_IPMC761_PRESENT) += i8259.o
 obj-$(CONFIG_OCOTEA)           += indirect_pci.o pci_auto.o todc_time.o
 obj-$(CONFIG_PAL4)             += cpc700_pic.o
-obj-$(CONFIG_PCORE)            += todc_time.o i8259.o pci_auto.o
 obj-$(CONFIG_POWERPMC250)      += pci_auto.o
 obj-$(CONFIG_PPLUS)            += hawk_common.o open_pic.o i8259.o \
                                   indirect_pci.o todc_time.o pci_auto.o
@@ -82,7 +73,8 @@ obj-$(CONFIG_SANDPOINT)               += i8259.o pci_auto.o todc_time.o
 obj-$(CONFIG_SBC82xx)          += todc_time.o
 obj-$(CONFIG_SPRUCE)           += cpc700_pic.o indirect_pci.o pci_auto.o \
                                   todc_time.o
-obj-$(CONFIG_8260)             += m8260_setup.o
+obj-$(CONFIG_8260)             += m8260_setup.o pq2_devices.o pq2_sys.o \
+                                  ppc_sys.o
 obj-$(CONFIG_PCI_8260)         += m82xx_pci.o indirect_pci.o pci_auto.o
 obj-$(CONFIG_8260_PCI9)                += m8260_pci_erratum9.o
 obj-$(CONFIG_CPM2)             += cpm2_common.o cpm2_pic.o
index a3702cfe8f7c70ff25c546b76f8b8cddc01e47eb..4c888da89b3c117c4aa709fc94a36b1165a7e150 100644 (file)
@@ -57,7 +57,7 @@ unsigned char __res[sizeof(bd_t)];
 extern void m8xx_ide_init(void);
 
 extern unsigned long find_available_memory(void);
-extern void m8xx_cpm_reset();
+extern void m8xx_cpm_reset(void);
 extern void m8xx_wdt_handler_install(bd_t *bp);
 extern void rpxfb_alloc_pages(void);
 extern void cpm_interrupt_init(void);
@@ -266,8 +266,8 @@ m8xx_show_percpuinfo(struct seq_file *m, int i)
 
        bp = (bd_t *)__res;
 
-       seq_printf(m, "clock\t\t: %ldMHz\n"
-                  "bus clock\t: %ldMHz\n",
+       seq_printf(m, "clock\t\t: %uMHz\n"
+                  "bus clock\t: %uMHz\n",
                   bp->bi_intfreq / 1000000,
                   bp->bi_busfreq / 1000000);
 
index 74d8996418e942ae3c67c9b8bf0509491185a650..8356da4678a2d49d8510b73680f5941042c44143 100644 (file)
@@ -366,10 +366,16 @@ mv64360_pci_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
+/*
+ * Bit 0 of MV64x60_PCIx_ERR_MASK does not exist on the 64360 and because of
+ * errata FEr-#11 and FEr-##16 for the 64460, it should be 0 on that chip as
+ * well.  IOW, don't set bit 0.
+ */
+#define MV64360_PCI0_ERR_MASK_VAL      0x00a50c24
+
 static int __init
 mv64360_register_hdlrs(void)
 {
-       u32     mask;
        int     rc;
 
        /* Clear old errors and register CPU interface error intr handler */
@@ -387,17 +393,6 @@ mv64360_register_hdlrs(void)
                mv64360_sram_error_int_handler,SA_INTERRUPT,SRAM_INTR_STR, 0)))
                printk(KERN_WARNING "Can't register SRAM error handler: %d",rc);
 
-       /*
-        * Bit 0 reserved on 64360 and erratum FEr PCI-#11 (PCI internal
-        * data parity error set incorrectly) on rev 0 & 1 of 64460 requires
-        * bit 0 to be cleared.
-        */
-       mask = 0x00a50c24;
-
-       if ((mv64x60_get_bridge_type() == MV64x60_TYPE_MV64460) &&
-               (mv64x60_get_bridge_rev() > 1))
-               mask |= 0x1;    /* enable DPErr on 64460 */
-
        /* Clear old errors and register PCI 0 error intr handler */
        mv64x60_write(&bh, MV64x60_PCI0_ERR_CAUSE, 0);
        if ((rc = request_irq(MV64360_IRQ_PCI0 + mv64360_irq_base,
@@ -407,7 +402,11 @@ mv64360_register_hdlrs(void)
                        rc);
 
        mv64x60_write(&bh, MV64x60_PCI0_ERR_MASK, 0);
-       mv64x60_write(&bh, MV64x60_PCI0_ERR_MASK, mask);
+       mv64x60_write(&bh, MV64x60_PCI0_ERR_MASK, MV64360_PCI0_ERR_MASK_VAL);
+
+       /* Erratum FEr PCI-#16 says to clear bit 0 of PCI SERRn Mask reg. */
+       mv64x60_write(&bh, MV64x60_PCI0_ERR_SERR_MASK,
+               mv64x60_read(&bh, MV64x60_PCI0_ERR_SERR_MASK) & ~0x1UL);
 
        /* Clear old errors and register PCI 1 error intr handler */
        mv64x60_write(&bh, MV64x60_PCI1_ERR_CAUSE, 0);
@@ -418,7 +417,11 @@ mv64360_register_hdlrs(void)
                        rc);
 
        mv64x60_write(&bh, MV64x60_PCI1_ERR_MASK, 0);
-       mv64x60_write(&bh, MV64x60_PCI1_ERR_MASK, mask);
+       mv64x60_write(&bh, MV64x60_PCI1_ERR_MASK, MV64360_PCI0_ERR_MASK_VAL);
+
+       /* Erratum FEr PCI-#16 says to clear bit 0 of PCI Intr Mask reg. */
+       mv64x60_write(&bh, MV64x60_PCI1_ERR_SERR_MASK,
+               mv64x60_read(&bh, MV64x60_PCI1_ERR_SERR_MASK) & ~0x1UL);
 
        return 0;
 }
index cc77177fa1c620eb6aad9efb5f1776a8d0b816cb..6262b11f366f713eaf228ca10bb6e77ef206bb82 100644 (file)
 #include <asm/mv64x60.h>
 
 
-u8             mv64x60_pci_exclude_bridge = 1;
+u8 mv64x60_pci_exclude_bridge = 1;
 spinlock_t     mv64x60_lock = SPIN_LOCK_UNLOCKED;
 
-static phys_addr_t     mv64x60_bridge_pbase = 0;
-static void            *mv64x60_bridge_vbase = 0;
+static phys_addr_t     mv64x60_bridge_pbase;
+static void            *mv64x60_bridge_vbase;
 static u32             mv64x60_bridge_type = MV64x60_TYPE_INVALID;
-static u32             mv64x60_bridge_rev = 0;
+static u32             mv64x60_bridge_rev;
+#if defined(CONFIG_SYSFS) && !defined(CONFIG_GT64260)
+static struct pci_controller   sysfs_hose_a;
+#endif
 
 static u32 gt64260_translate_size(u32 base, u32 size, u32 num_bits);
 static u32 gt64260_untranslate_size(u32 base, u32 size, u32 num_bits);
@@ -432,6 +435,20 @@ static struct platform_device i2c_device = {
 };
 #endif
 
+#if defined(CONFIG_SYSFS) && !defined(CONFIG_GT64260)
+static struct mv64xxx_pdata mv64xxx_pdata = {
+       .hs_reg_valid   = 0,
+};
+
+static struct platform_device mv64xxx_device = { /* general mv64x60 stuff */
+       .name   = MV64XXX_DEV_NAME,
+       .id     = 0,
+       .dev = {
+               .platform_data = &mv64xxx_pdata,
+       },
+};
+#endif
+
 static struct platform_device *mv64x60_pd_devs[] __initdata = {
 #ifdef CONFIG_SERIAL_MPSC
        &mpsc_shared_device,
@@ -453,6 +470,9 @@ static struct platform_device *mv64x60_pd_devs[] __initdata = {
 #ifdef CONFIG_I2C_MV64XXX
        &i2c_device,
 #endif
+#if defined(CONFIG_SYSFS) && !defined(CONFIG_GT64260)
+       &mv64xxx_device,
+#endif
 };
 
 /*
@@ -574,6 +594,11 @@ mv64x60_early_init(struct mv64x60_handle *bh, struct mv64x60_setup_info *si)
        bh->hose_a = &hose_a;
        bh->hose_b = &hose_b;
 
+#if defined(CONFIG_SYSFS) && !defined(CONFIG_GT64260)
+       /* Save a copy of hose_a for sysfs functions -- hack */
+       memcpy(&sysfs_hose_a, &hose_a, sizeof(hose_a));
+#endif
+
        mv64x60_set_bus(bh, 0, 0);
        mv64x60_set_bus(bh, 1, 0);
 
@@ -590,8 +615,6 @@ mv64x60_early_init(struct mv64x60_handle *bh, struct mv64x60_setup_info *si)
 
        mv64x60_set_bits(bh, MV64x60_PCI0_TO_RETRY, 0xffff);
        mv64x60_set_bits(bh, MV64x60_PCI1_TO_RETRY, 0xffff);
-
-       return;
 }
 
 /*
@@ -628,19 +651,15 @@ mv64x60_get_32bit_window(struct mv64x60_handle *bh, u32 window,
                        val = mv64x60_read(bh, size_reg);
                        val = get_from_field(val, size_bits);
                        *size = bh->ci->untranslate_size(*base, val, size_bits);
-               }
-               else
+               } else
                        *size = 0;
-       }
-       else {
+       } else {
                *base = 0;
                *size = 0;
        }
 
        pr_debug("get 32bit window: %d, base: 0x%x, size: 0x%x\n",
                window, *base, *size);
-
-       return;
 }
 
 /*
@@ -677,8 +696,6 @@ mv64x60_set_32bit_window(struct mv64x60_handle *bh, u32 window,
 
                (void)mv64x60_read(bh, base_reg); /* Flush FIFO */
        }
-
-       return;
 }
 
 /*
@@ -712,11 +729,9 @@ mv64x60_get_64bit_window(struct mv64x60_handle *bh, u32 window,
                        val = get_from_field(val, size_bits);
                        *size = bh->ci->untranslate_size(*base_lo, val,
                                                                size_bits);
-               }
-               else
+               } else
                        *size = 0;
-       }
-       else {
+       } else {
                *base_hi = 0;
                *base_lo = 0;
                *size = 0;
@@ -724,8 +739,6 @@ mv64x60_get_64bit_window(struct mv64x60_handle *bh, u32 window,
 
        pr_debug("get 64bit window: %d, base hi: 0x%x, base lo: 0x%x, "
                "size: 0x%x\n", window, *base_hi, *base_lo, *size);
-
-       return;
 }
 
 /*
@@ -766,8 +779,6 @@ mv64x60_set_64bit_window(struct mv64x60_handle *bh, u32 window,
 
                (void)mv64x60_read(bh, base_lo_reg); /* Flush FIFO */
        }
-
-       return;
 }
 
 /*
@@ -1008,8 +1019,6 @@ mv64x60_get_mem_windows(struct mv64x60_handle *bh,
                        mem_windows[i][0] = 0;
                        mem_windows[i][1] = 0;
                }
-
-       return;
 }
 
 /*
@@ -1077,8 +1086,6 @@ mv64x60_config_cpu2mem_windows(struct mv64x60_handle *bh,
                        }
 
                }
-
-       return;
 }
 
 /*
@@ -1112,8 +1119,7 @@ mv64x60_config_cpu2pci_windows(struct mv64x60_handle *bh,
                mv64x60_set_32bit_window(bh, remap_tab[bus][0],
                        pi->pci_io.pci_base_lo, 0, 0);
                bh->ci->enable_window_32bit(bh, win_tab[bus][0]);
-       }
-       else /* Actually, the window should already be disabled */
+       } else /* Actually, the window should already be disabled */
                bh->ci->disable_window_32bit(bh, win_tab[bus][0]);
 
        for (i=0; i<3; i++)
@@ -1125,11 +1131,8 @@ mv64x60_config_cpu2pci_windows(struct mv64x60_handle *bh,
                                pi->pci_mem[i].pci_base_hi,
                                pi->pci_mem[i].pci_base_lo, 0, 0);
                        bh->ci->enable_window_32bit(bh, win_tab[bus][i+1]);
-               }
-               else /* Actually, the window should already be disabled */
+               } else /* Actually, the window should already be disabled */
                        bh->ci->disable_window_32bit(bh, win_tab[bus][i+1]);
-
-       return;
 }
 
 /*
@@ -1206,8 +1209,6 @@ mv64x60_config_pci2mem_windows(struct mv64x60_handle *bh,
                                MV64x60_PCI0_BAR_ENABLE :
                                MV64x60_PCI1_BAR_ENABLE), (1 << i));
                }
-
-       return;
 }
 
 /*
@@ -1229,7 +1230,6 @@ mv64x60_alloc_hose(struct mv64x60_handle *bh, u32 cfg_addr, u32 cfg_data,
        *hose = pcibios_alloc_controller();
        setup_indirect_pci_nomap(*hose, bh->v_base + cfg_addr,
                bh->v_base + cfg_data);
-       return;
 }
 
 /*
@@ -1272,7 +1272,6 @@ mv64x60_config_resources(struct pci_controller *hose,
                                                pi->pci_mem[0].size - 1;
        hose->pci_mem_offset = pi->pci_mem[0].cpu_base -
                                                pi->pci_mem[0].pci_base_lo;
-       return;
 }
 
 /*
@@ -1309,7 +1308,6 @@ mv64x60_config_pci_params(struct pci_controller *hose,
        early_write_config_word(hose, 0, devfn, PCI_CACHE_LINE_SIZE, u16_val);
 
        mv64x60_pci_exclude_bridge = save_exclude;
-       return;
 }
 
 /*
@@ -1336,8 +1334,7 @@ mv64x60_set_bus(struct mv64x60_handle *bh, u32 bus, u32 child_bus)
                p2p_cfg = MV64x60_PCI0_P2P_CONFIG;
                pci_cfg_offset = 0x64;
                hose = bh->hose_a;
-       }
-       else {
+       } else {
                pci_mode = bh->pci_mode_b;
                p2p_cfg = MV64x60_PCI1_P2P_CONFIG;
                pci_cfg_offset = 0xe4;
@@ -1352,8 +1349,7 @@ mv64x60_set_bus(struct mv64x60_handle *bh, u32 bus, u32 child_bus)
                val |= (child_bus << 16) | 0xff;
                mv64x60_write(bh, p2p_cfg, val);
                (void)mv64x60_read(bh, p2p_cfg); /* Flush FIFO */
-       }
-       else { /* PCI-X */
+       } else { /* PCI-X */
                /*
                 * Need to use the current bus/dev number (that's in the
                 * P2P CONFIG reg) to access the bridge's pci config space.
@@ -1365,8 +1361,6 @@ mv64x60_set_bus(struct mv64x60_handle *bh, u32 bus, u32 child_bus)
                        pci_cfg_offset, child_bus << 8);
                mv64x60_pci_exclude_bridge = save_exclude;
        }
-
-       return;
 }
 
 /*
@@ -1423,8 +1417,6 @@ mv64x60_pd_fixup(struct mv64x60_handle *bh, struct platform_device *pd_devs[],
                        j++;
                }
        }
-
-       return;
 }
 
 /*
@@ -1498,8 +1490,6 @@ gt64260_set_pci2mem_window(struct pci_controller *hose, u32 bus, u32 window,
        early_write_config_dword(hose, 0, PCI_DEVFN(0, 0),
                gt64260_reg_addrs[bus][window], mv64x60_mask(base, 20) | 0x8);
        mv64x60_pci_exclude_bridge = save_exclude;
-
-       return;
 }
 
 /*
@@ -1523,8 +1513,6 @@ gt64260_set_pci2regs_window(struct mv64x60_handle *bh,
        early_write_config_dword(hose, 0, PCI_DEVFN(0,0), gt64260_offset[bus],
                (base << 16));
        mv64x60_pci_exclude_bridge = save_exclude;
-
-       return;
 }
 
 /*
@@ -1561,7 +1549,6 @@ static void __init
 gt64260_enable_window_32bit(struct mv64x60_handle *bh, u32 window)
 {
        pr_debug("enable 32bit window: %d\n", window);
-       return;
 }
 
 /*
@@ -1584,8 +1571,6 @@ gt64260_disable_window_32bit(struct mv64x60_handle *bh, u32 window)
                mv64x60_write(bh, gt64260_32bit_windows[window].base_reg,0xfff);
                mv64x60_write(bh, gt64260_32bit_windows[window].size_reg, 0);
        }
-
-       return;
 }
 
 /*
@@ -1599,7 +1584,6 @@ static void __init
 gt64260_enable_window_64bit(struct mv64x60_handle *bh, u32 window)
 {
        pr_debug("enable 64bit window: %d\n", window);
-       return; /* Enabled when window configured (i.e., when top >= base) */
 }
 
 /*
@@ -1624,8 +1608,6 @@ gt64260_disable_window_64bit(struct mv64x60_handle *bh, u32 window)
                mv64x60_write(bh, gt64260_64bit_windows[window].base_hi_reg, 0);
                mv64x60_write(bh, gt64260_64bit_windows[window].size_reg, 0);
        }
-
-       return;
 }
 
 /*
@@ -1712,8 +1694,6 @@ gt64260_disable_all_windows(struct mv64x60_handle *bh,
        mv64x60_write(bh, GT64260_IC_CPU_INT_1_MASK, 0);
        mv64x60_write(bh, GT64260_IC_CPU_INT_2_MASK, 0);
        mv64x60_write(bh, GT64260_IC_CPU_INT_3_MASK, 0);
-
-       return;
 }
 
 /*
@@ -1781,14 +1761,11 @@ gt64260a_chip_specific_init(struct mv64x60_handle *bh,
        mv64x60_mpsc1_pdata.cache_mgmt = 1;
 
        if ((r = platform_get_resource(&mpsc1_device, IORESOURCE_IRQ, 0))
-               != NULL) {
-
+                       != NULL) {
                r->start = MV64x60_IRQ_SDMA_0;
                r->end = MV64x60_IRQ_SDMA_0;
        }
 #endif
-
-       return;
 }
 
 /*
@@ -1861,14 +1838,11 @@ gt64260b_chip_specific_init(struct mv64x60_handle *bh,
        mv64x60_mpsc1_pdata.cache_mgmt = 1;
 
        if ((r = platform_get_resource(&mpsc1_device, IORESOURCE_IRQ, 0))
-               != NULL) {
-
+                       != NULL) {
                r->start = MV64x60_IRQ_SDMA_0;
                r->end = MV64x60_IRQ_SDMA_0;
        }
 #endif
-
-       return;
 }
 
 /*
@@ -1945,8 +1919,6 @@ mv64360_set_pci2mem_window(struct pci_controller *hose, u32 bus, u32 window,
                mv64360_reg_addrs[bus][window].base_lo_bar,
                mv64x60_mask(base,20) | 0xc);
        mv64x60_pci_exclude_bridge = save_exclude;
-
-       return;
 }
 
 /*
@@ -1972,8 +1944,6 @@ mv64360_set_pci2regs_window(struct mv64x60_handle *bh,
        early_write_config_dword(hose, 0, PCI_DEVFN(0,0),
                mv64360_offset[bus][1], 0);
        mv64x60_pci_exclude_bridge = save_exclude;
-
-       return;
 }
 
 /*
@@ -2082,8 +2052,6 @@ mv64360_enable_window_32bit(struct mv64x60_handle *bh, u32 window)
                                "32bit table corrupted");
                }
        }
-
-       return;
 }
 
 /*
@@ -2139,8 +2107,6 @@ mv64360_disable_window_32bit(struct mv64x60_handle *bh, u32 window)
                                "32bit table corrupted");
                }
        }
-
-       return;
 }
 
 /*
@@ -2158,8 +2124,7 @@ mv64360_enable_window_64bit(struct mv64x60_handle *bh, u32 window)
                (mv64360_64bit_windows[window].size_reg != 0)) {
 
                if ((mv64360_64bit_windows[window].extra & MV64x60_EXTRA_MASK)
-                       == MV64x60_EXTRA_PCIACC_ENAB)
-
+                               == MV64x60_EXTRA_PCIACC_ENAB)
                        mv64x60_set_bits(bh,
                                mv64360_64bit_windows[window].base_lo_reg,
                                (1 << (mv64360_64bit_windows[window].extra &
@@ -2168,8 +2133,6 @@ mv64360_enable_window_64bit(struct mv64x60_handle *bh, u32 window)
                        printk(KERN_ERR "mv64360_enable: %s\n",
                                "64bit table corrupted");
        }
-
-       return;
 }
 
 /*
@@ -2186,11 +2149,9 @@ mv64360_disable_window_64bit(struct mv64x60_handle *bh, u32 window)
                mv64360_64bit_windows[window].size_reg);
 
        if ((mv64360_64bit_windows[window].base_lo_reg != 0) &&
-               (mv64360_64bit_windows[window].size_reg != 0)) {
-
+                       (mv64360_64bit_windows[window].size_reg != 0)) {
                if ((mv64360_64bit_windows[window].extra & MV64x60_EXTRA_MASK)
-                       == MV64x60_EXTRA_PCIACC_ENAB)
-
+                               == MV64x60_EXTRA_PCIACC_ENAB)
                        mv64x60_clr_bits(bh,
                                mv64360_64bit_windows[window].base_lo_reg,
                                (1 << (mv64360_64bit_windows[window].extra &
@@ -2199,8 +2160,6 @@ mv64360_disable_window_64bit(struct mv64x60_handle *bh, u32 window)
                        printk(KERN_ERR "mv64360_disable: %s\n",
                                "64bit table corrupted");
        }
-
-       return;
 }
 
 /*
@@ -2241,8 +2200,6 @@ mv64360_disable_all_windows(struct mv64x60_handle *bh,
        /* Disable all PCI-><whatever> windows */
        mv64x60_set_bits(bh, MV64x60_PCI0_BAR_ENABLE, 0x0000f9ff);
        mv64x60_set_bits(bh, MV64x60_PCI1_BAR_ENABLE, 0x0000f9ff);
-
-       return;
 }
 
 /*
@@ -2335,8 +2292,6 @@ mv64360_config_io2mem_windows(struct mv64x60_handle *bh,
                        mv64x60_set_bits(bh, MV64360_IDMA2MEM_ACC_PROT_3,
                                (0x3 << (i << 1)));
                }
-
-       return;
 }
 
 /*
@@ -2350,42 +2305,145 @@ static void __init
 mv64360_set_mpsc2regs_window(struct mv64x60_handle *bh, u32 base)
 {
        pr_debug("set mpsc->internal regs, base: 0x%x\n", base);
-
        mv64x60_write(bh, MV64360_MPSC2REGS_BASE, base & 0xffff0000);
-       return;
 }
 
 /*
  * mv64360_chip_specific_init()
  *
- * No errata work arounds for the MV64360 implemented at this point.
+ * Implement errata work arounds for the MV64360.
  */
 static void __init
 mv64360_chip_specific_init(struct mv64x60_handle *bh,
        struct mv64x60_setup_info *si)
 {
+#if !defined(CONFIG_NOT_COHERENT_CACHE)
+       mv64x60_set_bits(bh, MV64360_D_UNIT_CONTROL_HIGH, (1<<24));
+#endif
 #ifdef CONFIG_SERIAL_MPSC
        mv64x60_mpsc0_pdata.brg_can_tune = 1;
        mv64x60_mpsc0_pdata.cache_mgmt = 1;
        mv64x60_mpsc1_pdata.brg_can_tune = 1;
        mv64x60_mpsc1_pdata.cache_mgmt = 1;
 #endif
-
-       return;
 }
 
 /*
  * mv64460_chip_specific_init()
  *
- * No errata work arounds for the MV64460 implemented at this point.
+ * Implement errata work arounds for the MV64460.
  */
 static void __init
 mv64460_chip_specific_init(struct mv64x60_handle *bh,
        struct mv64x60_setup_info *si)
 {
+#if !defined(CONFIG_NOT_COHERENT_CACHE)
+       mv64x60_set_bits(bh, MV64360_D_UNIT_CONTROL_HIGH, (1<<24) | (1<<25));
+       mv64x60_set_bits(bh, MV64460_D_UNIT_MMASK, (1<<1) | (1<<4));
+#endif
 #ifdef CONFIG_SERIAL_MPSC
        mv64x60_mpsc0_pdata.brg_can_tune = 1;
+       mv64x60_mpsc0_pdata.cache_mgmt = 1;
        mv64x60_mpsc1_pdata.brg_can_tune = 1;
+       mv64x60_mpsc1_pdata.cache_mgmt = 1;
 #endif
-       return;
 }
+
+
+#if defined(CONFIG_SYSFS) && !defined(CONFIG_GT64260)
+/* Export the hotswap register via sysfs for enum event monitoring */
+#define        VAL_LEN_MAX     11 /* 32-bit hex or dec stringified number + '\n' */
+
+DECLARE_MUTEX(mv64xxx_hs_lock);
+
+static ssize_t
+mv64xxx_hs_reg_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+       u32     v;
+       u8      save_exclude;
+
+       if (off > 0)
+               return 0;
+       if (count < VAL_LEN_MAX)
+               return -EINVAL;
+
+       if (down_interruptible(&mv64xxx_hs_lock))
+               return -ERESTARTSYS;
+       save_exclude = mv64x60_pci_exclude_bridge;
+       mv64x60_pci_exclude_bridge = 0;
+       early_read_config_dword(&sysfs_hose_a, 0, PCI_DEVFN(0, 0),
+                       MV64360_PCICFG_CPCI_HOTSWAP, &v);
+       mv64x60_pci_exclude_bridge = save_exclude;
+       up(&mv64xxx_hs_lock);
+
+       return sprintf(buf, "0x%08x\n", v);
+}
+
+static ssize_t
+mv64xxx_hs_reg_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+       u32     v;
+       u8      save_exclude;
+
+       if (off > 0)
+               return 0;
+       if (count <= 0)
+               return -EINVAL;
+
+       if (sscanf(buf, "%i", &v) == 1) {
+               if (down_interruptible(&mv64xxx_hs_lock))
+                       return -ERESTARTSYS;
+               save_exclude = mv64x60_pci_exclude_bridge;
+               mv64x60_pci_exclude_bridge = 0;
+               early_write_config_dword(&sysfs_hose_a, 0, PCI_DEVFN(0, 0),
+                               MV64360_PCICFG_CPCI_HOTSWAP, v);
+               mv64x60_pci_exclude_bridge = save_exclude;
+               up(&mv64xxx_hs_lock);
+       }
+       else
+               count = -EINVAL;
+
+       return count;
+}
+
+static struct bin_attribute mv64xxx_hs_reg_attr = { /* Hotswap register */
+       .attr = {
+               .name = "hs_reg",
+               .mode = S_IRUGO | S_IWUSR,
+               .owner = THIS_MODULE,
+       },
+       .size  = VAL_LEN_MAX,
+       .read  = mv64xxx_hs_reg_read,
+       .write = mv64xxx_hs_reg_write,
+};
+
+/* Provide sysfs file indicating if this platform supports the hs_reg */
+static ssize_t
+mv64xxx_hs_reg_valid_show(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct platform_device  *pdev;
+       struct mv64xxx_pdata    *pdp;
+       u32                     v;
+
+       pdev = container_of(dev, struct platform_device, dev);
+       pdp = (struct mv64xxx_pdata *)pdev->dev.platform_data;
+
+       if (down_interruptible(&mv64xxx_hs_lock))
+               return -ERESTARTSYS;
+       v = pdp->hs_reg_valid;
+       up(&mv64xxx_hs_lock);
+
+       return sprintf(buf, "%i\n", v);
+}
+static DEVICE_ATTR(hs_reg_valid, S_IRUGO, mv64xxx_hs_reg_valid_show, NULL);
+
+static int __init
+mv64xxx_sysfs_init(void)
+{
+       sysfs_create_bin_file(&mv64xxx_device.dev.kobj, &mv64xxx_hs_reg_attr);
+       sysfs_create_file(&mv64xxx_device.dev.kobj,&dev_attr_hs_reg_valid.attr);
+       return 0;
+}
+subsys_initcall(mv64xxx_sysfs_init);
+#endif
index e5fd2ae503ea7c2240c373f022ffa0c989ad52e3..9ccce438bd7af7ffc1dce54b32377a5975140bcd 100644 (file)
@@ -165,7 +165,7 @@ ocp_device_remove(struct device *dev)
 }
 
 static int
-ocp_device_suspend(struct device *dev, u32 state)
+ocp_device_suspend(struct device *dev, pm_message_t state)
 {
        struct ocp_device *ocp_dev = to_ocp_dev(dev);
        struct ocp_driver *ocp_drv = to_ocp_drv(dev->driver);
index 1eb4f726ca9ffb09567d77489d9e5bf341f29357..da8a0f2128dccc23bc06cc8b3f8a93809384e7ec 100644 (file)
@@ -105,7 +105,7 @@ static int of_device_remove(struct device *dev)
        return 0;
 }
 
-static int of_device_suspend(struct device *dev, u32 state)
+static int of_device_suspend(struct device *dev, pm_message_t state)
 {
        struct of_device * of_dev = to_of_device(dev);
        struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
index ad39b86ca92ca545c879c951307a05c3f0404208..53da58523e39f3380e303f4f33e0ca20c32db81d 100644 (file)
@@ -948,7 +948,7 @@ static void openpic_cached_disable_irq(u_int irq)
  * we need something better to deal with that... Maybe switch to S1 for
  * cpufreq changes
  */
-int openpic_suspend(struct sys_device *sysdev, u32 state)
+int openpic_suspend(struct sys_device *sysdev, pm_message_t state)
 {
        int     i;
        unsigned long flags;
index e170aebeb69b897dc94fdcf90b5e39870cf714e1..b843c4fef25e694ba56182ff2ff68e0fe9a0b269 100644 (file)
 extern void abort(void);
 extern void ppc4xx_find_bridges(void);
 
-extern void ppc4xx_wdt_heartbeat(void);
-extern int wdt_enable;
-extern unsigned long wdt_period;
-
 /* Global Variables */
 bd_t __res;
 
@@ -171,7 +167,7 @@ ppc4xx_calibrate_decr(void)
        unsigned int freq;
        bd_t *bip = &__res;
 
-#if defined(CONFIG_WALNUT) || defined(CONFIG_ASH) || defined(CONFIG_SYCAMORE)
+#if defined(CONFIG_WALNUT) || defined(CONFIG_SYCAMORE)
        /* Walnut boot rom sets DCR CHCR1 (aka CPC0_CR1) bit CETE to 1 */
        mtdcr(DCRN_CHCR1, mfdcr(DCRN_CHCR1) & ~CHR1_CETE);
 #endif
@@ -257,22 +253,6 @@ ppc4xx_init(unsigned long r3, unsigned long r4, unsigned long r5,
                *(char *) (r7 + KERNELBASE) = 0;
                strcpy(cmd_line, (char *) (r6 + KERNELBASE));
        }
-#if defined(CONFIG_PPC405_WDT)
-/* Look for wdt= option on command line */
-       if (strstr(cmd_line, "wdt=")) {
-               int valid_wdt = 0;
-               char *p, *q;
-               for (q = cmd_line; (p = strstr(q, "wdt=")) != 0;) {
-                       q = p + 4;
-                       if (p > cmd_line && p[-1] != ' ')
-                               continue;
-                       wdt_period = simple_strtoul(q, &q, 0);
-                       valid_wdt = 1;
-                       ++q;
-               }
-               wdt_enable = valid_wdt;
-       }
-#endif
 
        /* Initialize machine-dependent vectors */
 
@@ -287,11 +267,6 @@ ppc4xx_init(unsigned long r3, unsigned long r4, unsigned long r5,
 
        ppc_md.calibrate_decr = ppc4xx_calibrate_decr;
 
-#ifdef CONFIG_PPC405_WDT
-       ppc_md.heartbeat = ppc4xx_wdt_heartbeat;
-#endif
-       ppc_md.heartbeat_count = 0;
-
        ppc_md.find_end_of_memory = ppc4xx_find_end_of_memory;
        ppc_md.setup_io_mappings = ppc4xx_map_io;
 
diff --git a/arch/ppc/syslib/ppc83xx_pci.h b/arch/ppc/syslib/ppc83xx_pci.h
new file mode 100644 (file)
index 0000000..ec69164
--- /dev/null
@@ -0,0 +1,151 @@
+/* Created by Tony Li <tony.li@freescale.com>
+ * Copyright (c) 2005 freescale semiconductor
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __PPC_SYSLIB_PPC83XX_PCI_H
+#define __PPC_SYSLIB_PPC83XX_PCI_H
+
+typedef struct immr_clk {
+       u32 spmr; /* system PLL mode Register  */
+       u32 occr; /* output clock control Register  */
+       u32 sccr; /* system clock control Register  */
+       u8 res0[0xF4];
+} immr_clk_t;
+
+/*
+ * Sequencer
+ */
+typedef struct immr_ios {
+       u32     potar0;
+       u8      res0[4];
+       u32     pobar0;
+       u8      res1[4];
+       u32     pocmr0;
+       u8      res2[4];
+       u32     potar1;
+       u8      res3[4];
+       u32     pobar1;
+       u8      res4[4];
+       u32     pocmr1;
+       u8      res5[4];
+       u32     potar2;
+       u8      res6[4];
+       u32     pobar2;
+       u8      res7[4];
+       u32     pocmr2;
+       u8      res8[4];
+       u32     potar3;
+       u8      res9[4];
+       u32     pobar3;
+       u8      res10[4];
+       u32     pocmr3;
+       u8      res11[4];
+       u32     potar4;
+       u8      res12[4];
+       u32     pobar4;
+       u8      res13[4];
+       u32     pocmr4;
+       u8      res14[4];
+       u32     potar5;
+       u8      res15[4];
+       u32     pobar5;
+       u8      res16[4];
+       u32     pocmr5;
+       u8      res17[4];
+       u8      res18[0x60];
+       u32     pmcr;
+       u8      res19[4];
+       u32     dtcr;
+       u8      res20[4];
+} immr_ios_t;
+#define POTAR_TA_MASK  0x000fffff
+#define POBAR_BA_MASK  0x000fffff
+#define POCMR_EN       0x80000000
+#define POCMR_IO       0x40000000 /* 0--memory space 1--I/O space */
+#define POCMR_SE       0x20000000 /* streaming enable */
+#define POCMR_DST      0x10000000 /* 0--PCI1 1--PCI2 */
+#define POCMR_CM_MASK  0x000fffff
+
+/*
+ * PCI Controller Control and Status Registers
+ */
+typedef struct immr_pcictrl {
+       u32     esr;
+       u32     ecdr;
+       u32     eer;
+       u32     eatcr;
+       u32     eacr;
+       u32     eeacr;
+       u32     edlcr;
+       u32     edhcr;
+       u32     gcr;
+       u32     ecr;
+       u32     gsr;
+       u8      res0[12];
+       u32     pitar2;
+       u8      res1[4];
+       u32     pibar2;
+       u32     piebar2;
+       u32     piwar2;
+       u8      res2[4];
+       u32     pitar1;
+       u8      res3[4];
+       u32     pibar1;
+       u32     piebar1;
+       u32     piwar1;
+       u8      res4[4];
+       u32     pitar0;
+       u8      res5[4];
+       u32     pibar0;
+       u8      res6[4];
+       u32     piwar0;
+       u8      res7[132];
+} immr_pcictrl_t;
+#define PITAR_TA_MASK  0x000fffff
+#define PIBAR_MASK     0xffffffff
+#define PIEBAR_EBA_MASK        0x000fffff
+#define PIWAR_EN       0x80000000
+#define PIWAR_PF       0x20000000
+#define PIWAR_RTT_MASK 0x000f0000
+#define PIWAR_RTT_NO_SNOOP     0x00040000
+#define PIWAR_RTT_SNOOP        0x00050000
+#define PIWAR_WTT_MASK 0x0000f000
+#define PIWAR_WTT_NO_SNOOP     0x00004000
+#define PIWAR_WTT_SNOOP        0x00005000
+#define PIWAR_IWS_MASK 0x0000003F
+#define PIWAR_IWS_4K   0x0000000B
+#define PIWAR_IWS_8K   0x0000000C
+#define PIWAR_IWS_16K  0x0000000D
+#define PIWAR_IWS_32K  0x0000000E
+#define PIWAR_IWS_64K  0x0000000F
+#define PIWAR_IWS_128K 0x00000010
+#define PIWAR_IWS_256K 0x00000011
+#define PIWAR_IWS_512K 0x00000012
+#define PIWAR_IWS_1M   0x00000013
+#define PIWAR_IWS_2M   0x00000014
+#define PIWAR_IWS_4M   0x00000015
+#define PIWAR_IWS_8M   0x00000016
+#define PIWAR_IWS_16M  0x00000017
+#define PIWAR_IWS_32M  0x00000018
+#define PIWAR_IWS_64M  0x00000019
+#define PIWAR_IWS_128M 0x0000001A
+#define PIWAR_IWS_256M 0x0000001B
+#define PIWAR_IWS_512M 0x0000001C
+#define PIWAR_IWS_1G   0x0000001D
+#define PIWAR_IWS_2G   0x0000001E
+
+#endif /* __PPC_SYSLIB_PPC83XX_PCI_H */
index 602a86891f7fd826cf7b38ab92a899d23f21dc4d..890484e576e79ef7af48163043869da1a727e808 100644 (file)
  * under  the terms of  the GNU General  Public License as published by the
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
+ *
+ * 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.
+ *
+ * Added PCI support -- Tony Li <tony.li@freescale.com>
  */
 
 #include <linux/config.h>
 #include <asm/delay.h>
 
 #include <syslib/ppc83xx_setup.h>
+#if defined(CONFIG_PCI)
+#include <asm/delay.h>
+#include <syslib/ppc83xx_pci.h>
+#endif
 
 phys_addr_t immrbar;
 
@@ -162,4 +177,237 @@ mpc83xx_halt(void)
        for(;;);
 }
 
-/* PCI SUPPORT DOES NOT EXIT, MODEL after ppc85xx_setup.c */
+#if defined(CONFIG_PCI)
+void __init
+mpc83xx_setup_pci1(struct pci_controller *hose)
+{
+       u16 reg16;
+       volatile immr_pcictrl_t * pci_ctrl;
+       volatile immr_ios_t * ios;
+       bd_t *binfo = (bd_t *) __res;
+
+       pci_ctrl = ioremap(binfo->bi_immr_base + 0x8500, sizeof(immr_pcictrl_t));
+       ios = ioremap(binfo->bi_immr_base + 0x8400, sizeof(immr_ios_t));
+
+       /*
+        * Configure PCI Outbound Translation Windows
+        */
+       ios->potar0 = (MPC83xx_PCI1_LOWER_MEM >> 12) & POTAR_TA_MASK;
+       ios->pobar0 = (MPC83xx_PCI1_LOWER_MEM >> 12) & POBAR_BA_MASK;
+       ios->pocmr0 = POCMR_EN |
+               (((0xffffffff - (MPC83xx_PCI1_UPPER_MEM -
+                               MPC83xx_PCI1_LOWER_MEM)) >> 12) & POCMR_CM_MASK);
+
+       /* mapped to PCI1 IO space */
+       ios->potar1 = (MPC83xx_PCI1_LOWER_IO >> 12) & POTAR_TA_MASK;
+       ios->pobar1 = (MPC83xx_PCI1_IO_BASE >> 12) & POBAR_BA_MASK;
+       ios->pocmr1 = POCMR_EN | POCMR_IO |
+               (((0xffffffff - (MPC83xx_PCI1_UPPER_IO -
+                               MPC83xx_PCI1_LOWER_IO)) >> 12) & POCMR_CM_MASK);
+
+       /*
+        * Configure PCI Inbound Translation Windows
+        */
+       pci_ctrl->pitar1 = 0x0;
+       pci_ctrl->pibar1 = 0x0;
+       pci_ctrl->piebar1 = 0x0;
+       pci_ctrl->piwar1 = PIWAR_EN | PIWAR_PF | PIWAR_RTT_SNOOP | PIWAR_WTT_SNOOP | PIWAR_IWS_2G;
+
+       /*
+        * Release PCI RST signal
+        */
+       pci_ctrl->gcr = 0;
+       udelay(2000);
+       pci_ctrl->gcr = 1;
+       udelay(2000);
+
+       reg16 = 0xff;
+       early_read_config_word(hose, hose->first_busno, 0, PCI_COMMAND, &reg16);
+       reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+       early_write_config_word(hose, hose->first_busno, 0, PCI_COMMAND, reg16);
+
+       /*
+        * Clear non-reserved bits in status register.
+        */
+       early_write_config_word(hose, hose->first_busno, 0, PCI_STATUS, 0xffff);
+       early_write_config_byte(hose, hose->first_busno, 0, PCI_LATENCY_TIMER, 0x80);
+
+       iounmap(pci_ctrl);
+       iounmap(ios);
+}
+
+void __init
+mpc83xx_setup_pci2(struct pci_controller *hose)
+{
+       u16 reg16;
+       volatile immr_pcictrl_t * pci_ctrl;
+       volatile immr_ios_t * ios;
+       bd_t *binfo = (bd_t *) __res;
+
+       pci_ctrl = ioremap(binfo->bi_immr_base + 0x8600, sizeof(immr_pcictrl_t));
+       ios = ioremap(binfo->bi_immr_base + 0x8400, sizeof(immr_ios_t));
+
+       /*
+        * Configure PCI Outbound Translation Windows
+        */
+       ios->potar3 = (MPC83xx_PCI2_LOWER_MEM >> 12) & POTAR_TA_MASK;
+       ios->pobar3 = (MPC83xx_PCI2_LOWER_MEM >> 12) & POBAR_BA_MASK;
+       ios->pocmr3 = POCMR_EN | POCMR_DST |
+               (((0xffffffff - (MPC83xx_PCI2_UPPER_MEM -
+                               MPC83xx_PCI2_LOWER_MEM)) >> 12) & POCMR_CM_MASK);
+
+       /* mapped to PCI2 IO space */
+       ios->potar4 = (MPC83xx_PCI2_LOWER_IO >> 12) & POTAR_TA_MASK;
+       ios->pobar4 = (MPC83xx_PCI2_IO_BASE >> 12) & POBAR_BA_MASK;
+       ios->pocmr4 = POCMR_EN | POCMR_DST | POCMR_IO |
+               (((0xffffffff - (MPC83xx_PCI2_UPPER_IO -
+                               MPC83xx_PCI2_LOWER_IO)) >> 12) & POCMR_CM_MASK);
+
+       /*
+        * Configure PCI Inbound Translation Windows
+        */
+       pci_ctrl->pitar1 = 0x0;
+       pci_ctrl->pibar1 = 0x0;
+       pci_ctrl->piebar1 = 0x0;
+       pci_ctrl->piwar1 = PIWAR_EN | PIWAR_PF | PIWAR_RTT_SNOOP | PIWAR_WTT_SNOOP | PIWAR_IWS_2G;
+
+       /*
+        * Release PCI RST signal
+        */
+       pci_ctrl->gcr = 0;
+       udelay(2000);
+       pci_ctrl->gcr = 1;
+       udelay(2000);
+
+       reg16 = 0xff;
+       early_read_config_word(hose, hose->first_busno, 0, PCI_COMMAND, &reg16);
+       reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+       early_write_config_word(hose, hose->first_busno, 0, PCI_COMMAND, reg16);
+
+       /*
+        * Clear non-reserved bits in status register.
+        */
+       early_write_config_word(hose, hose->first_busno, 0, PCI_STATUS, 0xffff);
+       early_write_config_byte(hose, hose->first_busno, 0, PCI_LATENCY_TIMER, 0x80);
+
+       iounmap(pci_ctrl);
+       iounmap(ios);
+}
+
+/*
+ * PCI buses can be enabled only if SYS board combinates with PIB
+ * (Platform IO Board) board which provide 3 PCI slots. There is 2 PCI buses
+ * and 3 PCI slots, so people must configure the routes between them before
+ * enable PCI bus. This routes are under the control of PCA9555PW device which
+ * can be accessed via I2C bus 2 and are configured by firmware. Refer to
+ * Freescale to get more information about firmware configuration.
+ */
+
+extern int mpc83xx_exclude_device(u_char bus, u_char devfn);
+extern int mpc83xx_map_irq(struct pci_dev *dev, unsigned char idsel,
+               unsigned char pin);
+void __init
+mpc83xx_setup_hose(void)
+{
+       u32 val32;
+       volatile immr_clk_t * clk;
+       struct pci_controller * hose1;
+#ifdef CONFIG_MPC83xx_PCI2
+       struct pci_controller * hose2;
+#endif
+       bd_t * binfo = (bd_t *)__res;
+
+       clk = ioremap(binfo->bi_immr_base + 0xA00,
+                       sizeof(immr_clk_t));
+
+       /*
+        * Configure PCI controller and PCI_CLK_OUTPUT both in 66M mode
+        */
+       val32 = clk->occr;
+       udelay(2000);
+       clk->occr = 0xff000000;
+       udelay(2000);
+
+       iounmap(clk);
+
+       hose1 = pcibios_alloc_controller();
+       if(!hose1)
+               return;
+
+       ppc_md.pci_swizzle = common_swizzle;
+       ppc_md.pci_map_irq = mpc83xx_map_irq;
+
+       hose1->bus_offset = 0;
+       hose1->first_busno = 0;
+       hose1->last_busno = 0xff;
+
+       setup_indirect_pci(hose1, binfo->bi_immr_base + PCI1_CFG_ADDR_OFFSET,
+                       binfo->bi_immr_base + PCI1_CFG_DATA_OFFSET);
+       hose1->set_cfg_type = 1;
+
+       mpc83xx_setup_pci1(hose1);
+
+       hose1->pci_mem_offset = MPC83xx_PCI1_MEM_OFFSET;
+       hose1->mem_space.start = MPC83xx_PCI1_LOWER_MEM;
+       hose1->mem_space.end = MPC83xx_PCI1_UPPER_MEM;
+
+       hose1->io_base_phys = MPC83xx_PCI1_IO_BASE;
+       hose1->io_space.start = MPC83xx_PCI1_LOWER_IO;
+       hose1->io_space.end = MPC83xx_PCI1_UPPER_IO;
+#ifdef CONFIG_MPC83xx_PCI2
+       isa_io_base = (unsigned long)ioremap(MPC83xx_PCI1_IO_BASE,
+                       MPC83xx_PCI1_IO_SIZE + MPC83xx_PCI2_IO_SIZE);
+#else
+       isa_io_base = (unsigned long)ioremap(MPC83xx_PCI1_IO_BASE,
+                       MPC83xx_PCI1_IO_SIZE);
+#endif /* CONFIG_MPC83xx_PCI2 */
+       hose1->io_base_virt = (void *)isa_io_base;
+       /* setup resources */
+       pci_init_resource(&hose1->io_resource,
+                       MPC83xx_PCI1_LOWER_IO,
+                       MPC83xx_PCI1_UPPER_IO,
+                       IORESOURCE_IO, "PCI host bridge 1");
+       pci_init_resource(&hose1->mem_resources[0],
+                       MPC83xx_PCI1_LOWER_MEM,
+                       MPC83xx_PCI1_UPPER_MEM,
+                       IORESOURCE_MEM, "PCI host bridge 1");
+
+       ppc_md.pci_exclude_device = mpc83xx_exclude_device;
+       hose1->last_busno = pciauto_bus_scan(hose1, hose1->first_busno);
+
+#ifdef CONFIG_MPC83xx_PCI2
+       hose2 = pcibios_alloc_controller();
+       if(!hose2)
+               return;
+
+       hose2->bus_offset = hose1->last_busno + 1;
+       hose2->first_busno = hose1->last_busno + 1;
+       hose2->last_busno = 0xff;
+       setup_indirect_pci(hose2, binfo->bi_immr_base + PCI2_CFG_ADDR_OFFSET,
+                       binfo->bi_immr_base + PCI2_CFG_DATA_OFFSET);
+       hose2->set_cfg_type = 1;
+
+       mpc83xx_setup_pci2(hose2);
+
+       hose2->pci_mem_offset = MPC83xx_PCI2_MEM_OFFSET;
+       hose2->mem_space.start = MPC83xx_PCI2_LOWER_MEM;
+       hose2->mem_space.end = MPC83xx_PCI2_UPPER_MEM;
+
+       hose2->io_base_phys = MPC83xx_PCI2_IO_BASE;
+       hose2->io_space.start = MPC83xx_PCI2_LOWER_IO;
+       hose2->io_space.end = MPC83xx_PCI2_UPPER_IO;
+       hose2->io_base_virt = (void *)(isa_io_base + MPC83xx_PCI1_IO_SIZE);
+       /* setup resources */
+       pci_init_resource(&hose2->io_resource,
+                       MPC83xx_PCI2_LOWER_IO,
+                       MPC83xx_PCI2_UPPER_IO,
+                       IORESOURCE_IO, "PCI host bridge 2");
+       pci_init_resource(&hose2->mem_resources[0],
+                       MPC83xx_PCI2_LOWER_MEM,
+                       MPC83xx_PCI2_UPPER_MEM,
+                       IORESOURCE_MEM, "PCI host bridge 2");
+
+       hose2->last_busno = pciauto_bus_scan(hose2, hose2->first_busno);
+#endif /* CONFIG_MPC83xx_PCI2 */
+}
+#endif /*CONFIG_PCI*/
index 683f179b746ca995989ccf2ec8d588c275ac8c57..c766c1a5f786d62fee8413145563cf5634e0627d 100644 (file)
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
  *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef __PPC_SYSLIB_PPC83XX_SETUP_H
@@ -19,7 +27,6 @@
 
 #include <linux/config.h>
 #include <linux/init.h>
-#include <asm/ppcboot.h>
 
 extern unsigned long mpc83xx_find_end_of_memory(void) __init;
 extern long mpc83xx_time_init(void) __init;
@@ -31,13 +38,11 @@ extern void mpc83xx_halt(void);
 extern void mpc83xx_setup_hose(void) __init;
 
 /* PCI config */
-#if 0
-#define PCI1_CFG_ADDR_OFFSET   (FIXME)
-#define PCI1_CFG_DATA_OFFSET   (FIXME)
+#define PCI1_CFG_ADDR_OFFSET (0x8300)
+#define PCI1_CFG_DATA_OFFSET (0x8304)
 
-#define PCI2_CFG_ADDR_OFFSET   (FIXME)
-#define PCI2_CFG_DATA_OFFSET   (FIXME)
-#endif
+#define PCI2_CFG_ADDR_OFFSET (0x8380)
+#define PCI2_CFG_DATA_OFFSET (0x8384)
 
 /* Serial Config */
 #ifdef CONFIG_SERIAL_MANY_PORTS
index 879202352560d5993321e63947bdaee4b149d4c9..52ba0c68078df3c09052d4fcac72550af29b86cb 100644 (file)
@@ -6,6 +6,7 @@
  * Maintainer: Kumar Gala <kumar.gala@freescale.com>
  *
  * Copyright 2005 Freescale Semiconductor Inc.
+ * Copyright 2005 MontaVista, Inc. by Vitaly Bordug <vbordug@ru.mvista.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
@@ -35,10 +36,59 @@ void __init identify_ppc_sys_by_id(u32 id)
 
 void __init identify_ppc_sys_by_name(char *name)
 {
-       /* TODO */
+       unsigned int i = 0;
+       while (ppc_sys_specs[i].ppc_sys_name[0])
+       {
+               if (!strcmp(ppc_sys_specs[i].ppc_sys_name, name))
+                       break;
+               i++;
+       }
+       cur_ppc_sys_spec = &ppc_sys_specs[i];
        return;
 }
 
+static int __init count_sys_specs(void)
+{
+       int i = 0;
+       while (ppc_sys_specs[i].ppc_sys_name[0])
+               i++;
+       return i;
+}
+
+static int __init find_chip_by_name_and_id(char *name, u32 id)
+{
+       int ret = -1;
+       unsigned int i = 0;
+       unsigned int j = 0;
+       unsigned int dups = 0;
+
+       unsigned char matched[count_sys_specs()];
+
+       while (ppc_sys_specs[i].ppc_sys_name[0]) {
+               if (!strcmp(ppc_sys_specs[i].ppc_sys_name, name))
+                       matched[j++] = i;
+               i++;
+       }
+       if (j != 0) {
+               for (i = 0; i < j; i++) {
+                       if ((ppc_sys_specs[matched[i]].mask & id) ==
+                           ppc_sys_specs[matched[i]].value) {
+                               ret = matched[i];
+                               dups++;
+                       }
+               }
+               ret = (dups == 1) ? ret : (-1 * dups);
+       }
+       return ret;
+}
+
+void __init identify_ppc_sys_by_name_and_id(char *name, u32 id)
+{
+       int i = find_chip_by_name_and_id(name, id);
+       BUG_ON(i < 0);
+       cur_ppc_sys_spec = &ppc_sys_specs[i];
+}
+
 /* Update all memory resources by paddr, call before platform_device_register */
 void __init
 ppc_sys_fixup_mem_resource(struct platform_device *pdev, phys_addr_t paddr)
diff --git a/arch/ppc/syslib/pq2_devices.c b/arch/ppc/syslib/pq2_devices.c
new file mode 100644 (file)
index 0000000..1d38697
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * arch/ppc/syslib/pq2_devices.c
+ *
+ * PQ2 Device descriptions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <asm/cpm2.h>
+#include <asm/irq.h>
+#include <asm/ppc_sys.h>
+
+struct platform_device ppc_sys_platform_devices[] = {
+       [MPC82xx_CPM_FCC1] = {
+               .name = "fsl-cpm-fcc",
+               .id     = 1,
+               .num_resources   = 3,
+               .resource = (struct resource[]) {
+                       {
+                               .name   = "fcc_regs",
+                               .start  = 0x11300,
+                               .end    = 0x1131f,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .name   = "fcc_pram",
+                               .start  = 0x8400,
+                               .end    = 0x84ff,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .start  = SIU_INT_FCC1,
+                               .end    = SIU_INT_FCC1,
+                               .flags  = IORESOURCE_IRQ,
+                       },
+               },
+       },
+       [MPC82xx_CPM_FCC2] = {
+               .name = "fsl-cpm-fcc",
+               .id     = 2,
+               .num_resources   = 3,
+               .resource = (struct resource[]) {
+                       {
+                               .name   = "fcc_regs",
+                               .start  = 0x11320,
+                               .end    = 0x1133f,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .name   = "fcc_pram",
+                               .start  = 0x8500,
+                               .end    = 0x85ff,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .start  = SIU_INT_FCC2,
+                               .end    = SIU_INT_FCC2,
+                               .flags  = IORESOURCE_IRQ,
+                       },
+               },
+       },
+       [MPC82xx_CPM_FCC3] = {
+               .name = "fsl-cpm-fcc",
+               .id     = 3,
+               .num_resources   = 3,
+               .resource = (struct resource[]) {
+                       {
+                               .name   = "fcc_regs",
+                               .start  = 0x11340,
+                               .end    = 0x1135f,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .name   = "fcc_pram",
+                               .start  = 0x8600,
+                               .end    = 0x86ff,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .start  = SIU_INT_FCC3,
+                               .end    = SIU_INT_FCC3,
+                               .flags  = IORESOURCE_IRQ,
+                       },
+               },
+       },
+       [MPC82xx_CPM_I2C] = {
+               .name = "fsl-cpm-i2c",
+               .id     = 1,
+               .num_resources   = 3,
+               .resource = (struct resource[]) {
+                       {
+                               .name   = "i2c_mem",
+                               .start  = 0x11860,
+                               .end    = 0x118BF,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .name   = "i2c_pram",
+                               .start  = 0x8afc,
+                               .end    = 0x8afd,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .start  = SIU_INT_I2C,
+                               .end    = SIU_INT_I2C,
+                               .flags  = IORESOURCE_IRQ,
+                       },
+               },
+       },
+       [MPC82xx_CPM_SCC1] = {
+               .name = "fsl-cpm-scc",
+               .id     = 1,
+               .num_resources   = 3,
+               .resource = (struct resource[]) {
+                       {
+                               .name   = "scc_mem",
+                               .start  = 0x11A00,
+                               .end    = 0x11A1F,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .name   = "scc_pram",
+                               .start  = 0x8000,
+                               .end    = 0x80ff,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .start  = SIU_INT_SCC1,
+                               .end    = SIU_INT_SCC1,
+                               .flags  = IORESOURCE_IRQ,
+                       },
+               },
+       },
+       [MPC82xx_CPM_SCC2] = {
+               .name = "fsl-cpm-scc",
+               .id     = 2,
+               .num_resources   = 3,
+               .resource = (struct resource[]) {
+                       {
+                               .name   = "scc_mem",
+                               .start  = 0x11A20,
+                               .end    = 0x11A3F,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .name   = "scc_pram",
+                               .start  = 0x8100,
+                               .end    = 0x81ff,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .start  = SIU_INT_SCC2,
+                               .end    = SIU_INT_SCC2,
+                               .flags  = IORESOURCE_IRQ,
+                       },
+               },
+       },
+       [MPC82xx_CPM_SCC3] = {
+               .name = "fsl-cpm-scc",
+               .id     = 3,
+               .num_resources   = 3,
+               .resource = (struct resource[]) {
+                       {
+                               .name   = "scc_mem",
+                               .start  = 0x11A40,
+                               .end    = 0x11A5F,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .name   = "scc_pram",
+                               .start  = 0x8200,
+                               .end    = 0x82ff,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .start  = SIU_INT_SCC3,
+                               .end    = SIU_INT_SCC3,
+                               .flags  = IORESOURCE_IRQ,
+                       },
+               },
+       },
+       [MPC82xx_CPM_SCC4] = {
+               .name = "fsl-cpm-scc",
+               .id     = 4,
+               .num_resources   = 3,
+               .resource = (struct resource[]) {
+                       {
+                               .name   = "scc_mem",
+                               .start  = 0x11A60,
+                               .end    = 0x11A7F,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .name   = "scc_pram",
+                               .start  = 0x8300,
+                               .end    = 0x83ff,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .start  = SIU_INT_SCC4,
+                               .end    = SIU_INT_SCC4,
+                               .flags  = IORESOURCE_IRQ,
+                       },
+               },
+       },
+       [MPC82xx_CPM_SPI] = {
+               .name = "fsl-cpm-spi",
+               .id     = 1,
+               .num_resources   = 3,
+               .resource = (struct resource[]) {
+                       {
+                               .name   = "spi_mem",
+                               .start  = 0x11AA0,
+                               .end    = 0x11AFF,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .name   = "spi_pram",
+                               .start  = 0x89fc,
+                               .end    = 0x89fd,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .start  = SIU_INT_SPI,
+                               .end    = SIU_INT_SPI,
+                               .flags  = IORESOURCE_IRQ,
+                       },
+               },
+       },
+       [MPC82xx_CPM_MCC1] = {
+               .name = "fsl-cpm-mcc",
+               .id     = 1,
+               .num_resources   = 3,
+               .resource = (struct resource[]) {
+                       {
+                               .name   = "mcc_mem",
+                               .start  = 0x11B30,
+                               .end    = 0x11B3F,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .name   = "mcc_pram",
+                               .start  = 0x8700,
+                               .end    = 0x877f,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .start  = SIU_INT_MCC1,
+                               .end    = SIU_INT_MCC1,
+                               .flags  = IORESOURCE_IRQ,
+                       },
+               },
+       },
+       [MPC82xx_CPM_MCC2] = {
+               .name = "fsl-cpm-mcc",
+               .id     = 2,
+               .num_resources   = 3,
+               .resource = (struct resource[]) {
+                       {
+                               .name   = "mcc_mem",
+                               .start  = 0x11B50,
+                               .end    = 0x11B5F,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .name   = "mcc_pram",
+                               .start  = 0x8800,
+                               .end    = 0x887f,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .start  = SIU_INT_MCC2,
+                               .end    = SIU_INT_MCC2,
+                               .flags  = IORESOURCE_IRQ,
+                       },
+               },
+       },
+       [MPC82xx_CPM_SMC1] = {
+               .name = "fsl-cpm-smc",
+               .id     = 1,
+               .num_resources   = 3,
+               .resource = (struct resource[]) {
+                       {
+                               .name   = "smc_mem",
+                               .start  = 0x11A80,
+                               .end    = 0x11A8F,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .name   = "smc_pram",
+                               .start  = 0x87fc,
+                               .end    = 0x87fd,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .start  = SIU_INT_SMC1,
+                               .end    = SIU_INT_SMC1,
+                               .flags  = IORESOURCE_IRQ,
+                       },
+               },
+       },
+       [MPC82xx_CPM_SMC2] = {
+               .name = "fsl-cpm-smc",
+               .id     = 2,
+               .num_resources   = 3,
+               .resource = (struct resource[]) {
+                       {
+                               .name   = "smc_mem",
+                               .start  = 0x11A90,
+                               .end    = 0x11A9F,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .name   = "smc_pram",
+                               .start  = 0x88fc,
+                               .end    = 0x88fd,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .start  = SIU_INT_SMC2,
+                               .end    = SIU_INT_SMC2,
+                               .flags  = IORESOURCE_IRQ,
+                       },
+               },
+       },
+       [MPC82xx_CPM_USB] = {
+               .name = "fsl-cpm-usb",
+               .id     = 1,
+               .num_resources  = 3,
+               .resource = (struct resource[]) {
+                       {
+                               .name   = "usb_mem",
+                               .start  = 0x11b60,
+                               .end    = 0x11b78,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .name   = "usb_pram",
+                               .start  = 0x8b00,
+                               .end    = 0x8bff,
+                               .flags  = IORESOURCE_MEM,
+                       },
+                       {
+                               .start  = SIU_INT_USB,
+                               .end    = SIU_INT_USB,
+                               .flags  = IORESOURCE_IRQ,
+                       },
+
+               },
+       },
+       [MPC82xx_SEC1] = {
+               .name = "fsl-sec",
+               .id = 1,
+               .num_resources = 1,
+               .resource = (struct resource[]) {
+                       {
+                               .name   = "sec_mem",
+                               .start  = 0x40000,
+                               .end    = 0x52fff,
+                               .flags  = IORESOURCE_MEM,
+                       },
+               },
+       },
+};
+
+static int __init mach_mpc82xx_fixup(struct platform_device *pdev)
+{
+       ppc_sys_fixup_mem_resource(pdev, CPM_MAP_ADDR);
+       return 0;
+}
+
+static int __init mach_mpc82xx_init(void)
+{
+       if (ppc_md.progress)
+               ppc_md.progress("mach_mpc82xx_init:enter", 0);
+       ppc_sys_device_fixup = mach_mpc82xx_fixup;
+       return 0;
+}
+
+postcore_initcall(mach_mpc82xx_init);
diff --git a/arch/ppc/syslib/pq2_sys.c b/arch/ppc/syslib/pq2_sys.c
new file mode 100644 (file)
index 0000000..7b6c9eb
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * arch/ppc/syslib/pq2_devices.c
+ *
+ * PQ2 System descriptions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+
+#include <asm/ppc_sys.h>
+
+struct ppc_sys_spec *cur_ppc_sys_spec;
+struct ppc_sys_spec ppc_sys_specs[] = {
+       /* below is a list of the 8260 family of processors */
+       {
+               .ppc_sys_name   = "8250",
+               .mask           = 0x0000ff00,
+               .value          = 0x00000000,
+               .num_devices    = 12,
+               .device_list = (enum ppc_sys_devices[])
+               {
+                       MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_FCC3,
+                       MPC82xx_CPM_SCC1, MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3,
+                       MPC82xx_CPM_SCC4, MPC82xx_CPM_MCC1, MPC82xx_CPM_SMC1,
+                       MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+               }
+       },
+       {
+               .ppc_sys_name   = "8255",
+               .mask           = 0x0000ff00,
+               .value          = 0x00000000,
+               .num_devices    = 11,
+               .device_list = (enum ppc_sys_devices[])
+               {
+                       MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_SCC1,
+                       MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3, MPC82xx_CPM_SCC4,
+                       MPC82xx_CPM_MCC1, MPC82xx_CPM_SMC1, MPC82xx_CPM_SMC2,
+                       MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+               }
+       },
+       {
+               .ppc_sys_name   = "8260",
+               .mask           = 0x0000ff00,
+               .value          = 0x00000000,
+               .num_devices    = 12,
+               .device_list = (enum ppc_sys_devices[])
+               {
+                       MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_FCC3,
+                       MPC82xx_CPM_SCC1, MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3,
+                       MPC82xx_CPM_SCC4, MPC82xx_CPM_MCC1, MPC82xx_CPM_SMC1,
+                       MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+               }
+       },
+       {
+               .ppc_sys_name   = "8264",
+               .mask           = 0x0000ff00,
+               .value          = 0x00000000,
+               .num_devices    = 12,
+               .device_list = (enum ppc_sys_devices[])
+               {
+                       MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_FCC3,
+                       MPC82xx_CPM_SCC1, MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3,
+                       MPC82xx_CPM_SCC4, MPC82xx_CPM_MCC1, MPC82xx_CPM_SMC1,
+                       MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+               }
+       },
+       {
+               .ppc_sys_name   = "8265",
+               .mask           = 0x0000ff00,
+               .value          = 0x00000000,
+               .num_devices    = 12,
+               .device_list = (enum ppc_sys_devices[])
+               {
+                       MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_FCC3,
+                       MPC82xx_CPM_SCC1, MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3,
+                       MPC82xx_CPM_SCC4, MPC82xx_CPM_MCC1, MPC82xx_CPM_SMC1,
+                       MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+               }
+       },
+       {
+               .ppc_sys_name   = "8266",
+               .mask           = 0x0000ff00,
+               .value          = 0x00000000,
+               .num_devices    = 12,
+               .device_list = (enum ppc_sys_devices[])
+               {
+                       MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_FCC3,
+                       MPC82xx_CPM_SCC1, MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3,
+                       MPC82xx_CPM_SCC4, MPC82xx_CPM_MCC1, MPC82xx_CPM_SMC1,
+                       MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+               }
+       },
+       /* below is a list of the 8272 family of processors */
+       {
+               .ppc_sys_name   = "8247",
+               .mask           = 0x0000ff00,
+               .value          = 0x00000d00,
+               .num_devices    = 10,
+               .device_list = (enum ppc_sys_devices[])
+               {
+                       MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_SCC1,
+                       MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3, MPC82xx_CPM_SMC1,
+                       MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+                       MPC82xx_CPM_USB,
+               },
+       },
+       {
+               .ppc_sys_name   = "8248",
+               .mask           = 0x0000ff00,
+               .value          = 0x00000c00,
+               .num_devices    = 11,
+               .device_list = (enum ppc_sys_devices[])
+               {
+                       MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_SCC1,
+                       MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3, MPC82xx_CPM_SMC1,
+                       MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+                       MPC82xx_CPM_USB, MPC82xx_SEC1,
+               },
+       },
+       {
+               .ppc_sys_name   = "8271",
+               .mask           = 0x0000ff00,
+               .value          = 0x00000d00,
+               .num_devices    = 10,
+               .device_list = (enum ppc_sys_devices[])
+               {
+                       MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_SCC1,
+                       MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3, MPC82xx_CPM_SMC1,
+                       MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+                       MPC82xx_CPM_USB,
+               },
+       },
+       {
+               .ppc_sys_name   = "8272",
+               .mask           = 0x0000ff00,
+               .value          = 0x00000c00,
+               .num_devices    = 11,
+               .device_list = (enum ppc_sys_devices[])
+               {
+                       MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_SCC1,
+                       MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3, MPC82xx_CPM_SMC1,
+                       MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+                       MPC82xx_CPM_USB, MPC82xx_SEC1,
+               },
+       },
+       /* below is a list of the 8280 family of processors */
+       {
+               .ppc_sys_name   = "8270",
+               .mask           = 0x0000ff00,
+               .value          = 0x00000a00,
+               .num_devices    = 12,
+               .device_list = (enum ppc_sys_devices[])
+               {
+                       MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_FCC3,
+                       MPC82xx_CPM_SCC1, MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3,
+                       MPC82xx_CPM_SCC4, MPC82xx_CPM_MCC1, MPC82xx_CPM_SMC1,
+                       MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+               },
+       },
+       {
+               .ppc_sys_name   = "8275",
+               .mask           = 0x0000ff00,
+               .value          = 0x00000a00,
+               .num_devices    = 12,
+               .device_list = (enum ppc_sys_devices[])
+               {
+                       MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_FCC3,
+                       MPC82xx_CPM_SCC1, MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3,
+                       MPC82xx_CPM_SCC4, MPC82xx_CPM_MCC1, MPC82xx_CPM_SMC1,
+                       MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+               },
+       },
+       {
+               .ppc_sys_name   = "8280",
+               .mask           = 0x0000ff00,
+               .value          = 0x00000a00,
+               .num_devices    = 13,
+               .device_list = (enum ppc_sys_devices[])
+               {
+                       MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_FCC3,
+                       MPC82xx_CPM_SCC1, MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3,
+                       MPC82xx_CPM_SCC4, MPC82xx_CPM_MCC1, MPC82xx_CPM_MCC2,
+                       MPC82xx_CPM_SMC1, MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI,
+                       MPC82xx_CPM_I2C,
+               },
+       },
+       {
+               /* default match */
+               .ppc_sys_name   = "",
+               .mask           = 0x00000000,
+               .value          = 0x00000000,
+       },
+};
index 2ce87836c6711b76b8862eff790ce1b8c6f30d2b..deca68ad644ae41681537867c7e8accdb6d2a18b 100644 (file)
@@ -44,6 +44,10 @@ config SCHED_NO_NO_OMIT_FRAME_POINTER
        bool
        default y
 
+config ARCH_MAY_HAVE_PC_FDC
+       bool
+       default y
+
 # We optimistically allocate largepages from the VM, so make the limit
 # large enough (16MB). This badly named config option is actually
 # max order + 1
@@ -302,12 +306,6 @@ config GENERIC_HARDIRQS
        bool
        default y
 
-config MSCHUNKS
-       bool
-       depends on PPC_ISERIES
-       default y
-
-
 config PPC_RTAS
        bool
        depends on PPC_PSERIES || PPC_BPA
@@ -350,13 +348,46 @@ config SECCOMP
 
          If unsure, say Y. Only embedded should say N here.
 
+source "fs/Kconfig.binfmt"
+
+config HOTPLUG_CPU
+       bool "Support for hot-pluggable CPUs"
+       depends on SMP && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC)
+       select HOTPLUG
+       ---help---
+         Say Y here to be able to turn CPUs off and on.
+
+         Say N if you are unsure.
+
+config PROC_DEVICETREE
+       bool "Support for Open Firmware device tree in /proc"
+       depends on !PPC_ISERIES
+       help
+         This option adds a device-tree directory under /proc which contains
+         an image of the device tree that the kernel copies from Open
+         Firmware. If unsure, say Y here.
+
+config CMDLINE_BOOL
+       bool "Default bootloader kernel arguments"
+       depends on !PPC_ISERIES
+
+config CMDLINE
+       string "Initial kernel command string"
+       depends on CMDLINE_BOOL
+       default "console=ttyS0,9600 console=tty0 root=/dev/sda2"
+       help
+         On some platforms, there is currently no way for the boot loader to
+         pass arguments to the kernel. For these platforms, you can supply
+         some command-line options at build time by entering them here.  In
+         most cases you will need to specify the root device here.
+
 endmenu
 
 config ISA_DMA_API
        bool
        default y
 
-menu "General setup"
+menu "Bus Options"
 
 config ISA
        bool
@@ -389,45 +420,12 @@ config PCI_DOMAINS
        bool
        default PCI
 
-source "fs/Kconfig.binfmt"
-
 source "drivers/pci/Kconfig"
 
-config HOTPLUG_CPU
-       bool "Support for hot-pluggable CPUs"
-       depends on SMP && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC)
-       select HOTPLUG
-       ---help---
-         Say Y here to be able to turn CPUs off and on.
-
-         Say N if you are unsure.
-
 source "drivers/pcmcia/Kconfig"
 
 source "drivers/pci/hotplug/Kconfig"
 
-config PROC_DEVICETREE
-       bool "Support for Open Firmware device tree in /proc"
-       depends on !PPC_ISERIES
-       help
-         This option adds a device-tree directory under /proc which contains
-         an image of the device tree that the kernel copies from Open
-         Firmware. If unsure, say Y here.
-
-config CMDLINE_BOOL
-       bool "Default bootloader kernel arguments"
-       depends on !PPC_ISERIES
-
-config CMDLINE
-       string "Initial kernel command string"
-       depends on CMDLINE_BOOL
-       default "console=ttyS0,9600 console=tty0 root=/dev/sda2"
-       help
-         On some platforms, there is currently no way for the boot loader to
-         pass arguments to the kernel. For these platforms, you can supply
-         some command-line options at build time by entering them here.  In
-         most cases you will need to specify the root device here.
-
 endmenu
 
 source "net/Kconfig"
index 46b1ce58da3b39abd2ae6349040bc87001dd607c..f16a5030527bd1e8f8818dc7337d49ba049054f3 100644 (file)
@@ -41,10 +41,19 @@ config XMON
        help
          Include in-kernel hooks for the xmon kernel monitor/debugger.
          Unless you are intending to debug the kernel, say N here.
+         Make sure to enable also CONFIG_BOOTX_TEXT on Macs. Otherwise
+         nothing will appear on the screen (xmon writes directly to the
+         framebuffer memory).
+         The cmdline option 'xmon' or 'xmon=early' will drop into xmon very
+         early during boot. 'xmon=on' will just enable the xmon debugger hooks.
+         'xmon=off' will disable the debugger hooks if CONFIG_XMON_DEFAULT is set.
 
 config XMON_DEFAULT
        bool "Enable xmon by default"
        depends on XMON
+       help
+         xmon is normally disabled unless booted with 'xmon=on'.
+         Use 'xmon=off' to disable xmon init during runtime.
 
 config PPCDBG
        bool "Include PPCDBG realtime debugging"
index 731b84758331bfc5fc790554265b8bf9a4eb8557..8189953a372c93b6579f150359facb604cb4af46 100644 (file)
@@ -49,12 +49,14 @@ NM          := $(NM) --synthetic
 
 endif
 
-CHECKFLAGS     += -m64 -D__powerpc__
+CHECKFLAGS     += -m64 -D__powerpc__ -D__powerpc64__
 
 LDFLAGS                := -m elf64ppc
 LDFLAGS_vmlinux        := -Bstatic -e $(KERNELLOAD) -Ttext $(KERNELLOAD)
 CFLAGS         += -msoft-float -pipe -mminimal-toc -mtraceback=none \
                   -mcall-aixdesc
+# Temporary hack until we have migrated to asm-powerpc
+CPPFLAGS       += -Iinclude3
 
 GCC_VERSION     := $(call cc-version)
 GCC_BROKEN_VEC := $(shell if [ $(GCC_VERSION) -lt 0400 ] ; then echo "y"; fi ;)
@@ -112,6 +114,7 @@ all: $(KBUILD_IMAGE)
 
 archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
+       $(Q)rm -rf include3
 
 prepare: include/asm-ppc64/offsets.h
 
@@ -121,6 +124,12 @@ arch/ppc64/kernel/asm-offsets.s: include/asm include/linux/version.h \
 include/asm-ppc64/offsets.h: arch/ppc64/kernel/asm-offsets.s
        $(call filechk,gen-asm-offsets)
 
+# Temporary hack until we have migrated to asm-powerpc
+include/asm: include3/asm
+include3/asm:
+       $(Q)if [ ! -d include3 ]; then mkdir -p include3; fi;
+       $(Q)ln -fsn $(srctree)/include/asm-powerpc include3/asm
+
 define archhelp
   echo  '* zImage       - Compressed kernel image (arch/$(ARCH)/boot/zImage)'
   echo  '  zImage.initrd- Compressed kernel image with initrd attached,'
index 683b2d43c15fe2facb4a7a1d7f388f260481c3a0..2c5f5e73d00c76d3e4a56e8f721656c926aa55e9 100644 (file)
@@ -22,8 +22,8 @@
 
 
 HOSTCC         := gcc
-BOOTCFLAGS     := $(HOSTCFLAGS) $(LINUXINCLUDE) -fno-builtin 
-BOOTAFLAGS     := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional
+BOOTCFLAGS     := $(HOSTCFLAGS) -fno-builtin -nostdinc -isystem $(shell $(CROSS32CC) -print-file-name=include)
+BOOTAFLAGS     := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc
 BOOTLFLAGS     := -Ttext 0x00400000 -e _start -T $(srctree)/$(src)/zImage.lds
 OBJCOPYFLAGS    := contents,alloc,load,readonly,data
 
index 719663a694bb9a06d19ce3048154eb22dfd68ebb..8041a9845ab7efa9c94d58505a1d32c949b7e716 100644 (file)
@@ -157,7 +157,7 @@ main(int ac, char **av)
        PUT_32BE(ns, strlen(arch) + 1);
        PUT_32BE(ns + 4, N_DESCR * 4);
        PUT_32BE(ns + 8, 0x1275);
-       strcpy(&buf[ns + 12], arch);
+       strcpy((char *) &buf[ns + 12], arch);
        ns += 12 + strlen(arch) + 1;
        for (i = 0; i < N_DESCR; ++i, ns += 4)
                PUT_32BE(ns, descr[i]);
@@ -172,7 +172,7 @@ main(int ac, char **av)
        PUT_32BE(ns, strlen(rpaname) + 1);
        PUT_32BE(ns + 4, sizeof(rpanote));
        PUT_32BE(ns + 8, 0x12759999);
-       strcpy(&buf[ns + 12], rpaname);
+       strcpy((char *) &buf[ns + 12], rpaname);
        ns += 12 + ROUNDUP(strlen(rpaname) + 1);
        for (i = 0; i < N_RPA_DESCR; ++i, ns += 4)
                PUT_32BE(ns, rpanote[i]);
index 04d3e74cd72f7d53fd9fbbfe7378a6b2f5e62e2f..3861e7f9cf19fe47aafe8e65d52b600936d8b5c8 100644 (file)
@@ -9,7 +9,7 @@
  * NOTE: this code runs in 32 bit mode and is packaged as ELF32.
  */
 
-#include <asm/ppc_asm.h>
+#include "ppc_asm.h"
 
        .text
        .globl  _start
index 38f7e466d7d65603e1b62ead96b4dcbc5c479829..722f360a32a9e905b2edf6f3cdb90b9ef9e5d588 100644 (file)
@@ -13,7 +13,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-#include <asm/ppc_asm.h>
+#include "ppc_asm.h"
 
        .globl __div64_32
 __div64_32:
diff --git a/arch/ppc64/boot/elf.h b/arch/ppc64/boot/elf.h
new file mode 100644 (file)
index 0000000..d4828fc
--- /dev/null
@@ -0,0 +1,149 @@
+#ifndef _PPC_BOOT_ELF_H_
+#define _PPC_BOOT_ELF_H_
+
+/* 32-bit ELF base types. */
+typedef unsigned int Elf32_Addr;
+typedef unsigned short Elf32_Half;
+typedef unsigned int Elf32_Off;
+typedef signed int Elf32_Sword;
+typedef unsigned int Elf32_Word;
+
+/* 64-bit ELF base types. */
+typedef unsigned long long Elf64_Addr;
+typedef unsigned short Elf64_Half;
+typedef signed short Elf64_SHalf;
+typedef unsigned long long Elf64_Off;
+typedef signed int Elf64_Sword;
+typedef unsigned int Elf64_Word;
+typedef unsigned long long Elf64_Xword;
+typedef signed long long Elf64_Sxword;
+
+/* These constants are for the segment types stored in the image headers */
+#define PT_NULL    0
+#define PT_LOAD    1
+#define PT_DYNAMIC 2
+#define PT_INTERP  3
+#define PT_NOTE    4
+#define PT_SHLIB   5
+#define PT_PHDR    6
+#define PT_TLS     7           /* Thread local storage segment */
+#define PT_LOOS    0x60000000  /* OS-specific */
+#define PT_HIOS    0x6fffffff  /* OS-specific */
+#define PT_LOPROC  0x70000000
+#define PT_HIPROC  0x7fffffff
+#define PT_GNU_EH_FRAME                0x6474e550
+
+#define PT_GNU_STACK   (PT_LOOS + 0x474e551)
+
+/* These constants define the different elf file types */
+#define ET_NONE   0
+#define ET_REL    1
+#define ET_EXEC   2
+#define ET_DYN    3
+#define ET_CORE   4
+#define ET_LOPROC 0xff00
+#define ET_HIPROC 0xffff
+
+/* These constants define the various ELF target machines */
+#define EM_NONE  0
+#define EM_PPC        20       /* PowerPC */
+#define EM_PPC64       21      /* PowerPC64 */
+
+#define EI_NIDENT      16
+
+typedef struct elf32_hdr {
+       unsigned char e_ident[EI_NIDENT];
+       Elf32_Half e_type;
+       Elf32_Half e_machine;
+       Elf32_Word e_version;
+       Elf32_Addr e_entry;     /* Entry point */
+       Elf32_Off e_phoff;
+       Elf32_Off e_shoff;
+       Elf32_Word e_flags;
+       Elf32_Half e_ehsize;
+       Elf32_Half e_phentsize;
+       Elf32_Half e_phnum;
+       Elf32_Half e_shentsize;
+       Elf32_Half e_shnum;
+       Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+typedef struct elf64_hdr {
+       unsigned char e_ident[16];      /* ELF "magic number" */
+       Elf64_Half e_type;
+       Elf64_Half e_machine;
+       Elf64_Word e_version;
+       Elf64_Addr e_entry;     /* Entry point virtual address */
+       Elf64_Off e_phoff;      /* Program header table file offset */
+       Elf64_Off e_shoff;      /* Section header table file offset */
+       Elf64_Word e_flags;
+       Elf64_Half e_ehsize;
+       Elf64_Half e_phentsize;
+       Elf64_Half e_phnum;
+       Elf64_Half e_shentsize;
+       Elf64_Half e_shnum;
+       Elf64_Half e_shstrndx;
+} Elf64_Ehdr;
+
+/* These constants define the permissions on sections in the program
+   header, p_flags. */
+#define PF_R           0x4
+#define PF_W           0x2
+#define PF_X           0x1
+
+typedef struct elf32_phdr {
+       Elf32_Word p_type;
+       Elf32_Off p_offset;
+       Elf32_Addr p_vaddr;
+       Elf32_Addr p_paddr;
+       Elf32_Word p_filesz;
+       Elf32_Word p_memsz;
+       Elf32_Word p_flags;
+       Elf32_Word p_align;
+} Elf32_Phdr;
+
+typedef struct elf64_phdr {
+       Elf64_Word p_type;
+       Elf64_Word p_flags;
+       Elf64_Off p_offset;     /* Segment file offset */
+       Elf64_Addr p_vaddr;     /* Segment virtual address */
+       Elf64_Addr p_paddr;     /* Segment physical address */
+       Elf64_Xword p_filesz;   /* Segment size in file */
+       Elf64_Xword p_memsz;    /* Segment size in memory */
+       Elf64_Xword p_align;    /* Segment alignment, file & memory */
+} Elf64_Phdr;
+
+#define        EI_MAG0         0       /* e_ident[] indexes */
+#define        EI_MAG1         1
+#define        EI_MAG2         2
+#define        EI_MAG3         3
+#define        EI_CLASS        4
+#define        EI_DATA         5
+#define        EI_VERSION      6
+#define        EI_OSABI        7
+#define        EI_PAD          8
+
+#define        ELFMAG0         0x7f    /* EI_MAG */
+#define        ELFMAG1         'E'
+#define        ELFMAG2         'L'
+#define        ELFMAG3         'F'
+#define        ELFMAG          "\177ELF"
+#define        SELFMAG         4
+
+#define        ELFCLASSNONE    0       /* EI_CLASS */
+#define        ELFCLASS32      1
+#define        ELFCLASS64      2
+#define        ELFCLASSNUM     3
+
+#define ELFDATANONE    0       /* e_ident[EI_DATA] */
+#define ELFDATA2LSB    1
+#define ELFDATA2MSB    2
+
+#define EV_NONE                0       /* e_version, EI_VERSION */
+#define EV_CURRENT     1
+#define EV_NUM         2
+
+#define ELFOSABI_NONE  0
+#define ELFOSABI_LINUX 3
+
+#endif                         /* _PPC_BOOT_ELF_H_ */
index 199d9804f61c418a9351697846e1e83964f6f615..99e68cfbe6883b9ee0e6f249a6d4ba9b30ae59a2 100644 (file)
@@ -8,36 +8,28 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-#include "ppc32-types.h"
+#include <stdarg.h>
+#include <stddef.h>
+#include "elf.h"
+#include "page.h"
+#include "string.h"
+#include "stdio.h"
+#include "prom.h"
 #include "zlib.h"
-#include <linux/elf.h>
-#include <linux/string.h>
-#include <asm/processor.h>
-#include <asm/page.h>
-
-extern void *finddevice(const char *);
-extern int getprop(void *, const char *, void *, int);
-extern void printf(const char *fmt, ...);
-extern int sprintf(char *buf, const char *fmt, ...);
-void gunzip(void *, int, unsigned char *, int *);
-void *claim(unsigned int, unsigned int, unsigned int);
-void flush_cache(void *, unsigned long);
-void pause(void);
-extern void exit(void);
-
-unsigned long strlen(const char *s);
-void *memmove(void *dest, const void *src, unsigned long n);
-void *memcpy(void *dest, const void *src, unsigned long n);
+
+static void gunzip(void *, int, unsigned char *, int *);
+extern void flush_cache(void *, unsigned long);
+
 
 /* Value picked to match that used by yaboot */
 #define PROG_START     0x01400000
 #define RAM_END                (256<<20) // Fixme: use OF */
 
-char *avail_ram;
-char *begin_avail, *end_avail;
-char *avail_high;
-unsigned int heap_use;
-unsigned int heap_max;
+static char *avail_ram;
+static char *begin_avail, *end_avail;
+static char *avail_high;
+static unsigned int heap_use;
+static unsigned int heap_max;
 
 extern char _start[];
 extern char _vmlinux_start[];
@@ -52,9 +44,9 @@ struct addr_range {
        unsigned long size;
        unsigned long memsize;
 };
-struct addr_range vmlinux = {0, 0, 0};
-struct addr_range vmlinuz = {0, 0, 0};
-struct addr_range initrd  = {0, 0, 0};
+static struct addr_range vmlinux = {0, 0, 0};
+static struct addr_range vmlinuz = {0, 0, 0};
+static struct addr_range initrd  = {0, 0, 0};
 
 static char scratch[128<<10];  /* 128kB of scratch space for gunzip */
 
@@ -64,13 +56,6 @@ typedef void (*kernel_entry_t)( unsigned long,
                                void *);
 
 
-int (*prom)(void *);
-
-void *chosen_handle;
-void *stdin;
-void *stdout;
-void *stderr;
-
 #undef DEBUG
 
 static unsigned long claim_base = PROG_START;
@@ -277,7 +262,7 @@ void zfree(void *x, void *addr, unsigned nb)
 
 #define DEFLATED       8
 
-void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
 {
        z_stream s;
        int r, i, flags;
diff --git a/arch/ppc64/boot/page.h b/arch/ppc64/boot/page.h
new file mode 100644 (file)
index 0000000..14eca30
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef _PPC_BOOT_PAGE_H
+#define _PPC_BOOT_PAGE_H
+/*
+ * Copyright (C) 2001 PPC64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifdef __ASSEMBLY__
+#define ASM_CONST(x) x
+#else
+#define __ASM_CONST(x) x##UL
+#define ASM_CONST(x) __ASM_CONST(x)
+#endif
+
+/* PAGE_SHIFT determines the page size */
+#define PAGE_SHIFT     12
+#define PAGE_SIZE      (ASM_CONST(1) << PAGE_SHIFT)
+#define PAGE_MASK      (~(PAGE_SIZE-1))
+
+/* align addr on a size boundary - adjust address up/down if needed */
+#define _ALIGN_UP(addr,size)   (((addr)+((size)-1))&(~((size)-1)))
+#define _ALIGN_DOWN(addr,size) ((addr)&(~((size)-1)))
+
+/* align addr on a size boundary - adjust address up if needed */
+#define _ALIGN(addr,size)     _ALIGN_UP(addr,size)
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr)       _ALIGN(addr, PAGE_SIZE)
+
+#endif                         /* _PPC_BOOT_PAGE_H */
diff --git a/arch/ppc64/boot/ppc32-types.h b/arch/ppc64/boot/ppc32-types.h
deleted file mode 100644 (file)
index f7b8884..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef _PPC64_TYPES_H
-#define _PPC64_TYPES_H
-
-typedef __signed__ char __s8;
-typedef unsigned char __u8;
-
-typedef __signed__ short __s16;
-typedef unsigned short __u16;
-
-typedef __signed__ int __s32;
-typedef unsigned int __u32;
-
-typedef __signed__ long long __s64;
-typedef unsigned long long __u64;
-
-typedef signed char s8;
-typedef unsigned char u8;
-
-typedef signed short s16;
-typedef unsigned short u16;
-
-typedef signed int s32;
-typedef unsigned int u32;
-
-typedef signed long long s64;
-typedef unsigned long long u64;
-
-typedef struct {
-       __u32 u[4];
-} __attribute((aligned(16))) __vector128;
-
-#define BITS_PER_LONG 32
-
-typedef __vector128 vector128;
-
-#endif /* _PPC64_TYPES_H */
diff --git a/arch/ppc64/boot/ppc_asm.h b/arch/ppc64/boot/ppc_asm.h
new file mode 100644 (file)
index 0000000..1c2c281
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef _PPC64_PPC_ASM_H
+#define _PPC64_PPC_ASM_H
+/*
+ *
+ * Definitions used by various bits of low-level assembly code on PowerPC.
+ *
+ * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan.
+ *
+ *  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.
+ */
+
+/* Condition Register Bit Fields */
+
+#define        cr0     0
+#define        cr1     1
+#define        cr2     2
+#define        cr3     3
+#define        cr4     4
+#define        cr5     5
+#define        cr6     6
+#define        cr7     7
+
+
+/* General Purpose Registers (GPRs) */
+
+#define        r0      0
+#define        r1      1
+#define        r2      2
+#define        r3      3
+#define        r4      4
+#define        r5      5
+#define        r6      6
+#define        r7      7
+#define        r8      8
+#define        r9      9
+#define        r10     10
+#define        r11     11
+#define        r12     12
+#define        r13     13
+#define        r14     14
+#define        r15     15
+#define        r16     16
+#define        r17     17
+#define        r18     18
+#define        r19     19
+#define        r20     20
+#define        r21     21
+#define        r22     22
+#define        r23     23
+#define        r24     24
+#define        r25     25
+#define        r26     26
+#define        r27     27
+#define        r28     28
+#define        r29     29
+#define        r30     30
+#define        r31     31
+
+#endif /* _PPC64_PPC_ASM_H */
index 5e48b80ff5a07471bd2f07feba550bd85cf9bbaf..4bea2f4dcb067412be7610b23308a0d9c996302b 100644 (file)
@@ -7,43 +7,19 @@
  * 2 of the License, or (at your option) any later version.
  */
 #include <stdarg.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-
-extern __u32 __div64_32(unsigned long long *dividend, __u32 divisor);
-
-/* The unnecessary pointer compare is there
- * to check for type safety (n must be 64bit)
- */
-# define do_div(n,base) ({                             \
-       __u32 __base = (base);                  \
-       __u32 __rem;                                    \
-       (void)(((typeof((n)) *)0) == ((unsigned long long *)0));        \
-       if (((n) >> 32) == 0) {                 \
-               __rem = (__u32)(n) % __base;            \
-               (n) = (__u32)(n) / __base;              \
-       } else                                          \
-               __rem = __div64_32(&(n), __base);       \
-       __rem;                                          \
- })
+#include <stddef.h>
+#include "string.h"
+#include "stdio.h"
+#include "prom.h"
 
 int (*prom)(void *);
 
 void *chosen_handle;
+
 void *stdin;
 void *stdout;
 void *stderr;
 
-void exit(void);
-void *finddevice(const char *name);
-int getprop(void *phandle, const char *name, void *buf, int buflen);
-void chrpboot(int a1, int a2, void *prom);     /* in main.c */
-
-int printf(char *fmt, ...);
-
-/* there is no convenient header to get this from...  -- paulus */
-extern unsigned long strlen(const char *);
 
 int
 write(void *handle, void *ptr, int nb)
@@ -210,107 +186,6 @@ fputs(char *str, void *f)
        return write(f, str, n) == n? 0: -1;
 }
 
-int
-readchar(void)
-{
-       char ch;
-
-       for (;;) {
-               switch (read(stdin, &ch, 1)) {
-               case 1:
-                       return ch;
-               case -1:
-                       printf("read(stdin) returned -1\r\n");
-                       return -1;
-               }
-       }
-}
-
-static char line[256];
-static char *lineptr;
-static int lineleft;
-
-int
-getchar(void)
-{
-       int c;
-
-       if (lineleft == 0) {
-               lineptr = line;
-               for (;;) {
-                       c = readchar();
-                       if (c == -1 || c == 4)
-                               break;
-                       if (c == '\r' || c == '\n') {
-                               *lineptr++ = '\n';
-                               putchar('\n');
-                               break;
-                       }
-                       switch (c) {
-                       case 0177:
-                       case '\b':
-                               if (lineptr > line) {
-                                       putchar('\b');
-                                       putchar(' ');
-                                       putchar('\b');
-                                       --lineptr;
-                               }
-                               break;
-                       case 'U' & 0x1F:
-                               while (lineptr > line) {
-                                       putchar('\b');
-                                       putchar(' ');
-                                       putchar('\b');
-                                       --lineptr;
-                               }
-                               break;
-                       default:
-                               if (lineptr >= &line[sizeof(line) - 1])
-                                       putchar('\a');
-                               else {
-                                       putchar(c);
-                                       *lineptr++ = c;
-                               }
-                       }
-               }
-               lineleft = lineptr - line;
-               lineptr = line;
-       }
-       if (lineleft == 0)
-               return -1;
-       --lineleft;
-       return *lineptr++;
-}
-
-
-
-/* String functions lifted from lib/vsprintf.c and lib/ctype.c */
-unsigned char _ctype[] = {
-_C,_C,_C,_C,_C,_C,_C,_C,                       /* 0-7 */
-_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,                /* 8-15 */
-_C,_C,_C,_C,_C,_C,_C,_C,                       /* 16-23 */
-_C,_C,_C,_C,_C,_C,_C,_C,                       /* 24-31 */
-_S|_SP,_P,_P,_P,_P,_P,_P,_P,                   /* 32-39 */
-_P,_P,_P,_P,_P,_P,_P,_P,                       /* 40-47 */
-_D,_D,_D,_D,_D,_D,_D,_D,                       /* 48-55 */
-_D,_D,_P,_P,_P,_P,_P,_P,                       /* 56-63 */
-_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,     /* 64-71 */
-_U,_U,_U,_U,_U,_U,_U,_U,                       /* 72-79 */
-_U,_U,_U,_U,_U,_U,_U,_U,                       /* 80-87 */
-_U,_U,_U,_P,_P,_P,_P,_P,                       /* 88-95 */
-_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,     /* 96-103 */
-_L,_L,_L,_L,_L,_L,_L,_L,                       /* 104-111 */
-_L,_L,_L,_L,_L,_L,_L,_L,                       /* 112-119 */
-_L,_L,_L,_P,_P,_P,_P,_C,                       /* 120-127 */
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,               /* 128-143 */
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,               /* 144-159 */
-_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
-_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
-_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
-_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
-_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
-_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */
-
 size_t strnlen(const char * s, size_t count)
 {
        const char *sc;
@@ -320,44 +195,30 @@ size_t strnlen(const char * s, size_t count)
        return sc - s;
 }
 
-unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
-{
-       unsigned long result = 0,value;
+extern unsigned int __div64_32(unsigned long long *dividend,
+                              unsigned int divisor);
 
-       if (!base) {
-               base = 10;
-               if (*cp == '0') {
-                       base = 8;
-                       cp++;
-                       if ((*cp == 'x') && isxdigit(cp[1])) {
-                               cp++;
-                               base = 16;
-                       }
-               }
-       }
-       while (isxdigit(*cp) &&
-              (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
-               result = result*base + value;
-               cp++;
-       }
-       if (endp)
-               *endp = (char *)cp;
-       return result;
-}
-
-long simple_strtol(const char *cp,char **endp,unsigned int base)
-{
-       if(*cp=='-')
-               return -simple_strtoul(cp+1,endp,base);
-       return simple_strtoul(cp,endp,base);
-}
+/* The unnecessary pointer compare is there
+ * to check for type safety (n must be 64bit)
+ */
+# define do_div(n,base) ({                                             \
+       unsigned int __base = (base);                                   \
+       unsigned int __rem;                                             \
+       (void)(((typeof((n)) *)0) == ((unsigned long long *)0));        \
+       if (((n) >> 32) == 0) {                                         \
+               __rem = (unsigned int)(n) % __base;                     \
+               (n) = (unsigned int)(n) / __base;                       \
+       } else                                                          \
+               __rem = __div64_32(&(n), __base);                       \
+       __rem;                                                          \
+ })
 
 static int skip_atoi(const char **s)
 {
-       int i=0;
+       int i, c;
 
-       while (isdigit(**s))
-               i = i*10 + *((*s)++) - '0';
+       for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s)
+               i = i*10 + c - '0';
        return i;
 }
 
@@ -436,9 +297,6 @@ static char * number(char * str, unsigned long long num, int base, int size, int
        return str;
 }
 
-/* Forward decl. needed for IP address printing stuff... */
-int sprintf(char * buf, const char *fmt, ...);
-
 int vsprintf(char *buf, const char *fmt, va_list args)
 {
        int len;
@@ -477,7 +335,7 @@ int vsprintf(char *buf, const char *fmt, va_list args)
                
                /* get field width */
                field_width = -1;
-               if (isdigit(*fmt))
+               if ('0' <= *fmt && *fmt <= '9')
                        field_width = skip_atoi(&fmt);
                else if (*fmt == '*') {
                        ++fmt;
@@ -493,7 +351,7 @@ int vsprintf(char *buf, const char *fmt, va_list args)
                precision = -1;
                if (*fmt == '.') {
                        ++fmt;  
-                       if (isdigit(*fmt))
+                       if ('0' <= *fmt && *fmt <= '9')
                                precision = skip_atoi(&fmt);
                        else if (*fmt == '*') {
                                ++fmt;
@@ -628,7 +486,7 @@ int sprintf(char * buf, const char *fmt, ...)
 static char sprint_buf[1024];
 
 int
-printf(char *fmt, ...)
+printf(const char *fmt, ...)
 {
        va_list args;
        int n;
diff --git a/arch/ppc64/boot/prom.h b/arch/ppc64/boot/prom.h
new file mode 100644 (file)
index 0000000..96ab5ae
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _PPC_BOOT_PROM_H_
+#define _PPC_BOOT_PROM_H_
+
+extern int (*prom) (void *);
+extern void *chosen_handle;
+
+extern void *stdin;
+extern void *stdout;
+extern void *stderr;
+
+extern int write(void *handle, void *ptr, int nb);
+extern int read(void *handle, void *ptr, int nb);
+extern void exit(void);
+extern void pause(void);
+extern void *finddevice(const char *);
+extern void *claim(unsigned long virt, unsigned long size, unsigned long align);
+extern int getprop(void *phandle, const char *name, void *buf, int buflen);
+#endif                         /* _PPC_BOOT_PROM_H_ */
diff --git a/arch/ppc64/boot/stdio.h b/arch/ppc64/boot/stdio.h
new file mode 100644 (file)
index 0000000..24bd3a8
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _PPC_BOOT_STDIO_H_
+#define _PPC_BOOT_STDIO_H_
+
+extern int printf(const char *fmt, ...);
+
+extern int sprintf(char *buf, const char *fmt, ...);
+
+extern int vsprintf(char *buf, const char *fmt, va_list args);
+
+extern int putc(int c, void *f);
+extern int putchar(int c);
+extern int getchar(void);
+
+extern int fputs(char *str, void *f);
+
+#endif                         /* _PPC_BOOT_STDIO_H_ */
index ba5f2d21c9eade5fac5ab5fa4990bc0541dd04a7..7ade87ae7718304fc6ef0ff70c9d36a2cb9a523f 100644 (file)
@@ -9,7 +9,7 @@
  * NOTE: this code runs in 32 bit mode and is packaged as ELF32.
  */
 
-#include <asm/ppc_asm.h>
+#include "ppc_asm.h"
 
        .text
        .globl  strcpy
diff --git a/arch/ppc64/boot/string.h b/arch/ppc64/boot/string.h
new file mode 100644 (file)
index 0000000..9289258
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _PPC_BOOT_STRING_H_
+#define _PPC_BOOT_STRING_H_
+
+extern char *strcpy(char *dest, const char *src);
+extern char *strncpy(char *dest, const char *src, size_t n);
+extern char *strcat(char *dest, const char *src);
+extern int strcmp(const char *s1, const char *s2);
+extern size_t strlen(const char *s);
+extern size_t strnlen(const char *s, size_t count);
+
+extern void *memset(void *s, int c, size_t n);
+extern void *memmove(void *dest, const void *src, unsigned long n);
+extern void *memcpy(void *dest, const void *src, unsigned long n);
+extern int memcmp(const void *s1, const void *s2, size_t n);
+
+#endif /* _PPC_BOOT_STRING_H_ */
index 78837e884b8be4b6bb1240a3062713ad3058c4ec..0d910cd2079df021ea09dd1f87caa94f922e66bc 100644 (file)
@@ -107,7 +107,7 @@ extern void *memcpy(void *, const void *, unsigned long);
 
 /* Diagnostic functions */
 #ifdef DEBUG_ZLIB
-#  include <stdio.h>
+#  include "stdio.h"
 #  ifndef verbose
 #    define verbose 0
 #  endif
index ab567741e80e47e112bc1c0a18a3e4f2523234d8..fc83d93302821697bef3b1af1d7cd0fb49c6e340 100644 (file)
@@ -103,10 +103,10 @@ CONFIG_PREEMPT_NONE=y
 # CONFIG_PREEMPT_VOLUNTARY is not set
 # CONFIG_PREEMPT is not set
 # CONFIG_PREEMPT_BKL is not set
-CONFIG_HZ_100=y
-# CONFIG_HZ_250 is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
 # CONFIG_HZ_1000 is not set
-CONFIG_HZ=100
+CONFIG_HZ=250
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_SECCOMP=y
 CONFIG_ISA_DMA_API=y
index 394ba18b58c7ef8b29db505b2ef59554207271fd..013d4e0e4003aee687135c36124033c780f7f234 100644 (file)
@@ -94,12 +94,11 @@ CONFIG_PREEMPT_NONE=y
 # CONFIG_PREEMPT_VOLUNTARY is not set
 # CONFIG_PREEMPT is not set
 # CONFIG_PREEMPT_BKL is not set
-CONFIG_HZ_100=y
-# CONFIG_HZ_250 is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
 # CONFIG_HZ_1000 is not set
-CONFIG_HZ=100
+CONFIG_HZ=250
 CONFIG_GENERIC_HARDIRQS=y
-CONFIG_MSCHUNKS=y
 CONFIG_LPARCFG=y
 CONFIG_SECCOMP=y
 CONFIG_ISA_DMA_API=y
index 2033fe663dbe09481d6adbbdc3dd5010962c29e5..dd42892cd873720083b79760557138e9542e9bbf 100644 (file)
@@ -103,10 +103,10 @@ CONFIG_PREEMPT_NONE=y
 # CONFIG_PREEMPT_VOLUNTARY is not set
 # CONFIG_PREEMPT is not set
 # CONFIG_PREEMPT_BKL is not set
-CONFIG_HZ_100=y
-# CONFIG_HZ_250 is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
 # CONFIG_HZ_1000 is not set
-CONFIG_HZ=100
+CONFIG_HZ=250
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_SECCOMP=y
 CONFIG_ISA_DMA_API=y
index 297fd5229487e83d9db80d24ce091b86b210f33c..29f7b80b0efc9ea7b8385ef5aa06d35e4fba531a 100644 (file)
@@ -112,10 +112,10 @@ CONFIG_PREEMPT_NONE=y
 # CONFIG_PREEMPT_VOLUNTARY is not set
 # CONFIG_PREEMPT is not set
 # CONFIG_PREEMPT_BKL is not set
-CONFIG_HZ_100=y
-# CONFIG_HZ_250 is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
 # CONFIG_HZ_1000 is not set
-CONFIG_HZ=100
+CONFIG_HZ=250
 CONFIG_EEH=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_PPC_RTAS=y
index c361e7727b7ad89c2c65bdab0c5b70098065b1a3..7cb4750bb7a9bf86f406a261d1bdb85a55f2231a 100644 (file)
@@ -114,10 +114,10 @@ CONFIG_PREEMPT_NONE=y
 # CONFIG_PREEMPT_VOLUNTARY is not set
 # CONFIG_PREEMPT is not set
 # CONFIG_PREEMPT_BKL is not set
-CONFIG_HZ_100=y
-# CONFIG_HZ_250 is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
 # CONFIG_HZ_1000 is not set
-CONFIG_HZ=100
+CONFIG_HZ=250
 CONFIG_EEH=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_PPC_RTAS=y
index 1c11031c838eea170eb02f7db638d4c23a71ef23..0a9c23ca2f0ca6e901904273cd5fffbd12da36fd 100644 (file)
@@ -51,6 +51,17 @@ struct HvReleaseData hvReleaseData = {
                0xf4, 0x4b, 0xf6, 0xf4 },
 };
 
+/*
+ * The NACA.  The first dword of the naca is required by the iSeries
+ * hypervisor to point to itVpdAreas.  The hypervisor finds the NACA
+ * through the pointer in hvReleaseData.
+ */
+struct naca_struct naca = {
+       .xItVpdAreas = &itVpdAreas,
+       .xRamDisk = 0,
+       .xRamDiskSize = 0,
+};
+
 extern void system_reset_iSeries(void);
 extern void machine_check_iSeries(void);
 extern void data_access_iSeries(void);
@@ -214,29 +225,3 @@ struct ItVpdAreas itVpdAreas = {
                0,0
        }
 };
-
-struct msChunks msChunks;
-EXPORT_SYMBOL(msChunks);
-
-/* Depending on whether this is called from iSeries or pSeries setup
- * code, the location of the msChunks struct may or may not have
- * to be reloc'd, so we force the caller to do that for us by passing
- * in a pointer to the structure.
- */
-unsigned long
-msChunks_alloc(unsigned long mem, unsigned long num_chunks, unsigned long chunk_size)
-{
-       unsigned long offset = reloc_offset();
-       struct msChunks *_msChunks = PTRRELOC(&msChunks);
-
-       _msChunks->num_chunks  = num_chunks;
-       _msChunks->chunk_size  = chunk_size;
-       _msChunks->chunk_shift = __ilog2(chunk_size);
-       _msChunks->chunk_mask  = (1UL<<_msChunks->chunk_shift)-1;
-
-       mem = _ALIGN(mem, sizeof(msChunks_entry));
-       _msChunks->abs = (msChunks_entry *)(mem + offset);
-       mem += num_chunks * sizeof(msChunks_entry);
-
-       return mem;
-}
index 2ecccb6b4f8cb51dd7c971547b376eb41a51f140..ae60eb1193c6c5bd90cafc5c603cc2cdb4b54d3f 100644 (file)
@@ -11,7 +11,7 @@ obj-y               :=        setup.o entry.o traps.o irq.o idle.o dma.o \
                        udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \
                        ptrace32.o signal32.o rtc.o init_task.o \
                        lmb.o cputable.o cpu_setup_power4.o idle_power4.o \
-                       iommu.o sysfs.o vdso.o pmc.o
+                       iommu.o sysfs.o vdso.o pmc.o firmware.o
 obj-y += vdso32/ vdso64/
 
 obj-$(CONFIG_PPC_OF) +=        of_device.o
@@ -31,7 +31,7 @@ obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o prom.o
 
 obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \
                             pSeries_nvram.o rtasd.o ras.o pSeries_reconfig.o \
-                            pSeries_setup.o pSeries_iommu.o
+                            pSeries_setup.o pSeries_iommu.o udbg_16550.o
 
 obj-$(CONFIG_PPC_BPA) += bpa_setup.o bpa_iommu.o bpa_nvram.o \
                         bpa_iic.o spider-pic.o
@@ -50,14 +50,19 @@ obj-$(CONFIG_LPARCFG)               += lparcfg.o
 obj-$(CONFIG_HVC_CONSOLE)      += hvconsole.o
 obj-$(CONFIG_BOOTX_TEXT)       += btext.o
 obj-$(CONFIG_HVCS)             += hvcserver.o
-obj-$(CONFIG_IBMVIO)           += vio.o
+
+vio-obj-$(CONFIG_PPC_PSERIES)  += pSeries_vio.o
+vio-obj-$(CONFIG_PPC_ISERIES)  += iSeries_vio.o
+obj-$(CONFIG_IBMVIO)           += vio.o $(vio-obj-y)
 obj-$(CONFIG_XICS)             += xics.o
 obj-$(CONFIG_MPIC)             += mpic.o
 
 obj-$(CONFIG_PPC_PMAC)         += pmac_setup.o pmac_feature.o pmac_pci.o \
-                                  pmac_time.o pmac_nvram.o pmac_low_i2c.o
+                                  pmac_time.o pmac_nvram.o pmac_low_i2c.o \
+                                  udbg_scc.o
 
-obj-$(CONFIG_PPC_MAPLE)                += maple_setup.o maple_pci.o maple_time.o
+obj-$(CONFIG_PPC_MAPLE)                += maple_setup.o maple_pci.o maple_time.o \
+                                  udbg_16550.o
 
 obj-$(CONFIG_U3_DART)          += u3_iommu.o
 
index abb9e5b5da03b81aa42c88b2ad635f7d1cc00914..17e35d0fed09ff87d7eeb0d49e30b02d8e9f139d 100644 (file)
@@ -94,7 +94,8 @@ int main(void)
        DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr));
        DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id));
 #ifdef CONFIG_HUGETLB_PAGE
-       DEFINE(PACAHTLBSEGS, offsetof(struct paca_struct, context.htlb_segs));
+       DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas));
+       DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas));
 #endif /* CONFIG_HUGETLB_PAGE */
        DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr));
         DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen));
index c53f079e9b77af0a4ead0bc85543802ab882fe0f..b6fbfbe9032d4f26cee7109116e1464f7ad8a385 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <linux/version.h>
 
 #include <asm/sections.h>
 #include <asm/prom.h>
index 77cec42f9525897c960f85f86ee4793e2597cd77..8831a28c3c4ea2f5e28032e4bc3b4bad5d5cce62 100644 (file)
@@ -5,7 +5,7 @@
  *
  *  Modifications for ppc64:
  *      Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com>
- * 
+ *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
  *  as published by the Free Software Foundation; either version
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 
+#include <asm/oprofile_impl.h>
 #include <asm/cputable.h>
 
 struct cpu_spec* cur_cpu_spec = NULL;
@@ -54,26 +55,32 @@ struct cpu_spec     cpu_specs[] = {
                .pvr_value              = 0x00400000,
                .cpu_name               = "POWER3 (630)",
                .cpu_features           = CPU_FTR_SPLIT_ID_CACHE |
-                       CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
-                       CPU_FTR_PMC8,
+                       CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR,
                .cpu_user_features = COMMON_USER_PPC64,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
+               .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power3,
-               .firmware_features      = COMMON_PPC64_FW,
+#ifdef CONFIG_OPROFILE
+               .oprofile_cpu_type      = "ppc64/power3",
+               .oprofile_model         = &op_model_rs64,
+#endif
        },
        {       /* Power3+ */
                .pvr_mask               = 0xffff0000,
                .pvr_value              = 0x00410000,
                .cpu_name               = "POWER3 (630+)",
                .cpu_features           = CPU_FTR_SPLIT_ID_CACHE |
-                       CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
-                       CPU_FTR_PMC8,
+                       CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR,
                .cpu_user_features      = COMMON_USER_PPC64,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
+               .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power3,
-               .firmware_features      = COMMON_PPC64_FW,
+#ifdef CONFIG_OPROFILE
+               .oprofile_cpu_type      = "ppc64/power3",
+               .oprofile_model         = &op_model_rs64,
+#endif
        },
        {       /* Northstar */
                .pvr_mask               = 0xffff0000,
@@ -81,12 +88,16 @@ struct cpu_spec     cpu_specs[] = {
                .cpu_name               = "RS64-II (northstar)",
                .cpu_features           = CPU_FTR_SPLIT_ID_CACHE |
                        CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
-                       CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+                       CPU_FTR_MMCRA | CPU_FTR_CTRL,
                .cpu_user_features      = COMMON_USER_PPC64,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
+               .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power3,
-               .firmware_features      = COMMON_PPC64_FW,
+#ifdef CONFIG_OPROFILE
+               .oprofile_cpu_type      = "ppc64/rs64",
+               .oprofile_model         = &op_model_rs64,
+#endif
        },
        {       /* Pulsar */
                .pvr_mask               = 0xffff0000,
@@ -94,12 +105,16 @@ struct cpu_spec    cpu_specs[] = {
                .cpu_name               = "RS64-III (pulsar)",
                .cpu_features           = CPU_FTR_SPLIT_ID_CACHE |
                        CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
-                       CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+                       CPU_FTR_MMCRA | CPU_FTR_CTRL,
                .cpu_user_features      = COMMON_USER_PPC64,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
+               .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power3,
-               .firmware_features      = COMMON_PPC64_FW,
+#ifdef CONFIG_OPROFILE
+               .oprofile_cpu_type      = "ppc64/rs64",
+               .oprofile_model         = &op_model_rs64,
+#endif
        },
        {       /* I-star */
                .pvr_mask               = 0xffff0000,
@@ -107,12 +122,16 @@ struct cpu_spec   cpu_specs[] = {
                .cpu_name               = "RS64-III (icestar)",
                .cpu_features           = CPU_FTR_SPLIT_ID_CACHE |
                        CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
-                       CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+                       CPU_FTR_MMCRA | CPU_FTR_CTRL,
                .cpu_user_features      = COMMON_USER_PPC64,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
+               .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power3,
-               .firmware_features      = COMMON_PPC64_FW,
+#ifdef CONFIG_OPROFILE
+               .oprofile_cpu_type      = "ppc64/rs64",
+               .oprofile_model         = &op_model_rs64,
+#endif
        },
        {       /* S-star */
                .pvr_mask               = 0xffff0000,
@@ -120,12 +139,16 @@ struct cpu_spec   cpu_specs[] = {
                .cpu_name               = "RS64-IV (sstar)",
                .cpu_features           = CPU_FTR_SPLIT_ID_CACHE |
                        CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
-                       CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+                       CPU_FTR_MMCRA | CPU_FTR_CTRL,
                .cpu_user_features      = COMMON_USER_PPC64,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
+               .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power3,
-               .firmware_features      = COMMON_PPC64_FW,
+#ifdef CONFIG_OPROFILE
+               .oprofile_cpu_type      = "ppc64/rs64",
+               .oprofile_model         = &op_model_rs64,
+#endif
        },
        {       /* Power4 */
                .pvr_mask               = 0xffff0000,
@@ -133,12 +156,16 @@ struct cpu_spec   cpu_specs[] = {
                .cpu_name               = "POWER4 (gp)",
                .cpu_features           = CPU_FTR_SPLIT_ID_CACHE |
                        CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-                       CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+                       CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA,
                .cpu_user_features      = COMMON_USER_PPC64,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
+               .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power4,
-               .firmware_features      = COMMON_PPC64_FW,
+#ifdef CONFIG_OPROFILE
+               .oprofile_cpu_type      = "ppc64/power4",
+               .oprofile_model         = &op_model_rs64,
+#endif
        },
        {       /* Power4+ */
                .pvr_mask               = 0xffff0000,
@@ -146,12 +173,16 @@ struct cpu_spec   cpu_specs[] = {
                .cpu_name               = "POWER4+ (gq)",
                .cpu_features           = CPU_FTR_SPLIT_ID_CACHE |
                        CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-                       CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+                       CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA,
                .cpu_user_features      = COMMON_USER_PPC64,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
+               .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power4,
-               .firmware_features      = COMMON_PPC64_FW,
+#ifdef CONFIG_OPROFILE
+               .oprofile_cpu_type      = "ppc64/power4",
+               .oprofile_model         = &op_model_power4,
+#endif
        },
        {       /* PPC970 */
                .pvr_mask               = 0xffff0000,
@@ -160,13 +191,17 @@ struct cpu_spec   cpu_specs[] = {
                .cpu_features           = CPU_FTR_SPLIT_ID_CACHE |
                        CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
                        CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
-                       CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+                       CPU_FTR_CAN_NAP | CPU_FTR_MMCRA,
                .cpu_user_features      = COMMON_USER_PPC64 |
                        PPC_FEATURE_HAS_ALTIVEC_COMP,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
+               .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_ppc970,
-               .firmware_features      = COMMON_PPC64_FW,
+#ifdef CONFIG_OPROFILE
+               .oprofile_cpu_type      = "ppc64/970",
+               .oprofile_model         = &op_model_power4,
+#endif
        },
        {       /* PPC970FX */
                .pvr_mask               = 0xffff0000,
@@ -175,13 +210,17 @@ struct cpu_spec   cpu_specs[] = {
                .cpu_features           = CPU_FTR_SPLIT_ID_CACHE |
                        CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
                        CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
-                       CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+                       CPU_FTR_CAN_NAP | CPU_FTR_MMCRA,
                .cpu_user_features      = COMMON_USER_PPC64 |
                        PPC_FEATURE_HAS_ALTIVEC_COMP,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
+               .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_ppc970,
-               .firmware_features      = COMMON_PPC64_FW,
+#ifdef CONFIG_OPROFILE
+               .oprofile_cpu_type      = "ppc64/970",
+               .oprofile_model         = &op_model_power4,
+#endif
        },
        {       /* PPC970MP */
                .pvr_mask               = 0xffff0000,
@@ -190,13 +229,16 @@ struct cpu_spec   cpu_specs[] = {
                .cpu_features           = CPU_FTR_SPLIT_ID_CACHE |
                        CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
                        CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
-                       CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+                       CPU_FTR_CAN_NAP | CPU_FTR_MMCRA,
                .cpu_user_features      = COMMON_USER_PPC64 |
                        PPC_FEATURE_HAS_ALTIVEC_COMP,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
                .cpu_setup              = __setup_cpu_ppc970,
-               .firmware_features      = COMMON_PPC64_FW,
+#ifdef CONFIG_OPROFILE
+               .oprofile_cpu_type      = "ppc64/970",
+               .oprofile_model         = &op_model_power4,
+#endif
        },
        {       /* Power5 */
                .pvr_mask               = 0xffff0000,
@@ -210,8 +252,12 @@ struct cpu_spec    cpu_specs[] = {
                .cpu_user_features      = COMMON_USER_PPC64,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
+               .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_power4,
-               .firmware_features      = COMMON_PPC64_FW,
+#ifdef CONFIG_OPROFILE
+               .oprofile_cpu_type      = "ppc64/power5",
+               .oprofile_model         = &op_model_power4,
+#endif
        },
        {       /* Power5 */
                .pvr_mask               = 0xffff0000,
@@ -225,8 +271,12 @@ struct cpu_spec    cpu_specs[] = {
                .cpu_user_features      = COMMON_USER_PPC64,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
+               .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_power4,
-               .firmware_features      = COMMON_PPC64_FW,
+#ifdef CONFIG_OPROFILE
+               .oprofile_cpu_type      = "ppc64/power5",
+               .oprofile_model         = &op_model_power4,
+#endif
        },
        {       /* BE DD1.x */
                .pvr_mask               = 0xffff0000,
@@ -241,7 +291,6 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
                .cpu_setup              = __setup_cpu_be,
-               .firmware_features      = COMMON_PPC64_FW,
        },
        {       /* default match */
                .pvr_mask               = 0x00000000,
@@ -253,30 +302,7 @@ struct cpu_spec    cpu_specs[] = {
                .cpu_user_features      = COMMON_USER_PPC64,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
+               .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_power4,
-               .firmware_features      = COMMON_PPC64_FW,
        }
 };
-
-firmware_feature_t firmware_features_table[FIRMWARE_MAX_FEATURES] = {
-       {FW_FEATURE_PFT,                "hcall-pft"},
-       {FW_FEATURE_TCE,                "hcall-tce"},
-       {FW_FEATURE_SPRG0,              "hcall-sprg0"},
-       {FW_FEATURE_DABR,               "hcall-dabr"},
-       {FW_FEATURE_COPY,               "hcall-copy"},
-       {FW_FEATURE_ASR,                "hcall-asr"},
-       {FW_FEATURE_DEBUG,              "hcall-debug"},
-       {FW_FEATURE_PERF,               "hcall-perf"},
-       {FW_FEATURE_DUMP,               "hcall-dump"},
-       {FW_FEATURE_INTERRUPT,          "hcall-interrupt"},
-       {FW_FEATURE_MIGRATE,            "hcall-migrate"},
-       {FW_FEATURE_PERFMON,            "hcall-perfmon"},
-       {FW_FEATURE_CRQ,                "hcall-crq"},
-       {FW_FEATURE_VIO,                "hcall-vio"},
-       {FW_FEATURE_RDMA,               "hcall-rdma"},
-       {FW_FEATURE_LLAN,               "hcall-lLAN"},
-       {FW_FEATURE_BULK,               "hcall-bulk"},
-       {FW_FEATURE_XDABR,              "hcall-xdabr"},
-       {FW_FEATURE_MULTITCE,           "hcall-multi-tce"},
-       {FW_FEATURE_SPLPAR,             "hcall-splpar"},
-};
index b61572eb2a7130d7a46924f8412024b9879286e7..bf99b4a92f20864313c7d79211a5d5a6db68a7ce 100644 (file)
@@ -400,15 +400,14 @@ BEGIN_FTR_SECTION
        cmpd    cr1,r6,r9       /* or is new ESID the same as current ESID? */
        cror    eq,4*cr1+eq,eq
        beq     2f              /* if yes, don't slbie it */
-       oris    r0,r6,0x0800    /* set C (class) bit */
 
        /* Bolt in the new stack SLB entry */
        ld      r7,KSP_VSID(r4) /* Get new stack's VSID */
-       oris    r6,r6,(SLB_ESID_V)@h
-       ori     r6,r6,(SLB_NUM_BOLTED-1)@l
-       slbie   r0
-       slbie   r0              /* Workaround POWER5 < DD2.1 issue */
-       slbmte  r7,r6
+       oris    r0,r6,(SLB_ESID_V)@h
+       ori     r0,r0,(SLB_NUM_BOLTED-1)@l
+       slbie   r6
+       slbie   r6              /* Workaround POWER5 < DD2.1 issue */
+       slbmte  r7,r0
        isync
 
 2:
diff --git a/arch/ppc64/kernel/firmware.c b/arch/ppc64/kernel/firmware.c
new file mode 100644 (file)
index 0000000..d8432c0
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *  arch/ppc64/kernel/firmware.c
+ *
+ *  Extracted from cputable.c
+ *
+ *  Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
+ *
+ *  Modifications for ppc64:
+ *      Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com>
+ *  Copyright (C) 2005 Stephen Rothwell, IBM Corporation
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+
+#include <asm/firmware.h>
+
+unsigned long ppc64_firmware_features;
+
+#ifdef CONFIG_PPC_PSERIES
+firmware_feature_t firmware_features_table[FIRMWARE_MAX_FEATURES] = {
+       {FW_FEATURE_PFT,                "hcall-pft"},
+       {FW_FEATURE_TCE,                "hcall-tce"},
+       {FW_FEATURE_SPRG0,              "hcall-sprg0"},
+       {FW_FEATURE_DABR,               "hcall-dabr"},
+       {FW_FEATURE_COPY,               "hcall-copy"},
+       {FW_FEATURE_ASR,                "hcall-asr"},
+       {FW_FEATURE_DEBUG,              "hcall-debug"},
+       {FW_FEATURE_PERF,               "hcall-perf"},
+       {FW_FEATURE_DUMP,               "hcall-dump"},
+       {FW_FEATURE_INTERRUPT,          "hcall-interrupt"},
+       {FW_FEATURE_MIGRATE,            "hcall-migrate"},
+       {FW_FEATURE_PERFMON,            "hcall-perfmon"},
+       {FW_FEATURE_CRQ,                "hcall-crq"},
+       {FW_FEATURE_VIO,                "hcall-vio"},
+       {FW_FEATURE_RDMA,               "hcall-rdma"},
+       {FW_FEATURE_LLAN,               "hcall-lLAN"},
+       {FW_FEATURE_BULK,               "hcall-bulk"},
+       {FW_FEATURE_XDABR,              "hcall-xdabr"},
+       {FW_FEATURE_MULTITCE,           "hcall-multi-tce"},
+       {FW_FEATURE_SPLPAR,             "hcall-splpar"},
+};
+#endif
index accaa052d31fbe3b861e048ee0eb3de0bd5e2845..b436206e317df175118e3aed5ac28441e06980d7 100644 (file)
  *  2 of the License, or (at your option) any later version.
  */
 
-#define SECONDARY_PROCESSORS
-
 #include <linux/config.h>
 #include <linux/threads.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/mmu.h>
-#include <asm/naca.h>
 #include <asm/systemcfg.h>
 #include <asm/ppc_asm.h>
 #include <asm/offsets.h>
 #define DO_SOFT_DISABLE
 #endif
 
-/*
- * hcall interface to pSeries LPAR
- */
-#define H_SET_ASR      0x30
-
 /*
  * We layout physical memory as follows:
  * 0x0000 - 0x00ff : Secondary processor spin code
  * 0x0100 - 0x2fff : pSeries Interrupt prologs
- * 0x3000 - 0x3fff : Interrupt support
- * 0x4000 - 0x4fff : NACA
- * 0x6000         : iSeries and common interrupt prologs
- * 0x9000 - 0x9fff : Initial segment table
+ * 0x3000 - 0x5fff : interrupt support, iSeries and common interrupt prologs
+ * 0x6000 - 0x6fff : Initial (CPU0) segment table
+ * 0x7000 - 0x7fff : FWNMI data area
+ * 0x8000 -        : Early init and support code
  */
 
 /*
@@ -94,6 +86,7 @@ END_FTR_SECTION(0, 1)
 
        /* Catch branch to 0 in real mode */
        trap
+
 #ifdef CONFIG_PPC_ISERIES
        /*
         * At offset 0x20, there is a pointer to iSeries LPAR data.
@@ -103,12 +96,12 @@ END_FTR_SECTION(0, 1)
        .llong hvReleaseData-KERNELBASE
 
        /*
-        * At offset 0x28 and 0x30 are offsets to the msChunks
+        * At offset 0x28 and 0x30 are offsets to the mschunks_map
         * array (used by the iSeries LPAR debugger to do translation
         * between physical addresses and absolute addresses) and
         * to the pidhash table (also used by the debugger)
         */
-       .llong msChunks-KERNELBASE
+       .llong mschunks_map-KERNELBASE
        .llong 0        /* pidhash-KERNELBASE SFRXXX */
 
        /* Offset 0x38 - Pointer to start of embedded System.map */
@@ -120,7 +113,7 @@ embedded_sysmap_start:
 embedded_sysmap_end:
        .llong  0
 
-#else /* CONFIG_PPC_ISERIES */
+#endif /* CONFIG_PPC_ISERIES */
 
        /* Secondary processors spin on this value until it goes to 1. */
        .globl  __secondary_hold_spinloop
@@ -155,7 +148,7 @@ _GLOBAL(__secondary_hold)
        std     r24,__secondary_hold_acknowledge@l(0)
        sync
 
-       /* All secondary cpu's wait here until told to start. */
+       /* All secondary cpus wait here until told to start. */
 100:   ld      r4,__secondary_hold_spinloop@l(0)
        cmpdi   0,r4,1
        bne     100b
@@ -170,7 +163,6 @@ _GLOBAL(__secondary_hold)
        BUG_OPCODE
 #endif
 #endif
-#endif
 
 /* This value is used to mark exception frames on the stack. */
        .section ".toc","aw"
@@ -502,33 +494,37 @@ system_call_pSeries:
        STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint)
        STD_EXCEPTION_PSERIES(0x1700, altivec_assist)
 
+       . = 0x3000
+
+/*** pSeries interrupt support ***/
+
        /* moved from 0xf00 */
-       STD_EXCEPTION_PSERIES(0x3000, performance_monitor)
+       STD_EXCEPTION_PSERIES(., performance_monitor)
 
-       . = 0x3100
+       .align  7
 _GLOBAL(do_stab_bolted_pSeries)
        mtcrf   0x80,r12
        mfspr   r12,SPRG2
        EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted)
 
-       
-       /* Space for the naca.  Architected to be located at real address
-        * NACA_PHYS_ADDR.  Various tools rely on this location being fixed.
-        * The first dword of the naca is required by iSeries LPAR to
-        * point to itVpdAreas.  On pSeries native, this value is not used.
-        */
-       . = NACA_PHYS_ADDR
-       .globl __end_interrupts
-__end_interrupts:
-#ifdef CONFIG_PPC_ISERIES
-       .globl naca
-naca:
-       .llong  itVpdAreas
-       .llong  0               /* xRamDisk */
-       .llong  0               /* xRamDiskSize */
+/*
+ * Vectors for the FWNMI option.  Share common code.
+ */
+      .globl system_reset_fwnmi
+system_reset_fwnmi:
+      HMT_MEDIUM
+      mtspr   SPRG1,r13               /* save r13 */
+      RUNLATCH_ON(r13)
+      EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)
 
-       . = 0x6100
+      .globl machine_check_fwnmi
+machine_check_fwnmi:
+      HMT_MEDIUM
+      mtspr   SPRG1,r13               /* save r13 */
+      RUNLATCH_ON(r13)
+      EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
 
+#ifdef CONFIG_PPC_ISERIES
 /***  ISeries-LPAR interrupt handlers ***/
 
        STD_EXCEPTION_ISERIES(0x200, machine_check, PACA_EXMC)
@@ -626,9 +622,7 @@ system_reset_iSeries:
 
        cmpwi   0,r23,0
        beq     iSeries_secondary_smp_loop      /* Loop until told to go */
-#ifdef SECONDARY_PROCESSORS
        bne     .__secondary_start              /* Loop until told to go */
-#endif
 iSeries_secondary_smp_loop:
        /* Let the Hypervisor know we are alive */
        /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
@@ -671,51 +665,8 @@ hardware_interrupt_iSeries_masked:
        ld      r13,PACA_EXGEN+EX_R13(r13)
        rfid
        b       .       /* prevent speculative execution */
-#endif
-
-/*
- * Data area reserved for FWNMI option.
- */
-       .= 0x7000
-       .globl fwnmi_data_area
-fwnmi_data_area:
-
-#ifdef CONFIG_PPC_ISERIES
-       . = LPARMAP_PHYS
-#include "lparmap.s"
 #endif /* CONFIG_PPC_ISERIES */
 
-/*
- * Vectors for the FWNMI option.  Share common code.
- */
-       . = 0x8000
-       .globl system_reset_fwnmi
-system_reset_fwnmi:
-       HMT_MEDIUM
-       mtspr   SPRG1,r13               /* save r13 */
-       RUNLATCH_ON(r13)
-       EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)
-       .globl machine_check_fwnmi
-machine_check_fwnmi:
-       HMT_MEDIUM
-       mtspr   SPRG1,r13               /* save r13 */
-       RUNLATCH_ON(r13)
-       EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
-
-       /*
-        * Space for the initial segment table
-        * For LPAR, the hypervisor must fill in at least one entry
-        * before we get control (with relocate on)
-        */
-       . = STAB0_PHYS_ADDR
-       .globl __start_stab
-__start_stab:
-
-       . = (STAB0_PHYS_ADDR + PAGE_SIZE)
-       .globl __end_stab
-__end_stab:
-
-
 /*** Common interrupt handlers ***/
 
        STD_EXCEPTION_COMMON(0x100, system_reset, .system_reset_exception)
@@ -752,8 +703,8 @@ machine_check_common:
  * R9 contains the saved CR, r13 points to the paca,
  * r10 contains the (bad) kernel stack pointer,
  * r11 and r12 contain the saved SRR0 and SRR1.
- * We switch to using the paca guard page as an emergency stack,
- * save the registers there, and call kernel_bad_stack(), which panics.
+ * We switch to using an emergency stack, save the registers there,
+ * and call kernel_bad_stack(), which panics.
  */
 bad_stack:
        ld      r1,PACAEMERGSP(r13)
@@ -906,6 +857,62 @@ fp_unavailable_common:
        bl      .kernel_fp_unavailable_exception
        BUG_OPCODE
 
+/*
+ * load_up_fpu(unused, unused, tsk)
+ * Disable FP for the task which had the FPU previously,
+ * and save its floating-point registers in its thread_struct.
+ * Enables the FPU for use in the kernel on return.
+ * On SMP we know the fpu is free, since we give it up every
+ * switch (ie, no lazy save of the FP registers).
+ * On entry: r13 == 'current' && last_task_used_math != 'current'
+ */
+_STATIC(load_up_fpu)
+       mfmsr   r5                      /* grab the current MSR */
+       ori     r5,r5,MSR_FP
+       mtmsrd  r5                      /* enable use of fpu now */
+       isync
+/*
+ * For SMP, we don't do lazy FPU switching because it just gets too
+ * horrendously complex, especially when a task switches from one CPU
+ * to another.  Instead we call giveup_fpu in switch_to.
+ *
+ */
+#ifndef CONFIG_SMP
+       ld      r3,last_task_used_math@got(r2)
+       ld      r4,0(r3)
+       cmpdi   0,r4,0
+       beq     1f
+       /* Save FP state to last_task_used_math's THREAD struct */
+       addi    r4,r4,THREAD
+       SAVE_32FPRS(0, r4)
+       mffs    fr0
+       stfd    fr0,THREAD_FPSCR(r4)
+       /* Disable FP for last_task_used_math */
+       ld      r5,PT_REGS(r4)
+       ld      r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+       li      r6,MSR_FP|MSR_FE0|MSR_FE1
+       andc    r4,r4,r6
+       std     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#endif /* CONFIG_SMP */
+       /* enable use of FP after return */
+       ld      r4,PACACURRENT(r13)
+       addi    r5,r4,THREAD            /* Get THREAD */
+       ld      r4,THREAD_FPEXC_MODE(r5)
+       ori     r12,r12,MSR_FP
+       or      r12,r12,r4
+       std     r12,_MSR(r1)
+       lfd     fr0,THREAD_FPSCR(r5)
+       mtfsf   0xff,fr0
+       REST_32FPRS(0, r5)
+#ifndef CONFIG_SMP
+       /* Update last_task_used_math to 'current' */
+       subi    r4,r5,THREAD            /* Back to 'current' */
+       std     r4,0(r3)
+#endif /* CONFIG_SMP */
+       /* restore registers and return */
+       b       fast_exception_return
+
        .align  7
        .globl altivec_unavailable_common
 altivec_unavailable_common:
@@ -921,6 +928,80 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
        bl      .altivec_unavailable_exception
        b       .ret_from_except
 
+#ifdef CONFIG_ALTIVEC
+/*
+ * load_up_altivec(unused, unused, tsk)
+ * Disable VMX for the task which had it previously,
+ * and save its vector registers in its thread_struct.
+ * Enables the VMX for use in the kernel on return.
+ * On SMP we know the VMX is free, since we give it up every
+ * switch (ie, no lazy save of the vector registers).
+ * On entry: r13 == 'current' && last_task_used_altivec != 'current'
+ */
+_STATIC(load_up_altivec)
+       mfmsr   r5                      /* grab the current MSR */
+       oris    r5,r5,MSR_VEC@h
+       mtmsrd  r5                      /* enable use of VMX now */
+       isync
+
+/*
+ * For SMP, we don't do lazy VMX switching because it just gets too
+ * horrendously complex, especially when a task switches from one CPU
+ * to another.  Instead we call giveup_altvec in switch_to.
+ * VRSAVE isn't dealt with here, that is done in the normal context
+ * switch code. Note that we could rely on vrsave value to eventually
+ * avoid saving all of the VREGs here...
+ */
+#ifndef CONFIG_SMP
+       ld      r3,last_task_used_altivec@got(r2)
+       ld      r4,0(r3)
+       cmpdi   0,r4,0
+       beq     1f
+       /* Save VMX state to last_task_used_altivec's THREAD struct */
+       addi    r4,r4,THREAD
+       SAVE_32VRS(0,r5,r4)
+       mfvscr  vr0
+       li      r10,THREAD_VSCR
+       stvx    vr0,r10,r4
+       /* Disable VMX for last_task_used_altivec */
+       ld      r5,PT_REGS(r4)
+       ld      r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+       lis     r6,MSR_VEC@h
+       andc    r4,r4,r6
+       std     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#endif /* CONFIG_SMP */
+       /* Hack: if we get an altivec unavailable trap with VRSAVE
+        * set to all zeros, we assume this is a broken application
+        * that fails to set it properly, and thus we switch it to
+        * all 1's
+        */
+       mfspr   r4,SPRN_VRSAVE
+       cmpdi   0,r4,0
+       bne+    1f
+       li      r4,-1
+       mtspr   SPRN_VRSAVE,r4
+1:
+       /* enable use of VMX after return */
+       ld      r4,PACACURRENT(r13)
+       addi    r5,r4,THREAD            /* Get THREAD */
+       oris    r12,r12,MSR_VEC@h
+       std     r12,_MSR(r1)
+       li      r4,1
+       li      r10,THREAD_VSCR
+       stw     r4,THREAD_USED_VR(r5)
+       lvx     vr0,r10,r5
+       mtvscr  vr0
+       REST_32VRS(0,r4,r5)
+#ifndef CONFIG_SMP
+       /* Update last_task_used_math to 'current' */
+       subi    r4,r5,THREAD            /* Back to 'current' */
+       std     r4,0(r3)
+#endif /* CONFIG_SMP */
+       /* restore registers and return */
+       b       fast_exception_return
+#endif /* CONFIG_ALTIVEC */
+
 /*
  * Hash table stuff
  */
@@ -1167,6 +1248,42 @@ unrecov_slb:
        bl      .unrecoverable_exception
        b       1b
 
+/*
+ * Space for CPU0's segment table.
+ *
+ * On iSeries, the hypervisor must fill in at least one entry before
+ * we get control (with relocate on).  The address is give to the hv
+ * as a page number (see xLparMap in LparData.c), so this must be at a
+ * fixed address (the linker can't compute (u64)&initial_stab >>
+ * PAGE_SHIFT).
+ */
+       . = STAB0_PHYS_ADDR     /* 0x6000 */
+       .globl initial_stab
+initial_stab:
+       .space  4096
+
+/*
+ * Data area reserved for FWNMI option.
+ * This address (0x7000) is fixed by the RPA.
+ */
+       .= 0x7000
+       .globl fwnmi_data_area
+fwnmi_data_area:
+
+       /* iSeries does not use the FWNMI stuff, so it is safe to put
+        * this here, even if we later allow kernels that will boot on
+        * both pSeries and iSeries */
+#ifdef CONFIG_PPC_ISERIES
+        . = LPARMAP_PHYS
+#include "lparmap.s"
+/*
+ * This ".text" is here for old compilers that generate a trailing
+ * .note section when compiling .c files to .s
+ */
+       .text
+#endif /* CONFIG_PPC_ISERIES */
+
+        . = 0x8000
 
 /*
  * On pSeries, secondary processors spin in the following code.
@@ -1200,7 +1317,7 @@ _GLOBAL(pSeries_secondary_smp_init)
        b       .kexec_wait             /* next kernel might do better   */
 
 2:     mtspr   SPRG3,r13               /* Save vaddr of paca in SPRG3   */
-       /* From now on, r24 is expected to be logica cpuid */
+       /* From now on, r24 is expected to be logical cpuid */
        mr      r24,r5
 3:     HMT_LOW
        lbz     r23,PACAPROCSTART(r13)  /* Test if this processor should */
@@ -1213,9 +1330,7 @@ _GLOBAL(pSeries_secondary_smp_init)
 
        cmpwi   0,r23,0
 #ifdef CONFIG_SMP
-#ifdef SECONDARY_PROCESSORS
        bne     .__secondary_start
-#endif
 #endif
        b       3b                      /* Loop until told to go         */
 
@@ -1430,228 +1545,6 @@ _GLOBAL(copy_and_flush)
 .align 8
 copy_to_here:
 
-/*
- * load_up_fpu(unused, unused, tsk)
- * Disable FP for the task which had the FPU previously,
- * and save its floating-point registers in its thread_struct.
- * Enables the FPU for use in the kernel on return.
- * On SMP we know the fpu is free, since we give it up every
- * switch (ie, no lazy save of the FP registers).
- * On entry: r13 == 'current' && last_task_used_math != 'current'
- */
-_STATIC(load_up_fpu)
-       mfmsr   r5                      /* grab the current MSR */
-       ori     r5,r5,MSR_FP
-       mtmsrd  r5                      /* enable use of fpu now */
-       isync
-/*
- * For SMP, we don't do lazy FPU switching because it just gets too
- * horrendously complex, especially when a task switches from one CPU
- * to another.  Instead we call giveup_fpu in switch_to.
- *
- */
-#ifndef CONFIG_SMP
-       ld      r3,last_task_used_math@got(r2)
-       ld      r4,0(r3)
-       cmpdi   0,r4,0
-       beq     1f
-       /* Save FP state to last_task_used_math's THREAD struct */
-       addi    r4,r4,THREAD
-       SAVE_32FPRS(0, r4)
-       mffs    fr0
-       stfd    fr0,THREAD_FPSCR(r4)
-       /* Disable FP for last_task_used_math */
-       ld      r5,PT_REGS(r4)
-       ld      r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-       li      r6,MSR_FP|MSR_FE0|MSR_FE1
-       andc    r4,r4,r6
-       std     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#endif /* CONFIG_SMP */
-       /* enable use of FP after return */
-       ld      r4,PACACURRENT(r13)
-       addi    r5,r4,THREAD            /* Get THREAD */
-       ld      r4,THREAD_FPEXC_MODE(r5)
-       ori     r12,r12,MSR_FP
-       or      r12,r12,r4
-       std     r12,_MSR(r1)
-       lfd     fr0,THREAD_FPSCR(r5)
-       mtfsf   0xff,fr0
-       REST_32FPRS(0, r5)
-#ifndef CONFIG_SMP
-       /* Update last_task_used_math to 'current' */
-       subi    r4,r5,THREAD            /* Back to 'current' */
-       std     r4,0(r3)
-#endif /* CONFIG_SMP */
-       /* restore registers and return */
-       b       fast_exception_return
-
-/*
- * disable_kernel_fp()
- * Disable the FPU.
- */
-_GLOBAL(disable_kernel_fp)
-       mfmsr   r3
-       rldicl  r0,r3,(63-MSR_FP_LG),1
-       rldicl  r3,r0,(MSR_FP_LG+1),0
-       mtmsrd  r3                      /* disable use of fpu now */
-       isync
-       blr
-
-/*
- * giveup_fpu(tsk)
- * Disable FP for the task given as the argument,
- * and save the floating-point registers in its thread_struct.
- * Enables the FPU for use in the kernel on return.
- */
-_GLOBAL(giveup_fpu)
-       mfmsr   r5
-       ori     r5,r5,MSR_FP
-       mtmsrd  r5                      /* enable use of fpu now */
-       isync
-       cmpdi   0,r3,0
-       beqlr-                          /* if no previous owner, done */
-       addi    r3,r3,THREAD            /* want THREAD of task */
-       ld      r5,PT_REGS(r3)
-       cmpdi   0,r5,0
-       SAVE_32FPRS(0, r3)
-       mffs    fr0
-       stfd    fr0,THREAD_FPSCR(r3)
-       beq     1f
-       ld      r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-       li      r3,MSR_FP|MSR_FE0|MSR_FE1
-       andc    r4,r4,r3                /* disable FP for previous task */
-       std     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#ifndef CONFIG_SMP
-       li      r5,0
-       ld      r4,last_task_used_math@got(r2)
-       std     r5,0(r4)
-#endif /* CONFIG_SMP */
-       blr
-
-
-#ifdef CONFIG_ALTIVEC
-               
-/*
- * load_up_altivec(unused, unused, tsk)
- * Disable VMX for the task which had it previously,
- * and save its vector registers in its thread_struct.
- * Enables the VMX for use in the kernel on return.
- * On SMP we know the VMX is free, since we give it up every
- * switch (ie, no lazy save of the vector registers).
- * On entry: r13 == 'current' && last_task_used_altivec != 'current'
- */
-_STATIC(load_up_altivec)
-       mfmsr   r5                      /* grab the current MSR */
-       oris    r5,r5,MSR_VEC@h
-       mtmsrd  r5                      /* enable use of VMX now */
-       isync
-       
-/*
- * For SMP, we don't do lazy VMX switching because it just gets too
- * horrendously complex, especially when a task switches from one CPU
- * to another.  Instead we call giveup_altvec in switch_to.
- * VRSAVE isn't dealt with here, that is done in the normal context
- * switch code. Note that we could rely on vrsave value to eventually
- * avoid saving all of the VREGs here...
- */
-#ifndef CONFIG_SMP
-       ld      r3,last_task_used_altivec@got(r2)
-       ld      r4,0(r3)
-       cmpdi   0,r4,0
-       beq     1f
-       /* Save VMX state to last_task_used_altivec's THREAD struct */
-       addi    r4,r4,THREAD
-       SAVE_32VRS(0,r5,r4)
-       mfvscr  vr0
-       li      r10,THREAD_VSCR
-       stvx    vr0,r10,r4
-       /* Disable VMX for last_task_used_altivec */
-       ld      r5,PT_REGS(r4)
-       ld      r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-       lis     r6,MSR_VEC@h
-       andc    r4,r4,r6
-       std     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#endif /* CONFIG_SMP */
-       /* Hack: if we get an altivec unavailable trap with VRSAVE
-        * set to all zeros, we assume this is a broken application
-        * that fails to set it properly, and thus we switch it to
-        * all 1's
-        */
-       mfspr   r4,SPRN_VRSAVE
-       cmpdi   0,r4,0
-       bne+    1f
-       li      r4,-1
-       mtspr   SPRN_VRSAVE,r4
-1:
-       /* enable use of VMX after return */
-       ld      r4,PACACURRENT(r13)
-       addi    r5,r4,THREAD            /* Get THREAD */
-       oris    r12,r12,MSR_VEC@h
-       std     r12,_MSR(r1)
-       li      r4,1
-       li      r10,THREAD_VSCR
-       stw     r4,THREAD_USED_VR(r5)
-       lvx     vr0,r10,r5
-       mtvscr  vr0
-       REST_32VRS(0,r4,r5)
-#ifndef CONFIG_SMP
-       /* Update last_task_used_math to 'current' */
-       subi    r4,r5,THREAD            /* Back to 'current' */
-       std     r4,0(r3)
-#endif /* CONFIG_SMP */
-       /* restore registers and return */
-       b       fast_exception_return
-
-/*
- * disable_kernel_altivec()
- * Disable the VMX.
- */
-_GLOBAL(disable_kernel_altivec)
-       mfmsr   r3
-       rldicl  r0,r3,(63-MSR_VEC_LG),1
-       rldicl  r3,r0,(MSR_VEC_LG+1),0
-       mtmsrd  r3                      /* disable use of VMX now */
-       isync
-       blr
-
-/*
- * giveup_altivec(tsk)
- * Disable VMX for the task given as the argument,
- * and save the vector registers in its thread_struct.
- * Enables the VMX for use in the kernel on return.
- */
-_GLOBAL(giveup_altivec)
-       mfmsr   r5
-       oris    r5,r5,MSR_VEC@h
-       mtmsrd  r5                      /* enable use of VMX now */
-       isync
-       cmpdi   0,r3,0
-       beqlr-                          /* if no previous owner, done */
-       addi    r3,r3,THREAD            /* want THREAD of task */
-       ld      r5,PT_REGS(r3)
-       cmpdi   0,r5,0
-       SAVE_32VRS(0,r4,r3)
-       mfvscr  vr0
-       li      r4,THREAD_VSCR
-       stvx    vr0,r4,r3
-       beq     1f
-       ld      r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-       lis     r3,MSR_VEC@h
-       andc    r4,r4,r3                /* disable FP for previous task */
-       std     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#ifndef CONFIG_SMP
-       li      r5,0
-       ld      r4,last_task_used_altivec@got(r2)
-       std     r5,0(r4)
-#endif /* CONFIG_SMP */
-       blr
-
-#endif /* CONFIG_ALTIVEC */
-
 #ifdef CONFIG_SMP
 #ifdef CONFIG_PPC_PMAC
 /*
@@ -1753,8 +1646,9 @@ _GLOBAL(__secondary_start)
 #else
        /* set the ASR */
        ld      r3,systemcfg@got(r2)    /* r3 = ptr to systemcfg         */
+       ld      r3,0(r3)
        lwz     r3,PLATFORM(r3)         /* r3 = platform flags           */
-       cmpldi  r3,PLATFORM_PSERIES_LPAR
+       andi.   r3,r3,PLATFORM_LPAR     /* Test if bit 0 is set (LPAR bit) */
        bne     98f
        mfspr   r3,PVR
        srwi    r3,r3,16
@@ -1916,8 +1810,9 @@ _STATIC(start_here_multiplatform)
        ld      r3,PACASTABREAL(r13)
        ori     r4,r3,1                 /* turn on valid bit             */
        ld      r3,systemcfg@got(r2)    /* r3 = ptr to systemcfg */
+       ld      r3,0(r3)
        lwz     r3,PLATFORM(r3)         /* r3 = platform flags */
-       cmpldi  r3,PLATFORM_PSERIES_LPAR
+       andi.   r3,r3,PLATFORM_LPAR     /* Test if bit 0 is set (LPAR bit) */
        bne     98f
        mfspr   r3,PVR
        srwi    r3,r3,16
@@ -1935,9 +1830,10 @@ _STATIC(start_here_multiplatform)
 99:
        /* Set SDR1 (hash table pointer) */
        ld      r3,systemcfg@got(r2)    /* r3 = ptr to systemcfg */
+       ld      r3,0(r3)
        lwz     r3,PLATFORM(r3)         /* r3 = platform flags */
        /* Test if bit 0 is set (LPAR bit) */
-       andi.   r3,r3,0x1
+       andi.   r3,r3,PLATFORM_LPAR
        bne     98f
        LOADADDR(r6,_SDR1)              /* Only if NOT LPAR */
        sub     r6,r6,r26
@@ -2002,9 +1898,6 @@ _STATIC(start_here_common)
 
        bl .start_kernel
 
-_GLOBAL(__setup_cpu_power3)
-       blr
-
 _GLOBAL(hmt_init)
 #ifdef CONFIG_HMT
        LOADADDR(r5, hmt_thread_data)
@@ -2095,20 +1988,19 @@ _GLOBAL(smp_release_cpus)
 
 /*
  * We put a few things here that have to be page-aligned.
- * This stuff goes at the beginning of the data segment,
- * which is page-aligned.
+ * This stuff goes at the beginning of the bss, which is page-aligned.
  */
-       .data
+       .section ".bss"
+
        .align  12
-       .globl  sdata
-sdata:
+
        .globl  empty_zero_page
 empty_zero_page:
-       .space  4096
+       .space  PAGE_SIZE
 
        .globl  swapper_pg_dir
 swapper_pg_dir:
-       .space  4096
+       .space  PAGE_SIZE
 
 /*
  * This space gets a copy of optional info passed to us by the bootstrap
index b0250ae4a72a5954f77bc21fb600080aea83723a..2192055a90a07ba3f34f074e70cb75225d124fdb 100644 (file)
@@ -41,6 +41,7 @@ static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
                                unsigned long prpn, unsigned long vflags,
                                unsigned long rflags)
 {
+       unsigned long arpn;
        long slot;
        hpte_t lhpte;
        int secondary = 0;
@@ -70,8 +71,10 @@ static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
                slot &= 0x7fffffffffffffff;
        }
 
+       arpn = phys_to_abs(prpn << PAGE_SHIFT) >> PAGE_SHIFT;
+
        lhpte.v = (va >> 23) << HPTE_V_AVPN_SHIFT | vflags | HPTE_V_VALID;
-       lhpte.r = (physRpn_to_absRpn(prpn) << HPTE_R_RPN_SHIFT) | rflags;
+       lhpte.r = (arpn << HPTE_R_RPN_SHIFT) | rflags;
 
        /* Now fill in the actual HPTE */
        HvCallHpt_addValidate(slot, secondary, &lhpte);
index a649edbb23b6605aabe1a981fde2d36649229696..3ffefbbc6623a9e27e262691f5cb877bad32feb2 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/cputable.h>
 #include <asm/sections.h>
 #include <asm/iommu.h>
+#include <asm/firmware.h>
 
 #include <asm/time.h>
 #include "iSeries_setup.h"
@@ -314,6 +315,8 @@ static void __init iSeries_init_early(void)
 
        DBG(" -> iSeries_init_early()\n");
 
+       ppc64_firmware_features = FW_FEATURE_ISERIES;
+
        ppcdbg_initialize();
 
 #if defined(CONFIG_BLK_DEV_INITRD)
@@ -412,6 +415,22 @@ static void __init iSeries_init_early(void)
        DBG(" <- iSeries_init_early()\n");
 }
 
+struct mschunks_map mschunks_map = {
+       /* XXX We don't use these, but Piranha might need them. */
+       .chunk_size  = MSCHUNKS_CHUNK_SIZE,
+       .chunk_shift = MSCHUNKS_CHUNK_SHIFT,
+       .chunk_mask  = MSCHUNKS_OFFSET_MASK,
+};
+EXPORT_SYMBOL(mschunks_map);
+
+void mschunks_alloc(unsigned long num_chunks)
+{
+       klimit = _ALIGN(klimit, sizeof(u32));
+       mschunks_map.mapping = (u32 *)klimit;
+       klimit += num_chunks * sizeof(u32);
+       mschunks_map.num_chunks = num_chunks;
+}
+
 /*
  * The iSeries may have very large memories ( > 128 GB ) and a partition
  * may get memory in "chunks" that may be anywhere in the 2**52 real
@@ -449,7 +468,7 @@ static void __init build_iSeries_Memory_Map(void)
 
        /* Chunk size on iSeries is 256K bytes */
        totalChunks = (u32)HvLpConfig_getMsChunks();
-       klimit = msChunks_alloc(klimit, totalChunks, 1UL << 18);
+       mschunks_alloc(totalChunks);
 
        /*
         * Get absolute address of our load area
@@ -486,7 +505,7 @@ static void __init build_iSeries_Memory_Map(void)
        printk("Load area size %dK\n", loadAreaSize * 256);
 
        for (nextPhysChunk = 0; nextPhysChunk < loadAreaSize; ++nextPhysChunk)
-               msChunks.abs[nextPhysChunk] =
+               mschunks_map.mapping[nextPhysChunk] =
                        loadAreaFirstChunk + nextPhysChunk;
 
        /*
@@ -495,7 +514,7 @@ static void __init build_iSeries_Memory_Map(void)
         */
        hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress());
        hptSizePages = (u32)HvCallHpt_getHptPages();
-       hptSizeChunks = hptSizePages >> (msChunks.chunk_shift - PAGE_SHIFT);
+       hptSizeChunks = hptSizePages >> (MSCHUNKS_CHUNK_SHIFT - PAGE_SHIFT);
        hptLastChunk = hptFirstChunk + hptSizeChunks - 1;
 
        printk("HPT absolute addr = %016lx, size = %dK\n",
@@ -552,7 +571,8 @@ static void __init build_iSeries_Memory_Map(void)
                                     (absChunk > hptLastChunk)) &&
                                    ((absChunk < loadAreaFirstChunk) ||
                                     (absChunk > loadAreaLastChunk))) {
-                                       msChunks.abs[nextPhysChunk] = absChunk;
+                                       mschunks_map.mapping[nextPhysChunk] =
+                                               absChunk;
                                        ++nextPhysChunk;
                                }
                        }
@@ -944,6 +964,8 @@ void __init iSeries_early_setup(void)
        ppc_md.calibrate_decr = iSeries_calibrate_decr;
        ppc_md.progress = iSeries_progress;
 
+       /* XXX Implement enable_pmcs for iSeries */
+
        if (get_paca()->lppaca.shared_proc) {
                ppc_md.idle_loop = iseries_shared_idle;
                printk(KERN_INFO "Using shared processor idle loop\n");
diff --git a/arch/ppc64/kernel/iSeries_vio.c b/arch/ppc64/kernel/iSeries_vio.c
new file mode 100644 (file)
index 0000000..6b754b0
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * IBM PowerPC iSeries Virtual I/O Infrastructure Support.
+ *
+ *    Copyright (c) 2005 Stephen Rothwell, IBM Corp.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/init.h>
+
+#include <asm/vio.h>
+#include <asm/iommu.h>
+#include <asm/abs_addr.h>
+#include <asm/page.h>
+#include <asm/iSeries/vio.h>
+#include <asm/iSeries/HvTypes.h>
+#include <asm/iSeries/HvLpConfig.h>
+#include <asm/iSeries/HvCallXm.h>
+
+struct device *iSeries_vio_dev = &vio_bus_device.dev;
+EXPORT_SYMBOL(iSeries_vio_dev);
+
+static struct iommu_table veth_iommu_table;
+static struct iommu_table vio_iommu_table;
+
+static void __init iommu_vio_init(void)
+{
+       struct iommu_table *t;
+       struct iommu_table_cb cb;
+       unsigned long cbp;
+       unsigned long itc_entries;
+
+       cb.itc_busno = 255;    /* Bus 255 is the virtual bus */
+       cb.itc_virtbus = 0xff; /* Ask for virtual bus */
+
+       cbp = virt_to_abs(&cb);
+       HvCallXm_getTceTableParms(cbp);
+
+       itc_entries = cb.itc_size * PAGE_SIZE / sizeof(union tce_entry);
+       veth_iommu_table.it_size        = itc_entries / 2;
+       veth_iommu_table.it_busno       = cb.itc_busno;
+       veth_iommu_table.it_offset      = cb.itc_offset;
+       veth_iommu_table.it_index       = cb.itc_index;
+       veth_iommu_table.it_type        = TCE_VB;
+       veth_iommu_table.it_blocksize   = 1;
+
+       t = iommu_init_table(&veth_iommu_table);
+
+       if (!t)
+               printk("Virtual Bus VETH TCE table failed.\n");
+
+       vio_iommu_table.it_size         = itc_entries - veth_iommu_table.it_size;
+       vio_iommu_table.it_busno        = cb.itc_busno;
+       vio_iommu_table.it_offset       = cb.itc_offset +
+                                         veth_iommu_table.it_size;
+       vio_iommu_table.it_index        = cb.itc_index;
+       vio_iommu_table.it_type         = TCE_VB;
+       vio_iommu_table.it_blocksize    = 1;
+
+       t = iommu_init_table(&vio_iommu_table);
+
+       if (!t)
+               printk("Virtual Bus VIO TCE table failed.\n");
+}
+
+/**
+ * vio_register_device_iseries: - Register a new iSeries vio device.
+ * @voidev:    The device to register.
+ */
+static struct vio_dev *__init vio_register_device_iseries(char *type,
+               uint32_t unit_num)
+{
+       struct vio_dev *viodev;
+
+       /* allocate a vio_dev for this device */
+       viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
+       if (!viodev)
+               return NULL;
+       memset(viodev, 0, sizeof(struct vio_dev));
+
+       snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%s%d", type, unit_num);
+
+       viodev->name = viodev->dev.bus_id;
+       viodev->type = type;
+       viodev->unit_address = unit_num;
+       viodev->iommu_table = &vio_iommu_table;
+       if (vio_register_device(viodev) == NULL) {
+               kfree(viodev);
+               return NULL;
+       }
+       return viodev;
+}
+
+void __init probe_bus_iseries(void)
+{
+       HvLpIndexMap vlan_map;
+       struct vio_dev *viodev;
+       int i;
+
+       /* there is only one of each of these */
+       vio_register_device_iseries("viocons", 0);
+       vio_register_device_iseries("vscsi", 0);
+
+       vlan_map = HvLpConfig_getVirtualLanIndexMap();
+       for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
+               if ((vlan_map & (0x8000 >> i)) == 0)
+                       continue;
+               viodev = vio_register_device_iseries("vlan", i);
+               /* veth is special and has it own iommu_table */
+               viodev->iommu_table = &veth_iommu_table;
+       }
+       for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++)
+               vio_register_device_iseries("viodasd", i);
+       for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++)
+               vio_register_device_iseries("viocd", i);
+       for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)
+               vio_register_device_iseries("viotape", i);
+}
+
+/**
+ * vio_match_device_iseries: - Tell if a iSeries VIO device matches a
+ *     vio_device_id
+ */
+static int vio_match_device_iseries(const struct vio_device_id *id,
+               const struct vio_dev *dev)
+{
+       return strncmp(dev->type, id->type, strlen(id->type)) == 0;
+}
+
+static struct vio_bus_ops vio_bus_ops_iseries = {
+       .match = vio_match_device_iseries,
+};
+
+/**
+ * vio_bus_init_iseries: - Initialize the iSeries virtual IO bus
+ */
+static int __init vio_bus_init_iseries(void)
+{
+       int err;
+
+       err = vio_bus_init(&vio_bus_ops_iseries);
+       if (err == 0) {
+               iommu_vio_init();
+               vio_bus_device.iommu_table = &vio_iommu_table;
+               iSeries_vio_dev = &vio_bus_device.dev;
+               probe_bus_iseries();
+       }
+       return err;
+}
+
+__initcall(vio_bus_init_iseries);
index a3d519518fb8dfe41f2bcf7450bd2d5546bc3987..7e80d49c589a3bf2f5eea3e68f3d3690b1ceeb03 100644 (file)
@@ -44,7 +44,7 @@ static struct kprobe *kprobe_prev;
 static unsigned long kprobe_status_prev, kprobe_saved_msr_prev;
 static struct pt_regs jprobe_saved_regs;
 
-int arch_prepare_kprobe(struct kprobe *p)
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
 {
        int ret = 0;
        kprobe_opcode_t insn = *p->addr;
@@ -68,27 +68,27 @@ int arch_prepare_kprobe(struct kprobe *p)
        return ret;
 }
 
-void arch_copy_kprobe(struct kprobe *p)
+void __kprobes arch_copy_kprobe(struct kprobe *p)
 {
        memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
        p->opcode = *p->addr;
 }
 
-void arch_arm_kprobe(struct kprobe *p)
+void __kprobes arch_arm_kprobe(struct kprobe *p)
 {
        *p->addr = BREAKPOINT_INSTRUCTION;
        flush_icache_range((unsigned long) p->addr,
                           (unsigned long) p->addr + sizeof(kprobe_opcode_t));
 }
 
-void arch_disarm_kprobe(struct kprobe *p)
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
 {
        *p->addr = p->opcode;
        flush_icache_range((unsigned long) p->addr,
                           (unsigned long) p->addr + sizeof(kprobe_opcode_t));
 }
 
-void arch_remove_kprobe(struct kprobe *p)
+void __kprobes arch_remove_kprobe(struct kprobe *p)
 {
        up(&kprobe_mutex);
        free_insn_slot(p->ainsn.insn);
@@ -102,7 +102,7 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
        regs->msr |= MSR_SE;
 
        /* single step inline if it is a trap variant */
-       if (IS_TW(insn) || IS_TD(insn) || IS_TWI(insn) || IS_TDI(insn))
+       if (is_trap(insn))
                regs->nip = (unsigned long)p->addr;
        else
                regs->nip = (unsigned long)p->ainsn.insn;
@@ -122,7 +122,8 @@ static inline void restore_previous_kprobe(void)
        kprobe_saved_msr = kprobe_saved_msr_prev;
 }
 
-void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
+void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+                                     struct pt_regs *regs)
 {
        struct kretprobe_instance *ri;
 
@@ -151,7 +152,9 @@ static inline int kprobe_handler(struct pt_regs *regs)
                   Disarm the probe we just hit, and ignore it. */
                p = get_kprobe(addr);
                if (p) {
-                       if (kprobe_status == KPROBE_HIT_SS) {
+                       kprobe_opcode_t insn = *p->ainsn.insn;
+                       if (kprobe_status == KPROBE_HIT_SS &&
+                                       is_trap(insn)) {
                                regs->msr &= ~MSR_SE;
                                regs->msr |= kprobe_saved_msr;
                                unlock_kprobes();
@@ -191,8 +194,7 @@ static inline int kprobe_handler(struct pt_regs *regs)
                         * trap variant, it could belong to someone else
                         */
                        kprobe_opcode_t cur_insn = *addr;
-                       if (IS_TW(cur_insn) || IS_TD(cur_insn) ||
-                                       IS_TWI(cur_insn) || IS_TDI(cur_insn))
+                       if (is_trap(cur_insn))
                                goto no_kprobe;
                        /*
                         * The breakpoint instruction was removed right
@@ -244,7 +246,7 @@ void kretprobe_trampoline_holder(void)
 /*
  * Called when the probe at kretprobe trampoline is hit
  */
-int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 {
         struct kretprobe_instance *ri = NULL;
         struct hlist_head *head;
@@ -308,7 +310,7 @@ int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
  * single-stepped a copy of the instruction.  The address of this
  * copy is p->ainsn.insn.
  */
-static void resume_execution(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
 {
        int ret;
        unsigned int insn = *p->ainsn.insn;
@@ -373,8 +375,8 @@ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
 /*
  * Wrapper routine to for handling exceptions.
  */
-int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
-                            void *data)
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+                                      unsigned long val, void *data)
 {
        struct die_args *args = (struct die_args *)data;
        int ret = NOTIFY_DONE;
@@ -402,11 +404,11 @@ int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
        default:
                break;
        }
-       preempt_enable();
+       preempt_enable_no_resched();
        return ret;
 }
 
-int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 {
        struct jprobe *jp = container_of(p, struct jprobe, kp);
 
@@ -419,16 +421,16 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
        return 1;
 }
 
-void jprobe_return(void)
+void __kprobes jprobe_return(void)
 {
        asm volatile("trap" ::: "memory");
 }
 
-void jprobe_return_end(void)
+void __kprobes jprobe_return_end(void)
 {
 };
 
-int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 {
        /*
         * FIXME - we should ideally be validating that we got here 'cos
index d6c6bd03d2a42cf49ec1f8ebeec5ee077a2f683f..5adaca2ddc9da02456db4e2591120b73e7bce1e6 100644 (file)
@@ -28,33 +28,28 @@ void lmb_dump_all(void)
 {
 #ifdef DEBUG
        unsigned long i;
-       struct lmb *_lmb  = &lmb;
 
        udbg_printf("lmb_dump_all:\n");
        udbg_printf("    memory.cnt               = 0x%lx\n",
-                   _lmb->memory.cnt);
+                   lmb.memory.cnt);
        udbg_printf("    memory.size              = 0x%lx\n",
-                   _lmb->memory.size);
-       for (i=0; i < _lmb->memory.cnt ;i++) {
+                   lmb.memory.size);
+       for (i=0; i < lmb.memory.cnt ;i++) {
                udbg_printf("    memory.region[0x%x].base       = 0x%lx\n",
-                           i, _lmb->memory.region[i].base);
-               udbg_printf("                 .physbase = 0x%lx\n",
-                           _lmb->memory.region[i].physbase);
+                           i, lmb.memory.region[i].base);
                udbg_printf("                 .size     = 0x%lx\n",
-                           _lmb->memory.region[i].size);
+                           lmb.memory.region[i].size);
        }
 
        udbg_printf("\n    reserved.cnt   = 0x%lx\n",
-                   _lmb->reserved.cnt);
+                   lmb.reserved.cnt);
        udbg_printf("    reserved.size    = 0x%lx\n",
-                   _lmb->reserved.size);
-       for (i=0; i < _lmb->reserved.cnt ;i++) {
+                   lmb.reserved.size);
+       for (i=0; i < lmb.reserved.cnt ;i++) {
                udbg_printf("    reserved.region[0x%x].base       = 0x%lx\n",
-                           i, _lmb->reserved.region[i].base);
-               udbg_printf("                 .physbase = 0x%lx\n",
-                           _lmb->reserved.region[i].physbase);
+                           i, lmb.reserved.region[i].base);
                udbg_printf("                 .size     = 0x%lx\n",
-                           _lmb->reserved.region[i].size);
+                           lmb.reserved.region[i].size);
        }
 #endif /* DEBUG */
 }
@@ -98,7 +93,6 @@ lmb_coalesce_regions(struct lmb_region *rgn, unsigned long r1, unsigned long r2)
        rgn->region[r1].size += rgn->region[r2].size;
        for (i=r2; i < rgn->cnt-1; i++) {
                rgn->region[i].base = rgn->region[i+1].base;
-               rgn->region[i].physbase = rgn->region[i+1].physbase;
                rgn->region[i].size = rgn->region[i+1].size;
        }
        rgn->cnt--;
@@ -108,49 +102,29 @@ lmb_coalesce_regions(struct lmb_region *rgn, unsigned long r1, unsigned long r2)
 void __init
 lmb_init(void)
 {
-       struct lmb *_lmb = &lmb;
-
        /* Create a dummy zero size LMB which will get coalesced away later.
         * This simplifies the lmb_add() code below...
         */
-       _lmb->memory.region[0].base = 0;
-       _lmb->memory.region[0].size = 0;
-       _lmb->memory.cnt = 1;
+       lmb.memory.region[0].base = 0;
+       lmb.memory.region[0].size = 0;
+       lmb.memory.cnt = 1;
 
        /* Ditto. */
-       _lmb->reserved.region[0].base = 0;
-       _lmb->reserved.region[0].size = 0;
-       _lmb->reserved.cnt = 1;
+       lmb.reserved.region[0].base = 0;
+       lmb.reserved.region[0].size = 0;
+       lmb.reserved.cnt = 1;
 }
 
 /* This routine called with relocation disabled. */
 void __init
 lmb_analyze(void)
 {
-       unsigned long i;
-       unsigned long mem_size = 0;
-       unsigned long size_mask = 0;
-       struct lmb *_lmb = &lmb;
-#ifdef CONFIG_MSCHUNKS
-       unsigned long physbase = 0;
-#endif
-
-       for (i=0; i < _lmb->memory.cnt; i++) {
-               unsigned long lmb_size;
-
-               lmb_size = _lmb->memory.region[i].size;
-
-#ifdef CONFIG_MSCHUNKS
-               _lmb->memory.region[i].physbase = physbase;
-               physbase += lmb_size;
-#else
-               _lmb->memory.region[i].physbase = _lmb->memory.region[i].base;
-#endif
-               mem_size += lmb_size;
-               size_mask |= lmb_size;
-       }
+       int i;
+
+       lmb.memory.size = 0;
 
-       _lmb->memory.size = mem_size;
+       for (i = 0; i < lmb.memory.cnt; i++)
+               lmb.memory.size += lmb.memory.region[i].size;
 }
 
 /* This routine called with relocation disabled. */
@@ -168,7 +142,6 @@ lmb_add_region(struct lmb_region *rgn, unsigned long base, unsigned long size)
                adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize);
                if ( adjacent > 0 ) {
                        rgn->region[i].base -= size;
-                       rgn->region[i].physbase -= size;
                        rgn->region[i].size += size;
                        coalesced++;
                        break;
@@ -195,11 +168,9 @@ lmb_add_region(struct lmb_region *rgn, unsigned long base, unsigned long size)
        for (i=rgn->cnt-1; i >= 0; i--) {
                if (base < rgn->region[i].base) {
                        rgn->region[i+1].base = rgn->region[i].base;
-                       rgn->region[i+1].physbase = rgn->region[i].physbase;
                        rgn->region[i+1].size = rgn->region[i].size;
                }  else {
                        rgn->region[i+1].base = base;
-                       rgn->region[i+1].physbase = lmb_abs_to_phys(base);
                        rgn->region[i+1].size = size;
                        break;
                }
@@ -213,12 +184,11 @@ lmb_add_region(struct lmb_region *rgn, unsigned long base, unsigned long size)
 long __init
 lmb_add(unsigned long base, unsigned long size)
 {
-       struct lmb *_lmb = &lmb;
-       struct lmb_region *_rgn = &(_lmb->memory);
+       struct lmb_region *_rgn = &(lmb.memory);
 
        /* On pSeries LPAR systems, the first LMB is our RMO region. */
        if ( base == 0 )
-               _lmb->rmo_size = size;
+               lmb.rmo_size = size;
 
        return lmb_add_region(_rgn, base, size);
 
@@ -227,8 +197,7 @@ lmb_add(unsigned long base, unsigned long size)
 long __init
 lmb_reserve(unsigned long base, unsigned long size)
 {
-       struct lmb *_lmb = &lmb;
-       struct lmb_region *_rgn = &(_lmb->reserved);
+       struct lmb_region *_rgn = &(lmb.reserved);
 
        return lmb_add_region(_rgn, base, size);
 }
@@ -260,13 +229,10 @@ lmb_alloc_base(unsigned long size, unsigned long align, unsigned long max_addr)
 {
        long i, j;
        unsigned long base = 0;
-       struct lmb *_lmb = &lmb;
-       struct lmb_region *_mem = &(_lmb->memory);
-       struct lmb_region *_rsv = &(_lmb->reserved);
 
-       for (i=_mem->cnt-1; i >= 0; i--) {
-               unsigned long lmbbase = _mem->region[i].base;
-               unsigned long lmbsize = _mem->region[i].size;
+       for (i=lmb.memory.cnt-1; i >= 0; i--) {
+               unsigned long lmbbase = lmb.memory.region[i].base;
+               unsigned long lmbsize = lmb.memory.region[i].size;
 
                if ( max_addr == LMB_ALLOC_ANYWHERE )
                        base = _ALIGN_DOWN(lmbbase+lmbsize-size, align);
@@ -276,8 +242,8 @@ lmb_alloc_base(unsigned long size, unsigned long align, unsigned long max_addr)
                        continue;
 
                while ( (lmbbase <= base) &&
-                       ((j = lmb_overlaps_region(_rsv,base,size)) >= 0) ) {
-                       base = _ALIGN_DOWN(_rsv->region[j].base-size, align);
+                       ((j = lmb_overlaps_region(&lmb.reserved,base,size)) >= 0) ) {
+                       base = _ALIGN_DOWN(lmb.reserved.region[j].base-size, align);
                }
 
                if ( (base != 0) && (lmbbase <= base) )
@@ -287,62 +253,24 @@ lmb_alloc_base(unsigned long size, unsigned long align, unsigned long max_addr)
        if ( i < 0 )
                return 0;
 
-       lmb_add_region(_rsv, base, size);
+       lmb_add_region(&lmb.reserved, base, size);
 
        return base;
 }
 
+/* You must call lmb_analyze() before this. */
 unsigned long __init
 lmb_phys_mem_size(void)
 {
-       struct lmb *_lmb = &lmb;
-#ifdef CONFIG_MSCHUNKS
-       return _lmb->memory.size;
-#else
-       struct lmb_region *_mem = &(_lmb->memory);
-       unsigned long total = 0;
-       int i;
-
-       /* add all physical memory to the bootmem map */
-       for (i=0; i < _mem->cnt; i++)
-               total += _mem->region[i].size;
-       return total;
-#endif /* CONFIG_MSCHUNKS */
+       return lmb.memory.size;
 }
 
 unsigned long __init
 lmb_end_of_DRAM(void)
 {
-       struct lmb *_lmb = &lmb;
-       struct lmb_region *_mem = &(_lmb->memory);
-       int idx = _mem->cnt - 1;
-
-#ifdef CONFIG_MSCHUNKS
-       return (_mem->region[idx].physbase + _mem->region[idx].size);
-#else
-       return (_mem->region[idx].base + _mem->region[idx].size);
-#endif /* CONFIG_MSCHUNKS */
-
-       return 0;
-}
-
-unsigned long __init
-lmb_abs_to_phys(unsigned long aa)
-{
-       unsigned long i, pa = aa;
-       struct lmb *_lmb = &lmb;
-       struct lmb_region *_mem = &(_lmb->memory);
-
-       for (i=0; i < _mem->cnt; i++) {
-               unsigned long lmbbase = _mem->region[i].base;
-               unsigned long lmbsize = _mem->region[i].size;
-               if ( lmb_addrs_overlap(aa,1,lmbbase,lmbsize) ) {
-                       pa = _mem->region[i].physbase + (aa - lmbbase);
-                       break;
-               }
-       }
+       int idx = lmb.memory.cnt - 1;
 
-       return pa;
+       return (lmb.memory.region[idx].base + lmb.memory.region[idx].size);
 }
 
 /*
@@ -353,20 +281,19 @@ void __init lmb_enforce_memory_limit(void)
 {
        extern unsigned long memory_limit;
        unsigned long i, limit;
-       struct lmb_region *mem = &(lmb.memory);
 
        if (! memory_limit)
                return;
 
        limit = memory_limit;
-       for (i = 0; i < mem->cnt; i++) {
-               if (limit > mem->region[i].size) {
-                       limit -= mem->region[i].size;
+       for (i = 0; i < lmb.memory.cnt; i++) {
+               if (limit > lmb.memory.region[i].size) {
+                       limit -= lmb.memory.region[i].size;
                        continue;
                }
 
-               mem->region[i].size = limit;
-               mem->cnt = i + 1;
+               lmb.memory.region[i].size = limit;
+               lmb.memory.cnt = i + 1;
                break;
        }
 }
index 02e96627fa6604999b3ac6aafd926fea185e2676..cae19bbd5acd9d790ef84945b678872ffd1c2593 100644 (file)
@@ -29,7 +29,7 @@
 #include <asm/iSeries/HvLpConfig.h>
 #include <asm/lppaca.h>
 #include <asm/hvcall.h>
-#include <asm/cputable.h>
+#include <asm/firmware.h>
 #include <asm/rtas.h>
 #include <asm/system.h>
 #include <asm/time.h>
@@ -273,6 +273,7 @@ static void parse_system_parameter_string(struct seq_file *m)
                if (!workbuffer) {
                        printk(KERN_ERR "%s %s kmalloc failure at line %d \n",
                               __FILE__, __FUNCTION__, __LINE__);
+                       kfree(local_buffer);                    
                        return;
                }
 #ifdef LPARCFG_DEBUG
@@ -377,7 +378,7 @@ static int lparcfg_data(struct seq_file *m, void *v)
 
        partition_active_processors = lparcfg_count_active_processors();
 
-       if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
+       if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
                unsigned long h_entitled, h_unallocated;
                unsigned long h_aggregation, h_resource;
                unsigned long pool_idle_time, pool_procs;
@@ -568,10 +569,10 @@ struct file_operations lparcfg_fops = {
 int __init lparcfg_init(void)
 {
        struct proc_dir_entry *ent;
-       mode_t mode = S_IRUSR;
+       mode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
 
        /* Allow writing if we have FW_FEATURE_SPLPAR */
-       if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
+       if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
                lparcfg_fops.write = lparcfg_write;
                mode |= S_IWUSR;
        }
index bb55b5a569103ca48d7932d753f41ceeb9349f11..fc0567498a3a30deeb69bb80cc897e98e5b8db40 100644 (file)
@@ -207,9 +207,6 @@ static void __init maple_init_early(void)
                comport = (void *)ioremap(physport, 16);
                udbg_init_uart(comport, default_speed);
 
-               ppc_md.udbg_putc = udbg_putc;
-               ppc_md.udbg_getc = udbg_getc;
-               ppc_md.udbg_getc_poll = udbg_getc_poll;
                DBG("Hello World !\n");
        }
 
index a05b50b738e97b1c55ff1eb8013ae24d6abd929d..6d860c1d9fa0849f44fab1856d77932d3a35fed3 100644 (file)
@@ -183,7 +183,7 @@ PPC64_CACHES:
  *   flush all bytes from start through stop-1 inclusive
  */
 
-_GLOBAL(__flush_icache_range)
+_KPROBE(__flush_icache_range)
 
 /*
  * Flush the data cache to memory 
@@ -223,7 +223,7 @@ _GLOBAL(__flush_icache_range)
        bdnz    2b
        isync
        blr
-       
+       .previous .text
 /*
  * Like above, but only do the D-cache.
  *
@@ -680,6 +680,104 @@ _GLOBAL(kernel_thread)
        ld      r30,-16(r1)
        blr
 
+/*
+ * disable_kernel_fp()
+ * Disable the FPU.
+ */
+_GLOBAL(disable_kernel_fp)
+       mfmsr   r3
+       rldicl  r0,r3,(63-MSR_FP_LG),1
+       rldicl  r3,r0,(MSR_FP_LG+1),0
+       mtmsrd  r3                      /* disable use of fpu now */
+       isync
+       blr
+
+/*
+ * giveup_fpu(tsk)
+ * Disable FP for the task given as the argument,
+ * and save the floating-point registers in its thread_struct.
+ * Enables the FPU for use in the kernel on return.
+ */
+_GLOBAL(giveup_fpu)
+       mfmsr   r5
+       ori     r5,r5,MSR_FP
+       mtmsrd  r5                      /* enable use of fpu now */
+       isync
+       cmpdi   0,r3,0
+       beqlr-                          /* if no previous owner, done */
+       addi    r3,r3,THREAD            /* want THREAD of task */
+       ld      r5,PT_REGS(r3)
+       cmpdi   0,r5,0
+       SAVE_32FPRS(0, r3)
+       mffs    fr0
+       stfd    fr0,THREAD_FPSCR(r3)
+       beq     1f
+       ld      r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+       li      r3,MSR_FP|MSR_FE0|MSR_FE1
+       andc    r4,r4,r3                /* disable FP for previous task */
+       std     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#ifndef CONFIG_SMP
+       li      r5,0
+       ld      r4,last_task_used_math@got(r2)
+       std     r5,0(r4)
+#endif /* CONFIG_SMP */
+       blr
+
+#ifdef CONFIG_ALTIVEC
+
+#if 0 /* this has no callers for now */
+/*
+ * disable_kernel_altivec()
+ * Disable the VMX.
+ */
+_GLOBAL(disable_kernel_altivec)
+       mfmsr   r3
+       rldicl  r0,r3,(63-MSR_VEC_LG),1
+       rldicl  r3,r0,(MSR_VEC_LG+1),0
+       mtmsrd  r3                      /* disable use of VMX now */
+       isync
+       blr
+#endif /* 0 */
+
+/*
+ * giveup_altivec(tsk)
+ * Disable VMX for the task given as the argument,
+ * and save the vector registers in its thread_struct.
+ * Enables the VMX for use in the kernel on return.
+ */
+_GLOBAL(giveup_altivec)
+       mfmsr   r5
+       oris    r5,r5,MSR_VEC@h
+       mtmsrd  r5                      /* enable use of VMX now */
+       isync
+       cmpdi   0,r3,0
+       beqlr-                          /* if no previous owner, done */
+       addi    r3,r3,THREAD            /* want THREAD of task */
+       ld      r5,PT_REGS(r3)
+       cmpdi   0,r5,0
+       SAVE_32VRS(0,r4,r3)
+       mfvscr  vr0
+       li      r4,THREAD_VSCR
+       stvx    vr0,r4,r3
+       beq     1f
+       ld      r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+       lis     r3,MSR_VEC@h
+       andc    r4,r4,r3                /* disable FP for previous task */
+       std     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#ifndef CONFIG_SMP
+       li      r5,0
+       ld      r4,last_task_used_altivec@got(r2)
+       std     r5,0(r4)
+#endif /* CONFIG_SMP */
+       blr
+
+#endif /* CONFIG_ALTIVEC */
+
+_GLOBAL(__setup_cpu_power3)
+       blr
+
 /* kexec_wait(phys_cpu)
  *
  * wait for the flag to change, indicating this kernel is going away but
@@ -859,7 +957,7 @@ _GLOBAL(sys_call_table32)
        .llong .ppc_fork
        .llong .sys_read
        .llong .sys_write
-       .llong .sys32_open              /* 5 */
+       .llong .compat_sys_open         /* 5 */
        .llong .sys_close
        .llong .sys32_waitpid
        .llong .sys32_creat
index b80e81984ba867c5f03dcfe2c91caccf4d73802c..da580812ddfeeb6305b8604c03ae6867ade531af 100644 (file)
@@ -236,7 +236,6 @@ void of_device_unregister(struct of_device *ofdev)
 struct of_device* of_platform_device_create(struct device_node *np, const char *bus_id)
 {
        struct of_device *dev;
-       u32 *reg;
 
        dev = kmalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev)
@@ -250,7 +249,6 @@ struct of_device* of_platform_device_create(struct device_node *np, const char *
        dev->dev.bus = &of_platform_bus_type;
        dev->dev.release = of_release_dev;
 
-       reg = (u32 *)get_property(np, "reg", NULL);
        strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
 
        if (of_device_register(dev) != 0) {
index 69130522a87e17fed1d7de09562b4069aa0f2aba..9d5e1e7fc38962f26fdce0838d82d68f562e67f9 100644 (file)
@@ -45,6 +45,7 @@
 #include <asm/plpar_wrappers.h>
 #include <asm/pSeries_reconfig.h>
 #include <asm/systemcfg.h>
+#include <asm/firmware.h>
 #include "pci.h"
 
 #define DBG(fmt...)
@@ -546,7 +547,7 @@ void iommu_init_early_pSeries(void)
        }
 
        if (systemcfg->platform & PLATFORM_LPAR) {
-               if (cur_cpu_spec->firmware_features & FW_FEATURE_MULTITCE) {
+               if (firmware_has_feature(FW_FEATURE_MULTITCE)) {
                        ppc_md.tce_build = tce_buildmulti_pSeriesLP;
                        ppc_md.tce_free  = tce_freemulti_pSeriesLP;
                } else {
index 74dd144dcce8dd18a06d2f84023c4f93e988a6f0..a6de83f2078fc70c563fb6d487d789f0201e430f 100644 (file)
@@ -52,7 +52,6 @@ EXPORT_SYMBOL(plpar_hcall_4out);
 EXPORT_SYMBOL(plpar_hcall_norets);
 EXPORT_SYMBOL(plpar_hcall_8arg_2ret);
 
-extern void fw_feature_init(void);
 extern void pSeries_find_serial_port(void);
 
 
@@ -193,9 +192,9 @@ static unsigned char udbg_getcLP(void)
 void udbg_init_debug_lpar(void)
 {
        vtermno = 0;
-       ppc_md.udbg_putc = udbg_putcLP;
-       ppc_md.udbg_getc = udbg_getcLP;
-       ppc_md.udbg_getc_poll = udbg_getc_pollLP;
+       udbg_putc = udbg_putcLP;
+       udbg_getc = udbg_getcLP;
+       udbg_getc_poll = udbg_getc_pollLP;
 }
 
 /* returns 0 if couldn't find or use /chosen/stdout as console */
@@ -228,18 +227,18 @@ int find_udbg_vterm(void)
                        termno = (u32 *)get_property(stdout_node, "reg", NULL);
                        if (termno) {
                                vtermno = termno[0];
-                               ppc_md.udbg_putc = udbg_putcLP;
-                               ppc_md.udbg_getc = udbg_getcLP;
-                               ppc_md.udbg_getc_poll = udbg_getc_pollLP;
+                               udbg_putc = udbg_putcLP;
+                               udbg_getc = udbg_getcLP;
+                               udbg_getc_poll = udbg_getc_pollLP;
                                found = 1;
                        }
                } else if (device_is_compatible(stdout_node, "hvterm-protocol")) {
                        termno = (u32 *)get_property(stdout_node, "reg", NULL);
                        if (termno) {
                                vtermno = termno[0];
-                               ppc_md.udbg_putc = udbg_hvsi_putc;
-                               ppc_md.udbg_getc = udbg_hvsi_getc;
-                               ppc_md.udbg_getc_poll = udbg_hvsi_getc_poll;
+                               udbg_putc = udbg_hvsi_putc;
+                               udbg_getc = udbg_hvsi_getc;
+                               udbg_getc_poll = udbg_hvsi_getc_poll;
                                found = 1;
                        }
                }
@@ -267,6 +266,10 @@ void vpa_init(int cpu)
 
        /* Register the Virtual Processor Area (VPA) */
        flags = 1UL << (63 - 18);
+
+       if (cpu_has_feature(CPU_FTR_ALTIVEC))
+               paca[cpu].lppaca.vmxregs_in_use = 1;
+
        ret = register_vpa(flags, hwcpu, __pa(vpa));
 
        if (ret)
@@ -279,7 +282,6 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group,
                              unsigned long va, unsigned long prpn,
                              unsigned long vflags, unsigned long rflags)
 {
-       unsigned long arpn = physRpn_to_absRpn(prpn);
        unsigned long lpar_rc;
        unsigned long flags;
        unsigned long slot;
@@ -290,7 +292,7 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group,
        if (vflags & HPTE_V_LARGE)
                hpte_v &= ~(1UL << HPTE_V_AVPN_SHIFT);
 
-       hpte_r = (arpn << HPTE_R_RPN_SHIFT) | rflags;
+       hpte_r = (prpn << HPTE_R_RPN_SHIFT) | rflags;
 
        /* Now fill in the actual HPTE */
        /* Set CEC cookie to 0         */
index dc2a69d412a204820546107a47ab7c676036a7de..58c61219d08e0765646450c30cba107936db01ab 100644 (file)
@@ -111,7 +111,7 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist
        struct device_node *np;
        int err = -ENOMEM;
 
-       np = kcalloc(1, sizeof(*np), GFP_KERNEL);
+       np = kzalloc(sizeof(*np), GFP_KERNEL);
        if (!np)
                goto out_err;
 
index 5bec956e44a043775ffbd264807cebced14dfc77..9490b6c5b1736ae7fa5b42b7cbdf9a02020bd791 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/ioport.h>
 #include <linux/console.h>
 #include <linux/pci.h>
-#include <linux/version.h>
+#include <linux/utsname.h>
 #include <linux/adb.h>
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -60,7 +60,8 @@
 #include <asm/nvram.h>
 #include <asm/plpar_wrappers.h>
 #include <asm/xics.h>
-#include <asm/cputable.h>
+#include <asm/firmware.h>
+#include <asm/pmc.h>
 
 #include "i8259.h"
 #include "mpic.h"
@@ -187,6 +188,21 @@ static void __init pSeries_setup_mpic(void)
                                  " MPIC     ");
 }
 
+static void pseries_lpar_enable_pmcs(void)
+{
+       unsigned long set, reset;
+
+       power4_enable_pmcs();
+
+       set = 1UL << 63;
+       reset = 0;
+       plpar_hcall_norets(H_PERFMON, set, reset);
+
+       /* instruct hypervisor to maintain PMCs */
+       if (firmware_has_feature(FW_FEATURE_SPLPAR))
+               get_paca()->lppaca.pmcregs_in_use = 1;
+}
+
 static void __init pSeries_setup_arch(void)
 {
        /* Fixup ppc_md depending on the type of interrupt controller */
@@ -231,11 +247,9 @@ static void __init pSeries_setup_arch(void)
 
        pSeries_nvram_init();
 
-       if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)
-               vpa_init(boot_cpuid);
-
        /* Choose an idle loop */
-       if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
+       if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
+               vpa_init(boot_cpuid);
                if (get_paca()->lppaca.shared_proc) {
                        printk(KERN_INFO "Using shared processor idle loop\n");
                        ppc_md.idle_loop = pseries_shared_idle;
@@ -247,24 +261,29 @@ static void __init pSeries_setup_arch(void)
                printk(KERN_INFO "Using default idle loop\n");
                ppc_md.idle_loop = default_idle;
        }
+
+       if (systemcfg->platform & PLATFORM_LPAR)
+               ppc_md.enable_pmcs = pseries_lpar_enable_pmcs;
+       else
+               ppc_md.enable_pmcs = power4_enable_pmcs;
 }
 
 static int __init pSeries_init_panel(void)
 {
        /* Manually leave the kernel version on the panel. */
        ppc_md.progress("Linux ppc64\n", 0);
-       ppc_md.progress(UTS_RELEASE, 0);
+       ppc_md.progress(system_utsname.version, 0);
 
        return 0;
 }
 arch_initcall(pSeries_init_panel);
 
 
-/* Build up the firmware_features bitmask field
+/* Build up the ppc64_firmware_features bitmask field
  * using contents of device-tree/ibm,hypertas-functions.
  * Ultimately this functionality may be moved into prom.c prom_init().
  */
-void __init fw_feature_init(void)
+static void __init fw_feature_init(void)
 {
        struct device_node * dn;
        char * hypertas;
@@ -272,7 +291,7 @@ void __init fw_feature_init(void)
 
        DBG(" -> fw_feature_init()\n");
 
-       cur_cpu_spec->firmware_features = 0;
+       ppc64_firmware_features = 0;
        dn = of_find_node_by_path("/rtas");
        if (dn == NULL) {
                printk(KERN_ERR "WARNING ! Cannot find RTAS in device-tree !\n");
@@ -288,7 +307,7 @@ void __init fw_feature_init(void)
                                if ((firmware_features_table[i].name) &&
                                    (strcmp(firmware_features_table[i].name,hypertas))==0) {
                                        /* we have a match */
-                                       cur_cpu_spec->firmware_features |= 
+                                       ppc64_firmware_features |= 
                                                (firmware_features_table[i].val);
                                        break;
                                } 
@@ -302,7 +321,7 @@ void __init fw_feature_init(void)
        of_node_put(dn);
  no_rtas:
        printk(KERN_INFO "firmware_features = 0x%lx\n", 
-              cur_cpu_spec->firmware_features);
+              ppc64_firmware_features);
 
        DBG(" <- fw_feature_init()\n");
 }
@@ -378,9 +397,6 @@ static void __init pSeries_init_early(void)
                comport = (void *)ioremap(physport, 16);
                udbg_init_uart(comport, default_speed);
 
-               ppc_md.udbg_putc = udbg_putc;
-               ppc_md.udbg_getc = udbg_getc;
-               ppc_md.udbg_getc_poll = udbg_getc_poll;
                DBG("Hello World !\n");
        }
 
index 62c55a123560cf6850dc1c10c5a171c953a7290c..79c7f32236658805bab9f783d80cb3d42091893a 100644 (file)
@@ -41,6 +41,7 @@
 #include <asm/machdep.h>
 #include <asm/xics.h>
 #include <asm/cputable.h>
+#include <asm/firmware.h>
 #include <asm/system.h>
 #include <asm/rtas.h>
 #include <asm/plpar_wrappers.h>
@@ -326,7 +327,7 @@ static void __devinit smp_xics_setup_cpu(int cpu)
        if (cpu != boot_cpuid)
                xics_setup_cpu();
 
-       if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)
+       if (firmware_has_feature(FW_FEATURE_SPLPAR))
                vpa_init(cpu);
 
        cpu_clear(cpu, of_spin_map);
diff --git a/arch/ppc64/kernel/pSeries_vio.c b/arch/ppc64/kernel/pSeries_vio.c
new file mode 100644 (file)
index 0000000..e0ae06f
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * IBM PowerPC pSeries Virtual I/O Infrastructure Support.
+ *
+ *    Copyright (c) 2003-2005 IBM Corp.
+ *     Dave Engebretsen engebret@us.ibm.com
+ *     Santiago Leon santil@us.ibm.com
+ *     Hollis Blanchard <hollisb@us.ibm.com>
+ *     Stephen Rothwell
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/kobject.h>
+#include <asm/iommu.h>
+#include <asm/dma.h>
+#include <asm/prom.h>
+#include <asm/vio.h>
+#include <asm/hvcall.h>
+
+extern struct subsystem devices_subsys; /* needed for vio_find_name() */
+
+static void probe_bus_pseries(void)
+{
+       struct device_node *node_vroot, *of_node;
+
+       node_vroot = find_devices("vdevice");
+       if ((node_vroot == NULL) || (node_vroot->child == NULL))
+               /* this machine doesn't do virtual IO, and that's ok */
+               return;
+
+       /*
+        * Create struct vio_devices for each virtual device in the device tree.
+        * Drivers will associate with them later.
+        */
+       for (of_node = node_vroot->child; of_node != NULL;
+                       of_node = of_node->sibling) {
+               printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, of_node);
+               vio_register_device_node(of_node);
+       }
+}
+
+/**
+ * vio_match_device_pseries: - Tell if a pSeries VIO device matches a
+ *     vio_device_id
+ */
+static int vio_match_device_pseries(const struct vio_device_id *id,
+               const struct vio_dev *dev)
+{
+       return (strncmp(dev->type, id->type, strlen(id->type)) == 0) &&
+                       device_is_compatible(dev->dev.platform_data, id->compat);
+}
+
+static void vio_release_device_pseries(struct device *dev)
+{
+       /* XXX free TCE table */
+       of_node_put(dev->platform_data);
+}
+
+static ssize_t viodev_show_devspec(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct device_node *of_node = dev->platform_data;
+
+       return sprintf(buf, "%s\n", of_node->full_name);
+}
+DEVICE_ATTR(devspec, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_devspec, NULL);
+
+static void vio_unregister_device_pseries(struct vio_dev *viodev)
+{
+       device_remove_file(&viodev->dev, &dev_attr_devspec);
+}
+
+static struct vio_bus_ops vio_bus_ops_pseries = {
+       .match = vio_match_device_pseries,
+       .unregister_device = vio_unregister_device_pseries,
+       .release_device = vio_release_device_pseries,
+};
+
+/**
+ * vio_bus_init_pseries: - Initialize the pSeries virtual IO bus
+ */
+static int __init vio_bus_init_pseries(void)
+{
+       int err;
+
+       err = vio_bus_init(&vio_bus_ops_pseries);
+       if (err == 0)
+               probe_bus_pseries();
+       return err;
+}
+
+__initcall(vio_bus_init_pseries);
+
+/**
+ * vio_build_iommu_table: - gets the dma information from OF and
+ *     builds the TCE tree.
+ * @dev: the virtual device.
+ *
+ * Returns a pointer to the built tce tree, or NULL if it can't
+ * find property.
+*/
+static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
+{
+       unsigned int *dma_window;
+       struct iommu_table *newTceTable;
+       unsigned long offset;
+       int dma_window_property_size;
+
+       dma_window = (unsigned int *) get_property(dev->dev.platform_data, "ibm,my-dma-window", &dma_window_property_size);
+       if(!dma_window) {
+               return NULL;
+       }
+
+       newTceTable = (struct iommu_table *) kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
+
+       /*  There should be some code to extract the phys-encoded offset
+               using prom_n_addr_cells(). However, according to a comment
+               on earlier versions, it's always zero, so we don't bother */
+       offset = dma_window[1] >>  PAGE_SHIFT;
+
+       /* TCE table size - measured in tce entries */
+       newTceTable->it_size            = dma_window[4] >> PAGE_SHIFT;
+       /* offset for VIO should always be 0 */
+       newTceTable->it_offset          = offset;
+       newTceTable->it_busno           = 0;
+       newTceTable->it_index           = (unsigned long)dma_window[0];
+       newTceTable->it_type            = TCE_VB;
+
+       return iommu_init_table(newTceTable);
+}
+
+/**
+ * vio_register_device_node: - Register a new vio device.
+ * @of_node:   The OF node for this device.
+ *
+ * Creates and initializes a vio_dev structure from the data in
+ * of_node (dev.platform_data) and adds it to the list of virtual devices.
+ * Returns a pointer to the created vio_dev or NULL if node has
+ * NULL device_type or compatible fields.
+ */
+struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
+{
+       struct vio_dev *viodev;
+       unsigned int *unit_address;
+       unsigned int *irq_p;
+
+       /* we need the 'device_type' property, in order to match with drivers */
+       if ((NULL == of_node->type)) {
+               printk(KERN_WARNING
+                       "%s: node %s missing 'device_type'\n", __FUNCTION__,
+                       of_node->name ? of_node->name : "<unknown>");
+               return NULL;
+       }
+
+       unit_address = (unsigned int *)get_property(of_node, "reg", NULL);
+       if (!unit_address) {
+               printk(KERN_WARNING "%s: node %s missing 'reg'\n", __FUNCTION__,
+                       of_node->name ? of_node->name : "<unknown>");
+               return NULL;
+       }
+
+       /* allocate a vio_dev for this node */
+       viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
+       if (!viodev) {
+               return NULL;
+       }
+       memset(viodev, 0, sizeof(struct vio_dev));
+
+       viodev->dev.platform_data = of_node_get(of_node);
+
+       viodev->irq = NO_IRQ;
+       irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL);
+       if (irq_p) {
+               int virq = virt_irq_create_mapping(*irq_p);
+               if (virq == NO_IRQ) {
+                       printk(KERN_ERR "Unable to allocate interrupt "
+                              "number for %s\n", of_node->full_name);
+               } else
+                       viodev->irq = irq_offset_up(virq);
+       }
+
+       snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address);
+       viodev->name = of_node->name;
+       viodev->type = of_node->type;
+       viodev->unit_address = *unit_address;
+       viodev->iommu_table = vio_build_iommu_table(viodev);
+
+       /* register with generic device framework */
+       if (vio_register_device(viodev) == NULL) {
+               /* XXX free TCE table */
+               kfree(viodev);
+               return NULL;
+       }
+       device_create_file(&viodev->dev, &dev_attr_devspec);
+
+       return viodev;
+}
+EXPORT_SYMBOL(vio_register_device_node);
+
+/**
+ * vio_get_attribute: - get attribute for virtual device
+ * @vdev:      The vio device to get property.
+ * @which:     The property/attribute to be extracted.
+ * @length:    Pointer to length of returned data size (unused if NULL).
+ *
+ * Calls prom.c's get_property() to return the value of the
+ * attribute specified by the preprocessor constant @which
+*/
+const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length)
+{
+       return get_property(vdev->dev.platform_data, (char*)which, length);
+}
+EXPORT_SYMBOL(vio_get_attribute);
+
+/* vio_find_name() - internal because only vio.c knows how we formatted the
+ * kobject name
+ * XXX once vio_bus_type.devices is actually used as a kset in
+ * drivers/base/bus.c, this function should be removed in favor of
+ * "device_find(kobj_name, &vio_bus_type)"
+ */
+static struct vio_dev *vio_find_name(const char *kobj_name)
+{
+       struct kobject *found;
+
+       found = kset_find_obj(&devices_subsys.kset, kobj_name);
+       if (!found)
+               return NULL;
+
+       return to_vio_dev(container_of(found, struct device, kobj));
+}
+
+/**
+ * vio_find_node - find an already-registered vio_dev
+ * @vnode: device_node of the virtual device we're looking for
+ */
+struct vio_dev *vio_find_node(struct device_node *vnode)
+{
+       uint32_t *unit_address;
+       char kobj_name[BUS_ID_SIZE];
+
+       /* construct the kobject name from the device node */
+       unit_address = (uint32_t *)get_property(vnode, "reg", NULL);
+       if (!unit_address)
+               return NULL;
+       snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address);
+
+       return vio_find_name(kobj_name);
+}
+EXPORT_SYMBOL(vio_find_node);
+
+int vio_enable_interrupts(struct vio_dev *dev)
+{
+       int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE);
+       if (rc != H_Success)
+               printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc);
+       return rc;
+}
+EXPORT_SYMBOL(vio_enable_interrupts);
+
+int vio_disable_interrupts(struct vio_dev *dev)
+{
+       int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE);
+       if (rc != H_Success)
+               printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc);
+       return rc;
+}
+EXPORT_SYMBOL(vio_disable_interrupts);
index 6316188737b6eea0861e10cfa0041997456061c5..33a2d8db3f21d428feb9185b9909cc2f2fb8880e 100644 (file)
@@ -59,6 +59,7 @@ extern unsigned long __toc_start;
                .fpregs_in_use = 1,                                         \
                .end_of_quantum = 0xfffffffffffffffful,                     \
                .slb_count = 64,                                            \
+               .vmxregs_in_use = 0,                                        \
        },                                                                  \
 
 #ifdef CONFIG_PPC_ISERIES
@@ -78,7 +79,7 @@ extern unsigned long __toc_start;
 
 #define BOOTCPU_PACA_INIT(number)                                          \
 {                                                                          \
-       PACA_INIT_COMMON(number, 1, 0, STAB0_VIRT_ADDR)                     \
+       PACA_INIT_COMMON(number, 1, 0, (u64)&initial_stab)                  \
        PACA_INIT_ISERIES(number)                                           \
 }
 
@@ -90,7 +91,7 @@ extern unsigned long __toc_start;
 
 #define BOOTCPU_PACA_INIT(number)                                          \
 {                                                                          \
-       PACA_INIT_COMMON(number, 1, STAB0_PHYS_ADDR, STAB0_VIRT_ADDR)       \
+       PACA_INIT_COMMON(number, 1, STAB0_PHYS_ADDR, (u64)&initial_stab)    \
 }
 #endif
 
index e40877fa67cd0efd266a78d1446f10bded9efa7e..e7f695dcd8c8dd4dae28d7626e421f93397eca19 100644 (file)
@@ -71,6 +71,7 @@
 #include <asm/of_device.h>
 #include <asm/lmb.h>
 #include <asm/smu.h>
+#include <asm/pmc.h>
 
 #include "pmac.h"
 #include "mpic.h"
@@ -273,16 +274,6 @@ static void __pmac pmac_halt(void)
 }
 
 #ifdef CONFIG_BOOTX_TEXT
-static int dummy_getc_poll(void)
-{
-       return -1;
-}
-
-static unsigned char dummy_getc(void)
-{
-       return 0;
-}
-
 static void btext_putc(unsigned char c)
 {
        btext_drawchar(c);
@@ -341,16 +332,13 @@ static void __init pmac_init_early(void)
                sccdbg = 1;
                        udbg_init_scc(NULL);
                }
-
-       else {
 #ifdef CONFIG_BOOTX_TEXT
+       else {
                init_boot_display();
 
-               ppc_md.udbg_putc = btext_putc;
-               ppc_md.udbg_getc = dummy_getc;
-               ppc_md.udbg_getc_poll = dummy_getc_poll;
-#endif /* CONFIG_BOOTX_TEXT */
+               udbg_putc = btext_putc;
        }
+#endif /* CONFIG_BOOTX_TEXT */
 
        /* Setup interrupt mapping options */
        ppc64_interrupt_controller = IC_OPEN_PIC;
@@ -511,4 +499,5 @@ struct machdep_calls __initdata pmac_md = {
        .progress               = pmac_progress,
        .check_legacy_ioport    = pmac_check_legacy_ioport,
        .idle_loop              = native_idle,
+       .enable_pmcs            = power4_enable_pmcs,
 };
index 67be773f9c00d25d8df4ee6ed6c42870a57706f8..cdfec7438d0132334f17b65ec539fa919c997b91 100644 (file)
@@ -65,3 +65,24 @@ void release_pmc_hardware(void)
        spin_unlock(&pmc_owner_lock);
 }
 EXPORT_SYMBOL_GPL(release_pmc_hardware);
+
+void power4_enable_pmcs(void)
+{
+       unsigned long hid0;
+
+       hid0 = mfspr(HID0);
+       hid0 |= 1UL << (63 - 20);
+
+       /* POWER4 requires the following sequence */
+       asm volatile(
+               "sync\n"
+               "mtspr     %1, %0\n"
+               "mfspr     %0, %1\n"
+               "mfspr     %0, %1\n"
+               "mfspr     %0, %1\n"
+               "mfspr     %0, %1\n"
+               "mfspr     %0, %1\n"
+               "mfspr     %0, %1\n"
+               "isync" : "=&r" (hid0) : "i" (HID0), "0" (hid0):
+               "memory");
+}
index f7cae05e40fb2cbfcfb255998ec938c6eee72676..7a7e027653ad922dac160da11e545401696148ed 100644 (file)
@@ -50,6 +50,7 @@
 #include <asm/machdep.h>
 #include <asm/iSeries/HvCallHpt.h>
 #include <asm/cputable.h>
+#include <asm/firmware.h>
 #include <asm/sections.h>
 #include <asm/tlbflush.h>
 #include <asm/time.h>
@@ -202,11 +203,10 @@ struct task_struct *__switch_to(struct task_struct *prev,
        new_thread = &new->thread;
        old_thread = &current->thread;
 
-/* Collect purr utilization data per process and per processor wise */
-/* purr is nothing but processor time base                          */
-
-#if defined(CONFIG_PPC_PSERIES)
-       if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
+       /* Collect purr utilization data per process and per processor
+        * wise purr is nothing but processor time base
+        */
+       if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
                struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array);
                long unsigned start_tb, current_tb;
                start_tb = old_thread->start_tb;
@@ -214,8 +214,6 @@ struct task_struct *__switch_to(struct task_struct *prev,
                old_thread->accum_tb += (current_tb - start_tb);
                new_thread->start_tb = current_tb;
        }
-#endif
-
 
        local_irq_save(flags);
        last = _switch(old_thread, new_thread);
index 5aca01ddd81ff44272b896849dbc128d7d2bbb0a..6ad5a8467f87f1aed705aa793e6f1175e42f207d 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/threads.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
@@ -625,8 +624,8 @@ void __init finish_device_tree(void)
 
 static inline char *find_flat_dt_string(u32 offset)
 {
-       return ((char *)initial_boot_params) + initial_boot_params->off_dt_strings
-               + offset;
+       return ((char *)initial_boot_params) +
+               initial_boot_params->off_dt_strings + offset;
 }
 
 /**
@@ -635,26 +634,33 @@ static inline char *find_flat_dt_string(u32 offset)
  * unflatten the tree
  */
 static int __init scan_flat_dt(int (*it)(unsigned long node,
-                                        const char *full_path, void *data),
+                                        const char *uname, int depth,
+                                        void *data),
                               void *data)
 {
        unsigned long p = ((unsigned long)initial_boot_params) +
                initial_boot_params->off_dt_struct;
        int rc = 0;
+       int depth = -1;
 
        do {
                u32 tag = *((u32 *)p);
                char *pathp;
                
                p += 4;
-               if (tag == OF_DT_END_NODE)
+               if (tag == OF_DT_END_NODE) {
+                       depth --;
+                       continue;
+               }
+               if (tag == OF_DT_NOP)
                        continue;
                if (tag == OF_DT_END)
                        break;
                if (tag == OF_DT_PROP) {
                        u32 sz = *((u32 *)p);
                        p += 8;
-                       p = _ALIGN(p, sz >= 8 ? 8 : 4);
+                       if (initial_boot_params->version < 0x10)
+                               p = _ALIGN(p, sz >= 8 ? 8 : 4);
                        p += sz;
                        p = _ALIGN(p, 4);
                        continue;
@@ -664,9 +670,18 @@ static int __init scan_flat_dt(int (*it)(unsigned long node,
                               " device tree !\n", tag);
                        return -EINVAL;
                }
+               depth++;
                pathp = (char *)p;
                p = _ALIGN(p + strlen(pathp) + 1, 4);
-               rc = it(p, pathp, data);
+               if ((*pathp) == '/') {
+                       char *lp, *np;
+                       for (lp = NULL, np = pathp; *np; np++)
+                               if ((*np) == '/')
+                                       lp = np+1;
+                       if (lp != NULL)
+                               pathp = lp;
+               }
+               rc = it(p, pathp, depth, data);
                if (rc != 0)
                        break;          
        } while(1);
@@ -689,17 +704,21 @@ static void* __init get_flat_dt_prop(unsigned long node, const char *name,
                const char *nstr;
 
                p += 4;
+               if (tag == OF_DT_NOP)
+                       continue;
                if (tag != OF_DT_PROP)
                        return NULL;
 
                sz = *((u32 *)p);
                noff = *((u32 *)(p + 4));
                p += 8;
-               p = _ALIGN(p, sz >= 8 ? 8 : 4);
+               if (initial_boot_params->version < 0x10)
+                       p = _ALIGN(p, sz >= 8 ? 8 : 4);
 
                nstr = find_flat_dt_string(noff);
                if (nstr == NULL) {
-                       printk(KERN_WARNING "Can't find property index name !\n");
+                       printk(KERN_WARNING "Can't find property index"
+                              " name !\n");
                        return NULL;
                }
                if (strcmp(name, nstr) == 0) {
@@ -713,7 +732,7 @@ static void* __init get_flat_dt_prop(unsigned long node, const char *name,
 }
 
 static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
-                                              unsigned long align)
+                                      unsigned long align)
 {
        void *res;
 
@@ -727,13 +746,16 @@ static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
 static unsigned long __init unflatten_dt_node(unsigned long mem,
                                              unsigned long *p,
                                              struct device_node *dad,
-                                             struct device_node ***allnextpp)
+                                             struct device_node ***allnextpp,
+                                             unsigned long fpsize)
 {
        struct device_node *np;
        struct property *pp, **prev_pp = NULL;
        char *pathp;
        u32 tag;
-       unsigned int l;
+       unsigned int l, allocl;
+       int has_name = 0;
+       int new_format = 0;
 
        tag = *((u32 *)(*p));
        if (tag != OF_DT_BEGIN_NODE) {
@@ -742,21 +764,62 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
        }
        *p += 4;
        pathp = (char *)*p;
-       l = strlen(pathp) + 1;
+       l = allocl = strlen(pathp) + 1;
        *p = _ALIGN(*p + l, 4);
 
-       np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + l,
+       /* version 0x10 has a more compact unit name here instead of the full
+        * path. we accumulate the full path size using "fpsize", we'll rebuild
+        * it later. We detect this because the first character of the name is
+        * not '/'.
+        */
+       if ((*pathp) != '/') {
+               new_format = 1;
+               if (fpsize == 0) {
+                       /* root node: special case. fpsize accounts for path
+                        * plus terminating zero. root node only has '/', so
+                        * fpsize should be 2, but we want to avoid the first
+                        * level nodes to have two '/' so we use fpsize 1 here
+                        */
+                       fpsize = 1;
+                       allocl = 2;
+               } else {
+                       /* account for '/' and path size minus terminal 0
+                        * already in 'l'
+                        */
+                       fpsize += l;
+                       allocl = fpsize;
+               }
+       }
+
+
+       np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
                                __alignof__(struct device_node));
        if (allnextpp) {
                memset(np, 0, sizeof(*np));
                np->full_name = ((char*)np) + sizeof(struct device_node);
-               memcpy(np->full_name, pathp, l);
+               if (new_format) {
+                       char *p = np->full_name;
+                       /* rebuild full path for new format */
+                       if (dad && dad->parent) {
+                               strcpy(p, dad->full_name);
+#ifdef DEBUG
+                               if ((strlen(p) + l + 1) != allocl) {
+                                       DBG("%s: p: %d, l: %d, a: %d\n",
+                                           pathp, strlen(p), l, allocl);
+                               }
+#endif
+                               p += strlen(p);
+                       }
+                       *(p++) = '/';
+                       memcpy(p, pathp, l);
+               } else
+                       memcpy(np->full_name, pathp, l);
                prev_pp = &np->properties;
                **allnextpp = np;
                *allnextpp = &np->allnext;
                if (dad != NULL) {
                        np->parent = dad;
-                       /* we temporarily use the `next' field as `last_child'. */
+                       /* we temporarily use the next field as `last_child'*/
                        if (dad->next == 0)
                                dad->child = np;
                        else
@@ -770,18 +833,26 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
                char *pname;
 
                tag = *((u32 *)(*p));
+               if (tag == OF_DT_NOP) {
+                       *p += 4;
+                       continue;
+               }
                if (tag != OF_DT_PROP)
                        break;
                *p += 4;
                sz = *((u32 *)(*p));
                noff = *((u32 *)((*p) + 4));
-               *p = _ALIGN((*p) + 8, sz >= 8 ? 8 : 4);
+               *p += 8;
+               if (initial_boot_params->version < 0x10)
+                       *p = _ALIGN(*p, sz >= 8 ? 8 : 4);
 
                pname = find_flat_dt_string(noff);
                if (pname == NULL) {
                        printk("Can't find property name in list !\n");
                        break;
                }
+               if (strcmp(pname, "name") == 0)
+                       has_name = 1;
                l = strlen(pname) + 1;
                pp = unflatten_dt_alloc(&mem, sizeof(struct property),
                                        __alignof__(struct property));
@@ -801,6 +872,36 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
                }
                *p = _ALIGN((*p) + sz, 4);
        }
+       /* with version 0x10 we may not have the name property, recreate
+        * it here from the unit name if absent
+        */
+       if (!has_name) {
+               char *p = pathp, *ps = pathp, *pa = NULL;
+               int sz;
+
+               while (*p) {
+                       if ((*p) == '@')
+                               pa = p;
+                       if ((*p) == '/')
+                               ps = p + 1;
+                       p++;
+               }
+               if (pa < ps)
+                       pa = p;
+               sz = (pa - ps) + 1;
+               pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
+                                       __alignof__(struct property));
+               if (allnextpp) {
+                       pp->name = "name";
+                       pp->length = sz;
+                       pp->value = (unsigned char *)(pp + 1);
+                       *prev_pp = pp;
+                       prev_pp = &pp->next;
+                       memcpy(pp->value, ps, sz - 1);
+                       ((char *)pp->value)[sz - 1] = 0;
+                       DBG("fixed up name for %s -> %s\n", pathp, pp->value);
+               }
+       }
        if (allnextpp) {
                *prev_pp = NULL;
                np->name = get_property(np, "name", NULL);
@@ -812,11 +913,11 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
                        np->type = "<NULL>";
        }
        while (tag == OF_DT_BEGIN_NODE) {
-               mem = unflatten_dt_node(mem, p, np, allnextpp);
+               mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
                tag = *((u32 *)(*p));
        }
        if (tag != OF_DT_END_NODE) {
-               printk("Weird tag at start of node: %x\n", tag);
+               printk("Weird tag at end of node: %x\n", tag);
                return mem;
        }
        *p += 4;
@@ -842,21 +943,32 @@ void __init unflatten_device_tree(void)
        /* First pass, scan for size */
        start = ((unsigned long)initial_boot_params) +
                initial_boot_params->off_dt_struct;
-       size = unflatten_dt_node(0, &start, NULL, NULL);
+       size = unflatten_dt_node(0, &start, NULL, NULL, 0);
+       size = (size | 3) + 1;
 
        DBG("  size is %lx, allocating...\n", size);
 
        /* Allocate memory for the expanded device tree */
-       mem = (unsigned long)abs_to_virt(lmb_alloc(size,
-                                                  __alignof__(struct device_node)));
+       mem = lmb_alloc(size + 4, __alignof__(struct device_node));
+       if (!mem) {
+               DBG("Couldn't allocate memory with lmb_alloc()!\n");
+               panic("Couldn't allocate memory with lmb_alloc()!\n");
+       }
+       mem = (unsigned long)abs_to_virt(mem);
+
+       ((u32 *)mem)[size / 4] = 0xdeadbeef;
+
        DBG("  unflattening...\n", mem);
 
        /* Second pass, do actual unflattening */
        start = ((unsigned long)initial_boot_params) +
                initial_boot_params->off_dt_struct;
-       unflatten_dt_node(mem, &start, NULL, &allnextp);
+       unflatten_dt_node(mem, &start, NULL, &allnextp, 0);
        if (*((u32 *)start) != OF_DT_END)
-               printk(KERN_WARNING "Weird tag at end of tree: %x\n", *((u32 *)start));
+               printk(KERN_WARNING "Weird tag at end of tree: %08x\n", *((u32 *)start));
+       if (((u32 *)mem)[size / 4] != 0xdeadbeef)
+               printk(KERN_WARNING "End of tree marker overwritten: %08x\n",
+                      ((u32 *)mem)[size / 4] );
        *allnextp = NULL;
 
        /* Get pointer to OF "/chosen" node for use everywhere */
@@ -880,7 +992,7 @@ void __init unflatten_device_tree(void)
 
 
 static int __init early_init_dt_scan_cpus(unsigned long node,
-                                         const char *full_path, void *data)
+                                         const char *uname, int depth, void *data)
 {
        char *type = get_flat_dt_prop(node, "device_type", NULL);
        u32 *prop;
@@ -947,13 +1059,15 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
 }
 
 static int __init early_init_dt_scan_chosen(unsigned long node,
-                                           const char *full_path, void *data)
+                                           const char *uname, int depth, void *data)
 {
        u32 *prop;
        u64 *prop64;
        extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end;
 
-       if (strcmp(full_path, "/chosen") != 0)
+       DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
+
+       if (depth != 1 || strcmp(uname, "chosen") != 0)
                return 0;
 
        /* get platform type */
@@ -1003,18 +1117,20 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
 }
 
 static int __init early_init_dt_scan_root(unsigned long node,
-                                         const char *full_path, void *data)
+                                         const char *uname, int depth, void *data)
 {
        u32 *prop;
 
-       if (strcmp(full_path, "/") != 0)
+       if (depth != 0)
                return 0;
 
        prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL);
        dt_root_size_cells = (prop == NULL) ? 1 : *prop;
-               
+       DBG("dt_root_size_cells = %x\n", dt_root_size_cells);
+
        prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL);
        dt_root_addr_cells = (prop == NULL) ? 2 : *prop;
+       DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells);
        
        /* break now */
        return 1;
@@ -1042,7 +1158,7 @@ static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp)
 
 
 static int __init early_init_dt_scan_memory(unsigned long node,
-                                           const char *full_path, void *data)
+                                           const char *uname, int depth, void *data)
 {
        char *type = get_flat_dt_prop(node, "device_type", NULL);
        cell_t *reg, *endp;
@@ -1058,7 +1174,9 @@ static int __init early_init_dt_scan_memory(unsigned long node,
 
        endp = reg + (l / sizeof(cell_t));
 
-       DBG("memory scan node %s ...\n", full_path);
+       DBG("memory scan node %s ..., reg size %ld, data: %x %x %x %x, ...\n",
+           uname, l, reg[0], reg[1], reg[2], reg[3]);
+
        while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
                unsigned long base, size;
 
@@ -1469,10 +1587,11 @@ struct device_node *of_find_node_by_path(const char *path)
        struct device_node *np = allnodes;
 
        read_lock(&devtree_lock);
-       for (; np != 0; np = np->allnext)
+       for (; np != 0; np = np->allnext) {
                if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0
                    && of_node_get(np))
                        break;
+       }
        read_unlock(&devtree_lock);
        return np;
 }
index dbbe6c79d8dac4f1b5a370380635aa36a7b57912..9979919cdf9297c1481091151caca0a401ea6a94 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/threads.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
@@ -892,7 +891,10 @@ static void __init prom_init_mem(void)
        if ( RELOC(of_platform) == PLATFORM_PSERIES_LPAR )
                RELOC(alloc_top) = RELOC(rmo_top);
        else
-               RELOC(alloc_top) = RELOC(rmo_top) = min(0x40000000ul, RELOC(ram_top));
+               /* Some RS64 machines have buggy firmware where claims up at 1GB
+                * fails. Cap at 768MB as a workaround. Still plenty of room.
+                */
+               RELOC(alloc_top) = RELOC(rmo_top) = min(0x30000000ul, RELOC(ram_top));
 
        prom_printf("memory layout at init:\n");
        prom_printf("  memory_limit : %x (16 MB aligned)\n", RELOC(prom_memory_limit));
@@ -1534,7 +1536,8 @@ static unsigned long __init dt_find_string(char *str)
  */
 #define MAX_PROPERTY_NAME 64
 
-static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
+static void __init scan_dt_build_strings(phandle node,
+                                        unsigned long *mem_start,
                                         unsigned long *mem_end)
 {
        unsigned long offset = reloc_offset();
@@ -1547,16 +1550,21 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
        /* get and store all property names */
        prev_name = RELOC("");
        for (;;) {
-               int rc;
-
                /* 64 is max len of name including nul. */
                namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1);
-               rc = call_prom("nextprop", 3, 1, node, prev_name, namep);
-               if (rc != 1) {
+               if (call_prom("nextprop", 3, 1, node, prev_name, namep) != 1) {
                        /* No more nodes: unwind alloc */
                        *mem_start = (unsigned long)namep;
                        break;
                }
+
+               /* skip "name" */
+               if (strcmp(namep, RELOC("name")) == 0) {
+                       *mem_start = (unsigned long)namep;
+                       prev_name = RELOC("name");
+                       continue;
+               }
+               /* get/create string entry */
                soff = dt_find_string(namep);
                if (soff != 0) {
                        *mem_start = (unsigned long)namep;
@@ -1571,7 +1579,7 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
 
        /* do all our children */
        child = call_prom("child", 1, 1, node);
-       while (child != (phandle)0) {
+       while (child != 0) {
                scan_dt_build_strings(child, mem_start, mem_end);
                child = call_prom("peer", 1, 1, child);
        }
@@ -1580,16 +1588,13 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
 static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
                                        unsigned long *mem_end)
 {
-       int l, align;
        phandle child;
-       char *namep, *prev_name, *sstart, *p, *ep;
+       char *namep, *prev_name, *sstart, *p, *ep, *lp, *path;
        unsigned long soff;
        unsigned char *valp;
        unsigned long offset = reloc_offset();
-       char pname[MAX_PROPERTY_NAME];
-       char *path;
-
-       path = RELOC(prom_scratch);
+       static char pname[MAX_PROPERTY_NAME];
+       int l;
 
        dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);
 
@@ -1599,23 +1604,33 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
                      namep, *mem_end - *mem_start);
        if (l >= 0) {
                /* Didn't fit?  Get more room. */
-               if (l+1 > *mem_end - *mem_start) {
+               if ((l+1) > (*mem_end - *mem_start)) {
                        namep = make_room(mem_start, mem_end, l+1, 1);
                        call_prom("package-to-path", 3, 1, node, namep, l);
                }
                namep[l] = '\0';
+
                /* Fixup an Apple bug where they have bogus \0 chars in the
                 * middle of the path in some properties
                 */
                for (p = namep, ep = namep + l; p < ep; p++)
                        if (*p == '\0') {
                                memmove(p, p+1, ep - p);
-                               ep--; l--;
+                               ep--; l--; p--;
                        }
-               *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4);
+
+               /* now try to extract the unit name in that mess */
+               for (p = namep, lp = NULL; *p; p++)
+                       if (*p == '/')
+                               lp = p + 1;
+               if (lp != NULL)
+                       memmove(namep, lp, strlen(lp) + 1);
+               *mem_start = _ALIGN(((unsigned long) namep) +
+                                   strlen(namep) + 1, 4);
        }
 
        /* get it again for debugging */
+       path = RELOC(prom_scratch);
        memset(path, 0, PROM_SCRATCH_SIZE);
        call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);
 
@@ -1623,23 +1638,27 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
        prev_name = RELOC("");
        sstart = (char *)RELOC(dt_string_start);
        for (;;) {
-               int rc;
-
-               rc = call_prom("nextprop", 3, 1, node, prev_name, pname);
-               if (rc != 1)
+               if (call_prom("nextprop", 3, 1, node, prev_name,
+                             RELOC(pname)) != 1)
                        break;
 
+               /* skip "name" */
+               if (strcmp(RELOC(pname), RELOC("name")) == 0) {
+                       prev_name = RELOC("name");
+                       continue;
+               }
+
                /* find string offset */
-               soff = dt_find_string(pname);
+               soff = dt_find_string(RELOC(pname));
                if (soff == 0) {
-                       prom_printf("WARNING: Can't find string index for <%s>, node %s\n",
-                                   pname, path);
+                       prom_printf("WARNING: Can't find string index for"
+                                   " <%s>, node %s\n", RELOC(pname), path);
                        break;
                }
                prev_name = sstart + soff;
 
                /* get length */
-               l = call_prom("getproplen", 2, 1, node, pname);
+               l = call_prom("getproplen", 2, 1, node, RELOC(pname));
 
                /* sanity checks */
                if (l == PROM_ERROR)
@@ -1648,7 +1667,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
                        prom_printf("WARNING: ignoring large property ");
                        /* It seems OF doesn't null-terminate the path :-( */
                        prom_printf("[%s] ", path);
-                       prom_printf("%s length 0x%x\n", pname, l);
+                       prom_printf("%s length 0x%x\n", RELOC(pname), l);
                        continue;
                }
 
@@ -1658,17 +1677,16 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
                dt_push_token(soff, mem_start, mem_end);
 
                /* push property content */
-               align = (l >= 8) ? 8 : 4;
-               valp = make_room(mem_start, mem_end, l, align);
-               call_prom("getprop", 4, 1, node, pname, valp, l);
+               valp = make_room(mem_start, mem_end, l, 4);
+               call_prom("getprop", 4, 1, node, RELOC(pname), valp, l);
                *mem_start = _ALIGN(*mem_start, 4);
        }
 
        /* Add a "linux,phandle" property. */
        soff = dt_find_string(RELOC("linux,phandle"));
        if (soff == 0)
-               prom_printf("WARNING: Can't find string index for <linux-phandle>"
-                           " node %s\n", path);
+               prom_printf("WARNING: Can't find string index for"
+                           " <linux-phandle> node %s\n", path);
        else {
                dt_push_token(OF_DT_PROP, mem_start, mem_end);
                dt_push_token(4, mem_start, mem_end);
@@ -1679,7 +1697,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
 
        /* do all our children */
        child = call_prom("child", 1, 1, node);
-       while (child != (phandle)0) {
+       while (child != 0) {
                scan_dt_build_struct(child, mem_start, mem_end);
                child = call_prom("peer", 1, 1, child);
        }
@@ -1718,7 +1736,8 @@ static void __init flatten_device_tree(void)
 
        /* Build header and make room for mem rsv map */ 
        mem_start = _ALIGN(mem_start, 4);
-       hdr = make_room(&mem_start, &mem_end, sizeof(struct boot_param_header), 4);
+       hdr = make_room(&mem_start, &mem_end,
+                       sizeof(struct boot_param_header), 4);
        RELOC(dt_header_start) = (unsigned long)hdr;
        rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8);
 
@@ -1731,11 +1750,11 @@ static void __init flatten_device_tree(void)
        namep = make_room(&mem_start, &mem_end, 16, 1);
        strcpy(namep, RELOC("linux,phandle"));
        mem_start = (unsigned long)namep + strlen(namep) + 1;
-       RELOC(dt_string_end) = mem_start;
 
        /* Build string array */
        prom_printf("Building dt strings...\n"); 
        scan_dt_build_strings(root, &mem_start, &mem_end);
+       RELOC(dt_string_end) = mem_start;
 
        /* Build structure */
        mem_start = PAGE_ALIGN(mem_start);
@@ -1750,9 +1769,11 @@ static void __init flatten_device_tree(void)
        hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start);
        hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start);
        hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start);
+       hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start);
        hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start);
        hdr->version = OF_DT_VERSION;
-       hdr->last_comp_version = 1;
+       /* Version 16 is not backward compatible */
+       hdr->last_comp_version = 0x10;
 
        /* Reserve the whole thing and copy the reserve map in, we
         * also bump mem_reserve_cnt to cause further reservations to
@@ -1808,6 +1829,9 @@ static void __init fixup_device_tree(void)
        /* does it need fixup ? */
        if (prom_getproplen(i2c, "interrupts") > 0)
                return;
+
+       prom_printf("fixing up bogus interrupts for u3 i2c...\n");
+
        /* interrupt on this revision of u3 is number 0 and level */
        interrupts[0] = 0;
        interrupts[1] = 1;
index 1048817befb84a6614a4081396a3db08f333e7fe..1dccadaddd1d094551f0528fb2c747d2afac8773 100644 (file)
@@ -58,6 +58,21 @@ static int config_access_valid(struct device_node *dn, int where)
        return 0;
 }
 
+static int of_device_available(struct device_node * dn)
+{
+        char * status;
+
+        status = get_property(dn, "status", NULL);
+
+        if (!status)
+                return 1;
+
+        if (!strcmp(status, "okay"))
+                return 1;
+
+        return 0;
+}
+
 static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val)
 {
        int returnval = -1;
@@ -103,7 +118,7 @@ static int rtas_pci_read_config(struct pci_bus *bus,
 
        /* Search only direct children of the bus */
        for (dn = busdn->child; dn; dn = dn->sibling)
-               if (dn->devfn == devfn)
+               if (dn->devfn == devfn && of_device_available(dn))
                        return rtas_read_config(dn, where, size, val);
        return PCIBIOS_DEVICE_NOT_FOUND;
 }
@@ -146,7 +161,7 @@ static int rtas_pci_write_config(struct pci_bus *bus,
 
        /* Search only direct children of the bus */
        for (dn = busdn->child; dn; dn = dn->sibling)
-               if (dn->devfn == devfn)
+               if (dn->devfn == devfn && of_device_available(dn))
                        return rtas_write_config(dn, where, size, val);
        return PCIBIOS_DEVICE_NOT_FOUND;
 }
index b0c3b829fe47c43eac16b7d5ff9d885f0fd1b5c4..e26b0420b6ddea490c8a6fb8f81a0bd9ac351422 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/vmalloc.h>
 #include <linux/spinlock.h>
 #include <linux/cpu.h>
+#include <linux/delay.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -412,8 +413,7 @@ static void do_event_scan_all_cpus(long delay)
 
                /* Drop hotplug lock, and sleep for the specified delay */
                unlock_cpu_hotplug();
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(delay);
+               msleep_interruptible(delay);
                lock_cpu_hotplug();
 
                cpu = next_cpu(cpu, cpu_online_map);
@@ -442,7 +442,7 @@ static int rtasd(void *unused)
 
        printk(KERN_INFO "RTAS daemon started\n");
 
-       DEBUG("will sleep for %d jiffies\n", (HZ*60/rtas_event_scan_rate) / 2);
+       DEBUG("will sleep for %d milliseconds\n", (30000/rtas_event_scan_rate));
 
        /* See if we have any error stored in NVRAM */
        memset(logdata, 0, rtas_error_log_max);
@@ -459,7 +459,7 @@ static int rtasd(void *unused)
        }
 
        /* First pass. */
-       do_event_scan_all_cpus(HZ);
+       do_event_scan_all_cpus(1000);
 
        if (surveillance_timeout != -1) {
                DEBUG("enabling surveillance\n");
@@ -471,7 +471,7 @@ static int rtasd(void *unused)
         * machines have problems if we call event-scan too
         * quickly. */
        for (;;)
-               do_event_scan_all_cpus((HZ*60/rtas_event_scan_rate) / 2);
+               do_event_scan_all_cpus(30000/rtas_event_scan_rate);
 
 error:
        /* Should delete proc entries */
index d729fefa0df580f389eb2425edd54f89d53a7752..6ff52bc61325bc500c243ded44c6076415e663e6 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/spinlock.h>
 #include <linux/bcd.h>
 #include <linux/interrupt.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -351,8 +352,7 @@ void rtas_get_rtc_time(struct rtc_time *rtc_tm)
                                return; /* delay not allowed */
                        }
                        wait_time = rtas_extended_busy_delay_time(error);
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(wait_time);
+                       msleep_interruptible(wait_time);
                        error = RTAS_CLOCK_BUSY;
                }
        } while (error == RTAS_CLOCK_BUSY && (__get_tb() < max_wait_tb));
@@ -386,8 +386,7 @@ int rtas_set_rtc_time(struct rtc_time *tm)
                        if (in_interrupt())
                                return 1;       /* probably decrementer */
                        wait_time = rtas_extended_busy_delay_time(error);
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(wait_time);
+                       msleep_interruptible(wait_time);
                        error = RTAS_CLOCK_BUSY;
                }
        } while (error == RTAS_CLOCK_BUSY && (__get_tb() < max_wait_tb));
index 4d70736619c7d5153c8d54bc10e12eb078cb686a..215bf8900304ea8aa135434feeb26b33b53c6c41 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/errno.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 #include <asm/uaccess.h>
 #include <asm/rtas.h>
 #include <asm/prom.h>
@@ -77,7 +78,7 @@ static ssize_t scanlog_read(struct file *file, char __user *buf,
                return -EFAULT;
 
        for (;;) {
-               wait_time = HZ/2;       /* default wait if no data */
+               wait_time = 500;        /* default wait if no data */
                spin_lock(&rtas_data_buf_lock);
                memcpy(rtas_data_buf, data, RTAS_DATA_BUF_SIZE);
                status = rtas_call(ibm_scan_log_dump, 2, 1, NULL,
@@ -107,24 +108,14 @@ static ssize_t scanlog_read(struct file *file, char __user *buf,
                        break;
                    default:
                        if (status > 9900 && status <= 9905) {
-                               /* No data.  RTAS is hinting at a delay required
-                                * between 1-100000 milliseconds
-                                */
-                               int ms = 1;
-                               for (; status > 9900; status--)
-                                       ms = ms * 10;
-                               /* Use microseconds for reasonable accuracy */
-                               ms *= 1000;
-                               wait_time = ms / (1000000/HZ); /* round down is fine */
-                               /* Fall through to sleep */
+                               wait_time = rtas_extended_busy_delay_time(status);
                        } else {
                                printk(KERN_ERR "scanlog: unknown error from rtas: %d\n", status);
                                return -EIO;
                        }
                }
                /* Apparently no data yet.  Wait and try again. */
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(wait_time);
+               msleep_interruptible(wait_time);
        }
        /*NOTREACHED*/
 }
index e9c24d2dbd91276407ba53d2abd9e4b2fc013b34..d0bb68af0ea41d48bca4bc945d6e727ffcd2a424 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/seq_file.h>
 #include <linux/ioport.h>
 #include <linux/console.h>
-#include <linux/version.h>
+#include <linux/utsname.h>
 #include <linux/tty.h>
 #include <linux/root_dev.h>
 #include <linux/notifier.h>
@@ -89,7 +89,7 @@ extern void udbg_init_maple_realmode(void);
 #define EARLY_DEBUG_INIT() udbg_init_maple_realmode()
 #define EARLY_DEBUG_INIT() udbg_init_pmac_realmode()
 #define EARLY_DEBUG_INIT()                                             \
-       do { ppc_md.udbg_putc = call_rtas_display_status_delay; } while(0)
+       do { udbg_putc = call_rtas_display_status_delay; } while(0)
 #endif
 
 /* extern void *stab; */
@@ -108,7 +108,6 @@ int boot_cpuid = 0;
 int boot_cpuid_phys = 0;
 dev_t boot_dev;
 u64 ppc64_pft_size;
-u64 ppc64_debug_switch;
 
 struct ppc64_caches ppc64_caches;
 EXPORT_SYMBOL_GPL(ppc64_caches);
@@ -154,34 +153,6 @@ struct screen_info screen_info = {
        .orig_video_points = 16
 };
 
-/*
- * Initialize the PPCDBG state.  Called before relocation has been enabled.
- */
-void __init ppcdbg_initialize(void)
-{
-       ppc64_debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | */
-       /* PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */;
-}
-
-/*
- * Early boot console based on udbg
- */
-static struct console udbg_console = {
-       .name   = "udbg",
-       .write  = udbg_console_write,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,
-};
-static int early_console_initialized;
-
-void __init disable_early_printk(void)
-{
-       if (!early_console_initialized)
-               return;
-       unregister_console(&udbg_console);
-       early_console_initialized = 0;
-}
-
 #if defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP)
 
 static int smt_enabled_cmdline;
@@ -425,12 +396,6 @@ void __init early_setup(unsigned long dt_ptr)
        }
        ppc_md = **mach;
 
-       /* our udbg callbacks got overriden by the above, let's put them
-        * back in. Ultimately, I want those things to be split from the
-        * main ppc_md
-        */
-       EARLY_DEBUG_INIT();
-
        DBG("Found, Initializing memory management...\n");
 
        /*
@@ -536,15 +501,19 @@ static void __init check_for_initrd(void)
 
        DBG(" -> check_for_initrd()\n");
 
-       prop = (u64 *)get_property(of_chosen, "linux,initrd-start", NULL);
-       if (prop != NULL) {
-               initrd_start = (unsigned long)__va(*prop);
-               prop = (u64 *)get_property(of_chosen, "linux,initrd-end", NULL);
+       if (of_chosen) {
+               prop = (u64 *)get_property(of_chosen,
+                               "linux,initrd-start", NULL);
                if (prop != NULL) {
-                       initrd_end = (unsigned long)__va(*prop);
-                       initrd_below_start_ok = 1;
-               } else
-                       initrd_start = 0;
+                       initrd_start = (unsigned long)__va(*prop);
+                       prop = (u64 *)get_property(of_chosen,
+                                       "linux,initrd-end", NULL);
+                       if (prop != NULL) {
+                               initrd_end = (unsigned long)__va(*prop);
+                               initrd_below_start_ok = 1;
+                       } else
+                               initrd_start = 0;
+               }
        }
 
        /* If we were passed an initrd, set the ROOT_DEV properly if the values
@@ -627,13 +596,12 @@ void __init setup_system(void)
         * Initialize xmon
         */
 #ifdef CONFIG_XMON_DEFAULT
-       xmon_init();
+       xmon_init(1);
 #endif
        /*
         * Register early console
         */
-       early_console_initialized = 1;
-       register_console(&udbg_console);
+       register_early_udbg_console();
 
        /* Save unparsed command line copy for /proc/cmdline */
        strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE);
@@ -653,7 +621,7 @@ void __init setup_system(void)
        smp_release_cpus();
 #endif /* defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) */
 
-       printk("Starting Linux PPC64 %s\n", UTS_RELEASE);
+       printk("Starting Linux PPC64 %s\n", system_utsname.version);
 
        printk("-----------------------------------------------------\n");
        printk("ppc64_pft_size                = 0x%lx\n", ppc64_pft_size);
@@ -1343,11 +1311,13 @@ static int __init early_xmon(char *p)
        /* ensure xmon is enabled */
        if (p) {
                if (strncmp(p, "on", 2) == 0)
-                       xmon_init();
+                       xmon_init(1);
+               if (strncmp(p, "off", 3) == 0)
+                       xmon_init(0);
                if (strncmp(p, "early", 5) != 0)
                        return 0;
        }
-       xmon_init();
+       xmon_init(1);
        debugger(NULL);
 
        return 0;
index bf782276984c69147411c7aa5f513ab4cc545cda..49a79a55c32de7d5ab73191dbe78047a6dcf848e 100644 (file)
@@ -481,10 +481,11 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
        /* Set up Signal Frame */
        ret = setup_rt_frame(sig, ka, info, oldset, regs);
 
-       if (ret && !(ka->sa.sa_flags & SA_NODEFER)) {
+       if (ret) {
                spin_lock_irq(&current->sighand->siglock);
                sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
-               sigaddset(&current->blocked,sig);
+               if (!(ka->sa.sa_flags & SA_NODEFER))
+                       sigaddset(&current->blocked,sig);
                recalc_sigpending();
                spin_unlock_irq(&current->sighand->siglock);
        }
index 3c2fa5c284c04ef223c468c2df53f6c7676dc20a..46f4d6cc7fc9591ce7240887a05edadcd711c6f6 100644 (file)
@@ -976,11 +976,12 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
        else
                ret = handle_signal32(signr, &ka, &info, oldset, regs, newsp);
 
-       if (ret && !(ka.sa.sa_flags & SA_NODEFER)) {
+       if (ret) {
                spin_lock_irq(&current->sighand->siglock);
                sigorsets(&current->blocked, &current->blocked,
                          &ka.sa.sa_mask);
-               sigaddset(&current->blocked, signr);
+               if (!(ka.sa.sa_flags & SA_NODEFER))
+                       sigaddset(&current->blocked, signr);
                recalc_sigpending();
                spin_unlock_irq(&current->sighand->siglock);
        }
index 206619080e669b42cfdb3003dc85e715bf6e8221..214914a95a504e546a48837995bebfa9571a7eb1 100644 (file)
@@ -867,37 +867,6 @@ off_t ppc32_lseek(unsigned int fd, u32 offset, unsigned int origin)
        return sys_lseek(fd, (int)offset, origin);
 }
 
-/*
- * This is just a version for 32-bit applications which does
- * not force O_LARGEFILE on.
- */
-asmlinkage long sys32_open(const char __user * filename, int flags, int mode)
-{
-       char * tmp;
-       int fd, error;
-
-       tmp = getname(filename);
-       fd = PTR_ERR(tmp);
-       if (!IS_ERR(tmp)) {
-               fd = get_unused_fd();
-               if (fd >= 0) {
-                       struct file * f = filp_open(tmp, flags, mode);
-                       error = PTR_ERR(f);
-                       if (IS_ERR(f))
-                               goto out_error;
-                       fd_install(fd, f);
-               }
-out:
-               putname(tmp);
-       }
-       return fd;
-
-out_error:
-       put_unused_fd(fd);
-       fd = error;
-       goto out;
-}
-
 /* Note: it is necessary to treat bufsiz as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
index 02b8ac4e016883cfc5e4bfa0e151995346d4dc55..6654b350979cfd3a868c029677fff0239d9972ed 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/current.h>
 #include <asm/processor.h>
 #include <asm/cputable.h>
+#include <asm/firmware.h>
 #include <asm/hvcall.h>
 #include <asm/prom.h>
 #include <asm/systemcfg.h>
@@ -100,6 +101,8 @@ static int __init setup_smt_snooze_delay(char *str)
 }
 __setup("smt-snooze-delay=", setup_smt_snooze_delay);
 
+#endif /* CONFIG_PPC_MULTIPLATFORM */
+
 /*
  * Enabling PMCs will slow partition context switch times so we only do
  * it the first time we write to the PMCs.
@@ -109,65 +112,15 @@ static DEFINE_PER_CPU(char, pmcs_enabled);
 
 void ppc64_enable_pmcs(void)
 {
-       unsigned long hid0;
-#ifdef CONFIG_PPC_PSERIES
-       unsigned long set, reset;
-#endif /* CONFIG_PPC_PSERIES */
-
        /* Only need to enable them once */
        if (__get_cpu_var(pmcs_enabled))
                return;
 
        __get_cpu_var(pmcs_enabled) = 1;
 
-       switch (systemcfg->platform) {
-       case PLATFORM_PSERIES:
-       case PLATFORM_POWERMAC:
-               hid0 = mfspr(HID0);
-               hid0 |= 1UL << (63 - 20);
-
-               /* POWER4 requires the following sequence */
-               asm volatile(
-                            "sync\n"
-                            "mtspr     %1, %0\n"
-                            "mfspr     %0, %1\n"
-                            "mfspr     %0, %1\n"
-                            "mfspr     %0, %1\n"
-                            "mfspr     %0, %1\n"
-                            "mfspr     %0, %1\n"
-                            "mfspr     %0, %1\n"
-                            "isync" : "=&r" (hid0) : "i" (HID0), "0" (hid0):
-                            "memory");
-               break;
-
-#ifdef CONFIG_PPC_PSERIES
-       case PLATFORM_PSERIES_LPAR:
-               set = 1UL << 63;
-               reset = 0;
-               plpar_hcall_norets(H_PERFMON, set, reset);
-               break;
-#endif /* CONFIG_PPC_PSERIES */
-
-       default:
-               break;
-       }
-
-#ifdef CONFIG_PPC_PSERIES
-       /* instruct hypervisor to maintain PMCs */
-       if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)
-               get_paca()->lppaca.pmcregs_in_use = 1;
-#endif /* CONFIG_PPC_PSERIES */
+       if (ppc_md.enable_pmcs)
+               ppc_md.enable_pmcs();
 }
-
-#else
-
-/* PMC stuff */
-void ppc64_enable_pmcs(void)
-{
-       /* XXX Implement for iseries */
-}
-#endif /* CONFIG_PPC_MULTIPLATFORM */
-
 EXPORT_SYMBOL(ppc64_enable_pmcs);
 
 /* XXX convert to rusty's on_one_cpu */
@@ -262,18 +215,23 @@ static void register_cpu_online(unsigned int cpu)
        if (cpu_has_feature(CPU_FTR_MMCRA))
                sysdev_create_file(s, &attr_mmcra);
 
-       sysdev_create_file(s, &attr_pmc1);
-       sysdev_create_file(s, &attr_pmc2);
-       sysdev_create_file(s, &attr_pmc3);
-       sysdev_create_file(s, &attr_pmc4);
-       sysdev_create_file(s, &attr_pmc5);
-       sysdev_create_file(s, &attr_pmc6);
-
-       if (cpu_has_feature(CPU_FTR_PMC8)) {
+       if (cur_cpu_spec->num_pmcs >= 1)
+               sysdev_create_file(s, &attr_pmc1);
+       if (cur_cpu_spec->num_pmcs >= 2)
+               sysdev_create_file(s, &attr_pmc2);
+       if (cur_cpu_spec->num_pmcs >= 3)
+               sysdev_create_file(s, &attr_pmc3);
+       if (cur_cpu_spec->num_pmcs >= 4)
+               sysdev_create_file(s, &attr_pmc4);
+       if (cur_cpu_spec->num_pmcs >= 5)
+               sysdev_create_file(s, &attr_pmc5);
+       if (cur_cpu_spec->num_pmcs >= 6)
+               sysdev_create_file(s, &attr_pmc6);
+       if (cur_cpu_spec->num_pmcs >= 7)
                sysdev_create_file(s, &attr_pmc7);
+       if (cur_cpu_spec->num_pmcs >= 8)
                sysdev_create_file(s, &attr_pmc8);
-       }
-
+  
        if (cpu_has_feature(CPU_FTR_SMT))
                sysdev_create_file(s, &attr_purr);
 }
@@ -299,17 +257,22 @@ static void unregister_cpu_online(unsigned int cpu)
        if (cpu_has_feature(CPU_FTR_MMCRA))
                sysdev_remove_file(s, &attr_mmcra);
 
-       sysdev_remove_file(s, &attr_pmc1);
-       sysdev_remove_file(s, &attr_pmc2);
-       sysdev_remove_file(s, &attr_pmc3);
-       sysdev_remove_file(s, &attr_pmc4);
-       sysdev_remove_file(s, &attr_pmc5);
-       sysdev_remove_file(s, &attr_pmc6);
-
-       if (cpu_has_feature(CPU_FTR_PMC8)) {
+       if (cur_cpu_spec->num_pmcs >= 1)
+               sysdev_remove_file(s, &attr_pmc1);
+       if (cur_cpu_spec->num_pmcs >= 2)
+               sysdev_remove_file(s, &attr_pmc2);
+       if (cur_cpu_spec->num_pmcs >= 3)
+               sysdev_remove_file(s, &attr_pmc3);
+       if (cur_cpu_spec->num_pmcs >= 4)
+               sysdev_remove_file(s, &attr_pmc4);
+       if (cur_cpu_spec->num_pmcs >= 5)
+               sysdev_remove_file(s, &attr_pmc5);
+       if (cur_cpu_spec->num_pmcs >= 6)
+               sysdev_remove_file(s, &attr_pmc6);
+       if (cur_cpu_spec->num_pmcs >= 7)
                sysdev_remove_file(s, &attr_pmc7);
+       if (cur_cpu_spec->num_pmcs >= 8)
                sysdev_remove_file(s, &attr_pmc8);
-       }
 
        if (cpu_has_feature(CPU_FTR_SMT))
                sysdev_remove_file(s, &attr_purr);
index 909462e1adeaf7cc1bab5ec9b766315d2ee63ec8..9939c206afa42c776eef326e92094a29e5eaa211 100644 (file)
@@ -51,7 +51,6 @@
 #include <linux/cpu.h>
 #include <linux/security.h>
 
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/nvram.h>
@@ -67,6 +66,7 @@
 #include <asm/prom.h>
 #include <asm/sections.h>
 #include <asm/systemcfg.h>
+#include <asm/firmware.h>
 
 u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES;
 
@@ -128,7 +128,7 @@ static __inline__ void timer_check_rtc(void)
          * We should have an rtc call that only sets the minutes and
          * seconds like on Intel to avoid problems with non UTC clocks.
          */
-        if ( (time_status & STA_UNSYNC) == 0 &&
+        if (ntp_synced() &&
              xtime.tv_sec - last_rtc_update >= 659 &&
              abs((xtime.tv_nsec/1000) - (1000000-1000000/HZ)) < 500000/HZ &&
              jiffies - wall_jiffies == 1) {
@@ -370,13 +370,11 @@ int timer_interrupt(struct pt_regs * regs)
                process_hvlpevents(regs);
 #endif
 
-/* collect purr register values often, for accurate calculations */
-#if defined(CONFIG_PPC_PSERIES)
-       if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
+       /* collect purr register values often, for accurate calculations */
+       if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
                struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array);
                cu->current_tb = mfspr(SPRN_PURR);
        }
-#endif
 
        irq_exit();
 
@@ -437,10 +435,7 @@ int do_settimeofday(struct timespec *tv)
         */
        last_rtc_update = new_sec - 658;
 
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
 
        delta_xsec = mulhdu( (tb_last_stamp-do_gtod.varp->tb_orig_stamp),
                             do_gtod.varp->tb_to_xs );
index a8d5e83ee89fceafa18c46f43001aaebd4938567..7467ae508e6e27e734c1fc9110c2f03e60790900 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/delay.h>
+#include <linux/kprobes.h>
 #include <asm/kdebug.h>
 
 #include <asm/pgtable.h>
@@ -220,7 +221,7 @@ void instruction_breakpoint_exception(struct pt_regs *regs)
        _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
 }
 
-void single_step_exception(struct pt_regs *regs)
+void __kprobes single_step_exception(struct pt_regs *regs)
 {
        regs->msr &= ~MSR_SE;  /* Turn off 'trace' bit */
 
@@ -398,7 +399,7 @@ check_bug_trap(struct pt_regs *regs)
        return 0;
 }
 
-void program_check_exception(struct pt_regs *regs)
+void __kprobes program_check_exception(struct pt_regs *regs)
 {
        if (debugger_fault_handler(regs))
                return;
index c0da45540f0f50e1a2695b4f325e99831cccd3e1..ed6766e21f5a4c5df82405b2ac5530aec54f4e36 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * NS16550 Serial Port (uart) debugging stuff.
+ * polling mode stateless debugging stuff, originally for NS16550 Serial Ports
  *
  * c 2001 PPC 64 Team, IBM Corp
  *
 #define WANT_PPCDBG_TAB /* Only defined here */
 #include <linux/config.h>
 #include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/console.h>
 #include <asm/ppcdebug.h>
 #include <asm/processor.h>
-#include <asm/uaccess.h>
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/pmac_feature.h>
 
-extern u8 real_readb(volatile u8 __iomem  *addr);
-extern void real_writeb(u8 data, volatile u8 __iomem *addr);
-
-struct NS16550 {
-       /* this struct must be packed */
-       unsigned char rbr;  /* 0 */
-       unsigned char ier;  /* 1 */
-       unsigned char fcr;  /* 2 */
-       unsigned char lcr;  /* 3 */
-       unsigned char mcr;  /* 4 */
-       unsigned char lsr;  /* 5 */
-       unsigned char msr;  /* 6 */
-       unsigned char scr;  /* 7 */
-};
-
-#define thr rbr
-#define iir fcr
-#define dll rbr
-#define dlm ier
-#define dlab lcr
-
-#define LSR_DR   0x01  /* Data ready */
-#define LSR_OE   0x02  /* Overrun */
-#define LSR_PE   0x04  /* Parity error */
-#define LSR_FE   0x08  /* Framing error */
-#define LSR_BI   0x10  /* Break */
-#define LSR_THRE 0x20  /* Xmit holding register empty */
-#define LSR_TEMT 0x40  /* Xmitter empty */
-#define LSR_ERR  0x80  /* Error */
-
-static volatile struct NS16550 __iomem *udbg_comport;
-
-void udbg_init_uart(void __iomem *comport, unsigned int speed)
-{
-       u16 dll = speed ? (115200 / speed) : 12;
-
-       if (comport) {
-               udbg_comport = (struct NS16550 __iomem *)comport;
-               out_8(&udbg_comport->lcr, 0x00);
-               out_8(&udbg_comport->ier, 0xff);
-               out_8(&udbg_comport->ier, 0x00);
-               out_8(&udbg_comport->lcr, 0x80);        /* Access baud rate */
-               out_8(&udbg_comport->dll, dll & 0xff);  /* 1 = 115200,  2 = 57600,
-                                                          3 = 38400, 12 = 9600 baud */
-               out_8(&udbg_comport->dlm, dll >> 8);    /* dll >> 8 which should be zero
-                                                          for fast rates; */
-               out_8(&udbg_comport->lcr, 0x03);        /* 8 data, 1 stop, no parity */
-               out_8(&udbg_comport->mcr, 0x03);        /* RTS/DTR */
-               out_8(&udbg_comport->fcr ,0x07);        /* Clear & enable FIFOs */
-       }
-}
-
-#ifdef CONFIG_PPC_PMAC
-
-#define        SCC_TXRDY       4
-#define SCC_RXRDY      1
-
-static volatile u8 __iomem *sccc;
-static volatile u8 __iomem *sccd;
-
-static unsigned char scc_inittab[] = {
-    13, 0,             /* set baud rate divisor */
-    12, 0,
-    14, 1,             /* baud rate gen enable, src=rtxc */
-    11, 0x50,          /* clocks = br gen */
-    5,  0xea,          /* tx 8 bits, assert DTR & RTS */
-    4,  0x46,          /* x16 clock, 1 stop */
-    3,  0xc1,          /* rx enable, 8 bits */
-};
-
-void udbg_init_scc(struct device_node *np)
-{
-       u32 *reg;
-       unsigned long addr;
-       int i, x;
-
-       if (np == NULL)
-               np = of_find_node_by_name(NULL, "escc");
-       if (np == NULL || np->parent == NULL)
-               return;
-
-       udbg_printf("found SCC...\n");
-       /* Get address within mac-io ASIC */ 
-       reg = (u32 *)get_property(np, "reg", NULL);
-       if (reg == NULL)
-               return;
-       addr = reg[0];
-       udbg_printf("local addr: %lx\n", addr);
-       /* Get address of mac-io PCI itself */
-       reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL);
-       if (reg == NULL)
-               return;
-       addr += reg[2];
-       udbg_printf("final addr: %lx\n", addr);
-
-       /* Setup for 57600 8N1 */
-       addr += 0x20;
-       sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
-       sccc += addr & ~PAGE_MASK;
-       sccd = sccc + 0x10;
-
-       udbg_printf("ioremap result sccc: %p\n", sccc);
-       mb();
-
-       for (i = 20000; i != 0; --i)
-               x = in_8(sccc);
-       out_8(sccc, 0x09);              /* reset A or B side */
-       out_8(sccc, 0xc0);
-       for (i = 0; i < sizeof(scc_inittab); ++i)
-               out_8(sccc, scc_inittab[i]);
-
-       ppc_md.udbg_putc = udbg_putc;
-       ppc_md.udbg_getc = udbg_getc;
-       ppc_md.udbg_getc_poll = udbg_getc_poll;
-
-       udbg_puts("Hello World !\n");
-}
-
-#endif /* CONFIG_PPC_PMAC */
-
-#ifdef CONFIG_PPC_PMAC
-static void udbg_real_putc(unsigned char c)
-{
-       while ((real_readb(sccc) & SCC_TXRDY) == 0)
-               ;
-       real_writeb(c, sccd);
-       if (c == '\n')
-               udbg_real_putc('\r');
-}
-
-void udbg_init_pmac_realmode(void)
-{
-       sccc = (volatile u8 __iomem *)0x80013020ul;
-       sccd = (volatile u8 __iomem *)0x80013030ul;
-
-       ppc_md.udbg_putc = udbg_real_putc;
-       ppc_md.udbg_getc = NULL;
-       ppc_md.udbg_getc_poll = NULL;
-}
-#endif /* CONFIG_PPC_PMAC */
-
-#ifdef CONFIG_PPC_MAPLE
-void udbg_maple_real_putc(unsigned char c)
-{
-       if (udbg_comport) {
-               while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
-                       /* wait for idle */;
-               real_writeb(c, &udbg_comport->thr); eieio();
-               if (c == '\n') {
-                       /* Also put a CR.  This is for convenience. */
-                       while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
-                               /* wait for idle */;
-                       real_writeb('\r', &udbg_comport->thr); eieio();
-               }
-       }
-}
-
-void udbg_init_maple_realmode(void)
-{
-       udbg_comport = (volatile struct NS16550 __iomem *)0xf40003f8;
-
-       ppc_md.udbg_putc = udbg_maple_real_putc;
-       ppc_md.udbg_getc = NULL;
-       ppc_md.udbg_getc_poll = NULL;
-}
-#endif /* CONFIG_PPC_MAPLE */
-
-void udbg_putc(unsigned char c)
-{
-       if (udbg_comport) {
-               while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
-                       /* wait for idle */;
-               out_8(&udbg_comport->thr, c);
-               if (c == '\n') {
-                       /* Also put a CR.  This is for convenience. */
-                       while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
-                               /* wait for idle */; 
-                       out_8(&udbg_comport->thr, '\r');
-               }
-       }
-#ifdef CONFIG_PPC_PMAC
-       else if (sccc) {
-               while ((in_8(sccc) & SCC_TXRDY) == 0)
-                       ;
-               out_8(sccd,  c);                
-               if (c == '\n')
-                       udbg_putc('\r');
-       }
-#endif /* CONFIG_PPC_PMAC */
-}
-
-int udbg_getc_poll(void)
-{
-       if (udbg_comport) {
-               if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0)
-                       return in_8(&udbg_comport->rbr);
-               else
-                       return -1;
-       }
-#ifdef CONFIG_PPC_PMAC
-       else if (sccc) {
-               if ((in_8(sccc) & SCC_RXRDY) != 0)
-                       return in_8(sccd);
-               else
-                       return -1;
-       }
-#endif /* CONFIG_PPC_PMAC */
-       return -1;
-}
-
-unsigned char udbg_getc(void)
-{
-       if (udbg_comport) {
-               while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0)
-                       /* wait for char */;
-               return in_8(&udbg_comport->rbr);
-       }
-#ifdef CONFIG_PPC_PMAC
-       else if (sccc) {
-               while ((in_8(sccc) & SCC_RXRDY) == 0)
-                       ;
-               return in_8(sccd);
-       }
-#endif /* CONFIG_PPC_PMAC */
-       return 0;
-}
+void (*udbg_putc)(unsigned char c);
+unsigned char (*udbg_getc)(void);
+int (*udbg_getc_poll)(void);
 
+/* udbg library, used by xmon et al */
 void udbg_puts(const char *s)
 {
-       if (ppc_md.udbg_putc) {
+       if (udbg_putc) {
                char c;
 
                if (s && *s != '\0') {
                        while ((c = *s++) != '\0')
-                               ppc_md.udbg_putc(c);
+                               udbg_putc(c);
                }
        }
 #if 0
@@ -270,12 +45,12 @@ int udbg_write(const char *s, int n)
        int remain = n;
        char c;
 
-       if (!ppc_md.udbg_putc)
+       if (!udbg_putc)
                return 0;
 
        if (s && *s != '\0') {
                while (((c = *s++) != '\0') && (remain-- > 0)) {
-                       ppc_md.udbg_putc(c);
+                       udbg_putc(c);
                }
        }
 
@@ -287,12 +62,12 @@ int udbg_read(char *buf, int buflen)
        char c, *p = buf;
        int i;
 
-       if (!ppc_md.udbg_getc)
+       if (!udbg_getc)
                return 0;
 
        for (i = 0; i < buflen; ++i) {
                do {
-                       c = ppc_md.udbg_getc();
+                       c = udbg_getc();
                } while (c == 0x11 || c == 0x13);
                if (c == 0)
                        break;
@@ -302,11 +77,6 @@ int udbg_read(char *buf, int buflen)
        return i;
 }
 
-void udbg_console_write(struct console *con, const char *s, unsigned int n)
-{
-       udbg_write(s, n);
-}
-
 #define UDBG_BUFSIZE 256
 void udbg_printf(const char *fmt, ...)
 {
@@ -319,6 +89,10 @@ void udbg_printf(const char *fmt, ...)
        va_end(args);
 }
 
+/* PPCDBG stuff */
+
+u64 ppc64_debug_switch;
+
 /* Special print used by PPCDBG() macro */
 void udbg_ppcdbg(unsigned long debug_flags, const char *fmt, ...)
 {
@@ -358,3 +132,43 @@ unsigned long udbg_ifdebug(unsigned long flags)
 {
        return (flags & ppc64_debug_switch);
 }
+
+/*
+ * Initialize the PPCDBG state.  Called before relocation has been enabled.
+ */
+void __init ppcdbg_initialize(void)
+{
+       ppc64_debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | */
+       /* PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */;
+}
+
+/*
+ * Early boot console based on udbg
+ */
+static void udbg_console_write(struct console *con, const char *s,
+               unsigned int n)
+{
+       udbg_write(s, n);
+}
+
+static struct console udbg_console = {
+       .name   = "udbg",
+       .write  = udbg_console_write,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+};
+
+void __init disable_early_printk(void)
+{
+       unregister_console(&udbg_console);
+}
+
+/* called by setup_system */
+void register_early_udbg_console(void)
+{
+       register_console(&udbg_console);
+}
+
+#if 0   /* if you want to use this as a regular output console */
+console_initcall(register_udbg_console);
+#endif
diff --git a/arch/ppc64/kernel/udbg_16550.c b/arch/ppc64/kernel/udbg_16550.c
new file mode 100644 (file)
index 0000000..9313574
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * udbg for for NS16550 compatable serial ports
+ *
+ * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/udbg.h>
+#include <asm/io.h>
+
+extern u8 real_readb(volatile u8 __iomem  *addr);
+extern void real_writeb(u8 data, volatile u8 __iomem *addr);
+
+struct NS16550 {
+       /* this struct must be packed */
+       unsigned char rbr;  /* 0 */
+       unsigned char ier;  /* 1 */
+       unsigned char fcr;  /* 2 */
+       unsigned char lcr;  /* 3 */
+       unsigned char mcr;  /* 4 */
+       unsigned char lsr;  /* 5 */
+       unsigned char msr;  /* 6 */
+       unsigned char scr;  /* 7 */
+};
+
+#define thr rbr
+#define iir fcr
+#define dll rbr
+#define dlm ier
+#define dlab lcr
+
+#define LSR_DR   0x01  /* Data ready */
+#define LSR_OE   0x02  /* Overrun */
+#define LSR_PE   0x04  /* Parity error */
+#define LSR_FE   0x08  /* Framing error */
+#define LSR_BI   0x10  /* Break */
+#define LSR_THRE 0x20  /* Xmit holding register empty */
+#define LSR_TEMT 0x40  /* Xmitter empty */
+#define LSR_ERR  0x80  /* Error */
+
+static volatile struct NS16550 __iomem *udbg_comport;
+
+static void udbg_550_putc(unsigned char c)
+{
+       if (udbg_comport) {
+               while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
+                       /* wait for idle */;
+               out_8(&udbg_comport->thr, c);
+               if (c == '\n')
+                       udbg_550_putc('\r');
+       }
+}
+
+static int udbg_550_getc_poll(void)
+{
+       if (udbg_comport) {
+               if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0)
+                       return in_8(&udbg_comport->rbr);
+               else
+                       return -1;
+       }
+       return -1;
+}
+
+static unsigned char udbg_550_getc(void)
+{
+       if (udbg_comport) {
+               while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0)
+                       /* wait for char */;
+               return in_8(&udbg_comport->rbr);
+       }
+       return 0;
+}
+
+void udbg_init_uart(void __iomem *comport, unsigned int speed)
+{
+       u16 dll = speed ? (115200 / speed) : 12;
+
+       if (comport) {
+               udbg_comport = (struct NS16550 __iomem *)comport;
+               out_8(&udbg_comport->lcr, 0x00);
+               out_8(&udbg_comport->ier, 0xff);
+               out_8(&udbg_comport->ier, 0x00);
+               out_8(&udbg_comport->lcr, 0x80);        /* Access baud rate */
+               out_8(&udbg_comport->dll, dll & 0xff);  /* 1 = 115200,  2 = 57600,
+                                                          3 = 38400, 12 = 9600 baud */
+               out_8(&udbg_comport->dlm, dll >> 8);    /* dll >> 8 which should be zero
+                                                          for fast rates; */
+               out_8(&udbg_comport->lcr, 0x03);        /* 8 data, 1 stop, no parity */
+               out_8(&udbg_comport->mcr, 0x03);        /* RTS/DTR */
+               out_8(&udbg_comport->fcr ,0x07);        /* Clear & enable FIFOs */
+               udbg_putc = udbg_550_putc;
+               udbg_getc = udbg_550_getc;
+               udbg_getc_poll = udbg_550_getc_poll;
+       }
+}
+
+#ifdef CONFIG_PPC_MAPLE
+void udbg_maple_real_putc(unsigned char c)
+{
+       if (udbg_comport) {
+               while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
+                       /* wait for idle */;
+               real_writeb(c, &udbg_comport->thr); eieio();
+               if (c == '\n')
+                       udbg_maple_real_putc('\r');
+       }
+}
+
+void udbg_init_maple_realmode(void)
+{
+       udbg_comport = (volatile struct NS16550 __iomem *)0xf40003f8;
+
+       udbg_putc = udbg_maple_real_putc;
+       udbg_getc = NULL;
+       udbg_getc_poll = NULL;
+}
+#endif /* CONFIG_PPC_MAPLE */
diff --git a/arch/ppc64/kernel/udbg_scc.c b/arch/ppc64/kernel/udbg_scc.c
new file mode 100644 (file)
index 0000000..c47fd6c
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * udbg for for zilog scc ports as found on Apple PowerMacs
+ *
+ * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/udbg.h>
+#include <asm/processor.h>
+#include <asm/naca.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pmac_feature.h>
+
+extern u8 real_readb(volatile u8 __iomem  *addr);
+extern void real_writeb(u8 data, volatile u8 __iomem *addr);
+
+#define        SCC_TXRDY       4
+#define SCC_RXRDY      1
+
+static volatile u8 __iomem *sccc;
+static volatile u8 __iomem *sccd;
+
+static void udbg_scc_putc(unsigned char c)
+{
+       if (sccc) {
+               while ((in_8(sccc) & SCC_TXRDY) == 0)
+                       ;
+               out_8(sccd,  c);
+               if (c == '\n')
+                       udbg_scc_putc('\r');
+       }
+}
+
+static int udbg_scc_getc_poll(void)
+{
+       if (sccc) {
+               if ((in_8(sccc) & SCC_RXRDY) != 0)
+                       return in_8(sccd);
+               else
+                       return -1;
+       }
+       return -1;
+}
+
+static unsigned char udbg_scc_getc(void)
+{
+       if (sccc) {
+               while ((in_8(sccc) & SCC_RXRDY) == 0)
+                       ;
+               return in_8(sccd);
+       }
+       return 0;
+}
+
+static unsigned char scc_inittab[] = {
+    13, 0,             /* set baud rate divisor */
+    12, 0,
+    14, 1,             /* baud rate gen enable, src=rtxc */
+    11, 0x50,          /* clocks = br gen */
+    5,  0xea,          /* tx 8 bits, assert DTR & RTS */
+    4,  0x46,          /* x16 clock, 1 stop */
+    3,  0xc1,          /* rx enable, 8 bits */
+};
+
+void udbg_init_scc(struct device_node *np)
+{
+       u32 *reg;
+       unsigned long addr;
+       int i, x;
+
+       if (np == NULL)
+               np = of_find_node_by_name(NULL, "escc");
+       if (np == NULL || np->parent == NULL)
+               return;
+
+       udbg_printf("found SCC...\n");
+       /* Get address within mac-io ASIC */
+       reg = (u32 *)get_property(np, "reg", NULL);
+       if (reg == NULL)
+               return;
+       addr = reg[0];
+       udbg_printf("local addr: %lx\n", addr);
+       /* Get address of mac-io PCI itself */
+       reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL);
+       if (reg == NULL)
+               return;
+       addr += reg[2];
+       udbg_printf("final addr: %lx\n", addr);
+
+       /* Setup for 57600 8N1 */
+       addr += 0x20;
+       sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
+       sccc += addr & ~PAGE_MASK;
+       sccd = sccc + 0x10;
+
+       udbg_printf("ioremap result sccc: %p\n", sccc);
+       mb();
+
+       for (i = 20000; i != 0; --i)
+               x = in_8(sccc);
+       out_8(sccc, 0x09);              /* reset A or B side */
+       out_8(sccc, 0xc0);
+       for (i = 0; i < sizeof(scc_inittab); ++i)
+               out_8(sccc, scc_inittab[i]);
+
+       udbg_putc = udbg_scc_putc;
+       udbg_getc = udbg_scc_getc;
+       udbg_getc_poll = udbg_scc_getc_poll;
+
+       udbg_puts("Hello World !\n");
+}
+
+static void udbg_real_scc_putc(unsigned char c)
+{
+       while ((real_readb(sccc) & SCC_TXRDY) == 0)
+               ;
+       real_writeb(c, sccd);
+       if (c == '\n')
+               udbg_real_scc_putc('\r');
+}
+
+void udbg_init_pmac_realmode(void)
+{
+       sccc = (volatile u8 __iomem *)0x80013020ul;
+       sccd = (volatile u8 __iomem *)0x80013030ul;
+
+       udbg_putc = udbg_real_scc_putc;
+       udbg_getc = NULL;
+       udbg_getc_poll = NULL;
+}
index 0c0ba71ac0e8b79cd2a29b8fffd8d4f177ac006b..c90e1dd875ce1a59f8250410f0610d2324112a81 100644 (file)
@@ -1,10 +1,11 @@
 /*
  * IBM PowerPC Virtual I/O Infrastructure Support.
  *
- *    Copyright (c) 2003 IBM Corp.
+ *    Copyright (c) 2003-2005 IBM Corp.
  *     Dave Engebretsen engebret@us.ibm.com
  *     Santiago Leon santil@us.ibm.com
  *     Hollis Blanchard <hollisb@us.ibm.com>
+ *     Stephen Rothwell
  *
  *      This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
 
 #include <linux/init.h>
 #include <linux/console.h>
-#include <linux/version.h>
 #include <linux/module.h>
-#include <linux/kobject.h>
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
-#include <asm/rtas.h>
 #include <asm/iommu.h>
 #include <asm/dma.h>
-#include <asm/ppcdebug.h>
 #include <asm/vio.h>
-#include <asm/hvcall.h>
-#include <asm/iSeries/vio.h>
-#include <asm/iSeries/HvTypes.h>
-#include <asm/iSeries/HvCallXm.h>
-#include <asm/iSeries/HvLpConfig.h>
-
-#define DBGENTER() pr_debug("%s entered\n", __FUNCTION__)
-
-extern struct subsystem devices_subsys; /* needed for vio_find_name() */
 
 static const struct vio_device_id *vio_match_device(
                const struct vio_device_id *, const struct vio_dev *);
 
-#ifdef CONFIG_PPC_PSERIES
-static struct iommu_table *vio_build_iommu_table(struct vio_dev *);
-static int vio_num_address_cells;
-#endif
-#ifdef CONFIG_PPC_ISERIES
-static struct iommu_table veth_iommu_table;
-static struct iommu_table vio_iommu_table;
-#endif
-static struct vio_dev vio_bus_device  = { /* fake "parent" device */
+struct vio_dev vio_bus_device  = { /* fake "parent" device */
        .name = vio_bus_device.dev.bus_id,
        .type = "",
-#ifdef CONFIG_PPC_ISERIES
-       .iommu_table = &vio_iommu_table,
-#endif
        .dev.bus_id = "vio",
        .dev.bus = &vio_bus_type,
 };
 
-#ifdef CONFIG_PPC_ISERIES
-static struct vio_dev *__init vio_register_device_iseries(char *type,
-               uint32_t unit_num);
-
-struct device *iSeries_vio_dev = &vio_bus_device.dev;
-EXPORT_SYMBOL(iSeries_vio_dev);
-
-#define device_is_compatible(a, b)     1
+static struct vio_bus_ops vio_bus_ops;
 
-#endif
-
-/* convert from struct device to struct vio_dev and pass to driver.
+/*
+ * Convert from struct device to struct vio_dev and pass to driver.
  * dev->driver has already been set by generic code because vio_bus_match
- * succeeded. */
+ * succeeded.
+ */
 static int vio_bus_probe(struct device *dev)
 {
        struct vio_dev *viodev = to_vio_dev(dev);
@@ -76,15 +46,12 @@ static int vio_bus_probe(struct device *dev)
        const struct vio_device_id *id;
        int error = -ENODEV;
 
-       DBGENTER();
-
        if (!viodrv->probe)
                return error;
 
        id = vio_match_device(viodrv->id_table, viodev);
-       if (id) {
+       if (id)
                error = viodrv->probe(viodev, id);
-       }
 
        return error;
 }
@@ -95,11 +62,8 @@ static int vio_bus_remove(struct device *dev)
        struct vio_dev *viodev = to_vio_dev(dev);
        struct vio_driver *viodrv = to_vio_driver(dev->driver);
 
-       DBGENTER();
-
-       if (viodrv->remove) {
+       if (viodrv->remove)
                return viodrv->remove(viodev);
-       }
 
        /* driver can't remove */
        return 1;
@@ -135,193 +99,72 @@ void vio_unregister_driver(struct vio_driver *viodrv)
 EXPORT_SYMBOL(vio_unregister_driver);
 
 /**
- * vio_match_device: - Tell if a VIO device has a matching VIO device id structure.
- * @ids:       array of VIO device id structures to search in
- * @dev:       the VIO device structure to match against
+ * vio_match_device: - Tell if a VIO device has a matching
+ *                     VIO device id structure.
+ * @ids:       array of VIO device id structures to search in
+ * @dev:       the VIO device structure to match against
  *
  * Used by a driver to check whether a VIO device present in the
  * system is in its list of supported devices. Returns the matching
  * vio_device_id structure or NULL if there is no match.
  */
-static const struct vio_device_id * vio_match_device(const struct vio_device_id *ids,
-       const struct vio_dev *dev)
+static const struct vio_device_id *vio_match_device(
+               const struct vio_device_id *ids, const struct vio_dev *dev)
 {
-       DBGENTER();
-
-       while (ids->type) {
-               if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) &&
-                       device_is_compatible(dev->dev.platform_data, ids->compat))
+       while (ids->type[0] != '\0') {
+               if (vio_bus_ops.match(ids, dev))
                        return ids;
                ids++;
        }
        return NULL;
 }
 
-#ifdef CONFIG_PPC_ISERIES
-void __init iommu_vio_init(void)
-{
-       struct iommu_table *t;
-       struct iommu_table_cb cb;
-       unsigned long cbp;
-       unsigned long itc_entries;
-
-       cb.itc_busno = 255;    /* Bus 255 is the virtual bus */
-       cb.itc_virtbus = 0xff; /* Ask for virtual bus */
-
-       cbp = virt_to_abs(&cb);
-       HvCallXm_getTceTableParms(cbp);
-
-       itc_entries = cb.itc_size * PAGE_SIZE / sizeof(union tce_entry);
-       veth_iommu_table.it_size        = itc_entries / 2;
-       veth_iommu_table.it_busno       = cb.itc_busno;
-       veth_iommu_table.it_offset      = cb.itc_offset;
-       veth_iommu_table.it_index       = cb.itc_index;
-       veth_iommu_table.it_type        = TCE_VB;
-       veth_iommu_table.it_blocksize   = 1;
-
-       t = iommu_init_table(&veth_iommu_table);
-
-       if (!t)
-               printk("Virtual Bus VETH TCE table failed.\n");
-
-       vio_iommu_table.it_size         = itc_entries - veth_iommu_table.it_size;
-       vio_iommu_table.it_busno        = cb.itc_busno;
-       vio_iommu_table.it_offset       = cb.itc_offset +
-                                         veth_iommu_table.it_size;
-       vio_iommu_table.it_index        = cb.itc_index;
-       vio_iommu_table.it_type         = TCE_VB;
-       vio_iommu_table.it_blocksize    = 1;
-
-       t = iommu_init_table(&vio_iommu_table);
-
-       if (!t)
-               printk("Virtual Bus VIO TCE table failed.\n");
-}
-#endif
-
-#ifdef CONFIG_PPC_PSERIES
-static void probe_bus_pseries(void)
-{
-       struct device_node *node_vroot, *of_node;
-
-       node_vroot = find_devices("vdevice");
-       if ((node_vroot == NULL) || (node_vroot->child == NULL))
-               /* this machine doesn't do virtual IO, and that's ok */
-               return;
-
-       vio_num_address_cells = prom_n_addr_cells(node_vroot->child);
-
-       /*
-        * Create struct vio_devices for each virtual device in the device tree.
-        * Drivers will associate with them later.
-        */
-       for (of_node = node_vroot->child; of_node != NULL;
-                       of_node = of_node->sibling) {
-               printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, of_node);
-               vio_register_device_node(of_node);
-       }
-}
-#endif
-
-#ifdef CONFIG_PPC_ISERIES
-static void probe_bus_iseries(void)
-{
-       HvLpIndexMap vlan_map = HvLpConfig_getVirtualLanIndexMap();
-       struct vio_dev *viodev;
-       int i;
-
-       /* there is only one of each of these */
-       vio_register_device_iseries("viocons", 0);
-       vio_register_device_iseries("vscsi", 0);
-
-       vlan_map = HvLpConfig_getVirtualLanIndexMap();
-       for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
-               if ((vlan_map & (0x8000 >> i)) == 0)
-                       continue;
-               viodev = vio_register_device_iseries("vlan", i);
-               /* veth is special and has it own iommu_table */
-               viodev->iommu_table = &veth_iommu_table;
-       }
-       for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++)
-               vio_register_device_iseries("viodasd", i);
-       for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++)
-               vio_register_device_iseries("viocd", i);
-       for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)
-               vio_register_device_iseries("viotape", i);
-}
-#endif
-
 /**
  * vio_bus_init: - Initialize the virtual IO bus
  */
-static int __init vio_bus_init(void)
+int __init vio_bus_init(struct vio_bus_ops *ops)
 {
        int err;
 
+       vio_bus_ops = *ops;
+
        err = bus_register(&vio_bus_type);
        if (err) {
                printk(KERN_ERR "failed to register VIO bus\n");
                return err;
        }
 
-       /* the fake parent of all vio devices, just to give us a nice directory */
+       /*
+        * The fake parent of all vio devices, just to give us
+        * a nice directory
+        */
        err = device_register(&vio_bus_device.dev);
        if (err) {
-               printk(KERN_WARNING "%s: device_register returned %i\n", __FUNCTION__,
-                       err);
+               printk(KERN_WARNING "%s: device_register returned %i\n",
+                               __FUNCTION__, err);
                return err;
        }
 
-#ifdef CONFIG_PPC_PSERIES
-       probe_bus_pseries();
-#endif
-#ifdef CONFIG_PPC_ISERIES
-       probe_bus_iseries();
-#endif
-
        return 0;
 }
 
-__initcall(vio_bus_init);
-
 /* vio_dev refcount hit 0 */
 static void __devinit vio_dev_release(struct device *dev)
 {
-       DBGENTER();
-
-#ifdef CONFIG_PPC_PSERIES
-       /* XXX free TCE table */
-       of_node_put(dev->platform_data);
-#endif
+       if (vio_bus_ops.release_device)
+               vio_bus_ops.release_device(dev);
        kfree(to_vio_dev(dev));
 }
 
-#ifdef CONFIG_PPC_PSERIES
-static ssize_t viodev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct device_node *of_node = dev->platform_data;
-
-       return sprintf(buf, "%s\n", of_node->full_name);
-}
-DEVICE_ATTR(devspec, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_devspec, NULL);
-#endif
-
-static ssize_t viodev_show_name(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t viodev_show_name(struct device *dev,
+               struct device_attribute *attr, char *buf)
 {
        return sprintf(buf, "%s\n", to_vio_dev(dev)->name);
 }
 DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_name, NULL);
 
-static struct vio_dev * __devinit vio_register_device_common(
-               struct vio_dev *viodev, char *name, char *type,
-               uint32_t unit_address, struct iommu_table *iommu_table)
+struct vio_dev * __devinit vio_register_device(struct vio_dev *viodev)
 {
-       DBGENTER();
-
-       viodev->name = name;
-       viodev->type = type;
-       viodev->unit_address = unit_address;
-       viodev->iommu_table = iommu_table;
        /* init generic 'struct device' fields: */
        viodev->dev.parent = &vio_bus_device.dev;
        viodev->dev.bus = &vio_bus_type;
@@ -338,222 +181,15 @@ static struct vio_dev * __devinit vio_register_device_common(
        return viodev;
 }
 
-#ifdef CONFIG_PPC_PSERIES
-/**
- * vio_register_device_node: - Register a new vio device.
- * @of_node:   The OF node for this device.
- *
- * Creates and initializes a vio_dev structure from the data in
- * of_node (dev.platform_data) and adds it to the list of virtual devices.
- * Returns a pointer to the created vio_dev or NULL if node has
- * NULL device_type or compatible fields.
- */
-struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
-{
-       struct vio_dev *viodev;
-       unsigned int *unit_address;
-       unsigned int *irq_p;
-
-       DBGENTER();
-
-       /* we need the 'device_type' property, in order to match with drivers */
-       if ((NULL == of_node->type)) {
-               printk(KERN_WARNING
-                       "%s: node %s missing 'device_type'\n", __FUNCTION__,
-                       of_node->name ? of_node->name : "<unknown>");
-               return NULL;
-       }
-
-       unit_address = (unsigned int *)get_property(of_node, "reg", NULL);
-       if (!unit_address) {
-               printk(KERN_WARNING "%s: node %s missing 'reg'\n", __FUNCTION__,
-                       of_node->name ? of_node->name : "<unknown>");
-               return NULL;
-       }
-
-       /* allocate a vio_dev for this node */
-       viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
-       if (!viodev) {
-               return NULL;
-       }
-       memset(viodev, 0, sizeof(struct vio_dev));
-
-       viodev->dev.platform_data = of_node_get(of_node);
-
-       viodev->irq = NO_IRQ;
-       irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL);
-       if (irq_p) {
-               int virq = virt_irq_create_mapping(*irq_p);
-               if (virq == NO_IRQ) {
-                       printk(KERN_ERR "Unable to allocate interrupt "
-                              "number for %s\n", of_node->full_name);
-               } else
-                       viodev->irq = irq_offset_up(virq);
-       }
-
-       snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address);
-
-       /* register with generic device framework */
-       if (vio_register_device_common(viodev, of_node->name, of_node->type,
-                               *unit_address, vio_build_iommu_table(viodev))
-                       == NULL) {
-               /* XXX free TCE table */
-               kfree(viodev);
-               return NULL;
-       }
-       device_create_file(&viodev->dev, &dev_attr_devspec);
-
-       return viodev;
-}
-EXPORT_SYMBOL(vio_register_device_node);
-#endif
-
-#ifdef CONFIG_PPC_ISERIES
-/**
- * vio_register_device: - Register a new vio device.
- * @voidev:    The device to register.
- */
-static struct vio_dev *__init vio_register_device_iseries(char *type,
-               uint32_t unit_num)
-{
-       struct vio_dev *viodev;
-
-       DBGENTER();
-
-       /* allocate a vio_dev for this node */
-       viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
-       if (!viodev)
-               return NULL;
-       memset(viodev, 0, sizeof(struct vio_dev));
-
-       snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%s%d", type, unit_num);
-
-       return vio_register_device_common(viodev, viodev->dev.bus_id, type,
-                       unit_num, &vio_iommu_table);
-}
-#endif
-
 void __devinit vio_unregister_device(struct vio_dev *viodev)
 {
-       DBGENTER();
-#ifdef CONFIG_PPC_PSERIES
-       device_remove_file(&viodev->dev, &dev_attr_devspec);
-#endif
+       if (vio_bus_ops.unregister_device)
+               vio_bus_ops.unregister_device(viodev);
        device_remove_file(&viodev->dev, &dev_attr_name);
        device_unregister(&viodev->dev);
 }
 EXPORT_SYMBOL(vio_unregister_device);
 
-#ifdef CONFIG_PPC_PSERIES
-/**
- * vio_get_attribute: - get attribute for virtual device
- * @vdev:      The vio device to get property.
- * @which:     The property/attribute to be extracted.
- * @length:    Pointer to length of returned data size (unused if NULL).
- *
- * Calls prom.c's get_property() to return the value of the
- * attribute specified by the preprocessor constant @which
-*/
-const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length)
-{
-       return get_property(vdev->dev.platform_data, (char*)which, length);
-}
-EXPORT_SYMBOL(vio_get_attribute);
-
-/* vio_find_name() - internal because only vio.c knows how we formatted the
- * kobject name
- * XXX once vio_bus_type.devices is actually used as a kset in
- * drivers/base/bus.c, this function should be removed in favor of
- * "device_find(kobj_name, &vio_bus_type)"
- */
-static struct vio_dev *vio_find_name(const char *kobj_name)
-{
-       struct kobject *found;
-
-       found = kset_find_obj(&devices_subsys.kset, kobj_name);
-       if (!found)
-               return NULL;
-
-       return to_vio_dev(container_of(found, struct device, kobj));
-}
-
-/**
- * vio_find_node - find an already-registered vio_dev
- * @vnode: device_node of the virtual device we're looking for
- */
-struct vio_dev *vio_find_node(struct device_node *vnode)
-{
-       uint32_t *unit_address;
-       char kobj_name[BUS_ID_SIZE];
-
-       /* construct the kobject name from the device node */
-       unit_address = (uint32_t *)get_property(vnode, "reg", NULL);
-       if (!unit_address)
-               return NULL;
-       snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address);
-
-       return vio_find_name(kobj_name);
-}
-EXPORT_SYMBOL(vio_find_node);
-
-/**
- * vio_build_iommu_table: - gets the dma information from OF and builds the TCE tree.
- * @dev: the virtual device.
- *
- * Returns a pointer to the built tce tree, or NULL if it can't
- * find property.
-*/
-static struct iommu_table * vio_build_iommu_table(struct vio_dev *dev)
-{
-       unsigned int *dma_window;
-       struct iommu_table *newTceTable;
-       unsigned long offset;
-       int dma_window_property_size;
-
-       dma_window = (unsigned int *) get_property(dev->dev.platform_data, "ibm,my-dma-window", &dma_window_property_size);
-       if(!dma_window) {
-               return NULL;
-       }
-
-       newTceTable = (struct iommu_table *) kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
-
-       /*  There should be some code to extract the phys-encoded offset
-               using prom_n_addr_cells(). However, according to a comment
-               on earlier versions, it's always zero, so we don't bother */
-       offset = dma_window[1] >>  PAGE_SHIFT;
-
-       /* TCE table size - measured in tce entries */
-       newTceTable->it_size            = dma_window[4] >> PAGE_SHIFT;
-       /* offset for VIO should always be 0 */
-       newTceTable->it_offset          = offset;
-       newTceTable->it_busno           = 0;
-       newTceTable->it_index           = (unsigned long)dma_window[0];
-       newTceTable->it_type            = TCE_VB;
-
-       return iommu_init_table(newTceTable);
-}
-
-int vio_enable_interrupts(struct vio_dev *dev)
-{
-       int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE);
-       if (rc != H_Success) {
-               printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc);
-       }
-       return rc;
-}
-EXPORT_SYMBOL(vio_enable_interrupts);
-
-int vio_disable_interrupts(struct vio_dev *dev)
-{
-       int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE);
-       if (rc != H_Success) {
-               printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc);
-       }
-       return rc;
-}
-EXPORT_SYMBOL(vio_disable_interrupts);
-#endif
-
 static dma_addr_t vio_map_single(struct device *dev, void *vaddr,
                          size_t size, enum dma_data_direction direction)
 {
@@ -615,18 +251,8 @@ static int vio_bus_match(struct device *dev, struct device_driver *drv)
        const struct vio_dev *vio_dev = to_vio_dev(dev);
        struct vio_driver *vio_drv = to_vio_driver(drv);
        const struct vio_device_id *ids = vio_drv->id_table;
-       const struct vio_device_id *found_id;
-
-       DBGENTER();
 
-       if (!ids)
-               return 0;
-
-       found_id = vio_match_device(ids, vio_dev);
-       if (found_id)
-               return 1;
-
-       return 0;
+       return (ids != NULL) && (vio_match_device(ids, vio_dev) != NULL);
 }
 
 struct bus_type vio_bus_type = {
index 4103cc13f8d62e93eb8d526f3ffa6c061129a52d..0306510bc4ffb00aec0997129c152f2e512890fa 100644 (file)
@@ -15,6 +15,7 @@ SECTIONS
        *(.text .text.*)
        SCHED_TEXT
        LOCK_TEXT
+       KPROBES_TEXT
        *(.fixup)
        . = ALIGN(4096);
        _etext = .;
index 20b0f37e8bf8fbe3ac28c2f0113a97b6aa951675..772f0714a5b7d4be9231b362650c920c1c70cb9c 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/interrupt.h>
 #include <linux/smp_lock.h>
 #include <linux/module.h>
+#include <linux/kprobes.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -84,8 +85,8 @@ static int store_updates_sp(struct pt_regs *regs)
  * The return value is 0 if the fault was handled, or the signal
  * number if this is a kernel fault that can't be handled here.
  */
-int do_page_fault(struct pt_regs *regs, unsigned long address,
-                 unsigned long error_code)
+int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
+                           unsigned long error_code)
 {
        struct vm_area_struct * vma;
        struct mm_struct *mm = current->mm;
index fbff24827ae78d83809fc078900ed4299e16ab86..35eb49e1b8908d4c6c94580f45561f97e438c422 100644 (file)
@@ -128,13 +128,11 @@ _GLOBAL(__hash_page)
        /* We eventually do the icache sync here (maybe inline that
         * code rather than call a C function...) 
         */
-BEGIN_FTR_SECTION
 BEGIN_FTR_SECTION
        mr      r4,r30
        mr      r5,r7
        bl      .hash_page_do_lazy_icache
-END_FTR_SECTION_IFSET(CPU_FTR_NOEXECUTE)
-END_FTR_SECTION_IFCLR(CPU_FTR_COHERENT_ICACHE)
+END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
 
        /* At this point, r3 contains new PP bits, save them in
         * place of "access" in the param area (sic)
index a6abd3a979bf5be80412ed4c78f54e08074e9d56..7626bb59954d43e6fa6b7437aff89c68cf2fe5b2 100644 (file)
@@ -51,7 +51,6 @@ long native_hpte_insert(unsigned long hpte_group, unsigned long va,
                        unsigned long prpn, unsigned long vflags,
                        unsigned long rflags)
 {
-       unsigned long arpn = physRpn_to_absRpn(prpn);
        hpte_t *hptep = htab_address + hpte_group;
        unsigned long hpte_v, hpte_r;
        int i;
@@ -74,7 +73,7 @@ long native_hpte_insert(unsigned long hpte_group, unsigned long va,
        hpte_v = (va >> 23) << HPTE_V_AVPN_SHIFT | vflags | HPTE_V_VALID;
        if (vflags & HPTE_V_LARGE)
                va &= ~(1UL << HPTE_V_AVPN_SHIFT);
-       hpte_r = (arpn << HPTE_R_RPN_SHIFT) | rflags;
+       hpte_r = (prpn << HPTE_R_RPN_SHIFT) | rflags;
 
        hptep->r = hpte_r;
        /* Guarantee the second dword is visible before the valid bit */
index 623b5d130c3192766145a12ad45c5ef3f95541ad..09475c8edf7caea33dfb37f641c13879b8fac666 100644 (file)
@@ -210,7 +210,7 @@ void __init htab_initialize(void)
 
        /* create bolted the linear mapping in the hash table */
        for (i=0; i < lmb.memory.cnt; i++) {
-               base = lmb.memory.region[i].physbase + KERNELBASE;
+               base = lmb.memory.region[i].base + KERNELBASE;
                size = lmb.memory.region[i].size;
 
                DBG("creating mapping for region: %lx : %lx\n", base, size);
@@ -302,7 +302,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
        int local = 0;
        cpumask_t tmp;
 
-       if ((ea & ~REGION_MASK) > EADDR_MASK)
+       if ((ea & ~REGION_MASK) >= PGTABLE_RANGE)
                return 1;
 
        switch (REGION_ID(ea)) {
index f9524602818dad2aaaaad90fba4a2baf42be161b..338771ec70d7622775190417f69085496ac2e209 100644 (file)
 
 #include <linux/sysctl.h>
 
-#define        HUGEPGDIR_SHIFT         (HPAGE_SHIFT + PAGE_SHIFT - 3)
-#define HUGEPGDIR_SIZE         (1UL << HUGEPGDIR_SHIFT)
-#define HUGEPGDIR_MASK         (~(HUGEPGDIR_SIZE-1))
+#define NUM_LOW_AREAS  (0x100000000UL >> SID_SHIFT)
+#define NUM_HIGH_AREAS (PGTABLE_RANGE >> HTLB_AREA_SHIFT)
 
-#define HUGEPTE_INDEX_SIZE     9
-#define HUGEPGD_INDEX_SIZE     10
-
-#define PTRS_PER_HUGEPTE       (1 << HUGEPTE_INDEX_SIZE)
-#define PTRS_PER_HUGEPGD       (1 << HUGEPGD_INDEX_SIZE)
-
-static inline int hugepgd_index(unsigned long addr)
-{
-       return (addr & ~REGION_MASK) >> HUGEPGDIR_SHIFT;
-}
-
-static pud_t *hugepgd_offset(struct mm_struct *mm, unsigned long addr)
+/* Modelled after find_linux_pte() */
+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
 {
-       int index;
+       pgd_t *pg;
+       pud_t *pu;
+       pmd_t *pm;
+       pte_t *pt;
 
-       if (! mm->context.huge_pgdir)
-               return NULL;
+       BUG_ON(! in_hugepage_area(mm->context, addr));
 
+       addr &= HPAGE_MASK;
+
+       pg = pgd_offset(mm, addr);
+       if (!pgd_none(*pg)) {
+               pu = pud_offset(pg, addr);
+               if (!pud_none(*pu)) {
+                       pm = pmd_offset(pu, addr);
+                       pt = (pte_t *)pm;
+                       BUG_ON(!pmd_none(*pm)
+                              && !(pte_present(*pt) && pte_huge(*pt)));
+                       return pt;
+               }
+       }
 
-       index = hugepgd_index(addr);
-       BUG_ON(index >= PTRS_PER_HUGEPGD);
-       return (pud_t *)(mm->context.huge_pgdir + index);
+       return NULL;
 }
 
-static inline pte_t *hugepte_offset(pud_t *dir, unsigned long addr)
+pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
 {
-       int index;
-
-       if (pud_none(*dir))
-               return NULL;
+       pgd_t *pg;
+       pud_t *pu;
+       pmd_t *pm;
+       pte_t *pt;
 
-       index = (addr >> HPAGE_SHIFT) % PTRS_PER_HUGEPTE;
-       return (pte_t *)pud_page(*dir) + index;
-}
-
-static pud_t *hugepgd_alloc(struct mm_struct *mm, unsigned long addr)
-{
        BUG_ON(! in_hugepage_area(mm->context, addr));
 
-       if (! mm->context.huge_pgdir) {
-               pgd_t *new;
-               spin_unlock(&mm->page_table_lock);
-               /* Don't use pgd_alloc(), because we want __GFP_REPEAT */
-               new = kmem_cache_alloc(zero_cache, GFP_KERNEL | __GFP_REPEAT);
-               BUG_ON(memcmp(new, empty_zero_page, PAGE_SIZE));
-               spin_lock(&mm->page_table_lock);
+       addr &= HPAGE_MASK;
 
-               /*
-                * Because we dropped the lock, we should re-check the
-                * entry, as somebody else could have populated it..
-                */
-               if (mm->context.huge_pgdir)
-                       pgd_free(new);
-               else
-                       mm->context.huge_pgdir = new;
-       }
-       return hugepgd_offset(mm, addr);
-}
+       pg = pgd_offset(mm, addr);
+       pu = pud_alloc(mm, pg, addr);
 
-static pte_t *hugepte_alloc(struct mm_struct *mm, pud_t *dir, unsigned long addr)
-{
-       if (! pud_present(*dir)) {
-               pte_t *new;
-
-               spin_unlock(&mm->page_table_lock);
-               new = kmem_cache_alloc(zero_cache, GFP_KERNEL | __GFP_REPEAT);
-               BUG_ON(memcmp(new, empty_zero_page, PAGE_SIZE));
-               spin_lock(&mm->page_table_lock);
-               /*
-                * Because we dropped the lock, we should re-check the
-                * entry, as somebody else could have populated it..
-                */
-               if (pud_present(*dir)) {
-                       if (new)
-                               kmem_cache_free(zero_cache, new);
-               } else {
-                       struct page *ptepage;
-
-                       if (! new)
-                               return NULL;
-                       ptepage = virt_to_page(new);
-                       ptepage->mapping = (void *) mm;
-                       ptepage->index = addr & HUGEPGDIR_MASK;
-                       pud_populate(mm, dir, new);
+       if (pu) {
+               pm = pmd_alloc(mm, pu, addr);
+               if (pm) {
+                       pt = (pte_t *)pm;
+                       BUG_ON(!pmd_none(*pm)
+                              && !(pte_present(*pt) && pte_huge(*pt)));
+                       return pt;
                }
        }
 
-       return hugepte_offset(dir, addr);
+       return NULL;
 }
 
-pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
-{
-       pud_t *pud;
+#define HUGEPTE_BATCH_SIZE     (HPAGE_SIZE / PMD_SIZE)
 
-       BUG_ON(! in_hugepage_area(mm->context, addr));
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+                    pte_t *ptep, pte_t pte)
+{
+       int i;
 
-       pud = hugepgd_offset(mm, addr);
-       if (! pud)
-               return NULL;
+       if (pte_present(*ptep)) {
+               pte_clear(mm, addr, ptep);
+               flush_tlb_pending();
+       }
 
-       return hugepte_offset(pud, addr);
+       for (i = 0; i < HUGEPTE_BATCH_SIZE; i++) {
+               *ptep = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
+               ptep++;
+       }
 }
 
-pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+                             pte_t *ptep)
 {
-       pud_t *pud;
+       unsigned long old = pte_update(ptep, ~0UL);
+       int i;
 
-       BUG_ON(! in_hugepage_area(mm->context, addr));
+       if (old & _PAGE_HASHPTE)
+               hpte_update(mm, addr, old, 0);
 
-       pud = hugepgd_alloc(mm, addr);
-       if (! pud)
-               return NULL;
+       for (i = 1; i < HUGEPTE_BATCH_SIZE; i++)
+               ptep[i] = __pte(0);
 
-       return hugepte_alloc(mm, pud, addr);
+       return __pte(old);
 }
 
 /*
@@ -162,29 +132,53 @@ int is_aligned_hugepage_range(unsigned long addr, unsigned long len)
        return 0;
 }
 
-static void flush_segments(void *parm)
+static void flush_low_segments(void *parm)
 {
-       u16 segs = (unsigned long) parm;
+       u16 areas = (unsigned long) parm;
        unsigned long i;
 
        asm volatile("isync" : : : "memory");
 
-       for (i = 0; i < 16; i++) {
-               if (! (segs & (1U << i)))
+       BUILD_BUG_ON((sizeof(areas)*8) != NUM_LOW_AREAS);
+
+       for (i = 0; i < NUM_LOW_AREAS; i++) {
+               if (! (areas & (1U << i)))
                        continue;
-               asm volatile("slbie %0" : : "r" (i << SID_SHIFT));
+               asm volatile("slbie %0"
+                            : : "r" ((i << SID_SHIFT) | SLBIE_C));
        }
 
        asm volatile("isync" : : : "memory");
 }
 
-static int prepare_low_seg_for_htlb(struct mm_struct *mm, unsigned long seg)
+static void flush_high_segments(void *parm)
 {
-       unsigned long start = seg << SID_SHIFT;
-       unsigned long end = (seg+1) << SID_SHIFT;
+       u16 areas = (unsigned long) parm;
+       unsigned long i, j;
+
+       asm volatile("isync" : : : "memory");
+
+       BUILD_BUG_ON((sizeof(areas)*8) != NUM_HIGH_AREAS);
+
+       for (i = 0; i < NUM_HIGH_AREAS; i++) {
+               if (! (areas & (1U << i)))
+                       continue;
+               for (j = 0; j < (1UL << (HTLB_AREA_SHIFT-SID_SHIFT)); j++)
+                       asm volatile("slbie %0"
+                                    :: "r" (((i << HTLB_AREA_SHIFT)
+                                            + (j << SID_SHIFT)) | SLBIE_C));
+       }
+
+       asm volatile("isync" : : : "memory");
+}
+
+static int prepare_low_area_for_htlb(struct mm_struct *mm, unsigned long area)
+{
+       unsigned long start = area << SID_SHIFT;
+       unsigned long end = (area+1) << SID_SHIFT;
        struct vm_area_struct *vma;
 
-       BUG_ON(seg >= 16);
+       BUG_ON(area >= NUM_LOW_AREAS);
 
        /* Check no VMAs are in the region */
        vma = find_vma(mm, start);
@@ -194,20 +188,39 @@ static int prepare_low_seg_for_htlb(struct mm_struct *mm, unsigned long seg)
        return 0;
 }
 
-static int open_low_hpage_segs(struct mm_struct *mm, u16 newsegs)
+static int prepare_high_area_for_htlb(struct mm_struct *mm, unsigned long area)
+{
+       unsigned long start = area << HTLB_AREA_SHIFT;
+       unsigned long end = (area+1) << HTLB_AREA_SHIFT;
+       struct vm_area_struct *vma;
+
+       BUG_ON(area >= NUM_HIGH_AREAS);
+
+       /* Check no VMAs are in the region */
+       vma = find_vma(mm, start);
+       if (vma && (vma->vm_start < end))
+               return -EBUSY;
+
+       return 0;
+}
+
+static int open_low_hpage_areas(struct mm_struct *mm, u16 newareas)
 {
        unsigned long i;
 
-       newsegs &= ~(mm->context.htlb_segs);
-       if (! newsegs)
+       BUILD_BUG_ON((sizeof(newareas)*8) != NUM_LOW_AREAS);
+       BUILD_BUG_ON((sizeof(mm->context.low_htlb_areas)*8) != NUM_LOW_AREAS);
+
+       newareas &= ~(mm->context.low_htlb_areas);
+       if (! newareas)
                return 0; /* The segments we want are already open */
 
-       for (i = 0; i < 16; i++)
-               if ((1 << i) & newsegs)
-                       if (prepare_low_seg_for_htlb(mm, i) != 0)
+       for (i = 0; i < NUM_LOW_AREAS; i++)
+               if ((1 << i) & newareas)
+                       if (prepare_low_area_for_htlb(mm, i) != 0)
                                return -EBUSY;
 
-       mm->context.htlb_segs |= newsegs;
+       mm->context.low_htlb_areas |= newareas;
 
        /* update the paca copy of the context struct */
        get_paca()->context = mm->context;
@@ -215,29 +228,63 @@ static int open_low_hpage_segs(struct mm_struct *mm, u16 newsegs)
        /* the context change must make it to memory before the flush,
         * so that further SLB misses do the right thing. */
        mb();
-       on_each_cpu(flush_segments, (void *)(unsigned long)newsegs, 0, 1);
+       on_each_cpu(flush_low_segments, (void *)(unsigned long)newareas, 0, 1);
+
+       return 0;
+}
+
+static int open_high_hpage_areas(struct mm_struct *mm, u16 newareas)
+{
+       unsigned long i;
+
+       BUILD_BUG_ON((sizeof(newareas)*8) != NUM_HIGH_AREAS);
+       BUILD_BUG_ON((sizeof(mm->context.high_htlb_areas)*8)
+                    != NUM_HIGH_AREAS);
+
+       newareas &= ~(mm->context.high_htlb_areas);
+       if (! newareas)
+               return 0; /* The areas we want are already open */
+
+       for (i = 0; i < NUM_HIGH_AREAS; i++)
+               if ((1 << i) & newareas)
+                       if (prepare_high_area_for_htlb(mm, i) != 0)
+                               return -EBUSY;
+
+       mm->context.high_htlb_areas |= newareas;
+
+       /* update the paca copy of the context struct */
+       get_paca()->context = mm->context;
+
+       /* the context change must make it to memory before the flush,
+        * so that further SLB misses do the right thing. */
+       mb();
+       on_each_cpu(flush_high_segments, (void *)(unsigned long)newareas, 0, 1);
 
        return 0;
 }
 
 int prepare_hugepage_range(unsigned long addr, unsigned long len)
 {
-       if (within_hugepage_high_range(addr, len))
-               return 0;
-       else if ((addr < 0x100000000UL) && ((addr+len) < 0x100000000UL)) {
-               int err;
-               /* Yes, we need both tests, in case addr+len overflows
-                * 64-bit arithmetic */
-               err = open_low_hpage_segs(current->mm,
+       int err;
+
+       if ( (addr+len) < addr )
+               return -EINVAL;
+
+       if ((addr + len) < 0x100000000UL)
+               err = open_low_hpage_areas(current->mm,
                                          LOW_ESID_MASK(addr, len));
-               if (err)
-                       printk(KERN_DEBUG "prepare_hugepage_range(%lx, %lx)"
-                              " failed (segs: 0x%04hx)\n", addr, len,
-                              LOW_ESID_MASK(addr, len));
+       else
+               err = open_high_hpage_areas(current->mm,
+                                           HTLB_AREA_MASK(addr, len));
+       if (err) {
+               printk(KERN_DEBUG "prepare_hugepage_range(%lx, %lx)"
+                      " failed (lowmask: 0x%04hx, highmask: 0x%04hx)\n",
+                      addr, len,
+                      LOW_ESID_MASK(addr, len), HTLB_AREA_MASK(addr, len));
                return err;
        }
 
-       return -EINVAL;
+       return 0;
 }
 
 struct page *
@@ -309,8 +356,8 @@ full_search:
                        vma = find_vma(mm, addr);
                        continue;
                }
-               if (touches_hugepage_high_range(addr, len)) {
-                       addr = TASK_HPAGE_END;
+               if (touches_hugepage_high_range(mm, addr, len)) {
+                       addr = ALIGN(addr+1, 1UL<<HTLB_AREA_SHIFT);
                        vma = find_vma(mm, addr);
                        continue;
                }
@@ -389,8 +436,9 @@ hugepage_recheck:
                if (touches_hugepage_low_range(mm, addr, len)) {
                        addr = (addr & ((~0) << SID_SHIFT)) - len;
                        goto hugepage_recheck;
-               } else if (touches_hugepage_high_range(addr, len)) {
-                       addr = TASK_HPAGE_BASE - len;
+               } else if (touches_hugepage_high_range(mm, addr, len)) {
+                       addr = (addr & ((~0UL) << HTLB_AREA_SHIFT)) - len;
+                       goto hugepage_recheck;
                }
 
                /*
@@ -481,23 +529,28 @@ static unsigned long htlb_get_low_area(unsigned long len, u16 segmask)
        return -ENOMEM;
 }
 
-static unsigned long htlb_get_high_area(unsigned long len)
+static unsigned long htlb_get_high_area(unsigned long len, u16 areamask)
 {
-       unsigned long addr = TASK_HPAGE_BASE;
+       unsigned long addr = 0x100000000UL;
        struct vm_area_struct *vma;
 
        vma = find_vma(current->mm, addr);
-       for (vma = find_vma(current->mm, addr);
-            addr + len <= TASK_HPAGE_END;
-            vma = vma->vm_next) {
+       while (addr + len <= TASK_SIZE_USER64) {
                BUG_ON(vma && (addr >= vma->vm_end)); /* invariant */
-               BUG_ON(! within_hugepage_high_range(addr, len));
+
+               if (! __within_hugepage_high_range(addr, len, areamask)) {
+                       addr = ALIGN(addr+1, 1UL<<HTLB_AREA_SHIFT);
+                       vma = find_vma(current->mm, addr);
+                       continue;
+               }
 
                if (!vma || (addr + len) <= vma->vm_start)
                        return addr;
                addr = ALIGN(vma->vm_end, HPAGE_SIZE);
-               /* Because we're in a hugepage region, this alignment
-                * should not skip us over any VMAs */
+               /* Depending on segmask this might not be a confirmed
+                * hugepage region, so the ALIGN could have skipped
+                * some VMAs */
+               vma = find_vma(current->mm, addr);
        }
 
        return -ENOMEM;
@@ -507,6 +560,9 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
                                        unsigned long len, unsigned long pgoff,
                                        unsigned long flags)
 {
+       int lastshift;
+       u16 areamask, curareas;
+
        if (len & ~HPAGE_MASK)
                return -EINVAL;
 
@@ -514,67 +570,49 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
                return -EINVAL;
 
        if (test_thread_flag(TIF_32BIT)) {
-               int lastshift = 0;
-               u16 segmask, cursegs = current->mm->context.htlb_segs;
+               curareas = current->mm->context.low_htlb_areas;
 
                /* First see if we can do the mapping in the existing
-                * low hpage segments */
-               addr = htlb_get_low_area(len, cursegs);
+                * low areas */
+               addr = htlb_get_low_area(len, curareas);
                if (addr != -ENOMEM)
                        return addr;
 
-               for (segmask = LOW_ESID_MASK(0x100000000UL-len, len);
-                    ! lastshift; segmask >>=1) {
-                       if (segmask & 1)
+               lastshift = 0;
+               for (areamask = LOW_ESID_MASK(0x100000000UL-len, len);
+                    ! lastshift; areamask >>=1) {
+                       if (areamask & 1)
                                lastshift = 1;
 
-                       addr = htlb_get_low_area(len, cursegs | segmask);
+                       addr = htlb_get_low_area(len, curareas | areamask);
                        if ((addr != -ENOMEM)
-                           && open_low_hpage_segs(current->mm, segmask) == 0)
+                           && open_low_hpage_areas(current->mm, areamask) == 0)
                                return addr;
                }
-               printk(KERN_DEBUG "hugetlb_get_unmapped_area() unable to open"
-                      " enough segments\n");
-               return -ENOMEM;
        } else {
-               return htlb_get_high_area(len);
-       }
-}
-
-void hugetlb_mm_free_pgd(struct mm_struct *mm)
-{
-       int i;
-       pgd_t *pgdir;
-
-       spin_lock(&mm->page_table_lock);
-
-       pgdir = mm->context.huge_pgdir;
-       if (! pgdir)
-               goto out;
-
-       mm->context.huge_pgdir = NULL;
+               curareas = current->mm->context.high_htlb_areas;
 
-       /* cleanup any hugepte pages leftover */
-       for (i = 0; i < PTRS_PER_HUGEPGD; i++) {
-               pud_t *pud = (pud_t *)(pgdir + i);
-
-               if (! pud_none(*pud)) {
-                       pte_t *pte = (pte_t *)pud_page(*pud);
-                       struct page *ptepage = virt_to_page(pte);
+               /* First see if we can do the mapping in the existing
+                * high areas */
+               addr = htlb_get_high_area(len, curareas);
+               if (addr != -ENOMEM)
+                       return addr;
 
-                       ptepage->mapping = NULL;
+               lastshift = 0;
+               for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len);
+                    ! lastshift; areamask >>=1) {
+                       if (areamask & 1)
+                               lastshift = 1;
 
-                       BUG_ON(memcmp(pte, empty_zero_page, PAGE_SIZE));
-                       kmem_cache_free(zero_cache, pte);
+                       addr = htlb_get_high_area(len, curareas | areamask);
+                       if ((addr != -ENOMEM)
+                           && open_high_hpage_areas(current->mm, areamask) == 0)
+                               return addr;
                }
-               pud_clear(pud);
        }
-
-       BUG_ON(memcmp(pgdir, empty_zero_page, PAGE_SIZE));
-       kmem_cache_free(zero_cache, pgdir);
-
- out:
-       spin_unlock(&mm->page_table_lock);
+       printk(KERN_DEBUG "hugetlb_get_unmapped_area() unable to open"
+              " enough areas\n");
+       return -ENOMEM;
 }
 
 int hash_huge_page(struct mm_struct *mm, unsigned long access,
index b6e75b891ac0fef5a2aa9dea4152b2c2ea2b998b..c65b87b927567cd1a3dd9c30275a713006c34661 100644 (file)
@@ -31,7 +31,7 @@ static int get_free_im_addr(unsigned long size, unsigned long *im_addr)
                        break;
                if ((unsigned long)tmp->addr >= ioremap_bot)
                        addr = tmp->size + (unsigned long) tmp->addr;
-               if (addr > IMALLOC_END-size) 
+               if (addr >= IMALLOC_END-size)
                        return 1;
        }
        *im_addr = addr;
index e58a24d42879da92448a94a0b84c6f2dec1a682d..a14ab87df49114dbc9d02566b5014d4e91d0b939 100644 (file)
@@ -42,7 +42,6 @@
 
 #include <asm/pgalloc.h>
 #include <asm/page.h>
-#include <asm/abs_addr.h>
 #include <asm/prom.h>
 #include <asm/lmb.h>
 #include <asm/rtas.h>
 #include <asm/vdso.h>
 #include <asm/imalloc.h>
 
+#if PGTABLE_RANGE > USER_VSID_RANGE
+#warning Limited user VSID range means pagetable space is wasted
+#endif
+
+#if (TASK_SIZE_USER64 < PGTABLE_RANGE) && (TASK_SIZE_USER64 < USER_VSID_RANGE)
+#warning TASK_SIZE is smaller than it needs to be.
+#endif
+
 int mem_init_done;
 unsigned long ioremap_bot = IMALLOC_BASE;
 static unsigned long phbs_io_bot = PHBS_IO_BASE;
@@ -159,7 +166,6 @@ static int map_io_page(unsigned long ea, unsigned long pa, int flags)
                ptep = pte_alloc_kernel(&init_mm, pmdp, ea);
                if (!ptep)
                        return -ENOMEM;
-               pa = abs_to_phys(pa);
                set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT,
                                                          __pgprot(flags)));
                spin_unlock(&init_mm.page_table_lock);
@@ -226,7 +232,7 @@ void __iomem * __ioremap(unsigned long addr, unsigned long size,
         * Before that, we map using addresses going
         * up from ioremap_bot.  imalloc will use
         * the addresses from ioremap_bot through
-        * IMALLOC_END (0xE000001fffffffff)
+        * IMALLOC_END
         * 
         */
        pa = addr & PAGE_MASK;
@@ -386,6 +392,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);
                ClearPageReserved(virt_to_page(addr));
                set_page_count(virt_to_page(addr), 1);
                free_page(addr);
@@ -417,12 +424,6 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
        int index;
        int err;
 
-#ifdef CONFIG_HUGETLB_PAGE
-       /* We leave htlb_segs as it was, but for a fork, we need to
-        * clear the huge_pgdir. */
-       mm->context.huge_pgdir = NULL;
-#endif
-
 again:
        if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL))
                return -ENOMEM;
@@ -453,8 +454,6 @@ void destroy_context(struct mm_struct *mm)
        spin_unlock(&mmu_context_lock);
 
        mm->context.id = NO_CONTEXT;
-
-       hugetlb_mm_free_pgd(mm);
 }
 
 /*
@@ -484,9 +483,9 @@ void __init mm_init_ppc64(void)
        for (i = 1; i < lmb.memory.cnt; i++) {
                unsigned long base, prevbase, prevsize;
 
-               prevbase = lmb.memory.region[i-1].physbase;
+               prevbase = lmb.memory.region[i-1].base;
                prevsize = lmb.memory.region[i-1].size;
-               base = lmb.memory.region[i].physbase;
+               base = lmb.memory.region[i].base;
                if (base > (prevbase + prevsize)) {
                        io_hole_start = prevbase + prevsize;
                        io_hole_size = base  - (prevbase + prevsize);
@@ -513,11 +512,8 @@ int page_is_ram(unsigned long pfn)
        for (i=0; i < lmb.memory.cnt; i++) {
                unsigned long base;
 
-#ifdef CONFIG_MSCHUNKS
-               base = lmb.memory.region[i].physbase;
-#else
                base = lmb.memory.region[i].base;
-#endif
+
                if ((paddr >= base) &&
                        (paddr < (base + lmb.memory.region[i].size))) {
                        return 1;
@@ -547,7 +543,7 @@ void __init do_init_bootmem(void)
         */
        bootmap_pages = bootmem_bootmap_pages(total_pages);
 
-       start = abs_to_phys(lmb_alloc(bootmap_pages<<PAGE_SHIFT, PAGE_SIZE));
+       start = lmb_alloc(bootmap_pages<<PAGE_SHIFT, PAGE_SIZE);
        BUG_ON(!start);
 
        boot_mapsize = init_bootmem(start >> PAGE_SHIFT, total_pages);
@@ -557,27 +553,18 @@ void __init do_init_bootmem(void)
        /* Add all physical memory to the bootmem map, mark each area
         * present.
         */
-       for (i=0; i < lmb.memory.cnt; i++) {
-               unsigned long physbase, size;
-               unsigned long start_pfn, end_pfn;
-
-               physbase = lmb.memory.region[i].physbase;
-               size = lmb.memory.region[i].size;
-
-               start_pfn = physbase >> PAGE_SHIFT;
-               end_pfn = start_pfn + (size >> PAGE_SHIFT);
-               memory_present(0, start_pfn, end_pfn);
-
-               free_bootmem(physbase, size);
-       }
+       for (i=0; i < lmb.memory.cnt; i++)
+               free_bootmem(lmb_start_pfn(&lmb.memory, i),
+                            lmb_size_bytes(&lmb.memory, i));
 
        /* reserve the sections we're already using */
-       for (i=0; i < lmb.reserved.cnt; i++) {
-               unsigned long physbase = lmb.reserved.region[i].physbase;
-               unsigned long size = lmb.reserved.region[i].size;
+       for (i=0; i < lmb.reserved.cnt; i++)
+               reserve_bootmem(lmb_start_pfn(&lmb.reserved, i),
+                               lmb_size_bytes(&lmb.reserved, i));
 
-               reserve_bootmem(physbase, size);
-       }
+       for (i=0; i < lmb.memory.cnt; i++)
+               memory_present(0, lmb_start_pfn(&lmb.memory, i),
+                              lmb_end_pfn(&lmb.memory, i));
 }
 
 /*
@@ -615,10 +602,10 @@ static int __init setup_kcore(void)
        int i;
 
        for (i=0; i < lmb.memory.cnt; i++) {
-               unsigned long physbase, size;
+               unsigned long base, size;
                struct kcore_list *kcore_mem;
 
-               physbase = lmb.memory.region[i].physbase;
+               base = lmb.memory.region[i].base;
                size = lmb.memory.region[i].size;
 
                /* GFP_ATOMIC to avoid might_sleep warnings during boot */
@@ -626,7 +613,7 @@ static int __init setup_kcore(void)
                if (!kcore_mem)
                        panic("mem_init: kmalloc failed\n");
 
-               kclist_add(kcore_mem, __va(physbase), size);
+               kclist_add(kcore_mem, __va(base), size);
        }
 
        kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START);
@@ -686,9 +673,6 @@ void __init mem_init(void)
 
        mem_init_done = 1;
 
-#ifdef CONFIG_PPC_ISERIES
-       iommu_vio_init();
-#endif
        /* Initialize the vDSO */
        vdso_init();
 }
@@ -833,23 +817,43 @@ void __iomem * reserve_phb_iospace(unsigned long size)
        return virt_addr;
 }
 
-kmem_cache_t *zero_cache;
-
-static void zero_ctor(void *pte, kmem_cache_t *cache, unsigned long flags)
+static void zero_ctor(void *addr, kmem_cache_t *cache, unsigned long flags)
 {
-       memset(pte, 0, PAGE_SIZE);
+       memset(addr, 0, kmem_cache_size(cache));
 }
 
+static const int pgtable_cache_size[2] = {
+       PTE_TABLE_SIZE, PMD_TABLE_SIZE
+};
+static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = {
+       "pgd_pte_cache", "pud_pmd_cache",
+};
+
+kmem_cache_t *pgtable_cache[ARRAY_SIZE(pgtable_cache_size)];
+
 void pgtable_cache_init(void)
 {
-       zero_cache = kmem_cache_create("zero",
-                               PAGE_SIZE,
-                               0,
-                               SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN,
-                               zero_ctor,
-                               NULL);
-       if (!zero_cache)
-               panic("pgtable_cache_init(): could not create zero_cache!\n");
+       int i;
+
+       BUILD_BUG_ON(PTE_TABLE_SIZE != pgtable_cache_size[PTE_CACHE_NUM]);
+       BUILD_BUG_ON(PMD_TABLE_SIZE != pgtable_cache_size[PMD_CACHE_NUM]);
+       BUILD_BUG_ON(PUD_TABLE_SIZE != pgtable_cache_size[PUD_CACHE_NUM]);
+       BUILD_BUG_ON(PGD_TABLE_SIZE != pgtable_cache_size[PGD_CACHE_NUM]);
+
+       for (i = 0; i < ARRAY_SIZE(pgtable_cache_size); i++) {
+               int size = pgtable_cache_size[i];
+               const char *name = pgtable_cache_name[i];
+
+               pgtable_cache[i] = kmem_cache_create(name,
+                                                    size, size,
+                                                    SLAB_HWCACHE_ALIGN
+                                                    | SLAB_MUST_HWCACHE_ALIGN,
+                                                    zero_ctor,
+                                                    NULL);
+               if (! pgtable_cache[i])
+                       panic("pgtable_cache_init(): could not create %s!\n",
+                             name);
+       }
 }
 
 pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
index 0b191f2de0163b64d20b302a92f5047aee23ed8e..cb864b8f27505abee687702fca4833dbf9d6016b 100644 (file)
@@ -440,8 +440,6 @@ new_range:
                for (i = start ; i < (start+size); i += MEMORY_INCREMENT)
                        numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] =
                                numa_domain;
-               memory_present(numa_domain, start >> PAGE_SHIFT,
-                                               (start + size) >> PAGE_SHIFT);
 
                if (--ranges)
                        goto new_range;
@@ -483,7 +481,6 @@ static void __init setup_nonnuma(void)
 
        for (i = 0 ; i < top_of_ram; i += MEMORY_INCREMENT)
                numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] = 0;
-       memory_present(0, 0, init_node_data[0].node_end_pfn);
 }
 
 static void __init dump_numa_topology(void)
@@ -671,7 +668,7 @@ new_range:
                 * Mark reserved regions on this node
                 */
                for (i = 0; i < lmb.reserved.cnt; i++) {
-                       unsigned long physbase = lmb.reserved.region[i].physbase;
+                       unsigned long physbase = lmb.reserved.region[i].base;
                        unsigned long size = lmb.reserved.region[i].size;
 
                        if (pa_to_nid(physbase) != nid &&
@@ -695,6 +692,46 @@ new_range:
                                                     size);
                        }
                }
+               /*
+                * This loop may look famaliar, but we have to do it again
+                * after marking our reserved memory to mark memory present
+                * for sparsemem.
+                */
+               addr_cells = get_mem_addr_cells();
+               size_cells = get_mem_size_cells();
+               memory = NULL;
+               while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
+                       unsigned long mem_start, mem_size;
+                       int numa_domain, ranges;
+                       unsigned int *memcell_buf;
+                       unsigned int len;
+
+                       memcell_buf = (unsigned int *)get_property(memory, "reg", &len);
+                       if (!memcell_buf || len <= 0)
+                               continue;
+
+                       ranges = memory->n_addrs;       /* ranges in cell */
+new_range2:
+                       mem_start = read_n_cells(addr_cells, &memcell_buf);
+                       mem_size = read_n_cells(size_cells, &memcell_buf);
+                       if (numa_enabled) {
+                               numa_domain = of_node_numa_domain(memory);
+                               if (numa_domain  >= MAX_NUMNODES)
+                                       numa_domain = 0;
+                       } else
+                               numa_domain =  0;
+
+                       if (numa_domain != nid)
+                               continue;
+
+                       mem_size = numa_enforce_memory_limit(mem_start, mem_size);
+                       memory_present(numa_domain, mem_start >> PAGE_SHIFT,
+                                      (mem_start + mem_size) >> PAGE_SHIFT);
+
+                       if (--ranges)           /* process all ranges in cell */
+                               goto new_range2;
+               }
+
        }
 }
 
index 244150a0bc18713ee49267b4f79521d2197722fd..0473953f6a37713cdf1cc8d18597511a299c102e 100644 (file)
@@ -87,8 +87,8 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
                int i;
                asm volatile("isync" : : : "memory");
                for (i = 0; i < offset; i++) {
-                       esid_data = (unsigned long)get_paca()->slb_cache[i]
-                               << SID_SHIFT;
+                       esid_data = ((unsigned long)get_paca()->slb_cache[i]
+                               << SID_SHIFT) | SLBIE_C;
                        asm volatile("slbie %0" : : "r" (esid_data));
                }
                asm volatile("isync" : : : "memory");
index 8379d678f70f856c7ece883a5724cac91c0f0940..698d6b9ed6d19566d83a2299715f72a512ef96bb 100644 (file)
@@ -89,32 +89,29 @@ END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE)
        b       9f
 
 0:     /* user address: proto-VSID = context<<15 | ESID */
-       li      r11,SLB_VSID_USER
-
-       srdi.   r9,r3,13
+       srdi.   r9,r3,USER_ESID_BITS
        bne-    8f                      /* invalid ea bits set */
 
 #ifdef CONFIG_HUGETLB_PAGE
 BEGIN_FTR_SECTION
-       /* check against the hugepage ranges */
-       cmpldi  r3,(TASK_HPAGE_END>>SID_SHIFT)
-       bge     6f                      /* >= TASK_HPAGE_END */
-       cmpldi  r3,(TASK_HPAGE_BASE>>SID_SHIFT)
-       bge     5f                      /* TASK_HPAGE_BASE..TASK_HPAGE_END */
-       cmpldi  r3,16
-       bge     6f                      /* 4GB..TASK_HPAGE_BASE */
-
-       lhz     r9,PACAHTLBSEGS(r13)
-       srd     r9,r9,r3
-       andi.   r9,r9,1
-       beq     6f
-
-5:     /* this is a hugepage user address */
-       li      r11,(SLB_VSID_USER|SLB_VSID_L)
+       lhz     r9,PACAHIGHHTLBAREAS(r13)
+       srdi    r11,r3,(HTLB_AREA_SHIFT-SID_SHIFT)
+       srd     r9,r9,r11
+       lhz     r11,PACALOWHTLBAREAS(r13)
+       srd     r11,r11,r3
+       or      r9,r9,r11
+END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE)
+#endif /* CONFIG_HUGETLB_PAGE */
+
+       li      r11,SLB_VSID_USER
+
+#ifdef CONFIG_HUGETLB_PAGE
+BEGIN_FTR_SECTION
+       rldimi  r11,r9,8,55             /* shift masked bit into SLB_VSID_L */
 END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE)
 #endif /* CONFIG_HUGETLB_PAGE */
 
-6:     ld      r9,PACACONTEXTID(r13)
+       ld      r9,PACACONTEXTID(r13)
        rldimi  r3,r9,USER_ESID_BITS,0
 
 9:     /* r3 = protovsid, r11 = flags, r10 = esid_data, cr7 = <>KERNELBASE */
index 26f0172c4527ba897e58547fd93eade9f56681a4..d8a6593a13f0ad98fd0b64310b514551b02047e4 100644 (file)
@@ -41,7 +41,58 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
 unsigned long pte_freelist_forced_free;
 
-void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage)
+struct pte_freelist_batch
+{
+       struct rcu_head rcu;
+       unsigned int    index;
+       pgtable_free_t  tables[0];
+};
+
+DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
+unsigned long pte_freelist_forced_free;
+
+#define PTE_FREELIST_SIZE \
+       ((PAGE_SIZE - sizeof(struct pte_freelist_batch)) \
+         / sizeof(pgtable_free_t))
+
+#ifdef CONFIG_SMP
+static void pte_free_smp_sync(void *arg)
+{
+       /* Do nothing, just ensure we sync with all CPUs */
+}
+#endif
+
+/* This is only called when we are critically out of memory
+ * (and fail to get a page in pte_free_tlb).
+ */
+static void pgtable_free_now(pgtable_free_t pgf)
+{
+       pte_freelist_forced_free++;
+
+       smp_call_function(pte_free_smp_sync, NULL, 0, 1);
+
+       pgtable_free(pgf);
+}
+
+static void pte_free_rcu_callback(struct rcu_head *head)
+{
+       struct pte_freelist_batch *batch =
+               container_of(head, struct pte_freelist_batch, rcu);
+       unsigned int i;
+
+       for (i = 0; i < batch->index; i++)
+               pgtable_free(batch->tables[i]);
+
+       free_page((unsigned long)batch);
+}
+
+static void pte_free_submit(struct pte_freelist_batch *batch)
+{
+       INIT_RCU_HEAD(&batch->rcu);
+       call_rcu(&batch->rcu, pte_free_rcu_callback);
+}
+
+void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf)
 {
        /* This is safe as we are holding page_table_lock */
         cpumask_t local_cpumask = cpumask_of_cpu(smp_processor_id());
@@ -49,19 +100,19 @@ void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage)
 
        if (atomic_read(&tlb->mm->mm_users) < 2 ||
            cpus_equal(tlb->mm->cpu_vm_mask, local_cpumask)) {
-               pte_free(ptepage);
+               pgtable_free(pgf);
                return;
        }
 
        if (*batchp == NULL) {
                *batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC);
                if (*batchp == NULL) {
-                       pte_free_now(ptepage);
+                       pgtable_free_now(pgf);
                        return;
                }
                (*batchp)->index = 0;
        }
-       (*batchp)->pages[(*batchp)->index++] = ptepage;
+       (*batchp)->tables[(*batchp)->index++] = pgf;
        if ((*batchp)->index == PTE_FREELIST_SIZE) {
                pte_free_submit(*batchp);
                *batchp = NULL;
@@ -132,42 +183,6 @@ void __flush_tlb_pending(struct ppc64_tlb_batch *batch)
        put_cpu();
 }
 
-#ifdef CONFIG_SMP
-static void pte_free_smp_sync(void *arg)
-{
-       /* Do nothing, just ensure we sync with all CPUs */
-}
-#endif
-
-/* This is only called when we are critically out of memory
- * (and fail to get a page in pte_free_tlb).
- */
-void pte_free_now(struct page *ptepage)
-{
-       pte_freelist_forced_free++;
-
-       smp_call_function(pte_free_smp_sync, NULL, 0, 1);
-
-       pte_free(ptepage);
-}
-
-static void pte_free_rcu_callback(struct rcu_head *head)
-{
-       struct pte_freelist_batch *batch =
-               container_of(head, struct pte_freelist_batch, rcu);
-       unsigned int i;
-
-       for (i = 0; i < batch->index; i++)
-               pte_free(batch->pages[i]);
-       free_page((unsigned long)batch);
-}
-
-void pte_free_submit(struct pte_freelist_batch *batch)
-{
-       INIT_RCU_HEAD(&batch->rcu);
-       call_rcu(&batch->rcu, pte_free_rcu_callback);
-}
-
 void pte_free_finish(void)
 {
        /* This is safe as we are holding page_table_lock */
index b28bfda23d944b4b275ef9e0de4c2db6a891a082..e5f572710aa07bb2e912ec8c58f2a6cd2cac9132 100644 (file)
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/pmc.h>
+#include <asm/cputable.h>
+#include <asm/oprofile_impl.h>
 
-#include "op_impl.h"
-
-extern struct op_ppc64_model op_model_rs64;
-extern struct op_ppc64_model op_model_power4;
 static struct op_ppc64_model *model;
 
 static struct op_counter_config ctr[OP_MAX_COUNTER];
@@ -123,52 +121,13 @@ static int op_ppc64_create_files(struct super_block *sb, struct dentry *root)
 
 int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
-       unsigned int pvr;
-
-       pvr = mfspr(SPRN_PVR);
-
-       switch (PVR_VER(pvr)) {
-               case PV_630:
-               case PV_630p:
-                       model = &op_model_rs64;
-                       model->num_counters = 8;
-                       ops->cpu_type = "ppc64/power3";
-                       break;
-
-               case PV_NORTHSTAR:
-               case PV_PULSAR:
-               case PV_ICESTAR:
-               case PV_SSTAR:
-                       model = &op_model_rs64;
-                       model->num_counters = 8;
-                       ops->cpu_type = "ppc64/rs64";
-                       break;
-
-               case PV_POWER4:
-               case PV_POWER4p:
-                       model = &op_model_power4;
-                       model->num_counters = 8;
-                       ops->cpu_type = "ppc64/power4";
-                       break;
-
-               case PV_970:
-               case PV_970FX:
-                       model = &op_model_power4;
-                       model->num_counters = 8;
-                       ops->cpu_type = "ppc64/970";
-                       break;
-
-               case PV_POWER5:
-               case PV_POWER5p:
-                       model = &op_model_power4;
-                       model->num_counters = 6;
-                       ops->cpu_type = "ppc64/power5";
-                       break;
-
-               default:
-                       return -ENODEV;
-       }
+       if (!cur_cpu_spec->oprofile_model || !cur_cpu_spec->oprofile_cpu_type)
+               return -ENODEV;
+
+       model = cur_cpu_spec->oprofile_model;
+       model->num_counters = cur_cpu_spec->num_pmcs;
 
+       ops->cpu_type = cur_cpu_spec->oprofile_cpu_type;
        ops->create_files = op_ppc64_create_files;
        ops->setup = op_ppc64_setup;
        ops->shutdown = op_ppc64_shutdown;
index 3d103d66870dd55d285ba5329b658241c948c577..32b2bb5625fe3a4f055e445ab1f4619b148f4844 100644 (file)
 #include <asm/cputable.h>
 #include <asm/systemcfg.h>
 #include <asm/rtas.h>
+#include <asm/oprofile_impl.h>
 
 #define dbg(args...)
 
-#include "op_impl.h"
-
 static unsigned long reset_value[OP_MAX_COUNTER];
 
-static int num_counters;
 static int oprofile_running;
 static int mmcra_has_sihv;
 
@@ -45,8 +43,6 @@ static void power4_reg_setup(struct op_counter_config *ctr,
 {
        int i;
 
-       num_counters = num_ctrs;
-
        /*
         * SIHV / SIPR bits are only implemented on POWER4+ (GQ) and above.
         * However we disable it on all POWER4 until we verify it works
@@ -68,7 +64,7 @@ static void power4_reg_setup(struct op_counter_config *ctr,
 
        backtrace_spinlocks = sys->backtrace_spinlocks;
 
-       for (i = 0; i < num_counters; ++i)
+       for (i = 0; i < cur_cpu_spec->num_pmcs; ++i)
                reset_value[i] = 0x80000000UL - ctr[i].count;
 
        /* setup user and kernel profiling */
@@ -121,7 +117,7 @@ static void power4_start(struct op_counter_config *ctr)
        /* set the PMM bit (see comment below) */
        mtmsrd(mfmsr() | MSR_PMM);
 
-       for (i = 0; i < num_counters; ++i) {
+       for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) {
                if (ctr[i].enabled) {
                        ctr_write(i, reset_value[i]);
                } else {
@@ -272,7 +268,7 @@ static void power4_handle_interrupt(struct pt_regs *regs,
        /* set the PMM bit (see comment below) */
        mtmsrd(mfmsr() | MSR_PMM);
 
-       for (i = 0; i < num_counters; ++i) {
+       for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) {
                val = ctr_read(i);
                if (val < 0) {
                        if (oprofile_running && ctr[i].enabled) {
index bcec506c266a8d171f0ecbbba52aeeffb85a3723..08c5b333f5c4bfc5a266f294df95fb80c98cd5f8 100644 (file)
 #include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/cputable.h>
+#include <asm/oprofile_impl.h>
 
 #define dbg(args...)
 
-#include "op_impl.h"
-
 static void ctrl_write(unsigned int i, unsigned int val)
 {
        unsigned int tmp = 0;
index a9265bcc79b24d1e3750efdb3ec86e7ee3d1cd61..e50c158191e169fb4a08c23ef04caa842089c91c 100644 (file)
@@ -27,7 +27,7 @@ static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs,
                              struct tty_struct *tty) 
 {
        /* ensure xmon is enabled */
-       xmon_init();
+       xmon_init(1);
        debugger(pt_regs);
 }
 
@@ -61,7 +61,9 @@ xmon_read(void *handle, void *ptr, int nb)
 int
 xmon_read_poll(void)
 {
-       return udbg_getc_poll();
+       if (udbg_getc_poll)
+               return udbg_getc_poll();
+       return -1;
 }
  
 FILE *xmon_stdin;
index 05539439e6bc0eef1b020f402a7b218b4f2841cf..45908b10acd345970da83c6d5369fc850e6b072a 100644 (file)
@@ -2496,15 +2496,25 @@ static void dump_stab(void)
        }
 }
 
-void xmon_init(void)
-{
-       __debugger = xmon;
-       __debugger_ipi = xmon_ipi;
-       __debugger_bpt = xmon_bpt;
-       __debugger_sstep = xmon_sstep;
-       __debugger_iabr_match = xmon_iabr_match;
-       __debugger_dabr_match = xmon_dabr_match;
-       __debugger_fault_handler = xmon_fault_handler;
+void xmon_init(int enable)
+{
+       if (enable) {
+               __debugger = xmon;
+               __debugger_ipi = xmon_ipi;
+               __debugger_bpt = xmon_bpt;
+               __debugger_sstep = xmon_sstep;
+               __debugger_iabr_match = xmon_iabr_match;
+               __debugger_dabr_match = xmon_dabr_match;
+               __debugger_fault_handler = xmon_fault_handler;
+       } else {
+               __debugger = NULL;
+               __debugger_ipi = NULL;
+               __debugger_bpt = NULL;
+               __debugger_sstep = NULL;
+               __debugger_iabr_match = NULL;
+               __debugger_dabr_match = NULL;
+               __debugger_fault_handler = NULL;
+       }
 }
 
 void dump_segments(void)
index d05d65ac96940832776685c0f8b537269bc95231..7358cdb8441fbf960a1f1bb5371780f3f5e798c6 100644 (file)
@@ -637,12 +637,11 @@ handle_signal32(unsigned long sig, struct k_sigaction *ka,
        else
                setup_frame32(sig, ka, oldset, regs);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
index 960ba6029c3a00c0f77727519450b3591278a272..bc59282da7620408fd98aec3b8e3b643759e47e0 100644 (file)
@@ -62,7 +62,7 @@ typedef struct
 } debug_sprintf_entry_t;
 
 
-extern void tod_to_timeval(uint64_t todval, struct timeval *xtime);
+extern void tod_to_timeval(uint64_t todval, struct timespec *xtime);
 
 /* internal function prototyes */
 
@@ -374,9 +374,24 @@ debug_info_copy(debug_info_t* in, int mode)
 {
         int i,j;
         debug_info_t* rc;
+        unsigned long flags;
+
+       /* get a consistent copy of the debug areas */
+       do {
+               rc = debug_info_alloc(in->name, in->pages_per_area,
+                       in->nr_areas, in->buf_size, in->level, mode);
+               spin_lock_irqsave(&in->lock, flags);
+               if(!rc)
+                       goto out;
+               /* has something changed in the meantime ? */
+               if((rc->pages_per_area == in->pages_per_area) &&
+                  (rc->nr_areas == in->nr_areas)) {
+                       break;
+               }
+               spin_unlock_irqrestore(&in->lock, flags);
+               debug_info_free(rc);
+       } while (1);
 
-        rc = debug_info_alloc(in->name, in->pages_per_area, in->nr_areas,
-                               in->buf_size, in->level, mode);
         if(!rc || (mode == NO_AREAS))
                 goto out;
 
@@ -386,6 +401,7 @@ debug_info_copy(debug_info_t* in, int mode)
                }
         }
 out:
+        spin_unlock_irqrestore(&in->lock, flags);
         return rc;
 }
 
@@ -593,19 +609,15 @@ debug_open(struct inode *inode, struct file *file)
        debug_info_t *debug_info, *debug_info_snapshot;
 
        down(&debug_lock);
-
-       /* find debug log and view */
-       debug_info = debug_area_first;
-       while(debug_info != NULL){
-               for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
-                       if (!debug_info->views[i])
-                               continue;
-                       else if (debug_info->debugfs_entries[i] ==
-                                file->f_dentry) {
-                               goto found;     /* found view ! */
-                       }
+       debug_info = (struct debug_info*)file->f_dentry->d_inode->u.generic_ip;
+       /* find debug view */
+       for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+               if (!debug_info->views[i])
+                       continue;
+               else if (debug_info->debugfs_entries[i] ==
+                        file->f_dentry) {
+                       goto found;     /* found view ! */
                }
-               debug_info = debug_info->next;
        }
        /* no entry found */
        rc = -EINVAL;
@@ -833,7 +845,7 @@ extern inline void
 debug_finish_entry(debug_info_t * id, debug_entry_t* active, int level,
                        int exception)
 {
-       STCK(active->id.stck);
+       active->id.stck = get_clock();
        active->id.fields.cpuid = smp_processor_id();
        active->caller = __builtin_return_address(0);
        active->id.fields.exception = exception;
@@ -1078,7 +1090,7 @@ debug_register_view(debug_info_t * id, struct debug_view *view)
        if (view->input_proc)
                mode |= S_IWUSR;
        pde = debugfs_create_file(view->name, mode, id->debugfs_root_entry,
-                               NULL, &debug_file_ops);
+                               id , &debug_file_ops);
        if (!pde){
                printk(KERN_WARNING "debug: debugfs_create_file() failed!"\
                        " Cannot register view %s/%s\n", id->name,view->name);
@@ -1432,7 +1444,7 @@ int
 debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
                         int area, debug_entry_t * entry, char *out_buf)
 {
-       struct timeval time_val;
+       struct timespec time_spec;
        unsigned long long time;
        char *except_str;
        unsigned long caller;
@@ -1443,7 +1455,7 @@ debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
        time = entry->id.stck;
        /* adjust todclock to 1970 */
        time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
-       tod_to_timeval(time, &time_val);
+       tod_to_timeval(time, &time_spec);
 
        if (entry->id.fields.exception)
                except_str = "*";
@@ -1451,7 +1463,7 @@ debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
                except_str = "-";
        caller = ((unsigned long) entry->caller) & PSW_ADDR_INSN;
        rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %p  ",
-                     area, time_val.tv_sec, time_val.tv_usec, level,
+                     area, time_spec.tv_sec, time_spec.tv_nsec / 1000, level,
                      except_str, entry->id.fields.cpuid, (void *) caller);
        return rc;
 }
index 1a271b16cb5ca30d31af64a74423959d73d1b72e..cbe7d6a2d02cdc36bf5ac511f41e4c16f60410fa 100644 (file)
@@ -138,14 +138,14 @@ STACK_SIZE  = 1 << STACK_SHIFT
        st      %r12,__SF_BACKCHAIN(%r15)       # clear back chain
        .endm
 
-       .macro  RESTORE_ALL sync
-       mvc     __LC_RETURN_PSW(8),SP_PSW(%r15) # move user PSW to lowcore
+       .macro  RESTORE_ALL psworg,sync
+       mvc     \psworg(8),SP_PSW(%r15) # move user PSW to lowcore
        .if !\sync
-       ni      __LC_RETURN_PSW+1,0xfd  # clear wait state bit
+       ni      \psworg+1,0xfd          # clear wait state bit
        .endif
        lm      %r0,%r15,SP_R0(%r15)    # load gprs 0-15 of user
        STORE_TIMER __LC_EXIT_TIMER
-       lpsw    __LC_RETURN_PSW         # back to caller
+       lpsw    \psworg                 # back to caller
        .endm
 
 /*
@@ -235,7 +235,7 @@ sysc_return:
        tm      __TI_flags+3(%r9),_TIF_WORK_SVC
        bnz     BASED(sysc_work)  # there is work to do (signals etc.)
 sysc_leave:
-        RESTORE_ALL 1
+        RESTORE_ALL __LC_RETURN_PSW,1
 
 #
 # recheck if there is more work to do
@@ -312,8 +312,6 @@ sysc_singlestep:
        la      %r14,BASED(sysc_return) # load adr. of system return
        br      %r1                     # branch to do_single_step
 
-__critical_end:
-
 #
 # call trace before and after sys_call
 #
@@ -571,7 +569,8 @@ io_return:
        tm      __TI_flags+3(%r9),_TIF_WORK_INT
        bnz     BASED(io_work)         # there is work to do (signals etc.)
 io_leave:
-        RESTORE_ALL 0
+        RESTORE_ALL __LC_RETURN_PSW,0
+io_done:
 
 #ifdef CONFIG_PREEMPT
 io_preempt:
@@ -621,7 +620,7 @@ io_work_loop:
 #
 io_mcck_pending:
        l       %r1,BASED(.Ls390_handle_mcck)
-       l       %r14,BASED(io_work_loop)
+       la      %r14,BASED(io_work_loop)
        br      %r1                    # TIF bit will be cleared by handler
 
 #
@@ -674,6 +673,8 @@ ext_no_vtime:
        basr    %r14,%r1
        b       BASED(io_return)
 
+__critical_end:
+
 /*
  * Machine check handler routines
  */
@@ -681,6 +682,7 @@ ext_no_vtime:
         .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
@@ -693,17 +695,8 @@ mcck_int_handler:
        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
-0:     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 ?
-       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
-       mvc     __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
-mcck_no_vtime:
 #endif
-0:
-       tm      __LC_MCCK_CODE+2,0x09   # mwp + ia of old psw valid?
+0:     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
@@ -720,6 +713,16 @@ mcck_int_main:
        be      BASED(0f)
        l       %r15,__LC_PANIC_STACK   # load panic stack
 0:     CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32
+#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 ?
+       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
+       mvc     __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+mcck_no_vtime:
+#endif
        l       %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
        la      %r2,SP_PTREGS(%r15)     # load pt_regs
        l       %r1,BASED(.Ls390_mcck)
@@ -737,7 +740,7 @@ mcck_int_main:
        l       %r1,BASED(.Ls390_handle_mcck)
        basr    %r14,%r1                # call machine check handler
 mcck_return:
-        RESTORE_ALL 0
+        RESTORE_ALL __LC_RETURN_MCCK_PSW,0
 
 #ifdef CONFIG_SMP
 /*
@@ -803,6 +806,10 @@ 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_leave:
+       .long   io_leave + 0x80000000, io_done + 0x80000000
+cleanup_table_io_work_loop:
+       .long   io_work_loop + 0x80000000, io_mcck_pending + 0x80000000
 
 cleanup_critical:
        clc     4(4,%r12),BASED(cleanup_table_system_call)
@@ -824,11 +831,27 @@ 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_leave)
+       bl      BASED(0f)
+       clc     4(4,%r12),BASED(cleanup_table_io_leave+4)
+       bl      BASED(cleanup_io_leave)
+0:
+       clc     4(4,%r12),BASED(cleanup_table_io_work_loop)
+       bl      BASED(0f)
+       clc     4(4,%r12),BASED(cleanup_table_io_work_loop+4)
+       bl      BASED(cleanup_io_return)
 0:
        br      %r14
 
 cleanup_system_call:
        mvc     __LC_RETURN_PSW(8),0(%r12)
+       c       %r12,BASED(.Lmck_old_psw)
+       be      BASED(0f)
+       la      %r12,__LC_SAVE_AREA+16
+       b       BASED(1f)
+0:     la      %r12,__LC_SAVE_AREA+32
+1:
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        clc     __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+4)
        bh      BASED(0f)
@@ -838,11 +861,13 @@ cleanup_system_call:
 #endif
        clc     __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn)
        bh      BASED(0f)
-       mvc     __LC_SAVE_AREA(16),__LC_SAVE_AREA+16
-0:     st      %r13,__LC_SAVE_AREA+20
+       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
        CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
-       st      %r15,__LC_SAVE_AREA+28
+       l       %r12,__LC_SAVE_AREA+48  # argh
+       st      %r15,12(%r12)
        lh      %r7,0x8a
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 cleanup_vtime:
@@ -879,17 +904,21 @@ cleanup_sysc_return:
 
 cleanup_sysc_leave:
        clc     4(4,%r12),BASED(cleanup_sysc_leave_insn)
-       be      BASED(0f)
+       be      BASED(2f)
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        mvc     __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
        clc     4(4,%r12),BASED(cleanup_sysc_leave_insn+4)
-       be      BASED(0f)
+       be      BASED(2f)
 #endif
        mvc     __LC_RETURN_PSW(8),SP_PSW(%r15)
-       mvc     __LC_SAVE_AREA+16(16),SP_R12(%r15)
-       lm      %r0,%r11,SP_R0(%r15)
+       c       %r12,BASED(.Lmck_old_psw)
+       bne     BASED(0f)
+       mvc     __LC_SAVE_AREA+32(16),SP_R12(%r15)
+       b       BASED(1f)
+0:     mvc     __LC_SAVE_AREA+16(16),SP_R12(%r15)
+1:     lm      %r0,%r11,SP_R0(%r15)
        l       %r15,SP_R15(%r15)
-0:     la      %r12,__LC_RETURN_PSW
+2:     la      %r12,__LC_RETURN_PSW
        br      %r14
 cleanup_sysc_leave_insn:
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
@@ -897,6 +926,36 @@ cleanup_sysc_leave_insn:
 #endif
        .long   sysc_leave + 10 + 0x80000000
 
+cleanup_io_return:
+       mvc     __LC_RETURN_PSW(4),0(%r12)
+       mvc     __LC_RETURN_PSW+4(4),BASED(cleanup_table_io_work_loop)
+       la      %r12,__LC_RETURN_PSW
+       br      %r14
+
+cleanup_io_leave:
+       clc     4(4,%r12),BASED(cleanup_io_leave_insn)
+       be      BASED(2f)
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       mvc     __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
+       clc     4(4,%r12),BASED(cleanup_io_leave_insn+4)
+       be      BASED(2f)
+#endif
+       mvc     __LC_RETURN_PSW(8),SP_PSW(%r15)
+       c       %r12,BASED(.Lmck_old_psw)
+       bne     BASED(0f)
+       mvc     __LC_SAVE_AREA+32(16),SP_R12(%r15)
+       b       BASED(1f)
+0:     mvc     __LC_SAVE_AREA+16(16),SP_R12(%r15)
+1:     lm      %r0,%r11,SP_R0(%r15)
+       l       %r15,SP_R15(%r15)
+2:     la      %r12,__LC_RETURN_PSW
+       br      %r14
+cleanup_io_leave_insn:
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       .long   io_leave + 18 + 0x80000000
+#endif
+       .long   io_leave + 14 + 0x80000000
+
 /*
  * Integer constants
  */
@@ -918,6 +977,7 @@ cleanup_sysc_leave_insn:
 .Ls390_mcck:   .long  s390_do_machine_check
 .Ls390_handle_mcck:
               .long  s390_handle_mcck
+.Lmck_old_psw: .long  __LC_MCK_OLD_PSW
 .Ldo_IRQ:      .long  do_IRQ
 .Ldo_extint:   .long  do_extint
 .Ldo_signal:   .long  do_signal
index d9f22915008cf3465ecfdbde29ce9648f7d9d9cd..fb77b72ab2627a3ae3f7988f037bbfc230029e62 100644 (file)
@@ -131,14 +131,14 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
        stg     %r12,__SF_BACKCHAIN(%r15)
         .endm
 
-       .macro  RESTORE_ALL sync
-       mvc     __LC_RETURN_PSW(16),SP_PSW(%r15) # move user PSW to lowcore
+       .macro  RESTORE_ALL psworg,sync
+       mvc     \psworg(16),SP_PSW(%r15) # move user PSW to lowcore
        .if !\sync
-       ni      __LC_RETURN_PSW+1,0xfd  # clear wait state bit
+       ni      \psworg+1,0xfd          # clear wait state bit
        .endif
        lmg     %r0,%r15,SP_R0(%r15)    # load gprs 0-15 of user
        STORE_TIMER __LC_EXIT_TIMER
-       lpswe   __LC_RETURN_PSW         # back to caller
+       lpswe   \psworg                 # back to caller
        .endm
 
 /*
@@ -214,8 +214,8 @@ sysc_nr_ok:
 sysc_do_restart:
        larl    %r10,sys_call_table
 #ifdef CONFIG_S390_SUPPORT
-        tm      SP_PSW+3(%r15),0x01  # are we running in 31 bit mode ?
-        jo      sysc_noemu
+       tm      __TI_flags+5(%r9),(_TIF_31BIT>>16)  # running in 31 bit mode ?
+       jno     sysc_noemu
        larl    %r10,sys_call_table_emu  # use 31 bit emulation system calls
 sysc_noemu:
 #endif
@@ -233,7 +233,7 @@ sysc_return:
        tm      __TI_flags+7(%r9),_TIF_WORK_SVC
        jnz     sysc_work         # there is work to do (signals etc.)
 sysc_leave:
-        RESTORE_ALL 1
+        RESTORE_ALL __LC_RETURN_PSW,1
 
 #
 # recheck if there is more work to do
@@ -308,8 +308,6 @@ sysc_singlestep:
        jg      do_single_step          # branch to do_sigtrap
 
 
-__critical_end:
-
 #
 # call syscall_trace before and after system call
 # special linkage: %r12 contains the return address for trace_svc
@@ -612,7 +610,8 @@ io_return:
        tm      __TI_flags+7(%r9),_TIF_WORK_INT
        jnz     io_work                # there is work to do (signals etc.)
 io_leave:
-        RESTORE_ALL 0
+        RESTORE_ALL __LC_RETURN_PSW,0
+io_done:
 
 #ifdef CONFIG_PREEMPT
 io_preempt:
@@ -711,6 +710,8 @@ ext_no_vtime:
        brasl   %r14,do_extint
        j       io_return
 
+__critical_end:
+
 /*
  * Machine check handler routines
  */
@@ -718,6 +719,7 @@ ext_no_vtime:
 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
@@ -730,17 +732,8 @@ mcck_int_handler:
        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
-0:     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 ?
-       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
-       mvc     __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
-mcck_no_vtime:
 #endif
-0:
-       tm      __LC_MCCK_CODE+2,0x09   # mwp + ia of old psw valid?
+0:     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
@@ -756,6 +749,16 @@ mcck_int_main:
        jz      0f
        lg      %r15,__LC_PANIC_STACK   # load panic stack
 0:     CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64
+#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 ?
+       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
+       mvc     __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+mcck_no_vtime:
+#endif
        lg      %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
        la      %r2,SP_PTREGS(%r15)     # load pt_regs
        brasl   %r14,s390_do_machine_check
@@ -771,7 +774,7 @@ mcck_int_main:
        jno     mcck_return
        brasl   %r14,s390_handle_mcck
 mcck_return:
-        RESTORE_ALL 0
+        RESTORE_ALL __LC_RETURN_MCCK_PSW,0
 
 #ifdef CONFIG_SMP
 /*
@@ -833,6 +836,10 @@ cleanup_table_sysc_leave:
        .quad   sysc_leave, sysc_work_loop
 cleanup_table_sysc_work_loop:
        .quad   sysc_work_loop, sysc_reschedule
+cleanup_table_io_leave:
+       .quad   io_leave, io_done
+cleanup_table_io_work_loop:
+       .quad   io_work_loop, io_mcck_pending
 
 cleanup_critical:
        clc     8(8,%r12),BASED(cleanup_table_system_call)
@@ -854,11 +861,27 @@ 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_leave)
+       jl      0f
+       clc     8(8,%r12),BASED(cleanup_table_io_leave+8)
+       jl      cleanup_io_leave
+0:
+       clc     8(8,%r12),BASED(cleanup_table_io_work_loop)
+       jl      0f
+       clc     8(8,%r12),BASED(cleanup_table_io_work_loop+8)
+       jl      cleanup_io_return
 0:
        br      %r14
 
 cleanup_system_call:
        mvc     __LC_RETURN_PSW(16),0(%r12)
+       cghi    %r12,__LC_MCK_OLD_PSW
+       je      0f
+       la      %r12,__LC_SAVE_AREA+32
+       j       1f
+0:     la      %r12,__LC_SAVE_AREA+64
+1:
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        clc     __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+8)
        jh      0f
@@ -868,11 +891,13 @@ cleanup_system_call:
 #endif
        clc     __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn)
        jh      0f
-       mvc     __LC_SAVE_AREA(32),__LC_SAVE_AREA+32
-0:     stg     %r13,__LC_SAVE_AREA+40
+       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
        CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
-       stg     %r15,__LC_SAVE_AREA+56
+       lg      %r12,__LC_SAVE_AREA+96  # argh
+       stg     %r15,24(%r12)
        llgh    %r7,__LC_SVC_INT_CODE
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 cleanup_vtime:
@@ -909,17 +934,21 @@ cleanup_sysc_return:
 
 cleanup_sysc_leave:
        clc     8(8,%r12),BASED(cleanup_sysc_leave_insn)
-       je      0f
+       je      2f
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        mvc     __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
        clc     8(8,%r12),BASED(cleanup_sysc_leave_insn+8)
-       je      0f
+       je      2f
 #endif
        mvc     __LC_RETURN_PSW(16),SP_PSW(%r15)
-       mvc     __LC_SAVE_AREA+32(32),SP_R12(%r15)
-       lmg     %r0,%r11,SP_R0(%r15)
+       cghi    %r12,__LC_MCK_OLD_PSW
+       jne     0f
+       mvc     __LC_SAVE_AREA+64(32),SP_R12(%r15)
+       j       1f
+0:     mvc     __LC_SAVE_AREA+32(32),SP_R12(%r15)
+1:     lmg     %r0,%r11,SP_R0(%r15)
        lg      %r15,SP_R15(%r15)
-0:     la      %r12,__LC_RETURN_PSW
+2:     la      %r12,__LC_RETURN_PSW
        br      %r14
 cleanup_sysc_leave_insn:
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
@@ -927,6 +956,36 @@ cleanup_sysc_leave_insn:
 #endif
        .quad   sysc_leave + 12
 
+cleanup_io_return:
+       mvc     __LC_RETURN_PSW(8),0(%r12)
+       mvc     __LC_RETURN_PSW+8(8),BASED(cleanup_table_io_work_loop)
+       la      %r12,__LC_RETURN_PSW
+       br      %r14
+
+cleanup_io_leave:
+       clc     8(8,%r12),BASED(cleanup_io_leave_insn)
+       je      2f
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       mvc     __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
+       clc     8(8,%r12),BASED(cleanup_io_leave_insn+8)
+       je      2f
+#endif
+       mvc     __LC_RETURN_PSW(16),SP_PSW(%r15)
+       cghi    %r12,__LC_MCK_OLD_PSW
+       jne     0f
+       mvc     __LC_SAVE_AREA+64(32),SP_R12(%r15)
+       j       1f
+0:     mvc     __LC_SAVE_AREA+32(32),SP_R12(%r15)
+1:     lmg     %r0,%r11,SP_R0(%r15)
+       lg      %r15,SP_R15(%r15)
+2:     la      %r12,__LC_RETURN_PSW
+       br      %r14
+cleanup_io_leave_insn:
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       .quad   io_leave + 20
+#endif
+       .quad   io_leave + 16
+
 /*
  * Integer constants
  */
index 610c1d03e975701b152df903f399de25b4954ff2..6a3f5b7473a91b7c1a5ad08238430966f839e9f1 100644 (file)
@@ -429,13 +429,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
        else
                setup_frame(sig, ka, oldset, regs);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
index 8ca485676780de694b31134f2303b094e5053e68..2fd75da1549522b13816e9a9c50e1be8c4db2b42 100644 (file)
@@ -139,10 +139,7 @@ int do_settimeofday(struct timespec *tv)
        set_normalized_timespec(&xtime, sec, nsec);
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
        return 0;
index 75fde949d12570a68d1a5aaa228fc946fccc0c4b..856a971759b1a2d0776c347914d1dc3015885659 100644 (file)
@@ -563,12 +563,14 @@ pfault_interrupt(struct pt_regs *regs, __u16 error_code)
                         * interrupt. pfault_wait is valid. Set pfault_wait
                         * back to zero and wake up the process. This can
                         * safely be done because the task is still sleeping
-                        * and can't procude new pfaults. */
+                        * and can't produce new pfaults. */
                        tsk->thread.pfault_wait = 0;
                        wake_up_process(tsk);
+                       put_task_struct(tsk);
                }
        } else {
                /* signal bit not set -> a real page is missing. */
+               get_task_struct(tsk);
                set_task_state(tsk, TASK_UNINTERRUPTIBLE);
                if (xchg(&tsk->thread.pfault_wait, 1) != 0) {
                        /* Completion interrupt was faster than the initial
@@ -578,6 +580,7 @@ pfault_interrupt(struct pt_regs *regs, __u16 error_code)
                         * mode and can't produce new pfaults. */
                        tsk->thread.pfault_wait = 0;
                        set_task_state(tsk, TASK_RUNNING);
+                       put_task_struct(tsk);
                } else
                        set_tsk_need_resched(tsk);
        }
index adc8109f8b7719ca25c910f1600abd90495bc0e2..3e804c736e640eb9340128cf2adb18435a2ee61c 100644 (file)
@@ -37,6 +37,10 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default y
 
+config ARCH_MAY_HAVE_PC_FDC
+       bool
+       default y
+
 source "init/Kconfig"
 
 menu "System type"
index 8022243f017828a44875f6f79b86ff487388b0ec..b475c4d2405f3e81795dfb39dfdd8aa2c350e94d 100644 (file)
@@ -546,13 +546,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
        if (ka->sa.sa_flags & SA_ONESHOT)
                ka->sa.sa_handler = SIG_DFL;
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
index df7a9b9d4cbffb298c77518958b97a9581dbfc4d..02ca69918d7c0992a943f7d7d856149f0145a9a3 100644 (file)
@@ -215,10 +215,7 @@ int do_settimeofday(struct timespec *tv)
        set_normalized_timespec(&xtime, sec, nsec);
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
 
@@ -234,7 +231,7 @@ static long last_rtc_update;
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
-static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static inline void do_timer_interrupt(int irq, struct pt_regs *regs)
 {
        do_timer(regs);
 #ifndef CONFIG_SMP
@@ -252,7 +249,7 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *reg
         * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
         * called as close as possible to 500 ms before the new second starts.
         */
-       if ((time_status & STA_UNSYNC) == 0 &&
+       if (ntp_synced() &&
            xtime.tv_sec > last_rtc_update + 660 &&
            (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
            (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
@@ -285,7 +282,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
         * locally disabled. -arca
         */
        write_seqlock(&xtime_lock);
-       do_timer_interrupt(irq, NULL, regs);
+       do_timer_interrupt(irq, regs);
        write_sequnlock(&xtime_lock);
 
        return IRQ_HANDLED;
index 4c3e5334adb3208361123062aabf5abe8c7fd745..fb35b45dc130074b3fd6d0170c58588f17885f1e 100644 (file)
@@ -29,10 +29,6 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default y
 
-config LOG_BUF_SHIFT
-       int
-       default 14
-
 config RWSEM_XCHGADD_ALGORITHM
        bool
 
index c6a14a87c59b4a887664a34c6604c96515c31417..3ea8929e483b5fea4f99fc6b6ebe2144ed61eb77 100644 (file)
@@ -664,13 +664,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
        else
                setup_frame(sig, ka, oldset, regs);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
index 6c84da3efc7383d3511434c91ef7815a05b2421d..f4a62a10053c60e6921d00b280d050a90eae8735 100644 (file)
@@ -247,10 +247,7 @@ int do_settimeofday(struct timespec *tv)
        set_normalized_timespec(&xtime, sec, nsec);
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
 
@@ -303,7 +300,7 @@ static long last_rtc_update = 0;
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
-static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static inline void do_timer_interrupt(int irq, struct pt_regs *regs)
 {
        unsigned long long current_ctc;
        asm ("getcon cr62, %0" : "=r" (current_ctc));
@@ -328,7 +325,7 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *reg
         * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
         * called as close as possible to 500 ms before the new second starts.
         */
-       if ((time_status & STA_UNSYNC) == 0 &&
+       if (ntp_synced() &&
            xtime.tv_sec > last_rtc_update + 660 &&
            (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
            (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
@@ -361,7 +358,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
         * locally disabled. -arca
         */
        write_lock(&xtime_lock);
-       do_timer_interrupt(irq, NULL, regs);
+       do_timer_interrupt(irq, regs);
        write_unlock(&xtime_lock);
 
        return IRQ_HANDLED;
index aca028aa29bfb5d2fb42896a7a73019b4fca4697..aba05394d30a05603685e2bcc62cc9c2b85b4d3b 100644 (file)
@@ -211,6 +211,10 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default y
 
+config ARCH_MAY_HAVE_PC_FDC
+       bool
+       default y
+
 config SUN_PM
        bool
        default y
index 597d3ff6ad68ce16d1a5426a7562cfba3d4e065d..36a40697b8d61e66a9c129a61cb009712199f663 100644 (file)
@@ -840,10 +840,7 @@ static int pci_do_settimeofday(struct timespec *tv)
 
        xtime.tv_sec = tv->tv_sec;
        xtime.tv_nsec = tv->tv_nsec;
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
        return 0;
 }
 
index 55352ed85e8afe3187ec14ea00758e360d0e3d8e..53c192a4982f7210d8bd5587c2f0d99987a86b7b 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/spinlock.h>
 #include <linux/root_dev.h>
 
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/processor.h>
index 011ff35057a5149f332f2b928bb7e052b20d4292..5f34d7dc2b898672a4a8bfccd40940a647af0170 100644 (file)
@@ -1034,13 +1034,12 @@ handle_signal(unsigned long signr, struct k_sigaction *ka,
                else
                        setup_frame(&ka->sa, regs, signr, oldset, info);
        }
-       if (!(ka->sa.sa_flags & SA_NOMASK)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NOMASK))
                sigaddset(&current->blocked, signr);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
index 8faa8dc4de435cd7850170a5ea266f19cd00ac6b..5d974a2b735a9ac354295ec6e4870cfb85049e12 100644 (file)
@@ -175,7 +175,6 @@ EXPORT_SYMBOL(set_auxio);
 EXPORT_SYMBOL(get_auxio);
 #endif
 EXPORT_SYMBOL(request_fast_irq);
-EXPORT_SYMBOL(io_remap_page_range);
 EXPORT_SYMBOL(io_remap_pfn_range);
   /* P3: iounit_xxx may be needed, sun4d users */
 /* EXPORT_SYMBOL(iounit_map_dma_init); */
index fd8005a3e6bde45ea8ff3fc4bc6d0cc08c6b0f79..591547af4c656d801cff84635e8e8bb48e372566 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/interrupt.h>
 
 #include <asm/oplib.h>
-#include <asm/segment.h>
 #include <asm/timer.h>
 #include <asm/mostek.h>
 #include <asm/system.h>
index 6486cbf2efe9fd5a62d1aebd8ad12f30c1402759..bc015e980341060dc9eb3fa28d6bc9485cb964bd 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/profile.h>
 
 #include <asm/oplib.h>
-#include <asm/segment.h>
 #include <asm/timer.h>
 #include <asm/mostek.h>
 #include <asm/system.h>
@@ -140,7 +139,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 
 
        /* Determine when to update the Mostek clock. */
-       if ((time_status & STA_UNSYNC) == 0 &&
+       if (ntp_synced() &&
            xtime.tv_sec > last_rtc_update + 660 &&
            (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
            (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
@@ -555,10 +554,7 @@ static int sbus_do_settimeofday(struct timespec *tv)
        set_normalized_timespec(&xtime, sec, nsec);
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
        return 0;
 }
 
index 37f4107bae667b73c7bc14b05f85df48646347f2..2bbd53f3cafb2c461e111d10351e2436bd1a19bb 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/module.h>
 
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/memreg.h>
index db27eee3bda19511b49f7b83c0fd472082319d46..20ccb957fb7795118b5f06b21d7c5649423e72b4 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
-static inline void forget_pte(pte_t page)
-{
-#if 0 /* old 2.4 code */
-       if (pte_none(page))
-               return;
-       if (pte_present(page)) {
-               unsigned long pfn = pte_pfn(page);
-               struct page *ptpage;
-               if (!pfn_valid(pfn))
-                       return;
-               ptpage = pfn_to_page(pfn);
-               if (PageReserved(ptpage))
-                       return;
-               page_cache_release(ptpage);
-               return;
-       }
-       swap_free(pte_to_swp_entry(page));
-#else
-       if (!pte_none(page)) {
-               printk("forget_pte: old mapping existed!\n");
-               BUG();
-       }
-#endif
-}
-
 /* Remap IO memory, the same way as remap_pfn_range(), but use
  * the obio memory space.
  *
@@ -60,7 +35,6 @@ static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte, unsigne
                pte_t oldpage = *pte;
                pte_clear(mm, address, pte);
                set_pte(pte, mk_pte_io(offset, prot, space));
-               forget_pte(oldpage);
                address += PAGE_SIZE;
                offset += PAGE_SIZE;
                pte++;
@@ -88,37 +62,6 @@ static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned
        return 0;
 }
 
-int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space)
-{
-       int error = 0;
-       pgd_t * dir;
-       unsigned long beg = from;
-       unsigned long end = from + size;
-       struct mm_struct *mm = vma->vm_mm;
-
-       prot = __pgprot(pg_iobits);
-       offset -= from;
-       dir = pgd_offset(mm, from);
-       flush_cache_range(vma, beg, end);
-
-       spin_lock(&mm->page_table_lock);
-       while (from < end) {
-               pmd_t *pmd = pmd_alloc(current->mm, dir, from);
-               error = -ENOMEM;
-               if (!pmd)
-                       break;
-               error = io_remap_pmd_range(mm, pmd, from, end - from, offset + from, prot, space);
-               if (error)
-                       break;
-               from = (from + PGDIR_SIZE) & PGDIR_MASK;
-               dir++;
-       }
-       spin_unlock(&mm->page_table_lock);
-
-       flush_tlb_range(vma, beg, end);
-       return error;
-}
-
 int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
                        unsigned long pfn, unsigned long size, pgprot_t prot)
 {
index ec2e05028a10d7ff7804ef912833942e1e0fd20a..c03babaa0498b95787eac1bd3ec2244364208339 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/bootmem.h>
 
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <asm/vac-ops.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
index 9afd28e2c4d510e5d2e6f3f3c312f40ba8e9c748..1e9d8638a28a249823d31f53c7d629d392240088 100644 (file)
@@ -5,6 +5,16 @@
 
 mainmenu "Linux/UltraSPARC Kernel Configuration"
 
+config SPARC64
+       bool
+       default y
+       help
+         SPARC is a family of RISC microprocessors designed and marketed by
+         Sun Microsystems, incorporated.  This port covers the newer 64-bit
+         UltraSPARC.  The UltraLinux project maintains both the SPARC32 and
+         SPARC64 ports; its web page is available at
+         <http://www.ultralinux.org/>.
+
 config 64BIT
        def_bool y
 
@@ -16,6 +26,10 @@ config TIME_INTERPOLATION
        bool
        default y
 
+config ARCH_MAY_HAVE_PC_FDC
+       bool
+       default y
+
 choice
        prompt "Kernel page size"
        default SPARC64_PAGE_SIZE_8KB
@@ -71,75 +85,6 @@ config SYSVIPC_COMPAT
 
 menu "General machine setup"
 
-config BBC_I2C
-       tristate "UltraSPARC-III bootbus i2c controller driver"
-       depends on PCI
-       help
-         The BBC devices on the UltraSPARC III have two I2C controllers.  The
-         first I2C controller connects mainly to configuration PROMs (NVRAM,
-         CPU configuration, DIMM types, etc.).  The second I2C controller
-         connects to environmental control devices such as fans and
-         temperature sensors.  The second controller also connects to the
-         smartcard reader, if present.  Say Y to enable support for these.
-
-config VT
-       bool "Virtual terminal" if EMBEDDED
-       select INPUT
-       default y
-       ---help---
-         If you say Y here, you will get support for terminal devices with
-         display and keyboard devices. These are called "virtual" because you
-         can run several virtual terminals (also called virtual consoles) on
-         one physical terminal. This is rather useful, for example one
-         virtual terminal can collect system messages and warnings, another
-         one can be used for a text-mode user session, and a third could run
-         an X session, all in parallel. Switching between virtual terminals
-         is done with certain key combinations, usually Alt-<function key>.
-
-         The setterm command ("man setterm") can be used to change the
-         properties (such as colors or beeping) of a virtual terminal. The
-         man page console_codes(4) ("man console_codes") contains the special
-         character sequences that can be used to change those properties
-         directly. The fonts used on virtual terminals can be changed with
-         the setfont ("man setfont") command and the key bindings are defined
-         with the loadkeys ("man loadkeys") command.
-
-         You need at least one virtual terminal device in order to make use
-         of your keyboard and monitor. Therefore, only people configuring an
-         embedded system would want to say N here in order to save some
-         memory; the only way to log into such a system is then via a serial
-         or network connection.
-
-         If unsure, say Y, or else you won't be able to do much with your new
-         shiny Linux system :-)
-
-config VT_CONSOLE
-       bool "Support for console on virtual terminal" if EMBEDDED
-       depends on VT
-       default y
-       ---help---
-         The system console is the device which receives all kernel messages
-         and warnings and which allows logins in single user mode. If you
-         answer Y here, a virtual terminal (the device used to interact with
-         a physical terminal) can be used as system console. This is the most
-         common mode of operations, so you should say Y here unless you want
-         the kernel messages be output only to a serial port (in which case
-         you should say Y to "Console on serial port", below).
-
-         If you do say Y here, by default the currently visible virtual
-         terminal (/dev/tty0) will be used as system console. You can change
-         that with a kernel command line option such as "console=tty3" which
-         would use the third virtual terminal as system console. (Try "man
-         bootparam" or see the documentation of your boot loader (lilo or
-         loadlin) about how to pass options to the kernel at boot time.)
-
-         If unsure, say Y.
-
-config HW_CONSOLE
-       bool
-       depends on VT
-       default y
-
 config SMP
        bool "Symmetric multi-processing support"
        ---help---
@@ -205,17 +150,6 @@ config US2E_FREQ
 
          If in doubt, say N.
 
-# Identify this as a Sparc64 build
-config SPARC64
-       bool
-       default y
-       help
-         SPARC is a family of RISC microprocessors designed and marketed by
-         Sun Microsystems, incorporated.  This port covers the newer 64-bit
-         UltraSPARC.  The UltraLinux project maintains both the SPARC32 and
-         SPARC64 ports; its web page is available at
-         <http://www.ultralinux.org/>.
-
 # Global things across all Sun machines.
 config RWSEM_GENERIC_SPINLOCK
        bool
@@ -246,6 +180,10 @@ config HUGETLB_PAGE_SIZE_64K
 
 endchoice
 
+endmenu
+
+source "mm/Kconfig"
+
 config GENERIC_ISA_DMA
        bool
        default y
@@ -344,33 +282,6 @@ config PCI_DOMAINS
        bool
        default PCI
 
-config RTC
-       tristate
-       depends on PCI
-       default y
-       ---help---
-         If you say Y here and create a character special file /dev/rtc with
-         major number 10 and minor number 135 using mknod ("man mknod"), you
-         will get access to the real time clock (or hardware clock) built
-         into your computer.
-
-         Every PC has such a clock built in. It can be used to generate
-         signals from as low as 1Hz up to 8192Hz, and can also be used
-         as a 24 hour alarm. It reports status information via the file
-         /proc/driver/rtc and its behaviour is set by various ioctls on
-         /dev/rtc.
-
-         If you run Linux on a multiprocessor machine and said Y to
-         "Symmetric Multi Processing" above, you should say Y here to read
-         and set the RTC in an SMP compatible fashion.
-
-         If you think you have a use for such a device (such as periodic data
-         sampling), then say Y here, and read <file:Documentation/rtc.txt>
-         for details.
-
-         To compile this driver as a module, choose M here: the
-         module will be called rtc.
-
 source "drivers/pci/Kconfig"
 
 config SUN_OPENPROMFS
@@ -414,6 +325,8 @@ config BINFMT_AOUT32
          If you want to run SunOS binaries (see SunOS binary emulation below)
          or other a.out binaries, say Y. If unsure, say N.
 
+menu "Executable file formats"
+
 source "fs/Kconfig.binfmt"
 
 config SUNOS_EMUL
@@ -436,74 +349,7 @@ config SOLARIS_EMUL
          To compile this code as a module, choose M here: the
          module will be called solaris.
 
-source "drivers/parport/Kconfig"
-
-config PRINTER
-       tristate "Parallel printer support"
-       depends on PARPORT
-       ---help---
-         If you intend to attach a printer to the parallel port of your Linux
-         box (as opposed to using a serial printer; if the connector at the
-         printer has 9 or 25 holes ["female"], then it's serial), say Y.
-         Also read the Printing-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         It is possible to share one parallel port among several devices
-         (e.g. printer and ZIP drive) and it is safe to compile the
-         corresponding drivers into the kernel.
-         To compile this driver as a module, choose M here and read
-         <file:Documentation/parport.txt>.  The module will be called lp.
-
-         If you have several parallel ports, you can specify which ports to
-         use with the "lp" kernel command line option.  (Try "man bootparam"
-         or see the documentation of your boot loader (lilo or loadlin) about
-         how to pass options to the kernel at boot time.)  The syntax of the
-         "lp" command line option can be found in <file:drivers/char/lp.c>.
-
-         If you have more than 8 printers, you need to increase the LP_NO
-         macro in lp.c and the PARPORT_MAX macro in parport.h.
-
-config PPDEV
-       tristate "Support for user-space parallel port device drivers"
-       depends on PARPORT
-       ---help---
-         Saying Y to this adds support for /dev/parport device nodes.  This
-         is needed for programs that want portable access to the parallel
-         port, for instance deviceid (which displays Plug-and-Play device
-         IDs).
-
-         This is the parallel port equivalent of SCSI generic support (sg).
-         It is safe to say N to this -- it is not needed for normal printing
-         or parallel port CD-ROM/disk support.
-
-         To compile this driver as a module, choose M here: the
-         module will be called ppdev.
-
-         If unsure, say N.
-
-config ENVCTRL
-       tristate "SUNW, envctrl support"
-       depends on PCI
-       help
-         Kernel support for temperature and fan monitoring on Sun SME
-         machines.
-
-         To compile this driver as a module, choose M here: the
-         module will be called envctrl.
-
-config DISPLAY7SEG
-       tristate "7-Segment Display support"
-       depends on PCI
-       ---help---
-         This is the driver for the 7-segment display and LED present on
-         Sun Microsystems CompactPCI models CP1400 and CP1500.
-
-         To compile this driver as a module, choose M here: the
-         module will be called display7seg.
-
-         If you do not have a CompactPCI model CP1400 or CP1500, or
-         another UltraSPARC-IIi-cEngine boardset with a 7-segment display,
-         you should say N to this option.
+endmenu
 
 config CMDLINE_BOOL
        bool "Default bootloader kernel arguments"
@@ -521,148 +367,16 @@ config CMDLINE
 
          NOTE: This option WILL override the PROM bootargs setting!
 
-source "mm/Kconfig"
-
-endmenu
-
 source "net/Kconfig"
 
-source "drivers/base/Kconfig"
-
-source "drivers/video/Kconfig"
-
-source "drivers/serial/Kconfig"
+source "drivers/Kconfig"
 
 source "drivers/sbus/char/Kconfig"
 
-source "drivers/mtd/Kconfig"
-
-source "drivers/block/Kconfig"
-
-source "drivers/ide/Kconfig"
-
-source "drivers/scsi/Kconfig"
-
 source "drivers/fc4/Kconfig"
 
-source "drivers/md/Kconfig"
-
-if PCI
-source "drivers/message/fusion/Kconfig"
-endif
-
-source "drivers/ieee1394/Kconfig"
-
-source "drivers/net/Kconfig"
-
-source "drivers/isdn/Kconfig"
-
-source "drivers/telephony/Kconfig"
-
-# This one must be before the filesystem configs. -DaveM
-
-menu "Unix98 PTY support"
-
-config UNIX98_PTYS
-       bool "Unix98 PTY support"
-       ---help---
-         A pseudo terminal (PTY) is a software device consisting of two
-         halves: a master and a slave. The slave device behaves identical to
-         a physical terminal; the master device is used by a process to
-         read data from and write data to the slave, thereby emulating a
-         terminal. Typical programs for the master side are telnet servers
-         and xterms.
-
-         Linux has traditionally used the BSD-like names /dev/ptyxx for
-         masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
-         has a number of problems. The GNU C library glibc 2.1 and later,
-         however, supports the Unix98 naming standard: in order to acquire a
-         pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
-         terminal is then made available to the process and the pseudo
-         terminal slave can be accessed as /dev/pts/<number>. What was
-         traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
-
-         The entries in /dev/pts/ are created on the fly by a virtual
-         file system; therefore, if you say Y here you should say Y to
-         "/dev/pts file system for Unix98 PTYs" as well.
-
-         If you want to say Y here, you need to have the C library glibc 2.1
-         or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
-         Read the instructions in <file:Documentation/Changes> pertaining to
-         pseudo terminals. It's safe to say N.
-
-config UNIX98_PTY_COUNT
-       int "Maximum number of Unix98 PTYs in use (0-2048)"
-       depends on UNIX98_PTYS
-       default "256"
-       help
-         The maximum number of Unix98 PTYs that can be used at any one time.
-         The default is 256, and should be enough for desktop systems. Server
-         machines which support incoming telnet/rlogin/ssh connections and/or
-         serve several X terminals may want to increase this: every incoming
-         connection and every xterm uses up one PTY.
-
-         When not in use, each additional set of 256 PTYs occupy
-         approximately 8 KB of kernel memory on 32-bit architectures.
-
-endmenu
-
-menu "XFree86 DRI support"
-
-config DRM
-       bool "Direct Rendering Manager (XFree86 DRI support)"
-       help
-         Kernel-level support for the Direct Rendering Infrastructure (DRI)
-         introduced in XFree86 4.0. If you say Y here, you need to select
-         the module that's right for your graphics card from the list below.
-         These modules provide support for synchronization, security, and
-         DMA transfers. Please see <http://dri.sourceforge.net/> for more
-         details.  You should also select and configure AGP
-         (/dev/agpgart) support.
-
-config DRM_FFB
-       tristate "Creator/Creator3D"
-       depends on DRM && BROKEN
-       help
-         Choose this option if you have one of Sun's Creator3D-based graphics
-         and frame buffer cards.  Product page at
-         <http://www.sun.com/desktop/products/Graphics/creator3d.html>.
-
-config DRM_TDFX
-       tristate "3dfx Banshee/Voodoo3+"
-       depends on DRM
-       help
-         Choose this option if you have a 3dfx Banshee or Voodoo3 (or later),
-         graphics card.  If M is selected, the module will be called tdfx.
-
-config DRM_R128
-       tristate "ATI Rage 128"
-       depends on DRM
-       help
-         Choose this option if you have an ATI Rage 128 graphics card.  If M
-         is selected, the module will be called r128.  AGP support for
-         this card is strongly suggested (unless you have a PCI version).
-
-endmenu
-
-source "drivers/input/Kconfig"
-
-source "drivers/i2c/Kconfig"
-
-source "drivers/hwmon/Kconfig"
-
 source "fs/Kconfig"
 
-source "drivers/media/Kconfig"
-
-source "sound/Kconfig"
-
-source "drivers/usb/Kconfig"
-
-source "drivers/infiniband/Kconfig"
-
-source "drivers/char/watchdog/Kconfig"
-
 source "arch/sparc64/oprofile/Kconfig"
 
 source "arch/sparc64/Kconfig.debug"
index 88332f00094ac5d00ae9f0e2acdc0adbbdf595b5..3e0badb820c5798996c296b913130cb7e5ac9d0a 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/visasm.h>
 #include <asm/estate.h>
 #include <asm/auxio.h>
+#include <asm/sfafsr.h>
 
 #define curptr      g6
 
@@ -690,14 +691,159 @@ netbsd_syscall:
        retl
         nop
 
-       /* These next few routines must be sure to clear the
-        * SFSR FaultValid bit so that the fast tlb data protection
-        * handler does not flush the wrong context and lock up the
-        * box.
+       /* We need to carefully read the error status, ACK
+        * the errors, prevent recursive traps, and pass the
+        * information on to C code for logging.
+        *
+        * We pass the AFAR in as-is, and we encode the status
+        * information as described in asm-sparc64/sfafsr.h
+        */
+       .globl          __spitfire_access_error
+__spitfire_access_error:
+       /* Disable ESTATE error reporting so that we do not
+        * take recursive traps and RED state the processor.
+        */
+       stxa            %g0, [%g0] ASI_ESTATE_ERROR_EN
+       membar          #Sync
+
+       mov             UDBE_UE, %g1
+       ldxa            [%g0] ASI_AFSR, %g4     ! Get AFSR
+
+       /* __spitfire_cee_trap branches here with AFSR in %g4 and
+        * UDBE_CE in %g1.  It only clears ESTATE_ERR_CE in the
+        * ESTATE Error Enable register.
+        */
+__spitfire_cee_trap_continue:
+       ldxa            [%g0] ASI_AFAR, %g5     ! Get AFAR
+
+       rdpr            %tt, %g3
+       and             %g3, 0x1ff, %g3         ! Paranoia
+       sllx            %g3, SFSTAT_TRAP_TYPE_SHIFT, %g3
+       or              %g4, %g3, %g4
+       rdpr            %tl, %g3
+       cmp             %g3, 1
+       mov             1, %g3
+       bleu            %xcc, 1f
+        sllx           %g3, SFSTAT_TL_GT_ONE_SHIFT, %g3
+
+       or              %g4, %g3, %g4
+
+       /* Read in the UDB error register state, clearing the
+        * sticky error bits as-needed.  We only clear them if
+        * the UE bit is set.  Likewise, __spitfire_cee_trap
+        * below will only do so if the CE bit is set.
+        *
+        * NOTE: UltraSparc-I/II have high and low UDB error
+        *       registers, corresponding to the two UDB units
+        *       present on those chips.  UltraSparc-IIi only
+        *       has a single UDB, called "SDB" in the manual.
+        *       For IIi the upper UDB register always reads
+        *       as zero so for our purposes things will just
+        *       work with the checks below.
         */
-       .globl          __do_data_access_exception
-       .globl          __do_data_access_exception_tl1
-__do_data_access_exception_tl1:
+1:     ldxa            [%g0] ASI_UDBH_ERROR_R, %g3
+       and             %g3, 0x3ff, %g7         ! Paranoia
+       sllx            %g7, SFSTAT_UDBH_SHIFT, %g7
+       or              %g4, %g7, %g4
+       andcc           %g3, %g1, %g3           ! UDBE_UE or UDBE_CE
+       be,pn           %xcc, 1f
+        nop
+       stxa            %g3, [%g0] ASI_UDB_ERROR_W
+       membar          #Sync
+
+1:     mov             0x18, %g3
+       ldxa            [%g3] ASI_UDBL_ERROR_R, %g3
+       and             %g3, 0x3ff, %g7         ! Paranoia
+       sllx            %g7, SFSTAT_UDBL_SHIFT, %g7
+       or              %g4, %g7, %g4
+       andcc           %g3, %g1, %g3           ! UDBE_UE or UDBE_CE
+       be,pn           %xcc, 1f
+        nop
+       mov             0x18, %g7
+       stxa            %g3, [%g7] ASI_UDB_ERROR_W
+       membar          #Sync
+
+1:     /* Ok, now that we've latched the error state,
+        * clear the sticky bits in the AFSR.
+        */
+       stxa            %g4, [%g0] ASI_AFSR
+       membar          #Sync
+
+       rdpr            %tl, %g2
+       cmp             %g2, 1
+       rdpr            %pil, %g2
+       bleu,pt         %xcc, 1f
+        wrpr           %g0, 15, %pil
+
+       ba,pt           %xcc, etraptl1
+        rd             %pc, %g7
+
+       ba,pt           %xcc, 2f
+        nop
+
+1:     ba,pt           %xcc, etrap_irq
+        rd             %pc, %g7
+
+2:     mov             %l4, %o1
+       mov             %l5, %o2
+       call            spitfire_access_error
+        add            %sp, PTREGS_OFF, %o0
+       ba,pt           %xcc, rtrap
+        clr            %l6
+
+       /* This is the trap handler entry point for ECC correctable
+        * errors.  They are corrected, but we listen for the trap
+        * so that the event can be logged.
+        *
+        * Disrupting errors are either:
+        * 1) single-bit ECC errors during UDB reads to system
+        *    memory
+        * 2) data parity errors during write-back events
+        *
+        * As far as I can make out from the manual, the CEE trap
+        * is only for correctable errors during memory read
+        * accesses by the front-end of the processor.
+        *
+        * The code below is only for trap level 1 CEE events,
+        * as it is the only situation where we can safely record
+        * and log.  For trap level >1 we just clear the CE bit
+        * in the AFSR and return.
+        *
+        * This is just like __spiftire_access_error above, but it
+        * specifically handles correctable errors.  If an
+        * uncorrectable error is indicated in the AFSR we
+        * will branch directly above to __spitfire_access_error
+        * to handle it instead.  Uncorrectable therefore takes
+        * priority over correctable, and the error logging
+        * C code will notice this case by inspecting the
+        * trap type.
+        */
+       .globl          __spitfire_cee_trap
+__spitfire_cee_trap:
+       ldxa            [%g0] ASI_AFSR, %g4     ! Get AFSR
+       mov             1, %g3
+       sllx            %g3, SFAFSR_UE_SHIFT, %g3
+       andcc           %g4, %g3, %g0           ! Check for UE
+       bne,pn          %xcc, __spitfire_access_error
+        nop
+
+       /* Ok, in this case we only have a correctable error.
+        * Indicate we only wish to capture that state in register
+        * %g1, and we only disable CE error reporting unlike UE
+        * handling which disables all errors.
+        */
+       ldxa            [%g0] ASI_ESTATE_ERROR_EN, %g3
+       andn            %g3, ESTATE_ERR_CE, %g3
+       stxa            %g3, [%g0] ASI_ESTATE_ERROR_EN
+       membar          #Sync
+
+       /* Preserve AFSR in %g4, indicate UDB state to capture in %g1 */
+       ba,pt           %xcc, __spitfire_cee_trap_continue
+        mov            UDBE_CE, %g1
+
+       .globl          __spitfire_data_access_exception
+       .globl          __spitfire_data_access_exception_tl1
+__spitfire_data_access_exception_tl1:
        rdpr            %pstate, %g4
        wrpr            %g4, PSTATE_MG|PSTATE_AG, %pstate
        mov             TLB_SFSR, %g3
@@ -706,9 +852,25 @@ __do_data_access_exception_tl1:
        ldxa            [%g5] ASI_DMMU, %g5     ! Get SFAR
        stxa            %g0, [%g3] ASI_DMMU     ! Clear SFSR.FaultValid bit
        membar          #Sync
+       rdpr            %tt, %g3
+       cmp             %g3, 0x80               ! first win spill/fill trap
+       blu,pn          %xcc, 1f
+        cmp            %g3, 0xff               ! last win spill/fill trap
+       bgu,pn          %xcc, 1f
+        nop
        ba,pt           %xcc, winfix_dax
         rdpr           %tpc, %g3
-__do_data_access_exception:
+1:     sethi           %hi(109f), %g7
+       ba,pt           %xcc, etraptl1
+109:    or             %g7, %lo(109b), %g7
+       mov             %l4, %o1
+       mov             %l5, %o2
+       call            spitfire_data_access_exception_tl1
+        add            %sp, PTREGS_OFF, %o0
+       ba,pt           %xcc, rtrap
+        clr            %l6
+
+__spitfire_data_access_exception:
        rdpr            %pstate, %g4
        wrpr            %g4, PSTATE_MG|PSTATE_AG, %pstate
        mov             TLB_SFSR, %g3
@@ -722,20 +884,19 @@ __do_data_access_exception:
 109:    or             %g7, %lo(109b), %g7
        mov             %l4, %o1
        mov             %l5, %o2
-       call            data_access_exception
+       call            spitfire_data_access_exception
         add            %sp, PTREGS_OFF, %o0
        ba,pt           %xcc, rtrap
         clr            %l6
 
-       .globl          __do_instruction_access_exception
-       .globl          __do_instruction_access_exception_tl1
-__do_instruction_access_exception_tl1:
+       .globl          __spitfire_insn_access_exception
+       .globl          __spitfire_insn_access_exception_tl1
+__spitfire_insn_access_exception_tl1:
        rdpr            %pstate, %g4
        wrpr            %g4, PSTATE_MG|PSTATE_AG, %pstate
        mov             TLB_SFSR, %g3
-       mov             DMMU_SFAR, %g5
-       ldxa            [%g3] ASI_DMMU, %g4     ! Get SFSR
-       ldxa            [%g5] ASI_DMMU, %g5     ! Get SFAR
+       ldxa            [%g3] ASI_IMMU, %g4     ! Get SFSR
+       rdpr            %tpc, %g5               ! IMMU has no SFAR, use TPC
        stxa            %g0, [%g3] ASI_IMMU     ! Clear FaultValid bit
        membar          #Sync
        sethi           %hi(109f), %g7
@@ -743,18 +904,17 @@ __do_instruction_access_exception_tl1:
 109:    or             %g7, %lo(109b), %g7
        mov             %l4, %o1
        mov             %l5, %o2
-       call            instruction_access_exception_tl1
+       call            spitfire_insn_access_exception_tl1
         add            %sp, PTREGS_OFF, %o0
        ba,pt           %xcc, rtrap
         clr            %l6
 
-__do_instruction_access_exception:
+__spitfire_insn_access_exception:
        rdpr            %pstate, %g4
        wrpr            %g4, PSTATE_MG|PSTATE_AG, %pstate
        mov             TLB_SFSR, %g3
-       mov             DMMU_SFAR, %g5
-       ldxa            [%g3] ASI_DMMU, %g4     ! Get SFSR
-       ldxa            [%g5] ASI_DMMU, %g5     ! Get SFAR
+       ldxa            [%g3] ASI_IMMU, %g4     ! Get SFSR
+       rdpr            %tpc, %g5               ! IMMU has no SFAR, use TPC
        stxa            %g0, [%g3] ASI_IMMU     ! Clear FaultValid bit
        membar          #Sync
        sethi           %hi(109f), %g7
@@ -762,235 +922,11 @@ __do_instruction_access_exception:
 109:    or             %g7, %lo(109b), %g7
        mov             %l4, %o1
        mov             %l5, %o2
-       call            instruction_access_exception
+       call            spitfire_insn_access_exception
         add            %sp, PTREGS_OFF, %o0
        ba,pt           %xcc, rtrap
         clr            %l6
 
-       /* This is the trap handler entry point for ECC correctable
-        * errors.  They are corrected, but we listen for the trap
-        * so that the event can be logged.
-        *
-        * Disrupting errors are either:
-        * 1) single-bit ECC errors during UDB reads to system
-        *    memory
-        * 2) data parity errors during write-back events
-        *
-        * As far as I can make out from the manual, the CEE trap
-        * is only for correctable errors during memory read
-        * accesses by the front-end of the processor.
-        *
-        * The code below is only for trap level 1 CEE events,
-        * as it is the only situation where we can safely record
-        * and log.  For trap level >1 we just clear the CE bit
-        * in the AFSR and return.
-        */
-
-       /* Our trap handling infrastructure allows us to preserve
-        * two 64-bit values during etrap for arguments to
-        * subsequent C code.  Therefore we encode the information
-        * as follows:
-        *
-        * value 1) Full 64-bits of AFAR
-        * value 2) Low 33-bits of AFSR, then bits 33-->42
-        *          are UDBL error status and bits 43-->52
-        *          are UDBH error status
-        */
-       .align  64
-       .globl  cee_trap
-cee_trap:
-       ldxa    [%g0] ASI_AFSR, %g1             ! Read AFSR
-       ldxa    [%g0] ASI_AFAR, %g2             ! Read AFAR
-       sllx    %g1, 31, %g1                    ! Clear reserved bits
-       srlx    %g1, 31, %g1                    ! in AFSR
-
-       /* NOTE: UltraSparc-I/II have high and low UDB error
-        *       registers, corresponding to the two UDB units
-        *       present on those chips.  UltraSparc-IIi only
-        *       has a single UDB, called "SDB" in the manual.
-        *       For IIi the upper UDB register always reads
-        *       as zero so for our purposes things will just
-        *       work with the checks below.
-        */
-       ldxa    [%g0] ASI_UDBL_ERROR_R, %g3     ! Read UDB-Low error status
-       andcc   %g3, (1 << 8), %g4              ! Check CE bit
-       sllx    %g3, (64 - 10), %g3             ! Clear reserved bits
-       srlx    %g3, (64 - 10), %g3             ! in UDB-Low error status
-
-       sllx    %g3, (33 + 0), %g3              ! Shift up to encoding area
-       or      %g1, %g3, %g1                   ! Or it in
-       be,pn   %xcc, 1f                        ! Branch if CE bit was clear
-        nop
-       stxa    %g4, [%g0] ASI_UDB_ERROR_W      ! Clear CE sticky bit in UDBL
-       membar  #Sync                           ! Synchronize ASI stores
-1:     mov     0x18, %g5                       ! Addr of UDB-High error status
-       ldxa    [%g5] ASI_UDBH_ERROR_R, %g3     ! Read it
-
-       andcc   %g3, (1 << 8), %g4              ! Check CE bit
-       sllx    %g3, (64 - 10), %g3             ! Clear reserved bits
-       srlx    %g3, (64 - 10), %g3             ! in UDB-High error status
-       sllx    %g3, (33 + 10), %g3             ! Shift up to encoding area
-       or      %g1, %g3, %g1                   ! Or it in
-       be,pn   %xcc, 1f                        ! Branch if CE bit was clear
-        nop
-       nop
-
-       stxa    %g4, [%g5] ASI_UDB_ERROR_W      ! Clear CE sticky bit in UDBH
-       membar  #Sync                           ! Synchronize ASI stores
-1:     mov     1, %g5                          ! AFSR CE bit is
-       sllx    %g5, 20, %g5                    ! bit 20
-       stxa    %g5, [%g0] ASI_AFSR             ! Clear CE sticky bit in AFSR
-       membar  #Sync                           ! Synchronize ASI stores
-       sllx    %g2, (64 - 41), %g2             ! Clear reserved bits
-       srlx    %g2, (64 - 41), %g2             ! in latched AFAR
-
-       andn    %g2, 0x0f, %g2                  ! Finish resv bit clearing
-       mov     %g1, %g4                        ! Move AFSR+UDB* into save reg
-       mov     %g2, %g5                        ! Move AFAR into save reg
-       rdpr    %pil, %g2
-       wrpr    %g0, 15, %pil
-       ba,pt   %xcc, etrap_irq
-        rd     %pc, %g7
-       mov     %l4, %o0
-
-       mov     %l5, %o1
-       call    cee_log
-        add    %sp, PTREGS_OFF, %o2
-       ba,a,pt %xcc, rtrap_irq
-
-       /* Capture I/D/E-cache state into per-cpu error scoreboard.
-        *
-        * %g1:         (TL>=0) ? 1 : 0
-        * %g2:         scratch
-        * %g3:         scratch
-        * %g4:         AFSR
-        * %g5:         AFAR
-        * %g6:         current thread ptr
-        * %g7:         scratch
-        */
-#define CHEETAH_LOG_ERROR                                              \
-       /* Put "TL1" software bit into AFSR. */                         \
-       and             %g1, 0x1, %g1;                                  \
-       sllx            %g1, 63, %g2;                                   \
-       or              %g4, %g2, %g4;                                  \
-       /* Get log entry pointer for this cpu at this trap level. */    \
-       BRANCH_IF_JALAPENO(g2,g3,50f)                                   \
-       ldxa            [%g0] ASI_SAFARI_CONFIG, %g2;                   \
-       srlx            %g2, 17, %g2;                                   \
-       ba,pt           %xcc, 60f;                                      \
-        and            %g2, 0x3ff, %g2;                                \
-50:    ldxa            [%g0] ASI_JBUS_CONFIG, %g2;                     \
-       srlx            %g2, 17, %g2;                                   \
-       and             %g2, 0x1f, %g2;                                 \
-60:    sllx            %g2, 9, %g2;                                    \
-       sethi           %hi(cheetah_error_log), %g3;                    \
-       ldx             [%g3 + %lo(cheetah_error_log)], %g3;            \
-       brz,pn          %g3, 80f;                                       \
-        nop;                                                           \
-       add             %g3, %g2, %g3;                                  \
-       sllx            %g1, 8, %g1;                                    \
-       add             %g3, %g1, %g1;                                  \
-       /* %g1 holds pointer to the top of the logging scoreboard */    \
-       ldx             [%g1 + 0x0], %g7;                               \
-       cmp             %g7, -1;                                        \
-       bne,pn          %xcc, 80f;                                      \
-        nop;                                                           \
-       stx             %g4, [%g1 + 0x0];                               \
-       stx             %g5, [%g1 + 0x8];                               \
-       add             %g1, 0x10, %g1;                                 \
-       /* %g1 now points to D-cache logging area */                    \
-       set             0x3ff8, %g2;    /* DC_addr mask         */      \
-       and             %g5, %g2, %g2;  /* DC_addr bits of AFAR */      \
-       srlx            %g5, 12, %g3;                                   \
-       or              %g3, 1, %g3;    /* PHYS tag + valid     */      \
-10:    ldxa            [%g2] ASI_DCACHE_TAG, %g7;                      \
-       cmp             %g3, %g7;       /* TAG match?           */      \
-       bne,pt          %xcc, 13f;                                      \
-        nop;                                                           \
-       /* Yep, what we want, capture state. */                         \
-       stx             %g2, [%g1 + 0x20];                              \
-       stx             %g7, [%g1 + 0x28];                              \
-       /* A membar Sync is required before and after utag access. */   \
-       membar          #Sync;                                          \
-       ldxa            [%g2] ASI_DCACHE_UTAG, %g7;                     \
-       membar          #Sync;                                          \
-       stx             %g7, [%g1 + 0x30];                              \
-       ldxa            [%g2] ASI_DCACHE_SNOOP_TAG, %g7;                \
-       stx             %g7, [%g1 + 0x38];                              \
-       clr             %g3;                                            \
-12:    ldxa            [%g2 + %g3] ASI_DCACHE_DATA, %g7;               \
-       stx             %g7, [%g1];                                     \
-       add             %g3, (1 << 5), %g3;                             \
-       cmp             %g3, (4 << 5);                                  \
-       bl,pt           %xcc, 12b;                                      \
-        add            %g1, 0x8, %g1;                                  \
-       ba,pt           %xcc, 20f;                                      \
-        add            %g1, 0x20, %g1;                                 \
-13:    sethi           %hi(1 << 14), %g7;                              \
-       add             %g2, %g7, %g2;                                  \
-       srlx            %g2, 14, %g7;                                   \
-       cmp             %g7, 4;                                         \
-       bl,pt           %xcc, 10b;                                      \
-        nop;                                                           \
-       add             %g1, 0x40, %g1;                                 \
-20:    /* %g1 now points to I-cache logging area */                    \
-       set             0x1fe0, %g2;    /* IC_addr mask         */      \
-       and             %g5, %g2, %g2;  /* IC_addr bits of AFAR */      \
-       sllx            %g2, 1, %g2;    /* IC_addr[13:6]==VA[12:5] */   \
-       srlx            %g5, (13 - 8), %g3; /* Make PTAG */             \
-       andn            %g3, 0xff, %g3; /* Mask off undefined bits */   \
-21:    ldxa            [%g2] ASI_IC_TAG, %g7;                          \
-       andn            %g7, 0xff, %g7;                                 \
-       cmp             %g3, %g7;                                       \
-       bne,pt          %xcc, 23f;                                      \
-        nop;                                                           \
-       /* Yep, what we want, capture state. */                         \
-       stx             %g2, [%g1 + 0x40];                              \
-       stx             %g7, [%g1 + 0x48];                              \
-       add             %g2, (1 << 3), %g2;                             \
-       ldxa            [%g2] ASI_IC_TAG, %g7;                          \
-       add             %g2, (1 << 3), %g2;                             \
-       stx             %g7, [%g1 + 0x50];                              \
-       ldxa            [%g2] ASI_IC_TAG, %g7;                          \
-       add             %g2, (1 << 3), %g2;                             \
-       stx             %g7, [%g1 + 0x60];                              \
-       ldxa            [%g2] ASI_IC_TAG, %g7;                          \
-       stx             %g7, [%g1 + 0x68];                              \
-       sub             %g2, (3 << 3), %g2;                             \
-       ldxa            [%g2] ASI_IC_STAG, %g7;                         \
-       stx             %g7, [%g1 + 0x58];                              \
-       clr             %g3;                                            \
-       srlx            %g2, 2, %g2;                                    \
-22:    ldxa            [%g2 + %g3] ASI_IC_INSTR, %g7;                  \
-       stx             %g7, [%g1];                                     \
-       add             %g3, (1 << 3), %g3;                             \
-       cmp             %g3, (8 << 3);                                  \
-       bl,pt           %xcc, 22b;                                      \
-        add            %g1, 0x8, %g1;                                  \
-       ba,pt           %xcc, 30f;                                      \
-        add            %g1, 0x30, %g1;                                 \
-23:    sethi           %hi(1 << 14), %g7;                              \
-       add             %g2, %g7, %g2;                                  \
-       srlx            %g2, 14, %g7;                                   \
-       cmp             %g7, 4;                                         \
-       bl,pt           %xcc, 21b;                                      \
-        nop;                                                           \
-       add             %g1, 0x70, %g1;                                 \
-30:    /* %g1 now points to E-cache logging area */                    \
-       andn            %g5, (32 - 1), %g2;     /* E-cache subblock */  \
-       stx             %g2, [%g1 + 0x20];                              \
-       ldxa            [%g2] ASI_EC_TAG_DATA, %g7;                     \
-       stx             %g7, [%g1 + 0x28];                              \
-       ldxa            [%g2] ASI_EC_R, %g0;                            \
-       clr             %g3;                                            \
-31:    ldxa            [%g3] ASI_EC_DATA, %g7;                         \
-       stx             %g7, [%g1 + %g3];                               \
-       add             %g3, 0x8, %g3;                                  \
-       cmp             %g3, 0x20;                                      \
-       bl,pt           %xcc, 31b;                                      \
-        nop;                                                           \
-80:    /* DONE */
-
        /* These get patched into the trap table at boot time
         * once we know we have a cheetah processor.
         */
@@ -1227,6 +1163,170 @@ dcpe_icpe_tl1_common:
        membar          #Sync
        retry
 
+       /* Capture I/D/E-cache state into per-cpu error scoreboard.
+        *
+        * %g1:         (TL>=0) ? 1 : 0
+        * %g2:         scratch
+        * %g3:         scratch
+        * %g4:         AFSR
+        * %g5:         AFAR
+        * %g6:         current thread ptr
+        * %g7:         scratch
+        */
+__cheetah_log_error:
+       /* Put "TL1" software bit into AFSR. */
+       and             %g1, 0x1, %g1
+       sllx            %g1, 63, %g2
+       or              %g4, %g2, %g4
+
+       /* Get log entry pointer for this cpu at this trap level. */
+       BRANCH_IF_JALAPENO(g2,g3,50f)
+       ldxa            [%g0] ASI_SAFARI_CONFIG, %g2
+       srlx            %g2, 17, %g2
+       ba,pt           %xcc, 60f
+        and            %g2, 0x3ff, %g2
+
+50:    ldxa            [%g0] ASI_JBUS_CONFIG, %g2
+       srlx            %g2, 17, %g2
+       and             %g2, 0x1f, %g2
+
+60:    sllx            %g2, 9, %g2
+       sethi           %hi(cheetah_error_log), %g3
+       ldx             [%g3 + %lo(cheetah_error_log)], %g3
+       brz,pn          %g3, 80f
+        nop
+
+       add             %g3, %g2, %g3
+       sllx            %g1, 8, %g1
+       add             %g3, %g1, %g1
+
+       /* %g1 holds pointer to the top of the logging scoreboard */
+       ldx             [%g1 + 0x0], %g7
+       cmp             %g7, -1
+       bne,pn          %xcc, 80f
+        nop
+
+       stx             %g4, [%g1 + 0x0]
+       stx             %g5, [%g1 + 0x8]
+       add             %g1, 0x10, %g1
+
+       /* %g1 now points to D-cache logging area */
+       set             0x3ff8, %g2     /* DC_addr mask         */
+       and             %g5, %g2, %g2   /* DC_addr bits of AFAR */
+       srlx            %g5, 12, %g3
+       or              %g3, 1, %g3     /* PHYS tag + valid     */
+
+10:    ldxa            [%g2] ASI_DCACHE_TAG, %g7
+       cmp             %g3, %g7        /* TAG match?           */
+       bne,pt          %xcc, 13f
+        nop
+
+       /* Yep, what we want, capture state. */
+       stx             %g2, [%g1 + 0x20]
+       stx             %g7, [%g1 + 0x28]
+
+       /* A membar Sync is required before and after utag access. */
+       membar          #Sync
+       ldxa            [%g2] ASI_DCACHE_UTAG, %g7
+       membar          #Sync
+       stx             %g7, [%g1 + 0x30]
+       ldxa            [%g2] ASI_DCACHE_SNOOP_TAG, %g7
+       stx             %g7, [%g1 + 0x38]
+       clr             %g3
+
+12:    ldxa            [%g2 + %g3] ASI_DCACHE_DATA, %g7
+       stx             %g7, [%g1]
+       add             %g3, (1 << 5), %g3
+       cmp             %g3, (4 << 5)
+       bl,pt           %xcc, 12b
+        add            %g1, 0x8, %g1
+
+       ba,pt           %xcc, 20f
+        add            %g1, 0x20, %g1
+
+13:    sethi           %hi(1 << 14), %g7
+       add             %g2, %g7, %g2
+       srlx            %g2, 14, %g7
+       cmp             %g7, 4
+       bl,pt           %xcc, 10b
+        nop
+
+       add             %g1, 0x40, %g1
+
+       /* %g1 now points to I-cache logging area */
+20:    set             0x1fe0, %g2     /* IC_addr mask         */
+       and             %g5, %g2, %g2   /* IC_addr bits of AFAR */
+       sllx            %g2, 1, %g2     /* IC_addr[13:6]==VA[12:5] */
+       srlx            %g5, (13 - 8), %g3 /* Make PTAG */
+       andn            %g3, 0xff, %g3  /* Mask off undefined bits */
+
+21:    ldxa            [%g2] ASI_IC_TAG, %g7
+       andn            %g7, 0xff, %g7
+       cmp             %g3, %g7
+       bne,pt          %xcc, 23f
+        nop
+
+       /* Yep, what we want, capture state. */
+       stx             %g2, [%g1 + 0x40]
+       stx             %g7, [%g1 + 0x48]
+       add             %g2, (1 << 3), %g2
+       ldxa            [%g2] ASI_IC_TAG, %g7
+       add             %g2, (1 << 3), %g2
+       stx             %g7, [%g1 + 0x50]
+       ldxa            [%g2] ASI_IC_TAG, %g7
+       add             %g2, (1 << 3), %g2
+       stx             %g7, [%g1 + 0x60]
+       ldxa            [%g2] ASI_IC_TAG, %g7
+       stx             %g7, [%g1 + 0x68]
+       sub             %g2, (3 << 3), %g2
+       ldxa            [%g2] ASI_IC_STAG, %g7
+       stx             %g7, [%g1 + 0x58]
+       clr             %g3
+       srlx            %g2, 2, %g2
+
+22:    ldxa            [%g2 + %g3] ASI_IC_INSTR, %g7
+       stx             %g7, [%g1]
+       add             %g3, (1 << 3), %g3
+       cmp             %g3, (8 << 3)
+       bl,pt           %xcc, 22b
+        add            %g1, 0x8, %g1
+
+       ba,pt           %xcc, 30f
+        add            %g1, 0x30, %g1
+
+23:    sethi           %hi(1 << 14), %g7
+       add             %g2, %g7, %g2
+       srlx            %g2, 14, %g7
+       cmp             %g7, 4
+       bl,pt           %xcc, 21b
+        nop
+
+       add             %g1, 0x70, %g1
+
+       /* %g1 now points to E-cache logging area */
+30:    andn            %g5, (32 - 1), %g2
+       stx             %g2, [%g1 + 0x20]
+       ldxa            [%g2] ASI_EC_TAG_DATA, %g7
+       stx             %g7, [%g1 + 0x28]
+       ldxa            [%g2] ASI_EC_R, %g0
+       clr             %g3
+
+31:    ldxa            [%g3] ASI_EC_DATA, %g7
+       stx             %g7, [%g1 + %g3]
+       add             %g3, 0x8, %g3
+       cmp             %g3, 0x20
+
+       bl,pt           %xcc, 31b
+        nop
+80:
+       rdpr            %tt, %g2
+       cmp             %g2, 0x70
+       be              c_fast_ecc
+        cmp            %g2, 0x63
+       be              c_cee
+        nop
+       ba,pt           %xcc, c_deferred
+
        /* Cheetah FECC trap handling, we get here from tl{0,1}_fecc
         * in the trap table.  That code has done a memory barrier
         * and has disabled both the I-cache and D-cache in the DCU
@@ -1252,8 +1352,10 @@ cheetah_fast_ecc:
        stxa            %g4, [%g0] ASI_AFSR
        membar          #Sync
 
-       CHEETAH_LOG_ERROR
+       ba,pt           %xcc, __cheetah_log_error
+        nop
 
+c_fast_ecc:
        rdpr            %pil, %g2
        wrpr            %g0, 15, %pil
        ba,pt           %xcc, etrap_irq
@@ -1278,8 +1380,10 @@ cheetah_cee:
        stxa            %g4, [%g0] ASI_AFSR
        membar          #Sync
 
-       CHEETAH_LOG_ERROR
+       ba,pt           %xcc, __cheetah_log_error
+        nop
 
+c_cee:
        rdpr            %pil, %g2
        wrpr            %g0, 15, %pil
        ba,pt           %xcc, etrap_irq
@@ -1304,8 +1408,10 @@ cheetah_deferred_trap:
        stxa            %g4, [%g0] ASI_AFSR
        membar          #Sync
 
-       CHEETAH_LOG_ERROR
+       ba,pt           %xcc, __cheetah_log_error
+        nop
 
+c_deferred:
        rdpr            %pil, %g2
        wrpr            %g0, 15, %pil
        ba,pt           %xcc, etrap_irq
index 8104a56ca2d8e779b7999cf14d62db03155f8129..1fa06c4e3bdb8da1c5496dc14fa5547a69fe79f0 100644 (file)
@@ -538,11 +538,12 @@ cheetah_tlb_fixup:
         nop
        call    cheetah_plus_patch_winfixup
         nop
-       
 
 2:     /* Patch copy/page operations to cheetah optimized versions. */
        call    cheetah_patch_copyops
         nop
+       call    cheetah_patch_copy_page
+        nop
        call    cheetah_patch_cachetlbops
         nop
 
index bbf11f85dab15a00a05c4c9d11774a8f93776c13..0d66d07c8c6eead89fa6e5799ec6ba5fcf57873f 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/kprobes.h>
 #include <asm/kdebug.h>
 #include <asm/signal.h>
+#include <asm/cacheflush.h>
 
 /* We do not have hardware single-stepping on sparc64.
  * So we implement software single-stepping with breakpoint
  * - Mark that we are no longer actively in a kprobe.
  */
 
-int arch_prepare_kprobe(struct kprobe *p)
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
 {
        return 0;
 }
 
-void arch_copy_kprobe(struct kprobe *p)
+void __kprobes arch_copy_kprobe(struct kprobe *p)
 {
        p->ainsn.insn[0] = *p->addr;
        p->ainsn.insn[1] = BREAKPOINT_INSTRUCTION_2;
        p->opcode = *p->addr;
 }
 
-void arch_arm_kprobe(struct kprobe *p)
+void __kprobes arch_arm_kprobe(struct kprobe *p)
 {
        *p->addr = BREAKPOINT_INSTRUCTION;
        flushi(p->addr);
 }
 
-void arch_disarm_kprobe(struct kprobe *p)
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
 {
        *p->addr = p->opcode;
        flushi(p->addr);
 }
 
-void arch_remove_kprobe(struct kprobe *p)
+void __kprobes arch_remove_kprobe(struct kprobe *p)
 {
 }
 
@@ -111,7 +112,7 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
        }
 }
 
-static int kprobe_handler(struct pt_regs *regs)
+static int __kprobes kprobe_handler(struct pt_regs *regs)
 {
        struct kprobe *p;
        void *addr = (void *) regs->tpc;
@@ -191,8 +192,9 @@ no_kprobe:
  * The original INSN location was REAL_PC, it actually
  * executed at PC and produced destination address NPC.
  */
-static unsigned long relbranch_fixup(u32 insn, unsigned long real_pc,
-                                    unsigned long pc, unsigned long npc)
+static unsigned long __kprobes relbranch_fixup(u32 insn, unsigned long real_pc,
+                                              unsigned long pc,
+                                              unsigned long npc)
 {
        /* Branch not taken, no mods necessary.  */
        if (npc == pc + 0x4UL)
@@ -217,7 +219,8 @@ static unsigned long relbranch_fixup(u32 insn, unsigned long real_pc,
 /* If INSN is an instruction which writes it's PC location
  * into a destination register, fix that up.
  */
-static void retpc_fixup(struct pt_regs *regs, u32 insn, unsigned long real_pc)
+static void __kprobes retpc_fixup(struct pt_regs *regs, u32 insn,
+                                 unsigned long real_pc)
 {
        unsigned long *slot = NULL;
 
@@ -257,7 +260,7 @@ static void retpc_fixup(struct pt_regs *regs, u32 insn, unsigned long real_pc)
  * This function prepares to return from the post-single-step
  * breakpoint trap.
  */
-static void resume_execution(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
 {
        u32 insn = p->ainsn.insn[0];
 
@@ -315,8 +318,8 @@ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
 /*
  * Wrapper routine to for handling exceptions.
  */
-int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
-                            void *data)
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+                                      unsigned long val, void *data)
 {
        struct die_args *args = (struct die_args *)data;
        switch (val) {
@@ -344,7 +347,8 @@ int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
        return NOTIFY_DONE;
 }
 
-asmlinkage void kprobe_trap(unsigned long trap_level, struct pt_regs *regs)
+asmlinkage void __kprobes kprobe_trap(unsigned long trap_level,
+                                     struct pt_regs *regs)
 {
        BUG_ON(trap_level != 0x170 && trap_level != 0x171);
 
@@ -368,7 +372,7 @@ static struct pt_regs jprobe_saved_regs;
 static struct pt_regs *jprobe_saved_regs_location;
 static struct sparc_stackf jprobe_saved_stack;
 
-int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 {
        struct jprobe *jp = container_of(p, struct jprobe, kp);
 
@@ -390,7 +394,7 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
        return 1;
 }
 
-void jprobe_return(void)
+void __kprobes jprobe_return(void)
 {
        preempt_enable_no_resched();
        __asm__ __volatile__(
@@ -403,7 +407,7 @@ extern void jprobe_return_trap_instruction(void);
 
 extern void __show_regs(struct pt_regs * regs);
 
-int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 {
        u32 *addr = (u32 *) regs->tpc;
 
index f21c993f885616cf963e8fe804b7303ecdc1e6bc..ec8bf4012c0c411b66505727387d38a57f43fdc3 100644 (file)
@@ -736,8 +736,7 @@ static void __pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma
 static void __pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
                                             enum pci_mmap_state mmap_state)
 {
-       /* Our io_remap_page_range/io_remap_pfn_range takes care of this,
-          do nothing. */
+       /* Our io_remap_pfn_range takes care of this, do nothing.  */
 }
 
 /* Perform the actual remap of the pages for a PCI device mapping, as appropriate
index 2803bc7c2c798af12fc0d57b701991bc51727995..425c60cfea195a2b57f4931ceb42a5cb94b970f1 100644 (file)
@@ -466,7 +466,7 @@ do_flush_sync:
                if (!limit)
                        break;
                udelay(1);
-               membar("#LoadLoad");
+               rmb();
        }
        if (!limit)
                printk(KERN_WARNING "pci_strbuf_flush: flushflag timeout "
index 07424b075938b7651e53380cddcf712c42b324e0..66255434128a2e6ebf6b144d5d030003fe4ebaca 100644 (file)
@@ -103,7 +103,7 @@ void cpu_idle(void)
                 * other cpus see our increasing idleness for the buddy
                 * redistribution algorithm.  -DaveM
                 */
-               membar("#StoreStore | #StoreLoad");
+               membar_storeload_storestore();
        }
 }
 
index 0696ed4b9d644f01aef775f2a92aad1e67ea4a13..fafd227735fa1d13b79f8b97e74aa6b3d81f2715 100644 (file)
@@ -153,11 +153,14 @@ __handle_signal:
 rtrap_irq:
 rtrap_clr_l6:  clr                     %l6
 rtrap:
-               ldub                    [%g6 + TI_CPU], %l0
-               sethi                   %hi(irq_stat), %l2      ! &softirq_active
-               or                      %l2, %lo(irq_stat), %l2 ! &softirq_active
-irqsz_patchme: sllx                    %l0, 0, %l0
-               lduw                    [%l2 + %l0], %l1        ! softirq_pending
+#ifndef CONFIG_SMP
+               sethi                   %hi(per_cpu____cpu_data), %l0
+               lduw                    [%l0 + %lo(per_cpu____cpu_data)], %l1
+#else
+               sethi                   %hi(per_cpu____cpu_data), %l0
+               or                      %l0, %lo(per_cpu____cpu_data), %l0
+               lduw                    [%l0 + %g5], %l1
+#endif
                cmp                     %l1, 0
 
                /* mm/ultra.S:xcall_report_regs KNOWS about this load. */
index 89f5e019f24c02ade1ed11ab0c6ed721de1b4bfd..e09ddf927655e4f608bdf0cae6e349a26cf6f172 100644 (file)
@@ -147,7 +147,7 @@ static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long
                if (!limit)
                        break;
                udelay(1);
-               membar("#LoadLoad");
+               rmb();
        }
        if (!limit)
                printk(KERN_WARNING "sbus_strbuf_flush: flushflag timeout "
index b7e6a91952b213dacfe1ce43e2497df4192de634..ddbed3341a232770b7c929291fc4f959862d9a17 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/cpu.h>
 #include <linux/initrd.h>
 
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/processor.h>
@@ -512,18 +511,6 @@ void __init setup_arch(char **cmdline_p)
        conswitchp = &prom_con;
 #endif
 
-#ifdef CONFIG_SMP
-       i = (unsigned long)&irq_stat[1] - (unsigned long)&irq_stat[0];
-       if ((i == SMP_CACHE_BYTES) || (i == (2 * SMP_CACHE_BYTES))) {
-               extern unsigned int irqsz_patchme[1];
-               irqsz_patchme[0] |= ((i == SMP_CACHE_BYTES) ? SMP_CACHE_BYTES_SHIFT : \
-                                                       SMP_CACHE_BYTES_SHIFT + 1);
-               flushi((long)&irqsz_patchme[0]);
-       } else {
-               prom_printf("Unexpected size of irq_stat[] elements\n");
-               prom_halt();
-       }
-#endif
        /* Work out if we are starfire early on */
        check_if_starfire();
 
index b27934671c35324b713d355b6119541b3c8e69df..60f5dfabb1e173bcc08064c54cd64addf16c5030 100644 (file)
@@ -574,13 +574,12 @@ static inline void handle_signal(unsigned long signr, struct k_sigaction *ka,
 {
        setup_rt_frame(ka, regs, signr, oldset,
                       (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL);
-       if (!(ka->sa.sa_flags & SA_NOMASK)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NOMASK))
                sigaddset(&current->blocked,signr);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
index f28428f4170e67449259ce79e6a6ab1b0da6b2ca..aecccd0df1d129a6981ae85d86ef87d11bf47638 100644 (file)
@@ -877,11 +877,12 @@ static void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
                        unsigned long page = (unsigned long)
                                page_address(pte_page(*ptep));
 
-                       __asm__ __volatile__(
-                       "       membar  #StoreStore\n"
-                       "       flush   %0 + %1"
-                       : : "r" (page), "r" (address & (PAGE_SIZE - 1))
-                       : "memory");
+                       wmb();
+                       __asm__ __volatile__("flush     %0 + %1"
+                                            : /* no outputs */
+                                            : "r" (page),
+                                              "r" (address & (PAGE_SIZE - 1))
+                                            : "memory");
                }
                pte_unmap(ptep);
                preempt_enable();
@@ -1292,11 +1293,12 @@ static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
                        unsigned long page = (unsigned long)
                                page_address(pte_page(*ptep));
 
-                       __asm__ __volatile__(
-                       "       membar  #StoreStore\n"
-                       "       flush   %0 + %1"
-                       : : "r" (page), "r" (address & (PAGE_SIZE - 1))
-                       : "memory");
+                       wmb();
+                       __asm__ __volatile__("flush     %0 + %1"
+                                            : /* no outputs */
+                                            : "r" (page),
+                                              "r" (address & (PAGE_SIZE - 1))
+                                            : "memory");
                }
                pte_unmap(ptep);
                preempt_enable();
@@ -1325,13 +1327,12 @@ static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
                else
                        setup_frame32(&ka->sa, regs, signr, oldset, info);
        }
-       if (!(ka->sa.sa_flags & SA_NOMASK)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NOMASK))
                sigaddset(&current->blocked,signr);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs,
index b9b42491e118b6e273f40889de677ffb5d98cc1f..b4fc6a5462b2192065052a1693d194e375066910 100644 (file)
@@ -144,7 +144,7 @@ void __init smp_callin(void)
        current->active_mm = &init_mm;
 
        while (!cpu_isset(cpuid, smp_commenced_mask))
-               membar("#LoadLoad");
+               rmb();
 
        cpu_set(cpuid, cpu_online_map);
 }
@@ -184,11 +184,11 @@ static inline long get_delta (long *rt, long *master)
        for (i = 0; i < NUM_ITERS; i++) {
                t0 = tick_ops->get_tick();
                go[MASTER] = 1;
-               membar("#StoreLoad");
+               membar_storeload();
                while (!(tm = go[SLAVE]))
-                       membar("#LoadLoad");
+                       rmb();
                go[SLAVE] = 0;
-               membar("#StoreStore");
+               wmb();
                t1 = tick_ops->get_tick();
 
                if (t1 - t0 < best_t1 - best_t0)
@@ -221,7 +221,7 @@ void smp_synchronize_tick_client(void)
        go[MASTER] = 1;
 
        while (go[MASTER])
-               membar("#LoadLoad");
+               rmb();
 
        local_irq_save(flags);
        {
@@ -273,21 +273,21 @@ static void smp_synchronize_one_tick(int cpu)
 
        /* wait for client to be ready */
        while (!go[MASTER])
-               membar("#LoadLoad");
+               rmb();
 
        /* now let the client proceed into his loop */
        go[MASTER] = 0;
-       membar("#StoreLoad");
+       membar_storeload();
 
        spin_lock_irqsave(&itc_sync_lock, flags);
        {
                for (i = 0; i < NUM_ROUNDS*NUM_ITERS; i++) {
                        while (!go[MASTER])
-                               membar("#LoadLoad");
+                               rmb();
                        go[MASTER] = 0;
-                       membar("#StoreStore");
+                       wmb();
                        go[SLAVE] = tick_ops->get_tick();
-                       membar("#StoreLoad");
+                       membar_storeload();
                }
        }
        spin_unlock_irqrestore(&itc_sync_lock, flags);
@@ -927,11 +927,11 @@ void smp_capture(void)
                       smp_processor_id());
 #endif
                penguins_are_doing_time = 1;
-               membar("#StoreStore | #LoadStore");
+               membar_storestore_loadstore();
                atomic_inc(&smp_capture_registry);
                smp_cross_call(&xcall_capture, 0, 0, 0);
                while (atomic_read(&smp_capture_registry) != ncpus)
-                       membar("#LoadLoad");
+                       rmb();
 #ifdef CAPTURE_DEBUG
                printk("done\n");
 #endif
@@ -947,7 +947,7 @@ void smp_release(void)
                       smp_processor_id());
 #endif
                penguins_are_doing_time = 0;
-               membar("#StoreStore | #StoreLoad");
+               membar_storeload_storestore();
                atomic_dec(&smp_capture_registry);
        }
 }
@@ -970,9 +970,9 @@ void smp_penguin_jailcell(int irq, struct pt_regs *regs)
        save_alternate_globals(global_save);
        prom_world(1);
        atomic_inc(&smp_capture_registry);
-       membar("#StoreLoad | #StoreStore");
+       membar_storeload_storestore();
        while (penguins_are_doing_time)
-               membar("#LoadLoad");
+               rmb();
        restore_alternate_globals(global_save);
        atomic_dec(&smp_capture_registry);
        prom_world(0);
index 9202d925a9ce6961816b5920f5cd9e5bc8758c58..d89fc24808d3eccd137db229c0bef7438b19ec7a 100644 (file)
@@ -88,8 +88,6 @@ extern int svr4_setcontext(svr4_ucontext_t *uc, struct pt_regs *regs);
 extern int compat_sys_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
 extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *);
 extern long sparc32_open(const char __user * filename, int flags, int mode);
-extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from,
-       unsigned long offset, unsigned long size, pgprot_t prot, int space);
 extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
        unsigned long pfn, unsigned long size, pgprot_t prot);
 extern void (*prom_palette)(int);
@@ -99,17 +97,6 @@ extern int __ashrdi3(int, int);
 extern void dump_thread(struct pt_regs *, struct user *);
 extern int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs);
 
-#if defined(CONFIG_SMP) && defined(CONFIG_DEBUG_SPINLOCK)
-extern void _do_spin_lock (spinlock_t *lock, char *str);
-extern void _do_spin_unlock (spinlock_t *lock);
-extern int _spin_trylock (spinlock_t *lock);
-extern void _do_read_lock(rwlock_t *rw, char *str);
-extern void _do_read_unlock(rwlock_t *rw, char *str);
-extern void _do_write_lock(rwlock_t *rw, char *str);
-extern void _do_write_unlock(rwlock_t *rw);
-extern int _do_write_trylock(rwlock_t *rw, char *str);
-#endif
-
 extern unsigned long phys_base;
 extern unsigned long pfn_base;
 
@@ -152,18 +139,6 @@ EXPORT_SYMBOL(_mcount);
 EXPORT_SYMBOL(cpu_online_map);
 EXPORT_SYMBOL(phys_cpu_present_map);
 
-/* Spinlock debugging library, optional. */
-#ifdef CONFIG_DEBUG_SPINLOCK
-EXPORT_SYMBOL(_do_spin_lock);
-EXPORT_SYMBOL(_do_spin_unlock);
-EXPORT_SYMBOL(_spin_trylock);
-EXPORT_SYMBOL(_do_read_lock);
-EXPORT_SYMBOL(_do_read_unlock);
-EXPORT_SYMBOL(_do_write_lock);
-EXPORT_SYMBOL(_do_write_unlock);
-EXPORT_SYMBOL(_do_write_trylock);
-#endif
-
 EXPORT_SYMBOL(smp_call_function);
 #endif /* CONFIG_SMP */
 
@@ -268,7 +243,6 @@ EXPORT_SYMBOL(pci_dma_supported);
 #endif
 
 /* I/O device mmaping on Sparc64. */
-EXPORT_SYMBOL(io_remap_page_range);
 EXPORT_SYMBOL(io_remap_pfn_range);
 
 /* Solaris/SunOS binary compatibility */
@@ -429,3 +403,12 @@ EXPORT_SYMBOL(xor_vis_4);
 EXPORT_SYMBOL(xor_vis_5);
 
 EXPORT_SYMBOL(prom_palette);
+
+/* memory barriers */
+EXPORT_SYMBOL(mb);
+EXPORT_SYMBOL(rmb);
+EXPORT_SYMBOL(wmb);
+EXPORT_SYMBOL(membar_storeload);
+EXPORT_SYMBOL(membar_storeload_storestore);
+EXPORT_SYMBOL(membar_storeload_loadload);
+EXPORT_SYMBOL(membar_storestore_loadstore);
index 87c1aeb022204eac4faedfb1fc58e0b9e18920e5..7654b8a7f03a6ffb400ac8bbb27a8a02aab82d68 100644 (file)
@@ -152,11 +152,12 @@ asmlinkage int sunos_ioctl (int fd, u32 cmd, u32 arg)
                ret = compat_sys_ioctl(fd, SIOCGIFCONF, arg);
                goto out;
 
-       case _IOW('i', 21, struct ifreq): /* SIOCSIFMTU */
-               ret = sys_ioctl(fd, SIOCSIFMTU, arg);
+       case _IOW('i', 21, struct ifreq32):
+               ret = compat_sys_ioctl(fd, SIOCSIFMTU, arg);
                goto out;
-       case _IOWR('i', 22, struct ifreq): /* SIOCGIFMTU */
-               ret = sys_ioctl(fd, SIOCGIFMTU, arg);
+
+       case _IOWR('i', 22, struct ifreq32):
+               ret = compat_sys_ioctl(fd, SIOCGIFMTU, arg);
                goto out;
 
        case _IOWR('i', 23, struct ifreq32):
index 1d3aa588df8a5a8466113947ae3d3102c021c1e1..7f6239ed252142e52c45f2921de58b339d770086 100644 (file)
@@ -1002,29 +1002,7 @@ asmlinkage long sys32_adjtimex(struct timex32 __user *utp)
 asmlinkage long sparc32_open(const char __user *filename,
                             int flags, int mode)
 {
-       char * tmp;
-       int fd, error;
-
-       tmp = getname(filename);
-       fd = PTR_ERR(tmp);
-       if (!IS_ERR(tmp)) {
-               fd = get_unused_fd();
-               if (fd >= 0) {
-                       struct file * f = filp_open(tmp, flags, mode);
-                       error = PTR_ERR(f);
-                       if (IS_ERR(f))
-                               goto out_error;
-                       fd_install(fd, f);
-               }
-out:
-               putname(tmp);
-       }
-       return fd;
-
-out_error:
-       put_unused_fd(fd);
-       fd = error;
-       goto out;
+       return do_sys_open(filename, flags, mode);
 }
 
 extern unsigned long do_mremap(unsigned long addr,
index 362b9c26871b26af39abe9142bf7ed830ff31e66..3f08a32f51a16d2a91231ddcf15701dbdbe3d51b 100644 (file)
@@ -449,7 +449,7 @@ static inline void timer_check_rtc(void)
        static long last_rtc_update;
 
        /* Determine when to update the Mostek clock. */
-       if ((time_status & STA_UNSYNC) == 0 &&
+       if (ntp_synced() &&
            xtime.tv_sec > last_rtc_update + 660 &&
            (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
            (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
index 0c9e54b2f0c8874d08d01159a5365a7f7afa9f2a..b280b2ef674f4a80b57cfaf36dec0140be727a66 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/dcu.h>
 #include <asm/estate.h>
 #include <asm/chafsr.h>
+#include <asm/sfafsr.h>
 #include <asm/psrcompat.h>
 #include <asm/processor.h>
 #include <asm/timer.h>
@@ -143,8 +144,7 @@ void do_BUG(const char *file, int line)
 }
 #endif
 
-void instruction_access_exception(struct pt_regs *regs,
-                                 unsigned long sfsr, unsigned long sfar)
+void spitfire_insn_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
 {
        siginfo_t info;
 
@@ -153,8 +153,8 @@ void instruction_access_exception(struct pt_regs *regs,
                return;
 
        if (regs->tstate & TSTATE_PRIV) {
-               printk("instruction_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n",
-                      sfsr, sfar);
+               printk("spitfire_insn_access_exception: SFSR[%016lx] "
+                      "SFAR[%016lx], going.\n", sfsr, sfar);
                die_if_kernel("Iax", regs);
        }
        if (test_thread_flag(TIF_32BIT)) {
@@ -169,19 +169,17 @@ void instruction_access_exception(struct pt_regs *regs,
        force_sig_info(SIGSEGV, &info, current);
 }
 
-void instruction_access_exception_tl1(struct pt_regs *regs,
-                                     unsigned long sfsr, unsigned long sfar)
+void spitfire_insn_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
 {
        if (notify_die(DIE_TRAP_TL1, "instruction access exception tl1", regs,
                       0, 0x8, SIGTRAP) == NOTIFY_STOP)
                return;
 
        dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
-       instruction_access_exception(regs, sfsr, sfar);
+       spitfire_insn_access_exception(regs, sfsr, sfar);
 }
 
-void data_access_exception(struct pt_regs *regs,
-                          unsigned long sfsr, unsigned long sfar)
+void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
 {
        siginfo_t info;
 
@@ -207,8 +205,8 @@ void data_access_exception(struct pt_regs *regs,
                        return;
                }
                /* Shit... */
-               printk("data_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n",
-                      sfsr, sfar);
+               printk("spitfire_data_access_exception: SFSR[%016lx] "
+                      "SFAR[%016lx], going.\n", sfsr, sfar);
                die_if_kernel("Dax", regs);
        }
 
@@ -220,6 +218,16 @@ void data_access_exception(struct pt_regs *regs,
        force_sig_info(SIGSEGV, &info, current);
 }
 
+void spitfire_data_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
+{
+       if (notify_die(DIE_TRAP_TL1, "data access exception tl1", regs,
+                      0, 0x30, SIGTRAP) == NOTIFY_STOP)
+               return;
+
+       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
+       spitfire_data_access_exception(regs, sfsr, sfar);
+}
+
 #ifdef CONFIG_PCI
 /* This is really pathetic... */
 extern volatile int pci_poke_in_progress;
@@ -253,54 +261,13 @@ static void spitfire_clean_and_reenable_l1_caches(void)
                             : "memory");
 }
 
-void do_iae(struct pt_regs *regs)
+static void spitfire_enable_estate_errors(void)
 {
-       siginfo_t info;
-
-       spitfire_clean_and_reenable_l1_caches();
-
-       if (notify_die(DIE_TRAP, "instruction access exception", regs,
-                      0, 0x8, SIGTRAP) == NOTIFY_STOP)
-               return;
-
-       info.si_signo = SIGBUS;
-       info.si_errno = 0;
-       info.si_code = BUS_OBJERR;
-       info.si_addr = (void *)0;
-       info.si_trapno = 0;
-       force_sig_info(SIGBUS, &info, current);
-}
-
-void do_dae(struct pt_regs *regs)
-{
-       siginfo_t info;
-
-#ifdef CONFIG_PCI
-       if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) {
-               spitfire_clean_and_reenable_l1_caches();
-
-               pci_poke_faulted = 1;
-
-               /* Why the fuck did they have to change this? */
-               if (tlb_type == cheetah || tlb_type == cheetah_plus)
-                       regs->tpc += 4;
-
-               regs->tnpc = regs->tpc + 4;
-               return;
-       }
-#endif
-       spitfire_clean_and_reenable_l1_caches();
-
-       if (notify_die(DIE_TRAP, "data access exception", regs,
-                      0, 0x30, SIGTRAP) == NOTIFY_STOP)
-               return;
-
-       info.si_signo = SIGBUS;
-       info.si_errno = 0;
-       info.si_code = BUS_OBJERR;
-       info.si_addr = (void *)0;
-       info.si_trapno = 0;
-       force_sig_info(SIGBUS, &info, current);
+       __asm__ __volatile__("stxa      %0, [%%g0] %1\n\t"
+                            "membar    #Sync"
+                            : /* no outputs */
+                            : "r" (ESTATE_ERR_ALL),
+                              "i" (ASI_ESTATE_ERROR_EN));
 }
 
 static char ecc_syndrome_table[] = {
@@ -338,65 +305,15 @@ static char ecc_syndrome_table[] = {
        0x0b, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x4b, 0x4a
 };
 
-/* cee_trap in entry.S encodes AFSR/UDBH/UDBL error status
- * in the following format.  The AFAR is left as is, with
- * reserved bits cleared, and is a raw 40-bit physical
- * address.
- */
-#define CE_STATUS_UDBH_UE              (1UL << (43 + 9))
-#define CE_STATUS_UDBH_CE              (1UL << (43 + 8))
-#define CE_STATUS_UDBH_ESYNDR          (0xffUL << 43)
-#define CE_STATUS_UDBH_SHIFT           43
-#define CE_STATUS_UDBL_UE              (1UL << (33 + 9))
-#define CE_STATUS_UDBL_CE              (1UL << (33 + 8))
-#define CE_STATUS_UDBL_ESYNDR          (0xffUL << 33)
-#define CE_STATUS_UDBL_SHIFT           33
-#define CE_STATUS_AFSR_MASK            (0x1ffffffffUL)
-#define CE_STATUS_AFSR_ME              (1UL << 32)
-#define CE_STATUS_AFSR_PRIV            (1UL << 31)
-#define CE_STATUS_AFSR_ISAP            (1UL << 30)
-#define CE_STATUS_AFSR_ETP             (1UL << 29)
-#define CE_STATUS_AFSR_IVUE            (1UL << 28)
-#define CE_STATUS_AFSR_TO              (1UL << 27)
-#define CE_STATUS_AFSR_BERR            (1UL << 26)
-#define CE_STATUS_AFSR_LDP             (1UL << 25)
-#define CE_STATUS_AFSR_CP              (1UL << 24)
-#define CE_STATUS_AFSR_WP              (1UL << 23)
-#define CE_STATUS_AFSR_EDP             (1UL << 22)
-#define CE_STATUS_AFSR_UE              (1UL << 21)
-#define CE_STATUS_AFSR_CE              (1UL << 20)
-#define CE_STATUS_AFSR_ETS             (0xfUL << 16)
-#define CE_STATUS_AFSR_ETS_SHIFT       16
-#define CE_STATUS_AFSR_PSYND           (0xffffUL << 0)
-#define CE_STATUS_AFSR_PSYND_SHIFT     0
-
-/* Layout of Ecache TAG Parity Syndrome of AFSR */
-#define AFSR_ETSYNDROME_7_0            0x1UL /* E$-tag bus bits  <7:0> */
-#define AFSR_ETSYNDROME_15_8           0x2UL /* E$-tag bus bits <15:8> */
-#define AFSR_ETSYNDROME_21_16          0x4UL /* E$-tag bus bits <21:16> */
-#define AFSR_ETSYNDROME_24_22          0x8UL /* E$-tag bus bits <24:22> */
-
 static char *syndrome_unknown = "<Unknown>";
 
-asmlinkage void cee_log(unsigned long ce_status,
-                       unsigned long afar,
-                       struct pt_regs *regs)
+static void spitfire_log_udb_syndrome(unsigned long afar, unsigned long udbh, unsigned long udbl, unsigned long bit)
 {
-       char memmod_str[64];
-       char *p;
-       unsigned short scode, udb_reg;
+       unsigned short scode;
+       char memmod_str[64], *p;
 
-       printk(KERN_WARNING "CPU[%d]: Correctable ECC Error "
-              "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx]\n",
-              smp_processor_id(),
-              (ce_status & CE_STATUS_AFSR_MASK),
-              afar,
-              ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL),
-              ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL));
-
-       udb_reg = ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL);
-       if (udb_reg & (1 << 8)) {
-               scode = ecc_syndrome_table[udb_reg & 0xff];
+       if (udbl & bit) {
+               scode = ecc_syndrome_table[udbl & 0xff];
                if (prom_getunumber(scode, afar,
                                    memmod_str, sizeof(memmod_str)) == -1)
                        p = syndrome_unknown;
@@ -407,9 +324,8 @@ asmlinkage void cee_log(unsigned long ce_status,
                       smp_processor_id(), scode, p);
        }
 
-       udb_reg = ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL);
-       if (udb_reg & (1 << 8)) {
-               scode = ecc_syndrome_table[udb_reg & 0xff];
+       if (udbh & bit) {
+               scode = ecc_syndrome_table[udbh & 0xff];
                if (prom_getunumber(scode, afar,
                                    memmod_str, sizeof(memmod_str)) == -1)
                        p = syndrome_unknown;
@@ -419,6 +335,127 @@ asmlinkage void cee_log(unsigned long ce_status,
                       "Memory Module \"%s\"\n",
                       smp_processor_id(), scode, p);
        }
+
+}
+
+static void spitfire_cee_log(unsigned long afsr, unsigned long afar, unsigned long udbh, unsigned long udbl, int tl1, struct pt_regs *regs)
+{
+
+       printk(KERN_WARNING "CPU[%d]: Correctable ECC Error "
+              "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx] TL>1[%d]\n",
+              smp_processor_id(), afsr, afar, udbl, udbh, tl1);
+
+       spitfire_log_udb_syndrome(afar, udbh, udbl, UDBE_CE);
+
+       /* We always log it, even if someone is listening for this
+        * trap.
+        */
+       notify_die(DIE_TRAP, "Correctable ECC Error", regs,
+                  0, TRAP_TYPE_CEE, SIGTRAP);
+
+       /* The Correctable ECC Error trap does not disable I/D caches.  So
+        * we only have to restore the ESTATE Error Enable register.
+        */
+       spitfire_enable_estate_errors();
+}
+
+static void spitfire_ue_log(unsigned long afsr, unsigned long afar, unsigned long udbh, unsigned long udbl, unsigned long tt, int tl1, struct pt_regs *regs)
+{
+       siginfo_t info;
+
+       printk(KERN_WARNING "CPU[%d]: Uncorrectable Error AFSR[%lx] "
+              "AFAR[%lx] UDBL[%lx] UDBH[%ld] TT[%lx] TL>1[%d]\n",
+              smp_processor_id(), afsr, afar, udbl, udbh, tt, tl1);
+
+       /* XXX add more human friendly logging of the error status
+        * XXX as is implemented for cheetah
+        */
+
+       spitfire_log_udb_syndrome(afar, udbh, udbl, UDBE_UE);
+
+       /* We always log it, even if someone is listening for this
+        * trap.
+        */
+       notify_die(DIE_TRAP, "Uncorrectable Error", regs,
+                  0, tt, SIGTRAP);
+
+       if (regs->tstate & TSTATE_PRIV) {
+               if (tl1)
+                       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
+               die_if_kernel("UE", regs);
+       }
+
+       /* XXX need more intelligent processing here, such as is implemented
+        * XXX for cheetah errors, in fact if the E-cache still holds the
+        * XXX line with bad parity this will loop
+        */
+
+       spitfire_clean_and_reenable_l1_caches();
+       spitfire_enable_estate_errors();
+
+       if (test_thread_flag(TIF_32BIT)) {
+               regs->tpc &= 0xffffffff;
+               regs->tnpc &= 0xffffffff;
+       }
+       info.si_signo = SIGBUS;
+       info.si_errno = 0;
+       info.si_code = BUS_OBJERR;
+       info.si_addr = (void *)0;
+       info.si_trapno = 0;
+       force_sig_info(SIGBUS, &info, current);
+}
+
+void spitfire_access_error(struct pt_regs *regs, unsigned long status_encoded, unsigned long afar)
+{
+       unsigned long afsr, tt, udbh, udbl;
+       int tl1;
+
+       afsr = (status_encoded & SFSTAT_AFSR_MASK) >> SFSTAT_AFSR_SHIFT;
+       tt = (status_encoded & SFSTAT_TRAP_TYPE) >> SFSTAT_TRAP_TYPE_SHIFT;
+       tl1 = (status_encoded & SFSTAT_TL_GT_ONE) ? 1 : 0;
+       udbl = (status_encoded & SFSTAT_UDBL_MASK) >> SFSTAT_UDBL_SHIFT;
+       udbh = (status_encoded & SFSTAT_UDBH_MASK) >> SFSTAT_UDBH_SHIFT;
+
+#ifdef CONFIG_PCI
+       if (tt == TRAP_TYPE_DAE &&
+           pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) {
+               spitfire_clean_and_reenable_l1_caches();
+               spitfire_enable_estate_errors();
+
+               pci_poke_faulted = 1;
+               regs->tnpc = regs->tpc + 4;
+               return;
+       }
+#endif
+
+       if (afsr & SFAFSR_UE)
+               spitfire_ue_log(afsr, afar, udbh, udbl, tt, tl1, regs);
+
+       if (tt == TRAP_TYPE_CEE) {
+               /* Handle the case where we took a CEE trap, but ACK'd
+                * only the UE state in the UDB error registers.
+                */
+               if (afsr & SFAFSR_UE) {
+                       if (udbh & UDBE_CE) {
+                               __asm__ __volatile__(
+                                       "stxa   %0, [%1] %2\n\t"
+                                       "membar #Sync"
+                                       : /* no outputs */
+                                       : "r" (udbh & UDBE_CE),
+                                         "r" (0x0), "i" (ASI_UDB_ERROR_W));
+                       }
+                       if (udbl & UDBE_CE) {
+                               __asm__ __volatile__(
+                                       "stxa   %0, [%1] %2\n\t"
+                                       "membar #Sync"
+                                       : /* no outputs */
+                                       : "r" (udbl & UDBE_CE),
+                                         "r" (0x18), "i" (ASI_UDB_ERROR_W));
+                       }
+               }
+
+               spitfire_cee_log(afsr, afar, udbh, udbl, tl1, regs);
+       }
 }
 
 int cheetah_pcache_forced_on;
index 491bb3681f9d7d5c90a32261b7c37c9da7c07ee5..8365bc1f81f3105f969ad938c3b3de3cebf221e7 100644 (file)
@@ -18,9 +18,10 @@ sparc64_ttable_tl0:
 tl0_resv000:   BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3)
 tl0_resv004:   BTRAP(0x4)  BTRAP(0x5) BTRAP(0x6) BTRAP(0x7)
 tl0_iax:       membar #Sync
-               TRAP_NOSAVE_7INSNS(__do_instruction_access_exception)
+               TRAP_NOSAVE_7INSNS(__spitfire_insn_access_exception)
 tl0_resv009:   BTRAP(0x9)
-tl0_iae:       TRAP(do_iae)
+tl0_iae:       membar #Sync
+               TRAP_NOSAVE_7INSNS(__spitfire_access_error)
 tl0_resv00b:   BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf)
 tl0_ill:       membar #Sync
                TRAP_7INSNS(do_illegal_instruction)
@@ -36,9 +37,10 @@ tl0_cwin:    CLEAN_WINDOW
 tl0_div0:      TRAP(do_div0)
 tl0_resv029:   BTRAP(0x29) BTRAP(0x2a) BTRAP(0x2b) BTRAP(0x2c) BTRAP(0x2d) BTRAP(0x2e)
 tl0_resv02f:   BTRAP(0x2f)
-tl0_dax:       TRAP_NOSAVE(__do_data_access_exception)
+tl0_dax:       TRAP_NOSAVE(__spitfire_data_access_exception)
 tl0_resv031:   BTRAP(0x31)
-tl0_dae:       TRAP(do_dae)
+tl0_dae:       membar #Sync
+               TRAP_NOSAVE_7INSNS(__spitfire_access_error)
 tl0_resv033:   BTRAP(0x33)
 tl0_mna:       TRAP_NOSAVE(do_mna)
 tl0_lddfmna:   TRAP_NOSAVE(do_lddfmna)
@@ -73,7 +75,8 @@ tl0_resv05c:  BTRAP(0x5c) BTRAP(0x5d) BTRAP(0x5e) BTRAP(0x5f)
 tl0_ivec:      TRAP_IVEC
 tl0_paw:       TRAP(do_paw)
 tl0_vaw:       TRAP(do_vaw)
-tl0_cee:       TRAP_NOSAVE(cee_trap)
+tl0_cee:       membar #Sync
+               TRAP_NOSAVE_7INSNS(__spitfire_cee_trap)
 tl0_iamiss:
 #include       "itlb_base.S"
 tl0_damiss:
@@ -175,9 +178,10 @@ tl0_resv1f0:       BTRAPS(0x1f0) BTRAPS(0x1f8)
 sparc64_ttable_tl1:
 tl1_resv000:   BOOT_KERNEL    BTRAPTL1(0x1) BTRAPTL1(0x2) BTRAPTL1(0x3)
 tl1_resv004:   BTRAPTL1(0x4)  BTRAPTL1(0x5) BTRAPTL1(0x6) BTRAPTL1(0x7)
-tl1_iax:       TRAP_NOSAVE(__do_instruction_access_exception_tl1)
+tl1_iax:       TRAP_NOSAVE(__spitfire_insn_access_exception_tl1)
 tl1_resv009:   BTRAPTL1(0x9)
-tl1_iae:       TRAPTL1(do_iae_tl1)
+tl1_iae:       membar #Sync
+               TRAP_NOSAVE_7INSNS(__spitfire_access_error)
 tl1_resv00b:   BTRAPTL1(0xb) BTRAPTL1(0xc) BTRAPTL1(0xd) BTRAPTL1(0xe) BTRAPTL1(0xf)
 tl1_ill:       TRAPTL1(do_ill_tl1)
 tl1_privop:    BTRAPTL1(0x11)
@@ -193,9 +197,10 @@ tl1_cwin:  CLEAN_WINDOW
 tl1_div0:      TRAPTL1(do_div0_tl1)
 tl1_resv029:   BTRAPTL1(0x29) BTRAPTL1(0x2a) BTRAPTL1(0x2b) BTRAPTL1(0x2c)
 tl1_resv02d:   BTRAPTL1(0x2d) BTRAPTL1(0x2e) BTRAPTL1(0x2f)
-tl1_dax:       TRAP_NOSAVE(__do_data_access_exception_tl1)
+tl1_dax:       TRAP_NOSAVE(__spitfire_data_access_exception_tl1)
 tl1_resv031:   BTRAPTL1(0x31)
-tl1_dae:       TRAPTL1(do_dae_tl1)
+tl1_dae:       membar #Sync
+               TRAP_NOSAVE_7INSNS(__spitfire_access_error)
 tl1_resv033:   BTRAPTL1(0x33)
 tl1_mna:       TRAP_NOSAVE(do_mna)
 tl1_lddfmna:   TRAPTL1(do_lddfmna_tl1)
@@ -219,8 +224,8 @@ tl1_paw:    TRAPTL1(do_paw_tl1)
 tl1_vaw:       TRAPTL1(do_vaw_tl1)
 
                /* The grotty trick to save %g1 into current->thread.cee_stuff
-                * is because when we take this trap we could be interrupting trap
-                * code already using the trap alternate global registers.
+                * is because when we take this trap we could be interrupting
+                * trap code already using the trap alternate global registers.
                 *
                 * We cross our fingers and pray that this store/load does
                 * not cause yet another CEE trap.
index 11c3e88732e482ba54da15452ea38c45f1b0c713..da9739f0d43723cbee80f87cf9f491bff1ea11f3 100644 (file)
@@ -349,9 +349,9 @@ int handle_popc(u32 insn, struct pt_regs *regs)
 
 extern void do_fpother(struct pt_regs *regs);
 extern void do_privact(struct pt_regs *regs);
-extern void data_access_exception(struct pt_regs *regs,
-                                 unsigned long sfsr,
-                                 unsigned long sfar);
+extern void spitfire_data_access_exception(struct pt_regs *regs,
+                                          unsigned long sfsr,
+                                          unsigned long sfar);
 
 int handle_ldf_stq(u32 insn, struct pt_regs *regs)
 {
@@ -394,14 +394,14 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs)
                                break;
                        }
                default:
-                       data_access_exception(regs, 0, addr);
+                       spitfire_data_access_exception(regs, 0, addr);
                        return 1;
                }
                if (put_user (first >> 32, (u32 __user *)addr) ||
                    __put_user ((u32)first, (u32 __user *)(addr + 4)) ||
                    __put_user (second >> 32, (u32 __user *)(addr + 8)) ||
                    __put_user ((u32)second, (u32 __user *)(addr + 12))) {
-                       data_access_exception(regs, 0, addr);
+                       spitfire_data_access_exception(regs, 0, addr);
                        return 1;
                }
        } else {
@@ -414,7 +414,7 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs)
                        do_privact(regs);
                        return 1;
                } else if (asi > ASI_SNFL) {
-                       data_access_exception(regs, 0, addr);
+                       spitfire_data_access_exception(regs, 0, addr);
                        return 1;
                }
                switch (insn & 0x180000) {
@@ -431,7 +431,7 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs)
                                err |= __get_user (data[i], (u32 __user *)(addr + 4*i));
                }
                if (err && !(asi & 0x2 /* NF */)) {
-                       data_access_exception(regs, 0, addr);
+                       spitfire_data_access_exception(regs, 0, addr);
                        return 1;
                }
                if (asi & 0x8) /* Little */ {
@@ -534,7 +534,7 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
                *(u64 *)(f->regs + freg) = value;
                current_thread_info()->fpsaved[0] |= flag;
        } else {
-daex:          data_access_exception(regs, sfsr, sfar);
+daex:          spitfire_data_access_exception(regs, sfsr, sfar);
                return;
        }
        advance(regs);
@@ -578,7 +578,7 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
                    __put_user ((u32)value, (u32 __user *)(sfar + 4)))
                        goto daex;
        } else {
-daex:          data_access_exception(regs, sfsr, sfar);
+daex:          spitfire_data_access_exception(regs, sfsr, sfar);
                return;
        }
        advance(regs);
index 950423da8a6ab395767ce6aa8af112bcc773d493..f47d0be39378a2a7603e4470d0bb5962c1e2dc9e 100644 (file)
@@ -17,6 +17,7 @@ SECTIONS
     *(.text)
     SCHED_TEXT
     LOCK_TEXT
+    KPROBES_TEXT
     *(.gnu.warning)
   } =0
   _etext = .;
index dfbc7e0dcf70f7dedf71952c96d18a88e3ce02dd..99c809a1e5acbbeacebdf561504dd24a2cdfce5a 100644 (file)
@@ -318,7 +318,7 @@ fill_fixup_dax:
         nop
        rdpr            %pstate, %l1                    ! Prepare to change globals.
        mov             %g4, %o1                        ! Setup args for
-       mov             %g5, %o2                        ! final call to data_access_exception.
+       mov             %g5, %o2                        ! final call to spitfire_data_access_exception.
        andn            %l1, PSTATE_MM, %l1             ! We want to be in RMO
 
        mov             %g6, %o7                        ! Stash away current.
@@ -330,7 +330,7 @@ fill_fixup_dax:
        mov             TSB_REG, %g1
        ldxa            [%g1] ASI_IMMU, %g5
 #endif
-       call            data_access_exception
+       call            spitfire_data_access_exception
         add            %sp, PTREGS_OFF, %o0
 
        b,pt            %xcc, rtrap
@@ -391,7 +391,7 @@ window_dax_from_user_common:
 109:    or             %g7, %lo(109b), %g7
        mov             %l4, %o1
        mov             %l5, %o2
-       call            data_access_exception
+       call            spitfire_data_access_exception
         add            %sp, PTREGS_OFF, %o0
        ba,pt           %xcc, rtrap
         clr            %l6
index 40dbeec7e5d6a8ed75006dd2873e0d40e019b29e..6201f1040982aabde591d28673a4a0d7e2697f95 100644 (file)
@@ -12,7 +12,7 @@ lib-y := PeeCeeI.o copy_page.o clear_page.o strlen.o strncmp.o \
         U1memcpy.o U1copy_from_user.o U1copy_to_user.o \
         U3memcpy.o U3copy_from_user.o U3copy_to_user.o U3patch.o \
         copy_in_user.o user_fixup.o memmove.o \
-        mcount.o ipcsum.o rwsem.o xor.o find_bit.o delay.o
+        mcount.o ipcsum.o rwsem.o xor.o find_bit.o delay.o mb.o
 
 lib-$(CONFIG_DEBUG_SPINLOCK) += debuglocks.o
 lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
index 3008d536e8c29b4367a7b38969a3b2d1838eb9de..3c6cfbb20360fe7fb8a38a8105b356b88865928d 100644 (file)
@@ -7,28 +7,31 @@
 #include <asm/io.h>
 #include <asm/byteorder.h>
 
-void outsb(void __iomem *addr, const void *src, unsigned long count)
+void outsb(unsigned long __addr, const void *src, unsigned long count)
 {
+       void __iomem *addr = (void __iomem *) __addr;
        const u8 *p = src;
 
-       while(count--)
+       while (count--)
                outb(*p++, addr);
 }
 
-void outsw(void __iomem *addr, const void *src, unsigned long count)
+void outsw(unsigned long __addr, const void *src, unsigned long count)
 {
-       if(count) {
+       void __iomem *addr = (void __iomem *) __addr;
+
+       if (count) {
                u16 *ps = (u16 *)src;
                u32 *pi;
 
-               if(((u64)src) & 0x2) {
+               if (((u64)src) & 0x2) {
                        u16 val = le16_to_cpup(ps);
                        outw(val, addr);
                        ps++;
                        count--;
                }
                pi = (u32 *)ps;
-               while(count >= 2) {
+               while (count >= 2) {
                        u32 w = le32_to_cpup(pi);
 
                        pi++;
@@ -37,19 +40,21 @@ void outsw(void __iomem *addr, const void *src, unsigned long count)
                        count -= 2;
                }
                ps = (u16 *)pi;
-               if(count) {
+               if (count) {
                        u16 val = le16_to_cpup(ps);
                        outw(val, addr);
                }
        }
 }
 
-void outsl(void __iomem *addr, const void *src, unsigned long count)
+void outsl(unsigned long __addr, const void *src, unsigned long count)
 {
-       if(count) {
-               if((((u64)src) & 0x3) == 0) {
+       void __iomem *addr = (void __iomem *) __addr;
+
+       if (count) {
+               if ((((u64)src) & 0x3) == 0) {
                        u32 *p = (u32 *)src;
-                       while(count--) {
+                       while (count--) {
                                u32 val = cpu_to_le32p(p);
                                outl(val, addr);
                                p++;
@@ -60,13 +65,13 @@ void outsl(void __iomem *addr, const void *src, unsigned long count)
                        u32 l = 0, l2;
                        u32 *pi;
 
-                       switch(((u64)src) & 0x3) {
+                       switch (((u64)src) & 0x3) {
                        case 0x2:
                                count -= 1;
                                l = cpu_to_le16p(ps) << 16;
                                ps++;
                                pi = (u32 *)ps;
-                               while(count--) {
+                               while (count--) {
                                        l2 = cpu_to_le32p(pi);
                                        pi++;
                                        outl(((l >> 16) | (l2 << 16)), addr);
@@ -86,7 +91,7 @@ void outsl(void __iomem *addr, const void *src, unsigned long count)
                                ps++;
                                l |= (l2 << 16);
                                pi = (u32 *)ps;
-                               while(count--) {
+                               while (count--) {
                                        l2 = cpu_to_le32p(pi);
                                        pi++;
                                        outl(((l >> 8) | (l2 << 24)), addr);
@@ -101,7 +106,7 @@ void outsl(void __iomem *addr, const void *src, unsigned long count)
                                pb = (u8 *)src;
                                l = (*pb++ << 24);
                                pi = (u32 *)pb;
-                               while(count--) {
+                               while (count--) {
                                        l2 = cpu_to_le32p(pi);
                                        pi++;
                                        outl(((l >> 24) | (l2 << 8)), addr);
@@ -119,16 +124,18 @@ void outsl(void __iomem *addr, const void *src, unsigned long count)
        }
 }
 
-void insb(void __iomem *addr, void *dst, unsigned long count)
+void insb(unsigned long __addr, void *dst, unsigned long count)
 {
-       if(count) {
+       void __iomem *addr = (void __iomem *) __addr;
+
+       if (count) {
                u32 *pi;
                u8 *pb = dst;
 
-               while((((unsigned long)pb) & 0x3) && count--)
+               while ((((unsigned long)pb) & 0x3) && count--)
                        *pb++ = inb(addr);
                pi = (u32 *)pb;
-               while(count >= 4) {
+               while (count >= 4) {
                        u32 w;
 
                        w  = (inb(addr) << 24);
@@ -139,23 +146,25 @@ void insb(void __iomem *addr, void *dst, unsigned long count)
                        count -= 4;
                }
                pb = (u8 *)pi;
-               while(count--)
+               while (count--)
                        *pb++ = inb(addr);
        }
 }
 
-void insw(void __iomem *addr, void *dst, unsigned long count)
+void insw(unsigned long __addr, void *dst, unsigned long count)
 {
-       if(count) {
+       void __iomem *addr = (void __iomem *) __addr;
+
+       if (count) {
                u16 *ps = dst;
                u32 *pi;
 
-               if(((unsigned long)ps) & 0x2) {
+               if (((unsigned long)ps) & 0x2) {
                        *ps++ = le16_to_cpu(inw(addr));
                        count--;
                }
                pi = (u32 *)ps;
-               while(count >= 2) {
+               while (count >= 2) {
                        u32 w;
 
                        w  = (le16_to_cpu(inw(addr)) << 16);
@@ -164,31 +173,33 @@ void insw(void __iomem *addr, void *dst, unsigned long count)
                        count -= 2;
                }
                ps = (u16 *)pi;
-               if(count)
+               if (count)
                        *ps = le16_to_cpu(inw(addr));
        }
 }
 
-void insl(void __iomem *addr, void *dst, unsigned long count)
+void insl(unsigned long __addr, void *dst, unsigned long count)
 {
-       if(count) {
-               if((((unsigned long)dst) & 0x3) == 0) {
+       void __iomem *addr = (void __iomem *) __addr;
+
+       if (count) {
+               if ((((unsigned long)dst) & 0x3) == 0) {
                        u32 *pi = dst;
-                       while(count--)
+                       while (count--)
                                *pi++ = le32_to_cpu(inl(addr));
                } else {
                        u32 l = 0, l2, *pi;
                        u16 *ps;
                        u8 *pb;
 
-                       switch(((unsigned long)dst) & 3) {
+                       switch (((unsigned long)dst) & 3) {
                        case 0x2:
                                ps = dst;
                                count -= 1;
                                l = le32_to_cpu(inl(addr));
                                *ps++ = l;
                                pi = (u32 *)ps;
-                               while(count--) {
+                               while (count--) {
                                        l2 = le32_to_cpu(inl(addr));
                                        *pi++ = (l << 16) | (l2 >> 16);
                                        l = l2;
@@ -205,7 +216,7 @@ void insl(void __iomem *addr, void *dst, unsigned long count)
                                ps = (u16 *)pb;
                                *ps++ = ((l >> 8) & 0xffff);
                                pi = (u32 *)ps;
-                               while(count--) {
+                               while (count--) {
                                        l2 = le32_to_cpu(inl(addr));
                                        *pi++ = (l << 24) | (l2 >> 8);
                                        l = l2;
@@ -220,7 +231,7 @@ void insl(void __iomem *addr, void *dst, unsigned long count)
                                l = le32_to_cpu(inl(addr));
                                *pb++ = l >> 24;
                                pi = (u32 *)pb;
-                               while(count--) {
+                               while (count--) {
                                        l2 = le32_to_cpu(inl(addr));
                                        *pi++ = (l << 8) | (l2 >> 24);
                                        l = l2;
index 23ebf2c970b71d950c2bea623e60b58c36b7b46c..feebb14fd27a3d3d63adae00b4653e7d43d3083e 100644 (file)
@@ -87,7 +87,7 @@ copy_user_page:               /* %o0=dest, %o1=src, %o2=vaddr */
        membar          #Sync
        wrpr            %o2, 0x0, %pstate
 
-       BRANCH_IF_ANY_CHEETAH(g3,o2,1f)
+cheetah_copy_page_insn:
        ba,pt           %xcc, 9f
         nop
 
@@ -240,3 +240,14 @@ copy_user_page:            /* %o0=dest, %o1=src, %o2=vaddr */
         stw            %o4, [%g6 + TI_PRE_COUNT]
 
        .size           copy_user_page, .-copy_user_page
+
+       .globl          cheetah_patch_copy_page
+cheetah_patch_copy_page:
+       sethi           %hi(0x01000000), %o1    ! NOP
+       sethi           %hi(cheetah_copy_page_insn), %o0
+       or              %o0, %lo(cheetah_copy_page_insn), %o0
+       stw             %o1, [%o0]
+       membar          #StoreStore
+       flush           %o0
+       retl
+        nop
index f03344cf784e1785efbef5e0b195d89a568549b3..f5f0b5586f01a76ca110d4c04aec77c2be7d2931 100644 (file)
@@ -12,8 +12,6 @@
 
 #ifdef CONFIG_SMP
 
-#define GET_CALLER(PC) __asm__ __volatile__("mov %%i7, %0" : "=r" (PC))
-
 static inline void show (char *str, spinlock_t *lock, unsigned long caller)
 {
        int cpu = smp_processor_id();
@@ -51,20 +49,19 @@ static inline void show_write (char *str, rwlock_t *lock, unsigned long caller)
 #undef INIT_STUCK
 #define INIT_STUCK 100000000
 
-void _do_spin_lock(spinlock_t *lock, char *str)
+void _do_spin_lock(spinlock_t *lock, char *str, unsigned long caller)
 {
-       unsigned long caller, val;
+       unsigned long val;
        int stuck = INIT_STUCK;
        int cpu = get_cpu();
        int shown = 0;
 
-       GET_CALLER(caller);
 again:
        __asm__ __volatile__("ldstub [%1], %0"
                             : "=r" (val)
                             : "r" (&(lock->lock))
                             : "memory");
-       membar("#StoreLoad | #StoreStore");
+       membar_storeload_storestore();
        if (val) {
                while (lock->lock) {
                        if (!--stuck) {
@@ -72,7 +69,7 @@ again:
                                        show(str, lock, caller);
                                stuck = INIT_STUCK;
                        }
-                       membar("#LoadLoad");
+                       rmb();
                }
                goto again;
        }
@@ -84,17 +81,16 @@ again:
        put_cpu();
 }
 
-int _do_spin_trylock(spinlock_t *lock)
+int _do_spin_trylock(spinlock_t *lock, unsigned long caller)
 {
-       unsigned long val, caller;
+       unsigned long val;
        int cpu = get_cpu();
 
-       GET_CALLER(caller);
        __asm__ __volatile__("ldstub [%1], %0"
                             : "=r" (val)
                             : "r" (&(lock->lock))
                             : "memory");
-       membar("#StoreLoad | #StoreStore");
+       membar_storeload_storestore();
        if (!val) {
                lock->owner_pc = ((unsigned int)caller);
                lock->owner_cpu = cpu;
@@ -111,21 +107,20 @@ void _do_spin_unlock(spinlock_t *lock)
 {
        lock->owner_pc = 0;
        lock->owner_cpu = NO_PROC_ID;
-       membar("#StoreStore | #LoadStore");
+       membar_storestore_loadstore();
        lock->lock = 0;
        current->thread.smp_lock_count--;
 }
 
 /* Keep INIT_STUCK the same... */
 
-void _do_read_lock (rwlock_t *rw, char *str)
+void _do_read_lock(rwlock_t *rw, char *str, unsigned long caller)
 {
-       unsigned long caller, val;
+       unsigned long val;
        int stuck = INIT_STUCK;
        int cpu = get_cpu();
        int shown = 0;
 
-       GET_CALLER(caller);
 wlock_again:
        /* Wait for any writer to go away.  */
        while (((long)(rw->lock)) < 0) {
@@ -134,7 +129,7 @@ wlock_again:
                                show_read(str, rw, caller);
                        stuck = INIT_STUCK;
                }
-               membar("#LoadLoad");
+               rmb();
        }
        /* Try once to increment the counter.  */
        __asm__ __volatile__(
@@ -147,7 +142,7 @@ wlock_again:
 "2:"   : "=r" (val)
        : "0" (&(rw->lock))
        : "g1", "g7", "memory");
-       membar("#StoreLoad | #StoreStore");
+       membar_storeload_storestore();
        if (val)
                goto wlock_again;
        rw->reader_pc[cpu] = ((unsigned int)caller);
@@ -157,15 +152,13 @@ wlock_again:
        put_cpu();
 }
 
-void _do_read_unlock (rwlock_t *rw, char *str)
+void _do_read_unlock(rwlock_t *rw, char *str, unsigned long caller)
 {
-       unsigned long caller, val;
+       unsigned long val;
        int stuck = INIT_STUCK;
        int cpu = get_cpu();
        int shown = 0;
 
-       GET_CALLER(caller);
-
        /* Drop our identity _first_. */
        rw->reader_pc[cpu] = 0;
        current->thread.smp_lock_count--;
@@ -193,14 +186,13 @@ runlock_again:
        put_cpu();
 }
 
-void _do_write_lock (rwlock_t *rw, char *str)
+void _do_write_lock(rwlock_t *rw, char *str, unsigned long caller)
 {
-       unsigned long caller, val;
+       unsigned long val;
        int stuck = INIT_STUCK;
        int cpu = get_cpu();
        int shown = 0;
 
-       GET_CALLER(caller);
 wlock_again:
        /* Spin while there is another writer. */
        while (((long)rw->lock) < 0) {
@@ -209,7 +201,7 @@ wlock_again:
                                show_write(str, rw, caller);
                        stuck = INIT_STUCK;
                }
-               membar("#LoadLoad");
+               rmb();
        }
 
        /* Try to acuire the write bit.  */
@@ -264,7 +256,7 @@ wlock_again:
                                        show_write(str, rw, caller);
                                stuck = INIT_STUCK;
                        }
-                       membar("#LoadLoad");
+                       rmb();
                }
                goto wlock_again;
        }
@@ -278,14 +270,12 @@ wlock_again:
        put_cpu();
 }
 
-void _do_write_unlock(rwlock_t *rw)
+void _do_write_unlock(rwlock_t *rw, unsigned long caller)
 {
-       unsigned long caller, val;
+       unsigned long val;
        int stuck = INIT_STUCK;
        int shown = 0;
 
-       GET_CALLER(caller);
-
        /* Drop our identity _first_ */
        rw->writer_pc = 0;
        rw->writer_cpu = NO_PROC_ID;
@@ -313,13 +303,11 @@ wlock_again:
        }
 }
 
-int _do_write_trylock (rwlock_t *rw, char *str)
+int _do_write_trylock(rwlock_t *rw, char *str, unsigned long caller)
 {
-       unsigned long caller, val;
+       unsigned long val;
        int cpu = get_cpu();
 
-       GET_CALLER(caller);
-
        /* Try to acuire the write bit.  */
        __asm__ __volatile__(
 "      mov     1, %%g3\n"
diff --git a/arch/sparc64/lib/mb.S b/arch/sparc64/lib/mb.S
new file mode 100644 (file)
index 0000000..4004f74
--- /dev/null
@@ -0,0 +1,73 @@
+/* mb.S: Out of line memory barriers.
+ *
+ * Copyright (C) 2005 David S. Miller (davem@davemloft.net)
+ */
+
+       /* These are here in an effort to more fully work around
+        * Spitfire Errata #51.  Essentially, if a memory barrier
+        * occurs soon after a mispredicted branch, the chip can stop
+        * executing instructions until a trap occurs.  Therefore, if
+        * interrupts are disabled, the chip can hang forever.
+        *
+        * It used to be believed that the memory barrier had to be
+        * right in the delay slot, but a case has been traced
+        * recently wherein the memory barrier was one instruction
+        * after the branch delay slot and the chip still hung.  The
+        * offending sequence was the following in sym_wakeup_done()
+        * of the sym53c8xx_2 driver:
+        *
+        *      call    sym_ccb_from_dsa, 0
+        *       movge  %icc, 0, %l0
+        *      brz,pn  %o0, .LL1303
+        *       mov    %o0, %l2
+        *      membar  #LoadLoad
+        *
+        * The branch has to be mispredicted for the bug to occur.
+        * Therefore, we put the memory barrier explicitly into a
+        * "branch always, predicted taken" delay slot to avoid the
+        * problem case.
+        */
+
+       .text
+
+99:    retl
+        nop
+
+       .globl  mb
+mb:    ba,pt   %xcc, 99b
+        membar #LoadLoad | #LoadStore | #StoreStore | #StoreLoad
+       .size   mb, .-mb
+
+       .globl  rmb
+rmb:   ba,pt   %xcc, 99b
+        membar #LoadLoad
+       .size   rmb, .-rmb
+
+       .globl  wmb
+wmb:   ba,pt   %xcc, 99b
+        membar #StoreStore
+       .size   wmb, .-wmb
+
+       .globl  membar_storeload
+membar_storeload:
+       ba,pt   %xcc, 99b
+        membar #StoreLoad
+       .size   membar_storeload, .-membar_storeload
+
+       .globl  membar_storeload_storestore
+membar_storeload_storestore:
+       ba,pt   %xcc, 99b
+        membar #StoreLoad | #StoreStore
+       .size   membar_storeload_storestore, .-membar_storeload_storestore
+
+       .globl  membar_storeload_loadload
+membar_storeload_loadload:
+       ba,pt   %xcc, 99b
+        membar #StoreLoad | #LoadLoad
+       .size   membar_storeload_loadload, .-membar_storeload_loadload
+
+       .globl  membar_storestore_loadstore
+membar_storestore_loadstore:
+       ba,pt   %xcc, 99b
+        membar #StoreStore | #LoadStore
+       .size   membar_storestore_loadstore, .-membar_storestore_loadstore
index 52e9375288a96f34d63cf94261c5b4ba3498b14e..db1e3310e907dc2ba2f4c60a237f2c69664964ff 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/kprobes.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -117,8 +118,9 @@ unsigned long __init prom_probe_memory (void)
        return tally;
 }
 
-static void unhandled_fault(unsigned long address, struct task_struct *tsk,
-                           struct pt_regs *regs)
+static void __kprobes unhandled_fault(unsigned long address,
+                                     struct task_struct *tsk,
+                                     struct pt_regs *regs)
 {
        if ((unsigned long) address < PAGE_SIZE) {
                printk(KERN_ALERT "Unable to handle kernel NULL "
@@ -304,7 +306,7 @@ cannot_handle:
        unhandled_fault (address, current, regs);
 }
 
-asmlinkage void do_sparc64_fault(struct pt_regs *regs)
+asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
 {
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
index 6b31f6117a950ac400d3c78c68f759754c434b54..c954d91f01d0463aa75f607c393f1c7f4fd7dfcb 100644 (file)
@@ -116,37 +116,6 @@ static inline int io_remap_pud_range(struct mm_struct *mm, pud_t * pud, unsigned
        return 0;
 }
 
-int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space)
-{
-       int error = 0;
-       pgd_t * dir;
-       unsigned long beg = from;
-       unsigned long end = from + size;
-       struct mm_struct *mm = vma->vm_mm;
-
-       prot = __pgprot(pg_iobits);
-       offset -= from;
-       dir = pgd_offset(mm, from);
-       flush_cache_range(vma, beg, end);
-
-       spin_lock(&mm->page_table_lock);
-       while (from < end) {
-               pud_t *pud = pud_alloc(mm, dir, from);
-               error = -ENOMEM;
-               if (!pud)
-                       break;
-               error = io_remap_pud_range(mm, pud, from, end - from, offset + from, prot, space);
-               if (error)
-                       break;
-               from = (from + PGDIR_SIZE) & PGDIR_MASK;
-               dir++;
-       }
-       flush_tlb_range(vma, beg, end);
-       spin_unlock(&mm->page_table_lock);
-
-       return error;
-}
-
 int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
                unsigned long pfn, unsigned long size, pgprot_t prot)
 {
index 3fbaf342a452368972f0db2c9881d4be555ad41d..fdb1ebb308c95bad153283b87e8665b177e0df2d 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/pagemap.h>
 #include <linux/fs.h>
 #include <linux/seq_file.h>
+#include <linux/kprobes.h>
 
 #include <asm/head.h>
 #include <asm/system.h>
@@ -250,7 +251,7 @@ out:
        put_cpu();
 }
 
-void flush_icache_range(unsigned long start, unsigned long end)
+void __kprobes flush_icache_range(unsigned long start, unsigned long end)
 {
        /* Cheetah has coherent I-cache. */
        if (tlb_type == spitfire) {
index 363770893797770233005c315d7644ff902272a7..b2ee9b53227f5746b19351dc20ea873231831a58 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/page.h>
 #include <asm/spitfire.h>
 #include <asm/mmu_context.h>
+#include <asm/mmu.h>
 #include <asm/pil.h>
 #include <asm/head.h>
 #include <asm/thread_info.h>
@@ -45,6 +46,8 @@ __flush_tlb_mm: /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=SECONDARY_CONTEXT */
        nop
        nop
        nop
+       nop
+       nop
 
        .align          32
        .globl          __flush_tlb_pending
@@ -73,6 +76,9 @@ __flush_tlb_pending:
        retl
         wrpr           %g7, 0x0, %pstate
        nop
+       nop
+       nop
+       nop
 
        .align          32
        .globl          __flush_tlb_kernel_range
@@ -113,6 +119,7 @@ __spitfire_flush_tlb_mm_slow:
 #else
 #error unsupported PAGE_SIZE
 #endif
+       .section .kprobes.text, "ax"
        .align          32
        .globl          __flush_icache_page
 __flush_icache_page:   /* %o0 = phys_page */
@@ -195,6 +202,7 @@ dflush4:stxa                %g0, [%o4] ASI_DCACHE_TAG
         nop
 #endif /* DCACHE_ALIASING_POSSIBLE */
 
+       .previous .text
        .align          32
 __prefill_dtlb:
        rdpr            %pstate, %g7
@@ -224,16 +232,8 @@ __update_mmu_cache:        /* %o0=hw_context, %o1=address, %o2=pte, %o3=fault_code */
         or             %o5, %o0, %o5
        ba,a,pt         %xcc, __prefill_itlb
 
-       /* Cheetah specific versions, patched at boot time.
-        *
-        * This writes of the PRIMARY_CONTEXT register in this file are
-        * safe even on Cheetah+ and later wrt. the page size fields.
-        * The nucleus page size fields do not matter because we make
-        * no data references, and these instructions execute out of a
-        * locked I-TLB entry sitting in the fully assosciative I-TLB.
-        * This sequence should also never trap.
-        */
-__cheetah_flush_tlb_mm: /* 15 insns */
+       /* Cheetah specific versions, patched at boot time. */
+__cheetah_flush_tlb_mm: /* 18 insns */
        rdpr            %pstate, %g7
        andn            %g7, PSTATE_IE, %g2
        wrpr            %g2, 0x0, %pstate
@@ -241,6 +241,9 @@ __cheetah_flush_tlb_mm: /* 15 insns */
        mov             PRIMARY_CONTEXT, %o2
        mov             0x40, %g3
        ldxa            [%o2] ASI_DMMU, %g2
+       srlx            %g2, CTX_PGSZ1_NUC_SHIFT, %o1
+       sllx            %o1, CTX_PGSZ1_NUC_SHIFT, %o1
+       or              %o0, %o1, %o0   /* Preserve nucleus page size fields */
        stxa            %o0, [%o2] ASI_DMMU
        stxa            %g0, [%g3] ASI_DMMU_DEMAP
        stxa            %g0, [%g3] ASI_IMMU_DEMAP
@@ -250,7 +253,7 @@ __cheetah_flush_tlb_mm: /* 15 insns */
        retl
         wrpr           %g7, 0x0, %pstate
 
-__cheetah_flush_tlb_pending:   /* 23 insns */
+__cheetah_flush_tlb_pending:   /* 26 insns */
        /* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
        rdpr            %pstate, %g7
        sllx            %o1, 3, %o1
@@ -259,6 +262,9 @@ __cheetah_flush_tlb_pending:        /* 23 insns */
        wrpr            %g0, 1, %tl
        mov             PRIMARY_CONTEXT, %o4
        ldxa            [%o4] ASI_DMMU, %g2
+       srlx            %g2, CTX_PGSZ1_NUC_SHIFT, %o3
+       sllx            %o3, CTX_PGSZ1_NUC_SHIFT, %o3
+       or              %o0, %o3, %o0   /* Preserve nucleus page size fields */
        stxa            %o0, [%o4] ASI_DMMU
 1:     sub             %o1, (1 << 3), %o1
        ldx             [%o2 + %o1], %o3
@@ -311,14 +317,14 @@ cheetah_patch_cachetlbops:
        sethi           %hi(__cheetah_flush_tlb_mm), %o1
        or              %o1, %lo(__cheetah_flush_tlb_mm), %o1
        call            cheetah_patch_one
-        mov            15, %o2
+        mov            18, %o2
 
        sethi           %hi(__flush_tlb_pending), %o0
        or              %o0, %lo(__flush_tlb_pending), %o0
        sethi           %hi(__cheetah_flush_tlb_pending), %o1
        or              %o1, %lo(__cheetah_flush_tlb_pending), %o1
        call            cheetah_patch_one
-        mov            23, %o2
+        mov            26, %o2
 
 #ifdef DCACHE_ALIASING_POSSIBLE
        sethi           %hi(__flush_dcache_page), %o0
@@ -352,9 +358,12 @@ cheetah_patch_cachetlbops:
        .globl          xcall_flush_tlb_mm
 xcall_flush_tlb_mm:
        mov             PRIMARY_CONTEXT, %g2
-       mov             0x40, %g4
        ldxa            [%g2] ASI_DMMU, %g3
+       srlx            %g3, CTX_PGSZ1_NUC_SHIFT, %g4
+       sllx            %g4, CTX_PGSZ1_NUC_SHIFT, %g4
+       or              %g5, %g4, %g5   /* Preserve nucleus page size fields */
        stxa            %g5, [%g2] ASI_DMMU
+       mov             0x40, %g4
        stxa            %g0, [%g4] ASI_DMMU_DEMAP
        stxa            %g0, [%g4] ASI_IMMU_DEMAP
        stxa            %g3, [%g2] ASI_DMMU
@@ -366,6 +375,10 @@ xcall_flush_tlb_pending:
        sllx            %g1, 3, %g1
        mov             PRIMARY_CONTEXT, %g4
        ldxa            [%g4] ASI_DMMU, %g2
+       srlx            %g2, CTX_PGSZ1_NUC_SHIFT, %g4
+       sllx            %g4, CTX_PGSZ1_NUC_SHIFT, %g4
+       or              %g5, %g4, %g5
+       mov             PRIMARY_CONTEXT, %g4
        stxa            %g5, [%g4] ASI_DMMU
 1:     sub             %g1, (1 << 3), %g1
        ldx             [%g7 + %g1], %g5
index 15b4cfe075572afbd1c9c2e19a28aef3e574ae70..302efbcba70e85208d1fa8ba7387da963b8f8181 100644 (file)
@@ -737,7 +737,8 @@ MODULE_LICENSE("GPL");
 extern u32 tl0_solaris[8];
 #define update_ttable(x)                                                                               \
        tl0_solaris[3] = (((long)(x) - (long)tl0_solaris - 3) >> 2) | 0x40000000;                       \
-       __asm__ __volatile__ ("membar #StoreStore; flush %0" : : "r" (&tl0_solaris[3]))
+       wmb();          \
+       __asm__ __volatile__ ("flush %0" : : "r" (&tl0_solaris[3]))
 #else
 #endif 
 
@@ -761,7 +762,8 @@ int init_module(void)
        entry64_personality_patch |=
                (offsetof(struct task_struct, personality) +
                 (sizeof(unsigned long) - 1));
-       __asm__ __volatile__("membar #StoreStore; flush %0"
+       wmb();
+       __asm__ __volatile__("flush %0"
                             : : "r" (&entry64_personality_patch));
        return 0;
 }
index f945444df49c32aade7099e431fe14a10e756b3f..684e1f8b2755da5c5b2da0ad5e973505aa71a1a7 100644 (file)
@@ -73,7 +73,7 @@ config MODE_SKAS
        to CONFIG_MODE_TT).  Otherwise, it is safe to say Y.  Disabling this
        option will shrink the UML binary slightly.
 
-source "arch/um/Kconfig_arch"
+source "arch/um/Kconfig.arch"
 source "mm/Kconfig"
 
 config LD_SCRIPT_STATIC
@@ -196,7 +196,7 @@ config HOST_2G_2G
 config SMP
        bool "Symmetric multi-processing support (EXPERIMENTAL)"
        default n
-       depends on MODE_TT && EXPERIMENTAL
+       depends on (MODE_TT && EXPERIMENTAL && !SMP_BROKEN) || (BROKEN && SMP_BROKEN)
        help
        This option enables UML SMP support.
        It is NOT related to having a real SMP box. Not directly, at least.
@@ -279,7 +279,7 @@ source "net/Kconfig"
 
 source "drivers/base/Kconfig"
 
-source "arch/um/Kconfig_char"
+source "arch/um/Kconfig.char"
 
 source "drivers/block/Kconfig"
 
@@ -287,7 +287,7 @@ config NETDEVICES
        bool
        default NET
 
-source "arch/um/Kconfig_net"
+source "arch/um/Kconfig.net"
 
 source "drivers/net/Kconfig"
 
@@ -311,7 +311,7 @@ config GENERIC_ISA_DMA
        depends on SCSI
        default y
 
-source "arch/um/Kconfig_scsi"
+source "arch/um/Kconfig.scsi"
 
 endmenu
 
similarity index 100%
rename from arch/um/Kconfig_char
rename to arch/um/Kconfig.char
index bd41e4286d0d4b743fafc74a993f167c7cac0955..5681a8bd370b2db1201382405a7edf885efa12cd 100644 (file)
@@ -2,6 +2,17 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config CMDLINE_ON_HOST
+       bool "Show command line arguments on the host in TT mode"
+       depends on MODE_TT
+       default !DEBUG_INFO
+       help
+       This controls whether arguments in guest processes should be shown on
+       the host's ps output.
+       Enabling this option hinders debugging on some recent GDB versions
+       (because GDB gets "confused" when we do an execvp()). So probably you
+       should disable it.
+
 config PT_PROXY
        bool "Enable ptrace proxy"
        depends on XTERM_CHAN && DEBUG_INFO && MODE_TT
similarity index 93%
rename from arch/um/Kconfig_i386
rename to arch/um/Kconfig.i386
index 27c18a8d9d17d72c22d6f1c08ec6001d8bbc9563..8ad156a00499acf682a808e37d5120337f15c5b2 100644 (file)
@@ -6,6 +6,10 @@ config 64BIT
        bool
        default n
 
+config SEMAPHORE_SLEEPERS
+       bool
+       default y
+
 config TOP_ADDR
        hex
        default 0xc0000000 if !HOST_2G_2G
similarity index 98%
rename from arch/um/Kconfig_net
rename to arch/um/Kconfig.net
index fa2ab2dd78b71f7f1f44a84d3a6611c1fd3bba36..14a04ebdeae9cbd02703f70556afed68b8a2a23c 100644 (file)
@@ -34,7 +34,7 @@ config UML_NET_ETHERTAP
         link with the host.
 
         To use this, your host kernel must have support for Ethertap
-        devices.  Also, if your host kernel is 2.4.x, it must have 
+        devices.  Also, if your host kernel is 2.4.x, it must have
         CONFIG_NETLINK_DEV configured as Y or M.
 
         For more information, see
@@ -43,7 +43,7 @@ config UML_NET_ETHERTAP
         networking.
 
         If you'd like to set up an IP network with the host and/or the
-        outside world, say Y to this, the Daemon Transport and/or the 
+        outside world, say Y to this, the Daemon Transport and/or the
         Slip Transport.  You'll need at least one of them, but may choose
         more than one without conflict.  If you don't need UML networking,
         say N.
@@ -78,7 +78,7 @@ config UML_NET_SLIP
 
         The Ethertap Transport is preferred over slip because of its
         limitations.  If you prefer slip, however, say Y here.  Otherwise
-        choose the Multicast transport (to network multiple UMLs on 
+        choose the Multicast transport (to network multiple UMLs on
         multiple hosts), Ethertap (to network with the host and the
         outside world), and/or the Daemon transport (to network multiple
         UMLs on a single host).  You may choose more than one without
@@ -138,7 +138,7 @@ config UML_NET_PCAP
        depends on UML_NET && EXPERIMENTAL
        help
        The pcap transport makes a pcap packet stream on the host look
-       like an ethernet device inside UML.  This is useful for making 
+       like an ethernet device inside UML.  This is useful for making
        UML act as a network monitor for the host.  You must have libcap
        installed in order to build the pcap transport into UML.
 
@@ -169,11 +169,11 @@ config UML_NET_SLIRP
         setup string.  The effect of this transport on the UML is similar
         that of a host behind a firewall that masquerades all network
         connections passing through it (but is less secure).
-       
+
         To use this you should first have slirp compiled somewhere
         accessible on the host, and have read its documentation.  If you
         don't need UML networking, say N.
-       
+
         Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp"
 
 endmenu
similarity index 100%
rename from arch/um/Kconfig_scsi
rename to arch/um/Kconfig.scsi
similarity index 83%
rename from arch/um/Kconfig_x86_64
rename to arch/um/Kconfig.x86_64
index 735a047c890cadeb1784246ab92dca64cc5aa441..bd35e59419c8b8ff88aeeb2277a74b875eacc6df 100644 (file)
@@ -6,6 +6,10 @@ config 64BIT
        bool
        default y
 
+config SEMAPHORE_SLEEPERS
+       bool
+       default y
+
 config TOP_ADDR
        hex
        default 0x80000000
@@ -33,3 +37,7 @@ config ARCH_HAS_SC_SIGNALS
 config ARCH_REUSE_HOST_VSYSCALL_AREA
        bool
        default n
+
+config SMP_BROKEN
+       bool
+       default y
index f5a83a72aa75fef618989c92aefa7d551cd674b7..b15f6048caae839cbde7e8fe02ffc8041dbdfc78 100644 (file)
@@ -56,6 +56,7 @@ SYS_DIR               := $(ARCH_DIR)/include/sysdep-$(SUBARCH)
 
 CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
        $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap
+AFLAGS += $(ARCH_INCLUDE)
 
 USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
 USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \
@@ -101,10 +102,10 @@ define archhelp
 endef
 
 ifneq ($(KBUILD_SRC),)
-$(shell mkdir -p $(ARCH_DIR) && ln -fsn $(srctree)/$(ARCH_DIR)/Kconfig_$(SUBARCH) $(ARCH_DIR)/Kconfig_arch)
-CLEAN_FILES += $(ARCH_DIR)/Kconfig_arch
+$(shell mkdir -p $(ARCH_DIR) && ln -fsn $(srctree)/$(ARCH_DIR)/Kconfig.$(SUBARCH) $(ARCH_DIR)/Kconfig.arch)
+CLEAN_FILES += $(ARCH_DIR)/Kconfig.arch
 else
-$(shell cd $(ARCH_DIR) && ln -sf Kconfig_$(SUBARCH) Kconfig_arch)
+$(shell cd $(ARCH_DIR) && ln -sf Kconfig.$(SUBARCH) Kconfig.arch)
 endif
 
 prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS)
@@ -147,7 +148,7 @@ CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/include/uml-config.h \
 
 MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \
        $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) $(ARCH_DIR)/os \
-       $(ARCH_DIR)/Kconfig_arch
+       $(ARCH_DIR)/Kconfig.arch
 
 archclean:
        $(Q)$(MAKE) $(clean)=$(ARCH_DIR)/util
index a777e57dbf893a2b92517ec804eea57c4ab03acc..1ab431a53ac3d0cc3eb336d5d1c07a996e7ab554 100644 (file)
@@ -27,7 +27,7 @@ export LDFLAGS HOSTCFLAGS HOSTLDFLAGS UML_OBJCOPYFLAGS
 endif
 endif
 
-CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) $(STUB_CFLAGS)
+CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH)
 
 ifneq ($(CONFIG_GPROF),y)
 ARCH_CFLAGS += -DUM_FASTCALL
index aa2f7174ebca428f4674cdba4f684e8c20c23ba7..baddb5d64ca56ead6f3c1faee0670709e9f0d2d9 100644 (file)
@@ -6,7 +6,7 @@ START := 0x60000000
 
 #We #undef __x86_64__ for kernelspace, not for userspace where
 #it's needed for headers to work!
-CFLAGS += -U__$(SUBARCH)__ -fno-builtin $(STUB_CFLAGS)
+CFLAGS += -U__$(SUBARCH)__ -fno-builtin
 USER_CFLAGS += -fno-builtin
 
 ELF_ARCH := i386:x86-64
index de17d4c6e02db13309752ca26a99c2536f5f0163..783e18cae090ec1d1c77e0cafc05cfd5fa703608 100644 (file)
@@ -13,7 +13,7 @@ mcast-objs := mcast_kern.o mcast_user.o
 net-objs := net_kern.o net_user.o
 mconsole-objs := mconsole_kern.o mconsole_user.o
 hostaudio-objs := hostaudio_kern.o
-ubd-objs := ubd_kern.o ubd_user.o
+ubd-objs := ubd_kern.o
 port-objs := port_kern.o port_user.o
 harddog-objs := harddog_kern.o harddog_user.o
 
index 5d3768156c92b3a9653ac022ce6b9c1f3f486719..de3bce71aeb3e8f3b3d283da35a77949a6444022 100644 (file)
@@ -63,7 +63,7 @@ error:
  *
  * SIGWINCH can't be received synchronously, so you have to set up to receive it
  * as a signal.  That being the case, if you are going to wait for it, it is
- * convenient to sit in a pause() and wait for the signal to bounce you out of
+ * convenient to sit in sigsuspend() and wait for the signal to bounce you out of
  * it (see below for how we make sure to exit only on SIGWINCH).
  */
 
@@ -94,18 +94,19 @@ static int winch_thread(void *arg)
                       "byte, err = %d\n", -count);
 
        /* We are not using SIG_IGN on purpose, so don't fix it as I thought to
-        * do! If using SIG_IGN, the pause() call below would not stop on
+        * do! If using SIG_IGN, the sigsuspend() call below would not stop on
         * SIGWINCH. */
 
        signal(SIGWINCH, winch_handler);
        sigfillset(&sigs);
-       sigdelset(&sigs, SIGWINCH);
-       /* Block anything else than SIGWINCH. */
+       /* Block all signals possible. */
        if(sigprocmask(SIG_SETMASK, &sigs, NULL) < 0){
                printk("winch_thread : sigprocmask failed, errno = %d\n", 
                       errno);
                exit(1);
        }
+       /* In sigsuspend(), block anything else than SIGWINCH. */
+       sigdelset(&sigs, SIGWINCH);
 
        if(setsid() < 0){
                printk("winch_thread : setsid failed, errno = %d\n", errno);
@@ -130,7 +131,7 @@ static int winch_thread(void *arg)
        while(1){
                /* This will be interrupted by SIGWINCH only, since other signals
                 * are blocked.*/
-               pause();
+               sigsuspend(&sigs);
 
                count = os_write_file(pipe_fd, &c, sizeof(c));
                if(count != sizeof(c))
index 344b24d09a7c07a773f81ab99ab6b4688675b6d9..e77a38da4350d6b4abdccfd3cab1c1d5755c3864 100644 (file)
@@ -35,6 +35,7 @@
 #include "linux/blkpg.h"
 #include "linux/genhd.h"
 #include "linux/spinlock.h"
+#include "asm/atomic.h"
 #include "asm/segment.h"
 #include "asm/uaccess.h"
 #include "asm/irq.h"
 #include "mem.h"
 #include "mem_kern.h"
 #include "cow.h"
+#include "aio.h"
 
 enum ubd_req { UBD_READ, UBD_WRITE };
 
 struct io_thread_req {
-       enum ubd_req op;
+       enum aio_type op;
        int fds[2];
        unsigned long offsets[2];
        unsigned long long offset;
        unsigned long length;
        char *buffer;
        int sectorsize;
-       unsigned long sector_mask;
-       unsigned long long cow_offset;
-       unsigned long bitmap_words[2];
+       int bitmap_offset;
+       long bitmap_start;
+       long bitmap_end;
        int error;
 };
 
@@ -80,28 +82,31 @@ extern int create_cow_file(char *cow_file, char *backing_file,
                           unsigned long *bitmap_len_out,
                           int *data_offset_out);
 extern int read_cow_bitmap(int fd, void *buf, int offset, int len);
-extern void do_io(struct io_thread_req *req);
+extern void do_io(struct io_thread_req *req, struct request *r,
+                 unsigned long *bitmap);
 
-static inline int ubd_test_bit(__u64 bit, unsigned char *data)
+static inline int ubd_test_bit(__u64 bit, void *data)
 {
+       unsigned char *buffer = data;
        __u64 n;
        int bits, off;
 
-       bits = sizeof(data[0]) * 8;
+       bits = sizeof(buffer[0]) * 8;
        n = bit / bits;
        off = bit % bits;
-       return((data[n] & (1 << off)) != 0);
+       return((buffer[n] & (1 << off)) != 0);
 }
 
-static inline void ubd_set_bit(__u64 bit, unsigned char *data)
+static inline void ubd_set_bit(__u64 bit, void *data)
 {
+       unsigned char *buffer = data;
        __u64 n;
        int bits, off;
 
-       bits = sizeof(data[0]) * 8;
+       bits = sizeof(buffer[0]) * 8;
        n = bit / bits;
        off = bit % bits;
-       data[n] |= (1 << off);
+       buffer[n] |= (1 << off);
 }
 /*End stuff from ubd_user.h*/
 
@@ -110,8 +115,6 @@ static inline void ubd_set_bit(__u64 bit, unsigned char *data)
 static DEFINE_SPINLOCK(ubd_io_lock);
 static DEFINE_SPINLOCK(ubd_lock);
 
-static void (*do_ubd)(void);
-
 static int ubd_open(struct inode * inode, struct file * filp);
 static int ubd_release(struct inode * inode, struct file * file);
 static int ubd_ioctl(struct inode * inode, struct file * file,
@@ -158,6 +161,8 @@ struct cow {
         int data_offset;
 };
 
+#define MAX_SG 64
+
 struct ubd {
        char *file;
        int count;
@@ -168,6 +173,7 @@ struct ubd {
        int no_cow;
        struct cow cow;
        struct platform_device pdev;
+        struct scatterlist sg[MAX_SG];
 };
 
 #define DEFAULT_COW { \
@@ -460,80 +466,113 @@ __uml_help(fakehd,
 );
 
 static void do_ubd_request(request_queue_t * q);
-
-/* Only changed by ubd_init, which is an initcall. */
-int thread_fd = -1;
+static int in_ubd;
 
 /* Changed by ubd_handler, which is serialized because interrupts only
  * happen on CPU 0.
  */
 int intr_count = 0;
 
-/* call ubd_finish if you need to serialize */
-static void __ubd_finish(struct request *req, int error)
+static void ubd_end_request(struct request *req, int bytes, int uptodate)
 {
-       int nsect;
-
-       if(error){
-               end_request(req, 0);
-               return;
+       if (!end_that_request_first(req, uptodate, bytes >> 9)) {
+               add_disk_randomness(req->rq_disk);
+               end_that_request_last(req);
        }
-       nsect = req->current_nr_sectors;
-       req->sector += nsect;
-       req->buffer += nsect << 9;
-       req->errors = 0;
-       req->nr_sectors -= nsect;
-       req->current_nr_sectors = 0;
-       end_request(req, 1);
 }
 
-static inline void ubd_finish(struct request *req, int error)
+/* call ubd_finish if you need to serialize */
+static void __ubd_finish(struct request *req, int bytes)
 {
-       spin_lock(&ubd_io_lock);
-       __ubd_finish(req, error);
-       spin_unlock(&ubd_io_lock);
+       if(bytes < 0){
+               ubd_end_request(req, 0, 0);
+               return;
+       }
+
+       ubd_end_request(req, bytes, 1);
 }
 
-/* Called without ubd_io_lock held */
-static void ubd_handler(void)
+static inline void ubd_finish(struct request *req, int bytes)
 {
-       struct io_thread_req req;
-       struct request *rq = elv_next_request(ubd_queue);
-       int n;
-
-       do_ubd = NULL;
-       intr_count++;
-       n = os_read_file(thread_fd, &req, sizeof(req));
-       if(n != sizeof(req)){
-               printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
-                      "err = %d\n", os_getpid(), -n);
-               spin_lock(&ubd_io_lock);
-               end_request(rq, 0);
-               spin_unlock(&ubd_io_lock);
-               return;
-       }
-        
-       ubd_finish(rq, req.error);
-       reactivate_fd(thread_fd, UBD_IRQ);      
-       do_ubd_request(ubd_queue);
+       spin_lock(&ubd_io_lock);
+       __ubd_finish(req, bytes);
+       spin_unlock(&ubd_io_lock);
 }
 
+struct bitmap_io {
+        atomic_t count;
+        struct aio_context aio;
+};
+
+struct ubd_aio {
+        struct aio_context aio;
+        struct request *req;
+        int len;
+        struct bitmap_io *bitmap;
+        void *bitmap_buf;
+};
+
+static int ubd_reply_fd = -1;
+
 static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused)
 {
-       ubd_handler();
-       return(IRQ_HANDLED);
-}
+       struct aio_thread_reply reply;
+       struct ubd_aio *aio;
+       struct request *req;
+       int err, n, fd = (int) (long) dev;
+
+       while(1){
+               err = os_read_file(fd, &reply, sizeof(reply));
+               if(err == -EAGAIN)
+                       break;
+               if(err < 0){
+                       printk("ubd_aio_handler - read returned err %d\n",
+                              -err);
+                       break;
+               }
 
-/* Only changed by ubd_init, which is an initcall. */
-static int io_pid = -1;
+                aio = container_of(reply.data, struct ubd_aio, aio);
+                n = reply.err;
 
-void kill_io_thread(void)
-{
-       if(io_pid != -1) 
-               os_kill_process(io_pid, 1);
-}
+               if(n == 0){
+                       req = aio->req;
+                       req->nr_sectors -= aio->len >> 9;
+
+                       if((aio->bitmap != NULL) &&
+                          (atomic_dec_and_test(&aio->bitmap->count))){
+                                aio->aio = aio->bitmap->aio;
+                                aio->len = 0;
+                                kfree(aio->bitmap);
+                                aio->bitmap = NULL;
+                                submit_aio(&aio->aio);
+                       }
+                       else {
+                               if((req->nr_sectors == 0) &&
+                                   (aio->bitmap == NULL)){
+                                       int len = req->hard_nr_sectors << 9;
+                                       ubd_finish(req, len);
+                               }
+
+                                if(aio->bitmap_buf != NULL)
+                                        kfree(aio->bitmap_buf);
+                               kfree(aio);
+                       }
+               }
+                else if(n < 0){
+                        ubd_finish(aio->req, n);
+                        if(aio->bitmap != NULL)
+                                kfree(aio->bitmap);
+                        if(aio->bitmap_buf != NULL)
+                                kfree(aio->bitmap_buf);
+                        kfree(aio);
+                }
+       }
+       reactivate_fd(fd, UBD_IRQ);
 
-__uml_exitcall(kill_io_thread);
+        do_ubd_request(ubd_queue);
+
+       return(IRQ_HANDLED);
+}
 
 static int ubd_file_size(struct ubd *dev, __u64 *size_out)
 {
@@ -569,7 +608,7 @@ static int ubd_open_dev(struct ubd *dev)
                                &dev->cow.data_offset, create_ptr);
 
        if((dev->fd == -ENOENT) && create_cow){
-               dev->fd = create_cow_file(dev->file, dev->cow.file, 
+               dev->fd = create_cow_file(dev->file, dev->cow.file,
                                          dev->openflags, 1 << 9, PAGE_SIZE,
                                          &dev->cow.bitmap_offset, 
                                          &dev->cow.bitmap_len,
@@ -668,21 +707,22 @@ static int ubd_add(int n)
        struct ubd *dev = &ubd_dev[n];
        int err;
 
+       err = -ENODEV;
        if(dev->file == NULL)
-               return(-ENODEV);
+               goto out;
 
        if (ubd_open_dev(dev))
-               return(-ENODEV);
+               goto out;
 
        err = ubd_file_size(dev, &dev->size);
        if(err < 0)
-               return(err);
+               goto out_close;
 
        dev->size = ROUND_BLOCK(dev->size);
 
        err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]);
        if(err) 
-               return(err);
+               goto out_close;
  
        if(fake_major != MAJOR_NR)
                ubd_new_disk(fake_major, dev->size, n, 
@@ -693,8 +733,11 @@ static int ubd_add(int n)
        if (fake_ide)
                make_ide_entries(ubd_gendisk[n]->disk_name);
 
+       err = 0;
+out_close:
        ubd_close(dev);
-       return 0;
+out:
+       return err;
 }
 
 static int ubd_config(char *str)
@@ -827,6 +870,10 @@ int ubd_init(void)
 {
         int i;
 
+       ubd_reply_fd = init_aio_irq(UBD_IRQ, "ubd", ubd_intr);
+       if(ubd_reply_fd < 0)
+               printk("Setting up ubd AIO failed, err = %d\n", ubd_reply_fd);
+
        devfs_mk_dir("ubd");
        if (register_blkdev(MAJOR_NR, "ubd"))
                return -1;
@@ -837,6 +884,7 @@ int ubd_init(void)
                return -1;
        }
                
+       blk_queue_max_hw_segments(ubd_queue, MAX_SG);
        if (fake_major != MAJOR_NR) {
                char name[sizeof("ubd_nnn\0")];
 
@@ -848,40 +896,12 @@ int ubd_init(void)
        driver_register(&ubd_driver);
        for (i = 0; i < MAX_DEV; i++) 
                ubd_add(i);
+
        return 0;
 }
 
 late_initcall(ubd_init);
 
-int ubd_driver_init(void){
-       unsigned long stack;
-       int err;
-
-       /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
-       if(global_openflags.s){
-               printk(KERN_INFO "ubd: Synchronous mode\n");
-               /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
-                * enough. So use anyway the io thread. */
-       }
-       stack = alloc_stack(0, 0);
-       io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), 
-                                &thread_fd);
-       if(io_pid < 0){
-               printk(KERN_ERR 
-                      "ubd : Failed to start I/O thread (errno = %d) - "
-                      "falling back to synchronous I/O\n", -io_pid);
-               io_pid = -1;
-               return(0);
-       }
-       err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, 
-                            SA_INTERRUPT, "ubd", ubd_dev);
-       if(err != 0)
-               printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
-       return(err);
-}
-
-device_initcall(ubd_driver_init);
-
 static int ubd_open(struct inode *inode, struct file *filp)
 {
        struct gendisk *disk = inode->i_bdev->bd_disk;
@@ -919,105 +939,55 @@ static int ubd_release(struct inode * inode, struct file * file)
        return(0);
 }
 
-static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
-                         __u64 *cow_offset, unsigned long *bitmap,
-                         __u64 bitmap_offset, unsigned long *bitmap_words,
-                         __u64 bitmap_len)
+static void cowify_bitmap(struct io_thread_req *req, unsigned long *bitmap)
 {
-       __u64 sector = io_offset >> 9;
-       int i, update_bitmap = 0;
-
-       for(i = 0; i < length >> 9; i++){
-               if(cow_mask != NULL)
-                       ubd_set_bit(i, (unsigned char *) cow_mask);
-               if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
-                       continue;
-
-               update_bitmap = 1;
-               ubd_set_bit(sector + i, (unsigned char *) bitmap);
-       }
-
-       if(!update_bitmap)
-               return;
-
-       *cow_offset = sector / (sizeof(unsigned long) * 8);
-
-       /* This takes care of the case where we're exactly at the end of the
-        * device, and *cow_offset + 1 is off the end.  So, just back it up
-        * by one word.  Thanks to Lynn Kerby for the fix and James McMechan
-        * for the original diagnosis.
-        */
-       if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /
-                          sizeof(unsigned long) - 1))
-               (*cow_offset)--;
-
-       bitmap_words[0] = bitmap[*cow_offset];
-       bitmap_words[1] = bitmap[*cow_offset + 1];
-
-       *cow_offset *= sizeof(unsigned long);
-       *cow_offset += bitmap_offset;
-}
+        __u64 sector = req->offset / req->sectorsize;
+        int i;
 
-static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
-                      __u64 bitmap_offset, __u64 bitmap_len)
-{
-       __u64 sector = req->offset >> 9;
-       int i;
+        for(i = 0; i < req->length / req->sectorsize; i++){
+                if(ubd_test_bit(sector + i, bitmap))
+                        continue;
 
-       if(req->length > (sizeof(req->sector_mask) * 8) << 9)
-               panic("Operation too long");
+                if(req->bitmap_start == -1)
+                        req->bitmap_start = sector + i;
+                req->bitmap_end = sector + i + 1;
 
-       if(req->op == UBD_READ) {
-               for(i = 0; i < req->length >> 9; i++){
-                       if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
-                               ubd_set_bit(i, (unsigned char *) 
-                                           &req->sector_mask);
-                }
-       }
-       else cowify_bitmap(req->offset, req->length, &req->sector_mask,
-                          &req->cow_offset, bitmap, bitmap_offset,
-                          req->bitmap_words, bitmap_len);
+                ubd_set_bit(sector + i, bitmap);
+        }
 }
 
 /* Called with ubd_io_lock held */
-static int prepare_request(struct request *req, struct io_thread_req *io_req)
+static int prepare_request(struct request *req, struct io_thread_req *io_req,
+                           unsigned long long offset, int page_offset,
+                           int len, struct page *page)
 {
        struct gendisk *disk = req->rq_disk;
        struct ubd *dev = disk->private_data;
-       __u64 offset;
-       int len;
-
-       if(req->rq_status == RQ_INACTIVE) return(1);
 
        /* This should be impossible now */
        if((rq_data_dir(req) == WRITE) && !dev->openflags.w){
                printk("Write attempted on readonly ubd device %s\n", 
                       disk->disk_name);
-               end_request(req, 0);
+                ubd_end_request(req, 0, 0);
                return(1);
        }
 
-       offset = ((__u64) req->sector) << 9;
-       len = req->current_nr_sectors << 9;
-
        io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd;
        io_req->fds[1] = dev->fd;
-       io_req->cow_offset = -1;
        io_req->offset = offset;
        io_req->length = len;
        io_req->error = 0;
-       io_req->sector_mask = 0;
-
-       io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
+       io_req->op = (rq_data_dir(req) == READ) ? AIO_READ : AIO_WRITE;
        io_req->offsets[0] = 0;
        io_req->offsets[1] = dev->cow.data_offset;
-       io_req->buffer = req->buffer;
+        io_req->buffer = page_address(page) + page_offset;
        io_req->sectorsize = 1 << 9;
+        io_req->bitmap_offset = dev->cow.bitmap_offset;
+        io_req->bitmap_start = -1;
+        io_req->bitmap_end = -1;
 
-       if(dev->cow.file != NULL)
-               cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset,
-                          dev->cow.bitmap_len);
-
+        if((dev->cow.file != NULL) && (io_req->op == UBD_WRITE))
+                cowify_bitmap(io_req, dev->cow.bitmap);
        return(0);
 }
 
@@ -1026,30 +996,36 @@ static void do_ubd_request(request_queue_t *q)
 {
        struct io_thread_req io_req;
        struct request *req;
-       int err, n;
-
-       if(thread_fd == -1){
-               while((req = elv_next_request(q)) != NULL){
-                       err = prepare_request(req, &io_req);
-                       if(!err){
-                               do_io(&io_req);
-                               __ubd_finish(req, io_req.error);
-                       }
-               }
-       }
-       else {
-               if(do_ubd || (req = elv_next_request(q)) == NULL)
-                       return;
-               err = prepare_request(req, &io_req);
-               if(!err){
-                       do_ubd = ubd_handler;
-                       n = os_write_file(thread_fd, (char *) &io_req,
-                                        sizeof(io_req));
-                       if(n != sizeof(io_req))
-                               printk("write to io thread failed, "
-                                      "errno = %d\n", -n);
+       __u64 sector;
+       int err;
+
+       if(in_ubd)
+               return;
+       in_ubd = 1;
+       while((req = elv_next_request(q)) != NULL){
+               struct gendisk *disk = req->rq_disk;
+               struct ubd *dev = disk->private_data;
+               int n, i;
+
+               blkdev_dequeue_request(req);
+
+               sector = req->sector;
+               n = blk_rq_map_sg(q, req, dev->sg);
+
+               for(i = 0; i < n; i++){
+                       struct scatterlist *sg = &dev->sg[i];
+
+                       err = prepare_request(req, &io_req, sector << 9,
+                                             sg->offset, sg->length,
+                                             sg->page);
+                       if(err)
+                               continue;
+
+                       sector += sg->length >> 9;
+                       do_io(&io_req, req, dev->cow.bitmap);
                }
        }
+       in_ubd = 0;
 }
 
 static int ubd_ioctl(struct inode * inode, struct file * file,
@@ -1265,131 +1241,95 @@ int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
        return(err);
 }
 
-static int update_bitmap(struct io_thread_req *req)
-{
-       int n;
-
-       if(req->cow_offset == -1)
-               return(0);
-
-       n = os_seek_file(req->fds[1], req->cow_offset);
-       if(n < 0){
-               printk("do_io - bitmap lseek failed : err = %d\n", -n);
-               return(1);
-       }
-
-       n = os_write_file(req->fds[1], &req->bitmap_words,
-                         sizeof(req->bitmap_words));
-       if(n != sizeof(req->bitmap_words)){
-               printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
-                      req->fds[1]);
-               return(1);
-       }
-
-       return(0);
-}
-
-void do_io(struct io_thread_req *req)
+void do_io(struct io_thread_req *req, struct request *r, unsigned long *bitmap)
 {
-       char *buf;
-       unsigned long len;
-       int n, nsectors, start, end, bit;
-       int err;
-       __u64 off;
-
-       nsectors = req->length / req->sectorsize;
-       start = 0;
-       do {
-               bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
-               end = start;
-               while((end < nsectors) &&
-                     (ubd_test_bit(end, (unsigned char *)
-                                   &req->sector_mask) == bit))
-                       end++;
-
-               off = req->offset + req->offsets[bit] +
-                       start * req->sectorsize;
-               len = (end - start) * req->sectorsize;
-               buf = &req->buffer[start * req->sectorsize];
-
-               err = os_seek_file(req->fds[bit], off);
-               if(err < 0){
-                       printk("do_io - lseek failed : err = %d\n", -err);
-                       req->error = 1;
-                       return;
-               }
-               if(req->op == UBD_READ){
-                       n = 0;
-                       do {
-                               buf = &buf[n];
-                               len -= n;
-                               n = os_read_file(req->fds[bit], buf, len);
-                               if (n < 0) {
-                                       printk("do_io - read failed, err = %d "
-                                              "fd = %d\n", -n, req->fds[bit]);
-                                       req->error = 1;
-                                       return;
-                               }
-                       } while((n < len) && (n != 0));
-                       if (n < len) memset(&buf[n], 0, len - n);
-               } else {
-                       n = os_write_file(req->fds[bit], buf, len);
-                       if(n != len){
-                               printk("do_io - write failed err = %d "
-                                      "fd = %d\n", -n, req->fds[bit]);
-                               req->error = 1;
-                               return;
-                       }
-               }
+        struct ubd_aio *aio;
+        struct bitmap_io *bitmap_io = NULL;
+        char *buf;
+        void *bitmap_buf = NULL;
+        unsigned long len, sector;
+        int nsectors, start, end, bit, err;
+        __u64 off;
+
+        if(req->bitmap_start != -1){
+                /* Round up to the nearest word */
+                int round = sizeof(unsigned long);
+                len = (req->bitmap_end - req->bitmap_start +
+                       round * 8 - 1) / (round * 8);
+                len *= round;
+
+                off = req->bitmap_start / (8 * round);
+                off *= round;
+
+                bitmap_io = kmalloc(sizeof(*bitmap_io), GFP_KERNEL);
+                if(bitmap_io == NULL){
+                        printk("Failed to kmalloc bitmap IO\n");
+                        req->error = 1;
+                        return;
+                }
 
-               start = end;
-       } while(start < nsectors);
+                bitmap_buf = kmalloc(len, GFP_KERNEL);
+                if(bitmap_buf == NULL){
+                        printk("do_io : kmalloc of bitmap chunk "
+                               "failed\n");
+                        kfree(bitmap_io);
+                        req->error = 1;
+                        return;
+                }
+                memcpy(bitmap_buf, &bitmap[off / sizeof(bitmap[0])], len);
+
+                *bitmap_io = ((struct bitmap_io)
+                        { .count       = ATOMIC_INIT(0),
+                          .aio         = INIT_AIO(AIO_WRITE, req->fds[1],
+                                                   bitmap_buf, len,
+                                                   req->bitmap_offset + off,
+                                                   ubd_reply_fd) } );
+        }
 
-       req->error = update_bitmap(req);
-}
+        nsectors = req->length / req->sectorsize;
+        start = 0;
+        end = nsectors;
+        bit = 0;
+        do {
+                if(bitmap != NULL){
+                        sector = req->offset / req->sectorsize;
+                        bit = ubd_test_bit(sector + start, bitmap);
+                        end = start;
+                        while((end < nsectors) &&
+                              (ubd_test_bit(sector + end, bitmap) == bit))
+                                end++;
+                }
 
-/* Changed in start_io_thread, which is serialized by being called only
- * from ubd_init, which is an initcall.
- */
-int kernel_fd = -1;
+                off = req->offsets[bit] + req->offset +
+                        start * req->sectorsize;
+                len = (end - start) * req->sectorsize;
+                buf = &req->buffer[start * req->sectorsize];
 
-/* Only changed by the io thread */
-int io_count = 0;
+                aio = kmalloc(sizeof(*aio), GFP_KERNEL);
+                if(aio == NULL){
+                        req->error = 1;
+                        return;
+                }
 
-int io_thread(void *arg)
-{
-       struct io_thread_req req;
-       int n;
+                *aio = ((struct ubd_aio)
+                        { .aio         = INIT_AIO(req->op, req->fds[bit], buf,
+                                                   len, off, ubd_reply_fd),
+                          .len         = len,
+                          .req         = r,
+                          .bitmap      = bitmap_io,
+                          .bitmap_buf  = bitmap_buf });
+
+                if(aio->bitmap != NULL)
+                        atomic_inc(&aio->bitmap->count);
+
+                err = submit_aio(&aio->aio);
+                if(err){
+                        printk("do_io - submit_aio failed, "
+                               "err = %d\n", err);
+                        req->error = 1;
+                        return;
+                }
 
-       ignore_sigwinch_sig();
-       while(1){
-               n = os_read_file(kernel_fd, &req, sizeof(req));
-               if(n != sizeof(req)){
-                       if(n < 0)
-                               printk("io_thread - read failed, fd = %d, "
-                                      "err = %d\n", kernel_fd, -n);
-                       else {
-                               printk("io_thread - short read, fd = %d, "
-                                      "length = %d\n", kernel_fd, n);
-                       }
-                       continue;
-               }
-               io_count++;
-               do_io(&req);
-               n = os_write_file(kernel_fd, &req, sizeof(req));
-               if(n != sizeof(req))
-                       printk("io_thread - write failed, fd = %d, err = %d\n",
-                              kernel_fd, -n);
-       }
+                start = end;
+        } while(start < nsectors);
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/aio.h b/arch/um/include/aio.h
new file mode 100644 (file)
index 0000000..83f1687
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef AIO_H__
+#define AIO_H__
+
+enum aio_type { AIO_READ, AIO_WRITE, AIO_MMAP };
+
+struct aio_thread_reply {
+       void *data;
+       int err;
+};
+
+struct aio_context {
+       enum aio_type type;
+       int fd;
+       void *data;
+       int len;
+       unsigned long long offset;
+       int reply_fd;
+       struct aio_context *next;
+};
+
+#define INIT_AIO(aio_type, aio_fd, aio_data, aio_len, aio_offset, \
+                aio_reply_fd) \
+       { .type         = aio_type, \
+         .fd           = aio_fd, \
+         .data         = aio_data, \
+         .len          = aio_len, \
+         .offset       = aio_offset, \
+         .reply_fd     = aio_reply_fd }
+
+#define INIT_AIO_CONTEXT { .reply_fd   = -1, \
+                          .next        = NULL }
+
+extern int submit_aio(struct aio_context *aio);
+
+#endif
index d705daa2d8543119127775040796b7904525a306..0aa620970adb5a4e930f139a649ed3874742e3d6 100644 (file)
@@ -12,3 +12,4 @@ DEFINE_STR(UM_KERN_WARNING, KERN_WARNING);
 DEFINE_STR(UM_KERN_NOTICE, KERN_NOTICE);
 DEFINE_STR(UM_KERN_INFO, KERN_INFO);
 DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG);
+DEFINE(HOST_ELF_CLASS, ELF_CLASS);
index 55c2693f877827abab61514a648c8ee20ce7d98b..cbd79a8d213dc4532b8f760d3b1ca207fa98b3f1 100644 (file)
@@ -111,7 +111,15 @@ extern struct uml_param __uml_setup_start, __uml_setup_end;
 
 #ifndef __KERNEL__
 
-#define __initcall(fn) static initcall_t __initcall_##fn __init_call = fn
+#define __define_initcall(level,fn) \
+       static initcall_t __initcall_##fn __attribute_used__ \
+       __attribute__((__section__(".initcall" level ".init"))) = fn
+
+/* Userspace initcalls shouldn't depend on anything in the kernel, so we'll
+ * make them run first.
+ */
+#define __initcall(fn) __define_initcall("1", fn)
+
 #define __exitcall(fn) static exitcall_t __exitcall_##fn __exit_call = fn
 
 #define __init_call __attribute__ ((unused,__section__ (".initcall.init")))
index 3af52a634c4c2c5b9d8eb16cd93b1cd879e91e6d..c222d56b14940192c9a1b8eb659e8c966a4fb656 100644 (file)
@@ -7,12 +7,15 @@
 #define __IRQ_KERN_H__
 
 #include "linux/interrupt.h"
+#include "asm/ptrace.h"
 
 extern int um_request_irq(unsigned int irq, int fd, int type,
                          irqreturn_t (*handler)(int, void *,
                                                 struct pt_regs *),
                          unsigned long irqflags,  const char * devname,
                          void *dev_id);
+extern int init_aio_irq(int irq, char *name,
+                       irqreturn_t (*handler)(int, void *, struct pt_regs *));
 
 #endif
 
index 881d2988d2d80ef2564a41309edf0c93099f4edd..4c362458052cb3acf0d8a80256122e122b226f01 100644 (file)
@@ -153,6 +153,11 @@ extern int os_file_type(char *file);
 extern int os_file_mode(char *file, struct openflags *mode_out);
 extern int os_lock_file(int fd, int excl);
 
+/* start_up.c */
+extern void os_early_checks(void);
+extern int can_do_skas(void);
+
+/* process.c */
 extern unsigned long os_process_pc(int pid);
 extern int os_process_parent(int pid);
 extern void os_stop_process(int pid);
@@ -161,6 +166,9 @@ extern void os_kill_ptraced_process(int pid, int reap_child);
 extern void os_usr1_process(int pid);
 extern int os_getpid(void);
 extern int os_getpgrp(void);
+extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int));
+extern void init_new_thread_signals(int altstack);
+extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr);
 
 extern int os_map_memory(void *virt, int fd, unsigned long long off,
                         unsigned long len, int r, int w, int x);
@@ -170,6 +178,13 @@ extern int os_unmap_memory(void *addr, int len);
 extern void os_flush_stdout(void);
 extern unsigned long long os_usecs(void);
 
+/* tt.c
+ * for tt mode only (will be deleted in future...)
+ */
+extern void forward_pending_sigio(int target);
+extern int start_fork_tramp(void *arg, unsigned long temp_stack,
+                           int clone_flags, int (*tramp)(void *));
+
 #endif
 
 /*
diff --git a/arch/um/include/syscall.h b/arch/um/include/syscall.h
new file mode 100644 (file)
index 0000000..dda1df9
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSCALL_USER_H
+#define __SYSCALL_USER_H
+
+extern int record_syscall_start(int syscall);
+extern void record_syscall_end(int index, long result);
+
+#endif
diff --git a/arch/um/include/syscall_user.h b/arch/um/include/syscall_user.h
deleted file mode 100644 (file)
index 811d0ec..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/* 
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __SYSCALL_USER_H
-#define __SYSCALL_USER_H
-
-extern int record_syscall_start(int syscall);
-extern void record_syscall_end(int index, long result);
-
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index be0a3e3469ebd2a3d2c2350a9cef6fbea969d254..a0d5b74d3731f41f0b7b03138c882557dc022bb1 100644 (file)
@@ -16,6 +16,8 @@ extern syscall_handler_t sys_rt_sigaction;
 
 extern syscall_handler_t old_mmap_i386;
 
+extern syscall_handler_t *sys_call_table[];
+
 #define EXECUTE_SYSCALL(syscall, regs) \
        ((long (*)(struct syscall_args)) (*sys_call_table[syscall]))(SYSCALL_ARGS(&regs->regs))
 
index be8acd5efd974ac9a3b36a2b3a7703d332900996..331aa2d1f3f5469f04c0fa9bbefe0a15934edde0 100644 (file)
@@ -227,7 +227,7 @@ struct syscall_args {
                         panic("Bad register in UPT_SET : %d\n", reg);  \
                        break; \
                 } \
-                val; \
+                __upt_val; \
         })
 
 #define UPT_SET_SYSCALL_RETURN(r, res) \
index 67923cca5691952194da13faa048c94c16f560e2..e06f83e80f4a9e8aa57d5cf5ff26cd455e367d89 100644 (file)
@@ -14,6 +14,8 @@ typedef long syscall_handler_t(void);
 
 extern syscall_handler_t *ia32_sys_call_table[];
 
+extern syscall_handler_t *sys_call_table[];
+
 #define EXECUTE_SYSCALL(syscall, regs) \
        (((long (*)(long, long, long, long, long, long)) \
          (*sys_call_table[syscall]))(UPT_SYSCALL_ARG1(&regs->regs), \
index c6f9628f39bfd159a87df0dd19c07053b536142e..45d7da6c3b2c5a3eb25715e280e2274e32dcf155 100644 (file)
@@ -9,7 +9,7 @@
 #include "um_mmu.h"
 
 struct host_vm_op {
-       enum { MMAP, MUNMAP, MPROTECT } type;
+       enum { NONE, MMAP, MUNMAP, MPROTECT } type;
        union {
                struct {
                        unsigned long addr;
@@ -38,24 +38,10 @@ extern void mprotect_kernel_vm(int w);
 extern void force_flush_all(void);
 extern void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
                              unsigned long end_addr, int force,
-                             void (*do_ops)(union mm_context *,
-                                            struct host_vm_op *, int));
+                            int (*do_ops)(union mm_context *,
+                                          struct host_vm_op *, int, int,
+                                          void **));
 extern int flush_tlb_kernel_range_common(unsigned long start,
                                         unsigned long end);
 
-extern int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
-                   int r, int w, int x, struct host_vm_op *ops, int index,
-                    int last_filled, union mm_context *mmu,
-                    void (*do_ops)(union mm_context *, struct host_vm_op *,
-                                   int));
-extern int add_munmap(unsigned long addr, unsigned long len,
-                     struct host_vm_op *ops, int index, int last_filled,
-                      union mm_context *mmu,
-                      void (*do_ops)(union mm_context *, struct host_vm_op *,
-                                     int));
-extern int add_mprotect(unsigned long addr, unsigned long len, int r, int w,
-                       int x, struct host_vm_op *ops, int index,
-                        int last_filled, union mm_context *mmu,
-                        void (*do_ops)(union mm_context *, struct host_vm_op *,
-                                       int));
 #endif
index 6e348cb6de24a8eb1a0e6be8fa33868d72bbe73b..84c0868cd5613610c4f874aa280283d2d5f0a35b 100644 (file)
 #define access_ok(type, addr, size) \
        CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size)
 
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated verify_area(int type, const void __user *addr, unsigned long size)
-{
-       return (CHOOSE_MODE_PROC(verify_area_tt, verify_area_skas, type, addr,
-                               size));
-}
-
 static inline int copy_from_user(void *to, const void __user *from, int n)
 {
        return(CHOOSE_MODE_PROC(copy_from_user_tt, copy_from_user_skas, to,
index 7b6a24dfd302b7b90388a164c72e6c9ee79219f2..bb505e01d9942140ece4e25f43589d1949a03ec7 100644 (file)
@@ -54,8 +54,6 @@ extern void stack_protections(unsigned long address);
 extern void task_protections(unsigned long address);
 extern int wait_for_stop(int pid, int sig, int cont_type, void *relay);
 extern void *add_signal_handler(int sig, void (*handler)(int));
-extern int start_fork_tramp(void *arg, unsigned long temp_stack, 
-                           int clone_flags, int (*tramp)(void *));
 extern int linux_main(int argc, char **argv);
 extern void set_cmdline(char *cmd);
 extern void input_cb(void (*proc)(void *), void *arg, int arg_len);
@@ -64,8 +62,6 @@ extern void *um_kmalloc(int size);
 extern int switcheroo(int fd, int prot, void *from, void *to, int size);
 extern void setup_machinename(char *machine_out);
 extern void setup_hostinfo(void);
-extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int));
-extern void init_new_thread_signals(int altstack);
 extern void do_exec(int old_pid, int new_pid);
 extern void tracer_panic(char *msg, ...);
 extern char *get_umid(int only_if_set);
@@ -74,16 +70,12 @@ extern int detach(int pid, int sig);
 extern int attach(int pid);
 extern void kill_child_dead(int pid);
 extern int cont(int pid);
-extern void check_ptrace(void);
 extern void check_sigio(void);
-extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr);
 extern void write_sigio_workaround(void);
 extern void arch_check_bugs(void);
 extern int cpu_feature(char *what, char *buf, int len);
 extern int arch_handle_signal(int sig, union uml_pt_regs *regs);
 extern int arch_fixup(unsigned long address, void *sc_ptr);
-extern void forward_pending_sigio(int target);
-extern int can_do_skas(void);
 extern void arch_init_thread(void);
 extern int setjmp_wrapper(void (*proc)(void *, void *), ...);
 extern int raw(int fd);
index a8918e80df9623542a7b2cce781c2476b4fb9827..614b8ebeb0ed026a7ee41060eb2f5fd42a3b06c2 100644 (file)
@@ -8,25 +8,24 @@ clean-files :=
 
 obj-y = config.o exec_kern.o exitcode.o \
        helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o mem_user.o \
-       physmem.o process.o process_kern.o ptrace.o reboot.o resource.o \
-       sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \
-       syscall_kern.o sysrq.o tempfile.o time.o time_kern.o \
-       tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o umid.o \
-       user_util.o
+       physmem.o process_kern.o ptrace.o reboot.o resource.o sigio_user.o \
+       sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o sysrq.o \
+       tempfile.o time.o time_kern.o tlb.o trap_kern.o trap_user.o \
+       uaccess_user.o um_arch.o umid.o user_util.o
 
 obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
 obj-$(CONFIG_GPROF)    += gprof_syms.o
 obj-$(CONFIG_GCOV)     += gmon_syms.o
 obj-$(CONFIG_TTY_LOG)  += tty_log.o
-obj-$(CONFIG_SYSCALL_DEBUG) += syscall_user.o
+obj-$(CONFIG_SYSCALL_DEBUG) += syscall.o
 
 obj-$(CONFIG_MODE_TT) += tt/
 obj-$(CONFIG_MODE_SKAS) += skas/
 
 user-objs-$(CONFIG_TTY_LOG) += tty_log.o
 
-USER_OBJS := $(user-objs-y) config.o helper.o main.o process.o tempfile.o \
-       time.o tty_log.o umid.o user_util.o
+USER_OBJS := $(user-objs-y) config.o helper.o main.o tempfile.o time.o \
+       tty_log.o umid.o user_util.o
 
 include arch/um/scripts/Makefile.rules
 
index 9f18061ef4c98d16915f7f040709340ed6740ad2..dcd814971995ca858c2ce01667800437c65f43b9 100644 (file)
@@ -31,7 +31,7 @@
 #include "kern_util.h"
 #include "irq_user.h"
 #include "irq_kern.h"
-
+#include "os.h"
 
 /*
  * Generic, controller-independent functions:
@@ -168,13 +168,32 @@ void __init init_IRQ(void)
        }
 }
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+int init_aio_irq(int irq, char *name, irqreturn_t (*handler)(int, void *,
+                                                            struct pt_regs *))
+{
+       int fds[2], err;
+
+       err = os_pipe(fds, 1, 1);
+       if(err){
+               printk("init_aio_irq - os_pipe failed, err = %d\n", -err);
+               goto out;
+       }
+
+       err = um_request_irq(irq, fds[0], IRQ_READ, handler,
+                            SA_INTERRUPT | SA_SAMPLE_RANDOM, name,
+                            (void *) (long) fds[0]);
+       if(err){
+               printk("init_aio_irq - : um_request_irq failed, err = %d\n",
+                      err);
+               goto out_close;
+       }
+
+       err = fds[1];
+       goto out;
+
+ out_close:
+       os_close_file(fds[0]);
+       os_close_file(fds[1]);
+ out:
+       return(err);
+}
index 99439fa15ef42514b8e563623f6eaa8238c829cc..32d3076dd2204206e06aed7d835dbc4659c6e47a 100644 (file)
@@ -114,22 +114,3 @@ extern void FASTCALL( __read_lock_failed(rwlock_t *rw));
 EXPORT_SYMBOL(__read_lock_failed);
 
 #endif
-
-#ifdef CONFIG_HIGHMEM
-EXPORT_SYMBOL(kmap);
-EXPORT_SYMBOL(kunmap);
-EXPORT_SYMBOL(kmap_atomic);
-EXPORT_SYMBOL(kunmap_atomic);
-EXPORT_SYMBOL(kmap_atomic_to_page);
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 1e1a87f1c510cbc7a2d3a4ea472bd6395f6e4bb2..d31027f0fe392e9753fbe04e9ef106f719a2b5d4 100644 (file)
@@ -97,7 +97,7 @@ int main(int argc, char **argv, char **envp)
                exit(1);
        }
 
-#ifdef UML_CONFIG_MODE_TT
+#ifdef UML_CONFIG_CMDLINE_ON_HOST
        /* Allocate memory for thread command lines */
        if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){
 
index 5597bd39e6b54a9f9d93ac914327c5eb1fb264ed..64fa062cc1192bd60178d035cfe2e9bad80d67a3 100644 (file)
@@ -196,7 +196,7 @@ static void init_highmem(void)
 
 static void __init fixaddr_user_init( void)
 {
-#if CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA
+#ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA
        long size = FIXADDR_USER_END - FIXADDR_USER_START;
        pgd_t *pgd;
        pud_t *pud;
index 7807a3e8c426e362233c797a563f89523c2b7439..03618bd13d55f1521fb59a9b29224dd7fd0fd9f3 100644 (file)
@@ -87,12 +87,12 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr,
                recalc_sigpending();
                spin_unlock_irq(&current->sighand->siglock);
                force_sigsegv(signr, current);
-       }
-       else if(!(ka->sa.sa_flags & SA_NODEFER)){
+       } else {
                spin_lock_irq(&current->sighand->siglock);
                sigorsets(&current->blocked, &current->blocked, 
                          &ka->sa.sa_mask);
-               sigaddset(&current->blocked, signr);
+                if(!(ka->sa.sa_flags & SA_NODEFER))
+                       sigaddset(&current->blocked, signr);
                recalc_sigpending();
                spin_unlock_irq(&current->sighand->siglock);
        }
index d296d55ade4b99b9fac4488cb76f3420c9929a2a..db36c7c9594070669c4d328f0221f10f10550ac6 100644 (file)
@@ -4,7 +4,7 @@
 #
 
 obj-y := clone.o exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
-       syscall_kern.o syscall_user.o tlb.o trap_user.o uaccess.o \
+       syscall.o tlb.o trap_user.o uaccess.o
 
 subdir- := util
 
index 278b72f1d9adf5a6c3767dd972ae0bf153da9c06..09536f81ee42f6e527154d5085fa4f73865da114 100644 (file)
@@ -6,11 +6,15 @@
 #ifndef __SKAS_MMU_H
 #define __SKAS_MMU_H
 
+#include "linux/config.h"
 #include "mm_id.h"
 
 struct mmu_context_skas {
        struct mm_id id;
         unsigned long last_page_table;
+#ifdef CONFIG_3_LEVEL_PGTABLES
+        unsigned long last_pmd;
+#endif
 };
 
 extern void switch_mm_skas(struct mm_id * mm_idp);
index d983ea842547fe807fcd5b8c7bc1ca1d51887400..060934740f9f94e65ed1b4dafd2587b9836766ff 100644 (file)
@@ -24,28 +24,26 @@ extern void new_thread_proc(void *stack, void (*handler)(int sig));
 extern void remove_sigstack(void);
 extern void new_thread_handler(int sig);
 extern void handle_syscall(union uml_pt_regs *regs);
-extern int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
-               int r, int w, int x, int phys_fd, unsigned long long offset);
-extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len);
+extern int map(struct mm_id * mm_idp, unsigned long virt,
+              unsigned long len, int r, int w, int x, int phys_fd,
+              unsigned long long offset, int done, void **data);
+extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len,
+                int done, void **data);
 extern int protect(struct mm_id * mm_idp, unsigned long addr,
-                  unsigned long len, int r, int w, int x);
+                  unsigned long len, int r, int w, int x, int done,
+                  void **data);
 extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
-extern int new_mm(int from);
+extern int new_mm(int from, unsigned long stack);
 extern int start_userspace(unsigned long stub_stack);
 extern int copy_context_skas0(unsigned long stack, int pid);
 extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
 extern long execute_syscall_skas(void *r);
 extern unsigned long current_stub_stack(void);
+extern long run_syscall_stub(struct mm_id * mm_idp,
+                             int syscall, unsigned long *args, long expected,
+                             void **addr, int done);
+extern long syscall_stub_data(struct mm_id * mm_idp,
+                              unsigned long *data, int data_count,
+                              void **addr, void **stub_addr);
 
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index b0980ff3bd95bb14279ad94e2581f91ae725d1ac..1d89640bd5028852c5cf180534a37237ebaed8c3 100644 (file)
@@ -5,13 +5,14 @@
 
 #include <signal.h>
 #include <errno.h>
+#include <string.h>
 #include <sys/mman.h>
 #include <sys/wait.h>
 #include <asm/page.h>
 #include <asm/unistd.h>
 #include "mem_user.h"
 #include "mem.h"
-#include "mm_id.h"
+#include "skas.h"
 #include "user.h"
 #include "os.h"
 #include "proc_mm.h"
 #include "uml-config.h"
 #include "sysdep/ptrace.h"
 #include "sysdep/stub.h"
-#include "skas.h"
 
-extern unsigned long syscall_stub, __syscall_stub_start;
+extern unsigned long batch_syscall_stub, __syscall_stub_start;
 
 extern void wait_stub_done(int pid, int sig, char * fname);
 
-static long run_syscall_stub(struct mm_id * mm_idp, int syscall,
-                             unsigned long *args)
+static inline unsigned long *check_init_stack(struct mm_id * mm_idp,
+                                             unsigned long *stack)
+{
+       if(stack == NULL){
+               stack = (unsigned long *) mm_idp->stack + 2;
+               *stack = 0;
+       }
+       return stack;
+}
+
+extern int proc_mm;
+
+int single_count = 0;
+int multi_count = 0;
+int multi_op_count = 0;
+
+static long do_syscall_stub(struct mm_id *mm_idp, void **addr)
 {
+       unsigned long regs[MAX_REG_NR];
+       unsigned long *data;
+       unsigned long *syscall;
+       long ret, offset;
         int n, pid = mm_idp->u.pid;
-        unsigned long regs[MAX_REG_NR];
+
+       if(proc_mm)
+#warning Need to look up userspace_pid by cpu
+               pid = userspace_pid[0];
+
+       multi_count++;
 
         get_safe_registers(regs);
         regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
-                ((unsigned long) &syscall_stub -
+               ((unsigned long) &batch_syscall_stub -
                  (unsigned long) &__syscall_stub_start);
-        /* XXX Don't have a define for starting a syscall */
-        regs[REGS_SYSCALL_NR] = syscall;
-        regs[REGS_SYSCALL_ARG1] = args[0];
-        regs[REGS_SYSCALL_ARG2] = args[1];
-        regs[REGS_SYSCALL_ARG3] = args[2];
-        regs[REGS_SYSCALL_ARG4] = args[3];
-        regs[REGS_SYSCALL_ARG5] = args[4];
-        regs[REGS_SYSCALL_ARG6] = args[5];
-        n = ptrace_setregs(pid, regs);
-        if(n < 0){
-                printk("run_syscall_stub : PTRACE_SETREGS failed, "
-                       "errno = %d\n", n);
-                return(n);
+       n = ptrace_setregs(pid, regs);
+       if(n < 0)
+               panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n",
+                     n);
+
+       wait_stub_done(pid, 0, "do_syscall_stub");
+
+       /* When the stub stops, we find the following values on the
+        * beginning of the stack:
+        * (long )return_value
+        * (long )offset to failed sycall-data (0, if no error)
+        */
+       ret = *((unsigned long *) mm_idp->stack);
+       offset = *((unsigned long *) mm_idp->stack + 1);
+       if (offset) {
+               data = (unsigned long *)(mm_idp->stack +
+                                        offset - UML_CONFIG_STUB_DATA);
+               syscall = (unsigned long *)((unsigned long)data + data[0]);
+               printk("do_syscall_stub: syscall %ld failed, return value = "
+                      "0x%lx, expected return value = 0x%lx\n",
+                      syscall[0], ret, syscall[7]);
+               printk("    syscall parameters: "
+                      "0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
+                      syscall[1], syscall[2], syscall[3],
+                      syscall[4], syscall[5], syscall[6]);
+               for(n = 1; n < data[0]/sizeof(long); n++) {
+                       if(n == 1)
+                               printk("    additional syscall data:");
+                       if(n % 4 == 1)
+                               printk("\n      ");
+                       printk("  0x%lx", data[n]);
+               }
+               if(n > 1)
+                       printk("\n");
+       }
+       else ret = 0;
+
+       *addr = check_init_stack(mm_idp, NULL);
+
+       return ret;
+}
+
+long run_syscall_stub(struct mm_id * mm_idp, int syscall,
+                     unsigned long *args, long expected, void **addr,
+                     int done)
+{
+       unsigned long *stack = check_init_stack(mm_idp, *addr);
+
+       if(done && *addr == NULL)
+               single_count++;
+
+       *stack += sizeof(long);
+       stack += *stack / sizeof(long);
+
+        *stack++ = syscall;
+        *stack++ = args[0];
+        *stack++ = args[1];
+        *stack++ = args[2];
+        *stack++ = args[3];
+        *stack++ = args[4];
+        *stack++ = args[5];
+       *stack++ = expected;
+        *stack = 0;
+        multi_op_count++;
+
+        if(!done && ((((unsigned long) stack) & ~PAGE_MASK) <
+                    PAGE_SIZE - 10 * sizeof(long))){
+               *addr = stack;
+                return 0;
         }
 
-        wait_stub_done(pid, 0, "run_syscall_stub");
+       return do_syscall_stub(mm_idp, addr);
+}
+
+long syscall_stub_data(struct mm_id * mm_idp,
+                      unsigned long *data, int data_count,
+                      void **addr, void **stub_addr)
+{
+       unsigned long *stack;
+       int ret = 0;
 
-        return(*((unsigned long *) mm_idp->stack));
+       /* If *addr still is uninitialized, it *must* contain NULL.
+        * Thus in this case do_syscall_stub correctly won't be called.
+        */
+       if((((unsigned long) *addr) & ~PAGE_MASK) >=
+          PAGE_SIZE - (10 + data_count) * sizeof(long)) {
+               ret = do_syscall_stub(mm_idp, addr);
+               /* in case of error, don't overwrite data on stack */
+               if(ret)
+                       return ret;
+       }
+
+       stack = check_init_stack(mm_idp, *addr);
+       *addr = stack;
+
+       *stack = data_count * sizeof(long);
+
+       memcpy(stack + 1, data, data_count * sizeof(long));
+
+       *stub_addr = (void *)(((unsigned long)(stack + 1) & ~PAGE_MASK) +
+                             UML_CONFIG_STUB_DATA);
+
+       return 0;
 }
 
-int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len,
-        int r, int w, int x, int phys_fd, unsigned long long offset)
+int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
+       int r, int w, int x, int phys_fd, unsigned long long offset,
+       int done, void **data)
 {
-        int prot, n;
+        int prot, ret;
 
         prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
                 (x ? PROT_EXEC : 0);
@@ -70,6 +180,7 @@ int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len,
         if(proc_mm){
                 struct proc_mm_op map;
                 int fd = mm_idp->u.mm_fd;
+
                 map = ((struct proc_mm_op) { .op       = MM_MMAP,
                                              .u                =
                                              { .mmap   =
@@ -81,63 +192,61 @@ int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len,
                                                  .fd   = phys_fd,
                                                  .offset= offset
                                                } } } );
-                n = os_write_file(fd, &map, sizeof(map));
-                if(n != sizeof(map))
-                        printk("map : /proc/mm map failed, err = %d\n", -n);
+               ret = os_write_file(fd, &map, sizeof(map));
+               if(ret != sizeof(map))
+                       printk("map : /proc/mm map failed, err = %d\n", -ret);
+               else ret = 0;
         }
         else {
-                long res;
                 unsigned long args[] = { virt, len, prot,
                                          MAP_SHARED | MAP_FIXED, phys_fd,
                                          MMAP_OFFSET(offset) };
 
-                res = run_syscall_stub(mm_idp, STUB_MMAP_NR, args);
-                if((void *) res == MAP_FAILED)
-                        printk("mmap stub failed, errno = %d\n", res);
+               ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt,
+                                      data, done);
         }
 
-        return 0;
+       return ret;
 }
 
-int unmap(struct mm_id *mm_idp, void *addr, unsigned long len)
+int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done,
+         void **data)
 {
-        int n;
+        int ret;
 
         if(proc_mm){
                 struct proc_mm_op unmap;
                 int fd = mm_idp->u.mm_fd;
+
                 unmap = ((struct proc_mm_op) { .op     = MM_MUNMAP,
                                                .u      =
                                                { .munmap       =
                                                  { .addr       =
                                                    (unsigned long) addr,
                                                    .len                = len } } } );
-                n = os_write_file(fd, &unmap, sizeof(unmap));
-                if(n != sizeof(unmap)) {
-                        if(n < 0)
-                                return(n);
-                        else if(n > 0)
-                                return(-EIO);
-                }
+               ret = os_write_file(fd, &unmap, sizeof(unmap));
+               if(ret != sizeof(unmap))
+                       printk("unmap - proc_mm write returned %d\n", ret);
+               else ret = 0;
         }
         else {
-                int res;
                 unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
                                          0 };
 
-                res = run_syscall_stub(mm_idp, __NR_munmap, args);
-                if(res < 0)
-                        printk("munmap stub failed, errno = %d\n", res);
+               ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0,
+                                      data, done);
+                if(ret < 0)
+                        printk("munmap stub failed, errno = %d\n", ret);
         }
 
-        return(0);
+        return ret;
 }
 
-int protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len,
-           int r, int w, int x)
+int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
+           int r, int w, int x, int done, void **data)
 {
         struct proc_mm_op protect;
-        int prot, n;
+        int prot, ret;
 
         prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
                 (x ? PROT_EXEC : 0);
@@ -152,20 +261,19 @@ int protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len,
                                                      .len      = len,
                                                      .prot     = prot } } } );
 
-                n = os_write_file(fd, &protect, sizeof(protect));
-                if(n != sizeof(protect))
-                        panic("protect failed, err = %d", -n);
+                ret = os_write_file(fd, &protect, sizeof(protect));
+                if(ret != sizeof(protect))
+                        printk("protect failed, err = %d", -ret);
+                else ret = 0;
         }
         else {
-                int res;
                 unsigned long args[] = { addr, len, prot, 0, 0, 0 };
 
-                res = run_syscall_stub(mm_idp, __NR_mprotect, args);
-                if(res < 0)
-                        panic("mprotect stub failed, errno = %d\n", res);
+                ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0,
+                                       data, done);
         }
 
-        return(0);
+        return ret;
 }
 
 void before_mem_skas(unsigned long unused)
index d232daa42c314c009aa5e76141eae73217711641..240143b616a2c359629492e38fcfa8056732aa78 100644 (file)
@@ -56,6 +56,9 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
         */
 
         mm->context.skas.last_page_table = pmd_page_kernel(*pmd);
+#ifdef CONFIG_3_LEVEL_PGTABLES
+        mm->context.skas.last_pmd = (unsigned long) __va(pud_val(*pud));
+#endif
 
        *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT));
        *pte = pte_mkexec(*pte);
@@ -77,23 +80,14 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
        struct mm_struct *cur_mm = current->mm;
        struct mm_id *cur_mm_id = &cur_mm->context.skas.id;
        struct mm_id *mm_id = &mm->context.skas.id;
-       unsigned long stack;
-       int from, ret;
+       unsigned long stack = 0;
+       int from, ret = -ENOMEM;
 
-       if(proc_mm){
-               if((cur_mm != NULL) && (cur_mm != &init_mm))
-                       from = cur_mm->context.skas.id.u.mm_fd;
-               else from = -1;
+       if(!proc_mm || !ptrace_faultinfo){
+               stack = get_zeroed_page(GFP_KERNEL);
+               if(stack == 0)
+                       goto out;
 
-               ret = new_mm(from);
-               if(ret < 0){
-                       printk("init_new_context_skas - new_mm failed, "
-                              "errno = %d\n", ret);
-                       return ret;
-               }
-               mm_id->u.mm_fd = ret;
-       }
-       else {
                /* This zeros the entry that pgd_alloc didn't, needed since
                 * we are about to reinitialize it, and want mm.nr_ptes to
                 * be accurate.
@@ -103,20 +97,30 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
                ret = init_stub_pte(mm, CONFIG_STUB_CODE,
                                    (unsigned long) &__syscall_stub_start);
                if(ret)
-                       goto out;
-
-               ret = -ENOMEM;
-               stack = get_zeroed_page(GFP_KERNEL);
-               if(stack == 0)
-                       goto out;
-               mm_id->stack = stack;
+                       goto out_free;
 
                ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack);
                if(ret)
                        goto out_free;
 
                mm->nr_ptes--;
+       }
+       mm_id->stack = stack;
 
+       if(proc_mm){
+               if((cur_mm != NULL) && (cur_mm != &init_mm))
+                       from = cur_mm_id->u.mm_fd;
+               else from = -1;
+
+               ret = new_mm(from, stack);
+               if(ret < 0){
+                       printk("init_new_context_skas - new_mm failed, "
+                              "errno = %d\n", ret);
+                       goto out_free;
+               }
+               mm_id->u.mm_fd = ret;
+       }
+       else {
                if((cur_mm != NULL) && (cur_mm != &init_mm))
                        mm_id->u.pid = copy_context_skas0(stack,
                                                          cur_mm_id->u.pid);
@@ -126,7 +130,8 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
        return 0;
 
  out_free:
-       free_page(mm_id->stack);
+       if(mm_id->stack != 0)
+               free_page(mm_id->stack);
  out:
        return ret;
 }
@@ -137,9 +142,15 @@ void destroy_context_skas(struct mm_struct *mm)
 
        if(proc_mm)
                os_close_file(mmu->id.u.mm_fd);
-       else {
+       else
                os_kill_ptraced_process(mmu->id.u.pid, 1);
+
+       if(!proc_mm || !ptrace_faultinfo){
                free_page(mmu->id.stack);
-               free_page(mmu->last_page_table);
+               pte_free_kernel((pte_t *) mmu->last_page_table);
+                dec_page_state(nr_page_table_pages);
+#ifdef CONFIG_3_LEVEL_PGTABLES
+               pmd_free((pmd_t *) mmu->last_pmd);
+#endif
        }
 }
index f228f8b54194f3216b5382e83fea567af1471a2c..5cd0e992978969c8d076b3fd9ce4fd0fe9d3a4c1 100644 (file)
@@ -138,6 +138,8 @@ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu
 }
 
 extern int __syscall_stub_start;
+int stub_code_fd = -1;
+__u64 stub_code_offset;
 
 static int userspace_tramp(void *stack)
 {
@@ -152,31 +154,31 @@ static int userspace_tramp(void *stack)
                /* This has a pte, but it can't be mapped in with the usual
                 * tlb_flush mechanism because this is part of that mechanism
                 */
-               int fd;
-               __u64 offset;
-
-               fd = phys_mapping(to_phys(&__syscall_stub_start), &offset);
                addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(),
-                             PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
+                             PROT_EXEC, MAP_FIXED | MAP_PRIVATE,
+                             stub_code_fd, stub_code_offset);
                if(addr == MAP_FAILED){
-                       printk("mapping mmap stub failed, errno = %d\n",
+                       printk("mapping stub code failed, errno = %d\n",
                               errno);
                        exit(1);
                }
 
                if(stack != NULL){
+                       int fd;
+                       __u64 offset;
+
                        fd = phys_mapping(to_phys(stack), &offset);
                        addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(),
                                    PROT_READ | PROT_WRITE,
                                    MAP_FIXED | MAP_SHARED, fd, offset);
                        if(addr == MAP_FAILED){
-                               printk("mapping segfault stack failed, "
+                               printk("mapping stub stack failed, "
                                       "errno = %d\n", errno);
                                exit(1);
                        }
                }
        }
-       if(!ptrace_faultinfo && (stack != NULL)){
+       if(!ptrace_faultinfo){
                unsigned long v = UML_CONFIG_STUB_CODE +
                                  (unsigned long) stub_segv_handler -
                                  (unsigned long) &__syscall_stub_start;
@@ -202,6 +204,10 @@ int start_userspace(unsigned long stub_stack)
        unsigned long sp;
        int pid, status, n, flags;
 
+       if ( stub_code_fd == -1 )
+               stub_code_fd = phys_mapping(to_phys(&__syscall_stub_start),
+                                           &stub_code_offset);
+
        stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        if(stack == MAP_FAILED)
@@ -363,6 +369,53 @@ int copy_context_skas0(unsigned long new_stack, int pid)
        return pid;
 }
 
+/*
+ * This is used only, if proc_mm is available, while PTRACE_FAULTINFO
+ * isn't. Opening /proc/mm creates a new mm_context, which lacks the stub-pages
+ * Thus, we map them using /proc/mm-fd
+ */
+void map_stub_pages(int fd, unsigned long code,
+                   unsigned long data, unsigned long stack)
+{
+       struct proc_mm_op mmop;
+       int n;
+
+       mmop = ((struct proc_mm_op) { .op        = MM_MMAP,
+                                     .u         =
+                                     { .mmap    =
+                                       { .addr    = code,
+                                         .len     = PAGE_SIZE,
+                                         .prot    = PROT_EXEC,
+                                         .flags   = MAP_FIXED | MAP_PRIVATE,
+                                         .fd      = stub_code_fd,
+                                         .offset  = stub_code_offset
+       } } });
+       n = os_write_file(fd, &mmop, sizeof(mmop));
+       if(n != sizeof(mmop))
+               panic("map_stub_pages : /proc/mm map for code failed, "
+                     "err = %d\n", -n);
+
+       if ( stack ) {
+               __u64 map_offset;
+               int map_fd = phys_mapping(to_phys((void *)stack), &map_offset);
+               mmop = ((struct proc_mm_op)
+                               { .op        = MM_MMAP,
+                                 .u         =
+                                 { .mmap    =
+                                   { .addr    = data,
+                                     .len     = PAGE_SIZE,
+                                     .prot    = PROT_READ | PROT_WRITE,
+                                     .flags   = MAP_FIXED | MAP_SHARED,
+                                     .fd      = map_fd,
+                                     .offset  = map_offset
+               } } });
+               n = os_write_file(fd, &mmop, sizeof(mmop));
+               if(n != sizeof(mmop))
+                       panic("map_stub_pages : /proc/mm map for data failed, "
+                             "err = %d\n", -n);
+       }
+}
+
 void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
                void (*handler)(int))
 {
index cbabab104ac3ef904bdd7a2f9ec43e3d415e73ab..3d1b227226e653d6ded1b4b8005c6d20a388530d 100644 (file)
@@ -129,7 +129,9 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
        return(0);
 }
 
-int new_mm(int from)
+extern void map_stub_pages(int fd, unsigned long code,
+                          unsigned long data, unsigned long stack);
+int new_mm(int from, unsigned long stack)
 {
        struct proc_mm_op copy;
        int n, fd;
@@ -148,6 +150,9 @@ int new_mm(int from)
                               "err = %d\n", -n);
        }
 
+       if(!ptrace_faultinfo)
+               map_stub_pages(fd, CONFIG_STUB_CODE, CONFIG_STUB_DATA, stack);
+
        return(fd);
 }
 
diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c
new file mode 100644 (file)
index 0000000..51fb940
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sys.h"
+#include "linux/ptrace.h"
+#include "asm/errno.h"
+#include "asm/unistd.h"
+#include "asm/ptrace.h"
+#include "asm/current.h"
+#include "sysdep/syscalls.h"
+#include "kern_util.h"
+#include "syscall.h"
+
+void handle_syscall(union uml_pt_regs *r)
+{
+       struct pt_regs *regs = container_of(r, struct pt_regs, regs);
+       long result;
+       int syscall;
+#ifdef UML_CONFIG_SYSCALL_DEBUG
+       int index;
+
+       index = record_syscall_start(UPT_SYSCALL_NR(r));
+#endif
+       syscall_trace(r, 0);
+
+       current->thread.nsyscalls++;
+       nsyscalls++;
+
+       /* This should go in the declaration of syscall, but when I do that,
+        * strace -f -c bash -c 'ls ; ls' breaks, sometimes not tracing
+        * children at all, sometimes hanging when bash doesn't see the first
+        * ls exit.
+        * The assembly looks functionally the same to me.  This is
+        *     gcc version 4.0.1 20050727 (Red Hat 4.0.1-5)
+        * in case it's a compiler bug.
+        */
+       syscall = UPT_SYSCALL_NR(r);
+       if((syscall >= NR_syscalls) || (syscall < 0))
+               result = -ENOSYS;
+       else result = EXECUTE_SYSCALL(syscall, regs);
+
+       REGS_SET_SYSCALL_RETURN(r->skas.regs, result);
+
+       syscall_trace(r, 1);
+#ifdef UML_CONFIG_SYSCALL_DEBUG
+       record_syscall_end(index, result);
+#endif
+}
diff --git a/arch/um/kernel/skas/syscall_kern.c b/arch/um/kernel/skas/syscall_kern.c
deleted file mode 100644 (file)
index bdf040c..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/* 
- * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
- * Licensed under the GPL
- */
-
-#include "linux/sys.h"
-#include "linux/ptrace.h"
-#include "asm/errno.h"
-#include "asm/unistd.h"
-#include "asm/ptrace.h"
-#include "asm/current.h"
-#include "sysdep/syscalls.h"
-#include "kern_util.h"
-
-extern syscall_handler_t *sys_call_table[];
-
-long execute_syscall_skas(void *r)
-{
-       struct pt_regs *regs = r;
-       long res;
-       int syscall;
-
-       current->thread.nsyscalls++;
-       nsyscalls++;
-       syscall = UPT_SYSCALL_NR(&regs->regs);
-
-       if((syscall >= NR_syscalls) || (syscall < 0))
-               res = -ENOSYS;
-       else res = EXECUTE_SYSCALL(syscall, regs);
-
-       return(res);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/skas/syscall_user.c b/arch/um/kernel/skas/syscall_user.c
deleted file mode 100644 (file)
index 6b06649..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* 
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdlib.h>
-#include <signal.h>
-#include "kern_util.h"
-#include "uml-config.h"
-#include "syscall_user.h"
-#include "sysdep/ptrace.h"
-#include "sysdep/sigcontext.h"
-#include "skas.h"
-
-void handle_syscall(union uml_pt_regs *regs)
-{
-       long result;
-#ifdef UML_CONFIG_SYSCALL_DEBUG
-       int index;
-
-       index = record_syscall_start(UPT_SYSCALL_NR(regs));
-#endif
-
-       syscall_trace(regs, 0);
-       result = execute_syscall_skas(regs);
-
-       REGS_SET_SYSCALL_RETURN(regs->skas.regs, result);
-
-       syscall_trace(regs, 1);
-#ifdef UML_CONFIG_SYSCALL_DEBUG
-       record_syscall_end(index, result);
-#endif
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 6230999c672c90ff3a36abf31d23f8c774c3f2eb..6e84963dfc29e99c93bcdfe1cd2e11c1103c9310 100644 (file)
 #include "os.h"
 #include "tlb.h"
 
-static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
+static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last,
+                 int finished, void **flush)
 {
        struct host_vm_op *op;
-       int i;
+        int i, ret = 0;
 
-       for(i = 0; i <= last; i++){
+        for(i = 0; i <= last && !ret; i++){
                op = &ops[i];
                switch(op->type){
                case MMAP:
-                        map(&mmu->skas.id, op->u.mmap.addr, op->u.mmap.len,
-                           op->u.mmap.r, op->u.mmap.w, op->u.mmap.x,
-                           op->u.mmap.fd, op->u.mmap.offset);
+                       ret = map(&mmu->skas.id, op->u.mmap.addr,
+                                 op->u.mmap.len, op->u.mmap.r, op->u.mmap.w,
+                                 op->u.mmap.x, op->u.mmap.fd,
+                                 op->u.mmap.offset, finished, flush);
                        break;
                case MUNMAP:
-                        unmap(&mmu->skas.id, (void *) op->u.munmap.addr,
-                             op->u.munmap.len);
+                       ret = unmap(&mmu->skas.id,
+                                   (void *) op->u.munmap.addr,
+                                   op->u.munmap.len, finished, flush);
                        break;
                case MPROTECT:
-                        protect(&mmu->skas.id, op->u.mprotect.addr,
-                                op->u.mprotect.len, op->u.mprotect.r,
-                                op->u.mprotect.w, op->u.mprotect.x);
+                       ret = protect(&mmu->skas.id, op->u.mprotect.addr,
+                                     op->u.mprotect.len, op->u.mprotect.r,
+                                     op->u.mprotect.w, op->u.mprotect.x,
+                                     finished, flush);
                        break;
                default:
                        printk("Unknown op type %d in do_ops\n", op->type);
                        break;
                }
        }
+
+       return ret;
 }
 
 extern int proc_mm;
diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c
new file mode 100644 (file)
index 0000000..1429c13
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "kern_util.h"
+#include "syscall.h"
+#include "os.h"
+
+struct {
+       int syscall;
+       int pid;
+       long result;
+       unsigned long long start;
+       unsigned long long end;
+} syscall_record[1024];
+
+int record_syscall_start(int syscall)
+{
+       int max, index;
+
+       max = sizeof(syscall_record)/sizeof(syscall_record[0]);
+       index = next_syscall_index(max);
+
+       syscall_record[index].syscall = syscall;
+       syscall_record[index].pid = current_pid();
+       syscall_record[index].result = 0xdeadbeef;
+       syscall_record[index].start = os_usecs();
+       return(index);
+}
+
+void record_syscall_end(int index, long result)
+{
+       syscall_record[index].result = result;
+       syscall_record[index].end = os_usecs();
+}
diff --git a/arch/um/kernel/syscall_user.c b/arch/um/kernel/syscall_user.c
deleted file mode 100644 (file)
index 01b711e..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* 
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdlib.h>
-#include <sys/time.h>
-#include "kern_util.h"
-#include "syscall_user.h"
-
-struct {
-       int syscall;
-       int pid;
-       long result;
-       struct timeval start;
-       struct timeval end;
-} syscall_record[1024];
-
-int record_syscall_start(int syscall)
-{
-       int max, index;
-
-       max = sizeof(syscall_record)/sizeof(syscall_record[0]);
-       index = next_syscall_index(max);
-
-       syscall_record[index].syscall = syscall;
-       syscall_record[index].pid = current_pid();
-       syscall_record[index].result = 0xdeadbeef;
-       gettimeofday(&syscall_record[index].start, NULL);
-       return(index);
-}
-
-void record_syscall_end(int index, long result)
-{
-       syscall_record[index].result = result;
-       gettimeofday(&syscall_record[index].end, NULL);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 83ec8d4747fd039482aca79dc9137371d0b86989..80ed6188e8a21a511ce60216ffe7e53cb3f8786c 100644 (file)
 #include "mem_user.h"
 #include "os.h"
 
+static int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
+                   int r, int w, int x, struct host_vm_op *ops, int *index,
+                   int last_filled, union mm_context *mmu, void **flush,
+                   int (*do_ops)(union mm_context *, struct host_vm_op *,
+                                 int, int, void **))
+{
+        __u64 offset;
+       struct host_vm_op *last;
+       int fd, ret = 0;
+
+       fd = phys_mapping(phys, &offset);
+       if(*index != -1){
+               last = &ops[*index];
+               if((last->type == MMAP) &&
+                  (last->u.mmap.addr + last->u.mmap.len == virt) &&
+                  (last->u.mmap.r == r) && (last->u.mmap.w == w) &&
+                  (last->u.mmap.x == x) && (last->u.mmap.fd == fd) &&
+                  (last->u.mmap.offset + last->u.mmap.len == offset)){
+                       last->u.mmap.len += len;
+                       return 0;
+               }
+       }
+
+       if(*index == last_filled){
+               ret = (*do_ops)(mmu, ops, last_filled, 0, flush);
+               *index = -1;
+       }
+
+       ops[++*index] = ((struct host_vm_op) { .type    = MMAP,
+                                               .u = { .mmap = {
+                                                      .addr    = virt,
+                                                      .len     = len,
+                                                      .r       = r,
+                                                      .w       = w,
+                                                      .x       = x,
+                                                      .fd      = fd,
+                                                      .offset  = offset }
+                          } });
+       return ret;
+}
+
+static int add_munmap(unsigned long addr, unsigned long len,
+                     struct host_vm_op *ops, int *index, int last_filled,
+                     union mm_context *mmu, void **flush,
+                     int (*do_ops)(union mm_context *, struct host_vm_op *,
+                                   int, int, void **))
+{
+       struct host_vm_op *last;
+       int ret = 0;
+
+       if(*index != -1){
+               last = &ops[*index];
+               if((last->type == MUNMAP) &&
+                  (last->u.munmap.addr + last->u.mmap.len == addr)){
+                       last->u.munmap.len += len;
+                       return 0;
+               }
+       }
+
+       if(*index == last_filled){
+               ret = (*do_ops)(mmu, ops, last_filled, 0, flush);
+               *index = -1;
+       }
+
+       ops[++*index] = ((struct host_vm_op) { .type    = MUNMAP,
+                                              .u = { .munmap = {
+                                                       .addr   = addr,
+                                                       .len    = len } } });
+       return ret;
+}
+
+static int add_mprotect(unsigned long addr, unsigned long len, int r, int w,
+                       int x, struct host_vm_op *ops, int *index,
+                       int last_filled, union mm_context *mmu, void **flush,
+                       int (*do_ops)(union mm_context *, struct host_vm_op *,
+                                     int, int, void **))
+{
+       struct host_vm_op *last;
+       int ret = 0;
+
+       if(*index != -1){
+               last = &ops[*index];
+               if((last->type == MPROTECT) &&
+                  (last->u.mprotect.addr + last->u.mprotect.len == addr) &&
+                  (last->u.mprotect.r == r) && (last->u.mprotect.w == w) &&
+                  (last->u.mprotect.x == x)){
+                       last->u.mprotect.len += len;
+                       return 0;
+               }
+       }
+
+       if(*index == last_filled){
+               ret = (*do_ops)(mmu, ops, last_filled, 0, flush);
+               *index = -1;
+       }
+
+       ops[++*index] = ((struct host_vm_op) { .type    = MPROTECT,
+                                              .u = { .mprotect = {
+                                                      .addr    = addr,
+                                                      .len     = len,
+                                                      .r       = r,
+                                                      .w       = w,
+                                                      .x       = x } } });
+       return ret;
+}
+
 #define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1))
 
 void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
                       unsigned long end_addr, int force,
-                      void (*do_ops)(union mm_context *, struct host_vm_op *,
-                                     int))
+                     int (*do_ops)(union mm_context *, struct host_vm_op *,
+                                   int, int, void **))
 {
         pgd_t *npgd;
         pud_t *npud;
@@ -29,21 +135,24 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
         union mm_context *mmu = &mm->context;
         unsigned long addr, end;
         int r, w, x;
-        struct host_vm_op ops[16];
+        struct host_vm_op ops[1];
+        void *flush = NULL;
         int op_index = -1, last_op = sizeof(ops) / sizeof(ops[0]) - 1;
+        int ret = 0;
 
         if(mm == NULL) return;
 
-        for(addr = start_addr; addr < end_addr;){
+        ops[0].type = NONE;
+        for(addr = start_addr; addr < end_addr && !ret;){
                 npgd = pgd_offset(mm, addr);
                 if(!pgd_present(*npgd)){
                         end = ADD_ROUND(addr, PGDIR_SIZE);
                         if(end > end_addr)
                                 end = end_addr;
                         if(force || pgd_newpage(*npgd)){
-                                op_index = add_munmap(addr, end - addr, ops,
-                                                      op_index, last_op, mmu,
-                                                      do_ops);
+                                ret = add_munmap(addr, end - addr, ops,
+                                                 &op_index, last_op, mmu,
+                                                 &flush, do_ops);
                                 pgd_mkuptodate(*npgd);
                         }
                         addr = end;
@@ -56,9 +165,9 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
                         if(end > end_addr)
                                 end = end_addr;
                         if(force || pud_newpage(*npud)){
-                                op_index = add_munmap(addr, end - addr, ops,
-                                                      op_index, last_op, mmu,
-                                                      do_ops);
+                                ret = add_munmap(addr, end - addr, ops,
+                                                 &op_index, last_op, mmu,
+                                                 &flush, do_ops);
                                 pud_mkuptodate(*npud);
                         }
                         addr = end;
@@ -71,9 +180,9 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
                         if(end > end_addr)
                                 end = end_addr;
                         if(force || pmd_newpage(*npmd)){
-                                op_index = add_munmap(addr, end - addr, ops,
-                                                      op_index, last_op, mmu,
-                                                      do_ops);
+                                ret = add_munmap(addr, end - addr, ops,
+                                                 &op_index, last_op, mmu,
+                                                 &flush, do_ops);
                                 pmd_mkuptodate(*npmd);
                         }
                         addr = end;
@@ -92,24 +201,32 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
                 }
                 if(force || pte_newpage(*npte)){
                         if(pte_present(*npte))
-                                op_index = add_mmap(addr,
-                                                    pte_val(*npte) & PAGE_MASK,
-                                                    PAGE_SIZE, r, w, x, ops,
-                                                    op_index, last_op, mmu,
-                                                    do_ops);
-                        else op_index = add_munmap(addr, PAGE_SIZE, ops,
-                                                   op_index, last_op, mmu,
-                                                   do_ops);
+                         ret = add_mmap(addr,
+                                        pte_val(*npte) & PAGE_MASK,
+                                        PAGE_SIZE, r, w, x, ops,
+                                        &op_index, last_op, mmu,
+                                        &flush, do_ops);
+                       else ret = add_munmap(addr, PAGE_SIZE, ops,
+                                             &op_index, last_op, mmu,
+                                             &flush, do_ops);
                 }
                 else if(pte_newprot(*npte))
-                        op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
-                                                op_index, last_op, mmu,
-                                                do_ops);
+                       ret = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
+                                          &op_index, last_op, mmu,
+                                          &flush, do_ops);
 
                 *npte = pte_mkuptodate(*npte);
                 addr += PAGE_SIZE;
         }
-        (*do_ops)(mmu, ops, op_index);
+
+       if(!ret)
+               ret = (*do_ops)(mmu, ops, op_index, 1, &flush);
+
+       /* This is not an else because ret is modified above */
+       if(ret) {
+               printk("fix_range_common: failed, killing current process\n");
+               force_sig(SIGKILL, current);
+       }
 }
 
 int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
@@ -226,106 +343,6 @@ pte_t *addr_pte(struct task_struct *task, unsigned long addr)
         return(pte_offset_map(pmd, addr));
 }
 
-int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
-             int r, int w, int x, struct host_vm_op *ops, int index,
-             int last_filled, union mm_context *mmu,
-             void (*do_ops)(union mm_context *, struct host_vm_op *, int))
-{
-        __u64 offset;
-       struct host_vm_op *last;
-       int fd;
-
-       fd = phys_mapping(phys, &offset);
-       if(index != -1){
-               last = &ops[index];
-               if((last->type == MMAP) &&
-                  (last->u.mmap.addr + last->u.mmap.len == virt) &&
-                  (last->u.mmap.r == r) && (last->u.mmap.w == w) &&
-                  (last->u.mmap.x == x) && (last->u.mmap.fd == fd) &&
-                  (last->u.mmap.offset + last->u.mmap.len == offset)){
-                       last->u.mmap.len += len;
-                       return(index);
-               }
-       }
-
-       if(index == last_filled){
-               (*do_ops)(mmu, ops, last_filled);
-               index = -1;
-       }
-
-       ops[++index] = ((struct host_vm_op) { .type     = MMAP,
-                                             .u = { .mmap = {
-                                                     .addr     = virt,
-                                                     .len      = len,
-                                                     .r        = r,
-                                                     .w        = w,
-                                                     .x        = x,
-                                                     .fd       = fd,
-                                                     .offset   = offset }
-                                             } });
-       return(index);
-}
-
-int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
-              int index, int last_filled, union mm_context *mmu,
-              void (*do_ops)(union mm_context *, struct host_vm_op *, int))
-{
-       struct host_vm_op *last;
-
-       if(index != -1){
-               last = &ops[index];
-               if((last->type == MUNMAP) &&
-                  (last->u.munmap.addr + last->u.mmap.len == addr)){
-                       last->u.munmap.len += len;
-                       return(index);
-               }
-       }
-
-       if(index == last_filled){
-               (*do_ops)(mmu, ops, last_filled);
-               index = -1;
-       }
-
-       ops[++index] = ((struct host_vm_op) { .type     = MUNMAP,
-                                             .u = { .munmap = {
-                                                     .addr     = addr,
-                                                     .len      = len } } });
-       return(index);
-}
-
-int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
-                 struct host_vm_op *ops, int index, int last_filled,
-                 union mm_context *mmu,
-                 void (*do_ops)(union mm_context *, struct host_vm_op *, int))
-{
-       struct host_vm_op *last;
-
-       if(index != -1){
-               last = &ops[index];
-               if((last->type == MPROTECT) &&
-                  (last->u.mprotect.addr + last->u.mprotect.len == addr) &&
-                  (last->u.mprotect.r == r) && (last->u.mprotect.w == w) &&
-                  (last->u.mprotect.x == x)){
-                       last->u.mprotect.len += len;
-                       return(index);
-               }
-       }
-
-       if(index == last_filled){
-               (*do_ops)(mmu, ops, last_filled);
-               index = -1;
-       }
-
-       ops[++index] = ((struct host_vm_op) { .type     = MPROTECT,
-                                             .u = { .mprotect = {
-                                                     .addr     = addr,
-                                                     .len      = len,
-                                                     .r        = r,
-                                                     .w        = w,
-                                                     .x        = x } } });
-       return(index);
-}
-
 void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
 {
         address &= PAGE_MASK;
index c20aef120598ddb071f6362ca8868ecdc8373eca..b5fc89fe9eab8f2e51859e5a44c5f2bf5d226ab4 100644 (file)
@@ -26,6 +26,7 @@
 #include "mem.h"
 #include "mem_kern.h"
 
+/* Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by segv(). */
 int handle_page_fault(unsigned long address, unsigned long ip, 
                      int is_write, int is_user, int *code_out)
 {
@@ -35,7 +36,6 @@ int handle_page_fault(unsigned long address, unsigned long ip,
        pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
-       unsigned long page;
        int err = -EFAULT;
 
        *code_out = SEGV_MAPERR;
@@ -52,7 +52,7 @@ int handle_page_fault(unsigned long address, unsigned long ip,
        else if(expand_stack(vma, address)) 
                goto out;
 
- good_area:
+good_area:
        *code_out = SEGV_ACCERR;
        if(is_write && !(vma->vm_flags & VM_WRITE)) 
                goto out;
@@ -60,9 +60,8 @@ int handle_page_fault(unsigned long address, unsigned long ip,
         if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
                 goto out;
 
-       page = address & PAGE_MASK;
        do {
- survive:
+survive:
                switch (handle_mm_fault(mm, vma, address, is_write)){
                case VM_FAULT_MINOR:
                        current->min_flt++;
@@ -79,16 +78,16 @@ int handle_page_fault(unsigned long address, unsigned long ip,
                default:
                        BUG();
                }
-               pgd = pgd_offset(mm, page);
-               pud = pud_offset(pgd, page);
-               pmd = pmd_offset(pud, page);
-               pte = pte_offset_kernel(pmd, page);
+               pgd = pgd_offset(mm, address);
+               pud = pud_offset(pgd, address);
+               pmd = pmd_offset(pud, address);
+               pte = pte_offset_kernel(pmd, address);
        } while(!pte_present(*pte));
        err = 0;
        *pte = pte_mkyoung(*pte);
        if(pte_write(*pte)) *pte = pte_mkdirty(*pte);
-       flush_tlb_page(vma, page);
- out:
+       flush_tlb_page(vma, address);
+out:
        up_read(&mm->mmap_sem);
        return(err);
 
@@ -144,19 +143,18 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc)
                panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", 
                      address, ip);
 
-       if(err == -EACCES){
+       if (err == -EACCES) {
                si.si_signo = SIGBUS;
                si.si_errno = 0;
                si.si_code = BUS_ADRERR;
                si.si_addr = (void *)address;
                 current->thread.arch.faultinfo = fi;
                force_sig_info(SIGBUS, &si, current);
-       }
-       else if(err == -ENOMEM){
+       } else if (err == -ENOMEM) {
                printk("VM: killing process %s\n", current->comm);
                do_exit(SIGKILL);
-       }
-       else {
+       } else {
+               BUG_ON(err != -EFAULT);
                si.si_signo = SIGSEGV;
                si.si_addr = (void *) address;
                 current->thread.arch.faultinfo = fi;
@@ -200,30 +198,3 @@ void winch(int sig, union uml_pt_regs *regs)
 void trap_init(void)
 {
 }
-
-DEFINE_SPINLOCK(trap_lock);
-
-static int trap_index = 0;
-
-int next_trap_index(int limit)
-{
-       int ret;
-
-       spin_lock(&trap_lock);
-       ret = trap_index;
-       if(++trap_index == limit)
-               trap_index = 0;
-       spin_unlock(&trap_lock);
-       return(ret);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index f825a6eda3f599ac6f080cedce1f52bb69955715..e9ccd6b8d3c78d1092b07c4cb93cda92f9559f9d 100644 (file)
@@ -40,35 +40,14 @@ void kill_child_dead(int pid)
        } while(1);
 }
 
-/* Unlocked - don't care if this is a bit off */
-int nsegfaults = 0;
-
-struct {
-       unsigned long address;
-       int is_write;
-       int pid;
-       unsigned long sp;
-       int is_user;
-} segfault_record[1024];
-
 void segv_handler(int sig, union uml_pt_regs *regs)
 {
-       int index, max;
         struct faultinfo * fi = UPT_FAULTINFO(regs);
 
         if(UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)){
                 bad_segv(*fi, UPT_IP(regs));
                return;
        }
-       max = sizeof(segfault_record)/sizeof(segfault_record[0]);
-       index = next_trap_index(max);
-
-       nsegfaults++;
-        segfault_record[index].address = FAULT_ADDRESS(*fi);
-       segfault_record[index].pid = os_getpid();
-        segfault_record[index].is_write = FAULT_WRITE(*fi);
-       segfault_record[index].sp = UPT_SP(regs);
-       segfault_record[index].is_user = UPT_IS_USER(regs);
         segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs);
 }
 
index 2650a628719e41136291fae37b44ff9d3c02cb48..3d29c90514cc0e10093b15c40188281e9fe92e7b 100644 (file)
 #include "asm/uaccess.h"
 #include "asm/stat.h"
 #include "sysdep/syscalls.h"
+#include "sysdep/sigcontext.h"
 #include "kern_util.h"
+#include "syscall.h"
 
-extern syscall_handler_t *sys_call_table[];
-
-long execute_syscall_tt(void *r)
+void syscall_handler_tt(int sig, struct pt_regs *regs)
 {
-       struct pt_regs *regs = r;
-       long res;
+       void *sc;
+       long result;
        int syscall;
-
 #ifdef CONFIG_SYSCALL_DEBUG
+       int index;
+       index = record_syscall_start(syscall);
+#endif
+       sc = UPT_SC(&regs->regs);
+       SC_START_SYSCALL(sc);
+
+       syscall_trace(&regs->regs, 0);
+
        current->thread.nsyscalls++;
        nsyscalls++;
-#endif
        syscall = UPT_SYSCALL_NR(&regs->regs);
 
        if((syscall >= NR_syscalls) || (syscall < 0))
-               res = -ENOSYS;
-       else res = EXECUTE_SYSCALL(syscall, regs);
+               result = -ENOSYS;
+       else result = EXECUTE_SYSCALL(syscall, regs);
 
-       return(res);
-}
+       /* regs->sc may have changed while the system call ran (there may
+        * have been an interrupt or segfault), so it needs to be refreshed.
+        */
+       UPT_SC(&regs->regs) = sc;
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+       SC_SET_SYSCALL_RETURN(sc, result);
+
+       syscall_trace(&regs->regs, 1);
+#ifdef CONFIG_SYSCALL_DEBUG
+       record_syscall_end(index, result);
+#endif
+}
index b218316cfdb29aa169beb82ecdeca42d89a6407f..902987bf379b2c8bd55fed640704255b6e6d02bd 100644 (file)
 #include "task.h"
 #include "user_util.h"
 #include "kern_util.h"
-#include "syscall_user.h"
+#include "syscall.h"
 #include "tt.h"
 
-
-void syscall_handler_tt(int sig, union uml_pt_regs *regs)
-{
-       void *sc;
-       long result;
-       int syscall;
-#ifdef UML_CONFIG_DEBUG_SYSCALL
-       int index;
-#endif
-
-       syscall = UPT_SYSCALL_NR(regs);
-       sc = UPT_SC(regs);
-       SC_START_SYSCALL(sc);
-
-#ifdef UML_CONFIG_DEBUG_SYSCALL
-       index = record_syscall_start(syscall);
-#endif
-       syscall_trace(regs, 0);
-       result = execute_syscall_tt(regs);
-
-       /* regs->sc may have changed while the system call ran (there may
-        * have been an interrupt or segfault), so it needs to be refreshed.
-        */
-       UPT_SC(regs) = sc;
-
-       SC_SET_SYSCALL_RETURN(sc, result);
-
-       syscall_trace(regs, 1);
-#ifdef UML_CONFIG_DEBUG_SYSCALL
-       record_syscall_end(index, result);
-#endif
-}
-
 void do_sigtrap(void *task)
 {
        UPT_SYSCALL_NR(TASK_REGS(task)) = -1;
index 2eefb43bc9c2e3a01cb547ca657d654b98e2b19c..f1d85dbb45b9827d50f325d0d9560d4f3d4a09db 100644 (file)
 #include "os.h"
 #include "tlb.h"
 
-static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
+static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last,
+                   int finished, void **flush)
 {
        struct host_vm_op *op;
-       int i;
+        int i, ret=0;
 
-       for(i = 0; i <= last; i++){
+        for(i = 0; i <= last && !ret; i++){
                op = &ops[i];
                switch(op->type){
                case MMAP:
-                        os_map_memory((void *) op->u.mmap.addr, op->u.mmap.fd,
-                                     op->u.mmap.offset, op->u.mmap.len,
-                                     op->u.mmap.r, op->u.mmap.w,
-                                     op->u.mmap.x);
+                        ret = os_map_memory((void *) op->u.mmap.addr,
+                                            op->u.mmap.fd, op->u.mmap.offset,
+                                            op->u.mmap.len, op->u.mmap.r,
+                                            op->u.mmap.w, op->u.mmap.x);
                        break;
                case MUNMAP:
-                       os_unmap_memory((void *) op->u.munmap.addr,
-                                       op->u.munmap.len);
+                        ret = os_unmap_memory((void *) op->u.munmap.addr,
+                                              op->u.munmap.len);
                        break;
                case MPROTECT:
+                        ret = protect_memory(op->u.mprotect.addr,
+                                             op->u.munmap.len,
+                                             op->u.mprotect.r,
+                                             op->u.mprotect.w,
+                                             op->u.mprotect.x, 1);
                        protect_memory(op->u.mprotect.addr, op->u.munmap.len,
                                       op->u.mprotect.r, op->u.mprotect.w,
                                       op->u.mprotect.x, 1);
@@ -45,6 +51,8 @@ static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
                        break;
                }
        }
+
+       return ret;
 }
 
 static void fix_range(struct mm_struct *mm, unsigned long start_addr, 
index ca2bb6f09a7d4f5231f8910bb3df4ba2151ae478..09f6f7ce4695f73c10a1507acfb122b854cf2fe5 100644 (file)
@@ -126,7 +126,7 @@ unsigned long start_vm;
 unsigned long end_vm;
 int ncpus = 1;
 
-#ifdef CONFIG_MODE_TT
+#ifdef CONFIG_CMDLINE_ON_HOST
 /* Pointer set in linux_main, the array itself is private to each thread,
  * and changed at address space creation time so this poses no concurrency
  * problems.
@@ -141,7 +141,7 @@ long physmem_size = 32 * 1024 * 1024;
 
 void set_cmdline(char *cmd)
 {
-#ifdef CONFIG_MODE_TT
+#ifdef CONFIG_CMDLINE_ON_HOST
        char *umid, *ptr;
 
        if(CHOOSE_MODE(honeypot, 0)) return;
@@ -333,6 +333,7 @@ int linux_main(int argc, char **argv)
        if(have_root == 0)
                add_arg(DEFAULT_COMMAND_LINE);
 
+       os_early_checks();
        mode_tt = force_tt ? 1 : !can_do_skas();
 #ifndef CONFIG_MODE_TT
        if (mode_tt) {
@@ -385,7 +386,7 @@ int linux_main(int argc, char **argv)
 
        setup_machinename(system_utsname.machine);
 
-#ifdef CONFIG_MODE_TT
+#ifdef CONFIG_CMDLINE_ON_HOST
        argv1_begin = argv[1];
        argv1_end = &argv[1][strlen(argv[1])];
 #endif
@@ -470,7 +471,6 @@ void __init setup_arch(char **cmdline_p)
 void __init check_bugs(void)
 {
        arch_check_bugs();
-       check_ptrace();
        check_sigio();
        check_devanon();
 }
index 4ddf540284ce601b66f54f089656846d4522ec80..7a1662419c0c6d703e3f8d2f96d877aa379d643d 100644 (file)
@@ -3,11 +3,19 @@
 # Licensed under the GPL
 #
 
-obj-y = elf_aux.o file.o process.o signal.o time.o tty.o user_syms.o drivers/ \
-       sys-$(SUBARCH)/
+obj-y = aio.o elf_aux.o file.o process.o signal.o start_up.o time.o tt.o \
+       tty.o user_syms.o drivers/ sys-$(SUBARCH)/
 
-USER_OBJS := elf_aux.o file.o process.o signal.o time.o tty.o
+USER_OBJS := aio.o elf_aux.o file.o process.o signal.o start_up.o time.o tt.o \
+       tty.o
+
+elf_aux.o: $(ARCH_DIR)/kernel-offsets.h
+CFLAGS_elf_aux.o += -I$(objtree)/arch/um
 
 CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH)
 
+HAVE_AIO_ABI := $(shell [ -r /usr/include/linux/aio_abi.h ] && \
+       echo -DHAVE_AIO_ABI )
+CFLAGS_aio.o += $(HAVE_AIO_ABI)
+
 include arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c
new file mode 100644 (file)
index 0000000..b04897c
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <sched.h>
+#include <sys/syscall.h>
+#include "os.h"
+#include "helper.h"
+#include "aio.h"
+#include "init.h"
+#include "user.h"
+#include "mode.h"
+
+static int aio_req_fd_r = -1;
+static int aio_req_fd_w = -1;
+
+static int update_aio(struct aio_context *aio, int res)
+{
+        if(res < 0)
+                aio->len = res;
+        else if((res == 0) && (aio->type == AIO_READ)){
+                /* This is the EOF case - we have hit the end of the file
+                 * and it ends in a partial block, so we fill the end of
+                 * the block with zeros and claim success.
+                 */
+                memset(aio->data, 0, aio->len);
+                aio->len = 0;
+        }
+        else if(res > 0){
+                aio->len -= res;
+                aio->data += res;
+                aio->offset += res;
+                return aio->len;
+        }
+
+        return 0;
+}
+
+#if defined(HAVE_AIO_ABI)
+#include <linux/aio_abi.h>
+
+/* If we have the headers, we are going to build with AIO enabled.
+ * If we don't have aio in libc, we define the necessary stubs here.
+ */
+
+#if !defined(HAVE_AIO_LIBC)
+
+static long io_setup(int n, aio_context_t *ctxp)
+{
+        return syscall(__NR_io_setup, n, ctxp);
+}
+
+static long io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp)
+{
+        return syscall(__NR_io_submit, ctx, nr, iocbpp);
+}
+
+static long io_getevents(aio_context_t ctx_id, long min_nr, long nr,
+                         struct io_event *events, struct timespec *timeout)
+{
+        return syscall(__NR_io_getevents, ctx_id, min_nr, nr, events, timeout);
+}
+
+#endif
+
+/* The AIO_MMAP cases force the mmapped page into memory here
+ * rather than in whatever place first touches the data.  I used
+ * to do this by touching the page, but that's delicate because
+ * gcc is prone to optimizing that away.  So, what's done here
+ * is we read from the descriptor from which the page was
+ * mapped.  The caller is required to pass an offset which is
+ * inside the page that was mapped.  Thus, when the read
+ * returns, we know that the page is in the page cache, and
+ * that it now backs the mmapped area.
+ */
+
+static int do_aio(aio_context_t ctx, struct aio_context *aio)
+{
+        struct iocb iocb, *iocbp = &iocb;
+        char c;
+        int err;
+
+        iocb = ((struct iocb) { .aio_data      = (unsigned long) aio,
+                                .aio_reqprio   = 0,
+                                .aio_fildes    = aio->fd,
+                                .aio_buf       = (unsigned long) aio->data,
+                                .aio_nbytes    = aio->len,
+                                .aio_offset    = aio->offset,
+                                .aio_reserved1 = 0,
+                                .aio_reserved2 = 0,
+                                .aio_reserved3 = 0 });
+
+        switch(aio->type){
+        case AIO_READ:
+                iocb.aio_lio_opcode = IOCB_CMD_PREAD;
+                break;
+        case AIO_WRITE:
+                iocb.aio_lio_opcode = IOCB_CMD_PWRITE;
+                break;
+        case AIO_MMAP:
+                iocb.aio_lio_opcode = IOCB_CMD_PREAD;
+                iocb.aio_buf = (unsigned long) &c;
+                iocb.aio_nbytes = sizeof(c);
+                break;
+        default:
+                printk("Bogus op in do_aio - %d\n", aio->type);
+                err = -EINVAL;
+                goto out;
+        }
+
+        err = io_submit(ctx, 1, &iocbp);
+        if(err > 0)
+                err = 0;
+
+ out:
+        return err;
+}
+
+static aio_context_t ctx = 0;
+
+static int aio_thread(void *arg)
+{
+        struct aio_thread_reply reply;
+        struct aio_context *aio;
+        struct io_event event;
+        int err, n;
+
+        signal(SIGWINCH, SIG_IGN);
+
+        while(1){
+                n = io_getevents(ctx, 1, 1, &event, NULL);
+                if(n < 0){
+                        if(errno == EINTR)
+                                continue;
+                        printk("aio_thread - io_getevents failed, "
+                               "errno = %d\n", errno);
+                }
+                else {
+                       aio = (struct aio_context *) event.data;
+                       if(update_aio(aio, event.res)){
+                               do_aio(ctx, aio);
+                               continue;
+                       }
+
+                        reply = ((struct aio_thread_reply)
+                               { .data = aio,
+                                 .err  = aio->len });
+                       err = os_write_file(aio->reply_fd, &reply,
+                                           sizeof(reply));
+                        if(err != sizeof(reply))
+                               printk("aio_thread - write failed, "
+                                      "fd = %d, err = %d\n", aio->reply_fd,
+                                      -err);
+                }
+        }
+        return 0;
+}
+
+#endif
+
+static int do_not_aio(struct aio_context *aio)
+{
+        char c;
+        int err;
+
+        switch(aio->type){
+        case AIO_READ:
+                err = os_seek_file(aio->fd, aio->offset);
+                if(err)
+                        goto out;
+
+                err = os_read_file(aio->fd, aio->data, aio->len);
+                break;
+        case AIO_WRITE:
+                err = os_seek_file(aio->fd, aio->offset);
+                if(err)
+                        goto out;
+
+                err = os_write_file(aio->fd, aio->data, aio->len);
+                break;
+        case AIO_MMAP:
+                err = os_seek_file(aio->fd, aio->offset);
+                if(err)
+                        goto out;
+
+                err = os_read_file(aio->fd, &c, sizeof(c));
+                break;
+        default:
+                printk("do_not_aio - bad request type : %d\n", aio->type);
+                err = -EINVAL;
+                break;
+        }
+
+ out:
+        return err;
+}
+
+static int not_aio_thread(void *arg)
+{
+        struct aio_context *aio;
+        struct aio_thread_reply reply;
+        int err;
+
+        signal(SIGWINCH, SIG_IGN);
+        while(1){
+                err = os_read_file(aio_req_fd_r, &aio, sizeof(aio));
+                if(err != sizeof(aio)){
+                        if(err < 0)
+                                printk("not_aio_thread - read failed, "
+                                       "fd = %d, err = %d\n", aio_req_fd_r,
+                                       -err);
+                        else {
+                                printk("not_aio_thread - short read, fd = %d, "
+                                       "length = %d\n", aio_req_fd_r, err);
+                        }
+                        continue;
+                }
+ again:
+                err = do_not_aio(aio);
+
+                if(update_aio(aio, err))
+                        goto again;
+
+                reply = ((struct aio_thread_reply) { .data     = aio,
+                                                     .err      = aio->len });
+                err = os_write_file(aio->reply_fd, &reply, sizeof(reply));
+                if(err != sizeof(reply))
+                        printk("not_aio_thread - write failed, fd = %d, "
+                               "err = %d\n", aio_req_fd_r, -err);
+        }
+}
+
+static int submit_aio_24(struct aio_context *aio)
+{
+        int err;
+
+        err = os_write_file(aio_req_fd_w, &aio, sizeof(aio));
+        if(err == sizeof(aio))
+                err = 0;
+
+        return err;
+}
+
+static int aio_pid = -1;
+static int (*submit_proc)(struct aio_context *aio);
+
+static int init_aio_24(void)
+{
+        unsigned long stack;
+        int fds[2], err;
+
+        err = os_pipe(fds, 1, 1);
+        if(err)
+                goto out;
+
+        aio_req_fd_w = fds[0];
+        aio_req_fd_r = fds[1];
+        err = run_helper_thread(not_aio_thread, NULL,
+                                CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
+        if(err < 0)
+                goto out_close_pipe;
+
+        aio_pid = err;
+        goto out;
+
+ out_close_pipe:
+        os_close_file(fds[0]);
+        os_close_file(fds[1]);
+        aio_req_fd_w = -1;
+        aio_req_fd_r = -1;
+ out:
+#ifndef HAVE_AIO_ABI
+       printk("/usr/include/linux/aio_abi.h not present during build\n");
+#endif
+       printk("2.6 host AIO support not used - falling back to I/O "
+              "thread\n");
+
+       submit_proc = submit_aio_24;
+
+        return 0;
+}
+
+#ifdef HAVE_AIO_ABI
+#define DEFAULT_24_AIO 0
+static int submit_aio_26(struct aio_context *aio)
+{
+       struct aio_thread_reply reply;
+       int err;
+
+       err = do_aio(ctx, aio);
+       if(err){
+               reply = ((struct aio_thread_reply) { .data = aio,
+                                                    .err  = err });
+               err = os_write_file(aio->reply_fd, &reply, sizeof(reply));
+               if(err != sizeof(reply))
+                       printk("submit_aio_26 - write failed, "
+                              "fd = %d, err = %d\n", aio->reply_fd, -err);
+               else err = 0;
+       }
+
+       return err;
+}
+
+static int init_aio_26(void)
+{
+        unsigned long stack;
+        int err;
+
+        if(io_setup(256, &ctx)){
+                printk("aio_thread failed to initialize context, err = %d\n",
+                       errno);
+                return -errno;
+        }
+
+        err = run_helper_thread(aio_thread, NULL,
+                                CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
+        if(err < 0)
+                return -errno;
+
+        aio_pid = err;
+
+       printk("Using 2.6 host AIO\n");
+
+       submit_proc = submit_aio_26;
+
+        return 0;
+}
+
+#else
+#define DEFAULT_24_AIO 1
+static int submit_aio_26(struct aio_context *aio)
+{
+        return -ENOSYS;
+}
+
+static int init_aio_26(void)
+{
+       submit_proc = submit_aio_26;
+        return -ENOSYS;
+}
+#endif
+
+static int aio_24 = DEFAULT_24_AIO;
+
+static int __init set_aio_24(char *name, int *add)
+{
+        aio_24 = 1;
+        return 0;
+}
+
+__uml_setup("aio=2.4", set_aio_24,
+"aio=2.4\n"
+"    This is used to force UML to use 2.4-style AIO even when 2.6 AIO is\n"
+"    available.  2.4 AIO is a single thread that handles one request at a\n"
+"    time, synchronously.  2.6 AIO is a thread which uses the 2.6 AIO \n"
+"    interface to handle an arbitrary number of pending requests.  2.6 AIO \n"
+"    is not available in tt mode, on 2.4 hosts, or when UML is built with\n"
+"    /usr/include/linux/aio_abi.h not available.  Many distributions don't\n"
+"    include aio_abi.h, so you will need to copy it from a kernel tree to\n"
+"    your /usr/include/linux in order to build an AIO-capable UML\n\n"
+);
+
+static int init_aio(void)
+{
+        int err;
+
+        CHOOSE_MODE(({
+                if(!aio_24){
+                        printk("Disabling 2.6 AIO in tt mode\n");
+                        aio_24 = 1;
+                } }), (void) 0);
+
+        if(!aio_24){
+                err = init_aio_26();
+                if(err && (errno == ENOSYS)){
+                        printk("2.6 AIO not supported on the host - "
+                               "reverting to 2.4 AIO\n");
+                        aio_24 = 1;
+                }
+                else return err;
+        }
+
+        if(aio_24)
+                return init_aio_24();
+
+        return 0;
+}
+
+/* The reason for the __initcall/__uml_exitcall asymmetry is that init_aio
+ * needs to be called when the kernel is running because it calls run_helper,
+ * which needs get_free_page.  exit_aio is a __uml_exitcall because the generic
+ * kernel does not run __exitcalls on shutdown, and can't because many of them
+ * break when called outside of module unloading.
+ */
+__initcall(init_aio);
+
+static void exit_aio(void)
+{
+        if(aio_pid != -1)
+                os_kill_process(aio_pid, 1);
+}
+
+__uml_exitcall(exit_aio);
+
+int submit_aio(struct aio_context *aio)
+{
+       return (*submit_proc)(aio);
+}
index 4cca3e9c23fe065c3fb2c5a84464d7cd7ab44178..1399520a85889d79c37862f160233946939cbf22 100644 (file)
@@ -12,8 +12,9 @@
 #include "init.h"
 #include "elf_user.h"
 #include "mem_user.h"
+#include <kernel-offsets.h>
 
-#if ELF_CLASS == ELFCLASS32
+#if HOST_ELF_CLASS == ELFCLASS32
 typedef Elf32_auxv_t elf_auxv_t;
 #else
 typedef Elf64_auxv_t elf_auxv_t;
index 1e126bfd31a7b89b5d9663ae4a1b7cefcb294422..d32413e4b4ce21faa2f3b61dbb690b6fecd90d87 100644 (file)
@@ -3,10 +3,10 @@
  * Licensed under the GPL
  */
 
-#include <unistd.h>
 #include <stdio.h>
 #include <errno.h>
 #include <signal.h>
+#include <setjmp.h>
 #include <linux/unistd.h>
 #include <sys/mman.h>
 #include <sys/wait.h>
 #include "os.h"
 #include "user.h"
 #include "user_util.h"
+#include "signal_user.h"
+#include "process.h"
+#include "irq_user.h"
+#include "kern_util.h"
 
 #define ARBITRARY_ADDR -1
 #define FAILURE_PID    -1
@@ -114,8 +118,10 @@ void os_usr1_process(int pid)
        kill(pid, SIGUSR1);
 }
 
-/*Don't use the glibc version, which caches the result in TLS. It misses some
- * syscalls, and also breaks with clone(), which does not unshare the TLS.*/
+/* Don't use the glibc version, which caches the result in TLS. It misses some
+ * syscalls, and also breaks with clone(), which does not unshare the TLS.
+ */
+
 inline _syscall0(pid_t, getpid)
 
 int os_getpid(void)
@@ -164,6 +170,52 @@ int os_unmap_memory(void *addr, int len)
         return(0);
 }
 
+void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
+{
+       int flags = 0, pages;
+
+       if(sig_stack != NULL){
+               pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER);
+               set_sigstack(sig_stack, pages * page_size());
+               flags = SA_ONSTACK;
+       }
+       if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
+}
+
+void init_new_thread_signals(int altstack)
+{
+       int flags = altstack ? SA_ONSTACK : 0;
+
+       set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags,
+                   SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+       set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags,
+                   SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+       set_handler(SIGFPE, (__sighandler_t) sig_handler, flags,
+                   SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+       set_handler(SIGILL, (__sighandler_t) sig_handler, flags,
+                   SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+       set_handler(SIGBUS, (__sighandler_t) sig_handler, flags,
+                   SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+       set_handler(SIGUSR2, (__sighandler_t) sig_handler,
+                   flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+       signal(SIGHUP, SIG_IGN);
+
+       init_irq_signals(altstack);
+}
+
+int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
+{
+       sigjmp_buf buf;
+       int n;
+
+       *jmp_ptr = &buf;
+       n = sigsetjmp(buf, 1);
+       if(n != 0)
+               return(n);
+       (*fn)(arg);
+       return(0);
+}
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
similarity index 61%
rename from arch/um/kernel/process.c
rename to arch/um/os-Linux/start_up.c
index 67acd92c5322f14cc96c6186a7336df51906718d..040cc1472bc77d4ad44ca7022c253bdda9fbe4ef 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
  * Licensed under the GPL
  */
@@ -19,7 +19,6 @@
 #include "user_util.h"
 #include "kern_util.h"
 #include "user.h"
-#include "process.h"
 #include "signal_kern.h"
 #include "signal_user.h"
 #include "sysdep/ptrace.h"
 #include "registers.h"
 #endif
 
-void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
-{
-       int flags = 0, pages;
-
-       if(sig_stack != NULL){
-               pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER);
-               set_sigstack(sig_stack, pages * page_size());
-               flags = SA_ONSTACK;
-       }
-       if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
-}
-
-void init_new_thread_signals(int altstack)
-{
-       int flags = altstack ? SA_ONSTACK : 0;
-
-       set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags,
-                   SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
-       set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, 
-                   SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
-       set_handler(SIGFPE, (__sighandler_t) sig_handler, flags, 
-                   SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
-       set_handler(SIGILL, (__sighandler_t) sig_handler, flags, 
-                   SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
-       set_handler(SIGBUS, (__sighandler_t) sig_handler, flags, 
-                   SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
-       set_handler(SIGUSR2, (__sighandler_t) sig_handler, 
-                   flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
-       signal(SIGHUP, SIG_IGN);
-
-       init_irq_signals(altstack);
-}
-
-struct tramp {
-       int (*tramp)(void *);
-       void *tramp_data;
-       unsigned long temp_stack;
-       int flags;
-       int pid;
-};
-
-/* See above for why sigkill is here */
-
-int sigkill = SIGKILL;
-
-int outer_tramp(void *arg)
-{
-       struct tramp *t;
-       int sig = sigkill;
-
-       t = arg;
-       t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2,
-                      t->flags, t->tramp_data);
-       if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL);
-       kill(os_getpid(), sig);
-       _exit(0);
-}
-
-int start_fork_tramp(void *thread_arg, unsigned long temp_stack, 
-                    int clone_flags, int (*tramp)(void *))
-{
-       struct tramp arg;
-       unsigned long sp;
-       int new_pid, status, err;
-
-       /* The trampoline will run on the temporary stack */
-       sp = stack_sp(temp_stack);
-
-       clone_flags |= CLONE_FILES | SIGCHLD;
-
-       arg.tramp = tramp;
-       arg.tramp_data = thread_arg;
-       arg.temp_stack = temp_stack;
-       arg.flags = clone_flags;
-
-       /* Start the process and wait for it to kill itself */
-       new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg);
-       if(new_pid < 0)
-               return(new_pid);
-
-       CATCH_EINTR(err = waitpid(new_pid, &status, 0));
-       if(err < 0)
-               panic("Waiting for outer trampoline failed - errno = %d",
-                     errno);
-
-       if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL))
-               panic("outer trampoline didn't exit with SIGKILL, "
-                     "status = %d", status);
-
-       return(arg.pid);
-}
-
 static int ptrace_child(void *arg)
 {
        int ret;
@@ -165,7 +72,7 @@ static int start_ptraced_child(void **stack_out)
        void *stack;
        unsigned long sp;
        int pid, n, status;
-       
+
        stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        if(stack == MAP_FAILED)
@@ -173,10 +80,10 @@ static int start_ptraced_child(void **stack_out)
        sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
        pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL);
        if(pid < 0)
-               panic("check_ptrace : clone failed, errno = %d", errno);
+               panic("start_ptraced_child : clone failed, errno = %d", errno);
        CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
        if(n < 0)
-               panic("check_ptrace : wait failed, errno = %d", errno);
+               panic("check_ptrace : clone failed, errno = %d", errno);
        if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
                panic("check_ptrace : expected SIGSTOP, got status = %d",
                      status);
@@ -185,11 +92,14 @@ static int start_ptraced_child(void **stack_out)
        return(pid);
 }
 
-/* When testing for SYSEMU support, if it is one of the broken versions, we must
- * just avoid using sysemu, not panic, but only if SYSEMU features are broken.
+/* When testing for SYSEMU support, if it is one of the broken versions, we
+ * must just avoid using sysemu, not panic, but only if SYSEMU features are
+ * broken.
  * So only for SYSEMU features we test mustpanic, while normal host features
- * must work anyway!*/
-static int stop_ptraced_child(int pid, void *stack, int exitcode, int mustpanic)
+ * must work anyway!
+ */
+static int stop_ptraced_child(int pid, void *stack, int exitcode,
+                             int mustpanic)
 {
        int status, n, ret = 0;
 
@@ -217,8 +127,6 @@ static int stop_ptraced_child(int pid, void *stack, int exitcode, int mustpanic)
        return ret;
 }
 
-static int force_sysemu_disabled = 0;
-
 int ptrace_faultinfo = 1;
 int proc_mm = 1;
 
@@ -228,29 +136,32 @@ static int __init skas0_cmd_param(char *str, int* add)
        return 0;
 }
 
+__uml_setup("skas0", skas0_cmd_param,
+               "skas0\n"
+               "    Disables SKAS3 usage, so that SKAS0 is used, unless \n"
+               "    you specify mode=tt.\n\n");
+
+static int force_sysemu_disabled = 0;
+
 static int __init nosysemu_cmd_param(char *str, int* add)
 {
        force_sysemu_disabled = 1;
        return 0;
 }
 
-__uml_setup("skas0", skas0_cmd_param,
-               "skas0\n"
-               "    Disables SKAS3 usage, so that SKAS0 is used, unless you \n"
-               "    specify mode=tt.\n\n");
-
 __uml_setup("nosysemu", nosysemu_cmd_param,
-               "nosysemu\n"
-               "    Turns off syscall emulation patch for ptrace (SYSEMU) on.\n"
-               "    SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
-               "    behaviour of ptrace() and helps reducing host context switch rate.\n"
-               "    To make it working, you need a kernel patch for your host, too.\n"
-               "    See http://perso.wanadoo.fr/laurent.vivier/UML/ for further information.\n\n");
+"nosysemu\n"
+"    Turns off syscall emulation patch for ptrace (SYSEMU) on.\n"
+"    SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
+"    behaviour of ptrace() and helps reducing host context switch rate.\n"
+"    To make it working, you need a kernel patch for your host, too.\n"
+"    See http://perso.wanadoo.fr/laurent.vivier/UML/ for further \n"
+"    information.\n\n");
 
 static void __init check_sysemu(void)
 {
        void *stack;
-       int pid, syscall, n, status, count=0;
+       int pid, n, status, count=0;
 
        printk("Checking syscall emulation patch for ptrace...");
        sysemu_supported = 0;
@@ -281,6 +192,12 @@ static void __init check_sysemu(void)
 
        printk("Checking advanced syscall emulation patch for ptrace...");
        pid = start_ptraced_child(&stack);
+
+       if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
+                 (void *) PTRACE_O_TRACESYSGOOD) < 0)
+               panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d",
+                     errno);
+
        while(1){
                count++;
                if(ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
@@ -288,15 +205,10 @@ static void __init check_sysemu(void)
                CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
                if(n < 0)
                        panic("check_ptrace : wait failed, errno = %d", errno);
-               if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
-                       panic("check_ptrace : expected (SIGTRAP|SYSCALL_TRAP), "
-                             "got status = %d", status);
-
-               syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET,
-                                0);
-               if(syscall == __NR_getpid){
+               if(WIFSTOPPED(status) && (WSTOPSIG(status) == (SIGTRAP|0x80))){
                        if (!count)
-                               panic("check_ptrace : SYSEMU_SINGLESTEP doesn't singlestep");
+                               panic("check_ptrace : SYSEMU_SINGLESTEP "
+                                     "doesn't singlestep");
                        n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET,
                                   os_getpid());
                        if(n < 0)
@@ -304,6 +216,11 @@ static void __init check_sysemu(void)
                                      "call return, errno = %d", errno);
                        break;
                }
+               else if(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
+                       count++;
+               else
+                       panic("check_ptrace : expected SIGTRAP or "
+                             "(SIGTRAP|0x80), got status = %d", status);
        }
        if (stop_ptraced_child(pid, stack, 0, 0) < 0)
                goto fail_stopped;
@@ -321,7 +238,7 @@ fail_stopped:
        printk("missing\n");
 }
 
-void __init check_ptrace(void)
+static void __init check_ptrace(void)
 {
        void *stack;
        int pid, syscall, n, status;
@@ -329,20 +246,20 @@ void __init check_ptrace(void)
        printk("Checking that ptrace can change system call numbers...");
        pid = start_ptraced_child(&stack);
 
-       if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
-               panic("check_ptrace: PTRACE_SETOPTIONS failed, errno = %d", errno);
+       if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
+               panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d", errno);
 
        while(1){
                if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
-                       panic("check_ptrace : ptrace failed, errno = %d", 
+                       panic("check_ptrace : ptrace failed, errno = %d",
                              errno);
                CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
                if(n < 0)
                        panic("check_ptrace : wait failed, errno = %d", errno);
-               if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP + 0x80))
-                       panic("check_ptrace : expected SIGTRAP + 0x80, "
+               if(!WIFSTOPPED(status) || (WSTOPSIG(status) != (SIGTRAP|0x80)))
+                       panic("check_ptrace : expected (SIGTRAP|0x80), "
                              "got status = %d", status);
-               
+
                syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET,
                                 0);
                if(syscall == __NR_getpid){
@@ -359,33 +276,36 @@ void __init check_ptrace(void)
        check_sysemu();
 }
 
-int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
+void os_early_checks(void)
 {
-       sigjmp_buf buf;
-       int n;
-
-       *jmp_ptr = &buf;
-       n = sigsetjmp(buf, 1);
-       if(n != 0)
-               return(n);
-       (*fn)(arg);
-       return(0);
+       check_ptrace();
 }
 
-void forward_pending_sigio(int target)
+static int __init noprocmm_cmd_param(char *str, int* add)
 {
-       sigset_t sigs;
+       proc_mm = 0;
+       return 0;
+}
+
+__uml_setup("noprocmm", noprocmm_cmd_param,
+"noprocmm\n"
+"    Turns off usage of /proc/mm, even if host supports it.\n"
+"    To support /proc/mm, the host needs to be patched using\n"
+"    the current skas3 patch.\n\n");
 
-       if(sigpending(&sigs)) 
-               panic("forward_pending_sigio : sigpending failed");
-       if(sigismember(&sigs, SIGIO))
-               kill(target, SIGIO);
+static int __init noptracefaultinfo_cmd_param(char *str, int* add)
+{
+       ptrace_faultinfo = 0;
+       return 0;
 }
 
-extern void *__syscall_stub_start, __syscall_stub_end;
+__uml_setup("noptracefaultinfo", noptracefaultinfo_cmd_param,
+"noptracefaultinfo\n"
+"    Turns off usage of PTRACE_FAULTINFO, even if host supports\n"
+"    it. To support PTRACE_FAULTINFO, the host needs to be patched\n"
+"    using the current skas3 patch.\n\n");
 
 #ifdef UML_CONFIG_MODE_SKAS
-
 static inline void check_skas3_ptrace_support(void)
 {
        struct ptrace_faultinfo fi;
@@ -400,9 +320,8 @@ static inline void check_skas3_ptrace_support(void)
                ptrace_faultinfo = 0;
                if(errno == EIO)
                        printf("not found\n");
-               else {
+               else
                        perror("not found");
-               }
        }
        else {
                if (!ptrace_faultinfo)
@@ -419,9 +338,10 @@ int can_do_skas(void)
 {
        printf("Checking for /proc/mm...");
        if (os_access("/proc/mm", OS_ACC_W_OK) < 0) {
-               proc_mm = 0;
+               proc_mm = 0;
                printf("not found\n");
-       } else {
+       }
+       else {
                if (!proc_mm)
                        printf("found but disabled on command line\n");
                else
diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c
new file mode 100644 (file)
index 0000000..5b047ab
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sched.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sys/ptrace.h>
+#include <linux/ptrace.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <asm/ptrace.h>
+#include <asm/unistd.h>
+#include <asm/page.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "signal_kern.h"
+#include "signal_user.h"
+#include "sysdep/ptrace.h"
+#include "sysdep/sigcontext.h"
+#include "irq_user.h"
+#include "ptrace_user.h"
+#include "time_user.h"
+#include "init.h"
+#include "os.h"
+#include "uml-config.h"
+#include "choose-mode.h"
+#include "mode.h"
+#include "tempfile.h"
+
+/*
+ *-------------------------
+ * only for tt mode (will be deleted in future...)
+ *-------------------------
+ */
+
+struct tramp {
+       int (*tramp)(void *);
+       void *tramp_data;
+       unsigned long temp_stack;
+       int flags;
+       int pid;
+};
+
+/* See above for why sigkill is here */
+
+int sigkill = SIGKILL;
+
+int outer_tramp(void *arg)
+{
+       struct tramp *t;
+       int sig = sigkill;
+
+       t = arg;
+       t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2,
+                      t->flags, t->tramp_data);
+       if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL);
+       kill(os_getpid(), sig);
+       _exit(0);
+}
+
+int start_fork_tramp(void *thread_arg, unsigned long temp_stack,
+                    int clone_flags, int (*tramp)(void *))
+{
+       struct tramp arg;
+       unsigned long sp;
+       int new_pid, status, err;
+
+       /* The trampoline will run on the temporary stack */
+       sp = stack_sp(temp_stack);
+
+       clone_flags |= CLONE_FILES | SIGCHLD;
+
+       arg.tramp = tramp;
+       arg.tramp_data = thread_arg;
+       arg.temp_stack = temp_stack;
+       arg.flags = clone_flags;
+
+       /* Start the process and wait for it to kill itself */
+       new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg);
+       if(new_pid < 0)
+               return(new_pid);
+
+       CATCH_EINTR(err = waitpid(new_pid, &status, 0));
+       if(err < 0)
+               panic("Waiting for outer trampoline failed - errno = %d",
+                     errno);
+
+       if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL))
+               panic("outer trampoline didn't exit with SIGKILL, "
+                     "status = %d", status);
+
+       return(arg.pid);
+}
+
+void forward_pending_sigio(int target)
+{
+       sigset_t sigs;
+
+       if(sigpending(&sigs))
+               panic("forward_pending_sigio : sigpending failed");
+       if(sigismember(&sigs, SIGIO))
+               kill(target, SIGIO);
+}
+
index 802d027a1e13007a12dae1b0a1a329296853c0ce..b2165188d94219301225b6a4a1aaf1fb961cd3f5 100644 (file)
@@ -12,7 +12,7 @@ $(obj)/unmap.o: _c_flags = $(call unprofile,$(CFLAGS))
 
 quiet_cmd_wrapld = LD      $@
 define cmd_wrapld
-       $(LD) $(LDFLAGS) -r -o $(obj)/unmap_tmp.o $< $(shell $(CC) $(CFLAGS) -print-file-name=libc.a); \
+       $(LD) $(LDFLAGS) -r -o $(obj)/unmap_tmp.o $< ; \
        $(OBJCOPY) $(UML_OBJCOPYFLAGS) $(obj)/unmap_tmp.o $@ -G switcheroo
 endef
 
index 77c3c4d29f55f48702ef4e1e42d8b00b082f273e..4ca2a229da4997adebe0bc5f0425727bdda0e790 100644 (file)
@@ -16,13 +16,7 @@ semaphore.c-dir = kernel
 highmem.c-dir = mm
 module.c-dir = kernel
 
-STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
-
-# _cflags works with kernel files, not with userspace ones, but c_flags does,
-# why ask why?
-$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS)
-
-$(obj)/stub.o : a_flags = $(STUB_CFLAGS)
+$(obj)/stub_segv.o : _c_flags = $(call unprofile,$(CFLAGS))
 
 subdir- := util
 
index 9f8ecd1fdd9614b03a05c5fc03dd1d3d01b42132..a1070af2bcd823a1d2c580afbfb1c156b14242f5 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/stddef.h>
 #include <linux/sched.h>
 #include <linux/time.h>
+#include <linux/elf.h>
 #include <asm/page.h>
 
 #define DEFINE(sym, val) \
index 4efc69a039d70022592cec5430a46a1c9a08c826..16bc19928b3c53c49d93ca825798d42d256fdc06 100644 (file)
@@ -122,9 +122,9 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from,
        int err;
 
        to_fp = to->fpstate;
-       from_fp = from->fpstate;
        sigs = to->oldmask;
        err = copy_from_user(to, from, sizeof(*to));
+       from_fp = to->fpstate;
        to->oldmask = sigs;
        to->fpstate = to_fp;
        if(to_fp != NULL)
index 2f2c70a8f043440ef99f68c20332158292407972..6a70d9ab5c2905177429ba9b0f3ae2c1fc084fad 100644 (file)
@@ -2,7 +2,50 @@
 
        .globl syscall_stub
 .section .__syscall_stub, "x"
-syscall_stub:
-       int     $0x80
+
+       .globl batch_syscall_stub
+batch_syscall_stub:
+       /* load pointer to first operation */
+       mov     $(UML_CONFIG_STUB_DATA+8), %esp
+
+again:
+       /* load length of additional data */
+       mov     0x0(%esp), %eax
+
+       /* if(length == 0) : end of list */
+       /* write possible 0 to header */
+       mov     %eax, UML_CONFIG_STUB_DATA+4
+       cmpl    $0, %eax
+       jz      done
+
+       /* save current pointer */
+       mov     %esp, UML_CONFIG_STUB_DATA+4
+
+       /* skip additional data */
+       add     %eax, %esp
+
+       /* load syscall-# */
+       pop     %eax
+
+       /* load syscall params */
+       pop     %ebx
+       pop     %ecx
+       pop     %edx
+       pop     %esi
+       pop     %edi
+       pop     %ebp
+
+       /* execute syscall */
+       int     $0x80
+
+       /* check return value */
+       pop     %ebx
+       cmp     %ebx, %eax
+       je      again
+
+done:
+       /* save return value */
        mov     %eax, UML_CONFIG_STUB_DATA
+
+       /* stop */
        int3
index 68aeabe3a654703b76d20633ba7b3d36832060a4..1e88b275edacea8dede15209a158c2b4ad279cc4 100644 (file)
@@ -3,8 +3,7 @@
  * Licensed under the GPL
  */
 
-#include <signal.h>
-#include <asm/sigcontext.h>
+#include <asm/signal.h>
 #include <asm/unistd.h>
 #include "uml-config.h"
 #include "sysdep/sigcontext.h"
index 7488206ce6f4ae91ba20123a9efcede188b10996..f0ab574d1e95b6bc64a583e3ac1e6ac42ede4f03 100644 (file)
@@ -6,7 +6,7 @@
 
 #XXX: why into lib-y?
 lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \
-       ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o stub.o \
+       ptrace.o ptrace_user.o sigcontext.o signal.o stub.o \
        stub_segv.o syscalls.o syscall_table.o sysrq.o thunk.o
 
 obj-y := ksyms.o
@@ -15,7 +15,7 @@ obj-$(CONFIG_MODULES) += module.o um_module.o
 USER_OBJS := ptrace_user.o sigcontext.o
 
 SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c memcpy.S \
-       semaphore.c thunk.S module.c
+       thunk.S module.c
 
 include arch/um/scripts/Makefile.rules
 
@@ -24,17 +24,10 @@ csum-copy.S-dir = lib
 csum-partial.c-dir = lib
 csum-wrappers.c-dir = lib
 memcpy.S-dir = lib
-semaphore.c-dir = kernel
 thunk.S-dir = lib
 module.c-dir = kernel
 
-STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
-
-# _cflags works with kernel files, not with userspace ones, but c_flags does,
-# why ask why?
-$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS)
-
-$(obj)/stub.o : a_flags = $(STUB_CFLAGS)
+$(obj)/stub_segv.o: _c_flags = $(call unprofile,$(CFLAGS))
 
 subdir- := util
 
index 220e875cbe292c09641f66534610ce55177145d5..998541eade41e0cd80f16cfc0a9de8835dd8467e 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/stddef.h>
 #include <linux/sched.h>
 #include <linux/time.h>
+#include <linux/elf.h>
 #include <asm/page.h>
 
 #define DEFINE(sym, val) \
index 8fdaed06c10dcce12aed363bb7abe32788d8e441..fe1d065332b11d33f215a8f4a43654be69aff7a9 100644 (file)
@@ -104,28 +104,35 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp,
 int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from,
                         int fpsize)
 {
-       struct _fpstate *to_fp, *from_fp;
-       unsigned long sigs;
-       int err;
-
-       to_fp = to->fpstate;
-       from_fp = from->fpstate;
-       sigs = to->oldmask;
-       err = copy_from_user(to, from, sizeof(*to));
-       to->oldmask = sigs;
-       return(err);
+       struct _fpstate *to_fp, *from_fp;
+       unsigned long sigs;
+       int err;
+
+       to_fp = to->fpstate;
+       sigs = to->oldmask;
+       err = copy_from_user(to, from, sizeof(*to));
+       from_fp = to->fpstate;
+       to->fpstate = to_fp;
+       to->oldmask = sigs;
+       if(to_fp != NULL)
+               err |= copy_from_user(to_fp, from_fp, fpsize);
+       return(err);
 }
 
 int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp,
                       struct sigcontext *from, int fpsize)
 {
-       struct _fpstate *to_fp, *from_fp;
-       int err;
-
-       to_fp = (fp ? fp : (struct _fpstate *) (to + 1));
-       from_fp = from->fpstate;
-       err = copy_to_user(to, from, sizeof(*to));
-       return(err);
+       struct _fpstate *to_fp, *from_fp;
+       int err;
+
+       to_fp = (fp ? fp : (struct _fpstate *) (to + 1));
+       from_fp = from->fpstate;
+       err = copy_to_user(to, from, sizeof(*to));
+       if(from_fp != NULL){
+               err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate));
+               err |= copy_to_user(to_fp, from_fp, fpsize);
+       }
+       return(err);
 }
 
 #endif
index 31c14925716bc1c2cf7db2be034e79738c4cb0fa..03c2797357842f2ad8cc4d61651c1e110d88ddb5 100644 (file)
@@ -13,3 +13,54 @@ syscall_stub:
        or      %rcx, %rbx
        movq    %rax, (%rbx)
        int3
+
+       .globl batch_syscall_stub
+batch_syscall_stub:
+       mov     $(UML_CONFIG_STUB_DATA >> 32), %rbx
+       sal     $32, %rbx
+       mov     $(UML_CONFIG_STUB_DATA & 0xffffffff), %rax
+       or      %rax, %rbx
+       /* load pointer to first operation */
+       mov     %rbx, %rsp
+       add     $0x10, %rsp
+again:
+       /* load length of additional data */
+       mov     0x0(%rsp), %rax
+
+       /* if(length == 0) : end of list */
+       /* write possible 0 to header */
+       mov     %rax, 8(%rbx)
+       cmp     $0, %rax
+       jz      done
+
+       /* save current pointer */
+       mov     %rsp, 8(%rbx)
+
+       /* skip additional data */
+       add     %rax, %rsp
+
+       /* load syscall-# */
+       pop     %rax
+
+       /* load syscall params */
+       pop     %rdi
+       pop     %rsi
+       pop     %rdx
+       pop     %r10
+       pop     %r8
+       pop     %r9
+
+       /* execute syscall */
+       syscall
+
+       /* check return value */
+       pop     %rcx
+       cmp     %rcx, %rax
+       je      again
+
+done:
+       /* save return value */
+       mov     %rax, (%rbx)
+
+       /* stop */
+       int3
index 161d1fe9c034f8d931447d6303ded11b278d65ef..65a131b362b689b634608f0ae83ddbc6ebf5e029 100644 (file)
@@ -3,9 +3,10 @@
  * Licensed under the GPL
  */
 
-#include <signal.h>
+#include <asm/signal.h>
 #include <linux/compiler.h>
 #include <asm/unistd.h>
+#include <asm/ucontext.h>
 #include "uml-config.h"
 #include "sysdep/sigcontext.h"
 #include "sysdep/faultinfo.h"
index 1b5ca3c3a6586195bead156fbebd5a436f730b91..1a5beda36e29e91a8e9edad4633f80d00970abca 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-uc0
-# Thu Jul 21 11:08:27 2005
+# Linux kernel version: 2.6.13-uc0
+# Fri Sep  2 13:54:27 2005
 #
 # CONFIG_MMU is not set
 # CONFIG_UID16 is not set
@@ -44,6 +44,8 @@ CONFIG_ZERO_BSS=y
 # CONFIG_V850E_HIGHRES_TIMER is not set
 # CONFIG_RESET_GUARD is not set
 CONFIG_LARGE_ALLOCS=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
 
 #
 # Code maturity level options
@@ -110,6 +112,52 @@ CONFIG_BINFMT_FLAT=y
 # CONFIG_BINFMT_SHARED_FLAT is not set
 # CONFIG_BINFMT_MISC is not set
 
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_UNIX is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+
 #
 # Generic Driver Options
 #
@@ -158,6 +206,7 @@ CONFIG_MTD_CFI_I2=y
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
 
 #
 # Self-contained MTD device drivers
@@ -232,6 +281,7 @@ CONFIG_IOSCHED_NOOP=y
 #
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -244,53 +294,8 @@ CONFIG_IOSCHED_NOOP=y
 # CONFIG_I2O is not set
 
 #
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_UNIX is not set
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-# CONFIG_IP_TCPDIAG is not set
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
+# Network device support
 #
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
@@ -372,6 +377,8 @@ CONFIG_EEPRO100=y
 # CONFIG_FDDI is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
@@ -472,6 +479,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 # 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
@@ -479,6 +487,8 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
+# CONFIG_MAGIC_ROM_PTR is not set
+CONFIG_INOTIFY=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
@@ -524,9 +534,11 @@ CONFIG_RAMFS=y
 #
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
 # CONFIG_NFSD is not set
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
index 44becc065404ef3ee0b5359a8b5c268836ed6603..15e66647806129086517246af4450612ba6bd971 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-uc0
-# Thu Jul 21 11:30:08 2005
+# Linux kernel version: 2.6.13-uc0
+# Fri Sep  2 13:47:50 2005
 #
 # CONFIG_MMU is not set
 # CONFIG_UID16 is not set
@@ -41,6 +41,8 @@ CONFIG_ZERO_BSS=y
 # CONFIG_V850E_HIGHRES_TIMER is not set
 # CONFIG_RESET_GUARD is not set
 CONFIG_LARGE_ALLOCS=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
 
 #
 # Code maturity level options
@@ -56,7 +58,6 @@ CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_SYSCTL is not set
-# CONFIG_AUDIT is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
@@ -103,6 +104,11 @@ CONFIG_BINFMT_FLAT=y
 # CONFIG_BINFMT_SHARED_FLAT is not set
 # CONFIG_BINFMT_MISC is not set
 
+#
+# Networking
+#
+# CONFIG_NET is not set
+
 #
 # Generic Driver Options
 #
@@ -151,6 +157,7 @@ CONFIG_MTD_CFI_I2=y
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
 
 #
 # Self-contained MTD device drivers
@@ -218,6 +225,7 @@ CONFIG_IOSCHED_NOOP=y
 #
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -228,9 +236,8 @@ CONFIG_IOSCHED_NOOP=y
 #
 
 #
-# Networking support
+# Network device support
 #
-# CONFIG_NET is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
 
@@ -311,7 +318,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
 #
@@ -335,6 +341,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 # 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
@@ -342,6 +349,8 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
+# CONFIG_MAGIC_ROM_PTR is not set
+CONFIG_INOTIFY=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
index d73f5f9d8383cad36448998a76e5ac18078c4871..f31ba7398ad009f6499c389bab3be5dc0de23efc 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-uc0
-# Thu Jul 21 11:29:27 2005
+# Linux kernel version: 2.6.13-uc0
+# Fri Sep  2 13:36:43 2005
 #
 # CONFIG_MMU is not set
 # CONFIG_UID16 is not set
@@ -36,6 +36,8 @@ CONFIG_NO_CACHE=y
 CONFIG_ZERO_BSS=y
 # CONFIG_RESET_GUARD is not set
 CONFIG_LARGE_ALLOCS=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
 
 #
 # Code maturity level options
@@ -51,7 +53,6 @@ CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_SYSCTL is not set
-# CONFIG_AUDIT is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
@@ -98,6 +99,11 @@ CONFIG_BINFMT_FLAT=y
 # CONFIG_BINFMT_SHARED_FLAT is not set
 # CONFIG_BINFMT_MISC is not set
 
+#
+# Networking
+#
+# CONFIG_NET is not set
+
 #
 # Generic Driver Options
 #
@@ -146,6 +152,7 @@ CONFIG_MTD_CFI_I2=y
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
 
 #
 # Self-contained MTD device drivers
@@ -213,6 +220,7 @@ CONFIG_IOSCHED_NOOP=y
 #
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -223,9 +231,8 @@ CONFIG_IOSCHED_NOOP=y
 #
 
 #
-# Networking support
+# Network device support
 #
-# CONFIG_NET is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
 
@@ -300,7 +307,6 @@ CONFIG_SERIO=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
 #
@@ -324,6 +330,7 @@ CONFIG_SERIO=y
 # 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
@@ -331,6 +338,8 @@ CONFIG_SERIO=y
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
+# CONFIG_MAGIC_ROM_PTR is not set
+CONFIG_INOTIFY=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
index c41d72b01b8806cf07ddbc5a664240f0597a84b6..abd48409dcca51f5d4816aaf54e4fa9e149e7fe9 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * arch/v850/kernel/setup.c -- Arch-dependent initialization functions
  *
- *  Copyright (C) 2001,02,03  NEC Electronics Corporation
- *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *  Copyright (C) 2001,02,03,05  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03,05  Miles Bader <miles@gnu.org>
  *
  * This file is subject to the terms and conditions of the GNU General
  * Public License.  See the file COPYING in the main directory of this
@@ -98,10 +98,20 @@ void __init trap_init (void)
 }
 
 #ifdef CONFIG_MTD
+
+/* From drivers/mtd/devices/slram.c */
+#define SLRAM_BLK_SZ 0x4000
+
 /* Set the root filesystem to be the given memory region.
    Some parameter may be appended to CMD_LINE.  */
 void set_mem_root (void *addr, size_t len, char *cmd_line)
 {
+       /* Some sort of idiocy in MTD means we must supply a length that's
+          a multiple of SLRAM_BLK_SZ.  We just round up the real length,
+          as the file system shouldn't attempt to access anything beyond
+          the end of the image anyway.  */
+       len = (((len - 1) + SLRAM_BLK_SZ) / SLRAM_BLK_SZ) * SLRAM_BLK_SZ;
+
        /* The only way to pass info to the MTD slram driver is via
           the command line.  */
        if (*cmd_line) {
@@ -284,3 +294,33 @@ init_mem_alloc (unsigned long ram_start, unsigned long ram_len)
        free_area_init_node (0, NODE_DATA(0), zones_size,
                             ADDR_TO_PAGE (PAGE_OFFSET), 0);
 }
+
+\f
+
+/* Taken from m68knommu */
+void show_mem(void)
+{
+    unsigned long i;
+    int free = 0, total = 0, reserved = 0, shared = 0;
+    int cached = 0;
+
+    printk(KERN_INFO "\nMem-info:\n");
+    show_free_areas();
+    i = max_mapnr;
+    while (i-- > 0) {
+       total++;
+       if (PageReserved(mem_map+i))
+           reserved++;
+       else if (PageSwapCache(mem_map+i))
+           cached++;
+       else if (!page_count(mem_map+i))
+           free++;
+       else
+           shared += page_count(mem_map+i) - 1;
+    }
+    printk(KERN_INFO "%d pages of RAM\n",total);
+    printk(KERN_INFO "%d free pages\n",free);
+    printk(KERN_INFO "%d reserved pages\n",reserved);
+    printk(KERN_INFO "%d pages shared\n",shared);
+    printk(KERN_INFO "%d pages swap cached\n",cached);
+}
index 37061e32e1a42d3878a8108ebb340af11ab066e2..633e4e1b825f875daa32f2759ab3f6b94d555209 100644 (file)
@@ -462,13 +462,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
        else
                setup_frame(sig, ka, oldset, regs);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
index f722a268238a69f8921f09f63c9df3003c4b6763..ea3fd8844ff06b1bc4df01188db13407def7b833 100644 (file)
@@ -66,7 +66,7 @@ static irqreturn_t timer_interrupt (int irq, void *dummy, struct pt_regs *regs)
         * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
         * called as close as possible to 500 ms before the new second starts.
         */
-       if ((time_status & STA_UNSYNC) == 0 &&
+       if (ntp_synced() &&
            xtime.tv_sec > last_rtc_update + 660 &&
            (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
            (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
@@ -169,10 +169,7 @@ int do_settimeofday(struct timespec *tv)
        xtime.tv_sec = tv->tv_sec;
        xtime.tv_nsec = tv->tv_nsec;
 
-       time_adjust = 0;                /* stop active adjtime () */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
 
        write_sequnlock_irq (&xtime_lock);
        clock_was_set();
index 660a03a89e6663bf7f04bd83c163c441210e8dc1..8f868b67ef0f1fe0060d3688cd2a37573a830c4f 100644 (file)
@@ -24,6 +24,10 @@ config X86
        bool
        default y
 
+config SEMAPHORE_SLEEPERS
+       bool
+       default y
+
 config MMU
        bool
        default y
@@ -61,6 +65,10 @@ config GENERIC_IOMAP
        bool
        default y
 
+config ARCH_MAY_HAVE_PC_FDC
+       bool
+       default y
+
 source "init/Kconfig"
 
 
@@ -437,6 +445,11 @@ config ISA_DMA_API
        bool
        default y
 
+config GENERIC_PENDING_IRQ
+       bool
+       depends on GENERIC_HARDIRQS && SMP
+       default y
+
 menu "Power management options"
 
 source kernel/power/Kconfig
index ff58b2832b75d5b54df35e57a60fc9dd398c16cd..12ea0b6c52e2a8b48cea525ec530d49b8c1d97a5 100644 (file)
@@ -81,7 +81,7 @@ start:
 # This is the setup header, and it must start at %cs:2 (old 0x9020:2)
 
                .ascii  "HdrS"          # header signature
-               .word   0x0203          # header version number (>= 0x0105)
+               .word   0x0204          # header version number (>= 0x0105)
                                        # or else old loadlin-1.5 will fail)
 realmode_swtch:        .word   0, 0            # default_switch, SETUPSEG
 start_sys_seg: .word   SYSSEG
index 18b5bac1c4282fb94a8bb71afbc79a383164246a..c44f5e2ec1006fc93d09c7b958ccd5d4cb0ad709 100644 (file)
@@ -178,7 +178,9 @@ int main(int argc, char ** argv)
                die("Output: seek failed");
        buf[0] = (sys_size & 0xff);
        buf[1] = ((sys_size >> 8) & 0xff);
-       if (write(1, buf, 2) != 2)
+       buf[2] = ((sys_size >> 16) & 0xff);
+       buf[3] = ((sys_size >> 24) & 0xff);
+       if (write(1, buf, 4) != 4)
                die("Write of image length failed");
 
        return 0;                                           /* Everything is OK */
index c45d6a05b984f6d1e43e863e6da10b2b5f96d074..f174083d55672335bdbc0a442ae5c8fc4c2a697e 100644 (file)
@@ -307,7 +307,7 @@ ia32_sys_call_table:
        .quad stub32_fork
        .quad sys_read
        .quad sys_write
-       .quad sys32_open                /* 5 */
+       .quad compat_sys_open           /* 5 */
        .quad sys_close
        .quad sys32_waitpid
        .quad sys_creat
index be996d1b691e19e0061391794706484f2dac18a4..04d80406ce4fed4c1a6ce646253675c65b074269 100644 (file)
@@ -969,32 +969,6 @@ long sys32_kill(int pid, int sig)
        return sys_kill(pid, sig);
 }
  
-asmlinkage long sys32_open(const char __user * filename, int flags, int mode)
-{
-       char * tmp;
-       int fd, error;
-
-       /* don't force O_LARGEFILE */
-       tmp = getname(filename);
-       fd = PTR_ERR(tmp);
-       if (!IS_ERR(tmp)) {
-               fd = get_unused_fd();
-               if (fd >= 0) {
-                       struct file *f = filp_open(tmp, flags, mode);
-                       error = PTR_ERR(f);
-                       if (IS_ERR(f)) {
-                               put_unused_fd(fd); 
-                               fd = error;
-                       } else {
-                               fsnotify_open(f->f_dentry);
-                               fd_install(fd, f);
-                       }
-               }
-               putname(tmp);
-       }
-       return fd;
-}
-
 extern asmlinkage long
 sys_timer_create(clockid_t which_clock,
                 struct sigevent __user *timer_event_spec,
index 48f9e2c19cd6f78a4cdc21efdec7afec0da19277..c32e198d7b2bfa8c734cad85c249da3b230585c7 100644 (file)
@@ -4,10 +4,10 @@
 
 extra-y        := head.o head64.o init_task.o vmlinux.lds
 EXTRA_AFLAGS   := -traditional
-obj-y  := process.o semaphore.o signal.o entry.o traps.o irq.o \
+obj-y  := process.o signal.o entry.o traps.o irq.o \
                ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_x86_64.o \
                x8664_ksyms.o i387.o syscall.o vsyscall.o \
-               setup64.o bootflag.o e820.o reboot.o quirks.o
+               setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o
 
 obj-$(CONFIG_X86_MCE)         += mce.o
 obj-$(CONFIG_X86_MCE_INTEL)    += mce_intel.o
@@ -45,3 +45,4 @@ swiotlb-$(CONFIG_SWIOTLB)      += ../../ia64/lib/swiotlb.o
 microcode-$(subst m,y,$(CONFIG_MICROCODE))  += ../../i386/kernel/microcode.o
 intel_cacheinfo-y              += ../../i386/kernel/cpu/intel_cacheinfo.o
 quirks-y                       += ../../i386/kernel/quirks.o
+i8237-y                                += ../../i386/kernel/i8237.o
index b548dea4e5b95e30c01f369f0c95dcd06db67551..116ac5f53dced70d0098178e57b7e09207d90603 100644 (file)
@@ -85,7 +85,7 @@ int __init e820_mapped(unsigned long start, unsigned long end, unsigned type)
                struct e820entry *ei = &e820.map[i]; 
                if (type && ei->type != type) 
                        continue;
-               if (ei->addr >= end || ei->addr + ei->size < start) 
+               if (ei->addr >= end || ei->addr + ei->size <= start)
                        continue; 
                return 1; 
        } 
index 096d470e280f38d6e64eb179a23525ecaa1252e5..be51dbe1f75ec1a91765e8a4735a052ae144c6e1 100644 (file)
@@ -784,8 +784,9 @@ ENTRY(execve)
        ret
        CFI_ENDPROC
 
-ENTRY(page_fault)
+KPROBE_ENTRY(page_fault)
        errorentry do_page_fault
+       .previous .text
 
 ENTRY(coprocessor_error)
        zeroentry do_coprocessor_error
@@ -797,13 +798,14 @@ ENTRY(device_not_available)
        zeroentry math_state_restore
 
        /* runs on exception stack */
-ENTRY(debug)
+KPROBE_ENTRY(debug)
        CFI_STARTPROC
        pushq $0
        CFI_ADJUST_CFA_OFFSET 8         
        paranoidentry do_debug
        jmp paranoid_exit
        CFI_ENDPROC
+       .previous .text
 
        /* runs on exception stack */   
 ENTRY(nmi)
@@ -854,8 +856,9 @@ paranoid_schedule:
        jmp paranoid_userspace
        CFI_ENDPROC
 
-ENTRY(int3)
+KPROBE_ENTRY(int3)
        zeroentry do_int3       
+       .previous .text
 
 ENTRY(overflow)
        zeroentry do_overflow
@@ -892,8 +895,9 @@ ENTRY(stack_segment)
        jmp paranoid_exit
        CFI_ENDPROC
 
-ENTRY(general_protection)
+KPROBE_ENTRY(general_protection)
        errorentry do_general_protection
+       .previous .text
 
 ENTRY(alignment_check)
        errorentry do_alignment_check
index 30c843a5efddf7cb2c3ed9312e2aadcbfb16d95d..f062aa03bab7e282d149091b852c3718e5dbb537 100644 (file)
@@ -25,7 +25,7 @@
 #endif
 
 /* which logical CPU number maps to which CPU (physical APIC ID) */
-u8 x86_cpu_to_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
+u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
 EXPORT_SYMBOL(x86_cpu_to_apicid);
 u8 x86_cpu_to_log_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
 
index 9703da7202e368fe97b73b197c57465f1f3e9f34..f6523dd1bc0938fb6f21ff811af0b8292d77ca46 100644 (file)
@@ -72,10 +72,14 @@ static void cluster_send_IPI_mask(cpumask_t mask, int vector)
 static void cluster_send_IPI_allbutself(int vector)
 {
        cpumask_t mask = cpu_online_map;
-       cpu_clear(smp_processor_id(), mask);
+       int me = get_cpu(); /* Ensure we are not preempted when we clear */
+
+       cpu_clear(me, mask);
 
        if (!cpus_empty(mask))
                cluster_send_IPI_mask(mask, vector);
+
+       put_cpu();
 }
 
 static void cluster_send_IPI_all(int vector)
index d206d7e49cf5a5381e0c72c96d202bb77c677020..ba1a744e9bf0d72e0d8a49eaed6b287243a80415 100644 (file)
@@ -70,7 +70,7 @@ static struct irq_pin_list {
        short apic, pin, next;
 } irq_2_pin[PIN_MAP_SIZE];
 
-int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
+int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
 #ifdef CONFIG_PCI_MSI
 #define vector_to_irq(vector)  \
        (platform_legacy_irq(vector) ? vector : vector_irq[vector])
@@ -78,6 +78,54 @@ int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
 #define vector_to_irq(vector)  (vector)
 #endif
 
+#define __DO_ACTION(R, ACTION, FINAL)                                  \
+                                                                       \
+{                                                                      \
+       int pin;                                                        \
+       struct irq_pin_list *entry = irq_2_pin + irq;                   \
+                                                                       \
+       for (;;) {                                                      \
+               unsigned int reg;                                       \
+               pin = entry->pin;                                       \
+               if (pin == -1)                                          \
+                       break;                                          \
+               reg = io_apic_read(entry->apic, 0x10 + R + pin*2);      \
+               reg ACTION;                                             \
+               io_apic_modify(entry->apic, reg);                       \
+               if (!entry->next)                                       \
+                       break;                                          \
+               entry = irq_2_pin + entry->next;                        \
+       }                                                               \
+       FINAL;                                                          \
+}
+
+#ifdef CONFIG_SMP
+static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
+{
+       unsigned long flags;
+       unsigned int dest;
+       cpumask_t tmp;
+
+       cpus_and(tmp, mask, cpu_online_map);
+       if (cpus_empty(tmp))
+               tmp = TARGET_CPUS;
+
+       cpus_and(mask, tmp, CPU_MASK_ALL);
+
+       dest = cpu_mask_to_apicid(mask);
+
+       /*
+        * Only the high 8 bits are valid.
+        */
+       dest = SET_APIC_LOGICAL_ID(dest);
+
+       spin_lock_irqsave(&ioapic_lock, flags);
+       __DO_ACTION(1, = dest, )
+       set_irq_info(irq, mask);
+       spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+#endif
+
 /*
  * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
  * shared ISA-space IRQs, so we have to support them. We are super
@@ -101,26 +149,6 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
        entry->pin = pin;
 }
 
-#define __DO_ACTION(R, ACTION, FINAL)                                  \
-                                                                       \
-{                                                                      \
-       int pin;                                                        \
-       struct irq_pin_list *entry = irq_2_pin + irq;                   \
-                                                                       \
-       for (;;) {                                                      \
-               unsigned int reg;                                       \
-               pin = entry->pin;                                       \
-               if (pin == -1)                                          \
-                       break;                                          \
-               reg = io_apic_read(entry->apic, 0x10 + R + pin*2);      \
-               reg ACTION;                                             \
-               io_apic_modify(entry->apic, reg);                       \
-               if (!entry->next)                                       \
-                       break;                                          \
-               entry = irq_2_pin + entry->next;                        \
-       }                                                               \
-       FINAL;                                                          \
-}
 
 #define DO_ACTION(name,R,ACTION, FINAL)                                        \
                                                                        \
@@ -655,7 +683,7 @@ static inline int IO_APIC_irq_trigger(int irq)
 }
 
 /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
-u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
+u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
 
 int assign_irq_vector(int irq)
 {
@@ -767,6 +795,7 @@ static void __init setup_IO_APIC_irqs(void)
                spin_lock_irqsave(&ioapic_lock, flags);
                io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
                io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
+               set_native_irq_info(irq, TARGET_CPUS);
                spin_unlock_irqrestore(&ioapic_lock, flags);
        }
        }
@@ -1314,6 +1343,7 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq)
  */
 static void ack_edge_ioapic_irq(unsigned int irq)
 {
+       move_irq(irq);
        if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
                                        == (IRQ_PENDING | IRQ_DISABLED))
                mask_IO_APIC_irq(irq);
@@ -1343,26 +1373,10 @@ static unsigned int startup_level_ioapic_irq (unsigned int irq)
 
 static void end_level_ioapic_irq (unsigned int irq)
 {
+       move_irq(irq);
        ack_APIC_irq();
 }
 
-static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
-{
-       unsigned long flags;
-       unsigned int dest;
-
-       dest = cpu_mask_to_apicid(mask);
-
-       /*
-        * Only the high 8 bits are valid.
-        */
-       dest = SET_APIC_LOGICAL_ID(dest);
-
-       spin_lock_irqsave(&ioapic_lock, flags);
-       __DO_ACTION(1, = dest, )
-       spin_unlock_irqrestore(&ioapic_lock, flags);
-}
-
 #ifdef CONFIG_PCI_MSI
 static unsigned int startup_edge_ioapic_vector(unsigned int vector)
 {
@@ -1375,6 +1389,7 @@ static void ack_edge_ioapic_vector(unsigned int vector)
 {
        int irq = vector_to_irq(vector);
 
+       move_native_irq(vector);
        ack_edge_ioapic_irq(irq);
 }
 
@@ -1389,6 +1404,7 @@ static void end_level_ioapic_vector (unsigned int vector)
 {
        int irq = vector_to_irq(vector);
 
+       move_native_irq(vector);
        end_level_ioapic_irq(irq);
 }
 
@@ -1406,14 +1422,17 @@ static void unmask_IO_APIC_vector (unsigned int vector)
        unmask_IO_APIC_irq(irq);
 }
 
+#ifdef CONFIG_SMP
 static void set_ioapic_affinity_vector (unsigned int vector,
                                        cpumask_t cpu_mask)
 {
        int irq = vector_to_irq(vector);
 
+       set_native_irq_info(vector, cpu_mask);
        set_ioapic_affinity_irq(irq, cpu_mask);
 }
-#endif
+#endif // CONFIG_SMP
+#endif // CONFIG_PCI_MSI
 
 /*
  * Level and edge triggered IO-APIC interrupts need different handling,
@@ -1424,7 +1443,7 @@ static void set_ioapic_affinity_vector (unsigned int vector,
  * races.
  */
 
-static struct hw_interrupt_type ioapic_edge_type = {
+static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
        .typename = "IO-APIC-edge",
        .startup        = startup_edge_ioapic,
        .shutdown       = shutdown_edge_ioapic,
@@ -1432,10 +1451,12 @@ static struct hw_interrupt_type ioapic_edge_type = {
        .disable        = disable_edge_ioapic,
        .ack            = ack_edge_ioapic,
        .end            = end_edge_ioapic,
+#ifdef CONFIG_SMP
        .set_affinity = set_ioapic_affinity,
+#endif
 };
 
-static struct hw_interrupt_type ioapic_level_type = {
+static struct hw_interrupt_type ioapic_level_type __read_mostly = {
        .typename = "IO-APIC-level",
        .startup        = startup_level_ioapic,
        .shutdown       = shutdown_level_ioapic,
@@ -1443,7 +1464,9 @@ static struct hw_interrupt_type ioapic_level_type = {
        .disable        = disable_level_ioapic,
        .ack            = mask_and_ack_level_ioapic,
        .end            = end_level_ioapic,
+#ifdef CONFIG_SMP
        .set_affinity = set_ioapic_affinity,
+#endif
 };
 
 static inline void init_IO_APIC_traps(void)
@@ -1506,7 +1529,7 @@ static void ack_lapic_irq (unsigned int irq)
 
 static void end_lapic_irq (unsigned int i) { /* nothing */ }
 
-static struct hw_interrupt_type lapic_irq_type = {
+static struct hw_interrupt_type lapic_irq_type __read_mostly = {
        .typename = "local-APIC-edge",
        .startup = NULL, /* startup_irq() not used for IRQ0 */
        .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */
@@ -1918,6 +1941,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a
        spin_lock_irqsave(&ioapic_lock, flags);
        io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1));
        io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0));
+       set_native_irq_info(use_pci_vector() ?  entry.vector : irq, TARGET_CPUS);
        spin_unlock_irqrestore(&ioapic_lock, flags);
 
        return 0;
@@ -1931,6 +1955,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a
  * we need to reprogram the ioredtbls to cater for the cpus which have come online
  * so mask in all cases should simply be TARGET_CPUS
  */
+#ifdef CONFIG_SMP
 void __init setup_ioapic_dest(void)
 {
        int pin, ioapic, irq, irq_entry;
@@ -1949,3 +1974,4 @@ void __init setup_ioapic_dest(void)
 
        }
 }
+#endif
index 5c6dc705148299e5cede75693244e10ebe367410..df08c43276a07fffee23a7dd7edf28feb92b2de7 100644 (file)
@@ -74,7 +74,7 @@ static inline int is_IF_modifier(kprobe_opcode_t *insn)
        return 0;
 }
 
-int arch_prepare_kprobe(struct kprobe *p)
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
 {
        /* insn: must be on special executable page on x86_64. */
        up(&kprobe_mutex);
@@ -189,7 +189,7 @@ static inline s32 *is_riprel(u8 *insn)
        return NULL;
 }
 
-void arch_copy_kprobe(struct kprobe *p)
+void __kprobes arch_copy_kprobe(struct kprobe *p)
 {
        s32 *ripdisp;
        memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE);
@@ -215,21 +215,21 @@ void arch_copy_kprobe(struct kprobe *p)
        p->opcode = *p->addr;
 }
 
-void arch_arm_kprobe(struct kprobe *p)
+void __kprobes arch_arm_kprobe(struct kprobe *p)
 {
        *p->addr = BREAKPOINT_INSTRUCTION;
        flush_icache_range((unsigned long) p->addr,
                           (unsigned long) p->addr + sizeof(kprobe_opcode_t));
 }
 
-void arch_disarm_kprobe(struct kprobe *p)
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
 {
        *p->addr = p->opcode;
        flush_icache_range((unsigned long) p->addr,
                           (unsigned long) p->addr + sizeof(kprobe_opcode_t));
 }
 
-void arch_remove_kprobe(struct kprobe *p)
+void __kprobes arch_remove_kprobe(struct kprobe *p)
 {
        up(&kprobe_mutex);
        free_insn_slot(p->ainsn.insn);
@@ -261,7 +261,7 @@ static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs)
                kprobe_saved_rflags &= ~IF_MASK;
 }
 
-static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
 {
        regs->eflags |= TF_MASK;
        regs->eflags &= ~IF_MASK;
@@ -272,7 +272,8 @@ static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
                regs->rip = (unsigned long)p->ainsn.insn;
 }
 
-void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
+void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+                                     struct pt_regs *regs)
 {
        unsigned long *sara = (unsigned long *)regs->rsp;
         struct kretprobe_instance *ri;
@@ -295,7 +296,7 @@ void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
  * Interrupts are disabled on entry as trap3 is an interrupt gate and they
  * remain disabled thorough out this function.
  */
-int kprobe_handler(struct pt_regs *regs)
+int __kprobes kprobe_handler(struct pt_regs *regs)
 {
        struct kprobe *p;
        int ret = 0;
@@ -310,7 +311,8 @@ int kprobe_handler(struct pt_regs *regs)
                   Disarm the probe we just hit, and ignore it. */
                p = get_kprobe(addr);
                if (p) {
-                       if (kprobe_status == KPROBE_HIT_SS) {
+                       if (kprobe_status == KPROBE_HIT_SS &&
+                               *p->ainsn.insn == BREAKPOINT_INSTRUCTION) {
                                regs->eflags &= ~TF_MASK;
                                regs->eflags |= kprobe_saved_rflags;
                                unlock_kprobes();
@@ -360,7 +362,10 @@ int kprobe_handler(struct pt_regs *regs)
                         * either a probepoint or a debugger breakpoint
                         * at this address.  In either case, no further
                         * handling of this interrupt is appropriate.
+                        * Back up over the (now missing) int3 and run
+                        * the original instruction.
                         */
+                       regs->rip = (unsigned long)addr;
                        ret = 1;
                }
                /* Not one of ours: let kernel handle it */
@@ -399,7 +404,7 @@ no_kprobe:
 /*
  * Called when we hit the probe point at kretprobe_trampoline
  */
-int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 {
         struct kretprobe_instance *ri = NULL;
         struct hlist_head *head;
@@ -478,7 +483,7 @@ int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
  * that is atop the stack is the address following the copied instruction.
  * We need to make it the address following the original instruction.
  */
-static void resume_execution(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
 {
        unsigned long *tos = (unsigned long *)regs->rsp;
        unsigned long next_rip = 0;
@@ -536,7 +541,7 @@ static void resume_execution(struct kprobe *p, struct pt_regs *regs)
  * Interrupts are disabled on entry as trap1 is an interrupt gate and they
  * remain disabled thoroughout this function.  And we hold kprobe lock.
  */
-int post_kprobe_handler(struct pt_regs *regs)
+int __kprobes post_kprobe_handler(struct pt_regs *regs)
 {
        if (!kprobe_running())
                return 0;
@@ -571,7 +576,7 @@ out:
 }
 
 /* Interrupts disabled, kprobe_lock held. */
-int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
 {
        if (current_kprobe->fault_handler
            && current_kprobe->fault_handler(current_kprobe, regs, trapnr))
@@ -590,8 +595,8 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
 /*
  * Wrapper routine for handling exceptions.
  */
-int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
-                            void *data)
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+                                      unsigned long val, void *data)
 {
        struct die_args *args = (struct die_args *)data;
        switch (val) {
@@ -619,7 +624,7 @@ int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
        return NOTIFY_DONE;
 }
 
-int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 {
        struct jprobe *jp = container_of(p, struct jprobe, kp);
        unsigned long addr;
@@ -640,7 +645,7 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
        return 1;
 }
 
-void jprobe_return(void)
+void __kprobes jprobe_return(void)
 {
        preempt_enable_no_resched();
        asm volatile ("       xchg   %%rbx,%%rsp     \n"
@@ -651,7 +656,7 @@ void jprobe_return(void)
                      (jprobe_saved_rsp):"memory");
 }
 
-int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 {
        u8 *addr = (u8 *) (regs->rip - 1);
        unsigned long stack_addr = (unsigned long)jprobe_saved_rsp;
index 4e44d6e6b7e52f35d55993ea9616d4ef39a165fa..caf164959e197d25f100b54c1195ef19257e9c72 100644 (file)
@@ -290,7 +290,7 @@ void enable_timer_nmi_watchdog(void)
 
 static int nmi_pm_active; /* nmi_active before suspend */
 
-static int lapic_nmi_suspend(struct sys_device *dev, u32 state)
+static int lapic_nmi_suspend(struct sys_device *dev, pm_message_t state)
 {
        nmi_pm_active = nmi_active;
        disable_lapic_nmi_watchdog();
@@ -463,6 +463,8 @@ void touch_nmi_watchdog (void)
         */
        for (i = 0; i < NR_CPUS; i++)
                per_cpu(nmi_touch, i) = 1;
+
+       touch_softlockup_watchdog();
 }
 
 void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason)
@@ -522,14 +524,14 @@ asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
 
        nmi_enter();
        add_pda(__nmi_count,1);
-       if (!nmi_callback(regs, cpu))
+       if (!rcu_dereference(nmi_callback)(regs, cpu))
                default_do_nmi(regs);
        nmi_exit();
 }
 
 void set_nmi_callback(nmi_callback_t callback)
 {
-       nmi_callback = callback;
+       rcu_assign_pointer(nmi_callback, callback);
 }
 
 void unset_nmi_callback(void)
index 7577f9d7a75d8373f1a79be83c4e30c63b867f19..8661f82ac70b409d96a70b31b84ad87c485fbd30 100644 (file)
@@ -310,6 +310,7 @@ void __show_regs(struct pt_regs * regs)
 
 void show_regs(struct pt_regs *regs)
 {
+       printk("CPU %d:", smp_processor_id());
        __show_regs(regs);
        show_trace(&regs->rsp);
 }
index 116a491e2961bbca273d7319559e285be6e2aed0..b356f8e6adfe974f94cd890cd1ddd1d9cc17dd08 100644 (file)
@@ -65,7 +65,7 @@
  * Machine setup..
  */
 
-struct cpuinfo_x86 boot_cpu_data;
+struct cpuinfo_x86 boot_cpu_data __read_mostly;
 
 unsigned long mmu_cr4_features;
 
index 34082c1cc41e397f4254de5a6d22ba474ffeb90d..e3ffcacc8c90bf40d17a778c684401a9d66b17d3 100644 (file)
@@ -36,7 +36,7 @@ struct desc_ptr idt_descr = { 256 * 16, (unsigned long) idt_table };
 
 char boot_cpu_stack[IRQSTACKSIZE] __attribute__((section(".bss.page_aligned")));
 
-unsigned long __supported_pte_mask = ~0UL;
+unsigned long __supported_pte_mask __read_mostly = ~0UL;
 static int do_not_nx __initdata = 0;
 
 /* noexec=on|off
index 98590a989f3d759311935f6142191761bd42c376..d642fbf3da29d7823cd2a22f4329858aad7d76f3 100644 (file)
@@ -394,10 +394,11 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 #endif
        ret = setup_rt_frame(sig, ka, info, oldset, regs);
 
-       if (ret && !(ka->sa.sa_flags & SA_NODEFER)) {
+       if (ret) {
                spin_lock_irq(&current->sighand->siglock);
                sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-               sigaddset(&current->blocked,sig);
+               if (!(ka->sa.sa_flags & SA_NODEFER))
+                       sigaddset(&current->blocked,sig);
                recalc_sigpending();
                spin_unlock_irq(&current->sighand->siglock);
        }
index fa25e39fe54dfc4aab4390c95b45039da0202558..90aeccd1519074c27b65524c6fa8bc601f0efb09 100644 (file)
 /* Number of siblings per CPU package */
 int smp_num_siblings = 1;
 /* Package ID of each logical CPU */
-u8 phys_proc_id[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
-u8 cpu_core_id[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
+u8 phys_proc_id[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
+u8 cpu_core_id[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
 EXPORT_SYMBOL(phys_proc_id);
 EXPORT_SYMBOL(cpu_core_id);
 
 /* Bitmask of currently online CPUs */
-cpumask_t cpu_online_map;
+cpumask_t cpu_online_map __read_mostly;
 
 EXPORT_SYMBOL(cpu_online_map);
 
@@ -88,8 +88,8 @@ struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
 /* Set when the idlers are all forked */
 int smp_threads_ready;
 
-cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
-cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
+cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly;
+cpumask_t cpu_core_map[NR_CPUS] __read_mostly;
 EXPORT_SYMBOL(cpu_core_map);
 
 /*
index 66bf6ddeb0c334a956c6bc2e75beeca9262b5f9e..7b6abe0582536f54f5c5aea12587d22d3ab92f1d 100644 (file)
@@ -176,10 +176,7 @@ int do_settimeofday(struct timespec *tv)
        set_normalized_timespec(&xtime, sec, nsec);
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
 
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
@@ -471,7 +468,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  * off) isn't likely to go away much sooner anyway.
  */
 
-       if ((~time_status & STA_UNSYNC) && xtime.tv_sec > rtc_update &&
+       if (ntp_synced() && xtime.tv_sec > rtc_update &&
                abs(xtime.tv_nsec - 500000000) <= tick_nsec / 2) {
                set_rtc_mmss(xtime.tv_sec);
                rtc_update = xtime.tv_sec + 660;
@@ -1041,6 +1038,7 @@ static int timer_resume(struct sys_device *dev)
        write_sequnlock_irqrestore(&xtime_lock,flags);
        jiffies += sleep_length;
        wall_jiffies += sleep_length;
+       touch_softlockup_watchdog();
        return 0;
 }
 
index 6ead433a38851783a915e1abd44269a69cd90d90..f238d6078a5a921fcf94c935903b9aaa3aac5bf0 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/nmi.h>
+#include <linux/kprobes.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -419,8 +420,9 @@ void die_nmi(char *str, struct pt_regs *regs)
        do_exit(SIGSEGV);
 }
 
-static void do_trap(int trapnr, int signr, char *str, 
-                          struct pt_regs * regs, long error_code, siginfo_t *info)
+static void __kprobes do_trap(int trapnr, int signr, char *str,
+                             struct pt_regs * regs, long error_code,
+                             siginfo_t *info)
 {
        conditional_sti(regs);
 
@@ -504,7 +506,8 @@ DO_ERROR(18, SIGSEGV, "reserved", reserved)
 DO_ERROR(12, SIGBUS,  "stack segment", stack_segment)
 DO_ERROR( 8, SIGSEGV, "double fault", double_fault)
 
-asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
+asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,
+                                               long error_code)
 {
        conditional_sti(regs);
 
@@ -622,7 +625,7 @@ asmlinkage void default_do_nmi(struct pt_regs *regs)
                io_check_error(reason, regs);
 }
 
-asmlinkage void do_int3(struct pt_regs * regs, long error_code)
+asmlinkage void __kprobes do_int3(struct pt_regs * regs, long error_code)
 {
        if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) {
                return;
@@ -653,7 +656,8 @@ asmlinkage struct pt_regs *sync_regs(struct pt_regs *eregs)
 }
 
 /* runs on IST stack. */
-asmlinkage void do_debug(struct pt_regs * regs, unsigned long error_code)
+asmlinkage void __kprobes do_debug(struct pt_regs * regs,
+                                  unsigned long error_code)
 {
        unsigned long condition;
        struct task_struct *tsk = current;
index 2a94f9b60b2dd3eec9937cab4799f793582129f5..d4abb07af52dbef72da991331845b4438251a60b 100644 (file)
@@ -21,6 +21,7 @@ SECTIONS
        *(.text)
        SCHED_TEXT
        LOCK_TEXT
+       KPROBES_TEXT
        *(.fixup)
        *(.gnu.warning)
        } = 0x9090
index ca914c3bd49cf9ee3042a06426facc57516830fe..816732d8858c3195c7b6d78419b2b0b537de3f10 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/vt_kern.h>             /* For unblank_screen() */
 #include <linux/compiler.h>
 #include <linux/module.h>
+#include <linux/kprobes.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -294,7 +295,8 @@ int exception_trace = 1;
  *     bit 2 == 0 means kernel, 1 means user-mode
  *      bit 3 == 1 means fault was an instruction fetch
  */
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
+asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
+                                       unsigned long error_code)
 {
        struct task_struct *tsk;
        struct mm_struct *mm;
index 6a156f5692ae78a520a4dc0694a78f70b4a6c71a..04f7a33e144c4bbbd05befd65d6c396184e6e75d 100644 (file)
 #define Dprintk(x...)
 #endif
 
-struct pglist_data *node_data[MAX_NUMNODES];
+struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
 bootmem_data_t plat_node_bdata[MAX_NUMNODES];
 
 int memnode_shift;
 u8  memnodemap[NODEMAPSIZE];
 
-unsigned char cpu_to_node[NR_CPUS] = { [0 ... NR_CPUS-1] = NUMA_NO_NODE };
-cpumask_t     node_to_cpumask[MAX_NUMNODES];
+unsigned char cpu_to_node[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = NUMA_NO_NODE };
+cpumask_t     node_to_cpumask[MAX_NUMNODES] __read_mostly;
 
 int numa_off __initdata;
 
index df6e1e17b096ddc6093978f8c313c91dc7e1c5d2..dc42cede939462986a0acba34e756ee0614d4e3a 100644 (file)
@@ -702,12 +702,11 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
        if (ka.sa.sa_flags & SA_ONESHOT)
                ka.sa.sa_handler = SIG_DFL;
 
-       if (!(ka.sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked, &current->blocked, &ka.sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked, &current->blocked, &ka.sa.sa_mask);
+       if (!(ka.sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked, signr);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
        return 1;
 }
index e07287db5a40da91f6ce377e14cd9b356843a9f9..1ac7d5ce7456659ecf771df51580aacdb8282454 100644 (file)
@@ -122,10 +122,7 @@ int do_settimeofday(struct timespec *tv)
        set_normalized_timespec(&xtime, sec, nsec);
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
+       ntp_clear();
        write_sequnlock_irq(&xtime_lock);
        return 0;
 }
@@ -184,7 +181,7 @@ again:
                next += CCOUNT_PER_JIFFY;
                do_timer (regs); /* Linux handler in kernel/timer.c */
 
-               if ((time_status & STA_UNSYNC) == 0 &&
+               if (ntp_synced() &&
                    xtime.tv_sec - last_rtc_update >= 659 &&
                    abs((xtime.tv_nsec/1000)-(1000000-1000000/HZ))<5000000/HZ &&
                    jiffies - wall_jiffies == 1) {
index 256c0b1fed10ddfb8e3f242651ccdefdd970cfa9..89299f4ffe1243ae190ac5134cf8fc1d86474bf8 100644 (file)
@@ -219,7 +219,7 @@ config CRYPTO_CAST6
          described in RFC2612.
 
 config CRYPTO_TEA
-       tristate "TEA and XTEA cipher algorithms"
+       tristate "TEA, XTEA and XETA cipher algorithms"
        depends on CRYPTO
        help
          TEA cipher algorithm.
@@ -232,6 +232,9 @@ config CRYPTO_TEA
          the TEA algorithm to address a potential key weakness
          in the TEA algorithm.
 
+         Xtendend Encryption Tiny Algorithm is a mis-implementation 
+         of the XTEA algorithm for compatibility purposes.
+
 config CRYPTO_ARC4
        tristate "ARC4 cipher algorithm"
        depends on CRYPTO
index b4728811ce3b1570e7ee2806644692d099c32cdf..959c4e5f264f42ed831720149b3627d9a9e6300c 100644 (file)
@@ -66,7 +66,8 @@ static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name)
 
 static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags)
 {
-       tfm->crt_flags = 0;
+       tfm->crt_flags = flags & CRYPTO_TFM_REQ_MASK;
+       flags &= ~CRYPTO_TFM_REQ_MASK;
        
        switch (crypto_tfm_alg_type(tfm)) {
        case CRYPTO_ALG_TYPE_CIPHER:
index 8da644364cb4225824575ec4813741b9d46d7041..dfd4bcfc59758332d8ae82fc1d0db2e009c9b26a 100644 (file)
@@ -191,6 +191,8 @@ static unsigned int cbc_process_encrypt(const struct cipher_desc *desc,
        u8 *iv = desc->info;
        unsigned int done = 0;
 
+       nbytes -= bsize;
+
        do {
                xor(iv, src);
                fn(crypto_tfm_ctx(tfm), dst, iv);
@@ -198,7 +200,7 @@ static unsigned int cbc_process_encrypt(const struct cipher_desc *desc,
 
                src += bsize;
                dst += bsize;
-       } while ((done += bsize) < nbytes);
+       } while ((done += bsize) <= nbytes);
 
        return done;
 }
@@ -219,6 +221,8 @@ static unsigned int cbc_process_decrypt(const struct cipher_desc *desc,
        u8 *iv = desc->info;
        unsigned int done = 0;
 
+       nbytes -= bsize;
+
        do {
                u8 *tmp_dst = *dst_p;
 
@@ -230,7 +234,7 @@ static unsigned int cbc_process_decrypt(const struct cipher_desc *desc,
 
                src += bsize;
                dst += bsize;
-       } while ((done += bsize) < nbytes);
+       } while ((done += bsize) <= nbytes);
 
        return done;
 }
@@ -243,12 +247,14 @@ static unsigned int ecb_process(const struct cipher_desc *desc, u8 *dst,
        void (*fn)(void *, u8 *, const u8 *) = desc->crfn;
        unsigned int done = 0;
 
+       nbytes -= bsize;
+
        do {
                fn(crypto_tfm_ctx(tfm), dst, src);
 
                src += bsize;
                dst += bsize;
-       } while ((done += bsize) < nbytes);
+       } while ((done += bsize) <= nbytes);
 
        return done;
 }
@@ -377,11 +383,7 @@ static int nocrypt_iv(struct crypto_tfm *tfm,
 int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags)
 {
        u32 mode = flags & CRYPTO_TFM_MODE_MASK;
-       
        tfm->crt_cipher.cit_mode = mode ? mode : CRYPTO_TFM_MODE_ECB;
-       if (flags & CRYPTO_TFM_REQ_WEAK_KEY)
-               tfm->crt_flags = CRYPTO_TFM_REQ_WEAK_KEY;
-       
        return 0;
 }
 
index 37515beafc8ce44ff501d15d617968248656b59f..37aa652ce5ce6f89e4738ac07dd770b8df4a6ac9 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <asm/kmap_types.h>
 
 extern enum km_type crypto_km_types[];
@@ -38,7 +39,7 @@ static inline void crypto_kunmap(void *vaddr, int out)
 
 static inline void crypto_yield(struct crypto_tfm *tfm)
 {
-       if (!in_atomic())
+       if (tfm->crt_flags & CRYPTO_TFM_REQ_MAY_SLEEP)
                cond_resched();
 }
 
index bd7524cfff33e6ab71c9b37e6f98733e498a354a..68639419c5bd0283697d60defb50f6cf109e8f5e 100644 (file)
@@ -72,7 +72,7 @@ static char *check[] = {
        "des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish",
        "twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6",
        "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",
-       "khazad", "wp512", "wp384", "wp256", "tnepres", NULL
+       "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", NULL
 };
 
 static void hexdump(unsigned char *buf, unsigned int len)
@@ -859,6 +859,10 @@ static void do_test(void)
                test_cipher ("anubis", MODE_CBC, ENCRYPT, anubis_cbc_enc_tv_template, ANUBIS_CBC_ENC_TEST_VECTORS);
                test_cipher ("anubis", MODE_CBC, DECRYPT, anubis_cbc_dec_tv_template, ANUBIS_CBC_ENC_TEST_VECTORS);
 
+               //XETA
+               test_cipher ("xeta", MODE_ECB, ENCRYPT, xeta_enc_tv_template, XETA_ENC_TEST_VECTORS);
+               test_cipher ("xeta", MODE_ECB, DECRYPT, xeta_dec_tv_template, XETA_DEC_TEST_VECTORS);
+
                test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS);
                test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS);
                test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS);
@@ -1016,6 +1020,11 @@ static void do_test(void)
        case 29:
                test_hash("tgr128", tgr128_tv_template, TGR128_TEST_VECTORS);
                break;
+               
+       case 30:
+               test_cipher ("xeta", MODE_ECB, ENCRYPT, xeta_enc_tv_template, XETA_ENC_TEST_VECTORS);
+               test_cipher ("xeta", MODE_ECB, DECRYPT, xeta_dec_tv_template, XETA_DEC_TEST_VECTORS);
+               break;
 
 #ifdef CONFIG_CRYPTO_HMAC
        case 100:
index c01a0ce9b40a09be75d879246c7d667e7c28f9ba..522ffd4b6f43ef990ec9645ba6033ee4e755248f 100644 (file)
@@ -2211,7 +2211,7 @@ static struct cipher_testvec xtea_enc_tv_template[] = {
                .klen   = 16,
                .input  = { [0 ... 8] = 0x00 },
                .ilen   = 8,
-               .result = { 0xaa, 0x22, 0x96, 0xe5, 0x6c, 0x61, 0xf3, 0x45 },
+               .result = { 0xd8, 0xd4, 0xe9, 0xde, 0xd9, 0x1e, 0x13, 0xf7 },
                .rlen   = 8,
        }, {
                .key    = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76,
@@ -2219,31 +2219,31 @@ static struct cipher_testvec xtea_enc_tv_template[] = {
                .klen   = 16,
                .input  = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e },
                .ilen   = 8,
-               .result = { 0x82, 0x3e, 0xeb, 0x35, 0xdc, 0xdd, 0xd9, 0xc3 },
+               .result = { 0x94, 0xeb, 0xc8, 0x96, 0x84, 0x6a, 0x49, 0xa8 },
                .rlen   = 8,
        }, {
                .key    = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25,
                            0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e },
                .klen   = 16,
-               .input  = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74,
+               .input  = { 0x3e, 0xce, 0xae, 0x22, 0x60, 0x56, 0xa8, 0x9d,
                            0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 },
                .ilen   = 16,
-               .result = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea,
+               .result = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea, 
                            0x61, 0x35, 0xaa, 0xed, 0xb5, 0xcb, 0x71, 0x2c },
                .rlen   = 16,
        }, {
                .key    = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c,
                            0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f },
                .klen   = 16,
-               .input  = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67,
-                           0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20,
-                           0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72,
+               .input  = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67, 
+                           0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 
+                           0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72, 
                            0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 },
                .ilen   = 32,
-               .result = { 0x0b, 0x03, 0xcd, 0x8a, 0xbe, 0x95, 0xfd, 0xb1,
-                           0xc1, 0x44, 0x91, 0x0b, 0xa5, 0xc9, 0x1b, 0xb4,
-                           0xa9, 0xda, 0x1e, 0x9e, 0xb1, 0x3e, 0x2a, 0x8f,
-                           0xea, 0xa5, 0x6a, 0x85, 0xd1, 0xf4, 0xa8, 0xa5 },
+               .result = { 0x99, 0x81, 0x9f, 0x5d, 0x6f, 0x4b, 0x31, 0x3a,
+                           0x86, 0xff, 0x6f, 0xd0, 0xe3, 0x87, 0x70, 0x07,
+                           0x4d, 0xb8, 0xcf, 0xf3, 0x99, 0x50, 0xb3, 0xd4,
+                           0x73, 0xa2, 0xfa, 0xc9, 0x16, 0x59, 0x5d, 0x81 },
                .rlen   = 32,
        }
 };
@@ -2252,7 +2252,7 @@ static struct cipher_testvec xtea_dec_tv_template[] = {
        {
                .key    = { [0 ... 15] = 0x00 },
                .klen   = 16,
-               .input  = { 0xaa, 0x22, 0x96, 0xe5, 0x6c, 0x61, 0xf3, 0x45 },
+               .input  = { 0xd8, 0xd4, 0xe9, 0xde, 0xd9, 0x1e, 0x13, 0xf7 },
                .ilen   = 8,
                .result = { [0 ... 8] = 0x00 },
                .rlen   = 8,
@@ -2260,7 +2260,7 @@ static struct cipher_testvec xtea_dec_tv_template[] = {
                .key    = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76,
                            0x77, 0x5d, 0x0e, 0x26, 0x6c, 0x28, 0x78, 0x43 },
                .klen   = 16,
-               .input  = { 0x82, 0x3e, 0xeb, 0x35, 0xdc, 0xdd, 0xd9, 0xc3 },
+               .input  = { 0x94, 0xeb, 0xc8, 0x96, 0x84, 0x6a, 0x49, 0xa8 },
                .ilen   = 8,
                .result = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e },
                .rlen   = 8,
@@ -2268,24 +2268,24 @@ static struct cipher_testvec xtea_dec_tv_template[] = {
                .key    = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25,
                            0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e },
                .klen   = 16,
-               .input  = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea,
-                           0x61, 0x35, 0xaa, 0xed, 0xb5, 0xcb, 0x71, 0x2c },
+               .input  = { 0x3e, 0xce, 0xae, 0x22, 0x60, 0x56, 0xa8, 0x9d,
+                           0x77, 0x4d, 0xd4, 0xb4, 0x87, 0x24, 0xe3, 0x9a },
                .ilen   = 16,
-               .result = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74,
+               .result = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74, 
                            0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 },
                .rlen   = 16,
        }, {
                .key    = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c,
                            0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f },
                .klen   = 16,
-               .input  = { 0x0b, 0x03, 0xcd, 0x8a, 0xbe, 0x95, 0xfd, 0xb1,
-                           0xc1, 0x44, 0x91, 0x0b, 0xa5, 0xc9, 0x1b, 0xb4,
-                           0xa9, 0xda, 0x1e, 0x9e, 0xb1, 0x3e, 0x2a, 0x8f,
-                           0xea, 0xa5, 0x6a, 0x85, 0xd1, 0xf4, 0xa8, 0xa5 },
+               .input  = { 0x99, 0x81, 0x9f, 0x5d, 0x6f, 0x4b, 0x31, 0x3a,
+                           0x86, 0xff, 0x6f, 0xd0, 0xe3, 0x87, 0x70, 0x07,
+                           0x4d, 0xb8, 0xcf, 0xf3, 0x99, 0x50, 0xb3, 0xd4,
+                           0x73, 0xa2, 0xfa, 0xc9, 0x16, 0x59, 0x5d, 0x81 },
                .ilen   = 32,
-               .result = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67,
-                           0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20,
-                           0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72,
+               .result = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67, 
+                           0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 
+                           0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72, 
                            0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 },
                .rlen   = 32,
        }
@@ -2594,6 +2594,98 @@ static struct cipher_testvec anubis_cbc_dec_tv_template[] = {
        },
 };
 
+/* 
+ * XETA test vectors 
+ */
+#define XETA_ENC_TEST_VECTORS  4
+#define XETA_DEC_TEST_VECTORS  4
+
+static struct cipher_testvec xeta_enc_tv_template[] = {
+       {
+               .key    = { [0 ... 15] = 0x00 },
+               .klen   = 16,
+               .input  = { [0 ... 8] = 0x00 },
+               .ilen   = 8,
+               .result = { 0xaa, 0x22, 0x96, 0xe5, 0x6c, 0x61, 0xf3, 0x45 },
+               .rlen   = 8,
+       }, {
+               .key    = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76,
+                           0x77, 0x5d, 0x0e, 0x26, 0x6c, 0x28, 0x78, 0x43 },
+               .klen   = 16,
+               .input  = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e },
+               .ilen   = 8,
+               .result = { 0x82, 0x3e, 0xeb, 0x35, 0xdc, 0xdd, 0xd9, 0xc3 },
+               .rlen   = 8,
+       }, {
+               .key    = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25,
+                           0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e },
+               .klen   = 16,
+               .input  = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74, 
+                           0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 },
+               .ilen   = 16,
+               .result = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea, 
+                           0x61, 0x35, 0xaa, 0xed, 0xb5, 0xcb, 0x71, 0x2c },
+               .rlen   = 16,
+       }, {
+               .key    = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c,
+                           0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f },
+               .klen   = 16,
+               .input  = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67, 
+                           0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 
+                           0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72, 
+                           0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 },
+               .ilen   = 32,
+               .result = { 0x0b, 0x03, 0xcd, 0x8a, 0xbe, 0x95, 0xfd, 0xb1, 
+                           0xc1, 0x44, 0x91, 0x0b, 0xa5, 0xc9, 0x1b, 0xb4, 
+                           0xa9, 0xda, 0x1e, 0x9e, 0xb1, 0x3e, 0x2a, 0x8f, 
+                           0xea, 0xa5, 0x6a, 0x85, 0xd1, 0xf4, 0xa8, 0xa5 },
+               .rlen   = 32,
+       }
+};
+
+static struct cipher_testvec xeta_dec_tv_template[] = {
+       {
+               .key    = { [0 ... 15] = 0x00 },
+               .klen   = 16,
+               .input  = { 0xaa, 0x22, 0x96, 0xe5, 0x6c, 0x61, 0xf3, 0x45 },
+               .ilen   = 8,
+               .result = { [0 ... 8] = 0x00 },
+               .rlen   = 8,
+       }, {
+               .key    = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76,
+                           0x77, 0x5d, 0x0e, 0x26, 0x6c, 0x28, 0x78, 0x43 },
+               .klen   = 16,
+               .input  = { 0x82, 0x3e, 0xeb, 0x35, 0xdc, 0xdd, 0xd9, 0xc3 },
+               .ilen   = 8,
+               .result = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e },
+               .rlen   = 8,
+       }, {
+               .key    = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25,
+                           0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e },
+               .klen   = 16,
+               .input  = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea, 
+                           0x61, 0x35, 0xaa, 0xed, 0xb5, 0xcb, 0x71, 0x2c },
+               .ilen   = 16,
+               .result = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74, 
+                           0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 },
+               .rlen   = 16,
+       }, {
+               .key    = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c,
+                           0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f },
+               .klen   = 16,
+               .input  = { 0x0b, 0x03, 0xcd, 0x8a, 0xbe, 0x95, 0xfd, 0xb1, 
+                           0xc1, 0x44, 0x91, 0x0b, 0xa5, 0xc9, 0x1b, 0xb4, 
+                           0xa9, 0xda, 0x1e, 0x9e, 0xb1, 0x3e, 0x2a, 0x8f, 
+                           0xea, 0xa5, 0x6a, 0x85, 0xd1, 0xf4, 0xa8, 0xa5 },
+               .ilen   = 32,
+               .result = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67, 
+                           0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 
+                           0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72, 
+                           0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 },
+               .rlen   = 32,
+       }
+};
+
 /*
  * Compression stuff.
  */
index 03c23cbd3afa1f6373d964b308463701ab316458..5924efdd3a169980c3893a9b9f8d931259d25ec9 100644 (file)
@@ -1,11 +1,15 @@
 /* 
  * Cryptographic API.
  *
- * TEA and Xtended TEA Algorithms
+ * TEA, XTEA, and XETA crypto alogrithms
  *
  * The TEA and Xtended TEA algorithms were developed by David Wheeler 
  * and Roger Needham at the Computer Laboratory of Cambridge University.
  *
+ * Due to the order of evaluation in XTEA many people have incorrectly
+ * implemented it.  XETA (XTEA in the wrong order), exists for
+ * compatibility with these implementations.
+ *
  * Copyright (c) 2004 Aaron Grothe ajgrothe@yahoo.com
  *
  * This program is free software; you can redistribute it and/or modify
@@ -153,9 +157,9 @@ static void xtea_encrypt(void *ctx_arg, u8 *dst, const u8 *src)
        z = u32_in (src + 4);
 
        while (sum != limit) {
-               y += (z << 4 ^ z >> 5) + (z ^ sum) + ctx->KEY[sum&3]
+               y += ((z << 4 ^ z >> 5) + z) ^ (sum + ctx->KEY[sum&3])
                sum += XTEA_DELTA;
-               z += (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 &3]
+               z += ((y << 4 ^ y >> 5) + y) ^ (sum + ctx->KEY[sum>>11 &3])
        }
        
        u32_out (dst, y);
@@ -174,6 +178,51 @@ static void xtea_decrypt(void *ctx_arg, u8 *dst, const u8 *src)
 
        sum = XTEA_DELTA * XTEA_ROUNDS;
 
+       while (sum) {
+               z -= ((y << 4 ^ y >> 5) + y) ^ (sum + ctx->KEY[sum>>11 & 3]);
+               sum -= XTEA_DELTA;
+               y -= ((z << 4 ^ z >> 5) + z) ^ (sum + ctx->KEY[sum & 3]);
+       }
+       
+       u32_out (dst, y);
+       u32_out (dst + 4, z);
+
+}
+
+
+static void xeta_encrypt(void *ctx_arg, u8 *dst, const u8 *src)
+{ 
+
+       u32 y, z, sum = 0;
+       u32 limit = XTEA_DELTA * XTEA_ROUNDS;
+
+       struct xtea_ctx *ctx = ctx_arg;
+
+       y = u32_in (src);
+       z = u32_in (src + 4);
+
+       while (sum != limit) {
+               y += (z << 4 ^ z >> 5) + (z ^ sum) + ctx->KEY[sum&3];
+               sum += XTEA_DELTA;
+               z += (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 &3];
+       }
+       
+       u32_out (dst, y);
+       u32_out (dst + 4, z);
+
+}
+
+static void xeta_decrypt(void *ctx_arg, u8 *dst, const u8 *src)
+{ 
+
+       u32 y, z, sum;
+       struct tea_ctx *ctx = ctx_arg;
+
+       y = u32_in (src);
+       z = u32_in (src + 4);
+
+       sum = XTEA_DELTA * XTEA_ROUNDS;
+
        while (sum) {
                z -= (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 & 3];
                sum -= XTEA_DELTA;
@@ -215,6 +264,21 @@ static struct crypto_alg xtea_alg = {
        .cia_decrypt            =       xtea_decrypt } }
 };
 
+static struct crypto_alg xeta_alg = {
+       .cra_name               =       "xeta",
+       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          =       XTEA_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof (struct xtea_ctx),
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(xtea_alg.cra_list),
+       .cra_u                  =       { .cipher = {
+       .cia_min_keysize        =       XTEA_KEY_SIZE,
+       .cia_max_keysize        =       XTEA_KEY_SIZE,
+       .cia_setkey             =       xtea_setkey,
+       .cia_encrypt            =       xeta_encrypt,
+       .cia_decrypt            =       xeta_decrypt } }
+};
+
 static int __init init(void)
 {
        int ret = 0;
@@ -229,6 +293,13 @@ static int __init init(void)
                goto out;
        }
 
+       ret = crypto_register_alg(&xeta_alg);
+       if (ret < 0) {
+               crypto_unregister_alg(&tea_alg);
+               crypto_unregister_alg(&xtea_alg);
+               goto out;
+       }
+
 out:   
        return ret;
 }
@@ -237,12 +308,14 @@ static void __exit fini(void)
 {
        crypto_unregister_alg(&tea_alg);
        crypto_unregister_alg(&xtea_alg);
+       crypto_unregister_alg(&xeta_alg);
 }
 
 MODULE_ALIAS("xtea");
+MODULE_ALIAS("xeta");
 
 module_init(init);
 module_exit(fini);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("TEA & XTEA Cryptographic Algorithms");
+MODULE_DESCRIPTION("TEA, XTEA & XETA Cryptographic Algorithms");
index cecab0acc3fe6baf22311c574abdc96ede313b74..46d655fab1159c54768d08d226ac3bc36a393b2a 100644 (file)
@@ -48,6 +48,8 @@ source "drivers/hwmon/Kconfig"
 
 source "drivers/misc/Kconfig"
 
+source "drivers/mfd/Kconfig"
+
 source "drivers/media/Kconfig"
 
 source "drivers/video/Kconfig"
index 126a851d56538f8c336da54d3091d0491f470094..9663132ed82547d3584a280b19c14a26c0895a0a 100644 (file)
@@ -26,7 +26,7 @@ obj-$(CONFIG_FB_INTEL)          += video/intelfb/
 obj-$(CONFIG_SERIO)            += input/serio/
 obj-y                          += serial/
 obj-$(CONFIG_PARPORT)          += parport/
-obj-y                          += base/ block/ misc/ net/ media/
+obj-y                          += base/ block/ misc/ mfd/ net/ media/
 obj-$(CONFIG_NUBUS)            += nubus/
 obj-$(CONFIG_ATM)              += atm/
 obj-$(CONFIG_PPC_PMAC)         += macintosh/
index 73c6b85299c12e1e34097b7723b039ef5fc522e3..d74a7c5e75dda83fdca50df5f7f1d05045214226 100644 (file)
@@ -513,7 +513,7 @@ static void rx_complete (amb_dev * dev, rx_out * rx) {
          
          // VC layer stats
          atomic_inc(&atm_vcc->stats->rx);
-         do_gettimeofday(&skb->stamp);
+         __net_timestamp(skb);
          // end of our responsability
          atm_vcc->push (atm_vcc, skb);
          return;
index f2f01cb82cb4f6bd9b1e15206331b3ad5896b349..57f1810fdccd74df8f755d1aa1f935ccf68b482e 100644 (file)
@@ -325,7 +325,7 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
                result = -ENOBUFS;
                goto done;
        }
-       do_gettimeofday(&new_skb->stamp);
+       __net_timestamp(new_skb);
        memcpy(skb_put(new_skb,skb->len),skb->data,skb->len);
        out_vcc->push(out_vcc,new_skb);
        atomic_inc(&vcc->stats->tx);
index 10da36934769d6fbdf124945f546462e7a10f28a..c13c4d736ef56911324acb025b91bbe4bde0279e 100644 (file)
@@ -537,7 +537,7 @@ static int rx_aal0(struct atm_vcc *vcc)
                return 0;
        }
        skb_put(skb,length);
-       skb->stamp = eni_vcc->timestamp;
+       skb_set_timestamp(skb, &eni_vcc->timestamp);
        DPRINTK("got len %ld\n",length);
        if (do_rx_dma(vcc,skb,1,length >> 2,length >> 2)) return 1;
        eni_vcc->rxing++;
index b078fa548ebf9954babc6d0442455af4ae4396d4..58219744f5dbfef006d41888c893ff54be6648c8 100644 (file)
@@ -815,7 +815,7 @@ static void process_incoming (struct fs_dev *dev, struct queue *q)
                                skb_put (skb, qe->p1 & 0xffff); 
                                ATM_SKB(skb)->vcc = atm_vcc;
                                atomic_inc(&atm_vcc->stats->rx);
-                               do_gettimeofday(&skb->stamp);
+                               __net_timestamp(skb);
                                fs_dprintk (FS_DEBUG_ALLOC, "Free rec-skb: %p (pushed)\n", skb);
                                atm_vcc->push (atm_vcc, skb);
                                fs_dprintk (FS_DEBUG_ALLOC, "Free rec-d: %p\n", pe);
index 5f702199543ac043eec3905b6231e119e421ba7c..2bf723a7b6e62c12918b865cac2cf6c970d81736 100644 (file)
@@ -1176,7 +1176,7 @@ fore200e_push_rpd(struct fore200e* fore200e, struct atm_vcc* vcc, struct rpd* rp
        return -ENOMEM;
     } 
 
-    do_gettimeofday(&skb->stamp);
+    __net_timestamp(skb);
     
 #ifdef FORE200E_52BYTE_AAL0_SDU
     if (cell_header) {
index 28250c9b32d6cf9f28e48ce77a3b79444d773176..fde9334059af595428f3f871599a538e3c3a29b0 100644 (file)
@@ -1886,7 +1886,7 @@ he_service_rbrq(struct he_dev *he_dev, int group)
                if (rx_skb_reserve > 0)
                        skb_reserve(skb, rx_skb_reserve);
 
-               do_gettimeofday(&skb->stamp);
+               __net_timestamp(skb);
 
                for (iov = he_vcc->iov_head;
                                iov < he_vcc->iov_tail; ++iov) {
index 924a2c8988bd62d05236907c43a14b622a319cc0..0cded04680033a95c1cd93ad9ce771d7112651e1 100644 (file)
@@ -1034,7 +1034,7 @@ static void rx_schedule (hrz_dev * dev, int irq) {
          struct atm_vcc * vcc = ATM_SKB(skb)->vcc;
          // VC layer stats
          atomic_inc(&vcc->stats->rx);
-         do_gettimeofday(&skb->stamp);
+         __net_timestamp(skb);
          // end of our responsability
          vcc->push (vcc, skb);
        }
index 30b7e990ed0b19a4419b9cb51e967055830c3cba..b4a76cade646badde872e6895c07c97339465a22 100644 (file)
@@ -1101,7 +1101,7 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe)
                               cell, ATM_CELL_PAYLOAD);
 
                        ATM_SKB(sb)->vcc = vcc;
-                       do_gettimeofday(&sb->stamp);
+                       __net_timestamp(sb);
                        vcc->push(vcc, sb);
                        atomic_inc(&vcc->stats->rx);
 
@@ -1179,7 +1179,7 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe)
 
                        skb_trim(skb, len);
                        ATM_SKB(skb)->vcc = vcc;
-                       do_gettimeofday(&skb->stamp);
+                       __net_timestamp(skb);
 
                        vcc->push(vcc, skb);
                        atomic_inc(&vcc->stats->rx);
@@ -1201,7 +1201,7 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe)
 
                skb_trim(skb, len);
                ATM_SKB(skb)->vcc = vcc;
-               do_gettimeofday(&skb->stamp);
+               __net_timestamp(skb);
 
                vcc->push(vcc, skb);
                atomic_inc(&vcc->stats->rx);
@@ -1340,7 +1340,7 @@ idt77252_rx_raw(struct idt77252_dev *card)
                       ATM_CELL_PAYLOAD);
 
                ATM_SKB(sb)->vcc = vcc;
-               do_gettimeofday(&sb->stamp);
+               __net_timestamp(sb);
                vcc->push(vcc, sb);
                atomic_inc(&vcc->stats->rx);
 
index ffe3afa723b8db98e51e1ac91c39655e5cda6ff2..51ec147872934e902cb8c6ce4c99c6480cd2e0d5 100644 (file)
@@ -1427,7 +1427,7 @@ static void vcc_rx_aal5(struct lanai_vcc *lvcc, int endptr)
        skb_put(skb, size);
        vcc_rx_memcpy(skb->data, lvcc, size);
        ATM_SKB(skb)->vcc = lvcc->rx.atmvcc;
-       do_gettimeofday(&skb->stamp);
+       __net_timestamp(skb);
        lvcc->rx.atmvcc->push(lvcc->rx.atmvcc, skb);
        atomic_inc(&lvcc->rx.atmvcc->stats->rx);
     out:
index b2a7b754fd1403a4c7dbd4ffe5ab47cd3de70b5e..c57e20dcb0f839004267dc3ffbdc16e95a351403 100644 (file)
@@ -214,8 +214,7 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev);
 static void __devinit ns_init_card_error(ns_dev *card, int error);
 static scq_info *get_scq(int size, u32 scd);
 static void free_scq(scq_info *scq, struct atm_vcc *vcc);
-static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1,
-                       u32 handle2, u32 addr2);
+static void push_rxbufs(ns_dev *, struct sk_buff *);
 static irqreturn_t ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
 static int ns_open(struct atm_vcc *vcc);
 static void ns_close(struct atm_vcc *vcc);
@@ -766,6 +765,7 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
          ns_init_card_error(card, error);
         return error;
       }
+      NS_SKB_CB(hb)->buf_type = BUF_NONE;
       skb_queue_tail(&card->hbpool.queue, hb);
       card->hbpool.count++;
    }
@@ -786,9 +786,10 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
          ns_init_card_error(card, error);
         return error;
       }
+      NS_SKB_CB(lb)->buf_type = BUF_LG;
       skb_queue_tail(&card->lbpool.queue, lb);
       skb_reserve(lb, NS_SMBUFSIZE);
-      push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0);
+      push_rxbufs(card, lb);
       /* Due to the implementation of push_rxbufs() this is 1, not 0 */
       if (j == 1)
       {
@@ -822,9 +823,10 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
          ns_init_card_error(card, error);
         return error;
       }
+      NS_SKB_CB(sb)->buf_type = BUF_SM;
       skb_queue_tail(&card->sbpool.queue, sb);
       skb_reserve(sb, NS_AAL0_HEADER);
-      push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0);
+      push_rxbufs(card, sb);
    }
    /* Test for strange behaviour which leads to crashes */
    if ((bcount = ns_stat_sfbqc_get(readl(card->membase + STAT))) < card->sbnr.min)
@@ -852,6 +854,7 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
          ns_init_card_error(card, error);
         return error;
       }
+      NS_SKB_CB(iovb)->buf_type = BUF_NONE;
       skb_queue_tail(&card->iovpool.queue, iovb);
       card->iovpool.count++;
    }
@@ -1078,12 +1081,18 @@ static void free_scq(scq_info *scq, struct atm_vcc *vcc)
 
 /* The handles passed must be pointers to the sk_buff containing the small
    or large buffer(s) cast to u32. */
-static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1,
-                       u32 handle2, u32 addr2)
+static void push_rxbufs(ns_dev *card, struct sk_buff *skb)
 {
+   struct ns_skb_cb *cb = NS_SKB_CB(skb);
+   u32 handle1, addr1;
+   u32 handle2, addr2;
    u32 stat;
    unsigned long flags;
    
+   /* *BARF* */
+   handle2 = addr2 = 0;
+   handle1 = (u32)skb;
+   addr1 = (u32)virt_to_bus(skb->data);
 
 #ifdef GENERAL_DEBUG
    if (!addr1)
@@ -1093,7 +1102,7 @@ static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1,
    stat = readl(card->membase + STAT);
    card->sbfqc = ns_stat_sfbqc_get(stat);
    card->lbfqc = ns_stat_lfbqc_get(stat);
-   if (type == BUF_SM)
+   if (cb->buf_type == BUF_SM)
    {
       if (!addr2)
       {
@@ -1111,7 +1120,7 @@ static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1,
         }
       }      
    }
-   else /* type == BUF_LG */
+   else /* buf_type == BUF_LG */
    {
       if (!addr2)
       {
@@ -1132,26 +1141,26 @@ static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1,
 
    if (addr2)
    {
-      if (type == BUF_SM)
+      if (cb->buf_type == BUF_SM)
       {
          if (card->sbfqc >= card->sbnr.max)
          {
-            skb_unlink((struct sk_buff *) handle1);
+            skb_unlink((struct sk_buff *) handle1, &card->sbpool.queue);
             dev_kfree_skb_any((struct sk_buff *) handle1);
-            skb_unlink((struct sk_buff *) handle2);
+            skb_unlink((struct sk_buff *) handle2, &card->sbpool.queue);
             dev_kfree_skb_any((struct sk_buff *) handle2);
             return;
          }
         else
             card->sbfqc += 2;
       }
-      else /* (type == BUF_LG) */
+      else /* (buf_type == BUF_LG) */
       {
          if (card->lbfqc >= card->lbnr.max)
          {
-            skb_unlink((struct sk_buff *) handle1);
+            skb_unlink((struct sk_buff *) handle1, &card->lbpool.queue);
             dev_kfree_skb_any((struct sk_buff *) handle1);
-            skb_unlink((struct sk_buff *) handle2);
+            skb_unlink((struct sk_buff *) handle2, &card->lbpool.queue);
             dev_kfree_skb_any((struct sk_buff *) handle2);
             return;
          }
@@ -1166,12 +1175,12 @@ static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1,
       writel(handle2, card->membase + DR2);
       writel(addr1, card->membase + DR1);
       writel(handle1, card->membase + DR0);
-      writel(NS_CMD_WRITE_FREEBUFQ | (u32) type, card->membase + CMD);
+      writel(NS_CMD_WRITE_FREEBUFQ | cb->buf_type, card->membase + CMD);
  
       spin_unlock_irqrestore(&card->res_lock, flags);
 
       XPRINTK("nicstar%d: Pushing %s buffers at 0x%x and 0x%x.\n", card->index,
-              (type == BUF_SM ? "small" : "large"), addr1, addr2);
+              (cb->buf_type == BUF_SM ? "small" : "large"), addr1, addr2);
    }
 
    if (!card->efbie && card->sbfqc >= card->sbnr.min &&
@@ -1322,9 +1331,10 @@ static irqreturn_t ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
             card->efbie = 0;
             break;
          }
+         NS_SKB_CB(sb)->buf_type = BUF_SM;
          skb_queue_tail(&card->sbpool.queue, sb);
          skb_reserve(sb, NS_AAL0_HEADER);
-         push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0);
+         push_rxbufs(card, sb);
       }
       card->sbfqc = i;
       process_rsq(card);
@@ -1348,9 +1358,10 @@ static irqreturn_t ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
             card->efbie = 0;
             break;
          }
+         NS_SKB_CB(lb)->buf_type = BUF_LG;
          skb_queue_tail(&card->lbpool.queue, lb);
          skb_reserve(lb, NS_SMBUFSIZE);
-         push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0);
+         push_rxbufs(card, lb);
       }
       card->lbfqc = i;
       process_rsq(card);
@@ -2202,7 +2213,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
          memcpy(sb->tail, cell, ATM_CELL_PAYLOAD);
          skb_put(sb, ATM_CELL_PAYLOAD);
          ATM_SKB(sb)->vcc = vcc;
-         do_gettimeofday(&sb->stamp);
+        __net_timestamp(sb);
          vcc->push(vcc, sb);
          atomic_inc(&vcc->stats->rx);
          cell += ATM_CELL_PAYLOAD;
@@ -2227,6 +2238,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
             recycle_rx_buf(card, skb);
             return;
         }
+         NS_SKB_CB(iovb)->buf_type = BUF_NONE;
       }
       else
          if (--card->iovpool.count < card->iovnr.min)
@@ -2234,6 +2246,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
            struct sk_buff *new_iovb;
            if ((new_iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC)) != NULL)
            {
+               NS_SKB_CB(iovb)->buf_type = BUF_NONE;
                skb_queue_tail(&card->iovpool.queue, new_iovb);
                card->iovpool.count++;
            }
@@ -2264,7 +2277,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
 
    if (NS_SKB(iovb)->iovcnt == 1)
    {
-      if (skb->list != &card->sbpool.queue)
+      if (NS_SKB_CB(skb)->buf_type != BUF_SM)
       {
          printk("nicstar%d: Expected a small buffer, and this is not one.\n",
                card->index);
@@ -2278,7 +2291,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
    }
    else /* NS_SKB(iovb)->iovcnt >= 2 */
    {
-      if (skb->list != &card->lbpool.queue)
+      if (NS_SKB_CB(skb)->buf_type != BUF_LG)
       {
          printk("nicstar%d: Expected a large buffer, and this is not one.\n",
                card->index);
@@ -2322,8 +2335,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
          /* skb points to a small buffer */
          if (!atm_charge(vcc, skb->truesize))
          {
-            push_rxbufs(card, BUF_SM, (u32) skb, (u32) virt_to_bus(skb->data),
-                        0, 0);
+            push_rxbufs(card, skb);
             atomic_inc(&vcc->stats->rx_drop);
          }
          else
@@ -2334,7 +2346,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
             skb->destructor = ns_sb_destructor;
 #endif /* NS_USE_DESTRUCTORS */
             ATM_SKB(skb)->vcc = vcc;
-            do_gettimeofday(&skb->stamp);
+           __net_timestamp(skb);
             vcc->push(vcc, skb);
             atomic_inc(&vcc->stats->rx);
          }
@@ -2350,8 +2362,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
         {
             if (!atm_charge(vcc, sb->truesize))
             {
-               push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data),
-                           0, 0);
+               push_rxbufs(card, sb);
                atomic_inc(&vcc->stats->rx_drop);
             }
             else
@@ -2362,21 +2373,19 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
                sb->destructor = ns_sb_destructor;
 #endif /* NS_USE_DESTRUCTORS */
                ATM_SKB(sb)->vcc = vcc;
-               do_gettimeofday(&sb->stamp);
+              __net_timestamp(sb);
                vcc->push(vcc, sb);
                atomic_inc(&vcc->stats->rx);
             }
 
-            push_rxbufs(card, BUF_LG, (u32) skb,
-                          (u32) virt_to_bus(skb->data), 0, 0);
+            push_rxbufs(card, skb);
 
         }
         else                   /* len > NS_SMBUFSIZE, the usual case */
         {
             if (!atm_charge(vcc, skb->truesize))
             {
-               push_rxbufs(card, BUF_LG, (u32) skb,
-                           (u32) virt_to_bus(skb->data), 0, 0);
+               push_rxbufs(card, skb);
                atomic_inc(&vcc->stats->rx_drop);
             }
             else
@@ -2389,13 +2398,12 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
                memcpy(skb->data, sb->data, NS_SMBUFSIZE);
                skb_put(skb, len - NS_SMBUFSIZE);
                ATM_SKB(skb)->vcc = vcc;
-               do_gettimeofday(&skb->stamp);
+              __net_timestamp(skb);
                vcc->push(vcc, skb);
                atomic_inc(&vcc->stats->rx);
             }
 
-            push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data),
-                        0, 0);
+            push_rxbufs(card, sb);
 
          }
         
@@ -2430,6 +2438,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
                   card->hbpool.count++;
                }
             }
+            NS_SKB_CB(hb)->buf_type = BUF_NONE;
         }
         else
          if (--card->hbpool.count < card->hbnr.min)
@@ -2437,6 +2446,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
             struct sk_buff *new_hb;
             if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL)
             {
+               NS_SKB_CB(new_hb)->buf_type = BUF_NONE;
                skb_queue_tail(&card->hbpool.queue, new_hb);
                card->hbpool.count++;
             }
@@ -2444,6 +2454,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
            {
                if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL)
                {
+                  NS_SKB_CB(new_hb)->buf_type = BUF_NONE;
                   skb_queue_tail(&card->hbpool.queue, new_hb);
                   card->hbpool.count++;
                }
@@ -2473,8 +2484,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
             remaining = len - iov->iov_len;
             iov++;
             /* Free the small buffer */
-            push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data),
-                        0, 0);
+            push_rxbufs(card, sb);
 
             /* Copy all large buffers to the huge buffer and free them */
             for (j = 1; j < NS_SKB(iovb)->iovcnt; j++)
@@ -2485,8 +2495,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
                skb_put(hb, tocopy);
                iov++;
                remaining -= tocopy;
-               push_rxbufs(card, BUF_LG, (u32) lb,
-                           (u32) virt_to_bus(lb->data), 0, 0);
+               push_rxbufs(card, lb);
             }
 #ifdef EXTRA_DEBUG
             if (remaining != 0 || hb->len != len)
@@ -2496,7 +2505,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
 #ifdef NS_USE_DESTRUCTORS
             hb->destructor = ns_hb_destructor;
 #endif /* NS_USE_DESTRUCTORS */
-            do_gettimeofday(&hb->stamp);
+           __net_timestamp(hb);
             vcc->push(vcc, hb);
             atomic_inc(&vcc->stats->rx);
          }
@@ -2527,9 +2536,10 @@ static void ns_sb_destructor(struct sk_buff *sb)
       sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
       if (sb == NULL)
          break;
+      NS_SKB_CB(sb)->buf_type = BUF_SM;
       skb_queue_tail(&card->sbpool.queue, sb);
       skb_reserve(sb, NS_AAL0_HEADER);
-      push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0);
+      push_rxbufs(card, sb);
    } while (card->sbfqc < card->sbnr.min);
 }
 
@@ -2550,9 +2560,10 @@ static void ns_lb_destructor(struct sk_buff *lb)
       lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
       if (lb == NULL)
          break;
+      NS_SKB_CB(lb)->buf_type = BUF_LG;
       skb_queue_tail(&card->lbpool.queue, lb);
       skb_reserve(lb, NS_SMBUFSIZE);
-      push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0);
+      push_rxbufs(card, lb);
    } while (card->lbfqc < card->lbnr.min);
 }
 
@@ -2569,6 +2580,7 @@ static void ns_hb_destructor(struct sk_buff *hb)
       hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
       if (hb == NULL)
          break;
+      NS_SKB_CB(hb)->buf_type = BUF_NONE;
       skb_queue_tail(&card->hbpool.queue, hb);
       card->hbpool.count++;
    }
@@ -2577,45 +2589,25 @@ static void ns_hb_destructor(struct sk_buff *hb)
 #endif /* NS_USE_DESTRUCTORS */
 
 
-
 static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb)
 {
-   if (skb->list == &card->sbpool.queue)
-      push_rxbufs(card, BUF_SM, (u32) skb, (u32) virt_to_bus(skb->data), 0, 0);
-   else if (skb->list == &card->lbpool.queue)
-      push_rxbufs(card, BUF_LG, (u32) skb, (u32) virt_to_bus(skb->data), 0, 0);
-   else
-   {
-      printk("nicstar%d: What kind of rx buffer is this?\n", card->index);
-      dev_kfree_skb_any(skb);
-   }
-}
+       struct ns_skb_cb *cb = NS_SKB_CB(skb);
 
+       if (unlikely(cb->buf_type == BUF_NONE)) {
+               printk("nicstar%d: What kind of rx buffer is this?\n", card->index);
+               dev_kfree_skb_any(skb);
+       } else
+               push_rxbufs(card, skb);
+}
 
 
 static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count)
 {
-   struct sk_buff *skb;
-
-   for (; count > 0; count--)
-   {
-      skb = (struct sk_buff *) (iov++)->iov_base;
-      if (skb->list == &card->sbpool.queue)
-         push_rxbufs(card, BUF_SM, (u32) skb, (u32) virt_to_bus(skb->data),
-                    0, 0);
-      else if (skb->list == &card->lbpool.queue)
-         push_rxbufs(card, BUF_LG, (u32) skb, (u32) virt_to_bus(skb->data),
-                    0, 0);
-      else
-      {
-         printk("nicstar%d: What kind of rx buffer is this?\n", card->index);
-         dev_kfree_skb_any(skb);
-      }
-   }
+       while (count-- > 0)
+               recycle_rx_buf(card, (struct sk_buff *) (iov++)->iov_base);
 }
 
 
-
 static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb)
 {
    if (card->iovpool.count < card->iovnr.max)
@@ -2631,7 +2623,7 @@ static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb)
 
 static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb)
 {
-   skb_unlink(sb);
+   skb_unlink(sb, &card->sbpool.queue);
 #ifdef NS_USE_DESTRUCTORS
    if (card->sbfqc < card->sbnr.min)
 #else
@@ -2640,10 +2632,10 @@ static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb)
       struct sk_buff *new_sb;
       if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL)
       {
+         NS_SKB_CB(new_sb)->buf_type = BUF_SM;
          skb_queue_tail(&card->sbpool.queue, new_sb);
          skb_reserve(new_sb, NS_AAL0_HEADER);
-         push_rxbufs(card, BUF_SM, (u32) new_sb,
-                     (u32) virt_to_bus(new_sb->data), 0, 0);
+         push_rxbufs(card, new_sb);
       }
    }
    if (card->sbfqc < card->sbnr.init)
@@ -2652,10 +2644,10 @@ static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb)
       struct sk_buff *new_sb;
       if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL)
       {
+         NS_SKB_CB(new_sb)->buf_type = BUF_SM;
          skb_queue_tail(&card->sbpool.queue, new_sb);
          skb_reserve(new_sb, NS_AAL0_HEADER);
-         push_rxbufs(card, BUF_SM, (u32) new_sb,
-                     (u32) virt_to_bus(new_sb->data), 0, 0);
+         push_rxbufs(card, new_sb);
       }
    }
 }
@@ -2664,7 +2656,7 @@ static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb)
 
 static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb)
 {
-   skb_unlink(lb);
+   skb_unlink(lb, &card->lbpool.queue);
 #ifdef NS_USE_DESTRUCTORS
    if (card->lbfqc < card->lbnr.min)
 #else
@@ -2673,10 +2665,10 @@ static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb)
       struct sk_buff *new_lb;
       if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL)
       {
+         NS_SKB_CB(new_lb)->buf_type = BUF_LG;
          skb_queue_tail(&card->lbpool.queue, new_lb);
          skb_reserve(new_lb, NS_SMBUFSIZE);
-         push_rxbufs(card, BUF_LG, (u32) new_lb,
-                     (u32) virt_to_bus(new_lb->data), 0, 0);
+         push_rxbufs(card, new_lb);
       }
    }
    if (card->lbfqc < card->lbnr.init)
@@ -2685,10 +2677,10 @@ static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb)
       struct sk_buff *new_lb;
       if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL)
       {
+         NS_SKB_CB(new_lb)->buf_type = BUF_LG;
          skb_queue_tail(&card->lbpool.queue, new_lb);
          skb_reserve(new_lb, NS_SMBUFSIZE);
-         push_rxbufs(card, BUF_LG, (u32) new_lb,
-                     (u32) virt_to_bus(new_lb->data), 0, 0);
+         push_rxbufs(card, new_lb);
       }
    }
 }
@@ -2880,9 +2872,10 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg)
                   sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
                   if (sb == NULL)
                      return -ENOMEM;
+                  NS_SKB_CB(sb)->buf_type = BUF_SM;
                   skb_queue_tail(&card->sbpool.queue, sb);
                   skb_reserve(sb, NS_AAL0_HEADER);
-                  push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0);
+                  push_rxbufs(card, sb);
               }
               break;
 
@@ -2894,9 +2887,10 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg)
                   lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
                   if (lb == NULL)
                      return -ENOMEM;
+                  NS_SKB_CB(lb)->buf_type = BUF_LG;
                   skb_queue_tail(&card->lbpool.queue, lb);
                   skb_reserve(lb, NS_SMBUFSIZE);
-                  push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0);
+                  push_rxbufs(card, lb);
               }
               break;
 
@@ -2923,6 +2917,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg)
                   hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
                   if (hb == NULL)
                      return -ENOMEM;
+                  NS_SKB_CB(hb)->buf_type = BUF_NONE;
                   ns_grab_int_lock(card, flags);
                   skb_queue_tail(&card->hbpool.queue, hb);
                   card->hbpool.count++;
@@ -2953,6 +2948,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg)
                   iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL);
                   if (iovb == NULL)
                      return -ENOMEM;
+                  NS_SKB_CB(iovb)->buf_type = BUF_NONE;
                   ns_grab_int_lock(card, flags);
                   skb_queue_tail(&card->iovpool.queue, iovb);
                   card->iovpool.count++;
@@ -2979,17 +2975,12 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg)
 }
 
 
-
 static void which_list(ns_dev *card, struct sk_buff *skb)
 {
-   printk("It's a %s buffer.\n", skb->list == &card->sbpool.queue ?
-          "small" : skb->list == &card->lbpool.queue ? "large" :
-         skb->list == &card->hbpool.queue ? "huge" :
-         skb->list == &card->iovpool.queue ? "iovec" : "unknown");
+       printk("skb buf_type: 0x%08x\n", NS_SKB_CB(skb)->buf_type);
 }
 
 
-
 static void ns_poll(unsigned long arg)
 {
    int i;
index ea83c46c8ba58b1c63eadceb973d52e45ed816f4..5997bcb45b59492486bafb4d951b6171a6a01049 100644 (file)
 
 #define NS_IOREMAP_SIZE 4096
 
-#define BUF_SM 0x00000000      /* These two are used for push_rxbufs() */
-#define BUF_LG 0x00000001       /* CMD, Write_FreeBufQ, LBUF bit */
+/*
+ * BUF_XX distinguish the Rx buffers depending on their (small/large) size.
+ * BUG_SM and BUG_LG are both used by the driver and the device.
+ * BUF_NONE is only used by the driver.
+ */
+#define BUF_SM         0x00000000      /* These two are used for push_rxbufs() */
+#define BUF_LG         0x00000001      /* CMD, Write_FreeBufQ, LBUF bit */
+#define BUF_NONE       0xffffffff      /* Software only: */
 
 #define NS_HBUFSIZE 65568      /* Size of max. AAL5 PDU */
 #define NS_MAX_IOVECS (2 + (65568 - NS_SMBUFSIZE) / \
@@ -684,6 +690,12 @@ enum ns_regs
 /* Device driver structures ***************************************************/
 
 
+struct ns_skb_cb {
+       u32 buf_type;                   /* BUF_SM/BUF_LG/BUF_NONE */
+};
+
+#define NS_SKB_CB(skb) ((struct ns_skb_cb *)((skb)->cb))
+
 typedef struct tsq_info
 {
    void *org;
index a2b236a966e0599285698160e44a56161f94be5a..55959e4d1cb77d3aef5269340fff23241f873d58 100644 (file)
@@ -400,7 +400,7 @@ unsigned long *x;
 EVENT("error code 0x%x/0x%x\n",(here[3] & uPD98401_AAL5_ES) >>
   uPD98401_AAL5_ES_SHIFT,error);
                skb = ((struct rx_buffer_head *) bus_to_virt(here[2]))->skb;
-               do_gettimeofday(&skb->stamp);
+               __net_timestamp(skb);
 #if 0
 printk("[-3..0] 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",((unsigned *) skb->data)[-3],
   ((unsigned *) skb->data)[-2],((unsigned *) skb->data)[-1],
@@ -417,10 +417,12 @@ printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]);
                chan = (here[3] & uPD98401_AAL5_CHAN) >>
                    uPD98401_AAL5_CHAN_SHIFT;
                if (chan < zatm_dev->chans && zatm_dev->rx_map[chan]) {
+                       int pos;
                        vcc = zatm_dev->rx_map[chan];
-                       if (skb == zatm_dev->last_free[ZATM_VCC(vcc)->pool])
-                               zatm_dev->last_free[ZATM_VCC(vcc)->pool] = NULL;
-                       skb_unlink(skb);
+                       pos = ZATM_VCC(vcc)->pool;
+                       if (skb == zatm_dev->last_free[pos])
+                               zatm_dev->last_free[pos] = NULL;
+                       skb_unlink(skb, zatm_dev->pool + pos);
                }
                else {
                        printk(KERN_ERR DEV_LABEL "(itf %d): RX indication "
index ab53832d57e5eff507b8e4552983446641f02d51..17e96698410e43c47464fb6d509cf082b0a0a724 100644 (file)
@@ -156,7 +156,9 @@ static ssize_t driver_unbind(struct device_driver *drv,
                device_release_driver(dev);
                err = count;
        }
-       return err;
+       if (err)
+               return err;
+       return count;
 }
 static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
 
@@ -358,7 +360,7 @@ int bus_add_device(struct device * dev)
        if (bus) {
                pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);
                device_attach(dev);
-               klist_add_tail(&bus->klist_devices, &dev->knode_bus);
+               klist_add_tail(&dev->knode_bus, &bus->klist_devices);
                error = device_add_attrs(bus, dev);
                if (!error) {
                        sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id);
@@ -446,7 +448,7 @@ int bus_add_driver(struct device_driver * drv)
                }
 
                driver_attach(drv);
-               klist_add_tail(&bus->klist_drivers, &drv->knode_bus);
+               klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
                module_add_driver(drv->owner, drv);
 
                driver_add_attrs(bus, drv);
index 0154a1623b2198965be09dbf4bd9552b5525ba4e..d164c32a97ad4e90426a4f1e8a244b8d5f7d93d3 100644 (file)
@@ -299,10 +299,8 @@ static void class_dev_release(struct kobject * kobj)
 
        pr_debug("device class '%s': release.\n", cd->class_id);
 
-       if (cd->devt_attr) {
-               kfree(cd->devt_attr);
-               cd->devt_attr = NULL;
-       }
+       kfree(cd->devt_attr);
+       cd->devt_attr = NULL;
 
        if (cls->release)
                cls->release(cd);
@@ -452,10 +450,29 @@ void class_device_initialize(struct class_device *class_dev)
        INIT_LIST_HEAD(&class_dev->node);
 }
 
+static char *make_class_name(struct class_device *class_dev)
+{
+       char *name;
+       int size;
+
+       size = strlen(class_dev->class->name) +
+               strlen(kobject_name(&class_dev->kobj)) + 2;
+
+       name = kmalloc(size, GFP_KERNEL);
+       if (!name)
+               return ERR_PTR(-ENOMEM);
+
+       strcpy(name, class_dev->class->name);
+       strcat(name, ":");
+       strcat(name, kobject_name(&class_dev->kobj));
+       return name;
+}
+
 int class_device_add(struct class_device *class_dev)
 {
        struct class * parent = NULL;
        struct class_interface * class_intf;
+       char *class_name = NULL;
        int error;
 
        class_dev = class_device_get(class_dev);
@@ -500,9 +517,13 @@ int class_device_add(struct class_device *class_dev)
        }
 
        class_device_add_attrs(class_dev);
-       if (class_dev->dev)
+       if (class_dev->dev) {
+               class_name = make_class_name(class_dev);
                sysfs_create_link(&class_dev->kobj,
                                  &class_dev->dev->kobj, "device");
+               sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
+                                 class_name);
+       }
 
        /* notify any interfaces this device is now here */
        if (parent) {
@@ -519,6 +540,7 @@ int class_device_add(struct class_device *class_dev)
        if (error && parent)
                class_put(parent);
        class_device_put(class_dev);
+       kfree(class_name);
        return error;
 }
 
@@ -584,6 +606,7 @@ void class_device_del(struct class_device *class_dev)
 {
        struct class * parent = class_dev->class;
        struct class_interface * class_intf;
+       char *class_name = NULL;
 
        if (parent) {
                down(&parent->sem);
@@ -594,8 +617,11 @@ void class_device_del(struct class_device *class_dev)
                up(&parent->sem);
        }
 
-       if (class_dev->dev)
+       if (class_dev->dev) {
+               class_name = make_class_name(class_dev);
                sysfs_remove_link(&class_dev->kobj, "device");
+               sysfs_remove_link(&class_dev->dev->kobj, class_name);
+       }
        if (class_dev->devt_attr)
                class_device_remove_file(class_dev, class_dev->devt_attr);
        class_device_remove_attrs(class_dev);
@@ -605,6 +631,7 @@ void class_device_del(struct class_device *class_dev)
 
        if (parent)
                class_put(parent);
+       kfree(class_name);
 }
 
 void class_device_unregister(struct class_device *class_dev)
index efe03a024a5bc39bf958881143d740312c3b09bc..c8a33df007612b1e417744a262ba3fe1026114dd 100644 (file)
@@ -249,7 +249,7 @@ int device_add(struct device *dev)
        if ((error = bus_add_device(dev)))
                goto BusError;
        if (parent)
-               klist_add_tail(&parent->klist_children, &dev->knode_parent);
+               klist_add_tail(&dev->knode_parent, &parent->klist_children);
 
        /* notify platform of device entry */
        if (platform_notify)
index 16323f9cbff08fb066f8d10cda4bb76cfe711564..d5bbce38282fd233f06ef77891257a399be2471e 100644 (file)
@@ -42,7 +42,7 @@ void device_bind_driver(struct device * dev)
 {
        pr_debug("bound device '%s' to driver '%s'\n",
                 dev->bus_id, dev->driver->name);
-       klist_add_tail(&dev->driver->klist_devices, &dev->knode_driver);
+       klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices);
        sysfs_create_link(&dev->driver->kobj, &dev->kobj,
                          kobject_name(&dev->kobj));
        sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver");
index 652281402c923860d449ec7a652ff81fa6903447..5bfa2e9a7c2678efade79213aa5bd203054613b8 100644 (file)
@@ -28,6 +28,7 @@ enum {
        FW_STATUS_DONE,
        FW_STATUS_ABORT,
        FW_STATUS_READY,
+       FW_STATUS_READY_NOHOTPLUG,
 };
 
 static int loading_timeout = 10;       /* In seconds */
@@ -344,7 +345,7 @@ error_kfree:
 
 static int
 fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p,
-                     const char *fw_name, struct device *device)
+                     const char *fw_name, struct device *device, int hotplug)
 {
        struct class_device *class_dev;
        struct firmware_priv *fw_priv;
@@ -376,7 +377,10 @@ fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p,
                goto error_unreg;
        }
 
-       set_bit(FW_STATUS_READY, &fw_priv->status);
+       if (hotplug)
+                set_bit(FW_STATUS_READY, &fw_priv->status);
+        else
+                set_bit(FW_STATUS_READY_NOHOTPLUG, &fw_priv->status);
        *class_dev_p = class_dev;
        goto out;
 
@@ -386,21 +390,9 @@ out:
        return retval;
 }
 
-/**
- * request_firmware: - request firmware to hotplug and wait for it
- * Description:
- *     @firmware will be used to return a firmware image by the name
- *     of @name for device @device.
- *
- *     Should be called from user context where sleeping is allowed.
- *
- *     @name will be use as $FIRMWARE in the hotplug environment and
- *     should be distinctive enough not to be confused with any other
- *     firmware image for this or any other device.
- **/
-int
-request_firmware(const struct firmware **firmware_p, const char *name,
-                struct device *device)
+static int
+_request_firmware(const struct firmware **firmware_p, const char *name,
+                struct device *device, int hotplug)
 {
        struct class_device *class_dev;
        struct firmware_priv *fw_priv;
@@ -419,22 +411,25 @@ request_firmware(const struct firmware **firmware_p, const char *name,
        }
        memset(firmware, 0, sizeof (*firmware));
 
-       retval = fw_setup_class_device(firmware, &class_dev, name, device);
+       retval = fw_setup_class_device(firmware, &class_dev, name, device,
+               hotplug);
        if (retval)
                goto error_kfree_fw;
 
        fw_priv = class_get_devdata(class_dev);
 
-       if (loading_timeout > 0) {
-               fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
-               add_timer(&fw_priv->timeout);
-       }
-
-       kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
-       wait_for_completion(&fw_priv->completion);
-       set_bit(FW_STATUS_DONE, &fw_priv->status);
+       if (hotplug) {
+               if (loading_timeout > 0) {
+                       fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
+                       add_timer(&fw_priv->timeout);
+               }
 
-       del_timer_sync(&fw_priv->timeout);
+               kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
+               wait_for_completion(&fw_priv->completion);
+               set_bit(FW_STATUS_DONE, &fw_priv->status);
+               del_timer_sync(&fw_priv->timeout);
+       } else
+               wait_for_completion(&fw_priv->completion);
 
        down(&fw_lock);
        if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) {
@@ -454,6 +449,26 @@ out:
        return retval;
 }
 
+/**
+ * request_firmware: - request firmware to hotplug and wait for it
+ * Description:
+ *      @firmware will be used to return a firmware image by the name
+ *      of @name for device @device.
+ *
+ *      Should be called from user context where sleeping is allowed.
+ *
+ *      @name will be use as $FIRMWARE in the hotplug environment and
+ *      should be distinctive enough not to be confused with any other
+ *      firmware image for this or any other device.
+ **/
+int
+request_firmware(const struct firmware **firmware_p, const char *name,
+                 struct device *device)
+{
+        int hotplug = 1;
+        return _request_firmware(firmware_p, name, device, hotplug);
+}
+
 /**
  * release_firmware: - release the resource associated with a firmware image
  **/
@@ -491,6 +506,7 @@ struct firmware_work {
        struct device *device;
        void *context;
        void (*cont)(const struct firmware *fw, void *context);
+       int hotplug;
 };
 
 static int
@@ -503,7 +519,8 @@ request_firmware_work_func(void *arg)
                return 0;
        }
        daemonize("%s/%s", "firmware", fw_work->name);
-       request_firmware(&fw, fw_work->name, fw_work->device);
+       _request_firmware(&fw, fw_work->name, fw_work->device,
+               fw_work->hotplug);
        fw_work->cont(fw, fw_work->context);
        release_firmware(fw);
        module_put(fw_work->module);
@@ -518,6 +535,9 @@ request_firmware_work_func(void *arg)
  *     Asynchronous variant of request_firmware() for contexts where
  *     it is not possible to sleep.
  *
+ *      @hotplug invokes hotplug event to copy the firmware image if this flag
+ *      is non-zero else the firmware copy must be done manually.
+ *
  *     @cont will be called asynchronously when the firmware request is over.
  *
  *     @context will be passed over to @cont.
@@ -527,7 +547,7 @@ request_firmware_work_func(void *arg)
  **/
 int
 request_firmware_nowait(
-       struct module *module,
+       struct module *module, int hotplug,
        const char *name, struct device *device, void *context,
        void (*cont)(const struct firmware *fw, void *context))
 {
@@ -548,6 +568,7 @@ request_firmware_nowait(
                .device = device,
                .context = context,
                .cont = cont,
+               .hotplug = hotplug,
        };
 
        ret = kernel_thread(request_firmware_work_func, fw_work,
index 904b27caf697df2c0d14d1cab426212bad27bb25..16c513aa4d4877afa7522eedc7e695568648cbf7 100644 (file)
@@ -39,13 +39,25 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf)
        int n;
        int nid = dev->id;
        struct sysinfo i;
+       struct page_state ps;
        unsigned long inactive;
        unsigned long active;
        unsigned long free;
 
        si_meminfo_node(&i, nid);
+       get_page_state_node(&ps, nid);
        __get_zone_counts(&active, &inactive, &free, NODE_DATA(nid));
 
+       /* Check for negative values in these approximate counters */
+       if ((long)ps.nr_dirty < 0)
+               ps.nr_dirty = 0;
+       if ((long)ps.nr_writeback < 0)
+               ps.nr_writeback = 0;
+       if ((long)ps.nr_mapped < 0)
+               ps.nr_mapped = 0;
+       if ((long)ps.nr_slab < 0)
+               ps.nr_slab = 0;
+
        n = sprintf(buf, "\n"
                       "Node %d MemTotal:     %8lu kB\n"
                       "Node %d MemFree:      %8lu kB\n"
@@ -55,7 +67,11 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf)
                       "Node %d HighTotal:    %8lu kB\n"
                       "Node %d HighFree:     %8lu kB\n"
                       "Node %d LowTotal:     %8lu kB\n"
-                      "Node %d LowFree:      %8lu kB\n",
+                      "Node %d LowFree:      %8lu kB\n"
+                      "Node %d Dirty:        %8lu kB\n"
+                      "Node %d Writeback:    %8lu kB\n"
+                      "Node %d Mapped:       %8lu kB\n"
+                      "Node %d Slab:         %8lu kB\n",
                       nid, K(i.totalram),
                       nid, K(i.freeram),
                       nid, K(i.totalram - i.freeram),
@@ -64,7 +80,11 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf)
                       nid, K(i.totalhigh),
                       nid, K(i.freehigh),
                       nid, K(i.totalram - i.totalhigh),
-                      nid, K(i.freeram - i.freehigh));
+                      nid, K(i.freeram - i.freehigh),
+                      nid, K(ps.nr_dirty),
+                      nid, K(ps.nr_writeback),
+                      nid, K(ps.nr_mapped),
+                      nid, K(ps.nr_slab));
        n += hugetlb_report_node_meminfo(nid, buf + n);
        return n;
 }
index bdd96b03b8857a14367535bf408224b1eb939503..0a7aa07b9a2a600cc9b52992b8e0f0d44216af17 100644 (file)
@@ -26,11 +26,11 @@ int resume_device(struct device * dev)
 
        down(&dev->sem);
        if (dev->power.pm_parent
-                       && dev->power.pm_parent->power.power_state) {
+                       && dev->power.pm_parent->power.power_state.event) {
                dev_err(dev, "PM: resume from %d, parent %s still %d\n",
-                       dev->power.power_state,
+                       dev->power.power_state.event,
                        dev->power.pm_parent->bus_id,
-                       dev->power.pm_parent->power.power_state);
+                       dev->power.pm_parent->power.power_state.event);
        }
        if (dev->bus && dev->bus->resume) {
                dev_dbg(dev,"resuming\n");
@@ -54,7 +54,7 @@ void dpm_resume(void)
                list_add_tail(entry, &dpm_active);
 
                up(&dpm_list_sem);
-               if (!dev->power.prev_state)
+               if (!dev->power.prev_state.event)
                        resume_device(dev);
                down(&dpm_list_sem);
                put_device(dev);
index 325962d8019153d28316399ab7b5a8da3887293e..e8f0519f5dfa88566e3e49d34d0e637180793a7c 100644 (file)
 static void runtime_resume(struct device * dev)
 {
        dev_dbg(dev, "resuming\n");
-       if (!dev->power.power_state)
+       if (!dev->power.power_state.event)
                return;
        if (!resume_device(dev))
-               dev->power.power_state = 0;
+               dev->power.power_state = PMSG_ON;
 }
 
 
@@ -49,10 +49,10 @@ int dpm_runtime_suspend(struct device * dev, pm_message_t state)
        int error = 0;
 
        down(&dpm_sem);
-       if (dev->power.power_state == state)
+       if (dev->power.power_state.event == state.event)
                goto Done;
 
-       if (dev->power.power_state)
+       if (dev->power.power_state.event)
                runtime_resume(dev);
 
        if (!(error = suspend_device(dev, state)))
index 2ccee3763acfae23a3d1de899179dd5ac0ca9419..50501764d0508a6493256380df820eb35b8c96e1 100644 (file)
@@ -40,22 +40,22 @@ int suspend_device(struct device * dev, pm_message_t state)
        int error = 0;
 
        down(&dev->sem);
-       if (dev->power.power_state) {
+       if (dev->power.power_state.event) {
                dev_dbg(dev, "PM: suspend %d-->%d\n",
-                       dev->power.power_state, state);
+                       dev->power.power_state.event, state.event);
        }
        if (dev->power.pm_parent
-                       && dev->power.pm_parent->power.power_state) {
+                       && dev->power.pm_parent->power.power_state.event) {
                dev_err(dev,
                        "PM: suspend %d->%d, parent %s already %d\n",
-                       dev->power.power_state, state,
+                       dev->power.power_state.event, state.event,
                        dev->power.pm_parent->bus_id,
-                       dev->power.pm_parent->power.power_state);
+                       dev->power.pm_parent->power.power_state.event);
        }
 
        dev->power.prev_state = dev->power.power_state;
 
-       if (dev->bus && dev->bus->suspend && !dev->power.power_state) {
+       if (dev->bus && dev->bus->suspend && !dev->power.power_state.event) {
                dev_dbg(dev, "suspending\n");
                error = dev->bus->suspend(dev, state);
        }
index f82b3df9545f68b66cd1866862bc665a1f7e00c5..8d04fb435c176ebc92f89793cb5998d05721694b 100644 (file)
 
 static ssize_t state_show(struct device * dev, struct device_attribute *attr, char * buf)
 {
-       return sprintf(buf, "%u\n", dev->power.power_state);
+       return sprintf(buf, "%u\n", dev->power.power_state.event);
 }
 
 static ssize_t state_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t n)
 {
-       u32 state;
+       pm_message_t state;
        char * rest;
        int error = 0;
 
-       state = simple_strtoul(buf, &rest, 10);
+       state.event = simple_strtoul(buf, &rest, 10);
        if (*rest)
                return -EINVAL;
-       if (state)
+       if (state.event)
                error = dpm_runtime_suspend(dev, state);
        else
                dpm_runtime_resume(dev);
index 214b96435409e139ae730be68de1439b569cae1d..3431eb6004c3287f6c0be52ddcb75d13d6037f0e 100644 (file)
@@ -288,6 +288,27 @@ void sysdev_shutdown(void)
        up(&sysdev_drivers_lock);
 }
 
+static void __sysdev_resume(struct sys_device *dev)
+{
+       struct sysdev_class *cls = dev->cls;
+       struct sysdev_driver *drv;
+
+       /* First, call the class-specific one */
+       if (cls->resume)
+               cls->resume(dev);
+
+       /* Call auxillary drivers next. */
+       list_for_each_entry(drv, &cls->drivers, entry) {
+               if (drv->resume)
+                       drv->resume(dev);
+       }
+
+       /* Call global drivers. */
+       list_for_each_entry(drv, &sysdev_drivers, entry) {
+               if (drv->resume)
+                       drv->resume(dev);
+       }
+}
 
 /**
  *     sysdev_suspend - Suspend all system devices.
@@ -305,38 +326,93 @@ void sysdev_shutdown(void)
 int sysdev_suspend(pm_message_t state)
 {
        struct sysdev_class * cls;
+       struct sys_device *sysdev, *err_dev;
+       struct sysdev_driver *drv, *err_drv;
+       int ret;
 
        pr_debug("Suspending System Devices\n");
 
        list_for_each_entry_reverse(cls, &system_subsys.kset.list,
                                    kset.kobj.entry) {
-               struct sys_device * sysdev;
 
                pr_debug("Suspending type '%s':\n",
                         kobject_name(&cls->kset.kobj));
 
                list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
-                       struct sysdev_driver * drv;
                        pr_debug(" %s\n", kobject_name(&sysdev->kobj));
 
                        /* Call global drivers first. */
                        list_for_each_entry(drv, &sysdev_drivers, entry) {
-                               if (drv->suspend)
-                                       drv->suspend(sysdev, state);
+                               if (drv->suspend) {
+                                       ret = drv->suspend(sysdev, state);
+                                       if (ret)
+                                               goto gbl_driver;
+                               }
                        }
 
                        /* Call auxillary drivers next. */
                        list_for_each_entry(drv, &cls->drivers, entry) {
-                               if (drv->suspend)
-                                       drv->suspend(sysdev, state);
+                               if (drv->suspend) {
+                                       ret = drv->suspend(sysdev, state);
+                                       if (ret)
+                                               goto aux_driver;
+                               }
                        }
 
                        /* Now call the generic one */
-                       if (cls->suspend)
-                               cls->suspend(sysdev, state);
+                       if (cls->suspend) {
+                               ret = cls->suspend(sysdev, state);
+                               if (ret)
+                                       goto cls_driver;
+                       }
                }
        }
        return 0;
+       /* resume current sysdev */
+cls_driver:
+       drv = NULL;
+       printk(KERN_ERR "Class suspend failed for %s\n",
+               kobject_name(&sysdev->kobj));
+
+aux_driver:
+       if (drv)
+               printk(KERN_ERR "Class driver suspend failed for %s\n",
+                               kobject_name(&sysdev->kobj));
+       list_for_each_entry(err_drv, &cls->drivers, entry) {
+               if (err_drv == drv)
+                       break;
+               if (err_drv->resume)
+                       err_drv->resume(sysdev);
+       }
+       drv = NULL;
+
+gbl_driver:
+       if (drv)
+               printk(KERN_ERR "sysdev driver suspend failed for %s\n",
+                               kobject_name(&sysdev->kobj));
+       list_for_each_entry(err_drv, &sysdev_drivers, entry) {
+               if (err_drv == drv)
+                       break;
+               if (err_drv->resume)
+                       err_drv->resume(sysdev);
+       }
+       /* resume other sysdevs in current class */
+       list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
+               if (err_dev == sysdev)
+                       break;
+               pr_debug(" %s\n", kobject_name(&err_dev->kobj));
+               __sysdev_resume(err_dev);
+       }
+
+       /* resume other classes */
+       list_for_each_entry_continue(cls, &system_subsys.kset.list,
+                                       kset.kobj.entry) {
+               list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
+                       pr_debug(" %s\n", kobject_name(&err_dev->kobj));
+                       __sysdev_resume(err_dev);
+               }
+       }
+       return ret;
 }
 
 
@@ -362,25 +438,9 @@ int sysdev_resume(void)
                         kobject_name(&cls->kset.kobj));
 
                list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
-                       struct sysdev_driver * drv;
                        pr_debug(" %s\n", kobject_name(&sysdev->kobj));
 
-                       /* First, call the class-specific one */
-                       if (cls->resume)
-                               cls->resume(sysdev);
-
-                       /* Call auxillary drivers next. */
-                       list_for_each_entry(drv, &cls->drivers, entry) {
-                               if (drv->resume)
-                                       drv->resume(sysdev);
-                       }
-
-                       /* Call global drivers. */
-                       list_for_each_entry(drv, &sysdev_drivers, entry) {
-                               if (drv->resume)
-                                       drv->resume(sysdev);
-                       }
-
+                       __sysdev_resume(sysdev);
                }
        }
        return 0;
index b594768b0241f3d198d802ada4d192b356677310..51b0af1cebee15f0406ceaf4517538bb9a39edb3 100644 (file)
@@ -6,7 +6,7 @@ menu "Block devices"
 
 config BLK_DEV_FD
        tristate "Normal floppy disk support"
-       depends on (!ARCH_S390 && !M68K && !IA64 && !UML && !ARM) || Q40 || (SUN3X && BROKEN) || ARCH_RPC || ARCH_EBSA285
+       depends on ARCH_MAY_HAVE_PC_FDC
        ---help---
          If you want to use the floppy disk drive(s) of your PC under Linux,
          say Y. Information about this driver, especially important for IBM
@@ -408,54 +408,12 @@ config BLK_DEV_INITRD
          "real" root file system, etc. See <file:Documentation/initrd.txt>
          for details.
 
-config INITRAMFS_SOURCE
-       string "Initramfs source file(s)"
-       default ""
-       help
-         This can be either a single cpio archive with a .cpio suffix or a
-         space-separated list of directories and files for building the
-         initramfs image.  A cpio archive should contain a filesystem archive
-         to be used as an initramfs image.  Directories should contain a
-         filesystem layout to be included in the initramfs image.  Files
-         should contain entries according to the format described by the
-         "usr/gen_init_cpio" program in the kernel tree.
-
-         When multiple directories and files are specified then the
-         initramfs image will be the aggregate of all of them.
-
-         See <file:Documentation/early-userspace/README for more details.
-
-         If you are not sure, leave it blank.
-
-config INITRAMFS_ROOT_UID
-       int "User ID to map to 0 (user root)"
-       depends on INITRAMFS_SOURCE!=""
-       default "0"
-       help
-         This setting is only meaningful if the INITRAMFS_SOURCE is
-         contains a directory.  Setting this user ID (UID) to something
-         other than "0" will cause all files owned by that UID to be
-         owned by user root in the initial ramdisk image.
-
-         If you are not sure, leave it set to "0".
-
-config INITRAMFS_ROOT_GID
-       int "Group ID to map to 0 (group root)"
-       depends on INITRAMFS_SOURCE!=""
-       default "0"
-       help
-         This setting is only meaningful if the INITRAMFS_SOURCE is
-         contains a directory.  Setting this group ID (GID) to something
-         other than "0" will cause all files owned by that GID to be
-         owned by group root in the initial ramdisk image.
-
-         If you are not sure, leave it set to "0".
 
 #XXX - it makes sense to enable this only for 32-bit subarch's, not for x86_64
 #for instance.
 config LBD
        bool "Support for Large Block Devices"
-       depends on X86 || MIPS32 || PPC32 || ARCH_S390_31 || SUPERH || UML
+       depends on X86 || (MIPS && 32BIT) || PPC32 || ARCH_S390_31 || SUPERH || UML
        help
          Say Y here if you want to attach large (bigger than 2TB) discs to
          your machine, or if you want to have a raid or loopback device
index 6e231c5a119958dd3549e5d825f4706f9d04f9ec..ded33ba31accfccf0df29072903cad7493447470 100644 (file)
@@ -35,7 +35,7 @@ aoedev_newdev(ulong nframes)
        struct aoedev *d;
        struct frame *f, *e;
 
-       d = kcalloc(1, sizeof *d, GFP_ATOMIC);
+       d = kzalloc(sizeof *d, GFP_ATOMIC);
        if (d == NULL)
                return NULL;
        f = kcalloc(nframes, sizeof *f, GFP_ATOMIC);
index 9e6f51c528b094684c2b709c55be738c3d361225..4be976940f6971f28bc03b18bab09312c0be9957 100644 (file)
@@ -120,7 +120,7 @@ aoenet_xmit(struct sk_buff *sl)
  * (1) len doesn't include the header by default.  I want this. 
  */
 static int
-aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt)
+aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, struct net_device *orig_dev)
 {
        struct aoe_hdr *h;
        u32 n;
index cd056e7e64ec15d5cf81f16068623e29e07ad187..30c0903c7cddfdd46dbdd0de9c8e999c1ed7f349 100644 (file)
@@ -2260,8 +2260,6 @@ static void cfq_put_cfqd(struct cfq_data *cfqd)
        if (!atomic_dec_and_test(&cfqd->ref))
                return;
 
-       blk_put_queue(q);
-
        cfq_shutdown_timer_wq(cfqd);
        q->elevator->elevator_data = NULL;
 
@@ -2318,7 +2316,6 @@ static int cfq_init_queue(request_queue_t *q, elevator_t *e)
        e->elevator_data = cfqd;
 
        cfqd->queue = q;
-       atomic_inc(&q->refcnt);
 
        cfqd->max_queued = q->nr_requests / 4;
        q->nr_batching = cfq_queued;
index 5be6f998d8c56e0b2f1134624f115c89783a65e3..3d4261c39f16d2542b9dc22c1cc077ed8bc07c1f 100644 (file)
@@ -57,9 +57,11 @@ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info)
        mode = strsep(&cmsp, "-");
 
        if (mode == NULL || strcmp(mode, "cbc") == 0)
-               tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_CBC);
+               tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_CBC |
+                                              CRYPTO_TFM_REQ_MAY_SLEEP);
        else if (strcmp(mode, "ecb") == 0)
-               tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_ECB);
+               tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_ECB |
+                                              CRYPTO_TFM_REQ_MAY_SLEEP);
        if (tfm == NULL)
                return -EINVAL;
 
index ff5201e021534693987f30597817ef7cdb2de317..24594c57c3230e5a095eb10ddb282137ed9161ba 100644 (file)
@@ -507,18 +507,12 @@ static int deadline_dispatch_requests(struct deadline_data *dd)
        const int reads = !list_empty(&dd->fifo_list[READ]);
        const int writes = !list_empty(&dd->fifo_list[WRITE]);
        struct deadline_rq *drq;
-       int data_dir, other_dir;
+       int data_dir;
 
        /*
         * batches are currently reads XOR writes
         */
-       drq = NULL;
-
-       if (dd->next_drq[READ])
-               drq = dd->next_drq[READ];
-
-       if (dd->next_drq[WRITE])
-               drq = dd->next_drq[WRITE];
+       drq = dd->next_drq[WRITE] ? : dd->next_drq[READ];
 
        if (drq) {
                /* we have a "next request" */
@@ -544,7 +538,6 @@ static int deadline_dispatch_requests(struct deadline_data *dd)
                        goto dispatch_writes;
 
                data_dir = READ;
-               other_dir = WRITE;
 
                goto dispatch_find_request;
        }
@@ -560,7 +553,6 @@ dispatch_writes:
                dd->starved = 0;
 
                data_dir = WRITE;
-               other_dir = READ;
 
                goto dispatch_find_request;
        }
index f0c1084b840fd9fceb465521b1bb8cbbc7198529..888dad5eef34994fad9718223f31a1fc8513866f 100644 (file)
@@ -493,6 +493,8 @@ static struct floppy_struct user_params[N_DRIVE];
 
 static sector_t floppy_sizes[256];
 
+static char floppy_device_name[] = "floppy";
+
 /*
  * The driver is trying to determine the correct media format
  * while probing is set. rw_interrupt() clears it after a
@@ -4191,18 +4193,24 @@ static int __init floppy_setup(char *str)
 
 static int have_no_fdc = -ENODEV;
 
+static ssize_t floppy_cmos_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct platform_device *p;
+       int drive;
+
+       p = container_of(dev, struct platform_device,dev);
+       drive = p->id;
+       return sprintf(buf, "%X\n", UDP->cmos);
+}
+DEVICE_ATTR(cmos,S_IRUGO,floppy_cmos_show,NULL);
+
 static void floppy_device_release(struct device *dev)
 {
        complete(&device_release);
 }
 
-static struct platform_device floppy_device = {
-       .name           = "floppy",
-       .id             = 0,
-       .dev            = {
-                       .release = floppy_device_release,
-                       }
-};
+static struct platform_device floppy_device[N_DRIVE];
 
 static struct kobject *floppy_find(dev_t dev, int *part, void *data)
 {
@@ -4370,20 +4378,26 @@ static int __init floppy_init(void)
                goto out_flush_work;
        }
 
-       err = platform_device_register(&floppy_device);
-       if (err)
-               goto out_flush_work;
-
        for (drive = 0; drive < N_DRIVE; drive++) {
                if (!(allowed_drive_mask & (1 << drive)))
                        continue;
                if (fdc_state[FDC(drive)].version == FDC_NONE)
                        continue;
+
+               floppy_device[drive].name = floppy_device_name;
+               floppy_device[drive].id = drive;
+               floppy_device[drive].dev.release = floppy_device_release;
+
+               err = platform_device_register(&floppy_device[drive]);
+               if (err)
+                       goto out_flush_work;
+
+               device_create_file(&floppy_device[drive].dev,&dev_attr_cmos);
                /* to be cleaned up... */
                disks[drive]->private_data = (void *)(long)drive;
                disks[drive]->queue = floppy_queue;
                disks[drive]->flags |= GENHD_FL_REMOVABLE;
-               disks[drive]->driverfs_dev = &floppy_device.dev;
+               disks[drive]->driverfs_dev = &floppy_device[drive].dev;
                add_disk(disks[drive]);
        }
 
@@ -4603,10 +4617,11 @@ void cleanup_module(void)
                    fdc_state[FDC(drive)].version != FDC_NONE) {
                        del_gendisk(disks[drive]);
                        unregister_devfs_entries(drive);
+                       device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
+                       platform_device_unregister(&floppy_device[drive]);
                }
                put_disk(disks[drive]);
        }
-       platform_device_unregister(&floppy_device);
        devfs_remove("floppy");
 
        del_timer_sync(&fd_timeout);
index 47fd3659a061786967d2d150b5e9ba3212057bc9..d42840cc0d1dfcd0fad18fca25041c04ac69661a 100644 (file)
@@ -45,7 +45,7 @@ int get_blkdev_list(char *p, int used)
        struct blk_major_name *n;
        int i, len;
 
-       len = sprintf(p, "\nBlock devices:\n");
+       len = snprintf(p, (PAGE_SIZE-used), "\nBlock devices:\n");
 
        down(&block_subsys_sem);
        for (i = 0; i < ARRAY_SIZE(major_names); i++) {
index 0c7599563b651448a800eb4d19ccd330bcb4edee..483d71b10cf9307364f86cfcd244da6c2850ef96 100644 (file)
@@ -235,8 +235,8 @@ void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn)
         * set defaults
         */
        q->nr_requests = BLKDEV_MAX_RQ;
-       q->max_phys_segments = MAX_PHYS_SEGMENTS;
-       q->max_hw_segments = MAX_HW_SEGMENTS;
+       blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
+       blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
        q->make_request_fn = mfn;
        q->backing_dev_info.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
        q->backing_dev_info.state = 0;
index 46e56a25d2c8875966462bef4c53a225ac572090..e46ecd23b3ac74d6854c2839484e392326a71e6e 100644 (file)
@@ -776,7 +776,7 @@ static int viodasd_remove(struct vio_dev *vdev)
  */
 static struct vio_device_id viodasd_device_table[] __devinitdata = {
        { "viodasd", "" },
-       { 0, }
+       { "", "" }
 };
 
 MODULE_DEVICE_TABLE(vio, viodasd_device_table);
index c42d7e6ac1c5858c851096f38ff6afe65185ecc4..1e9db0156ea7d5e574f62cf08283fd5bd19f45f3 100644 (file)
@@ -158,7 +158,7 @@ static int bfusb_send_bulk(struct bfusb *bfusb, struct sk_buff *skb)
        if (err) {
                BT_ERR("%s bulk tx submit failed urb %p err %d", 
                                        bfusb->hdev->name, urb, err);
-               skb_unlink(skb);
+               skb_unlink(skb, &bfusb->pending_q);
                usb_free_urb(urb);
        } else
                atomic_inc(&bfusb->pending_tx);
@@ -212,7 +212,7 @@ static void bfusb_tx_complete(struct urb *urb, struct pt_regs *regs)
 
        read_lock(&bfusb->lock);
 
-       skb_unlink(skb);
+       skb_unlink(skb, &bfusb->pending_q);
        skb_queue_tail(&bfusb->completed_q, skb);
 
        bfusb_tx_wakeup(bfusb);
@@ -253,7 +253,7 @@ static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb)
        if (err) {
                BT_ERR("%s bulk rx submit failed urb %p err %d",
                                        bfusb->hdev->name, urb, err);
-               skb_unlink(skb);
+               skb_unlink(skb, &bfusb->pending_q);
                kfree_skb(skb);
                usb_free_urb(urb);
        }
@@ -330,7 +330,7 @@ static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *
                }
 
                skb->dev = (void *) bfusb->hdev;
-               skb->pkt_type = pkt_type;
+               bt_cb(skb)->pkt_type = pkt_type;
 
                bfusb->reassembly = skb;
        } else {
@@ -398,7 +398,7 @@ static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs)
                buf   += len;
        }
 
-       skb_unlink(skb);
+       skb_unlink(skb, &bfusb->pending_q);
        kfree_skb(skb);
 
        bfusb_rx_submit(bfusb, urb);
@@ -485,7 +485,7 @@ static int bfusb_send_frame(struct sk_buff *skb)
        unsigned char buf[3];
        int sent = 0, size, count;
 
-       BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, skb->pkt_type, skb->len);
+       BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, bt_cb(skb)->pkt_type, skb->len);
 
        if (!hdev) {
                BT_ERR("Frame for unknown HCI device (hdev=NULL)");
@@ -497,7 +497,7 @@ static int bfusb_send_frame(struct sk_buff *skb)
 
        bfusb = (struct bfusb *) hdev->driver_data;
 
-       switch (skb->pkt_type) {
+       switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
                hdev->stat.cmd_tx++;
                break;
@@ -510,7 +510,7 @@ static int bfusb_send_frame(struct sk_buff *skb)
        };
 
        /* Prepend skb with frame type */
-       memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
+       memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
 
        count = skb->len;
 
index bd2ec7e284cc790db66922cef1335b2479320286..26fe9c0e1d20e4c1ef51c47428cf5672ae5db56c 100644 (file)
@@ -270,7 +270,7 @@ static void bluecard_write_wakeup(bluecard_info_t *info)
                if (!(skb = skb_dequeue(&(info->txq))))
                        break;
 
-               if (skb->pkt_type & 0x80) {
+               if (bt_cb(skb)->pkt_type & 0x80) {
                        /* Disable RTS */
                        info->ctrl_reg |= REG_CONTROL_RTS;
                        outb(info->ctrl_reg, iobase + REG_CONTROL);
@@ -288,13 +288,13 @@ static void bluecard_write_wakeup(bluecard_info_t *info)
                /* Mark the buffer as dirty */
                clear_bit(ready_bit, &(info->tx_state));
 
-               if (skb->pkt_type & 0x80) {
+               if (bt_cb(skb)->pkt_type & 0x80) {
                        DECLARE_WAIT_QUEUE_HEAD(wq);
                        DEFINE_WAIT(wait);
 
                        unsigned char baud_reg;
 
-                       switch (skb->pkt_type) {
+                       switch (bt_cb(skb)->pkt_type) {
                        case PKT_BAUD_RATE_460800:
                                baud_reg = REG_CONTROL_BAUD_RATE_460800;
                                break;
@@ -410,9 +410,9 @@ static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
                if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
 
                        info->rx_skb->dev = (void *) info->hdev;
-                       info->rx_skb->pkt_type = buf[i];
+                       bt_cb(info->rx_skb)->pkt_type = buf[i];
 
-                       switch (info->rx_skb->pkt_type) {
+                       switch (bt_cb(info->rx_skb)->pkt_type) {
 
                        case 0x00:
                                /* init packet */
@@ -444,7 +444,7 @@ static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
 
                        default:
                                /* unknown packet */
-                               BT_ERR("Unknown HCI packet with type 0x%02x received", info->rx_skb->pkt_type);
+                               BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
                                info->hdev->stat.err_rx++;
 
                                kfree_skb(info->rx_skb);
@@ -586,21 +586,21 @@ static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
        switch (baud) {
        case 460800:
                cmd[4] = 0x00;
-               skb->pkt_type = PKT_BAUD_RATE_460800;
+               bt_cb(skb)->pkt_type = PKT_BAUD_RATE_460800;
                break;
        case 230400:
                cmd[4] = 0x01;
-               skb->pkt_type = PKT_BAUD_RATE_230400;
+               bt_cb(skb)->pkt_type = PKT_BAUD_RATE_230400;
                break;
        case 115200:
                cmd[4] = 0x02;
-               skb->pkt_type = PKT_BAUD_RATE_115200;
+               bt_cb(skb)->pkt_type = PKT_BAUD_RATE_115200;
                break;
        case 57600:
                /* Fall through... */
        default:
                cmd[4] = 0x03;
-               skb->pkt_type = PKT_BAUD_RATE_57600;
+               bt_cb(skb)->pkt_type = PKT_BAUD_RATE_57600;
                break;
        }
 
@@ -680,7 +680,7 @@ static int bluecard_hci_send_frame(struct sk_buff *skb)
 
        info = (bluecard_info_t *)(hdev->driver_data);
 
-       switch (skb->pkt_type) {
+       switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
                hdev->stat.cmd_tx++;
                break;
@@ -693,7 +693,7 @@ static int bluecard_hci_send_frame(struct sk_buff *skb)
        };
 
        /* Prepend skb with frame type */
-       memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
+       memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
        skb_queue_tail(&(info->txq), skb);
 
        bluecard_write_wakeup(info);
index f696da6f417b6439cae905488d1affff6a9378b4..a1bf8f066c888c227e546d982ae63a0978ef8e7f 100644 (file)
@@ -105,7 +105,7 @@ static void bpa10x_recv_bulk(struct bpa10x_data *data, unsigned char *buf, int c
                        if (skb) {
                                memcpy(skb_put(skb, len), buf, len);
                                skb->dev = (void *) data->hdev;
-                               skb->pkt_type = HCI_ACLDATA_PKT;
+                               bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
                                hci_recv_frame(skb);
                        }
                        break;
@@ -117,7 +117,7 @@ static void bpa10x_recv_bulk(struct bpa10x_data *data, unsigned char *buf, int c
                        if (skb) {
                                memcpy(skb_put(skb, len), buf, len);
                                skb->dev = (void *) data->hdev;
-                               skb->pkt_type = HCI_SCODATA_PKT;
+                               bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
                                hci_recv_frame(skb);
                        }
                        break;
@@ -129,7 +129,7 @@ static void bpa10x_recv_bulk(struct bpa10x_data *data, unsigned char *buf, int c
                        if (skb) {
                                memcpy(skb_put(skb, len), buf, len);
                                skb->dev = (void *) data->hdev;
-                               skb->pkt_type = HCI_VENDOR_PKT;
+                               bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
                                hci_recv_frame(skb);
                        }
                        break;
@@ -190,7 +190,7 @@ static int bpa10x_recv_event(struct bpa10x_data *data, unsigned char *buf, int s
                }
 
                skb->dev = (void *) data->hdev;
-               skb->pkt_type = pkt_type;
+               bt_cb(skb)->pkt_type = pkt_type;
 
                memcpy(skb_put(skb, size), buf, size);
 
@@ -307,7 +307,8 @@ unlock:
        read_unlock(&data->lock);
 }
 
-static inline struct urb *bpa10x_alloc_urb(struct usb_device *udev, unsigned int pipe, size_t size, int flags, void *data)
+static inline struct urb *bpa10x_alloc_urb(struct usb_device *udev, unsigned int pipe,
+                                       size_t size, unsigned int __nocast flags, void *data)
 {
        struct urb *urb;
        struct usb_ctrlrequest *cr;
@@ -487,7 +488,7 @@ static int bpa10x_send_frame(struct sk_buff *skb)
        struct hci_dev *hdev = (struct hci_dev *) skb->dev;
        struct bpa10x_data *data;
 
-       BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, skb->pkt_type, skb->len);
+       BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, bt_cb(skb)->pkt_type, skb->len);
 
        if (!hdev) {
                BT_ERR("Frame for unknown HCI device");
@@ -500,9 +501,9 @@ static int bpa10x_send_frame(struct sk_buff *skb)
        data = hdev->driver_data;
 
        /* Prepend skb with frame type */
-       memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
+       memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
 
-       switch (skb->pkt_type) {
+       switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
                hdev->stat.cmd_tx++;
                skb_queue_tail(&data->cmd_queue, skb);
index adf1750ea58d653a93fa71d1722412cf770912e9..2e0338d80f32c1db8ba8e2f1a4e524e08298aeb6 100644 (file)
@@ -259,11 +259,11 @@ static void bt3c_receive(bt3c_info_t *info)
                if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
 
                        info->rx_skb->dev = (void *) info->hdev;
-                       info->rx_skb->pkt_type = inb(iobase + DATA_L);
+                       bt_cb(info->rx_skb)->pkt_type = inb(iobase + DATA_L);
                        inb(iobase + DATA_H);
-                       //printk("bt3c: PACKET_TYPE=%02x\n", info->rx_skb->pkt_type);
+                       //printk("bt3c: PACKET_TYPE=%02x\n", bt_cb(info->rx_skb)->pkt_type);
 
-                       switch (info->rx_skb->pkt_type) {
+                       switch (bt_cb(info->rx_skb)->pkt_type) {
 
                        case HCI_EVENT_PKT:
                                info->rx_state = RECV_WAIT_EVENT_HEADER;
@@ -282,7 +282,7 @@ static void bt3c_receive(bt3c_info_t *info)
 
                        default:
                                /* Unknown packet */
-                               BT_ERR("Unknown HCI packet with type 0x%02x received", info->rx_skb->pkt_type);
+                               BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
                                info->hdev->stat.err_rx++;
                                clear_bit(HCI_RUNNING, &(info->hdev->flags));
 
@@ -439,7 +439,7 @@ static int bt3c_hci_send_frame(struct sk_buff *skb)
 
        info = (bt3c_info_t *) (hdev->driver_data);
 
-       switch (skb->pkt_type) {
+       switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
                hdev->stat.cmd_tx++;
                break;
@@ -452,7 +452,7 @@ static int bt3c_hci_send_frame(struct sk_buff *skb)
        };
 
        /* Prepend skb with frame type */
-       memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
+       memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
        skb_queue_tail(&(info->txq), skb);
 
        spin_lock_irqsave(&(info->lock), flags);
index e4c59fdc0e12bcc7e5d1e49231d211b5d3c67b7c..89486ea7a0216db3712b3182fddde49824920d15 100644 (file)
@@ -211,9 +211,9 @@ static void btuart_receive(btuart_info_t *info)
                if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
 
                        info->rx_skb->dev = (void *) info->hdev;
-                       info->rx_skb->pkt_type = inb(iobase + UART_RX);
+                       bt_cb(info->rx_skb)->pkt_type = inb(iobase + UART_RX);
 
-                       switch (info->rx_skb->pkt_type) {
+                       switch (bt_cb(info->rx_skb)->pkt_type) {
 
                        case HCI_EVENT_PKT:
                                info->rx_state = RECV_WAIT_EVENT_HEADER;
@@ -232,7 +232,7 @@ static void btuart_receive(btuart_info_t *info)
 
                        default:
                                /* Unknown packet */
-                               BT_ERR("Unknown HCI packet with type 0x%02x received", info->rx_skb->pkt_type);
+                               BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
                                info->hdev->stat.err_rx++;
                                clear_bit(HCI_RUNNING, &(info->hdev->flags));
 
@@ -447,7 +447,7 @@ static int btuart_hci_send_frame(struct sk_buff *skb)
 
        info = (btuart_info_t *)(hdev->driver_data);
 
-       switch (skb->pkt_type) {
+       switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
                hdev->stat.cmd_tx++;
                break;
@@ -460,7 +460,7 @@ static int btuart_hci_send_frame(struct sk_buff *skb)
        };
 
        /* Prepend skb with frame type */
-       memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
+       memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
        skb_queue_tail(&(info->txq), skb);
 
        btuart_write_wakeup(info);
index e39868c3da4815f89fb247badd3faa9e6b15cb91..84c1f88394225504ff7c2e02f77a8f043db85960 100644 (file)
@@ -251,7 +251,7 @@ static void dtl1_receive(dtl1_info_t *info)
                                info->rx_count = nsh->len + (nsh->len & 0x0001);
                                break;
                        case RECV_WAIT_DATA:
-                               info->rx_skb->pkt_type = nsh->type;
+                               bt_cb(info->rx_skb)->pkt_type = nsh->type;
 
                                /* remove PAD byte if it exists */
                                if (nsh->len & 0x0001) {
@@ -262,7 +262,7 @@ static void dtl1_receive(dtl1_info_t *info)
                                /* remove NSH */
                                skb_pull(info->rx_skb, NSHL);
 
-                               switch (info->rx_skb->pkt_type) {
+                               switch (bt_cb(info->rx_skb)->pkt_type) {
                                case 0x80:
                                        /* control data for the Nokia Card */
                                        dtl1_control(info, info->rx_skb);
@@ -272,12 +272,12 @@ static void dtl1_receive(dtl1_info_t *info)
                                case 0x84:
                                        /* send frame to the HCI layer */
                                        info->rx_skb->dev = (void *) info->hdev;
-                                       info->rx_skb->pkt_type &= 0x0f;
+                                       bt_cb(info->rx_skb)->pkt_type &= 0x0f;
                                        hci_recv_frame(info->rx_skb);
                                        break;
                                default:
                                        /* unknown packet */
-                                       BT_ERR("Unknown HCI packet with type 0x%02x received", info->rx_skb->pkt_type);
+                                       BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
                                        kfree_skb(info->rx_skb);
                                        break;
                                }
@@ -410,7 +410,7 @@ static int dtl1_hci_send_frame(struct sk_buff *skb)
 
        info = (dtl1_info_t *)(hdev->driver_data);
 
-       switch (skb->pkt_type) {
+       switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
                hdev->stat.cmd_tx++;
                nsh.type = 0x81;
index 858fddb046de8caba0dc1b5c84051dff4d086270..0ee324e1265de30d9f8e75605bbbe414fcfcbd89 100644 (file)
@@ -149,7 +149,7 @@ static int bcsp_enqueue(struct hci_uart *hu, struct sk_buff *skb)
                return 0;
        }
 
-       switch (skb->pkt_type) {
+       switch (bt_cb(skb)->pkt_type) {
        case HCI_ACLDATA_PKT:
        case HCI_COMMAND_PKT:
                skb_queue_tail(&bcsp->rel, skb);
@@ -227,7 +227,7 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
        if (!nskb)
                return NULL;
 
-       nskb->pkt_type = pkt_type;
+       bt_cb(nskb)->pkt_type = pkt_type;
 
        bcsp_slip_msgdelim(nskb);
 
@@ -286,7 +286,7 @@ static struct sk_buff *bcsp_dequeue(struct hci_uart *hu)
           since they have priority */
 
        if ((skb = skb_dequeue(&bcsp->unrel)) != NULL) {
-               struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type);
+               struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, bt_cb(skb)->pkt_type);
                if (nskb) {
                        kfree_skb(skb);
                        return nskb;
@@ -303,7 +303,7 @@ static struct sk_buff *bcsp_dequeue(struct hci_uart *hu)
        spin_lock_irqsave(&bcsp->unack.lock, flags);
 
        if (bcsp->unack.qlen < BCSP_TXWINSIZE && (skb = skb_dequeue(&bcsp->rel)) != NULL) {
-               struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type);
+               struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, bt_cb(skb)->pkt_type);
                if (nskb) {
                        __skb_queue_tail(&bcsp->unack, skb);
                        mod_timer(&bcsp->tbcsp, jiffies + HZ / 4);
@@ -401,7 +401,7 @@ static void bcsp_handle_le_pkt(struct hci_uart *hu)
                if (!nskb)
                        return;
                memcpy(skb_put(nskb, 4), conf_rsp_pkt, 4);
-               nskb->pkt_type = BCSP_LE_PKT;
+               bt_cb(nskb)->pkt_type = BCSP_LE_PKT;
 
                skb_queue_head(&bcsp->unrel, nskb);
                hci_uart_tx_wakeup(hu);
@@ -483,14 +483,14 @@ static inline void bcsp_complete_rx_pkt(struct hci_uart *hu)
        bcsp_pkt_cull(bcsp);
        if ((bcsp->rx_skb->data[1] & 0x0f) == 6 &&
                        bcsp->rx_skb->data[0] & 0x80) {
-               bcsp->rx_skb->pkt_type = HCI_ACLDATA_PKT;
+               bt_cb(bcsp->rx_skb)->pkt_type = HCI_ACLDATA_PKT;
                pass_up = 1;
        } else if ((bcsp->rx_skb->data[1] & 0x0f) == 5 &&
                        bcsp->rx_skb->data[0] & 0x80) {
-               bcsp->rx_skb->pkt_type = HCI_EVENT_PKT;
+               bt_cb(bcsp->rx_skb)->pkt_type = HCI_EVENT_PKT;
                pass_up = 1;
        } else if ((bcsp->rx_skb->data[1] & 0x0f) == 7) {
-               bcsp->rx_skb->pkt_type = HCI_SCODATA_PKT;
+               bt_cb(bcsp->rx_skb)->pkt_type = HCI_SCODATA_PKT;
                pass_up = 1;
        } else if ((bcsp->rx_skb->data[1] & 0x0f) == 1 &&
                        !(bcsp->rx_skb->data[0] & 0x80)) {
@@ -512,7 +512,7 @@ static inline void bcsp_complete_rx_pkt(struct hci_uart *hu)
                                hdr.evt = 0xff;
                                hdr.plen = bcsp->rx_skb->len;
                                memcpy(skb_push(bcsp->rx_skb, HCI_EVENT_HDR_SIZE), &hdr, HCI_EVENT_HDR_SIZE);
-                               bcsp->rx_skb->pkt_type = HCI_EVENT_PKT;
+                               bt_cb(bcsp->rx_skb)->pkt_type = HCI_EVENT_PKT;
 
                                hci_recv_frame(bcsp->rx_skb);
                        } else {
index 533323b60e6399dec3eb3a81cfcb8d4f94306321..cf8a22d58d960f6753ec4bc98a34bad70c779c70 100644 (file)
@@ -112,7 +112,7 @@ static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
        BT_DBG("hu %p skb %p", hu, skb);
 
        /* Prepend skb with frame type */
-       memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
+       memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
        skb_queue_tail(&h4->txq, skb);
        return 0;
 }
@@ -239,7 +239,7 @@ static int h4_recv(struct hci_uart *hu, void *data, int count)
                        return 0;
                }
                h4->rx_skb->dev = (void *) hu->hdev;
-               h4->rx_skb->pkt_type = type;
+               bt_cb(h4->rx_skb)->pkt_type = type;
        }
        return count;
 }
index 90be2eae52e0f99ae1c5cdb36420f16eac560c34..aed80cc2289028cda06e79125aaca8d066af447b 100644 (file)
@@ -153,7 +153,7 @@ restart:
                        break;
                }
        
-               hci_uart_tx_complete(hu, skb->pkt_type);
+               hci_uart_tx_complete(hu, bt_cb(skb)->pkt_type);
                kfree_skb(skb);
        } 
        
@@ -229,7 +229,7 @@ static int hci_uart_send_frame(struct sk_buff *skb)
        hu = (struct hci_uart *) hdev->driver_data;
        tty = hu->tty;
 
-       BT_DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len);
+       BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
 
        hu->proto->enqueue(hu, skb);
 
index 657719b8254f6c61d119128dec4ac7772ff824a2..67d96b5cbb96535568bb26f28595d75e1b869e6d 100644 (file)
@@ -127,7 +127,7 @@ static struct usb_device_id blacklist_ids[] = {
        { }     /* Terminating entry */
 };
 
-static struct _urb *_urb_alloc(int isoc, int gfp)
+static struct _urb *_urb_alloc(int isoc, unsigned int __nocast gfp)
 {
        struct _urb *_urb = kmalloc(sizeof(struct _urb) +
                                sizeof(struct usb_iso_packet_descriptor) * isoc, gfp);
@@ -443,7 +443,7 @@ static int __tx_submit(struct hci_usb *husb, struct _urb *_urb)
 
 static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb)
 {
-       struct _urb *_urb = __get_completed(husb, skb->pkt_type);
+       struct _urb *_urb = __get_completed(husb, bt_cb(skb)->pkt_type);
        struct usb_ctrlrequest *dr;
        struct urb *urb;
 
@@ -451,7 +451,7 @@ static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb)
                _urb = _urb_alloc(0, GFP_ATOMIC);
                if (!_urb)
                        return -ENOMEM;
-               _urb->type = skb->pkt_type;
+               _urb->type = bt_cb(skb)->pkt_type;
 
                dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
                if (!dr) {
@@ -479,7 +479,7 @@ static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb)
 
 static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb)
 {
-       struct _urb *_urb = __get_completed(husb, skb->pkt_type);
+       struct _urb *_urb = __get_completed(husb, bt_cb(skb)->pkt_type);
        struct urb *urb;
        int pipe;
 
@@ -487,7 +487,7 @@ static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb)
                _urb = _urb_alloc(0, GFP_ATOMIC);
                if (!_urb)
                        return -ENOMEM;
-               _urb->type = skb->pkt_type;
+               _urb->type = bt_cb(skb)->pkt_type;
        }
 
        urb  = &_urb->urb;
@@ -505,14 +505,14 @@ static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb)
 #ifdef CONFIG_BT_HCIUSB_SCO
 static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb)
 {
-       struct _urb *_urb = __get_completed(husb, skb->pkt_type);
+       struct _urb *_urb = __get_completed(husb, bt_cb(skb)->pkt_type);
        struct urb *urb;
 
        if (!_urb) {
                _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC);
                if (!_urb)
                        return -ENOMEM;
-               _urb->type = skb->pkt_type;
+               _urb->type = bt_cb(skb)->pkt_type;
        }
 
        BT_DBG("%s skb %p len %d", husb->hdev->name, skb, skb->len);
@@ -601,11 +601,11 @@ static int hci_usb_send_frame(struct sk_buff *skb)
        if (!test_bit(HCI_RUNNING, &hdev->flags))
                return -EBUSY;
 
-       BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
+       BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
 
        husb = (struct hci_usb *) hdev->driver_data;
 
-       switch (skb->pkt_type) {
+       switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
                hdev->stat.cmd_tx++;
                break;
@@ -627,7 +627,7 @@ static int hci_usb_send_frame(struct sk_buff *skb)
 
        read_lock(&husb->completion_lock);
 
-       skb_queue_tail(__transmit_q(husb, skb->pkt_type), skb);
+       skb_queue_tail(__transmit_q(husb, bt_cb(skb)->pkt_type), skb);
        hci_usb_tx_wakeup(husb);
 
        read_unlock(&husb->completion_lock);
@@ -682,7 +682,7 @@ static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int c
                                return -ENOMEM;
                        }
                        skb->dev = (void *) husb->hdev;
-                       skb->pkt_type = type;
+                       bt_cb(skb)->pkt_type = type;
        
                        __reassembly(husb, type) = skb;
 
@@ -702,6 +702,7 @@ static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int c
                if (!scb->expect) {
                        /* Complete frame */
                        __reassembly(husb, type) = NULL;
+                       bt_cb(skb)->pkt_type = type;
                        hci_recv_frame(skb);
                }
 
index f9b956fb2b8b81ac774cb772b21d06aee58a0a7f..52cbd45c308fa0189d9d0a6ef044ebc49651a379 100644 (file)
-/* 
-   BlueZ - Bluetooth protocol stack for Linux
-   Copyright (C) 2000-2001 Qualcomm Incorporated
-
-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License version 2 as
-   published by the Free Software Foundation;
-
-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
-   SOFTWARE IS DISCLAIMED.
-*/
-
 /*
- * Bluetooth HCI virtual device driver.
  *
- * $Id: hci_vhci.c,v 1.3 2002/04/17 17:37:20 maxk Exp $ 
+ *  Bluetooth virtual HCI driver
+ *
+ *  Copyright (C) 2000-2001 Qualcomm Incorporated
+ *  Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ *  Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
  */
-#define VERSION "1.1"
 
 #include <linux/config.h>
 #include <linux/module.h>
 
-#include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/sched.h>
+#include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
 #include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/random.h>
 
 #include <linux/skbuff.h>
 #include <linux/miscdevice.h>
 
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
-#include "hci_vhci.h"
 
-/* HCI device part */
+#ifndef CONFIG_BT_HCIVHCI_DEBUG
+#undef  BT_DBG
+#define BT_DBG(D...)
+#endif
+
+#define VERSION "1.2"
+
+static int minor = MISC_DYNAMIC_MINOR;
+
+struct vhci_data {
+       struct hci_dev *hdev;
+
+       unsigned long flags;
+
+       wait_queue_head_t read_wait;
+       struct sk_buff_head readq;
+
+       struct fasync_struct *fasync;
+};
 
-static int hci_vhci_open(struct hci_dev *hdev)
+#define VHCI_FASYNC    0x0010
+
+static struct miscdevice vhci_miscdev;
+
+static int vhci_open_dev(struct hci_dev *hdev)
 {
        set_bit(HCI_RUNNING, &hdev->flags);
-       return 0;
-}
 
-static int hci_vhci_flush(struct hci_dev *hdev)
-{
-       struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
-       skb_queue_purge(&hci_vhci->readq);
        return 0;
 }
 
-static int hci_vhci_close(struct hci_dev *hdev)
+static int vhci_close_dev(struct hci_dev *hdev)
 {
+       struct vhci_data *vhci = hdev->driver_data;
+
        if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
                return 0;
 
-       hci_vhci_flush(hdev);
+       skb_queue_purge(&vhci->readq);
+
        return 0;
 }
 
-static void hci_vhci_destruct(struct hci_dev *hdev)
+static int vhci_flush(struct hci_dev *hdev)
 {
-       struct hci_vhci_struct *vhci;
+       struct vhci_data *vhci = hdev->driver_data;
 
-       if (!hdev) return;
+       skb_queue_purge(&vhci->readq);
 
-       vhci = (struct hci_vhci_struct *) hdev->driver_data;
-       kfree(vhci);
+       return 0;
 }
 
-static int hci_vhci_send_frame(struct sk_buff *skb)
+static int vhci_send_frame(struct sk_buff *skb)
 {
        struct hci_dev* hdev = (struct hci_dev *) skb->dev;
-       struct hci_vhci_struct *hci_vhci;
+       struct vhci_data *vhci;
 
        if (!hdev) {
-               BT_ERR("Frame for uknown device (hdev=NULL)");
+               BT_ERR("Frame for unknown HCI device (hdev=NULL)");
                return -ENODEV;
        }
 
        if (!test_bit(HCI_RUNNING, &hdev->flags))
                return -EBUSY;
 
-       hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
+       vhci = hdev->driver_data;
+
+       memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+       skb_queue_tail(&vhci->readq, skb);
 
-       memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
-       skb_queue_tail(&hci_vhci->readq, skb);
+       if (vhci->flags & VHCI_FASYNC)
+               kill_fasync(&vhci->fasync, SIGIO, POLL_IN);
 
-       if (hci_vhci->flags & VHCI_FASYNC)
-               kill_fasync(&hci_vhci->fasync, SIGIO, POLL_IN);
-       wake_up_interruptible(&hci_vhci->read_wait);
+       wake_up_interruptible(&vhci->read_wait);
 
        return 0;
 }
 
-/* Character device part */
-
-/* Poll */
-static unsigned int hci_vhci_chr_poll(struct file *file, poll_table * wait)
-{  
-       struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
-
-       poll_wait(file, &hci_vhci->read_wait, wait);
-       if (!skb_queue_empty(&hci_vhci->readq))
-               return POLLIN | POLLRDNORM;
-
-       return POLLOUT | POLLWRNORM;
+static void vhci_destruct(struct hci_dev *hdev)
+{
+       kfree(hdev->driver_data);
 }
 
-/* Get packet from user space buffer(already verified) */
-static inline ssize_t hci_vhci_get_user(struct hci_vhci_struct *hci_vhci, const char __user *buf, size_t count)
+static inline ssize_t vhci_get_user(struct vhci_data *vhci,
+                                       const char __user *buf, size_t count)
 {
        struct sk_buff *skb;
 
        if (count > HCI_MAX_FRAME_SIZE)
                return -EINVAL;
 
-       if (!(skb = bt_skb_alloc(count, GFP_KERNEL)))
+       skb = bt_skb_alloc(count, GFP_KERNEL);
+       if (!skb)
                return -ENOMEM;
-       
+
        if (copy_from_user(skb_put(skb, count), buf, count)) {
                kfree_skb(skb);
                return -EFAULT;
        }
 
-       skb->dev = (void *) hci_vhci->hdev;
-       skb->pkt_type = *((__u8 *) skb->data);
+       skb->dev = (void *) vhci->hdev;
+       bt_cb(skb)->pkt_type = *((__u8 *) skb->data);
        skb_pull(skb, 1);
 
        hci_recv_frame(skb);
 
        return count;
-} 
-
-/* Write */
-static ssize_t hci_vhci_chr_write(struct file * file, const char __user * buf, 
-                            size_t count, loff_t *pos)
-{
-       struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
-
-       if (!access_ok(VERIFY_READ, buf, count))
-               return -EFAULT;
-
-       return hci_vhci_get_user(hci_vhci, buf, count);
 }
 
-/* Put packet to user space buffer(already verified) */
-static inline ssize_t hci_vhci_put_user(struct hci_vhci_struct *hci_vhci,
-                                      struct sk_buff *skb, char __user *buf,
-                                      int count)
+static inline ssize_t vhci_put_user(struct vhci_data *vhci,
+                       struct sk_buff *skb, char __user *buf, int count)
 {
-       int len = count, total = 0;
        char __user *ptr = buf;
+       int len, total = 0;
+
+       len = min_t(unsigned int, skb->len, count);
 
-       len = min_t(unsigned int, skb->len, len);
        if (copy_to_user(ptr, skb->data, len))
                return -EFAULT;
+
        total += len;
 
-       hci_vhci->hdev->stat.byte_tx += len;
-       switch (skb->pkt_type) {
-               case HCI_COMMAND_PKT:
-                       hci_vhci->hdev->stat.cmd_tx++;
-                       break;
+       vhci->hdev->stat.byte_tx += len;
 
-               case HCI_ACLDATA_PKT:
-                       hci_vhci->hdev->stat.acl_tx++;
-                       break;
+       switch (bt_cb(skb)->pkt_type) {
+       case HCI_COMMAND_PKT:
+               vhci->hdev->stat.cmd_tx++;
+               break;
+
+       case HCI_ACLDATA_PKT:
+               vhci->hdev->stat.acl_tx++;
+               break;
 
-               case HCI_SCODATA_PKT:
-                       hci_vhci->hdev->stat.cmd_tx++;
-                       break;
+       case HCI_SCODATA_PKT:
+               vhci->hdev->stat.cmd_tx++;
+               break;
        };
 
        return total;
 }
 
-/* Read */
-static ssize_t hci_vhci_chr_read(struct file * file, char __user * buf, size_t count, loff_t *pos)
+static loff_t vhci_llseek(struct file * file, loff_t offset, int origin)
+{
+       return -ESPIPE;
+}
+
+static ssize_t vhci_read(struct file * file, char __user * buf, size_t count, loff_t *pos)
 {
-       struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
        DECLARE_WAITQUEUE(wait, current);
+       struct vhci_data *vhci = file->private_data;
        struct sk_buff *skb;
        ssize_t ret = 0;
 
-       add_wait_queue(&hci_vhci->read_wait, &wait);
+       add_wait_queue(&vhci->read_wait, &wait);
        while (count) {
                set_current_state(TASK_INTERRUPTIBLE);
 
-               /* Read frames from device queue */
-               if (!(skb = skb_dequeue(&hci_vhci->readq))) {
+               skb = skb_dequeue(&vhci->readq);
+               if (!skb) {
                        if (file->f_flags & O_NONBLOCK) {
                                ret = -EAGAIN;
                                break;
                        }
+
                        if (signal_pending(current)) {
                                ret = -ERESTARTSYS;
                                break;
                        }
 
-                       /* Nothing to read, let's sleep */
                        schedule();
                        continue;
                }
 
                if (access_ok(VERIFY_WRITE, buf, count))
-                       ret = hci_vhci_put_user(hci_vhci, skb, buf, count);
+                       ret = vhci_put_user(vhci, skb, buf, count);
                else
                        ret = -EFAULT;
 
@@ -231,84 +222,90 @@ static ssize_t hci_vhci_chr_read(struct file * file, char __user * buf, size_t c
                break;
        }
        set_current_state(TASK_RUNNING);
-       remove_wait_queue(&hci_vhci->read_wait, &wait);
+       remove_wait_queue(&vhci->read_wait, &wait);
 
        return ret;
 }
 
-static loff_t hci_vhci_chr_lseek(struct file * file, loff_t offset, int origin)
+static ssize_t vhci_write(struct file *file,
+                       const char __user *buf, size_t count, loff_t *pos)
 {
-       return -ESPIPE;
-}
+       struct vhci_data *vhci = file->private_data;
 
-static int hci_vhci_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-       return -EINVAL;
+       if (!access_ok(VERIFY_READ, buf, count))
+               return -EFAULT;
+
+       return vhci_get_user(vhci, buf, count);
 }
 
-static int hci_vhci_chr_fasync(int fd, struct file *file, int on)
+static unsigned int vhci_poll(struct file *file, poll_table *wait)
 {
-       struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
-       int ret;
+       struct vhci_data *vhci = file->private_data;
 
-       if ((ret = fasync_helper(fd, file, on, &hci_vhci->fasync)) < 0)
-               return ret; 
-       if (on)
-               hci_vhci->flags |= VHCI_FASYNC;
-       else 
-               hci_vhci->flags &= ~VHCI_FASYNC;
+       poll_wait(file, &vhci->read_wait, wait);
 
-       return 0;
+       if (!skb_queue_empty(&vhci->readq))
+               return POLLIN | POLLRDNORM;
+
+       return POLLOUT | POLLWRNORM;
 }
 
-static int hci_vhci_chr_open(struct inode *inode, struct file * file)
+static int vhci_ioctl(struct inode *inode, struct file *file,
+                                       unsigned int cmd, unsigned long arg)
 {
-       struct hci_vhci_struct *hci_vhci = NULL; 
+       return -EINVAL;
+}
+
+static int vhci_open(struct inode *inode, struct file *file)
+{
+       struct vhci_data *vhci;
        struct hci_dev *hdev;
 
-       if (!(hci_vhci = kmalloc(sizeof(struct hci_vhci_struct), GFP_KERNEL)))
+       vhci = kmalloc(sizeof(struct vhci_data), GFP_KERNEL);
+       if (!vhci)
                return -ENOMEM;
 
-       memset(hci_vhci, 0, sizeof(struct hci_vhci_struct));
+       memset(vhci, 0, sizeof(struct vhci_data));
 
-       skb_queue_head_init(&hci_vhci->readq);
-       init_waitqueue_head(&hci_vhci->read_wait);
+       skb_queue_head_init(&vhci->readq);
+       init_waitqueue_head(&vhci->read_wait);
 
-       /* Initialize and register HCI device */
        hdev = hci_alloc_dev();
        if (!hdev) {
-               kfree(hci_vhci);
+               kfree(vhci);
                return -ENOMEM;
        }
 
-       hci_vhci->hdev = hdev;
+       vhci->hdev = hdev;
 
        hdev->type = HCI_VHCI;
-       hdev->driver_data = hci_vhci;
+       hdev->driver_data = vhci;
+       SET_HCIDEV_DEV(hdev, vhci_miscdev.dev);
 
-       hdev->open  = hci_vhci_open;
-       hdev->close = hci_vhci_close;
-       hdev->flush = hci_vhci_flush;
-       hdev->send  = hci_vhci_send_frame;
-       hdev->destruct = hci_vhci_destruct;
+       hdev->open     = vhci_open_dev;
+       hdev->close    = vhci_close_dev;
+       hdev->flush    = vhci_flush;
+       hdev->send     = vhci_send_frame;
+       hdev->destruct = vhci_destruct;
 
        hdev->owner = THIS_MODULE;
-       
+
        if (hci_register_dev(hdev) < 0) {
-               kfree(hci_vhci);
+               BT_ERR("Can't register HCI device");
+               kfree(vhci);
                hci_free_dev(hdev);
                return -EBUSY;
        }
 
-       file->private_data = hci_vhci;
-       return nonseekable_open(inode, file);   
+       file->private_data = vhci;
+
+       return nonseekable_open(inode, file);
 }
 
-static int hci_vhci_chr_close(struct inode *inode, struct file *file)
+static int vhci_release(struct inode *inode, struct file *file)
 {
-       struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
-       struct hci_dev *hdev = hci_vhci->hdev;
+       struct vhci_data *vhci = file->private_data;
+       struct hci_dev *hdev = vhci->hdev;
 
        if (hci_unregister_dev(hdev) < 0) {
                BT_ERR("Can't unregister HCI device %s", hdev->name);
@@ -317,48 +314,71 @@ static int hci_vhci_chr_close(struct inode *inode, struct file *file)
        hci_free_dev(hdev);
 
        file->private_data = NULL;
+
        return 0;
 }
 
-static struct file_operations hci_vhci_fops = {
-       .owner  = THIS_MODULE,  
-       .llseek = hci_vhci_chr_lseek,
-       .read   = hci_vhci_chr_read,
-       .write  = hci_vhci_chr_write,
-       .poll   = hci_vhci_chr_poll,
-       .ioctl  = hci_vhci_chr_ioctl,
-       .open   = hci_vhci_chr_open,
-       .release        = hci_vhci_chr_close,
-       .fasync = hci_vhci_chr_fasync           
+static int vhci_fasync(int fd, struct file *file, int on)
+{
+       struct vhci_data *vhci = file->private_data;
+       int err;
+
+       err = fasync_helper(fd, file, on, &vhci->fasync);
+       if (err < 0)
+               return err;
+
+       if (on)
+               vhci->flags |= VHCI_FASYNC;
+       else
+               vhci->flags &= ~VHCI_FASYNC;
+
+       return 0;
+}
+
+static struct file_operations vhci_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = vhci_llseek,
+       .read           = vhci_read,
+       .write          = vhci_write,
+       .poll           = vhci_poll,
+       .ioctl          = vhci_ioctl,
+       .open           = vhci_open,
+       .release        = vhci_release,
+       .fasync         = vhci_fasync,
 };
 
-static struct miscdevice hci_vhci_miscdev=
-{
-        VHCI_MINOR,
-        "hci_vhci",
-        &hci_vhci_fops
+static struct miscdevice vhci_miscdev= {
+       .name           = "vhci",
+       .fops           = &vhci_fops,
 };
 
-static int __init hci_vhci_init(void)
+static int __init vhci_init(void)
 {
-       BT_INFO("VHCI driver ver %s", VERSION);
+       BT_INFO("Virtual HCI driver ver %s", VERSION);
 
-       if (misc_register(&hci_vhci_miscdev)) {
-               BT_ERR("Can't register misc device %d\n", VHCI_MINOR);
+       vhci_miscdev.minor = minor;
+
+       if (misc_register(&vhci_miscdev) < 0) {
+               BT_ERR("Can't register misc device with minor %d", minor);
                return -EIO;
        }
 
        return 0;
 }
 
-static void hci_vhci_cleanup(void)
+static void __exit vhci_exit(void)
 {
-       misc_deregister(&hci_vhci_miscdev);
+       if (misc_deregister(&vhci_miscdev) < 0)
+               BT_ERR("Can't unregister misc device with minor %d", minor);
 }
 
-module_init(hci_vhci_init);
-module_exit(hci_vhci_cleanup);
+module_init(vhci_init);
+module_exit(vhci_exit);
+
+module_param(minor, int, 0444);
+MODULE_PARM_DESC(minor, "Miscellaneous minor device number");
 
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-MODULE_DESCRIPTION("Bluetooth VHCI driver ver " VERSION);
-MODULE_LICENSE("GPL"); 
+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
+MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/bluetooth/hci_vhci.h b/drivers/bluetooth/hci_vhci.h
deleted file mode 100644 (file)
index 53b11f9..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/* 
-   BlueZ - Bluetooth protocol stack for Linux
-   Copyright (C) 2000-2001 Qualcomm Incorporated
-
-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License version 2 as
-   published by the Free Software Foundation;
-
-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
-   SOFTWARE IS DISCLAIMED.
-*/
-
-/*
- * $Id: hci_vhci.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
- */
-
-#ifndef __HCI_VHCI_H
-#define __HCI_VHCI_H
-
-#ifdef __KERNEL__
-
-struct hci_vhci_struct {
-       struct hci_dev       *hdev;
-       __u32                flags;
-       wait_queue_head_t    read_wait;
-       struct sk_buff_head  readq;
-       struct fasync_struct *fasync;
-};
-
-/* VHCI device flags */
-#define VHCI_FASYNC            0x0010
-
-#endif /* __KERNEL__ */
-
-#define VHCI_DEV       "/dev/vhci"
-#define VHCI_MINOR     250
-
-#endif /* __HCI_VHCI_H */
index 38dd9ffbe8bcc147cc2174e3965870ab5a9aba73..0829db58462fd8d55a7a34d3680c9feb5404d437 100644 (file)
@@ -734,7 +734,7 @@ static int viocd_remove(struct vio_dev *vdev)
  */
 static struct vio_device_id viocd_device_table[] __devinitdata = {
        { "viocd", "" },
-       { 0, }
+       { "", "" }
 };
 
 MODULE_DEVICE_TABLE(vio, viocd_device_table);
index 7333b41d4224240b19f683e12010c261b94417cd..2bc9d64db106cc40df4cf709db77405f66258c9d 100644 (file)
@@ -138,7 +138,7 @@ config CYZ_INTR
 
 config DIGIEPCA
        tristate "Digiboard Intelligent Async Support"
-       depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP && (!64BIT || BROKEN)
+       depends on SERIAL_NONSTANDARD
        ---help---
          This is a driver for Digi International's Xx, Xeve, and Xem series
          of cards which provide multiple serial ports. You would need
@@ -735,7 +735,7 @@ config SGI_IP27_RTC
 
 config GEN_RTC
        tristate "Generic /dev/rtc emulation"
-       depends on RTC!=y && !IA64 && !ARM && !PPC64 && !M32R && !SPARC32
+       depends on RTC!=y && !IA64 && !ARM && !PPC64 && !M32R && !SPARC32 && !SPARC64
        ---help---
          If you say Y here and create a character special file /dev/rtc with
          major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -842,8 +842,7 @@ config SONYPI
 
 config TANBAC_TB0219
        tristate "TANBAC TB0219 base board support"
-       depends TANBAC_TB0229
-
+       depends TANBAC_TB022X
 
 menu "Ftape, the floppy tape device driver"
 
index 184378d23f8ce1598827da50ca87041d5c21e24f..94d4eab5d3ca30e494e6cf90feab98607725d48b 100644 (file)
@@ -1,46 +1,46 @@
 /*          Definitions for DigiBoard ditty(1) command.                 */
 
 #if !defined(TIOCMODG)
-#define        TIOCMODG        ('d'<<8) | 250          /* get modem ctrl state */
-#define        TIOCMODS        ('d'<<8) | 251          /* set modem ctrl state */
+#define        TIOCMODG        (('d'<<8) | 250)        /* get modem ctrl state */
+#define        TIOCMODS        (('d'<<8) | 251)        /* set modem ctrl state */
 #endif
 
 #if !defined(TIOCMSET)
-#define        TIOCMSET        ('d'<<8) | 252          /* set modem ctrl state */
-#define        TIOCMGET        ('d'<<8) | 253          /* set modem ctrl state */
+#define        TIOCMSET        (('d'<<8) | 252)        /* set modem ctrl state */
+#define        TIOCMGET        (('d'<<8) | 253)        /* set modem ctrl state */
 #endif
 
 #if !defined(TIOCMBIC)
-#define        TIOCMBIC        ('d'<<8) | 254          /* set modem ctrl state */
-#define        TIOCMBIS        ('d'<<8) | 255          /* set modem ctrl state */
+#define        TIOCMBIC        (('d'<<8) | 254)        /* set modem ctrl state */
+#define        TIOCMBIS        (('d'<<8) | 255)        /* set modem ctrl state */
 #endif
 
 #if !defined(TIOCSDTR)
-#define        TIOCSDTR        ('e'<<8) | 0            /* set DTR              */
-#define        TIOCCDTR        ('e'<<8) | 1            /* clear DTR            */
+#define        TIOCSDTR        (('e'<<8) | 0)          /* set DTR              */
+#define        TIOCCDTR        (('e'<<8) | 1)          /* clear DTR            */
 #endif
 
 /************************************************************************
  * Ioctl command arguments for DIGI parameters.
  ************************************************************************/
-#define DIGI_GETA      ('e'<<8) | 94           /* Read params          */
+#define DIGI_GETA      (('e'<<8) | 94)         /* Read params          */
 
-#define DIGI_SETA      ('e'<<8) | 95           /* Set params           */
-#define DIGI_SETAW     ('e'<<8) | 96           /* Drain & set params   */
-#define DIGI_SETAF     ('e'<<8) | 97           /* Drain, flush & set params */
+#define DIGI_SETA      (('e'<<8) | 95)         /* Set params           */
+#define DIGI_SETAW     (('e'<<8) | 96)         /* Drain & set params   */
+#define DIGI_SETAF     (('e'<<8) | 97)         /* Drain, flush & set params */
 
-#define        DIGI_GETFLOW    ('e'<<8) | 99           /* Get startc/stopc flow */
+#define        DIGI_GETFLOW    (('e'<<8) | 99)         /* Get startc/stopc flow */
                                                /* control characters    */
-#define        DIGI_SETFLOW    ('e'<<8) | 100          /* Set startc/stopc flow */
+#define        DIGI_SETFLOW    (('e'<<8) | 100)        /* Set startc/stopc flow */
                                                /* control characters    */
-#define        DIGI_GETAFLOW   ('e'<<8) | 101          /* Get Aux. startc/stopc */
+#define        DIGI_GETAFLOW   (('e'<<8) | 101)        /* Get Aux. startc/stopc */
                                                /* flow control chars    */
-#define        DIGI_SETAFLOW   ('e'<<8) | 102          /* Set Aux. startc/stopc */
+#define        DIGI_SETAFLOW   (('e'<<8) | 102)        /* Set Aux. startc/stopc */
                                                /* flow control chars    */
 
-#define        DIGI_GETINFO    ('e'<<8) | 103          /* Fill in digi_info */
-#define        DIGI_POLLER     ('e'<<8) | 104          /* Turn on/off poller */
-#define        DIGI_INIT       ('e'<<8) | 105          /* Allow things to run. */
+#define        DIGI_GETINFO    (('e'<<8) | 103)        /* Fill in digi_info */
+#define        DIGI_POLLER     (('e'<<8) | 104)        /* Turn on/off poller */
+#define        DIGI_INIT       (('e'<<8) | 105)        /* Allow things to run. */
 
 struct digiflow_struct 
 {
index c47d7fcb840017fe9372f079e0ffec0452cd2280..3c1f1922c798a4cff9dea622efc537bbfd885b40 100644 (file)
 
 struct global_data 
 {
-       volatile ushort cin;
-       volatile ushort cout;
-       volatile ushort cstart;
-       volatile ushort cmax;
-       volatile ushort ein;
-       volatile ushort eout;
-       volatile ushort istart;
-       volatile ushort imax;
+       u16 cin;
+       u16 cout;
+       u16 cstart;
+       u16 cmax;
+       u16 ein;
+       u16 eout;
+       u16 istart;
+       u16 imax;
 };
 
 
 struct board_chan 
 {
-       int filler1; 
-       int filler2;
-       volatile ushort tseg;
-       volatile ushort tin;
-       volatile ushort tout;
-       volatile ushort tmax;
-       
-       volatile ushort rseg;
-       volatile ushort rin;
-       volatile ushort rout;
-       volatile ushort rmax;
-       
-       volatile ushort tlow;
-       volatile ushort rlow;
-       volatile ushort rhigh;
-       volatile ushort incr;
-       
-       volatile ushort etime;
-       volatile ushort edelay;
-       volatile unchar *dev;
-       
-       volatile ushort iflag;
-       volatile ushort oflag;
-       volatile ushort cflag;
-       volatile ushort gmask;
-       
-       volatile ushort col;
-       volatile ushort delay;
-       volatile ushort imask;
-       volatile ushort tflush;
-
-       int filler3;
-       int filler4;
-       int filler5;
-       int filler6;
-       
-       volatile unchar num;
-       volatile unchar ract;
-       volatile unchar bstat;
-       volatile unchar tbusy;
-       volatile unchar iempty;
-       volatile unchar ilow;
-       volatile unchar idata;
-       volatile unchar eflag;
-       
-       volatile unchar tflag;
-       volatile unchar rflag;
-       volatile unchar xmask;
-       volatile unchar xval;
-       volatile unchar mstat;
-       volatile unchar mchange;
-       volatile unchar mint;
-       volatile unchar lstat;
-
-       volatile unchar mtran;
-       volatile unchar orun;
-       volatile unchar startca;
-       volatile unchar stopca;
-       volatile unchar startc;
-       volatile unchar stopc;
-       volatile unchar vnext;
-       volatile unchar hflow;
-
-       volatile unchar fillc;
-       volatile unchar ochar;
-       volatile unchar omask;
-
-       unchar filler7;
-       unchar filler8[28];
+       u32 filler1;
+       u32 filler2;
+       u16 tseg;
+       u16 tin;
+       u16 tout;
+       u16 tmax;
+
+       u16 rseg;
+       u16 rin;
+       u16 rout;
+       u16 rmax;
+
+       u16 tlow;
+       u16 rlow;
+       u16 rhigh;
+       u16 incr;
+
+       u16 etime;
+       u16 edelay;
+       unchar *dev;
+
+       u16 iflag;
+       u16 oflag;
+       u16 cflag;
+       u16 gmask;
+
+       u16 col;
+       u16 delay;
+       u16 imask;
+       u16 tflush;
+
+       u32 filler3;
+       u32 filler4;
+       u32 filler5;
+       u32 filler6;
+
+       u8 num;
+       u8 ract;
+       u8 bstat;
+       u8 tbusy;
+       u8 iempty;
+       u8 ilow;
+       u8 idata;
+       u8 eflag;
+
+       u8 tflag;
+       u8 rflag;
+       u8 xmask;
+       u8 xval;
+       u8 mstat;
+       u8 mchange;
+       u8 mint;
+       u8 lstat;
+
+       u8 mtran;
+       u8 orun;
+       u8 startca;
+       u8 stopca;
+       u8 startc;
+       u8 stopc;
+       u8 vnext;
+       u8 hflow;
+
+       u8 fillc;
+       u8 ochar;
+       u8 omask;
+
+       u8 filler7;
+       u8 filler8[28];
 }; 
 
 
index 123417e430405285dbe282fd3a5d99dd0e53910f..56ace9d5e2aef75b4cd095b3424e4cbc00094b23 100644 (file)
@@ -23,13 +23,6 @@ config DRM_TDFX
          Choose this option if you have a 3dfx Banshee or Voodoo3 (or later),
          graphics card.  If M is selected, the module will be called tdfx.
 
-config DRM_GAMMA
-       tristate "3dlabs GMX 2000"
-       depends on DRM && BROKEN
-       help
-         This is the old gamma driver, please tell me if it might actually
-         work.
-
 config DRM_R128
        tristate "ATI Rage 128"
        depends on DRM && PCI
@@ -82,7 +75,7 @@ endchoice
 
 config DRM_MGA
        tristate "Matrox g200/g400"
-       depends on DRM && AGP
+       depends on DRM
        help
          Choose this option if you have a Matrox G200, G400 or G450 graphics
          card.  If M is selected, the module will be called mga.  AGP
@@ -103,3 +96,10 @@ config DRM_VIA
          Choose this option if you have a Via unichrome or compatible video
          chipset. If M is selected the module will be called via.
 
+config DRM_SAVAGE
+       tristate "Savage video cards"
+       depends on DRM
+       help
+         Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
+         chipset. If M is selected the module will be called savage.
+
index ddd941045b1f96478742450ae26a1550f941a8df..e41060c76226cd66038d9abfe31b025245b25c72 100644 (file)
@@ -8,16 +8,16 @@ drm-objs    :=        drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
                drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
                drm_sysfs.o
 
-gamma-objs  := gamma_drv.o gamma_dma.o
 tdfx-objs   := tdfx_drv.o
 r128-objs   := r128_drv.o r128_cce.o r128_state.o r128_irq.o
 mga-objs    := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o
 i810-objs   := i810_drv.o i810_dma.o
 i830-objs   := i830_drv.o i830_dma.o i830_irq.o
 i915-objs   := i915_drv.o i915_dma.o i915_irq.o i915_mem.o
-radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o
+radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o
 ffb-objs    := ffb_drv.o ffb_context.o
 sis-objs    := sis_drv.o sis_ds.o sis_mm.o
+savage-objs := savage_drv.o savage_bci.o savage_state.o
 via-objs    := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o
 
 ifeq ($(CONFIG_COMPAT),y)
@@ -29,7 +29,6 @@ i915-objs   += i915_ioc32.o
 endif
 
 obj-$(CONFIG_DRM)      += drm.o
-obj-$(CONFIG_DRM_GAMMA) += gamma.o
 obj-$(CONFIG_DRM_TDFX) += tdfx.o
 obj-$(CONFIG_DRM_R128) += r128.o
 obj-$(CONFIG_DRM_RADEON)+= radeon.o
@@ -39,5 +38,7 @@ obj-$(CONFIG_DRM_I830)        += i830.o
 obj-$(CONFIG_DRM_I915)  += i915.o
 obj-$(CONFIG_DRM_FFB)   += ffb.o
 obj-$(CONFIG_DRM_SIS)   += sis.o
+obj-$(CONFIG_DRM_SAVAGE)+= savage.o
 obj-$(CONFIG_DRM_VIA)  +=via.o
 
+
index e8371dd87fbca0867953f1e53c07b5ec8b5a19d5..fc6598a81acdd5888fd11893f941e75fa0d13d70 100644 (file)
@@ -98,7 +98,7 @@
 #define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT))
 
 
-typedef unsigned long drm_handle_t;
+typedef unsigned int  drm_handle_t;
 typedef unsigned int  drm_context_t;
 typedef unsigned int  drm_drawable_t;
 typedef unsigned int  drm_magic_t;
@@ -209,7 +209,8 @@ typedef enum drm_map_type {
        _DRM_REGISTERS      = 1,  /**< no caching, no core dump */
        _DRM_SHM            = 2,  /**< shared, cached */
        _DRM_AGP            = 3,  /**< AGP/GART */
-       _DRM_SCATTER_GATHER = 4   /**< Scatter/gather memory for PCI DMA */
+       _DRM_SCATTER_GATHER = 4,  /**< Scatter/gather memory for PCI DMA */
+       _DRM_CONSISTENT     = 5,  /**< Consistent memory for PCI DMA */
 } drm_map_type_t;
 
 
@@ -368,7 +369,8 @@ typedef struct drm_buf_desc {
        enum {
                _DRM_PAGE_ALIGN = 0x01, /**< Align on page boundaries for DMA */
                _DRM_AGP_BUFFER = 0x02, /**< Buffer is in AGP space */
-               _DRM_SG_BUFFER  = 0x04  /**< Scatter/gather memory buffer */
+               _DRM_SG_BUFFER  = 0x04, /**< Scatter/gather memory buffer */
+               _DRM_FB_BUFFER  = 0x08  /**< Buffer is in frame buffer */
        }             flags;
        unsigned long agp_start; /**< 
                                  * Start address of where the AGP buffers are
index 5df09cc8c6db62a7eab1a2a3e1d6061bbb54c997..6f98701dfe15da844eb19aa5e1483f6b73b21a97 100644 (file)
@@ -53,7 +53,6 @@
 #include <linux/init.h>
 #include <linux/file.h>
 #include <linux/pci.h>
-#include <linux/version.h>
 #include <linux/jiffies.h>
 #include <linux/smp_lock.h>    /* For (un)lock_kernel */
 #include <linux/mm.h>
@@ -96,6 +95,7 @@
 #define DRIVER_IRQ_SHARED  0x80
 #define DRIVER_IRQ_VBL     0x100
 #define DRIVER_DMA_QUEUE   0x200
+#define DRIVER_FB_DMA      0x400
 
 /***********************************************************************/
 /** \name Begin the DRM... */
 #define pte_unmap(pte)
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
-static inline struct page * vmalloc_to_page(void * vmalloc_addr)
-{
-       unsigned long addr = (unsigned long) vmalloc_addr;
-       struct page *page = NULL;
-       pgd_t *pgd = pgd_offset_k(addr);
-       pmd_t *pmd;
-       pte_t *ptep, pte;
-  
-       if (!pgd_none(*pgd)) {
-               pmd = pmd_offset(pgd, addr);
-               if (!pmd_none(*pmd)) {
-                       preempt_disable();
-                       ptep = pte_offset_map(pmd, addr);
-                       pte = *ptep;
-                       if (pte_present(pte))
-                               page = pte_page(pte);
-                       pte_unmap(ptep);
-                       preempt_enable();
-               }
-       }
-       return page;
-}
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#define DRM_RPR_ARG(vma)
-#else
 #define DRM_RPR_ARG(vma) vma,
-#endif
 
 #define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
 
@@ -474,7 +445,8 @@ typedef struct drm_device_dma {
        unsigned long     byte_count;
        enum {
                _DRM_DMA_USE_AGP = 0x01,
-               _DRM_DMA_USE_SG  = 0x02
+               _DRM_DMA_USE_SG  = 0x02,
+               _DRM_DMA_USE_FB  = 0x04
        } flags;
 
 } drm_device_dma_t;
@@ -525,12 +497,19 @@ typedef struct drm_sigdata {
        drm_hw_lock_t *lock;
 } drm_sigdata_t;
 
+typedef struct drm_dma_handle {
+       dma_addr_t busaddr;
+       void *vaddr;
+       size_t size;
+} drm_dma_handle_t;
+
 /**
  * Mappings list
  */
 typedef struct drm_map_list {
        struct list_head        head;   /**< list head */
        drm_map_t               *map;   /**< mapping */
+       unsigned int user_token;
 } drm_map_list_t;
 
 typedef drm_map_t drm_local_map_t;
@@ -578,7 +557,22 @@ struct drm_driver {
        int (*kernel_context_switch)(struct drm_device *dev, int old, int new);
        void (*kernel_context_switch_unlock)(struct drm_device *dev, drm_lock_t *lock);
        int (*vblank_wait)(struct drm_device *dev, unsigned int *sequence);
+       
+       /**
+        * Called by \c drm_device_is_agp.  Typically used to determine if a
+        * card is really attached to AGP or not.
+        *
+        * \param dev  DRM device handle
+        *
+        * \returns
+        * One of three values is returned depending on whether or not the
+        * card is absolutely \b not AGP (return of 0), absolutely \b is AGP
+        * (return of 1), or may or may not be AGP (return of 2).
+        */
+       int (*device_is_agp) (struct drm_device * dev);
+
        /* these have to be filled in */
+  
        int (*postinit)(struct drm_device *, unsigned long flags);
        irqreturn_t (*irq_handler)( DRM_IRQ_ARGS );
        void (*irq_preinstall)(struct drm_device *dev);
@@ -722,11 +716,7 @@ typedef struct drm_device {
        int               pci_slot;     /**< PCI slot number */
        int               pci_func;     /**< PCI function number */
 #ifdef __alpha__
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3)
-       struct pci_controler *hose;
-#else
        struct pci_controller *hose;
-#endif
 #endif
        drm_sg_mem_t      *sg;  /**< Scatter gather memory */
        unsigned long     *ctx_bitmap;  /**< context bitmap */
@@ -736,6 +726,7 @@ typedef struct drm_device {
 
        struct            drm_driver *driver;
        drm_local_map_t   *agp_buffer_map;
+       unsigned int agp_buffer_token;
        drm_head_t primary;             /**< primary screen head */
 } drm_device_t;
 
@@ -806,7 +797,7 @@ extern void      *drm_ioremap_nocache(unsigned long offset, unsigned long size,
                                           drm_device_t *dev);
 extern void         drm_ioremapfree(void *pt, unsigned long size, drm_device_t *dev);
 
-extern DRM_AGP_MEM   *drm_alloc_agp(struct agp_bridge_data *bridge, int pages, u32 type);
+extern DRM_AGP_MEM   *drm_alloc_agp(drm_device_t *dev, int pages, u32 type);
 extern int           drm_free_agp(DRM_AGP_MEM *handle, int pages);
 extern int           drm_bind_agp(DRM_AGP_MEM *handle, unsigned int start);
 extern int           drm_unbind_agp(DRM_AGP_MEM *handle);
@@ -881,11 +872,19 @@ extern int             drm_lock_free(drm_device_t *dev,
                                    unsigned int context);
 
                                /* Buffer management support (drm_bufs.h) */
+extern int drm_addbufs_agp(drm_device_t *dev, drm_buf_desc_t *request);
+extern int drm_addbufs_pci(drm_device_t *dev, drm_buf_desc_t *request);
+extern int drm_addmap(drm_device_t *dev, unsigned int offset,
+                     unsigned int size, drm_map_type_t type,
+                     drm_map_flags_t flags, drm_local_map_t **map_ptr);
+extern int drm_addmap_ioctl(struct inode *inode, struct file *filp,
+                           unsigned int cmd, unsigned long arg);
+extern int drm_rmmap(drm_device_t *dev, drm_local_map_t *map);
+extern int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map);
+extern int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
+                          unsigned int cmd, unsigned long arg);
+
 extern int          drm_order( unsigned long size );
-extern int          drm_addmap( struct inode *inode, struct file *filp,
-                                 unsigned int cmd, unsigned long arg );
-extern int          drm_rmmap( struct inode *inode, struct file *filp,
-                                unsigned int cmd, unsigned long arg );
 extern int          drm_addbufs( struct inode *inode, struct file *filp,
                                   unsigned int cmd, unsigned long arg );
 extern int          drm_infobufs( struct inode *inode, struct file *filp,
@@ -896,6 +895,10 @@ extern int      drm_freebufs( struct inode *inode, struct file *filp,
                                    unsigned int cmd, unsigned long arg );
 extern int          drm_mapbufs( struct inode *inode, struct file *filp,
                                   unsigned int cmd, unsigned long arg );
+extern unsigned long drm_get_resource_start(drm_device_t *dev,
+                                           unsigned int resource);
+extern unsigned long drm_get_resource_len(drm_device_t *dev,
+                                         unsigned int resource);
 
                                /* DMA support (drm_dma.h) */
 extern int          drm_dma_setup(drm_device_t *dev);
@@ -919,15 +922,18 @@ extern void          drm_vbl_send_signals( drm_device_t *dev );
 
                                /* AGP/GART support (drm_agpsupport.h) */
 extern drm_agp_head_t *drm_agp_init(drm_device_t *dev);
-extern int            drm_agp_acquire(struct inode *inode, struct file *filp,
-                                      unsigned int cmd, unsigned long arg);
-extern void           drm_agp_do_release(drm_device_t *dev);
-extern int            drm_agp_release(struct inode *inode, struct file *filp,
-                                      unsigned int cmd, unsigned long arg);
-extern int            drm_agp_enable(struct inode *inode, struct file *filp,
-                                     unsigned int cmd, unsigned long arg);
-extern int            drm_agp_info(struct inode *inode, struct file *filp,
-                                   unsigned int cmd, unsigned long arg);
+extern int drm_agp_acquire(drm_device_t * dev);
+extern int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp,
+                          unsigned int cmd, unsigned long arg);
+extern int drm_agp_release(drm_device_t *dev);
+extern int drm_agp_release_ioctl(struct inode *inode, struct file *filp,
+                          unsigned int cmd, unsigned long arg);
+extern int drm_agp_enable(drm_device_t *dev, drm_agp_mode_t mode);
+extern int drm_agp_enable_ioctl(struct inode *inode, struct file *filp,
+                         unsigned int cmd, unsigned long arg);
+extern int drm_agp_info(drm_device_t * dev, drm_agp_info_t *info);
+extern int drm_agp_info_ioctl(struct inode *inode, struct file *filp,
+                       unsigned int cmd, unsigned long arg);
 extern int            drm_agp_alloc(struct inode *inode, struct file *filp,
                                     unsigned int cmd, unsigned long arg);
 extern int            drm_agp_free(struct inode *inode, struct file *filp,
@@ -976,12 +982,10 @@ extern int            drm_ati_pcigart_cleanup(drm_device_t *dev,
                                               unsigned long addr,
                                               dma_addr_t bus_addr);
 
-extern void *drm_pci_alloc(drm_device_t * dev, size_t size,
-                          size_t align, dma_addr_t maxaddr,
-                          dma_addr_t * busaddr);
-
-extern void drm_pci_free(drm_device_t * dev, size_t size,
-                        void *vaddr, dma_addr_t busaddr);
+extern drm_dma_handle_t *drm_pci_alloc(drm_device_t *dev, size_t size,
+                                      size_t align, dma_addr_t maxaddr);
+extern void __drm_pci_free(drm_device_t *dev, drm_dma_handle_t *dmah);
+extern void drm_pci_free(drm_device_t *dev, drm_dma_handle_t *dmah);
 
                               /* sysfs support (drm_sysfs.c) */
 struct drm_sysfs_class;
@@ -1012,17 +1016,26 @@ static __inline__ void drm_core_ioremapfree(struct drm_map *map, struct drm_devi
                drm_ioremapfree( map->handle, map->size, dev );
 }
 
-static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev, unsigned long offset)
+static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev, unsigned int token)
 {
-       struct list_head *_list;
-       list_for_each( _list, &dev->maplist->head ) {
-               drm_map_list_t *_entry = list_entry( _list, drm_map_list_t, head );
-               if ( _entry->map &&
-                    _entry->map->offset == offset ) {
+       drm_map_list_t *_entry;
+       list_for_each_entry(_entry, &dev->maplist->head, head)
+               if (_entry->user_token == token)
                        return _entry->map;
+       return NULL;
+}
+
+static __inline__ int drm_device_is_agp(drm_device_t *dev)
+{
+       if ( dev->driver->device_is_agp != NULL ) {
+               int err = (*dev->driver->device_is_agp)( dev );
+       
+               if (err != 2) {
+                       return err;
                }
        }
-       return NULL;
+
+       return pci_find_capability(dev->pdev, PCI_CAP_ID_AGP);
 }
 
 static __inline__ void drm_core_dropmap(struct drm_map *map)
index 8d94c0b5fa44f00c0859b3c63e1103d5876bc6bc..8c215adcb4b2b623e4848b50fba212a66956799a 100644 (file)
@@ -37,7 +37,7 @@
 #if __OS_HAS_AGP
 
 /**
- * AGP information ioctl.
+ * Get AGP information.
  *
  * \param inode device inode.
  * \param filp file pointer.
  * Verifies the AGP device has been initialized and acquired and fills in the
  * drm_agp_info structure with the information in drm_agp_head::agp_info.
  */
-int drm_agp_info(struct inode *inode, struct file *filp,
-                 unsigned int cmd, unsigned long arg)
+int drm_agp_info(drm_device_t *dev, drm_agp_info_t *info)
 {
-       drm_file_t       *priv   = filp->private_data;
-       drm_device_t     *dev    = priv->head->dev;
        DRM_AGP_KERN     *kern;
-       drm_agp_info_t   info;
 
        if (!dev->agp || !dev->agp->acquired)
                return -EINVAL;
 
        kern                   = &dev->agp->agp_info;
-       info.agp_version_major = kern->version.major;
-       info.agp_version_minor = kern->version.minor;
-       info.mode              = kern->mode;
-       info.aperture_base     = kern->aper_base;
-       info.aperture_size     = kern->aper_size * 1024 * 1024;
-       info.memory_allowed    = kern->max_memory << PAGE_SHIFT;
-       info.memory_used       = kern->current_memory << PAGE_SHIFT;
-       info.id_vendor         = kern->device->vendor;
-       info.id_device         = kern->device->device;
-
-       if (copy_to_user((drm_agp_info_t __user *)arg, &info, sizeof(info)))
+       info->agp_version_major = kern->version.major;
+       info->agp_version_minor = kern->version.minor;
+       info->mode              = kern->mode;
+       info->aperture_base     = kern->aper_base;
+       info->aperture_size     = kern->aper_size * 1024 * 1024;
+       info->memory_allowed    = kern->max_memory << PAGE_SHIFT;
+       info->memory_used       = kern->current_memory << PAGE_SHIFT;
+       info->id_vendor         = kern->device->vendor;
+       info->id_device         = kern->device->device;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_agp_info);
+
+int drm_agp_info_ioctl(struct inode *inode, struct file *filp,
+                unsigned int cmd, unsigned long arg)
+{
+       drm_file_t *priv = filp->private_data;
+       drm_device_t *dev = priv->head->dev;
+       drm_agp_info_t info;
+       int err;
+
+       err = drm_agp_info(dev, &info);
+       if (err)
+               return err;
+       
+       if (copy_to_user((drm_agp_info_t __user *) arg, &info, sizeof(info)))
                return -EFAULT;
        return 0;
 }
 
 /**
- * Acquire the AGP device (ioctl).
+ * Acquire the AGP device.
  *
- * \param inode device inode.
- * \param filp file pointer.
- * \param cmd command.
- * \param arg user argument.
+ * \param dev DRM device that is to acquire AGP
  * \return zero on success or a negative number on failure. 
  *
  * Verifies the AGP device hasn't been acquired before and calls
- * agp_acquire().
+ * \c agp_backend_acquire.
  */
-int drm_agp_acquire(struct inode *inode, struct file *filp,
-                    unsigned int cmd, unsigned long arg)
+int drm_agp_acquire(drm_device_t *dev)
 {
-       drm_file_t       *priv   = filp->private_data;
-       drm_device_t     *dev    = priv->head->dev;
-
        if (!dev->agp)
                return -ENODEV;
        if (dev->agp->acquired)
@@ -102,9 +107,10 @@ int drm_agp_acquire(struct inode *inode, struct file *filp,
        dev->agp->acquired = 1;
        return 0;
 }
+EXPORT_SYMBOL(drm_agp_acquire);
 
 /**
- * Release the AGP device (ioctl).
+ * Acquire the AGP device (ioctl).
  *
  * \param inode device inode.
  * \param filp file pointer.
@@ -112,63 +118,80 @@ int drm_agp_acquire(struct inode *inode, struct file *filp,
  * \param arg user argument.
  * \return zero on success or a negative number on failure.
  *
- * Verifies the AGP device has been acquired and calls agp_backend_release().
+ * Verifies the AGP device hasn't been acquired before and calls
+ * \c agp_backend_acquire.
  */
-int drm_agp_release(struct inode *inode, struct file *filp,
-                    unsigned int cmd, unsigned long arg)
+int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp,
+                         unsigned int cmd, unsigned long arg)
 {
-       drm_file_t       *priv   = filp->private_data;
-       drm_device_t     *dev    = priv->head->dev;
+       drm_file_t *priv = filp->private_data;
+       
+       return drm_agp_acquire( (drm_device_t *) priv->head->dev );
+}
 
+/**
+ * Release the AGP device.
+ *
+ * \param dev DRM device that is to release AGP
+ * \return zero on success or a negative number on failure.
+ *
+ * Verifies the AGP device has been acquired and calls \c agp_backend_release.
+ */
+int drm_agp_release(drm_device_t *dev)
+{
        if (!dev->agp || !dev->agp->acquired)
                return -EINVAL;
        agp_backend_release(dev->agp->bridge);
        dev->agp->acquired = 0;
        return 0;
-
 }
+EXPORT_SYMBOL(drm_agp_release);
 
-/**
- * Release the AGP device.
- *
- * Calls agp_backend_release().
- */
-void drm_agp_do_release(drm_device_t *dev)
+int drm_agp_release_ioctl(struct inode *inode, struct file *filp,
+                         unsigned int cmd, unsigned long arg)
 {
-  agp_backend_release(dev->agp->bridge);
+       drm_file_t *priv = filp->private_data;
+       drm_device_t *dev = priv->head->dev;
+       
+       return drm_agp_release(dev);
 }
 
 /**
  * Enable the AGP bus.
  * 
- * \param inode device inode.
- * \param filp file pointer.
- * \param cmd command.
- * \param arg pointer to a drm_agp_mode structure.
+ * \param dev DRM device that has previously acquired AGP.
+ * \param mode Requested AGP mode.
  * \return zero on success or a negative number on failure.
  *
  * Verifies the AGP device has been acquired but not enabled, and calls
- * agp_enable().
+ * \c agp_enable.
  */
-int drm_agp_enable(struct inode *inode, struct file *filp,
-                   unsigned int cmd, unsigned long arg)
+int drm_agp_enable(drm_device_t *dev, drm_agp_mode_t mode)
 {
-       drm_file_t       *priv   = filp->private_data;
-       drm_device_t     *dev    = priv->head->dev;
-       drm_agp_mode_t   mode;
-
        if (!dev->agp || !dev->agp->acquired)
                return -EINVAL;
 
-       if (copy_from_user(&mode, (drm_agp_mode_t __user *)arg, sizeof(mode)))
-               return -EFAULT;
-
        dev->agp->mode    = mode.mode;
        agp_enable(dev->agp->bridge, mode.mode);
        dev->agp->base    = dev->agp->agp_info.aper_base;
        dev->agp->enabled = 1;
        return 0;
 }
+EXPORT_SYMBOL(drm_agp_enable);
+
+int drm_agp_enable_ioctl(struct inode *inode, struct file *filp,
+                  unsigned int cmd, unsigned long arg)
+{
+       drm_file_t *priv = filp->private_data;
+       drm_device_t *dev = priv->head->dev;
+       drm_agp_mode_t mode;
+
+
+       if (copy_from_user(&mode, (drm_agp_mode_t __user *) arg, sizeof(mode)))
+               return -EFAULT;
+
+       return drm_agp_enable(dev, mode);
+}
 
 /**
  * Allocate AGP memory.
@@ -206,7 +229,7 @@ int drm_agp_alloc(struct inode *inode, struct file *filp,
        pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE;
        type = (u32) request.type;
 
-       if (!(memory = drm_alloc_agp(dev->agp->bridge, pages, type))) {
+       if (!(memory = drm_alloc_agp(dev, pages, type))) {
                drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
                return -ENOMEM;
        }
@@ -403,13 +426,8 @@ drm_agp_head_t *drm_agp_init(drm_device_t *dev)
                return NULL;
        }
        head->memory = NULL;
-#if LINUX_VERSION_CODE <= 0x020408
-       head->cant_use_aperture = 0;
-       head->page_mask = ~(0xfff);
-#else
        head->cant_use_aperture = head->agp_info.cant_use_aperture;
        head->page_mask = head->agp_info.page_mask;
-#endif
 
        return head;
 }
@@ -436,6 +454,7 @@ int drm_agp_bind_memory(DRM_AGP_MEM *handle, off_t start)
                return -EINVAL;
        return agp_bind_memory(handle, start);
 }
+EXPORT_SYMBOL(drm_agp_bind_memory);
 
 /** Calls agp_unbind_memory() */
 int drm_agp_unbind_memory(DRM_AGP_MEM *handle)
index 4c6191d231b8e06e20d876af0287d03df9335153..f28e70ae66065d4a498760af053d1ea5fa0b6a99 100644 (file)
 #include <linux/vmalloc.h>
 #include "drmP.h"
 
-/**
- * Compute size order.  Returns the exponent of the smaller power of two which
- * is greater or equal to given number.
- * 
- * \param size size.
- * \return order.
- *
- * \todo Can be made faster.
- */
-int drm_order( unsigned long size )
+unsigned long drm_get_resource_start(drm_device_t *dev, unsigned int resource)
 {
-       int order;
-       unsigned long tmp;
+       return pci_resource_start(dev->pdev, resource);
+}
+EXPORT_SYMBOL(drm_get_resource_start);
 
-       for (order = 0, tmp = size >> 1; tmp; tmp >>= 1, order++)
-               ;
+unsigned long drm_get_resource_len(drm_device_t *dev, unsigned int resource)
+{
+       return pci_resource_len(dev->pdev, resource);
+}
+EXPORT_SYMBOL(drm_get_resource_len);
 
-       if (size & (size - 1))
-               ++order;
+static drm_map_list_t *drm_find_matching_map(drm_device_t *dev,
+                                            drm_local_map_t *map)
+{
+       struct list_head *list;
 
-       return order;
+       list_for_each(list, &dev->maplist->head) {
+               drm_map_list_t *entry = list_entry(list, drm_map_list_t, head);
+               if (entry->map && map->type == entry->map->type &&
+                   entry->map->offset == map->offset) {
+                       return entry;
+               }
+       }
+
+       return NULL;
 }
-EXPORT_SYMBOL(drm_order);
 
-#ifdef CONFIG_COMPAT
 /*
- * Used to allocate 32-bit handles for _DRM_SHM regions
- * The 0x10000000 value is chosen to be out of the way of
- * FB/register and GART physical addresses.
+ * Used to allocate 32-bit handles for mappings.
  */
-static unsigned int map32_handle = 0x10000000;
+#define START_RANGE 0x10000000
+#define END_RANGE 0x40000000
+
+#ifdef _LP64
+static __inline__ unsigned int HandleID(unsigned long lhandle, drm_device_t *dev) 
+{
+       static unsigned int map32_handle = START_RANGE;
+       unsigned int hash;
+
+       if (lhandle & 0xffffffff00000000) {
+               hash = map32_handle;
+               map32_handle += PAGE_SIZE;
+               if (map32_handle > END_RANGE)
+                       map32_handle = START_RANGE;
+       } else 
+               hash = lhandle;
+
+       while (1) {
+               drm_map_list_t *_entry;
+               list_for_each_entry(_entry, &dev->maplist->head,head) {
+                       if (_entry->user_token == hash)
+                               break;
+               }
+               if (&_entry->head == &dev->maplist->head)
+                       return hash;
+
+               hash += PAGE_SIZE;
+               map32_handle += PAGE_SIZE;
+       }
+}
+#else
+# define HandleID(x,dev) (unsigned int)(x)
 #endif
 
 /**
@@ -82,25 +114,22 @@ static unsigned int map32_handle = 0x10000000;
  * type.  Adds the map to the map list drm_device::maplist. Adds MTRR's where
  * applicable and if supported by the kernel.
  */
-int drm_addmap( struct inode *inode, struct file *filp,
-                unsigned int cmd, unsigned long arg )
+int drm_addmap_core(drm_device_t * dev, unsigned int offset,
+                   unsigned int size, drm_map_type_t type,
+                   drm_map_flags_t flags, drm_map_list_t **maplist)
 {
-       drm_file_t *priv = filp->private_data;
-       drm_device_t *dev = priv->head->dev;
        drm_map_t *map;
-       drm_map_t __user *argp = (void __user *)arg;
        drm_map_list_t *list;
-
-       if ( !(filp->f_mode & 3) ) return -EACCES; /* Require read/write */
+       drm_dma_handle_t *dmah;
 
        map = drm_alloc( sizeof(*map), DRM_MEM_MAPS );
        if ( !map )
                return -ENOMEM;
 
-       if ( copy_from_user( map, argp, sizeof(*map) ) ) {
-               drm_free( map, sizeof(*map), DRM_MEM_MAPS );
-               return -EFAULT;
-       }
+       map->offset = offset;
+       map->size = size;
+       map->flags = flags;
+       map->type = type;
 
        /* Only allow shared memory to be removable since we only keep enough
         * book keeping information about shared memory to allow for removal
@@ -122,7 +151,7 @@ int drm_addmap( struct inode *inode, struct file *filp,
        switch ( map->type ) {
        case _DRM_REGISTERS:
        case _DRM_FRAME_BUFFER:
-#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__)
+#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__)
                if ( map->offset + map->size < map->offset ||
                     map->offset < virt_to_phys(high_memory) ) {
                        drm_free( map, sizeof(*map), DRM_MEM_MAPS );
@@ -132,6 +161,24 @@ int drm_addmap( struct inode *inode, struct file *filp,
 #ifdef __alpha__
                map->offset += dev->hose->mem_space->start;
 #endif
+               /* Some drivers preinitialize some maps, without the X Server
+                * needing to be aware of it.  Therefore, we just return success
+                * when the server tries to create a duplicate map.
+                */
+               list = drm_find_matching_map(dev, map);
+               if (list != NULL) {
+                       if (list->map->size != map->size) {
+                               DRM_DEBUG("Matching maps of type %d with "
+                                  "mismatched sizes, (%ld vs %ld)\n",
+                                   map->type, map->size, list->map->size);
+                               list->map->size = map->size;
+                       }
+
+                       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                       *maplist = list;
+                       return 0;
+               }
+
                if (drm_core_has_MTRR(dev)) {
                        if ( map->type == _DRM_FRAME_BUFFER ||
                             (map->flags & _DRM_WRITE_COMBINING) ) {
@@ -178,9 +225,22 @@ int drm_addmap( struct inode *inode, struct file *filp,
                        drm_free(map, sizeof(*map), DRM_MEM_MAPS);
                        return -EINVAL;
                }
-               map->offset += dev->sg->handle;
+               map->offset += (unsigned long)dev->sg->virtual;
+               break;
+       case _DRM_CONSISTENT: 
+               /* dma_addr_t is 64bit on i386 with CONFIG_HIGHMEM64G,
+                * As we're limiting the address to 2^32-1 (or less),
+                * casting it down to 32 bits is no problem, but we
+                * need to point to a 64bit variable first. */
+               dmah = drm_pci_alloc(dev, map->size, map->size, 0xffffffffUL);
+               if (!dmah) {
+                       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                       return -ENOMEM;
+               }
+               map->handle = dmah->vaddr;
+               map->offset = (unsigned long)dmah->busaddr;
+               kfree(dmah);
                break;
-
        default:
                drm_free( map, sizeof(*map), DRM_MEM_MAPS );
                return -EINVAL;
@@ -196,17 +256,57 @@ int drm_addmap( struct inode *inode, struct file *filp,
 
        down(&dev->struct_sem);
        list_add(&list->head, &dev->maplist->head);
-#ifdef CONFIG_COMPAT
-       /* Assign a 32-bit handle for _DRM_SHM mappings */
+       /* Assign a 32-bit handle */
        /* We do it here so that dev->struct_sem protects the increment */
-       if (map->type == _DRM_SHM)
-               map->offset = map32_handle += PAGE_SIZE;
-#endif
+       list->user_token = HandleID(map->type==_DRM_SHM
+                                   ? (unsigned long)map->handle
+                                   : map->offset, dev);
        up(&dev->struct_sem);
 
-       if ( copy_to_user( argp, map, sizeof(*map) ) )
+       *maplist = list;
+       return 0;
+}
+
+int drm_addmap(drm_device_t *dev, unsigned int offset,
+              unsigned int size, drm_map_type_t type,
+              drm_map_flags_t flags, drm_local_map_t **map_ptr)
+{
+       drm_map_list_t *list;
+       int rc;
+
+       rc = drm_addmap_core(dev, offset, size, type, flags, &list);
+       if (!rc)
+               *map_ptr = list->map;
+       return rc;
+}
+EXPORT_SYMBOL(drm_addmap);
+
+int drm_addmap_ioctl(struct inode *inode, struct file *filp,
+                    unsigned int cmd, unsigned long arg)
+{
+       drm_file_t *priv = filp->private_data;
+       drm_device_t *dev = priv->head->dev;
+       drm_map_t map;
+       drm_map_list_t *maplist;
+       drm_map_t __user *argp = (void __user *)arg;
+       int err;
+
+       if (!(filp->f_mode & 3))
+               return -EACCES; /* Require read/write */
+
+       if (copy_from_user(& map, argp, sizeof(map))) {
                return -EFAULT;
-       if (copy_to_user(&argp->handle, &map->offset, sizeof(map->offset)))
+       }
+
+       err = drm_addmap_core(dev, map.offset, map.size, map.type, map.flags,
+                             &maplist);
+
+       if (err) 
+               return err;
+
+       if (copy_to_user(argp, maplist->map, sizeof(drm_map_t)))
+               return -EFAULT;
+       if (put_user(maplist->user_token, &argp->handle))
                return -EFAULT;
        return 0;
 }
@@ -226,81 +326,138 @@ int drm_addmap( struct inode *inode, struct file *filp,
  * its being used, and free any associate resource (such as MTRR's) if it's not
  * being on use.
  *
- * \sa addmap().
+ * \sa drm_addmap
  */
-int drm_rmmap(struct inode *inode, struct file *filp,
-              unsigned int cmd, unsigned long arg)
+int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
 {
-       drm_file_t      *priv   = filp->private_data;
-       drm_device_t    *dev    = priv->head->dev;
        struct list_head *list;
        drm_map_list_t *r_list = NULL;
-       drm_vma_entry_t *pt, *prev;
-       drm_map_t *map;
+       drm_dma_handle_t dmah;
+
+       /* Find the list entry for the map and remove it */
+       list_for_each(list, &dev->maplist->head) {
+               r_list = list_entry(list, drm_map_list_t, head);
+
+               if (r_list->map == map) {
+                       list_del(list);
+                       drm_free(list, sizeof(*list), DRM_MEM_MAPS);
+                       break;
+               }
+       }
+
+       /* List has wrapped around to the head pointer, or it's empty and we
+        * didn't find anything.
+        */
+       if (list == (&dev->maplist->head)) {
+               return -EINVAL;
+       }
+
+       switch (map->type) {
+       case _DRM_REGISTERS:
+               drm_ioremapfree(map->handle, map->size, dev);
+               /* FALLTHROUGH */
+       case _DRM_FRAME_BUFFER:
+               if (drm_core_has_MTRR(dev) && map->mtrr >= 0) {
+                       int retcode;
+                       retcode = mtrr_del(map->mtrr, map->offset,
+                                          map->size);
+                       DRM_DEBUG ("mtrr_del=%d\n", retcode);
+               }
+               break;
+       case _DRM_SHM:
+               vfree(map->handle);
+               break;
+       case _DRM_AGP:
+       case _DRM_SCATTER_GATHER:
+               break;
+       case _DRM_CONSISTENT:
+               dmah.vaddr = map->handle;
+               dmah.busaddr = map->offset;
+               dmah.size = map->size;
+               __drm_pci_free(dev, &dmah);
+               break;
+       }
+       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_rmmap_locked);
+
+int drm_rmmap(drm_device_t *dev, drm_local_map_t *map)
+{
+       int ret;
+
+       down(&dev->struct_sem);
+       ret = drm_rmmap_locked(dev, map);
+       up(&dev->struct_sem);
+
+       return ret;
+}
+EXPORT_SYMBOL(drm_rmmap);
+
+/* The rmmap ioctl appears to be unnecessary.  All mappings are torn down on
+ * the last close of the device, and this is necessary for cleanup when things
+ * exit uncleanly.  Therefore, having userland manually remove mappings seems
+ * like a pointless exercise since they're going away anyway.
+ *
+ * One use case might be after addmap is allowed for normal users for SHM and
+ * gets used by drivers that the server doesn't need to care about.  This seems
+ * unlikely.
+ */
+int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
+                   unsigned int cmd, unsigned long arg)
+{
+       drm_file_t *priv = filp->private_data;
+       drm_device_t *dev = priv->head->dev;
        drm_map_t request;
-       int found_maps = 0;
+       drm_local_map_t *map = NULL;
+       struct list_head *list;
+       int ret;
 
-       if (copy_from_user(&request, (drm_map_t __user *)arg,
-                          sizeof(request))) {
+       if (copy_from_user(&request, (drm_map_t __user *)arg, sizeof(request))) {
                return -EFAULT;
        }
 
        down(&dev->struct_sem);
-       list = &dev->maplist->head;
        list_for_each(list, &dev->maplist->head) {
-               r_list = list_entry(list, drm_map_list_t, head);
+               drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head);
 
-               if(r_list->map &&
-                  r_list->map->offset == (unsigned long) request.handle &&
-                  r_list->map->flags & _DRM_REMOVABLE) break;
+               if (r_list->map &&
+                   r_list->user_token == (unsigned long) request.handle &&
+                   r_list->map->flags & _DRM_REMOVABLE) {
+                       map = r_list->map;
+                       break;
+               }
        }
 
        /* List has wrapped around to the head pointer, or its empty we didn't
         * find anything.
         */
-       if(list == (&dev->maplist->head)) {
+       if (list == (&dev->maplist->head)) {
                up(&dev->struct_sem);
                return -EINVAL;
        }
-       map = r_list->map;
-       list_del(list);
-       drm_free(list, sizeof(*list), DRM_MEM_MAPS);
 
-       for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) {
-               if (pt->vma->vm_private_data == map) found_maps++;
-       }
+       if (!map)
+               return -EINVAL;
 
-       if(!found_maps) {
-               switch (map->type) {
-               case _DRM_REGISTERS:
-               case _DRM_FRAME_BUFFER:
-                 if (drm_core_has_MTRR(dev)) {
-                               if (map->mtrr >= 0) {
-                                       int retcode;
-                                       retcode = mtrr_del(map->mtrr,
-                                                          map->offset,
-                                                          map->size);
-                                       DRM_DEBUG("mtrr_del = %d\n", retcode);
-                               }
-                       }
-                       drm_ioremapfree(map->handle, map->size, dev);
-                       break;
-               case _DRM_SHM:
-                       vfree(map->handle);
-                       break;
-               case _DRM_AGP:
-               case _DRM_SCATTER_GATHER:
-                       break;
-               }
-               drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+       /* Register and framebuffer maps are permanent */
+       if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) {
+               up(&dev->struct_sem);
+               return 0;
        }
+
+       ret = drm_rmmap_locked(dev, map);
+
        up(&dev->struct_sem);
-       return 0;
+
+       return ret;
 }
 
 /**
  * Cleanup after an error on one of the addbufs() functions.
  *
+ * \param dev DRM device.
  * \param entry buffer entry where the error occurred.
  *
  * Frees any pages and buffers associated with the given entry.
@@ -344,25 +501,19 @@ static void drm_cleanup_buf_error(drm_device_t *dev, drm_buf_entry_t *entry)
 
 #if __OS_HAS_AGP
 /**
- * Add AGP buffers for DMA transfers (ioctl).
+ * Add AGP buffers for DMA transfers.
  *
- * \param inode device inode.
- * \param filp file pointer.
- * \param cmd command.
- * \param arg pointer to a drm_buf_desc_t request.
+ * \param dev drm_device_t to which the buffers are to be added.
+ * \param request pointer to a drm_buf_desc_t describing the request.
  * \return zero on success or a negative number on failure.
  * 
  * After some sanity checks creates a drm_buf structure for each buffer and
  * reallocates the buffer list of the same size order to accommodate the new
  * buffers.
  */
-static int drm_addbufs_agp( struct inode *inode, struct file *filp,
-                           unsigned int cmd, unsigned long arg )
+int drm_addbufs_agp(drm_device_t *dev, drm_buf_desc_t *request)
 {
-       drm_file_t *priv = filp->private_data;
-       drm_device_t *dev = priv->head->dev;
        drm_device_dma_t *dma = dev->dma;
-       drm_buf_desc_t request;
        drm_buf_entry_t *entry;
        drm_buf_t *buf;
        unsigned long offset;
@@ -376,25 +527,20 @@ static int drm_addbufs_agp( struct inode *inode, struct file *filp,
        int byte_count;
        int i;
        drm_buf_t **temp_buflist;
-       drm_buf_desc_t __user *argp = (void __user *)arg;
 
        if ( !dma ) return -EINVAL;
 
-       if ( copy_from_user( &request, argp,
-                            sizeof(request) ) )
-               return -EFAULT;
-
-       count = request.count;
-       order = drm_order( request.size );
+       count = request->count;
+       order = drm_order(request->size);
        size = 1 << order;
 
-       alignment  = (request.flags & _DRM_PAGE_ALIGN)
+       alignment  = (request->flags & _DRM_PAGE_ALIGN)
                ? PAGE_ALIGN(size) : size;
        page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
        total = PAGE_SIZE << page_order;
 
        byte_count = 0;
-       agp_offset = dev->agp->base + request.agp_start;
+       agp_offset = dev->agp->base + request->agp_start;
 
        DRM_DEBUG( "count:      %d\n",  count );
        DRM_DEBUG( "order:      %d\n",  order );
@@ -508,26 +654,20 @@ static int drm_addbufs_agp( struct inode *inode, struct file *filp,
 
        up( &dev->struct_sem );
 
-       request.count = entry->buf_count;
-       request.size = size;
-
-       if ( copy_to_user( argp, &request, sizeof(request) ) )
-               return -EFAULT;
+       request->count = entry->buf_count;
+       request->size = size;
 
        dma->flags = _DRM_DMA_USE_AGP;
 
        atomic_dec( &dev->buf_alloc );
        return 0;
 }
+EXPORT_SYMBOL(drm_addbufs_agp);
 #endif /* __OS_HAS_AGP */
 
-static int drm_addbufs_pci( struct inode *inode, struct file *filp,
-                           unsigned int cmd, unsigned long arg )
+int drm_addbufs_pci(drm_device_t *dev, drm_buf_desc_t *request)
 {
-       drm_file_t *priv = filp->private_data;
-       drm_device_t *dev = priv->head->dev;
        drm_device_dma_t *dma = dev->dma;
-       drm_buf_desc_t request;
        int count;
        int order;
        int size;
@@ -543,26 +683,22 @@ static int drm_addbufs_pci( struct inode *inode, struct file *filp,
        int page_count;
        unsigned long *temp_pagelist;
        drm_buf_t **temp_buflist;
-       drm_buf_desc_t __user *argp = (void __user *)arg;
 
        if (!drm_core_check_feature(dev, DRIVER_PCI_DMA)) return -EINVAL;
        if ( !dma ) return -EINVAL;
 
-       if ( copy_from_user( &request, argp, sizeof(request) ) )
-               return -EFAULT;
-
-       count = request.count;
-       order = drm_order( request.size );
+       count = request->count;
+       order = drm_order(request->size);
        size = 1 << order;
 
        DRM_DEBUG( "count=%d, size=%d (%d), order=%d, queue_count=%d\n",
-                  request.count, request.size, size,
+                  request->count, request->size, size,
                   order, dev->queue_count );
 
        if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL;
        if ( dev->queue_count ) return -EBUSY; /* Not while in use */
 
-       alignment = (request.flags & _DRM_PAGE_ALIGN)
+       alignment = (request->flags & _DRM_PAGE_ALIGN)
                ? PAGE_ALIGN(size) : size;
        page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
        total = PAGE_SIZE << page_order;
@@ -740,25 +876,18 @@ static int drm_addbufs_pci( struct inode *inode, struct file *filp,
 
        up( &dev->struct_sem );
 
-       request.count = entry->buf_count;
-       request.size = size;
-
-       if ( copy_to_user( argp, &request, sizeof(request) ) )
-               return -EFAULT;
+       request->count = entry->buf_count;
+       request->size = size;
 
        atomic_dec( &dev->buf_alloc );
        return 0;
 
 }
+EXPORT_SYMBOL(drm_addbufs_pci);
 
-static int drm_addbufs_sg( struct inode *inode, struct file *filp,
-                          unsigned int cmd, unsigned long arg )
+static int drm_addbufs_sg(drm_device_t *dev, drm_buf_desc_t *request)
 {
-       drm_file_t *priv = filp->private_data;
-       drm_device_t *dev = priv->head->dev;
        drm_device_dma_t *dma = dev->dma;
-       drm_buf_desc_t __user *argp = (void __user *)arg;
-       drm_buf_desc_t request;
        drm_buf_entry_t *entry;
        drm_buf_t *buf;
        unsigned long offset;
@@ -777,20 +906,17 @@ static int drm_addbufs_sg( struct inode *inode, struct file *filp,
        
        if ( !dma ) return -EINVAL;
 
-       if ( copy_from_user( &request, argp, sizeof(request) ) )
-               return -EFAULT;
-
-       count = request.count;
-       order = drm_order( request.size );
+       count = request->count;
+       order = drm_order(request->size);
        size = 1 << order;
 
-       alignment  = (request.flags & _DRM_PAGE_ALIGN)
+       alignment  = (request->flags & _DRM_PAGE_ALIGN)
                        ? PAGE_ALIGN(size) : size;
        page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
        total = PAGE_SIZE << page_order;
 
        byte_count = 0;
-       agp_offset = request.agp_start;
+       agp_offset = request->agp_start;
 
        DRM_DEBUG( "count:      %d\n",  count );
        DRM_DEBUG( "order:      %d\n",  order );
@@ -848,7 +974,8 @@ static int drm_addbufs_sg( struct inode *inode, struct file *filp,
 
                buf->offset  = (dma->byte_count + offset);
                buf->bus_address = agp_offset + offset;
-               buf->address = (void *)(agp_offset + offset + dev->sg->handle);
+               buf->address = (void *)(agp_offset + offset 
+                                       + (unsigned long)dev->sg->virtual);
                buf->next    = NULL;
                buf->waiting = 0;
                buf->pending = 0;
@@ -905,11 +1032,8 @@ static int drm_addbufs_sg( struct inode *inode, struct file *filp,
 
        up( &dev->struct_sem );
 
-       request.count = entry->buf_count;
-       request.size = size;
-
-       if ( copy_to_user( argp, &request, sizeof(request) ) )
-               return -EFAULT;
+       request->count = entry->buf_count;
+       request->size = size;
 
        dma->flags = _DRM_DMA_USE_SG;
 
@@ -917,6 +1041,161 @@ static int drm_addbufs_sg( struct inode *inode, struct file *filp,
        return 0;
 }
 
+static int drm_addbufs_fb(drm_device_t *dev, drm_buf_desc_t *request)
+{
+       drm_device_dma_t *dma = dev->dma;
+       drm_buf_entry_t *entry;
+       drm_buf_t *buf;
+       unsigned long offset;
+       unsigned long agp_offset;
+       int count;
+       int order;
+       int size;
+       int alignment;
+       int page_order;
+       int total;
+       int byte_count;
+       int i;
+       drm_buf_t **temp_buflist;
+
+       if (!drm_core_check_feature(dev, DRIVER_FB_DMA))
+               return -EINVAL;
+    
+       if (!dma)
+               return -EINVAL;
+
+       count = request->count;
+       order = drm_order(request->size);
+       size = 1 << order;
+
+       alignment = (request->flags & _DRM_PAGE_ALIGN)
+           ? PAGE_ALIGN(size) : size;
+       page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+       total = PAGE_SIZE << page_order;
+
+       byte_count = 0;
+       agp_offset = request->agp_start;
+
+       DRM_DEBUG("count:      %d\n", count);
+       DRM_DEBUG("order:      %d\n", order);
+       DRM_DEBUG("size:       %d\n", size);
+       DRM_DEBUG("agp_offset: %lu\n", agp_offset);
+       DRM_DEBUG("alignment:  %d\n", alignment);
+       DRM_DEBUG("page_order: %d\n", page_order);
+       DRM_DEBUG("total:      %d\n", total);
+
+       if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
+               return -EINVAL;
+       if (dev->queue_count)
+               return -EBUSY;  /* Not while in use */
+
+       spin_lock(&dev->count_lock);
+       if (dev->buf_use) {
+               spin_unlock(&dev->count_lock);
+               return -EBUSY;
+       }
+       atomic_inc(&dev->buf_alloc);
+       spin_unlock(&dev->count_lock);
+
+       down(&dev->struct_sem);
+       entry = &dma->bufs[order];
+       if (entry->buf_count) {
+               up(&dev->struct_sem);
+               atomic_dec(&dev->buf_alloc);
+               return -ENOMEM; /* May only call once for each order */
+       }
+
+       if (count < 0 || count > 4096) {
+               up(&dev->struct_sem);
+               atomic_dec(&dev->buf_alloc);
+               return -EINVAL;
+       }
+
+       entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
+                                  DRM_MEM_BUFS);
+       if (!entry->buflist) {
+               up(&dev->struct_sem);
+               atomic_dec(&dev->buf_alloc);
+               return -ENOMEM;
+       }
+       memset(entry->buflist, 0, count * sizeof(*entry->buflist));
+
+       entry->buf_size = size;
+       entry->page_order = page_order;
+
+       offset = 0;
+
+       while (entry->buf_count < count) {
+               buf = &entry->buflist[entry->buf_count];
+               buf->idx = dma->buf_count + entry->buf_count;
+               buf->total = alignment;
+               buf->order = order;
+               buf->used = 0;
+
+               buf->offset = (dma->byte_count + offset);
+               buf->bus_address = agp_offset + offset;
+               buf->address = (void *)(agp_offset + offset);
+               buf->next = NULL;
+               buf->waiting = 0;
+               buf->pending = 0;
+               init_waitqueue_head(&buf->dma_wait);
+               buf->filp = NULL;
+
+               buf->dev_priv_size = dev->driver->dev_priv_size;
+               buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS);
+               if (!buf->dev_private) {
+                       /* Set count correctly so we free the proper amount. */
+                       entry->buf_count = count;
+                       drm_cleanup_buf_error(dev, entry);
+                       up(&dev->struct_sem);
+                       atomic_dec(&dev->buf_alloc);
+                       return -ENOMEM;
+               }
+               memset(buf->dev_private, 0, buf->dev_priv_size);
+
+               DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address);
+
+               offset += alignment;
+               entry->buf_count++;
+               byte_count += PAGE_SIZE << page_order;
+       }
+
+       DRM_DEBUG("byte_count: %d\n", byte_count);
+
+       temp_buflist = drm_realloc(dma->buflist,
+                                  dma->buf_count * sizeof(*dma->buflist),
+                                  (dma->buf_count + entry->buf_count)
+                                  * sizeof(*dma->buflist), DRM_MEM_BUFS);
+       if (!temp_buflist) {
+               /* Free the entry because it isn't valid */
+               drm_cleanup_buf_error(dev, entry);
+               up(&dev->struct_sem);
+               atomic_dec(&dev->buf_alloc);
+               return -ENOMEM;
+       }
+       dma->buflist = temp_buflist;
+
+       for (i = 0; i < entry->buf_count; i++) {
+               dma->buflist[i + dma->buf_count] = &entry->buflist[i];
+       }
+
+       dma->buf_count += entry->buf_count;
+       dma->byte_count += byte_count;
+
+       DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count);
+       DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count);
+
+       up(&dev->struct_sem);
+
+       request->count = entry->buf_count;
+       request->size = size;
+
+       dma->flags = _DRM_DMA_USE_FB;
+
+       atomic_dec(&dev->buf_alloc);
+       return 0;
+}
+
 /**
  * Add buffers for DMA transfers (ioctl).
  *
@@ -937,6 +1216,7 @@ int drm_addbufs( struct inode *inode, struct file *filp,
        drm_buf_desc_t request;
        drm_file_t *priv = filp->private_data;
        drm_device_t *dev = priv->head->dev;
+       int ret;
        
        if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
                return -EINVAL;
@@ -947,13 +1227,23 @@ int drm_addbufs( struct inode *inode, struct file *filp,
 
 #if __OS_HAS_AGP
        if ( request.flags & _DRM_AGP_BUFFER )
-               return drm_addbufs_agp( inode, filp, cmd, arg );
+               ret=drm_addbufs_agp(dev, &request);
        else
 #endif
        if ( request.flags & _DRM_SG_BUFFER )
-               return drm_addbufs_sg( inode, filp, cmd, arg );
+               ret=drm_addbufs_sg(dev, &request);
+       else if ( request.flags & _DRM_FB_BUFFER)
+               ret=drm_addbufs_fb(dev, &request);
        else
-               return drm_addbufs_pci( inode, filp, cmd, arg );
+               ret=drm_addbufs_pci(dev, &request);
+
+       if (ret==0) {
+               if (copy_to_user((void __user *)arg, &request,
+                                sizeof(request))) {
+                       ret = -EFAULT;
+               }
+       }
+       return ret;
 }
 
 
@@ -1196,43 +1486,31 @@ int drm_mapbufs( struct inode *inode, struct file *filp,
                return -EFAULT;
 
        if ( request.count >= dma->buf_count ) {
-               if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP)) ||
-                   (drm_core_check_feature(dev, DRIVER_SG) && (dma->flags & _DRM_DMA_USE_SG)) ) {
+               if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP))
+                   || (drm_core_check_feature(dev, DRIVER_SG) 
+                       && (dma->flags & _DRM_DMA_USE_SG))
+                   || (drm_core_check_feature(dev, DRIVER_FB_DMA)
+                       && (dma->flags & _DRM_DMA_USE_FB))) {
                        drm_map_t *map = dev->agp_buffer_map;
+                       unsigned long token = dev->agp_buffer_token;
 
                        if ( !map ) {
                                retcode = -EINVAL;
                                goto done;
                        }
 
-#if LINUX_VERSION_CODE <= 0x020402
-                       down( &current->mm->mmap_sem );
-#else
                        down_write( &current->mm->mmap_sem );
-#endif
                        virtual = do_mmap( filp, 0, map->size,
                                           PROT_READ | PROT_WRITE,
                                           MAP_SHARED,
-                                          (unsigned long)map->offset );
-#if LINUX_VERSION_CODE <= 0x020402
-                       up( &current->mm->mmap_sem );
-#else
+                                          token );
                        up_write( &current->mm->mmap_sem );
-#endif
                } else {
-#if LINUX_VERSION_CODE <= 0x020402
-                       down( &current->mm->mmap_sem );
-#else
                        down_write( &current->mm->mmap_sem );
-#endif
                        virtual = do_mmap( filp, 0, dma->byte_count,
                                           PROT_READ | PROT_WRITE,
                                           MAP_SHARED, 0 );
-#if LINUX_VERSION_CODE <= 0x020402
-                       up( &current->mm->mmap_sem );
-#else
                        up_write( &current->mm->mmap_sem );
-#endif
                }
                if ( virtual > -1024UL ) {
                        /* Real error */
@@ -1279,3 +1557,26 @@ int drm_mapbufs( struct inode *inode, struct file *filp,
        return retcode;
 }
 
+/**
+ * Compute size order.  Returns the exponent of the smaller power of two which
+ * is greater or equal to given number.
+ * 
+ * \param size size.
+ * \return order.
+ *
+ * \todo Can be made faster.
+ */
+int drm_order( unsigned long size )
+{
+       int order;
+       unsigned long tmp;
+
+       for (order = 0, tmp = size >> 1; tmp; tmp >>= 1, order++)
+               ;
+
+       if (size & (size - 1))
+               ++order;
+
+       return order;
+}
+EXPORT_SYMBOL(drm_order);
index a7cfabd1ca2e9d0801c3e8c10b12cc1acbb0601c..502892794c1676b6fb05fc7dd59381bf06fb8d9a 100644 (file)
@@ -212,6 +212,7 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
        drm_ctx_priv_map_t __user *argp = (void __user *)arg;
        drm_ctx_priv_map_t request;
        drm_map_t *map;
+       drm_map_list_t *_entry;
 
        if (copy_from_user(&request, argp, sizeof(request)))
                return -EFAULT;
@@ -225,7 +226,17 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
        map = dev->context_sareas[request.ctx_id];
        up(&dev->struct_sem);
 
-       request.handle = (void *) map->offset;
+       request.handle = 0;
+       list_for_each_entry(_entry, &dev->maplist->head,head) {
+               if (_entry->map == map) {
+                       request.handle = (void *)(unsigned long)_entry->user_token;
+                       break;
+               }
+       }
+       if (request.handle == 0)
+               return -EINVAL;
+
+
        if (copy_to_user(argp, &request, sizeof(request)))
                return -EFAULT;
        return 0;
@@ -262,7 +273,7 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
        list_for_each(list, &dev->maplist->head) {
                r_list = list_entry(list, drm_map_list_t, head);
                if (r_list->map
-                   && r_list->map->offset == (unsigned long) request.handle)
+                   && r_list->user_token == (unsigned long) request.handle)
                        goto found;
        }
 bad:
@@ -297,7 +308,7 @@ found:
  *
  * Attempt to set drm_device::context_flag.
  */
-int drm_context_switch( drm_device_t *dev, int old, int new )
+static int drm_context_switch( drm_device_t *dev, int old, int new )
 {
         if ( test_and_set_bit( 0, &dev->context_flag ) ) {
                 DRM_ERROR( "Reentering -- FIXME\n" );
@@ -369,7 +380,7 @@ int drm_resctx( struct inode *inode, struct file *filp,
                for ( i = 0 ; i < DRM_RESERVED_CONTEXTS ; i++ ) {
                        ctx.handle = i;
                        if ( copy_to_user( &res.contexts[i],
-                                          &i, sizeof(i) ) )
+                                          &ctx, sizeof(ctx) ) )
                                return -EFAULT;
                }
        }
index 3333c250c4d9995848053d4f8a3ecf1286b1ed6b..6ba48f346fcf2407d400e1d7217f10b2d72e0c7a 100644 (file)
@@ -70,8 +70,8 @@ static drm_ioctl_desc_t                 drm_ioctls[] = {
        [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)]       = { drm_noop,        1, 1 },
        [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)]    = { drm_authmagic,   1, 1 },
 
-       [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)]       = { drm_addmap,      1, 1 },
-       [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)]        = { drm_rmmap,       1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)]       = { drm_addmap_ioctl,1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)]        = { drm_rmmap_ioctl, 1, 0 },
 
        [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = { drm_setsareactx, 1, 1 },
        [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = { drm_getsareactx, 1, 0 },
@@ -102,10 +102,10 @@ static drm_ioctl_desc_t             drm_ioctls[] = {
        [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)]       = { drm_control,     1, 1 },
 
 #if __OS_HAS_AGP
-       [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)]   = { drm_agp_acquire, 1, 1 },
-       [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)]   = { drm_agp_release, 1, 1 },
-       [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)]    = { drm_agp_enable 1, 1 },
-       [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)]      = { drm_agp_info,    1, 0 },
+       [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)]   = { drm_agp_acquire_ioctl, 1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)]   = { drm_agp_release_ioctl, 1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)]    = { drm_agp_enable_ioctl, 1, 1 },
+       [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)]      = { drm_agp_info_ioctl, 1, 0 },
        [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)]     = { drm_agp_alloc,   1, 1 },
        [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)]      = { drm_agp_free,    1, 1 },
        [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)]      = { drm_agp_bind,    1, 1 },
@@ -127,14 +127,12 @@ static drm_ioctl_desc_t             drm_ioctls[] = {
  *
  * Frees every resource in \p dev.
  *
- * \sa drm_device and setup().
+ * \sa drm_device
  */
 int drm_takedown( drm_device_t *dev )
 {
        drm_magic_entry_t *pt, *next;
-       drm_map_t *map;
        drm_map_list_t *r_list;
-       struct list_head *list, *list_next;
        drm_vma_entry_t *vma, *vma_next;
        int i;
 
@@ -142,6 +140,7 @@ int drm_takedown( drm_device_t *dev )
 
        if (dev->driver->pretakedown)
          dev->driver->pretakedown(dev);
+       DRM_DEBUG("driver pretakedown completed\n");
 
        if (dev->unique) {
                drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER);
@@ -178,11 +177,16 @@ int drm_takedown( drm_device_t *dev )
                }
                dev->agp->memory = NULL;
 
-               if ( dev->agp->acquired ) drm_agp_do_release(dev);
+               if (dev->agp->acquired)
+                 drm_agp_release(dev);
 
                dev->agp->acquired = 0;
                dev->agp->enabled  = 0;
        }
+       if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg) {
+               drm_sg_cleanup(dev->sg);
+               dev->sg = NULL;
+       }
 
                                /* Clear vma list (only built for debugging) */
        if ( dev->vmalist ) {
@@ -194,48 +198,11 @@ int drm_takedown( drm_device_t *dev )
        }
 
        if( dev->maplist ) {
-               list_for_each_safe( list, list_next, &dev->maplist->head ) {
-                       r_list = (drm_map_list_t *)list;
-
-                       if ( ( map = r_list->map ) ) {
-                               switch ( map->type ) {
-                               case _DRM_REGISTERS:
-                               case _DRM_FRAME_BUFFER:
-                                       if (drm_core_has_MTRR(dev)) {
-                                               if ( map->mtrr >= 0 ) {
-                                                       int retcode;
-                                                       retcode = mtrr_del( map->mtrr,
-                                                                           map->offset,
-                                                                           map->size );
-                                                       DRM_DEBUG( "mtrr_del=%d\n", retcode );
-                                               }
-                                       }
-                                       drm_ioremapfree( map->handle, map->size, dev );
-                                       break;
-                               case _DRM_SHM:
-                                       vfree(map->handle);
-                                       break;
-
-                               case _DRM_AGP:
-                                       /* Do nothing here, because this is all
-                                        * handled in the AGP/GART driver.
-                                        */
-                                       break;
-                               case _DRM_SCATTER_GATHER:
-                                       /* Handle it */
-                                       if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg) {
-                                               drm_sg_cleanup(dev->sg);
-                                               dev->sg = NULL;
-                                       }
-                                       break;
-                               }
-                               drm_free(map, sizeof(*map), DRM_MEM_MAPS);
-                       }
-                       list_del( list );
-                       drm_free(r_list, sizeof(*r_list), DRM_MEM_MAPS);
-               }
-               drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
-               dev->maplist = NULL;
+               while (!list_empty(&dev->maplist->head)) {
+                       struct list_head *list = dev->maplist->head.next;
+                       r_list = list_entry(list, drm_map_list_t, head);
+                       drm_rmmap_locked(dev, r_list->map);
+               }
        }
 
        if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist ) {
@@ -264,6 +231,7 @@ int drm_takedown( drm_device_t *dev )
        }
        up( &dev->struct_sem );
 
+       DRM_DEBUG("takedown completed\n");
        return 0;
 }
 
@@ -312,7 +280,7 @@ EXPORT_SYMBOL(drm_init);
  *
  * Cleans up all DRM device, calling takedown().
  * 
- * \sa drm_init().
+ * \sa drm_init
  */
 static void drm_cleanup( drm_device_t *dev )
 {
@@ -325,6 +293,11 @@ static void drm_cleanup( drm_device_t *dev )
 
        drm_takedown( dev );    
 
+       if (dev->maplist) {
+               drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
+               dev->maplist = NULL;
+       }
+
        drm_ctxbitmap_cleanup( dev );
        
        if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&
index 10e64fde8d782ca23dbc3ef57a3348f97a40d87d..a1f4e9cd64edd17406cf2b6349c37a2039a9fac2 100644 (file)
@@ -71,12 +71,6 @@ static int drm_setup( drm_device_t *dev )
                dev->magiclist[i].tail = NULL;
        }
 
-       dev->maplist = drm_alloc(sizeof(*dev->maplist),
-                                 DRM_MEM_MAPS);
-       if(dev->maplist == NULL) return -ENOMEM;
-       memset(dev->maplist, 0, sizeof(*dev->maplist));
-       INIT_LIST_HEAD(&dev->maplist->head);
-
        dev->ctxlist = drm_alloc(sizeof(*dev->ctxlist),
                                  DRM_MEM_CTXLIST);
        if(dev->ctxlist == NULL) return -ENOMEM;
index 39afda0ccabe36d803e5bc89772d4b19edec6d94..d2ed3ba5aca9647259bfc932f3363adfec77ee26 100644 (file)
@@ -208,7 +208,7 @@ int drm_getmap( struct inode *inode, struct file *filp,
        map.size   = r_list->map->size;
        map.type   = r_list->map->type;
        map.flags  = r_list->map->flags;
-       map.handle = r_list->map->handle;
+       map.handle = (void *)(unsigned long) r_list->user_token;
        map.mtrr   = r_list->map->mtrr;
        up(&dev->struct_sem);
 
index ace3d42f4407e5df458d6578b79f0aaaa742127c..ff483fb418aae85e2d1d987747efc511a9b415a0 100644 (file)
@@ -142,27 +142,31 @@ void drm_free_pages(unsigned long address, int order, int area)
 
 #if __OS_HAS_AGP
 /** Wrapper around agp_allocate_memory() */
-DRM_AGP_MEM *drm_alloc_agp(struct agp_bridge_data *bridge, int pages, u32 type)
+DRM_AGP_MEM *drm_alloc_agp(drm_device_t *dev, int pages, u32 type)
 {
-       return drm_agp_allocate_memory(bridge, pages, type);
+       return drm_agp_allocate_memory(dev->agp->bridge, pages, type);
 }
+EXPORT_SYMBOL(drm_alloc_agp);
 
 /** Wrapper around agp_free_memory() */
 int drm_free_agp(DRM_AGP_MEM *handle, int pages)
 {
        return drm_agp_free_memory(handle) ? 0 : -EINVAL;
 }
+EXPORT_SYMBOL(drm_free_agp);
 
 /** Wrapper around agp_bind_memory() */
 int drm_bind_agp(DRM_AGP_MEM *handle, unsigned int start)
 {
        return drm_agp_bind_memory(handle, start);
 }
+EXPORT_SYMBOL(drm_bind_agp);
 
 /** Wrapper around agp_unbind_memory() */
 int drm_unbind_agp(DRM_AGP_MEM *handle)
 {
        return drm_agp_unbind_memory(handle);
 }
+EXPORT_SYMBOL(drm_unbind_agp);
 #endif /* agp */
 #endif /* debug_memory */
index 192e8762571c890b0b10d536234d326b0bfcac06..09ed712c1a7fe0c0d1dc4038d83db079517a9eb8 100644 (file)
 /**
  * \brief Allocate a PCI consistent memory block, for DMA.
  */
-void *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align,
-                   dma_addr_t maxaddr, dma_addr_t * busaddr)
+drm_dma_handle_t *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align,
+                               dma_addr_t maxaddr)
 {
-       void *address;
-#if DRM_DEBUG_MEMORY
+       drm_dma_handle_t *dmah;
+#ifdef DRM_DEBUG_MEMORY
        int area = DRM_MEM_DMA;
 
        spin_lock(&drm_mem_lock);
@@ -74,13 +74,19 @@ void *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align,
                return NULL;
        }
 
-       address = pci_alloc_consistent(dev->pdev, size, busaddr);
+       dmah = kmalloc(sizeof(drm_dma_handle_t), GFP_KERNEL);
+       if (!dmah)
+               return NULL;
+       
+       dmah->size = size;
+       dmah->vaddr = pci_alloc_consistent(dev->pdev, size, &dmah->busaddr);
 
-#if DRM_DEBUG_MEMORY
-       if (address == NULL) {
+#ifdef DRM_DEBUG_MEMORY
+       if (dmah->vaddr == NULL) {
                spin_lock(&drm_mem_lock);
                ++drm_mem_stats[area].fail_count;
                spin_unlock(&drm_mem_lock);
+               kfree(dmah);
                return NULL;
        }
 
@@ -90,37 +96,42 @@ void *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align,
        drm_ram_used += size;
        spin_unlock(&drm_mem_lock);
 #else
-       if (address == NULL)
+       if (dmah->vaddr == NULL) {
+               kfree(dmah);
                return NULL;
+       }
 #endif
 
-       memset(address, 0, size);
+       memset(dmah->vaddr, 0, size);
 
-       return address;
+       return dmah;
 }
 EXPORT_SYMBOL(drm_pci_alloc);
 
 /**
- * \brief Free a PCI consistent memory block.
+ * \brief Free a PCI consistent memory block with freeing its descriptor.
+ *
+ * This function is for internal use in the Linux-specific DRM core code.
  */
 void
-drm_pci_free(drm_device_t * dev, size_t size, void *vaddr, dma_addr_t busaddr)
+__drm_pci_free(drm_device_t * dev, drm_dma_handle_t *dmah)
 {
-#if DRM_DEBUG_MEMORY
+#ifdef DRM_DEBUG_MEMORY
        int area = DRM_MEM_DMA;
        int alloc_count;
        int free_count;
 #endif
 
-       if (!vaddr) {
-#if DRM_DEBUG_MEMORY
+       if (!dmah->vaddr) {
+#ifdef DRM_DEBUG_MEMORY
                DRM_MEM_ERROR(area, "Attempt to free address 0\n");
 #endif
        } else {
-               pci_free_consistent(dev->pdev, size, vaddr, busaddr);
+               pci_free_consistent(dev->pdev, dmah->size, dmah->vaddr,
+                                   dmah->busaddr);
        }
 
-#if DRM_DEBUG_MEMORY
+#ifdef DRM_DEBUG_MEMORY
        spin_lock(&drm_mem_lock);
        free_count = ++drm_mem_stats[area].free_count;
        alloc_count = drm_mem_stats[area].succeed_count;
@@ -135,6 +146,16 @@ drm_pci_free(drm_device_t * dev, size_t size, void *vaddr, dma_addr_t busaddr)
 #endif
 
 }
+
+/**
+ * \brief Free a PCI consistent memory block
+ */
+void
+drm_pci_free(drm_device_t *dev, drm_dma_handle_t *dmah)
+{
+       __drm_pci_free(dev, dmah);
+       kfree(dmah);
+}
 EXPORT_SYMBOL(drm_pci_free);
 
 /*@}*/
index 70ca4fa55c9dd2433a37951095e7661240402e18..58b1747cd44033f1056f2982d7e3c8a9e04803d6 100644 (file)
@@ -25,6 +25,8 @@
        {0x1002, 0x4965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \
        {0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \
        {0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \
+       {0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420}, \
+       {0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420}, \
        {0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
        {0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
        {0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
        {0x1002, 0x4C65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \
        {0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \
        {0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \
+       {0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
+       {0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
+       {0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
+       {0x1002, 0x4E47, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
+       {0x1002, 0x4E48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+       {0x1002, 0x4E49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+       {0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
+       {0x1002, 0x4E4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
        {0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
+       {0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
+       {0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
        {0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
        {0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
        {0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
@@ -56,6 +68,7 @@
        {0x1002, 0x516A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
        {0x1002, 0x516B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
        {0x1002, 0x516C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
+       {0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
        {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
        {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
        {0x1002, 0x5836, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
        {0, 0, 0}
 
 #define mga_PCI_IDS \
-       {0x102b, 0x0521, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x102b, 0x0525, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x102b, 0x2527, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+       {0x102b, 0x0520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G200}, \
+       {0x102b, 0x0521, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G200}, \
+       {0x102b, 0x0525, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G400}, \
+       {0x102b, 0x2527, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G550}, \
        {0, 0, 0}
 
 #define mach64_PCI_IDS \
 
 #define viadrv_PCI_IDS \
        {0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+       {0x1106, 0x3118, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+       {0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0, 0, 0}
 
 #define i810_PCI_IDS \
        {0x8086, 0x2572, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0, 0, 0}
 
-#define gamma_PCI_IDS \
-       {0x3d3d, 0x0008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0, 0, 0}
-
 #define savage_PCI_IDS \
-       {0x5333, 0x8a22, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8a23, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c13, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c22, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c24, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c2a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c2b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c2c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c2d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8c2f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8a25, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8a26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8d01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8d02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x5333, 0x8d04, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+       {0x5333, 0x8a20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE3D}, \
+       {0x5333, 0x8a21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE3D}, \
+       {0x5333, 0x8a22, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE4}, \
+       {0x5333, 0x8a23, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE4}, \
+       {0x5333, 0x8c10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE_MX}, \
+       {0x5333, 0x8c11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE_MX}, \
+       {0x5333, 0x8c12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE_MX}, \
+       {0x5333, 0x8c13, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE_MX}, \
+       {0x5333, 0x8c22, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
+       {0x5333, 0x8c24, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
+       {0x5333, 0x8c26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
+       {0x5333, 0x8c2a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
+       {0x5333, 0x8c2b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
+       {0x5333, 0x8c2c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
+       {0x5333, 0x8c2d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
+       {0x5333, 0x8c2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
+       {0x5333, 0x8c2f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
+       {0x5333, 0x8a25, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_PROSAVAGE}, \
+       {0x5333, 0x8a26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_PROSAVAGE}, \
+       {0x5333, 0x8d01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_TWISTER}, \
+       {0x5333, 0x8d02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_TWISTER}, \
+       {0x5333, 0x8d03, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_PROSAVAGEDDR}, \
+       {0x5333, 0x8d04, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_PROSAVAGEDDR}, \
        {0, 0, 0}
 
 #define ffb_PCI_IDS \
        {0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0, 0, 0}
 
-#define viadrv_PCI_IDS \
-       {0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0, 0, 0}
-
index 4774087d2e9e82c64d0d05511d02743d9371375f..32d2bb99462c67d7b9ef4416abd3147445afc36e 100644 (file)
@@ -210,8 +210,8 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request,
 
                                /* Hardcoded from _DRM_FRAME_BUFFER,
                                    _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and
-                                   _DRM_SCATTER_GATHER. */
-       const char   *types[] = { "FB", "REG", "SHM", "AGP", "SG" };
+                                   _DRM_SCATTER_GATHER and _DRM_CONSISTENT */
+       const char   *types[] = { "FB", "REG", "SHM", "AGP", "SG", "PCI" };
        const char   *type;
        int          i;
 
@@ -229,16 +229,19 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request,
        if (dev->maplist != NULL) list_for_each(list, &dev->maplist->head) {
                r_list = list_entry(list, drm_map_list_t, head);
                map = r_list->map;
-               if(!map) continue;
-               if (map->type < 0 || map->type > 4) type = "??";
-               else                                type = types[map->type];
-               DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s  0x%02x 0x%08lx ",
+               if(!map)
+                       continue;
+               if (map->type < 0 || map->type > 5)
+                       type = "??";
+               else    
+                       type = types[map->type];
+               DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s  0x%02x 0x%08x ",
                               i,
                               map->offset,
                               map->size,
                               type,
                               map->flags,
-                              (unsigned long)map->handle);
+                              r_list->user_token);
                if (map->mtrr < 0) {
                        DRM_PROC_PRINT("none\n");
                } else {
index 54fddb6ea2d1398f1da3263c4105097ee2cbd63f..ed267d49bc6aa9c4dee72c006a41a61f9991e35b 100644 (file)
@@ -61,6 +61,12 @@ void drm_sg_cleanup( drm_sg_mem_t *entry )
                   DRM_MEM_SGLISTS );
 }
 
+#ifdef _LP64
+# define ScatterHandle(x) (unsigned int)((x >> 32) + (x & ((1L << 32) - 1)))
+#else
+# define ScatterHandle(x) (unsigned int)(x)
+#endif
+
 int drm_sg_alloc( struct inode *inode, struct file *filp,
                   unsigned int cmd, unsigned long arg )
 {
@@ -133,12 +139,13 @@ int drm_sg_alloc( struct inode *inode, struct file *filp,
         */
        memset( entry->virtual, 0, pages << PAGE_SHIFT );
 
-       entry->handle = (unsigned long)entry->virtual;
+       entry->handle = ScatterHandle((unsigned long)entry->virtual);
 
        DRM_DEBUG( "sg alloc handle  = %08lx\n", entry->handle );
        DRM_DEBUG( "sg alloc virtual = %p\n", entry->virtual );
 
-       for ( i = entry->handle, j = 0 ; j < pages ; i += PAGE_SIZE, j++ ) {
+       for (i = (unsigned long)entry->virtual, j = 0; j < pages; 
+               i += PAGE_SIZE, j++) {
                entry->pagelist[j] = vmalloc_to_page((void *)i);
                if (!entry->pagelist[j])
                        goto failed;
index 48829a1a086a94cba10327d6896f8e1dbfdc5e95..95a976c96eb8303c9df9cc249c8c3d9e99cc999c 100644 (file)
@@ -75,6 +75,11 @@ static int drm_fill_in_dev(drm_device_t *dev, struct pci_dev *pdev, const struct
        dev->pci_func = PCI_FUNC(pdev->devfn);
        dev->irq = pdev->irq;
 
+       dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS);
+       if (dev->maplist == NULL)
+               return -ENOMEM;
+       INIT_LIST_HEAD(&dev->maplist->head);
+
        /* the DRM has 6 basic counters */
        dev->counters = 6;
        dev->types[0]  = _DRM_STAT_LOCK;
@@ -91,7 +96,8 @@ static int drm_fill_in_dev(drm_device_t *dev, struct pci_dev *pdev, const struct
                        goto error_out_unreg;
 
        if (drm_core_has_AGP(dev)) {
-               dev->agp = drm_agp_init(dev);
+               if (drm_device_is_agp(dev))
+                       dev->agp = drm_agp_init(dev);
                if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) && (dev->agp == NULL)) {
                        DRM_ERROR( "Cannot initialize the agpgart module.\n" );
                        retcode = -EINVAL;
index 2fc10c4bbcdfd4c9be3e5a11f822259d5f2aa746..475cc5e555e1c43626ed18be91df2e90babcf5a4 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/err.h>
 
 #include "drm_core.h"
+#include "drmP.h"
 
 struct drm_sysfs_class {
        struct class_device_attribute attr;
index 621220f3f37207492ed8bfccdcef7d5e94cc0fda..ced4215e2275e71dad67a2db787054bb03bfc12f 100644 (file)
@@ -73,12 +73,13 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
                r_list = list_entry(list, drm_map_list_t, head);
                map = r_list->map;
                if (!map) continue;
-               if (map->offset == VM_OFFSET(vma)) break;
+               if (r_list->user_token == VM_OFFSET(vma))
+                       break;
        }
 
        if (map && map->type == _DRM_AGP) {
                unsigned long offset = address - vma->vm_start;
-               unsigned long baddr = VM_OFFSET(vma) + offset;
+               unsigned long baddr = map->offset + offset;
                struct drm_agp_mem *agpmem;
                struct page *page;
 
@@ -210,6 +211,8 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
                }
 
                if(!found_maps) {
+                       drm_dma_handle_t dmah;
+
                        switch (map->type) {
                        case _DRM_REGISTERS:
                        case _DRM_FRAME_BUFFER:
@@ -228,6 +231,12 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
                        case _DRM_AGP:
                        case _DRM_SCATTER_GATHER:
                                break;
+                       case _DRM_CONSISTENT:
+                               dmah.vaddr = map->handle;
+                               dmah.busaddr = map->offset;
+                               dmah.size = map->size;
+                               __drm_pci_free(dev, &dmah);
+                               break;
                        }
                        drm_free(map, sizeof(*map), DRM_MEM_MAPS);
                }
@@ -296,7 +305,7 @@ static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma,
 
 
        offset = address - vma->vm_start;
-       map_offset = map->offset - dev->sg->handle;
+       map_offset = map->offset - (unsigned long)dev->sg->virtual;
        page_offset = (offset >> PAGE_SHIFT) + (map_offset >> PAGE_SHIFT);
        page = entry->pagelist[page_offset];
        get_page(page);
@@ -305,8 +314,6 @@ static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma,
 }
 
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
-
 static struct page *drm_vm_nopage(struct vm_area_struct *vma,
                                   unsigned long address,
                                   int *type) {
@@ -335,35 +342,6 @@ static struct page *drm_vm_sg_nopage(struct vm_area_struct *vma,
        return drm_do_vm_sg_nopage(vma, address);
 }
 
-#else  /* LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0) */
-
-static struct page *drm_vm_nopage(struct vm_area_struct *vma,
-                                  unsigned long address,
-                                  int unused) {
-       return drm_do_vm_nopage(vma, address);
-}
-
-static struct page *drm_vm_shm_nopage(struct vm_area_struct *vma,
-                                      unsigned long address,
-                                      int unused) {
-       return drm_do_vm_shm_nopage(vma, address);
-}
-
-static struct page *drm_vm_dma_nopage(struct vm_area_struct *vma,
-                                      unsigned long address,
-                                      int unused) {
-       return drm_do_vm_dma_nopage(vma, address);
-}
-
-static struct page *drm_vm_sg_nopage(struct vm_area_struct *vma,
-                                     unsigned long address,
-                                     int unused) {
-       return drm_do_vm_sg_nopage(vma, address);
-}
-
-#endif
-
-
 /** AGP virtual memory operations */
 static struct vm_operations_struct   drm_vm_ops = {
        .nopage = drm_vm_nopage,
@@ -487,11 +465,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
 
        vma->vm_ops   = &drm_vm_dma_ops;
 
-#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */
-       vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
-#else
        vma->vm_flags |= VM_RESERVED; /* Don't swap */
-#endif
 
        vma->vm_file  =  filp;  /* Needed for drm_vm_open() */
        drm_vm_open(vma);
@@ -560,13 +534,12 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
                                   for performance, even if the list was a
                                   bit longer. */
        list_for_each(list, &dev->maplist->head) {
-               unsigned long off;
 
                r_list = list_entry(list, drm_map_list_t, head);
                map = r_list->map;
                if (!map) continue;
-               off = dev->driver->get_map_ofs(map);
-               if (off == VM_OFFSET(vma)) break;
+               if (r_list->user_token == VM_OFFSET(vma))
+                       break;
        }
 
        if (!map || ((map->flags&_DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
@@ -605,17 +578,17 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
                 /* fall through to _DRM_FRAME_BUFFER... */        
        case _DRM_FRAME_BUFFER:
        case _DRM_REGISTERS:
-               if (VM_OFFSET(vma) >= __pa(high_memory)) {
 #if defined(__i386__) || defined(__x86_64__)
-                       if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) {
-                               pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
-                               pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
-                       }
+               if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) {
+                       pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+                       pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
+               }
 #elif defined(__powerpc__)
-                       pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+               pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
+               if (map->type == _DRM_REGISTERS)
+                       pgprot_val(vma->vm_page_prot) |= _PAGE_GUARDED;
 #endif
-                       vma->vm_flags |= VM_IO; /* not in core dump */
-               }
+               vma->vm_flags |= VM_IO; /* not in core dump */
 #if defined(__ia64__)
                if (efi_range_is_wc(vma->vm_start, vma->vm_end -
                                    vma->vm_start))
@@ -628,12 +601,12 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
                offset = dev->driver->get_reg_ofs(dev);
 #ifdef __sparc__
                if (io_remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start,
-                                       (VM_OFFSET(vma) + offset) >> PAGE_SHIFT,
+                                       (map->offset + offset) >> PAGE_SHIFT,
                                        vma->vm_end - vma->vm_start,
                                        vma->vm_page_prot))
 #else
                if (io_remap_pfn_range(vma, vma->vm_start,
-                                    (VM_OFFSET(vma) + offset) >> PAGE_SHIFT,
+                                    (map->offset + offset) >> PAGE_SHIFT,
                                     vma->vm_end - vma->vm_start,
                                     vma->vm_page_prot))
 #endif
@@ -641,37 +614,28 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
                DRM_DEBUG("   Type = %d; start = 0x%lx, end = 0x%lx,"
                          " offset = 0x%lx\n",
                          map->type,
-                         vma->vm_start, vma->vm_end, VM_OFFSET(vma) + offset);
+                         vma->vm_start, vma->vm_end, map->offset + offset);
                vma->vm_ops = &drm_vm_ops;
                break;
        case _DRM_SHM:
+       case _DRM_CONSISTENT:
+               /* Consistent memory is really like shared memory. It's only
+                * allocate in a different way */
                vma->vm_ops = &drm_vm_shm_ops;
                vma->vm_private_data = (void *)map;
                                /* Don't let this area swap.  Change when
                                   DRM_KERNEL advisory is supported. */
-#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */
-               vma->vm_flags |= VM_LOCKED;
-#else
                vma->vm_flags |= VM_RESERVED;
-#endif
                break;
        case _DRM_SCATTER_GATHER:
                vma->vm_ops = &drm_vm_sg_ops;
                vma->vm_private_data = (void *)map;
-#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */
-               vma->vm_flags |= VM_LOCKED;
-#else
                vma->vm_flags |= VM_RESERVED;
-#endif
                 break;
        default:
                return -EINVAL; /* This should never happen. */
        }
-#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */
-       vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
-#else
        vma->vm_flags |= VM_RESERVED; /* Don't swap */
-#endif
 
        vma->vm_file  =  filp;  /* Needed for drm_vm_open() */
        drm_vm_open(vma);
index ec614fff8f0481d7f6f6044373328a3012c5196d..1bd0d55ee0f0b4f98cb5eb93c0b112dfd074e4f4 100644 (file)
@@ -152,14 +152,11 @@ static drm_map_t *ffb_find_map(struct file *filp, unsigned long off)
                return NULL;
 
        list_for_each(list, &dev->maplist->head) {
-               unsigned long uoff;
-
                r_list = (drm_map_list_t *)list;
                map = r_list->map;
                if (!map)
                        continue;
-               uoff = (map->offset & 0xffffffff);
-               if (uoff == off)
+               if (r_list->user_token == off)
                        return map;
        }
 
diff --git a/drivers/char/drm/gamma_context.h b/drivers/char/drm/gamma_context.h
deleted file mode 100644 (file)
index d11b507..0000000
+++ /dev/null
@@ -1,492 +0,0 @@
-/* drm_context.h -- IOCTLs for generic contexts -*- linux-c -*-
- * Created: Fri Nov 24 18:31:37 2000 by gareth@valinux.com
- *
- * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Rickard E. (Rik) Faith <faith@valinux.com>
- *    Gareth Hughes <gareth@valinux.com>
- * ChangeLog:
- *  2001-11-16 Torsten Duwe <duwe@caldera.de>
- *             added context constructor/destructor hooks,
- *             needed by SiS driver's memory management.
- */
-
-/* ================================================================
- * Old-style context support -- only used by gamma.  
- */
-
-
-/* The drm_read and drm_write_string code (especially that which manages
-   the circular buffer), is based on Alessandro Rubini's LINUX DEVICE
-   DRIVERS (Cambridge: O'Reilly, 1998), pages 111-113. */
-
-ssize_t gamma_fops_read(struct file *filp, char __user *buf, size_t count, loff_t *off)
-{
-       drm_file_t    *priv   = filp->private_data;
-       drm_device_t  *dev    = priv->dev;
-       int           left;
-       int           avail;
-       int           send;
-       int           cur;
-
-       DRM_DEBUG("%p, %p\n", dev->buf_rp, dev->buf_wp);
-
-       while (dev->buf_rp == dev->buf_wp) {
-               DRM_DEBUG("  sleeping\n");
-               if (filp->f_flags & O_NONBLOCK) {
-                       return -EAGAIN;
-               }
-               interruptible_sleep_on(&dev->buf_readers);
-               if (signal_pending(current)) {
-                       DRM_DEBUG("  interrupted\n");
-                       return -ERESTARTSYS;
-               }
-               DRM_DEBUG("  awake\n");
-       }
-
-       left  = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
-       avail = DRM_BSZ - left;
-       send  = DRM_MIN(avail, count);
-
-       while (send) {
-               if (dev->buf_wp > dev->buf_rp) {
-                       cur = DRM_MIN(send, dev->buf_wp - dev->buf_rp);
-               } else {
-                       cur = DRM_MIN(send, dev->buf_end - dev->buf_rp);
-               }
-               if (copy_to_user(buf, dev->buf_rp, cur))
-                       return -EFAULT;
-               dev->buf_rp += cur;
-               if (dev->buf_rp == dev->buf_end) dev->buf_rp = dev->buf;
-               send -= cur;
-       }
-
-       wake_up_interruptible(&dev->buf_writers);
-       return DRM_MIN(avail, count);
-}
-
-
-/* In an incredibly convoluted setup, the kernel module actually calls
- * back into the X server to perform context switches on behalf of the
- * 3d clients.
- */
-int DRM(write_string)(drm_device_t *dev, const char *s)
-{
-       int left   = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
-       int send   = strlen(s);
-       int count;
-
-       DRM_DEBUG("%d left, %d to send (%p, %p)\n",
-                 left, send, dev->buf_rp, dev->buf_wp);
-
-       if (left == 1 || dev->buf_wp != dev->buf_rp) {
-               DRM_ERROR("Buffer not empty (%d left, wp = %p, rp = %p)\n",
-                         left,
-                         dev->buf_wp,
-                         dev->buf_rp);
-       }
-
-       while (send) {
-               if (dev->buf_wp >= dev->buf_rp) {
-                       count = DRM_MIN(send, dev->buf_end - dev->buf_wp);
-                       if (count == left) --count; /* Leave a hole */
-               } else {
-                       count = DRM_MIN(send, dev->buf_rp - dev->buf_wp - 1);
-               }
-               strncpy(dev->buf_wp, s, count);
-               dev->buf_wp += count;
-               if (dev->buf_wp == dev->buf_end) dev->buf_wp = dev->buf;
-               send -= count;
-       }
-
-       if (dev->buf_async) kill_fasync(&dev->buf_async, SIGIO, POLL_IN);
-
-       DRM_DEBUG("waking\n");
-       wake_up_interruptible(&dev->buf_readers);
-       return 0;
-}
-
-unsigned int gamma_fops_poll(struct file *filp, struct poll_table_struct *wait)
-{
-       drm_file_t   *priv = filp->private_data;
-       drm_device_t *dev  = priv->dev;
-
-       poll_wait(filp, &dev->buf_readers, wait);
-       if (dev->buf_wp != dev->buf_rp) return POLLIN | POLLRDNORM;
-       return 0;
-}
-
-int DRM(context_switch)(drm_device_t *dev, int old, int new)
-{
-       char        buf[64];
-       drm_queue_t *q;
-
-       if (test_and_set_bit(0, &dev->context_flag)) {
-               DRM_ERROR("Reentering -- FIXME\n");
-               return -EBUSY;
-       }
-
-       DRM_DEBUG("Context switch from %d to %d\n", old, new);
-
-       if (new >= dev->queue_count) {
-               clear_bit(0, &dev->context_flag);
-               return -EINVAL;
-       }
-
-       if (new == dev->last_context) {
-               clear_bit(0, &dev->context_flag);
-               return 0;
-       }
-
-       q = dev->queuelist[new];
-       atomic_inc(&q->use_count);
-       if (atomic_read(&q->use_count) == 1) {
-               atomic_dec(&q->use_count);
-               clear_bit(0, &dev->context_flag);
-               return -EINVAL;
-       }
-
-       /* This causes the X server to wake up & do a bunch of hardware
-        * interaction to actually effect the context switch.
-        */
-       sprintf(buf, "C %d %d\n", old, new);
-       DRM(write_string)(dev, buf);
-
-       atomic_dec(&q->use_count);
-
-       return 0;
-}
-
-int DRM(context_switch_complete)(drm_device_t *dev, int new)
-{
-       drm_device_dma_t *dma = dev->dma;
-
-       dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
-       dev->last_switch  = jiffies;
-
-       if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
-               DRM_ERROR("Lock isn't held after context switch\n");
-       }
-
-       if (!dma || !(dma->next_buffer && dma->next_buffer->while_locked)) {
-               if (DRM(lock_free)(dev, &dev->lock.hw_lock->lock,
-                                 DRM_KERNEL_CONTEXT)) {
-                       DRM_ERROR("Cannot free lock\n");
-               }
-       }
-
-       clear_bit(0, &dev->context_flag);
-       wake_up_interruptible(&dev->context_wait);
-
-       return 0;
-}
-
-static int DRM(init_queue)(drm_device_t *dev, drm_queue_t *q, drm_ctx_t *ctx)
-{
-       DRM_DEBUG("\n");
-
-       if (atomic_read(&q->use_count) != 1
-           || atomic_read(&q->finalization)
-           || atomic_read(&q->block_count)) {
-               DRM_ERROR("New queue is already in use: u%d f%d b%d\n",
-                         atomic_read(&q->use_count),
-                         atomic_read(&q->finalization),
-                         atomic_read(&q->block_count));
-       }
-
-       atomic_set(&q->finalization,  0);
-       atomic_set(&q->block_count,   0);
-       atomic_set(&q->block_read,    0);
-       atomic_set(&q->block_write,   0);
-       atomic_set(&q->total_queued,  0);
-       atomic_set(&q->total_flushed, 0);
-       atomic_set(&q->total_locks,   0);
-
-       init_waitqueue_head(&q->write_queue);
-       init_waitqueue_head(&q->read_queue);
-       init_waitqueue_head(&q->flush_queue);
-
-       q->flags = ctx->flags;
-
-       DRM(waitlist_create)(&q->waitlist, dev->dma->buf_count);
-
-       return 0;
-}
-
-
-/* drm_alloc_queue:
-PRE: 1) dev->queuelist[0..dev->queue_count] is allocated and will not
-       disappear (so all deallocation must be done after IOCTLs are off)
-     2) dev->queue_count < dev->queue_slots
-     3) dev->queuelist[i].use_count == 0 and
-       dev->queuelist[i].finalization == 0 if i not in use
-POST: 1) dev->queuelist[i].use_count == 1
-      2) dev->queue_count < dev->queue_slots */
-
-static int DRM(alloc_queue)(drm_device_t *dev)
-{
-       int         i;
-       drm_queue_t *queue;
-       int         oldslots;
-       int         newslots;
-                               /* Check for a free queue */
-       for (i = 0; i < dev->queue_count; i++) {
-               atomic_inc(&dev->queuelist[i]->use_count);
-               if (atomic_read(&dev->queuelist[i]->use_count) == 1
-                   && !atomic_read(&dev->queuelist[i]->finalization)) {
-                       DRM_DEBUG("%d (free)\n", i);
-                       return i;
-               }
-               atomic_dec(&dev->queuelist[i]->use_count);
-       }
-                               /* Allocate a new queue */
-       down(&dev->struct_sem);
-
-       queue = DRM(alloc)(sizeof(*queue), DRM_MEM_QUEUES);
-       memset(queue, 0, sizeof(*queue));
-       atomic_set(&queue->use_count, 1);
-
-       ++dev->queue_count;
-       if (dev->queue_count >= dev->queue_slots) {
-               oldslots = dev->queue_slots * sizeof(*dev->queuelist);
-               if (!dev->queue_slots) dev->queue_slots = 1;
-               dev->queue_slots *= 2;
-               newslots = dev->queue_slots * sizeof(*dev->queuelist);
-
-               dev->queuelist = DRM(realloc)(dev->queuelist,
-                                             oldslots,
-                                             newslots,
-                                             DRM_MEM_QUEUES);
-               if (!dev->queuelist) {
-                       up(&dev->struct_sem);
-                       DRM_DEBUG("out of memory\n");
-                       return -ENOMEM;
-               }
-       }
-       dev->queuelist[dev->queue_count-1] = queue;
-
-       up(&dev->struct_sem);
-       DRM_DEBUG("%d (new)\n", dev->queue_count - 1);
-       return dev->queue_count - 1;
-}
-
-int DRM(resctx)(struct inode *inode, struct file *filp,
-               unsigned int cmd, unsigned long arg)
-{
-       drm_ctx_res_t __user *argp = (void __user *)arg;
-       drm_ctx_res_t   res;
-       drm_ctx_t       ctx;
-       int             i;
-
-       DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
-       if (copy_from_user(&res, argp, sizeof(res)))
-               return -EFAULT;
-       if (res.count >= DRM_RESERVED_CONTEXTS) {
-               memset(&ctx, 0, sizeof(ctx));
-               for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
-                       ctx.handle = i;
-                       if (copy_to_user(&res.contexts[i],
-                                        &i,
-                                        sizeof(i)))
-                               return -EFAULT;
-               }
-       }
-       res.count = DRM_RESERVED_CONTEXTS;
-       if (copy_to_user(argp, &res, sizeof(res)))
-               return -EFAULT;
-       return 0;
-}
-
-int DRM(addctx)(struct inode *inode, struct file *filp,
-               unsigned int cmd, unsigned long arg)
-{
-       drm_file_t      *priv   = filp->private_data;
-       drm_device_t    *dev    = priv->dev;
-       drm_ctx_t       ctx;
-       drm_ctx_t       __user *argp = (void __user *)arg;
-
-       if (copy_from_user(&ctx, argp, sizeof(ctx)))
-               return -EFAULT;
-       if ((ctx.handle = DRM(alloc_queue)(dev)) == DRM_KERNEL_CONTEXT) {
-                               /* Init kernel's context and get a new one. */
-               DRM(init_queue)(dev, dev->queuelist[ctx.handle], &ctx);
-               ctx.handle = DRM(alloc_queue)(dev);
-       }
-       DRM(init_queue)(dev, dev->queuelist[ctx.handle], &ctx);
-       DRM_DEBUG("%d\n", ctx.handle);
-       if (copy_to_user(argp, &ctx, sizeof(ctx)))
-               return -EFAULT;
-       return 0;
-}
-
-int DRM(modctx)(struct inode *inode, struct file *filp,
-               unsigned int cmd, unsigned long arg)
-{
-       drm_file_t      *priv   = filp->private_data;
-       drm_device_t    *dev    = priv->dev;
-       drm_ctx_t       ctx;
-       drm_queue_t     *q;
-
-       if (copy_from_user(&ctx, (drm_ctx_t __user *)arg, sizeof(ctx)))
-               return -EFAULT;
-
-       DRM_DEBUG("%d\n", ctx.handle);
-
-       if (ctx.handle < 0 || ctx.handle >= dev->queue_count) return -EINVAL;
-       q = dev->queuelist[ctx.handle];
-
-       atomic_inc(&q->use_count);
-       if (atomic_read(&q->use_count) == 1) {
-                               /* No longer in use */
-               atomic_dec(&q->use_count);
-               return -EINVAL;
-       }
-
-       if (DRM_BUFCOUNT(&q->waitlist)) {
-               atomic_dec(&q->use_count);
-               return -EBUSY;
-       }
-
-       q->flags = ctx.flags;
-
-       atomic_dec(&q->use_count);
-       return 0;
-}
-
-int DRM(getctx)(struct inode *inode, struct file *filp,
-               unsigned int cmd, unsigned long arg)
-{
-       drm_file_t      *priv   = filp->private_data;
-       drm_device_t    *dev    = priv->dev;
-       drm_ctx_t       __user *argp = (void __user *)arg;
-       drm_ctx_t       ctx;
-       drm_queue_t     *q;
-
-       if (copy_from_user(&ctx, argp, sizeof(ctx)))
-               return -EFAULT;
-
-       DRM_DEBUG("%d\n", ctx.handle);
-
-       if (ctx.handle >= dev->queue_count) return -EINVAL;
-       q = dev->queuelist[ctx.handle];
-
-       atomic_inc(&q->use_count);
-       if (atomic_read(&q->use_count) == 1) {
-                               /* No longer in use */
-               atomic_dec(&q->use_count);
-               return -EINVAL;
-       }
-
-       ctx.flags = q->flags;
-       atomic_dec(&q->use_count);
-
-       if (copy_to_user(argp, &ctx, sizeof(ctx)))
-               return -EFAULT;
-
-       return 0;
-}
-
-int DRM(switchctx)(struct inode *inode, struct file *filp,
-                  unsigned int cmd, unsigned long arg)
-{
-       drm_file_t      *priv   = filp->private_data;
-       drm_device_t    *dev    = priv->dev;
-       drm_ctx_t       ctx;
-
-       if (copy_from_user(&ctx, (drm_ctx_t __user *)arg, sizeof(ctx)))
-               return -EFAULT;
-       DRM_DEBUG("%d\n", ctx.handle);
-       return DRM(context_switch)(dev, dev->last_context, ctx.handle);
-}
-
-int DRM(newctx)(struct inode *inode, struct file *filp,
-               unsigned int cmd, unsigned long arg)
-{
-       drm_file_t      *priv   = filp->private_data;
-       drm_device_t    *dev    = priv->dev;
-       drm_ctx_t       ctx;
-
-       if (copy_from_user(&ctx, (drm_ctx_t __user *)arg, sizeof(ctx)))
-               return -EFAULT;
-       DRM_DEBUG("%d\n", ctx.handle);
-       DRM(context_switch_complete)(dev, ctx.handle);
-
-       return 0;
-}
-
-int DRM(rmctx)(struct inode *inode, struct file *filp,
-              unsigned int cmd, unsigned long arg)
-{
-       drm_file_t      *priv   = filp->private_data;
-       drm_device_t    *dev    = priv->dev;
-       drm_ctx_t       ctx;
-       drm_queue_t     *q;
-       drm_buf_t       *buf;
-
-       if (copy_from_user(&ctx, (drm_ctx_t __user *)arg, sizeof(ctx)))
-               return -EFAULT;
-       DRM_DEBUG("%d\n", ctx.handle);
-
-       if (ctx.handle >= dev->queue_count) return -EINVAL;
-       q = dev->queuelist[ctx.handle];
-
-       atomic_inc(&q->use_count);
-       if (atomic_read(&q->use_count) == 1) {
-                               /* No longer in use */
-               atomic_dec(&q->use_count);
-               return -EINVAL;
-       }
-
-       atomic_inc(&q->finalization); /* Mark queue in finalization state */
-       atomic_sub(2, &q->use_count); /* Mark queue as unused (pending
-                                        finalization) */
-
-       while (test_and_set_bit(0, &dev->interrupt_flag)) {
-               schedule();
-               if (signal_pending(current)) {
-                       clear_bit(0, &dev->interrupt_flag);
-                       return -EINTR;
-               }
-       }
-                               /* Remove queued buffers */
-       while ((buf = DRM(waitlist_get)(&q->waitlist))) {
-               DRM(free_buffer)(dev, buf);
-       }
-       clear_bit(0, &dev->interrupt_flag);
-
-                               /* Wakeup blocked processes */
-       wake_up_interruptible(&q->read_queue);
-       wake_up_interruptible(&q->write_queue);
-       wake_up_interruptible(&q->flush_queue);
-
-                               /* Finalization over.  Queue is made
-                                  available when both use_count and
-                                  finalization become 0, which won't
-                                  happen until all the waiting processes
-                                  stop waiting. */
-       atomic_dec(&q->finalization);
-       return 0;
-}
-
diff --git a/drivers/char/drm/gamma_dma.c b/drivers/char/drm/gamma_dma.c
deleted file mode 100644 (file)
index e486fb8..0000000
+++ /dev/null
@@ -1,946 +0,0 @@
-/* gamma_dma.c -- DMA support for GMX 2000 -*- linux-c -*-
- * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Rickard E. (Rik) Faith <faith@valinux.com>
- *
- */
-
-#include "gamma.h"
-#include "drmP.h"
-#include "drm.h"
-#include "gamma_drm.h"
-#include "gamma_drv.h"
-
-#include <linux/interrupt.h>   /* For task queue support */
-#include <linux/delay.h>
-
-static inline void gamma_dma_dispatch(drm_device_t *dev, unsigned long address,
-                                     unsigned long length)
-{
-       drm_gamma_private_t *dev_priv =
-                               (drm_gamma_private_t *)dev->dev_private;
-       mb();
-       while ( GAMMA_READ(GAMMA_INFIFOSPACE) < 2)
-               cpu_relax();
-
-       GAMMA_WRITE(GAMMA_DMAADDRESS, address);
-
-       while (GAMMA_READ(GAMMA_GCOMMANDSTATUS) != 4)
-               cpu_relax();
-
-       GAMMA_WRITE(GAMMA_DMACOUNT, length / 4);
-}
-
-void gamma_dma_quiescent_single(drm_device_t *dev)
-{
-       drm_gamma_private_t *dev_priv =
-                               (drm_gamma_private_t *)dev->dev_private;
-       while (GAMMA_READ(GAMMA_DMACOUNT))
-               cpu_relax();
-
-       while (GAMMA_READ(GAMMA_INFIFOSPACE) < 2)
-               cpu_relax();
-
-       GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10);
-       GAMMA_WRITE(GAMMA_SYNC, 0);
-
-       do {
-               while (!GAMMA_READ(GAMMA_OUTFIFOWORDS))
-                       cpu_relax();
-       } while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG);
-}
-
-void gamma_dma_quiescent_dual(drm_device_t *dev)
-{
-       drm_gamma_private_t *dev_priv =
-                               (drm_gamma_private_t *)dev->dev_private;
-       while (GAMMA_READ(GAMMA_DMACOUNT))
-               cpu_relax();
-
-       while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
-               cpu_relax();
-
-       GAMMA_WRITE(GAMMA_BROADCASTMASK, 3);
-       GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10);
-       GAMMA_WRITE(GAMMA_SYNC, 0);
-
-       /* Read from first MX */
-       do {
-               while (!GAMMA_READ(GAMMA_OUTFIFOWORDS))
-                       cpu_relax();
-       } while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG);
-
-       /* Read from second MX */
-       do {
-               while (!GAMMA_READ(GAMMA_OUTFIFOWORDS + 0x10000))
-                       cpu_relax();
-       } while (GAMMA_READ(GAMMA_OUTPUTFIFO + 0x10000) != GAMMA_SYNC_TAG);
-}
-
-void gamma_dma_ready(drm_device_t *dev)
-{
-       drm_gamma_private_t *dev_priv =
-                               (drm_gamma_private_t *)dev->dev_private;
-       while (GAMMA_READ(GAMMA_DMACOUNT))
-               cpu_relax();
-}
-
-static inline int gamma_dma_is_ready(drm_device_t *dev)
-{
-       drm_gamma_private_t *dev_priv =
-                               (drm_gamma_private_t *)dev->dev_private;
-       return (!GAMMA_READ(GAMMA_DMACOUNT));
-}
-
-irqreturn_t gamma_driver_irq_handler( DRM_IRQ_ARGS )
-{
-       drm_device_t     *dev = (drm_device_t *)arg;
-       drm_device_dma_t *dma = dev->dma;
-       drm_gamma_private_t *dev_priv =
-                               (drm_gamma_private_t *)dev->dev_private;
-
-       /* FIXME: should check whether we're actually interested in the interrupt? */
-       atomic_inc(&dev->counts[6]); /* _DRM_STAT_IRQ */
-
-       while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
-               cpu_relax();
-
-       GAMMA_WRITE(GAMMA_GDELAYTIMER, 0xc350/2); /* 0x05S */
-       GAMMA_WRITE(GAMMA_GCOMMANDINTFLAGS, 8);
-       GAMMA_WRITE(GAMMA_GINTFLAGS, 0x2001);
-       if (gamma_dma_is_ready(dev)) {
-                               /* Free previous buffer */
-               if (test_and_set_bit(0, &dev->dma_flag))
-                       return IRQ_HANDLED;
-               if (dma->this_buffer) {
-                       gamma_free_buffer(dev, dma->this_buffer);
-                       dma->this_buffer = NULL;
-               }
-               clear_bit(0, &dev->dma_flag);
-
-               /* Dispatch new buffer */
-               schedule_work(&dev->work);
-       }
-       return IRQ_HANDLED;
-}
-
-/* Only called by gamma_dma_schedule. */
-static int gamma_do_dma(drm_device_t *dev, int locked)
-{
-       unsigned long    address;
-       unsigned long    length;
-       drm_buf_t        *buf;
-       int              retcode = 0;
-       drm_device_dma_t *dma = dev->dma;
-
-       if (test_and_set_bit(0, &dev->dma_flag)) return -EBUSY;
-
-
-       if (!dma->next_buffer) {
-               DRM_ERROR("No next_buffer\n");
-               clear_bit(0, &dev->dma_flag);
-               return -EINVAL;
-       }
-
-       buf     = dma->next_buffer;
-       /* WE NOW ARE ON LOGICAL PAGES!! - using page table setup in dma_init */
-       /* So we pass the buffer index value into the physical page offset */
-       address = buf->idx << 12;
-       length  = buf->used;
-
-       DRM_DEBUG("context %d, buffer %d (%ld bytes)\n",
-                 buf->context, buf->idx, length);
-
-       if (buf->list == DRM_LIST_RECLAIM) {
-               gamma_clear_next_buffer(dev);
-               gamma_free_buffer(dev, buf);
-               clear_bit(0, &dev->dma_flag);
-               return -EINVAL;
-       }
-
-       if (!length) {
-               DRM_ERROR("0 length buffer\n");
-               gamma_clear_next_buffer(dev);
-               gamma_free_buffer(dev, buf);
-               clear_bit(0, &dev->dma_flag);
-               return 0;
-       }
-
-       if (!gamma_dma_is_ready(dev)) {
-               clear_bit(0, &dev->dma_flag);
-               return -EBUSY;
-       }
-
-       if (buf->while_locked) {
-               if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
-                       DRM_ERROR("Dispatching buffer %d from pid %d"
-                                 " \"while locked\", but no lock held\n",
-                                 buf->idx, current->pid);
-               }
-       } else {
-               if (!locked && !gamma_lock_take(&dev->lock.hw_lock->lock,
-                                             DRM_KERNEL_CONTEXT)) {
-                       clear_bit(0, &dev->dma_flag);
-                       return -EBUSY;
-               }
-       }
-
-       if (dev->last_context != buf->context
-           && !(dev->queuelist[buf->context]->flags
-                & _DRM_CONTEXT_PRESERVED)) {
-                               /* PRE: dev->last_context != buf->context */
-               if (DRM(context_switch)(dev, dev->last_context,
-                                       buf->context)) {
-                       DRM(clear_next_buffer)(dev);
-                       DRM(free_buffer)(dev, buf);
-               }
-               retcode = -EBUSY;
-               goto cleanup;
-
-                               /* POST: we will wait for the context
-                                  switch and will dispatch on a later call
-                                  when dev->last_context == buf->context.
-                                  NOTE WE HOLD THE LOCK THROUGHOUT THIS
-                                  TIME! */
-       }
-
-       gamma_clear_next_buffer(dev);
-       buf->pending     = 1;
-       buf->waiting     = 0;
-       buf->list        = DRM_LIST_PEND;
-
-       /* WE NOW ARE ON LOGICAL PAGES!!! - overriding address */
-       address = buf->idx << 12;
-
-       gamma_dma_dispatch(dev, address, length);
-       gamma_free_buffer(dev, dma->this_buffer);
-       dma->this_buffer = buf;
-
-       atomic_inc(&dev->counts[7]); /* _DRM_STAT_DMA */
-       atomic_add(length, &dev->counts[8]); /* _DRM_STAT_PRIMARY */
-
-       if (!buf->while_locked && !dev->context_flag && !locked) {
-               if (gamma_lock_free(dev, &dev->lock.hw_lock->lock,
-                                 DRM_KERNEL_CONTEXT)) {
-                       DRM_ERROR("\n");
-               }
-       }
-cleanup:
-
-       clear_bit(0, &dev->dma_flag);
-
-
-       return retcode;
-}
-
-static void gamma_dma_timer_bh(unsigned long dev)
-{
-       gamma_dma_schedule((drm_device_t *)dev, 0);
-}
-
-void gamma_irq_immediate_bh(void *dev)
-{
-       gamma_dma_schedule(dev, 0);
-}
-
-int gamma_dma_schedule(drm_device_t *dev, int locked)
-{
-       int              next;
-       drm_queue_t      *q;
-       drm_buf_t        *buf;
-       int              retcode   = 0;
-       int              processed = 0;
-       int              missed;
-       int              expire    = 20;
-       drm_device_dma_t *dma      = dev->dma;
-
-       if (test_and_set_bit(0, &dev->interrupt_flag)) {
-                               /* Not reentrant */
-               atomic_inc(&dev->counts[10]); /* _DRM_STAT_MISSED */
-               return -EBUSY;
-       }
-       missed = atomic_read(&dev->counts[10]);
-
-
-again:
-       if (dev->context_flag) {
-               clear_bit(0, &dev->interrupt_flag);
-               return -EBUSY;
-       }
-       if (dma->next_buffer) {
-                               /* Unsent buffer that was previously
-                                  selected, but that couldn't be sent
-                                  because the lock could not be obtained
-                                  or the DMA engine wasn't ready.  Try
-                                  again. */
-               if (!(retcode = gamma_do_dma(dev, locked))) ++processed;
-       } else {
-               do {
-                       next = gamma_select_queue(dev, gamma_dma_timer_bh);
-                       if (next >= 0) {
-                               q   = dev->queuelist[next];
-                               buf = gamma_waitlist_get(&q->waitlist);
-                               dma->next_buffer = buf;
-                               dma->next_queue  = q;
-                               if (buf && buf->list == DRM_LIST_RECLAIM) {
-                                       gamma_clear_next_buffer(dev);
-                                       gamma_free_buffer(dev, buf);
-                               }
-                       }
-               } while (next >= 0 && !dma->next_buffer);
-               if (dma->next_buffer) {
-                       if (!(retcode = gamma_do_dma(dev, locked))) {
-                               ++processed;
-                       }
-               }
-       }
-
-       if (--expire) {
-               if (missed != atomic_read(&dev->counts[10])) {
-                       if (gamma_dma_is_ready(dev)) goto again;
-               }
-               if (processed && gamma_dma_is_ready(dev)) {
-                       processed = 0;
-                       goto again;
-               }
-       }
-
-       clear_bit(0, &dev->interrupt_flag);
-
-       return retcode;
-}
-
-static int gamma_dma_priority(struct file *filp, 
-                             drm_device_t *dev, drm_dma_t *d)
-{
-       unsigned long     address;
-       unsigned long     length;
-       int               must_free = 0;
-       int               retcode   = 0;
-       int               i;
-       int               idx;
-       drm_buf_t         *buf;
-       drm_buf_t         *last_buf = NULL;
-       drm_device_dma_t  *dma      = dev->dma;
-       int               *send_indices = NULL;
-       int               *send_sizes = NULL;
-
-       DECLARE_WAITQUEUE(entry, current);
-
-                               /* Turn off interrupt handling */
-       while (test_and_set_bit(0, &dev->interrupt_flag)) {
-               schedule();
-               if (signal_pending(current)) return -EINTR;
-       }
-       if (!(d->flags & _DRM_DMA_WHILE_LOCKED)) {
-               while (!gamma_lock_take(&dev->lock.hw_lock->lock,
-                                     DRM_KERNEL_CONTEXT)) {
-                       schedule();
-                       if (signal_pending(current)) {
-                               clear_bit(0, &dev->interrupt_flag);
-                               return -EINTR;
-                       }
-               }
-               ++must_free;
-       }
-
-       send_indices = DRM(alloc)(d->send_count * sizeof(*send_indices),
-                                 DRM_MEM_DRIVER);
-       if (send_indices == NULL)
-               return -ENOMEM;
-       if (copy_from_user(send_indices, d->send_indices, 
-                          d->send_count * sizeof(*send_indices))) {
-               retcode = -EFAULT;
-                goto cleanup;
-       }
-       
-       send_sizes = DRM(alloc)(d->send_count * sizeof(*send_sizes),
-                               DRM_MEM_DRIVER);
-       if (send_sizes == NULL)
-               return -ENOMEM;
-       if (copy_from_user(send_sizes, d->send_sizes, 
-                          d->send_count * sizeof(*send_sizes))) {
-               retcode = -EFAULT;
-                goto cleanup;
-       }
-
-       for (i = 0; i < d->send_count; i++) {
-               idx = send_indices[i];
-               if (idx < 0 || idx >= dma->buf_count) {
-                       DRM_ERROR("Index %d (of %d max)\n",
-                                 send_indices[i], dma->buf_count - 1);
-                       continue;
-               }
-               buf = dma->buflist[ idx ];
-               if (buf->filp != filp) {
-                       DRM_ERROR("Process %d using buffer not owned\n",
-                                 current->pid);
-                       retcode = -EINVAL;
-                       goto cleanup;
-               }
-               if (buf->list != DRM_LIST_NONE) {
-                       DRM_ERROR("Process %d using buffer on list %d\n",
-                                 current->pid, buf->list);
-                       retcode = -EINVAL;
-                       goto cleanup;
-               }
-                               /* This isn't a race condition on
-                                  buf->list, since our concern is the
-                                  buffer reclaim during the time the
-                                  process closes the /dev/drm? handle, so
-                                  it can't also be doing DMA. */
-               buf->list         = DRM_LIST_PRIO;
-               buf->used         = send_sizes[i];
-               buf->context      = d->context;
-               buf->while_locked = d->flags & _DRM_DMA_WHILE_LOCKED;
-               address           = (unsigned long)buf->address;
-               length            = buf->used;
-               if (!length) {
-                       DRM_ERROR("0 length buffer\n");
-               }
-               if (buf->pending) {
-                       DRM_ERROR("Sending pending buffer:"
-                                 " buffer %d, offset %d\n",
-                                 send_indices[i], i);
-                       retcode = -EINVAL;
-                       goto cleanup;
-               }
-               if (buf->waiting) {
-                       DRM_ERROR("Sending waiting buffer:"
-                                 " buffer %d, offset %d\n",
-                                 send_indices[i], i);
-                       retcode = -EINVAL;
-                       goto cleanup;
-               }
-               buf->pending = 1;
-
-               if (dev->last_context != buf->context
-                   && !(dev->queuelist[buf->context]->flags
-                        & _DRM_CONTEXT_PRESERVED)) {
-                       add_wait_queue(&dev->context_wait, &entry);
-                       current->state = TASK_INTERRUPTIBLE;
-                               /* PRE: dev->last_context != buf->context */
-                       DRM(context_switch)(dev, dev->last_context,
-                                           buf->context);
-                               /* POST: we will wait for the context
-                                  switch and will dispatch on a later call
-                                  when dev->last_context == buf->context.
-                                  NOTE WE HOLD THE LOCK THROUGHOUT THIS
-                                  TIME! */
-                       schedule();
-                       current->state = TASK_RUNNING;
-                       remove_wait_queue(&dev->context_wait, &entry);
-                       if (signal_pending(current)) {
-                               retcode = -EINTR;
-                               goto cleanup;
-                       }
-                       if (dev->last_context != buf->context) {
-                               DRM_ERROR("Context mismatch: %d %d\n",
-                                         dev->last_context,
-                                         buf->context);
-                       }
-               }
-
-               gamma_dma_dispatch(dev, address, length);
-               atomic_inc(&dev->counts[9]); /* _DRM_STAT_SPECIAL */
-               atomic_add(length, &dev->counts[8]); /* _DRM_STAT_PRIMARY */
-
-               if (last_buf) {
-                       gamma_free_buffer(dev, last_buf);
-               }
-               last_buf = buf;
-       }
-
-
-cleanup:
-       if (last_buf) {
-               gamma_dma_ready(dev);
-               gamma_free_buffer(dev, last_buf);
-       }
-       if (send_indices)
-               DRM(free)(send_indices, d->send_count * sizeof(*send_indices), 
-                         DRM_MEM_DRIVER);
-       if (send_sizes)
-               DRM(free)(send_sizes, d->send_count * sizeof(*send_sizes), 
-                         DRM_MEM_DRIVER);
-
-       if (must_free && !dev->context_flag) {
-               if (gamma_lock_free(dev, &dev->lock.hw_lock->lock,
-                                 DRM_KERNEL_CONTEXT)) {
-                       DRM_ERROR("\n");
-               }
-       }
-       clear_bit(0, &dev->interrupt_flag);
-       return retcode;
-}
-
-static int gamma_dma_send_buffers(struct file *filp,
-                                 drm_device_t *dev, drm_dma_t *d)
-{
-       DECLARE_WAITQUEUE(entry, current);
-       drm_buf_t         *last_buf = NULL;
-       int               retcode   = 0;
-       drm_device_dma_t  *dma      = dev->dma;
-       int               send_index;
-
-       if (get_user(send_index, &d->send_indices[d->send_count-1]))
-               return -EFAULT;
-
-       if (d->flags & _DRM_DMA_BLOCK) {
-               last_buf = dma->buflist[send_index];
-               add_wait_queue(&last_buf->dma_wait, &entry);
-       }
-
-       if ((retcode = gamma_dma_enqueue(filp, d))) {
-               if (d->flags & _DRM_DMA_BLOCK)
-                       remove_wait_queue(&last_buf->dma_wait, &entry);
-               return retcode;
-       }
-
-       gamma_dma_schedule(dev, 0);
-
-       if (d->flags & _DRM_DMA_BLOCK) {
-               DRM_DEBUG("%d waiting\n", current->pid);
-               for (;;) {
-                       current->state = TASK_INTERRUPTIBLE;
-                       if (!last_buf->waiting && !last_buf->pending)
-                               break; /* finished */
-                       schedule();
-                       if (signal_pending(current)) {
-                               retcode = -EINTR; /* Can't restart */
-                               break;
-                       }
-               }
-               current->state = TASK_RUNNING;
-               DRM_DEBUG("%d running\n", current->pid);
-               remove_wait_queue(&last_buf->dma_wait, &entry);
-               if (!retcode
-                   || (last_buf->list==DRM_LIST_PEND && !last_buf->pending)) {
-                       if (!waitqueue_active(&last_buf->dma_wait)) {
-                               gamma_free_buffer(dev, last_buf);
-                       }
-               }
-               if (retcode) {
-                       DRM_ERROR("ctx%d w%d p%d c%ld i%d l%d pid:%d\n",
-                                 d->context,
-                                 last_buf->waiting,
-                                 last_buf->pending,
-                                 (long)DRM_WAITCOUNT(dev, d->context),
-                                 last_buf->idx,
-                                 last_buf->list,
-                                 current->pid);
-               }
-       }
-       return retcode;
-}
-
-int gamma_dma(struct inode *inode, struct file *filp, unsigned int cmd,
-             unsigned long arg)
-{
-       drm_file_t        *priv     = filp->private_data;
-       drm_device_t      *dev      = priv->dev;
-       drm_device_dma_t  *dma      = dev->dma;
-       int               retcode   = 0;
-       drm_dma_t         __user *argp = (void __user *)arg;
-       drm_dma_t         d;
-
-       if (copy_from_user(&d, argp, sizeof(d)))
-               return -EFAULT;
-
-       if (d.send_count < 0 || d.send_count > dma->buf_count) {
-               DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n",
-                         current->pid, d.send_count, dma->buf_count);
-               return -EINVAL;
-       }
-
-       if (d.request_count < 0 || d.request_count > dma->buf_count) {
-               DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
-                         current->pid, d.request_count, dma->buf_count);
-               return -EINVAL;
-       }
-
-       if (d.send_count) {
-               if (d.flags & _DRM_DMA_PRIORITY)
-                       retcode = gamma_dma_priority(filp, dev, &d);
-               else
-                       retcode = gamma_dma_send_buffers(filp, dev, &d);
-       }
-
-       d.granted_count = 0;
-
-       if (!retcode && d.request_count) {
-               retcode = gamma_dma_get_buffers(filp, &d);
-       }
-
-       DRM_DEBUG("%d returning, granted = %d\n",
-                 current->pid, d.granted_count);
-       if (copy_to_user(argp, &d, sizeof(d)))
-               return -EFAULT;
-
-       return retcode;
-}
-
-/* =============================================================
- * DMA initialization, cleanup
- */
-
-static int gamma_do_init_dma( drm_device_t *dev, drm_gamma_init_t *init )
-{
-       drm_gamma_private_t *dev_priv;
-       drm_device_dma_t    *dma = dev->dma;
-       drm_buf_t           *buf;
-       int i;
-       struct list_head    *list;
-       unsigned long       *pgt;
-
-       DRM_DEBUG( "%s\n", __FUNCTION__ );
-
-       dev_priv = DRM(alloc)( sizeof(drm_gamma_private_t),
-                                                       DRM_MEM_DRIVER );
-       if ( !dev_priv )
-               return -ENOMEM;
-
-       dev->dev_private = (void *)dev_priv;
-
-       memset( dev_priv, 0, sizeof(drm_gamma_private_t) );
-
-       dev_priv->num_rast = init->num_rast;
-
-       list_for_each(list, &dev->maplist->head) {
-               drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head);
-               if( r_list->map &&
-                   r_list->map->type == _DRM_SHM &&
-                   r_list->map->flags & _DRM_CONTAINS_LOCK ) {
-                       dev_priv->sarea = r_list->map;
-                       break;
-               }
-       }
-       
-       dev_priv->mmio0 = drm_core_findmap(dev, init->mmio0);
-       dev_priv->mmio1 = drm_core_findmap(dev, init->mmio1);
-       dev_priv->mmio2 = drm_core_findmap(dev, init->mmio2);
-       dev_priv->mmio3 = drm_core_findmap(dev, init->mmio3);
-       
-       dev_priv->sarea_priv = (drm_gamma_sarea_t *)
-               ((u8 *)dev_priv->sarea->handle +
-                init->sarea_priv_offset);
-
-       if (init->pcimode) {
-               buf = dma->buflist[GLINT_DRI_BUF_COUNT];
-               pgt = buf->address;
-
-               for (i = 0; i < GLINT_DRI_BUF_COUNT; i++) {
-                       buf = dma->buflist[i];
-                       *pgt = virt_to_phys((void*)buf->address) | 0x07;
-                       pgt++;
-               }
-
-               buf = dma->buflist[GLINT_DRI_BUF_COUNT];
-       } else {
-               dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
-               drm_core_ioremap( dev->agp_buffer_map, dev);
-
-               buf = dma->buflist[GLINT_DRI_BUF_COUNT];
-               pgt = buf->address;
-
-               for (i = 0; i < GLINT_DRI_BUF_COUNT; i++) {
-                       buf = dma->buflist[i];
-                       *pgt = (unsigned long)buf->address + 0x07;
-                       pgt++;
-               }
-
-               buf = dma->buflist[GLINT_DRI_BUF_COUNT];
-
-               while (GAMMA_READ(GAMMA_INFIFOSPACE) < 1);
-               GAMMA_WRITE( GAMMA_GDMACONTROL, 0xe);
-       }
-       while (GAMMA_READ(GAMMA_INFIFOSPACE) < 2);
-       GAMMA_WRITE( GAMMA_PAGETABLEADDR, virt_to_phys((void*)buf->address) );
-       GAMMA_WRITE( GAMMA_PAGETABLELENGTH, 2 );
-
-       return 0;
-}
-
-int gamma_do_cleanup_dma( drm_device_t *dev )
-{
-       DRM_DEBUG( "%s\n", __FUNCTION__ );
-
-       /* Make sure interrupts are disabled here because the uninstall ioctl
-        * may not have been called from userspace and after dev_private
-        * is freed, it's too late.
-        */
-       if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
-               if ( dev->irq_enabled ) 
-                       DRM(irq_uninstall)(dev);
-
-       if ( dev->dev_private ) {
-
-               if ( dev->agp_buffer_map != NULL )
-                       drm_core_ioremapfree( dev->agp_buffer_map, dev );
-
-               DRM(free)( dev->dev_private, sizeof(drm_gamma_private_t),
-                          DRM_MEM_DRIVER );
-               dev->dev_private = NULL;
-       }
-
-       return 0;
-}
-
-int gamma_dma_init( struct inode *inode, struct file *filp,
-                 unsigned int cmd, unsigned long arg )
-{
-       drm_file_t *priv = filp->private_data;
-       drm_device_t *dev = priv->dev;
-       drm_gamma_init_t init;
-
-       LOCK_TEST_WITH_RETURN( dev, filp );
-
-       if ( copy_from_user( &init, (drm_gamma_init_t __user *)arg, sizeof(init) ) )
-               return -EFAULT;
-
-       switch ( init.func ) {
-       case GAMMA_INIT_DMA:
-               return gamma_do_init_dma( dev, &init );
-       case GAMMA_CLEANUP_DMA:
-               return gamma_do_cleanup_dma( dev );
-       }
-
-       return -EINVAL;
-}
-
-static int gamma_do_copy_dma( drm_device_t *dev, drm_gamma_copy_t *copy )
-{
-       drm_device_dma_t    *dma = dev->dma;
-       unsigned int        *screenbuf;
-
-       DRM_DEBUG( "%s\n", __FUNCTION__ );
-
-       /* We've DRM_RESTRICTED this DMA buffer */
-
-       screenbuf = dma->buflist[ GLINT_DRI_BUF_COUNT + 1 ]->address;
-
-#if 0
-       *buffer++ = 0x180;      /* Tag (FilterMode) */
-       *buffer++ = 0x200;      /* Allow FBColor through */
-       *buffer++ = 0x53B;      /* Tag */
-       *buffer++ = copy->Pitch;
-       *buffer++ = 0x53A;      /* Tag */
-       *buffer++ = copy->SrcAddress;
-       *buffer++ = 0x539;      /* Tag */
-       *buffer++ = copy->WidthHeight; /* Initiates transfer */
-       *buffer++ = 0x53C;      /* Tag - DMAOutputAddress */
-       *buffer++ = virt_to_phys((void*)screenbuf);
-       *buffer++ = 0x53D;      /* Tag - DMAOutputCount */
-       *buffer++ = copy->Count; /* Reads HostOutFifo BLOCKS until ..*/
-
-       /* Data now sitting in dma->buflist[ GLINT_DRI_BUF_COUNT + 1 ] */
-       /* Now put it back to the screen */
-
-       *buffer++ = 0x180;      /* Tag (FilterMode) */
-       *buffer++ = 0x400;      /* Allow Sync through */
-       *buffer++ = 0x538;      /* Tag - DMARectangleReadTarget */
-       *buffer++ = 0x155;      /* FBSourceData | count */
-       *buffer++ = 0x537;      /* Tag */
-       *buffer++ = copy->Pitch;
-       *buffer++ = 0x536;      /* Tag */
-       *buffer++ = copy->DstAddress;
-       *buffer++ = 0x535;      /* Tag */
-       *buffer++ = copy->WidthHeight; /* Initiates transfer */
-       *buffer++ = 0x530;      /* Tag - DMAAddr */
-       *buffer++ = virt_to_phys((void*)screenbuf);
-       *buffer++ = 0x531;
-       *buffer++ = copy->Count; /* initiates DMA transfer of color data */
-#endif
-
-       /* need to dispatch it now */
-
-       return 0;
-}
-
-int gamma_dma_copy( struct inode *inode, struct file *filp,
-                 unsigned int cmd, unsigned long arg )
-{
-       drm_file_t *priv = filp->private_data;
-       drm_device_t *dev = priv->dev;
-       drm_gamma_copy_t copy;
-
-       if ( copy_from_user( &copy, (drm_gamma_copy_t __user *)arg, sizeof(copy) ) )
-               return -EFAULT;
-
-       return gamma_do_copy_dma( dev, &copy );
-}
-
-/* =============================================================
- * Per Context SAREA Support
- */
-
-int gamma_getsareactx(struct inode *inode, struct file *filp,
-                    unsigned int cmd, unsigned long arg)
-{
-       drm_file_t      *priv   = filp->private_data;
-       drm_device_t    *dev    = priv->dev;
-       drm_ctx_priv_map_t __user *argp = (void __user *)arg;
-       drm_ctx_priv_map_t request;
-       drm_map_t *map;
-
-       if (copy_from_user(&request, argp, sizeof(request)))
-               return -EFAULT;
-
-       down(&dev->struct_sem);
-       if ((int)request.ctx_id >= dev->max_context) {
-               up(&dev->struct_sem);
-               return -EINVAL;
-       }
-
-       map = dev->context_sareas[request.ctx_id];
-       up(&dev->struct_sem);
-
-       request.handle = map->handle;
-       if (copy_to_user(argp, &request, sizeof(request)))
-               return -EFAULT;
-       return 0;
-}
-
-int gamma_setsareactx(struct inode *inode, struct file *filp,
-                    unsigned int cmd, unsigned long arg)
-{
-       drm_file_t      *priv   = filp->private_data;
-       drm_device_t    *dev    = priv->dev;
-       drm_ctx_priv_map_t request;
-       drm_map_t *map = NULL;
-       drm_map_list_t *r_list;
-       struct list_head *list;
-
-       if (copy_from_user(&request,
-                          (drm_ctx_priv_map_t __user *)arg,
-                          sizeof(request)))
-               return -EFAULT;
-
-       down(&dev->struct_sem);
-       r_list = NULL;
-       list_for_each(list, &dev->maplist->head) {
-               r_list = list_entry(list, drm_map_list_t, head);
-               if(r_list->map &&
-                  r_list->map->handle == request.handle) break;
-       }
-       if (list == &(dev->maplist->head)) {
-               up(&dev->struct_sem);
-               return -EINVAL;
-       }
-       map = r_list->map;
-       up(&dev->struct_sem);
-
-       if (!map) return -EINVAL;
-
-       down(&dev->struct_sem);
-       if ((int)request.ctx_id >= dev->max_context) {
-               up(&dev->struct_sem);
-               return -EINVAL;
-       }
-       dev->context_sareas[request.ctx_id] = map;
-       up(&dev->struct_sem);
-       return 0;
-}
-
-void gamma_driver_irq_preinstall( drm_device_t *dev ) {
-       drm_gamma_private_t *dev_priv =
-                               (drm_gamma_private_t *)dev->dev_private;
-
-       while(GAMMA_READ(GAMMA_INFIFOSPACE) < 2)
-               cpu_relax();
-
-       GAMMA_WRITE( GAMMA_GCOMMANDMODE,        0x00000004 );
-       GAMMA_WRITE( GAMMA_GDMACONTROL,         0x00000000 );
-}
-
-void gamma_driver_irq_postinstall( drm_device_t *dev ) {
-       drm_gamma_private_t *dev_priv =
-                               (drm_gamma_private_t *)dev->dev_private;
-
-       while(GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
-               cpu_relax();
-
-       GAMMA_WRITE( GAMMA_GINTENABLE,          0x00002001 );
-       GAMMA_WRITE( GAMMA_COMMANDINTENABLE,    0x00000008 );
-       GAMMA_WRITE( GAMMA_GDELAYTIMER,         0x00039090 );
-}
-
-void gamma_driver_irq_uninstall( drm_device_t *dev ) {
-       drm_gamma_private_t *dev_priv =
-                               (drm_gamma_private_t *)dev->dev_private;
-       if (!dev_priv)
-               return;
-
-       while(GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
-               cpu_relax();
-
-       GAMMA_WRITE( GAMMA_GDELAYTIMER,         0x00000000 );
-       GAMMA_WRITE( GAMMA_COMMANDINTENABLE,    0x00000000 );
-       GAMMA_WRITE( GAMMA_GINTENABLE,          0x00000000 );
-}
-
-extern drm_ioctl_desc_t DRM(ioctls)[];
-
-static int gamma_driver_preinit(drm_device_t *dev)
-{
-       /* reset the finish ioctl */
-       DRM(ioctls)[DRM_IOCTL_NR(DRM_IOCTL_FINISH)].func = DRM(finish);
-       return 0;
-}
-
-static void gamma_driver_pretakedown(drm_device_t *dev)
-{
-       gamma_do_cleanup_dma(dev);
-}
-
-static void gamma_driver_dma_ready(drm_device_t *dev)
-{
-       gamma_dma_ready(dev);
-}
-
-static int gamma_driver_dma_quiescent(drm_device_t *dev)
-{
-       drm_gamma_private_t *dev_priv = (
-               drm_gamma_private_t *)dev->dev_private;
-       if (dev_priv->num_rast == 2)
-               gamma_dma_quiescent_dual(dev);
-       else gamma_dma_quiescent_single(dev);
-       return 0;
-}
-
-void gamma_driver_register_fns(drm_device_t *dev)
-{
-       dev->driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ;
-       DRM(fops).read = gamma_fops_read;
-       DRM(fops).poll = gamma_fops_poll;
-       dev->driver.preinit = gamma_driver_preinit;
-       dev->driver.pretakedown = gamma_driver_pretakedown;
-       dev->driver.dma_ready = gamma_driver_dma_ready;
-       dev->driver.dma_quiescent = gamma_driver_dma_quiescent;
-       dev->driver.dma_flush_block_and_flush = gamma_flush_block_and_flush;
-       dev->driver.dma_flush_unblock = gamma_flush_unblock;
-}
diff --git a/drivers/char/drm/gamma_drm.h b/drivers/char/drm/gamma_drm.h
deleted file mode 100644 (file)
index 20819de..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-#ifndef _GAMMA_DRM_H_
-#define _GAMMA_DRM_H_
-
-typedef struct _drm_gamma_tex_region {
-       unsigned char next, prev; /* indices to form a circular LRU  */
-       unsigned char in_use;   /* owned by a client, or free? */
-       int age;                /* tracked by clients to update local LRU's */
-} drm_gamma_tex_region_t;
-
-typedef struct {
-       unsigned int    GDeltaMode;
-       unsigned int    GDepthMode;
-       unsigned int    GGeometryMode;
-       unsigned int    GTransformMode;
-} drm_gamma_context_regs_t;
-
-typedef struct _drm_gamma_sarea {
-       drm_gamma_context_regs_t context_state;
-
-       unsigned int dirty;
-
-
-       /* Maintain an LRU of contiguous regions of texture space.  If
-        * you think you own a region of texture memory, and it has an
-        * age different to the one you set, then you are mistaken and
-        * it has been stolen by another client.  If global texAge
-        * hasn't changed, there is no need to walk the list.
-        *
-        * These regions can be used as a proxy for the fine-grained
-        * texture information of other clients - by maintaining them
-        * in the same lru which is used to age their own textures,
-        * clients have an approximate lru for the whole of global
-        * texture space, and can make informed decisions as to which
-        * areas to kick out.  There is no need to choose whether to
-        * kick out your own texture or someone else's - simply eject
-        * them all in LRU order.  
-        */
-   
-#define GAMMA_NR_TEX_REGIONS 64
-       drm_gamma_tex_region_t texList[GAMMA_NR_TEX_REGIONS+1]; 
-                               /* Last elt is sentinal */
-        int texAge;            /* last time texture was uploaded */
-        int last_enqueue;      /* last time a buffer was enqueued */
-       int last_dispatch;      /* age of the most recently dispatched buffer */
-       int last_quiescent;     /*  */
-       int ctxOwner;           /* last context to upload state */
-
-       int vertex_prim;
-} drm_gamma_sarea_t;
-
-/* WARNING: If you change any of these defines, make sure to change the
- * defines in the Xserver file (xf86drmGamma.h)
- */
-
-/* Gamma specific ioctls
- * The device specific ioctl range is 0x40 to 0x79.
- */
-#define DRM_IOCTL_GAMMA_INIT           DRM_IOW( 0x40, drm_gamma_init_t)
-#define DRM_IOCTL_GAMMA_COPY           DRM_IOW( 0x41, drm_gamma_copy_t)
-
-typedef struct drm_gamma_copy {
-       unsigned int    DMAOutputAddress;
-       unsigned int    DMAOutputCount;
-       unsigned int    DMAReadGLINTSource;
-       unsigned int    DMARectangleWriteAddress;
-       unsigned int    DMARectangleWriteLinePitch;
-       unsigned int    DMARectangleWrite;
-       unsigned int    DMARectangleReadAddress;
-       unsigned int    DMARectangleReadLinePitch;
-       unsigned int    DMARectangleRead;
-       unsigned int    DMARectangleReadTarget;
-} drm_gamma_copy_t;
-
-typedef struct drm_gamma_init {
-       enum {
-               GAMMA_INIT_DMA    = 0x01,
-               GAMMA_CLEANUP_DMA = 0x02
-       } func;
-
-       int sarea_priv_offset;
-       int pcimode;
-       unsigned int mmio0;
-       unsigned int mmio1;
-       unsigned int mmio2;
-       unsigned int mmio3;
-       unsigned int buffers_offset;
-       int num_rast;
-} drm_gamma_init_t;
-
-#endif /* _GAMMA_DRM_H_ */
diff --git a/drivers/char/drm/gamma_drv.c b/drivers/char/drm/gamma_drv.c
deleted file mode 100644 (file)
index e7e64b6..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/* gamma.c -- 3dlabs GMX 2000 driver -*- linux-c -*-
- * Created: Mon Jan  4 08:58:31 1999 by faith@precisioninsight.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Rickard E. (Rik) Faith <faith@valinux.com>
- *    Gareth Hughes <gareth@valinux.com>
- */
-
-#include <linux/config.h>
-#include "gamma.h"
-#include "drmP.h"
-#include "drm.h"
-#include "gamma_drm.h"
-#include "gamma_drv.h"
-
-#include "drm_auth.h"
-#include "drm_agpsupport.h"
-#include "drm_bufs.h"
-#include "gamma_context.h"     /* NOTE! */
-#include "drm_dma.h"
-#include "gamma_old_dma.h"     /* NOTE */
-#include "drm_drawable.h"
-#include "drm_drv.h"
-
-#include "drm_fops.h"
-#include "drm_init.h"
-#include "drm_ioctl.h"
-#include "drm_irq.h"
-#include "gamma_lists.h"        /* NOTE */
-#include "drm_lock.h"
-#include "gamma_lock.h"                /* NOTE */
-#include "drm_memory.h"
-#include "drm_proc.h"
-#include "drm_vm.h"
-#include "drm_stub.h"
-#include "drm_scatter.h"
diff --git a/drivers/char/drm/gamma_drv.h b/drivers/char/drm/gamma_drv.h
deleted file mode 100644 (file)
index 146fcc6..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/* gamma_drv.h -- Private header for 3dlabs GMX 2000 driver -*- linux-c -*-
- * Created: Mon Jan  4 10:05:05 1999 by faith@precisioninsight.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Rickard E. (Rik) Faith <faith@valinux.com>
- *
- */
-
-#ifndef _GAMMA_DRV_H_
-#define _GAMMA_DRV_H_
-
-typedef struct drm_gamma_private {
-       drm_gamma_sarea_t *sarea_priv;
-       drm_map_t *sarea;
-       drm_map_t *mmio0;
-       drm_map_t *mmio1;
-       drm_map_t *mmio2;
-       drm_map_t *mmio3;
-       int num_rast;
-} drm_gamma_private_t;
-
-                               /* gamma_dma.c */
-extern int gamma_dma_init( struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg );
-extern int gamma_dma_copy( struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg );
-
-extern int gamma_do_cleanup_dma( drm_device_t *dev );
-extern void gamma_dma_ready(drm_device_t *dev);
-extern void gamma_dma_quiescent_single(drm_device_t *dev);
-extern void gamma_dma_quiescent_dual(drm_device_t *dev);
-
-                               /* gamma_dma.c */
-extern int  gamma_dma_schedule(drm_device_t *dev, int locked);
-extern int  gamma_dma(struct inode *inode, struct file *filp,
-                     unsigned int cmd, unsigned long arg);
-extern int  gamma_find_devices(void);
-extern int  gamma_found(void);
-
-/* Gamma-specific code pulled from drm_fops.h:
- */
-extern int          DRM(finish)(struct inode *inode, struct file *filp,
-                                unsigned int cmd, unsigned long arg);
-extern int          DRM(flush_unblock)(drm_device_t *dev, int context,
-                                       drm_lock_flags_t flags);
-extern int          DRM(flush_block_and_flush)(drm_device_t *dev, int context,
-                                               drm_lock_flags_t flags);
-
-/* Gamma-specific code pulled from drm_dma.h:
- */
-extern void         DRM(clear_next_buffer)(drm_device_t *dev);
-extern int          DRM(select_queue)(drm_device_t *dev,
-                                      void (*wrapper)(unsigned long));
-extern int          DRM(dma_enqueue)(struct file *filp, drm_dma_t *dma);
-extern int          DRM(dma_get_buffers)(struct file *filp, drm_dma_t *dma);
-
-
-/* Gamma-specific code pulled from drm_lists.h (now renamed gamma_lists.h):
- */
-extern int          DRM(waitlist_create)(drm_waitlist_t *bl, int count);
-extern int          DRM(waitlist_destroy)(drm_waitlist_t *bl);
-extern int          DRM(waitlist_put)(drm_waitlist_t *bl, drm_buf_t *buf);
-extern drm_buf_t     *DRM(waitlist_get)(drm_waitlist_t *bl);
-extern int          DRM(freelist_create)(drm_freelist_t *bl, int count);
-extern int          DRM(freelist_destroy)(drm_freelist_t *bl);
-extern int          DRM(freelist_put)(drm_device_t *dev, drm_freelist_t *bl,
-                                      drm_buf_t *buf);
-extern drm_buf_t     *DRM(freelist_get)(drm_freelist_t *bl, int block);
-
-/* externs for gamma changes to the ops */
-extern struct file_operations DRM(fops);
-extern unsigned int gamma_fops_poll(struct file *filp, struct poll_table_struct *wait);
-extern ssize_t gamma_fops_read(struct file *filp, char __user *buf, size_t count, loff_t *off);
-
-
-#define GLINT_DRI_BUF_COUNT 256
-
-#define GAMMA_OFF(reg)                                            \
-       ((reg < 0x1000)                                            \
-        ? reg                                                     \
-        : ((reg < 0x10000)                                        \
-           ? (reg - 0x1000)                                       \
-           : ((reg < 0x11000)                                     \
-              ? (reg - 0x10000)                                   \
-              : (reg - 0x11000))))
-
-#define GAMMA_BASE(reg)         ((unsigned long)                                    \
-                         ((reg < 0x1000)    ? dev_priv->mmio0->handle :     \
-                          ((reg < 0x10000)  ? dev_priv->mmio1->handle :     \
-                           ((reg < 0x11000) ? dev_priv->mmio2->handle :     \
-                                              dev_priv->mmio3->handle))))
-#define GAMMA_ADDR(reg)         (GAMMA_BASE(reg) + GAMMA_OFF(reg))
-#define GAMMA_DEREF(reg) *(__volatile__ int *)GAMMA_ADDR(reg)
-#define GAMMA_READ(reg)         GAMMA_DEREF(reg)
-#define GAMMA_WRITE(reg,val) do { GAMMA_DEREF(reg) = val; } while (0)
-
-#define GAMMA_BROADCASTMASK    0x9378
-#define GAMMA_COMMANDINTENABLE 0x0c48
-#define GAMMA_DMAADDRESS       0x0028
-#define GAMMA_DMACOUNT        0x0030
-#define GAMMA_FILTERMODE       0x8c00
-#define GAMMA_GCOMMANDINTFLAGS 0x0c50
-#define GAMMA_GCOMMANDMODE     0x0c40
-#define                GAMMA_QUEUED_DMA_MODE           1<<1
-#define GAMMA_GCOMMANDSTATUS   0x0c60
-#define GAMMA_GDELAYTIMER      0x0c38
-#define GAMMA_GDMACONTROL      0x0060
-#define        GAMMA_USE_AGP                   1<<1
-#define GAMMA_GINTENABLE       0x0808
-#define GAMMA_GINTFLAGS               0x0810
-#define GAMMA_INFIFOSPACE      0x0018
-#define GAMMA_OUTFIFOWORDS     0x0020
-#define GAMMA_OUTPUTFIFO       0x2000
-#define GAMMA_SYNC            0x8c40
-#define GAMMA_SYNC_TAG        0x0188
-#define GAMMA_PAGETABLEADDR    0x0C00
-#define GAMMA_PAGETABLELENGTH  0x0C08
-
-#define GAMMA_PASSTHROUGH      0x1FE
-#define GAMMA_DMAADDRTAG       0x530
-#define GAMMA_DMACOUNTTAG      0x531
-#define GAMMA_COMMANDINTTAG    0x532
-
-#endif
diff --git a/drivers/char/drm/gamma_lists.h b/drivers/char/drm/gamma_lists.h
deleted file mode 100644 (file)
index 2d93f41..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-/* drm_lists.h -- Buffer list handling routines -*- linux-c -*-
- * Created: Mon Apr 19 20:54:22 1999 by faith@valinux.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Rickard E. (Rik) Faith <faith@valinux.com>
- *    Gareth Hughes <gareth@valinux.com>
- */
-
-#include "drmP.h"
-
-
-int DRM(waitlist_create)(drm_waitlist_t *bl, int count)
-{
-       if (bl->count) return -EINVAL;
-
-       bl->bufs       = DRM(alloc)((bl->count + 2) * sizeof(*bl->bufs),
-                                   DRM_MEM_BUFLISTS);
-
-       if(!bl->bufs) return -ENOMEM;
-       memset(bl->bufs, 0, sizeof(*bl->bufs));
-       bl->count      = count;
-       bl->rp         = bl->bufs;
-       bl->wp         = bl->bufs;
-       bl->end        = &bl->bufs[bl->count+1];
-       spin_lock_init(&bl->write_lock);
-       spin_lock_init(&bl->read_lock);
-       return 0;
-}
-
-int DRM(waitlist_destroy)(drm_waitlist_t *bl)
-{
-       if (bl->rp != bl->wp) return -EINVAL;
-       if (bl->bufs) DRM(free)(bl->bufs,
-                               (bl->count + 2) * sizeof(*bl->bufs),
-                               DRM_MEM_BUFLISTS);
-       bl->count = 0;
-       bl->bufs  = NULL;
-       bl->rp    = NULL;
-       bl->wp    = NULL;
-       bl->end   = NULL;
-       return 0;
-}
-
-int DRM(waitlist_put)(drm_waitlist_t *bl, drm_buf_t *buf)
-{
-       int           left;
-       unsigned long flags;
-
-       left = DRM_LEFTCOUNT(bl);
-       if (!left) {
-               DRM_ERROR("Overflow while adding buffer %d from filp %p\n",
-                         buf->idx, buf->filp);
-               return -EINVAL;
-       }
-       buf->list        = DRM_LIST_WAIT;
-
-       spin_lock_irqsave(&bl->write_lock, flags);
-       *bl->wp = buf;
-       if (++bl->wp >= bl->end) bl->wp = bl->bufs;
-       spin_unlock_irqrestore(&bl->write_lock, flags);
-
-       return 0;
-}
-
-drm_buf_t *DRM(waitlist_get)(drm_waitlist_t *bl)
-{
-       drm_buf_t     *buf;
-       unsigned long flags;
-
-       spin_lock_irqsave(&bl->read_lock, flags);
-       buf = *bl->rp;
-       if (bl->rp == bl->wp) {
-               spin_unlock_irqrestore(&bl->read_lock, flags);
-               return NULL;
-       }
-       if (++bl->rp >= bl->end) bl->rp = bl->bufs;
-       spin_unlock_irqrestore(&bl->read_lock, flags);
-
-       return buf;
-}
-
-int DRM(freelist_create)(drm_freelist_t *bl, int count)
-{
-       atomic_set(&bl->count, 0);
-       bl->next      = NULL;
-       init_waitqueue_head(&bl->waiting);
-       bl->low_mark  = 0;
-       bl->high_mark = 0;
-       atomic_set(&bl->wfh,   0);
-       spin_lock_init(&bl->lock);
-       ++bl->initialized;
-       return 0;
-}
-
-int DRM(freelist_destroy)(drm_freelist_t *bl)
-{
-       atomic_set(&bl->count, 0);
-       bl->next = NULL;
-       return 0;
-}
-
-int DRM(freelist_put)(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf)
-{
-       drm_device_dma_t *dma  = dev->dma;
-
-       if (!dma) {
-               DRM_ERROR("No DMA support\n");
-               return 1;
-       }
-
-       if (buf->waiting || buf->pending || buf->list == DRM_LIST_FREE) {
-               DRM_ERROR("Freed buffer %d: w%d, p%d, l%d\n",
-                         buf->idx, buf->waiting, buf->pending, buf->list);
-       }
-       if (!bl) return 1;
-       buf->list       = DRM_LIST_FREE;
-
-       spin_lock(&bl->lock);
-       buf->next       = bl->next;
-       bl->next        = buf;
-       spin_unlock(&bl->lock);
-
-       atomic_inc(&bl->count);
-       if (atomic_read(&bl->count) > dma->buf_count) {
-               DRM_ERROR("%d of %d buffers free after addition of %d\n",
-                         atomic_read(&bl->count), dma->buf_count, buf->idx);
-               return 1;
-       }
-                               /* Check for high water mark */
-       if (atomic_read(&bl->wfh) && atomic_read(&bl->count)>=bl->high_mark) {
-               atomic_set(&bl->wfh, 0);
-               wake_up_interruptible(&bl->waiting);
-       }
-       return 0;
-}
-
-static drm_buf_t *DRM(freelist_try)(drm_freelist_t *bl)
-{
-       drm_buf_t         *buf;
-
-       if (!bl) return NULL;
-
-                               /* Get buffer */
-       spin_lock(&bl->lock);
-       if (!bl->next) {
-               spin_unlock(&bl->lock);
-               return NULL;
-       }
-       buf       = bl->next;
-       bl->next  = bl->next->next;
-       spin_unlock(&bl->lock);
-
-       atomic_dec(&bl->count);
-       buf->next = NULL;
-       buf->list = DRM_LIST_NONE;
-       if (buf->waiting || buf->pending) {
-               DRM_ERROR("Free buffer %d: w%d, p%d, l%d\n",
-                         buf->idx, buf->waiting, buf->pending, buf->list);
-       }
-
-       return buf;
-}
-
-drm_buf_t *DRM(freelist_get)(drm_freelist_t *bl, int block)
-{
-       drm_buf_t         *buf  = NULL;
-       DECLARE_WAITQUEUE(entry, current);
-
-       if (!bl || !bl->initialized) return NULL;
-
-                               /* Check for low water mark */
-       if (atomic_read(&bl->count) <= bl->low_mark) /* Became low */
-               atomic_set(&bl->wfh, 1);
-       if (atomic_read(&bl->wfh)) {
-               if (block) {
-                       add_wait_queue(&bl->waiting, &entry);
-                       for (;;) {
-                               current->state = TASK_INTERRUPTIBLE;
-                               if (!atomic_read(&bl->wfh)
-                                   && (buf = DRM(freelist_try)(bl))) break;
-                               schedule();
-                               if (signal_pending(current)) break;
-                       }
-                       current->state = TASK_RUNNING;
-                       remove_wait_queue(&bl->waiting, &entry);
-               }
-               return buf;
-       }
-
-       return DRM(freelist_try)(bl);
-}
-
diff --git a/drivers/char/drm/gamma_lock.h b/drivers/char/drm/gamma_lock.h
deleted file mode 100644 (file)
index ddec67e..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/* lock.c -- IOCTLs for locking -*- linux-c -*-
- * Created: Tue Feb  2 08:37:54 1999 by faith@valinux.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Rickard E. (Rik) Faith <faith@valinux.com>
- *    Gareth Hughes <gareth@valinux.com>
- */
-
-
-/* Gamma-specific code extracted from drm_lock.h:
- */
-static int DRM(flush_queue)(drm_device_t *dev, int context)
-{
-       DECLARE_WAITQUEUE(entry, current);
-       int               ret   = 0;
-       drm_queue_t       *q    = dev->queuelist[context];
-
-       DRM_DEBUG("\n");
-
-       atomic_inc(&q->use_count);
-       if (atomic_read(&q->use_count) > 1) {
-               atomic_inc(&q->block_write);
-               add_wait_queue(&q->flush_queue, &entry);
-               atomic_inc(&q->block_count);
-               for (;;) {
-                       current->state = TASK_INTERRUPTIBLE;
-                       if (!DRM_BUFCOUNT(&q->waitlist)) break;
-                       schedule();
-                       if (signal_pending(current)) {
-                               ret = -EINTR; /* Can't restart */
-                               break;
-                       }
-               }
-               atomic_dec(&q->block_count);
-               current->state = TASK_RUNNING;
-               remove_wait_queue(&q->flush_queue, &entry);
-       }
-       atomic_dec(&q->use_count);
-
-                               /* NOTE: block_write is still incremented!
-                                  Use drm_flush_unlock_queue to decrement. */
-       return ret;
-}
-
-static int DRM(flush_unblock_queue)(drm_device_t *dev, int context)
-{
-       drm_queue_t       *q    = dev->queuelist[context];
-
-       DRM_DEBUG("\n");
-
-       atomic_inc(&q->use_count);
-       if (atomic_read(&q->use_count) > 1) {
-               if (atomic_read(&q->block_write)) {
-                       atomic_dec(&q->block_write);
-                       wake_up_interruptible(&q->write_queue);
-               }
-       }
-       atomic_dec(&q->use_count);
-       return 0;
-}
-
-int DRM(flush_block_and_flush)(drm_device_t *dev, int context,
-                              drm_lock_flags_t flags)
-{
-       int ret = 0;
-       int i;
-
-       DRM_DEBUG("\n");
-
-       if (flags & _DRM_LOCK_FLUSH) {
-               ret = DRM(flush_queue)(dev, DRM_KERNEL_CONTEXT);
-               if (!ret) ret = DRM(flush_queue)(dev, context);
-       }
-       if (flags & _DRM_LOCK_FLUSH_ALL) {
-               for (i = 0; !ret && i < dev->queue_count; i++) {
-                       ret = DRM(flush_queue)(dev, i);
-               }
-       }
-       return ret;
-}
-
-int DRM(flush_unblock)(drm_device_t *dev, int context, drm_lock_flags_t flags)
-{
-       int ret = 0;
-       int i;
-
-       DRM_DEBUG("\n");
-
-       if (flags & _DRM_LOCK_FLUSH) {
-               ret = DRM(flush_unblock_queue)(dev, DRM_KERNEL_CONTEXT);
-               if (!ret) ret = DRM(flush_unblock_queue)(dev, context);
-       }
-       if (flags & _DRM_LOCK_FLUSH_ALL) {
-               for (i = 0; !ret && i < dev->queue_count; i++) {
-                       ret = DRM(flush_unblock_queue)(dev, i);
-               }
-       }
-
-       return ret;
-}
-
-int DRM(finish)(struct inode *inode, struct file *filp, unsigned int cmd,
-               unsigned long arg)
-{
-       drm_file_t        *priv   = filp->private_data;
-       drm_device_t      *dev    = priv->dev;
-       int               ret     = 0;
-       drm_lock_t        lock;
-
-       DRM_DEBUG("\n");
-
-       if (copy_from_user(&lock, (drm_lock_t __user *)arg, sizeof(lock)))
-               return -EFAULT;
-       ret = DRM(flush_block_and_flush)(dev, lock.context, lock.flags);
-       DRM(flush_unblock)(dev, lock.context, lock.flags);
-       return ret;
-}
diff --git a/drivers/char/drm/gamma_old_dma.h b/drivers/char/drm/gamma_old_dma.h
deleted file mode 100644 (file)
index abdd454..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-/* drm_dma.c -- DMA IOCTL and function support -*- linux-c -*-
- * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com
- *
- * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Rickard E. (Rik) Faith <faith@valinux.com>
- *    Gareth Hughes <gareth@valinux.com>
- */
-
-
-/* Gamma-specific code pulled from drm_dma.h:
- */
-
-void DRM(clear_next_buffer)(drm_device_t *dev)
-{
-       drm_device_dma_t *dma = dev->dma;
-
-       dma->next_buffer = NULL;
-       if (dma->next_queue && !DRM_BUFCOUNT(&dma->next_queue->waitlist)) {
-               wake_up_interruptible(&dma->next_queue->flush_queue);
-       }
-       dma->next_queue  = NULL;
-}
-
-int DRM(select_queue)(drm_device_t *dev, void (*wrapper)(unsigned long))
-{
-       int        i;
-       int        candidate = -1;
-       int        j         = jiffies;
-
-       if (!dev) {
-               DRM_ERROR("No device\n");
-               return -1;
-       }
-       if (!dev->queuelist || !dev->queuelist[DRM_KERNEL_CONTEXT]) {
-                               /* This only happens between the time the
-                                  interrupt is initialized and the time
-                                  the queues are initialized. */
-               return -1;
-       }
-
-                               /* Doing "while locked" DMA? */
-       if (DRM_WAITCOUNT(dev, DRM_KERNEL_CONTEXT)) {
-               return DRM_KERNEL_CONTEXT;
-       }
-
-                               /* If there are buffers on the last_context
-                                  queue, and we have not been executing
-                                  this context very long, continue to
-                                  execute this context. */
-       if (dev->last_switch <= j
-           && dev->last_switch + DRM_TIME_SLICE > j
-           && DRM_WAITCOUNT(dev, dev->last_context)) {
-               return dev->last_context;
-       }
-
-                               /* Otherwise, find a candidate */
-       for (i = dev->last_checked + 1; i < dev->queue_count; i++) {
-               if (DRM_WAITCOUNT(dev, i)) {
-                       candidate = dev->last_checked = i;
-                       break;
-               }
-       }
-
-       if (candidate < 0) {
-               for (i = 0; i < dev->queue_count; i++) {
-                       if (DRM_WAITCOUNT(dev, i)) {
-                               candidate = dev->last_checked = i;
-                               break;
-                       }
-               }
-       }
-
-       if (wrapper
-           && candidate >= 0
-           && candidate != dev->last_context
-           && dev->last_switch <= j
-           && dev->last_switch + DRM_TIME_SLICE > j) {
-               if (dev->timer.expires != dev->last_switch + DRM_TIME_SLICE) {
-                       del_timer(&dev->timer);
-                       dev->timer.function = wrapper;
-                       dev->timer.data     = (unsigned long)dev;
-                       dev->timer.expires  = dev->last_switch+DRM_TIME_SLICE;
-                       add_timer(&dev->timer);
-               }
-               return -1;
-       }
-
-       return candidate;
-}
-
-
-int DRM(dma_enqueue)(struct file *filp, drm_dma_t *d)
-{
-       drm_file_t    *priv   = filp->private_data;
-       drm_device_t  *dev    = priv->dev;
-       int               i;
-       drm_queue_t       *q;
-       drm_buf_t         *buf;
-       int               idx;
-       int               while_locked = 0;
-       drm_device_dma_t  *dma = dev->dma;
-       int               *ind;
-       int               err;
-       DECLARE_WAITQUEUE(entry, current);
-
-       DRM_DEBUG("%d\n", d->send_count);
-
-       if (d->flags & _DRM_DMA_WHILE_LOCKED) {
-               int context = dev->lock.hw_lock->lock;
-
-               if (!_DRM_LOCK_IS_HELD(context)) {
-                       DRM_ERROR("No lock held during \"while locked\""
-                                 " request\n");
-                       return -EINVAL;
-               }
-               if (d->context != _DRM_LOCKING_CONTEXT(context)
-                   && _DRM_LOCKING_CONTEXT(context) != DRM_KERNEL_CONTEXT) {
-                       DRM_ERROR("Lock held by %d while %d makes"
-                                 " \"while locked\" request\n",
-                                 _DRM_LOCKING_CONTEXT(context),
-                                 d->context);
-                       return -EINVAL;
-               }
-               q = dev->queuelist[DRM_KERNEL_CONTEXT];
-               while_locked = 1;
-       } else {
-               q = dev->queuelist[d->context];
-       }
-
-
-       atomic_inc(&q->use_count);
-       if (atomic_read(&q->block_write)) {
-               add_wait_queue(&q->write_queue, &entry);
-               atomic_inc(&q->block_count);
-               for (;;) {
-                       current->state = TASK_INTERRUPTIBLE;
-                       if (!atomic_read(&q->block_write)) break;
-                       schedule();
-                       if (signal_pending(current)) {
-                               atomic_dec(&q->use_count);
-                               remove_wait_queue(&q->write_queue, &entry);
-                               return -EINTR;
-                       }
-               }
-               atomic_dec(&q->block_count);
-               current->state = TASK_RUNNING;
-               remove_wait_queue(&q->write_queue, &entry);
-       }
-
-       ind = DRM(alloc)(d->send_count * sizeof(int), DRM_MEM_DRIVER);
-       if (!ind)
-               return -ENOMEM;
-
-       if (copy_from_user(ind, d->send_indices, d->send_count * sizeof(int))) {
-               err = -EFAULT;
-                goto out;
-       }
-
-       err = -EINVAL;
-       for (i = 0; i < d->send_count; i++) {
-               idx = ind[i];
-               if (idx < 0 || idx >= dma->buf_count) {
-                       DRM_ERROR("Index %d (of %d max)\n",
-                                 ind[i], dma->buf_count - 1);
-                       goto out;
-               }
-               buf = dma->buflist[ idx ];
-               if (buf->filp != filp) {
-                       DRM_ERROR("Process %d using buffer not owned\n",
-                                 current->pid);
-                       goto out;
-               }
-               if (buf->list != DRM_LIST_NONE) {
-                       DRM_ERROR("Process %d using buffer %d on list %d\n",
-                                 current->pid, buf->idx, buf->list);
-                       goto out;
-               }
-               buf->used         = ind[i];
-               buf->while_locked = while_locked;
-               buf->context      = d->context;
-               if (!buf->used) {
-                       DRM_ERROR("Queueing 0 length buffer\n");
-               }
-               if (buf->pending) {
-                       DRM_ERROR("Queueing pending buffer:"
-                                 " buffer %d, offset %d\n",
-                                 ind[i], i);
-                       goto out;
-               }
-               if (buf->waiting) {
-                       DRM_ERROR("Queueing waiting buffer:"
-                                 " buffer %d, offset %d\n",
-                                 ind[i], i);
-                       goto out;
-               }
-               buf->waiting = 1;
-               if (atomic_read(&q->use_count) == 1
-                   || atomic_read(&q->finalization)) {
-                       DRM(free_buffer)(dev, buf);
-               } else {
-                       DRM(waitlist_put)(&q->waitlist, buf);
-                       atomic_inc(&q->total_queued);
-               }
-       }
-       atomic_dec(&q->use_count);
-
-       return 0;
-
-out:
-       DRM(free)(ind, d->send_count * sizeof(int), DRM_MEM_DRIVER);
-       atomic_dec(&q->use_count);
-       return err;
-}
-
-static int DRM(dma_get_buffers_of_order)(struct file *filp, drm_dma_t *d,
-                                        int order)
-{
-       drm_file_t    *priv   = filp->private_data;
-       drm_device_t  *dev    = priv->dev;
-       int               i;
-       drm_buf_t         *buf;
-       drm_device_dma_t  *dma = dev->dma;
-
-       for (i = d->granted_count; i < d->request_count; i++) {
-               buf = DRM(freelist_get)(&dma->bufs[order].freelist,
-                                       d->flags & _DRM_DMA_WAIT);
-               if (!buf) break;
-               if (buf->pending || buf->waiting) {
-                       DRM_ERROR("Free buffer %d in use: filp %p (w%d, p%d)\n",
-                                 buf->idx,
-                                 buf->filp,
-                                 buf->waiting,
-                                 buf->pending);
-               }
-               buf->filp     = filp;
-               if (copy_to_user(&d->request_indices[i],
-                                &buf->idx,
-                                sizeof(buf->idx)))
-                       return -EFAULT;
-
-               if (copy_to_user(&d->request_sizes[i],
-                                &buf->total,
-                                sizeof(buf->total)))
-                       return -EFAULT;
-
-               ++d->granted_count;
-       }
-       return 0;
-}
-
-
-int DRM(dma_get_buffers)(struct file *filp, drm_dma_t *dma)
-{
-       int               order;
-       int               retcode = 0;
-       int               tmp_order;
-
-       order = DRM(order)(dma->request_size);
-
-       dma->granted_count = 0;
-       retcode            = DRM(dma_get_buffers_of_order)(filp, dma, order);
-
-       if (dma->granted_count < dma->request_count
-           && (dma->flags & _DRM_DMA_SMALLER_OK)) {
-               for (tmp_order = order - 1;
-                    !retcode
-                            && dma->granted_count < dma->request_count
-                            && tmp_order >= DRM_MIN_ORDER;
-                    --tmp_order) {
-
-                       retcode = DRM(dma_get_buffers_of_order)(filp, dma,
-                                                               tmp_order);
-               }
-       }
-
-       if (dma->granted_count < dma->request_count
-           && (dma->flags & _DRM_DMA_LARGER_OK)) {
-               for (tmp_order = order + 1;
-                    !retcode
-                            && dma->granted_count < dma->request_count
-                            && tmp_order <= DRM_MAX_ORDER;
-                    ++tmp_order) {
-
-                       retcode = DRM(dma_get_buffers_of_order)(filp, dma,
-                                                               tmp_order);
-               }
-       }
-       return 0;
-}
-
index 18e0b76228937d5236f4f55ee820b573353ed819..2f1659b96fd13771e64b24ad67c854baab4418a1 100644 (file)
 #define I810_BUF_UNMAPPED 0
 #define I810_BUF_MAPPED   1
 
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,2)
-#define down_write down
-#define up_write up
-#endif
-
 static drm_buf_t *i810_freelist_get(drm_device_t *dev)
 {
        drm_device_dma_t *dma = dev->dma;
@@ -351,6 +346,7 @@ static int i810_dma_initialize(drm_device_t *dev,
                DRM_ERROR("can not find mmio map!\n");
                return -EINVAL;
        }
+       dev->agp_buffer_token = init->buffers_offset;
        dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
        if (!dev->agp_buffer_map) {
                dev->dev_private = (void *)dev_priv;
@@ -1383,3 +1379,19 @@ drm_ioctl_desc_t i810_ioctls[] = {
 };
 
 int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls);
+
+/**
+ * Determine if the device really is AGP or not.
+ *
+ * All Intel graphics chipsets are treated as AGP, even if they are really
+ * PCI-e.
+ *
+ * \param dev   The device to be tested.
+ *
+ * \returns
+ * A value of 1 is always retured to indictate every i810 is AGP.
+ */
+int i810_driver_device_is_agp(drm_device_t * dev)
+{
+       return 1;
+}
index ff51b3259af9268ef4ac34e1743ed4d634ed43b9..00609329d5786be3e0671483dc07a5dacbd26116 100644 (file)
@@ -84,6 +84,7 @@ static struct drm_driver driver = {
        .dev_priv_size = sizeof(drm_i810_buf_priv_t),
        .pretakedown = i810_driver_pretakedown,
        .prerelease = i810_driver_prerelease,
+       .device_is_agp = i810_driver_device_is_agp,
        .release = i810_driver_release,
        .dma_quiescent = i810_driver_dma_quiescent,
        .reclaim_buffers = i810_reclaim_buffers,
index 1b40538d1725041d3dff8c603ef54b7adf4d1552..62ee4f58c59a97d7ab5186a0de5b6ad4719ea438 100644 (file)
@@ -120,6 +120,7 @@ extern int i810_driver_dma_quiescent(drm_device_t *dev);
 extern void i810_driver_release(drm_device_t *dev, struct file *filp);
 extern void i810_driver_pretakedown(drm_device_t *dev);
 extern void i810_driver_prerelease(drm_device_t *dev, DRMFILE filp);
+extern int i810_driver_device_is_agp(drm_device_t * dev);
 
 #define I810_BASE(reg)         ((unsigned long) \
                                dev_priv->mmio_map->handle)
index dc7733035864d9e2e058e0b86766bec7d1e11643..6f89d5796ef3b58f8d0e5bf113e6bb691de0e450 100644 (file)
 #define I830_BUF_UNMAPPED 0
 #define I830_BUF_MAPPED   1
 
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,2)
-#define down_write down
-#define up_write up
-#endif
-
 static drm_buf_t *i830_freelist_get(drm_device_t *dev)
 {
        drm_device_dma_t *dma = dev->dma;
@@ -358,6 +353,7 @@ static int i830_dma_initialize(drm_device_t *dev,
                DRM_ERROR("can not find mmio map!\n");
                return -EINVAL;
        }
+       dev->agp_buffer_token = init->buffers_offset;
        dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
        if(!dev->agp_buffer_map) {
                dev->dev_private = (void *)dev_priv;
@@ -1586,3 +1582,19 @@ drm_ioctl_desc_t i830_ioctls[] = {
 };
 
 int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls);
+
+/**
+ * Determine if the device really is AGP or not.
+ *
+ * All Intel graphics chipsets are treated as AGP, even if they are really
+ * PCI-e.
+ *
+ * \param dev   The device to be tested.
+ *
+ * \returns
+ * A value of 1 is always retured to indictate every i8xx is AGP.
+ */
+int i830_driver_device_is_agp(drm_device_t * dev)
+{
+       return 1;
+}
index bc36be76b8b238f79f13b4cdf0125fa7513a0cce..0da9cd19919e619369a480ae9bb707fa19b835a7 100644 (file)
@@ -88,6 +88,7 @@ static struct drm_driver driver = {
        .dev_priv_size = sizeof(drm_i830_buf_priv_t),
        .pretakedown = i830_driver_pretakedown,
        .prerelease = i830_driver_prerelease,
+       .device_is_agp = i830_driver_device_is_agp,
        .release = i830_driver_release,
        .dma_quiescent = i830_driver_dma_quiescent,
        .reclaim_buffers = i830_reclaim_buffers,
index df7746131dea80b1866d938c72cfda6c4e24e9a2..63f96a8b6a4a5bd77190ed07b49d69fe471f4b80 100644 (file)
@@ -137,6 +137,7 @@ extern void i830_driver_pretakedown(drm_device_t *dev);
 extern void i830_driver_release(drm_device_t *dev, struct file *filp);
 extern int i830_driver_dma_quiescent(drm_device_t *dev);
 extern void i830_driver_prerelease(drm_device_t *dev, DRMFILE filp);
+extern int i830_driver_device_is_agp(drm_device_t * dev);
 
 #define I830_BASE(reg)         ((unsigned long) \
                                dev_priv->mmio_map->handle)
index acf9e52a9507ff9293d0cd629a450289487d9774..34f552f90c4a82aaa857f8955e909c15c0ef28a3 100644 (file)
@@ -95,9 +95,8 @@ static int i915_dma_cleanup(drm_device_t * dev)
                        drm_core_ioremapfree( &dev_priv->ring.map, dev);
                }
 
-               if (dev_priv->hw_status_page) {
-                       drm_pci_free(dev, PAGE_SIZE, dev_priv->hw_status_page,
-                                    dev_priv->dma_status_page);
+               if (dev_priv->status_page_dmah) {
+                       drm_pci_free(dev, dev_priv->status_page_dmah);
                        /* Need to rewrite hardware status page */
                        I915_WRITE(0x02080, 0x1ffff000);
                }
@@ -174,16 +173,18 @@ static int i915_initialize(drm_device_t * dev,
        dev_priv->allow_batchbuffer = 1;
 
        /* Program Hardware Status Page */
-       dev_priv->hw_status_page = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE,
-                                                0xffffffff, 
-                                                &dev_priv->dma_status_page);
+       dev_priv->status_page_dmah = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE,
+                                                  0xffffffff);
 
-       if (!dev_priv->hw_status_page) {
+       if (!dev_priv->status_page_dmah) {
                dev->dev_private = (void *)dev_priv;
                i915_dma_cleanup(dev);
                DRM_ERROR("Can not allocate hardware status page\n");
                return DRM_ERR(ENOMEM);
        }
+       dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr;
+       dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;
+
        memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
        DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
 
@@ -731,3 +732,19 @@ drm_ioctl_desc_t i915_ioctls[] = {
 };
 
 int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
+
+/**
+ * Determine if the device really is AGP or not.
+ *
+ * All Intel graphics chipsets are treated as AGP, even if they are really
+ * PCI-e.
+ *
+ * \param dev   The device to be tested.
+ *
+ * \returns
+ * A value of 1 is always retured to indictate every i9x5 is AGP.
+ */
+int i915_driver_device_is_agp(drm_device_t * dev)
+{
+       return 1;
+}
index 1f59d3fc79bcdabcbf0715556c3010c5be60a1b3..106b9ec022133316f67e9c5ae3d05c4764f09f5b 100644 (file)
@@ -79,6 +79,7 @@ static struct drm_driver driver = {
                                DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
        .pretakedown = i915_driver_pretakedown,
        .prerelease = i915_driver_prerelease,
+       .device_is_agp = i915_driver_device_is_agp,
        .irq_preinstall = i915_driver_irq_preinstall,
        .irq_postinstall = i915_driver_irq_postinstall,
        .irq_uninstall = i915_driver_irq_uninstall,
index 9c37d2367dd578bc6b6851c47cc5a82b560598d3..70ed4e68eac81e32158b762c4652b23eef2da905 100644 (file)
@@ -79,9 +79,10 @@ typedef struct drm_i915_private {
        drm_i915_sarea_t *sarea_priv;
        drm_i915_ring_buffer_t ring;
 
+       drm_dma_handle_t *status_page_dmah;
        void *hw_status_page;
-       unsigned long counter;
        dma_addr_t dma_status_page;
+       unsigned long counter;
 
        int back_offset;
        int front_offset;
@@ -102,6 +103,7 @@ typedef struct drm_i915_private {
 extern void i915_kernel_lost_context(drm_device_t * dev);
 extern void i915_driver_pretakedown(drm_device_t *dev);
 extern void i915_driver_prerelease(drm_device_t *dev, DRMFILE filp);
+extern int i915_driver_device_is_agp(drm_device_t *dev);
 
 /* i915_irq.c */
 extern int i915_irq_emit(DRM_IOCTL_ARGS);
index 832eaf8a5068db6ebe5d57e624ed76c4e32b5b93..fc7d4a594bca01b78c69552f96353fabd31c76ec 100644 (file)
  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Rickard E. (Rik) Faith <faith@valinux.com>
- *    Jeff Hartmann <jhartmann@valinux.com>
- *    Keith Whitwell <keith@tungstengraphics.com>
- *
- * Rewritten by:
- *    Gareth Hughes <gareth@valinux.com>
+ */
+
+/**
+ * \file mga_dma.c
+ * DMA support for MGA G200 / G400.
+ * 
+ * \author Rickard E. (Rik) Faith <faith@valinux.com>
+ * \author Jeff Hartmann <jhartmann@valinux.com>
+ * \author Keith Whitwell <keith@tungstengraphics.com>
+ * \author Gareth Hughes <gareth@valinux.com>
  */
 
 #include "drmP.h"
 #include "drm.h"
+#include "drm_sarea.h"
 #include "mga_drm.h"
 #include "mga_drv.h"
 
@@ -148,7 +151,7 @@ void mga_do_dma_flush( drm_mga_private_t *dev_priv )
        DRM_DEBUG( "  space = 0x%06x\n", primary->space );
 
        mga_flush_write_combine();
-       MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER );
+       MGA_WRITE(MGA_PRIMEND, tail | dev_priv->dma_access);
 
        DRM_DEBUG( "done.\n" );
 }
@@ -190,7 +193,7 @@ void mga_do_dma_wrap_start( drm_mga_private_t *dev_priv )
        DRM_DEBUG( "  space = 0x%06x\n", primary->space );
 
        mga_flush_write_combine();
-       MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER );
+       MGA_WRITE(MGA_PRIMEND, tail | dev_priv->dma_access);
 
        set_bit( 0, &primary->wrapped );
        DRM_DEBUG( "done.\n" );
@@ -396,23 +399,390 @@ int mga_freelist_put( drm_device_t *dev, drm_buf_t *buf )
  * DMA initialization, cleanup
  */
 
+
+int mga_driver_preinit(drm_device_t *dev, unsigned long flags)
+{
+       drm_mga_private_t * dev_priv;
+
+       dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER);
+       if (!dev_priv)
+               return DRM_ERR(ENOMEM);
+
+       dev->dev_private = (void *)dev_priv;
+       memset(dev_priv, 0, sizeof(drm_mga_private_t));
+
+       dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT;
+       dev_priv->chipset = flags;
+
+       return 0;
+}
+
+#if __OS_HAS_AGP
+/**
+ * Bootstrap the driver for AGP DMA.
+ * 
+ * \todo
+ * Investigate whether there is any benifit to storing the WARP microcode in
+ * AGP memory.  If not, the microcode may as well always be put in PCI
+ * memory.
+ *
+ * \todo
+ * This routine needs to set dma_bs->agp_mode to the mode actually configured
+ * in the hardware.  Looking just at the Linux AGP driver code, I don't see
+ * an easy way to determine this.
+ *
+ * \sa mga_do_dma_bootstrap, mga_do_pci_dma_bootstrap
+ */
+static int mga_do_agp_dma_bootstrap(drm_device_t * dev,
+                                   drm_mga_dma_bootstrap_t * dma_bs)
+{
+       drm_mga_private_t * const dev_priv = (drm_mga_private_t *) dev->dev_private;
+       const unsigned int warp_size = mga_warp_microcode_size(dev_priv);
+       int err;
+       unsigned  offset;
+       const unsigned secondary_size = dma_bs->secondary_bin_count
+               * dma_bs->secondary_bin_size;
+       const unsigned agp_size = (dma_bs->agp_size << 20);
+       drm_buf_desc_t req;
+       drm_agp_mode_t mode;
+       drm_agp_info_t info;
+
+       
+       /* Acquire AGP. */
+       err = drm_agp_acquire(dev);
+       if (err) {
+               DRM_ERROR("Unable to acquire AGP\n");
+               return err;
+       }
+
+       err = drm_agp_info(dev, &info);
+       if (err) {
+               DRM_ERROR("Unable to get AGP info\n");
+               return err;
+       }
+
+       mode.mode = (info.mode & ~0x07) | dma_bs->agp_mode;
+       err = drm_agp_enable(dev, mode);
+       if (err) {
+               DRM_ERROR("Unable to enable AGP (mode = 0x%lx)\n", mode.mode);
+               return err;
+       }
+
+
+       /* In addition to the usual AGP mode configuration, the G200 AGP cards
+        * need to have the AGP mode "manually" set.
+        */
+
+       if (dev_priv->chipset == MGA_CARD_TYPE_G200) {
+               if (mode.mode & 0x02) {
+                       MGA_WRITE(MGA_AGP_PLL, MGA_AGP2XPLL_ENABLE);
+               }
+               else {
+                       MGA_WRITE(MGA_AGP_PLL, MGA_AGP2XPLL_DISABLE);
+               }
+       }
+
+
+       /* Allocate and bind AGP memory. */
+       dev_priv->agp_pages = agp_size / PAGE_SIZE;
+       dev_priv->agp_mem = drm_alloc_agp( dev, dev_priv->agp_pages, 0 );
+       if (dev_priv->agp_mem == NULL) {
+               dev_priv->agp_pages = 0;
+               DRM_ERROR("Unable to allocate %uMB AGP memory\n",
+                         dma_bs->agp_size);
+               return DRM_ERR(ENOMEM);
+       }
+               
+       err = drm_bind_agp( dev_priv->agp_mem, 0 );
+       if (err) {
+               DRM_ERROR("Unable to bind AGP memory\n");
+               return err;
+       }
+
+       offset = 0;
+       err = drm_addmap( dev, offset, warp_size,
+                         _DRM_AGP, _DRM_READ_ONLY, & dev_priv->warp );
+       if (err) {
+               DRM_ERROR("Unable to map WARP microcode\n");
+               return err;
+       }
+
+       offset += warp_size;
+       err = drm_addmap( dev, offset, dma_bs->primary_size,
+                         _DRM_AGP, _DRM_READ_ONLY, & dev_priv->primary );
+       if (err) {
+               DRM_ERROR("Unable to map primary DMA region\n");
+               return err;
+       }
+
+       offset += dma_bs->primary_size;
+       err = drm_addmap( dev, offset, secondary_size,
+                         _DRM_AGP, 0, & dev->agp_buffer_map );
+       if (err) {
+               DRM_ERROR("Unable to map secondary DMA region\n");
+               return err;
+       }
+
+       (void) memset( &req, 0, sizeof(req) );
+       req.count = dma_bs->secondary_bin_count;
+       req.size = dma_bs->secondary_bin_size;
+       req.flags = _DRM_AGP_BUFFER;
+       req.agp_start = offset;
+
+       err = drm_addbufs_agp( dev, & req );
+       if (err) {
+               DRM_ERROR("Unable to add secondary DMA buffers\n");
+               return err;
+       }
+
+       offset += secondary_size;
+       err = drm_addmap( dev, offset, agp_size - offset,
+                         _DRM_AGP, 0, & dev_priv->agp_textures );
+       if (err) {
+               DRM_ERROR("Unable to map AGP texture region\n");
+               return err;
+       }
+
+       drm_core_ioremap(dev_priv->warp, dev);
+       drm_core_ioremap(dev_priv->primary, dev);
+       drm_core_ioremap(dev->agp_buffer_map, dev);
+
+       if (!dev_priv->warp->handle ||
+           !dev_priv->primary->handle || !dev->agp_buffer_map->handle) {
+               DRM_ERROR("failed to ioremap agp regions! (%p, %p, %p)\n",
+                         dev_priv->warp->handle, dev_priv->primary->handle,
+                         dev->agp_buffer_map->handle);
+               return DRM_ERR(ENOMEM);
+       }
+
+       dev_priv->dma_access = MGA_PAGPXFER;
+       dev_priv->wagp_enable = MGA_WAGP_ENABLE;
+
+       DRM_INFO("Initialized card for AGP DMA.\n");
+       return 0;
+}
+#else
+static int mga_do_agp_dma_bootstrap(drm_device_t * dev,
+                                   drm_mga_dma_bootstrap_t * dma_bs)
+{
+       return -EINVAL;
+}
+#endif
+
+/**
+ * Bootstrap the driver for PCI DMA.
+ * 
+ * \todo
+ * The algorithm for decreasing the size of the primary DMA buffer could be
+ * better.  The size should be rounded up to the nearest page size, then
+ * decrease the request size by a single page each pass through the loop.
+ *
+ * \todo
+ * Determine whether the maximum address passed to drm_pci_alloc is correct.
+ * The same goes for drm_addbufs_pci.
+ * 
+ * \sa mga_do_dma_bootstrap, mga_do_agp_dma_bootstrap
+ */
+static int mga_do_pci_dma_bootstrap(drm_device_t * dev,
+                                   drm_mga_dma_bootstrap_t * dma_bs)
+{
+       drm_mga_private_t * const dev_priv = (drm_mga_private_t *) dev->dev_private;
+       const unsigned int warp_size = mga_warp_microcode_size(dev_priv);
+       unsigned int primary_size;
+       unsigned int bin_count;
+       int err;
+       drm_buf_desc_t req;
+
+       
+       if (dev->dma == NULL) {
+               DRM_ERROR("dev->dma is NULL\n");
+               return DRM_ERR(EFAULT);
+       }
+
+       /* The proper alignment is 0x100 for this mapping */
+       err = drm_addmap(dev, 0, warp_size, _DRM_CONSISTENT,
+                        _DRM_READ_ONLY, &dev_priv->warp);
+       if (err != 0) {
+               DRM_ERROR("Unable to create mapping for WARP microcode\n");
+               return err;
+       }
+
+       /* Other than the bottom two bits being used to encode other
+        * information, there don't appear to be any restrictions on the
+        * alignment of the primary or secondary DMA buffers.
+        */
+
+       for ( primary_size = dma_bs->primary_size
+             ; primary_size != 0
+             ; primary_size >>= 1 ) {
+               /* The proper alignment for this mapping is 0x04 */
+               err = drm_addmap(dev, 0, primary_size, _DRM_CONSISTENT,
+                                _DRM_READ_ONLY, &dev_priv->primary);
+               if (!err)
+                       break;
+       }
+
+       if (err != 0) {
+               DRM_ERROR("Unable to allocate primary DMA region\n");
+               return DRM_ERR(ENOMEM);
+       }
+
+       if (dev_priv->primary->size != dma_bs->primary_size) {
+               DRM_INFO("Primary DMA buffer size reduced from %u to %u.\n",
+                        dma_bs->primary_size, 
+                        (unsigned) dev_priv->primary->size);
+               dma_bs->primary_size = dev_priv->primary->size;
+       }
+
+       for ( bin_count = dma_bs->secondary_bin_count
+             ; bin_count > 0 
+             ; bin_count-- ) {
+               (void) memset( &req, 0, sizeof(req) );
+               req.count = bin_count;
+               req.size = dma_bs->secondary_bin_size;
+
+               err = drm_addbufs_pci( dev, & req );
+               if (!err) {
+                       break;
+               }
+       }
+       
+       if (bin_count == 0) {
+               DRM_ERROR("Unable to add secondary DMA buffers\n");
+               return err;
+       }
+
+       if (bin_count != dma_bs->secondary_bin_count) {
+               DRM_INFO("Secondary PCI DMA buffer bin count reduced from %u "
+                        "to %u.\n", dma_bs->secondary_bin_count, bin_count);
+
+               dma_bs->secondary_bin_count = bin_count;
+       }
+
+       dev_priv->dma_access = 0;
+       dev_priv->wagp_enable = 0;
+
+       dma_bs->agp_mode = 0;
+
+       DRM_INFO("Initialized card for PCI DMA.\n");
+       return 0;
+}
+
+
+static int mga_do_dma_bootstrap(drm_device_t * dev,
+                               drm_mga_dma_bootstrap_t * dma_bs)
+{
+       const int is_agp = (dma_bs->agp_mode != 0) && drm_device_is_agp(dev);
+       int err;
+       drm_mga_private_t * const dev_priv =
+               (drm_mga_private_t *) dev->dev_private;
+
+
+       dev_priv->used_new_dma_init = 1;
+
+       /* The first steps are the same for both PCI and AGP based DMA.  Map
+        * the cards MMIO registers and map a status page.
+        */
+       err = drm_addmap( dev, dev_priv->mmio_base, dev_priv->mmio_size,
+                         _DRM_REGISTERS, _DRM_READ_ONLY, & dev_priv->mmio );
+       if (err) {
+               DRM_ERROR("Unable to map MMIO region\n");
+               return err;
+       }
+
+
+       err = drm_addmap( dev, 0, SAREA_MAX, _DRM_SHM,
+                         _DRM_READ_ONLY | _DRM_LOCKED | _DRM_KERNEL,
+                         & dev_priv->status );
+       if (err) {
+               DRM_ERROR("Unable to map status region\n");
+               return err;
+       }
+
+
+       /* The DMA initialization procedure is slightly different for PCI and
+        * AGP cards.  AGP cards just allocate a large block of AGP memory and
+        * carve off portions of it for internal uses.  The remaining memory
+        * is returned to user-mode to be used for AGP textures.
+        */
+       if (is_agp) {
+               err = mga_do_agp_dma_bootstrap(dev, dma_bs);
+       }
+       
+       /* If we attempted to initialize the card for AGP DMA but failed,
+        * clean-up any mess that may have been created.
+        */
+
+       if (err) {
+               mga_do_cleanup_dma(dev);
+       }
+
+
+       /* Not only do we want to try and initialized PCI cards for PCI DMA,
+        * but we also try to initialized AGP cards that could not be
+        * initialized for AGP DMA.  This covers the case where we have an AGP
+        * card in a system with an unsupported AGP chipset.  In that case the
+        * card will be detected as AGP, but we won't be able to allocate any
+        * AGP memory, etc.
+        */
+
+       if (!is_agp || err) {
+               err = mga_do_pci_dma_bootstrap(dev, dma_bs);
+       }
+
+
+       return err;
+}
+
+int mga_dma_bootstrap(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_mga_dma_bootstrap_t bootstrap;
+       int err;
+
+
+       DRM_COPY_FROM_USER_IOCTL(bootstrap,
+                                (drm_mga_dma_bootstrap_t __user *) data,
+                                sizeof(bootstrap));
+
+       err = mga_do_dma_bootstrap(dev, & bootstrap);
+       if (! err) {
+               static const int modes[] = { 0, 1, 2, 2, 4, 4, 4, 4 };
+               const drm_mga_private_t * const dev_priv = 
+                       (drm_mga_private_t *) dev->dev_private;
+
+               if (dev_priv->agp_textures != NULL) {
+                       bootstrap.texture_handle = dev_priv->agp_textures->offset;
+                       bootstrap.texture_size = dev_priv->agp_textures->size;
+               }
+               else {
+                       bootstrap.texture_handle = 0;
+                       bootstrap.texture_size = 0;
+               }
+
+               bootstrap.agp_mode = modes[ bootstrap.agp_mode & 0x07 ];
+               if (DRM_COPY_TO_USER( (void __user *) data, & bootstrap,
+                                    sizeof(bootstrap))) {
+                       err = DRM_ERR(EFAULT);
+               }
+       }
+       else {
+               mga_do_cleanup_dma(dev);
+       }
+
+       return err;
+}
+
 static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init )
 {
        drm_mga_private_t *dev_priv;
        int ret;
        DRM_DEBUG( "\n" );
 
-       dev_priv = drm_alloc( sizeof(drm_mga_private_t), DRM_MEM_DRIVER );
-       if ( !dev_priv )
-               return DRM_ERR(ENOMEM);
-
-       memset( dev_priv, 0, sizeof(drm_mga_private_t) );
 
-       dev_priv->chipset = init->chipset;
+       dev_priv = dev->dev_private;
 
-       dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT;
-
-       if ( init->sgram ) {
+       if (init->sgram) {
                dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_BLK;
        } else {
                dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_RSTR;
@@ -436,88 +806,66 @@ static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init )
 
        DRM_GETSAREA();
 
-       if(!dev_priv->sarea) {
-               DRM_ERROR( "failed to find sarea!\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
+       if (!dev_priv->sarea) {
+               DRM_ERROR("failed to find sarea!\n");
                return DRM_ERR(EINVAL);
        }
 
-       dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
-       if(!dev_priv->mmio) {
-               DRM_ERROR( "failed to find mmio region!\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
-               return DRM_ERR(EINVAL);
-       }
-       dev_priv->status = drm_core_findmap(dev, init->status_offset);
-       if(!dev_priv->status) {
-               DRM_ERROR( "failed to find status page!\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
-               return DRM_ERR(EINVAL);
-       }
-       dev_priv->warp = drm_core_findmap(dev, init->warp_offset);
-       if(!dev_priv->warp) {
-               DRM_ERROR( "failed to find warp microcode region!\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
-               return DRM_ERR(EINVAL);
-       }
-       dev_priv->primary = drm_core_findmap(dev, init->primary_offset);
-       if(!dev_priv->primary) {
-               DRM_ERROR( "failed to find primary dma region!\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
-               return DRM_ERR(EINVAL);
-       }
-       dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
-       if(!dev->agp_buffer_map) {
-               DRM_ERROR( "failed to find dma buffer region!\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
-               return DRM_ERR(EINVAL);
+       if (! dev_priv->used_new_dma_init) {
+               dev_priv->status = drm_core_findmap(dev, init->status_offset);
+               if (!dev_priv->status) {
+                       DRM_ERROR("failed to find status page!\n");
+                       return DRM_ERR(EINVAL);
+               }
+               dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
+               if (!dev_priv->mmio) {
+                       DRM_ERROR("failed to find mmio region!\n");
+                       return DRM_ERR(EINVAL);
+               }
+               dev_priv->warp = drm_core_findmap(dev, init->warp_offset);
+               if (!dev_priv->warp) {
+                       DRM_ERROR("failed to find warp microcode region!\n");
+                       return DRM_ERR(EINVAL);
+               }
+               dev_priv->primary = drm_core_findmap(dev, init->primary_offset);
+               if (!dev_priv->primary) {
+                       DRM_ERROR("failed to find primary dma region!\n");
+                       return DRM_ERR(EINVAL);
+               }
+               dev->agp_buffer_token = init->buffers_offset;
+               dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
+               if (!dev->agp_buffer_map) {
+                       DRM_ERROR("failed to find dma buffer region!\n");
+                       return DRM_ERR(EINVAL);
+               }
+
+               drm_core_ioremap(dev_priv->warp, dev);
+               drm_core_ioremap(dev_priv->primary, dev);
+               drm_core_ioremap(dev->agp_buffer_map, dev);
        }
 
        dev_priv->sarea_priv =
                (drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle +
                                    init->sarea_priv_offset);
 
-       drm_core_ioremap( dev_priv->warp, dev );
-       drm_core_ioremap( dev_priv->primary, dev );
-       drm_core_ioremap( dev->agp_buffer_map, dev );
-
-       if(!dev_priv->warp->handle ||
-          !dev_priv->primary->handle ||
-          !dev->agp_buffer_map->handle ) {
-               DRM_ERROR( "failed to ioremap agp regions!\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
+       if (!dev_priv->warp->handle ||
+           !dev_priv->primary->handle ||
+           ((dev_priv->dma_access != 0) &&
+            ((dev->agp_buffer_map == NULL) ||
+             (dev->agp_buffer_map->handle == NULL)))) {
+               DRM_ERROR("failed to ioremap agp regions!\n");
                return DRM_ERR(ENOMEM);
        }
 
-       ret = mga_warp_install_microcode( dev_priv );
-       if ( ret < 0 ) {
-               DRM_ERROR( "failed to install WARP ucode!\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
+       ret = mga_warp_install_microcode(dev_priv);
+       if (ret < 0) {
+               DRM_ERROR("failed to install WARP ucode!\n");
                return ret;
        }
 
-       ret = mga_warp_init( dev_priv );
-       if ( ret < 0 ) {
-               DRM_ERROR( "failed to init WARP engine!\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
+       ret = mga_warp_init(dev_priv);
+       if (ret < 0) {
+               DRM_ERROR("failed to init WARP engine!\n");
                return ret;
        }
 
@@ -557,22 +905,18 @@ static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init )
        dev_priv->sarea_priv->last_frame.head = 0;
        dev_priv->sarea_priv->last_frame.wrap = 0;
 
-       if ( mga_freelist_init( dev, dev_priv ) < 0 ) {
-               DRM_ERROR( "could not initialize freelist\n" );
-               /* Assign dev_private so we can do cleanup. */
-               dev->dev_private = (void *)dev_priv;
-               mga_do_cleanup_dma( dev );
+       if (mga_freelist_init(dev, dev_priv) < 0) {
+               DRM_ERROR("could not initialize freelist\n");
                return DRM_ERR(ENOMEM);
        }
 
-       /* Make dev_private visable to others. */
-       dev->dev_private = (void *)dev_priv;
        return 0;
 }
 
 static int mga_do_cleanup_dma( drm_device_t *dev )
 {
-       DRM_DEBUG( "\n" );
+       int err = 0;
+       DRM_DEBUG("\n");
 
        /* Make sure interrupts are disabled here because the uninstall ioctl
         * may not have been called from userspace and after dev_private
@@ -583,37 +927,73 @@ static int mga_do_cleanup_dma( drm_device_t *dev )
        if ( dev->dev_private ) {
                drm_mga_private_t *dev_priv = dev->dev_private;
 
-               if ( dev_priv->warp != NULL )
-                       drm_core_ioremapfree( dev_priv->warp, dev );
-               if ( dev_priv->primary != NULL )
-                       drm_core_ioremapfree( dev_priv->primary, dev );
-               if ( dev->agp_buffer_map != NULL )
-                       drm_core_ioremapfree( dev->agp_buffer_map, dev );
+               if ((dev_priv->warp != NULL) 
+                   && (dev_priv->mmio->type != _DRM_CONSISTENT))
+                       drm_core_ioremapfree(dev_priv->warp, dev);
+
+               if ((dev_priv->primary != NULL) 
+                   && (dev_priv->primary->type != _DRM_CONSISTENT))
+                       drm_core_ioremapfree(dev_priv->primary, dev);
+
+               if (dev->agp_buffer_map != NULL)
+                       drm_core_ioremapfree(dev->agp_buffer_map, dev);
 
-               if ( dev_priv->head != NULL ) {
-                       mga_freelist_cleanup( dev );
+               if (dev_priv->used_new_dma_init) {
+#if __OS_HAS_AGP
+                       if (dev_priv->agp_mem != NULL) {
+                               dev_priv->agp_textures = NULL;
+                               drm_unbind_agp(dev_priv->agp_mem);
+
+                               drm_free_agp(dev_priv->agp_mem, dev_priv->agp_pages);
+                               dev_priv->agp_pages = 0;
+                               dev_priv->agp_mem = NULL;
+                       }
+
+                       if ((dev->agp != NULL) && dev->agp->acquired) {
+                               err = drm_agp_release(dev);
+                       }
+#endif
+                       dev_priv->used_new_dma_init = 0;
                }
 
-               drm_free( dev->dev_private, sizeof(drm_mga_private_t),
-                          DRM_MEM_DRIVER );
-               dev->dev_private = NULL;
+               dev_priv->warp = NULL;
+               dev_priv->primary = NULL;
+               dev_priv->mmio = NULL;
+               dev_priv->status = NULL;
+               dev_priv->sarea = NULL;
+               dev_priv->sarea_priv = NULL;
+               dev->agp_buffer_map = NULL;
+
+               memset(&dev_priv->prim, 0, sizeof(dev_priv->prim));
+               dev_priv->warp_pipe = 0;
+               memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys));
+
+               if (dev_priv->head != NULL) {
+                       mga_freelist_cleanup(dev);
+               }
        }
 
-       return 0;
+       return err;
 }
 
 int mga_dma_init( DRM_IOCTL_ARGS )
 {
        DRM_DEVICE;
        drm_mga_init_t init;
+       int err;
 
        LOCK_TEST_WITH_RETURN( dev, filp );
 
-       DRM_COPY_FROM_USER_IOCTL( init, (drm_mga_init_t __user *)data, sizeof(init) );
+       DRM_COPY_FROM_USER_IOCTL(init, (drm_mga_init_t __user *) data,
+                                sizeof(init));
 
        switch ( init.func ) {
        case MGA_INIT_DMA:
-               return mga_do_init_dma( dev, &init );
+               err = mga_do_init_dma(dev, &init);
+               if (err) {
+                       (void) mga_do_cleanup_dma(dev);
+               }
+               return err;
        case MGA_CLEANUP_DMA:
                return mga_do_cleanup_dma( dev );
        }
@@ -742,7 +1122,21 @@ int mga_dma_buffers( DRM_IOCTL_ARGS )
        return ret;
 }
 
-void mga_driver_pretakedown(drm_device_t *dev)
+/**
+ * Called just before the module is unloaded.
+ */
+int mga_driver_postcleanup(drm_device_t * dev)
+{
+       drm_free(dev->dev_private, sizeof(drm_mga_private_t), DRM_MEM_DRIVER);
+       dev->dev_private = NULL;
+
+       return 0;
+}
+
+/**
+ * Called when the last opener of the device is closed.
+ */
+void mga_driver_pretakedown(drm_device_t * dev)
 {
        mga_do_cleanup_dma( dev );
 }
index 521d4451d012fd17dc3d852631535c0403ce6c84..d20aab3bd57bb66fdf6086f2d27a1d45cb0b1c6b 100644 (file)
@@ -73,7 +73,8 @@
 
 #define MGA_CARD_TYPE_G200     1
 #define MGA_CARD_TYPE_G400     2
-
+#define MGA_CARD_TYPE_G450     3       /* not currently used */
+#define MGA_CARD_TYPE_G550     4
 
 #define MGA_FRONT              0x1
 #define MGA_BACK               0x2
@@ -225,10 +226,6 @@ typedef struct _drm_mga_sarea {
 } drm_mga_sarea_t;
 
 
-/* WARNING: If you change any of these defines, make sure to change the
- * defines in the Xserver file (xf86drmMga.h)
- */
-
 /* MGA specific ioctls
  * The device specific ioctl range is 0x40 to 0x79.
  */
@@ -243,6 +240,14 @@ typedef struct _drm_mga_sarea {
 #define DRM_MGA_BLIT     0x08
 #define DRM_MGA_GETPARAM 0x09
 
+/* 3.2:
+ * ioctls for operating on fences.
+ */
+#define DRM_MGA_SET_FENCE      0x0a
+#define DRM_MGA_WAIT_FENCE     0x0b
+#define DRM_MGA_DMA_BOOTSTRAP  0x0c
+
+
 #define DRM_IOCTL_MGA_INIT     DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_INIT, drm_mga_init_t)
 #define DRM_IOCTL_MGA_FLUSH    DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_FLUSH, drm_lock_t)
 #define DRM_IOCTL_MGA_RESET    DRM_IO(  DRM_COMMAND_BASE + DRM_MGA_RESET)
@@ -253,6 +258,9 @@ typedef struct _drm_mga_sarea {
 #define DRM_IOCTL_MGA_ILOAD    DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_ILOAD, drm_mga_iload_t)
 #define DRM_IOCTL_MGA_BLIT     DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_BLIT, drm_mga_blit_t)
 #define DRM_IOCTL_MGA_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_GETPARAM, drm_mga_getparam_t)
+#define DRM_IOCTL_MGA_SET_FENCE     DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_SET_FENCE, uint32_t)
+#define DRM_IOCTL_MGA_WAIT_FENCE    DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_WAIT_FENCE, uint32_t)
+#define DRM_IOCTL_MGA_DMA_BOOTSTRAP DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_DMA_BOOTSTRAP, drm_mga_dma_bootstrap_t)
 
 typedef struct _drm_mga_warp_index {
        int installed;
@@ -291,12 +299,72 @@ typedef struct drm_mga_init {
        unsigned long buffers_offset;
 } drm_mga_init_t;
 
-typedef struct drm_mga_fullscreen {
-       enum {
-               MGA_INIT_FULLSCREEN    = 0x01,
-               MGA_CLEANUP_FULLSCREEN = 0x02
-       } func;
-} drm_mga_fullscreen_t;
+typedef struct drm_mga_dma_bootstrap {
+       /**
+        * \name AGP texture region
+        * 
+        * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, these fields will
+        * be filled in with the actual AGP texture settings.
+        * 
+        * \warning
+        * If these fields are non-zero, but dma_mga_dma_bootstrap::agp_mode
+        * is zero, it means that PCI memory (most likely through the use of
+        * an IOMMU) is being used for "AGP" textures.
+        */
+       /*@{*/
+       unsigned long texture_handle; /**< Handle used to map AGP textures. */
+       uint32_t     texture_size;    /**< Size of the AGP texture region. */
+       /*@}*/
+
+
+       /**
+        * Requested size of the primary DMA region.
+        * 
+        * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be
+        * filled in with the actual AGP mode.  If AGP was not available
+        */
+       uint32_t primary_size;
+
+
+       /**
+        * Requested number of secondary DMA buffers.
+        * 
+        * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be
+        * filled in with the actual number of secondary DMA buffers
+        * allocated.  Particularly when PCI DMA is used, this may be
+        * (subtantially) less than the number requested.
+        */
+       uint32_t secondary_bin_count;
+       
+       
+       /**
+        * Requested size of each secondary DMA buffer.
+        * 
+        * While the kernel \b is free to reduce
+        * dma_mga_dma_bootstrap::secondary_bin_count, it is \b not allowed
+        * to reduce dma_mga_dma_bootstrap::secondary_bin_size.
+        */
+       uint32_t secondary_bin_size;
+
+
+       /**
+        * Bit-wise mask of AGPSTAT2_* values.  Currently only \c AGPSTAT2_1X,
+        * \c AGPSTAT2_2X, and \c AGPSTAT2_4X are supported.  If this value is
+        * zero, it means that PCI DMA should be used, even if AGP is
+        * possible.
+        * 
+        * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be
+        * filled in with the actual AGP mode.  If AGP was not available
+        * (i.e., PCI DMA was used), this value will be zero.
+        */
+       uint32_t agp_mode;
+
+
+       /**
+        * Desired AGP GART size, measured in megabytes.
+        */
+       uint8_t agp_size;
+} drm_mga_dma_bootstrap_t;
 
 typedef struct drm_mga_clear {
        unsigned int flags;
@@ -341,6 +409,14 @@ typedef struct _drm_mga_blit {
  */
 #define MGA_PARAM_IRQ_NR            1
 
+/* 3.2: Query the actual card type.  The DDX only distinguishes between
+ * G200 chips and non-G200 chips, which it calls G400.  It turns out that
+ * there are some very sublte differences between the G4x0 chips and the G550
+ * chips.  Using this parameter query, a client-side driver can detect the
+ * difference between a G4x0 and a G550.
+ */
+#define MGA_PARAM_CARD_TYPE         2
+
 typedef struct drm_mga_getparam {
        int param;
        void __user *value;
index 844cca9cb29dfa65cf0d8bb3a44171846875c942..daabbba3b29789de0e1b662306e3fcbb9873e94e 100644 (file)
   
 #include "drm_pciids.h"
 
+static int mga_driver_device_is_agp(drm_device_t * dev);
 static int postinit( struct drm_device *dev, unsigned long flags )
 {
+       drm_mga_private_t * const dev_priv =
+               (drm_mga_private_t *) dev->dev_private;
+
+       dev_priv->mmio_base = pci_resource_start(dev->pdev, 1);
+       dev_priv->mmio_size = pci_resource_len(dev->pdev, 1);
+
        dev->counters += 3;
        dev->types[6] = _DRM_STAT_IRQ;
        dev->types[7] = _DRM_STAT_PRIMARY;
@@ -79,8 +86,11 @@ extern int mga_max_ioctl;
 
 static struct drm_driver driver = {
        .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
+       .preinit = mga_driver_preinit,
+       .postcleanup = mga_driver_postcleanup,
        .pretakedown = mga_driver_pretakedown,
        .dma_quiescent = mga_driver_dma_quiescent,
+       .device_is_agp = mga_driver_device_is_agp,
        .vblank_wait = mga_driver_vblank_wait,
        .irq_preinstall = mga_driver_irq_preinstall,
        .irq_postinstall = mga_driver_irq_postinstall,
@@ -128,3 +138,38 @@ module_exit(mga_exit);
 MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
 MODULE_LICENSE("GPL and additional rights");
+
+/**
+ * Determine if the device really is AGP or not.
+ *
+ * In addition to the usual tests performed by \c drm_device_is_agp, this
+ * function detects PCI G450 cards that appear to the system exactly like
+ * AGP G450 cards.
+ *
+ * \param dev   The device to be tested.
+ *
+ * \returns
+ * If the device is a PCI G450, zero is returned.  Otherwise 2 is returned.
+ */
+int mga_driver_device_is_agp(drm_device_t * dev)
+{
+       const struct pci_dev * const pdev = dev->pdev;
+
+
+       /* There are PCI versions of the G450.  These cards have the
+        * same PCI ID as the AGP G450, but have an additional PCI-to-PCI
+        * bridge chip.  We detect these cards, which are not currently
+        * supported by this driver, by looking at the device ID of the
+        * bus the "card" is on.  If vendor is 0x3388 (Hint Corp) and the
+        * device is 0x0021 (HB6 Universal PCI-PCI bridge), we reject the
+        * device.
+        */
+       
+       if ( (pdev->device == 0x0525)
+            && (pdev->bus->self->vendor == 0x3388)
+            && (pdev->bus->self->device == 0x0021) ) {
+               return 0;
+       }
+
+       return 2;
+}
index 9412e2816eb720d1794aeeb948c74b6ce274c495..b22fdbd4f830b561d058584383d107d42468144b 100644 (file)
 
 #define DRIVER_NAME            "mga"
 #define DRIVER_DESC            "Matrox G200/G400"
-#define DRIVER_DATE            "20021029"
+#define DRIVER_DATE            "20050607"
 
 #define DRIVER_MAJOR           3
-#define DRIVER_MINOR           1
+#define DRIVER_MINOR           2
 #define DRIVER_PATCHLEVEL      0
 
 typedef struct drm_mga_primary_buffer {
@@ -87,9 +87,43 @@ typedef struct drm_mga_private {
        int chipset;
        int usec_timeout;
 
+       /**
+        * If set, the new DMA initialization sequence was used.  This is
+        * primarilly used to select how the driver should uninitialized its
+        * internal DMA structures.
+        */
+       int used_new_dma_init;
+
+       /**
+        * If AGP memory is used for DMA buffers, this will be the value
+        * \c MGA_PAGPXFER.  Otherwise, it will be zero (for a PCI transfer).
+        */
+       u32 dma_access;
+
+       /**
+        * If AGP memory is used for DMA buffers, this will be the value
+        * \c MGA_WAGP_ENABLE.  Otherwise, it will be zero (for a PCI
+        * transfer).
+        */
+       u32 wagp_enable;
+
+       /**
+        * \name MMIO region parameters.
+        * 
+        * \sa drm_mga_private_t::mmio
+        */
+       /*@{*/
+       u32 mmio_base;             /**< Bus address of base of MMIO. */
+       u32 mmio_size;             /**< Size of the MMIO region. */
+       /*@}*/
+
        u32 clear_cmd;
        u32 maccess;
 
+       wait_queue_head_t fence_queue;
+       atomic_t last_fence_retired;
+       u32 next_fence_to_post;
+
        unsigned int fb_cpp;
        unsigned int front_offset;
        unsigned int front_pitch;
@@ -108,35 +142,43 @@ typedef struct drm_mga_private {
        drm_local_map_t *status;
        drm_local_map_t *warp;
        drm_local_map_t *primary;
-       drm_local_map_t *buffers;
        drm_local_map_t *agp_textures;
+       
+       DRM_AGP_MEM *agp_mem;
+       unsigned int agp_pages;
 } drm_mga_private_t;
 
                                /* mga_dma.c */
-extern int mga_dma_init( DRM_IOCTL_ARGS );
-extern int mga_dma_flush( DRM_IOCTL_ARGS );
-extern int mga_dma_reset( DRM_IOCTL_ARGS );
-extern int mga_dma_buffers( DRM_IOCTL_ARGS );
-extern void mga_driver_pretakedown(drm_device_t *dev);
-extern int mga_driver_dma_quiescent(drm_device_t *dev);
-
-extern int mga_do_wait_for_idle( drm_mga_private_t *dev_priv );
-
-extern void mga_do_dma_flush( drm_mga_private_t *dev_priv );
-extern void mga_do_dma_wrap_start( drm_mga_private_t *dev_priv );
-extern void mga_do_dma_wrap_end( drm_mga_private_t *dev_priv );
+extern int mga_driver_preinit(drm_device_t * dev, unsigned long flags);
+extern int mga_dma_bootstrap(DRM_IOCTL_ARGS);
+extern int mga_dma_init(DRM_IOCTL_ARGS);
+extern int mga_dma_flush(DRM_IOCTL_ARGS);
+extern int mga_dma_reset(DRM_IOCTL_ARGS);
+extern int mga_dma_buffers(DRM_IOCTL_ARGS);
+extern int mga_driver_postcleanup(drm_device_t * dev);
+extern void mga_driver_pretakedown(drm_device_t * dev);
+extern int mga_driver_dma_quiescent(drm_device_t * dev);
+
+extern int mga_do_wait_for_idle(drm_mga_private_t * dev_priv);
+
+extern void mga_do_dma_flush(drm_mga_private_t * dev_priv);
+extern void mga_do_dma_wrap_start(drm_mga_private_t * dev_priv);
+extern void mga_do_dma_wrap_end(drm_mga_private_t * dev_priv);
 
 extern int mga_freelist_put( drm_device_t *dev, drm_buf_t *buf );
 
                                /* mga_warp.c */
-extern int mga_warp_install_microcode( drm_mga_private_t *dev_priv );
-extern int mga_warp_init( drm_mga_private_t *dev_priv );
-
-extern int mga_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence);
-extern irqreturn_t mga_driver_irq_handler( DRM_IRQ_ARGS );
-extern void mga_driver_irq_preinstall( drm_device_t *dev );
-extern void mga_driver_irq_postinstall( drm_device_t *dev );
-extern void mga_driver_irq_uninstall( drm_device_t *dev );
+extern unsigned int mga_warp_microcode_size(const drm_mga_private_t * dev_priv);
+extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv);
+extern int mga_warp_init(drm_mga_private_t * dev_priv);
+
+                               /* mga_irq.c */
+extern int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence);
+extern int mga_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence);
+extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS);
+extern void mga_driver_irq_preinstall(drm_device_t * dev);
+extern void mga_driver_irq_postinstall(drm_device_t * dev);
+extern void mga_driver_irq_uninstall(drm_device_t * dev);
 extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
                             unsigned long arg);
 
@@ -527,6 +569,12 @@ do {                                                                       \
  */
 #define MGA_EXEC                       0x0100
 
+/* AGP PLL encoding (for G200 only).
+ */
+#define MGA_AGP_PLL                    0x1e4c
+#      define MGA_AGP2XPLL_DISABLE             (0 << 0)
+#      define MGA_AGP2XPLL_ENABLE              (1 << 0)
+
 /* Warp registers
  */
 #define MGA_WR0                                0x2d00
index bc745cfa2095dc7e5370ed909063bbeb8fcb1921..77d738e75a4df598b8a0a97d5d4377a0170efab7 100644 (file)
@@ -129,9 +129,76 @@ static int compat_mga_getparam(struct file *file, unsigned int cmd,
                         DRM_IOCTL_MGA_GETPARAM, (unsigned long)getparam);
 }
 
+typedef struct drm_mga_drm_bootstrap32 {
+       u32 texture_handle;
+       u32 texture_size;
+       u32 primary_size;
+       u32 secondary_bin_count;
+       u32 secondary_bin_size;
+       u32 agp_mode;
+       u8 agp_size;
+} drm_mga_dma_bootstrap32_t;
+
+static int compat_mga_dma_bootstrap(struct file *file, unsigned int cmd,
+                                   unsigned long arg)
+{
+       drm_mga_dma_bootstrap32_t dma_bootstrap32;
+       drm_mga_dma_bootstrap_t __user *dma_bootstrap;
+       int err;
+
+       if (copy_from_user(&dma_bootstrap32, (void __user *)arg,
+                          sizeof(dma_bootstrap32)))
+               return -EFAULT;
+
+       dma_bootstrap = compat_alloc_user_space(sizeof(*dma_bootstrap));
+       if (!access_ok(VERIFY_WRITE, dma_bootstrap, sizeof(*dma_bootstrap))
+           || __put_user(dma_bootstrap32.texture_handle,
+                         &dma_bootstrap->texture_handle)
+           || __put_user(dma_bootstrap32.texture_size,
+                         &dma_bootstrap->texture_size)
+           || __put_user(dma_bootstrap32.primary_size,
+                         &dma_bootstrap->primary_size)
+           || __put_user(dma_bootstrap32.secondary_bin_count,
+                         &dma_bootstrap->secondary_bin_count)
+           || __put_user(dma_bootstrap32.secondary_bin_size,
+                         &dma_bootstrap->secondary_bin_size)
+           || __put_user(dma_bootstrap32.agp_mode, &dma_bootstrap->agp_mode)
+           || __put_user(dma_bootstrap32.agp_size, &dma_bootstrap->agp_size))
+               return -EFAULT;
+
+       err = drm_ioctl(file->f_dentry->d_inode, file,
+                       DRM_IOCTL_MGA_DMA_BOOTSTRAP,
+                       (unsigned long)dma_bootstrap);
+       if (err)
+               return err;
+
+       if (__get_user(dma_bootstrap32.texture_handle,
+                      &dma_bootstrap->texture_handle)
+           || __get_user(dma_bootstrap32.texture_size,
+                         &dma_bootstrap->texture_size)
+           || __get_user(dma_bootstrap32.primary_size,
+                         &dma_bootstrap->primary_size)
+           || __get_user(dma_bootstrap32.secondary_bin_count,
+                         &dma_bootstrap->secondary_bin_count)
+           || __get_user(dma_bootstrap32.secondary_bin_size,
+                         &dma_bootstrap->secondary_bin_size)
+           || __get_user(dma_bootstrap32.agp_mode,
+                         &dma_bootstrap->agp_mode)
+           || __get_user(dma_bootstrap32.agp_size,
+                         &dma_bootstrap->agp_size))
+               return -EFAULT;
+
+       if (copy_to_user((void __user *)arg, &dma_bootstrap32,
+                        sizeof(dma_bootstrap32)))
+               return -EFAULT;
+
+       return 0;
+}
+
 drm_ioctl_compat_t *mga_compat_ioctls[] = {
        [DRM_MGA_INIT] = compat_mga_init,
        [DRM_MGA_GETPARAM] = compat_mga_getparam,
+       [DRM_MGA_DMA_BOOTSTRAP] = compat_mga_dma_bootstrap,
 };
 
 /**
index bc0b6b5d43a6de1de438d9ad5ce1e3ce2988cfc8..52eaa4e788f91f2cef5548b149ca648eed2b6550 100644 (file)
@@ -41,15 +41,40 @@ irqreturn_t mga_driver_irq_handler( DRM_IRQ_ARGS )
        drm_mga_private_t *dev_priv = 
           (drm_mga_private_t *)dev->dev_private;
        int status;
+       int handled = 0;
+
+       status = MGA_READ(MGA_STATUS);
 
-       status = MGA_READ( MGA_STATUS );
-       
        /* VBLANK interrupt */
        if ( status & MGA_VLINEPEN ) {
                MGA_WRITE( MGA_ICLEAR, MGA_VLINEICLR );
                atomic_inc(&dev->vbl_received);
                DRM_WAKEUP(&dev->vbl_queue);
-               drm_vbl_send_signals( dev );
+               drm_vbl_send_signals(dev);
+               handled = 1;
+       }
+
+       /* SOFTRAP interrupt */
+       if (status & MGA_SOFTRAPEN) {
+               const u32 prim_start = MGA_READ(MGA_PRIMADDRESS);
+               const u32 prim_end   = MGA_READ(MGA_PRIMEND);
+
+
+               MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR);
+
+               /* In addition to clearing the interrupt-pending bit, we
+                * have to write to MGA_PRIMEND to re-start the DMA operation.
+                */
+               if ( (prim_start & ~0x03) != (prim_end & ~0x03) ) {
+                       MGA_WRITE(MGA_PRIMEND, prim_end);
+               }
+
+               atomic_inc(&dev_priv->last_fence_retired);
+               DRM_WAKEUP(&dev_priv->fence_queue);
+               handled = 1;
+       }
+
+       if ( handled ) {
                return IRQ_HANDLED;
        }
        return IRQ_NONE;
@@ -73,9 +98,28 @@ int mga_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
        return ret;
 }
 
-void mga_driver_irq_preinstall( drm_device_t *dev ) {
-       drm_mga_private_t *dev_priv = 
-          (drm_mga_private_t *)dev->dev_private;
+int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence)
+{
+       drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
+       unsigned int cur_fence;
+       int ret = 0;
+
+       /* Assume that the user has missed the current sequence number
+        * by about a day rather than she wants to wait for years
+        * using fences.
+        */
+       DRM_WAIT_ON(ret, dev_priv->fence_queue, 3 * DRM_HZ,
+                   (((cur_fence = atomic_read(&dev_priv->last_fence_retired))
+                     - *sequence) <= (1 << 23)));
+
+       *sequence = cur_fence;
+
+       return ret;
+}
+
+void mga_driver_irq_preinstall(drm_device_t * dev)
+{
+       drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
 
        /* Disable *all* interrupts */
        MGA_WRITE( MGA_IEN, 0 );
@@ -83,12 +127,14 @@ void mga_driver_irq_preinstall( drm_device_t *dev ) {
        MGA_WRITE( MGA_ICLEAR, ~0 );
 }
 
-void mga_driver_irq_postinstall( drm_device_t *dev ) {
-       drm_mga_private_t *dev_priv = 
-          (drm_mga_private_t *)dev->dev_private;
+void mga_driver_irq_postinstall(drm_device_t * dev)
+{
+       drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
+
+       DRM_INIT_WAITQUEUE( &dev_priv->fence_queue );
 
-       /* Turn on VBL interrupt */
-       MGA_WRITE( MGA_IEN, MGA_VLINEIEN );
+       /* Turn on vertical blank interrupt and soft trap interrupt. */
+       MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
 }
 
 void mga_driver_irq_uninstall( drm_device_t *dev ) {
@@ -98,5 +144,7 @@ void mga_driver_irq_uninstall( drm_device_t *dev ) {
                return;
 
        /* Disable *all* interrupts */
-       MGA_WRITE( MGA_IEN, 0 );
+       MGA_WRITE(MGA_IEN, 0);
+       
+       dev->irq_enabled = 0;
 }
index 3c7a8f5ba50133e3289971b05e52402418935a82..05bbb4719376ac9fe1f424f8633d29a5643c2005 100644 (file)
@@ -53,16 +53,16 @@ static void mga_emit_clip_rect( drm_mga_private_t *dev_priv,
 
        /* Force reset of DWGCTL on G400 (eliminates clip disable bit).
         */
-       if ( dev_priv->chipset == MGA_CARD_TYPE_G400 ) {
-               DMA_BLOCK( MGA_DWGCTL,          ctx->dwgctl,
-                          MGA_LEN + MGA_EXEC,  0x80000000,
-                          MGA_DWGCTL,          ctx->dwgctl,
-                          MGA_LEN + MGA_EXEC,  0x80000000 );
+       if (dev_priv->chipset == MGA_CARD_TYPE_G400) {
+               DMA_BLOCK(MGA_DWGCTL, ctx->dwgctl,
+                         MGA_LEN + MGA_EXEC, 0x80000000,
+                         MGA_DWGCTL, ctx->dwgctl,
+                         MGA_LEN + MGA_EXEC, 0x80000000);
        }
-       DMA_BLOCK( MGA_DMAPAD,  0x00000000,
-                  MGA_CXBNDRY, (box->x2 << 16) | box->x1,
-                  MGA_YTOP,    box->y1 * pitch,
-                  MGA_YBOT,    box->y2 * pitch );
+       DMA_BLOCK(MGA_DMAPAD, 0x00000000,
+                 MGA_CXBNDRY, ((box->x2 - 1) << 16) | box->x1,
+                 MGA_YTOP, box->y1 * pitch,
+                 MGA_YBOT, (box->y2 - 1) * pitch);
 
        ADVANCE_DMA();
 }
@@ -260,12 +260,11 @@ static __inline__ void mga_g200_emit_pipe( drm_mga_private_t *dev_priv )
 
        /* Padding required to to hardware bug.
         */
-       DMA_BLOCK( MGA_DMAPAD,  0xffffffff,
-                  MGA_DMAPAD,  0xffffffff,
-                  MGA_DMAPAD,  0xffffffff,
-                  MGA_WIADDR,  (dev_priv->warp_pipe_phys[pipe] |
-                                MGA_WMODE_START |
-                                MGA_WAGP_ENABLE) );
+       DMA_BLOCK(MGA_DMAPAD, 0xffffffff,
+                 MGA_DMAPAD, 0xffffffff,
+                 MGA_DMAPAD, 0xffffffff,
+                 MGA_WIADDR, (dev_priv->warp_pipe_phys[pipe] |
+                              MGA_WMODE_START | dev_priv->wagp_enable));
 
        ADVANCE_DMA();
 }
@@ -342,12 +341,11 @@ static __inline__ void mga_g400_emit_pipe( drm_mga_private_t *dev_priv )
                   MGA_WR60,    MGA_G400_WR_MAGIC );    /* tex1 height       */
 
        /* Padding required to to hardware bug */
-       DMA_BLOCK( MGA_DMAPAD,  0xffffffff,
-                  MGA_DMAPAD,  0xffffffff,
-                  MGA_DMAPAD,  0xffffffff,
-                  MGA_WIADDR2, (dev_priv->warp_pipe_phys[pipe] |
-                                MGA_WMODE_START |
-                                MGA_WAGP_ENABLE) );
+       DMA_BLOCK(MGA_DMAPAD, 0xffffffff,
+                 MGA_DMAPAD, 0xffffffff,
+                 MGA_DMAPAD, 0xffffffff,
+                 MGA_WIADDR2, (dev_priv->warp_pipe_phys[pipe] |
+                               MGA_WMODE_START | dev_priv->wagp_enable));
 
        ADVANCE_DMA();
 }
@@ -459,9 +457,9 @@ static int mga_verify_state( drm_mga_private_t *dev_priv )
        if ( dirty & MGA_UPLOAD_TEX0 )
                ret |= mga_verify_tex( dev_priv, 0 );
 
-       if ( dev_priv->chipset == MGA_CARD_TYPE_G400 ) {
-               if ( dirty & MGA_UPLOAD_TEX1 )
-                       ret |= mga_verify_tex( dev_priv, 1 );
+       if (dev_priv->chipset >= MGA_CARD_TYPE_G400) {
+               if (dirty & MGA_UPLOAD_TEX1)
+                       ret |= mga_verify_tex(dev_priv, 1);
 
                if ( dirty & MGA_UPLOAD_PIPE )
                        ret |= ( sarea_priv->warp_pipe > MGA_MAX_G400_PIPES );
@@ -686,12 +684,12 @@ static void mga_dma_dispatch_vertex( drm_device_t *dev, drm_buf_t *buf )
 
                        BEGIN_DMA( 1 );
 
-                       DMA_BLOCK( MGA_DMAPAD,          0x00000000,
-                                  MGA_DMAPAD,          0x00000000,
-                                  MGA_SECADDRESS,      (address |
-                                                        MGA_DMA_VERTEX),
-                                  MGA_SECEND,          ((address + length) |
-                                                        MGA_PAGPXFER) );
+                       DMA_BLOCK(MGA_DMAPAD, 0x00000000,
+                                 MGA_DMAPAD, 0x00000000,
+                                 MGA_SECADDRESS, (address |
+                                                  MGA_DMA_VERTEX),
+                                 MGA_SECEND, ((address + length) |
+                                              dev_priv->dma_access));
 
                        ADVANCE_DMA();
                } while ( ++i < sarea_priv->nbox );
@@ -733,11 +731,11 @@ static void mga_dma_dispatch_indices( drm_device_t *dev, drm_buf_t *buf,
 
                        BEGIN_DMA( 1 );
 
-                       DMA_BLOCK( MGA_DMAPAD,          0x00000000,
-                                  MGA_DMAPAD,          0x00000000,
-                                  MGA_SETUPADDRESS,    address + start,
-                                  MGA_SETUPEND,        ((address + end) |
-                                                        MGA_PAGPXFER) );
+                       DMA_BLOCK(MGA_DMAPAD, 0x00000000,
+                                 MGA_DMAPAD, 0x00000000,
+                                 MGA_SETUPADDRESS, address + start,
+                                 MGA_SETUPEND, ((address + end) |
+                                                dev_priv->dma_access));
 
                        ADVANCE_DMA();
                } while ( ++i < sarea_priv->nbox );
@@ -764,7 +762,7 @@ static void mga_dma_dispatch_iload( drm_device_t *dev, drm_buf_t *buf,
        drm_mga_private_t *dev_priv = dev->dev_private;
        drm_mga_buf_priv_t *buf_priv = buf->dev_private;
        drm_mga_context_regs_t *ctx = &dev_priv->sarea_priv->context_state;
-       u32 srcorg = buf->bus_address | MGA_SRCACC_AGP | MGA_SRCMAP_SYSMEM;
+       u32 srcorg = buf->bus_address | dev_priv->dma_access | MGA_SRCMAP_SYSMEM;
        u32 y2;
        DMA_LOCALS;
        DRM_DEBUG( "buf=%d used=%d\n", buf->idx, buf->used );
@@ -1095,6 +1093,9 @@ static int mga_getparam( DRM_IOCTL_ARGS )
        case MGA_PARAM_IRQ_NR:
                value = dev->irq;
                break;
+       case MGA_PARAM_CARD_TYPE:
+               value = dev_priv->chipset;
+               break;
        default:
                return DRM_ERR(EINVAL);
        }
@@ -1107,17 +1108,82 @@ static int mga_getparam( DRM_IOCTL_ARGS )
        return 0;
 }
 
+static int mga_set_fence(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_mga_private_t *dev_priv = dev->dev_private;
+       u32 temp;
+       DMA_LOCALS;
+
+       if (!dev_priv) {
+               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               return DRM_ERR(EINVAL);
+       }
+
+       DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
+
+       /* I would normal do this assignment in the declaration of temp,
+        * but dev_priv may be NULL.
+        */
+
+       temp = dev_priv->next_fence_to_post;
+       dev_priv->next_fence_to_post++;
+
+       BEGIN_DMA(1);
+       DMA_BLOCK(MGA_DMAPAD, 0x00000000,
+                 MGA_DMAPAD, 0x00000000,
+                 MGA_DMAPAD, 0x00000000,
+                 MGA_SOFTRAP, 0x00000000);
+       ADVANCE_DMA();
+
+       if (DRM_COPY_TO_USER( (u32 __user *) data, & temp, sizeof(u32))) {
+               DRM_ERROR("copy_to_user\n");
+               return DRM_ERR(EFAULT);
+       }
+
+       return 0;
+}
+
+static int mga_wait_fence(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_mga_private_t *dev_priv = dev->dev_private;
+       u32 fence;
+
+       if (!dev_priv) {
+               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               return DRM_ERR(EINVAL);
+       }
+
+       DRM_COPY_FROM_USER_IOCTL(fence, (u32 __user *) data, sizeof(u32));
+
+       DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
+
+       mga_driver_fence_wait(dev, & fence);
+
+       if (DRM_COPY_TO_USER( (u32 __user *) data, & fence, sizeof(u32))) {
+               DRM_ERROR("copy_to_user\n");
+               return DRM_ERR(EFAULT);
+       }
+
+       return 0;
+}
+
 drm_ioctl_desc_t mga_ioctls[] = {
-       [DRM_IOCTL_NR(DRM_MGA_INIT)]    = { mga_dma_init,    1, 1 },
-       [DRM_IOCTL_NR(DRM_MGA_FLUSH)]   = { mga_dma_flush,   1, 0 },
-       [DRM_IOCTL_NR(DRM_MGA_RESET)]   = { mga_dma_reset,   1, 0 },
-       [DRM_IOCTL_NR(DRM_MGA_SWAP)]    = { mga_dma_swap,    1, 0 },
-       [DRM_IOCTL_NR(DRM_MGA_CLEAR)]   = { mga_dma_clear,   1, 0 },
-       [DRM_IOCTL_NR(DRM_MGA_VERTEX)]  = { mga_dma_vertex,  1, 0 },
-       [DRM_IOCTL_NR(DRM_MGA_INDICES)] = { mga_dma_indices, 1, 0 },
-       [DRM_IOCTL_NR(DRM_MGA_ILOAD)]   = { mga_dma_iload,   1, 0 },
-       [DRM_IOCTL_NR(DRM_MGA_BLIT)]    = { mga_dma_blit,    1, 0 },
-       [DRM_IOCTL_NR(DRM_MGA_GETPARAM)]= { mga_getparam,    1, 0 },
+       [DRM_IOCTL_NR(DRM_MGA_INIT)] = {mga_dma_init, 1, 1},
+       [DRM_IOCTL_NR(DRM_MGA_FLUSH)] = {mga_dma_flush, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_RESET)] = {mga_dma_reset, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_SWAP)] = {mga_dma_swap, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_CLEAR)] = {mga_dma_clear, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_VERTEX)] = {mga_dma_vertex, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_INDICES)] = {mga_dma_indices, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_ILOAD)] = {mga_dma_iload, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_BLIT)] = {mga_dma_blit, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_GETPARAM)] = {mga_getparam, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_SET_FENCE)] = {mga_set_fence, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_WAIT_FENCE)] = {mga_wait_fence, 1, 0},
+       [DRM_IOCTL_NR(DRM_MGA_DMA_BOOTSTRAP)] = {mga_dma_bootstrap, 1, 1},
+
 };
 
 int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls);
index 0a3a0cc700dce028152916834d70c1ff9bf2c504..55ccc8a0ac2990d7d56f8065aedc109e904ec619 100644 (file)
@@ -48,65 +48,52 @@ do {                                                                        \
        vcbase += WARP_UCODE_SIZE( which );                             \
 } while (0)
 
-
-static unsigned int mga_warp_g400_microcode_size( drm_mga_private_t *dev_priv )
-{
-       unsigned int size;
-
-       size = ( WARP_UCODE_SIZE( warp_g400_tgz ) +
-                WARP_UCODE_SIZE( warp_g400_tgza ) +
-                WARP_UCODE_SIZE( warp_g400_tgzaf ) +
-                WARP_UCODE_SIZE( warp_g400_tgzf ) +
-                WARP_UCODE_SIZE( warp_g400_tgzs ) +
-                WARP_UCODE_SIZE( warp_g400_tgzsa ) +
-                WARP_UCODE_SIZE( warp_g400_tgzsaf ) +
-                WARP_UCODE_SIZE( warp_g400_tgzsf ) +
-                WARP_UCODE_SIZE( warp_g400_t2gz ) +
-                WARP_UCODE_SIZE( warp_g400_t2gza ) +
-                WARP_UCODE_SIZE( warp_g400_t2gzaf ) +
-                WARP_UCODE_SIZE( warp_g400_t2gzf ) +
-                WARP_UCODE_SIZE( warp_g400_t2gzs ) +
-                WARP_UCODE_SIZE( warp_g400_t2gzsa ) +
-                WARP_UCODE_SIZE( warp_g400_t2gzsaf ) +
-                WARP_UCODE_SIZE( warp_g400_t2gzsf ) );
-
-       size = PAGE_ALIGN( size );
-
-       DRM_DEBUG( "G400 ucode size = %d bytes\n", size );
-       return size;
-}
-
-static unsigned int mga_warp_g200_microcode_size( drm_mga_private_t *dev_priv )
+static const unsigned int mga_warp_g400_microcode_size =
+              (WARP_UCODE_SIZE(warp_g400_tgz) +
+               WARP_UCODE_SIZE(warp_g400_tgza) +
+               WARP_UCODE_SIZE(warp_g400_tgzaf) +
+               WARP_UCODE_SIZE(warp_g400_tgzf) +
+               WARP_UCODE_SIZE(warp_g400_tgzs) +
+               WARP_UCODE_SIZE(warp_g400_tgzsa) +
+               WARP_UCODE_SIZE(warp_g400_tgzsaf) +
+               WARP_UCODE_SIZE(warp_g400_tgzsf) +
+               WARP_UCODE_SIZE(warp_g400_t2gz) +
+               WARP_UCODE_SIZE(warp_g400_t2gza) +
+               WARP_UCODE_SIZE(warp_g400_t2gzaf) +
+               WARP_UCODE_SIZE(warp_g400_t2gzf) +
+               WARP_UCODE_SIZE(warp_g400_t2gzs) +
+               WARP_UCODE_SIZE(warp_g400_t2gzsa) +
+               WARP_UCODE_SIZE(warp_g400_t2gzsaf) +
+               WARP_UCODE_SIZE(warp_g400_t2gzsf));
+
+static const unsigned int mga_warp_g200_microcode_size =
+              (WARP_UCODE_SIZE(warp_g200_tgz) +
+               WARP_UCODE_SIZE(warp_g200_tgza) +
+               WARP_UCODE_SIZE(warp_g200_tgzaf) +
+               WARP_UCODE_SIZE(warp_g200_tgzf) +
+               WARP_UCODE_SIZE(warp_g200_tgzs) +
+               WARP_UCODE_SIZE(warp_g200_tgzsa) +
+               WARP_UCODE_SIZE(warp_g200_tgzsaf) +
+               WARP_UCODE_SIZE(warp_g200_tgzsf));
+
+
+unsigned int mga_warp_microcode_size(const drm_mga_private_t * dev_priv)
 {
-       unsigned int size;
-
-       size = ( WARP_UCODE_SIZE( warp_g200_tgz ) +
-                WARP_UCODE_SIZE( warp_g200_tgza ) +
-                WARP_UCODE_SIZE( warp_g200_tgzaf ) +
-                WARP_UCODE_SIZE( warp_g200_tgzf ) +
-                WARP_UCODE_SIZE( warp_g200_tgzs ) +
-                WARP_UCODE_SIZE( warp_g200_tgzsa ) +
-                WARP_UCODE_SIZE( warp_g200_tgzsaf ) +
-                WARP_UCODE_SIZE( warp_g200_tgzsf ) );
-
-       size = PAGE_ALIGN( size );
-
-       DRM_DEBUG( "G200 ucode size = %d bytes\n", size );
-       return size;
+       switch (dev_priv->chipset) {
+       case MGA_CARD_TYPE_G400:
+       case MGA_CARD_TYPE_G550:
+               return PAGE_ALIGN(mga_warp_g400_microcode_size);
+       case MGA_CARD_TYPE_G200:
+               return PAGE_ALIGN(mga_warp_g200_microcode_size);
+       default:
+               return 0;
+       }
 }
 
 static int mga_warp_install_g400_microcode( drm_mga_private_t *dev_priv )
 {
        unsigned char *vcbase = dev_priv->warp->handle;
        unsigned long pcbase = dev_priv->warp->offset;
-       unsigned int size;
-
-       size = mga_warp_g400_microcode_size( dev_priv );
-       if ( size > dev_priv->warp->size ) {
-               DRM_ERROR( "microcode too large! (%u > %lu)\n",
-                          size, dev_priv->warp->size );
-               return DRM_ERR(ENOMEM);
-       }
 
        memset( dev_priv->warp_pipe_phys, 0,
                sizeof(dev_priv->warp_pipe_phys) );
@@ -136,35 +123,36 @@ static int mga_warp_install_g200_microcode( drm_mga_private_t *dev_priv )
 {
        unsigned char *vcbase = dev_priv->warp->handle;
        unsigned long pcbase = dev_priv->warp->offset;
-       unsigned int size;
-
-       size = mga_warp_g200_microcode_size( dev_priv );
-       if ( size > dev_priv->warp->size ) {
-               DRM_ERROR( "microcode too large! (%u > %lu)\n",
-                          size, dev_priv->warp->size );
-               return DRM_ERR(ENOMEM);
-       }
 
-       memset( dev_priv->warp_pipe_phys, 0,
-               sizeof(dev_priv->warp_pipe_phys) );
+       memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys));
 
-       WARP_UCODE_INSTALL( warp_g200_tgz,      MGA_WARP_TGZ );
-       WARP_UCODE_INSTALL( warp_g200_tgzf,     MGA_WARP_TGZF );
-       WARP_UCODE_INSTALL( warp_g200_tgza,     MGA_WARP_TGZA );
-       WARP_UCODE_INSTALL( warp_g200_tgzaf,    MGA_WARP_TGZAF );
-       WARP_UCODE_INSTALL( warp_g200_tgzs,     MGA_WARP_TGZS );
-       WARP_UCODE_INSTALL( warp_g200_tgzsf,    MGA_WARP_TGZSF );
-       WARP_UCODE_INSTALL( warp_g200_tgzsa,    MGA_WARP_TGZSA );
-       WARP_UCODE_INSTALL( warp_g200_tgzsaf,   MGA_WARP_TGZSAF );
+       WARP_UCODE_INSTALL(warp_g200_tgz, MGA_WARP_TGZ);
+       WARP_UCODE_INSTALL(warp_g200_tgzf, MGA_WARP_TGZF);
+       WARP_UCODE_INSTALL(warp_g200_tgza, MGA_WARP_TGZA);
+       WARP_UCODE_INSTALL(warp_g200_tgzaf, MGA_WARP_TGZAF);
+       WARP_UCODE_INSTALL(warp_g200_tgzs, MGA_WARP_TGZS);
+       WARP_UCODE_INSTALL(warp_g200_tgzsf, MGA_WARP_TGZSF);
+       WARP_UCODE_INSTALL(warp_g200_tgzsa, MGA_WARP_TGZSA);
+       WARP_UCODE_INSTALL(warp_g200_tgzsaf, MGA_WARP_TGZSAF);
 
        return 0;
 }
 
 int mga_warp_install_microcode(        drm_mga_private_t *dev_priv )
 {
-       switch ( dev_priv->chipset ) {
+       const unsigned int size = mga_warp_microcode_size(dev_priv);
+
+       DRM_DEBUG("MGA ucode size = %d bytes\n", size);
+       if (size > dev_priv->warp->size) {
+               DRM_ERROR("microcode too large! (%u > %lu)\n",
+                         size, dev_priv->warp->size);
+               return DRM_ERR(ENOMEM);
+       }
+
+       switch (dev_priv->chipset) {
        case MGA_CARD_TYPE_G400:
-               return mga_warp_install_g400_microcode( dev_priv );
+       case MGA_CARD_TYPE_G550:
+               return mga_warp_install_g400_microcode(dev_priv);
        case MGA_CARD_TYPE_G200:
                return mga_warp_install_g200_microcode( dev_priv );
        default:
@@ -182,10 +170,11 @@ int mga_warp_init( drm_mga_private_t *dev_priv )
         */
        switch ( dev_priv->chipset ) {
        case MGA_CARD_TYPE_G400:
-               MGA_WRITE( MGA_WIADDR2, MGA_WMODE_SUSPEND );
-               MGA_WRITE( MGA_WGETMSB, 0x00000E00 );
-               MGA_WRITE( MGA_WVRTXSZ, 0x00001807 );
-               MGA_WRITE( MGA_WACCEPTSEQ, 0x18000000 );
+       case MGA_CARD_TYPE_G550:
+               MGA_WRITE(MGA_WIADDR2, MGA_WMODE_SUSPEND);
+               MGA_WRITE(MGA_WGETMSB, 0x00000E00);
+               MGA_WRITE(MGA_WVRTXSZ, 0x00001807);
+               MGA_WRITE(MGA_WACCEPTSEQ, 0x18000000);
                break;
        case MGA_CARD_TYPE_G200:
                MGA_WRITE( MGA_WIADDR, MGA_WMODE_SUSPEND );
index 08ed8d01d9d95f6d7c2491ddd932ff8d8afc4e85..895152206b31f086c0b98ba6add5d07089e00324 100644 (file)
@@ -326,7 +326,8 @@ static void r128_cce_init_ring_buffer( drm_device_t *dev,
                ring_start = dev_priv->cce_ring->offset - dev->agp->base;
        else
 #endif
-               ring_start = dev_priv->cce_ring->offset - dev->sg->handle;
+               ring_start = dev_priv->cce_ring->offset - 
+                               (unsigned long)dev->sg->virtual;
 
        R128_WRITE( R128_PM4_BUFFER_OFFSET, ring_start | R128_AGP_OFFSET );
 
@@ -487,6 +488,7 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init )
                r128_do_cleanup_cce( dev );
                return DRM_ERR(EINVAL);
        }
+       dev->agp_buffer_token = init->buffers_offset;
        dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
        if(!dev->agp_buffer_map) {
                DRM_ERROR("could not find dma buffer region!\n");
@@ -537,7 +539,7 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init )
                dev_priv->cce_buffers_offset = dev->agp->base;
        else
 #endif
-               dev_priv->cce_buffers_offset = dev->sg->handle;
+               dev_priv->cce_buffers_offset = (unsigned long)dev->sg->virtual;
 
        dev_priv->ring.start = (u32 *)dev_priv->cce_ring->handle;
        dev_priv->ring.end = ((u32 *)dev_priv->cce_ring->handle
index 0cba17d1e0ffa9614b48b41ad30cfa752fdd705b..b616cd3ed2cd05fcbc1fc6e0834431242ec2d98a 100644 (file)
@@ -215,7 +215,7 @@ typedef struct drm_r128_sarea {
 #define DRM_IOCTL_R128_INDIRECT   DRM_IOWR(DRM_COMMAND_BASE + DRM_R128_INDIRECT, drm_r128_indirect_t)
 #define DRM_IOCTL_R128_FULLSCREEN DRM_IOW( DRM_COMMAND_BASE + DRM_R128_FULLSCREEN, drm_r128_fullscreen_t)
 #define DRM_IOCTL_R128_CLEAR2     DRM_IOW( DRM_COMMAND_BASE + DRM_R128_CLEAR2, drm_r128_clear2_t)
-#define DRM_IOCTL_R128_GETPARAM   DRM_IOW( DRM_COMMAND_BASE + DRM_R128_GETPARAM, drm_r128_getparam_t)
+#define DRM_IOCTL_R128_GETPARAM   DRM_IOWR( DRM_COMMAND_BASE + DRM_R128_GETPARAM, drm_r128_getparam_t)
 #define DRM_IOCTL_R128_FLIP       DRM_IO(  DRM_COMMAND_BASE + DRM_R128_FLIP)
 
 typedef struct drm_r128_init {
diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c
new file mode 100644 (file)
index 0000000..623f1f4
--- /dev/null
@@ -0,0 +1,801 @@
+/* r300_cmdbuf.c -- Command buffer emission for R300 -*- linux-c -*-
+ *
+ * Copyright (C) The Weather Channel, Inc.  2002.
+ * Copyright (C) 2004 Nicolai Haehnle.
+ * All Rights Reserved.
+ *
+ * The Weather Channel (TM) funded Tungsten Graphics to develop the
+ * initial release of the Radeon 8500 driver under the XFree86 license.
+ * This notice must be preserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Nicolai Haehnle <prefect_@gmx.net>
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_drm.h"
+#include "radeon_drv.h"
+#include "r300_reg.h"
+
+
+#define R300_SIMULTANEOUS_CLIPRECTS            4
+
+/* Values for R300_RE_CLIPRECT_CNTL depending on the number of cliprects
+ */
+static const int r300_cliprect_cntl[4] = {
+       0xAAAA,
+       0xEEEE,
+       0xFEFE,
+       0xFFFE
+};
+
+
+/**
+ * Emit up to R300_SIMULTANEOUS_CLIPRECTS cliprects from the given command
+ * buffer, starting with index n.
+ */
+static int r300_emit_cliprects(drm_radeon_private_t* dev_priv,
+                              drm_radeon_cmd_buffer_t* cmdbuf,
+                              int n)
+{
+       drm_clip_rect_t box;
+       int nr;
+       int i;
+       RING_LOCALS;
+
+       nr = cmdbuf->nbox - n;
+       if (nr > R300_SIMULTANEOUS_CLIPRECTS)
+               nr = R300_SIMULTANEOUS_CLIPRECTS;
+
+       DRM_DEBUG("%i cliprects\n", nr);
+
+       if (nr) {
+               BEGIN_RING(6 + nr*2);
+               OUT_RING( CP_PACKET0( R300_RE_CLIPRECT_TL_0, nr*2 - 1 ) );
+
+               for(i = 0; i < nr; ++i) {
+                       if (DRM_COPY_FROM_USER_UNCHECKED(&box, &cmdbuf->boxes[n+i], sizeof(box))) {
+                               DRM_ERROR("copy cliprect faulted\n");
+                               return DRM_ERR(EFAULT);
+                       }
+
+                       box.x1 = (box.x1 + R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;
+                       box.y1 = (box.y1 + R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;
+                       box.x2 = (box.x2 + R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;
+                       box.y2 = (box.y2 + R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;
+
+                       OUT_RING((box.x1 << R300_CLIPRECT_X_SHIFT) |
+                                       (box.y1 << R300_CLIPRECT_Y_SHIFT));
+                       OUT_RING((box.x2 << R300_CLIPRECT_X_SHIFT) |
+                                       (box.y2 << R300_CLIPRECT_Y_SHIFT));
+               }
+
+               OUT_RING_REG( R300_RE_CLIPRECT_CNTL, r300_cliprect_cntl[nr-1] );
+
+               /* TODO/SECURITY: Force scissors to a safe value, otherwise the
+               * client might be able to trample over memory.
+               * The impact should be very limited, but I'd rather be safe than
+               * sorry.
+               */
+               OUT_RING( CP_PACKET0( R300_RE_SCISSORS_TL, 1 ) );
+               OUT_RING( 0 );
+               OUT_RING( R300_SCISSORS_X_MASK | R300_SCISSORS_Y_MASK );
+               ADVANCE_RING();
+               } else {
+               /* Why we allow zero cliprect rendering:
+                * There are some commands in a command buffer that must be submitted
+                * even when there are no cliprects, e.g. DMA buffer discard
+                * or state setting (though state setting could be avoided by
+                * simulating a loss of context).
+                *
+                * Now since the cmdbuf interface is so chaotic right now (and is
+                * bound to remain that way for a bit until things settle down),
+                * it is basically impossible to filter out the commands that are
+                * necessary and those that aren't.
+                *
+                * So I choose the safe way and don't do any filtering at all;
+                * instead, I simply set up the engine so that all rendering
+                * can't produce any fragments.
+                */
+               BEGIN_RING(2);
+               OUT_RING_REG( R300_RE_CLIPRECT_CNTL, 0 );
+               ADVANCE_RING();
+               }
+
+       return 0;
+}
+
+u8  r300_reg_flags[0x10000>>2];
+
+
+void r300_init_reg_flags(void)
+{
+       int i;
+       memset(r300_reg_flags, 0, 0x10000>>2);
+       #define ADD_RANGE_MARK(reg, count,mark) \
+               for(i=((reg)>>2);i<((reg)>>2)+(count);i++)\
+                       r300_reg_flags[i]|=(mark);
+       
+       #define MARK_SAFE               1
+       #define MARK_CHECK_OFFSET       2
+       
+       #define ADD_RANGE(reg, count)   ADD_RANGE_MARK(reg, count, MARK_SAFE)
+
+       /* these match cmducs() command in r300_driver/r300/r300_cmdbuf.c */
+       ADD_RANGE(R300_SE_VPORT_XSCALE, 6);
+       ADD_RANGE(0x2080, 1);
+       ADD_RANGE(R300_SE_VTE_CNTL, 2);
+       ADD_RANGE(0x2134, 2);
+       ADD_RANGE(0x2140, 1);
+       ADD_RANGE(R300_VAP_INPUT_CNTL_0, 2);
+       ADD_RANGE(0x21DC, 1);
+       ADD_RANGE(0x221C, 1);
+       ADD_RANGE(0x2220, 4);
+       ADD_RANGE(0x2288, 1);
+       ADD_RANGE(R300_VAP_OUTPUT_VTX_FMT_0, 2);
+       ADD_RANGE(R300_VAP_PVS_CNTL_1, 3);
+       ADD_RANGE(R300_GB_ENABLE, 1);
+       ADD_RANGE(R300_GB_MSPOS0, 5);
+       ADD_RANGE(R300_TX_ENABLE, 1);
+       ADD_RANGE(0x4200, 4);
+       ADD_RANGE(0x4214, 1);
+       ADD_RANGE(R300_RE_POINTSIZE, 1);
+       ADD_RANGE(0x4230, 3);
+       ADD_RANGE(R300_RE_LINE_CNT, 1);
+       ADD_RANGE(0x4238, 1);
+       ADD_RANGE(0x4260, 3);
+       ADD_RANGE(0x4274, 4);
+       ADD_RANGE(0x4288, 5);
+       ADD_RANGE(0x42A0, 1);
+       ADD_RANGE(R300_RE_ZBIAS_T_FACTOR, 4);
+       ADD_RANGE(0x42B4, 1);
+       ADD_RANGE(R300_RE_CULL_CNTL, 1);
+       ADD_RANGE(0x42C0, 2);
+       ADD_RANGE(R300_RS_CNTL_0, 2);
+       ADD_RANGE(R300_RS_INTERP_0, 8);
+       ADD_RANGE(R300_RS_ROUTE_0, 8);
+       ADD_RANGE(0x43A4, 2);
+       ADD_RANGE(0x43E8, 1);
+       ADD_RANGE(R300_PFS_CNTL_0, 3);
+       ADD_RANGE(R300_PFS_NODE_0, 4);
+       ADD_RANGE(R300_PFS_TEXI_0, 64);
+       ADD_RANGE(0x46A4, 5);
+       ADD_RANGE(R300_PFS_INSTR0_0, 64);
+       ADD_RANGE(R300_PFS_INSTR1_0, 64);
+       ADD_RANGE(R300_PFS_INSTR2_0, 64);
+       ADD_RANGE(R300_PFS_INSTR3_0, 64);
+       ADD_RANGE(0x4BC0, 1);
+       ADD_RANGE(0x4BC8, 3);
+       ADD_RANGE(R300_PP_ALPHA_TEST, 2);
+       ADD_RANGE(0x4BD8, 1);
+       ADD_RANGE(R300_PFS_PARAM_0_X, 64);
+       ADD_RANGE(0x4E00, 1);
+       ADD_RANGE(R300_RB3D_CBLEND, 2);
+       ADD_RANGE(R300_RB3D_COLORMASK, 1);
+       ADD_RANGE(0x4E10, 3);
+       ADD_RANGE_MARK(R300_RB3D_COLOROFFSET0, 1, MARK_CHECK_OFFSET); /* check offset */
+       ADD_RANGE(R300_RB3D_COLORPITCH0, 1);
+       ADD_RANGE(0x4E50, 9);
+       ADD_RANGE(0x4E88, 1);
+       ADD_RANGE(0x4EA0, 2);
+       ADD_RANGE(R300_RB3D_ZSTENCIL_CNTL_0, 3);
+       ADD_RANGE(0x4F10, 4);
+       ADD_RANGE_MARK(R300_RB3D_DEPTHOFFSET, 1, MARK_CHECK_OFFSET); /* check offset */
+       ADD_RANGE(R300_RB3D_DEPTHPITCH, 1); 
+       ADD_RANGE(0x4F28, 1);
+       ADD_RANGE(0x4F30, 2);
+       ADD_RANGE(0x4F44, 1);
+       ADD_RANGE(0x4F54, 1);
+
+       ADD_RANGE(R300_TX_FILTER_0, 16);
+       ADD_RANGE(R300_TX_UNK1_0, 16);
+       ADD_RANGE(R300_TX_SIZE_0, 16);
+       ADD_RANGE(R300_TX_FORMAT_0, 16);
+               /* Texture offset is dangerous and needs more checking */
+       ADD_RANGE_MARK(R300_TX_OFFSET_0, 16, MARK_CHECK_OFFSET);
+       ADD_RANGE(R300_TX_UNK4_0, 16);
+       ADD_RANGE(R300_TX_BORDER_COLOR_0, 16);
+
+       /* Sporadic registers used as primitives are emitted */
+       ADD_RANGE(0x4f18, 1);
+       ADD_RANGE(R300_RB3D_DSTCACHE_CTLSTAT, 1);
+       ADD_RANGE(R300_VAP_INPUT_ROUTE_0_0, 8);
+       ADD_RANGE(R300_VAP_INPUT_ROUTE_1_0, 8);
+
+}
+
+static __inline__ int r300_check_range(unsigned  reg, int count)
+{
+       int i;
+       if(reg & ~0xffff)return -1;
+       for(i=(reg>>2);i<(reg>>2)+count;i++)
+               if(r300_reg_flags[i]!=MARK_SAFE)return 1;
+       return 0;
+}
+
+  /* we expect offsets passed to the framebuffer to be either within video memory or
+      within AGP space */
+static __inline__ int r300_check_offset(drm_radeon_private_t* dev_priv, u32 offset)
+{
+       /* we realy want to check against end of video aperture
+               but this value is not being kept. 
+               This code is correct for now (does the same thing as the
+               code that sets MC_FB_LOCATION) in radeon_cp.c */
+       if((offset>=dev_priv->fb_location) && 
+               (offset<dev_priv->gart_vm_start))return 0;
+       if((offset>=dev_priv->gart_vm_start) &&
+                (offset<dev_priv->gart_vm_start+dev_priv->gart_size))return 0;
+       return 1;
+}
+
+static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t* dev_priv,
+                                               drm_radeon_cmd_buffer_t* cmdbuf,
+                                               drm_r300_cmd_header_t header)
+{
+       int reg;
+       int sz;
+       int i;
+       int values[64];
+       RING_LOCALS;
+
+       sz = header.packet0.count;
+       reg = (header.packet0.reghi << 8) | header.packet0.reglo;
+       
+       if((sz>64)||(sz<0)){
+               DRM_ERROR("Cannot emit more than 64 values at a time (reg=%04x sz=%d)\n", reg, sz);
+               return DRM_ERR(EINVAL);
+               }
+       for(i=0;i<sz;i++){
+               values[i]=((int __user*)cmdbuf->buf)[i];
+               switch(r300_reg_flags[(reg>>2)+i]){
+               case MARK_SAFE:
+                       break;
+               case MARK_CHECK_OFFSET:
+                       if(r300_check_offset(dev_priv, (u32)values[i])){
+                               DRM_ERROR("Offset failed range check (reg=%04x sz=%d)\n", reg, sz);
+                               return DRM_ERR(EINVAL);
+                               }
+                       break;
+               default:
+                       DRM_ERROR("Register %04x failed check as flag=%02x\n", reg+i*4, r300_reg_flags[(reg>>2)+i]);
+                       return DRM_ERR(EINVAL);
+                       }
+               }
+               
+       BEGIN_RING(1+sz);
+       OUT_RING( CP_PACKET0( reg, sz-1 ) );
+       OUT_RING_TABLE( values, sz );
+       ADVANCE_RING();
+
+       cmdbuf->buf += sz*4;
+       cmdbuf->bufsz -= sz*4;
+
+       return 0;
+}
+
+/**
+ * Emits a packet0 setting arbitrary registers.
+ * Called by r300_do_cp_cmdbuf.
+ *
+ * Note that checks are performed on contents and addresses of the registers
+ */
+static __inline__ int r300_emit_packet0(drm_radeon_private_t* dev_priv,
+                                               drm_radeon_cmd_buffer_t* cmdbuf,
+                                               drm_r300_cmd_header_t header)
+{
+       int reg;
+       int sz;
+       RING_LOCALS;
+
+       sz = header.packet0.count;
+       reg = (header.packet0.reghi << 8) | header.packet0.reglo;
+
+       if (!sz)
+               return 0;
+
+       if (sz*4 > cmdbuf->bufsz)
+               return DRM_ERR(EINVAL);
+               
+       if (reg+sz*4 >= 0x10000){
+               DRM_ERROR("No such registers in hardware reg=%04x sz=%d\n", reg, sz);
+               return DRM_ERR(EINVAL);
+               }
+
+       if(r300_check_range(reg, sz)){
+               /* go and check everything */
+               return r300_emit_carefully_checked_packet0(dev_priv, cmdbuf, header);
+               }
+       /* the rest of the data is safe to emit, whatever the values the user passed */
+
+       BEGIN_RING(1+sz);
+       OUT_RING( CP_PACKET0( reg, sz-1 ) );
+       OUT_RING_TABLE( (int __user*)cmdbuf->buf, sz );
+       ADVANCE_RING();
+
+       cmdbuf->buf += sz*4;
+       cmdbuf->bufsz -= sz*4;
+
+       return 0;
+}
+
+
+/**
+ * Uploads user-supplied vertex program instructions or parameters onto
+ * the graphics card.
+ * Called by r300_do_cp_cmdbuf.
+ */
+static __inline__ int r300_emit_vpu(drm_radeon_private_t* dev_priv,
+                                   drm_radeon_cmd_buffer_t* cmdbuf,
+                                   drm_r300_cmd_header_t header)
+{
+       int sz;
+       int addr;
+       RING_LOCALS;
+
+       sz = header.vpu.count;
+       addr = (header.vpu.adrhi << 8) | header.vpu.adrlo;
+
+       if (!sz)
+               return 0;
+       if (sz*16 > cmdbuf->bufsz)
+               return DRM_ERR(EINVAL);
+
+       BEGIN_RING(5+sz*4);
+       /* Wait for VAP to come to senses.. */
+       /* there is no need to emit it multiple times, (only once before VAP is programmed,
+          but this optimization is for later */
+       OUT_RING_REG( R300_VAP_PVS_WAITIDLE, 0 );
+       OUT_RING_REG( R300_VAP_PVS_UPLOAD_ADDRESS, addr );
+       OUT_RING( CP_PACKET0_TABLE( R300_VAP_PVS_UPLOAD_DATA, sz*4 - 1 ) );
+       OUT_RING_TABLE( (int __user*)cmdbuf->buf, sz*4 );
+
+       ADVANCE_RING();
+
+       cmdbuf->buf += sz*16;
+       cmdbuf->bufsz -= sz*16;
+
+       return 0;
+}
+
+
+/**
+ * Emit a clear packet from userspace.
+ * Called by r300_emit_packet3.
+ */
+static __inline__ int r300_emit_clear(drm_radeon_private_t* dev_priv,
+                                     drm_radeon_cmd_buffer_t* cmdbuf)
+{
+       RING_LOCALS;
+
+       if (8*4 > cmdbuf->bufsz)
+               return DRM_ERR(EINVAL);
+
+       BEGIN_RING(10);
+       OUT_RING( CP_PACKET3( R200_3D_DRAW_IMMD_2, 8 ) );
+       OUT_RING( R300_PRIM_TYPE_POINT|R300_PRIM_WALK_RING|
+                 (1<<R300_PRIM_NUM_VERTICES_SHIFT) );
+       OUT_RING_TABLE( (int __user*)cmdbuf->buf, 8 );
+       ADVANCE_RING();
+
+       cmdbuf->buf += 8*4;
+       cmdbuf->bufsz -= 8*4;
+
+       return 0;
+}
+
+static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t* dev_priv,
+                                     drm_radeon_cmd_buffer_t* cmdbuf,
+                                     u32 header)
+{
+       int count, i,k;
+       #define MAX_ARRAY_PACKET  64
+       u32 payload[MAX_ARRAY_PACKET];
+       u32 narrays;
+       RING_LOCALS;
+
+       count=(header>>16) & 0x3fff;
+       
+       if((count+1)>MAX_ARRAY_PACKET){
+               DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n", count);
+               return DRM_ERR(EINVAL);
+               }
+       memset(payload, 0, MAX_ARRAY_PACKET*4);
+       memcpy(payload, cmdbuf->buf+4, (count+1)*4);    
+       
+       /* carefully check packet contents */
+       
+       narrays=payload[0];
+       k=0;
+       i=1;
+       while((k<narrays) && (i<(count+1))){
+               i++; /* skip attribute field */
+               if(r300_check_offset(dev_priv, payload[i])){
+                       DRM_ERROR("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n", k, i);
+                       return DRM_ERR(EINVAL);
+                       }
+               k++;
+               i++;
+               if(k==narrays)break;
+               /* have one more to process, they come in pairs */
+               if(r300_check_offset(dev_priv, payload[i])){
+                       DRM_ERROR("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n", k, i);
+                       return DRM_ERR(EINVAL);
+                       }
+               k++;
+               i++;                    
+               }
+       /* do the counts match what we expect ? */
+       if((k!=narrays) || (i!=(count+1))){
+               DRM_ERROR("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n", k, i, narrays, count+1);
+               return DRM_ERR(EINVAL);
+               }
+
+       /* all clear, output packet */
+
+       BEGIN_RING(count+2);
+       OUT_RING(header);
+       OUT_RING_TABLE(payload, count+1);
+       ADVANCE_RING();
+
+       cmdbuf->buf += (count+2)*4;
+       cmdbuf->bufsz -= (count+2)*4;
+
+       return 0;
+}
+
+static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t* dev_priv,
+                                     drm_radeon_cmd_buffer_t* cmdbuf)
+{
+       u32 header;
+       int count;
+       RING_LOCALS;
+
+       if (4 > cmdbuf->bufsz)
+               return DRM_ERR(EINVAL);
+
+        /* Fixme !! This simply emits a packet without much checking.
+          We need to be smarter. */
+
+       /* obtain first word - actual packet3 header */
+       header = *(u32 __user*)cmdbuf->buf;
+
+       /* Is it packet 3 ? */
+       if( (header>>30)!=0x3 ) {
+               DRM_ERROR("Not a packet3 header (0x%08x)\n", header);
+               return DRM_ERR(EINVAL);
+               }
+
+       count=(header>>16) & 0x3fff;
+
+       /* Check again now that we know how much data to expect */
+       if ((count+2)*4 > cmdbuf->bufsz){
+               DRM_ERROR("Expected packet3 of length %d but have only %d bytes left\n",
+                       (count+2)*4, cmdbuf->bufsz);
+               return DRM_ERR(EINVAL);
+               }
+
+       /* Is it a packet type we know about ? */
+       switch(header & 0xff00){
+       case RADEON_3D_LOAD_VBPNTR: /* load vertex array pointers */
+               return r300_emit_3d_load_vbpntr(dev_priv, cmdbuf, header);
+
+       case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */
+       case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */
+       case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */
+       case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */
+       case RADEON_WAIT_FOR_IDLE:
+       case RADEON_CP_NOP:
+               /* these packets are safe */
+               break;
+       default:
+               DRM_ERROR("Unknown packet3 header (0x%08x)\n", header);
+               return DRM_ERR(EINVAL);
+               }
+
+
+       BEGIN_RING(count+2);
+       OUT_RING(header);
+       OUT_RING_TABLE( (int __user*)(cmdbuf->buf+4), count+1);
+       ADVANCE_RING();
+
+       cmdbuf->buf += (count+2)*4;
+       cmdbuf->bufsz -= (count+2)*4;
+
+       return 0;
+}
+
+
+/**
+ * Emit a rendering packet3 from userspace.
+ * Called by r300_do_cp_cmdbuf.
+ */
+static __inline__ int r300_emit_packet3(drm_radeon_private_t* dev_priv,
+                                       drm_radeon_cmd_buffer_t* cmdbuf,
+                                       drm_r300_cmd_header_t header)
+{
+       int n;
+       int ret;
+       char __user* orig_buf = cmdbuf->buf;
+       int orig_bufsz = cmdbuf->bufsz;
+
+       /* This is a do-while-loop so that we run the interior at least once,
+        * even if cmdbuf->nbox is 0. Compare r300_emit_cliprects for rationale.
+        */
+       n = 0;
+       do {
+               if (cmdbuf->nbox > R300_SIMULTANEOUS_CLIPRECTS) {
+                       ret = r300_emit_cliprects(dev_priv, cmdbuf, n);
+                       if (ret)
+                               return ret;
+
+                       cmdbuf->buf = orig_buf;
+                       cmdbuf->bufsz = orig_bufsz;
+                       }
+
+               switch(header.packet3.packet) {
+               case R300_CMD_PACKET3_CLEAR:
+                       DRM_DEBUG("R300_CMD_PACKET3_CLEAR\n");
+                       ret = r300_emit_clear(dev_priv, cmdbuf);
+                       if (ret) {
+                               DRM_ERROR("r300_emit_clear failed\n");
+                               return ret;
+                               }
+                       break;
+
+               case R300_CMD_PACKET3_RAW:
+                       DRM_DEBUG("R300_CMD_PACKET3_RAW\n");
+                       ret = r300_emit_raw_packet3(dev_priv, cmdbuf);
+                       if (ret) {
+                               DRM_ERROR("r300_emit_raw_packet3 failed\n");
+                               return ret;
+                               }
+                       break;
+
+               default:
+                       DRM_ERROR("bad packet3 type %i at %p\n",
+                               header.packet3.packet,
+                               cmdbuf->buf - sizeof(header));
+                       return DRM_ERR(EINVAL);
+                       }
+
+               n += R300_SIMULTANEOUS_CLIPRECTS;
+       } while(n < cmdbuf->nbox);
+
+       return 0;
+}
+
+/* Some of the R300 chips seem to be extremely touchy about the two registers
+ * that are configured in r300_pacify.
+ * Among the worst offenders seems to be the R300 ND (0x4E44): When userspace
+ * sends a command buffer that contains only state setting commands and a
+ * vertex program/parameter upload sequence, this will eventually lead to a
+ * lockup, unless the sequence is bracketed by calls to r300_pacify.
+ * So we should take great care to *always* call r300_pacify before
+ * *anything* 3D related, and again afterwards. This is what the
+ * call bracket in r300_do_cp_cmdbuf is for.
+ */
+
+/**
+ * Emit the sequence to pacify R300.
+ */
+static __inline__ void r300_pacify(drm_radeon_private_t* dev_priv)
+{
+       RING_LOCALS;
+
+       BEGIN_RING(6);
+       OUT_RING( CP_PACKET0( R300_RB3D_DSTCACHE_CTLSTAT, 0 ) );
+       OUT_RING( 0xa );
+       OUT_RING( CP_PACKET0( 0x4f18, 0 ) );
+       OUT_RING( 0x3 );
+       OUT_RING( CP_PACKET3( RADEON_CP_NOP, 0 ) );
+       OUT_RING( 0x0 );
+       ADVANCE_RING();
+}
+
+
+/**
+ * Called by r300_do_cp_cmdbuf to update the internal buffer age and state.
+ * The actual age emit is done by r300_do_cp_cmdbuf, which is why you must
+ * be careful about how this function is called.
+ */
+static void r300_discard_buffer(drm_device_t * dev, drm_buf_t * buf)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
+
+       buf_priv->age = ++dev_priv->sarea_priv->last_dispatch;
+       buf->pending = 1;
+       buf->used = 0;
+}
+
+
+/**
+ * Parses and validates a user-supplied command buffer and emits appropriate
+ * commands on the DMA ring buffer.
+ * Called by the ioctl handler function radeon_cp_cmdbuf.
+ */
+int r300_do_cp_cmdbuf(drm_device_t* dev,
+                         DRMFILE filp,
+                     drm_file_t* filp_priv,
+                     drm_radeon_cmd_buffer_t* cmdbuf)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+        drm_device_dma_t *dma = dev->dma;
+        drm_buf_t *buf = NULL;
+       int emit_dispatch_age = 0;
+       int ret = 0;
+
+       DRM_DEBUG("\n");
+
+       /* See the comment above r300_emit_begin3d for why this call must be here,
+        * and what the cleanup gotos are for. */
+       r300_pacify(dev_priv);
+
+       if (cmdbuf->nbox <= R300_SIMULTANEOUS_CLIPRECTS) {
+               ret = r300_emit_cliprects(dev_priv, cmdbuf, 0);
+               if (ret)
+                       goto cleanup;
+               }
+
+       while(cmdbuf->bufsz >= sizeof(drm_r300_cmd_header_t)) {
+               int idx;
+               drm_r300_cmd_header_t header;
+
+               header.u = *(unsigned int *)cmdbuf->buf;
+
+               cmdbuf->buf += sizeof(header);
+               cmdbuf->bufsz -= sizeof(header);
+
+               switch(header.header.cmd_type) {
+               case R300_CMD_PACKET0: 
+                       DRM_DEBUG("R300_CMD_PACKET0\n");
+                       ret = r300_emit_packet0(dev_priv, cmdbuf, header);
+                       if (ret) {
+                               DRM_ERROR("r300_emit_packet0 failed\n");
+                               goto cleanup;
+                               }
+                       break;
+
+               case R300_CMD_VPU:
+                       DRM_DEBUG("R300_CMD_VPU\n");
+                       ret = r300_emit_vpu(dev_priv, cmdbuf, header);
+                       if (ret) {
+                               DRM_ERROR("r300_emit_vpu failed\n");
+                               goto cleanup;
+                               }
+                       break;
+
+               case R300_CMD_PACKET3:
+                       DRM_DEBUG("R300_CMD_PACKET3\n");
+                       ret = r300_emit_packet3(dev_priv, cmdbuf, header);
+                       if (ret) {
+                               DRM_ERROR("r300_emit_packet3 failed\n");
+                               goto cleanup;
+                               }
+                       break;
+
+               case R300_CMD_END3D:
+                       DRM_DEBUG("R300_CMD_END3D\n");
+                       /* TODO: 
+                               Ideally userspace driver should not need to issue this call, 
+                               i.e. the drm driver should issue it automatically and prevent
+                               lockups.
+                               
+                               In practice, we do not understand why this call is needed and what
+                               it does (except for some vague guesses that it has to do with cache
+                               coherence) and so the user space driver does it. 
+                               
+                               Once we are sure which uses prevent lockups the code could be moved
+                               into the kernel and the userspace driver will not
+                               need to use this command.
+
+                               Note that issuing this command does not hurt anything
+                               except, possibly, performance */
+                       r300_pacify(dev_priv);
+                       break;
+
+               case R300_CMD_CP_DELAY:
+                       /* simple enough, we can do it here */
+                       DRM_DEBUG("R300_CMD_CP_DELAY\n");
+                       {
+                               int i;
+                               RING_LOCALS;
+
+                               BEGIN_RING(header.delay.count);
+                               for(i=0;i<header.delay.count;i++)
+                                       OUT_RING(RADEON_CP_PACKET2);
+                               ADVANCE_RING();
+                       }
+                       break;
+
+               case R300_CMD_DMA_DISCARD:
+                       DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
+                       idx = header.dma.buf_idx;
+                       if (idx < 0 || idx >= dma->buf_count) {
+                               DRM_ERROR("buffer index %d (of %d max)\n",
+                                       idx, dma->buf_count - 1);
+                               ret = DRM_ERR(EINVAL);
+                               goto cleanup;
+                               }
+
+                       buf = dma->buflist[idx];
+                       if (buf->filp != filp || buf->pending) {
+                               DRM_ERROR("bad buffer %p %p %d\n",
+                               buf->filp, filp, buf->pending);
+                               ret = DRM_ERR(EINVAL);
+                               goto cleanup;
+                               }
+
+                       emit_dispatch_age = 1;
+                       r300_discard_buffer(dev, buf);
+                       break;
+
+               case R300_CMD_WAIT:
+                       /* simple enough, we can do it here */
+                       DRM_DEBUG("R300_CMD_WAIT\n");
+                       if(header.wait.flags==0)break; /* nothing to do */
+
+                       {
+                               RING_LOCALS;
+
+                               BEGIN_RING(2);
+                               OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) );
+                               OUT_RING( (header.wait.flags & 0xf)<<14 );
+                               ADVANCE_RING();
+                       }
+                       break;
+
+               default:
+                       DRM_ERROR("bad cmd_type %i at %p\n",
+                                 header.header.cmd_type,
+                                 cmdbuf->buf - sizeof(header));
+                       ret = DRM_ERR(EINVAL);
+                       goto cleanup;
+                       }
+       }
+
+       DRM_DEBUG("END\n");
+
+cleanup:
+       r300_pacify(dev_priv);
+
+       /* We emit the vertex buffer age here, outside the pacifier "brackets"
+        * for two reasons:
+        *  (1) This may coalesce multiple age emissions into a single one and
+        *  (2) more importantly, some chips lock up hard when scratch registers
+        *      are written inside the pacifier bracket.
+        */
+       if (emit_dispatch_age) {
+               RING_LOCALS;
+
+               /* Emit the vertex buffer age */
+               BEGIN_RING(2);
+               RADEON_DISPATCH_AGE(dev_priv->sarea_priv->last_dispatch);
+               ADVANCE_RING();
+               }
+
+       COMMIT_RING();
+
+       return ret;
+}
+
diff --git a/drivers/char/drm/r300_reg.h b/drivers/char/drm/r300_reg.h
new file mode 100644 (file)
index 0000000..c3e7ca3
--- /dev/null
@@ -0,0 +1,1412 @@
+/**************************************************************************
+
+Copyright (C) 2004-2005 Nicolai Haehnle et al.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, and/or sell copies of the Software, and to permit persons to whom
+the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+#ifndef _R300_REG_H
+#define _R300_REG_H
+
+#define R300_MC_INIT_MISC_LAT_TIMER    0x180
+#      define R300_MC_MISC__MC_CPR_INIT_LAT_SHIFT      0
+#      define R300_MC_MISC__MC_VF_INIT_LAT_SHIFT       4
+#      define R300_MC_MISC__MC_DISP0R_INIT_LAT_SHIFT   8
+#      define R300_MC_MISC__MC_DISP1R_INIT_LAT_SHIFT   12
+#      define R300_MC_MISC__MC_FIXED_INIT_LAT_SHIFT    16
+#      define R300_MC_MISC__MC_E2R_INIT_LAT_SHIFT      20
+#      define R300_MC_MISC__MC_SAME_PAGE_PRIO_SHIFT    24
+#      define R300_MC_MISC__MC_GLOBW_INIT_LAT_SHIFT    28
+
+
+#define R300_MC_INIT_GFX_LAT_TIMER     0x154
+#      define R300_MC_MISC__MC_G3D0R_INIT_LAT_SHIFT    0
+#      define R300_MC_MISC__MC_G3D1R_INIT_LAT_SHIFT    4
+#      define R300_MC_MISC__MC_G3D2R_INIT_LAT_SHIFT    8
+#      define R300_MC_MISC__MC_G3D3R_INIT_LAT_SHIFT    12
+#      define R300_MC_MISC__MC_TX0R_INIT_LAT_SHIFT     16
+#      define R300_MC_MISC__MC_TX1R_INIT_LAT_SHIFT     20
+#      define R300_MC_MISC__MC_GLOBR_INIT_LAT_SHIFT    24
+#      define R300_MC_MISC__MC_GLOBW_FULL_LAT_SHIFT    28
+
+/*
+This file contains registers and constants for the R300. They have been
+found mostly by examining command buffers captured using glxtest, as well
+as by extrapolating some known registers and constants from the R200.
+
+I am fairly certain that they are correct unless stated otherwise in comments.
+*/
+
+#define R300_SE_VPORT_XSCALE                0x1D98
+#define R300_SE_VPORT_XOFFSET               0x1D9C
+#define R300_SE_VPORT_YSCALE                0x1DA0
+#define R300_SE_VPORT_YOFFSET               0x1DA4
+#define R300_SE_VPORT_ZSCALE                0x1DA8
+#define R300_SE_VPORT_ZOFFSET               0x1DAC
+
+
+/* This register is written directly and also starts data section in many 3d CP_PACKET3's */
+#define R300_VAP_VF_CNTL       0x2084
+
+#      define  R300_VAP_VF_CNTL__PRIM_TYPE__SHIFT                       0
+#      define  R300_VAP_VF_CNTL__PRIM_NONE                              (0<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_POINTS                            (1<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_LINES                             (2<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_LINE_STRIP                        (3<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_TRIANGLES                         (4<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_TRIANGLE_FAN                      (5<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_TRIANGLE_STRIP                    (6<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_LINE_LOOP                         (12<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_QUADS                             (13<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_QUAD_STRIP                        (14<<0)
+#      define  R300_VAP_VF_CNTL__PRIM_POLYGON                           (15<<0)
+
+#      define  R300_VAP_VF_CNTL__PRIM_WALK__SHIFT                       4
+       /* State based - direct writes to registers trigger vertex generation */
+#      define  R300_VAP_VF_CNTL__PRIM_WALK_STATE_BASED                      (0<<4)
+#      define  R300_VAP_VF_CNTL__PRIM_WALK_INDICES                          (1<<4)
+#      define  R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_LIST                      (2<<4)
+#      define  R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_EMBEDDED                  (3<<4)
+
+               /* I don't think I saw these three used.. */
+#      define  R300_VAP_VF_CNTL__COLOR_ORDER__SHIFT                     6
+#      define  R300_VAP_VF_CNTL__TCL_OUTPUT_CTL_ENA__SHIFT              9
+#      define  R300_VAP_VF_CNTL__PROG_STREAM_ENA__SHIFT                 10
+
+               /* index size - when not set the indices are assumed to be 16 bit */
+#      define  R300_VAP_VF_CNTL__INDEX_SIZE_32bit                      (1<<11)
+                /* number of vertices */
+#      define  R300_VAP_VF_CNTL__NUM_VERTICES__SHIFT                    16
+
+/* BEGIN: Wild guesses */
+#define R300_VAP_OUTPUT_VTX_FMT_0           0x2090
+#       define R300_VAP_OUTPUT_VTX_FMT_0__POS_PRESENT     (1<<0)
+#       define R300_VAP_OUTPUT_VTX_FMT_0__COLOR_PRESENT   (1<<1)
+#       define R300_VAP_OUTPUT_VTX_FMT_0__COLOR_1_PRESENT (1<<2) /* GUESS */
+#       define R300_VAP_OUTPUT_VTX_FMT_0__COLOR_2_PRESENT (1<<3) /* GUESS */
+#       define R300_VAP_OUTPUT_VTX_FMT_0__COLOR_3_PRESENT (1<<4) /* GUESS */
+#       define R300_VAP_OUTPUT_VTX_FMT_0__PT_SIZE_PRESENT (1<<16) /* GUESS */
+
+#define R300_VAP_OUTPUT_VTX_FMT_1           0x2094
+#       define R300_VAP_OUTPUT_VTX_FMT_1__TEX_0_COMP_CNT_SHIFT 0
+#       define R300_VAP_OUTPUT_VTX_FMT_1__TEX_1_COMP_CNT_SHIFT 3
+#       define R300_VAP_OUTPUT_VTX_FMT_1__TEX_2_COMP_CNT_SHIFT 6
+#       define R300_VAP_OUTPUT_VTX_FMT_1__TEX_3_COMP_CNT_SHIFT 9
+#       define R300_VAP_OUTPUT_VTX_FMT_1__TEX_4_COMP_CNT_SHIFT 12
+#       define R300_VAP_OUTPUT_VTX_FMT_1__TEX_5_COMP_CNT_SHIFT 15
+#       define R300_VAP_OUTPUT_VTX_FMT_1__TEX_6_COMP_CNT_SHIFT 18
+#       define R300_VAP_OUTPUT_VTX_FMT_1__TEX_7_COMP_CNT_SHIFT 21
+/* END */
+
+#define R300_SE_VTE_CNTL                  0x20b0
+#      define     R300_VPORT_X_SCALE_ENA                0x00000001
+#      define     R300_VPORT_X_OFFSET_ENA               0x00000002
+#      define     R300_VPORT_Y_SCALE_ENA                0x00000004
+#      define     R300_VPORT_Y_OFFSET_ENA               0x00000008
+#      define     R300_VPORT_Z_SCALE_ENA                0x00000010
+#      define     R300_VPORT_Z_OFFSET_ENA               0x00000020
+#      define     R300_VTX_XY_FMT                       0x00000100
+#      define     R300_VTX_Z_FMT                        0x00000200
+#      define     R300_VTX_W0_FMT                       0x00000400
+#      define     R300_VTX_W0_NORMALIZE                 0x00000800
+#      define     R300_VTX_ST_DENORMALIZED              0x00001000
+
+/* BEGIN: Vertex data assembly - lots of uncertainties */
+/* gap */
+/* Where do we get our vertex data?
+//
+// Vertex data either comes either from immediate mode registers or from
+// vertex arrays.
+// There appears to be no mixed mode (though we can force the pitch of
+// vertex arrays to 0, effectively reusing the same element over and over
+// again).
+//
+// Immediate mode is controlled by the INPUT_CNTL registers. I am not sure
+// if these registers influence vertex array processing.
+//
+// Vertex arrays are controlled via the 3D_LOAD_VBPNTR packet3.
+//
+// In both cases, vertex attributes are then passed through INPUT_ROUTE.
+
+// Beginning with INPUT_ROUTE_0_0 is a list of WORDs that route vertex data
+// into the vertex processor's input registers.
+// The first word routes the first input, the second word the second, etc.
+// The corresponding input is routed into the register with the given index.
+// The list is ended by a word with INPUT_ROUTE_END set.
+//
+// Always set COMPONENTS_4 in immediate mode. */
+
+#define R300_VAP_INPUT_ROUTE_0_0            0x2150
+#       define R300_INPUT_ROUTE_COMPONENTS_1     (0 << 0)
+#       define R300_INPUT_ROUTE_COMPONENTS_2     (1 << 0)
+#       define R300_INPUT_ROUTE_COMPONENTS_3     (2 << 0)
+#       define R300_INPUT_ROUTE_COMPONENTS_4     (3 << 0)
+#       define R300_INPUT_ROUTE_COMPONENTS_RGBA  (4 << 0) /* GUESS */
+#       define R300_VAP_INPUT_ROUTE_IDX_SHIFT    8
+#       define R300_VAP_INPUT_ROUTE_IDX_MASK     (31 << 8) /* GUESS */
+#       define R300_VAP_INPUT_ROUTE_END          (1 << 13)
+#       define R300_INPUT_ROUTE_IMMEDIATE_MODE   (0 << 14) /* GUESS */
+#       define R300_INPUT_ROUTE_FLOAT            (1 << 14) /* GUESS */
+#       define R300_INPUT_ROUTE_UNSIGNED_BYTE    (2 << 14) /* GUESS */
+#       define R300_INPUT_ROUTE_FLOAT_COLOR      (3 << 14) /* GUESS */
+#define R300_VAP_INPUT_ROUTE_0_1            0x2154
+#define R300_VAP_INPUT_ROUTE_0_2            0x2158
+#define R300_VAP_INPUT_ROUTE_0_3            0x215C
+#define R300_VAP_INPUT_ROUTE_0_4            0x2160
+#define R300_VAP_INPUT_ROUTE_0_5            0x2164
+#define R300_VAP_INPUT_ROUTE_0_6            0x2168
+#define R300_VAP_INPUT_ROUTE_0_7            0x216C
+
+/* gap */
+/* Notes:
+//  - always set up to produce at least two attributes:
+//    if vertex program uses only position, fglrx will set normal, too
+//  - INPUT_CNTL_0_COLOR and INPUT_CNTL_COLOR bits are always equal */
+#define R300_VAP_INPUT_CNTL_0               0x2180
+#       define R300_INPUT_CNTL_0_COLOR           0x00000001
+#define R300_VAP_INPUT_CNTL_1               0x2184
+#       define R300_INPUT_CNTL_POS               0x00000001
+#       define R300_INPUT_CNTL_NORMAL            0x00000002
+#       define R300_INPUT_CNTL_COLOR             0x00000004
+#       define R300_INPUT_CNTL_TC0               0x00000400
+#       define R300_INPUT_CNTL_TC1               0x00000800
+#       define R300_INPUT_CNTL_TC2               0x00001000 /* GUESS */
+#       define R300_INPUT_CNTL_TC3               0x00002000 /* GUESS */
+#       define R300_INPUT_CNTL_TC4               0x00004000 /* GUESS */
+#       define R300_INPUT_CNTL_TC5               0x00008000 /* GUESS */
+#       define R300_INPUT_CNTL_TC6               0x00010000 /* GUESS */
+#       define R300_INPUT_CNTL_TC7               0x00020000 /* GUESS */
+
+/* gap */
+/* Words parallel to INPUT_ROUTE_0; All words that are active in INPUT_ROUTE_0
+// are set to a swizzling bit pattern, other words are 0.
+//
+// In immediate mode, the pattern is always set to xyzw. In vertex array
+// mode, the swizzling pattern is e.g. used to set zw components in texture
+// coordinates with only tweo components. */
+#define R300_VAP_INPUT_ROUTE_1_0            0x21E0
+#       define R300_INPUT_ROUTE_SELECT_X    0
+#       define R300_INPUT_ROUTE_SELECT_Y    1
+#       define R300_INPUT_ROUTE_SELECT_Z    2
+#       define R300_INPUT_ROUTE_SELECT_W    3
+#       define R300_INPUT_ROUTE_SELECT_ZERO 4
+#       define R300_INPUT_ROUTE_SELECT_ONE  5
+#       define R300_INPUT_ROUTE_SELECT_MASK 7
+#       define R300_INPUT_ROUTE_X_SHIFT          0
+#       define R300_INPUT_ROUTE_Y_SHIFT          3
+#       define R300_INPUT_ROUTE_Z_SHIFT          6
+#       define R300_INPUT_ROUTE_W_SHIFT          9
+#       define R300_INPUT_ROUTE_ENABLE           (15 << 12)
+#define R300_VAP_INPUT_ROUTE_1_1            0x21E4
+#define R300_VAP_INPUT_ROUTE_1_2            0x21E8
+#define R300_VAP_INPUT_ROUTE_1_3            0x21EC
+#define R300_VAP_INPUT_ROUTE_1_4            0x21F0
+#define R300_VAP_INPUT_ROUTE_1_5            0x21F4
+#define R300_VAP_INPUT_ROUTE_1_6            0x21F8
+#define R300_VAP_INPUT_ROUTE_1_7            0x21FC
+
+/* END */
+
+/* gap */
+/* BEGIN: Upload vertex program and data
+// The programmable vertex shader unit has a memory bank of unknown size
+// that can be written to in 16 byte units by writing the address into
+// UPLOAD_ADDRESS, followed by data in UPLOAD_DATA (multiples of 4 DWORDs).
+//
+// Pointers into the memory bank are always in multiples of 16 bytes.
+//
+// The memory bank is divided into areas with fixed meaning.
+//
+// Starting at address UPLOAD_PROGRAM: Vertex program instructions.
+// Native limits reported by drivers from ATI suggest size 256 (i.e. 4KB),
+// whereas the difference between known addresses suggests size 512.
+//
+// Starting at address UPLOAD_PARAMETERS: Vertex program parameters.
+// Native reported limits and the VPI layout suggest size 256, whereas
+// difference between known addresses suggests size 512.
+//
+// At address UPLOAD_POINTSIZE is a vector (0, 0, ps, 0), where ps is the
+// floating point pointsize. The exact purpose of this state is uncertain,
+// as there is also the R300_RE_POINTSIZE register.
+//
+// Multiple vertex programs and parameter sets can be loaded at once,
+// which could explain the size discrepancy. */
+#define R300_VAP_PVS_UPLOAD_ADDRESS         0x2200
+#       define R300_PVS_UPLOAD_PROGRAM           0x00000000
+#       define R300_PVS_UPLOAD_PARAMETERS        0x00000200
+#       define R300_PVS_UPLOAD_POINTSIZE         0x00000406
+/* gap */
+#define R300_VAP_PVS_UPLOAD_DATA            0x2208
+/* END */
+
+/* gap */
+/* I do not know the purpose of this register. However, I do know that
+// it is set to 221C_CLEAR for clear operations and to 221C_NORMAL
+// for normal rendering. */
+#define R300_VAP_UNKNOWN_221C               0x221C
+#       define R300_221C_NORMAL                  0x00000000
+#       define R300_221C_CLEAR                   0x0001C000
+
+/* gap */
+/* Sometimes, END_OF_PKT and 0x2284=0 are the only commands sent between
+// rendering commands and overwriting vertex program parameters.
+// Therefore, I suspect writing zero to 0x2284 synchronizes the engine and
+// avoids bugs caused by still running shaders reading bad data from memory. */
+#define R300_VAP_PVS_WAITIDLE               0x2284 /* GUESS */
+
+/* Absolutely no clue what this register is about. */
+#define R300_VAP_UNKNOWN_2288               0x2288
+#       define R300_2288_R300                    0x00750000 /* -- nh */
+#       define R300_2288_RV350                   0x0000FFFF /* -- Vladimir */
+
+/* gap */
+/* Addresses are relative to the vertex program instruction area of the
+// memory bank. PROGRAM_END points to the last instruction of the active
+// program
+//
+// The meaning of the two UNKNOWN fields is obviously not known. However,
+// experiments so far have shown that both *must* point to an instruction
+// inside the vertex program, otherwise the GPU locks up.
+// fglrx usually sets CNTL_3_UNKNOWN to the end of the program and
+// CNTL_1_UNKNOWN points to instruction where last write to position takes place. 
+// Most likely this is used to ignore rest of the program in cases where group of verts arent visible.
+// For some reason this "section" is sometimes accepted other instruction that have
+// no relationship with position calculations. 
+*/
+#define R300_VAP_PVS_CNTL_1                 0x22D0
+#       define R300_PVS_CNTL_1_PROGRAM_START_SHIFT   0
+#       define R300_PVS_CNTL_1_POS_END_SHIFT         10
+#       define R300_PVS_CNTL_1_PROGRAM_END_SHIFT     20
+/* Addresses are relative the the vertex program parameters area. */
+#define R300_VAP_PVS_CNTL_2                 0x22D4
+#       define R300_PVS_CNTL_2_PARAM_OFFSET_SHIFT 0
+#       define R300_PVS_CNTL_2_PARAM_COUNT_SHIFT  16
+#define R300_VAP_PVS_CNTL_3               0x22D8
+#       define R300_PVS_CNTL_3_PROGRAM_UNKNOWN_SHIFT 10
+#       define R300_PVS_CNTL_3_PROGRAM_UNKNOWN2_SHIFT 0
+
+/* The entire range from 0x2300 to 0x2AC inclusive seems to be used for
+// immediate vertices */
+#define R300_VAP_VTX_COLOR_R                0x2464
+#define R300_VAP_VTX_COLOR_G                0x2468
+#define R300_VAP_VTX_COLOR_B                0x246C
+#define R300_VAP_VTX_POS_0_X_1              0x2490 /* used for glVertex2*() */
+#define R300_VAP_VTX_POS_0_Y_1              0x2494
+#define R300_VAP_VTX_COLOR_PKD              0x249C /* RGBA */
+#define R300_VAP_VTX_POS_0_X_2              0x24A0 /* used for glVertex3*() */
+#define R300_VAP_VTX_POS_0_Y_2              0x24A4
+#define R300_VAP_VTX_POS_0_Z_2              0x24A8
+#define R300_VAP_VTX_END_OF_PKT             0x24AC /* write 0 to indicate end of packet? */
+
+/* gap */
+
+/* These are values from r300_reg/r300_reg.h - they are known to be correct
+   and are here so we can use one register file instead of several
+   - Vladimir */
+#define R300_GB_VAP_RASTER_VTX_FMT_0   0x4000
+#      define R300_GB_VAP_RASTER_VTX_FMT_0__POS_PRESENT        (1<<0)
+#      define R300_GB_VAP_RASTER_VTX_FMT_0__COLOR_0_PRESENT    (1<<1)
+#      define R300_GB_VAP_RASTER_VTX_FMT_0__COLOR_1_PRESENT    (1<<2)
+#      define R300_GB_VAP_RASTER_VTX_FMT_0__COLOR_2_PRESENT    (1<<3)
+#      define R300_GB_VAP_RASTER_VTX_FMT_0__COLOR_3_PRESENT    (1<<4)
+#      define R300_GB_VAP_RASTER_VTX_FMT_0__COLOR_SPACE        (0xf<<5)
+#      define R300_GB_VAP_RASTER_VTX_FMT_0__PT_SIZE_PRESENT    (0x1<<16)
+
+#define R300_GB_VAP_RASTER_VTX_FMT_1   0x4004
+       /* each of the following is 3 bits wide, specifies number
+          of components */
+#      define R300_GB_VAP_RASTER_VTX_FMT_1__TEX_0_COMP_CNT_SHIFT       0
+#      define R300_GB_VAP_RASTER_VTX_FMT_1__TEX_1_COMP_CNT_SHIFT       3
+#      define R300_GB_VAP_RASTER_VTX_FMT_1__TEX_2_COMP_CNT_SHIFT       6
+#      define R300_GB_VAP_RASTER_VTX_FMT_1__TEX_3_COMP_CNT_SHIFT       9
+#      define R300_GB_VAP_RASTER_VTX_FMT_1__TEX_4_COMP_CNT_SHIFT       12
+#      define R300_GB_VAP_RASTER_VTX_FMT_1__TEX_5_COMP_CNT_SHIFT       15
+#      define R300_GB_VAP_RASTER_VTX_FMT_1__TEX_6_COMP_CNT_SHIFT       18
+#      define R300_GB_VAP_RASTER_VTX_FMT_1__TEX_7_COMP_CNT_SHIFT       21
+
+/* UNK30 seems to enables point to quad transformation on textures
+   (or something closely related to that).
+   This bit is rather fatal at the time being due to lackings at pixel shader side */
+#define R300_GB_ENABLE 0x4008
+#      define R300_GB_POINT_STUFF_ENABLE       (1<<0)
+#      define R300_GB_LINE_STUFF_ENABLE        (1<<1)
+#      define R300_GB_TRIANGLE_STUFF_ENABLE    (1<<2)
+#      define R300_GB_STENCIL_AUTO_ENABLE      (1<<4)
+#      define R300_GB_UNK30                    (1<<30)
+       /* each of the following is 2 bits wide */
+#define R300_GB_TEX_REPLICATE  0
+#define R300_GB_TEX_ST         1
+#define R300_GB_TEX_STR                2
+#      define R300_GB_TEX0_SOURCE_SHIFT        16
+#      define R300_GB_TEX1_SOURCE_SHIFT        18
+#      define R300_GB_TEX2_SOURCE_SHIFT        20
+#      define R300_GB_TEX3_SOURCE_SHIFT        22
+#      define R300_GB_TEX4_SOURCE_SHIFT        24
+#      define R300_GB_TEX5_SOURCE_SHIFT        26
+#      define R300_GB_TEX6_SOURCE_SHIFT        28
+#      define R300_GB_TEX7_SOURCE_SHIFT        30
+
+/* MSPOS - positions for multisample antialiasing (?) */
+#define R300_GB_MSPOS0 0x4010
+       /* shifts - each of the fields is 4 bits */
+#      define R300_GB_MSPOS0__MS_X0_SHIFT      0
+#      define R300_GB_MSPOS0__MS_Y0_SHIFT      4
+#      define R300_GB_MSPOS0__MS_X1_SHIFT      8
+#      define R300_GB_MSPOS0__MS_Y1_SHIFT      12
+#      define R300_GB_MSPOS0__MS_X2_SHIFT      16
+#      define R300_GB_MSPOS0__MS_Y2_SHIFT      20
+#      define R300_GB_MSPOS0__MSBD0_Y          24
+#      define R300_GB_MSPOS0__MSBD0_X          28
+
+#define R300_GB_MSPOS1 0x4014
+#      define R300_GB_MSPOS1__MS_X3_SHIFT      0
+#      define R300_GB_MSPOS1__MS_Y3_SHIFT      4
+#      define R300_GB_MSPOS1__MS_X4_SHIFT      8
+#      define R300_GB_MSPOS1__MS_Y4_SHIFT      12
+#      define R300_GB_MSPOS1__MS_X5_SHIFT      16
+#      define R300_GB_MSPOS1__MS_Y5_SHIFT      20
+#      define R300_GB_MSPOS1__MSBD1            24
+
+
+#define R300_GB_TILE_CONFIG    0x4018
+#      define R300_GB_TILE_ENABLE      (1<<0)
+#      define R300_GB_TILE_PIPE_COUNT_RV300    0
+#      define R300_GB_TILE_PIPE_COUNT_R300     (3<<1)
+#      define R300_GB_TILE_PIPE_COUNT_R420     (7<<1)
+#      define R300_GB_TILE_SIZE_8              0
+#      define R300_GB_TILE_SIZE_16             (1<<4)
+#      define R300_GB_TILE_SIZE_32             (2<<4)
+#      define R300_GB_SUPER_SIZE_1             (0<<6)
+#      define R300_GB_SUPER_SIZE_2             (1<<6)
+#      define R300_GB_SUPER_SIZE_4             (2<<6)
+#      define R300_GB_SUPER_SIZE_8             (3<<6)
+#      define R300_GB_SUPER_SIZE_16            (4<<6)
+#      define R300_GB_SUPER_SIZE_32            (5<<6)
+#      define R300_GB_SUPER_SIZE_64            (6<<6)
+#      define R300_GB_SUPER_SIZE_128           (7<<6)
+#      define R300_GB_SUPER_X_SHIFT            9       /* 3 bits wide */
+#      define R300_GB_SUPER_Y_SHIFT            12      /* 3 bits wide */
+#      define R300_GB_SUPER_TILE_A             0
+#      define R300_GB_SUPER_TILE_B             (1<<15)
+#      define R300_GB_SUBPIXEL_1_12            0
+#      define R300_GB_SUBPIXEL_1_16            (1<<16)
+
+#define R300_GB_FIFO_SIZE      0x4024
+       /* each of the following is 2 bits wide */
+#define R300_GB_FIFO_SIZE_32   0
+#define R300_GB_FIFO_SIZE_64   1
+#define R300_GB_FIFO_SIZE_128  2
+#define R300_GB_FIFO_SIZE_256  3
+#      define R300_SC_IFIFO_SIZE_SHIFT 0
+#      define R300_SC_TZFIFO_SIZE_SHIFT        2
+#      define R300_SC_BFIFO_SIZE_SHIFT 4
+
+#      define R300_US_OFIFO_SIZE_SHIFT 12
+#      define R300_US_WFIFO_SIZE_SHIFT 14
+       /* the following use the same constants as above, but meaning is
+          is times 2 (i.e. instead of 32 words it means 64 */
+#      define R300_RS_TFIFO_SIZE_SHIFT 6
+#      define R300_RS_CFIFO_SIZE_SHIFT 8
+#      define R300_US_RAM_SIZE_SHIFT           10
+       /* watermarks, 3 bits wide */
+#      define R300_RS_HIGHWATER_COL_SHIFT      16
+#      define R300_RS_HIGHWATER_TEX_SHIFT      19
+#      define R300_OFIFO_HIGHWATER_SHIFT       22      /* two bits only */
+#      define R300_CUBE_FIFO_HIGHWATER_COL_SHIFT       24
+
+#define R300_GB_SELECT 0x401C
+#      define R300_GB_FOG_SELECT_C0A           0
+#      define R300_GB_FOG_SELECT_C1A           1
+#      define R300_GB_FOG_SELECT_C2A           2
+#      define R300_GB_FOG_SELECT_C3A           3
+#      define R300_GB_FOG_SELECT_1_1_W 4
+#      define R300_GB_FOG_SELECT_Z             5
+#      define R300_GB_DEPTH_SELECT_Z           0
+#      define R300_GB_DEPTH_SELECT_1_1_W       (1<<3)
+#      define R300_GB_W_SELECT_1_W             0
+#      define R300_GB_W_SELECT_1               (1<<4)
+
+#define R300_GB_AA_CONFIG              0x4020
+#      define R300_AA_ENABLE                   0x01
+#      define R300_AA_SUBSAMPLES_2             0
+#      define R300_AA_SUBSAMPLES_3             (1<<1)
+#      define R300_AA_SUBSAMPLES_4             (2<<1)
+#      define R300_AA_SUBSAMPLES_6             (3<<1)
+
+/* END */
+
+/* gap */
+/* The upper enable bits are guessed, based on fglrx reported limits. */
+#define R300_TX_ENABLE                      0x4104
+#       define R300_TX_ENABLE_0                  (1 << 0)
+#       define R300_TX_ENABLE_1                  (1 << 1)
+#       define R300_TX_ENABLE_2                  (1 << 2)
+#       define R300_TX_ENABLE_3                  (1 << 3)
+#       define R300_TX_ENABLE_4                  (1 << 4)
+#       define R300_TX_ENABLE_5                  (1 << 5)
+#       define R300_TX_ENABLE_6                  (1 << 6)
+#       define R300_TX_ENABLE_7                  (1 << 7)
+#       define R300_TX_ENABLE_8                  (1 << 8)
+#       define R300_TX_ENABLE_9                  (1 << 9)
+#       define R300_TX_ENABLE_10                 (1 << 10)
+#       define R300_TX_ENABLE_11                 (1 << 11)
+#       define R300_TX_ENABLE_12                 (1 << 12)
+#       define R300_TX_ENABLE_13                 (1 << 13)
+#       define R300_TX_ENABLE_14                 (1 << 14)
+#       define R300_TX_ENABLE_15                 (1 << 15)
+
+/* The pointsize is given in multiples of 6. The pointsize can be
+// enormous: Clear() renders a single point that fills the entire
+// framebuffer. */
+#define R300_RE_POINTSIZE                   0x421C
+#       define R300_POINTSIZE_Y_SHIFT            0
+#       define R300_POINTSIZE_Y_MASK             (0xFFFF << 0) /* GUESS */
+#       define R300_POINTSIZE_X_SHIFT            16
+#       define R300_POINTSIZE_X_MASK             (0xFFFF << 16) /* GUESS */
+#       define R300_POINTSIZE_MAX             (R300_POINTSIZE_Y_MASK / 6)
+
+/* The line width is given in multiples of 6.
+   In default mode lines are classified as vertical lines.
+   HO: horizontal
+   VE: vertical or horizontal
+   HO & VE: no classification
+*/
+#define R300_RE_LINE_CNT                      0x4234
+#       define R300_LINESIZE_SHIFT            0
+#       define R300_LINESIZE_MASK             (0xFFFF << 0) /* GUESS */
+#       define R300_LINESIZE_MAX             (R300_LINESIZE_MASK / 6)
+#       define R300_LINE_CNT_HO               (1 << 16)
+#       define R300_LINE_CNT_VE               (1 << 17)
+
+/* Some sort of scale or clamp value for texcoordless textures. */
+#define R300_RE_UNK4238                       0x4238
+
+#define R300_RE_SHADE_MODEL                   0x4278
+#      define R300_RE_SHADE_MODEL_SMOOTH     0x3aaaa
+#      define R300_RE_SHADE_MODEL_FLAT       0x39595
+
+/* Dangerous */
+#define R300_RE_POLYGON_MODE                  0x4288
+#      define R300_PM_ENABLED                (1 << 0)
+#      define R300_PM_FRONT_POINT            (0 << 0)
+#      define R300_PM_BACK_POINT             (0 << 0)
+#      define R300_PM_FRONT_LINE             (1 << 4)
+#      define R300_PM_FRONT_FILL             (1 << 5)
+#      define R300_PM_BACK_LINE              (1 << 7)
+#      define R300_PM_BACK_FILL              (1 << 8)
+
+/* Not sure why there are duplicate of factor and constant values. 
+   My best guess so far is that there are seperate zbiases for test and write. 
+   Ordering might be wrong.
+   Some of the tests indicate that fgl has a fallback implementation of zbias
+   via pixel shaders. */
+#define R300_RE_ZBIAS_T_FACTOR                0x42A4
+#define R300_RE_ZBIAS_T_CONSTANT              0x42A8
+#define R300_RE_ZBIAS_W_FACTOR                0x42AC
+#define R300_RE_ZBIAS_W_CONSTANT              0x42B0
+
+/* This register needs to be set to (1<<1) for RV350 to correctly
+   perform depth test (see --vb-triangles in r300_demo)
+   Don't know about other chips. - Vladimir
+   This is set to 3 when GL_POLYGON_OFFSET_FILL is on.
+   My guess is that there are two bits for each zbias primitive (FILL, LINE, POINT).
+   One to enable depth test and one for depth write.
+   Yet this doesnt explain why depth writes work ...
+    */
+#define R300_RE_OCCLUSION_CNTL             0x42B4
+#      define R300_OCCLUSION_ON                (1<<1)
+
+#define R300_RE_CULL_CNTL                   0x42B8
+#       define R300_CULL_FRONT                   (1 << 0)
+#       define R300_CULL_BACK                    (1 << 1)
+#       define R300_FRONT_FACE_CCW               (0 << 2)
+#       define R300_FRONT_FACE_CW                (1 << 2)
+
+
+/* BEGIN: Rasterization / Interpolators - many guesses
+// 0_UNKNOWN_18 has always been set except for clear operations.
+// TC_CNT is the number of incoming texture coordinate sets (i.e. it depends
+// on the vertex program, *not* the fragment program) */
+#define R300_RS_CNTL_0                      0x4300
+#       define R300_RS_CNTL_TC_CNT_SHIFT         2
+#       define R300_RS_CNTL_TC_CNT_MASK          (7 << 2)
+#              define R300_RS_CNTL_CI_CNT_SHIFT         7 /* number of color interpolators used */
+#       define R300_RS_CNTL_0_UNKNOWN_18         (1 << 18)
+/* Guess: RS_CNTL_1 holds the index of the highest used RS_ROUTE_n register. */
+#define R300_RS_CNTL_1                      0x4304
+
+/* gap */
+/* Only used for texture coordinates.
+// Use the source field to route texture coordinate input from the vertex program
+// to the desired interpolator. Note that the source field is relative to the
+// outputs the vertex program *actually* writes. If a vertex program only writes
+// texcoord[1], this will be source index 0.
+// Set INTERP_USED on all interpolators that produce data used by the
+// fragment program. INTERP_USED looks like a swizzling mask, but
+// I haven't seen it used that way.
+//
+// Note: The _UNKNOWN constants are always set in their respective register.
+// I don't know if this is necessary. */
+#define R300_RS_INTERP_0                    0x4310
+#define R300_RS_INTERP_1                    0x4314
+#       define R300_RS_INTERP_1_UNKNOWN          0x40
+#define R300_RS_INTERP_2                    0x4318
+#       define R300_RS_INTERP_2_UNKNOWN          0x80
+#define R300_RS_INTERP_3                    0x431C
+#       define R300_RS_INTERP_3_UNKNOWN          0xC0
+#define R300_RS_INTERP_4                    0x4320
+#define R300_RS_INTERP_5                    0x4324
+#define R300_RS_INTERP_6                    0x4328
+#define R300_RS_INTERP_7                    0x432C
+#       define R300_RS_INTERP_SRC_SHIFT          2
+#       define R300_RS_INTERP_SRC_MASK           (7 << 2)
+#       define R300_RS_INTERP_USED               0x00D10000
+
+/* These DWORDs control how vertex data is routed into fragment program
+// registers, after interpolators. */
+#define R300_RS_ROUTE_0                     0x4330
+#define R300_RS_ROUTE_1                     0x4334
+#define R300_RS_ROUTE_2                     0x4338
+#define R300_RS_ROUTE_3                     0x433C /* GUESS */
+#define R300_RS_ROUTE_4                     0x4340 /* GUESS */
+#define R300_RS_ROUTE_5                     0x4344 /* GUESS */
+#define R300_RS_ROUTE_6                     0x4348 /* GUESS */
+#define R300_RS_ROUTE_7                     0x434C /* GUESS */
+#       define R300_RS_ROUTE_SOURCE_INTERP_0     0
+#       define R300_RS_ROUTE_SOURCE_INTERP_1     1
+#       define R300_RS_ROUTE_SOURCE_INTERP_2     2
+#       define R300_RS_ROUTE_SOURCE_INTERP_3     3
+#       define R300_RS_ROUTE_SOURCE_INTERP_4     4
+#       define R300_RS_ROUTE_SOURCE_INTERP_5     5 /* GUESS */
+#       define R300_RS_ROUTE_SOURCE_INTERP_6     6 /* GUESS */
+#       define R300_RS_ROUTE_SOURCE_INTERP_7     7 /* GUESS */
+#       define R300_RS_ROUTE_ENABLE              (1 << 3) /* GUESS */
+#       define R300_RS_ROUTE_DEST_SHIFT          6
+#       define R300_RS_ROUTE_DEST_MASK           (31 << 6) /* GUESS */
+
+/* Special handling for color: When the fragment program uses color,
+// the ROUTE_0_COLOR bit is set and ROUTE_0_COLOR_DEST contains the
+// color register index. */
+#       define R300_RS_ROUTE_0_COLOR             (1 << 14)
+#       define R300_RS_ROUTE_0_COLOR_DEST_SHIFT  17
+#       define R300_RS_ROUTE_0_COLOR_DEST_MASK   (31 << 17) /* GUESS */
+/* As above, but for secondary color */
+#              define R300_RS_ROUTE_1_COLOR1            (1 << 14)
+#              define R300_RS_ROUTE_1_COLOR1_DEST_SHIFT 17
+#              define R300_RS_ROUTE_1_COLOR1_DEST_MASK  (31 << 17)
+#              define R300_RS_ROUTE_1_UNKNOWN11         (1 << 11)
+/* END */
+
+/* BEGIN: Scissors and cliprects
+// There are four clipping rectangles. Their corner coordinates are inclusive.
+// Every pixel is assigned a number from 0 and 15 by setting bits 0-3 depending
+// on whether the pixel is inside cliprects 0-3, respectively. For example,
+// if a pixel is inside cliprects 0 and 1, but outside 2 and 3, it is assigned
+// the number 3 (binary 0011).
+// Iff the bit corresponding to the pixel's number in RE_CLIPRECT_CNTL is set,
+// the pixel is rasterized.
+//
+// In addition to this, there is a scissors rectangle. Only pixels inside the
+// scissors rectangle are drawn. (coordinates are inclusive)
+//
+// For some reason, the top-left corner of the framebuffer is at (1440, 1440)
+// for the purpose of clipping and scissors. */
+#define R300_RE_CLIPRECT_TL_0               0x43B0
+#define R300_RE_CLIPRECT_BR_0               0x43B4
+#define R300_RE_CLIPRECT_TL_1               0x43B8
+#define R300_RE_CLIPRECT_BR_1               0x43BC
+#define R300_RE_CLIPRECT_TL_2               0x43C0
+#define R300_RE_CLIPRECT_BR_2               0x43C4
+#define R300_RE_CLIPRECT_TL_3               0x43C8
+#define R300_RE_CLIPRECT_BR_3               0x43CC
+#       define R300_CLIPRECT_OFFSET              1440
+#       define R300_CLIPRECT_MASK                0x1FFF
+#       define R300_CLIPRECT_X_SHIFT             0
+#       define R300_CLIPRECT_X_MASK              (0x1FFF << 0)
+#       define R300_CLIPRECT_Y_SHIFT             13
+#       define R300_CLIPRECT_Y_MASK              (0x1FFF << 13)
+#define R300_RE_CLIPRECT_CNTL               0x43D0
+#       define R300_CLIP_OUT                     (1 << 0)
+#       define R300_CLIP_0                       (1 << 1)
+#       define R300_CLIP_1                       (1 << 2)
+#       define R300_CLIP_10                      (1 << 3)
+#       define R300_CLIP_2                       (1 << 4)
+#       define R300_CLIP_20                      (1 << 5)
+#       define R300_CLIP_21                      (1 << 6)
+#       define R300_CLIP_210                     (1 << 7)
+#       define R300_CLIP_3                       (1 << 8)
+#       define R300_CLIP_30                      (1 << 9)
+#       define R300_CLIP_31                      (1 << 10)
+#       define R300_CLIP_310                     (1 << 11)
+#       define R300_CLIP_32                      (1 << 12)
+#       define R300_CLIP_320                     (1 << 13)
+#       define R300_CLIP_321                     (1 << 14)
+#       define R300_CLIP_3210                    (1 << 15)
+
+/* gap */
+#define R300_RE_SCISSORS_TL                 0x43E0
+#define R300_RE_SCISSORS_BR                 0x43E4
+#       define R300_SCISSORS_OFFSET              1440
+#       define R300_SCISSORS_X_SHIFT             0
+#       define R300_SCISSORS_X_MASK              (0x1FFF << 0)
+#       define R300_SCISSORS_Y_SHIFT             13
+#       define R300_SCISSORS_Y_MASK              (0x1FFF << 13)
+/* END */
+
+/* BEGIN: Texture specification
+// The texture specification dwords are grouped by meaning and not by texture unit.
+// This means that e.g. the offset for texture image unit N is found in register
+// TX_OFFSET_0 + (4*N) */
+#define R300_TX_FILTER_0                    0x4400
+#       define R300_TX_REPEAT                    0
+#       define R300_TX_MIRRORED                  1
+#       define R300_TX_CLAMP                     4
+#       define R300_TX_CLAMP_TO_EDGE             2
+#       define R300_TX_CLAMP_TO_BORDER           6
+#       define R300_TX_WRAP_S_SHIFT              0
+#       define R300_TX_WRAP_S_MASK               (7 << 0)
+#       define R300_TX_WRAP_T_SHIFT              3
+#       define R300_TX_WRAP_T_MASK               (7 << 3)
+#       define R300_TX_WRAP_Q_SHIFT              6
+#       define R300_TX_WRAP_Q_MASK               (7 << 6)
+#       define R300_TX_MAG_FILTER_NEAREST        (1 << 9)
+#       define R300_TX_MAG_FILTER_LINEAR         (2 << 9)
+#       define R300_TX_MAG_FILTER_MASK           (3 << 9)
+#       define R300_TX_MIN_FILTER_NEAREST        (1 << 11)
+#       define R300_TX_MIN_FILTER_LINEAR         (2 << 11)
+#      define R300_TX_MIN_FILTER_NEAREST_MIP_NEAREST       (5  <<  11)
+#      define R300_TX_MIN_FILTER_NEAREST_MIP_LINEAR        (9  <<  11)
+#      define R300_TX_MIN_FILTER_LINEAR_MIP_NEAREST        (6  <<  11)
+#      define R300_TX_MIN_FILTER_LINEAR_MIP_LINEAR         (10 <<  11)
+
+/* NOTE: NEAREST doesnt seem to exist.
+   Im not seting MAG_FILTER_MASK and (3 << 11) on for all
+   anisotropy modes because that would void selected mag filter */
+#      define R300_TX_MIN_FILTER_ANISO_NEAREST             ((0 << 13) /*|R300_TX_MAG_FILTER_MASK|(3<<11)*/)
+#      define R300_TX_MIN_FILTER_ANISO_LINEAR              ((0 << 13) /*|R300_TX_MAG_FILTER_MASK|(3<<11)*/)
+#      define R300_TX_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST ((1 << 13) /*|R300_TX_MAG_FILTER_MASK|(3<<11)*/)
+#      define R300_TX_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR  ((2 << 13) /*|R300_TX_MAG_FILTER_MASK|(3<<11)*/)
+#       define R300_TX_MIN_FILTER_MASK           ( (15 << 11) | (3 << 13) )
+#      define R300_TX_MAX_ANISO_1_TO_1  (0 << 21)
+#      define R300_TX_MAX_ANISO_2_TO_1  (2 << 21)
+#      define R300_TX_MAX_ANISO_4_TO_1  (4 << 21)
+#      define R300_TX_MAX_ANISO_8_TO_1  (6 << 21)
+#      define R300_TX_MAX_ANISO_16_TO_1 (8 << 21)
+#      define R300_TX_MAX_ANISO_MASK    (14 << 21)
+
+#define R300_TX_UNK1_0                      0x4440
+#      define R300_LOD_BIAS_MASK           0x1fff
+
+#define R300_TX_SIZE_0                      0x4480
+#       define R300_TX_WIDTHMASK_SHIFT           0
+#       define R300_TX_WIDTHMASK_MASK            (2047 << 0)
+#       define R300_TX_HEIGHTMASK_SHIFT          11
+#       define R300_TX_HEIGHTMASK_MASK           (2047 << 11)
+#       define R300_TX_UNK23                     (1 << 23)
+#       define R300_TX_SIZE_SHIFT                26 /* largest of width, height */
+#       define R300_TX_SIZE_MASK                 (15 << 26)
+#define R300_TX_FORMAT_0                    0x44C0
+       /* The interpretation of the format word by Wladimir van der Laan */
+       /* The X, Y, Z and W refer to the layout of the components.
+          They are given meanings as R, G, B and Alpha by the swizzle
+          specification */
+#      define R300_TX_FORMAT_X8                    0x0
+#      define R300_TX_FORMAT_X16                   0x1
+#      define R300_TX_FORMAT_Y4X4                  0x2
+#      define R300_TX_FORMAT_Y8X8                  0x3
+#      define R300_TX_FORMAT_Y16X16                0x4
+#      define R300_TX_FORMAT_Z3Y3X2                0x5
+#      define R300_TX_FORMAT_Z5Y6X5                0x6
+#      define R300_TX_FORMAT_Z6Y5X5                0x7
+#      define R300_TX_FORMAT_Z11Y11X10             0x8
+#      define R300_TX_FORMAT_Z10Y11X11             0x9
+#      define R300_TX_FORMAT_W4Z4Y4X4              0xA
+#      define R300_TX_FORMAT_W1Z5Y5X5              0xB
+#      define R300_TX_FORMAT_W8Z8Y8X8              0xC
+#      define R300_TX_FORMAT_W2Z10Y10X10           0xD
+#      define R300_TX_FORMAT_W16Z16Y16X16          0xE
+#      define R300_TX_FORMAT_DXT1                  0xF
+#      define R300_TX_FORMAT_DXT3                  0x10
+#      define R300_TX_FORMAT_DXT5                  0x11
+#      define R300_TX_FORMAT_D3DMFT_CxV8U8         0x12     /* no swizzle */
+#      define R300_TX_FORMAT_A8R8G8B8              0x13     /* no swizzle */
+#      define R300_TX_FORMAT_B8G8_B8G8             0x14     /* no swizzle */
+#      define R300_TX_FORMAT_G8R8_G8B8             0x15     /* no swizzle */
+                                                 /* 0x16 - some 16 bit green format.. ?? */
+#      define R300_TX_FORMAT_UNK25                (1 << 25) /* no swizzle */
+
+       /* gap */
+       /* Floating point formats */
+       /* Note - hardware supports both 16 and 32 bit floating point */
+#      define R300_TX_FORMAT_FL_I16                0x18
+#      define R300_TX_FORMAT_FL_I16A16             0x19
+#      define R300_TX_FORMAT_FL_R16G16B16A16       0x1A
+#      define R300_TX_FORMAT_FL_I32                0x1B
+#      define R300_TX_FORMAT_FL_I32A32             0x1C
+#      define R300_TX_FORMAT_FL_R32G32B32A32       0x1D
+       /* alpha modes, convenience mostly */
+       /* if you have alpha, pick constant appropriate to the
+          number of channels (1 for I8, 2 for I8A8, 4 for R8G8B8A8, etc */
+#      define R300_TX_FORMAT_ALPHA_1CH             0x000
+#      define R300_TX_FORMAT_ALPHA_2CH             0x200
+#      define R300_TX_FORMAT_ALPHA_4CH             0x600
+#      define R300_TX_FORMAT_ALPHA_NONE            0xA00
+       /* Swizzling */
+       /* constants */
+#      define R300_TX_FORMAT_X         0
+#      define R300_TX_FORMAT_Y         1
+#      define R300_TX_FORMAT_Z         2
+#      define R300_TX_FORMAT_W         3
+#      define R300_TX_FORMAT_ZERO      4
+#      define R300_TX_FORMAT_ONE       5
+#      define R300_TX_FORMAT_CUT_Z     6               /* 2.0*Z, everything above 1.0 is set to 0.0 */
+#      define R300_TX_FORMAT_CUT_W     7               /* 2.0*W, everything above 1.0 is set to 0.0 */
+
+#      define R300_TX_FORMAT_B_SHIFT   18
+#      define R300_TX_FORMAT_G_SHIFT   15
+#      define R300_TX_FORMAT_R_SHIFT   12
+#      define R300_TX_FORMAT_A_SHIFT   9
+       /* Convenience macro to take care of layout and swizzling */
+#      define R300_EASY_TX_FORMAT(B, G, R, A, FMT)     (\
+         ((R300_TX_FORMAT_##B)<<R300_TX_FORMAT_B_SHIFT) \
+       | ((R300_TX_FORMAT_##G)<<R300_TX_FORMAT_G_SHIFT) \
+       | ((R300_TX_FORMAT_##R)<<R300_TX_FORMAT_R_SHIFT) \
+       | ((R300_TX_FORMAT_##A)<<R300_TX_FORMAT_A_SHIFT) \
+       | (R300_TX_FORMAT_##FMT) \
+         )
+       /* These can be ORed with result of R300_EASY_TX_FORMAT() */
+       /* We don't really know what they do. Take values from a constant color ? */
+#      define R300_TX_FORMAT_CONST_X           (1<<5)
+#      define R300_TX_FORMAT_CONST_Y           (2<<5)
+#      define R300_TX_FORMAT_CONST_Z           (4<<5)
+#      define R300_TX_FORMAT_CONST_W           (8<<5)
+
+#      define R300_TX_FORMAT_YUV_MODE          0x00800000
+
+#define R300_TX_OFFSET_0                    0x4540
+/* BEGIN: Guess from R200 */
+#       define R300_TXO_ENDIAN_NO_SWAP           (0 << 0)
+#       define R300_TXO_ENDIAN_BYTE_SWAP         (1 << 0)
+#       define R300_TXO_ENDIAN_WORD_SWAP         (2 << 0)
+#       define R300_TXO_ENDIAN_HALFDW_SWAP       (3 << 0)
+#       define R300_TXO_OFFSET_MASK              0xffffffe0
+#       define R300_TXO_OFFSET_SHIFT             5
+/* END */
+#define R300_TX_UNK4_0                      0x4580
+#define R300_TX_BORDER_COLOR_0              0x45C0 //ff00ff00 == { 0, 1.0, 0, 1.0 }
+
+/* END */
+
+/* BEGIN: Fragment program instruction set
+// Fragment programs are written directly into register space.
+// There are separate instruction streams for texture instructions and ALU
+// instructions.
+// In order to synchronize these streams, the program is divided into up
+// to 4 nodes. Each node begins with a number of TEX operations, followed
+// by a number of ALU operations.
+// The first node can have zero TEX ops, all subsequent nodes must have at least
+// one TEX ops.
+// All nodes must have at least one ALU op.
+//
+// The index of the last node is stored in PFS_CNTL_0: A value of 0 means
+// 1 node, a value of 3 means 4 nodes.
+// The total amount of instructions is defined in PFS_CNTL_2. The offsets are
+// offsets into the respective instruction streams, while *_END points to the
+// last instruction relative to this offset. */
+#define R300_PFS_CNTL_0                     0x4600
+#       define R300_PFS_CNTL_LAST_NODES_SHIFT    0
+#       define R300_PFS_CNTL_LAST_NODES_MASK     (3 << 0)
+#       define R300_PFS_CNTL_FIRST_NODE_HAS_TEX  (1 << 3)
+#define R300_PFS_CNTL_1                     0x4604
+/* There is an unshifted value here which has so far always been equal to the
+// index of the highest used temporary register. */
+#define R300_PFS_CNTL_2                     0x4608
+#       define R300_PFS_CNTL_ALU_OFFSET_SHIFT    0
+#       define R300_PFS_CNTL_ALU_OFFSET_MASK     (63 << 0)
+#       define R300_PFS_CNTL_ALU_END_SHIFT       6
+#       define R300_PFS_CNTL_ALU_END_MASK        (63 << 0)
+#       define R300_PFS_CNTL_TEX_OFFSET_SHIFT    12
+#       define R300_PFS_CNTL_TEX_OFFSET_MASK     (31 << 12) /* GUESS */
+#       define R300_PFS_CNTL_TEX_END_SHIFT       18
+#       define R300_PFS_CNTL_TEX_END_MASK        (31 << 18) /* GUESS */
+
+/* gap */
+/* Nodes are stored backwards. The last active node is always stored in
+// PFS_NODE_3.
+// Example: In a 2-node program, NODE_0 and NODE_1 are set to 0. The
+// first node is stored in NODE_2, the second node is stored in NODE_3.
+//
+// Offsets are relative to the master offset from PFS_CNTL_2.
+// LAST_NODE is set for the last node, and only for the last node. */
+#define R300_PFS_NODE_0                     0x4610
+#define R300_PFS_NODE_1                     0x4614
+#define R300_PFS_NODE_2                     0x4618
+#define R300_PFS_NODE_3                     0x461C
+#       define R300_PFS_NODE_ALU_OFFSET_SHIFT    0
+#       define R300_PFS_NODE_ALU_OFFSET_MASK     (63 << 0)
+#       define R300_PFS_NODE_ALU_END_SHIFT       6
+#       define R300_PFS_NODE_ALU_END_MASK        (63 << 6)
+#       define R300_PFS_NODE_TEX_OFFSET_SHIFT    12
+#       define R300_PFS_NODE_TEX_OFFSET_MASK     (31 << 12)
+#       define R300_PFS_NODE_TEX_END_SHIFT       17
+#       define R300_PFS_NODE_TEX_END_MASK        (31 << 17)
+#       define R300_PFS_NODE_LAST_NODE           (1 << 22)
+
+/* TEX
+// As far as I can tell, texture instructions cannot write into output
+// registers directly. A subsequent ALU instruction is always necessary,
+// even if it's just MAD o0, r0, 1, 0 */
+#define R300_PFS_TEXI_0                     0x4620
+#       define R300_FPITX_SRC_SHIFT              0
+#       define R300_FPITX_SRC_MASK               (31 << 0)
+#       define R300_FPITX_SRC_CONST              (1 << 5) /* GUESS */
+#       define R300_FPITX_DST_SHIFT              6
+#       define R300_FPITX_DST_MASK               (31 << 6)
+#       define R300_FPITX_IMAGE_SHIFT            11
+#       define R300_FPITX_IMAGE_MASK             (15 << 11) /* GUESS based on layout and native limits */
+/* Unsure if these are opcodes, or some kind of bitfield, but this is how
+ * they were set when I checked
+ */
+#              define R300_FPITX_OPCODE_SHIFT                  15
+#                      define R300_FPITX_OP_TEX                        1
+#                      define R300_FPITX_OP_TXP                        3
+#                      define R300_FPITX_OP_TXB                        4
+
+/* ALU
+// The ALU instructions register blocks are enumerated according to the order
+// in which fglrx. I assume there is space for 64 instructions, since
+// each block has space for a maximum of 64 DWORDs, and this matches reported
+// native limits.
+//
+// The basic functional block seems to be one MAD for each color and alpha,
+// and an adder that adds all components after the MUL.
+//  - ADD, MUL, MAD etc.: use MAD with appropriate neutral operands
+//  - DP4: Use OUTC_DP4, OUTA_DP4
+//  - DP3: Use OUTC_DP3, OUTA_DP4, appropriate alpha operands
+//  - DPH: Use OUTC_DP4, OUTA_DP4, appropriate alpha operands
+//  - CMP: If ARG2 < 0, return ARG1, else return ARG0
+//  - FLR: use FRC+MAD
+//  - XPD: use MAD+MAD
+//  - SGE, SLT: use MAD+CMP
+//  - RSQ: use ABS modifier for argument
+//  - Use OUTC_REPL_ALPHA to write results of an alpha-only operation (e.g. RCP)
+//    into color register
+//  - apparently, there's no quick DST operation
+//  - fglrx set FPI2_UNKNOWN_31 on a "MAD fragment.color, tmp0, tmp1, tmp2"
+//  - fglrx set FPI2_UNKNOWN_31 on a "MAX r2, r1, c0"
+//  - fglrx once set FPI0_UNKNOWN_31 on a "FRC r1, r1"
+//
+// Operand selection
+// First stage selects three sources from the available registers and
+// constant parameters. This is defined in INSTR1 (color) and INSTR3 (alpha).
+// fglrx sorts the three source fields: Registers before constants,
+// lower indices before higher indices; I do not know whether this is necessary.
+// fglrx fills unused sources with "read constant 0"
+// According to specs, you cannot select more than two different constants.
+//
+// Second stage selects the operands from the sources. This is defined in
+// INSTR0 (color) and INSTR2 (alpha). You can also select the special constants
+// zero and one.
+// Swizzling and negation happens in this stage, as well.
+//
+// Important: Color and alpha seem to be mostly separate, i.e. their sources
+// selection appears to be fully independent (the register storage is probably
+// physically split into a color and an alpha section).
+// However (because of the apparent physical split), there is some interaction
+// WRT swizzling. If, for example, you want to load an R component into an
+// Alpha operand, this R component is taken from a *color* source, not from
+// an alpha source. The corresponding register doesn't even have to appear in
+// the alpha sources list. (I hope this alll makes sense to you)
+//
+// Destination selection
+// The destination register index is in FPI1 (color) and FPI3 (alpha) together
+// with enable bits.
+// There are separate enable bits for writing into temporary registers
+// (DSTC_REG_* /DSTA_REG) and and program output registers (DSTC_OUTPUT_* /DSTA_OUTPUT).
+// You can write to both at once, or not write at all (the same index
+// must be used for both).
+//
+// Note: There is a special form for LRP
+//  - Argument order is the same as in ARB_fragment_program.
+//  - Operation is MAD
+//  - ARG1 is set to ARGC_SRC1C_LRP/ARGC_SRC1A_LRP
+//  - Set FPI0/FPI2_SPECIAL_LRP
+// Arbitrary LRP (including support for swizzling) requires vanilla MAD+MAD */
+#define R300_PFS_INSTR1_0                   0x46C0
+#       define R300_FPI1_SRC0C_SHIFT             0
+#       define R300_FPI1_SRC0C_MASK              (31 << 0)
+#       define R300_FPI1_SRC0C_CONST             (1 << 5)
+#       define R300_FPI1_SRC1C_SHIFT             6
+#       define R300_FPI1_SRC1C_MASK              (31 << 6)
+#       define R300_FPI1_SRC1C_CONST             (1 << 11)
+#       define R300_FPI1_SRC2C_SHIFT             12
+#       define R300_FPI1_SRC2C_MASK              (31 << 12)
+#       define R300_FPI1_SRC2C_CONST             (1 << 17)
+#       define R300_FPI1_DSTC_SHIFT              18
+#       define R300_FPI1_DSTC_MASK               (31 << 18)
+#       define R300_FPI1_DSTC_REG_X              (1 << 23)
+#       define R300_FPI1_DSTC_REG_Y              (1 << 24)
+#       define R300_FPI1_DSTC_REG_Z              (1 << 25)
+#       define R300_FPI1_DSTC_OUTPUT_X           (1 << 26)
+#       define R300_FPI1_DSTC_OUTPUT_Y           (1 << 27)
+#       define R300_FPI1_DSTC_OUTPUT_Z           (1 << 28)
+
+#define R300_PFS_INSTR3_0                   0x47C0
+#       define R300_FPI3_SRC0A_SHIFT             0
+#       define R300_FPI3_SRC0A_MASK              (31 << 0)
+#       define R300_FPI3_SRC0A_CONST             (1 << 5)
+#       define R300_FPI3_SRC1A_SHIFT             6
+#       define R300_FPI3_SRC1A_MASK              (31 << 6)
+#       define R300_FPI3_SRC1A_CONST             (1 << 11)
+#       define R300_FPI3_SRC2A_SHIFT             12
+#       define R300_FPI3_SRC2A_MASK              (31 << 12)
+#       define R300_FPI3_SRC2A_CONST             (1 << 17)
+#       define R300_FPI3_DSTA_SHIFT              18
+#       define R300_FPI3_DSTA_MASK               (31 << 18)
+#       define R300_FPI3_DSTA_REG                (1 << 23)
+#       define R300_FPI3_DSTA_OUTPUT             (1 << 24)
+
+#define R300_PFS_INSTR0_0                   0x48C0
+#       define R300_FPI0_ARGC_SRC0C_XYZ          0
+#       define R300_FPI0_ARGC_SRC0C_XXX          1
+#       define R300_FPI0_ARGC_SRC0C_YYY          2
+#       define R300_FPI0_ARGC_SRC0C_ZZZ          3
+#       define R300_FPI0_ARGC_SRC1C_XYZ          4
+#       define R300_FPI0_ARGC_SRC1C_XXX          5
+#       define R300_FPI0_ARGC_SRC1C_YYY          6
+#       define R300_FPI0_ARGC_SRC1C_ZZZ          7
+#       define R300_FPI0_ARGC_SRC2C_XYZ          8
+#       define R300_FPI0_ARGC_SRC2C_XXX          9
+#       define R300_FPI0_ARGC_SRC2C_YYY          10
+#       define R300_FPI0_ARGC_SRC2C_ZZZ          11
+#       define R300_FPI0_ARGC_SRC0A              12
+#       define R300_FPI0_ARGC_SRC1A              13
+#       define R300_FPI0_ARGC_SRC2A              14
+#       define R300_FPI0_ARGC_SRC1C_LRP          15
+#       define R300_FPI0_ARGC_ZERO               20
+#       define R300_FPI0_ARGC_ONE                21
+#       define R300_FPI0_ARGC_HALF               22 /* GUESS */
+#       define R300_FPI0_ARGC_SRC0C_YZX          23
+#       define R300_FPI0_ARGC_SRC1C_YZX          24
+#       define R300_FPI0_ARGC_SRC2C_YZX          25
+#       define R300_FPI0_ARGC_SRC0C_ZXY          26
+#       define R300_FPI0_ARGC_SRC1C_ZXY          27
+#       define R300_FPI0_ARGC_SRC2C_ZXY          28
+#       define R300_FPI0_ARGC_SRC0CA_WZY         29
+#       define R300_FPI0_ARGC_SRC1CA_WZY         30
+#       define R300_FPI0_ARGC_SRC2CA_WZY         31
+
+#       define R300_FPI0_ARG0C_SHIFT             0
+#       define R300_FPI0_ARG0C_MASK              (31 << 0)
+#       define R300_FPI0_ARG0C_NEG               (1 << 5)
+#       define R300_FPI0_ARG0C_ABS               (1 << 6)
+#       define R300_FPI0_ARG1C_SHIFT             7
+#       define R300_FPI0_ARG1C_MASK              (31 << 7)
+#       define R300_FPI0_ARG1C_NEG               (1 << 12)
+#       define R300_FPI0_ARG1C_ABS               (1 << 13)
+#       define R300_FPI0_ARG2C_SHIFT             14
+#       define R300_FPI0_ARG2C_MASK              (31 << 14)
+#       define R300_FPI0_ARG2C_NEG               (1 << 19)
+#       define R300_FPI0_ARG2C_ABS               (1 << 20)
+#       define R300_FPI0_SPECIAL_LRP             (1 << 21)
+#       define R300_FPI0_OUTC_MAD                (0 << 23)
+#       define R300_FPI0_OUTC_DP3                (1 << 23)
+#       define R300_FPI0_OUTC_DP4                (2 << 23)
+#       define R300_FPI0_OUTC_MIN                (4 << 23)
+#       define R300_FPI0_OUTC_MAX                (5 << 23)
+#       define R300_FPI0_OUTC_CMP                (8 << 23)
+#       define R300_FPI0_OUTC_FRC                (9 << 23)
+#       define R300_FPI0_OUTC_REPL_ALPHA         (10 << 23)
+#       define R300_FPI0_OUTC_SAT                (1 << 30)
+#       define R300_FPI0_UNKNOWN_31              (1 << 31)
+
+#define R300_PFS_INSTR2_0                   0x49C0
+#       define R300_FPI2_ARGA_SRC0C_X            0
+#       define R300_FPI2_ARGA_SRC0C_Y            1
+#       define R300_FPI2_ARGA_SRC0C_Z            2
+#       define R300_FPI2_ARGA_SRC1C_X            3
+#       define R300_FPI2_ARGA_SRC1C_Y            4
+#       define R300_FPI2_ARGA_SRC1C_Z            5
+#       define R300_FPI2_ARGA_SRC2C_X            6
+#       define R300_FPI2_ARGA_SRC2C_Y            7
+#       define R300_FPI2_ARGA_SRC2C_Z            8
+#       define R300_FPI2_ARGA_SRC0A              9
+#       define R300_FPI2_ARGA_SRC1A              10
+#       define R300_FPI2_ARGA_SRC2A              11
+#       define R300_FPI2_ARGA_SRC1A_LRP          15
+#       define R300_FPI2_ARGA_ZERO               16
+#       define R300_FPI2_ARGA_ONE                17
+#       define R300_FPI2_ARGA_HALF               18 /* GUESS */
+
+#       define R300_FPI2_ARG0A_SHIFT             0
+#       define R300_FPI2_ARG0A_MASK              (31 << 0)
+#       define R300_FPI2_ARG0A_NEG               (1 << 5)
+#              define R300_FPI2_ARG0A_ABS                               (1 << 6) /* GUESS */
+#       define R300_FPI2_ARG1A_SHIFT             7
+#       define R300_FPI2_ARG1A_MASK              (31 << 7)
+#       define R300_FPI2_ARG1A_NEG               (1 << 12)
+#              define R300_FPI2_ARG1A_ABS                               (1 << 13) /* GUESS */
+#       define R300_FPI2_ARG2A_SHIFT             14
+#       define R300_FPI2_ARG2A_MASK              (31 << 14)
+#       define R300_FPI2_ARG2A_NEG               (1 << 19)
+#              define R300_FPI2_ARG2A_ABS                               (1 << 20) /* GUESS */
+#       define R300_FPI2_SPECIAL_LRP             (1 << 21)
+#       define R300_FPI2_OUTA_MAD                (0 << 23)
+#       define R300_FPI2_OUTA_DP4                (1 << 23)
+#       define R300_FPI2_OUTA_MIN                (2 << 23)
+#       define R300_FPI2_OUTA_MAX                (3 << 23)
+#       define R300_FPI2_OUTA_CMP                (6 << 23)
+#       define R300_FPI2_OUTA_FRC                (7 << 23)
+#       define R300_FPI2_OUTA_EX2                (8 << 23)
+#       define R300_FPI2_OUTA_LG2                (9 << 23)
+#       define R300_FPI2_OUTA_RCP                (10 << 23)
+#       define R300_FPI2_OUTA_RSQ                (11 << 23)
+#       define R300_FPI2_OUTA_SAT                (1 << 30)
+#       define R300_FPI2_UNKNOWN_31              (1 << 31)
+/* END */
+
+/* gap */
+#define R300_PP_ALPHA_TEST                  0x4BD4
+#       define R300_REF_ALPHA_MASK               0x000000ff
+#       define R300_ALPHA_TEST_FAIL              (0 << 8)
+#       define R300_ALPHA_TEST_LESS              (1 << 8)
+#       define R300_ALPHA_TEST_LEQUAL            (3 << 8)
+#       define R300_ALPHA_TEST_EQUAL             (2 << 8)
+#       define R300_ALPHA_TEST_GEQUAL            (6 << 8)
+#       define R300_ALPHA_TEST_GREATER           (4 << 8)
+#       define R300_ALPHA_TEST_NEQUAL            (5 << 8)
+#       define R300_ALPHA_TEST_PASS              (7 << 8)
+#       define R300_ALPHA_TEST_OP_MASK           (7 << 8)
+#       define R300_ALPHA_TEST_ENABLE            (1 << 11)
+
+/* gap */
+/* Fragment program parameters in 7.16 floating point */
+#define R300_PFS_PARAM_0_X                  0x4C00
+#define R300_PFS_PARAM_0_Y                  0x4C04
+#define R300_PFS_PARAM_0_Z                  0x4C08
+#define R300_PFS_PARAM_0_W                  0x4C0C
+/* GUESS: PARAM_31 is last, based on native limits reported by fglrx */
+#define R300_PFS_PARAM_31_X                 0x4DF0
+#define R300_PFS_PARAM_31_Y                 0x4DF4
+#define R300_PFS_PARAM_31_Z                 0x4DF8
+#define R300_PFS_PARAM_31_W                 0x4DFC
+
+/* Notes:
+// - AFAIK fglrx always sets BLEND_UNKNOWN when blending is used in the application
+// - AFAIK fglrx always sets BLEND_NO_SEPARATE when CBLEND and ABLEND are set to the same
+//   function (both registers are always set up completely in any case)
+// - Most blend flags are simply copied from R200 and not tested yet */
+#define R300_RB3D_CBLEND                    0x4E04
+#define R300_RB3D_ABLEND                    0x4E08
+ /* the following only appear in CBLEND */
+#       define R300_BLEND_ENABLE                     (1 << 0)
+#       define R300_BLEND_UNKNOWN                    (3 << 1)
+#       define R300_BLEND_NO_SEPARATE                (1 << 3)
+ /* the following are shared between CBLEND and ABLEND */
+#       define R300_FCN_MASK                         (3  << 12)
+#       define R300_COMB_FCN_ADD_CLAMP               (0  << 12)
+#       define R300_COMB_FCN_ADD_NOCLAMP             (1  << 12)
+#       define R300_COMB_FCN_SUB_CLAMP               (2  << 12)
+#       define R300_COMB_FCN_SUB_NOCLAMP             (3  << 12)
+#       define R300_SRC_BLEND_GL_ZERO                (32 << 16)
+#       define R300_SRC_BLEND_GL_ONE                 (33 << 16)
+#       define R300_SRC_BLEND_GL_SRC_COLOR           (34 << 16)
+#       define R300_SRC_BLEND_GL_ONE_MINUS_SRC_COLOR (35 << 16)
+#       define R300_SRC_BLEND_GL_DST_COLOR           (36 << 16)
+#       define R300_SRC_BLEND_GL_ONE_MINUS_DST_COLOR (37 << 16)
+#       define R300_SRC_BLEND_GL_SRC_ALPHA           (38 << 16)
+#       define R300_SRC_BLEND_GL_ONE_MINUS_SRC_ALPHA (39 << 16)
+#       define R300_SRC_BLEND_GL_DST_ALPHA           (40 << 16)
+#       define R300_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA (41 << 16)
+#       define R300_SRC_BLEND_GL_SRC_ALPHA_SATURATE  (42 << 16)
+#       define R300_SRC_BLEND_MASK                   (63 << 16)
+#       define R300_DST_BLEND_GL_ZERO                (32 << 24)
+#       define R300_DST_BLEND_GL_ONE                 (33 << 24)
+#       define R300_DST_BLEND_GL_SRC_COLOR           (34 << 24)
+#       define R300_DST_BLEND_GL_ONE_MINUS_SRC_COLOR (35 << 24)
+#       define R300_DST_BLEND_GL_DST_COLOR           (36 << 24)
+#       define R300_DST_BLEND_GL_ONE_MINUS_DST_COLOR (37 << 24)
+#       define R300_DST_BLEND_GL_SRC_ALPHA           (38 << 24)
+#       define R300_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA (39 << 24)
+#       define R300_DST_BLEND_GL_DST_ALPHA           (40 << 24)
+#       define R300_DST_BLEND_GL_ONE_MINUS_DST_ALPHA (41 << 24)
+#       define R300_DST_BLEND_MASK                   (63 << 24)
+#define R300_RB3D_COLORMASK                 0x4E0C
+#       define R300_COLORMASK0_B                 (1<<0)
+#       define R300_COLORMASK0_G                 (1<<1)
+#       define R300_COLORMASK0_R                 (1<<2)
+#       define R300_COLORMASK0_A                 (1<<3)
+
+/* gap */
+#define R300_RB3D_COLOROFFSET0              0x4E28
+#       define R300_COLOROFFSET_MASK             0xFFFFFFF0 /* GUESS */
+#define R300_RB3D_COLOROFFSET1              0x4E2C /* GUESS */
+#define R300_RB3D_COLOROFFSET2              0x4E30 /* GUESS */
+#define R300_RB3D_COLOROFFSET3              0x4E34 /* GUESS */
+/* gap */
+/* Bit 16: Larger tiles
+// Bit 17: 4x2 tiles
+// Bit 18: Extremely weird tile like, but some pixels duplicated? */
+#define R300_RB3D_COLORPITCH0               0x4E38
+#       define R300_COLORPITCH_MASK              0x00001FF8 /* GUESS */
+#       define R300_COLOR_TILE_ENABLE            (1 << 16) /* GUESS */
+#       define R300_COLOR_MICROTILE_ENABLE       (1 << 17) /* GUESS */
+#       define R300_COLOR_ENDIAN_NO_SWAP         (0 << 18) /* GUESS */
+#       define R300_COLOR_ENDIAN_WORD_SWAP       (1 << 18) /* GUESS */
+#       define R300_COLOR_ENDIAN_DWORD_SWAP      (2 << 18) /* GUESS */
+#       define R300_COLOR_FORMAT_RGB565          (2 << 22)
+#       define R300_COLOR_FORMAT_ARGB8888        (3 << 22)
+#define R300_RB3D_COLORPITCH1               0x4E3C /* GUESS */
+#define R300_RB3D_COLORPITCH2               0x4E40 /* GUESS */
+#define R300_RB3D_COLORPITCH3               0x4E44 /* GUESS */
+
+/* gap */
+/* Guess by Vladimir.
+// Set to 0A before 3D operations, set to 02 afterwards. */
+#define R300_RB3D_DSTCACHE_CTLSTAT          0x4E4C
+#       define R300_RB3D_DSTCACHE_02             0x00000002
+#       define R300_RB3D_DSTCACHE_0A             0x0000000A
+
+/* gap */
+/* There seems to be no "write only" setting, so use Z-test = ALWAYS for this. */
+/* Bit (1<<8) is the "test" bit. so plain write is 6  - vd */
+#define R300_RB3D_ZSTENCIL_CNTL_0                   0x4F00
+#       define R300_RB3D_Z_DISABLED_1            0x00000010 /* GUESS */
+#       define R300_RB3D_Z_DISABLED_2            0x00000014 /* GUESS */
+#       define R300_RB3D_Z_TEST                  0x00000012
+#       define R300_RB3D_Z_TEST_AND_WRITE        0x00000016
+#       define R300_RB3D_Z_WRITE_ONLY           0x00000006
+
+#       define R300_RB3D_Z_TEST                  0x00000012
+#       define R300_RB3D_Z_TEST_AND_WRITE        0x00000016
+#       define R300_RB3D_Z_WRITE_ONLY           0x00000006
+#      define R300_RB3D_STENCIL_ENABLE          0x00000001
+
+#define R300_RB3D_ZSTENCIL_CNTL_1                   0x4F04
+               /* functions */
+#      define R300_ZS_NEVER                    0
+#      define R300_ZS_LESS                     1
+#      define R300_ZS_LEQUAL                   2
+#      define R300_ZS_EQUAL                    3
+#      define R300_ZS_GEQUAL                   4
+#      define R300_ZS_GREATER                  5
+#      define R300_ZS_NOTEQUAL                 6
+#      define R300_ZS_ALWAYS                   7
+#       define R300_ZS_MASK                     7
+               /* operations */
+#      define R300_ZS_KEEP                     0
+#      define R300_ZS_ZERO                     1
+#      define R300_ZS_REPLACE                  2
+#      define R300_ZS_INCR                     3
+#      define R300_ZS_DECR                     4
+#      define R300_ZS_INVERT                   5
+#      define R300_ZS_INCR_WRAP                6
+#      define R300_ZS_DECR_WRAP                7
+
+       /* front and back refer to operations done for front
+          and back faces, i.e. separate stencil function support */
+#      define R300_RB3D_ZS1_DEPTH_FUNC_SHIFT           0
+#      define R300_RB3D_ZS1_FRONT_FUNC_SHIFT           3
+#      define R300_RB3D_ZS1_FRONT_FAIL_OP_SHIFT        6
+#      define R300_RB3D_ZS1_FRONT_ZPASS_OP_SHIFT       9
+#      define R300_RB3D_ZS1_FRONT_ZFAIL_OP_SHIFT      12
+#      define R300_RB3D_ZS1_BACK_FUNC_SHIFT           15
+#      define R300_RB3D_ZS1_BACK_FAIL_OP_SHIFT        18
+#      define R300_RB3D_ZS1_BACK_ZPASS_OP_SHIFT       21
+#      define R300_RB3D_ZS1_BACK_ZFAIL_OP_SHIFT       24
+
+
+
+#define R300_RB3D_ZSTENCIL_CNTL_2                   0x4F08
+#      define R300_RB3D_ZS2_STENCIL_REF_SHIFT          0
+#      define R300_RB3D_ZS2_STENCIL_MASK               0xFF
+#      define R300_RB3D_ZS2_STENCIL_MASK_SHIFT         8
+#      define R300_RB3D_ZS2_STENCIL_WRITE_MASK_SHIFT   16
+
+/* gap */
+
+#define R300_RB3D_ZSTENCIL_FORMAT                   0x4F10
+#      define R300_DEPTH_FORMAT_16BIT_INT_Z     (0 << 0)
+#      define R300_DEPTH_FORMAT_24BIT_INT_Z     (2 << 0)
+
+/* gap */
+#define R300_RB3D_DEPTHOFFSET               0x4F20
+#define R300_RB3D_DEPTHPITCH                0x4F24
+#       define R300_DEPTHPITCH_MASK              0x00001FF8 /* GUESS */
+#       define R300_DEPTH_TILE_ENABLE            (1 << 16) /* GUESS */
+#       define R300_DEPTH_MICROTILE_ENABLE       (1 << 17) /* GUESS */
+#       define R300_DEPTH_ENDIAN_NO_SWAP         (0 << 18) /* GUESS */
+#       define R300_DEPTH_ENDIAN_WORD_SWAP       (1 << 18) /* GUESS */
+#       define R300_DEPTH_ENDIAN_DWORD_SWAP      (2 << 18) /* GUESS */
+
+/* BEGIN: Vertex program instruction set
+// Every instruction is four dwords long:
+//  DWORD 0: output and opcode
+//  DWORD 1: first argument
+//  DWORD 2: second argument
+//  DWORD 3: third argument
+//
+// Notes:
+//  - ABS r, a is implemented as MAX r, a, -a
+//  - MOV is implemented as ADD to zero
+//  - XPD is implemented as MUL + MAD
+//  - FLR is implemented as FRC + ADD
+//  - apparently, fglrx tries to schedule instructions so that there is at least
+//    one instruction between the write to a temporary and the first read
+//    from said temporary; however, violations of this scheduling are allowed
+//  - register indices seem to be unrelated with OpenGL aliasing to conventional state
+//  - only one attribute and one parameter can be loaded at a time; however, the
+//    same attribute/parameter can be used for more than one argument
+//  - the second software argument for POW is the third hardware argument (no idea why)
+//  - MAD with only temporaries as input seems to use VPI_OUT_SELECT_MAD_2
+//
+// There is some magic surrounding LIT:
+//  The single argument is replicated across all three inputs, but swizzled:
+//   First argument: xyzy
+//   Second argument: xyzx
+//   Third argument: xyzw
+//  Whenever the result is used later in the fragment program, fglrx forces x and w
+//  to be 1.0 in the input selection; I don't know whether this is strictly necessary */
+#define R300_VPI_OUT_OP_DOT                     (1 << 0)
+#define R300_VPI_OUT_OP_MUL                     (2 << 0)
+#define R300_VPI_OUT_OP_ADD                     (3 << 0)
+#define R300_VPI_OUT_OP_MAD                     (4 << 0)
+#define R300_VPI_OUT_OP_DST                     (5 << 0)
+#define R300_VPI_OUT_OP_FRC                     (6 << 0)
+#define R300_VPI_OUT_OP_MAX                     (7 << 0)
+#define R300_VPI_OUT_OP_MIN                     (8 << 0)
+#define R300_VPI_OUT_OP_SGE                     (9 << 0)
+#define R300_VPI_OUT_OP_SLT                     (10 << 0)
+#define R300_VPI_OUT_OP_UNK12                   (12 << 0) /* Used in GL_POINT_DISTANCE_ATTENUATION_ARB, vector(scalar, vector) */
+#define R300_VPI_OUT_OP_EXP                     (65 << 0)
+#define R300_VPI_OUT_OP_LOG                     (66 << 0)
+#define R300_VPI_OUT_OP_UNK67                   (67 << 0) /* Used in fog computations, scalar(scalar) */
+#define R300_VPI_OUT_OP_LIT                     (68 << 0)
+#define R300_VPI_OUT_OP_POW                     (69 << 0)
+#define R300_VPI_OUT_OP_RCP                     (70 << 0)
+#define R300_VPI_OUT_OP_RSQ                     (72 << 0)
+#define R300_VPI_OUT_OP_UNK73                   (73 << 0) /* Used in GL_POINT_DISTANCE_ATTENUATION_ARB, scalar(scalar) */
+#define R300_VPI_OUT_OP_EX2                     (75 << 0)
+#define R300_VPI_OUT_OP_LG2                     (76 << 0)
+#define R300_VPI_OUT_OP_MAD_2                   (128 << 0)
+#define R300_VPI_OUT_OP_UNK129                  (129 << 0) /* all temps, vector(scalar, vector, vector) */
+
+#define R300_VPI_OUT_REG_CLASS_TEMPORARY        (0 << 8)
+#define R300_VPI_OUT_REG_CLASS_RESULT           (2 << 8)
+#define R300_VPI_OUT_REG_CLASS_MASK             (31 << 8)
+
+#define R300_VPI_OUT_REG_INDEX_SHIFT            13
+#define R300_VPI_OUT_REG_INDEX_MASK             (31 << 13) /* GUESS based on fglrx native limits */
+
+#define R300_VPI_OUT_WRITE_X                    (1 << 20)
+#define R300_VPI_OUT_WRITE_Y                    (1 << 21)
+#define R300_VPI_OUT_WRITE_Z                    (1 << 22)
+#define R300_VPI_OUT_WRITE_W                    (1 << 23)
+
+#define R300_VPI_IN_REG_CLASS_TEMPORARY         (0 << 0)
+#define R300_VPI_IN_REG_CLASS_ATTRIBUTE         (1 << 0)
+#define R300_VPI_IN_REG_CLASS_PARAMETER         (2 << 0)
+#define R300_VPI_IN_REG_CLASS_NONE              (9 << 0)
+#define R300_VPI_IN_REG_CLASS_MASK              (31 << 0) /* GUESS */
+
+#define R300_VPI_IN_REG_INDEX_SHIFT             5
+#define R300_VPI_IN_REG_INDEX_MASK              (255 << 5) /* GUESS based on fglrx native limits */
+
+/* The R300 can select components from the input register arbitrarily.
+// Use the following constants, shifted by the component shift you
+// want to select */
+#define R300_VPI_IN_SELECT_X    0
+#define R300_VPI_IN_SELECT_Y    1
+#define R300_VPI_IN_SELECT_Z    2
+#define R300_VPI_IN_SELECT_W    3
+#define R300_VPI_IN_SELECT_ZERO 4
+#define R300_VPI_IN_SELECT_ONE  5
+#define R300_VPI_IN_SELECT_MASK 7
+
+#define R300_VPI_IN_X_SHIFT                     13
+#define R300_VPI_IN_Y_SHIFT                     16
+#define R300_VPI_IN_Z_SHIFT                     19
+#define R300_VPI_IN_W_SHIFT                     22
+
+#define R300_VPI_IN_NEG_X                       (1 << 25)
+#define R300_VPI_IN_NEG_Y                       (1 << 26)
+#define R300_VPI_IN_NEG_Z                       (1 << 27)
+#define R300_VPI_IN_NEG_W                       (1 << 28)
+/* END */
+
+//BEGIN: Packet 3 commands
+
+// A primitive emission dword.
+#define R300_PRIM_TYPE_NONE                     (0 << 0)
+#define R300_PRIM_TYPE_POINT                    (1 << 0)
+#define R300_PRIM_TYPE_LINE                     (2 << 0)
+#define R300_PRIM_TYPE_LINE_STRIP               (3 << 0)
+#define R300_PRIM_TYPE_TRI_LIST                 (4 << 0)
+#define R300_PRIM_TYPE_TRI_FAN                  (5 << 0)
+#define R300_PRIM_TYPE_TRI_STRIP                (6 << 0)
+#define R300_PRIM_TYPE_TRI_TYPE2                (7 << 0)
+#define R300_PRIM_TYPE_RECT_LIST                (8 << 0)
+#define R300_PRIM_TYPE_3VRT_POINT_LIST          (9 << 0)
+#define R300_PRIM_TYPE_3VRT_LINE_LIST           (10 << 0)
+#define R300_PRIM_TYPE_POINT_SPRITES            (11 << 0) // GUESS (based on r200)
+#define R300_PRIM_TYPE_LINE_LOOP                (12 << 0)
+#define R300_PRIM_TYPE_QUADS                    (13 << 0)
+#define R300_PRIM_TYPE_QUAD_STRIP               (14 << 0)
+#define R300_PRIM_TYPE_POLYGON                  (15 << 0)
+#define R300_PRIM_TYPE_MASK                     0xF
+#define R300_PRIM_WALK_IND                      (1 << 4)
+#define R300_PRIM_WALK_LIST                     (2 << 4)
+#define R300_PRIM_WALK_RING                     (3 << 4)
+#define R300_PRIM_WALK_MASK                     (3 << 4)
+#define R300_PRIM_COLOR_ORDER_BGRA              (0 << 6) // GUESS (based on r200)
+#define R300_PRIM_COLOR_ORDER_RGBA              (1 << 6) // GUESS
+#define R300_PRIM_NUM_VERTICES_SHIFT            16
+
+// Draw a primitive from vertex data in arrays loaded via 3D_LOAD_VBPNTR.
+// Two parameter dwords:
+// 0. The first parameter appears to be always 0
+// 1. The second parameter is a standard primitive emission dword.
+#define R300_PACKET3_3D_DRAW_VBUF           0x00002800
+
+// Specify the full set of vertex arrays as (address, stride).
+// The first parameter is the number of vertex arrays specified.
+// The rest of the command is a variable length list of blocks, where
+// each block is three dwords long and specifies two arrays.
+// The first dword of a block is split into two words, the lower significant
+// word refers to the first array, the more significant word to the second
+// array in the block.
+// The low byte of each word contains the size of an array entry in dwords,
+// the high byte contains the stride of the array.
+// The second dword of a block contains the pointer to the first array,
+// the third dword of a block contains the pointer to the second array.
+// Note that if the total number of arrays is odd, the third dword of
+// the last block is omitted.
+#define R300_PACKET3_3D_LOAD_VBPNTR         0x00002F00
+
+#define R300_PACKET3_INDX_BUFFER            0x00003300
+#    define R300_EB_UNK1_SHIFT                      24
+#    define R300_EB_UNK1                    (0x80<<24)
+#    define R300_EB_UNK2                        0x0810
+#define R300_PACKET3_3D_DRAW_INDX_2         0x00003600
+
+//END
+
+#endif /* _R300_REG_H */
index 20bcf872b348859fec8ca7ccab6270d2d400a192..6d9080a3ca7e97fefb3302959bb445ce3dc0aac0 100644 (file)
@@ -32,6 +32,7 @@
 #include "drm.h"
 #include "radeon_drm.h"
 #include "radeon_drv.h"
+#include "r300_reg.h"
 
 #define RADEON_FIFO_DEBUG      0
 
@@ -1151,6 +1152,8 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev,
 
 #if __OS_HAS_AGP
        if ( !dev_priv->is_pci ) {
+               /* set RADEON_AGP_BASE here instead of relying on X from user space */
+               RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
                RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR,
                              dev_priv->ring_rptr->offset
                              - dev->agp->base
@@ -1407,6 +1410,7 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init )
                radeon_do_cleanup_cp(dev);
                return DRM_ERR(EINVAL);
        }
+       dev->agp_buffer_token = init->buffers_offset;
        dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
        if(!dev->agp_buffer_map) {
                DRM_ERROR("could not find dma buffer region!\n");
@@ -1625,6 +1629,9 @@ int radeon_cp_init( DRM_IOCTL_ARGS )
 
        DRM_COPY_FROM_USER_IOCTL( init, (drm_radeon_init_t __user *)data, sizeof(init) );
 
+       if(init.func == RADEON_INIT_R300_CP)
+               r300_init_reg_flags();
+
        switch ( init.func ) {
        case RADEON_INIT_CP:
        case RADEON_INIT_R200_CP:
@@ -2039,15 +2046,43 @@ int radeon_driver_preinit(struct drm_device *dev, unsigned long flags)
        case CHIP_RV200:
        case CHIP_R200:
        case CHIP_R300:
+       case CHIP_R420:
                dev_priv->flags |= CHIP_HAS_HIERZ;
                break;
        default:
        /* all other chips have no hierarchical z buffer */
                break;
        }
+
+       if (drm_device_is_agp(dev))
+               dev_priv->flags |= CHIP_IS_AGP;
+       
+       DRM_DEBUG("%s card detected\n",
+                 ((dev_priv->flags & CHIP_IS_AGP) ? "AGP" : "PCI"));
        return ret;
 }
 
+int radeon_presetup(struct drm_device *dev)
+{
+       int ret;
+       drm_local_map_t *map;
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+
+       ret = drm_addmap(dev, drm_get_resource_start(dev, 2),
+                        drm_get_resource_len(dev, 2), _DRM_REGISTERS,
+                        _DRM_READ_ONLY, &dev_priv->mmio);
+       if (ret != 0)
+               return ret;
+
+       ret = drm_addmap(dev, drm_get_resource_start(dev, 0),
+                        drm_get_resource_len(dev, 0), _DRM_FRAME_BUFFER,
+                        _DRM_WRITE_COMBINING, &map);
+       if (ret != 0)
+               return ret;
+
+       return 0;
+}
+
 int radeon_driver_postcleanup(struct drm_device *dev)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
index c1e62d047989aa6e61d34367ace2863810b65248..3792798270a4341bda91d0c2dc6f3d13a87554da 100644 (file)
@@ -195,6 +195,52 @@ typedef union {
 #define RADEON_WAIT_2D  0x1
 #define RADEON_WAIT_3D  0x2
 
+/* Allowed parameters for R300_CMD_PACKET3
+ */
+#define R300_CMD_PACKET3_CLEAR         0
+#define R300_CMD_PACKET3_RAW           1
+
+/* Commands understood by cmd_buffer ioctl for R300.
+ * The interface has not been stabilized, so some of these may be removed
+ * and eventually reordered before stabilization.
+ */
+#define R300_CMD_PACKET0               1 
+#define R300_CMD_VPU                   2 /* emit vertex program upload */
+#define R300_CMD_PACKET3               3 /* emit a packet3 */
+#define R300_CMD_END3D                 4 /* emit sequence ending 3d rendering */
+#define R300_CMD_CP_DELAY              5
+#define R300_CMD_DMA_DISCARD           6
+#define R300_CMD_WAIT                  7
+#      define R300_WAIT_2D             0x1
+#      define R300_WAIT_3D             0x2
+#      define R300_WAIT_2D_CLEAN       0x3
+#      define R300_WAIT_3D_CLEAN       0x4
+
+typedef union {
+       unsigned int u;
+       struct {
+               unsigned char cmd_type, pad0, pad1, pad2;
+       } header;
+       struct {
+               unsigned char cmd_type, count, reglo, reghi;
+       } packet0;
+       struct {
+               unsigned char cmd_type, count, adrlo, adrhi;
+       } vpu;
+       struct {
+               unsigned char cmd_type, packet, pad0, pad1;
+       } packet3;
+       struct {
+               unsigned char cmd_type, packet;
+               unsigned short count; /* amount of packet2 to emit */
+       } delay;
+       struct {
+               unsigned char cmd_type, buf_idx, pad0, pad1;
+       } dma;
+       struct {
+               unsigned char cmd_type, flags, pad0, pad1;      
+       } wait;
+} drm_r300_cmd_header_t;
 
 #define RADEON_FRONT                   0x1
 #define RADEON_BACK                    0x2
index 18e4e5b0952f4f60c5143253f57b476949fd23c2..e0682f64b400c48de09cb9b43cbb488d6c7c173c 100644 (file)
@@ -76,6 +76,7 @@ static struct drm_driver driver = {
        .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
        .dev_priv_size = sizeof(drm_radeon_buf_priv_t),
        .preinit = radeon_driver_preinit,
+       .presetup = radeon_presetup,
        .postcleanup = radeon_driver_postcleanup,
        .prerelease = radeon_driver_prerelease,
        .pretakedown = radeon_driver_pretakedown,
index 771aa80a5e8c24233193b0c73566e03f4ebc1248..f12a963ede18986a73391f69bc260c42c233bc5a 100644 (file)
  *     - Add support for r100 cube maps
  * 1.16- Add R200_EMIT_PP_TRI_PERF_CNTL packet to support brilinear
  *       texture filtering on r200
+ * 1.17- Add initial support for R300 (3D).
  */
 #define DRIVER_MAJOR           1
-#define DRIVER_MINOR           16
+#define DRIVER_MINOR           17
 #define DRIVER_PATCHLEVEL      0
 
 #define GET_RING_HEAD(dev_priv)                DRM_READ32(  (dev_priv)->ring_rptr, 0 )
@@ -106,7 +107,9 @@ enum radeon_family {
        CHIP_RV280,
        CHIP_R300,
        CHIP_RS300,
+       CHIP_R350,
        CHIP_RV350,
+       CHIP_R420,
        CHIP_LAST,
 };
 
@@ -290,6 +293,7 @@ extern int radeon_wait_ring( drm_radeon_private_t *dev_priv, int n );
 extern int radeon_do_cp_idle( drm_radeon_private_t *dev_priv );
 
 extern int radeon_driver_preinit(struct drm_device *dev, unsigned long flags);
+extern int radeon_presetup(struct drm_device *dev);
 extern int radeon_driver_postcleanup(struct drm_device *dev);
 
 extern int radeon_mem_alloc( DRM_IOCTL_ARGS );
@@ -320,6 +324,14 @@ extern int radeon_postcleanup( struct drm_device *dev );
 extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
                                unsigned long arg);
 
+
+/* r300_cmdbuf.c */
+extern void r300_init_reg_flags(void);
+
+extern int r300_do_cp_cmdbuf(drm_device_t* dev, DRMFILE filp,
+                            drm_file_t* filp_priv,
+                            drm_radeon_cmd_buffer_t* cmdbuf);
+
 /* Flags for stats.boxes
  */
 #define RADEON_BOX_DMA_IDLE      0x1
@@ -357,6 +369,11 @@ extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
 #define RADEON_CRTC2_OFFSET            0x0324
 #define RADEON_CRTC2_OFFSET_CNTL       0x0328
 
+#define RADEON_MPP_TB_CONFIG           0x01c0
+#define RADEON_MEM_CNTL                        0x0140
+#define RADEON_MEM_SDRAM_MODE_REG      0x0158
+#define RADEON_AGP_BASE                        0x0170
+
 #define RADEON_RB3D_COLOROFFSET                0x1c40
 #define RADEON_RB3D_COLORPITCH         0x1c48
 
@@ -651,16 +668,27 @@ extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
 #define RADEON_CP_PACKET1              0x40000000
 #define RADEON_CP_PACKET2              0x80000000
 #define RADEON_CP_PACKET3              0xC0000000
+#       define RADEON_CP_NOP                    0x00001000
+#       define RADEON_CP_NEXT_CHAR              0x00001900
+#       define RADEON_CP_PLY_NEXTSCAN           0x00001D00
+#       define RADEON_CP_SET_SCISSORS           0x00001E00
+             /* GEN_INDX_PRIM is unsupported starting with R300 */
 #      define RADEON_3D_RNDR_GEN_INDX_PRIM     0x00002300
 #      define RADEON_WAIT_FOR_IDLE             0x00002600
 #      define RADEON_3D_DRAW_VBUF              0x00002800
 #      define RADEON_3D_DRAW_IMMD              0x00002900
 #      define RADEON_3D_DRAW_INDX              0x00002A00
+#       define RADEON_CP_LOAD_PALETTE           0x00002C00
 #      define RADEON_3D_LOAD_VBPNTR            0x00002F00
 #      define RADEON_MPEG_IDCT_MACROBLOCK      0x00003000
 #      define RADEON_MPEG_IDCT_MACROBLOCK_REV  0x00003100
 #      define RADEON_3D_CLEAR_ZMASK            0x00003200
+#      define RADEON_CP_INDX_BUFFER            0x00003300
+#       define RADEON_CP_3D_DRAW_VBUF_2         0x00003400
+#       define RADEON_CP_3D_DRAW_IMMD_2         0x00003500
+#       define RADEON_CP_3D_DRAW_INDX_2         0x00003600
 #      define RADEON_3D_CLEAR_HIZ              0x00003700
+#       define RADEON_CP_3D_CLEAR_CMASK         0x00003802
 #      define RADEON_CNTL_HOSTDATA_BLT         0x00009400
 #      define RADEON_CNTL_PAINT_MULTI          0x00009A00
 #      define RADEON_CNTL_BITBLT_MULTI         0x00009B00
index 1f79e249146c9585a8ae1d968b47dc852924760b..64a3e3a406ef74dea8088f6fb05b2f0f0b5dd504 100644 (file)
@@ -1493,7 +1493,7 @@ static void radeon_cp_dispatch_indices( drm_device_t *dev,
 
 }
 
-#define RADEON_MAX_TEXTURE_SIZE (RADEON_BUFFER_SIZE - 8 * sizeof(u32))
+#define RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE
 
 static int radeon_cp_dispatch_texture( DRMFILE filp,
                                       drm_device_t *dev,
@@ -1506,10 +1506,11 @@ static int radeon_cp_dispatch_texture( DRMFILE filp,
        u32 format;
        u32 *buffer;
        const u8 __user *data;
-       int size, dwords, tex_width, blit_width;
+       int size, dwords, tex_width, blit_width, spitch;
        u32 height;
        int i;
        u32 texpitch, microtile;
+       u32 offset;
        RING_LOCALS;
 
        DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
@@ -1530,17 +1531,6 @@ static int radeon_cp_dispatch_texture( DRMFILE filp,
        RADEON_WAIT_UNTIL_IDLE();
        ADVANCE_RING();
 
-#ifdef __BIG_ENDIAN
-       /* The Mesa texture functions provide the data in little endian as the
-        * chip wants it, but we need to compensate for the fact that the CP
-        * ring gets byte-swapped
-        */
-       BEGIN_RING( 2 );
-       OUT_RING_REG( RADEON_RBBM_GUICNTL, RADEON_HOST_DATA_SWAP_32BIT );
-       ADVANCE_RING();
-#endif
-
-
        /* The compiler won't optimize away a division by a variable,
         * even if the only legal values are powers of two.  Thus, we'll
         * use a shift instead.
@@ -1572,6 +1562,10 @@ static int radeon_cp_dispatch_texture( DRMFILE filp,
                DRM_ERROR( "invalid texture format %d\n", tex->format );
                return DRM_ERR(EINVAL);
        }
+       spitch = blit_width >> 6;
+       if (spitch == 0 && image->height > 1)
+               return DRM_ERR(EINVAL);
+
        texpitch = tex->pitch;
        if ((texpitch << 22) & RADEON_DST_TILE_MICRO) {
                microtile = 1;
@@ -1624,25 +1618,6 @@ static int radeon_cp_dispatch_texture( DRMFILE filp,
                 */
                buffer = (u32*)((char*)dev->agp_buffer_map->handle + buf->offset);
                dwords = size / 4;
-               buffer[0] = CP_PACKET3( RADEON_CNTL_HOSTDATA_BLT, dwords + 6 );
-               buffer[1] = (RADEON_GMC_DST_PITCH_OFFSET_CNTL |
-                            RADEON_GMC_BRUSH_NONE |
-                            (format << 8) |
-                            RADEON_GMC_SRC_DATATYPE_COLOR |
-                            RADEON_ROP3_S |
-                            RADEON_DP_SRC_SOURCE_HOST_DATA |
-                            RADEON_GMC_CLR_CMP_CNTL_DIS |
-                            RADEON_GMC_WR_MSK_DIS);
-               
-               buffer[2] = (texpitch << 22) | (tex->offset >> 10);
-               buffer[3] = 0xffffffff;
-               buffer[4] = 0xffffffff;
-               buffer[5] = (image->y << 16) | image->x;
-               buffer[6] = (height << 16) | image->width;
-               buffer[7] = dwords;
-               buffer += 8;
-
-               
 
                if (microtile) {
                        /* texture micro tiling in use, minimum texture width is thus 16 bytes.
@@ -1750,9 +1725,28 @@ static int radeon_cp_dispatch_texture( DRMFILE filp,
                }
 
                buf->filp = filp;
-               buf->used = (dwords + 8) * sizeof(u32);
-               radeon_cp_dispatch_indirect( dev, buf, 0, buf->used );
-               radeon_cp_discard_buffer( dev, buf );
+               buf->used = size;
+               offset = dev_priv->gart_buffers_offset + buf->offset;
+               BEGIN_RING(9);
+               OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
+               OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
+                        RADEON_GMC_DST_PITCH_OFFSET_CNTL |
+                        RADEON_GMC_BRUSH_NONE |
+                        (format << 8) |
+                        RADEON_GMC_SRC_DATATYPE_COLOR |
+                        RADEON_ROP3_S |
+                        RADEON_DP_SRC_SOURCE_MEMORY |
+                        RADEON_GMC_CLR_CMP_CNTL_DIS |
+                        RADEON_GMC_WR_MSK_DIS );
+               OUT_RING((spitch << 22) | (offset >> 10));
+               OUT_RING((texpitch << 22) | (tex->offset >> 10));
+               OUT_RING(0);
+               OUT_RING((image->x << 16) | image->y);
+               OUT_RING((image->width << 16) | height);
+               RADEON_WAIT_UNTIL_2D_IDLE();
+               ADVANCE_RING();
+
+               radeon_cp_discard_buffer(dev, buf);
 
                /* Update the input parameters for next time */
                image->y += height;
@@ -2797,6 +2791,17 @@ static int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
 
        orig_nbox = cmdbuf.nbox;
 
+       if(dev_priv->microcode_version == UCODE_R300) {
+               int temp;
+               temp=r300_do_cp_cmdbuf(dev, filp, filp_priv, &cmdbuf);
+       
+               if (orig_bufsz != 0)
+                       drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
+       
+               return temp;
+       }
+
+       /* microcode_version != r300 */
        while ( cmdbuf.bufsz >= sizeof(header) ) {
 
                header.i = *(int *)cmdbuf.buf;
diff --git a/drivers/char/drm/savage_bci.c b/drivers/char/drm/savage_bci.c
new file mode 100644 (file)
index 0000000..2fd40ba
--- /dev/null
@@ -0,0 +1,1096 @@
+/* savage_bci.c -- BCI support for Savage
+ *
+ * Copyright 2004  Felix Kuehling
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "drmP.h"
+#include "savage_drm.h"
+#include "savage_drv.h"
+
+/* Need a long timeout for shadow status updates can take a while
+ * and so can waiting for events when the queue is full. */
+#define SAVAGE_DEFAULT_USEC_TIMEOUT    1000000 /* 1s */
+#define SAVAGE_EVENT_USEC_TIMEOUT      5000000 /* 5s */
+#define SAVAGE_FREELIST_DEBUG          0
+
+static int
+savage_bci_wait_fifo_shadow(drm_savage_private_t *dev_priv, unsigned int n)
+{
+       uint32_t mask = dev_priv->status_used_mask;
+       uint32_t threshold = dev_priv->bci_threshold_hi;
+       uint32_t status;
+       int i;
+
+#if SAVAGE_BCI_DEBUG
+       if (n > dev_priv->cob_size + SAVAGE_BCI_FIFO_SIZE - threshold)
+               DRM_ERROR("Trying to emit %d words "
+                         "(more than guaranteed space in COB)\n", n);
+#endif
+
+       for (i = 0; i < SAVAGE_DEFAULT_USEC_TIMEOUT; i++) {
+               DRM_MEMORYBARRIER();
+               status = dev_priv->status_ptr[0];
+               if ((status & mask) < threshold)
+                       return 0;
+               DRM_UDELAY(1);
+       }
+
+#if SAVAGE_BCI_DEBUG
+       DRM_ERROR("failed!\n");
+       DRM_INFO("   status=0x%08x, threshold=0x%08x\n", status, threshold);
+#endif
+       return DRM_ERR(EBUSY);
+}
+
+static int
+savage_bci_wait_fifo_s3d(drm_savage_private_t *dev_priv, unsigned int n)
+{
+       uint32_t maxUsed = dev_priv->cob_size + SAVAGE_BCI_FIFO_SIZE - n;
+       uint32_t status;
+       int i;
+
+       for (i = 0; i < SAVAGE_DEFAULT_USEC_TIMEOUT; i++) {
+               status = SAVAGE_READ(SAVAGE_STATUS_WORD0);
+               if ((status & SAVAGE_FIFO_USED_MASK_S3D) <= maxUsed)
+                       return 0;
+               DRM_UDELAY(1);
+       }
+
+#if SAVAGE_BCI_DEBUG
+       DRM_ERROR("failed!\n");
+       DRM_INFO("   status=0x%08x\n", status);
+#endif
+       return DRM_ERR(EBUSY);
+}
+
+static int
+savage_bci_wait_fifo_s4(drm_savage_private_t *dev_priv, unsigned int n)
+{
+       uint32_t maxUsed = dev_priv->cob_size + SAVAGE_BCI_FIFO_SIZE - n;
+       uint32_t status;
+       int i;
+
+       for (i = 0; i < SAVAGE_DEFAULT_USEC_TIMEOUT; i++) {
+               status = SAVAGE_READ(SAVAGE_ALT_STATUS_WORD0);
+               if ((status & SAVAGE_FIFO_USED_MASK_S4) <= maxUsed)
+                       return 0;
+               DRM_UDELAY(1);
+       }
+
+#if SAVAGE_BCI_DEBUG
+       DRM_ERROR("failed!\n");
+       DRM_INFO("   status=0x%08x\n", status);
+#endif
+       return DRM_ERR(EBUSY);
+}
+
+/*
+ * Waiting for events.
+ *
+ * The BIOSresets the event tag to 0 on mode changes. Therefore we
+ * never emit 0 to the event tag. If we find a 0 event tag we know the
+ * BIOS stomped on it and return success assuming that the BIOS waited
+ * for engine idle.
+ *
+ * Note: if the Xserver uses the event tag it has to follow the same
+ * rule. Otherwise there may be glitches every 2^16 events.
+ */
+static int
+savage_bci_wait_event_shadow(drm_savage_private_t *dev_priv, uint16_t e)
+{
+       uint32_t status;
+       int i;
+
+       for (i = 0; i < SAVAGE_EVENT_USEC_TIMEOUT; i++) {
+               DRM_MEMORYBARRIER();
+               status = dev_priv->status_ptr[1];
+               if ((((status & 0xffff) - e) & 0xffff) <= 0x7fff ||
+                   (status & 0xffff) == 0)
+                       return 0;
+               DRM_UDELAY(1);
+       }
+
+#if SAVAGE_BCI_DEBUG
+       DRM_ERROR("failed!\n");
+       DRM_INFO("   status=0x%08x, e=0x%04x\n", status, e);
+#endif
+
+       return DRM_ERR(EBUSY);
+}
+
+static int
+savage_bci_wait_event_reg(drm_savage_private_t *dev_priv, uint16_t e)
+{
+       uint32_t status;
+       int i;
+
+       for (i = 0; i < SAVAGE_EVENT_USEC_TIMEOUT; i++) {
+               status = SAVAGE_READ(SAVAGE_STATUS_WORD1);
+               if ((((status & 0xffff) - e) & 0xffff) <= 0x7fff ||
+                   (status & 0xffff) == 0)
+                       return 0;
+               DRM_UDELAY(1);
+       }
+
+#if SAVAGE_BCI_DEBUG
+       DRM_ERROR("failed!\n");
+       DRM_INFO("   status=0x%08x, e=0x%04x\n", status, e);
+#endif
+
+       return DRM_ERR(EBUSY);
+}
+
+uint16_t savage_bci_emit_event(drm_savage_private_t *dev_priv,
+                              unsigned int flags)
+{
+       uint16_t count;
+       BCI_LOCALS;
+
+       if (dev_priv->status_ptr) {
+               /* coordinate with Xserver */
+               count = dev_priv->status_ptr[1023];
+               if (count < dev_priv->event_counter)
+                       dev_priv->event_wrap++;
+       } else {
+               count = dev_priv->event_counter;
+       }
+       count = (count + 1) & 0xffff;
+       if (count == 0) {
+               count++; /* See the comment above savage_wait_event_*. */
+               dev_priv->event_wrap++;
+       }
+       dev_priv->event_counter = count;
+       if (dev_priv->status_ptr)
+               dev_priv->status_ptr[1023] = (uint32_t)count;
+
+       if ((flags & (SAVAGE_WAIT_2D | SAVAGE_WAIT_3D))) {
+               unsigned int wait_cmd = BCI_CMD_WAIT;
+               if ((flags & SAVAGE_WAIT_2D))
+                       wait_cmd |= BCI_CMD_WAIT_2D;
+               if ((flags & SAVAGE_WAIT_3D))
+                       wait_cmd |= BCI_CMD_WAIT_3D;
+               BEGIN_BCI(2);
+               BCI_WRITE(wait_cmd);
+       } else {
+               BEGIN_BCI(1);
+       }
+       BCI_WRITE(BCI_CMD_UPDATE_EVENT_TAG | (uint32_t)count);
+
+       return count;
+}
+
+/*
+ * Freelist management
+ */
+static int savage_freelist_init(drm_device_t *dev)
+{
+       drm_savage_private_t *dev_priv = dev->dev_private;
+       drm_device_dma_t *dma = dev->dma;
+       drm_buf_t *buf;
+       drm_savage_buf_priv_t *entry;
+       int i;
+       DRM_DEBUG("count=%d\n", dma->buf_count);
+
+       dev_priv->head.next = &dev_priv->tail;
+       dev_priv->head.prev = NULL;
+       dev_priv->head.buf = NULL;
+
+       dev_priv->tail.next = NULL;
+       dev_priv->tail.prev = &dev_priv->head;
+       dev_priv->tail.buf = NULL;
+
+       for (i = 0; i < dma->buf_count; i++) {
+               buf = dma->buflist[i];
+               entry = buf->dev_private;
+
+               SET_AGE(&entry->age, 0, 0);
+               entry->buf = buf;
+
+               entry->next = dev_priv->head.next;
+               entry->prev = &dev_priv->head;
+               dev_priv->head.next->prev = entry;
+               dev_priv->head.next = entry;
+       }
+
+       return 0;
+}
+
+static drm_buf_t *savage_freelist_get(drm_device_t *dev)
+{
+       drm_savage_private_t *dev_priv = dev->dev_private;
+       drm_savage_buf_priv_t *tail = dev_priv->tail.prev;
+       uint16_t event;
+       unsigned int wrap;
+       DRM_DEBUG("\n");
+
+       UPDATE_EVENT_COUNTER();
+       if (dev_priv->status_ptr)
+               event = dev_priv->status_ptr[1] & 0xffff;
+       else
+               event = SAVAGE_READ(SAVAGE_STATUS_WORD1) & 0xffff;
+       wrap = dev_priv->event_wrap;
+       if (event > dev_priv->event_counter)
+               wrap--; /* hardware hasn't passed the last wrap yet */
+
+       DRM_DEBUG("   tail=0x%04x %d\n", tail->age.event, tail->age.wrap);
+       DRM_DEBUG("   head=0x%04x %d\n", event, wrap);
+
+       if (tail->buf && (TEST_AGE(&tail->age, event, wrap) || event == 0)) {
+               drm_savage_buf_priv_t *next = tail->next;
+               drm_savage_buf_priv_t *prev = tail->prev;
+               prev->next = next;
+               next->prev = prev;
+               tail->next = tail->prev = NULL;
+               return tail->buf;
+       }
+
+       DRM_DEBUG("returning NULL, tail->buf=%p!\n", tail->buf);
+       return NULL;
+}
+
+void savage_freelist_put(drm_device_t *dev, drm_buf_t *buf)
+{
+       drm_savage_private_t *dev_priv = dev->dev_private;
+       drm_savage_buf_priv_t *entry = buf->dev_private, *prev, *next;
+
+       DRM_DEBUG("age=0x%04x wrap=%d\n", entry->age.event, entry->age.wrap);
+
+       if (entry->next != NULL || entry->prev != NULL) {
+               DRM_ERROR("entry already on freelist.\n");
+               return;
+       }
+
+       prev = &dev_priv->head;
+       next = prev->next;
+       prev->next = entry;
+       next->prev = entry;
+       entry->prev = prev;
+       entry->next = next;
+}
+
+/*
+ * Command DMA
+ */
+static int savage_dma_init(drm_savage_private_t *dev_priv)
+{
+       unsigned int i;
+
+       dev_priv->nr_dma_pages = dev_priv->cmd_dma->size /
+               (SAVAGE_DMA_PAGE_SIZE*4);
+       dev_priv->dma_pages = drm_alloc(sizeof(drm_savage_dma_page_t) *
+                                       dev_priv->nr_dma_pages,
+                                       DRM_MEM_DRIVER);
+       if (dev_priv->dma_pages == NULL)
+               return DRM_ERR(ENOMEM);
+
+       for (i = 0; i < dev_priv->nr_dma_pages; ++i) {
+               SET_AGE(&dev_priv->dma_pages[i].age, 0, 0);
+               dev_priv->dma_pages[i].used = 0;
+               dev_priv->dma_pages[i].flushed = 0;
+       }
+       SET_AGE(&dev_priv->last_dma_age, 0, 0);
+
+       dev_priv->first_dma_page = 0;
+       dev_priv->current_dma_page = 0;
+
+       return 0;
+}
+
+void savage_dma_reset(drm_savage_private_t *dev_priv)
+{
+       uint16_t event;
+       unsigned int wrap, i;
+       event = savage_bci_emit_event(dev_priv, 0);
+       wrap = dev_priv->event_wrap;
+       for (i = 0; i < dev_priv->nr_dma_pages; ++i) {
+               SET_AGE(&dev_priv->dma_pages[i].age, event, wrap);
+               dev_priv->dma_pages[i].used = 0;
+               dev_priv->dma_pages[i].flushed = 0;
+       }
+       SET_AGE(&dev_priv->last_dma_age, event, wrap);
+       dev_priv->first_dma_page = dev_priv->current_dma_page = 0;
+}
+
+void savage_dma_wait(drm_savage_private_t *dev_priv, unsigned int page)
+{
+       uint16_t event;
+       unsigned int wrap;
+
+       /* Faked DMA buffer pages don't age. */
+       if (dev_priv->cmd_dma == &dev_priv->fake_dma)
+               return;
+
+       UPDATE_EVENT_COUNTER();
+       if (dev_priv->status_ptr)
+               event = dev_priv->status_ptr[1] & 0xffff;
+       else
+               event = SAVAGE_READ(SAVAGE_STATUS_WORD1) & 0xffff;
+       wrap = dev_priv->event_wrap;
+       if (event > dev_priv->event_counter)
+               wrap--; /* hardware hasn't passed the last wrap yet */
+
+       if (dev_priv->dma_pages[page].age.wrap > wrap ||
+           (dev_priv->dma_pages[page].age.wrap == wrap &&
+            dev_priv->dma_pages[page].age.event > event)) {
+               if (dev_priv->wait_evnt(dev_priv,
+                                       dev_priv->dma_pages[page].age.event)
+                   < 0)
+                       DRM_ERROR("wait_evnt failed!\n");
+       }
+}
+
+uint32_t *savage_dma_alloc(drm_savage_private_t *dev_priv, unsigned int n)
+{
+       unsigned int cur = dev_priv->current_dma_page;
+       unsigned int rest = SAVAGE_DMA_PAGE_SIZE -
+               dev_priv->dma_pages[cur].used;
+       unsigned int nr_pages = (n - rest + SAVAGE_DMA_PAGE_SIZE-1) /
+               SAVAGE_DMA_PAGE_SIZE;
+       uint32_t *dma_ptr;
+       unsigned int i;
+
+       DRM_DEBUG("cur=%u, cur->used=%u, n=%u, rest=%u, nr_pages=%u\n",
+                 cur, dev_priv->dma_pages[cur].used, n, rest, nr_pages);
+
+       if (cur + nr_pages < dev_priv->nr_dma_pages) {
+               dma_ptr = (uint32_t *)dev_priv->cmd_dma->handle +
+                       cur*SAVAGE_DMA_PAGE_SIZE +
+                       dev_priv->dma_pages[cur].used;
+               if (n < rest)
+                       rest = n;
+               dev_priv->dma_pages[cur].used += rest;
+               n -= rest;
+               cur++;
+       } else {
+               dev_priv->dma_flush(dev_priv);
+               nr_pages = (n + SAVAGE_DMA_PAGE_SIZE-1) / SAVAGE_DMA_PAGE_SIZE;
+               for (i = cur; i < dev_priv->nr_dma_pages; ++i) {
+                       dev_priv->dma_pages[i].age = dev_priv->last_dma_age;
+                       dev_priv->dma_pages[i].used = 0;
+                       dev_priv->dma_pages[i].flushed = 0;
+               }
+               dma_ptr = (uint32_t *)dev_priv->cmd_dma->handle;
+               dev_priv->first_dma_page = cur = 0;
+       }
+       for (i = cur; nr_pages > 0; ++i, --nr_pages) {
+#if SAVAGE_DMA_DEBUG
+               if (dev_priv->dma_pages[i].used) {
+                       DRM_ERROR("unflushed page %u: used=%u\n",
+                                 i, dev_priv->dma_pages[i].used);
+               }
+#endif
+               if (n > SAVAGE_DMA_PAGE_SIZE)
+                       dev_priv->dma_pages[i].used = SAVAGE_DMA_PAGE_SIZE;
+               else
+                       dev_priv->dma_pages[i].used = n;
+               n -= SAVAGE_DMA_PAGE_SIZE;
+       }
+       dev_priv->current_dma_page = --i;
+
+       DRM_DEBUG("cur=%u, cur->used=%u, n=%u\n",
+                 i, dev_priv->dma_pages[i].used, n);
+
+       savage_dma_wait(dev_priv, dev_priv->current_dma_page);
+
+       return dma_ptr;
+}
+
+static void savage_dma_flush(drm_savage_private_t *dev_priv)
+{
+       unsigned int first = dev_priv->first_dma_page;
+       unsigned int cur = dev_priv->current_dma_page;
+       uint16_t event;
+       unsigned int wrap, pad, align, len, i;
+       unsigned long phys_addr;
+       BCI_LOCALS;
+
+       if (first == cur &&
+           dev_priv->dma_pages[cur].used == dev_priv->dma_pages[cur].flushed)
+               return;
+
+       /* pad length to multiples of 2 entries
+        * align start of next DMA block to multiles of 8 entries */
+       pad = -dev_priv->dma_pages[cur].used & 1;
+       align = -(dev_priv->dma_pages[cur].used + pad) & 7;
+
+       DRM_DEBUG("first=%u, cur=%u, first->flushed=%u, cur->used=%u, "
+                 "pad=%u, align=%u\n",
+                 first, cur, dev_priv->dma_pages[first].flushed,
+                 dev_priv->dma_pages[cur].used, pad, align);
+
+       /* pad with noops */
+       if (pad) {
+               uint32_t *dma_ptr = (uint32_t *)dev_priv->cmd_dma->handle +
+                       cur * SAVAGE_DMA_PAGE_SIZE +
+                       dev_priv->dma_pages[cur].used;
+               dev_priv->dma_pages[cur].used += pad;
+               while(pad != 0) {
+                       *dma_ptr++ = BCI_CMD_WAIT;
+                       pad--;
+               }
+       }
+
+       DRM_MEMORYBARRIER();
+
+       /* do flush ... */
+       phys_addr = dev_priv->cmd_dma->offset +
+               (first * SAVAGE_DMA_PAGE_SIZE +
+                dev_priv->dma_pages[first].flushed) * 4;
+       len = (cur - first) * SAVAGE_DMA_PAGE_SIZE +
+               dev_priv->dma_pages[cur].used -
+               dev_priv->dma_pages[first].flushed;
+
+       DRM_DEBUG("phys_addr=%lx, len=%u\n",
+                 phys_addr | dev_priv->dma_type, len);
+
+       BEGIN_BCI(3);
+       BCI_SET_REGISTERS(SAVAGE_DMABUFADDR, 1);
+       BCI_WRITE(phys_addr | dev_priv->dma_type);
+       BCI_DMA(len);
+
+       /* fix alignment of the start of the next block */
+       dev_priv->dma_pages[cur].used += align;
+
+       /* age DMA pages */
+       event = savage_bci_emit_event(dev_priv, 0);
+       wrap = dev_priv->event_wrap;
+       for (i = first; i < cur; ++i) {
+               SET_AGE(&dev_priv->dma_pages[i].age, event, wrap);
+               dev_priv->dma_pages[i].used = 0;
+               dev_priv->dma_pages[i].flushed = 0;
+       }
+       /* age the current page only when it's full */
+       if (dev_priv->dma_pages[cur].used == SAVAGE_DMA_PAGE_SIZE) {
+               SET_AGE(&dev_priv->dma_pages[cur].age, event, wrap);
+               dev_priv->dma_pages[cur].used = 0;
+               dev_priv->dma_pages[cur].flushed = 0;
+               /* advance to next page */
+               cur++;
+               if (cur == dev_priv->nr_dma_pages)
+                       cur = 0;
+               dev_priv->first_dma_page = dev_priv->current_dma_page = cur;
+       } else {
+               dev_priv->first_dma_page = cur;
+               dev_priv->dma_pages[cur].flushed = dev_priv->dma_pages[i].used;
+       }
+       SET_AGE(&dev_priv->last_dma_age, event, wrap);
+
+       DRM_DEBUG("first=cur=%u, cur->used=%u, cur->flushed=%u\n", cur,
+                 dev_priv->dma_pages[cur].used,
+                 dev_priv->dma_pages[cur].flushed);
+}
+
+static void savage_fake_dma_flush(drm_savage_private_t *dev_priv)
+{
+       unsigned int i, j;
+       BCI_LOCALS;
+
+       if (dev_priv->first_dma_page == dev_priv->current_dma_page &&
+           dev_priv->dma_pages[dev_priv->current_dma_page].used == 0)
+               return;
+
+       DRM_DEBUG("first=%u, cur=%u, cur->used=%u\n",
+                 dev_priv->first_dma_page, dev_priv->current_dma_page,
+                 dev_priv->dma_pages[dev_priv->current_dma_page].used);
+
+       for (i = dev_priv->first_dma_page;
+            i <= dev_priv->current_dma_page && dev_priv->dma_pages[i].used;
+            ++i) {
+               uint32_t *dma_ptr = (uint32_t *)dev_priv->cmd_dma->handle +
+                       i * SAVAGE_DMA_PAGE_SIZE;
+#if SAVAGE_DMA_DEBUG
+               /* Sanity check: all pages except the last one must be full. */
+               if (i < dev_priv->current_dma_page &&
+                   dev_priv->dma_pages[i].used != SAVAGE_DMA_PAGE_SIZE) {
+                       DRM_ERROR("partial DMA page %u: used=%u",
+                                 i, dev_priv->dma_pages[i].used);
+               }
+#endif
+               BEGIN_BCI(dev_priv->dma_pages[i].used);
+               for (j = 0; j < dev_priv->dma_pages[i].used; ++j) {
+                       BCI_WRITE(dma_ptr[j]);
+               }
+               dev_priv->dma_pages[i].used = 0;
+       }
+
+       /* reset to first page */
+       dev_priv->first_dma_page = dev_priv->current_dma_page = 0;
+}
+
+/*
+ * Initalize mappings. On Savage4 and SavageIX the alignment
+ * and size of the aperture is not suitable for automatic MTRR setup
+ * in drm_addmap. Therefore we do it manually before the maps are
+ * initialized. We also need to take care of deleting the MTRRs in
+ * postcleanup.
+ */
+int savage_preinit(drm_device_t *dev, unsigned long chipset)
+{
+       drm_savage_private_t *dev_priv;
+       unsigned long mmio_base, fb_base, fb_size, aperture_base;
+       /* fb_rsrc and aper_rsrc aren't really used currently, but still exist
+        * in case we decide we need information on the BAR for BSD in the
+        * future.
+        */
+       unsigned int fb_rsrc, aper_rsrc;
+       int ret = 0;
+
+       dev_priv = drm_alloc(sizeof(drm_savage_private_t), DRM_MEM_DRIVER);
+       if (dev_priv == NULL)
+               return DRM_ERR(ENOMEM);
+
+       memset(dev_priv, 0, sizeof(drm_savage_private_t));
+       dev->dev_private = (void *)dev_priv;
+       dev_priv->chipset = (enum savage_family)chipset;
+
+       dev_priv->mtrr[0].handle = -1;
+       dev_priv->mtrr[1].handle = -1;
+       dev_priv->mtrr[2].handle = -1;
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+               fb_rsrc = 0;
+               fb_base = drm_get_resource_start(dev, 0);
+               fb_size = SAVAGE_FB_SIZE_S3;
+               mmio_base = fb_base + SAVAGE_FB_SIZE_S3;
+               aper_rsrc = 0;
+               aperture_base = fb_base + SAVAGE_APERTURE_OFFSET;
+               /* this should always be true */
+               if (drm_get_resource_len(dev, 0) == 0x08000000) {
+                       /* Don't make MMIO write-cobining! We need 3
+                        * MTRRs. */
+                       dev_priv->mtrr[0].base = fb_base;
+                       dev_priv->mtrr[0].size = 0x01000000;
+                       dev_priv->mtrr[0].handle = mtrr_add(
+                               dev_priv->mtrr[0].base, dev_priv->mtrr[0].size,
+                               MTRR_TYPE_WRCOMB, 1);
+                       dev_priv->mtrr[1].base = fb_base+0x02000000;
+                       dev_priv->mtrr[1].size = 0x02000000;
+                       dev_priv->mtrr[1].handle = mtrr_add(
+                               dev_priv->mtrr[1].base, dev_priv->mtrr[1].size,
+                               MTRR_TYPE_WRCOMB, 1);
+                       dev_priv->mtrr[2].base = fb_base+0x04000000;
+                       dev_priv->mtrr[2].size = 0x04000000;
+                       dev_priv->mtrr[2].handle = mtrr_add(
+                               dev_priv->mtrr[2].base, dev_priv->mtrr[2].size,
+                               MTRR_TYPE_WRCOMB, 1);
+               } else {
+                       DRM_ERROR("strange pci_resource_len %08lx\n",
+                                 drm_get_resource_len(dev, 0));
+               }
+       } else if (chipset != S3_SUPERSAVAGE && chipset != S3_SAVAGE2000) {
+               mmio_base = drm_get_resource_start(dev, 0);
+               fb_rsrc = 1;
+               fb_base = drm_get_resource_start(dev, 1);
+               fb_size = SAVAGE_FB_SIZE_S4;
+               aper_rsrc = 1;
+               aperture_base = fb_base + SAVAGE_APERTURE_OFFSET;
+               /* this should always be true */
+               if (drm_get_resource_len(dev, 1) == 0x08000000) {
+                       /* Can use one MTRR to cover both fb and
+                        * aperture. */
+                       dev_priv->mtrr[0].base = fb_base;
+                       dev_priv->mtrr[0].size = 0x08000000;
+                       dev_priv->mtrr[0].handle = mtrr_add(
+                               dev_priv->mtrr[0].base, dev_priv->mtrr[0].size,
+                               MTRR_TYPE_WRCOMB, 1);
+               } else {
+                       DRM_ERROR("strange pci_resource_len %08lx\n",
+                                 drm_get_resource_len(dev, 1));
+               }
+       } else {
+               mmio_base = drm_get_resource_start(dev, 0);
+               fb_rsrc = 1;
+               fb_base = drm_get_resource_start(dev, 1);
+               fb_size = drm_get_resource_len(dev, 1);
+               aper_rsrc = 2;
+               aperture_base = drm_get_resource_start(dev, 2);
+               /* Automatic MTRR setup will do the right thing. */
+       }
+
+       ret = drm_addmap(dev, mmio_base, SAVAGE_MMIO_SIZE, _DRM_REGISTERS,
+                        _DRM_READ_ONLY, &dev_priv->mmio);
+       if (ret)
+               return ret;
+
+       ret = drm_addmap(dev, fb_base, fb_size, _DRM_FRAME_BUFFER,
+                        _DRM_WRITE_COMBINING, &dev_priv->fb);
+       if (ret)
+               return ret;
+
+       ret = drm_addmap(dev, aperture_base, SAVAGE_APERTURE_SIZE,
+                        _DRM_FRAME_BUFFER, _DRM_WRITE_COMBINING,
+                        &dev_priv->aperture);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
+/*
+ * Delete MTRRs and free device-private data.
+ */
+int savage_postcleanup(drm_device_t *dev)
+{
+       drm_savage_private_t *dev_priv = dev->dev_private;
+       int i;
+
+       for (i = 0; i < 3; ++i)
+               if (dev_priv->mtrr[i].handle >= 0)
+                       mtrr_del(dev_priv->mtrr[i].handle,
+                                dev_priv->mtrr[i].base,
+                                dev_priv->mtrr[i].size);
+
+       drm_free(dev_priv, sizeof(drm_savage_private_t), DRM_MEM_DRIVER);
+
+       return 0;
+}
+
+static int savage_do_init_bci(drm_device_t *dev, drm_savage_init_t *init)
+{
+       drm_savage_private_t *dev_priv = dev->dev_private;
+
+       if (init->fb_bpp != 16 && init->fb_bpp != 32) {
+               DRM_ERROR("invalid frame buffer bpp %d!\n", init->fb_bpp);
+               return DRM_ERR(EINVAL);
+       }
+       if (init->depth_bpp != 16 && init->depth_bpp != 32) {
+               DRM_ERROR("invalid depth buffer bpp %d!\n", init->fb_bpp);
+               return DRM_ERR(EINVAL);
+       }
+       if (init->dma_type != SAVAGE_DMA_AGP &&
+           init->dma_type != SAVAGE_DMA_PCI) {
+               DRM_ERROR("invalid dma memory type %d!\n", init->dma_type);
+               return DRM_ERR(EINVAL);
+       }
+
+       dev_priv->cob_size = init->cob_size;
+       dev_priv->bci_threshold_lo = init->bci_threshold_lo;
+       dev_priv->bci_threshold_hi = init->bci_threshold_hi;
+       dev_priv->dma_type = init->dma_type;
+
+       dev_priv->fb_bpp = init->fb_bpp;
+       dev_priv->front_offset = init->front_offset;
+       dev_priv->front_pitch = init->front_pitch;
+       dev_priv->back_offset = init->back_offset;
+       dev_priv->back_pitch = init->back_pitch;
+       dev_priv->depth_bpp = init->depth_bpp;
+       dev_priv->depth_offset = init->depth_offset;
+       dev_priv->depth_pitch = init->depth_pitch;
+
+       dev_priv->texture_offset = init->texture_offset;
+       dev_priv->texture_size = init->texture_size;
+
+       DRM_GETSAREA();
+       if (!dev_priv->sarea) {
+               DRM_ERROR("could not find sarea!\n");
+               savage_do_cleanup_bci(dev);
+               return DRM_ERR(EINVAL);
+       }
+       if (init->status_offset != 0) {
+               dev_priv->status = drm_core_findmap(dev, init->status_offset);
+               if (!dev_priv->status) {
+                       DRM_ERROR("could not find shadow status region!\n");
+                       savage_do_cleanup_bci(dev);
+                       return DRM_ERR(EINVAL);
+               }
+       } else {
+               dev_priv->status = NULL;
+       }
+       if (dev_priv->dma_type == SAVAGE_DMA_AGP && init->buffers_offset) {
+               dev->agp_buffer_map = drm_core_findmap(dev,
+                                                      init->buffers_offset);
+               if (!dev->agp_buffer_map) {
+                       DRM_ERROR("could not find DMA buffer region!\n");
+                       savage_do_cleanup_bci(dev);
+                       return DRM_ERR(EINVAL);
+               }
+               drm_core_ioremap(dev->agp_buffer_map, dev);
+               if (!dev->agp_buffer_map) {
+                       DRM_ERROR("failed to ioremap DMA buffer region!\n");
+                       savage_do_cleanup_bci(dev);
+                       return DRM_ERR(ENOMEM);
+               }
+       }
+       if (init->agp_textures_offset) {
+               dev_priv->agp_textures =
+                       drm_core_findmap(dev, init->agp_textures_offset);
+               if (!dev_priv->agp_textures) {
+                       DRM_ERROR("could not find agp texture region!\n");
+                       savage_do_cleanup_bci(dev);
+                       return DRM_ERR(EINVAL);
+               }
+       } else {
+               dev_priv->agp_textures = NULL;
+       }
+
+       if (init->cmd_dma_offset) {
+               if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+                       DRM_ERROR("command DMA not supported on "
+                                 "Savage3D/MX/IX.\n");
+                       savage_do_cleanup_bci(dev);
+                       return DRM_ERR(EINVAL);
+               }
+               if (dev->dma && dev->dma->buflist) {
+                       DRM_ERROR("command and vertex DMA not supported "
+                                 "at the same time.\n");
+                       savage_do_cleanup_bci(dev);
+                       return DRM_ERR(EINVAL);
+               }
+               dev_priv->cmd_dma = drm_core_findmap(dev, init->cmd_dma_offset);
+               if (!dev_priv->cmd_dma) {
+                       DRM_ERROR("could not find command DMA region!\n");
+                       savage_do_cleanup_bci(dev);
+                       return DRM_ERR(EINVAL);
+               }
+               if (dev_priv->dma_type == SAVAGE_DMA_AGP) {
+                       if (dev_priv->cmd_dma->type != _DRM_AGP) {
+                               DRM_ERROR("AGP command DMA region is not a "
+                                         "_DRM_AGP map!\n");
+                               savage_do_cleanup_bci(dev);
+                               return DRM_ERR(EINVAL);
+                       }
+                       drm_core_ioremap(dev_priv->cmd_dma, dev);
+                       if (!dev_priv->cmd_dma->handle) {
+                               DRM_ERROR("failed to ioremap command "
+                                         "DMA region!\n");
+                               savage_do_cleanup_bci(dev);
+                               return DRM_ERR(ENOMEM);
+                       }
+               } else if (dev_priv->cmd_dma->type != _DRM_CONSISTENT) {
+                       DRM_ERROR("PCI command DMA region is not a "
+                                 "_DRM_CONSISTENT map!\n");
+                       savage_do_cleanup_bci(dev);
+                       return DRM_ERR(EINVAL);
+               }
+       } else {
+               dev_priv->cmd_dma = NULL;
+       }
+
+       dev_priv->dma_flush = savage_dma_flush;
+       if (!dev_priv->cmd_dma) {
+               DRM_DEBUG("falling back to faked command DMA.\n");
+               dev_priv->fake_dma.offset = 0;
+               dev_priv->fake_dma.size = SAVAGE_FAKE_DMA_SIZE;
+               dev_priv->fake_dma.type = _DRM_SHM;
+               dev_priv->fake_dma.handle = drm_alloc(SAVAGE_FAKE_DMA_SIZE,
+                                                     DRM_MEM_DRIVER);
+               if (!dev_priv->fake_dma.handle) {
+                       DRM_ERROR("could not allocate faked DMA buffer!\n");
+                       savage_do_cleanup_bci(dev);
+                       return DRM_ERR(ENOMEM);
+               }
+               dev_priv->cmd_dma = &dev_priv->fake_dma;
+               dev_priv->dma_flush = savage_fake_dma_flush;
+       }
+
+       dev_priv->sarea_priv =
+               (drm_savage_sarea_t *)((uint8_t *)dev_priv->sarea->handle +
+                                      init->sarea_priv_offset);
+
+       /* setup bitmap descriptors */
+       {
+               unsigned int color_tile_format;
+               unsigned int depth_tile_format;
+               unsigned int front_stride, back_stride, depth_stride;
+               if (dev_priv->chipset <= S3_SAVAGE4) {
+                       color_tile_format = dev_priv->fb_bpp == 16 ?
+                               SAVAGE_BD_TILE_16BPP : SAVAGE_BD_TILE_32BPP;
+                       depth_tile_format = dev_priv->depth_bpp == 16 ?
+                               SAVAGE_BD_TILE_16BPP : SAVAGE_BD_TILE_32BPP;
+               } else {
+                       color_tile_format = SAVAGE_BD_TILE_DEST;
+                       depth_tile_format = SAVAGE_BD_TILE_DEST;
+               }
+               front_stride = dev_priv->front_pitch / (dev_priv->fb_bpp/8);
+               back_stride  = dev_priv-> back_pitch / (dev_priv->fb_bpp/8);
+               depth_stride = dev_priv->depth_pitch / (dev_priv->depth_bpp/8);
+
+               dev_priv->front_bd = front_stride | SAVAGE_BD_BW_DISABLE |
+                       (dev_priv->fb_bpp << SAVAGE_BD_BPP_SHIFT) |
+                       (color_tile_format << SAVAGE_BD_TILE_SHIFT);
+
+               dev_priv-> back_bd =  back_stride | SAVAGE_BD_BW_DISABLE |
+                       (dev_priv->fb_bpp << SAVAGE_BD_BPP_SHIFT) |
+                       (color_tile_format << SAVAGE_BD_TILE_SHIFT);
+
+               dev_priv->depth_bd = depth_stride | SAVAGE_BD_BW_DISABLE |
+                       (dev_priv->depth_bpp << SAVAGE_BD_BPP_SHIFT) |
+                       (depth_tile_format << SAVAGE_BD_TILE_SHIFT);
+       }
+
+       /* setup status and bci ptr */
+       dev_priv->event_counter = 0;
+       dev_priv->event_wrap = 0;
+       dev_priv->bci_ptr = (volatile uint32_t *)
+           ((uint8_t *)dev_priv->mmio->handle + SAVAGE_BCI_OFFSET);
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+               dev_priv->status_used_mask = SAVAGE_FIFO_USED_MASK_S3D;
+       } else {
+               dev_priv->status_used_mask = SAVAGE_FIFO_USED_MASK_S4;
+       }
+       if (dev_priv->status != NULL) {
+               dev_priv->status_ptr =
+                       (volatile uint32_t *)dev_priv->status->handle;
+               dev_priv->wait_fifo = savage_bci_wait_fifo_shadow;
+               dev_priv->wait_evnt = savage_bci_wait_event_shadow;
+               dev_priv->status_ptr[1023] = dev_priv->event_counter;
+       } else {
+               dev_priv->status_ptr = NULL;
+               if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+                       dev_priv->wait_fifo = savage_bci_wait_fifo_s3d;
+               } else {
+                       dev_priv->wait_fifo = savage_bci_wait_fifo_s4;
+               }
+               dev_priv->wait_evnt = savage_bci_wait_event_reg;
+       }
+
+       /* cliprect functions */
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset))
+               dev_priv->emit_clip_rect = savage_emit_clip_rect_s3d;
+       else
+               dev_priv->emit_clip_rect = savage_emit_clip_rect_s4;
+
+       if (savage_freelist_init(dev) < 0) {
+               DRM_ERROR("could not initialize freelist\n");
+               savage_do_cleanup_bci(dev);
+               return DRM_ERR(ENOMEM);
+       }
+
+       if (savage_dma_init(dev_priv) <  0) {
+               DRM_ERROR("could not initialize command DMA\n");
+               savage_do_cleanup_bci(dev);
+               return DRM_ERR(ENOMEM);
+       }
+
+       return 0;
+}
+
+int savage_do_cleanup_bci(drm_device_t *dev)
+{
+       drm_savage_private_t *dev_priv = dev->dev_private;
+
+       if (dev_priv->cmd_dma == &dev_priv->fake_dma) {
+               if (dev_priv->fake_dma.handle)
+                       drm_free(dev_priv->fake_dma.handle,
+                                SAVAGE_FAKE_DMA_SIZE, DRM_MEM_DRIVER);
+       } else if (dev_priv->cmd_dma && dev_priv->cmd_dma->handle &&
+                  dev_priv->cmd_dma->type == _DRM_AGP &&
+                  dev_priv->dma_type == SAVAGE_DMA_AGP)
+               drm_core_ioremapfree(dev_priv->cmd_dma, dev);
+
+       if (dev_priv->dma_type == SAVAGE_DMA_AGP &&
+           dev->agp_buffer_map && dev->agp_buffer_map->handle) {
+               drm_core_ioremapfree(dev->agp_buffer_map, dev);
+               /* make sure the next instance (which may be running
+                * in PCI mode) doesn't try to use an old
+                * agp_buffer_map. */
+               dev->agp_buffer_map = NULL;
+       }
+
+       if (dev_priv->dma_pages)
+               drm_free(dev_priv->dma_pages,
+                        sizeof(drm_savage_dma_page_t)*dev_priv->nr_dma_pages,
+                        DRM_MEM_DRIVER);
+
+       return 0;
+}
+
+static int savage_bci_init(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_savage_init_t init;
+
+       LOCK_TEST_WITH_RETURN(dev, filp);
+
+       DRM_COPY_FROM_USER_IOCTL(init, (drm_savage_init_t __user *)data,
+                                sizeof(init));
+
+       switch (init.func) {
+       case SAVAGE_INIT_BCI:
+               return savage_do_init_bci(dev, &init);
+       case SAVAGE_CLEANUP_BCI:
+               return savage_do_cleanup_bci(dev);
+       }
+
+       return DRM_ERR(EINVAL);
+}
+
+static int savage_bci_event_emit(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_savage_private_t *dev_priv = dev->dev_private;
+       drm_savage_event_emit_t event;
+
+       DRM_DEBUG("\n");
+
+       LOCK_TEST_WITH_RETURN(dev, filp);
+
+       DRM_COPY_FROM_USER_IOCTL(event, (drm_savage_event_emit_t __user *)data,
+                                sizeof(event));
+
+       event.count = savage_bci_emit_event(dev_priv, event.flags);
+       event.count |= dev_priv->event_wrap << 16;
+       DRM_COPY_TO_USER_IOCTL(&((drm_savage_event_emit_t __user *)data)->count,
+                              event.count, sizeof(event.count));
+       return 0;
+}
+
+static int savage_bci_event_wait(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_savage_private_t *dev_priv = dev->dev_private;
+       drm_savage_event_wait_t event;
+       unsigned int event_e, hw_e;
+       unsigned int event_w, hw_w;
+
+       DRM_DEBUG("\n");
+
+       DRM_COPY_FROM_USER_IOCTL(event, (drm_savage_event_wait_t __user *)data,
+                                sizeof(event));
+
+       UPDATE_EVENT_COUNTER();
+       if (dev_priv->status_ptr)
+               hw_e = dev_priv->status_ptr[1] & 0xffff;
+       else
+               hw_e = SAVAGE_READ(SAVAGE_STATUS_WORD1) & 0xffff;
+       hw_w = dev_priv->event_wrap;
+       if (hw_e > dev_priv->event_counter)
+               hw_w--; /* hardware hasn't passed the last wrap yet */
+
+       event_e = event.count & 0xffff;
+       event_w = event.count >> 16;
+
+       /* Don't need to wait if
+        * - event counter wrapped since the event was emitted or
+        * - the hardware has advanced up to or over the event to wait for.
+        */
+       if (event_w < hw_w || (event_w == hw_w && event_e <= hw_e) )
+               return 0;
+       else
+               return dev_priv->wait_evnt(dev_priv, event_e);
+}
+
+/*
+ * DMA buffer management
+ */
+
+static int savage_bci_get_buffers(DRMFILE filp, drm_device_t *dev, drm_dma_t *d)
+{
+       drm_buf_t *buf;
+       int i;
+
+       for (i = d->granted_count; i < d->request_count; i++) {
+               buf = savage_freelist_get(dev);
+               if (!buf)
+                       return DRM_ERR(EAGAIN);
+
+               buf->filp = filp;
+
+               if (DRM_COPY_TO_USER(&d->request_indices[i],
+                                    &buf->idx, sizeof(buf->idx)))
+                       return DRM_ERR(EFAULT);
+               if (DRM_COPY_TO_USER(&d->request_sizes[i],
+                                    &buf->total, sizeof(buf->total)))
+                       return DRM_ERR(EFAULT);
+
+               d->granted_count++;
+       }
+       return 0;
+}
+
+int savage_bci_buffers(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_device_dma_t *dma = dev->dma;
+       drm_dma_t d;
+       int ret = 0;
+
+       LOCK_TEST_WITH_RETURN(dev, filp);
+
+       DRM_COPY_FROM_USER_IOCTL(d, (drm_dma_t __user *)data, sizeof(d));
+
+       /* Please don't send us buffers.
+        */
+       if (d.send_count != 0) {
+               DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
+                         DRM_CURRENTPID, d.send_count);
+               return DRM_ERR(EINVAL);
+       }
+
+       /* We'll send you buffers.
+        */
+       if (d.request_count < 0 || d.request_count > dma->buf_count) {
+               DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
+                         DRM_CURRENTPID, d.request_count, dma->buf_count);
+               return DRM_ERR(EINVAL);
+       }
+
+       d.granted_count = 0;
+
+       if (d.request_count) {
+               ret = savage_bci_get_buffers(filp, dev, &d);
+       }
+
+       DRM_COPY_TO_USER_IOCTL((drm_dma_t __user *)data, d, sizeof(d));
+
+       return ret;
+}
+
+void savage_reclaim_buffers(drm_device_t *dev, DRMFILE filp) {
+       drm_device_dma_t *dma = dev->dma;
+       drm_savage_private_t *dev_priv = dev->dev_private;
+       int i;
+
+       if (!dma)
+               return;
+       if (!dev_priv)
+               return;
+       if (!dma->buflist)
+               return;
+
+       /*i830_flush_queue(dev);*/
+
+       for (i = 0; i < dma->buf_count; i++) {
+               drm_buf_t *buf = dma->buflist[i];
+               drm_savage_buf_priv_t *buf_priv = buf->dev_private;
+
+               if (buf->filp == filp && buf_priv &&
+                   buf_priv->next == NULL && buf_priv->prev == NULL) {
+                       uint16_t event;
+                       DRM_DEBUG("reclaimed from client\n");
+                       event = savage_bci_emit_event(dev_priv, SAVAGE_WAIT_3D);
+                       SET_AGE(&buf_priv->age, event, dev_priv->event_wrap);
+                       savage_freelist_put(dev, buf);
+               }
+       }
+
+       drm_core_reclaim_buffers(dev, filp);
+}
+
+
+drm_ioctl_desc_t savage_ioctls[] = {
+       [DRM_IOCTL_NR(DRM_SAVAGE_BCI_INIT)] = {savage_bci_init, 1, 1},
+       [DRM_IOCTL_NR(DRM_SAVAGE_BCI_CMDBUF)] = {savage_bci_cmdbuf, 1, 0},
+       [DRM_IOCTL_NR(DRM_SAVAGE_BCI_EVENT_EMIT)] = {savage_bci_event_emit, 1, 0},
+       [DRM_IOCTL_NR(DRM_SAVAGE_BCI_EVENT_WAIT)] = {savage_bci_event_wait, 1, 0},
+};
+
+int savage_max_ioctl = DRM_ARRAY_SIZE(savage_ioctls);
diff --git a/drivers/char/drm/savage_drm.h b/drivers/char/drm/savage_drm.h
new file mode 100644 (file)
index 0000000..6526c9a
--- /dev/null
@@ -0,0 +1,209 @@
+/* savage_drm.h -- Public header for the savage driver
+ *
+ * Copyright 2004  Felix Kuehling
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __SAVAGE_DRM_H__
+#define __SAVAGE_DRM_H__
+
+#ifndef __SAVAGE_SAREA_DEFINES__
+#define __SAVAGE_SAREA_DEFINES__
+
+/* 2 heaps (1 for card, 1 for agp), each divided into upto 128
+ * regions, subject to a minimum region size of (1<<16) == 64k.
+ *
+ * Clients may subdivide regions internally, but when sharing between
+ * clients, the region size is the minimum granularity.
+ */
+
+#define SAVAGE_CARD_HEAP               0
+#define SAVAGE_AGP_HEAP                        1
+#define SAVAGE_NR_TEX_HEAPS            2
+#define SAVAGE_NR_TEX_REGIONS          16
+#define SAVAGE_LOG_MIN_TEX_REGION_SIZE 16
+
+#endif /* __SAVAGE_SAREA_DEFINES__ */
+
+typedef struct _drm_savage_sarea {
+       /* LRU lists for texture memory in agp space and on the card.
+        */
+       drm_tex_region_t texList[SAVAGE_NR_TEX_HEAPS][SAVAGE_NR_TEX_REGIONS+1];
+       unsigned int texAge[SAVAGE_NR_TEX_HEAPS];
+
+       /* Mechanism to validate card state.
+        */
+       int ctxOwner;
+} drm_savage_sarea_t, *drm_savage_sarea_ptr;
+
+/* Savage-specific ioctls
+ */
+#define DRM_SAVAGE_BCI_INIT            0x00
+#define DRM_SAVAGE_BCI_CMDBUF           0x01
+#define DRM_SAVAGE_BCI_EVENT_EMIT      0x02
+#define DRM_SAVAGE_BCI_EVENT_WAIT      0x03
+
+#define DRM_IOCTL_SAVAGE_INIT          DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_INIT, drm_savage_init_t)
+#define DRM_IOCTL_SAVAGE_CMDBUF                DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_CMDBUF, drm_savage_cmdbuf_t)
+#define DRM_IOCTL_SAVAGE_EVENT_EMIT    DRM_IOWR(DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_EMIT, drm_savage_event_emit_t)
+#define DRM_IOCTL_SAVAGE_EVENT_WAIT    DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_WAIT, drm_savage_event_wait_t)
+
+#define SAVAGE_DMA_PCI 1
+#define SAVAGE_DMA_AGP 3
+typedef struct drm_savage_init {
+       enum {
+               SAVAGE_INIT_BCI = 1,
+               SAVAGE_CLEANUP_BCI = 2
+       } func;
+       unsigned int sarea_priv_offset;
+
+       /* some parameters */
+       unsigned int cob_size;
+       unsigned int bci_threshold_lo, bci_threshold_hi;
+       unsigned int dma_type;
+
+       /* frame buffer layout */
+       unsigned int fb_bpp;
+       unsigned int front_offset, front_pitch;
+       unsigned int back_offset, back_pitch;
+       unsigned int depth_bpp;
+       unsigned int depth_offset, depth_pitch;
+
+       /* local textures */
+       unsigned int texture_offset;
+       unsigned int texture_size;
+
+       /* physical locations of non-permanent maps */
+       unsigned long status_offset;
+       unsigned long buffers_offset;
+       unsigned long agp_textures_offset;
+       unsigned long cmd_dma_offset;
+} drm_savage_init_t;
+
+typedef union drm_savage_cmd_header drm_savage_cmd_header_t;
+typedef struct drm_savage_cmdbuf {
+                               /* command buffer in client's address space */
+       drm_savage_cmd_header_t __user *cmd_addr;
+       unsigned int size;      /* size of the command buffer in 64bit units */
+
+       unsigned int dma_idx;   /* DMA buffer index to use */
+       int discard;            /* discard DMA buffer when done */
+                               /* vertex buffer in client's address space */
+       unsigned int __user *vb_addr;
+       unsigned int vb_size;   /* size of client vertex buffer in bytes */
+       unsigned int vb_stride; /* stride of vertices in 32bit words */
+                               /* boxes in client's address space */
+       drm_clip_rect_t __user *box_addr;
+       unsigned int nbox;      /* number of clipping boxes */
+} drm_savage_cmdbuf_t;
+
+#define SAVAGE_WAIT_2D  0x1 /* wait for 2D idle before updating event tag */
+#define SAVAGE_WAIT_3D  0x2 /* wait for 3D idle before updating event tag */
+#define SAVAGE_WAIT_IRQ 0x4 /* emit or wait for IRQ, not implemented yet */
+typedef struct drm_savage_event {
+       unsigned int count;
+       unsigned int flags;
+} drm_savage_event_emit_t, drm_savage_event_wait_t;
+
+/* Commands for the cmdbuf ioctl
+ */
+#define SAVAGE_CMD_STATE       0  /* a range of state registers */
+#define SAVAGE_CMD_DMA_PRIM    1  /* vertices from DMA buffer */
+#define SAVAGE_CMD_VB_PRIM     2  /* vertices from client vertex buffer */
+#define SAVAGE_CMD_DMA_IDX     3  /* indexed vertices from DMA buffer */
+#define SAVAGE_CMD_VB_IDX      4  /* indexed vertices client vertex buffer */
+#define SAVAGE_CMD_CLEAR       5  /* clear buffers */
+#define SAVAGE_CMD_SWAP                6  /* swap buffers */
+
+/* Primitive types
+*/
+#define SAVAGE_PRIM_TRILIST    0  /* triangle list */
+#define SAVAGE_PRIM_TRISTRIP   1  /* triangle strip */
+#define SAVAGE_PRIM_TRIFAN     2  /* triangle fan */
+#define SAVAGE_PRIM_TRILIST_201        3  /* reorder verts for correct flat
+                                   * shading on s3d */
+
+/* Skip flags (vertex format)
+ */
+#define SAVAGE_SKIP_Z          0x01
+#define SAVAGE_SKIP_W          0x02
+#define SAVAGE_SKIP_C0         0x04
+#define SAVAGE_SKIP_C1         0x08
+#define SAVAGE_SKIP_S0         0x10
+#define SAVAGE_SKIP_T0         0x20
+#define SAVAGE_SKIP_ST0                0x30
+#define SAVAGE_SKIP_S1         0x40
+#define SAVAGE_SKIP_T1         0x80
+#define SAVAGE_SKIP_ST1                0xc0
+#define SAVAGE_SKIP_ALL_S3D    0x3f
+#define SAVAGE_SKIP_ALL_S4     0xff
+
+/* Buffer names for clear command
+ */
+#define SAVAGE_FRONT           0x1
+#define SAVAGE_BACK            0x2
+#define SAVAGE_DEPTH           0x4
+
+/* 64-bit command header
+ */
+union drm_savage_cmd_header {
+       struct {
+               unsigned char cmd;      /* command */
+               unsigned char pad0;
+               unsigned short pad1;
+               unsigned short pad2;
+               unsigned short pad3;
+       } cmd; /* generic */
+       struct {
+               unsigned char cmd;
+               unsigned char global;   /* need idle engine? */
+               unsigned short count;   /* number of consecutive registers */
+               unsigned short start;   /* first register */
+               unsigned short pad3;
+       } state; /* SAVAGE_CMD_STATE */
+       struct {
+               unsigned char cmd;
+               unsigned char prim;     /* primitive type */
+               unsigned short skip;    /* vertex format (skip flags) */
+               unsigned short count;   /* number of vertices */
+               unsigned short start;   /* first vertex in DMA/vertex buffer */
+       } prim; /* SAVAGE_CMD_DMA_PRIM, SAVAGE_CMD_VB_PRIM */
+       struct {
+               unsigned char cmd;
+               unsigned char prim;
+               unsigned short skip;
+               unsigned short count;   /* number of indices that follow */
+               unsigned short pad3;
+       } idx; /* SAVAGE_CMD_DMA_IDX, SAVAGE_CMD_VB_IDX */
+       struct {
+               unsigned char cmd;
+               unsigned char pad0;
+               unsigned short pad1;
+               unsigned int flags;
+       } clear0; /* SAVAGE_CMD_CLEAR */
+       struct {
+               unsigned int mask;
+               unsigned int value;
+       } clear1; /* SAVAGE_CMD_CLEAR data */
+};
+
+#endif
diff --git a/drivers/char/drm/savage_drv.c b/drivers/char/drm/savage_drv.c
new file mode 100644 (file)
index 0000000..ac8d270
--- /dev/null
@@ -0,0 +1,112 @@
+/* savage_drv.c -- Savage driver for Linux
+ *
+ * Copyright 2004  Felix Kuehling
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/config.h>
+#include "drmP.h"
+#include "savage_drm.h"
+#include "savage_drv.h"
+
+#include "drm_pciids.h"
+
+static int postinit( struct drm_device *dev, unsigned long flags )
+{
+       DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d: %s\n",
+               DRIVER_NAME,
+               DRIVER_MAJOR,
+               DRIVER_MINOR,
+               DRIVER_PATCHLEVEL,
+               DRIVER_DATE,
+               dev->primary.minor,
+               pci_pretty_name(dev->pdev)
+               );
+       return 0;
+}
+
+static int version( drm_version_t *version )
+{
+       int len;
+
+       version->version_major = DRIVER_MAJOR;
+       version->version_minor = DRIVER_MINOR;
+       version->version_patchlevel = DRIVER_PATCHLEVEL;
+       DRM_COPY( version->name, DRIVER_NAME );
+       DRM_COPY( version->date, DRIVER_DATE );
+       DRM_COPY( version->desc, DRIVER_DESC );
+       return 0;
+}
+
+static struct pci_device_id pciidlist[] = {
+       savage_PCI_IDS
+};
+
+extern drm_ioctl_desc_t savage_ioctls[];
+extern int savage_max_ioctl;
+
+static struct drm_driver driver = {
+       .driver_features =
+           DRIVER_USE_AGP | DRIVER_USE_MTRR |
+           DRIVER_HAVE_DMA | DRIVER_PCI_DMA,
+       .dev_priv_size = sizeof(drm_savage_buf_priv_t),
+       .preinit = savage_preinit,
+       .postinit = postinit,
+       .postcleanup = savage_postcleanup,
+       .reclaim_buffers = savage_reclaim_buffers,
+       .get_map_ofs = drm_core_get_map_ofs,
+       .get_reg_ofs = drm_core_get_reg_ofs,
+       .version = version,
+       .ioctls = savage_ioctls,
+       .dma_ioctl = savage_bci_buffers,
+       .fops = {
+               .owner   = THIS_MODULE,
+               .open    = drm_open,
+               .release = drm_release,
+               .ioctl   = drm_ioctl,
+               .mmap    = drm_mmap,
+               .poll = drm_poll,
+               .fasync  = drm_fasync,
+       },
+       .pci_driver = {
+               .name          = DRIVER_NAME,
+               .id_table      = pciidlist,
+       }
+};
+
+static int __init savage_init(void)
+{
+       driver.num_ioctls = savage_max_ioctl;
+       return drm_init(&driver);
+}
+
+static void __exit savage_exit(void)
+{
+       drm_exit(&driver);
+}
+
+module_init(savage_init);
+module_exit(savage_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/char/drm/savage_drv.h b/drivers/char/drm/savage_drv.h
new file mode 100644 (file)
index 0000000..a454349
--- /dev/null
@@ -0,0 +1,579 @@
+/* savage_drv.h -- Private header for the savage driver
+ *
+ * Copyright 2004  Felix Kuehling
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __SAVAGE_DRV_H__
+#define __SAVAGE_DRV_H__
+
+#define DRIVER_AUTHOR  "Felix Kuehling"
+
+#define DRIVER_NAME    "savage"
+#define DRIVER_DESC    "Savage3D/MX/IX, Savage4, SuperSavage, Twister, ProSavage[DDR]"
+#define DRIVER_DATE    "20050313"
+
+#define DRIVER_MAJOR           2
+#define DRIVER_MINOR           4
+#define DRIVER_PATCHLEVEL      1
+/* Interface history:
+ *
+ * 1.x   The DRM driver from the VIA/S3 code drop, basically a dummy
+ * 2.0   The first real DRM
+ * 2.1   Scissors registers managed by the DRM, 3D operations clipped by
+ *       cliprects of the cmdbuf ioctl
+ * 2.2   Implemented SAVAGE_CMD_DMA_IDX and SAVAGE_CMD_VB_IDX
+ * 2.3   Event counters used by BCI_EVENT_EMIT/WAIT ioctls are now 32 bits
+ *       wide and thus very long lived (unlikely to ever wrap). The size
+ *       in the struct was 32 bits before, but only 16 bits were used
+ * 2.4   Implemented command DMA. Now drm_savage_init_t.cmd_dma_offset is
+ *       actually used
+ */
+
+typedef struct drm_savage_age {
+       uint16_t event;
+       unsigned int wrap;
+} drm_savage_age_t;
+
+typedef struct drm_savage_buf_priv {
+       struct drm_savage_buf_priv *next;
+       struct drm_savage_buf_priv *prev;
+       drm_savage_age_t age;
+       drm_buf_t *buf;
+} drm_savage_buf_priv_t;
+
+typedef struct drm_savage_dma_page {
+       drm_savage_age_t age;
+       unsigned int used, flushed;
+} drm_savage_dma_page_t;
+#define SAVAGE_DMA_PAGE_SIZE 1024 /* in dwords */
+/* Fake DMA buffer size in bytes. 4 pages. Allows a maximum command
+ * size of 16kbytes or 4k entries. Minimum requirement would be
+ * 10kbytes for 255 40-byte vertices in one drawing command. */
+#define SAVAGE_FAKE_DMA_SIZE (SAVAGE_DMA_PAGE_SIZE*4*4)
+
+/* interesting bits of hardware state that are saved in dev_priv */
+typedef union {
+       struct drm_savage_common_state {
+               uint32_t vbaddr;
+       } common;
+       struct {
+               unsigned char pad[sizeof(struct drm_savage_common_state)];
+               uint32_t texctrl, texaddr;
+               uint32_t scstart, new_scstart;
+               uint32_t scend, new_scend;
+       } s3d;
+       struct {
+               unsigned char pad[sizeof(struct drm_savage_common_state)];
+               uint32_t texdescr, texaddr0, texaddr1;
+               uint32_t drawctrl0, new_drawctrl0;
+               uint32_t drawctrl1, new_drawctrl1;
+       } s4;
+} drm_savage_state_t;
+
+/* these chip tags should match the ones in the 2D driver in savage_regs.h. */
+enum savage_family {
+       S3_UNKNOWN = 0,
+       S3_SAVAGE3D,
+       S3_SAVAGE_MX,
+       S3_SAVAGE4,
+       S3_PROSAVAGE,
+       S3_TWISTER,
+       S3_PROSAVAGEDDR,
+       S3_SUPERSAVAGE,
+       S3_SAVAGE2000,
+       S3_LAST
+};
+
+#define S3_SAVAGE3D_SERIES(chip)  ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX))
+
+#define S3_SAVAGE4_SERIES(chip)  ((chip==S3_SAVAGE4)            \
+                                  || (chip==S3_PROSAVAGE)       \
+                                  || (chip==S3_TWISTER)         \
+                                  || (chip==S3_PROSAVAGEDDR))
+
+#define        S3_SAVAGE_MOBILE_SERIES(chip)   ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE))
+
+#define S3_SAVAGE_SERIES(chip)    ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000))
+
+#define S3_MOBILE_TWISTER_SERIES(chip)   ((chip==S3_TWISTER)    \
+                                          ||(chip==S3_PROSAVAGEDDR))
+
+/* flags */
+#define SAVAGE_IS_AGP 1
+
+typedef struct drm_savage_private {
+       drm_savage_sarea_t *sarea_priv;
+
+       drm_savage_buf_priv_t head, tail;
+
+       /* who am I? */
+       enum savage_family chipset;
+
+       unsigned int cob_size;
+       unsigned int bci_threshold_lo, bci_threshold_hi;
+       unsigned int dma_type;
+
+       /* frame buffer layout */
+       unsigned int fb_bpp;
+       unsigned int front_offset, front_pitch;
+       unsigned int back_offset, back_pitch;
+       unsigned int depth_bpp;
+       unsigned int depth_offset, depth_pitch;
+
+       /* bitmap descriptors for swap and clear */
+       unsigned int front_bd, back_bd, depth_bd;
+
+       /* local textures */
+       unsigned int texture_offset;
+       unsigned int texture_size;
+
+       /* memory regions in physical memory */
+       drm_local_map_t *sarea;
+       drm_local_map_t *mmio;
+       drm_local_map_t *fb;
+       drm_local_map_t *aperture;
+       drm_local_map_t *status;
+       drm_local_map_t *agp_textures;
+       drm_local_map_t *cmd_dma;
+       drm_local_map_t fake_dma;
+
+       struct {
+               int handle;
+               unsigned long base, size;
+       } mtrr[3];
+
+       /* BCI and status-related stuff */
+       volatile uint32_t *status_ptr, *bci_ptr;
+       uint32_t status_used_mask;
+       uint16_t event_counter;
+       unsigned int event_wrap;
+
+       /* Savage4 command DMA */
+       drm_savage_dma_page_t *dma_pages;
+       unsigned int nr_dma_pages, first_dma_page, current_dma_page;
+       drm_savage_age_t last_dma_age;
+
+       /* saved hw state for global/local check on S3D */
+       uint32_t hw_draw_ctrl, hw_zbuf_ctrl;
+       /* and for scissors (global, so don't emit if not changed) */
+       uint32_t hw_scissors_start, hw_scissors_end;
+
+       drm_savage_state_t state;
+
+       /* after emitting a wait cmd Savage3D needs 63 nops before next DMA */
+       unsigned int waiting;
+
+       /* config/hardware-dependent function pointers */
+       int (*wait_fifo)(struct drm_savage_private *dev_priv, unsigned int n);
+       int (*wait_evnt)(struct drm_savage_private *dev_priv, uint16_t e);
+       /* Err, there is a macro wait_event in include/linux/wait.h.
+        * Avoid unwanted macro expansion. */
+       void (*emit_clip_rect)(struct drm_savage_private *dev_priv,
+                              drm_clip_rect_t *pbox);
+       void (*dma_flush)(struct drm_savage_private *dev_priv);
+} drm_savage_private_t;
+
+/* ioctls */
+extern int savage_bci_cmdbuf(DRM_IOCTL_ARGS);
+extern int savage_bci_buffers(DRM_IOCTL_ARGS);
+
+/* BCI functions */
+extern uint16_t savage_bci_emit_event(drm_savage_private_t *dev_priv,
+                                     unsigned int flags);
+extern void savage_freelist_put(drm_device_t *dev, drm_buf_t *buf);
+extern void savage_dma_reset(drm_savage_private_t *dev_priv);
+extern void savage_dma_wait(drm_savage_private_t *dev_priv, unsigned int page);
+extern uint32_t *savage_dma_alloc(drm_savage_private_t *dev_priv,
+                                 unsigned int n);
+extern int savage_preinit(drm_device_t *dev, unsigned long chipset);
+extern int savage_postcleanup(drm_device_t *dev);
+extern int savage_do_cleanup_bci(drm_device_t *dev);
+extern void savage_reclaim_buffers(drm_device_t *dev, DRMFILE filp);
+
+/* state functions */
+extern void savage_emit_clip_rect_s3d(drm_savage_private_t *dev_priv,
+                                     drm_clip_rect_t *pbox);
+extern void savage_emit_clip_rect_s4(drm_savage_private_t *dev_priv,
+                                    drm_clip_rect_t *pbox);
+
+#define SAVAGE_FB_SIZE_S3      0x01000000      /*  16MB */
+#define SAVAGE_FB_SIZE_S4      0x02000000      /*  32MB */
+#define SAVAGE_MMIO_SIZE        0x00080000     /* 512kB */
+#define SAVAGE_APERTURE_OFFSET  0x02000000     /*  32MB */
+#define SAVAGE_APERTURE_SIZE    0x05000000     /* 5 tiled surfaces, 16MB each */
+
+#define SAVAGE_BCI_OFFSET       0x00010000      /* offset of the BCI region
+                                                * inside the MMIO region */
+#define SAVAGE_BCI_FIFO_SIZE   32              /* number of entries in on-chip
+                                                * BCI FIFO */
+
+/*
+ * MMIO registers
+ */
+#define SAVAGE_STATUS_WORD0            0x48C00
+#define SAVAGE_STATUS_WORD1            0x48C04
+#define SAVAGE_ALT_STATUS_WORD0        0x48C60
+
+#define SAVAGE_FIFO_USED_MASK_S3D      0x0001ffff
+#define SAVAGE_FIFO_USED_MASK_S4       0x001fffff
+
+/* Copied from savage_bci.h in the 2D driver with some renaming. */
+
+/* Bitmap descriptors */
+#define SAVAGE_BD_STRIDE_SHIFT 0
+#define SAVAGE_BD_BPP_SHIFT   16
+#define SAVAGE_BD_TILE_SHIFT  24
+#define SAVAGE_BD_BW_DISABLE  (1<<28)
+/* common: */
+#define        SAVAGE_BD_TILE_LINEAR           0
+/* savage4, MX, IX, 3D */
+#define        SAVAGE_BD_TILE_16BPP            2
+#define        SAVAGE_BD_TILE_32BPP            3
+/* twister, prosavage, DDR, supersavage, 2000 */
+#define        SAVAGE_BD_TILE_DEST             1
+#define        SAVAGE_BD_TILE_TEXTURE          2
+/* GBD - BCI enable */
+/* savage4, MX, IX, 3D */
+#define SAVAGE_GBD_BCI_ENABLE                    8
+/* twister, prosavage, DDR, supersavage, 2000 */
+#define SAVAGE_GBD_BCI_ENABLE_TWISTER            0
+
+#define SAVAGE_GBD_BIG_ENDIAN                    4
+#define SAVAGE_GBD_LITTLE_ENDIAN                 0
+#define SAVAGE_GBD_64                            1
+
+/*  Global Bitmap Descriptor */
+#define SAVAGE_BCI_GLB_BD_LOW             0x8168
+#define SAVAGE_BCI_GLB_BD_HIGH            0x816C
+
+/*
+ * BCI registers
+ */
+/* Savage4/Twister/ProSavage 3D registers */
+#define SAVAGE_DRAWLOCALCTRL_S4                0x1e
+#define SAVAGE_TEXPALADDR_S4           0x1f
+#define SAVAGE_TEXCTRL0_S4             0x20
+#define SAVAGE_TEXCTRL1_S4             0x21
+#define SAVAGE_TEXADDR0_S4             0x22
+#define SAVAGE_TEXADDR1_S4             0x23
+#define SAVAGE_TEXBLEND0_S4            0x24
+#define SAVAGE_TEXBLEND1_S4            0x25
+#define SAVAGE_TEXXPRCLR_S4            0x26 /* never used */
+#define SAVAGE_TEXDESCR_S4             0x27
+#define SAVAGE_FOGTABLE_S4             0x28
+#define SAVAGE_FOGCTRL_S4              0x30
+#define SAVAGE_STENCILCTRL_S4          0x31
+#define SAVAGE_ZBUFCTRL_S4             0x32
+#define SAVAGE_ZBUFOFF_S4              0x33
+#define SAVAGE_DESTCTRL_S4             0x34
+#define SAVAGE_DRAWCTRL0_S4            0x35
+#define SAVAGE_DRAWCTRL1_S4            0x36
+#define SAVAGE_ZWATERMARK_S4           0x37
+#define SAVAGE_DESTTEXRWWATERMARK_S4   0x38
+#define SAVAGE_TEXBLENDCOLOR_S4                0x39
+/* Savage3D/MX/IX 3D registers */
+#define SAVAGE_TEXPALADDR_S3D          0x18
+#define SAVAGE_TEXXPRCLR_S3D           0x19 /* never used */
+#define SAVAGE_TEXADDR_S3D             0x1A
+#define SAVAGE_TEXDESCR_S3D            0x1B
+#define SAVAGE_TEXCTRL_S3D             0x1C
+#define SAVAGE_FOGTABLE_S3D            0x20
+#define SAVAGE_FOGCTRL_S3D             0x30
+#define SAVAGE_DRAWCTRL_S3D            0x31
+#define SAVAGE_ZBUFCTRL_S3D            0x32
+#define SAVAGE_ZBUFOFF_S3D             0x33
+#define SAVAGE_DESTCTRL_S3D            0x34
+#define SAVAGE_SCSTART_S3D             0x35
+#define SAVAGE_SCEND_S3D               0x36
+#define SAVAGE_ZWATERMARK_S3D          0x37 
+#define SAVAGE_DESTTEXRWWATERMARK_S3D  0x38
+/* common stuff */
+#define SAVAGE_VERTBUFADDR             0x3e
+#define SAVAGE_BITPLANEWTMASK          0xd7
+#define SAVAGE_DMABUFADDR              0x51
+
+/* texture enable bits (needed for tex addr checking) */
+#define SAVAGE_TEXCTRL_TEXEN_MASK      0x00010000 /* S3D */
+#define SAVAGE_TEXDESCR_TEX0EN_MASK    0x02000000 /* S4 */
+#define SAVAGE_TEXDESCR_TEX1EN_MASK    0x04000000 /* S4 */
+
+/* Global fields in Savage4/Twister/ProSavage 3D registers:
+ *
+ * All texture registers and DrawLocalCtrl are local. All other
+ * registers are global. */
+
+/* Global fields in Savage3D/MX/IX 3D registers:
+ *
+ * All texture registers are local. DrawCtrl and ZBufCtrl are
+ * partially local. All other registers are global.
+ *
+ * DrawCtrl global fields: cullMode, alphaTestCmpFunc, alphaTestEn, alphaRefVal
+ * ZBufCtrl global fields: zCmpFunc, zBufEn
+ */
+#define SAVAGE_DRAWCTRL_S3D_GLOBAL     0x03f3c00c
+#define SAVAGE_ZBUFCTRL_S3D_GLOBAL     0x00000027
+
+/* Masks for scissor bits (drawCtrl[01] on s4, scissorStart/End on s3d)
+ */
+#define SAVAGE_SCISSOR_MASK_S4         0x00fff7ff
+#define SAVAGE_SCISSOR_MASK_S3D                0x07ff07ff
+
+/*
+ * BCI commands
+ */
+#define BCI_CMD_NOP                  0x40000000
+#define BCI_CMD_RECT                 0x48000000
+#define BCI_CMD_RECT_XP              0x01000000
+#define BCI_CMD_RECT_YP              0x02000000
+#define BCI_CMD_SCANLINE             0x50000000
+#define BCI_CMD_LINE                 0x5C000000
+#define BCI_CMD_LINE_LAST_PIXEL      0x58000000
+#define BCI_CMD_BYTE_TEXT            0x63000000
+#define BCI_CMD_NT_BYTE_TEXT         0x67000000
+#define BCI_CMD_BIT_TEXT             0x6C000000
+#define BCI_CMD_GET_ROP(cmd)         (((cmd) >> 16) & 0xFF)
+#define BCI_CMD_SET_ROP(cmd, rop)    ((cmd) |= ((rop & 0xFF) << 16))
+#define BCI_CMD_SEND_COLOR           0x00008000
+
+#define BCI_CMD_CLIP_NONE            0x00000000
+#define BCI_CMD_CLIP_CURRENT         0x00002000
+#define BCI_CMD_CLIP_LR              0x00004000
+#define BCI_CMD_CLIP_NEW             0x00006000
+
+#define BCI_CMD_DEST_GBD             0x00000000
+#define BCI_CMD_DEST_PBD             0x00000800
+#define BCI_CMD_DEST_PBD_NEW         0x00000C00
+#define BCI_CMD_DEST_SBD             0x00001000
+#define BCI_CMD_DEST_SBD_NEW         0x00001400
+
+#define BCI_CMD_SRC_TRANSPARENT      0x00000200
+#define BCI_CMD_SRC_SOLID            0x00000000
+#define BCI_CMD_SRC_GBD              0x00000020
+#define BCI_CMD_SRC_COLOR            0x00000040
+#define BCI_CMD_SRC_MONO             0x00000060
+#define BCI_CMD_SRC_PBD_COLOR        0x00000080
+#define BCI_CMD_SRC_PBD_MONO         0x000000A0
+#define BCI_CMD_SRC_PBD_COLOR_NEW    0x000000C0
+#define BCI_CMD_SRC_PBD_MONO_NEW     0x000000E0
+#define BCI_CMD_SRC_SBD_COLOR        0x00000100
+#define BCI_CMD_SRC_SBD_MONO         0x00000120
+#define BCI_CMD_SRC_SBD_COLOR_NEW    0x00000140
+#define BCI_CMD_SRC_SBD_MONO_NEW     0x00000160
+
+#define BCI_CMD_PAT_TRANSPARENT      0x00000010
+#define BCI_CMD_PAT_NONE             0x00000000
+#define BCI_CMD_PAT_COLOR            0x00000002
+#define BCI_CMD_PAT_MONO             0x00000003
+#define BCI_CMD_PAT_PBD_COLOR        0x00000004
+#define BCI_CMD_PAT_PBD_MONO         0x00000005
+#define BCI_CMD_PAT_PBD_COLOR_NEW    0x00000006
+#define BCI_CMD_PAT_PBD_MONO_NEW     0x00000007
+#define BCI_CMD_PAT_SBD_COLOR        0x00000008
+#define BCI_CMD_PAT_SBD_MONO         0x00000009
+#define BCI_CMD_PAT_SBD_COLOR_NEW    0x0000000A
+#define BCI_CMD_PAT_SBD_MONO_NEW     0x0000000B
+
+#define BCI_BD_BW_DISABLE            0x10000000
+#define BCI_BD_TILE_MASK             0x03000000
+#define BCI_BD_TILE_NONE             0x00000000
+#define BCI_BD_TILE_16               0x02000000
+#define BCI_BD_TILE_32               0x03000000
+#define BCI_BD_GET_BPP(bd)           (((bd) >> 16) & 0xFF)
+#define BCI_BD_SET_BPP(bd, bpp)      ((bd) |= (((bpp) & 0xFF) << 16))
+#define BCI_BD_GET_STRIDE(bd)        ((bd) & 0xFFFF)
+#define BCI_BD_SET_STRIDE(bd, st)    ((bd) |= ((st) & 0xFFFF))
+
+#define BCI_CMD_SET_REGISTER            0x96000000
+
+#define BCI_CMD_WAIT                    0xC0000000
+#define BCI_CMD_WAIT_3D                 0x00010000
+#define BCI_CMD_WAIT_2D                 0x00020000
+
+#define BCI_CMD_UPDATE_EVENT_TAG        0x98000000
+
+#define BCI_CMD_DRAW_PRIM               0x80000000
+#define BCI_CMD_DRAW_INDEXED_PRIM       0x88000000
+#define BCI_CMD_DRAW_CONT               0x01000000
+#define BCI_CMD_DRAW_TRILIST            0x00000000
+#define BCI_CMD_DRAW_TRISTRIP           0x02000000
+#define BCI_CMD_DRAW_TRIFAN             0x04000000
+#define BCI_CMD_DRAW_SKIPFLAGS          0x000000ff
+#define BCI_CMD_DRAW_NO_Z              0x00000001
+#define BCI_CMD_DRAW_NO_W              0x00000002
+#define BCI_CMD_DRAW_NO_CD             0x00000004
+#define BCI_CMD_DRAW_NO_CS             0x00000008
+#define BCI_CMD_DRAW_NO_U0             0x00000010
+#define BCI_CMD_DRAW_NO_V0             0x00000020
+#define BCI_CMD_DRAW_NO_UV0            0x00000030
+#define BCI_CMD_DRAW_NO_U1             0x00000040
+#define BCI_CMD_DRAW_NO_V1             0x00000080
+#define BCI_CMD_DRAW_NO_UV1            0x000000c0
+
+#define BCI_CMD_DMA                    0xa8000000
+
+#define BCI_W_H(w, h)                ((((h) << 16) | (w)) & 0x0FFF0FFF)
+#define BCI_X_Y(x, y)                ((((y) << 16) | (x)) & 0x0FFF0FFF)
+#define BCI_X_W(x, y)                ((((w) << 16) | (x)) & 0x0FFF0FFF)
+#define BCI_CLIP_LR(l, r)            ((((r) << 16) | (l)) & 0x0FFF0FFF)
+#define BCI_CLIP_TL(t, l)            ((((t) << 16) | (l)) & 0x0FFF0FFF)
+#define BCI_CLIP_BR(b, r)            ((((b) << 16) | (r)) & 0x0FFF0FFF)
+
+#define BCI_LINE_X_Y(x, y)           (((y) << 16) | ((x) & 0xFFFF))
+#define BCI_LINE_STEPS(diag, axi)    (((axi) << 16) | ((diag) & 0xFFFF))
+#define BCI_LINE_MISC(maj, ym, xp, yp, err) \
+       (((maj) & 0x1FFF) | \
+       ((ym) ? 1<<13 : 0) | \
+       ((xp) ? 1<<14 : 0) | \
+       ((yp) ? 1<<15 : 0) | \
+       ((err) << 16))
+
+/*
+ * common commands
+ */
+#define BCI_SET_REGISTERS( first, n )                  \
+       BCI_WRITE(BCI_CMD_SET_REGISTER |                \
+                 ((uint32_t)(n) & 0xff) << 16 |        \
+                 ((uint32_t)(first) & 0xffff))
+#define DMA_SET_REGISTERS( first, n )                  \
+       DMA_WRITE(BCI_CMD_SET_REGISTER |                \
+                 ((uint32_t)(n) & 0xff) << 16 |        \
+                 ((uint32_t)(first) & 0xffff))
+
+#define BCI_DRAW_PRIMITIVE(n, type, skip)         \
+        BCI_WRITE(BCI_CMD_DRAW_PRIM | (type) | (skip) | \
+                 ((n) << 16))
+#define DMA_DRAW_PRIMITIVE(n, type, skip)         \
+        DMA_WRITE(BCI_CMD_DRAW_PRIM | (type) | (skip) | \
+                 ((n) << 16))
+
+#define BCI_DRAW_INDICES_S3D(n, type, i0)         \
+        BCI_WRITE(BCI_CMD_DRAW_INDEXED_PRIM | (type) |  \
+                 ((n) << 16) | (i0))
+
+#define BCI_DRAW_INDICES_S4(n, type, skip)        \
+        BCI_WRITE(BCI_CMD_DRAW_INDEXED_PRIM | (type) |  \
+                  (skip) | ((n) << 16))
+
+#define BCI_DMA(n)     \
+       BCI_WRITE(BCI_CMD_DMA | (((n) >> 1) - 1))
+
+/*
+ * access to MMIO
+ */
+#define SAVAGE_READ(reg)       DRM_READ32(  dev_priv->mmio, (reg) )
+#define SAVAGE_WRITE(reg)      DRM_WRITE32( dev_priv->mmio, (reg) )
+
+/*
+ * access to the burst command interface (BCI)
+ */
+#define SAVAGE_BCI_DEBUG 1
+
+#define BCI_LOCALS    volatile uint32_t *bci_ptr;
+
+#define BEGIN_BCI( n ) do {                    \
+       dev_priv->wait_fifo(dev_priv, (n));     \
+       bci_ptr = dev_priv->bci_ptr;            \
+} while(0)
+
+#define BCI_WRITE( val ) *bci_ptr++ = (uint32_t)(val)
+
+#define BCI_COPY_FROM_USER(src,n) do {                         \
+    unsigned int i;                                            \
+    for (i = 0; i < n; ++i) {                                  \
+       uint32_t val;                                           \
+       DRM_GET_USER_UNCHECKED(val, &((uint32_t*)(src))[i]);    \
+       BCI_WRITE(val);                                         \
+    }                                                          \
+} while(0)
+
+/*
+ * command DMA support
+ */
+#define SAVAGE_DMA_DEBUG 1
+
+#define DMA_LOCALS   uint32_t *dma_ptr;
+
+#define BEGIN_DMA( n ) do {                                            \
+       unsigned int cur = dev_priv->current_dma_page;                  \
+       unsigned int rest = SAVAGE_DMA_PAGE_SIZE -                      \
+               dev_priv->dma_pages[cur].used;                          \
+       if ((n) > rest) {                                               \
+               dma_ptr = savage_dma_alloc(dev_priv, (n));              \
+       } else { /* fast path for small allocations */                  \
+               dma_ptr = (uint32_t *)dev_priv->cmd_dma->handle +       \
+                       cur * SAVAGE_DMA_PAGE_SIZE +                    \
+                       dev_priv->dma_pages[cur].used;                  \
+               if (dev_priv->dma_pages[cur].used == 0)                 \
+                       savage_dma_wait(dev_priv, cur);                 \
+               dev_priv->dma_pages[cur].used += (n);                   \
+       }                                                               \
+} while(0)
+
+#define DMA_WRITE( val ) *dma_ptr++ = (uint32_t)(val)
+
+#define DMA_COPY_FROM_USER(src,n) do {                         \
+       DRM_COPY_FROM_USER_UNCHECKED(dma_ptr, (src), (n)*4);    \
+       dma_ptr += n;                                           \
+} while(0)
+
+#if SAVAGE_DMA_DEBUG
+#define DMA_COMMIT() do {                                              \
+       unsigned int cur = dev_priv->current_dma_page;                  \
+       uint32_t *expected = (uint32_t *)dev_priv->cmd_dma->handle +    \
+                       cur * SAVAGE_DMA_PAGE_SIZE +                    \
+                       dev_priv->dma_pages[cur].used;                  \
+       if (dma_ptr != expected) {                                      \
+               DRM_ERROR("DMA allocation and use don't match: "        \
+                         "%p != %p\n", expected, dma_ptr);             \
+               savage_dma_reset(dev_priv);                             \
+       }                                                               \
+} while(0)
+#else
+#define DMA_COMMIT() do {/* nothing */} while(0)
+#endif
+
+#define DMA_FLUSH() dev_priv->dma_flush(dev_priv)
+
+/* Buffer aging via event tag
+ */
+
+#define UPDATE_EVENT_COUNTER( ) do {                   \
+       if (dev_priv->status_ptr) {                     \
+               uint16_t count;                         \
+               /* coordinate with Xserver */           \
+               count = dev_priv->status_ptr[1023];     \
+               if (count < dev_priv->event_counter)    \
+                       dev_priv->event_wrap++;         \
+               dev_priv->event_counter = count;        \
+       }                                               \
+} while(0)
+
+#define SET_AGE( age, e, w ) do {      \
+       (age)->event = e;               \
+       (age)->wrap = w;                \
+} while(0)
+
+#define TEST_AGE( age, e, w )                          \
+       ( (age)->wrap < (w) || ( (age)->wrap == (w) && (age)->event <= (e) ) )
+
+#endif /* __SAVAGE_DRV_H__ */
diff --git a/drivers/char/drm/savage_state.c b/drivers/char/drm/savage_state.c
new file mode 100644 (file)
index 0000000..475695a
--- /dev/null
@@ -0,0 +1,1146 @@
+/* savage_state.c -- State and drawing support for Savage
+ *
+ * Copyright 2004  Felix Kuehling
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "drmP.h"
+#include "savage_drm.h"
+#include "savage_drv.h"
+
+void savage_emit_clip_rect_s3d(drm_savage_private_t *dev_priv,
+                              drm_clip_rect_t *pbox)
+{
+       uint32_t scstart = dev_priv->state.s3d.new_scstart;
+       uint32_t scend   = dev_priv->state.s3d.new_scend;
+       scstart = (scstart & ~SAVAGE_SCISSOR_MASK_S3D) |
+               ((uint32_t)pbox->x1 & 0x000007ff) | 
+               (((uint32_t)pbox->y1 << 16) & 0x07ff0000);
+       scend   = (scend   & ~SAVAGE_SCISSOR_MASK_S3D) |
+               (((uint32_t)pbox->x2-1) & 0x000007ff) |
+               ((((uint32_t)pbox->y2-1) << 16) & 0x07ff0000);
+       if (scstart != dev_priv->state.s3d.scstart ||
+           scend   != dev_priv->state.s3d.scend) {
+               DMA_LOCALS;
+               BEGIN_DMA(4);
+               DMA_WRITE(BCI_CMD_WAIT|BCI_CMD_WAIT_3D);
+               DMA_SET_REGISTERS(SAVAGE_SCSTART_S3D, 2);
+               DMA_WRITE(scstart);
+               DMA_WRITE(scend);
+               dev_priv->state.s3d.scstart = scstart;
+               dev_priv->state.s3d.scend   = scend;
+               dev_priv->waiting = 1;
+               DMA_COMMIT();
+       }
+}
+
+void savage_emit_clip_rect_s4(drm_savage_private_t *dev_priv,
+                             drm_clip_rect_t *pbox)
+{
+       uint32_t drawctrl0 = dev_priv->state.s4.new_drawctrl0;
+       uint32_t drawctrl1 = dev_priv->state.s4.new_drawctrl1;
+       drawctrl0 = (drawctrl0 & ~SAVAGE_SCISSOR_MASK_S4) |
+               ((uint32_t)pbox->x1 & 0x000007ff) |
+               (((uint32_t)pbox->y1 << 12) & 0x00fff000);
+       drawctrl1 = (drawctrl1 & ~SAVAGE_SCISSOR_MASK_S4) |
+               (((uint32_t)pbox->x2-1) & 0x000007ff) |
+               ((((uint32_t)pbox->y2-1) << 12) & 0x00fff000);
+       if (drawctrl0 != dev_priv->state.s4.drawctrl0 ||
+           drawctrl1 != dev_priv->state.s4.drawctrl1) {
+               DMA_LOCALS;
+               BEGIN_DMA(4);
+               DMA_WRITE(BCI_CMD_WAIT|BCI_CMD_WAIT_3D);
+               DMA_SET_REGISTERS(SAVAGE_DRAWCTRL0_S4, 2);
+               DMA_WRITE(drawctrl0);
+               DMA_WRITE(drawctrl1);
+               dev_priv->state.s4.drawctrl0 = drawctrl0;
+               dev_priv->state.s4.drawctrl1 = drawctrl1;
+               dev_priv->waiting = 1;
+               DMA_COMMIT();
+       }
+}
+
+static int savage_verify_texaddr(drm_savage_private_t *dev_priv, int unit,
+                                uint32_t addr)
+{
+       if ((addr & 6) != 2) { /* reserved bits */
+               DRM_ERROR("bad texAddr%d %08x (reserved bits)\n", unit, addr);
+               return DRM_ERR(EINVAL);
+       }
+       if (!(addr & 1)) { /* local */
+               addr &= ~7;
+               if (addr <  dev_priv->texture_offset ||
+                   addr >= dev_priv->texture_offset+dev_priv->texture_size) {
+                       DRM_ERROR("bad texAddr%d %08x (local addr out of range)\n",
+                                 unit, addr);
+                       return DRM_ERR(EINVAL);
+               }
+       } else { /* AGP */
+               if (!dev_priv->agp_textures) {
+                       DRM_ERROR("bad texAddr%d %08x (AGP not available)\n",
+                                 unit, addr);
+                       return DRM_ERR(EINVAL);
+               }
+               addr &= ~7;
+               if (addr < dev_priv->agp_textures->offset ||
+                   addr >= (dev_priv->agp_textures->offset +
+                            dev_priv->agp_textures->size)) {
+                       DRM_ERROR("bad texAddr%d %08x (AGP addr out of range)\n",
+                                 unit, addr);
+                       return DRM_ERR(EINVAL);
+               }
+       }
+       return 0;
+}
+
+#define SAVE_STATE(reg,where)                  \
+       if(start <= reg && start+count > reg)   \
+               DRM_GET_USER_UNCHECKED(dev_priv->state.where, &regs[reg-start])
+#define SAVE_STATE_MASK(reg,where,mask) do {                   \
+       if(start <= reg && start+count > reg) {                 \
+               uint32_t tmp;                                   \
+               DRM_GET_USER_UNCHECKED(tmp, &regs[reg-start]);  \
+               dev_priv->state.where = (tmp & (mask)) |        \
+                       (dev_priv->state.where & ~(mask));      \
+       }                                                       \
+} while (0)
+static int savage_verify_state_s3d(drm_savage_private_t *dev_priv,
+                                  unsigned int start, unsigned int count,
+                                  const uint32_t __user *regs)
+{
+       if (start < SAVAGE_TEXPALADDR_S3D ||
+           start+count-1 > SAVAGE_DESTTEXRWWATERMARK_S3D) {
+               DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",
+                         start, start+count-1);
+               return DRM_ERR(EINVAL);
+       }
+
+       SAVE_STATE_MASK(SAVAGE_SCSTART_S3D, s3d.new_scstart,
+                       ~SAVAGE_SCISSOR_MASK_S3D);
+       SAVE_STATE_MASK(SAVAGE_SCEND_S3D, s3d.new_scend,
+                       ~SAVAGE_SCISSOR_MASK_S3D);
+
+       /* if any texture regs were changed ... */
+       if (start <= SAVAGE_TEXCTRL_S3D &&
+           start+count > SAVAGE_TEXPALADDR_S3D) {
+               /* ... check texture state */
+               SAVE_STATE(SAVAGE_TEXCTRL_S3D, s3d.texctrl);
+               SAVE_STATE(SAVAGE_TEXADDR_S3D, s3d.texaddr);
+               if (dev_priv->state.s3d.texctrl & SAVAGE_TEXCTRL_TEXEN_MASK)
+                       return savage_verify_texaddr(
+                               dev_priv, 0, dev_priv->state.s3d.texaddr);
+       }
+
+       return 0;
+}
+
+static int savage_verify_state_s4(drm_savage_private_t *dev_priv,
+                                 unsigned int start, unsigned int count,
+                                 const uint32_t __user *regs)
+{
+       int ret = 0;
+
+       if (start < SAVAGE_DRAWLOCALCTRL_S4 ||
+           start+count-1 > SAVAGE_TEXBLENDCOLOR_S4) {
+               DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",
+                         start, start+count-1);
+               return DRM_ERR(EINVAL);
+       }
+
+       SAVE_STATE_MASK(SAVAGE_DRAWCTRL0_S4, s4.new_drawctrl0,
+                       ~SAVAGE_SCISSOR_MASK_S4);
+       SAVE_STATE_MASK(SAVAGE_DRAWCTRL1_S4, s4.new_drawctrl1,
+                       ~SAVAGE_SCISSOR_MASK_S4);
+
+       /* if any texture regs were changed ... */
+       if (start <= SAVAGE_TEXDESCR_S4 &&
+           start+count > SAVAGE_TEXPALADDR_S4) {
+               /* ... check texture state */
+               SAVE_STATE(SAVAGE_TEXDESCR_S4, s4.texdescr);
+               SAVE_STATE(SAVAGE_TEXADDR0_S4, s4.texaddr0);
+               SAVE_STATE(SAVAGE_TEXADDR1_S4, s4.texaddr1);
+               if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX0EN_MASK)
+                       ret |= savage_verify_texaddr(
+                               dev_priv, 0, dev_priv->state.s4.texaddr0);
+               if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX1EN_MASK)
+                       ret |= savage_verify_texaddr(
+                               dev_priv, 1, dev_priv->state.s4.texaddr1);
+       }
+
+       return ret;
+}
+#undef SAVE_STATE
+#undef SAVE_STATE_MASK
+
+static int savage_dispatch_state(drm_savage_private_t *dev_priv,
+                                const drm_savage_cmd_header_t *cmd_header,
+                                const uint32_t __user *regs)
+{
+       unsigned int count = cmd_header->state.count;
+       unsigned int start = cmd_header->state.start;
+       unsigned int count2 = 0;
+       unsigned int bci_size;
+       int ret;
+       DMA_LOCALS;
+
+       if (!count)
+               return 0;
+
+       if (DRM_VERIFYAREA_READ(regs, count*4))
+               return DRM_ERR(EFAULT);
+
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+               ret = savage_verify_state_s3d(dev_priv, start, count, regs);
+               if (ret != 0)
+                       return ret;
+               /* scissor regs are emitted in savage_dispatch_draw */
+               if (start < SAVAGE_SCSTART_S3D) {
+                       if (start+count > SAVAGE_SCEND_S3D+1)
+                               count2 = count - (SAVAGE_SCEND_S3D+1 - start);
+                       if (start+count > SAVAGE_SCSTART_S3D)
+                               count = SAVAGE_SCSTART_S3D - start;
+               } else if (start <= SAVAGE_SCEND_S3D) {
+                       if (start+count > SAVAGE_SCEND_S3D+1) {
+                               count -= SAVAGE_SCEND_S3D+1 - start;
+                               start = SAVAGE_SCEND_S3D+1;
+                       } else
+                               return 0;
+               }
+       } else {
+               ret = savage_verify_state_s4(dev_priv, start, count, regs);
+               if (ret != 0)
+                       return ret;
+               /* scissor regs are emitted in savage_dispatch_draw */
+               if (start < SAVAGE_DRAWCTRL0_S4) {
+                       if (start+count > SAVAGE_DRAWCTRL1_S4+1)
+                               count2 = count - (SAVAGE_DRAWCTRL1_S4+1 - start);
+                       if (start+count > SAVAGE_DRAWCTRL0_S4)
+                               count = SAVAGE_DRAWCTRL0_S4 - start;
+               } else if (start <= SAVAGE_DRAWCTRL1_S4) {
+                       if (start+count > SAVAGE_DRAWCTRL1_S4+1) {
+                               count -= SAVAGE_DRAWCTRL1_S4+1 - start;
+                               start = SAVAGE_DRAWCTRL1_S4+1;
+                       } else
+                               return 0;
+               }
+       }
+
+       bci_size = count + (count+254)/255 + count2 + (count2+254)/255;
+
+       if (cmd_header->state.global) {
+               BEGIN_DMA(bci_size+1);
+               DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D);
+               dev_priv->waiting = 1;
+       } else {
+               BEGIN_DMA(bci_size);
+       }
+
+       do {
+               while (count > 0) {
+                       unsigned int n = count < 255 ? count : 255;
+                       DMA_SET_REGISTERS(start, n);
+                       DMA_COPY_FROM_USER(regs, n);
+                       count -= n;
+                       start += n;
+                       regs += n;
+               }
+               start += 2;
+               regs += 2;
+               count = count2;
+               count2 = 0;
+       } while (count);
+
+       DMA_COMMIT();
+
+       return 0;
+}
+
+static int savage_dispatch_dma_prim(drm_savage_private_t *dev_priv,
+                                   const drm_savage_cmd_header_t *cmd_header,
+                                   const drm_buf_t *dmabuf)
+{
+       unsigned char reorder = 0;
+       unsigned int prim = cmd_header->prim.prim;
+       unsigned int skip = cmd_header->prim.skip;
+       unsigned int n = cmd_header->prim.count;
+       unsigned int start = cmd_header->prim.start;
+       unsigned int i;
+       BCI_LOCALS;
+
+       if (!dmabuf) {
+           DRM_ERROR("called without dma buffers!\n");
+           return DRM_ERR(EINVAL);
+       }
+
+       if (!n)
+               return 0;
+
+       switch (prim) {
+       case SAVAGE_PRIM_TRILIST_201:
+               reorder = 1;
+               prim = SAVAGE_PRIM_TRILIST;
+       case SAVAGE_PRIM_TRILIST:
+               if (n % 3 != 0) {
+                       DRM_ERROR("wrong number of vertices %u in TRILIST\n",
+                                 n);
+                       return DRM_ERR(EINVAL);
+               }
+               break;
+       case SAVAGE_PRIM_TRISTRIP:
+       case SAVAGE_PRIM_TRIFAN:
+               if (n < 3) {
+                       DRM_ERROR("wrong number of vertices %u in TRIFAN/STRIP\n",
+                                 n);
+                       return DRM_ERR(EINVAL);
+               }
+               break;
+       default:
+               DRM_ERROR("invalid primitive type %u\n", prim);
+               return DRM_ERR(EINVAL);
+       }
+
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+               if (skip != 0) {
+                       DRM_ERROR("invalid skip flags 0x%04x for DMA\n",
+                                 skip);
+                       return DRM_ERR(EINVAL);
+               }
+       } else {
+               unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -
+                       (skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) -
+                       (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
+               if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {
+                       DRM_ERROR("invalid skip flags 0x%04x for DMA\n",
+                                 skip);
+                       return DRM_ERR(EINVAL);
+               }
+               if (reorder) {
+                       DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");
+                       return DRM_ERR(EINVAL);
+               }
+       }
+
+       if (start + n > dmabuf->total/32) {
+               DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",
+                         start, start + n - 1, dmabuf->total/32);
+               return DRM_ERR(EINVAL);
+       }
+
+       /* Vertex DMA doesn't work with command DMA at the same time,
+        * so we use BCI_... to submit commands here. Flush buffered
+        * faked DMA first. */
+       DMA_FLUSH();
+
+       if (dmabuf->bus_address != dev_priv->state.common.vbaddr) {
+               BEGIN_BCI(2);
+               BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1);
+               BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type);
+               dev_priv->state.common.vbaddr = dmabuf->bus_address;
+       }
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) {
+               /* Workaround for what looks like a hardware bug. If a
+                * WAIT_3D_IDLE was emitted some time before the
+                * indexed drawing command then the engine will lock
+                * up. There are two known workarounds:
+                * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */
+               BEGIN_BCI(63);
+               for (i = 0; i < 63; ++i)
+                       BCI_WRITE(BCI_CMD_WAIT);
+               dev_priv->waiting = 0;
+       }
+
+       prim <<= 25;
+       while (n != 0) {
+               /* Can emit up to 255 indices (85 triangles) at once. */
+               unsigned int count = n > 255 ? 255 : n;
+               if (reorder) {
+                       /* Need to reorder indices for correct flat
+                        * shading while preserving the clock sense
+                        * for correct culling. Only on Savage3D. */
+                       int reorder[3] = {-1, -1, -1};
+                       reorder[start%3] = 2;
+
+                       BEGIN_BCI((count+1+1)/2);
+                       BCI_DRAW_INDICES_S3D(count, prim, start+2);
+
+                       for (i = start+1; i+1 < start+count; i += 2)
+                               BCI_WRITE((i + reorder[i % 3]) |
+                                         ((i+1 + reorder[(i+1) % 3]) << 16));
+                       if (i < start+count)
+                               BCI_WRITE(i + reorder[i%3]);
+               } else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+                       BEGIN_BCI((count+1+1)/2);
+                       BCI_DRAW_INDICES_S3D(count, prim, start);
+
+                       for (i = start+1; i+1 < start+count; i += 2)
+                               BCI_WRITE(i | ((i+1) << 16));
+                       if (i < start+count)
+                               BCI_WRITE(i);
+               } else {
+                       BEGIN_BCI((count+2+1)/2);
+                       BCI_DRAW_INDICES_S4(count, prim, skip);
+
+                       for (i = start; i+1 < start+count; i += 2)
+                               BCI_WRITE(i | ((i+1) << 16));
+                       if (i < start+count)
+                               BCI_WRITE(i);
+               }
+
+               start += count;
+               n -= count;
+
+               prim |= BCI_CMD_DRAW_CONT;
+       }
+
+       return 0;
+}
+
+static int savage_dispatch_vb_prim(drm_savage_private_t *dev_priv,
+                                  const drm_savage_cmd_header_t *cmd_header,
+                                  const uint32_t __user *vtxbuf,
+                                  unsigned int vb_size,
+                                  unsigned int vb_stride)
+{
+       unsigned char reorder = 0;
+       unsigned int prim = cmd_header->prim.prim;
+       unsigned int skip = cmd_header->prim.skip;
+       unsigned int n = cmd_header->prim.count;
+       unsigned int start = cmd_header->prim.start;
+       unsigned int vtx_size;
+       unsigned int i;
+       DMA_LOCALS;
+
+       if (!n)
+               return 0;
+
+       switch (prim) {
+       case SAVAGE_PRIM_TRILIST_201:
+               reorder = 1;
+               prim = SAVAGE_PRIM_TRILIST;
+       case SAVAGE_PRIM_TRILIST:
+               if (n % 3 != 0) {
+                       DRM_ERROR("wrong number of vertices %u in TRILIST\n",
+                                 n);
+                       return DRM_ERR(EINVAL);
+               }
+               break;
+       case SAVAGE_PRIM_TRISTRIP:
+       case SAVAGE_PRIM_TRIFAN:
+               if (n < 3) {
+                       DRM_ERROR("wrong number of vertices %u in TRIFAN/STRIP\n",
+                                 n);
+                       return DRM_ERR(EINVAL);
+               }
+               break;
+       default:
+               DRM_ERROR("invalid primitive type %u\n", prim);
+               return DRM_ERR(EINVAL);
+       }
+
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+               if (skip > SAVAGE_SKIP_ALL_S3D) {
+                       DRM_ERROR("invalid skip flags 0x%04x\n", skip);
+                       return DRM_ERR(EINVAL);
+               }
+               vtx_size = 8; /* full vertex */
+       } else {
+               if (skip > SAVAGE_SKIP_ALL_S4) {
+                       DRM_ERROR("invalid skip flags 0x%04x\n", skip);
+                       return DRM_ERR(EINVAL);
+               }
+               vtx_size = 10; /* full vertex */
+       }
+
+       vtx_size -= (skip & 1) + (skip >> 1 & 1) +
+               (skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) +
+               (skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1);
+
+       if (vtx_size > vb_stride) {
+               DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",
+                         vtx_size, vb_stride);
+               return DRM_ERR(EINVAL);
+       }
+
+       if (start + n > vb_size / (vb_stride*4)) {
+               DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",
+                         start, start + n - 1, vb_size / (vb_stride*4));
+               return DRM_ERR(EINVAL);
+       }
+
+       prim <<= 25;
+       while (n != 0) {
+               /* Can emit up to 255 vertices (85 triangles) at once. */
+               unsigned int count = n > 255 ? 255 : n;
+               if (reorder) {
+                       /* Need to reorder vertices for correct flat
+                        * shading while preserving the clock sense
+                        * for correct culling. Only on Savage3D. */
+                       int reorder[3] = {-1, -1, -1};
+                       reorder[start%3] = 2;
+
+                       BEGIN_DMA(count*vtx_size+1);
+                       DMA_DRAW_PRIMITIVE(count, prim, skip);
+
+                       for (i = start; i < start+count; ++i) {
+                               unsigned int j = i + reorder[i % 3];
+                               DMA_COPY_FROM_USER(&vtxbuf[vb_stride*j],
+                                                  vtx_size);
+                       }
+
+                       DMA_COMMIT();
+               } else {
+                       BEGIN_DMA(count*vtx_size+1);
+                       DMA_DRAW_PRIMITIVE(count, prim, skip);
+
+                       if (vb_stride == vtx_size) {
+                               DMA_COPY_FROM_USER(&vtxbuf[vb_stride*start],
+                                                  vtx_size*count);
+                       } else {
+                               for (i = start; i < start+count; ++i) {
+                                       DMA_COPY_FROM_USER(
+                                               &vtxbuf[vb_stride*i],
+                                               vtx_size);
+                               }
+                       }
+
+                       DMA_COMMIT();
+               }
+
+               start += count;
+               n -= count;
+
+               prim |= BCI_CMD_DRAW_CONT;
+       }
+
+       return 0;
+}
+
+static int savage_dispatch_dma_idx(drm_savage_private_t *dev_priv,
+                                  const drm_savage_cmd_header_t *cmd_header,
+                                  const uint16_t __user *usr_idx,
+                                  const drm_buf_t *dmabuf)
+{
+       unsigned char reorder = 0;
+       unsigned int prim = cmd_header->idx.prim;
+       unsigned int skip = cmd_header->idx.skip;
+       unsigned int n = cmd_header->idx.count;
+       unsigned int i;
+       BCI_LOCALS;
+
+       if (!dmabuf) {
+           DRM_ERROR("called without dma buffers!\n");
+           return DRM_ERR(EINVAL);
+       }
+
+       if (!n)
+               return 0;
+
+       switch (prim) {
+       case SAVAGE_PRIM_TRILIST_201:
+               reorder = 1;
+               prim = SAVAGE_PRIM_TRILIST;
+       case SAVAGE_PRIM_TRILIST:
+               if (n % 3 != 0) {
+                       DRM_ERROR("wrong number of indices %u in TRILIST\n",
+                                 n);
+                       return DRM_ERR(EINVAL);
+               }
+               break;
+       case SAVAGE_PRIM_TRISTRIP:
+       case SAVAGE_PRIM_TRIFAN:
+               if (n < 3) {
+                       DRM_ERROR("wrong number of indices %u in TRIFAN/STRIP\n",
+                                 n);
+                       return DRM_ERR(EINVAL);
+               }
+               break;
+       default:
+               DRM_ERROR("invalid primitive type %u\n", prim);
+               return DRM_ERR(EINVAL);
+       }
+
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+               if (skip != 0) {
+                       DRM_ERROR("invalid skip flags 0x%04x for DMA\n",
+                                 skip);
+                       return DRM_ERR(EINVAL);
+               }
+       } else {
+               unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -
+                       (skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) -
+                       (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
+               if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {
+                       DRM_ERROR("invalid skip flags 0x%04x for DMA\n",
+                                 skip);
+                       return DRM_ERR(EINVAL);
+               }
+               if (reorder) {
+                       DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");
+                       return DRM_ERR(EINVAL);
+               }
+       }
+
+       /* Vertex DMA doesn't work with command DMA at the same time,
+        * so we use BCI_... to submit commands here. Flush buffered
+        * faked DMA first. */
+       DMA_FLUSH();
+
+       if (dmabuf->bus_address != dev_priv->state.common.vbaddr) {
+               BEGIN_BCI(2);
+               BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1);
+               BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type);
+               dev_priv->state.common.vbaddr = dmabuf->bus_address;
+       }
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) {
+               /* Workaround for what looks like a hardware bug. If a
+                * WAIT_3D_IDLE was emitted some time before the
+                * indexed drawing command then the engine will lock
+                * up. There are two known workarounds:
+                * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */
+               BEGIN_BCI(63);
+               for (i = 0; i < 63; ++i)
+                       BCI_WRITE(BCI_CMD_WAIT);
+               dev_priv->waiting = 0;
+       }
+
+       prim <<= 25;
+       while (n != 0) {
+               /* Can emit up to 255 indices (85 triangles) at once. */
+               unsigned int count = n > 255 ? 255 : n;
+               /* Is it ok to allocate 510 bytes on the stack in an ioctl? */
+               uint16_t idx[255];
+
+               /* Copy and check indices */
+               DRM_COPY_FROM_USER_UNCHECKED(idx, usr_idx, count*2);
+               for (i = 0; i < count; ++i) {
+                       if (idx[i] > dmabuf->total/32) {
+                               DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",
+                                         i, idx[i], dmabuf->total/32);
+                               return DRM_ERR(EINVAL);
+                       }
+               }
+
+               if (reorder) {
+                       /* Need to reorder indices for correct flat
+                        * shading while preserving the clock sense
+                        * for correct culling. Only on Savage3D. */
+                       int reorder[3] = {2, -1, -1};
+
+                       BEGIN_BCI((count+1+1)/2);
+                       BCI_DRAW_INDICES_S3D(count, prim, idx[2]);
+
+                       for (i = 1; i+1 < count; i += 2)
+                               BCI_WRITE(idx[i + reorder[i % 3]] |
+                                         (idx[i+1 + reorder[(i+1) % 3]] << 16));
+                       if (i < count)
+                               BCI_WRITE(idx[i + reorder[i%3]]);
+               } else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+                       BEGIN_BCI((count+1+1)/2);
+                       BCI_DRAW_INDICES_S3D(count, prim, idx[0]);
+
+                       for (i = 1; i+1 < count; i += 2)
+                               BCI_WRITE(idx[i] | (idx[i+1] << 16));
+                       if (i < count)
+                               BCI_WRITE(idx[i]);
+               } else {
+                       BEGIN_BCI((count+2+1)/2);
+                       BCI_DRAW_INDICES_S4(count, prim, skip);
+
+                       for (i = 0; i+1 < count; i += 2)
+                               BCI_WRITE(idx[i] | (idx[i+1] << 16));
+                       if (i < count)
+                               BCI_WRITE(idx[i]);
+               }
+
+               usr_idx += count;
+               n -= count;
+
+               prim |= BCI_CMD_DRAW_CONT;
+       }
+
+       return 0;
+}
+
+static int savage_dispatch_vb_idx(drm_savage_private_t *dev_priv,
+                                 const drm_savage_cmd_header_t *cmd_header,
+                                 const uint16_t __user *usr_idx,
+                                 const uint32_t __user *vtxbuf,
+                                 unsigned int vb_size,
+                                 unsigned int vb_stride)
+{
+       unsigned char reorder = 0;
+       unsigned int prim = cmd_header->idx.prim;
+       unsigned int skip = cmd_header->idx.skip;
+       unsigned int n = cmd_header->idx.count;
+       unsigned int vtx_size;
+       unsigned int i;
+       DMA_LOCALS;
+
+       if (!n)
+               return 0;
+
+       switch (prim) {
+       case SAVAGE_PRIM_TRILIST_201:
+               reorder = 1;
+               prim = SAVAGE_PRIM_TRILIST;
+       case SAVAGE_PRIM_TRILIST:
+               if (n % 3 != 0) {
+                       DRM_ERROR("wrong number of indices %u in TRILIST\n",
+                                 n);
+                       return DRM_ERR(EINVAL);
+               }
+               break;
+       case SAVAGE_PRIM_TRISTRIP:
+       case SAVAGE_PRIM_TRIFAN:
+               if (n < 3) {
+                       DRM_ERROR("wrong number of indices %u in TRIFAN/STRIP\n",
+                                 n);
+                       return DRM_ERR(EINVAL);
+               }
+               break;
+       default:
+               DRM_ERROR("invalid primitive type %u\n", prim);
+               return DRM_ERR(EINVAL);
+       }
+
+       if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
+               if (skip > SAVAGE_SKIP_ALL_S3D) {
+                       DRM_ERROR("invalid skip flags 0x%04x\n", skip);
+                       return DRM_ERR(EINVAL);
+               }
+               vtx_size = 8; /* full vertex */
+       } else {
+               if (skip > SAVAGE_SKIP_ALL_S4) {
+                       DRM_ERROR("invalid skip flags 0x%04x\n", skip);
+                       return DRM_ERR(EINVAL);
+               }
+               vtx_size = 10; /* full vertex */
+       }
+
+       vtx_size -= (skip & 1) + (skip >> 1 & 1) +
+               (skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) +
+               (skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1);
+
+       if (vtx_size > vb_stride) {
+               DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",
+                         vtx_size, vb_stride);
+               return DRM_ERR(EINVAL);
+       }
+
+       prim <<= 25;
+       while (n != 0) {
+               /* Can emit up to 255 vertices (85 triangles) at once. */
+               unsigned int count = n > 255 ? 255 : n;
+               /* Is it ok to allocate 510 bytes on the stack in an ioctl? */
+               uint16_t idx[255];
+
+               /* Copy and check indices */
+               DRM_COPY_FROM_USER_UNCHECKED(idx, usr_idx, count*2);
+               for (i = 0; i < count; ++i) {
+                       if (idx[i] > vb_size / (vb_stride*4)) {
+                               DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",
+                                         i, idx[i],  vb_size / (vb_stride*4));
+                               return DRM_ERR(EINVAL);
+                       }
+               }
+
+               if (reorder) {
+                       /* Need to reorder vertices for correct flat
+                        * shading while preserving the clock sense
+                        * for correct culling. Only on Savage3D. */
+                       int reorder[3] = {2, -1, -1};
+
+                       BEGIN_DMA(count*vtx_size+1);
+                       DMA_DRAW_PRIMITIVE(count, prim, skip);
+
+                       for (i = 0; i < count; ++i) {
+                               unsigned int j = idx[i + reorder[i % 3]];
+                               DMA_COPY_FROM_USER(&vtxbuf[vb_stride*j],
+                                                  vtx_size);
+                       }
+
+                       DMA_COMMIT();
+               } else {
+                       BEGIN_DMA(count*vtx_size+1);
+                       DMA_DRAW_PRIMITIVE(count, prim, skip);
+
+                       for (i = 0; i < count; ++i) {
+                               unsigned int j = idx[i];
+                               DMA_COPY_FROM_USER(&vtxbuf[vb_stride*j],
+                                                  vtx_size);
+                       }
+
+                       DMA_COMMIT();
+               }
+
+               usr_idx += count;
+               n -= count;
+
+               prim |= BCI_CMD_DRAW_CONT;
+       }
+
+       return 0;
+}
+
+static int savage_dispatch_clear(drm_savage_private_t *dev_priv,
+                                const drm_savage_cmd_header_t *cmd_header,
+                                const drm_savage_cmd_header_t __user *data,
+                                unsigned int nbox,
+                                const drm_clip_rect_t __user *usr_boxes)
+{
+       unsigned int flags = cmd_header->clear0.flags, mask, value;
+       unsigned int clear_cmd;
+       unsigned int i, nbufs;
+       DMA_LOCALS;
+
+       if (nbox == 0)
+               return 0;
+
+       DRM_GET_USER_UNCHECKED(mask, &((const drm_savage_cmd_header_t*)data)
+                              ->clear1.mask);
+       DRM_GET_USER_UNCHECKED(value, &((const drm_savage_cmd_header_t*)data)
+                              ->clear1.value);
+
+       clear_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |
+               BCI_CMD_SEND_COLOR | BCI_CMD_DEST_PBD_NEW;
+       BCI_CMD_SET_ROP(clear_cmd,0xCC);
+
+       nbufs = ((flags & SAVAGE_FRONT) ? 1 : 0) +
+               ((flags & SAVAGE_BACK) ? 1 : 0) +
+               ((flags & SAVAGE_DEPTH) ? 1 : 0);
+       if (nbufs == 0)
+               return 0;
+
+       if (mask != 0xffffffff) {
+               /* set mask */
+               BEGIN_DMA(2);
+               DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1);
+               DMA_WRITE(mask);
+               DMA_COMMIT();
+       }
+       for (i = 0; i < nbox; ++i) {
+               drm_clip_rect_t box;
+               unsigned int x, y, w, h;
+               unsigned int buf;
+               DRM_COPY_FROM_USER_UNCHECKED(&box, &usr_boxes[i], sizeof(box));
+               x = box.x1, y = box.y1;
+               w = box.x2 - box.x1;
+               h = box.y2 - box.y1;
+               BEGIN_DMA(nbufs*6);
+               for (buf = SAVAGE_FRONT; buf <= SAVAGE_DEPTH; buf <<= 1) {
+                       if (!(flags & buf))
+                               continue;
+                       DMA_WRITE(clear_cmd);
+                       switch(buf) {
+                       case SAVAGE_FRONT:
+                               DMA_WRITE(dev_priv->front_offset);
+                               DMA_WRITE(dev_priv->front_bd);
+                               break;
+                       case SAVAGE_BACK:
+                               DMA_WRITE(dev_priv->back_offset);
+                               DMA_WRITE(dev_priv->back_bd);
+                               break;
+                       case SAVAGE_DEPTH:
+                               DMA_WRITE(dev_priv->depth_offset);
+                               DMA_WRITE(dev_priv->depth_bd);
+                               break;
+                       }
+                       DMA_WRITE(value);
+                       DMA_WRITE(BCI_X_Y(x, y));
+                       DMA_WRITE(BCI_W_H(w, h));
+               }
+               DMA_COMMIT();
+       }
+       if (mask != 0xffffffff) {
+               /* reset mask */
+               BEGIN_DMA(2);
+               DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1);
+               DMA_WRITE(0xffffffff);
+               DMA_COMMIT();
+       }
+
+       return 0;
+}
+
+static int savage_dispatch_swap(drm_savage_private_t *dev_priv,
+                               unsigned int nbox,
+                               const drm_clip_rect_t __user *usr_boxes)
+{
+       unsigned int swap_cmd;
+       unsigned int i;
+       DMA_LOCALS;
+
+       if (nbox == 0)
+               return 0;
+
+       swap_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |
+               BCI_CMD_SRC_PBD_COLOR_NEW | BCI_CMD_DEST_GBD;
+       BCI_CMD_SET_ROP(swap_cmd,0xCC);
+
+       for (i = 0; i < nbox; ++i) {
+               drm_clip_rect_t box;
+               DRM_COPY_FROM_USER_UNCHECKED(&box, &usr_boxes[i], sizeof(box));
+
+               BEGIN_DMA(6);
+               DMA_WRITE(swap_cmd);
+               DMA_WRITE(dev_priv->back_offset);
+               DMA_WRITE(dev_priv->back_bd);
+               DMA_WRITE(BCI_X_Y(box.x1, box.y1));
+               DMA_WRITE(BCI_X_Y(box.x1, box.y1));
+               DMA_WRITE(BCI_W_H(box.x2-box.x1, box.y2-box.y1));
+               DMA_COMMIT();
+       }
+
+       return 0;
+}
+
+static int savage_dispatch_draw(drm_savage_private_t *dev_priv,
+                               const drm_savage_cmd_header_t __user *start,
+                               const drm_savage_cmd_header_t __user *end,
+                               const drm_buf_t *dmabuf,
+                               const unsigned int __user *usr_vtxbuf,
+                               unsigned int vb_size, unsigned int vb_stride,
+                               unsigned int nbox,
+                               const drm_clip_rect_t __user *usr_boxes)
+{
+       unsigned int i, j;
+       int ret;
+
+       for (i = 0; i < nbox; ++i) {
+               drm_clip_rect_t box;
+               const drm_savage_cmd_header_t __user *usr_cmdbuf;
+               DRM_COPY_FROM_USER_UNCHECKED(&box, &usr_boxes[i], sizeof(box));
+               dev_priv->emit_clip_rect(dev_priv, &box);
+
+               usr_cmdbuf = start;
+               while (usr_cmdbuf < end) {
+                       drm_savage_cmd_header_t cmd_header;
+                       DRM_COPY_FROM_USER_UNCHECKED(&cmd_header, usr_cmdbuf,
+                                                    sizeof(cmd_header));
+                       usr_cmdbuf++;
+                       switch (cmd_header.cmd.cmd) {
+                       case SAVAGE_CMD_DMA_PRIM:
+                               ret = savage_dispatch_dma_prim(
+                                       dev_priv, &cmd_header, dmabuf);
+                               break;
+                       case SAVAGE_CMD_VB_PRIM:
+                               ret = savage_dispatch_vb_prim(
+                                       dev_priv, &cmd_header,
+                                       (const uint32_t __user *)usr_vtxbuf,
+                                       vb_size, vb_stride);
+                               break;
+                       case SAVAGE_CMD_DMA_IDX:
+                               j = (cmd_header.idx.count + 3) / 4;
+                               /* j was check in savage_bci_cmdbuf */
+                               ret = savage_dispatch_dma_idx(
+                                       dev_priv, &cmd_header,
+                                       (const uint16_t __user *)usr_cmdbuf,
+                                       dmabuf);
+                               usr_cmdbuf += j;
+                               break;
+                       case SAVAGE_CMD_VB_IDX:
+                               j = (cmd_header.idx.count + 3) / 4;
+                               /* j was check in savage_bci_cmdbuf */
+                               ret = savage_dispatch_vb_idx(
+                                       dev_priv, &cmd_header,
+                                       (const uint16_t __user *)usr_cmdbuf,
+                                       (const uint32_t __user *)usr_vtxbuf,
+                                       vb_size, vb_stride);
+                               usr_cmdbuf += j;
+                               break;
+                       default:
+                               /* What's the best return code? EFAULT? */
+                               DRM_ERROR("IMPLEMENTATION ERROR: "
+                                         "non-drawing-command %d\n",
+                                         cmd_header.cmd.cmd);
+                               return DRM_ERR(EINVAL);
+                       }
+
+                       if (ret != 0)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_savage_private_t *dev_priv = dev->dev_private;
+       drm_device_dma_t *dma = dev->dma;
+       drm_buf_t *dmabuf;
+       drm_savage_cmdbuf_t cmdbuf;
+       drm_savage_cmd_header_t __user *usr_cmdbuf;
+       drm_savage_cmd_header_t __user *first_draw_cmd;
+       unsigned int __user *usr_vtxbuf;
+       drm_clip_rect_t __user *usr_boxes;
+       unsigned int i, j;
+       int ret = 0;
+
+       DRM_DEBUG("\n");
+       
+       LOCK_TEST_WITH_RETURN(dev, filp);
+
+       DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_savage_cmdbuf_t __user *)data,
+                                sizeof(cmdbuf));
+
+       if (dma && dma->buflist) {
+               if (cmdbuf.dma_idx > dma->buf_count) {
+                       DRM_ERROR("vertex buffer index %u out of range (0-%u)\n",
+                                 cmdbuf.dma_idx, dma->buf_count-1);
+                       return DRM_ERR(EINVAL);
+               }
+               dmabuf = dma->buflist[cmdbuf.dma_idx];
+       } else {
+               dmabuf = NULL;
+       }
+
+       usr_cmdbuf = (drm_savage_cmd_header_t __user *)cmdbuf.cmd_addr;
+       usr_vtxbuf = (unsigned int __user *)cmdbuf.vb_addr;
+       usr_boxes = (drm_clip_rect_t __user *)cmdbuf.box_addr;
+       if ((cmdbuf.size && DRM_VERIFYAREA_READ(usr_cmdbuf, cmdbuf.size*8)) ||
+           (cmdbuf.vb_size && DRM_VERIFYAREA_READ(
+                   usr_vtxbuf, cmdbuf.vb_size)) ||
+           (cmdbuf.nbox && DRM_VERIFYAREA_READ(
+                   usr_boxes, cmdbuf.nbox*sizeof(drm_clip_rect_t))))
+               return DRM_ERR(EFAULT);
+
+       /* Make sure writes to DMA buffers are finished before sending
+        * DMA commands to the graphics hardware. */
+       DRM_MEMORYBARRIER();
+
+       /* Coming from user space. Don't know if the Xserver has
+        * emitted wait commands. Assuming the worst. */
+       dev_priv->waiting = 1;
+
+       i = 0;
+       first_draw_cmd = NULL;
+       while (i < cmdbuf.size) {
+               drm_savage_cmd_header_t cmd_header;
+               DRM_COPY_FROM_USER_UNCHECKED(&cmd_header, usr_cmdbuf,
+                                            sizeof(cmd_header));
+               usr_cmdbuf++;
+               i++;
+
+               /* Group drawing commands with same state to minimize
+                * iterations over clip rects. */
+               j = 0;
+               switch (cmd_header.cmd.cmd) {
+               case SAVAGE_CMD_DMA_IDX:
+               case SAVAGE_CMD_VB_IDX:
+                       j = (cmd_header.idx.count + 3) / 4;
+                       if (i + j > cmdbuf.size) {
+                               DRM_ERROR("indexed drawing command extends "
+                                         "beyond end of command buffer\n");
+                               DMA_FLUSH();
+                               return DRM_ERR(EINVAL);
+                       }
+                       /* fall through */
+               case SAVAGE_CMD_DMA_PRIM:
+               case SAVAGE_CMD_VB_PRIM:
+                       if (!first_draw_cmd)
+                               first_draw_cmd = usr_cmdbuf-1;
+                       usr_cmdbuf += j;
+                       i += j;
+                       break;
+               default:
+                       if (first_draw_cmd) {
+                               ret = savage_dispatch_draw (
+                                       dev_priv, first_draw_cmd, usr_cmdbuf-1,
+                                       dmabuf, usr_vtxbuf, cmdbuf.vb_size,
+                                       cmdbuf.vb_stride,
+                                       cmdbuf.nbox, usr_boxes);
+                               if (ret != 0)
+                                       return ret;
+                               first_draw_cmd = NULL;
+                       }
+               }
+               if (first_draw_cmd)
+                       continue;
+
+               switch (cmd_header.cmd.cmd) {
+               case SAVAGE_CMD_STATE:
+                       j = (cmd_header.state.count + 1) / 2;
+                       if (i + j > cmdbuf.size) {
+                               DRM_ERROR("command SAVAGE_CMD_STATE extends "
+                                         "beyond end of command buffer\n");
+                               DMA_FLUSH();
+                               return DRM_ERR(EINVAL);
+                       }
+                       ret = savage_dispatch_state(
+                               dev_priv, &cmd_header,
+                               (uint32_t __user *)usr_cmdbuf);
+                       usr_cmdbuf += j;
+                       i += j;
+                       break;
+               case SAVAGE_CMD_CLEAR:
+                       if (i + 1 > cmdbuf.size) {
+                               DRM_ERROR("command SAVAGE_CMD_CLEAR extends "
+                                         "beyond end of command buffer\n");
+                               DMA_FLUSH();
+                               return DRM_ERR(EINVAL);
+                       }
+                       ret = savage_dispatch_clear(dev_priv, &cmd_header,
+                                                   usr_cmdbuf,
+                                                   cmdbuf.nbox, usr_boxes);
+                       usr_cmdbuf++;
+                       i++;
+                       break;
+               case SAVAGE_CMD_SWAP:
+                       ret = savage_dispatch_swap(dev_priv,
+                                                  cmdbuf.nbox, usr_boxes);
+                       break;
+               default:
+                       DRM_ERROR("invalid command 0x%x\n", cmd_header.cmd.cmd);
+                       DMA_FLUSH();
+                       return DRM_ERR(EINVAL);
+               }
+
+               if (ret != 0) {
+                       DMA_FLUSH();
+                       return ret;
+               }
+       }
+
+       if (first_draw_cmd) {
+               ret = savage_dispatch_draw (
+                       dev_priv, first_draw_cmd, usr_cmdbuf, dmabuf,
+                       usr_vtxbuf, cmdbuf.vb_size, cmdbuf.vb_stride,
+                       cmdbuf.nbox, usr_boxes);
+               if (ret != 0) {
+                       DMA_FLUSH();
+                       return ret;
+               }
+       }
+
+       DMA_FLUSH();
+
+       if (dmabuf && cmdbuf.discard) {
+               drm_savage_buf_priv_t *buf_priv = dmabuf->dev_private;
+               uint16_t event;
+               event = savage_bci_emit_event(dev_priv, SAVAGE_WAIT_3D);
+               SET_AGE(&buf_priv->age, event, dev_priv->event_wrap);
+               savage_freelist_put(dev, dmabuf);
+       }
+
+       return 0;
+}
index 6025e1866c7e5e0afeb74dbd74a979b77795da5d..58d3738a2b7fd4eab9d51cd783fba8bf98ceb562 100644 (file)
@@ -6,6 +6,8 @@
        For technical support please email digiLinux@dgii.com or
        call Digi tech support at (612) 912-3456
 
+       ** This driver is no longer supported by Digi **
+
        Much of this design and code came from epca.c which was 
        copyright (C) 1994, 1995 Troy De Jongh, and subsquently 
        modified by David Nugent, Christoph Lameter, Mike McLagan. 
 #include <linux/interrupt.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
-
-#ifdef CONFIG_PCI
-#define ENABLE_PCI
-#endif /* CONFIG_PCI */
-
-#define putUser(arg1, arg2) put_user(arg1, (unsigned long __user *)arg2)
-#define getUser(arg1, arg2) get_user(arg1, (unsigned __user *)arg2)
-
-#ifdef ENABLE_PCI
+#include <linux/spinlock.h>
 #include <linux/pci.h>
 #include "digiPCI.h"
-#endif /* ENABLE_PCI */
+
 
 #include "digi1.h"
 #include "digiFep1.h"
 #include "epca.h"
 #include "epcaconfig.h"
 
-#if BITS_PER_LONG != 32
-#  error FIXME: this driver only works on 32-bit platforms
-#endif
-
 /* ---------------------- Begin defines ------------------------ */
 
-#define VERSION            "1.3.0.1-LK"
+#define VERSION            "1.3.0.1-LK2.6"
 
 /* This major needs to be submitted to Linux to join the majors list */
 
 
 /* ----------------- Begin global definitions ------------------- */
 
-static char mesg[100];
 static int nbdevs, num_cards, liloconfig;
 static int digi_poller_inhibited = 1 ;
 
 static int setup_error_code;
 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;
+
 /* -----------------------------------------------------------------------
        MAXBOARDS is typically 12, but ISA and EISA cards are restricted to 
        7 below.
@@ -129,58 +123,58 @@ static struct timer_list epca_timer;
        configured.
 ----------------------------------------------------------------------- */
        
-static inline void memwinon(struct board_info *b, unsigned int win);
-static inline void memwinoff(struct board_info *b, unsigned int win);
-static inline void globalwinon(struct channel *ch);
-static inline void rxwinon(struct channel *ch);
-static inline void txwinon(struct channel *ch);
-static inline void memoff(struct channel *ch);
-static inline void assertgwinon(struct channel *ch);
-static inline void assertmemoff(struct channel *ch);
+static void memwinon(struct board_info *b, unsigned int win);
+static void memwinoff(struct board_info *b, unsigned int win);
+static void globalwinon(struct channel *ch);
+static void rxwinon(struct channel *ch);
+static void txwinon(struct channel *ch);
+static void memoff(struct channel *ch);
+static void assertgwinon(struct channel *ch);
+static void assertmemoff(struct channel *ch);
 
 /* ---- Begin more 'specific' memory functions for cx_like products --- */
 
-static inline void pcxem_memwinon(struct board_info *b, unsigned int win);
-static inline void pcxem_memwinoff(struct board_info *b, unsigned int win);
-static inline void pcxem_globalwinon(struct channel *ch);
-static inline void pcxem_rxwinon(struct channel *ch);
-static inline void pcxem_txwinon(struct channel *ch);
-static inline void pcxem_memoff(struct channel *ch);
+static void pcxem_memwinon(struct board_info *b, unsigned int win);
+static void pcxem_memwinoff(struct board_info *b, unsigned int win);
+static void pcxem_globalwinon(struct channel *ch);
+static void pcxem_rxwinon(struct channel *ch);
+static void pcxem_txwinon(struct channel *ch);
+static void pcxem_memoff(struct channel *ch);
 
 /* ------ Begin more 'specific' memory functions for the pcxe ------- */
 
-static inline void pcxe_memwinon(struct board_info *b, unsigned int win);
-static inline void pcxe_memwinoff(struct board_info *b, unsigned int win);
-static inline void pcxe_globalwinon(struct channel *ch);
-static inline void pcxe_rxwinon(struct channel *ch);
-static inline void pcxe_txwinon(struct channel *ch);
-static inline void pcxe_memoff(struct channel *ch);
+static void pcxe_memwinon(struct board_info *b, unsigned int win);
+static void pcxe_memwinoff(struct board_info *b, unsigned int win);
+static void pcxe_globalwinon(struct channel *ch);
+static void pcxe_rxwinon(struct channel *ch);
+static void pcxe_txwinon(struct channel *ch);
+static void pcxe_memoff(struct channel *ch);
 
 /* ---- Begin more 'specific' memory functions for the pc64xe and pcxi ---- */
 /* Note : pc64xe and pcxi share the same windowing routines */
 
-static inline void pcxi_memwinon(struct board_info *b, unsigned int win);
-static inline void pcxi_memwinoff(struct board_info *b, unsigned int win);
-static inline void pcxi_globalwinon(struct channel *ch);
-static inline void pcxi_rxwinon(struct channel *ch);
-static inline void pcxi_txwinon(struct channel *ch);
-static inline void pcxi_memoff(struct channel *ch);
+static void pcxi_memwinon(struct board_info *b, unsigned int win);
+static void pcxi_memwinoff(struct board_info *b, unsigned int win);
+static void pcxi_globalwinon(struct channel *ch);
+static void pcxi_rxwinon(struct channel *ch);
+static void pcxi_txwinon(struct channel *ch);
+static void pcxi_memoff(struct channel *ch);
 
 /* - Begin 'specific' do nothing memory functions needed for some cards - */
 
-static inline void dummy_memwinon(struct board_info *b, unsigned int win);
-static inline void dummy_memwinoff(struct board_info *b, unsigned int win);
-static inline void dummy_globalwinon(struct channel *ch);
-static inline void dummy_rxwinon(struct channel *ch);
-static inline void dummy_txwinon(struct channel *ch);
-static inline void dummy_memoff(struct channel *ch);
-static inline void dummy_assertgwinon(struct channel *ch);
-static inline void dummy_assertmemoff(struct channel *ch);
+static void dummy_memwinon(struct board_info *b, unsigned int win);
+static void dummy_memwinoff(struct board_info *b, unsigned int win);
+static void dummy_globalwinon(struct channel *ch);
+static void dummy_rxwinon(struct channel *ch);
+static void dummy_txwinon(struct channel *ch);
+static void dummy_memoff(struct channel *ch);
+static void dummy_assertgwinon(struct channel *ch);
+static void dummy_assertmemoff(struct channel *ch);
 
 /* ------------------- Begin declare functions ----------------------- */
 
-static inline struct channel *verifyChannel(register struct tty_struct *);
-static inline void pc_sched_event(struct channel *, int);
+static struct channel *verifyChannel(struct tty_struct *);
+static void pc_sched_event(struct channel *, int);
 static void epca_error(int, char *);
 static void pc_close(struct tty_struct *, struct file *);
 static void shutdown(struct channel *);
@@ -215,15 +209,11 @@ static void pc_unthrottle(struct tty_struct *tty);
 static void digi_send_break(struct channel *ch, int msec);
 static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
 void epca_setup(char *, int *);
-void console_print(const char *);
 
 static int get_termio(struct tty_struct *, struct termio __user *);
 static int pc_write(struct tty_struct *, const unsigned char *, int);
-int pc_init(void);
-
-#ifdef ENABLE_PCI
+static int pc_init(void);
 static int init_PCI(void);
-#endif /* ENABLE_PCI */
 
 
 /* ------------------------------------------------------------------
@@ -237,41 +227,41 @@ static int init_PCI(void);
        making direct calls deserves what they get.
 -------------------------------------------------------------------- */
 
-static inline void memwinon(struct board_info *b, unsigned int win)
+static void memwinon(struct board_info *b, unsigned int win)
 {
        (b->memwinon)(b, win);
 }
 
-static inline void memwinoff(struct board_info *b, unsigned int win)
+static void memwinoff(struct board_info *b, unsigned int win)
 {
        (b->memwinoff)(b, win);
 }
 
-static inline void globalwinon(struct channel *ch)
+static void globalwinon(struct channel *ch)
 {
        (ch->board->globalwinon)(ch);
 }
 
-static inline void rxwinon(struct channel *ch)
+static void rxwinon(struct channel *ch)
 {
        (ch->board->rxwinon)(ch);
 }
 
-static inline void txwinon(struct channel *ch)
+static void txwinon(struct channel *ch)
 {
        (ch->board->txwinon)(ch);
 }
 
-static inline void memoff(struct channel *ch)
+static void memoff(struct channel *ch)
 {
        (ch->board->memoff)(ch);
 }
-static inline void assertgwinon(struct channel *ch)
+static void assertgwinon(struct channel *ch)
 {
        (ch->board->assertgwinon)(ch);
 }
 
-static inline void assertmemoff(struct channel *ch)
+static void assertmemoff(struct channel *ch)
 {
        (ch->board->assertmemoff)(ch);
 }
@@ -281,66 +271,66 @@ static inline void assertmemoff(struct channel *ch)
        and CX series cards.
 ------------------------------------------------------------ */
 
-static inline void pcxem_memwinon(struct board_info *b, unsigned int win)
+static void pcxem_memwinon(struct board_info *b, unsigned int win)
 {
-        outb_p(FEPWIN|win, (int)b->port + 1);
+        outb_p(FEPWIN|win, b->port + 1);
 }
 
-static inline void pcxem_memwinoff(struct board_info *b, unsigned int win)
+static void pcxem_memwinoff(struct board_info *b, unsigned int win)
 {
-       outb_p(0, (int)b->port + 1);
+       outb_p(0, b->port + 1);
 }
 
-static inline void pcxem_globalwinon(struct channel *ch)
+static void pcxem_globalwinon(struct channel *ch)
 {
        outb_p( FEPWIN, (int)ch->board->port + 1);
 }
 
-static inline void pcxem_rxwinon(struct channel *ch)
+static void pcxem_rxwinon(struct channel *ch)
 {
        outb_p(ch->rxwin, (int)ch->board->port + 1);
 }
 
-static inline void pcxem_txwinon(struct channel *ch)
+static void pcxem_txwinon(struct channel *ch)
 {
        outb_p(ch->txwin, (int)ch->board->port + 1);
 }
 
-static inline void pcxem_memoff(struct channel *ch)
+static void pcxem_memoff(struct channel *ch)
 {
        outb_p(0, (int)ch->board->port + 1);
 }
 
 /* ----------------- Begin pcxe memory window stuff ------------------ */
 
-static inline void pcxe_memwinon(struct board_info *b, unsigned int win)
+static void pcxe_memwinon(struct board_info *b, unsigned int win)
 {
-               outb_p(FEPWIN | win, (int)b->port + 1);
+               outb_p(FEPWIN | win, b->port + 1);
 }
 
-static inline void pcxe_memwinoff(struct board_info *b, unsigned int win)
+static void pcxe_memwinoff(struct board_info *b, unsigned int win)
 {
-       outb_p(inb((int)b->port) & ~FEPMEM,
-                  (int)b->port + 1);
-       outb_p(0, (int)b->port + 1);
+       outb_p(inb(b->port) & ~FEPMEM,
+                  b->port + 1);
+       outb_p(0, b->port + 1);
 }
 
-static inline void pcxe_globalwinon(struct channel *ch)
+static void pcxe_globalwinon(struct channel *ch)
 {
        outb_p( FEPWIN, (int)ch->board->port + 1);
 }
 
-static inline void pcxe_rxwinon(struct channel *ch)
+static void pcxe_rxwinon(struct channel *ch)
 {
                outb_p(ch->rxwin, (int)ch->board->port + 1);
 }
 
-static inline void pcxe_txwinon(struct channel *ch)
+static void pcxe_txwinon(struct channel *ch)
 {
                outb_p(ch->txwin, (int)ch->board->port + 1);
 }
 
-static inline void pcxe_memoff(struct channel *ch)
+static void pcxe_memoff(struct channel *ch)
 {
        outb_p(0, (int)ch->board->port);
        outb_p(0, (int)ch->board->port + 1);
@@ -348,44 +338,44 @@ static inline void pcxe_memoff(struct channel *ch)
 
 /* ------------- Begin pc64xe and pcxi memory window stuff -------------- */
 
-static inline void pcxi_memwinon(struct board_info *b, unsigned int win)
+static void pcxi_memwinon(struct board_info *b, unsigned int win)
 {
-               outb_p(inb((int)b->port) | FEPMEM, (int)b->port);
+               outb_p(inb(b->port) | FEPMEM, b->port);
 }
 
-static inline void pcxi_memwinoff(struct board_info *b, unsigned int win)
+static void pcxi_memwinoff(struct board_info *b, unsigned int win)
 {
-       outb_p(inb((int)b->port) & ~FEPMEM, (int)b->port);
+       outb_p(inb(b->port) & ~FEPMEM, b->port);
 }
 
-static inline void pcxi_globalwinon(struct channel *ch)
+static void pcxi_globalwinon(struct channel *ch)
 {
-       outb_p(FEPMEM, (int)ch->board->port);
+       outb_p(FEPMEM, ch->board->port);
 }
 
-static inline void pcxi_rxwinon(struct channel *ch)
+static void pcxi_rxwinon(struct channel *ch)
 {
-               outb_p(FEPMEM, (int)ch->board->port);
+               outb_p(FEPMEM, ch->board->port);
 }
 
-static inline void pcxi_txwinon(struct channel *ch)
+static void pcxi_txwinon(struct channel *ch)
 {
-               outb_p(FEPMEM, (int)ch->board->port);
+               outb_p(FEPMEM, ch->board->port);
 }
 
-static inline void pcxi_memoff(struct channel *ch)
+static void pcxi_memoff(struct channel *ch)
 {
-       outb_p(0, (int)ch->board->port);
+       outb_p(0, ch->board->port);
 }
 
-static inline void pcxi_assertgwinon(struct channel *ch)
+static void pcxi_assertgwinon(struct channel *ch)
 {
-       epcaassert(inb((int)ch->board->port) & FEPMEM, "Global memory off");
+       epcaassert(inb(ch->board->port) & FEPMEM, "Global memory off");
 }
 
-static inline void pcxi_assertmemoff(struct channel *ch)
+static void pcxi_assertmemoff(struct channel *ch)
 {
-       epcaassert(!(inb((int)ch->board->port) & FEPMEM), "Memory on");
+       epcaassert(!(inb(ch->board->port) & FEPMEM), "Memory on");
 }
 
 
@@ -398,185 +388,143 @@ static inline void pcxi_assertmemoff(struct channel *ch)
        may or may not do anything.
 ---------------------------------------------------------------------------*/
 
-static inline void dummy_memwinon(struct board_info *b, unsigned int win)
+static void dummy_memwinon(struct board_info *b, unsigned int win)
 {
 }
 
-static inline void dummy_memwinoff(struct board_info *b, unsigned int win)
+static void dummy_memwinoff(struct board_info *b, unsigned int win)
 {
 }
 
-static inline void dummy_globalwinon(struct channel *ch)
+static void dummy_globalwinon(struct channel *ch)
 {
 }
 
-static inline void dummy_rxwinon(struct channel *ch)
+static void dummy_rxwinon(struct channel *ch)
 {
 }
 
-static inline void dummy_txwinon(struct channel *ch)
+static void dummy_txwinon(struct channel *ch)
 {
 }
 
-static inline void dummy_memoff(struct channel *ch)
+static void dummy_memoff(struct channel *ch)
 {
 }
 
-static inline void dummy_assertgwinon(struct channel *ch)
+static void dummy_assertgwinon(struct channel *ch)
 {
 }
 
-static inline void dummy_assertmemoff(struct channel *ch)
+static void dummy_assertmemoff(struct channel *ch)
 {
 }
 
 /* ----------------- Begin verifyChannel function ----------------------- */
-static inline struct channel *verifyChannel(register struct tty_struct *tty)
+static struct channel *verifyChannel(struct tty_struct *tty)
 { /* Begin verifyChannel */
-
        /* --------------------------------------------------------------------
                This routine basically provides a sanity check.  It insures that
                the channel returned is within the proper range of addresses as
                well as properly initialized.  If some bogus info gets passed in
                through tty->driver_data this should catch it.
-       --------------------------------------------------------------------- */
-
-       if (tty) 
-       { /* Begin if tty */
-
-               register struct channel *ch = (struct channel *)tty->driver_data;
-
-               if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) 
-               {
+               --------------------------------------------------------------------- */
+       if (tty) {
+               struct channel *ch = (struct channel *)tty->driver_data;
+               if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) {
                        if (ch->magic == EPCA_MAGIC)
                                return ch;
                }
-
-       } /* End if tty */
-
-       /* Else return a NULL for invalid */
+       }
        return NULL;
 
 } /* End verifyChannel */
 
 /* ------------------ Begin pc_sched_event ------------------------- */
 
-static inline void pc_sched_event(struct channel *ch, int event)
-{ /* Begin pc_sched_event */
-
-
+static void pc_sched_event(struct channel *ch, int event)
+{
        /* ----------------------------------------------------------------------
                We call this to schedule interrupt processing on some event.  The 
                kernel sees our request and calls the related routine in OUR driver.
        -------------------------------------------------------------------------*/
-
        ch->event |= 1 << event;
        schedule_work(&ch->tqueue);
-
-
 } /* End pc_sched_event */
 
 /* ------------------ Begin epca_error ------------------------- */
 
 static void epca_error(int line, char *msg)
-{ /* Begin epca_error */
-
+{
        printk(KERN_ERR "epca_error (Digi): line = %d %s\n",line,msg);
-       return;
-
-} /* End epca_error */
+}
 
 /* ------------------ Begin pc_close ------------------------- */
 static void pc_close(struct tty_struct * tty, struct file * filp)
-{ /* Begin pc_close */
-
+{
        struct channel *ch;
        unsigned long flags;
-
        /* ---------------------------------------------------------
                verifyChannel returns the channel from the tty struct
                if it is valid.  This serves as a sanity check.
        ------------------------------------------------------------- */
-
-       if ((ch = verifyChannel(tty)) != NULL) 
-       { /* Begin if ch != NULL */
-
-               save_flags(flags);
-               cli();
-
-               if (tty_hung_up_p(filp)) 
-               {
-                       restore_flags(flags);
+       if ((ch = verifyChannel(tty)) != NULL)  { /* Begin if ch != NULL */
+               spin_lock_irqsave(&epca_lock, flags);
+               if (tty_hung_up_p(filp)) {
+                       spin_unlock_irqrestore(&epca_lock, flags);
                        return;
                }
-
                /* Check to see if the channel is open more than once */
-               if (ch->count-- > 1) 
-               { /* Begin channel is open more than once */
-
+               if (ch->count-- > 1)  {
+                       /* Begin channel is open more than once */
                        /* -------------------------------------------------------------
                                Return without doing anything.  Someone might still be using
                                the channel.
                        ---------------------------------------------------------------- */
-
-                       restore_flags(flags);
+                       spin_unlock_irqrestore(&epca_lock, flags);
                        return;
                } /* End channel is open more than once */
 
                /* Port open only once go ahead with shutdown & reset */
-
-               if (ch->count < 0) 
-               {
-                       ch->count = 0;
-               }
+               if (ch->count < 0)
+                       BUG();
 
                /* ---------------------------------------------------------------
                        Let the rest of the driver know the channel is being closed.
                        This becomes important if an open is attempted before close 
                        is finished.
                ------------------------------------------------------------------ */
-
                ch->asyncflags |= ASYNC_CLOSING;
-       
                tty->closing = 1;
 
-               if (ch->asyncflags & ASYNC_INITIALIZED) 
-               {
+               spin_unlock_irqrestore(&epca_lock, flags);
+
+               if (ch->asyncflags & ASYNC_INITIALIZED)  {
                        /* Setup an event to indicate when the transmit buffer empties */
                        setup_empty_event(tty, ch);             
                        tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
                }
-       
                if (tty->driver->flush_buffer)
                        tty->driver->flush_buffer(tty);
 
                tty_ldisc_flush(tty);
                shutdown(ch);
+
+               spin_lock_irqsave(&epca_lock, flags);
                tty->closing = 0;
                ch->event = 0;
                ch->tty = NULL;
+               spin_unlock_irqrestore(&epca_lock, flags);
 
-               if (ch->blocked_open) 
-               { /* Begin if blocked_open */
-
+               if (ch->blocked_open)  { /* Begin if blocked_open */
                        if (ch->close_delay) 
-                       {
                                msleep_interruptible(jiffies_to_msecs(ch->close_delay));
-                       }
-
                        wake_up_interruptible(&ch->open_wait);
-
                } /* End if blocked_open */
-
                ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | 
                                      ASYNC_CLOSING);
                wake_up_interruptible(&ch->close_wait);
-
-
-               restore_flags(flags);
-
        } /* End if ch != NULL */
-
 } /* End pc_close */ 
 
 /* ------------------ Begin shutdown  ------------------------- */
@@ -586,15 +534,14 @@ static void shutdown(struct channel *ch)
 
        unsigned long flags;
        struct tty_struct *tty;
-       volatile struct board_chan *bc;
+       struct board_chan *bc;
 
        if (!(ch->asyncflags & ASYNC_INITIALIZED)) 
                return;
 
-       save_flags(flags);
-       cli();
-       globalwinon(ch);
+       spin_lock_irqsave(&epca_lock, flags);
 
+       globalwinon(ch);
        bc = ch->brdchan;
 
        /* ------------------------------------------------------------------
@@ -604,20 +551,17 @@ static void shutdown(struct channel *ch)
        --------------------------------------------------------------------- */ 
 
        if (bc)
-               bc->idata = 0;
-
+               writeb(0, &bc->idata);
        tty = ch->tty;
 
        /* ----------------------------------------------------------------
           If we're a modem control device and HUPCL is on, drop RTS & DTR.
        ------------------------------------------------------------------ */
 
-       if (tty->termios->c_cflag & HUPCL) 
-       {
+       if (tty->termios->c_cflag & HUPCL)  {
                ch->omodem &= ~(ch->m_rts | ch->m_dtr);
                fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1);
        }
-
        memoff(ch);
 
        /* ------------------------------------------------------------------
@@ -628,7 +572,7 @@ static void shutdown(struct channel *ch)
        /* Prevent future Digi programmed interrupts from coming active */
 
        ch->asyncflags &= ~ASYNC_INITIALIZED;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&epca_lock, flags);
 
 } /* End shutdown */
 
@@ -636,7 +580,6 @@ static void shutdown(struct channel *ch)
 
 static void pc_hangup(struct tty_struct *tty)
 { /* Begin pc_hangup */
-
        struct channel *ch;
        
        /* ---------------------------------------------------------
@@ -644,25 +587,21 @@ static void pc_hangup(struct tty_struct *tty)
                if it is valid.  This serves as a sanity check.
        ------------------------------------------------------------- */
 
-       if ((ch = verifyChannel(tty)) != NULL) 
-       { /* Begin if ch != NULL */
-
+       if ((ch = verifyChannel(tty)) != NULL)  { /* Begin if ch != NULL */
                unsigned long flags;
 
-               save_flags(flags);
-               cli();
                if (tty->driver->flush_buffer)
                        tty->driver->flush_buffer(tty);
                tty_ldisc_flush(tty);
                shutdown(ch);
 
+               spin_lock_irqsave(&epca_lock, flags);
                ch->tty   = NULL;
                ch->event = 0;
                ch->count = 0;
-               restore_flags(flags);
                ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED);
+               spin_unlock_irqrestore(&epca_lock, flags);
                wake_up_interruptible(&ch->open_wait);
-
        } /* End if ch != NULL */
 
 } /* End pc_hangup */
@@ -672,18 +611,14 @@ static void pc_hangup(struct tty_struct *tty)
 static int pc_write(struct tty_struct * tty,
                     const unsigned char *buf, int bytesAvailable)
 { /* Begin pc_write */
-
-       register unsigned int head, tail;
-       register int dataLen;
-       register int size;
-       register int amountCopied;
-
-
+       unsigned int head, tail;
+       int dataLen;
+       int size;
+       int amountCopied;
        struct channel *ch;
        unsigned long flags;
        int remain;
-       volatile struct board_chan *bc;
-
+       struct board_chan *bc;
 
        /* ----------------------------------------------------------------
                pc_write is primarily called directly by the kernel routine
@@ -706,24 +641,20 @@ static int pc_write(struct tty_struct * tty,
 
        bc   = ch->brdchan;
        size = ch->txbufsize;
-
        amountCopied = 0;
-       save_flags(flags);
-       cli();
 
+       spin_lock_irqsave(&epca_lock, flags);
        globalwinon(ch);
 
-       head = bc->tin & (size - 1);
-       tail = bc->tout;
+       head = readw(&bc->tin) & (size - 1);
+       tail = readw(&bc->tout);
 
-       if (tail != bc->tout)
-               tail = bc->tout;
+       if (tail != readw(&bc->tout))
+               tail = readw(&bc->tout);
        tail &= (size - 1);
 
        /*      If head >= tail, head has not wrapped around. */ 
-       if (head >= tail) 
-       { /* Begin head has not wrapped */
-
+       if (head >= tail)  { /* Begin head has not wrapped */
                /* ---------------------------------------------------------------
                        remain (much like dataLen above) represents the total amount of
                        space available on the card for data.  Here dataLen represents
@@ -731,26 +662,19 @@ static int pc_write(struct tty_struct * tty,
                        buffer.  This is important because a memcpy cannot be told to
                        automatically wrap around when it hits the buffer end.
                ------------------------------------------------------------------ */ 
-
                dataLen = size - head;
                remain = size - (head - tail) - 1;
-
-       } /* End head has not wrapped */
-       else 
-       { /* Begin head has wrapped around */
+       } else { /* Begin head has wrapped around */
 
                remain = tail - head - 1;
                dataLen = remain;
 
        } /* End head has wrapped around */
-
        /* -------------------------------------------------------------------
                        Check the space on the card.  If we have more data than 
                        space; reduce the amount of data to fit the space.
        ---------------------------------------------------------------------- */
-
        bytesAvailable = min(remain, bytesAvailable);
-
        txwinon(ch);
        while (bytesAvailable > 0) 
        { /* Begin while there is data to copy onto card */
@@ -767,26 +691,21 @@ static int pc_write(struct tty_struct * tty,
                amountCopied += dataLen;
                bytesAvailable -= dataLen;
 
-               if (head >= size) 
-               {
+               if (head >= size) {
                        head = 0;
                        dataLen = tail;
                }
-
        } /* End while there is data to copy onto card */
-
        ch->statusflags |= TXBUSY;
        globalwinon(ch);
-       bc->tin = head;
+       writew(head, &bc->tin);
 
-       if ((ch->statusflags & LOWWAIT) == 0) 
-       {
+       if ((ch->statusflags & LOWWAIT) == 0)  {
                ch->statusflags |= LOWWAIT;
-               bc->ilow = 1;
+               writeb(1, &bc->ilow);
        }
        memoff(ch);
-       restore_flags(flags);
-
+       spin_unlock_irqrestore(&epca_lock, flags);
        return(amountCopied);
 
 } /* End pc_write */
@@ -795,11 +714,7 @@ static int pc_write(struct tty_struct * tty,
 
 static void pc_put_char(struct tty_struct *tty, unsigned char c)
 { /* Begin pc_put_char */
-
-   
        pc_write(tty, &c, 1);
-       return;
-
 } /* End pc_put_char */
 
 /* ------------------ Begin pc_write_room  ------------------------- */
@@ -811,7 +726,7 @@ static int pc_write_room(struct tty_struct *tty)
        struct channel *ch;
        unsigned long flags;
        unsigned int head, tail;
-       volatile struct board_chan *bc;
+       struct board_chan *bc;
 
        remain = 0;
 
@@ -820,33 +735,29 @@ static int pc_write_room(struct tty_struct *tty)
                if it is valid.  This serves as a sanity check.
        ------------------------------------------------------------- */
 
-       if ((ch = verifyChannel(tty)) != NULL) 
-       {
-               save_flags(flags);
-               cli();
+       if ((ch = verifyChannel(tty)) != NULL)  {
+               spin_lock_irqsave(&epca_lock, flags);
                globalwinon(ch);
 
                bc   = ch->brdchan;
-               head = bc->tin & (ch->txbufsize - 1);
-               tail = bc->tout;
+               head = readw(&bc->tin) & (ch->txbufsize - 1);
+               tail = readw(&bc->tout);
 
-               if (tail != bc->tout)
-                       tail = bc->tout;
+               if (tail != readw(&bc->tout))
+                       tail = readw(&bc->tout);
                /* Wrap tail if necessary */
                tail &= (ch->txbufsize - 1);
 
                if ((remain = tail - head - 1) < 0 )
                        remain += ch->txbufsize;
 
-               if (remain && (ch->statusflags & LOWWAIT) == 0) 
-               {
+               if (remain && (ch->statusflags & LOWWAIT) == 0) {
                        ch->statusflags |= LOWWAIT;
-                       bc->ilow = 1;
+                       writeb(1, &bc->ilow);
                }
                memoff(ch);
-               restore_flags(flags);
+               spin_unlock_irqrestore(&epca_lock, flags);
        }
-
        /* Return how much room is left on card */
        return remain;
 
@@ -862,8 +773,7 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
        int remain;
        unsigned long flags;
        struct channel *ch;
-       volatile struct board_chan *bc;
-
+       struct board_chan *bc;
 
        /* ---------------------------------------------------------
                verifyChannel returns the channel from the tty struct
@@ -873,34 +783,27 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
        if ((ch = verifyChannel(tty)) == NULL)
                return(0);
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&epca_lock, flags);
        globalwinon(ch);
 
        bc = ch->brdchan;
-       tail = bc->tout;
-       head = bc->tin;
-       ctail = ch->mailbox->cout;
+       tail = readw(&bc->tout);
+       head = readw(&bc->tin);
+       ctail = readw(&ch->mailbox->cout);
 
-       if (tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0)
+       if (tail == head && readw(&ch->mailbox->cin) == ctail && readb(&bc->tbusy) == 0)
                chars = 0;
-       else 
-       { /* Begin if some space on the card has been used */
-
-               head = bc->tin & (ch->txbufsize - 1);
+       else  { /* Begin if some space on the card has been used */
+               head = readw(&bc->tin) & (ch->txbufsize - 1);
                tail &= (ch->txbufsize - 1);
-
                /*  --------------------------------------------------------------
                        The logic here is basically opposite of the above pc_write_room
                        here we are finding the amount of bytes in the buffer filled.
                        Not the amount of bytes empty.
                ------------------------------------------------------------------- */
-
                if ((remain = tail - head - 1) < 0 )
                        remain += ch->txbufsize;
-
                chars = (int)(ch->txbufsize - remain);
-
                /* -------------------------------------------------------------  
                        Make it possible to wakeup anything waiting for output
                        in tty_ioctl.c, etc.
@@ -908,15 +811,12 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
                        If not already set.  Setup an event to indicate when the
                        transmit buffer empties 
                ----------------------------------------------------------------- */
-
                if (!(ch->statusflags & EMPTYWAIT))
                        setup_empty_event(tty,ch);
 
        } /* End if some space on the card has been used */
-
        memoff(ch);
-       restore_flags(flags);
-
+       spin_unlock_irqrestore(&epca_lock, flags);
        /* Return number of characters residing on card. */
        return(chars);
 
@@ -930,67 +830,46 @@ static void pc_flush_buffer(struct tty_struct *tty)
        unsigned int tail;
        unsigned long flags;
        struct channel *ch;
-       volatile struct board_chan *bc;
-
-
+       struct board_chan *bc;
        /* ---------------------------------------------------------
                verifyChannel returns the channel from the tty struct
                if it is valid.  This serves as a sanity check.
        ------------------------------------------------------------- */
-
        if ((ch = verifyChannel(tty)) == NULL)
                return;
 
-       save_flags(flags);
-       cli();
-
+       spin_lock_irqsave(&epca_lock, flags);
        globalwinon(ch);
-
        bc   = ch->brdchan;
-       tail = bc->tout;
-
+       tail = readw(&bc->tout);
        /* Have FEP move tout pointer; effectively flushing transmit buffer */
-
        fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
-
        memoff(ch);
-       restore_flags(flags);
-
+       spin_unlock_irqrestore(&epca_lock, flags);
        wake_up_interruptible(&tty->write_wait);
        tty_wakeup(tty);
-
 } /* End pc_flush_buffer */
 
 /* ------------------ Begin pc_flush_chars  ---------------------- */
 
 static void pc_flush_chars(struct tty_struct *tty)
 { /* Begin pc_flush_chars */
-
        struct channel * ch;
-
        /* ---------------------------------------------------------
                verifyChannel returns the channel from the tty struct
                if it is valid.  This serves as a sanity check.
        ------------------------------------------------------------- */
-
-       if ((ch = verifyChannel(tty)) != NULL) 
-       {
+       if ((ch = verifyChannel(tty)) != NULL) {
                unsigned long flags;
-
-               save_flags(flags);
-               cli();
-
+               spin_lock_irqsave(&epca_lock, flags);
                /* ----------------------------------------------------------------
                        If not already set and the transmitter is busy setup an event
                        to indicate when the transmit empties.
                ------------------------------------------------------------------- */
-
                if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
                        setup_empty_event(tty,ch);
-
-               restore_flags(flags);
+               spin_unlock_irqrestore(&epca_lock, flags);
        }
-
 } /* End pc_flush_chars */
 
 /* ------------------ Begin block_til_ready  ---------------------- */
@@ -998,14 +877,11 @@ static void pc_flush_chars(struct tty_struct *tty)
 static int block_til_ready(struct tty_struct *tty, 
                            struct file *filp, struct channel *ch)
 { /* Begin block_til_ready */
-
        DECLARE_WAITQUEUE(wait,current);
        int     retval, do_clocal = 0;
        unsigned long flags;
 
-
-       if (tty_hung_up_p(filp))
-       {
+       if (tty_hung_up_p(filp)) {
                if (ch->asyncflags & ASYNC_HUP_NOTIFY)
                        retval = -EAGAIN;
                else
@@ -1017,8 +893,7 @@ static int block_til_ready(struct tty_struct *tty,
                If the device is in the middle of being closed, then block
                until it's done, and then try again.
        -------------------------------------------------------------------- */
-       if (ch->asyncflags & ASYNC_CLOSING) 
-       {
+       if (ch->asyncflags & ASYNC_CLOSING) {
                interruptible_sleep_on(&ch->close_wait);
 
                if (ch->asyncflags & ASYNC_HUP_NOTIFY)
@@ -1027,43 +902,29 @@ static int block_til_ready(struct tty_struct *tty,
                        return -ERESTARTSYS;
        }
 
-       if (filp->f_flags & O_NONBLOCK) 
-       {
+       if (filp->f_flags & O_NONBLOCK)  {
                /* ----------------------------------------------------------------- 
                 If non-blocking mode is set, then make the check up front
                 and then exit.
                -------------------------------------------------------------------- */
-
                ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
-
                return 0;
        }
-
-
        if (tty->termios->c_cflag & CLOCAL)
                do_clocal = 1;
-       
-   /* Block waiting for the carrier detect and the line to become free */
+       /* Block waiting for the carrier detect and the line to become free */
        
        retval = 0;
        add_wait_queue(&ch->open_wait, &wait);
-       save_flags(flags);
-       cli();
-
 
+       spin_lock_irqsave(&epca_lock, flags);
        /* We dec count so that pc_close will know when to free things */
        if (!tty_hung_up_p(filp))
                ch->count--;
-
-       restore_flags(flags);
-
        ch->blocked_open++;
-
        while(1) 
        { /* Begin forever while  */
-
                set_current_state(TASK_INTERRUPTIBLE);
-
                if (tty_hung_up_p(filp) ||
                    !(ch->asyncflags & ASYNC_INITIALIZED)) 
                {
@@ -1073,17 +934,14 @@ static int block_til_ready(struct tty_struct *tty,
                                retval = -ERESTARTSYS;  
                        break;
                }
-
                if (!(ch->asyncflags & ASYNC_CLOSING) && 
                          (do_clocal || (ch->imodem & ch->dcd)))
                        break;
-
-               if (signal_pending(current)) 
-               {
+               if (signal_pending(current)) {
                        retval = -ERESTARTSYS;
                        break;
                }
-
+               spin_unlock_irqrestore(&epca_lock, flags);
                /* ---------------------------------------------------------------
                        Allow someone else to be scheduled.  We will occasionally go
                        through this loop until one of the above conditions change.
@@ -1091,25 +949,23 @@ static int block_til_ready(struct tty_struct *tty,
                        prevent this loop from hogging the cpu.
                ------------------------------------------------------------------ */
                schedule();
+               spin_lock_irqsave(&epca_lock, flags);
 
        } /* End forever while  */
 
        current->state = TASK_RUNNING;
        remove_wait_queue(&ch->open_wait, &wait);
-       cli();
        if (!tty_hung_up_p(filp))
                ch->count++;
-       restore_flags(flags);
-
        ch->blocked_open--;
 
+       spin_unlock_irqrestore(&epca_lock, flags);
+
        if (retval)
                return retval;
 
        ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
-
        return 0;
-
 } /* End block_til_ready */    
 
 /* ------------------ Begin pc_open  ---------------------- */
@@ -1120,17 +976,12 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
        struct channel *ch;
        unsigned long flags;
        int line, retval, boardnum;
-       volatile struct board_chan *bc;
-       volatile unsigned int head;
+       struct board_chan *bc;
+       unsigned int head;
 
        line = tty->index;
-       if (line < 0 || line >= nbdevs) 
-       {
-               printk(KERN_ERR "<Error> - pc_open : line out of range in pc_open\n");
-               tty->driver_data = NULL;
-               return(-ENODEV);
-       }
-
+       if (line < 0 || line >= nbdevs)
+               return -ENODEV;
 
        ch = &digi_channels[line];
        boardnum = ch->boardnum;
@@ -1143,66 +994,49 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
                goes here.
        ---------------------------------------------------------------------- */
 
-       if (invalid_lilo_config)
-       {
+       if (invalid_lilo_config) {
                if (setup_error_code & INVALID_BOARD_TYPE)
-                       printk(KERN_ERR "<Error> - pc_open: Invalid board type specified in LILO command\n");
-
+                       printk(KERN_ERR "epca: pc_open: Invalid board type specified in kernel options.\n");
                if (setup_error_code & INVALID_NUM_PORTS)
-                       printk(KERN_ERR "<Error> - pc_open: Invalid number of ports specified in LILO command\n");
-
+                       printk(KERN_ERR "epca: pc_open: Invalid number of ports specified in kernel options.\n");
                if (setup_error_code & INVALID_MEM_BASE)
-                       printk(KERN_ERR "<Error> - pc_open: Invalid board memory address specified in LILO command\n");
-
+                       printk(KERN_ERR "epca: pc_open: Invalid board memory address specified in kernel options.\n");
                if (setup_error_code & INVALID_PORT_BASE)
-                       printk(KERN_ERR "<Error> - pc_open: Invalid board port address specified in LILO command\n");
-
+                       printk(KERN_ERR "epca; pc_open: Invalid board port address specified in kernel options.\n");
                if (setup_error_code & INVALID_BOARD_STATUS)
-                       printk(KERN_ERR "<Error> - pc_open: Invalid board status specified in LILO command\n");
-
+                       printk(KERN_ERR "epca: pc_open: Invalid board status specified in kernel options.\n");
                if (setup_error_code & INVALID_ALTPIN)
-                       printk(KERN_ERR "<Error> - pc_open: Invalid board altpin specified in LILO command\n");
-
+                       printk(KERN_ERR "epca: pc_open: Invalid board altpin specified in kernel options;\n");
                tty->driver_data = NULL;   /* Mark this device as 'down' */
-               return(-ENODEV);
+               return -ENODEV;
        }
-
-       if ((boardnum >= num_cards) || (boards[boardnum].status == DISABLED)) 
-       {
+       if (boardnum >= num_cards || boards[boardnum].status == DISABLED)  {
                tty->driver_data = NULL;   /* Mark this device as 'down' */
                return(-ENODEV);
        }
        
-       if (( bc = ch->brdchan) == 0) 
-       {
+       if ((bc = ch->brdchan) == 0) {
                tty->driver_data = NULL;
-               return(-ENODEV);
+               return -ENODEV;
        }
 
+       spin_lock_irqsave(&epca_lock, flags);
        /* ------------------------------------------------------------------
                Every time a channel is opened, increment a counter.  This is 
                necessary because we do not wish to flush and shutdown the channel
                until the last app holding the channel open, closes it.         
        --------------------------------------------------------------------- */
-
        ch->count++;
-
        /* ----------------------------------------------------------------
                Set a kernel structures pointer to our local channel 
                structure.  This way we can get to it when passed only
                a tty struct.
        ------------------------------------------------------------------ */
-
        tty->driver_data = ch;
-       
        /* ----------------------------------------------------------------
                If this is the first time the channel has been opened, initialize
                the tty->termios struct otherwise let pc_close handle it.
        -------------------------------------------------------------------- */
-
-       save_flags(flags);
-       cli();
-
        globalwinon(ch);
        ch->statusflags = 0;
 
@@ -1213,8 +1047,8 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
           Set receive head and tail ptrs to each other.  This indicates
           no data available to read.
        ----------------------------------------------------------------- */
-       head = bc->rin;
-       bc->rout = head;
+       head = readw(&bc->rin);
+       writew(head, &bc->rout);
 
        /* Set the channels associated tty structure */
        ch->tty = tty;
@@ -1224,122 +1058,74 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
                issues, etc.... It effect both control flags and input flags.
        -------------------------------------------------------------------- */
        epcaparam(tty,ch);
-
        ch->asyncflags |= ASYNC_INITIALIZED;
        memoff(ch);
-
-       restore_flags(flags);
+       spin_unlock_irqrestore(&epca_lock, flags);
 
        retval = block_til_ready(tty, filp, ch);
        if (retval)
-       {
                return retval;
-       }
-
        /* -------------------------------------------------------------
                Set this again in case a hangup set it to zero while this 
                open() was waiting for the line...
        --------------------------------------------------------------- */
+       spin_lock_irqsave(&epca_lock, flags);
        ch->tty = tty;
-
-       save_flags(flags);
-       cli();
        globalwinon(ch);
-
        /* Enable Digi Data events */
-       bc->idata = 1;
-
+       writeb(1, &bc->idata);
        memoff(ch);
-       restore_flags(flags);
-
+       spin_unlock_irqrestore(&epca_lock, flags);
        return 0;
-
 } /* End pc_open */
 
-#ifdef MODULE
 static int __init epca_module_init(void)
 { /* Begin init_module */
-
-       unsigned long   flags;
-
-       save_flags(flags);
-       cli();
-
-       pc_init();
-
-       restore_flags(flags);
-
-       return(0);
+       return pc_init();
 }
 
 module_init(epca_module_init);
-#endif
 
-#ifdef ENABLE_PCI
 static struct pci_driver epca_driver;
-#endif
-
-#ifdef MODULE
-/* -------------------- Begin cleanup_module  ---------------------- */
 
 static void __exit epca_module_exit(void)
 {
-
        int               count, crd;
        struct board_info *bd;
        struct channel    *ch;
-       unsigned long     flags;
 
        del_timer_sync(&epca_timer);
 
-       save_flags(flags);
-       cli();
-
        if ((tty_unregister_driver(pc_driver)) ||  
            (tty_unregister_driver(pc_info)))
        {
-               printk(KERN_WARNING "<Error> - DIGI : cleanup_module failed to un-register tty driver\n");
-               restore_flags(flags);
+               printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n");
                return;
        }
        put_tty_driver(pc_driver);
        put_tty_driver(pc_info);
 
-       for (crd = 0; crd < num_cards; crd++) 
-       { /* Begin for each card */
-
+       for (crd = 0; crd < num_cards; crd++)  { /* Begin for each card */
                bd = &boards[crd];
-
                if (!bd)
                { /* Begin sanity check */
                        printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");
                        return;
                } /* End sanity check */
-
-               ch = card_ptr[crd]; 
-
+               ch = card_ptr[crd];
                for (count = 0; count < bd->numports; count++, ch++) 
                { /* Begin for each port */
-
-                       if (ch) 
-                       {
+                       if (ch) {
                                if (ch->tty)
                                        tty_hangup(ch->tty);
                                kfree(ch->tmp_buf);
                        }
-
                } /* End for each port */
        } /* End for each card */
-
-#ifdef ENABLE_PCI
        pci_unregister_driver (&epca_driver);
-#endif
-
-       restore_flags(flags);
-
 }
+
 module_exit(epca_module_exit);
-#endif /* MODULE */
 
 static struct tty_operations pc_ops = {
        .open = pc_open,
@@ -1371,34 +1157,15 @@ static struct tty_operations info_ops = {
 
 /* ------------------ Begin pc_init  ---------------------- */
 
-int __init pc_init(void)
+static int __init pc_init(void)
 { /* Begin pc_init */
-
-       /* ----------------------------------------------------------------
-               pc_init is called by the operating system during boot up prior to
-               any open calls being made.  In the older versions of Linux (Prior
-               to 2.0.0) an entry is made into tty_io.c.  A pointer to the last
-               memory location (from kernel space) used (kmem_start) is passed
-               to pc_init.  It is pc_inits responsibility to modify this value 
-               for any memory that the Digi driver might need and then return
-               this value to the operating system.  For example if the driver
-               wishes to allocate 1K of kernel memory, pc_init would return 
-               (kmem_start + 1024).  This memory (Between kmem_start and kmem_start
-               + 1024) would then be available for use exclusively by the driver.  
-               In this case our driver does not allocate any of this kernel 
-               memory.
-       ------------------------------------------------------------------*/
-
-       ulong flags;
        int crd;
        struct board_info *bd;
        unsigned char board_id = 0;
 
-#ifdef ENABLE_PCI
        int pci_boards_found, pci_count;
 
        pci_count = 0;
-#endif /* ENABLE_PCI */
 
        pc_driver = alloc_tty_driver(MAX_ALLOC);
        if (!pc_driver)
@@ -1416,8 +1183,7 @@ int __init pc_init(void)
                Note : If LILO has ran epca_setup then epca_setup will handle defining
                num_cards as well as copying the data into the board structure.
        -------------------------------------------------------------------------- */
-       if (!liloconfig)
-       { /* Begin driver has been configured via. epcaconfig */
+       if (!liloconfig) { /* Begin driver has been configured via. epcaconfig */
 
                nbdevs = NBDEVS;
                num_cards = NUMCARDS;
@@ -1440,8 +1206,6 @@ int __init pc_init(void)
 
        printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION);
 
-#ifdef ENABLE_PCI
-
        /* ------------------------------------------------------------------
                NOTE : This code assumes that the number of ports found in 
                       the boards array is correct.  This could be wrong if
@@ -1467,8 +1231,6 @@ int __init pc_init(void)
                pci_boards_found += init_PCI();
        num_cards += pci_boards_found;
 
-#endif /* ENABLE_PCI */
-
        pc_driver->owner = THIS_MODULE;
        pc_driver->name = "ttyD"; 
        pc_driver->devfs_name = "tts/D";
@@ -1499,9 +1261,6 @@ int __init pc_init(void)
        tty_set_operations(pc_info, &info_ops);
 
 
-       save_flags(flags);
-       cli();
-
        for (crd = 0; crd < num_cards; crd++) 
        { /* Begin for each card */
 
@@ -1610,11 +1369,7 @@ int __init pc_init(void)
                                        if ((board_id & 0x30) == 0x30) 
                                                bd->memory_seg = 0x8000;
 
-                               } /* End it is an XI card */
-                               else
-                               {
-                                       printk(KERN_ERR "<Error> - Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);
-                               }
+                               } else printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);
                        break;
 
                } /* End switch on bd->type */
@@ -1634,9 +1389,6 @@ int __init pc_init(void)
        init_timer(&epca_timer);
        epca_timer.function = epcapoll;
        mod_timer(&epca_timer, jiffies + HZ/25);
-
-       restore_flags(flags);
-
        return 0;
 
 } /* End pc_init */
@@ -1647,10 +1399,10 @@ static void post_fep_init(unsigned int crd)
 { /* Begin post_fep_init */
 
        int i;
-       unchar *memaddr;
-       volatile struct global_data *gd;
+       unsigned char *memaddr;
+       struct global_data *gd;
        struct board_info *bd;
-       volatile struct board_chan *bc;
+       struct board_chan *bc;
        struct channel *ch; 
        int shrinkmem = 0, lowwater ; 
  
@@ -1669,9 +1421,7 @@ static void post_fep_init(unsigned int crd)
                after DIGI_INIT has been called will return the proper values. 
        ------------------------------------------------------------------- */
 
-       if (bd->type >= PCIXEM) /* If the board in question is PCI */
-       { /* Begin get PCI number of ports */
-
+       if (bd->type >= PCIXEM) { /* Begin get PCI number of ports */
                /* --------------------------------------------------------------------
                        Below we use XEMPORTS as a memory offset regardless of which PCI
                        card it is.  This is because all of the supported PCI cards have
@@ -1685,15 +1435,15 @@ static void post_fep_init(unsigned int crd)
                        (FYI - The id should be located at 0x1ac (And may use up to 4 bytes
                        if the box in question is a XEM or CX)).  
                ------------------------------------------------------------------------ */ 
-
-               bd->numports = (unsigned short)*(unsigned char *)bus_to_virt((unsigned long)
-                                                       (bd->re_map_membase + XEMPORTS));
-
-               
+               /* PCI cards are already remapped at this point ISA are not */
+               bd->numports = readw(bd->re_map_membase + XEMPORTS);
                epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports");
                nbdevs += (bd->numports);
-
-       } /* End get PCI number of ports */
+       } else {
+               /* Fix up the mappings for ISA/EISA etc */
+               /* FIXME: 64K - can we be smarter ? */
+               bd->re_map_membase = ioremap(bd->membase, 0x10000);
+       }
 
        if (crd != 0)
                card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports;
@@ -1701,19 +1451,9 @@ static void post_fep_init(unsigned int crd)
                card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */
 
        ch = card_ptr[crd];
-
-
        epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range");
 
-       memaddr = (unchar *)bd->re_map_membase;
-
-       /* 
-          The below command is necessary because newer kernels (2.1.x and
-          up) do not have a 1:1 virtual to physical mapping.  The below
-          call adjust for that.
-       */
-
-       memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr);
+       memaddr = bd->re_map_membase;
 
        /* -----------------------------------------------------------------
                The below assignment will set bc to point at the BEGINING of
@@ -1721,7 +1461,7 @@ static void post_fep_init(unsigned int crd)
                8 and 64 of these structures.
        -------------------------------------------------------------------- */
 
-       bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT);
+       bc = (struct board_chan *)(memaddr + CHANSTRUCT);
 
        /* -------------------------------------------------------------------
                The below assignment will set gd to point at the BEGINING of
@@ -1730,20 +1470,18 @@ static void post_fep_init(unsigned int crd)
                pointer begins at 0xd10.
        ---------------------------------------------------------------------- */
 
-       gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL);
+       gd = (struct global_data *)(memaddr + GLOBAL);
 
        /* --------------------------------------------------------------------
                XEPORTS (address 0xc22) points at the number of channels the
                card supports. (For 64XE, XI, XEM, and XR use 0xc02)
        ----------------------------------------------------------------------- */
 
-       if (((bd->type == PCXEVE) | (bd->type == PCXE)) &&
-           (*(ushort *)((ulong)memaddr + XEPORTS) < 3))
+       if ((bd->type == PCXEVE || bd->type == PCXE) && (readw(memaddr + XEPORTS) < 3))
                shrinkmem = 1;
        if (bd->type < PCIXEM)
                if (!request_region((int)bd->port, 4, board_desc[bd->type]))
                        return;         
-
        memwinon(bd, 0);
 
        /*  --------------------------------------------------------------------
@@ -1753,17 +1491,16 @@ static void post_fep_init(unsigned int crd)
 
        /* For every port on the card do ..... */
 
-       for (i = 0; i < bd->numports; i++, ch++, bc++) 
-       { /* Begin for each port */
+       for (i = 0; i < bd->numports; i++, ch++, bc++)  { /* Begin for each port */
+               unsigned long flags;
 
                ch->brdchan        = bc;
                ch->mailbox        = gd; 
                INIT_WORK(&ch->tqueue, do_softint, ch);
                ch->board          = &boards[crd];
 
-               switch (bd->type)
-               { /* Begin switch bd->type */
-
+               spin_lock_irqsave(&epca_lock, flags);
+               switch (bd->type) {
                        /* ----------------------------------------------------------------
                                Since some of the boards use different bitmaps for their
                                control signals we cannot hard code these values and retain
@@ -1796,14 +1533,12 @@ static void post_fep_init(unsigned int crd)
        
                } /* End switch bd->type */
 
-               if (boards[crd].altpin) 
-               {
+               if (boards[crd].altpin) {
                        ch->dsr = ch->m_dcd;
                        ch->dcd = ch->m_dsr;
                        ch->digiext.digi_flags |= DIGI_ALTPIN;
                }
-               else 
-               { 
+               else {
                        ch->dcd = ch->m_dcd;
                        ch->dsr = ch->m_dsr;
                }
@@ -1813,14 +1548,12 @@ static void post_fep_init(unsigned int crd)
                ch->magic      = EPCA_MAGIC;
                ch->tty        = NULL;
 
-               if (shrinkmem) 
-               {
+               if (shrinkmem) {
                        fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
                        shrinkmem = 0;
                }
 
-               switch (bd->type)
-               { /* Begin switch bd->type */
+               switch (bd->type) {
 
                        case PCIXEM:
                        case PCIXRJ:
@@ -1878,13 +1611,13 @@ static void post_fep_init(unsigned int crd)
 
                fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0);
 
-               bc->edelay = 100;
-               bc->idata = 1;
+               writew(100, &bc->edelay);
+               writeb(1, &bc->idata);
        
-               ch->startc  = bc->startc;
-               ch->stopc   = bc->stopc;
-               ch->startca = bc->startca;
-               ch->stopca  = bc->stopca;
+               ch->startc  = readb(&bc->startc);
+               ch->stopc   = readb(&bc->stopc);
+               ch->startca = readb(&bc->startca);
+               ch->stopca  = readb(&bc->stopca);
        
                ch->fepcflag = 0;
                ch->fepiflag = 0;
@@ -1899,27 +1632,23 @@ static void post_fep_init(unsigned int crd)
                ch->blocked_open = 0;
                init_waitqueue_head(&ch->open_wait);
                init_waitqueue_head(&ch->close_wait);
+
+               spin_unlock_irqrestore(&epca_lock, flags);
+
                ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
-               if (!(ch->tmp_buf))
-               {
+               if (!ch->tmp_buf) {
                        printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i);
                        release_region((int)bd->port, 4);
                        while(i-- > 0)
                                kfree((ch--)->tmp_buf);
                        return;
-               }
-               else 
+               } else
                        memset((void *)ch->tmp_buf,0,ch->txbufsize);
        } /* End for each port */
 
        printk(KERN_INFO 
                "Digi PC/Xx Driver V%s:  %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n", 
                VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
-       sprintf(mesg, 
-               "Digi PC/Xx Driver V%s:  %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n", 
-               VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
-       console_print(mesg);
-
        memwinoff(bd, 0);
 
 } /* End post_fep_init */
@@ -1943,9 +1672,6 @@ static void epcapoll(unsigned long ignored)
                buffer empty) and acts on those events.
        ----------------------------------------------------------------------- */
        
-       save_flags(flags);
-       cli();
-
        for (crd = 0; crd < num_cards; crd++) 
        { /* Begin for each card */
 
@@ -1961,6 +1687,8 @@ static void epcapoll(unsigned long ignored)
                        some legacy boards.
                ---------------------------------------------------------------- */
 
+               spin_lock_irqsave(&epca_lock, flags);
+
                assertmemoff(ch);
 
                globalwinon(ch);
@@ -1970,21 +1698,19 @@ static void epcapoll(unsigned long ignored)
                        the transmit or receive queue.
                ------------------------------------------------------------------- */
 
-               head = ch->mailbox->ein;
-               tail = ch->mailbox->eout;
+               head = readw(&ch->mailbox->ein);
+               tail = readw(&ch->mailbox->eout);
                
                /* If head isn't equal to tail we have an event */
 
                if (head != tail)
                        doevent(crd);
-
                memoff(ch);
 
-       } /* End for each card */
+               spin_unlock_irqrestore(&epca_lock, flags);
 
+       } /* End for each card */
        mod_timer(&epca_timer, jiffies + (HZ / 25));
-
-       restore_flags(flags);
 } /* End epcapoll */
 
 /* --------------------- Begin doevent  ------------------------ */
@@ -1992,53 +1718,42 @@ static void epcapoll(unsigned long ignored)
 static void doevent(int crd)
 { /* Begin doevent */
 
-       volatile unchar *eventbuf;
+       void *eventbuf;
        struct channel *ch, *chan0;
        static struct tty_struct *tty;
-       volatile struct board_info *bd;
-       volatile struct board_chan *bc;
-       register volatile unsigned int tail, head;
-       register int event, channel;
-       register int mstat, lstat;
+       struct board_info *bd;
+       struct board_chan *bc;
+       unsigned int tail, head;
+       int event, channel;
+       int mstat, lstat;
 
        /* -------------------------------------------------------------------
                This subroutine is called by epcapoll when an event is detected 
                in the event queue.  This routine responds to those events.
        --------------------------------------------------------------------- */
-
        bd = &boards[crd];
 
        chan0 = card_ptr[crd];
        epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
-
        assertgwinon(chan0);
-
-       while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein)) 
+       while ((tail = readw(&chan0->mailbox->eout)) != (head = readw(&chan0->mailbox->ein)))
        { /* Begin while something in event queue */
-
                assertgwinon(chan0);
-
-               eventbuf = (volatile unchar *)bus_to_virt((ulong)(bd->re_map_membase + tail + ISTART));
-
+               eventbuf = bd->re_map_membase + tail + ISTART;
                /* Get the channel the event occurred on */
-               channel = eventbuf[0];
-
+               channel = readb(eventbuf);
                /* Get the actual event code that occurred */
-               event = eventbuf[1];
-
+               event = readb(eventbuf + 1);
                /*  ----------------------------------------------------------------
                        The two assignments below get the current modem status (mstat)
                        and the previous modem status (lstat).  These are useful becuase
                        an event could signal a change in modem signals itself.
                ------------------------------------------------------------------- */
-
-               mstat = eventbuf[2];
-               lstat = eventbuf[3];
+               mstat = readb(eventbuf + 2);
+               lstat = readb(eventbuf + 3);
 
                ch = chan0 + channel;
-
-               if ((unsigned)channel >= bd->numports || !ch) 
-               { 
+               if ((unsigned)channel >= bd->numports || !ch)  {
                        if (channel >= bd->numports)
                                ch = chan0;
                        bc = ch->brdchan;
@@ -2048,97 +1763,53 @@ static void doevent(int crd)
                if ((bc = ch->brdchan) == NULL)
                        goto next;
 
-               if (event & DATA_IND) 
-               { /* Begin DATA_IND */
-
+               if (event & DATA_IND)  { /* Begin DATA_IND */
                        receive_data(ch);
                        assertgwinon(ch);
-
                } /* End DATA_IND */
                /* else *//* Fix for DCD transition missed bug */
-               if (event & MODEMCHG_IND) 
-               { /* Begin MODEMCHG_IND */
-
+               if (event & MODEMCHG_IND)  { /* Begin MODEMCHG_IND */
                        /* A modem signal change has been indicated */
-
                        ch->imodem = mstat;
-
-                       if (ch->asyncflags & ASYNC_CHECK_CD) 
-                       {
+                       if (ch->asyncflags & ASYNC_CHECK_CD)  {
                                if (mstat & ch->dcd)  /* We are now receiving dcd */
                                        wake_up_interruptible(&ch->open_wait);
                                else
                                        pc_sched_event(ch, EPCA_EVENT_HANGUP); /* No dcd; hangup */
                        }
-
                } /* End MODEMCHG_IND */
-
                tty = ch->tty;
-               if (tty) 
-               { /* Begin if valid tty */
-
-                       if (event & BREAK_IND) 
-                       { /* Begin if BREAK_IND */
-
+               if (tty)  { /* Begin if valid tty */
+                       if (event & BREAK_IND)  { /* Begin if BREAK_IND */
                                /* A break has been indicated */
-
                                tty->flip.count++;
                                *tty->flip.flag_buf_ptr++ = TTY_BREAK;
-
                                *tty->flip.char_buf_ptr++ = 0;
-
                                tty_schedule_flip(tty); 
-
-                       } /* End if BREAK_IND */
-                       else
-                       if (event & LOWTX_IND) 
-                       { /* Begin LOWTX_IND */
-
+                       } else if (event & LOWTX_IND)  { /* Begin LOWTX_IND */
                                if (ch->statusflags & LOWWAIT) 
                                { /* Begin if LOWWAIT */
-
                                        ch->statusflags &= ~LOWWAIT;
                                        tty_wakeup(tty);
                                        wake_up_interruptible(&tty->write_wait);
-
                                } /* End if LOWWAIT */
-
-                       } /* End LOWTX_IND */
-                       else
-                       if (event & EMPTYTX_IND) 
-                       { /* Begin EMPTYTX_IND */
-
+                       } else if (event & EMPTYTX_IND)  { /* Begin EMPTYTX_IND */
                                /* This event is generated by setup_empty_event */
-
                                ch->statusflags &= ~TXBUSY;
-                               if (ch->statusflags & EMPTYWAIT) 
-                               { /* Begin if EMPTYWAIT */
-
+                               if (ch->statusflags & EMPTYWAIT)  { /* Begin if EMPTYWAIT */
                                        ch->statusflags &= ~EMPTYWAIT;
                                        tty_wakeup(tty);
-
                                        wake_up_interruptible(&tty->write_wait);
-
                                } /* End if EMPTYWAIT */
-
                        } /* End EMPTYTX_IND */
-
                } /* End if valid tty */
-
-
        next:
                globalwinon(ch);
-
-               if (!bc)
-                       printk(KERN_ERR "<Error> - bc == NULL in doevent!\n");
-               else 
-                       bc->idata = 1;
-
-               chan0->mailbox->eout = (tail + 4) & (IMAX - ISTART - 4);
+               BUG_ON(!bc);
+               writew(1, &bc->idata);
+               writew((tail + 4) & (IMAX - ISTART - 4), &chan0->mailbox->eout);
                globalwinon(chan0);
-
        } /* End while something in event queue */
-
 } /* End doevent */
 
 /* --------------------- Begin fepcmd  ------------------------ */
@@ -2146,7 +1817,6 @@ static void doevent(int crd)
 static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
                    int byte2, int ncmds, int bytecmd)
 { /* Begin fepcmd */
-
        unchar *memaddr;
        unsigned int head, cmdTail, cmdStart, cmdMax;
        long count;
@@ -2155,93 +1825,57 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
        /* This is the routine in which commands may be passed to the card. */
 
        if (ch->board->status == DISABLED)
-       {
                return;
-       }
-
        assertgwinon(ch);
-
        /* Remember head (As well as max) is just an offset not a base addr */
-       head = ch->mailbox->cin;
-
+       head = readw(&ch->mailbox->cin);
        /* cmdStart is a base address */
-       cmdStart = ch->mailbox->cstart;
-
+       cmdStart = readw(&ch->mailbox->cstart);
        /* ------------------------------------------------------------------
                We do the addition below because we do not want a max pointer 
                relative to cmdStart.  We want a max pointer that points at the 
                physical end of the command queue.
        -------------------------------------------------------------------- */
-
-       cmdMax = (cmdStart + 4 + (ch->mailbox->cmax));
-
+       cmdMax = (cmdStart + 4 + readw(&ch->mailbox->cmax));
        memaddr = ch->board->re_map_membase;
 
-       /* 
-          The below command is necessary because newer kernels (2.1.x and
-          up) do not have a 1:1 virtual to physical mapping.  The below
-          call adjust for that.
-       */
-
-       memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr);
-
-       if (head >= (cmdMax - cmdStart) || (head & 03)) 
-       {
-               printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__, 
-              cmd, head);
-               printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__, 
-              cmdMax, cmdStart);
+       if (head >= (cmdMax - cmdStart) || (head & 03))  {
+               printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__,  cmd, head);
+               printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__,  cmdMax, cmdStart);
                return;
        }
-
-       if (bytecmd) 
-       {
-               *(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd;
-
-               *(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum;
+       if (bytecmd)  {
+               writeb(cmd, memaddr + head + cmdStart + 0);
+               writeb(ch->channelnum,  memaddr + head + cmdStart + 1);
                /* Below word_or_byte is bits to set */
-               *(volatile unchar *)(memaddr + head + cmdStart + 2) = (unchar)word_or_byte;
+               writeb(word_or_byte,  memaddr + head + cmdStart + 2);
                /* Below byte2 is bits to reset */
-               *(volatile unchar *)(memaddr + head + cmdStart + 3) = (unchar)byte2;
-
-       } 
-       else 
-       {
-               *(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd;
-               *(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum;
-               *(volatile ushort*)(memaddr + head + cmdStart + 2) = (ushort)word_or_byte;
+               writeb(byte2, memaddr + head + cmdStart + 3);
+       }  else {
+               writeb(cmd, memaddr + head + cmdStart + 0);
+               writeb(ch->channelnum,  memaddr + head + cmdStart + 1);
+               writeb(word_or_byte,  memaddr + head + cmdStart + 2);
        }
-
        head = (head + 4) & (cmdMax - cmdStart - 4);
-       ch->mailbox->cin = head;
-
+       writew(head, &ch->mailbox->cin);
        count = FEPTIMEOUT;
 
-       for (;;) 
-       { /* Begin forever loop */
-
+       for (;;)  { /* Begin forever loop */
                count--;
-               if (count == 0) 
-               {
+               if (count == 0)  {
                        printk(KERN_ERR "<Error> - Fep not responding in fepcmd()\n");
                        return;
                }
-
-               head = ch->mailbox->cin;
-               cmdTail = ch->mailbox->cout;
-
+               head = readw(&ch->mailbox->cin);
+               cmdTail = readw(&ch->mailbox->cout);
                n = (head - cmdTail) & (cmdMax - cmdStart - 4);
-
                /* ----------------------------------------------------------
                        Basically this will break when the FEP acknowledges the 
                        command by incrementing cmdTail (Making it equal to head).
                ------------------------------------------------------------- */
-
                if (n <= ncmds * (sizeof(short) * 4))
                        break; /* Well nearly forever :-) */
-
        } /* End forever loop */
-
 } /* End fepcmd */
 
 /* ---------------------------------------------------------------------
@@ -2255,11 +1889,9 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
 
 static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
 { /* Begin termios2digi_h */
-
        unsigned res = 0;
 
-       if (cflag & CRTSCTS) 
-       {
+       if (cflag & CRTSCTS) {
                ch->digiext.digi_flags |= (RTSPACE | CTSPACE);
                res |= ((ch->m_cts) | (ch->m_rts));
        }
@@ -2295,7 +1927,6 @@ static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
 
        unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | 
                                INPCK | ISTRIP|IXON|IXANY|IXOFF);
-       
        if (ch->digiext.digi_flags & DIGI_AIXON)
                res |= IAIXON;
        return res;
@@ -2308,28 +1939,15 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
 { /* Begin termios2digi_c */
 
        unsigned res = 0;
-
-#ifdef SPEED_HACK
-       /* CL: HACK to force 115200 at 38400 and 57600 at 19200 Baud */
-       if ((cflag & CBAUD)== B38400) cflag=cflag - B38400 + B115200;
-       if ((cflag & CBAUD)== B19200) cflag=cflag - B19200 + B57600;
-#endif /* SPEED_HACK */
-
-       if (cflag & CBAUDEX)
-       { /* Begin detected CBAUDEX */
-
+       if (cflag & CBAUDEX) { /* Begin detected CBAUDEX */
                ch->digiext.digi_flags |= DIGI_FAST;
-
                /* -------------------------------------------------------------
                   HUPCL bit is used by FEP to indicate fast baud
                   table is to be used.
                ----------------------------------------------------------------- */
-
                res |= FEP_HUPCL;
-
        } /* End detected CBAUDEX */
        else ch->digiext.digi_flags &= ~DIGI_FAST; 
-
        /* -------------------------------------------------------------------
                CBAUD has bit position 0x1000 set these days to indicate Linux
                baud rate remap.  Digi hardware can't handle the bit assignment.
@@ -2337,7 +1955,6 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
                bit out.
        ---------------------------------------------------------------------- */
        res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
-
        /* -------------------------------------------------------------
                This gets a little confusing.  The Digi cards have their own
                representation of c_cflags controling baud rate.  For the most
@@ -2357,10 +1974,8 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
                should be checked for a screened out prior to termios2digi_c 
                returning.  Since CLOCAL isn't used by the board this can be
                ignored as long as the returned value is used only by Digi hardware. 
-       ----------------------------------------------------------------- */
-
-       if (cflag & CBAUDEX)
-       {
+               ----------------------------------------------------------------- */
+       if (cflag & CBAUDEX) {
                /* -------------------------------------------------------------
                        The below code is trying to guarantee that only baud rates
                        115200 and 230400 are remapped.  We use exclusive or because
@@ -2371,138 +1986,96 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
                                
                if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) || 
                    (!((cflag & 0x7) ^ (B230400 & ~CBAUDEX))))
-               {
                        res += 1;
-               }
        }
-
        return res;
 
 } /* End termios2digi_c */
 
 /* --------------------- Begin epcaparam  ----------------------- */
 
+/* Caller must hold the locks */
 static void epcaparam(struct tty_struct *tty, struct channel *ch)
 { /* Begin epcaparam */
 
        unsigned int cmdHead;
        struct termios *ts;
-       volatile struct board_chan *bc;
+       struct board_chan *bc;
        unsigned mval, hflow, cflag, iflag;
 
        bc = ch->brdchan;
        epcaassert(bc !=0, "bc out of range");
 
        assertgwinon(ch);
-
        ts = tty->termios;
-
-       if ((ts->c_cflag & CBAUD) == 0) 
-       { /* Begin CBAUD detected */
-
-               cmdHead = bc->rin;
+       if ((ts->c_cflag & CBAUD) == 0)  { /* Begin CBAUD detected */
+               cmdHead = readw(&bc->rin);
                bc->rout = cmdHead;
-               cmdHead = bc->tin;
-
+               cmdHead = readw(&bc->tin);
                /* Changing baud in mid-stream transmission can be wonderful */
                /* ---------------------------------------------------------------
                        Flush current transmit buffer by setting cmdTail pointer (tout)
                        to cmdHead pointer (tin).  Hopefully the transmit buffer is empty.
                ----------------------------------------------------------------- */
-
                fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0);
                mval = 0;
-
-       } /* End CBAUD detected */
-       else 
-       { /* Begin CBAUD not detected */
-
+       } else  { /* Begin CBAUD not detected */
                /* -------------------------------------------------------------------
                        c_cflags have changed but that change had nothing to do with BAUD.
                        Propagate the change to the card.
                ---------------------------------------------------------------------- */ 
-
                cflag = termios2digi_c(ch, ts->c_cflag);
-
-               if (cflag != ch->fepcflag) 
-               {
+               if (cflag != ch->fepcflag)  {
                        ch->fepcflag = cflag;
                        /* Set baud rate, char size, stop bits, parity */
                        fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
                }
-
-
                /* ----------------------------------------------------------------
                        If the user has not forced CLOCAL and if the device is not a 
                        CALLOUT device (Which is always CLOCAL) we set flags such that
                        the driver will wait on carrier detect.
                ------------------------------------------------------------------- */
-
                if (ts->c_cflag & CLOCAL)
-               { /* Begin it is a cud device or a ttyD device with CLOCAL on */
                        ch->asyncflags &= ~ASYNC_CHECK_CD;
-               } /* End it is a cud device or a ttyD device with CLOCAL on */
                else
-               { /* Begin it is a ttyD device */
                        ch->asyncflags |= ASYNC_CHECK_CD;
-               } /* End it is a ttyD device */
-
                mval = ch->m_dtr | ch->m_rts;
-
        } /* End CBAUD not detected */
-
        iflag = termios2digi_i(ch, ts->c_iflag);
-
        /* Check input mode flags */
-
-       if (iflag != ch->fepiflag) 
-       {
+       if (iflag != ch->fepiflag)  {
                ch->fepiflag = iflag;
-
                /* ---------------------------------------------------------------
                        Command sets channels iflag structure on the board. Such things 
                        as input soft flow control, handling of parity errors, and
                        break handling are all set here.
                ------------------------------------------------------------------- */
-
                /* break handling, parity handling, input stripping, flow control chars */
                fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
        }
-
        /* ---------------------------------------------------------------
                Set the board mint value for this channel.  This will cause hardware
                events to be generated each time the DCD signal (Described in mint) 
                changes.        
        ------------------------------------------------------------------- */
-       bc->mint = ch->dcd;
-
+       writeb(ch->dcd, &bc->mint);
        if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
                if (ch->digiext.digi_flags & DIGI_FORCEDCD)
-                       bc->mint = 0;
-
-       ch->imodem = bc->mstat;
-
+                       writeb(0, &bc->mint);
+       ch->imodem = readb(&bc->mstat);
        hflow = termios2digi_h(ch, ts->c_cflag);
-
-       if (hflow != ch->hflow) 
-       {
+       if (hflow != ch->hflow)  {
                ch->hflow = hflow;
-
                /* --------------------------------------------------------------
                        Hard flow control has been selected but the board is not
                        using it.  Activate hard flow control now.
                ----------------------------------------------------------------- */
-
                fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
        }
-       
-
        mval ^= ch->modemfake & (mval ^ ch->modem);
 
-       if (ch->omodem ^ mval) 
-       {
+       if (ch->omodem ^ mval)  {
                ch->omodem = mval;
-
                /* --------------------------------------------------------------
                        The below command sets the DTR and RTS mstat structure.  If
                        hard flow control is NOT active these changes will drive the
@@ -2514,87 +2087,65 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
                /* First reset DTR & RTS; then set them */
                fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1);
                fepcmd(ch, SETMODEM, mval, 0, 0, 1);
-
        }
-
-       if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) 
-       {
+       if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc)  {
                ch->fepstartc = ch->startc;
                ch->fepstopc = ch->stopc;
-
                /* ------------------------------------------------------------
                        The XON / XOFF characters have changed; propagate these
                        changes to the card.    
                --------------------------------------------------------------- */
-
                fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
        }
-
-       if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) 
-       {
+       if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca)  {
                ch->fepstartca = ch->startca;
                ch->fepstopca = ch->stopca;
-
                /* ---------------------------------------------------------------
                        Similar to the above, this time the auxilarly XON / XOFF 
                        characters have changed; propagate these changes to the card.
                ------------------------------------------------------------------ */
-
                fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
        }
-
 } /* End epcaparam */
 
 /* --------------------- Begin receive_data  ----------------------- */
-
+/* Caller holds lock */
 static void receive_data(struct channel *ch)
 { /* Begin receive_data */
 
        unchar *rptr;
        struct termios *ts = NULL;
        struct tty_struct *tty;
-       volatile struct board_chan *bc;
-       register int dataToRead, wrapgap, bytesAvailable;
-       register unsigned int tail, head;
+       struct board_chan *bc;
+       int dataToRead, wrapgap, bytesAvailable;
+       unsigned int tail, head;
        unsigned int wrapmask;
        int rc;
 
-
        /* ---------------------------------------------------------------
                This routine is called by doint when a receive data event 
                has taken place.
        ------------------------------------------------------------------- */
 
        globalwinon(ch);
-
        if (ch->statusflags & RXSTOPPED)
                return;
-
        tty = ch->tty;
        if (tty)
                ts = tty->termios;
-
        bc = ch->brdchan;
-
-       if (!bc) 
-       {
-               printk(KERN_ERR "<Error> - bc is NULL in receive_data!\n");
-               return;
-       }
-
+       BUG_ON(!bc);
        wrapmask = ch->rxbufsize - 1;
 
        /* --------------------------------------------------------------------- 
                Get the head and tail pointers to the receiver queue.  Wrap the 
                head pointer if it has reached the end of the buffer.
        ------------------------------------------------------------------------ */
-
-       head = bc->rin;
+       head = readw(&bc->rin);
        head &= wrapmask;
-       tail = bc->rout & wrapmask;
+       tail = readw(&bc->rout) & wrapmask;
 
        bytesAvailable = (head - tail) & wrapmask;
-
        if (bytesAvailable == 0)
                return;
 
@@ -2602,8 +2153,7 @@ static void receive_data(struct channel *ch)
           If CREAD bit is off or device not open, set TX tail to head
        --------------------------------------------------------------------- */
 
-       if (!tty || !ts || !(ts->c_cflag & CREAD)) 
-       {
+       if (!tty || !ts || !(ts->c_cflag & CREAD))  {
                bc->rout = head;
                return;
        }
@@ -2611,64 +2161,45 @@ static void receive_data(struct channel *ch)
        if (tty->flip.count == TTY_FLIPBUF_SIZE) 
                return;
 
-       if (bc->orun) 
-       {
-               bc->orun = 0;
-               printk(KERN_WARNING "overrun! DigiBoard device %s\n",tty->name);
+       if (readb(&bc->orun)) {
+               writeb(0, &bc->orun);
+               printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",tty->name);
        }
-
        rxwinon(ch);
        rptr = tty->flip.char_buf_ptr;
        rc = tty->flip.count;
-
-       while (bytesAvailable > 0) 
-       { /* Begin while there is data on the card */
-
+       while (bytesAvailable > 0)  { /* Begin while there is data on the card */
                wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
-
                /* ---------------------------------------------------------------
                        Even if head has wrapped around only report the amount of
                        data to be equal to the size - tail.  Remember memcpy can't
                        automaticly wrap around the receive buffer.
                ----------------------------------------------------------------- */
-
                dataToRead = (wrapgap < bytesAvailable) ? wrapgap : bytesAvailable;
-
                /* --------------------------------------------------------------
                   Make sure we don't overflow the buffer
                ----------------------------------------------------------------- */
-
                if ((rc + dataToRead) > TTY_FLIPBUF_SIZE)
                        dataToRead = TTY_FLIPBUF_SIZE - rc;
-
                if (dataToRead == 0)
                        break;
-
                /* ---------------------------------------------------------------
                        Move data read from our card into the line disciplines buffer
                        for translation if necessary.
                ------------------------------------------------------------------ */
-
-               if ((memcpy(rptr, ch->rxptr + tail, dataToRead)) != rptr)
-                       printk(KERN_ERR "<Error> - receive_data : memcpy failed\n");
-                       
+               memcpy_fromio(rptr, ch->rxptr + tail, dataToRead);
                rc   += dataToRead;
                rptr += dataToRead;
                tail = (tail + dataToRead) & wrapmask;
                bytesAvailable -= dataToRead;
-
        } /* End while there is data on the card */
-
-
        tty->flip.count = rc;
        tty->flip.char_buf_ptr = rptr;
        globalwinon(ch);
-       bc->rout = tail;
-
+       writew(tail, &bc->rout);
        /* Must be called with global data */
        tty_schedule_flip(ch->tty); 
        return;
-
 } /* End receive_data */
 
 static int info_ioctl(struct tty_struct *tty, struct file * file,
@@ -2676,17 +2207,15 @@ static int info_ioctl(struct tty_struct *tty, struct file * file,
 {
        switch (cmd) 
        { /* Begin switch cmd */
-
                case DIGI_GETINFO:
                { /* Begin case DIGI_GETINFO */
-
                        struct digi_info di ;
                        int brd;
 
-                       getUser(brd, (unsigned int __user *)arg);
-
-                       if ((brd < 0) || (brd >= num_cards) || (num_cards == 0))
-                               return (-ENODEV);
+                       if(get_user(brd, (unsigned int __user *)arg))
+                               return -EFAULT;
+                       if (brd < 0 || brd >= num_cards || num_cards == 0)
+                               return -ENODEV;
 
                        memset(&di, 0, sizeof(di));
 
@@ -2694,8 +2223,9 @@ static int info_ioctl(struct tty_struct *tty, struct file * file,
                        di.status = boards[brd].status;
                        di.type = boards[brd].type ;
                        di.numports = boards[brd].numports ;
-                       di.port = boards[brd].port ;
-                       di.membase = boards[brd].membase ;
+                       /* Legacy fixups - just move along nothing to see */
+                       di.port = (unsigned char *)boards[brd].port ;
+                       di.membase = (unsigned char *)boards[brd].membase ;
 
                        if (copy_to_user((void __user *)arg, &di, sizeof (di)))
                                return -EFAULT;
@@ -2709,39 +2239,29 @@ static int info_ioctl(struct tty_struct *tty, struct file * file,
                        int brd = arg & 0xff000000 >> 16 ; 
                        unsigned char state = arg & 0xff ; 
 
-                       if ((brd < 0) || (brd >= num_cards))
-                       {
-                               printk(KERN_ERR "<Error> - DIGI POLLER : brd not valid!\n");
+                       if (brd < 0 || brd >= num_cards) {
+                               printk(KERN_ERR "epca: DIGI POLLER : brd not valid!\n");
                                return (-ENODEV);
                        }
-
                        digi_poller_inhibited = state ;
                        break ; 
-
                } /* End case DIGI_POLLER */
 
                case DIGI_INIT:
                { /* Begin case DIGI_INIT */
-
                        /* ------------------------------------------------------------
                                This call is made by the apps to complete the initilization
                                of the board(s).  This routine is responsible for setting
                                the card to its initial state and setting the drivers control
                                fields to the sutianle settings for the card in question.
                        ---------------------------------------------------------------- */
-               
                        int crd ; 
                        for (crd = 0; crd < num_cards; crd++) 
                                post_fep_init (crd);
-
                        break ; 
-
                } /* End case DIGI_INIT */
-
-
                default:
-                       return -ENOIOCTLCMD;
-
+                       return -ENOTTY;
        } /* End switch cmd */
        return (0) ;
 }
@@ -2750,43 +2270,33 @@ static int info_ioctl(struct tty_struct *tty, struct file * file,
 static int pc_tiocmget(struct tty_struct *tty, struct file *file)
 {
        struct channel *ch = (struct channel *) tty->driver_data;
-       volatile struct board_chan *bc;
+       struct board_chan *bc;
        unsigned int mstat, mflag = 0;
        unsigned long flags;
 
        if (ch)
                bc = ch->brdchan;
        else
-       {
-               printk(KERN_ERR "<Error> - ch is NULL in pc_tiocmget!\n");
-               return(-EINVAL);
-       }
+               return -EINVAL;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&epca_lock, flags);
        globalwinon(ch);
-       mstat = bc->mstat;
+       mstat = readb(&bc->mstat);
        memoff(ch);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&epca_lock, flags);
 
        if (mstat & ch->m_dtr)
                mflag |= TIOCM_DTR;
-
        if (mstat & ch->m_rts)
                mflag |= TIOCM_RTS;
-
        if (mstat & ch->m_cts)
                mflag |= TIOCM_CTS;
-
        if (mstat & ch->dsr)
                mflag |= TIOCM_DSR;
-
        if (mstat & ch->m_ri)
                mflag |= TIOCM_RI;
-
        if (mstat & ch->dcd)
                mflag |= TIOCM_CD;
-
        return mflag;
 }
 
@@ -2796,13 +2306,10 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file,
        struct channel *ch = (struct channel *) tty->driver_data;
        unsigned long flags;
 
-       if (!ch) {
-               printk(KERN_ERR "<Error> - ch is NULL in pc_tiocmset!\n");
-               return(-EINVAL);
-       }
+       if (!ch)
+               return -EINVAL;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&epca_lock, flags);
        /*
         * I think this modemfake stuff is broken.  It doesn't
         * correctly reflect the behaviour desired by the TIOCM*
@@ -2824,17 +2331,14 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file,
                ch->modemfake |= ch->m_dtr;
                ch->modem &= ~ch->m_dtr;
        }
-
        globalwinon(ch);
-
        /*  --------------------------------------------------------------
                The below routine generally sets up parity, baud, flow control
                issues, etc.... It effect both control flags and input flags.
        ------------------------------------------------------------------ */
-
        epcaparam(tty,ch);
        memoff(ch);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&epca_lock, flags);
        return 0;
 }
 
@@ -2847,19 +2351,14 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
        unsigned long flags;
        unsigned int mflag, mstat;
        unsigned char startc, stopc;
-       volatile struct board_chan *bc;
+       struct board_chan *bc;
        struct channel *ch = (struct channel *) tty->driver_data;
        void __user *argp = (void __user *)arg;
        
        if (ch)
                bc = ch->brdchan;
        else 
-       {
-               printk(KERN_ERR "<Error> - ch is NULL in pc_ioctl!\n");
-               return(-EINVAL);
-       }
-
-       save_flags(flags);
+               return -EINVAL;
 
        /* -------------------------------------------------------------------
                For POSIX compliance we need to add more ioctls.  See tty_ioctl.c
@@ -2871,46 +2370,39 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
        { /* Begin switch cmd */
 
                case TCGETS:
-                       if (copy_to_user(argp, 
-                                        tty->termios, sizeof(struct termios)))
+                       if (copy_to_user(argp, tty->termios, sizeof(struct termios)))
                                return -EFAULT;
-                       return(0);
-
+                       return 0;
                case TCGETA:
                        return get_termio(tty, argp);
-
                case TCSBRK:    /* SVID version: non-zero arg --> no break */
-
                        retval = tty_check_change(tty);
                        if (retval)
                                return retval;
-
                        /* Setup an event to indicate when the transmit buffer empties */
-
+                       spin_lock_irqsave(&epca_lock, flags);
                        setup_empty_event(tty,ch);              
+                       spin_unlock_irqrestore(&epca_lock, flags);
                        tty_wait_until_sent(tty, 0);
                        if (!arg)
                                digi_send_break(ch, HZ/4);    /* 1/4 second */
                        return 0;
-
                case TCSBRKP:   /* support for POSIX tcsendbreak() */
-
                        retval = tty_check_change(tty);
                        if (retval)
                                return retval;
 
                        /* Setup an event to indicate when the transmit buffer empties */
-
+                       spin_lock_irqsave(&epca_lock, flags);
                        setup_empty_event(tty,ch);              
+                       spin_unlock_irqrestore(&epca_lock, flags);
                        tty_wait_until_sent(tty, 0);
                        digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
                        return 0;
-
                case TIOCGSOFTCAR:
                        if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)arg))
                                return -EFAULT;
                        return 0;
-
                case TIOCSSOFTCAR:
                {
                        unsigned int value;
@@ -2922,75 +2414,63 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
                                 (value ? CLOCAL : 0));
                        return 0;
                }
-
                case TIOCMODG:
                        mflag = pc_tiocmget(tty, file);
                        if (put_user(mflag, (unsigned long __user *)argp))
                                return -EFAULT;
                        break;
-
                case TIOCMODS:
                        if (get_user(mstat, (unsigned __user *)argp))
                                return -EFAULT;
                        return pc_tiocmset(tty, file, mstat, ~mstat);
-
                case TIOCSDTR:
+                       spin_lock_irqsave(&epca_lock, flags);
                        ch->omodem |= ch->m_dtr;
-                       cli();
                        globalwinon(ch);
                        fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1);
                        memoff(ch);
-                       restore_flags(flags);
+                       spin_unlock_irqrestore(&epca_lock, flags);
                        break;
 
                case TIOCCDTR:
+                       spin_lock_irqsave(&epca_lock, flags);
                        ch->omodem &= ~ch->m_dtr;
-                       cli();
                        globalwinon(ch);
                        fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1);
                        memoff(ch);
-                       restore_flags(flags);
+                       spin_unlock_irqrestore(&epca_lock, flags);
                        break;
-
                case DIGI_GETA:
                        if (copy_to_user(argp, &ch->digiext, sizeof(digi_t)))
                                return -EFAULT;
                        break;
-
                case DIGI_SETAW:
                case DIGI_SETAF:
-                       if ((cmd) == (DIGI_SETAW)) 
-                       {
+                       if (cmd == DIGI_SETAW) {
                                /* Setup an event to indicate when the transmit buffer empties */
-
+                               spin_lock_irqsave(&epca_lock, flags);
                                setup_empty_event(tty,ch);              
+                               spin_unlock_irqrestore(&epca_lock, flags);
                                tty_wait_until_sent(tty, 0);
-                       }
-                       else 
-                       {
+                       } else  {
                                /* ldisc lock already held in ioctl */
                                if (tty->ldisc.flush_buffer)
                                        tty->ldisc.flush_buffer(tty);
                        }
-
                        /* Fall Thru */
-
                case DIGI_SETA:
                        if (copy_from_user(&ch->digiext, argp, sizeof(digi_t)))
                                return -EFAULT;
                        
-                       if (ch->digiext.digi_flags & DIGI_ALTPIN) 
-                       {
+                       if (ch->digiext.digi_flags & DIGI_ALTPIN)  {
                                ch->dcd = ch->m_dsr;
                                ch->dsr = ch->m_dcd;
-                       } 
-                       else 
-                       {
+                       } else {
                                ch->dcd = ch->m_dcd;
                                ch->dsr = ch->m_dsr;
                        }
                
-                       cli();
+                       spin_lock_irqsave(&epca_lock, flags);
                        globalwinon(ch);
 
                        /* -----------------------------------------------------------------
@@ -3000,25 +2480,22 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
 
                        epcaparam(tty,ch);
                        memoff(ch);
-                       restore_flags(flags);
+                       spin_unlock_irqrestore(&epca_lock, flags);
                        break;
 
                case DIGI_GETFLOW:
                case DIGI_GETAFLOW:
-                       cli();  
+                       spin_lock_irqsave(&epca_lock, flags);
                        globalwinon(ch);
-                       if ((cmd) == (DIGI_GETFLOW)) 
-                       {
-                               dflow.startc = bc->startc;
-                               dflow.stopc = bc->stopc;
-                       }
-                       else 
-                       {
-                               dflow.startc = bc->startca;
-                               dflow.stopc = bc->stopca;
+                       if (cmd == DIGI_GETFLOW) {
+                               dflow.startc = readb(&bc->startc);
+                               dflow.stopc = readb(&bc->stopc);
+                       } else {
+                               dflow.startc = readb(&bc->startca);
+                               dflow.stopc = readb(&bc->stopca);
                        }
                        memoff(ch);
-                       restore_flags(flags);
+                       spin_unlock_irqrestore(&epca_lock, flags);
 
                        if (copy_to_user(argp, &dflow, sizeof(dflow)))
                                return -EFAULT;
@@ -3026,13 +2503,10 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
 
                case DIGI_SETAFLOW:
                case DIGI_SETFLOW:
-                       if ((cmd) == (DIGI_SETFLOW)) 
-                       {
+                       if (cmd == DIGI_SETFLOW) {
                                startc = ch->startc;
                                stopc = ch->stopc;
-                       } 
-                       else 
-                       {
+                       } else {
                                startc = ch->startca;
                                stopc = ch->stopca;
                        }
@@ -3040,40 +2514,31 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
                        if (copy_from_user(&dflow, argp, sizeof(dflow)))
                                return -EFAULT;
 
-                       if (dflow.startc != startc || dflow.stopc != stopc) 
-                       { /* Begin  if setflow toggled */
-                               cli();
+                       if (dflow.startc != startc || dflow.stopc != stopc) { /* Begin  if setflow toggled */
+                               spin_lock_irqsave(&epca_lock, flags);
                                globalwinon(ch);
 
-                               if ((cmd) == (DIGI_SETFLOW)) 
-                               {
+                               if (cmd == DIGI_SETFLOW) {
                                        ch->fepstartc = ch->startc = dflow.startc;
                                        ch->fepstopc = ch->stopc = dflow.stopc;
                                        fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
-                               } 
-                               else 
-                               {
+                               } else {
                                        ch->fepstartca = ch->startca = dflow.startc;
                                        ch->fepstopca  = ch->stopca = dflow.stopc;
                                        fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
                                }
 
-                               if      (ch->statusflags & TXSTOPPED)
+                               if (ch->statusflags & TXSTOPPED)
                                        pc_start(tty);
 
                                memoff(ch);
-                               restore_flags(flags);
-
+                               spin_unlock_irqrestore(&epca_lock, flags);
                        } /* End if setflow toggled */
                        break;
-
                default:
                        return -ENOIOCTLCMD;
-
        } /* End switch cmd */
-
        return 0;
-
 } /* End pc_ioctl */
 
 /* --------------------- Begin pc_set_termios  ----------------------- */
@@ -3083,20 +2548,16 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios)
 
        struct channel *ch;
        unsigned long flags;
-
        /* ---------------------------------------------------------
                verifyChannel returns the channel from the tty struct
                if it is valid.  This serves as a sanity check.
        ------------------------------------------------------------- */
-
-       if ((ch = verifyChannel(tty)) != NULL) 
-       { /* Begin if channel valid */
-
-               save_flags(flags);
-               cli();
+       if ((ch = verifyChannel(tty)) != NULL)  { /* Begin if channel valid */
+               spin_lock_irqsave(&epca_lock, flags);
                globalwinon(ch);
                epcaparam(tty, ch);
                memoff(ch);
+               spin_unlock_irqrestore(&epca_lock, flags);
 
                if ((old_termios->c_cflag & CRTSCTS) &&
                         ((tty->termios->c_cflag & CRTSCTS) == 0))
@@ -3106,8 +2567,6 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios)
                         (tty->termios->c_cflag & CLOCAL))
                        wake_up_interruptible(&ch->open_wait);
 
-               restore_flags(flags);
-
        } /* End if channel valid */
 
 } /* End pc_set_termios */
@@ -3116,29 +2575,18 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios)
 
 static void do_softint(void *private_)
 { /* Begin do_softint */
-
        struct channel *ch = (struct channel *) private_;
-       
-
        /* Called in response to a modem change event */
-
-       if (ch && ch->magic == EPCA_MAGIC) 
-       { /* Begin EPCA_MAGIC */
-
+       if (ch && ch->magic == EPCA_MAGIC)  { /* Begin EPCA_MAGIC */
                struct tty_struct *tty = ch->tty;
 
-               if (tty && tty->driver_data) 
-               { 
-                       if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) 
-                       { /* Begin if clear_bit */
-
+               if (tty && tty->driver_data) {
+                       if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) { /* Begin if clear_bit */
                                tty_hangup(tty);        /* FIXME: module removal race here - AKPM */
                                wake_up_interruptible(&ch->open_wait);
                                ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
-
                        } /* End if clear_bit */
                }
-
        } /* End EPCA_MAGIC */
 } /* End do_softint */
 
@@ -3154,82 +2602,49 @@ static void pc_stop(struct tty_struct *tty)
 
        struct channel *ch;
        unsigned long flags;
-
        /* ---------------------------------------------------------
                verifyChannel returns the channel from the tty struct
                if it is valid.  This serves as a sanity check.
        ------------------------------------------------------------- */
-
-       if ((ch = verifyChannel(tty)) != NULL) 
-       { /* Begin if valid channel */
-
-               save_flags(flags); 
-               cli();
-
-               if ((ch->statusflags & TXSTOPPED) == 0) 
-               { /* Begin if transmit stop requested */
-
+       if ((ch = verifyChannel(tty)) != NULL)  { /* Begin if valid channel */
+               spin_lock_irqsave(&epca_lock, flags);
+               if ((ch->statusflags & TXSTOPPED) == 0)  { /* Begin if transmit stop requested */
                        globalwinon(ch);
-
                        /* STOP transmitting now !! */
-
                        fepcmd(ch, PAUSETX, 0, 0, 0, 0);
-
                        ch->statusflags |= TXSTOPPED;
                        memoff(ch);
-
                } /* End if transmit stop requested */
-
-               restore_flags(flags);
-
+               spin_unlock_irqrestore(&epca_lock, flags);
        } /* End if valid channel */
-
 } /* End pc_stop */
 
 /* --------------------- Begin pc_start  ----------------------- */
 
 static void pc_start(struct tty_struct *tty)
 { /* Begin pc_start */
-
        struct channel *ch;
-
        /* ---------------------------------------------------------
                verifyChannel returns the channel from the tty struct
                if it is valid.  This serves as a sanity check.
        ------------------------------------------------------------- */
-
-       if ((ch = verifyChannel(tty)) != NULL) 
-       { /* Begin if channel valid */
-
+       if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
                unsigned long flags;
-
-               save_flags(flags);
-               cli();
-
+               spin_lock_irqsave(&epca_lock, flags);
                /* Just in case output was resumed because of a change in Digi-flow */
-               if (ch->statusflags & TXSTOPPED) 
-               { /* Begin transmit resume requested */
-
-                       volatile struct board_chan *bc;
-
+               if (ch->statusflags & TXSTOPPED)  { /* Begin transmit resume requested */
+                       struct board_chan *bc;
                        globalwinon(ch);
                        bc = ch->brdchan;
                        if (ch->statusflags & LOWWAIT)
-                               bc->ilow = 1;
-
+                               writeb(1, &bc->ilow);
                        /* Okay, you can start transmitting again... */
-
                        fepcmd(ch, RESUMETX, 0, 0, 0, 0);
-
                        ch->statusflags &= ~TXSTOPPED;
                        memoff(ch);
-
                } /* End transmit resume requested */
-
-               restore_flags(flags);
-
+               spin_unlock_irqrestore(&epca_lock, flags);
        } /* End if channel valid */
-
 } /* End pc_start */
 
 /* ------------------------------------------------------------------
@@ -3244,86 +2659,55 @@ ______________________________________________________________________ */
 
 static void pc_throttle(struct tty_struct * tty)
 { /* Begin pc_throttle */
-
        struct channel *ch;
        unsigned long flags;
-
        /* ---------------------------------------------------------
                verifyChannel returns the channel from the tty struct
                if it is valid.  This serves as a sanity check.
        ------------------------------------------------------------- */
-
-       if ((ch = verifyChannel(tty)) != NULL) 
-       { /* Begin if channel valid */
-
-
-               save_flags(flags);
-               cli();
-
-               if ((ch->statusflags & RXSTOPPED) == 0)
-               {
+       if ((ch = verifyChannel(tty)) != NULL)  { /* Begin if channel valid */
+               spin_lock_irqsave(&epca_lock, flags);
+               if ((ch->statusflags & RXSTOPPED) == 0) {
                        globalwinon(ch);
                        fepcmd(ch, PAUSERX, 0, 0, 0, 0);
-
                        ch->statusflags |= RXSTOPPED;
                        memoff(ch);
                }
-               restore_flags(flags);
-
+               spin_unlock_irqrestore(&epca_lock, flags);
        } /* End if channel valid */
-
 } /* End pc_throttle */
 
 /* --------------------- Begin unthrottle  ----------------------- */
 
 static void pc_unthrottle(struct tty_struct *tty)
 { /* Begin pc_unthrottle */
-
        struct channel *ch;
        unsigned long flags;
-       volatile struct board_chan *bc;
-
-
        /* ---------------------------------------------------------
                verifyChannel returns the channel from the tty struct
                if it is valid.  This serves as a sanity check.
        ------------------------------------------------------------- */
-
-       if ((ch = verifyChannel(tty)) != NULL) 
-       { /* Begin if channel valid */
-
-
+       if ((ch = verifyChannel(tty)) != NULL)  { /* Begin if channel valid */
                /* Just in case output was resumed because of a change in Digi-flow */
-               save_flags(flags);
-               cli();
-
-               if (ch->statusflags & RXSTOPPED) 
-               {
-
+               spin_lock_irqsave(&epca_lock, flags);
+               if (ch->statusflags & RXSTOPPED) {
                        globalwinon(ch);
-                       bc = ch->brdchan;
                        fepcmd(ch, RESUMERX, 0, 0, 0, 0);
-
                        ch->statusflags &= ~RXSTOPPED;
                        memoff(ch);
                }
-               restore_flags(flags);
-
+               spin_unlock_irqrestore(&epca_lock, flags);
        } /* End if channel valid */
-
 } /* End pc_unthrottle */
 
 /* --------------------- Begin digi_send_break  ----------------------- */
 
 void digi_send_break(struct channel *ch, int msec)
 { /* Begin digi_send_break */
-
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&epca_lock, flags);
        globalwinon(ch);
-
        /* -------------------------------------------------------------------- 
           Maybe I should send an infinite break here, schedule() for
           msec amount of time, and then stop the break.  This way,
@@ -3331,36 +2715,28 @@ void digi_send_break(struct channel *ch, int msec)
           to be called (i.e. via an ioctl()) more than once in msec amount 
           of time.  Try this for now...
        ------------------------------------------------------------------------ */
-
        fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
        memoff(ch);
-
-       restore_flags(flags);
-
+       spin_unlock_irqrestore(&epca_lock, flags);
 } /* End digi_send_break */
 
 /* --------------------- Begin setup_empty_event  ----------------------- */
 
+/* Caller MUST hold the lock */
+
 static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
 { /* Begin setup_empty_event */
 
-       volatile struct board_chan *bc = ch->brdchan;
-       unsigned long int flags;
+       struct board_chan *bc = ch->brdchan;
 
-       save_flags(flags);
-       cli();
        globalwinon(ch);
        ch->statusflags |= EMPTYWAIT;
-       
        /* ------------------------------------------------------------------
                When set the iempty flag request a event to be generated when the 
                transmit buffer is empty (If there is no BREAK in progress).
        --------------------------------------------------------------------- */
-
-       bc->iempty = 1;
+       writeb(1, &bc->iempty);
        memoff(ch);
-       restore_flags(flags);
-
 } /* End setup_empty_event */
 
 /* --------------------- Begin get_termio ----------------------- */
@@ -3369,10 +2745,10 @@ static int get_termio(struct tty_struct * tty, struct termio __user * termio)
 { /* Begin get_termio */
        return kernel_termios_to_user_termio(termio, tty->termios);
 } /* End get_termio */
+
 /* ---------------------- Begin epca_setup  -------------------------- */
 void epca_setup(char *str, int *ints)
 { /* Begin epca_setup */
-
        struct board_info board;
        int               index, loop, last;
        char              *temp, *t2;
@@ -3394,49 +2770,41 @@ void epca_setup(char *str, int *ints)
        for (last = 0, index = 1; index <= ints[0]; index++)
                switch(index)
                { /* Begin parse switch */
-
                        case 1:
                                board.status = ints[index];
-                               
                                /* ---------------------------------------------------------
                                        We check for 2 (As opposed to 1; because 2 is a flag
                                        instructing the driver to ignore epcaconfig.)  For this
                                        reason we check for 2.
                                ------------------------------------------------------------ */ 
-                               if (board.status == 2)
-                               { /* Begin ignore epcaconfig as well as lilo cmd line */
+                               if (board.status == 2) { /* Begin ignore epcaconfig as well as lilo cmd line */
                                        nbdevs = 0;
                                        num_cards = 0;
                                        return;
                                } /* End ignore epcaconfig as well as lilo cmd line */
        
-                               if (board.status > 2)
-                               {
-                                       printk(KERN_ERR "<Error> - epca_setup: Invalid board status 0x%x\n", board.status);
+                               if (board.status > 2) {
+                                       printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n", board.status);
                                        invalid_lilo_config = 1;
                                        setup_error_code |= INVALID_BOARD_STATUS;
                                        return;
                                }
                                last = index;
                                break;
-
                        case 2:
                                board.type = ints[index];
-                               if (board.type >= PCIXEM) 
-                               {
-                                       printk(KERN_ERR "<Error> - epca_setup: Invalid board type 0x%x\n", board.type);
+                               if (board.type >= PCIXEM)  {
+                                       printk(KERN_ERR "epca_setup: Invalid board type 0x%x\n", board.type);
                                        invalid_lilo_config = 1;
                                        setup_error_code |= INVALID_BOARD_TYPE;
                                        return;
                                }
                                last = index;
                                break;
-
                        case 3:
                                board.altpin = ints[index];
-                               if (board.altpin > 1)
-                               {
-                                       printk(KERN_ERR "<Error> - epca_setup: Invalid board altpin 0x%x\n", board.altpin);
+                               if (board.altpin > 1) {
+                                       printk(KERN_ERR "epca_setup: Invalid board altpin 0x%x\n", board.altpin);
                                        invalid_lilo_config = 1;
                                        setup_error_code |= INVALID_ALTPIN;
                                        return;
@@ -3446,9 +2814,8 @@ void epca_setup(char *str, int *ints)
 
                        case 4:
                                board.numports = ints[index];
-                               if ((board.numports < 2) || (board.numports > 256))
-                               {
-                                       printk(KERN_ERR "<Error> - epca_setup: Invalid board numports 0x%x\n", board.numports);
+                               if (board.numports < 2 || board.numports > 256) {
+                                       printk(KERN_ERR "epca_setup: Invalid board numports 0x%x\n", board.numports);
                                        invalid_lilo_config = 1;
                                        setup_error_code |= INVALID_NUM_PORTS;
                                        return;
@@ -3458,10 +2825,9 @@ void epca_setup(char *str, int *ints)
                                break;
 
                        case 5:
-                               board.port = (unsigned char *)ints[index];
-                               if (ints[index] <= 0)
-                               {
-                                       printk(KERN_ERR "<Error> - epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
+                               board.port = ints[index];
+                               if (ints[index] <= 0) {
+                                       printk(KERN_ERR "epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
                                        invalid_lilo_config = 1;
                                        setup_error_code |= INVALID_PORT_BASE;
                                        return;
@@ -3470,10 +2836,9 @@ void epca_setup(char *str, int *ints)
                                break;
 
                        case 6:
-                               board.membase = (unsigned char *)ints[index];
-                               if (ints[index] <= 0)
-                               {
-                                       printk(KERN_ERR "<Error> - epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
+                               board.membase = ints[index];
+                               if (ints[index] <= 0) {
+                                       printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
                                        invalid_lilo_config = 1;
                                        setup_error_code |= INVALID_MEM_BASE;
                                        return;
@@ -3487,21 +2852,16 @@ void epca_setup(char *str, int *ints)
 
                } /* End parse switch */
 
-       while (str && *str) 
-       { /* Begin while there is a string arg */
-
+       while (str && *str)  { /* Begin while there is a string arg */
                /* find the next comma or terminator */
                temp = str;
-
                /* While string is not null, and a comma hasn't been found */
                while (*temp && (*temp != ','))
                        temp++;
-
                if (!*temp)
                        temp = NULL;
                else
                        *temp++ = 0;
-
                /* Set index to the number of args + 1 */
                index = last + 1;
 
@@ -3511,12 +2871,10 @@ void epca_setup(char *str, int *ints)
                                len = strlen(str);
                                if (strncmp("Disable", str, len) == 0) 
                                        board.status = 0;
-                               else
-                               if (strncmp("Enable", str, len) == 0)
+                               else if (strncmp("Enable", str, len) == 0)
                                        board.status = 1;
-                               else
-                               {
-                                       printk(KERN_ERR "<Error> - epca_setup: Invalid status %s\n", str);
+                               else {
+                                       printk(KERN_ERR "epca_setup: Invalid status %s\n", str);
                                        invalid_lilo_config = 1;
                                        setup_error_code |= INVALID_BOARD_STATUS;
                                        return;
@@ -3525,22 +2883,17 @@ void epca_setup(char *str, int *ints)
                                break;
 
                        case 2:
-
                                for(loop = 0; loop < EPCA_NUM_TYPES; loop++)
                                        if (strcmp(board_desc[loop], str) == 0)
                                                break;
-
-
                                /* ---------------------------------------------------------------
                                        If the index incremented above refers to a legitamate board 
                                        type set it here. 
                                ------------------------------------------------------------------*/
-
                                if (index < EPCA_NUM_TYPES) 
                                        board.type = loop;
-                               else
-                               {
-                                       printk(KERN_ERR "<Error> - epca_setup: Invalid board type: %s\n", str);
+                               else {
+                                       printk(KERN_ERR "epca_setup: Invalid board type: %s\n", str);
                                        invalid_lilo_config = 1;
                                        setup_error_code |= INVALID_BOARD_TYPE;
                                        return;
@@ -3552,12 +2905,10 @@ void epca_setup(char *str, int *ints)
                                len = strlen(str);
                                if (strncmp("Disable", str, len) == 0) 
                                        board.altpin = 0;
-                               else
-                               if (strncmp("Enable", str, len) == 0)
+                               else if (strncmp("Enable", str, len) == 0)
                                        board.altpin = 1;
-                               else
-                               {
-                                       printk(KERN_ERR "<Error> - epca_setup: Invalid altpin %s\n", str);
+                               else {
+                                       printk(KERN_ERR "epca_setup: Invalid altpin %s\n", str);
                                        invalid_lilo_config = 1;
                                        setup_error_code |= INVALID_ALTPIN;
                                        return;
@@ -3570,9 +2921,8 @@ void epca_setup(char *str, int *ints)
                                while (isdigit(*t2))
                                        t2++;
 
-                               if (*t2)
-                               {
-                                       printk(KERN_ERR "<Error> - epca_setup: Invalid port count %s\n", str);
+                               if (*t2) {
+                                       printk(KERN_ERR "epca_setup: Invalid port count %s\n", str);
                                        invalid_lilo_config = 1;
                                        setup_error_code |= INVALID_NUM_PORTS;
                                        return;
@@ -3601,15 +2951,14 @@ void epca_setup(char *str, int *ints)
                                while (isxdigit(*t2))
                                        t2++;
 
-                               if (*t2)
-                               {
-                                       printk(KERN_ERR "<Error> - epca_setup: Invalid i/o address %s\n", str);
+                               if (*t2) {
+                                       printk(KERN_ERR "epca_setup: Invalid i/o address %s\n", str);
                                        invalid_lilo_config = 1;
                                        setup_error_code |= INVALID_PORT_BASE;
                                        return;
                                }
 
-                               board.port = (unsigned char *)simple_strtoul(str, NULL, 16);
+                               board.port = simple_strtoul(str, NULL, 16);
                                last = index;
                                break;
 
@@ -3618,52 +2967,38 @@ void epca_setup(char *str, int *ints)
                                while (isxdigit(*t2))
                                        t2++;
 
-                               if (*t2)
-                               {
-                                       printk(KERN_ERR "<Error> - epca_setup: Invalid memory base %s\n",str);
+                               if (*t2) {
+                                       printk(KERN_ERR "epca_setup: Invalid memory base %s\n",str);
                                        invalid_lilo_config = 1;
                                        setup_error_code |= INVALID_MEM_BASE;
                                        return;
                                }
-
-                               board.membase = (unsigned char *)simple_strtoul(str, NULL, 16);
+                               board.membase = simple_strtoul(str, NULL, 16);
                                last = index;
                                break;
-
                        default:
-                               printk(KERN_ERR "PC/Xx: Too many string parms\n");
+                               printk(KERN_ERR "epca: Too many string parms\n");
                                return;
                }
                str = temp;
-
        } /* End while there is a string arg */
 
-
-       if (last < 6)  
-       {
-               printk(KERN_ERR "PC/Xx: Insufficient parms specified\n");
+       if (last < 6) {
+               printk(KERN_ERR "epca: Insufficient parms specified\n");
                return;
        }
  
        /* I should REALLY validate the stuff here */
-
        /* Copies our local copy of board into boards */
        memcpy((void *)&boards[num_cards],(void *)&board, sizeof(board));
-
-
        /* Does this get called once per lilo arg are what ? */
-
        printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n", 
                num_cards, board_desc[board.type], 
                board.numports, (int)board.port, (unsigned int) board.membase);
-
        num_cards++;
-
 } /* End epca_setup */
 
 
-
-#ifdef ENABLE_PCI
 /* ------------------------ Begin init_PCI  --------------------------- */
 
 enum epic_board_types {
@@ -3685,7 +3020,6 @@ static struct {
        { PCIXRJ, 2, },
 };
 
-
 static int __devinit epca_init_one (struct pci_dev *pdev,
                                 const struct pci_device_id *ent)
 {
@@ -3711,10 +3045,8 @@ static int __devinit epca_init_one (struct pci_dev *pdev,
        boards[board_idx].status = ENABLED;
        boards[board_idx].type = epca_info_tbl[info_idx].board_type;
        boards[board_idx].numports = 0x0;
-       boards[board_idx].port =
-               (unsigned char *)((char *) addr + PCI_IO_OFFSET);
-       boards[board_idx].membase =
-               (unsigned char *)((char *) addr);
+       boards[board_idx].port = addr + PCI_IO_OFFSET;
+       boards[board_idx].membase = addr;
 
        if (!request_mem_region (addr + PCI_IO_OFFSET, 0x200000, "epca")) {
                printk (KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
@@ -3775,15 +3107,13 @@ static struct pci_device_id epca_pci_tbl[] = {
 MODULE_DEVICE_TABLE(pci, epca_pci_tbl);
 
 int __init init_PCI (void)
-{ /* Begin init_PCI */
+{      /* Begin init_PCI */
        memset (&epca_driver, 0, sizeof (epca_driver));
        epca_driver.name = "epca";
        epca_driver.id_table = epca_pci_tbl;
        epca_driver.probe = epca_init_one;
 
        return pci_register_driver(&epca_driver);
-} /* End init_PCI */
-
-#endif /* ENABLE_PCI */
+}
 
 MODULE_LICENSE("GPL");
index 52205ef7131483ae59a17a0220c3803fe0939741..20eeb5a70e1ad841c9b73490df25d82d6c7f8786 100644 (file)
@@ -85,73 +85,73 @@ static char *board_desc[] =
 struct channel 
 {
        long   magic;
-       unchar boardnum;
-       unchar channelnum;
-       unchar omodem;         /* FEP output modem status     */
-       unchar imodem;         /* FEP input modem status      */
-       unchar modemfake;      /* Modem values to be forced   */
-       unchar modem;          /* Force values                */
-       unchar hflow;
-       unchar dsr;
-       unchar dcd;
-       unchar m_rts ;          /* The bits used in whatever FEP */
-       unchar m_dcd ;          /* is indiginous to this board to */
-       unchar m_dsr ;          /* represent each of the physical */
-       unchar m_cts ;          /* handshake lines */
-       unchar m_ri ;
-       unchar m_dtr ;
-       unchar stopc;
-       unchar startc;
-       unchar stopca;
-       unchar startca;
-       unchar fepstopc;
-       unchar fepstartc;
-       unchar fepstopca;
-       unchar fepstartca;
-       unchar txwin;
-       unchar rxwin;
-       ushort fepiflag;
-       ushort fepcflag;
-       ushort fepoflag;
-       ushort txbufhead;
-       ushort txbufsize;
-       ushort rxbufhead;
-       ushort rxbufsize;
+       unsigned char boardnum;
+       unsigned char channelnum;
+       unsigned char omodem;         /* FEP output modem status     */
+       unsigned char imodem;         /* FEP input modem status      */
+       unsigned char modemfake;      /* Modem values to be forced   */
+       unsigned char modem;          /* Force values                */
+       unsigned char hflow;
+       unsigned char dsr;
+       unsigned char dcd;
+       unsigned char m_rts ;           /* The bits used in whatever FEP */
+       unsigned char m_dcd ;           /* is indiginous to this board to */
+       unsigned char m_dsr ;           /* represent each of the physical */
+       unsigned char m_cts ;           /* handshake lines */
+       unsigned char m_ri ;
+       unsigned char m_dtr ;
+       unsigned char stopc;
+       unsigned char startc;
+       unsigned char stopca;
+       unsigned char startca;
+       unsigned char fepstopc;
+       unsigned char fepstartc;
+       unsigned char fepstopca;
+       unsigned char fepstartca;
+       unsigned char txwin;
+       unsigned char rxwin;
+       unsigned short fepiflag;
+       unsigned short fepcflag;
+       unsigned short fepoflag;
+       unsigned short txbufhead;
+       unsigned short txbufsize;
+       unsigned short rxbufhead;
+       unsigned short rxbufsize;
        int    close_delay;
        int    count;
        int    blocked_open;
-       ulong  event;
+       unsigned long  event;
        int    asyncflags;
        uint   dev;
-       ulong  statusflags;
-       ulong  c_iflag;
-       ulong  c_cflag;
-       ulong  c_lflag;
-       ulong  c_oflag;
-       unchar *txptr;
-       unchar *rxptr;
-       unchar *tmp_buf;
+       unsigned long  statusflags;
+       unsigned long  c_iflag;
+       unsigned long  c_cflag;
+       unsigned long  c_lflag;
+       unsigned long  c_oflag;
+       unsigned char *txptr;
+       unsigned char *rxptr;
+       unsigned char *tmp_buf;
        struct board_info           *board;
-       volatile struct board_chan  *brdchan;
+       struct board_chan           *brdchan;
        struct digi_struct          digiext;
        struct tty_struct           *tty;
        wait_queue_head_t           open_wait;
        wait_queue_head_t           close_wait;
-       struct work_struct            tqueue;
-       volatile struct global_data *mailbox;
+       struct work_struct          tqueue;
+       struct global_data          *mailbox;
 };
 
 struct board_info      
 {
-       unchar status;
-       unchar type;
-       unchar altpin;
-       ushort numports;
-       unchar *port;
-       unchar *membase;
-       unchar __iomem *re_map_port;
-       unchar *re_map_membase;
-       ulong  memory_seg;
+       unsigned char status;
+       unsigned char type;
+       unsigned char altpin;
+       unsigned short numports;
+       unsigned long port;
+       unsigned long membase;
+       unsigned char __iomem *re_map_port;
+       unsigned char *re_map_membase;
+       unsigned long  memory_seg;
        void ( * memwinon )     (struct board_info *, unsigned int) ;
        void ( * memwinoff )    (struct board_info *, unsigned int) ;
        void ( * globalwinon )  (struct channel *) ;
@@ -160,6 +160,6 @@ struct board_info
        void ( * memoff )       (struct channel *) ;
        void ( * assertgwinon ) (struct channel *) ;
        void ( * assertmemoff ) (struct channel *) ;
-       unchar poller_inhibited ;
+       unsigned char poller_inhibited ;
 };
 
index 762fa430fb5be3b6a7615eed705e741509475ba7..a695f25e4497b647cb20c776f1f2f0a0e6b4d545 100644 (file)
@@ -44,7 +44,7 @@
 /*
  * The High Precision Event Timer driver.
  * This driver is closely modelled after the rtc.c driver.
- * http://www.intel.com/labs/platcomp/hpet/hpetspec.htm
+ * http://www.intel.com/hardwaredesign/hpetspec.htm
  */
 #define        HPET_USER_FREQ  (64)
 #define        HPET_DRIFT      (500)
@@ -712,7 +712,7 @@ static void hpet_register_interpolator(struct hpets *hpetp)
        ti->shift = 10;
        ti->addr = &hpetp->hp_hpet->hpet_mc;
        ti->frequency = hpet_time_div(hpets->hp_period);
-       ti->drift = ti->frequency * HPET_DRIFT / 1000000;
+       ti->drift = HPET_DRIFT;
        ti->mask = -1;
 
        hpetp->hp_interpolator = ti;
index 60bb9152b832fdc3f5021ae0af310dd71b1f275b..78d681dc35a8f362d11466db471aaf2ae45cc312 100644 (file)
@@ -39,7 +39,7 @@ char hvc_driver_name[] = "hvc_console";
 
 static struct vio_device_id hvc_driver_table[] __devinitdata = {
        {"serial", "hvterm1"},
-       { NULL, }
+       { "", "" }
 };
 MODULE_DEVICE_TABLE(vio, hvc_driver_table);
 
index 3236d2404905003ad92ce5b2ef82cc96f28a3906..f47f009f9259c1597e60b1f7740c1f9bfeb6b203 100644 (file)
@@ -527,7 +527,7 @@ static int khvcsd(void *unused)
 
 static struct vio_device_id hvcs_driver_table[] __devinitdata= {
        {"serial-server", "hvterm2"},
-       { NULL, }
+       { "", "" }
 };
 MODULE_DEVICE_TABLE(vio, hvcs_driver_table);
 
index 5ce9c62690334cdf50ada526ec2c2a123b087849..33862670e285542fe7f4733fc299aef0346db31c 100644 (file)
@@ -31,8 +31,6 @@
 #include <linux/ipmi_msgdefs.h>                /* for completion codes */
 #include "ipmi_si_sm.h"
 
-#define IPMI_BT_VERSION "v33"
-
 static int bt_debug = 0x00;    /* Production value 0, see following flags */
 
 #define        BT_DEBUG_ENABLE 1
@@ -163,7 +161,8 @@ static int bt_start_transaction(struct si_sm_data *bt,
 {
        unsigned int i;
 
-       if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH)) return -1;
+       if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH))
+              return -1;
 
        if ((bt->state != BT_STATE_IDLE) && (bt->state != BT_STATE_HOSED))
                return -2;
@@ -171,7 +170,8 @@ static int bt_start_transaction(struct si_sm_data *bt,
        if (bt_debug & BT_DEBUG_MSG) {
                printk(KERN_WARNING "+++++++++++++++++++++++++++++++++++++\n");
                printk(KERN_WARNING "BT: write seq=0x%02X:", bt->seq);
-               for (i = 0; i < size; i ++) printk (" %02x", data[i]);
+               for (i = 0; i < size; i ++)
+                      printk (" %02x", data[i]);
                printk("\n");
        }
        bt->write_data[0] = size + 1;   /* all data plus seq byte */
@@ -210,15 +210,18 @@ static int bt_get_result(struct si_sm_data *bt,
        } else {
                data[0] = bt->read_data[1];
                data[1] = bt->read_data[3];
-               if (length < msg_len) bt->truncated = 1;
+               if (length < msg_len)
+                      bt->truncated = 1;
                if (bt->truncated) {    /* can be set in read_all_bytes() */
                        data[2] = IPMI_ERR_MSG_TRUNCATED;
                        msg_len = 3;
-               } else memcpy(data + 2, bt->read_data + 4, msg_len - 2);
+               } else
+                      memcpy(data + 2, bt->read_data + 4, msg_len - 2);
 
                if (bt_debug & BT_DEBUG_MSG) {
                        printk (KERN_WARNING "BT: res (raw)");
-                       for (i = 0; i < msg_len; i++) printk(" %02x", data[i]);
+                       for (i = 0; i < msg_len; i++)
+                              printk(" %02x", data[i]);
                        printk ("\n");
                }
        }
@@ -231,8 +234,10 @@ static int bt_get_result(struct si_sm_data *bt,
 
 static void reset_flags(struct si_sm_data *bt)
 {
-       if (BT_STATUS & BT_H_BUSY) BT_CONTROL(BT_H_BUSY);
-       if (BT_STATUS & BT_B_BUSY) BT_CONTROL(BT_B_BUSY);
+       if (BT_STATUS & BT_H_BUSY)
+              BT_CONTROL(BT_H_BUSY);
+       if (BT_STATUS & BT_B_BUSY)
+              BT_CONTROL(BT_B_BUSY);
        BT_CONTROL(BT_CLR_WR_PTR);
        BT_CONTROL(BT_SMS_ATN);
 #ifdef DEVELOPMENT_ONLY_NOT_FOR_PRODUCTION
@@ -241,7 +246,8 @@ static void reset_flags(struct si_sm_data *bt)
                BT_CONTROL(BT_H_BUSY);
                BT_CONTROL(BT_B2H_ATN);
                BT_CONTROL(BT_CLR_RD_PTR);
-               for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++) BMC2HOST;
+               for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++)
+                      BMC2HOST;
                BT_CONTROL(BT_H_BUSY);
        }
 #endif
@@ -258,7 +264,8 @@ static inline void write_all_bytes(struct si_sm_data *bt)
                        printk (" %02x", bt->write_data[i]);
                printk ("\n");
        }
-       for (i = 0; i < bt->write_count; i++) HOST2BMC(bt->write_data[i]);
+       for (i = 0; i < bt->write_count; i++)
+              HOST2BMC(bt->write_data[i]);
 }
 
 static inline int read_all_bytes(struct si_sm_data *bt)
@@ -278,7 +285,8 @@ static inline int read_all_bytes(struct si_sm_data *bt)
                bt->truncated = 1;
                return 1;       /* let next XACTION START clean it up */
        }
-       for (i = 1; i <= bt->read_count; i++) bt->read_data[i] = BMC2HOST;
+       for (i = 1; i <= bt->read_count; i++)
+              bt->read_data[i] = BMC2HOST;
        bt->read_count++;       /* account for the length byte */
 
        if (bt_debug & BT_DEBUG_MSG) {
@@ -295,7 +303,8 @@ static inline int read_all_bytes(struct si_sm_data *bt)
                ((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8)))
                        return 1;
 
-       if (bt_debug & BT_DEBUG_MSG) printk(KERN_WARNING "BT: bad packet: "
+       if (bt_debug & BT_DEBUG_MSG)
+              printk(KERN_WARNING "BT: bad packet: "
                "want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n",
                bt->write_data[1], bt->write_data[2], bt->write_data[3],
                bt->read_data[1],  bt->read_data[2],  bt->read_data[3]);
@@ -359,7 +368,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
                        time);
        bt->last_state = bt->state;
 
-       if (bt->state == BT_STATE_HOSED) return SI_SM_HOSED;
+       if (bt->state == BT_STATE_HOSED)
+              return SI_SM_HOSED;
 
        if (bt->state != BT_STATE_IDLE) {       /* do timeout test */
 
@@ -371,7 +381,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
        /* FIXME: bt_event is sometimes called with time > BT_NORMAL_TIMEOUT
               (noticed in ipmi_smic_sm.c January 2004) */
 
-               if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT)) time = 100;
+               if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT))
+                      time = 100;
                bt->timeout -= time;
                if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) {
                        error_recovery(bt, "timed out");
@@ -393,12 +404,14 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
                        BT_CONTROL(BT_H_BUSY);
                        break;
                }
-               if (status & BT_B2H_ATN) break;
+               if (status & BT_B2H_ATN)
+                      break;
                bt->state = BT_STATE_WRITE_BYTES;
                return SI_SM_CALL_WITHOUT_DELAY;        /* for logging */
 
        case BT_STATE_WRITE_BYTES:
-               if (status & (BT_B_BUSY | BT_H2B_ATN)) break;
+               if (status & (BT_B_BUSY | BT_H2B_ATN))
+                      break;
                BT_CONTROL(BT_CLR_WR_PTR);
                write_all_bytes(bt);
                BT_CONTROL(BT_H2B_ATN); /* clears too fast to catch? */
@@ -406,7 +419,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
                return SI_SM_CALL_WITHOUT_DELAY; /* it MIGHT sail through */
 
        case BT_STATE_WRITE_CONSUME: /* BMCs usually blow right thru here */
-               if (status & (BT_H2B_ATN | BT_B_BUSY)) break;
+               if (status & (BT_H2B_ATN | BT_B_BUSY))
+                      break;
                bt->state = BT_STATE_B2H_WAIT;
                /* fall through with status */
 
@@ -415,15 +429,18 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
           generation of B2H_ATN so ALWAYS return CALL_WITH_DELAY. */
 
        case BT_STATE_B2H_WAIT:
-               if (!(status & BT_B2H_ATN)) break;
+               if (!(status & BT_B2H_ATN))
+                      break;
 
                /* Assume ordered, uncached writes: no need to wait */
-               if (!(status & BT_H_BUSY)) BT_CONTROL(BT_H_BUSY); /* set */
+               if (!(status & BT_H_BUSY))
+                      BT_CONTROL(BT_H_BUSY); /* set */
                BT_CONTROL(BT_B2H_ATN);         /* clear it, ACK to the BMC */
                BT_CONTROL(BT_CLR_RD_PTR);      /* reset the queue */
                i = read_all_bytes(bt);
                BT_CONTROL(BT_H_BUSY);          /* clear */
-               if (!i) break;                  /* Try this state again */
+               if (!i)                         /* Try this state again */
+                      break;
                bt->state = BT_STATE_READ_END;
                return SI_SM_CALL_WITHOUT_DELAY;        /* for logging */
 
@@ -436,7 +453,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
 
 #ifdef MAKE_THIS_TRUE_IF_NECESSARY
 
-               if (status & BT_H_BUSY) break;
+               if (status & BT_H_BUSY)
+                      break;
 #endif
                bt->seq++;
                bt->state = BT_STATE_IDLE;
@@ -459,7 +477,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
                break;
 
        case BT_STATE_RESET3:
-               if (bt->timeout > 0) return SI_SM_CALL_WITH_DELAY;
+               if (bt->timeout > 0)
+                      return SI_SM_CALL_WITH_DELAY;
                bt->state = BT_STATE_RESTART;   /* printk in debug modes */
                break;
 
@@ -485,7 +504,8 @@ static int bt_detect(struct si_sm_data *bt)
           but that's what you get from reading a bogus address, so we
           test that first.  The calling routine uses negative logic. */
 
-       if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) return 1;
+       if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF))
+              return 1;
        reset_flags(bt);
        return 0;
 }
@@ -501,7 +521,6 @@ static int bt_size(void)
 
 struct si_sm_handlers bt_smi_handlers =
 {
-       .version           = IPMI_BT_VERSION,
        .init_data         = bt_init_data,
        .start_transaction = bt_start_transaction,
        .get_result        = bt_get_result,
index e0a53570fea1a755485a90f1aa59c8778d753b26..883ac4352be49e4e1606e361d763a8503199a058 100644 (file)
@@ -47,8 +47,6 @@
 #include <linux/device.h>
 #include <linux/compat.h>
 
-#define IPMI_DEVINTF_VERSION "v33"
-
 struct ipmi_file_private
 {
        ipmi_user_t          user;
@@ -411,6 +409,7 @@ static int ipmi_ioctl(struct inode  *inode,
                break;
        }
 
+       /* The next four are legacy, not per-channel. */
        case IPMICTL_SET_MY_ADDRESS_CMD:
        {
                unsigned int val;
@@ -420,22 +419,25 @@ static int ipmi_ioctl(struct inode  *inode,
                        break;
                }
 
-               ipmi_set_my_address(priv->user, val);
-               rv = 0;
+               rv = ipmi_set_my_address(priv->user, 0, val);
                break;
        }
 
        case IPMICTL_GET_MY_ADDRESS_CMD:
        {
-               unsigned int val;
+               unsigned int  val;
+               unsigned char rval;
+
+               rv = ipmi_get_my_address(priv->user, 0, &rval);
+               if (rv)
+                       break;
 
-               val = ipmi_get_my_address(priv->user);
+               val = rval;
 
                if (copy_to_user(arg, &val, sizeof(val))) {
                        rv = -EFAULT;
                        break;
                }
-               rv = 0;
                break;
        }
 
@@ -448,24 +450,94 @@ static int ipmi_ioctl(struct inode  *inode,
                        break;
                }
 
-               ipmi_set_my_LUN(priv->user, val);
-               rv = 0;
+               rv = ipmi_set_my_LUN(priv->user, 0, val);
                break;
        }
 
        case IPMICTL_GET_MY_LUN_CMD:
        {
-               unsigned int val;
+               unsigned int  val;
+               unsigned char rval;
 
-               val = ipmi_get_my_LUN(priv->user);
+               rv = ipmi_get_my_LUN(priv->user, 0, &rval);
+               if (rv)
+                       break;
+
+               val = rval;
+
+               if (copy_to_user(arg, &val, sizeof(val))) {
+                       rv = -EFAULT;
+                       break;
+               }
+               break;
+       }
+
+       case IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD:
+       {
+               struct ipmi_channel_lun_address_set val;
+
+               if (copy_from_user(&val, arg, sizeof(val))) {
+                       rv = -EFAULT;
+                       break;
+               }
+
+               return ipmi_set_my_address(priv->user, val.channel, val.value);
+               break;
+       }
+
+       case IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD:
+       {
+               struct ipmi_channel_lun_address_set val;
+
+               if (copy_from_user(&val, arg, sizeof(val))) {
+                       rv = -EFAULT;
+                       break;
+               }
+
+               rv = ipmi_get_my_address(priv->user, val.channel, &val.value);
+               if (rv)
+                       break;
+
+               if (copy_to_user(arg, &val, sizeof(val))) {
+                       rv = -EFAULT;
+                       break;
+               }
+               break;
+       }
+
+       case IPMICTL_SET_MY_CHANNEL_LUN_CMD:
+       {
+               struct ipmi_channel_lun_address_set val;
+
+               if (copy_from_user(&val, arg, sizeof(val))) {
+                       rv = -EFAULT;
+                       break;
+               }
+
+               rv = ipmi_set_my_LUN(priv->user, val.channel, val.value);
+               break;
+       }
+
+       case IPMICTL_GET_MY_CHANNEL_LUN_CMD:
+       {
+               struct ipmi_channel_lun_address_set val;
+
+               if (copy_from_user(&val, arg, sizeof(val))) {
+                       rv = -EFAULT;
+                       break;
+               }
+
+               rv = ipmi_get_my_LUN(priv->user, val.channel, &val.value);
+               if (rv)
+                       break;
 
                if (copy_to_user(arg, &val, sizeof(val))) {
                        rv = -EFAULT;
                        break;
                }
-               rv = 0;
                break;
        }
+
        case IPMICTL_SET_TIMING_PARMS_CMD:
        {
                struct ipmi_timing_parms parms;
@@ -748,8 +820,7 @@ static __init int init_ipmi_devintf(void)
        if (ipmi_major < 0)
                return -EINVAL;
 
-       printk(KERN_INFO "ipmi device interface version "
-              IPMI_DEVINTF_VERSION "\n");
+       printk(KERN_INFO "ipmi device interface\n");
 
        ipmi_class = class_create(THIS_MODULE, "ipmi");
        if (IS_ERR(ipmi_class)) {
@@ -792,3 +863,5 @@ static __exit void cleanup_ipmi(void)
 module_exit(cleanup_ipmi);
 
 MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("Linux device interface for the IPMI message handler.");
index 48cce24329bea516b62a0f3578ea162a48b73556..d21853a594a3b74c2354988d523f8cdd0bbcf71d 100644 (file)
@@ -42,8 +42,6 @@
 #include <linux/ipmi_msgdefs.h>                /* for completion codes */
 #include "ipmi_si_sm.h"
 
-#define IPMI_KCS_VERSION "v33"
-
 /* Set this if you want a printout of why the state machine was hosed
    when it gets hosed. */
 #define DEBUG_HOSED_REASON
@@ -489,7 +487,6 @@ static void kcs_cleanup(struct si_sm_data *kcs)
 
 struct si_sm_handlers kcs_smi_handlers =
 {
-       .version           = IPMI_KCS_VERSION,
        .init_data         = init_kcs_data,
        .start_transaction = start_kcs_transaction,
        .get_result        = get_kcs_result,
index e16c13fe698dff7c71ad27508d64904f84be80be..463351d4f9423c388d424231326b8bbe23a60cd0 100644 (file)
@@ -47,7 +47,8 @@
 #include <linux/proc_fs.h>
 
 #define PFX "IPMI message handler: "
-#define IPMI_MSGHANDLER_VERSION "v33"
+
+#define IPMI_DRIVER_VERSION "36.0"
 
 static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
 static int ipmi_init_msghandler(void);
@@ -116,7 +117,7 @@ struct seq_table
        do {                                                            \
                seq = ((msgid >> 26) & 0x3f);                           \
                seqid = (msgid & 0x3fffff);                             \
-        } while(0)
+        } while (0)
 
 #define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
 
@@ -124,6 +125,14 @@ struct ipmi_channel
 {
        unsigned char medium;
        unsigned char protocol;
+
+       /* My slave address.  This is initialized to IPMI_BMC_SLAVE_ADDR,
+          but may be changed by the user. */
+       unsigned char address;
+
+       /* My LUN.  This should generally stay the SMS LUN, but just in
+          case... */
+       unsigned char lun;
 };
 
 #ifdef CONFIG_PROC_FS
@@ -135,7 +144,7 @@ struct ipmi_proc_entry
 #endif
 
 #define IPMI_IPMB_NUM_SEQ      64
-#define IPMI_MAX_CHANNELS       8
+#define IPMI_MAX_CHANNELS       16
 struct ipmi_smi
 {
        /* What interface number are we? */
@@ -193,20 +202,6 @@ struct ipmi_smi
        struct list_head waiting_events;
        unsigned int     waiting_events_count; /* How many events in queue? */
 
-       /* This will be non-null if someone registers to receive all
-          IPMI commands (this is for interface emulation).  There
-          may not be any things in the cmd_rcvrs list above when
-          this is registered. */
-       ipmi_user_t all_cmd_rcvr;
-
-       /* My slave address.  This is initialized to IPMI_BMC_SLAVE_ADDR,
-          but may be changed by the user. */
-       unsigned char my_address;
-
-       /* My LUN.  This should generally stay the SMS LUN, but just in
-          case... */
-       unsigned char my_lun;
-
        /* The event receiver for my BMC, only really used at panic
           shutdown as a place to store this. */
        unsigned char event_receiver;
@@ -218,7 +213,7 @@ struct ipmi_smi
           interface comes in with a NULL user, call this routine with
           it.  Note that the message will still be freed by the
           caller.  This only works on the system interface. */
-       void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_smi_msg *msg);
+       void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
 
        /* When we are scanning the channels for an SMI, this will
           tell which channel we are scanning. */
@@ -325,7 +320,7 @@ int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
        down_read(&interfaces_sem);
        down_write(&smi_watchers_sem);
        list_add(&(watcher->link), &smi_watchers);
-       for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+       for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
                if (ipmi_interfaces[i] != NULL) {
                        watcher->new_smi(i);
                }
@@ -458,7 +453,27 @@ unsigned int ipmi_addr_length(int addr_type)
 
 static void deliver_response(struct ipmi_recv_msg *msg)
 {
-       msg->user->handler->ipmi_recv_hndl(msg, msg->user->handler_data);
+       if (! msg->user) {
+               ipmi_smi_t    intf = msg->user_msg_data;
+               unsigned long flags;
+
+               /* Special handling for NULL users. */
+               if (intf->null_user_handler) {
+                       intf->null_user_handler(intf, msg);
+                       spin_lock_irqsave(&intf->counter_lock, flags);
+                       intf->handled_local_responses++;
+                       spin_unlock_irqrestore(&intf->counter_lock, flags);
+               } else {
+                       /* No handler, so give up. */
+                       spin_lock_irqsave(&intf->counter_lock, flags);
+                       intf->unhandled_local_responses++;
+                       spin_unlock_irqrestore(&intf->counter_lock, flags);
+               }
+               ipmi_free_recv_msg(msg);
+       } else {
+               msg->user->handler->ipmi_recv_hndl(msg,
+                                                  msg->user->handler_data);
+       }
 }
 
 /* Find the next sequence number not being used and add the given
@@ -475,9 +490,9 @@ static int intf_next_seq(ipmi_smi_t           intf,
        int          rv = 0;
        unsigned int i;
 
-       for (i=intf->curr_seq;
+       for (i = intf->curr_seq;
             (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
-            i=(i+1)%IPMI_IPMB_NUM_SEQ)
+            i = (i+1)%IPMI_IPMB_NUM_SEQ)
        {
                if (! intf->seq_table[i].inuse)
                        break;
@@ -712,7 +727,7 @@ static int ipmi_destroy_user_nolock(ipmi_user_t user)
 
        /* Remove the user from the interfaces sequence table. */
        spin_lock_irqsave(&(user->intf->seq_lock), flags);
-       for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) {
+       for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
                if (user->intf->seq_table[i].inuse
                    && (user->intf->seq_table[i].recv_msg->user == user))
                {
@@ -766,26 +781,44 @@ void ipmi_get_version(ipmi_user_t   user,
        *minor = user->intf->version_minor;
 }
 
-void ipmi_set_my_address(ipmi_user_t   user,
-                        unsigned char address)
+int ipmi_set_my_address(ipmi_user_t   user,
+                       unsigned int  channel,
+                       unsigned char address)
 {
-       user->intf->my_address = address;
+       if (channel >= IPMI_MAX_CHANNELS)
+               return -EINVAL;
+       user->intf->channels[channel].address = address;
+       return 0;
 }
 
-unsigned char ipmi_get_my_address(ipmi_user_t user)
+int ipmi_get_my_address(ipmi_user_t   user,
+                       unsigned int  channel,
+                       unsigned char *address)
 {
-       return user->intf->my_address;
+       if (channel >= IPMI_MAX_CHANNELS)
+               return -EINVAL;
+       *address = user->intf->channels[channel].address;
+       return 0;
 }
 
-void ipmi_set_my_LUN(ipmi_user_t   user,
-                    unsigned char LUN)
+int ipmi_set_my_LUN(ipmi_user_t   user,
+                   unsigned int  channel,
+                   unsigned char LUN)
 {
-       user->intf->my_lun = LUN & 0x3;
+       if (channel >= IPMI_MAX_CHANNELS)
+               return -EINVAL;
+       user->intf->channels[channel].lun = LUN & 0x3;
+       return 0;
 }
 
-unsigned char ipmi_get_my_LUN(ipmi_user_t user)
+int ipmi_get_my_LUN(ipmi_user_t   user,
+                   unsigned int  channel,
+                   unsigned char *address)
 {
-       return user->intf->my_lun;
+       if (channel >= IPMI_MAX_CHANNELS)
+               return -EINVAL;
+       *address = user->intf->channels[channel].lun;
+       return 0;
 }
 
 int ipmi_set_gets_events(ipmi_user_t user, int val)
@@ -828,11 +861,6 @@ int ipmi_register_for_cmd(ipmi_user_t   user,
 
        read_lock(&(user->intf->users_lock));
        write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);
-       if (user->intf->all_cmd_rcvr != NULL) {
-               rv = -EBUSY;
-               goto out_unlock;
-       }
-
        /* Make sure the command/netfn is not already registered. */
        list_for_each_entry(cmp, &(user->intf->cmd_rcvrs), link) {
                if ((cmp->netfn == netfn) && (cmp->cmd == cmd)) {
@@ -847,7 +875,7 @@ int ipmi_register_for_cmd(ipmi_user_t   user,
                rcvr->user = user;
                list_add_tail(&(rcvr->link), &(user->intf->cmd_rcvrs));
        }
- out_unlock:
+
        write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags);
        read_unlock(&(user->intf->users_lock));
 
@@ -1213,7 +1241,7 @@ static inline int i_ipmi_request(ipmi_user_t          user,
                unsigned char         ipmb_seq;
                long                  seqid;
 
-               if (addr->channel > IPMI_NUM_CHANNELS) {
+               if (addr->channel >= IPMI_NUM_CHANNELS) {
                        spin_lock_irqsave(&intf->counter_lock, flags);
                        intf->sent_invalid_commands++;
                        spin_unlock_irqrestore(&intf->counter_lock, flags);
@@ -1331,7 +1359,7 @@ static inline int i_ipmi_request(ipmi_user_t          user,
 #ifdef DEBUG_MSGING
        {
                int m;
-               for (m=0; m<smi_msg->data_size; m++)
+               for (m = 0; m < smi_msg->data_size; m++)
                        printk(" %2.2x", smi_msg->data[m]);
                printk("\n");
        }
@@ -1346,6 +1374,18 @@ static inline int i_ipmi_request(ipmi_user_t          user,
        return rv;
 }
 
+static int check_addr(ipmi_smi_t       intf,
+                     struct ipmi_addr *addr,
+                     unsigned char    *saddr,
+                     unsigned char    *lun)
+{
+       if (addr->channel >= IPMI_MAX_CHANNELS)
+               return -EINVAL;
+       *lun = intf->channels[addr->channel].lun;
+       *saddr = intf->channels[addr->channel].address;
+       return 0;
+}
+
 int ipmi_request_settime(ipmi_user_t      user,
                         struct ipmi_addr *addr,
                         long             msgid,
@@ -1355,6 +1395,14 @@ int ipmi_request_settime(ipmi_user_t      user,
                         int              retries,
                         unsigned int     retry_time_ms)
 {
+       unsigned char saddr, lun;
+       int           rv;
+
+       if (! user)
+               return -EINVAL;
+       rv = check_addr(user->intf, addr, &saddr, &lun);
+       if (rv)
+               return rv;
        return i_ipmi_request(user,
                              user->intf,
                              addr,
@@ -1363,8 +1411,8 @@ int ipmi_request_settime(ipmi_user_t      user,
                              user_msg_data,
                              NULL, NULL,
                              priority,
-                             user->intf->my_address,
-                             user->intf->my_lun,
+                             saddr,
+                             lun,
                              retries,
                              retry_time_ms);
 }
@@ -1378,6 +1426,14 @@ int ipmi_request_supply_msgs(ipmi_user_t          user,
                             struct ipmi_recv_msg *supplied_recv,
                             int                  priority)
 {
+       unsigned char saddr, lun;
+       int           rv;
+
+       if (! user)
+               return -EINVAL;
+       rv = check_addr(user->intf, addr, &saddr, &lun);
+       if (rv)
+               return rv;
        return i_ipmi_request(user,
                              user->intf,
                              addr,
@@ -1387,8 +1443,8 @@ int ipmi_request_supply_msgs(ipmi_user_t          user,
                              supplied_smi,
                              supplied_recv,
                              priority,
-                             user->intf->my_address,
-                             user->intf->my_lun,
+                             saddr,
+                             lun,
                              -1, 0);
 }
 
@@ -1397,8 +1453,15 @@ static int ipmb_file_read_proc(char *page, char **start, off_t off,
 {
        char       *out = (char *) page;
        ipmi_smi_t intf = data;
+       int        i;
+       int        rv= 0;
 
-       return sprintf(out, "%x\n", intf->my_address);
+       for (i = 0; i < IPMI_MAX_CHANNELS; i++)
+               rv += sprintf(out+rv, "%x ", intf->channels[i].address);
+       out[rv-1] = '\n'; /* Replace the final space with a newline */
+       out[rv] = '\0';
+       rv++;
+       return rv;
 }
 
 static int version_file_read_proc(char *page, char **start, off_t off,
@@ -1588,29 +1651,30 @@ send_channel_info_cmd(ipmi_smi_t intf, int chan)
                              (struct ipmi_addr *) &si,
                              0,
                              &msg,
-                             NULL,
+                             intf,
                              NULL,
                              NULL,
                              0,
-                             intf->my_address,
-                             intf->my_lun,
+                             intf->channels[0].address,
+                             intf->channels[0].lun,
                              -1, 0);
 }
 
 static void
-channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
 {
        int rv = 0;
        int chan;
 
-       if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2))
-           && (msg->rsp[1] == IPMI_GET_CHANNEL_INFO_CMD))
+       if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+           && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
+           && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
        {
                /* It's the one we want */
-               if (msg->rsp[2] != 0) {
+               if (msg->msg.data[0] != 0) {
                        /* Got an error from the channel, just go on. */
 
-                       if (msg->rsp[2] == IPMI_INVALID_COMMAND_ERR) {
+                       if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
                                /* If the MC does not support this
                                   command, that is legal.  We just
                                   assume it has one IPMB at channel
@@ -1627,13 +1691,13 @@ channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
                        }
                        goto next_channel;
                }
-               if (msg->rsp_size < 6) {
+               if (msg->msg.data_len < 4) {
                        /* Message not big enough, just go on. */
                        goto next_channel;
                }
                chan = intf->curr_channel;
-               intf->channels[chan].medium = msg->rsp[4] & 0x7f;
-               intf->channels[chan].protocol = msg->rsp[5] & 0x1f;
+               intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
+               intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
 
        next_channel:
                intf->curr_channel++;
@@ -1691,22 +1755,24 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
        rv = -ENOMEM;
 
        down_write(&interfaces_sem);
-       for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+       for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
                if (ipmi_interfaces[i] == NULL) {
                        new_intf->intf_num = i;
                        new_intf->version_major = version_major;
                        new_intf->version_minor = version_minor;
-                       if (slave_addr == 0)
-                               new_intf->my_address = IPMI_BMC_SLAVE_ADDR;
-                       else
-                               new_intf->my_address = slave_addr;
-                       new_intf->my_lun = 2;  /* the SMS LUN. */
+                       for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
+                               new_intf->channels[j].address
+                                       = IPMI_BMC_SLAVE_ADDR;
+                               new_intf->channels[j].lun = 2;
+                       }
+                       if (slave_addr != 0)
+                               new_intf->channels[0].address = slave_addr;
                        rwlock_init(&(new_intf->users_lock));
                        INIT_LIST_HEAD(&(new_intf->users));
                        new_intf->handlers = handlers;
                        new_intf->send_info = send_info;
                        spin_lock_init(&(new_intf->seq_lock));
-                       for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) {
+                       for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
                                new_intf->seq_table[j].inuse = 0;
                                new_intf->seq_table[j].seqid = 0;
                        }
@@ -1722,7 +1788,6 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
                        rwlock_init(&(new_intf->cmd_rcvr_lock));
                        init_waitqueue_head(&new_intf->waitq);
                        INIT_LIST_HEAD(&(new_intf->cmd_rcvrs));
-                       new_intf->all_cmd_rcvr = NULL;
 
                        spin_lock_init(&(new_intf->counter_lock));
 
@@ -1814,7 +1879,7 @@ static void clean_up_interface_data(ipmi_smi_t intf)
        free_recv_msg_list(&(intf->waiting_events));
        free_cmd_rcvr_list(&(intf->cmd_rcvrs));
 
-       for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) {
+       for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
                if ((intf->seq_table[i].inuse)
                    && (intf->seq_table[i].recv_msg))
                {
@@ -1833,7 +1898,7 @@ int ipmi_unregister_smi(ipmi_smi_t intf)
        down_write(&interfaces_sem);
        if (list_empty(&(intf->users)))
        {
-               for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+               for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
                        if (ipmi_interfaces[i] == intf) {
                                remove_proc_entries(intf);
                                spin_lock_irqsave(&interfaces_lock, flags);
@@ -1960,15 +2025,11 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t          intf,
 
        read_lock(&(intf->cmd_rcvr_lock));
        
-       if (intf->all_cmd_rcvr) {
-               user = intf->all_cmd_rcvr;
-       } else {
-               /* Find the command/netfn. */
-               list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
-                       if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
-                               user = rcvr->user;
-                               break;
-                       }
+       /* Find the command/netfn. */
+       list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
+               if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+                       user = rcvr->user;
+                       break;
                }
        }
        read_unlock(&(intf->cmd_rcvr_lock));
@@ -1985,7 +2046,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t          intf,
                msg->data[3] = msg->rsp[6];
                 msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
                msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
-               msg->data[6] = intf->my_address;
+               msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
                 /* rqseq/lun */
                 msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
                msg->data[8] = msg->rsp[8]; /* cmd */
@@ -1997,7 +2058,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t          intf,
        {
                int m;
                printk("Invalid command:");
-               for (m=0; m<msg->data_size; m++)
+               for (m = 0; m < msg->data_size; m++)
                        printk(" %2.2x", msg->data[m]);
                printk("\n");
        }
@@ -2145,15 +2206,11 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t          intf,
 
        read_lock(&(intf->cmd_rcvr_lock));
 
-       if (intf->all_cmd_rcvr) {
-               user = intf->all_cmd_rcvr;
-       } else {
-               /* Find the command/netfn. */
-               list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
-                       if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
-                               user = rcvr->user;
-                               break;
-                       }
+       /* Find the command/netfn. */
+       list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
+               if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+                       user = rcvr->user;
+                       break;
                }
        }
        read_unlock(&(intf->cmd_rcvr_lock));
@@ -2330,6 +2387,14 @@ static int handle_bmc_rsp(ipmi_smi_t          intf,
        unsigned long        flags;
 
        recv_msg = (struct ipmi_recv_msg *) msg->user_data;
+       if (recv_msg == NULL)
+       {
+               printk(KERN_WARNING"IPMI message received with no owner. This\n"
+                       "could be because of a malformed message, or\n"
+                       "because of a hardware error.  Contact your\n"
+                       "hardware vender for assistance\n");
+               return 0;
+       }
 
        /* Make sure the user still exists. */
        list_for_each_entry(user, &(intf->users), link) {
@@ -2340,19 +2405,11 @@ static int handle_bmc_rsp(ipmi_smi_t          intf,
                }
        }
 
-       if (!found) {
-               /* Special handling for NULL users. */
-               if (!recv_msg->user && intf->null_user_handler){
-                       intf->null_user_handler(intf, msg);
-                       spin_lock_irqsave(&intf->counter_lock, flags);
-                       intf->handled_local_responses++;
-                       spin_unlock_irqrestore(&intf->counter_lock, flags);
-               }else{
-                       /* The user for the message went away, so give up. */
-                       spin_lock_irqsave(&intf->counter_lock, flags);
-                       intf->unhandled_local_responses++;
-                       spin_unlock_irqrestore(&intf->counter_lock, flags);
-               }
+       if ((! found) && recv_msg->user) {
+               /* The user for the message went away, so give up. */
+               spin_lock_irqsave(&intf->counter_lock, flags);
+               intf->unhandled_local_responses++;
+               spin_unlock_irqrestore(&intf->counter_lock, flags);
                ipmi_free_recv_msg(recv_msg);
        } else {
                struct ipmi_system_interface_addr *smi_addr;
@@ -2392,7 +2449,7 @@ static int handle_new_recv_msg(ipmi_smi_t          intf,
 #ifdef DEBUG_MSGING
        int m;
        printk("Recv:");
-       for (m=0; m<msg->rsp_size; m++)
+       for (m = 0; m < msg->rsp_size; m++)
                printk(" %2.2x", msg->rsp[m]);
        printk("\n");
 #endif
@@ -2626,7 +2683,7 @@ smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
        {
                int m;
                printk("Resend: ");
-               for (m=0; m<smi_msg->data_size; m++)
+               for (m = 0; m < smi_msg->data_size; m++)
                        printk(" %2.2x", smi_msg->data[m]);
                printk("\n");
        }
@@ -2647,7 +2704,7 @@ ipmi_timeout_handler(long timeout_period)
        INIT_LIST_HEAD(&timeouts);
 
        spin_lock(&interfaces_lock);
-       for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+       for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
                intf = ipmi_interfaces[i];
                if (intf == NULL)
                        continue;
@@ -2672,7 +2729,7 @@ ipmi_timeout_handler(long timeout_period)
                   have timed out, putting them in the timeouts
                   list. */
                spin_lock_irqsave(&(intf->seq_lock), flags);
-               for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) {
+               for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
                        struct seq_table *ent = &(intf->seq_table[j]);
                        if (!ent->inuse)
                                continue;
@@ -2712,7 +2769,7 @@ ipmi_timeout_handler(long timeout_period)
                                spin_unlock(&intf->counter_lock);
                                smi_msg = smi_from_recv_msg(intf,
                                                ent->recv_msg, j, ent->seqid);
-                               if(!smi_msg)
+                               if (! smi_msg)
                                        continue;
 
                                spin_unlock_irqrestore(&(intf->seq_lock),flags);
@@ -2743,7 +2800,7 @@ static void ipmi_request_event(void)
        int        i;
 
        spin_lock(&interfaces_lock);
-       for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+       for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
                intf = ipmi_interfaces[i];
                if (intf == NULL)
                        continue;
@@ -2838,28 +2895,30 @@ static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
 }
 
 #ifdef CONFIG_IPMI_PANIC_STRING
-static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
 {
-       if ((msg->rsp[0] == (IPMI_NETFN_SENSOR_EVENT_RESPONSE << 2))
-           && (msg->rsp[1] == IPMI_GET_EVENT_RECEIVER_CMD)
-           && (msg->rsp[2] == IPMI_CC_NO_ERROR))
+       if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+           && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
+           && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
+           && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
        {
                /* A get event receiver command, save it. */
-               intf->event_receiver = msg->rsp[3];
-               intf->event_receiver_lun = msg->rsp[4] & 0x3;
+               intf->event_receiver = msg->msg.data[1];
+               intf->event_receiver_lun = msg->msg.data[2] & 0x3;
        }
 }
 
-static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
 {
-       if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2))
-           && (msg->rsp[1] == IPMI_GET_DEVICE_ID_CMD)
-           && (msg->rsp[2] == IPMI_CC_NO_ERROR))
+       if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+           && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
+           && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
+           && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
        {
                /* A get device id command, save if we are an event
                   receiver or generator. */
-               intf->local_sel_device = (msg->rsp[8] >> 2) & 1;
-               intf->local_event_generator = (msg->rsp[8] >> 5) & 1;
+               intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
+               intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
        }
 }
 #endif
@@ -2903,7 +2962,7 @@ static void send_panic_events(char *str)
        recv_msg.done = dummy_recv_done_handler;
 
        /* For every registered interface, send the event. */
-       for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+       for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
                intf = ipmi_interfaces[i];
                if (intf == NULL)
                        continue;
@@ -2915,12 +2974,12 @@ static void send_panic_events(char *str)
                               &addr,
                               0,
                               &msg,
-                              NULL,
+                              intf,
                               &smi_msg,
                               &recv_msg,
                               0,
-                              intf->my_address,
-                              intf->my_lun,
+                              intf->channels[0].address,
+                              intf->channels[0].lun,
                               0, 1); /* Don't retry, and don't wait. */
        }
 
@@ -2930,7 +2989,7 @@ static void send_panic_events(char *str)
        if (!str) 
                return;
 
-       for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+       for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
                char                  *p = str;
                struct ipmi_ipmb_addr *ipmb;
                int                   j;
@@ -2961,12 +3020,12 @@ static void send_panic_events(char *str)
                               &addr,
                               0,
                               &msg,
-                              NULL,
+                              intf,
                               &smi_msg,
                               &recv_msg,
                               0,
-                              intf->my_address,
-                              intf->my_lun,
+                              intf->channels[0].address,
+                              intf->channels[0].lun,
                               0, 1); /* Don't retry, and don't wait. */
 
                if (intf->local_event_generator) {
@@ -2981,12 +3040,12 @@ static void send_panic_events(char *str)
                                       &addr,
                                       0,
                                       &msg,
-                                      NULL,
+                                      intf,
                                       &smi_msg,
                                       &recv_msg,
                                       0,
-                                      intf->my_address,
-                                      intf->my_lun,
+                                      intf->channels[0].address,
+                                      intf->channels[0].lun,
                                       0, 1); /* no retry, and no wait. */
                }
                intf->null_user_handler = NULL;
@@ -2996,7 +3055,7 @@ static void send_panic_events(char *str)
                   be zero, and it must not be my address. */
                 if (((intf->event_receiver & 1) == 0)
                    && (intf->event_receiver != 0)
-                   && (intf->event_receiver != intf->my_address))
+                   && (intf->event_receiver != intf->channels[0].address))
                {
                        /* The event receiver is valid, send an IPMB
                           message. */
@@ -3031,7 +3090,7 @@ static void send_panic_events(char *str)
                        data[0] = 0;
                        data[1] = 0;
                        data[2] = 0xf0; /* OEM event without timestamp. */
-                       data[3] = intf->my_address;
+                       data[3] = intf->channels[0].address;
                        data[4] = j++; /* sequence # */
                        /* Always give 11 bytes, so strncpy will fill
                           it with zeroes for me. */
@@ -3043,12 +3102,12 @@ static void send_panic_events(char *str)
                                       &addr,
                                       0,
                                       &msg,
-                                      NULL,
+                                      intf,
                                       &smi_msg,
                                       &recv_msg,
                                       0,
-                                      intf->my_address,
-                                      intf->my_lun,
+                                      intf->channels[0].address,
+                                      intf->channels[0].lun,
                                       0, 1); /* no retry, and no wait. */
                }
        }       
@@ -3070,7 +3129,7 @@ static int panic_event(struct notifier_block *this,
        has_paniced = 1;
 
        /* For every registered interface, set it to run to completion. */
-       for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+       for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
                intf = ipmi_interfaces[i];
                if (intf == NULL)
                        continue;
@@ -3099,9 +3158,9 @@ static int ipmi_init_msghandler(void)
                return 0;
 
        printk(KERN_INFO "ipmi message handler version "
-              IPMI_MSGHANDLER_VERSION "\n");
+              IPMI_DRIVER_VERSION "\n");
 
-       for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+       for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
                ipmi_interfaces[i] = NULL;
        }
 
@@ -3171,6 +3230,9 @@ module_exit(cleanup_ipmi);
 
 module_init(ipmi_init_msghandler_mod);
 MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
+MODULE_VERSION(IPMI_DRIVER_VERSION);
 
 EXPORT_SYMBOL(ipmi_create_user);
 EXPORT_SYMBOL(ipmi_destroy_user);
index f951c30236c98aac5ed60473073118793a242924..e82a96ba396bb8ea49a460b26f2a71d4570f5284 100644 (file)
@@ -42,7 +42,6 @@
 #include <linux/ipmi_smi.h>
 
 #define PFX "IPMI poweroff: "
-#define IPMI_POWEROFF_VERSION  "v33"
 
 /* Where to we insert our poweroff function? */
 extern void (*pm_power_off)(void);
@@ -53,16 +52,17 @@ extern void (*pm_power_off)(void);
 #define IPMI_CHASSIS_POWER_CYCLE       0x02    /* power cycle */
 
 /* the IPMI data command */
-static int poweroff_control = IPMI_CHASSIS_POWER_DOWN;
+static int poweroff_powercycle;
 
 /* parameter definition to allow user to flag power cycle */
-module_param(poweroff_control, int, IPMI_CHASSIS_POWER_DOWN);
-MODULE_PARM_DESC(poweroff_control, " Set to 2 to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down.");
+module_param(poweroff_powercycle, int, 0);
+MODULE_PARM_DESC(poweroff_powercycles, " Set to non-zero to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down.");
 
 /* Stuff from the get device id command. */
 static unsigned int mfg_id;
 static unsigned int prod_id;
 static unsigned char capabilities;
+static unsigned char ipmi_version;
 
 /* We use our own messages for this operation, we don't let the system
    allocate them, since we may be in a panic situation.  The whole
@@ -337,6 +337,25 @@ static void ipmi_poweroff_cpi1 (ipmi_user_t user)
        return;
 }
 
+/*
+ * ipmi_dell_chassis_detect()
+ * Dell systems with IPMI < 1.5 don't set the chassis capability bit
+ * but they can handle a chassis poweroff or powercycle command.
+ */
+
+#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00}
+static int ipmi_dell_chassis_detect (ipmi_user_t user)
+{
+       const char ipmi_version_major = ipmi_version & 0xF;
+       const char ipmi_version_minor = (ipmi_version >> 4) & 0xF;
+       const char mfr[3]=DELL_IANA_MFR_ID;
+       if (!memcmp(mfr, &mfg_id, sizeof(mfr)) &&
+           ipmi_version_major <= 1 &&
+           ipmi_version_minor < 5)
+               return 1;
+       return 0;
+}
+
 /*
  * Standard chassis support
  */
@@ -366,37 +385,34 @@ static void ipmi_poweroff_chassis (ipmi_user_t user)
 
  powercyclefailed:
        printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n",
-               ((poweroff_control != IPMI_CHASSIS_POWER_CYCLE) ? "down" : "cycle"));
+               (poweroff_powercycle ? "cycle" : "down"));
 
        /*
         * Power down
         */
        send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST;
        send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD;
-       data[0] = poweroff_control;
+       if (poweroff_powercycle)
+               data[0] = IPMI_CHASSIS_POWER_CYCLE;
+       else
+               data[0] = IPMI_CHASSIS_POWER_DOWN;
        send_msg.data = data;
        send_msg.data_len = sizeof(data);
        rv = ipmi_request_in_rc_mode(user,
                                     (struct ipmi_addr *) &smi_addr,
                                     &send_msg);
        if (rv) {
-               switch (poweroff_control) {
-                       case IPMI_CHASSIS_POWER_CYCLE:
-                               /* power cycle failed, default to power down */
-                               printk(KERN_ERR PFX "Unable to send chassis power " \
-                                       "cycle message, IPMI error 0x%x\n", rv);
-                               poweroff_control = IPMI_CHASSIS_POWER_DOWN;
-                               goto powercyclefailed;
-
-                       case IPMI_CHASSIS_POWER_DOWN:
-                       default:
-                               printk(KERN_ERR PFX "Unable to send chassis power " \
-                                       "down message, IPMI error 0x%x\n", rv);
-                               break;
+               if (poweroff_powercycle) {
+                       /* power cycle failed, default to power down */
+                       printk(KERN_ERR PFX "Unable to send chassis power " \
+                              "cycle message, IPMI error 0x%x\n", rv);
+                       poweroff_powercycle = 0;
+                       goto powercyclefailed;
                }
-       }
 
-       return;
+               printk(KERN_ERR PFX "Unable to send chassis power " \
+                      "down message, IPMI error 0x%x\n", rv);
+       }
 }
 
 
@@ -414,6 +430,9 @@ static struct poweroff_function poweroff_functions[] = {
        { .platform_type        = "CPI1",
          .detect               = ipmi_cpi1_detect,
          .poweroff_func        = ipmi_poweroff_cpi1 },
+       { .platform_type        = "chassis",
+         .detect               = ipmi_dell_chassis_detect,
+         .poweroff_func        = ipmi_poweroff_chassis },
        /* Chassis should generally be last, other things should override
           it. */
        { .platform_type        = "chassis",
@@ -499,10 +518,11 @@ static void ipmi_po_new_smi(int if_num)
        prod_id = (halt_recv_msg.msg.data[10]
                   | (halt_recv_msg.msg.data[11] << 8));
        capabilities = halt_recv_msg.msg.data[6];
+       ipmi_version = halt_recv_msg.msg.data[5];
 
 
        /* Scan for a poweroff method */
-       for (i=0; i<NUM_PO_FUNCS; i++) {
+       for (i = 0; i < NUM_PO_FUNCS; i++) {
                if (poweroff_functions[i].detect(ipmi_user))
                        goto found;
        }
@@ -538,39 +558,35 @@ static struct ipmi_smi_watcher smi_watcher =
 
 
 #ifdef CONFIG_PROC_FS
-/* displays properties to proc */
-static int proc_read_chassctrl(char *page, char **start, off_t off, int count,
-                              int *eof, void *data)
-{
-       return sprintf(page, "%d\t[ 0=powerdown 2=powercycle ]\n",
-                       poweroff_control);
-}
+#include <linux/sysctl.h>
+
+static ctl_table ipmi_table[] = {
+       { .ctl_name     = DEV_IPMI_POWEROFF_POWERCYCLE,
+         .procname     = "poweroff_powercycle",
+         .data         = &poweroff_powercycle,
+         .maxlen       = sizeof(poweroff_powercycle),
+         .mode         = 0644,
+         .proc_handler = &proc_dointvec },
+       { }
+};
 
-/* process property writes from proc */
-static int proc_write_chassctrl(struct file *file, const char *buffer,
-                               unsigned long count, void *data)
-{
-       int          rv = count;
-       unsigned int newval = 0;
-
-       sscanf(buffer, "%d", &newval);
-       switch (newval) {
-               case IPMI_CHASSIS_POWER_CYCLE:
-                       printk(KERN_INFO PFX "power cycle is now enabled\n");
-                       poweroff_control = newval;
-                       break;
-
-               case IPMI_CHASSIS_POWER_DOWN:
-                       poweroff_control = IPMI_CHASSIS_POWER_DOWN;
-                       break;
-
-               default:
-                       rv = -EINVAL;
-                       break;
-       }
+static ctl_table ipmi_dir_table[] = {
+       { .ctl_name     = DEV_IPMI,
+         .procname     = "ipmi",
+         .mode         = 0555,
+         .child        = ipmi_table },
+       { }
+};
 
-       return rv;
-}
+static ctl_table ipmi_root_table[] = {
+       { .ctl_name     = CTL_DEV,
+         .procname     = "dev",
+         .mode         = 0555,
+         .child        = ipmi_dir_table },
+       { }
+};
+
+static struct ctl_table_header *ipmi_table_header;
 #endif /* CONFIG_PROC_FS */
 
 /*
@@ -578,42 +594,32 @@ static int proc_write_chassctrl(struct file *file, const char *buffer,
  */
 static int ipmi_poweroff_init (void)
 {
-       int                   rv;
-       struct proc_dir_entry *file;
+       int rv;
 
        printk ("Copyright (C) 2004 MontaVista Software -"
-               " IPMI Powerdown via sys_reboot version "
-               IPMI_POWEROFF_VERSION ".\n");
-
-       switch (poweroff_control) {
-               case IPMI_CHASSIS_POWER_CYCLE:
-                       printk(KERN_INFO PFX "Power cycle is enabled.\n");
-                       break;
-
-               case IPMI_CHASSIS_POWER_DOWN:
-               default:
-                       poweroff_control = IPMI_CHASSIS_POWER_DOWN;
-                       break;
+               " IPMI Powerdown via sys_reboot.\n");
+
+       if (poweroff_powercycle)
+               printk(KERN_INFO PFX "Power cycle is enabled.\n");
+
+#ifdef CONFIG_PROC_FS
+       ipmi_table_header = register_sysctl_table(ipmi_root_table, 1);
+       if (!ipmi_table_header) {
+               printk(KERN_ERR PFX "Unable to register powercycle sysctl\n");
+               rv = -ENOMEM;
+               goto out_err;
        }
+#endif
 
+#ifdef CONFIG_PROC_FS
        rv = ipmi_smi_watcher_register(&smi_watcher);
+#endif
        if (rv) {
+               unregister_sysctl_table(ipmi_table_header);
                printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv);
                goto out_err;
        }
 
-#ifdef CONFIG_PROC_FS
-       file = create_proc_entry("poweroff_control", 0, proc_ipmi_root);
-       if (!file) {
-               printk(KERN_ERR PFX "Unable to create proc power control\n");
-       } else {
-               file->nlink = 1;
-               file->read_proc = proc_read_chassctrl;
-               file->write_proc = proc_write_chassctrl;
-               file->owner = THIS_MODULE;
-       }
-#endif
-
  out_err:
        return rv;
 }
@@ -624,7 +630,7 @@ static __exit void ipmi_poweroff_cleanup(void)
        int rv;
 
 #ifdef CONFIG_PROC_FS
-       remove_proc_entry("poweroff_control", proc_ipmi_root);
+       unregister_sysctl_table(ipmi_table_header);
 #endif
 
        ipmi_smi_watcher_unregister(&smi_watcher);
@@ -642,3 +648,5 @@ module_exit(ipmi_poweroff_cleanup);
 
 module_init(ipmi_poweroff_init);
 MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("IPMI Poweroff extension to sys_reboot");
index a44b97304e95a6e38426e973428f744b1764dd61..1abec687865cf5b4862d26f4552abc39e748094d 100644 (file)
 # endif
 static inline void add_usec_to_timer(struct timer_list *t, long v)
 {
-       t->sub_expires += nsec_to_arch_cycle(v * 1000);
-       while (t->sub_expires >= arch_cycles_per_jiffy)
+       t->arch_cycle_expires += nsec_to_arch_cycle(v * 1000);
+       while (t->arch_cycle_expires >= arch_cycles_per_jiffy)
        {
                t->expires++;
-               t->sub_expires -= arch_cycles_per_jiffy;
+               t->arch_cycle_expires -= arch_cycles_per_jiffy;
        }
 }
 #endif
@@ -75,8 +75,7 @@ static inline void add_usec_to_timer(struct timer_list *t, long v)
 #include <asm/io.h>
 #include "ipmi_si_sm.h"
 #include <linux/init.h>
-
-#define IPMI_SI_VERSION "v33"
+#include <linux/dmi.h>
 
 /* Measure times between events in the driver. */
 #undef DEBUG_TIMING
@@ -109,6 +108,21 @@ enum si_type {
     SI_KCS, SI_SMIC, SI_BT
 };
 
+struct ipmi_device_id {
+       unsigned char device_id;
+       unsigned char device_revision;
+       unsigned char firmware_revision_1;
+       unsigned char firmware_revision_2;
+       unsigned char ipmi_version;
+       unsigned char additional_device_support;
+       unsigned char manufacturer_id[3];
+       unsigned char product_id[2];
+       unsigned char aux_firmware_revision[4];
+} __attribute__((packed));
+
+#define ipmi_version_major(v) ((v)->ipmi_version & 0xf)
+#define ipmi_version_minor(v) ((v)->ipmi_version >> 4)
+
 struct smi_info
 {
        ipmi_smi_t             intf;
@@ -131,12 +145,24 @@ struct smi_info
        void (*irq_cleanup)(struct smi_info *info);
        unsigned int io_size;
 
+       /* Per-OEM handler, called from handle_flags().
+          Returns 1 when handle_flags() needs to be re-run
+          or 0 indicating it set si_state itself.
+       */
+       int (*oem_data_avail_handler)(struct smi_info *smi_info);
+
        /* Flags from the last GET_MSG_FLAGS command, used when an ATTN
           is set to hold the flags until we are done handling everything
           from the flags. */
 #define RECEIVE_MSG_AVAIL      0x01
 #define EVENT_MSG_BUFFER_FULL  0x02
 #define WDT_PRE_TIMEOUT_INT    0x08
+#define OEM0_DATA_AVAIL     0x20
+#define OEM1_DATA_AVAIL     0x40
+#define OEM2_DATA_AVAIL     0x80
+#define OEM_DATA_AVAIL      (OEM0_DATA_AVAIL | \
+                             OEM1_DATA_AVAIL | \
+                             OEM2_DATA_AVAIL)
        unsigned char       msg_flags;
 
        /* If set to true, this will request events the next time the
@@ -175,11 +201,7 @@ struct smi_info
           interrupts. */
        int interrupt_disabled;
 
-       unsigned char ipmi_si_dev_rev;
-       unsigned char ipmi_si_fw_rev_major;
-       unsigned char ipmi_si_fw_rev_minor;
-       unsigned char ipmi_version_major;
-       unsigned char ipmi_version_minor;
+       struct ipmi_device_id device_id;
 
        /* Slave address, could be reported from DMI. */
        unsigned char slave_addr;
@@ -245,7 +267,7 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
                entry = smi_info->xmit_msgs.next;
        }
 
-       if (!entry) {
+       if (! entry) {
                smi_info->curr_msg = NULL;
                rv = SI_SM_IDLE;
        } else {
@@ -306,7 +328,7 @@ static void start_clear_flags(struct smi_info *smi_info)
    memory, we will re-enable the interrupt. */
 static inline void disable_si_irq(struct smi_info *smi_info)
 {
-       if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
+       if ((smi_info->irq) && (! smi_info->interrupt_disabled)) {
                disable_irq_nosync(smi_info->irq);
                smi_info->interrupt_disabled = 1;
        }
@@ -322,6 +344,7 @@ static inline void enable_si_irq(struct smi_info *smi_info)
 
 static void handle_flags(struct smi_info *smi_info)
 {
+ retry:
        if (smi_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
                /* Watchdog pre-timeout */
                spin_lock(&smi_info->count_lock);
@@ -336,7 +359,7 @@ static void handle_flags(struct smi_info *smi_info)
        } else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
                /* Messages available. */
                smi_info->curr_msg = ipmi_alloc_smi_msg();
-               if (!smi_info->curr_msg) {
+               if (! smi_info->curr_msg) {
                        disable_si_irq(smi_info);
                        smi_info->si_state = SI_NORMAL;
                        return;
@@ -355,7 +378,7 @@ static void handle_flags(struct smi_info *smi_info)
        } else if (smi_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
                /* Events available. */
                smi_info->curr_msg = ipmi_alloc_smi_msg();
-               if (!smi_info->curr_msg) {
+               if (! smi_info->curr_msg) {
                        disable_si_irq(smi_info);
                        smi_info->si_state = SI_NORMAL;
                        return;
@@ -371,6 +394,10 @@ static void handle_flags(struct smi_info *smi_info)
                        smi_info->curr_msg->data,
                        smi_info->curr_msg->data_size);
                smi_info->si_state = SI_GETTING_EVENTS;
+       } else if (smi_info->msg_flags & OEM_DATA_AVAIL) {
+               if (smi_info->oem_data_avail_handler)
+                       if (smi_info->oem_data_avail_handler(smi_info))
+                               goto retry;
        } else {
                smi_info->si_state = SI_NORMAL;
        }
@@ -387,7 +414,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
 #endif
        switch (smi_info->si_state) {
        case SI_NORMAL:
-               if (!smi_info->curr_msg)
+               if (! smi_info->curr_msg)
                        break;
 
                smi_info->curr_msg->rsp_size
@@ -761,18 +788,20 @@ 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. */
 
-               /* We already have irqsave on, so no need for it
-                   here. */
-               read_lock(&xtime_lock);
-               jiffies_now = jiffies;
-               smi_info->si_timer.expires = jiffies_now;
-               smi_info->si_timer.sub_expires = get_arch_cycles(jiffies_now);
+               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);
 
@@ -826,15 +855,19 @@ 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)
-               read_lock(&xtime_lock);
-                smi_info->si_timer.expires = jiffies;
-                smi_info->si_timer.sub_expires
-                        = get_arch_cycles(smi_info->si_timer.expires);
-                read_unlock(&xtime_lock);
+               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;
@@ -845,7 +878,7 @@ static void smi_timeout(unsigned long data)
                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.sub_expires = 0;
+               smi_info->si_timer.arch_cycle_expires = 0;
 #endif
        }
 
@@ -1014,7 +1047,7 @@ static int std_irq_setup(struct smi_info *info)
 {
        int rv;
 
-       if (!info->irq)
+       if (! info->irq)
                return 0;
 
        if (info->si_type == SI_BT) {
@@ -1023,7 +1056,7 @@ static int std_irq_setup(struct smi_info *info)
                                 SA_INTERRUPT,
                                 DEVICE_NAME,
                                 info);
-               if (!rv)
+               if (! rv)
                        /* Enable the interrupt in the BT interface. */
                        info->io.outputb(&info->io, IPMI_BT_INTMASK_REG,
                                         IPMI_BT_INTMASK_ENABLE_IRQ_BIT);
@@ -1048,7 +1081,7 @@ static int std_irq_setup(struct smi_info *info)
 
 static void std_irq_cleanup(struct smi_info *info)
 {
-       if (!info->irq)
+       if (! info->irq)
                return;
 
        if (info->si_type == SI_BT)
@@ -1121,7 +1154,7 @@ static int port_setup(struct smi_info *info)
        unsigned int *addr = info->io.info;
        int           mapsize;
 
-       if (!addr || (!*addr))
+       if (! addr || (! *addr))
                return -ENODEV;
 
        info->io_cleanup = port_cleanup;
@@ -1164,15 +1197,15 @@ static int try_init_port(int intf_num, struct smi_info **new_info)
 {
        struct smi_info *info;
 
-       if (!ports[intf_num])
+       if (! ports[intf_num])
                return -ENODEV;
 
-       if (!is_new_interface(intf_num, IPMI_IO_ADDR_SPACE,
+       if (! is_new_interface(intf_num, IPMI_IO_ADDR_SPACE,
                              ports[intf_num]))
                return -ENODEV;
 
        info = kmalloc(sizeof(*info), GFP_KERNEL);
-       if (!info) {
+       if (! info) {
                printk(KERN_ERR "ipmi_si: Could not allocate SI data (1)\n");
                return -ENOMEM;
        }
@@ -1182,10 +1215,10 @@ static int try_init_port(int intf_num, struct smi_info **new_info)
        info->io.info = &(ports[intf_num]);
        info->io.addr = NULL;
        info->io.regspacing = regspacings[intf_num];
-       if (!info->io.regspacing)
+       if (! info->io.regspacing)
                info->io.regspacing = DEFAULT_REGSPACING;
        info->io.regsize = regsizes[intf_num];
-       if (!info->io.regsize)
+       if (! info->io.regsize)
                info->io.regsize = DEFAULT_REGSPACING;
        info->io.regshift = regshifts[intf_num];
        info->irq = 0;
@@ -1270,7 +1303,7 @@ static int mem_setup(struct smi_info *info)
        unsigned long *addr = info->io.info;
        int           mapsize;
 
-       if (!addr || (!*addr))
+       if (! addr || (! *addr))
                return -ENODEV;
 
        info->io_cleanup = mem_cleanup;
@@ -1325,15 +1358,15 @@ static int try_init_mem(int intf_num, struct smi_info **new_info)
 {
        struct smi_info *info;
 
-       if (!addrs[intf_num])
+       if (! addrs[intf_num])
                return -ENODEV;
 
-       if (!is_new_interface(intf_num, IPMI_MEM_ADDR_SPACE,
+       if (! is_new_interface(intf_num, IPMI_MEM_ADDR_SPACE,
                              addrs[intf_num]))
                return -ENODEV;
 
        info = kmalloc(sizeof(*info), GFP_KERNEL);
-       if (!info) {
+       if (! info) {
                printk(KERN_ERR "ipmi_si: Could not allocate SI data (2)\n");
                return -ENOMEM;
        }
@@ -1343,10 +1376,10 @@ static int try_init_mem(int intf_num, struct smi_info **new_info)
        info->io.info = &addrs[intf_num];
        info->io.addr = NULL;
        info->io.regspacing = regspacings[intf_num];
-       if (!info->io.regspacing)
+       if (! info->io.regspacing)
                info->io.regspacing = DEFAULT_REGSPACING;
        info->io.regsize = regsizes[intf_num];
-       if (!info->io.regsize)
+       if (! info->io.regsize)
                info->io.regsize = DEFAULT_REGSPACING;
        info->io.regshift = regshifts[intf_num];
        info->irq = 0;
@@ -1404,7 +1437,7 @@ static int acpi_gpe_irq_setup(struct smi_info *info)
 {
        acpi_status status;
 
-       if (!info->irq)
+       if (! info->irq)
                return 0;
 
        /* FIXME - is level triggered right? */
@@ -1428,7 +1461,7 @@ static int acpi_gpe_irq_setup(struct smi_info *info)
 
 static void acpi_gpe_irq_cleanup(struct smi_info *info)
 {
-       if (!info->irq)
+       if (! info->irq)
                return;
 
        acpi_remove_gpe_handler(NULL, info->irq, &ipmi_acpi_gpe);
@@ -1504,10 +1537,10 @@ static int try_init_acpi(int intf_num, struct smi_info **new_info)
                addr_space = IPMI_MEM_ADDR_SPACE;
        else
                addr_space = IPMI_IO_ADDR_SPACE;
-       if (!is_new_interface(-1, addr_space, spmi->addr.address))
+       if (! is_new_interface(-1, addr_space, spmi->addr.address))
                return -ENODEV;
 
-       if (!spmi->addr.register_bit_width) {
+       if (! spmi->addr.register_bit_width) {
                acpi_failure = 1;
                return -ENODEV;
        }
@@ -1534,7 +1567,7 @@ static int try_init_acpi(int intf_num, struct smi_info **new_info)
        }
 
        info = kmalloc(sizeof(*info), GFP_KERNEL);
-       if (!info) {
+       if (! info) {
                printk(KERN_ERR "ipmi_si: Could not allocate SI data (3)\n");
                return -ENOMEM;
        }
@@ -1610,22 +1643,15 @@ typedef struct dmi_ipmi_data
 static dmi_ipmi_data_t dmi_data[SI_MAX_DRIVERS];
 static int dmi_data_entries;
 
-typedef struct dmi_header
-{
-       u8      type;
-       u8      length;
-       u16     handle;
-} dmi_header_t;
-
-static int decode_dmi(dmi_header_t __iomem *dm, int intf_num)
+static int __init decode_dmi(struct dmi_header *dm, int intf_num)
 {
-       u8              __iomem *data = (u8 __iomem *)dm;
+       u8              *data = (u8 *)dm;
        unsigned long   base_addr;
        u8              reg_spacing;
-       u8              len = readb(&dm->length);
+       u8              len = dm->length;
        dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num;
 
-       ipmi_data->type = readb(&data[4]);
+       ipmi_data->type = data[4];
 
        memcpy(&base_addr, data+8, sizeof(unsigned long));
        if (len >= 0x11) {
@@ -1640,12 +1666,12 @@ static int decode_dmi(dmi_header_t __iomem *dm, int intf_num)
                }
                /* If bit 4 of byte 0x10 is set, then the lsb for the address
                   is odd. */
-               ipmi_data->base_addr = base_addr | ((readb(&data[0x10]) & 0x10) >> 4);
+               ipmi_data->base_addr = base_addr | ((data[0x10] & 0x10) >> 4);
 
-               ipmi_data->irq = readb(&data[0x11]);
+               ipmi_data->irq = data[0x11];
 
                /* The top two bits of byte 0x10 hold the register spacing. */
-               reg_spacing = (readb(&data[0x10]) & 0xC0) >> 6;
+               reg_spacing = (data[0x10] & 0xC0) >> 6;
                switch(reg_spacing){
                case 0x00: /* Byte boundaries */
                    ipmi_data->offset = 1;
@@ -1673,7 +1699,7 @@ static int decode_dmi(dmi_header_t __iomem *dm, int intf_num)
                ipmi_data->offset = 1;
        }
 
-       ipmi_data->slave_addr = readb(&data[6]);
+       ipmi_data->slave_addr = data[6];
 
        if (is_new_interface(-1, ipmi_data->addr_space,ipmi_data->base_addr)) {
                dmi_data_entries++;
@@ -1685,94 +1711,29 @@ static int decode_dmi(dmi_header_t __iomem *dm, int intf_num)
        return -1;
 }
 
-static int dmi_table(u32 base, int len, int num)
+static void __init dmi_find_bmc(void)
 {
-       u8                __iomem *buf;
-       struct dmi_header __iomem *dm;
-       u8                __iomem *data;
-       int               i=1;
-       int               status=-1;
+       struct dmi_device *dev = NULL;
        int               intf_num = 0;
 
-       buf = ioremap(base, len);
-       if(buf==NULL)
-               return -1;
-
-       data = buf;
-
-       while(i<num && (data - buf) < len)
-       {
-               dm=(dmi_header_t __iomem *)data;
-
-               if((data-buf+readb(&dm->length)) >= len)
-                       break;
-
-               if (readb(&dm->type) == 38) {
-                       if (decode_dmi(dm, intf_num) == 0) {
-                               intf_num++;
-                               if (intf_num >= SI_MAX_DRIVERS)
-                                       break;
-                       }
-               }
-
-               data+=readb(&dm->length);
-               while((data-buf) < len && (readb(data)||readb(data+1)))
-                       data++;
-               data+=2;
-               i++;
-       }
-       iounmap(buf);
-
-       return status;
-}
-
-static inline int dmi_checksum(u8 *buf)
-{
-       u8   sum=0;
-       int  a;
-
-       for(a=0; a<15; a++)
-               sum+=buf[a];
-       return (sum==0);
-}
-
-static int dmi_decode(void)
-{
-       u8   buf[15];
-       u32  fp=0xF0000;
-
-#ifdef CONFIG_SIMNOW
-       return -1;
-#endif
-
-       while(fp < 0xFFFFF)
-       {
-               isa_memcpy_fromio(buf, fp, 15);
-               if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf))
-               {
-                       u16 num=buf[13]<<8|buf[12];
-                       u16 len=buf[7]<<8|buf[6];
-                       u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
+       while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) {
+               if (intf_num >= SI_MAX_DRIVERS)
+                       break;
 
-                       if(dmi_table(base, len, num) == 0)
-                               return 0;
-               }
-               fp+=16;
+               decode_dmi((struct dmi_header *) dev->device_data, intf_num++);
        }
-
-       return -1;
 }
 
 static int try_init_smbios(int intf_num, struct smi_info **new_info)
 {
-       struct smi_info   *info;
-       dmi_ipmi_data_t   *ipmi_data = dmi_data+intf_num;
-       char              *io_type;
+       struct smi_info *info;
+       dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num;
+       char            *io_type;
 
        if (intf_num >= dmi_data_entries)
                return -ENODEV;
 
-       switch(ipmi_data->type) {
+       switch (ipmi_data->type) {
                case 0x01: /* KCS */
                        si_type[intf_num] = "kcs";
                        break;
@@ -1787,7 +1748,7 @@ static int try_init_smbios(int intf_num, struct smi_info **new_info)
        }
 
        info = kmalloc(sizeof(*info), GFP_KERNEL);
-       if (!info) {
+       if (! info) {
                printk(KERN_ERR "ipmi_si: Could not allocate SI data (4)\n");
                return -ENOMEM;
        }
@@ -1811,7 +1772,7 @@ static int try_init_smbios(int intf_num, struct smi_info **new_info)
 
        regspacings[intf_num] = ipmi_data->offset;
        info->io.regspacing = regspacings[intf_num];
-       if (!info->io.regspacing)
+       if (! info->io.regspacing)
                info->io.regspacing = DEFAULT_REGSPACING;
        info->io.regsize = DEFAULT_REGSPACING;
        info->io.regshift = regshifts[intf_num];
@@ -1853,14 +1814,14 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info)
 
        pci_smic_checked = 1;
 
-       if ((pci_dev = pci_get_device(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID,
-                                      NULL)))
-               ;
-       else if ((pci_dev = pci_get_class(PCI_ERMC_CLASSCODE, NULL)) &&
-                pci_dev->subsystem_vendor == PCI_HP_VENDOR_ID)
-               fe_rmc = 1;
-       else
-               return -ENODEV;
+       pci_dev = pci_get_device(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID, NULL);
+       if (! pci_dev) {
+               pci_dev = pci_get_class(PCI_ERMC_CLASSCODE, NULL);
+               if (pci_dev && (pci_dev->subsystem_vendor == PCI_HP_VENDOR_ID))
+                       fe_rmc = 1;
+               else
+                       return -ENODEV;
+       }
 
        error = pci_read_config_word(pci_dev, PCI_MMC_ADDR_CW, &base_addr);
        if (error)
@@ -1873,7 +1834,7 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info)
        }
 
        /* Bit 0: 1 specifies programmed I/O, 0 specifies memory mapped I/O */
-       if (!(base_addr & 0x0001))
+       if (! (base_addr & 0x0001))
        {
                pci_dev_put(pci_dev);
                printk(KERN_ERR
@@ -1883,17 +1844,17 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info)
        }
 
        base_addr &= 0xFFFE;
-       if (!fe_rmc)
+       if (! fe_rmc)
                /* Data register starts at base address + 1 in eRMC */
                ++base_addr;
 
-       if (!is_new_interface(-1, IPMI_IO_ADDR_SPACE, base_addr)) {
+       if (! is_new_interface(-1, IPMI_IO_ADDR_SPACE, base_addr)) {
                pci_dev_put(pci_dev);
                return -ENODEV;
        }
 
        info = kmalloc(sizeof(*info), GFP_KERNEL);
-       if (!info) {
+       if (! info) {
                pci_dev_put(pci_dev);
                printk(KERN_ERR "ipmi_si: Could not allocate SI data (5)\n");
                return -ENOMEM;
@@ -1904,7 +1865,7 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info)
        ports[intf_num] = base_addr;
        info->io.info = &(ports[intf_num]);
        info->io.regspacing = regspacings[intf_num];
-       if (!info->io.regspacing)
+       if (! info->io.regspacing)
                info->io.regspacing = DEFAULT_REGSPACING;
        info->io.regsize = DEFAULT_REGSPACING;
        info->io.regshift = regshifts[intf_num];
@@ -1925,7 +1886,7 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info)
 static int try_init_plug_and_play(int intf_num, struct smi_info **new_info)
 {
 #ifdef CONFIG_PCI
-       if (find_pci_smic(intf_num, new_info)==0)
+       if (find_pci_smic(intf_num, new_info) == 0)
                return 0;
 #endif
        /* Include other methods here. */
@@ -1943,7 +1904,7 @@ static int try_get_dev_id(struct smi_info *smi_info)
        int               rv = 0;
 
        resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
-       if (!resp)
+       if (! resp)
                return -ENOMEM;
 
        /* Do a Get Device ID command, since it comes back with some
@@ -1992,11 +1953,8 @@ static int try_get_dev_id(struct smi_info *smi_info)
        }
 
        /* Record info from the get device id, in case we need it. */
-       smi_info->ipmi_si_dev_rev = resp[4] & 0xf;
-       smi_info->ipmi_si_fw_rev_major = resp[5] & 0x7f;
-       smi_info->ipmi_si_fw_rev_minor = resp[6];
-       smi_info->ipmi_version_major = resp[7] & 0xf;
-       smi_info->ipmi_version_minor = resp[7] >> 4;
+       memcpy(&smi_info->device_id, &resp[3],
+              min_t(unsigned long, resp_len-3, sizeof(smi_info->device_id)));
 
  out:
        kfree(resp);
@@ -2028,7 +1986,7 @@ static int stat_file_read_proc(char *page, char **start, off_t off,
        struct smi_info *smi = data;
 
        out += sprintf(out, "interrupts_enabled:    %d\n",
-                      smi->irq && !smi->interrupt_disabled);
+                      smi->irq && ! smi->interrupt_disabled);
        out += sprintf(out, "short_timeouts:        %ld\n",
                       smi->short_timeouts);
        out += sprintf(out, "long_timeouts:         %ld\n",
@@ -2057,6 +2015,73 @@ static int stat_file_read_proc(char *page, char **start, off_t off,
        return (out - ((char *) page));
 }
 
+/*
+ * oem_data_avail_to_receive_msg_avail
+ * @info - smi_info structure with msg_flags set
+ *
+ * Converts flags from OEM_DATA_AVAIL to RECEIVE_MSG_AVAIL
+ * Returns 1 indicating need to re-run handle_flags().
+ */
+static int oem_data_avail_to_receive_msg_avail(struct smi_info *smi_info)
+{
+       smi_info->msg_flags = ((smi_info->msg_flags & ~OEM_DATA_AVAIL) |
+                               RECEIVE_MSG_AVAIL);
+       return 1;
+}
+
+/*
+ * setup_dell_poweredge_oem_data_handler
+ * @info - smi_info.device_id must be populated
+ *
+ * Systems that match, but have firmware version < 1.40 may assert
+ * OEM0_DATA_AVAIL on their own, without being told via Set Flags that
+ * it's safe to do so.  Such systems will de-assert OEM1_DATA_AVAIL
+ * upon receipt of IPMI_GET_MSG_CMD, so we should treat these flags
+ * as RECEIVE_MSG_AVAIL instead.
+ *
+ * As Dell has no plans to release IPMI 1.5 firmware that *ever*
+ * assert the OEM[012] bits, and if it did, the driver would have to
+ * change to handle that properly, we don't actually check for the
+ * firmware version.
+ * Device ID = 0x20                BMC on PowerEdge 8G servers
+ * Device Revision = 0x80
+ * Firmware Revision1 = 0x01       BMC version 1.40
+ * Firmware Revision2 = 0x40       BCD encoded
+ * IPMI Version = 0x51             IPMI 1.5
+ * Manufacturer ID = A2 02 00      Dell IANA
+ *
+ */
+#define DELL_POWEREDGE_8G_BMC_DEVICE_ID  0x20
+#define DELL_POWEREDGE_8G_BMC_DEVICE_REV 0x80
+#define DELL_POWEREDGE_8G_BMC_IPMI_VERSION 0x51
+#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00}
+static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info)
+{
+       struct ipmi_device_id *id = &smi_info->device_id;
+       const char mfr[3]=DELL_IANA_MFR_ID;
+       if (! memcmp(mfr, id->manufacturer_id, sizeof(mfr))
+           && (id->device_id       == DELL_POWEREDGE_8G_BMC_DEVICE_ID)
+           && (id->device_revision == DELL_POWEREDGE_8G_BMC_DEVICE_REV)
+           && (id->ipmi_version    == DELL_POWEREDGE_8G_BMC_IPMI_VERSION))
+       {
+               smi_info->oem_data_avail_handler =
+                       oem_data_avail_to_receive_msg_avail;
+       }
+}
+
+/*
+ * setup_oem_data_handler
+ * @info - smi_info.device_id must be filled in already
+ *
+ * Fills in smi_info.device_id.oem_data_available_handler
+ * when we know what function to use there.
+ */
+
+static void setup_oem_data_handler(struct smi_info *smi_info)
+{
+       setup_dell_poweredge_oem_data_handler(smi_info);
+}
+
 /* Returns 0 if initialized, or negative on an error. */
 static int init_one_smi(int intf_num, struct smi_info **smi)
 {
@@ -2068,19 +2093,15 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
        if (rv)
                rv = try_init_port(intf_num, &new_smi);
 #ifdef CONFIG_ACPI_INTERPRETER
-       if ((rv) && (si_trydefaults)) {
+       if (rv && si_trydefaults)
                rv = try_init_acpi(intf_num, &new_smi);
-       }
 #endif
 #ifdef CONFIG_X86
-       if ((rv) && (si_trydefaults)) {
+       if (rv && si_trydefaults)
                rv = try_init_smbios(intf_num, &new_smi);
-        }
 #endif
-       if ((rv) && (si_trydefaults)) {
+       if (rv && si_trydefaults)
                rv = try_init_plug_and_play(intf_num, &new_smi);
-       }
-
 
        if (rv)
                return rv;
@@ -2090,7 +2111,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
        new_smi->si_sm = NULL;
        new_smi->handlers = NULL;
 
-       if (!new_smi->irq_setup) {
+       if (! new_smi->irq_setup) {
                new_smi->irq = irqs[intf_num];
                new_smi->irq_setup = std_irq_setup;
                new_smi->irq_cleanup = std_irq_cleanup;
@@ -2124,7 +2145,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
 
        /* Allocate the state machine's data and initialize it. */
        new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL);
-       if (!new_smi->si_sm) {
+       if (! new_smi->si_sm) {
                printk(" Could not allocate state machine memory\n");
                rv = -ENOMEM;
                goto out_err;
@@ -2155,6 +2176,8 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
        if (rv)
                goto out_err;
 
+       setup_oem_data_handler(new_smi);
+
        /* Try to claim any interrupts. */
        new_smi->irq_setup(new_smi);
 
@@ -2188,8 +2211,8 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
 
        rv = ipmi_register_smi(&handlers,
                               new_smi,
-                              new_smi->ipmi_version_major,
-                              new_smi->ipmi_version_minor,
+                              ipmi_version_major(&new_smi->device_id),
+                              ipmi_version_minor(&new_smi->device_id),
                               new_smi->slave_addr,
                               &(new_smi->intf));
        if (rv) {
@@ -2230,7 +2253,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
 
        /* Wait for the timer to stop.  This avoids problems with race
           conditions removing the timer here. */
-       while (!new_smi->timer_stopped) {
+       while (! new_smi->timer_stopped) {
                set_current_state(TASK_UNINTERRUPTIBLE);
                schedule_timeout(1);
        }
@@ -2270,7 +2293,7 @@ static __init int init_ipmi_si(void)
        /* Parse out the si_type string into its components. */
        str = si_type_str;
        if (*str != '\0') {
-               for (i=0; (i<SI_MAX_PARMS) && (*str != '\0'); i++) {
+               for (i = 0; (i < SI_MAX_PARMS) && (*str != '\0'); i++) {
                        si_type[i] = str;
                        str = strchr(str, ',');
                        if (str) {
@@ -2282,22 +2305,14 @@ static __init int init_ipmi_si(void)
                }
        }
 
-       printk(KERN_INFO "IPMI System Interface driver version "
-              IPMI_SI_VERSION);
-       if (kcs_smi_handlers.version)
-               printk(", KCS version %s", kcs_smi_handlers.version);
-       if (smic_smi_handlers.version)
-               printk(", SMIC version %s", smic_smi_handlers.version);
-       if (bt_smi_handlers.version)
-               printk(", BT version %s", bt_smi_handlers.version);
-       printk("\n");
+       printk(KERN_INFO "IPMI System Interface driver.\n");
 
 #ifdef CONFIG_X86
-       dmi_decode();
+       dmi_find_bmc();
 #endif
 
        rv = init_one_smi(0, &(smi_infos[pos]));
-       if (rv && !ports[0] && si_trydefaults) {
+       if (rv && ! ports[0] && si_trydefaults) {
                /* If we are trying defaults and the initial port is
                    not set, then set it. */
                si_type[0] = "kcs";
@@ -2319,7 +2334,7 @@ static __init int init_ipmi_si(void)
        if (rv == 0)
                pos++;
 
-       for (i=1; i < SI_MAX_PARMS; i++) {
+       for (i = 1; i < SI_MAX_PARMS; i++) {
                rv = init_one_smi(i, &(smi_infos[pos]));
                if (rv == 0)
                        pos++;
@@ -2361,14 +2376,14 @@ static void __exit cleanup_one_si(struct smi_info *to_clean)
 
        /* Wait for the timer to stop.  This avoids problems with race
           conditions removing the timer here. */
-       while (!to_clean->timer_stopped) {
+       while (! to_clean->timer_stopped) {
                set_current_state(TASK_UNINTERRUPTIBLE);
                schedule_timeout(1);
        }
 
        /* Interrupts and timeouts are stopped, now make sure the
           interface is in a clean state. */
-       while ((to_clean->curr_msg) || (to_clean->si_state != SI_NORMAL)) {
+       while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
                poll(to_clean);
                set_current_state(TASK_UNINTERRUPTIBLE);
                schedule_timeout(1);
@@ -2392,13 +2407,15 @@ static __exit void cleanup_ipmi_si(void)
 {
        int i;
 
-       if (!initialized)
+       if (! initialized)
                return;
 
-       for (i=0; i<SI_MAX_DRIVERS; i++) {
+       for (i = 0; i < SI_MAX_DRIVERS; i++) {
                cleanup_one_si(smi_infos[i]);
        }
 }
 module_exit(cleanup_ipmi_si);
 
 MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("Interface to the IPMI driver for the KCS, SMIC, and BT system interfaces.");
index ae18747e670b10c0f2255403811f1210c85df982..add2aa2732f0c56c4324088a1a18b08ec08c7b9a 100644 (file)
@@ -46,8 +46,6 @@
 #include <linux/ipmi_msgdefs.h>                /* for completion codes */
 #include "ipmi_si_sm.h"
 
-#define IPMI_SMIC_VERSION "v33"
-
 /* smic_debug is a bit-field
  *     SMIC_DEBUG_ENABLE -     turned on for now
  *     SMIC_DEBUG_MSG -        commands and their responses
@@ -588,7 +586,6 @@ static int smic_size(void)
 
 struct si_sm_handlers smic_smi_handlers =
 {
-       .version           = IPMI_SMIC_VERSION,
        .init_data         = init_smic_data,
        .start_transaction = start_smic_transaction,
        .get_result        = smic_get_result,
index d35a953961cb9df8d5df54310cea2342f68fd8f9..e71aaae855adda775f9c296e6d91a333192d8110 100644 (file)
@@ -53,8 +53,6 @@
 
 #define        PFX "IPMI Watchdog: "
 
-#define IPMI_WATCHDOG_VERSION "v33"
-
 /*
  * The IPMI command/response information for the watchdog timer.
  */
@@ -259,7 +257,7 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg  *smi_msg,
 
        data[1] = 0;
        WDOG_SET_TIMEOUT_ACT(data[1], ipmi_watchdog_state);
-       if (pretimeout > 0) {
+       if ((pretimeout > 0) && (ipmi_watchdog_state != WDOG_TIMEOUT_NONE)) {
            WDOG_SET_PRETIMEOUT_ACT(data[1], preaction_val);
            data[2] = pretimeout;
        } else {
@@ -659,19 +657,18 @@ static ssize_t ipmi_read(struct file *file,
 
 static int ipmi_open(struct inode *ino, struct file *filep)
 {
-        switch (iminor(ino))
-        {
-                case WATCHDOG_MINOR:
-                   if(test_and_set_bit(0, &ipmi_wdog_open))
+        switch (iminor(ino)) {
+        case WATCHDOG_MINOR:
+               if (test_and_set_bit(0, &ipmi_wdog_open))
                         return -EBUSY;
 
-                   /* Don't start the timer now, let it start on the
-                      first heartbeat. */
-                   ipmi_start_timer_on_heartbeat = 1;
-                    return nonseekable_open(ino, filep);
+               /* Don't start the timer now, let it start on the
+                  first heartbeat. */
+               ipmi_start_timer_on_heartbeat = 1;
+               return nonseekable_open(ino, filep);
 
-                default:
-                    return (-ENODEV);
+       default:
+               return (-ENODEV);
         }
 }
 
@@ -817,15 +814,19 @@ static void ipmi_register_watchdog(int ipmi_intf)
 static int
 ipmi_nmi(void *dev_id, struct pt_regs *regs, int cpu, int handled)
 {
+        /* If we are not expecting a timeout, ignore it. */
+       if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
+               return NOTIFY_DONE;
+
        /* If no one else handled the NMI, we assume it was the IPMI
            watchdog. */
-       if ((!handled) && (preop_val == WDOG_PREOP_PANIC))
+       if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) {
+               /* On some machines, the heartbeat will give
+                  an error and not work unless we re-enable
+                  the timer.   So do so. */
+               pretimeout_since_last_heartbeat = 1;
                panic(PFX "pre-timeout");
-
-       /* On some machines, the heartbeat will give
-          an error and not work unless we re-enable
-          the timer.   So do so. */
-       pretimeout_since_last_heartbeat = 1;
+       }
 
        return NOTIFY_DONE;
 }
@@ -924,9 +925,6 @@ static int __init ipmi_wdog_init(void)
 {
        int rv;
 
-       printk(KERN_INFO PFX "driver version "
-              IPMI_WATCHDOG_VERSION "\n");
-
        if (strcmp(action, "reset") == 0) {
                action_val = WDOG_TIMEOUT_RESET;
        } else if (strcmp(action, "none") == 0) {
@@ -1011,6 +1009,8 @@ static int __init ipmi_wdog_init(void)
        register_reboot_notifier(&wdog_reboot_notifier);
        notifier_chain_register(&panic_notifier_list, &wdog_panic_notifier);
 
+       printk(KERN_INFO PFX "driver initialized\n");
+
        return 0;
 }
 
@@ -1062,3 +1062,5 @@ static void __exit ipmi_wdog_exit(void)
 module_exit(ipmi_wdog_exit);
 module_init(ipmi_wdog_init);
 MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("watchdog timer based upon the IPMI interface.");
index 115dbb35334b031e71acaedff084402499a449a2..3fa64c63110864597f6fb5d32a3d40ebe0d84384 100644 (file)
@@ -750,7 +750,7 @@ static int mbcs_probe(struct cx_dev *dev, const struct cx_device_id *id)
 
        dev->soft = NULL;
 
-       soft = kcalloc(1, sizeof(struct mbcs_soft), GFP_KERNEL);
+       soft = kzalloc(sizeof(struct mbcs_soft), GFP_KERNEL);
        if (soft == NULL)
                return -ENOMEM;
 
index 850a78c9c4bc9c639dd5b2c5816a4c89e7568eb1..f182752fe918b9b08bb601bd0bc827bb3e1f0cf2 100644 (file)
 # include <linux/efi.h>
 #endif
 
-#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR)
-extern void tapechar_init(void);
-#endif
-
 /*
  * Architectures vary in how they handle caching for addresses
  * outside of main memory.
index 931efd58f87a2d4270a7180f2fd9b7c22bcbfa81..0c8375165e29afca09a0ba82a6387f7a56c7e9a4 100644 (file)
@@ -63,8 +63,6 @@ static DECLARE_MUTEX(misc_sem);
 #define DYNAMIC_MINORS 64 /* like dynamic majors */
 static unsigned char misc_minors[DYNAMIC_MINORS / 8];
 
-extern int rtc_DP8570A_init(void);
-extern int rtc_MK48T08_init(void);
 extern int pmu_device_init(void);
 
 #ifdef CONFIG_PROC_FS
@@ -303,12 +301,7 @@ static int __init misc_init(void)
        misc_class = class_create(THIS_MODULE, "misc");
        if (IS_ERR(misc_class))
                return PTR_ERR(misc_class);
-#ifdef CONFIG_MVME16x
-       rtc_MK48T08_init();
-#endif
-#ifdef CONFIG_BVME6000
-       rtc_DP8570A_init();
-#endif
+
        if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
                printk("unable to get major %d for misc devices\n",
                       MISC_MAJOR);
index 95f7046ff059184c5c7b8024e83881c922c25289..79e490ef2cf2ea352045e2d5a71913bac50158eb 100644 (file)
@@ -339,7 +339,7 @@ static int __init moxa_init(void)
 
        init_MUTEX(&moxaBuffSem);
        moxaDriver->owner = THIS_MODULE;
-       moxaDriver->name = "ttya";
+       moxaDriver->name = "ttyMX";
        moxaDriver->devfs_name = "tts/a";
        moxaDriver->major = ttymajor;
        moxaDriver->minor_start = 0;
index d568991ac6b3eafcc2dd85b48a881756c9353d2c..8666171e187b0cf1b53437308566d0ef48b8de9e 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/delay.h>
+#include <linux/serial_8250.h>
 #include "smapi.h"
 #include "mwavedd.h"
 #include "3780i.h"
@@ -410,8 +411,8 @@ static ssize_t mwave_write(struct file *file, const char __user *buf,
 
 static int register_serial_portandirq(unsigned int port, int irq)
 {
-       struct serial_struct serial;
-
+       struct uart_port uart;
+       
        switch ( port ) {
                case 0x3f8:
                case 0x2f8:
@@ -442,12 +443,14 @@ static int register_serial_portandirq(unsigned int port, int irq)
        } /* switch */
        /* irq is okay */
 
-       memset(&serial, 0, sizeof(serial));
-       serial.port = port;
-       serial.irq = irq;
-       serial.flags = ASYNC_SHARE_IRQ;
-
-       return register_serial(&serial);
+       memset(&uart, 0, sizeof(struct uart_port));
+       
+       uart.uartclk =  1843200;
+       uart.iobase = port;
+       uart.irq = irq;
+       uart.iotype = UPIO_PORT;
+       uart.flags =  UPF_SHARE_IRQ;
+       return serial8250_register_port(&uart);
 }
 
 
@@ -523,7 +526,7 @@ static void mwave_exit(void)
 #endif
 
        if ( pDrvData->sLine >= 0 ) {
-               unregister_serial(pDrvData->sLine);
+               serial8250_unregister_port(pDrvData->sLine);
        }
        if (pDrvData->bMwaveDevRegistered) {
                misc_deregister(&mwave_misc_dev);
index f022f0944434158f31eb3a9b3f0c9da35abadf1b..d0ef1ae412981d774289575dba2ea8a866975e37 100644 (file)
@@ -63,7 +63,6 @@
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/segment.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 
index 6b11d6b2129f08cb9a800292f05f409e0b70835d..7999da25fe40afb035c4342cd1f227f0b4d21078 100644 (file)
@@ -1589,6 +1589,40 @@ u32 secure_tcpv6_port_ephemeral(const __u32 *saddr, const __u32 *daddr, __u16 dp
 EXPORT_SYMBOL(secure_tcpv6_port_ephemeral);
 #endif
 
+#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
+/* Similar to secure_tcp_sequence_number but generate a 48 bit value
+ * bit's 32-47 increase every key exchange
+ *       0-31  hash(source, dest)
+ */
+u64 secure_dccp_sequence_number(__u32 saddr, __u32 daddr,
+                               __u16 sport, __u16 dport)
+{
+       struct timeval tv;
+       u64 seq;
+       __u32 hash[4];
+       struct keydata *keyptr = get_keyptr();
+
+       hash[0] = saddr;
+       hash[1] = daddr;
+       hash[2] = (sport << 16) + dport;
+       hash[3] = keyptr->secret[11];
+
+       seq = half_md4_transform(hash, keyptr->secret);
+       seq |= ((u64)keyptr->count) << (32 - HASH_BITS);
+
+       do_gettimeofday(&tv);
+       seq += tv.tv_usec + tv.tv_sec * 1000000;
+       seq &= (1ull << 48) - 1;
+#if 0
+       printk("dccp init_seq(%lx, %lx, %d, %d) = %d\n",
+              saddr, daddr, sport, dport, seq);
+#endif
+       return seq;
+}
+
+EXPORT_SYMBOL(secure_dccp_sequence_number);
+#endif
+
 #endif /* CONFIG_INET */
 
 
index cd4fe8b1709f67593d47939819c9fd6a37e32ce3..63fff7c1244a29941dba32b1047ad63a31644831 100644 (file)
@@ -938,10 +938,9 @@ found:
 
        /*
         * XXX Interrupt pin #7 in Espresso is shared between RTC and
-        * PCI Slot 2 INTA# (and some INTx# in Slot 1). SA_INTERRUPT here
-        * is asking for trouble with add-on boards. Change to SA_SHIRQ.
+        * PCI Slot 2 INTA# (and some INTx# in Slot 1).
         */
-       if (request_irq(rtc_irq, rtc_interrupt, SA_INTERRUPT, "rtc", (void *)&rtc_port)) {
+       if (request_irq(rtc_irq, rtc_interrupt, SA_SHIRQ, "rtc", (void *)&rtc_port)) {
                /*
                 * Standard way for sparc to print irq's is to use
                 * __irq_itoa(). I think for EBus it's ok to use %d.
index d692af57213a7cbfac0a7e884749c94a35fb4b73..baaa365285fa973776beddcb0ae5c09389ffbe65 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/sched.h>
 #include <linux/byteorder/generic.h>
 #include <asm/sn/sn_sal.h>
+#include <asm/unaligned.h>
 #include "snsc.h"
 
 static struct subch_data_s *event_sd;
@@ -62,13 +63,16 @@ static int
 scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc)
 {
        char *desc_end;
+       __be32 from_buf;
 
        /* record event source address */
-       *src = be32_to_cpup((__be32 *)event);
+       from_buf = get_unaligned((__be32 *)event);
+       *src = be32_to_cpup(&from_buf);
        event += 4;                     /* move on to event code */
 
        /* record the system controller's event code */
-       *code = be32_to_cpup((__be32 *)event);
+       from_buf = get_unaligned((__be32 *)event);
+       *code = be32_to_cpup(&from_buf);
        event += 4;                     /* move on to event arguments */
 
        /* how many arguments are in the packet? */
@@ -82,7 +86,8 @@ scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc)
                /* not an integer argument, so give up */
                return -1;
        }
-       *esp_code = be32_to_cpup((__be32 *)event);
+       from_buf = get_unaligned((__be32 *)event);
+       *esp_code = be32_to_cpup(&from_buf);
        event += 4;
 
        /* parse out the event description */
index cefbe985e55cf57e94f07f52d7bc57e6e11834f3..36ae9ad2598cc755cbad3a40a86111b1a25374b2 100644 (file)
@@ -98,12 +98,13 @@ MODULE_PARM_DESC(useinput,
 
 #define SONYPI_DEVICE_MODEL_TYPE1      1
 #define SONYPI_DEVICE_MODEL_TYPE2      2
+#define SONYPI_DEVICE_MODEL_TYPE3      3
 
 /* type1 models use those */
 #define SONYPI_IRQ_PORT                        0x8034
 #define SONYPI_IRQ_SHIFT               22
-#define SONYPI_BASE                    0x50
-#define SONYPI_G10A                    (SONYPI_BASE+0x14)
+#define SONYPI_TYPE1_BASE              0x50
+#define SONYPI_G10A                    (SONYPI_TYPE1_BASE+0x14)
 #define SONYPI_TYPE1_REGION_SIZE       0x08
 #define SONYPI_TYPE1_EVTYPE_OFFSET     0x04
 
@@ -114,6 +115,13 @@ MODULE_PARM_DESC(useinput,
 #define SONYPI_TYPE2_REGION_SIZE       0x20
 #define SONYPI_TYPE2_EVTYPE_OFFSET     0x12
 
+/* type3 series specifics */
+#define SONYPI_TYPE3_BASE              0x40
+#define SONYPI_TYPE3_GID2              (SONYPI_TYPE3_BASE+0x48) /* 16 bits */
+#define SONYPI_TYPE3_MISC              (SONYPI_TYPE3_BASE+0x6d) /* 8 bits  */
+#define SONYPI_TYPE3_REGION_SIZE       0x20
+#define SONYPI_TYPE3_EVTYPE_OFFSET     0x12
+
 /* battery / brightness addresses */
 #define SONYPI_BAT_FLAGS       0x81
 #define SONYPI_LCD_LIGHT       0x96
@@ -159,6 +167,10 @@ static struct sonypi_ioport_list sonypi_type2_ioport_list[] = {
        { 0x0, 0x0 }
 };
 
+/* same as in type 2 models */
+static struct sonypi_ioport_list *sonypi_type3_ioport_list =
+       sonypi_type2_ioport_list;
+
 /* The set of possible interrupts */
 struct sonypi_irq_list {
        u16     irq;
@@ -180,6 +192,9 @@ static struct sonypi_irq_list sonypi_type2_irq_list[] = {
        {  0, 0x00 }    /* no IRQ, 0x00 in SIRQ in AML */
 };
 
+/* same as in type2 models */
+static struct sonypi_irq_list *sonypi_type3_irq_list = sonypi_type2_irq_list;
+
 #define SONYPI_CAMERA_BRIGHTNESS               0
 #define SONYPI_CAMERA_CONTRAST                 1
 #define SONYPI_CAMERA_HUE                      2
@@ -223,6 +238,7 @@ static struct sonypi_irq_list sonypi_type2_irq_list[] = {
 #define SONYPI_MEYE_MASK                       0x00000400
 #define SONYPI_MEMORYSTICK_MASK                        0x00000800
 #define SONYPI_BATTERY_MASK                    0x00001000
+#define SONYPI_WIRELESS_MASK                   0x00002000
 
 struct sonypi_event {
        u8      data;
@@ -305,6 +321,13 @@ static struct sonypi_event sonypi_blueev[] = {
        { 0, 0 }
 };
 
+/* The set of possible wireless events */
+static struct sonypi_event sonypi_wlessev[] = {
+       { 0x59, SONYPI_EVENT_WIRELESS_ON },
+       { 0x5a, SONYPI_EVENT_WIRELESS_OFF },
+       { 0, 0 }
+};
+
 /* The set of possible back button events */
 static struct sonypi_event sonypi_backev[] = {
        { 0x20, SONYPI_EVENT_BACK_PRESSED },
@@ -383,7 +406,6 @@ static struct sonypi_eventtypes {
        { SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
        { SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
        { SONYPI_DEVICE_MODEL_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev },
-       { SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_HELP_MASK, sonypi_helpev },
        { SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev },
        { SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
        { SONYPI_DEVICE_MODEL_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
@@ -391,6 +413,12 @@ static struct sonypi_eventtypes {
        { SONYPI_DEVICE_MODEL_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
        { SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
 
+       { SONYPI_DEVICE_MODEL_TYPE3, 0, 0xffffffff, sonypi_releaseev },
+       { SONYPI_DEVICE_MODEL_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+       { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
+       { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+       { SONYPI_DEVICE_MODEL_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+       { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
        { 0 }
 };
 
@@ -563,6 +591,23 @@ static void sonypi_type2_srs(void)
        udelay(10);
 }
 
+static void sonypi_type3_srs(void)
+{
+       u16 v16;
+       u8  v8;
+
+       /* This model type uses the same initialiazation of
+        * the embedded controller as the type2 models. */
+       sonypi_type2_srs();
+
+       /* Initialization of PCI config space of the LPC interface bridge. */
+       v16 = (sonypi_device.ioport1 & 0xFFF0) | 0x01;
+       pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, v16);
+       pci_read_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, &v8);
+       v8 = (v8 & 0xCF) | 0x10;
+       pci_write_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, v8);
+}
+
 /* Disables the device - this comes from the AML code in the ACPI bios */
 static void sonypi_type1_dis(void)
 {
@@ -587,6 +632,13 @@ static void sonypi_type2_dis(void)
                printk(KERN_WARNING "ec_write failed\n");
 }
 
+static void sonypi_type3_dis(void)
+{
+       sonypi_type2_dis();
+       udelay(10);
+       pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, 0);
+}
+
 static u8 sonypi_call1(u8 dev)
 {
        u8 v1, v2;
@@ -1067,10 +1119,17 @@ static struct miscdevice sonypi_misc_device = {
 
 static void sonypi_enable(unsigned int camera_on)
 {
-       if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
-               sonypi_type2_srs();
-       else
+       switch (sonypi_device.model) {
+       case SONYPI_DEVICE_MODEL_TYPE1:
                sonypi_type1_srs();
+               break;
+       case SONYPI_DEVICE_MODEL_TYPE2:
+               sonypi_type2_srs();
+               break;
+       case SONYPI_DEVICE_MODEL_TYPE3:
+               sonypi_type3_srs();
+               break;
+       }
 
        sonypi_call1(0x82);
        sonypi_call2(0x81, 0xff);
@@ -1094,10 +1153,18 @@ static int sonypi_disable(void)
        if (!SONYPI_ACPI_ACTIVE && fnkeyinit)
                outb(0xf1, 0xb2);
 
-       if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
-               sonypi_type2_dis();
-       else
+       switch (sonypi_device.model) {
+       case SONYPI_DEVICE_MODEL_TYPE1:
                sonypi_type1_dis();
+               break;
+       case SONYPI_DEVICE_MODEL_TYPE2:
+               sonypi_type2_dis();
+               break;
+       case SONYPI_DEVICE_MODEL_TYPE3:
+               sonypi_type3_dis();
+               break;
+       }
+
        return 0;
 }
 
@@ -1143,12 +1210,16 @@ static int __devinit sonypi_probe(void)
        struct sonypi_irq_list *irq_list;
        struct pci_dev *pcidev;
 
-       pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                               PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
+       if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                    PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
+               sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1;
+       else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                         PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
+               sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
+       else
+               sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
 
        sonypi_device.dev = pcidev;
-       sonypi_device.model = pcidev ?
-               SONYPI_DEVICE_MODEL_TYPE1 : SONYPI_DEVICE_MODEL_TYPE2;
 
        spin_lock_init(&sonypi_device.fifo_lock);
        sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
@@ -1176,16 +1247,22 @@ static int __devinit sonypi_probe(void)
                goto out_miscreg;
        }
 
-       if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
+
+       if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) {
+               ioport_list = sonypi_type1_ioport_list;
+               sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE;
+               sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET;
+               irq_list = sonypi_type1_irq_list;
+       } else if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
                ioport_list = sonypi_type2_ioport_list;
                sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE;
                sonypi_device.evtype_offset = SONYPI_TYPE2_EVTYPE_OFFSET;
                irq_list = sonypi_type2_irq_list;
        } else {
-               ioport_list = sonypi_type1_ioport_list;
-               sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE;
-               sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET;
-               irq_list = sonypi_type1_irq_list;
+               ioport_list = sonypi_type3_ioport_list;
+               sonypi_device.region_size = SONYPI_TYPE3_REGION_SIZE;
+               sonypi_device.evtype_offset = SONYPI_TYPE3_EVTYPE_OFFSET;
+               irq_list = sonypi_type3_irq_list;
        }
 
        for (i = 0; ioport_list[i].port1; i++) {
@@ -1274,11 +1351,10 @@ static int __devinit sonypi_probe(void)
 
        printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver"
               "v%s.\n", SONYPI_DRIVER_VERSION);
-       printk(KERN_INFO "sonypi: detected %s model, "
+       printk(KERN_INFO "sonypi: detected type%d model, "
               "verbose = %d, fnkeyinit = %s, camera = %s, "
               "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n",
-              (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) ?
-                       "type1" : "type2",
+              sonypi_device.model,
               verbose,
               fnkeyinit ? "on" : "off",
               camera ? "on" : "off",
index cc2cc77fd174c2e825938c5d436aa7e3db2a39ce..c0d64914595fe182fb31bce1d8cc207fb19d66e4 100644 (file)
@@ -206,6 +206,9 @@ static struct pci_device_id tpm_pci_tbl[] __devinitdata = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)},
        {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
        {PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)},
        {0,}
index dc8c540391fdc690f2f30c0a69a6f586794d4c86..939e51e119e62bb63665afbf4591887861e5ea33 100644 (file)
@@ -14,7 +14,6 @@
  * License.
  */
 
-#include <acpi/acpi_bus.h>
 #include <linux/pnp.h>
 #include "tpm.h"
 
 #define        TPM_MAX_TRIES           5000
 #define        TPM_INFINEON_DEV_VEN_VALUE      0x15D1
 
-/* These values will be filled after ACPI-call */
+/* These values will be filled after PnP-call */
 static int TPM_INF_DATA = 0;
 static int TPM_INF_ADDR = 0;
+static int pnp_registered = 0;
 
 /* TPM header definitions */
 enum infineon_tpm_header {
@@ -356,24 +356,26 @@ static const struct pnp_device_id tpm_pnp_tbl[] = {
        {"IFX0102", 0},
        {"", 0}
 };
+MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
 
-static int __devinit tpm_inf_acpi_probe(struct pnp_dev *dev,
+static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
                                        const struct pnp_device_id *dev_id)
 {
-       TPM_INF_ADDR = (pnp_port_start(dev, 0) & 0xff);
-       TPM_INF_DATA = ((TPM_INF_ADDR + 1) & 0xff);
-       tpm_inf.base = pnp_port_start(dev, 1);
-       dev_info(&dev->dev, "Found %s with ID %s\n",
-                dev->name, dev_id->id);
-       if (!((tpm_inf.base >> 8) & 0xff))
-               tpm_inf.base = 0;
-       return 0;
+       if (pnp_port_valid(dev, 0)) {
+               TPM_INF_ADDR = (pnp_port_start(dev, 0) & 0xff);
+               TPM_INF_DATA = ((TPM_INF_ADDR + 1) & 0xff);
+               tpm_inf.base = pnp_port_start(dev, 1);
+               dev_info(&dev->dev, "Found %s with ID %s\n",
+               dev->name, dev_id->id);
+               return 0;
+       }
+       return -ENODEV;
 }
 
 static struct pnp_driver tpm_inf_pnp = {
        .name = "tpm_inf_pnp",
        .id_table = tpm_pnp_tbl,
-       .probe = tpm_inf_acpi_probe,
+       .probe = tpm_inf_pnp_probe,
 };
 
 static int __devinit tpm_inf_probe(struct pci_dev *pci_dev,
@@ -386,19 +388,30 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev,
        int productid[2];
        char chipname[20];
 
-       if (pci_enable_device(pci_dev))
-               return -EIO;
+       rc = pci_enable_device(pci_dev);
+       if (rc)
+               return rc;
 
        dev_info(&pci_dev->dev, "LPC-bus found at 0x%x\n", pci_id->device);
 
-       /* read IO-ports from ACPI */
-       pnp_register_driver(&tpm_inf_pnp);
-       pnp_unregister_driver(&tpm_inf_pnp);
+       /* read IO-ports from PnP */
+       rc = pnp_register_driver(&tpm_inf_pnp);
+       if (rc < 0) {
+               dev_err(&pci_dev->dev,
+                       "Error %x from pnp_register_driver!\n",rc);
+               goto error2;
+       }
+       if (!rc) {
+               dev_info(&pci_dev->dev, "No Infineon TPM found!\n");
+               goto error;
+       } else {
+               pnp_registered = 1;
+       }
 
        /* Make sure, we have received valid config ports */
        if (!TPM_INF_ADDR) {
-               pci_disable_device(pci_dev);
-               return -EIO;
+               dev_err(&pci_dev->dev, "No valid IO-ports received!\n");
+               goto error;
        }
 
        /* query chip for its vendor, its version number a.s.o. */
@@ -418,23 +431,21 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev,
 
        switch ((productid[0] << 8) | productid[1]) {
        case 6:
-               sprintf(chipname, " (SLD 9630 TT 1.1)");
+               snprintf(chipname, sizeof(chipname), " (SLD 9630 TT 1.1)");
                break;
        case 11:
-               sprintf(chipname, " (SLB 9635 TT 1.2)");
+               snprintf(chipname, sizeof(chipname), " (SLB 9635 TT 1.2)");
                break;
        default:
-               sprintf(chipname, " (unknown chip)");
+               snprintf(chipname, sizeof(chipname), " (unknown chip)");
                break;
        }
-       chipname[19] = 0;
 
        if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) {
 
                if (tpm_inf.base == 0) {
                        dev_err(&pci_dev->dev, "No IO-ports found!\n");
-                       pci_disable_device(pci_dev);
-                       return -EIO;
+                       goto error;
                }
                /* configure TPM with IO-ports */
                outb(IOLIMH, TPM_INF_ADDR);
@@ -452,8 +463,7 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev,
                        dev_err(&pci_dev->dev,
                                "Could not set IO-ports to %04x\n",
                                tpm_inf.base);
-                       pci_disable_device(pci_dev);
-                       return -EIO;
+                       goto error;
                }
 
                /* activate register */
@@ -479,14 +489,16 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev,
                         productid[0], productid[1], chipname);
 
                rc = tpm_register_hardware(pci_dev, &tpm_inf);
-               if (rc < 0) {
-                       pci_disable_device(pci_dev);
-                       return -ENODEV;
-               }
+               if (rc < 0)
+                       goto error;
                return 0;
        } else {
                dev_info(&pci_dev->dev, "No Infineon TPM found!\n");
+error:
+               pnp_unregister_driver(&tpm_inf_pnp);
+error2:
                pci_disable_device(pci_dev);
+               pnp_registered = 0;
                return -ENODEV;
        }
 }
@@ -521,6 +533,8 @@ static int __init init_inf(void)
 
 static void __exit cleanup_inf(void)
 {
+       if (pnp_registered)
+               pnp_unregister_driver(&tpm_inf_pnp);
        pci_unregister_driver(&inf_pci_driver);
 }
 
index 6e4be3bb2d89d56b95792bf98e08bb3d201cc3ae..9d657127f313f21e653b0dd7b49fc539a66a0501 100644 (file)
@@ -153,7 +153,6 @@ static int tty_release(struct inode *, struct file *);
 int tty_ioctl(struct inode * inode, struct file * file,
              unsigned int cmd, unsigned long arg);
 static int tty_fasync(int fd, struct file * filp, int on);
-extern void rs_360_init(void);
 static void release_mem(struct tty_struct *tty, int idx);
 
 
@@ -2910,11 +2909,6 @@ void __init console_init(void)
         */
 #ifdef CONFIG_EARLY_PRINTK
        disable_early_printk();
-#endif
-#ifdef CONFIG_SERIAL_68360
-       /* This is not a console initcall. I know not what it's doing here.
-          So I haven't moved it. dwmw2 */
-        rs_360_init();
 #endif
        call = __con_initcall_start;
        while (call < __con_initcall_end) {
index 4764b4f9555de93de3ec0e945a7089a4e5dbf537..0aff45fac2e6c9f52fc3390bdf29b913f01b8f03 100644 (file)
@@ -991,7 +991,7 @@ static int viotape_remove(struct vio_dev *vdev)
  */
 static struct vio_device_id viotape_device_table[] __devinitdata = {
        { "viotape", "" },
-       { 0, }
+       { "", "" }
 };
 
 MODULE_DEVICE_TABLE(vio, viotape_device_table);
index 665103ccaee83b69b6ca30a7fda0f40eec8983f7..b8d0c290b0dbf137152a03d3a992ad07e308738a 100644 (file)
@@ -434,21 +434,25 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
 /* used by selection: complement pointer position */
 void complement_pos(struct vc_data *vc, int offset)
 {
-       static unsigned short *p;
+       static int old_offset = -1;
        static unsigned short old;
        static unsigned short oldx, oldy;
 
        WARN_CONSOLE_UNLOCKED();
 
-       if (p) {
-               scr_writew(old, p);
+       if (old_offset != -1 && old_offset >= 0 &&
+           old_offset < vc->vc_screenbuf_size) {
+               scr_writew(old, screenpos(vc, old_offset, 1));
                if (DO_UPDATE(vc))
                        vc->vc_sw->con_putc(vc, old, oldy, oldx);
        }
-       if (offset == -1)
-               p = NULL;
-       else {
+
+       old_offset = offset;
+
+       if (offset != -1 && offset >= 0 &&
+           offset < vc->vc_screenbuf_size) {
                unsigned short new;
+               unsigned short *p;
                p = screenpos(vc, offset, 1);
                old = scr_readw(p);
                new = old ^ vc->vc_complement_mask;
@@ -459,6 +463,7 @@ void complement_pos(struct vc_data *vc, int offset)
                        vc->vc_sw->con_putc(vc, new, oldy, oldx);
                }
        }
+
 }
 
 static void insert_char(struct vc_data *vc, unsigned int nr)
@@ -2272,7 +2277,9 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
                        ret = paste_selection(tty);
                        break;
                case TIOCL_UNBLANKSCREEN:
+                       acquire_console_sem();
                        unblank_screen();
+                       release_console_sem();
                        break;
                case TIOCL_SELLOADLUT:
                        ret = sel_loadlut(p);
@@ -2317,8 +2324,10 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
                        }
                        break;
                case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */
+                       acquire_console_sem();
                        ignore_poke = 1;
                        do_blank_screen(0);
+                       release_console_sem();
                        break;
                case TIOCL_BLANKEDSCREEN:
                        ret = console_blanked;
index b53e2e2b5aee93f3dcd03b362b51652b75a78c03..c3898afce3aed341e06e56a7d03b0425f27296b4 100644 (file)
@@ -346,6 +346,13 @@ config 8xx_WDT
        tristate "MPC8xx Watchdog Timer"
        depends on WATCHDOG && 8xx
 
+config BOOKE_WDT
+       tristate "PowerPC Book-E Watchdog Timer"
+       depends on WATCHDOG && (BOOKE || 4xx)
+       ---help---
+         Please see Documentation/watchdog/watchdog-api.txt for
+         more information.
+
 # MIPS Architecture
 
 config INDYDOG
index c1838834ea7f0ac5ea147a724d985853a535ce49..cfeac6f10137e5fc30862d8f287a53d3c084e73a 100644 (file)
@@ -2,42 +2,68 @@
 # Makefile for the WatchDog device drivers.
 #
 
+# Only one watchdog can succeed. We probe the ISA/PCI/USB based
+# watchdog-cards first, then the architecture specific watchdog
+# drivers and then the architecture independant "softdog" driver.
+# This means that if your ISA/PCI/USB card isn't detected that
+# you can fall back to an architecture specific driver and if
+# that also fails then you can fall back to the software watchdog
+# to give you some cover.
+
+# ISA-based Watchdog Cards
 obj-$(CONFIG_PCWATCHDOG) += pcwd.o
-obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
-obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
-obj-$(CONFIG_IB700_WDT) += ib700wdt.o
 obj-$(CONFIG_MIXCOMWD) += mixcomwd.o
-obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
-obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
 obj-$(CONFIG_WDT) += wdt.o
+
+# PCI-based Watchdog Cards
+obj-$(CONFIG_PCIPCWATCHDOG) += pcwd_pci.o
 obj-$(CONFIG_WDTPCI) += wdt_pci.o
+
+# USB-based Watchdog Cards
+obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
+
+# ARM Architecture
 obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
 obj-$(CONFIG_977_WATCHDOG) += wdt977.o
-obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o
-obj-$(CONFIG_MACHZ_WDT) += machzwd.o
-obj-$(CONFIG_SH_WDT) += shwdt.o
+obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
+obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
 obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
 obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
-obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
-obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
-obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
-obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
-obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
+
+# X86 (i386 + ia64 + x86_64) Architecture
+obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
+obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
 obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o
-obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
+obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
+obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
+obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
+obj-$(CONFIG_IB700_WDT) += ib700wdt.o
 obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
+obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o
+obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
+obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
+obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
 obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
-obj-$(CONFIG_INDYDOG) += indydog.o
-obj-$(CONFIG_PCIPCWATCHDOG) += pcwd_pci.o
-obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
-obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
-obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
+obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
+obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
+obj-$(CONFIG_MACHZ_WDT) += machzwd.o
+
+# PowerPC Architecture
 obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
+
+# PPC64 Architecture
 obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
+obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
+
+# MIPS Architecture
+obj-$(CONFIG_INDYDOG) += indydog.o
+
+# S390 Architecture
+
+# SUPERH Architecture
+obj-$(CONFIG_SH_WDT) += shwdt.o
 
-# Only one watchdog can succeed. We probe the hardware watchdog
-# drivers first, then the softdog driver.  This means if your hardware
-# watchdog dies or is 'borrowed' for some reason the software watchdog
-# still gives you some cover.
+# SPARC64 Architecture
 
+# Architecture Independant
 obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c
new file mode 100644 (file)
index 0000000..abc30cc
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * drivers/char/watchdog/booke_wdt.c
+ *
+ * Watchdog timer for PowerPC Book-E systems
+ *
+ * Author: Matthew McClintock
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2005 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/notifier.h>
+#include <linux/watchdog.h>
+
+#include <asm/reg_booke.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+/* If the kernel parameter wdt_enable=1, the watchdog will be enabled at boot.
+ * Also, the wdt_period sets the watchdog timer period timeout.
+ * For E500 cpus the wdt_period sets which bit changing from 0->1 will
+ * trigger a watchog timeout. This watchdog timeout will occur 3 times, the
+ * first time nothing will happen, the second time a watchdog exception will
+ * occur, and the final time the board will reset.
+ */
+
+#ifdef CONFIG_FSL_BOOKE
+#define WDT_PERIOD_DEFAULT 63  /* Ex. wdt_period=28 bus=333Mhz , reset=~40sec */
+#else
+#define WDT_PERIOD_DEFAULT 4   /* Refer to the PPC40x and PPC4xx manuals */
+#endif                         /* for timing information */
+
+u32 booke_wdt_enabled = 0;
+u32 booke_wdt_period = WDT_PERIOD_DEFAULT;
+
+#ifdef CONFIG_FSL_BOOKE
+#define WDTP(x)                ((((63-x)&0x3)<<30)|(((63-x)&0x3c)<<15))
+#else
+#define WDTP(x)                (TCR_WP(x))
+#endif
+
+/*
+ * booke_wdt_enable:
+ */
+static __inline__ void booke_wdt_enable(void)
+{
+       u32 val;
+
+       val = mfspr(SPRN_TCR);
+       val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period));
+
+       mtspr(SPRN_TCR, val);
+}
+
+/*
+ * booke_wdt_ping:
+ */
+static __inline__ void booke_wdt_ping(void)
+{
+       mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
+}
+
+/*
+ * booke_wdt_write:
+ */
+static ssize_t booke_wdt_write (struct file *file, const char *buf,
+                               size_t count, loff_t *ppos)
+{
+       booke_wdt_ping();
+       return count;
+}
+
+static struct watchdog_info ident = {
+  .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+  .firmware_version = 0,
+  .identity = "PowerPC Book-E Watchdog",
+};
+
+/*
+ * booke_wdt_ioctl:
+ */
+static int booke_wdt_ioctl (struct inode *inode, struct file *file,
+                           unsigned int cmd, unsigned long arg)
+{
+       u32 tmp = 0;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               if (copy_to_user ((struct watchdog_info *) arg, &ident,
+                               sizeof(struct watchdog_info)))
+                       return -EFAULT;
+       case WDIOC_GETSTATUS:
+               return put_user(ident.options, (u32 *) arg);
+       case WDIOC_GETBOOTSTATUS:
+               /* XXX: something is clearing TSR */
+               tmp = mfspr(SPRN_TSR) & TSR_WRS(3);
+               /* returns 1 if last reset was caused by the WDT */
+               return (tmp ? 1 : 0);
+       case WDIOC_KEEPALIVE:
+               booke_wdt_ping();
+               return 0;
+       case WDIOC_SETTIMEOUT:
+               if (get_user(booke_wdt_period, (u32 *) arg))
+                       return -EFAULT;
+               mtspr(SPRN_TCR, (mfspr(SPRN_TCR)&~WDTP(0))|WDTP(booke_wdt_period));
+               return 0;
+       case WDIOC_GETTIMEOUT:
+               return put_user(booke_wdt_period, (u32 *) arg);
+       case WDIOC_SETOPTIONS:
+               if (get_user(tmp, (u32 *) arg))
+                       return -EINVAL;
+               if (tmp == WDIOS_ENABLECARD) {
+                       booke_wdt_ping();
+                       break;
+               } else
+                       return -EINVAL;
+               return 0;
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       return 0;
+}
+/*
+ * booke_wdt_open:
+ */
+static int booke_wdt_open (struct inode *inode, struct file *file)
+{
+       if (booke_wdt_enabled == 0) {
+               booke_wdt_enabled = 1;
+               booke_wdt_enable();
+               printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
+                               booke_wdt_period);
+       }
+
+       return 0;
+}
+
+static struct file_operations booke_wdt_fops = {
+  .owner = THIS_MODULE,
+  .llseek = no_llseek,
+  .write = booke_wdt_write,
+  .ioctl = booke_wdt_ioctl,
+  .open = booke_wdt_open,
+};
+
+static struct miscdevice booke_wdt_miscdev = {
+  .minor = WATCHDOG_MINOR,
+  .name = "watchdog",
+  .fops = &booke_wdt_fops,
+};
+
+static void __exit booke_wdt_exit(void)
+{
+       misc_deregister(&booke_wdt_miscdev);
+}
+
+/*
+ * booke_wdt_init:
+ */
+static int __init booke_wdt_init(void)
+{
+       int ret = 0;
+
+       printk (KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n");
+       ident.firmware_version = cpu_specs[0].pvr_value;
+
+       ret = misc_register(&booke_wdt_miscdev);
+       if (ret) {
+               printk (KERN_CRIT "Cannot register miscdev on minor=%d (err=%d)\n",
+                               WATCHDOG_MINOR, ret);
+               return ret;
+       }
+
+       if (booke_wdt_enabled == 1) {
+               printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
+                               booke_wdt_period);
+               booke_wdt_enable();
+       }
+
+       return ret;
+}
+device_initcall(booke_wdt_init);
index e7640bc4904b3fb869f75f770027edcdd9022ba9..0cfb9b9c4a4b2c47634cf329640b89651a6802ad 100644 (file)
@@ -182,7 +182,7 @@ static struct file_operations ixp2000_wdt_fops =
 static struct miscdevice ixp2000_wdt_miscdev =
 {
        .minor          = WATCHDOG_MINOR,
-       .name           = "IXP2000 Watchdog",
+       .name           = "watchdog",
        .fops           = &ixp2000_wdt_fops,
 };
 
index 8d916afbf4facdab59621fa874195bbaf4c4bacd..b5be8b11104af45e10c8f2f998de50706f1c5f25 100644 (file)
@@ -176,7 +176,7 @@ static struct file_operations ixp4xx_wdt_fops =
 static struct miscdevice ixp4xx_wdt_miscdev =
 {
        .minor          = WATCHDOG_MINOR,
-       .name           = "IXP4xx Watchdog",
+       .name           = "watchdog",
        .fops           = &ixp4xx_wdt_fops,
 };
 
index f85ac898a49aa7632cf06a5182acbbc1bb742a2f..8b292bf343c4169d57ee694fbc14f38d9c659695 100644 (file)
  *                             Fixed tmr_count / wdt_count confusion
  *                             Added configurable debug
  *
- *     11-Jan-2004     BJD     Fixed divide-by-2 in timeout code
+ *     11-Jan-2005     BJD     Fixed divide-by-2 in timeout code
+ *
+ *     25-Jan-2005     DA      Added suspend/resume support
+ *                             Replaced reboot notifier with .shutdown method
  *
  *     10-Mar-2005     LCVR    Changed S3C2410_VA to S3C24XX_VA
 */
@@ -40,8 +43,6 @@
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/fs.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
@@ -317,20 +318,6 @@ static int s3c2410wdt_ioctl(struct inode *inode, struct file *file,
        }
 }
 
-/*
- *     Notifier for system down
- */
-
-static int s3c2410wdt_notify_sys(struct notifier_block *this, unsigned long code,
-                             void *unused)
-{
-       if(code==SYS_DOWN || code==SYS_HALT) {
-               /* Turn the WDT off */
-               s3c2410wdt_stop();
-       }
-       return NOTIFY_DONE;
-}
-
 /* kernel interface */
 
 static struct file_operations s3c2410wdt_fops = {
@@ -348,10 +335,6 @@ static struct miscdevice s3c2410wdt_miscdev = {
        .fops           = &s3c2410wdt_fops,
 };
 
-static struct notifier_block s3c2410wdt_notifier = {
-       .notifier_call  = s3c2410wdt_notify_sys,
-};
-
 /* interrupt handler code */
 
 static irqreturn_t s3c2410wdt_irq(int irqno, void *param,
@@ -432,18 +415,10 @@ static int s3c2410wdt_probe(struct device *dev)
                }
        }
 
-       ret = register_reboot_notifier(&s3c2410wdt_notifier);
-       if (ret) {
-               printk (KERN_ERR PFX "cannot register reboot notifier (%d)\n",
-                       ret);
-               return ret;
-       }
-
        ret = misc_register(&s3c2410wdt_miscdev);
        if (ret) {
                printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n",
                        WATCHDOG_MINOR, ret);
-               unregister_reboot_notifier(&s3c2410wdt_notifier);
                return ret;
        }
 
@@ -479,15 +454,63 @@ static int s3c2410wdt_remove(struct device *dev)
        return 0;
 }
 
+static void s3c2410wdt_shutdown(struct device *dev)
+{
+       s3c2410wdt_stop();      
+}
+
+#ifdef CONFIG_PM
+
+static unsigned long wtcon_save;
+static unsigned long wtdat_save;
+
+static int s3c2410wdt_suspend(struct device *dev, u32 state, u32 level)
+{
+       if (level == SUSPEND_POWER_DOWN) {
+               /* Save watchdog state, and turn it off. */
+               wtcon_save = readl(wdt_base + S3C2410_WTCON);
+               wtdat_save = readl(wdt_base + S3C2410_WTDAT);
+
+               /* Note that WTCNT doesn't need to be saved. */
+               s3c2410wdt_stop();
+       }
+
+       return 0;
+}
+
+static int s3c2410wdt_resume(struct device *dev, u32 level)
+{
+       if (level == RESUME_POWER_ON) {
+               /* Restore watchdog state. */
+
+               writel(wtdat_save, wdt_base + S3C2410_WTDAT);
+               writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */
+               writel(wtcon_save, wdt_base + S3C2410_WTCON);
+
+               printk(KERN_INFO PFX "watchdog %sabled\n",
+                      (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
+       }
+
+       return 0;
+}
+
+#else
+#define s3c2410wdt_suspend NULL
+#define s3c2410wdt_resume  NULL
+#endif /* CONFIG_PM */
+
+
 static struct device_driver s3c2410wdt_driver = {
        .name           = "s3c2410-wdt",
        .bus            = &platform_bus_type,
        .probe          = s3c2410wdt_probe,
        .remove         = s3c2410wdt_remove,
+       .shutdown       = s3c2410wdt_shutdown,
+       .suspend        = s3c2410wdt_suspend,
+       .resume         = s3c2410wdt_resume,
 };
 
 
-
 static char banner[] __initdata = KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n";
 
 static int __init watchdog_init(void)
@@ -499,13 +522,13 @@ static int __init watchdog_init(void)
 static void __exit watchdog_exit(void)
 {
        driver_unregister(&s3c2410wdt_driver);
-       unregister_reboot_notifier(&s3c2410wdt_notifier);
 }
 
 module_init(watchdog_init);
 module_exit(watchdog_exit);
 
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, "
+             "Dimitry Andric <dimitry.andric@tomtom.com>");
 MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index c4568569f3a8cf9fe3561c80881ba99580563dc4..b4a102a2d7e390cfa3774d0a6c7871756e6b11ec 100644 (file)
@@ -206,7 +206,7 @@ static struct file_operations scx200_wdt_fops = {
 
 static struct miscdevice scx200_wdt_miscdev = {
        .minor = WATCHDOG_MINOR,
-       .name  = NAME,
+       .name  = "watchdog",
        .fops  = &scx200_wdt_fops,
 };
 
index 4d7ed931f5c6c918f738eea02caee70acfd4b493..20e5eb8667f2a738d9bbb16031cf0e6a4dc22733 100644 (file)
@@ -77,7 +77,7 @@ static void watchdog_fire(unsigned long);
 
 static struct timer_list watchdog_ticktock =
                TIMER_INITIALIZER(watchdog_fire, 0, 0);
-static unsigned long timer_alive;
+static unsigned long driver_open, orphan_timer;
 static char expect_close;
 
 
@@ -87,6 +87,9 @@ static char expect_close;
 
 static void watchdog_fire(unsigned long data)
 {
+       if (test_and_clear_bit(0, &orphan_timer))
+               module_put(THIS_MODULE);
+
        if (soft_noboot)
                printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n");
        else
@@ -128,9 +131,9 @@ static int softdog_set_heartbeat(int t)
 
 static int softdog_open(struct inode *inode, struct file *file)
 {
-       if(test_and_set_bit(0, &timer_alive))
+       if (test_and_set_bit(0, &driver_open))
                return -EBUSY;
-       if (nowayout)
+       if (!test_and_clear_bit(0, &orphan_timer))
                __module_get(THIS_MODULE);
        /*
         *      Activate timer
@@ -147,11 +150,13 @@ static int softdog_release(struct inode *inode, struct file *file)
         */
        if (expect_close == 42) {
                softdog_stop();
+               module_put(THIS_MODULE);
        } else {
                printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+               set_bit(0, &orphan_timer);
                softdog_keepalive();
        }
-       clear_bit(0, &timer_alive);
+       clear_bit(0, &driver_open);
        expect_close = 0;
        return 0;
 }
index 465e0fd0423d48b2c405836ac428a14af8c37a09..b5d8210154216bec46da66ae16ede0793746010f 100644 (file)
@@ -93,6 +93,12 @@ w83627hf_init(void)
 
        w83627hf_select_wd_register();
 
+       outb_p(0xF6, WDT_EFER); /* Select CRF6 */
+       t=inb_p(WDT_EFDR);      /* read CRF6 */
+       if (t != 0) {
+               printk (KERN_INFO PFX "Watchdog already running. Resetting timeout to %d sec\n", timeout);
+               outb_p(timeout, WDT_EFDR);    /* Write back to CRF6 */
+       }
        outb_p(0xF5, WDT_EFER); /* Select CRF5 */
        t=inb_p(WDT_EFDR);      /* read CRF5 */
        t&=~0x0C;               /* set second mode & disable keyboard turning off watchdog */
index 5b29c3b2a331bd28fb34a31d18bea4d2abf6d4ad..327b58e648753013e28026f4fb9f66f4af89edfe 100644 (file)
@@ -58,4 +58,31 @@ config EFI_PCDP
 
          See <http://www.dig64.org/specifications/DIG64_HCDPv20_042804.pdf>
 
+config DELL_RBU
+       tristate "BIOS update support for DELL systems via sysfs"
+       select FW_LOADER
+       help
+        Say m if you want to have the option of updating the BIOS for your
+        DELL system. Note you need a Dell OpenManage or Dell Update package (DUP)
+        supporting application to comunicate with the BIOS regarding the new
+        image for the image update to take effect.
+        See <file:Documentation/dell_rbu.txt> for more details on the driver.
+
+config DCDBAS
+       tristate "Dell Systems Management Base Driver"
+       depends on X86 || X86_64
+       default m
+       help
+         The Dell Systems Management Base Driver provides a sysfs interface
+         for systems management software to perform System Management
+         Interrupts (SMIs) and Host Control Actions (system power cycle or
+         power off after OS shutdown) on certain Dell systems.
+
+         See <file:Documentation/dcdbas.txt> for more details on the driver
+         and the Dell systems on which Dell systems management software makes
+         use of this driver.
+
+         Say Y or M here to enable the driver for use by Dell systems
+         management software such as Dell OpenManage.
+
 endmenu
index 90fd0b26db8b0d667b7ac1b9c9c347b1eb3fed74..85429979d0db2a27021a34c5d8199b1dd47754c1 100644 (file)
@@ -4,3 +4,5 @@
 obj-$(CONFIG_EDD)              += edd.o
 obj-$(CONFIG_EFI_VARS)         += efivars.o
 obj-$(CONFIG_EFI_PCDP)         += pcdp.o
+obj-$(CONFIG_DELL_RBU)          += dell_rbu.o
+obj-$(CONFIG_DCDBAS)           += dcdbas.o
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
new file mode 100644 (file)
index 0000000..955537f
--- /dev/null
@@ -0,0 +1,596 @@
+/*
+ *  dcdbas.c: Dell Systems Management Base Driver
+ *
+ *  The Dell Systems Management Base Driver provides a sysfs interface for
+ *  systems management software to perform System Management Interrupts (SMIs)
+ *  and Host Control Actions (power cycle or power off after OS shutdown) on
+ *  Dell systems.
+ *
+ *  See Documentation/dcdbas.txt for more information.
+ *
+ *  Copyright (C) 1995-2005 Dell Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License v2.0 as published by
+ *  the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mc146818rtc.h>
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+
+#include "dcdbas.h"
+
+#define DRIVER_NAME            "dcdbas"
+#define DRIVER_VERSION         "5.6.0-1"
+#define DRIVER_DESCRIPTION     "Dell Systems Management Base Driver"
+
+static struct platform_device *dcdbas_pdev;
+
+static u8 *smi_data_buf;
+static dma_addr_t smi_data_buf_handle;
+static unsigned long smi_data_buf_size;
+static u32 smi_data_buf_phys_addr;
+static DECLARE_MUTEX(smi_data_lock);
+
+static unsigned int host_control_action;
+static unsigned int host_control_smi_type;
+static unsigned int host_control_on_shutdown;
+
+/**
+ * smi_data_buf_free: free SMI data buffer
+ */
+static void smi_data_buf_free(void)
+{
+       if (!smi_data_buf)
+               return;
+
+       dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n",
+               __FUNCTION__, smi_data_buf_phys_addr, smi_data_buf_size);
+
+       dma_free_coherent(&dcdbas_pdev->dev, smi_data_buf_size, smi_data_buf,
+                         smi_data_buf_handle);
+       smi_data_buf = NULL;
+       smi_data_buf_handle = 0;
+       smi_data_buf_phys_addr = 0;
+       smi_data_buf_size = 0;
+}
+
+/**
+ * smi_data_buf_realloc: grow SMI data buffer if needed
+ */
+static int smi_data_buf_realloc(unsigned long size)
+{
+       void *buf;
+       dma_addr_t handle;
+
+       if (smi_data_buf_size >= size)
+               return 0;
+
+       if (size > MAX_SMI_DATA_BUF_SIZE)
+               return -EINVAL;
+
+       /* new buffer is needed */
+       buf = dma_alloc_coherent(&dcdbas_pdev->dev, size, &handle, GFP_KERNEL);
+       if (!buf) {
+               dev_dbg(&dcdbas_pdev->dev,
+                       "%s: failed to allocate memory size %lu\n",
+                       __FUNCTION__, size);
+               return -ENOMEM;
+       }
+       /* memory zeroed by dma_alloc_coherent */
+
+       if (smi_data_buf)
+               memcpy(buf, smi_data_buf, smi_data_buf_size);
+
+       /* free any existing buffer */
+       smi_data_buf_free();
+
+       /* set up new buffer for use */
+       smi_data_buf = buf;
+       smi_data_buf_handle = handle;
+       smi_data_buf_phys_addr = (u32) virt_to_phys(buf);
+       smi_data_buf_size = size;
+
+       dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n",
+               __FUNCTION__, smi_data_buf_phys_addr, smi_data_buf_size);
+
+       return 0;
+}
+
+static ssize_t smi_data_buf_phys_addr_show(struct device *dev,
+                                          struct device_attribute *attr,
+                                          char *buf)
+{
+       return sprintf(buf, "%x\n", smi_data_buf_phys_addr);
+}
+
+static ssize_t smi_data_buf_size_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       return sprintf(buf, "%lu\n", smi_data_buf_size);
+}
+
+static ssize_t smi_data_buf_size_store(struct device *dev,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t count)
+{
+       unsigned long buf_size;
+       ssize_t ret;
+
+       buf_size = simple_strtoul(buf, NULL, 10);
+
+       /* make sure SMI data buffer is at least buf_size */
+       down(&smi_data_lock);
+       ret = smi_data_buf_realloc(buf_size);
+       up(&smi_data_lock);
+       if (ret)
+               return ret;
+
+       return count;
+}
+
+static ssize_t smi_data_read(struct kobject *kobj, char *buf, loff_t pos,
+                            size_t count)
+{
+       size_t max_read;
+       ssize_t ret;
+
+       down(&smi_data_lock);
+
+       if (pos >= smi_data_buf_size) {
+               ret = 0;
+               goto out;
+       }
+
+       max_read = smi_data_buf_size - pos;
+       ret = min(max_read, count);
+       memcpy(buf, smi_data_buf + pos, ret);
+out:
+       up(&smi_data_lock);
+       return ret;
+}
+
+static ssize_t smi_data_write(struct kobject *kobj, char *buf, loff_t pos,
+                             size_t count)
+{
+       ssize_t ret;
+
+       down(&smi_data_lock);
+
+       ret = smi_data_buf_realloc(pos + count);
+       if (ret)
+               goto out;
+
+       memcpy(smi_data_buf + pos, buf, count);
+       ret = count;
+out:
+       up(&smi_data_lock);
+       return ret;
+}
+
+static ssize_t host_control_action_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       return sprintf(buf, "%u\n", host_control_action);
+}
+
+static ssize_t host_control_action_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
+{
+       ssize_t ret;
+
+       /* make sure buffer is available for host control command */
+       down(&smi_data_lock);
+       ret = smi_data_buf_realloc(sizeof(struct apm_cmd));
+       up(&smi_data_lock);
+       if (ret)
+               return ret;
+
+       host_control_action = simple_strtoul(buf, NULL, 10);
+       return count;
+}
+
+static ssize_t host_control_smi_type_show(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
+{
+       return sprintf(buf, "%u\n", host_control_smi_type);
+}
+
+static ssize_t host_control_smi_type_store(struct device *dev,
+                                          struct device_attribute *attr,
+                                          const char *buf, size_t count)
+{
+       host_control_smi_type = simple_strtoul(buf, NULL, 10);
+       return count;
+}
+
+static ssize_t host_control_on_shutdown_show(struct device *dev,
+                                            struct device_attribute *attr,
+                                            char *buf)
+{
+       return sprintf(buf, "%u\n", host_control_on_shutdown);
+}
+
+static ssize_t host_control_on_shutdown_store(struct device *dev,
+                                             struct device_attribute *attr,
+                                             const char *buf, size_t count)
+{
+       host_control_on_shutdown = simple_strtoul(buf, NULL, 10);
+       return count;
+}
+
+/**
+ * smi_request: generate SMI request
+ *
+ * Called with smi_data_lock.
+ */
+static int smi_request(struct smi_cmd *smi_cmd)
+{
+       cpumask_t old_mask;
+       int ret = 0;
+
+       if (smi_cmd->magic != SMI_CMD_MAGIC) {
+               dev_info(&dcdbas_pdev->dev, "%s: invalid magic value\n",
+                        __FUNCTION__);
+               return -EBADR;
+       }
+
+       /* SMI requires CPU 0 */
+       old_mask = current->cpus_allowed;
+       set_cpus_allowed(current, cpumask_of_cpu(0));
+       if (smp_processor_id() != 0) {
+               dev_dbg(&dcdbas_pdev->dev, "%s: failed to get CPU 0\n",
+                       __FUNCTION__);
+               ret = -EBUSY;
+               goto out;
+       }
+
+       /* generate SMI */
+       asm volatile (
+               "outb %b0,%w1"
+               : /* no output args */
+               : "a" (smi_cmd->command_code),
+                 "d" (smi_cmd->command_address),
+                 "b" (smi_cmd->ebx),
+                 "c" (smi_cmd->ecx)
+               : "memory"
+       );
+
+out:
+       set_cpus_allowed(current, old_mask);
+       return ret;
+}
+
+/**
+ * smi_request_store:
+ *
+ * The valid values are:
+ * 0: zero SMI data buffer
+ * 1: generate calling interface SMI
+ * 2: generate raw SMI
+ *
+ * User application writes smi_cmd to smi_data before telling driver
+ * to generate SMI.
+ */
+static ssize_t smi_request_store(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       struct smi_cmd *smi_cmd;
+       unsigned long val = simple_strtoul(buf, NULL, 10);
+       ssize_t ret;
+
+       down(&smi_data_lock);
+
+       if (smi_data_buf_size < sizeof(struct smi_cmd)) {
+               ret = -ENODEV;
+               goto out;
+       }
+       smi_cmd = (struct smi_cmd *)smi_data_buf;
+
+       switch (val) {
+       case 2:
+               /* Raw SMI */
+               ret = smi_request(smi_cmd);
+               if (!ret)
+                       ret = count;
+               break;
+       case 1:
+               /* Calling Interface SMI */
+               smi_cmd->ebx = (u32) virt_to_phys(smi_cmd->command_buffer);
+               ret = smi_request(smi_cmd);
+               if (!ret)
+                       ret = count;
+               break;
+       case 0:
+               memset(smi_data_buf, 0, smi_data_buf_size);
+               ret = count;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+out:
+       up(&smi_data_lock);
+       return ret;
+}
+
+/**
+ * host_control_smi: generate host control SMI
+ *
+ * Caller must set up the host control command in smi_data_buf.
+ */
+static int host_control_smi(void)
+{
+       struct apm_cmd *apm_cmd;
+       u8 *data;
+       unsigned long flags;
+       u32 num_ticks;
+       s8 cmd_status;
+       u8 index;
+
+       apm_cmd = (struct apm_cmd *)smi_data_buf;
+       apm_cmd->status = ESM_STATUS_CMD_UNSUCCESSFUL;
+
+       switch (host_control_smi_type) {
+       case HC_SMITYPE_TYPE1:
+               spin_lock_irqsave(&rtc_lock, flags);
+               /* write SMI data buffer physical address */
+               data = (u8 *)&smi_data_buf_phys_addr;
+               for (index = PE1300_CMOS_CMD_STRUCT_PTR;
+                    index < (PE1300_CMOS_CMD_STRUCT_PTR + 4);
+                    index++, data++) {
+                       outb(index,
+                            (CMOS_BASE_PORT + CMOS_PAGE2_INDEX_PORT_PIIX4));
+                       outb(*data,
+                            (CMOS_BASE_PORT + CMOS_PAGE2_DATA_PORT_PIIX4));
+               }
+
+               /* first set status to -1 as called by spec */
+               cmd_status = ESM_STATUS_CMD_UNSUCCESSFUL;
+               outb((u8) cmd_status, PCAT_APM_STATUS_PORT);
+
+               /* generate SMM call */
+               outb(ESM_APM_CMD, PCAT_APM_CONTROL_PORT);
+               spin_unlock_irqrestore(&rtc_lock, flags);
+
+               /* wait a few to see if it executed */
+               num_ticks = TIMEOUT_USEC_SHORT_SEMA_BLOCKING;
+               while ((cmd_status = inb(PCAT_APM_STATUS_PORT))
+                      == ESM_STATUS_CMD_UNSUCCESSFUL) {
+                       num_ticks--;
+                       if (num_ticks == EXPIRED_TIMER)
+                               return -ETIME;
+               }
+               break;
+
+       case HC_SMITYPE_TYPE2:
+       case HC_SMITYPE_TYPE3:
+               spin_lock_irqsave(&rtc_lock, flags);
+               /* write SMI data buffer physical address */
+               data = (u8 *)&smi_data_buf_phys_addr;
+               for (index = PE1400_CMOS_CMD_STRUCT_PTR;
+                    index < (PE1400_CMOS_CMD_STRUCT_PTR + 4);
+                    index++, data++) {
+                       outb(index, (CMOS_BASE_PORT + CMOS_PAGE1_INDEX_PORT));
+                       outb(*data, (CMOS_BASE_PORT + CMOS_PAGE1_DATA_PORT));
+               }
+
+               /* generate SMM call */
+               if (host_control_smi_type == HC_SMITYPE_TYPE3)
+                       outb(ESM_APM_CMD, PCAT_APM_CONTROL_PORT);
+               else
+                       outb(ESM_APM_CMD, PE1400_APM_CONTROL_PORT);
+
+               /* restore RTC index pointer since it was written to above */
+               CMOS_READ(RTC_REG_C);
+               spin_unlock_irqrestore(&rtc_lock, flags);
+
+               /* read control port back to serialize write */
+               cmd_status = inb(PE1400_APM_CONTROL_PORT);
+
+               /* wait a few to see if it executed */
+               num_ticks = TIMEOUT_USEC_SHORT_SEMA_BLOCKING;
+               while (apm_cmd->status == ESM_STATUS_CMD_UNSUCCESSFUL) {
+                       num_ticks--;
+                       if (num_ticks == EXPIRED_TIMER)
+                               return -ETIME;
+               }
+               break;
+
+       default:
+               dev_dbg(&dcdbas_pdev->dev, "%s: invalid SMI type %u\n",
+                       __FUNCTION__, host_control_smi_type);
+               return -ENOSYS;
+       }
+
+       return 0;
+}
+
+/**
+ * dcdbas_host_control: initiate host control
+ *
+ * This function is called by the driver after the system has
+ * finished shutting down if the user application specified a
+ * host control action to perform on shutdown.  It is safe to
+ * use smi_data_buf at this point because the system has finished
+ * shutting down and no userspace apps are running.
+ */
+static void dcdbas_host_control(void)
+{
+       struct apm_cmd *apm_cmd;
+       u8 action;
+
+       if (host_control_action == HC_ACTION_NONE)
+               return;
+
+       action = host_control_action;
+       host_control_action = HC_ACTION_NONE;
+
+       if (!smi_data_buf) {
+               dev_dbg(&dcdbas_pdev->dev, "%s: no SMI buffer\n", __FUNCTION__);
+               return;
+       }
+
+       if (smi_data_buf_size < sizeof(struct apm_cmd)) {
+               dev_dbg(&dcdbas_pdev->dev, "%s: SMI buffer too small\n",
+                       __FUNCTION__);
+               return;
+       }
+
+       apm_cmd = (struct apm_cmd *)smi_data_buf;
+
+       /* power off takes precedence */
+       if (action & HC_ACTION_HOST_CONTROL_POWEROFF) {
+               apm_cmd->command = ESM_APM_POWER_CYCLE;
+               apm_cmd->reserved = 0;
+               *((s16 *)&apm_cmd->parameters.shortreq.parm[0]) = (s16) 0;
+               host_control_smi();
+       } else if (action & HC_ACTION_HOST_CONTROL_POWERCYCLE) {
+               apm_cmd->command = ESM_APM_POWER_CYCLE;
+               apm_cmd->reserved = 0;
+               *((s16 *)&apm_cmd->parameters.shortreq.parm[0]) = (s16) 20;
+               host_control_smi();
+       }
+}
+
+/**
+ * dcdbas_reboot_notify: handle reboot notification for host control
+ */
+static int dcdbas_reboot_notify(struct notifier_block *nb, unsigned long code,
+                               void *unused)
+{
+       static unsigned int notify_cnt = 0;
+
+       switch (code) {
+       case SYS_DOWN:
+       case SYS_HALT:
+       case SYS_POWER_OFF:
+               if (host_control_on_shutdown) {
+                       /* firmware is going to perform host control action */
+                       if (++notify_cnt == 2) {
+                               printk(KERN_WARNING
+                                      "Please wait for shutdown "
+                                      "action to complete...\n");
+                               dcdbas_host_control();
+                       }
+                       /*
+                        * register again and initiate the host control
+                        * action on the second notification to allow
+                        * everyone that registered to be notified
+                        */
+                       register_reboot_notifier(nb);
+               }
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block dcdbas_reboot_nb = {
+       .notifier_call = dcdbas_reboot_notify,
+       .next = NULL,
+       .priority = 0
+};
+
+static DCDBAS_BIN_ATTR_RW(smi_data);
+
+static struct bin_attribute *dcdbas_bin_attrs[] = {
+       &bin_attr_smi_data,
+       NULL
+};
+
+static DCDBAS_DEV_ATTR_RW(smi_data_buf_size);
+static DCDBAS_DEV_ATTR_RO(smi_data_buf_phys_addr);
+static DCDBAS_DEV_ATTR_WO(smi_request);
+static DCDBAS_DEV_ATTR_RW(host_control_action);
+static DCDBAS_DEV_ATTR_RW(host_control_smi_type);
+static DCDBAS_DEV_ATTR_RW(host_control_on_shutdown);
+
+static struct device_attribute *dcdbas_dev_attrs[] = {
+       &dev_attr_smi_data_buf_size,
+       &dev_attr_smi_data_buf_phys_addr,
+       &dev_attr_smi_request,
+       &dev_attr_host_control_action,
+       &dev_attr_host_control_smi_type,
+       &dev_attr_host_control_on_shutdown,
+       NULL
+};
+
+/**
+ * dcdbas_init: initialize driver
+ */
+static int __init dcdbas_init(void)
+{
+       int i;
+
+       host_control_action = HC_ACTION_NONE;
+       host_control_smi_type = HC_SMITYPE_NONE;
+
+       dcdbas_pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
+       if (IS_ERR(dcdbas_pdev))
+               return PTR_ERR(dcdbas_pdev);
+
+       /*
+        * BIOS SMI calls require buffer addresses be in 32-bit address space.
+        * This is done by setting the DMA mask below.
+        */
+       dcdbas_pdev->dev.coherent_dma_mask = DMA_32BIT_MASK;
+       dcdbas_pdev->dev.dma_mask = &dcdbas_pdev->dev.coherent_dma_mask;
+
+       register_reboot_notifier(&dcdbas_reboot_nb);
+
+       for (i = 0; dcdbas_bin_attrs[i]; i++)
+               sysfs_create_bin_file(&dcdbas_pdev->dev.kobj,
+                                     dcdbas_bin_attrs[i]);
+
+       for (i = 0; dcdbas_dev_attrs[i]; i++)
+               device_create_file(&dcdbas_pdev->dev, dcdbas_dev_attrs[i]);
+
+       dev_info(&dcdbas_pdev->dev, "%s (version %s)\n",
+                DRIVER_DESCRIPTION, DRIVER_VERSION);
+
+       return 0;
+}
+
+/**
+ * dcdbas_exit: perform driver cleanup
+ */
+static void __exit dcdbas_exit(void)
+{
+       platform_device_unregister(dcdbas_pdev);
+       unregister_reboot_notifier(&dcdbas_reboot_nb);
+       smi_data_buf_free();
+}
+
+module_init(dcdbas_init);
+module_exit(dcdbas_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESCRIPTION " (version " DRIVER_VERSION ")");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_AUTHOR("Dell Inc.");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/firmware/dcdbas.h b/drivers/firmware/dcdbas.h
new file mode 100644 (file)
index 0000000..58a8518
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ *  dcdbas.h: Definitions for Dell Systems Management Base driver
+ *
+ *  Copyright (C) 1995-2005 Dell Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License v2.0 as published by
+ *  the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#ifndef _DCDBAS_H_
+#define _DCDBAS_H_
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+#define MAX_SMI_DATA_BUF_SIZE                  (256 * 1024)
+
+#define HC_ACTION_NONE                         (0)
+#define HC_ACTION_HOST_CONTROL_POWEROFF                BIT(1)
+#define HC_ACTION_HOST_CONTROL_POWERCYCLE      BIT(2)
+
+#define HC_SMITYPE_NONE                                (0)
+#define HC_SMITYPE_TYPE1                       (1)
+#define HC_SMITYPE_TYPE2                       (2)
+#define HC_SMITYPE_TYPE3                       (3)
+
+#define ESM_APM_CMD                            (0x0A0)
+#define ESM_APM_POWER_CYCLE                    (0x10)
+#define ESM_STATUS_CMD_UNSUCCESSFUL            (-1)
+
+#define CMOS_BASE_PORT                         (0x070)
+#define CMOS_PAGE1_INDEX_PORT                  (0)
+#define CMOS_PAGE1_DATA_PORT                   (1)
+#define CMOS_PAGE2_INDEX_PORT_PIIX4            (2)
+#define CMOS_PAGE2_DATA_PORT_PIIX4             (3)
+#define PE1400_APM_CONTROL_PORT                        (0x0B0)
+#define PCAT_APM_CONTROL_PORT                  (0x0B2)
+#define PCAT_APM_STATUS_PORT                   (0x0B3)
+#define PE1300_CMOS_CMD_STRUCT_PTR             (0x38)
+#define PE1400_CMOS_CMD_STRUCT_PTR             (0x70)
+
+#define MAX_SYSMGMT_SHORTCMD_PARMBUF_LEN       (14)
+#define MAX_SYSMGMT_LONGCMD_SGENTRY_NUM                (16)
+
+#define TIMEOUT_USEC_SHORT_SEMA_BLOCKING       (10000)
+#define EXPIRED_TIMER                          (0)
+
+#define SMI_CMD_MAGIC                          (0x534D4931)
+
+#define DCDBAS_DEV_ATTR_RW(_name) \
+       DEVICE_ATTR(_name,0600,_name##_show,_name##_store);
+
+#define DCDBAS_DEV_ATTR_RO(_name) \
+       DEVICE_ATTR(_name,0400,_name##_show,NULL);
+
+#define DCDBAS_DEV_ATTR_WO(_name) \
+       DEVICE_ATTR(_name,0200,NULL,_name##_store);
+
+#define DCDBAS_BIN_ATTR_RW(_name) \
+struct bin_attribute bin_attr_##_name = { \
+       .attr =  { .name = __stringify(_name), \
+                  .mode = 0600, \
+                  .owner = THIS_MODULE }, \
+       .read =  _name##_read, \
+       .write = _name##_write, \
+}
+
+struct smi_cmd {
+       __u32 magic;
+       __u32 ebx;
+       __u32 ecx;
+       __u16 command_address;
+       __u8 command_code;
+       __u8 reserved;
+       __u8 command_buffer[1];
+} __attribute__ ((packed));
+
+struct apm_cmd {
+       __u8 command;
+       __s8 status;
+       __u16 reserved;
+       union {
+               struct {
+                       __u8 parm[MAX_SYSMGMT_SHORTCMD_PARMBUF_LEN];
+               } __attribute__ ((packed)) shortreq;
+
+               struct {
+                       __u16 num_sg_entries;
+                       struct {
+                               __u32 size;
+                               __u64 addr;
+                       } __attribute__ ((packed))
+                           sglist[MAX_SYSMGMT_LONGCMD_SGENTRY_NUM];
+               } __attribute__ ((packed)) longreq;
+       } __attribute__ ((packed)) parameters;
+} __attribute__ ((packed));
+
+#endif /* _DCDBAS_H_ */
+
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c
new file mode 100644 (file)
index 0000000..3b865f3
--- /dev/null
@@ -0,0 +1,634 @@
+/*
+ * dell_rbu.c
+ * Bios Update driver for Dell systems
+ * Author: Dell Inc
+ *         Abhay Salunke <abhay_salunke@dell.com>
+ *
+ * Copyright (C) 2005 Dell Inc.
+ *
+ * Remote BIOS Update (rbu) driver is used for updating DELL BIOS by
+ * creating entries in the /sys file systems on Linux 2.6 and higher
+ * kernels. The driver supports two mechanism to update the BIOS namely
+ * contiguous and packetized. Both these methods still require having some
+ * application to set the CMOS bit indicating the BIOS to update itself
+ * after a reboot.
+ *
+ * Contiguous method:
+ * This driver writes the incoming data in a monolithic image by allocating
+ * contiguous physical pages large enough to accommodate the incoming BIOS
+ * image size.
+ *
+ * Packetized method:
+ * The driver writes the incoming packet image by allocating a new packet
+ * on every time the packet data is written. This driver requires an
+ * application to break the BIOS image in to fixed sized packet chunks.
+ *
+ * See Documentation/dell_rbu.txt for more info.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/blkdev.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+
+MODULE_AUTHOR("Abhay Salunke <abhay_salunke@dell.com>");
+MODULE_DESCRIPTION("Driver for updating BIOS image on DELL systems");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+
+#define BIOS_SCAN_LIMIT 0xffffffff
+#define MAX_IMAGE_LENGTH 16
+static struct _rbu_data {
+       void *image_update_buffer;
+       unsigned long image_update_buffer_size;
+       unsigned long bios_image_size;
+       int image_update_ordernum;
+       int dma_alloc;
+       spinlock_t lock;
+       unsigned long packet_read_count;
+       unsigned long packet_write_count;
+       unsigned long num_packets;
+       unsigned long packetsize;
+} rbu_data;
+
+static char image_type[MAX_IMAGE_LENGTH] = "mono";
+module_param_string(image_type, image_type, sizeof(image_type), 0);
+MODULE_PARM_DESC(image_type, "BIOS image type. choose- mono or packet");
+
+struct packet_data {
+       struct list_head list;
+       size_t length;
+       void *data;
+       int ordernum;
+};
+
+static struct packet_data packet_data_head;
+
+static struct platform_device *rbu_device;
+static int context;
+static dma_addr_t dell_rbu_dmaaddr;
+
+static void init_packet_head(void)
+{
+       INIT_LIST_HEAD(&packet_data_head.list);
+       rbu_data.packet_write_count = 0;
+       rbu_data.packet_read_count = 0;
+       rbu_data.num_packets = 0;
+       rbu_data.packetsize = 0;
+}
+
+static int fill_last_packet(void *data, size_t length)
+{
+       struct list_head *ptemp_list;
+       struct packet_data *packet = NULL;
+       int packet_count = 0;
+
+       pr_debug("fill_last_packet: entry \n");
+
+       if (!rbu_data.num_packets) {
+               pr_debug("fill_last_packet: num_packets=0\n");
+               return -ENOMEM;
+       }
+
+       packet_count = rbu_data.num_packets;
+
+       ptemp_list = (&packet_data_head.list)->prev;
+
+       packet = list_entry(ptemp_list, struct packet_data, list);
+
+       if ((rbu_data.packet_write_count + length) > rbu_data.packetsize) {
+               pr_debug("dell_rbu:%s: packet size data "
+                        "overrun\n", __FUNCTION__);
+               return -EINVAL;
+       }
+
+       pr_debug("fill_last_packet : buffer = %p\n", packet->data);
+
+       memcpy((packet->data + rbu_data.packet_write_count), data, length);
+
+       if ((rbu_data.packet_write_count + length) == rbu_data.packetsize) {
+               /*
+                * this was the last data chunk in the packet
+                * so reinitialize the packet data counter to zero
+                */
+               rbu_data.packet_write_count = 0;
+       } else
+               rbu_data.packet_write_count += length;
+
+       pr_debug("fill_last_packet: exit \n");
+       return 0;
+}
+
+static int create_packet(size_t length)
+{
+       struct packet_data *newpacket;
+       int ordernum = 0;
+
+       pr_debug("create_packet: entry \n");
+
+       if (!rbu_data.packetsize) {
+               pr_debug("create_packet: packetsize not specified\n");
+               return -EINVAL;
+       }
+
+       newpacket = kmalloc(sizeof(struct packet_data), GFP_KERNEL);
+       if (!newpacket) {
+               printk(KERN_WARNING
+                      "dell_rbu:%s: failed to allocate new "
+                      "packet\n", __FUNCTION__);
+               return -ENOMEM;
+       }
+
+       ordernum = get_order(length);
+       /*
+        * there is no upper limit on memory
+        * address for packetized mechanism
+        */
+       newpacket->data = (unsigned char *)__get_free_pages(GFP_KERNEL,
+                                                           ordernum);
+
+       pr_debug("create_packet: newpacket %p\n", newpacket->data);
+
+       if (!newpacket->data) {
+               printk(KERN_WARNING
+                      "dell_rbu:%s: failed to allocate new "
+                      "packet\n", __FUNCTION__);
+               kfree(newpacket);
+               return -ENOMEM;
+       }
+
+       newpacket->ordernum = ordernum;
+       ++rbu_data.num_packets;
+       /*
+        * initialize the newly created packet headers
+        */
+       INIT_LIST_HEAD(&newpacket->list);
+       list_add_tail(&newpacket->list, &packet_data_head.list);
+       /*
+        * packets have fixed size
+        */
+       newpacket->length = rbu_data.packetsize;
+
+       pr_debug("create_packet: exit \n");
+
+       return 0;
+}
+
+static int packetize_data(void *data, size_t length)
+{
+       int rc = 0;
+
+       if (!rbu_data.packet_write_count) {
+               if ((rc = create_packet(length)))
+                       return rc;
+       }
+       if ((rc = fill_last_packet(data, length)))
+               return rc;
+
+       return rc;
+}
+
+static int
+do_packet_read(char *data, struct list_head *ptemp_list,
+              int length, int bytes_read, int *list_read_count)
+{
+       void *ptemp_buf;
+       struct packet_data *newpacket = NULL;
+       int bytes_copied = 0;
+       int j = 0;
+
+       newpacket = list_entry(ptemp_list, struct packet_data, list);
+       *list_read_count += newpacket->length;
+
+       if (*list_read_count > bytes_read) {
+               /* point to the start of unread data */
+               j = newpacket->length - (*list_read_count - bytes_read);
+               /* point to the offset in the packet buffer */
+               ptemp_buf = (u8 *) newpacket->data + j;
+               /*
+                * check if there is enough room in
+                * * the incoming buffer
+                */
+               if (length > (*list_read_count - bytes_read))
+                       /*
+                        * copy what ever is there in this
+                        * packet and move on
+                        */
+                       bytes_copied = (*list_read_count - bytes_read);
+               else
+                       /* copy the remaining */
+                       bytes_copied = length;
+               memcpy(data, ptemp_buf, bytes_copied);
+       }
+       return bytes_copied;
+}
+
+static int packet_read_list(char *data, size_t * pread_length)
+{
+       struct list_head *ptemp_list;
+       int temp_count = 0;
+       int bytes_copied = 0;
+       int bytes_read = 0;
+       int remaining_bytes = 0;
+       char *pdest = data;
+
+       /* check if we have any packets */
+       if (0 == rbu_data.num_packets)
+               return -ENOMEM;
+
+       remaining_bytes = *pread_length;
+       bytes_read = rbu_data.packet_read_count;
+
+       ptemp_list = (&packet_data_head.list)->next;
+       while (!list_empty(ptemp_list)) {
+               bytes_copied = do_packet_read(pdest, ptemp_list,
+                                             remaining_bytes, bytes_read,
+                                             &temp_count);
+               remaining_bytes -= bytes_copied;
+               bytes_read += bytes_copied;
+               pdest += bytes_copied;
+               /*
+                * check if we reached end of buffer before reaching the
+                * last packet
+                */
+               if (remaining_bytes == 0)
+                       break;
+
+               ptemp_list = ptemp_list->next;
+       }
+       /*finally set the bytes read */
+       *pread_length = bytes_read - rbu_data.packet_read_count;
+       rbu_data.packet_read_count = bytes_read;
+       return 0;
+}
+
+static void packet_empty_list(void)
+{
+       struct list_head *ptemp_list;
+       struct list_head *pnext_list;
+       struct packet_data *newpacket;
+
+       ptemp_list = (&packet_data_head.list)->next;
+       while (!list_empty(ptemp_list)) {
+               newpacket =
+                   list_entry(ptemp_list, struct packet_data, list);
+               pnext_list = ptemp_list->next;
+               list_del(ptemp_list);
+               ptemp_list = pnext_list;
+               /*
+                * zero out the RBU packet memory before freeing
+                * to make sure there are no stale RBU packets left in memory
+                */
+               memset(newpacket->data, 0, rbu_data.packetsize);
+               free_pages((unsigned long)newpacket->data,
+                          newpacket->ordernum);
+               kfree(newpacket);
+       }
+       rbu_data.packet_write_count = 0;
+       rbu_data.packet_read_count = 0;
+       rbu_data.num_packets = 0;
+       rbu_data.packetsize = 0;
+}
+
+/*
+ * img_update_free: Frees the buffer allocated for storing BIOS image
+ * Always called with lock held and returned with lock held
+ */
+static void img_update_free(void)
+{
+       if (!rbu_data.image_update_buffer)
+               return;
+       /*
+        * zero out this buffer before freeing it to get rid of any stale
+        * BIOS image copied in memory.
+        */
+       memset(rbu_data.image_update_buffer, 0,
+              rbu_data.image_update_buffer_size);
+       if (rbu_data.dma_alloc == 1)
+               dma_free_coherent(NULL, rbu_data.bios_image_size,
+                                 rbu_data.image_update_buffer,
+                                 dell_rbu_dmaaddr);
+       else
+               free_pages((unsigned long)rbu_data.image_update_buffer,
+                          rbu_data.image_update_ordernum);
+
+       /*
+        * Re-initialize the rbu_data variables after a free
+        */
+       rbu_data.image_update_ordernum = -1;
+       rbu_data.image_update_buffer = NULL;
+       rbu_data.image_update_buffer_size = 0;
+       rbu_data.bios_image_size = 0;
+       rbu_data.dma_alloc = 0;
+}
+
+/*
+ * img_update_realloc: This function allocates the contiguous pages to
+ * accommodate the requested size of data. The memory address and size
+ * values are stored globally and on every call to this function the new
+ * size is checked to see if more data is required than the existing size.
+ * If true the previous memory is freed and new allocation is done to
+ * accommodate the new size. If the incoming size is less then than the
+ * already allocated size, then that memory is reused. This function is
+ * called with lock held and returns with lock held.
+ */
+static int img_update_realloc(unsigned long size)
+{
+       unsigned char *image_update_buffer = NULL;
+       unsigned long rc;
+       unsigned long img_buf_phys_addr;
+       int ordernum;
+       int dma_alloc = 0;
+
+       /*
+        * check if the buffer of sufficient size has been
+        * already allocated
+        */
+       if (rbu_data.image_update_buffer_size >= size) {
+               /*
+                * check for corruption
+                */
+               if ((size != 0) && (rbu_data.image_update_buffer == NULL)) {
+                       printk(KERN_ERR "dell_rbu:%s: corruption "
+                              "check failed\n", __FUNCTION__);
+                       return -EINVAL;
+               }
+               /*
+                * we have a valid pre-allocated buffer with
+                * sufficient size
+                */
+               return 0;
+       }
+
+       /*
+        * free any previously allocated buffer
+        */
+       img_update_free();
+
+       spin_unlock(&rbu_data.lock);
+
+       ordernum = get_order(size);
+       image_update_buffer =
+           (unsigned char *)__get_free_pages(GFP_KERNEL, ordernum);
+
+       img_buf_phys_addr =
+           (unsigned long)virt_to_phys(image_update_buffer);
+
+       if (img_buf_phys_addr > BIOS_SCAN_LIMIT) {
+               free_pages((unsigned long)image_update_buffer, ordernum);
+               ordernum = -1;
+               image_update_buffer = dma_alloc_coherent(NULL, size,
+                                                        &dell_rbu_dmaaddr,
+                                                        GFP_KERNEL);
+               dma_alloc = 1;
+       }
+
+       spin_lock(&rbu_data.lock);
+
+       if (image_update_buffer != NULL) {
+               rbu_data.image_update_buffer = image_update_buffer;
+               rbu_data.image_update_buffer_size = size;
+               rbu_data.bios_image_size =
+                   rbu_data.image_update_buffer_size;
+               rbu_data.image_update_ordernum = ordernum;
+               rbu_data.dma_alloc = dma_alloc;
+               rc = 0;
+       } else {
+               pr_debug("Not enough memory for image update:"
+                        "size = %ld\n", size);
+               rc = -ENOMEM;
+       }
+
+       return rc;
+}
+
+static ssize_t read_packet_data(char *buffer, loff_t pos, size_t count)
+{
+       int retval;
+       size_t bytes_left;
+       size_t data_length;
+       char *ptempBuf = buffer;
+       unsigned long imagesize;
+
+       /* check to see if we have something to return */
+       if (rbu_data.num_packets == 0) {
+               pr_debug("read_packet_data: no packets written\n");
+               retval = -ENOMEM;
+               goto read_rbu_data_exit;
+       }
+
+       imagesize = rbu_data.num_packets * rbu_data.packetsize;
+
+       if (pos > imagesize) {
+               retval = 0;
+               printk(KERN_WARNING "dell_rbu:read_packet_data: "
+                      "data underrun\n");
+               goto read_rbu_data_exit;
+       }
+
+       bytes_left = imagesize - pos;
+       data_length = min(bytes_left, count);
+
+       if ((retval = packet_read_list(ptempBuf, &data_length)) < 0)
+               goto read_rbu_data_exit;
+
+       if ((pos + count) > imagesize) {
+               rbu_data.packet_read_count = 0;
+               /* this was the last copy */
+               retval = bytes_left;
+       } else
+               retval = count;
+
+      read_rbu_data_exit:
+       return retval;
+}
+
+static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count)
+{
+       unsigned char *ptemp = NULL;
+       size_t bytes_left = 0;
+       size_t data_length = 0;
+       ssize_t ret_count = 0;
+
+       /* check to see if we have something to return */
+       if ((rbu_data.image_update_buffer == NULL) ||
+           (rbu_data.bios_image_size == 0)) {
+               pr_debug("read_rbu_data_mono: image_update_buffer %p ,"
+                        "bios_image_size %lu\n",
+                        rbu_data.image_update_buffer,
+                        rbu_data.bios_image_size);
+               ret_count = -ENOMEM;
+               goto read_rbu_data_exit;
+       }
+
+       if (pos > rbu_data.bios_image_size) {
+               ret_count = 0;
+               goto read_rbu_data_exit;
+       }
+
+       bytes_left = rbu_data.bios_image_size - pos;
+       data_length = min(bytes_left, count);
+
+       ptemp = rbu_data.image_update_buffer;
+       memcpy(buffer, (ptemp + pos), data_length);
+
+       if ((pos + count) > rbu_data.bios_image_size)
+               /* this was the last copy */
+               ret_count = bytes_left;
+       else
+               ret_count = count;
+      read_rbu_data_exit:
+       return ret_count;
+}
+
+static ssize_t
+read_rbu_data(struct kobject *kobj, char *buffer, loff_t pos, size_t count)
+{
+       ssize_t ret_count = 0;
+
+       spin_lock(&rbu_data.lock);
+
+       if (!strcmp(image_type, "mono"))
+               ret_count = read_rbu_mono_data(buffer, pos, count);
+       else if (!strcmp(image_type, "packet"))
+               ret_count = read_packet_data(buffer, pos, count);
+       else
+               pr_debug("read_rbu_data: invalid image type specified\n");
+
+       spin_unlock(&rbu_data.lock);
+       return ret_count;
+}
+
+static ssize_t
+read_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos,
+                   size_t count)
+{
+       int size = 0;
+       if (!pos)
+               size = sprintf(buffer, "%s\n", image_type);
+       return size;
+}
+
+static ssize_t
+write_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos,
+                    size_t count)
+{
+       int rc = count;
+       spin_lock(&rbu_data.lock);
+
+       if (strlen(buffer) < MAX_IMAGE_LENGTH)
+               sscanf(buffer, "%s", image_type);
+       else
+               printk(KERN_WARNING "dell_rbu: image_type is invalid"
+                      "max chars = %d, \n incoming str--%s-- \n",
+                      MAX_IMAGE_LENGTH, buffer);
+
+       /* we must free all previous allocations */
+       packet_empty_list();
+       img_update_free();
+
+       spin_unlock(&rbu_data.lock);
+       return rc;
+
+}
+
+static struct bin_attribute rbu_data_attr = {
+       .attr = {.name = "data",.owner = THIS_MODULE,.mode = 0444},
+       .read = read_rbu_data,
+};
+
+static struct bin_attribute rbu_image_type_attr = {
+       .attr = {.name = "image_type",.owner = THIS_MODULE,.mode = 0644},
+       .read = read_rbu_image_type,
+       .write = write_rbu_image_type,
+};
+
+static void callbackfn_rbu(const struct firmware *fw, void *context)
+{
+       int rc = 0;
+
+       if (!fw || !fw->size)
+               return;
+
+       spin_lock(&rbu_data.lock);
+       if (!strcmp(image_type, "mono")) {
+               if (!img_update_realloc(fw->size))
+                       memcpy(rbu_data.image_update_buffer,
+                              fw->data, fw->size);
+       } else if (!strcmp(image_type, "packet")) {
+               if (!rbu_data.packetsize)
+                       rbu_data.packetsize = fw->size;
+               else if (rbu_data.packetsize != fw->size) {
+                       packet_empty_list();
+                       rbu_data.packetsize = fw->size;
+               }
+               packetize_data(fw->data, fw->size);
+       } else
+               pr_debug("invalid image type specified.\n");
+       spin_unlock(&rbu_data.lock);
+
+       rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
+                                    "dell_rbu", &rbu_device->dev,
+                                    &context, callbackfn_rbu);
+       if (rc)
+               printk(KERN_ERR
+                      "dell_rbu:%s request_firmware_nowait failed"
+                      " %d\n", __FUNCTION__, rc);
+}
+
+static int __init dcdrbu_init(void)
+{
+       int rc = 0;
+       spin_lock_init(&rbu_data.lock);
+
+       init_packet_head();
+       rbu_device =
+           platform_device_register_simple("dell_rbu", -1, NULL, 0);
+       if (!rbu_device) {
+               printk(KERN_ERR
+                      "dell_rbu:%s:platform_device_register_simple "
+                      "failed\n", __FUNCTION__);
+               return -EIO;
+       }
+
+       sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr);
+       sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr);
+
+       rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
+                                    "dell_rbu", &rbu_device->dev,
+                                    &context, callbackfn_rbu);
+       if (rc)
+               printk(KERN_ERR "dell_rbu:%s:request_firmware_nowait"
+                      " failed %d\n", __FUNCTION__, rc);
+
+       return rc;
+
+}
+
+static __exit void dcdrbu_exit(void)
+{
+       spin_lock(&rbu_data.lock);
+       packet_empty_list();
+       img_update_free();
+       spin_unlock(&rbu_data.lock);
+       platform_device_unregister(rbu_device);
+}
+
+module_exit(dcdrbu_exit);
+module_init(dcdrbu_init);
index 140d5f851a5b0c735dffc620778f4735048152b9..138dc50270e3e51e714893602c937b5fa95ec14e 100644 (file)
@@ -12,12 +12,20 @@ config HWMON
          of a system. Most modern motherboards include such a device. It
          can include temperature sensors, voltage sensors, fan speed
          sensors and various additional features such as the ability to
-         control the speed of the fans.
+         control the speed of the fans.  If you want this support you
+         should say Y here and also to the specific driver(s) for your
+         sensors chip(s) below.
+
+         This support can also be built as a module.  If so, the module
+         will be called hwmon.
+
+config HWMON_VID
+       tristate
+       default n
 
 config SENSORS_ADM1021
        tristate "Analog Devices ADM1021 and compatibles"
        depends on HWMON && I2C
-       select I2C_SENSOR
        help
          If you say yes here you get support for Analog Devices ADM1021
          and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A,
@@ -30,7 +38,7 @@ config SENSORS_ADM1021
 config SENSORS_ADM1025
        tristate "Analog Devices ADM1025 and compatibles"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
+       select HWMON_VID
        help
          If you say yes here you get support for Analog Devices ADM1025
          and Philips NE1619 sensor chips.
@@ -41,7 +49,7 @@ config SENSORS_ADM1025
 config SENSORS_ADM1026
        tristate "Analog Devices ADM1026 and compatibles"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
+       select HWMON_VID
        help
          If you say yes here you get support for Analog Devices ADM1026
          sensor chip.
@@ -52,7 +60,6 @@ config SENSORS_ADM1026
 config SENSORS_ADM1031
        tristate "Analog Devices ADM1031 and compatibles"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
        help
          If you say yes here you get support for Analog Devices ADM1031
          and ADM1030 sensor chips.
@@ -63,7 +70,7 @@ config SENSORS_ADM1031
 config SENSORS_ADM9240
        tristate "Analog Devices ADM9240 and compatibles"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
+       select HWMON_VID
        help
          If you say yes here you get support for Analog Devices ADM9240,
          Dallas DS1780, National Semiconductor LM81 sensor chips.
@@ -74,7 +81,7 @@ config SENSORS_ADM9240
 config SENSORS_ASB100
        tristate "Asus ASB100 Bach"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
+       select HWMON_VID
        help
          If you say yes here you get support for the ASB100 Bach sensor
          chip found on some Asus mainboards.
@@ -85,7 +92,7 @@ config SENSORS_ASB100
 config SENSORS_ATXP1
        tristate "Attansic ATXP1 VID controller"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
+       select HWMON_VID
        help
          If you say yes here you get support for the Attansic ATXP1 VID
          controller.
@@ -99,7 +106,6 @@ config SENSORS_ATXP1
 config SENSORS_DS1621
        tristate "Dallas Semiconductor DS1621 and DS1625"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
        help
          If you say yes here you get support for Dallas Semiconductor
          DS1621 and DS1625 sensor chips.
@@ -110,7 +116,6 @@ config SENSORS_DS1621
 config SENSORS_FSCHER
        tristate "FSC Hermes"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
        help
          If you say yes here you get support for Fujitsu Siemens
          Computers Hermes sensor chips.
@@ -121,7 +126,6 @@ config SENSORS_FSCHER
 config SENSORS_FSCPOS
        tristate "FSC Poseidon"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
        help
          If you say yes here you get support for Fujitsu Siemens
          Computers Poseidon sensor chips.
@@ -132,7 +136,6 @@ config SENSORS_FSCPOS
 config SENSORS_GL518SM
        tristate "Genesys Logic GL518SM"
        depends on HWMON && I2C
-       select I2C_SENSOR
        help
          If you say yes here you get support for Genesys Logic GL518SM
          sensor chips.
@@ -143,7 +146,7 @@ config SENSORS_GL518SM
 config SENSORS_GL520SM
        tristate "Genesys Logic GL520SM"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
+       select HWMON_VID
        help
          If you say yes here you get support for Genesys Logic GL520SM
          sensor chips.
@@ -154,7 +157,8 @@ config SENSORS_GL520SM
 config SENSORS_IT87
        tristate "ITE IT87xx and compatibles"
        depends on HWMON && I2C
-       select I2C_SENSOR
+       select I2C_ISA
+       select HWMON_VID
        help
          If you say yes here you get support for ITE IT87xx sensor chips
          and clones: SiS960.
@@ -165,7 +169,6 @@ config SENSORS_IT87
 config SENSORS_LM63
        tristate "National Semiconductor LM63"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
        help
          If you say yes here you get support for the National Semiconductor
          LM63 remote diode digital temperature sensor with integrated fan
@@ -178,7 +181,6 @@ config SENSORS_LM63
 config SENSORS_LM75
        tristate "National Semiconductor LM75 and compatibles"
        depends on HWMON && I2C
-       select I2C_SENSOR
        help
          If you say yes here you get support for National Semiconductor LM75
          sensor chips and clones: Dallas Semiconductor DS75 and DS1775 (in
@@ -194,7 +196,6 @@ config SENSORS_LM75
 config SENSORS_LM77
        tristate "National Semiconductor LM77"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
        help
          If you say yes here you get support for National Semiconductor LM77
          sensor chips.
@@ -205,7 +206,8 @@ config SENSORS_LM77
 config SENSORS_LM78
        tristate "National Semiconductor LM78 and compatibles"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
+       select I2C_ISA
+       select HWMON_VID
        help
          If you say yes here you get support for National Semiconductor LM78,
          LM78-J and LM79.
@@ -216,7 +218,6 @@ config SENSORS_LM78
 config SENSORS_LM80
        tristate "National Semiconductor LM80"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
        help
          If you say yes here you get support for National Semiconductor
          LM80 sensor chips.
@@ -227,7 +228,6 @@ config SENSORS_LM80
 config SENSORS_LM83
        tristate "National Semiconductor LM83"
        depends on HWMON && I2C
-       select I2C_SENSOR
        help
          If you say yes here you get support for National Semiconductor
          LM83 sensor chips.
@@ -238,7 +238,7 @@ config SENSORS_LM83
 config SENSORS_LM85
        tristate "National Semiconductor LM85 and compatibles"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
+       select HWMON_VID
        help
          If you say yes here you get support for National Semiconductor LM85
          sensor chips and clones: ADT7463, EMC6D100, EMC6D102 and ADM1027.
@@ -249,7 +249,7 @@ config SENSORS_LM85
 config SENSORS_LM87
        tristate "National Semiconductor LM87"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
+       select HWMON_VID
        help
          If you say yes here you get support for National Semiconductor LM87
          sensor chips.
@@ -260,7 +260,6 @@ config SENSORS_LM87
 config SENSORS_LM90
        tristate "National Semiconductor LM90 and compatibles"
        depends on HWMON && I2C
-       select I2C_SENSOR
        help
          If you say yes here you get support for National Semiconductor LM90,
          LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and
@@ -275,7 +274,6 @@ config SENSORS_LM90
 config SENSORS_LM92
        tristate "National Semiconductor LM92 and compatibles"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
        help
          If you say yes here you get support for National Semiconductor LM92
          and Maxim MAX6635 sensor chips.
@@ -286,7 +284,6 @@ config SENSORS_LM92
 config SENSORS_MAX1619
        tristate "Maxim MAX1619 sensor chip"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
        help
          If you say yes here you get support for MAX1619 sensor chip.
 
@@ -296,8 +293,8 @@ config SENSORS_MAX1619
 config SENSORS_PC87360
        tristate "National Semiconductor PC87360 family"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
        select I2C_ISA
+       select HWMON_VID
        help
          If you say yes here you get access to the hardware monitoring
          functions of the National Semiconductor PC8736x Super-I/O chips.
@@ -311,7 +308,6 @@ config SENSORS_PC87360
 config SENSORS_SIS5595
        tristate "Silicon Integrated Systems Corp. SiS5595"
        depends on HWMON && I2C && PCI && EXPERIMENTAL
-       select I2C_SENSOR
        select I2C_ISA
        help
          If you say yes here you get support for the integrated sensors in
@@ -323,7 +319,6 @@ config SENSORS_SIS5595
 config SENSORS_SMSC47M1
        tristate "SMSC LPC47M10x and compatibles"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
        select I2C_ISA
        help
          If you say yes here you get support for the integrated fan
@@ -336,7 +331,6 @@ config SENSORS_SMSC47M1
 config SENSORS_SMSC47B397
        tristate "SMSC LPC47B397-NC"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
        select I2C_ISA
        help
          If you say yes here you get support for the SMSC LPC47B397-NC
@@ -348,7 +342,6 @@ config SENSORS_SMSC47B397
 config SENSORS_VIA686A
        tristate "VIA686A"
        depends on HWMON && I2C && PCI
-       select I2C_SENSOR
        select I2C_ISA
        help
          If you say yes here you get support for the integrated sensors in
@@ -360,7 +353,8 @@ config SENSORS_VIA686A
 config SENSORS_W83781D
        tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F"
        depends on HWMON && I2C
-       select I2C_SENSOR
+       select I2C_ISA
+       select HWMON_VID
        help
          If you say yes here you get support for the Winbond W8378x series
          of sensor chips: the W83781D, W83782D, W83783S and W83627HF,
@@ -369,10 +363,18 @@ config SENSORS_W83781D
          This driver can also be built as a module.  If so, the module
          will be called w83781d.
 
+config SENSORS_W83792D
+       tristate "Winbond W83792D"
+       depends on HWMON && I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for the Winbond W83792D chip.
+
+         This driver can also be built as a module.  If so, the module
+         will be called w83792d.
+
 config SENSORS_W83L785TS
        tristate "Winbond W83L785TS-S"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
        help
          If you say yes here you get support for the Winbond W83L785TS-S
          sensor chip, which is used on the Asus A7N8X, among other
@@ -384,8 +386,8 @@ config SENSORS_W83L785TS
 config SENSORS_W83627HF
        tristate "Winbond W83627HF, W83627THF, W83637HF, W83697HF"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
        select I2C_ISA
+       select HWMON_VID
        help
          If you say yes here you get support for the Winbond W836X7 series
          of sensor chips: the W83627HF, W83627THF, W83637HF, and the W83697HF
@@ -396,7 +398,6 @@ config SENSORS_W83627HF
 config SENSORS_W83627EHF
        tristate "Winbond W83627EHF"
        depends on HWMON && I2C && EXPERIMENTAL
-       select I2C_SENSOR
        select I2C_ISA
        help
          If you say yes here you get preliminary support for the hardware
@@ -404,6 +405,9 @@ config SENSORS_W83627EHF
          Only fan and temperature inputs are supported at the moment, while
          the chip does much more than that.
 
+         This driver also supports the W83627EHG, which is the lead-free
+         version of the W83627EHF.
+
          This driver can also be built as a module.  If so, the module
          will be called w83627ehf.
 
index 2781403a0236d1e02d3c82d3bdaac323da2a2dd7..381f1bf04cc5531f2f4f2376f2c0afc61fff57b7 100644 (file)
@@ -2,9 +2,13 @@
 # Makefile for sensor chip drivers.
 #
 
+obj-$(CONFIG_HWMON)            += hwmon.o
+obj-$(CONFIG_HWMON_VID)                += hwmon-vid.o
+
 # asb100, then w83781d go first, as they can override other drivers' addresses.
 obj-$(CONFIG_SENSORS_ASB100)   += asb100.o
 obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o
+obj-$(CONFIG_SENSORS_W83792D)  += w83792d.o
 obj-$(CONFIG_SENSORS_W83781D)  += w83781d.o
 
 obj-$(CONFIG_SENSORS_ADM1021)  += adm1021.o
index d2c774c32f45b942a92453eb110346fa028e7bd7..e928cdb041cba28d76f23821172becc7c3589397 100644 (file)
@@ -24,7 +24,8 @@
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
 
 
 /* Addresses to scan */
@@ -32,10 +33,9 @@ static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
                                        0x29, 0x2a, 0x2b,
                                        0x4c, 0x4d, 0x4e, 
                                        I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
-SENSORS_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066);
+I2C_CLIENT_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066);
 
 /* adm1021 constants specified below */
 
@@ -89,6 +89,7 @@ clearing it.  Weird, ey?   --Phil  */
 /* Each client has this additional data */
 struct adm1021_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        enum chips type;
 
        struct semaphore update_lock;
@@ -185,7 +186,7 @@ static int adm1021_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, adm1021_detect);
+       return i2c_probe(adapter, &addr_data, adm1021_detect);
 }
 
 static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -196,15 +197,6 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
        int err = 0;
        const char *type_name = "";
 
-       /* Make sure we aren't probing the ISA bus!! This is just a safety check
-          at this moment; i2c_detect really won't call us. */
-#ifdef DEBUG
-       if (i2c_is_isa_adapter(adapter)) {
-               dev_dbg(&adapter->dev, "adm1021_detect called for an ISA bus adapter?!?\n");
-               return 0;
-       }
-#endif
-
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                goto error0;
 
@@ -295,6 +287,12 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
                adm1021_init_client(new_client);
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto error2;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_temp1_max);
        device_create_file(&new_client->dev, &dev_attr_temp1_min);
        device_create_file(&new_client->dev, &dev_attr_temp1_input);
@@ -305,6 +303,8 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+error2:
+       i2c_detach_client(new_client);
 error1:
        kfree(data);
 error0:
@@ -322,14 +322,15 @@ static void adm1021_init_client(struct i2c_client *client)
 
 static int adm1021_detach_client(struct i2c_client *client)
 {
+       struct adm1021_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
index e452d0daf906e314f9b0a2444aa64a9b93803609..526b7ff179ebb83c0bc1197a978e85344424a6c8 100644 (file)
@@ -50,8 +50,9 @@
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
 
 /*
  * Addresses to scan
  */
 
 static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /*
  * Insmod parameters
  */
 
-SENSORS_INSMOD_2(adm1025, ne1619);
+I2C_CLIENT_INSMOD_2(adm1025, ne1619);
 
 /*
  * The ADM1025 registers
@@ -132,6 +132,7 @@ static struct i2c_driver adm1025_driver = {
 
 struct adm1025_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
@@ -312,7 +313,7 @@ static int adm1025_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, adm1025_detect);
+       return i2c_probe(adapter, &addr_data, adm1025_detect);
 }
 
 /*
@@ -416,6 +417,12 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
        adm1025_init_client(new_client);
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_in0_input);
        device_create_file(&new_client->dev, &dev_attr_in1_input);
        device_create_file(&new_client->dev, &dev_attr_in2_input);
@@ -452,6 +459,8 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+exit_detach:
+       i2c_detach_client(new_client);
 exit_free:
        kfree(data);
 exit:
@@ -464,7 +473,7 @@ static void adm1025_init_client(struct i2c_client *client)
        struct adm1025_data *data = i2c_get_clientdata(client);
        int i;
 
-       data->vrm = i2c_which_vrm();
+       data->vrm = vid_which_vrm();
 
        /*
         * Set high limits
@@ -502,15 +511,15 @@ static void adm1025_init_client(struct i2c_client *client)
 
 static int adm1025_detach_client(struct i2c_client *client)
 {
+       struct adm1025_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                       "client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
index c8a7f47911f99f315189cc60cb73ba23e888b5fb..625158110fd4ff74294debbc2a67a550012f90c9 100644 (file)
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
-SENSORS_INSMOD_1(adm1026);
+I2C_CLIENT_INSMOD_1(adm1026);
 
 static int gpio_input[17]  = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
                                -1, -1, -1, -1, -1, -1, -1, -1 }; 
@@ -259,6 +259,7 @@ struct pwm_data {
 
 struct adm1026_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore lock;
        enum chips type;
 
@@ -319,13 +320,15 @@ int adm1026_attach_adapter(struct i2c_adapter *adapter)
        if (!(adapter->class & I2C_CLASS_HWMON)) {
                return 0;
        }
-       return i2c_detect(adapter, &addr_data, adm1026_detect);
+       return i2c_probe(adapter, &addr_data, adm1026_detect);
 }
 
 int adm1026_detach_client(struct i2c_client *client)
 {
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       hwmon_device_unregister(data->class_dev);
        i2c_detach_client(client);
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
@@ -1549,12 +1552,18 @@ int adm1026_detect(struct i2c_adapter *adapter, int address,
                goto exitfree;
 
        /* Set the VRM version */
-       data->vrm = i2c_which_vrm();
+       data->vrm = vid_which_vrm();
 
        /* Initialize the ADM1026 chip */
        adm1026_init_client(new_client);
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exitdetach;
+       }
+
        device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
        device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
        device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
@@ -1690,6 +1699,8 @@ int adm1026_detect(struct i2c_adapter *adapter, int address,
        return 0;
 
        /* Error out and cleanup code */
+exitdetach:
+       i2c_detach_client(new_client);
 exitfree:
        kfree(data);
 exit:
index 9362509572709596d92849a666199f4cf1bcb46a..58338ed7c8a1c676095e3c9672fa08e453455a7b 100644 (file)
@@ -26,7 +26,8 @@
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
 
 /* Following macros takes channel parameter starting from 0 to 2 */
 #define ADM1031_REG_FAN_SPEED(nr)      (0x08 + (nr))
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
-SENSORS_INSMOD_2(adm1030, adm1031);
+I2C_CLIENT_INSMOD_2(adm1030, adm1031);
 
 typedef u8 auto_chan_table_t[8][2];
 
 /* Each client has this additional data */
 struct adm1031_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore update_lock;
        int chip_type;
        char valid;             /* !=0 if following fields are valid */
@@ -725,10 +726,10 @@ static int adm1031_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, adm1031_detect);
+       return i2c_probe(adapter, &addr_data, adm1031_detect);
 }
 
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
 static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
 {
        struct i2c_client *new_client;
@@ -788,6 +789,12 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
        adm1031_init_client(new_client);
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_fan1_input);
        device_create_file(&new_client->dev, &dev_attr_fan1_div);
        device_create_file(&new_client->dev, &dev_attr_fan1_min);
@@ -833,6 +840,8 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+exit_detach:
+       i2c_detach_client(new_client);
 exit_free:
        kfree(data);
 exit:
@@ -841,11 +850,14 @@ exit:
 
 static int adm1031_detach_client(struct i2c_client *client)
 {
+       struct adm1031_data *data = i2c_get_clientdata(client);
        int ret;
+
+       hwmon_device_unregister(data->class_dev);
        if ((ret = i2c_detach_client(client)) != 0) {
                return ret;
        }
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
index ce2a6eb93f6e5d4c7baed6fc26797b86988559e4..bc7faef162f7b562fc99a8c8481d73c0809e6e2c 100644 (file)
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
                                        I2C_CLIENT_END };
 
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
-
 /* Insmod parameters */
-SENSORS_INSMOD_3(adm9240, ds1780, lm81);
+I2C_CLIENT_INSMOD_3(adm9240, ds1780, lm81);
 
 /* ADM9240 registers */
 #define ADM9240_REG_MAN_ID             0x3e
@@ -150,6 +149,7 @@ static struct i2c_driver adm9240_driver = {
 struct adm9240_data {
        enum chips type;
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore update_lock;
        char valid;
        unsigned long last_updated_measure;
@@ -582,6 +582,12 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
        adm9240_init_client(new_client);
 
        /* populate sysfs filesystem */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_in0_input);
        device_create_file(&new_client->dev, &dev_attr_in0_min);
        device_create_file(&new_client->dev, &dev_attr_in0_max);
@@ -615,6 +621,9 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
        device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
 
        return 0;
+
+exit_detach:
+       i2c_detach_client(new_client);
 exit_free:
        kfree(data);
 exit:
@@ -625,20 +634,20 @@ static int adm9240_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, adm9240_detect);
+       return i2c_probe(adapter, &addr_data, adm9240_detect);
 }
 
 static int adm9240_detach_client(struct i2c_client *client)
 {
+       struct adm9240_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                               "client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
@@ -648,7 +657,7 @@ static void adm9240_init_client(struct i2c_client *client)
        u8 conf = adm9240_read_value(client, ADM9240_REG_CONFIG);
        u8 mode = adm9240_read_value(client, ADM9240_REG_TEMP_CONF) & 3;
 
-       data->vrm = i2c_which_vrm(); /* need this to report vid as mV */
+       data->vrm = vid_which_vrm(); /* need this to report vid as mV */
 
        dev_info(&client->dev, "Using VRM: %d.%d\n", data->vrm / 10,
                        data->vrm % 10);
index 70d996d6fe0a95c607c06afe6b0a8da01025a39e..8e34855a627406200510db53dd9e374d87ce7db9 100644 (file)
@@ -39,8 +39,9 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/jiffies.h>
 #include "lm75.h"
 /* I2C addresses to scan */
 static unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
 
-/* ISA addresses to scan (none) */
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
-
 /* Insmod parameters */
-SENSORS_INSMOD_1(asb100);
+I2C_CLIENT_INSMOD_1(asb100);
 I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
        "{bus, clientaddr, subclientaddr1, subclientaddr2}");
 
@@ -183,6 +181,7 @@ static u8 DIV_TO_REG(long val)
    dynamically allocated, at the same time the client itself is allocated. */
 struct asb100_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore lock;
        enum chips type;
 
@@ -621,7 +620,7 @@ static int asb100_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, asb100_detect);
+       return i2c_probe(adapter, &addr_data, asb100_detect);
 }
 
 static int asb100_detect_subclients(struct i2c_adapter *adapter, int address,
@@ -714,14 +713,6 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
        struct i2c_client *new_client;
        struct asb100_data *data;
 
-       /* asb100 is SMBus only */
-       if (i2c_is_isa_adapter(adapter)) {
-               pr_debug("asb100.o: detect failed, "
-                               "cannot attach to legacy adapter!\n");
-               err = -ENODEV;
-               goto ERROR0;
-       }
-
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
                pr_debug("asb100.o: detect failed, "
                                "smbus byte data not supported!\n");
@@ -821,6 +812,12 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
        data->fan_min[2] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(2));
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto ERROR3;
+       }
+
        device_create_file_in(new_client, 0);
        device_create_file_in(new_client, 1);
        device_create_file_in(new_client, 2);
@@ -847,6 +844,11 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+ERROR3:
+       i2c_detach_client(data->lm75[1]);
+       i2c_detach_client(data->lm75[0]);
+       kfree(data->lm75[1]);
+       kfree(data->lm75[0]);
 ERROR2:
        i2c_detach_client(new_client);
 ERROR1:
@@ -857,21 +859,23 @@ ERROR0:
 
 static int asb100_detach_client(struct i2c_client *client)
 {
+       struct asb100_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "client deregistration failed; "
-                       "client not detached.\n");
+       /* main client */
+       if (data)
+               hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
-       if (i2c_get_clientdata(client)==NULL) {
-               /* subclients */
+       /* main client */
+       if (data)
+               kfree(data);
+
+       /* subclient */
+       else
                kfree(client);
-       } else {
-               /* main client */
-               kfree(i2c_get_clientdata(client));
-       }
 
        return 0;
 }
@@ -969,7 +973,7 @@ static void asb100_init_client(struct i2c_client *client)
 
        vid = asb100_read_value(client, ASB100_REG_VID_FANDIV) & 0x0f;
        vid |= (asb100_read_value(client, ASB100_REG_CHIPID) & 0x01) << 4;
-       data->vrm = i2c_which_vrm();
+       data->vrm = vid_which_vrm();
        vid = vid_from_reg(vid, data->vrm);
 
        /* Start monitoring */
index fca3fc1cef72f02c1217d32cbfc0fa8876c63e40..deb4d34c9539bab6428d9f5fad5d62a357b787b2 100644 (file)
@@ -23,8 +23,9 @@
 #include <linux/module.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("System voltages control via Attansic ATXP1");
@@ -40,9 +41,8 @@ MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
 #define ATXP1_GPIO1MASK        0x0f
 
 static unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
-SENSORS_INSMOD_1(atxp1);
+I2C_CLIENT_INSMOD_1(atxp1);
 
 static int atxp1_attach_adapter(struct i2c_adapter * adapter);
 static int atxp1_detach_client(struct i2c_client * client);
@@ -59,6 +59,7 @@ static struct i2c_driver atxp1_driver = {
 
 struct atxp1_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore update_lock;
        unsigned long last_updated;
        u8 valid;
@@ -252,7 +253,7 @@ static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2);
 
 static int atxp1_attach_adapter(struct i2c_adapter *adapter)
 {
-       return i2c_detect(adapter, &addr_data, &atxp1_detect);
+       return i2c_probe(adapter, &addr_data, &atxp1_detect);
 };
 
 static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -295,7 +296,7 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
        }
 
        /* Get VRM */
-       data->vrm = i2c_which_vrm();
+       data->vrm = vid_which_vrm();
 
        if ((data->vrm != 90) && (data->vrm != 91)) {
                dev_err(&new_client->dev, "Not supporting VRM %d.%d\n",
@@ -317,6 +318,12 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
                goto exit_free;
        }
 
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_gpio1);
        device_create_file(&new_client->dev, &dev_attr_gpio2);
        device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
@@ -326,6 +333,8 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+exit_detach:
+       i2c_detach_client(new_client);
 exit_free:
        kfree(data);
 exit:
@@ -334,14 +343,17 @@ exit:
 
 static int atxp1_detach_client(struct i2c_client * client)
 {
+       struct atxp1_data * data = i2c_get_clientdata(client);
        int err;
 
+       hwmon_device_unregister(data->class_dev);
+
        err = i2c_detach_client(client);
 
        if (err)
                dev_err(&client->dev, "Failed to detach client.\n");
        else
-               kfree(i2c_get_clientdata(client));
+               kfree(data);
 
        return err;
 };
index 5360d58804f6244e4de94a2b85b9b312cd36a409..b0199e063d0ebf02f1b8f92910086b0353f5cd55 100644 (file)
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
 #include "lm75.h"
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
                                        0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
-SENSORS_INSMOD_1(ds1621);
+I2C_CLIENT_INSMOD_1(ds1621);
 static int polarity = -1;
 module_param(polarity, int, 0);
 MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low");
@@ -71,6 +71,7 @@ MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low")
 /* Each client has this additional data */
 struct ds1621_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore update_lock;
        char valid;                     /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
@@ -179,10 +180,10 @@ static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
 
 static int ds1621_attach_adapter(struct i2c_adapter *adapter)
 {
-       return i2c_detect(adapter, &addr_data, ds1621_detect);
+       return i2c_probe(adapter, &addr_data, ds1621_detect);
 }
 
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
 int ds1621_detect(struct i2c_adapter *adapter, int address,
                   int kind)
 {
@@ -250,6 +251,12 @@ int ds1621_detect(struct i2c_adapter *adapter, int address,
        ds1621_init_client(new_client);
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_alarms);
        device_create_file(&new_client->dev, &dev_attr_temp1_input);
        device_create_file(&new_client->dev, &dev_attr_temp1_min);
@@ -259,6 +266,8 @@ int ds1621_detect(struct i2c_adapter *adapter, int address,
 
 /* OK, this is not exactly good programming practice, usually. But it is
    very code-efficient in this case. */
+      exit_detach:
+       i2c_detach_client(new_client);
       exit_free:
        kfree(data);
       exit:
@@ -267,15 +276,15 @@ int ds1621_detect(struct i2c_adapter *adapter, int address,
 
 static int ds1621_detach_client(struct i2c_client *client)
 {
+       struct ds1621_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                       "client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
 
        return 0;
 }
index da411741c2c579964e8b1ac857d370154a8a33f3..eef6061d786b4e3c397b6bf9445a2d835be2b427 100644 (file)
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
 
 /*
  * Addresses to scan
  */
 
 static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /*
  * Insmod parameters
  */
 
-SENSORS_INSMOD_1(fscher);
+I2C_CLIENT_INSMOD_1(fscher);
 
 /*
  * The FSCHER registers
@@ -132,6 +132,7 @@ static struct i2c_driver fscher_driver = {
 
 struct fscher_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
@@ -287,7 +288,7 @@ static int fscher_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, fscher_detect);
+       return i2c_probe(adapter, &addr_data, fscher_detect);
 }
 
 static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -341,6 +342,12 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
        fscher_init_client(new_client);
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file_revision(new_client);
        device_create_file_alarms(new_client);
        device_create_file_control(new_client);
@@ -360,6 +367,8 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+exit_detach:
+       i2c_detach_client(new_client);
 exit_free:
        kfree(data);
 exit:
@@ -368,15 +377,15 @@ exit:
 
 static int fscher_detach_client(struct i2c_client *client)
 {
+       struct fscher_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                       "client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
index 301ae98bd0adb1fca9d0f0e6687a538019439a0b..5fc77a5fed07b4b25d8fc21d27e22cc55a6a71a9 100644 (file)
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
 #include <linux/init.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
 
 /*
  * Addresses to scan
  */
 static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /*
  * Insmod parameters
  */
-SENSORS_INSMOD_1(fscpos);
+I2C_CLIENT_INSMOD_1(fscpos);
 
 /*
  * The FSCPOS registers
@@ -113,6 +113,7 @@ static struct i2c_driver fscpos_driver = {
  */
 struct fscpos_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore update_lock;
        char valid;             /* 0 until following fields are valid */
        unsigned long last_updated;     /* In jiffies */
@@ -434,7 +435,7 @@ static int fscpos_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, fscpos_detect);
+       return i2c_probe(adapter, &addr_data, fscpos_detect);
 }
 
 int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -496,6 +497,12 @@ int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
        dev_info(&new_client->dev, "Found fscpos chip, rev %u\n", data->revision);
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_event);
        device_create_file(&new_client->dev, &dev_attr_in0_input);
        device_create_file(&new_client->dev, &dev_attr_in1_input);
@@ -526,6 +533,8 @@ int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+exit_detach:
+       i2c_detach_client(new_client);
 exit_free:
        kfree(data);
 exit:
@@ -534,14 +543,14 @@ exit:
 
 static int fscpos_detach_client(struct i2c_client *client)
 {
+       struct fscpos_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, client"
-                                                       " not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
index 6bedf729dcf5c251b27c18676af66fab4b68793f..256b9323c84b1e83f087cf51a3b34bb9190548fb 100644 (file)
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
-SENSORS_INSMOD_2(gl518sm_r00, gl518sm_r80);
+I2C_CLIENT_INSMOD_2(gl518sm_r00, gl518sm_r80);
 
 /* Many GL518 constants specified below */
 
@@ -117,6 +117,7 @@ static inline u8 FAN_TO_REG(long rpm, int div)
 /* Each client has this additional data */
 struct gl518_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        enum chips type;
 
        struct semaphore update_lock;
@@ -346,7 +347,7 @@ static int gl518_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, gl518_detect);
+       return i2c_probe(adapter, &addr_data, gl518_detect);
 }
 
 static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -419,6 +420,12 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
        gl518_init_client((struct i2c_client *) new_client);
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_in0_input);
        device_create_file(&new_client->dev, &dev_attr_in1_input);
        device_create_file(&new_client->dev, &dev_attr_in2_input);
@@ -450,6 +457,8 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
 /* OK, this is not exactly good programming practice, usually. But it is
    very code-efficient in this case. */
 
+exit_detach:
+       i2c_detach_client(new_client);
 exit_free:
        kfree(data);
 exit:
@@ -477,16 +486,15 @@ static void gl518_init_client(struct i2c_client *client)
 
 static int gl518_detach_client(struct i2c_client *client)
 {
+       struct gl518_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                       "client not detached.\n");
-               return err;
-       }
+       hwmon_device_unregister(data->class_dev);
 
-       kfree(i2c_get_clientdata(client));
+       if ((err = i2c_detach_client(client)))
+               return err;
 
+       kfree(data);
        return 0;
 }
 
index 80ae8d30c2afc4d556f054a0f6e7fbcf1a0d627e..12fd757066fc9cad503b32a5c1df1e056909fbb5 100644 (file)
@@ -26,8 +26,9 @@
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
 
 /* Type of the extra sensor */
 static unsigned short extra_sensor_type;
@@ -36,10 +37,9 @@ MODULE_PARM_DESC(extra_sensor_type, "Type of extra sensor (0=autodetect, 1=tempe
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
-SENSORS_INSMOD_1(gl520sm);
+I2C_CLIENT_INSMOD_1(gl520sm);
 
 /* Many GL520 constants specified below 
 One of the inputs can be configured as either temp or voltage.
@@ -120,6 +120,7 @@ static struct i2c_driver gl520_driver = {
 /* Client data */
 struct gl520_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore update_lock;
        char valid;             /* zero until the following fields are valid */
        unsigned long last_updated;     /* in jiffies */
@@ -518,7 +519,7 @@ static int gl520_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, gl520_detect);
+       return i2c_probe(adapter, &addr_data, gl520_detect);
 }
 
 static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -571,6 +572,12 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
        gl520_init_client(new_client);
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file_vid(new_client, 0);
 
        device_create_file_in(new_client, 0);
@@ -592,6 +599,8 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+exit_detach:
+       i2c_detach_client(new_client);
 exit_free:
        kfree(data);
 exit:
@@ -608,7 +617,7 @@ static void gl520_init_client(struct i2c_client *client)
        conf = oldconf = gl520_read_value(client, GL520_REG_CONF);
 
        data->alarm_mask = 0xff;
-       data->vrm = i2c_which_vrm();
+       data->vrm = vid_which_vrm();
 
        if (extra_sensor_type == 1)
                conf &= ~0x10;
@@ -639,15 +648,15 @@ static void gl520_init_client(struct i2c_client *client)
 
 static int gl520_detach_client(struct i2c_client *client)
 {
+       struct gl520_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                       "client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c
new file mode 100644 (file)
index 0000000..312769a
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+    hwmon-vid.c - VID/VRM/VRD voltage conversions
+
+    Copyright (c) 2004 Rudolf Marek <r.marek@sh.cvut.cz>
+
+    Partly imported from i2c-vid.h of the lm_sensors project
+    Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
+    With assistance from Trent Piepho <xyzzy@speakeasy.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/hwmon-vid.h>
+
+/*
+    Common code for decoding VID pins.
+
+    References:
+
+    For VRM 8.4 to 9.1, "VRM x.y DC-DC Converter Design Guidelines",
+    available at http://developer.intel.com/.
+
+    For VRD 10.0 and up, "VRD x.y Design Guide",
+    available at http://developer.intel.com/.
+
+    AMD Opteron processors don't follow the Intel specifications.
+    I'm going to "make up" 2.4 as the spec number for the Opterons.
+    No good reason just a mnemonic for the 24x Opteron processor
+    series.
+
+    Opteron VID encoding is:
+       00000  =  1.550 V
+       00001  =  1.525 V
+        . . . .
+       11110  =  0.800 V
+       11111  =  0.000 V (off)
+*/
+
+/* vrm is the VRM/VRD document version multiplied by 10.
+   val is the 4-, 5- or 6-bit VID code.
+   Returned value is in mV to avoid floating point in the kernel. */
+int vid_from_reg(int val, int vrm)
+{
+       int vid;
+
+       switch(vrm) {
+
+       case  0:
+               return 0;
+
+       case 100:               /* VRD 10.0 */
+               if((val & 0x1f) == 0x1f)
+                       return 0;
+               if((val & 0x1f) <= 0x09 || val == 0x0a)
+                       vid = 10875 - (val & 0x1f) * 250;
+               else
+                       vid = 18625 - (val & 0x1f) * 250;
+               if(val & 0x20)
+                       vid -= 125;
+               vid /= 10;      /* only return 3 dec. places for now */
+               return vid;
+
+       case 24:                /* Opteron processor */
+               return(val == 0x1f ? 0 : 1550 - val * 25);
+
+       case 91:                /* VRM 9.1 */
+       case 90:                /* VRM 9.0 */
+               return(val == 0x1f ? 0 :
+                                      1850 - val * 25);
+
+       case 85:                /* VRM 8.5 */
+               return((val & 0x10  ? 25 : 0) +
+                      ((val & 0x0f) > 0x04 ? 2050 : 1250) -
+                      ((val & 0x0f) * 50));
+
+       case 84:                /* VRM 8.4 */
+               val &= 0x0f;
+                               /* fall through */
+       default:                /* VRM 8.2 */
+               return(val == 0x1f ? 0 :
+                      val & 0x10  ? 5100 - (val) * 100 :
+                                    2050 - (val) * 50);
+       }
+}
+
+
+/*
+    After this point is the code to automatically determine which
+    VRM/VRD specification should be used depending on the CPU.
+*/
+
+struct vrm_model {
+       u8 vendor;
+       u8 eff_family;
+       u8 eff_model;
+       int vrm_type;
+};
+
+#define ANY 0xFF
+
+#ifdef CONFIG_X86
+
+static struct vrm_model vrm_models[] = {
+       {X86_VENDOR_AMD, 0x6, ANY, 90},         /* Athlon Duron etc */
+       {X86_VENDOR_AMD, 0xF, ANY, 24},         /* Athlon 64, Opteron */
+       {X86_VENDOR_INTEL, 0x6, 0x9, 85},       /* 0.13um too */
+       {X86_VENDOR_INTEL, 0x6, 0xB, 85},       /* Tualatin */
+       {X86_VENDOR_INTEL, 0x6, ANY, 82},       /* any P6 */
+       {X86_VENDOR_INTEL, 0x7, ANY, 0},        /* Itanium */
+       {X86_VENDOR_INTEL, 0xF, 0x0, 90},       /* P4 */
+       {X86_VENDOR_INTEL, 0xF, 0x1, 90},       /* P4 Willamette */
+       {X86_VENDOR_INTEL, 0xF, 0x2, 90},       /* P4 Northwood */
+       {X86_VENDOR_INTEL, 0xF, 0x3, 100},      /* P4 Prescott */
+       {X86_VENDOR_INTEL, 0xF, 0x4, 100},      /* P4 Prescott */
+       {X86_VENDOR_INTEL, 0x10,ANY, 0},        /* Itanium 2 */
+       {X86_VENDOR_UNKNOWN, ANY, ANY, 0}       /* stop here */
+};
+
+static int find_vrm(u8 eff_family, u8 eff_model, u8 vendor)
+{
+       int i = 0;
+
+       while (vrm_models[i].vendor!=X86_VENDOR_UNKNOWN) {
+               if (vrm_models[i].vendor==vendor)
+                       if ((vrm_models[i].eff_family==eff_family)
+                        && ((vrm_models[i].eff_model==eff_model) ||
+                            (vrm_models[i].eff_model==ANY)))
+                               return vrm_models[i].vrm_type;
+               i++;
+       }
+
+       return 0;
+}
+
+int vid_which_vrm(void)
+{
+       struct cpuinfo_x86 *c = cpu_data;
+       u32 eax;
+       u8 eff_family, eff_model;
+       int vrm_ret;
+
+       if (c->x86 < 6)         /* Any CPU with family lower than 6 */
+               return 0;       /* doesn't have VID and/or CPUID */
+
+       eax = cpuid_eax(1);
+       eff_family = ((eax & 0x00000F00)>>8);
+       eff_model  = ((eax & 0x000000F0)>>4);
+       if (eff_family == 0xF) {        /* use extended model & family */
+               eff_family += ((eax & 0x00F00000)>>20);
+               eff_model += ((eax & 0x000F0000)>>16)<<4;
+       }
+       vrm_ret = find_vrm(eff_family,eff_model,c->x86_vendor);
+       if (vrm_ret == 0)
+               printk(KERN_INFO "hwmon-vid: Unknown VRM version of your "
+                      "x86 CPU\n");
+       return vrm_ret;
+}
+
+/* and now something completely different for the non-x86 world */
+#else
+int vid_which_vrm(void)
+{
+       printk(KERN_INFO "hwmon-vid: Unknown VRM version of your CPU\n");
+       return 0;
+}
+#endif
+
+EXPORT_SYMBOL(vid_from_reg);
+EXPORT_SYMBOL(vid_which_vrm);
+
+MODULE_AUTHOR("Rudolf Marek <r.marek@sh.cvut.cz>");
+
+MODULE_DESCRIPTION("hwmon-vid driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
new file mode 100644 (file)
index 0000000..9b41c9b
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+    hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring
+
+    This file defines the sysfs class "hwmon", for use by sensors drivers.
+
+    Copyright (C) 2005 Mark M. Hoffman <mhoffman@lightlink.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; version 2 of the License.
+*/
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kdev_t.h>
+#include <linux/idr.h>
+#include <linux/hwmon.h>
+
+#define HWMON_ID_PREFIX "hwmon"
+#define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d"
+
+static struct class *hwmon_class;
+
+static DEFINE_IDR(hwmon_idr);
+
+/**
+ * hwmon_device_register - register w/ hwmon sysfs class
+ * @dev: the device to register
+ *
+ * hwmon_device_unregister() must be called when the class device is no
+ * longer needed.
+ *
+ * Returns the pointer to the new struct class device.
+ */
+struct class_device *hwmon_device_register(struct device *dev)
+{
+       struct class_device *cdev;
+       int id;
+
+       if (idr_pre_get(&hwmon_idr, GFP_KERNEL) == 0)
+               return ERR_PTR(-ENOMEM);
+
+       if (idr_get_new(&hwmon_idr, NULL, &id) < 0)
+               return ERR_PTR(-ENOMEM);
+
+       id = id & MAX_ID_MASK;
+       cdev = class_device_create(hwmon_class, MKDEV(0,0), dev,
+                                       HWMON_ID_FORMAT, id);
+
+       if (IS_ERR(cdev))
+               idr_remove(&hwmon_idr, id);
+
+       return cdev;
+}
+
+/**
+ * hwmon_device_unregister - removes the previously registered class device
+ *
+ * @cdev: the class device to destroy
+ */
+void hwmon_device_unregister(struct class_device *cdev)
+{
+       int id;
+
+       if (sscanf(cdev->class_id, HWMON_ID_FORMAT, &id) == 1) {
+               class_device_unregister(cdev);
+               idr_remove(&hwmon_idr, id);
+       } else
+               dev_dbg(cdev->dev,
+                       "hwmon_device_unregister() failed: bad class ID!\n");
+}
+
+static int __init hwmon_init(void)
+{
+       hwmon_class = class_create(THIS_MODULE, "hwmon");
+       if (IS_ERR(hwmon_class)) {
+               printk(KERN_ERR "hwmon.c: couldn't create sysfs class\n");
+               return PTR_ERR(hwmon_class);
+       }
+       return 0;
+}
+
+static void __exit hwmon_exit(void)
+{
+       class_destroy(hwmon_class);
+}
+
+module_init(hwmon_init);
+module_exit(hwmon_exit);
+
+EXPORT_SYMBOL_GPL(hwmon_device_register);
+EXPORT_SYMBOL_GPL(hwmon_device_unregister);
+
+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
+MODULE_DESCRIPTION("hardware monitoring sysfs/class support");
+MODULE_LICENSE("GPL");
+
index db20c9e47393a36bbd04b580ce92560ff6dcc331..53cc2b6d63854a835e661a0b2921640b6e36e915 100644 (file)
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
 #include <asm/io.h>
 
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
                                        0x2e, 0x2f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END };
+static unsigned short isa_address = 0x290;
 
 /* Insmod parameters */
-SENSORS_INSMOD_2(it87, it8712);
+I2C_CLIENT_INSMOD_2(it87, it8712);
 
 #define        REG     0x2e    /* The register to read/write */
 #define        DEV     0x07    /* Register: Logical device select */
@@ -192,6 +194,7 @@ static int DIV_TO_REG(int val)
    allocated. */
 struct it87_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore lock;
        enum chips type;
 
@@ -218,7 +221,7 @@ struct it87_data {
 
 
 static int it87_attach_adapter(struct i2c_adapter *adapter);
-static int it87_find(int *address);
+static int it87_isa_attach_adapter(struct i2c_adapter *adapter);
 static int it87_detect(struct i2c_adapter *adapter, int address, int kind);
 static int it87_detach_client(struct i2c_client *client);
 
@@ -239,6 +242,14 @@ static struct i2c_driver it87_driver = {
        .detach_client  = it87_detach_client,
 };
 
+static struct i2c_driver it87_isa_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "it87-isa",
+       .attach_adapter = it87_isa_attach_adapter,
+       .detach_client  = it87_detach_client,
+};
+
+
 static ssize_t show_in(struct device *dev, struct device_attribute *attr,
                char *buf)
 {
@@ -686,11 +697,16 @@ static int it87_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, it87_detect);
+       return i2c_probe(adapter, &addr_data, it87_detect);
 }
 
-/* SuperIO detection - will change normal_isa[0] if a chip is found */
-static int it87_find(int *address)
+static int it87_isa_attach_adapter(struct i2c_adapter *adapter)
+{
+       return it87_detect(adapter, isa_address, -1);
+}
+
+/* SuperIO detection - will change isa_address if a chip is found */
+static int __init it87_find(int *address)
 {
        int err = -ENODEV;
 
@@ -721,7 +737,7 @@ exit:
        return err;
 }
 
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
 int it87_detect(struct i2c_adapter *adapter, int address, int kind)
 {
        int i;
@@ -738,7 +754,7 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind)
 
        /* Reserve the ISA region */
        if (is_isa)
-               if (!request_region(address, IT87_EXTENT, it87_driver.name))
+               if (!request_region(address, IT87_EXTENT, it87_isa_driver.name))
                        goto ERROR0;
 
        /* Probe whether there is anything available on this address. Already
@@ -784,7 +800,7 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind)
        i2c_set_clientdata(new_client, data);
        new_client->addr = address;
        new_client->adapter = adapter;
-       new_client->driver = &it87_driver;
+       new_client->driver = is_isa ? &it87_isa_driver : &it87_driver;
        new_client->flags = 0;
 
        /* Now, we do the remaining detection. */
@@ -840,6 +856,12 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind)
        it87_init_client(new_client, data);
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto ERROR3;
+       }
+
        device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
        device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr);
        device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr);
@@ -897,13 +919,15 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind)
        }
 
        if (data->type == it8712) {
-               data->vrm = i2c_which_vrm();
+               data->vrm = vid_which_vrm();
                device_create_file_vrm(new_client);
                device_create_file_vid(new_client);
        }
 
        return 0;
 
+ERROR3:
+       i2c_detach_client(new_client);
 ERROR2:
        kfree(data);
 ERROR1:
@@ -915,17 +939,17 @@ ERROR0:
 
 static int it87_detach_client(struct i2c_client *client)
 {
+       struct it87_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev,
-                       "Client deregistration failed, client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
        if(i2c_is_isa_client(client))
                release_region(client->addr, IT87_EXTENT);
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
 
        return 0;
 }
@@ -1158,16 +1182,28 @@ static struct it87_data *it87_update_device(struct device *dev)
 
 static int __init sm_it87_init(void)
 {
-       int addr;
+       int addr, res;
 
        if (!it87_find(&addr)) {
-               normal_isa[0] = addr;
+               isa_address = addr;
+       }
+
+       res = i2c_add_driver(&it87_driver);
+       if (res)
+               return res;
+
+       res = i2c_isa_add_driver(&it87_isa_driver);
+       if (res) {
+               i2c_del_driver(&it87_driver);
+               return res;
        }
-       return i2c_add_driver(&it87_driver);
+
+       return 0;
 }
 
 static void __exit sm_it87_exit(void)
 {
+       i2c_isa_del_driver(&it87_isa_driver);
        i2c_del_driver(&it87_driver);
 }
 
index 7c6f9ea5a254c53614e2269a89263a4aad96184f..be5c7095ecbb2648bf86a05583373b0e9a30a157 100644 (file)
@@ -42,8 +42,9 @@
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
 #include <linux/hwmon-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
 
 /*
  * Addresses to scan
  */
 
 static unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /*
  * Insmod parameters
  */
 
-SENSORS_INSMOD_1(lm63);
+I2C_CLIENT_INSMOD_1(lm63);
 
 /*
  * The LM63 registers
@@ -152,6 +152,7 @@ static struct i2c_driver lm63_driver = {
 
 struct lm63_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
@@ -358,7 +359,7 @@ static int lm63_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, lm63_detect);
+       return i2c_probe(adapter, &addr_data, lm63_detect);
 }
 
 /*
@@ -437,6 +438,12 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
        lm63_init_client(new_client);
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        if (data->config & 0x04) { /* tachometer enabled */
                device_create_file(&new_client->dev,
                                   &sensor_dev_attr_fan1_input.dev_attr);
@@ -462,6 +469,8 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+exit_detach:
+       i2c_detach_client(new_client);
 exit_free:
        kfree(data);
 exit:
@@ -505,15 +514,15 @@ static void lm63_init_client(struct i2c_client *client)
 
 static int lm63_detach_client(struct i2c_client *client)
 {
+       struct lm63_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                       "client not detached\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
index 5be164ed278ebaf236f9b65b98663b450cef8ba5..9a3ebdf583f403ec80f4c066aa64459bfb4ccfac 100644 (file)
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
 #include "lm75.h"
 
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
                                        0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
-SENSORS_INSMOD_1(lm75);
+I2C_CLIENT_INSMOD_1(lm75);
 
 /* Many LM75 constants specified below */
 
@@ -46,6 +46,7 @@ SENSORS_INSMOD_1(lm75);
 /* Each client has this additional data */
 struct lm75_data {
        struct i2c_client       client;
+       struct class_device *class_dev;
        struct semaphore        update_lock;
        char                    valid;          /* !=0 if following fields are valid */
        unsigned long           last_updated;   /* In jiffies */
@@ -107,10 +108,10 @@ static int lm75_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, lm75_detect);
+       return i2c_probe(adapter, &addr_data, lm75_detect);
 }
 
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
 static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
 {
        int i;
@@ -119,16 +120,6 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
        int err = 0;
        const char *name = "";
 
-       /* Make sure we aren't probing the ISA bus!! This is just a safety check
-          at this moment; i2c_detect really won't call us. */
-#ifdef DEBUG
-       if (i2c_is_isa_adapter(adapter)) {
-               dev_dbg(&adapter->dev,
-                       "lm75_detect called for an ISA bus adapter?!?\n");
-               goto exit;
-       }
-#endif
-
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
                                     I2C_FUNC_SMBUS_WORD_DATA))
                goto exit;
@@ -208,12 +199,20 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
        lm75_init_client(new_client);
        
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_temp1_max);
        device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
        device_create_file(&new_client->dev, &dev_attr_temp1_input);
 
        return 0;
 
+exit_detach:
+       i2c_detach_client(new_client);
 exit_free:
        kfree(data);
 exit:
@@ -222,8 +221,10 @@ exit:
 
 static int lm75_detach_client(struct i2c_client *client)
 {
+       struct lm75_data *data = i2c_get_clientdata(client);
+       hwmon_device_unregister(data->class_dev);
        i2c_detach_client(client);
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
@@ -251,8 +252,12 @@ static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value)
 
 static void lm75_init_client(struct i2c_client *client)
 {
-       /* Initialize the LM75 chip */
-       lm75_write_value(client, LM75_REG_CONF, 0);
+       int reg;
+
+       /* Enable if in shutdown mode */
+       reg = lm75_read_value(client, LM75_REG_CONF);
+       if (reg >= 0 && (reg & 0x01))
+               lm75_write_value(client, LM75_REG_CONF, reg & 0xfe);
 }
 
 static struct lm75_data *lm75_update_device(struct device *dev)
index 63e3f2fb4c21dd4ef6b2063a993e4b5f2e237672..af7dc650ee1506878901453ea51bc75dee764392 100644 (file)
@@ -25,7 +25,7 @@
     which contains this code, we don't worry about the wasted space.
 */
 
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
 
 /* straight from the datasheet */
 #define LM75_TEMP_MIN (-55000)
index b98f449529976083b38c881f5cc9997050d500a7..866eab96a6f6f6594374037bda6eeb08c5a39c1a 100644 (file)
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-
+#include <linux/hwmon.h>
+#include <linux/err.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
-SENSORS_INSMOD_1(lm77);
+I2C_CLIENT_INSMOD_1(lm77);
 
 /* The LM77 registers */
 #define LM77_REG_TEMP          0x00
@@ -51,6 +50,7 @@ SENSORS_INSMOD_1(lm77);
 /* Each client has this additional data */
 struct lm77_data {
        struct i2c_client       client;
+       struct class_device *class_dev;
        struct semaphore        update_lock;
        char                    valid;
        unsigned long           last_updated;   /* In jiffies */
@@ -208,10 +208,10 @@ static int lm77_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, lm77_detect);
+       return i2c_probe(adapter, &addr_data, lm77_detect);
 }
 
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
 static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
 {
        struct i2c_client *new_client;
@@ -317,6 +317,12 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
        lm77_init_client(new_client);
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_temp1_input);
        device_create_file(&new_client->dev, &dev_attr_temp1_crit);
        device_create_file(&new_client->dev, &dev_attr_temp1_min);
@@ -327,6 +333,8 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
        device_create_file(&new_client->dev, &dev_attr_alarms);
        return 0;
 
+exit_detach:
+       i2c_detach_client(new_client);
 exit_free:
        kfree(data);
 exit:
@@ -335,8 +343,10 @@ exit:
 
 static int lm77_detach_client(struct i2c_client *client)
 {
+       struct lm77_data *data = i2c_get_clientdata(client);
+       hwmon_device_unregister(data->class_dev);
        i2c_detach_client(client);
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
index 29241469dcbac09d2617c365e7b5388fc6908308..f6730dc3573b68096814ccff7e8a898aae45122a 100644 (file)
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
 #include <asm/io.h>
 
 /* Addresses to scan */
@@ -31,10 +34,10 @@ static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24,
                                        0x25, 0x26, 0x27, 0x28, 0x29,
                                        0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
                                        0x2f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END };
+static unsigned short isa_address = 0x290;
 
 /* Insmod parameters */
-SENSORS_INSMOD_3(lm78, lm78j, lm79);
+I2C_CLIENT_INSMOD_2(lm78, lm79);
 
 /* Many LM78 constants specified below */
 
@@ -104,13 +107,6 @@ static inline int TEMP_FROM_REG(s8 val)
        return val * 1000;
 }
 
-/* VID: mV
-   REG: (see doc/vid) */
-static inline int VID_FROM_REG(u8 val)
-{
-       return val==0x1f ? 0 : val>=0x10 ? 5100-val*100 : 2050-val*50;
-}
-
 #define DIV_FROM_REG(val) (1 << (val))
 
 /* There are some complications in a module like this. First off, LM78 chips
@@ -134,6 +130,7 @@ static inline int VID_FROM_REG(u8 val)
    allocated. */
 struct lm78_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore lock;
        enum chips type;
 
@@ -156,6 +153,7 @@ struct lm78_data {
 
 
 static int lm78_attach_adapter(struct i2c_adapter *adapter);
+static int lm78_isa_attach_adapter(struct i2c_adapter *adapter);
 static int lm78_detect(struct i2c_adapter *adapter, int address, int kind);
 static int lm78_detach_client(struct i2c_client *client);
 
@@ -174,6 +172,14 @@ static struct i2c_driver lm78_driver = {
        .detach_client  = lm78_detach_client,
 };
 
+static struct i2c_driver lm78_isa_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "lm78-isa",
+       .attach_adapter = lm78_isa_attach_adapter,
+       .detach_client  = lm78_detach_client,
+};
+
+
 /* 7 Voltages */
 static ssize_t show_in(struct device *dev, char *buf, int nr)
 {
@@ -445,7 +451,7 @@ static DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_3_div, NULL);
 static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct lm78_data *data = lm78_update_device(dev);
-       return sprintf(buf, "%d\n", VID_FROM_REG(data->vid));
+       return sprintf(buf, "%d\n", vid_from_reg(82, data->vid));
 }
 static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
 
@@ -465,10 +471,15 @@ static int lm78_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, lm78_detect);
+       return i2c_probe(adapter, &addr_data, lm78_detect);
+}
+
+static int lm78_isa_attach_adapter(struct i2c_adapter *adapter)
+{
+       return lm78_detect(adapter, isa_address, -1);
 }
 
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
 int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
 {
        int i, err;
@@ -485,7 +496,8 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
 
        /* Reserve the ISA region */
        if (is_isa)
-               if (!request_region(address, LM78_EXTENT, lm78_driver.name)) {
+               if (!request_region(address, LM78_EXTENT,
+                                   lm78_isa_driver.name)) {
                        err = -EBUSY;
                        goto ERROR0;
                }
@@ -540,7 +552,7 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
        i2c_set_clientdata(new_client, data);
        new_client->addr = address;
        new_client->adapter = adapter;
-       new_client->driver = &lm78_driver;
+       new_client->driver = is_isa ? &lm78_isa_driver : &lm78_driver;
        new_client->flags = 0;
 
        /* Now, we do the remaining detection. */
@@ -559,10 +571,9 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
        /* Determine the chip type. */
        if (kind <= 0) {
                i = lm78_read_value(new_client, LM78_REG_CHIPID);
-               if (i == 0x00 || i == 0x20)
+               if (i == 0x00 || i == 0x20      /* LM78 */
+                || i == 0x40)                  /* LM78-J */
                        kind = lm78;
-               else if (i == 0x40)
-                       kind = lm78j;
                else if ((i & 0xfe) == 0xc0)
                        kind = lm79;
                else {
@@ -578,8 +589,6 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
 
        if (kind == lm78) {
                client_name = "lm78";
-       } else if (kind == lm78j) {
-               client_name = "lm78-j";
        } else if (kind == lm79) {
                client_name = "lm79";
        }
@@ -605,6 +614,12 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
        }
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto ERROR3;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_in0_input);
        device_create_file(&new_client->dev, &dev_attr_in0_min);
        device_create_file(&new_client->dev, &dev_attr_in0_max);
@@ -643,6 +658,8 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+ERROR3:
+       i2c_detach_client(new_client);
 ERROR2:
        kfree(data);
 ERROR1:
@@ -654,18 +671,18 @@ ERROR0:
 
 static int lm78_detach_client(struct i2c_client *client)
 {
+       struct lm78_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev,
-                   "Client deregistration failed, client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
        if(i2c_is_isa_client(client))
                release_region(client->addr, LM78_EXTENT);
 
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
 
        return 0;
 }
@@ -777,18 +794,31 @@ static struct lm78_data *lm78_update_device(struct device *dev)
 
 static int __init sm_lm78_init(void)
 {
-       return i2c_add_driver(&lm78_driver);
+       int res;
+
+       res = i2c_add_driver(&lm78_driver);
+       if (res)
+               return res;
+
+       res = i2c_isa_add_driver(&lm78_isa_driver);
+       if (res) {
+               i2c_del_driver(&lm78_driver);
+               return res;
+       }
+
+       return 0;
 }
 
 static void __exit sm_lm78_exit(void)
 {
+       i2c_isa_del_driver(&lm78_isa_driver);
        i2c_del_driver(&lm78_driver);
 }
 
 
 
 MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
-MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver");
+MODULE_DESCRIPTION("LM78/LM79 driver");
 MODULE_LICENSE("GPL");
 
 module_init(sm_lm78_init);
index 8100595feb44640133c6ae6aa7308839f35c7711..83af8b3a0cac02ba04ef70f1ec4b8f118de210b5 100644 (file)
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c,
                                        0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
-SENSORS_INSMOD_1(lm80);
+I2C_CLIENT_INSMOD_1(lm80);
 
 /* Many LM80 constants specified below */
 
@@ -107,6 +107,7 @@ static inline long TEMP_FROM_REG(u16 temp)
 
 struct lm80_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore update_lock;
        char valid;             /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
@@ -389,7 +390,7 @@ static int lm80_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, lm80_detect);
+       return i2c_probe(adapter, &addr_data, lm80_detect);
 }
 
 int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -451,6 +452,12 @@ int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
        data->fan_min[1] = lm80_read_value(new_client, LM80_REG_FAN_MIN(2));
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto error_detach;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_in0_min);
        device_create_file(&new_client->dev, &dev_attr_in1_min);
        device_create_file(&new_client->dev, &dev_attr_in2_min);
@@ -487,6 +494,8 @@ int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+error_detach:
+       i2c_detach_client(new_client);
 error_free:
        kfree(data);
 exit:
@@ -495,15 +504,15 @@ exit:
 
 static int lm80_detach_client(struct i2c_client *client)
 {
+       struct lm80_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                       "client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
index a49008b444c8ef483f3e6ec933578c3a9e57e240..d74b2c20c719376eea2c8231938f66be28a5f9d8 100644 (file)
@@ -32,8 +32,9 @@
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
 #include <linux/hwmon-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
 
 /*
  * Addresses to scan
@@ -45,13 +46,12 @@ static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
                                        0x29, 0x2a, 0x2b,
                                        0x4c, 0x4d, 0x4e,
                                        I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /*
  * Insmod parameters
  */
 
-SENSORS_INSMOD_1(lm83);
+I2C_CLIENT_INSMOD_1(lm83);
 
 /*
  * The LM83 registers
@@ -138,6 +138,7 @@ static struct i2c_driver lm83_driver = {
 
 struct lm83_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
@@ -212,7 +213,7 @@ static int lm83_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, lm83_detect);
+       return i2c_probe(adapter, &addr_data, lm83_detect);
 }
 
 /*
@@ -312,6 +313,12 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
         */
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file(&new_client->dev,
                           &sensor_dev_attr_temp1_input.dev_attr);
        device_create_file(&new_client->dev,
@@ -340,6 +347,8 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+exit_detach:
+       i2c_detach_client(new_client);
 exit_free:
        kfree(data);
 exit:
@@ -348,15 +357,15 @@ exit:
 
 static int lm83_detach_client(struct i2c_client *client)
 {
+       struct lm83_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev,
-                   "Client deregistration failed, client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
index b4d7fd41826478a241d50535a70bbbf0507c8de4..ab214df9624bc423376bef632b4a87d0d1f2cf96 100644 (file)
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
-SENSORS_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
+I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
 
 /* The LM85 registers */
 
@@ -281,15 +281,6 @@ static int ZONE_TO_REG( int zone )
 #define PPR_TO_REG(val,fan) (SENSORS_LIMIT((val)-1,0,3)<<(fan *2))
 #define PPR_FROM_REG(val,fan) ((((val)>>(fan * 2))&0x03)+1)
 
-/* i2c-vid.h defines vid_from_reg() */
-#define VID_FROM_REG(val,vrm) (vid_from_reg((val),(vrm)))
-
-/* Unlike some other drivers we DO NOT set initial limits.  Use
- * the config file to set limits.  Some users have reported
- * motherboards shutting down when we set limits in a previous
- * version of the driver.
- */
-
 /* Chip sampling rates
  *
  * Some sensors are not updated more frequently than once per second
@@ -339,6 +330,7 @@ struct lm85_autofan {
 
 struct lm85_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore lock;
        enum chips type;
 
@@ -1019,7 +1011,7 @@ int lm85_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, lm85_detect);
+       return i2c_probe(adapter, &addr_data, lm85_detect);
 }
 
 int lm85_detect(struct i2c_adapter *adapter, int address,
@@ -1031,11 +1023,6 @@ int lm85_detect(struct i2c_adapter *adapter, int address,
        int err = 0;
        const char *type_name = "";
 
-       if (i2c_is_isa_adapter(adapter)) {
-               /* This chip has no ISA interface */
-               goto ERROR0 ;
-       };
-
        if (!i2c_check_functionality(adapter,
                                        I2C_FUNC_SMBUS_BYTE_DATA)) {
                /* We need to be able to do byte I/O */
@@ -1160,12 +1147,18 @@ int lm85_detect(struct i2c_adapter *adapter, int address,
                goto ERROR1;
 
        /* Set the VRM version */
-       data->vrm = i2c_which_vrm();
+       data->vrm = vid_which_vrm();
 
        /* Initialize the LM85 chip */
        lm85_init_client(new_client);
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto ERROR2;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_fan1_input);
        device_create_file(&new_client->dev, &dev_attr_fan2_input);
        device_create_file(&new_client->dev, &dev_attr_fan3_input);
@@ -1235,6 +1228,8 @@ int lm85_detect(struct i2c_adapter *adapter, int address,
        return 0;
 
        /* Error out and cleanup code */
+    ERROR2:
+       i2c_detach_client(new_client);
     ERROR1:
        kfree(data);
     ERROR0:
@@ -1243,8 +1238,10 @@ int lm85_detect(struct i2c_adapter *adapter, int address,
 
 int lm85_detach_client(struct i2c_client *client)
 {
+       struct lm85_data *data = i2c_get_clientdata(client);
+       hwmon_device_unregister(data->class_dev);
        i2c_detach_client(client);
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
index 1921ed1af182df9f05dc68b114e7115f51009bea..dca996de4c331e5eae87c3a868fb47c46ca9b3e6 100644 (file)
@@ -57,8 +57,9 @@
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
 
 /*
  * Addresses to scan
  */
 
 static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /*
  * Insmod parameters
  */
 
-SENSORS_INSMOD_1(lm87);
+I2C_CLIENT_INSMOD_1(lm87);
 
 /*
  * The LM87 registers
@@ -175,6 +175,7 @@ static struct i2c_driver lm87_driver = {
 
 struct lm87_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* In jiffies */
@@ -537,7 +538,7 @@ static int lm87_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, lm87_detect);
+       return i2c_probe(adapter, &addr_data, lm87_detect);
 }
 
 /*
@@ -608,6 +609,12 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
        data->in_scale[7] = 1875;
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_in1_input);
        device_create_file(&new_client->dev, &dev_attr_in1_min);
        device_create_file(&new_client->dev, &dev_attr_in1_max);
@@ -673,6 +680,8 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+exit_detach:
+       i2c_detach_client(new_client);
 exit_free:
        kfree(data);
 exit:
@@ -685,7 +694,7 @@ static void lm87_init_client(struct i2c_client *client)
        u8 config;
 
        data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE);
-       data->vrm = i2c_which_vrm();
+       data->vrm = vid_which_vrm();
 
        config = lm87_read_value(client, LM87_REG_CONFIG);
        if (!(config & 0x01)) {
@@ -719,15 +728,15 @@ static void lm87_init_client(struct i2c_client *client)
 
 static int lm87_detach_client(struct i2c_client *client)
 {
+       struct lm87_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                       "client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
index a67dcadf7cb04381882b71185786fa1c945677d2..14de05fcd431e76c87c4a7ffc2e65c4d1e1252a4 100644 (file)
@@ -75,8 +75,9 @@
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
 #include <linux/hwmon-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
 
 /*
  * Addresses to scan
  */
 
 static unsigned short normal_i2c[] = { 0x4c, 0x4d, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /*
  * Insmod parameters
  */
 
-SENSORS_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461);
+I2C_CLIENT_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461);
 
 /*
  * The LM90 registers
@@ -200,6 +200,7 @@ static struct i2c_driver lm90_driver = {
 
 struct lm90_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
@@ -352,7 +353,7 @@ static int lm90_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, lm90_detect);
+       return i2c_probe(adapter, &addr_data, lm90_detect);
 }
 
 /*
@@ -500,6 +501,12 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
        lm90_init_client(new_client);
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file(&new_client->dev,
                           &sensor_dev_attr_temp1_input.dev_attr);
        device_create_file(&new_client->dev,
@@ -524,6 +531,8 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+exit_detach:
+       i2c_detach_client(new_client);
 exit_free:
        kfree(data);
 exit:
@@ -547,15 +556,15 @@ static void lm90_init_client(struct i2c_client *client)
 
 static int lm90_detach_client(struct i2c_client *client)
 {
+       struct lm90_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                       "client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
index 215c8e40ffdd4041e114aa7912f93e9292b61be3..647b7c7cd575df129ed9ed7bbb7535e2d1422232 100644 (file)
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-
+#include <linux/hwmon.h>
+#include <linux/err.h>
 
 /* The LM92 and MAX6635 have 2 two-state pins for address selection,
    resulting in 4 possible addresses. */
 static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
                                       I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
-SENSORS_INSMOD_1(lm92);
+I2C_CLIENT_INSMOD_1(lm92);
 
 /* The LM92 registers */
 #define LM92_REG_CONFIG                        0x01 /* 8-bit, RW */
@@ -96,6 +95,7 @@ static struct i2c_driver lm92_driver;
 /* Client data (each client gets its own) */
 struct lm92_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
@@ -359,6 +359,12 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
        lm92_init_client(new_client);
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_temp1_input);
        device_create_file(&new_client->dev, &dev_attr_temp1_crit);
        device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
@@ -370,6 +376,8 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+exit_detach:
+       i2c_detach_client(new_client);
 exit_free:
        kfree(data);
 exit:
@@ -380,20 +388,20 @@ static int lm92_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, lm92_detect);
+       return i2c_probe(adapter, &addr_data, lm92_detect);
 }
 
 static int lm92_detach_client(struct i2c_client *client)
 {
+       struct lm92_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                       "client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
index 3c159f1d49ee3e6e0bf6b8acd5ccbfa8093ec938..16bf71f3a04d941f92391e64f8a6980b2e903315 100644 (file)
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-
+#include <linux/hwmon.h>
+#include <linux/err.h>
 
 static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
                                        0x29, 0x2a, 0x2b,
                                        0x4c, 0x4d, 0x4e,
                                        I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /*
  * Insmod parameters
  */
 
-SENSORS_INSMOD_1(max1619);
+I2C_CLIENT_INSMOD_1(max1619);
 
 /*
  * The MAX1619 registers
@@ -104,6 +103,7 @@ static struct i2c_driver max1619_driver = {
 
 struct max1619_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
@@ -179,7 +179,7 @@ static int max1619_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, max1619_detect);
+       return i2c_probe(adapter, &addr_data, max1619_detect);
 }
 
 /*
@@ -275,6 +275,12 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
        max1619_init_client(new_client);
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_temp1_input);
        device_create_file(&new_client->dev, &dev_attr_temp2_input);
        device_create_file(&new_client->dev, &dev_attr_temp2_min);
@@ -285,6 +291,8 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+exit_detach:
+       i2c_detach_client(new_client);
 exit_free:
        kfree(data);
 exit:
@@ -308,15 +316,15 @@ static void max1619_init_client(struct i2c_client *client)
 
 static int max1619_detach_client(struct i2c_client *client)
 {
+       struct max1619_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                       "client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
index fa4032d53b790b3e08dd6fdf6d730e4258ae05e5..cf2a35799c7ce5939744ba91adf5b23a24a9289e 100644 (file)
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
 #include <asm/io.h>
 
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END };
-static struct i2c_force_data forces[] = {{ NULL }};
 static u8 devid;
-static unsigned int extra_isa[3];
+static unsigned short address;
+static unsigned short extra_isa[3];
 static u8 confreg[4];
 
 enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 };
-static struct i2c_address_data addr_data = {
-       .normal_i2c             = normal_i2c,
-       .normal_isa             = normal_isa,
-       .forces                 = forces,
-};
 
 static int init = 1;
 module_param(init, int, 0);
@@ -186,6 +182,7 @@ static inline u8 PWM_TO_REG(int val, int inv)
 
 struct pc87360_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore lock;
        struct semaphore update_lock;
        char valid;             /* !=0 if following fields are valid */
@@ -224,8 +221,7 @@ struct pc87360_data {
  * Functions declaration
  */
 
-static int pc87360_attach_adapter(struct i2c_adapter *adapter);
-static int pc87360_detect(struct i2c_adapter *adapter, int address, int kind);
+static int pc87360_detect(struct i2c_adapter *adapter);
 static int pc87360_detach_client(struct i2c_client *client);
 
 static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
@@ -242,8 +238,7 @@ static struct pc87360_data *pc87360_update_device(struct device *dev);
 static struct i2c_driver pc87360_driver = {
        .owner          = THIS_MODULE,
        .name           = "pc87360",
-       .flags          = I2C_DF_NOTIFY,
-       .attach_adapter = pc87360_attach_adapter,
+       .attach_adapter = pc87360_detect,
        .detach_client  = pc87360_detach_client,
 };
 
@@ -251,168 +246,178 @@ static struct i2c_driver pc87360_driver = {
  * Sysfs stuff
  */
 
-static ssize_t set_fan_min(struct device *dev, const char *buf,
-       size_t count, int nr)
+static ssize_t show_fan_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[attr->index],
+                      FAN_DIV_FROM_REG(data->fan_status[attr->index])));
+}
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[attr->index],
+                      FAN_DIV_FROM_REG(data->fan_status[attr->index])));
+}
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%u\n",
+                      FAN_DIV_FROM_REG(data->fan_status[attr->index]));
+}
+static ssize_t show_fan_status(struct device *dev, struct device_attribute *devattr, char *buf)
 {
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%u\n",
+                      FAN_STATUS_FROM_REG(data->fan_status[attr->index]));
+}
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *devattr, const char *buf,
+       size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct pc87360_data *data = i2c_get_clientdata(client);
        long fan_min = simple_strtol(buf, NULL, 10);
 
        down(&data->update_lock);
-       fan_min = FAN_TO_REG(fan_min, FAN_DIV_FROM_REG(data->fan_status[nr]));
+       fan_min = FAN_TO_REG(fan_min, FAN_DIV_FROM_REG(data->fan_status[attr->index]));
 
        /* If it wouldn't fit, change clock divisor */
        while (fan_min > 255
-           && (data->fan_status[nr] & 0x60) != 0x60) {
+           && (data->fan_status[attr->index] & 0x60) != 0x60) {
                fan_min >>= 1;
-               data->fan[nr] >>= 1;
-               data->fan_status[nr] += 0x20;
+               data->fan[attr->index] >>= 1;
+               data->fan_status[attr->index] += 0x20;
        }
-       data->fan_min[nr] = fan_min > 255 ? 255 : fan_min;
-       pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_MIN(nr),
-                           data->fan_min[nr]);
+       data->fan_min[attr->index] = fan_min > 255 ? 255 : fan_min;
+       pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_MIN(attr->index),
+                           data->fan_min[attr->index]);
 
        /* Write new divider, preserve alarm bits */
-       pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(nr),
-                           data->fan_status[nr] & 0xF9);
+       pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(attr->index),
+                           data->fan_status[attr->index] & 0xF9);
        up(&data->update_lock);
 
        return count;
 }
 
 #define show_and_set_fan(offset) \
-static ssize_t show_fan##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[offset-1], \
-                      FAN_DIV_FROM_REG(data->fan_status[offset-1]))); \
-} \
-static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[offset-1], \
-                      FAN_DIV_FROM_REG(data->fan_status[offset-1]))); \
-} \
-static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%u\n", \
-                      FAN_DIV_FROM_REG(data->fan_status[offset-1])); \
-} \
-static ssize_t show_fan##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%u\n", \
-                      FAN_STATUS_FROM_REG(data->fan_status[offset-1])); \
-} \
-static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \
-       size_t count) \
-{ \
-       return set_fan_min(dev, buf, count, offset-1); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
-       show_fan##offset##_input, NULL); \
-static DEVICE_ATTR(fan##offset##_min, S_IWUSR | S_IRUGO, \
-       show_fan##offset##_min, set_fan##offset##_min); \
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \
-       show_fan##offset##_div, NULL); \
-static DEVICE_ATTR(fan##offset##_status, S_IRUGO, \
-       show_fan##offset##_status, NULL);
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+       show_fan_input, NULL, offset-1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IWUSR | S_IRUGO, \
+       show_fan_min, set_fan_min, offset-1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO, \
+       show_fan_div, NULL, offset-1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_status, S_IRUGO, \
+       show_fan_status, NULL, offset-1);
 show_and_set_fan(1)
 show_and_set_fan(2)
 show_and_set_fan(3)
 
+static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%u\n",
+                      PWM_FROM_REG(data->pwm[attr->index],
+                                   FAN_CONFIG_INVERT(data->fan_conf,
+                                                     attr->index)));
+}
+static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, const char *buf,
+       size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct pc87360_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+
+       down(&data->update_lock);
+       data->pwm[attr->index] = PWM_TO_REG(val,
+                             FAN_CONFIG_INVERT(data->fan_conf, attr->index));
+       pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(attr->index),
+                           data->pwm[attr->index]);
+       up(&data->update_lock);
+       return count;
+}
+
 #define show_and_set_pwm(offset) \
-static ssize_t show_pwm##offset(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%u\n", \
-                      PWM_FROM_REG(data->pwm[offset-1], \
-                                   FAN_CONFIG_INVERT(data->fan_conf, \
-                                                     offset-1))); \
-} \
-static ssize_t set_pwm##offset(struct device *dev, struct device_attribute *attr, const char *buf, \
-       size_t count) \
-{ \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct pc87360_data *data = i2c_get_clientdata(client); \
-       long val = simple_strtol(buf, NULL, 10); \
- \
-       down(&data->update_lock); \
-       data->pwm[offset-1] = PWM_TO_REG(val, \
-                             FAN_CONFIG_INVERT(data->fan_conf, offset-1)); \
-       pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(offset-1), \
-                           data->pwm[offset-1]); \
-       up(&data->update_lock); \
-       return count; \
-} \
-static DEVICE_ATTR(pwm##offset, S_IWUSR | S_IRUGO, \
-       show_pwm##offset, set_pwm##offset);
+static SENSOR_DEVICE_ATTR(pwm##offset, S_IWUSR | S_IRUGO, \
+       show_pwm, set_pwm, offset-1);
 show_and_set_pwm(1)
 show_and_set_pwm(2)
 show_and_set_pwm(3)
 
+static ssize_t show_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in[attr->index],
+                      data->in_vref));
+}
+static ssize_t show_in_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index],
+                      data->in_vref));
+}
+static ssize_t show_in_max(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index],
+                      data->in_vref));
+}
+static ssize_t show_in_status(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%u\n", data->in_status[attr->index]);
+}
+static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr, const char *buf,
+       size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct pc87360_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+
+       down(&data->update_lock);
+       data->in_min[attr->index] = IN_TO_REG(val, data->in_vref);
+       pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_IN_MIN,
+                           data->in_min[attr->index]);
+       up(&data->update_lock);
+       return count;
+}
+static ssize_t set_in_max(struct device *dev, struct device_attribute *devattr, const char *buf,
+       size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct pc87360_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+
+       down(&data->update_lock);
+       data->in_max[attr->index] = IN_TO_REG(val,
+                              data->in_vref);
+       pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_IN_MAX,
+                           data->in_max[attr->index]);
+       up(&data->update_lock);
+       return count;
+}
+
 #define show_and_set_in(offset) \
-static ssize_t show_in##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \
-                      data->in_vref)); \
-} \
-static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \
-                      data->in_vref)); \
-} \
-static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \
-                      data->in_vref)); \
-} \
-static ssize_t show_in##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%u\n", data->in_status[offset]); \
-} \
-static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \
-       size_t count) \
-{ \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct pc87360_data *data = i2c_get_clientdata(client); \
-       long val = simple_strtol(buf, NULL, 10); \
- \
-       down(&data->update_lock); \
-       data->in_min[offset] = IN_TO_REG(val, data->in_vref); \
-       pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MIN, \
-                           data->in_min[offset]); \
-       up(&data->update_lock); \
-       return count; \
-} \
-static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \
-       size_t count) \
-{ \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct pc87360_data *data = i2c_get_clientdata(client); \
-       long val = simple_strtol(buf, NULL, 10); \
- \
-       down(&data->update_lock); \
-       data->in_max[offset] = IN_TO_REG(val, \
-                              data->in_vref); \
-       pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MAX, \
-                           data->in_max[offset]); \
-       up(&data->update_lock); \
-       return count; \
-} \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
-       show_in##offset##_input, NULL); \
-static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \
-       show_in##offset##_min, set_in##offset##_min); \
-static DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \
-       show_in##offset##_max, set_in##offset##_max); \
-static DEVICE_ATTR(in##offset##_status, S_IRUGO, \
-       show_in##offset##_status, NULL);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+       show_in_input, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \
+       show_in_min, set_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \
+       show_in_max, set_in_max, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_status, S_IRUGO, \
+       show_in_status, NULL, offset);
 show_and_set_in(0)
 show_and_set_in(1)
 show_and_set_in(2)
@@ -425,88 +430,97 @@ show_and_set_in(8)
 show_and_set_in(9)
 show_and_set_in(10)
 
+static ssize_t show_therm_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in[attr->index],
+                      data->in_vref));
+}
+static ssize_t show_therm_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index],
+                      data->in_vref));
+}
+static ssize_t show_therm_max(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index],
+                      data->in_vref));
+}
+static ssize_t show_therm_crit(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[attr->index-11],
+                      data->in_vref));
+}
+static ssize_t show_therm_status(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%u\n", data->in_status[attr->index]);
+}
+static ssize_t set_therm_min(struct device *dev, struct device_attribute *devattr, const char *buf,
+       size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct pc87360_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+
+       down(&data->update_lock);
+       data->in_min[attr->index] = IN_TO_REG(val, data->in_vref);
+       pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_MIN,
+                           data->in_min[attr->index]);
+       up(&data->update_lock);
+       return count;
+}
+static ssize_t set_therm_max(struct device *dev, struct device_attribute *devattr, const char *buf,
+       size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct pc87360_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+
+       down(&data->update_lock);
+       data->in_max[attr->index] = IN_TO_REG(val, data->in_vref);
+       pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_MAX,
+                           data->in_max[attr->index]);
+       up(&data->update_lock);
+       return count;
+}
+static ssize_t set_therm_crit(struct device *dev, struct device_attribute *devattr, const char *buf,
+       size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct pc87360_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+
+       down(&data->update_lock);
+       data->in_crit[attr->index-11] = IN_TO_REG(val, data->in_vref);
+       pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_CRIT,
+                           data->in_crit[attr->index-11]);
+       up(&data->update_lock);
+       return count;
+}
+
 #define show_and_set_therm(offset) \
-static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset+7], \
-                      data->in_vref)); \
-} \
-static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset+7], \
-                      data->in_vref)); \
-} \
-static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset+7], \
-                      data->in_vref)); \
-} \
-static ssize_t show_temp##offset##_crit(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[offset-4], \
-                      data->in_vref)); \
-} \
-static ssize_t show_temp##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%u\n", data->in_status[offset+7]); \
-} \
-static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \
-       size_t count) \
-{ \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct pc87360_data *data = i2c_get_clientdata(client); \
-       long val = simple_strtol(buf, NULL, 10); \
- \
-       down(&data->update_lock); \
-       data->in_min[offset+7] = IN_TO_REG(val, data->in_vref); \
-       pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MIN, \
-                           data->in_min[offset+7]); \
-       up(&data->update_lock); \
-       return count; \
-} \
-static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \
-       size_t count) \
-{ \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct pc87360_data *data = i2c_get_clientdata(client); \
-       long val = simple_strtol(buf, NULL, 10); \
- \
-       down(&data->update_lock); \
-       data->in_max[offset+7] = IN_TO_REG(val, data->in_vref); \
-       pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MAX, \
-                           data->in_max[offset+7]); \
-       up(&data->update_lock); \
-       return count; \
-} \
-static ssize_t set_temp##offset##_crit(struct device *dev, struct device_attribute *attr, const char *buf, \
-       size_t count) \
-{ \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct pc87360_data *data = i2c_get_clientdata(client); \
-       long val = simple_strtol(buf, NULL, 10); \
- \
-       down(&data->update_lock); \
-       data->in_crit[offset-4] = IN_TO_REG(val, data->in_vref); \
-       pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_CRIT, \
-                           data->in_crit[offset-4]); \
-       up(&data->update_lock); \
-       return count; \
-} \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
-       show_temp##offset##_input, NULL); \
-static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
-       show_temp##offset##_min, set_temp##offset##_min); \
-static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
-       show_temp##offset##_max, set_temp##offset##_max); \
-static DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \
-       show_temp##offset##_crit, set_temp##offset##_crit); \
-static DEVICE_ATTR(temp##offset##_status, S_IRUGO, \
-       show_temp##offset##_status, NULL);
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+       show_therm_input, NULL, 11+offset-4); \
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
+       show_therm_min, set_therm_min, 11+offset-4); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
+       show_therm_max, set_therm_max, 11+offset-4); \
+static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \
+       show_therm_crit, set_therm_crit, 11+offset-4); \
+static SENSOR_DEVICE_ATTR(temp##offset##_status, S_IRUGO, \
+       show_therm_status, NULL, 11+offset-4);
 show_and_set_therm(4)
 show_and_set_therm(5)
 show_and_set_therm(6)
@@ -539,84 +553,93 @@ static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL);
 
+static ssize_t show_temp_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
+}
+static ssize_t show_temp_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[attr->index]));
+}
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[attr->index]));
+}
+static ssize_t show_temp_crit(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[attr->index]));
+}
+static ssize_t show_temp_status(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%d\n", data->temp_status[attr->index]);
+}
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *devattr, const char *buf,
+       size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct pc87360_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+
+       down(&data->update_lock);
+       data->temp_min[attr->index] = TEMP_TO_REG(val);
+       pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_MIN,
+                           data->temp_min[attr->index]);
+       up(&data->update_lock);
+       return count;
+}
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *devattr, const char *buf,
+       size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct pc87360_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+
+       down(&data->update_lock);
+       data->temp_max[attr->index] = TEMP_TO_REG(val);
+       pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_MAX,
+                           data->temp_max[attr->index]);
+       up(&data->update_lock);
+       return count;
+}
+static ssize_t set_temp_crit(struct device *dev, struct device_attribute *devattr, const char *buf,
+       size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct pc87360_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+
+       down(&data->update_lock);
+       data->temp_crit[attr->index] = TEMP_TO_REG(val);
+       pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_CRIT,
+                           data->temp_crit[attr->index]);
+       up(&data->update_lock);
+       return count;
+}
+
 #define show_and_set_temp(offset) \
-static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \
-} \
-static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[offset-1])); \
-} \
-static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[offset-1])); \
-}\
-static ssize_t show_temp##offset##_crit(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[offset-1])); \
-}\
-static ssize_t show_temp##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct pc87360_data *data = pc87360_update_device(dev); \
-       return sprintf(buf, "%d\n", data->temp_status[offset-1]); \
-}\
-static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \
-       size_t count) \
-{ \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct pc87360_data *data = i2c_get_clientdata(client); \
-       long val = simple_strtol(buf, NULL, 10); \
- \
-       down(&data->update_lock); \
-       data->temp_min[offset-1] = TEMP_TO_REG(val); \
-       pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MIN, \
-                           data->temp_min[offset-1]); \
-       up(&data->update_lock); \
-       return count; \
-} \
-static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \
-       size_t count) \
-{ \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct pc87360_data *data = i2c_get_clientdata(client); \
-       long val = simple_strtol(buf, NULL, 10); \
- \
-       down(&data->update_lock); \
-       data->temp_max[offset-1] = TEMP_TO_REG(val); \
-       pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MAX, \
-                           data->temp_max[offset-1]); \
-       up(&data->update_lock); \
-       return count; \
-} \
-static ssize_t set_temp##offset##_crit(struct device *dev, struct device_attribute *attr, const char *buf, \
-       size_t count) \
-{ \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct pc87360_data *data = i2c_get_clientdata(client); \
-       long val = simple_strtol(buf, NULL, 10); \
- \
-       down(&data->update_lock); \
-       data->temp_crit[offset-1] = TEMP_TO_REG(val); \
-       pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_CRIT, \
-                           data->temp_crit[offset-1]); \
-       up(&data->update_lock); \
-       return count; \
-} \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
-       show_temp##offset##_input, NULL); \
-static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
-       show_temp##offset##_min, set_temp##offset##_min); \
-static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
-       show_temp##offset##_max, set_temp##offset##_max); \
-static DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \
-       show_temp##offset##_crit, set_temp##offset##_crit); \
-static DEVICE_ATTR(temp##offset##_status, S_IRUGO, \
-       show_temp##offset##_status, NULL);
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+       show_temp_input, NULL, offset-1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
+       show_temp_min, set_temp_min, offset-1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
+       show_temp_max, set_temp_max, offset-1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \
+       show_temp_crit, set_temp_crit, offset-1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_status, S_IRUGO, \
+       show_temp_status, NULL, offset-1);
 show_and_set_temp(1)
 show_and_set_temp(2)
 show_and_set_temp(3)
@@ -632,12 +655,7 @@ static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL);
  * Device detection, registration and update
  */
 
-static int pc87360_attach_adapter(struct i2c_adapter *adapter)
-{
-       return i2c_detect(adapter, &addr_data, pc87360_detect);
-}
-
-static int pc87360_find(int sioaddr, u8 *devid, int *address)
+static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses)
 {
        u16 val;
        int i;
@@ -683,7 +701,7 @@ static int pc87360_find(int sioaddr, u8 *devid, int *address)
                        continue;
                }
 
-               address[i] = val;
+               addresses[i] = val;
 
                if (i==0) { /* Fans */
                        confreg[0] = superio_inb(sioaddr, 0xF0);
@@ -727,9 +745,7 @@ static int pc87360_find(int sioaddr, u8 *devid, int *address)
        return 0;
 }
 
-/* We don't really care about the address.
-   Read from extra_isa instead. */
-int pc87360_detect(struct i2c_adapter *adapter, int address, int kind)
+static int pc87360_detect(struct i2c_adapter *adapter)
 {
        int i;
        struct i2c_client *new_client;
@@ -738,9 +754,6 @@ int pc87360_detect(struct i2c_adapter *adapter, int address, int kind)
        const char *name = "pc87360";
        int use_thermistors = 0;
 
-       if (!i2c_is_isa_adapter(adapter))
-               return -ENODEV;
-
        if (!(data = kmalloc(sizeof(struct pc87360_data), GFP_KERNEL)))
                return -ENOMEM;
        memset(data, 0x00, sizeof(struct pc87360_data));
@@ -838,51 +851,57 @@ int pc87360_detect(struct i2c_adapter *adapter, int address, int kind)
        }
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto ERROR3;
+       }
+
        if (data->innr) {
-               device_create_file(&new_client->dev, &dev_attr_in0_input);
-               device_create_file(&new_client->dev, &dev_attr_in1_input);
-               device_create_file(&new_client->dev, &dev_attr_in2_input);
-               device_create_file(&new_client->dev, &dev_attr_in3_input);
-               device_create_file(&new_client->dev, &dev_attr_in4_input);
-               device_create_file(&new_client->dev, &dev_attr_in5_input);
-               device_create_file(&new_client->dev, &dev_attr_in6_input);
-               device_create_file(&new_client->dev, &dev_attr_in7_input);
-               device_create_file(&new_client->dev, &dev_attr_in8_input);
-               device_create_file(&new_client->dev, &dev_attr_in9_input);
-               device_create_file(&new_client->dev, &dev_attr_in10_input);
-               device_create_file(&new_client->dev, &dev_attr_in0_min);
-               device_create_file(&new_client->dev, &dev_attr_in1_min);
-               device_create_file(&new_client->dev, &dev_attr_in2_min);
-               device_create_file(&new_client->dev, &dev_attr_in3_min);
-               device_create_file(&new_client->dev, &dev_attr_in4_min);
-               device_create_file(&new_client->dev, &dev_attr_in5_min);
-               device_create_file(&new_client->dev, &dev_attr_in6_min);
-               device_create_file(&new_client->dev, &dev_attr_in7_min);
-               device_create_file(&new_client->dev, &dev_attr_in8_min);
-               device_create_file(&new_client->dev, &dev_attr_in9_min);
-               device_create_file(&new_client->dev, &dev_attr_in10_min);
-               device_create_file(&new_client->dev, &dev_attr_in0_max);
-               device_create_file(&new_client->dev, &dev_attr_in1_max);
-               device_create_file(&new_client->dev, &dev_attr_in2_max);
-               device_create_file(&new_client->dev, &dev_attr_in3_max);
-               device_create_file(&new_client->dev, &dev_attr_in4_max);
-               device_create_file(&new_client->dev, &dev_attr_in5_max);
-               device_create_file(&new_client->dev, &dev_attr_in6_max);
-               device_create_file(&new_client->dev, &dev_attr_in7_max);
-               device_create_file(&new_client->dev, &dev_attr_in8_max);
-               device_create_file(&new_client->dev, &dev_attr_in9_max);
-               device_create_file(&new_client->dev, &dev_attr_in10_max);
-               device_create_file(&new_client->dev, &dev_attr_in0_status);
-               device_create_file(&new_client->dev, &dev_attr_in1_status);
-               device_create_file(&new_client->dev, &dev_attr_in2_status);
-               device_create_file(&new_client->dev, &dev_attr_in3_status);
-               device_create_file(&new_client->dev, &dev_attr_in4_status);
-               device_create_file(&new_client->dev, &dev_attr_in5_status);
-               device_create_file(&new_client->dev, &dev_attr_in6_status);
-               device_create_file(&new_client->dev, &dev_attr_in7_status);
-               device_create_file(&new_client->dev, &dev_attr_in8_status);
-               device_create_file(&new_client->dev, &dev_attr_in9_status);
-               device_create_file(&new_client->dev, &dev_attr_in10_status);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in9_input.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in10_input.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in8_min.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in9_min.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in10_min.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in8_max.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in9_max.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in10_max.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in0_status.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in1_status.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in2_status.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in3_status.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in4_status.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in5_status.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in6_status.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in7_status.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in8_status.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in9_status.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_in10_status.dev_attr);
 
                device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
                device_create_file(&new_client->dev, &dev_attr_vrm);
@@ -890,90 +909,92 @@ int pc87360_detect(struct i2c_adapter *adapter, int address, int kind)
        }
 
        if (data->tempnr) {
-               device_create_file(&new_client->dev, &dev_attr_temp1_input);
-               device_create_file(&new_client->dev, &dev_attr_temp2_input);
-               device_create_file(&new_client->dev, &dev_attr_temp1_min);
-               device_create_file(&new_client->dev, &dev_attr_temp2_min);
-               device_create_file(&new_client->dev, &dev_attr_temp1_max);
-               device_create_file(&new_client->dev, &dev_attr_temp2_max);
-               device_create_file(&new_client->dev, &dev_attr_temp1_crit);
-               device_create_file(&new_client->dev, &dev_attr_temp2_crit);
-               device_create_file(&new_client->dev, &dev_attr_temp1_status);
-               device_create_file(&new_client->dev, &dev_attr_temp2_status);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp1_crit.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp2_crit.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp1_status.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp2_status.dev_attr);
 
                device_create_file(&new_client->dev, &dev_attr_alarms_temp);
        }
        if (data->tempnr == 3) {
-               device_create_file(&new_client->dev, &dev_attr_temp3_input);
-               device_create_file(&new_client->dev, &dev_attr_temp3_min);
-               device_create_file(&new_client->dev, &dev_attr_temp3_max);
-               device_create_file(&new_client->dev, &dev_attr_temp3_crit);
-               device_create_file(&new_client->dev, &dev_attr_temp3_status);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp3_crit.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp3_status.dev_attr);
        }
        if (data->innr == 14) {
-               device_create_file(&new_client->dev, &dev_attr_temp4_input);
-               device_create_file(&new_client->dev, &dev_attr_temp5_input);
-               device_create_file(&new_client->dev, &dev_attr_temp6_input);
-               device_create_file(&new_client->dev, &dev_attr_temp4_min);
-               device_create_file(&new_client->dev, &dev_attr_temp5_min);
-               device_create_file(&new_client->dev, &dev_attr_temp6_min);
-               device_create_file(&new_client->dev, &dev_attr_temp4_max);
-               device_create_file(&new_client->dev, &dev_attr_temp5_max);
-               device_create_file(&new_client->dev, &dev_attr_temp6_max);
-               device_create_file(&new_client->dev, &dev_attr_temp4_crit);
-               device_create_file(&new_client->dev, &dev_attr_temp5_crit);
-               device_create_file(&new_client->dev, &dev_attr_temp6_crit);
-               device_create_file(&new_client->dev, &dev_attr_temp4_status);
-               device_create_file(&new_client->dev, &dev_attr_temp5_status);
-               device_create_file(&new_client->dev, &dev_attr_temp6_status);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp4_input.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp5_input.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp6_input.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp4_min.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp5_min.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp6_min.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp4_max.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp5_max.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp6_max.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp4_crit.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp5_crit.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp6_crit.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp4_status.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp5_status.dev_attr);
+               device_create_file(&new_client->dev, &sensor_dev_attr_temp6_status.dev_attr);
        }
 
        if (data->fannr) {
                if (FAN_CONFIG_MONITOR(data->fan_conf, 0)) {
                        device_create_file(&new_client->dev,
-                                          &dev_attr_fan1_input);
+                                          &sensor_dev_attr_fan1_input.dev_attr);
                        device_create_file(&new_client->dev,
-                                          &dev_attr_fan1_min);
+                                          &sensor_dev_attr_fan1_min.dev_attr);
                        device_create_file(&new_client->dev,
-                                          &dev_attr_fan1_div);
+                                          &sensor_dev_attr_fan1_div.dev_attr);
                        device_create_file(&new_client->dev,
-                                          &dev_attr_fan1_status);
+                                          &sensor_dev_attr_fan1_status.dev_attr);
                }
 
                if (FAN_CONFIG_MONITOR(data->fan_conf, 1)) {
                        device_create_file(&new_client->dev,
-                                          &dev_attr_fan2_input);
+                                          &sensor_dev_attr_fan2_input.dev_attr);
                        device_create_file(&new_client->dev,
-                                          &dev_attr_fan2_min);
+                                          &sensor_dev_attr_fan2_min.dev_attr);
                        device_create_file(&new_client->dev,
-                                          &dev_attr_fan2_div);
+                                          &sensor_dev_attr_fan2_div.dev_attr);
                        device_create_file(&new_client->dev,
-                                          &dev_attr_fan2_status);
+                                          &sensor_dev_attr_fan2_status.dev_attr);
                }
 
                if (FAN_CONFIG_CONTROL(data->fan_conf, 0))
-                       device_create_file(&new_client->dev, &dev_attr_pwm1);
+                       device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr);
                if (FAN_CONFIG_CONTROL(data->fan_conf, 1))
-                       device_create_file(&new_client->dev, &dev_attr_pwm2);
+                       device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr);
        }
        if (data->fannr == 3) {
                if (FAN_CONFIG_MONITOR(data->fan_conf, 2)) {
                        device_create_file(&new_client->dev,
-                                          &dev_attr_fan3_input);
+                                          &sensor_dev_attr_fan3_input.dev_attr);
                        device_create_file(&new_client->dev,
-                                          &dev_attr_fan3_min);
+                                          &sensor_dev_attr_fan3_min.dev_attr);
                        device_create_file(&new_client->dev,
-                                          &dev_attr_fan3_div);
+                                          &sensor_dev_attr_fan3_div.dev_attr);
                        device_create_file(&new_client->dev,
-                                          &dev_attr_fan3_status);
+                                          &sensor_dev_attr_fan3_status.dev_attr);
                }
 
                if (FAN_CONFIG_CONTROL(data->fan_conf, 2))
-                       device_create_file(&new_client->dev, &dev_attr_pwm3);
+                       device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr);
        }
 
        return 0;
 
+ERROR3:
+       i2c_detach_client(new_client);
 ERROR2:
        for (i = 0; i < 3; i++) {
                if (data->address[i]) {
@@ -990,11 +1011,10 @@ static int pc87360_detach_client(struct i2c_client *client)
        struct pc87360_data *data = i2c_get_clientdata(client);
        int i;
 
-       if ((i = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                       "client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((i = i2c_detach_client(client)))
                return i;
-       }
 
        for (i = 0; i < 3; i++) {
                if (data->address[i]) {
@@ -1320,23 +1340,23 @@ static int __init pc87360_init(void)
        /* Arbitrarily pick one of the addresses */
        for (i = 0; i < 3; i++) {
                if (extra_isa[i] != 0x0000) {
-                       normal_isa[0] = extra_isa[i];
+                       address = extra_isa[i];
                        break;
                }
        }
 
-       if (normal_isa[0] == 0x0000) {
+       if (address == 0x0000) {
                printk(KERN_WARNING "pc87360: No active logical device, "
                       "module not inserted.\n");
                return -ENODEV;
        }
 
-       return i2c_add_driver(&pc87360_driver);
+       return i2c_isa_add_driver(&pc87360_driver);
 }
 
 static void __exit pc87360_exit(void)
 {
-       i2c_del_driver(&pc87360_driver);
+       i2c_isa_del_driver(&pc87360_driver);
 }
 
 
index 6bbfc8fb4f13247d61cedb2124a74b5df4589620..8610bce08244d1bb3f74dcca18ef48112c717073 100644 (file)
@@ -55,7 +55,9 @@
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/jiffies.h>
 #include <asm/io.h>
@@ -68,14 +70,10 @@ module_param(force_addr, ushort, 0);
 MODULE_PARM_DESC(force_addr,
                 "Initialize the base address of the sensors");
 
-/* Addresses to scan.
+/* Device address
    Note that we can't determine the ISA address until we have initialized
    our module */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END };
-
-/* Insmod parameters */
-SENSORS_INSMOD_1(sis5595);
+static unsigned short address;
 
 /* Many SIS5595 constants specified below */
 
@@ -168,6 +166,7 @@ static inline u8 DIV_TO_REG(int val)
    allocated. */
 struct sis5595_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore lock;
 
        struct semaphore update_lock;
@@ -190,8 +189,7 @@ struct sis5595_data {
 
 static struct pci_dev *s_bridge;       /* pointer to the (only) sis5595 */
 
-static int sis5595_attach_adapter(struct i2c_adapter *adapter);
-static int sis5595_detect(struct i2c_adapter *adapter, int address, int kind);
+static int sis5595_detect(struct i2c_adapter *adapter);
 static int sis5595_detach_client(struct i2c_client *client);
 
 static int sis5595_read_value(struct i2c_client *client, u8 register);
@@ -202,9 +200,7 @@ static void sis5595_init_client(struct i2c_client *client);
 static struct i2c_driver sis5595_driver = {
        .owner          = THIS_MODULE,
        .name           = "sis5595",
-       .id             = I2C_DRIVERID_SIS5595,
-       .flags          = I2C_DF_NOTIFY,
-       .attach_adapter = sis5595_attach_adapter,
+       .attach_adapter = sis5595_detect,
        .detach_client  = sis5595_detach_client,
 };
 
@@ -476,14 +472,7 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
  
 /* This is called when the module is loaded */
-static int sis5595_attach_adapter(struct i2c_adapter *adapter)
-{
-       if (!(adapter->class & I2C_CLASS_HWMON))
-               return 0;
-       return i2c_detect(adapter, &addr_data, sis5595_detect);
-}
-
-int sis5595_detect(struct i2c_adapter *adapter, int address, int kind)
+static int sis5595_detect(struct i2c_adapter *adapter)
 {
        int err = 0;
        int i;
@@ -492,10 +481,6 @@ int sis5595_detect(struct i2c_adapter *adapter, int address, int kind)
        char val;
        u16 a;
 
-       /* Make sure we are probing the ISA bus!!  */
-       if (!i2c_is_isa_adapter(adapter))
-               goto exit;
-
        if (force_addr)
                address = force_addr & ~(SIS5595_EXTENT - 1);
        /* Reserve the ISA region */
@@ -578,6 +563,12 @@ int sis5595_detect(struct i2c_adapter *adapter, int address, int kind)
        }
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_in0_input);
        device_create_file(&new_client->dev, &dev_attr_in0_min);
        device_create_file(&new_client->dev, &dev_attr_in0_max);
@@ -608,7 +599,9 @@ int sis5595_detect(struct i2c_adapter *adapter, int address, int kind)
                device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
        }
        return 0;
-       
+
+exit_detach:
+       i2c_detach_client(new_client);
 exit_free:
        kfree(data);
 exit_release:
@@ -619,18 +612,17 @@ exit:
 
 static int sis5595_detach_client(struct i2c_client *client)
 {
+       struct sis5595_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev,
-                   "Client deregistration failed, client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
-       if (i2c_is_isa_client(client))
-               release_region(client->addr, SIS5595_EXTENT);
+       release_region(client->addr, SIS5595_EXTENT);
 
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
 
        return 0;
 }
@@ -745,7 +737,6 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev,
 {
        u16 val;
        int *i;
-       int addr = 0;
 
        for (i = blacklist; *i != 0; i++) {
                struct pci_dev *dev;
@@ -761,22 +752,19 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev,
            pci_read_config_word(dev, SIS5595_BASE_REG, &val))
                return -ENODEV;
        
-       addr = val & ~(SIS5595_EXTENT - 1);
-       if (addr == 0 && force_addr == 0) {
+       address = val & ~(SIS5595_EXTENT - 1);
+       if (address == 0 && force_addr == 0) {
                dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n");
                return -ENODEV;
        }
-       if (force_addr)
-               addr = force_addr;      /* so detect will get called */
 
-       if (!addr) {
+       if (!address) {
                dev_err(&dev->dev,"No SiS 5595 sensors found.\n");
                return -ENODEV;
        }
-       normal_isa[0] = addr;
 
        s_bridge = pci_dev_get(dev);
-       if (i2c_add_driver(&sis5595_driver)) {
+       if (i2c_isa_add_driver(&sis5595_driver)) {
                pci_dev_put(s_bridge);
                s_bridge = NULL;
        }
@@ -803,7 +791,7 @@ static void __exit sm_sis5595_exit(void)
 {
        pci_unregister_driver(&sis5595_pci_driver);
        if (s_bridge != NULL) {
-               i2c_del_driver(&sis5595_driver);
+               i2c_isa_del_driver(&sis5595_driver);
                pci_dev_put(s_bridge);
                s_bridge = NULL;
        }
index fdeeb3ab6f2f3e9146b607ddc00c5d3ffd239bed..7fe71576dea4b7416e6b15ae387e56dc6238da1d 100644 (file)
 #include <linux/ioport.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
 #include <linux/init.h>
 #include <asm/io.h>
 
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
 /* Address is autodetected, there is no default value */
-static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END };
-static struct i2c_force_data forces[] = {{NULL}};
-
-enum chips { any_chip, smsc47b397 };
-static struct i2c_address_data addr_data = {
-       .normal_i2c             = normal_i2c,
-       .normal_isa             = normal_isa,
-       .probe                  = normal_i2c,           /* cheat */
-       .ignore                 = normal_i2c,           /* cheat */
-       .forces                 = forces,
-};
+static unsigned short address;
 
 /* Super-I/0 registers and commands */
 
@@ -100,6 +91,7 @@ static u8 smsc47b397_reg_temp[] = {0x25, 0x26, 0x27, 0x80};
 
 struct smsc47b397_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore lock;
 
        struct semaphore update_lock;
@@ -215,52 +207,40 @@ sysfs_fan(4);
 #define device_create_file_fan(client, num) \
        device_create_file(&client->dev, &dev_attr_fan##num##_input)
 
-static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind);
-
-static int smsc47b397_attach_adapter(struct i2c_adapter *adapter)
-{
-       if (!(adapter->class & I2C_CLASS_HWMON))
-               return 0;
-       return i2c_detect(adapter, &addr_data, smsc47b397_detect);
-}
-
 static int smsc47b397_detach_client(struct i2c_client *client)
 {
+       struct smsc47b397_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                       "client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
        release_region(client->addr, SMSC_EXTENT);
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
 
        return 0;
 }
 
+static int smsc47b397_detect(struct i2c_adapter *adapter);
+
 static struct i2c_driver smsc47b397_driver = {
        .owner          = THIS_MODULE,
        .name           = "smsc47b397",
-       .id             = I2C_DRIVERID_SMSC47B397,
-       .flags          = I2C_DF_NOTIFY,
-       .attach_adapter = smsc47b397_attach_adapter,
+       .attach_adapter = smsc47b397_detect,
        .detach_client  = smsc47b397_detach_client,
 };
 
-static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind)
+static int smsc47b397_detect(struct i2c_adapter *adapter)
 {
        struct i2c_client *new_client;
        struct smsc47b397_data *data;
        int err = 0;
 
-       if (!i2c_is_isa_adapter(adapter)) {
-               return 0;
-       }
-
-       if (!request_region(addr, SMSC_EXTENT, smsc47b397_driver.name)) {
-               dev_err(&adapter->dev, "Region 0x%x already in use!\n", addr);
+       if (!request_region(address, SMSC_EXTENT, smsc47b397_driver.name)) {
+               dev_err(&adapter->dev, "Region 0x%x already in use!\n",
+                       address);
                return -EBUSY;
        }
 
@@ -272,7 +252,7 @@ static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind)
 
        new_client = &data->client;
        i2c_set_clientdata(new_client, data);
-       new_client->addr = addr;
+       new_client->addr = address;
        init_MUTEX(&data->lock);
        new_client->adapter = adapter;
        new_client->driver = &smsc47b397_driver;
@@ -285,6 +265,12 @@ static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind)
        if ((err = i2c_attach_client(new_client)))
                goto error_free;
 
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto error_detach;
+       }
+
        device_create_file_temp(new_client, 1);
        device_create_file_temp(new_client, 2);
        device_create_file_temp(new_client, 3);
@@ -297,14 +283,16 @@ static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind)
 
        return 0;
 
+error_detach:
+       i2c_detach_client(new_client);
 error_free:
        kfree(data);
 error_release:
-       release_region(addr, SMSC_EXTENT);
+       release_region(address, SMSC_EXTENT);
        return err;
 }
 
-static int __init smsc47b397_find(unsigned int *addr)
+static int __init smsc47b397_find(unsigned short *addr)
 {
        u8 id, rev;
 
@@ -333,15 +321,15 @@ static int __init smsc47b397_init(void)
 {
        int ret;
 
-       if ((ret = smsc47b397_find(normal_isa)))
+       if ((ret = smsc47b397_find(&address)))
                return ret;
 
-       return i2c_add_driver(&smsc47b397_driver);
+       return i2c_isa_add_driver(&smsc47b397_driver);
 }
 
 static void __exit smsc47b397_exit(void)
 {
-       i2c_del_driver(&smsc47b397_driver);
+       i2c_isa_del_driver(&smsc47b397_driver);
 }
 
 MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
index 7166ad0b2fda666e5ace936c0b3960de9bbdd7b0..7e699a8ede262916369a88c57001f6de86eafbad 100644 (file)
 #include <linux/ioport.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
 #include <linux/init.h>
 #include <asm/io.h>
 
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
 /* Address is autodetected, there is no default value */
-static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END };
-static struct i2c_force_data forces[] = {{NULL}};
-
-enum chips { any_chip, smsc47m1 };
-static struct i2c_address_data addr_data = {
-       .normal_i2c             = normal_i2c,
-       .normal_isa             = normal_isa,
-       .forces                 = forces,
-};
+static unsigned short address;
 
 /* Super-I/0 registers and commands */
 
@@ -108,6 +101,7 @@ superio_exit(void)
 
 struct smsc47m1_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore lock;
 
        struct semaphore update_lock;
@@ -121,9 +115,7 @@ struct smsc47m1_data {
 };
 
 
-static int smsc47m1_attach_adapter(struct i2c_adapter *adapter);
-static int smsc47m1_find(int *address);
-static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind);
+static int smsc47m1_detect(struct i2c_adapter *adapter);
 static int smsc47m1_detach_client(struct i2c_client *client);
 
 static int smsc47m1_read_value(struct i2c_client *client, u8 reg);
@@ -136,9 +128,7 @@ static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
 static struct i2c_driver smsc47m1_driver = {
        .owner          = THIS_MODULE,
        .name           = "smsc47m1",
-       .id             = I2C_DRIVERID_SMSC47M1,
-       .flags          = I2C_DF_NOTIFY,
-       .attach_adapter = smsc47m1_attach_adapter,
+       .attach_adapter = smsc47m1_detect,
        .detach_client  = smsc47m1_detach_client,
 };
 
@@ -354,14 +344,7 @@ fan_present(2);
 
 static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
 
-static int smsc47m1_attach_adapter(struct i2c_adapter *adapter)
-{
-       if (!(adapter->class & I2C_CLASS_HWMON))
-               return 0;
-       return i2c_detect(adapter, &addr_data, smsc47m1_detect);
-}
-
-static int smsc47m1_find(int *address)
+static int __init smsc47m1_find(unsigned short *addr)
 {
        u8 val;
 
@@ -388,10 +371,10 @@ static int smsc47m1_find(int *address)
        }
 
        superio_select();
-       *address = (superio_inb(SUPERIO_REG_BASE) << 8)
-                |  superio_inb(SUPERIO_REG_BASE + 1);
+       *addr = (superio_inb(SUPERIO_REG_BASE) << 8)
+             |  superio_inb(SUPERIO_REG_BASE + 1);
        val = superio_inb(SUPERIO_REG_ACT);
-       if (*address == 0 || (val & 0x01) == 0) {
+       if (*addr == 0 || (val & 0x01) == 0) {
                printk(KERN_INFO "smsc47m1: Device is disabled, will not use\n");
                superio_exit();
                return -ENODEV;
@@ -401,17 +384,13 @@ static int smsc47m1_find(int *address)
        return 0;
 }
 
-static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind)
+static int smsc47m1_detect(struct i2c_adapter *adapter)
 {
        struct i2c_client *new_client;
        struct smsc47m1_data *data;
        int err = 0;
        int fan1, fan2, pwm1, pwm2;
 
-       if (!i2c_is_isa_adapter(adapter)) {
-               return 0;
-       }
-
        if (!request_region(address, SMSC_EXTENT, smsc47m1_driver.name)) {
                dev_err(&adapter->dev, "Region 0x%x already in use!\n", address);
                return -EBUSY;
@@ -461,6 +440,13 @@ static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind)
           function. */
        smsc47m1_update_device(&new_client->dev, 1);
 
+       /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto error_detach;
+       }
+
        if (fan1) {
                device_create_file(&new_client->dev, &dev_attr_fan1_input);
                device_create_file(&new_client->dev, &dev_attr_fan1_min);
@@ -494,6 +480,8 @@ static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+error_detach:
+       i2c_detach_client(new_client);
 error_free:
        kfree(data);
 error_release:
@@ -503,16 +491,16 @@ error_release:
 
 static int smsc47m1_detach_client(struct i2c_client *client)
 {
+       struct smsc47m1_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                       "client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
        release_region(client->addr, SMSC_EXTENT);
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
 
        return 0;
 }
@@ -573,16 +561,16 @@ static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
 
 static int __init sm_smsc47m1_init(void)
 {
-       if (smsc47m1_find(normal_isa)) {
+       if (smsc47m1_find(&address)) {
                return -ENODEV;
        }
 
-       return i2c_add_driver(&smsc47m1_driver);
+       return i2c_isa_add_driver(&smsc47m1_driver);
 }
 
 static void __exit sm_smsc47m1_exit(void)
 {
-       i2c_del_driver(&smsc47m1_driver);
+       i2c_isa_del_driver(&smsc47m1_driver);
 }
 
 MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
index 164d47948390d39206537b206c5e11c9a2c6faa1..eb84997627c8245456ab40c3d402d72b51104ce9 100644 (file)
@@ -35,7 +35,9 @@
 #include <linux/pci.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
 #include <linux/init.h>
 #include <asm/io.h>
 
@@ -47,14 +49,10 @@ module_param(force_addr, ushort, 0);
 MODULE_PARM_DESC(force_addr,
                 "Initialize the base address of the sensors");
 
-/* Addresses to scan.
+/* Device address
    Note that we can't determine the ISA address until we have initialized
    our module */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END };
-
-/* Insmod parameters */
-SENSORS_INSMOD_1(via686a);
+static unsigned short address;
 
 /*
    The Via 686a southbridge has a LM78-like chip integrated on the same IC.
@@ -297,6 +295,7 @@ static inline long TEMP_FROM_REG10(u16 val)
    via686a client is allocated. */
 struct via686a_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore update_lock;
        char valid;             /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
@@ -315,8 +314,7 @@ struct via686a_data {
 
 static struct pci_dev *s_bridge;       /* pointer to the (only) via686a */
 
-static int via686a_attach_adapter(struct i2c_adapter *adapter);
-static int via686a_detect(struct i2c_adapter *adapter, int address, int kind);
+static int via686a_detect(struct i2c_adapter *adapter);
 static int via686a_detach_client(struct i2c_client *client);
 
 static inline int via686a_read_value(struct i2c_client *client, u8 reg)
@@ -576,22 +574,13 @@ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 static struct i2c_driver via686a_driver = {
        .owner          = THIS_MODULE,
        .name           = "via686a",
-       .id             = I2C_DRIVERID_VIA686A,
-       .flags          = I2C_DF_NOTIFY,
-       .attach_adapter = via686a_attach_adapter,
+       .attach_adapter = via686a_detect,
        .detach_client  = via686a_detach_client,
 };
 
 
 /* This is called when the module is loaded */
-static int via686a_attach_adapter(struct i2c_adapter *adapter)
-{
-       if (!(adapter->class & I2C_CLASS_HWMON))
-               return 0;
-       return i2c_detect(adapter, &addr_data, via686a_detect);
-}
-
-static int via686a_detect(struct i2c_adapter *adapter, int address, int kind)
+static int via686a_detect(struct i2c_adapter *adapter)
 {
        struct i2c_client *new_client;
        struct via686a_data *data;
@@ -599,13 +588,6 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind)
        const char client_name[] = "via686a";
        u16 val;
 
-       /* Make sure we are probing the ISA bus!!  */
-       if (!i2c_is_isa_adapter(adapter)) {
-               dev_err(&adapter->dev,
-               "via686a_detect called for an I2C bus adapter?!?\n");
-               return 0;
-       }
-
        /* 8231 requires multiple of 256, we enforce that on 686 as well */
        if (force_addr)
                address = force_addr & 0xFF00;
@@ -637,7 +619,7 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind)
 
        if (!(data = kmalloc(sizeof(struct via686a_data), GFP_KERNEL))) {
                err = -ENOMEM;
-               goto ERROR0;
+               goto exit_release;
        }
        memset(data, 0, sizeof(struct via686a_data));
 
@@ -655,12 +637,18 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind)
        init_MUTEX(&data->update_lock);
        /* Tell the I2C layer a new client has arrived */
        if ((err = i2c_attach_client(new_client)))
-               goto ERROR3;
+               goto exit_free;
 
        /* Initialize the VIA686A chip */
        via686a_init_client(new_client);
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_in0_input);
        device_create_file(&new_client->dev, &dev_attr_in1_input);
        device_create_file(&new_client->dev, &dev_attr_in2_input);
@@ -695,25 +683,27 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
-ERROR3:
+exit_detach:
+       i2c_detach_client(new_client);
+exit_free:
        kfree(data);
-ERROR0:
+exit_release:
        release_region(address, VIA686A_EXTENT);
        return err;
 }
 
 static int via686a_detach_client(struct i2c_client *client)
 {
+       struct via686a_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev,
-               "Client deregistration failed, client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
        release_region(client->addr, VIA686A_EXTENT);
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
 
        return 0;
 }
@@ -810,29 +800,25 @@ static int __devinit via686a_pci_probe(struct pci_dev *dev,
                                       const struct pci_device_id *id)
 {
        u16 val;
-       int addr = 0;
 
        if (PCIBIOS_SUCCESSFUL !=
            pci_read_config_word(dev, VIA686A_BASE_REG, &val))
                return -ENODEV;
 
-       addr = val & ~(VIA686A_EXTENT - 1);
-       if (addr == 0 && force_addr == 0) {
+       address = val & ~(VIA686A_EXTENT - 1);
+       if (address == 0 && force_addr == 0) {
                dev_err(&dev->dev, "base address not set - upgrade BIOS "
                        "or use force_addr=0xaddr\n");
                return -ENODEV;
        }
-       if (force_addr)
-               addr = force_addr;      /* so detect will get called */
 
-       if (!addr) {
+       if (!address) {
                dev_err(&dev->dev, "No Via 686A sensors found.\n");
                return -ENODEV;
        }
-       normal_isa[0] = addr;
 
        s_bridge = pci_dev_get(dev);
-       if (i2c_add_driver(&via686a_driver)) {
+       if (i2c_isa_add_driver(&via686a_driver)) {
                pci_dev_put(s_bridge);
                s_bridge = NULL;
        }
@@ -859,7 +845,7 @@ static void __exit sm_via686a_exit(void)
 {
        pci_unregister_driver(&via686a_pci_driver);
        if (s_bridge != NULL) {
-               i2c_del_driver(&via686a_driver);
+               i2c_isa_del_driver(&via686a_driver);
                pci_dev_put(s_bridge);
                s_bridge = NULL;
        }
index 8a40b6976e1ad25838a37c70c49e4235a1ea3281..b60efe8f8b26691a70bc64f5617d362b68e7a2be 100644 (file)
@@ -9,6 +9,9 @@
     Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
     in testing and debugging this driver.
 
+    This driver also supports the W83627EHG, which is the lead-free
+    version of the W83627EHF.
+
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
 #include <asm/io.h>
 #include "lm75.h"
 
-/* Addresses to scan
-   The actual ISA address is read from Super-I/O configuration space */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END };
-
-/* Insmod parameters */
-SENSORS_INSMOD_1(w83627ehf);
+/* The actual ISA address is read from Super-I/O configuration space */
+static unsigned short address;
 
 /*
  * Super-I/O constants and functions
@@ -174,6 +174,7 @@ temp1_to_reg(int temp)
 
 struct w83627ehf_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore lock;
 
        struct semaphore update_lock;
@@ -666,15 +667,12 @@ static void w83627ehf_init_client(struct i2c_client *client)
        }
 }
 
-static int w83627ehf_detect(struct i2c_adapter *adapter, int address, int kind)
+static int w83627ehf_detect(struct i2c_adapter *adapter)
 {
        struct i2c_client *client;
        struct w83627ehf_data *data;
        int i, err = 0;
 
-       if (!i2c_is_isa_adapter(adapter))
-               return 0;
-
        if (!request_region(address, REGION_LENGTH, w83627ehf_driver.name)) {
                err = -EBUSY;
                goto exit;
@@ -720,6 +718,12 @@ static int w83627ehf_detect(struct i2c_adapter *adapter, int address, int kind)
                data->has_fan |= (1 << 4);
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file(&client->dev, &dev_attr_fan1_input);
        device_create_file(&client->dev, &dev_attr_fan1_min);
        device_create_file(&client->dev, &dev_attr_fan1_div);
@@ -753,6 +757,8 @@ static int w83627ehf_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+exit_detach:
+       i2c_detach_client(client);
 exit_free:
        kfree(data);
 exit_release:
@@ -761,24 +767,17 @@ exit:
        return err;
 }
 
-static int w83627ehf_attach_adapter(struct i2c_adapter *adapter)
-{
-       if (!(adapter->class & I2C_CLASS_HWMON))
-               return 0;
-       return i2c_detect(adapter, &addr_data, w83627ehf_detect);
-}
-
 static int w83627ehf_detach_client(struct i2c_client *client)
 {
+       struct w83627ehf_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                       "client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
        release_region(client->addr, REGION_LENGTH);
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
 
        return 0;
 }
@@ -786,12 +785,11 @@ static int w83627ehf_detach_client(struct i2c_client *client)
 static struct i2c_driver w83627ehf_driver = {
        .owner          = THIS_MODULE,
        .name           = "w83627ehf",
-       .flags          = I2C_DF_NOTIFY,
-       .attach_adapter = w83627ehf_attach_adapter,
+       .attach_adapter = w83627ehf_detect,
        .detach_client  = w83627ehf_detach_client,
 };
 
-static int __init w83627ehf_find(int sioaddr, int *address)
+static int __init w83627ehf_find(int sioaddr, unsigned short *addr)
 {
        u16 val;
 
@@ -809,8 +807,8 @@ static int __init w83627ehf_find(int sioaddr, int *address)
        superio_select(W83627EHF_LD_HWM);
        val = (superio_inb(SIO_REG_ADDR) << 8)
            | superio_inb(SIO_REG_ADDR + 1);
-       *address = val & ~(REGION_LENGTH - 1);
-       if (*address == 0) {
+       *addr = val & ~(REGION_LENGTH - 1);
+       if (*addr == 0) {
                superio_exit();
                return -ENODEV;
        }
@@ -826,16 +824,16 @@ static int __init w83627ehf_find(int sioaddr, int *address)
 
 static int __init sensors_w83627ehf_init(void)
 {
-       if (w83627ehf_find(0x2e, &normal_isa[0])
-        && w83627ehf_find(0x4e, &normal_isa[0]))
+       if (w83627ehf_find(0x2e, &address)
+        && w83627ehf_find(0x4e, &address))
                return -ENODEV;
 
-       return i2c_add_driver(&w83627ehf_driver);
+       return i2c_isa_add_driver(&w83627ehf_driver);
 }
 
 static void __exit sensors_w83627ehf_exit(void)
 {
-       i2c_del_driver(&w83627ehf_driver);
+       i2c_isa_del_driver(&w83627ehf_driver);
 }
 
 MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
index bd87a42e068ae4d6ac0fd1763d61b3c32b1bb5d7..02bd5c0239a2daba693652cdafb431efd75e77a4 100644 (file)
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
 #include <asm/io.h>
 #include "lm75.h"
 
@@ -56,12 +58,11 @@ module_param(force_i2c, byte, 0);
 MODULE_PARM_DESC(force_i2c,
                 "Initialize the i2c address of the sensors");
 
-/* Addresses to scan */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END };
+/* The actual ISA address is read from Super-I/O configuration space */
+static unsigned short address;
 
 /* Insmod parameters */
-SENSORS_INSMOD_4(w83627hf, w83627thf, w83697hf, w83637hf);
+enum chips { any_chip, w83627hf, w83627thf, w83697hf, w83637hf };
 
 static int init = 1;
 module_param(init, bool, 0);
@@ -277,6 +278,7 @@ static inline u8 DIV_TO_REG(long val)
    dynamically allocated, at the same time when a new client is allocated. */
 struct w83627hf_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore lock;
        enum chips type;
 
@@ -314,9 +316,7 @@ struct w83627hf_data {
 };
 
 
-static int w83627hf_attach_adapter(struct i2c_adapter *adapter);
-static int w83627hf_detect(struct i2c_adapter *adapter, int address,
-                         int kind);
+static int w83627hf_detect(struct i2c_adapter *adapter);
 static int w83627hf_detach_client(struct i2c_client *client);
 
 static int w83627hf_read_value(struct i2c_client *client, u16 register);
@@ -328,9 +328,7 @@ static void w83627hf_init_client(struct i2c_client *client);
 static struct i2c_driver w83627hf_driver = {
        .owner          = THIS_MODULE,
        .name           = "w83627hf",
-       .id             = I2C_DRIVERID_W83627HF,
-       .flags          = I2C_DF_NOTIFY,
-       .attach_adapter = w83627hf_attach_adapter,
+       .attach_adapter = w83627hf_detect,
        .detach_client  = w83627hf_detach_client,
 };
 
@@ -959,16 +957,7 @@ device_create_file(&client->dev, &dev_attr_temp##offset##_type); \
 } while (0)
 
 
-/* This function is called when:
-     * w83627hf_driver is inserted (when this module is loaded), for each
-       available adapter
-     * when a new adapter is inserted (and w83627hf_driver is still present) */
-static int w83627hf_attach_adapter(struct i2c_adapter *adapter)
-{
-       return i2c_detect(adapter, &addr_data, w83627hf_detect);
-}
-
-static int w83627hf_find(int sioaddr, int *address)
+static int __init w83627hf_find(int sioaddr, unsigned short *addr)
 {
        u16 val;
 
@@ -988,32 +977,24 @@ static int w83627hf_find(int sioaddr, int *address)
        superio_select(W83627HF_LD_HWM);
        val = (superio_inb(WINB_BASE_REG) << 8) |
               superio_inb(WINB_BASE_REG + 1);
-       *address = val & ~(WINB_EXTENT - 1);
-       if (*address == 0 && force_addr == 0) {
+       *addr = val & ~(WINB_EXTENT - 1);
+       if (*addr == 0 && force_addr == 0) {
                superio_exit();
                return -ENODEV;
        }
-       if (force_addr)
-               *address = force_addr;  /* so detect will get called */
 
        superio_exit();
        return 0;
 }
 
-int w83627hf_detect(struct i2c_adapter *adapter, int address,
-                  int kind)
+static int w83627hf_detect(struct i2c_adapter *adapter)
 {
-       int val;
+       int val, kind;
        struct i2c_client *new_client;
        struct w83627hf_data *data;
        int err = 0;
        const char *client_name = "";
 
-       if (!i2c_is_isa_adapter(adapter)) {
-               err = -ENODEV;
-               goto ERROR0;
-       }
-
        if(force_addr)
                address = force_addr & ~(WINB_EXTENT - 1);
 
@@ -1102,6 +1083,12 @@ int w83627hf_detect(struct i2c_adapter *adapter, int address,
        data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3));
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto ERROR3;
+       }
+
        device_create_file_in(new_client, 0);
        if (kind != w83697hf)
                device_create_file_in(new_client, 1);
@@ -1152,6 +1139,8 @@ int w83627hf_detect(struct i2c_adapter *adapter, int address,
 
        return 0;
 
+      ERROR3:
+       i2c_detach_client(new_client);
       ERROR2:
        kfree(data);
       ERROR1:
@@ -1162,16 +1151,16 @@ int w83627hf_detect(struct i2c_adapter *adapter, int address,
 
 static int w83627hf_detach_client(struct i2c_client *client)
 {
+       struct w83627hf_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev,
-                      "Client deregistration failed, client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
        release_region(client->addr, WINB_EXTENT);
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
 
        return 0;
 }
@@ -1327,7 +1316,7 @@ static void w83627hf_init_client(struct i2c_client *client)
                data->vrm = (data->vrm_ovt & 0x01) ? 90 : 82;
        } else {
                /* Convert VID to voltage based on default VRM */
-               data->vrm = i2c_which_vrm();
+               data->vrm = vid_which_vrm();
        }
 
        tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
@@ -1485,20 +1474,17 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
 
 static int __init sensors_w83627hf_init(void)
 {
-       int addr;
-
-       if (w83627hf_find(0x2e, &addr)
-        && w83627hf_find(0x4e, &addr)) {
+       if (w83627hf_find(0x2e, &address)
+        && w83627hf_find(0x4e, &address)) {
                return -ENODEV;
        }
-       normal_isa[0] = addr;
 
-       return i2c_add_driver(&w83627hf_driver);
+       return i2c_isa_add_driver(&w83627hf_driver);
 }
 
 static void __exit sensors_w83627hf_exit(void)
 {
-       i2c_del_driver(&w83627hf_driver);
+       i2c_isa_del_driver(&w83627hf_driver);
 }
 
 MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
index 0bb131ce09ebc931fdebf415c75c6c6f255f7e11..4c43337ca780abe0cde6ee81590de98b3edfbff8 100644 (file)
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
 #include <asm/io.h>
 #include "lm75.h"
 
 static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
                                        0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
                                        0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END };
+static unsigned short isa_address = 0x290;
 
 /* Insmod parameters */
-SENSORS_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f);
+I2C_CLIENT_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f);
 I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
                    "{bus, clientaddr, subclientaddr1, subclientaddr2}");
 
@@ -218,6 +220,7 @@ DIV_TO_REG(long val, enum chips type)
    allocated. */
 struct w83781d_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore lock;
        enum chips type;
 
@@ -255,6 +258,7 @@ struct w83781d_data {
 };
 
 static int w83781d_attach_adapter(struct i2c_adapter *adapter);
+static int w83781d_isa_attach_adapter(struct i2c_adapter *adapter);
 static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind);
 static int w83781d_detach_client(struct i2c_client *client);
 
@@ -273,6 +277,14 @@ static struct i2c_driver w83781d_driver = {
        .detach_client = w83781d_detach_client,
 };
 
+static struct i2c_driver w83781d_isa_driver = {
+       .owner = THIS_MODULE,
+       .name = "w83781d-isa",
+       .attach_adapter = w83781d_isa_attach_adapter,
+       .detach_client = w83781d_detach_client,
+};
+
+
 /* following are the sysfs callback functions */
 #define show_in_reg(reg) \
 static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
@@ -856,7 +868,13 @@ w83781d_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, w83781d_detect);
+       return i2c_probe(adapter, &addr_data, w83781d_detect);
+}
+
+static int
+w83781d_isa_attach_adapter(struct i2c_adapter *adapter)
+{
+       return w83781d_detect(adapter, isa_address, -1);
 }
 
 /* Assumes that adapter is of I2C, not ISA variety.
@@ -961,10 +979,10 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
 ERROR_SC_3:
        i2c_detach_client(data->lm75[0]);
 ERROR_SC_2:
-       if (NULL != data->lm75[1])
+       if (data->lm75[1])
                kfree(data->lm75[1]);
 ERROR_SC_1:
-       if (NULL != data->lm75[0])
+       if (data->lm75[0])
                kfree(data->lm75[0]);
 ERROR_SC_0:
        return err;
@@ -999,7 +1017,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
        
        if (is_isa)
                if (!request_region(address, W83781D_EXTENT,
-                                   w83781d_driver.name)) {
+                                   w83781d_isa_driver.name)) {
                        dev_dbg(&adapter->dev, "Request of region "
                                "0x%x-0x%x for w83781d failed\n", address,
                                address + W83781D_EXTENT - 1);
@@ -1057,7 +1075,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
        new_client->addr = address;
        init_MUTEX(&data->lock);
        new_client->adapter = adapter;
-       new_client->driver = &w83781d_driver;
+       new_client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver;
        new_client->flags = 0;
 
        /* Now, we do the remaining detection. */
@@ -1189,6 +1207,12 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
                        data->pwmenable[i] = 1;
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto ERROR4;
+       }
+
        device_create_file_in(new_client, 0);
        if (kind != w83783s)
                device_create_file_in(new_client, 1);
@@ -1241,6 +1265,15 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
+ERROR4:
+       if (data->lm75[1]) {
+               i2c_detach_client(data->lm75[1]);
+               kfree(data->lm75[1]);
+       }
+       if (data->lm75[0]) {
+               i2c_detach_client(data->lm75[0]);
+               kfree(data->lm75[0]);
+       }
 ERROR3:
        i2c_detach_client(new_client);
 ERROR2:
@@ -1255,24 +1288,26 @@ ERROR0:
 static int
 w83781d_detach_client(struct i2c_client *client)
 {
+       struct w83781d_data *data = i2c_get_clientdata(client);
        int err;
 
+       /* main client */
+       if (data)
+               hwmon_device_unregister(data->class_dev);
+
        if (i2c_is_isa_client(client))
                release_region(client->addr, W83781D_EXTENT);
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev,
-                      "Client deregistration failed, client not detached.\n");
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
-       if (i2c_get_clientdata(client)==NULL) {
-               /* subclients */
+       /* main client */
+       if (data)
+               kfree(data);
+
+       /* subclient */
+       else
                kfree(client);
-       } else {
-               /* main client */
-               kfree(i2c_get_clientdata(client));
-       }
 
        return 0;
 }
@@ -1443,7 +1478,7 @@ w83781d_init_client(struct i2c_client *client)
                w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0);
        }
 
-       data->vrm = i2c_which_vrm();
+       data->vrm = vid_which_vrm();
 
        if ((type != w83781d) && (type != as99127f)) {
                tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
@@ -1613,12 +1648,25 @@ static struct w83781d_data *w83781d_update_device(struct device *dev)
 static int __init
 sensors_w83781d_init(void)
 {
-       return i2c_add_driver(&w83781d_driver);
+       int res;
+
+       res = i2c_add_driver(&w83781d_driver);
+       if (res)
+               return res;
+
+       res = i2c_isa_add_driver(&w83781d_isa_driver);
+       if (res) {
+               i2c_del_driver(&w83781d_driver);
+               return res;
+       }
+
+       return 0;
 }
 
 static void __exit
 sensors_w83781d_exit(void)
 {
+       i2c_isa_del_driver(&w83781d_isa_driver);
        i2c_del_driver(&w83781d_driver);
 }
 
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
new file mode 100644 (file)
index 0000000..ba0c280
--- /dev/null
@@ -0,0 +1,1649 @@
+/*
+    w83792d.c - Part of lm_sensors, Linux kernel modules for hardware
+                monitoring
+    Copyright (C) 2004, 2005 Winbond Electronics Corp.
+                        Chunhao Huang <DZShen@Winbond.com.tw>,
+                        Rudolf Marek <r.marek@sh.cvut.cz>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    Note:
+    1. This driver is only for 2.6 kernel, 2.4 kernel need a different driver.
+    2. This driver is only for Winbond W83792D C version device, there
+       are also some motherboards with B version W83792D device. The
+       calculation method to in6-in7(measured value, limits) is a little
+       different between C and B version. C or B version can be identified
+       by CR[0x49h].
+*/
+
+/*
+    Supports following chips:
+
+    Chip       #vin    #fanin  #pwm    #temp   wchipid vendid  i2c     ISA
+    w83792d    9       7       7       3       0x7a    0x5ca3  yes     no
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(w83792d);
+I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
+                       "{bus, clientaddr, subclientaddr1, subclientaddr2}");
+
+static int init;
+module_param(init, bool, 0);
+MODULE_PARM_DESC(init, "Set to one to force chip initialization");
+
+/* The W83792D registers */
+static const u8 W83792D_REG_IN[9] = {
+       0x20,   /* Vcore A in DataSheet */
+       0x21,   /* Vcore B in DataSheet */
+       0x22,   /* VIN0 in DataSheet */
+       0x23,   /* VIN1 in DataSheet */
+       0x24,   /* VIN2 in DataSheet */
+       0x25,   /* VIN3 in DataSheet */
+       0x26,   /* 5VCC in DataSheet */
+       0xB0,   /* 5VSB in DataSheet */
+       0xB1    /* VBAT in DataSheet */
+};
+#define W83792D_REG_LOW_BITS1 0x3E  /* Low Bits I in DataSheet */
+#define W83792D_REG_LOW_BITS2 0x3F  /* Low Bits II in DataSheet */
+static const u8 W83792D_REG_IN_MAX[9] = {
+       0x2B,   /* Vcore A High Limit in DataSheet */
+       0x2D,   /* Vcore B High Limit in DataSheet */
+       0x2F,   /* VIN0 High Limit in DataSheet */
+       0x31,   /* VIN1 High Limit in DataSheet */
+       0x33,   /* VIN2 High Limit in DataSheet */
+       0x35,   /* VIN3 High Limit in DataSheet */
+       0x37,   /* 5VCC High Limit in DataSheet */
+       0xB4,   /* 5VSB High Limit in DataSheet */
+       0xB6    /* VBAT High Limit in DataSheet */
+};
+static const u8 W83792D_REG_IN_MIN[9] = {
+       0x2C,   /* Vcore A Low Limit in DataSheet */
+       0x2E,   /* Vcore B Low Limit in DataSheet */
+       0x30,   /* VIN0 Low Limit in DataSheet */
+       0x32,   /* VIN1 Low Limit in DataSheet */
+       0x34,   /* VIN2 Low Limit in DataSheet */
+       0x36,   /* VIN3 Low Limit in DataSheet */
+       0x38,   /* 5VCC Low Limit in DataSheet */
+       0xB5,   /* 5VSB Low Limit in DataSheet */
+       0xB7    /* VBAT Low Limit in DataSheet */
+};
+static const u8 W83792D_REG_FAN[7] = {
+       0x28,   /* FAN 1 Count in DataSheet */
+       0x29,   /* FAN 2 Count in DataSheet */
+       0x2A,   /* FAN 3 Count in DataSheet */
+       0xB8,   /* FAN 4 Count in DataSheet */
+       0xB9,   /* FAN 5 Count in DataSheet */
+       0xBA,   /* FAN 6 Count in DataSheet */
+       0xBE    /* FAN 7 Count in DataSheet */
+};
+static const u8 W83792D_REG_FAN_MIN[7] = {
+       0x3B,   /* FAN 1 Count Low Limit in DataSheet */
+       0x3C,   /* FAN 2 Count Low Limit in DataSheet */
+       0x3D,   /* FAN 3 Count Low Limit in DataSheet */
+       0xBB,   /* FAN 4 Count Low Limit in DataSheet */
+       0xBC,   /* FAN 5 Count Low Limit in DataSheet */
+       0xBD,   /* FAN 6 Count Low Limit in DataSheet */
+       0xBF    /* FAN 7 Count Low Limit in DataSheet */
+};
+#define W83792D_REG_FAN_CFG 0x84       /* FAN Configuration in DataSheet */
+static const u8 W83792D_REG_FAN_DIV[4] = {
+       0x47,   /* contains FAN2 and FAN1 Divisor */
+       0x5B,   /* contains FAN4 and FAN3 Divisor */
+       0x5C,   /* contains FAN6 and FAN5 Divisor */
+       0x9E    /* contains FAN7 Divisor. */
+};
+static const u8 W83792D_REG_PWM[7] = {
+       0x81,   /* FAN 1 Duty Cycle, be used to control */
+       0x83,   /* FAN 2 Duty Cycle, be used to control */
+       0x94,   /* FAN 3 Duty Cycle, be used to control */
+       0xA3,   /* FAN 4 Duty Cycle, be used to control */
+       0xA4,   /* FAN 5 Duty Cycle, be used to control */
+       0xA5,   /* FAN 6 Duty Cycle, be used to control */
+       0xA6    /* FAN 7 Duty Cycle, be used to control */
+};
+#define W83792D_REG_BANK               0x4E
+#define W83792D_REG_TEMP2_CONFIG       0xC2
+#define W83792D_REG_TEMP3_CONFIG       0xCA
+
+static const u8 W83792D_REG_TEMP1[3] = {
+       0x27,   /* TEMP 1 in DataSheet */
+       0x39,   /* TEMP 1 Over in DataSheet */
+       0x3A,   /* TEMP 1 Hyst in DataSheet */
+};
+
+static const u8 W83792D_REG_TEMP_ADD[2][6] = {
+       { 0xC0,         /* TEMP 2 in DataSheet */
+         0xC1,         /* TEMP 2(0.5 deg) in DataSheet */
+         0xC5,         /* TEMP 2 Over High part in DataSheet */
+         0xC6,         /* TEMP 2 Over Low part in DataSheet */
+         0xC3,         /* TEMP 2 Thyst High part in DataSheet */
+         0xC4 },       /* TEMP 2 Thyst Low part in DataSheet */
+       { 0xC8,         /* TEMP 3 in DataSheet */
+         0xC9,         /* TEMP 3(0.5 deg) in DataSheet */
+         0xCD,         /* TEMP 3 Over High part in DataSheet */
+         0xCE,         /* TEMP 3 Over Low part in DataSheet */
+         0xCB,         /* TEMP 3 Thyst High part in DataSheet */
+         0xCC }        /* TEMP 3 Thyst Low part in DataSheet */
+};
+
+static const u8 W83792D_REG_THERMAL[3] = {
+       0x85,   /* SmartFanI: Fan1 target value */
+       0x86,   /* SmartFanI: Fan2 target value */
+       0x96    /* SmartFanI: Fan3 target value */
+};
+
+static const u8 W83792D_REG_TOLERANCE[3] = {
+       0x87,   /* (bit3-0)SmartFan Fan1 tolerance */
+       0x87,   /* (bit7-4)SmartFan Fan2 tolerance */
+       0x97    /* (bit3-0)SmartFan Fan3 tolerance */
+};
+
+static const u8 W83792D_REG_POINTS[3][4] = {
+       { 0x85,         /* SmartFanII: Fan1 temp point 1 */
+         0xE3,         /* SmartFanII: Fan1 temp point 2 */
+         0xE4,         /* SmartFanII: Fan1 temp point 3 */
+         0xE5 },       /* SmartFanII: Fan1 temp point 4 */
+       { 0x86,         /* SmartFanII: Fan2 temp point 1 */
+         0xE6,         /* SmartFanII: Fan2 temp point 2 */
+         0xE7,         /* SmartFanII: Fan2 temp point 3 */
+         0xE8 },       /* SmartFanII: Fan2 temp point 4 */
+       { 0x96,         /* SmartFanII: Fan3 temp point 1 */
+         0xE9,         /* SmartFanII: Fan3 temp point 2 */
+         0xEA,         /* SmartFanII: Fan3 temp point 3 */
+         0xEB }        /* SmartFanII: Fan3 temp point 4 */
+};
+
+static const u8 W83792D_REG_LEVELS[3][4] = {
+       { 0x88,         /* (bit3-0) SmartFanII: Fan1 Non-Stop */
+         0x88,         /* (bit7-4) SmartFanII: Fan1 Level 1 */
+         0xE0,         /* (bit7-4) SmartFanII: Fan1 Level 2 */
+         0xE0 },       /* (bit3-0) SmartFanII: Fan1 Level 3 */
+       { 0x89,         /* (bit3-0) SmartFanII: Fan2 Non-Stop */
+         0x89,         /* (bit7-4) SmartFanII: Fan2 Level 1 */
+         0xE1,         /* (bit7-4) SmartFanII: Fan2 Level 2 */
+         0xE1 },       /* (bit3-0) SmartFanII: Fan2 Level 3 */
+       { 0x98,         /* (bit3-0) SmartFanII: Fan3 Non-Stop */
+         0x98,         /* (bit7-4) SmartFanII: Fan3 Level 1 */
+         0xE2,         /* (bit7-4) SmartFanII: Fan3 Level 2 */
+         0xE2 }        /* (bit3-0) SmartFanII: Fan3 Level 3 */
+};
+
+#define W83792D_REG_CONFIG             0x40
+#define W83792D_REG_VID_FANDIV         0x47
+#define W83792D_REG_CHIPID             0x49
+#define W83792D_REG_WCHIPID            0x58
+#define W83792D_REG_CHIPMAN            0x4F
+#define W83792D_REG_PIN                        0x4B
+#define W83792D_REG_I2C_SUBADDR                0x4A
+
+#define W83792D_REG_ALARM1 0xA9                /* realtime status register1 */
+#define W83792D_REG_ALARM2 0xAA                /* realtime status register2 */
+#define W83792D_REG_ALARM3 0xAB                /* realtime status register3 */
+#define W83792D_REG_CHASSIS 0x42       /* Bit 5: Case Open status bit */
+#define W83792D_REG_CHASSIS_CLR 0x44   /* Bit 7: Case Open CLR_CHS/Reset bit */
+
+/* control in0/in1 's limit modifiability */
+#define W83792D_REG_VID_IN_B           0x17
+
+#define W83792D_REG_VBAT               0x5D
+#define W83792D_REG_I2C_ADDR           0x48
+
+/* Conversions. Rounding and limit checking is only done on the TO_REG
+   variants. Note that you should be a bit careful with which arguments
+   these macros are called: arguments may be evaluated more than once.
+   Fixing this is just not worth it. */
+#define IN_FROM_REG(nr,val) (((nr)<=1)?(val*2): \
+                               ((((nr)==6)||((nr)==7))?(val*6):(val*4)))
+#define IN_TO_REG(nr,val) (((nr)<=1)?(val/2): \
+                               ((((nr)==6)||((nr)==7))?(val/6):(val/4)))
+
+static inline u8
+FAN_TO_REG(long rpm, int div)
+{
+       if (rpm == 0)
+               return 255;
+       rpm = SENSORS_LIMIT(rpm, 1, 1000000);
+       return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+}
+
+#define FAN_FROM_REG(val,div)  ((val) == 0   ? -1 : \
+                               ((val) == 255 ? 0 : \
+                                               1350000 / ((val) * (div))))
+
+/* for temp1 */
+#define TEMP1_TO_REG(val)      (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \
+                                       : (val)) / 1000, 0, 0xff))
+#define TEMP1_FROM_REG(val)    (((val) & 0x80 ? (val)-0x100 : (val)) * 1000)
+/* for temp2 and temp3, because they need addtional resolution */
+#define TEMP_ADD_FROM_REG(val1, val2) \
+       ((((val1) & 0x80 ? (val1)-0x100 \
+               : (val1)) * 1000) + ((val2 & 0x80) ? 500 : 0))
+#define TEMP_ADD_TO_REG_HIGH(val) \
+       (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \
+                       : (val)) / 1000, 0, 0xff))
+#define TEMP_ADD_TO_REG_LOW(val)       ((val%1000) ? 0x80 : 0x00)
+
+#define PWM_FROM_REG(val)              (val)
+#define PWM_TO_REG(val)                        (SENSORS_LIMIT((val),0,255))
+#define DIV_FROM_REG(val)              (1 << (val))
+
+static inline u8
+DIV_TO_REG(long val)
+{
+       int i;
+       val = SENSORS_LIMIT(val, 1, 128) >> 1;
+       for (i = 0; i < 6; i++) {
+               if (val == 0)
+                       break;
+               val >>= 1;
+       }
+       return ((u8) i);
+}
+
+struct w83792d_data {
+       struct i2c_client client;
+       struct class_device *class_dev;
+       struct semaphore lock;
+       enum chips type;
+
+       struct semaphore update_lock;
+       char valid;             /* !=0 if following fields are valid */
+       unsigned long last_updated;     /* In jiffies */
+
+       /* array of 2 pointers to subclients */
+       struct i2c_client *lm75[2];
+
+       u8 in[9];               /* Register value */
+       u8 in_max[9];           /* Register value */
+       u8 in_min[9];           /* Register value */
+       u8 low_bits[2];         /* Additional resolution to voltage in0-6 */
+       u8 fan[7];              /* Register value */
+       u8 fan_min[7];          /* Register value */
+       u8 temp1[3];            /* current, over, thyst */
+       u8 temp_add[2][6];      /* Register value */
+       u8 fan_div[7];          /* Register encoding, shifted right */
+       u8 pwm[7];              /* We only consider the first 3 set of pwm,
+                                  although 792 chip has 7 set of pwm. */
+       u8 pwmenable[3];
+       u8 pwm_mode[7];         /* indicates PWM or DC mode: 1->PWM; 0->DC */
+       u32 alarms;             /* realtime status register encoding,combined */
+       u8 chassis;             /* Chassis status */
+       u8 chassis_clear;       /* CLR_CHS, clear chassis intrusion detection */
+       u8 thermal_cruise[3];   /* Smart FanI: Fan1,2,3 target value */
+       u8 tolerance[3];        /* Fan1,2,3 tolerance(Smart Fan I/II) */
+       u8 sf2_points[3][4];    /* Smart FanII: Fan1,2,3 temperature points */
+       u8 sf2_levels[3][4];    /* Smart FanII: Fan1,2,3 duty cycle levels */
+};
+
+static int w83792d_attach_adapter(struct i2c_adapter *adapter);
+static int w83792d_detect(struct i2c_adapter *adapter, int address, int kind);
+static int w83792d_detach_client(struct i2c_client *client);
+
+static int w83792d_read_value(struct i2c_client *client, u8 register);
+static int w83792d_write_value(struct i2c_client *client, u8 register,
+                               u8 value);
+static struct w83792d_data *w83792d_update_device(struct device *dev);
+
+#ifdef DEBUG
+static void w83792d_print_debug(struct w83792d_data *data, struct device *dev);
+#endif
+
+static void w83792d_init_client(struct i2c_client *client);
+
+static struct i2c_driver w83792d_driver = {
+       .owner = THIS_MODULE,
+       .name = "w83792d",
+       .flags = I2C_DF_NOTIFY,
+       .attach_adapter = w83792d_attach_adapter,
+       .detach_client = w83792d_detach_client,
+};
+
+static long in_count_from_reg(int nr, struct w83792d_data *data)
+{
+       u16 vol_count = data->in[nr];
+       u16 low_bits = 0;
+       vol_count = (vol_count << 2);
+       switch (nr)
+       {
+       case 0:  /* vin0 */
+               low_bits = (data->low_bits[0]) & 0x03;
+               break;
+       case 1:  /* vin1 */
+               low_bits = ((data->low_bits[0]) & 0x0c) >> 2;
+               break;
+       case 2:  /* vin2 */
+               low_bits = ((data->low_bits[0]) & 0x30) >> 4;
+               break;
+       case 3:  /* vin3 */
+               low_bits = ((data->low_bits[0]) & 0xc0) >> 6;
+               break;
+       case 4:  /* vin4 */
+               low_bits = (data->low_bits[1]) & 0x03;
+               break;
+       case 5:  /* vin5 */
+               low_bits = ((data->low_bits[1]) & 0x0c) >> 2;
+               break;
+       case 6:  /* vin6 */
+               low_bits = ((data->low_bits[1]) & 0x30) >> 4;
+       default:
+               break;
+       }
+       vol_count = vol_count | low_bits;
+       return vol_count;
+}
+
+/* following are the sysfs callback functions */
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index;
+       struct w83792d_data *data = w83792d_update_device(dev);
+       return sprintf(buf,"%ld\n", IN_FROM_REG(nr,(in_count_from_reg(nr, data))));
+}
+
+#define show_in_reg(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+                       char *buf) \
+{ \
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+       int nr = sensor_attr->index; \
+       struct w83792d_data *data = w83792d_update_device(dev); \
+       return sprintf(buf,"%ld\n", (long)(IN_FROM_REG(nr, (data->reg[nr])*4))); \
+}
+
+show_in_reg(in_min);
+show_in_reg(in_max);
+
+#define store_in_reg(REG, reg) \
+static ssize_t store_in_##reg (struct device *dev, \
+                               struct device_attribute *attr, \
+                               const char *buf, size_t count) \
+{ \
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+       int nr = sensor_attr->index; \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct w83792d_data *data = i2c_get_clientdata(client); \
+       u32 val; \
+        \
+       val = simple_strtoul(buf, NULL, 10); \
+       data->in_##reg[nr] = SENSORS_LIMIT(IN_TO_REG(nr, val)/4, 0, 255); \
+       w83792d_write_value(client, W83792D_REG_IN_##REG[nr], data->in_##reg[nr]); \
+        \
+       return count; \
+}
+store_in_reg(MIN, min);
+store_in_reg(MAX, max);
+
+#define sysfs_in_reg(offset) \
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in, \
+                               NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+                               show_in_min, store_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+                               show_in_max, store_in_max, offset);
+
+sysfs_in_reg(0);
+sysfs_in_reg(1);
+sysfs_in_reg(2);
+sysfs_in_reg(3);
+sysfs_in_reg(4);
+sysfs_in_reg(5);
+sysfs_in_reg(6);
+sysfs_in_reg(7);
+sysfs_in_reg(8);
+
+#define device_create_file_in(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_in##offset##_input.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_in##offset##_max.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_in##offset##_min.dev_attr); \
+} while (0)
+
+#define show_fan_reg(reg) \
+static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
+                       char *buf) \
+{ \
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+       int nr = sensor_attr->index - 1; \
+       struct w83792d_data *data = w83792d_update_device(dev); \
+       return sprintf(buf,"%d\n", \
+               FAN_FROM_REG(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \
+}
+
+show_fan_reg(fan);
+show_fan_reg(fan_min);
+
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index - 1;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct w83792d_data *data = i2c_get_clientdata(client);
+       u32 val;
+
+       val = simple_strtoul(buf, NULL, 10);
+       data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+       w83792d_write_value(client, W83792D_REG_FAN_MIN[nr],
+                               data->fan_min[nr]);
+
+       return count;
+}
+
+static ssize_t
+show_fan_div(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index;
+       struct w83792d_data *data = w83792d_update_device(dev);
+       return sprintf(buf, "%u\n", DIV_FROM_REG(data->fan_div[nr - 1]));
+}
+
+/* Note: we save and restore the fan minimum here, because its value is
+   determined in part by the fan divisor.  This follows the principle of
+   least suprise; the user doesn't expect the fan minimum to change just
+   because the divisor changed. */
+static ssize_t
+store_fan_div(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index - 1;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct w83792d_data *data = i2c_get_clientdata(client);
+       unsigned long min;
+       /*u8 reg;*/
+       u8 fan_div_reg = 0;
+       u8 tmp_fan_div;
+
+       /* Save fan_min */
+       min = FAN_FROM_REG(data->fan_min[nr],
+                          DIV_FROM_REG(data->fan_div[nr]));
+
+       data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10));
+
+       fan_div_reg = w83792d_read_value(client, W83792D_REG_FAN_DIV[nr >> 1]);
+       fan_div_reg &= (nr & 0x01) ? 0x8f : 0xf8;
+       tmp_fan_div = (nr & 0x01) ? (((data->fan_div[nr]) << 4) & 0x70)
+                                       : ((data->fan_div[nr]) & 0x07);
+       w83792d_write_value(client, W83792D_REG_FAN_DIV[nr >> 1],
+                                       fan_div_reg | tmp_fan_div);
+
+       /* Restore fan_min */
+       data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+       w83792d_write_value(client, W83792D_REG_FAN_MIN[nr], data->fan_min[nr]);
+
+       return count;
+}
+
+#define sysfs_fan(offset) \
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan, NULL, \
+                               offset); \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
+                               show_fan_div, store_fan_div, offset); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+                               show_fan_min, store_fan_min, offset);
+
+sysfs_fan(1);
+sysfs_fan(2);
+sysfs_fan(3);
+sysfs_fan(4);
+sysfs_fan(5);
+sysfs_fan(6);
+sysfs_fan(7);
+
+#define device_create_file_fan(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_fan##offset##_input.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_fan##offset##_div.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_fan##offset##_min.dev_attr); \
+} while (0)
+
+
+/* read/write the temperature1, includes measured value and limits */
+
+static ssize_t show_temp1(struct device *dev, struct device_attribute *attr,
+                               char *buf)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index;
+       struct w83792d_data *data = w83792d_update_device(dev);
+       return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp1[nr]));
+}
+
+static ssize_t store_temp1(struct device *dev, struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct w83792d_data *data = i2c_get_clientdata(client);
+       s32 val;
+
+       val = simple_strtol(buf, NULL, 10);
+
+       data->temp1[nr] = TEMP1_TO_REG(val);
+       w83792d_write_value(client, W83792D_REG_TEMP1[nr],
+               data->temp1[nr]);
+
+       return count;
+}
+
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1,
+                               store_temp1, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1,
+                               store_temp1, 2);
+
+#define device_create_file_temp1(client) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_temp1_input.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_temp1_max.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_temp1_max_hyst.dev_attr); \
+} while (0)
+
+
+/* read/write the temperature2-3, includes measured value and limits */
+
+static ssize_t show_temp23(struct device *dev, struct device_attribute *attr,
+                               char *buf)
+{
+       struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
+       int nr = sensor_attr->nr;
+       int index = sensor_attr->index;
+       struct w83792d_data *data = w83792d_update_device(dev);
+       return sprintf(buf,"%ld\n",
+               (long)TEMP_ADD_FROM_REG(data->temp_add[nr][index],
+                       data->temp_add[nr][index+1]));
+}
+
+static ssize_t store_temp23(struct device *dev, struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
+       int nr = sensor_attr->nr;
+       int index = sensor_attr->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct w83792d_data *data = i2c_get_clientdata(client);
+       s32 val;
+
+       val = simple_strtol(buf, NULL, 10);
+
+       data->temp_add[nr][index] = TEMP_ADD_TO_REG_HIGH(val);
+       data->temp_add[nr][index+1] = TEMP_ADD_TO_REG_LOW(val);
+       w83792d_write_value(client, W83792D_REG_TEMP_ADD[nr][index],
+               data->temp_add[nr][index]);
+       w83792d_write_value(client, W83792D_REG_TEMP_ADD[nr][index+1],
+               data->temp_add[nr][index+1]);
+
+       return count;
+}
+
+#define sysfs_temp23(name,idx) \
+static SENSOR_DEVICE_ATTR_2(name##_input, S_IRUGO, show_temp23, NULL, \
+                               idx, 0); \
+static SENSOR_DEVICE_ATTR_2(name##_max, S_IRUGO | S_IWUSR, \
+                               show_temp23, store_temp23, idx, 2); \
+static SENSOR_DEVICE_ATTR_2(name##_max_hyst, S_IRUGO | S_IWUSR, \
+                               show_temp23, store_temp23, idx, 4);
+
+sysfs_temp23(temp2,0)
+sysfs_temp23(temp3,1)
+
+#define device_create_file_temp_add(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_temp##offset##_input.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_temp##offset##_max.dev_attr); \
+device_create_file(&client->dev, \
+&sensor_dev_attr_temp##offset##_max_hyst.dev_attr); \
+} while (0)
+
+
+/* get reatime status of all sensors items: voltage, temp, fan */
+static ssize_t
+show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct w83792d_data *data = w83792d_update_device(dev);
+       return sprintf(buf, "%d\n", data->alarms);
+}
+
+static
+DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+#define device_create_file_alarms(client) \
+device_create_file(&client->dev, &dev_attr_alarms);
+
+
+
+static ssize_t
+show_pwm(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index;
+       struct w83792d_data *data = w83792d_update_device(dev);
+       return sprintf(buf, "%ld\n", (long) PWM_FROM_REG(data->pwm[nr-1]));
+}
+
+static ssize_t
+show_pwmenable(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index - 1;
+       struct w83792d_data *data = w83792d_update_device(dev);
+       long pwm_enable_tmp = 1;
+
+       switch (data->pwmenable[nr]) {
+       case 0:
+               pwm_enable_tmp = 1; /* manual mode */
+               break;
+       case 1:
+               pwm_enable_tmp = 3; /*thermal cruise/Smart Fan I */
+               break;
+       case 2:
+               pwm_enable_tmp = 2; /* Smart Fan II */
+               break;
+       }
+
+       return sprintf(buf, "%ld\n", pwm_enable_tmp);
+}
+
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index - 1;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct w83792d_data *data = i2c_get_clientdata(client);
+       u32 val;
+
+       val = simple_strtoul(buf, NULL, 10);
+       data->pwm[nr] = PWM_TO_REG(val);
+       w83792d_write_value(client, W83792D_REG_PWM[nr], data->pwm[nr]);
+
+       return count;
+}
+
+static ssize_t
+store_pwmenable(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index - 1;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct w83792d_data *data = i2c_get_clientdata(client);
+       u32 val;
+       u8 fan_cfg_tmp, cfg1_tmp, cfg2_tmp, cfg3_tmp, cfg4_tmp;
+
+       val = simple_strtoul(buf, NULL, 10);
+       switch (val) {
+       case 1:
+               data->pwmenable[nr] = 0; /* manual mode */
+               break;
+       case 2:
+               data->pwmenable[nr] = 2; /* Smart Fan II */
+               break;
+       case 3:
+               data->pwmenable[nr] = 1; /* thermal cruise/Smart Fan I */
+               break;
+       default:
+               return -EINVAL;
+       }
+       cfg1_tmp = data->pwmenable[0];
+       cfg2_tmp = (data->pwmenable[1]) << 2;
+       cfg3_tmp = (data->pwmenable[2]) << 4;
+       cfg4_tmp = w83792d_read_value(client,W83792D_REG_FAN_CFG) & 0xc0;
+       fan_cfg_tmp = ((cfg4_tmp | cfg3_tmp) | cfg2_tmp) | cfg1_tmp;
+       w83792d_write_value(client, W83792D_REG_FAN_CFG, fan_cfg_tmp);
+
+       return count;
+}
+
+#define sysfs_pwm(offset) \
+static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
+                               show_pwm, store_pwm, offset); \
+static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
+                               show_pwmenable, store_pwmenable, offset); \
+
+sysfs_pwm(1);
+sysfs_pwm(2);
+sysfs_pwm(3);
+
+
+#define device_create_file_pwm(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_pwm##offset.dev_attr); \
+} while (0)
+
+#define device_create_file_pwmenable(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_pwm##offset##_enable.dev_attr); \
+} while (0)
+
+
+static ssize_t
+show_pwm_mode(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index;
+       struct w83792d_data *data = w83792d_update_device(dev);
+       return sprintf(buf, "%d\n", data->pwm_mode[nr-1]);
+}
+
+static ssize_t
+store_pwm_mode(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index - 1;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct w83792d_data *data = i2c_get_clientdata(client);
+       u32 val;
+       u8 pwm_mode_mask = 0;
+
+       val = simple_strtoul(buf, NULL, 10);
+       data->pwm_mode[nr] = SENSORS_LIMIT(val, 0, 1);
+       pwm_mode_mask = w83792d_read_value(client,
+               W83792D_REG_PWM[nr]) & 0x7f;
+       w83792d_write_value(client, W83792D_REG_PWM[nr],
+               ((data->pwm_mode[nr]) << 7) | pwm_mode_mask);
+
+       return count;
+}
+
+#define sysfs_pwm_mode(offset) \
+static SENSOR_DEVICE_ATTR(pwm##offset##_mode, S_IRUGO | S_IWUSR, \
+                               show_pwm_mode, store_pwm_mode, offset);
+
+sysfs_pwm_mode(1);
+sysfs_pwm_mode(2);
+sysfs_pwm_mode(3);
+
+#define device_create_file_pwm_mode(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_pwm##offset##_mode.dev_attr); \
+} while (0)
+
+
+static ssize_t
+show_regs_chassis(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct w83792d_data *data = w83792d_update_device(dev);
+       return sprintf(buf, "%d\n", data->chassis);
+}
+
+static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL);
+
+#define device_create_file_chassis(client) \
+do { \
+device_create_file(&client->dev, &dev_attr_chassis); \
+} while (0)
+
+
+static ssize_t
+show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct w83792d_data *data = w83792d_update_device(dev);
+       return sprintf(buf, "%d\n", data->chassis_clear);
+}
+
+static ssize_t
+store_chassis_clear(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct w83792d_data *data = i2c_get_clientdata(client);
+       u32 val;
+       u8 temp1 = 0, temp2 = 0;
+
+       val = simple_strtoul(buf, NULL, 10);
+
+       data->chassis_clear = SENSORS_LIMIT(val, 0 ,1);
+       temp1 = ((data->chassis_clear) << 7) & 0x80;
+       temp2 = w83792d_read_value(client,
+               W83792D_REG_CHASSIS_CLR) & 0x7f;
+       w83792d_write_value(client, W83792D_REG_CHASSIS_CLR, temp1 | temp2);
+
+       return count;
+}
+
+static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR,
+               show_chassis_clear, store_chassis_clear);
+
+#define device_create_file_chassis_clear(client) \
+do { \
+device_create_file(&client->dev, &dev_attr_chassis_clear); \
+} while (0)
+
+
+
+/* For Smart Fan I / Thermal Cruise */
+static ssize_t
+show_thermal_cruise(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index;
+       struct w83792d_data *data = w83792d_update_device(dev);
+       return sprintf(buf, "%ld\n", (long)data->thermal_cruise[nr-1]);
+}
+
+static ssize_t
+store_thermal_cruise(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index - 1;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct w83792d_data *data = i2c_get_clientdata(client);
+       u32 val;
+       u8 target_tmp=0, target_mask=0;
+
+       val = simple_strtoul(buf, NULL, 10);
+       target_tmp = val;
+       target_tmp = target_tmp & 0x7f;
+       target_mask = w83792d_read_value(client, W83792D_REG_THERMAL[nr]) & 0x80;
+       data->thermal_cruise[nr] = SENSORS_LIMIT(target_tmp, 0, 255);
+       w83792d_write_value(client, W83792D_REG_THERMAL[nr],
+               (data->thermal_cruise[nr]) | target_mask);
+
+       return count;
+}
+
+#define sysfs_thermal_cruise(offset) \
+static SENSOR_DEVICE_ATTR(thermal_cruise##offset, S_IRUGO | S_IWUSR, \
+                       show_thermal_cruise, store_thermal_cruise, offset);
+
+sysfs_thermal_cruise(1);
+sysfs_thermal_cruise(2);
+sysfs_thermal_cruise(3);
+
+#define device_create_file_thermal_cruise(client, offset) \
+do { \
+device_create_file(&client->dev, \
+&sensor_dev_attr_thermal_cruise##offset.dev_attr); \
+} while (0)
+
+
+/* For Smart Fan I/Thermal Cruise and Smart Fan II */
+static ssize_t
+show_tolerance(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index;
+       struct w83792d_data *data = w83792d_update_device(dev);
+       return sprintf(buf, "%ld\n", (long)data->tolerance[nr-1]);
+}
+
+static ssize_t
+store_tolerance(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index - 1;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct w83792d_data *data = i2c_get_clientdata(client);
+       u32 val;
+       u8 tol_tmp, tol_mask;
+
+       val = simple_strtoul(buf, NULL, 10);
+       tol_mask = w83792d_read_value(client,
+               W83792D_REG_TOLERANCE[nr]) & ((nr == 1) ? 0x0f : 0xf0);
+       tol_tmp = SENSORS_LIMIT(val, 0, 15);
+       tol_tmp &= 0x0f;
+       data->tolerance[nr] = tol_tmp;
+       if (nr == 1) {
+               tol_tmp <<= 4;
+       }
+       w83792d_write_value(client, W83792D_REG_TOLERANCE[nr],
+               tol_mask | tol_tmp);
+
+       return count;
+}
+
+#define sysfs_tolerance(offset) \
+static SENSOR_DEVICE_ATTR(tolerance##offset, S_IRUGO | S_IWUSR, \
+                               show_tolerance, store_tolerance, offset);
+
+sysfs_tolerance(1);
+sysfs_tolerance(2);
+sysfs_tolerance(3);
+
+#define device_create_file_tolerance(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_tolerance##offset.dev_attr); \
+} while (0)
+
+
+/* For Smart Fan II */
+static ssize_t
+show_sf2_point(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
+       int nr = sensor_attr->nr;
+       int index = sensor_attr->index;
+       struct w83792d_data *data = w83792d_update_device(dev);
+       return sprintf(buf, "%ld\n", (long)data->sf2_points[index-1][nr-1]);
+}
+
+static ssize_t
+store_sf2_point(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
+       int nr = sensor_attr->nr - 1;
+       int index = sensor_attr->index - 1;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct w83792d_data *data = i2c_get_clientdata(client);
+       u32 val;
+       u8 mask_tmp = 0;
+
+       val = simple_strtoul(buf, NULL, 10);
+       data->sf2_points[index][nr] = SENSORS_LIMIT(val, 0, 127);
+       mask_tmp = w83792d_read_value(client,
+                                       W83792D_REG_POINTS[index][nr]) & 0x80;
+       w83792d_write_value(client, W83792D_REG_POINTS[index][nr],
+               mask_tmp|data->sf2_points[index][nr]);
+
+       return count;
+}
+
+#define sysfs_sf2_point(offset, index) \
+static SENSOR_DEVICE_ATTR_2(sf2_point##offset##_fan##index, S_IRUGO | S_IWUSR, \
+                               show_sf2_point, store_sf2_point, offset, index);
+
+sysfs_sf2_point(1, 1); /* Fan1 */
+sysfs_sf2_point(2, 1); /* Fan1 */
+sysfs_sf2_point(3, 1); /* Fan1 */
+sysfs_sf2_point(4, 1); /* Fan1 */
+sysfs_sf2_point(1, 2); /* Fan2 */
+sysfs_sf2_point(2, 2); /* Fan2 */
+sysfs_sf2_point(3, 2); /* Fan2 */
+sysfs_sf2_point(4, 2); /* Fan2 */
+sysfs_sf2_point(1, 3); /* Fan3 */
+sysfs_sf2_point(2, 3); /* Fan3 */
+sysfs_sf2_point(3, 3); /* Fan3 */
+sysfs_sf2_point(4, 3); /* Fan3 */
+
+#define device_create_file_sf2_point(client, offset, index) \
+do { \
+device_create_file(&client->dev, \
+&sensor_dev_attr_sf2_point##offset##_fan##index.dev_attr); \
+} while (0)
+
+
+static ssize_t
+show_sf2_level(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
+       int nr = sensor_attr->nr;
+       int index = sensor_attr->index;
+       struct w83792d_data *data = w83792d_update_device(dev);
+       return sprintf(buf, "%d\n",
+                       (((data->sf2_levels[index-1][nr]) * 100) / 15));
+}
+
+static ssize_t
+store_sf2_level(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
+       int nr = sensor_attr->nr;
+       int index = sensor_attr->index - 1;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct w83792d_data *data = i2c_get_clientdata(client);
+       u32 val;
+       u8 mask_tmp=0, level_tmp=0;
+
+       val = simple_strtoul(buf, NULL, 10);
+       data->sf2_levels[index][nr] = SENSORS_LIMIT((val * 15) / 100, 0, 15);
+       mask_tmp = w83792d_read_value(client, W83792D_REG_LEVELS[index][nr])
+               & ((nr==3) ? 0xf0 : 0x0f);
+       if (nr==3) {
+               level_tmp = data->sf2_levels[index][nr];
+       } else {
+               level_tmp = data->sf2_levels[index][nr] << 4;
+       }
+       w83792d_write_value(client, W83792D_REG_LEVELS[index][nr], level_tmp | mask_tmp);
+
+       return count;
+}
+
+#define sysfs_sf2_level(offset, index) \
+static SENSOR_DEVICE_ATTR_2(sf2_level##offset##_fan##index, S_IRUGO | S_IWUSR, \
+                               show_sf2_level, store_sf2_level, offset, index);
+
+sysfs_sf2_level(1, 1); /* Fan1 */
+sysfs_sf2_level(2, 1); /* Fan1 */
+sysfs_sf2_level(3, 1); /* Fan1 */
+sysfs_sf2_level(1, 2); /* Fan2 */
+sysfs_sf2_level(2, 2); /* Fan2 */
+sysfs_sf2_level(3, 2); /* Fan2 */
+sysfs_sf2_level(1, 3); /* Fan3 */
+sysfs_sf2_level(2, 3); /* Fan3 */
+sysfs_sf2_level(3, 3); /* Fan3 */
+
+#define device_create_file_sf2_level(client, offset, index) \
+do { \
+device_create_file(&client->dev, \
+&sensor_dev_attr_sf2_level##offset##_fan##index.dev_attr); \
+} while (0)
+
+
+/* This function is called when:
+     * w83792d_driver is inserted (when this module is loaded), for each
+       available adapter
+     * when a new adapter is inserted (and w83792d_driver is still present) */
+static int
+w83792d_attach_adapter(struct i2c_adapter *adapter)
+{
+       if (!(adapter->class & I2C_CLASS_HWMON))
+               return 0;
+       return i2c_probe(adapter, &addr_data, w83792d_detect);
+}
+
+
+static int
+w83792d_create_subclient(struct i2c_adapter *adapter,
+                               struct i2c_client *new_client, int addr,
+                               struct i2c_client **sub_cli)
+{
+       int err;
+       struct i2c_client *sub_client;
+
+       (*sub_cli) = sub_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (!(sub_client)) {
+               return -ENOMEM;
+       }
+       memset(sub_client, 0x00, sizeof(struct i2c_client));
+       sub_client->addr = 0x48 + addr;
+       i2c_set_clientdata(sub_client, NULL);
+       sub_client->adapter = adapter;
+       sub_client->driver = &w83792d_driver;
+       sub_client->flags = 0;
+       strlcpy(sub_client->name, "w83792d subclient", I2C_NAME_SIZE);
+       if ((err = i2c_attach_client(sub_client))) {
+               dev_err(&new_client->dev, "subclient registration "
+                       "at address 0x%x failed\n", sub_client->addr);
+               kfree(sub_client);
+               return err;
+       }
+       return 0;
+}
+
+
+static int
+w83792d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
+               struct i2c_client *new_client)
+{
+       int i, id, err;
+       u8 val;
+       struct w83792d_data *data = i2c_get_clientdata(new_client);
+
+       id = i2c_adapter_id(adapter);
+       if (force_subclients[0] == id && force_subclients[1] == address) {
+               for (i = 2; i <= 3; i++) {
+                       if (force_subclients[i] < 0x48 ||
+                           force_subclients[i] > 0x4f) {
+                               dev_err(&new_client->dev, "invalid subclient "
+                                       "address %d; must be 0x48-0x4f\n",
+                                       force_subclients[i]);
+                               err = -ENODEV;
+                               goto ERROR_SC_0;
+                       }
+               }
+               w83792d_write_value(new_client, W83792D_REG_I2C_SUBADDR,
+                                       (force_subclients[2] & 0x07) |
+                                       ((force_subclients[3] & 0x07) << 4));
+       }
+
+       val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR);
+       if (!(val & 0x08)) {
+               err = w83792d_create_subclient(adapter, new_client, val & 0x7,
+                                               &data->lm75[0]);
+               if (err < 0)
+                       goto ERROR_SC_0;
+       }
+       if (!(val & 0x80)) {
+               if ((data->lm75[0] != NULL) &&
+                       ((val & 0x7) == ((val >> 4) & 0x7))) {
+                       dev_err(&new_client->dev, "duplicate addresses 0x%x, "
+                               "use force_subclient\n", data->lm75[0]->addr);
+                       err = -ENODEV;
+                       goto ERROR_SC_1;
+               }
+               err = w83792d_create_subclient(adapter, new_client,
+                                               (val >> 4) & 0x7, &data->lm75[1]);
+               if (err < 0)
+                       goto ERROR_SC_1;
+       }
+
+       return 0;
+
+/* Undo inits in case of errors */
+
+ERROR_SC_1:
+       if (data->lm75[0] != NULL) {
+               i2c_detach_client(data->lm75[0]);
+               kfree(data->lm75[0]);
+       }
+ERROR_SC_0:
+       return err;
+}
+
+
+static int
+w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+       int i = 0, val1 = 0, val2;
+       struct i2c_client *new_client;
+       struct w83792d_data *data;
+       int err = 0;
+       const char *client_name = "";
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+               goto ERROR0;
+       }
+
+       /* OK. For now, we presume we have a valid client. We now create the
+          client structure, even though we cannot fill it completely yet.
+          But it allows us to access w83792d_{read,write}_value. */
+
+       if (!(data = kmalloc(sizeof(struct w83792d_data), GFP_KERNEL))) {
+               err = -ENOMEM;
+               goto ERROR0;
+       }
+       memset(data, 0, sizeof(struct w83792d_data));
+
+       new_client = &data->client;
+       i2c_set_clientdata(new_client, data);
+       new_client->addr = address;
+       init_MUTEX(&data->lock);
+       new_client->adapter = adapter;
+       new_client->driver = &w83792d_driver;
+       new_client->flags = 0;
+
+       /* Now, we do the remaining detection. */
+
+       /* The w83792d may be stuck in some other bank than bank 0. This may
+          make reading other information impossible. Specify a force=... or
+          force_*=... parameter, and the Winbond will be reset to the right
+          bank. */
+       if (kind < 0) {
+               if (w83792d_read_value(new_client, W83792D_REG_CONFIG) & 0x80) {
+                       dev_warn(&new_client->dev, "Detection failed at step "
+                               "3\n");
+                       goto ERROR1;
+               }
+               val1 = w83792d_read_value(new_client, W83792D_REG_BANK);
+               val2 = w83792d_read_value(new_client, W83792D_REG_CHIPMAN);
+               /* Check for Winbond ID if in bank 0 */
+               if (!(val1 & 0x07)) {  /* is Bank0 */
+                       if (((!(val1 & 0x80)) && (val2 != 0xa3)) ||
+                            ((val1 & 0x80) && (val2 != 0x5c))) {
+                               goto ERROR1;
+                       }
+               }
+               /* If Winbond chip, address of chip and W83792D_REG_I2C_ADDR
+                  should match */
+               if (w83792d_read_value(new_client,
+                                       W83792D_REG_I2C_ADDR) != address) {
+                       dev_warn(&new_client->dev, "Detection failed "
+                               "at step 5\n");
+                       goto ERROR1;
+               }
+       }
+
+       /* We have either had a force parameter, or we have already detected the
+          Winbond. Put it now into bank 0 and Vendor ID High Byte */
+       w83792d_write_value(new_client,
+                           W83792D_REG_BANK,
+                           (w83792d_read_value(new_client,
+                               W83792D_REG_BANK) & 0x78) | 0x80);
+
+       /* Determine the chip type. */
+       if (kind <= 0) {
+               /* get vendor ID */
+               val2 = w83792d_read_value(new_client, W83792D_REG_CHIPMAN);
+               if (val2 != 0x5c) {  /* the vendor is NOT Winbond */
+                       goto ERROR1;
+               }
+               val1 = w83792d_read_value(new_client, W83792D_REG_WCHIPID);
+               if (val1 == 0x7a && address >= 0x2c) {
+                       kind = w83792d;
+               } else {
+                       if (kind == 0)
+                                       dev_warn(&new_client->dev,
+                                       "w83792d: Ignoring 'force' parameter for"
+                                       " unknown chip at adapter %d, address"
+                                       " 0x%02x\n", i2c_adapter_id(adapter),
+                                       address);
+                       goto ERROR1;
+               }
+       }
+
+       if (kind == w83792d) {
+               client_name = "w83792d";
+       } else {
+               dev_err(&new_client->dev, "w83792d: Internal error: unknown"
+                                         " kind (%d)?!?", kind);
+               goto ERROR1;
+       }
+
+       /* Fill in the remaining client fields and put into the global list */
+       strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
+       data->type = kind;
+
+       data->valid = 0;
+       init_MUTEX(&data->update_lock);
+
+       /* Tell the I2C layer a new client has arrived */
+       if ((err = i2c_attach_client(new_client)))
+               goto ERROR1;
+
+       if ((err = w83792d_detect_subclients(adapter, address,
+                       kind, new_client)))
+               goto ERROR2;
+
+       /* Initialize the chip */
+       w83792d_init_client(new_client);
+
+       /* A few vars need to be filled upon startup */
+       for (i = 1; i <= 7; i++) {
+               data->fan_min[i - 1] = w83792d_read_value(new_client,
+                                       W83792D_REG_FAN_MIN[i]);
+       }
+
+       /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto ERROR3;
+       }
+       device_create_file_in(new_client, 0);
+       device_create_file_in(new_client, 1);
+       device_create_file_in(new_client, 2);
+       device_create_file_in(new_client, 3);
+       device_create_file_in(new_client, 4);
+       device_create_file_in(new_client, 5);
+       device_create_file_in(new_client, 6);
+       device_create_file_in(new_client, 7);
+       device_create_file_in(new_client, 8);
+
+       device_create_file_fan(new_client, 1);
+       device_create_file_fan(new_client, 2);
+       device_create_file_fan(new_client, 3);
+       device_create_file_fan(new_client, 4);
+       device_create_file_fan(new_client, 5);
+       device_create_file_fan(new_client, 6);
+       device_create_file_fan(new_client, 7);
+
+       device_create_file_temp1(new_client);           /* Temp1 */
+       device_create_file_temp_add(new_client, 2);     /* Temp2 */
+       device_create_file_temp_add(new_client, 3);     /* Temp3 */
+
+       device_create_file_alarms(new_client);
+
+       device_create_file_pwm(new_client, 1);
+       device_create_file_pwm(new_client, 2);
+       device_create_file_pwm(new_client, 3);
+
+       device_create_file_pwmenable(new_client, 1);
+       device_create_file_pwmenable(new_client, 2);
+       device_create_file_pwmenable(new_client, 3);
+
+       device_create_file_pwm_mode(new_client, 1);
+       device_create_file_pwm_mode(new_client, 2);
+       device_create_file_pwm_mode(new_client, 3);
+
+       device_create_file_chassis(new_client);
+       device_create_file_chassis_clear(new_client);
+
+       device_create_file_thermal_cruise(new_client, 1);
+       device_create_file_thermal_cruise(new_client, 2);
+       device_create_file_thermal_cruise(new_client, 3);
+
+       device_create_file_tolerance(new_client, 1);
+       device_create_file_tolerance(new_client, 2);
+       device_create_file_tolerance(new_client, 3);
+
+       device_create_file_sf2_point(new_client, 1, 1); /* Fan1 */
+       device_create_file_sf2_point(new_client, 2, 1); /* Fan1 */
+       device_create_file_sf2_point(new_client, 3, 1); /* Fan1 */
+       device_create_file_sf2_point(new_client, 4, 1); /* Fan1 */
+       device_create_file_sf2_point(new_client, 1, 2); /* Fan2 */
+       device_create_file_sf2_point(new_client, 2, 2); /* Fan2 */
+       device_create_file_sf2_point(new_client, 3, 2); /* Fan2 */
+       device_create_file_sf2_point(new_client, 4, 2); /* Fan2 */
+       device_create_file_sf2_point(new_client, 1, 3); /* Fan3 */
+       device_create_file_sf2_point(new_client, 2, 3); /* Fan3 */
+       device_create_file_sf2_point(new_client, 3, 3); /* Fan3 */
+       device_create_file_sf2_point(new_client, 4, 3); /* Fan3 */
+
+       device_create_file_sf2_level(new_client, 1, 1); /* Fan1 */
+       device_create_file_sf2_level(new_client, 2, 1); /* Fan1 */
+       device_create_file_sf2_level(new_client, 3, 1); /* Fan1 */
+       device_create_file_sf2_level(new_client, 1, 2); /* Fan2 */
+       device_create_file_sf2_level(new_client, 2, 2); /* Fan2 */
+       device_create_file_sf2_level(new_client, 3, 2); /* Fan2 */
+       device_create_file_sf2_level(new_client, 1, 3); /* Fan3 */
+       device_create_file_sf2_level(new_client, 2, 3); /* Fan3 */
+       device_create_file_sf2_level(new_client, 3, 3); /* Fan3 */
+
+       return 0;
+
+ERROR3:
+       if (data->lm75[0] != NULL) {
+               i2c_detach_client(data->lm75[0]);
+               kfree(data->lm75[0]);
+       }
+       if (data->lm75[1] != NULL) {
+               i2c_detach_client(data->lm75[1]);
+               kfree(data->lm75[1]);
+       }
+ERROR2:
+       i2c_detach_client(new_client);
+ERROR1:
+       kfree(data);
+ERROR0:
+       return err;
+}
+
+static int
+w83792d_detach_client(struct i2c_client *client)
+{
+       struct w83792d_data *data = i2c_get_clientdata(client);
+       int err;
+
+       /* main client */
+       if (data)
+               hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
+               return err;
+
+       /* main client */
+       if (data)
+               kfree(data);
+       /* subclient */
+       else
+               kfree(client);
+
+       return 0;
+}
+
+/* The SMBus locks itself, usually, but nothing may access the Winbond between
+   bank switches. ISA access must always be locked explicitly!
+   We ignore the W83792D BUSY flag at this moment - it could lead to deadlocks,
+   would slow down the W83792D access and should not be necessary.
+   There are some ugly typecasts here, but the good news is - they should
+   nowhere else be necessary! */
+static int
+w83792d_read_value(struct i2c_client *client, u8 reg)
+{
+       int res=0;
+       res = i2c_smbus_read_byte_data(client, reg);
+
+       return res;
+}
+
+static int
+w83792d_write_value(struct i2c_client *client, u8 reg, u8 value)
+{
+       i2c_smbus_write_byte_data(client, reg,  value);
+       return 0;
+}
+
+/* Called when we have found a new W83792D. It should set limits, etc. */
+static void
+w83792d_init_client(struct i2c_client *client)
+{
+       u8 temp2_cfg, temp3_cfg, vid_in_b;
+
+       if (init) {
+               w83792d_write_value(client, W83792D_REG_CONFIG, 0x80);
+       }
+       /* Clear the bit6 of W83792D_REG_VID_IN_B(set it into 0):
+          W83792D_REG_VID_IN_B bit6 = 0: the high/low limit of
+            vin0/vin1 can be modified by user;
+          W83792D_REG_VID_IN_B bit6 = 1: the high/low limit of
+            vin0/vin1 auto-updated, can NOT be modified by user. */
+       vid_in_b = w83792d_read_value(client, W83792D_REG_VID_IN_B);
+       w83792d_write_value(client, W83792D_REG_VID_IN_B,
+                           vid_in_b & 0xbf);
+
+       temp2_cfg = w83792d_read_value(client, W83792D_REG_TEMP2_CONFIG);
+       temp3_cfg = w83792d_read_value(client, W83792D_REG_TEMP3_CONFIG);
+       w83792d_write_value(client, W83792D_REG_TEMP2_CONFIG,
+                               temp2_cfg & 0xe6);
+       w83792d_write_value(client, W83792D_REG_TEMP3_CONFIG,
+                               temp3_cfg & 0xe6);
+
+       /* Start monitoring */
+       w83792d_write_value(client, W83792D_REG_CONFIG,
+                           (w83792d_read_value(client,
+                                               W83792D_REG_CONFIG) & 0xf7)
+                           | 0x01);
+}
+
+static struct w83792d_data *w83792d_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct w83792d_data *data = i2c_get_clientdata(client);
+       int i, j;
+       u8 reg_array_tmp[4], pwm_array_tmp[7], reg_tmp;
+
+       down(&data->update_lock);
+
+       if (time_after
+           (jiffies - data->last_updated, (unsigned long) (HZ * 3))
+           || time_before(jiffies, data->last_updated) || !data->valid) {
+               dev_dbg(dev, "Starting device update\n");
+
+               /* Update the voltages measured value and limits */
+               for (i = 0; i < 9; i++) {
+                       data->in[i] = w83792d_read_value(client,
+                                               W83792D_REG_IN[i]);
+                       data->in_max[i] = w83792d_read_value(client,
+                                               W83792D_REG_IN_MAX[i]);
+                       data->in_min[i] = w83792d_read_value(client,
+                                               W83792D_REG_IN_MIN[i]);
+               }
+               data->low_bits[0] = w83792d_read_value(client,
+                                               W83792D_REG_LOW_BITS1);
+               data->low_bits[1] = w83792d_read_value(client,
+                                               W83792D_REG_LOW_BITS2);
+               for (i = 0; i < 7; i++) {
+                       /* Update the Fan measured value and limits */
+                       data->fan[i] = w83792d_read_value(client,
+                                               W83792D_REG_FAN[i]);
+                       data->fan_min[i] = w83792d_read_value(client,
+                                               W83792D_REG_FAN_MIN[i]);
+                       /* Update the PWM/DC Value and PWM/DC flag */
+                       pwm_array_tmp[i] = w83792d_read_value(client,
+                                               W83792D_REG_PWM[i]);
+                       data->pwm[i] = pwm_array_tmp[i] & 0x0f;
+                       data->pwm_mode[i] = (pwm_array_tmp[i] >> 7) & 0x01;
+               }
+
+               reg_tmp = w83792d_read_value(client, W83792D_REG_FAN_CFG);
+               data->pwmenable[0] = reg_tmp & 0x03;
+               data->pwmenable[1] = (reg_tmp>>2) & 0x03;
+               data->pwmenable[2] = (reg_tmp>>4) & 0x03;
+
+               for (i = 0; i < 3; i++) {
+                       data->temp1[i] = w83792d_read_value(client,
+                                                       W83792D_REG_TEMP1[i]);
+               }
+               for (i = 0; i < 2; i++) {
+                       for (j = 0; j < 6; j++) {
+                               data->temp_add[i][j] = w83792d_read_value(
+                                       client,W83792D_REG_TEMP_ADD[i][j]);
+                       }
+               }
+
+               /* Update the Fan Divisor */
+               for (i = 0; i < 4; i++) {
+                       reg_array_tmp[i] = w83792d_read_value(client,
+                                                       W83792D_REG_FAN_DIV[i]);
+               }
+               data->fan_div[0] = reg_array_tmp[0] & 0x07;
+               data->fan_div[1] = (reg_array_tmp[0] >> 4) & 0x07;
+               data->fan_div[2] = reg_array_tmp[1] & 0x07;
+               data->fan_div[3] = (reg_array_tmp[1] >> 4) & 0x07;
+               data->fan_div[4] = reg_array_tmp[2] & 0x07;
+               data->fan_div[5] = (reg_array_tmp[2] >> 4) & 0x07;
+               data->fan_div[6] = reg_array_tmp[3] & 0x07;
+
+               /* Update the realtime status */
+               data->alarms = w83792d_read_value(client, W83792D_REG_ALARM1) +
+                       (w83792d_read_value(client, W83792D_REG_ALARM2) << 8) +
+                       (w83792d_read_value(client, W83792D_REG_ALARM3) << 16);
+
+               /* Update CaseOpen status and it's CLR_CHS. */
+               data->chassis = (w83792d_read_value(client,
+                       W83792D_REG_CHASSIS) >> 5) & 0x01;
+               data->chassis_clear = (w83792d_read_value(client,
+                       W83792D_REG_CHASSIS_CLR) >> 7) & 0x01;
+
+               /* Update Thermal Cruise/Smart Fan I target value */
+               for (i = 0; i < 3; i++) {
+                       data->thermal_cruise[i] =
+                               w83792d_read_value(client,
+                               W83792D_REG_THERMAL[i]) & 0x7f;
+               }
+
+               /* Update Smart Fan I/II tolerance */
+               reg_tmp = w83792d_read_value(client, W83792D_REG_TOLERANCE[0]);
+               data->tolerance[0] = reg_tmp & 0x0f;
+               data->tolerance[1] = (reg_tmp >> 4) & 0x0f;
+               data->tolerance[2] = w83792d_read_value(client,
+                                       W83792D_REG_TOLERANCE[2]) & 0x0f;
+
+               /* Update Smart Fan II temperature points */
+               for (i = 0; i < 3; i++) {
+                       for (j = 0; j < 4; j++) {
+                               data->sf2_points[i][j] = w83792d_read_value(
+                                       client,W83792D_REG_POINTS[i][j]) & 0x7f;
+                       }
+               }
+
+               /* Update Smart Fan II duty cycle levels */
+               for (i = 0; i < 3; i++) {
+                       reg_tmp = w83792d_read_value(client,
+                                               W83792D_REG_LEVELS[i][0]);
+                       data->sf2_levels[i][0] = reg_tmp & 0x0f;
+                       data->sf2_levels[i][1] = (reg_tmp >> 4) & 0x0f;
+                       reg_tmp = w83792d_read_value(client,
+                                               W83792D_REG_LEVELS[i][2]);
+                       data->sf2_levels[i][2] = (reg_tmp >> 4) & 0x0f;
+                       data->sf2_levels[i][3] = reg_tmp & 0x0f;
+               }
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       up(&data->update_lock);
+
+#ifdef DEBUG
+       w83792d_print_debug(data, dev);
+#endif
+
+       return data;
+}
+
+#ifdef DEBUG
+static void w83792d_print_debug(struct w83792d_data *data, struct device *dev)
+{
+       int i=0, j=0;
+       dev_dbg(dev, "==========The following is the debug message...========\n");
+       dev_dbg(dev, "9 set of Voltages: =====>\n");
+       for (i=0; i<9; i++) {
+               dev_dbg(dev, "vin[%d] is: 0x%x\n", i, data->in[i]);
+               dev_dbg(dev, "vin[%d] max is: 0x%x\n", i, data->in_max[i]);
+               dev_dbg(dev, "vin[%d] min is: 0x%x\n", i, data->in_min[i]);
+       }
+       dev_dbg(dev, "Low Bit1 is: 0x%x\n", data->low_bits[0]);
+       dev_dbg(dev, "Low Bit2 is: 0x%x\n", data->low_bits[1]);
+       dev_dbg(dev, "7 set of Fan Counts and Duty Cycles: =====>\n");
+       for (i=0; i<7; i++) {
+               dev_dbg(dev, "fan[%d] is: 0x%x\n", i, data->fan[i]);
+               dev_dbg(dev, "fan[%d] min is: 0x%x\n", i, data->fan_min[i]);
+               dev_dbg(dev, "pwm[%d]     is: 0x%x\n", i, data->pwm[i]);
+               dev_dbg(dev, "pwm_mode[%d] is: 0x%x\n", i, data->pwm_mode[i]);
+       }
+       dev_dbg(dev, "3 set of Temperatures: =====>\n");
+       for (i=0; i<3; i++) {
+               dev_dbg(dev, "temp1[%d] is: 0x%x\n", i, data->temp1[i]);
+       }
+
+       for (i=0; i<2; i++) {
+               for (j=0; j<6; j++) {
+                       dev_dbg(dev, "temp_add[%d][%d] is: 0x%x\n", i, j,
+                                                       data->temp_add[i][j]);
+               }
+       }
+
+       for (i=0; i<7; i++) {
+               dev_dbg(dev, "fan_div[%d] is: 0x%x\n", i, data->fan_div[i]);
+       }
+       dev_dbg(dev, "==========End of the debug message...==================\n");
+       dev_dbg(dev, "\n");
+}
+#endif
+
+static int __init
+sensors_w83792d_init(void)
+{
+       return i2c_add_driver(&w83792d_driver);
+}
+
+static void __exit
+sensors_w83792d_exit(void)
+{
+       i2c_del_driver(&w83792d_driver);
+}
+
+MODULE_AUTHOR("Chunhao Huang @ Winbond <DZShen@Winbond.com.tw>");
+MODULE_DESCRIPTION("W83792AD/D driver for linux-2.6");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_w83792d_init);
+module_exit(sensors_w83792d_exit);
+
index 4469d52aba4c6faefa0bc3047b379ad614eea6d3..133e34ab1d0af1a1ab0b965ca58fb59c554d6d11 100644 (file)
@@ -36,7 +36,8 @@
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
 
 /* How many retries on register read error */
 #define MAX_RETRIES    5
  */
 
 static unsigned short normal_i2c[] = { 0x2e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /*
  * Insmod parameters
  */
 
-SENSORS_INSMOD_1(w83l785ts);
+I2C_CLIENT_INSMOD_1(w83l785ts);
 
 /*
  * The W83L785TS-S registers
@@ -105,6 +105,7 @@ static struct i2c_driver w83l785ts_driver = {
 
 struct w83l785ts_data {
        struct i2c_client client;
+       struct class_device *class_dev;
        struct semaphore update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
@@ -140,7 +141,7 @@ static int w83l785ts_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, w83l785ts_detect);
+       return i2c_probe(adapter, &addr_data, w83l785ts_detect);
 }
 
 /*
@@ -239,11 +240,19 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind)
         */
 
        /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_detach;
+       }
+
        device_create_file(&new_client->dev, &dev_attr_temp1_input);
        device_create_file(&new_client->dev, &dev_attr_temp1_max);
 
        return 0;
 
+exit_detach:
+       i2c_detach_client(new_client);
 exit_free:
        kfree(data);
 exit:
@@ -252,15 +261,15 @@ exit:
 
 static int w83l785ts_detach_client(struct i2c_client *client)
 {
+       struct w83l785ts_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                       "client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
        return 0;
 }
 
index cd170395a8c7ced66695536007f0684e2cf4201d..71c5a854ac5d646d31e03ad511ea5ceb00ef8af8 100644 (file)
@@ -4,12 +4,8 @@
 
 obj-$(CONFIG_I2C)              += i2c-core.o
 obj-$(CONFIG_I2C_CHARDEV)      += i2c-dev.o
-obj-$(CONFIG_I2C_SENSOR)       += i2c-sensor.o
 obj-y                          += busses/ chips/ algos/
 
-i2c-sensor-objs := i2c-sensor-detect.o i2c-sensor-vid.o
-
-
 ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
 EXTRA_CFLAGS += -DDEBUG
 endif
index fb5b732238ed814095319f5e7518159cd6bbd8ac..df05df1a0ef61f20de8239e36bb3202ac7ae6ae5 100644 (file)
@@ -519,8 +519,6 @@ static u32 bit_func(struct i2c_adapter *adap)
 /* -----exported algorithm data: ------------------------------------- */
 
 static struct i2c_algorithm i2c_bit_algo = {
-       .name           = "Bit-shift algorithm",
-       .id             = I2C_ALGO_BIT,
        .master_xfer    = bit_xfer,
        .functionality  = bit_func,
 };
@@ -541,8 +539,6 @@ int i2c_bit_add_bus(struct i2c_adapter *adap)
        DEB2(dev_dbg(&adap->dev, "hw routines registered.\n"));
 
        /* register new adapter to i2c module... */
-
-       adap->id |= i2c_bit_algo.id;
        adap->algo = &i2c_bit_algo;
 
        adap->timeout = 100;    /* default values, should       */
index e6cae39f47aa062c7f09eb67ed1500bf41dbf665..2db7bfc852252dbf1b74c29ede26071b522a92e1 100644 (file)
@@ -713,8 +713,6 @@ static u32 iic_func(struct i2c_adapter *adap)
 /* -----exported algorithm data: ------------------------------------- */
 
 static struct i2c_algorithm iic_algo = {
-       .name           = "ITE IIC algorithm",
-       .id             = I2C_ALGO_IIC,
        .master_xfer    = iic_xfer,
        .algo_control   = algo_control, /* ioctl */
        .functionality  = iic_func,
@@ -738,8 +736,6 @@ int i2c_iic_add_bus(struct i2c_adapter *adap)
                    adap->name));
 
        /* register new adapter to i2c module... */
-
-       adap->id |= iic_algo.id;
        adap->algo = &iic_algo;
 
        adap->timeout = 100;    /* default values, should       */
index cc3a952401f2ea8354cf89ac5e43c151bd151cbe..beb10edfe9c1774c7426945962b749b9831c7c88 100644 (file)
@@ -187,12 +187,14 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
        int numbytes = 0;
        int state;
        int ret;
+       int timeout = 100;
 
-       state = pca_status(adap);
-       if ( state != 0xF8 ) {
-               dev_dbg(&i2c_adap->dev, "bus is not idle. status is %#04x\n", state );
-               /* FIXME: what to do. Force stop ? */
-               return -EREMOTEIO;
+       while ((state = pca_status(adap)) != 0xf8 && timeout--) {
+               msleep(10);
+       }
+       if (state != 0xf8) {
+               dev_dbg(&i2c_adap->dev, "bus is not idle. status is %#04x\n", state);
+               return -EIO;
        }
 
        DEB1("{{{ XFER %d messages\n", num);
@@ -354,8 +356,6 @@ static int pca_init(struct i2c_algo_pca_data *adap)
 }
 
 static struct i2c_algorithm pca_algo = {
-       .name           = "PCA9564 algorithm",
-       .id             = I2C_ALGO_PCA,
        .master_xfer    = pca_xfer,
        .functionality  = pca_func,
 };
@@ -369,8 +369,6 @@ int i2c_pca_add_bus(struct i2c_adapter *adap)
        int rval;
 
        /* register new adapter to i2c module... */
-
-       adap->id |= pca_algo.id;
        adap->algo = &pca_algo;
 
        adap->timeout = 100;            /* default values, should       */
index 8d087dac32afc7e22575ff32be4c8a2262d3ddb1..6e498df1f717aea6f238b6ce91d990b9a7cbedfa 100644 (file)
@@ -459,8 +459,6 @@ static u32 pcf_func(struct i2c_adapter *adap)
 /* -----exported algorithm data: ------------------------------------- */
 
 static struct i2c_algorithm pcf_algo = {
-       .name           = "PCF8584 algorithm",
-       .id             = I2C_ALGO_PCF,
        .master_xfer    = pcf_xfer,
        .functionality  = pcf_func,
 };
@@ -476,8 +474,6 @@ int i2c_pcf_add_bus(struct i2c_adapter *adap)
        DEB2(dev_dbg(&adap->dev, "hw routines registered.\n"));
 
        /* register new adapter to i2c module... */
-
-       adap->id |= pcf_algo.id;
        adap->algo = &pcf_algo;
 
        adap->timeout = 100;            /* default values, should       */
index 422721b241e5a0914f5383502035eb3dffc1f165..932c4fa86c7374eb9cf667ab14a8d20cc94adcbf 100644 (file)
@@ -149,7 +149,7 @@ static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
                        err = i2c_write(adap, p->buf, p->len);
        }
 
-       return err;
+       return (err < 0) ? err : i;
 }
 
 static u32 sgi_func(struct i2c_adapter *adap)
@@ -158,8 +158,6 @@ static u32 sgi_func(struct i2c_adapter *adap)
 }
 
 static struct i2c_algorithm sgi_algo = {
-       .name           = "SGI algorithm",
-       .id             = I2C_ALGO_SGI,
        .master_xfer    = sgi_xfer,
        .functionality  = sgi_func,
 };
@@ -169,7 +167,6 @@ static struct i2c_algorithm sgi_algo = {
  */
 int i2c_sgi_add_bus(struct i2c_adapter *adap)
 {
-       adap->id |= sgi_algo.id;
        adap->algo = &sgi_algo;
 
        return i2c_add_adapter(adap);
index f2785499237bf10135f571c0ebfddb9b9e4e5474..8ed5ad12552fed1ccf1f6ee7669c54afd652cf83 100644 (file)
@@ -135,8 +135,6 @@ static u32 bit_func(struct i2c_adapter *adap)
 /* -----exported algorithm data: ------------------------------------- */
 
 static struct i2c_algorithm i2c_sibyte_algo = {
-       .name           = "SiByte algorithm",
-       .id             = I2C_ALGO_SIBYTE,
        .smbus_xfer     = smbus_xfer,
        .algo_control   = algo_control, /* ioctl */
        .functionality  = bit_func,
@@ -151,8 +149,6 @@ int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
        struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
 
        /* register new adapter to i2c module... */
-
-       i2c_adap->id |= i2c_sibyte_algo.id;
        i2c_adap->algo = &i2c_sibyte_algo;
         
         /* Set the frequency to 100 kHz */
index 916ba5e40a96dd9810a0e4014cefb46541054475..6e9da1372225b73ab74c304824be223c5f078592 100644 (file)
@@ -182,14 +182,8 @@ config I2C_IOP3XX
          will be called i2c-iop3xx.
 
 config I2C_ISA
-       tristate "ISA Bus support"
+       tristate
        depends on I2C
-       help
-         If you say yes to this option, support will be included for i2c
-         interfaces that are on the ISA bus.
-
-         This driver can also be built as a module.  If so, the module
-         will be called i2c-isa.
 
 config I2C_ITE
        tristate "ITE I2C Adapter"
index f634a0780cf04b400a24ffb134967394b91c5b47..f021acd2674e9cfe6377a3225520418363a51fc9 100644 (file)
@@ -472,8 +472,6 @@ static u32 ali1535_func(struct i2c_adapter *adapter)
 }
 
 static struct i2c_algorithm smbus_algorithm = {
-       .name           = "Non-i2c SMBus adapter",
-       .id             = I2C_ALGO_SMBUS,
        .smbus_xfer     = ali1535_access,
        .functionality  = ali1535_func,
 };
index fdd881aee618172df04f70977ee4cb4a57e7d58c..86947504aea1e041f64677052882a552bae14d7a 100644 (file)
@@ -366,8 +366,6 @@ static void ali1563_shutdown(struct pci_dev *dev)
 }
 
 static struct i2c_algorithm ali1563_algorithm = {
-       .name           = "Non-i2c SMBus adapter",
-       .id             = I2C_ALGO_SMBUS,
        .smbus_xfer     = ali1563_access,
        .functionality  = ali1563_func,
 };
index 0f781a1a3323bc3c49c000ef1820ba7773d601ca..b3f50bff39a06c79f00e5ce59ddc0eea229008e3 100644 (file)
@@ -462,8 +462,6 @@ static u32 ali15x3_func(struct i2c_adapter *adapter)
 }
 
 static struct i2c_algorithm smbus_algorithm = {
-       .name           = "Non-I2C SMBus adapter",
-       .id             = I2C_ALGO_SMBUS,
        .smbus_xfer     = ali15x3_access,
        .functionality  = ali15x3_func,
 };
index 6347ebc6fb53522c1a423b5b6b21cb3589c55524..6ad0603384b8a34c8577c442185cece17c70d763 100644 (file)
@@ -295,8 +295,6 @@ static u32 amd756_func(struct i2c_adapter *adapter)
 }
 
 static struct i2c_algorithm smbus_algorithm = {
-       .name           = "Non-I2C SMBus adapter",
-       .id             = I2C_ALGO_SMBUS,
        .smbus_xfer     = amd756_access,
        .functionality  = amd756_func,
 };
index d6644481d2a097230d508e02fcd57248d84fb927..45ea24ba14d5b2d537502a6d3e43a4065f96902a 100644 (file)
@@ -323,8 +323,6 @@ static u32 amd8111_func(struct i2c_adapter *adapter)
 }
 
 static struct i2c_algorithm smbus_algorithm = {
-       .name = "Non-I2C SMBus 2.0 adapter",
-       .id = I2C_ALGO_SMBUS,
        .smbus_xfer = amd8111_access,
        .functionality = amd8111_func,
 };
index a7ff112e49bf28b5c0aed2ae46a353a9f56bf0bf..d06edce03bf40dd83604708018d4ce5165cd852f 100644 (file)
@@ -283,8 +283,6 @@ au1550_func(struct i2c_adapter *adap)
 }
 
 static struct i2c_algorithm au1550_algo = {
-       .name           = "Au1550 algorithm",
-       .id             = I2C_ALGO_AU1550,
        .master_xfer    = au1550_xfer,
        .functionality  = au1550_func,
 };
index 1ab41313ce5186d72f3a7398295dee8524576b0a..709beab76609eb43bdd4deb1b2a96db195d23aa0 100644 (file)
@@ -535,8 +535,6 @@ static u32 i801_func(struct i2c_adapter *adapter)
 }
 
 static struct i2c_algorithm smbus_algorithm = {
-       .name           = "Non-I2C SMBus adapter",
-       .id             = I2C_ALGO_SMBUS,
        .smbus_xfer     = i801_access,
        .functionality  = i801_func,
 };
index 93ca36dc777e3cd474a798ecbaaf5081aa760e5d..a3ed9590f028b17796e984816e0003ae3dca8270 100644 (file)
@@ -627,8 +627,6 @@ static u32 iic_func(struct i2c_adapter *adap)
 }
 
 static struct i2c_algorithm iic_algo = {
-       .name           = "IBM IIC algorithm",
-       .id             = I2C_ALGO_OCP,
        .master_xfer    = iic_xfer,
        .functionality  = iic_func
 };
@@ -727,7 +725,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
        adap = &dev->adap;
        strcpy(adap->name, "IBM IIC");
        i2c_set_adapdata(adap, dev);
-       adap->id = I2C_HW_OCP | iic_algo.id;
+       adap->id = I2C_HW_OCP;
        adap->algo = &iic_algo;
        adap->client_register = NULL;
        adap->client_unregister = NULL;
index 6b682e903f09c6735abaedf7f75508b9177c3cc0..7bd9102db701cd205eb0c347eba78deb971e99d8 100644 (file)
@@ -399,8 +399,6 @@ iop3xx_i2c_func(struct i2c_adapter *adap)
 }
 
 static struct i2c_algorithm iop3xx_i2c_algo = {
-       .name           = "IOP3xx I2C algorithm",
-       .id             = I2C_ALGO_IOP3XX,
        .master_xfer    = iop3xx_i2c_master_xfer,
        .algo_control   = iop3xx_i2c_algo_control,
        .functionality  = iop3xx_i2c_func,
index 00e7f7157b75d98f46ef085f9d311517a546a726..bdc6806dafaece2b13752d55ded93cdd7bc7c525 100644 (file)
@@ -1,6 +1,8 @@
 /*
-    i2c-isa.c - Part of lm_sensors, Linux kernel modules for hardware
-            monitoring
+    i2c-isa.c - an i2c-core-like thing for ISA hardware monitoring chips
+    Copyright (C) 2005  Jean Delvare <khali@linux-fr.org>
+
+    Based on the i2c-isa pseudo-adapter from the lm_sensors project
     Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> 
 
     This program is free software; you can redistribute it and/or modify
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-/* This implements an i2c algorithm/adapter for ISA bus. Not that this is
-   on first sight very useful; almost no functionality is preserved.
-   Except that it makes writing drivers for chips which can be on both
-   the SMBus and the ISA bus very much easier. See lm78.c for an example
-   of this. */
+/* This implements an i2c-core-like thing for ISA hardware monitoring
+   chips. Such chips are linked to the i2c subsystem for historical
+   reasons (because the early ISA hardware monitoring chips such as the
+   LM78 had both an I2C and an ISA interface). They used to be
+   registered with the main i2c-core, but as a first step in the
+   direction of a clean separation between I2C and ISA chip drivers,
+   we now have this separate core for ISA ones. It is significantly
+   more simple than the real one, of course, because we don't have to
+   handle multiple busses: there is only one (fake) ISA adapter.
+   It is worth noting that we still rely on i2c-core for some things
+   at the moment - but hopefully this won't last. */
 
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/i2c.h>
+#include <linux/i2c-isa.h>
 
 static u32 isa_func(struct i2c_adapter *adapter);
 
 /* This is the actual algorithm we define */
 static struct i2c_algorithm isa_algorithm = {
-       .name           = "ISA bus algorithm",
-       .id             = I2C_ALGO_ISA,
        .functionality  = isa_func,
 };
 
 /* There can only be one... */
 static struct i2c_adapter isa_adapter = {
        .owner          = THIS_MODULE,
+       .id             = I2C_HW_ISA,
        .class          = I2C_CLASS_HWMON,
        .algo           = &isa_algorithm,
        .name           = "ISA main adapter",
@@ -53,17 +61,146 @@ static u32 isa_func(struct i2c_adapter *adapter)
        return 0;
 }
 
+
+/* Copied from i2c-core */
+static ssize_t show_adapter_name(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
+       return sprintf(buf, "%s\n", adap->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
+
+static int i2c_isa_device_probe(struct device *dev)
+{
+       return -ENODEV;
+}
+
+static int i2c_isa_device_remove(struct device *dev)
+{
+       return 0;
+}
+
+
+/* We implement an interface which resembles i2c_{add,del}_driver,
+   but for i2c-isa drivers. We don't have to remember and handle lists
+   of drivers and adapters so this is much more simple, of course. */
+
+int i2c_isa_add_driver(struct i2c_driver *driver)
+{
+       int res;
+
+       /* Add the driver to the list of i2c drivers in the driver core */
+       driver->driver.name = driver->name;
+       driver->driver.bus = &i2c_bus_type;
+       driver->driver.probe = i2c_isa_device_probe;
+       driver->driver.remove = i2c_isa_device_remove;
+       res = driver_register(&driver->driver);
+       if (res)
+               return res;
+       dev_dbg(&isa_adapter.dev, "Driver %s registered\n", driver->name);
+
+       /* Now look for clients */
+       driver->attach_adapter(&isa_adapter);
+
+       return 0;
+}
+
+int i2c_isa_del_driver(struct i2c_driver *driver)
+{
+       struct list_head *item, *_n;
+       struct i2c_client *client;
+       int res;
+
+       /* Detach all clients belonging to this one driver */
+       list_for_each_safe(item, _n, &isa_adapter.clients) {
+               client = list_entry(item, struct i2c_client, list);
+               if (client->driver != driver)
+                       continue;
+               dev_dbg(&isa_adapter.dev, "Detaching client %s at 0x%x\n",
+                       client->name, client->addr);
+               if ((res = driver->detach_client(client))) {
+                       dev_err(&isa_adapter.dev, "Failed, driver "
+                               "%s not unregistered!\n",
+                               driver->name);
+                       return res;
+               }
+       }
+
+       /* Get the driver off the core list */
+       driver_unregister(&driver->driver);
+       dev_dbg(&isa_adapter.dev, "Driver %s unregistered\n", driver->name);
+
+       return 0;
+}
+
+
 static int __init i2c_isa_init(void)
 {
-       return i2c_add_adapter(&isa_adapter);
+       init_MUTEX(&isa_adapter.clist_lock);
+       INIT_LIST_HEAD(&isa_adapter.clients);
+
+       isa_adapter.nr = ANY_I2C_ISA_BUS;
+       isa_adapter.dev.parent = &platform_bus;
+       sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr);
+       isa_adapter.dev.driver = &i2c_adapter_driver;
+       isa_adapter.dev.release = &i2c_adapter_dev_release;
+       device_register(&isa_adapter.dev);
+       device_create_file(&isa_adapter.dev, &dev_attr_name);
+
+       /* Add this adapter to the i2c_adapter class */
+       memset(&isa_adapter.class_dev, 0x00, sizeof(struct class_device));
+       isa_adapter.class_dev.dev = &isa_adapter.dev;
+       isa_adapter.class_dev.class = &i2c_adapter_class;
+       strlcpy(isa_adapter.class_dev.class_id, isa_adapter.dev.bus_id,
+               BUS_ID_SIZE);
+       class_device_register(&isa_adapter.class_dev);
+
+       dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name);
+
+       return 0;
 }
 
 static void __exit i2c_isa_exit(void)
 {
-       i2c_del_adapter(&isa_adapter);
+#ifdef DEBUG
+       struct list_head  *item, *_n;
+       struct i2c_client *client = NULL;
+#endif
+
+       /* There should be no more active client */
+#ifdef DEBUG
+       dev_dbg(&isa_adapter.dev, "Looking for clients\n");
+       list_for_each_safe(item, _n, &isa_adapter.clients) {
+               client = list_entry(item, struct i2c_client, list);
+               dev_err(&isa_adapter.dev, "Driver %s still has an active "
+                       "ISA client at 0x%x\n", client->driver->name,
+                       client->addr);
+       }
+       if (client != NULL)
+               return;
+#endif
+
+       /* Clean up the sysfs representation */
+       dev_dbg(&isa_adapter.dev, "Unregistering from sysfs\n");
+       init_completion(&isa_adapter.dev_released);
+       init_completion(&isa_adapter.class_dev_released);
+       class_device_unregister(&isa_adapter.class_dev);
+       device_remove_file(&isa_adapter.dev, &dev_attr_name);
+       device_unregister(&isa_adapter.dev);
+
+       /* Wait for sysfs to drop all references */
+       dev_dbg(&isa_adapter.dev, "Waiting for sysfs completion\n");
+       wait_for_completion(&isa_adapter.dev_released);
+       wait_for_completion(&isa_adapter.class_dev_released);
+
+       dev_dbg(&isa_adapter.dev, "%s unregistered\n", isa_adapter.name);
 }
 
-MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
+EXPORT_SYMBOL(i2c_isa_add_driver);
+EXPORT_SYMBOL(i2c_isa_del_driver);
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
 MODULE_DESCRIPTION("ISA bus access through i2c");
 MODULE_LICENSE("GPL");
 
index 94ae808314f75905bf3dfb00d8ac075fce1c08f9..37b49c2daf5f824a5057ff713effce45149f7116 100644 (file)
@@ -87,12 +87,9 @@ static const char *__kw_state_names[] = {
 };
 #endif /* DEBUG */
 
-static int probe;
-
 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
 MODULE_DESCRIPTION("I2C driver for Apple's Keywest");
 MODULE_LICENSE("GPL");
-module_param(probe, bool, 0);
 
 #ifdef POLLED_MODE
 /* Don't schedule, the g5 fan controller is too
@@ -498,8 +495,6 @@ keywest_func(struct i2c_adapter * adapter)
 
 /* For now, we only handle combined mode (smbus) */
 static struct i2c_algorithm keywest_algorithm = {
-       .name           = "Keywest i2c",
-       .id             = I2C_ALGO_SMBUS,
        .smbus_xfer     = keywest_smbus_xfer,
        .master_xfer    = keywest_xfer,
        .functionality  = keywest_func,
@@ -621,7 +616,6 @@ create_iface(struct device_node *np, struct device *dev)
                sprintf(chan->adapter.name, "%s %d", np->parent->name, i);
                chan->iface = iface;
                chan->chan_no = i;
-               chan->adapter.id = I2C_ALGO_SMBUS;
                chan->adapter.algo = &keywest_algorithm;
                chan->adapter.algo_data = NULL;
                chan->adapter.client_register = NULL;
@@ -635,15 +629,6 @@ create_iface(struct device_node *np, struct device *dev)
                                chan->adapter.name);
                        i2c_set_adapdata(&chan->adapter, NULL);
                }
-               if (probe) {
-                       printk("Probe: ");
-                       for (addr = 0x00; addr <= 0x7f; addr++) {
-                               if (i2c_smbus_xfer(&chan->adapter,addr,
-                                   0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
-                                       printk("%02x ", addr);
-                       }
-                       printk("\n");
-               }
        }
 
        printk(KERN_INFO "Found KeyWest i2c on \"%s\", %d channel%s, stepping: %d bits\n",
index 9ad3e9262e8ae059621c43413cb48c95ccd9aec7..f065583ddcf104dea3b14ef5e3015234c985c72f 100644 (file)
@@ -272,8 +272,6 @@ static u32 mpc_functionality(struct i2c_adapter *adap)
 }
 
 static struct i2c_algorithm mpc_algo = {
-       .name = "MPC algorithm",
-       .id = I2C_ALGO_MPC107,
        .master_xfer = mpc_xfer,
        .functionality = mpc_functionality,
 };
@@ -281,7 +279,7 @@ static struct i2c_algorithm mpc_algo = {
 static struct i2c_adapter mpc_ops = {
        .owner = THIS_MODULE,
        .name = "MPC adapter",
-       .id = I2C_ALGO_MPC107 | I2C_HW_MPC107,
+       .id = I2C_HW_MPC107,
        .algo = &mpc_algo,
        .class = I2C_CLASS_HWMON,
        .timeout = 1,
index 5b852782d2f5956cc4984a617facd1da2e64f592..99abca45fece4d9ea24603529e4ff00a5d9ad271 100644 (file)
@@ -423,18 +423,16 @@ static int
 mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 {
        struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap);
-       int     i, rc = 0;
+       int     i, rc;
 
        for (i=0; i<num; i++)
-               if ((rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i])) != 0)
-                       break;
+               if ((rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i])) < 0)
+                       return rc;
 
-       return rc;
+       return num;
 }
 
 static struct i2c_algorithm mv64xxx_i2c_algo = {
-       .name = MV64XXX_I2C_CTLR_NAME " algorithm",
-       .id = I2C_ALGO_MV64XXX,
        .master_xfer = mv64xxx_i2c_xfer,
        .functionality = mv64xxx_i2c_functionality,
 };
@@ -523,7 +521,7 @@ mv64xxx_i2c_probe(struct device *dev)
        drv_data->freq_m = pdata->freq_m;
        drv_data->freq_n = pdata->freq_n;
        drv_data->irq = platform_get_irq(pd, 0);
-       drv_data->adapter.id = I2C_ALGO_MV64XXX | I2C_HW_MV64XXX;
+       drv_data->adapter.id = I2C_HW_MV64XXX;
        drv_data->adapter.algo = &mv64xxx_i2c_algo;
        drv_data->adapter.owner = THIS_MODULE;
        drv_data->adapter.class = I2C_CLASS_HWMON;
index 74eb89aa935084819903ff54d79722d5c368574a..e0b7a913431e0c1c7664f474a904e8db44a57c92 100644 (file)
@@ -110,8 +110,6 @@ static u32 nforce2_func(struct i2c_adapter *adapter);
 
 
 static struct i2c_algorithm smbus_algorithm = {
-       .name = "Non-I2C SMBus adapter",
-       .id = I2C_ALGO_SMBUS,
        .smbus_xfer = nforce2_access,
        .functionality = nforce2_func,
 };
@@ -131,7 +129,6 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
        struct nforce2_smbus *smbus = adap->algo_data;
        unsigned char protocol, pec, temp;
        unsigned char len = 0; /* to keep the compiler quiet */
-       int timeout = 0;
        int i;
 
        protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ :
@@ -191,29 +188,10 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
                case I2C_SMBUS_PROC_CALL:
                        dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
                        return -1;
-                       /*
-                       outb_p(command, NVIDIA_SMB_CMD);
-                       outb_p(data->word, NVIDIA_SMB_DATA);
-                       outb_p(data->word >> 8, NVIDIA_SMB_DATA + 1);
-                       protocol = NVIDIA_SMB_PRTCL_PROC_CALL | pec;
-                       read_write = I2C_SMBUS_READ;
-                       break;
-                        */
 
                case I2C_SMBUS_BLOCK_PROC_CALL:
                        dev_err(&adap->dev, "I2C_SMBUS_BLOCK_PROC_CALL not supported!\n");
                        return -1;
-                       /*
-                       protocol |= pec;
-                       len = min_t(u8, data->block[0], 31);
-                       outb_p(command, NVIDIA_SMB_CMD);
-                       outb_p(len, NVIDIA_SMB_BCNT);
-                       for (i = 0; i < len; i++)
-                               outb_p(data->block[i + 1], NVIDIA_SMB_DATA + i);
-                       protocol = NVIDIA_SMB_PRTCL_BLOCK_PROC_CALL | pec;
-                       read_write = I2C_SMBUS_READ;
-                       break;
-                       */
 
                case I2C_SMBUS_WORD_DATA_PEC:
                case I2C_SMBUS_BLOCK_DATA_PEC:
@@ -232,12 +210,6 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
 
        temp = inb_p(NVIDIA_SMB_STS);
 
-#if 0
-       do {
-               i2c_do_pause(1);
-               temp = inb_p(NVIDIA_SMB_STS);
-       } while (((temp & NVIDIA_SMB_STS_DONE) == 0) && (timeout++ < MAX_TIMEOUT));
-#endif
        if (~temp & NVIDIA_SMB_STS_DONE) {
                udelay(500);
                temp = inb_p(NVIDIA_SMB_STS);
@@ -247,9 +219,10 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
                temp = inb_p(NVIDIA_SMB_STS);
        }
 
-       if ((timeout >= MAX_TIMEOUT) || (~temp & NVIDIA_SMB_STS_DONE)
-               || (temp & NVIDIA_SMB_STS_STATUS))
+       if ((~temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {
+               dev_dbg(&adap->dev, "SMBus Timeout! (0x%02x)\n", temp);
                return -1;
+       }
 
        if (read_write == I2C_SMBUS_WRITE)
                return 0;
index 6d34ee381ce19837a92a98b0cf47274dd92d7a16..6d48a4da7bed97e2d4ecabdbe8ee98e3f8f12244 100644 (file)
@@ -399,8 +399,6 @@ static u32 piix4_func(struct i2c_adapter *adapter)
 }
 
 static struct i2c_algorithm smbus_algorithm = {
-       .name           = "Non-I2C SMBus adapter",
-       .id             = I2C_ALGO_SMBUS,
        .smbus_xfer     = piix4_access,
        .functionality  = piix4_func,
 };
index a3b38257cc3d51e9f4d9ab826c03edd7173a4523..73a092fb0e7e955411bb2f559c0e92222980716b 100644 (file)
@@ -568,7 +568,6 @@ static u32 s3c24xx_i2c_func(struct i2c_adapter *adap)
 /* i2c bus registration info */
 
 static struct i2c_algorithm s3c24xx_i2c_algorithm = {
-       .name                   = "S3C2410-I2C-Algorithm",
        .master_xfer            = s3c24xx_i2c_xfer,
        .functionality          = s3c24xx_i2c_func,
 };
index bbd5e4e52f093cd7709d2c2d98d657ed9b598c1a..080318d6f54b313faa9458e6170499afaa8585c6 100644 (file)
@@ -357,8 +357,6 @@ static u32 sis5595_func(struct i2c_adapter *adapter)
 }
 
 static struct i2c_algorithm smbus_algorithm = {
-       .name           = "Non-I2C SMBus adapter",
-       .id             = I2C_ALGO_SMBUS,
        .smbus_xfer     = sis5595_access,
        .functionality  = sis5595_func,
 };
index f58455e7689e57da7aff99a086a4f6846153b329..86f0f448fa0b91a6ad3f2da9d6c29e5efe2dc70e 100644 (file)
@@ -448,8 +448,6 @@ exit:
 
 
 static struct i2c_algorithm smbus_algorithm = {
-       .name           = "Non-I2C SMBus adapter",
-       .id             = I2C_ALGO_SMBUS,
        .smbus_xfer     = sis630_access,
        .functionality  = sis630_func,
 };
index 6484792e23a1aacf9402ab41413ecb16987581e6..ead2ff3cf60e705eb9e0d36d0e8c67c139b2e5f9 100644 (file)
@@ -249,8 +249,6 @@ static u32 sis96x_func(struct i2c_adapter *adapter)
 }
 
 static struct i2c_algorithm smbus_algorithm = {
-       .name           = "Non-I2C SMBus adapter",
-       .id             = I2C_ALGO_SMBUS,
        .smbus_xfer     = sis96x_access,
        .functionality  = sis96x_func,
 };
index 00d94e886955eb9b4374e2d8bd07dcab1ba5d04b..73f481e93a36458c3040e391d3a16ac649d9affd 100644 (file)
@@ -109,8 +109,6 @@ static u32 stub_func(struct i2c_adapter *adapter)
 }
 
 static struct i2c_algorithm smbus_algorithm = {
-       .name           = "Non-I2C SMBus adapter",
-       .id             = I2C_ALGO_SMBUS,
        .functionality  = stub_func,
        .smbus_xfer     = stub_xfer,
 };
index 6b5008005c6fc1e276e9bf766d5eeb9815a997bf..99d209e0485adba2e08d23117e404c4656a46c99 100644 (file)
@@ -286,8 +286,6 @@ static u32 vt596_func(struct i2c_adapter *adapter)
 }
 
 static struct i2c_algorithm smbus_algorithm = {
-       .name           = "Non-I2C SMBus adapter",
-       .id             = I2C_ALGO_SMBUS,
        .smbus_xfer     = vt596_access,
        .functionality  = vt596_func,
 };
index a18bdd9aa7ba29b65fa6d699b74ea6595cfff848..a1d580e05361255d8096ea01fa72399f2d9ad94b 100644 (file)
@@ -395,8 +395,6 @@ static u32 scx200_acb_func(struct i2c_adapter *adapter)
 
 /* For now, we only handle combined mode (smbus) */
 static struct i2c_algorithm scx200_acb_algorithm = {
-       .name           = "NatSemi SCx200 ACCESS.bus",
-       .id             = I2C_ALGO_SMBUS,
        .smbus_xfer     = scx200_acb_smbus_xfer,
        .functionality  = scx200_acb_func,
 };
@@ -456,7 +454,7 @@ static int  __init scx200_acb_create(int base, int index)
        i2c_set_adapdata(adapter, iface);
        snprintf(adapter->name, I2C_NAME_SIZE, "SCx200 ACB%d", index);
        adapter->owner = THIS_MODULE;
-       adapter->id = I2C_ALGO_SMBUS;
+       adapter->id = I2C_HW_SMBUS_SCX200;
        adapter->algo = &scx200_acb_algorithm;
        adapter->class = I2C_CLASS_HWMON;
 
index 43f70dbfc03f6f8865580816ab311fa8ac8a4854..6bd44a44cd28bedc1b3b3157f88e44c99645b5d6 100644 (file)
@@ -2,17 +2,12 @@
 # Miscellaneous I2C chip drivers configuration
 #
 
-config I2C_SENSOR
-       tristate
-       default n
-
 menu "Miscellaneous I2C Chip support"
        depends on I2C
 
 config SENSORS_DS1337
        tristate "Dallas Semiconductor DS1337 and DS1339 Real Time Clock"
        depends on I2C && EXPERIMENTAL
-       select I2C_SENSOR
        help
          If you say yes here you get support for Dallas Semiconductor
          DS1337 and DS1339 real-time clock chips.
@@ -23,7 +18,6 @@ config SENSORS_DS1337
 config SENSORS_DS1374
        tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock"
        depends on I2C && EXPERIMENTAL
-       select I2C_SENSOR
        help
          If you say yes here you get support for Dallas Semiconductor
          DS1374 real-time clock chips.
@@ -34,7 +28,6 @@ config SENSORS_DS1374
 config SENSORS_EEPROM
        tristate "EEPROM reader"
        depends on I2C && EXPERIMENTAL
-       select I2C_SENSOR
        help
          If you say yes here you get read-only access to the EEPROM data
          available on modern memory DIMMs and Sony Vaio laptops.  Such
@@ -46,7 +39,6 @@ config SENSORS_EEPROM
 config SENSORS_PCF8574
        tristate "Philips PCF8574 and PCF8574A"
        depends on I2C && EXPERIMENTAL
-       select I2C_SENSOR
        help
          If you say yes here you get support for Philips PCF8574 and 
          PCF8574A chips.
@@ -67,7 +59,6 @@ config SENSORS_PCA9539
 config SENSORS_PCF8591
        tristate "Philips PCF8591"
        depends on I2C && EXPERIMENTAL
-       select I2C_SENSOR
        help
          If you say yes here you get support for Philips PCF8591 chips.
 
@@ -77,7 +68,6 @@ config SENSORS_PCF8591
 config SENSORS_RTC8564
        tristate "Epson 8564 RTC chip"
        depends on I2C && EXPERIMENTAL
-       select I2C_SENSOR
        help
          If you say yes here you get support for the Epson 8564 RTC chip.
 
index 82cf959989fd3f3126ea83255a57e2e8c659fb1d..9d3175c03395681d1fe3b29a91bccb3566f64869 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
 #include <linux/string.h>
 #include <linux/rtc.h>         /* get the user-level API */
 #include <linux/bcd.h>
@@ -39,9 +38,8 @@
  * Functions declaration
  */
 static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
-SENSORS_INSMOD_1(ds1337);
+I2C_CLIENT_INSMOD_1(ds1337);
 
 static int ds1337_attach_adapter(struct i2c_adapter *adapter);
 static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind);
@@ -227,7 +225,7 @@ int ds1337_do_command(int bus, int cmd, void *arg)
 
 static int ds1337_attach_adapter(struct i2c_adapter *adapter)
 {
-       return i2c_detect(adapter, &addr_data, ds1337_detect);
+       return i2c_probe(adapter, &addr_data, ds1337_detect);
 }
 
 /*
@@ -354,11 +352,8 @@ static int ds1337_detach_client(struct i2c_client *client)
        int err;
        struct ds1337_data *data = i2c_get_clientdata(client);
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                       "client not detached.\n");
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
        list_del(&data->list);
        kfree(data);
index a445736d8838c46df70ab7c23d3a396d33915145..0936327a946db0a8c5ca673f4a42ef8eae3dc598 100644 (file)
@@ -53,7 +53,6 @@ static struct i2c_client_address_data addr_data = {
        .normal_i2c = normal_addr,
        .probe = ignore,
        .ignore = ignore,
-       .force = ignore,
 };
 
 static ulong ds1374_read_rtc(void)
@@ -166,7 +165,7 @@ static void ds1374_set_tlet(ulong arg)
                         "can't confirm time set from rtc chip\n");
 }
 
-ulong new_time;
+static ulong new_time;
 
 DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet, (ulong) & new_time);
 
index a2da31b0dd7bda7260f77a93478b4d5d688af40c..d58403a479086d9b8660f85b0fcf5e4bbacbffe7 100644 (file)
 #include <linux/sched.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,
                                        0x55, 0x56, 0x57, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
-SENSORS_INSMOD_1(eeprom);
+I2C_CLIENT_INSMOD_1(eeprom);
 
 
 /* Size of EEPROM in bytes */
@@ -153,21 +151,16 @@ static struct bin_attribute eeprom_attr = {
 
 static int eeprom_attach_adapter(struct i2c_adapter *adapter)
 {
-       return i2c_detect(adapter, &addr_data, eeprom_detect);
+       return i2c_probe(adapter, &addr_data, eeprom_detect);
 }
 
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
 int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
 {
        struct i2c_client *new_client;
        struct eeprom_data *data;
        int err = 0;
 
-       /* prevent 24RF08 corruption */
-       if (kind < 0)
-               i2c_smbus_xfer(adapter, address, 0, 0, 0,
-                              I2C_SMBUS_QUICK, NULL);
-
        /* There are three ways we can read the EEPROM data:
           (1) I2C block reads (faster, but unsupported by most adapters)
           (2) Consecutive byte reads (100% overhead)
@@ -231,10 +224,8 @@ static int eeprom_detach_client(struct i2c_client *client)
        int err;
 
        err = i2c_detach_client(client);
-       if (err) {
-               dev_err(&client->dev, "Client deregistration failed, client not detached.\n");
+       if (err)
                return err;
-       }
 
        kfree(i2c_get_clientdata(client));
 
index 354a262956725ebe8812908bf3a5341e593bc171..8ee56d4b38910486b42746c953d9f4e6cff5135a 100644 (file)
@@ -1489,7 +1489,7 @@ static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
        if (the_transceiver)
                return 0;
 
-       isp = kcalloc(1, sizeof *isp, GFP_KERNEL);
+       isp = kzalloc(sizeof *isp, GFP_KERNEL);
        if (!isp)
                return 0;
 
index 778d7e12859dd0de54ed2b877c6d0ffcee72dfee..3f14528a52a9248cdc1d44a0968fe4d54956d547 100644 (file)
@@ -42,7 +42,6 @@ static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_addr,
        .probe                  = ignore,
        .ignore                 = ignore,
-       .force                  = ignore,
 };
 
 ulong
@@ -145,7 +144,7 @@ m41t00_set_tlet(ulong arg)
        return;
 }
 
-ulong  new_time;
+static ulong   new_time;
 
 DECLARE_TASKLET_DISABLED(m41t00_tasklet, m41t00_set_tlet, (ulong)&new_time);
 
index 0230375f72e551bb227fda676eecadff0e5def79..9e1aeb69abf9fa1009e281e7a88f22e9aef21089 100644 (file)
@@ -5,97 +5,60 @@
 
     Based on i2c/chips/eeprom.c
 
-    The MAX6875 has two EEPROM sections: config and user.
-    At reset, the config EEPROM is read into the registers.
+    The MAX6875 has a bank of registers and two banks of EEPROM.
+    Address ranges are defined as follows:
+     * 0x0000 - 0x0046 = configuration registers
+     * 0x8000 - 0x8046 = configuration EEPROM
+     * 0x8100 - 0x82FF = user EEPROM
 
-    This driver make 3 binary files available in sysfs:
-      reg_config    - direct access to the registers
-      eeprom_config - acesses configuration eeprom space
-      eeprom_user   - free for application use
+    This driver makes the user EEPROM available for read.
 
-    In our application, we put device serial & model numbers in user eeprom.
+    The registers & config EEPROM should be accessed via i2c-dev.
 
-    Notes:
-      1) The datasheet says that register 0x44 / EEPROM 0x8044 should NOT
-         be overwritten, so the driver explicitly prevents that.
-      2) It's a good idea to keep the config (0x45) locked in config EEPROM.
-         You can temporarily enable config writes by changing register 0x45.
+    The MAX6875 ignores the lowest address bit, so each chip responds to
+    two addresses - 0x50/0x51 and 0x52/0x53.
+
+    Note that the MAX6875 uses i2c_smbus_write_byte_data() to set the read
+    address, so this driver is destructive if loaded for the wrong EEPROM chip.
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; version 2 of the License.
 */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <asm/semaphore.h>
 
-/* Addresses to scan */
-/* No address scanned by default, as this could corrupt standard EEPROMS. */
+/* Do not scan - the MAX6875 access method will write to some EEPROM chips */
 static unsigned short normal_i2c[] = {I2C_CLIENT_END};
-static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END};
 
 /* Insmod parameters */
-SENSORS_INSMOD_1(max6875);
-
-/* this param will prevent 'accidental' writes to the eeprom */
-static int allow_write = 0;
-module_param(allow_write, int, 0);
-MODULE_PARM_DESC(allow_write,
-                "Enable write access:\n"
-                "*0: Read only\n"
-                " 1: Read/Write access");
+I2C_CLIENT_INSMOD_1(max6875);
 
 /* The MAX6875 can only read/write 16 bytes at a time */
 #define SLICE_SIZE                     16
 #define SLICE_BITS                     4
 
-/* CONFIG EEPROM is at addresses 0x8000 - 0x8045, registers are at 0 - 0x45 */
-#define CONFIG_EEPROM_BASE             0x8000
-#define CONFIG_EEPROM_SIZE             0x0046
-#define CONFIG_EEPROM_SLICES           5
-
 /* USER EEPROM is at addresses 0x8100 - 0x82FF */
 #define USER_EEPROM_BASE               0x8100
 #define USER_EEPROM_SIZE               0x0200
 #define USER_EEPROM_SLICES             32
 
 /* MAX6875 commands */
-#define MAX6875_CMD_BLOCK_WRITE                0x83
-#define MAX6875_CMD_BLOCK_READ         0x84
-#define MAX6875_CMD_REBOOT             0x88
-
-enum max6875_area_type {
-       max6875_register_config=0,
-       max6875_eeprom_config,
-       max6875_eeprom_user,
-       max6857_max
-};
-
-struct eeprom_block {
-       enum max6875_area_type  type;
-       u8                      slices;
-       u32                     size;
-       u32                     valid;
-       u32                     base;
-       unsigned long           *updated;
-       u8                      *data;
-};
+#define MAX6875_CMD_BLK_READ           0x84
 
 /* Each client has this additional data */
 struct max6875_data {
        struct i2c_client       client;
        struct semaphore        update_lock;
-       struct eeprom_block     blocks[max6857_max];
-       /* the above structs point into the arrays below */
-       u8 data[USER_EEPROM_SIZE + (CONFIG_EEPROM_SIZE*2)];
-       unsigned long last_updated[USER_EEPROM_SLICES + (CONFIG_EEPROM_SLICES*2)];
+
+       u32                     valid;
+       u8                      data[USER_EEPROM_SIZE];
+       unsigned long           last_updated[USER_EEPROM_SLICES];
 };
 
 static int max6875_attach_adapter(struct i2c_adapter *adapter);
@@ -111,337 +74,160 @@ static struct i2c_driver max6875_driver = {
        .detach_client  = max6875_detach_client,
 };
 
-static int max6875_update_slice(struct i2c_client *client,
-                               struct eeprom_block *blk,
-                               int slice)
+static void max6875_update_slice(struct i2c_client *client, int slice)
 {
        struct max6875_data *data = i2c_get_clientdata(client);
-       int i, j, addr, count;
-       u8 rdbuf[SLICE_SIZE];
-       int retval = 0;
+       int i, j, addr;
+       u8 *buf;
 
-       if (slice >= blk->slices)
-               return -1;
+       if (slice >= USER_EEPROM_SLICES)
+               return;
 
        down(&data->update_lock);
 
-       if (!(blk->valid & (1 << slice)) ||
-           (jiffies - blk->updated[slice] > 300 * HZ) ||
-           (jiffies < blk->updated[slice])) {
-               dev_dbg(&client->dev, "Starting eeprom update, slice %u, base %u\n",
-                       slice, blk->base);
+       buf = &data->data[slice << SLICE_BITS];
 
-               addr = blk->base + (slice << SLICE_BITS);
-               count = blk->size - (slice << SLICE_BITS);
-               if (count > SLICE_SIZE) {
-                       count = SLICE_SIZE;
-               }
+       if (!(data->valid & (1 << slice)) ||
+           time_after(jiffies, data->last_updated[slice])) {
 
-               /* Preset the read address */
-               if (addr < 0x100) {
-                       /* select the register */
-                       if (i2c_smbus_write_byte(client, addr & 0xFF)) {
-                               dev_dbg(&client->dev, "max6875 register select has failed!\n");
-                               retval = -1;
-                               goto exit;
-                       }
-               } else {
-                       /* select the eeprom */
-                       if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) {
-                               dev_dbg(&client->dev, "max6875 address set has failed!\n");
-                               retval = -1;
-                               goto exit;
-                       }
+               dev_dbg(&client->dev, "Starting update of slice %u\n", slice);
+
+               data->valid &= ~(1 << slice);
+
+               addr = USER_EEPROM_BASE + (slice << SLICE_BITS);
+
+               /* select the eeprom address */
+               if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) {
+                       dev_err(&client->dev, "address set failed\n");
+                       goto exit_up;
                }
 
-               if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
-                       if (i2c_smbus_read_i2c_block_data(client, MAX6875_CMD_BLOCK_READ,
-                                                         rdbuf) != SLICE_SIZE)
-                       {
-                               retval = -1;
-                               goto exit;
+               if (i2c_check_functionality(client->adapter,
+                                           I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+                       if (i2c_smbus_read_i2c_block_data(client,
+                                                         MAX6875_CMD_BLK_READ,
+                                                         buf) != SLICE_SIZE) {
+                               goto exit_up;
                        }
-
-                       memcpy(&blk->data[slice << SLICE_BITS], rdbuf, count);
                } else {
-                       for (i = 0; i < count; i++) {
+                       for (i = 0; i < SLICE_SIZE; i++) {
                                j = i2c_smbus_read_byte(client);
-                               if (j < 0)
-                               {
-                                       retval = -1;
-                                       goto exit;
+                               if (j < 0) {
+                                       goto exit_up;
                                }
-                               blk->data[(slice << SLICE_BITS) + i] = (u8) j;
+                               buf[i] = j;
                        }
                }
-               blk->updated[slice] = jiffies;
-               blk->valid |= (1 << slice);
+               data->last_updated[slice] = jiffies;
+               data->valid |= (1 << slice);
        }
-       exit:
+exit_up:
        up(&data->update_lock);
-       return retval;
 }
 
-static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off, size_t count,
-                           enum max6875_area_type area_type)
+static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off,
+                           size_t count)
 {
-       struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
+       struct i2c_client *client = kobj_to_i2c_client(kobj);
        struct max6875_data *data = i2c_get_clientdata(client);
-       struct eeprom_block *blk;
-       int slice;
-
-       blk = &data->blocks[area_type];
+       int slice, max_slice;
 
-       if (off > blk->size)
+       if (off > USER_EEPROM_SIZE)
                return 0;
-       if (off + count > blk->size)
-               count = blk->size - off;
 
-       /* Only refresh slices which contain requested bytes */
-       for (slice = (off >> SLICE_BITS); slice <= ((off + count - 1) >> SLICE_BITS); slice++)
-               max6875_update_slice(client, blk, slice);
+       if (off + count > USER_EEPROM_SIZE)
+               count = USER_EEPROM_SIZE - off;
 
-       memcpy(buf, &blk->data[off], count);
+       /* refresh slices which contain requested bytes */
+       max_slice = (off + count - 1) >> SLICE_BITS;
+       for (slice = (off >> SLICE_BITS); slice <= max_slice; slice++)
+               max6875_update_slice(client, slice);
 
-       return count;
-}
-
-static ssize_t max6875_user_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
-{
-       return max6875_read(kobj, buf, off, count, max6875_eeprom_user);
-}
-
-static ssize_t max6875_config_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
-{
-       return max6875_read(kobj, buf, off, count, max6875_eeprom_config);
-}
-
-static ssize_t max6875_cfgreg_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
-{
-       return max6875_read(kobj, buf, off, count, max6875_register_config);
-}
-
-
-static ssize_t max6875_write(struct kobject *kobj, char *buf, loff_t off, size_t count,
-                            enum max6875_area_type area_type)
-{
-       struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
-       struct max6875_data *data = i2c_get_clientdata(client);
-       struct eeprom_block *blk;
-       int slice, addr, retval;
-       ssize_t sent = 0;
-
-       blk = &data->blocks[area_type];
-
-       if (off > blk->size)
-               return 0;
-       if ((off + count) > blk->size)
-               count = blk->size - off;
-
-       if (down_interruptible(&data->update_lock))
-               return -EAGAIN;
-
-       /* writing to a register is done with i2c_smbus_write_byte_data() */
-       if (blk->type == max6875_register_config) {
-               for (sent = 0; sent < count; sent++) {
-                       addr = off + sent;
-                       if (addr == 0x44)
-                               continue;
-
-                       retval = i2c_smbus_write_byte_data(client, addr, buf[sent]);
-               }
-       } else {
-               int cmd, val;
-
-               /* We are writing to EEPROM */
-               for (sent = 0; sent < count; sent++) {
-                       addr = blk->base + off + sent;
-                       cmd = addr >> 8;
-                       val = (addr & 0xff) | (buf[sent] << 8); // reversed
-
-                       if (addr == 0x8044)
-                               continue;
-
-                       retval = i2c_smbus_write_word_data(client, cmd, val);
-
-                       if (retval) {
-                               goto error_exit;
-                       }
+       memcpy(buf, &data->data[off], count);
 
-                       /* A write takes up to 11 ms */
-                       msleep(11);
-               }
-       }
-
-       /* Invalidate the scratch buffer */
-       for (slice = (off >> SLICE_BITS); slice <= ((off + count - 1) >> SLICE_BITS); slice++)
-               blk->valid &= ~(1 << slice);
-
-       error_exit:
-       up(&data->update_lock);
-
-       return sent;
-}
-
-static ssize_t max6875_user_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
-{
-       return max6875_write(kobj, buf, off, count, max6875_eeprom_user);
-}
-
-static ssize_t max6875_config_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
-{
-       return max6875_write(kobj, buf, off, count, max6875_eeprom_config);
-}
-
-static ssize_t max6875_cfgreg_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
-{
-       return max6875_write(kobj, buf, off, count, max6875_register_config);
+       return count;
 }
 
 static struct bin_attribute user_eeprom_attr = {
        .attr = {
-               .name = "eeprom_user",
-               .mode = S_IRUGO | S_IWUSR | S_IWGRP,
-               .owner = THIS_MODULE,
-       },
-       .size  = USER_EEPROM_SIZE,
-       .read  = max6875_user_read,
-       .write = max6875_user_write,
-};
-
-static struct bin_attribute config_eeprom_attr = {
-       .attr = {
-               .name = "eeprom_config",
-               .mode = S_IRUGO | S_IWUSR,
-               .owner = THIS_MODULE,
-       },
-       .size  = CONFIG_EEPROM_SIZE,
-       .read  = max6875_config_read,
-       .write = max6875_config_write,
-};
-
-static struct bin_attribute config_register_attr = {
-       .attr = {
-               .name = "reg_config",
-               .mode = S_IRUGO | S_IWUSR,
+               .name = "eeprom",
+               .mode = S_IRUGO,
                .owner = THIS_MODULE,
        },
-       .size  = CONFIG_EEPROM_SIZE,
-       .read  = max6875_cfgreg_read,
-       .write = max6875_cfgreg_write,
+       .size = USER_EEPROM_SIZE,
+       .read = max6875_read,
 };
 
 static int max6875_attach_adapter(struct i2c_adapter *adapter)
 {
-       return i2c_detect(adapter, &addr_data, max6875_detect);
+       return i2c_probe(adapter, &addr_data, max6875_detect);
 }
 
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
 static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
 {
-       struct i2c_client *new_client;
+       struct i2c_client *real_client;
+       struct i2c_client *fake_client;
        struct max6875_data *data;
        int err = 0;
 
-       /* Prevent 24RF08 corruption (in case of user error) */
-       if (kind < 0)
-               i2c_smbus_xfer(adapter, address, 0, 0, 0,
-                              I2C_SMBUS_QUICK, NULL);
-
-       /* There are three ways we can read the EEPROM data:
-          (1) I2C block reads (faster, but unsupported by most adapters)
-          (2) Consecutive byte reads (100% overhead)
-          (3) Regular byte data reads (200% overhead)
-          The third method is not implemented by this driver because all
-          known adapters support at least the second. */
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA |
-                                    I2C_FUNC_SMBUS_BYTE |
-                                    I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
-               goto exit;
-
-       /* OK. For now, we presume we have a valid client. We now create the
-          client structure, even though we cannot fill it completely yet.
-          But it allows us to access eeprom_{read,write}_value. */
-       if (!(data = kmalloc(sizeof(struct max6875_data), GFP_KERNEL))) {
-               err = -ENOMEM;
-               goto exit;
-       }
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA
+                                    | I2C_FUNC_SMBUS_READ_BYTE))
+               return 0;
+
+       /* Only check even addresses */
+       if (address & 1)
+               return 0;
+
+       if (!(data = kmalloc(sizeof(struct max6875_data), GFP_KERNEL)))
+               return -ENOMEM;
        memset(data, 0, sizeof(struct max6875_data));
 
-       new_client = &data->client;
-       i2c_set_clientdata(new_client, data);
-       new_client->addr = address;
-       new_client->adapter = adapter;
-       new_client->driver = &max6875_driver;
-       new_client->flags = 0;
-
-       /* Setup the user section */
-       data->blocks[max6875_eeprom_user].type    = max6875_eeprom_user;
-       data->blocks[max6875_eeprom_user].slices  = USER_EEPROM_SLICES;
-       data->blocks[max6875_eeprom_user].size    = USER_EEPROM_SIZE;
-       data->blocks[max6875_eeprom_user].base    = USER_EEPROM_BASE;
-       data->blocks[max6875_eeprom_user].data    = data->data;
-       data->blocks[max6875_eeprom_user].updated = data->last_updated;
-
-       /* Setup the config section */
-       data->blocks[max6875_eeprom_config].type    = max6875_eeprom_config;
-       data->blocks[max6875_eeprom_config].slices  = CONFIG_EEPROM_SLICES;
-       data->blocks[max6875_eeprom_config].size    = CONFIG_EEPROM_SIZE;
-       data->blocks[max6875_eeprom_config].base    = CONFIG_EEPROM_BASE;
-       data->blocks[max6875_eeprom_config].data    = &data->data[USER_EEPROM_SIZE];
-       data->blocks[max6875_eeprom_config].updated = &data->last_updated[USER_EEPROM_SLICES];
-
-       /* Setup the register section */
-       data->blocks[max6875_register_config].type    = max6875_register_config;
-       data->blocks[max6875_register_config].slices  = CONFIG_EEPROM_SLICES;
-       data->blocks[max6875_register_config].size    = CONFIG_EEPROM_SIZE;
-       data->blocks[max6875_register_config].base    = 0;
-       data->blocks[max6875_register_config].data    = &data->data[USER_EEPROM_SIZE+CONFIG_EEPROM_SIZE];
-       data->blocks[max6875_register_config].updated = &data->last_updated[USER_EEPROM_SLICES+CONFIG_EEPROM_SLICES];
-
-       /* Init the data */
-       memset(data->data, 0xff, sizeof(data->data));
-
-       /* Fill in the remaining client fields */
-       strlcpy(new_client->name, "max6875", I2C_NAME_SIZE);
+       /* A fake client is created on the odd address */
+       if (!(fake_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+               err = -ENOMEM;
+               goto exit_kfree1;
+       }
+       memset(fake_client, 0, sizeof(struct i2c_client));
+
+       /* Init real i2c_client */
+       real_client = &data->client;
+       i2c_set_clientdata(real_client, data);
+       real_client->addr = address;
+       real_client->adapter = adapter;
+       real_client->driver = &max6875_driver;
+       real_client->flags = 0;
+       strlcpy(real_client->name, "max6875", I2C_NAME_SIZE);
        init_MUTEX(&data->update_lock);
 
-       /* Verify that the chip is really what we think it is */
-       if ((max6875_update_slice(new_client, &data->blocks[max6875_eeprom_config], 4) < 0) ||
-           (max6875_update_slice(new_client, &data->blocks[max6875_register_config], 4) < 0))
-               goto exit_kfree;
-
-       /* 0x41,0x42 must be zero and 0x40 must match in eeprom and registers */
-       if ((data->blocks[max6875_eeprom_config].data[0x41] != 0) ||
-           (data->blocks[max6875_eeprom_config].data[0x42] != 0) ||
-           (data->blocks[max6875_register_config].data[0x41] != 0) ||
-           (data->blocks[max6875_register_config].data[0x42] != 0) ||
-           (data->blocks[max6875_eeprom_config].data[0x40] !=
-            data->blocks[max6875_register_config].data[0x40]))
-               goto exit_kfree;
-
-       /* Tell the I2C layer a new client has arrived */
-       if ((err = i2c_attach_client(new_client)))
-               goto exit_kfree;
-
-       /* create the sysfs eeprom files with the correct permissions */
-       if (allow_write == 0) {
-               user_eeprom_attr.attr.mode &= ~S_IWUGO;
-               user_eeprom_attr.write = NULL;
-               config_eeprom_attr.attr.mode &= ~S_IWUGO;
-               config_eeprom_attr.write = NULL;
-               config_register_attr.attr.mode &= ~S_IWUGO;
-               config_register_attr.write = NULL;
-       }
-       sysfs_create_bin_file(&new_client->dev.kobj, &user_eeprom_attr);
-       sysfs_create_bin_file(&new_client->dev.kobj, &config_eeprom_attr);
-       sysfs_create_bin_file(&new_client->dev.kobj, &config_register_attr);
+       /* Init fake client data */
+       /* set the client data to the i2c_client so that it will get freed */
+       i2c_set_clientdata(fake_client, fake_client);
+       fake_client->addr = address | 1;
+       fake_client->adapter = adapter;
+       fake_client->driver = &max6875_driver;
+       fake_client->flags = 0;
+       strlcpy(fake_client->name, "max6875 subclient", I2C_NAME_SIZE);
+
+       /* Prevent 24RF08 corruption (in case of user error) */
+       i2c_smbus_write_quick(real_client, 0);
+
+       if ((err = i2c_attach_client(real_client)) != 0)
+               goto exit_kfree2;
+
+       if ((err = i2c_attach_client(fake_client)) != 0)
+               goto exit_detach;
+
+       sysfs_create_bin_file(&real_client->dev.kobj, &user_eeprom_attr);
 
        return 0;
 
-exit_kfree:
+exit_detach:
+       i2c_detach_client(real_client);
+exit_kfree2:
+       kfree(fake_client);
+exit_kfree1:
        kfree(data);
-exit:
        return err;
 }
 
@@ -450,13 +236,9 @@ static int max6875_detach_client(struct i2c_client *client)
        int err;
 
        err = i2c_detach_client(client);
-       if (err) {
-               dev_err(&client->dev, "Client deregistration failed, client not detached.\n");
+       if (err)
                return err;
-       }
-
        kfree(i2c_get_clientdata(client));
-
        return 0;
 }
 
index 9f3ad45daae209e27bb656780ebb44a7d3e81764..225577fdda4d58113202f395ce08ee1c1c4f200a 100644 (file)
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/hwmon-sysfs.h>
-#include <linux/i2c-sensor.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = {0x74, 0x75, 0x76, 0x77, I2C_CLIENT_END};
-static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END};
 
 /* Insmod parameters */
-SENSORS_INSMOD_1(pca9539);
+I2C_CLIENT_INSMOD_1(pca9539);
 
 enum pca9539_cmd
 {
@@ -109,10 +107,10 @@ static struct attribute_group pca9539_defattr_group = {
 
 static int pca9539_attach_adapter(struct i2c_adapter *adapter)
 {
-       return i2c_detect(adapter, &addr_data, pca9539_detect);
+       return i2c_probe(adapter, &addr_data, pca9539_detect);
 }
 
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
 static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind)
 {
        struct i2c_client *new_client;
@@ -164,10 +162,8 @@ static int pca9539_detach_client(struct i2c_client *client)
 {
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed.\n");
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
        kfree(i2c_get_clientdata(client));
        return 0;
index cfcf646540804c11780bb4d6503f74f075a4635c..6525743ff9fd76846c4fbc7c74c6dcdbd06121cf 100644 (file)
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
                                        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
                                        I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
-SENSORS_INSMOD_2(pcf8574, pcf8574a);
+I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a);
 
 /* Initial values */
 #define PCF8574_INIT 255       /* All outputs on (input mode) */
@@ -113,10 +111,10 @@ static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write);
 
 static int pcf8574_attach_adapter(struct i2c_adapter *adapter)
 {
-       return i2c_detect(adapter, &addr_data, pcf8574_detect);
+       return i2c_probe(adapter, &addr_data, pcf8574_detect);
 }
 
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
 int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind)
 {
        struct i2c_client *new_client;
@@ -186,11 +184,8 @@ static int pcf8574_detach_client(struct i2c_client *client)
 {
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev,
-                       "Client deregistration failed, client not detached.\n");
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
        kfree(i2c_get_clientdata(client));
        return 0;
index db812ade85645bb2288190eec7a2f0359a532d92..80f1df9a4500f7582c757b815eb1efc7d8f101fd 100644 (file)
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
                                        0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
-SENSORS_INSMOD_1(pcf8591);
+I2C_CLIENT_INSMOD_1(pcf8591);
 
 static int input_mode;
 module_param(input_mode, int, 0);
@@ -164,10 +162,10 @@ static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO,
  */
 static int pcf8591_attach_adapter(struct i2c_adapter *adapter)
 {
-       return i2c_detect(adapter, &addr_data, pcf8591_detect);
+       return i2c_probe(adapter, &addr_data, pcf8591_detect);
 }
 
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
 int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind)
 {
        struct i2c_client *new_client;
@@ -241,11 +239,8 @@ static int pcf8591_detach_client(struct i2c_client *client)
 {
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev,
-                       "Client deregistration failed, client not detached.\n");
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
        kfree(i2c_get_clientdata(client));
        return 0;
index 588fc2261a91e5f3695a8c4234ece5c9b364553f..0b5385c892b1ae827fcb9d3345a77787fe56f5cb 100644 (file)
@@ -67,7 +67,6 @@ static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_addr,
        .probe                  = ignore,
        .ignore                 = ignore,
-       .force                  = ignore,
 };
 
 static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem);
index 4a9ead27759693bd218f294d53c2bfd54d656b4e..dda472e5e8be3bca0be40f383b2643048c3d0c51 100644 (file)
@@ -61,7 +61,7 @@ static int i2c_bus_resume(struct device * dev)
        return rc;
 }
 
-static struct bus_type i2c_bus_type = {
+struct bus_type i2c_bus_type = {
        .name =         "i2c",
        .match =        i2c_device_match,
        .suspend =      i2c_bus_suspend,
@@ -78,13 +78,13 @@ static int i2c_device_remove(struct device *dev)
        return 0;
 }
 
-static void i2c_adapter_dev_release(struct device *dev)
+void i2c_adapter_dev_release(struct device *dev)
 {
        struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
        complete(&adap->dev_released);
 }
 
-static struct device_driver i2c_adapter_driver = {
+struct device_driver i2c_adapter_driver = {
        .name = "i2c_adapter",
        .bus = &i2c_bus_type,
        .probe = i2c_device_probe,
@@ -97,7 +97,7 @@ static void i2c_adapter_class_dev_release(struct class_device *dev)
        complete(&adap->class_dev_released);
 }
 
-static struct class i2c_adapter_class = {
+struct class i2c_adapter_class = {
        .name =         "i2c-adapter",
        .release =      &i2c_adapter_class_dev_release,
 };
@@ -188,6 +188,8 @@ int i2c_add_adapter(struct i2c_adapter *adap)
        strlcpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE);
        class_device_register(&adap->class_dev);
 
+       dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
+
        /* inform drivers of new adapters */
        list_for_each(item,&drivers) {
                driver = list_entry(item, struct i2c_driver, list);
@@ -196,8 +198,6 @@ int i2c_add_adapter(struct i2c_adapter *adap)
                        driver->attach_adapter(adap);
        }
 
-       dev_dbg(&adap->dev, "registered as adapter #%d\n", adap->nr);
-
 out_unlock:
        up(&core_lists);
        return res;
@@ -220,8 +220,8 @@ int i2c_del_adapter(struct i2c_adapter *adap)
                        break;
        }
        if (adap_from_list != adap) {
-               pr_debug("I2C: Attempting to delete an unregistered "
-                        "adapter\n");
+               pr_debug("i2c-core: attempting to delete unregistered "
+                        "adapter [%s]\n", adap->name);
                res = -EINVAL;
                goto out_unlock;
        }
@@ -230,9 +230,8 @@ int i2c_del_adapter(struct i2c_adapter *adap)
                driver = list_entry(item, struct i2c_driver, list);
                if (driver->detach_adapter)
                        if ((res = driver->detach_adapter(adap))) {
-                               dev_warn(&adap->dev, "can't detach adapter "
-                                        "while detaching driver %s: driver "
-                                        "not detached!\n", driver->name);
+                               dev_err(&adap->dev, "detach_adapter failed "
+                                       "for driver [%s]\n", driver->name);
                                goto out_unlock;
                        }
        }
@@ -247,9 +246,8 @@ int i2c_del_adapter(struct i2c_adapter *adap)
                 * must be deleted, as this would cause invalid states.
                 */
                if ((res=client->driver->detach_client(client))) {
-                       dev_err(&adap->dev, "adapter not "
-                               "unregistered, because client at "
-                               "address %02x can't be detached. ",
+                       dev_err(&adap->dev, "detach_client failed for client "
+                               "[%s] at address 0x%02x\n", client->name,
                                client->addr);
                        goto out_unlock;
                }
@@ -270,7 +268,7 @@ int i2c_del_adapter(struct i2c_adapter *adap)
        /* free dynamically allocated bus id */
        idr_remove(&i2c_adapter_idr, adap->nr);
 
-       dev_dbg(&adap->dev, "adapter unregistered\n");
+       dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
 
  out_unlock:
        up(&core_lists);
@@ -303,7 +301,7 @@ int i2c_add_driver(struct i2c_driver *driver)
                goto out_unlock;
        
        list_add_tail(&driver->list,&drivers);
-       pr_debug("i2c-core: driver %s registered.\n", driver->name);
+       pr_debug("i2c-core: driver [%s] registered\n", driver->name);
 
        /* now look for instances of driver on our adapters */
        if (driver->flags & I2C_DF_NOTIFY) {
@@ -331,21 +329,17 @@ int i2c_del_driver(struct i2c_driver *driver)
        /* Have a look at each adapter, if clients of this driver are still
         * attached. If so, detach them to be able to kill the driver 
         * afterwards.
-        */
-       pr_debug("i2c-core: unregister_driver - looking for clients.\n");
-       /* removing clients does not depend on the notify flag, else 
+        *
+        * Removing clients does not depend on the notify flag, else
         * invalid operation might (will!) result, when using stale client
         * pointers.
         */
        list_for_each(item1,&adapters) {
                adap = list_entry(item1, struct i2c_adapter, list);
-               dev_dbg(&adap->dev, "examining adapter\n");
                if (driver->detach_adapter) {
                        if ((res = driver->detach_adapter(adap))) {
-                               dev_warn(&adap->dev, "while unregistering "
-                                      "dummy driver %s, adapter could "
-                                      "not be detached properly; driver "
-                                      "not unloaded!",driver->name);
+                               dev_err(&adap->dev, "detach_adapter failed "
+                                       "for driver [%s]\n", driver->name);
                                goto out_unlock;
                        }
                } else {
@@ -353,16 +347,13 @@ int i2c_del_driver(struct i2c_driver *driver)
                                client = list_entry(item2, struct i2c_client, list);
                                if (client->driver != driver)
                                        continue;
-                               pr_debug("i2c-core.o: detaching client %s:\n", client->name);
+                               dev_dbg(&adap->dev, "detaching client [%s] "
+                                       "at 0x%02x\n", client->name,
+                                       client->addr);
                                if ((res = driver->detach_client(client))) {
-                                       dev_err(&adap->dev, "while "
-                                               "unregistering driver "
-                                               "`%s', the client at "
-                                               "address %02x of "
-                                               "adapter could not "
-                                               "be detached; driver "
-                                               "not unloaded!",
-                                               driver->name,
+                                       dev_err(&adap->dev, "detach_client "
+                                               "failed for client [%s] at "
+                                               "0x%02x\n", client->name,
                                                client->addr);
                                        goto out_unlock;
                                }
@@ -372,7 +363,7 @@ int i2c_del_driver(struct i2c_driver *driver)
 
        driver_unregister(&driver->driver);
        list_del(&driver->list);
-       pr_debug("i2c-core: driver unregistered: %s\n", driver->name);
+       pr_debug("i2c-core: driver [%s] unregistered\n", driver->name);
 
  out_unlock:
        up(&core_lists);
@@ -417,15 +408,12 @@ int i2c_attach_client(struct i2c_client *client)
        
        if (adapter->client_register)  {
                if (adapter->client_register(client))  {
-                       dev_warn(&adapter->dev, "warning: client_register "
-                               "seems to have failed for client %02x\n",
-                               client->addr);
+                       dev_dbg(&adapter->dev, "client_register "
+                               "failed for client [%s] at 0x%02x\n",
+                               client->name, client->addr);
                }
        }
 
-       dev_dbg(&adapter->dev, "client [%s] registered to adapter\n",
-               client->name);
-
        if (client->flags & I2C_CLIENT_ALLOW_USE)
                client->usage_count = 0;
 
@@ -436,7 +424,8 @@ int i2c_attach_client(struct i2c_client *client)
        
        snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
                "%d-%04x", i2c_adapter_id(adapter), client->addr);
-       pr_debug("registering %s\n", client->dev.bus_id);
+       dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
+               client->name, client->dev.bus_id);
        device_register(&client->dev);
        device_create_file(&client->dev, &dev_attr_client_name);
        
@@ -449,8 +438,12 @@ int i2c_detach_client(struct i2c_client *client)
        struct i2c_adapter *adapter = client->adapter;
        int res = 0;
        
-       if ((client->flags & I2C_CLIENT_ALLOW_USE) && (client->usage_count > 0))
+       if ((client->flags & I2C_CLIENT_ALLOW_USE)
+        && (client->usage_count > 0)) {
+               dev_warn(&client->dev, "Client [%s] still busy, "
+                        "can't detach\n", client->name);
                return -EBUSY;
+       }
 
        if (adapter->client_unregister)  {
                res = adapter->client_unregister(client);
@@ -669,98 +662,128 @@ int i2c_control(struct i2c_client *client,
  * Will not work for 10-bit addresses!
  * ----------------------------------------------------
  */
+static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind,
+                            int (*found_proc) (struct i2c_adapter *, int, int))
+{
+       int err;
+
+       /* Make sure the address is valid */
+       if (addr < 0x03 || addr > 0x77) {
+               dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",
+                        addr);
+               return -EINVAL;
+       }
+
+       /* Skip if already in use */
+       if (i2c_check_addr(adapter, addr))
+               return 0;
+
+       /* Make sure there is something at this address, unless forced */
+       if (kind < 0) {
+               if (i2c_smbus_xfer(adapter, addr, 0, 0, 0,
+                                  I2C_SMBUS_QUICK, NULL) < 0)
+                       return 0;
+
+               /* prevent 24RF08 corruption */
+               if ((addr & ~0x0f) == 0x50)
+                       i2c_smbus_xfer(adapter, addr, 0, 0, 0,
+                                      I2C_SMBUS_QUICK, NULL);
+       }
+
+       /* Finally call the custom detection function */
+       err = found_proc(adapter, addr, kind);
+
+       /* -ENODEV can be returned if there is a chip at the given address
+          but it isn't supported by this chip driver. We catch it here as
+          this isn't an error. */
+       return (err == -ENODEV) ? 0 : err;
+}
+
 int i2c_probe(struct i2c_adapter *adapter,
              struct i2c_client_address_data *address_data,
              int (*found_proc) (struct i2c_adapter *, int, int))
 {
-       int addr,i,found,err;
+       int i, err;
        int adap_id = i2c_adapter_id(adapter);
 
        /* Forget it if we can't probe using SMBUS_QUICK */
        if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK))
                return -1;
 
-       for (addr = 0x00; addr <= 0x7f; addr++) {
-
-               /* Skip if already in use */
-               if (i2c_check_addr(adapter,addr))
-                       continue;
-
-               /* If it is in one of the force entries, we don't do any detection
-                  at all */
-               found = 0;
-
-               for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 2) {
-                       if (((adap_id == address_data->force[i]) || 
-                            (address_data->force[i] == ANY_I2C_BUS)) &&
-                            (addr == address_data->force[i+1])) {
-                               dev_dbg(&adapter->dev, "found force parameter for adapter %d, addr %04x\n",
-                                       adap_id, addr);
-                               if ((err = found_proc(adapter,addr,0)))
-                                       return err;
-                               found = 1;
-                       }
-               }
-               if (found) 
-                       continue;
-
-               /* If this address is in one of the ignores, we can forget about
-                  it right now */
-               for (i = 0;
-                    !found && (address_data->ignore[i] != I2C_CLIENT_END);
-                    i += 2) {
-                       if (((adap_id == address_data->ignore[i]) || 
-                           ((address_data->ignore[i] == ANY_I2C_BUS))) &&
-                           (addr == address_data->ignore[i+1])) {
-                               dev_dbg(&adapter->dev, "found ignore parameter for adapter %d, "
-                                       "addr %04x\n", adap_id ,addr);
-                               found = 1;
+       /* Force entries are done first, and are not affected by ignore
+          entries */
+       if (address_data->forces) {
+               unsigned short **forces = address_data->forces;
+               int kind;
+
+               for (kind = 0; forces[kind]; kind++) {
+                       for (i = 0; forces[kind][i] != I2C_CLIENT_END;
+                            i += 2) {
+                               if (forces[kind][i] == adap_id
+                                || forces[kind][i] == ANY_I2C_BUS) {
+                                       dev_dbg(&adapter->dev, "found force "
+                                               "parameter for adapter %d, "
+                                               "addr 0x%02x, kind %d\n",
+                                               adap_id, forces[kind][i + 1],
+                                               kind);
+                                       err = i2c_probe_address(adapter,
+                                               forces[kind][i + 1],
+                                               kind, found_proc);
+                                       if (err)
+                                               return err;
+                               }
                        }
                }
-               if (found) 
-                       continue;
+       }
 
-               /* Now, we will do a detection, but only if it is in the normal or 
-                  probe entries */  
-               for (i = 0;
-                    !found && (address_data->normal_i2c[i] != I2C_CLIENT_END);
-                    i += 1) {
-                       if (addr == address_data->normal_i2c[i]) {
-                               found = 1;
-                               dev_dbg(&adapter->dev, "found normal i2c entry for adapter %d, "
-                                       "addr %02x\n", adap_id, addr);
-                       }
+       /* Probe entries are done second, and are not affected by ignore
+          entries either */
+       for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) {
+               if (address_data->probe[i] == adap_id
+                || address_data->probe[i] == ANY_I2C_BUS) {
+                       dev_dbg(&adapter->dev, "found probe parameter for "
+                               "adapter %d, addr 0x%02x\n", adap_id,
+                               address_data->probe[i + 1]);
+                       err = i2c_probe_address(adapter,
+                                               address_data->probe[i + 1],
+                                               -1, found_proc);
+                       if (err)
+                               return err;
                }
+       }
 
-               for (i = 0;
-                    !found && (address_data->probe[i] != I2C_CLIENT_END);
-                    i += 2) {
-                       if (((adap_id == address_data->probe[i]) ||
-                           ((address_data->probe[i] == ANY_I2C_BUS))) &&
-                           (addr == address_data->probe[i+1])) {
-                               found = 1;
-                               dev_dbg(&adapter->dev, "found probe parameter for adapter %d, "
-                                       "addr %04x\n", adap_id,addr);
+       /* Normal entries are done last, unless shadowed by an ignore entry */
+       for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) {
+               int j, ignore;
+
+               ignore = 0;
+               for (j = 0; address_data->ignore[j] != I2C_CLIENT_END;
+                    j += 2) {
+                       if ((address_data->ignore[j] == adap_id ||
+                            address_data->ignore[j] == ANY_I2C_BUS)
+                        && address_data->ignore[j + 1]
+                           == address_data->normal_i2c[i]) {
+                               dev_dbg(&adapter->dev, "found ignore "
+                                       "parameter for adapter %d, "
+                                       "addr 0x%02x\n", adap_id,
+                                       address_data->ignore[j + 1]);
                        }
+                       ignore = 1;
+                       break;
                }
-               if (!found) 
+               if (ignore)
                        continue;
 
-               /* OK, so we really should examine this address. First check
-                  whether there is some client here at all! */
-               if (i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
-                       if ((err = found_proc(adapter,addr,-1)))
-                               return err;
+               dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
+                       "addr 0x%02x\n", adap_id,
+                       address_data->normal_i2c[i]);
+               err = i2c_probe_address(adapter, address_data->normal_i2c[i],
+                                       -1, found_proc);
+               if (err)
+                       return err;
        }
-       return 0;
-}
 
-/*
- * return id number for a specific adapter
- */
-int i2c_adapter_id(struct i2c_adapter *adap)
-{
-       return adap->nr;
+       return 0;
 }
 
 struct i2c_adapter* i2c_get_adapter(int id)
@@ -1171,6 +1194,12 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
 }
 
 
+/* Next four are needed by i2c-isa */
+EXPORT_SYMBOL_GPL(i2c_adapter_dev_release);
+EXPORT_SYMBOL_GPL(i2c_adapter_driver);
+EXPORT_SYMBOL_GPL(i2c_adapter_class);
+EXPORT_SYMBOL_GPL(i2c_bus_type);
+
 EXPORT_SYMBOL(i2c_add_adapter);
 EXPORT_SYMBOL(i2c_del_adapter);
 EXPORT_SYMBOL(i2c_add_driver);
@@ -1186,7 +1215,6 @@ EXPORT_SYMBOL(i2c_master_send);
 EXPORT_SYMBOL(i2c_master_recv);
 EXPORT_SYMBOL(i2c_control);
 EXPORT_SYMBOL(i2c_transfer);
-EXPORT_SYMBOL(i2c_adapter_id);
 EXPORT_SYMBOL(i2c_get_adapter);
 EXPORT_SYMBOL(i2c_put_adapter);
 EXPORT_SYMBOL(i2c_probe);
index bc5d557e5dd93063ba7d6a18d2abde2569e482cd..aa7a4fadef64d6d8106bd1a9d80d5227e8d9026a 100644 (file)
@@ -434,7 +434,8 @@ static int i2cdev_attach_adapter(struct i2c_adapter *adap)
 
        devfs_mk_cdev(MKDEV(I2C_MAJOR, i2c_dev->minor),
                        S_IFCHR|S_IRUSR|S_IWUSR, "i2c/%d", i2c_dev->minor);
-       dev_dbg(&adap->dev, "Registered as minor %d\n", i2c_dev->minor);
+       pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
+                adap->name, i2c_dev->minor);
 
        /* register this i2c device with the driver core */
        i2c_dev->adap = adap;
@@ -471,7 +472,7 @@ static int i2cdev_detach_adapter(struct i2c_adapter *adap)
        wait_for_completion(&i2c_dev->released);
        kfree(i2c_dev);
 
-       dev_dbg(&adap->dev, "Adapter unregistered\n");
+       pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
        return 0;
 }
 
diff --git a/drivers/i2c/i2c-sensor-detect.c b/drivers/i2c/i2c-sensor-detect.c
deleted file mode 100644 (file)
index f99a816..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
-    i2c-sensor-detect.c - Part of lm_sensors, Linux kernel modules for hardware
-                         monitoring
-    Copyright (c) 1998 - 2001 Frodo Looijaard <frodol@dds.nl> and
-    Mark D. Studebaker <mdsxyz123@yahoo.com>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-
-static unsigned short empty[] = {I2C_CLIENT_END};
-static unsigned int empty_isa[] = {I2C_CLIENT_ISA_END};
-
-/* Very inefficient for ISA detects, and won't work for 10-bit addresses! */
-int i2c_detect(struct i2c_adapter *adapter,
-              struct i2c_address_data *address_data,
-              int (*found_proc) (struct i2c_adapter *, int, int))
-{
-       int addr, i, found, j, err;
-       struct i2c_force_data *this_force;
-       int is_isa = i2c_is_isa_adapter(adapter);
-       int adapter_id =
-           is_isa ? ANY_I2C_ISA_BUS : i2c_adapter_id(adapter);
-       unsigned short *normal_i2c;
-       unsigned int *normal_isa;
-       unsigned short *probe;
-       unsigned short *ignore;
-
-       /* Forget it if we can't probe using SMBUS_QUICK */
-       if ((!is_isa) &&
-           !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK))
-               return -1;
-       
-       /* Use default "empty" list if the adapter doesn't specify any */
-       normal_i2c = probe = ignore = empty;
-       normal_isa = empty_isa;
-       if (address_data->normal_i2c)
-               normal_i2c = address_data->normal_i2c;
-       if (address_data->normal_isa)
-               normal_isa = address_data->normal_isa;
-       if (address_data->probe)
-               probe = address_data->probe;
-       if (address_data->ignore)
-               ignore = address_data->ignore;
-
-       for (addr = 0x00; addr <= (is_isa ? 0xffff : 0x7f); addr++) {
-               if (!is_isa && i2c_check_addr(adapter, addr))
-                       continue;
-
-               /* If it is in one of the force entries, we don't do any
-                  detection at all */
-               found = 0;
-               for (i = 0; !found && (this_force = address_data->forces + i, this_force->force); i++) {
-                       for (j = 0; !found && (this_force->force[j] != I2C_CLIENT_END); j += 2) {
-                               if ( ((adapter_id == this_force->force[j]) ||
-                                     ((this_force->force[j] == ANY_I2C_BUS) && !is_isa)) &&
-                                     (addr == this_force->force[j + 1]) ) {
-                                       dev_dbg(&adapter->dev, "found force parameter for adapter %d, addr %04x\n", adapter_id, addr);
-                                       if ((err = found_proc(adapter, addr, this_force->kind)))
-                                               return err;
-                                       found = 1;
-                               }
-                       }
-               }
-               if (found)
-                       continue;
-
-               /* If this address is in one of the ignores, we can forget about it
-                  right now */
-               for (i = 0; !found && (ignore[i] != I2C_CLIENT_END); i += 2) {
-                       if ( ((adapter_id == ignore[i]) ||
-                             ((ignore[i] == ANY_I2C_BUS) &&
-                              !is_isa)) &&
-                             (addr == ignore[i + 1])) {
-                               dev_dbg(&adapter->dev, "found ignore parameter for adapter %d, addr %04x\n", adapter_id, addr);
-                               found = 1;
-                       }
-               }
-               if (found)
-                       continue;
-
-               /* Now, we will do a detection, but only if it is in the normal or 
-                  probe entries */
-               if (is_isa) {
-                       for (i = 0; !found && (normal_isa[i] != I2C_CLIENT_ISA_END); i += 1) {
-                               if (addr == normal_isa[i]) {
-                                       dev_dbg(&adapter->dev, "found normal isa entry for adapter %d, addr %04x\n", adapter_id, addr);
-                                       found = 1;
-                               }
-                       }
-               } else {
-                       for (i = 0; !found && (normal_i2c[i] != I2C_CLIENT_END); i += 1) {
-                               if (addr == normal_i2c[i]) {
-                                       found = 1;
-                                       dev_dbg(&adapter->dev, "found normal i2c entry for adapter %d, addr %02x\n", adapter_id, addr);
-                               }
-                       }
-               }
-
-               for (i = 0;
-                    !found && (probe[i] != I2C_CLIENT_END);
-                    i += 2) {
-                       if (((adapter_id == probe[i]) ||
-                            ((probe[i] == ANY_I2C_BUS) && !is_isa))
-                           && (addr == probe[i + 1])) {
-                               dev_dbg(&adapter->dev, "found probe parameter for adapter %d, addr %04x\n", adapter_id, addr);
-                               found = 1;
-                       }
-               }
-               if (!found)
-                       continue;
-
-               /* OK, so we really should examine this address. First check
-                  whether there is some client here at all! */
-               if (is_isa ||
-                   (i2c_smbus_xfer (adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL) >= 0))
-                       if ((err = found_proc(adapter, addr, -1)))
-                               return err;
-       }
-       return 0;
-}
-
-EXPORT_SYMBOL(i2c_detect);
-
-MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
-             "Rudolf Marek <r.marek@sh.cvut.cz>");
-
-MODULE_DESCRIPTION("i2c-sensor driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/i2c-sensor-vid.c b/drivers/i2c/i2c-sensor-vid.c
deleted file mode 100644 (file)
index 922e22f..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
-    i2c-sensor-vid.c -  Part of lm_sensors, Linux kernel modules for hardware
-                       monitoring
-
-    Copyright (c) 2004 Rudolf Marek <r.marek@sh.cvut.cz>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-
-struct vrm_model {
-       u8 vendor;
-       u8 eff_family;
-       u8 eff_model;
-       int vrm_type;
-};
-
-#define ANY 0xFF
-
-#ifdef CONFIG_X86
-
-static struct vrm_model vrm_models[] = {
-       {X86_VENDOR_AMD, 0x6, ANY, 90},         /* Athlon Duron etc */
-       {X86_VENDOR_AMD, 0xF, ANY, 24},         /* Athlon 64, Opteron */
-       {X86_VENDOR_INTEL, 0x6, 0x9, 85},       /* 0.13um too */
-       {X86_VENDOR_INTEL, 0x6, 0xB, 85},       /* 0xB Tualatin */
-       {X86_VENDOR_INTEL, 0x6, ANY, 82},       /* any P6 */
-       {X86_VENDOR_INTEL, 0x7, ANY, 0},        /* Itanium */
-       {X86_VENDOR_INTEL, 0xF, 0x3, 100},      /* P4 Prescott */
-       {X86_VENDOR_INTEL, 0xF, ANY, 90},       /* P4 before Prescott */
-       {X86_VENDOR_INTEL, 0x10,ANY, 0},        /* Itanium 2 */
-       {X86_VENDOR_UNKNOWN, ANY, ANY, 0}       /* stop here */
-       };
-
-static int find_vrm(u8 eff_family, u8 eff_model, u8 vendor)
-{
-       int i = 0;
-
-       while (vrm_models[i].vendor!=X86_VENDOR_UNKNOWN) {
-               if (vrm_models[i].vendor==vendor)
-                       if ((vrm_models[i].eff_family==eff_family)&& \
-                       ((vrm_models[i].eff_model==eff_model)|| \
-                       (vrm_models[i].eff_model==ANY)))
-                               return vrm_models[i].vrm_type;
-               i++;
-       }
-
-       return 0;
-}
-
-int i2c_which_vrm(void)
-{
-       struct cpuinfo_x86 *c = cpu_data;
-       u32 eax;
-       u8 eff_family, eff_model;
-       int vrm_ret;
-
-       if (c->x86 < 6) return 0;       /* any CPU with familly lower than 6
-                                       dont have VID and/or CPUID */
-       eax = cpuid_eax(1);
-       eff_family = ((eax & 0x00000F00)>>8);
-       eff_model  = ((eax & 0x000000F0)>>4);
-       if (eff_family == 0xF) {        /* use extended model & family */
-               eff_family += ((eax & 0x00F00000)>>20);
-               eff_model += ((eax & 0x000F0000)>>16)<<4;
-       }
-       vrm_ret = find_vrm(eff_family,eff_model,c->x86_vendor);
-       if (vrm_ret == 0)
-               printk(KERN_INFO "i2c-sensor.o: Unknown VRM version of your"
-               " x86 CPU\n");
-       return vrm_ret;
-}
-
-/* and now for something completely different for Non-x86 world*/
-#else
-int i2c_which_vrm(void)
-{
-       printk(KERN_INFO "i2c-sensor.o: Unknown VRM version of your CPU\n");
-       return 0;
-}
-#endif
-
-EXPORT_SYMBOL(i2c_which_vrm);
index 248e3cc8b3527dd37bbc8a60417a1658e46d8845..f174aee659e5e0d086314e6ba3ebcfb3c92249cc 100644 (file)
@@ -150,7 +150,7 @@ static void ide_complete_power_step(ide_drive_t *drive, struct request *rq, u8 s
 
        switch (rq->pm->pm_step) {
        case ide_pm_flush_cache:        /* Suspend step 1 (flush cache) complete */
-               if (rq->pm->pm_state == 4)
+               if (rq->pm->pm_state == PM_EVENT_FREEZE)
                        rq->pm->pm_step = ide_pm_state_completed;
                else
                        rq->pm->pm_step = idedisk_pm_standby;
index dae1bd5b8c3e1e16872af0eb5470ff93b3231230..73ca8f73917d9172bba616311437ccb3de9966e9 100644 (file)
@@ -1229,7 +1229,7 @@ static int generic_ide_suspend(struct device *dev, pm_message_t state)
        rq.special = &args;
        rq.pm = &rqpm;
        rqpm.pm_step = ide_pm_state_start_suspend;
-       rqpm.pm_state = state;
+       rqpm.pm_state = state.event;
 
        return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
@@ -1248,7 +1248,7 @@ static int generic_ide_resume(struct device *dev)
        rq.special = &args;
        rq.pm = &rqpm;
        rqpm.pm_step = ide_pm_state_start_resume;
-       rqpm.pm_state = 0;
+       rqpm.pm_state = PM_EVENT_ON;
 
        return ide_do_drive_cmd(drive, &rq, ide_head_wait);
 }
index 10592cec6c43aca4e7bdf2443cff2d0dde5ca402..24e21b2838c15028bd4f72c4a2305ddf0b7b54a3 100644 (file)
@@ -350,9 +350,9 @@ static int sc1200_suspend (struct pci_dev *dev, pm_message_t state)
 {
        ide_hwif_t              *hwif = NULL;
 
-       printk("SC1200: suspend(%u)\n", state);
+       printk("SC1200: suspend(%u)\n", state.event);
 
-       if (state == 0) {
+       if (state.event == PM_EVENT_ON) {
                // we only save state when going from full power to less
 
                //
@@ -386,8 +386,8 @@ static int sc1200_suspend (struct pci_dev *dev, pm_message_t state)
        /* You don't need to iterate over disks -- sysfs should have done that for you already */ 
 
        pci_disable_device(dev);
-       pci_set_power_state(dev,state);
-       dev->current_state = state;
+       pci_set_power_state(dev, pci_choose_state(dev, state));
+       dev->current_state = state.event;
        return 0;
 }
 
@@ -396,8 +396,8 @@ static int sc1200_resume (struct pci_dev *dev)
        ide_hwif_t      *hwif = NULL;
 
 printk("SC1200: resume\n");
-       pci_set_power_state(dev,0);     // bring chip back from sleep state
-       dev->current_state = 0;
+       pci_set_power_state(dev, PCI_D0);       // bring chip back from sleep state
+       dev->current_state = PM_EVENT_ON;
        pci_enable_device(dev);
        //
        // loop over all interfaces that are part of this pci device:
index ea65b070a3675b2e3c3f2b6e1e1840f93adb6cb8..87d1f8a1f41e4de7a0595d8702bf101276af2ba5 100644 (file)
@@ -1504,12 +1504,12 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
 }
 
 static int
-pmac_ide_macio_suspend(struct macio_dev *mdev, u32 state)
+pmac_ide_macio_suspend(struct macio_dev *mdev, pm_message_t state)
 {
        ide_hwif_t      *hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
        int             rc = 0;
 
-       if (state != mdev->ofdev.dev.power.power_state && state >= 2) {
+       if (state.event != mdev->ofdev.dev.power.power_state.event && state.event >= PM_EVENT_SUSPEND) {
                rc = pmac_ide_do_suspend(hwif);
                if (rc == 0)
                        mdev->ofdev.dev.power.power_state = state;
@@ -1524,10 +1524,10 @@ pmac_ide_macio_resume(struct macio_dev *mdev)
        ide_hwif_t      *hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
        int             rc = 0;
        
-       if (mdev->ofdev.dev.power.power_state != 0) {
+       if (mdev->ofdev.dev.power.power_state.event != PM_EVENT_ON) {
                rc = pmac_ide_do_resume(hwif);
                if (rc == 0)
-                       mdev->ofdev.dev.power.power_state = 0;
+                       mdev->ofdev.dev.power.power_state = PMSG_ON;
        }
 
        return rc;
@@ -1608,12 +1608,12 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
 }
 
 static int
-pmac_ide_pci_suspend(struct pci_dev *pdev, u32 state)
+pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        ide_hwif_t      *hwif = (ide_hwif_t *)pci_get_drvdata(pdev);
        int             rc = 0;
        
-       if (state != pdev->dev.power.power_state && state >= 2) {
+       if (state.event != pdev->dev.power.power_state.event && state.event >= 2) {
                rc = pmac_ide_do_suspend(hwif);
                if (rc == 0)
                        pdev->dev.power.power_state = state;
@@ -1628,10 +1628,10 @@ pmac_ide_pci_resume(struct pci_dev *pdev)
        ide_hwif_t      *hwif = (ide_hwif_t *)pci_get_drvdata(pdev);
        int             rc = 0;
        
-       if (pdev->dev.power.power_state != 0) {
+       if (pdev->dev.power.power_state.event != PM_EVENT_ON) {
                rc = pmac_ide_do_resume(hwif);
                if (rc == 0)
-                       pdev->dev.power.power_state = 0;
+                       pdev->dev.power.power_state = PMSG_ON;
        }
 
        return rc;
index b248d89de8b4e26c543d5b30c2bd7a187d657059..d633770fac8ee3b99a3a77c84356db02be2bf7c6 100644 (file)
@@ -681,7 +681,7 @@ static void handle_packet_response(struct hpsb_host *host, int tcode,
                 return;
         }
 
-       __skb_unlink(skb, skb->list);
+       __skb_unlink(skb, &host->pending_packet_queue);
 
        if (packet->state == hpsb_queued) {
                packet->sendtime = jiffies;
@@ -989,7 +989,7 @@ void abort_timedouts(unsigned long __opaque)
                packet = (struct hpsb_packet *)skb->data;
 
                if (time_before(packet->sendtime + expire, jiffies)) {
-                       __skb_unlink(skb, skb->list);
+                       __skb_unlink(skb, &host->pending_packet_queue);
                        packet->state = hpsb_complete;
                        packet->ack_code = ACKX_TIMEOUT;
                        queue_packet_complete(packet);
index bebcc47ab06c2614c0d141d522c7731a212afa08..b23322523ef57b1cf147e4368239487e55ef15bc 100644 (file)
@@ -1068,6 +1068,8 @@ static int nodemgr_hotplug(struct class_device *cdev, char **envp, int num_envp,
        struct unit_directory *ud;
        int i = 0;
        int length = 0;
+       /* ieee1394:venNmoNspNverN */
+       char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
 
        if (!cdev)
                return -ENODEV;
@@ -1094,6 +1096,12 @@ do {                                                             \
        PUT_ENVP("GUID=%016Lx", (unsigned long long)ud->ne->guid);
        PUT_ENVP("SPECIFIER_ID=%06x", ud->specifier_id);
        PUT_ENVP("VERSION=%06x", ud->version);
+       snprintf(buf, sizeof(buf), "ieee1394:ven%08Xmo%08Xsp%08Xver%08X",
+                       ud->vendor_id,
+                       ud->model_id,
+                       ud->specifier_id,
+                       ud->version);
+       PUT_ENVP("MODALIAS=%s", buf);
 
 #undef PUT_ENVP
 
index 36074e6eeebb5703e9a9848f40254c000eef65b8..6b1ab875333b1d54d88fc53f40fc571899538985 100644 (file)
@@ -1464,26 +1464,6 @@ static int __devinit add_card(struct pci_dev *dev,
                                                   { 0x50, I2C_M_RD, 20, (unsigned char*) lynx->bus_info_block }
                                                 };
 
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-                        union i2c_smbus_data data;
-
-                        if (i2c_smbus_xfer(i2c_ad, 80, 0, I2C_SMBUS_WRITE, 0, I2C_SMBUS_BYTE,NULL))
-                                PRINT(KERN_ERR, lynx->id,"eeprom read start has failed");
-                        else
-                        {
-                                u16 addr;
-                                for (addr=0x00; addr < 0x100; addr++) {
-                                        if (i2c_smbus_xfer(i2c_ad, 80, 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE,& data)) {
-                                                PRINT(KERN_ERR, lynx->id, "unable to read i2c %x", addr);
-                                                break;
-                                        }
-                                        else
-                                                PRINT(KERN_DEBUG, lynx->id,"got serial eeprom data at %x: %x",addr, data.byte);
-                                }
-                        }
-#endif
-
                         /* we use i2c_transfer, because i2c_smbus_read_block_data does not work properly and we
                            do it more efficiently in one transaction rather then using several reads */
                         if (i2c_transfer(i2c_ad, msg, 2) < 0) {
index 10be36731ed7baef2cfc30abb3aa57f036fc6c02..678a7e097f329de2e3e6b926443807babf2ccdf4 100644 (file)
@@ -1,5 +1,3 @@
-EXTRA_CFLAGS += -Idrivers/infiniband/include
-
 obj-$(CONFIG_INFINIBAND) +=            ib_core.o ib_mad.o ib_sa.o \
                                        ib_cm.o ib_umad.o ib_ucm.o
 obj-$(CONFIG_INFINIBAND_USER_VERBS) += ib_uverbs.o
index 729f0b0d983a0fe91abae6f54c4545ec77522919..5ac86f566dc020004f28f73bacf4934998a9fd30 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2004 Mellanox Technologies Ltd.  All rights reserved.
- * Copyright (c) 2004 Infinicon Corporation.  All rights reserved.
- * Copyright (c) 2004 Intel Corporation.  All rights reserved.
- * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
- * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
+ * Copyright (c) 2004, 2005 Mellanox Technologies Ltd.  All rights reserved.
+ * Copyright (c) 2004, 2005 Infinicon Corporation.  All rights reserved.
+ * Copyright (c) 2004, 2005 Intel Corporation.  All rights reserved.
+ * Copyright (c) 2004, 2005 Topspin Corporation.  All rights reserved.
+ * Copyright (c) 2004, 2005 Voltaire Corporation.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -40,7 +41,7 @@
 
 #include <asm/bug.h>
 
-#include <ib_smi.h>
+#include <rdma/ib_smi.h>
 
 #include "smi.h"
 #include "agent_priv.h"
index 17435af1e914d22fe9b6097f6157881b9e586c8d..2ec6d7f1b7d083197301899752be400deef5c068 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * Copyright (c) 2004 Mellanox Technologies Ltd.  All rights reserved.
- * Copyright (c) 2004 Infinicon Corporation.  All rights reserved.
- * Copyright (c) 2004 Intel Corporation.  All rights reserved.
- * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
- * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
+ * Copyright (c) 2004, 2005 Mellanox Technologies Ltd.  All rights reserved.
+ * Copyright (c) 2004, 2005 Infinicon Corporation.  All rights reserved.
+ * Copyright (c) 2004, 2005 Intel Corporation.  All rights reserved.
+ * Copyright (c) 2004, 2005 Topspin Corporation.  All rights reserved.
+ * Copyright (c) 2004, 2005 Voltaire Corporation.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
index 3042360c97e1910b052ff48c8e57378c7390749e..f014e639088ca13d923df980234b998244062983 100644 (file)
@@ -1,5 +1,8 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Intel Corporation. All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
  * $Id: cache.c 1349 2004-12-16 21:09:43Z roland $
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 
-#include <ib_cache.h>
+#include <rdma/ib_cache.h>
 
 #include "core_priv.h"
 
index 403ed125d8f4c1c7adbc14916446a8ce6c2b2f40..4de93ba274a61202e7e9d29d494826a148c79ac2 100644 (file)
@@ -43,8 +43,8 @@
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
 
-#include <ib_cache.h>
-#include <ib_cm.h>
+#include <rdma/ib_cache.h>
+#include <rdma/ib_cm.h>
 #include "cm_msgs.h"
 
 MODULE_AUTHOR("Sean Hefty");
@@ -83,7 +83,7 @@ struct cm_port {
 struct cm_device {
        struct list_head list;
        struct ib_device *device;
-       u64 ca_guid;
+       __be64 ca_guid;
        struct cm_port port[0];
 };
 
@@ -100,8 +100,8 @@ struct cm_work {
        struct list_head list;
        struct cm_port *port;
        struct ib_mad_recv_wc *mad_recv_wc;     /* Received MADs */
-       u32 local_id;                           /* Established / timewait */
-       u32 remote_id;
+       __be32 local_id;                        /* Established / timewait */
+       __be32 remote_id;
        struct ib_cm_event cm_event;
        struct ib_sa_path_rec path[0];
 };
@@ -110,8 +110,8 @@ struct cm_timewait_info {
        struct cm_work work;                    /* Must be first. */
        struct rb_node remote_qp_node;
        struct rb_node remote_id_node;
-       u64 remote_ca_guid;
-       u32 remote_qpn;
+       __be64 remote_ca_guid;
+       __be32 remote_qpn;
        u8 inserted_remote_qp;
        u8 inserted_remote_id;
 };
@@ -132,11 +132,11 @@ struct cm_id_private {
        struct cm_av alt_av;
 
        void *private_data;
-       u64 tid;
-       u32 local_qpn;
-       u32 remote_qpn;
-       u32 sq_psn;
-       u32 rq_psn;
+       __be64 tid;
+       __be32 local_qpn;
+       __be32 remote_qpn;
+       __be32 sq_psn;
+       __be32 rq_psn;
        int timeout_ms;
        enum ib_mtu path_mtu;
        u8 private_data_len;
@@ -253,7 +253,7 @@ static void cm_set_ah_attr(struct ib_ah_attr *ah_attr, u8 port_num,
                           u16 dlid, u8 sl, u16 src_path_bits)
 {
        memset(ah_attr, 0, sizeof ah_attr);
-       ah_attr->dlid = be16_to_cpu(dlid);
+       ah_attr->dlid = dlid;
        ah_attr->sl = sl;
        ah_attr->src_path_bits = src_path_bits;
        ah_attr->port_num = port_num;
@@ -264,7 +264,7 @@ static void cm_init_av_for_response(struct cm_port *port,
 {
        av->port = port;
        av->pkey_index = wc->pkey_index;
-       cm_set_ah_attr(&av->ah_attr, port->port_num, cpu_to_be16(wc->slid),
+       cm_set_ah_attr(&av->ah_attr, port->port_num, wc->slid,
                       wc->sl, wc->dlid_path_bits);
 }
 
@@ -295,8 +295,9 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
                return ret;
 
        av->port = port;
-       cm_set_ah_attr(&av->ah_attr, av->port->port_num, path->dlid,
-                      path->sl, path->slid & 0x7F);
+       cm_set_ah_attr(&av->ah_attr, av->port->port_num,
+                      be16_to_cpu(path->dlid), path->sl,
+                      be16_to_cpu(path->slid) & 0x7F);
        av->packet_life_time = path->packet_life_time;
        return 0;
 }
@@ -309,26 +310,26 @@ static int cm_alloc_id(struct cm_id_private *cm_id_priv)
        do {
                spin_lock_irqsave(&cm.lock, flags);
                ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, 1,
-                                       (int *) &cm_id_priv->id.local_id);
+                                       (__force int *) &cm_id_priv->id.local_id);
                spin_unlock_irqrestore(&cm.lock, flags);
        } while( (ret == -EAGAIN) && idr_pre_get(&cm.local_id_table, GFP_KERNEL) );
        return ret;
 }
 
-static void cm_free_id(u32 local_id)
+static void cm_free_id(__be32 local_id)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&cm.lock, flags);
-       idr_remove(&cm.local_id_table, (int) local_id);
+       idr_remove(&cm.local_id_table, (__force int) local_id);
        spin_unlock_irqrestore(&cm.lock, flags);
 }
 
-static struct cm_id_private * cm_get_id(u32 local_id, u32 remote_id)
+static struct cm_id_private * cm_get_id(__be32 local_id, __be32 remote_id)
 {
        struct cm_id_private *cm_id_priv;
 
-       cm_id_priv = idr_find(&cm.local_id_table, (int) local_id);
+       cm_id_priv = idr_find(&cm.local_id_table, (__force int) local_id);
        if (cm_id_priv) {
                if (cm_id_priv->id.remote_id == remote_id)
                        atomic_inc(&cm_id_priv->refcount);
@@ -339,7 +340,7 @@ static struct cm_id_private * cm_get_id(u32 local_id, u32 remote_id)
        return cm_id_priv;
 }
 
-static struct cm_id_private * cm_acquire_id(u32 local_id, u32 remote_id)
+static struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id)
 {
        struct cm_id_private *cm_id_priv;
        unsigned long flags;
@@ -356,8 +357,8 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
        struct rb_node **link = &cm.listen_service_table.rb_node;
        struct rb_node *parent = NULL;
        struct cm_id_private *cur_cm_id_priv;
-       u64 service_id = cm_id_priv->id.service_id;
-       u64 service_mask = cm_id_priv->id.service_mask;
+       __be64 service_id = cm_id_priv->id.service_id;
+       __be64 service_mask = cm_id_priv->id.service_mask;
 
        while (*link) {
                parent = *link;
@@ -376,7 +377,7 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
        return NULL;
 }
 
-static struct cm_id_private * cm_find_listen(u64 service_id)
+static struct cm_id_private * cm_find_listen(__be64 service_id)
 {
        struct rb_node *node = cm.listen_service_table.rb_node;
        struct cm_id_private *cm_id_priv;
@@ -400,8 +401,8 @@ static struct cm_timewait_info * cm_insert_remote_id(struct cm_timewait_info
        struct rb_node **link = &cm.remote_id_table.rb_node;
        struct rb_node *parent = NULL;
        struct cm_timewait_info *cur_timewait_info;
-       u64 remote_ca_guid = timewait_info->remote_ca_guid;
-       u32 remote_id = timewait_info->work.remote_id;
+       __be64 remote_ca_guid = timewait_info->remote_ca_guid;
+       __be32 remote_id = timewait_info->work.remote_id;
 
        while (*link) {
                parent = *link;
@@ -424,8 +425,8 @@ static struct cm_timewait_info * cm_insert_remote_id(struct cm_timewait_info
        return NULL;
 }
 
-static struct cm_timewait_info * cm_find_remote_id(u64 remote_ca_guid,
-                                                  u32 remote_id)
+static struct cm_timewait_info * cm_find_remote_id(__be64 remote_ca_guid,
+                                                  __be32 remote_id)
 {
        struct rb_node *node = cm.remote_id_table.rb_node;
        struct cm_timewait_info *timewait_info;
@@ -453,8 +454,8 @@ static struct cm_timewait_info * cm_insert_remote_qpn(struct cm_timewait_info
        struct rb_node **link = &cm.remote_qp_table.rb_node;
        struct rb_node *parent = NULL;
        struct cm_timewait_info *cur_timewait_info;
-       u64 remote_ca_guid = timewait_info->remote_ca_guid;
-       u32 remote_qpn = timewait_info->remote_qpn;
+       __be64 remote_ca_guid = timewait_info->remote_ca_guid;
+       __be32 remote_qpn = timewait_info->remote_qpn;
 
        while (*link) {
                parent = *link;
@@ -484,7 +485,7 @@ static struct cm_id_private * cm_insert_remote_sidr(struct cm_id_private
        struct rb_node *parent = NULL;
        struct cm_id_private *cur_cm_id_priv;
        union ib_gid *port_gid = &cm_id_priv->av.dgid;
-       u32 remote_id = cm_id_priv->id.remote_id;
+       __be32 remote_id = cm_id_priv->id.remote_id;
 
        while (*link) {
                parent = *link;
@@ -598,7 +599,7 @@ static void cm_cleanup_timewait(struct cm_timewait_info *timewait_info)
        spin_unlock_irqrestore(&cm.lock, flags);
 }
 
-static struct cm_timewait_info * cm_create_timewait_info(u32 local_id)
+static struct cm_timewait_info * cm_create_timewait_info(__be32 local_id)
 {
        struct cm_timewait_info *timewait_info;
 
@@ -715,14 +716,15 @@ retest:
 EXPORT_SYMBOL(ib_destroy_cm_id);
 
 int ib_cm_listen(struct ib_cm_id *cm_id,
-                u64 service_id,
-                u64 service_mask)
+                __be64 service_id,
+                __be64 service_mask)
 {
        struct cm_id_private *cm_id_priv, *cur_cm_id_priv;
        unsigned long flags;
        int ret = 0;
 
-       service_mask = service_mask ? service_mask : ~0ULL;
+       service_mask = service_mask ? service_mask :
+                      __constant_cpu_to_be64(~0ULL);
        service_id &= service_mask;
        if ((service_id & IB_SERVICE_ID_AGN_MASK) == IB_CM_ASSIGN_SERVICE_ID &&
            (service_id != IB_CM_ASSIGN_SERVICE_ID))
@@ -735,8 +737,8 @@ int ib_cm_listen(struct ib_cm_id *cm_id,
 
        spin_lock_irqsave(&cm.lock, flags);
        if (service_id == IB_CM_ASSIGN_SERVICE_ID) {
-               cm_id->service_id = __cpu_to_be64(cm.listen_service_id++);
-               cm_id->service_mask = ~0ULL;
+               cm_id->service_id = cpu_to_be64(cm.listen_service_id++);
+               cm_id->service_mask = __constant_cpu_to_be64(~0ULL);
        } else {
                cm_id->service_id = service_id;
                cm_id->service_mask = service_mask;
@@ -752,18 +754,19 @@ int ib_cm_listen(struct ib_cm_id *cm_id,
 }
 EXPORT_SYMBOL(ib_cm_listen);
 
-static u64 cm_form_tid(struct cm_id_private *cm_id_priv,
-                      enum cm_msg_sequence msg_seq)
+static __be64 cm_form_tid(struct cm_id_private *cm_id_priv,
+                         enum cm_msg_sequence msg_seq)
 {
        u64 hi_tid, low_tid;
 
        hi_tid   = ((u64) cm_id_priv->av.port->mad_agent->hi_tid) << 32;
-       low_tid  = (u64) (cm_id_priv->id.local_id | (msg_seq << 30));
+       low_tid  = (u64) ((__force u32)cm_id_priv->id.local_id |
+                         (msg_seq << 30));
        return cpu_to_be64(hi_tid | low_tid);
 }
 
 static void cm_format_mad_hdr(struct ib_mad_hdr *hdr,
-                             enum cm_msg_attr_id attr_id, u64 tid)
+                             __be16 attr_id, __be64 tid)
 {
        hdr->base_version  = IB_MGMT_BASE_VERSION;
        hdr->mgmt_class    = IB_MGMT_CLASS_CM;
@@ -896,7 +899,7 @@ int ib_send_cm_req(struct ib_cm_id *cm_id,
                        goto error1;
        }
        cm_id->service_id = param->service_id;
-       cm_id->service_mask = ~0ULL;
+       cm_id->service_mask = __constant_cpu_to_be64(~0ULL);
        cm_id_priv->timeout_ms = cm_convert_to_ms(
                                    param->primary_path->packet_life_time) * 2 +
                                 cm_convert_to_ms(
@@ -963,7 +966,7 @@ static int cm_issue_rej(struct cm_port *port,
        rej_msg->remote_comm_id = rcv_msg->local_comm_id;
        rej_msg->local_comm_id = rcv_msg->remote_comm_id;
        cm_rej_set_msg_rejected(rej_msg, msg_rejected);
-       rej_msg->reason = reason;
+       rej_msg->reason = cpu_to_be16(reason);
 
        if (ari && ari_length) {
                cm_rej_set_reject_info_len(rej_msg, ari_length);
@@ -977,8 +980,8 @@ static int cm_issue_rej(struct cm_port *port,
        return ret;
 }
 
-static inline int cm_is_active_peer(u64 local_ca_guid, u64 remote_ca_guid,
-                                   u32 local_qpn, u32 remote_qpn)
+static inline int cm_is_active_peer(__be64 local_ca_guid, __be64 remote_ca_guid,
+                                   __be32 local_qpn, __be32 remote_qpn)
 {
        return (be64_to_cpu(local_ca_guid) > be64_to_cpu(remote_ca_guid) ||
                ((local_ca_guid == remote_ca_guid) &&
@@ -1137,7 +1140,7 @@ static void cm_format_rej(struct cm_rej_msg *rej_msg,
                break;
        }
 
-       rej_msg->reason = reason;
+       rej_msg->reason = cpu_to_be16(reason);
        if (ari && ari_length) {
                cm_rej_set_reject_info_len(rej_msg, ari_length);
                memcpy(rej_msg->ari, ari, ari_length);
@@ -1276,7 +1279,7 @@ static int cm_req_handler(struct cm_work *work)
        cm_id_priv->id.cm_handler = listen_cm_id_priv->id.cm_handler;
        cm_id_priv->id.context = listen_cm_id_priv->id.context;
        cm_id_priv->id.service_id = req_msg->service_id;
-       cm_id_priv->id.service_mask = ~0ULL;
+       cm_id_priv->id.service_mask = __constant_cpu_to_be64(~0ULL);
 
        cm_format_paths_from_req(req_msg, &work->path[0], &work->path[1]);
        ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av);
@@ -1969,7 +1972,7 @@ static void cm_format_rej_event(struct cm_work *work)
        param = &work->cm_event.param.rej_rcvd;
        param->ari = rej_msg->ari;
        param->ari_length = cm_rej_get_reject_info_len(rej_msg);
-       param->reason = rej_msg->reason;
+       param->reason = __be16_to_cpu(rej_msg->reason);
        work->cm_event.private_data = &rej_msg->private_data;
 }
 
@@ -1978,20 +1981,20 @@ static struct cm_id_private * cm_acquire_rejected_id(struct cm_rej_msg *rej_msg)
        struct cm_timewait_info *timewait_info;
        struct cm_id_private *cm_id_priv;
        unsigned long flags;
-       u32 remote_id;
+       __be32 remote_id;
 
        remote_id = rej_msg->local_comm_id;
 
-       if (rej_msg->reason == IB_CM_REJ_TIMEOUT) {
+       if (__be16_to_cpu(rej_msg->reason) == IB_CM_REJ_TIMEOUT) {
                spin_lock_irqsave(&cm.lock, flags);
-               timewait_info = cm_find_remote_id( *((u64 *) rej_msg->ari),
+               timewait_info = cm_find_remote_id( *((__be64 *) rej_msg->ari),
                                                  remote_id);
                if (!timewait_info) {
                        spin_unlock_irqrestore(&cm.lock, flags);
                        return NULL;
                }
                cm_id_priv = idr_find(&cm.local_id_table,
-                                     (int) timewait_info->work.local_id);
+                                     (__force int) timewait_info->work.local_id);
                if (cm_id_priv) {
                        if (cm_id_priv->id.remote_id == remote_id)
                                atomic_inc(&cm_id_priv->refcount);
@@ -2032,7 +2035,7 @@ static int cm_rej_handler(struct cm_work *work)
                /* fall through */
        case IB_CM_REQ_RCVD:
        case IB_CM_MRA_REQ_SENT:
-               if (rej_msg->reason == IB_CM_REJ_STALE_CONN)
+               if (__be16_to_cpu(rej_msg->reason) == IB_CM_REJ_STALE_CONN)
                        cm_enter_timewait(cm_id_priv);
                else
                        cm_reset_to_idle(cm_id_priv);
@@ -2553,7 +2556,7 @@ static void cm_format_sidr_req(struct cm_sidr_req_msg *sidr_req_msg,
        cm_format_mad_hdr(&sidr_req_msg->hdr, CM_SIDR_REQ_ATTR_ID,
                          cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_SIDR));
        sidr_req_msg->request_id = cm_id_priv->id.local_id;
-       sidr_req_msg->pkey = param->pkey;
+       sidr_req_msg->pkey = cpu_to_be16(param->pkey);
        sidr_req_msg->service_id = param->service_id;
 
        if (param->private_data && param->private_data_len)
@@ -2580,7 +2583,7 @@ int ib_send_cm_sidr_req(struct ib_cm_id *cm_id,
                goto out;
 
        cm_id->service_id = param->service_id;
-       cm_id->service_mask = ~0ULL;
+       cm_id->service_mask = __constant_cpu_to_be64(~0ULL);
        cm_id_priv->timeout_ms = param->timeout_ms;
        cm_id_priv->max_cm_retries = param->max_cm_retries;
        ret = cm_alloc_msg(cm_id_priv, &msg);
@@ -2621,7 +2624,7 @@ static void cm_format_sidr_req_event(struct cm_work *work,
        sidr_req_msg = (struct cm_sidr_req_msg *)
                                work->mad_recv_wc->recv_buf.mad;
        param = &work->cm_event.param.sidr_req_rcvd;
-       param->pkey = sidr_req_msg->pkey;
+       param->pkey = __be16_to_cpu(sidr_req_msg->pkey);
        param->listen_id = listen_id;
        param->device = work->port->mad_agent->device;
        param->port = work->port->port_num;
@@ -2645,7 +2648,7 @@ static int cm_sidr_req_handler(struct cm_work *work)
        sidr_req_msg = (struct cm_sidr_req_msg *)
                                work->mad_recv_wc->recv_buf.mad;
        wc = work->mad_recv_wc->wc;
-       cm_id_priv->av.dgid.global.subnet_prefix = wc->slid;
+       cm_id_priv->av.dgid.global.subnet_prefix = cpu_to_be64(wc->slid);
        cm_id_priv->av.dgid.global.interface_id = 0;
        cm_init_av_for_response(work->port, work->mad_recv_wc->wc,
                                &cm_id_priv->av);
@@ -2673,7 +2676,7 @@ static int cm_sidr_req_handler(struct cm_work *work)
        cm_id_priv->id.cm_handler = cur_cm_id_priv->id.cm_handler;
        cm_id_priv->id.context = cur_cm_id_priv->id.context;
        cm_id_priv->id.service_id = sidr_req_msg->service_id;
-       cm_id_priv->id.service_mask = ~0ULL;
+       cm_id_priv->id.service_mask = __constant_cpu_to_be64(~0ULL);
 
        cm_format_sidr_req_event(work, &cur_cm_id_priv->id);
        cm_process_work(cm_id_priv, work);
@@ -3175,10 +3178,10 @@ int ib_cm_init_qp_attr(struct ib_cm_id *cm_id,
 }
 EXPORT_SYMBOL(ib_cm_init_qp_attr);
 
-static u64 cm_get_ca_guid(struct ib_device *device)
+static __be64 cm_get_ca_guid(struct ib_device *device)
 {
        struct ib_device_attr *device_attr;
-       u64 guid;
+       __be64 guid;
        int ret;
 
        device_attr = kmalloc(sizeof *device_attr, GFP_KERNEL);
index 15a309a77b2b675f65028b3fd3c485f6375204bb..813ab70bf6d5ebd5642bde4d499ce0cb911f81be 100644 (file)
@@ -34,7 +34,7 @@
 #if !defined(CM_MSGS_H)
 #define CM_MSGS_H
 
-#include <ib_mad.h>
+#include <rdma/ib_mad.h>
 
 /*
  * Parameters to routines below should be in network-byte order, and values
 
 #define IB_CM_CLASS_VERSION    2 /* IB specification 1.2 */
 
-enum cm_msg_attr_id {
-       CM_REQ_ATTR_ID      = __constant_htons(0x0010),
-       CM_MRA_ATTR_ID      = __constant_htons(0x0011),
-       CM_REJ_ATTR_ID      = __constant_htons(0x0012),
-       CM_REP_ATTR_ID      = __constant_htons(0x0013),
-       CM_RTU_ATTR_ID      = __constant_htons(0x0014),
-       CM_DREQ_ATTR_ID     = __constant_htons(0x0015),
-       CM_DREP_ATTR_ID     = __constant_htons(0x0016),
-       CM_SIDR_REQ_ATTR_ID = __constant_htons(0x0017),
-       CM_SIDR_REP_ATTR_ID = __constant_htons(0x0018),
-       CM_LAP_ATTR_ID      = __constant_htons(0x0019),
-       CM_APR_ATTR_ID      = __constant_htons(0x001A)
-};
+#define CM_REQ_ATTR_ID     __constant_htons(0x0010)
+#define CM_MRA_ATTR_ID     __constant_htons(0x0011)
+#define CM_REJ_ATTR_ID     __constant_htons(0x0012)
+#define CM_REP_ATTR_ID     __constant_htons(0x0013)
+#define CM_RTU_ATTR_ID     __constant_htons(0x0014)
+#define CM_DREQ_ATTR_ID            __constant_htons(0x0015)
+#define CM_DREP_ATTR_ID            __constant_htons(0x0016)
+#define CM_SIDR_REQ_ATTR_ID __constant_htons(0x0017)
+#define CM_SIDR_REP_ATTR_ID __constant_htons(0x0018)
+#define CM_LAP_ATTR_ID      __constant_htons(0x0019)
+#define CM_APR_ATTR_ID      __constant_htons(0x001A)
 
 enum cm_msg_sequence {
        CM_MSG_SEQUENCE_REQ,
@@ -67,35 +65,35 @@ enum cm_msg_sequence {
 struct cm_req_msg {
        struct ib_mad_hdr hdr;
 
-       u32 local_comm_id;
-       u32 rsvd4;
-       u64 service_id;
-       u64 local_ca_guid;
-       u32 rsvd24;
-       u32 local_qkey;
+       __be32 local_comm_id;
+       __be32 rsvd4;
+       __be64 service_id;
+       __be64 local_ca_guid;
+       __be32 rsvd24;
+       __be32 local_qkey;
        /* local QPN:24, responder resources:8 */
-       u32 offset32;
+       __be32 offset32;
        /* local EECN:24, initiator depth:8 */
-       u32 offset36;
+       __be32 offset36;
        /*
         * remote EECN:24, remote CM response timeout:5,
         * transport service type:2, end-to-end flow control:1
         */
-       u32 offset40;
+       __be32 offset40;
        /* starting PSN:24, local CM response timeout:5, retry count:3 */
-       u32 offset44;
-       u16 pkey;
+       __be32 offset44;
+       __be16 pkey;
        /* path MTU:4, RDC exists:1, RNR retry count:3. */
        u8 offset50;
        /* max CM Retries:4, SRQ:1, rsvd:3 */
        u8 offset51;
 
-       u16 primary_local_lid;
-       u16 primary_remote_lid;
+       __be16 primary_local_lid;
+       __be16 primary_remote_lid;
        union ib_gid primary_local_gid;
        union ib_gid primary_remote_gid;
        /* flow label:20, rsvd:6, packet rate:6 */
-       u32 primary_offset88;
+       __be32 primary_offset88;
        u8 primary_traffic_class;
        u8 primary_hop_limit;
        /* SL:4, subnet local:1, rsvd:3 */
@@ -103,12 +101,12 @@ struct cm_req_msg {
        /* local ACK timeout:5, rsvd:3 */
        u8 primary_offset95;
 
-       u16 alt_local_lid;
-       u16 alt_remote_lid;
+       __be16 alt_local_lid;
+       __be16 alt_remote_lid;
        union ib_gid alt_local_gid;
        union ib_gid alt_remote_gid;
        /* flow label:20, rsvd:6, packet rate:6 */
-       u32 alt_offset132;
+       __be32 alt_offset132;
        u8 alt_traffic_class;
        u8 alt_hop_limit;
        /* SL:4, subnet local:1, rsvd:3 */
@@ -120,12 +118,12 @@ struct cm_req_msg {
 
 } __attribute__ ((packed));
 
-static inline u32 cm_req_get_local_qpn(struct cm_req_msg *req_msg)
+static inline __be32 cm_req_get_local_qpn(struct cm_req_msg *req_msg)
 {
        return cpu_to_be32(be32_to_cpu(req_msg->offset32) >> 8);
 }
 
-static inline void cm_req_set_local_qpn(struct cm_req_msg *req_msg, u32 qpn)
+static inline void cm_req_set_local_qpn(struct cm_req_msg *req_msg, __be32 qpn)
 {
        req_msg->offset32 = cpu_to_be32((be32_to_cpu(qpn) << 8) |
                                         (be32_to_cpu(req_msg->offset32) &
@@ -208,13 +206,13 @@ static inline void cm_req_set_flow_ctrl(struct cm_req_msg *req_msg,
                                          0xFFFFFFFE));
 }
 
-static inline u32 cm_req_get_starting_psn(struct cm_req_msg *req_msg)
+static inline __be32 cm_req_get_starting_psn(struct cm_req_msg *req_msg)
 {
        return cpu_to_be32(be32_to_cpu(req_msg->offset44) >> 8);
 }
 
 static inline void cm_req_set_starting_psn(struct cm_req_msg *req_msg,
-                                          u32 starting_psn)
+                                          __be32 starting_psn)
 {
        req_msg->offset44 = cpu_to_be32((be32_to_cpu(starting_psn) << 8) |
                            (be32_to_cpu(req_msg->offset44) & 0x000000FF));
@@ -288,13 +286,13 @@ static inline void cm_req_set_srq(struct cm_req_msg *req_msg, u8 srq)
                                  ((srq & 0x1) << 3));
 }
 
-static inline u32 cm_req_get_primary_flow_label(struct cm_req_msg *req_msg)
+static inline __be32 cm_req_get_primary_flow_label(struct cm_req_msg *req_msg)
 {
-       return cpu_to_be32((be32_to_cpu(req_msg->primary_offset88) >> 12));
+       return cpu_to_be32(be32_to_cpu(req_msg->primary_offset88) >> 12);
 }
 
 static inline void cm_req_set_primary_flow_label(struct cm_req_msg *req_msg,
-                                                u32 flow_label)
+                                                __be32 flow_label)
 {
        req_msg->primary_offset88 = cpu_to_be32(
                                    (be32_to_cpu(req_msg->primary_offset88) &
@@ -350,13 +348,13 @@ static inline void cm_req_set_primary_local_ack_timeout(struct cm_req_msg *req_m
                                          (local_ack_timeout << 3));
 }
 
-static inline u32 cm_req_get_alt_flow_label(struct cm_req_msg *req_msg)
+static inline __be32 cm_req_get_alt_flow_label(struct cm_req_msg *req_msg)
 {
-       return cpu_to_be32((be32_to_cpu(req_msg->alt_offset132) >> 12));
+       return cpu_to_be32(be32_to_cpu(req_msg->alt_offset132) >> 12);
 }
 
 static inline void cm_req_set_alt_flow_label(struct cm_req_msg *req_msg,
-                                            u32 flow_label)
+                                            __be32 flow_label)
 {
        req_msg->alt_offset132 = cpu_to_be32(
                                 (be32_to_cpu(req_msg->alt_offset132) &
@@ -422,8 +420,8 @@ enum cm_msg_response {
  struct cm_mra_msg {
        struct ib_mad_hdr hdr;
 
-       u32 local_comm_id;
-       u32 remote_comm_id;
+       __be32 local_comm_id;
+       __be32 remote_comm_id;
        /* message MRAed:2, rsvd:6 */
        u8 offset8;
        /* service timeout:5, rsvd:3 */
@@ -458,13 +456,13 @@ static inline void cm_mra_set_service_timeout(struct cm_mra_msg *mra_msg,
 struct cm_rej_msg {
        struct ib_mad_hdr hdr;
 
-       u32 local_comm_id;
-       u32 remote_comm_id;
+       __be32 local_comm_id;
+       __be32 remote_comm_id;
        /* message REJected:2, rsvd:6 */
        u8 offset8;
        /* reject info length:7, rsvd:1. */
        u8 offset9;
-       u16 reason;
+       __be16 reason;
        u8 ari[IB_CM_REJ_ARI_LENGTH];
 
        u8 private_data[IB_CM_REJ_PRIVATE_DATA_SIZE];
@@ -495,45 +493,45 @@ static inline void cm_rej_set_reject_info_len(struct cm_rej_msg *rej_msg,
 struct cm_rep_msg {
        struct ib_mad_hdr hdr;
 
-       u32 local_comm_id;
-       u32 remote_comm_id;
-       u32 local_qkey;
+       __be32 local_comm_id;
+       __be32 remote_comm_id;
+       __be32 local_qkey;
        /* local QPN:24, rsvd:8 */
-       u32 offset12;
+       __be32 offset12;
        /* local EECN:24, rsvd:8 */
-       u32 offset16;
+       __be32 offset16;
        /* starting PSN:24 rsvd:8 */
-       u32 offset20;
+       __be32 offset20;
        u8 resp_resources;
        u8 initiator_depth;
        /* target ACK delay:5, failover accepted:2, end-to-end flow control:1 */
        u8 offset26;
        /* RNR retry count:3, SRQ:1, rsvd:5 */
        u8 offset27;
-       u64 local_ca_guid;
+       __be64 local_ca_guid;
 
        u8 private_data[IB_CM_REP_PRIVATE_DATA_SIZE];
 
 } __attribute__ ((packed));
 
-static inline u32 cm_rep_get_local_qpn(struct cm_rep_msg *rep_msg)
+static inline __be32 cm_rep_get_local_qpn(struct cm_rep_msg *rep_msg)
 {
        return cpu_to_be32(be32_to_cpu(rep_msg->offset12) >> 8);
 }
 
-static inline void cm_rep_set_local_qpn(struct cm_rep_msg *rep_msg, u32 qpn)
+static inline void cm_rep_set_local_qpn(struct cm_rep_msg *rep_msg, __be32 qpn)
 {
        rep_msg->offset12 = cpu_to_be32((be32_to_cpu(qpn) << 8) |
                            (be32_to_cpu(rep_msg->offset12) & 0x000000FF));
 }
 
-static inline u32 cm_rep_get_starting_psn(struct cm_rep_msg *rep_msg)
+static inline __be32 cm_rep_get_starting_psn(struct cm_rep_msg *rep_msg)
 {
        return cpu_to_be32(be32_to_cpu(rep_msg->offset20) >> 8);
 }
 
 static inline void cm_rep_set_starting_psn(struct cm_rep_msg *rep_msg,
-                                          u32 starting_psn)
+                                          __be32 starting_psn)
 {
        rep_msg->offset20 = cpu_to_be32((be32_to_cpu(starting_psn) << 8) |
                            (be32_to_cpu(rep_msg->offset20) & 0x000000FF));
@@ -600,8 +598,8 @@ static inline void cm_rep_set_srq(struct cm_rep_msg *rep_msg, u8 srq)
 struct cm_rtu_msg {
        struct ib_mad_hdr hdr;
 
-       u32 local_comm_id;
-       u32 remote_comm_id;
+       __be32 local_comm_id;
+       __be32 remote_comm_id;
 
        u8 private_data[IB_CM_RTU_PRIVATE_DATA_SIZE];
 
@@ -610,21 +608,21 @@ struct cm_rtu_msg {
 struct cm_dreq_msg {
        struct ib_mad_hdr hdr;
 
-       u32 local_comm_id;
-       u32 remote_comm_id;
+       __be32 local_comm_id;
+       __be32 remote_comm_id;
        /* remote QPN/EECN:24, rsvd:8 */
-       u32 offset8;
+       __be32 offset8;
 
        u8 private_data[IB_CM_DREQ_PRIVATE_DATA_SIZE];
 
 } __attribute__ ((packed));
 
-static inline u32 cm_dreq_get_remote_qpn(struct cm_dreq_msg *dreq_msg)
+static inline __be32 cm_dreq_get_remote_qpn(struct cm_dreq_msg *dreq_msg)
 {
        return cpu_to_be32(be32_to_cpu(dreq_msg->offset8) >> 8);
 }
 
-static inline void cm_dreq_set_remote_qpn(struct cm_dreq_msg *dreq_msg, u32 qpn)
+static inline void cm_dreq_set_remote_qpn(struct cm_dreq_msg *dreq_msg, __be32 qpn)
 {
        dreq_msg->offset8 = cpu_to_be32((be32_to_cpu(qpn) << 8) |
                            (be32_to_cpu(dreq_msg->offset8) & 0x000000FF));
@@ -633,8 +631,8 @@ static inline void cm_dreq_set_remote_qpn(struct cm_dreq_msg *dreq_msg, u32 qpn)
 struct cm_drep_msg {
        struct ib_mad_hdr hdr;
 
-       u32 local_comm_id;
-       u32 remote_comm_id;
+       __be32 local_comm_id;
+       __be32 remote_comm_id;
 
        u8 private_data[IB_CM_DREP_PRIVATE_DATA_SIZE];
 
@@ -643,37 +641,37 @@ struct cm_drep_msg {
 struct cm_lap_msg {
        struct ib_mad_hdr hdr;
 
-       u32 local_comm_id;
-       u32 remote_comm_id;
+       __be32 local_comm_id;
+       __be32 remote_comm_id;
 
-       u32 rsvd8;
+       __be32 rsvd8;
        /* remote QPN/EECN:24, remote CM response timeout:5, rsvd:3 */
-       u32 offset12;
-       u32 rsvd16;
+       __be32 offset12;
+       __be32 rsvd16;
 
-       u16 alt_local_lid;
-       u16 alt_remote_lid;
+       __be16 alt_local_lid;
+       __be16 alt_remote_lid;
        union ib_gid alt_local_gid;
        union ib_gid alt_remote_gid;
        /* flow label:20, rsvd:4, traffic class:8 */
-       u32 offset56;
+       __be32 offset56;
        u8 alt_hop_limit;
        /* rsvd:2, packet rate:6 */
-       uint8_t offset61;
+       u8 offset61;
        /* SL:4, subnet local:1, rsvd:3 */
-       uint8_t offset62;
+       u8 offset62;
        /* local ACK timeout:5, rsvd:3 */
-       uint8_t offset63;
+       u8 offset63;
 
        u8 private_data[IB_CM_LAP_PRIVATE_DATA_SIZE];
 } __attribute__  ((packed));
 
-static inline u32 cm_lap_get_remote_qpn(struct cm_lap_msg *lap_msg)
+static inline __be32 cm_lap_get_remote_qpn(struct cm_lap_msg *lap_msg)
 {
        return cpu_to_be32(be32_to_cpu(lap_msg->offset12) >> 8);
 }
 
-static inline void cm_lap_set_remote_qpn(struct cm_lap_msg *lap_msg, u32 qpn)
+static inline void cm_lap_set_remote_qpn(struct cm_lap_msg *lap_msg, __be32 qpn)
 {
        lap_msg->offset12 = cpu_to_be32((be32_to_cpu(qpn) << 8) |
                                         (be32_to_cpu(lap_msg->offset12) &
@@ -693,17 +691,17 @@ static inline void cm_lap_set_remote_resp_timeout(struct cm_lap_msg *lap_msg,
                                          0xFFFFFF07));
 }
 
-static inline u32 cm_lap_get_flow_label(struct cm_lap_msg *lap_msg)
+static inline __be32 cm_lap_get_flow_label(struct cm_lap_msg *lap_msg)
 {
-       return be32_to_cpu(lap_msg->offset56) >> 12;
+       return cpu_to_be32(be32_to_cpu(lap_msg->offset56) >> 12);
 }
 
 static inline void cm_lap_set_flow_label(struct cm_lap_msg *lap_msg,
-                                        u32 flow_label)
+                                        __be32 flow_label)
 {
-       lap_msg->offset56 = cpu_to_be32((flow_label << 12) |
-                                        (be32_to_cpu(lap_msg->offset56) &
-                                         0x00000FFF));
+       lap_msg->offset56 = cpu_to_be32(
+                                (be32_to_cpu(lap_msg->offset56) & 0x00000FFF) |
+                                (be32_to_cpu(flow_label) << 12));
 }
 
 static inline u8 cm_lap_get_traffic_class(struct cm_lap_msg *lap_msg)
@@ -766,8 +764,8 @@ static inline void cm_lap_set_local_ack_timeout(struct cm_lap_msg *lap_msg,
 struct cm_apr_msg {
        struct ib_mad_hdr hdr;
 
-       u32 local_comm_id;
-       u32 remote_comm_id;
+       __be32 local_comm_id;
+       __be32 remote_comm_id;
 
        u8 info_length;
        u8 ap_status;
@@ -779,10 +777,10 @@ struct cm_apr_msg {
 struct cm_sidr_req_msg {
        struct ib_mad_hdr hdr;
 
-       u32 request_id;
-       u16 pkey;
-       u16 rsvd;
-       u64 service_id;
+       __be32 request_id;
+       __be16 pkey;
+       __be16 rsvd;
+       __be64 service_id;
 
        u8 private_data[IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE];
 } __attribute__ ((packed));
@@ -790,26 +788,26 @@ struct cm_sidr_req_msg {
 struct cm_sidr_rep_msg {
        struct ib_mad_hdr hdr;
 
-       u32 request_id;
+       __be32 request_id;
        u8 status;
        u8 info_length;
-       u16 rsvd;
+       __be16 rsvd;
        /* QPN:24, rsvd:8 */
-       u32 offset8;
-       u64 service_id;
-       u32 qkey;
+       __be32 offset8;
+       __be64 service_id;
+       __be32 qkey;
        u8 info[IB_CM_SIDR_REP_INFO_LENGTH];
 
        u8 private_data[IB_CM_SIDR_REP_PRIVATE_DATA_SIZE];
 } __attribute__ ((packed));
 
-static inline u32 cm_sidr_rep_get_qpn(struct cm_sidr_rep_msg *sidr_rep_msg)
+static inline __be32 cm_sidr_rep_get_qpn(struct cm_sidr_rep_msg *sidr_rep_msg)
 {
        return cpu_to_be32(be32_to_cpu(sidr_rep_msg->offset8) >> 8);
 }
 
 static inline void cm_sidr_rep_set_qpn(struct cm_sidr_rep_msg *sidr_rep_msg,
-                                      u32 qpn)
+                                      __be32 qpn)
 {
        sidr_rep_msg->offset8 = cpu_to_be32((be32_to_cpu(qpn) << 8) |
                                        (be32_to_cpu(sidr_rep_msg->offset8) &
index 797049626ff67b49fa7e678b44f0f98018223de8..7ad47a4b166b2bfbd35e5f8359b80827637c8e80 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 
-#include <ib_verbs.h>
+#include <rdma/ib_verbs.h>
 
 int  ib_device_register_sysfs(struct ib_device *device);
 void ib_device_unregister_sysfs(struct ib_device *device);
index 9197e92d708a1208230edcfb2750bdec9caf7214..d3cf84e01587176bdfaa26926abbc0c8c6c63ae1 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
index 7763b31abba70b61f8d2c1557b98f1cd2c2c06d6..d34a6f1c4f4c53a48c2d6ea401ccf5bfcdfa61e0 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/jhash.h>
 #include <linux/kthread.h>
 
-#include <ib_fmr_pool.h>
+#include <rdma/ib_fmr_pool.h>
 
 #include "core_priv.h"
 
@@ -334,6 +334,7 @@ void ib_destroy_fmr_pool(struct ib_fmr_pool *pool)
 {
        struct ib_pool_fmr *fmr;
        struct ib_pool_fmr *tmp;
+       LIST_HEAD(fmr_list);
        int                 i;
 
        kthread_stop(pool->thread);
@@ -341,6 +342,11 @@ void ib_destroy_fmr_pool(struct ib_fmr_pool *pool)
 
        i = 0;
        list_for_each_entry_safe(fmr, tmp, &pool->free_list, list) {
+               if (fmr->remap_count) {
+                       INIT_LIST_HEAD(&fmr_list);
+                       list_add_tail(&fmr->fmr->list, &fmr_list);
+                       ib_unmap_fmr(&fmr_list);
+               }
                ib_dealloc_fmr(fmr->fmr);
                list_del(&fmr->list);
                kfree(fmr);
index b97e210ce9c81ff16e7bc3ee47abbb58a54607dd..a4a4d9c1eef3ebb70603441d81f418898bb9cfa8 100644 (file)
@@ -693,7 +693,8 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
                goto out;
        }
 
-       build_smp_wc(send_wr->wr_id, smp->dr_slid, send_wr->wr.ud.pkey_index,
+       build_smp_wc(send_wr->wr_id, be16_to_cpu(smp->dr_slid),
+                    send_wr->wr.ud.pkey_index,
                     send_wr->wr.ud.port_num, &mad_wc);
 
        /* No GRH for DR SMP */
@@ -1554,7 +1555,7 @@ static int is_data_mad(struct ib_mad_agent_private *mad_agent_priv,
 }
 
 struct ib_mad_send_wr_private*
-ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, u64 tid)
+ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, __be64 tid)
 {
        struct ib_mad_send_wr_private *mad_send_wr;
 
@@ -1597,7 +1598,7 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
        struct ib_mad_send_wr_private *mad_send_wr;
        struct ib_mad_send_wc mad_send_wc;
        unsigned long flags;
-       u64 tid;
+       __be64 tid;
 
        INIT_LIST_HEAD(&mad_recv_wc->rmpp_list);
        list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list);
@@ -2165,7 +2166,8 @@ static void local_completions(void *data)
                         * Defined behavior is to complete response
                         * before request
                         */
-                       build_smp_wc(local->wr_id, IB_LID_PERMISSIVE,
+                       build_smp_wc(local->wr_id,
+                                    be16_to_cpu(IB_LID_PERMISSIVE),
                                     0 /* pkey index */,
                                     recv_mad_agent->agent.port_num, &wc);
 
@@ -2294,7 +2296,7 @@ static void timeout_sends(void *data)
        spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
 }
 
-static void ib_mad_thread_completion_handler(struct ib_cq *cq)
+static void ib_mad_thread_completion_handler(struct ib_cq *cq, void *arg)
 {
        struct ib_mad_port_private *port_priv = cq->cq_context;
 
@@ -2574,8 +2576,7 @@ static int ib_mad_port_open(struct ib_device *device,
 
        cq_size = (IB_MAD_QP_SEND_SIZE + IB_MAD_QP_RECV_SIZE) * 2;
        port_priv->cq = ib_create_cq(port_priv->device,
-                                    (ib_comp_handler)
-                                       ib_mad_thread_completion_handler,
+                                    ib_mad_thread_completion_handler,
                                     NULL, port_priv, cq_size);
        if (IS_ERR(port_priv->cq)) {
                printk(KERN_ERR PFX "Couldn't create ib_mad CQ\n");
index 568da10b05ab28675dff4697ac35dd2f9cd51282..f1ba794e0daa62a3dea35bfc7d2b0f232449af7e 100644 (file)
@@ -40,8 +40,8 @@
 #include <linux/pci.h>
 #include <linux/kthread.h>
 #include <linux/workqueue.h>
-#include <ib_mad.h>
-#include <ib_smi.h>
+#include <rdma/ib_mad.h>
+#include <rdma/ib_smi.h>
 
 
 #define PFX "ib_mad: "
@@ -121,7 +121,7 @@ struct ib_mad_send_wr_private {
        struct ib_send_wr send_wr;
        struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG];
        u64 wr_id;                      /* client WR ID */
-       u64 tid;
+       __be64 tid;
        unsigned long timeout;
        int retries;
        int retry;
@@ -144,7 +144,7 @@ struct ib_mad_local_private {
        struct ib_send_wr send_wr;
        struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG];
        u64 wr_id;                      /* client WR ID */
-       u64 tid;
+       __be64 tid;
 };
 
 struct ib_mad_mgmt_method_table {
@@ -210,7 +210,7 @@ extern kmem_cache_t *ib_mad_cache;
 int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr);
 
 struct ib_mad_send_wr_private *
-ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, u64 tid);
+ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, __be64 tid);
 
 void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr,
                             struct ib_mad_send_wc *mad_send_wc);
index 8f1eb80e421f12e7d763267e59df4bf64c459c99..43fd805e02659ce6f81befac85696c34f47beb9f 100644 (file)
@@ -61,7 +61,7 @@ struct mad_rmpp_recv {
        int seg_num;
        int newwin;
 
-       u64 tid;
+       __be64 tid;
        u32 src_qp;
        u16 slid;
        u8 mgmt_class;
@@ -100,6 +100,121 @@ void ib_cancel_rmpp_recvs(struct ib_mad_agent_private *agent)
        }
 }
 
+static int data_offset(u8 mgmt_class)
+{
+       if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM)
+               return offsetof(struct ib_sa_mad, data);
+       else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
+                (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END))
+               return offsetof(struct ib_vendor_mad, data);
+       else
+               return offsetof(struct ib_rmpp_mad, data);
+}
+
+static void format_ack(struct ib_rmpp_mad *ack,
+                      struct ib_rmpp_mad *data,
+                      struct mad_rmpp_recv *rmpp_recv)
+{
+       unsigned long flags;
+
+       memcpy(&ack->mad_hdr, &data->mad_hdr,
+              data_offset(data->mad_hdr.mgmt_class));
+
+       ack->mad_hdr.method ^= IB_MGMT_METHOD_RESP;
+       ack->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_ACK;
+       ib_set_rmpp_flags(&ack->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);
+
+       spin_lock_irqsave(&rmpp_recv->lock, flags);
+       rmpp_recv->last_ack = rmpp_recv->seg_num;
+       ack->rmpp_hdr.seg_num = cpu_to_be32(rmpp_recv->seg_num);
+       ack->rmpp_hdr.paylen_newwin = cpu_to_be32(rmpp_recv->newwin);
+       spin_unlock_irqrestore(&rmpp_recv->lock, flags);
+}
+
+static void ack_recv(struct mad_rmpp_recv *rmpp_recv,
+                    struct ib_mad_recv_wc *recv_wc)
+{
+       struct ib_mad_send_buf *msg;
+       struct ib_send_wr *bad_send_wr;
+       int hdr_len, ret;
+
+       hdr_len = sizeof(struct ib_mad_hdr) + sizeof(struct ib_rmpp_hdr);
+       msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp,
+                                recv_wc->wc->pkey_index, rmpp_recv->ah, 1,
+                                hdr_len, sizeof(struct ib_rmpp_mad) - hdr_len,
+                                GFP_KERNEL);
+       if (!msg)
+               return;
+
+       format_ack((struct ib_rmpp_mad *) msg->mad,
+                  (struct ib_rmpp_mad *) recv_wc->recv_buf.mad, rmpp_recv);
+       ret = ib_post_send_mad(&rmpp_recv->agent->agent, &msg->send_wr,
+                              &bad_send_wr);
+       if (ret)
+               ib_free_send_mad(msg);
+}
+
+static int alloc_response_msg(struct ib_mad_agent *agent,
+                             struct ib_mad_recv_wc *recv_wc,
+                             struct ib_mad_send_buf **msg)
+{
+       struct ib_mad_send_buf *m;
+       struct ib_ah *ah;
+       int hdr_len;
+
+       ah = ib_create_ah_from_wc(agent->qp->pd, recv_wc->wc,
+                                 recv_wc->recv_buf.grh, agent->port_num);
+       if (IS_ERR(ah))
+               return PTR_ERR(ah);
+
+       hdr_len = sizeof(struct ib_mad_hdr) + sizeof(struct ib_rmpp_hdr);
+       m = ib_create_send_mad(agent, recv_wc->wc->src_qp,
+                              recv_wc->wc->pkey_index, ah, 1, hdr_len,
+                              sizeof(struct ib_rmpp_mad) - hdr_len,
+                              GFP_KERNEL);
+       if (IS_ERR(m)) {
+               ib_destroy_ah(ah);
+               return PTR_ERR(m);
+       }
+       *msg = m;
+       return 0;
+}
+
+static void free_msg(struct ib_mad_send_buf *msg)
+{
+       ib_destroy_ah(msg->send_wr.wr.ud.ah);
+       ib_free_send_mad(msg);
+}
+
+static void nack_recv(struct ib_mad_agent_private *agent,
+                     struct ib_mad_recv_wc *recv_wc, u8 rmpp_status)
+{
+       struct ib_mad_send_buf *msg;
+       struct ib_rmpp_mad *rmpp_mad;
+       struct ib_send_wr *bad_send_wr;
+       int ret;
+
+       ret = alloc_response_msg(&agent->agent, recv_wc, &msg);
+       if (ret)
+               return;
+
+       rmpp_mad = (struct ib_rmpp_mad *) msg->mad;
+       memcpy(rmpp_mad, recv_wc->recv_buf.mad,
+              data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class));
+
+       rmpp_mad->mad_hdr.method ^= IB_MGMT_METHOD_RESP;
+       rmpp_mad->rmpp_hdr.rmpp_version = IB_MGMT_RMPP_VERSION;
+       rmpp_mad->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_ABORT;
+       ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);
+       rmpp_mad->rmpp_hdr.rmpp_status = rmpp_status;
+       rmpp_mad->rmpp_hdr.seg_num = 0;
+       rmpp_mad->rmpp_hdr.paylen_newwin = 0;
+
+       ret = ib_post_send_mad(&agent->agent, &msg->send_wr, &bad_send_wr);
+       if (ret)
+               free_msg(msg);
+}
+
 static void recv_timeout_handler(void *data)
 {
        struct mad_rmpp_recv *rmpp_recv = data;
@@ -115,8 +230,8 @@ static void recv_timeout_handler(void *data)
        list_del(&rmpp_recv->list);
        spin_unlock_irqrestore(&rmpp_recv->agent->lock, flags);
 
-       /* TODO: send abort. */
        rmpp_wc = rmpp_recv->rmpp_wc;
+       nack_recv(rmpp_recv->agent, rmpp_wc, IB_MGMT_RMPP_STATUS_T2L);
        destroy_rmpp_recv(rmpp_recv);
        ib_free_recv_mad(rmpp_wc);
 }
@@ -230,60 +345,6 @@ insert_rmpp_recv(struct ib_mad_agent_private *agent,
        return cur_rmpp_recv;
 }
 
-static int data_offset(u8 mgmt_class)
-{
-       if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM)
-               return offsetof(struct ib_sa_mad, data);
-       else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
-                (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END))
-               return offsetof(struct ib_vendor_mad, data);
-       else
-               return offsetof(struct ib_rmpp_mad, data);
-}
-
-static void format_ack(struct ib_rmpp_mad *ack,
-                      struct ib_rmpp_mad *data,
-                      struct mad_rmpp_recv *rmpp_recv)
-{
-       unsigned long flags;
-
-       memcpy(&ack->mad_hdr, &data->mad_hdr,
-              data_offset(data->mad_hdr.mgmt_class));
-
-       ack->mad_hdr.method ^= IB_MGMT_METHOD_RESP;
-       ack->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_ACK;
-       ib_set_rmpp_flags(&ack->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);
-
-       spin_lock_irqsave(&rmpp_recv->lock, flags);
-       rmpp_recv->last_ack = rmpp_recv->seg_num;
-       ack->rmpp_hdr.seg_num = cpu_to_be32(rmpp_recv->seg_num);
-       ack->rmpp_hdr.paylen_newwin = cpu_to_be32(rmpp_recv->newwin);
-       spin_unlock_irqrestore(&rmpp_recv->lock, flags);
-}
-
-static void ack_recv(struct mad_rmpp_recv *rmpp_recv,
-                    struct ib_mad_recv_wc *recv_wc)
-{
-       struct ib_mad_send_buf *msg;
-       struct ib_send_wr *bad_send_wr;
-       int hdr_len, ret;
-
-       hdr_len = sizeof(struct ib_mad_hdr) + sizeof(struct ib_rmpp_hdr);
-       msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp,
-                                recv_wc->wc->pkey_index, rmpp_recv->ah, 1,
-                                hdr_len, sizeof(struct ib_rmpp_mad) - hdr_len,
-                                GFP_KERNEL);
-       if (!msg)
-               return;
-
-       format_ack((struct ib_rmpp_mad *) msg->mad,
-                  (struct ib_rmpp_mad *) recv_wc->recv_buf.mad, rmpp_recv);
-       ret = ib_post_send_mad(&rmpp_recv->agent->agent, &msg->send_wr,
-                              &bad_send_wr);
-       if (ret)
-               ib_free_send_mad(msg);
-}
-
 static inline int get_last_flag(struct ib_mad_recv_buf *seg)
 {
        struct ib_rmpp_mad *rmpp_mad;
@@ -559,6 +620,34 @@ static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr)
        return ib_send_mad(mad_send_wr);
 }
 
+static void abort_send(struct ib_mad_agent_private *agent, __be64 tid,
+                      u8 rmpp_status)
+{
+       struct ib_mad_send_wr_private *mad_send_wr;
+       struct ib_mad_send_wc wc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&agent->lock, flags);
+       mad_send_wr = ib_find_send_mad(agent, tid);
+       if (!mad_send_wr)
+               goto out;       /* Unmatched send */
+
+       if ((mad_send_wr->last_ack == mad_send_wr->total_seg) ||
+           (!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS))
+               goto out;       /* Send is already done */
+
+       ib_mark_mad_done(mad_send_wr);
+       spin_unlock_irqrestore(&agent->lock, flags);
+
+       wc.status = IB_WC_REM_ABORT_ERR;
+       wc.vendor_err = rmpp_status;
+       wc.wr_id = mad_send_wr->wr_id;
+       ib_mad_complete_send_wr(mad_send_wr, &wc);
+       return;
+out:
+       spin_unlock_irqrestore(&agent->lock, flags);
+}
+
 static void process_rmpp_ack(struct ib_mad_agent_private *agent,
                             struct ib_mad_recv_wc *mad_recv_wc)
 {
@@ -568,11 +657,21 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
        int seg_num, newwin, ret;
 
        rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;
-       if (rmpp_mad->rmpp_hdr.rmpp_status)
+       if (rmpp_mad->rmpp_hdr.rmpp_status) {
+               abort_send(agent, rmpp_mad->mad_hdr.tid,
+                          IB_MGMT_RMPP_STATUS_BAD_STATUS);
+               nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
                return;
+       }
 
        seg_num = be32_to_cpu(rmpp_mad->rmpp_hdr.seg_num);
        newwin = be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin);
+       if (newwin < seg_num) {
+               abort_send(agent, rmpp_mad->mad_hdr.tid,
+                          IB_MGMT_RMPP_STATUS_W2S);
+               nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_W2S);
+               return;
+       }
 
        spin_lock_irqsave(&agent->lock, flags);
        mad_send_wr = ib_find_send_mad(agent, rmpp_mad->mad_hdr.tid);
@@ -583,8 +682,13 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
            (!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS))
                goto out;       /* Send is already done */
 
-       if (seg_num > mad_send_wr->total_seg)
-               goto out;       /* Bad ACK */
+       if (seg_num > mad_send_wr->total_seg || seg_num > mad_send_wr->newwin) {
+               spin_unlock_irqrestore(&agent->lock, flags);
+               abort_send(agent, rmpp_mad->mad_hdr.tid,
+                          IB_MGMT_RMPP_STATUS_S2B);
+               nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_S2B);
+               return;
+       }
 
        if (newwin < mad_send_wr->newwin || seg_num < mad_send_wr->last_ack)
                goto out;       /* Old ACK */
@@ -628,6 +732,72 @@ out:
        spin_unlock_irqrestore(&agent->lock, flags);
 }
 
+static struct ib_mad_recv_wc *
+process_rmpp_data(struct ib_mad_agent_private *agent,
+                 struct ib_mad_recv_wc *mad_recv_wc)
+{
+       struct ib_rmpp_hdr *rmpp_hdr;
+       u8 rmpp_status;
+
+       rmpp_hdr = &((struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad)->rmpp_hdr;
+
+       if (rmpp_hdr->rmpp_status) {
+               rmpp_status = IB_MGMT_RMPP_STATUS_BAD_STATUS;
+               goto bad;
+       }
+
+       if (rmpp_hdr->seg_num == __constant_htonl(1)) {
+               if (!(ib_get_rmpp_flags(rmpp_hdr) & IB_MGMT_RMPP_FLAG_FIRST)) {
+                       rmpp_status = IB_MGMT_RMPP_STATUS_BAD_SEG;
+                       goto bad;
+               }
+               return start_rmpp(agent, mad_recv_wc);
+       } else {
+               if (ib_get_rmpp_flags(rmpp_hdr) & IB_MGMT_RMPP_FLAG_FIRST) {
+                       rmpp_status = IB_MGMT_RMPP_STATUS_BAD_SEG;
+                       goto bad;
+               }
+               return continue_rmpp(agent, mad_recv_wc);
+       }
+bad:
+       nack_recv(agent, mad_recv_wc, rmpp_status);
+       ib_free_recv_mad(mad_recv_wc);
+       return NULL;
+}
+
+static void process_rmpp_stop(struct ib_mad_agent_private *agent,
+                             struct ib_mad_recv_wc *mad_recv_wc)
+{
+       struct ib_rmpp_mad *rmpp_mad;
+
+       rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;
+
+       if (rmpp_mad->rmpp_hdr.rmpp_status != IB_MGMT_RMPP_STATUS_RESX) {
+               abort_send(agent, rmpp_mad->mad_hdr.tid,
+                          IB_MGMT_RMPP_STATUS_BAD_STATUS);
+               nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
+       } else
+               abort_send(agent, rmpp_mad->mad_hdr.tid,
+                          rmpp_mad->rmpp_hdr.rmpp_status);
+}
+
+static void process_rmpp_abort(struct ib_mad_agent_private *agent,
+                              struct ib_mad_recv_wc *mad_recv_wc)
+{
+       struct ib_rmpp_mad *rmpp_mad;
+
+       rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;
+
+       if (rmpp_mad->rmpp_hdr.rmpp_status < IB_MGMT_RMPP_STATUS_ABORT_MIN ||
+           rmpp_mad->rmpp_hdr.rmpp_status > IB_MGMT_RMPP_STATUS_ABORT_MAX) {
+               abort_send(agent, rmpp_mad->mad_hdr.tid,
+                          IB_MGMT_RMPP_STATUS_BAD_STATUS);
+               nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
+       } else
+               abort_send(agent, rmpp_mad->mad_hdr.tid,
+                          rmpp_mad->rmpp_hdr.rmpp_status);
+}
+
 struct ib_mad_recv_wc *
 ib_process_rmpp_recv_wc(struct ib_mad_agent_private *agent,
                        struct ib_mad_recv_wc *mad_recv_wc)
@@ -638,23 +808,29 @@ ib_process_rmpp_recv_wc(struct ib_mad_agent_private *agent,
        if (!(rmpp_mad->rmpp_hdr.rmpp_rtime_flags & IB_MGMT_RMPP_FLAG_ACTIVE))
                return mad_recv_wc;
 
-       if (rmpp_mad->rmpp_hdr.rmpp_version != IB_MGMT_RMPP_VERSION)
+       if (rmpp_mad->rmpp_hdr.rmpp_version != IB_MGMT_RMPP_VERSION) {
+               abort_send(agent, rmpp_mad->mad_hdr.tid,
+                          IB_MGMT_RMPP_STATUS_UNV);
+               nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_UNV);
                goto out;
+       }
 
        switch (rmpp_mad->rmpp_hdr.rmpp_type) {
        case IB_MGMT_RMPP_TYPE_DATA:
-               if (rmpp_mad->rmpp_hdr.seg_num == __constant_htonl(1))
-                       return start_rmpp(agent, mad_recv_wc);
-               else
-                       return continue_rmpp(agent, mad_recv_wc);
+               return process_rmpp_data(agent, mad_recv_wc);
        case IB_MGMT_RMPP_TYPE_ACK:
                process_rmpp_ack(agent, mad_recv_wc);
                break;
        case IB_MGMT_RMPP_TYPE_STOP:
+               process_rmpp_stop(agent, mad_recv_wc);
+               break;
        case IB_MGMT_RMPP_TYPE_ABORT:
-               /* TODO: process_rmpp_nack(agent, mad_recv_wc); */
+               process_rmpp_abort(agent, mad_recv_wc);
                break;
        default:
+               abort_send(agent, rmpp_mad->mad_hdr.tid,
+                          IB_MGMT_RMPP_STATUS_BADT);
+               nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BADT);
                break;
        }
 out:
@@ -714,7 +890,10 @@ int ib_process_rmpp_send_wc(struct ib_mad_send_wr_private *mad_send_wr,
        if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA) {
                msg = (struct ib_mad_send_buf *) (unsigned long)
                      mad_send_wc->wr_id;
-               ib_free_send_mad(msg);
+               if (rmpp_mad->rmpp_hdr.rmpp_type == IB_MGMT_RMPP_TYPE_ACK)
+                       ib_free_send_mad(msg);
+               else
+                       free_msg(msg);
                return IB_RMPP_RESULT_INTERNAL;  /* ACK, STOP, or ABORT */
        }
 
index eb5ff54c10d75e758088f2e594167a18a4f3fabc..35df5010e723ecf9d466f0a27fd33f51bfe80e86 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -32,7 +33,7 @@
  * $Id: packer.c 1349 2004-12-16 21:09:43Z roland $
  */
 
-#include <ib_pack.h>
+#include <rdma/ib_pack.h>
 
 static u64 value_read(int offset, int size, void *structure)
 {
index 795184931c83e84318a34c0dc188db4bf6a957d6..126ac80db7b84f3e71b83211188b8b8024e07912 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Voltaire, Inc.  All rights reserved.
+ * Copyright (c) 2005 Voltaire, Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -44,8 +44,8 @@
 #include <linux/kref.h>
 #include <linux/idr.h>
 
-#include <ib_pack.h>
-#include <ib_sa.h>
+#include <rdma/ib_pack.h>
+#include <rdma/ib_sa.h>
 
 MODULE_AUTHOR("Roland Dreier");
 MODULE_DESCRIPTION("InfiniBand subnet administration query support");
index b4b284324a33a5be9356dd1f01ba1dae71b70889..35852e794e26533aa61c8c8fe3900c3b5d372eee 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2004 Mellanox Technologies Ltd.  All rights reserved.
- * Copyright (c) 2004 Infinicon Corporation.  All rights reserved.
- * Copyright (c) 2004 Intel Corporation.  All rights reserved.
- * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
- * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
+ * Copyright (c) 2004, 2005 Mellanox Technologies Ltd.  All rights reserved.
+ * Copyright (c) 2004, 2005 Infinicon Corporation.  All rights reserved.
+ * Copyright (c) 2004, 2005 Intel Corporation.  All rights reserved.
+ * Copyright (c) 2004, 2005 Topspin Corporation.  All rights reserved.
+ * Copyright (c) 2004, 2005 Voltaire Corporation.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -36,7 +37,7 @@
  * $Id: smi.c 1389 2004-12-27 22:56:47Z roland $
  */
 
-#include <ib_smi.h>
+#include <rdma/ib_smi.h>
 #include "smi.h"
 
 /*
index 90d51b179abe72671603f80b5545cc919f51e841..211ba3223f65cc7c2d78f77d3cc84ab50d3639cd 100644 (file)
@@ -1,5 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies Ltd.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -34,7 +36,7 @@
 
 #include "core_priv.h"
 
-#include <ib_mad.h>
+#include <rdma/ib_mad.h>
 
 struct ib_port {
        struct kobject         kobj;
@@ -253,14 +255,14 @@ static ssize_t show_port_gid(struct ib_port *p, struct port_attribute *attr,
                return ret;
 
        return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
-                      be16_to_cpu(((u16 *) gid.raw)[0]),
-                      be16_to_cpu(((u16 *) gid.raw)[1]),
-                      be16_to_cpu(((u16 *) gid.raw)[2]),
-                      be16_to_cpu(((u16 *) gid.raw)[3]),
-                      be16_to_cpu(((u16 *) gid.raw)[4]),
-                      be16_to_cpu(((u16 *) gid.raw)[5]),
-                      be16_to_cpu(((u16 *) gid.raw)[6]),
-                      be16_to_cpu(((u16 *) gid.raw)[7]));
+                      be16_to_cpu(((__be16 *) gid.raw)[0]),
+                      be16_to_cpu(((__be16 *) gid.raw)[1]),
+                      be16_to_cpu(((__be16 *) gid.raw)[2]),
+                      be16_to_cpu(((__be16 *) gid.raw)[3]),
+                      be16_to_cpu(((__be16 *) gid.raw)[4]),
+                      be16_to_cpu(((__be16 *) gid.raw)[5]),
+                      be16_to_cpu(((__be16 *) gid.raw)[6]),
+                      be16_to_cpu(((__be16 *) gid.raw)[7]));
 }
 
 static ssize_t show_port_pkey(struct ib_port *p, struct port_attribute *attr,
@@ -332,11 +334,11 @@ static ssize_t show_pma_counter(struct ib_port *p, struct port_attribute *attr,
                break;
        case 16:
                ret = sprintf(buf, "%u\n",
-                             be16_to_cpup((u16 *)(out_mad->data + 40 + offset / 8)));
+                             be16_to_cpup((__be16 *)(out_mad->data + 40 + offset / 8)));
                break;
        case 32:
                ret = sprintf(buf, "%u\n",
-                             be32_to_cpup((u32 *)(out_mad->data + 40 + offset / 8)));
+                             be32_to_cpup((__be32 *)(out_mad->data + 40 + offset / 8)));
                break;
        default:
                ret = 0;
@@ -461,7 +463,7 @@ alloc_group_attrs(ssize_t (*show)(struct ib_port *,
                return NULL;
 
        for (i = 0; i < len; i++) {
-               element = kcalloc(1, sizeof(struct port_table_attribute),
+               element = kzalloc(sizeof(struct port_table_attribute),
                                  GFP_KERNEL);
                if (!element)
                        goto err;
@@ -598,10 +600,10 @@ static ssize_t show_sys_image_guid(struct class_device *cdev, char *buf)
                return ret;
 
        return sprintf(buf, "%04x:%04x:%04x:%04x\n",
-                      be16_to_cpu(((u16 *) &attr.sys_image_guid)[0]),
-                      be16_to_cpu(((u16 *) &attr.sys_image_guid)[1]),
-                      be16_to_cpu(((u16 *) &attr.sys_image_guid)[2]),
-                      be16_to_cpu(((u16 *) &attr.sys_image_guid)[3]));
+                      be16_to_cpu(((__be16 *) &attr.sys_image_guid)[0]),
+                      be16_to_cpu(((__be16 *) &attr.sys_image_guid)[1]),
+                      be16_to_cpu(((__be16 *) &attr.sys_image_guid)[2]),
+                      be16_to_cpu(((__be16 *) &attr.sys_image_guid)[3]));
 }
 
 static ssize_t show_node_guid(struct class_device *cdev, char *buf)
@@ -615,10 +617,10 @@ static ssize_t show_node_guid(struct class_device *cdev, char *buf)
                return ret;
 
        return sprintf(buf, "%04x:%04x:%04x:%04x\n",
-                      be16_to_cpu(((u16 *) &attr.node_guid)[0]),
-                      be16_to_cpu(((u16 *) &attr.node_guid)[1]),
-                      be16_to_cpu(((u16 *) &attr.node_guid)[2]),
-                      be16_to_cpu(((u16 *) &attr.node_guid)[3]));
+                      be16_to_cpu(((__be16 *) &attr.node_guid)[0]),
+                      be16_to_cpu(((__be16 *) &attr.node_guid)[1]),
+                      be16_to_cpu(((__be16 *) &attr.node_guid)[2]),
+                      be16_to_cpu(((__be16 *) &attr.node_guid)[3]));
 }
 
 static CLASS_DEVICE_ATTR(node_type, S_IRUGO, show_node_type, NULL);
index 61d07c732f4932178235a61958e3ff7abbe301c7..79595826ccc7392aa2e9d05c1ad45454eedfccc0 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Intel Corporation.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -73,14 +74,18 @@ static struct semaphore ctx_id_mutex;
 static struct idr       ctx_id_table;
 static int              ctx_id_rover = 0;
 
-static struct ib_ucm_context *ib_ucm_ctx_get(int id)
+static struct ib_ucm_context *ib_ucm_ctx_get(struct ib_ucm_file *file, int id)
 {
        struct ib_ucm_context *ctx;
 
        down(&ctx_id_mutex);
        ctx = idr_find(&ctx_id_table, id);
-       if (ctx)
-               ctx->ref++;
+       if (!ctx)
+               ctx = ERR_PTR(-ENOENT);
+       else if (ctx->file != file)
+               ctx = ERR_PTR(-EINVAL);
+       else
+               atomic_inc(&ctx->ref);
        up(&ctx_id_mutex);
 
        return ctx;
@@ -88,21 +93,37 @@ static struct ib_ucm_context *ib_ucm_ctx_get(int id)
 
 static void ib_ucm_ctx_put(struct ib_ucm_context *ctx)
 {
+       if (atomic_dec_and_test(&ctx->ref))
+               wake_up(&ctx->wait);
+}
+
+static ssize_t ib_ucm_destroy_ctx(struct ib_ucm_file *file, int id)
+{
+       struct ib_ucm_context *ctx;
        struct ib_ucm_event *uevent;
 
        down(&ctx_id_mutex);
-
-       ctx->ref--;
-       if (!ctx->ref)
+       ctx = idr_find(&ctx_id_table, id);
+       if (!ctx)
+               ctx = ERR_PTR(-ENOENT);
+       else if (ctx->file != file)
+               ctx = ERR_PTR(-EINVAL);
+       else
                idr_remove(&ctx_id_table, ctx->id);
-
        up(&ctx_id_mutex);
 
-       if (ctx->ref)
-               return;
+       if (IS_ERR(ctx))
+               return PTR_ERR(ctx);
 
-       down(&ctx->file->mutex);
+       atomic_dec(&ctx->ref);
+       wait_event(ctx->wait, !atomic_read(&ctx->ref));
+
+       /* No new events will be generated after destroying the cm_id. */
+       if (!IS_ERR(ctx->cm_id))
+               ib_destroy_cm_id(ctx->cm_id);
 
+       /* Cleanup events not yet reported to the user. */
+       down(&file->mutex);
        list_del(&ctx->file_list);
        while (!list_empty(&ctx->events)) {
 
@@ -117,13 +138,10 @@ static void ib_ucm_ctx_put(struct ib_ucm_context *ctx)
 
                kfree(uevent);
        }
+       up(&file->mutex);
 
-       up(&ctx->file->mutex);
-
-       ucm_dbg("Destroyed CM ID <%d>\n", ctx->id);
-
-       ib_destroy_cm_id(ctx->cm_id);
        kfree(ctx);
+       return 0;
 }
 
 static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file)
@@ -135,11 +153,11 @@ static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file)
        if (!ctx)
                return NULL;
 
-       ctx->ref  = 1; /* user reference */
+       atomic_set(&ctx->ref, 1);
+       init_waitqueue_head(&ctx->wait);
        ctx->file = file;
 
        INIT_LIST_HEAD(&ctx->events);
-       init_MUTEX(&ctx->mutex);
 
        list_add_tail(&ctx->file_list, &file->ctxs);
 
@@ -177,8 +195,8 @@ static void ib_ucm_event_path_get(struct ib_ucm_path_rec *upath,
        if (!kpath || !upath)
                return;
 
-       memcpy(upath->dgid, kpath->dgid.raw, sizeof(union ib_gid));
-       memcpy(upath->sgid, kpath->sgid.raw, sizeof(union ib_gid));
+       memcpy(upath->dgid, kpath->dgid.raw, sizeof *upath->dgid);
+       memcpy(upath->sgid, kpath->sgid.raw, sizeof *upath->sgid);
 
        upath->dlid             = kpath->dlid;
        upath->slid             = kpath->slid;
@@ -201,10 +219,11 @@ static void ib_ucm_event_path_get(struct ib_ucm_path_rec *upath,
                kpath->packet_life_time_selector;
 }
 
-static void ib_ucm_event_req_get(struct ib_ucm_req_event_resp *ureq,
+static void ib_ucm_event_req_get(struct ib_ucm_context *ctx,
+                                struct ib_ucm_req_event_resp *ureq,
                                 struct ib_cm_req_event_param *kreq)
 {
-       ureq->listen_id = (long)kreq->listen_id->context;
+       ureq->listen_id = ctx->id;
 
        ureq->remote_ca_guid             = kreq->remote_ca_guid;
        ureq->remote_qkey                = kreq->remote_qkey;
@@ -240,34 +259,11 @@ static void ib_ucm_event_rep_get(struct ib_ucm_rep_event_resp *urep,
        urep->srq                 = krep->srq;
 }
 
-static void ib_ucm_event_rej_get(struct ib_ucm_rej_event_resp *urej,
-                                struct ib_cm_rej_event_param *krej)
-{
-       urej->reason = krej->reason;
-}
-
-static void ib_ucm_event_mra_get(struct ib_ucm_mra_event_resp *umra,
-                                struct ib_cm_mra_event_param *kmra)
-{
-       umra->timeout = kmra->service_timeout;
-}
-
-static void ib_ucm_event_lap_get(struct ib_ucm_lap_event_resp *ulap,
-                                struct ib_cm_lap_event_param *klap)
-{
-       ib_ucm_event_path_get(&ulap->path, klap->alternate_path);
-}
-
-static void ib_ucm_event_apr_get(struct ib_ucm_apr_event_resp *uapr,
-                                struct ib_cm_apr_event_param *kapr)
-{
-       uapr->status = kapr->ap_status;
-}
-
-static void ib_ucm_event_sidr_req_get(struct ib_ucm_sidr_req_event_resp *ureq,
+static void ib_ucm_event_sidr_req_get(struct ib_ucm_context *ctx,
+                                     struct ib_ucm_sidr_req_event_resp *ureq,
                                      struct ib_cm_sidr_req_event_param *kreq)
 {
-       ureq->listen_id = (long)kreq->listen_id->context;
+       ureq->listen_id = ctx->id;
        ureq->pkey      = kreq->pkey;
 }
 
@@ -279,19 +275,18 @@ static void ib_ucm_event_sidr_rep_get(struct ib_ucm_sidr_rep_event_resp *urep,
        urep->qpn    = krep->qpn;
 };
 
-static int ib_ucm_event_process(struct ib_cm_event *evt,
+static int ib_ucm_event_process(struct ib_ucm_context *ctx,
+                               struct ib_cm_event *evt,
                                struct ib_ucm_event *uvt)
 {
        void *info = NULL;
-       int result;
 
        switch (evt->event) {
        case IB_CM_REQ_RECEIVED:
-               ib_ucm_event_req_get(&uvt->resp.u.req_resp,
+               ib_ucm_event_req_get(ctx, &uvt->resp.u.req_resp,
                                     &evt->param.req_rcvd);
                uvt->data_len      = IB_CM_REQ_PRIVATE_DATA_SIZE;
-               uvt->resp.present |= (evt->param.req_rcvd.primary_path ?
-                                     IB_UCM_PRES_PRIMARY : 0);
+               uvt->resp.present  = IB_UCM_PRES_PRIMARY;
                uvt->resp.present |= (evt->param.req_rcvd.alternate_path ?
                                      IB_UCM_PRES_ALTERNATE : 0);
                break;
@@ -299,57 +294,46 @@ static int ib_ucm_event_process(struct ib_cm_event *evt,
                ib_ucm_event_rep_get(&uvt->resp.u.rep_resp,
                                     &evt->param.rep_rcvd);
                uvt->data_len = IB_CM_REP_PRIVATE_DATA_SIZE;
-
                break;
        case IB_CM_RTU_RECEIVED:
                uvt->data_len = IB_CM_RTU_PRIVATE_DATA_SIZE;
                uvt->resp.u.send_status = evt->param.send_status;
-
                break;
        case IB_CM_DREQ_RECEIVED:
                uvt->data_len = IB_CM_DREQ_PRIVATE_DATA_SIZE;
                uvt->resp.u.send_status = evt->param.send_status;
-
                break;
        case IB_CM_DREP_RECEIVED:
                uvt->data_len = IB_CM_DREP_PRIVATE_DATA_SIZE;
                uvt->resp.u.send_status = evt->param.send_status;
-
                break;
        case IB_CM_MRA_RECEIVED:
-               ib_ucm_event_mra_get(&uvt->resp.u.mra_resp,
-                                    &evt->param.mra_rcvd);
+               uvt->resp.u.mra_resp.timeout =
+                                       evt->param.mra_rcvd.service_timeout;
                uvt->data_len = IB_CM_MRA_PRIVATE_DATA_SIZE;
-
                break;
        case IB_CM_REJ_RECEIVED:
-               ib_ucm_event_rej_get(&uvt->resp.u.rej_resp,
-                                    &evt->param.rej_rcvd);
+               uvt->resp.u.rej_resp.reason = evt->param.rej_rcvd.reason;
                uvt->data_len = IB_CM_REJ_PRIVATE_DATA_SIZE;
                uvt->info_len = evt->param.rej_rcvd.ari_length;
                info          = evt->param.rej_rcvd.ari;
-
                break;
        case IB_CM_LAP_RECEIVED:
-               ib_ucm_event_lap_get(&uvt->resp.u.lap_resp,
-                                    &evt->param.lap_rcvd);
+               ib_ucm_event_path_get(&uvt->resp.u.lap_resp.path,
+                                     evt->param.lap_rcvd.alternate_path);
                uvt->data_len = IB_CM_LAP_PRIVATE_DATA_SIZE;
-               uvt->resp.present |= (evt->param.lap_rcvd.alternate_path ?
-                                     IB_UCM_PRES_ALTERNATE : 0);
+               uvt->resp.present = IB_UCM_PRES_ALTERNATE;
                break;
        case IB_CM_APR_RECEIVED:
-               ib_ucm_event_apr_get(&uvt->resp.u.apr_resp,
-                                    &evt->param.apr_rcvd);
+               uvt->resp.u.apr_resp.status = evt->param.apr_rcvd.ap_status;
                uvt->data_len = IB_CM_APR_PRIVATE_DATA_SIZE;
                uvt->info_len = evt->param.apr_rcvd.info_len;
                info          = evt->param.apr_rcvd.apr_info;
-
                break;
        case IB_CM_SIDR_REQ_RECEIVED:
-               ib_ucm_event_sidr_req_get(&uvt->resp.u.sidr_req_resp,
+               ib_ucm_event_sidr_req_get(ctx, &uvt->resp.u.sidr_req_resp,
                                          &evt->param.sidr_req_rcvd);
                uvt->data_len = IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE;
-
                break;
        case IB_CM_SIDR_REP_RECEIVED:
                ib_ucm_event_sidr_rep_get(&uvt->resp.u.sidr_rep_resp,
@@ -357,43 +341,35 @@ static int ib_ucm_event_process(struct ib_cm_event *evt,
                uvt->data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE;
                uvt->info_len = evt->param.sidr_rep_rcvd.info_len;
                info          = evt->param.sidr_rep_rcvd.info;
-
                break;
        default:
                uvt->resp.u.send_status = evt->param.send_status;
-
                break;
        }
 
-       if (uvt->data_len && evt->private_data) {
-
+       if (uvt->data_len) {
                uvt->data = kmalloc(uvt->data_len, GFP_KERNEL);
-               if (!uvt->data) {
-                       result = -ENOMEM;
-                       goto error;
-               }
+               if (!uvt->data)
+                       goto err1;
 
                memcpy(uvt->data, evt->private_data, uvt->data_len);
                uvt->resp.present |= IB_UCM_PRES_DATA;
        }
 
-       if (uvt->info_len && info) {
-
+       if (uvt->info_len) {
                uvt->info = kmalloc(uvt->info_len, GFP_KERNEL);
-               if (!uvt->info) {
-                       result = -ENOMEM;
-                       goto error;
-               }
+               if (!uvt->info)
+                       goto err2;
 
                memcpy(uvt->info, info, uvt->info_len);
                uvt->resp.present |= IB_UCM_PRES_INFO;
        }
-
        return 0;
-error:
-       kfree(uvt->info);
+
+err2:
        kfree(uvt->data);
-       return result;
+err1:
+       return -ENOMEM;
 }
 
 static int ib_ucm_event_handler(struct ib_cm_id *cm_id,
@@ -403,63 +379,42 @@ static int ib_ucm_event_handler(struct ib_cm_id *cm_id,
        struct ib_ucm_context *ctx;
        int result = 0;
        int id;
-       /*
-        * lookup correct context based on event type.
-        */
-       switch (event->event) {
-       case IB_CM_REQ_RECEIVED:
-               id = (long)event->param.req_rcvd.listen_id->context;
-               break;
-       case IB_CM_SIDR_REQ_RECEIVED:
-               id = (long)event->param.sidr_req_rcvd.listen_id->context;
-               break;
-       default:
-               id = (long)cm_id->context;
-               break;
-       }
 
-       ucm_dbg("Event. CM ID <%d> event <%d>\n", id, event->event);
-
-       ctx = ib_ucm_ctx_get(id);
-       if (!ctx)
-               return -ENOENT;
+       ctx = cm_id->context;
 
        if (event->event == IB_CM_REQ_RECEIVED ||
            event->event == IB_CM_SIDR_REQ_RECEIVED)
                id = IB_UCM_CM_ID_INVALID;
+       else
+               id = ctx->id;
 
        uevent = kmalloc(sizeof(*uevent), GFP_KERNEL);
-       if (!uevent) {
-               result = -ENOMEM;
-               goto done;
-       }
+       if (!uevent)
+               goto err1;
 
        memset(uevent, 0, sizeof(*uevent));
-
        uevent->resp.id    = id;
        uevent->resp.event = event->event;
 
-       result = ib_ucm_event_process(event, uevent);
+       result = ib_ucm_event_process(ctx, event, uevent);
        if (result)
-               goto done;
+               goto err2;
 
        uevent->ctx   = ctx;
-       uevent->cm_id = ((event->event == IB_CM_REQ_RECEIVED ||
-                         event->event == IB_CM_SIDR_REQ_RECEIVED ) ?
-                        cm_id : NULL);
+       uevent->cm_id = (id == IB_UCM_CM_ID_INVALID) ? cm_id : NULL;
 
        down(&ctx->file->mutex);
-
        list_add_tail(&uevent->file_list, &ctx->file->events);
        list_add_tail(&uevent->ctx_list, &ctx->events);
-
        wake_up_interruptible(&ctx->file->poll_wait);
-
        up(&ctx->file->mutex);
-done:
-       ctx->error = result;
-       ib_ucm_ctx_put(ctx); /* func reference */
-       return result;
+       return 0;
+
+err2:
+       kfree(uevent);
+err1:
+       /* Destroy new cm_id's */
+       return (id == IB_UCM_CM_ID_INVALID);
 }
 
 static ssize_t ib_ucm_event(struct ib_ucm_file *file,
@@ -517,9 +472,8 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file,
                goto done;
        }
 
-       ctx->cm_id             = uevent->cm_id;
-       ctx->cm_id->cm_handler = ib_ucm_event_handler;
-       ctx->cm_id->context    = (void *)(unsigned long)ctx->id;
+       ctx->cm_id          = uevent->cm_id;
+       ctx->cm_id->context = ctx;
 
        uevent->resp.id = ctx->id;
 
@@ -585,30 +539,29 @@ static ssize_t ib_ucm_create_id(struct ib_ucm_file *file,
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
                return -EFAULT;
 
+       down(&file->mutex);
        ctx = ib_ucm_ctx_alloc(file);
+       up(&file->mutex);
        if (!ctx)
                return -ENOMEM;
 
-       ctx->cm_id = ib_create_cm_id(ib_ucm_event_handler,
-                                    (void *)(unsigned long)ctx->id);
-       if (!ctx->cm_id) {
-               result = -ENOMEM;
-               goto err_cm;
+       ctx->cm_id = ib_create_cm_id(ib_ucm_event_handler, ctx);
+       if (IS_ERR(ctx->cm_id)) {
+               result = PTR_ERR(ctx->cm_id);
+               goto err;
        }
 
        resp.id = ctx->id;
        if (copy_to_user((void __user *)(unsigned long)cmd.response,
                         &resp, sizeof(resp))) {
                result = -EFAULT;
-               goto err_ret;
+               goto err;
        }
 
        return 0;
-err_ret:
-       ib_destroy_cm_id(ctx->cm_id);
-err_cm:
-       ib_ucm_ctx_put(ctx); /* user reference */
 
+err:
+       ib_ucm_destroy_ctx(file, ctx->id);
        return result;
 }
 
@@ -617,19 +570,11 @@ static ssize_t ib_ucm_destroy_id(struct ib_ucm_file *file,
                                 int in_len, int out_len)
 {
        struct ib_ucm_destroy_id cmd;
-       struct ib_ucm_context *ctx;
 
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
                return -EFAULT;
 
-       ctx = ib_ucm_ctx_get(cmd.id);
-       if (!ctx)
-               return -ENOENT;
-
-       ib_ucm_ctx_put(ctx); /* user reference */
-       ib_ucm_ctx_put(ctx); /* func reference */
-
-       return 0;
+       return ib_ucm_destroy_ctx(file, cmd.id);
 }
 
 static ssize_t ib_ucm_attr_id(struct ib_ucm_file *file,
@@ -647,15 +592,9 @@ static ssize_t ib_ucm_attr_id(struct ib_ucm_file *file,
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
                return -EFAULT;
 
-       ctx = ib_ucm_ctx_get(cmd.id);
-       if (!ctx)
-               return -ENOENT;
-
-       down(&ctx->file->mutex);
-       if (ctx->file != file) {
-               result = -EINVAL;
-               goto done;
-       }
+       ctx = ib_ucm_ctx_get(file, cmd.id);
+       if (IS_ERR(ctx))
+               return PTR_ERR(ctx);
 
        resp.service_id   = ctx->cm_id->service_id;
        resp.service_mask = ctx->cm_id->service_mask;
@@ -666,9 +605,7 @@ static ssize_t ib_ucm_attr_id(struct ib_ucm_file *file,
                         &resp, sizeof(resp)))
                result = -EFAULT;
 
-done:
-       up(&ctx->file->mutex);
-       ib_ucm_ctx_put(ctx); /* func reference */
+       ib_ucm_ctx_put(ctx);
        return result;
 }
 
@@ -683,19 +620,12 @@ static ssize_t ib_ucm_listen(struct ib_ucm_file *file,
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
                return -EFAULT;
 
-       ctx = ib_ucm_ctx_get(cmd.id);
-       if (!ctx)
-               return -ENOENT;
+       ctx = ib_ucm_ctx_get(file, cmd.id);
+       if (IS_ERR(ctx))
+               return PTR_ERR(ctx);
 
-       down(&ctx->file->mutex);
-       if (ctx->file != file)
-               result = -EINVAL;
-       else
-               result = ib_cm_listen(ctx->cm_id, cmd.service_id,
-                                     cmd.service_mask);
-
-       up(&ctx->file->mutex);
-       ib_ucm_ctx_put(ctx); /* func reference */
+       result = ib_cm_listen(ctx->cm_id, cmd.service_id, cmd.service_mask);
+       ib_ucm_ctx_put(ctx);
        return result;
 }
 
@@ -710,18 +640,12 @@ static ssize_t ib_ucm_establish(struct ib_ucm_file *file,
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
                return -EFAULT;
 
-       ctx = ib_ucm_ctx_get(cmd.id);
-       if (!ctx)
-               return -ENOENT;
-
-       down(&ctx->file->mutex);
-       if (ctx->file != file)
-               result = -EINVAL;
-       else
-               result = ib_cm_establish(ctx->cm_id);
+       ctx = ib_ucm_ctx_get(file, cmd.id);
+       if (IS_ERR(ctx))
+               return PTR_ERR(ctx);
 
-       up(&ctx->file->mutex);
-       ib_ucm_ctx_put(ctx); /* func reference */
+       result = ib_cm_establish(ctx->cm_id);
+       ib_ucm_ctx_put(ctx);
        return result;
 }
 
@@ -768,8 +692,8 @@ static int ib_ucm_path_get(struct ib_sa_path_rec **path, u64 src)
                return -EFAULT;
        }
 
-       memcpy(sa_path->dgid.raw, ucm_path.dgid, sizeof(union ib_gid));
-       memcpy(sa_path->sgid.raw, ucm_path.sgid, sizeof(union ib_gid));
+       memcpy(sa_path->dgid.raw, ucm_path.dgid, sizeof sa_path->dgid);
+       memcpy(sa_path->sgid.raw, ucm_path.sgid, sizeof sa_path->sgid);
 
        sa_path->dlid             = ucm_path.dlid;
        sa_path->slid             = ucm_path.slid;
@@ -839,25 +763,17 @@ static ssize_t ib_ucm_send_req(struct ib_ucm_file *file,
        param.max_cm_retries             = cmd.max_cm_retries;
        param.srq                        = cmd.srq;
 
-       ctx = ib_ucm_ctx_get(cmd.id);
-       if (!ctx) {
-               result = -ENOENT;
-               goto done;
-       }
-
-       down(&ctx->file->mutex);
-       if (ctx->file != file)
-               result = -EINVAL;
-       else
+       ctx = ib_ucm_ctx_get(file, cmd.id);
+       if (!IS_ERR(ctx)) {
                result = ib_send_cm_req(ctx->cm_id, &param);
+               ib_ucm_ctx_put(ctx);
+       } else
+               result = PTR_ERR(ctx);
 
-       up(&ctx->file->mutex);
-       ib_ucm_ctx_put(ctx); /* func reference */
 done:
        kfree(param.private_data);
        kfree(param.primary_path);
        kfree(param.alternate_path);
-
        return result;
 }
 
@@ -890,23 +806,14 @@ static ssize_t ib_ucm_send_rep(struct ib_ucm_file *file,
        param.rnr_retry_count     = cmd.rnr_retry_count;
        param.srq                 = cmd.srq;
 
-       ctx = ib_ucm_ctx_get(cmd.id);
-       if (!ctx) {
-               result = -ENOENT;
-               goto done;
-       }
-
-       down(&ctx->file->mutex);
-       if (ctx->file != file)
-               result = -EINVAL;
-       else
+       ctx = ib_ucm_ctx_get(file, cmd.id);
+       if (!IS_ERR(ctx)) {
                result = ib_send_cm_rep(ctx->cm_id, &param);
+               ib_ucm_ctx_put(ctx);
+       } else
+               result = PTR_ERR(ctx);
 
-       up(&ctx->file->mutex);
-       ib_ucm_ctx_put(ctx); /* func reference */
-done:
        kfree(param.private_data);
-
        return result;
 }
 
@@ -928,23 +835,14 @@ static ssize_t ib_ucm_send_private_data(struct ib_ucm_file *file,
        if (result)
                return result;
 
-       ctx = ib_ucm_ctx_get(cmd.id);
-       if (!ctx) {
-               result = -ENOENT;
-               goto done;
-       }
-
-       down(&ctx->file->mutex);
-       if (ctx->file != file)
-               result = -EINVAL;
-       else
+       ctx = ib_ucm_ctx_get(file, cmd.id);
+       if (!IS_ERR(ctx)) {
                result = func(ctx->cm_id, private_data, cmd.len);
+               ib_ucm_ctx_put(ctx);
+       } else
+               result = PTR_ERR(ctx);
 
-       up(&ctx->file->mutex);
-       ib_ucm_ctx_put(ctx); /* func reference */
-done:
        kfree(private_data);
-
        return result;
 }
 
@@ -995,26 +893,17 @@ static ssize_t ib_ucm_send_info(struct ib_ucm_file *file,
        if (result)
                goto done;
 
-       ctx = ib_ucm_ctx_get(cmd.id);
-       if (!ctx) {
-               result = -ENOENT;
-               goto done;
-       }
-
-       down(&ctx->file->mutex);
-       if (ctx->file != file)
-               result = -EINVAL;
-       else
-               result = func(ctx->cm_id, cmd.status,
-                             info, cmd.info_len,
+       ctx = ib_ucm_ctx_get(file, cmd.id);
+       if (!IS_ERR(ctx)) {
+               result = func(ctx->cm_id, cmd.status, info, cmd.info_len,
                              data, cmd.data_len);
+               ib_ucm_ctx_put(ctx);
+       } else
+               result = PTR_ERR(ctx);
 
-       up(&ctx->file->mutex);
-       ib_ucm_ctx_put(ctx); /* func reference */
 done:
        kfree(data);
        kfree(info);
-
        return result;
 }
 
@@ -1048,24 +937,14 @@ static ssize_t ib_ucm_send_mra(struct ib_ucm_file *file,
        if (result)
                return result;
 
-       ctx = ib_ucm_ctx_get(cmd.id);
-       if (!ctx) {
-               result = -ENOENT;
-               goto done;
-       }
+       ctx = ib_ucm_ctx_get(file, cmd.id);
+       if (!IS_ERR(ctx)) {
+               result = ib_send_cm_mra(ctx->cm_id, cmd.timeout, data, cmd.len);
+               ib_ucm_ctx_put(ctx);
+       } else
+               result = PTR_ERR(ctx);
 
-       down(&ctx->file->mutex);
-       if (ctx->file != file)
-               result = -EINVAL;
-       else
-               result = ib_send_cm_mra(ctx->cm_id, cmd.timeout,
-                                       data, cmd.len);
-
-       up(&ctx->file->mutex);
-       ib_ucm_ctx_put(ctx); /* func reference */
-done:
        kfree(data);
-
        return result;
 }
 
@@ -1090,24 +969,16 @@ static ssize_t ib_ucm_send_lap(struct ib_ucm_file *file,
        if (result)
                goto done;
 
-       ctx = ib_ucm_ctx_get(cmd.id);
-       if (!ctx) {
-               result = -ENOENT;
-               goto done;
-       }
-
-       down(&ctx->file->mutex);
-       if (ctx->file != file)
-               result = -EINVAL;
-       else
+       ctx = ib_ucm_ctx_get(file, cmd.id);
+       if (!IS_ERR(ctx)) {
                result = ib_send_cm_lap(ctx->cm_id, path, data, cmd.len);
+               ib_ucm_ctx_put(ctx);
+       } else
+               result = PTR_ERR(ctx);
 
-       up(&ctx->file->mutex);
-       ib_ucm_ctx_put(ctx); /* func reference */
 done:
        kfree(data);
        kfree(path);
-
        return result;
 }
 
@@ -1140,24 +1011,16 @@ static ssize_t ib_ucm_send_sidr_req(struct ib_ucm_file *file,
        param.max_cm_retries   = cmd.max_cm_retries;
        param.pkey             = cmd.pkey;
 
-       ctx = ib_ucm_ctx_get(cmd.id);
-       if (!ctx) {
-               result = -ENOENT;
-               goto done;
-       }
-
-       down(&ctx->file->mutex);
-       if (ctx->file != file)
-               result = -EINVAL;
-       else
+       ctx = ib_ucm_ctx_get(file, cmd.id);
+       if (!IS_ERR(ctx)) {
                result = ib_send_cm_sidr_req(ctx->cm_id, &param);
+               ib_ucm_ctx_put(ctx);
+       } else
+               result = PTR_ERR(ctx);
 
-       up(&ctx->file->mutex);
-       ib_ucm_ctx_put(ctx); /* func reference */
 done:
        kfree(param.private_data);
        kfree(param.path);
-
        return result;
 }
 
@@ -1184,30 +1047,22 @@ static ssize_t ib_ucm_send_sidr_rep(struct ib_ucm_file *file,
        if (result)
                goto done;
 
-       param.qp_num       = cmd.qpn;
-       param.qkey           = cmd.qkey;
-       param.status       = cmd.status;
-       param.info_length      = cmd.info_len;
-       param.private_data_len = cmd.data_len;
-
-       ctx = ib_ucm_ctx_get(cmd.id);
-       if (!ctx) {
-               result = -ENOENT;
-               goto done;
-       }
+       param.qp_num            = cmd.qpn;
+       param.qkey              = cmd.qkey;
+       param.status            = cmd.status;
+       param.info_length       = cmd.info_len;
+       param.private_data_len  = cmd.data_len;
 
-       down(&ctx->file->mutex);
-       if (ctx->file != file)
-               result = -EINVAL;
-       else
+       ctx = ib_ucm_ctx_get(file, cmd.id);
+       if (!IS_ERR(ctx)) {
                result = ib_send_cm_sidr_rep(ctx->cm_id, &param);
+               ib_ucm_ctx_put(ctx);
+       } else
+               result = PTR_ERR(ctx);
 
-       up(&ctx->file->mutex);
-       ib_ucm_ctx_put(ctx); /* func reference */
 done:
        kfree(param.private_data);
        kfree(param.info);
-
        return result;
 }
 
@@ -1305,22 +1160,17 @@ static int ib_ucm_close(struct inode *inode, struct file *filp)
        struct ib_ucm_context *ctx;
 
        down(&file->mutex);
-
        while (!list_empty(&file->ctxs)) {
 
                ctx = list_entry(file->ctxs.next,
                                 struct ib_ucm_context, file_list);
 
-               up(&ctx->file->mutex);
-               ib_ucm_ctx_put(ctx); /* user reference */
+               up(&file->mutex);
+               ib_ucm_destroy_ctx(file, ctx->id);
                down(&file->mutex);
        }
-
        up(&file->mutex);
-
        kfree(file);
-
-       ucm_dbg("Deleted struct\n");
        return 0;
 }
 
index 6d36606151b2690abfaf269fffe8ffc4a6d2ac43..c8819b928a1ba82772d0ae48761ee41e7ebc6f4d 100644 (file)
 #include <linux/cdev.h>
 #include <linux/idr.h>
 
-#include <ib_cm.h>
-#include <ib_user_cm.h>
+#include <rdma/ib_cm.h>
+#include <rdma/ib_user_cm.h>
 
 #define IB_UCM_CM_ID_INVALID 0xffffffff
 
 struct ib_ucm_file {
        struct semaphore mutex;
        struct file *filp;
-       /*
-        * list of pending events
-        */
+
        struct list_head  ctxs;   /* list of active connections */
        struct list_head  events; /* list of pending events */
        wait_queue_head_t poll_wait;
@@ -58,12 +56,11 @@ struct ib_ucm_file {
 
 struct ib_ucm_context {
        int                 id;
-       int                 ref;
-       int                 error;
+       wait_queue_head_t   wait;
+       atomic_t            ref;
 
        struct ib_ucm_file *file;
        struct ib_cm_id    *cm_id;
-       struct semaphore    mutex;
 
        struct list_head    events;    /* list of pending events. */
        struct list_head    file_list; /* member in file ctx list */
index dc4eb1db5e962a8d3541ccd7f273d1cad5684328..527b23450ab3d72dc12e3298e8bbdc49a871e12b 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -34,7 +35,7 @@
 
 #include <linux/errno.h>
 
-#include <ib_pack.h>
+#include <rdma/ib_pack.h>
 
 #define STRUCT_FIELD(header, field) \
        .struct_offset_bytes = offsetof(struct ib_unpacked_ ## header, field),      \
@@ -194,6 +195,7 @@ void ib_ud_header_init(int                      payload_bytes,
                       struct ib_ud_header *header)
 {
        int header_len;
+       u16 packet_length;
 
        memset(header, 0, sizeof *header);
 
@@ -208,7 +210,7 @@ void ib_ud_header_init(int                      payload_bytes,
        header->lrh.link_version     = 0;
        header->lrh.link_next_header =
                grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
-       header->lrh.packet_length    = (IB_LRH_BYTES     +
+       packet_length                = (IB_LRH_BYTES     +
                                        IB_BTH_BYTES     +
                                        IB_DETH_BYTES    +
                                        payload_bytes    +
@@ -217,8 +219,7 @@ void ib_ud_header_init(int                      payload_bytes,
 
        header->grh_present          = grh_present;
        if (grh_present) {
-               header->lrh.packet_length  += IB_GRH_BYTES / 4;
-
+               packet_length              += IB_GRH_BYTES / 4;
                header->grh.ip_version      = 6;
                header->grh.payload_length  =
                        cpu_to_be16((IB_BTH_BYTES     +
@@ -229,7 +230,7 @@ void ib_ud_header_init(int                      payload_bytes,
                header->grh.next_header     = 0x1b;
        }
 
-       cpu_to_be16s(&header->lrh.packet_length);
+       header->lrh.packet_length = cpu_to_be16(packet_length);
 
        if (header->immediate_present)
                header->bth.opcode           = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
index 2e38792df533568c4e25d6e5a4dfd0469d3cf0c3..7c2f03057ddb1f6ed411d3509c68ba768e4bf0ad 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2005 Voltaire, Inc. All rights reserved. 
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -49,8 +49,8 @@
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 
-#include <ib_mad.h>
-#include <ib_user_mad.h>
+#include <rdma/ib_mad.h>
+#include <rdma/ib_user_mad.h>
 
 MODULE_AUTHOR("Roland Dreier");
 MODULE_DESCRIPTION("InfiniBand userspace MAD packet access");
@@ -271,7 +271,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
        struct ib_send_wr *bad_wr;
        struct ib_rmpp_mad *rmpp_mad;
        u8 method;
-       u64 *tid;
+       __be64 *tid;
        int ret, length, hdr_len, data_len, rmpp_hdr_size;
        int rmpp_active = 0;
 
@@ -316,7 +316,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
        if (packet->mad.hdr.grh_present) {
                ah_attr.ah_flags = IB_AH_GRH;
                memcpy(ah_attr.grh.dgid.raw, packet->mad.hdr.gid, 16);
-               ah_attr.grh.flow_label     = packet->mad.hdr.flow_label;
+               ah_attr.grh.flow_label     = be32_to_cpu(packet->mad.hdr.flow_label);
                ah_attr.grh.hop_limit      = packet->mad.hdr.hop_limit;
                ah_attr.grh.traffic_class  = packet->mad.hdr.traffic_class;
        }
index 7696022f9a4ec3365fa574a88239b5dfd2c3d515..180b3d4765e40bc4eae9d3c0c6516006fefdbee2 100644 (file)
@@ -1,6 +1,8 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -43,8 +45,8 @@
 #include <linux/kref.h>
 #include <linux/idr.h>
 
-#include <ib_verbs.h>
-#include <ib_user_verbs.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
 
 struct ib_uverbs_device {
        int                                     devnum;
@@ -97,10 +99,12 @@ extern struct idr ib_uverbs_mw_idr;
 extern struct idr ib_uverbs_ah_idr;
 extern struct idr ib_uverbs_cq_idr;
 extern struct idr ib_uverbs_qp_idr;
+extern struct idr ib_uverbs_srq_idr;
 
 void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context);
 void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr);
 void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr);
+void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr);
 
 int ib_umem_get(struct ib_device *dev, struct ib_umem *mem,
                void *addr, size_t size, int write);
@@ -129,5 +133,8 @@ IB_UVERBS_DECLARE_CMD(modify_qp);
 IB_UVERBS_DECLARE_CMD(destroy_qp);
 IB_UVERBS_DECLARE_CMD(attach_mcast);
 IB_UVERBS_DECLARE_CMD(detach_mcast);
+IB_UVERBS_DECLARE_CMD(create_srq);
+IB_UVERBS_DECLARE_CMD(modify_srq);
+IB_UVERBS_DECLARE_CMD(destroy_srq);
 
 #endif /* UVERBS_H */
index 5f2bbcda4c73000ed2b042c3f25282925aac6b28..ebccf9f38af946e6cfb1c894ecf020f4c96aaae8 100644 (file)
@@ -724,6 +724,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
        struct ib_uobject              *uobj;
        struct ib_pd                   *pd;
        struct ib_cq                   *scq, *rcq;
+       struct ib_srq                  *srq;
        struct ib_qp                   *qp;
        struct ib_qp_init_attr          attr;
        int ret;
@@ -747,10 +748,12 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
        pd  = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
        scq = idr_find(&ib_uverbs_cq_idr, cmd.send_cq_handle);
        rcq = idr_find(&ib_uverbs_cq_idr, cmd.recv_cq_handle);
+       srq = cmd.is_srq ? idr_find(&ib_uverbs_srq_idr, cmd.srq_handle) : NULL;
 
        if (!pd  || pd->uobject->context  != file->ucontext ||
            !scq || scq->uobject->context != file->ucontext ||
-           !rcq || rcq->uobject->context != file->ucontext) {
+           !rcq || rcq->uobject->context != file->ucontext ||
+           (cmd.is_srq && (!srq || srq->uobject->context != file->ucontext))) {
                ret = -EINVAL;
                goto err_up;
        }
@@ -759,7 +762,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
        attr.qp_context    = file;
        attr.send_cq       = scq;
        attr.recv_cq       = rcq;
-       attr.srq           = NULL;
+       attr.srq           = srq;
        attr.sq_sig_type   = cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR;
        attr.qp_type       = cmd.qp_type;
 
@@ -1004,3 +1007,178 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
 
        return ret ? ret : in_len;
 }
+
+ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
+                            const char __user *buf, int in_len,
+                            int out_len)
+{
+       struct ib_uverbs_create_srq      cmd;
+       struct ib_uverbs_create_srq_resp resp;
+       struct ib_udata                  udata;
+       struct ib_uobject               *uobj;
+       struct ib_pd                    *pd;
+       struct ib_srq                   *srq;
+       struct ib_srq_init_attr          attr;
+       int ret;
+
+       if (out_len < sizeof resp)
+               return -ENOSPC;
+
+       if (copy_from_user(&cmd, buf, sizeof cmd))
+               return -EFAULT;
+
+       INIT_UDATA(&udata, buf + sizeof cmd,
+                  (unsigned long) cmd.response + sizeof resp,
+                  in_len - sizeof cmd, out_len - sizeof resp);
+
+       uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
+       if (!uobj)
+               return -ENOMEM;
+
+       down(&ib_uverbs_idr_mutex);
+
+       pd  = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
+
+       if (!pd || pd->uobject->context != file->ucontext) {
+               ret = -EINVAL;
+               goto err_up;
+       }
+
+       attr.event_handler  = ib_uverbs_srq_event_handler;
+       attr.srq_context    = file;
+       attr.attr.max_wr    = cmd.max_wr;
+       attr.attr.max_sge   = cmd.max_sge;
+       attr.attr.srq_limit = cmd.srq_limit;
+
+       uobj->user_handle = cmd.user_handle;
+       uobj->context     = file->ucontext;
+
+       srq = pd->device->create_srq(pd, &attr, &udata);
+       if (IS_ERR(srq)) {
+               ret = PTR_ERR(srq);
+               goto err_up;
+       }
+
+       srq->device        = pd->device;
+       srq->pd            = pd;
+       srq->uobject       = uobj;
+       srq->event_handler = attr.event_handler;
+       srq->srq_context   = attr.srq_context;
+       atomic_inc(&pd->usecnt);
+       atomic_set(&srq->usecnt, 0);
+
+       memset(&resp, 0, sizeof resp);
+
+retry:
+       if (!idr_pre_get(&ib_uverbs_srq_idr, GFP_KERNEL)) {
+               ret = -ENOMEM;
+               goto err_destroy;
+       }
+
+       ret = idr_get_new(&ib_uverbs_srq_idr, srq, &uobj->id);
+
+       if (ret == -EAGAIN)
+               goto retry;
+       if (ret)
+               goto err_destroy;
+
+       resp.srq_handle = uobj->id;
+
+       spin_lock_irq(&file->ucontext->lock);
+       list_add_tail(&uobj->list, &file->ucontext->srq_list);
+       spin_unlock_irq(&file->ucontext->lock);
+
+       if (copy_to_user((void __user *) (unsigned long) cmd.response,
+                        &resp, sizeof resp)) {
+               ret = -EFAULT;
+               goto err_list;
+       }
+
+       up(&ib_uverbs_idr_mutex);
+
+       return in_len;
+
+err_list:
+       spin_lock_irq(&file->ucontext->lock);
+       list_del(&uobj->list);
+       spin_unlock_irq(&file->ucontext->lock);
+
+err_destroy:
+       ib_destroy_srq(srq);
+
+err_up:
+       up(&ib_uverbs_idr_mutex);
+
+       kfree(uobj);
+       return ret;
+}
+
+ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file,
+                            const char __user *buf, int in_len,
+                            int out_len)
+{
+       struct ib_uverbs_modify_srq cmd;
+       struct ib_srq              *srq;
+       struct ib_srq_attr          attr;
+       int                         ret;
+
+       if (copy_from_user(&cmd, buf, sizeof cmd))
+               return -EFAULT;
+
+       down(&ib_uverbs_idr_mutex);
+
+       srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
+       if (!srq || srq->uobject->context != file->ucontext) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       attr.max_wr    = cmd.max_wr;
+       attr.max_sge   = cmd.max_sge;
+       attr.srq_limit = cmd.srq_limit;
+
+       ret = ib_modify_srq(srq, &attr, cmd.attr_mask);
+
+out:
+       up(&ib_uverbs_idr_mutex);
+
+       return ret ? ret : in_len;
+}
+
+ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
+                             const char __user *buf, int in_len,
+                             int out_len)
+{
+       struct ib_uverbs_destroy_srq cmd;
+       struct ib_srq               *srq;
+       struct ib_uobject           *uobj;
+       int                          ret = -EINVAL;
+
+       if (copy_from_user(&cmd, buf, sizeof cmd))
+               return -EFAULT;
+
+       down(&ib_uverbs_idr_mutex);
+
+       srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
+       if (!srq || srq->uobject->context != file->ucontext)
+               goto out;
+
+       uobj = srq->uobject;
+
+       ret = ib_destroy_srq(srq);
+       if (ret)
+               goto out;
+
+       idr_remove(&ib_uverbs_srq_idr, cmd.srq_handle);
+
+       spin_lock_irq(&file->ucontext->lock);
+       list_del(&uobj->list);
+       spin_unlock_irq(&file->ucontext->lock);
+
+       kfree(uobj);
+
+out:
+       up(&ib_uverbs_idr_mutex);
+
+       return ret ? ret : in_len;
+}
index 5f6e9ea29cd772f1f819ea21d2a2ad47840b5c81..09caf5b1ef36131305bc02171672cc39550d777b 100644 (file)
@@ -1,6 +1,8 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -67,6 +69,7 @@ DEFINE_IDR(ib_uverbs_mw_idr);
 DEFINE_IDR(ib_uverbs_ah_idr);
 DEFINE_IDR(ib_uverbs_cq_idr);
 DEFINE_IDR(ib_uverbs_qp_idr);
+DEFINE_IDR(ib_uverbs_srq_idr);
 
 static spinlock_t map_lock;
 static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES);
@@ -91,6 +94,9 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
        [IB_USER_VERBS_CMD_DESTROY_QP]    = ib_uverbs_destroy_qp,
        [IB_USER_VERBS_CMD_ATTACH_MCAST]  = ib_uverbs_attach_mcast,
        [IB_USER_VERBS_CMD_DETACH_MCAST]  = ib_uverbs_detach_mcast,
+       [IB_USER_VERBS_CMD_CREATE_SRQ]    = ib_uverbs_create_srq,
+       [IB_USER_VERBS_CMD_MODIFY_SRQ]    = ib_uverbs_modify_srq,
+       [IB_USER_VERBS_CMD_DESTROY_SRQ]   = ib_uverbs_destroy_srq,
 };
 
 static struct vfsmount *uverbs_event_mnt;
@@ -125,7 +131,14 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context)
                kfree(uobj);
        }
 
-       /* XXX Free SRQs */
+       list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) {
+               struct ib_srq *srq = idr_find(&ib_uverbs_srq_idr, uobj->id);
+               idr_remove(&ib_uverbs_srq_idr, uobj->id);
+               ib_destroy_srq(srq);
+               list_del(&uobj->list);
+               kfree(uobj);
+       }
+
        /* XXX Free MWs */
 
        list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) {
@@ -344,6 +357,13 @@ void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr)
                                event->event);
 }
 
+void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr)
+{
+       ib_uverbs_async_handler(context_ptr,
+                               event->element.srq->uobject->user_handle,
+                               event->event);
+}
+
 static void ib_uverbs_event_handler(struct ib_event_handler *handler,
                                    struct ib_event *event)
 {
index ed550f6595bd7c07efa8d8597c1715f6cd8dd653..36a32c315668cebbc7e34be30704b0c4851bcf66 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
index 506fdf1f2a268de31fe957f7c362fb7ae7d1e1f9..5081d903e5617d00e602da1a89731a555984598a 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (c) 2004 Intel Corporation.  All rights reserved.
  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
  * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  * Copyright (c) 2005 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -40,8 +41,8 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 
-#include <ib_verbs.h>
-#include <ib_cache.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_cache.h>
 
 /* Protection domains */
 
@@ -153,6 +154,66 @@ int ib_destroy_ah(struct ib_ah *ah)
 }
 EXPORT_SYMBOL(ib_destroy_ah);
 
+/* Shared receive queues */
+
+struct ib_srq *ib_create_srq(struct ib_pd *pd,
+                            struct ib_srq_init_attr *srq_init_attr)
+{
+       struct ib_srq *srq;
+
+       if (!pd->device->create_srq)
+               return ERR_PTR(-ENOSYS);
+
+       srq = pd->device->create_srq(pd, srq_init_attr, NULL);
+
+       if (!IS_ERR(srq)) {
+               srq->device        = pd->device;
+               srq->pd            = pd;
+               srq->uobject       = NULL;
+               srq->event_handler = srq_init_attr->event_handler;
+               srq->srq_context   = srq_init_attr->srq_context;
+               atomic_inc(&pd->usecnt);
+               atomic_set(&srq->usecnt, 0);
+       }
+
+       return srq;
+}
+EXPORT_SYMBOL(ib_create_srq);
+
+int ib_modify_srq(struct ib_srq *srq,
+                 struct ib_srq_attr *srq_attr,
+                 enum ib_srq_attr_mask srq_attr_mask)
+{
+       return srq->device->modify_srq(srq, srq_attr, srq_attr_mask);
+}
+EXPORT_SYMBOL(ib_modify_srq);
+
+int ib_query_srq(struct ib_srq *srq,
+                struct ib_srq_attr *srq_attr)
+{
+       return srq->device->query_srq ?
+               srq->device->query_srq(srq, srq_attr) : -ENOSYS;
+}
+EXPORT_SYMBOL(ib_query_srq);
+
+int ib_destroy_srq(struct ib_srq *srq)
+{
+       struct ib_pd *pd;
+       int ret;
+
+       if (atomic_read(&srq->usecnt))
+               return -EBUSY;
+
+       pd = srq->pd;
+
+       ret = srq->device->destroy_srq(srq);
+       if (!ret)
+               atomic_dec(&pd->usecnt);
+
+       return ret;
+}
+EXPORT_SYMBOL(ib_destroy_srq);
+
 /* Queue pairs */
 
 struct ib_qp *ib_create_qp(struct ib_pd *pd,
index 5dcbd43073e2454d3944b3fddf1006b325c0d0b5..c44f7bae5424fd8227430918ecfd264522569cd0 100644 (file)
@@ -1,5 +1,3 @@
-EXTRA_CFLAGS += -Idrivers/infiniband/include
-
 ifdef CONFIG_INFINIBAND_MTHCA_DEBUG
 EXTRA_CFLAGS += -DDEBUG
 endif
@@ -9,4 +7,4 @@ obj-$(CONFIG_INFINIBAND_MTHCA) += ib_mthca.o
 ib_mthca-y :=  mthca_main.o mthca_cmd.o mthca_profile.o mthca_reset.o \
                mthca_allocator.o mthca_eq.o mthca_pd.o mthca_cq.o \
                mthca_mr.o mthca_qp.o mthca_av.o mthca_mcg.o mthca_mad.o \
-               mthca_provider.o mthca_memfree.o mthca_uar.o
+               mthca_provider.o mthca_memfree.o mthca_uar.o mthca_srq.o
index b1db48dd91d6ee8ba484c178fa1e851cdb00bfe5..9ba3211cef7cb2a7747348420d5dbad3ff0ee18d 100644 (file)
@@ -177,3 +177,119 @@ void mthca_array_cleanup(struct mthca_array *array, int nent)
 
        kfree(array->page_list);
 }
+
+/*
+ * Handling for queue buffers -- we allocate a bunch of memory and
+ * register it in a memory region at HCA virtual address 0.  If the
+ * requested size is > max_direct, we split the allocation into
+ * multiple pages, so we don't require too much contiguous memory.
+ */
+
+int mthca_buf_alloc(struct mthca_dev *dev, int size, int max_direct,
+                   union mthca_buf *buf, int *is_direct, struct mthca_pd *pd,
+                   int hca_write, struct mthca_mr *mr)
+{
+       int err = -ENOMEM;
+       int npages, shift;
+       u64 *dma_list = NULL;
+       dma_addr_t t;
+       int i;
+
+       if (size <= max_direct) {
+               *is_direct = 1;
+               npages     = 1;
+               shift      = get_order(size) + PAGE_SHIFT;
+
+               buf->direct.buf = dma_alloc_coherent(&dev->pdev->dev,
+                                                    size, &t, GFP_KERNEL);
+               if (!buf->direct.buf)
+                       return -ENOMEM;
+
+               pci_unmap_addr_set(&buf->direct, mapping, t);
+
+               memset(buf->direct.buf, 0, size);
+
+               while (t & ((1 << shift) - 1)) {
+                       --shift;
+                       npages *= 2;
+               }
+
+               dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL);
+               if (!dma_list)
+                       goto err_free;
+
+               for (i = 0; i < npages; ++i)
+                       dma_list[i] = t + i * (1 << shift);
+       } else {
+               *is_direct = 0;
+               npages     = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+               shift      = PAGE_SHIFT;
+
+               dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL);
+               if (!dma_list)
+                       return -ENOMEM;
+
+               buf->page_list = kmalloc(npages * sizeof *buf->page_list,
+                                        GFP_KERNEL);
+               if (!buf->page_list)
+                       goto err_out;
+
+               for (i = 0; i < npages; ++i)
+                       buf->page_list[i].buf = NULL;
+
+               for (i = 0; i < npages; ++i) {
+                       buf->page_list[i].buf =
+                               dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
+                                                  &t, GFP_KERNEL);
+                       if (!buf->page_list[i].buf)
+                               goto err_free;
+
+                       dma_list[i] = t;
+                       pci_unmap_addr_set(&buf->page_list[i], mapping, t);
+
+                       memset(buf->page_list[i].buf, 0, PAGE_SIZE);
+               }
+       }
+
+       err = mthca_mr_alloc_phys(dev, pd->pd_num,
+                                 dma_list, shift, npages,
+                                 0, size,
+                                 MTHCA_MPT_FLAG_LOCAL_READ |
+                                 (hca_write ? MTHCA_MPT_FLAG_LOCAL_WRITE : 0),
+                                 mr);
+       if (err)
+               goto err_free;
+
+       kfree(dma_list);
+
+       return 0;
+
+err_free:
+       mthca_buf_free(dev, size, buf, *is_direct, NULL);
+
+err_out:
+       kfree(dma_list);
+
+       return err;
+}
+
+void mthca_buf_free(struct mthca_dev *dev, int size, union mthca_buf *buf,
+                   int is_direct, struct mthca_mr *mr)
+{
+       int i;
+
+       if (mr)
+               mthca_free_mr(dev, mr);
+
+       if (is_direct)
+               dma_free_coherent(&dev->pdev->dev, size, buf->direct.buf,
+                                 pci_unmap_addr(&buf->direct, mapping));
+       else {
+               for (i = 0; i < (size + PAGE_SIZE - 1) / PAGE_SIZE; ++i)
+                       dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+                                         buf->page_list[i].buf,
+                                         pci_unmap_addr(&buf->page_list[i],
+                                                        mapping));
+               kfree(buf->page_list);
+       }
+}
index d58dcbe66488080b3ccdfc497cfb7fdc19822aae..889e85096736c198ef2cbc6a6525cfafcd06c7ea 100644 (file)
 
 #include <linux/init.h>
 
-#include <ib_verbs.h>
-#include <ib_cache.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_cache.h>
 
 #include "mthca_dev.h"
 
 struct mthca_av {
-       u32 port_pd;
-       u8  reserved1;
-       u8  g_slid;
-       u16 dlid;
-       u8  reserved2;
-       u8  gid_index;
-       u8  msg_sr;
-       u8  hop_limit;
-       u32 sl_tclass_flowlabel;
-       u32 dgid[4];
+       __be32 port_pd;
+       u8     reserved1;
+       u8     g_slid;
+       __be16 dlid;
+       u8     reserved2;
+       u8     gid_index;
+       u8     msg_sr;
+       u8     hop_limit;
+       __be32 sl_tclass_flowlabel;
+       __be32 dgid[4];
 };
 
 int mthca_create_ah(struct mthca_dev *dev,
@@ -128,7 +128,7 @@ on_hca_fail:
                          av, (unsigned long) ah->avdma);
                for (j = 0; j < 8; ++j)
                        printk(KERN_DEBUG "  [%2x] %08x\n",
-                              j * 4, be32_to_cpu(((u32 *) av)[j]));
+                              j * 4, be32_to_cpu(((__be32 *) av)[j]));
        }
 
        if (ah->type == MTHCA_AH_ON_HCA) {
@@ -169,7 +169,7 @@ int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
 
        header->lrh.service_level   = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28;
        header->lrh.destination_lid = ah->av->dlid;
-       header->lrh.source_lid      = ah->av->g_slid & 0x7f;
+       header->lrh.source_lid      = cpu_to_be16(ah->av->g_slid & 0x7f);
        if (ah->av->g_slid & 0x80) {
                header->grh_present = 1;
                header->grh.traffic_class =
index 1557a522d8319a8e3e2c1bc497a933094a056f87..cc758a2d2bc6cad452f73b644ada7246ea2441bc 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -36,7 +37,7 @@
 #include <linux/pci.h>
 #include <linux/errno.h>
 #include <asm/io.h>
-#include <ib_mad.h>
+#include <rdma/ib_mad.h>
 
 #include "mthca_dev.h"
 #include "mthca_config_reg.h"
@@ -108,6 +109,7 @@ enum {
        CMD_SW2HW_SRQ       = 0x35,
        CMD_HW2SW_SRQ       = 0x36,
        CMD_QUERY_SRQ       = 0x37,
+       CMD_ARM_SRQ         = 0x40,
 
        /* QP/EE commands */
        CMD_RST2INIT_QPEE   = 0x19,
@@ -219,20 +221,20 @@ static int mthca_cmd_post(struct mthca_dev *dev,
         * (and some architectures such as ia64 implement memcpy_toio
         * in terms of writeb).
         */
-       __raw_writel(cpu_to_be32(in_param >> 32),           dev->hcr + 0 * 4);
-       __raw_writel(cpu_to_be32(in_param & 0xfffffffful),  dev->hcr + 1 * 4);
-       __raw_writel(cpu_to_be32(in_modifier),              dev->hcr + 2 * 4);
-       __raw_writel(cpu_to_be32(out_param >> 32),          dev->hcr + 3 * 4);
-       __raw_writel(cpu_to_be32(out_param & 0xfffffffful), dev->hcr + 4 * 4);
-       __raw_writel(cpu_to_be32(token << 16),              dev->hcr + 5 * 4);
+       __raw_writel((__force u32) cpu_to_be32(in_param >> 32),           dev->hcr + 0 * 4);
+       __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful),  dev->hcr + 1 * 4);
+       __raw_writel((__force u32) cpu_to_be32(in_modifier),              dev->hcr + 2 * 4);
+       __raw_writel((__force u32) cpu_to_be32(out_param >> 32),          dev->hcr + 3 * 4);
+       __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), dev->hcr + 4 * 4);
+       __raw_writel((__force u32) cpu_to_be32(token << 16),              dev->hcr + 5 * 4);
 
        /* __raw_writel may not order writes. */
        wmb();
 
-       __raw_writel(cpu_to_be32((1 << HCR_GO_BIT)                |
-                                (event ? (1 << HCA_E_BIT) : 0)   |
-                                (op_modifier << HCR_OPMOD_SHIFT) |
-                                op),                       dev->hcr + 6 * 4);
+       __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT)                |
+                                              (event ? (1 << HCA_E_BIT) : 0)   |
+                                              (op_modifier << HCR_OPMOD_SHIFT) |
+                                              op),                       dev->hcr + 6 * 4);
 
 out:
        up(&dev->cmd.hcr_sem);
@@ -273,12 +275,14 @@ static int mthca_cmd_poll(struct mthca_dev *dev,
                goto out;
        }
 
-       if (out_is_imm) {
-               memcpy_fromio(out_param, dev->hcr + HCR_OUT_PARAM_OFFSET, sizeof (u64));
-               be64_to_cpus(out_param);
-       }
+       if (out_is_imm)
+               *out_param = 
+                       (u64) be32_to_cpu((__force __be32)
+                                         __raw_readl(dev->hcr + HCR_OUT_PARAM_OFFSET)) << 32 |
+                       (u64) be32_to_cpu((__force __be32)
+                                         __raw_readl(dev->hcr + HCR_OUT_PARAM_OFFSET + 4));
 
-       *status = be32_to_cpu(__raw_readl(dev->hcr + HCR_STATUS_OFFSET)) >> 24;
+       *status = be32_to_cpu((__force __be32) __raw_readl(dev->hcr + HCR_STATUS_OFFSET)) >> 24;
 
 out:
        up(&dev->cmd.poll_sem);
@@ -1029,6 +1033,8 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
 
        mthca_dbg(dev, "Max QPs: %d, reserved QPs: %d, entry size: %d\n",
                  dev_lim->max_qps, dev_lim->reserved_qps, dev_lim->qpc_entry_sz);
+       mthca_dbg(dev, "Max SRQs: %d, reserved SRQs: %d, entry size: %d\n",
+                 dev_lim->max_srqs, dev_lim->reserved_srqs, dev_lim->srq_entry_sz);
        mthca_dbg(dev, "Max CQs: %d, reserved CQs: %d, entry size: %d\n",
                  dev_lim->max_cqs, dev_lim->reserved_cqs, dev_lim->cqc_entry_sz);
        mthca_dbg(dev, "Max EQs: %d, reserved EQs: %d, entry size: %d\n",
@@ -1082,6 +1088,34 @@ out:
        return err;
 }
 
+static void get_board_id(void *vsd, char *board_id)
+{
+       int i;
+
+#define VSD_OFFSET_SIG1                0x00
+#define VSD_OFFSET_SIG2                0xde
+#define VSD_OFFSET_MLX_BOARD_ID        0xd0
+#define VSD_OFFSET_TS_BOARD_ID 0x20
+
+#define VSD_SIGNATURE_TOPSPIN  0x5ad
+
+       memset(board_id, 0, MTHCA_BOARD_ID_LEN);
+
+       if (be16_to_cpup(vsd + VSD_OFFSET_SIG1) == VSD_SIGNATURE_TOPSPIN &&
+           be16_to_cpup(vsd + VSD_OFFSET_SIG2) == VSD_SIGNATURE_TOPSPIN) {
+               strlcpy(board_id, vsd + VSD_OFFSET_TS_BOARD_ID, MTHCA_BOARD_ID_LEN);
+       } else {
+               /*
+                * The board ID is a string but the firmware byte
+                * swaps each 4-byte word before passing it back to
+                * us.  Therefore we need to swab it before printing.
+                */
+               for (i = 0; i < 4; ++i)
+                       ((u32 *) board_id)[i] =
+                               swab32(*(u32 *) (vsd + VSD_OFFSET_MLX_BOARD_ID + i * 4));
+       }
+}
+
 int mthca_QUERY_ADAPTER(struct mthca_dev *dev,
                        struct mthca_adapter *adapter, u8 *status)
 {
@@ -1094,6 +1128,7 @@ int mthca_QUERY_ADAPTER(struct mthca_dev *dev,
 #define QUERY_ADAPTER_DEVICE_ID_OFFSET     0x04
 #define QUERY_ADAPTER_REVISION_ID_OFFSET   0x08
 #define QUERY_ADAPTER_INTA_PIN_OFFSET      0x10
+#define QUERY_ADAPTER_VSD_OFFSET           0x20
 
        mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
        if (IS_ERR(mailbox))
@@ -1111,6 +1146,9 @@ int mthca_QUERY_ADAPTER(struct mthca_dev *dev,
        MTHCA_GET(adapter->revision_id, outbox, QUERY_ADAPTER_REVISION_ID_OFFSET);
        MTHCA_GET(adapter->inta_pin, outbox,    QUERY_ADAPTER_INTA_PIN_OFFSET);
 
+       get_board_id(outbox + QUERY_ADAPTER_VSD_OFFSET / 4,
+                    adapter->board_id);
+
 out:
        mthca_free_mailbox(dev, mailbox);
        return err;
@@ -1121,7 +1159,7 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
                   u8 *status)
 {
        struct mthca_mailbox *mailbox;
-       u32 *inbox;
+       __be32 *inbox;
        int err;
 
 #define INIT_HCA_IN_SIZE                0x200
@@ -1247,10 +1285,8 @@ int mthca_INIT_IB(struct mthca_dev *dev,
 #define INIT_IB_FLAG_SIG         (1 << 18)
 #define INIT_IB_FLAG_NG          (1 << 17)
 #define INIT_IB_FLAG_G0          (1 << 16)
-#define INIT_IB_FLAG_1X          (1 << 8)
-#define INIT_IB_FLAG_4X          (1 << 9)
-#define INIT_IB_FLAG_12X         (1 << 11)
 #define INIT_IB_VL_SHIFT         4
+#define INIT_IB_PORT_WIDTH_SHIFT 8
 #define INIT_IB_MTU_SHIFT        12
 #define INIT_IB_MAX_GID_OFFSET   0x06
 #define INIT_IB_MAX_PKEY_OFFSET  0x0a
@@ -1266,12 +1302,11 @@ int mthca_INIT_IB(struct mthca_dev *dev,
        memset(inbox, 0, INIT_IB_IN_SIZE);
 
        flags = 0;
-       flags |= param->enable_1x     ? INIT_IB_FLAG_1X  : 0;
-       flags |= param->enable_4x     ? INIT_IB_FLAG_4X  : 0;
        flags |= param->set_guid0     ? INIT_IB_FLAG_G0  : 0;
        flags |= param->set_node_guid ? INIT_IB_FLAG_NG  : 0;
        flags |= param->set_si_guid   ? INIT_IB_FLAG_SIG : 0;
        flags |= param->vl_cap << INIT_IB_VL_SHIFT;
+       flags |= param->port_width << INIT_IB_PORT_WIDTH_SHIFT;
        flags |= param->mtu_cap << INIT_IB_MTU_SHIFT;
        MTHCA_PUT(inbox, flags, INIT_IB_FLAGS_OFFSET);
 
@@ -1342,7 +1377,7 @@ int mthca_MAP_ICM(struct mthca_dev *dev, struct mthca_icm *icm, u64 virt, u8 *st
 int mthca_MAP_ICM_page(struct mthca_dev *dev, u64 dma_addr, u64 virt, u8 *status)
 {
        struct mthca_mailbox *mailbox;
-       u64 *inbox;
+       __be64 *inbox;
        int err;
 
        mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
@@ -1468,6 +1503,27 @@ int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                             CMD_TIME_CLASS_A, status);
 }
 
+int mthca_SW2HW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
+                   int srq_num, u8 *status)
+{
+       return mthca_cmd(dev, mailbox->dma, srq_num, 0, CMD_SW2HW_SRQ,
+                       CMD_TIME_CLASS_A, status);
+}
+
+int mthca_HW2SW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
+                   int srq_num, u8 *status)
+{
+       return mthca_cmd_box(dev, 0, mailbox->dma, srq_num, 0,
+                            CMD_HW2SW_SRQ,
+                            CMD_TIME_CLASS_A, status);
+}
+
+int mthca_ARM_SRQ(struct mthca_dev *dev, int srq_num, int limit, u8 *status)
+{
+       return mthca_cmd(dev, limit, srq_num, 0, CMD_ARM_SRQ,
+                        CMD_TIME_CLASS_B, status);
+}
+
 int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
                    int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
                    u8 *status)
@@ -1513,7 +1569,7 @@ int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
                                if (i % 8 == 0)
                                        printk("  [%02x] ", i * 4);
                                printk(" %08x",
-                                      be32_to_cpu(((u32 *) mailbox->buf)[i + 2]));
+                                      be32_to_cpu(((__be32 *) mailbox->buf)[i + 2]));
                                if ((i + 1) % 8 == 0)
                                        printk("\n");
                        }
@@ -1533,7 +1589,7 @@ int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
                                if (i % 8 == 0)
                                        printk("[%02x] ", i * 4);
                                printk(" %08x",
-                                      be32_to_cpu(((u32 *) mailbox->buf)[i + 2]));
+                                      be32_to_cpu(((__be32 *) mailbox->buf)[i + 2]));
                                if ((i + 1) % 8 == 0)
                                        printk("\n");
                        }
index ed517f175dd6e68aee23bdbf8a4d97af82deab38..65f976a13e02065469c99001d41d2a09201853e7 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -35,7 +36,7 @@
 #ifndef MTHCA_CMD_H
 #define MTHCA_CMD_H
 
-#include <ib_verbs.h>
+#include <rdma/ib_verbs.h>
 
 #define MTHCA_MAILBOX_SIZE 4096
 
@@ -183,10 +184,11 @@ struct mthca_dev_lim {
 };
 
 struct mthca_adapter {
-       u32 vendor_id;
-       u32 device_id;
-       u32 revision_id;
-       u8  inta_pin;
+       u32  vendor_id;
+       u32  device_id;
+       u32  revision_id;
+       char board_id[MTHCA_BOARD_ID_LEN];
+       u8   inta_pin;
 };
 
 struct mthca_init_hca_param {
@@ -218,8 +220,7 @@ struct mthca_init_hca_param {
 };
 
 struct mthca_init_ib_param {
-       int enable_1x;
-       int enable_4x;
+       int port_width;
        int vl_cap;
        int mtu_cap;
        u16 gid_cap;
@@ -297,6 +298,11 @@ int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                   int cq_num, u8 *status);
 int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                   int cq_num, u8 *status);
+int mthca_SW2HW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
+                   int srq_num, u8 *status);
+int mthca_HW2SW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
+                   int srq_num, u8 *status);
+int mthca_ARM_SRQ(struct mthca_dev *dev, int srq_num, int limit, u8 *status);
 int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
                    int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
                    u8 *status);
index b4bfbbfe2c3df20a586dd8f71bc8cdf2a5d1dbf9..afa56bfaab2ee11e4e0d023084291a0eabd3f8d1 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
index 5687c3014522567140845aaa8ac3cde98df1539b..8600b6c3e0c262c72c45a8a281091238012619d8 100644 (file)
@@ -2,6 +2,8 @@
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  * Copyright (c) 2005 Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -37,7 +39,7 @@
 #include <linux/init.h>
 #include <linux/hardirq.h>
 
-#include <ib_pack.h>
+#include <rdma/ib_pack.h>
 
 #include "mthca_dev.h"
 #include "mthca_cmd.h"
@@ -55,21 +57,21 @@ enum {
  * Must be packed because start is 64 bits but only aligned to 32 bits.
  */
 struct mthca_cq_context {
-       u32 flags;
-       u64 start;
-       u32 logsize_usrpage;
-       u32 error_eqn;          /* Tavor only */
-       u32 comp_eqn;
-       u32 pd;
-       u32 lkey;
-       u32 last_notified_index;
-       u32 solicit_producer_index;
-       u32 consumer_index;
-       u32 producer_index;
-       u32 cqn;
-       u32 ci_db;              /* Arbel only */
-       u32 state_db;           /* Arbel only */
-       u32 reserved;
+       __be32 flags;
+       __be64 start;
+       __be32 logsize_usrpage;
+       __be32 error_eqn;       /* Tavor only */
+       __be32 comp_eqn;
+       __be32 pd;
+       __be32 lkey;
+       __be32 last_notified_index;
+       __be32 solicit_producer_index;
+       __be32 consumer_index;
+       __be32 producer_index;
+       __be32 cqn;
+       __be32 ci_db;           /* Arbel only */
+       __be32 state_db;        /* Arbel only */
+       u32    reserved;
 } __attribute__((packed));
 
 #define MTHCA_CQ_STATUS_OK          ( 0 << 28)
@@ -108,31 +110,31 @@ enum {
 };
 
 struct mthca_cqe {
-       u32 my_qpn;
-       u32 my_ee;
-       u32 rqpn;
-       u16 sl_g_mlpath;
-       u16 rlid;
-       u32 imm_etype_pkey_eec;
-       u32 byte_cnt;
-       u32 wqe;
-       u8  opcode;
-       u8  is_send;
-       u8  reserved;
-       u8  owner;
+       __be32 my_qpn;
+       __be32 my_ee;
+       __be32 rqpn;
+       __be16 sl_g_mlpath;
+       __be16 rlid;
+       __be32 imm_etype_pkey_eec;
+       __be32 byte_cnt;
+       __be32 wqe;
+       u8     opcode;
+       u8     is_send;
+       u8     reserved;
+       u8     owner;
 };
 
 struct mthca_err_cqe {
-       u32 my_qpn;
-       u32 reserved1[3];
-       u8  syndrome;
-       u8  reserved2;
-       u16 db_cnt;
-       u32 reserved3;
-       u32 wqe;
-       u8  opcode;
-       u8  reserved4[2];
-       u8  owner;
+       __be32 my_qpn;
+       u32    reserved1[3];
+       u8     syndrome;
+       u8     reserved2;
+       __be16 db_cnt;
+       u32    reserved3;
+       __be32 wqe;
+       u8     opcode;
+       u8     reserved4[2];
+       u8     owner;
 };
 
 #define MTHCA_CQ_ENTRY_OWNER_SW      (0 << 7)
@@ -191,7 +193,7 @@ static void dump_cqe(struct mthca_dev *dev, void *cqe_ptr)
 static inline void update_cons_index(struct mthca_dev *dev, struct mthca_cq *cq,
                                     int incr)
 {
-       u32 doorbell[2];
+       __be32 doorbell[2];
 
        if (mthca_is_memfree(dev)) {
                *cq->set_ci_db = cpu_to_be32(cq->cons_index);
@@ -222,7 +224,8 @@ void mthca_cq_event(struct mthca_dev *dev, u32 cqn)
        cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context);
 }
 
-void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn)
+void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn,
+                   struct mthca_srq *srq)
 {
        struct mthca_cq *cq;
        struct mthca_cqe *cqe;
@@ -263,8 +266,11 @@ void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn)
         */
        while (prod_index > cq->cons_index) {
                cqe = get_cqe(cq, (prod_index - 1) & cq->ibcq.cqe);
-               if (cqe->my_qpn == cpu_to_be32(qpn))
+               if (cqe->my_qpn == cpu_to_be32(qpn)) {
+                       if (srq)
+                               mthca_free_srq_wqe(srq, be32_to_cpu(cqe->wqe));
                        ++nfreed;
+               }
                else if (nfreed)
                        memcpy(get_cqe(cq, (prod_index - 1 + nfreed) &
                                       cq->ibcq.cqe),
@@ -291,7 +297,7 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
 {
        int err;
        int dbd;
-       u32 new_wqe;
+       __be32 new_wqe;
 
        if (cqe->syndrome == SYNDROME_LOCAL_QP_OP_ERR) {
                mthca_dbg(dev, "local QP operation err "
@@ -365,6 +371,13 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
                break;
        }
 
+       /*
+        * Mem-free HCAs always generate one CQE per WQE, even in the
+        * error case, so we don't have to check the doorbell count, etc.
+        */
+       if (mthca_is_memfree(dev))
+               return 0;
+
        err = mthca_free_err_wqe(dev, qp, is_send, wqe_index, &dbd, &new_wqe);
        if (err)
                return err;
@@ -373,12 +386,8 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
         * If we're at the end of the WQE chain, or we've used up our
         * doorbell count, free the CQE.  Otherwise just update it for
         * the next poll operation.
-        *
-        * This does not apply to mem-free HCAs: they don't use the
-        * doorbell count field, and so we should always free the CQE.
         */
-       if (mthca_is_memfree(dev) ||
-           !(new_wqe & cpu_to_be32(0x3f)) || (!cqe->db_cnt && dbd))
+       if (!(new_wqe & cpu_to_be32(0x3f)) || (!cqe->db_cnt && dbd))
                return 0;
 
        cqe->db_cnt   = cpu_to_be16(be16_to_cpu(cqe->db_cnt) - dbd);
@@ -450,23 +459,27 @@ static inline int mthca_poll_one(struct mthca_dev *dev,
                             >> wq->wqe_shift);
                entry->wr_id = (*cur_qp)->wrid[wqe_index +
                                               (*cur_qp)->rq.max];
+       } else if ((*cur_qp)->ibqp.srq) {
+               struct mthca_srq *srq = to_msrq((*cur_qp)->ibqp.srq);
+               u32 wqe = be32_to_cpu(cqe->wqe);
+               wq = NULL;
+               wqe_index = wqe >> srq->wqe_shift;
+               entry->wr_id = srq->wrid[wqe_index];
+               mthca_free_srq_wqe(srq, wqe);
        } else {
                wq = &(*cur_qp)->rq;
                wqe_index = be32_to_cpu(cqe->wqe) >> wq->wqe_shift;
                entry->wr_id = (*cur_qp)->wrid[wqe_index];
        }
 
-       if (wq->last_comp < wqe_index)
-               wq->tail += wqe_index - wq->last_comp;
-       else
-               wq->tail += wqe_index + wq->max - wq->last_comp;
-
-       wq->last_comp = wqe_index;
+       if (wq) {
+               if (wq->last_comp < wqe_index)
+                       wq->tail += wqe_index - wq->last_comp;
+               else
+                       wq->tail += wqe_index + wq->max - wq->last_comp;
 
-       if (0)
-               mthca_dbg(dev, "%s completion for QP %06x, index %d (nr %d)\n",
-                         is_send ? "Send" : "Receive",
-                         (*cur_qp)->qpn, wqe_index, wq->max);
+               wq->last_comp = wqe_index;
+       }
 
        if (is_error) {
                err = handle_error_cqe(dev, cq, *cur_qp, wqe_index, is_send,
@@ -584,13 +597,13 @@ int mthca_poll_cq(struct ib_cq *ibcq, int num_entries,
 
 int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify)
 {
-       u32 doorbell[2];
+       __be32 doorbell[2];
 
        doorbell[0] = cpu_to_be32((notify == IB_CQ_SOLICITED ?
                                   MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL :
                                   MTHCA_TAVOR_CQ_DB_REQ_NOT)      |
                                  to_mcq(cq)->cqn);
-       doorbell[1] = 0xffffffff;
+       doorbell[1] = (__force __be32) 0xffffffff;
 
        mthca_write64(doorbell,
                      to_mdev(cq->device)->kar + MTHCA_CQ_DOORBELL,
@@ -602,9 +615,9 @@ int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify)
 int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
 {
        struct mthca_cq *cq = to_mcq(ibcq);
-       u32 doorbell[2];
+       __be32 doorbell[2];
        u32 sn;
-       u32 ci;
+       __be32 ci;
 
        sn = cq->arm_sn & 3;
        ci = cpu_to_be32(cq->cons_index);
@@ -637,113 +650,8 @@ int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
 
 static void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq *cq)
 {
-       int i;
-       int size;
-
-       if (cq->is_direct)
-               dma_free_coherent(&dev->pdev->dev,
-                                 (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
-                                 cq->queue.direct.buf,
-                                 pci_unmap_addr(&cq->queue.direct,
-                                                mapping));
-       else {
-               size = (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE;
-               for (i = 0; i < (size + PAGE_SIZE - 1) / PAGE_SIZE; ++i)
-                       if (cq->queue.page_list[i].buf)
-                               dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
-                                                 cq->queue.page_list[i].buf,
-                                                 pci_unmap_addr(&cq->queue.page_list[i],
-                                                                mapping));
-
-               kfree(cq->queue.page_list);
-       }
-}
-
-static int mthca_alloc_cq_buf(struct mthca_dev *dev, int size,
-                             struct mthca_cq *cq)
-{
-       int err = -ENOMEM;
-       int npages, shift;
-       u64 *dma_list = NULL;
-       dma_addr_t t;
-       int i;
-
-       if (size <= MTHCA_MAX_DIRECT_CQ_SIZE) {
-               cq->is_direct = 1;
-               npages        = 1;
-               shift         = get_order(size) + PAGE_SHIFT;
-
-               cq->queue.direct.buf = dma_alloc_coherent(&dev->pdev->dev,
-                                                         size, &t, GFP_KERNEL);
-               if (!cq->queue.direct.buf)
-                       return -ENOMEM;
-
-               pci_unmap_addr_set(&cq->queue.direct, mapping, t);
-
-               memset(cq->queue.direct.buf, 0, size);
-
-               while (t & ((1 << shift) - 1)) {
-                       --shift;
-                       npages *= 2;
-               }
-
-               dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL);
-               if (!dma_list)
-                       goto err_free;
-
-               for (i = 0; i < npages; ++i)
-                       dma_list[i] = t + i * (1 << shift);
-       } else {
-               cq->is_direct = 0;
-               npages        = (size + PAGE_SIZE - 1) / PAGE_SIZE;
-               shift         = PAGE_SHIFT;
-
-               dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL);
-               if (!dma_list)
-                       return -ENOMEM;
-
-               cq->queue.page_list = kmalloc(npages * sizeof *cq->queue.page_list,
-                                             GFP_KERNEL);
-               if (!cq->queue.page_list)
-                       goto err_out;
-
-               for (i = 0; i < npages; ++i)
-                       cq->queue.page_list[i].buf = NULL;
-
-               for (i = 0; i < npages; ++i) {
-                       cq->queue.page_list[i].buf =
-                               dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
-                                                  &t, GFP_KERNEL);
-                       if (!cq->queue.page_list[i].buf)
-                               goto err_free;
-
-                       dma_list[i] = t;
-                       pci_unmap_addr_set(&cq->queue.page_list[i], mapping, t);
-
-                       memset(cq->queue.page_list[i].buf, 0, PAGE_SIZE);
-               }
-       }
-
-       err = mthca_mr_alloc_phys(dev, dev->driver_pd.pd_num,
-                                 dma_list, shift, npages,
-                                 0, size,
-                                 MTHCA_MPT_FLAG_LOCAL_WRITE |
-                                 MTHCA_MPT_FLAG_LOCAL_READ,
-                                 &cq->mr);
-       if (err)
-               goto err_free;
-
-       kfree(dma_list);
-
-       return 0;
-
-err_free:
-       mthca_free_cq_buf(dev, cq);
-
-err_out:
-       kfree(dma_list);
-
-       return err;
+       mthca_buf_free(dev, (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
+                      &cq->queue, cq->is_direct, &cq->mr);
 }
 
 int mthca_init_cq(struct mthca_dev *dev, int nent,
@@ -795,7 +703,9 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
        cq_context = mailbox->buf;
 
        if (cq->is_kernel) {
-               err = mthca_alloc_cq_buf(dev, size, cq);
+               err = mthca_buf_alloc(dev, size, MTHCA_MAX_DIRECT_CQ_SIZE,
+                                     &cq->queue, &cq->is_direct,
+                                     &dev->driver_pd, 1, &cq->mr);
                if (err)
                        goto err_out_mailbox;
 
@@ -811,7 +721,6 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
        cq_context->flags           = cpu_to_be32(MTHCA_CQ_STATUS_OK      |
                                                  MTHCA_CQ_STATE_DISARMED |
                                                  MTHCA_CQ_FLAG_TR);
-       cq_context->start           = cpu_to_be64(0);
        cq_context->logsize_usrpage = cpu_to_be32((ffs(nent) - 1) << 24);
        if (ctx)
                cq_context->logsize_usrpage |= cpu_to_be32(ctx->uar.index);
@@ -857,10 +766,8 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
        return 0;
 
 err_out_free_mr:
-       if (cq->is_kernel) {
-               mthca_free_mr(dev, &cq->mr);
+       if (cq->is_kernel)
                mthca_free_cq_buf(dev, cq);
-       }
 
 err_out_mailbox:
        mthca_free_mailbox(dev, mailbox);
@@ -904,7 +811,7 @@ void mthca_free_cq(struct mthca_dev *dev,
                mthca_warn(dev, "HW2SW_CQ returned status 0x%02x\n", status);
 
        if (0) {
-               u32 *ctx = mailbox->buf;
+               __be32 *ctx = mailbox->buf;
                int j;
 
                printk(KERN_ERR "context for CQN %x (cons index %x, next sw %d)\n",
@@ -928,7 +835,6 @@ void mthca_free_cq(struct mthca_dev *dev,
        wait_event(cq->wait, !atomic_read(&cq->refcount));
 
        if (cq->is_kernel) {
-               mthca_free_mr(dev, &cq->mr);
                mthca_free_cq_buf(dev, cq);
                if (mthca_is_memfree(dev)) {
                        mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM,    cq->arm_db_index);
index 5ecdd2eeeb0f0c18ac3e96e8c8b140acaee895ec..7bff5a8425f4e5c5fbd7eb634a78b13eb8a3b88f 100644 (file)
@@ -2,6 +2,8 @@
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -66,6 +68,10 @@ enum {
        MTHCA_MAX_PORTS = 2
 };
 
+enum {
+       MTHCA_BOARD_ID_LEN = 64
+};
+
 enum {
        MTHCA_EQ_CONTEXT_SIZE =  0x40,
        MTHCA_CQ_CONTEXT_SIZE =  0x40,
@@ -142,6 +148,7 @@ struct mthca_limits {
        int      reserved_mcgs;
        int      num_pds;
        int      reserved_pds;
+       u8       port_width_cap;
 };
 
 struct mthca_alloc {
@@ -211,6 +218,13 @@ struct mthca_cq_table {
        struct mthca_icm_table *table;
 };
 
+struct mthca_srq_table {
+       struct mthca_alloc      alloc;
+       spinlock_t              lock;
+       struct mthca_array      srq;
+       struct mthca_icm_table *table;
+};
+
 struct mthca_qp_table {
        struct mthca_alloc      alloc;
        u32                     rdb_base;
@@ -246,6 +260,7 @@ struct mthca_dev {
        unsigned long    device_cap_flags;
 
        u32              rev_id;
+       char             board_id[MTHCA_BOARD_ID_LEN];
 
        /* firmware info */
        u64              fw_ver;
@@ -291,6 +306,7 @@ struct mthca_dev {
        struct mthca_mr_table  mr_table;
        struct mthca_eq_table  eq_table;
        struct mthca_cq_table  cq_table;
+       struct mthca_srq_table srq_table;
        struct mthca_qp_table  qp_table;
        struct mthca_av_table  av_table;
        struct mthca_mcg_table mcg_table;
@@ -331,14 +347,13 @@ extern void __buggy_use_of_MTHCA_PUT(void);
 
 #define MTHCA_PUT(dest, source, offset)                               \
        do {                                                          \
-               __typeof__(source) *__p =                             \
-                       (__typeof__(source) *) ((char *) (dest) + (offset)); \
+               void *__d = ((char *) (dest) + (offset));             \
                switch (sizeof(source)) {                             \
-                       case 1: *__p = (source);            break;    \
-                       case 2: *__p = cpu_to_be16(source); break;    \
-                       case 4: *__p = cpu_to_be32(source); break;    \
-                       case 8: *__p = cpu_to_be64(source); break;    \
-                       default: __buggy_use_of_MTHCA_PUT();          \
+               case 1: *(u8 *) __d = (source);                break; \
+               case 2: *(__be16 *) __d = cpu_to_be16(source); break; \
+               case 4: *(__be32 *) __d = cpu_to_be32(source); break; \
+               case 8: *(__be64 *) __d = cpu_to_be64(source); break; \
+               default: __buggy_use_of_MTHCA_PUT();                  \
                }                                                     \
        } while (0)
 
@@ -354,12 +369,18 @@ int mthca_array_set(struct mthca_array *array, int index, void *value);
 void mthca_array_clear(struct mthca_array *array, int index);
 int mthca_array_init(struct mthca_array *array, int nent);
 void mthca_array_cleanup(struct mthca_array *array, int nent);
+int mthca_buf_alloc(struct mthca_dev *dev, int size, int max_direct,
+                   union mthca_buf *buf, int *is_direct, struct mthca_pd *pd,
+                   int hca_write, struct mthca_mr *mr);
+void mthca_buf_free(struct mthca_dev *dev, int size, union mthca_buf *buf,
+                   int is_direct, struct mthca_mr *mr);
 
 int mthca_init_uar_table(struct mthca_dev *dev);
 int mthca_init_pd_table(struct mthca_dev *dev);
 int mthca_init_mr_table(struct mthca_dev *dev);
 int mthca_init_eq_table(struct mthca_dev *dev);
 int mthca_init_cq_table(struct mthca_dev *dev);
+int mthca_init_srq_table(struct mthca_dev *dev);
 int mthca_init_qp_table(struct mthca_dev *dev);
 int mthca_init_av_table(struct mthca_dev *dev);
 int mthca_init_mcg_table(struct mthca_dev *dev);
@@ -369,6 +390,7 @@ void mthca_cleanup_pd_table(struct mthca_dev *dev);
 void mthca_cleanup_mr_table(struct mthca_dev *dev);
 void mthca_cleanup_eq_table(struct mthca_dev *dev);
 void mthca_cleanup_cq_table(struct mthca_dev *dev);
+void mthca_cleanup_srq_table(struct mthca_dev *dev);
 void mthca_cleanup_qp_table(struct mthca_dev *dev);
 void mthca_cleanup_av_table(struct mthca_dev *dev);
 void mthca_cleanup_mcg_table(struct mthca_dev *dev);
@@ -419,7 +441,19 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
 void mthca_free_cq(struct mthca_dev *dev,
                   struct mthca_cq *cq);
 void mthca_cq_event(struct mthca_dev *dev, u32 cqn);
-void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn);
+void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn,
+                   struct mthca_srq *srq);
+
+int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
+                   struct ib_srq_attr *attr, struct mthca_srq *srq);
+void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq);
+void mthca_srq_event(struct mthca_dev *dev, u32 srqn,
+                    enum ib_event_type event_type);
+void mthca_free_srq_wqe(struct mthca_srq *srq, u32 wqe_addr);
+int mthca_tavor_post_srq_recv(struct ib_srq *srq, struct ib_recv_wr *wr,
+                             struct ib_recv_wr **bad_wr);
+int mthca_arbel_post_srq_recv(struct ib_srq *srq, struct ib_recv_wr *wr,
+                             struct ib_recv_wr **bad_wr);
 
 void mthca_qp_event(struct mthca_dev *dev, u32 qpn,
                    enum ib_event_type event_type);
@@ -433,7 +467,7 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 int mthca_arbel_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
                             struct ib_recv_wr **bad_wr);
 int mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
-                      int index, int *dbd, u32 *new_wqe);
+                      int index, int *dbd, __be32 *new_wqe);
 int mthca_alloc_qp(struct mthca_dev *dev,
                   struct mthca_pd *pd,
                   struct mthca_cq *send_cq,
index 535fad7710fb7129e7d9b2cea96c981cc1d9436e..dd9a44d170c9e951e60517b6a3c0c77b03163b04 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -57,13 +58,13 @@ static inline void mthca_write64_raw(__be64 val, void __iomem *dest)
        __raw_writeq((__force u64) val, dest);
 }
 
-static inline void mthca_write64(u32 val[2], void __iomem *dest,
+static inline void mthca_write64(__be32 val[2], void __iomem *dest,
                                 spinlock_t *doorbell_lock)
 {
        __raw_writeq(*(u64 *) val, dest);
 }
 
-static inline void mthca_write_db_rec(u32 val[2], u32 *db)
+static inline void mthca_write_db_rec(__be32 val[2], __be32 *db)
 {
        *(u64 *) db = *(u64 *) val;
 }
@@ -86,18 +87,18 @@ static inline void mthca_write64_raw(__be64 val, void __iomem *dest)
        __raw_writel(((__force u32 *) &val)[1], dest + 4);
 }
 
-static inline void mthca_write64(u32 val[2], void __iomem *dest,
+static inline void mthca_write64(__be32 val[2], void __iomem *dest,
                                 spinlock_t *doorbell_lock)
 {
        unsigned long flags;
 
        spin_lock_irqsave(doorbell_lock, flags);
-       __raw_writel(val[0], dest);
-       __raw_writel(val[1], dest + 4);
+       __raw_writel((__force u32) val[0], dest);
+       __raw_writel((__force u32) val[1], dest + 4);
        spin_unlock_irqrestore(doorbell_lock, flags);
 }
 
-static inline void mthca_write_db_rec(u32 val[2], u32 *db)
+static inline void mthca_write_db_rec(__be32 val[2], __be32 *db)
 {
        db[0] = val[0];
        wmb();
index cbcf2b4722e4598e7f520add89dbb6868329fde7..18f0981eb0c15e977c587ccf052d590f51f1ed85 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -51,18 +52,18 @@ enum {
  * Must be packed because start is 64 bits but only aligned to 32 bits.
  */
 struct mthca_eq_context {
-       u32 flags;
-       u64 start;
-       u32 logsize_usrpage;
-       u32 tavor_pd;           /* reserved for Arbel */
-       u8  reserved1[3];
-       u8  intr;
-       u32 arbel_pd;           /* lost_count for Tavor */
-       u32 lkey;
-       u32 reserved2[2];
-       u32 consumer_index;
-       u32 producer_index;
-       u32 reserved3[4];
+       __be32 flags;
+       __be64 start;
+       __be32 logsize_usrpage;
+       __be32 tavor_pd;        /* reserved for Arbel */
+       u8     reserved1[3];
+       u8     intr;
+       __be32 arbel_pd;        /* lost_count for Tavor */
+       __be32 lkey;
+       u32    reserved2[2];
+       __be32 consumer_index;
+       __be32 producer_index;
+       u32    reserved3[4];
 } __attribute__((packed));
 
 #define MTHCA_EQ_STATUS_OK          ( 0 << 28)
@@ -127,28 +128,28 @@ struct mthca_eqe {
        union {
                u32 raw[6];
                struct {
-                       u32 cqn;
+                       __be32 cqn;
                } __attribute__((packed)) comp;
                struct {
-                       u16 reserved1;
-                       u16 token;
-                       u32 reserved2;
-                       u8  reserved3[3];
-                       u8  status;
-                       u64 out_param;
+                       u16    reserved1;
+                       __be16 token;
+                       u32    reserved2;
+                       u8     reserved3[3];
+                       u8     status;
+                       __be64 out_param;
                } __attribute__((packed)) cmd;
                struct {
-                       u32 qpn;
+                       __be32 qpn;
                } __attribute__((packed)) qp;
                struct {
-                       u32 cqn;
-                       u32 reserved1;
-                       u8  reserved2[3];
-                       u8  syndrome;
+                       __be32 cqn;
+                       u32    reserved1;
+                       u8     reserved2[3];
+                       u8     syndrome;
                } __attribute__((packed)) cq_err;
                struct {
-                       u32 reserved1[2];
-                       u32 port;
+                       u32    reserved1[2];
+                       __be32 port;
                } __attribute__((packed)) port_change;
        } event;
        u8 reserved3[3];
@@ -167,7 +168,7 @@ static inline u64 async_mask(struct mthca_dev *dev)
 
 static inline void tavor_set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)
 {
-       u32 doorbell[2];
+       __be32 doorbell[2];
 
        doorbell[0] = cpu_to_be32(MTHCA_EQ_DB_SET_CI | eq->eqn);
        doorbell[1] = cpu_to_be32(ci & (eq->nent - 1));
@@ -190,8 +191,8 @@ static inline void arbel_set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u
 {
        /* See comment in tavor_set_eq_ci() above. */
        wmb();
-       __raw_writel(cpu_to_be32(ci), dev->eq_regs.arbel.eq_set_ci_base +
-                    eq->eqn * 8);
+       __raw_writel((__force u32) cpu_to_be32(ci),
+                    dev->eq_regs.arbel.eq_set_ci_base + eq->eqn * 8);
        /* We still want ordering, just not swabbing, so add a barrier */
        mb();
 }
@@ -206,7 +207,7 @@ static inline void set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)
 
 static inline void tavor_eq_req_not(struct mthca_dev *dev, int eqn)
 {
-       u32 doorbell[2];
+       __be32 doorbell[2];
 
        doorbell[0] = cpu_to_be32(MTHCA_EQ_DB_REQ_NOT | eqn);
        doorbell[1] = 0;
@@ -224,7 +225,7 @@ static inline void arbel_eq_req_not(struct mthca_dev *dev, u32 eqn_mask)
 static inline void disarm_cq(struct mthca_dev *dev, int eqn, int cqn)
 {
        if (!mthca_is_memfree(dev)) {
-               u32 doorbell[2];
+               __be32 doorbell[2];
 
                doorbell[0] = cpu_to_be32(MTHCA_EQ_DB_DISARM_CQ | eqn);
                doorbell[1] = cpu_to_be32(cqn);
index 7df2236420155eaa687d22122b98b2c9fd46cc4e..9804174f7f3c5b9594f337c4dcdf16a4554deef5 100644 (file)
@@ -1,5 +1,7 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -32,9 +34,9 @@
  * $Id: mthca_mad.c 1349 2004-12-16 21:09:43Z roland $
  */
 
-#include <ib_verbs.h>
-#include <ib_mad.h>
-#include <ib_smi.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_mad.h>
+#include <rdma/ib_smi.h>
 
 #include "mthca_dev.h"
 #include "mthca_cmd.h"
@@ -192,7 +194,7 @@ int mthca_process_mad(struct ib_device *ibdev,
 {
        int err;
        u8 status;
-       u16 slid = in_wc ? in_wc->slid : IB_LID_PERMISSIVE;
+       u16 slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE);
 
        /* Forward locally generated traps to the SM */
        if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP &&
index 2ef916859e1752427864a973df28ac27f8c006b9..3241d6c9dc11d2f2a959224f22cd58070449d0b5 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -34,7 +35,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/errno.h>
@@ -171,6 +171,7 @@ static int __devinit mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim
        mdev->limits.reserved_mrws      = dev_lim->reserved_mrws;
        mdev->limits.reserved_uars      = dev_lim->reserved_uars;
        mdev->limits.reserved_pds       = dev_lim->reserved_pds;
+       mdev->limits.port_width_cap     = dev_lim->max_port_width;
 
        /* IB_DEVICE_RESIZE_MAX_WR not supported by driver.
           May be doable since hardware supports it for SRQ.
@@ -212,7 +213,6 @@ static int __devinit mthca_init_tavor(struct mthca_dev *mdev)
        struct mthca_dev_lim        dev_lim;
        struct mthca_profile        profile;
        struct mthca_init_hca_param init_hca;
-       struct mthca_adapter        adapter;
 
        err = mthca_SYS_EN(mdev, &status);
        if (err) {
@@ -253,6 +253,8 @@ static int __devinit mthca_init_tavor(struct mthca_dev *mdev)
        profile = default_profile;
        profile.num_uar   = dev_lim.uar_size / PAGE_SIZE;
        profile.uarc_size = 0;
+       if (mdev->mthca_flags & MTHCA_FLAG_SRQ)
+               profile.num_srq = dev_lim.max_srqs;
 
        err = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca);
        if (err < 0)
@@ -270,26 +272,8 @@ static int __devinit mthca_init_tavor(struct mthca_dev *mdev)
                goto err_disable;
        }
 
-       err = mthca_QUERY_ADAPTER(mdev, &adapter, &status);
-       if (err) {
-               mthca_err(mdev, "QUERY_ADAPTER command failed, aborting.\n");
-               goto err_close;
-       }
-       if (status) {
-               mthca_err(mdev, "QUERY_ADAPTER returned status 0x%02x, "
-                         "aborting.\n", status);
-               err = -EINVAL;
-               goto err_close;
-       }
-
-       mdev->eq_table.inta_pin = adapter.inta_pin;
-       mdev->rev_id            = adapter.revision_id;
-
        return 0;
 
-err_close:
-       mthca_CLOSE_HCA(mdev, 0, &status);
-
 err_disable:
        mthca_SYS_DIS(mdev, &status);
 
@@ -442,15 +426,29 @@ static int __devinit mthca_init_icm(struct mthca_dev *mdev,
        }
 
        mdev->cq_table.table = mthca_alloc_icm_table(mdev, init_hca->cqc_base,
-                                                    dev_lim->cqc_entry_sz,
-                                                    mdev->limits.num_cqs,
-                                                    mdev->limits.reserved_cqs, 0);
+                                                   dev_lim->cqc_entry_sz,
+                                                   mdev->limits.num_cqs,
+                                                   mdev->limits.reserved_cqs, 0);
        if (!mdev->cq_table.table) {
                mthca_err(mdev, "Failed to map CQ context memory, aborting.\n");
                err = -ENOMEM;
                goto err_unmap_rdb;
        }
 
+       if (mdev->mthca_flags & MTHCA_FLAG_SRQ) {
+               mdev->srq_table.table =
+                       mthca_alloc_icm_table(mdev, init_hca->srqc_base,
+                                             dev_lim->srq_entry_sz,
+                                             mdev->limits.num_srqs,
+                                             mdev->limits.reserved_srqs, 0);
+               if (!mdev->srq_table.table) {
+                       mthca_err(mdev, "Failed to map SRQ context memory, "
+                                 "aborting.\n");
+                       err = -ENOMEM;
+                       goto err_unmap_cq;
+               }
+       }
+
        /*
         * It's not strictly required, but for simplicity just map the
         * whole multicast group table now.  The table isn't very big
@@ -466,11 +464,15 @@ static int __devinit mthca_init_icm(struct mthca_dev *mdev,
        if (!mdev->mcg_table.table) {
                mthca_err(mdev, "Failed to map MCG context memory, aborting.\n");
                err = -ENOMEM;
-               goto err_unmap_cq;
+               goto err_unmap_srq;
        }
 
        return 0;
 
+err_unmap_srq:
+       if (mdev->mthca_flags & MTHCA_FLAG_SRQ)
+               mthca_free_icm_table(mdev, mdev->srq_table.table);
+
 err_unmap_cq:
        mthca_free_icm_table(mdev, mdev->cq_table.table);
 
@@ -506,7 +508,6 @@ static int __devinit mthca_init_arbel(struct mthca_dev *mdev)
        struct mthca_dev_lim        dev_lim;
        struct mthca_profile        profile;
        struct mthca_init_hca_param init_hca;
-       struct mthca_adapter        adapter;
        u64 icm_size;
        u8 status;
        int err;
@@ -551,6 +552,8 @@ static int __devinit mthca_init_arbel(struct mthca_dev *mdev)
        profile = default_profile;
        profile.num_uar  = dev_lim.uar_size / PAGE_SIZE;
        profile.num_udav = 0;
+       if (mdev->mthca_flags & MTHCA_FLAG_SRQ)
+               profile.num_srq = dev_lim.max_srqs;
 
        icm_size = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca);
        if ((int) icm_size < 0) {
@@ -574,24 +577,11 @@ static int __devinit mthca_init_arbel(struct mthca_dev *mdev)
                goto err_free_icm;
        }
 
-       err = mthca_QUERY_ADAPTER(mdev, &adapter, &status);
-       if (err) {
-               mthca_err(mdev, "QUERY_ADAPTER command failed, aborting.\n");
-               goto err_free_icm;
-       }
-       if (status) {
-               mthca_err(mdev, "QUERY_ADAPTER returned status 0x%02x, "
-                         "aborting.\n", status);
-               err = -EINVAL;
-               goto err_free_icm;
-       }
-
-       mdev->eq_table.inta_pin = adapter.inta_pin;
-       mdev->rev_id            = adapter.revision_id;
-
        return 0;
 
 err_free_icm:
+       if (mdev->mthca_flags & MTHCA_FLAG_SRQ)
+               mthca_free_icm_table(mdev, mdev->srq_table.table);
        mthca_free_icm_table(mdev, mdev->cq_table.table);
        mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);
        mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);
@@ -614,12 +604,70 @@ err_disable:
        return err;
 }
 
+static void mthca_close_hca(struct mthca_dev *mdev)
+{
+       u8 status;
+
+       mthca_CLOSE_HCA(mdev, 0, &status);
+
+       if (mthca_is_memfree(mdev)) {
+               if (mdev->mthca_flags & MTHCA_FLAG_SRQ)
+                       mthca_free_icm_table(mdev, mdev->srq_table.table);
+               mthca_free_icm_table(mdev, mdev->cq_table.table);
+               mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);
+               mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);
+               mthca_free_icm_table(mdev, mdev->qp_table.qp_table);
+               mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);
+               mthca_free_icm_table(mdev, mdev->mr_table.mtt_table);
+               mthca_unmap_eq_icm(mdev);
+
+               mthca_UNMAP_ICM_AUX(mdev, &status);
+               mthca_free_icm(mdev, mdev->fw.arbel.aux_icm);
+
+               mthca_UNMAP_FA(mdev, &status);
+               mthca_free_icm(mdev, mdev->fw.arbel.fw_icm);
+
+               if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM))
+                       mthca_DISABLE_LAM(mdev, &status);
+       } else
+               mthca_SYS_DIS(mdev, &status);
+}
+
 static int __devinit mthca_init_hca(struct mthca_dev *mdev)
 {
+       u8 status;
+       int err;
+       struct mthca_adapter adapter;
+
        if (mthca_is_memfree(mdev))
-               return mthca_init_arbel(mdev);
+               err = mthca_init_arbel(mdev);
        else
-               return mthca_init_tavor(mdev);
+               err = mthca_init_tavor(mdev);
+
+       if (err)
+               return err;
+
+       err = mthca_QUERY_ADAPTER(mdev, &adapter, &status);
+       if (err) {
+               mthca_err(mdev, "QUERY_ADAPTER command failed, aborting.\n");
+               goto err_close;
+       }
+       if (status) {
+               mthca_err(mdev, "QUERY_ADAPTER returned status 0x%02x, "
+                         "aborting.\n", status);
+               err = -EINVAL;
+               goto err_close;
+       }
+
+       mdev->eq_table.inta_pin = adapter.inta_pin;
+       mdev->rev_id            = adapter.revision_id;
+       memcpy(mdev->board_id, adapter.board_id, sizeof mdev->board_id);
+
+       return 0;
+
+err_close:
+       mthca_close_hca(mdev);
+       return err;
 }
 
 static int __devinit mthca_setup_hca(struct mthca_dev *dev)
@@ -709,11 +757,18 @@ static int __devinit mthca_setup_hca(struct mthca_dev *dev)
                goto err_cmd_poll;
        }
 
+       err = mthca_init_srq_table(dev);
+       if (err) {
+               mthca_err(dev, "Failed to initialize "
+                         "shared receive queue table, aborting.\n");
+               goto err_cq_table_free;
+       }
+
        err = mthca_init_qp_table(dev);
        if (err) {
                mthca_err(dev, "Failed to initialize "
                          "queue pair table, aborting.\n");
-               goto err_cq_table_free;
+               goto err_srq_table_free;
        }
 
        err = mthca_init_av_table(dev);
@@ -738,6 +793,9 @@ err_av_table_free:
 err_qp_table_free:
        mthca_cleanup_qp_table(dev);
 
+err_srq_table_free:
+       mthca_cleanup_srq_table(dev);
+
 err_cq_table_free:
        mthca_cleanup_cq_table(dev);
 
@@ -844,33 +902,6 @@ static int __devinit mthca_enable_msi_x(struct mthca_dev *mdev)
        return 0;
 }
 
-static void mthca_close_hca(struct mthca_dev *mdev)
-{
-       u8 status;
-
-       mthca_CLOSE_HCA(mdev, 0, &status);
-
-       if (mthca_is_memfree(mdev)) {
-               mthca_free_icm_table(mdev, mdev->cq_table.table);
-               mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);
-               mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);
-               mthca_free_icm_table(mdev, mdev->qp_table.qp_table);
-               mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);
-               mthca_free_icm_table(mdev, mdev->mr_table.mtt_table);
-               mthca_unmap_eq_icm(mdev);
-
-               mthca_UNMAP_ICM_AUX(mdev, &status);
-               mthca_free_icm(mdev, mdev->fw.arbel.aux_icm);
-
-               mthca_UNMAP_FA(mdev, &status);
-               mthca_free_icm(mdev, mdev->fw.arbel.fw_icm);
-
-               if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM))
-                       mthca_DISABLE_LAM(mdev, &status);
-       } else
-               mthca_SYS_DIS(mdev, &status);
-}
-
 /* Types of supported HCA */
 enum {
        TAVOR,                  /* MT23108                        */
@@ -887,9 +918,9 @@ static struct {
        int is_memfree;
        int is_pcie;
 } mthca_hca_table[] = {
-       [TAVOR]        = { .latest_fw = MTHCA_FW_VER(3, 3, 2), .is_memfree = 0, .is_pcie = 0 },
-       [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 6, 2), .is_memfree = 0, .is_pcie = 1 },
-       [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 0, 1), .is_memfree = 1, .is_pcie = 1 },
+       [TAVOR]        = { .latest_fw = MTHCA_FW_VER(3, 3, 3), .is_memfree = 0, .is_pcie = 0 },
+       [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 7, 0), .is_memfree = 0, .is_pcie = 1 },
+       [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 1, 0), .is_memfree = 1, .is_pcie = 1 },
        [SINAI]        = { .latest_fw = MTHCA_FW_VER(1, 0, 1), .is_memfree = 1, .is_pcie = 1 }
 };
 
@@ -1051,6 +1082,7 @@ err_cleanup:
        mthca_cleanup_mcg_table(mdev);
        mthca_cleanup_av_table(mdev);
        mthca_cleanup_qp_table(mdev);
+       mthca_cleanup_srq_table(mdev);
        mthca_cleanup_cq_table(mdev);
        mthca_cmd_use_polling(mdev);
        mthca_cleanup_eq_table(mdev);
@@ -1100,6 +1132,7 @@ static void __devexit mthca_remove_one(struct pci_dev *pdev)
                mthca_cleanup_mcg_table(mdev);
                mthca_cleanup_av_table(mdev);
                mthca_cleanup_qp_table(mdev);
+               mthca_cleanup_srq_table(mdev);
                mthca_cleanup_cq_table(mdev);
                mthca_cmd_use_polling(mdev);
                mthca_cleanup_eq_table(mdev);
index 5be7d949dbf61b74e06dc2a73931a05cf27fd38c..a2707605f4c8ba3319644452f2deb48004e001e9 100644 (file)
@@ -42,10 +42,10 @@ enum {
 };
 
 struct mthca_mgm {
-       u32 next_gid_index;
-       u32 reserved[3];
-       u8  gid[16];
-       u32 qp[MTHCA_QP_PER_MGM];
+       __be32 next_gid_index;
+       u32    reserved[3];
+       u8     gid[16];
+       __be32 qp[MTHCA_QP_PER_MGM];
 };
 
 static const u8 zero_gid[16];  /* automatically initialized to 0 */
@@ -94,10 +94,14 @@ static int find_mgm(struct mthca_dev *dev,
        if (0)
                mthca_dbg(dev, "Hash for %04x:%04x:%04x:%04x:"
                          "%04x:%04x:%04x:%04x is %04x\n",
-                         be16_to_cpu(((u16 *) gid)[0]), be16_to_cpu(((u16 *) gid)[1]),
-                         be16_to_cpu(((u16 *) gid)[2]), be16_to_cpu(((u16 *) gid)[3]),
-                         be16_to_cpu(((u16 *) gid)[4]), be16_to_cpu(((u16 *) gid)[5]),
-                         be16_to_cpu(((u16 *) gid)[6]), be16_to_cpu(((u16 *) gid)[7]),
+                         be16_to_cpu(((__be16 *) gid)[0]),
+                         be16_to_cpu(((__be16 *) gid)[1]),
+                         be16_to_cpu(((__be16 *) gid)[2]),
+                         be16_to_cpu(((__be16 *) gid)[3]),
+                         be16_to_cpu(((__be16 *) gid)[4]),
+                         be16_to_cpu(((__be16 *) gid)[5]),
+                         be16_to_cpu(((__be16 *) gid)[6]),
+                         be16_to_cpu(((__be16 *) gid)[7]),
                          *hash);
 
        *index = *hash;
@@ -258,14 +262,14 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
        if (index == -1) {
                mthca_err(dev, "MGID %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
                          "not found\n",
-                         be16_to_cpu(((u16 *) gid->raw)[0]),
-                         be16_to_cpu(((u16 *) gid->raw)[1]),
-                         be16_to_cpu(((u16 *) gid->raw)[2]),
-                         be16_to_cpu(((u16 *) gid->raw)[3]),
-                         be16_to_cpu(((u16 *) gid->raw)[4]),
-                         be16_to_cpu(((u16 *) gid->raw)[5]),
-                         be16_to_cpu(((u16 *) gid->raw)[6]),
-                         be16_to_cpu(((u16 *) gid->raw)[7]));
+                         be16_to_cpu(((__be16 *) gid->raw)[0]),
+                         be16_to_cpu(((__be16 *) gid->raw)[1]),
+                         be16_to_cpu(((__be16 *) gid->raw)[2]),
+                         be16_to_cpu(((__be16 *) gid->raw)[3]),
+                         be16_to_cpu(((__be16 *) gid->raw)[4]),
+                         be16_to_cpu(((__be16 *) gid->raw)[5]),
+                         be16_to_cpu(((__be16 *) gid->raw)[6]),
+                         be16_to_cpu(((__be16 *) gid->raw)[7]));
                err = -EINVAL;
                goto out;
        }
index 2a864615035510fa33d515cc5e6e406a086e42f4..1827400f189be87a61c5c7c062147a978a16b133 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -285,6 +286,7 @@ struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev,
 {
        struct mthca_icm_table *table;
        int num_icm;
+       unsigned chunk_size;
        int i;
        u8 status;
 
@@ -305,7 +307,11 @@ struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev,
                table->icm[i] = NULL;
 
        for (i = 0; i * MTHCA_TABLE_CHUNK_SIZE < reserved * obj_size; ++i) {
-               table->icm[i] = mthca_alloc_icm(dev, MTHCA_TABLE_CHUNK_SIZE >> PAGE_SHIFT,
+               chunk_size = MTHCA_TABLE_CHUNK_SIZE;
+               if ((i + 1) * MTHCA_TABLE_CHUNK_SIZE > nobj * obj_size)
+                       chunk_size = nobj * obj_size - i * MTHCA_TABLE_CHUNK_SIZE;
+
+               table->icm[i] = mthca_alloc_icm(dev, chunk_size >> PAGE_SHIFT,
                                                (use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
                                                __GFP_NOWARN);
                if (!table->icm[i])
@@ -481,7 +487,7 @@ void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar,
        }
 }
 
-int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db)
+int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, __be32 **db)
 {
        int group;
        int start, end, dir;
@@ -564,7 +570,7 @@ found:
 
        page->db_rec[j] = cpu_to_be64((qn << 8) | (type << 5));
 
-       *db = (u32 *) &page->db_rec[j];
+       *db = (__be32 *) &page->db_rec[j];
 
 out:
        up(&dev->db_tab->mutex);
index 4761d844cb5f93bbacb9f960b34e70d8cad8402c..bafa51544aa39db8db19cf2626361550fec7ea89 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -137,7 +138,7 @@ enum {
 
 struct mthca_db_page {
        DECLARE_BITMAP(used, MTHCA_DB_REC_PER_PAGE);
-       u64       *db_rec;
+       __be64    *db_rec;
        dma_addr_t mapping;
 };
 
@@ -172,7 +173,7 @@ void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar,
 
 int mthca_init_db_tab(struct mthca_dev *dev);
 void mthca_cleanup_db_tab(struct mthca_dev *dev);
-int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db);
+int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, __be32 **db);
 void mthca_free_db(struct mthca_dev *dev, int type, int db_index);
 
 #endif /* MTHCA_MEMFREE_H */
index cbe50feaf68073967c76b0e58569fde0de16e513..1f97a44477f5d8f31e37ebffb8e3c59bab779ddc 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -50,18 +51,18 @@ struct mthca_mtt {
  * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits.
  */
 struct mthca_mpt_entry {
-       u32 flags;
-       u32 page_size;
-       u32 key;
-       u32 pd;
-       u64 start;
-       u64 length;
-       u32 lkey;
-       u32 window_count;
-       u32 window_count_limit;
-       u64 mtt_seg;
-       u32 mtt_sz;             /* Arbel only */
-       u32 reserved[2];
+       __be32 flags;
+       __be32 page_size;
+       __be32 key;
+       __be32 pd;
+       __be64 start;
+       __be64 length;
+       __be32 lkey;
+       __be32 window_count;
+       __be32 window_count_limit;
+       __be64 mtt_seg;
+       __be32 mtt_sz;          /* Arbel only */
+       u32    reserved[2];
 } __attribute__((packed));
 
 #define MTHCA_MPT_FLAG_SW_OWNS       (0xfUL << 28)
@@ -247,7 +248,7 @@ int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
                    int start_index, u64 *buffer_list, int list_len)
 {
        struct mthca_mailbox *mailbox;
-       u64 *mtt_entry;
+       __be64 *mtt_entry;
        int err = 0;
        u8 status;
        int i;
@@ -389,7 +390,7 @@ int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
                for (i = 0; i < sizeof (struct mthca_mpt_entry) / 4; ++i) {
                        if (i % 4 == 0)
                                printk("[%02x] ", i * 4);
-                       printk(" %08x", be32_to_cpu(((u32 *) mpt_entry)[i]));
+                       printk(" %08x", be32_to_cpu(((__be32 *) mpt_entry)[i]));
                        if ((i + 1) % 4 == 0)
                                printk("\n");
                }
@@ -458,7 +459,7 @@ int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
 static void mthca_free_region(struct mthca_dev *dev, u32 lkey)
 {
        mthca_table_put(dev, dev->mr_table.mpt_table,
-                       arbel_key_to_hw_index(lkey));
+                       key_to_hw_index(dev, lkey));
 
        mthca_free(&dev->mr_table.mpt_alloc, key_to_hw_index(dev, lkey));
 }
@@ -562,7 +563,7 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
                for (i = 0; i < sizeof (struct mthca_mpt_entry) / 4; ++i) {
                        if (i % 4 == 0)
                                printk("[%02x] ", i * 4);
-                       printk(" %08x", be32_to_cpu(((u32 *) mpt_entry)[i]));
+                       printk(" %08x", be32_to_cpu(((__be32 *) mpt_entry)[i]));
                        if ((i + 1) % 4 == 0)
                                printk("\n");
                }
@@ -669,7 +670,7 @@ int mthca_tavor_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
        mpt_entry.length = cpu_to_be64(list_len * (1ull << fmr->attr.page_size));
        mpt_entry.start  = cpu_to_be64(iova);
 
-       writel(mpt_entry.lkey, &fmr->mem.tavor.mpt->key);
+       __raw_writel((__force u32) mpt_entry.lkey, &fmr->mem.tavor.mpt->key);
        memcpy_toio(&fmr->mem.tavor.mpt->start, &mpt_entry.start,
                    offsetof(struct mthca_mpt_entry, window_count) -
                    offsetof(struct mthca_mpt_entry, start));
index c2c899844e98b2ab36389c095a53aa24a6181885..3dbf06a6e6f4e097f84aceaa71a56104849ffeca 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
index 4fedc32d5871a4dfa54a9b2de2dc031c41dd6771..0576056b34f463742b7979ac9791b5bde002d8d0 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -101,6 +102,7 @@ u64 mthca_make_profile(struct mthca_dev *dev,
        profile[MTHCA_RES_UARC].size = request->uarc_size;
 
        profile[MTHCA_RES_QP].num    = request->num_qp;
+       profile[MTHCA_RES_SRQ].num   = request->num_srq;
        profile[MTHCA_RES_EQP].num   = request->num_qp;
        profile[MTHCA_RES_RDB].num   = request->num_qp * request->rdb_per_qp;
        profile[MTHCA_RES_CQ].num    = request->num_cq;
index 17aef3357661cbf2f35f0ed50e43c36ee99031f1..94641808f97f5cff4ef7cf93dd323d1ab4a5f584 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -41,6 +42,7 @@
 struct mthca_profile {
        int num_qp;
        int rdb_per_qp;
+       int num_srq;
        int num_cq;
        int num_mcg;
        int num_mpt;
index 81919a7b4935d97983f00170a302e0c6e0995460..1c1c2e230871202fe4b57bcf26aa602e6b505586 100644 (file)
@@ -2,6 +2,8 @@
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -34,7 +36,7 @@
  * $Id: mthca_provider.c 1397 2004-12-28 05:09:00Z roland $
  */
 
-#include <ib_smi.h>
+#include <rdma/ib_smi.h>
 #include <linux/mm.h>
 
 #include "mthca_dev.h"
@@ -79,10 +81,10 @@ static int mthca_query_device(struct ib_device *ibdev,
        }
 
        props->device_cap_flags    = mdev->device_cap_flags;
-       props->vendor_id           = be32_to_cpup((u32 *) (out_mad->data + 36)) &
+       props->vendor_id           = be32_to_cpup((__be32 *) (out_mad->data + 36)) &
                0xffffff;
-       props->vendor_part_id      = be16_to_cpup((u16 *) (out_mad->data + 30));
-       props->hw_ver              = be16_to_cpup((u16 *) (out_mad->data + 32));
+       props->vendor_part_id      = be16_to_cpup((__be16 *) (out_mad->data + 30));
+       props->hw_ver              = be16_to_cpup((__be16 *) (out_mad->data + 32));
        memcpy(&props->sys_image_guid, out_mad->data +  4, 8);
        memcpy(&props->node_guid,      out_mad->data + 12, 8);
 
@@ -118,6 +120,8 @@ static int mthca_query_port(struct ib_device *ibdev,
        if (!in_mad || !out_mad)
                goto out;
 
+       memset(props, 0, sizeof *props);
+
        memset(in_mad, 0, sizeof *in_mad);
        in_mad->base_version       = 1;
        in_mad->mgmt_class         = IB_MGMT_CLASS_SUBN_LID_ROUTED;
@@ -136,16 +140,17 @@ static int mthca_query_port(struct ib_device *ibdev,
                goto out;
        }
 
-       props->lid               = be16_to_cpup((u16 *) (out_mad->data + 16));
+       props->lid               = be16_to_cpup((__be16 *) (out_mad->data + 16));
        props->lmc               = out_mad->data[34] & 0x7;
-       props->sm_lid            = be16_to_cpup((u16 *) (out_mad->data + 18));
+       props->sm_lid            = be16_to_cpup((__be16 *) (out_mad->data + 18));
        props->sm_sl             = out_mad->data[36] & 0xf;
        props->state             = out_mad->data[32] & 0xf;
        props->phys_state        = out_mad->data[33] >> 4;
-       props->port_cap_flags    = be32_to_cpup((u32 *) (out_mad->data + 20));
+       props->port_cap_flags    = be32_to_cpup((__be32 *) (out_mad->data + 20));
        props->gid_tbl_len       = to_mdev(ibdev)->limits.gid_table_len;
+       props->max_msg_sz        = 0x80000000;
        props->pkey_tbl_len      = to_mdev(ibdev)->limits.pkey_table_len;
-       props->qkey_viol_cntr    = be16_to_cpup((u16 *) (out_mad->data + 48));
+       props->qkey_viol_cntr    = be16_to_cpup((__be16 *) (out_mad->data + 48));
        props->active_width      = out_mad->data[31] & 0xf;
        props->active_speed      = out_mad->data[35] >> 4;
 
@@ -221,7 +226,7 @@ static int mthca_query_pkey(struct ib_device *ibdev,
                goto out;
        }
 
-       *pkey = be16_to_cpu(((u16 *) out_mad->data)[index % 32]);
+       *pkey = be16_to_cpu(((__be16 *) out_mad->data)[index % 32]);
 
  out:
        kfree(in_mad);
@@ -420,6 +425,77 @@ static int mthca_ah_destroy(struct ib_ah *ah)
        return 0;
 }
 
+static struct ib_srq *mthca_create_srq(struct ib_pd *pd,
+                                      struct ib_srq_init_attr *init_attr,
+                                      struct ib_udata *udata)
+{
+       struct mthca_create_srq ucmd;
+       struct mthca_ucontext *context = NULL;
+       struct mthca_srq *srq;
+       int err;
+
+       srq = kmalloc(sizeof *srq, GFP_KERNEL);
+       if (!srq)
+               return ERR_PTR(-ENOMEM);
+
+       if (pd->uobject) {
+               context = to_mucontext(pd->uobject->context);
+
+               if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
+                       return ERR_PTR(-EFAULT);
+
+               err = mthca_map_user_db(to_mdev(pd->device), &context->uar,
+                                       context->db_tab, ucmd.db_index,
+                                       ucmd.db_page);
+
+               if (err)
+                       goto err_free;
+
+               srq->mr.ibmr.lkey = ucmd.lkey;
+               srq->db_index     = ucmd.db_index;
+       }
+
+       err = mthca_alloc_srq(to_mdev(pd->device), to_mpd(pd),
+                             &init_attr->attr, srq);
+
+       if (err && pd->uobject)
+               mthca_unmap_user_db(to_mdev(pd->device), &context->uar,
+                                   context->db_tab, ucmd.db_index);
+
+       if (err)
+               goto err_free;
+
+       if (context && ib_copy_to_udata(udata, &srq->srqn, sizeof (__u32))) {
+               mthca_free_srq(to_mdev(pd->device), srq);
+               err = -EFAULT;
+               goto err_free;
+       }
+
+       return &srq->ibsrq;
+
+err_free:
+       kfree(srq);
+
+       return ERR_PTR(err);
+}
+
+static int mthca_destroy_srq(struct ib_srq *srq)
+{
+       struct mthca_ucontext *context;
+
+       if (srq->uobject) {
+               context = to_mucontext(srq->uobject->context);
+
+               mthca_unmap_user_db(to_mdev(srq->device), &context->uar,
+                                   context->db_tab, to_msrq(srq)->db_index);
+       }
+
+       mthca_free_srq(to_mdev(srq->device), to_msrq(srq));
+       kfree(srq);
+
+       return 0;
+}
+
 static struct ib_qp *mthca_create_qp(struct ib_pd *pd,
                                     struct ib_qp_init_attr *init_attr,
                                     struct ib_udata *udata)
@@ -956,14 +1032,22 @@ static ssize_t show_hca(struct class_device *cdev, char *buf)
        }
 }
 
+static ssize_t show_board(struct class_device *cdev, char *buf)
+{
+       struct mthca_dev *dev = container_of(cdev, struct mthca_dev, ib_dev.class_dev);
+       return sprintf(buf, "%.*s\n", MTHCA_BOARD_ID_LEN, dev->board_id);
+}
+
 static CLASS_DEVICE_ATTR(hw_rev,   S_IRUGO, show_rev,    NULL);
 static CLASS_DEVICE_ATTR(fw_ver,   S_IRUGO, show_fw_ver, NULL);
 static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca,    NULL);
+static CLASS_DEVICE_ATTR(board_id, S_IRUGO, show_board,  NULL);
 
 static struct class_device_attribute *mthca_class_attributes[] = {
        &class_device_attr_hw_rev,
        &class_device_attr_fw_ver,
-       &class_device_attr_hca_type
+       &class_device_attr_hca_type,
+       &class_device_attr_board_id
 };
 
 int mthca_register_device(struct mthca_dev *dev)
@@ -990,6 +1074,17 @@ int mthca_register_device(struct mthca_dev *dev)
        dev->ib_dev.dealloc_pd           = mthca_dealloc_pd;
        dev->ib_dev.create_ah            = mthca_ah_create;
        dev->ib_dev.destroy_ah           = mthca_ah_destroy;
+
+       if (dev->mthca_flags & MTHCA_FLAG_SRQ) {
+               dev->ib_dev.create_srq           = mthca_create_srq;
+               dev->ib_dev.destroy_srq          = mthca_destroy_srq;
+
+               if (mthca_is_memfree(dev))
+                       dev->ib_dev.post_srq_recv = mthca_arbel_post_srq_recv;
+               else
+                       dev->ib_dev.post_srq_recv = mthca_tavor_post_srq_recv;
+       }
+
        dev->ib_dev.create_qp            = mthca_create_qp;
        dev->ib_dev.modify_qp            = mthca_modify_qp;
        dev->ib_dev.destroy_qp           = mthca_destroy_qp;
index 1d032791cc8b67a3ad217dc3a235ead72dab1f6b..bcd4b01a339cb1f7abae1d82f582b754df0cb4bc 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -36,8 +37,8 @@
 #ifndef MTHCA_PROVIDER_H
 #define MTHCA_PROVIDER_H
 
-#include <ib_verbs.h>
-#include <ib_pack.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_pack.h>
 
 #define MTHCA_MPT_FLAG_ATOMIC        (1 << 14)
 #define MTHCA_MPT_FLAG_REMOTE_WRITE  (1 << 13)
@@ -50,6 +51,11 @@ struct mthca_buf_list {
        DECLARE_PCI_UNMAP_ADDR(mapping)
 };
 
+union mthca_buf {
+       struct mthca_buf_list direct;
+       struct mthca_buf_list *page_list;
+};
+
 struct mthca_uar {
        unsigned long pfn;
        int           index;
@@ -181,19 +187,39 @@ struct mthca_cq {
 
        /* Next fields are Arbel only */
        int                    set_ci_db_index;
-       u32                   *set_ci_db;
+       __be32                *set_ci_db;
        int                    arm_db_index;
-       u32                   *arm_db;
+       __be32                *arm_db;
        int                    arm_sn;
 
-       union {
-               struct mthca_buf_list direct;
-               struct mthca_buf_list *page_list;
-       }                      queue;
+       union mthca_buf        queue;
        struct mthca_mr        mr;
        wait_queue_head_t      wait;
 };
 
+struct mthca_srq {
+       struct ib_srq           ibsrq;
+       spinlock_t              lock;
+       atomic_t                refcount;
+       int                     srqn;
+       int                     max;
+       int                     max_gs;
+       int                     wqe_shift;
+       int                     first_free;
+       int                     last_free;
+       u16                     counter;  /* Arbel only */
+       int                     db_index; /* Arbel only */
+       __be32                 *db;       /* Arbel only */
+       void                   *last;
+
+       int                     is_direct;
+       u64                    *wrid;
+       union mthca_buf         queue;
+       struct mthca_mr         mr;
+
+       wait_queue_head_t       wait;
+};
+
 struct mthca_wq {
        spinlock_t lock;
        int        max;
@@ -206,7 +232,7 @@ struct mthca_wq {
        int        wqe_shift;
 
        int        db_index;    /* Arbel only */
-       u32       *db;
+       __be32    *db;
 };
 
 struct mthca_qp {
@@ -227,10 +253,7 @@ struct mthca_qp {
        int                    send_wqe_offset;
 
        u64                   *wrid;
-       union {
-               struct mthca_buf_list direct;
-               struct mthca_buf_list *page_list;
-       }                      queue;
+       union mthca_buf        queue;
 
        wait_queue_head_t      wait;
 };
@@ -277,6 +300,11 @@ static inline struct mthca_cq *to_mcq(struct ib_cq *ibcq)
        return container_of(ibcq, struct mthca_cq, ibcq);
 }
 
+static inline struct mthca_srq *to_msrq(struct ib_srq *ibsrq)
+{
+       return container_of(ibsrq, struct mthca_srq, ibsrq);
+}
+
 static inline struct mthca_qp *to_mqp(struct ib_qp *ibqp)
 {
        return container_of(ibqp, struct mthca_qp, ibqp);
index f7126b14d5aeac2ac06f7d91bd2c0b3523375ff9..0164b84d4ec643062892122cf6ebf567d92ec5f1 100644 (file)
@@ -1,6 +1,8 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved. 
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
 
 #include <linux/init.h>
 
-#include <ib_verbs.h>
-#include <ib_cache.h>
-#include <ib_pack.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_cache.h>
+#include <rdma/ib_pack.h>
 
 #include "mthca_dev.h"
 #include "mthca_cmd.h"
 #include "mthca_memfree.h"
+#include "mthca_wqe.h"
 
 enum {
        MTHCA_MAX_DIRECT_QP_SIZE = 4 * PAGE_SIZE,
@@ -95,62 +98,62 @@ enum {
 };
 
 struct mthca_qp_path {
-       u32 port_pkey;
-       u8  rnr_retry;
-       u8  g_mylmc;
-       u16 rlid;
-       u8  ackto;
-       u8  mgid_index;
-       u8  static_rate;
-       u8  hop_limit;
-       u32 sl_tclass_flowlabel;
-       u8  rgid[16];
+       __be32 port_pkey;
+       u8     rnr_retry;
+       u8     g_mylmc;
+       __be16 rlid;
+       u8     ackto;
+       u8     mgid_index;
+       u8     static_rate;
+       u8     hop_limit;
+       __be32 sl_tclass_flowlabel;
+       u8     rgid[16];
 } __attribute__((packed));
 
 struct mthca_qp_context {
-       u32 flags;
-       u32 tavor_sched_queue;  /* Reserved on Arbel */
-       u8  mtu_msgmax;
-       u8  rq_size_stride;     /* Reserved on Tavor */
-       u8  sq_size_stride;     /* Reserved on Tavor */
-       u8  rlkey_arbel_sched_queue;    /* Reserved on Tavor */
-       u32 usr_page;
-       u32 local_qpn;
-       u32 remote_qpn;
-       u32 reserved1[2];
+       __be32 flags;
+       __be32 tavor_sched_queue; /* Reserved on Arbel */
+       u8     mtu_msgmax;
+       u8     rq_size_stride;  /* Reserved on Tavor */
+       u8     sq_size_stride;  /* Reserved on Tavor */
+       u8     rlkey_arbel_sched_queue; /* Reserved on Tavor */
+       __be32 usr_page;
+       __be32 local_qpn;
+       __be32 remote_qpn;
+       u32    reserved1[2];
        struct mthca_qp_path pri_path;
        struct mthca_qp_path alt_path;
-       u32 rdd;
-       u32 pd;
-       u32 wqe_base;
-       u32 wqe_lkey;
-       u32 params1;
-       u32 reserved2;
-       u32 next_send_psn;
-       u32 cqn_snd;
-       u32 snd_wqe_base_l;     /* Next send WQE on Tavor */
-       u32 snd_db_index;       /* (debugging only entries) */
-       u32 last_acked_psn;
-       u32 ssn;
-       u32 params2;
-       u32 rnr_nextrecvpsn;
-       u32 ra_buff_indx;
-       u32 cqn_rcv;
-       u32 rcv_wqe_base_l;     /* Next recv WQE on Tavor */
-       u32 rcv_db_index;       /* (debugging only entries) */
-       u32 qkey;
-       u32 srqn;
-       u32 rmsn;
-       u16 rq_wqe_counter;     /* reserved on Tavor */
-       u16 sq_wqe_counter;     /* reserved on Tavor */
-       u32 reserved3[18];
+       __be32 rdd;
+       __be32 pd;
+       __be32 wqe_base;
+       __be32 wqe_lkey;
+       __be32 params1;
+       __be32 reserved2;
+       __be32 next_send_psn;
+       __be32 cqn_snd;
+       __be32 snd_wqe_base_l;  /* Next send WQE on Tavor */
+       __be32 snd_db_index;    /* (debugging only entries) */
+       __be32 last_acked_psn;
+       __be32 ssn;
+       __be32 params2;
+       __be32 rnr_nextrecvpsn;
+       __be32 ra_buff_indx;
+       __be32 cqn_rcv;
+       __be32 rcv_wqe_base_l;  /* Next recv WQE on Tavor */
+       __be32 rcv_db_index;    /* (debugging only entries) */
+       __be32 qkey;
+       __be32 srqn;
+       __be32 rmsn;
+       __be16 rq_wqe_counter;  /* reserved on Tavor */
+       __be16 sq_wqe_counter;  /* reserved on Tavor */
+       u32    reserved3[18];
 } __attribute__((packed));
 
 struct mthca_qp_param {
-       u32 opt_param_mask;
-       u32 reserved1;
+       __be32 opt_param_mask;
+       u32    reserved1;
        struct mthca_qp_context context;
-       u32 reserved2[62];
+       u32    reserved2[62];
 } __attribute__((packed));
 
 enum {
@@ -173,80 +176,6 @@ enum {
        MTHCA_QP_OPTPAR_SCHED_QUEUE       = 1 << 16
 };
 
-enum {
-       MTHCA_NEXT_DBD       = 1 << 7,
-       MTHCA_NEXT_FENCE     = 1 << 6,
-       MTHCA_NEXT_CQ_UPDATE = 1 << 3,
-       MTHCA_NEXT_EVENT_GEN = 1 << 2,
-       MTHCA_NEXT_SOLICIT   = 1 << 1,
-
-       MTHCA_MLX_VL15       = 1 << 17,
-       MTHCA_MLX_SLR        = 1 << 16
-};
-
-enum {
-       MTHCA_INVAL_LKEY = 0x100
-};
-
-struct mthca_next_seg {
-       u32 nda_op;             /* [31:6] next WQE [4:0] next opcode */
-       u32 ee_nds;             /* [31:8] next EE  [7] DBD [6] F [5:0] next WQE size */
-       u32 flags;              /* [3] CQ [2] Event [1] Solicit */
-       u32 imm;                /* immediate data */
-};
-
-struct mthca_tavor_ud_seg {
-       u32 reserved1;
-       u32 lkey;
-       u64 av_addr;
-       u32 reserved2[4];
-       u32 dqpn;
-       u32 qkey;
-       u32 reserved3[2];
-};
-
-struct mthca_arbel_ud_seg {
-       u32 av[8];
-       u32 dqpn;
-       u32 qkey;
-       u32 reserved[2];
-};
-
-struct mthca_bind_seg {
-       u32 flags;              /* [31] Atomic [30] rem write [29] rem read */
-       u32 reserved;
-       u32 new_rkey;
-       u32 lkey;
-       u64 addr;
-       u64 length;
-};
-
-struct mthca_raddr_seg {
-       u64 raddr;
-       u32 rkey;
-       u32 reserved;
-};
-
-struct mthca_atomic_seg {
-       u64 swap_add;
-       u64 compare;
-};
-
-struct mthca_data_seg {
-       u32 byte_count;
-       u32 lkey;
-       u64 addr;
-};
-
-struct mthca_mlx_seg {
-       u32 nda_op;
-       u32 nds;
-       u32 flags;              /* [17] VL15 [16] SLR [14:12] static rate
-                                  [11:8] SL [3] C [2] E */
-       u16 rlid;
-       u16 vcrc;
-};
-
 static const u8 mthca_opcode[] = {
        [IB_WR_SEND]                 = MTHCA_OPCODE_SEND,
        [IB_WR_SEND_WITH_IMM]        = MTHCA_OPCODE_SEND_IMM,
@@ -573,12 +502,11 @@ static void init_port(struct mthca_dev *dev, int port)
 
        memset(&param, 0, sizeof param);
 
-       param.enable_1x = 1;
-       param.enable_4x = 1;
-       param.vl_cap    = dev->limits.vl_cap;
-       param.mtu_cap   = dev->limits.mtu_cap;
-       param.gid_cap   = dev->limits.gid_table_len;
-       param.pkey_cap  = dev->limits.pkey_table_len;
+       param.port_width = dev->limits.port_width_cap;
+       param.vl_cap     = dev->limits.vl_cap;
+       param.mtu_cap    = dev->limits.mtu_cap;
+       param.gid_cap    = dev->limits.gid_table_len;
+       param.pkey_cap   = dev->limits.pkey_table_len;
 
        err = mthca_INIT_IB(dev, &param, port, &status);
        if (err)
@@ -684,10 +612,13 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
                qp_context->mtu_msgmax = (attr->path_mtu << 5) | 31;
 
        if (mthca_is_memfree(dev)) {
-               qp_context->rq_size_stride =
-                       ((ffs(qp->rq.max) - 1) << 3) | (qp->rq.wqe_shift - 4);
-               qp_context->sq_size_stride =
-                       ((ffs(qp->sq.max) - 1) << 3) | (qp->sq.wqe_shift - 4);
+               if (qp->rq.max)
+                       qp_context->rq_size_stride = long_log2(qp->rq.max) << 3;
+               qp_context->rq_size_stride |= qp->rq.wqe_shift - 4;
+
+               if (qp->sq.max)
+                       qp_context->sq_size_stride = long_log2(qp->sq.max) << 3;
+               qp_context->sq_size_stride |= qp->sq.wqe_shift - 4;
        }
 
        /* leave arbel_sched_queue as 0 */
@@ -856,6 +787,9 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 
        qp_context->params2 |= cpu_to_be32(MTHCA_QP_BIT_RSC);
 
+       if (ibqp->srq)
+               qp_context->params2 |= cpu_to_be32(MTHCA_QP_BIT_RIC);
+
        if (attr_mask & IB_QP_MIN_RNR_TIMER) {
                qp_context->rnr_nextrecvpsn |= cpu_to_be32(attr->min_rnr_timer << 24);
                qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RNR_TIMEOUT);
@@ -878,6 +812,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
                qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_Q_KEY);
        }
 
+       if (ibqp->srq)
+               qp_context->srqn = cpu_to_be32(1 << 24 |
+                                              to_msrq(ibqp->srq)->srqn);
+
        err = mthca_MODIFY_QP(dev, state_table[cur_state][new_state].trans,
                              qp->qpn, 0, mailbox, 0, &status);
        if (status) {
@@ -925,10 +863,6 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
                               struct mthca_qp *qp)
 {
        int size;
-       int i;
-       int npages, shift;
-       dma_addr_t t;
-       u64 *dma_list = NULL;
        int err = -ENOMEM;
 
        size = sizeof (struct mthca_next_seg) +
@@ -978,116 +912,24 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
        if (!qp->wrid)
                goto err_out;
 
-       if (size <= MTHCA_MAX_DIRECT_QP_SIZE) {
-               qp->is_direct = 1;
-               npages = 1;
-               shift = get_order(size) + PAGE_SHIFT;
-
-               if (0)
-                       mthca_dbg(dev, "Creating direct QP of size %d (shift %d)\n",
-                                 size, shift);
-
-               qp->queue.direct.buf = dma_alloc_coherent(&dev->pdev->dev, size,
-                                                         &t, GFP_KERNEL);
-               if (!qp->queue.direct.buf)
-                       goto err_out;
-
-               pci_unmap_addr_set(&qp->queue.direct, mapping, t);
-
-               memset(qp->queue.direct.buf, 0, size);
-
-               while (t & ((1 << shift) - 1)) {
-                       --shift;
-                       npages *= 2;
-               }
-
-               dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL);
-               if (!dma_list)
-                       goto err_out_free;
-
-               for (i = 0; i < npages; ++i)
-                       dma_list[i] = t + i * (1 << shift);
-       } else {
-               qp->is_direct = 0;
-               npages = size / PAGE_SIZE;
-               shift = PAGE_SHIFT;
-
-               if (0)
-                       mthca_dbg(dev, "Creating indirect QP with %d pages\n", npages);
-
-               dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL);
-               if (!dma_list)
-                       goto err_out;
-
-               qp->queue.page_list = kmalloc(npages *
-                                             sizeof *qp->queue.page_list,
-                                             GFP_KERNEL);
-               if (!qp->queue.page_list)
-                       goto err_out;
-
-               for (i = 0; i < npages; ++i) {
-                       qp->queue.page_list[i].buf =
-                               dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
-                                                  &t, GFP_KERNEL);
-                       if (!qp->queue.page_list[i].buf)
-                               goto err_out_free;
-
-                       memset(qp->queue.page_list[i].buf, 0, PAGE_SIZE);
-
-                       pci_unmap_addr_set(&qp->queue.page_list[i], mapping, t);
-                       dma_list[i] = t;
-               }
-       }
-
-       err = mthca_mr_alloc_phys(dev, pd->pd_num, dma_list, shift,
-                                 npages, 0, size,
-                                 MTHCA_MPT_FLAG_LOCAL_READ,
-                                 &qp->mr);
+       err = mthca_buf_alloc(dev, size, MTHCA_MAX_DIRECT_QP_SIZE,
+                             &qp->queue, &qp->is_direct, pd, 0, &qp->mr);
        if (err)
-               goto err_out_free;
+               goto err_out;
 
-       kfree(dma_list);
        return 0;
 
- err_out_free:
-       if (qp->is_direct) {
-               dma_free_coherent(&dev->pdev->dev, size, qp->queue.direct.buf,
-                                 pci_unmap_addr(&qp->queue.direct, mapping));
-       } else
-               for (i = 0; i < npages; ++i) {
-                       if (qp->queue.page_list[i].buf)
-                               dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
-                                                 qp->queue.page_list[i].buf,
-                                                 pci_unmap_addr(&qp->queue.page_list[i],
-                                                                mapping));
-
-               }
-
- err_out:
+err_out:
        kfree(qp->wrid);
-       kfree(dma_list);
        return err;
 }
 
 static void mthca_free_wqe_buf(struct mthca_dev *dev,
                               struct mthca_qp *qp)
 {
-       int i;
-       int size = PAGE_ALIGN(qp->send_wqe_offset +
-                             (qp->sq.max << qp->sq.wqe_shift));
-
-       if (qp->is_direct) {
-               dma_free_coherent(&dev->pdev->dev, size, qp->queue.direct.buf,
-                                 pci_unmap_addr(&qp->queue.direct, mapping));
-       } else {
-               for (i = 0; i < size / PAGE_SIZE; ++i) {
-                       dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
-                                         qp->queue.page_list[i].buf,
-                                         pci_unmap_addr(&qp->queue.page_list[i],
-                                                        mapping));
-               }
-       }
-
+       mthca_buf_free(dev, PAGE_ALIGN(qp->send_wqe_offset +
+                                      (qp->sq.max << qp->sq.wqe_shift)),
+                      &qp->queue, qp->is_direct, &qp->mr);
        kfree(qp->wrid);
 }
 
@@ -1428,11 +1270,12 @@ void mthca_free_qp(struct mthca_dev *dev,
         * unref the mem-free tables and free the QPN in our table.
         */
        if (!qp->ibqp.uobject) {
-               mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn);
+               mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn,
+                              qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
                if (qp->ibqp.send_cq != qp->ibqp.recv_cq)
-                       mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn);
+                       mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn,
+                                      qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
 
-               mthca_free_mr(dev, &qp->mr);
                mthca_free_memfree(dev, qp);
                mthca_free_wqe_buf(dev, qp);
        }
@@ -1457,6 +1300,7 @@ static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp,
 {
        int header_size;
        int err;
+       u16 pkey;
 
        ib_ud_header_init(256, /* assume a MAD */
                          sqp->ud_header.grh_present,
@@ -1467,8 +1311,8 @@ static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp,
                return err;
        mlx->flags &= ~cpu_to_be32(MTHCA_NEXT_SOLICIT | 1);
        mlx->flags |= cpu_to_be32((!sqp->qp.ibqp.qp_num ? MTHCA_MLX_VL15 : 0) |
-                                 (sqp->ud_header.lrh.destination_lid == 0xffff ?
-                                  MTHCA_MLX_SLR : 0) |
+                                 (sqp->ud_header.lrh.destination_lid ==
+                                  IB_LID_PERMISSIVE ? MTHCA_MLX_SLR : 0) |
                                  (sqp->ud_header.lrh.service_level << 8));
        mlx->rlid = sqp->ud_header.lrh.destination_lid;
        mlx->vcrc = 0;
@@ -1488,18 +1332,16 @@ static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp,
        }
 
        sqp->ud_header.lrh.virtual_lane    = !sqp->qp.ibqp.qp_num ? 15 : 0;
-       if (sqp->ud_header.lrh.destination_lid == 0xffff)
-               sqp->ud_header.lrh.source_lid = 0xffff;
+       if (sqp->ud_header.lrh.destination_lid == IB_LID_PERMISSIVE)
+               sqp->ud_header.lrh.source_lid = IB_LID_PERMISSIVE;
        sqp->ud_header.bth.solicited_event = !!(wr->send_flags & IB_SEND_SOLICITED);
        if (!sqp->qp.ibqp.qp_num)
                ib_get_cached_pkey(&dev->ib_dev, sqp->port,
-                                  sqp->pkey_index,
-                                  &sqp->ud_header.bth.pkey);
+                                  sqp->pkey_index, &pkey);
        else
                ib_get_cached_pkey(&dev->ib_dev, sqp->port,
-                                  wr->wr.ud.pkey_index,
-                                  &sqp->ud_header.bth.pkey);
-       cpu_to_be16s(&sqp->ud_header.bth.pkey);
+                                  wr->wr.ud.pkey_index, &pkey);
+       sqp->ud_header.bth.pkey = cpu_to_be16(pkey);
        sqp->ud_header.bth.destination_qpn = cpu_to_be32(wr->wr.ud.remote_qpn);
        sqp->ud_header.bth.psn = cpu_to_be32((sqp->send_psn++) & ((1 << 24) - 1));
        sqp->ud_header.deth.qkey = cpu_to_be32(wr->wr.ud.remote_qkey & 0x80000000 ?
@@ -1742,7 +1584,7 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 
 out:
        if (likely(nreq)) {
-               u32 doorbell[2];
+               __be32 doorbell[2];
 
                doorbell[0] = cpu_to_be32(((qp->sq.next_ind << qp->sq.wqe_shift) +
                                           qp->send_wqe_offset) | f0 | op0);
@@ -1843,7 +1685,7 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
 
 out:
        if (likely(nreq)) {
-               u32 doorbell[2];
+               __be32 doorbell[2];
 
                doorbell[0] = cpu_to_be32((qp->rq.next_ind << qp->rq.wqe_shift) | size0);
                doorbell[1] = cpu_to_be32((qp->qpn << 8) | nreq);
@@ -2064,7 +1906,7 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 
 out:
        if (likely(nreq)) {
-               u32 doorbell[2];
+               __be32 doorbell[2];
 
                doorbell[0] = cpu_to_be32((nreq << 24)                  |
                                          ((qp->sq.head & 0xffff) << 8) |
@@ -2174,19 +2016,25 @@ out:
 }
 
 int mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
-                      int index, int *dbd, u32 *new_wqe)
+                      int index, int *dbd, __be32 *new_wqe)
 {
        struct mthca_next_seg *next;
 
+       /*
+        * For SRQs, all WQEs generate a CQE, so we're always at the
+        * end of the doorbell chain.
+        */
+       if (qp->ibqp.srq) {
+               *new_wqe = 0;
+               return 0;
+       }
+
        if (is_send)
                next = get_send_wqe(qp, index);
        else
                next = get_recv_wqe(qp, index);
 
-       if (mthca_is_memfree(dev))
-               *dbd = 1;
-       else
-               *dbd = !!(next->ee_nds & cpu_to_be32(MTHCA_NEXT_DBD));
+       *dbd = !!(next->ee_nds & cpu_to_be32(MTHCA_NEXT_DBD));
        if (next->ee_nds & cpu_to_be32(0x3f))
                *new_wqe = (next->nda_op & cpu_to_be32(~0x3f)) |
                        (next->ee_nds & cpu_to_be32(0x3f));
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c
new file mode 100644 (file)
index 0000000..75cd2d8
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: mthca_srq.c 3047 2005-08-10 03:59:35Z roland $
+ */
+
+#include "mthca_dev.h"
+#include "mthca_cmd.h"
+#include "mthca_memfree.h"
+#include "mthca_wqe.h"
+
+enum {
+       MTHCA_MAX_DIRECT_SRQ_SIZE = 4 * PAGE_SIZE
+};
+
+struct mthca_tavor_srq_context {
+       __be64 wqe_base_ds;     /* low 6 bits is descriptor size */
+       __be32 state_pd;
+       __be32 lkey;
+       __be32 uar;
+       __be32 wqe_cnt;
+       u32    reserved[2];
+};
+
+struct mthca_arbel_srq_context {
+       __be32 state_logsize_srqn;
+       __be32 lkey;
+       __be32 db_index;
+       __be32 logstride_usrpage;
+       __be64 wqe_base;
+       __be32 eq_pd;
+       __be16 limit_watermark;
+       __be16 wqe_cnt;
+       u16    reserved1;
+       __be16 wqe_counter;
+       u32    reserved2[3];
+};
+
+static void *get_wqe(struct mthca_srq *srq, int n)
+{
+       if (srq->is_direct)
+               return srq->queue.direct.buf + (n << srq->wqe_shift);
+       else
+               return srq->queue.page_list[(n << srq->wqe_shift) >> PAGE_SHIFT].buf +
+                       ((n << srq->wqe_shift) & (PAGE_SIZE - 1));
+}
+
+/*
+ * Return a pointer to the location within a WQE that we're using as a
+ * link when the WQE is in the free list.  We use an offset of 4
+ * because in the Tavor case, posting a WQE may overwrite the first
+ * four bytes of the previous WQE.  The offset avoids corrupting our
+ * free list if the WQE has already completed and been put on the free
+ * list when we post the next WQE.
+ */
+static inline int *wqe_to_link(void *wqe)
+{
+       return (int *) (wqe + 4);
+}
+
+static void mthca_tavor_init_srq_context(struct mthca_dev *dev,
+                                        struct mthca_pd *pd,
+                                        struct mthca_srq *srq,
+                                        struct mthca_tavor_srq_context *context)
+{
+       memset(context, 0, sizeof *context);
+
+       context->wqe_base_ds = cpu_to_be64(1 << (srq->wqe_shift - 4));
+       context->state_pd    = cpu_to_be32(pd->pd_num);
+       context->lkey        = cpu_to_be32(srq->mr.ibmr.lkey);
+
+       if (pd->ibpd.uobject)
+               context->uar =
+                       cpu_to_be32(to_mucontext(pd->ibpd.uobject->context)->uar.index);
+       else
+               context->uar = cpu_to_be32(dev->driver_uar.index);
+}
+
+static void mthca_arbel_init_srq_context(struct mthca_dev *dev,
+                                        struct mthca_pd *pd,
+                                        struct mthca_srq *srq,
+                                        struct mthca_arbel_srq_context *context)
+{
+       int logsize;
+
+       memset(context, 0, sizeof *context);
+
+       logsize = long_log2(srq->max) + srq->wqe_shift;
+       context->state_logsize_srqn = cpu_to_be32(logsize << 24 | srq->srqn);
+       context->lkey = cpu_to_be32(srq->mr.ibmr.lkey);
+       context->db_index = cpu_to_be32(srq->db_index);
+       context->logstride_usrpage = cpu_to_be32((srq->wqe_shift - 4) << 29);
+       if (pd->ibpd.uobject)
+               context->logstride_usrpage |=
+                       cpu_to_be32(to_mucontext(pd->ibpd.uobject->context)->uar.index);
+       else
+               context->logstride_usrpage |= cpu_to_be32(dev->driver_uar.index);
+       context->eq_pd = cpu_to_be32(MTHCA_EQ_ASYNC << 24 | pd->pd_num);
+}
+
+static void mthca_free_srq_buf(struct mthca_dev *dev, struct mthca_srq *srq)
+{
+       mthca_buf_free(dev, srq->max << srq->wqe_shift, &srq->queue,
+                      srq->is_direct, &srq->mr);
+       kfree(srq->wrid);
+}
+
+static int mthca_alloc_srq_buf(struct mthca_dev *dev, struct mthca_pd *pd,
+                              struct mthca_srq *srq)
+{
+       struct mthca_data_seg *scatter;
+       void *wqe;
+       int err;
+       int i;
+
+       if (pd->ibpd.uobject)
+               return 0;
+
+       srq->wrid = kmalloc(srq->max * sizeof (u64), GFP_KERNEL);
+       if (!srq->wrid)
+               return -ENOMEM;
+
+       err = mthca_buf_alloc(dev, srq->max << srq->wqe_shift,
+                             MTHCA_MAX_DIRECT_SRQ_SIZE,
+                             &srq->queue, &srq->is_direct, pd, 1, &srq->mr);
+       if (err) {
+               kfree(srq->wrid);
+               return err;
+       }
+
+       /*
+        * Now initialize the SRQ buffer so that all of the WQEs are
+        * linked into the list of free WQEs.  In addition, set the
+        * scatter list L_Keys to the sentry value of 0x100.
+        */
+       for (i = 0; i < srq->max; ++i) {
+               wqe = get_wqe(srq, i);
+
+               *wqe_to_link(wqe) = i < srq->max - 1 ? i + 1 : -1;
+
+               for (scatter = wqe + sizeof (struct mthca_next_seg);
+                    (void *) scatter < wqe + (1 << srq->wqe_shift);
+                    ++scatter)
+                       scatter->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
+       }
+
+       return 0;
+}
+
+int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
+                   struct ib_srq_attr *attr, struct mthca_srq *srq)
+{
+       struct mthca_mailbox *mailbox;
+       u8 status;
+       int ds;
+       int err;
+
+       /* Sanity check SRQ size before proceeding */
+       if (attr->max_wr > 16 << 20 || attr->max_sge > 64)
+               return -EINVAL;
+
+       srq->max      = attr->max_wr;
+       srq->max_gs   = attr->max_sge;
+       srq->last     = NULL;
+       srq->counter  = 0;
+
+       if (mthca_is_memfree(dev))
+               srq->max = roundup_pow_of_two(srq->max + 1);
+
+       ds = min(64UL,
+                roundup_pow_of_two(sizeof (struct mthca_next_seg) +
+                                   srq->max_gs * sizeof (struct mthca_data_seg)));
+       srq->wqe_shift = long_log2(ds);
+
+       srq->srqn = mthca_alloc(&dev->srq_table.alloc);
+       if (srq->srqn == -1)
+               return -ENOMEM;
+
+       if (mthca_is_memfree(dev)) {
+               err = mthca_table_get(dev, dev->srq_table.table, srq->srqn);
+               if (err)
+                       goto err_out;
+
+               if (!pd->ibpd.uobject) {
+                       srq->db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_SRQ,
+                                                      srq->srqn, &srq->db);
+                       if (srq->db_index < 0) {
+                               err = -ENOMEM;
+                               goto err_out_icm;
+                       }
+               }
+       }
+
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox)) {
+               err = PTR_ERR(mailbox);
+               goto err_out_db;
+       }
+
+       err = mthca_alloc_srq_buf(dev, pd, srq);
+       if (err)
+               goto err_out_mailbox;
+
+       spin_lock_init(&srq->lock);
+       atomic_set(&srq->refcount, 1);
+       init_waitqueue_head(&srq->wait);
+
+       if (mthca_is_memfree(dev))
+               mthca_arbel_init_srq_context(dev, pd, srq, mailbox->buf);
+       else
+               mthca_tavor_init_srq_context(dev, pd, srq, mailbox->buf);
+
+       err = mthca_SW2HW_SRQ(dev, mailbox, srq->srqn, &status);
+
+       if (err) {
+               mthca_warn(dev, "SW2HW_SRQ failed (%d)\n", err);
+               goto err_out_free_buf;
+       }
+       if (status) {
+               mthca_warn(dev, "SW2HW_SRQ returned status 0x%02x\n",
+                          status);
+               err = -EINVAL;
+               goto err_out_free_buf;
+       }
+
+       spin_lock_irq(&dev->srq_table.lock);
+       if (mthca_array_set(&dev->srq_table.srq,
+                           srq->srqn & (dev->limits.num_srqs - 1),
+                           srq)) {
+               spin_unlock_irq(&dev->srq_table.lock);
+               goto err_out_free_srq;
+       }
+       spin_unlock_irq(&dev->srq_table.lock);
+
+       mthca_free_mailbox(dev, mailbox);
+
+       srq->first_free = 0;
+       srq->last_free  = srq->max - 1;
+
+       return 0;
+
+err_out_free_srq:
+       err = mthca_HW2SW_SRQ(dev, mailbox, srq->srqn, &status);
+       if (err)
+               mthca_warn(dev, "HW2SW_SRQ failed (%d)\n", err);
+       else if (status)
+               mthca_warn(dev, "HW2SW_SRQ returned status 0x%02x\n", status);
+
+err_out_free_buf:
+       if (!pd->ibpd.uobject)
+               mthca_free_srq_buf(dev, srq);
+
+err_out_mailbox:
+       mthca_free_mailbox(dev, mailbox);
+
+err_out_db:
+       if (!pd->ibpd.uobject && mthca_is_memfree(dev))
+               mthca_free_db(dev, MTHCA_DB_TYPE_SRQ, srq->db_index);
+
+err_out_icm:
+       mthca_table_put(dev, dev->srq_table.table, srq->srqn);
+
+err_out:
+       mthca_free(&dev->srq_table.alloc, srq->srqn);
+
+       return err;
+}
+
+void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq)
+{
+       struct mthca_mailbox *mailbox;
+       int err;
+       u8 status;
+
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox)) {
+               mthca_warn(dev, "No memory for mailbox to free SRQ.\n");
+               return;
+       }
+
+       err = mthca_HW2SW_SRQ(dev, mailbox, srq->srqn, &status);
+       if (err)
+               mthca_warn(dev, "HW2SW_SRQ failed (%d)\n", err);
+       else if (status)
+               mthca_warn(dev, "HW2SW_SRQ returned status 0x%02x\n", status);
+
+       spin_lock_irq(&dev->srq_table.lock);
+       mthca_array_clear(&dev->srq_table.srq,
+                         srq->srqn & (dev->limits.num_srqs - 1));
+       spin_unlock_irq(&dev->srq_table.lock);
+
+       atomic_dec(&srq->refcount);
+       wait_event(srq->wait, !atomic_read(&srq->refcount));
+
+       if (!srq->ibsrq.uobject) {
+               mthca_free_srq_buf(dev, srq);
+               if (mthca_is_memfree(dev))
+                       mthca_free_db(dev, MTHCA_DB_TYPE_SRQ, srq->db_index);
+       }
+
+       mthca_table_put(dev, dev->srq_table.table, srq->srqn);
+       mthca_free(&dev->srq_table.alloc, srq->srqn);
+       mthca_free_mailbox(dev, mailbox);
+}
+
+void mthca_srq_event(struct mthca_dev *dev, u32 srqn,
+                    enum ib_event_type event_type)
+{
+       struct mthca_srq *srq;
+       struct ib_event event;
+
+       spin_lock(&dev->srq_table.lock);
+       srq = mthca_array_get(&dev->srq_table.srq, srqn & (dev->limits.num_srqs - 1));
+       if (srq)
+               atomic_inc(&srq->refcount);
+       spin_unlock(&dev->srq_table.lock);
+
+       if (!srq) {
+               mthca_warn(dev, "Async event for bogus SRQ %08x\n", srqn);
+               return;
+       }
+
+       if (!srq->ibsrq.event_handler)
+               goto out;
+
+       event.device      = &dev->ib_dev;
+       event.event       = event_type;
+       event.element.srq  = &srq->ibsrq;
+       srq->ibsrq.event_handler(&event, srq->ibsrq.srq_context);
+
+out:
+       if (atomic_dec_and_test(&srq->refcount))
+               wake_up(&srq->wait);
+}
+
+/*
+ * This function must be called with IRQs disabled.
+ */
+void mthca_free_srq_wqe(struct mthca_srq *srq, u32 wqe_addr)
+{
+       int ind;
+
+       ind = wqe_addr >> srq->wqe_shift;
+
+       spin_lock(&srq->lock);
+
+       if (likely(srq->first_free >= 0))
+               *wqe_to_link(get_wqe(srq, srq->last_free)) = ind;
+       else
+               srq->first_free = ind;
+
+       *wqe_to_link(get_wqe(srq, ind)) = -1;
+       srq->last_free = ind;
+
+       spin_unlock(&srq->lock);
+}
+
+int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
+                             struct ib_recv_wr **bad_wr)
+{
+       struct mthca_dev *dev = to_mdev(ibsrq->device);
+       struct mthca_srq *srq = to_msrq(ibsrq);
+       unsigned long flags;
+       int err = 0;
+       int first_ind;
+       int ind;
+       int next_ind;
+       int nreq;
+       int i;
+       void *wqe;
+       void *prev_wqe;
+
+       spin_lock_irqsave(&srq->lock, flags);
+
+       first_ind = srq->first_free;
+
+       for (nreq = 0; wr; ++nreq, wr = wr->next) {
+               ind = srq->first_free;
+
+               if (ind < 0) {
+                       mthca_err(dev, "SRQ %06x full\n", srq->srqn);
+                       err = -ENOMEM;
+                       *bad_wr = wr;
+                       return nreq;
+               }
+
+               wqe       = get_wqe(srq, ind);
+               next_ind  = *wqe_to_link(wqe);
+               prev_wqe  = srq->last;
+               srq->last = wqe;
+
+               ((struct mthca_next_seg *) wqe)->nda_op = 0;
+               ((struct mthca_next_seg *) wqe)->ee_nds = 0;
+               /* flags field will always remain 0 */
+
+               wqe += sizeof (struct mthca_next_seg);
+
+               if (unlikely(wr->num_sge > srq->max_gs)) {
+                       err = -EINVAL;
+                       *bad_wr = wr;
+                       srq->last = prev_wqe;
+                       return nreq;
+               }
+
+               for (i = 0; i < wr->num_sge; ++i) {
+                       ((struct mthca_data_seg *) wqe)->byte_count =
+                               cpu_to_be32(wr->sg_list[i].length);
+                       ((struct mthca_data_seg *) wqe)->lkey =
+                               cpu_to_be32(wr->sg_list[i].lkey);
+                       ((struct mthca_data_seg *) wqe)->addr =
+                               cpu_to_be64(wr->sg_list[i].addr);
+                       wqe += sizeof (struct mthca_data_seg);
+               }
+
+               if (i < srq->max_gs) {
+                       ((struct mthca_data_seg *) wqe)->byte_count = 0;
+                       ((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
+                       ((struct mthca_data_seg *) wqe)->addr = 0;
+               }
+
+               if (likely(prev_wqe)) {
+                       ((struct mthca_next_seg *) prev_wqe)->nda_op =
+                               cpu_to_be32((ind << srq->wqe_shift) | 1);
+                       wmb();
+                       ((struct mthca_next_seg *) prev_wqe)->ee_nds =
+                               cpu_to_be32(MTHCA_NEXT_DBD);
+               }
+
+               srq->wrid[ind]  = wr->wr_id;
+               srq->first_free = next_ind;
+       }
+
+       return nreq;
+
+       if (likely(nreq)) {
+               __be32 doorbell[2];
+
+               doorbell[0] = cpu_to_be32(first_ind << srq->wqe_shift);
+               doorbell[1] = cpu_to_be32((srq->srqn << 8) | nreq);
+
+               /*
+                * Make sure that descriptors are written before
+                * doorbell is rung.
+                */
+               wmb();
+
+               mthca_write64(doorbell,
+                             dev->kar + MTHCA_RECEIVE_DOORBELL,
+                             MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
+       }
+
+       spin_unlock_irqrestore(&srq->lock, flags);
+       return err;
+}
+
+int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
+                             struct ib_recv_wr **bad_wr)
+{
+       struct mthca_dev *dev = to_mdev(ibsrq->device);
+       struct mthca_srq *srq = to_msrq(ibsrq);
+       unsigned long flags;
+       int err = 0;
+       int ind;
+       int next_ind;
+       int nreq;
+       int i;
+       void *wqe;
+
+       spin_lock_irqsave(&srq->lock, flags);
+
+       for (nreq = 0; wr; ++nreq, wr = wr->next) {
+               ind = srq->first_free;
+
+               if (ind < 0) {
+                       mthca_err(dev, "SRQ %06x full\n", srq->srqn);
+                       err = -ENOMEM;
+                       *bad_wr = wr;
+                       return nreq;
+               }
+
+               wqe       = get_wqe(srq, ind);
+               next_ind  = *wqe_to_link(wqe);
+
+               ((struct mthca_next_seg *) wqe)->nda_op =
+                       cpu_to_be32((next_ind << srq->wqe_shift) | 1);
+               ((struct mthca_next_seg *) wqe)->ee_nds = 0;
+               /* flags field will always remain 0 */
+
+               wqe += sizeof (struct mthca_next_seg);
+
+               if (unlikely(wr->num_sge > srq->max_gs)) {
+                       err = -EINVAL;
+                       *bad_wr = wr;
+                       return nreq;
+               }
+
+               for (i = 0; i < wr->num_sge; ++i) {
+                       ((struct mthca_data_seg *) wqe)->byte_count =
+                               cpu_to_be32(wr->sg_list[i].length);
+                       ((struct mthca_data_seg *) wqe)->lkey =
+                               cpu_to_be32(wr->sg_list[i].lkey);
+                       ((struct mthca_data_seg *) wqe)->addr =
+                               cpu_to_be64(wr->sg_list[i].addr);
+                       wqe += sizeof (struct mthca_data_seg);
+               }
+
+               if (i < srq->max_gs) {
+                       ((struct mthca_data_seg *) wqe)->byte_count = 0;
+                       ((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
+                       ((struct mthca_data_seg *) wqe)->addr = 0;
+               }
+
+               srq->wrid[ind]  = wr->wr_id;
+               srq->first_free = next_ind;
+       }
+
+       if (likely(nreq)) {
+               srq->counter += nreq;
+
+               /*
+                * Make sure that descriptors are written before
+                * we write doorbell record.
+                */
+               wmb();
+               *srq->db = cpu_to_be32(srq->counter);
+       }
+
+       spin_unlock_irqrestore(&srq->lock, flags);
+       return err;
+}
+
+int __devinit mthca_init_srq_table(struct mthca_dev *dev)
+{
+       int err;
+
+       if (!(dev->mthca_flags & MTHCA_FLAG_SRQ))
+               return 0;
+
+       spin_lock_init(&dev->srq_table.lock);
+
+       err = mthca_alloc_init(&dev->srq_table.alloc,
+                              dev->limits.num_srqs,
+                              dev->limits.num_srqs - 1,
+                              dev->limits.reserved_srqs);
+       if (err)
+               return err;
+
+       err = mthca_array_init(&dev->srq_table.srq,
+                              dev->limits.num_srqs);
+       if (err)
+               mthca_alloc_cleanup(&dev->srq_table.alloc);
+
+       return err;
+}
+
+void __devexit mthca_cleanup_srq_table(struct mthca_dev *dev)
+{
+       if (!(dev->mthca_flags & MTHCA_FLAG_SRQ))
+               return;
+
+       mthca_array_cleanup(&dev->srq_table.srq, dev->limits.num_srqs);
+       mthca_alloc_cleanup(&dev->srq_table.alloc);
+}
index 3024c1b4547d790e3f9cf0bca4c87bf01c736fb6..41613ec8a04e63c92fdfdbfe5d82e897c63c6a8b 100644 (file)
@@ -69,6 +69,17 @@ struct mthca_create_cq_resp {
        __u32 reserved;
 };
 
+struct mthca_create_srq {
+       __u32 lkey;
+       __u32 db_index;
+       __u64 db_page;
+};
+
+struct mthca_create_srq_resp {
+       __u32 srqn;
+       __u32 reserved;
+};
+
 struct mthca_create_qp {
        __u32 lkey;
        __u32 reserved;
diff --git a/drivers/infiniband/hw/mthca/mthca_wqe.h b/drivers/infiniband/hw/mthca/mthca_wqe.h
new file mode 100644 (file)
index 0000000..1f4c0ff
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: mthca_wqe.h 3047 2005-08-10 03:59:35Z roland $
+ */
+
+#ifndef MTHCA_WQE_H
+#define MTHCA_WQE_H
+
+#include <linux/types.h>
+
+enum {
+       MTHCA_NEXT_DBD       = 1 << 7,
+       MTHCA_NEXT_FENCE     = 1 << 6,
+       MTHCA_NEXT_CQ_UPDATE = 1 << 3,
+       MTHCA_NEXT_EVENT_GEN = 1 << 2,
+       MTHCA_NEXT_SOLICIT   = 1 << 1,
+
+       MTHCA_MLX_VL15       = 1 << 17,
+       MTHCA_MLX_SLR        = 1 << 16
+};
+
+enum {
+       MTHCA_INVAL_LKEY = 0x100
+};
+
+struct mthca_next_seg {
+       __be32 nda_op;          /* [31:6] next WQE [4:0] next opcode */
+       __be32 ee_nds;          /* [31:8] next EE  [7] DBD [6] F [5:0] next WQE size */
+       __be32 flags;           /* [3] CQ [2] Event [1] Solicit */
+       __be32 imm;             /* immediate data */
+};
+
+struct mthca_tavor_ud_seg {
+       u32    reserved1;
+       __be32 lkey;
+       __be64 av_addr;
+       u32    reserved2[4];
+       __be32 dqpn;
+       __be32 qkey;
+       u32    reserved3[2];
+};
+
+struct mthca_arbel_ud_seg {
+       __be32 av[8];
+       __be32 dqpn;
+       __be32 qkey;
+       u32    reserved[2];
+};
+
+struct mthca_bind_seg {
+       __be32 flags;           /* [31] Atomic [30] rem write [29] rem read */
+       u32    reserved;
+       __be32 new_rkey;
+       __be32 lkey;
+       __be64 addr;
+       __be64 length;
+};
+
+struct mthca_raddr_seg {
+       __be64 raddr;
+       __be32 rkey;
+       u32    reserved;
+};
+
+struct mthca_atomic_seg {
+       __be64 swap_add;
+       __be64 compare;
+};
+
+struct mthca_data_seg {
+       __be32 byte_count;
+       __be32 lkey;
+       __be64 addr;
+};
+
+struct mthca_mlx_seg {
+       __be32 nda_op;
+       __be32 nds;
+       __be32 flags;           /* [17] VL15 [16] SLR [14:12] static rate
+                                  [11:8] SL [3] C [2] E */
+       __be16 rlid;
+       __be16 vcrc;
+};
+
+#endif /* MTHCA_WQE_H */
index 394bc08abc6fc318677f049bd3d0fc639931a69f..8935e74ae3f8e9608ced0be86d2e3818db268dd8 100644 (file)
@@ -1,5 +1,3 @@
-EXTRA_CFLAGS += -Idrivers/infiniband/include
-
 obj-$(CONFIG_INFINIBAND_IPOIB)                 += ib_ipoib.o
 
 ib_ipoib-y                                     := ipoib_main.o \
index 04c98f54e9c4dbc4740fc724a571a0978670c834..bea960b8191feffff376dd7b64a26c2d9586d6f6 100644 (file)
@@ -1,5 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -49,9 +51,9 @@
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
 
-#include <ib_verbs.h>
-#include <ib_pack.h>
-#include <ib_sa.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_pack.h>
+#include <rdma/ib_sa.h>
 
 /* constants */
 
@@ -88,8 +90,8 @@ enum {
 /* structs */
 
 struct ipoib_header {
-       u16 proto;
-       u16 reserved;
+       __be16  proto;
+       u16     reserved;
 };
 
 struct ipoib_pseudoheader {
index a84e5fe0f1933d8e06acacd0b3ea86b4b1612381..38b150f775e7fdf931315869b2ce5e23335d6573 100644 (file)
@@ -97,7 +97,7 @@ static int ipoib_mcg_seq_show(struct seq_file *file, void *iter_ptr)
 
                for (n = 0, i = 0; i < sizeof mgid / 2; ++i) {
                        n += sprintf(gid_buf + n, "%x",
-                                    be16_to_cpu(((u16 *)mgid.raw)[i]));
+                                    be16_to_cpu(((__be16 *) mgid.raw)[i]));
                        if (i < sizeof mgid / 2 - 1)
                                gid_buf[n++] = ':';
                }
index eee82363167da841c3aad9b56443bac922bceeb0..ef0e3894863c023c08082c4c201da070fb393871 100644 (file)
@@ -1,5 +1,8 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -35,7 +38,7 @@
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 
-#include <ib_cache.h>
+#include <rdma/ib_cache.h>
 
 #include "ipoib.h"
 
index fa00816a3cf7d31edb604481b810f445c2d7720e..0e8ac138e355bd4c71e2c21f58a809eb7d0f190e 100644 (file)
@@ -1,5 +1,7 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -34,7 +36,6 @@
 
 #include "ipoib.h"
 
-#include <linux/version.h>
 #include <linux/module.h>
 
 #include <linux/init.h>
@@ -607,8 +608,8 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                ipoib_warn(priv, "Unicast, no %s: type %04x, QPN %06x "
                                           IPOIB_GID_FMT "\n",
                                           skb->dst ? "neigh" : "dst",
-                                          be16_to_cpup((u16 *) skb->data),
-                                          be32_to_cpup((u32 *) phdr->hwaddr),
+                                          be16_to_cpup((__be16 *) skb->data),
+                                          be32_to_cpup((__be32 *) phdr->hwaddr),
                                           IPOIB_GID_ARG(*(union ib_gid *) (phdr->hwaddr + 4)));
                                dev_kfree_skb_any(skb);
                                ++priv->stats.tx_dropped;
@@ -671,7 +672,7 @@ static void ipoib_set_mcast_list(struct net_device *dev)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
 
-       schedule_work(&priv->restart_task);
+       queue_work(ipoib_workqueue, &priv->restart_task);
 }
 
 static void ipoib_neigh_destructor(struct neighbour *n)
@@ -780,15 +781,11 @@ void ipoib_dev_cleanup(struct net_device *dev)
 
        ipoib_ib_dev_cleanup(dev);
 
-       if (priv->rx_ring) {
-               kfree(priv->rx_ring);
-               priv->rx_ring = NULL;
-       }
+       kfree(priv->rx_ring);
+       kfree(priv->tx_ring);
 
-       if (priv->tx_ring) {
-               kfree(priv->tx_ring);
-               priv->tx_ring = NULL;
-       }
+       priv->rx_ring = NULL;
+       priv->tx_ring = NULL;
 }
 
 static void ipoib_setup(struct net_device *dev)
@@ -886,6 +883,12 @@ static ssize_t create_child(struct class_device *cdev,
        if (pkey < 0 || pkey > 0xffff)
                return -EINVAL;
 
+       /*
+        * Set the full membership bit, so that we join the right
+        * broadcast group, etc.
+        */
+       pkey |= 0x8000;
+
        ret = ipoib_vlan_add(container_of(cdev, struct net_device, class_dev),
                             pkey);
 
@@ -938,6 +941,12 @@ static struct net_device *ipoib_add_port(const char *format,
                goto alloc_mem_failed;
        }
 
+       /*
+        * Set the full membership bit, so that we join the right
+        * broadcast group, etc.
+        */
+       priv->pkey |= 0x8000;
+
        priv->dev->broadcast[8] = priv->pkey >> 8;
        priv->dev->broadcast[9] = priv->pkey & 0xff;
 
index 70208c3d21e28d415a8f9a82f886e62b64c4590d..aca7aea18a69006ed0b403a439611c66dd0f9781 100644 (file)
@@ -1,5 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -357,7 +359,7 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast)
 
        rec.mgid     = mcast->mcmember.mgid;
        rec.port_gid = priv->local_gid;
-       rec.pkey     = be16_to_cpu(priv->pkey);
+       rec.pkey     = cpu_to_be16(priv->pkey);
 
        ret = ib_sa_mcmember_rec_set(priv->ca, priv->port, &rec,
                                     IB_SA_MCMEMBER_REC_MGID            |
@@ -457,7 +459,7 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast,
 
        rec.mgid     = mcast->mcmember.mgid;
        rec.port_gid = priv->local_gid;
-       rec.pkey     = be16_to_cpu(priv->pkey);
+       rec.pkey     = cpu_to_be16(priv->pkey);
 
        comp_mask =
                IB_SA_MCMEMBER_REC_MGID         |
@@ -646,7 +648,7 @@ static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast)
 
        rec.mgid     = mcast->mcmember.mgid;
        rec.port_gid = priv->local_gid;
-       rec.pkey     = be16_to_cpu(priv->pkey);
+       rec.pkey     = cpu_to_be16(priv->pkey);
 
        /* Remove ourselves from the multicast group */
        ret = ipoib_mcast_detach(dev, be16_to_cpu(mcast->mcmember.mlid),
index 4933edf062c2bbc95890fd33da01484aea48a981..79f59d0563edc04b04a1e9d211ce6f6bbfa4c538 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -32,7 +33,7 @@
  * $Id: ipoib_verbs.c 1349 2004-12-16 21:09:43Z roland $
  */
 
-#include <ib_cache.h>
+#include <rdma/ib_cache.h>
 
 #include "ipoib.h"
 
index 94b8ea812feff35bcf3bdee04ee85b2df1937f80..332d730e60c23a81e3576ad9e27c00fd43f1cd7e 100644 (file)
@@ -32,7 +32,6 @@
  * $Id: ipoib_vlan.c 1349 2004-12-16 21:09:43Z roland $
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 
 #include <linux/init.h>
index 20e3a165989fb943b0ce29a2009120ce86b57f0b..19c14c4beb44e2537b2207435e5a625efb9a5f2f 100644 (file)
@@ -160,6 +160,8 @@ struct input_event_compat {
 #  define COMPAT_TEST IS_IA32_PROCESS(ia64_task_regs(current))
 #elif defined(CONFIG_ARCH_S390)
 #  define COMPAT_TEST test_thread_flag(TIF_31BIT)
+#elif defined(CONFIG_MIPS)
+#  define COMPAT_TEST (current->thread.mflags & MF_32BIT_ADDR)
 #else
 #  define COMPAT_TEST test_thread_flag(TIF_32BIT)
 #endif
@@ -391,6 +393,7 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                                case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
                                                case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
                                                case EV_FF:  bits = dev->ffbit;  len = FF_MAX;  break;
+                                               case EV_SW:  bits = dev->swbit;  len = SW_MAX;  break;
                                                default: return -EINVAL;
                                        }
                                        len = NBITS(len) * sizeof(long);
@@ -419,6 +422,13 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                        return copy_to_user(p, dev->snd, len) ? -EFAULT : len;
                                }
 
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) {
+                                       int len;
+                                       len = NBITS(SW_MAX) * sizeof(long);
+                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+                                       return copy_to_user(p, dev->sw, len) ? -EFAULT : len;
+                               }
+
                                if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
                                        int len;
                                        if (!dev->name) return -ENOENT;
index a0118038330a9702f0fd7a03e8269920575f8d18..462f8d300aae5629719c58a983627fed065879a5 100644 (file)
@@ -75,7 +75,7 @@ static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id
        if (!request_region(ioport, iolen, "emu10k1-gp"))
                return -EBUSY;
 
-       emu = kcalloc(1, sizeof(struct emu), GFP_KERNEL);
+       emu = kzalloc(sizeof(struct emu), GFP_KERNEL);
        port = gameport_allocate_port();
        if (!emu || !port) {
                printk(KERN_ERR "emu10k1-gp: Memory allocation failed\n");
index 57615bc639061384d7243230620cd542952213f1..47e93daa0fa7c498aec5ae237135126d0ef2e040 100644 (file)
@@ -83,7 +83,7 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device
        struct fm801_gp *gp;
        struct gameport *port;
 
-       gp = kcalloc(1, sizeof(struct fm801_gp), GFP_KERNEL);
+       gp = kzalloc(sizeof(struct fm801_gp), GFP_KERNEL);
        port = gameport_allocate_port();
        if (!gp || !port) {
                printk(KERN_ERR "fm801-gp: Memory allocation failed\n");
index 70f051894a3cfa4d50f5dda7268c6af26e63b96f..d2e55dc956bafd3477ebd4e7ea448263b6375fcd 100644 (file)
@@ -142,7 +142,7 @@ static int ns558_isa_probe(int io)
                        return -EBUSY;
        }
 
-       ns558 = kcalloc(1, sizeof(struct ns558), GFP_KERNEL);
+       ns558 = kzalloc(sizeof(struct ns558), GFP_KERNEL);
        port = gameport_allocate_port();
        if (!ns558 || !port) {
                printk(KERN_ERR "ns558: Memory allocation failed.\n");
@@ -215,7 +215,7 @@ static int ns558_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *did)
        if (!request_region(ioport, iolen, "ns558-pnp"))
                return -EBUSY;
 
-       ns558 = kcalloc(1, sizeof(struct ns558), GFP_KERNEL);
+       ns558 = kzalloc(sizeof(struct ns558), GFP_KERNEL);
        port = gameport_allocate_port();
        if (!ns558 || !port) {
                printk(KERN_ERR "ns558: Memory allocation failed\n");
index a275211c8e1e3434a2788771b63b68077807892f..88636a204525e84862972ea7034c02ae020ae4bb 100644 (file)
@@ -89,6 +89,15 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
 
                        break;
 
+               case EV_SW:
+
+                       if (code > SW_MAX || !test_bit(code, dev->swbit) || !!test_bit(code, dev->sw) == value)
+                               return;
+
+                       change_bit(code, dev->sw);
+
+                       break;
+
                case EV_ABS:
 
                        if (code > ABS_MAX || !test_bit(code, dev->absbit))
@@ -402,6 +411,7 @@ static void input_call_hotplug(char *verb, struct input_dev *dev)
        SPRINTF_BIT_A2(ledbit, "LED=", LED_MAX, EV_LED);
        SPRINTF_BIT_A2(sndbit, "SND=", SND_MAX, EV_SND);
        SPRINTF_BIT_A2(ffbit,  "FF=",  FF_MAX, EV_FF);
+       SPRINTF_BIT_A2(swbit,  "SW=",  SW_MAX, EV_SW);
 
        envp[i++] = NULL;
 
@@ -490,6 +500,7 @@ static int input_devices_read(char *buf, char **start, off_t pos, int count, int
                SPRINTF_BIT_B2(ledbit, "LED=", LED_MAX, EV_LED);
                SPRINTF_BIT_B2(sndbit, "SND=", SND_MAX, EV_SND);
                SPRINTF_BIT_B2(ffbit,  "FF=",  FF_MAX, EV_FF);
+               SPRINTF_BIT_B2(swbit,  "SW=",  SW_MAX, EV_SW);
 
                len += sprintf(buf + len, "\n");
 
index bf34f75b9467f6650c5447a020f562787bccacfb..bf65430181faf0f2ee5db443f950bd35c90963f8 100644 (file)
@@ -269,7 +269,7 @@ static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv)
        int i;
        int err;
 
-       if (!(a3d = kcalloc(1, sizeof(struct a3d), GFP_KERNEL)))
+       if (!(a3d = kzalloc(sizeof(struct a3d), GFP_KERNEL)))
                return -ENOMEM;
 
        a3d->gameport = gameport;
index 265962956c63cbf9d924f8bd8518981d10cf2ea5..cf35ae638a0d2c129544d16d90c87c22027e2b4e 100644 (file)
@@ -469,7 +469,7 @@ static int adi_connect(struct gameport *gameport, struct gameport_driver *drv)
        int i;
        int err;
 
-       if (!(port = kcalloc(1, sizeof(struct adi_port), GFP_KERNEL)))
+       if (!(port = kzalloc(sizeof(struct adi_port), GFP_KERNEL)))
                return -ENOMEM;
 
        port->gameport = gameport;
index c3a5739030c3ba45d8dd1dda01cd79382faf3478..64b1313a3c66d0c6400dcbd8e35c9f60c0041bd9 100644 (file)
@@ -655,7 +655,7 @@ static int analog_connect(struct gameport *gameport, struct gameport_driver *drv
        int i;
        int err;
 
-       if (!(port = kcalloc(1, sizeof(struct analog_port), GFP_KERNEL)))
+       if (!(port = kzalloc(sizeof(struct analog_port), GFP_KERNEL)))
                return - ENOMEM;
 
        err = analog_init_port(gameport, drv, port);
index a6002205328f80d16bf882054f5bfc32f9b806ac..0b2e9fa2657969457dfc2db4c12b39c5984f8966 100644 (file)
@@ -163,7 +163,7 @@ static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv)
        int i, j;
        int err;
 
-       if (!(cobra = kcalloc(1, sizeof(struct cobra), GFP_KERNEL)))
+       if (!(cobra = kzalloc(sizeof(struct cobra), GFP_KERNEL)))
                return -ENOMEM;
 
        cobra->gameport = gameport;
index fbd3eed07f90403806e1bce3212781a638e35241..2a3e4bb2da507ef78f9cc33cf88b88e19d262fac 100644 (file)
@@ -572,7 +572,7 @@ static struct db9 __init *db9_probe(int *config, int nargs)
                }
        }
 
-       if (!(db9 = kcalloc(1, sizeof(struct db9), GFP_KERNEL))) {
+       if (!(db9 = kzalloc(sizeof(struct db9), GFP_KERNEL))) {
                parport_put_port(pp);
                return NULL;
        }
index 95bbdd302aad8639bacc4817e6f49b472e749211..5427bf9fc862320261a2c45aebbe53beeb761d00 100644 (file)
@@ -554,7 +554,7 @@ static struct gc __init *gc_probe(int *config, int nargs)
                return NULL;
        }
 
-       if (!(gc = kcalloc(1, sizeof(struct gc), GFP_KERNEL))) {
+       if (!(gc = kzalloc(sizeof(struct gc), GFP_KERNEL))) {
                parport_put_port(pp);
                return NULL;
        }
index 7d969420066c75c0140eed3ba2d88bc9cf7fedf5..8e4f92b115e6aa8188c70745011e40c71e00ab48 100644 (file)
@@ -242,7 +242,7 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
        unsigned char data[GF2K_LENGTH];
        int i, err;
 
-       if (!(gf2k = kcalloc(1, sizeof(struct gf2k), GFP_KERNEL)))
+       if (!(gf2k = kzalloc(sizeof(struct gf2k), GFP_KERNEL)))
                return -ENOMEM;
 
        gf2k->gameport = gameport;
index d1500d2562d67ec99fcaa72de01dac377cf14d23..9d3f910dd568b4cb46f7daf8ee0a6027b7ab5f8a 100644 (file)
@@ -301,7 +301,7 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
        int i, j, t;
        int err;
 
-       if (!(grip = kcalloc(1, sizeof(struct grip), GFP_KERNEL)))
+       if (!(grip = kzalloc(sizeof(struct grip), GFP_KERNEL)))
                return -ENOMEM;
 
        grip->gameport = gameport;
index 0da7bd133ccf39f03e948d60e2bfa19e18b742ea..da17eee6f5741f45cea1d86eca0be7c5045307a9 100644 (file)
@@ -607,7 +607,7 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
        struct grip_mp *grip;
        int err;
 
-       if (!(grip = kcalloc(1, sizeof(struct grip_mp), GFP_KERNEL)))
+       if (!(grip = kzalloc(sizeof(struct grip_mp), GFP_KERNEL)))
                return -ENOMEM;
 
        grip->gameport = gameport;
index f93da7bc082d08622b0859222a87b7e981407304..6a70ec429f063eb28d6f6f251037b695cb794841 100644 (file)
@@ -183,7 +183,7 @@ static int guillemot_connect(struct gameport *gameport, struct gameport_driver *
        int i, t;
        int err;
 
-       if (!(guillemot = kcalloc(1, sizeof(struct guillemot), GFP_KERNEL)))
+       if (!(guillemot = kzalloc(sizeof(struct guillemot), GFP_KERNEL)))
                return -ENOMEM;
 
        guillemot->gameport = gameport;
index 9d3f8c38cb097391403f44846781a75d4c68d845..d7b3472bd686611a5e30276203ea42778b1ea199 100644 (file)
@@ -212,7 +212,7 @@ static int interact_connect(struct gameport *gameport, struct gameport_driver *d
        int i, t;
        int err;
 
-       if (!(interact = kcalloc(1, sizeof(struct interact), GFP_KERNEL)))
+       if (!(interact = kzalloc(sizeof(struct interact), GFP_KERNEL)))
                return -ENOMEM;
 
        interact->gameport = gameport;
index 47144a7ed9e750f4682eac415c9d6bf7c8ac1b49..9e0353721a35d8892e96d5a5779075bafb1b92e5 100644 (file)
@@ -590,7 +590,7 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
 
        comment[0] = 0;
 
-       sw = kcalloc(1, sizeof(struct sw), GFP_KERNEL);
+       sw = kzalloc(sizeof(struct sw), GFP_KERNEL);
        buf = kmalloc(SW_LENGTH, GFP_KERNEL);
        idbuf = kmalloc(SW_LENGTH, GFP_KERNEL);
        if (!sw || !buf || !idbuf) {
index 9eb9954cac6e2584e70ef4c9a9d6646c494e348d..7431efc4330edb090696ea66b78e06e5c4d30378 100644 (file)
@@ -262,7 +262,7 @@ static int tmdc_connect(struct gameport *gameport, struct gameport_driver *drv)
        int i, j, k, l, m;
        int err;
 
-       if (!(tmdc = kcalloc(1, sizeof(struct tmdc), GFP_KERNEL)))
+       if (!(tmdc = kzalloc(sizeof(struct tmdc), GFP_KERNEL)))
                return -ENOMEM;
 
        tmdc->gameport = gameport;
index 28100d461cb751c1c1d8b34f4fb5001b970e1b2c..0c5b9c8297cd4ff1afb1c1fe979f962d944a6dca 100644 (file)
@@ -178,7 +178,7 @@ static struct tgfx __init *tgfx_probe(int *config, int nargs)
                return NULL;
        }
 
-       if (!(tgfx = kcalloc(1, sizeof(struct tgfx), GFP_KERNEL))) {
+       if (!(tgfx = kzalloc(sizeof(struct tgfx), GFP_KERNEL))) {
                parport_put_port(pp);
                return NULL;
        }
index a8551711e8d60031ffaadbb1e7e632a32f162aed..cd4b6e795013a841399cdcfbb25012990e240054 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
+#include <linux/jiffies.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <asm/irq.h>
@@ -32,7 +33,6 @@
 /* zero code, 124 scancodes + 3 hinge combinations */
 #define        NR_SCANCODES            ( SCANCODE(KB_ROWS-1,KB_COLS-1) +1 +1 +3 )
 #define SCAN_INTERVAL          (HZ/10)
-#define CORGIKBD_PRESSED       1
 
 #define HINGE_SCAN_INTERVAL            (HZ/4)
 
@@ -73,25 +73,13 @@ struct corgikbd {
        struct input_dev input;
        char phys[32];
 
-       unsigned char state[ARRAY_SIZE(corgikbd_keycode)];
        spinlock_t lock;
-
        struct timer_list timer;
        struct timer_list htimer;
-};
 
-static void handle_scancode(unsigned int pressed,unsigned int scancode, struct corgikbd *corgikbd_data)
-{
-       if (pressed && !(corgikbd_data->state[scancode] & CORGIKBD_PRESSED)) {
-               corgikbd_data->state[scancode] |= CORGIKBD_PRESSED;
-               input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], 1);
-               if (corgikbd_data->keycode[scancode] == CORGI_KEY_OFF)
-                       input_event(&corgikbd_data->input, EV_PWR, CORGI_KEY_OFF, 1);
-       } else if (!pressed && corgikbd_data->state[scancode] & CORGIKBD_PRESSED) {
-               corgikbd_data->state[scancode] &= ~CORGIKBD_PRESSED;
-               input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], 0);
-       }
-}
+       unsigned int suspended;
+       unsigned long suspend_jiffies;
+};
 
 #define KB_DISCHARGE_DELAY     10
 #define KB_ACTIVATE_DELAY      10
@@ -105,36 +93,36 @@ static void handle_scancode(unsigned int pressed,unsigned int scancode, struct c
  */
 static inline void corgikbd_discharge_all(void)
 {
-       // STROBE All HiZ
+       /* STROBE All HiZ */
        GPCR2  = CORGI_GPIO_ALL_STROBE_BIT;
        GPDR2 &= ~CORGI_GPIO_ALL_STROBE_BIT;
 }
 
 static inline void corgikbd_activate_all(void)
 {
-       // STROBE ALL -> High
+       /* STROBE ALL -> High */
        GPSR2  = CORGI_GPIO_ALL_STROBE_BIT;
        GPDR2 |= CORGI_GPIO_ALL_STROBE_BIT;
 
        udelay(KB_DISCHARGE_DELAY);
 
-       // Clear any interrupts we may have triggered when altering the GPIO lines
+       /* Clear any interrupts we may have triggered when altering the GPIO lines */
        GEDR1 = CORGI_GPIO_HIGH_SENSE_BIT;
        GEDR2 = CORGI_GPIO_LOW_SENSE_BIT;
 }
 
 static inline void corgikbd_activate_col(int col)
 {
-       // STROBE col -> High, not col -> HiZ
+       /* STROBE col -> High, not col -> HiZ */
        GPSR2 = CORGI_GPIO_STROBE_BIT(col);
        GPDR2 = (GPDR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(col);
 }
 
 static inline void corgikbd_reset_col(int col)
 {
-       // STROBE col -> Low
+       /* STROBE col -> Low */
        GPCR2 = CORGI_GPIO_STROBE_BIT(col);
-       // STROBE col -> out, not col -> HiZ
+       /* STROBE col -> out, not col -> HiZ */
        GPDR2 = (GPDR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(col);
 }
 
@@ -149,10 +137,13 @@ static inline void corgikbd_reset_col(int col)
 /* Scan the hardware keyboard and push any changes up through the input layer */
 static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs *regs)
 {
-       unsigned int row, col, rowd, scancode;
+       unsigned int row, col, rowd;
        unsigned long flags;
        unsigned int num_pressed;
 
+       if (corgikbd_data->suspended)
+               return;
+
        spin_lock_irqsave(&corgikbd_data->lock, flags);
 
        if (regs)
@@ -173,10 +164,21 @@ static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs
 
                rowd = GET_ROWS_STATUS(col);
                for (row = 0; row < KB_ROWS; row++) {
+                       unsigned int scancode, pressed;
+
                        scancode = SCANCODE(row, col);
-                       handle_scancode((rowd & KB_ROWMASK(row)), scancode, corgikbd_data);
-                       if (rowd & KB_ROWMASK(row))
+                       pressed = rowd & KB_ROWMASK(row);
+
+                       input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], pressed);
+
+                       if (pressed)
                                num_pressed++;
+
+                       if (pressed && (corgikbd_data->keycode[scancode] == CORGI_KEY_OFF)
+                                       && time_after(jiffies, corgikbd_data->suspend_jiffies + HZ)) {
+                               input_event(&corgikbd_data->input, EV_PWR, CORGI_KEY_OFF, 1);
+                               corgikbd_data->suspend_jiffies=jiffies;
+                       }
                }
                corgikbd_reset_col(col);
        }
@@ -221,8 +223,11 @@ static void corgikbd_timer_callback(unsigned long data)
  * The hinge switches generate no interrupt so they need to be
  * monitored by a timer.
  *
- * When we detect changes, we debounce it and then pass the three
- * positions the system can take as keypresses to the input system.
+ * We debounce the switches and pass them to the input system.
+ *
+ *  gprr == 0x00 - Keyboard with Landscape Screen
+ *          0x08 - No Keyboard with Portrait Screen
+ *          0x0c - Keyboard and Screen Closed
  */
 
 #define HINGE_STABLE_COUNT 2
@@ -235,7 +240,7 @@ static void corgikbd_hinge_timer(unsigned long data)
        unsigned long gprr;
        unsigned long flags;
 
-       gprr = read_scoop_reg(SCOOP_GPRR) & (CORGI_SCP_SWA | CORGI_SCP_SWB);
+       gprr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_GPRR) & (CORGI_SCP_SWA | CORGI_SCP_SWB);
        if (gprr != sharpsl_hinge_state) {
                hinge_count = 0;
                sharpsl_hinge_state = gprr;
@@ -244,9 +249,8 @@ static void corgikbd_hinge_timer(unsigned long data)
                if (hinge_count >= HINGE_STABLE_COUNT) {
                        spin_lock_irqsave(&corgikbd_data->lock, flags);
 
-                       handle_scancode((sharpsl_hinge_state == 0x00), 125, corgikbd_data); /* Keyboard with Landscape Screen */
-                       handle_scancode((sharpsl_hinge_state == 0x08), 126, corgikbd_data); /* No Keyboard with Portrait Screen */
-                       handle_scancode((sharpsl_hinge_state == 0x0c), 127, corgikbd_data); /* Keyboard and Screen Closed  */
+                       input_report_switch(&corgikbd_data->input, SW_0, ((sharpsl_hinge_state & CORGI_SCP_SWA) != 0));
+                       input_report_switch(&corgikbd_data->input, SW_1, ((sharpsl_hinge_state & CORGI_SCP_SWB) != 0));
                        input_sync(&corgikbd_data->input);
 
                        spin_unlock_irqrestore(&corgikbd_data->lock, flags);
@@ -255,19 +259,45 @@ static void corgikbd_hinge_timer(unsigned long data)
        mod_timer(&corgikbd_data->htimer, jiffies + HINGE_SCAN_INTERVAL);
 }
 
+#ifdef CONFIG_PM
+static int corgikbd_suspend(struct device *dev, pm_message_t state, uint32_t level)
+{
+       if (level == SUSPEND_POWER_DOWN) {
+               struct corgikbd *corgikbd = dev_get_drvdata(dev);
+               corgikbd->suspended = 1;
+       }
+       return 0;
+}
+
+static int corgikbd_resume(struct device *dev, uint32_t level)
+{
+       if (level == RESUME_POWER_ON) {
+               struct corgikbd *corgikbd = dev_get_drvdata(dev);
+
+               /* Upon resume, ignore the suspend key for a short while */
+               corgikbd->suspend_jiffies=jiffies;
+               corgikbd->suspended = 0;
+       }
+       return 0;
+}
+#else
+#define corgikbd_suspend       NULL
+#define corgikbd_resume                NULL
+#endif
+
 static int __init corgikbd_probe(struct device *dev)
 {
        int i;
        struct corgikbd *corgikbd;
 
-       corgikbd = kcalloc(1, sizeof(struct corgikbd), GFP_KERNEL);
+       corgikbd = kzalloc(sizeof(struct corgikbd), GFP_KERNEL);
        if (!corgikbd)
                return -ENOMEM;
 
        dev_set_drvdata(dev,corgikbd);
        strcpy(corgikbd->phys, "corgikbd/input0");
 
-       spin_lock_init(corgikbd->lock);
+       spin_lock_init(&corgikbd->lock);
 
        /* Init Keyboard rescan timer */
        init_timer(&corgikbd->timer);
@@ -279,6 +309,8 @@ static int __init corgikbd_probe(struct device *dev)
        corgikbd->htimer.function = corgikbd_hinge_timer;
        corgikbd->htimer.data = (unsigned long) corgikbd;
 
+       corgikbd->suspend_jiffies=jiffies;
+
        init_input_dev(&corgikbd->input);
        corgikbd->input.private = corgikbd;
        corgikbd->input.name = "Corgi Keyboard";
@@ -288,7 +320,7 @@ static int __init corgikbd_probe(struct device *dev)
        corgikbd->input.id.vendor = 0x0001;
        corgikbd->input.id.product = 0x0001;
        corgikbd->input.id.version = 0x0100;
-       corgikbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR);
+       corgikbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW);
        corgikbd->input.keycode = corgikbd->keycode;
        corgikbd->input.keycodesize = sizeof(unsigned char);
        corgikbd->input.keycodemax = ARRAY_SIZE(corgikbd_keycode);
@@ -297,6 +329,8 @@ static int __init corgikbd_probe(struct device *dev)
        for (i = 0; i < ARRAY_SIZE(corgikbd_keycode); i++)
                set_bit(corgikbd->keycode[i], corgikbd->input.keybit);
        clear_bit(0, corgikbd->input.keybit);
+       set_bit(SW_0, corgikbd->input.swbit);
+       set_bit(SW_1, corgikbd->input.swbit);
 
        input_register_device(&corgikbd->input);
        mod_timer(&corgikbd->htimer, jiffies + HINGE_SCAN_INTERVAL);
@@ -343,6 +377,8 @@ static struct device_driver corgikbd_driver = {
        .bus            = &platform_bus_type,
        .probe          = corgikbd_probe,
        .remove         = corgikbd_remove,
+       .suspend        = corgikbd_suspend,
+       .resume         = corgikbd_resume,
 };
 
 static int __devinit corgikbd_init(void)
index 2bb2fe78bdca988f34ccae1cdebf0ba0faff79c5..12bdd3eff923ea32042d76f47110d217c43243f7 100644 (file)
@@ -883,7 +883,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
                psmouse_deactivate(parent);
        }
 
-       if (!(psmouse = kcalloc(1, sizeof(struct psmouse), GFP_KERNEL))) {
+       if (!(psmouse = kzalloc(sizeof(struct psmouse), GFP_KERNEL))) {
                retval = -ENOMEM;
                goto out;
        }
index 79ca38469159b90abd6d1f52bffb162dbb89968c..1bd88fca05425a9d6ddfb9f52c36d296f832fad2 100644 (file)
@@ -87,7 +87,7 @@ static int serport_ldisc_open(struct tty_struct *tty)
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       serport = kcalloc(1, sizeof(struct serport), GFP_KERNEL);
+       serport = kzalloc(sizeof(struct serport), GFP_KERNEL);
        if (!serport)
                return -ENOMEM;
 
@@ -165,7 +165,7 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, u
        if (test_and_set_bit(SERPORT_BUSY, &serport->flags))
                return -EBUSY;
 
-       serport->serio = serio = kcalloc(1, sizeof(struct serio), GFP_KERNEL);
+       serport->serio = serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
        if (!serio)
                return -ENOMEM;
 
index 3f8b61cfbc37977abc2453a2fab177e1149a410a..5d19261b884fe8f09ebe48432589011080942e41 100644 (file)
@@ -53,11 +53,8 @@ struct corgi_ts {
 
 #define SyncHS()       while((STATUS_HSYNC) == 0); while((STATUS_HSYNC) != 0);
 #define CCNT(a)                asm volatile ("mrc p14, 0, %0, C1, C0, 0" : "=r"(a))
-#define CCNT_ON()      {int pmnc = 1; asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(pmnc));}
-#define CCNT_OFF()     {int pmnc = 0; asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(pmnc));}
-
-#define WAIT_HS_400_VGA                7013U   // 17.615us
-#define WAIT_HS_400_QVGA       16622U  // 41.750us
+#define PMNC_GET(x)    asm volatile ("mrc p14, 0, %0, C0, C0, 0" : "=r"(x))
+#define PMNC_SET(x)    asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(x))
 
 
 /* ADS7846 Touch Screen Controller bit definitions */
@@ -69,41 +66,29 @@ struct corgi_ts {
 #define ADSCTRL_STS            (1u << 7)       /* Start Bit */
 
 /* External Functions */
-extern int w100fb_get_xres(void);
-extern int w100fb_get_blanking(void);
-extern int w100fb_get_fastsysclk(void);
+extern unsigned long w100fb_get_hsynclen(struct device *dev);
 extern unsigned int get_clk_frequency_khz(int info);
 
 static unsigned long calc_waittime(void)
 {
-       int w100fb_xres = w100fb_get_xres();
-       unsigned int waittime = 0;
-
-       if (w100fb_xres == 480 || w100fb_xres == 640) {
-               waittime = WAIT_HS_400_VGA * get_clk_frequency_khz(0) / 398131U;
-
-               if (w100fb_get_fastsysclk() == 100)
-                       waittime = waittime * 75 / 100;
-
-               if (w100fb_xres == 640)
-                       waittime *= 3;
+       unsigned long hsync_len = w100fb_get_hsynclen(&corgifb_device.dev);
 
-               return waittime;
-       }
-
-       return WAIT_HS_400_QVGA * get_clk_frequency_khz(0) / 398131U;
+       if (hsync_len)
+               return get_clk_frequency_khz(0)*1000/hsync_len;
+       else
+               return 0;
 }
 
 static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int address, unsigned long wait_time)
 {
+       unsigned long timer1 = 0, timer2, pmnc = 0;
        int pos = 0;
-       unsigned long timer1 = 0, timer2;
-       int dosleep;
 
-       dosleep = !w100fb_get_blanking();
+       if (wait_time && doSend) {
+               PMNC_GET(pmnc);
+               if (!(pmnc & 0x01))
+                       PMNC_SET(0x01);
 
-       if (dosleep && doSend) {
-               CCNT_ON();
                /* polling HSync */
                SyncHS();
                /* get CCNT */
@@ -119,11 +104,11 @@ static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int add
                corgi_ssp_ads7846_put(cmd);
                corgi_ssp_ads7846_get();
 
-               if (dosleep) {
+               if (wait_time) {
                        /* Wait after HSync */
                        CCNT(timer2);
                        if (timer2-timer1 > wait_time) {
-                               /* timeout */
+                               /* too slow - timeout, try again */
                                SyncHS();
                                /* get OSCR */
                                CCNT(timer1);
@@ -134,8 +119,8 @@ static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int add
                                CCNT(timer2);
                }
                corgi_ssp_ads7846_put(cmd);
-               if (dosleep)
-                       CCNT_OFF();
+               if (wait_time && !(pmnc & 0x01))
+                       PMNC_SET(pmnc);
        }
        return pos;
 }
@@ -244,7 +229,7 @@ static irqreturn_t ts_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 }
 
 #ifdef CONFIG_PM
-static int corgits_suspend(struct device *dev, uint32_t state, uint32_t level)
+static int corgits_suspend(struct device *dev, pm_message_t state, uint32_t level)
 {
        if (level == SUSPEND_POWER_DOWN) {
                struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
index afa46681f9833c576e3afd7b54f9a74debdac2bc..6ae6eb32211141a93c299a65f15dd8bd14e20a79 100644 (file)
@@ -606,7 +606,7 @@ handle_ack(act2000_card *card, act2000_chan *chan, __u8 blocknr) {
                 if ((((m->msg.data_b3_req.fakencci >> 8) & 0xff) == chan->ncci) &&
                    (m->msg.data_b3_req.blocknr == blocknr)) {
                        /* found corresponding DATA_B3_REQ */
-                        skb_unlink(tmp);
+                        skb_unlink(tmp, &card->ackq);
                        chan->queued -= m->msg.data_b3_req.datalen;
                        if (m->msg.data_b3_req.flags)
                                ret = m->msg.data_b3_req.datalen;
index 17cf7663c58233fda3610b9890d2e663254ba643..26c545fa223be8672a5e3cace0e4377b04af48a2 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/major.h>
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
@@ -1242,6 +1241,8 @@ struct IsdnCardState {
 
 #ifdef CONFIG_HISAX_ENTERNOW_PCI
 #define CARD_FN_ENTERNOW_PCI 1
+#else
+#define CARD_FN_ENTERNOW_PCI 0
 #endif
 
 #define TEI_PER_CARD 1
index f30e8e63ae0dedf9802a044d5d3c6eedd3679721..96c115e13389cd16b2d18a34bd5bc65e19d4fd47 100644 (file)
@@ -1786,7 +1786,6 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
                lp->stats.rx_bytes += skb->len;
        }
        skb->dev = ndev;
-       skb->input_dev = ndev;
        skb->pkt_type = PACKET_HOST;
        skb->mac.raw = skb->data;
 #ifdef ISDN_DEBUG_NET_DUMP
index 260a323a96d38c07003f80b92c2b3dad5c2c025a..d97a9be5469c45deb6f8d5965a3a84125c446314 100644 (file)
@@ -1177,7 +1177,6 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
                mlp->huptimer = 0;
 #endif /* CONFIG_IPPP_FILTER */
        skb->dev = dev;
-       skb->input_dev = dev;
        skb->mac.raw = skb->data;
        netif_rx(skb);
        /* net_dev->local->stats.rx_packets++; done in isdn_net.c */
index f47f2b9846d8fc45c55ef777a989316c9908c18e..38619e8cd8230b4c9d893fbb85976a6a9055df2e 100644 (file)
@@ -516,11 +516,11 @@ buffer_full:
 }
 
 int
-isdn_v110_stat_callback(int idx, isdn_ctrl * c)
+isdn_v110_stat_callback(int idx, isdn_ctrl *c)
 {
        isdn_v110_stream *v = NULL;
        int i;
-       int ret;
+       int ret = 0;
 
        if (idx < 0)
                return 0;
index 7c16c25fc5d471068945bf04d9bc00c63b4e037f..c0712a1ea5afabc9e7370371bf545fe11d1b118d 100644 (file)
@@ -708,7 +708,7 @@ static int __pmac media_bay_suspend(struct macio_dev *mdev, pm_message_t state)
 {
        struct media_bay_info   *bay = macio_get_drvdata(mdev);
 
-       if (state != mdev->ofdev.dev.power.power_state && state == PM_SUSPEND_MEM) {
+       if (state.event != mdev->ofdev.dev.power.power_state.event && state.event == PM_EVENT_SUSPEND) {
                down(&bay->lock);
                bay->sleeping = 1;
                set_mb_power(bay, 0);
@@ -723,8 +723,8 @@ static int __pmac media_bay_resume(struct macio_dev *mdev)
 {
        struct media_bay_info   *bay = macio_get_drvdata(mdev);
 
-       if (mdev->ofdev.dev.power.power_state != 0) {
-               mdev->ofdev.dev.power.power_state = 0;
+       if (mdev->ofdev.dev.power.power_state.event != PM_EVENT_ON) {
+               mdev->ofdev.dev.power.power_state = PMSG_ON;
 
                /* We re-enable the bay using it's previous content
                   only if it did not change. Note those bozo timings,
index 4a0a0ad2d03c09e7bff0e9185c4355e274514264..645a2e5c70ab494298b9d0359dcb38726d5fe4d6 100644 (file)
@@ -3065,7 +3065,7 @@ static int pmu_sys_suspended = 0;
 
 static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state)
 {
-       if (state != PM_SUSPEND_DISK || pmu_sys_suspended)
+       if (state.event != PM_EVENT_SUSPEND || pmu_sys_suspended)
                return 0;
 
        /* Suspend PMU event interrupts */
index d0a4bab220e5e6b5608e50810b3dead70e7be095..b82bc31504762e8bee7db798d44d1ce697b43258 100644 (file)
@@ -144,7 +144,7 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
        }
 
        /* Hash the cipher key with the given hash algorithm */
-       hash_tfm = crypto_alloc_tfm(opts, 0);
+       hash_tfm = crypto_alloc_tfm(opts, CRYPTO_TFM_REQ_MAY_SLEEP);
        if (hash_tfm == NULL) {
                ti->error = PFX "Error initializing ESSIV hash";
                return -EINVAL;
@@ -172,7 +172,8 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
 
        /* Setup the essiv_tfm with the given salt */
        essiv_tfm = crypto_alloc_tfm(crypto_tfm_alg_name(cc->tfm),
-                                    CRYPTO_TFM_MODE_ECB);
+                                    CRYPTO_TFM_MODE_ECB |
+                                    CRYPTO_TFM_REQ_MAY_SLEEP);
        if (essiv_tfm == NULL) {
                ti->error = PFX "Error allocating crypto tfm for ESSIV";
                kfree(salt);
@@ -587,7 +588,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto bad1;
        }
 
-       tfm = crypto_alloc_tfm(cipher, crypto_flags);
+       tfm = crypto_alloc_tfm(cipher, crypto_flags | CRYPTO_TFM_REQ_MAY_SLEEP);
        if (!tfm) {
                ti->error = PFX "Error allocating crypto tfm";
                goto bad1;
index 45754bb6a79994678901f967bc29dc3c91d34d62..9de000131a8a2cb729c9e66858d30ed0d5700088 100644 (file)
@@ -239,6 +239,11 @@ static void vm_dp_init(struct dpages *dp, void *data)
        dp->context_ptr = data;
 }
 
+static void dm_bio_destructor(struct bio *bio)
+{
+       bio_free(bio, _bios);
+}
+
 /*-----------------------------------------------------------------
  * IO routines that accept a list of pages.
  *---------------------------------------------------------------*/
@@ -263,6 +268,7 @@ static void do_region(int rw, unsigned int region, struct io_region *where,
                bio->bi_bdev = where->bdev;
                bio->bi_end_io = endio;
                bio->bi_private = io;
+               bio->bi_destructor = dm_bio_destructor;
                bio_set_region(bio, region);
 
                /*
index d487d9deb98e1c04ddb4bc152e2a47d880c3332d..930b9fc27953766e94b2ce8869f6228feb5f04b3 100644 (file)
@@ -399,6 +399,11 @@ struct clone_info {
        unsigned short idx;
 };
 
+static void dm_bio_destructor(struct bio *bio)
+{
+       bio_free(bio, dm_set);
+}
+
 /*
  * Creates a little bio that is just does part of a bvec.
  */
@@ -410,6 +415,7 @@ static struct bio *split_bvec(struct bio *bio, sector_t sector,
        struct bio_vec *bv = bio->bi_io_vec + idx;
 
        clone = bio_alloc_bioset(GFP_NOIO, 1, dm_set);
+       clone->bi_destructor = dm_bio_destructor;
        *clone->bi_io_vec = *bv;
 
        clone->bi_sector = sector;
index 781f23f0cbcc597e79363d230cda2872908b06e3..6284894505c6f0595d8afb06e06087c1b8231cbe 100644 (file)
@@ -387,8 +387,6 @@ static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, in
 
 /* exported algorithm data */
 static struct i2c_algorithm saa7146_algo = {
-       .name           = "saa7146 i2c algorithm",
-       .id             = I2C_ALGO_SAA7146,
        .master_xfer    = saa7146_i2c_xfer,
        .functionality  = saa7146_i2c_func,
 };
@@ -412,7 +410,7 @@ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c
 #endif
                i2c_adapter->algo          = &saa7146_algo;
                i2c_adapter->algo_data     = NULL;
-               i2c_adapter->id            = I2C_ALGO_SAA7146;
+               i2c_adapter->id            = I2C_HW_SAA7146;
                i2c_adapter->timeout = SAA7146_I2C_TIMEOUT;
                i2c_adapter->retries = SAA7146_I2C_RETRIES;
        }
index be4266d4ae9114da7d1a56e74f97453ee9e14065..56495cb6cd02d39a3ded4a581e3d732231c4c320 100644 (file)
@@ -172,8 +172,6 @@ static u32 flexcop_i2c_func(struct i2c_adapter *adapter)
 }
 
 static struct i2c_algorithm flexcop_algo = {
-       .name                   = "FlexCop I2C algorithm",
-       .id                             = I2C_ALGO_BIT,
        .master_xfer    = flexcop_master_xfer,
        .functionality  = flexcop_i2c_func,
 };
@@ -192,7 +190,6 @@ int flexcop_i2c_init(struct flexcop_device *fc)
        fc->i2c_adap.class          = I2C_CLASS_TV_DIGITAL;
        fc->i2c_adap.algo       = &flexcop_algo;
        fc->i2c_adap.algo_data  = NULL;
-       fc->i2c_adap.id         = I2C_ALGO_BIT;
 
        if ((ret = i2c_add_adapter(&fc->i2c_adap)) < 0)
                return ret;
index b12545f093f8aacd54e4aac476a0b504aaddda38..1e85d16491b02acb426d9f6a48f5439fc38c603c 100644 (file)
@@ -1,5 +1,5 @@
 config DVB_BT8XX
-       tristate "Nebula/Pinnacle PCTV/Twinhan PCI cards"
+       tristate "BT8xx based PCI cards"
        depends on DVB_CORE && PCI && VIDEO_BT848
        select DVB_MT352
        select DVB_SP887X
@@ -8,8 +8,8 @@ config DVB_BT8XX
        select DVB_OR51211
        help
          Support for PCI cards based on the Bt8xx PCI bridge. Examples are
-         the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards and
-         pcHDTV HD2000 cards.
+         the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
+         the pcHDTV HD2000 cards, and certain AVerMedia cards.
 
          Since these cards have no MPEG decoder onboard, they transmit
          only compressed MPEG data over the PCI bus, so you need
index 7d8b3cad350bea238b84d4029cf209d894c116f5..9ea5747b121101759808370f15f68d6e2280312e 100644 (file)
@@ -888,7 +888,7 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
        if (down_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
-       if (state > 0) {        /* state 0 seems to mean DEVICE_PM_ON */
+       if (state.event > PM_EVENT_ON) {
                struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
 #ifdef ENABLE_RC
                cancel_delayed_work(&cinergyt2->rc_query_work);
index c3e1b661aae632b74c74c207e67a0f1c1483605b..9e96a188f1e9a7b0996c44d64eb6d90aa10cdc54 100644 (file)
@@ -141,8 +141,6 @@ static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
 }
 
 static struct i2c_algorithm cxusb_i2c_algo = {
-       .name          = "Conexant USB I2C algorithm",
-       .id            = I2C_ALGO_BIT,
        .master_xfer   = cxusb_i2c_xfer,
        .functionality = cxusb_i2c_func,
 };
index 9b9d6f8ee74eb768d919297c82a9818cbeac8987..00b946419b408fb1128bd52088f2d5fd034f4811 100644 (file)
@@ -156,8 +156,6 @@ static u32 dibusb_i2c_func(struct i2c_adapter *adapter)
 }
 
 struct i2c_algorithm dibusb_i2c_algo = {
-       .name          = "DiBcom USB I2C algorithm",
-       .id            = I2C_ALGO_BIT,
        .master_xfer   = dibusb_i2c_xfer,
        .functionality = dibusb_i2c_func,
 };
index 9a676afc1d6e89c4943db39b1e3a93202adbf033..f70e0be0920aee35ef9b1cdc075a4331fc3e7511 100644 (file)
@@ -77,8 +77,6 @@ static u32 digitv_i2c_func(struct i2c_adapter *adapter)
 }
 
 static struct i2c_algorithm digitv_i2c_algo = {
-       .name          = "Nebula DigiTV USB I2C algorithm",
-       .id            = I2C_ALGO_BIT,
        .master_xfer   = digitv_i2c_xfer,
        .functionality = digitv_i2c_func,
 };
index 9f0a8d90d1463885c106b9f8191f012f13f25824..da970947dfc72e5a77df1a4fa4a552c8ad16b038 100644 (file)
@@ -27,7 +27,6 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d)
 #endif
        d->i2c_adap.algo      = d->props.i2c_algo;
        d->i2c_adap.algo_data = NULL;
-       d->i2c_adap.id        = I2C_ALGO_BIT;
 
        i2c_set_adapdata(&d->i2c_adap, d);
 
index 1f1cd7a8d500846c07e8fd4fa49c0d8335cd7443..7142b9c51dd2460e3b2c65ec91bddf08d877f8b0 100644 (file)
@@ -69,8 +69,8 @@ struct lgdt330x_state
 };
 
 static int i2c_write_demod_bytes (struct lgdt330x_state* state,
-                          u8 *buf, /* data bytes to send */
-                          int len  /* number of bytes to send */ )
+                                 u8 *buf, /* data bytes to send */
+                                 int len  /* number of bytes to send */ )
 {
        struct i2c_msg msg =
                { .addr = state->config->demod_address,
@@ -129,13 +129,13 @@ static int lgdt3302_SwReset(struct lgdt330x_state* state)
        };
 
        ret = i2c_write_demod_bytes(state,
-                            reset, sizeof(reset));
+                                   reset, sizeof(reset));
        if (ret == 0) {
 
                /* force reset high (inactive) and unmask interrupts */
                reset[1] = 0x7f;
                ret = i2c_write_demod_bytes(state,
-                                    reset, sizeof(reset));
+                                           reset, sizeof(reset));
        }
        return ret;
 }
@@ -149,13 +149,13 @@ static int lgdt3303_SwReset(struct lgdt330x_state* state)
        };
 
        ret = i2c_write_demod_bytes(state,
-                            reset, sizeof(reset));
+                                   reset, sizeof(reset));
        if (ret == 0) {
 
                /* force reset high (inactive) */
                reset[1] = 0x01;
                ret = i2c_write_demod_bytes(state,
-                                    reset, sizeof(reset));
+                                           reset, sizeof(reset));
        }
        return ret;
 }
@@ -172,7 +172,6 @@ static int lgdt330x_SwReset(struct lgdt330x_state* state)
        }
 }
 
-
 static int lgdt330x_init(struct dvb_frontend* fe)
 {
        /* Hardware reset is done using gpio[0] of cx23880x chip.
@@ -229,13 +228,13 @@ static int lgdt330x_init(struct dvb_frontend* fe)
        case LGDT3302:
                chip_name = "LGDT3302";
                err = i2c_write_demod_bytes(state, lgdt3302_init_data,
-                                                                       sizeof(lgdt3302_init_data));
-               break;
+                                           sizeof(lgdt3302_init_data));
+               break;
        case LGDT3303:
                chip_name = "LGDT3303";
                err = i2c_write_demod_bytes(state, lgdt3303_init_data,
-                                                                       sizeof(lgdt3303_init_data));
-               break;
+                                           sizeof(lgdt3303_init_data));
+               break;
        default:
                chip_name = "undefined";
                printk (KERN_WARNING "Only LGDT3302 and LGDT3303 are supported chips.\n");
@@ -262,15 +261,15 @@ static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
        switch (state->config->demod_chip) {
        case LGDT3302:
                err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1,
-                                                                 buf, sizeof(buf));
-               break;
+                                          buf, sizeof(buf));
+               break;
        case LGDT3303:
                err = i2c_read_demod_bytes(state, LGDT3303_PACKET_ERR_COUNTER1,
-                                                                 buf, sizeof(buf));
-               break;
+                                          buf, sizeof(buf));
+               break;
        default:
                printk(KERN_WARNING
-                          "Only LGDT3302 and LGDT3303 are supported chips.\n");
+                      "Only LGDT3302 and LGDT3303 are supported chips.\n");
                err = -ENODEV;
        }
 
@@ -330,7 +329,7 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
 
                        if (state->config->demod_chip == LGDT3303) {
                                err = i2c_write_demod_bytes(state, lgdt3303_8vsb_44_data,
-                                                                                       sizeof(lgdt3303_8vsb_44_data));
+                                                           sizeof(lgdt3303_8vsb_44_data));
                        }
                        break;
 
@@ -378,18 +377,19 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
 
                /* Select the requested mode */
                i2c_write_demod_bytes(state, top_ctrl_cfg,
-                                                         sizeof(top_ctrl_cfg));
-               state->config->set_ts_params(fe, 0);
+                                     sizeof(top_ctrl_cfg));
+               if (state->config->set_ts_params)
+                       state->config->set_ts_params(fe, 0);
                state->current_modulation = param->u.vsb.modulation;
        }
 
-       /* Change only if we are actually changing the channel */
-       if (state->current_frequency != param->frequency) {
-               /* Tune to the new frequency */
+       /* Tune to the specified frequency */
+       if (state->config->pll_set)
                state->config->pll_set(fe, param);
-               /* Keep track of the new frequency */
-               state->current_frequency = param->frequency;
-       }
+
+       /* Keep track of the new frequency */
+       state->current_frequency = param->frequency;
+
        lgdt330x_SwReset(state);
        return 0;
 }
index 88e125079ca15579acf8eea92cf06d480e79d003..d1cabb6a0a139247ff0dc0f0190707edd8446b69 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <asm/irq.h>
 #include <asm/div64.h>
 
 #include "dvb_frontend.h"
index 706e0bcb5ede3dd750f8387cc9ccd156834cdcf4..85b437bbddcdaed624b6a1389dafd982b5560c07 100644 (file)
@@ -633,7 +633,6 @@ static int __devinit pluto2_probe(struct pci_dev *pdev,
        i2c_set_adapdata(&pluto->i2c_adap, pluto);
        strcpy(pluto->i2c_adap.name, DRIVER_NAME);
        pluto->i2c_adap.owner = THIS_MODULE;
-       pluto->i2c_adap.id = I2C_ALGO_BIT;
        pluto->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
        pluto->i2c_adap.dev.parent = &pdev->dev;
        pluto->i2c_adap.algo_data = &pluto->i2c_bit;
index bf3c011d2cfb3cbc77852c36712d665fe5e25e6f..d8bf65877897bd6a0e1650c19e825584ead7ea9c 100644 (file)
@@ -102,6 +102,9 @@ config DVB_BUDGET_AV
        select VIDEO_DEV
        select VIDEO_SAA7146_VV
        select DVB_STV0299
+       select DVB_TDA1004X
+       select DVB_TDA10021
+       select FW_LOADER
        help
          Support for simple SAA7146 based DVB cards
          (so called Budget- or Nova-PCI cards) without onboard
index aa43b5fcb8e7b352999ef911f93d7fc4f9955155..7daf7b1598a0d4dfb96c37daf6b406044d03bf8c 100644 (file)
@@ -1472,8 +1472,6 @@ static void frontend_init(struct ttusb* ttusb)
 
 
 static struct i2c_algorithm ttusb_dec_algo = {
-       .name           = "ttusb dec i2c algorithm",
-       .id             = I2C_ALGO_BIT,
        .master_xfer    = master_xfer,
        .functionality  = functionality,
 };
@@ -1525,7 +1523,6 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
 #endif
        ttusb->i2c_adap.algo              = &ttusb_dec_algo;
        ttusb->i2c_adap.algo_data         = NULL;
-       ttusb->i2c_adap.id                = I2C_ALGO_BIT;
 
        result = i2c_add_adapter(&ttusb->i2c_adap);
        if (result) {
index 3f5742396096dd61cbc49648c63d763bb530b84e..16c85c081e6ebe1533462a08084d0427a93f90bb 100644 (file)
@@ -254,6 +254,7 @@ config VIDEO_SAA7134_DVB
        select VIDEO_BUF_DVB
        select DVB_MT352
        select DVB_CX22702
+       select DVB_TDA1004X
        ---help---
          This adds support for DVB cards based on the
          Philips saa7134 chip.
index 810e7aac0a535edeed845e2c435d3d8f5cbb9d8f..3e6f5347da21ef90f97e99a0c651d28fc1edf070 100644 (file)
@@ -29,7 +29,7 @@ obj-$(CONFIG_VIDEO_ZORAN_LML33R10) += saa7114.o adv7170.o zr36060.o
 obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o
 obj-$(CONFIG_VIDEO_PMS) += pms.o
 obj-$(CONFIG_VIDEO_PLANB) += planb.o
-obj-$(CONFIG_VIDEO_VINO) += vino.o
+obj-$(CONFIG_VIDEO_VINO) += vino.o saa7191.o indycam.o
 obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
 obj-$(CONFIG_VIDEO_CPIA) += cpia.o
 obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
index 48989eda2400a120e5fea0a7e74bc500309d10e5..1ca2b67aedfb653c66fc9b35467356d87604274f 100644 (file)
@@ -43,7 +43,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 
 #include <linux/videodev.h>
@@ -391,7 +390,6 @@ static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
        .probe                  = &ignore,
        .ignore                 = &ignore,
-       .force                  = &ignore,
 };
 
 static struct i2c_driver i2c_driver_adv7170;
index f898b65863741162d6269cf062d625e51660d3be..173bca1e02950cdd29d340e56474f1da30389fbb 100644 (file)
@@ -39,7 +39,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 
 #include <linux/videodev.h>
@@ -441,7 +440,6 @@ static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
        .probe                  = &ignore,
        .ignore                 = &ignore,
-       .force                  = &ignore,
 };
 
 static struct i2c_driver i2c_driver_adv7175;
index 8733588f6db3db1905628cc1ba99a4c62c51ec9e..3ee0afca76a7f1b206a39688648aacbd68e4ae5e 100644 (file)
@@ -43,7 +43,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 
 #include <linux/videodev.h>
@@ -507,7 +506,6 @@ static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
        .probe                  = &ignore,
        .ignore                 = &ignore,
-       .force                  = &ignore,
 };
 
 static struct i2c_driver i2c_driver_bt819;
index a070417e65e6c9ce5a4219c00cf944a35c0fb6a2..76c1b63ebdf27b4eb78c47cdd8a4d74065ca62dc 100644 (file)
@@ -188,7 +188,7 @@ static int bt832_probe(struct i2c_adapter *adap)
        if (adap->class & I2C_CLASS_TV_ANALOG)
                return i2c_probe(adap, &addr_data, bt832_attach);
 #else
-       if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+       if (adap->id == I2C_HW_B_BT848)
                return i2c_probe(adap, &addr_data, bt832_attach);
 #endif
        return 0;
@@ -241,7 +241,7 @@ static struct i2c_driver driver = {
 };
 static struct i2c_client client_template =
 {
-       I2C_DEVNAME("bt832"),
+       .name       = "bt832",
        .flags      = I2C_CLIENT_ALLOW_USE,
         .driver     = &driver,
 };
index a5d529ccf3ad174fb1aead3cac87e48f03dcebd2..8eb871d0e85b61cdf1d139d73116bcbd32ff88f8 100644 (file)
@@ -43,7 +43,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 
 #include <linux/videodev.h>
@@ -295,7 +294,6 @@ static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
        .probe                  = &ignore,
        .ignore                 = &ignore,
-       .force                  = &ignore,
 };
 
 static struct i2c_driver i2c_driver_bt856;
index eee9322ce21b06efb02a6bf51e2b662231983189..087efb4dea09a4b67a36e21a7a46c28f76c8831a 100644 (file)
@@ -4047,7 +4047,6 @@ static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
        struct bttv_buffer_set idle;
        unsigned long flags;
 
-       dprintk("bttv%d: suspend %d\n", btv->c.nr, state);
 
        /* stop dma + irqs */
        spin_lock_irqsave(&btv->s_lock,flags);
index 234a85563769164e69987082961728d45a20af1b..706dc48df9625e1741bc9c9029db86b897fe500a 100644 (file)
@@ -109,7 +109,7 @@ static struct i2c_adapter bttv_i2c_adap_sw_template = {
 #ifdef I2C_CLASS_TV_ANALOG
        .class             = I2C_CLASS_TV_ANALOG,
 #endif
-       I2C_DEVNAME("bt848"),
+       .name              = "bt848",
        .id                = I2C_HW_B_BT848,
        .client_register   = attach_inform,
 };
@@ -270,8 +270,6 @@ static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int
 }
 
 static struct i2c_algorithm bttv_algo = {
-       .name          = "bt878",
-       .id            = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */,
        .master_xfer   = bttv_i2c_xfer,
        .algo_control  = algo_control,
        .functionality = functionality,
@@ -282,8 +280,8 @@ static struct i2c_adapter bttv_i2c_adap_hw_template = {
 #ifdef I2C_CLASS_TV_ANALOG
        .class         = I2C_CLASS_TV_ANALOG,
 #endif
-       I2C_DEVNAME("bt878"),
-       .id            = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */,
+       .name          = "bt878",
+       .id            = I2C_HW_B_BT848 /* FIXME */,
        .algo          = &bttv_algo,
        .client_register = attach_inform,
 };
@@ -298,7 +296,7 @@ static int attach_inform(struct i2c_client *client)
        if (bttv_debug)
                printk(KERN_DEBUG "bttv%d: %s i2c attach [addr=0x%x,client=%s]\n",
                        btv->c.nr,client->driver->name,client->addr,
-                       i2c_clientname(client));
+                       client->name);
        if (!client->driver->command)
                return 0;
 
@@ -326,7 +324,7 @@ void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
 }
 
 static struct i2c_client bttv_i2c_client_template = {
-       I2C_DEVNAME("bttv internal"),
+       .name   = "bttv internal",
 };
 
 
index a628a55299c670cb87f1554f6e566f3fff69a664..7f598039e0257602bf8016c9e097b982e2c257e3 100644 (file)
@@ -95,7 +95,7 @@ static int attach_inform(struct i2c_client *client)
        struct cx88_core *core = i2c_get_adapdata(client->adapter);
 
        dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
-               client->driver->name,client->addr,i2c_clientname(client));
+               client->driver->name, client->addr, client->name);
        if (!client->driver->command)
                return 0;
 
@@ -128,7 +128,7 @@ static int detach_inform(struct i2c_client *client)
 {
        struct cx88_core *core = i2c_get_adapdata(client->adapter);
 
-       dprintk(1, "i2c detach [client=%s]\n", i2c_clientname(client));
+       dprintk(1, "i2c detach [client=%s]\n", client->name);
        return 0;
 }
 
@@ -152,7 +152,7 @@ static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
 /* ----------------------------------------------------------------------- */
 
 static struct i2c_adapter cx8800_i2c_adap_template = {
-       I2C_DEVNAME("cx2388x"),
+       .name              = "cx2388x",
        .owner             = THIS_MODULE,
        .id                = I2C_HW_B_CX2388x,
        .client_register   = attach_inform,
@@ -160,7 +160,7 @@ static struct i2c_adapter cx8800_i2c_adap_template = {
 };
 
 static struct i2c_client cx8800_i2c_client_template = {
-        I2C_DEVNAME("cx88xx internal"),
+        .name  = "cx88xx internal",
 };
 
 static char *i2c_devs[128] = {
diff --git a/drivers/media/video/indycam.c b/drivers/media/video/indycam.c
new file mode 100644 (file)
index 0000000..b2b0384
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ *  indycam.c - Silicon Graphics IndyCam digital camera driver
+ *
+ *  Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ *  Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ *  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/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <linux/videodev.h>
+/* IndyCam decodes stream of photons into digital image representation ;-) */
+#include <linux/video_decoder.h>
+#include <linux/i2c.h>
+
+#include "indycam.h"
+
+//#define INDYCAM_DEBUG
+
+#define INDYCAM_MODULE_VERSION "0.0.3"
+
+MODULE_DESCRIPTION("SGI IndyCam driver");
+MODULE_VERSION(INDYCAM_MODULE_VERSION);
+MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
+MODULE_LICENSE("GPL");
+
+#ifdef INDYCAM_DEBUG
+#define dprintk(x...) printk("IndyCam: " x);
+#define indycam_regdump(client) indycam_regdump_debug(client)
+#else
+#define dprintk(x...)
+#define indycam_regdump(client)
+#endif
+
+#define VINO_ADAPTER   (I2C_ALGO_SGI | I2C_HW_SGI_VINO)
+
+struct indycam {
+       struct i2c_client *client;
+       int version;
+};
+
+static struct i2c_driver i2c_driver_indycam;
+
+static const unsigned char initseq[] = {
+       INDYCAM_CONTROL_AGCENA,         /* INDYCAM_CONTROL */
+       INDYCAM_SHUTTER_DEFAULT,        /* INDYCAM_SHUTTER */
+       INDYCAM_GAIN_DEFAULT,           /* INDYCAM_GAIN */
+       0x00,                           /* INDYCAM_BRIGHTNESS (read-only) */
+       INDYCAM_RED_BALANCE_DEFAULT,    /* INDYCAM_RED_BALANCE */
+       INDYCAM_BLUE_BALANCE_DEFAULT,   /* INDYCAM_BLUE_BALANCE */
+       INDYCAM_RED_SATURATION_DEFAULT, /* INDYCAM_RED_SATURATION */
+       INDYCAM_BLUE_SATURATION_DEFAULT,/* INDYCAM_BLUE_SATURATION */
+};
+
+/* IndyCam register handling */
+
+static int indycam_read_reg(struct i2c_client *client, unsigned char reg,
+                            unsigned char *value)
+{
+       int ret;
+
+       if (reg == INDYCAM_RESET) {
+               dprintk("indycam_read_reg(): "
+                       "skipping write-only register %d\n", reg);
+               *value = 0;
+               return 0;
+       }
+
+       ret = i2c_smbus_read_byte_data(client, reg);
+       if (ret < 0) {
+               printk(KERN_ERR "IndyCam: indycam_read_reg(): read failed, "
+                      "register = 0x%02x\n", reg);
+               return ret;
+       }
+
+       *value = (unsigned char)ret;
+
+       return 0;
+}
+
+static int indycam_write_reg(struct i2c_client *client, unsigned char reg,
+                            unsigned char value)
+{
+       int err;
+
+       if ((reg == INDYCAM_BRIGHTNESS)
+           || (reg == INDYCAM_VERSION)) {
+               dprintk("indycam_write_reg(): "
+                       "skipping read-only register %d\n", reg);
+               return 0;
+       }
+
+       dprintk("Writing Reg %d = 0x%02x\n", reg, value);
+       err = i2c_smbus_write_byte_data(client, reg, value);
+       if (err) {
+               printk(KERN_ERR "IndyCam: indycam_write_reg(): write failed, "
+                      "register = 0x%02x, value = 0x%02x\n", reg, value);
+       }
+       return err;
+}
+
+static int indycam_write_block(struct i2c_client *client, unsigned char reg,
+                               unsigned char length, unsigned char *data)
+{
+       unsigned char i;
+       int err;
+
+       for (i = reg; i < length; i++) {
+               err = indycam_write_reg(client, reg + i, data[i]);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+/* Helper functions */
+
+#ifdef INDYCAM_DEBUG
+static void indycam_regdump_debug(struct i2c_client *client)
+{
+       int i;
+       unsigned char val;
+
+       for (i = 0; i < 9; i++) {
+               indycam_read_reg(client, i, &val);
+               dprintk("Reg %d = 0x%02x\n", i, val);
+       }
+}
+#endif
+
+static int indycam_get_controls(struct i2c_client *client,
+                               struct indycam_control *ctrl)
+{
+       unsigned char ctrl_reg;
+
+       indycam_read_reg(client, INDYCAM_CONTROL, &ctrl_reg);
+       ctrl->agc = (ctrl_reg & INDYCAM_CONTROL_AGCENA)
+               ? INDYCAM_VALUE_ENABLED
+               : INDYCAM_VALUE_DISABLED;
+       ctrl->awb = (ctrl_reg & INDYCAM_CONTROL_AWBCTL)
+               ? INDYCAM_VALUE_ENABLED
+               : INDYCAM_VALUE_DISABLED;
+       indycam_read_reg(client, INDYCAM_SHUTTER,
+                        (unsigned char *)&ctrl->shutter);
+       indycam_read_reg(client, INDYCAM_GAIN,
+                        (unsigned char *)&ctrl->gain);
+       indycam_read_reg(client, INDYCAM_RED_BALANCE,
+                        (unsigned char *)&ctrl->red_balance);
+       indycam_read_reg(client, INDYCAM_BLUE_BALANCE,
+                        (unsigned char *)&ctrl->blue_balance);
+       indycam_read_reg(client, INDYCAM_RED_SATURATION,
+                        (unsigned char *)&ctrl->red_saturation);
+       indycam_read_reg(client, INDYCAM_BLUE_SATURATION,
+                        (unsigned char *)&ctrl->blue_saturation);
+       indycam_read_reg(client, INDYCAM_GAMMA,
+                        (unsigned char *)&ctrl->gamma);
+
+       return 0;
+}
+
+static int indycam_set_controls(struct i2c_client *client,
+                               struct indycam_control *ctrl)
+{
+       unsigned char ctrl_reg;
+
+       indycam_read_reg(client, INDYCAM_CONTROL, &ctrl_reg);
+       if (ctrl->agc != INDYCAM_VALUE_UNCHANGED) {
+               if (ctrl->agc)
+                       ctrl_reg |= INDYCAM_CONTROL_AGCENA;
+               else
+                       ctrl_reg &= ~INDYCAM_CONTROL_AGCENA;
+       }
+       if (ctrl->awb != INDYCAM_VALUE_UNCHANGED) {
+               if (ctrl->awb)
+                       ctrl_reg |= INDYCAM_CONTROL_AWBCTL;
+               else
+                       ctrl_reg &= ~INDYCAM_CONTROL_AWBCTL;
+       }
+       indycam_write_reg(client, INDYCAM_CONTROL, ctrl_reg);
+
+       if (ctrl->shutter >= 0)
+               indycam_write_reg(client, INDYCAM_SHUTTER, ctrl->shutter);
+       if (ctrl->gain >= 0)
+               indycam_write_reg(client, INDYCAM_GAIN, ctrl->gain);
+       if (ctrl->red_balance >= 0)
+               indycam_write_reg(client, INDYCAM_RED_BALANCE,
+                                 ctrl->red_balance);
+       if (ctrl->blue_balance >= 0)
+               indycam_write_reg(client, INDYCAM_BLUE_BALANCE,
+                                 ctrl->blue_balance);
+       if (ctrl->red_saturation >= 0)
+               indycam_write_reg(client, INDYCAM_RED_SATURATION,
+                                 ctrl->red_saturation);
+       if (ctrl->blue_saturation >= 0)
+               indycam_write_reg(client, INDYCAM_BLUE_SATURATION,
+                                 ctrl->blue_saturation);
+       if (ctrl->gamma >= 0)
+               indycam_write_reg(client, INDYCAM_GAMMA, ctrl->gamma);
+
+       return 0;
+}
+
+/* I2C-interface */
+
+static int indycam_attach(struct i2c_adapter *adap, int addr, int kind)
+{
+       int err = 0;
+       struct indycam *camera;
+       struct i2c_client *client;
+
+       printk(KERN_INFO "SGI IndyCam driver version %s\n",
+              INDYCAM_MODULE_VERSION);
+
+       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (!client)
+               return -ENOMEM;
+       camera = kmalloc(sizeof(struct indycam), GFP_KERNEL);
+       if (!camera) {
+               err = -ENOMEM;
+               goto out_free_client;
+       }
+
+       memset(client, 0, sizeof(struct i2c_client));
+       memset(camera, 0, sizeof(struct indycam));
+
+       client->addr = addr;
+       client->adapter = adap;
+       client->driver = &i2c_driver_indycam;
+       client->flags = 0;
+       strcpy(client->name, "IndyCam client");
+       i2c_set_clientdata(client, camera);
+
+       camera->client = client;
+
+       err = i2c_attach_client(client);
+       if (err)
+               goto out_free_camera;
+
+       camera->version = i2c_smbus_read_byte_data(client, INDYCAM_VERSION);
+       if (camera->version != CAMERA_VERSION_INDY &&
+           camera->version != CAMERA_VERSION_MOOSE) {
+               err = -ENODEV;
+               goto out_detach_client;
+       }
+       printk(KERN_INFO "IndyCam v%d.%d detected\n",
+              INDYCAM_VERSION_MAJOR(camera->version),
+              INDYCAM_VERSION_MINOR(camera->version));
+
+       indycam_regdump(client);
+
+       // initialize
+       err = indycam_write_block(client, 0, sizeof(initseq),
+                                 (unsigned char *)&initseq);
+       if (err) {
+               printk(KERN_ERR "IndyCam initalization failed\n");
+               err = -EIO;
+               goto out_detach_client;
+       }
+
+       indycam_regdump(client);
+
+       // white balance
+       err = indycam_write_reg(client, INDYCAM_CONTROL,
+                         INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL);
+       if (err) {
+               printk(KERN_ERR "IndyCam white balance "
+                      "initialization failed\n");
+               err = -EIO;
+               goto out_detach_client;
+       }
+
+       indycam_regdump(client);
+
+       printk(KERN_INFO "IndyCam initialized\n");
+
+       return 0;
+
+out_detach_client:
+       i2c_detach_client(client);
+out_free_camera:
+       kfree(camera);
+out_free_client:
+       kfree(client);
+       return err;
+}
+
+static int indycam_probe(struct i2c_adapter *adap)
+{
+       /* Indy specific crap */
+       if (adap->id == VINO_ADAPTER)
+               return indycam_attach(adap, INDYCAM_ADDR, 0);
+       /* Feel free to add probe here :-) */
+       return -ENODEV;
+}
+
+static int indycam_detach(struct i2c_client *client)
+{
+       struct indycam *camera = i2c_get_clientdata(client);
+
+       i2c_detach_client(client);
+       kfree(camera);
+       kfree(client);
+       return 0;
+}
+
+static int indycam_command(struct i2c_client *client, unsigned int cmd,
+                          void *arg)
+{
+       // struct indycam *camera = i2c_get_clientdata(client);
+
+       /* The old video_decoder interface just isn't enough,
+        * so we'll use some custom commands. */
+       switch (cmd) {
+       case DECODER_GET_CAPABILITIES: {
+               struct video_decoder_capability *cap = arg;
+
+               cap->flags  = VIDEO_DECODER_NTSC;
+               cap->inputs = 1;
+               cap->outputs = 1;
+               break;
+       }
+       case DECODER_GET_STATUS: {
+               int *iarg = arg;
+
+               *iarg = DECODER_STATUS_GOOD | DECODER_STATUS_NTSC |
+                       DECODER_STATUS_COLOR;
+               break;
+       }
+       case DECODER_SET_NORM: {
+               int *iarg = arg;
+
+               switch (*iarg) {
+               case VIDEO_MODE_NTSC:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       }
+       case DECODER_SET_INPUT: {
+               int *iarg = arg;
+
+               if (*iarg != 0)
+                       return -EINVAL;
+               break;
+       }
+       case DECODER_SET_OUTPUT: {
+               int *iarg = arg;
+
+               if (*iarg != 0)
+                       return -EINVAL;
+               break;
+       }
+       case DECODER_ENABLE_OUTPUT: {
+               /* Always enabled */
+               break;
+       }
+       case DECODER_SET_PICTURE: {
+               // struct video_picture *pic = arg;
+               /* TODO: convert values for indycam_set_controls() */
+               break;
+       }
+       case DECODER_INDYCAM_GET_CONTROLS: {
+               struct indycam_control *ctrl = arg;
+               indycam_get_controls(client, ctrl);
+       }
+       case DECODER_INDYCAM_SET_CONTROLS: {
+               struct indycam_control *ctrl = arg;
+               indycam_set_controls(client, ctrl);
+       }
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct i2c_driver i2c_driver_indycam = {
+       .owner          = THIS_MODULE,
+       .name           = "indycam",
+       .id             = I2C_DRIVERID_INDYCAM,
+       .flags          = I2C_DF_NOTIFY,
+       .attach_adapter = indycam_probe,
+       .detach_client  = indycam_detach,
+       .command        = indycam_command,
+};
+
+static int __init indycam_init(void)
+{
+       return i2c_add_driver(&i2c_driver_indycam);
+}
+
+static void __exit indycam_exit(void)
+{
+       i2c_del_driver(&i2c_driver_indycam);
+}
+
+module_init(indycam_init);
+module_exit(indycam_exit);
diff --git a/drivers/media/video/indycam.h b/drivers/media/video/indycam.h
new file mode 100644 (file)
index 0000000..d9ddb6b
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ *  indycam.h - Silicon Graphics IndyCam digital camera driver
+ *
+ *  Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ *  Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ *  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 _INDYCAM_H_
+#define _INDYCAM_H_
+
+/* I2C address for the Guinness Camera */
+#define INDYCAM_ADDR                   0x56
+
+/* Camera version */
+#define CAMERA_VERSION_INDY            0x10    /* v1.0 */
+#define CAMERA_VERSION_MOOSE           0x12    /* v1.2 */
+#define INDYCAM_VERSION_MAJOR(x)       (((x) & 0xf0) >> 4)
+#define INDYCAM_VERSION_MINOR(x)       ((x) & 0x0f)
+
+/* Register bus addresses */
+#define INDYCAM_CONTROL                        0x00
+#define INDYCAM_SHUTTER                        0x01
+#define INDYCAM_GAIN                   0x02
+#define INDYCAM_BRIGHTNESS             0x03 /* read-only */
+#define INDYCAM_RED_BALANCE            0x04
+#define INDYCAM_BLUE_BALANCE           0x05
+#define INDYCAM_RED_SATURATION         0x06
+#define INDYCAM_BLUE_SATURATION                0x07
+#define INDYCAM_GAMMA                  0x08
+#define INDYCAM_VERSION                        0x0e /* read-only */
+#define INDYCAM_RESET                  0x0f /* write-only */
+
+#define INDYCAM_LED                    0x46
+#define INDYCAM_ORIENTATION            0x47
+#define INDYCAM_BUTTON                 0x48
+
+/* Field definitions of registers */
+#define INDYCAM_CONTROL_AGCENA         (1<<0) /* automatic gain control */
+#define INDYCAM_CONTROL_AWBCTL         (1<<1) /* automatic white balance */
+                                               /* 2-3 are reserved */
+#define INDYCAM_CONTROL_EVNFLD         (1<<4)  /* read-only */
+
+#define INDYCAM_SHUTTER_10000          0x02    /* 1/10000 second */
+#define INDYCAM_SHUTTER_4000           0x04    /* 1/4000 second */
+#define INDYCAM_SHUTTER_2000           0x08    /* 1/2000 second */
+#define INDYCAM_SHUTTER_1000           0x10    /* 1/1000 second */
+#define INDYCAM_SHUTTER_500            0x20    /* 1/500 second */
+#define INDYCAM_SHUTTER_250            0x3f    /* 1/250 second */
+#define INDYCAM_SHUTTER_125            0x7e    /* 1/125 second */
+#define INDYCAM_SHUTTER_100            0x9e    /* 1/100 second */
+#define INDYCAM_SHUTTER_60             0x00    /* 1/60 second */
+
+#define INDYCAM_LED_ACTIVE                     0x10
+#define INDYCAM_LED_INACTIVE                   0x30
+#define INDYCAM_ORIENTATION_BOTTOM_TO_TOP      0x40
+#define INDYCAM_BUTTON_RELEASED                        0x10
+
+#define INDYCAM_SHUTTER_MIN            0x00
+#define INDYCAM_SHUTTER_MAX            0xff
+#define INDYCAM_GAIN_MIN                0x00
+#define INDYCAM_GAIN_MAX                0xff
+#define INDYCAM_RED_BALANCE_MIN        0x00 /* the effect is the opposite? */
+#define INDYCAM_RED_BALANCE_MAX        0xff
+#define INDYCAM_BLUE_BALANCE_MIN        0x00 /* the effect is the opposite? */
+#define INDYCAM_BLUE_BALANCE_MAX        0xff
+#define INDYCAM_RED_SATURATION_MIN      0x00
+#define INDYCAM_RED_SATURATION_MAX      0xff
+#define INDYCAM_BLUE_SATURATION_MIN    0x00
+#define INDYCAM_BLUE_SATURATION_MAX    0xff
+#define INDYCAM_GAMMA_MIN              0x00
+#define INDYCAM_GAMMA_MAX              0xff
+
+/* Driver interface definitions */
+
+#define INDYCAM_VALUE_ENABLED          1
+#define INDYCAM_VALUE_DISABLED         0
+#define INDYCAM_VALUE_UNCHANGED                -1
+
+/* When setting controls, a value of -1 leaves the control unchanged. */
+struct indycam_control {
+       int agc;        /* boolean */
+       int awb;        /* boolean */
+       int shutter;
+       int gain;
+       int red_balance;
+       int blue_balance;
+       int red_saturation;
+       int blue_saturation;
+       int gamma;
+};
+
+#define        DECODER_INDYCAM_GET_CONTROLS    _IOR('d', 193, struct indycam_control)
+#define        DECODER_INDYCAM_SET_CONTROLS    _IOW('d', 194, struct indycam_control)
+
+/* Default values for controls */
+
+#define INDYCAM_AGC_DEFAULT            INDYCAM_VALUE_ENABLED
+#define INDYCAM_AWB_DEFAULT            INDYCAM_VALUE_ENABLED
+
+#define INDYCAM_SHUTTER_DEFAULT                INDYCAM_SHUTTER_60
+#define INDYCAM_GAIN_DEFAULT           0x80
+#define INDYCAM_RED_BALANCE_DEFAULT    0x18
+#define INDYCAM_BLUE_BALANCE_DEFAULT   0xa4
+#define INDYCAM_RED_SATURATION_DEFAULT 0x80
+#define INDYCAM_BLUE_SATURATION_DEFAULT        0xc0
+#define INDYCAM_GAMMA_DEFAULT          0x80
+
+#endif
index 9fc5055e001cd9f0f5aeaaee1a856ff093070edd..1e273ff3f956802b9b664a62e3c9505e1e8efc49 100644 (file)
@@ -308,7 +308,7 @@ static struct i2c_driver driver = {
 
 static struct i2c_client client_template =
 {
-        I2C_DEVNAME("unset"),
+        .name = "unset",
         .driver = &driver
 };
 
@@ -429,10 +429,10 @@ static int ir_probe(struct i2c_adapter *adap)
        struct i2c_client c; char buf; int i,rc;
 
        switch (adap->id) {
-       case I2C_ALGO_BIT | I2C_HW_B_BT848:
+       case I2C_HW_B_BT848:
                probe = probe_bttv;
                break;
-       case I2C_ALGO_SAA7134:
+       case I2C_HW_SAA7134:
                probe = probe_saa7134;
                break;
        }
index fe194012bccf65aac168a7bfc61b48fa621767c8..3f2a882bc20a6a6b31b00af7bef5278596f253db 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/vmalloc.h>
+#include <linux/dma-mapping.h>
 
 #include "meye.h"
 #include <linux/meye.h>
@@ -121,7 +122,7 @@ static int ptable_alloc(void)
        memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable));
 
        /* give only 32 bit DMA addresses */
-       if (dma_set_mask(&meye.mchip_dev->dev, 0xffffffff))
+       if (dma_set_mask(&meye.mchip_dev->dev, DMA_32BIT_MASK))
                return -1;
 
        meye.mchip_ptable_toc = dma_alloc_coherent(&meye.mchip_dev->dev,
index 62f1b8ddb98b8bc153602271c7d84337c6e67efe..ca02f6f14b000ece1f11eb12333da9b141dd2e90 100644 (file)
@@ -1416,7 +1416,7 @@ static int msp_detach(struct i2c_client *client);
 static int msp_probe(struct i2c_adapter *adap);
 static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg);
 
-static int msp_suspend(struct device * dev, u32 state, u32 level);
+static int msp_suspend(struct device * dev, pm_message_t state, u32 level);
 static int msp_resume(struct device * dev, u32 level);
 
 static void msp_wake_thread(struct i2c_client *client);
@@ -1437,7 +1437,7 @@ static struct i2c_driver driver = {
 
 static struct i2c_client client_template =
 {
-       I2C_DEVNAME("(unset)"),
+       .name      = "(unset)",
        .flags     = I2C_CLIENT_ALLOW_USE,
         .driver    = &driver,
 };
@@ -1509,7 +1509,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
        }
 
        /* hello world :-) */
-       printk(KERN_INFO "msp34xx: init: chip=%s",i2c_clientname(c));
+       printk(KERN_INFO "msp34xx: init: chip=%s", c->name);
        if (HAVE_NICAM(msp))
                printk(" +nicam");
        if (HAVE_SIMPLE(msp))
@@ -1817,7 +1817,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
        return 0;
 }
 
-static int msp_suspend(struct device * dev, u32 state, u32 level)
+static int msp_suspend(struct device * dev, pm_message_t state, u32 level)
 {
        struct i2c_client *c = container_of(dev, struct i2c_client, dev);
 
index 3433619ad93f91c501f34677dbd822b2336dfcb4..b3f4d266cedead6f1afd053ec0b4e2edd117b88e 100644 (file)
@@ -164,10 +164,10 @@ static int ov6x20_init(struct i2c_client *c)
        DDEBUG(4, &c->dev, "entered");
 
        switch (c->adapter->id) {
-       case I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV511:
+       case I2C_HW_SMBUS_OV511:
                rc = ov_write_regvals(c, regvals_init_6x20_511);
                break;
-       case I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518:
+       case I2C_HW_SMBUS_OV518:
                rc = ov_write_regvals(c, regvals_init_6x20_518);
                break;
        default:
@@ -338,7 +338,7 @@ static int ov6x20_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
        /******** Palette-specific regs ********/
 
        /* OV518 needs 8 bit multiplexed in color mode, and 16 bit in B&W */
-       if (c->adapter->id == (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518)) {
+       if (c->adapter->id == I2C_HW_SMBUS_OV518) {
                if (win->format == VIDEO_PALETTE_GREY)
                        ov_write_mask(c, 0x13, 0x00, 0x20);
                else
index 44a842379b457bce335279b447d348bce027886f..6eab458ab792a88e58313731f11ab27160fe1535 100644 (file)
@@ -301,7 +301,7 @@ static int ov6x30_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
        /******** Palette-specific regs ********/
 
        if (win->format == VIDEO_PALETTE_GREY) {
-               if (c->adapter->id == (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518)) {
+               if (c->adapter->id == I2C_HW_SMBUS_OV518) {
                        /* Do nothing - we're already in 8-bit mode */
                } else {
                        ov_write_mask(c, 0x13, 0x20, 0x20);
@@ -313,7 +313,7 @@ static int ov6x30_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
                 * Therefore, the OV6630 needs to be in 8-bit multiplexed
                 * output mode */
 
-               if (c->adapter->id == (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518)) {
+               if (c->adapter->id == I2C_HW_SMBUS_OV518) {
                        /* Do nothing - we want to stay in 8-bit mode */
                        /* Warning: Messing with reg 0x13 breaks OV518 color */
                } else {
index 54dd5612d3b823d2a4a761605078720cbdac51ba..2de34ebf0673db67f0785e15a845cf371c4ef4a6 100644 (file)
@@ -296,10 +296,10 @@ static int ovcamchip_attach(struct i2c_adapter *adap)
         * attach to adapters that are known to contain OV camera chips. */
 
        switch (adap->id) {
-       case (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV511):
-       case (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518):
-       case (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OVFX2):
-       case (I2C_ALGO_SMBUS | I2C_HW_SMBUS_W9968CF):
+       case I2C_HW_SMBUS_OV511:
+       case I2C_HW_SMBUS_OV518:
+       case I2C_HW_SMBUS_OVFX2:
+       case I2C_HW_SMBUS_W9968CF:
                PDEBUG(1, "Adapter ID 0x%06x accepted", adap->id);
                break;
        default:
@@ -314,7 +314,7 @@ static int ovcamchip_attach(struct i2c_adapter *adap)
        }
        memcpy(c, &client_template, sizeof *c);
        c->adapter = adap;
-       strcpy(i2c_clientname(c), "OV????");
+       strcpy(c->name, "OV????");
 
        ov = kmalloc(sizeof *ov, GFP_KERNEL);
        if (!ov) {
@@ -328,7 +328,7 @@ static int ovcamchip_attach(struct i2c_adapter *adap)
        if (rc < 0)
                goto error;
 
-       strcpy(i2c_clientname(c), chip_names[ov->subtype]);
+       strcpy(c->name, chip_names[ov->subtype]);
 
        PDEBUG(1, "Camera chip detection complete");
 
@@ -421,7 +421,7 @@ static struct i2c_driver driver = {
 };
 
 static struct i2c_client client_template = {
-       I2C_DEVNAME("(unset)"),
+       .name =         "(unset)",
        .driver =       &driver,
 };
 
index 22d055d8a695591d04b65107a6034488c462dcb5..e116bdbed310945a3cb51f0975bac25e6776c0c7 100644 (file)
@@ -470,7 +470,6 @@ static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
        .probe                  = &ignore,
        .ignore                 = &ignore,
-       .force                  = &ignore,
 };
 
 static struct i2c_driver i2c_driver_saa7110;
index fcd897382fcfc0fe5dc1271db95a6ae0079634ca..fe8a5e45396982ca0a1a62ee2ab6571ca4d7ba23 100644 (file)
@@ -42,7 +42,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 
 #include <linux/videodev.h>
@@ -489,7 +488,6 @@ static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
        .probe                  = &ignore,
        .ignore                 = &ignore,
-       .force                  = &ignore,
 };
 
 static struct i2c_driver i2c_driver_saa7111;
index 2ba997f5ef1d50c20a785eadc3a2bfba2f3779f8..d9f50e2f7b92f1c14997945c465ffdc13fad668c 100644 (file)
@@ -45,7 +45,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 
 #include <linux/videodev.h>
@@ -827,7 +826,6 @@ static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
        .probe                  = &ignore,
        .ignore                 = &ignore,
-       .force                  = &ignore,
 };
 
 static struct i2c_driver i2c_driver_saa7114;
index 79d05ea1b69b06535ddb3206ba6ed5a25e006c60..382911c6ef2243813b02fe7d8107ed5194f17b4c 100644 (file)
@@ -598,7 +598,7 @@ static struct i2c_driver driver = {
 
 static struct i2c_client client_template =
 {
-       I2C_DEVNAME("saa6752hs"),
+       .name       = "saa6752hs",
        .flags      = I2C_CLIENT_ALLOW_USE,
         .driver     = &driver,
 };
index 1203b93a572c4a80da2a872a80e5a9be7c0d58cd..eae6b529713fe6cb3ff77673878fbcaeda776aae 100644 (file)
@@ -334,7 +334,7 @@ static int attach_inform(struct i2c_client *client)
        struct tuner_setup tun_setup;
 
        d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
-               client->driver->name,client->addr,i2c_clientname(client));
+                client->driver->name, client->addr, client->name);
 
        if (!client->driver->command)
                return 0;
@@ -370,8 +370,6 @@ static int attach_inform(struct i2c_client *client)
 }
 
 static struct i2c_algorithm saa7134_algo = {
-       .name          = "saa7134",
-       .id            = I2C_ALGO_SAA7134,
        .master_xfer   = saa7134_i2c_xfer,
        .algo_control  = algo_control,
        .functionality = functionality,
@@ -382,14 +380,14 @@ static struct i2c_adapter saa7134_adap_template = {
 #ifdef I2C_CLASS_TV_ANALOG
        .class         = I2C_CLASS_TV_ANALOG,
 #endif
-       I2C_DEVNAME("saa7134"),
-       .id            = I2C_ALGO_SAA7134,
+       .name          = "saa7134",
+       .id            = I2C_HW_SAA7134,
        .algo          = &saa7134_algo,
        .client_register = attach_inform,
 };
 
 static struct i2c_client saa7134_client_template = {
-       I2C_DEVNAME("saa7134 internal"),
+       .name   = "saa7134 internal",
 };
 
 /* ----------------------------------------------------------- */
index 108e7a4a02734dbd9d1e803a0a40ab5ac2ad3691..132aa7943c1625a7385a15a9d69bbd37b3864a3e 100644 (file)
@@ -39,7 +39,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 
 #include <linux/videodev.h>
@@ -387,7 +386,6 @@ static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
        .probe                  = &ignore,
        .ignore                 = &ignore,
-       .force                  = &ignore,
 };
 
 static struct i2c_driver i2c_driver_saa7185;
diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c
new file mode 100644 (file)
index 0000000..454f5c1
--- /dev/null
@@ -0,0 +1,512 @@
+/*
+ *  saa7191.c - Philips SAA7191 video decoder driver
+ *
+ *  Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ *  Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ *  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/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <linux/videodev.h>
+#include <linux/video_decoder.h>
+#include <linux/i2c.h>
+
+#include "saa7191.h"
+
+#define SAA7191_MODULE_VERSION "0.0.3"
+
+MODULE_DESCRIPTION("Philips SAA7191 video decoder driver");
+MODULE_VERSION(SAA7191_MODULE_VERSION);
+MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
+MODULE_LICENSE("GPL");
+
+#define VINO_ADAPTER   (I2C_ALGO_SGI | I2C_HW_SGI_VINO)
+
+struct saa7191 {
+       struct i2c_client *client;
+
+       /* the register values are stored here as the actual
+        * I2C-registers are write-only */
+       unsigned char reg[25];
+
+       unsigned char norm;
+       unsigned char input;
+};
+
+static struct i2c_driver i2c_driver_saa7191;
+
+static const unsigned char initseq[] = {
+       0,      /* Subaddress */
+       0x50,   /* SAA7191_REG_IDEL */
+       0x30,   /* SAA7191_REG_HSYB */
+       0x00,   /* SAA7191_REG_HSYS */
+       0xe8,   /* SAA7191_REG_HCLB */
+       0xb6,   /* SAA7191_REG_HCLS */
+       0xf4,   /* SAA7191_REG_HPHI */
+       0x01,   /* SAA7191_REG_LUMA - chrominance trap active (CVBS) */
+       0x00,   /* SAA7191_REG_HUEC */
+       0xf8,   /* SAA7191_REG_CKTQ */
+       0xf8,   /* SAA7191_REG_CKTS */
+       0x90,   /* SAA7191_REG_PLSE */
+       0x90,   /* SAA7191_REG_SESE */
+       0x00,   /* SAA7191_REG_GAIN */
+       0x0c,   /* SAA7191_REG_STDC - not SECAM, slow time constant */
+       0x78,   /* SAA7191_REG_IOCK - chrominance from CVBS, GPSW1 & 2 off */
+       0x99,   /* SAA7191_REG_CTL3 - automatic field detection */
+       0x00,   /* SAA7191_REG_CTL4 */
+       0x2c,   /* SAA7191_REG_CHCV */
+       0x00,   /* unused */
+       0x00,   /* unused */
+       0x34,   /* SAA7191_REG_HS6B */
+       0x0a,   /* SAA7191_REG_HS6S */
+       0xf4,   /* SAA7191_REG_HC6B */
+       0xce,   /* SAA7191_REG_HC6S */
+       0xf4,   /* SAA7191_REG_HP6I */
+};
+
+/* SAA7191 register handling */
+
+static unsigned char saa7191_read_reg(struct i2c_client *client,
+                                     unsigned char reg)
+{
+       return ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg];
+}
+
+static int saa7191_read_status(struct i2c_client *client,
+                              unsigned char *value)
+{
+       int ret;
+
+       ret = i2c_master_recv(client, value, 1);
+       if (ret < 0) {
+               printk(KERN_ERR "SAA7191: saa7191_read_status(): read failed");
+               return ret;
+       }
+
+       return 0;
+}
+
+
+static int saa7191_write_reg(struct i2c_client *client, unsigned char reg,
+                            unsigned char value)
+{
+
+       ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg] = value;
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/* the first byte of data must be the first subaddress number (register) */
+static int saa7191_write_block(struct i2c_client *client,
+                              unsigned char length, unsigned char *data)
+{
+       int i;
+       int ret;
+
+       struct saa7191 *decoder = (struct saa7191 *)i2c_get_clientdata(client);
+       for (i = 0; i < (length - 1); i++) {
+               decoder->reg[data[0] + i] = data[i + 1];
+       }
+
+       ret = i2c_master_send(client, data, length);
+       if (ret < 0) {
+               printk(KERN_ERR "SAA7191: saa7191_write_block(): "
+                      "write failed");
+               return ret;
+       }
+
+       return 0;
+}
+
+/* Helper functions */
+
+static int saa7191_set_input(struct i2c_client *client, int input)
+{
+       unsigned char luma = saa7191_read_reg(client, SAA7191_REG_LUMA);
+       unsigned char iock = saa7191_read_reg(client, SAA7191_REG_IOCK);
+       int err;
+
+       switch (input) {
+       case SAA7191_INPUT_COMPOSITE: /* Set Composite input */
+               iock &= ~(SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW1
+                         | SAA7191_IOCK_GPSW2);
+               /* Chrominance trap active */
+               luma &= ~SAA7191_LUMA_BYPS;
+               break;
+       case SAA7191_INPUT_SVIDEO: /* Set S-Video input */
+               iock |= SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW2;
+               /* Chrominance trap bypassed */
+               luma |= SAA7191_LUMA_BYPS;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       err = saa7191_write_reg(client, SAA7191_REG_LUMA, luma);
+       if (err)
+               return -EIO;
+       err = saa7191_write_reg(client, SAA7191_REG_IOCK, iock);
+       if (err)
+               return -EIO;
+
+       return 0;
+}
+
+static int saa7191_set_norm(struct i2c_client *client, int norm)
+{
+       struct saa7191 *decoder = i2c_get_clientdata(client);
+       unsigned char stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
+       unsigned char ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3);
+       unsigned char chcv = saa7191_read_reg(client, SAA7191_REG_CHCV);
+       int err;
+
+       switch(norm) {
+       case SAA7191_NORM_AUTO: {
+               unsigned char status;
+
+               // does status depend on current norm ?
+               if (saa7191_read_status(client, &status))
+                       return -EIO;
+
+               stdc &= ~SAA7191_STDC_SECS;
+               ctl3 &= ~SAA7191_CTL3_FSEL;
+               ctl3 |= SAA7191_CTL3_AUFD;
+               chcv = (status & SAA7191_STATUS_FIDT)
+                              ? SAA7191_CHCV_NTSC : SAA7191_CHCV_PAL;
+               break;
+       }
+       case SAA7191_NORM_PAL:
+               stdc &= ~SAA7191_STDC_SECS;
+               ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
+               chcv = SAA7191_CHCV_PAL;
+               break;
+       case SAA7191_NORM_NTSC:
+               stdc &= ~SAA7191_STDC_SECS;
+               ctl3 &= ~SAA7191_CTL3_AUFD;
+               ctl3 |= SAA7191_CTL3_FSEL;
+               chcv = SAA7191_CHCV_NTSC;
+               break;
+       case SAA7191_NORM_SECAM:
+               stdc |= SAA7191_STDC_SECS;
+               ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
+               chcv = SAA7191_CHCV_PAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
+       if (err)
+               return -EIO;
+       err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc);
+       if (err)
+               return -EIO;
+       err = saa7191_write_reg(client, SAA7191_REG_CHCV, chcv);
+       if (err)
+               return -EIO;
+
+       decoder->norm = norm;
+
+       return 0;
+}
+
+static int saa7191_get_controls(struct i2c_client *client,
+                               struct saa7191_control *ctrl)
+{
+       unsigned char hue = saa7191_read_reg(client, SAA7191_REG_HUEC);
+       unsigned char stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
+
+       if (hue < 0x80) {
+               hue += 0x80;
+       } else {
+               hue -= 0x80;
+       }
+       ctrl->hue = hue;
+
+       ctrl->vtrc = (stdc & SAA7191_STDC_VTRC)
+               ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
+
+       return 0;
+}
+
+static int saa7191_set_controls(struct i2c_client *client,
+                               struct saa7191_control *ctrl)
+{
+       int err;
+
+       if (ctrl->hue >= 0) {
+               unsigned char hue = ctrl->hue & 0xff;
+               if (hue < 0x80) {
+                       hue += 0x80;
+               } else {
+                       hue -= 0x80;
+               }
+               err = saa7191_write_reg(client, SAA7191_REG_HUEC, hue);
+               if (err)
+                       return -EIO;
+       }
+       if (ctrl->vtrc >= 0) {
+               unsigned char stdc =
+                       saa7191_read_reg(client, SAA7191_REG_STDC);
+
+               if (ctrl->vtrc) {
+                       stdc |= SAA7191_STDC_VTRC;
+               } else {
+                       stdc &= ~SAA7191_STDC_VTRC;
+               }
+
+               err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc);
+               if (err)
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+/* I2C-interface */
+
+static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind)
+{
+       int err = 0;
+       struct saa7191 *decoder;
+       struct i2c_client *client;
+
+       printk(KERN_INFO "Philips SAA7191 driver version %s\n",
+              SAA7191_MODULE_VERSION);
+
+       client = kmalloc(sizeof(*client), GFP_KERNEL);
+       if (!client)
+               return -ENOMEM;
+       decoder = kmalloc(sizeof(*decoder), GFP_KERNEL);
+       if (!decoder) {
+               err = -ENOMEM;
+               goto out_free_client;
+       }
+
+       memset(client, 0, sizeof(struct i2c_client));
+       memset(decoder, 0, sizeof(struct saa7191));
+
+       client->addr = addr;
+       client->adapter = adap;
+       client->driver = &i2c_driver_saa7191;
+       client->flags = 0;
+       strcpy(client->name, "saa7191 client");
+       i2c_set_clientdata(client, decoder);
+
+       decoder->client = client;
+
+       err = i2c_attach_client(client);
+       if (err)
+               goto out_free_decoder;
+
+       decoder->input = SAA7191_INPUT_COMPOSITE;
+       decoder->norm = SAA7191_NORM_AUTO;
+
+       err = saa7191_write_block(client, sizeof(initseq),
+                                 (unsigned char *)initseq);
+       if (err) {
+               printk(KERN_ERR "SAA7191 initialization failed\n");
+               goto out_detach_client;
+       }
+
+       printk(KERN_INFO "SAA7191 initialized\n");
+
+       return 0;
+
+out_detach_client:
+       i2c_detach_client(client);
+out_free_decoder:
+       kfree(decoder);
+out_free_client:
+       kfree(client);
+       return err;
+}
+
+static int saa7191_probe(struct i2c_adapter *adap)
+{
+       /* Always connected to VINO */
+       if (adap->id == VINO_ADAPTER)
+               return saa7191_attach(adap, SAA7191_ADDR, 0);
+       /* Feel free to add probe here :-) */
+       return -ENODEV;
+}
+
+static int saa7191_detach(struct i2c_client *client)
+{
+       struct saa7191 *decoder = i2c_get_clientdata(client);
+
+       i2c_detach_client(client);
+       kfree(decoder);
+       kfree(client);
+       return 0;
+}
+
+static int saa7191_command(struct i2c_client *client, unsigned int cmd,
+                          void *arg)
+{
+       struct saa7191 *decoder = i2c_get_clientdata(client);
+
+       switch (cmd) {
+       case DECODER_GET_CAPABILITIES: {
+               struct video_decoder_capability *cap = arg;
+
+               cap->flags  = VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC |
+                             VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO;
+               cap->inputs = (client->adapter->id == VINO_ADAPTER) ? 2 : 1;
+               cap->outputs = 1;
+               break;
+       }
+       case DECODER_GET_STATUS: {
+               int *iarg = arg;
+               unsigned char status;
+               int res = 0;
+
+               if (saa7191_read_status(client, &status)) {
+                       return -EIO;
+               }
+               if ((status & SAA7191_STATUS_HLCK) == 0)
+                       res |= DECODER_STATUS_GOOD;
+               if (status & SAA7191_STATUS_CODE)
+                       res |= DECODER_STATUS_COLOR;
+               switch (decoder->norm) {
+               case SAA7191_NORM_NTSC:
+                       res |= DECODER_STATUS_NTSC;
+                       break;
+               case SAA7191_NORM_PAL:
+                       res |= DECODER_STATUS_PAL;
+                       break;
+               case SAA7191_NORM_SECAM:
+                       res |= DECODER_STATUS_SECAM;
+                       break;
+               case SAA7191_NORM_AUTO:
+               default:
+                       if (status & SAA7191_STATUS_FIDT)
+                               res |= DECODER_STATUS_NTSC;
+                       else
+                               res |= DECODER_STATUS_PAL;
+                       break;
+               }
+               *iarg = res;
+               break;
+       }
+       case DECODER_SET_NORM: {
+               int *iarg = arg;
+
+               switch (*iarg) {
+               case VIDEO_MODE_AUTO:
+                       return saa7191_set_norm(client, SAA7191_NORM_AUTO);
+               case VIDEO_MODE_PAL:
+                       return saa7191_set_norm(client, SAA7191_NORM_PAL);
+               case VIDEO_MODE_NTSC:
+                       return saa7191_set_norm(client, SAA7191_NORM_NTSC);
+               case VIDEO_MODE_SECAM:
+                       return saa7191_set_norm(client, SAA7191_NORM_SECAM);
+               default:
+                       return -EINVAL;
+               }
+               break;
+       }
+       case DECODER_SET_INPUT: {
+               int *iarg = arg;
+
+               switch (client->adapter->id) {
+               case VINO_ADAPTER:
+                       return saa7191_set_input(client, *iarg);
+               default:
+                       if (*iarg != 0)
+                               return -EINVAL;
+               }
+               break;
+       }
+       case DECODER_SET_OUTPUT: {
+               int *iarg = arg;
+
+               /* not much choice of outputs */
+               if (*iarg != 0)
+                       return -EINVAL;
+               break;
+       }
+       case DECODER_ENABLE_OUTPUT: {
+               /* Always enabled */
+               break;
+       }
+       case DECODER_SET_PICTURE: {
+               struct video_picture *pic = arg;
+               unsigned val;
+               int err;
+
+               val = (pic->hue >> 8) - 0x80;
+               err = saa7191_write_reg(client, SAA7191_REG_HUEC, val);
+               if (err)
+                       return -EIO;
+               break;
+       }
+       case DECODER_SAA7191_GET_STATUS: {
+               struct saa7191_status *status = arg;
+               unsigned char status_reg;
+
+               if (saa7191_read_status(client, &status_reg))
+                       return -EIO;
+               status->signal = ((status_reg & SAA7191_STATUS_HLCK) == 0)
+                       ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
+               status->ntsc = (status_reg & SAA7191_STATUS_FIDT)
+                       ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
+               status->color = (status_reg & SAA7191_STATUS_CODE)
+                       ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
+
+               status->input = decoder->input;
+               status->norm = decoder->norm;
+       }
+       case DECODER_SAA7191_SET_NORM: {
+               int *norm = arg;
+               return saa7191_set_norm(client, *norm);
+       }
+       case DECODER_SAA7191_GET_CONTROLS: {
+               struct saa7191_control *ctrl = arg;
+               return saa7191_get_controls(client, ctrl);
+       }
+       case DECODER_SAA7191_SET_CONTROLS: {
+               struct saa7191_control *ctrl = arg;
+               return saa7191_set_controls(client, ctrl);
+       }
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct i2c_driver i2c_driver_saa7191 = {
+       .owner          = THIS_MODULE,
+       .name           = "saa7191",
+       .id             = I2C_DRIVERID_SAA7191,
+       .flags          = I2C_DF_NOTIFY,
+       .attach_adapter = saa7191_probe,
+       .detach_client  = saa7191_detach,
+       .command        = saa7191_command
+};
+
+static int saa7191_init(void)
+{
+       return i2c_add_driver(&i2c_driver_saa7191);
+}
+
+static void saa7191_exit(void)
+{
+       i2c_del_driver(&i2c_driver_saa7191);
+}
+
+module_init(saa7191_init);
+module_exit(saa7191_exit);
diff --git a/drivers/media/video/saa7191.h b/drivers/media/video/saa7191.h
new file mode 100644 (file)
index 0000000..2720450
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ *  saa7191.h - Philips SAA7191 video decoder driver
+ *
+ *  Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ *  Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ *  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 _SAA7191_H_
+#define _SAA7191_H_
+
+/* Philips SAA7191 DMSD I2C bus address */
+#define SAA7191_ADDR           0x8a
+
+/* Register subaddresses. */
+#define SAA7191_REG_IDEL       0x00
+#define SAA7191_REG_HSYB       0x01
+#define SAA7191_REG_HSYS       0x02
+#define SAA7191_REG_HCLB       0x03
+#define SAA7191_REG_HCLS       0x04
+#define SAA7191_REG_HPHI       0x05
+#define SAA7191_REG_LUMA       0x06
+#define SAA7191_REG_HUEC       0x07
+#define SAA7191_REG_CKTQ       0x08
+#define SAA7191_REG_CKTS       0x09
+#define SAA7191_REG_PLSE       0x0a
+#define SAA7191_REG_SESE       0x0b
+#define SAA7191_REG_GAIN       0x0c
+#define SAA7191_REG_STDC       0x0d
+#define SAA7191_REG_IOCK       0x0e
+#define SAA7191_REG_CTL3       0x0f
+#define SAA7191_REG_CTL4       0x10
+#define SAA7191_REG_CHCV       0x11
+#define SAA7191_REG_HS6B       0x14
+#define SAA7191_REG_HS6S       0x15
+#define SAA7191_REG_HC6B       0x16
+#define SAA7191_REG_HC6S       0x17
+#define SAA7191_REG_HP6I       0x18
+#define SAA7191_REG_STATUS     0xff    /* not really a subaddress */
+
+/* Status Register definitions */
+#define SAA7191_STATUS_CODE    0x01    /* color detected flag */
+#define SAA7191_STATUS_FIDT    0x20    /* format type NTSC/PAL */
+#define SAA7191_STATUS_HLCK    0x40    /* PLL unlocked/locked */
+#define SAA7191_STATUS_STTC    0x80    /* tv/vtr time constant */
+
+/* Luminance Control Register definitions */
+#define SAA7191_LUMA_BYPS      0x80
+
+/* Chroma Gain Control Settings Register definitions */
+/* 0=automatic colour-killer enabled, 1=forced colour on */
+#define SAA7191_GAIN_COLO      0x80
+
+/* Standard/Mode Control Register definitions */
+/* tv/vtr mode bit: 0=TV mode (slow time constant),
+ * 1=VTR mode (fast time constant) */
+#define SAA7191_STDC_VTRC      0x80
+/* SECAM mode bit: 0=other standards, 1=SECAM */
+#define SAA7191_STDC_SECS      0x01
+/* the bit fields above must be or'd with this value */
+#define SAA7191_STDC_VALUE     0x0c
+
+/* I/O and Clock Control Register definitions */
+/* horizontal clock PLL: 0=PLL closed,
+ * 1=PLL circuit open and horizontal freq fixed */
+#define SAA7191_IOCK_HPLL      0x80
+/* S-VHS bit (chrominance from CVBS or from chrominance input):
+ * 0=controlled by BYPS-bit, 1=from chrominance input */
+#define SAA7191_IOCK_CHRS      0x04
+/* general purpose switch 2
+ * VINO-specific: 0=used with CVBS, 1=used with S-Video */
+#define SAA7191_IOCK_GPSW2     0x02
+/* general purpose switch 1 */
+/* VINO-specific: 0=always, 1=not used!*/
+#define SAA7191_IOCK_GPSW1     0x01
+
+/* Miscellaneous Control #1 Register definitions */
+/* automatic field detection (50/60Hz standard) */
+#define SAA7191_CTL3_AUFD      0x80
+/* field select: (if AUFD=0)
+ * 0=50Hz (625 lines), 1=60Hz (525 lines) */
+#define SAA7191_CTL3_FSEL      0x40
+/* the bit fields above must be or'd with this value */
+#define SAA7191_CTL3_VALUE     0x19
+
+/* Chrominance Gain Control Register definitions
+ * (nominal value for UV CCIR level) */
+#define SAA7191_CHCV_NTSC      0x2c
+#define SAA7191_CHCV_PAL       0x59
+
+/* Driver interface definitions */
+#define SAA7191_INPUT_COMPOSITE        0
+#define SAA7191_INPUT_SVIDEO   1
+
+#define SAA7191_NORM_AUTO      0
+#define SAA7191_NORM_PAL       1
+#define SAA7191_NORM_NTSC      2
+#define SAA7191_NORM_SECAM     3
+
+#define SAA7191_VALUE_ENABLED          1
+#define SAA7191_VALUE_DISABLED         0
+#define SAA7191_VALUE_UNCHANGED                -1
+
+struct saa7191_status {
+       /* 0=no signal, 1=signal active*/
+       int signal;
+       /* 0=50hz (pal) signal, 1=60hz (ntsc) signal */
+       int ntsc;
+       /* 0=no color detected, 1=color detected */
+       int color;
+
+       /* current SAA7191_INPUT_ */
+       int input;
+       /* current SAA7191_NORM_ */
+       int norm;
+};
+
+#define SAA7191_HUE_MIN                0x00
+#define SAA7191_HUE_MAX                0xff
+#define SAA7191_HUE_DEFAULT    0x80
+
+#define SAA7191_VTRC_MIN       0x00
+#define SAA7191_VTRC_MAX       0x01
+#define SAA7191_VTRC_DEFAULT   0x00
+
+struct saa7191_control {
+       int hue;
+       int vtrc;
+};
+
+#define        DECODER_SAA7191_GET_STATUS      _IOR('d', 195, struct saa7191_status)
+#define        DECODER_SAA7191_SET_NORM        _IOW('d', 196, int)
+#define        DECODER_SAA7191_GET_CONTROLS    _IOR('d', 197, struct saa7191_control)
+#define        DECODER_SAA7191_SET_CONTROLS    _IOW('d', 198, struct saa7191_control)
+
+#endif
index 7cb1fb3e66f90a46f015982657beb02c2a973f55..255b6088ebf9ba8a86f448a29b96e57f3cce33d8 100644 (file)
@@ -328,7 +328,7 @@ static int tda7432_probe(struct i2c_adapter *adap)
        if (adap->class & I2C_CLASS_TV_ANALOG)
                return i2c_probe(adap, &addr_data, tda7432_attach);
 #else
-       if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+       if (adap->id == I2C_HW_B_BT848)
                return i2c_probe(adap, &addr_data, tda7432_attach);
 #endif
        return 0;
@@ -513,7 +513,7 @@ static struct i2c_driver driver = {
 
 static struct i2c_client client_template =
 {
-       I2C_DEVNAME("tda7432"),
+       .name       = "tda7432",
        .driver     = &driver,
 };
 
index c29bdfc3244e8f2562e9744d5f8d508f89a4b525..1794686612c6dccac93431e3b5f22f1f1c62f9f1 100644 (file)
@@ -205,7 +205,7 @@ static int detect(struct i2c_adapter *adapter, int address, int kind)
 static int attach(struct i2c_adapter *adapter)
 {
        /* let's see whether this is a know adapter we can attach to */
-       if (adapter->id != I2C_ALGO_SAA7146) {
+       if (adapter->id != I2C_HW_SAA7146) {
                dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id);
                return -ENODEV;
        }
@@ -231,7 +231,7 @@ static struct i2c_driver driver = {
 };
 
 static struct i2c_client client_template = {
-       I2C_DEVNAME("tda9840"),
+       .name = "tda9840",
        .driver = &driver,
 };
 
index 566e1a5ca135578c002b8d833706522bec4cd176..7e3dcdb262b0ef0c65e18a7c693da652b3da37bc 100644 (file)
@@ -262,7 +262,7 @@ static int tda9875_probe(struct i2c_adapter *adap)
        if (adap->class & I2C_CLASS_TV_ANALOG)
                return i2c_probe(adap, &addr_data, tda9875_attach);
 #else
-       if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+       if (adap->id == I2C_HW_B_BT848)
                return i2c_probe(adap, &addr_data, tda9875_attach);
 #endif
        return 0;
@@ -384,7 +384,7 @@ static struct i2c_driver driver = {
 
 static struct i2c_client client_template =
 {
-        I2C_DEVNAME("tda9875"),
+        .name      = "tda9875",
         .driver    = &driver,
 };
 
index 108c3ad7d62229f73d29e0c75459311da8d8e359..d60fc562aecdc4a1e2d05974cf976e11ec29aaf4 100644 (file)
@@ -618,9 +618,9 @@ static int tda9887_probe(struct i2c_adapter *adap)
                return i2c_probe(adap, &addr_data, tda9887_attach);
 #else
        switch (adap->id) {
-       case I2C_ALGO_BIT | I2C_HW_B_BT848:
-       case I2C_ALGO_BIT | I2C_HW_B_RIVA:
-       case I2C_ALGO_SAA7134:
+       case I2C_HW_B_BT848:
+       case I2C_HW_B_RIVA:
+       case I2C_HW_SAA7134:
                return i2c_probe(adap, &addr_data, tda9887_attach);
                break;
        }
@@ -760,7 +760,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
        return 0;
 }
 
-static int tda9887_suspend(struct device * dev, u32 state, u32 level)
+static int tda9887_suspend(struct device * dev, pm_message_t state, u32 level)
 {
        dprintk("tda9887: suspend\n");
        return 0;
@@ -793,7 +793,7 @@ static struct i2c_driver driver = {
 };
 static struct i2c_client client_template =
 {
-       I2C_DEVNAME("tda9887"),
+       .name      = "tda9887",
        .flags     = I2C_CLIENT_ALLOW_USE,
         .driver    = &driver,
 };
index b44db8a7b94dfed4ca0e6e3c1acd03ad9c4465d0..ee3688348b662bac1dc06dc7be1893cd537f185d 100644 (file)
@@ -86,7 +86,7 @@ static int detect(struct i2c_adapter *adapter, int address, int kind)
 static int attach(struct i2c_adapter *adapter)
 {
        /* let's see whether this is a know adapter we can attach to */
-       if (adapter->id != I2C_ALGO_SAA7146) {
+       if (adapter->id != I2C_HW_SAA7146) {
                dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id);
                return -ENODEV;
        }
@@ -200,7 +200,7 @@ static struct i2c_driver driver = {
 };
 
 static struct i2c_client client_template = {
-       I2C_DEVNAME("tea6415c"),
+       .name = "tea6415c",
        .driver = &driver,
 };
 
index 48d4db7d507b1d77b14429abae83d2960bb1a9a9..17975c19da5ee376f08ba2b7e98b96d4469b519b 100644 (file)
@@ -135,7 +135,7 @@ static int tea6420_detect(struct i2c_adapter *adapter, int address, int kind)
 static int attach(struct i2c_adapter *adapter)
 {
        /* let's see whether this is a know adapter we can attach to */
-       if (adapter->id != I2C_ALGO_SAA7146) {
+       if (adapter->id != I2C_HW_SAA7146) {
                dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id);
                return -ENODEV;
        }
@@ -177,7 +177,7 @@ static struct i2c_driver driver = {
 };
 
 static struct i2c_client client_template = {
-       I2C_DEVNAME("tea6420"),
+       .name = "tea6420",
        .driver = &driver,
 };
 
index 7d825e510ffd577a891c281e941658713b3a729e..79203595b9c13456d09c7c700b3127f16ed52734 100644 (file)
@@ -41,7 +41,6 @@ static struct i2c_client_address_data addr_data = {
        .normal_i2c     = normal_i2c,
        .probe          = &ignore,
        .ignore         = &ignore,
-       .force          = &ignore,
 };
 
 /* ---------------------------------------------------------------------- */
@@ -166,7 +165,7 @@ static int
 tuner_probe(struct i2c_adapter *adap)
 {
        this_adap = 0;
-       if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_LP))
+       if (adap->id == I2C_HW_B_LP)
                return i2c_probe(adap, &addr_data, tuner_attach);
        return 0;
 }
index f0a579827a2416d0c132320ac8842118a220ae45..3b1893c2ae3b136ffbf80d6fbf7122e53ce274ca 100644 (file)
@@ -672,7 +672,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
        return 0;
 }
 
-static int tuner_suspend(struct device *dev, u32 state, u32 level)
+static int tuner_suspend(struct device *dev, pm_message_t state, u32 level)
 {
        struct i2c_client *c = container_of (dev, struct i2c_client, dev);
        struct tuner *t = i2c_get_clientdata (c);
@@ -709,7 +709,7 @@ static struct i2c_driver driver = {
                   },
 };
 static struct i2c_client client_template = {
-       I2C_DEVNAME("(tuner unset)"),
+       .name = "(tuner unset)",
        .flags = I2C_CLIENT_ALLOW_USE,
        .driver = &driver,
 };
index f42a1efa8fcfa8c4ce83fbe7b6a6dae7337ff645..258724b2d6d21a2001450996a3ac23541bc5afdb 100644 (file)
@@ -162,24 +162,23 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
        unsigned char buffer[2];
 
        if (-1 == subaddr) {
-               dprintk("%s: chip_write: 0x%x\n",
-                       i2c_clientname(&chip->c), val);
+               dprintk("%s: chip_write: 0x%x\n", chip->c.name, val);
                chip->shadow.bytes[1] = val;
                buffer[0] = val;
                if (1 != i2c_master_send(&chip->c,buffer,1)) {
                        printk(KERN_WARNING "%s: I/O error (write 0x%x)\n",
-                              i2c_clientname(&chip->c), val);
+                              chip->c.name, val);
                        return -1;
                }
        } else {
                dprintk("%s: chip_write: reg%d=0x%x\n",
-                       i2c_clientname(&chip->c), subaddr, val);
+                       chip->c.name, subaddr, val);
                chip->shadow.bytes[subaddr+1] = val;
                buffer[0] = subaddr;
                buffer[1] = val;
                if (2 != i2c_master_send(&chip->c,buffer,2)) {
                        printk(KERN_WARNING "%s: I/O error (write reg%d=0x%x)\n",
-                              i2c_clientname(&chip->c), subaddr, val);
+                              chip->c.name, subaddr, val);
                        return -1;
                }
        }
@@ -203,11 +202,10 @@ static int chip_read(struct CHIPSTATE *chip)
        unsigned char buffer;
 
        if (1 != i2c_master_recv(&chip->c,&buffer,1)) {
-               printk(KERN_WARNING "%s: I/O error (read)\n",
-                      i2c_clientname(&chip->c));
+               printk(KERN_WARNING "%s: I/O error (read)\n", chip->c.name);
                return -1;
        }
-       dprintk("%s: chip_read: 0x%x\n",i2c_clientname(&chip->c),buffer);
+       dprintk("%s: chip_read: 0x%x\n", chip->c.name, buffer);
        return buffer;
 }
 
@@ -222,12 +220,11 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr)
         write[0] = subaddr;
 
        if (2 != i2c_transfer(chip->c.adapter,msgs,2)) {
-               printk(KERN_WARNING "%s: I/O error (read2)\n",
-                      i2c_clientname(&chip->c));
+               printk(KERN_WARNING "%s: I/O error (read2)\n", chip->c.name);
                return -1;
        }
        dprintk("%s: chip_read2: reg%d=0x%x\n",
-               i2c_clientname(&chip->c),subaddr,read[0]);
+               chip->c.name, subaddr, read[0]);
        return read[0];
 }
 
@@ -240,7 +237,7 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
 
        /* update our shadow register set; print bytes if (debug > 0) */
        dprintk("%s: chip_cmd(%s): reg=%d, data:",
-               i2c_clientname(&chip->c),name,cmd->bytes[0]);
+               chip->c.name, name, cmd->bytes[0]);
        for (i = 1; i < cmd->count; i++) {
                dprintk(" 0x%x",cmd->bytes[i]);
                chip->shadow.bytes[i+cmd->bytes[0]] = cmd->bytes[i];
@@ -249,7 +246,7 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
 
        /* send data to the chip */
        if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) {
-               printk(KERN_WARNING "%s: I/O error (%s)\n", i2c_clientname(&chip->c), name);
+               printk(KERN_WARNING "%s: I/O error (%s)\n", chip->c.name, name);
                return -1;
        }
        return 0;
@@ -274,9 +271,9 @@ static int chip_thread(void *data)
         struct CHIPSTATE *chip = data;
        struct CHIPDESC  *desc = chiplist + chip->type;
 
-       daemonize("%s",i2c_clientname(&chip->c));
+       daemonize("%s", chip->c.name);
        allow_signal(SIGTERM);
-       dprintk("%s: thread started\n", i2c_clientname(&chip->c));
+       dprintk("%s: thread started\n", chip->c.name);
 
        for (;;) {
                add_wait_queue(&chip->wq, &wait);
@@ -288,7 +285,7 @@ static int chip_thread(void *data)
                try_to_freeze();
                if (chip->done || signal_pending(current))
                        break;
-               dprintk("%s: thread wakeup\n", i2c_clientname(&chip->c));
+               dprintk("%s: thread wakeup\n", chip->c.name);
 
                /* don't do anything for radio or if mode != auto */
                if (chip->norm == VIDEO_MODE_RADIO || chip->mode != 0)
@@ -301,7 +298,7 @@ static int chip_thread(void *data)
                mod_timer(&chip->wt, jiffies+2*HZ);
        }
 
-       dprintk("%s: thread exiting\n", i2c_clientname(&chip->c));
+       dprintk("%s: thread exiting\n", chip->c.name);
         complete_and_exit(&chip->texit, 0);
        return 0;
 }
@@ -314,7 +311,7 @@ static void generic_checkmode(struct CHIPSTATE *chip)
        if (mode == chip->prevmode)
            return;
 
-       dprintk("%s: thread checkmode\n", i2c_clientname(&chip->c));
+       dprintk("%s: thread checkmode\n", chip->c.name);
        chip->prevmode = mode;
 
        if (mode & VIDEO_SOUND_STEREO)
@@ -1098,7 +1095,7 @@ static int tda8425_initialize(struct CHIPSTATE *chip)
                            /* extern   */ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF,
                            /* off      */ TDA8425_S1_OFF, /* on     */ TDA8425_S1_CH2};
 
-       if (chip->c.adapter->id == (I2C_ALGO_BIT | I2C_HW_B_RIVA)) {
+       if (chip->c.adapter->id == I2C_HW_B_RIVA) {
                memcpy (desc->inputmap, inputmap, sizeof (inputmap));
        }
        return 0;
@@ -1501,7 +1498,7 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
                (desc->flags & CHIP_HAS_INPUTSEL)   ? " audiomux"    : "");
 
        /* fill required data structures */
-       strcpy(i2c_clientname(&chip->c),desc->name);
+       strcpy(chip->c.name, desc->name);
        chip->type = desc-chiplist;
        chip->shadow.count = desc->registers+1;
         chip->prevmode = -1;
@@ -1538,7 +1535,7 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
                chip->tpid = kernel_thread(chip_thread,(void *)chip,0);
                if (chip->tpid < 0)
                        printk(KERN_WARNING "%s: kernel_thread() failed\n",
-                              i2c_clientname(&chip->c));
+                              chip->c.name);
                wake_up_interruptible(&chip->wq);
        }
        return 0;
@@ -1548,16 +1545,16 @@ static int chip_probe(struct i2c_adapter *adap)
 {
        /* don't attach on saa7146 based cards,
           because dedicated drivers are used */
-       if ((adap->id & I2C_ALGO_SAA7146))
+       if (adap->id == I2C_HW_SAA7146)
                return 0;
 #ifdef I2C_CLASS_TV_ANALOG
        if (adap->class & I2C_CLASS_TV_ANALOG)
                return i2c_probe(adap, &addr_data, chip_attach);
 #else
        switch (adap->id) {
-       case I2C_ALGO_BIT | I2C_HW_B_BT848:
-       case I2C_ALGO_BIT | I2C_HW_B_RIVA:
-       case I2C_ALGO_SAA7134:
+       case I2C_HW_B_BT848:
+       case I2C_HW_B_RIVA:
+       case I2C_HW_SAA7134:
                return i2c_probe(adap, &addr_data, chip_attach);
        }
 #endif
@@ -1591,7 +1588,7 @@ static int chip_command(struct i2c_client *client,
        struct CHIPSTATE *chip = i2c_get_clientdata(client);
        struct CHIPDESC  *desc = chiplist + chip->type;
 
-       dprintk("%s: chip_command 0x%x\n",i2c_clientname(&chip->c),cmd);
+       dprintk("%s: chip_command 0x%x\n", chip->c.name, cmd);
 
        switch (cmd) {
        case AUDC_SET_INPUT:
@@ -1702,7 +1699,7 @@ static struct i2c_driver driver = {
 
 static struct i2c_client client_template =
 {
-       I2C_DEVNAME("(unset)"),
+       .name       = "(unset)",
        .flags      = I2C_CLIENT_ALLOW_USE,
         .driver     = &driver,
 };
index 127ec38ebd60822d4b48954a6331705c8f3ffd3e..3c3356a01cc67e9dc3cf9b09114a3bd8e1485dcf 100644 (file)
@@ -534,7 +534,7 @@ static int
 tveeprom_attach_adapter (struct i2c_adapter *adapter)
 {
        dprintk(1,"%s: id 0x%x\n",__FUNCTION__,adapter->id);
-       if (adapter->id != (I2C_ALGO_BIT | I2C_HW_B_BT848))
+       if (adapter->id != I2C_HW_B_BT848)
                return 0;
        return i2c_probe(adapter, &addr_data, tveeprom_detect_client);
 }
index 51b99cdbf29e8bc9447dc65eea4b53d7f230e2ae..a43301a154af413dc2f5754beaa410ee3dfd14ca 100644 (file)
@@ -91,7 +91,7 @@ static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cm
         if (cmd == SOUND_MIXER_INFO) {
                 mixer_info info;
                 strlcpy(info.id, "tv card", sizeof(info.id));
-                strlcpy(info.name, i2c_clientname(client), sizeof(info.name));
+                strlcpy(info.name, client->name, sizeof(info.name));
                 info.modify_counter = 42 /* FIXME */;
                 if (copy_to_user(argp, &info, sizeof(info)))
                         return -EFAULT;
@@ -100,7 +100,7 @@ static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cm
         if (cmd == SOUND_OLD_MIXER_INFO) {
                 _old_mixer_info info;
                 strlcpy(info.id, "tv card", sizeof(info.id));
-                strlcpy(info.name, i2c_clientname(client), sizeof(info.name));
+                strlcpy(info.name, client->name, sizeof(info.name));
                 if (copy_to_user(argp, &info, sizeof(info)))
                         return -EFAULT;
                 return 0;
@@ -276,9 +276,9 @@ static int tvmixer_clients(struct i2c_client *client)
 #else
        /* TV card ??? */
        switch (client->adapter->id) {
-       case I2C_ALGO_BIT | I2C_HW_SMBUS_VOODOO3:
-       case I2C_ALGO_BIT | I2C_HW_B_BT848:
-       case I2C_ALGO_BIT | I2C_HW_B_RIVA:
+       case I2C_HW_SMBUS_VOODOO3:
+       case I2C_HW_B_BT848:
+       case I2C_HW_B_RIVA:
                /* ok, have a look ... */
                break;
        default:
@@ -295,7 +295,7 @@ static int tvmixer_clients(struct i2c_client *client)
                        devices[i].dev = NULL;
                        devices[i].minor = -1;
                        printk("tvmixer: %s unregistered (#1)\n",
-                              i2c_clientname(client));
+                              client->name);
                        return 0;
                }
        }
@@ -354,7 +354,7 @@ static void __exit tvmixer_cleanup_module(void)
                if (devices[i].minor != -1) {
                        unregister_sound_mixer(devices[i].minor);
                        printk("tvmixer: %s unregistered (#2)\n",
-                              i2c_clientname(devices[i].dev));
+                              devices[i].dev->name);
                }
        }
 }
index 76e8681d65c662f863636fb67deaf35f7158391b..d8a0f763ca101314d18f1c501631dca62d125f62 100644 (file)
 /*
- * (incomplete) Driver for the VINO (Video In No Out) system found in SGI Indys.
+ * Driver for the VINO (Video In No Out) system found in SGI Indys.
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License version 2 as published by the Free Software Foundation.
  *
+ * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ * Based on the previous version of the driver for 2.4 kernels by:
  * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
  */
 
-#include <linux/module.h>
+/*
+ * TODO:
+ * - remove "hacks" from memory allocation code and implement nopage()
+ * - check decimation, calculating and reporting image size when
+ *   using decimation
+ * - check vino_acquire_input(), vino_set_input() and channel
+ *   ownership handling
+ * - report VINO error-interrupts via ioctls ?
+ * - implement picture controls (all implemented?)
+ * - use macros for boolean values (?)
+ * - implement user mode buffers and overlay (?)
+ */
+
 #include <linux/init.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/wrapper.h>
-#include <linux/errno.h>
-#include <linux/irq.h>
+#include <linux/module.h>
 #include <linux/delay.h>
-#include <linux/videodev.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/time.h>
+#include <linux/moduleparam.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
 #include <linux/i2c.h>
 #include <linux/i2c-algo-sgi.h>
 
-#include <asm/addrspace.h>
-#include <asm/system.h>
-#include <asm/bootinfo.h>
-#include <asm/pgtable.h>
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <linux/video_decoder.h>
+
 #include <asm/paccess.h>
 #include <asm/io.h>
 #include <asm/sgi/ip22.h>
-#include <asm/sgi/hpc3.h>
 #include <asm/sgi/mc.h>
 
 #include "vino.h"
+#include "saa7191.h"
+#include "indycam.h"
 
-/* debugging? */
-#if 1
-#define DEBUG(x...)     printk(x);
+/* Uncomment the following line to get lots and lots of (mostly useless)
+ * debug info.
+ * Note that the debug output also slows down the driver significantly */
+// #define VINO_DEBUG
+
+#define VINO_MODULE_VERSION "0.0.3"
+#define VINO_VERSION_CODE KERNEL_VERSION(0, 0, 3)
+
+MODULE_DESCRIPTION("SGI VINO Video4Linux2 driver");
+MODULE_VERSION(VINO_MODULE_VERSION);
+MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
+MODULE_LICENSE("GPL");
+
+#define mem_map_reserve(p) set_bit(PG_reserved, &((p)->flags))
+#define mem_map_unreserve(p) clear_bit(PG_reserved, &((p)->flags))
+
+#ifdef VINO_DEBUG
+#define dprintk(x...) printk("VINO: " x);
 #else
-#define DEBUG(x...)
+#define dprintk(x...)
 #endif
 
+#define VINO_NO_CHANNEL                        0
+#define VINO_CHANNEL_A                 1
+#define VINO_CHANNEL_B                 2
+
+#define VINO_PAL_WIDTH                 768
+#define VINO_PAL_HEIGHT                        576
+#define VINO_NTSC_WIDTH                        640
+#define VINO_NTSC_HEIGHT               480
+
+#define VINO_MIN_WIDTH                 32
+#define VINO_MIN_HEIGHT                        32
+
+#define VINO_CLIPPING_START_ODD_D1     1
+#define VINO_CLIPPING_START_ODD_PAL    1
+#define VINO_CLIPPING_START_ODD_NTSC   1
+
+#define VINO_CLIPPING_START_EVEN_D1    2
+#define VINO_CLIPPING_START_EVEN_PAL   2
+#define VINO_CLIPPING_START_EVEN_NTSC  2
+
+#define VINO_INPUT_CHANNEL_COUNT       3
+
+#define VINO_INPUT_NONE                        -1
+#define VINO_INPUT_COMPOSITE           0
+#define VINO_INPUT_SVIDEO              1
+#define VINO_INPUT_D1                  2
+
+#define VINO_PAGE_RATIO                        (PAGE_SIZE / VINO_PAGE_SIZE)
+
+#define VINO_FIFO_THRESHOLD_DEFAULT    512
+
+/*#define VINO_FRAMEBUFFER_SIZE                (VINO_PAL_WIDTH * VINO_PAL_HEIGHT * 4 \
+  + 2 * PAGE_SIZE)*/
+#define VINO_FRAMEBUFFER_SIZE          ((VINO_PAL_WIDTH \
+                                         * VINO_PAL_HEIGHT * 4 \
+                                         + 3 * PAGE_SIZE) & ~(PAGE_SIZE - 1))
+
+#define VINO_FRAMEBUFFER_MAX_COUNT     8
+
+#define VINO_FRAMEBUFFER_UNUSED                0
+#define VINO_FRAMEBUFFER_IN_USE                1
+#define VINO_FRAMEBUFFER_READY         2
+
+#define VINO_QUEUE_ERROR               -1
+#define VINO_QUEUE_MAGIC               0x20050125
+
+#define VINO_MEMORY_NONE               0
+#define VINO_MEMORY_MMAP               1
+#define VINO_MEMORY_USERPTR            2
+
+#define VINO_DUMMY_DESC_COUNT          4
+#define VINO_DESC_FETCH_DELAY          5       /* microseconds */
+
+/* the number is the index for vino_data_formats */
+#define VINO_DATA_FMT_NONE             -1
+#define VINO_DATA_FMT_GREY             0
+#define VINO_DATA_FMT_RGB332           1
+#define VINO_DATA_FMT_RGB32            2
+#define VINO_DATA_FMT_YUV              3
+//#define VINO_DATA_FMT_RGB24          4
+
+#define VINO_DATA_FMT_COUNT            4
+
+#define VINO_DATA_NORM_NONE            -1
+#define VINO_DATA_NORM_NTSC            0
+#define VINO_DATA_NORM_PAL             1
+#define VINO_DATA_NORM_SECAM           2
+#define VINO_DATA_NORM_D1              3
+/* The following is a special entry that can be used to
+ * autodetect the norm. */
+#define VINO_DATA_NORM_AUTO            0xff
+
+#define VINO_DATA_NORM_COUNT           4
+
+/* Internal data structure definitions */
+
+struct vino_input {
+       char *name;
+       v4l2_std_id std;
+};
+
+struct vino_clipping {
+       unsigned int left, right, top, bottom;
+};
+
+struct vino_data_format {
+       /* the description */
+       char *description;
+       /* bytes per pixel */
+       unsigned int bpp;
+       /* V4L2 fourcc code */
+       __u32 pixelformat;
+       /* V4L2 colorspace (duh!) */
+       enum v4l2_colorspace colorspace;
+};
+
+struct vino_data_norm {
+       char *description;
+       unsigned int width, height;
+       struct vino_clipping odd;
+       struct vino_clipping even;
+
+       v4l2_std_id std;
+       unsigned int fps_min, fps_max;
+       __u32 framelines;
+};
+
+struct vino_descriptor_table {
+       /* the number of PAGE_SIZE sized pages in the buffer */
+       unsigned int page_count;
+       /* virtual (kmalloc'd) pointers to the actual data
+        * (in PAGE_SIZE chunks, used with mmap streaming) */
+       unsigned long *virtual;
+
+       /* cpu address for the VINO descriptor table
+        * (contains DMA addresses, VINO_PAGE_SIZE chunks) */
+       unsigned long *dma_cpu;
+       /* dma address for the VINO descriptor table
+        * (contains DMA addresses, VINO_PAGE_SIZE chunks) */
+       dma_addr_t dma;
+};
+
+struct vino_framebuffer {
+       /* identifier nubmer */
+       unsigned int id;
+       /* the length of the whole buffer */
+       unsigned int size;
+       /* the length of actual data in buffer */
+       unsigned int data_size;
+       /* the data format */
+       unsigned int data_format;
+       /* the state of buffer data */
+       unsigned int state;
+       /* is the buffer mapped in user space? */
+       unsigned int map_count;
+       /* memory offset for mmap() */
+       unsigned int offset;
+       /* frame counter */
+       unsigned int frame_counter;
+       /* timestamp (written when image capture finishes) */
+       struct timeval timestamp;
+
+       struct vino_descriptor_table desc_table;
+
+       spinlock_t state_lock;
+};
+
+struct vino_framebuffer_fifo {
+       unsigned int length;
+
+       unsigned int used;
+       unsigned int head;
+       unsigned int tail;
+
+       unsigned int data[VINO_FRAMEBUFFER_MAX_COUNT];
+};
+
+struct vino_framebuffer_queue {
+       unsigned int magic;
+
+       /* VINO_MEMORY_NONE, VINO_MEMORY_MMAP or VINO_MEMORY_USERPTR */
+       unsigned int type;
+       unsigned int length;
+
+       /* data field of in and out contain index numbers for buffer */
+       struct vino_framebuffer_fifo in;
+       struct vino_framebuffer_fifo out;
+
+       struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_MAX_COUNT];
 
-/* VINO ASIC registers */
-struct sgi_vino *vino;
+       spinlock_t queue_lock;
+       struct semaphore queue_sem;
+       wait_queue_head_t frame_wait_queue;
+};
+
+struct vino_channel_settings {
+       unsigned int channel;
+
+       int input;
+       unsigned int data_format;
+       unsigned int data_norm;
+       struct vino_clipping clipping;
+       unsigned int decimation;
+       unsigned int line_size;
+       unsigned int alpha;
+       unsigned int fps;
+       unsigned int framert_reg;
+
+       unsigned int fifo_threshold;
+
+       struct vino_framebuffer_queue fb_queue;
+
+       /* number of the current field */
+       unsigned int field;
+
+       /* read in progress */
+       int reading;
+       /* streaming is active */
+       int streaming;
+       /* the driver is currently processing the queue */
+       int capturing;
+
+       struct semaphore sem;
+       spinlock_t capture_lock;
 
-static const char *vinostr = "VINO IndyCam/TV";
-static int threshold_a = 512;
-static int threshold_b = 512;
+       unsigned int users;
 
-struct vino_device {
-       struct video_device vdev;
-#define VINO_CHAN_A            1
-#define VINO_CHAN_B            2
-       int chan;
+       /* V4L support */
+       struct video_device *v4l_device;
 };
 
 struct vino_client {
+       /* the channel which owns this client:
+        * VINO_NO_CHANNEL, VINO_CHANNEL_A or VINO_CHANNEL_B */
+       unsigned int owner;
        struct i2c_client *driver;
-       int owner;
 };
 
-struct vino_video {
-       struct vino_device chA;
-       struct vino_device chB;
+struct vino_settings {
+       struct vino_channel_settings a;
+       struct vino_channel_settings b;
 
        struct vino_client decoder;
        struct vino_client camera;
 
-       struct semaphore input_lock;
+       /* a lock for vino register access */
+       spinlock_t vino_lock;
+       /* a lock for channel input changes */
+       spinlock_t input_lock;
 
-       /* Loaded into VINO descriptors to clear End Of Descriptors table
-        * interupt condition */
        unsigned long dummy_page;
-       unsigned int dummy_buf[4] __attribute__((aligned(8)));
+       struct vino_descriptor_table dummy_desc_table;
+};
+
+/* Module parameters */
+
+/*
+ * Using vino_pixel_conversion the ARGB32-format pixels supplied
+ * by the VINO chip can be converted to more common formats
+ * like RGBA32 (or probably RGB24 in the future). This way we
+ * can give out data that can be specified correctly with
+ * the V4L2-definitions.
+ *
+ * The pixel format is specified as RGBA32 when no conversion
+ * is used.
+ *
+ * Note that this only affects the 32-bit bit depth.
+ *
+ * Use non-zero value to enable conversion.
+ */
+static int vino_pixel_conversion = 0;
+module_param_named(pixelconv, vino_pixel_conversion, int, 0);
+MODULE_PARM_DESC(pixelconv,
+                "enable pixel conversion (non-zero value enables)");
+
+/* Internal data structures */
+
+static struct sgi_vino *vino;
+
+static struct vino_settings *vino_drvdata;
+
+static const char *vino_driver_name = "vino";
+static const char *vino_driver_description = "SGI VINO";
+static const char *vino_bus_name = "GIO64 bus";
+static const char *vino_v4l_device_name_a = "SGI VINO Channel A";
+static const char *vino_v4l_device_name_b = "SGI VINO Channel B";
+
+static const struct vino_input vino_inputs[] = {
+       {
+               .name           = "Composite",
+               .std            = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
+       },{
+               .name           = "S-Video",
+               .std            = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
+       },{
+               .name           = "D1 (IndyCam)",
+               .std            = V4L2_STD_NTSC,
+       }
+};
+
+static const struct vino_data_format vino_data_formats[] = {
+       {
+               .description    = "8-bit greyscale",
+               .bpp            = 1,
+               .pixelformat    = V4L2_PIX_FMT_GREY,
+               .colorspace     = V4L2_COLORSPACE_SMPTE170M,
+       },{
+               .description    = "8-bit dithered RGB 3-3-2",
+               .bpp            = 1,
+               .pixelformat    = V4L2_PIX_FMT_RGB332,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
+       },{
+               .description    = "32-bit RGB",
+               .bpp            = 4,
+               .pixelformat    = V4L2_PIX_FMT_RGB32,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
+       },{
+               .description    = "YUV 4:2:2",
+               .bpp            = 4,
+               .pixelformat    = V4L2_PIX_FMT_YUYV, // XXX: swapped?
+               .colorspace     = V4L2_COLORSPACE_SMPTE170M,
+       }/*,{
+               .description    = "24-bit RGB",
+               .bpp            = 3,
+               .pixelformat    = V4L2_PIX_FMT_RGB24,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
+               }*/
+};
+
+static const struct vino_data_norm vino_data_norms[] = {
+       {
+               .description    = "NTSC",
+               .std            = V4L2_STD_NTSC,
+               .fps_min        = 6,
+               .fps_max        = 30,
+               .framelines     = 525,
+               .width          = VINO_NTSC_WIDTH,
+               .height         = VINO_NTSC_HEIGHT,
+               .odd            = {
+                       .top    = VINO_CLIPPING_START_ODD_NTSC,
+                       .left   = 0,
+                       .bottom = VINO_CLIPPING_START_ODD_NTSC
+                       + VINO_NTSC_HEIGHT / 2 - 1,
+                       .right  = VINO_NTSC_WIDTH,
+               },
+               .even           = {
+                       .top    = VINO_CLIPPING_START_EVEN_NTSC,
+                       .left   = 0,
+                       .bottom = VINO_CLIPPING_START_EVEN_NTSC
+                       + VINO_NTSC_HEIGHT / 2 - 1,
+                       .right  = VINO_NTSC_WIDTH,
+               },
+       },{
+               .description    = "PAL",
+               .std            = V4L2_STD_PAL,
+               .fps_min        = 5,
+               .fps_max        = 25,
+               .framelines     = 625,
+               .width          = VINO_PAL_WIDTH,
+               .height         = VINO_PAL_HEIGHT,
+               .odd            = {
+                       .top    = VINO_CLIPPING_START_ODD_PAL,
+                       .left   = 0,
+                       .bottom = VINO_CLIPPING_START_ODD_PAL
+                       + VINO_PAL_HEIGHT / 2 - 1,
+                       .right  = VINO_PAL_WIDTH,
+               },
+               .even           = {
+                       .top    = VINO_CLIPPING_START_EVEN_PAL,
+                       .left   = 0,
+                       .bottom = VINO_CLIPPING_START_EVEN_PAL
+                       + VINO_PAL_HEIGHT / 2 - 1,
+                       .right  = VINO_PAL_WIDTH,
+               },
+       },{
+               .description    = "SECAM",
+               .std            = V4L2_STD_SECAM,
+               .fps_min        = 5,
+               .fps_max        = 25,
+               .framelines     = 625,
+               .width          = VINO_PAL_WIDTH,
+               .height         = VINO_PAL_HEIGHT,
+               .odd            = {
+                       .top    = VINO_CLIPPING_START_ODD_PAL,
+                       .left   = 0,
+                       .bottom = VINO_CLIPPING_START_ODD_PAL
+                       + VINO_PAL_HEIGHT / 2 - 1,
+                       .right  = VINO_PAL_WIDTH,
+               },
+               .even           = {
+                       .top    = VINO_CLIPPING_START_EVEN_PAL,
+                       .left   = 0,
+                       .bottom = VINO_CLIPPING_START_EVEN_PAL
+                       + VINO_PAL_HEIGHT / 2 - 1,
+                       .right  = VINO_PAL_WIDTH,
+               },
+       },{
+               .description    = "NTSC (D1 input)",
+               .std            = V4L2_STD_NTSC,
+               .fps_min        = 6,
+               .fps_max        = 30,
+               .framelines     = 525,
+               .width          = VINO_NTSC_WIDTH,
+               .height         = VINO_NTSC_HEIGHT,
+               .odd            = {
+                       .top    = VINO_CLIPPING_START_ODD_D1,
+                       .left   = 0,
+                       .bottom = VINO_CLIPPING_START_ODD_D1
+                       + VINO_NTSC_HEIGHT / 2 - 1,
+                       .right  = VINO_NTSC_WIDTH,
+               },
+               .even           = {
+                       .top    = VINO_CLIPPING_START_EVEN_D1,
+                       .left   = 0,
+                       .bottom = VINO_CLIPPING_START_EVEN_D1
+                       + VINO_NTSC_HEIGHT / 2 - 1,
+                       .right  = VINO_NTSC_WIDTH,
+               },
+       }
+};
+
+#define VINO_INDYCAM_V4L2_CONTROL_COUNT                9
+
+struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
+       {
+               .id = V4L2_CID_AUTOGAIN,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "Automatic Gain Control",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = INDYCAM_AGC_DEFAULT,
+               .flags = 0,
+               .reserved = { 0, 0 },
+       },{
+               .id = V4L2_CID_AUTO_WHITE_BALANCE,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "Automatic White Balance",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = INDYCAM_AWB_DEFAULT,
+               .flags = 0,
+               .reserved = { 0, 0 },
+       },{
+               .id = V4L2_CID_GAIN,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Gain",
+               .minimum = INDYCAM_GAIN_MIN,
+               .maximum = INDYCAM_GAIN_MAX,
+               .step = 1,
+               .default_value = INDYCAM_GAIN_DEFAULT,
+               .flags = 0,
+               .reserved = { 0, 0 },
+       },{
+               .id = V4L2_CID_PRIVATE_BASE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Red Saturation",
+               .minimum = INDYCAM_RED_SATURATION_MIN,
+               .maximum = INDYCAM_RED_SATURATION_MAX,
+               .step = 1,
+               .default_value = INDYCAM_RED_SATURATION_DEFAULT,
+               .flags = 0,
+               .reserved = { 0, 0 },
+       },{
+               .id = V4L2_CID_PRIVATE_BASE + 1,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Blue Saturation",
+               .minimum = INDYCAM_BLUE_SATURATION_MIN,
+               .maximum = INDYCAM_BLUE_SATURATION_MAX,
+               .step = 1,
+               .default_value = INDYCAM_BLUE_SATURATION_DEFAULT,
+               .flags = 0,
+               .reserved = { 0, 0 },
+       },{
+               .id = V4L2_CID_RED_BALANCE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Red Balance",
+               .minimum = INDYCAM_RED_BALANCE_MIN,
+               .maximum = INDYCAM_RED_BALANCE_MAX,
+               .step = 1,
+               .default_value = INDYCAM_RED_BALANCE_DEFAULT,
+               .flags = 0,
+               .reserved = { 0, 0 },
+       },{
+               .id = V4L2_CID_BLUE_BALANCE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Blue Balance",
+               .minimum = INDYCAM_BLUE_BALANCE_MIN,
+               .maximum = INDYCAM_BLUE_BALANCE_MAX,
+               .step = 1,
+               .default_value = INDYCAM_BLUE_BALANCE_DEFAULT,
+               .flags = 0,
+               .reserved = { 0, 0 },
+       },{
+               .id = V4L2_CID_EXPOSURE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Shutter Control",
+               .minimum = INDYCAM_SHUTTER_MIN,
+               .maximum = INDYCAM_SHUTTER_MAX,
+               .step = 1,
+               .default_value = INDYCAM_SHUTTER_DEFAULT,
+               .flags = 0,
+               .reserved = { 0, 0 },
+       },{
+               .id = V4L2_CID_GAMMA,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Gamma",
+               .minimum = INDYCAM_GAMMA_MIN,
+               .maximum = INDYCAM_GAMMA_MAX,
+               .step = 1,
+               .default_value = INDYCAM_GAMMA_DEFAULT,
+               .flags = 0,
+               .reserved = { 0, 0 },
+       }
+};
+
+#define VINO_SAA7191_V4L2_CONTROL_COUNT                2
+
+struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = {
+       {
+               .id = V4L2_CID_HUE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Hue",
+               .minimum = SAA7191_HUE_MIN,
+               .maximum = SAA7191_HUE_MAX,
+               .step = 1,
+               .default_value = SAA7191_HUE_DEFAULT,
+               .flags = 0,
+               .reserved = { 0, 0 },
+       },{
+               .id = V4L2_CID_PRIVATE_BASE,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "VTR Time Constant",
+               .minimum = SAA7191_VTRC_MIN,
+               .maximum = SAA7191_VTRC_MAX,
+               .step = 1,
+               .default_value = SAA7191_VTRC_DEFAULT,
+               .flags = 0,
+               .reserved = { 0, 0 },
+       }
 };
 
-static struct vino_video *Vino;
+/* VINO I2C bus functions */
 
 unsigned i2c_vino_getctrl(void *data)
 {
@@ -112,49 +638,49 @@ static struct i2c_algo_sgi_data i2c_sgi_vino_data =
  */
 static int i2c_vino_client_reg(struct i2c_client *client)
 {
-       int res = 0;
+       int ret = 0;
 
-       down(&Vino->input_lock);
+       spin_lock(&vino_drvdata->input_lock);
        switch (client->driver->id) {
        case I2C_DRIVERID_SAA7191:
-               if (Vino->decoder.driver)
-                       res = -EBUSY;
+               if (vino_drvdata->decoder.driver)
+                       ret = -EBUSY;
                else
-                       Vino->decoder.driver = client;
+                       vino_drvdata->decoder.driver = client;
                break;
        case I2C_DRIVERID_INDYCAM:
-               if (Vino->camera.driver)
-                       res = -EBUSY;
+               if (vino_drvdata->camera.driver)
+                       ret = -EBUSY;
                else
-                       Vino->camera.driver = client;
+                       vino_drvdata->camera.driver = client;
                break;
        default:
-               res = -ENODEV;
+               ret = -ENODEV;
        }
-       up(&Vino->input_lock);
+       spin_unlock(&vino_drvdata->input_lock);
 
-       return res;
+       return ret;
 }
 
 static int i2c_vino_client_unreg(struct i2c_client *client)
 {
-       int res = 0;
+       int ret = 0;
 
-       down(&Vino->input_lock);
-       if (client == Vino->decoder.driver) {
-               if (Vino->decoder.owner)
-                       res = -EBUSY;
+       spin_lock(&vino_drvdata->input_lock);
+       if (client == vino_drvdata->decoder.driver) {
+               if (vino_drvdata->decoder.owner != VINO_NO_CHANNEL)
+                       ret = -EBUSY;
                else
-                       Vino->decoder.driver = NULL;
-       } else if (client == Vino->camera.driver) {
-               if (Vino->camera.owner)
-                       res = -EBUSY;
+                       vino_drvdata->decoder.driver = NULL;
+       } else if (client == vino_drvdata->camera.driver) {
+               if (vino_drvdata->camera.owner != VINO_NO_CHANNEL)
+                       ret = -EBUSY;
                else
-                       Vino->camera.driver = NULL;
+                       vino_drvdata->camera.driver = NULL;
        }
-       up(&Vino->input_lock);
+       spin_unlock(&vino_drvdata->input_lock);
 
-       return res;
+       return ret;
 }
 
 static struct i2c_adapter vino_i2c_adapter =
@@ -176,172 +702,3591 @@ static int vino_i2c_del_bus(void)
        return i2c_sgi_del_bus(&vino_i2c_adapter);
 }
 
+static int i2c_camera_command(unsigned int cmd, void *arg)
+{
+       return vino_drvdata->camera.driver->
+               driver->command(vino_drvdata->camera.driver,
+                               cmd, arg);
+}
 
-static void vino_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static int i2c_decoder_command(unsigned int cmd, void *arg)
 {
+       return vino_drvdata->decoder.driver->
+               driver->command(vino_drvdata->decoder.driver,
+                               cmd, arg);
 }
 
-static int vino_open(struct video_device *dev, int flags)
+/* VINO framebuffer/DMA descriptor management */
+
+static void vino_free_buffer_with_count(struct vino_framebuffer *fb,
+                                              unsigned int count)
 {
-       struct vino_device *videv = (struct vino_device *)dev;
+       unsigned int i;
 
-       return 0;
+       dprintk("vino_free_buffer_with_count(): count = %d\n", count);
+
+       for (i = 0; i < count; i++) {
+               mem_map_unreserve(virt_to_page(fb->desc_table.virtual[i]));
+               dma_unmap_single(NULL,
+                                fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
+                                PAGE_SIZE, DMA_FROM_DEVICE);
+               free_page(fb->desc_table.virtual[i]);
+       }
+
+       dma_free_coherent(NULL,
+                         VINO_PAGE_RATIO * (fb->desc_table.page_count + 4) *
+                         sizeof(dma_addr_t), (void *)fb->desc_table.dma_cpu,
+                         fb->desc_table.dma);
+       kfree(fb->desc_table.virtual);
+
+       memset(fb, 0, sizeof(struct vino_framebuffer));
+}
+
+static void vino_free_buffer(struct vino_framebuffer *fb)
+{
+       vino_free_buffer_with_count(fb, fb->desc_table.page_count);
 }
 
-static void vino_close(struct video_device *dev)
+static int vino_allocate_buffer(struct vino_framebuffer *fb,
+                               unsigned int size)
 {
-       struct vino_device *videv = (struct vino_device *)dev;
+       unsigned int count, i, j;
+       int ret = 0;
+
+       dprintk("vino_allocate_buffer():\n");
+
+       if (size < 1)
+               return -EINVAL;
+
+       memset(fb, 0, sizeof(struct vino_framebuffer));
+
+       count = ((size / PAGE_SIZE) + 4) & ~3;
+
+       dprintk("vino_allocate_buffer(): size = %d, count = %d\n",
+               size, count);
+
+       /* allocate memory for table with virtual (page) addresses */
+       fb->desc_table.virtual = (unsigned long *)
+               kmalloc(count * sizeof(unsigned long), GFP_KERNEL);
+       if (!fb->desc_table.virtual)
+               return -ENOMEM;
+
+       /* allocate memory for table with dma addresses
+        * (has space for four extra descriptors) */
+       fb->desc_table.dma_cpu =
+               dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) *
+                                  sizeof(dma_addr_t), &fb->desc_table.dma,
+                                  GFP_KERNEL | GFP_DMA);
+       if (!fb->desc_table.dma_cpu) {
+               ret = -ENOMEM;
+               goto out_free_virtual;
+       }
+
+       /* allocate pages for the buffer and acquire the according
+        * dma addresses */
+       for (i = 0; i < count; i++) {
+               dma_addr_t dma_data_addr;
+
+               fb->desc_table.virtual[i] =
+                       get_zeroed_page(GFP_KERNEL | GFP_DMA);
+               if (!fb->desc_table.virtual[i]) {
+                       ret = -ENOBUFS;
+                       break;
+               }
+
+               dma_data_addr =
+                       dma_map_single(NULL,
+                                      (void *)fb->desc_table.virtual[i],
+                                      PAGE_SIZE, DMA_FROM_DEVICE);
+
+               for (j = 0; j < VINO_PAGE_RATIO; j++) {
+                       fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] =
+                               dma_data_addr + VINO_PAGE_SIZE * j;
+               }
+
+               mem_map_reserve(virt_to_page(fb->desc_table.virtual[i]));
+       }
+
+       /* page_count needs to be set anyway, because the descriptor table has
+        * been allocated according to this number */
+       fb->desc_table.page_count = count;
+
+       if (ret) {
+               /* the descriptor with index i doesn't contain
+                * a valid address yet */
+               vino_free_buffer_with_count(fb, i);
+               return ret;
+       }
+
+       //fb->size = size;
+       fb->size = count * PAGE_SIZE;
+       fb->data_format = VINO_DATA_FMT_NONE;
+
+       /* set the dma stop-bit for the last (count+1)th descriptor */
+       fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP;
+       return 0;
+
+ out_free_virtual:
+       kfree(fb->desc_table.virtual);
+       return ret;
 }
 
-static int vino_mmap(struct video_device *dev, const char *adr,
-                    unsigned long size)
+#if 0
+/* user buffers not fully implemented yet */
+static int vino_prepare_user_buffer(struct vino_framebuffer *fb,
+                                    void *user,
+                                    unsigned int size)
 {
-       struct vino_device *videv = (struct vino_device *)dev;
+       unsigned int count, i, j;
+       int ret = 0;
+
+       dprintk("vino_prepare_user_buffer():\n");
+
+       if (size < 1)
+               return -EINVAL;
+
+       memset(fb, 0, sizeof(struct vino_framebuffer));
+
+       count = ((size / PAGE_SIZE)) & ~3;
+
+       dprintk("vino_prepare_user_buffer(): size = %d, count = %d\n",
+               size, count);
+
+       /* allocate memory for table with virtual (page) addresses */
+       fb->desc_table.virtual = (unsigned long *)
+               kmalloc(count * sizeof(unsigned long), GFP_KERNEL);
+       if (!fb->desc_table.virtual)
+               return -ENOMEM;
+
+       /* allocate memory for table with dma addresses
+        * (has space for four extra descriptors) */
+       fb->desc_table.dma_cpu =
+               dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) *
+                                  sizeof(dma_addr_t), &fb->desc_table.dma,
+                                  GFP_KERNEL | GFP_DMA);
+       if (!fb->desc_table.dma_cpu) {
+               ret = -ENOMEM;
+               goto out_free_virtual;
+       }
+
+       /* allocate pages for the buffer and acquire the according
+        * dma addresses */
+       for (i = 0; i < count; i++) {
+               dma_addr_t dma_data_addr;
+
+               fb->desc_table.virtual[i] =
+                       get_zeroed_page(GFP_KERNEL | GFP_DMA);
+               if (!fb->desc_table.virtual[i]) {
+                       ret = -ENOBUFS;
+                       break;
+               }
+
+               dma_data_addr =
+                       dma_map_single(NULL,
+                                      (void *)fb->desc_table.virtual[i],
+                                      PAGE_SIZE, DMA_FROM_DEVICE);
+
+               for (j = 0; j < VINO_PAGE_RATIO; j++) {
+                       fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] =
+                               dma_data_addr + VINO_PAGE_SIZE * j;
+               }
+
+               mem_map_reserve(virt_to_page(fb->desc_table.virtual[i]));
+       }
 
-       return -EINVAL;
+       /* page_count needs to be set anyway, because the descriptor table has
+        * been allocated according to this number */
+       fb->desc_table.page_count = count;
+
+       if (ret) {
+               /* the descriptor with index i doesn't contain
+                * a valid address yet */
+               vino_free_buffer_with_count(fb, i);
+               return ret;
+       }
+
+       //fb->size = size;
+       fb->size = count * PAGE_SIZE;
+
+       /* set the dma stop-bit for the last (count+1)th descriptor */
+       fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP;
+       return 0;
+
+ out_free_virtual:
+       kfree(fb->desc_table.virtual);
+       return ret;
 }
+#endif
 
-static int vino_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+static void vino_sync_buffer(struct vino_framebuffer *fb)
 {
-       struct vino_device *videv = (struct vino_device *)dev;
+       int i;
+
+       dprintk("vino_sync_buffer():\n");
 
-       return -EINVAL;
+       for (i = 0; i < fb->desc_table.page_count; i++)
+               dma_sync_single(NULL,
+                               fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
+                               PAGE_SIZE, DMA_FROM_DEVICE);
 }
 
-static const struct video_device vino_device = {
-       .owner          = THIS_MODULE,
-       .type           = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE,
-       .hardware       = VID_HARDWARE_VINO,
-       .name           = "VINO",
-       .open           = vino_open,
-       .close          = vino_close,
-       .ioctl          = vino_ioctl,
-       .mmap           = vino_mmap,
-};
+/* Framebuffer fifo functions (need to be locked externally) */
 
-static int __init vino_init(void)
+static void vino_fifo_init(struct vino_framebuffer_fifo *f,
+                          unsigned int length)
 {
-       unsigned long rev;
-       int i, ret = 0;
+       f->length = 0;
+       f->used = 0;
+       f->head = 0;
+       f->tail = 0;
 
-       /* VINO is Indy specific beast */
-       if (ip22_is_fullhouse())
-               return -ENODEV;
+       if (length > VINO_FRAMEBUFFER_MAX_COUNT)
+               length = VINO_FRAMEBUFFER_MAX_COUNT;
 
-       /*
-        * VINO is in the EISA address space, so the sysid register will tell
-        * us if the EISA_PRESENT pin on MC has been pulled low.
-        *
-        * If EISA_PRESENT is not set we definitely don't have a VINO equiped
-        * system.
-        */
-       if (!(sgimc->systemid & SGIMC_SYSID_EPRESENT)) {
-               printk(KERN_ERR "VINO not found\n");
-               return -ENODEV;
+       f->length = length;
+}
+
+/* returns true/false */
+static int vino_fifo_has_id(struct vino_framebuffer_fifo *f, unsigned int id)
+{
+       unsigned int i;
+       for (i = f->head; i == (f->tail - 1); i = (i + 1) % f->length) {
+               if (f->data[i] == id)
+                       return 1;
        }
 
-       vino = (struct sgi_vino *)ioremap(VINO_BASE, sizeof(struct sgi_vino));
-       if (!vino)
-               return -EIO;
+       return 0;
+}
 
-       /* Okay, once we know that VINO is present we'll read its revision
-        * safe way. One never knows... */
-       if (get_dbe(rev, &(vino->rev_id))) {
-               printk(KERN_ERR "VINO: failed to read revision register\n");
-               ret = -ENODEV;
-               goto out_unmap;
+/* returns true/false */
+static int vino_fifo_full(struct vino_framebuffer_fifo *f)
+{
+       return (f->used == f->length);
+}
+
+static unsigned int vino_fifo_get_used(struct vino_framebuffer_fifo *f)
+{
+       return f->used;
+}
+
+static int vino_fifo_enqueue(struct vino_framebuffer_fifo *f, unsigned int id)
+{
+       if (id >= f->length) {
+               return VINO_QUEUE_ERROR;
        }
-       if (VINO_ID_VALUE(rev) != VINO_CHIP_ID) {
-               printk(KERN_ERR "VINO is not VINO (Rev/ID: 0x%04lx)\n", rev);
-               ret = -ENODEV;
-               goto out_unmap;
+
+       if (vino_fifo_has_id(f, id)) {
+               return VINO_QUEUE_ERROR;
        }
-       printk(KERN_INFO "VINO Rev: 0x%02lx\n", VINO_REV_NUM(rev));
 
-       Vino = (struct vino_video *)
-               kmalloc(sizeof(struct vino_video), GFP_KERNEL);
-       if (!Vino) {
-               ret = -ENOMEM;
-               goto out_unmap;
+       if (f->used < f->length) {
+               f->data[f->tail] = id;
+               f->tail = (f->tail + 1) % f->length;
+               f->used++;
+       } else {
+               return VINO_QUEUE_ERROR;
        }
 
-       Vino->dummy_page = get_zeroed_page(GFP_KERNEL | GFP_DMA);
-       if (!Vino->dummy_page) {
-               ret = -ENOMEM;
-               goto out_free_vino;
+       return 0;
+}
+
+static int vino_fifo_peek(struct vino_framebuffer_fifo *f, unsigned int *id)
+{
+       if (f->used > 0) {
+               *id = f->data[f->head];
+       } else {
+               return VINO_QUEUE_ERROR;
        }
-       for (i = 0; i < 4; i++)
-               Vino->dummy_buf[i] = PHYSADDR(Vino->dummy_page);
 
-       vino->control = 0;
-       /* prevent VINO from throwing spurious interrupts */
-       vino->a.next_4_desc = PHYSADDR(Vino->dummy_buf);
-       vino->b.next_4_desc = PHYSADDR(Vino->dummy_buf);
-       udelay(5);
-       vino->intr_status = 0;
-        /* set threshold level */
-        vino->a.fifo_thres = threshold_a;
-       vino->b.fifo_thres = threshold_b;
+       return 0;
+}
+
+static int vino_fifo_dequeue(struct vino_framebuffer_fifo *f, unsigned int *id)
+{
+       if (f->used > 0) {
+               *id = f->data[f->head];
+               f->head = (f->head + 1) % f->length;
+               f->used--;
+       } else {
+               return VINO_QUEUE_ERROR;
+       }
+
+       return 0;
+}
 
-       init_MUTEX(&Vino->input_lock);
+/* Framebuffer queue functions */
 
-       if (request_irq(SGI_VINO_IRQ, vino_interrupt, 0, vinostr, NULL)) {
-               printk(KERN_ERR "VINO: irq%02d registration failed\n",
-                      SGI_VINO_IRQ);
-               ret = -EAGAIN;
-               goto out_free_page;
+/* execute with queue_lock locked */
+static void vino_queue_free_with_count(struct vino_framebuffer_queue *q,
+                                      unsigned int length)
+{
+       unsigned int i;
+
+       q->length = 0;
+       memset(&q->in, 0, sizeof(struct vino_framebuffer_fifo));
+       memset(&q->out, 0, sizeof(struct vino_framebuffer_fifo));
+       for (i = 0; i < length; i++) {
+               dprintk("vino_queue_free_with_count(): freeing buffer %d\n",
+                       i);
+               vino_free_buffer(q->buffer[i]);
+               kfree(q->buffer[i]);
        }
 
-       ret = vino_i2c_add_bus();
-       if (ret) {
-               printk(KERN_ERR "VINO: I2C bus registration failed\n");
-               goto out_free_irq;
+       q->type = VINO_MEMORY_NONE;
+       q->magic = 0;
+}
+
+static void vino_queue_free(struct vino_framebuffer_queue *q)
+{
+       dprintk("vino_queue_free():\n");
+
+       if (q->magic != VINO_QUEUE_MAGIC)
+               return;
+       if (q->type != VINO_MEMORY_MMAP)
+               return;
+
+       down(&q->queue_sem);
+
+       vino_queue_free_with_count(q, q->length);
+
+       up(&q->queue_sem);
+}
+
+static int vino_queue_init(struct vino_framebuffer_queue *q,
+                          unsigned int *length)
+{
+       unsigned int i;
+       int ret = 0;
+
+       dprintk("vino_queue_init(): length = %d\n", *length);
+
+       if (q->magic == VINO_QUEUE_MAGIC) {
+               dprintk("vino_queue_init(): queue already initialized!\n");
+               return -EINVAL;
        }
 
-       if (video_register_device(&Vino->chA.vdev, VFL_TYPE_GRABBER, -1) < 0) {
-               printk("%s, chnl %d: device registration failed.\n",
-                       Vino->chA.vdev.name, Vino->chA.chan);
-               ret = -EINVAL;
-               goto out_i2c_del_bus;
+       if (q->type != VINO_MEMORY_NONE) {
+               dprintk("vino_queue_init(): queue already initialized!\n");
+               return -EINVAL;
        }
-       if (video_register_device(&Vino->chB.vdev, VFL_TYPE_GRABBER, -1) < 0) {
-               printk("%s, chnl %d: device registration failed.\n",
-                       Vino->chB.vdev.name, Vino->chB.chan);
-               ret = -EINVAL;
-               goto out_unregister_vdev;
+
+       if (*length < 1)
+               return -EINVAL;
+
+       down(&q->queue_sem);
+
+       if (*length > VINO_FRAMEBUFFER_MAX_COUNT)
+               *length = VINO_FRAMEBUFFER_MAX_COUNT;
+
+       q->length = 0;
+
+       for (i = 0; i < *length; i++) {
+               dprintk("vino_queue_init(): allocating buffer %d\n", i);
+               q->buffer[i] = kmalloc(sizeof(struct vino_framebuffer),
+                                      GFP_KERNEL);
+               if (!q->buffer[i]) {
+                       dprintk("vino_queue_init(): kmalloc() failed\n");
+                       ret = -ENOMEM;
+                       break;
+               }
+
+               ret = vino_allocate_buffer(q->buffer[i],
+                                          VINO_FRAMEBUFFER_SIZE);
+               if (ret) {
+                       kfree(q->buffer[i]);
+                       dprintk("vino_queue_init(): "
+                               "vino_allocate_buffer() failed\n");
+                       break;
+               }
+
+               q->buffer[i]->id = i;
+               if (i > 0) {
+                       q->buffer[i]->offset = q->buffer[i - 1]->offset +
+                               q->buffer[i - 1]->size;
+               } else {
+                       q->buffer[i]->offset = 0;
+               }
+
+               spin_lock_init(&q->buffer[i]->state_lock);
+
+               dprintk("vino_queue_init(): buffer = %d, offset = %d, "
+                       "size = %d\n", i, q->buffer[i]->offset,
+                       q->buffer[i]->size);
        }
 
-       return 0;
+       if (ret) {
+               vino_queue_free_with_count(q, i);
+               *length = 0;
+       } else {
+               q->length = *length;
+               vino_fifo_init(&q->in, q->length);
+               vino_fifo_init(&q->out, q->length);
+               q->type = VINO_MEMORY_MMAP;
+               q->magic = VINO_QUEUE_MAGIC;
+       }
 
-out_unregister_vdev:
-       video_unregister_device(&Vino->chA.vdev);
-out_i2c_del_bus:
-       vino_i2c_del_bus();
-out_free_irq:
-       free_irq(SGI_VINO_IRQ, NULL);
-out_free_page:
-       free_page(Vino->dummy_page);
-out_free_vino:
-       kfree(Vino);
-out_unmap:
-       iounmap(vino);
+       up(&q->queue_sem);
 
        return ret;
 }
 
-static void __exit vino_exit(void)
+static struct vino_framebuffer *vino_queue_add(struct
+                                              vino_framebuffer_queue *q,
+                                              unsigned int id)
 {
-       video_unregister_device(&Vino->chA.vdev);
-       video_unregister_device(&Vino->chB.vdev);
-       vino_i2c_del_bus();
-       free_irq(SGI_VINO_IRQ, NULL);
-       free_page(Vino->dummy_page);
-       kfree(Vino);
-       iounmap(vino);
+       struct vino_framebuffer *ret = NULL;
+       unsigned int total;
+       unsigned long flags;
+
+       dprintk("vino_queue_add(): id = %d\n", id);
+
+       if (q->magic != VINO_QUEUE_MAGIC) {
+               return ret;
+       }
+
+       spin_lock_irqsave(&q->queue_lock, flags);
+
+       if (q->length == 0)
+               goto out;
+
+       if (id >= q->length)
+               goto out;
+
+       /* not needed?: if (vino_fifo_full(&q->out)) {
+               goto out;
+               }*/
+       /* check that outgoing queue isn't already full
+        * (or that it won't become full) */
+       total = vino_fifo_get_used(&q->in) +
+               vino_fifo_get_used(&q->out);
+       if (total >= q->length)
+               goto out;
+
+       if (vino_fifo_enqueue(&q->in, id))
+               goto out;
+
+       ret = q->buffer[id];
+
+out:
+       spin_unlock_irqrestore(&q->queue_lock, flags);
+
+       return ret;
 }
 
-module_init(vino_init);
-module_exit(vino_exit);
+static struct vino_framebuffer *vino_queue_transfer(struct
+                                                   vino_framebuffer_queue *q)
+{
+       struct vino_framebuffer *ret = NULL;
+       struct vino_framebuffer *fb;
+       int id;
+       unsigned long flags;
 
-MODULE_DESCRIPTION("Video4Linux driver for SGI Indy VINO (IndyCam)");
-MODULE_LICENSE("GPL");
+       dprintk("vino_queue_transfer():\n");
+
+       if (q->magic != VINO_QUEUE_MAGIC) {
+               return ret;
+       }
+
+       spin_lock_irqsave(&q->queue_lock, flags);
+
+       if (q->length == 0)
+               goto out;
+
+       // now this actually removes an entry from the incoming queue
+       if (vino_fifo_dequeue(&q->in, &id)) {
+               goto out;
+       }
+
+       dprintk("vino_queue_transfer(): id = %d\n", id);
+       fb = q->buffer[id];
+
+       // we have already checked that the outgoing queue is not full, but...
+       if (vino_fifo_enqueue(&q->out, id)) {
+               printk(KERN_ERR "vino_queue_transfer(): "
+                      "outgoing queue is full, this shouldn't happen!\n");
+               goto out;
+       }
+
+       ret = fb;
+out:
+       spin_unlock_irqrestore(&q->queue_lock, flags);
+
+       return ret;
+}
+
+/* returns true/false */
+static int vino_queue_incoming_contains(struct vino_framebuffer_queue *q,
+                                       unsigned int id)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       if (q->magic != VINO_QUEUE_MAGIC) {
+               return ret;
+       }
+
+       spin_lock_irqsave(&q->queue_lock, flags);
+
+       if (q->length == 0)
+               goto out;
+
+       ret = vino_fifo_has_id(&q->in, id);
+
+out:
+       spin_unlock_irqrestore(&q->queue_lock, flags);
+
+       return ret;
+}
+
+/* returns true/false */
+static int vino_queue_outgoing_contains(struct vino_framebuffer_queue *q,
+                                       unsigned int id)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       if (q->magic != VINO_QUEUE_MAGIC) {
+               return ret;
+       }
+
+       spin_lock_irqsave(&q->queue_lock, flags);
+
+       if (q->length == 0)
+               goto out;
+
+       ret = vino_fifo_has_id(&q->out, id);
+
+out:
+       spin_unlock_irqrestore(&q->queue_lock, flags);
+
+       return ret;
+}
+
+static int vino_queue_get_incoming(struct vino_framebuffer_queue *q,
+                                  unsigned int *used)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       if (q->magic != VINO_QUEUE_MAGIC) {
+               return VINO_QUEUE_ERROR;
+       }
+
+       spin_lock_irqsave(&q->queue_lock, flags);
+
+       if (q->length == 0) {
+               ret = VINO_QUEUE_ERROR;
+               goto out;
+       }
+
+       *used = vino_fifo_get_used(&q->in);
+
+out:
+       spin_unlock_irqrestore(&q->queue_lock, flags);
+
+       return ret;
+}
+
+static int vino_queue_get_outgoing(struct vino_framebuffer_queue *q,
+                                  unsigned int *used)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       if (q->magic != VINO_QUEUE_MAGIC) {
+               return VINO_QUEUE_ERROR;
+       }
+
+       spin_lock_irqsave(&q->queue_lock, flags);
+
+       if (q->length == 0) {
+               ret = VINO_QUEUE_ERROR;
+               goto out;
+       }
+
+       *used = vino_fifo_get_used(&q->out);
+
+out:
+       spin_unlock_irqrestore(&q->queue_lock, flags);
+
+       return ret;
+}
+
+static int vino_queue_get_total(struct vino_framebuffer_queue *q,
+                               unsigned int *total)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       if (q->magic != VINO_QUEUE_MAGIC) {
+               return VINO_QUEUE_ERROR;
+       }
+
+       spin_lock_irqsave(&q->queue_lock, flags);
+
+       if (q->length == 0) {
+               ret = VINO_QUEUE_ERROR;
+               goto out;
+       }
+
+       *total = vino_fifo_get_used(&q->in) +
+               vino_fifo_get_used(&q->out);
+
+out:
+       spin_unlock_irqrestore(&q->queue_lock, flags);
+
+       return ret;
+}
+
+static struct vino_framebuffer *vino_queue_peek(struct
+                                               vino_framebuffer_queue *q,
+                                               unsigned int *id)
+{
+       struct vino_framebuffer *ret = NULL;
+       unsigned long flags;
+
+       if (q->magic != VINO_QUEUE_MAGIC) {
+               return ret;
+       }
+
+       spin_lock_irqsave(&q->queue_lock, flags);
+
+       if (q->length == 0)
+               goto out;
+
+       if (vino_fifo_peek(&q->in, id)) {
+               goto out;
+       }
+
+       ret = q->buffer[*id];
+out:
+       spin_unlock_irqrestore(&q->queue_lock, flags);
+
+       return ret;
+}
+
+static struct vino_framebuffer *vino_queue_remove(struct
+                                                 vino_framebuffer_queue *q,
+                                                 unsigned int *id)
+{
+       struct vino_framebuffer *ret = NULL;
+       unsigned long flags;
+       dprintk("vino_queue_remove():\n");
+
+       if (q->magic != VINO_QUEUE_MAGIC) {
+               return ret;
+       }
+
+       spin_lock_irqsave(&q->queue_lock, flags);
+
+       if (q->length == 0)
+               goto out;
+
+       if (vino_fifo_dequeue(&q->out, id)) {
+               goto out;
+       }
+
+       dprintk("vino_queue_remove(): id = %d\n", *id);
+       ret = q->buffer[*id];
+out:
+       spin_unlock_irqrestore(&q->queue_lock, flags);
+
+       return ret;
+}
+
+static struct
+vino_framebuffer *vino_queue_get_buffer(struct vino_framebuffer_queue *q,
+                                       unsigned int id)
+{
+       struct vino_framebuffer *ret = NULL;
+       unsigned long flags;
+
+       if (q->magic != VINO_QUEUE_MAGIC) {
+               return ret;
+       }
+
+       spin_lock_irqsave(&q->queue_lock, flags);
+
+       if (q->length == 0)
+               goto out;
+
+       if (id >= q->length)
+               goto out;
+
+       ret = q->buffer[id];
+ out:
+       spin_unlock_irqrestore(&q->queue_lock, flags);
+
+       return ret;
+}
+
+static unsigned int vino_queue_get_length(struct vino_framebuffer_queue *q)
+{
+       unsigned int length = 0;
+       unsigned long flags;
+
+       if (q->magic != VINO_QUEUE_MAGIC) {
+               return length;
+       }
+
+       spin_lock_irqsave(&q->queue_lock, flags);
+       length = q->length;
+       spin_unlock_irqrestore(&q->queue_lock, flags);
+
+       return length;
+}
+
+static int vino_queue_has_mapped_buffers(struct vino_framebuffer_queue *q)
+{
+       unsigned int i;
+       int ret = 0;
+       unsigned long flags;
+
+       if (q->magic != VINO_QUEUE_MAGIC) {
+               return ret;
+       }
+
+       spin_lock_irqsave(&q->queue_lock, flags);
+       for (i = 0; i < q->length; i++) {
+               if (q->buffer[i]->map_count > 0) {
+                       ret = 1;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&q->queue_lock, flags);
+
+       return ret;
+}
+
+/* VINO functions */
+
+/* execute with input_lock locked */
+static void vino_update_line_size(struct vino_channel_settings *vcs)
+{
+       unsigned int w = vcs->clipping.right - vcs->clipping.left;
+       unsigned int d = vcs->decimation;
+       unsigned int bpp = vino_data_formats[vcs->data_format].bpp;
+        unsigned int lsize;
+
+       dprintk("update_line_size(): before: w = %d, d = %d, "
+               "line_size = %d\n", w, d, vcs->line_size);
+        /* line size must be multiple of 8 bytes */
+       lsize = (bpp * (w / d)) & ~7;
+       w = (lsize / bpp) * d;
+
+       vcs->clipping.right = vcs->clipping.left + w;
+       vcs->line_size = lsize;
+       dprintk("update_line_size(): after: w = %d, d = %d, "
+               "line_size = %d\n", w, d, vcs->line_size);
+}
+
+/* execute with input_lock locked */
+static void vino_set_clipping(struct vino_channel_settings *vcs,
+                             unsigned int x, unsigned int y,
+                             unsigned int w, unsigned int h)
+{
+       unsigned int maxwidth, maxheight;
+       unsigned int d;
+
+       maxwidth = vino_data_norms[vcs->data_norm].width;
+       maxheight = vino_data_norms[vcs->data_norm].height;
+       d = vcs->decimation;
+
+       y &= ~1;        /* odd/even fields */
+
+       if (x > maxwidth) {
+               x = 0;
+       }
+       if (y > maxheight) {
+               y = 0;
+       }
+
+       if (((w / d) < VINO_MIN_WIDTH)
+           || ((h / d) < VINO_MIN_HEIGHT)) {
+               w = VINO_MIN_WIDTH * d;
+               h = VINO_MIN_HEIGHT * d;
+       }
+
+       if ((x + w) > maxwidth) {
+               w = maxwidth - x;
+               if ((w / d) < VINO_MIN_WIDTH)
+                       x = maxwidth - VINO_MIN_WIDTH * d;
+       }
+       if ((y + h) > maxheight) {
+               h = maxheight - y;
+               if ((h / d) < VINO_MIN_HEIGHT)
+                       y = maxheight - VINO_MIN_HEIGHT * d;
+       }
+
+       vcs->clipping.left = x;
+       vcs->clipping.top = y;
+       vcs->clipping.right = x + w;
+       vcs->clipping.bottom = y + h;
+
+       vino_update_line_size(vcs);
+
+       dprintk("clipping %d, %d, %d, %d / %d - %d\n",
+               vcs->clipping.left, vcs->clipping.top, vcs->clipping.right,
+               vcs->clipping.bottom, vcs->decimation, vcs->line_size);
+}
+
+/* execute with input_lock locked */
+static void vino_set_default_clipping(struct vino_channel_settings *vcs)
+{
+       vino_set_clipping(vcs, 0, 0, vino_data_norms[vcs->data_norm].width,
+                         vino_data_norms[vcs->data_norm].height);
+}
+
+/* execute with input_lock locked */
+static void vino_set_scaling(struct vino_channel_settings *vcs,
+                            unsigned int w, unsigned int h)
+{
+       unsigned int x, y, curw, curh, d;
+
+       x = vcs->clipping.left;
+       y = vcs->clipping.top;
+       curw = vcs->clipping.right - vcs->clipping.left;
+       curh = vcs->clipping.bottom - vcs->clipping.top;
+
+       d = max(curw / w, curh / h);
+
+       dprintk("scaling w: %d, h: %d, curw: %d, curh: %d, d: %d\n",
+               w, h, curw, curh, d);
+
+       if (d < 1) {
+               d = 1;
+       }
+       if (d > 8) {
+               d = 8;
+       }
+
+       vcs->decimation = d;
+       vino_set_clipping(vcs, x, y, w * d, h * d);
+
+       dprintk("scaling %d, %d, %d, %d / %d - %d\n", vcs->clipping.left,
+               vcs->clipping.top, vcs->clipping.right, vcs->clipping.bottom,
+               vcs->decimation, vcs->line_size);
+}
+
+/* execute with input_lock locked */
+static void vino_reset_scaling(struct vino_channel_settings *vcs)
+{
+       vino_set_scaling(vcs, vcs->clipping.right - vcs->clipping.left,
+                        vcs->clipping.bottom - vcs->clipping.top);
+}
+
+/* execute with input_lock locked */
+static void vino_set_framerate(struct vino_channel_settings *vcs,
+                              unsigned int fps)
+{
+       unsigned int mask;
+
+       switch (vcs->data_norm) {
+       case VINO_DATA_NORM_NTSC:
+       case VINO_DATA_NORM_D1:
+               fps = (unsigned int)(fps / 6) * 6; // FIXME: round!
+
+               if (fps < vino_data_norms[vcs->data_norm].fps_min)
+                       fps = vino_data_norms[vcs->data_norm].fps_min;
+               if (fps > vino_data_norms[vcs->data_norm].fps_max)
+                       fps = vino_data_norms[vcs->data_norm].fps_max;
+
+               switch (fps) {
+               case 6:
+                       mask = 0x003;
+                       break;
+               case 12:
+                       mask = 0x0c3;
+                       break;
+               case 18:
+                       mask = 0x333;
+                       break;
+               case 24:
+                       mask = 0x3ff;
+                       break;
+               case 30:
+                       mask = 0xfff;
+                       break;
+               default:
+                       mask = VINO_FRAMERT_FULL;
+               }
+               vcs->framert_reg = VINO_FRAMERT_RT(mask);
+               break;
+       case VINO_DATA_NORM_PAL:
+       case VINO_DATA_NORM_SECAM:
+               fps = (unsigned int)(fps / 5) * 5; // FIXME: round!
+
+               if (fps < vino_data_norms[vcs->data_norm].fps_min)
+                       fps = vino_data_norms[vcs->data_norm].fps_min;
+               if (fps > vino_data_norms[vcs->data_norm].fps_max)
+                       fps = vino_data_norms[vcs->data_norm].fps_max;
+
+               switch (fps) {
+               case 5:
+                       mask = 0x003;
+                       break;
+               case 10:
+                       mask = 0x0c3;
+                       break;
+               case 15:
+                       mask = 0x333;
+                       break;
+               case 20:
+                       mask = 0x0ff;
+                       break;
+               case 25:
+                       mask = 0x3ff;
+                       break;
+               default:
+                       mask = VINO_FRAMERT_FULL;
+               }
+               vcs->framert_reg = VINO_FRAMERT_RT(mask) | VINO_FRAMERT_PAL;
+               break;
+       }
+
+       vcs->fps = fps;
+}
+
+/* execute with input_lock locked */
+static void vino_set_default_framerate(struct vino_channel_settings *vcs)
+{
+       vino_set_framerate(vcs, vino_data_norms[vcs->data_norm].fps_max);
+}
+
+/*
+ * Prepare VINO for DMA transfer...
+ * (execute only with vino_lock and input_lock locked)
+ */
+static int vino_dma_setup(struct vino_channel_settings *vcs,
+                         struct vino_framebuffer *fb)
+{
+       u32 ctrl, intr;
+       struct sgi_vino_channel *ch;
+       const struct vino_data_norm *norm;
+
+       dprintk("vino_dma_setup():\n");
+
+       vcs->field = 0;
+       fb->frame_counter = 0;
+
+       ch = (vcs->channel == VINO_CHANNEL_A) ? &vino->a : &vino->b;
+       norm = &vino_data_norms[vcs->data_norm];
+
+       ch->page_index = 0;
+       ch->line_count = 0;
+
+       /* VINO line size register is set 8 bytes less than actual */
+       ch->line_size = vcs->line_size - 8;
+
+       /* let VINO know where to transfer data */
+       ch->start_desc_tbl = fb->desc_table.dma;
+       ch->next_4_desc = fb->desc_table.dma;
+
+       /* give vino time to fetch the first four descriptors, 5 usec
+        * should be more than enough time */
+       udelay(VINO_DESC_FETCH_DELAY);
+
+       /* set the alpha register */
+       ch->alpha = vcs->alpha;
+
+       /* set clipping registers */
+       ch->clip_start = VINO_CLIP_ODD(norm->odd.top + vcs->clipping.top / 2) |
+               VINO_CLIP_EVEN(norm->even.top +
+                              vcs->clipping.top / 2) |
+               VINO_CLIP_X(vcs->clipping.left);
+       ch->clip_end = VINO_CLIP_ODD(norm->odd.top +
+                                    vcs->clipping.bottom / 2 - 1) |
+               VINO_CLIP_EVEN(norm->even.top +
+                              vcs->clipping.bottom / 2 - 1) |
+               VINO_CLIP_X(vcs->clipping.right);
+       /* FIXME: end-of-field bug workaround
+                      VINO_CLIP_X(VINO_PAL_WIDTH);
+        */
+
+       /* set the size of actual content in the buffer (DECIMATION !) */
+       fb->data_size = ((vcs->clipping.right - vcs->clipping.left) /
+                        vcs->decimation) *
+               ((vcs->clipping.bottom - vcs->clipping.top) /
+                vcs->decimation) *
+               vino_data_formats[vcs->data_format].bpp;
+
+       ch->frame_rate = vcs->framert_reg;
+
+       ctrl = vino->control;
+       intr = vino->intr_status;
+
+       if (vcs->channel == VINO_CHANNEL_A) {
+               /* All interrupt conditions for this channel was cleared
+                * so clear the interrupt status register and enable
+                * interrupts */
+               intr &= ~VINO_INTSTAT_A;
+               ctrl |= VINO_CTRL_A_INT;
+
+               /* enable synchronization */
+               ctrl |= VINO_CTRL_A_SYNC_ENBL;
+
+               /* enable frame assembly */
+               ctrl |= VINO_CTRL_A_INTERLEAVE_ENBL;
+
+               /* set decimation used */
+               if (vcs->decimation < 2)
+                       ctrl &= ~VINO_CTRL_A_DEC_ENBL;
+               else {
+                       ctrl |= VINO_CTRL_A_DEC_ENBL;
+                       ctrl &= ~VINO_CTRL_A_DEC_SCALE_MASK;
+                       ctrl |= (vcs->decimation - 1) <<
+                               VINO_CTRL_A_DEC_SCALE_SHIFT;
+               }
+
+               /* select input interface */
+               if (vcs->input == VINO_INPUT_D1)
+                       ctrl |= VINO_CTRL_A_SELECT;
+               else
+                       ctrl &= ~VINO_CTRL_A_SELECT;
+
+               /* palette */
+               ctrl &= ~(VINO_CTRL_A_LUMA_ONLY | VINO_CTRL_A_RGB |
+                         VINO_CTRL_A_DITHER);
+       } else {
+               intr &= ~VINO_INTSTAT_B;
+               ctrl |= VINO_CTRL_B_INT;
+
+               ctrl |= VINO_CTRL_B_SYNC_ENBL;
+               ctrl |= VINO_CTRL_B_INTERLEAVE_ENBL;
+
+               if (vcs->decimation < 2)
+                       ctrl &= ~VINO_CTRL_B_DEC_ENBL;
+               else {
+                       ctrl |= VINO_CTRL_B_DEC_ENBL;
+                       ctrl &= ~VINO_CTRL_B_DEC_SCALE_MASK;
+                       ctrl |= (vcs->decimation - 1) <<
+                               VINO_CTRL_B_DEC_SCALE_SHIFT;
+
+               }
+               if (vcs->input == VINO_INPUT_D1)
+                       ctrl |= VINO_CTRL_B_SELECT;
+               else
+                       ctrl &= ~VINO_CTRL_B_SELECT;
+
+               ctrl &= ~(VINO_CTRL_B_LUMA_ONLY | VINO_CTRL_B_RGB |
+                         VINO_CTRL_B_DITHER);
+       }
+
+       /* set palette */
+       fb->data_format = vcs->data_format;
+
+       switch (vcs->data_format) {
+               case VINO_DATA_FMT_GREY:
+                       ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
+                               VINO_CTRL_A_LUMA_ONLY : VINO_CTRL_B_LUMA_ONLY;
+                       break;
+               case VINO_DATA_FMT_RGB32:
+                       ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
+                               VINO_CTRL_A_RGB : VINO_CTRL_B_RGB;
+                       break;
+               case VINO_DATA_FMT_YUV:
+                       /* nothing needs to be done */
+                       break;
+               case VINO_DATA_FMT_RGB332:
+                       ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
+                               VINO_CTRL_A_RGB | VINO_CTRL_A_DITHER :
+                               VINO_CTRL_B_RGB | VINO_CTRL_B_DITHER;
+                       break;
+       }
+
+       vino->intr_status = intr;
+       vino->control = ctrl;
+
+       return 0;
+}
+
+/* (execute only with vino_lock locked) */
+static void vino_dma_start(struct vino_channel_settings *vcs)
+{
+       u32 ctrl = vino->control;
+
+       dprintk("vino_dma_start():\n");
+       ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
+               VINO_CTRL_A_DMA_ENBL : VINO_CTRL_B_DMA_ENBL;
+       vino->control = ctrl;
+}
+
+/* (execute only with vino_lock locked) */
+static void vino_dma_stop(struct vino_channel_settings *vcs)
+{
+       u32 ctrl = vino->control;
+
+       ctrl &= (vcs->channel == VINO_CHANNEL_A) ?
+               ~VINO_CTRL_A_DMA_ENBL : ~VINO_CTRL_B_DMA_ENBL;
+       vino->control = ctrl;
+       dprintk("vino_dma_stop():\n");
+}
+
+/*
+ * Load dummy page to descriptor registers. This prevents generating of
+ * spurious interrupts. (execute only with vino_lock locked)
+ */
+static void vino_clear_interrupt(struct vino_channel_settings *vcs)
+{
+       struct sgi_vino_channel *ch;
+
+       ch = (vcs->channel == VINO_CHANNEL_A) ? &vino->a : &vino->b;
+
+       ch->page_index = 0;
+       ch->line_count = 0;
+
+       ch->start_desc_tbl = vino_drvdata->dummy_desc_table.dma;
+       ch->next_4_desc = vino_drvdata->dummy_desc_table.dma;
+
+       udelay(VINO_DESC_FETCH_DELAY);
+       dprintk("channel %c clear interrupt condition\n",
+              (vcs->channel == VINO_CHANNEL_A) ? 'A':'B');
+}
+
+static int vino_capture(struct vino_channel_settings *vcs,
+                       struct vino_framebuffer *fb)
+{
+       int err = 0;
+       unsigned long flags, flags2;
+
+       spin_lock_irqsave(&fb->state_lock, flags);
+
+       if (fb->state == VINO_FRAMEBUFFER_IN_USE)
+               err = -EBUSY;
+       fb->state = VINO_FRAMEBUFFER_IN_USE;
+
+       spin_unlock_irqrestore(&fb->state_lock, flags);
+
+       if (err)
+               return err;
+
+       spin_lock_irqsave(&vino_drvdata->vino_lock, flags);
+       spin_lock_irqsave(&vino_drvdata->input_lock, flags2);
+
+       vino_dma_setup(vcs, fb);
+       vino_dma_start(vcs);
+
+       spin_unlock_irqrestore(&vino_drvdata->input_lock, flags2);
+       spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags);
+
+       return err;
+}
+
+static
+struct vino_framebuffer *vino_capture_enqueue(struct
+                                             vino_channel_settings *vcs,
+                                             unsigned int index)
+{
+       struct vino_framebuffer *fb;
+       unsigned long flags;
+
+       dprintk("vino_capture_enqueue():\n");
+
+       spin_lock_irqsave(&vcs->capture_lock, flags);
+
+       fb = vino_queue_add(&vcs->fb_queue, index);
+       if (fb == NULL) {
+               dprintk("vino_capture_enqueue(): vino_queue_add() failed, "
+                       "queue full?\n");
+               goto out;
+       }
+out:
+       spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+       return fb;
+}
+
+static int vino_capture_next(struct vino_channel_settings *vcs, int start)
+{
+       struct vino_framebuffer *fb;
+       unsigned int incoming, id;
+       int err = 0;
+       unsigned long flags, flags2;
+
+       dprintk("vino_capture_next():\n");
+
+       spin_lock_irqsave(&vcs->capture_lock, flags);
+
+       if (start) {
+               /* start capture only if capture isn't in progress already */
+               if (vcs->capturing) {
+                       spin_unlock_irqrestore(&vcs->capture_lock, flags);
+                       return 0;
+               }
+
+       } else {
+               /* capture next frame:
+                * stop capture if capturing is not set */
+               if (!vcs->capturing) {
+                       spin_unlock_irqrestore(&vcs->capture_lock, flags);
+                       return 0;
+               }
+       }
+
+       err = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
+       if (err) {
+               dprintk("vino_capture_next(): vino_queue_get_incoming() "
+                       "failed\n");
+               err = -EINVAL;
+               goto out;
+       }
+       if (incoming == 0) {
+               dprintk("vino_capture_next(): no buffers available\n");
+               goto out;
+       }
+
+       fb = vino_queue_peek(&vcs->fb_queue, &id);
+       if (fb == NULL) {
+               dprintk("vino_capture_next(): vino_queue_peek() failed\n");
+               err = -EINVAL;
+               goto out;
+       }
+
+       spin_lock_irqsave(&fb->state_lock, flags2);
+       fb->state = VINO_FRAMEBUFFER_UNUSED;
+       spin_unlock_irqrestore(&fb->state_lock, flags2);
+
+       if (start) {
+               vcs->capturing = 1;
+       }
+
+       spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+       err = vino_capture(vcs, fb);
+
+       return err;
+
+out:
+       vcs->capturing = 0;
+       spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+       return err;
+}
+
+static int vino_is_capturing(struct vino_channel_settings *vcs)
+{
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&vcs->capture_lock, flags);
+
+       ret = vcs->capturing;
+
+       spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+       return ret;
+}
+
+/* waits until a frame is captured */
+static int vino_wait_for_frame(struct vino_channel_settings *vcs)
+{
+       wait_queue_t wait;
+       int err = 0;
+
+       dprintk("vino_wait_for_frame():\n");
+
+       init_waitqueue_entry(&wait, current);
+       /* add ourselves into wait queue */
+       add_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait);
+       /* and set current state */
+       set_current_state(TASK_INTERRUPTIBLE);
+
+       /* to ensure that schedule_timeout will return immediately
+        * if VINO interrupt was triggred meanwhile */
+       schedule_timeout(HZ / 10);
+
+       if (signal_pending(current))
+               err = -EINTR;
+
+       remove_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait);
+
+       dprintk("vino_wait_for_frame(): waiting for frame %s\n",
+               err ? "failed" : "ok");
+
+       return err;
+}
+
+/* the function assumes that PAGE_SIZE % 4 == 0 */
+static void vino_convert_to_rgba(struct vino_framebuffer *fb) {
+       unsigned char *pageptr;
+       unsigned int page, i;
+       unsigned char a;
+
+       for (page = 0; page < fb->desc_table.page_count; page++) {
+               pageptr = (unsigned char *)fb->desc_table.virtual[page];
+
+               for (i = 0; i < PAGE_SIZE; i += 4) {
+                       a = pageptr[0];
+                       pageptr[0] = pageptr[3];
+                       pageptr[1] = pageptr[2];
+                       pageptr[2] = pageptr[1];
+                       pageptr[3] = a;
+                       pageptr += 4;
+               }
+       }
+}
+
+/* checks if the buffer is in correct state and syncs data */
+static int vino_check_buffer(struct vino_channel_settings *vcs,
+                            struct vino_framebuffer *fb)
+{
+       int err = 0;
+       unsigned long flags;
+
+       dprintk("vino_check_buffer():\n");
+
+       spin_lock_irqsave(&fb->state_lock, flags);
+       switch (fb->state) {
+       case VINO_FRAMEBUFFER_IN_USE:
+               err = -EIO;
+               break;
+       case VINO_FRAMEBUFFER_READY:
+               vino_sync_buffer(fb);
+               fb->state = VINO_FRAMEBUFFER_UNUSED;
+               break;
+       default:
+               err = -EINVAL;
+       }
+       spin_unlock_irqrestore(&fb->state_lock, flags);
+
+       if (!err) {
+               if (vino_pixel_conversion
+                   && (fb->data_format == VINO_DATA_FMT_RGB32)) {
+                       vino_convert_to_rgba(fb);
+               }
+       } else if (err && (err != -EINVAL)) {
+               dprintk("vino_check_buffer(): buffer not ready\n");
+
+               spin_lock_irqsave(&vino_drvdata->vino_lock, flags);
+               vino_dma_stop(vcs);
+               vino_clear_interrupt(vcs);
+               spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags);
+       }
+
+       return err;
+}
+
+/* forcefully terminates capture */
+static void vino_capture_stop(struct vino_channel_settings *vcs)
+{
+       unsigned int incoming = 0, outgoing = 0, id;
+       unsigned long flags, flags2;
+
+       dprintk("vino_capture_stop():\n");
+
+       spin_lock_irqsave(&vcs->capture_lock, flags);
+       /* unset capturing to stop queue processing */
+       vcs->capturing = 0;
+
+       spin_lock_irqsave(&vino_drvdata->vino_lock, flags2);
+
+       vino_dma_stop(vcs);
+       vino_clear_interrupt(vcs);
+
+       spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags2);
+
+       /* remove all items from the queue */
+       if (vino_queue_get_incoming(&vcs->fb_queue, &incoming)) {
+               dprintk("vino_capture_stop(): "
+                       "vino_queue_get_incoming() failed\n");
+               goto out;
+       }
+       while (incoming > 0) {
+               vino_queue_transfer(&vcs->fb_queue);
+
+               if (vino_queue_get_incoming(&vcs->fb_queue, &incoming)) {
+                       dprintk("vino_capture_stop(): "
+                               "vino_queue_get_incoming() failed\n");
+                       goto out;
+               }
+       }
+
+       if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
+               dprintk("vino_capture_stop(): "
+                       "vino_queue_get_outgoing() failed\n");
+               goto out;
+       }
+       while (outgoing > 0) {
+               vino_queue_remove(&vcs->fb_queue, &id);
+
+               if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
+                       dprintk("vino_capture_stop(): "
+                               "vino_queue_get_outgoing() failed\n");
+                       goto out;
+               }
+       }
+
+out:
+       spin_unlock_irqrestore(&vcs->capture_lock, flags);
+}
+
+static int vino_capture_failed(struct vino_channel_settings *vcs)
+{
+       struct vino_framebuffer *fb;
+       unsigned long flags;
+       unsigned int i;
+       int ret;
+
+       dprintk("vino_capture_failed():\n");
+
+       spin_lock_irqsave(&vino_drvdata->vino_lock, flags);
+
+       vino_dma_stop(vcs);
+       vino_clear_interrupt(vcs);
+
+       spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags);
+
+       ret = vino_queue_get_incoming(&vcs->fb_queue, &i);
+       if (ret == VINO_QUEUE_ERROR) {
+               dprintk("vino_queue_get_incoming() failed\n");
+               return -EINVAL;
+       }
+       if (i == 0) {
+               /* no buffers to process */
+               return 0;
+       }
+
+       fb = vino_queue_peek(&vcs->fb_queue, &i);
+       if (fb == NULL) {
+               dprintk("vino_queue_peek() failed\n");
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&fb->state_lock, flags);
+       if (fb->state == VINO_FRAMEBUFFER_IN_USE) {
+               fb->state = VINO_FRAMEBUFFER_UNUSED;
+               vino_queue_transfer(&vcs->fb_queue);
+               vino_queue_remove(&vcs->fb_queue, &i);
+               /* we should actually discard the newest frame,
+                * but who cares ... */
+       }
+       spin_unlock_irqrestore(&fb->state_lock, flags);
+
+       return 0;
+}
+
+static void vino_frame_done(struct vino_channel_settings *vcs,
+                           unsigned int fc)
+{
+       struct vino_framebuffer *fb;
+       unsigned long flags;
+
+       spin_lock_irqsave(&vcs->capture_lock, flags);
+       fb = vino_queue_transfer(&vcs->fb_queue);
+       if (!fb) {
+               spin_unlock_irqrestore(&vcs->capture_lock, flags);
+               dprintk("vino_frame_done(): vino_queue_transfer() failed!\n");
+               return;
+       }
+       spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+       fb->frame_counter = fc;
+       do_gettimeofday(&fb->timestamp);
+
+       spin_lock_irqsave(&fb->state_lock, flags);
+       if (fb->state == VINO_FRAMEBUFFER_IN_USE)
+               fb->state = VINO_FRAMEBUFFER_READY;
+       spin_unlock_irqrestore(&fb->state_lock, flags);
+
+       wake_up(&vcs->fb_queue.frame_wait_queue);
+
+       vino_capture_next(vcs, 0);
+}
+
+static irqreturn_t vino_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       u32 intr;
+       unsigned int fc_a, fc_b;
+       int done_a = 0;
+       int done_b = 0;
+
+       spin_lock(&vino_drvdata->vino_lock);
+
+       intr = vino->intr_status;
+       fc_a = vino->a.field_counter / 2;
+       fc_b = vino->b.field_counter / 2;
+
+       // TODO: handle error-interrupts in some special way ?
+
+       if (intr & VINO_INTSTAT_A) {
+               if (intr & VINO_INTSTAT_A_EOF) {
+                       vino_drvdata->a.field++;
+                       if (vino_drvdata->a.field > 1) {
+                               vino_dma_stop(&vino_drvdata->a);
+                               vino_clear_interrupt(&vino_drvdata->a);
+                               vino_drvdata->a.field = 0;
+                               done_a = 1;
+                       }
+                       dprintk("intr: channel A end-of-field interrupt: "
+                               "%04x\n", intr);
+               } else {
+                       vino_dma_stop(&vino_drvdata->a);
+                       vino_clear_interrupt(&vino_drvdata->a);
+                       done_a = 1;
+                       dprintk("channel A error interrupt: %04x\n", intr);
+               }
+       }
+       if (intr & VINO_INTSTAT_B) {
+               if (intr & VINO_INTSTAT_B_EOF) {
+                       vino_drvdata->b.field++;
+                       if (vino_drvdata->b.field > 1) {
+                               vino_dma_stop(&vino_drvdata->b);
+                               vino_clear_interrupt(&vino_drvdata->b);
+                               vino_drvdata->b.field = 0;
+                               done_b = 1;
+                       }
+                       dprintk("intr: channel B end-of-field interrupt: "
+                               "%04x\n", intr);
+               } else {
+                       vino_dma_stop(&vino_drvdata->b);
+                       vino_clear_interrupt(&vino_drvdata->b);
+                       done_b = 1;
+                       dprintk("channel B error interrupt: %04x\n", intr);
+               }
+       }
+
+       /* always remember to clear interrupt status */
+       vino->intr_status = ~intr;
+
+       spin_unlock(&vino_drvdata->vino_lock);
+
+       if (done_a) {
+               vino_frame_done(&vino_drvdata->a, fc_a);
+               dprintk("channel A frame done, interrupt: %d\n", intr);
+       }
+       if (done_b) {
+               vino_frame_done(&vino_drvdata->b, fc_b);
+               dprintk("channel B frame done, interrupt: %d\n", intr);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/* VINO video input management */
+
+static int vino_get_saa7191_input(int input)
+{
+       switch (input) {
+       case VINO_INPUT_COMPOSITE:
+               return SAA7191_INPUT_COMPOSITE;
+       case VINO_INPUT_SVIDEO:
+               return SAA7191_INPUT_SVIDEO;
+       default:
+               printk(KERN_ERR "VINO: vino_get_saa7191_input(): "
+                      "invalid input!\n");
+               return -1;
+       }
+}
+
+static int vino_get_saa7191_norm(int norm)
+{
+       switch (norm) {
+       case VINO_DATA_NORM_AUTO:
+               return SAA7191_NORM_AUTO;
+       case VINO_DATA_NORM_PAL:
+               return SAA7191_NORM_PAL;
+       case VINO_DATA_NORM_NTSC:
+               return SAA7191_NORM_NTSC;
+       case VINO_DATA_NORM_SECAM:
+               return SAA7191_NORM_SECAM;
+       default:
+               printk(KERN_ERR "VINO: vino_get_saa7191_norm(): "
+                      "invalid norm!\n");
+               return -1;
+       }
+}
+
+/* execute with input_lock locked */
+static int vino_is_input_owner(struct vino_channel_settings *vcs)
+{
+       switch(vcs->input) {
+       case VINO_INPUT_COMPOSITE:
+       case VINO_INPUT_SVIDEO:
+               return (vino_drvdata->decoder.owner == vcs->channel);
+       case VINO_INPUT_D1:
+               return (vino_drvdata->camera.owner == vcs->channel);
+       default:
+               return 0;
+       }
+}
+
+static int vino_acquire_input(struct vino_channel_settings *vcs)
+{
+       int ret = 0;
+
+       dprintk("vino_acquire_input():\n");
+
+       spin_lock(&vino_drvdata->input_lock);
+
+       /* First try D1 and then SAA7191 */
+       if (vino_drvdata->camera.driver
+           && (vino_drvdata->camera.owner == VINO_NO_CHANNEL)) {
+               if (i2c_use_client(vino_drvdata->camera.driver)) {
+                       ret = -ENODEV;
+                       goto out;
+               }
+
+               vino_drvdata->camera.owner = vcs->channel;
+               vcs->input = VINO_INPUT_D1;
+               vcs->data_norm = VINO_DATA_NORM_D1;
+       } else if (vino_drvdata->decoder.driver
+                  && (vino_drvdata->decoder.owner == VINO_NO_CHANNEL)) {
+               int saa7191_input;
+               int saa7191_norm;
+
+               if (i2c_use_client(vino_drvdata->decoder.driver)) {
+                       ret = -ENODEV;
+                       goto out;
+               }
+
+               vino_drvdata->decoder.owner = vcs->channel;
+               vcs->input = VINO_INPUT_COMPOSITE;
+               vcs->data_norm = VINO_DATA_NORM_PAL;
+
+               saa7191_input = vino_get_saa7191_input(vcs->input);
+               i2c_decoder_command(DECODER_SET_INPUT, &saa7191_input);
+
+               saa7191_norm = vino_get_saa7191_norm(vcs->data_norm);
+               i2c_decoder_command(DECODER_SAA7191_SET_NORM, &saa7191_norm);
+       } else {
+               vcs->input = (vcs->channel == VINO_CHANNEL_A) ?
+                       vino_drvdata->b.input : vino_drvdata->a.input;
+               vcs->data_norm = (vcs->channel == VINO_CHANNEL_A) ?
+                       vino_drvdata->b.data_norm : vino_drvdata->a.data_norm;
+       }
+
+       if (vcs->input == VINO_INPUT_NONE) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       if (vino_is_input_owner(vcs)) {
+               vino_set_default_clipping(vcs);
+               vino_set_default_framerate(vcs);
+       }
+
+       dprintk("vino_acquire_input(): %s\n", vino_inputs[vcs->input].name);
+
+out:
+       spin_unlock(&vino_drvdata->input_lock);
+
+       return ret;
+}
+
+static int vino_set_input(struct vino_channel_settings *vcs, int input)
+{
+       struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ?
+               &vino_drvdata->b : &vino_drvdata->a;
+       int ret = 0;
+
+       dprintk("vino_set_input():\n");
+
+       spin_lock(&vino_drvdata->input_lock);
+
+       if (vcs->input == input)
+               goto out;
+
+       switch(input) {
+       case VINO_INPUT_COMPOSITE:
+       case VINO_INPUT_SVIDEO:
+               if (!vino_drvdata->decoder.driver) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               if (vino_drvdata->decoder.owner == VINO_NO_CHANNEL) {
+                       if (i2c_use_client(vino_drvdata->decoder.driver)) {
+                               ret = -ENODEV;
+                               goto out;
+                       }
+                       vino_drvdata->decoder.owner = vcs->channel;
+               }
+
+               if (vino_drvdata->decoder.owner == vcs->channel) {
+                       int saa7191_input;
+                       int saa7191_norm;
+
+                       vcs->input = input;
+                       vcs->data_norm = VINO_DATA_NORM_PAL;
+
+                       saa7191_input = vino_get_saa7191_input(vcs->input);
+                       i2c_decoder_command(DECODER_SET_INPUT, &saa7191_input);
+                       saa7191_norm = vino_get_saa7191_norm(vcs->data_norm);
+                       i2c_decoder_command(DECODER_SAA7191_SET_NORM,
+                                           &saa7191_norm);
+               } else {
+                       if (vcs2->input != input) {
+                               ret = -EBUSY;
+                               goto out;
+                       }
+
+                       vcs->input = input;
+                       vcs->data_norm = vcs2->data_norm;
+               }
+
+               if (vino_drvdata->camera.owner == vcs->channel) {
+                       /* Transfer the ownership or release the input */
+                       if (vcs2->input == VINO_INPUT_D1) {
+                               vino_drvdata->camera.owner = vcs2->channel;
+                       } else {
+                               i2c_release_client(vino_drvdata->
+                                                  camera.driver);
+                               vino_drvdata->camera.owner = VINO_NO_CHANNEL;
+                       }
+               }
+               break;
+       case VINO_INPUT_D1:
+               if (!vino_drvdata->camera.driver) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               if (vino_drvdata->camera.owner == VINO_NO_CHANNEL) {
+                       if (i2c_use_client(vino_drvdata->camera.driver)) {
+                               ret = -ENODEV;
+                               goto out;
+                       }
+                       vino_drvdata->camera.owner = vcs->channel;
+               }
+
+               if (vino_drvdata->decoder.owner == vcs->channel) {
+                       /* Transfer the ownership or release the input */
+                       if ((vcs2->input == VINO_INPUT_COMPOSITE) ||
+                                (vcs2->input == VINO_INPUT_SVIDEO)) {
+                               vino_drvdata->decoder.owner = vcs2->channel;
+                       } else {
+                               i2c_release_client(vino_drvdata->
+                                                  decoder.driver);
+                               vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+                       }
+               }
+
+               vcs->input = input;
+               vcs->data_norm = VINO_DATA_NORM_D1;
+               break;
+       default:
+               ret = -EINVAL;
+               goto out;
+       }
+
+       vino_set_default_clipping(vcs);
+       vino_set_default_framerate(vcs);
+
+       dprintk("vino_set_input(): %s\n", vino_inputs[vcs->input].name);
+
+out:
+       spin_unlock(&vino_drvdata->input_lock);
+
+       return ret;
+}
+
+static void vino_release_input(struct vino_channel_settings *vcs)
+{
+       struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ?
+               &vino_drvdata->b : &vino_drvdata->a;
+
+       dprintk("vino_release_input():\n");
+
+       spin_lock(&vino_drvdata->input_lock);
+
+       /* Release ownership of the channel
+        * and if the other channel takes input from
+        * the same source, transfer the ownership */
+       if (vino_drvdata->camera.owner == vcs->channel) {
+               if (vcs2->input == VINO_INPUT_D1) {
+                       vino_drvdata->camera.owner = vcs2->channel;
+               } else {
+                       i2c_release_client(vino_drvdata->camera.driver);
+                       vino_drvdata->camera.owner = VINO_NO_CHANNEL;
+               }
+       } else if (vino_drvdata->decoder.owner == vcs->channel) {
+               if ((vcs2->input == VINO_INPUT_COMPOSITE) ||
+                        (vcs2->input == VINO_INPUT_SVIDEO)) {
+                       vino_drvdata->decoder.owner = vcs2->channel;
+               } else {
+                       i2c_release_client(vino_drvdata->decoder.driver);
+                       vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+               }
+       }
+       vcs->input = VINO_INPUT_NONE;
+
+       spin_unlock(&vino_drvdata->input_lock);
+}
+
+/* execute with input_lock locked */
+static int vino_set_data_norm(struct vino_channel_settings *vcs,
+                             unsigned int data_norm)
+{
+       int saa7191_norm;
+
+       switch (vcs->input) {
+       case VINO_INPUT_D1:
+               /* only one "norm" supported */
+               if (data_norm != VINO_DATA_NORM_D1)
+                       return -EINVAL;
+               break;
+       case VINO_INPUT_COMPOSITE:
+       case VINO_INPUT_SVIDEO:
+
+               saa7191_norm = vino_get_saa7191_norm(data_norm);
+
+               i2c_decoder_command(DECODER_SAA7191_SET_NORM, &saa7191_norm);
+               vcs->data_norm = data_norm;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* V4L2 helper functions */
+
+static int vino_find_data_format(__u32 pixelformat)
+{
+       int i;
+
+       for (i = 0; i < VINO_DATA_FMT_COUNT; i++) {
+               if (vino_data_formats[i].pixelformat == pixelformat)
+                       return i;
+       }
+
+       return VINO_DATA_FMT_NONE;
+}
+
+static int vino_enum_data_norm(struct vino_channel_settings *vcs, __u32 index)
+{
+       int data_norm = VINO_DATA_NORM_NONE;
+
+       spin_lock(&vino_drvdata->input_lock);
+       switch(vcs->input) {
+       case VINO_INPUT_COMPOSITE:
+       case VINO_INPUT_SVIDEO:
+               if (index == 0) {
+                       data_norm = VINO_DATA_NORM_PAL;
+               } else if (index == 1) {
+                       data_norm = VINO_DATA_NORM_NTSC;
+               } else if (index == 2) {
+                       data_norm = VINO_DATA_NORM_SECAM;
+               }
+               break;
+       case VINO_INPUT_D1:
+               if (index == 0) {
+                       data_norm = VINO_DATA_NORM_D1;
+               }
+               break;
+       }
+       spin_unlock(&vino_drvdata->input_lock);
+
+       return data_norm;
+}
+
+static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index)
+{
+       int input = VINO_INPUT_NONE;
+
+       spin_lock(&vino_drvdata->input_lock);
+       if (vino_drvdata->decoder.driver && vino_drvdata->camera.driver) {
+               switch (index) {
+               case 0:
+                       input = VINO_INPUT_COMPOSITE;
+                       break;
+               case 1:
+                       input = VINO_INPUT_SVIDEO;
+                       break;
+               case 2:
+                       input = VINO_INPUT_D1;
+                       break;
+               }
+       } else if (vino_drvdata->decoder.driver) {
+               switch (index) {
+               case 0:
+                       input = VINO_INPUT_COMPOSITE;
+                       break;
+               case 1:
+                       input = VINO_INPUT_SVIDEO;
+                       break;
+               }
+       } else if (vino_drvdata->camera.driver) {
+               switch (index) {
+               case 0:
+                       input = VINO_INPUT_D1;
+                       break;
+               }
+       }
+       spin_unlock(&vino_drvdata->input_lock);
+
+       return input;
+}
+
+/* execute with input_lock locked */
+static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
+{
+       __u32 index = 0;
+       // FIXME: detect when no inputs available
+
+       if (vino_drvdata->decoder.driver && vino_drvdata->camera.driver) {
+               switch (vcs->input) {
+               case VINO_INPUT_COMPOSITE:
+                       index = 0;
+                       break;
+               case VINO_INPUT_SVIDEO:
+                       index = 1;
+                       break;
+               case VINO_INPUT_D1:
+                       index = 2;
+                       break;
+               }
+       } else if (vino_drvdata->decoder.driver) {
+               switch (vcs->input) {
+               case VINO_INPUT_COMPOSITE:
+                       index = 0;
+                       break;
+               case VINO_INPUT_SVIDEO:
+                       index = 1;
+                       break;
+               }
+       } else if (vino_drvdata->camera.driver) {
+               switch (vcs->input) {
+               case VINO_INPUT_D1:
+                       index = 0;
+                       break;
+               }
+       }
+
+       return index;
+}
+
+/* V4L2 ioctls */
+
+static void vino_v4l2_querycap(struct v4l2_capability *cap)
+{
+       memset(cap, 0, sizeof(struct v4l2_capability));
+
+       strcpy(cap->driver, vino_driver_name);
+       strcpy(cap->card, vino_driver_description);
+       strcpy(cap->bus_info, vino_bus_name);
+       cap->version = VINO_VERSION_CODE;
+       cap->capabilities =
+               V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_STREAMING;
+       // V4L2_CAP_OVERLAY, V4L2_CAP_READWRITE
+}
+
+static int vino_v4l2_enuminput(struct vino_channel_settings *vcs,
+                              struct v4l2_input *i)
+{
+       __u32 index = i->index;
+       int input;
+       dprintk("requested index = %d\n", index);
+
+       input = vino_enum_input(vcs, index);
+       if (input == VINO_INPUT_NONE)
+               return -EINVAL;
+
+       memset(i, 0, sizeof(struct v4l2_input));
+
+       i->index = index;
+       i->type = V4L2_INPUT_TYPE_CAMERA;
+       i->std = vino_inputs[input].std;
+       strcpy(i->name, vino_inputs[input].name);
+
+       if ((input == VINO_INPUT_COMPOSITE)
+           || (input == VINO_INPUT_SVIDEO)) {
+               struct saa7191_status status;
+               i2c_decoder_command(DECODER_SAA7191_GET_STATUS, &status);
+               i->status |= status.signal ? 0 : V4L2_IN_ST_NO_SIGNAL;
+               i->status |= status.color ? 0 : V4L2_IN_ST_NO_COLOR;
+       }
+
+       return 0;
+}
+
+static int vino_v4l2_g_input(struct vino_channel_settings *vcs,
+                            struct v4l2_input *i)
+{
+       __u32 index;
+       int input;
+
+       spin_lock(&vino_drvdata->input_lock);
+       input = vcs->input;
+       index = vino_find_input_index(vcs);
+       spin_unlock(&vino_drvdata->input_lock);
+
+       dprintk("input = %d\n", input);
+
+       if (input == VINO_INPUT_NONE) {
+               return -EINVAL;
+       }
+
+       memset(i, 0, sizeof(struct v4l2_input));
+
+       i->index = index;
+       i->type = V4L2_INPUT_TYPE_CAMERA;
+       i->std = vino_inputs[input].std;
+       strcpy(i->name, vino_inputs[input].name);
+
+       return 0;
+}
+
+static int vino_v4l2_s_input(struct vino_channel_settings *vcs,
+                            struct v4l2_input *i)
+{
+       int input;
+       dprintk("requested input = %d\n", i->index);
+
+       input = vino_enum_input(vcs, i->index);
+       if (input == VINO_INPUT_NONE)
+               return -EINVAL;
+
+       return vino_set_input(vcs, input);
+}
+
+static int vino_v4l2_enumstd(struct vino_channel_settings *vcs,
+                            struct v4l2_standard *s)
+{
+       int index = s->index;
+       int data_norm = vino_enum_data_norm(vcs, index);
+       dprintk("standard index = %d\n", index);
+
+       if (data_norm == VINO_DATA_NORM_NONE)
+               return -EINVAL;
+
+       dprintk("standard name = %s\n",
+              vino_data_norms[data_norm].description);
+
+       memset(s, 0, sizeof(struct v4l2_standard));
+       s->index = index;
+
+       s->id = vino_data_norms[data_norm].std;
+       s->frameperiod.numerator = 1;
+       s->frameperiod.denominator =
+               vino_data_norms[data_norm].fps_max;
+       s->framelines =
+               vino_data_norms[data_norm].framelines;
+       strcpy(s->name,
+              vino_data_norms[data_norm].description);
+
+       return 0;
+}
+
+static int vino_v4l2_g_std(struct vino_channel_settings *vcs,
+                          v4l2_std_id *std)
+{
+       spin_lock(&vino_drvdata->input_lock);
+       dprintk("current standard = %d\n", vcs->data_norm);
+       *std = vino_data_norms[vcs->data_norm].std;
+       spin_unlock(&vino_drvdata->input_lock);
+
+       return 0;
+}
+
+static int vino_v4l2_s_std(struct vino_channel_settings *vcs,
+                          v4l2_std_id *std)
+{
+       int ret = 0;
+
+       spin_lock(&vino_drvdata->input_lock);
+
+       /* check if the standard is valid for the current input */
+       if (vino_is_input_owner(vcs)
+           && (vino_inputs[vcs->input].std & (*std))) {
+               dprintk("standard accepted\n");
+
+               /* change the video norm for SAA7191
+                * and accept NTSC for D1 (do nothing) */
+
+               if (vcs->input == VINO_INPUT_D1)
+                       goto out;
+
+               if ((*std) & V4L2_STD_PAL) {
+                       vino_set_data_norm(vcs, VINO_DATA_NORM_PAL);
+                       vcs->data_norm = VINO_DATA_NORM_PAL;
+               } else if ((*std) & V4L2_STD_NTSC) {
+                       vino_set_data_norm(vcs, VINO_DATA_NORM_NTSC);
+                       vcs->data_norm = VINO_DATA_NORM_NTSC;
+               } else if ((*std) & V4L2_STD_SECAM) {
+                       vino_set_data_norm(vcs, VINO_DATA_NORM_SECAM);
+                       vcs->data_norm = VINO_DATA_NORM_SECAM;
+               } else {
+                       ret = -EINVAL;
+               }
+       } else {
+               ret = -EINVAL;
+       }
+
+out:
+       spin_unlock(&vino_drvdata->input_lock);
+
+       return ret;
+}
+
+static int vino_v4l2_enum_fmt(struct vino_channel_settings *vcs,
+                             struct v4l2_fmtdesc *fd)
+{
+       enum v4l2_buf_type type = fd->type;
+       int index = fd->index;
+       dprintk("format index = %d\n", index);
+
+       switch (fd->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               if ((fd->index < 0) ||
+                   (fd->index >= VINO_DATA_FMT_COUNT))
+                       return -EINVAL;
+               dprintk("format name = %s\n",
+                      vino_data_formats[index].description);
+
+               memset(fd, 0, sizeof(struct v4l2_fmtdesc));
+               fd->index = index;
+               fd->type = type;
+               fd->pixelformat = vino_data_formats[index].pixelformat;
+               strcpy(fd->description, vino_data_formats[index].description);
+               break;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vino_v4l2_try_fmt(struct vino_channel_settings *vcs,
+                            struct v4l2_format *f)
+{
+       struct vino_channel_settings tempvcs;
+
+       switch (f->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+               struct v4l2_pix_format *pf = &f->fmt.pix;
+
+               dprintk("requested: w = %d, h = %d\n",
+                      pf->width, pf->height);
+
+               spin_lock(&vino_drvdata->input_lock);
+               memcpy(&tempvcs, vcs, sizeof(struct vino_channel_settings));
+               spin_unlock(&vino_drvdata->input_lock);
+
+               tempvcs.data_format = vino_find_data_format(pf->pixelformat);
+               if (tempvcs.data_format == VINO_DATA_FMT_NONE) {
+                       tempvcs.data_format = VINO_DATA_FMT_RGB32;
+                       pf->pixelformat =
+                               vino_data_formats[tempvcs.data_format].
+                               pixelformat;
+               }
+
+               /* data format must be set before clipping/scaling */
+               vino_set_scaling(&tempvcs, pf->width, pf->height);
+
+               dprintk("data format = %s\n",
+                      vino_data_formats[tempvcs.data_format].description);
+
+               pf->width = (tempvcs.clipping.right - tempvcs.clipping.left) /
+                       tempvcs.decimation;
+               pf->height = (tempvcs.clipping.bottom - tempvcs.clipping.top) /
+                       tempvcs.decimation;
+
+               pf->field = V4L2_FIELD_INTERLACED;
+               pf->bytesperline = tempvcs.line_size;
+               pf->sizeimage = tempvcs.line_size *
+                       (tempvcs.clipping.bottom - tempvcs.clipping.top) /
+                       tempvcs.decimation;
+               pf->colorspace =
+                       vino_data_formats[tempvcs.data_format].colorspace;
+
+               pf->priv = 0;
+               break;
+       }
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vino_v4l2_g_fmt(struct vino_channel_settings *vcs,
+                          struct v4l2_format *f)
+{
+       switch (f->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+               struct v4l2_pix_format *pf = &f->fmt.pix;
+               spin_lock(&vino_drvdata->input_lock);
+
+               pf->width = (vcs->clipping.right - vcs->clipping.left) /
+                       vcs->decimation;
+               pf->height = (vcs->clipping.bottom - vcs->clipping.top) /
+                       vcs->decimation;
+               pf->pixelformat =
+                       vino_data_formats[vcs->data_format].pixelformat;
+
+               pf->field = V4L2_FIELD_INTERLACED;
+               pf->bytesperline = vcs->line_size;
+               pf->sizeimage = vcs->line_size *
+                       (vcs->clipping.bottom - vcs->clipping.top) /
+                       vcs->decimation;
+               pf->colorspace =
+                       vino_data_formats[vcs->data_format].colorspace;
+
+               pf->priv = 0;
+
+               spin_unlock(&vino_drvdata->input_lock);
+               break;
+       }
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vino_v4l2_s_fmt(struct vino_channel_settings *vcs,
+                          struct v4l2_format *f)
+{
+       int data_format;
+
+       switch (f->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+               struct v4l2_pix_format *pf = &f->fmt.pix;
+               spin_lock(&vino_drvdata->input_lock);
+
+               if (!vino_is_input_owner(vcs)) {
+                       spin_unlock(&vino_drvdata->input_lock);
+                       return -EINVAL;
+               }
+
+               data_format = vino_find_data_format(pf->pixelformat);
+               if (data_format == VINO_DATA_FMT_NONE) {
+                       vcs->data_format = VINO_DATA_FMT_RGB32;
+                       pf->pixelformat =
+                               vino_data_formats[vcs->data_format].
+                               pixelformat;
+               } else {
+                       vcs->data_format = data_format;
+               }
+
+               /* data format must be set before clipping/scaling */
+               vino_set_scaling(vcs, pf->width, pf->height);
+
+               dprintk("data format = %s\n",
+                      vino_data_formats[vcs->data_format].description);
+
+               pf->width = vcs->clipping.right - vcs->clipping.left;
+               pf->height = vcs->clipping.bottom - vcs->clipping.top;
+
+               pf->field = V4L2_FIELD_INTERLACED;
+               pf->bytesperline = vcs->line_size;
+               pf->sizeimage = vcs->line_size *
+                       (vcs->clipping.bottom - vcs->clipping.top) /
+                       vcs->decimation;
+               pf->colorspace =
+                       vino_data_formats[vcs->data_format].colorspace;
+
+               pf->priv = 0;
+
+               spin_unlock(&vino_drvdata->input_lock);
+               break;
+       }
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vino_v4l2_cropcap(struct vino_channel_settings *vcs,
+                            struct v4l2_cropcap *ccap)
+{
+       const struct vino_data_norm *norm;
+
+       switch (ccap->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               spin_lock(&vino_drvdata->input_lock);
+               norm = &vino_data_norms[vcs->data_norm];
+               spin_unlock(&vino_drvdata->input_lock);
+
+               ccap->bounds.left = 0;
+               ccap->bounds.top = 0;
+               ccap->bounds.width = norm->width;
+               ccap->bounds.height = norm->height;
+               memcpy(&ccap->defrect, &ccap->bounds,
+                      sizeof(struct v4l2_rect));
+
+               ccap->pixelaspect.numerator = 1;
+               ccap->pixelaspect.denominator = 1;
+               break;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vino_v4l2_g_crop(struct vino_channel_settings *vcs,
+                           struct v4l2_crop *c)
+{
+       switch (c->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               spin_lock(&vino_drvdata->input_lock);
+
+               c->c.left = vcs->clipping.left;
+               c->c.top = vcs->clipping.top;
+               c->c.width = vcs->clipping.right - vcs->clipping.left;
+               c->c.height = vcs->clipping.bottom - vcs->clipping.top;
+
+               spin_unlock(&vino_drvdata->input_lock);
+               break;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vino_v4l2_s_crop(struct vino_channel_settings *vcs,
+                           struct v4l2_crop *c)
+{
+       switch (c->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               spin_lock(&vino_drvdata->input_lock);
+
+               if (!vino_is_input_owner(vcs)) {
+                       spin_unlock(&vino_drvdata->input_lock);
+                       return -EINVAL;
+               }
+               vino_set_clipping(vcs, c->c.left, c->c.top,
+                                 c->c.width, c->c.height);
+
+               spin_unlock(&vino_drvdata->input_lock);
+               break;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vino_v4l2_g_parm(struct vino_channel_settings *vcs,
+                           struct v4l2_streamparm *sp)
+{
+       switch (sp->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+               struct v4l2_captureparm *cp = &sp->parm.capture;
+               memset(cp, 0, sizeof(struct v4l2_captureparm));
+
+               cp->capability = V4L2_CAP_TIMEPERFRAME;
+               cp->timeperframe.numerator = 1;
+
+               spin_lock(&vino_drvdata->input_lock);
+               cp->timeperframe.denominator = vcs->fps;
+               spin_unlock(&vino_drvdata->input_lock);
+
+               // TODO: cp->readbuffers = xxx;
+               break;
+       }
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vino_v4l2_s_parm(struct vino_channel_settings *vcs,
+                           struct v4l2_streamparm *sp)
+{
+       switch (sp->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+               struct v4l2_captureparm *cp = &sp->parm.capture;
+
+               spin_lock(&vino_drvdata->input_lock);
+               if (!vino_is_input_owner(vcs)) {
+                       spin_unlock(&vino_drvdata->input_lock);
+                       return -EINVAL;
+               }
+
+               if ((cp->timeperframe.numerator == 0) ||
+                   (cp->timeperframe.denominator == 0)) {
+                       /* reset framerate */
+                       vino_set_default_framerate(vcs);
+               } else {
+                       vino_set_framerate(vcs, cp->timeperframe.denominator /
+                                          cp->timeperframe.numerator);
+               }
+               spin_unlock(&vino_drvdata->input_lock);
+
+               // TODO: set buffers according to cp->readbuffers
+               break;
+       }
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vino_v4l2_reqbufs(struct vino_channel_settings *vcs,
+                            struct v4l2_requestbuffers *rb)
+{
+       if (vcs->reading)
+               return -EBUSY;
+
+       switch (rb->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+               // TODO: check queue type
+               if (rb->memory != V4L2_MEMORY_MMAP) {
+                       dprintk("type not mmap\n");
+                       return -EINVAL;
+               }
+
+               if (vino_is_capturing(vcs)) {
+                       dprintk("busy, capturing\n");
+                       return -EBUSY;
+               }
+
+               dprintk("count = %d\n", rb->count);
+               if (rb->count > 0) {
+                       if (vino_queue_has_mapped_buffers(&vcs->fb_queue)) {
+                               dprintk("busy, buffers still mapped\n");
+                               return -EBUSY;
+                       } else {
+                               vino_queue_free(&vcs->fb_queue);
+                               vino_queue_init(&vcs->fb_queue, &rb->count);
+                       }
+               } else {
+                       vino_capture_stop(vcs);
+                       vino_queue_free(&vcs->fb_queue);
+               }
+               break;
+       }
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void vino_v4l2_get_buffer_status(struct vino_channel_settings *vcs,
+                                       struct vino_framebuffer *fb,
+                                       struct v4l2_buffer *b)
+{
+       if (vino_queue_outgoing_contains(&vcs->fb_queue,
+                                        fb->id)) {
+               b->flags &= ~V4L2_BUF_FLAG_QUEUED;
+               b->flags |= V4L2_BUF_FLAG_DONE;
+       } else if (vino_queue_incoming_contains(&vcs->fb_queue,
+                                      fb->id)) {
+               b->flags &= ~V4L2_BUF_FLAG_DONE;
+               b->flags |= V4L2_BUF_FLAG_QUEUED;
+       } else {
+               b->flags &= ~(V4L2_BUF_FLAG_DONE |
+                             V4L2_BUF_FLAG_QUEUED);
+       }
+
+       b->flags &= ~(V4L2_BUF_FLAG_TIMECODE);
+
+       if (fb->map_count > 0)
+               b->flags |= V4L2_BUF_FLAG_MAPPED;
+
+       b->index = fb->id;
+       b->memory = (vcs->fb_queue.type == VINO_MEMORY_MMAP) ?
+               V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR;
+       b->m.offset = fb->offset;
+       b->bytesused = fb->data_size;
+       b->length = fb->size;
+       b->field = V4L2_FIELD_INTERLACED;
+       b->sequence = fb->frame_counter;
+       memcpy(&b->timestamp, &fb->timestamp,
+              sizeof(struct timeval));
+       // b->input ?
+
+       dprintk("buffer %d: length = %d, bytesused = %d, offset = %d\n",
+               fb->id, fb->size, fb->data_size, fb->offset);
+}
+
+static int vino_v4l2_querybuf(struct vino_channel_settings *vcs,
+                             struct v4l2_buffer *b)
+{
+       if (vcs->reading)
+               return -EBUSY;
+
+       switch (b->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+               struct vino_framebuffer *fb;
+
+               // TODO: check queue type
+               if (b->index >= vino_queue_get_length(&vcs->fb_queue)) {
+                       dprintk("invalid index = %d\n",
+                              b->index);
+                       return -EINVAL;
+               }
+
+               fb = vino_queue_get_buffer(&vcs->fb_queue,
+                                          b->index);
+               if (fb == NULL) {
+                       dprintk("vino_queue_get_buffer() failed");
+                       return -EINVAL;
+               }
+
+               vino_v4l2_get_buffer_status(vcs, fb, b);
+               break;
+       }
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vino_v4l2_qbuf(struct vino_channel_settings *vcs,
+                         struct v4l2_buffer *b)
+{
+       if (vcs->reading)
+               return -EBUSY;
+
+       switch (b->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+               struct vino_framebuffer *fb;
+               int ret;
+
+               // TODO: check queue type
+               if (b->memory != V4L2_MEMORY_MMAP) {
+                       dprintk("type not mmap\n");
+                       return -EINVAL;
+               }
+
+               fb = vino_capture_enqueue(vcs, b->index);
+               if (fb == NULL)
+                       return -EINVAL;
+
+               vino_v4l2_get_buffer_status(vcs, fb, b);
+
+               if (vcs->streaming) {
+                       ret = vino_capture_next(vcs, 1);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       }
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vino_v4l2_dqbuf(struct vino_channel_settings *vcs,
+                          struct v4l2_buffer *b,
+                          unsigned int nonblocking)
+{
+       if (vcs->reading)
+               return -EBUSY;
+
+       switch (b->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+               struct vino_framebuffer *fb;
+               unsigned int incoming, outgoing;
+               int err;
+
+               // TODO: check queue type
+
+               err = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
+               if (err) {
+                       dprintk("vino_queue_get_incoming() failed\n");
+                       return -EIO;
+               }
+               err = vino_queue_get_outgoing(&vcs->fb_queue, &outgoing);
+               if (err) {
+                       dprintk("vino_queue_get_outgoing() failed\n");
+                       return -EIO;
+               }
+
+               dprintk("incoming = %d, outgoing = %d\n", incoming, outgoing);
+
+               if (outgoing == 0) {
+                       if (incoming == 0) {
+                               dprintk("no incoming or outgoing buffers\n");
+                               return -EINVAL;
+                       }
+                       if (nonblocking) {
+                               dprintk("non-blocking I/O was selected and "
+                                       "there are no buffers to dequeue\n");
+                               return -EAGAIN;
+                       }
+
+                       err = vino_wait_for_frame(vcs);
+                       if (err) {
+                               err = vino_wait_for_frame(vcs);
+                               if (err) {
+                                       /* interrupted */
+                                       vino_capture_failed(vcs);
+                                       return -EIO;
+                               }
+                       }
+               }
+
+               fb = vino_queue_remove(&vcs->fb_queue, &b->index);
+               if (fb == NULL) {
+                       dprintk("vino_queue_remove() failed\n");
+                       return -EINVAL;
+               }
+
+               err = vino_check_buffer(vcs, fb);
+               if (err)
+                       return -EIO;
+
+               vino_v4l2_get_buffer_status(vcs, fb, b);
+               break;
+       }
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vino_v4l2_streamon(struct vino_channel_settings *vcs)
+{
+       unsigned int incoming;
+       int ret;
+       if (vcs->reading)
+               return -EBUSY;
+
+       if (vcs->streaming)
+               return 0;
+
+       // TODO: check queue type
+
+       if (vino_queue_get_length(&vcs->fb_queue) < 1) {
+               dprintk("no buffers allocated\n");
+               return -EINVAL;
+       }
+
+       ret = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
+       if (ret) {
+               dprintk("vino_queue_get_incoming() failed\n");
+               return -EINVAL;
+       }
+
+       vcs->streaming = 1;
+
+       if (incoming > 0) {
+               ret = vino_capture_next(vcs, 1);
+               if (ret) {
+                       vcs->streaming = 0;
+
+                       dprintk("couldn't start capture\n");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static int vino_v4l2_streamoff(struct vino_channel_settings *vcs)
+{
+       if (vcs->reading)
+               return -EBUSY;
+
+       if (!vcs->streaming)
+               return 0;
+
+       vino_capture_stop(vcs);
+       vcs->streaming = 0;
+
+       return 0;
+}
+
+static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs,
+                              struct v4l2_queryctrl *queryctrl)
+{
+       int i;
+       int err = 0;
+
+       spin_lock(&vino_drvdata->input_lock);
+
+       switch (vcs->input) {
+       case VINO_INPUT_D1:
+               for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
+                       if (vino_indycam_v4l2_controls[i].id ==
+                           queryctrl->id) {
+                               memcpy(queryctrl,
+                                      &vino_indycam_v4l2_controls[i],
+                                      sizeof(struct v4l2_queryctrl));
+                               goto found;
+                       }
+               }
+
+               err =  -EINVAL;
+               break;
+       case VINO_INPUT_COMPOSITE:
+       case VINO_INPUT_SVIDEO:
+               for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
+                       if (vino_saa7191_v4l2_controls[i].id ==
+                           queryctrl->id) {
+                               memcpy(queryctrl,
+                                      &vino_saa7191_v4l2_controls[i],
+                                      sizeof(struct v4l2_queryctrl));
+                               goto found;
+                       }
+               }
+
+               err =  -EINVAL;
+               break;
+       default:
+               err =  -EINVAL;
+       }
+
+ found:
+       spin_unlock(&vino_drvdata->input_lock);
+
+       return err;
+}
+
+static int vino_v4l2_g_ctrl(struct vino_channel_settings *vcs,
+                           struct v4l2_control *control)
+{
+       struct indycam_control indycam_ctrl;
+       struct saa7191_control saa7191_ctrl;
+       int err = 0;
+
+       spin_lock(&vino_drvdata->input_lock);
+
+       switch (vcs->input) {
+       case VINO_INPUT_D1:
+               i2c_camera_command(DECODER_INDYCAM_GET_CONTROLS,
+                                  &indycam_ctrl);
+
+               switch(control->id) {
+               case V4L2_CID_AUTOGAIN:
+                       control->value = indycam_ctrl.agc;
+                       break;
+               case V4L2_CID_AUTO_WHITE_BALANCE:
+                       control->value = indycam_ctrl.awb;
+                       break;
+               case V4L2_CID_GAIN:
+                       control->value = indycam_ctrl.gain;
+                       break;
+               case V4L2_CID_PRIVATE_BASE:
+                       control->value = indycam_ctrl.red_saturation;
+                       break;
+               case V4L2_CID_PRIVATE_BASE + 1:
+                       control->value = indycam_ctrl.blue_saturation;
+                       break;
+               case V4L2_CID_RED_BALANCE:
+                       control->value = indycam_ctrl.red_balance;
+                       break;
+               case V4L2_CID_BLUE_BALANCE:
+                       control->value = indycam_ctrl.blue_balance;
+                       break;
+               case V4L2_CID_EXPOSURE:
+                       control->value = indycam_ctrl.shutter;
+                       break;
+               case V4L2_CID_GAMMA:
+                       control->value = indycam_ctrl.gamma;
+                       break;
+               default:
+                       err = -EINVAL;
+               }
+               break;
+       case VINO_INPUT_COMPOSITE:
+       case VINO_INPUT_SVIDEO:
+               i2c_decoder_command(DECODER_SAA7191_GET_CONTROLS,
+                                  &saa7191_ctrl);
+
+               switch(control->id) {
+               case V4L2_CID_HUE:
+                       control->value = saa7191_ctrl.hue;
+                       break;
+               case V4L2_CID_PRIVATE_BASE:
+                       control->value = saa7191_ctrl.vtrc;
+                       break;
+               default:
+                       err = -EINVAL;
+               }
+               break;
+       default:
+               err =  -EINVAL;
+       }
+
+       spin_unlock(&vino_drvdata->input_lock);
+
+       return err;
+}
+
+static int vino_v4l2_s_ctrl(struct vino_channel_settings *vcs,
+                           struct v4l2_control *control)
+{
+       struct indycam_control indycam_ctrl;
+       struct saa7191_control saa7191_ctrl;
+       int i;
+       int err = 0;
+
+       spin_lock(&vino_drvdata->input_lock);
+
+       switch (vcs->input) {
+       case VINO_INPUT_D1:
+               for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
+                       if (vino_indycam_v4l2_controls[i].id ==
+                           control->id) {
+                               if ((control->value >=
+                                    vino_indycam_v4l2_controls[i].minimum)
+                                   && (control->value <=
+                                       vino_indycam_v4l2_controls[i].
+                                       maximum)) {
+                                       goto ok1;
+                               } else {
+                                       err = -ERANGE;
+                                       goto error;
+                               }
+                       }
+               }
+               err = -EINVAL;
+               goto error;
+
+ok1:
+               indycam_ctrl.agc = INDYCAM_VALUE_UNCHANGED;
+               indycam_ctrl.awb = INDYCAM_VALUE_UNCHANGED;
+               indycam_ctrl.shutter = INDYCAM_VALUE_UNCHANGED;
+               indycam_ctrl.gain = INDYCAM_VALUE_UNCHANGED;
+               indycam_ctrl.red_balance = INDYCAM_VALUE_UNCHANGED;
+               indycam_ctrl.blue_balance = INDYCAM_VALUE_UNCHANGED;
+               indycam_ctrl.red_saturation = INDYCAM_VALUE_UNCHANGED;
+               indycam_ctrl.blue_saturation = INDYCAM_VALUE_UNCHANGED;
+               indycam_ctrl.gamma = INDYCAM_VALUE_UNCHANGED;
+
+               switch(control->id) {
+               case V4L2_CID_AUTOGAIN:
+                       indycam_ctrl.agc = control->value;
+                       break;
+               case V4L2_CID_AUTO_WHITE_BALANCE:
+                       indycam_ctrl.awb = control->value;
+                       break;
+               case V4L2_CID_GAIN:
+                       indycam_ctrl.gain = control->value;
+                       break;
+               case V4L2_CID_PRIVATE_BASE:
+                       indycam_ctrl.red_saturation = control->value;
+                       break;
+               case V4L2_CID_PRIVATE_BASE + 1:
+                       indycam_ctrl.blue_saturation = control->value;
+                       break;
+               case V4L2_CID_RED_BALANCE:
+                       indycam_ctrl.red_balance = control->value;
+                       break;
+               case V4L2_CID_BLUE_BALANCE:
+                       indycam_ctrl.blue_balance = control->value;
+                       break;
+               case V4L2_CID_EXPOSURE:
+                       indycam_ctrl.shutter = control->value;
+                       break;
+               case V4L2_CID_GAMMA:
+                       indycam_ctrl.gamma = control->value;
+                       break;
+               default:
+                       err =  -EINVAL;
+               }
+
+               if (!err)
+                       i2c_camera_command(DECODER_INDYCAM_SET_CONTROLS,
+                                          &indycam_ctrl);
+               break;
+       case VINO_INPUT_COMPOSITE:
+       case VINO_INPUT_SVIDEO:
+               for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
+                       if (vino_saa7191_v4l2_controls[i].id ==
+                           control->id) {
+                               if ((control->value >=
+                                    vino_saa7191_v4l2_controls[i].minimum)
+                                   && (control->value <=
+                                       vino_saa7191_v4l2_controls[i].
+                                       maximum)) {
+                                       goto ok2;
+                               } else {
+                                       err = -ERANGE;
+                                       goto error;
+                               }
+                       }
+               }
+               err = -EINVAL;
+               goto error;
+
+ok2:
+               saa7191_ctrl.hue = SAA7191_VALUE_UNCHANGED;
+               saa7191_ctrl.vtrc = SAA7191_VALUE_UNCHANGED;
+
+               switch(control->id) {
+               case V4L2_CID_HUE:
+                       saa7191_ctrl.hue = control->value;
+                       break;
+               case V4L2_CID_PRIVATE_BASE:
+                       saa7191_ctrl.vtrc = control->value;
+                       break;
+               default:
+                       err =  -EINVAL;
+               }
+
+               if (!err)
+                       i2c_decoder_command(DECODER_SAA7191_SET_CONTROLS,
+                                           &saa7191_ctrl);
+               break;
+       default:
+               err =  -EINVAL;
+       }
+
+error:
+       spin_unlock(&vino_drvdata->input_lock);
+
+       return err;
+}
+
+/* File operations */
+
+static int vino_open(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct vino_channel_settings *vcs = video_get_drvdata(dev);
+       int ret = 0;
+       dprintk("open(): channel = %c\n",
+              (vcs->channel == VINO_CHANNEL_A) ? 'A' : 'B');
+
+       down(&vcs->sem);
+
+       if (vcs->users) {
+               dprintk("open(): driver busy\n");
+               ret = -EBUSY;
+               goto out;
+       }
+
+       ret = vino_acquire_input(vcs);
+       if (ret) {
+               dprintk("open(): vino_acquire_input() failed\n");
+               goto out;
+       }
+
+       vcs->users++;
+
+ out:
+       up(&vcs->sem);
+
+       dprintk("open(): %s!\n", ret ? "failed" : "complete");
+
+       return ret;
+}
+
+static int vino_close(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct vino_channel_settings *vcs = video_get_drvdata(dev);
+       dprintk("close():\n");
+
+       down(&vcs->sem);
+
+       vcs->users--;
+
+       if (!vcs->users) {
+               vino_release_input(vcs);
+
+               /* stop DMA and free buffers */
+               vino_capture_stop(vcs);
+               vino_queue_free(&vcs->fb_queue);
+       }
+
+       up(&vcs->sem);
+
+       return 0;
+}
+
+static void vino_vm_open(struct vm_area_struct *vma)
+{
+       struct vino_framebuffer *fb = vma->vm_private_data;
+
+       fb->map_count++;
+       dprintk("vino_vm_open(): count = %d\n", fb->map_count);
+}
+
+static void vino_vm_close(struct vm_area_struct *vma)
+{
+       struct vino_framebuffer *fb = vma->vm_private_data;
+
+       fb->map_count--;
+       dprintk("vino_vm_close(): count = %d\n", fb->map_count);
+}
+
+static struct vm_operations_struct vino_vm_ops = {
+       .open   = vino_vm_open,
+       .close  = vino_vm_close,
+};
+
+static int vino_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct video_device *dev = video_devdata(file);
+       struct vino_channel_settings *vcs = video_get_drvdata(dev);
+
+       unsigned long start = vma->vm_start;
+       unsigned long size = vma->vm_end - vma->vm_start;
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+       struct vino_framebuffer *fb = NULL;
+       unsigned int i, length;
+       int ret = 0;
+
+       dprintk("mmap():\n");
+
+       // TODO: reject mmap if already mapped
+
+       if (down_interruptible(&vcs->sem))
+               return -EINTR;
+
+       if (vcs->reading) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       // TODO: check queue type
+
+       if (!(vma->vm_flags & VM_WRITE)) {
+               dprintk("mmap(): app bug: PROT_WRITE please\n");
+               ret = -EINVAL;
+               goto out;
+       }
+       if (!(vma->vm_flags & VM_SHARED)) {
+               dprintk("mmap(): app bug: MAP_SHARED please\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* find the correct buffer using offset */
+       length = vino_queue_get_length(&vcs->fb_queue);
+       if (length == 0) {
+               dprintk("mmap(): queue not initialized\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       for (i = 0; i < length; i++) {
+               fb = vino_queue_get_buffer(&vcs->fb_queue, i);
+               if (fb == NULL) {
+                       dprintk("mmap(): vino_queue_get_buffer() failed\n");
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               if (fb->offset == offset)
+                       goto found;
+       }
+
+       dprintk("mmap(): invalid offset = %lu\n", offset);
+       ret = -EINVAL;
+       goto out;
+
+found:
+       dprintk("mmap(): buffer = %d\n", i);
+
+       if (size > (fb->desc_table.page_count * PAGE_SIZE)) {
+               dprintk("mmap(): failed: size = %lu > %lu\n",
+                       size, fb->desc_table.page_count * PAGE_SIZE);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       for (i = 0; i < fb->desc_table.page_count; i++) {
+               unsigned long pfn =
+                       virt_to_phys((void *)fb->desc_table.virtual[i]) >>
+                       PAGE_SHIFT;
+
+               if (size < PAGE_SIZE)
+                       break;
+
+               // protection was: PAGE_READONLY
+               if (remap_pfn_range(vma, start, pfn, PAGE_SIZE,
+                                   vma->vm_page_prot)) {
+                       dprintk("mmap(): remap_pfn_range() failed\n");
+                       ret = -EAGAIN;
+                       goto out;
+               }
+
+               start += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       fb->map_count = 1;
+
+       vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
+       vma->vm_flags &= ~VM_IO;
+       vma->vm_private_data = fb;
+       vma->vm_file = file;
+       vma->vm_ops = &vino_vm_ops;
+
+out:
+       up(&vcs->sem);
+
+       return ret;
+}
+
+static unsigned int vino_poll(struct file *file, poll_table *pt)
+{
+       struct video_device *dev = video_devdata(file);
+       struct vino_channel_settings *vcs = video_get_drvdata(dev);
+       unsigned int outgoing;
+       unsigned int ret = 0;
+
+       // lock mutex (?)
+       // TODO: this has to be corrected for different read modes
+
+       dprintk("poll():\n");
+
+       if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
+               dprintk("poll(): vino_queue_get_outgoing() failed\n");
+               ret = POLLERR;
+               goto error;
+       }
+       if (outgoing > 0)
+               goto over;
+
+       poll_wait(file, &vcs->fb_queue.frame_wait_queue, pt);
+
+       if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
+               dprintk("poll(): vino_queue_get_outgoing() failed\n");
+               ret = POLLERR;
+               goto error;
+       }
+
+over:
+       dprintk("poll(): data %savailable\n",
+               (outgoing > 0) ? "" : "not ");
+       if (outgoing > 0) {
+               ret = POLLIN | POLLRDNORM;
+       }
+
+error:
+
+       return ret;
+}
+
+static int vino_do_ioctl(struct inode *inode, struct file *file,
+                     unsigned int cmd, void *arg)
+{
+       struct video_device *dev = video_devdata(file);
+       struct vino_channel_settings *vcs = video_get_drvdata(dev);
+
+       switch (_IOC_TYPE(cmd)) {
+       case 'v':
+               dprintk("ioctl(): V4L1 unsupported (0x%08x)\n", cmd);
+               break;
+       case 'V':
+               dprintk("ioctl(): V4L2 %s (0x%08x)\n",
+                       v4l2_ioctl_names[_IOC_NR(cmd)], cmd);
+               break;
+       default:
+               dprintk("ioctl(): unsupported command 0x%08x\n", cmd);
+       }
+
+       switch (cmd) {
+       /* TODO: V4L1 interface (use compatibility layer?) */
+       /* V4L2 interface */
+       case VIDIOC_QUERYCAP: {
+               vino_v4l2_querycap(arg);
+               break;
+       }
+       case VIDIOC_ENUMINPUT: {
+               return vino_v4l2_enuminput(vcs, arg);
+       }
+       case VIDIOC_G_INPUT: {
+               return vino_v4l2_g_input(vcs, arg);
+       }
+       case VIDIOC_S_INPUT: {
+               return vino_v4l2_s_input(vcs, arg);
+       }
+       case VIDIOC_ENUMSTD: {
+               return vino_v4l2_enumstd(vcs, arg);
+       }
+       case VIDIOC_G_STD: {
+               return vino_v4l2_g_std(vcs, arg);
+       }
+       case VIDIOC_S_STD: {
+               return vino_v4l2_s_std(vcs, arg);
+       }
+       case VIDIOC_ENUM_FMT: {
+               return vino_v4l2_enum_fmt(vcs, arg);
+       }
+       case VIDIOC_TRY_FMT: {
+               return vino_v4l2_try_fmt(vcs, arg);
+       }
+       case VIDIOC_G_FMT: {
+               return vino_v4l2_g_fmt(vcs, arg);
+       }
+       case VIDIOC_S_FMT: {
+               return vino_v4l2_s_fmt(vcs, arg);
+       }
+       case VIDIOC_CROPCAP: {
+               return vino_v4l2_cropcap(vcs, arg);
+       }
+       case VIDIOC_G_CROP: {
+               return vino_v4l2_g_crop(vcs, arg);
+       }
+       case VIDIOC_S_CROP: {
+               return vino_v4l2_s_crop(vcs, arg);
+       }
+       case VIDIOC_G_PARM: {
+               return vino_v4l2_g_parm(vcs, arg);
+       }
+       case VIDIOC_S_PARM: {
+               return vino_v4l2_s_parm(vcs, arg);
+       }
+       case VIDIOC_REQBUFS: {
+               return vino_v4l2_reqbufs(vcs, arg);
+       }
+       case VIDIOC_QUERYBUF: {
+               return vino_v4l2_querybuf(vcs, arg);
+       }
+       case VIDIOC_QBUF: {
+               return vino_v4l2_qbuf(vcs, arg);
+       }
+       case VIDIOC_DQBUF: {
+               return vino_v4l2_dqbuf(vcs, arg, file->f_flags & O_NONBLOCK);
+       }
+       case VIDIOC_STREAMON: {
+               return vino_v4l2_streamon(vcs);
+       }
+       case VIDIOC_STREAMOFF: {
+               return vino_v4l2_streamoff(vcs);
+       }
+       case VIDIOC_QUERYCTRL: {
+               return vino_v4l2_queryctrl(vcs, arg);
+       }
+       case VIDIOC_G_CTRL: {
+               return vino_v4l2_g_ctrl(vcs, arg);
+       }
+       case VIDIOC_S_CTRL: {
+               return vino_v4l2_s_ctrl(vcs, arg);
+       }
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       return 0;
+}
+
+static int vino_ioctl(struct inode *inode, struct file *file,
+                     unsigned int cmd, unsigned long arg)
+{
+       struct video_device *dev = video_devdata(file);
+       struct vino_channel_settings *vcs = video_get_drvdata(dev);
+       int ret;
+
+       if (down_interruptible(&vcs->sem))
+               return -EINTR;
+
+       ret = video_usercopy(inode, file, cmd, arg, vino_do_ioctl);
+
+       up(&vcs->sem);
+
+       return ret;
+}
+
+/* Initialization and cleanup */
+
+// __initdata
+static int vino_init_stage = 0;
+
+static struct file_operations vino_fops = {
+       .owner          = THIS_MODULE,
+       .open           = vino_open,
+       .release        = vino_close,
+       .ioctl          = vino_ioctl,
+       .mmap           = vino_mmap,
+       .poll           = vino_poll,
+       .llseek         = no_llseek,
+};
+
+static struct video_device v4l_device_template = {
+       .name           = "NOT SET",
+       //.type         = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE |
+       //      VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY
+       .hardware       = VID_HARDWARE_VINO,
+       .fops           = &vino_fops,
+       .minor          = -1,
+};
+
+static void vino_module_cleanup(int stage)
+{
+       switch(stage) {
+       case 10:
+               video_unregister_device(vino_drvdata->b.v4l_device);
+               vino_drvdata->b.v4l_device = NULL;
+       case 9:
+               video_unregister_device(vino_drvdata->a.v4l_device);
+               vino_drvdata->a.v4l_device = NULL;
+       case 8:
+               vino_i2c_del_bus();
+       case 7:
+               free_irq(SGI_VINO_IRQ, NULL);
+       case 6:
+               if (vino_drvdata->b.v4l_device) {
+                       video_device_release(vino_drvdata->b.v4l_device);
+                       vino_drvdata->b.v4l_device = NULL;
+               }
+       case 5:
+               if (vino_drvdata->a.v4l_device) {
+                       video_device_release(vino_drvdata->a.v4l_device);
+                       vino_drvdata->a.v4l_device = NULL;
+               }
+       case 4:
+               /* all entries in dma_cpu dummy table have the same address */
+               dma_unmap_single(NULL,
+                                vino_drvdata->dummy_desc_table.dma_cpu[0],
+                                PAGE_SIZE, DMA_FROM_DEVICE);
+               dma_free_coherent(NULL, VINO_DUMMY_DESC_COUNT
+                                 * sizeof(dma_addr_t),
+                                 (void *)vino_drvdata->
+                                 dummy_desc_table.dma_cpu,
+                                 vino_drvdata->dummy_desc_table.dma);
+       case 3:
+               free_page(vino_drvdata->dummy_page);
+       case 2:
+               kfree(vino_drvdata);
+       case 1:
+               iounmap(vino);
+       case 0:
+               break;
+       default:
+               dprintk("vino_module_cleanup(): invalid cleanup stage = %d\n",
+                       stage);
+       }
+}
+
+static int vino_probe(void)
+{
+       unsigned long rev_id;
+
+       if (ip22_is_fullhouse()) {
+               printk(KERN_ERR "VINO doesn't exist in IP22 Fullhouse\n");
+               return -ENODEV;
+       }
+
+       if (!(sgimc->systemid & SGIMC_SYSID_EPRESENT)) {
+               printk(KERN_ERR "VINO is not found (EISA BUS not present)\n");
+               return -ENODEV;
+       }
+
+       vino = (struct sgi_vino *)ioremap(VINO_BASE, sizeof(struct sgi_vino));
+       if (!vino) {
+               printk(KERN_ERR "VINO: ioremap() failed\n");
+               return -EIO;
+       }
+       vino_init_stage++;
+
+       if (get_dbe(rev_id, &(vino->rev_id))) {
+               printk(KERN_ERR "Failed to read VINO revision register\n");
+               vino_module_cleanup(vino_init_stage);
+               return -ENODEV;
+       }
+
+       if (VINO_ID_VALUE(rev_id) != VINO_CHIP_ID) {
+               printk(KERN_ERR "Unknown VINO chip ID (Rev/ID: 0x%02lx)\n",
+                      rev_id);
+               vino_module_cleanup(vino_init_stage);
+               return -ENODEV;
+       }
+
+       printk(KERN_INFO "VINO with chip ID %ld, revision %ld found\n",
+              VINO_ID_VALUE(rev_id), VINO_REV_NUM(rev_id));
+
+       return 0;
+}
+
+static int vino_init(void)
+{
+       dma_addr_t dma_dummy_address;
+       int i;
+
+       vino_drvdata = (struct vino_settings *)
+               kmalloc(sizeof(struct vino_settings), GFP_KERNEL);
+       if (!vino_drvdata) {
+               vino_module_cleanup(vino_init_stage);
+               return -ENOMEM;
+       }
+       memset(vino_drvdata, 0, sizeof(struct vino_settings));
+       vino_init_stage++;
+
+       /* create a dummy dma descriptor */
+       vino_drvdata->dummy_page = get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!vino_drvdata->dummy_page) {
+               vino_module_cleanup(vino_init_stage);
+               return -ENOMEM;
+       }
+       vino_init_stage++;
+
+       // TODO: use page_count in dummy_desc_table
+
+       vino_drvdata->dummy_desc_table.dma_cpu =
+               dma_alloc_coherent(NULL,
+               VINO_DUMMY_DESC_COUNT * sizeof(dma_addr_t),
+               &vino_drvdata->dummy_desc_table.dma,
+               GFP_KERNEL | GFP_DMA);
+       if (!vino_drvdata->dummy_desc_table.dma_cpu) {
+               vino_module_cleanup(vino_init_stage);
+               return -ENOMEM;
+       }
+       vino_init_stage++;
+
+       dma_dummy_address = dma_map_single(NULL,
+                                          (void *)vino_drvdata->dummy_page,
+                                       PAGE_SIZE, DMA_FROM_DEVICE);
+       for (i = 0; i < VINO_DUMMY_DESC_COUNT; i++) {
+               vino_drvdata->dummy_desc_table.dma_cpu[i] = dma_dummy_address;
+       }
+
+       /* initialize VINO */
+
+       vino->control = 0;
+       vino->a.next_4_desc = vino_drvdata->dummy_desc_table.dma;
+       vino->b.next_4_desc = vino_drvdata->dummy_desc_table.dma;
+       udelay(VINO_DESC_FETCH_DELAY);
+
+       vino->intr_status = 0;
+
+       vino->a.fifo_thres = VINO_FIFO_THRESHOLD_DEFAULT;
+       vino->b.fifo_thres = VINO_FIFO_THRESHOLD_DEFAULT;
+
+       return 0;
+}
+
+static int vino_init_channel_settings(struct vino_channel_settings *vcs,
+                                unsigned int channel, const char *name)
+{
+       vcs->channel = channel;
+       vcs->input = VINO_INPUT_NONE;
+       vcs->alpha = 0;
+       vcs->users = 0;
+       vcs->data_format = VINO_DATA_FMT_GREY;
+       vcs->data_norm = VINO_DATA_NORM_NTSC;
+       vcs->decimation = 1;
+       vino_set_default_clipping(vcs);
+       vino_set_default_framerate(vcs);
+
+       vcs->capturing = 0;
+
+       init_MUTEX(&vcs->sem);
+       spin_lock_init(&vcs->capture_lock);
+
+       init_MUTEX(&vcs->fb_queue.queue_sem);
+       spin_lock_init(&vcs->fb_queue.queue_lock);
+       init_waitqueue_head(&vcs->fb_queue.frame_wait_queue);
+
+       vcs->v4l_device = video_device_alloc();
+       if (!vcs->v4l_device) {
+               vino_module_cleanup(vino_init_stage);
+               return -ENOMEM;
+       }
+       vino_init_stage++;
+
+       memcpy(vcs->v4l_device, &v4l_device_template,
+              sizeof(struct video_device));
+       strcpy(vcs->v4l_device->name, name);
+       vcs->v4l_device->release = video_device_release;
+
+       video_set_drvdata(vcs->v4l_device, vcs);
+
+       return 0;
+}
+
+static int __init vino_module_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "SGI VINO driver version %s\n",
+              VINO_MODULE_VERSION);
+
+       ret = vino_probe();
+       if (ret)
+               return ret;
+
+       ret = vino_init();
+       if (ret)
+               return ret;
+
+       /* initialize data structures */
+
+       spin_lock_init(&vino_drvdata->vino_lock);
+       spin_lock_init(&vino_drvdata->input_lock);
+
+       ret = vino_init_channel_settings(&vino_drvdata->a, VINO_CHANNEL_A,
+                                   vino_v4l_device_name_a);
+       if (ret)
+               return ret;
+
+       ret = vino_init_channel_settings(&vino_drvdata->b, VINO_CHANNEL_B,
+                                   vino_v4l_device_name_b);
+       if (ret)
+               return ret;
+
+       /* initialize hardware and register V4L devices */
+
+       ret = request_irq(SGI_VINO_IRQ, vino_interrupt, 0,
+               vino_driver_description, NULL);
+       if (ret) {
+               printk(KERN_ERR "VINO: requesting IRQ %02d failed\n",
+                      SGI_VINO_IRQ);
+               vino_module_cleanup(vino_init_stage);
+               return -EAGAIN;
+       }
+       vino_init_stage++;
+
+       ret = vino_i2c_add_bus();
+       if (ret) {
+               printk(KERN_ERR "VINO I2C bus registration failed\n");
+               vino_module_cleanup(vino_init_stage);
+               return ret;
+       }
+       vino_init_stage++;
+
+       ret = video_register_device(vino_drvdata->a.v4l_device,
+                                   VFL_TYPE_GRABBER, -1);
+       if (ret < 0) {
+               printk(KERN_ERR "VINO channel A Video4Linux-device "
+                      "registration failed\n");
+               vino_module_cleanup(vino_init_stage);
+               return -EINVAL;
+       }
+       vino_init_stage++;
+
+       ret = video_register_device(vino_drvdata->b.v4l_device,
+                                   VFL_TYPE_GRABBER, -1);
+       if (ret < 0) {
+               printk(KERN_ERR "VINO channel B Video4Linux-device "
+                      "registration failed\n");
+               vino_module_cleanup(vino_init_stage);
+               return -EINVAL;
+       }
+       vino_init_stage++;
+
+#if defined(CONFIG_KMOD) && defined(MODULE)
+       request_module("saa7191");
+       request_module("indycam");
+#endif
+
+       dprintk("init complete!\n");
+
+       return 0;
+}
+
+static void __exit vino_module_exit(void)
+{
+       dprintk("exiting, stage = %d ...\n", vino_init_stage);
+       vino_module_cleanup(vino_init_stage);
+       dprintk("cleanup complete, exit!\n");
+}
+
+module_init(vino_module_init);
+module_exit(vino_module_exit);
index d2fce472f35ab7543c58805b525e438eaae2389d..de2d615ae7c9492bc14b72eea236cb67a87331a7 100644 (file)
@@ -1,13 +1,19 @@
 /*
+ * Driver for the VINO (Video In No Out) system found in SGI Indys.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
  * Copyright (C) 1999 Ulf Karlsson <ulfc@bun.falkenberg.se>
  * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
  */
 
-#ifndef VINO_H
-#define VINO_H
+#ifndef _VINO_H_
+#define _VINO_H_
 
 #define VINO_BASE      0x00080000      /* Vino is in the EISA address space,
                                         * but it is not an EISA bus card */
+#define VINO_PAGE_SIZE 4096
 
 struct sgi_vino_channel {
        u32 _pad_alpha;
@@ -21,8 +27,9 @@ struct sgi_vino_channel {
        u32 _pad_clip_end;
        volatile u32 clip_end;
 
+#define VINO_FRAMERT_FULL      0xfff
 #define VINO_FRAMERT_PAL       (1<<0)                  /* 0=NTSC 1=PAL */
-#define VINO_FRAMERT_RT(x)     (((x) & 0x1fff) << 1)   /* bits 1:12 */
+#define VINO_FRAMERT_RT(x)     (((x) & 0xfff) << 1)    /* bits 1:12 */
        u32 _pad_frame_rate;
        volatile u32 frame_rate;
 
@@ -67,18 +74,18 @@ struct sgi_vino {
        volatile u32 rev_id;
 
 #define VINO_CTRL_LITTLE_ENDIAN                (1<<0)
-#define VINO_CTRL_A_FIELD_TRANS_INT    (1<<1)  /* Field transferred int */
-#define VINO_CTRL_A_FIFO_OF_INT                (1<<2)  /* FIFO overflow int */
-#define VINO_CTRL_A_END_DESC_TBL_INT   (1<<3)  /* End of desc table int */
-#define VINO_CTRL_A_INT                        (VINO_CTRL_A_FIELD_TRANS_INT | \
-                                        VINO_CTRL_A_FIFO_OF_INT | \
-                                        VINO_CTRL_A_END_DESC_TBL_INT)
-#define VINO_CTRL_B_FIELD_TRANS_INT    (1<<4)  /* Field transferred int */
-#define VINO_CTRL_B_FIFO_OF_INT                (1<<5)  /* FIFO overflow int */
-#define VINO_CTRL_B_END_DESC_TBL_INT   (1<<6)  /* End of desc table int */
-#define VINO_CTRL_B_INT                        (VINO_CTRL_B_FIELD_TRANS_INT | \
-                                        VINO_CTRL_B_FIFO_OF_INT | \
-                                        VINO_CTRL_B_END_DESC_TBL_INT)
+#define VINO_CTRL_A_EOF_INT            (1<<1)  /* Field transferred int */
+#define VINO_CTRL_A_FIFO_INT           (1<<2)  /* FIFO overflow int */
+#define VINO_CTRL_A_EOD_INT            (1<<3)  /* End of desc table int */
+#define VINO_CTRL_A_INT                        (VINO_CTRL_A_EOF_INT | \
+                                        VINO_CTRL_A_FIFO_INT | \
+                                        VINO_CTRL_A_EOD_INT)
+#define VINO_CTRL_B_EOF_INT            (1<<4)  /* Field transferred int */
+#define VINO_CTRL_B_FIFO_INT           (1<<5)  /* FIFO overflow int */
+#define VINO_CTRL_B_EOD_INT            (1<<6)  /* End of desc table int */
+#define VINO_CTRL_B_INT                        (VINO_CTRL_B_EOF_INT | \
+                                        VINO_CTRL_B_FIFO_INT | \
+                                        VINO_CTRL_B_EOD_INT)
 #define VINO_CTRL_A_DMA_ENBL           (1<<7)
 #define VINO_CTRL_A_INTERLEAVE_ENBL    (1<<8)
 #define VINO_CTRL_A_SYNC_ENBL          (1<<9)
@@ -104,18 +111,18 @@ struct sgi_vino {
        u32 _pad_control;
        volatile u32 control;
 
-#define VINO_INTSTAT_A_FIELD_TRANS     (1<<0)  /* Field transferred int */
-#define VINO_INTSTAT_A_FIFO_OF         (1<<1)  /* FIFO overflow int */
-#define VINO_INTSTAT_A_END_DESC_TBL    (1<<2)  /* End of desc table int */
-#define VINO_INTSTAT_A                 (VINO_INTSTAT_A_FIELD_TRANS | \
-                                        VINO_INTSTAT_A_FIFO_OF | \
-                                        VINO_INTSTAT_A_END_DESC_TBL)
-#define VINO_INTSTAT_B_FIELD_TRANS     (1<<3)  /* Field transferred int */
-#define VINO_INTSTAT_B_FIFO_OF         (1<<4)  /* FIFO overflow int */
-#define VINO_INTSTAT_B_END_DESC_TBL    (1<<5)  /* End of desc table int */
-#define VINO_INTSTAT_B                 (VINO_INTSTAT_B_FIELD_TRANS | \
-                                        VINO_INTSTAT_B_FIFO_OF | \
-                                        VINO_INTSTAT_B_END_DESC_TBL)
+#define VINO_INTSTAT_A_EOF             (1<<0)  /* Field transferred int */
+#define VINO_INTSTAT_A_FIFO            (1<<1)  /* FIFO overflow int */
+#define VINO_INTSTAT_A_EOD             (1<<2)  /* End of desc table int */
+#define VINO_INTSTAT_A                 (VINO_INTSTAT_A_EOF | \
+                                        VINO_INTSTAT_A_FIFO | \
+                                        VINO_INTSTAT_A_EOD)
+#define VINO_INTSTAT_B_EOF             (1<<3)  /* Field transferred int */
+#define VINO_INTSTAT_B_FIFO            (1<<4)  /* FIFO overflow int */
+#define VINO_INTSTAT_B_EOD             (1<<5)  /* End of desc table int */
+#define VINO_INTSTAT_B                 (VINO_INTSTAT_B_EOF | \
+                                        VINO_INTSTAT_B_FIFO | \
+                                        VINO_INTSTAT_B_EOD)
        u32 _pad_intr_status;
        volatile u32 intr_status;
 
index 5dbd9f6bf353b4730309411e514a4ba0c77a6a54..4437bdebe24f64676c3249961326aa3c1c17505d 100644 (file)
@@ -576,7 +576,6 @@ static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
        .probe                  = &ignore,
        .ignore                 = &ignore,
-       .force                  = &ignore,
 };
 
 static struct i2c_driver vpx3220_i2c_driver;
index 25743085b2d5a97a1a800939aad63ba5eb5c20ca..eed2acea17791305a94965ab63020b7f9d41459f 100644 (file)
@@ -737,7 +737,7 @@ static struct i2c_algo_bit_data zoran_i2c_bit_data_template = {
 };
 
 static struct i2c_adapter zoran_i2c_adapter_template = {
-       I2C_DEVNAME("zr36057"),
+       .name = "zr36057",
        .id = I2C_HW_B_ZR36067,
        .algo = NULL,
        .client_register = zoran_i2c_client_register,
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
new file mode 100644 (file)
index 0000000..1588a59
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# Multifunction miscellaneous devices
+#
+
+menu "Multimedia Capabilities Port drivers"
+
+config MCP
+       tristate
+
+# Interface drivers
+config MCP_SA11X0
+       tristate "Support SA11x0 MCP interface"
+       depends on ARCH_SA1100
+       select MCP
+
+endmenu
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
new file mode 100644 (file)
index 0000000..98bdd6a
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Makefile for multifunction miscellaneous devices
+#
+
+obj-$(CONFIG_MCP)              += mcp-core.o
+obj-$(CONFIG_MCP_SA11X0)       += mcp-sa11x0.o
diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
new file mode 100644 (file)
index 0000000..c75d713
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ *  linux/drivers/mfd/mcp-core.c
+ *
+ *  Copyright (C) 2001 Russell King
+ *
+ * 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.
+ *
+ *  Generic MCP (Multimedia Communications Port) layer.  All MCP locking
+ *  is solely held within this file.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/smp.h>
+#include <linux/device.h>
+
+#include <asm/dma.h>
+#include <asm/system.h>
+
+#include "mcp.h"
+
+#define to_mcp(d)              container_of(d, struct mcp, attached_device)
+#define to_mcp_driver(d)       container_of(d, struct mcp_driver, drv)
+
+static int mcp_bus_match(struct device *dev, struct device_driver *drv)
+{
+       return 1;
+}
+
+static int mcp_bus_probe(struct device *dev)
+{
+       struct mcp *mcp = to_mcp(dev);
+       struct mcp_driver *drv = to_mcp_driver(dev->driver);
+
+       return drv->probe(mcp);
+}
+
+static int mcp_bus_remove(struct device *dev)
+{
+       struct mcp *mcp = to_mcp(dev);
+       struct mcp_driver *drv = to_mcp_driver(dev->driver);
+
+       drv->remove(mcp);
+       return 0;
+}
+
+static int mcp_bus_suspend(struct device *dev, pm_message_t state)
+{
+       struct mcp *mcp = to_mcp(dev);
+       int ret = 0;
+
+       if (dev->driver) {
+               struct mcp_driver *drv = to_mcp_driver(dev->driver);
+
+               ret = drv->suspend(mcp, state);
+       }
+       return ret;
+}
+
+static int mcp_bus_resume(struct device *dev)
+{
+       struct mcp *mcp = to_mcp(dev);
+       int ret = 0;
+
+       if (dev->driver) {
+               struct mcp_driver *drv = to_mcp_driver(dev->driver);
+
+               ret = drv->resume(mcp);
+       }
+       return ret;
+}
+
+static struct bus_type mcp_bus_type = {
+       .name           = "mcp",
+       .match          = mcp_bus_match,
+       .suspend        = mcp_bus_suspend,
+       .resume         = mcp_bus_resume,
+};
+
+/**
+ *     mcp_set_telecom_divisor - set the telecom divisor
+ *     @mcp: MCP interface structure
+ *     @div: SIB clock divisor
+ *
+ *     Set the telecom divisor on the MCP interface.  The resulting
+ *     sample rate is SIBCLOCK/div.
+ */
+void mcp_set_telecom_divisor(struct mcp *mcp, unsigned int div)
+{
+       spin_lock_irq(&mcp->lock);
+       mcp->ops->set_telecom_divisor(mcp, div);
+       spin_unlock_irq(&mcp->lock);
+}
+EXPORT_SYMBOL(mcp_set_telecom_divisor);
+
+/**
+ *     mcp_set_audio_divisor - set the audio divisor
+ *     @mcp: MCP interface structure
+ *     @div: SIB clock divisor
+ *
+ *     Set the audio divisor on the MCP interface.
+ */
+void mcp_set_audio_divisor(struct mcp *mcp, unsigned int div)
+{
+       spin_lock_irq(&mcp->lock);
+       mcp->ops->set_audio_divisor(mcp, div);
+       spin_unlock_irq(&mcp->lock);
+}
+EXPORT_SYMBOL(mcp_set_audio_divisor);
+
+/**
+ *     mcp_reg_write - write a device register
+ *     @mcp: MCP interface structure
+ *     @reg: 4-bit register index
+ *     @val: 16-bit data value
+ *
+ *     Write a device register.  The MCP interface must be enabled
+ *     to prevent this function hanging.
+ */
+void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mcp->lock, flags);
+       mcp->ops->reg_write(mcp, reg, val);
+       spin_unlock_irqrestore(&mcp->lock, flags);
+}
+EXPORT_SYMBOL(mcp_reg_write);
+
+/**
+ *     mcp_reg_read - read a device register
+ *     @mcp: MCP interface structure
+ *     @reg: 4-bit register index
+ *
+ *     Read a device register and return its value.  The MCP interface
+ *     must be enabled to prevent this function hanging.
+ */
+unsigned int mcp_reg_read(struct mcp *mcp, unsigned int reg)
+{
+       unsigned long flags;
+       unsigned int val;
+
+       spin_lock_irqsave(&mcp->lock, flags);
+       val = mcp->ops->reg_read(mcp, reg);
+       spin_unlock_irqrestore(&mcp->lock, flags);
+
+       return val;
+}
+EXPORT_SYMBOL(mcp_reg_read);
+
+/**
+ *     mcp_enable - enable the MCP interface
+ *     @mcp: MCP interface to enable
+ *
+ *     Enable the MCP interface.  Each call to mcp_enable will need
+ *     a corresponding call to mcp_disable to disable the interface.
+ */
+void mcp_enable(struct mcp *mcp)
+{
+       spin_lock_irq(&mcp->lock);
+       if (mcp->use_count++ == 0)
+               mcp->ops->enable(mcp);
+       spin_unlock_irq(&mcp->lock);
+}
+EXPORT_SYMBOL(mcp_enable);
+
+/**
+ *     mcp_disable - disable the MCP interface
+ *     @mcp: MCP interface to disable
+ *
+ *     Disable the MCP interface.  The MCP interface will only be
+ *     disabled once the number of calls to mcp_enable matches the
+ *     number of calls to mcp_disable.
+ */
+void mcp_disable(struct mcp *mcp)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mcp->lock, flags);
+       if (--mcp->use_count == 0)
+               mcp->ops->disable(mcp);
+       spin_unlock_irqrestore(&mcp->lock, flags);
+}
+EXPORT_SYMBOL(mcp_disable);
+
+static void mcp_release(struct device *dev)
+{
+       struct mcp *mcp = container_of(dev, struct mcp, attached_device);
+
+       kfree(mcp);
+}
+
+struct mcp *mcp_host_alloc(struct device *parent, size_t size)
+{
+       struct mcp *mcp;
+
+       mcp = kmalloc(sizeof(struct mcp) + size, GFP_KERNEL);
+       if (mcp) {
+               memset(mcp, 0, sizeof(struct mcp) + size);
+               spin_lock_init(&mcp->lock);
+               mcp->attached_device.parent = parent;
+               mcp->attached_device.bus = &mcp_bus_type;
+               mcp->attached_device.dma_mask = parent->dma_mask;
+               mcp->attached_device.release = mcp_release;
+       }
+       return mcp;
+}
+EXPORT_SYMBOL(mcp_host_alloc);
+
+int mcp_host_register(struct mcp *mcp)
+{
+       strcpy(mcp->attached_device.bus_id, "mcp0");
+       return device_register(&mcp->attached_device);
+}
+EXPORT_SYMBOL(mcp_host_register);
+
+void mcp_host_unregister(struct mcp *mcp)
+{
+       device_unregister(&mcp->attached_device);
+}
+EXPORT_SYMBOL(mcp_host_unregister);
+
+int mcp_driver_register(struct mcp_driver *mcpdrv)
+{
+       mcpdrv->drv.bus = &mcp_bus_type;
+       mcpdrv->drv.probe = mcp_bus_probe;
+       mcpdrv->drv.remove = mcp_bus_remove;
+       return driver_register(&mcpdrv->drv);
+}
+EXPORT_SYMBOL(mcp_driver_register);
+
+void mcp_driver_unregister(struct mcp_driver *mcpdrv)
+{
+       driver_unregister(&mcpdrv->drv);
+}
+EXPORT_SYMBOL(mcp_driver_unregister);
+
+static int __init mcp_init(void)
+{
+       return bus_register(&mcp_bus_type);
+}
+
+static void __exit mcp_exit(void)
+{
+       bus_unregister(&mcp_bus_type);
+}
+
+module_init(mcp_init);
+module_exit(mcp_exit);
+
+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
+MODULE_DESCRIPTION("Core multimedia communications port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
new file mode 100644 (file)
index 0000000..e9806fb
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ *  linux/drivers/mfd/mcp-sa11x0.c
+ *
+ *  Copyright (C) 2001-2005 Russell King
+ *
+ * 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.
+ *
+ *  SA11x0 MCP (Multimedia Communications Port) driver.
+ *
+ *  MCP read/write timeouts from Jordi Colomer, rehacked by rmk.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+
+#include <asm/dma.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/system.h>
+#include <asm/arch/mcp.h>
+
+#include <asm/arch/assabet.h>
+
+#include "mcp.h"
+
+struct mcp_sa11x0 {
+       u32     mccr0;
+       u32     mccr1;
+};
+
+#define priv(mcp)      ((struct mcp_sa11x0 *)mcp_priv(mcp))
+
+static void
+mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
+{
+       unsigned int mccr0;
+
+       divisor /= 32;
+
+       mccr0 = Ser4MCCR0 & ~0x00007f00;
+       mccr0 |= divisor << 8;
+       Ser4MCCR0 = mccr0;
+}
+
+static void
+mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
+{
+       unsigned int mccr0;
+
+       divisor /= 32;
+
+       mccr0 = Ser4MCCR0 & ~0x0000007f;
+       mccr0 |= divisor;
+       Ser4MCCR0 = mccr0;
+}
+
+/*
+ * Write data to the device.  The bit should be set after 3 subframe
+ * times (each frame is 64 clocks).  We wait a maximum of 6 subframes.
+ * We really should try doing something more productive while we
+ * wait.
+ */
+static void
+mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
+{
+       int ret = -ETIME;
+       int i;
+
+       Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff);
+
+       for (i = 0; i < 2; i++) {
+               udelay(mcp->rw_timeout);
+               if (Ser4MCSR & MCSR_CWC) {
+                       ret = 0;
+                       break;
+               }
+       }
+
+       if (ret < 0)
+               printk(KERN_WARNING "mcp: write timed out\n");
+}
+
+/*
+ * Read data from the device.  The bit should be set after 3 subframe
+ * times (each frame is 64 clocks).  We wait a maximum of 6 subframes.
+ * We really should try doing something more productive while we
+ * wait.
+ */
+static unsigned int
+mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
+{
+       int ret = -ETIME;
+       int i;
+
+       Ser4MCDR2 = reg << 17 | MCDR2_Rd;
+
+       for (i = 0; i < 2; i++) {
+               udelay(mcp->rw_timeout);
+               if (Ser4MCSR & MCSR_CRC) {
+                       ret = Ser4MCDR2 & 0xffff;
+                       break;
+               }
+       }
+
+       if (ret < 0)
+               printk(KERN_WARNING "mcp: read timed out\n");
+
+       return ret;
+}
+
+static void mcp_sa11x0_enable(struct mcp *mcp)
+{
+       Ser4MCSR = -1;
+       Ser4MCCR0 |= MCCR0_MCE;
+}
+
+static void mcp_sa11x0_disable(struct mcp *mcp)
+{
+       Ser4MCCR0 &= ~MCCR0_MCE;
+}
+
+/*
+ * Our methods.
+ */
+static struct mcp_ops mcp_sa11x0 = {
+       .set_telecom_divisor    = mcp_sa11x0_set_telecom_divisor,
+       .set_audio_divisor      = mcp_sa11x0_set_audio_divisor,
+       .reg_write              = mcp_sa11x0_write,
+       .reg_read               = mcp_sa11x0_read,
+       .enable                 = mcp_sa11x0_enable,
+       .disable                = mcp_sa11x0_disable,
+};
+
+static int mcp_sa11x0_probe(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct mcp_plat_data *data = pdev->dev.platform_data;
+       struct mcp *mcp;
+       int ret;
+
+       if (!data)
+               return -ENODEV;
+
+       if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
+               return -EBUSY;
+
+       mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
+       if (!mcp) {
+               ret = -ENOMEM;
+               goto release;
+       }
+
+       mcp->owner              = THIS_MODULE;
+       mcp->ops                = &mcp_sa11x0;
+       mcp->sclk_rate          = data->sclk_rate;
+       mcp->dma_audio_rd       = DMA_Ser4MCP0Rd;
+       mcp->dma_audio_wr       = DMA_Ser4MCP0Wr;
+       mcp->dma_telco_rd       = DMA_Ser4MCP1Rd;
+       mcp->dma_telco_wr       = DMA_Ser4MCP1Wr;
+
+       dev_set_drvdata(dev, mcp);
+
+       if (machine_is_assabet()) {
+               ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
+       }
+
+       /*
+        * Setup the PPC unit correctly.
+        */
+       PPDR &= ~PPC_RXD4;
+       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+       PSDR |= PPC_RXD4;
+       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+
+       /*
+        * Initialise device.  Note that we initially
+        * set the sampling rate to minimum.
+        */
+       Ser4MCSR = -1;
+       Ser4MCCR1 = data->mccr1;
+       Ser4MCCR0 = data->mccr0 | 0x7f7f;
+
+       /*
+        * Calculate the read/write timeout (us) from the bit clock
+        * rate.  This is the period for 3 64-bit frames.  Always
+        * round this time up.
+        */
+       mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
+                         mcp->sclk_rate;
+
+       ret = mcp_host_register(mcp);
+       if (ret == 0)
+               goto out;
+
+ release:
+       release_mem_region(0x80060000, 0x60);
+       dev_set_drvdata(dev, NULL);
+
+ out:
+       return ret;
+}
+
+static int mcp_sa11x0_remove(struct device *dev)
+{
+       struct mcp *mcp = dev_get_drvdata(dev);
+
+       dev_set_drvdata(dev, NULL);
+       mcp_host_unregister(mcp);
+       release_mem_region(0x80060000, 0x60);
+
+       return 0;
+}
+
+static int mcp_sa11x0_suspend(struct device *dev, pm_message_t state, u32 level)
+{
+       struct mcp *mcp = dev_get_drvdata(dev);
+
+       if (level == SUSPEND_DISABLE) {
+               priv(mcp)->mccr0 = Ser4MCCR0;
+               priv(mcp)->mccr1 = Ser4MCCR1;
+               Ser4MCCR0 &= ~MCCR0_MCE;
+       }
+       return 0;
+}
+
+static int mcp_sa11x0_resume(struct device *dev, u32 level)
+{
+       struct mcp *mcp = dev_get_drvdata(dev);
+
+       if (level == RESUME_RESTORE_STATE) {
+               Ser4MCCR1 = priv(mcp)->mccr1;
+               Ser4MCCR0 = priv(mcp)->mccr0;
+       }
+       return 0;
+}
+
+/*
+ * The driver for the SA11x0 MCP port.
+ */
+static struct device_driver mcp_sa11x0_driver = {
+       .name           = "sa11x0-mcp",
+       .bus            = &platform_bus_type,
+       .probe          = mcp_sa11x0_probe,
+       .remove         = mcp_sa11x0_remove,
+       .suspend        = mcp_sa11x0_suspend,
+       .resume         = mcp_sa11x0_resume,
+};
+
+/*
+ * This needs re-working
+ */
+static int __init mcp_sa11x0_init(void)
+{
+       return driver_register(&mcp_sa11x0_driver);
+}
+
+static void __exit mcp_sa11x0_exit(void)
+{
+       driver_unregister(&mcp_sa11x0_driver);
+}
+
+module_init(mcp_sa11x0_init);
+module_exit(mcp_sa11x0_exit);
+
+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
+MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/mcp.h b/drivers/mfd/mcp.h
new file mode 100644 (file)
index 0000000..c093a93
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *  linux/drivers/mfd/mcp.h
+ *
+ *  Copyright (C) 2001 Russell King, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ */
+#ifndef MCP_H
+#define MCP_H
+
+struct mcp_ops;
+
+struct mcp {
+       struct module   *owner;
+       struct mcp_ops  *ops;
+       spinlock_t      lock;
+       int             use_count;
+       unsigned int    sclk_rate;
+       unsigned int    rw_timeout;
+       dma_device_t    dma_audio_rd;
+       dma_device_t    dma_audio_wr;
+       dma_device_t    dma_telco_rd;
+       dma_device_t    dma_telco_wr;
+       struct device   attached_device;
+};
+
+struct mcp_ops {
+       void            (*set_telecom_divisor)(struct mcp *, unsigned int);
+       void            (*set_audio_divisor)(struct mcp *, unsigned int);
+       void            (*reg_write)(struct mcp *, unsigned int, unsigned int);
+       unsigned int    (*reg_read)(struct mcp *, unsigned int);
+       void            (*enable)(struct mcp *);
+       void            (*disable)(struct mcp *);
+};
+
+void mcp_set_telecom_divisor(struct mcp *, unsigned int);
+void mcp_set_audio_divisor(struct mcp *, unsigned int);
+void mcp_reg_write(struct mcp *, unsigned int, unsigned int);
+unsigned int mcp_reg_read(struct mcp *, unsigned int);
+void mcp_enable(struct mcp *);
+void mcp_disable(struct mcp *);
+#define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate)
+
+struct mcp *mcp_host_alloc(struct device *, size_t);
+int mcp_host_register(struct mcp *);
+void mcp_host_unregister(struct mcp *);
+
+struct mcp_driver {
+       struct device_driver drv;
+       int (*probe)(struct mcp *);
+       void (*remove)(struct mcp *);
+       int (*suspend)(struct mcp *, pm_message_t);
+       int (*resume)(struct mcp *);
+};
+
+int mcp_driver_register(struct mcp_driver *);
+void mcp_driver_unregister(struct mcp_driver *);
+
+#define mcp_get_drvdata(mcp)   dev_get_drvdata(&(mcp)->attached_device)
+#define mcp_set_drvdata(mcp,d) dev_set_drvdata(&(mcp)->attached_device, d)
+
+#define mcp_priv(mcp)          ((void *)((mcp)+1))
+
+#endif
index 914804512dba00e7bb3971927a6b7b77e0382824..7e98434cfa37783b1cfa45c1bd162e9a56f14bad 100644 (file)
 #include <linux/termios.h>
 #include <linux/tty.h>
 #include <linux/serial_core.h>
-#include <linux/serial.h>
 #include <linux/serial_reg.h>
+#include <linux/serial_8250.h>
 #include "ibmasm.h"
 #include "lowlevel.h"
 
 
 void ibmasm_register_uart(struct service_processor *sp)
 {
-       struct serial_struct serial;
+       struct uart_port uport;
        void __iomem *iomem_base;
 
        iomem_base = sp->base_address + SCOUT_COM_B_BASE;
@@ -47,14 +47,14 @@ void ibmasm_register_uart(struct service_processor *sp)
                return;
        }
 
-       memset(&serial, 0, sizeof(serial));
-       serial.irq              = sp->irq;
-       serial.baud_base        = 3686400 / 16;
-       serial.flags            = UPF_AUTOPROBE | UPF_SHARE_IRQ;
-       serial.io_type          = UPIO_MEM;
-       serial.iomem_base       = iomem_base;
+       memset(&uport, 0, sizeof(struct uart_port));
+       uport.irq       = sp->irq;
+       uport.uartclk   = 3686400;
+       uport.flags     = UPF_AUTOPROBE | UPF_SHARE_IRQ;
+       uport.iotype    = UPIO_MEM;
+       uport.membase   = iomem_base;
 
-       sp->serial_line = register_serial(&serial);
+       sp->serial_line = serial8250_register_port(&uport);
        if (sp->serial_line < 0) {
                dev_err(sp->dev, "Failed to register serial port\n");
                return;
@@ -68,5 +68,5 @@ void ibmasm_unregister_uart(struct service_processor *sp)
                return;
 
        disable_uart_interrupts(sp->base_address);
-       unregister_serial(sp->serial_line);
+       serial8250_unregister_port(sp->serial_line);
 }
index eeb9f6668e69167044b3b41bf6559479f30dd5ab..0a117c61cd1809e4f2ee6d924ac716810c8c848e 100644 (file)
@@ -2,6 +2,8 @@
  *  linux/drivers/mmc/mmc.c
  *
  *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.
+ *  SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
+ *  SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -16,6 +18,8 @@
 #include <linux/delay.h>
 #include <linux/pagemap.h>
 #include <linux/err.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -172,7 +176,81 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
 
 EXPORT_SYMBOL(mmc_wait_for_cmd);
 
+/**
+ *     mmc_wait_for_app_cmd - start an application command and wait for
+                              completion
+ *     @host: MMC host to start command
+ *     @rca: RCA to send MMC_APP_CMD to
+ *     @cmd: MMC command to start
+ *     @retries: maximum number of retries
+ *
+ *     Sends a MMC_APP_CMD, checks the card response, sends the command
+ *     in the parameter and waits for it to complete. Return any error
+ *     that occurred while the command was executing.  Do not attempt to
+ *     parse the response.
+ */
+int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
+       struct mmc_command *cmd, int retries)
+{
+       struct mmc_request mrq;
+       struct mmc_command appcmd;
+
+       int i, err;
+
+       BUG_ON(host->card_busy == NULL);
+       BUG_ON(retries < 0);
+
+       err = MMC_ERR_INVALID;
+
+       /*
+        * We have to resend MMC_APP_CMD for each attempt so
+        * we cannot use the retries field in mmc_command.
+        */
+       for (i = 0;i <= retries;i++) {
+               memset(&mrq, 0, sizeof(struct mmc_request));
+
+               appcmd.opcode = MMC_APP_CMD;
+               appcmd.arg = rca << 16;
+               appcmd.flags = MMC_RSP_R1;
+               appcmd.retries = 0;
+               memset(appcmd.resp, 0, sizeof(appcmd.resp));
+               appcmd.data = NULL;
+
+               mrq.cmd = &appcmd;
+               appcmd.data = NULL;
+
+               mmc_wait_for_req(host, &mrq);
+
+               if (appcmd.error) {
+                       err = appcmd.error;
+                       continue;
+               }
+
+               /* Check that card supported application commands */
+               if (!(appcmd.resp[0] & R1_APP_CMD))
+                       return MMC_ERR_FAILED;
+
+               memset(&mrq, 0, sizeof(struct mmc_request));
+
+               memset(cmd->resp, 0, sizeof(cmd->resp));
+               cmd->retries = 0;
+
+               mrq.cmd = cmd;
+               cmd->data = NULL;
+
+               mmc_wait_for_req(host, &mrq);
+
+               err = cmd->error;
+               if (cmd->error == MMC_ERR_NONE)
+                       break;
+       }
 
+       return err;
+}
+
+EXPORT_SYMBOL(mmc_wait_for_app_cmd);
+
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card);
 
 /**
  *     __mmc_claim_host - exclusively claim a host
@@ -206,16 +284,10 @@ int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card)
        spin_unlock_irqrestore(&host->lock, flags);
        remove_wait_queue(&host->wq, &wait);
 
-       if (card != (void *)-1 && host->card_selected != card) {
-               struct mmc_command cmd;
-
-               host->card_selected = card;
-
-               cmd.opcode = MMC_SELECT_CARD;
-               cmd.arg = card->rca << 16;
-               cmd.flags = MMC_RSP_R1;
-
-               err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+       if (card != (void *)-1) {
+               err = mmc_select_card(host, card);
+               if (err != MMC_ERR_NONE)
+                       return err;
        }
 
        return err;
@@ -245,6 +317,63 @@ void mmc_release_host(struct mmc_host *host)
 
 EXPORT_SYMBOL(mmc_release_host);
 
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
+{
+       int err;
+       struct mmc_command cmd;
+
+       BUG_ON(host->card_busy == NULL);
+
+       if (host->card_selected == card)
+               return MMC_ERR_NONE;
+
+       host->card_selected = card;
+
+       cmd.opcode = MMC_SELECT_CARD;
+       cmd.arg = card->rca << 16;
+       cmd.flags = MMC_RSP_R1;
+
+       err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+       if (err != MMC_ERR_NONE)
+               return err;
+
+       /*
+        * Default bus width is 1 bit.
+        */
+       host->ios.bus_width = MMC_BUS_WIDTH_1;
+
+       /*
+        * We can only change the bus width of the selected
+        * card so therefore we have to put the handling
+        * here.
+        */
+       if (host->caps & MMC_CAP_4_BIT_DATA) {
+               /*
+                * The card is in 1 bit mode by default so
+                * we only need to change if it supports the
+                * wider version.
+                */
+               if (mmc_card_sd(card) &&
+                       (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+                       struct mmc_command cmd;
+                       cmd.opcode = SD_APP_SET_BUS_WIDTH;
+                       cmd.arg = SD_BUS_WIDTH_4;
+                       cmd.flags = MMC_RSP_R1;
+
+                       err = mmc_wait_for_app_cmd(host, card->rca, &cmd,
+                               CMD_RETRIES);
+                       if (err != MMC_ERR_NONE)
+                               return err;
+
+                       host->ios.bus_width = MMC_BUS_WIDTH_4;
+               }
+       }
+
+       host->ops->set_ios(host, &host->ios);
+
+       return MMC_ERR_NONE;
+}
+
 /*
  * Ensure that no card is selected.
  */
@@ -322,48 +451,69 @@ static void mmc_decode_cid(struct mmc_card *card)
 
        memset(&card->cid, 0, sizeof(struct mmc_cid));
 
-       /*
-        * The selection of the format here is guesswork based upon
-        * information people have sent to date.
-        */
-       switch (card->csd.mmca_vsn) {
-       case 0: /* MMC v1.? */
-       case 1: /* MMC v1.4 */
-               card->cid.manfid        = UNSTUFF_BITS(resp, 104, 24);
-               card->cid.prod_name[0]  = UNSTUFF_BITS(resp, 96, 8);
-               card->cid.prod_name[1]  = UNSTUFF_BITS(resp, 88, 8);
-               card->cid.prod_name[2]  = UNSTUFF_BITS(resp, 80, 8);
-               card->cid.prod_name[3]  = UNSTUFF_BITS(resp, 72, 8);
-               card->cid.prod_name[4]  = UNSTUFF_BITS(resp, 64, 8);
-               card->cid.prod_name[5]  = UNSTUFF_BITS(resp, 56, 8);
-               card->cid.prod_name[6]  = UNSTUFF_BITS(resp, 48, 8);
-               card->cid.hwrev         = UNSTUFF_BITS(resp, 44, 4);
-               card->cid.fwrev         = UNSTUFF_BITS(resp, 40, 4);
-               card->cid.serial        = UNSTUFF_BITS(resp, 16, 24);
-               card->cid.month         = UNSTUFF_BITS(resp, 12, 4);
-               card->cid.year          = UNSTUFF_BITS(resp, 8, 4) + 1997;
-               break;
-
-       case 2: /* MMC v2.x ? */
-       case 3: /* MMC v3.x ? */
-               card->cid.manfid        = UNSTUFF_BITS(resp, 120, 8);
-               card->cid.oemid         = UNSTUFF_BITS(resp, 104, 16);
-               card->cid.prod_name[0]  = UNSTUFF_BITS(resp, 96, 8);
-               card->cid.prod_name[1]  = UNSTUFF_BITS(resp, 88, 8);
-               card->cid.prod_name[2]  = UNSTUFF_BITS(resp, 80, 8);
-               card->cid.prod_name[3]  = UNSTUFF_BITS(resp, 72, 8);
-               card->cid.prod_name[4]  = UNSTUFF_BITS(resp, 64, 8);
-               card->cid.prod_name[5]  = UNSTUFF_BITS(resp, 56, 8);
-               card->cid.serial        = UNSTUFF_BITS(resp, 16, 32);
-               card->cid.month         = UNSTUFF_BITS(resp, 12, 4);
-               card->cid.year          = UNSTUFF_BITS(resp, 8, 4) + 1997;
-               break;
-
-       default:
-               printk("%s: card has unknown MMCA version %d\n",
-                       card->host->host_name, card->csd.mmca_vsn);
-               mmc_card_set_bad(card);
-               break;
+       if (mmc_card_sd(card)) {
+               /*
+                * SD doesn't currently have a version field so we will
+                * have to assume we can parse this.
+                */
+               card->cid.manfid                = UNSTUFF_BITS(resp, 120, 8);
+               card->cid.oemid                 = UNSTUFF_BITS(resp, 104, 16);
+               card->cid.prod_name[0]          = UNSTUFF_BITS(resp, 96, 8);
+               card->cid.prod_name[1]          = UNSTUFF_BITS(resp, 88, 8);
+               card->cid.prod_name[2]          = UNSTUFF_BITS(resp, 80, 8);
+               card->cid.prod_name[3]          = UNSTUFF_BITS(resp, 72, 8);
+               card->cid.prod_name[4]          = UNSTUFF_BITS(resp, 64, 8);
+               card->cid.hwrev                 = UNSTUFF_BITS(resp, 60, 4);
+               card->cid.fwrev                 = UNSTUFF_BITS(resp, 56, 4);
+               card->cid.serial                = UNSTUFF_BITS(resp, 24, 32);
+               card->cid.year                  = UNSTUFF_BITS(resp, 12, 8);
+               card->cid.month                 = UNSTUFF_BITS(resp, 8, 4);
+
+               card->cid.year += 2000; /* SD cards year offset */
+       } else {
+               /*
+                * The selection of the format here is based upon published
+                * specs from sandisk and from what people have reported.
+                */
+               switch (card->csd.mmca_vsn) {
+               case 0: /* MMC v1.0 - v1.2 */
+               case 1: /* MMC v1.4 */
+                       card->cid.manfid        = UNSTUFF_BITS(resp, 104, 24);
+                       card->cid.prod_name[0]  = UNSTUFF_BITS(resp, 96, 8);
+                       card->cid.prod_name[1]  = UNSTUFF_BITS(resp, 88, 8);
+                       card->cid.prod_name[2]  = UNSTUFF_BITS(resp, 80, 8);
+                       card->cid.prod_name[3]  = UNSTUFF_BITS(resp, 72, 8);
+                       card->cid.prod_name[4]  = UNSTUFF_BITS(resp, 64, 8);
+                       card->cid.prod_name[5]  = UNSTUFF_BITS(resp, 56, 8);
+                       card->cid.prod_name[6]  = UNSTUFF_BITS(resp, 48, 8);
+                       card->cid.hwrev         = UNSTUFF_BITS(resp, 44, 4);
+                       card->cid.fwrev         = UNSTUFF_BITS(resp, 40, 4);
+                       card->cid.serial        = UNSTUFF_BITS(resp, 16, 24);
+                       card->cid.month         = UNSTUFF_BITS(resp, 12, 4);
+                       card->cid.year          = UNSTUFF_BITS(resp, 8, 4) + 1997;
+                       break;
+
+               case 2: /* MMC v2.0 - v2.2 */
+               case 3: /* MMC v3.1 - v3.3 */
+                       card->cid.manfid        = UNSTUFF_BITS(resp, 120, 8);
+                       card->cid.oemid         = UNSTUFF_BITS(resp, 104, 16);
+                       card->cid.prod_name[0]  = UNSTUFF_BITS(resp, 96, 8);
+                       card->cid.prod_name[1]  = UNSTUFF_BITS(resp, 88, 8);
+                       card->cid.prod_name[2]  = UNSTUFF_BITS(resp, 80, 8);
+                       card->cid.prod_name[3]  = UNSTUFF_BITS(resp, 72, 8);
+                       card->cid.prod_name[4]  = UNSTUFF_BITS(resp, 64, 8);
+                       card->cid.prod_name[5]  = UNSTUFF_BITS(resp, 56, 8);
+                       card->cid.serial        = UNSTUFF_BITS(resp, 16, 32);
+                       card->cid.month         = UNSTUFF_BITS(resp, 12, 4);
+                       card->cid.year          = UNSTUFF_BITS(resp, 8, 4) + 1997;
+                       break;
+
+               default:
+                       printk("%s: card has unknown MMCA version %d\n",
+                               mmc_hostname(card->host), card->csd.mmca_vsn);
+                       mmc_card_set_bad(card);
+                       break;
+               }
        }
 }
 
@@ -376,34 +526,86 @@ static void mmc_decode_csd(struct mmc_card *card)
        unsigned int e, m, csd_struct;
        u32 *resp = card->raw_csd;
 
-       /*
-        * We only understand CSD structure v1.1 and v2.
-        * v2 has extra information in bits 15, 11 and 10.
-        */
-       csd_struct = UNSTUFF_BITS(resp, 126, 2);
-       if (csd_struct != 1 && csd_struct != 2) {
-               printk("%s: unrecognised CSD structure version %d\n",
-                       card->host->host_name, csd_struct);
-               mmc_card_set_bad(card);
-               return;
+       if (mmc_card_sd(card)) {
+               csd_struct = UNSTUFF_BITS(resp, 126, 2);
+               if (csd_struct != 0) {
+                       printk("%s: unrecognised CSD structure version %d\n",
+                               mmc_hostname(card->host), csd_struct);
+                       mmc_card_set_bad(card);
+                       return;
+               }
+
+               m = UNSTUFF_BITS(resp, 115, 4);
+               e = UNSTUFF_BITS(resp, 112, 3);
+               csd->tacc_ns     = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+               csd->tacc_clks   = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+               m = UNSTUFF_BITS(resp, 99, 4);
+               e = UNSTUFF_BITS(resp, 96, 3);
+               csd->max_dtr      = tran_exp[e] * tran_mant[m];
+               csd->cmdclass     = UNSTUFF_BITS(resp, 84, 12);
+
+               e = UNSTUFF_BITS(resp, 47, 3);
+               m = UNSTUFF_BITS(resp, 62, 12);
+               csd->capacity     = (1 + m) << (e + 2);
+
+               csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+       } else {
+               /*
+                * We only understand CSD structure v1.1 and v1.2.
+                * v1.2 has extra information in bits 15, 11 and 10.
+                */
+               csd_struct = UNSTUFF_BITS(resp, 126, 2);
+               if (csd_struct != 1 && csd_struct != 2) {
+                       printk("%s: unrecognised CSD structure version %d\n",
+                               mmc_hostname(card->host), csd_struct);
+                       mmc_card_set_bad(card);
+                       return;
+               }
+
+               csd->mmca_vsn    = UNSTUFF_BITS(resp, 122, 4);
+               m = UNSTUFF_BITS(resp, 115, 4);
+               e = UNSTUFF_BITS(resp, 112, 3);
+               csd->tacc_ns     = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+               csd->tacc_clks   = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+               m = UNSTUFF_BITS(resp, 99, 4);
+               e = UNSTUFF_BITS(resp, 96, 3);
+               csd->max_dtr      = tran_exp[e] * tran_mant[m];
+               csd->cmdclass     = UNSTUFF_BITS(resp, 84, 12);
+
+               e = UNSTUFF_BITS(resp, 47, 3);
+               m = UNSTUFF_BITS(resp, 62, 12);
+               csd->capacity     = (1 + m) << (e + 2);
+
+               csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
        }
+}
 
-       csd->mmca_vsn    = UNSTUFF_BITS(resp, 122, 4);
-       m = UNSTUFF_BITS(resp, 115, 4);
-       e = UNSTUFF_BITS(resp, 112, 3);
-       csd->tacc_ns     = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
-       csd->tacc_clks   = UNSTUFF_BITS(resp, 104, 8) * 100;
+/*
+ * Given a 64-bit response, decode to our card SCR structure.
+ */
+static void mmc_decode_scr(struct mmc_card *card)
+{
+       struct sd_scr *scr = &card->scr;
+       unsigned int scr_struct;
+       u32 resp[4];
+
+       BUG_ON(!mmc_card_sd(card));
 
-       m = UNSTUFF_BITS(resp, 99, 4);
-       e = UNSTUFF_BITS(resp, 96, 3);
-       csd->max_dtr      = tran_exp[e] * tran_mant[m];
-       csd->cmdclass     = UNSTUFF_BITS(resp, 84, 12);
+       resp[3] = card->raw_scr[1];
+       resp[2] = card->raw_scr[0];
 
-       e = UNSTUFF_BITS(resp, 47, 3);
-       m = UNSTUFF_BITS(resp, 62, 12);
-       csd->capacity     = (1 + m) << (e + 2);
+       scr_struct = UNSTUFF_BITS(resp, 60, 4);
+       if (scr_struct != 0) {
+               printk("%s: unrecognised SCR structure version %d\n",
+                       mmc_hostname(card->host), scr_struct);
+               mmc_card_set_bad(card);
+               return;
+       }
 
-       csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+       scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
+       scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
 }
 
 /*
@@ -457,6 +659,11 @@ static void mmc_idle_cards(struct mmc_host *host)
 {
        struct mmc_command cmd;
 
+       host->ios.chip_select = MMC_CS_HIGH;
+       host->ops->set_ios(host, &host->ios);
+
+       mmc_delay(1);
+
        cmd.opcode = MMC_GO_IDLE_STATE;
        cmd.arg = 0;
        cmd.flags = MMC_RSP_NONE;
@@ -464,6 +671,11 @@ static void mmc_idle_cards(struct mmc_host *host)
        mmc_wait_for_cmd(host, &cmd, 0);
 
        mmc_delay(1);
+
+       host->ios.chip_select = MMC_CS_DONTCARE;
+       host->ops->set_ios(host, &host->ios);
+
+       mmc_delay(1);
 }
 
 /*
@@ -475,7 +687,9 @@ static void mmc_power_up(struct mmc_host *host)
 
        host->ios.vdd = bit;
        host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+       host->ios.chip_select = MMC_CS_DONTCARE;
        host->ios.power_mode = MMC_POWER_UP;
+       host->ios.bus_width = MMC_BUS_WIDTH_1;
        host->ops->set_ios(host, &host->ios);
 
        mmc_delay(1);
@@ -492,7 +706,9 @@ static void mmc_power_off(struct mmc_host *host)
        host->ios.clock = 0;
        host->ios.vdd = 0;
        host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+       host->ios.chip_select = MMC_CS_DONTCARE;
        host->ios.power_mode = MMC_POWER_OFF;
+       host->ios.bus_width = MMC_BUS_WIDTH_1;
        host->ops->set_ios(host, &host->ios);
 }
 
@@ -524,6 +740,34 @@ static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
        return err;
 }
 
+static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+       struct mmc_command cmd;
+       int i, err = 0;
+
+       cmd.opcode = SD_APP_OP_COND;
+       cmd.arg = ocr;
+       cmd.flags = MMC_RSP_R3;
+
+       for (i = 100; i; i--) {
+               err = mmc_wait_for_app_cmd(host, 0, &cmd, CMD_RETRIES);
+               if (err != MMC_ERR_NONE)
+                       break;
+
+               if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+                       break;
+
+               err = MMC_ERR_TIMEOUT;
+
+               mmc_delay(10);
+       }
+
+       if (rocr)
+               *rocr = cmd.resp[0];
+
+       return err;
+}
+
 /*
  * Discover cards by requesting their CID.  If this command
  * times out, it is not an error; there are no further cards
@@ -551,7 +795,7 @@ static void mmc_discover_cards(struct mmc_host *host)
                }
                if (err != MMC_ERR_NONE) {
                        printk(KERN_ERR "%s: error requesting CID: %d\n",
-                               host->host_name, err);
+                               mmc_hostname(host), err);
                        break;
                }
 
@@ -567,13 +811,38 @@ static void mmc_discover_cards(struct mmc_host *host)
 
                card->state &= ~MMC_STATE_DEAD;
 
-               cmd.opcode = MMC_SET_RELATIVE_ADDR;
-               cmd.arg = card->rca << 16;
-               cmd.flags = MMC_RSP_R1;
+               if (host->mode == MMC_MODE_SD) {
+                       mmc_card_set_sd(card);
 
-               err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
-               if (err != MMC_ERR_NONE)
-                       mmc_card_set_dead(card);
+                       cmd.opcode = SD_SEND_RELATIVE_ADDR;
+                       cmd.arg = 0;
+                       cmd.flags = MMC_RSP_R1;
+
+                       err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+                       if (err != MMC_ERR_NONE)
+                               mmc_card_set_dead(card);
+                       else {
+                               card->rca = cmd.resp[0] >> 16;
+
+                               if (!host->ops->get_ro) {
+                                       printk(KERN_WARNING "%s: host does not "
+                                               "support reading read-only "
+                                               "switch. assuming write-enable.\n",
+                                               mmc_hostname(host));
+                               } else {
+                                       if (host->ops->get_ro(host))
+                                               mmc_card_set_readonly(card);
+                               }
+                       }
+               } else {
+                       cmd.opcode = MMC_SET_RELATIVE_ADDR;
+                       cmd.arg = card->rca << 16;
+                       cmd.flags = MMC_RSP_R1;
+
+                       err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+                       if (err != MMC_ERR_NONE)
+                               mmc_card_set_dead(card);
+               }
        }
 }
 
@@ -605,6 +874,79 @@ static void mmc_read_csds(struct mmc_host *host)
        }
 }
 
+static void mmc_read_scrs(struct mmc_host *host)
+{
+       int err;
+       struct mmc_card *card;
+
+       struct mmc_request mrq;
+       struct mmc_command cmd;
+       struct mmc_data data;
+
+       struct scatterlist sg;
+
+       list_for_each_entry(card, &host->cards, node) {
+               if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
+                       continue;
+               if (!mmc_card_sd(card))
+                       continue;
+
+               err = mmc_select_card(host, card);
+               if (err != MMC_ERR_NONE) {
+                       mmc_card_set_dead(card);
+                       continue;
+               }
+
+               memset(&cmd, 0, sizeof(struct mmc_command));
+
+               cmd.opcode = MMC_APP_CMD;
+               cmd.arg = card->rca << 16;
+               cmd.flags = MMC_RSP_R1;
+
+               err = mmc_wait_for_cmd(host, &cmd, 0);
+               if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) {
+                       mmc_card_set_dead(card);
+                       continue;
+               }
+
+               memset(&cmd, 0, sizeof(struct mmc_command));
+
+               cmd.opcode = SD_APP_SEND_SCR;
+               cmd.arg = 0;
+               cmd.flags = MMC_RSP_R1;
+
+               memset(&data, 0, sizeof(struct mmc_data));
+
+               data.timeout_ns = card->csd.tacc_ns * 10;
+               data.timeout_clks = card->csd.tacc_clks * 10;
+               data.blksz_bits = 3;
+               data.blocks = 1;
+               data.flags = MMC_DATA_READ;
+               data.sg = &sg;
+               data.sg_len = 1;
+
+               memset(&mrq, 0, sizeof(struct mmc_request));
+
+               mrq.cmd = &cmd;
+               mrq.data = &data;
+
+               sg_init_one(&sg, (u8*)card->raw_scr, 8);
+
+               err = mmc_wait_for_req(host, &mrq);
+               if (err != MMC_ERR_NONE) {
+                       mmc_card_set_dead(card);
+                       continue;
+               }
+
+               card->raw_scr[0] = ntohl(card->raw_scr[0]);
+               card->raw_scr[1] = ntohl(card->raw_scr[1]);
+
+               mmc_decode_scr(card);
+       }
+
+       mmc_deselect_cards(host);
+}
+
 static unsigned int mmc_calculate_clock(struct mmc_host *host)
 {
        struct mmc_card *card;
@@ -657,12 +999,24 @@ static void mmc_setup(struct mmc_host *host)
                int err;
                u32 ocr;
 
+               host->mode = MMC_MODE_SD;
+
                mmc_power_up(host);
                mmc_idle_cards(host);
 
-               err = mmc_send_op_cond(host, 0, &ocr);
-               if (err != MMC_ERR_NONE)
-                       return;
+               err = mmc_send_app_op_cond(host, 0, &ocr);
+
+               /*
+                * If we fail to detect any SD cards then try
+                * searching for MMC cards.
+                */
+               if (err != MMC_ERR_NONE) {
+                       host->mode = MMC_MODE_MMC;
+
+                       err = mmc_send_op_cond(host, 0, &ocr);
+                       if (err != MMC_ERR_NONE)
+                               return;
+               }
 
                host->ocr = mmc_select_voltage(host, ocr);
 
@@ -702,7 +1056,10 @@ static void mmc_setup(struct mmc_host *host)
         * all get the idea that they should be ready for CMD2.
         * (My SanDisk card seems to need this.)
         */
-       mmc_send_op_cond(host, host->ocr, NULL);
+       if (host->mode == MMC_MODE_SD)
+               mmc_send_app_op_cond(host, host->ocr, NULL);
+       else
+               mmc_send_op_cond(host, host->ocr, NULL);
 
        mmc_discover_cards(host);
 
@@ -713,6 +1070,9 @@ static void mmc_setup(struct mmc_host *host)
        host->ops->set_ios(host, &host->ios);
 
        mmc_read_csds(host);
+
+       if (host->mode == MMC_MODE_SD)
+               mmc_read_scrs(host);
 }
 
 
@@ -796,17 +1156,13 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
 {
        struct mmc_host *host;
 
-       host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
+       host = mmc_alloc_host_sysfs(extra, dev);
        if (host) {
-               memset(host, 0, sizeof(struct mmc_host) + extra);
-
                spin_lock_init(&host->lock);
                init_waitqueue_head(&host->wq);
                INIT_LIST_HEAD(&host->cards);
                INIT_WORK(&host->detect, mmc_rescan, host);
 
-               host->dev = dev;
-
                /*
                 * By default, hosts do not support SGIO or large requests.
                 * They have to set these according to their abilities.
@@ -828,15 +1184,15 @@ EXPORT_SYMBOL(mmc_alloc_host);
  */
 int mmc_add_host(struct mmc_host *host)
 {
-       static unsigned int host_num;
+       int ret;
 
-       snprintf(host->host_name, sizeof(host->host_name),
-                "mmc%d", host_num++);
-
-       mmc_power_off(host);
-       mmc_detect_change(host);
+       ret = mmc_add_host_sysfs(host);
+       if (ret == 0) {
+               mmc_power_off(host);
+               mmc_detect_change(host);
+       }
 
-       return 0;
+       return ret;
 }
 
 EXPORT_SYMBOL(mmc_add_host);
@@ -859,6 +1215,7 @@ void mmc_remove_host(struct mmc_host *host)
        }
 
        mmc_power_off(host);
+       mmc_remove_host_sysfs(host);
 }
 
 EXPORT_SYMBOL(mmc_remove_host);
@@ -872,7 +1229,7 @@ EXPORT_SYMBOL(mmc_remove_host);
 void mmc_free_host(struct mmc_host *host)
 {
        flush_scheduled_work();
-       kfree(host);
+       mmc_free_host_sysfs(host);
 }
 
 EXPORT_SYMBOL(mmc_free_host);
index b498dffe0b118c48d392b6d4c39730dfb03ab67a..97bae00292fafdfdfc7d785d9b4725603e5583d5 100644 (file)
@@ -13,4 +13,9 @@
 void mmc_init_card(struct mmc_card *card, struct mmc_host *host);
 int mmc_register_card(struct mmc_card *card);
 void mmc_remove_card(struct mmc_card *card);
+
+struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev);
+int mmc_add_host_sysfs(struct mmc_host *host);
+void mmc_remove_host_sysfs(struct mmc_host *host);
+void mmc_free_host_sysfs(struct mmc_host *host);
 #endif
index d4eee99c2bf65ffe86798deb86cdd5ef0a2e81da..fa83f15fdf161d8eafda24958a8e9ccb6ebc2573 100644 (file)
@@ -95,6 +95,10 @@ static int mmc_blk_open(struct inode *inode, struct file *filp)
                if (md->usage == 2)
                        check_disk_change(inode->i_bdev);
                ret = 0;
+
+               if ((filp->f_mode & FMODE_WRITE) &&
+                       mmc_card_readonly(md->queue.card))
+                       ret = -EROFS;
        }
 
        return ret;
@@ -403,9 +407,10 @@ static int mmc_blk_probe(struct mmc_card *card)
        if (err)
                goto out;
 
-       printk(KERN_INFO "%s: %s %s %dKiB\n",
+       printk(KERN_INFO "%s: %s %s %dKiB %s\n",
                md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
-               (card->csd.capacity << card->csd.read_blkbits) / 1024);
+               (card->csd.capacity << card->csd.read_blkbits) / 1024,
+               mmc_card_readonly(card)?"(ro)":"");
 
        mmc_set_drvdata(card, md);
        add_disk(md->disk);
index 5556cd3b555917768f7fc4d341e4b8c93f63db80..3f4a66ca9555e6c354c468266d22609adf56c628 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/idr.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -20,6 +21,7 @@
 
 #define dev_to_mmc_card(d)     container_of(d, struct mmc_card, dev)
 #define to_mmc_driver(d)       container_of(d, struct mmc_driver, drv)
+#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
 
 #define MMC_ATTR(name, fmt, args...)                                   \
 static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf)        \
@@ -32,6 +34,7 @@ MMC_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
        card->raw_cid[2], card->raw_cid[3]);
 MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
        card->raw_csd[2], card->raw_csd[3]);
+MMC_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
 MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
 MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
 MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
@@ -55,6 +58,8 @@ static struct device_attribute mmc_dev_attrs[] = {
        __ATTR_NULL
 };
 
+static struct device_attribute mmc_dev_attr_scr = MMC_ATTR_RO(scr);
+
 
 static void mmc_release_card(struct device *dev)
 {
@@ -205,10 +210,20 @@ void mmc_init_card(struct mmc_card *card, struct mmc_host *host)
  */
 int mmc_register_card(struct mmc_card *card)
 {
-       snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
-                "%s:%04x", card->host->host_name, card->rca);
+       int ret;
 
-       return device_add(&card->dev);
+       snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
+                "%s:%04x", mmc_hostname(card->host), card->rca);
+
+       ret = device_add(&card->dev);
+       if (ret == 0) {
+               if (mmc_card_sd(card)) {
+                       ret = device_create_file(&card->dev, &mmc_dev_attr_scr);
+                       if (ret)
+                               device_del(&card->dev);
+               }
+       }
+       return ret;
 }
 
 /*
@@ -217,20 +232,108 @@ int mmc_register_card(struct mmc_card *card)
  */
 void mmc_remove_card(struct mmc_card *card)
 {
-       if (mmc_card_present(card))
+       if (mmc_card_present(card)) {
+               if (mmc_card_sd(card))
+                       device_remove_file(&card->dev, &mmc_dev_attr_scr);
+
                device_del(&card->dev);
+       }
 
        put_device(&card->dev);
 }
 
 
+static void mmc_host_classdev_release(struct class_device *dev)
+{
+       struct mmc_host *host = cls_dev_to_mmc_host(dev);
+       kfree(host);
+}
+
+static struct class mmc_host_class = {
+       .name           = "mmc_host",
+       .release        = mmc_host_classdev_release,
+};
+
+static DEFINE_IDR(mmc_host_idr);
+static DEFINE_SPINLOCK(mmc_host_lock);
+
+/*
+ * Internal function. Allocate a new MMC host.
+ */
+struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev)
+{
+       struct mmc_host *host;
+
+       host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
+       if (host) {
+               memset(host, 0, sizeof(struct mmc_host) + extra);
+
+               host->dev = dev;
+               host->class_dev.dev = host->dev;
+               host->class_dev.class = &mmc_host_class;
+               class_device_initialize(&host->class_dev);
+       }
+
+       return host;
+}
+
+/*
+ * Internal function. Register a new MMC host with the MMC class.
+ */
+int mmc_add_host_sysfs(struct mmc_host *host)
+{
+       int err;
+
+       if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
+               return -ENOMEM;
+
+       spin_lock(&mmc_host_lock);
+       err = idr_get_new(&mmc_host_idr, host, &host->index);
+       spin_unlock(&mmc_host_lock);
+       if (err)
+               return err;
+
+       snprintf(host->class_dev.class_id, BUS_ID_SIZE,
+                "mmc%d", host->index);
+
+       return class_device_add(&host->class_dev);
+}
+
+/*
+ * Internal function. Unregister a MMC host with the MMC class.
+ */
+void mmc_remove_host_sysfs(struct mmc_host *host)
+{
+       class_device_del(&host->class_dev);
+
+       spin_lock(&mmc_host_lock);
+       idr_remove(&mmc_host_idr, host->index);
+       spin_unlock(&mmc_host_lock);
+}
+
+/*
+ * Internal function. Free a MMC host.
+ */
+void mmc_free_host_sysfs(struct mmc_host *host)
+{
+       class_device_put(&host->class_dev);
+}
+
+
 static int __init mmc_init(void)
 {
-       return bus_register(&mmc_bus_type);
+       int ret = bus_register(&mmc_bus_type);
+       if (ret == 0) {
+               ret = class_register(&mmc_host_class);
+               if (ret)
+                       bus_unregister(&mmc_bus_type);
+       }
+       return ret;
 }
 
 static void __exit mmc_exit(void)
 {
+       class_unregister(&mmc_host_class);
        bus_unregister(&mmc_bus_type);
 }
 
index 7a42966d755bd00a7defabfe47e8d69fe4820aac..716c4ef4faf6f8c46c9582d5211d5fba3a332255 100644 (file)
@@ -34,7 +34,7 @@
 
 #ifdef CONFIG_MMC_DEBUG
 #define DBG(host,fmt,args...)  \
-       pr_debug("%s: %s: " fmt, host->mmc->host_name, __func__ , args)
+       pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args)
 #else
 #define DBG(host,fmt,args...)  do { } while (0)
 #endif
@@ -541,7 +541,7 @@ 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",
-               mmc->host_name, amba_rev(dev), amba_config(dev),
+               mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
                dev->res.start, dev->irq[0], dev->irq[1]);
 
        init_timer(&host->timer);
index b78beb1b0159cc66748c15c19e05407c8c12d076..e99a53b09e321390d683362cf483923774d535a7 100644 (file)
@@ -362,6 +362,16 @@ static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq)
        pxamci_start_cmd(host, mrq->cmd, cmdat);
 }
 
+static int pxamci_get_ro(struct mmc_host *mmc)
+{
+       struct pxamci_host *host = mmc_priv(mmc);
+
+       if (host->pdata && host->pdata->get_ro)
+               return host->pdata->get_ro(mmc->dev);
+       /* Host doesn't support read only detection so assume writeable */
+       return 0;
+}
+
 static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct pxamci_host *host = mmc_priv(mmc);
@@ -401,6 +411,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
 static struct mmc_host_ops pxamci_ops = {
        .request        = pxamci_request,
+       .get_ro         = pxamci_get_ro,
        .set_ios        = pxamci_set_ios,
 };
 
index 974f2f36bdbe6abe21d4ba06d31418e8bfcb2674..dec01d38c782fce5935ffb575ca90122934260e7 100644 (file)
@@ -42,7 +42,7 @@
 #include "wbsd.h"
 
 #define DRIVER_NAME "wbsd"
-#define DRIVER_VERSION "1.3"
+#define DRIVER_VERSION "1.4"
 
 #ifdef CONFIG_MMC_DEBUG
 #define DBG(x...) \
@@ -720,11 +720,28 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
         * calculate CRC.
         *
         * Space for CRC must be included in the size.
+        * Two bytes are needed for each data line.
         */
-       blksize = (1 << data->blksz_bits) + 2;
+       if (host->bus_width == MMC_BUS_WIDTH_1)
+       {
+               blksize = (1 << data->blksz_bits) + 2;
+
+               wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0);
+               wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
+       }
+       else if (host->bus_width == MMC_BUS_WIDTH_4)
+       {
+               blksize = (1 << data->blksz_bits) + 2 * 4;
        
-       wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0);
-       wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
+               wbsd_write_index(host, WBSD_IDX_PBSMSB, ((blksize >> 4) & 0xF0)
+                       | WBSD_DATA_WIDTH);
+               wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
+       }
+       else
+       {
+               data->error = MMC_ERR_INVALID;
+               return;
+       }
 
        /*
         * Clear the FIFO. This is needed even for DMA
@@ -960,8 +977,9 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
        struct wbsd_host* host = mmc_priv(mmc);
        u8 clk, setup, pwr;
        
-       DBGF("clock %uHz busmode %u powermode %u Vdd %u\n",
-               ios->clock, ios->bus_mode, ios->power_mode, ios->vdd);
+       DBGF("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n",
+            ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select,
+            ios->vdd, ios->bus_width);
 
        spin_lock_bh(&host->lock);
 
@@ -1003,30 +1021,63 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
 
        /*
         * MMC cards need to have pin 1 high during init.
-        * Init time corresponds rather nicely with the bus mode.
         * It wreaks havoc with the card detection though so
-        * that needs to be disabed.
+        * that needs to be disabled.
         */
        setup = wbsd_read_index(host, WBSD_IDX_SETUP);
-       if ((ios->power_mode == MMC_POWER_ON) &&
-               (ios->bus_mode == MMC_BUSMODE_OPENDRAIN))
+       if (ios->chip_select == MMC_CS_HIGH)
        {
+               BUG_ON(ios->bus_width != MMC_BUS_WIDTH_1);
                setup |= WBSD_DAT3_H;
                host->flags |= WBSD_FIGNORE_DETECT;
        }
        else
        {
                setup &= ~WBSD_DAT3_H;
-               host->flags &= ~WBSD_FIGNORE_DETECT;
+
+               /*
+                * We cannot resume card detection immediatly
+                * because of capacitance and delays in the chip.
+                */
+               mod_timer(&host->ignore_timer, jiffies + HZ/100);
        }
        wbsd_write_index(host, WBSD_IDX_SETUP, setup);
        
+       /*
+        * Store bus width for later. Will be used when
+        * setting up the data transfer.
+        */
+       host->bus_width = ios->bus_width;
+
+       spin_unlock_bh(&host->lock);
+}
+
+static int wbsd_get_ro(struct mmc_host* mmc)
+{
+       struct wbsd_host* host = mmc_priv(mmc);
+       u8 csr;
+
+       spin_lock_bh(&host->lock);
+
+       csr = inb(host->base + WBSD_CSR);
+       csr |= WBSD_MSLED;
+       outb(csr, host->base + WBSD_CSR);
+
+       mdelay(1);
+
+       csr = inb(host->base + WBSD_CSR);
+       csr &= ~WBSD_MSLED;
+       outb(csr, host->base + WBSD_CSR);
+
        spin_unlock_bh(&host->lock);
+
+       return csr & WBSD_WRPT;
 }
 
 static struct mmc_host_ops wbsd_ops = {
        .request        = wbsd_request,
        .set_ios        = wbsd_set_ios,
+       .get_ro         = wbsd_get_ro,
 };
 
 /*****************************************************************************\
@@ -1035,6 +1086,31 @@ static struct mmc_host_ops wbsd_ops = {
  *                                                                           *
 \*****************************************************************************/
 
+/*
+ * Helper function to reset detection ignore
+ */
+
+static void wbsd_reset_ignore(unsigned long data)
+{
+       struct wbsd_host *host = (struct wbsd_host*)data;
+
+       BUG_ON(host == NULL);
+
+       DBG("Resetting card detection ignore\n");
+
+       spin_lock_bh(&host->lock);
+
+       host->flags &= ~WBSD_FIGNORE_DETECT;
+
+       /*
+        * Card status might have changed during the
+        * blackout.
+        */
+       tasklet_schedule(&host->card_tasklet);
+
+       spin_unlock_bh(&host->lock);
+}
+
 /*
  * Helper function for card detection
  */
@@ -1097,7 +1173,7 @@ static void wbsd_tasklet_card(unsigned long param)
                         * Delay card detection to allow electrical connections
                         * to stabilise.
                         */
-                       mod_timer(&host->timer, jiffies + HZ/2);
+                       mod_timer(&host->detect_timer, jiffies + HZ/2);
                }
                
                spin_unlock(&host->lock);
@@ -1124,6 +1200,8 @@ static void wbsd_tasklet_card(unsigned long param)
 
                mmc_detect_change(host->mmc);
        }
+       else
+               spin_unlock(&host->lock);
 }
 
 static void wbsd_tasklet_fifo(unsigned long param)
@@ -1324,15 +1402,20 @@ static int __devinit wbsd_alloc_mmc(struct device* dev)
        mmc->f_min = 375000;
        mmc->f_max = 24000000;
        mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+       mmc->caps = MMC_CAP_4_BIT_DATA;
        
        spin_lock_init(&host->lock);
        
        /*
-        * Set up detection timer
+        * Set up timers
         */
-       init_timer(&host->timer);
-       host->timer.data = (unsigned long)host;
-       host->timer.function = wbsd_detect_card;
+       init_timer(&host->detect_timer);
+       host->detect_timer.data = (unsigned long)host;
+       host->detect_timer.function = wbsd_detect_card;
+
+       init_timer(&host->ignore_timer);
+       host->ignore_timer.data = (unsigned long)host;
+       host->ignore_timer.function = wbsd_reset_ignore;
        
        /*
         * Maximum number of segments. Worst case is one sector per segment
@@ -1370,7 +1453,8 @@ static void __devexit wbsd_free_mmc(struct device* dev)
        host = mmc_priv(mmc);
        BUG_ON(host == NULL);
        
-       del_timer_sync(&host->timer);
+       del_timer_sync(&host->ignore_timer);
+       del_timer_sync(&host->detect_timer);
        
        mmc_free_host(mmc);
        
@@ -1796,7 +1880,7 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma,
        
        mmc_add_host(mmc);
 
-       printk(KERN_INFO "%s: W83L51xD", mmc->host_name);
+       printk(KERN_INFO "%s: W83L51xD", mmc_hostname(mmc));
        if (host->chip_id != 0)
                printk(" id %x", (int)host->chip_id);
        printk(" at 0x%x irq %d", (int)host->base, (int)host->irq);
index 661a9f6a6e6ff5b63cfc423f1bd203fa5b1eb614..9005b5241b3cce44c132f13be7e9b5270cfc691c 100644 (file)
 #define WBSD_CLK_16M           0x02
 #define WBSD_CLK_24M           0x03
 
+#define WBSD_DATA_WIDTH                0x01
+
 #define WBSD_DAT3_H            0x08
 #define WBSD_FIFO_RESET                0x04
 #define WBSD_SOFT_RESET                0x02
@@ -164,6 +166,7 @@ struct wbsd_host
        int                     firsterr;       /* See fifo functions */
        
        u8                      clk;            /* Current clock speed */
+       unsigned char           bus_width;      /* Current bus width */
        
        int                     config;         /* Config port */
        u8                      unlock_code;    /* Code to unlock config */
@@ -181,5 +184,6 @@ struct wbsd_host
        struct tasklet_struct   finish_tasklet;
        struct tasklet_struct   block_tasklet;
        
-       struct timer_list       timer;          /* Card detection timer */
+       struct timer_list       detect_timer;   /* Card detection timer */
+       struct timer_list       ignore_timer;   /* Ignore detection timer */
 };
index eee5115658c8c37bc3bf91136f48494e4221cb16..04e54318bc6a603f2c44b32e3b2f8b5b260a64dc 100644 (file)
@@ -526,6 +526,7 @@ static void nand_wait_ready(struct mtd_info *mtd)
        do {
                if (this->dev_ready(mtd))
                        return;
+               touch_softlockup_watchdog();
        } while (time_before(jiffies, timeo));  
 }
 
index 07746b95fd83754cb3875bdea4ebe9b545bbcf6c..455ba915ede738adc53f533f1b0a672cb07228d9 100644 (file)
@@ -973,6 +973,11 @@ static int vortex_suspend (struct pci_dev *pdev, pm_message_t state)
                        netif_device_detach(dev);
                        vortex_down(dev, 1);
                }
+               pci_save_state(pdev);
+               pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+               free_irq(dev->irq, dev);
+               pci_disable_device(pdev);
+               pci_set_power_state(pdev, pci_choose_state(pdev, state));
        }
        return 0;
 }
@@ -980,8 +985,19 @@ static int vortex_suspend (struct pci_dev *pdev, pm_message_t state)
 static int vortex_resume (struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
+       struct vortex_private *vp = netdev_priv(dev);
 
-       if (dev && dev->priv) {
+       if (dev && vp) {
+               pci_set_power_state(pdev, PCI_D0);
+               pci_restore_state(pdev);
+               pci_enable_device(pdev);
+               pci_set_master(pdev);
+               if (request_irq(dev->irq, vp->full_bus_master_rx ?
+                               &boomerang_interrupt : &vortex_interrupt, SA_SHIRQ, dev->name, dev)) {
+                       printk(KERN_WARNING "%s: Could not reserve IRQ %d\n", dev->name, dev->irq);
+                       pci_disable_device(pdev);
+                       return -EBUSY;
+               }
                if (netif_running(dev)) {
                        vortex_up(dev);
                        netif_device_attach(dev);
@@ -1873,6 +1889,7 @@ vortex_timer(unsigned long data)
                {
                        spin_lock_bh(&vp->lock);
                        mii_status = mdio_read(dev, vp->phys[0], 1);
+                       mii_status = mdio_read(dev, vp->phys[0], 1);
                        ok = 1;
                        if (vortex_debug > 2)
                                printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n",
index 8edb6936fb9b846810645f6f3f6de4164dec172a..6bb9232514b4e95a1b6506fe792e61a5f46779e5 100644 (file)
@@ -131,6 +131,8 @@ config NET_SB1000
 
        source "drivers/net/arcnet/Kconfig"
 
+source "drivers/net/phy/Kconfig"
+
 #
 #      Ethernet
 #
@@ -395,7 +397,7 @@ config SUN3LANCE
          If you're not building a kernel for a Sun 3, say N.
 
 config SUN3_82586
-       tristate "Sun3 on-board Intel 82586 support"
+       bool "Sun3 on-board Intel 82586 support"
        depends on NET_ETHERNET && SUN3
        help
          This driver enables support for the on-board Intel 82586 based
@@ -445,7 +447,7 @@ config NET_SB1250_MAC
 
 config SGI_IOC3_ETH
        bool "SGI IOC3 Ethernet"
-       depends on NET_ETHERNET && PCI && SGI_IP27
+       depends on NET_ETHERNET && PCI && SGI_IP27 && BROKEN
        select CRC32
        select MII
        help
@@ -1921,6 +1923,20 @@ config R8169_VLAN
          
          If in doubt, say Y.
 
+config SIS190
+       tristate "SiS190/SiS191 gigabit ethernet support"
+       depends on PCI
+       select CRC32
+       select MII
+       ---help---
+         Say Y here if you have a SiS 190 PCI Fast Ethernet adapter or
+         a SiS 191 PCI Gigabit Ethernet adapter. Both are expected to
+         appear in lan on motherboard designs which are based on SiS 965
+         and SiS 966 south bridge.
+
+         To compile this driver as a module, choose M here: the module
+         will be called sis190.  This is recommended.
+
 config SKGE
        tristate "New SysKonnect GigaEthernet support (EXPERIMENTAL)"
        depends on PCI && EXPERIMENTAL
@@ -2042,6 +2058,13 @@ config BNX2
          To compile this driver as a module, choose M here: the module
          will be called bnx2.  This is recommended.
 
+config SPIDER_NET
+       tristate "Spider Gigabit Ethernet driver"
+       depends on PCI && PPC_BPA
+       help
+         This driver supports the Gigabit Ethernet chips present on the
+         Cell Processor-Based Blades from IBM.
+
 config GIANFAR
        tristate "Gianfar Ethernet"
        depends on 85xx || 83xx
@@ -2091,6 +2114,25 @@ endmenu
 menu "Ethernet (10000 Mbit)"
        depends on !UML
 
+config CHELSIO_T1
+        tristate "Chelsio 10Gb Ethernet support"
+        depends on PCI
+        help
+          This driver supports Chelsio N110 and N210 models 10Gb Ethernet
+          cards. More information about adapter features and performance
+          tuning is in <file:Documentation/networking/cxgb.txt>.
+
+          For general information about Chelsio and our products, visit
+          our website at <http://www.chelsio.com>.
+
+          For customer support, please visit our customer support page at
+          <http://www.chelsio.com/support.htm>.
+
+          Please send feedback to <linux-bugs@chelsio.com>.
+
+          To compile this driver as a module, choose M here: the module
+          will be called cxgb.
+
 config IXGB
        tristate "Intel(R) PRO/10GbE support"
        depends on PCI
index 63c6d1e6d4d982937ada0fdaca07003ec29ef9e6..8645c843cf4d0216c8e8e4a53b202d7a576c2b07 100644 (file)
@@ -9,6 +9,7 @@ endif
 obj-$(CONFIG_E1000) += e1000/
 obj-$(CONFIG_IBM_EMAC) += ibm_emac/
 obj-$(CONFIG_IXGB) += ixgb/
+obj-$(CONFIG_CHELSIO_T1) += chelsio/
 obj-$(CONFIG_BONDING) += bonding/
 obj-$(CONFIG_GIANFAR) += gianfar_driver.o
 
@@ -42,6 +43,7 @@ obj-$(CONFIG_EEPRO100) += eepro100.o
 obj-$(CONFIG_E100) += e100.o
 obj-$(CONFIG_TLAN) += tlan.o
 obj-$(CONFIG_EPIC100) += epic100.o
+obj-$(CONFIG_SIS190) += sis190.o
 obj-$(CONFIG_SIS900) += sis900.o
 obj-$(CONFIG_YELLOWFIN) += yellowfin.o
 obj-$(CONFIG_ACENIC) += acenic.o
@@ -52,6 +54,8 @@ obj-$(CONFIG_STNIC) += stnic.o 8390.o
 obj-$(CONFIG_FEALNX) += fealnx.o
 obj-$(CONFIG_TIGON3) += tg3.o
 obj-$(CONFIG_BNX2) += bnx2.o
+spidernet-y += spider_net.o spider_net_ethtool.o sungem_phy.o
+obj-$(CONFIG_SPIDER_NET) += spidernet.o
 obj-$(CONFIG_TC35815) += tc35815.o
 obj-$(CONFIG_SKGE) += skge.o
 obj-$(CONFIG_SK98LIN) += sk98lin/
@@ -65,6 +69,7 @@ obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
 #
 
 obj-$(CONFIG_MII) += mii.o
+obj-$(CONFIG_PHYLIB) += phy/
 
 obj-$(CONFIG_SUNDANCE) += sundance.o
 obj-$(CONFIG_HAMACHI) += hamachi.o
index 3707df6b0cfaf5a734ef7de6e636fd8a1aecaa76..60304f7e7e5b9703a6973a733cb452ff44517b18 100644 (file)
@@ -87,7 +87,6 @@ extern struct net_device *mvme147lance_probe(int unit);
 extern struct net_device *tc515_probe(int unit);
 extern struct net_device *lance_probe(int unit);
 extern struct net_device *mace_probe(int unit);
-extern struct net_device *macsonic_probe(int unit);
 extern struct net_device *mac8390_probe(int unit);
 extern struct net_device *mac89x0_probe(int unit);
 extern struct net_device *mc32_probe(int unit);
@@ -284,9 +283,6 @@ static struct devprobe2 m68k_probes[] __initdata = {
 #ifdef CONFIG_MACMACE          /* Mac 68k Quadra AV builtin Ethernet */
        {mace_probe, 0},
 #endif
-#ifdef CONFIG_MACSONIC         /* Mac SONIC-based Ethernet of all sorts */ 
-       {macsonic_probe, 0},
-#endif
 #ifdef CONFIG_MAC8390           /* NuBus NS8390-based cards */
        {mac8390_probe, 0},
 #endif
@@ -318,17 +314,9 @@ static void __init ethif_probe2(int unit)
 #ifdef CONFIG_TR
 /* Token-ring device probe */
 extern int ibmtr_probe_card(struct net_device *);
-extern struct net_device *sk_isa_probe(int unit);
-extern struct net_device *proteon_probe(int unit);
 extern struct net_device *smctr_probe(int unit);
 
 static struct devprobe2 tr_probes2[] __initdata = {
-#ifdef CONFIG_SKISA
-       {sk_isa_probe, 0},
-#endif
-#ifdef CONFIG_PROTEON
-       {proteon_probe, 0},
-#endif
 #ifdef CONFIG_SMCTR
        {smctr_probe, 0},
 #endif
index 91791ba3776930bb8354ad691680ac00e0882b85..8a0af5453e21c93ed6eb19e7d8d925b65cc16cee 100644 (file)
@@ -275,7 +275,7 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev)
        return 0;
 out2:
        if (ei_status.reg0)
-               iounmap((void *)dev->mem_start);
+               iounmap(ei_status.mem);
 out1:
        free_irq(dev->irq, dev);
 out:
index 4f9f69e22c1bd3c2f63c17f245d95f67e3565ca3..12ef52c193a39a2e1743bda3292110c4f76279d8 100644 (file)
@@ -597,7 +597,7 @@ static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev)
        struct ArcProto *proto;
        int txbuf;
        unsigned long flags;
-       int freeskb = 0;
+       int freeskb, retval;
 
        BUGMSG(D_DURING,
               "transmit requested (status=%Xh, txbufs=%d/%d, len=%d, protocol %x)\n",
@@ -615,7 +615,7 @@ static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev)
        if (skb->len - ARC_HDR_SIZE > XMTU && !proto->continue_tx) {
                BUGMSG(D_NORMAL, "fixme: packet too large: compensating badly!\n");
                dev_kfree_skb(skb);
-               return 0;       /* don't try again */
+               return NETDEV_TX_OK;    /* don't try again */
        }
 
        /* We're busy transmitting a packet... */
@@ -623,8 +623,11 @@ static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev)
 
        spin_lock_irqsave(&lp->lock, flags);
        AINTMASK(0);
-
-       txbuf = get_arcbuf(dev);
+       if(lp->next_tx == -1)
+               txbuf = get_arcbuf(dev);
+       else {
+               txbuf = -1;
+       }
        if (txbuf != -1) {
                if (proto->prepare_tx(dev, pkt, skb->len, txbuf) &&
                    !proto->ack_tx) {
@@ -638,6 +641,8 @@ static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev)
                        lp->outgoing.skb = skb;
                        lp->outgoing.pkt = pkt;
 
+                       freeskb = 0;
+
                        if (proto->continue_tx &&
                            proto->continue_tx(dev, txbuf)) {
                          BUGMSG(D_NORMAL,
@@ -645,10 +650,12 @@ static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev)
                                 "(proto='%c')\n", proto->suffix);
                        }
                }
-
+               retval = NETDEV_TX_OK;
+               dev->trans_start = jiffies;
                lp->next_tx = txbuf;
        } else {
-               freeskb = 1;
+               retval = NETDEV_TX_BUSY;
+               freeskb = 0;
        }
 
        BUGMSG(D_DEBUG, "%s: %d: %s, status: %x\n",__FILE__,__LINE__,__FUNCTION__,ASTATUS());
@@ -664,7 +671,7 @@ static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev)
        if (freeskb) {
                dev_kfree_skb(skb);
        }
-       return 0;               /* no need to try again */
+       return retval;          /* no need to try again */
 }
 
 
@@ -690,7 +697,6 @@ static int go_tx(struct net_device *dev)
        /* start sending */
        ACOMMAND(TXcmd | (lp->cur_tx << 3));
 
-       dev->trans_start = jiffies;
        lp->stats.tx_packets++;
        lp->lasttrans_dest = lp->lastload_dest;
        lp->lastload_dest = 0;
@@ -917,6 +923,9 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
                        BUGMSG(D_RECON, "Network reconfiguration detected (status=%Xh)\n",
                               status);
+                       /* MYRECON bit is at bit 7 of diagstatus */
+                       if(diagstatus & 0x80)
+                               BUGMSG(D_RECON,"Put out that recon myself\n");
 
                        /* is the RECON info empty or old? */
                        if (!lp->first_recon || !lp->last_recon ||
index ad011214c7f2a0ffc19029642aacda83e3065e6a..e01b6a78ec6330115ce08a104498aeb3dbf91194 100644 (file)
@@ -235,7 +235,7 @@ struct lance_private {
 #define        MEM             lp->mem
 #define        DREG    IO->data
 #define        AREG    IO->addr
-#define        REGA(a) ( AREG = (a), DREG )
+#define        REGA(a) (*( AREG = (a), &DREG ))
 
 /* Definitions for packet buffer access: */
 #define PKT_BUF_SZ             1544
index 8acc655ec1e82e911c88cea2cbe8340cb2ab89d2..55a72c7ad001a20ae03b4c3ebf3fe61281688884 100644 (file)
@@ -14,8 +14,8 @@
 
 #define DRV_MODULE_NAME                "bnx2"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "1.2.19"
-#define DRV_MODULE_RELDATE     "May 23, 2005"
+#define DRV_MODULE_VERSION     "1.2.20"
+#define DRV_MODULE_RELDATE     "August 22, 2005"
 
 #define RUN_AT(x) (jiffies + (x))
 
@@ -52,7 +52,6 @@ static struct {
        { "HP NC370i Multifunction Gigabit Server Adapter" },
        { "Broadcom NetXtreme II BCM5706 1000Base-SX" },
        { "HP NC370F Multifunction Gigabit Server Adapter" },
-       { 0 },
        };
 
 static struct pci_device_id bnx2_pci_tbl[] = {
@@ -108,6 +107,15 @@ static struct flash_spec flash_table[] =
 
 MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
 
+static inline u32 bnx2_tx_avail(struct bnx2 *bp)
+{
+       u32 diff = TX_RING_IDX(bp->tx_prod) - TX_RING_IDX(bp->tx_cons);
+
+       if (diff > MAX_TX_DESC_CNT)
+               diff = (diff & MAX_TX_DESC_CNT) - 1;
+       return (bp->tx_ring_size - diff);
+}
+
 static u32
 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
 {
@@ -807,7 +815,19 @@ bnx2_setup_serdes_phy(struct bnx2 *bp)
                bnx2_write_phy(bp, MII_ADVERTISE, new_adv);
                bnx2_write_phy(bp, MII_BMCR, bmcr | BMCR_ANRESTART |
                        BMCR_ANENABLE);
-               bp->serdes_an_pending = SERDES_AN_TIMEOUT / bp->timer_interval;
+               if (CHIP_NUM(bp) == CHIP_NUM_5706) {
+                       /* Speed up link-up time when the link partner
+                        * does not autonegotiate which is very common
+                        * in blade servers. Some blade servers use
+                        * IPMI for kerboard input and it's important
+                        * to minimize link disruptions. Autoneg. involves
+                        * exchanging base pages plus 3 next pages and
+                        * normally completes in about 120 msec.
+                        */
+                       bp->current_interval = SERDES_AN_TIMEOUT;
+                       bp->serdes_an_pending = 1;
+                       mod_timer(&bp->timer, jiffies + bp->current_interval);
+               }
        }
 
        return 0;
@@ -1327,22 +1347,17 @@ bnx2_tx_int(struct bnx2 *bp)
                }
        }
 
-       atomic_add(tx_free_bd, &bp->tx_avail_bd);
+       bp->tx_cons = sw_cons;
 
        if (unlikely(netif_queue_stopped(bp->dev))) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&bp->tx_lock, flags);
+               spin_lock(&bp->tx_lock);
                if ((netif_queue_stopped(bp->dev)) &&
-                       (atomic_read(&bp->tx_avail_bd) > MAX_SKB_FRAGS)) {
+                   (bnx2_tx_avail(bp) > MAX_SKB_FRAGS)) {
 
                        netif_wake_queue(bp->dev);
                }
-               spin_unlock_irqrestore(&bp->tx_lock, flags);
+               spin_unlock(&bp->tx_lock);
        }
-
-       bp->tx_cons = sw_cons;
-
 }
 
 static inline void
@@ -1523,15 +1538,12 @@ bnx2_msi(int irq, void *dev_instance, struct pt_regs *regs)
                BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
 
        /* Return here if interrupt is disabled. */
-       if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
-               return IRQ_RETVAL(1);
-       }
+       if (unlikely(atomic_read(&bp->intr_sem) != 0))
+               return IRQ_HANDLED;
 
-       if (netif_rx_schedule_prep(dev)) {
-               __netif_rx_schedule(dev);
-       }
+       netif_rx_schedule(dev);
 
-       return IRQ_RETVAL(1);
+       return IRQ_HANDLED;
 }
 
 static irqreturn_t
@@ -1549,22 +1561,19 @@ bnx2_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
        if ((bp->status_blk->status_idx == bp->last_status_idx) ||
            (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
             BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
-               return IRQ_RETVAL(0);
+               return IRQ_NONE;
 
        REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
                BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
                BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
 
        /* Return here if interrupt is shared and is disabled. */
-       if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
-               return IRQ_RETVAL(1);
-       }
+       if (unlikely(atomic_read(&bp->intr_sem) != 0))
+               return IRQ_HANDLED;
 
-       if (netif_rx_schedule_prep(dev)) {
-               __netif_rx_schedule(dev);
-       }
+       netif_rx_schedule(dev);
 
-       return IRQ_RETVAL(1);
+       return IRQ_HANDLED;
 }
 
 static int
@@ -1581,11 +1590,9 @@ bnx2_poll(struct net_device *dev, int *budget)
                (bp->status_blk->status_attn_bits_ack &
                STATUS_ATTN_BITS_LINK_STATE)) {
 
-               unsigned long flags;
-
-               spin_lock_irqsave(&bp->phy_lock, flags);
+               spin_lock(&bp->phy_lock);
                bnx2_phy_int(bp);
-               spin_unlock_irqrestore(&bp->phy_lock, flags);
+               spin_unlock(&bp->phy_lock);
        }
 
        if (bp->status_blk->status_tx_quick_consumer_index0 != bp->tx_cons) {
@@ -1628,9 +1635,8 @@ bnx2_set_rx_mode(struct net_device *dev)
        struct bnx2 *bp = dev->priv;
        u32 rx_mode, sort_mode;
        int i;
-       unsigned long flags;
 
-       spin_lock_irqsave(&bp->phy_lock, flags);
+       spin_lock_bh(&bp->phy_lock);
 
        rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
                                  BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
@@ -1691,7 +1697,7 @@ bnx2_set_rx_mode(struct net_device *dev)
        REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
        REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
 
-       spin_unlock_irqrestore(&bp->phy_lock, flags);
+       spin_unlock_bh(&bp->phy_lock);
 }
 
 static void
@@ -1998,14 +2004,14 @@ bnx2_init_cpus(struct bnx2 *bp)
 }
 
 static int
-bnx2_set_power_state(struct bnx2 *bp, int state)
+bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
 {
        u16 pmcsr;
 
        pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
 
        switch (state) {
-       case 0: {
+       case PCI_D0: {
                u32 val;
 
                pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
@@ -2026,7 +2032,7 @@ bnx2_set_power_state(struct bnx2 *bp, int state)
                REG_WR(bp, BNX2_RPM_CONFIG, val);
                break;
        }
-       case 3: {
+       case PCI_D3hot: {
                int i;
                u32 val, wol_msg;
 
@@ -2960,7 +2966,6 @@ bnx2_init_tx_ring(struct bnx2 *bp)
        bp->tx_prod = 0;
        bp->tx_cons = 0;
        bp->tx_prod_bseq = 0;
-       atomic_set(&bp->tx_avail_bd, bp->tx_ring_size);
        
        val = BNX2_L2CTX_TYPE_TYPE_L2;
        val |= BNX2_L2CTX_TYPE_SIZE_L2;
@@ -3507,11 +3512,11 @@ bnx2_test_registers(struct bnx2 *bp)
                rw_mask = reg_tbl[i].rw_mask;
                ro_mask = reg_tbl[i].ro_mask;
 
-               save_val = readl((u8 *) bp->regview + offset);
+               save_val = readl(bp->regview + offset);
 
-               writel(0, (u8 *) bp->regview + offset);
+               writel(0, bp->regview + offset);
 
-               val = readl((u8 *) bp->regview + offset);
+               val = readl(bp->regview + offset);
                if ((val & rw_mask) != 0) {
                        goto reg_test_err;
                }
@@ -3520,9 +3525,9 @@ bnx2_test_registers(struct bnx2 *bp)
                        goto reg_test_err;
                }
 
-               writel(0xffffffff, (u8 *) bp->regview + offset);
+               writel(0xffffffff, bp->regview + offset);
 
-               val = readl((u8 *) bp->regview + offset);
+               val = readl(bp->regview + offset);
                if ((val & rw_mask) != rw_mask) {
                        goto reg_test_err;
                }
@@ -3531,11 +3536,11 @@ bnx2_test_registers(struct bnx2 *bp)
                        goto reg_test_err;
                }
 
-               writel(save_val, (u8 *) bp->regview + offset);
+               writel(save_val, bp->regview + offset);
                continue;
 
 reg_test_err:
-               writel(save_val, (u8 *) bp->regview + offset);
+               writel(save_val, bp->regview + offset);
                ret = -ENODEV;
                break;
        }
@@ -3752,10 +3757,10 @@ bnx2_test_link(struct bnx2 *bp)
 {
        u32 bmsr;
 
-       spin_lock_irq(&bp->phy_lock);
+       spin_lock_bh(&bp->phy_lock);
        bnx2_read_phy(bp, MII_BMSR, &bmsr);
        bnx2_read_phy(bp, MII_BMSR, &bmsr);
-       spin_unlock_irq(&bp->phy_lock);
+       spin_unlock_bh(&bp->phy_lock);
                
        if (bmsr & BMSR_LSTATUS) {
                return 0;
@@ -3801,6 +3806,9 @@ bnx2_timer(unsigned long data)
        struct bnx2 *bp = (struct bnx2 *) data;
        u32 msg;
 
+       if (!netif_running(bp->dev))
+               return;
+
        if (atomic_read(&bp->intr_sem) != 0)
                goto bnx2_restart_timer;
 
@@ -3809,15 +3817,16 @@ bnx2_timer(unsigned long data)
 
        if ((bp->phy_flags & PHY_SERDES_FLAG) &&
            (CHIP_NUM(bp) == CHIP_NUM_5706)) {
-               unsigned long flags;
 
-               spin_lock_irqsave(&bp->phy_lock, flags);
+               spin_lock(&bp->phy_lock);
                if (bp->serdes_an_pending) {
                        bp->serdes_an_pending--;
                }
                else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
                        u32 bmcr;
 
+                       bp->current_interval = bp->timer_interval;
+
                        bnx2_read_phy(bp, MII_BMCR, &bmcr);
 
                        if (bmcr & BMCR_ANENABLE) {
@@ -3860,14 +3869,14 @@ bnx2_timer(unsigned long data)
 
                        }
                }
+               else
+                       bp->current_interval = bp->timer_interval;
 
-               spin_unlock_irqrestore(&bp->phy_lock, flags);
+               spin_unlock(&bp->phy_lock);
        }
 
 bnx2_restart_timer:
-       bp->timer.expires = RUN_AT(bp->timer_interval);
-
-       add_timer(&bp->timer);
+       mod_timer(&bp->timer, jiffies + bp->current_interval);
 }
 
 /* Called with rtnl_lock */
@@ -3877,7 +3886,7 @@ bnx2_open(struct net_device *dev)
        struct bnx2 *bp = dev->priv;
        int rc;
 
-       bnx2_set_power_state(bp, 0);
+       bnx2_set_power_state(bp, PCI_D0);
        bnx2_disable_int(bp);
 
        rc = bnx2_alloc_mem(bp);
@@ -3920,12 +3929,7 @@ bnx2_open(struct net_device *dev)
                return rc;
        }
        
-       init_timer(&bp->timer);
-
-       bp->timer.expires = RUN_AT(bp->timer_interval);
-       bp->timer.data = (unsigned long) bp;
-       bp->timer.function = bnx2_timer;
-       add_timer(&bp->timer);
+       mod_timer(&bp->timer, jiffies + bp->current_interval);
 
        atomic_set(&bp->intr_sem, 0);
 
@@ -3976,12 +3980,17 @@ bnx2_reset_task(void *data)
 {
        struct bnx2 *bp = data;
 
+       if (!netif_running(bp->dev))
+               return;
+
+       bp->in_reset_task = 1;
        bnx2_netif_stop(bp);
 
        bnx2_init_nic(bp);
 
        atomic_set(&bp->intr_sem, 1);
        bnx2_netif_start(bp);
+       bp->in_reset_task = 0;
 }
 
 static void
@@ -4041,9 +4050,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
        u16 prod, ring_prod;
        int i;
 
-       if (unlikely(atomic_read(&bp->tx_avail_bd) <
-               (skb_shinfo(skb)->nr_frags + 1))) {
-
+       if (unlikely(bnx2_tx_avail(bp) < (skb_shinfo(skb)->nr_frags + 1))) {
                netif_stop_queue(dev);
                printk(KERN_ERR PFX "%s: BUG! Tx ring full when queue awake!\n",
                        dev->name);
@@ -4140,8 +4147,6 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
        prod = NEXT_TX_BD(prod);
        bp->tx_prod_bseq += skb->len;
 
-       atomic_sub(last_frag + 1, &bp->tx_avail_bd);
-
        REG_WR16(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BIDX, prod);
        REG_WR(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BSEQ, bp->tx_prod_bseq);
 
@@ -4150,17 +4155,13 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
        bp->tx_prod = prod;
        dev->trans_start = jiffies;
 
-       if (unlikely(atomic_read(&bp->tx_avail_bd) <= MAX_SKB_FRAGS)) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&bp->tx_lock, flags);
-               if (atomic_read(&bp->tx_avail_bd) <= MAX_SKB_FRAGS) {
-                       netif_stop_queue(dev);
-
-                       if (atomic_read(&bp->tx_avail_bd) > MAX_SKB_FRAGS)
-                               netif_wake_queue(dev);
-               }
-               spin_unlock_irqrestore(&bp->tx_lock, flags);
+       if (unlikely(bnx2_tx_avail(bp) <= MAX_SKB_FRAGS)) {
+               spin_lock(&bp->tx_lock);
+               netif_stop_queue(dev);
+               
+               if (bnx2_tx_avail(bp) > MAX_SKB_FRAGS)
+                       netif_wake_queue(dev);
+               spin_unlock(&bp->tx_lock);
        }
 
        return NETDEV_TX_OK;
@@ -4173,7 +4174,13 @@ bnx2_close(struct net_device *dev)
        struct bnx2 *bp = dev->priv;
        u32 reset_code;
 
-       flush_scheduled_work();
+       /* Calling flush_scheduled_work() may deadlock because
+        * linkwatch_event() may be on the workqueue and it will try to get
+        * the rtnl_lock which we are holding.
+        */
+       while (bp->in_reset_task)
+               msleep(1);
+
        bnx2_netif_stop(bp);
        del_timer_sync(&bp->timer);
        if (bp->wol)
@@ -4190,7 +4197,7 @@ bnx2_close(struct net_device *dev)
        bnx2_free_mem(bp);
        bp->link_up = 0;
        netif_carrier_off(bp->dev);
-       bnx2_set_power_state(bp, 3);
+       bnx2_set_power_state(bp, PCI_D3hot);
        return 0;
 }
 
@@ -4390,11 +4397,11 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        bp->req_line_speed = req_line_speed;
        bp->req_duplex = req_duplex;
 
-       spin_lock_irq(&bp->phy_lock);
+       spin_lock_bh(&bp->phy_lock);
 
        bnx2_setup_phy(bp);
 
-       spin_unlock_irq(&bp->phy_lock);
+       spin_unlock_bh(&bp->phy_lock);
 
        return 0;
 }
@@ -4464,19 +4471,20 @@ bnx2_nway_reset(struct net_device *dev)
                return -EINVAL;
        }
 
-       spin_lock_irq(&bp->phy_lock);
+       spin_lock_bh(&bp->phy_lock);
 
        /* Force a link down visible on the other side */
        if (bp->phy_flags & PHY_SERDES_FLAG) {
                bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
-               spin_unlock_irq(&bp->phy_lock);
+               spin_unlock_bh(&bp->phy_lock);
 
                msleep(20);
 
-               spin_lock_irq(&bp->phy_lock);
+               spin_lock_bh(&bp->phy_lock);
                if (CHIP_NUM(bp) == CHIP_NUM_5706) {
-                       bp->serdes_an_pending = SERDES_AN_TIMEOUT /
-                               bp->timer_interval;
+                       bp->current_interval = SERDES_AN_TIMEOUT;
+                       bp->serdes_an_pending = 1;
+                       mod_timer(&bp->timer, jiffies + bp->current_interval);
                }
        }
 
@@ -4484,7 +4492,7 @@ bnx2_nway_reset(struct net_device *dev)
        bmcr &= ~BMCR_LOOPBACK;
        bnx2_write_phy(bp, MII_BMCR, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
 
-       spin_unlock_irq(&bp->phy_lock);
+       spin_unlock_bh(&bp->phy_lock);
 
        return 0;
 }
@@ -4670,11 +4678,11 @@ bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
                bp->autoneg &= ~AUTONEG_FLOW_CTRL;
        }
 
-       spin_lock_irq(&bp->phy_lock);
+       spin_lock_bh(&bp->phy_lock);
 
        bnx2_setup_phy(bp);
 
-       spin_unlock_irq(&bp->phy_lock);
+       spin_unlock_bh(&bp->phy_lock);
 
        return 0;
 }
@@ -4698,7 +4706,7 @@ bnx2_set_rx_csum(struct net_device *dev, u32 data)
 
 #define BNX2_NUM_STATS 45
 
-struct {
+static struct {
        char string[ETH_GSTRING_LEN];
 } bnx2_stats_str_arr[BNX2_NUM_STATS] = {
        { "rx_bytes" },
@@ -4750,7 +4758,7 @@ struct {
 
 #define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
 
-unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
+static unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
     STATS_OFFSET32(stat_IfHCInOctets_hi),
     STATS_OFFSET32(stat_IfHCInBadOctets_hi),
     STATS_OFFSET32(stat_IfHCOutOctets_hi),
@@ -4801,7 +4809,7 @@ unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
 /* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
  * skipped because of errata.
  */               
-u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
+static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
        8,0,8,8,8,8,8,8,8,8,
        4,0,4,4,4,4,4,4,4,4,
        4,4,4,4,4,4,4,4,4,4,
@@ -4811,7 +4819,7 @@ u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
 
 #define BNX2_NUM_TESTS 6
 
-struct {
+static struct {
        char string[ETH_GSTRING_LEN];
 } bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
        { "register_test (offline)" },
@@ -4910,7 +4918,7 @@ bnx2_get_ethtool_stats(struct net_device *dev,
        struct bnx2 *bp = dev->priv;
        int i;
        u32 *hw_stats = (u32 *) bp->stats_blk;
-       u8 *stats_len_arr = 0;
+       u8 *stats_len_arr = NULL;
 
        if (hw_stats == NULL) {
                memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
@@ -5012,7 +5020,7 @@ static struct ethtool_ops bnx2_ethtool_ops = {
 static int
 bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-       struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
+       struct mii_ioctl_data *data = if_mii(ifr);
        struct bnx2 *bp = dev->priv;
        int err;
 
@@ -5024,9 +5032,9 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        case SIOCGMIIREG: {
                u32 mii_regval;
 
-               spin_lock_irq(&bp->phy_lock);
+               spin_lock_bh(&bp->phy_lock);
                err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
-               spin_unlock_irq(&bp->phy_lock);
+               spin_unlock_bh(&bp->phy_lock);
 
                data->val_out = mii_regval;
 
@@ -5037,9 +5045,9 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                if (!capable(CAP_NET_ADMIN))
                        return -EPERM;
 
-               spin_lock_irq(&bp->phy_lock);
+               spin_lock_bh(&bp->phy_lock);
                err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
-               spin_unlock_irq(&bp->phy_lock);
+               spin_unlock_bh(&bp->phy_lock);
 
                return err;
 
@@ -5057,6 +5065,9 @@ bnx2_change_mac_addr(struct net_device *dev, void *p)
        struct sockaddr *addr = p;
        struct bnx2 *bp = dev->priv;
 
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EINVAL;
+
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
        if (netif_running(dev))
                bnx2_set_mac_addr(bp);
@@ -5192,7 +5203,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
                               BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
                               BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
 
-       bnx2_set_power_state(bp, 0);
+       bnx2_set_power_state(bp, PCI_D0);
 
        bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
 
@@ -5305,6 +5316,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        bp->stats_ticks = 1000000 & 0xffff00;
 
        bp->timer_interval =  HZ;
+       bp->current_interval =  HZ;
 
        /* Disable WOL support if we are running on a SERDES chip. */
        if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT) {
@@ -5328,6 +5340,15 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        bp->req_line_speed = 0;
        if (bp->phy_flags & PHY_SERDES_FLAG) {
                bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
+
+               reg = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE +
+                                BNX2_PORT_HW_CFG_CONFIG);
+               reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
+               if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
+                       bp->autoneg = 0;
+                       bp->req_line_speed = bp->line_speed = SPEED_1000;
+                       bp->req_duplex = DUPLEX_FULL;
+               }
        }
        else {
                bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
@@ -5335,11 +5356,17 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 
        bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
 
+       init_timer(&bp->timer);
+       bp->timer.expires = RUN_AT(bp->timer_interval);
+       bp->timer.data = (unsigned long) bp;
+       bp->timer.function = bnx2_timer;
+
        return 0;
 
 err_out_unmap:
        if (bp->regview) {
                iounmap(bp->regview);
+               bp->regview = NULL;
        }
 
 err_out_release:
@@ -5454,6 +5481,8 @@ bnx2_remove_one(struct pci_dev *pdev)
        struct net_device *dev = pci_get_drvdata(pdev);
        struct bnx2 *bp = dev->priv;
 
+       flush_scheduled_work();
+
        unregister_netdev(dev);
 
        if (bp->regview)
@@ -5466,7 +5495,7 @@ bnx2_remove_one(struct pci_dev *pdev)
 }
 
 static int
-bnx2_suspend(struct pci_dev *pdev, u32 state)
+bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
        struct bnx2 *bp = dev->priv;
@@ -5484,7 +5513,7 @@ bnx2_suspend(struct pci_dev *pdev, u32 state)
                reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
        bnx2_reset_chip(bp, reset_code);
        bnx2_free_skbs(bp);
-       bnx2_set_power_state(bp, state);
+       bnx2_set_power_state(bp, pci_choose_state(pdev, state));
        return 0;
 }
 
@@ -5497,7 +5526,7 @@ bnx2_resume(struct pci_dev *pdev)
        if (!netif_running(dev))
                return 0;
 
-       bnx2_set_power_state(bp, 0);
+       bnx2_set_power_state(bp, PCI_D0);
        netif_device_attach(dev);
        bnx2_init_nic(bp);
        bnx2_netif_start(bp);
@@ -5505,12 +5534,12 @@ bnx2_resume(struct pci_dev *pdev)
 }
 
 static struct pci_driver bnx2_pci_driver = {
-       name:           DRV_MODULE_NAME,
-       id_table:       bnx2_pci_tbl,
-       probe:          bnx2_init_one,
-       remove:         __devexit_p(bnx2_remove_one),
-       suspend:        bnx2_suspend,
-       resume:         bnx2_resume,
+       .name           = DRV_MODULE_NAME,
+       .id_table       = bnx2_pci_tbl,
+       .probe          = bnx2_init_one,
+       .remove         = __devexit_p(bnx2_remove_one),
+       .suspend        = bnx2_suspend,
+       .resume         = bnx2_resume,
 };
 
 static int __init bnx2_init(void)
index 8214a2853d0df92a71545348bb70a506fce23ee4..9ad3f5740cd8ee450a3aa96b2996b4d8c8882fca 100644 (file)
@@ -3841,12 +3841,12 @@ struct bnx2 {
        struct status_block     *status_blk;
        u32                     last_status_idx;
 
-       atomic_t                tx_avail_bd;
        struct tx_bd            *tx_desc_ring;
        struct sw_bd            *tx_buf_ring;
        u32                     tx_prod_bseq;
        u16                     tx_prod;
        u16                     tx_cons;
+       int                     tx_ring_size;
 
 #ifdef BCM_VLAN 
        struct                  vlan_group *vlgrp;
@@ -3872,8 +3872,10 @@ struct bnx2 {
        char                    *name;
 
        int                     timer_interval;
+       int                     current_interval;
        struct                  timer_list timer;
        struct work_struct      reset_task;
+       int                     in_reset_task;
 
        /* Used to synchronize phy accesses. */
        spinlock_t              phy_lock;
@@ -3927,7 +3929,6 @@ struct bnx2 {
        u16                     fw_wr_seq;
        u16                     fw_drv_pulse_wr_seq;
 
-       int                     tx_ring_size;
        dma_addr_t              tx_desc_mapping;
 
 
@@ -3985,7 +3986,7 @@ struct bnx2 {
 #define PHY_LOOPBACK           2
 
        u8                      serdes_an_pending;
-#define SERDES_AN_TIMEOUT      (2 * HZ)
+#define SERDES_AN_TIMEOUT      (HZ / 3)
 
        u8                      mac_addr[8];
 
@@ -4171,6 +4172,9 @@ struct fw_info {
 
 #define BNX2_PORT_HW_CFG_MAC_LOWER             0x00000054
 #define BNX2_PORT_HW_CFG_CONFIG                        0x00000058
+#define BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK     0x001f0000
+#define BNX2_PORT_HW_CFG_CFG_DFLT_LINK_AN       0x00000000
+#define BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G       0x00030000
 
 #define BNX2_PORT_HW_CFG_IMD_MAC_A_UPPER       0x00000068
 #define BNX2_PORT_HW_CFG_IMD_MAC_A_LOWER       0x0000006c
index a2e8dda5afac6b30aa0a608f521789415fb637ea..d2f34d5a80835c786122a4ba359164d524b5bde6 100644 (file)
@@ -2419,22 +2419,19 @@ out:
        return 0;
 }
 
-int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype)
+int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev)
 {
        struct bonding *bond = dev->priv;
        struct slave *slave = NULL;
        int ret = NET_RX_DROP;
 
-       if (!(dev->flags & IFF_MASTER)) {
+       if (!(dev->flags & IFF_MASTER))
                goto out;
-       }
 
        read_lock(&bond->lock);
-       slave = bond_get_slave_by_dev((struct bonding *)dev->priv,
-                                     skb->real_dev);
-       if (slave == NULL) {
+       slave = bond_get_slave_by_dev((struct bonding *)dev->priv, orig_dev);
+       if (!slave)
                goto out_unlock;
-       }
 
        bond_3ad_rx_indication((struct lacpdu *) skb->data, slave, skb->len);
 
index f46823894187fbb117bd79e661376154deb8006d..673a30af5660f58a096f1253c34fb10bd40bcbec 100644 (file)
@@ -295,6 +295,6 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave);
 void bond_3ad_handle_link_change(struct slave *slave, char link);
 int  bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info);
 int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev);
-int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype);
+int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev);
 #endif //__BOND_3AD_H__
 
index 5ce606d9dc03f9b145c3024abecfca20ec65fd9d..f8fce39611972f18fefdd8524368955425d84466 100644 (file)
@@ -354,15 +354,14 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
        _unlock_rx_hashtbl(bond);
 }
 
-static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct packet_type *ptype)
+static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct packet_type *ptype, struct net_device *orig_dev)
 {
        struct bonding *bond = bond_dev->priv;
        struct arp_pkt *arp = (struct arp_pkt *)skb->data;
        int res = NET_RX_DROP;
 
-       if (!(bond_dev->flags & IFF_MASTER)) {
+       if (!(bond_dev->flags & IFF_MASTER))
                goto out;
-       }
 
        if (!arp) {
                dprintk("Packet has no ARP data\n");
@@ -1106,18 +1105,13 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
                        }
                }
 
-               if (found) {
-                       /* a slave was found that is using the mac address
-                        * of the new slave
-                        */
-                       printk(KERN_ERR DRV_NAME
-                              ": Error: the hw address of slave %s is not "
-                              "unique - cannot enslave it!",
-                              slave->dev->name);
-                       return -EINVAL;
-               }
+               if (!found)
+                       return 0;
 
-               return 0;
+               /* Try setting slave mac to bond address and fall-through
+                  to code handling that situation below... */
+               alb_set_slave_mac_addr(slave, bond->dev->dev_addr,
+                                      bond->alb_info.rlb_enabled);
        }
 
        /* The slave's address is equal to the address of the bond.
index 2c930da90a854d957f881cff3b3032ce0b1ff921..94c9f68dd16bacf4686eac5cb7da66062bf8df33 100644 (file)
@@ -1604,6 +1604,44 @@ static int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_
        return 0;
 }
 
+#define BOND_INTERSECT_FEATURES \
+       (NETIF_F_SG|NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM)
+
+/* 
+ * Compute the features available to the bonding device by 
+ * intersection of all of the slave devices' BOND_INTERSECT_FEATURES.
+ * Call this after attaching or detaching a slave to update the 
+ * bond's features.
+ */
+static int bond_compute_features(struct bonding *bond)
+{
+       int i;
+       struct slave *slave;
+       struct net_device *bond_dev = bond->dev;
+       int features = bond->bond_features;
+
+       bond_for_each_slave(bond, slave, i) {
+               struct net_device * slave_dev = slave->dev;
+               if (i == 0) {
+                       features |= BOND_INTERSECT_FEATURES;
+               }
+               features &=
+                       ~(~slave_dev->features & BOND_INTERSECT_FEATURES);
+       }
+
+       /* turn off NETIF_F_SG if we need a csum and h/w can't do it */
+       if ((features & NETIF_F_SG) && 
+               !(features & (NETIF_F_IP_CSUM |
+                             NETIF_F_NO_CSUM |
+                             NETIF_F_HW_CSUM))) {
+               features &= ~NETIF_F_SG;
+       }
+
+       bond_dev->features = features;
+
+       return 0;
+}
+
 /* enslave device <slave> to bond device <master> */
 static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 {
@@ -1811,6 +1849,8 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
        new_slave->delay = 0;
        new_slave->link_failure_count = 0;
 
+       bond_compute_features(bond);
+
        if (bond->params.miimon && !bond->params.use_carrier) {
                link_reporting = bond_check_dev_link(bond, slave_dev, 1);
 
@@ -2015,7 +2055,7 @@ err_free:
 
 err_undo_flags:
        bond_dev->features = old_features;
-
        return res;
 }
 
@@ -2100,6 +2140,8 @@ static int bond_release(struct net_device *bond_dev, struct net_device *slave_de
        /* release the slave from its bond */
        bond_detach_slave(bond, slave);
 
+       bond_compute_features(bond);
+
        if (bond->primary_slave == slave) {
                bond->primary_slave = NULL;
        }
@@ -2243,6 +2285,8 @@ static int bond_release_all(struct net_device *bond_dev)
                        bond_alb_deinit_slave(bond, slave);
                }
 
+               bond_compute_features(bond);
+
                /* now that the slave is detached, unlock and perform
                 * all the undo steps that should not be called from
                 * within a lock.
@@ -3588,6 +3632,7 @@ static int bond_master_netdev_event(unsigned long event, struct net_device *bond
 static int bond_slave_netdev_event(unsigned long event, struct net_device *slave_dev)
 {
        struct net_device *bond_dev = slave_dev->master;
+       struct bonding *bond = bond_dev->priv;
 
        switch (event) {
        case NETDEV_UNREGISTER:
@@ -3626,6 +3671,9 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave
                 * TODO: handle changing the primary's name
                 */
                break;
+       case NETDEV_FEAT_CHANGE:
+               bond_compute_features(bond);
+               break;
        default:
                break;
        }
@@ -4526,6 +4574,11 @@ static inline void bond_set_mode_ops(struct bonding *bond, int mode)
        }
 }
 
+static struct ethtool_ops bond_ethtool_ops = {
+       .get_tx_csum            = ethtool_op_get_tx_csum,
+       .get_sg                 = ethtool_op_get_sg,
+};
+
 /*
  * Does not allocate but creates a /proc entry.
  * Allowed to fail.
@@ -4555,6 +4608,7 @@ static int __init bond_init(struct net_device *bond_dev, struct bond_params *par
        bond_dev->stop = bond_close;
        bond_dev->get_stats = bond_get_stats;
        bond_dev->do_ioctl = bond_do_ioctl;
+       bond_dev->ethtool_ops = &bond_ethtool_ops;
        bond_dev->set_multicast_list = bond_set_multicast_list;
        bond_dev->change_mtu = bond_change_mtu;
        bond_dev->set_mac_address = bond_set_mac_address;
@@ -4591,6 +4645,8 @@ static int __init bond_init(struct net_device *bond_dev, struct bond_params *par
                               NETIF_F_HW_VLAN_RX |
                               NETIF_F_HW_VLAN_FILTER);
 
+       bond->bond_features = bond_dev->features;
+
 #ifdef CONFIG_PROC_FS
        bond_create_proc_entry(bond);
 #endif
index d27f377b3eeb52bf2f8a47c3f3b6a5a61463faad..3881969808627cebcb7ed6a25f6b9b3557b6a1ec 100644 (file)
@@ -211,6 +211,9 @@ struct bonding {
        struct   bond_params params;
        struct   list_head vlan_list;
        struct   vlan_group *vlgrp;
+       /* the features the bonding device supports, independently 
+        * of any slaves */
+       int      bond_features; 
 };
 
 /**
diff --git a/drivers/net/chelsio/Makefile b/drivers/net/chelsio/Makefile
new file mode 100644 (file)
index 0000000..91e9278
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Chelsio 10Gb NIC driver for Linux.
+#
+
+obj-$(CONFIG_CHELSIO_T1) += cxgb.o
+
+EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/chelsio $(DEBUG_FLAGS)
+
+
+cxgb-objs := cxgb2.o espi.o pm3393.o sge.o subr.o mv88x201x.o
+
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
new file mode 100644 (file)
index 0000000..bf3e7b6
--- /dev/null
@@ -0,0 +1,314 @@
+/*****************************************************************************
+ *                                                                           *
+ * File: common.h                                                            *
+ * $Revision: 1.21 $                                                         *
+ * $Date: 2005/06/22 00:43:25 $                                              *
+ * Description:                                                              *
+ *  part of the Chelsio 10Gb Ethernet Driver.                                *
+ *                                                                           *
+ * This program is free software; you can redistribute it and/or modify      *
+ * it under the terms of the GNU General Public License, version 2, as       *
+ * published by the Free Software Foundation.                                *
+ *                                                                           *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED    *
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF      *
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.                     *
+ *                                                                           *
+ * http://www.chelsio.com                                                    *
+ *                                                                           *
+ * Copyright (c) 2003 - 2005 Chelsio Communications, Inc.                    *
+ * All rights reserved.                                                      *
+ *                                                                           *
+ * Maintainers: maintainers@chelsio.com                                      *
+ *                                                                           *
+ * Authors: Dimitrios Michailidis   <dm@chelsio.com>                         *
+ *          Tina Yang               <tainay@chelsio.com>                     *
+ *          Felix Marti             <felix@chelsio.com>                      *
+ *          Scott Bardone           <sbardone@chelsio.com>                   *
+ *          Kurt Ottaway            <kottaway@chelsio.com>                   *
+ *          Frank DiMambro          <frank@chelsio.com>                      *
+ *                                                                           *
+ * History:                                                                  *
+ *                                                                           *
+ ****************************************************************************/
+
+#ifndef _CXGB_COMMON_H_
+#define _CXGB_COMMON_H_
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <linux/pci_ids.h>
+
+#define DRV_DESCRIPTION "Chelsio 10Gb Ethernet Driver"
+#define DRV_NAME "cxgb"
+#define DRV_VERSION "2.1.1"
+#define PFX      DRV_NAME ": "
+
+#define CH_ERR(fmt, ...)   printk(KERN_ERR PFX fmt, ## __VA_ARGS__)
+#define CH_WARN(fmt, ...)  printk(KERN_WARNING PFX fmt, ## __VA_ARGS__)
+#define CH_ALERT(fmt, ...) printk(KERN_ALERT PFX fmt, ## __VA_ARGS__)
+
+#define CH_DEVICE(devid, ssid, idx) \
+       { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, ssid, 0, 0, idx }
+
+#define SUPPORTED_PAUSE       (1 << 13)
+#define SUPPORTED_LOOPBACK    (1 << 15)
+
+#define ADVERTISED_PAUSE      (1 << 13)
+#define ADVERTISED_ASYM_PAUSE (1 << 14)
+
+typedef struct adapter adapter_t;
+
+void t1_elmer0_ext_intr(adapter_t *adapter);
+void t1_link_changed(adapter_t *adapter, int port_id, int link_status,
+                       int speed, int duplex, int fc);
+
+struct t1_rx_mode {
+       struct net_device *dev;
+       u32 idx;
+       struct dev_mc_list *list;
+};
+
+#define t1_rx_mode_promisc(rm) (rm->dev->flags & IFF_PROMISC)
+#define t1_rx_mode_allmulti(rm)        (rm->dev->flags & IFF_ALLMULTI)
+#define t1_rx_mode_mc_cnt(rm)  (rm->dev->mc_count)
+
+static inline u8 *t1_get_next_mcaddr(struct t1_rx_mode *rm)
+{
+       u8 *addr = NULL;
+
+       if (rm->idx++ < rm->dev->mc_count) {
+               addr = rm->list->dmi_addr;
+               rm->list = rm->list->next;
+       }
+       return addr;
+}
+
+#define        MAX_NPORTS 4
+
+#define SPEED_INVALID 0xffff
+#define DUPLEX_INVALID 0xff
+
+enum {
+       CHBT_BOARD_N110,
+       CHBT_BOARD_N210
+};
+
+enum {
+       CHBT_TERM_T1,
+       CHBT_TERM_T2
+};
+
+enum {
+       CHBT_MAC_PM3393,
+};
+
+enum {
+       CHBT_PHY_88X2010,
+};
+
+enum {
+       PAUSE_RX      = 1 << 0,
+       PAUSE_TX      = 1 << 1,
+       PAUSE_AUTONEG = 1 << 2
+};
+
+/* Revisions of T1 chip */
+enum {
+       TERM_T1A   = 0,
+       TERM_T1B   = 1,
+       TERM_T2    = 3
+};
+
+struct sge_params {
+       unsigned int cmdQ_size[2];
+       unsigned int freelQ_size[2];
+       unsigned int large_buf_capacity;
+       unsigned int rx_coalesce_usecs;
+       unsigned int last_rx_coalesce_raw;
+       unsigned int default_rx_coalesce_usecs;
+       unsigned int sample_interval_usecs;
+       unsigned int coalesce_enable;
+       unsigned int polling;
+};
+
+struct chelsio_pci_params {
+       unsigned short speed;
+       unsigned char  width;
+       unsigned char  is_pcix;
+};
+
+struct adapter_params {
+       struct sge_params sge;
+       struct chelsio_pci_params pci;
+
+       const struct board_info *brd_info;
+
+       unsigned int   nports;          /* # of ethernet ports */
+       unsigned int   stats_update_period;
+       unsigned short chip_revision;
+       unsigned char  chip_version;
+};
+
+struct link_config {
+       unsigned int   supported;        /* link capabilities */
+       unsigned int   advertising;      /* advertised capabilities */
+       unsigned short requested_speed;  /* speed user has requested */
+       unsigned short speed;            /* actual link speed */
+       unsigned char  requested_duplex; /* duplex user has requested */
+       unsigned char  duplex;           /* actual link duplex */
+       unsigned char  requested_fc;     /* flow control user has requested */
+       unsigned char  fc;               /* actual link flow control */
+       unsigned char  autoneg;          /* autonegotiating? */
+};
+
+struct cmac;
+struct cphy;
+
+struct port_info {
+       struct net_device *dev;
+       struct cmac *mac;
+       struct cphy *phy;
+       struct link_config link_config;
+       struct net_device_stats netstats;
+};
+
+struct sge;
+struct peespi;
+
+struct adapter {
+       u8 __iomem *regs;
+       struct pci_dev *pdev;
+       unsigned long registered_device_map;
+       unsigned long open_device_map;
+       unsigned long flags;
+
+       const char *name;
+       int msg_enable;
+       u32 mmio_len;
+
+       struct work_struct ext_intr_handler_task;
+       struct adapter_params params;
+
+       struct vlan_group *vlan_grp;
+
+       /* Terminator modules. */
+       struct sge    *sge;
+       struct peespi *espi;
+
+       struct port_info port[MAX_NPORTS];
+       struct work_struct stats_update_task;
+       struct timer_list stats_update_timer;
+
+       struct semaphore mib_mutex;
+       spinlock_t tpi_lock;
+       spinlock_t work_lock;
+       /* guards async operations */
+       spinlock_t async_lock ____cacheline_aligned;
+       u32 slow_intr_mask;
+};
+
+enum {                                           /* adapter flags */
+       FULL_INIT_DONE        = 1 << 0,
+       TSO_CAPABLE           = 1 << 2,
+       TCP_CSUM_CAPABLE      = 1 << 3,
+       UDP_CSUM_CAPABLE      = 1 << 4,
+       VLAN_ACCEL_CAPABLE    = 1 << 5,
+       RX_CSUM_ENABLED       = 1 << 6,
+};
+
+struct mdio_ops;
+struct gmac;
+struct gphy;
+
+struct board_info {
+       unsigned char           board;
+       unsigned char           port_number;
+       unsigned long           caps;
+       unsigned char           chip_term;
+       unsigned char           chip_mac;
+       unsigned char           chip_phy;
+       unsigned int            clock_core;
+       unsigned int            clock_mc3;
+       unsigned int            clock_mc4;
+       unsigned int            espi_nports;
+       unsigned int            clock_cspi;
+       unsigned int            clock_elmer0;
+       unsigned char           mdio_mdien;
+       unsigned char           mdio_mdiinv;
+       unsigned char           mdio_mdc;
+       unsigned char           mdio_phybaseaddr;
+       struct gmac            *gmac;
+       struct gphy            *gphy;
+       struct mdio_ops        *mdio_ops;
+       const char             *desc;
+};
+
+extern struct pci_device_id t1_pci_tbl[];
+
+static inline int adapter_matches_type(const adapter_t *adapter,
+                                      int version, int revision)
+{
+       return adapter->params.chip_version == version &&
+              adapter->params.chip_revision == revision;
+}
+
+#define t1_is_T1B(adap) adapter_matches_type(adap, CHBT_TERM_T1, TERM_T1B)
+#define is_T2(adap)     adapter_matches_type(adap, CHBT_TERM_T2, TERM_T2)
+
+/* Returns true if an adapter supports VLAN acceleration and TSO */
+static inline int vlan_tso_capable(const adapter_t *adapter)
+{
+       return !t1_is_T1B(adapter);
+}
+
+#define for_each_port(adapter, iter) \
+       for (iter = 0; iter < (adapter)->params.nports; ++iter)
+
+#define board_info(adapter) ((adapter)->params.brd_info)
+#define is_10G(adapter) (board_info(adapter)->caps & SUPPORTED_10000baseT_Full)
+
+static inline unsigned int core_ticks_per_usec(const adapter_t *adap)
+{
+       return board_info(adap)->clock_core / 1000000;
+}
+
+extern int t1_tpi_write(adapter_t *adapter, u32 addr, u32 value);
+extern int t1_tpi_read(adapter_t *adapter, u32 addr, u32 *value);
+
+extern void t1_interrupts_enable(adapter_t *adapter);
+extern void t1_interrupts_disable(adapter_t *adapter);
+extern void t1_interrupts_clear(adapter_t *adapter);
+extern int elmer0_ext_intr_handler(adapter_t *adapter);
+extern int t1_slow_intr_handler(adapter_t *adapter);
+
+extern int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc);
+extern const struct board_info *t1_get_board_info(unsigned int board_id);
+extern const struct board_info *t1_get_board_info_from_ids(unsigned int devid,
+                                                   unsigned short ssid);
+extern int t1_seeprom_read(adapter_t *adapter, u32 addr, u32 *data);
+extern int t1_get_board_rev(adapter_t *adapter, const struct board_info *bi,
+                    struct adapter_params *p);
+extern int t1_init_hw_modules(adapter_t *adapter);
+extern int t1_init_sw_modules(adapter_t *adapter, const struct board_info *bi);
+extern void t1_free_sw_modules(adapter_t *adapter);
+extern void t1_fatal_err(adapter_t *adapter);
+
+extern void t1_tp_set_udp_checksum_offload(adapter_t *adapter, int enable);
+extern void t1_tp_set_tcp_checksum_offload(adapter_t *adapter, int enable);
+extern void t1_tp_set_ip_checksum_offload(adapter_t *adapter, int enable);
+
+#endif /* _CXGB_COMMON_H_ */
diff --git a/drivers/net/chelsio/cphy.h b/drivers/net/chelsio/cphy.h
new file mode 100644 (file)
index 0000000..3412342
--- /dev/null
@@ -0,0 +1,148 @@
+/*****************************************************************************
+ *                                                                           *
+ * File: cphy.h                                                              *
+ * $Revision: 1.7 $                                                          *
+ * $Date: 2005/06/21 18:29:47 $                                              *
+ * Description:                                                              *
+ *  part of the Chelsio 10Gb Ethernet Driver.                                *
+ *                                                                           *
+ * This program is free software; you can redistribute it and/or modify      *
+ * it under the terms of the GNU General Public License, version 2, as       *
+ * published by the Free Software Foundation.                                *
+ *                                                                           *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED    *
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF      *
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.                     *
+ *                                                                           *
+ * http://www.chelsio.com                                                    *
+ *                                                                           *
+ * Copyright (c) 2003 - 2005 Chelsio Communications, Inc.                    *
+ * All rights reserved.                                                      *
+ *                                                                           *
+ * Maintainers: maintainers@chelsio.com                                      *
+ *                                                                           *
+ * Authors: Dimitrios Michailidis   <dm@chelsio.com>                         *
+ *          Tina Yang               <tainay@chelsio.com>                     *
+ *          Felix Marti             <felix@chelsio.com>                      *
+ *          Scott Bardone           <sbardone@chelsio.com>                   *
+ *          Kurt Ottaway            <kottaway@chelsio.com>                   *
+ *          Frank DiMambro          <frank@chelsio.com>                      *
+ *                                                                           *
+ * History:                                                                  *
+ *                                                                           *
+ ****************************************************************************/
+
+#ifndef _CXGB_CPHY_H_
+#define _CXGB_CPHY_H_
+
+#include "common.h"
+
+struct mdio_ops {
+       void (*init)(adapter_t *adapter, const struct board_info *bi);
+       int  (*read)(adapter_t *adapter, int phy_addr, int mmd_addr,
+                    int reg_addr, unsigned int *val);
+       int  (*write)(adapter_t *adapter, int phy_addr, int mmd_addr,
+                     int reg_addr, unsigned int val);
+};
+
+/* PHY interrupt types */
+enum {
+       cphy_cause_link_change = 0x1,
+       cphy_cause_error = 0x2
+};
+
+struct cphy;
+
+/* PHY operations */
+struct cphy_ops {
+       void (*destroy)(struct cphy *);
+       int (*reset)(struct cphy *, int wait);
+
+       int (*interrupt_enable)(struct cphy *);
+       int (*interrupt_disable)(struct cphy *);
+       int (*interrupt_clear)(struct cphy *);
+       int (*interrupt_handler)(struct cphy *);
+
+       int (*autoneg_enable)(struct cphy *);
+       int (*autoneg_disable)(struct cphy *);
+       int (*autoneg_restart)(struct cphy *);
+
+       int (*advertise)(struct cphy *phy, unsigned int advertise_map);
+       int (*set_loopback)(struct cphy *, int on);
+       int (*set_speed_duplex)(struct cphy *phy, int speed, int duplex);
+       int (*get_link_status)(struct cphy *phy, int *link_ok, int *speed,
+                              int *duplex, int *fc);
+};
+
+/* A PHY instance */
+struct cphy {
+       int addr;                            /* PHY address */
+       adapter_t *adapter;                  /* associated adapter */
+       struct cphy_ops *ops;                /* PHY operations */
+       int (*mdio_read)(adapter_t *adapter, int phy_addr, int mmd_addr,
+                        int reg_addr, unsigned int *val);
+       int (*mdio_write)(adapter_t *adapter, int phy_addr, int mmd_addr,
+                         int reg_addr, unsigned int val);
+       struct cphy_instance *instance;
+};
+
+/* Convenience MDIO read/write wrappers */
+static inline int mdio_read(struct cphy *cphy, int mmd, int reg,
+                           unsigned int *valp)
+{
+       return cphy->mdio_read(cphy->adapter, cphy->addr, mmd, reg, valp);
+}
+
+static inline int mdio_write(struct cphy *cphy, int mmd, int reg,
+                            unsigned int val)
+{
+       return cphy->mdio_write(cphy->adapter, cphy->addr, mmd, reg, val);
+}
+
+static inline int simple_mdio_read(struct cphy *cphy, int reg,
+                                  unsigned int *valp)
+{
+       return mdio_read(cphy, 0, reg, valp);
+}
+
+static inline int simple_mdio_write(struct cphy *cphy, int reg,
+                                   unsigned int val)
+{
+       return mdio_write(cphy, 0, reg, val);
+}
+
+/* Convenience initializer */
+static inline void cphy_init(struct cphy *phy, adapter_t *adapter,
+                            int phy_addr, struct cphy_ops *phy_ops,
+                            struct mdio_ops *mdio_ops)
+{
+       phy->adapter = adapter;
+       phy->addr    = phy_addr;
+       phy->ops     = phy_ops;
+       if (mdio_ops) {
+               phy->mdio_read  = mdio_ops->read;
+               phy->mdio_write = mdio_ops->write;
+       }
+}
+
+/* Operations of the PHY-instance factory */
+struct gphy {
+       /* Construct a PHY instance with the given PHY address */
+       struct cphy *(*create)(adapter_t *adapter, int phy_addr,
+                              struct mdio_ops *mdio_ops);
+
+       /*
+        * Reset the PHY chip.  This resets the whole PHY chip, not individual
+        * ports.
+        */
+       int (*reset)(adapter_t *adapter);
+};
+
+extern struct gphy t1_mv88x201x_ops;
+extern struct gphy t1_dummy_phy_ops;
+
+#endif /* _CXGB_CPHY_H_ */
diff --git a/drivers/net/chelsio/cpl5_cmd.h b/drivers/net/chelsio/cpl5_cmd.h
new file mode 100644 (file)
index 0000000..27925e4
--- /dev/null
@@ -0,0 +1,145 @@
+/*****************************************************************************
+ *                                                                           *
+ * File: cpl5_cmd.h                                                          *
+ * $Revision: 1.6 $                                                          *
+ * $Date: 2005/06/21 18:29:47 $                                              *
+ * Description:                                                              *
+ *  part of the Chelsio 10Gb Ethernet Driver.                                *
+ *                                                                           *
+ * This program is free software; you can redistribute it and/or modify      *
+ * it under the terms of the GNU General Public License, version 2, as       *
+ * published by the Free Software Foundation.                                *
+ *                                                                           *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED    *
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF      *
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.                     *
+ *                                                                           *
+ * http://www.chelsio.com                                                    *
+ *                                                                           *
+ * Copyright (c) 2003 - 2005 Chelsio Communications, Inc.                    *
+ * All rights reserved.                                                      *
+ *                                                                           *
+ * Maintainers: maintainers@chelsio.com                                      *
+ *                                                                           *
+ * Authors: Dimitrios Michailidis   <dm@chelsio.com>                         *
+ *          Tina Yang               <tainay@chelsio.com>                     *
+ *          Felix Marti             <felix@chelsio.com>                      *
+ *          Scott Bardone           <sbardone@chelsio.com>                   *
+ *          Kurt Ottaway            <kottaway@chelsio.com>                   *
+ *          Frank DiMambro          <frank@chelsio.com>                      *
+ *                                                                           *
+ * History:                                                                  *
+ *                                                                           *
+ ****************************************************************************/
+
+#ifndef _CXGB_CPL5_CMD_H_
+#define _CXGB_CPL5_CMD_H_
+
+#include <asm/byteorder.h>
+
+#if !defined(__LITTLE_ENDIAN_BITFIELD) && !defined(__BIG_ENDIAN_BITFIELD)
+#error "Adjust your <asm/byteorder.h> defines"
+#endif
+
+enum CPL_opcode {
+       CPL_RX_PKT            = 0xAD,
+       CPL_TX_PKT            = 0xB2,
+       CPL_TX_PKT_LSO        = 0xB6,
+};
+
+enum {                /* TX_PKT_LSO ethernet types */
+       CPL_ETH_II,
+       CPL_ETH_II_VLAN,
+       CPL_ETH_802_3,
+       CPL_ETH_802_3_VLAN
+};
+
+struct cpl_rx_data {
+       u32 rsvd0;
+       u32 len;
+       u32 seq;
+       u16 urg;
+       u8  rsvd1;
+       u8  status;
+};
+
+/*
+ * We want this header's alignment to be no more stringent than 2-byte aligned.
+ * All fields are u8 or u16 except for the length.  However that field is not
+ * used so we break it into 2 16-bit parts to easily meet our alignment needs.
+ */
+struct cpl_tx_pkt {
+       u8 opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       u8 iff:4;
+       u8 ip_csum_dis:1;
+       u8 l4_csum_dis:1;
+       u8 vlan_valid:1;
+       u8 rsvd:1;
+#else
+       u8 rsvd:1;
+       u8 vlan_valid:1;
+       u8 l4_csum_dis:1;
+       u8 ip_csum_dis:1;
+       u8 iff:4;
+#endif
+       u16 vlan;
+       u16 len_hi;
+       u16 len_lo;
+};
+
+struct cpl_tx_pkt_lso {
+       u8 opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       u8 iff:4;
+       u8 ip_csum_dis:1;
+       u8 l4_csum_dis:1;
+       u8 vlan_valid:1;
+       u8 rsvd:1;
+#else
+       u8 rsvd:1;
+       u8 vlan_valid:1;
+       u8 l4_csum_dis:1;
+       u8 ip_csum_dis:1;
+       u8 iff:4;
+#endif
+       u16 vlan;
+       u32 len;
+
+       u32 rsvd2;
+       u8 rsvd3;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       u8 tcp_hdr_words:4;
+       u8 ip_hdr_words:4;
+#else
+       u8 ip_hdr_words:4;
+       u8 tcp_hdr_words:4;
+#endif
+       u16 eth_type_mss;
+};
+
+struct cpl_rx_pkt {
+       u8 opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       u8 iff:4;
+       u8 csum_valid:1;
+       u8 bad_pkt:1;
+       u8 vlan_valid:1;
+       u8 rsvd:1;
+#else
+       u8 rsvd:1;
+       u8 vlan_valid:1;
+       u8 bad_pkt:1;
+       u8 csum_valid:1;
+       u8 iff:4;
+#endif
+       u16 csum;
+       u16 vlan;
+       u16 len;
+};
+
+#endif /* _CXGB_CPL5_CMD_H_ */
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
new file mode 100644 (file)
index 0000000..349ebe7
--- /dev/null
@@ -0,0 +1,1256 @@
+/*****************************************************************************
+ *                                                                           *
+ * File: cxgb2.c                                                             *
+ * $Revision: 1.25 $                                                         *
+ * $Date: 2005/06/22 00:43:25 $                                              *
+ * Description:                                                              *
+ *  Chelsio 10Gb Ethernet Driver.                                            *
+ *                                                                           *
+ * This program is free software; you can redistribute it and/or modify      *
+ * it under the terms of the GNU General Public License, version 2, as       *
+ * published by the Free Software Foundation.                                *
+ *                                                                           *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED    *
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF      *
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.                     *
+ *                                                                           *
+ * http://www.chelsio.com                                                    *
+ *                                                                           *
+ * Copyright (c) 2003 - 2005 Chelsio Communications, Inc.                    *
+ * All rights reserved.                                                      *
+ *                                                                           *
+ * Maintainers: maintainers@chelsio.com                                      *
+ *                                                                           *
+ * Authors: Dimitrios Michailidis   <dm@chelsio.com>                         *
+ *          Tina Yang               <tainay@chelsio.com>                     *
+ *          Felix Marti             <felix@chelsio.com>                      *
+ *          Scott Bardone           <sbardone@chelsio.com>                   *
+ *          Kurt Ottaway            <kottaway@chelsio.com>                   *
+ *          Frank DiMambro          <frank@chelsio.com>                      *
+ *                                                                           *
+ * History:                                                                  *
+ *                                                                           *
+ ****************************************************************************/
+
+#include "common.h"
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/mii.h>
+#include <linux/sockios.h>
+#include <linux/proc_fs.h>
+#include <linux/dma-mapping.h>
+#include <asm/uaccess.h>
+
+#include "cpl5_cmd.h"
+#include "regs.h"
+#include "gmac.h"
+#include "cphy.h"
+#include "sge.h"
+#include "espi.h"
+
+#ifdef work_struct
+#include <linux/tqueue.h>
+#define INIT_WORK INIT_TQUEUE
+#define schedule_work schedule_task
+#define flush_scheduled_work flush_scheduled_tasks
+
+static inline void schedule_mac_stats_update(struct adapter *ap, int secs)
+{
+       mod_timer(&ap->stats_update_timer, jiffies + secs * HZ);
+}
+
+static inline void cancel_mac_stats_update(struct adapter *ap)
+{
+       del_timer_sync(&ap->stats_update_timer);
+       flush_scheduled_tasks();
+}
+
+/*
+ * Stats update timer for 2.4.  It schedules a task to do the actual update as
+ * we need to access MAC statistics in process context.
+ */
+static void mac_stats_timer(unsigned long data)
+{
+       struct adapter *ap = (struct adapter *)data;
+
+       schedule_task(&ap->stats_update_task);
+}
+#else
+#include <linux/workqueue.h>
+
+static inline void schedule_mac_stats_update(struct adapter *ap, int secs)
+{
+       schedule_delayed_work(&ap->stats_update_task, secs * HZ);
+}
+
+static inline void cancel_mac_stats_update(struct adapter *ap)
+{
+       cancel_delayed_work(&ap->stats_update_task);
+}
+#endif
+
+#define MAX_CMDQ_ENTRIES 16384
+#define MAX_CMDQ1_ENTRIES 1024
+#define MAX_RX_BUFFERS 16384
+#define MAX_RX_JUMBO_BUFFERS 16384
+#define MAX_TX_BUFFERS_HIGH    16384U
+#define MAX_TX_BUFFERS_LOW     1536U
+#define MIN_FL_ENTRIES 32
+
+#define PORT_MASK ((1 << MAX_NPORTS) - 1)
+
+#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
+                        NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
+                        NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
+
+/*
+ * The EEPROM is actually bigger but only the first few bytes are used so we
+ * only report those.
+ */
+#define EEPROM_SIZE 32
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_AUTHOR("Chelsio Communications");
+MODULE_LICENSE("GPL");
+
+static int dflt_msg_enable = DFLT_MSG_ENABLE;
+
+MODULE_PARM(dflt_msg_enable, "i");
+MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T1 message enable bitmap");
+
+
+static const char pci_speed[][4] = {
+       "33", "66", "100", "133"
+};
+
+/*
+ * Setup MAC to receive the types of packets we want.
+ */
+static void t1_set_rxmode(struct net_device *dev)
+{
+       struct adapter *adapter = dev->priv;
+       struct cmac *mac = adapter->port[dev->if_port].mac;
+       struct t1_rx_mode rm;
+
+       rm.dev = dev;
+       rm.idx = 0;
+       rm.list = dev->mc_list;
+       mac->ops->set_rx_mode(mac, &rm);
+}
+
+static void link_report(struct port_info *p)
+{
+       if (!netif_carrier_ok(p->dev))
+               printk(KERN_INFO "%s: link down\n", p->dev->name);
+       else {
+               const char *s = "10Mbps";
+
+               switch (p->link_config.speed) {
+                       case SPEED_10000: s = "10Gbps"; break;
+                       case SPEED_1000:  s = "1000Mbps"; break;
+                       case SPEED_100:   s = "100Mbps"; break;
+               }
+
+        printk(KERN_INFO "%s: link up, %s, %s-duplex\n",
+                      p->dev->name, s,
+                      p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
+       }
+}
+
+void t1_link_changed(struct adapter *adapter, int port_id, int link_stat,
+                       int speed, int duplex, int pause)
+{
+       struct port_info *p = &adapter->port[port_id];
+
+       if (link_stat != netif_carrier_ok(p->dev)) {
+               if (link_stat)
+                       netif_carrier_on(p->dev);
+               else
+                       netif_carrier_off(p->dev);
+               link_report(p);
+
+       }
+}
+
+static void link_start(struct port_info *p)
+{
+       struct cmac *mac = p->mac;
+
+       mac->ops->reset(mac);
+       if (mac->ops->macaddress_set)
+               mac->ops->macaddress_set(mac, p->dev->dev_addr);
+       t1_set_rxmode(p->dev);
+       t1_link_start(p->phy, mac, &p->link_config);
+       mac->ops->enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
+}
+
+static void enable_hw_csum(struct adapter *adapter)
+{
+       if (adapter->flags & TSO_CAPABLE)
+               t1_tp_set_ip_checksum_offload(adapter, 1); /* for TSO only */
+       t1_tp_set_tcp_checksum_offload(adapter, 1);
+}
+
+/*
+ * Things to do upon first use of a card.
+ * This must run with the rtnl lock held.
+ */
+static int cxgb_up(struct adapter *adapter)
+{
+       int err = 0;
+
+       if (!(adapter->flags & FULL_INIT_DONE)) {
+               err = t1_init_hw_modules(adapter);
+               if (err)
+                       goto out_err;
+
+               enable_hw_csum(adapter);
+               adapter->flags |= FULL_INIT_DONE;
+       }
+
+       t1_interrupts_clear(adapter);
+       if ((err = request_irq(adapter->pdev->irq,
+                              t1_select_intr_handler(adapter), SA_SHIRQ,
+                              adapter->name, adapter))) {
+               goto out_err;
+       }
+       t1_sge_start(adapter->sge);
+       t1_interrupts_enable(adapter);
+ out_err:
+       return err;
+}
+
+/*
+ * Release resources when all the ports have been stopped.
+ */
+static void cxgb_down(struct adapter *adapter)
+{
+       t1_sge_stop(adapter->sge);
+       t1_interrupts_disable(adapter);
+       free_irq(adapter->pdev->irq, adapter);
+}
+
+static int cxgb_open(struct net_device *dev)
+{
+       int err;
+       struct adapter *adapter = dev->priv;
+       int other_ports = adapter->open_device_map & PORT_MASK;
+
+       if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
+               return err;
+
+       __set_bit(dev->if_port, &adapter->open_device_map);
+       link_start(&adapter->port[dev->if_port]);
+       netif_start_queue(dev);
+       if (!other_ports && adapter->params.stats_update_period)
+               schedule_mac_stats_update(adapter,
+                                         adapter->params.stats_update_period);
+       return 0;
+}
+
+static int cxgb_close(struct net_device *dev)
+{
+       struct adapter *adapter = dev->priv;
+       struct port_info *p = &adapter->port[dev->if_port];
+       struct cmac *mac = p->mac;
+
+       netif_stop_queue(dev);
+       mac->ops->disable(mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
+       netif_carrier_off(dev);
+
+       clear_bit(dev->if_port, &adapter->open_device_map);
+       if (adapter->params.stats_update_period &&
+           !(adapter->open_device_map & PORT_MASK)) {
+               /* Stop statistics accumulation. */
+               smp_mb__after_clear_bit();
+               spin_lock(&adapter->work_lock);   /* sync with update task */
+               spin_unlock(&adapter->work_lock);
+               cancel_mac_stats_update(adapter);
+       }
+
+       if (!adapter->open_device_map)
+               cxgb_down(adapter);
+       return 0;
+}
+
+static struct net_device_stats *t1_get_stats(struct net_device *dev)
+{
+       struct adapter *adapter = dev->priv;
+       struct port_info *p = &adapter->port[dev->if_port];
+       struct net_device_stats *ns = &p->netstats;
+       const struct cmac_statistics *pstats;
+
+       /* Do a full update of the MAC stats */
+       pstats = p->mac->ops->statistics_update(p->mac,
+                                                     MAC_STATS_UPDATE_FULL);
+
+       ns->tx_packets = pstats->TxUnicastFramesOK +
+               pstats->TxMulticastFramesOK + pstats->TxBroadcastFramesOK;
+
+       ns->rx_packets = pstats->RxUnicastFramesOK +
+               pstats->RxMulticastFramesOK + pstats->RxBroadcastFramesOK;
+
+       ns->tx_bytes = pstats->TxOctetsOK;
+       ns->rx_bytes = pstats->RxOctetsOK;
+
+       ns->tx_errors = pstats->TxLateCollisions + pstats->TxLengthErrors +
+               pstats->TxUnderrun + pstats->TxFramesAbortedDueToXSCollisions;
+       ns->rx_errors = pstats->RxDataErrors + pstats->RxJabberErrors +
+               pstats->RxFCSErrors + pstats->RxAlignErrors +
+               pstats->RxSequenceErrors + pstats->RxFrameTooLongErrors +
+               pstats->RxSymbolErrors + pstats->RxRuntErrors;
+
+       ns->multicast  = pstats->RxMulticastFramesOK;
+       ns->collisions = pstats->TxTotalCollisions;
+
+       /* detailed rx_errors */
+       ns->rx_length_errors = pstats->RxFrameTooLongErrors +
+               pstats->RxJabberErrors;
+       ns->rx_over_errors   = 0;
+       ns->rx_crc_errors    = pstats->RxFCSErrors;
+       ns->rx_frame_errors  = pstats->RxAlignErrors;
+       ns->rx_fifo_errors   = 0;
+       ns->rx_missed_errors = 0;
+
+       /* detailed tx_errors */
+       ns->tx_aborted_errors   = pstats->TxFramesAbortedDueToXSCollisions;
+       ns->tx_carrier_errors   = 0;
+       ns->tx_fifo_errors      = pstats->TxUnderrun;
+       ns->tx_heartbeat_errors = 0;
+       ns->tx_window_errors    = pstats->TxLateCollisions;
+       return ns;
+}
+
+static u32 get_msglevel(struct net_device *dev)
+{
+       struct adapter *adapter = dev->priv;
+
+       return adapter->msg_enable;
+}
+
+static void set_msglevel(struct net_device *dev, u32 val)
+{
+       struct adapter *adapter = dev->priv;
+
+       adapter->msg_enable = val;
+}
+
+static char stats_strings[][ETH_GSTRING_LEN] = {
+        "TxOctetsOK",
+        "TxOctetsBad",
+        "TxUnicastFramesOK",
+        "TxMulticastFramesOK",
+        "TxBroadcastFramesOK",
+        "TxPauseFrames",
+        "TxFramesWithDeferredXmissions",
+        "TxLateCollisions",
+        "TxTotalCollisions",
+        "TxFramesAbortedDueToXSCollisions",
+        "TxUnderrun",
+        "TxLengthErrors",
+        "TxInternalMACXmitError",
+        "TxFramesWithExcessiveDeferral",
+        "TxFCSErrors",
+
+        "RxOctetsOK",
+        "RxOctetsBad",
+        "RxUnicastFramesOK",
+        "RxMulticastFramesOK",
+        "RxBroadcastFramesOK",
+        "RxPauseFrames",
+        "RxFCSErrors",
+        "RxAlignErrors",
+        "RxSymbolErrors",
+        "RxDataErrors",
+        "RxSequenceErrors",
+        "RxRuntErrors",
+        "RxJabberErrors",
+        "RxInternalMACRcvError",
+        "RxInRangeLengthErrors",
+        "RxOutOfRangeLengthField",
+        "RxFrameTooLongErrors",
+
+       "TSO",
+       "VLANextractions",
+       "VLANinsertions",
+       "RxCsumGood",
+       "TxCsumOffload",
+       "RxDrops"
+
+       "respQ_empty",
+       "respQ_overflow",
+       "freelistQ_empty",
+       "pkt_too_big",
+       "pkt_mismatch",
+       "cmdQ_full0",
+       "cmdQ_full1",
+       "tx_ipfrags",
+       "tx_reg_pkts",
+       "tx_lso_pkts",
+       "tx_do_cksum",
+       
+       "espi_DIP2ParityErr",
+       "espi_DIP4Err",
+       "espi_RxDrops",
+       "espi_TxDrops",
+       "espi_RxOvfl",
+       "espi_ParityErr"
+};
+#define T2_REGMAP_SIZE (3 * 1024)
+
+static int get_regs_len(struct net_device *dev)
+{
+       return T2_REGMAP_SIZE;
+}
+
+static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+       struct adapter *adapter = dev->priv;
+
+       strcpy(info->driver, DRV_NAME);
+       strcpy(info->version, DRV_VERSION);
+       strcpy(info->fw_version, "N/A");
+       strcpy(info->bus_info, pci_name(adapter->pdev));
+}
+
+static int get_stats_count(struct net_device *dev)
+{
+       return ARRAY_SIZE(stats_strings);
+}
+
+static void get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+       if (stringset == ETH_SS_STATS)
+               memcpy(data, stats_strings, sizeof(stats_strings));
+}
+
+static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
+                     u64 *data)
+{
+       struct adapter *adapter = dev->priv;
+       struct cmac *mac = adapter->port[dev->if_port].mac;
+       const struct cmac_statistics *s;
+       const struct sge_port_stats *ss;
+       const struct sge_intr_counts *t;
+
+       s = mac->ops->statistics_update(mac, MAC_STATS_UPDATE_FULL);
+       ss = t1_sge_get_port_stats(adapter->sge, dev->if_port);
+       t = t1_sge_get_intr_counts(adapter->sge);
+
+        *data++ = s->TxOctetsOK;
+        *data++ = s->TxOctetsBad;
+        *data++ = s->TxUnicastFramesOK;
+        *data++ = s->TxMulticastFramesOK;
+        *data++ = s->TxBroadcastFramesOK;
+        *data++ = s->TxPauseFrames;
+        *data++ = s->TxFramesWithDeferredXmissions;
+        *data++ = s->TxLateCollisions;
+        *data++ = s->TxTotalCollisions;
+        *data++ = s->TxFramesAbortedDueToXSCollisions;
+        *data++ = s->TxUnderrun;
+        *data++ = s->TxLengthErrors;
+        *data++ = s->TxInternalMACXmitError;
+        *data++ = s->TxFramesWithExcessiveDeferral;
+        *data++ = s->TxFCSErrors;
+
+        *data++ = s->RxOctetsOK;
+        *data++ = s->RxOctetsBad;
+        *data++ = s->RxUnicastFramesOK;
+        *data++ = s->RxMulticastFramesOK;
+        *data++ = s->RxBroadcastFramesOK;
+        *data++ = s->RxPauseFrames;
+        *data++ = s->RxFCSErrors;
+        *data++ = s->RxAlignErrors;
+        *data++ = s->RxSymbolErrors;
+        *data++ = s->RxDataErrors;
+        *data++ = s->RxSequenceErrors;
+        *data++ = s->RxRuntErrors;
+        *data++ = s->RxJabberErrors;
+        *data++ = s->RxInternalMACRcvError;
+        *data++ = s->RxInRangeLengthErrors;
+        *data++ = s->RxOutOfRangeLengthField;
+        *data++ = s->RxFrameTooLongErrors;
+
+       *data++ = ss->tso;
+       *data++ = ss->vlan_xtract;
+       *data++ = ss->vlan_insert;
+       *data++ = ss->rx_cso_good;
+       *data++ = ss->tx_cso;
+       *data++ = ss->rx_drops;
+
+       *data++ = (u64)t->respQ_empty;
+       *data++ = (u64)t->respQ_overflow;
+       *data++ = (u64)t->freelistQ_empty;
+       *data++ = (u64)t->pkt_too_big;
+       *data++ = (u64)t->pkt_mismatch;
+       *data++ = (u64)t->cmdQ_full[0];
+       *data++ = (u64)t->cmdQ_full[1];
+       *data++ = (u64)t->tx_ipfrags;
+       *data++ = (u64)t->tx_reg_pkts;
+       *data++ = (u64)t->tx_lso_pkts;
+       *data++ = (u64)t->tx_do_cksum;
+}
+
+static inline void reg_block_dump(struct adapter *ap, void *buf,
+                                 unsigned int start, unsigned int end)
+{
+       u32 *p = buf + start;
+
+       for ( ; start <= end; start += sizeof(u32))
+               *p++ = readl(ap->regs + start);
+}
+
+static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
+                    void *buf)
+{
+       struct adapter *ap = dev->priv;
+
+       /*
+        * Version scheme: bits 0..9: chip version, bits 10..15: chip revision
+        */
+       regs->version = 2;
+
+       memset(buf, 0, T2_REGMAP_SIZE);
+       reg_block_dump(ap, buf, 0, A_SG_RESPACCUTIMER);
+}
+
+static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct adapter *adapter = dev->priv;
+       struct port_info *p = &adapter->port[dev->if_port];
+
+       cmd->supported = p->link_config.supported;
+       cmd->advertising = p->link_config.advertising;
+
+       if (netif_carrier_ok(dev)) {
+               cmd->speed = p->link_config.speed;
+               cmd->duplex = p->link_config.duplex;
+       } else {
+               cmd->speed = -1;
+               cmd->duplex = -1;
+       }
+
+        cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
+        cmd->phy_address = p->phy->addr;
+        cmd->transceiver = XCVR_EXTERNAL;
+        cmd->autoneg = p->link_config.autoneg;
+        cmd->maxtxpkt = 0;
+        cmd->maxrxpkt = 0;
+       return 0;
+}
+
+static int speed_duplex_to_caps(int speed, int duplex)
+{
+       int cap = 0;
+
+       switch (speed) {
+       case SPEED_10:
+               if (duplex == DUPLEX_FULL)
+                       cap = SUPPORTED_10baseT_Full;
+               else
+                       cap = SUPPORTED_10baseT_Half;
+               break;
+       case SPEED_100:
+               if (duplex == DUPLEX_FULL)
+                       cap = SUPPORTED_100baseT_Full;
+               else
+                       cap = SUPPORTED_100baseT_Half;
+               break;
+       case SPEED_1000:
+               if (duplex == DUPLEX_FULL)
+                       cap = SUPPORTED_1000baseT_Full;
+               else
+                       cap = SUPPORTED_1000baseT_Half;
+               break;
+       case SPEED_10000:
+               if (duplex == DUPLEX_FULL)
+                       cap = SUPPORTED_10000baseT_Full;
+       }
+       return cap;
+}
+
+#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
+                     ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
+                     ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \
+                     ADVERTISED_10000baseT_Full)
+
+static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct adapter *adapter = dev->priv;
+       struct port_info *p = &adapter->port[dev->if_port];
+       struct link_config *lc = &p->link_config;
+
+       if (!(lc->supported & SUPPORTED_Autoneg))
+               return -EOPNOTSUPP;             /* can't change speed/duplex */
+
+       if (cmd->autoneg == AUTONEG_DISABLE) {
+               int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
+
+               if (!(lc->supported & cap) || cmd->speed == SPEED_1000)
+                       return -EINVAL;
+               lc->requested_speed = cmd->speed;
+               lc->requested_duplex = cmd->duplex;
+               lc->advertising = 0;
+       } else {
+               cmd->advertising &= ADVERTISED_MASK;
+               if (cmd->advertising & (cmd->advertising - 1))
+                       cmd->advertising = lc->supported;
+               cmd->advertising &= lc->supported;
+               if (!cmd->advertising)
+                       return -EINVAL;
+               lc->requested_speed = SPEED_INVALID;
+               lc->requested_duplex = DUPLEX_INVALID;
+               lc->advertising = cmd->advertising | ADVERTISED_Autoneg;
+       }
+       lc->autoneg = cmd->autoneg;
+       if (netif_running(dev))
+               t1_link_start(p->phy, p->mac, lc);
+       return 0;
+}
+
+static void get_pauseparam(struct net_device *dev,
+                          struct ethtool_pauseparam *epause)
+{
+       struct adapter *adapter = dev->priv;
+       struct port_info *p = &adapter->port[dev->if_port];
+
+       epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0;
+       epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0;
+       epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0;
+}
+
+static int set_pauseparam(struct net_device *dev,
+                         struct ethtool_pauseparam *epause)
+{
+       struct adapter *adapter = dev->priv;
+       struct port_info *p = &adapter->port[dev->if_port];
+       struct link_config *lc = &p->link_config;
+
+       if (epause->autoneg == AUTONEG_DISABLE)
+               lc->requested_fc = 0;
+       else if (lc->supported & SUPPORTED_Autoneg)
+               lc->requested_fc = PAUSE_AUTONEG;
+       else
+               return -EINVAL;
+
+       if (epause->rx_pause)
+               lc->requested_fc |= PAUSE_RX;
+       if (epause->tx_pause)
+               lc->requested_fc |= PAUSE_TX;
+       if (lc->autoneg == AUTONEG_ENABLE) {
+               if (netif_running(dev))
+                       t1_link_start(p->phy, p->mac, lc);
+       } else {
+               lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+               if (netif_running(dev))
+                       p->mac->ops->set_speed_duplex_fc(p->mac, -1, -1,
+                                                        lc->fc);
+       }
+       return 0;
+}
+
+static u32 get_rx_csum(struct net_device *dev)
+{
+       struct adapter *adapter = dev->priv;
+
+       return (adapter->flags & RX_CSUM_ENABLED) != 0;
+}
+
+static int set_rx_csum(struct net_device *dev, u32 data)
+{
+       struct adapter *adapter = dev->priv;
+
+       if (data)
+               adapter->flags |= RX_CSUM_ENABLED;
+       else
+               adapter->flags &= ~RX_CSUM_ENABLED;
+       return 0;
+}
+
+static int set_tso(struct net_device *dev, u32 value)
+{
+       struct adapter *adapter = dev->priv;
+
+       if (!(adapter->flags & TSO_CAPABLE))
+               return value ? -EOPNOTSUPP : 0;
+       return ethtool_op_set_tso(dev, value);
+}
+
+static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
+{
+       struct adapter *adapter = dev->priv;
+       int jumbo_fl = t1_is_T1B(adapter) ? 1 : 0;
+
+       e->rx_max_pending = MAX_RX_BUFFERS;
+       e->rx_mini_max_pending = 0;
+       e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS;
+       e->tx_max_pending = MAX_CMDQ_ENTRIES;
+
+       e->rx_pending = adapter->params.sge.freelQ_size[!jumbo_fl];
+       e->rx_mini_pending = 0;
+       e->rx_jumbo_pending = adapter->params.sge.freelQ_size[jumbo_fl];
+       e->tx_pending = adapter->params.sge.cmdQ_size[0];
+}
+
+static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
+{
+       struct adapter *adapter = dev->priv;
+       int jumbo_fl = t1_is_T1B(adapter) ? 1 : 0;
+
+       if (e->rx_pending > MAX_RX_BUFFERS || e->rx_mini_pending ||
+           e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS ||
+           e->tx_pending > MAX_CMDQ_ENTRIES ||
+           e->rx_pending < MIN_FL_ENTRIES ||
+           e->rx_jumbo_pending < MIN_FL_ENTRIES ||
+           e->tx_pending < (adapter->params.nports + 1) * (MAX_SKB_FRAGS + 1))
+               return -EINVAL;
+
+       if (adapter->flags & FULL_INIT_DONE)
+        return -EBUSY;
+
+       adapter->params.sge.freelQ_size[!jumbo_fl] = e->rx_pending;
+       adapter->params.sge.freelQ_size[jumbo_fl] = e->rx_jumbo_pending;
+       adapter->params.sge.cmdQ_size[0] = e->tx_pending;
+       adapter->params.sge.cmdQ_size[1] = e->tx_pending > MAX_CMDQ1_ENTRIES ?
+               MAX_CMDQ1_ENTRIES : e->tx_pending;
+       return 0;
+}
+
+static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
+{
+       struct adapter *adapter = dev->priv;
+
+       /*
+        * If RX coalescing is requested we use NAPI, otherwise interrupts.
+        * This choice can be made only when all ports and the TOE are off.
+        */
+       if (adapter->open_device_map == 0)
+               adapter->params.sge.polling = c->use_adaptive_rx_coalesce;
+
+       if (adapter->params.sge.polling) {
+               adapter->params.sge.rx_coalesce_usecs = 0;
+       } else {
+               adapter->params.sge.rx_coalesce_usecs = c->rx_coalesce_usecs;
+       }
+       adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce;
+       adapter->params.sge.sample_interval_usecs = c->rate_sample_interval;
+       t1_sge_set_coalesce_params(adapter->sge, &adapter->params.sge);
+       return 0;
+}
+
+static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
+{
+       struct adapter *adapter = dev->priv;
+
+       c->rx_coalesce_usecs = adapter->params.sge.rx_coalesce_usecs;
+       c->rate_sample_interval = adapter->params.sge.sample_interval_usecs;
+       c->use_adaptive_rx_coalesce = adapter->params.sge.coalesce_enable;
+       return 0;
+}
+
+static int get_eeprom_len(struct net_device *dev)
+{
+    return EEPROM_SIZE;
+}
+
+#define EEPROM_MAGIC(ap) \
+       (PCI_VENDOR_ID_CHELSIO | ((ap)->params.chip_version << 16))
+
+static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
+                     u8 *data)
+{
+       int i;
+       u8 buf[EEPROM_SIZE] __attribute__((aligned(4)));
+       struct adapter *adapter = dev->priv;
+
+       e->magic = EEPROM_MAGIC(adapter);
+       for (i = e->offset & ~3; i < e->offset + e->len; i += sizeof(u32))
+               t1_seeprom_read(adapter, i, (u32 *)&buf[i]);
+       memcpy(data, buf + e->offset, e->len);
+       return 0;
+}
+
+static struct ethtool_ops t1_ethtool_ops = {
+       .get_settings      = get_settings,
+       .set_settings      = set_settings,
+       .get_drvinfo       = get_drvinfo,
+       .get_msglevel      = get_msglevel,
+       .set_msglevel      = set_msglevel,
+       .get_ringparam     = get_sge_param,
+       .set_ringparam     = set_sge_param,
+       .get_coalesce      = get_coalesce,
+       .set_coalesce      = set_coalesce,
+       .get_eeprom_len    = get_eeprom_len,
+       .get_eeprom        = get_eeprom,
+       .get_pauseparam    = get_pauseparam,
+       .set_pauseparam    = set_pauseparam,
+       .get_rx_csum       = get_rx_csum,
+       .set_rx_csum       = set_rx_csum,
+       .get_tx_csum       = ethtool_op_get_tx_csum,
+       .set_tx_csum       = ethtool_op_set_tx_csum,
+       .get_sg            = ethtool_op_get_sg,
+       .set_sg            = ethtool_op_set_sg,
+       .get_link          = ethtool_op_get_link,
+       .get_strings       = get_strings,
+       .get_stats_count   = get_stats_count,
+       .get_ethtool_stats = get_stats,
+       .get_regs_len      = get_regs_len,
+       .get_regs          = get_regs,
+       .get_tso           = ethtool_op_get_tso,
+       .set_tso           = set_tso,
+};
+
+static void cxgb_proc_cleanup(struct adapter *adapter,
+                                       struct proc_dir_entry *dir)
+{
+       const char *name;
+       name = adapter->name;
+       remove_proc_entry(name, dir);
+}
+//#define chtoe_setup_toedev(adapter) NULL
+#define update_mtu_tab(adapter)
+#define write_smt_entry(adapter, idx)
+
+static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+        struct adapter *adapter = dev->priv;
+        struct mii_ioctl_data *data = if_mii(req);
+
+       switch (cmd) {
+        case SIOCGMIIPHY:
+                data->phy_id = adapter->port[dev->if_port].phy->addr;
+                /* FALLTHRU */
+        case SIOCGMIIREG: {
+               struct cphy *phy = adapter->port[dev->if_port].phy;
+               u32 val;
+
+               if (!phy->mdio_read)
+            return -EOPNOTSUPP;
+               phy->mdio_read(adapter, data->phy_id, 0, data->reg_num & 0x1f,
+                              &val);
+                data->val_out = val;
+                break;
+       }
+        case SIOCSMIIREG: {
+               struct cphy *phy = adapter->port[dev->if_port].phy;
+
+                if (!capable(CAP_NET_ADMIN))
+                    return -EPERM;
+               if (!phy->mdio_write)
+            return -EOPNOTSUPP;
+               phy->mdio_write(adapter, data->phy_id, 0, data->reg_num & 0x1f,
+                               data->val_in);
+                break;
+       }
+
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+static int t1_change_mtu(struct net_device *dev, int new_mtu)
+{
+       int ret;
+       struct adapter *adapter = dev->priv;
+       struct cmac *mac = adapter->port[dev->if_port].mac;
+
+       if (!mac->ops->set_mtu)
+        return -EOPNOTSUPP;
+       if (new_mtu < 68)
+        return -EINVAL;
+       if ((ret = mac->ops->set_mtu(mac, new_mtu)))
+               return ret;
+       dev->mtu = new_mtu;
+       return 0;
+}
+
+static int t1_set_mac_addr(struct net_device *dev, void *p)
+{
+       struct adapter *adapter = dev->priv;
+       struct cmac *mac = adapter->port[dev->if_port].mac;
+       struct sockaddr *addr = p;
+
+       if (!mac->ops->macaddress_set)
+               return -EOPNOTSUPP;
+
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+       mac->ops->macaddress_set(mac, dev->dev_addr);
+       return 0;
+}
+
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+static void vlan_rx_register(struct net_device *dev,
+                                  struct vlan_group *grp)
+{
+       struct adapter *adapter = dev->priv;
+
+       spin_lock_irq(&adapter->async_lock);
+       adapter->vlan_grp = grp;
+       t1_set_vlan_accel(adapter, grp != NULL);
+       spin_unlock_irq(&adapter->async_lock);
+}
+
+static void vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+       struct adapter *adapter = dev->priv;
+
+       spin_lock_irq(&adapter->async_lock);
+       if (adapter->vlan_grp)
+               adapter->vlan_grp->vlan_devices[vid] = NULL;
+       spin_unlock_irq(&adapter->async_lock);
+}
+#endif
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void t1_netpoll(struct net_device *dev)
+{
+       unsigned long flags;
+       struct adapter *adapter = dev->priv;
+
+       local_irq_save(flags);
+        t1_select_intr_handler(adapter)(adapter->pdev->irq, adapter, NULL);
+       local_irq_restore(flags);
+}
+#endif
+
+/*
+ * Periodic accumulation of MAC statistics.  This is used only if the MAC
+ * does not have any other way to prevent stats counter overflow.
+ */
+static void mac_stats_task(void *data)
+{
+       int i;
+       struct adapter *adapter = data;
+
+       for_each_port(adapter, i) {
+               struct port_info *p = &adapter->port[i];
+
+               if (netif_running(p->dev))
+                       p->mac->ops->statistics_update(p->mac,
+                                                      MAC_STATS_UPDATE_FAST);
+       }
+
+       /* Schedule the next statistics update if any port is active. */
+       spin_lock(&adapter->work_lock);
+       if (adapter->open_device_map & PORT_MASK)
+               schedule_mac_stats_update(adapter,
+                                         adapter->params.stats_update_period);
+       spin_unlock(&adapter->work_lock);
+}
+
+/*
+ * Processes elmer0 external interrupts in process context.
+ */
+static void ext_intr_task(void *data)
+{
+       struct adapter *adapter = data;
+
+       elmer0_ext_intr_handler(adapter);
+
+       /* Now reenable external interrupts */
+       spin_lock_irq(&adapter->async_lock);
+       adapter->slow_intr_mask |= F_PL_INTR_EXT;
+       writel(F_PL_INTR_EXT, adapter->regs + A_PL_CAUSE);
+       writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA,
+                   adapter->regs + A_PL_ENABLE);
+       spin_unlock_irq(&adapter->async_lock);
+}
+
+/*
+ * Interrupt-context handler for elmer0 external interrupts.
+ */
+void t1_elmer0_ext_intr(struct adapter *adapter)
+{
+       /*
+        * Schedule a task to handle external interrupts as we require
+        * a process context.  We disable EXT interrupts in the interim
+        * and let the task reenable them when it's done.
+        */
+       adapter->slow_intr_mask &= ~F_PL_INTR_EXT;
+       writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA,
+                   adapter->regs + A_PL_ENABLE);
+       schedule_work(&adapter->ext_intr_handler_task);
+}
+
+void t1_fatal_err(struct adapter *adapter)
+{
+       if (adapter->flags & FULL_INIT_DONE) {
+               t1_sge_stop(adapter->sge);
+               t1_interrupts_disable(adapter);
+       }
+       CH_ALERT("%s: encountered fatal error, operation suspended\n",
+                adapter->name);
+}
+
+static int __devinit init_one(struct pci_dev *pdev,
+                             const struct pci_device_id *ent)
+{
+       static int version_printed;
+
+       int i, err, pci_using_dac = 0;
+       unsigned long mmio_start, mmio_len;
+       const struct board_info *bi;
+       struct adapter *adapter = NULL;
+       struct port_info *pi;
+
+       if (!version_printed) {
+               printk(KERN_INFO "%s - version %s\n", DRV_DESCRIPTION,
+                      DRV_VERSION);
+               ++version_printed;
+       }
+
+       err = pci_enable_device(pdev);
+       if (err)
+        return err;
+
+       if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+               CH_ERR("%s: cannot find PCI device memory base address\n",
+                      pci_name(pdev));
+               err = -ENODEV;
+               goto out_disable_pdev;
+       }
+
+       if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+               pci_using_dac = 1;
+
+               if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
+                       CH_ERR("%s: unable to obtain 64-bit DMA for"
+                              "consistent allocations\n", pci_name(pdev));
+                       err = -ENODEV;
+                       goto out_disable_pdev;
+               }
+
+       } else if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) {
+               CH_ERR("%s: no usable DMA configuration\n", pci_name(pdev));
+               goto out_disable_pdev;
+       }
+
+       err = pci_request_regions(pdev, DRV_NAME);
+       if (err) {
+               CH_ERR("%s: cannot obtain PCI resources\n", pci_name(pdev));
+               goto out_disable_pdev;
+       }
+
+       pci_set_master(pdev);
+
+    mmio_start = pci_resource_start(pdev, 0);
+       mmio_len = pci_resource_len(pdev, 0);
+       bi = t1_get_board_info(ent->driver_data);
+
+       for (i = 0; i < bi->port_number; ++i) {
+               struct net_device *netdev;
+
+               netdev = alloc_etherdev(adapter ? 0 : sizeof(*adapter));
+               if (!netdev) {
+                       err = -ENOMEM;
+                       goto out_free_dev;
+               }
+
+               SET_MODULE_OWNER(netdev);
+               SET_NETDEV_DEV(netdev, &pdev->dev);
+
+               if (!adapter) {
+                       adapter = netdev->priv;
+                       adapter->pdev = pdev;
+                       adapter->port[0].dev = netdev;  /* so we don't leak it */
+
+                       adapter->regs = ioremap(mmio_start, mmio_len);
+                       if (!adapter->regs) {
+                               CH_ERR("%s: cannot map device registers\n",
+                                      pci_name(pdev));
+                               err = -ENOMEM;
+                               goto out_free_dev;
+                       }
+
+                       if (t1_get_board_rev(adapter, bi, &adapter->params)) {
+                               err = -ENODEV;    /* Can't handle this chip rev */
+                               goto out_free_dev;
+                       }
+
+                       adapter->name = pci_name(pdev);
+                       adapter->msg_enable = dflt_msg_enable;
+                       adapter->mmio_len = mmio_len;
+
+                       init_MUTEX(&adapter->mib_mutex);
+                       spin_lock_init(&adapter->tpi_lock);
+                       spin_lock_init(&adapter->work_lock);
+                       spin_lock_init(&adapter->async_lock);
+
+                       INIT_WORK(&adapter->ext_intr_handler_task,
+                                 ext_intr_task, adapter);
+                       INIT_WORK(&adapter->stats_update_task, mac_stats_task,
+                                 adapter);
+#ifdef work_struct
+                       init_timer(&adapter->stats_update_timer);
+                       adapter->stats_update_timer.function = mac_stats_timer;
+                       adapter->stats_update_timer.data =
+                               (unsigned long)adapter;
+#endif
+
+                       pci_set_drvdata(pdev, netdev);
+               }
+
+               pi = &adapter->port[i];
+               pi->dev = netdev;
+               netif_carrier_off(netdev);
+               netdev->irq = pdev->irq;
+               netdev->if_port = i;
+               netdev->mem_start = mmio_start;
+               netdev->mem_end = mmio_start + mmio_len - 1;
+               netdev->priv = adapter;
+               netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+               netdev->features |= NETIF_F_LLTX;
+
+               adapter->flags |= RX_CSUM_ENABLED | TCP_CSUM_CAPABLE;
+               if (pci_using_dac)
+                       netdev->features |= NETIF_F_HIGHDMA;
+               if (vlan_tso_capable(adapter)) {
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+                       adapter->flags |= VLAN_ACCEL_CAPABLE;
+                       netdev->features |=
+                               NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+                       netdev->vlan_rx_register = vlan_rx_register;
+                       netdev->vlan_rx_kill_vid = vlan_rx_kill_vid;
+#endif
+                       adapter->flags |= TSO_CAPABLE;
+                       netdev->features |= NETIF_F_TSO;
+               }
+
+               netdev->open = cxgb_open;
+               netdev->stop = cxgb_close;
+               netdev->hard_start_xmit = t1_start_xmit;
+               netdev->hard_header_len += (adapter->flags & TSO_CAPABLE) ?
+                       sizeof(struct cpl_tx_pkt_lso) :
+                       sizeof(struct cpl_tx_pkt);
+               netdev->get_stats = t1_get_stats;
+               netdev->set_multicast_list = t1_set_rxmode;
+               netdev->do_ioctl = t1_ioctl;
+               netdev->change_mtu = t1_change_mtu;
+               netdev->set_mac_address = t1_set_mac_addr;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+               netdev->poll_controller = t1_netpoll;
+#endif
+               netdev->weight = 64;
+
+        SET_ETHTOOL_OPS(netdev, &t1_ethtool_ops);
+       }
+
+       if (t1_init_sw_modules(adapter, bi) < 0) {
+               err = -ENODEV;
+               goto out_free_dev;
+       }
+
+       /*
+        * The card is now ready to go.  If any errors occur during device
+        * registration we do not fail the whole card but rather proceed only
+        * with the ports we manage to register successfully.  However we must
+        * register at least one net device.
+        */
+       for (i = 0; i < bi->port_number; ++i) {
+               err = register_netdev(adapter->port[i].dev);
+               if (err)
+                       CH_WARN("%s: cannot register net device %s, skipping\n",
+                               pci_name(pdev), adapter->port[i].dev->name);
+               else {
+                       /*
+                        * Change the name we use for messages to the name of
+                        * the first successfully registered interface.
+                        */
+                       if (!adapter->registered_device_map)
+                               adapter->name = adapter->port[i].dev->name;
+
+                __set_bit(i, &adapter->registered_device_map);
+               }
+       }
+       if (!adapter->registered_device_map) {
+               CH_ERR("%s: could not register any net devices\n",
+                      pci_name(pdev));
+               goto out_release_adapter_res;
+       }
+
+       printk(KERN_INFO "%s: %s (rev %d), %s %dMHz/%d-bit\n", adapter->name,
+              bi->desc, adapter->params.chip_revision,
+              adapter->params.pci.is_pcix ? "PCIX" : "PCI",
+              adapter->params.pci.speed, adapter->params.pci.width);
+       return 0;
+
+ out_release_adapter_res:
+       t1_free_sw_modules(adapter);
+ out_free_dev:
+       if (adapter) {
+               if (adapter->regs) iounmap(adapter->regs);
+               for (i = bi->port_number - 1; i >= 0; --i)
+                       if (adapter->port[i].dev) {
+                               cxgb_proc_cleanup(adapter, proc_root_driver);
+                               kfree(adapter->port[i].dev);
+                       }
+       }
+       pci_release_regions(pdev);
+ out_disable_pdev:
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+       return err;
+}
+
+static inline void t1_sw_reset(struct pci_dev *pdev)
+{
+       pci_write_config_dword(pdev, A_PCICFG_PM_CSR, 3);
+       pci_write_config_dword(pdev, A_PCICFG_PM_CSR, 0);
+}
+
+static void __devexit remove_one(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+
+       if (dev) {
+               int i;
+               struct adapter *adapter = dev->priv;
+
+               for_each_port(adapter, i)
+                       if (test_bit(i, &adapter->registered_device_map))
+                               unregister_netdev(adapter->port[i].dev);
+
+               t1_free_sw_modules(adapter);
+               iounmap(adapter->regs);
+               while (--i >= 0)
+                       if (adapter->port[i].dev) {
+                               cxgb_proc_cleanup(adapter, proc_root_driver);
+                               kfree(adapter->port[i].dev);
+                       }
+               pci_release_regions(pdev);
+               pci_disable_device(pdev);
+               pci_set_drvdata(pdev, NULL);
+               t1_sw_reset(pdev);
+       }
+}
+
+static struct pci_driver driver = {
+       .name     = DRV_NAME,
+       .id_table = t1_pci_tbl,
+       .probe    = init_one,
+       .remove   = __devexit_p(remove_one),
+};
+
+static int __init t1_init_module(void)
+{
+       return pci_module_init(&driver);
+}
+
+static void __exit t1_cleanup_module(void)
+{
+       pci_unregister_driver(&driver);
+}
+
+module_init(t1_init_module);
+module_exit(t1_cleanup_module);
diff --git a/drivers/net/chelsio/elmer0.h b/drivers/net/chelsio/elmer0.h
new file mode 100644 (file)
index 0000000..5590cb2
--- /dev/null
@@ -0,0 +1,151 @@
+/*****************************************************************************
+ *                                                                           *
+ * File: elmer0.h                                                            *
+ * $Revision: 1.6 $                                                          *
+ * $Date: 2005/06/21 22:49:43 $                                              *
+ * Description:                                                              *
+ *  part of the Chelsio 10Gb Ethernet Driver.                                *
+ *                                                                           *
+ * This program is free software; you can redistribute it and/or modify      *
+ * it under the terms of the GNU General Public License, version 2, as       *
+ * published by the Free Software Foundation.                                *
+ *                                                                           *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED    *
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF      *
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.                     *
+ *                                                                           *
+ * http://www.chelsio.com                                                    *
+ *                                                                           *
+ * Copyright (c) 2003 - 2005 Chelsio Communications, Inc.                    *
+ * All rights reserved.                                                      *
+ *                                                                           *
+ * Maintainers: maintainers@chelsio.com                                      *
+ *                                                                           *
+ * Authors: Dimitrios Michailidis   <dm@chelsio.com>                         *
+ *          Tina Yang               <tainay@chelsio.com>                     *
+ *          Felix Marti             <felix@chelsio.com>                      *
+ *          Scott Bardone           <sbardone@chelsio.com>                   *
+ *          Kurt Ottaway            <kottaway@chelsio.com>                   *
+ *          Frank DiMambro          <frank@chelsio.com>                      *
+ *                                                                           *
+ * History:                                                                  *
+ *                                                                           *
+ ****************************************************************************/
+
+#ifndef _CXGB_ELMER0_H_
+#define _CXGB_ELMER0_H_
+
+/* ELMER0 registers */
+#define A_ELMER0_VERSION 0x100000
+#define A_ELMER0_PHY_CFG 0x100004
+#define A_ELMER0_INT_ENABLE 0x100008
+#define A_ELMER0_INT_CAUSE 0x10000c
+#define A_ELMER0_GPI_CFG 0x100010
+#define A_ELMER0_GPI_STAT 0x100014
+#define A_ELMER0_GPO 0x100018
+#define A_ELMER0_PORT0_MI1_CFG 0x400000
+
+#define S_MI1_MDI_ENABLE    0
+#define V_MI1_MDI_ENABLE(x) ((x) << S_MI1_MDI_ENABLE)
+#define F_MI1_MDI_ENABLE    V_MI1_MDI_ENABLE(1U)
+
+#define S_MI1_MDI_INVERT    1
+#define V_MI1_MDI_INVERT(x) ((x) << S_MI1_MDI_INVERT)
+#define F_MI1_MDI_INVERT    V_MI1_MDI_INVERT(1U)
+
+#define S_MI1_PREAMBLE_ENABLE    2
+#define V_MI1_PREAMBLE_ENABLE(x) ((x) << S_MI1_PREAMBLE_ENABLE)
+#define F_MI1_PREAMBLE_ENABLE    V_MI1_PREAMBLE_ENABLE(1U)
+
+#define S_MI1_SOF    3
+#define M_MI1_SOF    0x3
+#define V_MI1_SOF(x) ((x) << S_MI1_SOF)
+#define G_MI1_SOF(x) (((x) >> S_MI1_SOF) & M_MI1_SOF)
+
+#define S_MI1_CLK_DIV    5
+#define M_MI1_CLK_DIV    0xff
+#define V_MI1_CLK_DIV(x) ((x) << S_MI1_CLK_DIV)
+#define G_MI1_CLK_DIV(x) (((x) >> S_MI1_CLK_DIV) & M_MI1_CLK_DIV)
+
+#define A_ELMER0_PORT0_MI1_ADDR 0x400004
+
+#define S_MI1_REG_ADDR    0
+#define M_MI1_REG_ADDR    0x1f
+#define V_MI1_REG_ADDR(x) ((x) << S_MI1_REG_ADDR)
+#define G_MI1_REG_ADDR(x) (((x) >> S_MI1_REG_ADDR) & M_MI1_REG_ADDR)
+
+#define S_MI1_PHY_ADDR    5
+#define M_MI1_PHY_ADDR    0x1f
+#define V_MI1_PHY_ADDR(x) ((x) << S_MI1_PHY_ADDR)
+#define G_MI1_PHY_ADDR(x) (((x) >> S_MI1_PHY_ADDR) & M_MI1_PHY_ADDR)
+
+#define A_ELMER0_PORT0_MI1_DATA 0x400008
+
+#define S_MI1_DATA    0
+#define M_MI1_DATA    0xffff
+#define V_MI1_DATA(x) ((x) << S_MI1_DATA)
+#define G_MI1_DATA(x) (((x) >> S_MI1_DATA) & M_MI1_DATA)
+
+#define A_ELMER0_PORT0_MI1_OP 0x40000c
+
+#define S_MI1_OP    0
+#define M_MI1_OP    0x3
+#define V_MI1_OP(x) ((x) << S_MI1_OP)
+#define G_MI1_OP(x) (((x) >> S_MI1_OP) & M_MI1_OP)
+
+#define S_MI1_ADDR_AUTOINC    2
+#define V_MI1_ADDR_AUTOINC(x) ((x) << S_MI1_ADDR_AUTOINC)
+#define F_MI1_ADDR_AUTOINC    V_MI1_ADDR_AUTOINC(1U)
+
+#define S_MI1_OP_BUSY    31
+#define V_MI1_OP_BUSY(x) ((x) << S_MI1_OP_BUSY)
+#define F_MI1_OP_BUSY    V_MI1_OP_BUSY(1U)
+
+#define A_ELMER0_PORT1_MI1_CFG 0x500000
+#define A_ELMER0_PORT1_MI1_ADDR 0x500004
+#define A_ELMER0_PORT1_MI1_DATA 0x500008
+#define A_ELMER0_PORT1_MI1_OP 0x50000c
+#define A_ELMER0_PORT2_MI1_CFG 0x600000
+#define A_ELMER0_PORT2_MI1_ADDR 0x600004
+#define A_ELMER0_PORT2_MI1_DATA 0x600008
+#define A_ELMER0_PORT2_MI1_OP 0x60000c
+#define A_ELMER0_PORT3_MI1_CFG 0x700000
+#define A_ELMER0_PORT3_MI1_ADDR 0x700004
+#define A_ELMER0_PORT3_MI1_DATA 0x700008
+#define A_ELMER0_PORT3_MI1_OP 0x70000c
+
+/* Simple bit definition for GPI and GP0 registers. */
+#define     ELMER0_GP_BIT0              0x0001
+#define     ELMER0_GP_BIT1              0x0002
+#define     ELMER0_GP_BIT2              0x0004
+#define     ELMER0_GP_BIT3              0x0008
+#define     ELMER0_GP_BIT4              0x0010
+#define     ELMER0_GP_BIT5              0x0020
+#define     ELMER0_GP_BIT6              0x0040
+#define     ELMER0_GP_BIT7              0x0080
+#define     ELMER0_GP_BIT8              0x0100
+#define     ELMER0_GP_BIT9              0x0200
+#define     ELMER0_GP_BIT10             0x0400
+#define     ELMER0_GP_BIT11             0x0800
+#define     ELMER0_GP_BIT12             0x1000
+#define     ELMER0_GP_BIT13             0x2000
+#define     ELMER0_GP_BIT14             0x4000
+#define     ELMER0_GP_BIT15             0x8000
+#define     ELMER0_GP_BIT16             0x10000
+#define     ELMER0_GP_BIT17             0x20000
+#define     ELMER0_GP_BIT18             0x40000
+#define     ELMER0_GP_BIT19             0x80000
+
+#define MI1_OP_DIRECT_WRITE 1
+#define MI1_OP_DIRECT_READ  2
+
+#define MI1_OP_INDIRECT_ADDRESS  0
+#define MI1_OP_INDIRECT_WRITE    1
+#define MI1_OP_INDIRECT_READ_INC 2
+#define MI1_OP_INDIRECT_READ     3
+
+#endif /* _CXGB_ELMER0_H_ */
diff --git a/drivers/net/chelsio/espi.c b/drivers/net/chelsio/espi.c
new file mode 100644 (file)
index 0000000..2306425
--- /dev/null
@@ -0,0 +1,346 @@
+/*****************************************************************************
+ *                                                                           *
+ * File: espi.c                                                              *
+ * $Revision: 1.14 $                                                         *
+ * $Date: 2005/05/14 00:59:32 $                                              *
+ * Description:                                                              *
+ *  Ethernet SPI functionality.                                              *
+ *  part of the Chelsio 10Gb Ethernet Driver.                                *
+ *                                                                           *
+ * This program is free software; you can redistribute it and/or modify      *
+ * it under the terms of the GNU General Public License, version 2, as       *
+ * published by the Free Software Foundation.                                *
+ *                                                                           *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED    *
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF      *
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.                     *
+ *                                                                           *
+ * http://www.chelsio.com                                                    *
+ *                                                                           *
+ * Copyright (c) 2003 - 2005 Chelsio Communications, Inc.                    *
+ * All rights reserved.                                                      *
+ *                                                                           *
+ * Maintainers: maintainers@chelsio.com                                      *
+ *                                                                           *
+ * Authors: Dimitrios Michailidis   <dm@chelsio.com>                         *
+ *          Tina Yang               <tainay@chelsio.com>                     *
+ *          Felix Marti             <felix@chelsio.com>                      *
+ *          Scott Bardone           <sbardone@chelsio.com>                   *
+ *          Kurt Ottaway            <kottaway@chelsio.com>                   *
+ *          Frank DiMambro          <frank@chelsio.com>                      *
+ *                                                                           *
+ * History:                                                                  *
+ *                                                                           *
+ ****************************************************************************/
+
+#include "common.h"
+#include "regs.h"
+#include "espi.h"
+
+struct peespi {
+       adapter_t *adapter;
+       struct espi_intr_counts intr_cnt;
+       u32 misc_ctrl;
+       spinlock_t lock;
+};
+
+#define ESPI_INTR_MASK (F_DIP4ERR | F_RXDROP | F_TXDROP | F_RXOVERFLOW | \
+                       F_RAMPARITYERR | F_DIP2PARITYERR)
+#define MON_MASK  (V_MONITORED_PORT_NUM(3) | F_MONITORED_DIRECTION \
+                  | F_MONITORED_INTERFACE)
+
+#define TRICN_CNFG 14
+#define TRICN_CMD_READ  0x11
+#define TRICN_CMD_WRITE 0x21
+#define TRICN_CMD_ATTEMPTS 10
+
+static int tricn_write(adapter_t *adapter, int bundle_addr, int module_addr,
+                      int ch_addr, int reg_offset, u32 wr_data)
+{
+       int busy, attempts = TRICN_CMD_ATTEMPTS;
+
+       writel(V_WRITE_DATA(wr_data) |
+              V_REGISTER_OFFSET(reg_offset) |
+              V_CHANNEL_ADDR(ch_addr) | V_MODULE_ADDR(module_addr) |
+              V_BUNDLE_ADDR(bundle_addr) |
+              V_SPI4_COMMAND(TRICN_CMD_WRITE),
+              adapter->regs + A_ESPI_CMD_ADDR);
+       writel(0, adapter->regs + A_ESPI_GOSTAT);
+
+       do {
+               busy = readl(adapter->regs + A_ESPI_GOSTAT) & F_ESPI_CMD_BUSY;
+       } while (busy && --attempts);
+
+       if (busy)
+               CH_ERR("%s: TRICN write timed out\n", adapter->name);
+
+       return busy;
+}
+
+/* 1. Deassert rx_reset_core. */
+/* 2. Program TRICN_CNFG registers. */
+/* 3. Deassert rx_reset_link */
+static int tricn_init(adapter_t *adapter)
+{
+       int     i               = 0;
+       int     sme             = 1;
+       int     stat            = 0;
+       int     timeout         = 0;
+       int     is_ready        = 0;
+       int     dynamic_deskew  = 0;
+
+       if (dynamic_deskew)
+               sme = 0;
+
+
+       /* 1 */
+       timeout=1000;
+       do {
+               stat = readl(adapter->regs + A_ESPI_RX_RESET);
+               is_ready = (stat & 0x4);
+               timeout--;
+               udelay(5);
+       } while (!is_ready || (timeout==0));
+       writel(0x2, adapter->regs + A_ESPI_RX_RESET);
+       if (timeout==0)
+       {
+               CH_ERR("ESPI : ERROR : Timeout tricn_init() \n");
+               t1_fatal_err(adapter);
+       }
+
+       /* 2 */
+       if (sme) {
+               tricn_write(adapter, 0, 0, 0, TRICN_CNFG, 0x81);
+               tricn_write(adapter, 0, 1, 0, TRICN_CNFG, 0x81);
+               tricn_write(adapter, 0, 2, 0, TRICN_CNFG, 0x81);
+       }
+       for (i=1; i<= 8; i++) tricn_write(adapter, 0, 0, i, TRICN_CNFG, 0xf1);
+       for (i=1; i<= 2; i++) tricn_write(adapter, 0, 1, i, TRICN_CNFG, 0xf1);
+       for (i=1; i<= 3; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1);
+       for (i=4; i<= 4; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xf1);
+       for (i=5; i<= 5; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1);
+       for (i=6; i<= 6; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xf1);
+       for (i=7; i<= 7; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0x80);
+       for (i=8; i<= 8; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xf1);
+
+       /* 3 */
+       writel(0x3, adapter->regs + A_ESPI_RX_RESET);
+
+       return 0;
+}
+
+void t1_espi_intr_enable(struct peespi *espi)
+{
+       u32 enable, pl_intr = readl(espi->adapter->regs + A_PL_ENABLE);
+
+       /*
+        * Cannot enable ESPI interrupts on T1B because HW asserts the
+        * interrupt incorrectly, namely the driver gets ESPI interrupts
+        * but no data is actually dropped (can verify this reading the ESPI
+        * drop registers).  Also, once the ESPI interrupt is asserted it
+        * cannot be cleared (HW bug).
+        */
+       enable = t1_is_T1B(espi->adapter) ? 0 : ESPI_INTR_MASK;
+       writel(enable, espi->adapter->regs + A_ESPI_INTR_ENABLE);
+       writel(pl_intr | F_PL_INTR_ESPI, espi->adapter->regs + A_PL_ENABLE);
+}
+
+void t1_espi_intr_clear(struct peespi *espi)
+{
+       writel(0xffffffff, espi->adapter->regs + A_ESPI_INTR_STATUS);
+       writel(F_PL_INTR_ESPI, espi->adapter->regs + A_PL_CAUSE);
+}
+
+void t1_espi_intr_disable(struct peespi *espi)
+{
+       u32 pl_intr = readl(espi->adapter->regs + A_PL_ENABLE);
+
+       writel(0, espi->adapter->regs + A_ESPI_INTR_ENABLE);
+       writel(pl_intr & ~F_PL_INTR_ESPI, espi->adapter->regs + A_PL_ENABLE);
+}
+
+int t1_espi_intr_handler(struct peespi *espi)
+{
+       u32 cnt;
+       u32 status = readl(espi->adapter->regs + A_ESPI_INTR_STATUS);
+
+       if (status & F_DIP4ERR)
+               espi->intr_cnt.DIP4_err++;
+       if (status & F_RXDROP)
+               espi->intr_cnt.rx_drops++;
+       if (status & F_TXDROP)
+               espi->intr_cnt.tx_drops++;
+       if (status & F_RXOVERFLOW)
+               espi->intr_cnt.rx_ovflw++;
+       if (status & F_RAMPARITYERR)
+               espi->intr_cnt.parity_err++;
+       if (status & F_DIP2PARITYERR) {
+               espi->intr_cnt.DIP2_parity_err++;
+
+               /*
+                * Must read the error count to clear the interrupt
+                * that it causes.
+                */
+               cnt = readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT);
+       }
+
+       /*
+        * For T1B we need to write 1 to clear ESPI interrupts.  For T2+ we
+        * write the status as is.
+        */
+       if (status && t1_is_T1B(espi->adapter))
+               status = 1;
+       writel(status, espi->adapter->regs + A_ESPI_INTR_STATUS);
+       return 0;
+}
+
+const struct espi_intr_counts *t1_espi_get_intr_counts(struct peespi *espi)
+{
+    return &espi->intr_cnt;
+}
+
+static void espi_setup_for_pm3393(adapter_t *adapter)
+{
+       u32 wmark = t1_is_T1B(adapter) ? 0x4000 : 0x3200;
+
+       writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0);
+       writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN1);
+       writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2);
+       writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN3);
+       writel(0x100, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK);
+       writel(wmark, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK);
+       writel(3, adapter->regs + A_ESPI_CALENDAR_LENGTH);
+       writel(0x08000008, adapter->regs + A_ESPI_TRAIN);
+       writel(V_RX_NPORTS(1) | V_TX_NPORTS(1), adapter->regs + A_PORT_CONFIG);
+}
+
+/* T2 Init part --  */
+/* 1. Set T_ESPI_MISCCTRL_ADDR */
+/* 2. Init ESPI registers. */
+/* 3. Init TriCN Hard Macro */
+int t1_espi_init(struct peespi *espi, int mac_type, int nports)
+{
+       u32 cnt;
+
+       u32 status_enable_extra = 0;
+       adapter_t *adapter = espi->adapter;
+       u32 status, burstval = 0x800100;
+
+       /* Disable ESPI training.  MACs that can handle it enable it below. */
+       writel(0, adapter->regs + A_ESPI_TRAIN);
+
+       if (is_T2(adapter)) {
+               writel(V_OUT_OF_SYNC_COUNT(4) |
+                      V_DIP2_PARITY_ERR_THRES(3) |
+                      V_DIP4_THRES(1), adapter->regs + A_ESPI_MISC_CONTROL);
+               if (nports == 4) {
+                       /* T204: maxburst1 = 0x40, maxburst2 = 0x20 */
+                       burstval = 0x200040;
+               }
+       }
+       writel(burstval, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
+
+       switch (mac_type) {
+       case CHBT_MAC_PM3393:
+               espi_setup_for_pm3393(adapter);
+               break;
+       default:
+               return -1;
+       }
+
+       /*
+        * Make sure any pending interrupts from the SPI are
+        * Cleared before enabling the interrupt.
+        */
+       writel(ESPI_INTR_MASK, espi->adapter->regs + A_ESPI_INTR_ENABLE);
+       status = readl(espi->adapter->regs + A_ESPI_INTR_STATUS);
+       if (status & F_DIP2PARITYERR) {
+               cnt = readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT);
+       }
+
+       /*
+        * For T1B we need to write 1 to clear ESPI interrupts.  For T2+ we
+        * write the status as is.
+        */
+       if (status && t1_is_T1B(espi->adapter))
+               status = 1;
+       writel(status, espi->adapter->regs + A_ESPI_INTR_STATUS);
+
+       writel(status_enable_extra | F_RXSTATUSENABLE,
+              adapter->regs + A_ESPI_FIFO_STATUS_ENABLE);
+
+       if (is_T2(adapter)) {
+               tricn_init(adapter);
+               /*
+                * Always position the control at the 1st port egress IN
+                * (sop,eop) counter to reduce PIOs for T/N210 workaround.
+                */
+               espi->misc_ctrl = (readl(adapter->regs + A_ESPI_MISC_CONTROL)
+                                  & ~MON_MASK) | (F_MONITORED_DIRECTION
+                                  | F_MONITORED_INTERFACE);
+               writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
+               spin_lock_init(&espi->lock);
+       }
+
+       return 0;
+}
+
+void t1_espi_destroy(struct peespi *espi)
+{
+       kfree(espi);
+}
+
+struct peespi *t1_espi_create(adapter_t *adapter)
+{
+       struct peespi *espi = kmalloc(sizeof(*espi), GFP_KERNEL);
+
+       memset(espi, 0, sizeof(*espi));
+
+       if (espi)
+               espi->adapter = adapter;
+       return espi;
+}
+
+void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val)
+{
+       struct peespi *espi = adapter->espi;
+
+       if (!is_T2(adapter))
+               return;
+       spin_lock(&espi->lock);
+       espi->misc_ctrl = (val & ~MON_MASK) |
+                         (espi->misc_ctrl & MON_MASK);
+       writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
+       spin_unlock(&espi->lock);
+}
+
+u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait)
+{
+       u32 sel;
+
+       struct peespi *espi = adapter->espi;
+
+       if (!is_T2(adapter))
+               return 0;
+       sel = V_MONITORED_PORT_NUM((addr & 0x3c) >> 2);
+       if (!wait) {
+               if (!spin_trylock(&espi->lock))
+                       return 0;
+       }
+       else
+               spin_lock(&espi->lock);
+       if ((sel != (espi->misc_ctrl & MON_MASK))) {
+               writel(((espi->misc_ctrl & ~MON_MASK) | sel),
+                      adapter->regs + A_ESPI_MISC_CONTROL);
+               sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
+               writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
+       }
+       else
+               sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
+       spin_unlock(&espi->lock);
+       return sel;
+}
diff --git a/drivers/net/chelsio/espi.h b/drivers/net/chelsio/espi.h
new file mode 100644 (file)
index 0000000..c90e37f
--- /dev/null
@@ -0,0 +1,68 @@
+/*****************************************************************************
+ *                                                                           *
+ * File: espi.h                                                              *
+ * $Revision: 1.7 $                                                          *
+ * $Date: 2005/06/21 18:29:47 $                                              *
+ * Description:                                                              *
+ *  part of the Chelsio 10Gb Ethernet Driver.                                *
+ *                                                                           *
+ * This program is free software; you can redistribute it and/or modify      *
+ * it under the terms of the GNU General Public License, version 2, as       *
+ * published by the Free Software Foundation.                                *
+ *                                                                           *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED    *
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF      *
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.                     *
+ *                                                                           *
+ * http://www.chelsio.com                                                    *
+ *                                                                           *
+ * Copyright (c) 2003 - 2005 Chelsio Communications, Inc.                    *
+ * All rights reserved.                                                      *
+ *                                                                           *
+ * Maintainers: maintainers@chelsio.com                                      *
+ *                                                                           *
+ * Authors: Dimitrios Michailidis   <dm@chelsio.com>                         *
+ *          Tina Yang               <tainay@chelsio.com>                     *
+ *          Felix Marti             <felix@chelsio.com>                      *
+ *          Scott Bardone           <sbardone@chelsio.com>                   *
+ *          Kurt Ottaway            <kottaway@chelsio.com>                   *
+ *          Frank DiMambro          <frank@chelsio.com>                      *
+ *                                                                           *
+ * History:                                                                  *
+ *                                                                           *
+ ****************************************************************************/
+
+#ifndef _CXGB_ESPI_H_
+#define _CXGB_ESPI_H_
+
+#include "common.h"
+
+struct espi_intr_counts {
+       unsigned int DIP4_err;
+       unsigned int rx_drops;
+       unsigned int tx_drops;
+       unsigned int rx_ovflw;
+       unsigned int parity_err;
+       unsigned int DIP2_parity_err;
+};
+
+struct peespi;
+
+struct peespi *t1_espi_create(adapter_t *adapter);
+void t1_espi_destroy(struct peespi *espi);
+int t1_espi_init(struct peespi *espi, int mac_type, int nports);
+
+void t1_espi_intr_enable(struct peespi *);
+void t1_espi_intr_clear(struct peespi *);
+void t1_espi_intr_disable(struct peespi *);
+int t1_espi_intr_handler(struct peespi *);
+const struct espi_intr_counts *t1_espi_get_intr_counts(struct peespi *espi);
+
+void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val);
+u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait);
+
+#endif /* _CXGB_ESPI_H_ */
diff --git a/drivers/net/chelsio/gmac.h b/drivers/net/chelsio/gmac.h
new file mode 100644 (file)
index 0000000..746b0ee
--- /dev/null
@@ -0,0 +1,134 @@
+/*****************************************************************************
+ *                                                                           *
+ * File: gmac.h                                                              *
+ * $Revision: 1.6 $                                                          *
+ * $Date: 2005/06/21 18:29:47 $                                              *
+ * Description:                                                              *
+ *  Generic MAC functionality.                                               *
+ *  part of the Chelsio 10Gb Ethernet Driver.                                *
+ *                                                                           *
+ * This program is free software; you can redistribute it and/or modify      *
+ * it under the terms of the GNU General Public License, version 2, as       *
+ * published by the Free Software Foundation.                                *
+ *                                                                           *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED    *
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF      *
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.                     *
+ *                                                                           *
+ * http://www.chelsio.com                                                    *
+ *                                                                           *
+ * Copyright (c) 2003 - 2005 Chelsio Communications, Inc.                    *
+ * All rights reserved.                                                      *
+ *                                                                           *
+ * Maintainers: maintainers@chelsio.com                                      *
+ *                                                                           *
+ * Authors: Dimitrios Michailidis   <dm@chelsio.com>                         *
+ *          Tina Yang               <tainay@chelsio.com>                     *
+ *          Felix Marti             <felix@chelsio.com>                      *
+ *          Scott Bardone           <sbardone@chelsio.com>                   *
+ *          Kurt Ottaway            <kottaway@chelsio.com>                   *
+ *          Frank DiMambro          <frank@chelsio.com>                      *
+ *                                                                           *
+ * History:                                                                  *
+ *                                                                           *
+ ****************************************************************************/
+
+#ifndef _CXGB_GMAC_H_
+#define _CXGB_GMAC_H_
+
+#include "common.h"
+
+enum { MAC_STATS_UPDATE_FAST, MAC_STATS_UPDATE_FULL };
+enum { MAC_DIRECTION_RX = 1, MAC_DIRECTION_TX = 2 };
+
+struct cmac_statistics {
+       /* Transmit */
+       u64 TxOctetsOK;
+       u64 TxOctetsBad;
+       u64 TxUnicastFramesOK;
+       u64 TxMulticastFramesOK;
+       u64 TxBroadcastFramesOK;
+       u64 TxPauseFrames;
+       u64 TxFramesWithDeferredXmissions;
+       u64 TxLateCollisions;
+       u64 TxTotalCollisions;
+       u64 TxFramesAbortedDueToXSCollisions;
+       u64 TxUnderrun;
+       u64 TxLengthErrors;
+       u64 TxInternalMACXmitError;
+       u64 TxFramesWithExcessiveDeferral;
+       u64 TxFCSErrors;
+
+       /* Receive */
+       u64 RxOctetsOK;
+       u64 RxOctetsBad;
+       u64 RxUnicastFramesOK;
+       u64 RxMulticastFramesOK;
+       u64 RxBroadcastFramesOK;
+       u64 RxPauseFrames;
+       u64 RxFCSErrors;
+       u64 RxAlignErrors;
+       u64 RxSymbolErrors;
+       u64 RxDataErrors;
+       u64 RxSequenceErrors;
+       u64 RxRuntErrors;
+       u64 RxJabberErrors;
+       u64 RxInternalMACRcvError;
+       u64 RxInRangeLengthErrors;
+       u64 RxOutOfRangeLengthField;
+       u64 RxFrameTooLongErrors;
+};
+
+struct cmac_ops {
+       void (*destroy)(struct cmac *);
+       int (*reset)(struct cmac *);
+       int (*interrupt_enable)(struct cmac *);
+       int (*interrupt_disable)(struct cmac *);
+       int (*interrupt_clear)(struct cmac *);
+       int (*interrupt_handler)(struct cmac *);
+
+       int (*enable)(struct cmac *, int);
+       int (*disable)(struct cmac *, int);
+
+       int (*loopback_enable)(struct cmac *);
+       int (*loopback_disable)(struct cmac *);
+
+       int (*set_mtu)(struct cmac *, int mtu);
+       int (*set_rx_mode)(struct cmac *, struct t1_rx_mode *rm);
+
+       int (*set_speed_duplex_fc)(struct cmac *, int speed, int duplex, int fc);
+       int (*get_speed_duplex_fc)(struct cmac *, int *speed, int *duplex,
+                                  int *fc);
+
+       const struct cmac_statistics *(*statistics_update)(struct cmac *, int);
+
+       int (*macaddress_get)(struct cmac *, u8 mac_addr[6]);
+       int (*macaddress_set)(struct cmac *, u8 mac_addr[6]);
+};
+
+typedef struct _cmac_instance cmac_instance;
+
+struct cmac {
+       struct cmac_statistics stats;
+       adapter_t *adapter;
+       struct cmac_ops *ops;
+       cmac_instance *instance;
+};
+
+struct gmac {
+       unsigned int stats_update_period;
+       struct cmac *(*create)(adapter_t *adapter, int index);
+       int (*reset)(adapter_t *);
+};
+
+extern struct gmac t1_pm3393_ops;
+extern struct gmac t1_chelsio_mac_ops;
+extern struct gmac t1_vsc7321_ops;
+extern struct gmac t1_ixf1010_ops;
+extern struct gmac t1_dummy_mac_ops;
+
+#endif /* _CXGB_GMAC_H_ */
diff --git a/drivers/net/chelsio/mv88x201x.c b/drivers/net/chelsio/mv88x201x.c
new file mode 100644 (file)
index 0000000..db50342
--- /dev/null
@@ -0,0 +1,252 @@
+/*****************************************************************************
+ *                                                                           *
+ * File: mv88x201x.c                                                         *
+ * $Revision: 1.12 $                                                         *
+ * $Date: 2005/04/15 19:27:14 $                                              *
+ * Description:                                                              *
+ *  Marvell PHY (mv88x201x) functionality.                                   *
+ *  part of the Chelsio 10Gb Ethernet Driver.                                *
+ *                                                                           *
+ * This program is free software; you can redistribute it and/or modify      *
+ * it under the terms of the GNU General Public License, version 2, as       *
+ * published by the Free Software Foundation.                                *
+ *                                                                           *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED    *
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF      *
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.                     *
+ *                                                                           *
+ * http://www.chelsio.com                                                    *
+ *                                                                           *
+ * Copyright (c) 2003 - 2005 Chelsio Communications, Inc.                    *
+ * All rights reserved.                                                      *
+ *                                                                           *
+ * Maintainers: maintainers@chelsio.com                                      *
+ *                                                                           *
+ * Authors: Dimitrios Michailidis   <dm@chelsio.com>                         *
+ *          Tina Yang               <tainay@chelsio.com>                     *
+ *          Felix Marti             <felix@chelsio.com>                      *
+ *          Scott Bardone           <sbardone@chelsio.com>                   *
+ *          Kurt Ottaway            <kottaway@chelsio.com>                   *
+ *          Frank DiMambro          <frank@chelsio.com>                      *
+ *                                                                           *
+ * History:                                                                  *
+ *                                                                           *
+ ****************************************************************************/
+
+#include "cphy.h"
+#include "elmer0.h"
+
+/*
+ * The 88x2010 Rev C. requires some link status registers * to be read
+ * twice in order to get the right values. Future * revisions will fix
+ * this problem and then this macro * can disappear.
+ */
+#define MV88x2010_LINK_STATUS_BUGS    1
+
+static int led_init(struct cphy *cphy)
+{
+       /* Setup the LED registers so we can turn on/off.
+        * Writing these bits maps control to another
+        * register. mmd(0x1) addr(0x7)
+        */
+       mdio_write(cphy, 0x3, 0x8304, 0xdddd);
+       return 0;
+}
+
+static int led_link(struct cphy *cphy, u32 do_enable)
+{
+       u32 led = 0;
+#define LINK_ENABLE_BIT 0x1
+
+       mdio_read(cphy, 0x1, 0x7, &led);
+
+       if (do_enable & LINK_ENABLE_BIT) {
+               led |= LINK_ENABLE_BIT;
+               mdio_write(cphy, 0x1, 0x7, led);
+       } else {
+               led &= ~LINK_ENABLE_BIT;
+               mdio_write(cphy, 0x1, 0x7, led);
+       }
+       return 0;
+}
+
+/* Port Reset */
+static int mv88x201x_reset(struct cphy *cphy, int wait)
+{
+       /* This can be done through registers.  It is not required since
+        * a full chip reset is used.
+        */
+       return 0;
+}
+
+static int mv88x201x_interrupt_enable(struct cphy *cphy)
+{
+       u32 elmer;
+
+       /* Enable PHY LASI interrupts. */
+       mdio_write(cphy, 0x1, 0x9002, 0x1);
+
+       /* Enable Marvell interrupts through Elmer0. */
+       t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
+       elmer |= ELMER0_GP_BIT6;
+       t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
+       return 0;
+}
+
+static int mv88x201x_interrupt_disable(struct cphy *cphy)
+{
+       u32 elmer;
+
+       /* Disable PHY LASI interrupts. */
+       mdio_write(cphy, 0x1, 0x9002, 0x0);
+
+       /* Disable Marvell interrupts through Elmer0. */
+       t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
+       elmer &= ~ELMER0_GP_BIT6;
+       t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
+       return 0;
+}
+
+static int mv88x201x_interrupt_clear(struct cphy *cphy)
+{
+       u32 elmer;
+       u32 val;
+
+#ifdef MV88x2010_LINK_STATUS_BUGS
+       /* Required to read twice before clear takes affect. */
+       mdio_read(cphy, 0x1, 0x9003, &val);
+       mdio_read(cphy, 0x1, 0x9004, &val);
+       mdio_read(cphy, 0x1, 0x9005, &val);
+
+       /* Read this register after the others above it else
+        * the register doesn't clear correctly.
+        */
+       mdio_read(cphy, 0x1, 0x1, &val);
+#endif
+
+       /* Clear link status. */
+       mdio_read(cphy, 0x1, 0x1, &val);
+       /* Clear PHY LASI interrupts. */
+       mdio_read(cphy, 0x1, 0x9005, &val);
+
+#ifdef MV88x2010_LINK_STATUS_BUGS
+       /* Do it again. */
+       mdio_read(cphy, 0x1, 0x9003, &val);
+       mdio_read(cphy, 0x1, 0x9004, &val);
+#endif
+
+       /* Clear Marvell interrupts through Elmer0. */
+       t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
+       elmer |= ELMER0_GP_BIT6;
+       t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
+       return 0;
+}
+
+static int mv88x201x_interrupt_handler(struct cphy *cphy)
+{
+       /* Clear interrupts */
+       mv88x201x_interrupt_clear(cphy);
+
+       /* We have only enabled link change interrupts and so
+        * cphy_cause must be a link change interrupt.
+        */
+       return cphy_cause_link_change;
+}
+
+static int mv88x201x_set_loopback(struct cphy *cphy, int on)
+{
+       return 0;
+}
+
+static int mv88x201x_get_link_status(struct cphy *cphy, int *link_ok,
+                                    int *speed, int *duplex, int *fc)
+{
+       u32 val = 0;
+#define LINK_STATUS_BIT 0x4
+
+       if (link_ok) {
+               /* Read link status. */
+               mdio_read(cphy, 0x1, 0x1, &val);
+               val &= LINK_STATUS_BIT;
+               *link_ok = (val == LINK_STATUS_BIT);
+               /* Turn on/off Link LED */
+               led_link(cphy, *link_ok);
+       }
+       if (speed)
+               *speed = SPEED_10000;
+       if (duplex)
+               *duplex = DUPLEX_FULL;
+       if (fc)
+               *fc = PAUSE_RX | PAUSE_TX;
+       return 0;
+}
+
+static void mv88x201x_destroy(struct cphy *cphy)
+{
+       kfree(cphy);
+}
+
+static struct cphy_ops mv88x201x_ops = {
+       .destroy           = mv88x201x_destroy,
+       .reset             = mv88x201x_reset,
+       .interrupt_enable  = mv88x201x_interrupt_enable,
+       .interrupt_disable = mv88x201x_interrupt_disable,
+       .interrupt_clear   = mv88x201x_interrupt_clear,
+       .interrupt_handler = mv88x201x_interrupt_handler,
+       .get_link_status   = mv88x201x_get_link_status,
+       .set_loopback      = mv88x201x_set_loopback,
+};
+
+static struct cphy *mv88x201x_phy_create(adapter_t *adapter, int phy_addr,
+                                        struct mdio_ops *mdio_ops)
+{
+       u32 val;
+       struct cphy *cphy = kmalloc(sizeof(*cphy), GFP_KERNEL);
+
+       if (!cphy)
+               return NULL;
+       memset(cphy, 0, sizeof(*cphy));
+       cphy_init(cphy, adapter, phy_addr, &mv88x201x_ops, mdio_ops);
+
+       /* Commands the PHY to enable XFP's clock. */
+       mdio_read(cphy, 0x3, 0x8300, &val);
+       mdio_write(cphy, 0x3, 0x8300, val | 1);
+
+       /* Clear link status. Required because of a bug in the PHY.  */
+       mdio_read(cphy, 0x1, 0x8, &val);
+       mdio_read(cphy, 0x3, 0x8, &val);
+
+       /* Allows for Link,Ack LED turn on/off */
+       led_init(cphy);
+       return cphy;
+}
+
+/* Chip Reset */
+static int mv88x201x_phy_reset(adapter_t *adapter)
+{
+       u32 val;
+
+       t1_tpi_read(adapter, A_ELMER0_GPO, &val);
+       val &= ~4;
+       t1_tpi_write(adapter, A_ELMER0_GPO, val);
+       msleep(100);
+
+       t1_tpi_write(adapter, A_ELMER0_GPO, val | 4);
+       msleep(1000);
+
+       /* Now lets enable the Laser. Delay 100us */
+       t1_tpi_read(adapter, A_ELMER0_GPO, &val);
+       val |= 0x8000;
+       t1_tpi_write(adapter, A_ELMER0_GPO, val);
+       udelay(100);
+       return 0;
+}
+
+struct gphy t1_mv88x201x_ops = {
+       mv88x201x_phy_create,
+       mv88x201x_phy_reset
+};
diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/chelsio/pm3393.c
new file mode 100644 (file)
index 0000000..04a1404
--- /dev/null
@@ -0,0 +1,826 @@
+/*****************************************************************************
+ *                                                                           *
+ * File: pm3393.c                                                            *
+ * $Revision: 1.16 $                                                         *
+ * $Date: 2005/05/14 00:59:32 $                                              *
+ * Description:                                                              *
+ *  PMC/SIERRA (pm3393) MAC-PHY functionality.                               *
+ *  part of the Chelsio 10Gb Ethernet Driver.                                *
+ *                                                                           *
+ * This program is free software; you can redistribute it and/or modify      *
+ * it under the terms of the GNU General Public License, version 2, as       *
+ * published by the Free Software Foundation.                                *
+ *                                                                           *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED    *
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF      *
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.                     *
+ *                                                                           *
+ * http://www.chelsio.com                                                    *
+ *                                                                           *
+ * Copyright (c) 2003 - 2005 Chelsio Communications, Inc.                    *
+ * All rights reserved.                                                      *
+ *                                                                           *
+ * Maintainers: maintainers@chelsio.com                                      *
+ *                                                                           *
+ * Authors: Dimitrios Michailidis   <dm@chelsio.com>                         *
+ *          Tina Yang               <tainay@chelsio.com>                     *
+ *          Felix Marti             <felix@chelsio.com>                      *
+ *          Scott Bardone           <sbardone@chelsio.com>                   *
+ *          Kurt Ottaway            <kottaway@chelsio.com>                   *
+ *          Frank DiMambro          <frank@chelsio.com>                      *
+ *                                                                           *
+ * History:                                                                  *
+ *                                                                           *
+ ****************************************************************************/
+
+#include "common.h"
+#include "regs.h"
+#include "gmac.h"
+#include "elmer0.h"
+#include "suni1x10gexp_regs.h"
+
+/* 802.3ae 10Gb/s MDIO Manageable Device(MMD)
+ */
+enum {
+    MMD_RESERVED,
+    MMD_PMAPMD,
+    MMD_WIS,
+    MMD_PCS,
+    MMD_PHY_XGXS,      /* XGMII Extender Sublayer */
+    MMD_DTE_XGXS,
+};
+
+enum {
+    PHY_XGXS_CTRL_1,
+    PHY_XGXS_STATUS_1
+};
+
+#define OFFSET(REG_ADDR)    (REG_ADDR << 2)
+
+/* Max frame size PM3393 can handle. Includes Ethernet header and CRC. */
+#define MAX_FRAME_SIZE  9600
+
+#define IPG 12
+#define TXXG_CONF1_VAL ((IPG << SUNI1x10GEXP_BITOFF_TXXG_IPGT) | \
+       SUNI1x10GEXP_BITMSK_TXXG_32BIT_ALIGN | SUNI1x10GEXP_BITMSK_TXXG_CRCEN | \
+       SUNI1x10GEXP_BITMSK_TXXG_PADEN)
+#define RXXG_CONF1_VAL (SUNI1x10GEXP_BITMSK_RXXG_PUREP | 0x14 | \
+       SUNI1x10GEXP_BITMSK_RXXG_FLCHK | SUNI1x10GEXP_BITMSK_RXXG_CRC_STRIP)
+
+/* Update statistics every 15 minutes */
+#define STATS_TICK_SECS (15 * 60)
+
+enum {                     /* RMON registers */
+       RxOctetsReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_1_LOW,
+       RxUnicastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_4_LOW,
+       RxMulticastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_5_LOW,
+       RxBroadcastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_6_LOW,
+       RxPAUSEMACCtrlFramesReceived = SUNI1x10GEXP_REG_MSTAT_COUNTER_8_LOW,
+       RxFrameCheckSequenceErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_10_LOW,
+       RxFramesLostDueToInternalMACErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_11_LOW,
+       RxSymbolErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_12_LOW,
+       RxInRangeLengthErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_13_LOW,
+       RxFramesTooLongErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_15_LOW,
+       RxJabbers = SUNI1x10GEXP_REG_MSTAT_COUNTER_16_LOW,
+       RxFragments = SUNI1x10GEXP_REG_MSTAT_COUNTER_17_LOW,
+       RxUndersizedFrames =  SUNI1x10GEXP_REG_MSTAT_COUNTER_18_LOW,
+
+       TxOctetsTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_33_LOW,
+       TxFramesLostDueToInternalMACTransmissionError = SUNI1x10GEXP_REG_MSTAT_COUNTER_35_LOW,
+       TxTransmitSystemError = SUNI1x10GEXP_REG_MSTAT_COUNTER_36_LOW,
+       TxUnicastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_38_LOW,
+       TxMulticastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_40_LOW,
+       TxBroadcastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_42_LOW,
+       TxPAUSEMACCtrlFramesTransmitted = SUNI1x10GEXP_REG_MSTAT_COUNTER_43_LOW
+};
+
+struct _cmac_instance {
+       u8 enabled;
+       u8 fc;
+       u8 mac_addr[6];
+};
+
+static int pmread(struct cmac *cmac, u32 reg, u32 * data32)
+{
+       t1_tpi_read(cmac->adapter, OFFSET(reg), data32);
+       return 0;
+}
+
+static int pmwrite(struct cmac *cmac, u32 reg, u32 data32)
+{
+       t1_tpi_write(cmac->adapter, OFFSET(reg), data32);
+       return 0;
+}
+
+/* Port reset. */
+static int pm3393_reset(struct cmac *cmac)
+{
+       return 0;
+}
+
+/*
+ * Enable interrupts for the PM3393
+
+       1. Enable PM3393 BLOCK interrupts.
+       2. Enable PM3393 Master Interrupt bit(INTE)
+       3. Enable ELMER's PM3393 bit.
+       4. Enable Terminator external interrupt.
+*/
+static int pm3393_interrupt_enable(struct cmac *cmac)
+{
+       u32 pl_intr;
+
+       /* PM3393 - Enabling all hardware block interrupts.
+        */
+       pmwrite(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE, 0xffff);
+       pmwrite(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE, 0xffff);
+       pmwrite(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE, 0xffff);
+       pmwrite(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE, 0xffff);
+
+       /* Don't interrupt on statistics overflow, we are polling */
+       pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3, 0);
+
+       pmwrite(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE, 0xffff);
+       pmwrite(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK, 0xffff);
+       pmwrite(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE, 0xffff);
+       pmwrite(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE, 0xffff);
+       pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_3, 0xffff);
+       pmwrite(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK, 0xffff);
+       pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_3, 0xffff);
+       pmwrite(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK, 0xffff);
+       pmwrite(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE, 0xffff);
+
+       /* PM3393 - Global interrupt enable
+        */
+       /* TBD XXX Disable for now until we figure out why error interrupts keep asserting. */
+       pmwrite(cmac, SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE,
+               0 /*SUNI1x10GEXP_BITMSK_TOP_INTE */ );
+
+       /* TERMINATOR - PL_INTERUPTS_EXT */
+       pl_intr = readl(cmac->adapter->regs + A_PL_ENABLE);
+       pl_intr |= F_PL_INTR_EXT;
+       writel(pl_intr, cmac->adapter->regs + A_PL_ENABLE);
+       return 0;
+}
+
+static int pm3393_interrupt_disable(struct cmac *cmac)
+{
+       u32 elmer;
+
+       /* PM3393 - Enabling HW interrupt blocks. */
+       pmwrite(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_3, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_3, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK, 0);
+       pmwrite(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE, 0);
+
+       /* PM3393 - Global interrupt enable */
+       pmwrite(cmac, SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE, 0);
+
+       /* ELMER - External chip interrupts. */
+       t1_tpi_read(cmac->adapter, A_ELMER0_INT_ENABLE, &elmer);
+       elmer &= ~ELMER0_GP_BIT1;
+       t1_tpi_write(cmac->adapter, A_ELMER0_INT_ENABLE, elmer);
+
+       /* TERMINATOR - PL_INTERUPTS_EXT */
+       /* DO NOT DISABLE TERMINATOR's EXTERNAL INTERRUPTS. ANOTHER CHIP
+        * COULD WANT THEM ENABLED. We disable PM3393 at the ELMER level.
+        */
+
+       return 0;
+}
+
+static int pm3393_interrupt_clear(struct cmac *cmac)
+{
+       u32 elmer;
+       u32 pl_intr;
+       u32 val32;
+
+       /* PM3393 - Clearing HW interrupt blocks. Note, this assumes
+        *          bit WCIMODE=0 for a clear-on-read.
+        */
+       pmread(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_STATUS, &val32);
+       pmread(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_STATUS, &val32);
+       pmread(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_STATUS, &val32);
+       pmread(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_STATUS, &val32);
+       pmread(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT, &val32);
+       pmread(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_STATUS, &val32);
+       pmread(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_INTERRUPT, &val32);
+       pmread(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_STATUS, &val32);
+       pmread(cmac, SUNI1x10GEXP_REG_RXXG_INTERRUPT, &val32);
+       pmread(cmac, SUNI1x10GEXP_REG_TXXG_INTERRUPT, &val32);
+       pmread(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT, &val32);
+       pmread(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_INDICATION,
+              &val32);
+       pmread(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_STATUS, &val32);
+       pmread(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_CHANGE, &val32);
+
+       /* PM3393 - Global interrupt status
+        */
+       pmread(cmac, SUNI1x10GEXP_REG_MASTER_INTERRUPT_STATUS, &val32);
+
+       /* ELMER - External chip interrupts.
+        */
+       t1_tpi_read(cmac->adapter, A_ELMER0_INT_CAUSE, &elmer);
+       elmer |= ELMER0_GP_BIT1;
+       t1_tpi_write(cmac->adapter, A_ELMER0_INT_CAUSE, elmer);
+
+       /* TERMINATOR - PL_INTERUPTS_EXT
+        */
+       pl_intr = readl(cmac->adapter->regs + A_PL_CAUSE);
+       pl_intr |= F_PL_INTR_EXT;
+       writel(pl_intr, cmac->adapter->regs + A_PL_CAUSE);
+
+       return 0;
+}
+
+/* Interrupt handler */
+static int pm3393_interrupt_handler(struct cmac *cmac)
+{
+       u32 master_intr_status;
+/*
+       1. Read master interrupt register.
+       2. Read BLOCK's interrupt status registers.
+       3. Handle BLOCK interrupts.
+*/
+       /* Read the master interrupt status register. */
+       pmread(cmac, SUNI1x10GEXP_REG_MASTER_INTERRUPT_STATUS,
+              &master_intr_status);
+
+       /* TBD XXX Lets just clear everything for now */
+       pm3393_interrupt_clear(cmac);
+
+       return 0;
+}
+
+static int pm3393_enable(struct cmac *cmac, int which)
+{
+       if (which & MAC_DIRECTION_RX)
+               pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_1,
+                       (RXXG_CONF1_VAL | SUNI1x10GEXP_BITMSK_RXXG_RXEN));
+
+       if (which & MAC_DIRECTION_TX) {
+               u32 val = TXXG_CONF1_VAL | SUNI1x10GEXP_BITMSK_TXXG_TXEN0;
+
+               if (cmac->instance->fc & PAUSE_RX)
+                       val |= SUNI1x10GEXP_BITMSK_TXXG_FCRX;
+               if (cmac->instance->fc & PAUSE_TX)
+                       val |= SUNI1x10GEXP_BITMSK_TXXG_FCTX;
+               pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_1, val);
+       }
+
+       cmac->instance->enabled |= which;
+       return 0;
+}
+
+static int pm3393_enable_port(struct cmac *cmac, int which)
+{
+       /* Clear port statistics */
+       pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_CONTROL,
+               SUNI1x10GEXP_BITMSK_MSTAT_CLEAR);
+       udelay(2);
+       memset(&cmac->stats, 0, sizeof(struct cmac_statistics));
+
+       pm3393_enable(cmac, which);
+
+       /*
+        * XXX This should be done by the PHY and preferrably not at all.
+        * The PHY doesn't give us link status indication on its own so have
+        * the link management code query it instead.
+        */
+       {
+               extern void link_changed(adapter_t *adapter, int port_id);
+
+               link_changed(cmac->adapter, 0);
+       }
+       return 0;
+}
+
+static int pm3393_disable(struct cmac *cmac, int which)
+{
+       if (which & MAC_DIRECTION_RX)
+               pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_1, RXXG_CONF1_VAL);
+       if (which & MAC_DIRECTION_TX)
+               pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_1, TXXG_CONF1_VAL);
+
+       /*
+        * The disable is graceful. Give the PM3393 time.  Can't wait very
+        * long here, we may be holding locks.
+        */
+       udelay(20);
+
+       cmac->instance->enabled &= ~which;
+       return 0;
+}
+
+static int pm3393_loopback_enable(struct cmac *cmac)
+{
+       return 0;
+}
+
+static int pm3393_loopback_disable(struct cmac *cmac)
+{
+       return 0;
+}
+
+static int pm3393_set_mtu(struct cmac *cmac, int mtu)
+{
+       int enabled = cmac->instance->enabled;
+
+       /* MAX_FRAME_SIZE includes header + FCS, mtu doesn't */
+       mtu += 14 + 4;
+       if (mtu > MAX_FRAME_SIZE)
+               return -EINVAL;
+
+       /* Disable Rx/Tx MAC before configuring it. */
+       if (enabled)
+               pm3393_disable(cmac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
+
+       pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MAX_FRAME_LENGTH, mtu);
+       pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_MAX_FRAME_SIZE, mtu);
+
+       if (enabled)
+               pm3393_enable(cmac, enabled);
+       return 0;
+}
+
+static u32 calc_crc(u8 *b, int len)
+{
+       int i;
+       u32 crc = (u32)~0;
+
+       /* calculate crc one bit at a time */
+       while (len--) {
+               crc ^= *b++;
+               for (i = 0; i < 8; i++) {
+                       if (crc & 0x1)
+                               crc = (crc >> 1) ^ 0xedb88320;
+                       else
+                               crc = (crc >> 1);
+               }
+       }
+
+       /* reverse bits */
+       crc = ((crc >> 4) & 0x0f0f0f0f) | ((crc << 4) & 0xf0f0f0f0);
+       crc = ((crc >> 2) & 0x33333333) | ((crc << 2) & 0xcccccccc);
+       crc = ((crc >> 1) & 0x55555555) | ((crc << 1) & 0xaaaaaaaa);
+       /* swap bytes */
+       crc = (crc >> 16) | (crc << 16);
+       crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
+
+       return crc;
+}
+
+static int pm3393_set_rx_mode(struct cmac *cmac, struct t1_rx_mode *rm)
+{
+       int enabled = cmac->instance->enabled & MAC_DIRECTION_RX;
+       u32 rx_mode;
+
+       /* Disable MAC RX before reconfiguring it */
+       if (enabled)
+               pm3393_disable(cmac, MAC_DIRECTION_RX);
+
+       pmread(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, &rx_mode);
+       rx_mode &= ~(SUNI1x10GEXP_BITMSK_RXXG_PMODE |
+                    SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN);
+       pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2,
+               (u16)rx_mode);
+
+       if (t1_rx_mode_promisc(rm)) {
+               /* Promiscuous mode. */
+               rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_PMODE;
+       }
+       if (t1_rx_mode_allmulti(rm)) {
+               /* Accept all multicast. */
+               pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW, 0xffff);
+               pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDLOW, 0xffff);
+               pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDHIGH, 0xffff);
+               pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_HIGH, 0xffff);
+               rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN;
+       } else if (t1_rx_mode_mc_cnt(rm)) {
+               /* Accept one or more multicast(s). */
+               u8 *addr;
+               int bit;
+               u16 mc_filter[4] = { 0, };
+
+               while ((addr = t1_get_next_mcaddr(rm))) {
+                       bit = (calc_crc(addr, ETH_ALEN) >> 23) & 0x3f;  /* bit[23:28] */
+                       mc_filter[bit >> 4] |= 1 << (bit & 0xf);
+               }
+               pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW, mc_filter[0]);
+               pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDLOW, mc_filter[1]);
+               pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDHIGH, mc_filter[2]);
+               pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_HIGH, mc_filter[3]);
+               rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN;
+       }
+
+       pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, (u16)rx_mode);
+
+       if (enabled)
+               pm3393_enable(cmac, MAC_DIRECTION_RX);
+
+       return 0;
+}
+
+static int pm3393_get_speed_duplex_fc(struct cmac *cmac, int *speed,
+                                     int *duplex, int *fc)
+{
+       if (speed)
+               *speed = SPEED_10000;
+       if (duplex)
+               *duplex = DUPLEX_FULL;
+       if (fc)
+               *fc = cmac->instance->fc;
+       return 0;
+}
+
+static int pm3393_set_speed_duplex_fc(struct cmac *cmac, int speed, int duplex,
+                                     int fc)
+{
+       if (speed >= 0 && speed != SPEED_10000)
+               return -1;
+       if (duplex >= 0 && duplex != DUPLEX_FULL)
+               return -1;
+       if (fc & ~(PAUSE_TX | PAUSE_RX))
+               return -1;
+
+       if (fc != cmac->instance->fc) {
+               cmac->instance->fc = (u8) fc;
+               if (cmac->instance->enabled & MAC_DIRECTION_TX)
+                       pm3393_enable(cmac, MAC_DIRECTION_TX);
+       }
+       return 0;
+}
+
+#define RMON_UPDATE(mac, name, stat_name) \
+       { \
+               t1_tpi_read((mac)->adapter, OFFSET(name), &val0);       \
+               t1_tpi_read((mac)->adapter, OFFSET(((name)+1)), &val1); \
+               t1_tpi_read((mac)->adapter, OFFSET(((name)+2)), &val2); \
+               (mac)->stats.stat_name = ((u64)val0 & 0xffff) | \
+                                               (((u64)val1 & 0xffff) << 16) | \
+                                               (((u64)val2 & 0xff) << 32) | \
+                                               ((mac)->stats.stat_name & \
+                                                       (~(u64)0 << 40)); \
+               if (ro &        \
+                       ((name -  SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW) >> 2)) \
+                       (mac)->stats.stat_name += ((u64)1 << 40); \
+       }
+
+static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac,
+                                                             int flag)
+{
+       u64     ro;
+       u32     val0, val1, val2, val3;
+
+       /* Snap the counters */
+       pmwrite(mac, SUNI1x10GEXP_REG_MSTAT_CONTROL,
+               SUNI1x10GEXP_BITMSK_MSTAT_SNAP);
+
+       /* Counter rollover, clear on read */
+       pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_0, &val0);
+       pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_1, &val1);
+       pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_2, &val2);
+       pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_3, &val3);
+       ro = ((u64)val0 & 0xffff) | (((u64)val1 & 0xffff) << 16) |
+               (((u64)val2 & 0xffff) << 32) | (((u64)val3 & 0xffff) << 48);
+
+       /* Rx stats */
+       RMON_UPDATE(mac, RxOctetsReceivedOK, RxOctetsOK);
+       RMON_UPDATE(mac, RxUnicastFramesReceivedOK, RxUnicastFramesOK);
+       RMON_UPDATE(mac, RxMulticastFramesReceivedOK, RxMulticastFramesOK);
+       RMON_UPDATE(mac, RxBroadcastFramesReceivedOK, RxBroadcastFramesOK);
+       RMON_UPDATE(mac, RxPAUSEMACCtrlFramesReceived, RxPauseFrames);
+       RMON_UPDATE(mac, RxFrameCheckSequenceErrors, RxFCSErrors);
+       RMON_UPDATE(mac, RxFramesLostDueToInternalMACErrors,
+                               RxInternalMACRcvError);
+       RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors);
+       RMON_UPDATE(mac, RxInRangeLengthErrors, RxInRangeLengthErrors);
+       RMON_UPDATE(mac, RxFramesTooLongErrors , RxFrameTooLongErrors);
+       RMON_UPDATE(mac, RxJabbers, RxJabberErrors);
+       RMON_UPDATE(mac, RxFragments, RxRuntErrors);
+       RMON_UPDATE(mac, RxUndersizedFrames, RxRuntErrors);
+
+       /* Tx stats */
+       RMON_UPDATE(mac, TxOctetsTransmittedOK, TxOctetsOK);
+       RMON_UPDATE(mac, TxFramesLostDueToInternalMACTransmissionError,
+                               TxInternalMACXmitError);
+       RMON_UPDATE(mac, TxTransmitSystemError, TxFCSErrors);
+       RMON_UPDATE(mac, TxUnicastFramesTransmittedOK, TxUnicastFramesOK);
+       RMON_UPDATE(mac, TxMulticastFramesTransmittedOK, TxMulticastFramesOK);
+       RMON_UPDATE(mac, TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK);
+       RMON_UPDATE(mac, TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames);
+
+       return &mac->stats;
+}
+
+static int pm3393_macaddress_get(struct cmac *cmac, u8 mac_addr[6])
+{
+       memcpy(mac_addr, cmac->instance->mac_addr, 6);
+       return 0;
+}
+
+static int pm3393_macaddress_set(struct cmac *cmac, u8 ma[6])
+{
+       u32 val, lo, mid, hi, enabled = cmac->instance->enabled;
+
+       /*
+        * MAC addr: 00:07:43:00:13:09
+        *
+        * ma[5] = 0x09
+        * ma[4] = 0x13
+        * ma[3] = 0x00
+        * ma[2] = 0x43
+        * ma[1] = 0x07
+        * ma[0] = 0x00
+        *
+        * The PM3393 requires byte swapping and reverse order entry
+        * when programming MAC addresses:
+        *
+        * low_bits[15:0]    = ma[1]:ma[0]
+        * mid_bits[31:16]   = ma[3]:ma[2]
+        * high_bits[47:32]  = ma[5]:ma[4]
+        */
+
+       /* Store local copy */
+       memcpy(cmac->instance->mac_addr, ma, 6);
+
+       lo = ((u32) ma[1] << 8) | (u32) ma[0];
+       mid = ((u32) ma[3] << 8) | (u32) ma[2];
+       hi = ((u32) ma[5] << 8) | (u32) ma[4];
+
+       /* Disable Rx/Tx MAC before configuring it. */
+       if (enabled)
+               pm3393_disable(cmac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
+
+       /* Set RXXG Station Address */
+       pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_SA_15_0, lo);
+       pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_SA_31_16, mid);
+       pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_SA_47_32, hi);
+
+       /* Set TXXG Station Address */
+       pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_SA_15_0, lo);
+       pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_SA_31_16, mid);
+       pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_SA_47_32, hi);
+
+       /* Setup Exact Match Filter 1 with our MAC address
+        *
+        * Must disable exact match filter before configuring it.
+        */
+       pmread(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0, &val);
+       val &= 0xff0f;
+       pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0, val);
+
+       pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_LOW, lo);
+       pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_MID, mid);
+       pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_HIGH, hi);
+
+       val |= 0x0090;
+       pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0, val);
+
+       if (enabled)
+               pm3393_enable(cmac, enabled);
+       return 0;
+}
+
+static void pm3393_destroy(struct cmac *cmac)
+{
+       kfree(cmac);
+}
+
+static struct cmac_ops pm3393_ops = {
+       .destroy                 = pm3393_destroy,
+       .reset                   = pm3393_reset,
+       .interrupt_enable        = pm3393_interrupt_enable,
+       .interrupt_disable       = pm3393_interrupt_disable,
+       .interrupt_clear         = pm3393_interrupt_clear,
+       .interrupt_handler       = pm3393_interrupt_handler,
+       .enable                  = pm3393_enable_port,
+       .disable                 = pm3393_disable,
+       .loopback_enable         = pm3393_loopback_enable,
+       .loopback_disable        = pm3393_loopback_disable,
+       .set_mtu                 = pm3393_set_mtu,
+       .set_rx_mode             = pm3393_set_rx_mode,
+       .get_speed_duplex_fc     = pm3393_get_speed_duplex_fc,
+       .set_speed_duplex_fc     = pm3393_set_speed_duplex_fc,
+       .statistics_update       = pm3393_update_statistics,
+       .macaddress_get          = pm3393_macaddress_get,
+       .macaddress_set          = pm3393_macaddress_set
+};
+
+static struct cmac *pm3393_mac_create(adapter_t *adapter, int index)
+{
+       struct cmac *cmac;
+
+       cmac = kmalloc(sizeof(*cmac) + sizeof(cmac_instance), GFP_KERNEL);
+       if (!cmac)
+               return NULL;
+       memset(cmac, 0, sizeof(*cmac));
+
+       cmac->ops = &pm3393_ops;
+       cmac->instance = (cmac_instance *) (cmac + 1);
+       cmac->adapter = adapter;
+       cmac->instance->fc = PAUSE_TX | PAUSE_RX;
+
+       t1_tpi_write(adapter, OFFSET(0x0001), 0x00008000);
+       t1_tpi_write(adapter, OFFSET(0x0001), 0x00000000);
+       t1_tpi_write(adapter, OFFSET(0x2308), 0x00009800);
+       t1_tpi_write(adapter, OFFSET(0x2305), 0x00001001);   /* PL4IO Enable */
+       t1_tpi_write(adapter, OFFSET(0x2320), 0x00008800);
+       t1_tpi_write(adapter, OFFSET(0x2321), 0x00008800);
+       t1_tpi_write(adapter, OFFSET(0x2322), 0x00008800);
+       t1_tpi_write(adapter, OFFSET(0x2323), 0x00008800);
+       t1_tpi_write(adapter, OFFSET(0x2324), 0x00008800);
+       t1_tpi_write(adapter, OFFSET(0x2325), 0x00008800);
+       t1_tpi_write(adapter, OFFSET(0x2326), 0x00008800);
+       t1_tpi_write(adapter, OFFSET(0x2327), 0x00008800);
+       t1_tpi_write(adapter, OFFSET(0x2328), 0x00008800);
+       t1_tpi_write(adapter, OFFSET(0x2329), 0x00008800);
+       t1_tpi_write(adapter, OFFSET(0x232a), 0x00008800);
+       t1_tpi_write(adapter, OFFSET(0x232b), 0x00008800);
+       t1_tpi_write(adapter, OFFSET(0x232c), 0x00008800);
+       t1_tpi_write(adapter, OFFSET(0x232d), 0x00008800);
+       t1_tpi_write(adapter, OFFSET(0x232e), 0x00008800);
+       t1_tpi_write(adapter, OFFSET(0x232f), 0x00008800);
+       t1_tpi_write(adapter, OFFSET(0x230d), 0x00009c00);
+       t1_tpi_write(adapter, OFFSET(0x2304), 0x00000202);      /* PL4IO Calendar Repetitions */
+
+       t1_tpi_write(adapter, OFFSET(0x3200), 0x00008080);      /* EFLX Enable */
+       t1_tpi_write(adapter, OFFSET(0x3210), 0x00000000);      /* EFLX Channel Deprovision */
+       t1_tpi_write(adapter, OFFSET(0x3203), 0x00000000);      /* EFLX Low Limit */
+       t1_tpi_write(adapter, OFFSET(0x3204), 0x00000040);      /* EFLX High Limit */
+       t1_tpi_write(adapter, OFFSET(0x3205), 0x000002cc);      /* EFLX Almost Full */
+       t1_tpi_write(adapter, OFFSET(0x3206), 0x00000199);      /* EFLX Almost Empty */
+       t1_tpi_write(adapter, OFFSET(0x3207), 0x00000240);      /* EFLX Cut Through Threshold */
+       t1_tpi_write(adapter, OFFSET(0x3202), 0x00000000);      /* EFLX Indirect Register Update */
+       t1_tpi_write(adapter, OFFSET(0x3210), 0x00000001);      /* EFLX Channel Provision */
+       t1_tpi_write(adapter, OFFSET(0x3208), 0x0000ffff);      /* EFLX Undocumented */
+       t1_tpi_write(adapter, OFFSET(0x320a), 0x0000ffff);      /* EFLX Undocumented */
+       t1_tpi_write(adapter, OFFSET(0x320c), 0x0000ffff);      /* EFLX enable overflow interrupt The other bit are undocumented */
+       t1_tpi_write(adapter, OFFSET(0x320e), 0x0000ffff);      /* EFLX Undocumented */
+
+       t1_tpi_write(adapter, OFFSET(0x2200), 0x0000c000);      /* IFLX Configuration - enable */
+       t1_tpi_write(adapter, OFFSET(0x2201), 0x00000000);      /* IFLX Channel Deprovision */
+       t1_tpi_write(adapter, OFFSET(0x220e), 0x00000000);      /* IFLX Low Limit */
+       t1_tpi_write(adapter, OFFSET(0x220f), 0x00000100);      /* IFLX High Limit */
+       t1_tpi_write(adapter, OFFSET(0x2210), 0x00000c00);      /* IFLX Almost Full Limit */
+       t1_tpi_write(adapter, OFFSET(0x2211), 0x00000599);      /* IFLX Almost Empty Limit */
+       t1_tpi_write(adapter, OFFSET(0x220d), 0x00000000);      /* IFLX Indirect Register Update */
+       t1_tpi_write(adapter, OFFSET(0x2201), 0x00000001);      /* IFLX Channel Provision */
+       t1_tpi_write(adapter, OFFSET(0x2203), 0x0000ffff);      /* IFLX Undocumented */
+       t1_tpi_write(adapter, OFFSET(0x2205), 0x0000ffff);      /* IFLX Undocumented */
+       t1_tpi_write(adapter, OFFSET(0x2209), 0x0000ffff);      /* IFLX Enable overflow interrupt.  The other bit are undocumented */
+
+       t1_tpi_write(adapter, OFFSET(0x2241), 0xfffffffe);      /* PL4MOS Undocumented */
+       t1_tpi_write(adapter, OFFSET(0x2242), 0x0000ffff);      /* PL4MOS Undocumented */
+       t1_tpi_write(adapter, OFFSET(0x2243), 0x00000008);      /* PL4MOS Starving Burst Size */
+       t1_tpi_write(adapter, OFFSET(0x2244), 0x00000008);      /* PL4MOS Hungry Burst Size */
+       t1_tpi_write(adapter, OFFSET(0x2245), 0x00000008);      /* PL4MOS Transfer Size */
+       t1_tpi_write(adapter, OFFSET(0x2240), 0x00000005);      /* PL4MOS Disable */
+
+       t1_tpi_write(adapter, OFFSET(0x2280), 0x00002103);      /* PL4ODP Training Repeat and SOP rule */
+       t1_tpi_write(adapter, OFFSET(0x2284), 0x00000000);      /* PL4ODP MAX_T setting */
+
+       t1_tpi_write(adapter, OFFSET(0x3280), 0x00000087);      /* PL4IDU Enable data forward, port state machine. Set ALLOW_NON_ZERO_OLB */
+       t1_tpi_write(adapter, OFFSET(0x3282), 0x0000001f);      /* PL4IDU Enable Dip4 check error interrupts */
+
+       t1_tpi_write(adapter, OFFSET(0x3040), 0x0c32);  /* # TXXG Config */
+       /* For T1 use timer based Mac flow control. */
+       t1_tpi_write(adapter, OFFSET(0x304d), 0x8000);
+       t1_tpi_write(adapter, OFFSET(0x2040), 0x059c);  /* # RXXG Config */
+       t1_tpi_write(adapter, OFFSET(0x2049), 0x0001);  /* # RXXG Cut Through */
+       t1_tpi_write(adapter, OFFSET(0x2070), 0x0000);  /* # Disable promiscuous mode */
+
+       /* Setup Exact Match Filter 0 to allow broadcast packets.
+        */
+       t1_tpi_write(adapter, OFFSET(0x206e), 0x0000);  /* # Disable Match Enable bit */
+       t1_tpi_write(adapter, OFFSET(0x204a), 0xffff);  /* # low addr */
+       t1_tpi_write(adapter, OFFSET(0x204b), 0xffff);  /* # mid addr */
+       t1_tpi_write(adapter, OFFSET(0x204c), 0xffff);  /* # high addr */
+       t1_tpi_write(adapter, OFFSET(0x206e), 0x0009);  /* # Enable Match Enable bit */
+
+       t1_tpi_write(adapter, OFFSET(0x0003), 0x0000);  /* # NO SOP/ PAD_EN setup */
+       t1_tpi_write(adapter, OFFSET(0x0100), 0x0ff0);  /* # RXEQB disabled */
+       t1_tpi_write(adapter, OFFSET(0x0101), 0x0f0f);  /* # No Preemphasis */
+
+       return cmac;
+}
+
+static int pm3393_mac_reset(adapter_t * adapter)
+{
+       u32 val;
+       u32 x;
+       u32 is_pl4_reset_finished;
+       u32 is_pl4_outof_lock;
+       u32 is_xaui_mabc_pll_locked;
+       u32 successful_reset;
+       int i;
+
+       /* The following steps are required to properly reset
+        * the PM3393. This information is provided in the
+        * PM3393 datasheet (Issue 2: November 2002)
+        * section 13.1 -- Device Reset.
+        *
+        * The PM3393 has three types of components that are
+        * individually reset:
+        *
+        * DRESETB      - Digital circuitry
+        * PL4_ARESETB  - PL4 analog circuitry
+        * XAUI_ARESETB - XAUI bus analog circuitry
+        *
+        * Steps to reset PM3393 using RSTB pin:
+        *
+        * 1. Assert RSTB pin low ( write 0 )
+        * 2. Wait at least 1ms to initiate a complete initialization of device.
+        * 3. Wait until all external clocks and REFSEL are stable.
+        * 4. Wait minimum of 1ms. (after external clocks and REFEL are stable)
+        * 5. De-assert RSTB ( write 1 )
+        * 6. Wait until internal timers to expires after ~14ms.
+        *    - Allows analog clock synthesizer(PL4CSU) to stabilize to
+        *      selected reference frequency before allowing the digital
+        *      portion of the device to operate.
+        * 7. Wait at least 200us for XAUI interface to stabilize.
+        * 8. Verify the PM3393 came out of reset successfully.
+        *    Set successful reset flag if everything worked else try again
+        *    a few more times.
+        */
+
+       successful_reset = 0;
+       for (i = 0; i < 3 && !successful_reset; i++) {
+               /* 1 */
+               t1_tpi_read(adapter, A_ELMER0_GPO, &val);
+               val &= ~1;
+               t1_tpi_write(adapter, A_ELMER0_GPO, val);
+
+               /* 2 */
+               msleep(1);
+
+               /* 3 */
+               msleep(1);
+
+               /* 4 */
+               msleep(2 /*1 extra ms for safety */ );
+
+               /* 5 */
+               val |= 1;
+               t1_tpi_write(adapter, A_ELMER0_GPO, val);
+
+               /* 6 */
+               msleep(15 /*1 extra ms for safety */ );
+
+               /* 7 */
+               msleep(1);
+
+               /* 8 */
+
+               /* Has PL4 analog block come out of reset correctly? */
+               t1_tpi_read(adapter, OFFSET(SUNI1x10GEXP_REG_DEVICE_STATUS), &val);
+               is_pl4_reset_finished = (val & SUNI1x10GEXP_BITMSK_TOP_EXPIRED);
+
+               /* TBD XXX SUNI1x10GEXP_BITMSK_TOP_PL4_IS_DOOL gets locked later in the init sequence
+                *         figure out why? */
+
+               /* Have all PL4 block clocks locked? */
+               x = (SUNI1x10GEXP_BITMSK_TOP_PL4_ID_DOOL
+                    /*| SUNI1x10GEXP_BITMSK_TOP_PL4_IS_DOOL */  |
+                    SUNI1x10GEXP_BITMSK_TOP_PL4_ID_ROOL |
+                    SUNI1x10GEXP_BITMSK_TOP_PL4_IS_ROOL |
+                    SUNI1x10GEXP_BITMSK_TOP_PL4_OUT_ROOL);
+               is_pl4_outof_lock = (val & x);
+
+               /* ??? If this fails, might be able to software reset the XAUI part
+                *     and try to recover... thus saving us from doing another HW reset */
+               /* Has the XAUI MABC PLL circuitry stablized? */
+               is_xaui_mabc_pll_locked =
+                   (val & SUNI1x10GEXP_BITMSK_TOP_SXRA_EXPIRED);
+
+               successful_reset = (is_pl4_reset_finished && !is_pl4_outof_lock
+                                   && is_xaui_mabc_pll_locked);
+       }
+       return successful_reset ? 0 : 1;
+}
+
+struct gmac t1_pm3393_ops = {
+       STATS_TICK_SECS,
+       pm3393_mac_create,
+       pm3393_mac_reset
+};
diff --git a/drivers/net/chelsio/regs.h b/drivers/net/chelsio/regs.h
new file mode 100644 (file)
index 0000000..b90e11f
--- /dev/null
@@ -0,0 +1,468 @@
+/*****************************************************************************
+ *                                                                           *
+ * File: regs.h                                                              *
+ * $Revision: 1.8 $                                                          *
+ * $Date: 2005/06/21 18:29:48 $                                              *
+ * Description:                                                              *
+ *  part of the Chelsio 10Gb Ethernet Driver.                                *
+ *                                                                           *
+ * This program is free software; you can redistribute it and/or modify      *
+ * it under the terms of the GNU General Public License, version 2, as       *
+ * published by the Free Software Foundation.                                *
+ *                                                                           *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED    *
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF      *
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.                     *
+ *                                                                           *
+ * http://www.chelsio.com                                                    *
+ *                                                                           *
+ * Copyright (c) 2003 - 2005 Chelsio Communications, Inc.                    *
+ * All rights reserved.                                                      *
+ *                                                                           *
+ * Maintainers: maintainers@chelsio.com                                      *
+ *                                                                           *
+ * Authors: Dimitrios Michailidis   <dm@chelsio.com>                         *
+ *          Tina Yang               <tainay@chelsio.com>                     *
+ *          Felix Marti             <felix@chelsio.com>                      *
+ *          Scott Bardone           <sbardone@chelsio.com>                   *
+ *          Kurt Ottaway            <kottaway@chelsio.com>                   *
+ *          Frank DiMambro          <frank@chelsio.com>                      *
+ *                                                                           *
+ * History:                                                                  *
+ *                                                                           *
+ ****************************************************************************/
+
+#ifndef _CXGB_REGS_H_
+#define _CXGB_REGS_H_
+
+/* SGE registers */
+#define A_SG_CONTROL 0x0
+
+#define S_CMDQ0_ENABLE    0
+#define V_CMDQ0_ENABLE(x) ((x) << S_CMDQ0_ENABLE)
+#define F_CMDQ0_ENABLE    V_CMDQ0_ENABLE(1U)
+
+#define S_CMDQ1_ENABLE    1
+#define V_CMDQ1_ENABLE(x) ((x) << S_CMDQ1_ENABLE)
+#define F_CMDQ1_ENABLE    V_CMDQ1_ENABLE(1U)
+
+#define S_FL0_ENABLE    2
+#define V_FL0_ENABLE(x) ((x) << S_FL0_ENABLE)
+#define F_FL0_ENABLE    V_FL0_ENABLE(1U)
+
+#define S_FL1_ENABLE    3
+#define V_FL1_ENABLE(x) ((x) << S_FL1_ENABLE)
+#define F_FL1_ENABLE    V_FL1_ENABLE(1U)
+
+#define S_CPL_ENABLE    4
+#define V_CPL_ENABLE(x) ((x) << S_CPL_ENABLE)
+#define F_CPL_ENABLE    V_CPL_ENABLE(1U)
+
+#define S_RESPONSE_QUEUE_ENABLE    5
+#define V_RESPONSE_QUEUE_ENABLE(x) ((x) << S_RESPONSE_QUEUE_ENABLE)
+#define F_RESPONSE_QUEUE_ENABLE    V_RESPONSE_QUEUE_ENABLE(1U)
+
+#define S_CMDQ_PRIORITY    6
+#define M_CMDQ_PRIORITY    0x3
+#define V_CMDQ_PRIORITY(x) ((x) << S_CMDQ_PRIORITY)
+#define G_CMDQ_PRIORITY(x) (((x) >> S_CMDQ_PRIORITY) & M_CMDQ_PRIORITY)
+
+#define S_DISABLE_CMDQ1_GTS    9
+#define V_DISABLE_CMDQ1_GTS(x) ((x) << S_DISABLE_CMDQ1_GTS)
+#define F_DISABLE_CMDQ1_GTS    V_DISABLE_CMDQ1_GTS(1U)
+
+#define S_DISABLE_FL0_GTS    10
+#define V_DISABLE_FL0_GTS(x) ((x) << S_DISABLE_FL0_GTS)
+#define F_DISABLE_FL0_GTS    V_DISABLE_FL0_GTS(1U)
+
+#define S_DISABLE_FL1_GTS    11
+#define V_DISABLE_FL1_GTS(x) ((x) << S_DISABLE_FL1_GTS)
+#define F_DISABLE_FL1_GTS    V_DISABLE_FL1_GTS(1U)
+
+#define S_ENABLE_BIG_ENDIAN    12
+#define V_ENABLE_BIG_ENDIAN(x) ((x) << S_ENABLE_BIG_ENDIAN)
+#define F_ENABLE_BIG_ENDIAN    V_ENABLE_BIG_ENDIAN(1U)
+
+#define S_ISCSI_COALESCE    14
+#define V_ISCSI_COALESCE(x) ((x) << S_ISCSI_COALESCE)
+#define F_ISCSI_COALESCE    V_ISCSI_COALESCE(1U)
+
+#define S_RX_PKT_OFFSET    15
+#define V_RX_PKT_OFFSET(x) ((x) << S_RX_PKT_OFFSET)
+
+#define S_VLAN_XTRACT    18
+#define V_VLAN_XTRACT(x) ((x) << S_VLAN_XTRACT)
+#define F_VLAN_XTRACT    V_VLAN_XTRACT(1U)
+
+#define A_SG_DOORBELL 0x4
+#define A_SG_CMD0BASELWR 0x8
+#define A_SG_CMD0BASEUPR 0xc
+#define A_SG_CMD1BASELWR 0x10
+#define A_SG_CMD1BASEUPR 0x14
+#define A_SG_FL0BASELWR 0x18
+#define A_SG_FL0BASEUPR 0x1c
+#define A_SG_FL1BASELWR 0x20
+#define A_SG_FL1BASEUPR 0x24
+#define A_SG_CMD0SIZE 0x28
+#define A_SG_FL0SIZE 0x2c
+#define A_SG_RSPSIZE 0x30
+#define A_SG_RSPBASELWR 0x34
+#define A_SG_RSPBASEUPR 0x38
+#define A_SG_FLTHRESHOLD 0x3c
+#define A_SG_RSPQUEUECREDIT 0x40
+#define A_SG_SLEEPING 0x48
+#define A_SG_INTRTIMER 0x4c
+#define A_SG_CMD1SIZE 0xb0
+#define A_SG_FL1SIZE 0xb4
+#define A_SG_INT_ENABLE 0xb8
+
+#define S_RESPQ_EXHAUSTED    0
+#define V_RESPQ_EXHAUSTED(x) ((x) << S_RESPQ_EXHAUSTED)
+#define F_RESPQ_EXHAUSTED    V_RESPQ_EXHAUSTED(1U)
+
+#define S_RESPQ_OVERFLOW    1
+#define V_RESPQ_OVERFLOW(x) ((x) << S_RESPQ_OVERFLOW)
+#define F_RESPQ_OVERFLOW    V_RESPQ_OVERFLOW(1U)
+
+#define S_FL_EXHAUSTED    2
+#define V_FL_EXHAUSTED(x) ((x) << S_FL_EXHAUSTED)
+#define F_FL_EXHAUSTED    V_FL_EXHAUSTED(1U)
+
+#define S_PACKET_TOO_BIG    3
+#define V_PACKET_TOO_BIG(x) ((x) << S_PACKET_TOO_BIG)
+#define F_PACKET_TOO_BIG    V_PACKET_TOO_BIG(1U)
+
+#define S_PACKET_MISMATCH    4
+#define V_PACKET_MISMATCH(x) ((x) << S_PACKET_MISMATCH)
+#define F_PACKET_MISMATCH    V_PACKET_MISMATCH(1U)
+
+#define A_SG_INT_CAUSE 0xbc
+#define A_SG_RESPACCUTIMER 0xc0
+
+/* MC3 registers */
+
+#define S_READY    1
+#define V_READY(x) ((x) << S_READY)
+#define F_READY    V_READY(1U)
+
+/* MC4 registers */
+
+#define A_MC4_CFG 0x180
+#define S_MC4_SLOW    25
+#define V_MC4_SLOW(x) ((x) << S_MC4_SLOW)
+#define F_MC4_SLOW    V_MC4_SLOW(1U)
+
+/* TPI registers */
+
+#define A_TPI_ADDR 0x280
+#define A_TPI_WR_DATA 0x284
+#define A_TPI_RD_DATA 0x288
+#define A_TPI_CSR 0x28c
+
+#define S_TPIWR    0
+#define V_TPIWR(x) ((x) << S_TPIWR)
+#define F_TPIWR    V_TPIWR(1U)
+
+#define S_TPIRDY    1
+#define V_TPIRDY(x) ((x) << S_TPIRDY)
+#define F_TPIRDY    V_TPIRDY(1U)
+
+#define A_TPI_PAR 0x29c
+
+#define S_TPIPAR    0
+#define M_TPIPAR    0x7f
+#define V_TPIPAR(x) ((x) << S_TPIPAR)
+#define G_TPIPAR(x) (((x) >> S_TPIPAR) & M_TPIPAR)
+
+/* TP registers */
+
+#define A_TP_IN_CONFIG 0x300
+
+#define S_TP_IN_CSPI_CPL    3
+#define V_TP_IN_CSPI_CPL(x) ((x) << S_TP_IN_CSPI_CPL)
+#define F_TP_IN_CSPI_CPL    V_TP_IN_CSPI_CPL(1U)
+
+#define S_TP_IN_CSPI_CHECK_IP_CSUM    5
+#define V_TP_IN_CSPI_CHECK_IP_CSUM(x) ((x) << S_TP_IN_CSPI_CHECK_IP_CSUM)
+#define F_TP_IN_CSPI_CHECK_IP_CSUM    V_TP_IN_CSPI_CHECK_IP_CSUM(1U)
+
+#define S_TP_IN_CSPI_CHECK_TCP_CSUM    6
+#define V_TP_IN_CSPI_CHECK_TCP_CSUM(x) ((x) << S_TP_IN_CSPI_CHECK_TCP_CSUM)
+#define F_TP_IN_CSPI_CHECK_TCP_CSUM    V_TP_IN_CSPI_CHECK_TCP_CSUM(1U)
+
+#define S_TP_IN_ESPI_ETHERNET    8
+#define V_TP_IN_ESPI_ETHERNET(x) ((x) << S_TP_IN_ESPI_ETHERNET)
+#define F_TP_IN_ESPI_ETHERNET    V_TP_IN_ESPI_ETHERNET(1U)
+
+#define S_TP_IN_ESPI_CHECK_IP_CSUM    12
+#define V_TP_IN_ESPI_CHECK_IP_CSUM(x) ((x) << S_TP_IN_ESPI_CHECK_IP_CSUM)
+#define F_TP_IN_ESPI_CHECK_IP_CSUM    V_TP_IN_ESPI_CHECK_IP_CSUM(1U)
+
+#define S_TP_IN_ESPI_CHECK_TCP_CSUM    13
+#define V_TP_IN_ESPI_CHECK_TCP_CSUM(x) ((x) << S_TP_IN_ESPI_CHECK_TCP_CSUM)
+#define F_TP_IN_ESPI_CHECK_TCP_CSUM    V_TP_IN_ESPI_CHECK_TCP_CSUM(1U)
+
+#define S_OFFLOAD_DISABLE    14
+#define V_OFFLOAD_DISABLE(x) ((x) << S_OFFLOAD_DISABLE)
+#define F_OFFLOAD_DISABLE    V_OFFLOAD_DISABLE(1U)
+
+#define A_TP_OUT_CONFIG 0x304
+
+#define S_TP_OUT_CSPI_CPL    2
+#define V_TP_OUT_CSPI_CPL(x) ((x) << S_TP_OUT_CSPI_CPL)
+#define F_TP_OUT_CSPI_CPL    V_TP_OUT_CSPI_CPL(1U)
+
+#define S_TP_OUT_ESPI_ETHERNET    6
+#define V_TP_OUT_ESPI_ETHERNET(x) ((x) << S_TP_OUT_ESPI_ETHERNET)
+#define F_TP_OUT_ESPI_ETHERNET    V_TP_OUT_ESPI_ETHERNET(1U)
+
+#define S_TP_OUT_ESPI_GENERATE_IP_CSUM    10
+#define V_TP_OUT_ESPI_GENERATE_IP_CSUM(x) ((x) << S_TP_OUT_ESPI_GENERATE_IP_CSUM)
+#define F_TP_OUT_ESPI_GENERATE_IP_CSUM    V_TP_OUT_ESPI_GENERATE_IP_CSUM(1U)
+
+#define S_TP_OUT_ESPI_GENERATE_TCP_CSUM    11
+#define V_TP_OUT_ESPI_GENERATE_TCP_CSUM(x) ((x) << S_TP_OUT_ESPI_GENERATE_TCP_CSUM)
+#define F_TP_OUT_ESPI_GENERATE_TCP_CSUM    V_TP_OUT_ESPI_GENERATE_TCP_CSUM(1U)
+
+#define A_TP_GLOBAL_CONFIG 0x308
+
+#define S_IP_TTL    0
+#define M_IP_TTL    0xff
+#define V_IP_TTL(x) ((x) << S_IP_TTL)
+
+#define S_TCP_CSUM    11
+#define V_TCP_CSUM(x) ((x) << S_TCP_CSUM)
+#define F_TCP_CSUM    V_TCP_CSUM(1U)
+
+#define S_UDP_CSUM    12
+#define V_UDP_CSUM(x) ((x) << S_UDP_CSUM)
+#define F_UDP_CSUM    V_UDP_CSUM(1U)
+
+#define S_IP_CSUM    13
+#define V_IP_CSUM(x) ((x) << S_IP_CSUM)
+#define F_IP_CSUM    V_IP_CSUM(1U)
+
+#define S_PATH_MTU    15
+#define V_PATH_MTU(x) ((x) << S_PATH_MTU)
+#define F_PATH_MTU    V_PATH_MTU(1U)
+
+#define S_5TUPLE_LOOKUP    17
+#define V_5TUPLE_LOOKUP(x) ((x) << S_5TUPLE_LOOKUP)
+
+#define S_SYN_COOKIE_PARAMETER    26
+#define V_SYN_COOKIE_PARAMETER(x) ((x) << S_SYN_COOKIE_PARAMETER)
+
+#define A_TP_PC_CONFIG 0x348
+#define S_DIS_TX_FILL_WIN_PUSH    12
+#define V_DIS_TX_FILL_WIN_PUSH(x) ((x) << S_DIS_TX_FILL_WIN_PUSH)
+#define F_DIS_TX_FILL_WIN_PUSH    V_DIS_TX_FILL_WIN_PUSH(1U)
+
+#define S_TP_PC_REV    30
+#define M_TP_PC_REV    0x3
+#define G_TP_PC_REV(x) (((x) >> S_TP_PC_REV) & M_TP_PC_REV)
+#define A_TP_RESET 0x44c
+#define S_TP_RESET    0
+#define V_TP_RESET(x) ((x) << S_TP_RESET)
+#define F_TP_RESET    V_TP_RESET(1U)
+
+#define A_TP_INT_ENABLE 0x470
+#define A_TP_INT_CAUSE 0x474
+#define A_TP_TX_DROP_CONFIG 0x4b8
+
+#define S_ENABLE_TX_DROP    31
+#define V_ENABLE_TX_DROP(x) ((x) << S_ENABLE_TX_DROP)
+#define F_ENABLE_TX_DROP    V_ENABLE_TX_DROP(1U)
+
+#define S_ENABLE_TX_ERROR    30
+#define V_ENABLE_TX_ERROR(x) ((x) << S_ENABLE_TX_ERROR)
+#define F_ENABLE_TX_ERROR    V_ENABLE_TX_ERROR(1U)
+
+#define S_DROP_TICKS_CNT    4
+#define V_DROP_TICKS_CNT(x) ((x) << S_DROP_TICKS_CNT)
+
+#define S_NUM_PKTS_DROPPED    0
+#define V_NUM_PKTS_DROPPED(x) ((x) << S_NUM_PKTS_DROPPED)
+
+/* CSPI registers */
+
+#define S_DIP4ERR    0
+#define V_DIP4ERR(x) ((x) << S_DIP4ERR)
+#define F_DIP4ERR    V_DIP4ERR(1U)
+
+#define S_RXDROP    1
+#define V_RXDROP(x) ((x) << S_RXDROP)
+#define F_RXDROP    V_RXDROP(1U)
+
+#define S_TXDROP    2
+#define V_TXDROP(x) ((x) << S_TXDROP)
+#define F_TXDROP    V_TXDROP(1U)
+
+#define S_RXOVERFLOW    3
+#define V_RXOVERFLOW(x) ((x) << S_RXOVERFLOW)
+#define F_RXOVERFLOW    V_RXOVERFLOW(1U)
+
+#define S_RAMPARITYERR    4
+#define V_RAMPARITYERR(x) ((x) << S_RAMPARITYERR)
+#define F_RAMPARITYERR    V_RAMPARITYERR(1U)
+
+/* ESPI registers */
+
+#define A_ESPI_SCH_TOKEN0 0x880
+#define A_ESPI_SCH_TOKEN1 0x884
+#define A_ESPI_SCH_TOKEN2 0x888
+#define A_ESPI_SCH_TOKEN3 0x88c
+#define A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK 0x890
+#define A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK 0x894
+#define A_ESPI_CALENDAR_LENGTH 0x898
+#define A_PORT_CONFIG 0x89c
+
+#define S_RX_NPORTS    0
+#define V_RX_NPORTS(x) ((x) << S_RX_NPORTS)
+
+#define S_TX_NPORTS    8
+#define V_TX_NPORTS(x) ((x) << S_TX_NPORTS)
+
+#define A_ESPI_FIFO_STATUS_ENABLE 0x8a0
+
+#define S_RXSTATUSENABLE    0
+#define V_RXSTATUSENABLE(x) ((x) << S_RXSTATUSENABLE)
+#define F_RXSTATUSENABLE    V_RXSTATUSENABLE(1U)
+
+#define S_INTEL1010MODE    4
+#define V_INTEL1010MODE(x) ((x) << S_INTEL1010MODE)
+#define F_INTEL1010MODE    V_INTEL1010MODE(1U)
+
+#define A_ESPI_MAXBURST1_MAXBURST2 0x8a8
+#define A_ESPI_TRAIN 0x8ac
+#define A_ESPI_INTR_STATUS 0x8c8
+
+#define S_DIP2PARITYERR    5
+#define V_DIP2PARITYERR(x) ((x) << S_DIP2PARITYERR)
+#define F_DIP2PARITYERR    V_DIP2PARITYERR(1U)
+
+#define A_ESPI_INTR_ENABLE 0x8cc
+#define A_RX_DROP_THRESHOLD 0x8d0
+#define A_ESPI_RX_RESET 0x8ec
+#define A_ESPI_MISC_CONTROL 0x8f0
+
+#define S_OUT_OF_SYNC_COUNT    0
+#define V_OUT_OF_SYNC_COUNT(x) ((x) << S_OUT_OF_SYNC_COUNT)
+
+#define S_DIP2_PARITY_ERR_THRES    5
+#define V_DIP2_PARITY_ERR_THRES(x) ((x) << S_DIP2_PARITY_ERR_THRES)
+
+#define S_DIP4_THRES    9
+#define V_DIP4_THRES(x) ((x) << S_DIP4_THRES)
+
+#define S_MONITORED_PORT_NUM    25
+#define V_MONITORED_PORT_NUM(x) ((x) << S_MONITORED_PORT_NUM)
+
+#define S_MONITORED_DIRECTION    27
+#define V_MONITORED_DIRECTION(x) ((x) << S_MONITORED_DIRECTION)
+#define F_MONITORED_DIRECTION    V_MONITORED_DIRECTION(1U)
+
+#define S_MONITORED_INTERFACE    28
+#define V_MONITORED_INTERFACE(x) ((x) << S_MONITORED_INTERFACE)
+#define F_MONITORED_INTERFACE    V_MONITORED_INTERFACE(1U)
+
+#define A_ESPI_DIP2_ERR_COUNT 0x8f4
+#define A_ESPI_CMD_ADDR 0x8f8
+
+#define S_WRITE_DATA    0
+#define V_WRITE_DATA(x) ((x) << S_WRITE_DATA)
+
+#define S_REGISTER_OFFSET    8
+#define V_REGISTER_OFFSET(x) ((x) << S_REGISTER_OFFSET)
+
+#define S_CHANNEL_ADDR    12
+#define V_CHANNEL_ADDR(x) ((x) << S_CHANNEL_ADDR)
+
+#define S_MODULE_ADDR    16
+#define V_MODULE_ADDR(x) ((x) << S_MODULE_ADDR)
+
+#define S_BUNDLE_ADDR    20
+#define V_BUNDLE_ADDR(x) ((x) << S_BUNDLE_ADDR)
+
+#define S_SPI4_COMMAND    24
+#define V_SPI4_COMMAND(x) ((x) << S_SPI4_COMMAND)
+
+#define A_ESPI_GOSTAT 0x8fc
+#define S_ESPI_CMD_BUSY    8
+#define V_ESPI_CMD_BUSY(x) ((x) << S_ESPI_CMD_BUSY)
+#define F_ESPI_CMD_BUSY    V_ESPI_CMD_BUSY(1U)
+
+/* PL registers */
+
+#define A_PL_ENABLE 0xa00
+
+#define S_PL_INTR_SGE_ERR    0
+#define V_PL_INTR_SGE_ERR(x) ((x) << S_PL_INTR_SGE_ERR)
+#define F_PL_INTR_SGE_ERR    V_PL_INTR_SGE_ERR(1U)
+
+#define S_PL_INTR_SGE_DATA    1
+#define V_PL_INTR_SGE_DATA(x) ((x) << S_PL_INTR_SGE_DATA)
+#define F_PL_INTR_SGE_DATA    V_PL_INTR_SGE_DATA(1U)
+
+#define S_PL_INTR_TP    6
+#define V_PL_INTR_TP(x) ((x) << S_PL_INTR_TP)
+#define F_PL_INTR_TP    V_PL_INTR_TP(1U)
+
+#define S_PL_INTR_ESPI    8
+#define V_PL_INTR_ESPI(x) ((x) << S_PL_INTR_ESPI)
+#define F_PL_INTR_ESPI    V_PL_INTR_ESPI(1U)
+
+#define S_PL_INTR_PCIX    10
+#define V_PL_INTR_PCIX(x) ((x) << S_PL_INTR_PCIX)
+#define F_PL_INTR_PCIX    V_PL_INTR_PCIX(1U)
+
+#define S_PL_INTR_EXT    11
+#define V_PL_INTR_EXT(x) ((x) << S_PL_INTR_EXT)
+#define F_PL_INTR_EXT    V_PL_INTR_EXT(1U)
+
+#define A_PL_CAUSE 0xa04
+
+/* MC5 registers */
+
+#define A_MC5_CONFIG 0xc04
+
+#define S_TCAM_RESET    1
+#define V_TCAM_RESET(x) ((x) << S_TCAM_RESET)
+#define F_TCAM_RESET    V_TCAM_RESET(1U)
+
+#define S_M_BUS_ENABLE    5
+#define V_M_BUS_ENABLE(x) ((x) << S_M_BUS_ENABLE)
+#define F_M_BUS_ENABLE    V_M_BUS_ENABLE(1U)
+
+/* PCICFG registers */
+
+#define A_PCICFG_PM_CSR 0x44
+#define A_PCICFG_VPD_ADDR 0x4a
+
+#define S_VPD_OP_FLAG    15
+#define V_VPD_OP_FLAG(x) ((x) << S_VPD_OP_FLAG)
+#define F_VPD_OP_FLAG    V_VPD_OP_FLAG(1U)
+
+#define A_PCICFG_VPD_DATA 0x4c
+
+#define A_PCICFG_INTR_ENABLE 0xf4
+#define A_PCICFG_INTR_CAUSE 0xf8
+
+#define A_PCICFG_MODE 0xfc
+
+#define S_PCI_MODE_64BIT    0
+#define V_PCI_MODE_64BIT(x) ((x) << S_PCI_MODE_64BIT)
+#define F_PCI_MODE_64BIT    V_PCI_MODE_64BIT(1U)
+
+#define S_PCI_MODE_PCIX    5
+#define V_PCI_MODE_PCIX(x) ((x) << S_PCI_MODE_PCIX)
+#define F_PCI_MODE_PCIX    V_PCI_MODE_PCIX(1U)
+
+#define S_PCI_MODE_CLK    6
+#define M_PCI_MODE_CLK    0x3
+#define G_PCI_MODE_CLK(x) (((x) >> S_PCI_MODE_CLK) & M_PCI_MODE_CLK)
+
+#endif /* _CXGB_REGS_H_ */
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
new file mode 100644 (file)
index 0000000..53b41d9
--- /dev/null
@@ -0,0 +1,1684 @@
+/*****************************************************************************
+ *                                                                           *
+ * File: sge.c                                                               *
+ * $Revision: 1.26 $                                                         *
+ * $Date: 2005/06/21 18:29:48 $                                              *
+ * Description:                                                              *
+ *  DMA engine.                                                              *
+ *  part of the Chelsio 10Gb Ethernet Driver.                                *
+ *                                                                           *
+ * This program is free software; you can redistribute it and/or modify      *
+ * it under the terms of the GNU General Public License, version 2, as       *
+ * published by the Free Software Foundation.                                *
+ *                                                                           *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED    *
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF      *
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.                     *
+ *                                                                           *
+ * http://www.chelsio.com                                                    *
+ *                                                                           *
+ * Copyright (c) 2003 - 2005 Chelsio Communications, Inc.                    *
+ * All rights reserved.                                                      *
+ *                                                                           *
+ * Maintainers: maintainers@chelsio.com                                      *
+ *                                                                           *
+ * Authors: Dimitrios Michailidis   <dm@chelsio.com>                         *
+ *          Tina Yang               <tainay@chelsio.com>                     *
+ *          Felix Marti             <felix@chelsio.com>                      *
+ *          Scott Bardone           <sbardone@chelsio.com>                   *
+ *          Kurt Ottaway            <kottaway@chelsio.com>                   *
+ *          Frank DiMambro          <frank@chelsio.com>                      *
+ *                                                                           *
+ * History:                                                                  *
+ *                                                                           *
+ ****************************************************************************/
+
+#include "common.h"
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/if_arp.h>
+
+#include "cpl5_cmd.h"
+#include "sge.h"
+#include "regs.h"
+#include "espi.h"
+
+
+#ifdef NETIF_F_TSO
+#include <linux/tcp.h>
+#endif
+
+#define SGE_CMDQ_N             2
+#define SGE_FREELQ_N           2
+#define SGE_CMDQ0_E_N          1024
+#define SGE_CMDQ1_E_N          128
+#define SGE_FREEL_SIZE         4096
+#define SGE_JUMBO_FREEL_SIZE   512
+#define SGE_FREEL_REFILL_THRESH        16
+#define SGE_RESPQ_E_N          1024
+#define SGE_INTRTIMER_NRES     1000
+#define SGE_RX_COPY_THRES      256
+#define SGE_RX_SM_BUF_SIZE     1536
+
+# define SGE_RX_DROP_THRES 2
+
+#define SGE_RESPQ_REPLENISH_THRES (SGE_RESPQ_E_N / 4)
+
+/*
+ * Period of the TX buffer reclaim timer.  This timer does not need to run
+ * frequently as TX buffers are usually reclaimed by new TX packets.
+ */
+#define TX_RECLAIM_PERIOD (HZ / 4)
+
+#ifndef NET_IP_ALIGN
+# define NET_IP_ALIGN 2
+#endif
+
+#define M_CMD_LEN       0x7fffffff
+#define V_CMD_LEN(v)    (v)
+#define G_CMD_LEN(v)    ((v) & M_CMD_LEN)
+#define V_CMD_GEN1(v)   ((v) << 31)
+#define V_CMD_GEN2(v)   (v)
+#define F_CMD_DATAVALID (1 << 1)
+#define F_CMD_SOP       (1 << 2)
+#define V_CMD_EOP(v)    ((v) << 3)
+
+/*
+ * Command queue, receive buffer list, and response queue descriptors.
+ */
+#if defined(__BIG_ENDIAN_BITFIELD)
+struct cmdQ_e {
+       u32 addr_lo;
+       u32 len_gen;
+       u32 flags;
+       u32 addr_hi;
+};
+
+struct freelQ_e {
+       u32 addr_lo;
+       u32 len_gen;
+       u32 gen2;
+       u32 addr_hi;
+};
+
+struct respQ_e {
+       u32 Qsleeping           : 4;
+       u32 Cmdq1CreditReturn   : 5;
+       u32 Cmdq1DmaComplete    : 5;
+       u32 Cmdq0CreditReturn   : 5;
+       u32 Cmdq0DmaComplete    : 5;
+       u32 FreelistQid         : 2;
+       u32 CreditValid         : 1;
+       u32 DataValid           : 1;
+       u32 Offload             : 1;
+       u32 Eop                 : 1;
+       u32 Sop                 : 1;
+       u32 GenerationBit       : 1;
+       u32 BufferLength;
+};
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+struct cmdQ_e {
+       u32 len_gen;
+       u32 addr_lo;
+       u32 addr_hi;
+       u32 flags;
+};
+
+struct freelQ_e {
+       u32 len_gen;
+       u32 addr_lo;
+       u32 addr_hi;
+       u32 gen2;
+};
+
+struct respQ_e {
+       u32 BufferLength;
+       u32 GenerationBit       : 1;
+       u32 Sop                 : 1;
+       u32 Eop                 : 1;
+       u32 Offload             : 1;
+       u32 DataValid           : 1;
+       u32 CreditValid         : 1;
+       u32 FreelistQid         : 2;
+       u32 Cmdq0DmaComplete    : 5;
+       u32 Cmdq0CreditReturn   : 5;
+       u32 Cmdq1DmaComplete    : 5;
+       u32 Cmdq1CreditReturn   : 5;
+       u32 Qsleeping           : 4;
+} ;
+#endif
+
+/*
+ * SW Context Command and Freelist Queue Descriptors
+ */
+struct cmdQ_ce {
+       struct sk_buff *skb;
+       DECLARE_PCI_UNMAP_ADDR(dma_addr);
+       DECLARE_PCI_UNMAP_LEN(dma_len);
+};
+
+struct freelQ_ce {
+       struct sk_buff *skb;
+       DECLARE_PCI_UNMAP_ADDR(dma_addr);
+       DECLARE_PCI_UNMAP_LEN(dma_len);
+};
+
+/*
+ * SW command, freelist and response rings
+ */
+struct cmdQ {
+       unsigned long   status;         /* HW DMA fetch status */
+       unsigned int    in_use;         /* # of in-use command descriptors */
+       unsigned int    size;           /* # of descriptors */
+       unsigned int    processed;      /* total # of descs HW has processed */
+       unsigned int    cleaned;        /* total # of descs SW has reclaimed */
+       unsigned int    stop_thres;     /* SW TX queue suspend threshold */
+       u16             pidx;           /* producer index (SW) */
+       u16             cidx;           /* consumer index (HW) */
+       u8              genbit;         /* current generation (=valid) bit */
+       u8              sop;            /* is next entry start of packet? */
+       struct cmdQ_e  *entries;        /* HW command descriptor Q */
+       struct cmdQ_ce *centries;       /* SW command context descriptor Q */
+       spinlock_t      lock;           /* Lock to protect cmdQ enqueuing */
+       dma_addr_t      dma_addr;       /* DMA addr HW command descriptor Q */
+};
+
+struct freelQ {
+       unsigned int    credits;        /* # of available RX buffers */
+       unsigned int    size;           /* free list capacity */
+       u16             pidx;           /* producer index (SW) */
+       u16             cidx;           /* consumer index (HW) */
+       u16             rx_buffer_size; /* Buffer size on this free list */
+       u16             dma_offset;     /* DMA offset to align IP headers */
+       u16             recycleq_idx;   /* skb recycle q to use */
+       u8              genbit;         /* current generation (=valid) bit */
+       struct freelQ_e *entries;       /* HW freelist descriptor Q */
+       struct freelQ_ce *centries;     /* SW freelist context descriptor Q */
+       dma_addr_t      dma_addr;       /* DMA addr HW freelist descriptor Q */
+};
+
+struct respQ {
+       unsigned int    credits;        /* credits to be returned to SGE */
+       unsigned int    size;           /* # of response Q descriptors */
+       u16             cidx;           /* consumer index (SW) */
+       u8              genbit;         /* current generation(=valid) bit */
+       struct respQ_e *entries;        /* HW response descriptor Q */
+       dma_addr_t      dma_addr;       /* DMA addr HW response descriptor Q */
+};
+
+/* Bit flags for cmdQ.status */
+enum {
+       CMDQ_STAT_RUNNING = 1,          /* fetch engine is running */
+       CMDQ_STAT_LAST_PKT_DB = 2       /* last packet rung the doorbell */
+};
+
+/*
+ * Main SGE data structure
+ *
+ * Interrupts are handled by a single CPU and it is likely that on a MP system
+ * the application is migrated to another CPU. In that scenario, we try to
+ * seperate the RX(in irq context) and TX state in order to decrease memory
+ * contention.
+ */
+struct sge {
+       struct adapter *adapter;        /* adapter backpointer */
+       struct net_device *netdev;      /* netdevice backpointer */
+       struct freelQ   freelQ[SGE_FREELQ_N]; /* buffer free lists */
+       struct respQ    respQ;          /* response Q */
+       unsigned long   stopped_tx_queues; /* bitmap of suspended Tx queues */
+       unsigned int    rx_pkt_pad;     /* RX padding for L2 packets */
+       unsigned int    jumbo_fl;       /* jumbo freelist Q index */
+       unsigned int    intrtimer_nres; /* no-resource interrupt timer */
+       unsigned int    fixed_intrtimer;/* non-adaptive interrupt timer */
+       struct timer_list tx_reclaim_timer; /* reclaims TX buffers */
+       struct timer_list espibug_timer;
+       unsigned int    espibug_timeout;
+       struct sk_buff  *espibug_skb;
+       u32             sge_control;    /* shadow value of sge control reg */
+       struct sge_intr_counts stats;
+       struct sge_port_stats port_stats[MAX_NPORTS];
+       struct cmdQ cmdQ[SGE_CMDQ_N] ____cacheline_aligned_in_smp;
+};
+
+/*
+ * PIO to indicate that memory mapped Q contains valid descriptor(s).
+ */
+static inline void doorbell_pio(struct adapter *adapter, u32 val)
+{
+       wmb();
+       writel(val, adapter->regs + A_SG_DOORBELL);
+}
+
+/*
+ * Frees all RX buffers on the freelist Q. The caller must make sure that
+ * the SGE is turned off before calling this function.
+ */
+static void free_freelQ_buffers(struct pci_dev *pdev, struct freelQ *q)
+{
+       unsigned int cidx = q->cidx;
+
+       while (q->credits--) {
+               struct freelQ_ce *ce = &q->centries[cidx];
+
+               pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr),
+                                pci_unmap_len(ce, dma_len),
+                                PCI_DMA_FROMDEVICE);
+               dev_kfree_skb(ce->skb);
+               ce->skb = NULL;
+               if (++cidx == q->size)
+                       cidx = 0;
+       }
+}
+
+/*
+ * Free RX free list and response queue resources.
+ */
+static void free_rx_resources(struct sge *sge)
+{
+       struct pci_dev *pdev = sge->adapter->pdev;
+       unsigned int size, i;
+
+       if (sge->respQ.entries) {
+               size = sizeof(struct respQ_e) * sge->respQ.size;
+               pci_free_consistent(pdev, size, sge->respQ.entries,
+                                   sge->respQ.dma_addr);
+       }
+
+       for (i = 0; i < SGE_FREELQ_N; i++) {
+               struct freelQ *q = &sge->freelQ[i];
+
+               if (q->centries) {
+                       free_freelQ_buffers(pdev, q);
+                       kfree(q->centries);
+               }
+               if (q->entries) {
+                       size = sizeof(struct freelQ_e) * q->size;
+                       pci_free_consistent(pdev, size, q->entries,
+                                           q->dma_addr);
+               }
+       }
+}
+
+/*
+ * Allocates basic RX resources, consisting of memory mapped freelist Qs and a
+ * response queue.
+ */
+static int alloc_rx_resources(struct sge *sge, struct sge_params *p)
+{
+       struct pci_dev *pdev = sge->adapter->pdev;
+       unsigned int size, i;
+
+       for (i = 0; i < SGE_FREELQ_N; i++) {
+               struct freelQ *q = &sge->freelQ[i];
+
+               q->genbit = 1;
+               q->size = p->freelQ_size[i];
+               q->dma_offset = sge->rx_pkt_pad ? 0 : NET_IP_ALIGN;
+               size = sizeof(struct freelQ_e) * q->size;
+               q->entries = (struct freelQ_e *)
+                             pci_alloc_consistent(pdev, size, &q->dma_addr);
+               if (!q->entries)
+                       goto err_no_mem;
+               memset(q->entries, 0, size);
+               size = sizeof(struct freelQ_ce) * q->size;
+               q->centries = kmalloc(size, GFP_KERNEL);
+               if (!q->centries)
+                       goto err_no_mem;
+               memset(q->centries, 0, size);
+       }
+
+       /*
+        * Calculate the buffer sizes for the two free lists.  FL0 accommodates
+        * regular sized Ethernet frames, FL1 is sized not to exceed 16K,
+        * including all the sk_buff overhead.
+        *
+        * Note: For T2 FL0 and FL1 are reversed.
+        */
+       sge->freelQ[!sge->jumbo_fl].rx_buffer_size = SGE_RX_SM_BUF_SIZE +
+               sizeof(struct cpl_rx_data) +
+               sge->freelQ[!sge->jumbo_fl].dma_offset;
+       sge->freelQ[sge->jumbo_fl].rx_buffer_size = (16 * 1024) -
+               SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+       /*
+        * Setup which skb recycle Q should be used when recycling buffers from
+        * each free list.
+        */
+       sge->freelQ[!sge->jumbo_fl].recycleq_idx = 0;
+       sge->freelQ[sge->jumbo_fl].recycleq_idx = 1;
+
+       sge->respQ.genbit = 1;
+       sge->respQ.size = SGE_RESPQ_E_N;
+       sge->respQ.credits = 0;
+       size = sizeof(struct respQ_e) * sge->respQ.size;
+       sge->respQ.entries = (struct respQ_e *)
+               pci_alloc_consistent(pdev, size, &sge->respQ.dma_addr);
+       if (!sge->respQ.entries)
+               goto err_no_mem;
+       memset(sge->respQ.entries, 0, size);
+       return 0;
+
+err_no_mem:
+       free_rx_resources(sge);
+       return -ENOMEM;
+}
+
+/*
+ * Reclaims n TX descriptors and frees the buffers associated with them.
+ */
+static void free_cmdQ_buffers(struct sge *sge, struct cmdQ *q, unsigned int n)
+{
+       struct cmdQ_ce *ce;
+       struct pci_dev *pdev = sge->adapter->pdev;
+       unsigned int cidx = q->cidx;
+
+       q->in_use -= n;
+       ce = &q->centries[cidx];
+       while (n--) {
+               if (q->sop)
+                       pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr),
+                                        pci_unmap_len(ce, dma_len),
+                                        PCI_DMA_TODEVICE);
+               else
+                       pci_unmap_page(pdev, pci_unmap_addr(ce, dma_addr),
+                                      pci_unmap_len(ce, dma_len),
+                                      PCI_DMA_TODEVICE);
+               q->sop = 0;
+               if (ce->skb) {
+                       dev_kfree_skb(ce->skb);
+                       q->sop = 1;
+               }
+               ce++;
+               if (++cidx == q->size) {
+                       cidx = 0;
+                       ce = q->centries;
+               }
+       }
+       q->cidx = cidx;
+}
+
+/*
+ * Free TX resources.
+ *
+ * Assumes that SGE is stopped and all interrupts are disabled.
+ */
+static void free_tx_resources(struct sge *sge)
+{
+       struct pci_dev *pdev = sge->adapter->pdev;
+       unsigned int size, i;
+
+       for (i = 0; i < SGE_CMDQ_N; i++) {
+               struct cmdQ *q = &sge->cmdQ[i];
+
+               if (q->centries) {
+                       if (q->in_use)
+                               free_cmdQ_buffers(sge, q, q->in_use);
+                       kfree(q->centries);
+               }
+               if (q->entries) {
+                       size = sizeof(struct cmdQ_e) * q->size;
+                       pci_free_consistent(pdev, size, q->entries,
+                                           q->dma_addr);
+               }
+       }
+}
+
+/*
+ * Allocates basic TX resources, consisting of memory mapped command Qs.
+ */
+static int alloc_tx_resources(struct sge *sge, struct sge_params *p)
+{
+       struct pci_dev *pdev = sge->adapter->pdev;
+       unsigned int size, i;
+
+       for (i = 0; i < SGE_CMDQ_N; i++) {
+               struct cmdQ *q = &sge->cmdQ[i];
+
+               q->genbit = 1;
+               q->sop = 1;
+               q->size = p->cmdQ_size[i];
+               q->in_use = 0;
+               q->status = 0;
+               q->processed = q->cleaned = 0;
+               q->stop_thres = 0;
+               spin_lock_init(&q->lock);
+               size = sizeof(struct cmdQ_e) * q->size;
+               q->entries = (struct cmdQ_e *)
+                             pci_alloc_consistent(pdev, size, &q->dma_addr);
+               if (!q->entries)
+                       goto err_no_mem;
+               memset(q->entries, 0, size);
+               size = sizeof(struct cmdQ_ce) * q->size;
+               q->centries = kmalloc(size, GFP_KERNEL);
+               if (!q->centries)
+                       goto err_no_mem;
+               memset(q->centries, 0, size);
+       }
+
+       /*
+        * CommandQ 0 handles Ethernet and TOE packets, while queue 1 is TOE
+        * only.  For queue 0 set the stop threshold so we can handle one more
+        * packet from each port, plus reserve an additional 24 entries for
+        * Ethernet packets only.  Queue 1 never suspends nor do we reserve
+        * space for Ethernet packets.
+        */
+       sge->cmdQ[0].stop_thres = sge->adapter->params.nports *
+               (MAX_SKB_FRAGS + 1);
+       return 0;
+
+err_no_mem:
+       free_tx_resources(sge);
+       return -ENOMEM;
+}
+
+static inline void setup_ring_params(struct adapter *adapter, u64 addr,
+                                    u32 size, int base_reg_lo,
+                                    int base_reg_hi, int size_reg)
+{
+       writel((u32)addr, adapter->regs + base_reg_lo);
+       writel(addr >> 32, adapter->regs + base_reg_hi);
+       writel(size, adapter->regs + size_reg);
+}
+
+/*
+ * Enable/disable VLAN acceleration.
+ */
+void t1_set_vlan_accel(struct adapter *adapter, int on_off)
+{
+       struct sge *sge = adapter->sge;
+
+       sge->sge_control &= ~F_VLAN_XTRACT;
+       if (on_off)
+               sge->sge_control |= F_VLAN_XTRACT;
+       if (adapter->open_device_map) {
+               writel(sge->sge_control, adapter->regs + A_SG_CONTROL);
+               readl(adapter->regs + A_SG_CONTROL); /* flush */
+       }
+}
+
+/*
+ * Programs the various SGE registers. However, the engine is not yet enabled,
+ * but sge->sge_control is setup and ready to go.
+ */
+static void configure_sge(struct sge *sge, struct sge_params *p)
+{
+       struct adapter *ap = sge->adapter;
+       
+       writel(0, ap->regs + A_SG_CONTROL);
+       setup_ring_params(ap, sge->cmdQ[0].dma_addr, sge->cmdQ[0].size,
+                         A_SG_CMD0BASELWR, A_SG_CMD0BASEUPR, A_SG_CMD0SIZE);
+       setup_ring_params(ap, sge->cmdQ[1].dma_addr, sge->cmdQ[1].size,
+                         A_SG_CMD1BASELWR, A_SG_CMD1BASEUPR, A_SG_CMD1SIZE);
+       setup_ring_params(ap, sge->freelQ[0].dma_addr,
+                         sge->freelQ[0].size, A_SG_FL0BASELWR,
+                         A_SG_FL0BASEUPR, A_SG_FL0SIZE);
+       setup_ring_params(ap, sge->freelQ[1].dma_addr,
+                         sge->freelQ[1].size, A_SG_FL1BASELWR,
+                         A_SG_FL1BASEUPR, A_SG_FL1SIZE);
+
+       /* The threshold comparison uses <. */
+       writel(SGE_RX_SM_BUF_SIZE + 1, ap->regs + A_SG_FLTHRESHOLD);
+
+       setup_ring_params(ap, sge->respQ.dma_addr, sge->respQ.size,
+                         A_SG_RSPBASELWR, A_SG_RSPBASEUPR, A_SG_RSPSIZE);
+       writel((u32)sge->respQ.size - 1, ap->regs + A_SG_RSPQUEUECREDIT);
+
+       sge->sge_control = F_CMDQ0_ENABLE | F_CMDQ1_ENABLE | F_FL0_ENABLE |
+               F_FL1_ENABLE | F_CPL_ENABLE | F_RESPONSE_QUEUE_ENABLE |
+               V_CMDQ_PRIORITY(2) | F_DISABLE_CMDQ1_GTS | F_ISCSI_COALESCE |
+               F_DISABLE_FL0_GTS | F_DISABLE_FL1_GTS |
+               V_RX_PKT_OFFSET(sge->rx_pkt_pad);
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+       sge->sge_control |= F_ENABLE_BIG_ENDIAN;
+#endif
+
+       /* Initialize no-resource timer */
+       sge->intrtimer_nres = SGE_INTRTIMER_NRES * core_ticks_per_usec(ap);
+
+       t1_sge_set_coalesce_params(sge, p);
+}
+
+/*
+ * Return the payload capacity of the jumbo free-list buffers.
+ */
+static inline unsigned int jumbo_payload_capacity(const struct sge *sge)
+{
+       return sge->freelQ[sge->jumbo_fl].rx_buffer_size -
+               sge->freelQ[sge->jumbo_fl].dma_offset -
+               sizeof(struct cpl_rx_data);
+}
+
+/*
+ * Frees all SGE related resources and the sge structure itself
+ */
+void t1_sge_destroy(struct sge *sge)
+{
+       if (sge->espibug_skb)
+               kfree_skb(sge->espibug_skb);
+
+       free_tx_resources(sge);
+       free_rx_resources(sge);
+       kfree(sge);
+}
+
+/*
+ * Allocates new RX buffers on the freelist Q (and tracks them on the freelist
+ * context Q) until the Q is full or alloc_skb fails.
+ *
+ * It is possible that the generation bits already match, indicating that the
+ * buffer is already valid and nothing needs to be done. This happens when we
+ * copied a received buffer into a new sk_buff during the interrupt processing.
+ *
+ * If the SGE doesn't automatically align packets properly (!sge->rx_pkt_pad),
+ * we specify a RX_OFFSET in order to make sure that the IP header is 4B
+ * aligned.
+ */
+static void refill_free_list(struct sge *sge, struct freelQ *q)
+{
+       struct pci_dev *pdev = sge->adapter->pdev;
+       struct freelQ_ce *ce = &q->centries[q->pidx];
+       struct freelQ_e *e = &q->entries[q->pidx];
+       unsigned int dma_len = q->rx_buffer_size - q->dma_offset;
+
+
+       while (q->credits < q->size) {
+               struct sk_buff *skb;
+               dma_addr_t mapping;
+
+               skb = alloc_skb(q->rx_buffer_size, GFP_ATOMIC);
+               if (!skb)
+                       break;
+
+               skb_reserve(skb, q->dma_offset);
+               mapping = pci_map_single(pdev, skb->data, dma_len,
+                                        PCI_DMA_FROMDEVICE);
+               ce->skb = skb;
+               pci_unmap_addr_set(ce, dma_addr, mapping);
+               pci_unmap_len_set(ce, dma_len, dma_len);
+               e->addr_lo = (u32)mapping;
+               e->addr_hi = (u64)mapping >> 32;
+               e->len_gen = V_CMD_LEN(dma_len) | V_CMD_GEN1(q->genbit);
+               wmb();
+               e->gen2 = V_CMD_GEN2(q->genbit);
+
+               e++;
+               ce++;
+               if (++q->pidx == q->size) {
+                       q->pidx = 0;
+                       q->genbit ^= 1;
+                       ce = q->centries;
+                       e = q->entries;
+               }
+               q->credits++;
+       }
+
+}
+
+/*
+ * Calls refill_free_list for both free lists. If we cannot fill at least 1/4
+ * of both rings, we go into 'few interrupt mode' in order to give the system
+ * time to free up resources.
+ */
+static void freelQs_empty(struct sge *sge)
+{
+       struct adapter *adapter = sge->adapter;
+       u32 irq_reg = readl(adapter->regs + A_SG_INT_ENABLE);
+       u32 irqholdoff_reg;
+
+       refill_free_list(sge, &sge->freelQ[0]);
+       refill_free_list(sge, &sge->freelQ[1]);
+
+       if (sge->freelQ[0].credits > (sge->freelQ[0].size >> 2) &&
+           sge->freelQ[1].credits > (sge->freelQ[1].size >> 2)) {
+               irq_reg |= F_FL_EXHAUSTED;
+               irqholdoff_reg = sge->fixed_intrtimer;
+       } else {
+               /* Clear the F_FL_EXHAUSTED interrupts for now */
+               irq_reg &= ~F_FL_EXHAUSTED;
+               irqholdoff_reg = sge->intrtimer_nres;
+       }
+       writel(irqholdoff_reg, adapter->regs + A_SG_INTRTIMER);
+       writel(irq_reg, adapter->regs + A_SG_INT_ENABLE);
+
+       /* We reenable the Qs to force a freelist GTS interrupt later */
+       doorbell_pio(adapter, F_FL0_ENABLE | F_FL1_ENABLE);
+}
+
+#define SGE_PL_INTR_MASK (F_PL_INTR_SGE_ERR | F_PL_INTR_SGE_DATA)
+#define SGE_INT_FATAL (F_RESPQ_OVERFLOW | F_PACKET_TOO_BIG | F_PACKET_MISMATCH)
+#define SGE_INT_ENABLE (F_RESPQ_EXHAUSTED | F_RESPQ_OVERFLOW | \
+                       F_FL_EXHAUSTED | F_PACKET_TOO_BIG | F_PACKET_MISMATCH)
+
+/*
+ * Disable SGE Interrupts
+ */
+void t1_sge_intr_disable(struct sge *sge)
+{
+       u32 val = readl(sge->adapter->regs + A_PL_ENABLE);
+
+       writel(val & ~SGE_PL_INTR_MASK, sge->adapter->regs + A_PL_ENABLE);
+       writel(0, sge->adapter->regs + A_SG_INT_ENABLE);
+}
+
+/*
+ * Enable SGE interrupts.
+ */
+void t1_sge_intr_enable(struct sge *sge)
+{
+       u32 en = SGE_INT_ENABLE;
+       u32 val = readl(sge->adapter->regs + A_PL_ENABLE);
+
+       if (sge->adapter->flags & TSO_CAPABLE)
+               en &= ~F_PACKET_TOO_BIG;
+       writel(en, sge->adapter->regs + A_SG_INT_ENABLE);
+       writel(val | SGE_PL_INTR_MASK, sge->adapter->regs + A_PL_ENABLE);
+}
+
+/*
+ * Clear SGE interrupts.
+ */
+void t1_sge_intr_clear(struct sge *sge)
+{
+       writel(SGE_PL_INTR_MASK, sge->adapter->regs + A_PL_CAUSE);
+       writel(0xffffffff, sge->adapter->regs + A_SG_INT_CAUSE);
+}
+
+/*
+ * SGE 'Error' interrupt handler
+ */
+int t1_sge_intr_error_handler(struct sge *sge)
+{
+       struct adapter *adapter = sge->adapter;
+       u32 cause = readl(adapter->regs + A_SG_INT_CAUSE);
+
+       if (adapter->flags & TSO_CAPABLE)
+               cause &= ~F_PACKET_TOO_BIG;
+       if (cause & F_RESPQ_EXHAUSTED)
+               sge->stats.respQ_empty++;
+       if (cause & F_RESPQ_OVERFLOW) {
+               sge->stats.respQ_overflow++;
+               CH_ALERT("%s: SGE response queue overflow\n",
+                        adapter->name);
+       }
+       if (cause & F_FL_EXHAUSTED) {
+               sge->stats.freelistQ_empty++;
+               freelQs_empty(sge);
+       }
+       if (cause & F_PACKET_TOO_BIG) {
+               sge->stats.pkt_too_big++;
+               CH_ALERT("%s: SGE max packet size exceeded\n",
+                        adapter->name);
+       }
+       if (cause & F_PACKET_MISMATCH) {
+               sge->stats.pkt_mismatch++;
+               CH_ALERT("%s: SGE packet mismatch\n", adapter->name);
+       }
+       if (cause & SGE_INT_FATAL)
+               t1_fatal_err(adapter);
+
+       writel(cause, adapter->regs + A_SG_INT_CAUSE);
+       return 0;
+}
+
+const struct sge_intr_counts *t1_sge_get_intr_counts(struct sge *sge)
+{
+       return &sge->stats;
+}
+
+const struct sge_port_stats *t1_sge_get_port_stats(struct sge *sge, int port)
+{
+       return &sge->port_stats[port];
+}
+
+/**
+ *     recycle_fl_buf - recycle a free list buffer
+ *     @fl: the free list
+ *     @idx: index of buffer to recycle
+ *
+ *     Recycles the specified buffer on the given free list by adding it at
+ *     the next available slot on the list.
+ */
+static void recycle_fl_buf(struct freelQ *fl, int idx)
+{
+       struct freelQ_e *from = &fl->entries[idx];
+       struct freelQ_e *to = &fl->entries[fl->pidx];
+
+       fl->centries[fl->pidx] = fl->centries[idx];
+       to->addr_lo = from->addr_lo;
+       to->addr_hi = from->addr_hi;
+       to->len_gen = G_CMD_LEN(from->len_gen) | V_CMD_GEN1(fl->genbit);
+       wmb();
+       to->gen2 = V_CMD_GEN2(fl->genbit);
+       fl->credits++;
+
+       if (++fl->pidx == fl->size) {
+               fl->pidx = 0;
+               fl->genbit ^= 1;
+       }
+}
+
+/**
+ *     get_packet - return the next ingress packet buffer
+ *     @pdev: the PCI device that received the packet
+ *     @fl: the SGE free list holding the packet
+ *     @len: the actual packet length, excluding any SGE padding
+ *     @dma_pad: padding at beginning of buffer left by SGE DMA
+ *     @skb_pad: padding to be used if the packet is copied
+ *     @copy_thres: length threshold under which a packet should be copied
+ *     @drop_thres: # of remaining buffers before we start dropping packets
+ *
+ *     Get the next packet from a free list and complete setup of the
+ *     sk_buff.  If the packet is small we make a copy and recycle the
+ *     original buffer, otherwise we use the original buffer itself.  If a
+ *     positive drop threshold is supplied packets are dropped and their
+ *     buffers recycled if (a) the number of remaining buffers is under the
+ *     threshold and the packet is too big to copy, or (b) the packet should
+ *     be copied but there is no memory for the copy.
+ */
+static inline struct sk_buff *get_packet(struct pci_dev *pdev,
+                                        struct freelQ *fl, unsigned int len,
+                                        int dma_pad, int skb_pad,
+                                        unsigned int copy_thres,
+                                        unsigned int drop_thres)
+{
+       struct sk_buff *skb;
+       struct freelQ_ce *ce = &fl->centries[fl->cidx];
+
+       if (len < copy_thres) {
+               skb = alloc_skb(len + skb_pad, GFP_ATOMIC);
+               if (likely(skb != NULL)) {
+                       skb_reserve(skb, skb_pad);
+                       skb_put(skb, len);
+                       pci_dma_sync_single_for_cpu(pdev,
+                                           pci_unmap_addr(ce, dma_addr),
+                                           pci_unmap_len(ce, dma_len),
+                                           PCI_DMA_FROMDEVICE);
+                       memcpy(skb->data, ce->skb->data + dma_pad, len);
+                       pci_dma_sync_single_for_device(pdev,
+                                           pci_unmap_addr(ce, dma_addr),
+                                           pci_unmap_len(ce, dma_len),
+                                           PCI_DMA_FROMDEVICE);
+               } else if (!drop_thres)
+                       goto use_orig_buf;
+
+               recycle_fl_buf(fl, fl->cidx);
+               return skb;
+       }
+
+       if (fl->credits < drop_thres) {
+               recycle_fl_buf(fl, fl->cidx);
+               return NULL;
+       }
+
+use_orig_buf:
+       pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr),
+                        pci_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE);
+       skb = ce->skb;
+       skb_reserve(skb, dma_pad);
+       skb_put(skb, len);
+       return skb;
+}
+
+/**
+ *     unexpected_offload - handle an unexpected offload packet
+ *     @adapter: the adapter
+ *     @fl: the free list that received the packet
+ *
+ *     Called when we receive an unexpected offload packet (e.g., the TOE
+ *     function is disabled or the card is a NIC).  Prints a message and
+ *     recycles the buffer.
+ */
+static void unexpected_offload(struct adapter *adapter, struct freelQ *fl)
+{
+       struct freelQ_ce *ce = &fl->centries[fl->cidx];
+       struct sk_buff *skb = ce->skb;
+
+       pci_dma_sync_single_for_cpu(adapter->pdev, pci_unmap_addr(ce, dma_addr),
+                           pci_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE);
+       CH_ERR("%s: unexpected offload packet, cmd %u\n",
+              adapter->name, *skb->data);
+       recycle_fl_buf(fl, fl->cidx);
+}
+
+/*
+ * Write the command descriptors to transmit the given skb starting at
+ * descriptor pidx with the given generation.
+ */
+static inline void write_tx_descs(struct adapter *adapter, struct sk_buff *skb,
+                                 unsigned int pidx, unsigned int gen,
+                                 struct cmdQ *q)
+{
+       dma_addr_t mapping;
+       struct cmdQ_e *e, *e1;
+       struct cmdQ_ce *ce;
+       unsigned int i, flags, nfrags = skb_shinfo(skb)->nr_frags;
+
+       mapping = pci_map_single(adapter->pdev, skb->data,
+                                skb->len - skb->data_len, PCI_DMA_TODEVICE);
+       ce = &q->centries[pidx];
+       ce->skb = NULL;
+       pci_unmap_addr_set(ce, dma_addr, mapping);
+       pci_unmap_len_set(ce, dma_len, skb->len - skb->data_len);
+
+       flags = F_CMD_DATAVALID | F_CMD_SOP | V_CMD_EOP(nfrags == 0) |
+               V_CMD_GEN2(gen);
+       e = &q->entries[pidx];
+       e->addr_lo = (u32)mapping;
+       e->addr_hi = (u64)mapping >> 32;
+       e->len_gen = V_CMD_LEN(skb->len - skb->data_len) | V_CMD_GEN1(gen);
+       for (e1 = e, i = 0; nfrags--; i++) {
+               skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+               ce++;
+               e1++;
+               if (++pidx == q->size) {
+                       pidx = 0;
+                       gen ^= 1;
+                       ce = q->centries;
+                       e1 = q->entries;
+               }
+
+               mapping = pci_map_page(adapter->pdev, frag->page,
+                                      frag->page_offset, frag->size,
+                                      PCI_DMA_TODEVICE);
+               ce->skb = NULL;
+               pci_unmap_addr_set(ce, dma_addr, mapping);
+               pci_unmap_len_set(ce, dma_len, frag->size);
+
+               e1->addr_lo = (u32)mapping;
+               e1->addr_hi = (u64)mapping >> 32;
+               e1->len_gen = V_CMD_LEN(frag->size) | V_CMD_GEN1(gen);
+               e1->flags = F_CMD_DATAVALID | V_CMD_EOP(nfrags == 0) |
+                           V_CMD_GEN2(gen);
+       }
+
+       ce->skb = skb;
+       wmb();
+       e->flags = flags;
+}
+
+/*
+ * Clean up completed Tx buffers.
+ */
+static inline void reclaim_completed_tx(struct sge *sge, struct cmdQ *q)
+{
+       unsigned int reclaim = q->processed - q->cleaned;
+
+       if (reclaim) {
+               free_cmdQ_buffers(sge, q, reclaim);
+               q->cleaned += reclaim;
+       }
+}
+
+#ifndef SET_ETHTOOL_OPS
+# define __netif_rx_complete(dev) netif_rx_complete(dev)
+#endif
+
+/*
+ * We cannot use the standard netif_rx_schedule_prep() because we have multiple
+ * ports plus the TOE all multiplexing onto a single response queue, therefore
+ * accepting new responses cannot depend on the state of any particular port.
+ * So define our own equivalent that omits the netif_running() test.
+ */
+static inline int napi_schedule_prep(struct net_device *dev)
+{
+       return !test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state);
+}
+
+
+/**
+ *     sge_rx - process an ingress ethernet packet
+ *     @sge: the sge structure
+ *     @fl: the free list that contains the packet buffer
+ *     @len: the packet length
+ *
+ *     Process an ingress ethernet pakcet and deliver it to the stack.
+ */
+static int sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
+{
+       struct sk_buff *skb;
+       struct cpl_rx_pkt *p;
+       struct adapter *adapter = sge->adapter;
+
+       sge->stats.ethernet_pkts++;
+       skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad,
+                        sge->rx_pkt_pad, 2, SGE_RX_COPY_THRES,
+                        SGE_RX_DROP_THRES);
+       if (!skb) {
+               sge->port_stats[0].rx_drops++; /* charge only port 0 for now */
+               return 0;
+       }
+
+       p = (struct cpl_rx_pkt *)skb->data;
+       skb_pull(skb, sizeof(*p));
+       skb->dev = adapter->port[p->iff].dev;
+       skb->dev->last_rx = jiffies;
+       skb->protocol = eth_type_trans(skb, skb->dev);
+       if ((adapter->flags & RX_CSUM_ENABLED) && p->csum == 0xffff &&
+           skb->protocol == htons(ETH_P_IP) &&
+           (skb->data[9] == IPPROTO_TCP || skb->data[9] == IPPROTO_UDP)) {
+               sge->port_stats[p->iff].rx_cso_good++;
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+       } else
+               skb->ip_summed = CHECKSUM_NONE;
+
+       if (unlikely(adapter->vlan_grp && p->vlan_valid)) {
+               sge->port_stats[p->iff].vlan_xtract++;
+               if (adapter->params.sge.polling)
+                       vlan_hwaccel_receive_skb(skb, adapter->vlan_grp,
+                                                ntohs(p->vlan));
+               else
+                       vlan_hwaccel_rx(skb, adapter->vlan_grp,
+                                       ntohs(p->vlan));
+       } else if (adapter->params.sge.polling)
+               netif_receive_skb(skb);
+       else
+               netif_rx(skb);
+       return 0;
+}
+
+/*
+ * Returns true if a command queue has enough available descriptors that
+ * we can resume Tx operation after temporarily disabling its packet queue.
+ */
+static inline int enough_free_Tx_descs(const struct cmdQ *q)
+{
+       unsigned int r = q->processed - q->cleaned;
+
+       return q->in_use - r < (q->size >> 1);
+}
+
+/*
+ * Called when sufficient space has become available in the SGE command queues
+ * after the Tx packet schedulers have been suspended to restart the Tx path.
+ */
+static void restart_tx_queues(struct sge *sge)
+{
+       struct adapter *adap = sge->adapter;
+
+       if (enough_free_Tx_descs(&sge->cmdQ[0])) {
+               int i;
+
+               for_each_port(adap, i) {
+                       struct net_device *nd = adap->port[i].dev;
+
+                       if (test_and_clear_bit(nd->if_port,
+                                              &sge->stopped_tx_queues) &&
+                           netif_running(nd)) {
+                               sge->stats.cmdQ_restarted[3]++;
+                               netif_wake_queue(nd);
+                       }
+               }
+       }
+}
+
+/*
+ * update_tx_info is called from the interrupt handler/NAPI to return cmdQ0 
+ * information.
+ */
+static unsigned int update_tx_info(struct adapter *adapter, 
+                                         unsigned int flags, 
+                                         unsigned int pr0)
+{
+       struct sge *sge = adapter->sge;
+       struct cmdQ *cmdq = &sge->cmdQ[0];
+
+       cmdq->processed += pr0;
+
+       if (flags & F_CMDQ0_ENABLE) {
+               clear_bit(CMDQ_STAT_RUNNING, &cmdq->status);
+       
+               if (cmdq->cleaned + cmdq->in_use != cmdq->processed &&
+                   !test_and_set_bit(CMDQ_STAT_LAST_PKT_DB, &cmdq->status)) {
+                       set_bit(CMDQ_STAT_RUNNING, &cmdq->status);
+                       writel(F_CMDQ0_ENABLE, adapter->regs + A_SG_DOORBELL);
+               }
+               flags &= ~F_CMDQ0_ENABLE;
+       }
+       
+       if (unlikely(sge->stopped_tx_queues != 0))
+               restart_tx_queues(sge);
+
+       return flags;
+}
+
+/*
+ * Process SGE responses, up to the supplied budget.  Returns the number of
+ * responses processed.  A negative budget is effectively unlimited.
+ */
+static int process_responses(struct adapter *adapter, int budget)
+{
+       struct sge *sge = adapter->sge;
+       struct respQ *q = &sge->respQ;
+       struct respQ_e *e = &q->entries[q->cidx];
+       int budget_left = budget;
+       unsigned int flags = 0;
+       unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0};
+       
+
+       while (likely(budget_left && e->GenerationBit == q->genbit)) {
+               flags |= e->Qsleeping;
+               
+               cmdq_processed[0] += e->Cmdq0CreditReturn;
+               cmdq_processed[1] += e->Cmdq1CreditReturn;
+               
+               /* We batch updates to the TX side to avoid cacheline
+                * ping-pong of TX state information on MP where the sender
+                * might run on a different CPU than this function...
+                */
+               if (unlikely(flags & F_CMDQ0_ENABLE || cmdq_processed[0] > 64)) {
+                       flags = update_tx_info(adapter, flags, cmdq_processed[0]);
+                       cmdq_processed[0] = 0;
+               }
+               if (unlikely(cmdq_processed[1] > 16)) {
+                       sge->cmdQ[1].processed += cmdq_processed[1];
+                       cmdq_processed[1] = 0;
+               }
+               if (likely(e->DataValid)) {
+                       struct freelQ *fl = &sge->freelQ[e->FreelistQid];
+
+                       if (unlikely(!e->Sop || !e->Eop))
+                               BUG();
+                       if (unlikely(e->Offload))
+                               unexpected_offload(adapter, fl);
+                       else
+                               sge_rx(sge, fl, e->BufferLength);
+
+                       /*
+                        * Note: this depends on each packet consuming a
+                        * single free-list buffer; cf. the BUG above.
+                        */
+                       if (++fl->cidx == fl->size)
+                               fl->cidx = 0;
+                       if (unlikely(--fl->credits <
+                                    fl->size - SGE_FREEL_REFILL_THRESH))
+                               refill_free_list(sge, fl);
+               } else
+                       sge->stats.pure_rsps++;
+
+               e++;
+               if (unlikely(++q->cidx == q->size)) {
+                       q->cidx = 0;
+                       q->genbit ^= 1;
+                       e = q->entries;
+               }
+               prefetch(e);
+
+               if (++q->credits > SGE_RESPQ_REPLENISH_THRES) {
+                       writel(q->credits, adapter->regs + A_SG_RSPQUEUECREDIT);
+                       q->credits = 0;
+               }
+               --budget_left;
+       }
+
+       flags = update_tx_info(adapter, flags, cmdq_processed[0]); 
+       sge->cmdQ[1].processed += cmdq_processed[1];
+
+       budget -= budget_left;
+       return budget;
+}
+
+/*
+ * A simpler version of process_responses() that handles only pure (i.e.,
+ * non data-carrying) responses.  Such respones are too light-weight to justify
+ * calling a softirq when using NAPI, so we handle them specially in hard
+ * interrupt context.  The function is called with a pointer to a response,
+ * which the caller must ensure is a valid pure response.  Returns 1 if it
+ * encounters a valid data-carrying response, 0 otherwise.
+ */
+static int process_pure_responses(struct adapter *adapter, struct respQ_e *e)
+{
+       struct sge *sge = adapter->sge;
+       struct respQ *q = &sge->respQ;
+       unsigned int flags = 0;
+       unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0};
+
+       do {
+               flags |= e->Qsleeping;
+
+               cmdq_processed[0] += e->Cmdq0CreditReturn;
+               cmdq_processed[1] += e->Cmdq1CreditReturn;
+               
+               e++;
+               if (unlikely(++q->cidx == q->size)) {
+                       q->cidx = 0;
+                       q->genbit ^= 1;
+                       e = q->entries;
+               }
+               prefetch(e);
+
+               if (++q->credits > SGE_RESPQ_REPLENISH_THRES) {
+                       writel(q->credits, adapter->regs + A_SG_RSPQUEUECREDIT);
+                       q->credits = 0;
+               }
+               sge->stats.pure_rsps++;
+       } while (e->GenerationBit == q->genbit && !e->DataValid);
+
+       flags = update_tx_info(adapter, flags, cmdq_processed[0]); 
+       sge->cmdQ[1].processed += cmdq_processed[1];
+
+       return e->GenerationBit == q->genbit;
+}
+
+/*
+ * Handler for new data events when using NAPI.  This does not need any locking
+ * or protection from interrupts as data interrupts are off at this point and
+ * other adapter interrupts do not interfere.
+ */
+static int t1_poll(struct net_device *dev, int *budget)
+{
+       struct adapter *adapter = dev->priv;
+       int effective_budget = min(*budget, dev->quota);
+
+       int work_done = process_responses(adapter, effective_budget);
+       *budget -= work_done;
+       dev->quota -= work_done;
+
+       if (work_done >= effective_budget)
+               return 1;
+
+       __netif_rx_complete(dev);
+
+       /*
+        * Because we don't atomically flush the following write it is
+        * possible that in very rare cases it can reach the device in a way
+        * that races with a new response being written plus an error interrupt
+        * causing the NAPI interrupt handler below to return unhandled status
+        * to the OS.  To protect against this would require flushing the write
+        * and doing both the write and the flush with interrupts off.  Way too
+        * expensive and unjustifiable given the rarity of the race.
+        */
+       writel(adapter->sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
+       return 0;
+}
+
+/*
+ * Returns true if the device is already scheduled for polling.
+ */
+static inline int napi_is_scheduled(struct net_device *dev)
+{
+       return test_bit(__LINK_STATE_RX_SCHED, &dev->state);
+}
+
+/*
+ * NAPI version of the main interrupt handler.
+ */
+static irqreturn_t t1_interrupt_napi(int irq, void *data, struct pt_regs *regs)
+{
+       int handled;
+       struct adapter *adapter = data;
+       struct sge *sge = adapter->sge;
+       struct respQ *q = &adapter->sge->respQ;
+
+       /*
+        * Clear the SGE_DATA interrupt first thing.  Normally the NAPI
+        * handler has control of the response queue and the interrupt handler
+        * can look at the queue reliably only once it knows NAPI is off.
+        * We can't wait that long to clear the SGE_DATA interrupt because we
+        * could race with t1_poll rearming the SGE interrupt, so we need to
+        * clear the interrupt speculatively and really early on.
+        */
+       writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
+
+       spin_lock(&adapter->async_lock);
+       if (!napi_is_scheduled(sge->netdev)) {
+               struct respQ_e *e = &q->entries[q->cidx];
+
+               if (e->GenerationBit == q->genbit) {
+                       if (e->DataValid ||
+                           process_pure_responses(adapter, e)) {
+                               if (likely(napi_schedule_prep(sge->netdev)))
+                                       __netif_rx_schedule(sge->netdev);
+                               else
+                                       printk(KERN_CRIT
+                                              "NAPI schedule failure!\n");
+                       } else
+                       writel(q->cidx, adapter->regs + A_SG_SLEEPING);
+                       handled = 1;
+                       goto unlock;
+               } else
+               writel(q->cidx, adapter->regs + A_SG_SLEEPING);
+       }  else
+       if (readl(adapter->regs + A_PL_CAUSE) & F_PL_INTR_SGE_DATA)
+               printk(KERN_ERR "data interrupt while NAPI running\n");
+       
+       handled = t1_slow_intr_handler(adapter);
+       if (!handled)
+               sge->stats.unhandled_irqs++;
+ unlock:
+       spin_unlock(&adapter->async_lock);
+       return IRQ_RETVAL(handled != 0);
+}
+
+/*
+ * Main interrupt handler, optimized assuming that we took a 'DATA'
+ * interrupt.
+ *
+ * 1. Clear the interrupt
+ * 2. Loop while we find valid descriptors and process them; accumulate
+ *      information that can be processed after the loop
+ * 3. Tell the SGE at which index we stopped processing descriptors
+ * 4. Bookkeeping; free TX buffers, ring doorbell if there are any
+ *      outstanding TX buffers waiting, replenish RX buffers, potentially
+ *      reenable upper layers if they were turned off due to lack of TX
+ *      resources which are available again.
+ * 5. If we took an interrupt, but no valid respQ descriptors was found we
+ *      let the slow_intr_handler run and do error handling.
+ */
+static irqreturn_t t1_interrupt(int irq, void *cookie, struct pt_regs *regs)
+{
+       int work_done;
+       struct respQ_e *e;
+       struct adapter *adapter = cookie;
+       struct respQ *Q = &adapter->sge->respQ;
+
+       spin_lock(&adapter->async_lock);
+       e = &Q->entries[Q->cidx];
+       prefetch(e);
+
+       writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
+
+       if (likely(e->GenerationBit == Q->genbit))
+               work_done = process_responses(adapter, -1);
+       else
+               work_done = t1_slow_intr_handler(adapter);
+
+       /*
+        * The unconditional clearing of the PL_CAUSE above may have raced
+        * with DMA completion and the corresponding generation of a response
+        * to cause us to miss the resulting data interrupt.  The next write
+        * is also unconditional to recover the missed interrupt and render
+        * this race harmless.
+        */
+       writel(Q->cidx, adapter->regs + A_SG_SLEEPING);
+
+       if (!work_done)
+               adapter->sge->stats.unhandled_irqs++;
+       spin_unlock(&adapter->async_lock);
+       return IRQ_RETVAL(work_done != 0);
+}
+
+intr_handler_t t1_select_intr_handler(adapter_t *adapter)
+{
+       return adapter->params.sge.polling ? t1_interrupt_napi : t1_interrupt;
+}
+
+/*
+ * Enqueues the sk_buff onto the cmdQ[qid] and has hardware fetch it.
+ *
+ * The code figures out how many entries the sk_buff will require in the
+ * cmdQ and updates the cmdQ data structure with the state once the enqueue
+ * has complete. Then, it doesn't access the global structure anymore, but
+ * uses the corresponding fields on the stack. In conjuction with a spinlock
+ * around that code, we can make the function reentrant without holding the
+ * lock when we actually enqueue (which might be expensive, especially on
+ * architectures with IO MMUs).
+ *
+ * This runs with softirqs disabled.
+ */
+unsigned int t1_sge_tx(struct sk_buff *skb, struct adapter *adapter,
+                      unsigned int qid, struct net_device *dev)
+{
+       struct sge *sge = adapter->sge;
+       struct cmdQ *q = &sge->cmdQ[qid];
+       unsigned int credits, pidx, genbit, count;
+
+       spin_lock(&q->lock);
+       reclaim_completed_tx(sge, q);
+
+       pidx = q->pidx;
+       credits = q->size - q->in_use;
+       count = 1 + skb_shinfo(skb)->nr_frags;
+
+       {       /* Ethernet packet */
+               if (unlikely(credits < count)) {
+                       netif_stop_queue(dev);
+                       set_bit(dev->if_port, &sge->stopped_tx_queues);
+                       sge->stats.cmdQ_full[3]++;
+                       spin_unlock(&q->lock);
+                       CH_ERR("%s: Tx ring full while queue awake!\n",
+                              adapter->name);
+                       return 1;
+               }
+               if (unlikely(credits - count < q->stop_thres)) {
+                       sge->stats.cmdQ_full[3]++;
+                       netif_stop_queue(dev);
+                       set_bit(dev->if_port, &sge->stopped_tx_queues);
+               }
+       }
+       q->in_use += count;
+       genbit = q->genbit;
+       q->pidx += count;
+       if (q->pidx >= q->size) {
+               q->pidx -= q->size;
+               q->genbit ^= 1;
+       }
+       spin_unlock(&q->lock);
+
+       write_tx_descs(adapter, skb, pidx, genbit, q);
+
+       /*
+        * We always ring the doorbell for cmdQ1.  For cmdQ0, we only ring
+        * the doorbell if the Q is asleep. There is a natural race, where
+        * the hardware is going to sleep just after we checked, however,
+        * then the interrupt handler will detect the outstanding TX packet
+        * and ring the doorbell for us.
+        */
+       if (qid)
+               doorbell_pio(adapter, F_CMDQ1_ENABLE);
+       else {
+               clear_bit(CMDQ_STAT_LAST_PKT_DB, &q->status);
+               if (test_and_set_bit(CMDQ_STAT_RUNNING, &q->status) == 0) {
+                       set_bit(CMDQ_STAT_LAST_PKT_DB, &q->status);
+                       writel(F_CMDQ0_ENABLE, adapter->regs + A_SG_DOORBELL);
+               }
+       }
+       return 0;
+}
+
+#define MK_ETH_TYPE_MSS(type, mss) (((mss) & 0x3FFF) | ((type) << 14))
+
+/*
+ *     eth_hdr_len - return the length of an Ethernet header
+ *     @data: pointer to the start of the Ethernet header
+ *
+ *     Returns the length of an Ethernet header, including optional VLAN tag.
+ */
+static inline int eth_hdr_len(const void *data)
+{
+       const struct ethhdr *e = data;
+
+       return e->h_proto == htons(ETH_P_8021Q) ? VLAN_ETH_HLEN : ETH_HLEN;
+}
+
+/*
+ * Adds the CPL header to the sk_buff and passes it to t1_sge_tx.
+ */
+int t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct adapter *adapter = dev->priv;
+       struct sge_port_stats *st = &adapter->sge->port_stats[dev->if_port];
+       struct sge *sge = adapter->sge;
+       struct cpl_tx_pkt *cpl;
+
+#ifdef NETIF_F_TSO
+       if (skb_shinfo(skb)->tso_size) {
+               int eth_type;
+               struct cpl_tx_pkt_lso *hdr;
+
+               st->tso++;
+
+               eth_type = skb->nh.raw - skb->data == ETH_HLEN ?
+                       CPL_ETH_II : CPL_ETH_II_VLAN;
+
+               hdr = (struct cpl_tx_pkt_lso *)skb_push(skb, sizeof(*hdr));
+               hdr->opcode = CPL_TX_PKT_LSO;
+               hdr->ip_csum_dis = hdr->l4_csum_dis = 0;
+               hdr->ip_hdr_words = skb->nh.iph->ihl;
+               hdr->tcp_hdr_words = skb->h.th->doff;
+               hdr->eth_type_mss = htons(MK_ETH_TYPE_MSS(eth_type,
+                                               skb_shinfo(skb)->tso_size));
+               hdr->len = htonl(skb->len - sizeof(*hdr));
+               cpl = (struct cpl_tx_pkt *)hdr;
+               sge->stats.tx_lso_pkts++;
+       } else
+#endif
+       {
+               /*
+                * Packets shorter than ETH_HLEN can break the MAC, drop them
+                * early.  Also, we may get oversized packets because some
+                * parts of the kernel don't handle our unusual hard_header_len
+                * right, drop those too.
+                */
+               if (unlikely(skb->len < ETH_HLEN ||
+                            skb->len > dev->mtu + eth_hdr_len(skb->data))) {
+                       dev_kfree_skb_any(skb);
+                       return NET_XMIT_SUCCESS;
+               }
+
+               /*
+                * We are using a non-standard hard_header_len and some kernel
+                * components, such as pktgen, do not handle it right.
+                * Complain when this happens but try to fix things up.
+                */
+               if (unlikely(skb_headroom(skb) <
+                            dev->hard_header_len - ETH_HLEN)) {
+                       struct sk_buff *orig_skb = skb;
+
+                       if (net_ratelimit())
+                               printk(KERN_ERR "%s: inadequate headroom in "
+                                      "Tx packet\n", dev->name);
+                       skb = skb_realloc_headroom(skb, sizeof(*cpl));
+                       dev_kfree_skb_any(orig_skb);
+                       if (!skb)
+                               return -ENOMEM;
+               }
+
+               if (!(adapter->flags & UDP_CSUM_CAPABLE) &&
+                   skb->ip_summed == CHECKSUM_HW &&
+                   skb->nh.iph->protocol == IPPROTO_UDP)
+                       if (unlikely(skb_checksum_help(skb, 0))) {
+                               dev_kfree_skb_any(skb);
+                               return -ENOMEM;
+                       }
+
+               /* Hmmm, assuming to catch the gratious arp... and we'll use
+                * it to flush out stuck espi packets...
+                 */
+               if (unlikely(!adapter->sge->espibug_skb)) {
+                       if (skb->protocol == htons(ETH_P_ARP) &&
+                           skb->nh.arph->ar_op == htons(ARPOP_REQUEST)) {
+                               adapter->sge->espibug_skb = skb;
+                               /* We want to re-use this skb later. We
+                                * simply bump the reference count and it
+                                * will not be freed...
+                                */
+                               skb = skb_get(skb);
+                       }
+               }
+
+               cpl = (struct cpl_tx_pkt *)__skb_push(skb, sizeof(*cpl));
+               cpl->opcode = CPL_TX_PKT;
+               cpl->ip_csum_dis = 1;    /* SW calculates IP csum */
+               cpl->l4_csum_dis = skb->ip_summed == CHECKSUM_HW ? 0 : 1;
+               /* the length field isn't used so don't bother setting it */
+
+               st->tx_cso += (skb->ip_summed == CHECKSUM_HW);
+               sge->stats.tx_do_cksum += (skb->ip_summed == CHECKSUM_HW);
+               sge->stats.tx_reg_pkts++;
+       }
+       cpl->iff = dev->if_port;
+
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+       if (adapter->vlan_grp && vlan_tx_tag_present(skb)) {
+               cpl->vlan_valid = 1;
+               cpl->vlan = htons(vlan_tx_tag_get(skb));
+               st->vlan_insert++;
+       } else
+#endif
+               cpl->vlan_valid = 0;
+
+       dev->trans_start = jiffies;
+       return t1_sge_tx(skb, adapter, 0, dev);
+}
+
+/*
+ * Callback for the Tx buffer reclaim timer.  Runs with softirqs disabled.
+ */
+static void sge_tx_reclaim_cb(unsigned long data)
+{
+       int i;
+       struct sge *sge = (struct sge *)data;
+
+       for (i = 0; i < SGE_CMDQ_N; ++i) {
+               struct cmdQ *q = &sge->cmdQ[i];
+
+               if (!spin_trylock(&q->lock))
+                       continue;
+
+               reclaim_completed_tx(sge, q);
+               if (i == 0 && q->in_use)   /* flush pending credits */
+                       writel(F_CMDQ0_ENABLE,
+                               sge->adapter->regs + A_SG_DOORBELL);
+
+               spin_unlock(&q->lock);
+       }
+       mod_timer(&sge->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD);
+}
+
+/*
+ * Propagate changes of the SGE coalescing parameters to the HW.
+ */
+int t1_sge_set_coalesce_params(struct sge *sge, struct sge_params *p)
+{
+       sge->netdev->poll = t1_poll;
+       sge->fixed_intrtimer = p->rx_coalesce_usecs *
+               core_ticks_per_usec(sge->adapter);
+       writel(sge->fixed_intrtimer, sge->adapter->regs + A_SG_INTRTIMER);
+       return 0;
+}
+
+/*
+ * Allocates both RX and TX resources and configures the SGE. However,
+ * the hardware is not enabled yet.
+ */
+int t1_sge_configure(struct sge *sge, struct sge_params *p)
+{
+       if (alloc_rx_resources(sge, p))
+               return -ENOMEM;
+       if (alloc_tx_resources(sge, p)) {
+               free_rx_resources(sge);
+               return -ENOMEM;
+       }
+       configure_sge(sge, p);
+
+       /*
+        * Now that we have sized the free lists calculate the payload
+        * capacity of the large buffers.  Other parts of the driver use
+        * this to set the max offload coalescing size so that RX packets
+        * do not overflow our large buffers.
+        */
+       p->large_buf_capacity = jumbo_payload_capacity(sge);
+       return 0;
+}
+
+/*
+ * Disables the DMA engine.
+ */
+void t1_sge_stop(struct sge *sge)
+{
+       writel(0, sge->adapter->regs + A_SG_CONTROL);
+       (void) readl(sge->adapter->regs + A_SG_CONTROL); /* flush */
+       if (is_T2(sge->adapter))
+               del_timer_sync(&sge->espibug_timer);
+       del_timer_sync(&sge->tx_reclaim_timer);
+}
+
+/*
+ * Enables the DMA engine.
+ */
+void t1_sge_start(struct sge *sge)
+{
+       refill_free_list(sge, &sge->freelQ[0]);
+       refill_free_list(sge, &sge->freelQ[1]);
+
+       writel(sge->sge_control, sge->adapter->regs + A_SG_CONTROL);
+       doorbell_pio(sge->adapter, F_FL0_ENABLE | F_FL1_ENABLE);
+       (void) readl(sge->adapter->regs + A_SG_CONTROL); /* flush */
+
+       mod_timer(&sge->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD);
+
+       if (is_T2(sge->adapter)) 
+               mod_timer(&sge->espibug_timer, jiffies + sge->espibug_timeout);
+}
+
+/*
+ * Callback for the T2 ESPI 'stuck packet feature' workaorund
+ */
+static void espibug_workaround(void *data)
+{
+       struct adapter *adapter = (struct adapter *)data;
+       struct sge *sge = adapter->sge;
+
+       if (netif_running(adapter->port[0].dev)) {
+               struct sk_buff *skb = sge->espibug_skb;
+
+               u32 seop = t1_espi_get_mon(adapter, 0x930, 0);
+
+               if ((seop & 0xfff0fff) == 0xfff && skb) {
+                       if (!skb->cb[0]) {
+                               u8 ch_mac_addr[ETH_ALEN] =
+                                   {0x0, 0x7, 0x43, 0x0, 0x0, 0x0};
+                               memcpy(skb->data + sizeof(struct cpl_tx_pkt),
+                                   ch_mac_addr, ETH_ALEN);
+                               memcpy(skb->data + skb->len - 10, ch_mac_addr,
+                                   ETH_ALEN);
+                               skb->cb[0] = 0xff;
+                       }
+
+                       /* bump the reference count to avoid freeing of the
+                        * skb once the DMA has completed.
+                        */
+                       skb = skb_get(skb);
+                       t1_sge_tx(skb, adapter, 0, adapter->port[0].dev);
+               }
+       }
+       mod_timer(&sge->espibug_timer, jiffies + sge->espibug_timeout);
+}
+
+/*
+ * Creates a t1_sge structure and returns suggested resource parameters.
+ */
+struct sge * __devinit t1_sge_create(struct adapter *adapter,
+                                    struct sge_params *p)
+{
+       struct sge *sge = kmalloc(sizeof(*sge), GFP_KERNEL);
+
+       if (!sge)
+               return NULL;
+       memset(sge, 0, sizeof(*sge));
+
+       sge->adapter = adapter;
+       sge->netdev = adapter->port[0].dev;
+       sge->rx_pkt_pad = t1_is_T1B(adapter) ? 0 : 2;
+       sge->jumbo_fl = t1_is_T1B(adapter) ? 1 : 0;
+
+       init_timer(&sge->tx_reclaim_timer);
+       sge->tx_reclaim_timer.data = (unsigned long)sge;
+       sge->tx_reclaim_timer.function = sge_tx_reclaim_cb;
+
+       if (is_T2(sge->adapter)) {
+               init_timer(&sge->espibug_timer);
+               sge->espibug_timer.function = (void *)&espibug_workaround;
+               sge->espibug_timer.data = (unsigned long)sge->adapter;
+               sge->espibug_timeout = 1;
+       }
+        
+
+       p->cmdQ_size[0] = SGE_CMDQ0_E_N;
+       p->cmdQ_size[1] = SGE_CMDQ1_E_N;
+       p->freelQ_size[!sge->jumbo_fl] = SGE_FREEL_SIZE;
+       p->freelQ_size[sge->jumbo_fl] = SGE_JUMBO_FREEL_SIZE;
+       p->rx_coalesce_usecs =  50;
+       p->coalesce_enable = 0;
+       p->sample_interval_usecs = 0;
+       p->polling = 0;
+
+       return sge;
+}
diff --git a/drivers/net/chelsio/sge.h b/drivers/net/chelsio/sge.h
new file mode 100644 (file)
index 0000000..434b255
--- /dev/null
@@ -0,0 +1,105 @@
+/*****************************************************************************
+ *                                                                           *
+ * File: sge.h                                                               *
+ * $Revision: 1.11 $                                                          *
+ * $Date: 2005/06/21 22:10:55 $                                              *
+ * Description:                                                              *
+ *  part of the Chelsio 10Gb Ethernet Driver.                                *
+ *                                                                           *
+ * This program is free software; you can redistribute it and/or modify      *
+ * it under the terms of the GNU General Public License, version 2, as       *
+ * published by the Free Software Foundation.                                *
+ *                                                                           *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED    *
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF      *
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.                     *
+ *                                                                           *
+ * http://www.chelsio.com                                                    *
+ *                                                                           *
+ * Copyright (c) 2003 - 2005 Chelsio Communications, Inc.                    *
+ * All rights reserved.                                                      *
+ *                                                                           *
+ * Maintainers: maintainers@chelsio.com                                      *
+ *                                                                           *
+ * Authors: Dimitrios Michailidis   <dm@chelsio.com>                         *
+ *          Tina Yang               <tainay@chelsio.com>                     *
+ *          Felix Marti             <felix@chelsio.com>                      *
+ *          Scott Bardone           <sbardone@chelsio.com>                   *
+ *          Kurt Ottaway            <kottaway@chelsio.com>                   *
+ *          Frank DiMambro          <frank@chelsio.com>                      *
+ *                                                                           *
+ * History:                                                                  *
+ *                                                                           *
+ ****************************************************************************/
+
+#ifndef _CXGB_SGE_H_
+#define _CXGB_SGE_H_
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <asm/byteorder.h>
+
+#ifndef IRQ_RETVAL
+#define IRQ_RETVAL(x)
+typedef void irqreturn_t;
+#endif
+
+typedef irqreturn_t (*intr_handler_t)(int, void *, struct pt_regs *);
+
+struct sge_intr_counts {
+       unsigned int respQ_empty;      /* # times respQ empty */
+       unsigned int respQ_overflow;   /* # respQ overflow (fatal) */
+       unsigned int freelistQ_empty;  /* # times freelist empty */
+       unsigned int pkt_too_big;      /* packet too large (fatal) */
+       unsigned int pkt_mismatch;
+       unsigned int cmdQ_full[3];     /* not HW IRQ, host cmdQ[] full */
+       unsigned int cmdQ_restarted[3];/* # of times cmdQ X was restarted */
+       unsigned int ethernet_pkts;    /* # of Ethernet packets received */
+       unsigned int offload_pkts;     /* # of offload packets received */
+       unsigned int offload_bundles;  /* # of offload pkt bundles delivered */
+       unsigned int pure_rsps;        /* # of non-payload responses */
+       unsigned int unhandled_irqs;   /* # of unhandled interrupts */
+       unsigned int tx_ipfrags;
+       unsigned int tx_reg_pkts;
+       unsigned int tx_lso_pkts;
+       unsigned int tx_do_cksum;
+};
+
+struct sge_port_stats {
+       unsigned long rx_cso_good;     /* # of successful RX csum offloads */
+       unsigned long tx_cso;          /* # of TX checksum offloads */
+       unsigned long vlan_xtract;     /* # of VLAN tag extractions */
+       unsigned long vlan_insert;     /* # of VLAN tag extractions */
+       unsigned long tso;             /* # of TSO requests */
+       unsigned long rx_drops;        /* # of packets dropped due to no mem */
+};
+
+struct sk_buff;
+struct net_device;
+struct adapter;
+struct sge_params;
+struct sge;
+
+struct sge *t1_sge_create(struct adapter *, struct sge_params *);
+int t1_sge_configure(struct sge *, struct sge_params *);
+int t1_sge_set_coalesce_params(struct sge *, struct sge_params *);
+void t1_sge_destroy(struct sge *);
+intr_handler_t t1_select_intr_handler(adapter_t *adapter);
+unsigned int t1_sge_tx(struct sk_buff *skb, struct adapter *adapter,
+                      unsigned int qid, struct net_device *netdev);
+int t1_start_xmit(struct sk_buff *skb, struct net_device *dev);
+void t1_set_vlan_accel(struct adapter *adapter, int on_off);
+void t1_sge_start(struct sge *);
+void t1_sge_stop(struct sge *);
+int t1_sge_intr_error_handler(struct sge *);
+void t1_sge_intr_enable(struct sge *);
+void t1_sge_intr_disable(struct sge *);
+void t1_sge_intr_clear(struct sge *);
+const struct sge_intr_counts *t1_sge_get_intr_counts(struct sge *sge);
+const struct sge_port_stats *t1_sge_get_port_stats(struct sge *sge, int port);
+
+#endif /* _CXGB_SGE_H_ */
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
new file mode 100644 (file)
index 0000000..1ebb5d1
--- /dev/null
@@ -0,0 +1,812 @@
+/*****************************************************************************
+ *                                                                           *
+ * File: subr.c                                                              *
+ * $Revision: 1.27 $                                                         *
+ * $Date: 2005/06/22 01:08:36 $                                              *
+ * Description:                                                              *
+ *  Various subroutines (intr,pio,etc.) used by Chelsio 10G Ethernet driver. *
+ *  part of the Chelsio 10Gb Ethernet Driver.                                *
+ *                                                                           *
+ * This program is free software; you can redistribute it and/or modify      *
+ * it under the terms of the GNU General Public License, version 2, as       *
+ * published by the Free Software Foundation.                                *
+ *                                                                           *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED    *
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF      *
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.                     *
+ *                                                                           *
+ * http://www.chelsio.com                                                    *
+ *                                                                           *
+ * Copyright (c) 2003 - 2005 Chelsio Communications, Inc.                    *
+ * All rights reserved.                                                      *
+ *                                                                           *
+ * Maintainers: maintainers@chelsio.com                                      *
+ *                                                                           *
+ * Authors: Dimitrios Michailidis   <dm@chelsio.com>                         *
+ *          Tina Yang               <tainay@chelsio.com>                     *
+ *          Felix Marti             <felix@chelsio.com>                      *
+ *          Scott Bardone           <sbardone@chelsio.com>                   *
+ *          Kurt Ottaway            <kottaway@chelsio.com>                   *
+ *          Frank DiMambro          <frank@chelsio.com>                      *
+ *                                                                           *
+ * History:                                                                  *
+ *                                                                           *
+ ****************************************************************************/
+
+#include "common.h"
+#include "elmer0.h"
+#include "regs.h"
+#include "gmac.h"
+#include "cphy.h"
+#include "sge.h"
+#include "espi.h"
+
+/**
+ *     t1_wait_op_done - wait until an operation is completed
+ *     @adapter: the adapter performing the operation
+ *     @reg: the register to check for completion
+ *     @mask: a single-bit field within @reg that indicates completion
+ *     @polarity: the value of the field when the operation is completed
+ *     @attempts: number of check iterations
+ *      @delay: delay in usecs between iterations
+ *
+ *     Wait until an operation is completed by checking a bit in a register
+ *     up to @attempts times.  Returns %0 if the operation completes and %1
+ *     otherwise.
+ */
+static int t1_wait_op_done(adapter_t *adapter, int reg, u32 mask, int polarity,
+                   int attempts, int delay)
+{
+       while (1) {
+               u32 val = readl(adapter->regs + reg) & mask;
+
+               if (!!val == polarity)
+                       return 0;
+               if (--attempts == 0)
+                       return 1;
+               if (delay)
+                       udelay(delay);
+       }
+}
+
+#define TPI_ATTEMPTS 50
+
+/*
+ * Write a register over the TPI interface (unlocked and locked versions).
+ */
+static int __t1_tpi_write(adapter_t *adapter, u32 addr, u32 value)
+{
+       int tpi_busy;
+
+       writel(addr, adapter->regs + A_TPI_ADDR);
+       writel(value, adapter->regs + A_TPI_WR_DATA);
+       writel(F_TPIWR, adapter->regs + A_TPI_CSR);
+
+       tpi_busy = t1_wait_op_done(adapter, A_TPI_CSR, F_TPIRDY, 1,
+                                  TPI_ATTEMPTS, 3);
+       if (tpi_busy)
+               CH_ALERT("%s: TPI write to 0x%x failed\n",
+                        adapter->name, addr);
+       return tpi_busy;
+}
+
+int t1_tpi_write(adapter_t *adapter, u32 addr, u32 value)
+{
+       int ret;
+
+       spin_lock(&(adapter)->tpi_lock);
+       ret = __t1_tpi_write(adapter, addr, value);
+       spin_unlock(&(adapter)->tpi_lock);
+       return ret;
+}
+
+/*
+ * Read a register over the TPI interface (unlocked and locked versions).
+ */
+static int __t1_tpi_read(adapter_t *adapter, u32 addr, u32 *valp)
+{
+       int tpi_busy;
+
+       writel(addr, adapter->regs + A_TPI_ADDR);
+       writel(0, adapter->regs + A_TPI_CSR);
+
+       tpi_busy = t1_wait_op_done(adapter, A_TPI_CSR, F_TPIRDY, 1,
+                                  TPI_ATTEMPTS, 3);
+       if (tpi_busy)
+               CH_ALERT("%s: TPI read from 0x%x failed\n",
+                        adapter->name, addr);
+       else
+               *valp = readl(adapter->regs + A_TPI_RD_DATA);
+       return tpi_busy;
+}
+
+int t1_tpi_read(adapter_t *adapter, u32 addr, u32 *valp)
+{
+       int ret;
+
+       spin_lock(&(adapter)->tpi_lock);
+       ret = __t1_tpi_read(adapter, addr, valp);
+       spin_unlock(&(adapter)->tpi_lock);
+       return ret;
+}
+
+/*
+ * Called when a port's link settings change to propagate the new values to the
+ * associated PHY and MAC.  After performing the common tasks it invokes an
+ * OS-specific handler.
+ */
+/* static */ void link_changed(adapter_t *adapter, int port_id)
+{
+       int link_ok, speed, duplex, fc;
+       struct cphy *phy = adapter->port[port_id].phy;
+       struct link_config *lc = &adapter->port[port_id].link_config;
+
+       phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
+
+       lc->speed = speed < 0 ? SPEED_INVALID : speed;
+       lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
+       if (!(lc->requested_fc & PAUSE_AUTONEG))
+               fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+
+       if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) {
+               /* Set MAC speed, duplex, and flow control to match PHY. */
+               struct cmac *mac = adapter->port[port_id].mac;
+
+               mac->ops->set_speed_duplex_fc(mac, speed, duplex, fc);
+               lc->fc = (unsigned char)fc;
+       }
+       t1_link_changed(adapter, port_id, link_ok, speed, duplex, fc);
+}
+
+static int t1_pci_intr_handler(adapter_t *adapter)
+{
+       u32 pcix_cause;
+
+       pci_read_config_dword(adapter->pdev, A_PCICFG_INTR_CAUSE, &pcix_cause);
+
+       if (pcix_cause) {
+               pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_CAUSE,
+                                        pcix_cause);
+               t1_fatal_err(adapter);    /* PCI errors are fatal */
+       }
+       return 0;
+}
+
+
+/*
+ * Wait until Elmer's MI1 interface is ready for new operations.
+ */
+static int mi1_wait_until_ready(adapter_t *adapter, int mi1_reg)
+{
+       int attempts = 100, busy;
+
+       do {
+               u32 val;
+
+               __t1_tpi_read(adapter, mi1_reg, &val);
+               busy = val & F_MI1_OP_BUSY;
+               if (busy)
+                       udelay(10);
+       } while (busy && --attempts);
+       if (busy)
+               CH_ALERT("%s: MDIO operation timed out\n",
+                        adapter->name);
+       return busy;
+}
+
+/*
+ * MI1 MDIO initialization.
+ */
+static void mi1_mdio_init(adapter_t *adapter, const struct board_info *bi)
+{
+       u32 clkdiv = bi->clock_elmer0 / (2 * bi->mdio_mdc) - 1;
+       u32 val = F_MI1_PREAMBLE_ENABLE | V_MI1_MDI_INVERT(bi->mdio_mdiinv) |
+               V_MI1_MDI_ENABLE(bi->mdio_mdien) | V_MI1_CLK_DIV(clkdiv);
+
+       if (!(bi->caps & SUPPORTED_10000baseT_Full))
+               val |= V_MI1_SOF(1);
+       t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_CFG, val);
+}
+
+static int mi1_mdio_ext_read(adapter_t *adapter, int phy_addr, int mmd_addr,
+                            int reg_addr, unsigned int *valp)
+{
+       u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr);
+
+       spin_lock(&(adapter)->tpi_lock);
+
+       /* Write the address we want. */
+       __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);
+       __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, reg_addr);
+       __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP,
+                      MI1_OP_INDIRECT_ADDRESS);
+       mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
+
+       /* Write the operation we want. */
+       __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP, MI1_OP_INDIRECT_READ);
+       mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
+
+       /* Read the data. */
+       __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, valp);
+       spin_unlock(&(adapter)->tpi_lock);
+       return 0;
+}
+
+static int mi1_mdio_ext_write(adapter_t *adapter, int phy_addr, int mmd_addr,
+                             int reg_addr, unsigned int val)
+{
+       u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr);
+
+       spin_lock(&(adapter)->tpi_lock);
+
+       /* Write the address we want. */
+       __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);
+       __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, reg_addr);
+       __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP,
+                      MI1_OP_INDIRECT_ADDRESS);
+       mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
+
+       /* Write the data. */
+       __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, val);
+       __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP, MI1_OP_INDIRECT_WRITE);
+       mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
+       spin_unlock(&(adapter)->tpi_lock);
+       return 0;
+}
+
+static struct mdio_ops mi1_mdio_ext_ops = {
+       mi1_mdio_init,
+       mi1_mdio_ext_read,
+       mi1_mdio_ext_write
+};
+
+enum {
+       CH_BRD_N110_1F,
+       CH_BRD_N210_1F,
+};
+
+static struct board_info t1_board[] = {
+
+{ CHBT_BOARD_N110, 1/*ports#*/,
+  SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T1,
+  CHBT_MAC_PM3393, CHBT_PHY_88X2010,
+  125000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/,
+  1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
+  0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
+  &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
+  "Chelsio N110 1x10GBaseX NIC" },
+
+{ CHBT_BOARD_N210, 1/*ports#*/,
+  SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T2,
+  CHBT_MAC_PM3393, CHBT_PHY_88X2010,
+  125000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/,
+  1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
+  0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
+  &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
+  "Chelsio N210 1x10GBaseX NIC" },
+
+};
+
+struct pci_device_id t1_pci_tbl[] = {
+       CH_DEVICE(7, 0, CH_BRD_N110_1F),
+       CH_DEVICE(10, 1, CH_BRD_N210_1F),
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, t1_pci_tbl);
+
+/*
+ * Return the board_info structure with a given index.  Out-of-range indices
+ * return NULL.
+ */
+const struct board_info *t1_get_board_info(unsigned int board_id)
+{
+       return board_id < ARRAY_SIZE(t1_board) ? &t1_board[board_id] : NULL;
+}
+
+struct chelsio_vpd_t {
+       u32 format_version;
+       u8 serial_number[16];
+       u8 mac_base_address[6];
+       u8 pad[2];           /* make multiple-of-4 size requirement explicit */
+};
+
+#define EEPROMSIZE        (8 * 1024)
+#define EEPROM_MAX_POLL   4
+
+/*
+ * Read SEEPROM. A zero is written to the flag register when the addres is
+ * written to the Control register. The hardware device will set the flag to a
+ * one when 4B have been transferred to the Data register.
+ */
+int t1_seeprom_read(adapter_t *adapter, u32 addr, u32 *data)
+{
+       int i = EEPROM_MAX_POLL;
+       u16 val;
+
+       if (addr >= EEPROMSIZE || (addr & 3))
+               return -EINVAL;
+
+       pci_write_config_word(adapter->pdev, A_PCICFG_VPD_ADDR, (u16)addr);
+       do {
+               udelay(50);
+               pci_read_config_word(adapter->pdev, A_PCICFG_VPD_ADDR, &val);
+       } while (!(val & F_VPD_OP_FLAG) && --i);
+
+       if (!(val & F_VPD_OP_FLAG)) {
+               CH_ERR("%s: reading EEPROM address 0x%x failed\n",
+                      adapter->name, addr);
+               return -EIO;
+       }
+       pci_read_config_dword(adapter->pdev, A_PCICFG_VPD_DATA, data);
+       *data = le32_to_cpu(*data);
+       return 0;
+}
+
+static int t1_eeprom_vpd_get(adapter_t *adapter, struct chelsio_vpd_t *vpd)
+{
+       int addr, ret = 0;
+
+       for (addr = 0; !ret && addr < sizeof(*vpd); addr += sizeof(u32))
+               ret = t1_seeprom_read(adapter, addr,
+                                     (u32 *)((u8 *)vpd + addr));
+
+       return ret;
+}
+
+/*
+ * Read a port's MAC address from the VPD ROM.
+ */
+static int vpd_macaddress_get(adapter_t *adapter, int index, u8 mac_addr[])
+{
+       struct chelsio_vpd_t vpd;
+
+       if (t1_eeprom_vpd_get(adapter, &vpd))
+               return 1;
+       memcpy(mac_addr, vpd.mac_base_address, 5);
+       mac_addr[5] = vpd.mac_base_address[5] + index;
+       return 0;
+}
+
+/*
+ * Set up the MAC/PHY according to the requested link settings.
+ *
+ * If the PHY can auto-negotiate first decide what to advertise, then
+ * enable/disable auto-negotiation as desired and reset.
+ *
+ * If the PHY does not auto-negotiate we just reset it.
+ *
+ * If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
+ * otherwise do it later based on the outcome of auto-negotiation.
+ */
+int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
+{
+       unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+
+       if (lc->supported & SUPPORTED_Autoneg) {
+               lc->advertising &= ~(ADVERTISED_ASYM_PAUSE | ADVERTISED_PAUSE);
+               if (fc) {
+                       lc->advertising |= ADVERTISED_ASYM_PAUSE;
+                       if (fc == (PAUSE_RX | PAUSE_TX))
+                               lc->advertising |= ADVERTISED_PAUSE;
+               }
+               phy->ops->advertise(phy, lc->advertising);
+
+               if (lc->autoneg == AUTONEG_DISABLE) {
+                       lc->speed = lc->requested_speed;
+                       lc->duplex = lc->requested_duplex;
+                       lc->fc = (unsigned char)fc;
+                       mac->ops->set_speed_duplex_fc(mac, lc->speed,
+                                                     lc->duplex, fc);
+                       /* Also disables autoneg */
+                       phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);
+                       phy->ops->reset(phy, 0);
+               } else
+                       phy->ops->autoneg_enable(phy); /* also resets PHY */
+       } else {
+               mac->ops->set_speed_duplex_fc(mac, -1, -1, fc);
+               lc->fc = (unsigned char)fc;
+               phy->ops->reset(phy, 0);
+       }
+       return 0;
+}
+
+/*
+ * External interrupt handler for boards using elmer0.
+ */
+int elmer0_ext_intr_handler(adapter_t *adapter)
+{
+       struct cphy *phy;
+       int phy_cause;
+       u32 cause;
+
+       t1_tpi_read(adapter, A_ELMER0_INT_CAUSE, &cause);
+
+       switch (board_info(adapter)->board) {
+       case CHBT_BOARD_N210:
+       case CHBT_BOARD_N110:
+               if (cause & ELMER0_GP_BIT6) { /* Marvell 88x2010 interrupt */
+                       phy = adapter->port[0].phy;
+                       phy_cause = phy->ops->interrupt_handler(phy);
+                       if (phy_cause & cphy_cause_link_change)
+                               link_changed(adapter, 0);
+               }
+               break;
+       }
+       t1_tpi_write(adapter, A_ELMER0_INT_CAUSE, cause);
+       return 0;
+}
+
+/* Enables all interrupts. */
+void t1_interrupts_enable(adapter_t *adapter)
+{
+       unsigned int i;
+       u32 pl_intr;
+
+       adapter->slow_intr_mask = F_PL_INTR_SGE_ERR;
+
+       t1_sge_intr_enable(adapter->sge);
+       if (adapter->espi) {
+               adapter->slow_intr_mask |= F_PL_INTR_ESPI;
+               t1_espi_intr_enable(adapter->espi);
+       }
+
+       /* Enable MAC/PHY interrupts for each port. */
+       for_each_port(adapter, i) {
+               adapter->port[i].mac->ops->interrupt_enable(adapter->port[i].mac);
+               adapter->port[i].phy->ops->interrupt_enable(adapter->port[i].phy);
+       }
+
+       /* Enable PCIX & external chip interrupts on ASIC boards. */
+       pl_intr = readl(adapter->regs + A_PL_ENABLE);
+
+       /* PCI-X interrupts */
+       pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE,
+                              0xffffffff);
+
+       adapter->slow_intr_mask |= F_PL_INTR_EXT | F_PL_INTR_PCIX;
+       pl_intr |= F_PL_INTR_EXT | F_PL_INTR_PCIX;
+       writel(pl_intr, adapter->regs + A_PL_ENABLE);
+}
+
+/* Disables all interrupts. */
+void t1_interrupts_disable(adapter_t* adapter)
+{
+       unsigned int i;
+
+       t1_sge_intr_disable(adapter->sge);
+       if (adapter->espi)
+               t1_espi_intr_disable(adapter->espi);
+
+       /* Disable MAC/PHY interrupts for each port. */
+       for_each_port(adapter, i) {
+               adapter->port[i].mac->ops->interrupt_disable(adapter->port[i].mac);
+               adapter->port[i].phy->ops->interrupt_disable(adapter->port[i].phy);
+       }
+
+       /* Disable PCIX & external chip interrupts. */
+       writel(0, adapter->regs + A_PL_ENABLE);
+
+       /* PCI-X interrupts */
+       pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE, 0);
+
+       adapter->slow_intr_mask = 0;
+}
+
+/* Clears all interrupts */
+void t1_interrupts_clear(adapter_t* adapter)
+{
+       unsigned int i;
+       u32 pl_intr;
+
+
+       t1_sge_intr_clear(adapter->sge);
+       if (adapter->espi)
+               t1_espi_intr_clear(adapter->espi);
+
+       /* Clear MAC/PHY interrupts for each port. */
+       for_each_port(adapter, i) {
+               adapter->port[i].mac->ops->interrupt_clear(adapter->port[i].mac);
+               adapter->port[i].phy->ops->interrupt_clear(adapter->port[i].phy);
+       }
+
+       /* Enable interrupts for external devices. */
+       pl_intr = readl(adapter->regs + A_PL_CAUSE);
+
+       writel(pl_intr | F_PL_INTR_EXT | F_PL_INTR_PCIX,
+              adapter->regs + A_PL_CAUSE);
+
+       /* PCI-X interrupts */
+       pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_CAUSE, 0xffffffff);
+}
+
+/*
+ * Slow path interrupt handler for ASICs.
+ */
+int t1_slow_intr_handler(adapter_t *adapter)
+{
+       u32 cause = readl(adapter->regs + A_PL_CAUSE);
+
+       cause &= adapter->slow_intr_mask;
+       if (!cause)
+               return 0;
+       if (cause & F_PL_INTR_SGE_ERR)
+               t1_sge_intr_error_handler(adapter->sge);
+       if (cause & F_PL_INTR_ESPI)
+               t1_espi_intr_handler(adapter->espi);
+       if (cause & F_PL_INTR_PCIX)
+               t1_pci_intr_handler(adapter);
+       if (cause & F_PL_INTR_EXT)
+               t1_elmer0_ext_intr(adapter);
+
+       /* Clear the interrupts just processed. */
+       writel(cause, adapter->regs + A_PL_CAUSE);
+       (void)readl(adapter->regs + A_PL_CAUSE); /* flush writes */
+       return 1;
+}
+
+/* Pause deadlock avoidance parameters */
+#define DROP_MSEC 16
+#define DROP_PKTS_CNT  1
+
+static void set_csum_offload(adapter_t *adapter, u32 csum_bit, int enable)
+{
+       u32 val = readl(adapter->regs + A_TP_GLOBAL_CONFIG);
+
+       if (enable)
+               val |= csum_bit;
+       else
+               val &= ~csum_bit;
+       writel(val, adapter->regs + A_TP_GLOBAL_CONFIG);
+}
+
+void t1_tp_set_ip_checksum_offload(adapter_t *adapter, int enable)
+{
+       set_csum_offload(adapter, F_IP_CSUM, enable);
+}
+
+void t1_tp_set_udp_checksum_offload(adapter_t *adapter, int enable)
+{
+       set_csum_offload(adapter, F_UDP_CSUM, enable);
+}
+
+void t1_tp_set_tcp_checksum_offload(adapter_t *adapter, int enable)
+{
+       set_csum_offload(adapter, F_TCP_CSUM, enable);
+}
+
+static void t1_tp_reset(adapter_t *adapter, unsigned int tp_clk)
+{
+       u32 val;
+
+       val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM |
+             F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET;
+       val |= F_TP_IN_ESPI_CHECK_IP_CSUM |
+              F_TP_IN_ESPI_CHECK_TCP_CSUM;
+       writel(val, adapter->regs + A_TP_IN_CONFIG);
+       writel(F_TP_OUT_CSPI_CPL |
+              F_TP_OUT_ESPI_ETHERNET |
+              F_TP_OUT_ESPI_GENERATE_IP_CSUM |
+              F_TP_OUT_ESPI_GENERATE_TCP_CSUM,
+              adapter->regs + A_TP_OUT_CONFIG);
+
+       val = readl(adapter->regs + A_TP_GLOBAL_CONFIG);
+       val &= ~(F_IP_CSUM | F_UDP_CSUM | F_TCP_CSUM);
+       writel(val, adapter->regs + A_TP_GLOBAL_CONFIG);
+
+       /*
+        * Enable pause frame deadlock prevention.
+        */
+       if (is_T2(adapter)) {
+               u32 drop_ticks = DROP_MSEC * (tp_clk / 1000);
+
+               writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR |
+                      V_DROP_TICKS_CNT(drop_ticks) |
+                      V_NUM_PKTS_DROPPED(DROP_PKTS_CNT),
+                      adapter->regs + A_TP_TX_DROP_CONFIG);
+       }
+
+       writel(F_TP_RESET, adapter->regs + A_TP_RESET);
+}
+
+int __devinit t1_get_board_rev(adapter_t *adapter, const struct board_info *bi,
+                              struct adapter_params *p)
+{
+       p->chip_version = bi->chip_term;
+       if (p->chip_version == CHBT_TERM_T1 ||
+           p->chip_version == CHBT_TERM_T2) {
+               u32 val = readl(adapter->regs + A_TP_PC_CONFIG);
+
+               val = G_TP_PC_REV(val);
+               if (val == 2)
+                       p->chip_revision = TERM_T1B;
+               else if (val == 3)
+                       p->chip_revision = TERM_T2;
+               else
+                       return -1;
+       } else
+               return -1;
+       return 0;
+}
+
+/*
+ * Enable board components other than the Chelsio chip, such as external MAC
+ * and PHY.
+ */
+static int board_init(adapter_t *adapter, const struct board_info *bi)
+{
+       switch (bi->board) {
+       case CHBT_BOARD_N110:
+       case CHBT_BOARD_N210:
+               writel(V_TPIPAR(0xf), adapter->regs + A_TPI_PAR);
+               t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);
+               break;
+       }
+       return 0;
+}
+
+/*
+ * Initialize and configure the Terminator HW modules.  Note that external
+ * MAC and PHYs are initialized separately.
+ */
+int t1_init_hw_modules(adapter_t *adapter)
+{
+       int err = -EIO;
+       const struct board_info *bi = board_info(adapter);
+
+       if (!bi->clock_mc4) {
+               u32 val = readl(adapter->regs + A_MC4_CFG);
+
+               writel(val | F_READY | F_MC4_SLOW, adapter->regs + A_MC4_CFG);
+               writel(F_M_BUS_ENABLE | F_TCAM_RESET,
+                      adapter->regs + A_MC5_CONFIG);
+       }
+
+       if (adapter->espi && t1_espi_init(adapter->espi, bi->chip_mac,
+                                         bi->espi_nports))
+               goto out_err;
+
+       t1_tp_reset(adapter, bi->clock_core);
+
+       err = t1_sge_configure(adapter->sge, &adapter->params.sge);
+       if (err)
+               goto out_err;
+
+       err = 0;
+ out_err:
+       return err;
+}
+
+/*
+ * Determine a card's PCI mode.
+ */
+static void __devinit get_pci_mode(adapter_t *adapter, struct chelsio_pci_params *p)
+{
+       static unsigned short speed_map[] = { 33, 66, 100, 133 };
+       u32 pci_mode;
+
+       pci_read_config_dword(adapter->pdev, A_PCICFG_MODE, &pci_mode);
+       p->speed = speed_map[G_PCI_MODE_CLK(pci_mode)];
+       p->width = (pci_mode & F_PCI_MODE_64BIT) ? 64 : 32;
+       p->is_pcix = (pci_mode & F_PCI_MODE_PCIX) != 0;
+}
+
+/*
+ * Release the structures holding the SW per-Terminator-HW-module state.
+ */
+void t1_free_sw_modules(adapter_t *adapter)
+{
+       unsigned int i;
+
+       for_each_port(adapter, i) {
+               struct cmac *mac = adapter->port[i].mac;
+               struct cphy *phy = adapter->port[i].phy;
+
+               if (mac)
+                       mac->ops->destroy(mac);
+               if (phy)
+                       phy->ops->destroy(phy);
+       }
+
+       if (adapter->sge)
+               t1_sge_destroy(adapter->sge);
+       if (adapter->espi)
+               t1_espi_destroy(adapter->espi);
+}
+
+static void __devinit init_link_config(struct link_config *lc,
+                                      const struct board_info *bi)
+{
+       lc->supported = bi->caps;
+       lc->requested_speed = lc->speed = SPEED_INVALID;
+       lc->requested_duplex = lc->duplex = DUPLEX_INVALID;
+       lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
+       if (lc->supported & SUPPORTED_Autoneg) {
+               lc->advertising = lc->supported;
+               lc->autoneg = AUTONEG_ENABLE;
+               lc->requested_fc |= PAUSE_AUTONEG;
+       } else {
+               lc->advertising = 0;
+               lc->autoneg = AUTONEG_DISABLE;
+       }
+}
+
+
+/*
+ * Allocate and initialize the data structures that hold the SW state of
+ * the Terminator HW modules.
+ */
+int __devinit t1_init_sw_modules(adapter_t *adapter,
+                                const struct board_info *bi)
+{
+       unsigned int i;
+
+       adapter->params.brd_info = bi;
+       adapter->params.nports = bi->port_number;
+       adapter->params.stats_update_period = bi->gmac->stats_update_period;
+
+       adapter->sge = t1_sge_create(adapter, &adapter->params.sge);
+       if (!adapter->sge) {
+               CH_ERR("%s: SGE initialization failed\n",
+                      adapter->name);
+               goto error;
+       }
+
+       if (bi->espi_nports && !(adapter->espi = t1_espi_create(adapter))) {
+               CH_ERR("%s: ESPI initialization failed\n",
+                      adapter->name);
+               goto error;
+       }
+
+       board_init(adapter, bi);
+       bi->mdio_ops->init(adapter, bi);
+       if (bi->gphy->reset)
+               bi->gphy->reset(adapter);
+       if (bi->gmac->reset)
+               bi->gmac->reset(adapter);
+
+       for_each_port(adapter, i) {
+               u8 hw_addr[6];
+               struct cmac *mac;
+               int phy_addr = bi->mdio_phybaseaddr + i;
+
+               adapter->port[i].phy = bi->gphy->create(adapter, phy_addr,
+                                                       bi->mdio_ops);
+               if (!adapter->port[i].phy) {
+                       CH_ERR("%s: PHY %d initialization failed\n",
+                              adapter->name, i);
+                       goto error;
+               }
+
+               adapter->port[i].mac = mac = bi->gmac->create(adapter, i);
+               if (!mac) {
+                       CH_ERR("%s: MAC %d initialization failed\n",
+                              adapter->name, i);
+                       goto error;
+               }
+
+               /*
+                * Get the port's MAC addresses either from the EEPROM if one
+                * exists or the one hardcoded in the MAC.
+                */
+               if (vpd_macaddress_get(adapter, i, hw_addr)) {
+                       CH_ERR("%s: could not read MAC address from VPD ROM\n",
+                              adapter->port[i].dev->name);
+                       goto error;
+               }
+               memcpy(adapter->port[i].dev->dev_addr, hw_addr, ETH_ALEN);
+               init_link_config(&adapter->port[i].link_config, bi);
+       }
+
+       get_pci_mode(adapter, &adapter->params.pci);
+       t1_interrupts_clear(adapter);
+       return 0;
+
+ error:
+       t1_free_sw_modules(adapter);
+       return -1;
+}
diff --git a/drivers/net/chelsio/suni1x10gexp_regs.h b/drivers/net/chelsio/suni1x10gexp_regs.h
new file mode 100644 (file)
index 0000000..81816c2
--- /dev/null
@@ -0,0 +1,213 @@
+/*****************************************************************************
+ *                                                                           *
+ * File: suni1x10gexp_regs.h                                                 *
+ * $Revision: 1.9 $                                                          *
+ * $Date: 2005/06/22 00:17:04 $                                              *
+ * Description:                                                              *
+ *  PMC/SIERRA (pm3393) MAC-PHY functionality.                               *
+ *  part of the Chelsio 10Gb Ethernet Driver.                                *
+ *                                                                           *
+ * This program is free software; you can redistribute it and/or modify      *
+ * it under the terms of the GNU General Public License, version 2, as       *
+ * published by the Free Software Foundation.                                *
+ *                                                                           *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED    *
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF      *
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.                     *
+ *                                                                           *
+ * http://www.chelsio.com                                                    *
+ *                                                                           *
+ * Maintainers: maintainers@chelsio.com                                      *
+ *                                                                           *
+ * Authors: PMC/SIERRA                                                       *
+ *                                                                           *
+ * History:                                                                  *
+ *                                                                           *
+ ****************************************************************************/
+
+#ifndef _CXGB_SUNI1x10GEXP_REGS_H_
+#define _CXGB_SUNI1x10GEXP_REGS_H_
+
+/******************************************************************************/
+/** S/UNI-1x10GE-XP REGISTER ADDRESS MAP                                     **/
+/******************************************************************************/
+/* Refer to the Register Bit Masks bellow for the naming of each register and */
+/* to the S/UNI-1x10GE-XP Data Sheet for the signification of each bit        */
+/******************************************************************************/
+
+#define SUNI1x10GEXP_REG_DEVICE_STATUS                                   0x0004
+#define SUNI1x10GEXP_REG_MASTER_INTERRUPT_STATUS                         0x000D
+#define SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE                         0x000E
+#define SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE                    0x0102
+#define SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_STATUS                    0x0104
+#define SUNI1x10GEXP_REG_RXXG_CONFIG_1                                   0x2040
+#define SUNI1x10GEXP_REG_RXXG_CONFIG_3                                   0x2042
+#define SUNI1x10GEXP_REG_RXXG_INTERRUPT                                  0x2043
+#define SUNI1x10GEXP_REG_RXXG_MAX_FRAME_LENGTH                           0x2045
+#define SUNI1x10GEXP_REG_RXXG_SA_15_0                                    0x2046
+#define SUNI1x10GEXP_REG_RXXG_SA_31_16                                   0x2047
+#define SUNI1x10GEXP_REG_RXXG_SA_47_32                                   0x2048
+#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_LOW                     0x204D
+#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_MID                     0x204E
+#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_HIGH                    0x204F
+#define SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW                         0x206A
+#define SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDLOW                      0x206B
+#define SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDHIGH                     0x206C
+#define SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_HIGH                        0x206D
+#define SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0                   0x206E
+#define SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2                   0x2070
+#define SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE                            0x2088
+#define SUNI1x10GEXP_REG_XRF_INTERRUPT_STATUS                            0x2089
+#define SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE                       0x208B
+#define SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_STATUS                       0x208C
+#define SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE                          0x20C7
+#define SUNI1x10GEXP_REG_RXOAM_INTERRUPT_STATUS                          0x20C8
+#define SUNI1x10GEXP_REG_MSTAT_CONTROL                                   0x2100
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_0                        0x2101
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_1                        0x2102
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_2                        0x2103
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_3                        0x2104
+#define SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0                          0x2105
+#define SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1                          0x2106
+#define SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2                          0x2107
+#define SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3                          0x2108
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW                             0x2110
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_1_LOW                             0x2114
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_4_LOW                             0x2120
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_5_LOW                             0x2124
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_6_LOW                             0x2128
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_8_LOW                             0x2130
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_10_LOW                            0x2138
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_11_LOW                            0x213C
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_12_LOW                            0x2140
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_13_LOW                            0x2144
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_15_LOW                            0x214C
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_16_LOW                            0x2150
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_17_LOW                            0x2154
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_18_LOW                            0x2158
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_33_LOW                            0x2194
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_35_LOW                            0x219C
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_36_LOW                            0x21A0
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_38_LOW                            0x21A8
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_40_LOW                            0x21B0
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_42_LOW                            0x21B8
+#define SUNI1x10GEXP_REG_MSTAT_COUNTER_43_LOW                            0x21BC
+#define SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE                       0x2209
+#define SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_INTERRUPT                    0x220A
+#define SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK                           0x2282
+#define SUNI1x10GEXP_REG_PL4ODP_INTERRUPT                                0x2283
+#define SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_STATUS                        0x2300
+#define SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_CHANGE                        0x2301
+#define SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK                          0x2302
+#define SUNI1x10GEXP_REG_TXXG_CONFIG_1                                   0x3040
+#define SUNI1x10GEXP_REG_TXXG_CONFIG_3                                   0x3042
+#define SUNI1x10GEXP_REG_TXXG_INTERRUPT                                  0x3043
+#define SUNI1x10GEXP_REG_TXXG_MAX_FRAME_SIZE                             0x3045
+#define SUNI1x10GEXP_REG_TXXG_SA_15_0                                    0x3047
+#define SUNI1x10GEXP_REG_TXXG_SA_31_16                                   0x3048
+#define SUNI1x10GEXP_REG_TXXG_SA_47_32                                   0x3049
+#define SUNI1x10GEXP_REG_XTEF_INTERRUPT_STATUS                           0x3084
+#define SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE                           0x3085
+#define SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE                          0x30C6
+#define SUNI1x10GEXP_REG_TXOAM_INTERRUPT_STATUS                          0x30C7
+#define SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE                 0x320C
+#define SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_INDICATION             0x320D
+#define SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK                           0x3282
+#define SUNI1x10GEXP_REG_PL4IDU_INTERRUPT                                0x3283
+
+/******************************************************************************/
+/*                 -- End register offset definitions --                      */
+/******************************************************************************/
+
+/******************************************************************************/
+/** SUNI-1x10GE-XP REGISTER BIT MASKS                                        **/
+/******************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * Register 0x0004: S/UNI-1x10GE-XP Device Status
+ *    Bit 9 TOP_SXRA_EXPIRED
+ *    Bit 8 TOP_MDIO_BUSY
+ *    Bit 7 TOP_DTRB
+ *    Bit 6 TOP_EXPIRED
+ *    Bit 5 TOP_PAUSED
+ *    Bit 4 TOP_PL4_ID_DOOL
+ *    Bit 3 TOP_PL4_IS_DOOL
+ *    Bit 2 TOP_PL4_ID_ROOL
+ *    Bit 1 TOP_PL4_IS_ROOL
+ *    Bit 0 TOP_PL4_OUT_ROOL
+ *----------------------------------------------------------------------------*/
+#define SUNI1x10GEXP_BITMSK_TOP_SXRA_EXPIRED  0x0200
+#define SUNI1x10GEXP_BITMSK_TOP_EXPIRED       0x0040
+#define SUNI1x10GEXP_BITMSK_TOP_PL4_ID_DOOL   0x0010
+#define SUNI1x10GEXP_BITMSK_TOP_PL4_IS_DOOL   0x0008
+#define SUNI1x10GEXP_BITMSK_TOP_PL4_ID_ROOL   0x0004
+#define SUNI1x10GEXP_BITMSK_TOP_PL4_IS_ROOL   0x0002
+#define SUNI1x10GEXP_BITMSK_TOP_PL4_OUT_ROOL  0x0001
+
+/*----------------------------------------------------------------------------
+ * Register 0x000E:PM3393 Global interrupt enable
+ *    Bit 15 TOP_INTE
+ *----------------------------------------------------------------------------*/
+#define SUNI1x10GEXP_BITMSK_TOP_INTE  0x8000
+
+/*----------------------------------------------------------------------------
+ * Register 0x2040: RXXG Configuration 1
+ *    Bit 15  RXXG_RXEN
+ *    Bit 14  RXXG_ROCF
+ *    Bit 13  RXXG_PAD_STRIP
+ *    Bit 10  RXXG_PUREP
+ *    Bit 9   RXXG_LONGP
+ *    Bit 8   RXXG_PARF
+ *    Bit 7   RXXG_FLCHK
+ *    Bit 5   RXXG_PASS_CTRL
+ *    Bit 3   RXXG_CRC_STRIP
+ *    Bit 2-0 RXXG_MIFG
+ *----------------------------------------------------------------------------*/
+#define SUNI1x10GEXP_BITMSK_RXXG_RXEN       0x8000
+#define SUNI1x10GEXP_BITMSK_RXXG_PUREP      0x0400
+#define SUNI1x10GEXP_BITMSK_RXXG_FLCHK      0x0080
+#define SUNI1x10GEXP_BITMSK_RXXG_CRC_STRIP  0x0008
+
+/*----------------------------------------------------------------------------
+ * Register 0x2070: RXXG Address Filter Control 2
+ *    Bit 1 RXXG_PMODE
+ *    Bit 0 RXXG_MHASH_EN
+ *----------------------------------------------------------------------------*/
+#define SUNI1x10GEXP_BITMSK_RXXG_PMODE     0x0002
+#define SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN  0x0001
+
+/*----------------------------------------------------------------------------
+ * Register 0x2100: MSTAT Control
+ *    Bit 2 MSTAT_WRITE
+ *    Bit 1 MSTAT_CLEAR
+ *    Bit 0 MSTAT_SNAP
+ *----------------------------------------------------------------------------*/
+#define SUNI1x10GEXP_BITMSK_MSTAT_CLEAR  0x0002
+#define SUNI1x10GEXP_BITMSK_MSTAT_SNAP   0x0001
+
+/*----------------------------------------------------------------------------
+ * Register 0x3040: TXXG Configuration Register 1
+ *    Bit 15   TXXG_TXEN0
+ *    Bit 13   TXXG_HOSTPAUSE
+ *    Bit 12-7 TXXG_IPGT
+ *    Bit 5    TXXG_32BIT_ALIGN
+ *    Bit 4    TXXG_CRCEN
+ *    Bit 3    TXXG_FCTX
+ *    Bit 2    TXXG_FCRX
+ *    Bit 1    TXXG_PADEN
+ *    Bit 0    TXXG_SPRE
+ *----------------------------------------------------------------------------*/
+#define SUNI1x10GEXP_BITMSK_TXXG_TXEN0        0x8000
+#define SUNI1x10GEXP_BITOFF_TXXG_IPGT         7
+#define SUNI1x10GEXP_BITMSK_TXXG_32BIT_ALIGN  0x0020
+#define SUNI1x10GEXP_BITMSK_TXXG_CRCEN        0x0010
+#define SUNI1x10GEXP_BITMSK_TXXG_FCTX         0x0008
+#define SUNI1x10GEXP_BITMSK_TXXG_FCRX         0x0004
+#define SUNI1x10GEXP_BITMSK_TXXG_PADEN        0x0002
+
+#endif /* _CXGB_SUNI1x10GEXP_REGS_H_ */
+
index 6440a892bb813ca4a08e0a1878cf0dedb43b254d..e54fc10f68467c7fd9bf92e11b9fb9d3fba3cee4 100644 (file)
@@ -1140,7 +1140,7 @@ dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int value)
 }
 
 static int
-dm9000_drv_suspend(struct device *dev, u32 state, u32 level)
+dm9000_drv_suspend(struct device *dev, pm_message_t state, u32 level)
 {
        struct net_device *ndev = dev_get_drvdata(dev);
 
index d0fa2448761d0fdb1dcebae2b23de9b9c23d0b25..25cc20e415dae23247825fe947b4cb19725ee0bf 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
   
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by the Free 
 
 #define DRV_NAME               "e100"
 #define DRV_EXT                "-NAPI"
-#define DRV_VERSION            "3.4.8-k2"DRV_EXT
+#define DRV_VERSION            "3.4.14-k2"DRV_EXT
 #define DRV_DESCRIPTION                "Intel(R) PRO/100 Network Driver"
 #define DRV_COPYRIGHT          "Copyright(c) 1999-2005 Intel Corporation"
 #define PFX                    DRV_NAME ": "
@@ -785,6 +785,7 @@ static int e100_eeprom_save(struct nic *nic, u16 start, u16 count)
 }
 
 #define E100_WAIT_SCB_TIMEOUT 20000 /* we might have to wait 100ms!!! */
+#define E100_WAIT_SCB_FAST 20       /* delay like the old code */
 static inline int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
 {
        unsigned long flags;
@@ -798,7 +799,7 @@ static inline int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
                if(likely(!readb(&nic->csr->scb.cmd_lo)))
                        break;
                cpu_relax();
-               if(unlikely(i > (E100_WAIT_SCB_TIMEOUT >> 1)))
+               if(unlikely(i > E100_WAIT_SCB_FAST))
                        udelay(5);
        }
        if(unlikely(i == E100_WAIT_SCB_TIMEOUT)) {
@@ -902,8 +903,8 @@ static void mdio_write(struct net_device *netdev, int addr, int reg, int data)
 
 static void e100_get_defaults(struct nic *nic)
 {
-       struct param_range rfds = { .min = 16, .max = 256, .count = 64 };
-       struct param_range cbs  = { .min = 64, .max = 256, .count = 64 };
+       struct param_range rfds = { .min = 16, .max = 256, .count = 256 };
+       struct param_range cbs  = { .min = 64, .max = 256, .count = 128 };
 
        pci_read_config_byte(nic->pdev, PCI_REVISION_ID, &nic->rev_id);
        /* MAC type is encoded as rev ID; exception: ICH is treated as 82559 */
@@ -1006,25 +1007,213 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb)
                c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]);
 }
 
+/********************************************************/
+/*  Micro code for 8086:1229 Rev 8                      */
+/********************************************************/
+
+/*  Parameter values for the D101M B-step  */
+#define D101M_CPUSAVER_TIMER_DWORD             78
+#define D101M_CPUSAVER_BUNDLE_DWORD            65
+#define D101M_CPUSAVER_MIN_SIZE_DWORD          126
+
+#define D101M_B_RCVBUNDLE_UCODE \
+{\
+0x00550215, 0xFFFF0437, 0xFFFFFFFF, 0x06A70789, 0xFFFFFFFF, 0x0558FFFF, \
+0x000C0001, 0x00101312, 0x000C0008, 0x00380216, \
+0x0010009C, 0x00204056, 0x002380CC, 0x00380056, \
+0x0010009C, 0x00244C0B, 0x00000800, 0x00124818, \
+0x00380438, 0x00000000, 0x00140000, 0x00380555, \
+0x00308000, 0x00100662, 0x00100561, 0x000E0408, \
+0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
+0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
+0x000C007E, 0x00222C21, 0x000C0002, 0x00103093, \
+0x00380C7A, 0x00080000, 0x00103090, 0x00380C7A, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x00244C2D, 0x00010004, 0x00041000, \
+0x003A0437, 0x00044010, 0x0038078A, 0x00000000, \
+0x00100099, 0x00206C7A, 0x0010009C, 0x00244C48, \
+0x00130824, 0x000C0001, 0x00101213, 0x00260C75, \
+0x00041000, 0x00010004, 0x00130826, 0x000C0006, \
+0x002206A8, 0x0013C926, 0x00101313, 0x003806A8, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
+0x00101210, 0x00380C34, 0x00000000, 0x00000000, \
+0x0021155B, 0x00100099, 0x00206559, 0x0010009C, \
+0x00244559, 0x00130836, 0x000C0000, 0x00220C62, \
+0x000C0001, 0x00101B13, 0x00229C0E, 0x00210C0E, \
+0x00226C0E, 0x00216C0E, 0x0022FC0E, 0x00215C0E, \
+0x00214C0E, 0x00380555, 0x00010004, 0x00041000, \
+0x00278C67, 0x00040800, 0x00018100, 0x003A0437, \
+0x00130826, 0x000C0001, 0x00220559, 0x00101313, \
+0x00380559, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00130831, 0x0010090B, 0x00124813, \
+0x000CFF80, 0x002606AB, 0x00041000, 0x00010004, \
+0x003806A8, 0x00000000, 0x00000000, 0x00000000, \
+}
+
+/********************************************************/
+/*  Micro code for 8086:1229 Rev 9                      */
+/********************************************************/
+
+/*  Parameter values for the D101S  */
+#define D101S_CPUSAVER_TIMER_DWORD             78
+#define D101S_CPUSAVER_BUNDLE_DWORD            67
+#define D101S_CPUSAVER_MIN_SIZE_DWORD          128
+
+#define D101S_RCVBUNDLE_UCODE \
+{\
+0x00550242, 0xFFFF047E, 0xFFFFFFFF, 0x06FF0818, 0xFFFFFFFF, 0x05A6FFFF, \
+0x000C0001, 0x00101312, 0x000C0008, 0x00380243, \
+0x0010009C, 0x00204056, 0x002380D0, 0x00380056, \
+0x0010009C, 0x00244F8B, 0x00000800, 0x00124818, \
+0x0038047F, 0x00000000, 0x00140000, 0x003805A3, \
+0x00308000, 0x00100610, 0x00100561, 0x000E0408, \
+0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
+0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
+0x000C007E, 0x00222FA1, 0x000C0002, 0x00103093, \
+0x00380F90, 0x00080000, 0x00103090, 0x00380F90, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x00244FAD, 0x00010004, 0x00041000, \
+0x003A047E, 0x00044010, 0x00380819, 0x00000000, \
+0x00100099, 0x00206FFD, 0x0010009A, 0x0020AFFD, \
+0x0010009C, 0x00244FC8, 0x00130824, 0x000C0001, \
+0x00101213, 0x00260FF7, 0x00041000, 0x00010004, \
+0x00130826, 0x000C0006, 0x00220700, 0x0013C926, \
+0x00101313, 0x00380700, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
+0x00101210, 0x00380FB6, 0x00000000, 0x00000000, \
+0x002115A9, 0x00100099, 0x002065A7, 0x0010009A, \
+0x0020A5A7, 0x0010009C, 0x002445A7, 0x00130836, \
+0x000C0000, 0x00220FE4, 0x000C0001, 0x00101B13, \
+0x00229F8E, 0x00210F8E, 0x00226F8E, 0x00216F8E, \
+0x0022FF8E, 0x00215F8E, 0x00214F8E, 0x003805A3, \
+0x00010004, 0x00041000, 0x00278FE9, 0x00040800, \
+0x00018100, 0x003A047E, 0x00130826, 0x000C0001, \
+0x002205A7, 0x00101313, 0x003805A7, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00130831, \
+0x0010090B, 0x00124813, 0x000CFF80, 0x00260703, \
+0x00041000, 0x00010004, 0x00380700  \
+}
+
+/********************************************************/
+/*  Micro code for the 8086:1229 Rev F/10               */
+/********************************************************/
+
+/*  Parameter values for the D102 E-step  */
+#define D102_E_CPUSAVER_TIMER_DWORD            42
+#define D102_E_CPUSAVER_BUNDLE_DWORD           54
+#define D102_E_CPUSAVER_MIN_SIZE_DWORD         46
+
+#define     D102_E_RCVBUNDLE_UCODE \
+{\
+0x007D028F, 0x0E4204F9, 0x14ED0C85, 0x14FA14E9, 0x0EF70E36, 0x1FFF1FFF, \
+0x00E014B9, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014BD, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014D5, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014C1, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014C8, 0x00000000, 0x00000000, 0x00000000, \
+0x00200600, 0x00E014EE, 0x00000000, 0x00000000, \
+0x0030FF80, 0x00940E46, 0x00038200, 0x00102000, \
+0x00E00E43, 0x00000000, 0x00000000, 0x00000000, \
+0x00300006, 0x00E014FB, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00906E41, 0x00800E3C, 0x00E00E39, 0x00000000, \
+0x00906EFD, 0x00900EFD, 0x00E00EF8, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+}
+
 static void e100_load_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb)
 {
-       int i;
-       static const u32 ucode[UCODE_SIZE] = {
-               /* NFS packets are misinterpreted as TCO packets and
-                * incorrectly routed to the BMC over SMBus.  This
-                * microcode patch checks the fragmented IP bit in the
-                * NFS/UDP header to distinguish between NFS and TCO. */
-               0x0EF70E36, 0x1FFF1FFF, 0x1FFF1FFF, 0x1FFF1FFF, 0x1FFF1FFF,
-               0x1FFF1FFF, 0x00906E41, 0x00800E3C, 0x00E00E39, 0x00000000,
-               0x00906EFD, 0x00900EFD, 0x00E00EF8,
-       };
+/* *INDENT-OFF* */
+       static struct {
+               u32 ucode[UCODE_SIZE + 1];
+               u8 mac;
+               u8 timer_dword;
+               u8 bundle_dword;
+               u8 min_size_dword;
+       } ucode_opts[] = {
+               { D101M_B_RCVBUNDLE_UCODE,
+                 mac_82559_D101M,
+                 D101M_CPUSAVER_TIMER_DWORD,
+                 D101M_CPUSAVER_BUNDLE_DWORD,
+                 D101M_CPUSAVER_MIN_SIZE_DWORD },
+               { D101S_RCVBUNDLE_UCODE,
+                 mac_82559_D101S,
+                 D101S_CPUSAVER_TIMER_DWORD,
+                 D101S_CPUSAVER_BUNDLE_DWORD,
+                 D101S_CPUSAVER_MIN_SIZE_DWORD },
+               { D102_E_RCVBUNDLE_UCODE,
+                 mac_82551_F,
+                 D102_E_CPUSAVER_TIMER_DWORD,
+                 D102_E_CPUSAVER_BUNDLE_DWORD,
+                 D102_E_CPUSAVER_MIN_SIZE_DWORD },
+               { D102_E_RCVBUNDLE_UCODE,
+                 mac_82551_10,
+                 D102_E_CPUSAVER_TIMER_DWORD,
+                 D102_E_CPUSAVER_BUNDLE_DWORD,
+                 D102_E_CPUSAVER_MIN_SIZE_DWORD },
+               { {0}, 0, 0, 0, 0}
+       }, *opts;
+/* *INDENT-ON* */
+
+#define BUNDLESMALL 1
+#define BUNDLEMAX 50
+#define INTDELAY 15000
+
+       opts = ucode_opts;
+
+       /* do not load u-code for ICH devices */
+       if (nic->flags & ich)
+               return;
+
+       /* Search for ucode match against h/w rev_id */
+       while (opts->mac) {
+               if (nic->mac == opts->mac) {
+                       int i;
+                       u32 *ucode = opts->ucode;
+
+                       /* Insert user-tunable settings */
+                       ucode[opts->timer_dword] &= 0xFFFF0000;
+                       ucode[opts->timer_dword] |=
+                               (u16) INTDELAY;
+                       ucode[opts->bundle_dword] &= 0xFFFF0000;
+                       ucode[opts->bundle_dword] |= (u16) BUNDLEMAX;
+                       ucode[opts->min_size_dword] &= 0xFFFF0000;
+                       ucode[opts->min_size_dword] |=
+                               (BUNDLESMALL) ?  0xFFFF : 0xFF80;
+
+                       for(i = 0; i < UCODE_SIZE; i++)
+                               cb->u.ucode[i] = cpu_to_le32(ucode[i]);
+                       cb->command = cpu_to_le16(cb_ucode);
+                       return;
+               }
+               opts++;
+       }
 
-       if(nic->mac == mac_82551_F || nic->mac == mac_82551_10) {
-               for(i = 0; i < UCODE_SIZE; i++)
-                       cb->u.ucode[i] = cpu_to_le32(ucode[i]);
-               cb->command = cpu_to_le16(cb_ucode);
-       } else
-               cb->command = cpu_to_le16(cb_nop);
+       cb->command = cpu_to_le16(cb_nop);
 }
 
 static void e100_setup_iaaddr(struct nic *nic, struct cb *cb,
@@ -1307,14 +1496,15 @@ static inline void e100_xmit_prepare(struct nic *nic, struct cb *cb,
 {
        cb->command = nic->tx_command;
        /* interrupt every 16 packets regardless of delay */
-       if((nic->cbs_avail & ~15) == nic->cbs_avail) cb->command |= cb_i;
+       if((nic->cbs_avail & ~15) == nic->cbs_avail)
+               cb->command |= cpu_to_le16(cb_i);
        cb->u.tcb.tbd_array = cb->dma_addr + offsetof(struct cb, u.tcb.tbd);
        cb->u.tcb.tcb_byte_count = 0;
        cb->u.tcb.threshold = nic->tx_threshold;
        cb->u.tcb.tbd_count = 1;
        cb->u.tcb.tbd.buf_addr = cpu_to_le32(pci_map_single(nic->pdev,
                skb->data, skb->len, PCI_DMA_TODEVICE));
-       // check for mapping failure?
+       /* check for mapping failure? */
        cb->u.tcb.tbd.size = cpu_to_le16(skb->len);
 }
 
@@ -1539,7 +1729,7 @@ static inline int e100_rx_indicate(struct nic *nic, struct rx *rx,
                /* Don't indicate if hardware indicates errors */
                nic->net_stats.rx_dropped++;
                dev_kfree_skb_any(skb);
-       } else if(actual_size > nic->netdev->mtu + VLAN_ETH_HLEN) {
+       } else if(actual_size > ETH_DATA_LEN + VLAN_ETH_HLEN) {
                /* Don't indicate oversized frames */
                nic->rx_over_length_errors++;
                nic->net_stats.rx_dropped++;
@@ -1706,6 +1896,7 @@ static int e100_poll(struct net_device *netdev, int *budget)
 static void e100_netpoll(struct net_device *netdev)
 {
        struct nic *nic = netdev_priv(netdev);
+
        e100_disable_irq(nic);
        e100_intr(nic->pdev->irq, netdev, NULL);
        e100_tx_clean(nic);
@@ -2108,6 +2299,8 @@ static void e100_diag_test(struct net_device *netdev,
        }
        for(i = 0; i < E100_TEST_LEN; i++)
                test->flags |= data[i] ? ETH_TEST_FL_FAILED : 0;
+
+       msleep_interruptible(4 * 1000);
 }
 
 static int e100_phys_id(struct net_device *netdev, u32 data)
index 93e9f8788751e462f31d2f2edb17212f7aa7e954..51c2b3a18b6f385f9c86698b7840cf70838025a0 100644 (file)
@@ -1270,7 +1270,7 @@ struct e1000_hw_stats {
 
 /* Structure containing variables used by the shared code (e1000_hw.c) */
 struct e1000_hw {
-    uint8_t *hw_addr;
+    uint8_t __iomem *hw_addr;
     uint8_t *flash_address;
     e1000_mac_type mac_type;
     e1000_phy_type phy_type;
index b82fd15d08911f3f004485c060986bc7a338d464..7c8a0a22dcd5425545389fb056f9e9a1f4ee8f90 100644 (file)
@@ -162,7 +162,7 @@ static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid);
 static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
 static void e1000_restore_vlan(struct e1000_adapter *adapter);
 
-static int e1000_suspend(struct pci_dev *pdev, uint32_t state);
+static int e1000_suspend(struct pci_dev *pdev, pm_message_t state);
 #ifdef CONFIG_PM
 static int e1000_resume(struct pci_dev *pdev);
 #endif
@@ -2767,7 +2767,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
                                        "  next_to_use          <%x>\n"
                                        "  next_to_clean        <%x>\n"
                                        "buffer_info[next_to_clean]\n"
-                                       "  dma                  <%zx>\n"
+                                       "  dma                  <%llx>\n"
                                        "  time_stamp           <%lx>\n"
                                        "  next_to_watch        <%x>\n"
                                        "  jiffies              <%lx>\n"
@@ -2776,7 +2776,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
                                E1000_READ_REG(&adapter->hw, TDT),
                                tx_ring->next_to_use,
                                i,
-                               tx_ring->buffer_info[i].dma,
+                               (unsigned long long)tx_ring->buffer_info[i].dma,
                                tx_ring->buffer_info[i].time_stamp,
                                eop,
                                jiffies,
@@ -3642,7 +3642,7 @@ e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx)
 }
 
 static int
-e1000_suspend(struct pci_dev *pdev, uint32_t state)
+e1000_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -3726,9 +3726,7 @@ e1000_suspend(struct pci_dev *pdev, uint32_t state)
        }
 
        pci_disable_device(pdev);
-
-       state = (state > 0) ? 3 : 0;
-       pci_set_power_state(pdev, state);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
 
        return 0;
 }
@@ -3741,13 +3739,13 @@ e1000_resume(struct pci_dev *pdev)
        struct e1000_adapter *adapter = netdev_priv(netdev);
        uint32_t manc, ret_val, swsm;
 
-       pci_set_power_state(pdev, 0);
+       pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
        ret_val = pci_enable_device(pdev);
        pci_set_master(pdev);
 
-       pci_enable_wake(pdev, 3, 0);
-       pci_enable_wake(pdev, 4, 0); /* 4 == D3 cold */
+       pci_enable_wake(pdev, PCI_D3hot, 0);
+       pci_enable_wake(pdev, PCI_D3cold, 0);
 
        e1000_reset(adapter);
        E1000_WRITE_REG(&adapter->hw, WUS, ~0);
index 1795425f512e1f789dbccea4492cc1d659ed2111..8c62ced2c9b2304a99808f07a26ecb61ee0ce169 100644 (file)
@@ -1263,8 +1263,8 @@ speedo_init_rx_ring(struct net_device *dev)
        for (i = 0; i < RX_RING_SIZE; i++) {
                struct sk_buff *skb;
                skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-               /* XXX: do we really want to call this before the NULL check? --hch */
-               rx_align(skb);                  /* Align IP on 16 byte boundary */
+               if (skb)
+                       rx_align(skb);        /* Align IP on 16 byte boundary */
                sp->rx_skbuff[i] = skb;
                if (skb == NULL)
                        break;                  /* OK.  Just initially short of Rx bufs. */
@@ -1654,8 +1654,8 @@ static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry)
        struct sk_buff *skb;
        /* Get a fresh skbuff to replace the consumed one. */
        skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-       /* XXX: do we really want to call this before the NULL check? --hch */
-       rx_align(skb);                          /* Align IP on 16 byte boundary */
+       if (skb)
+               rx_align(skb);          /* Align IP on 16 byte boundary */
        sp->rx_skbuff[entry] = skb;
        if (skb == NULL) {
                sp->rx_ringp[entry] = NULL;
index 64f0f697c958ad399317fe7cc628bf93d9f73018..d6eefdb71c174889b6491635121fe33f9b789594 100644 (file)
  *     0.33: 16 May 2005: Support for MCP51 added.
  *     0.34: 18 Jun 2005: Add DEV_NEED_LINKTIMER to all nForce nics.
  *     0.35: 26 Jun 2005: Support for MCP55 added.
+ *     0.36: 28 Jun 2005: Add jumbo frame support.
+ *     0.37: 10 Jul 2005: Additional ethtool support, cleanup of pci id list
+ *     0.38: 16 Jul 2005: tx irq rewrite: Use global flags instead of
+ *                        per-packet flags.
+ *      0.39: 18 Jul 2005: Add 64bit descriptor support.
+ *      0.40: 19 Jul 2005: Add support for mac address change.
+ *      0.41: 30 Jul 2005: Write back original MAC in nv_close instead
+ *                        of nv_remove
+ *      0.42: 06 Aug 2005: Fix lack of link speed initialization
+ *                        in the second (and later) nv_open call
  *
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  */
-#define FORCEDETH_VERSION              "0.35"
+#define FORCEDETH_VERSION              "0.41"
 #define DRV_NAME                       "forcedeth"
 
 #include <linux/module.h>
  * Hardware access:
  */
 
-#define DEV_NEED_LASTPACKET1   0x0001  /* set LASTPACKET1 in tx flags */
-#define DEV_IRQMASK_1          0x0002  /* use NVREG_IRQMASK_WANTED_1 for irq mask */
-#define DEV_IRQMASK_2          0x0004  /* use NVREG_IRQMASK_WANTED_2 for irq mask */
-#define DEV_NEED_TIMERIRQ      0x0008  /* set the timer irq flag in the irq mask */
-#define DEV_NEED_LINKTIMER     0x0010  /* poll link settings. Relies on the timer irq */
+#define DEV_NEED_TIMERIRQ      0x0001  /* set the timer irq flag in the irq mask */
+#define DEV_NEED_LINKTIMER     0x0002  /* poll link settings. Relies on the timer irq */
+#define DEV_HAS_LARGEDESC      0x0004  /* device supports jumbo frames and needs packet format 2 */
+#define DEV_HAS_HIGH_DMA        0x0008  /* device supports 64bit dma */
 
 enum {
        NvRegIrqStatus = 0x000,
@@ -146,13 +155,16 @@ enum {
 #define NVREG_IRQ_RX                   0x0002
 #define NVREG_IRQ_RX_NOBUF             0x0004
 #define NVREG_IRQ_TX_ERR               0x0008
-#define NVREG_IRQ_TX2                  0x0010
+#define NVREG_IRQ_TX_OK                        0x0010
 #define NVREG_IRQ_TIMER                        0x0020
 #define NVREG_IRQ_LINK                 0x0040
+#define NVREG_IRQ_TX_ERROR             0x0080
 #define NVREG_IRQ_TX1                  0x0100
-#define NVREG_IRQMASK_WANTED_1         0x005f
-#define NVREG_IRQMASK_WANTED_2         0x0147
-#define NVREG_IRQ_UNKNOWN              (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1))
+#define NVREG_IRQMASK_WANTED           0x00df
+
+#define NVREG_IRQ_UNKNOWN      (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR| \
+                                       NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX_ERROR| \
+                                       NVREG_IRQ_TX1))
 
        NvRegUnknownSetupReg6 = 0x008,
 #define NVREG_UNKSETUP6_VAL            3
@@ -286,6 +298,18 @@ struct ring_desc {
        u32 FlagLen;
 };
 
+struct ring_desc_ex {
+       u32 PacketBufferHigh;
+       u32 PacketBufferLow;
+       u32 Reserved;
+       u32 FlagLen;
+};
+
+typedef union _ring_type {
+       struct ring_desc* orig;
+       struct ring_desc_ex* ex;
+} ring_type;
+
 #define FLAG_MASK_V1 0xffff0000
 #define FLAG_MASK_V2 0xffffc000
 #define LEN_MASK_V1 (0xffffffff ^ FLAG_MASK_V1)
@@ -293,7 +317,7 @@ struct ring_desc {
 
 #define NV_TX_LASTPACKET       (1<<16)
 #define NV_TX_RETRYERROR       (1<<19)
-#define NV_TX_LASTPACKET1      (1<<24)
+#define NV_TX_FORCED_INTERRUPT (1<<24)
 #define NV_TX_DEFERRED         (1<<26)
 #define NV_TX_CARRIERLOST      (1<<27)
 #define NV_TX_LATECOLLISION    (1<<28)
@@ -303,7 +327,7 @@ struct ring_desc {
 
 #define NV_TX2_LASTPACKET      (1<<29)
 #define NV_TX2_RETRYERROR      (1<<18)
-#define NV_TX2_LASTPACKET1     (1<<23)
+#define NV_TX2_FORCED_INTERRUPT        (1<<30)
 #define NV_TX2_DEFERRED                (1<<25)
 #define NV_TX2_CARRIERLOST     (1<<26)
 #define NV_TX2_LATECOLLISION   (1<<27)
@@ -379,9 +403,13 @@ struct ring_desc {
 #define TX_LIMIT_START 62
 
 /* rx/tx mac addr + type + vlan + align + slack*/
-#define RX_NIC_BUFSIZE         (ETH_DATA_LEN + 64)
-/* even more slack */
-#define RX_ALLOC_BUFSIZE       (ETH_DATA_LEN + 128)
+#define NV_RX_HEADERS          (64)
+/* even more slack. */
+#define NV_RX_ALLOC_PAD                (64)
+
+/* maximum mtu size */
+#define NV_PKTLIMIT_1  ETH_DATA_LEN    /* hard limit not known */
+#define NV_PKTLIMIT_2  9100    /* Actual limit according to NVidia: 9202 */
 
 #define OOM_REFILL     (1+HZ/20)
 #define POLL_WAIT      (1+HZ/100)
@@ -396,6 +424,7 @@ struct ring_desc {
  */
 #define DESC_VER_1     0x0
 #define DESC_VER_2     (0x02100|NVREG_TXRXCTL_RXCHECK)
+#define DESC_VER_3      (0x02200|NVREG_TXRXCTL_RXCHECK)
 
 /* PHY defines */
 #define PHY_OUI_MARVELL        0x5043
@@ -468,11 +497,12 @@ struct fe_priv {
        /* rx specific fields.
         * Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
         */
-       struct ring_desc *rx_ring;
+       ring_type rx_ring;
        unsigned int cur_rx, refill_rx;
        struct sk_buff *rx_skbuff[RX_RING];
        dma_addr_t rx_dma[RX_RING];
        unsigned int rx_buf_sz;
+       unsigned int pkt_limit;
        struct timer_list oom_kick;
        struct timer_list nic_poll;
 
@@ -484,7 +514,7 @@ struct fe_priv {
        /*
         * tx specific fields.
         */
-       struct ring_desc *tx_ring;
+       ring_type tx_ring;
        unsigned int next_tx, nic_tx;
        struct sk_buff *tx_skbuff[TX_RING];
        dma_addr_t tx_dma[TX_RING];
@@ -519,6 +549,11 @@ static inline u32 nv_descr_getlength(struct ring_desc *prd, u32 v)
                & ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2);
 }
 
+static inline u32 nv_descr_getlength_ex(struct ring_desc_ex *prd, u32 v)
+{
+       return le32_to_cpu(prd->FlagLen) & LEN_MASK_V2;
+}
+
 static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target,
                                int delay, int delaymax, const char *msg)
 {
@@ -792,7 +827,7 @@ static int nv_alloc_rx(struct net_device *dev)
                nr = refill_rx % RX_RING;
                if (np->rx_skbuff[nr] == NULL) {
 
-                       skb = dev_alloc_skb(RX_ALLOC_BUFSIZE);
+                       skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
                        if (!skb)
                                break;
 
@@ -803,9 +838,16 @@ static int nv_alloc_rx(struct net_device *dev)
                }
                np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len,
                                                PCI_DMA_FROMDEVICE);
-               np->rx_ring[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]);
-               wmb();
-               np->rx_ring[nr].FlagLen = cpu_to_le32(RX_NIC_BUFSIZE | NV_RX_AVAIL);
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+                       np->rx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]);
+                       wmb();
+                       np->rx_ring.orig[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
+               } else {
+                       np->rx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
+                       np->rx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
+                       wmb();
+                       np->rx_ring.ex[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
+               }
                dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n",
                                        dev->name, refill_rx);
                refill_rx++;
@@ -831,19 +873,37 @@ static void nv_do_rx_refill(unsigned long data)
        enable_irq(dev->irq);
 }
 
-static int nv_init_ring(struct net_device *dev)
+static void nv_init_rx(struct net_device *dev) 
 {
        struct fe_priv *np = get_nvpriv(dev);
        int i;
 
-       np->next_tx = np->nic_tx = 0;
-       for (i = 0; i < TX_RING; i++)
-               np->tx_ring[i].FlagLen = 0;
-
        np->cur_rx = RX_RING;
        np->refill_rx = 0;
        for (i = 0; i < RX_RING; i++)
-               np->rx_ring[i].FlagLen = 0;
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+                       np->rx_ring.orig[i].FlagLen = 0;
+               else
+                       np->rx_ring.ex[i].FlagLen = 0;
+}
+
+static void nv_init_tx(struct net_device *dev)
+{
+       struct fe_priv *np = get_nvpriv(dev);
+       int i;
+
+       np->next_tx = np->nic_tx = 0;
+       for (i = 0; i < TX_RING; i++)
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+                       np->tx_ring.orig[i].FlagLen = 0;
+               else
+                       np->tx_ring.ex[i].FlagLen = 0;
+}
+
+static int nv_init_ring(struct net_device *dev)
+{
+       nv_init_tx(dev);
+       nv_init_rx(dev);
        return nv_alloc_rx(dev);
 }
 
@@ -852,7 +912,10 @@ static void nv_drain_tx(struct net_device *dev)
        struct fe_priv *np = get_nvpriv(dev);
        int i;
        for (i = 0; i < TX_RING; i++) {
-               np->tx_ring[i].FlagLen = 0;
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+                       np->tx_ring.orig[i].FlagLen = 0;
+               else
+                       np->tx_ring.ex[i].FlagLen = 0;
                if (np->tx_skbuff[i]) {
                        pci_unmap_single(np->pci_dev, np->tx_dma[i],
                                                np->tx_skbuff[i]->len,
@@ -869,7 +932,10 @@ static void nv_drain_rx(struct net_device *dev)
        struct fe_priv *np = get_nvpriv(dev);
        int i;
        for (i = 0; i < RX_RING; i++) {
-               np->rx_ring[i].FlagLen = 0;
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+                       np->rx_ring.orig[i].FlagLen = 0;
+               else
+                       np->rx_ring.ex[i].FlagLen = 0;
                wmb();
                if (np->rx_skbuff[i]) {
                        pci_unmap_single(np->pci_dev, np->rx_dma[i],
@@ -900,11 +966,19 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
        np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len,
                                        PCI_DMA_TODEVICE);
 
-       np->tx_ring[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
+       else {
+               np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+               np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+       }
 
        spin_lock_irq(&np->lock);
        wmb();
-       np->tx_ring[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags );
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags );
+       else
+               np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags );
        dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission.\n",
                                dev->name, np->next_tx);
        {
@@ -942,7 +1016,10 @@ static void nv_tx_done(struct net_device *dev)
        while (np->nic_tx != np->next_tx) {
                i = np->nic_tx % TX_RING;
 
-               Flags = le32_to_cpu(np->tx_ring[i].FlagLen);
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+                       Flags = le32_to_cpu(np->tx_ring.orig[i].FlagLen);
+               else
+                       Flags = le32_to_cpu(np->tx_ring.ex[i].FlagLen);
 
                dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n",
                                        dev->name, np->nic_tx, Flags);
@@ -993,9 +1070,56 @@ static void nv_tx_timeout(struct net_device *dev)
        struct fe_priv *np = get_nvpriv(dev);
        u8 __iomem *base = get_hwbase(dev);
 
-       dprintk(KERN_DEBUG "%s: Got tx_timeout. irq: %08x\n", dev->name,
+       printk(KERN_INFO "%s: Got tx_timeout. irq: %08x\n", dev->name,
                        readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK);
 
+       {
+               int i;
+
+               printk(KERN_INFO "%s: Ring at %lx: next %d nic %d\n",
+                               dev->name, (unsigned long)np->ring_addr,
+                               np->next_tx, np->nic_tx);
+               printk(KERN_INFO "%s: Dumping tx registers\n", dev->name);
+               for (i=0;i<0x400;i+= 32) {
+                       printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+                                       i,
+                                       readl(base + i + 0), readl(base + i + 4),
+                                       readl(base + i + 8), readl(base + i + 12),
+                                       readl(base + i + 16), readl(base + i + 20),
+                                       readl(base + i + 24), readl(base + i + 28));
+               }
+               printk(KERN_INFO "%s: Dumping tx ring\n", dev->name);
+               for (i=0;i<TX_RING;i+= 4) {
+                       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+                               printk(KERN_INFO "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n",
+                                      i, 
+                                      le32_to_cpu(np->tx_ring.orig[i].PacketBuffer),
+                                      le32_to_cpu(np->tx_ring.orig[i].FlagLen),
+                                      le32_to_cpu(np->tx_ring.orig[i+1].PacketBuffer),
+                                      le32_to_cpu(np->tx_ring.orig[i+1].FlagLen),
+                                      le32_to_cpu(np->tx_ring.orig[i+2].PacketBuffer),
+                                      le32_to_cpu(np->tx_ring.orig[i+2].FlagLen),
+                                      le32_to_cpu(np->tx_ring.orig[i+3].PacketBuffer),
+                                      le32_to_cpu(np->tx_ring.orig[i+3].FlagLen));
+                       } else {
+                               printk(KERN_INFO "%03x: %08x %08x %08x // %08x %08x %08x // %08x %08x %08x // %08x %08x %08x\n",
+                                      i, 
+                                      le32_to_cpu(np->tx_ring.ex[i].PacketBufferHigh),
+                                      le32_to_cpu(np->tx_ring.ex[i].PacketBufferLow),
+                                      le32_to_cpu(np->tx_ring.ex[i].FlagLen),
+                                      le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferHigh),
+                                      le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferLow),
+                                      le32_to_cpu(np->tx_ring.ex[i+1].FlagLen),
+                                      le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferHigh),
+                                      le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferLow),
+                                      le32_to_cpu(np->tx_ring.ex[i+2].FlagLen),
+                                      le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferHigh),
+                                      le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferLow),
+                                      le32_to_cpu(np->tx_ring.ex[i+3].FlagLen));
+                       }
+               }
+       }
+
        spin_lock_irq(&np->lock);
 
        /* 1) stop tx engine */
@@ -1009,7 +1133,10 @@ static void nv_tx_timeout(struct net_device *dev)
                printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name);
                nv_drain_tx(dev);
                np->next_tx = np->nic_tx = 0;
-               writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+                       writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
+               else
+                       writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr);
                netif_wake_queue(dev);
        }
 
@@ -1084,8 +1211,13 @@ static void nv_rx_process(struct net_device *dev)
                        break;  /* we scanned the whole ring - do not continue */
 
                i = np->cur_rx % RX_RING;
-               Flags = le32_to_cpu(np->rx_ring[i].FlagLen);
-               len = nv_descr_getlength(&np->rx_ring[i], np->desc_ver);
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+                       Flags = le32_to_cpu(np->rx_ring.orig[i].FlagLen);
+                       len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver);
+               } else {
+                       Flags = le32_to_cpu(np->rx_ring.ex[i].FlagLen);
+                       len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver);
+               }
 
                dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n",
                                        dev->name, np->cur_rx, Flags);
@@ -1207,15 +1339,133 @@ next_pkt:
        }
 }
 
+static void set_bufsize(struct net_device *dev)
+{
+       struct fe_priv *np = netdev_priv(dev);
+
+       if (dev->mtu <= ETH_DATA_LEN)
+               np->rx_buf_sz = ETH_DATA_LEN + NV_RX_HEADERS;
+       else
+               np->rx_buf_sz = dev->mtu + NV_RX_HEADERS;
+}
+
 /*
  * nv_change_mtu: dev->change_mtu function
  * Called with dev_base_lock held for read.
  */
 static int nv_change_mtu(struct net_device *dev, int new_mtu)
 {
-       if (new_mtu > ETH_DATA_LEN)
+       struct fe_priv *np = get_nvpriv(dev);
+       int old_mtu;
+
+       if (new_mtu < 64 || new_mtu > np->pkt_limit)
                return -EINVAL;
+
+       old_mtu = dev->mtu;
        dev->mtu = new_mtu;
+
+       /* return early if the buffer sizes will not change */
+       if (old_mtu <= ETH_DATA_LEN && new_mtu <= ETH_DATA_LEN)
+               return 0;
+       if (old_mtu == new_mtu)
+               return 0;
+
+       /* synchronized against open : rtnl_lock() held by caller */
+       if (netif_running(dev)) {
+               u8 __iomem *base = get_hwbase(dev);
+               /*
+                * It seems that the nic preloads valid ring entries into an
+                * internal buffer. The procedure for flushing everything is
+                * guessed, there is probably a simpler approach.
+                * Changing the MTU is a rare event, it shouldn't matter.
+                */
+               disable_irq(dev->irq);
+               spin_lock_bh(&dev->xmit_lock);
+               spin_lock(&np->lock);
+               /* stop engines */
+               nv_stop_rx(dev);
+               nv_stop_tx(dev);
+               nv_txrx_reset(dev);
+               /* drain rx queue */
+               nv_drain_rx(dev);
+               nv_drain_tx(dev);
+               /* reinit driver view of the rx queue */
+               nv_init_rx(dev);
+               nv_init_tx(dev);
+               /* alloc new rx buffers */
+               set_bufsize(dev);
+               if (nv_alloc_rx(dev)) {
+                       if (!np->in_shutdown)
+                               mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+               }
+               /* reinit nic view of the rx queue */
+               writel(np->rx_buf_sz, base + NvRegOffloadConfig);
+               writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr);
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+                       writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
+               else
+                       writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr);
+               writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT),
+                       base + NvRegRingSizes);
+               pci_push(base);
+               writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl);
+               pci_push(base);
+
+               /* restart rx engine */
+               nv_start_rx(dev);
+               nv_start_tx(dev);
+               spin_unlock(&np->lock);
+               spin_unlock_bh(&dev->xmit_lock);
+               enable_irq(dev->irq);
+       }
+       return 0;
+}
+
+static void nv_copy_mac_to_hw(struct net_device *dev)
+{
+       u8 __iomem *base = get_hwbase(dev);
+       u32 mac[2];
+
+       mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) +
+                       (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24);
+       mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8);
+
+       writel(mac[0], base + NvRegMacAddrA);
+       writel(mac[1], base + NvRegMacAddrB);
+}
+
+/*
+ * nv_set_mac_address: dev->set_mac_address function
+ * Called with rtnl_lock() held.
+ */
+static int nv_set_mac_address(struct net_device *dev, void *addr)
+{
+       struct fe_priv *np = get_nvpriv(dev);
+       struct sockaddr *macaddr = (struct sockaddr*)addr;
+
+       if(!is_valid_ether_addr(macaddr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       /* synchronized against open : rtnl_lock() held by caller */
+       memcpy(dev->dev_addr, macaddr->sa_data, ETH_ALEN);
+
+       if (netif_running(dev)) {
+               spin_lock_bh(&dev->xmit_lock);
+               spin_lock_irq(&np->lock);
+
+               /* stop rx engine */
+               nv_stop_rx(dev);
+
+               /* set mac address */
+               nv_copy_mac_to_hw(dev);
+
+               /* restart rx engine */
+               nv_start_rx(dev);
+               spin_unlock_irq(&np->lock);
+               spin_unlock_bh(&dev->xmit_lock);
+       } else {
+               nv_copy_mac_to_hw(dev);
+       }
        return 0;
 }
 
@@ -1470,7 +1720,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
                if (!(events & np->irqmask))
                        break;
 
-               if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) {
+               if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX_OK|NVREG_IRQ_TX_ERROR|NVREG_IRQ_TX_ERR)) {
                        spin_lock(&np->lock);
                        nv_tx_done(dev);
                        spin_unlock(&np->lock);
@@ -1761,6 +2011,50 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
        return 0;
 }
 
+#define FORCEDETH_REGS_VER     1
+#define FORCEDETH_REGS_SIZE    0x400 /* 256 32-bit registers */
+
+static int nv_get_regs_len(struct net_device *dev)
+{
+       return FORCEDETH_REGS_SIZE;
+}
+
+static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf)
+{
+       struct fe_priv *np = get_nvpriv(dev);
+       u8 __iomem *base = get_hwbase(dev);
+       u32 *rbuf = buf;
+       int i;
+
+       regs->version = FORCEDETH_REGS_VER;
+       spin_lock_irq(&np->lock);
+       for (i=0;i<FORCEDETH_REGS_SIZE/sizeof(u32);i++)
+               rbuf[i] = readl(base + i*sizeof(u32));
+       spin_unlock_irq(&np->lock);
+}
+
+static int nv_nway_reset(struct net_device *dev)
+{
+       struct fe_priv *np = get_nvpriv(dev);
+       int ret;
+
+       spin_lock_irq(&np->lock);
+       if (np->autoneg) {
+               int bmcr;
+
+               bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
+               bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+               mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
+
+               ret = 0;
+       } else {
+               ret = -EINVAL;
+       }
+       spin_unlock_irq(&np->lock);
+
+       return ret;
+}
+
 static struct ethtool_ops ops = {
        .get_drvinfo = nv_get_drvinfo,
        .get_link = ethtool_op_get_link,
@@ -1768,6 +2062,9 @@ static struct ethtool_ops ops = {
        .set_wol = nv_set_wol,
        .get_settings = nv_get_settings,
        .set_settings = nv_set_settings,
+       .get_regs_len = nv_get_regs_len,
+       .get_regs = nv_get_regs,
+       .nway_reset = nv_nway_reset,
 };
 
 static int nv_open(struct net_device *dev)
@@ -1792,6 +2089,7 @@ static int nv_open(struct net_device *dev)
        writel(0, base + NvRegAdapterControl);
 
        /* 2) initialize descriptor rings */
+       set_bufsize(dev);
        oom = nv_init_ring(dev);
 
        writel(0, base + NvRegLinkSpeed);
@@ -1802,20 +2100,14 @@ static int nv_open(struct net_device *dev)
        np->in_shutdown = 0;
 
        /* 3) set mac address */
-       {
-               u32 mac[2];
-
-               mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) +
-                               (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24);
-               mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8);
-
-               writel(mac[0], base + NvRegMacAddrA);
-               writel(mac[1], base + NvRegMacAddrB);
-       }
+       nv_copy_mac_to_hw(dev);
 
        /* 4) give hw rings */
        writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr);
-       writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
+       else
+               writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr);
        writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT),
                base + NvRegRingSizes);
 
@@ -1837,7 +2129,7 @@ static int nv_open(struct net_device *dev)
        writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1);
        writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus);
        writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags);
-       writel(NVREG_OFFLOAD_NORMAL, base + NvRegOffloadConfig);
+       writel(np->rx_buf_sz, base + NvRegOffloadConfig);
 
        writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus);
        get_random_bytes(&i, sizeof(i));
@@ -1888,6 +2180,9 @@ static int nv_open(struct net_device *dev)
                writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
                dprintk(KERN_INFO "startup: got 0x%08x.\n", miistat);
        }
+       /* set linkspeed to invalid value, thus force nv_update_linkspeed
+        * to init hw */
+       np->linkspeed = 0;
        ret = nv_update_linkspeed(dev);
        nv_start_rx(dev);
        nv_start_tx(dev);
@@ -1942,6 +2237,12 @@ static int nv_close(struct net_device *dev)
        if (np->wolenabled)
                nv_start_rx(dev);
 
+       /* special op: write back the misordered MAC address - otherwise
+        * the next nv_probe would see a wrong address.
+        */
+       writel(np->orig_mac[0], base + NvRegMacAddrA);
+       writel(np->orig_mac[1], base + NvRegMacAddrB);
+
        /* FIXME: power down nic */
 
        return 0;
@@ -2006,32 +2307,55 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        }
 
        /* handle different descriptor versions */
-       if (pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_1 ||
-               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_2 ||
-               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3 ||    
-               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 ||
-               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_13)
-               np->desc_ver = DESC_VER_1;
-       else
+       if (id->driver_data & DEV_HAS_HIGH_DMA) {
+               /* packet format 3: supports 40-bit addressing */
+               np->desc_ver = DESC_VER_3;
+               if (pci_set_dma_mask(pci_dev, 0x0000007fffffffffULL)) {
+                       printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n",
+                                       pci_name(pci_dev));
+               }
+       } else if (id->driver_data & DEV_HAS_LARGEDESC) {
+               /* packet format 2: supports jumbo frames */
                np->desc_ver = DESC_VER_2;
+       } else {
+               /* original packet format */
+               np->desc_ver = DESC_VER_1;
+       }
+
+       np->pkt_limit = NV_PKTLIMIT_1;
+       if (id->driver_data & DEV_HAS_LARGEDESC)
+               np->pkt_limit = NV_PKTLIMIT_2;
 
        err = -ENOMEM;
        np->base = ioremap(addr, NV_PCI_REGSZ);
        if (!np->base)
                goto out_relreg;
        dev->base_addr = (unsigned long)np->base;
+
        dev->irq = pci_dev->irq;
-       np->rx_ring = pci_alloc_consistent(pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING),
-                                               &np->ring_addr);
-       if (!np->rx_ring)
-               goto out_unmap;
-       np->tx_ring = &np->rx_ring[RX_RING];
+
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+               np->rx_ring.orig = pci_alloc_consistent(pci_dev,
+                                       sizeof(struct ring_desc) * (RX_RING + TX_RING),
+                                       &np->ring_addr);
+               if (!np->rx_ring.orig)
+                       goto out_unmap;
+               np->tx_ring.orig = &np->rx_ring.orig[RX_RING];
+       } else {
+               np->rx_ring.ex = pci_alloc_consistent(pci_dev,
+                                       sizeof(struct ring_desc_ex) * (RX_RING + TX_RING),
+                                       &np->ring_addr);
+               if (!np->rx_ring.ex)
+                       goto out_unmap;
+               np->tx_ring.ex = &np->rx_ring.ex[RX_RING];
+       }
 
        dev->open = nv_open;
        dev->stop = nv_close;
        dev->hard_start_xmit = nv_start_xmit;
        dev->get_stats = nv_get_stats;
        dev->change_mtu = nv_change_mtu;
+       dev->set_mac_address = nv_set_mac_address;
        dev->set_multicast_list = nv_set_multicast;
 #ifdef CONFIG_NET_POLL_CONTROLLER
        dev->poll_controller = nv_poll_controller;
@@ -2080,17 +2404,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
 
        if (np->desc_ver == DESC_VER_1) {
                np->tx_flags = NV_TX_LASTPACKET|NV_TX_VALID;
-               if (id->driver_data & DEV_NEED_LASTPACKET1)
-                       np->tx_flags |= NV_TX_LASTPACKET1;
        } else {
                np->tx_flags = NV_TX2_LASTPACKET|NV_TX2_VALID;
-               if (id->driver_data & DEV_NEED_LASTPACKET1)
-                       np->tx_flags |= NV_TX2_LASTPACKET1;
        }
-       if (id->driver_data & DEV_IRQMASK_1)
-               np->irqmask = NVREG_IRQMASK_WANTED_1;
-       if (id->driver_data & DEV_IRQMASK_2)
-               np->irqmask = NVREG_IRQMASK_WANTED_2;
+       np->irqmask = NVREG_IRQMASK_WANTED;
        if (id->driver_data & DEV_NEED_TIMERIRQ)
                np->irqmask |= NVREG_IRQ_TIMER;
        if (id->driver_data & DEV_NEED_LINKTIMER) {
@@ -2155,8 +2472,12 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        return 0;
 
 out_freering:
-       pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING),
-                               np->rx_ring, np->ring_addr);
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING),
+                                   np->rx_ring.orig, np->ring_addr);
+       else
+               pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (RX_RING + TX_RING),
+                                   np->rx_ring.ex, np->ring_addr);
        pci_set_drvdata(pci_dev, NULL);
 out_unmap:
        iounmap(get_hwbase(dev));
@@ -2174,18 +2495,14 @@ static void __devexit nv_remove(struct pci_dev *pci_dev)
 {
        struct net_device *dev = pci_get_drvdata(pci_dev);
        struct fe_priv *np = get_nvpriv(dev);
-       u8 __iomem *base = get_hwbase(dev);
 
        unregister_netdev(dev);
 
-       /* special op: write back the misordered MAC address - otherwise
-        * the next nv_probe would see a wrong address.
-        */
-       writel(np->orig_mac[0], base + NvRegMacAddrA);
-       writel(np->orig_mac[1], base + NvRegMacAddrB);
-
        /* free all structures */
-       pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring, np->ring_addr);
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring.orig, np->ring_addr);
+       else
+               pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (RX_RING + TX_RING), np->rx_ring.ex, np->ring_addr);
        iounmap(get_hwbase(dev));
        pci_release_regions(pci_dev);
        pci_disable_device(pci_dev);
@@ -2195,109 +2512,64 @@ static void __devexit nv_remove(struct pci_dev *pci_dev)
 
 static struct pci_device_id pci_tbl[] = {
        {       /* nForce Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_1,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_IRQMASK_1|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_1),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* nForce2 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_2,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_2),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* nForce3 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_3,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_3),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* nForce3 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_4,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_4),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
        },
        {       /* nForce3 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_5,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_5),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
        },
        {       /* nForce3 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_6,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_6),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
        },
        {       /* nForce3 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_7,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_7),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
        },
        {       /* CK804 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_8,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
        },
        {       /* CK804 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_9,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
        },
        {       /* MCP04 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_10,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
        },
        {       /* MCP04 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_11,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
        },
        {       /* MCP51 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_12,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA,
        },
        {       /* MCP51 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_13,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA,
        },
        {       /* MCP55 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_14,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
        },
        {       /* MCP55 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_15,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
        },
        {0,},
 };
index d9df1d9a5739c471c82ec43186c8312c90f6b63f..bc9a3bf8d5605d2301ad300b9f848cfefa267465 100644 (file)
@@ -204,6 +204,10 @@ KERN_INFO "   Further modifications by Keith Underwood <keithu@parl.clemson.edu>
 
 #define RUN_AT(x) (jiffies + (x))
 
+#ifndef ADDRLEN
+#define ADDRLEN 32
+#endif
+
 /* Condensed bus+endian portability operations. */
 #if ADDRLEN == 64
 #define cpu_to_leXX(addr)      cpu_to_le64(addr)
index 0cd54306e63680c6030a8ebdb82f9eff62aa7a4a..de087cd609d98fcf916c638187ed0df9b0e9eb59 100644 (file)
@@ -1,6 +1,6 @@
 config MKISS
        tristate "Serial port KISS driver"
-       depends on AX25 && BROKEN_ON_SMP
+       depends on AX25
        ---help---
          KISS is a protocol used for the exchange of data between a computer
          and a Terminal Node Controller (a small embedded system commonly
index a7f15d9f13e5ccd04faa36b6dda826c20e750fbb..5298096afbdb6efc7a9031ec2d746a0e3438772f 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/kmod.h>
 #include <linux/hdlcdrv.h>
 #include <linux/baycom.h>
+#include <linux/jiffies.h>
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 /* prototypes for ax25_encapsulate and ax25_rebuild_header */
 #include <net/ax25.h> 
@@ -287,7 +288,7 @@ static inline void baycom_int_freq(struct baycom_state *bc)
         * measure the interrupt frequency
         */
        bc->debug_vals.cur_intcnt++;
-       if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) {
+       if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
                bc->debug_vals.last_jiffies = cur_jiffies;
                bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
                bc->debug_vals.cur_intcnt = 0;
index 612ad452bee03b32d0dc0188907b37face5c7a9a..3b1bef1ee21507ec9a453382ed94810d0d5053ce 100644 (file)
@@ -84,6 +84,7 @@
 #include <linux/baycom.h>
 #include <linux/parport.h>
 #include <linux/bitops.h>
+#include <linux/jiffies.h>
 
 #include <asm/bug.h>
 #include <asm/system.h>
@@ -165,7 +166,7 @@ static void __inline__ baycom_int_freq(struct baycom_state *bc)
         * measure the interrupt frequency
         */
        bc->debug_vals.cur_intcnt++;
-       if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) {
+       if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
                bc->debug_vals.last_jiffies = cur_jiffies;
                bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
                bc->debug_vals.cur_intcnt = 0;
index 25f270b053788cbcb7b87265cab9036ca8add64a..232793d2ce6b0a46bf7d4a1a04e6683ac7624d14 100644 (file)
@@ -79,6 +79,7 @@
 #include <asm/io.h>
 #include <linux/hdlcdrv.h>
 #include <linux/baycom.h>
+#include <linux/jiffies.h>
 
 /* --------------------------------------------------------------------- */
 
@@ -159,7 +160,7 @@ static inline void baycom_int_freq(struct baycom_state *bc)
         * measure the interrupt frequency
         */
        bc->debug_vals.cur_intcnt++;
-       if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) {
+       if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
                bc->debug_vals.last_jiffies = cur_jiffies;
                bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
                bc->debug_vals.cur_intcnt = 0;
index eead85d009627980818e9c66b8420deca995ec46..be596a3eb3fd9b164b6107410498d4dde7a76ace 100644 (file)
@@ -69,6 +69,7 @@
 #include <asm/io.h>
 #include <linux/hdlcdrv.h>
 #include <linux/baycom.h>
+#include <linux/jiffies.h>
 
 /* --------------------------------------------------------------------- */
 
@@ -150,7 +151,7 @@ static inline void baycom_int_freq(struct baycom_state *bc)
         * measure the interrupt frequency
         */
        bc->debug_vals.cur_intcnt++;
-       if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) {
+       if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
                bc->debug_vals.last_jiffies = cur_jiffies;
                bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
                bc->debug_vals.cur_intcnt = 0;
index ba9f0580e1f9be97d9398bcfdccc6d7aa1754789..2946e037a9b1f1e4bab304c2982a0575bf07c69d 100644 (file)
@@ -98,7 +98,7 @@ static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
 
 static char bpq_eth_addr[6];
 
-static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *);
+static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
 static int bpq_device_event(struct notifier_block *, unsigned long, void *);
 static const char *bpq_print_ethaddr(const unsigned char *);
 
@@ -165,7 +165,7 @@ static inline int dev_is_ethdev(struct net_device *dev)
 /*
  *     Receive an AX.25 frame via an ethernet interface.
  */
-static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype)
+static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev)
 {
        int len;
        char * ptr;
index 3035422f5ad8c867dfdfaeb151f7e05647c572ca..63b1a2b86acb19650fdee9e84efb2e86e7971bed 100644 (file)
@@ -1,30 +1,19 @@
 /*
- *     MKISS Driver
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
  *
- *     This module:
- *             This module is free software; you can redistribute it and/or
- *             modify it under the terms of the GNU General Public License
- *             as published by the Free Software Foundation; either version
- *             2 of the License, or (at your option) any later version.
+ *  This program is distributed in the hope 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.
  *
- *             This module implements the AX.25 protocol for kernel-based
- *             devices like TTYs. It interfaces between a raw TTY, and the
- *             kernel's AX.25 protocol layers, just like slip.c.
- *             AX.25 needs to be separated from slip.c while slip.c is no
- *             longer a static kernel device since it is a module.
- *             This method clears the way to implement other kiss protocols
- *             like mkiss smack g8bpq ..... so far only mkiss is implemented.
+ *  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.
  *
- * Hans Alblas <hans@esrac.ele.tue.nl>
- *
- *     History
- *     Jonathan (G4KLX)        Fixed to match Linux networking changes - 2.1.15.
- *     Matthias (DG2FEF)       Added support for FlexNet CRC (on special request)
- *                              Fixed bug in ax25_close(): dev_lock_wait() was
- *                              called twice, causing a deadlock.
- *     Jeroen (PE1RXQ)         Removed old MKISS_MAGIC stuff and calls to
- *                             MOD_*_USE_COUNT
- *                             Remove cli() and fix rtnl lock usage.
+ * Copyright (C) Hans Alblas PE1AYX <hans@esrac.ele.tue.nl>
+ * Copyright (C) 2004, 05 Ralf Baechle DL5RB <ralf@linux-mips.org>
  */
 
 #include <linux/config.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
+#include <linux/jiffies.h>
 
 #include <net/ax25.h>
 
-#include "mkiss.h"
-
 #ifdef CONFIG_INET
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #endif
 
-static char banner[] __initdata = KERN_INFO "mkiss: AX.25 Multikiss, Hans Albas PE1AYX\n";
-
-typedef struct ax25_ctrl {
-       struct ax_disp ctrl;    /*                              */
-       struct net_device  dev; /* the device                   */
-} ax25_ctrl_t;
-
-static ax25_ctrl_t **ax25_ctrls;
-
-int ax25_maxdev = AX25_MAXDEV;         /* Can be overridden with insmod! */
-
-static struct tty_ldisc        ax_ldisc;
-
-static int ax25_init(struct net_device *);
-static int kiss_esc(unsigned char *, unsigned char *, int);
-static int kiss_esc_crc(unsigned char *, unsigned char *, unsigned short, int);
-static void kiss_unesc(struct ax_disp *, unsigned char);
+#define AX_MTU         236
+
+/* SLIP/KISS protocol characters. */
+#define END             0300           /* indicates end of frame       */
+#define ESC             0333           /* indicates byte stuffing      */
+#define ESC_END         0334           /* ESC ESC_END means END 'data' */
+#define ESC_ESC         0335           /* ESC ESC_ESC means ESC 'data' */
+
+struct mkiss {
+       struct tty_struct       *tty;   /* ptr to TTY structure         */
+       struct net_device       *dev;   /* easy for intr handling       */
+
+       /* These are pointers to the malloc()ed frame buffers. */
+       spinlock_t              buflock;/* lock for rbuf and xbuf */
+       unsigned char           *rbuff; /* receiver buffer              */
+       int                     rcount; /* received chars counter       */
+       unsigned char           *xbuff; /* transmitter buffer           */
+       unsigned char           *xhead; /* pointer to next byte to XMIT */
+       int                     xleft;  /* bytes left in XMIT queue     */
+
+       struct net_device_stats stats;
+
+       /* Detailed SLIP statistics. */
+       int             mtu;            /* Our mtu (to spot changes!)   */
+       int             buffsize;       /* Max buffers sizes            */
+
+       unsigned long   flags;          /* Flag values/ mode etc        */
+                                       /* long req'd: used by set_bit --RR */
+#define AXF_INUSE      0               /* Channel in use               */
+#define AXF_ESCAPE     1               /* ESC received                 */
+#define AXF_ERROR      2               /* Parity, etc. error           */
+#define AXF_KEEPTEST   3               /* Keepalive test flag          */
+#define AXF_OUTWAIT    4               /* is outpacket was flag        */
+
+       int             mode;
+        int            crcmode;        /* MW: for FlexNet, SMACK etc.  */
+#define CRC_MODE_NONE   0
+#define CRC_MODE_FLEX   1
+#define CRC_MODE_SMACK  2
+
+       atomic_t                refcnt;
+       struct semaphore        dead_sem;
+};
 
 /*---------------------------------------------------------------------------*/
 
-static const unsigned short Crc_flex_table[] = {
-  0x0f87, 0x1e0e, 0x2c95, 0x3d1c, 0x49a3, 0x582a, 0x6ab1, 0x7b38,
-  0x83cf, 0x9246, 0xa0dd, 0xb154, 0xc5eb, 0xd462, 0xe6f9, 0xf770,
-  0x1f06, 0x0e8f, 0x3c14, 0x2d9d, 0x5922, 0x48ab, 0x7a30, 0x6bb9,
-  0x934e, 0x82c7, 0xb05c, 0xa1d5, 0xd56a, 0xc4e3, 0xf678, 0xe7f1,
-  0x2e85, 0x3f0c, 0x0d97, 0x1c1e, 0x68a1, 0x7928, 0x4bb3, 0x5a3a,
-  0xa2cd, 0xb344, 0x81df, 0x9056, 0xe4e9, 0xf560, 0xc7fb, 0xd672,
-  0x3e04, 0x2f8d, 0x1d16, 0x0c9f, 0x7820, 0x69a9, 0x5b32, 0x4abb,
-  0xb24c, 0xa3c5, 0x915e, 0x80d7, 0xf468, 0xe5e1, 0xd77a, 0xc6f3,
-  0x4d83, 0x5c0a, 0x6e91, 0x7f18, 0x0ba7, 0x1a2e, 0x28b5, 0x393c,
-  0xc1cb, 0xd042, 0xe2d9, 0xf350, 0x87ef, 0x9666, 0xa4fd, 0xb574,
-  0x5d02, 0x4c8b, 0x7e10, 0x6f99, 0x1b26, 0x0aaf, 0x3834, 0x29bd,
-  0xd14a, 0xc0c3, 0xf258, 0xe3d1, 0x976e, 0x86e7, 0xb47c, 0xa5f5,
-  0x6c81, 0x7d08, 0x4f93, 0x5e1a, 0x2aa5, 0x3b2c, 0x09b7, 0x183e,
-  0xe0c9, 0xf140, 0xc3db, 0xd252, 0xa6ed, 0xb764, 0x85ff, 0x9476,
-  0x7c00, 0x6d89, 0x5f12, 0x4e9b, 0x3a24, 0x2bad, 0x1936, 0x08bf,
-  0xf048, 0xe1c1, 0xd35a, 0xc2d3, 0xb66c, 0xa7e5, 0x957e, 0x84f7,
-  0x8b8f, 0x9a06, 0xa89d, 0xb914, 0xcdab, 0xdc22, 0xeeb9, 0xff30,
-  0x07c7, 0x164e, 0x24d5, 0x355c, 0x41e3, 0x506a, 0x62f1, 0x7378,
-  0x9b0e, 0x8a87, 0xb81c, 0xa995, 0xdd2a, 0xcca3, 0xfe38, 0xefb1,
-  0x1746, 0x06cf, 0x3454, 0x25dd, 0x5162, 0x40eb, 0x7270, 0x63f9,
-  0xaa8d, 0xbb04, 0x899f, 0x9816, 0xeca9, 0xfd20, 0xcfbb, 0xde32,
-  0x26c5, 0x374c, 0x05d7, 0x145e, 0x60e1, 0x7168, 0x43f3, 0x527a,
-  0xba0c, 0xab85, 0x991e, 0x8897, 0xfc28, 0xeda1, 0xdf3a, 0xceb3,
-  0x3644, 0x27cd, 0x1556, 0x04df, 0x7060, 0x61e9, 0x5372, 0x42fb,
-  0xc98b, 0xd802, 0xea99, 0xfb10, 0x8faf, 0x9e26, 0xacbd, 0xbd34,
-  0x45c3, 0x544a, 0x66d1, 0x7758, 0x03e7, 0x126e, 0x20f5, 0x317c,
-  0xd90a, 0xc883, 0xfa18, 0xeb91, 0x9f2e, 0x8ea7, 0xbc3c, 0xadb5,
-  0x5542, 0x44cb, 0x7650, 0x67d9, 0x1366, 0x02ef, 0x3074, 0x21fd,
-  0xe889, 0xf900, 0xcb9b, 0xda12, 0xaead, 0xbf24, 0x8dbf, 0x9c36,
-  0x64c1, 0x7548, 0x47d3, 0x565a, 0x22e5, 0x336c, 0x01f7, 0x107e,
-  0xf808, 0xe981, 0xdb1a, 0xca93, 0xbe2c, 0xafa5, 0x9d3e, 0x8cb7,
-  0x7440, 0x65c9, 0x5752, 0x46db, 0x3264, 0x23ed, 0x1176, 0x00ff
+static const unsigned short crc_flex_table[] = {
+       0x0f87, 0x1e0e, 0x2c95, 0x3d1c, 0x49a3, 0x582a, 0x6ab1, 0x7b38,
+       0x83cf, 0x9246, 0xa0dd, 0xb154, 0xc5eb, 0xd462, 0xe6f9, 0xf770,
+       0x1f06, 0x0e8f, 0x3c14, 0x2d9d, 0x5922, 0x48ab, 0x7a30, 0x6bb9,
+       0x934e, 0x82c7, 0xb05c, 0xa1d5, 0xd56a, 0xc4e3, 0xf678, 0xe7f1,
+       0x2e85, 0x3f0c, 0x0d97, 0x1c1e, 0x68a1, 0x7928, 0x4bb3, 0x5a3a,
+       0xa2cd, 0xb344, 0x81df, 0x9056, 0xe4e9, 0xf560, 0xc7fb, 0xd672,
+       0x3e04, 0x2f8d, 0x1d16, 0x0c9f, 0x7820, 0x69a9, 0x5b32, 0x4abb,
+       0xb24c, 0xa3c5, 0x915e, 0x80d7, 0xf468, 0xe5e1, 0xd77a, 0xc6f3,
+       0x4d83, 0x5c0a, 0x6e91, 0x7f18, 0x0ba7, 0x1a2e, 0x28b5, 0x393c,
+       0xc1cb, 0xd042, 0xe2d9, 0xf350, 0x87ef, 0x9666, 0xa4fd, 0xb574,
+       0x5d02, 0x4c8b, 0x7e10, 0x6f99, 0x1b26, 0x0aaf, 0x3834, 0x29bd,
+       0xd14a, 0xc0c3, 0xf258, 0xe3d1, 0x976e, 0x86e7, 0xb47c, 0xa5f5,
+       0x6c81, 0x7d08, 0x4f93, 0x5e1a, 0x2aa5, 0x3b2c, 0x09b7, 0x183e,
+       0xe0c9, 0xf140, 0xc3db, 0xd252, 0xa6ed, 0xb764, 0x85ff, 0x9476,
+       0x7c00, 0x6d89, 0x5f12, 0x4e9b, 0x3a24, 0x2bad, 0x1936, 0x08bf,
+       0xf048, 0xe1c1, 0xd35a, 0xc2d3, 0xb66c, 0xa7e5, 0x957e, 0x84f7,
+       0x8b8f, 0x9a06, 0xa89d, 0xb914, 0xcdab, 0xdc22, 0xeeb9, 0xff30,
+       0x07c7, 0x164e, 0x24d5, 0x355c, 0x41e3, 0x506a, 0x62f1, 0x7378,
+       0x9b0e, 0x8a87, 0xb81c, 0xa995, 0xdd2a, 0xcca3, 0xfe38, 0xefb1,
+       0x1746, 0x06cf, 0x3454, 0x25dd, 0x5162, 0x40eb, 0x7270, 0x63f9,
+       0xaa8d, 0xbb04, 0x899f, 0x9816, 0xeca9, 0xfd20, 0xcfbb, 0xde32,
+       0x26c5, 0x374c, 0x05d7, 0x145e, 0x60e1, 0x7168, 0x43f3, 0x527a,
+       0xba0c, 0xab85, 0x991e, 0x8897, 0xfc28, 0xeda1, 0xdf3a, 0xceb3,
+       0x3644, 0x27cd, 0x1556, 0x04df, 0x7060, 0x61e9, 0x5372, 0x42fb,
+       0xc98b, 0xd802, 0xea99, 0xfb10, 0x8faf, 0x9e26, 0xacbd, 0xbd34,
+       0x45c3, 0x544a, 0x66d1, 0x7758, 0x03e7, 0x126e, 0x20f5, 0x317c,
+       0xd90a, 0xc883, 0xfa18, 0xeb91, 0x9f2e, 0x8ea7, 0xbc3c, 0xadb5,
+       0x5542, 0x44cb, 0x7650, 0x67d9, 0x1366, 0x02ef, 0x3074, 0x21fd,
+       0xe889, 0xf900, 0xcb9b, 0xda12, 0xaead, 0xbf24, 0x8dbf, 0x9c36,
+       0x64c1, 0x7548, 0x47d3, 0x565a, 0x22e5, 0x336c, 0x01f7, 0x107e,
+       0xf808, 0xe981, 0xdb1a, 0xca93, 0xbe2c, 0xafa5, 0x9d3e, 0x8cb7,
+       0x7440, 0x65c9, 0x5752, 0x46db, 0x3264, 0x23ed, 0x1176, 0x00ff
 };
 
-/*---------------------------------------------------------------------------*/
-
 static unsigned short calc_crc_flex(unsigned char *cp, int size)
 {
-    unsigned short crc = 0xffff;
-    
-    while (size--)
-       crc = (crc << 8) ^ Crc_flex_table[((crc >> 8) ^ *cp++) & 0xff];
+       unsigned short crc = 0xffff;
 
-    return crc;
-}
+       while (size--)
+               crc = (crc << 8) ^ crc_flex_table[((crc >> 8) ^ *cp++) & 0xff];
 
-/*---------------------------------------------------------------------------*/
+       return crc;
+}
 
 static int check_crc_flex(unsigned char *cp, int size)
 {
-  unsigned short crc = 0xffff;
+       unsigned short crc = 0xffff;
 
-  if (size < 3)
-      return -1;
+       if (size < 3)
+               return -1;
 
-  while (size--)
-      crc = (crc << 8) ^ Crc_flex_table[((crc >> 8) ^ *cp++) & 0xff];
+       while (size--)
+               crc = (crc << 8) ^ crc_flex_table[((crc >> 8) ^ *cp++) & 0xff];
 
-  if ((crc & 0xffff) != 0x7070) 
-      return -1;
+       if ((crc & 0xffff) != 0x7070)
+               return -1;
 
-  return 0;
+       return 0;
 }
 
-/*---------------------------------------------------------------------------*/
+/*
+ * Standard encapsulation
+ */
 
-/* Find a free channel, and link in this `tty' line. */
-static inline struct ax_disp *ax_alloc(void)
+static int kiss_esc(unsigned char *s, unsigned char *d, int len)
 {
-       ax25_ctrl_t *axp=NULL;
-       int i;
+       unsigned char *ptr = d;
+       unsigned char c;
 
-       for (i = 0; i < ax25_maxdev; i++) {
-               axp = ax25_ctrls[i];
+       /*
+        * Send an initial END character to flush out any data that may have
+        * accumulated in the receiver due to line noise.
+        */
 
-               /* Not allocated ? */
-               if (axp == NULL)
-                       break;
+       *ptr++ = END;
 
-               /* Not in use ? */
-               if (!test_and_set_bit(AXF_INUSE, &axp->ctrl.flags))
+       while (len-- > 0) {
+               switch (c = *s++) {
+               case END:
+                       *ptr++ = ESC;
+                       *ptr++ = ESC_END;
                        break;
+               case ESC:
+                       *ptr++ = ESC;
+                       *ptr++ = ESC_ESC;
+                       break;
+               default:
+                       *ptr++ = c;
+                       break;
+               }
        }
 
-       /* Sorry, too many, all slots in use */
-       if (i >= ax25_maxdev)
-               return NULL;
+       *ptr++ = END;
+
+       return ptr - d;
+}
+
+/*
+ * MW:
+ * OK its ugly, but tell me a better solution without copying the
+ * packet to a temporary buffer :-)
+ */
+static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc,
+       int len)
+{
+       unsigned char *ptr = d;
+       unsigned char c=0;
+
+       *ptr++ = END;
+       while (len > 0) {
+               if (len > 2)
+                       c = *s++;
+               else if (len > 1)
+                       c = crc >> 8;
+               else if (len > 0)
+                       c = crc & 0xff;
+
+               len--;
 
-       /* If no channels are available, allocate one */
-       if (axp == NULL && (ax25_ctrls[i] = kmalloc(sizeof(ax25_ctrl_t), GFP_KERNEL)) != NULL) {
-               axp = ax25_ctrls[i];
+               switch (c) {
+               case END:
+                       *ptr++ = ESC;
+                       *ptr++ = ESC_END;
+                       break;
+               case ESC:
+                       *ptr++ = ESC;
+                       *ptr++ = ESC_ESC;
+                       break;
+               default:
+                       *ptr++ = c;
+                       break;
+               }
        }
-       memset(axp, 0, sizeof(ax25_ctrl_t));
-
-       /* Initialize channel control data */
-       set_bit(AXF_INUSE, &axp->ctrl.flags);
-       sprintf(axp->dev.name, "ax%d", i++);
-       axp->ctrl.tty      = NULL;
-       axp->dev.base_addr = i;
-       axp->dev.priv      = (void *)&axp->ctrl;
-       axp->dev.next      = NULL;
-       axp->dev.init      = ax25_init;
-
-       if (axp != NULL) {
-               /*
-                * register device so that it can be ifconfig'ed
-                * ax25_init() will be called as a side-effect
-                * SIDE-EFFECT WARNING: ax25_init() CLEARS axp->ctrl !
-                */
-               if (register_netdev(&axp->dev) == 0) {
-                       /* (Re-)Set the INUSE bit.   Very Important! */
-                       set_bit(AXF_INUSE, &axp->ctrl.flags);
-                       axp->ctrl.dev = &axp->dev;
-                       axp->dev.priv = (void *) &axp->ctrl;
-
-                       return &axp->ctrl;
-               } else {
-                       clear_bit(AXF_INUSE,&axp->ctrl.flags);
-                       printk(KERN_ERR "mkiss: ax_alloc() - register_netdev() failure.\n");
+       *ptr++ = END;
+
+       return ptr - d;
+}
+
+/* Send one completely decapsulated AX.25 packet to the AX.25 layer. */
+static void ax_bump(struct mkiss *ax)
+{
+       struct sk_buff *skb;
+       int count;
+
+       spin_lock_bh(&ax->buflock);
+       if (ax->rbuff[0] > 0x0f) {
+               if (ax->rbuff[0] & 0x20) {
+                       ax->crcmode = CRC_MODE_FLEX;
+                       if (check_crc_flex(ax->rbuff, ax->rcount) < 0) {
+                               ax->stats.rx_errors++;
+                               return;
+                       }
+                       ax->rcount -= 2;
+                        /* dl9sau bugfix: the trailling two bytes flexnet crc
+                         * will not be passed to the kernel. thus we have
+                         * to correct the kissparm signature, because it
+                         * indicates a crc but there's none
+                        */
+                        *ax->rbuff &= ~0x20;
                }
+       }
+       spin_unlock_bh(&ax->buflock);
+
+       count = ax->rcount;
+
+       if ((skb = dev_alloc_skb(count)) == NULL) {
+               printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n",
+                      ax->dev->name);
+               ax->stats.rx_dropped++;
+               return;
        }
 
-       return NULL;
+       spin_lock_bh(&ax->buflock);
+       memcpy(skb_put(skb,count), ax->rbuff, count);
+       spin_unlock_bh(&ax->buflock);
+       skb->protocol = ax25_type_trans(skb, ax->dev);
+       netif_rx(skb);
+       ax->dev->last_rx = jiffies;
+       ax->stats.rx_packets++;
+       ax->stats.rx_bytes += count;
 }
 
-/* Free an AX25 channel. */
-static inline void ax_free(struct ax_disp *ax)
+static void kiss_unesc(struct mkiss *ax, unsigned char s)
 {
-       /* Free all AX25 frame buffers. */
-       if (ax->rbuff)
-               kfree(ax->rbuff);
-       ax->rbuff = NULL;
-       if (ax->xbuff)
-               kfree(ax->xbuff);
-       ax->xbuff = NULL;
-       if (!test_and_clear_bit(AXF_INUSE, &ax->flags))
-               printk(KERN_ERR "mkiss: %s: ax_free for already free unit.\n", ax->dev->name);
+       switch (s) {
+       case END:
+               /* drop keeptest bit = VSV */
+               if (test_bit(AXF_KEEPTEST, &ax->flags))
+                       clear_bit(AXF_KEEPTEST, &ax->flags);
+
+               if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2))
+                       ax_bump(ax);
+
+               clear_bit(AXF_ESCAPE, &ax->flags);
+               ax->rcount = 0;
+               return;
+
+       case ESC:
+               set_bit(AXF_ESCAPE, &ax->flags);
+               return;
+       case ESC_ESC:
+               if (test_and_clear_bit(AXF_ESCAPE, &ax->flags))
+                       s = ESC;
+               break;
+       case ESC_END:
+               if (test_and_clear_bit(AXF_ESCAPE, &ax->flags))
+                       s = END;
+               break;
+       }
+
+       spin_lock_bh(&ax->buflock);
+       if (!test_bit(AXF_ERROR, &ax->flags)) {
+               if (ax->rcount < ax->buffsize) {
+                       ax->rbuff[ax->rcount++] = s;
+                       spin_unlock_bh(&ax->buflock);
+                       return;
+               }
+
+               ax->stats.rx_over_errors++;
+               set_bit(AXF_ERROR, &ax->flags);
+       }
+       spin_unlock_bh(&ax->buflock);
+}
+
+static int ax_set_mac_address(struct net_device *dev, void *addr)
+{
+       struct sockaddr_ax25 *sa = addr;
+
+       spin_lock_irq(&dev->xmit_lock);
+       memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN);
+       spin_unlock_irq(&dev->xmit_lock);
+
+       return 0;
 }
 
-static void ax_changedmtu(struct ax_disp *ax)
+/*---------------------------------------------------------------------------*/
+
+static void ax_changedmtu(struct mkiss *ax)
 {
        struct net_device *dev = ax->dev;
        unsigned char *xbuff, *rbuff, *oxbuff, *orbuff;
@@ -236,7 +348,8 @@ static void ax_changedmtu(struct ax_disp *ax)
        rbuff = kmalloc(len + 4, GFP_ATOMIC);
 
        if (xbuff == NULL || rbuff == NULL)  {
-               printk(KERN_ERR "mkiss: %s: unable to grow ax25 buffers, MTU change cancelled.\n",
+               printk(KERN_ERR "mkiss: %s: unable to grow ax25 buffers, "
+                      "MTU change cancelled.\n",
                       ax->dev->name);
                dev->mtu = ax->mtu;
                if (xbuff != NULL)
@@ -258,7 +371,7 @@ static void ax_changedmtu(struct ax_disp *ax)
                        memcpy(ax->xbuff, ax->xhead, ax->xleft);
                } else  {
                        ax->xleft = 0;
-                       ax->tx_dropped++;
+                       ax->stats.tx_dropped++;
                }
        }
 
@@ -269,7 +382,7 @@ static void ax_changedmtu(struct ax_disp *ax)
                        memcpy(ax->rbuff, orbuff, ax->rcount);
                } else  {
                        ax->rcount = 0;
-                       ax->rx_over_errors++;
+                       ax->stats.rx_over_errors++;
                        set_bit(AXF_ERROR, &ax->flags);
                }
        }
@@ -279,72 +392,14 @@ static void ax_changedmtu(struct ax_disp *ax)
 
        spin_unlock_bh(&ax->buflock);
 
-       if (oxbuff != NULL)
-               kfree(oxbuff);
-       if (orbuff != NULL)
-               kfree(orbuff);
-}
-
-
-/* Set the "sending" flag.  This must be atomic. */
-static inline void ax_lock(struct ax_disp *ax)
-{
-       netif_stop_queue(ax->dev);
-}
-
-
-/* Clear the "sending" flag.  This must be atomic. */
-static inline void ax_unlock(struct ax_disp *ax)
-{
-       netif_start_queue(ax->dev);
-}
-
-/* Send one completely decapsulated AX.25 packet to the AX.25 layer. */
-static void ax_bump(struct ax_disp *ax)
-{
-       struct sk_buff *skb;
-       int count;
-
-       spin_lock_bh(&ax->buflock);
-       if (ax->rbuff[0] > 0x0f) {
-               if (ax->rbuff[0] & 0x20) {
-                       ax->crcmode = CRC_MODE_FLEX;
-                       if (check_crc_flex(ax->rbuff, ax->rcount) < 0) {
-                               ax->rx_errors++;
-                               return;
-                       }
-                       ax->rcount -= 2;
-                        /* dl9sau bugfix: the trailling two bytes flexnet crc
-                         * will not be passed to the kernel. thus we have
-                         * to correct the kissparm signature, because it
-                         * indicates a crc but there's none
-                        */
-                        *ax->rbuff &= ~0x20;
-               }
-       }
-       spin_unlock_bh(&ax->buflock);
-
-       count = ax->rcount;
-
-       if ((skb = dev_alloc_skb(count)) == NULL) {
-               printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n", ax->dev->name);
-               ax->rx_dropped++;
-               return;
-       }
-
-       spin_lock_bh(&ax->buflock);
-       memcpy(skb_put(skb,count), ax->rbuff, count);
-       spin_unlock_bh(&ax->buflock);
-       skb->protocol = ax25_type_trans(skb, ax->dev);
-       netif_rx(skb);
-       ax->dev->last_rx = jiffies;
-       ax->rx_packets++;
-       ax->rx_bytes+=count;
+       kfree(oxbuff);
+       kfree(orbuff);
 }
 
 /* Encapsulate one AX.25 packet and stuff into a TTY queue. */
-static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len)
+static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
 {
+       struct mkiss *ax = netdev_priv(dev);
        unsigned char *p;
        int actual, count;
 
@@ -354,8 +409,8 @@ static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len)
        if (len > ax->mtu) {            /* Sigh, shouldn't occur BUT ... */
                len = ax->mtu;
                printk(KERN_ERR "mkiss: %s: truncating oversized transmit packet!\n", ax->dev->name);
-               ax->tx_dropped++;
-               ax_unlock(ax);
+               ax->stats.tx_dropped++;
+               netif_start_queue(dev);
                return;
        }
 
@@ -376,10 +431,11 @@ static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len)
                 break;
        }
        
-       ax->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+       set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
        actual = ax->tty->driver->write(ax->tty, ax->xbuff, count);
-       ax->tx_packets++;
-       ax->tx_bytes+=actual;
+       ax->stats.tx_packets++;
+       ax->stats.tx_bytes += actual;
+
        ax->dev->trans_start = jiffies;
        ax->xleft = count - actual;
        ax->xhead = ax->xbuff + actual;
@@ -387,37 +443,10 @@ static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len)
        spin_unlock_bh(&ax->buflock);
 }
 
-/*
- * Called by the driver when there's room for more data.  If we have
- * more packets to send, we send them here.
- */
-static void ax25_write_wakeup(struct tty_struct *tty)
-{
-       int actual;
-       struct ax_disp *ax = (struct ax_disp *) tty->disc_data;
-
-       /* First make sure we're connected. */
-       if (ax == NULL || ax->magic != AX25_MAGIC || !netif_running(ax->dev))
-               return;
-       if (ax->xleft <= 0)  {
-               /* Now serial buffer is almost free & we can start
-                * transmission of another packet
-                */
-               tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-
-               netif_wake_queue(ax->dev);
-               return;
-       }
-
-       actual = tty->driver->write(tty, ax->xhead, ax->xleft);
-       ax->xleft -= actual;
-       ax->xhead += actual;
-}
-
 /* Encapsulate an AX.25 packet and kick it into a TTY queue. */
 static int ax_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       struct ax_disp *ax = netdev_priv(dev);
+       struct mkiss *ax = netdev_priv(dev);
 
        if (!netif_running(dev))  {
                printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name);
@@ -429,7 +458,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev)
                 * May be we must check transmitter timeout here ?
                 *      14 Oct 1994 Dmitry Gorodchanin.
                 */
-               if (jiffies - dev->trans_start  < 20 * HZ) {
+               if (time_before(jiffies, dev->trans_start + 20 * HZ)) {
                        /* 20 sec timeout not reached */
                        return 1;
                }
@@ -439,20 +468,30 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev)
                       "bad line quality" : "driver error");
 
                ax->xleft = 0;
-               ax->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-               ax_unlock(ax);
+               clear_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
+               netif_start_queue(dev);
        }
 
        /* We were not busy, so we are now... :-) */
        if (skb != NULL) {
-               ax_lock(ax);
-               ax_encaps(ax, skb->data, skb->len);
+               netif_stop_queue(dev);
+               ax_encaps(dev, skb->data, skb->len);
                kfree_skb(skb);
        }
 
        return 0;
 }
 
+static int ax_open_dev(struct net_device *dev)
+{
+       struct mkiss *ax = netdev_priv(dev);
+
+       if (ax->tty == NULL)
+               return -ENODEV;
+
+       return 0;
+}
+
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 
 /* Return the frame type ID */
@@ -481,7 +520,7 @@ static int ax_rebuild_header(struct sk_buff *skb)
 /* Open the low-level part of the AX25 channel. Easy! */
 static int ax_open(struct net_device *dev)
 {
-       struct ax_disp *ax = netdev_priv(dev);
+       struct mkiss *ax = netdev_priv(dev);
        unsigned long len;
 
        if (ax->tty == NULL)
@@ -518,7 +557,6 @@ static int ax_open(struct net_device *dev)
 
        spin_lock_init(&ax->buflock);
 
-       netif_start_queue(dev);
        return 0;
 
 noxbuff:
@@ -532,68 +570,100 @@ norbuff:
 /* Close the low-level part of the AX25 channel. Easy! */
 static int ax_close(struct net_device *dev)
 {
-       struct ax_disp *ax = netdev_priv(dev);
+       struct mkiss *ax = netdev_priv(dev);
 
-       if (ax->tty == NULL)
-               return -EBUSY;
-
-       ax->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+       if (ax->tty)
+               clear_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
 
        netif_stop_queue(dev);
 
        return 0;
 }
 
-static int ax25_receive_room(struct tty_struct *tty)
+static struct net_device_stats *ax_get_stats(struct net_device *dev)
 {
-       return 65536;  /* We can handle an infinite amount of data. :-) */
+       struct mkiss *ax = netdev_priv(dev);
+
+       return &ax->stats;
+}
+
+static void ax_setup(struct net_device *dev)
+{
+       static char ax25_bcast[AX25_ADDR_LEN] =
+               {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
+       static char ax25_test[AX25_ADDR_LEN] =
+               {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
+
+       /* Finish setting up the DEVICE info. */
+       dev->mtu             = AX_MTU;
+       dev->hard_start_xmit = ax_xmit;
+       dev->open            = ax_open_dev;
+       dev->stop            = ax_close;
+       dev->get_stats       = ax_get_stats;
+       dev->set_mac_address = ax_set_mac_address;
+       dev->hard_header_len = 0;
+       dev->addr_len        = 0;
+       dev->type            = ARPHRD_AX25;
+       dev->tx_queue_len    = 10;
+       dev->hard_header     = ax_header;
+       dev->rebuild_header  = ax_rebuild_header;
+
+       memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
+       memcpy(dev->dev_addr,  ax25_test,  AX25_ADDR_LEN);
+
+       dev->flags      = IFF_BROADCAST | IFF_MULTICAST;
 }
 
 /*
- * Handle the 'receiver data ready' interrupt.
- * This function is called by the 'tty_io' module in the kernel when
- * a block of data has been received, which can now be decapsulated
- * and sent on to the AX.25 layer for further processing.
+ * We have a potential race on dereferencing tty->disc_data, because the tty
+ * layer provides no locking at all - thus one cpu could be running
+ * sixpack_receive_buf while another calls sixpack_close, which zeroes
+ * tty->disc_data and frees the memory that sixpack_receive_buf is using.  The
+ * best way to fix this is to use a rwlock in the tty struct, but for now we
+ * use a single global rwlock for all ttys in ppp line discipline.
  */
-static void ax25_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED;
+
+static struct mkiss *mkiss_get(struct tty_struct *tty)
 {
-       struct ax_disp *ax = (struct ax_disp *) tty->disc_data;
+       struct mkiss *ax;
 
-       if (ax == NULL || ax->magic != AX25_MAGIC || !netif_running(ax->dev))
-               return;
+       read_lock(&disc_data_lock);
+       ax = tty->disc_data;
+       if (ax)
+               atomic_inc(&ax->refcnt);
+       read_unlock(&disc_data_lock);
 
-       /*
-        * Argh! mtu change time! - costs us the packet part received
-        * at the change
-        */
-       if (ax->mtu != ax->dev->mtu + 73)
-               ax_changedmtu(ax);
-
-       /* Read the characters out of the buffer */
-       while (count--) {
-               if (fp != NULL && *fp++) {
-                       if (!test_and_set_bit(AXF_ERROR, &ax->flags))
-                               ax->rx_errors++;
-                       cp++;
-                       continue;
-               }
+       return ax;
+}
 
-               kiss_unesc(ax, *cp++);
-       }
+static void mkiss_put(struct mkiss *ax)
+{
+       if (atomic_dec_and_test(&ax->refcnt))
+               up(&ax->dead_sem);
 }
 
-static int ax25_open(struct tty_struct *tty)
+static int mkiss_open(struct tty_struct *tty)
 {
-       struct ax_disp *ax = (struct ax_disp *) tty->disc_data;
+       struct net_device *dev;
+       struct mkiss *ax;
        int err;
 
-       /* First make sure we're not already connected. */
-       if (ax && ax->magic == AX25_MAGIC)
-               return -EEXIST;
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
 
-       /* OK.  Find a free AX25 channel to use. */
-       if ((ax = ax_alloc()) == NULL)
-               return -ENFILE;
+       dev = alloc_netdev(sizeof(struct mkiss), "ax%d", ax_setup);
+       if (!dev) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       ax = netdev_priv(dev);
+       ax->dev = dev;
+
+       spin_lock_init(&ax->buflock);
+       atomic_set(&ax->refcnt, 1);
+       init_MUTEX_LOCKED(&ax->dead_sem);
 
        ax->tty = tty;
        tty->disc_data = ax;
@@ -602,283 +672,212 @@ static int ax25_open(struct tty_struct *tty)
                tty->driver->flush_buffer(tty);
 
        /* Restore default settings */
-       ax->dev->type = ARPHRD_AX25;
+       dev->type = ARPHRD_AX25;
 
        /* Perform the low-level AX25 initialization. */
-       if ((err = ax_open(ax->dev)))
-               return err;
+       if ((err = ax_open(ax->dev))) {
+               goto out_free_netdev;
+       }
 
-       /* Done.  We have linked the TTY line to a channel. */
-       return ax->dev->base_addr;
-}
+       if (register_netdev(dev))
+               goto out_free_buffers;
 
-static void ax25_close(struct tty_struct *tty)
-{
-       struct ax_disp *ax = (struct ax_disp *) tty->disc_data;
+       netif_start_queue(dev);
 
-       /* First make sure we're connected. */
-       if (ax == NULL || ax->magic != AX25_MAGIC)
-               return;
+       /* Done.  We have linked the TTY line to a channel. */
+       return 0;
 
-       unregister_netdev(ax->dev);
+out_free_buffers:
+       kfree(ax->rbuff);
+       kfree(ax->xbuff);
 
-       tty->disc_data = NULL;
-       ax->tty        = NULL;
+out_free_netdev:
+       free_netdev(dev);
 
-       ax_free(ax);
+out:
+       return err;
 }
 
-
-static struct net_device_stats *ax_get_stats(struct net_device *dev)
+static void mkiss_close(struct tty_struct *tty)
 {
-       static struct net_device_stats stats;
-       struct ax_disp *ax = netdev_priv(dev);
-
-       memset(&stats, 0, sizeof(struct net_device_stats));
-
-       stats.rx_packets     = ax->rx_packets;
-       stats.tx_packets     = ax->tx_packets;
-       stats.rx_bytes       = ax->rx_bytes;
-       stats.tx_bytes       = ax->tx_bytes;
-       stats.rx_dropped     = ax->rx_dropped;
-       stats.tx_dropped     = ax->tx_dropped;
-       stats.tx_errors      = ax->tx_errors;
-       stats.rx_errors      = ax->rx_errors;
-       stats.rx_over_errors = ax->rx_over_errors;
-
-       return &stats;
-}
+       struct mkiss *ax;
 
+       write_lock(&disc_data_lock);
+       ax = tty->disc_data;
+       tty->disc_data = NULL;
+       write_unlock(&disc_data_lock);
 
-/************************************************************************
- *                        STANDARD ENCAPSULATION                        *
- ************************************************************************/
-
-static int kiss_esc(unsigned char *s, unsigned char *d, int len)
-{
-       unsigned char *ptr = d;
-       unsigned char c;
+       if (ax == 0)
+               return;
 
        /*
-        * Send an initial END character to flush out any
-        * data that may have accumulated in the receiver
-        * due to line noise.
+        * We have now ensured that nobody can start using ap from now on, but
+        * we have to wait for all existing users to finish.
         */
+       if (!atomic_dec_and_test(&ax->refcnt))
+               down(&ax->dead_sem);
 
-       *ptr++ = END;
-
-       while (len-- > 0) {
-               switch (c = *s++) {
-                       case END:
-                               *ptr++ = ESC;
-                               *ptr++ = ESC_END;
-                               break;
-                       case ESC:
-                               *ptr++ = ESC;
-                               *ptr++ = ESC_ESC;
-                               break;
-                       default:
-                               *ptr++ = c;
-                               break;
-               }
-       }
+       unregister_netdev(ax->dev);
 
-       *ptr++ = END;
+       /* Free all AX25 frame buffers. */
+       kfree(ax->rbuff);
+       kfree(ax->xbuff);
 
-       return ptr - d;
+       ax->tty = NULL;
 }
 
-/*
- * MW:
- * OK its ugly, but tell me a better solution without copying the
- * packet to a temporary buffer :-)
- */
-static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc, int len)
+/* Perform I/O control on an active ax25 channel. */
+static int mkiss_ioctl(struct tty_struct *tty, struct file *file,
+       unsigned int cmd, unsigned long arg)
 {
-       unsigned char *ptr = d;
-       unsigned char c=0;
-
-       *ptr++ = END;
-       while (len > 0) {
-               if (len > 2) 
-                       c = *s++;
-               else if (len > 1)
-                       c = crc >> 8;
-               else if (len > 0)
-                       c = crc & 0xff;
+       struct mkiss *ax = mkiss_get(tty);
+       struct net_device *dev = ax->dev;
+       unsigned int tmp, err;
 
-               len--;
+       /* First make sure we're connected. */
+       if (ax == NULL)
+               return -ENXIO;
 
-               switch (c) {
-                        case END:
-                                *ptr++ = ESC;
-                                *ptr++ = ESC_END;
-                                break;
-                        case ESC:
-                                *ptr++ = ESC;
-                                *ptr++ = ESC_ESC;
-                                break;
-                        default:
-                                *ptr++ = c;
-                                break;
+       switch (cmd) {
+       case SIOCGIFNAME:
+               err = copy_to_user((void __user *) arg, ax->dev->name,
+                                  strlen(ax->dev->name) + 1) ? -EFAULT : 0;
+               break;
+
+       case SIOCGIFENCAP:
+               err = put_user(4, (int __user *) arg);
+               break;
+
+       case SIOCSIFENCAP:
+               if (get_user(tmp, (int __user *) arg)) {
+                       err = -EFAULT;
+                       break;
                }
-       }
-       *ptr++ = END;
-       return ptr - d;         
-}
 
-static void kiss_unesc(struct ax_disp *ax, unsigned char s)
-{
-       switch (s) {
-               case END:
-                       /* drop keeptest bit = VSV */
-                       if (test_bit(AXF_KEEPTEST, &ax->flags))
-                               clear_bit(AXF_KEEPTEST, &ax->flags);
+               ax->mode = tmp;
+               dev->addr_len        = AX25_ADDR_LEN;
+               dev->hard_header_len = AX25_KISS_HEADER_LEN +
+                                      AX25_MAX_HEADER_LEN + 3;
+               dev->type            = ARPHRD_AX25;
 
-                       if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2))
-                               ax_bump(ax);
+               err = 0;
+               break;
 
-                       clear_bit(AXF_ESCAPE, &ax->flags);
-                       ax->rcount = 0;
-                       return;
+       case SIOCSIFHWADDR: {
+               char addr[AX25_ADDR_LEN];
+printk(KERN_INFO "In SIOCSIFHWADDR");
 
-               case ESC:
-                       set_bit(AXF_ESCAPE, &ax->flags);
-                       return;
-               case ESC_ESC:
-                       if (test_and_clear_bit(AXF_ESCAPE, &ax->flags))
-                               s = ESC;
+               if (copy_from_user(&addr,
+                                  (void __user *) arg, AX25_ADDR_LEN)) {
+                       err = -EFAULT;
                        break;
-               case ESC_END:
-                       if (test_and_clear_bit(AXF_ESCAPE, &ax->flags))
-                               s = END;
-                       break;
-       }
-
-       spin_lock_bh(&ax->buflock);
-       if (!test_bit(AXF_ERROR, &ax->flags)) {
-               if (ax->rcount < ax->buffsize) {
-                       ax->rbuff[ax->rcount++] = s;
-                       spin_unlock_bh(&ax->buflock);
-                       return;
                }
 
-               ax->rx_over_errors++;
-               set_bit(AXF_ERROR, &ax->flags);
+               spin_lock_irq(&dev->xmit_lock);
+               memcpy(dev->dev_addr, addr, AX25_ADDR_LEN);
+               spin_unlock_irq(&dev->xmit_lock);
+
+               err = 0;
+               break;
+       }
+       default:
+               err = -ENOIOCTLCMD;
        }
-       spin_unlock_bh(&ax->buflock);
-}
 
+       mkiss_put(ax);
 
-static int ax_set_mac_address(struct net_device *dev, void __user *addr)
-{
-       if (copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN))
-               return -EFAULT;
-       return 0;
+       return err;
 }
 
-static int ax_set_dev_mac_address(struct net_device *dev, void *addr)
+/*
+ * Handle the 'receiver data ready' interrupt.
+ * This function is called by the 'tty_io' module in the kernel when
+ * a block of data has been received, which can now be decapsulated
+ * and sent on to the AX.25 layer for further processing.
+ */
+static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+       char *fp, int count)
 {
-       struct sockaddr *sa = addr;
-
-       memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN);
+       struct mkiss *ax = mkiss_get(tty);
 
-       return 0;
-}
-
-
-/* Perform I/O control on an active ax25 channel. */
-static int ax25_disp_ioctl(struct tty_struct *tty, void *file, int cmd, void __user *arg)
-{
-       struct ax_disp *ax = (struct ax_disp *) tty->disc_data;
-       unsigned int tmp;
+       if (!ax)
+               return;
 
-       /* First make sure we're connected. */
-       if (ax == NULL || ax->magic != AX25_MAGIC)
-               return -EINVAL;
+       /*
+        * Argh! mtu change time! - costs us the packet part received
+        * at the change
+        */
+       if (ax->mtu != ax->dev->mtu + 73)
+               ax_changedmtu(ax);
 
-       switch (cmd) {
-               case SIOCGIFNAME:
-                       if (copy_to_user(arg, ax->dev->name, strlen(ax->dev->name) + 1))
-                               return -EFAULT;
-                       return 0;
-
-               case SIOCGIFENCAP:
-                       return put_user(4, (int __user *)arg);
-
-               case SIOCSIFENCAP:
-                       if (get_user(tmp, (int __user *)arg))
-                               return -EFAULT;
-                       ax->mode = tmp;
-                       ax->dev->addr_len        = AX25_ADDR_LEN;         /* sizeof an AX.25 addr */
-                       ax->dev->hard_header_len = AX25_KISS_HEADER_LEN + AX25_MAX_HEADER_LEN + 3;
-                       ax->dev->type            = ARPHRD_AX25;
-                       return 0;
-
-                case SIOCSIFHWADDR:
-                       return ax_set_mac_address(ax->dev, arg);
+       /* Read the characters out of the buffer */
+       while (count--) {
+               if (fp != NULL && *fp++) {
+                       if (!test_and_set_bit(AXF_ERROR, &ax->flags))
+                               ax->stats.rx_errors++;
+                       cp++;
+                       continue;
+               }
 
-               default:
-                       return -ENOIOCTLCMD;
+               kiss_unesc(ax, *cp++);
        }
+
+       mkiss_put(ax);
+       if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
+           && tty->driver->unthrottle)
+               tty->driver->unthrottle(tty);
 }
 
-static int ax_open_dev(struct net_device *dev)
+static int mkiss_receive_room(struct tty_struct *tty)
 {
-       struct ax_disp *ax = netdev_priv(dev);
-
-       if (ax->tty == NULL)
-               return -ENODEV;
-
-       return 0;
+       return 65536;  /* We can handle an infinite amount of data. :-) */
 }
 
-
-/* Initialize the driver.  Called by network startup. */
-static int ax25_init(struct net_device *dev)
+/*
+ * Called by the driver when there's room for more data.  If we have
+ * more packets to send, we send them here.
+ */
+static void mkiss_write_wakeup(struct tty_struct *tty)
 {
-       struct ax_disp *ax = netdev_priv(dev);
-
-       static char ax25_bcast[AX25_ADDR_LEN] =
-               {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
-       static char ax25_test[AX25_ADDR_LEN] =
-               {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
-
-       if (ax == NULL)         /* Allocation failed ?? */
-               return -ENODEV;
+       struct mkiss *ax = mkiss_get(tty);
+       int actual;
 
-       /* Set up the "AX25 Control Block". (And clear statistics) */
-       memset(ax, 0, sizeof (struct ax_disp));
-       ax->magic  = AX25_MAGIC;
-       ax->dev    = dev;
+       if (!ax)
+               return;
 
-       /* Finish setting up the DEVICE info. */
-       dev->mtu             = AX_MTU;
-       dev->hard_start_xmit = ax_xmit;
-       dev->open            = ax_open_dev;
-       dev->stop            = ax_close;
-       dev->get_stats       = ax_get_stats;
-       dev->set_mac_address = ax_set_dev_mac_address;
-       dev->hard_header_len = 0;
-       dev->addr_len        = 0;
-       dev->type            = ARPHRD_AX25;
-       dev->tx_queue_len    = 10;
-       dev->hard_header     = ax_header;
-       dev->rebuild_header  = ax_rebuild_header;
+       if (ax->xleft <= 0)  {
+               /* Now serial buffer is almost free & we can start
+                * transmission of another packet
+                */
+               clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 
-       memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
-       memcpy(dev->dev_addr,  ax25_test,  AX25_ADDR_LEN);
+               netif_wake_queue(ax->dev);
+               goto out;
+       }
 
-       /* New-style flags. */
-       dev->flags      = IFF_BROADCAST | IFF_MULTICAST;
+       actual = tty->driver->write(tty, ax->xhead, ax->xleft);
+       ax->xleft -= actual;
+       ax->xhead += actual;
 
-       return 0;
+out:
+       mkiss_put(ax);
 }
 
+static struct tty_ldisc ax_ldisc = {
+       .magic          = TTY_LDISC_MAGIC,
+       .name           = "mkiss",
+       .open           = mkiss_open,
+       .close          = mkiss_close,
+       .ioctl          = mkiss_ioctl,
+       .receive_buf    = mkiss_receive_buf,
+       .receive_room   = mkiss_receive_room,
+       .write_wakeup   = mkiss_write_wakeup
+};
 
-/* ******************************************************************** */
-/* *                   Init MKISS driver                             * */
-/* ******************************************************************** */
+static char banner[] __initdata = KERN_INFO \
+       "mkiss: AX.25 Multikiss, Hans Albas PE1AYX\n";
+static char msg_regfail[] __initdata = KERN_ERR \
+       "mkiss: can't register line discipline (err = %d)\n";
 
 static int __init mkiss_init_driver(void)
 {
@@ -886,64 +885,27 @@ static int __init mkiss_init_driver(void)
 
        printk(banner);
 
-       if (ax25_maxdev < 4)
-         ax25_maxdev = 4; /* Sanity */
+       if ((status = tty_register_ldisc(N_AX25, &ax_ldisc)) != 0)
+               printk(msg_regfail);
 
-       if ((ax25_ctrls = kmalloc(sizeof(void *) * ax25_maxdev, GFP_KERNEL)) == NULL) {
-               printk(KERN_ERR "mkiss: Can't allocate ax25_ctrls[] array!\n");
-               return -ENOMEM;
-       }
-
-       /* Clear the pointer array, we allocate devices when we need them */
-       memset(ax25_ctrls, 0, sizeof(void*) * ax25_maxdev); /* Pointers */
-
-       /* Fill in our line protocol discipline, and register it */
-       ax_ldisc.magic          = TTY_LDISC_MAGIC;
-       ax_ldisc.name           = "mkiss";
-       ax_ldisc.open           = ax25_open;
-       ax_ldisc.close          = ax25_close;
-       ax_ldisc.ioctl          = (int (*)(struct tty_struct *, struct file *,
-                                       unsigned int, unsigned long))ax25_disp_ioctl;
-       ax_ldisc.receive_buf    = ax25_receive_buf;
-       ax_ldisc.receive_room   = ax25_receive_room;
-       ax_ldisc.write_wakeup   = ax25_write_wakeup;
-
-       if ((status = tty_register_ldisc(N_AX25, &ax_ldisc)) != 0) {
-               printk(KERN_ERR "mkiss: can't register line discipline (err = %d)\n", status);
-               kfree(ax25_ctrls);
-       }
        return status;
 }
 
+static const char msg_unregfail[] __exitdata = KERN_ERR \
+       "mkiss: can't unregister line discipline (err = %d)\n";
+
 static void __exit mkiss_exit_driver(void)
 {
-       int i;
-
-       for (i = 0; i < ax25_maxdev; i++) {
-               if (ax25_ctrls[i]) {
-                       /*
-                       * VSV = if dev->start==0, then device
-                       * unregistered while close proc.
-                       */
-                       if (netif_running(&ax25_ctrls[i]->dev))
-                               unregister_netdev(&ax25_ctrls[i]->dev);
-                       kfree(ax25_ctrls[i]);
-               }
-       }
+       int ret;
 
-       kfree(ax25_ctrls);
-       ax25_ctrls = NULL;
-
-       if ((i = tty_unregister_ldisc(N_AX25)))
-               printk(KERN_ERR "mkiss: can't unregister line discipline (err = %d)\n", i);
+       if ((ret = tty_unregister_ldisc(N_AX25)))
+               printk(msg_unregfail, ret);
 }
 
-MODULE_AUTHOR("Hans Albas PE1AYX <hans@esrac.ele.tue.nl>");
+MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>");
 MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs");
-MODULE_PARM(ax25_maxdev, "i");
-MODULE_PARM_DESC(ax25_maxdev, "number of MKISS devices");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_LDISC(N_AX25);
+
 module_init(mkiss_init_driver);
 module_exit(mkiss_exit_driver);
-
index c39b0609742a3394754b2cf70e2841305bc2a8c8..32d5fabd4b1019a2c26378f72dbd7d6d518fb2e4 100644 (file)
@@ -1144,7 +1144,7 @@ static void ibmveth_proc_unregister_driver(void)
 
 static struct vio_device_id ibmveth_device_table[] __devinitdata= {
        { "network", "IBM,l-lan"},
-       { 0,}
+       { "", "" }
 };
 
 MODULE_DEVICE_TABLE(vio, ibmveth_device_table);
index 10125a1dba22bb33bd941b258779bf4f9b486ba2..dd89bda1f1315914349fe692029108b30dd6262a 100644 (file)
@@ -4,10 +4,10 @@
  * Description:   Driver for the SMC Infrared Communications Controller
  * Status:        Experimental.
  * Author:        Daniele Peri (peri@csai.unipa.it)
- * Created at:    
- * Modified at:   
- * Modified by:   
- * 
+ * Created at:
+ * Modified at:
+ * Modified by:
+ *
  *     Copyright (c) 2002      Daniele Peri
  *     All Rights Reserved.
  *     Copyright (c) 2002      Jean Tourrilhes
  *
  *     Copyright (c) 2001      Stefani Seibold
  *     Copyright (c) 1999-2001 Dag Brattli
- *     Copyright (c) 1998-1999 Thomas Davis, 
+ *     Copyright (c) 1998-1999 Thomas Davis,
  *
  *     and irport.c:
  *
  *     Copyright (c) 1997, 1998, 1999-2000 Dag Brattli, All Rights Reserved.
  *
- * 
- *     This program is free software; you can redistribute it and/or 
- *     modify it under the terms of the GNU General Public License as 
- *     published by the Free Software Foundation; either version 2 of 
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
  *     the License, or (at your option) any later version.
- * 
+ *
  *     This program is distributed in the hope that it will be useful,
  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  *     GNU General Public License for more details.
- * 
- *     You should have received a copy of the GNU General Public License 
- *     along with this program; if not, write to the Free Software 
- *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+ *
+ *     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 "smsc-ircc2.h"
 #include "smsc-sio.h"
 
+
+MODULE_AUTHOR("Daniele Peri <peri@csai.unipa.it>");
+MODULE_DESCRIPTION("SMC IrCC SIR/FIR controller driver");
+MODULE_LICENSE("GPL");
+
+static int ircc_dma = 255;
+module_param(ircc_dma, int, 0);
+MODULE_PARM_DESC(ircc_dma, "DMA channel");
+
+static int ircc_irq = 255;
+module_param(ircc_irq, int, 0);
+MODULE_PARM_DESC(ircc_irq, "IRQ line");
+
+static int ircc_fir;
+module_param(ircc_fir, int, 0);
+MODULE_PARM_DESC(ircc_fir, "FIR Base Address");
+
+static int ircc_sir;
+module_param(ircc_sir, int, 0);
+MODULE_PARM_DESC(ircc_sir, "SIR Base Address");
+
+static int ircc_cfg;
+module_param(ircc_cfg, int, 0);
+MODULE_PARM_DESC(ircc_cfg, "Configuration register base address");
+
+static int ircc_transceiver;
+module_param(ircc_transceiver, int, 0);
+MODULE_PARM_DESC(ircc_transceiver, "Transceiver type");
+
 /* Types */
 
 struct smsc_transceiver {
        char *name;
-       void (*set_for_speed)(int fir_base, u32 speed); 
+       void (*set_for_speed)(int fir_base, u32 speed);
        int  (*probe)(int fir_base);
 };
-typedef struct smsc_transceiver smsc_transceiver_t;
-
-#if 0
-struct smc_chip {
-       char *name;
-       u16 flags;
-       u8 devid;
-       u8 rev;
-};
-typedef struct smc_chip smc_chip_t;
-#endif
 
 struct smsc_chip {
        char *name;
@@ -96,20 +114,18 @@ struct smsc_chip {
        u8 devid;
        u8 rev;
 };
-typedef struct smsc_chip smsc_chip_t;
 
 struct smsc_chip_address {
        unsigned int cfg_base;
        unsigned int type;
 };
-typedef struct smsc_chip_address smsc_chip_address_t;
 
 /* Private data for each instance */
 struct smsc_ircc_cb {
        struct net_device *netdev;     /* Yes! we are some kind of netdevice */
        struct net_device_stats stats;
        struct irlap_cb    *irlap; /* The link layer we are binded to */
-       
+
        chipio_t io;               /* IrDA controller information */
        iobuff_t tx_buff;          /* Transmit buffer */
        iobuff_t rx_buff;          /* Receive buffer */
@@ -119,7 +135,7 @@ struct smsc_ircc_cb {
        struct qos_info qos;       /* QoS capabilities for this device */
 
        spinlock_t lock;           /* For serializing operations */
-       
+
        __u32 new_speed;
        __u32 flags;               /* Interface flags */
 
@@ -127,18 +143,20 @@ struct smsc_ircc_cb {
        int tx_len;                /* Number of frames in tx_buff */
 
        int transceiver;
-       struct pm_dev *pmdev;
+       struct platform_device *pldev;
 };
 
 /* Constants */
 
-static const char *driver_name = "smsc-ircc2";
-#define        DIM(x)  (sizeof(x)/(sizeof(*(x))))
+#define SMSC_IRCC2_DRIVER_NAME                 "smsc-ircc2"
+
 #define SMSC_IRCC2_C_IRDA_FALLBACK_SPEED       9600
 #define SMSC_IRCC2_C_DEFAULT_TRANSCEIVER       1
-#define SMSC_IRCC2_C_NET_TIMEOUT                       0
+#define SMSC_IRCC2_C_NET_TIMEOUT               0
 #define SMSC_IRCC2_C_SIR_STOP                  0
 
+static const char *driver_name = SMSC_IRCC2_DRIVER_NAME;
+
 /* Prototypes */
 
 static int smsc_ircc_open(unsigned int firbase, unsigned int sirbase, u8 dma, u8 irq);
@@ -147,15 +165,15 @@ static void smsc_ircc_setup_io(struct smsc_ircc_cb *self, unsigned int fir_base,
 static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self);
 static void smsc_ircc_init_chip(struct smsc_ircc_cb *self);
 static int __exit smsc_ircc_close(struct smsc_ircc_cb *self);
-static int  smsc_ircc_dma_receive(struct smsc_ircc_cb *self, int iobase); 
-static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self, int iobase);
+static int  smsc_ircc_dma_receive(struct smsc_ircc_cb *self);
+static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self);
 static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self);
 static int  smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev);
 static int  smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev);
-static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int iobase, int bofs);
-static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self, int iobase);
-static void smsc_ircc_change_speed(void *priv, u32 speed);
-static void smsc_ircc_set_sir_speed(void *priv, u32 speed);
+static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int bofs);
+static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self);
+static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed);
+static void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, u32 speed);
 static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev);
 static void smsc_ircc_sir_start(struct smsc_ircc_cb *self);
@@ -171,7 +189,6 @@ static int  smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cm
 static void smsc_ircc_timeout(struct net_device *dev);
 #endif
 static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev);
-static int  smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
 static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self);
 static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self);
 static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed);
@@ -179,9 +196,9 @@ static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self);
 
 /* Probing */
 static int __init smsc_ircc_look_for_chips(void);
-static const smsc_chip_t * __init smsc_ircc_probe(unsigned short cfg_base,u8 reg,const smsc_chip_t *chip,char *type);
-static int __init smsc_superio_flat(const smsc_chip_t *chips, unsigned short cfg_base, char *type);
-static int __init smsc_superio_paged(const smsc_chip_t *chips, unsigned short cfg_base, char *type);
+static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type);
+static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
+static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
 static int __init smsc_superio_fdc(unsigned short cfg_base);
 static int __init smsc_superio_lpc(unsigned short cfg_base);
 
@@ -196,21 +213,26 @@ static int  smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base);
 
 /* Power Management */
 
-static void smsc_ircc_suspend(struct smsc_ircc_cb *self);
-static void smsc_ircc_wakeup(struct smsc_ircc_cb *self);
-static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
+static int smsc_ircc_suspend(struct device *dev, pm_message_t state, u32 level);
+static int smsc_ircc_resume(struct device *dev, u32 level);
 
+static struct device_driver smsc_ircc_driver = {
+       .name           = SMSC_IRCC2_DRIVER_NAME,
+       .bus            = &platform_bus_type,
+       .suspend        = smsc_ircc_suspend,
+       .resume         = smsc_ircc_resume,
+};
 
 /* Transceivers for SMSC-ircc */
 
-static smsc_transceiver_t smsc_transceivers[]=
+static struct smsc_transceiver smsc_transceivers[] =
 {
-       { "Toshiba Satellite 1800 (GP data pin select)", smsc_ircc_set_transceiver_toshiba_sat1800, smsc_ircc_probe_transceiver_toshiba_sat1800},
-       { "Fast pin select", smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select, smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select},
-       { "ATC IRMode", smsc_ircc_set_transceiver_smsc_ircc_atc, smsc_ircc_probe_transceiver_smsc_ircc_atc},
-       { NULL, NULL}
+       { "Toshiba Satellite 1800 (GP data pin select)", smsc_ircc_set_transceiver_toshiba_sat1800, smsc_ircc_probe_transceiver_toshiba_sat1800 },
+       { "Fast pin select", smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select, smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select },
+       { "ATC IRMode", smsc_ircc_set_transceiver_smsc_ircc_atc, smsc_ircc_probe_transceiver_smsc_ircc_atc },
+       { NULL, NULL }
 };
-#define SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS (DIM(smsc_transceivers)-1)
+#define SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS (ARRAY_SIZE(smsc_transceivers) - 1)
 
 /*  SMC SuperIO chipsets definitions */
 
@@ -221,7 +243,7 @@ static smsc_transceiver_t smsc_transceivers[]=
 #define        FIR     4       /* SuperIO Chip has fast IRDA */
 #define        SERx4   8       /* SuperIO Chip supports 115,2 KBaud * 4=460,8 KBaud */
 
-static smsc_chip_t __initdata fdc_chips_flat[]=
+static struct smsc_chip __initdata fdc_chips_flat[] =
 {
        /* Base address 0x3f0 or 0x370 */
        { "37C44",      KEY55_1|NoIRDA,         0x00, 0x00 }, /* This chip cannot be detected */
@@ -235,7 +257,7 @@ static smsc_chip_t __initdata fdc_chips_flat[]=
        { NULL }
 };
 
-static smsc_chip_t __initdata fdc_chips_paged[]=
+static struct smsc_chip __initdata fdc_chips_paged[] =
 {
        /* Base address 0x3f0 or 0x370 */
        { "37B72X",     KEY55_1|SIR|SERx4,      0x4c, 0x00 },
@@ -254,7 +276,7 @@ static smsc_chip_t __initdata fdc_chips_paged[]=
        { NULL }
 };
 
-static smsc_chip_t __initdata lpc_chips_flat[]=
+static struct smsc_chip __initdata lpc_chips_flat[] =
 {
        /* Base address 0x2E or 0x4E */
        { "47N227",     KEY55_1|FIR|SERx4,      0x5a, 0x00 },
@@ -262,7 +284,7 @@ static smsc_chip_t __initdata lpc_chips_flat[]=
        { NULL }
 };
 
-static smsc_chip_t __initdata lpc_chips_paged[]=
+static struct smsc_chip __initdata lpc_chips_paged[] =
 {
        /* Base address 0x2E or 0x4E */
        { "47B27X",     KEY55_1|SIR|SERx4,      0x51, 0x00 },
@@ -281,33 +303,25 @@ static smsc_chip_t __initdata lpc_chips_paged[]=
 #define SMSCSIO_TYPE_FLAT      4
 #define SMSCSIO_TYPE_PAGED     8
 
-static smsc_chip_address_t __initdata possible_addresses[]=
+static struct smsc_chip_address __initdata possible_addresses[] =
 {
-       {0x3f0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
-       {0x370, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
-       {0xe0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
-       {0x2e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
-       {0x4e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
-       {0,0}
+       { 0x3f0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
+       { 0x370, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
+       { 0xe0,  SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
+       { 0x2e,  SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
+       { 0x4e,  SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
+       { 0, 0 }
 };
 
 /* Globals */
 
-static struct smsc_ircc_cb *dev_self[] = { NULL, NULL};
-
-static int ircc_irq=255;
-static int ircc_dma=255;
-static int ircc_fir=0;
-static int ircc_sir=0;
-static int ircc_cfg=0;
-static int ircc_transceiver=0;
-
-static unsigned short  dev_count=0;
+static struct smsc_ircc_cb *dev_self[] = { NULL, NULL };
+static unsigned short dev_count;
 
 static inline void register_bank(int iobase, int bank)
 {
-        outb(((inb(iobase+IRCC_MASTER) & 0xf0) | (bank & 0x07)),
-               iobase+IRCC_MASTER);
+        outb(((inb(iobase + IRCC_MASTER) & 0xf0) | (bank & 0x07)),
+               iobase + IRCC_MASTER);
 }
 
 
@@ -327,34 +341,44 @@ static inline void register_bank(int iobase, int bank)
  */
 static int __init smsc_ircc_init(void)
 {
-       int ret=-ENODEV;
+       int ret;
 
        IRDA_DEBUG(1, "%s\n", __FUNCTION__);
 
-       dev_count=0;
-       if ((ircc_fir>0)&&(ircc_sir>0)) {
+       ret = driver_register(&smsc_ircc_driver);
+       if (ret) {
+               IRDA_ERROR("%s, Can't register driver!\n", driver_name);
+               return ret;
+       }
+
+       dev_count = 0;
+
+       if (ircc_fir > 0 && ircc_sir > 0) {
                IRDA_MESSAGE(" Overriding FIR address 0x%04x\n", ircc_fir);
                IRDA_MESSAGE(" Overriding SIR address 0x%04x\n", ircc_sir);
 
-               if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq) == 0)
-                       return 0;
-
-               return -ENODEV;
-       }
+               if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq))
+                       ret = -ENODEV;
+       } else {
+               ret = -ENODEV;
+
+               /* try user provided configuration register base address */
+               if (ircc_cfg > 0) {
+                       IRDA_MESSAGE(" Overriding configuration address "
+                                    "0x%04x\n", ircc_cfg);
+                       if (!smsc_superio_fdc(ircc_cfg))
+                               ret = 0;
+                       if (!smsc_superio_lpc(ircc_cfg))
+                               ret = 0;
+               }
 
-       /* try user provided configuration register base address */
-       if (ircc_cfg>0) {
-               IRDA_MESSAGE(" Overriding configuration address 0x%04x\n",
-                            ircc_cfg);
-               if (!smsc_superio_fdc(ircc_cfg))
-                       ret = 0;
-               if (!smsc_superio_lpc(ircc_cfg))
+               if (smsc_ircc_look_for_chips() > 0)
                        ret = 0;
        }
-       
-       if(smsc_ircc_look_for_chips()>0) ret = 0;
-       
+
+       if (ret)
+               driver_unregister(&smsc_ircc_driver);
+
        return ret;
 }
 
@@ -369,15 +393,15 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u
        struct smsc_ircc_cb *self;
        struct net_device *dev;
        int err;
-       
+
        IRDA_DEBUG(1, "%s\n", __FUNCTION__);
 
        err = smsc_ircc_present(fir_base, sir_base);
-       if(err) 
+       if (err)
                goto err_out;
-               
+
        err = -ENOMEM;
-       if (dev_count > DIM(dev_self)) {
+       if (dev_count >= ARRAY_SIZE(dev_self)) {
                IRDA_WARNING("%s(), too many devices!\n", __FUNCTION__);
                goto err_out1;
        }
@@ -396,14 +420,14 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u
        dev->hard_start_xmit = smsc_ircc_hard_xmit_sir;
 #if SMSC_IRCC2_C_NET_TIMEOUT
        dev->tx_timeout      = smsc_ircc_timeout;
-       dev->watchdog_timeo  = HZ*2;  /* Allow enough time for speed change */
+       dev->watchdog_timeo  = HZ * 2;  /* Allow enough time for speed change */
 #endif
        dev->open            = smsc_ircc_net_open;
        dev->stop            = smsc_ircc_net_close;
        dev->do_ioctl        = smsc_ircc_net_ioctl;
        dev->get_stats       = smsc_ircc_net_get_stats;
-       
-       self = dev->priv;
+
+       self = netdev_priv(dev);
        self->netdev = dev;
 
        /* Make ifconfig display some details */
@@ -411,10 +435,10 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u
        dev->irq = self->io.irq = irq;
 
        /* Need to store self somewhere */
-       dev_self[dev_count++] = self;
+       dev_self[dev_count] = self;
        spin_lock_init(&self->lock);
 
-       self->rx_buff.truesize = SMSC_IRCC2_RX_BUFF_TRUESIZE; 
+       self->rx_buff.truesize = SMSC_IRCC2_RX_BUFF_TRUESIZE;
        self->tx_buff.truesize = SMSC_IRCC2_TX_BUFF_TRUESIZE;
 
        self->rx_buff.head =
@@ -442,33 +466,40 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u
        self->rx_buff.state = OUTSIDE_FRAME;
        self->tx_buff.data = self->tx_buff.head;
        self->rx_buff.data = self->rx_buff.head;
-          
-       smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq);
 
+       smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq);
        smsc_ircc_setup_qos(self);
-
        smsc_ircc_init_chip(self);
-       
-       if(ircc_transceiver > 0  && 
-          ircc_transceiver < SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS)
+
+       if (ircc_transceiver > 0  &&
+           ircc_transceiver < SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS)
                self->transceiver = ircc_transceiver;
        else
                smsc_ircc_probe_transceiver(self);
 
        err = register_netdev(self->netdev);
-       if(err) {
+       if (err) {
                IRDA_ERROR("%s, Network device registration failed!\n",
                           driver_name);
                goto err_out4;
        }
 
-       self->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, smsc_ircc_pmproc);
-       if (self->pmdev)
-               self->pmdev->data = self;
+       self->pldev = platform_device_register_simple(SMSC_IRCC2_DRIVER_NAME,
+                                                     dev_count, NULL, 0);
+       if (IS_ERR(self->pldev)) {
+               err = PTR_ERR(self->pldev);
+               goto err_out5;
+       }
+       dev_set_drvdata(&self->pldev->dev, self);
 
        IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name);
+       dev_count++;
 
        return 0;
+
+ err_out5:
+       unregister_netdev(self->netdev);
+
  err_out4:
        dma_free_coherent(NULL, self->tx_buff.truesize,
                          self->tx_buff.head, self->tx_buff_dma);
@@ -477,7 +508,7 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u
                          self->rx_buff.head, self->rx_buff_dma);
  err_out2:
        free_netdev(self->netdev);
-       dev_self[--dev_count] = NULL;
+       dev_self[dev_count] = NULL;
  err_out1:
        release_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT);
        release_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT);
@@ -511,16 +542,16 @@ static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base)
 
        register_bank(fir_base, 3);
 
-       high    = inb(fir_base+IRCC_ID_HIGH);
-       low     = inb(fir_base+IRCC_ID_LOW);
-       chip    = inb(fir_base+IRCC_CHIP_ID);
-       version = inb(fir_base+IRCC_VERSION);
-       config  = inb(fir_base+IRCC_INTERFACE);
+       high    = inb(fir_base + IRCC_ID_HIGH);
+       low     = inb(fir_base + IRCC_ID_LOW);
+       chip    = inb(fir_base + IRCC_CHIP_ID);
+       version = inb(fir_base + IRCC_VERSION);
+       config  = inb(fir_base + IRCC_INTERFACE);
        dma     = config & IRCC_INTERFACE_DMA_MASK;
        irq     = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;
 
-       if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) { 
-               IRDA_WARNING("%s(), addr 0x%04x - no device found!\n",
+       if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) {
+               IRDA_WARNING("%s(), addr 0x%04x - no device found!\n",
                             __FUNCTION__, fir_base);
                goto out3;
        }
@@ -529,6 +560,7 @@ static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base)
                     chip & 0x0f, version, fir_base, sir_base, dma, irq);
 
        return 0;
+
  out3:
        release_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT);
  out2:
@@ -543,16 +575,16 @@ static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base)
  *    Setup I/O
  *
  */
-static void smsc_ircc_setup_io(struct smsc_ircc_cb *self, 
-                              unsigned int fir_base, unsigned int sir_base, 
+static void smsc_ircc_setup_io(struct smsc_ircc_cb *self,
+                              unsigned int fir_base, unsigned int sir_base,
                               u8 dma, u8 irq)
 {
        unsigned char config, chip_dma, chip_irq;
 
        register_bank(fir_base, 3);
-       config  = inb(fir_base+IRCC_INTERFACE);
-       chip_dma     = config & IRCC_INTERFACE_DMA_MASK;
-       chip_irq     = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;
+       config = inb(fir_base + IRCC_INTERFACE);
+       chip_dma = config & IRCC_INTERFACE_DMA_MASK;
+       chip_irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;
 
        self->io.fir_base  = fir_base;
        self->io.sir_base  = sir_base;
@@ -566,17 +598,15 @@ static void smsc_ircc_setup_io(struct smsc_ircc_cb *self,
                        IRDA_MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",
                                     driver_name, chip_irq, irq);
                self->io.irq = irq;
-       }
-       else
+       } else
                self->io.irq = chip_irq;
-       
+
        if (dma < 255) {
                if (dma != chip_dma)
                        IRDA_MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",
                                     driver_name, chip_dma, dma);
                self->io.dma = dma;
-       }
-       else
+       } else
                self->io.dma = chip_dma;
 
 }
@@ -591,7 +621,7 @@ static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self)
 {
        /* Initialize QoS for this device */
        irda_init_max_qos_capabilies(&self->qos);
-       
+
        self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
                IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);
 
@@ -608,43 +638,43 @@ static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self)
  */
 static void smsc_ircc_init_chip(struct smsc_ircc_cb *self)
 {
-       int iobase, ir_mode, ctrl, fast; 
-       
-       IRDA_ASSERT( self != NULL, return; );
-       iobase = self->io.fir_base;
+       int iobase, ir_mode, ctrl, fast;
+
+       IRDA_ASSERT(self != NULL, return;);
 
+       iobase = self->io.fir_base;
        ir_mode = IRCC_CFGA_IRDA_SIR_A;
        ctrl = 0;
        fast = 0;
 
        register_bank(iobase, 0);
-       outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
-       outb(0x00, iobase+IRCC_MASTER);
+       outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER);
+       outb(0x00, iobase + IRCC_MASTER);
 
        register_bank(iobase, 1);
-       outb(((inb(iobase+IRCC_SCE_CFGA) & 0x87) | ir_mode), 
-            iobase+IRCC_SCE_CFGA);
+       outb(((inb(iobase + IRCC_SCE_CFGA) & 0x87) | ir_mode),
+            iobase + IRCC_SCE_CFGA);
 
 #ifdef smsc_669 /* Uses pin 88/89 for Rx/Tx */
-       outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM), 
-            iobase+IRCC_SCE_CFGB);
-#else  
-       outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
-            iobase+IRCC_SCE_CFGB);
-#endif 
-       (void) inb(iobase+IRCC_FIFO_THRESHOLD);
-       outb(SMSC_IRCC2_FIFO_THRESHOLD, iobase+IRCC_FIFO_THRESHOLD);
-       
+       outb(((inb(iobase + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM),
+            iobase + IRCC_SCE_CFGB);
+#else
+       outb(((inb(iobase + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
+            iobase + IRCC_SCE_CFGB);
+#endif
+       (void) inb(iobase + IRCC_FIFO_THRESHOLD);
+       outb(SMSC_IRCC2_FIFO_THRESHOLD, iobase + IRCC_FIFO_THRESHOLD);
+
        register_bank(iobase, 4);
-       outb((inb(iobase+IRCC_CONTROL) & 0x30) | ctrl, iobase+IRCC_CONTROL);
-       
+       outb((inb(iobase + IRCC_CONTROL) & 0x30) | ctrl, iobase + IRCC_CONTROL);
+
        register_bank(iobase, 0);
-       outb(fast, iobase+IRCC_LCR_A);
+       outb(fast, iobase + IRCC_LCR_A);
 
        smsc_ircc_set_sir_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED);
-       
+
        /* Power on device */
-       outb(0x00, iobase+IRCC_MASTER);
+       outb(0x00, iobase + IRCC_MASTER);
 }
 
 /*
@@ -662,12 +692,12 @@ static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd
 
        IRDA_ASSERT(dev != NULL, return -1;);
 
-       self = dev->priv;
+       self = netdev_priv(dev);
 
        IRDA_ASSERT(self != NULL, return -1;);
 
        IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
-       
+
        switch (cmd) {
        case SIOCSBANDWIDTH: /* Set bandwidth */
                if (!capable(CAP_NET_ADMIN))
@@ -703,14 +733,14 @@ static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd
        default:
                ret = -EOPNOTSUPP;
        }
-       
+
        return ret;
 }
 
 static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev)
 {
-       struct smsc_ircc_cb *self = (struct smsc_ircc_cb *) dev->priv;
-       
+       struct smsc_ircc_cb *self = netdev_priv(dev);
+
        return &self->stats;
 }
 
@@ -724,11 +754,9 @@ static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev)
 
 static void smsc_ircc_timeout(struct net_device *dev)
 {
-       struct smsc_ircc_cb *self;
+       struct smsc_ircc_cb *self = netdev_priv(dev);
        unsigned long flags;
 
-       self = (struct smsc_ircc_cb *) dev->priv;
-       
        IRDA_WARNING("%s: transmit timed out, changing speed to: %d\n",
                     dev->name, self->io.speed);
        spin_lock_irqsave(&self->lock, flags);
@@ -751,26 +779,23 @@ int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
 {
        struct smsc_ircc_cb *self;
        unsigned long flags;
-       int iobase;
        s32 speed;
 
        IRDA_DEBUG(1, "%s\n", __FUNCTION__);
 
        IRDA_ASSERT(dev != NULL, return 0;);
-       
-       self = (struct smsc_ircc_cb *) dev->priv;
-       IRDA_ASSERT(self != NULL, return 0;);
 
-       iobase = self->io.sir_base;
+       self = netdev_priv(dev);
+       IRDA_ASSERT(self != NULL, return 0;);
 
        netif_stop_queue(dev);
-       
+
        /* Make sure test of self->io.speed & speed change are atomic */
        spin_lock_irqsave(&self->lock, flags);
 
        /* Check if we need to change the speed */
        speed = irda_get_next_speed(skb);
-       if ((speed != self->io.speed) && (speed != -1)) {
+       if (speed != self->io.speed && speed != -1) {
                /* Check for empty frame */
                if (!skb->len) {
                        /*
@@ -787,27 +812,26 @@ int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
                        spin_unlock_irqrestore(&self->lock, flags);
                        dev_kfree_skb(skb);
                        return 0;
-               } else {
-                       self->new_speed = speed;
                }
+               self->new_speed = speed;
        }
 
        /* Init tx buffer */
        self->tx_buff.data = self->tx_buff.head;
 
        /* Copy skb to tx_buff while wrapping, stuffing and making CRC */
-       self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, 
+       self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
                                           self->tx_buff.truesize);
-       
+
        self->stats.tx_bytes += self->tx_buff.len;
 
        /* Turn on transmit finished interrupt. Will fire immediately!  */
-       outb(UART_IER_THRI, iobase+UART_IER); 
+       outb(UART_IER_THRI, self->io.sir_base + UART_IER);
 
        spin_unlock_irqrestore(&self->lock, flags);
 
        dev_kfree_skb(skb);
-       
+
        return 0;
 }
 
@@ -826,9 +850,9 @@ static void smsc_ircc_set_fir_speed(struct smsc_ircc_cb *self, u32 speed)
 
        self->io.speed = speed;
 
-       switch(speed) {
+       switch (speed) {
        default:
-       case 576000:            
+       case 576000:
                ir_mode = IRCC_CFGA_IRDA_HDLC;
                ctrl = IRCC_CRC;
                fast = 0;
@@ -853,14 +877,14 @@ static void smsc_ircc_set_fir_speed(struct smsc_ircc_cb *self, u32 speed)
        Now in tranceiver!
        /* This causes an interrupt */
        register_bank(fir_base, 0);
-       outb((inb(fir_base+IRCC_LCR_A) &  0xbf) | fast, fir_base+IRCC_LCR_A);
+       outb((inb(fir_base + IRCC_LCR_A) &  0xbf) | fast, fir_base + IRCC_LCR_A);
        #endif
-       
+
        register_bank(fir_base, 1);
-       outb(((inb(fir_base+IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | ir_mode), fir_base+IRCC_SCE_CFGA);
-       
+       outb(((inb(fir_base + IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | ir_mode), fir_base + IRCC_SCE_CFGA);
+
        register_bank(fir_base, 4);
-       outb((inb(fir_base+IRCC_CONTROL) & 0x30) | ctrl, fir_base+IRCC_CONTROL);
+       outb((inb(fir_base + IRCC_CONTROL) & 0x30) | ctrl, fir_base + IRCC_CONTROL);
 }
 
 /*
@@ -885,31 +909,31 @@ static void smsc_ircc_fir_start(struct smsc_ircc_cb *self)
        /* Reset everything */
 
        /* Install FIR transmit handler */
-       dev->hard_start_xmit = smsc_ircc_hard_xmit_fir; 
+       dev->hard_start_xmit = smsc_ircc_hard_xmit_fir;
 
        /* Clear FIFO */
-       outb(inb(fir_base+IRCC_LCR_A)|IRCC_LCR_A_FIFO_RESET, fir_base+IRCC_LCR_A);
+       outb(inb(fir_base + IRCC_LCR_A) | IRCC_LCR_A_FIFO_RESET, fir_base + IRCC_LCR_A);
 
        /* Enable interrupt */
-       /*outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base+IRCC_IER);*/
+       /*outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base + IRCC_IER);*/
 
        register_bank(fir_base, 1);
 
-       /* Select the TX/RX interface */        
+       /* Select the TX/RX interface */
 #ifdef SMSC_669 /* Uses pin 88/89 for Rx/Tx */
-       outb(((inb(fir_base+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM), 
-            fir_base+IRCC_SCE_CFGB);
-#else  
-       outb(((inb(fir_base+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
-            fir_base+IRCC_SCE_CFGB);
-#endif 
-       (void) inb(fir_base+IRCC_FIFO_THRESHOLD);
+       outb(((inb(fir_base + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM),
+            fir_base + IRCC_SCE_CFGB);
+#else
+       outb(((inb(fir_base + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
+            fir_base + IRCC_SCE_CFGB);
+#endif
+       (void) inb(fir_base + IRCC_FIFO_THRESHOLD);
 
        /* Enable SCE interrupts */
-       outb(0, fir_base+IRCC_MASTER);
+       outb(0, fir_base + IRCC_MASTER);
        register_bank(fir_base, 0);
-       outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base+IRCC_IER);
-       outb(IRCC_MASTER_INT_EN, fir_base+IRCC_MASTER);
+       outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, fir_base + IRCC_IER);
+       outb(IRCC_MASTER_INT_EN, fir_base + IRCC_MASTER);
 }
 
 /*
@@ -923,13 +947,13 @@ static void smsc_ircc_fir_stop(struct smsc_ircc_cb *self)
        int fir_base;
 
        IRDA_DEBUG(1, "%s\n", __FUNCTION__);
-       
+
        IRDA_ASSERT(self != NULL, return;);
 
        fir_base = self->io.fir_base;
        register_bank(fir_base, 0);
-       /*outb(IRCC_MASTER_RESET, fir_base+IRCC_MASTER);*/      
-       outb(inb(fir_base+IRCC_LCR_B) & IRCC_LCR_B_SIP_ENABLE, fir_base+IRCC_LCR_B);
+       /*outb(IRCC_MASTER_RESET, fir_base + IRCC_MASTER);*/
+       outb(inb(fir_base + IRCC_LCR_B) & IRCC_LCR_B_SIP_ENABLE, fir_base + IRCC_LCR_B);
 }
 
 
@@ -941,18 +965,15 @@ static void smsc_ircc_fir_stop(struct smsc_ircc_cb *self)
  * This function *must* be called with spinlock held, because it may
  * be called from the irq handler. - Jean II
  */
-static void smsc_ircc_change_speed(void *priv, u32 speed)
+static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed)
 {
-       struct smsc_ircc_cb *self = (struct smsc_ircc_cb *) priv;
        struct net_device *dev;
-       int iobase;
        int last_speed_was_sir;
-       
+
        IRDA_DEBUG(0, "%s() changing speed to: %d\n", __FUNCTION__, speed);
 
        IRDA_ASSERT(self != NULL, return;);
        dev = self->netdev;
-       iobase = self->io.fir_base;
 
        last_speed_was_sir = self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED;
 
@@ -961,30 +982,30 @@ static void smsc_ircc_change_speed(void *priv, u32 speed)
        speed= 1152000;
        self->io.speed = speed;
        last_speed_was_sir = 0;
-       smsc_ircc_fir_start(self);      
+       smsc_ircc_fir_start(self);
        #endif
-       
-       if(self->io.speed == 0)
+
+       if (self->io.speed == 0)
                smsc_ircc_sir_start(self);
 
        #if 0
-       if(!last_speed_was_sir) speed = self->io.speed;
+       if (!last_speed_was_sir) speed = self->io.speed;
        #endif
 
-       if(self->io.speed != speed) smsc_ircc_set_transceiver_for_speed(self, speed);
+       if (self->io.speed != speed)
+               smsc_ircc_set_transceiver_for_speed(self, speed);
 
        self->io.speed = speed;
-       
-       if(speed <= SMSC_IRCC2_MAX_SIR_SPEED) {
-               if(!last_speed_was_sir) {
+
+       if (speed <= SMSC_IRCC2_MAX_SIR_SPEED) {
+               if (!last_speed_was_sir) {
                        smsc_ircc_fir_stop(self);
                        smsc_ircc_sir_start(self);
                }
-               smsc_ircc_set_sir_speed(self, speed); 
-       }
-       else {
-               if(last_speed_was_sir) {
-                       #if SMSC_IRCC2_C_SIR_STOP               
+               smsc_ircc_set_sir_speed(self, speed);
+       } else {
+               if (last_speed_was_sir) {
+                       #if SMSC_IRCC2_C_SIR_STOP
                        smsc_ircc_sir_stop(self);
                        #endif
                        smsc_ircc_fir_start(self);
@@ -994,13 +1015,13 @@ static void smsc_ircc_change_speed(void *priv, u32 speed)
                #if 0
                self->tx_buff.len = 10;
                self->tx_buff.data = self->tx_buff.head;
-               
-               smsc_ircc_dma_xmit(self, iobase, 4000);
+
+               smsc_ircc_dma_xmit(self, 4000);
                #endif
                /* Be ready for incoming frames */
-               smsc_ircc_dma_receive(self, iobase);
+               smsc_ircc_dma_receive(self);
        }
-       
+
        netif_wake_queue(dev);
 }
 
@@ -1010,10 +1031,9 @@ static void smsc_ircc_change_speed(void *priv, u32 speed)
  *    Set speed of IrDA port to specified baudrate
  *
  */
-void smsc_ircc_set_sir_speed(void *priv, __u32 speed)
+void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, __u32 speed)
 {
-       struct smsc_ircc_cb *self = (struct smsc_ircc_cb *) priv;
-       int iobase; 
+       int iobase;
        int fcr;    /* FIFO control reg */
        int lcr;    /* Line control reg */
        int divisor;
@@ -1022,38 +1042,36 @@ void smsc_ircc_set_sir_speed(void *priv, __u32 speed)
 
        IRDA_ASSERT(self != NULL, return;);
        iobase = self->io.sir_base;
-       
+
        /* Update accounting for new speed */
        self->io.speed = speed;
 
        /* Turn off interrupts */
-       outb(0, iobase+UART_IER); 
+       outb(0, iobase + UART_IER);
+
+       divisor = SMSC_IRCC2_MAX_SIR_SPEED / speed;
 
-       divisor = SMSC_IRCC2_MAX_SIR_SPEED/speed;
-       
        fcr = UART_FCR_ENABLE_FIFO;
 
-       /* 
+       /*
         * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
         * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
-        * about this timeout since it will always be fast enough. 
+        * about this timeout since it will always be fast enough.
         */
-       if (self->io.speed < 38400)
-               fcr |= UART_FCR_TRIGGER_1;
-       else 
-               fcr |= UART_FCR_TRIGGER_14;
-        
+       fcr |= self->io.speed < 38400 ?
+               UART_FCR_TRIGGER_1 : UART_FCR_TRIGGER_14;
+
        /* IrDA ports use 8N1 */
        lcr = UART_LCR_WLEN8;
-       
-       outb(UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */
-       outb(divisor & 0xff,      iobase+UART_DLL); /* Set speed */
-       outb(divisor >> 8,        iobase+UART_DLM);
-       outb(lcr,                 iobase+UART_LCR); /* Set 8N1  */
-       outb(fcr,                 iobase+UART_FCR); /* Enable FIFO's */
+
+       outb(UART_LCR_DLAB | lcr, iobase + UART_LCR); /* Set DLAB */
+       outb(divisor & 0xff,      iobase + UART_DLL); /* Set speed */
+       outb(divisor >> 8,        iobase + UART_DLM);
+       outb(lcr,                 iobase + UART_LCR); /* Set 8N1 */
+       outb(fcr,                 iobase + UART_FCR); /* Enable FIFO's */
 
        /* Turn on interrups */
-       outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, iobase+UART_IER);
+       outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
 
        IRDA_DEBUG(2, "%s() speed changed to: %d\n", __FUNCTION__, speed);
 }
@@ -1070,15 +1088,12 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
        struct smsc_ircc_cb *self;
        unsigned long flags;
        s32 speed;
-       int iobase;
        int mtt;
 
        IRDA_ASSERT(dev != NULL, return 0;);
-       self = (struct smsc_ircc_cb *) dev->priv;
+       self = netdev_priv(dev);
        IRDA_ASSERT(self != NULL, return 0;);
 
-       iobase = self->io.fir_base;
-
        netif_stop_queue(dev);
 
        /* Make sure test of self->io.speed & speed change are atomic */
@@ -1086,30 +1101,31 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
 
        /* Check if we need to change the speed after this frame */
        speed = irda_get_next_speed(skb);
-       if ((speed != self->io.speed) && (speed != -1)) {
+       if (speed != self->io.speed && speed != -1) {
                /* Check for empty frame */
                if (!skb->len) {
                        /* Note : you should make sure that speed changes
                         * are not going to corrupt any outgoing frame.
                         * Look at nsc-ircc for the gory details - Jean II */
-                       smsc_ircc_change_speed(self, speed); 
+                       smsc_ircc_change_speed(self, speed);
                        spin_unlock_irqrestore(&self->lock, flags);
                        dev_kfree_skb(skb);
                        return 0;
-               } else
-                       self->new_speed = speed;
+               }
+
+               self->new_speed = speed;
        }
-       
+
        memcpy(self->tx_buff.head, skb->data, skb->len);
 
        self->tx_buff.len = skb->len;
        self->tx_buff.data = self->tx_buff.head;
-       
-       mtt = irda_get_mtt(skb);        
+
+       mtt = irda_get_mtt(skb);
        if (mtt) {
                int bofs;
 
-               /* 
+               /*
                 * Compute how many BOFs (STA or PA's) we need to waste the
                 * min turn time given the speed of the link.
                 */
@@ -1117,11 +1133,12 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
                if (bofs > 4095)
                        bofs = 4095;
 
-               smsc_ircc_dma_xmit(self, iobase, bofs);
+               smsc_ircc_dma_xmit(self, bofs);
        } else {
                /* Transmit frame */
-               smsc_ircc_dma_xmit(self, iobase, 0);
+               smsc_ircc_dma_xmit(self, 0);
        }
+
        spin_unlock_irqrestore(&self->lock, flags);
        dev_kfree_skb(skb);
 
@@ -1129,43 +1146,44 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
 }
 
 /*
- * Function smsc_ircc_dma_xmit (self, iobase)
+ * Function smsc_ircc_dma_xmit (self, bofs)
  *
  *    Transmit data using DMA
  *
  */
-static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int iobase, int bofs)
+static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int bofs)
 {
+       int iobase = self->io.fir_base;
        u8 ctrl;
 
        IRDA_DEBUG(3, "%s\n", __FUNCTION__);
 #if 1
        /* Disable Rx */
        register_bank(iobase, 0);
-       outb(0x00, iobase+IRCC_LCR_B);
+       outb(0x00, iobase + IRCC_LCR_B);
 #endif
        register_bank(iobase, 1);
-       outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, 
-            iobase+IRCC_SCE_CFGB);
+       outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+            iobase + IRCC_SCE_CFGB);
 
        self->io.direction = IO_XMIT;
 
        /* Set BOF additional count for generating the min turn time */
        register_bank(iobase, 4);
-       outb(bofs & 0xff, iobase+IRCC_BOF_COUNT_LO);
-       ctrl = inb(iobase+IRCC_CONTROL) & 0xf0;
-       outb(ctrl | ((bofs >> 8) & 0x0f), iobase+IRCC_BOF_COUNT_HI);
+       outb(bofs & 0xff, iobase + IRCC_BOF_COUNT_LO);
+       ctrl = inb(iobase + IRCC_CONTROL) & 0xf0;
+       outb(ctrl | ((bofs >> 8) & 0x0f), iobase + IRCC_BOF_COUNT_HI);
 
        /* Set max Tx frame size */
-       outb(self->tx_buff.len >> 8, iobase+IRCC_TX_SIZE_HI);
-       outb(self->tx_buff.len & 0xff, iobase+IRCC_TX_SIZE_LO);
+       outb(self->tx_buff.len >> 8, iobase + IRCC_TX_SIZE_HI);
+       outb(self->tx_buff.len & 0xff, iobase + IRCC_TX_SIZE_LO);
 
        /*outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR);*/
-       
+
        /* Enable burst mode chip Tx DMA */
        register_bank(iobase, 1);
-       outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
-            IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB);
+       outb(inb(iobase + IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
+            IRCC_CFGB_DMA_BURST, iobase + IRCC_SCE_CFGB);
 
        /* Setup DMA controller (must be done after enabling chip DMA) */
        irda_setup_dma(self->io.dma, self->tx_buff_dma, self->tx_buff.len,
@@ -1174,50 +1192,52 @@ static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int iobase, int bofs)
        /* Enable interrupt */
 
        register_bank(iobase, 0);
-       outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER);
-       outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
-       
+       outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER);
+       outb(IRCC_MASTER_INT_EN, iobase + IRCC_MASTER);
+
        /* Enable transmit */
-       outb(IRCC_LCR_B_SCE_TRANSMIT | IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B);
+       outb(IRCC_LCR_B_SCE_TRANSMIT | IRCC_LCR_B_SIP_ENABLE, iobase + IRCC_LCR_B);
 }
 
 /*
  * Function smsc_ircc_dma_xmit_complete (self)
  *
- *    The transfer of a frame in finished. This function will only be called 
+ *    The transfer of a frame in finished. This function will only be called
  *    by the interrupt handler
  *
  */
-static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self, int iobase)
+static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self)
 {
+       int iobase = self->io.fir_base;
+
        IRDA_DEBUG(3, "%s\n", __FUNCTION__);
 #if 0
        /* Disable Tx */
        register_bank(iobase, 0);
-       outb(0x00, iobase+IRCC_LCR_B);
+       outb(0x00, iobase + IRCC_LCR_B);
 #endif
-       register_bank(self->io.fir_base, 1);
-       outb(inb(self->io.fir_base+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
-            self->io.fir_base+IRCC_SCE_CFGB);
+       register_bank(iobase, 1);
+       outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+            iobase + IRCC_SCE_CFGB);
 
        /* Check for underrun! */
        register_bank(iobase, 0);
-       if (inb(iobase+IRCC_LSR) & IRCC_LSR_UNDERRUN) {
+       if (inb(iobase + IRCC_LSR) & IRCC_LSR_UNDERRUN) {
                self->stats.tx_errors++;
                self->stats.tx_fifo_errors++;
 
                /* Reset error condition */
                register_bank(iobase, 0);
-               outb(IRCC_MASTER_ERROR_RESET, iobase+IRCC_MASTER);
-               outb(0x00, iobase+IRCC_MASTER);
+               outb(IRCC_MASTER_ERROR_RESET, iobase + IRCC_MASTER);
+               outb(0x00, iobase + IRCC_MASTER);
        } else {
                self->stats.tx_packets++;
-               self->stats.tx_bytes +=  self->tx_buff.len;
+               self->stats.tx_bytes += self->tx_buff.len;
        }
 
        /* Check if it's time to change the speed */
        if (self->new_speed) {
-               smsc_ircc_change_speed(self, self->new_speed);          
+               smsc_ircc_change_speed(self, self->new_speed);
                self->new_speed = 0;
        }
 
@@ -1231,31 +1251,32 @@ static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self, int iobase)
  *    if it starts to receive a frame.
  *
  */
-static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self, int iobase) 
+static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self)
 {
+       int iobase = self->io.fir_base;
 #if 0
        /* Turn off chip DMA */
        register_bank(iobase, 1);
-       outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, 
-            iobase+IRCC_SCE_CFGB);
+       outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+            iobase + IRCC_SCE_CFGB);
 #endif
-       
+
        /* Disable Tx */
        register_bank(iobase, 0);
-       outb(0x00, iobase+IRCC_LCR_B);
+       outb(0x00, iobase + IRCC_LCR_B);
 
        /* Turn off chip DMA */
        register_bank(iobase, 1);
-       outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, 
-            iobase+IRCC_SCE_CFGB);
+       outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+            iobase + IRCC_SCE_CFGB);
 
        self->io.direction = IO_RECV;
        self->rx_buff.data = self->rx_buff.head;
 
        /* Set max Rx frame size */
        register_bank(iobase, 4);
-       outb((2050 >> 8) & 0x0f, iobase+IRCC_RX_SIZE_HI);
-       outb(2050 & 0xff, iobase+IRCC_RX_SIZE_LO);
+       outb((2050 >> 8) & 0x0f, iobase + IRCC_RX_SIZE_HI);
+       outb(2050 & 0xff, iobase + IRCC_RX_SIZE_LO);
 
        /* Setup DMA controller */
        irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize,
@@ -1263,83 +1284,83 @@ static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self, int iobase)
 
        /* Enable burst mode chip Rx DMA */
        register_bank(iobase, 1);
-       outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE | 
-            IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB);
+       outb(inb(iobase + IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
+            IRCC_CFGB_DMA_BURST, iobase + IRCC_SCE_CFGB);
 
        /* Enable interrupt */
        register_bank(iobase, 0);
-       outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER);
-       outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
-
+       outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER);
+       outb(IRCC_MASTER_INT_EN, iobase + IRCC_MASTER);
 
        /* Enable receiver */
        register_bank(iobase, 0);
-       outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE, 
-            iobase+IRCC_LCR_B);
-       
+       outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE,
+            iobase + IRCC_LCR_B);
+
        return 0;
 }
 
 /*
- * Function smsc_ircc_dma_receive_complete(self, iobase)
+ * Function smsc_ircc_dma_receive_complete(self)
  *
  *    Finished with receiving frames
  *
  */
-static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self, int iobase)
+static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self)
 {
        struct sk_buff *skb;
        int len, msgcnt, lsr;
-       
+       int iobase = self->io.fir_base;
+
        register_bank(iobase, 0);
-       
+
        IRDA_DEBUG(3, "%s\n", __FUNCTION__);
 #if 0
        /* Disable Rx */
        register_bank(iobase, 0);
-       outb(0x00, iobase+IRCC_LCR_B);
+       outb(0x00, iobase + IRCC_LCR_B);
 #endif
        register_bank(iobase, 0);
-       outb(inb(iobase+IRCC_LSAR) & ~IRCC_LSAR_ADDRESS_MASK, iobase+IRCC_LSAR);
-       lsr= inb(iobase+IRCC_LSR);
-       msgcnt = inb(iobase+IRCC_LCR_B) & 0x08;
+       outb(inb(iobase + IRCC_LSAR) & ~IRCC_LSAR_ADDRESS_MASK, iobase + IRCC_LSAR);
+       lsr= inb(iobase + IRCC_LSR);
+       msgcnt = inb(iobase + IRCC_LCR_B) & 0x08;
 
        IRDA_DEBUG(2, "%s: dma count = %d\n", __FUNCTION__,
                   get_dma_residue(self->io.dma));
 
        len = self->rx_buff.truesize - get_dma_residue(self->io.dma);
 
-       /* Look for errors 
-        */     
-
-       if(lsr & (IRCC_LSR_FRAME_ERROR | IRCC_LSR_CRC_ERROR | IRCC_LSR_SIZE_ERROR)) {
+       /* Look for errors */
+       if (lsr & (IRCC_LSR_FRAME_ERROR | IRCC_LSR_CRC_ERROR | IRCC_LSR_SIZE_ERROR)) {
                self->stats.rx_errors++;
-               if(lsr & IRCC_LSR_FRAME_ERROR) self->stats.rx_frame_errors++;
-               if(lsr & IRCC_LSR_CRC_ERROR) self->stats.rx_crc_errors++;
-               if(lsr & IRCC_LSR_SIZE_ERROR) self->stats.rx_length_errors++;
-               if(lsr & (IRCC_LSR_UNDERRUN | IRCC_LSR_OVERRUN)) self->stats.rx_length_errors++;
+               if (lsr & IRCC_LSR_FRAME_ERROR)
+                       self->stats.rx_frame_errors++;
+               if (lsr & IRCC_LSR_CRC_ERROR)
+                       self->stats.rx_crc_errors++;
+               if (lsr & IRCC_LSR_SIZE_ERROR)
+                       self->stats.rx_length_errors++;
+               if (lsr & (IRCC_LSR_UNDERRUN | IRCC_LSR_OVERRUN))
+                       self->stats.rx_length_errors++;
                return;
        }
+
        /* Remove CRC */
-       if (self->io.speed < 4000000)
-               len -= 2;
-       else
-               len -= 4;
+       len -= self->io.speed < 4000000 ? 2 : 4;
 
-       if ((len < 2) || (len > 2050)) {
+       if (len < 2 || len > 2050) {
                IRDA_WARNING("%s(), bogus len=%d\n", __FUNCTION__, len);
                return;
        }
        IRDA_DEBUG(2, "%s: msgcnt = %d, len=%d\n", __FUNCTION__, msgcnt, len);
 
-       skb = dev_alloc_skb(len+1);
-       if (!skb)  {
+       skb = dev_alloc_skb(len + 1);
+       if (!skb) {
                IRDA_WARNING("%s(), memory squeeze, dropping frame.\n",
                             __FUNCTION__);
                return;
-       }                       
+       }
        /* Make sure IP header gets aligned */
-       skb_reserve(skb, 1); 
+       skb_reserve(skb, 1);
 
        memcpy(skb_put(skb, len), self->rx_buff.data, len);
        self->stats.rx_packets++;
@@ -1357,7 +1378,7 @@ static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self, int iobase
  *    Receive one frame from the infrared port
  *
  */
-static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self) 
+static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self)
 {
        int boguscount = 0;
        int iobase;
@@ -1366,20 +1387,20 @@ static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self)
 
        iobase = self->io.sir_base;
 
-       /*  
-        * Receive all characters in Rx FIFO, unwrap and unstuff them. 
-         * async_unwrap_char will deliver all found frames  
+       /*
+        * Receive all characters in Rx FIFO, unwrap and unstuff them.
+         * async_unwrap_char will deliver all found frames
         */
        do {
-               async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, 
-                                 inb(iobase+UART_RX));
+               async_unwrap_char(self->netdev, &self->stats, &self->rx_buff,
+                                 inb(iobase + UART_RX));
 
                /* Make sure we don't stay here to long */
                if (boguscount++ > 32) {
                        IRDA_DEBUG(2, "%s(), breaking!\n", __FUNCTION__);
                        break;
                }
-       } while (inb(iobase+UART_LSR) & UART_LSR_DR);   
+       } while (inb(iobase + UART_LSR) & UART_LSR_DR);
 }
 
 
@@ -1397,18 +1418,19 @@ static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *re
        irqreturn_t ret = IRQ_NONE;
 
        if (dev == NULL) {
-               printk(KERN_WARNING "%s: irq %d for unknown device.\n", 
+               printk(KERN_WARNING "%s: irq %d for unknown device.\n",
                       driver_name, irq);
                goto irq_ret;
        }
-       self = (struct smsc_ircc_cb *) dev->priv;
+
+       self = netdev_priv(dev);
        IRDA_ASSERT(self != NULL, return IRQ_NONE;);
 
        /* Serialise the interrupt handler in various CPUs, stop Tx path */
-       spin_lock(&self->lock); 
+       spin_lock(&self->lock);
 
        /* Check if we should use the SIR interrupt handler */
-       if (self->io.speed <=  SMSC_IRCC2_MAX_SIR_SPEED) {
+       if (self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED) {
                ret = smsc_ircc_interrupt_sir(dev);
                goto irq_ret_unlock;
        }
@@ -1416,25 +1438,25 @@ static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *re
        iobase = self->io.fir_base;
 
        register_bank(iobase, 0);
-       iir = inb(iobase+IRCC_IIR);
-       if (iir == 0) 
+       iir = inb(iobase + IRCC_IIR);
+       if (iir == 0)
                goto irq_ret_unlock;
        ret = IRQ_HANDLED;
 
        /* Disable interrupts */
-       outb(0, iobase+IRCC_IER);
-       lcra = inb(iobase+IRCC_LCR_A);
-       lsr = inb(iobase+IRCC_LSR);
-       
+       outb(0, iobase + IRCC_IER);
+       lcra = inb(iobase + IRCC_LCR_A);
+       lsr = inb(iobase + IRCC_LSR);
+
        IRDA_DEBUG(2, "%s(), iir = 0x%02x\n", __FUNCTION__, iir);
 
        if (iir & IRCC_IIR_EOM) {
                if (self->io.direction == IO_RECV)
-                       smsc_ircc_dma_receive_complete(self, iobase);
+                       smsc_ircc_dma_receive_complete(self);
                else
-                       smsc_ircc_dma_xmit_complete(self, iobase);
-               
-               smsc_ircc_dma_receive(self, iobase);
+                       smsc_ircc_dma_xmit_complete(self);
+
+               smsc_ircc_dma_receive(self);
        }
 
        if (iir & IRCC_IIR_ACTIVE_FRAME) {
@@ -1444,7 +1466,7 @@ static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *re
        /* Enable interrupts again */
 
        register_bank(iobase, 0);
-       outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER);
+       outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER);
 
  irq_ret_unlock:
        spin_unlock(&self->lock);
@@ -1459,7 +1481,7 @@ static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *re
  */
 static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev)
 {
-       struct smsc_ircc_cb *self = dev->priv;
+       struct smsc_ircc_cb *self = netdev_priv(dev);
        int boguscount = 0;
        int iobase;
        int iir, lsr;
@@ -1469,14 +1491,14 @@ static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev)
 
        iobase = self->io.sir_base;
 
-       iir = inb(iobase+UART_IIR) & UART_IIR_ID;
+       iir = inb(iobase + UART_IIR) & UART_IIR_ID;
        if (iir == 0)
                return IRQ_NONE;
        while (iir) {
                /* Clear interrupt */
-               lsr = inb(iobase+UART_LSR);
+               lsr = inb(iobase + UART_LSR);
 
-               IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", 
+               IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n",
                            __FUNCTION__, iir, lsr, iobase);
 
                switch (iir) {
@@ -1496,13 +1518,13 @@ static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev)
                        IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n",
                                   __FUNCTION__, iir);
                        break;
-               } 
-               
+               }
+
                /* Make sure we don't stay here to long */
                if (boguscount++ > 100)
                        break;
 
-               iir = inb(iobase + UART_IIR) & UART_IIR_ID;
+               iir = inb(iobase + UART_IIR) & UART_IIR_ID;
        }
        /*spin_unlock(&self->lock);*/
        return IRQ_HANDLED;
@@ -1529,7 +1551,7 @@ static int ircc_is_receiving(struct smsc_ircc_cb *self)
                   get_dma_residue(self->io.dma));
 
        status = (self->rx_buff.state != OUTSIDE_FRAME);
-       
+
        return status;
 }
 #endif /* unused */
@@ -1544,19 +1566,16 @@ static int ircc_is_receiving(struct smsc_ircc_cb *self)
 static int smsc_ircc_net_open(struct net_device *dev)
 {
        struct smsc_ircc_cb *self;
-       int iobase;
        char hwname[16];
        unsigned long flags;
 
        IRDA_DEBUG(1, "%s\n", __FUNCTION__);
-       
+
        IRDA_ASSERT(dev != NULL, return -1;);
-       self = (struct smsc_ircc_cb *) dev->priv;
+       self = netdev_priv(dev);
        IRDA_ASSERT(self != NULL, return 0;);
-       
-       iobase = self->io.fir_base;
 
-       if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name, 
+       if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name,
                        (void *) dev)) {
                IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n",
                           __FUNCTION__, self->io.irq);
@@ -1568,14 +1587,14 @@ static int smsc_ircc_net_open(struct net_device *dev)
        self->io.speed = 0;
        smsc_ircc_change_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED);
        spin_unlock_irqrestore(&self->lock, flags);
-       
+
        /* Give self a hardware name */
        /* It would be cool to offer the chip revision here - Jean II */
        sprintf(hwname, "SMSC @ 0x%03x", self->io.fir_base);
 
-       /* 
+       /*
         * Open new IrLAP layer instance, now that everything should be
-        * initialized properly 
+        * initialized properly
         */
        self->irlap = irlap_open(dev, &self->qos, hwname);
 
@@ -1590,7 +1609,7 @@ static int smsc_ircc_net_open(struct net_device *dev)
                             __FUNCTION__, self->io.dma);
                return -EAGAIN;
        }
-       
+
        netif_start_queue(dev);
 
        return 0;
@@ -1605,73 +1624,53 @@ static int smsc_ircc_net_open(struct net_device *dev)
 static int smsc_ircc_net_close(struct net_device *dev)
 {
        struct smsc_ircc_cb *self;
-       int iobase;
 
        IRDA_DEBUG(1, "%s\n", __FUNCTION__);
-       
+
        IRDA_ASSERT(dev != NULL, return -1;);
-       self = (struct smsc_ircc_cb *) dev->priv;       
+       self = netdev_priv(dev);
        IRDA_ASSERT(self != NULL, return 0;);
-       
-       iobase = self->io.fir_base;
 
        /* Stop device */
        netif_stop_queue(dev);
-       
+
        /* Stop and remove instance of IrLAP */
        if (self->irlap)
                irlap_close(self->irlap);
        self->irlap = NULL;
 
        free_irq(self->io.irq, dev);
-
        disable_dma(self->io.dma);
-
        free_dma(self->io.dma);
 
        return 0;
 }
 
-
-static void smsc_ircc_suspend(struct smsc_ircc_cb *self)
+static int smsc_ircc_suspend(struct device *dev, pm_message_t state, u32 level)
 {
-       IRDA_MESSAGE("%s, Suspending\n", driver_name);
+       struct smsc_ircc_cb *self = dev_get_drvdata(dev);
 
-       if (self->io.suspended)
-               return;
+       IRDA_MESSAGE("%s, Suspending\n", driver_name);
 
-       smsc_ircc_net_close(self->netdev);
+       if (level == SUSPEND_DISABLE && !self->io.suspended) {
+               smsc_ircc_net_close(self->netdev);
+               self->io.suspended = 1;
+       }
 
-       self->io.suspended = 1;
+       return 0;
 }
 
-static void smsc_ircc_wakeup(struct smsc_ircc_cb *self)
+static int smsc_ircc_resume(struct device *dev, u32 level)
 {
-       if (!self->io.suspended)
-               return;
+       struct smsc_ircc_cb *self = dev_get_drvdata(dev);
 
-       /* The code was doing a "cli()" here, but this can't be right.
-        * If you need protection, do it in net_open with a spinlock
-        * or give a good reason. - Jean II */
+       if (level == RESUME_ENABLE && self->io.suspended) {
 
-       smsc_ircc_net_open(self->netdev);
-       
-       IRDA_MESSAGE("%s, Waking up\n", driver_name);
-}
+               smsc_ircc_net_open(self->netdev);
+               self->io.suspended = 0;
 
-static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data)
-{
-        struct smsc_ircc_cb *self = (struct smsc_ircc_cb*) dev->data;
-        if (self) {
-                switch (rqst) {
-                case PM_SUSPEND:
-                        smsc_ircc_suspend(self);
-                        break;
-                case PM_RESUME:
-                        smsc_ircc_wakeup(self);
-                        break;
-                }
-        }
+               IRDA_MESSAGE("%s, Waking up\n", driver_name);
+       }
        return 0;
 }
 
@@ -1690,10 +1689,7 @@ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self)
 
        IRDA_ASSERT(self != NULL, return -1;);
 
-       iobase = self->io.fir_base;
-
-       if (self->pmdev)
-               pm_unregister(self->pmdev);
+       platform_device_unregister(self->pldev);
 
        /* Remove netdevice */
        unregister_netdev(self->netdev);
@@ -1702,15 +1698,16 @@ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self)
        spin_lock_irqsave(&self->lock, flags);
 
        /* Stop interrupts */
+       iobase = self->io.fir_base;
        register_bank(iobase, 0);
-       outb(0, iobase+IRCC_IER);
-       outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
-       outb(0x00, iobase+IRCC_MASTER);
+       outb(0, iobase + IRCC_IER);
+       outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER);
+       outb(0x00, iobase + IRCC_MASTER);
 #if 0
        /* Reset to SIR mode */
        register_bank(iobase, 1);
-        outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA);
-        outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB);
+        outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase + IRCC_SCE_CFGA);
+        outb(IRCC_CFGB_IR, iobase + IRCC_SCE_CFGB);
 #endif
        spin_unlock_irqrestore(&self->lock, flags);
 
@@ -1720,7 +1717,7 @@ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self)
 
        release_region(self->io.fir_base, self->io.fir_ext);
 
-       IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__, 
+       IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__,
                   self->io.sir_base);
 
        release_region(self->io.sir_base, self->io.sir_ext);
@@ -1728,7 +1725,7 @@ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self)
        if (self->tx_buff.head)
                dma_free_coherent(NULL, self->tx_buff.truesize,
                                  self->tx_buff.head, self->tx_buff_dma);
-       
+
        if (self->rx_buff.head)
                dma_free_coherent(NULL, self->rx_buff.truesize,
                                  self->rx_buff.head, self->rx_buff_dma);
@@ -1744,10 +1741,12 @@ static void __exit smsc_ircc_cleanup(void)
 
        IRDA_DEBUG(1, "%s\n", __FUNCTION__);
 
-       for (i=0; i < 2; i++) {
+       for (i = 0; i < 2; i++) {
                if (dev_self[i])
                        smsc_ircc_close(dev_self[i]);
        }
+
+       driver_unregister(&smsc_ircc_driver);
 }
 
 /*
@@ -1763,34 +1762,34 @@ void smsc_ircc_sir_start(struct smsc_ircc_cb *self)
 
        IRDA_DEBUG(3, "%s\n", __FUNCTION__);
 
-       IRDA_ASSERT(self != NULL, return;);     
-       dev= self->netdev;
-       IRDA_ASSERT(dev != NULL, return;);              
+       IRDA_ASSERT(self != NULL, return;);
+       dev = self->netdev;
+       IRDA_ASSERT(dev != NULL, return;);
        dev->hard_start_xmit = &smsc_ircc_hard_xmit_sir;
 
        fir_base = self->io.fir_base;
        sir_base = self->io.sir_base;
 
        /* Reset everything */
-       outb(IRCC_MASTER_RESET, fir_base+IRCC_MASTER);
+       outb(IRCC_MASTER_RESET, fir_base + IRCC_MASTER);
 
        #if SMSC_IRCC2_C_SIR_STOP
        /*smsc_ircc_sir_stop(self);*/
        #endif
 
        register_bank(fir_base, 1);
-       outb(((inb(fir_base+IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | IRCC_CFGA_IRDA_SIR_A), fir_base+IRCC_SCE_CFGA);
+       outb(((inb(fir_base + IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | IRCC_CFGA_IRDA_SIR_A), fir_base + IRCC_SCE_CFGA);
 
        /* Initialize UART */
-       outb(UART_LCR_WLEN8, sir_base+UART_LCR);  /* Reset DLAB */
-       outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), sir_base+UART_MCR);
-       
+       outb(UART_LCR_WLEN8, sir_base + UART_LCR);  /* Reset DLAB */
+       outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), sir_base + UART_MCR);
+
        /* Turn on interrups */
-       outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, sir_base+UART_IER);
+       outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, sir_base + UART_IER);
 
        IRDA_DEBUG(3, "%s() - exit\n", __FUNCTION__);
 
-       outb(0x00, fir_base+IRCC_MASTER);
+       outb(0x00, fir_base + IRCC_MASTER);
 }
 
 #if SMSC_IRCC2_C_SIR_STOP
@@ -1802,10 +1801,10 @@ void smsc_ircc_sir_stop(struct smsc_ircc_cb *self)
        iobase = self->io.sir_base;
 
        /* Reset UART */
-       outb(0, iobase+UART_MCR);
-       
+       outb(0, iobase + UART_MCR);
+
        /* Turn off interrupts */
-       outb(0, iobase+UART_IER);
+       outb(0, iobase + UART_IER);
 }
 #endif
 
@@ -1831,16 +1830,16 @@ static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self)
        /* Finished with frame?  */
        if (self->tx_buff.len > 0)  {
                /* Write data left in transmit buffer */
-               actual = smsc_ircc_sir_write(iobase, self->io.fifo_size, 
+               actual = smsc_ircc_sir_write(iobase, self->io.fifo_size,
                                      self->tx_buff.data, self->tx_buff.len);
                self->tx_buff.data += actual;
                self->tx_buff.len  -= actual;
        } else {
-       
+
        /*if (self->tx_buff.len ==0)  {*/
-               
-               /* 
-                *  Now serial buffer is almost free & we can start 
+
+               /*
+                *  Now serial buffer is almost free & we can start
                 *  transmission of another packet. But first we must check
                 *  if we need to change the speed of the hardware
                 */
@@ -1856,21 +1855,19 @@ static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self)
                }
                self->stats.tx_packets++;
 
-               if(self->io.speed <= 115200) {
-               /* 
-                * Reset Rx FIFO to make sure that all reflected transmit data
-                * is discarded. This is needed for half duplex operation
-                */
-               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR;
-               if (self->io.speed < 38400)
-                       fcr |= UART_FCR_TRIGGER_1;
-               else 
-                       fcr |= UART_FCR_TRIGGER_14;
+               if (self->io.speed <= 115200) {
+                       /*
+                        * Reset Rx FIFO to make sure that all reflected transmit data
+                        * is discarded. This is needed for half duplex operation
+                        */
+                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR;
+                       fcr |= self->io.speed < 38400 ?
+                                       UART_FCR_TRIGGER_1 : UART_FCR_TRIGGER_14;
 
-               outb(fcr, iobase+UART_FCR);
+                       outb(fcr, iobase + UART_FCR);
 
-               /* Turn on receive interrupts */
-               outb(UART_IER_RDI, iobase+UART_IER);
+                       /* Turn on receive interrupts */
+                       outb(UART_IER_RDI, iobase + UART_IER);
                }
        }
 }
@@ -1884,17 +1881,17 @@ static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self)
 static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len)
 {
        int actual = 0;
-       
+
        /* Tx FIFO should be empty! */
-       if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
+       if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) {
                IRDA_WARNING("%s(), failed, fifo not empty!\n", __FUNCTION__);
                return 0;
        }
-        
+
        /* Fill FIFO with current frame */
-       while ((fifo_size-- > 0) && (actual < len)) {
+       while (fifo_size-- > 0 && actual < len) {
                /* Transmit next byte */
-               outb(buf[actual], iobase+UART_TX);
+               outb(buf[actual], iobase + UART_TX);
                actual++;
        }
        return actual;
@@ -1921,20 +1918,21 @@ static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self)
 static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self)
 {
        unsigned int    i;
-       
+
        IRDA_ASSERT(self != NULL, return;);
-       
-       for(i=0; smsc_transceivers[i].name!=NULL; i++) 
-               if((*smsc_transceivers[i].probe)(self->io.fir_base)) {
+
+       for (i = 0; smsc_transceivers[i].name != NULL; i++)
+               if (smsc_transceivers[i].probe(self->io.fir_base)) {
                        IRDA_MESSAGE(" %s transceiver found\n",
                                     smsc_transceivers[i].name);
-                       self->transceiver= i+1;
+                       self->transceiver= i + 1;
                        return;
                }
+
        IRDA_MESSAGE("No transceiver found. Defaulting to %s\n",
                     smsc_transceivers[SMSC_IRCC2_C_DEFAULT_TRANSCEIVER].name);
-                       
-       self->transceiver= SMSC_IRCC2_C_DEFAULT_TRANSCEIVER;
+
+       self->transceiver = SMSC_IRCC2_C_DEFAULT_TRANSCEIVER;
 }
 
 
@@ -1947,9 +1945,10 @@ static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self)
 static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed)
 {
        unsigned int trx;
-       
+
        trx = self->transceiver;
-       if(trx>0) (*smsc_transceivers[trx-1].set_for_speed)(self->io.fir_base, speed);
+       if (trx > 0)
+               smsc_transceivers[trx - 1].set_for_speed(self->io.fir_base, speed);
 }
 
 /*
@@ -1977,16 +1976,14 @@ static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 s
 
 static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self)
 {
-       int iobase;
+       int iobase = self->io.sir_base;
        int count = SMSC_IRCC2_HW_TRANSMITTER_TIMEOUT_US;
-       
-       iobase = self->io.sir_base;
-       
+
        /* Calibrated busy loop */
-       while((count-- > 0) && !(inb(iobase+UART_LSR) & UART_LSR_TEMT))
+       while (count-- > 0 && !(inb(iobase + UART_LSR) & UART_LSR_TEMT))
                udelay(1);
 
-       if(count == 0)
+       if (count == 0)
                IRDA_DEBUG(0, "%s(): stuck transmitter\n", __FUNCTION__);
 }
 
@@ -1998,40 +1995,42 @@ static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self)
 
 static int __init smsc_ircc_look_for_chips(void)
 {
-       smsc_chip_address_t *address;
-       char    *type;
+       struct smsc_chip_address *address;
+       char *type;
        unsigned int cfg_base, found;
-       
+
        found = 0;
        address = possible_addresses;
-       
-       while(address->cfg_base){
+
+       while (address->cfg_base) {
                cfg_base = address->cfg_base;
-               
+
                /*printk(KERN_WARNING "%s(): probing: 0x%02x for: 0x%02x\n", __FUNCTION__, cfg_base, address->type);*/
-               
-               if( address->type & SMSCSIO_TYPE_FDC){
+
+               if (address->type & SMSCSIO_TYPE_FDC) {
                        type = "FDC";
-                       if((address->type) & SMSCSIO_TYPE_FLAT) {
-                               if(!smsc_superio_flat(fdc_chips_flat,cfg_base, type)) found++;
-                       }
-                       if((address->type) & SMSCSIO_TYPE_PAGED) {
-                               if(!smsc_superio_paged(fdc_chips_paged,cfg_base, type)) found++;                
-                       }                       
+                       if (address->type & SMSCSIO_TYPE_FLAT)
+                               if (!smsc_superio_flat(fdc_chips_flat, cfg_base, type))
+                                       found++;
+
+                       if (address->type & SMSCSIO_TYPE_PAGED)
+                               if (!smsc_superio_paged(fdc_chips_paged, cfg_base, type))
+                                       found++;
                }
-               if( address->type & SMSCSIO_TYPE_LPC){
+               if (address->type & SMSCSIO_TYPE_LPC) {
                        type = "LPC";
-                       if((address->type) & SMSCSIO_TYPE_FLAT) {
-                               if(!smsc_superio_flat(lpc_chips_flat,cfg_base,type)) found++;
-                       }
-                       if((address->type) & SMSCSIO_TYPE_PAGED) {
-                               if(!smsc_superio_paged(lpc_chips_paged,cfg_base,"LPC")) found++;                
-                       }                       
+                       if (address->type & SMSCSIO_TYPE_FLAT)
+                               if (!smsc_superio_flat(lpc_chips_flat, cfg_base, type))
+                                       found++;
+
+                       if (address->type & SMSCSIO_TYPE_PAGED)
+                               if (!smsc_superio_paged(lpc_chips_paged, cfg_base, type))
+                                       found++;
                }
                address++;
        }
        return found;
-} 
+}
 
 /*
  * Function smsc_superio_flat (chip, base, type)
@@ -2039,7 +2038,7 @@ static int __init smsc_ircc_look_for_chips(void)
  *    Try to get configuration of a smc SuperIO chip with flat register model
  *
  */
-static int __init smsc_superio_flat(const smsc_chip_t *chips, unsigned short cfgbase, char *type)
+static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfgbase, char *type)
 {
        unsigned short firbase, sirbase;
        u8 mode, dma, irq;
@@ -2047,39 +2046,37 @@ static int __init smsc_superio_flat(const smsc_chip_t *chips, unsigned short cfg
 
        IRDA_DEBUG(1, "%s\n", __FUNCTION__);
 
-       if (smsc_ircc_probe(cfgbase, SMSCSIOFLAT_DEVICEID_REG, chips, type)==NULL)
+       if (smsc_ircc_probe(cfgbase, SMSCSIOFLAT_DEVICEID_REG, chips, type) == NULL)
                return ret;
 
        outb(SMSCSIOFLAT_UARTMODE0C_REG, cfgbase);
-       mode = inb(cfgbase+1);
-       
+       mode = inb(cfgbase + 1);
+
        /*printk(KERN_WARNING "%s(): mode: 0x%02x\n", __FUNCTION__, mode);*/
-       
-       if(!(mode & SMSCSIOFLAT_UART2MODE_VAL_IRDA))
+
+       if (!(mode & SMSCSIOFLAT_UART2MODE_VAL_IRDA))
                IRDA_WARNING("%s(): IrDA not enabled\n", __FUNCTION__);
 
        outb(SMSCSIOFLAT_UART2BASEADDR_REG, cfgbase);
-       sirbase = inb(cfgbase+1) << 2;
+       sirbase = inb(cfgbase + 1) << 2;
 
-       /* FIR iobase */
+       /* FIR iobase */
        outb(SMSCSIOFLAT_FIRBASEADDR_REG, cfgbase);
-       firbase = inb(cfgbase+1) << 3;
+       firbase = inb(cfgbase + 1) << 3;
 
        /* DMA */
        outb(SMSCSIOFLAT_FIRDMASELECT_REG, cfgbase);
-       dma = inb(cfgbase+1) & SMSCSIOFLAT_FIRDMASELECT_MASK;
-       
+       dma = inb(cfgbase + 1) & SMSCSIOFLAT_FIRDMASELECT_MASK;
+
        /* IRQ */
        outb(SMSCSIOFLAT_UARTIRQSELECT_REG, cfgbase);
-       irq = inb(cfgbase+1) & SMSCSIOFLAT_UART2IRQSELECT_MASK;
+       irq = inb(cfgbase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK;
 
        IRDA_MESSAGE("%s(): fir: 0x%02x, sir: 0x%02x, dma: %02d, irq: %d, mode: 0x%02x\n", __FUNCTION__, firbase, sirbase, dma, irq, mode);
 
-       if (firbase) {
-               if (smsc_ircc_open(firbase, sirbase, dma, irq) == 0)
-                       ret=0; 
-       }
-       
+       if (firbase && smsc_ircc_open(firbase, sirbase, dma, irq) == 0)
+               ret = 0;
+
        /* Exit configuration */
        outb(SMSCSIO_CFGEXITKEY, cfgbase);
 
@@ -2092,26 +2089,26 @@ static int __init smsc_superio_flat(const smsc_chip_t *chips, unsigned short cfg
  *    Try  to get configuration of a smc SuperIO chip with paged register model
  *
  */
-static int __init smsc_superio_paged(const smsc_chip_t *chips, unsigned short cfg_base, char *type)
+static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type)
 {
        unsigned short fir_io, sir_io;
        int ret = -ENODEV;
-       
+
        IRDA_DEBUG(1, "%s\n", __FUNCTION__);
 
-       if (smsc_ircc_probe(cfg_base,0x20,chips,type)==NULL)
+       if (smsc_ircc_probe(cfg_base, 0x20, chips, type) == NULL)
                return ret;
-       
+
        /* Select logical device (UART2) */
        outb(0x07, cfg_base);
        outb(0x05, cfg_base + 1);
-               
+
        /* SIR iobase */
        outb(0x60, cfg_base);
-       sir_io  = inb(cfg_base + 1) << 8;
+       sir_io = inb(cfg_base + 1) << 8;
        outb(0x61, cfg_base);
        sir_io |= inb(cfg_base + 1);
-               
+
        /* Read FIR base */
        outb(0x62, cfg_base);
        fir_io = inb(cfg_base + 1) << 8;
@@ -2119,11 +2116,9 @@ static int __init smsc_superio_paged(const smsc_chip_t *chips, unsigned short cf
        fir_io |= inb(cfg_base + 1);
        outb(0x2b, cfg_base); /* ??? */
 
-       if (fir_io) {
-               if (smsc_ircc_open(fir_io, sir_io, ircc_dma, ircc_irq) == 0)
-                       ret=0; 
-       }
-       
+       if (fir_io && smsc_ircc_open(fir_io, sir_io, ircc_dma, ircc_irq) == 0)
+               ret = 0;
+
        /* Exit configuration */
        outb(SMSCSIO_CFGEXITKEY, cfg_base);
 
@@ -2131,21 +2126,17 @@ static int __init smsc_superio_paged(const smsc_chip_t *chips, unsigned short cf
 }
 
 
-static int __init smsc_access(unsigned short cfg_base,unsigned char reg)
+static int __init smsc_access(unsigned short cfg_base, unsigned char reg)
 {
        IRDA_DEBUG(1, "%s\n", __FUNCTION__);
 
        outb(reg, cfg_base);
-
-       if (inb(cfg_base)!=reg)
-               return -1;
-
-       return 0;
+       return inb(cfg_base) != reg ? -1 : 0;
 }
 
-static const smsc_chip_t * __init smsc_ircc_probe(unsigned short cfg_base,u8 reg,const smsc_chip_t *chip,char *type)
+static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type)
 {
-       u8 devid,xdevid,rev; 
+       u8 devid, xdevid, rev;
 
        IRDA_DEBUG(1, "%s\n", __FUNCTION__);
 
@@ -2158,7 +2149,7 @@ static const smsc_chip_t * __init smsc_ircc_probe(unsigned short cfg_base,u8 reg
 
        outb(reg, cfg_base);
 
-       xdevid=inb(cfg_base+1);
+       xdevid = inb(cfg_base + 1);
 
        /* Enter configuration */
 
@@ -2168,51 +2159,49 @@ static const smsc_chip_t * __init smsc_ircc_probe(unsigned short cfg_base,u8 reg
        if (smsc_access(cfg_base,0x55)) /* send second key and check */
                return NULL;
        #endif
-       
+
        /* probe device ID */
 
-       if (smsc_access(cfg_base,reg))
+       if (smsc_access(cfg_base, reg))
                return NULL;
 
-       devid=inb(cfg_base+1);
-       
-       if (devid==0)                   /* typical value for unused port */
-               return NULL;
+       devid = inb(cfg_base + 1);
 
-       if (devid==0xff)                /* typical value for unused port */
+       if (devid == 0 || devid == 0xff)        /* typical values for unused port */
                return NULL;
 
        /* probe revision ID */
 
-       if (smsc_access(cfg_base,reg+1))
+       if (smsc_access(cfg_base, reg + 1))
                return NULL;
 
-       rev=inb(cfg_base+1);
+       rev = inb(cfg_base + 1);
 
-       if (rev>=128)                   /* i think this will make no sense */
+       if (rev >= 128)                 /* i think this will make no sense */
                return NULL;
 
-       if (devid==xdevid)              /* protection against false positives */        
+       if (devid == xdevid)            /* protection against false positives */
                return NULL;
 
        /* Check for expected device ID; are there others? */
 
-       while(chip->devid!=devid) {
+       while (chip->devid != devid) {
 
                chip++;
 
-               if (chip->name==NULL)
+               if (chip->name == NULL)
                        return NULL;
        }
 
-       IRDA_MESSAGE("found SMC SuperIO Chip (devid=0x%02x rev=%02X base=0x%04x): %s%s\n",devid,rev,cfg_base,type,chip->name);
+       IRDA_MESSAGE("found SMC SuperIO Chip (devid=0x%02x rev=%02X base=0x%04x): %s%s\n",
+                    devid, rev, cfg_base, type, chip->name);
 
-       if (chip->rev>rev){
-               IRDA_MESSAGE("Revision higher than expected\n");        
+       if (chip->rev > rev) {
+               IRDA_MESSAGE("Revision higher than expected\n");
                return NULL;
        }
-       
-       if (chip->flags&NoIRDA)
+
+       if (chip->flags & NoIRDA)
                IRDA_MESSAGE("chipset does not support IRDA\n");
 
        return chip;
@@ -2226,8 +2215,8 @@ static int __init smsc_superio_fdc(unsigned short cfg_base)
                IRDA_WARNING("%s: can't get cfg_base of 0x%03x\n",
                             __FUNCTION__, cfg_base);
        } else {
-               if (!smsc_superio_flat(fdc_chips_flat,cfg_base,"FDC")
-                   ||!smsc_superio_paged(fdc_chips_paged,cfg_base,"FDC"))
+               if (!smsc_superio_flat(fdc_chips_flat, cfg_base, "FDC") ||
+                   !smsc_superio_paged(fdc_chips_paged, cfg_base, "FDC"))
                        ret =  0;
 
                release_region(cfg_base, 2);
@@ -2244,9 +2233,10 @@ static int __init smsc_superio_lpc(unsigned short cfg_base)
                IRDA_WARNING("%s: can't get cfg_base of 0x%03x\n",
                             __FUNCTION__, cfg_base);
        } else {
-               if (!smsc_superio_flat(lpc_chips_flat,cfg_base,"LPC")
-                   ||!smsc_superio_paged(lpc_chips_paged,cfg_base,"LPC"))
+               if (!smsc_superio_flat(lpc_chips_flat, cfg_base, "LPC") ||
+                   !smsc_superio_paged(lpc_chips_paged, cfg_base, "LPC"))
                        ret = 0;
+
                release_region(cfg_base, 2);
        }
        return ret;
@@ -2269,18 +2259,23 @@ static int __init smsc_superio_lpc(unsigned short cfg_base)
 static void smsc_ircc_set_transceiver_smsc_ircc_atc(int fir_base, u32 speed)
 {
        unsigned long jiffies_now, jiffies_timeout;
-       u8      val;
-       
-       jiffies_now= jiffies;
-       jiffies_timeout= jiffies+SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES;
-       
+       u8 val;
+
+       jiffies_now = jiffies;
+       jiffies_timeout = jiffies + SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES;
+
        /* ATC */
        register_bank(fir_base, 4);
-       outb((inb(fir_base+IRCC_ATC) & IRCC_ATC_MASK) |IRCC_ATC_nPROGREADY|IRCC_ATC_ENABLE, fir_base+IRCC_ATC);
-       while((val=(inb(fir_base+IRCC_ATC) & IRCC_ATC_nPROGREADY)) && !time_after(jiffies, jiffies_timeout));
-       if(val)
+       outb((inb(fir_base + IRCC_ATC) & IRCC_ATC_MASK) | IRCC_ATC_nPROGREADY|IRCC_ATC_ENABLE,
+            fir_base + IRCC_ATC);
+
+       while ((val = (inb(fir_base + IRCC_ATC) & IRCC_ATC_nPROGREADY)) &&
+               !time_after(jiffies, jiffies_timeout))
+               /* empty */;
+
+       if (val)
                IRDA_WARNING("%s(): ATC: 0x%02x\n", __FUNCTION__,
-                            inb(fir_base+IRCC_ATC));
+                            inb(fir_base + IRCC_ATC));
 }
 
 /*
@@ -2298,34 +2293,32 @@ static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base)
 /*
  * Function smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(self, speed)
  *
- *    Set transceiver 
+ *    Set transceiver
  *
  */
 
 static void smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(int fir_base, u32 speed)
 {
-       u8      fast_mode;
-       
-       switch(speed)
-       {
-               default:
-               case 576000 :
-               fast_mode = 0; 
+       u8 fast_mode;
+
+       switch (speed) {
+       default:
+       case 576000 :
+               fast_mode = 0;
                break;
-               case 1152000 :
-               case 4000000 :
+       case 1152000 :
+       case 4000000 :
                fast_mode = IRCC_LCR_A_FAST;
                break;
-               
        }
        register_bank(fir_base, 0);
-       outb((inb(fir_base+IRCC_LCR_A) &  0xbf) | fast_mode, fir_base+IRCC_LCR_A);
+       outb((inb(fir_base + IRCC_LCR_A) & 0xbf) | fast_mode, fir_base + IRCC_LCR_A);
 }
 
 /*
  * Function smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(fir_base)
  *
- *    Probe transceiver 
+ *    Probe transceiver
  *
  */
 
@@ -2337,35 +2330,34 @@ static int smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(int fir_base)
 /*
  * Function smsc_ircc_set_transceiver_toshiba_sat1800(fir_base, speed)
  *
- *    Set transceiver 
+ *    Set transceiver
  *
  */
 
 static void smsc_ircc_set_transceiver_toshiba_sat1800(int fir_base, u32 speed)
 {
-       u8      fast_mode;
-       
-       switch(speed)
-       {
-               default:
-               case 576000 :
-               fast_mode = 0; 
+       u8 fast_mode;
+
+       switch (speed) {
+       default:
+       case 576000 :
+               fast_mode = 0;
                break;
-               case 1152000 :
-               case 4000000 :
+       case 1152000 :
+       case 4000000 :
                fast_mode = /*IRCC_LCR_A_FAST |*/ IRCC_LCR_A_GP_DATA;
                break;
-               
+
        }
        /* This causes an interrupt */
        register_bank(fir_base, 0);
-       outb((inb(fir_base+IRCC_LCR_A) &  0xbf) | fast_mode, fir_base+IRCC_LCR_A);
+       outb((inb(fir_base + IRCC_LCR_A) &  0xbf) | fast_mode, fir_base + IRCC_LCR_A);
 }
 
 /*
  * Function smsc_ircc_probe_transceiver_toshiba_sat1800(fir_base)
  *
- *    Probe transceiver 
+ *    Probe transceiver
  *
  */
 
@@ -2377,20 +2369,3 @@ static int smsc_ircc_probe_transceiver_toshiba_sat1800(int fir_base)
 
 module_init(smsc_ircc_init);
 module_exit(smsc_ircc_cleanup);
-
-MODULE_AUTHOR("Daniele Peri <peri@csai.unipa.it>");
-MODULE_DESCRIPTION("SMC IrCC SIR/FIR controller driver");
-MODULE_LICENSE("GPL");
-
-module_param(ircc_dma, int, 0);
-MODULE_PARM_DESC(ircc_dma, "DMA channel");
-module_param(ircc_irq, int, 0);
-MODULE_PARM_DESC(ircc_irq, "IRQ line");
-module_param(ircc_fir, int, 0);
-MODULE_PARM_DESC(ircc_fir, "FIR Base Address");
-module_param(ircc_sir, int, 0);
-MODULE_PARM_DESC(ircc_sir, "SIR Base Address");
-module_param(ircc_cfg, int, 0);
-MODULE_PARM_DESC(ircc_cfg, "Configuration register base address");
-module_param(ircc_transceiver, int, 0);
-MODULE_PARM_DESC(ircc_transceiver, "Transceiver type");
index 458611cc0d40c8d027a8e3aacf2701e34854dd65..0c36286d87f7022f3530b0f13bfa9d0b37ae46ef 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************************
- * $Id: smsc-ircc2.h,v 1.12.2.1 2002/10/27 10:52:37 dip Exp $               
+ * $Id: smsc-ircc2.h,v 1.12.2.1 2002/10/27 10:52:37 dip Exp $
  *
  * Description:   Definitions for the SMC IrCC chipset
  * Status:        Experimental.
@@ -9,25 +9,25 @@
  *     All Rights Reserved.
  *
  * Based on smc-ircc.h:
- * 
+ *
  *     Copyright (c) 1999-2000, Dag Brattli <dagb@cs.uit.no>
  *     Copyright (c) 1998-1999, Thomas Davis (tadavis@jps.net>
  *     All Rights Reserved
  *
- *      
- *     This program is free software; you can redistribute it and/or 
- *     modify it under the terms of the GNU General Public License as 
- *     published by the Free Software Foundation; either version 2 of 
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
  *     the License, or (at your option) any later version.
- * 
+ *
  *     This program is distributed in the hope that it will be useful,
  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  *     GNU General Public License for more details.
- * 
- *     You should have received a copy of the GNU General Public License 
- *     along with this program; if not, write to the Free Software 
- *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  *     MA 02111-1307 USA
  *
  ********************************************************************/
 
 #define   IRCC_CFGA_COM                                0x00
 #define                IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK      0x87
-#define        IRCC_CFGA_IRDA_SIR_A    0x08
-#define        IRCC_CFGA_ASK_SIR               0x10
-#define        IRCC_CFGA_IRDA_SIR_B    0x18
-#define        IRCC_CFGA_IRDA_HDLC             0x20
+#define                IRCC_CFGA_IRDA_SIR_A    0x08
+#define                IRCC_CFGA_ASK_SIR               0x10
+#define                IRCC_CFGA_IRDA_SIR_B    0x18
+#define                IRCC_CFGA_IRDA_HDLC             0x20
 #define                IRCC_CFGA_IRDA_4PPM             0x28
 #define                IRCC_CFGA_CONSUMER              0x30
 #define                IRCC_CFGA_RAW_IR                0x38
 #define IRCC_CFGB_LPBCK_TX_CRC    0x10
 #define IRCC_CFGB_NOWAIT          0x08
 #define IRCC_CFGB_STRING_MOVE     0x04
-#define IRCC_CFGB_DMA_BURST       0x02
+#define IRCC_CFGB_DMA_BURST       0x02
 #define IRCC_CFGB_DMA_ENABLE      0x01
 
 #define IRCC_CFGB_MUX_COM          0x00
 /* Register block 3 - Identification Registers! */
 #define IRCC_ID_HIGH              0x00   /* 0x10 */
 #define IRCC_ID_LOW               0x01   /* 0xB8 */
-#define IRCC_CHIP_ID              0x02   /* 0xF1 */
+#define IRCC_CHIP_ID              0x02   /* 0xF1 */
 #define IRCC_VERSION              0x03   /* 0x01 */
 #define IRCC_INTERFACE            0x04   /* low 4 = DMA, high 4 = IRQ */
-#define        IRCC_INTERFACE_DMA_MASK 0x0F   /* low 4 = DMA, high 4 = IRQ */
-#define        IRCC_INTERFACE_IRQ_MASK 0xF0   /* low 4 = DMA, high 4 = IRQ */
+#define                IRCC_INTERFACE_DMA_MASK 0x0F   /* low 4 = DMA, high 4 = IRQ */
+#define                IRCC_INTERFACE_IRQ_MASK 0xF0   /* low 4 = DMA, high 4 = IRQ */
 
 /* Register block 4 - IrDA */
 #define IRCC_CONTROL               0x00
 
 /* Register block 5 - IrDA */
 #define IRCC_ATC                                       0x00
-#define        IRCC_ATC_nPROGREADY             0x80
-#define        IRCC_ATC_SPEED                  0x40
-#define        IRCC_ATC_ENABLE                 0x20
-#define        IRCC_ATC_MASK                   0xE0
+#define                IRCC_ATC_nPROGREADY             0x80
+#define                IRCC_ATC_SPEED                  0x40
+#define                IRCC_ATC_ENABLE                 0x20
+#define                IRCC_ATC_MASK                   0xE0
 
 
 #define IRCC_IRHALFDUPLEX_TIMEOUT      0x01
  */
 
 #define SMSC_IRCC2_MAX_SIR_SPEED               115200
-#define SMSC_IRCC2_FIR_CHIP_IO_EXTENT  8
-#define SMSC_IRCC2_SIR_CHIP_IO_EXTENT  8
+#define SMSC_IRCC2_FIR_CHIP_IO_EXTENT  8
+#define SMSC_IRCC2_SIR_CHIP_IO_EXTENT  8
 #define SMSC_IRCC2_FIFO_SIZE                   16
 #define SMSC_IRCC2_FIFO_THRESHOLD              64
 /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
index 006e4f57560675bb48a19b62fa6ec54fd0158337..6d9de626c9670db8e0f4d436cfbfda6913fd6ceb 100644 (file)
@@ -1749,11 +1749,6 @@ static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state)
        struct net_device *ndev = pci_get_drvdata(pdev);
        vlsi_irda_dev_t *idev;
 
-       if (state < 1 || state > 3 ) {
-               IRDA_ERROR("%s - %s: invalid pm state request: %u\n",
-                          __FUNCTION__, PCIDEV_NAME(pdev), state);
-               return 0;
-       }
        if (!ndev) {
                IRDA_ERROR("%s - %s: no netdevice \n",
                           __FUNCTION__, PCIDEV_NAME(pdev));
@@ -1762,12 +1757,12 @@ static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state)
        idev = ndev->priv;      
        down(&idev->sem);
        if (pdev->current_state != 0) {                 /* already suspended */
-               if (state > pdev->current_state) {      /* simply go deeper */
-                       pci_set_power_state(pdev,state);
-                       pdev->current_state = state;
+               if (state.event > pdev->current_state) {        /* simply go deeper */
+                       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+                       pdev->current_state = state.event;
                }
                else
-                       IRDA_ERROR("%s - %s: invalid suspend request %u -> %u\n", __FUNCTION__, PCIDEV_NAME(pdev), pdev->current_state, state);
+                       IRDA_ERROR("%s - %s: invalid suspend request %u -> %u\n", __FUNCTION__, PCIDEV_NAME(pdev), pdev->current_state, state.event);
                up(&idev->sem);
                return 0;
        }
@@ -1781,8 +1776,8 @@ static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state)
                        idev->new_baud = idev->baud;
        }
 
-       pci_set_power_state(pdev,state);
-       pdev->current_state = state;
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+       pdev->current_state = state.event;
        idev->resume_ok = 1;
        up(&idev->sem);
        return 0;
@@ -1807,8 +1802,8 @@ static int vlsi_irda_resume(struct pci_dev *pdev)
                return 0;
        }
        
-       pci_set_power_state(pdev, 0);
-       pdev->current_state = 0;
+       pci_set_power_state(pdev, PCI_D0);
+       pdev->current_state = PM_EVENT_ON;
 
        if (!idev->resume_ok) {
                /* should be obsolete now - but used to happen due to:
index 55af32e9bf082ad7f8d88b96b2e068eb0e35304f..3d56cf5a4e23964e8a960dfc8e53583e580abeec 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 2001 Kyle A. Lucke (klucke@us.ibm.com), IBM Corp.
  * Substantially cleaned up by:
  * Copyright (C) 2003 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
+ * Copyright (C) 2004-2005 Michael Ellerman, IBM Corporation.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
 #include <asm/iommu.h>
 #include <asm/vio.h>
 
-#include "iseries_veth.h"
+#undef DEBUG
 
 MODULE_AUTHOR("Kyle Lucke <klucke@us.ibm.com>");
 MODULE_DESCRIPTION("iSeries Virtual ethernet driver");
 MODULE_LICENSE("GPL");
 
+#define VETH_EVENT_CAP (0)
+#define VETH_EVENT_FRAMES      (1)
+#define VETH_EVENT_MONITOR     (2)
+#define VETH_EVENT_FRAMES_ACK  (3)
+
+#define VETH_MAX_ACKS_PER_MSG  (20)
+#define VETH_MAX_FRAMES_PER_MSG        (6)
+
+struct veth_frames_data {
+       u32 addr[VETH_MAX_FRAMES_PER_MSG];
+       u16 len[VETH_MAX_FRAMES_PER_MSG];
+       u32 eofmask;
+};
+#define VETH_EOF_SHIFT         (32-VETH_MAX_FRAMES_PER_MSG)
+
+struct veth_frames_ack_data {
+       u16 token[VETH_MAX_ACKS_PER_MSG];
+};
+
+struct veth_cap_data {
+       u8 caps_version;
+       u8 rsvd1;
+       u16 num_buffers;
+       u16 ack_threshold;
+       u16 rsvd2;
+       u32 ack_timeout;
+       u32 rsvd3;
+       u64 rsvd4[3];
+};
+
+struct veth_lpevent {
+       struct HvLpEvent base_event;
+       union {
+               struct veth_cap_data caps_data;
+               struct veth_frames_data frames_data;
+               struct veth_frames_ack_data frames_ack_data;
+       } u;
+
+};
+
+#define DRV_NAME       "iseries_veth"
+#define DRV_VERSION    "2.0"
+
 #define VETH_NUMBUFFERS                (120)
 #define VETH_ACKTIMEOUT        (1000000) /* microseconds */
 #define VETH_MAX_MCAST         (12)
@@ -113,9 +157,9 @@ MODULE_LICENSE("GPL");
 
 struct veth_msg {
        struct veth_msg *next;
-       struct VethFramesData data;
+       struct veth_frames_data data;
        int token;
-       unsigned long in_use;
+       int in_use;
        struct sk_buff *skb;
        struct device *dev;
 };
@@ -125,23 +169,28 @@ struct veth_lpar_connection {
        struct work_struct statemachine_wq;
        struct veth_msg *msgs;
        int num_events;
-       struct VethCapData local_caps;
+       struct veth_cap_data local_caps;
 
+       struct kobject kobject;
        struct timer_list ack_timer;
 
+       struct timer_list reset_timer;
+       unsigned int reset_timeout;
+       unsigned long last_contact;
+       int outstanding_tx;
+
        spinlock_t lock;
        unsigned long state;
        HvLpInstanceId src_inst;
        HvLpInstanceId dst_inst;
-       struct VethLpEvent cap_event, cap_ack_event;
+       struct veth_lpevent cap_event, cap_ack_event;
        u16 pending_acks[VETH_MAX_ACKS_PER_MSG];
        u32 num_pending_acks;
 
        int num_ack_events;
-       struct VethCapData remote_caps;
+       struct veth_cap_data remote_caps;
        u32 ack_timeout;
 
-       spinlock_t msg_stack_lock;
        struct veth_msg *msg_stack_head;
 };
 
@@ -151,15 +200,17 @@ struct veth_port {
        u64 mac_addr;
        HvLpIndexMap lpar_map;
 
-       spinlock_t pending_gate;
-       struct sk_buff *pending_skb;
-       HvLpIndexMap pending_lpmask;
+       /* queue_lock protects the stopped_map and dev's queue. */
+       spinlock_t queue_lock;
+       HvLpIndexMap stopped_map;
 
+       /* mcast_gate protects promiscuous, num_mcast & mcast_addr. */
        rwlock_t mcast_gate;
        int promiscuous;
-       int all_mcast;
        int num_mcast;
        u64 mcast_addr[VETH_MAX_MCAST];
+
+       struct kobject kobject;
 };
 
 static HvLpIndex this_lp;
@@ -168,44 +219,56 @@ static struct net_device *veth_dev[HVMAXARCHITECTEDVIRTUALLANS]; /* = 0 */
 
 static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static void veth_recycle_msg(struct veth_lpar_connection *, struct veth_msg *);
-static void veth_flush_pending(struct veth_lpar_connection *cnx);
-static void veth_receive(struct veth_lpar_connection *, struct VethLpEvent *);
-static void veth_timed_ack(unsigned long connectionPtr);
+static void veth_wake_queues(struct veth_lpar_connection *cnx);
+static void veth_stop_queues(struct veth_lpar_connection *cnx);
+static void veth_receive(struct veth_lpar_connection *, struct veth_lpevent *);
+static void veth_release_connection(struct kobject *kobject);
+static void veth_timed_ack(unsigned long ptr);
+static void veth_timed_reset(unsigned long ptr);
 
 /*
  * Utility functions
  */
 
-#define veth_printk(prio, fmt, args...) \
-       printk(prio "%s: " fmt, __FILE__, ## args)
+#define veth_info(fmt, args...) \
+       printk(KERN_INFO DRV_NAME ": " fmt, ## args)
 
 #define veth_error(fmt, args...) \
-       printk(KERN_ERR "(%s:%3.3d) ERROR: " fmt, __FILE__, __LINE__ , ## args)
+       printk(KERN_ERR DRV_NAME ": Error: " fmt, ## args)
+
+#ifdef DEBUG
+#define veth_debug(fmt, args...) \
+       printk(KERN_DEBUG DRV_NAME ": " fmt, ## args)
+#else
+#define veth_debug(fmt, args...) do {} while (0)
+#endif
 
+/* You must hold the connection's lock when you call this function. */
 static inline void veth_stack_push(struct veth_lpar_connection *cnx,
                                   struct veth_msg *msg)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&cnx->msg_stack_lock, flags);
        msg->next = cnx->msg_stack_head;
        cnx->msg_stack_head = msg;
-       spin_unlock_irqrestore(&cnx->msg_stack_lock, flags);
 }
 
+/* You must hold the connection's lock when you call this function. */
 static inline struct veth_msg *veth_stack_pop(struct veth_lpar_connection *cnx)
 {
-       unsigned long flags;
        struct veth_msg *msg;
 
-       spin_lock_irqsave(&cnx->msg_stack_lock, flags);
        msg = cnx->msg_stack_head;
        if (msg)
                cnx->msg_stack_head = cnx->msg_stack_head->next;
-       spin_unlock_irqrestore(&cnx->msg_stack_lock, flags);
+
        return msg;
 }
 
+/* You must hold the connection's lock when you call this function. */
+static inline int veth_stack_is_empty(struct veth_lpar_connection *cnx)
+{
+       return cnx->msg_stack_head == NULL;
+}
+
 static inline HvLpEvent_Rc
 veth_signalevent(struct veth_lpar_connection *cnx, u16 subtype,
                 HvLpEvent_AckInd ackind, HvLpEvent_AckType acktype,
@@ -249,13 +312,144 @@ static int veth_allocate_events(HvLpIndex rlp, int number)
        struct veth_allocation vc = { COMPLETION_INITIALIZER(vc.c), 0 };
 
        mf_allocate_lp_events(rlp, HvLpEvent_Type_VirtualLan,
-                           sizeof(struct VethLpEvent), number,
+                           sizeof(struct veth_lpevent), number,
                            &veth_complete_allocation, &vc);
        wait_for_completion(&vc.c);
 
        return vc.num;
 }
 
+/*
+ * sysfs support
+ */
+
+struct veth_cnx_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct veth_lpar_connection *, char *buf);
+       ssize_t (*store)(struct veth_lpar_connection *, const char *buf);
+};
+
+static ssize_t veth_cnx_attribute_show(struct kobject *kobj,
+               struct attribute *attr, char *buf)
+{
+       struct veth_cnx_attribute *cnx_attr;
+       struct veth_lpar_connection *cnx;
+
+       cnx_attr = container_of(attr, struct veth_cnx_attribute, attr);
+       cnx = container_of(kobj, struct veth_lpar_connection, kobject);
+
+       if (!cnx_attr->show)
+               return -EIO;
+
+       return cnx_attr->show(cnx, buf);
+}
+
+#define CUSTOM_CNX_ATTR(_name, _format, _expression)                   \
+static ssize_t _name##_show(struct veth_lpar_connection *cnx, char *buf)\
+{                                                                      \
+       return sprintf(buf, _format, _expression);                      \
+}                                                                      \
+struct veth_cnx_attribute veth_cnx_attr_##_name = __ATTR_RO(_name)
+
+#define SIMPLE_CNX_ATTR(_name) \
+       CUSTOM_CNX_ATTR(_name, "%lu\n", (unsigned long)cnx->_name)
+
+SIMPLE_CNX_ATTR(outstanding_tx);
+SIMPLE_CNX_ATTR(remote_lp);
+SIMPLE_CNX_ATTR(num_events);
+SIMPLE_CNX_ATTR(src_inst);
+SIMPLE_CNX_ATTR(dst_inst);
+SIMPLE_CNX_ATTR(num_pending_acks);
+SIMPLE_CNX_ATTR(num_ack_events);
+CUSTOM_CNX_ATTR(ack_timeout, "%d\n", jiffies_to_msecs(cnx->ack_timeout));
+CUSTOM_CNX_ATTR(reset_timeout, "%d\n", jiffies_to_msecs(cnx->reset_timeout));
+CUSTOM_CNX_ATTR(state, "0x%.4lX\n", cnx->state);
+CUSTOM_CNX_ATTR(last_contact, "%d\n", cnx->last_contact ?
+               jiffies_to_msecs(jiffies - cnx->last_contact) : 0);
+
+#define GET_CNX_ATTR(_name)    (&veth_cnx_attr_##_name.attr)
+
+static struct attribute *veth_cnx_default_attrs[] = {
+       GET_CNX_ATTR(outstanding_tx),
+       GET_CNX_ATTR(remote_lp),
+       GET_CNX_ATTR(num_events),
+       GET_CNX_ATTR(reset_timeout),
+       GET_CNX_ATTR(last_contact),
+       GET_CNX_ATTR(state),
+       GET_CNX_ATTR(src_inst),
+       GET_CNX_ATTR(dst_inst),
+       GET_CNX_ATTR(num_pending_acks),
+       GET_CNX_ATTR(num_ack_events),
+       GET_CNX_ATTR(ack_timeout),
+       NULL
+};
+
+static struct sysfs_ops veth_cnx_sysfs_ops = {
+               .show = veth_cnx_attribute_show
+};
+
+static struct kobj_type veth_lpar_connection_ktype = {
+       .release        = veth_release_connection,
+       .sysfs_ops      = &veth_cnx_sysfs_ops,
+       .default_attrs  = veth_cnx_default_attrs
+};
+
+struct veth_port_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct veth_port *, char *buf);
+       ssize_t (*store)(struct veth_port *, const char *buf);
+};
+
+static ssize_t veth_port_attribute_show(struct kobject *kobj,
+               struct attribute *attr, char *buf)
+{
+       struct veth_port_attribute *port_attr;
+       struct veth_port *port;
+
+       port_attr = container_of(attr, struct veth_port_attribute, attr);
+       port = container_of(kobj, struct veth_port, kobject);
+
+       if (!port_attr->show)
+               return -EIO;
+
+       return port_attr->show(port, buf);
+}
+
+#define CUSTOM_PORT_ATTR(_name, _format, _expression)                  \
+static ssize_t _name##_show(struct veth_port *port, char *buf)         \
+{                                                                      \
+       return sprintf(buf, _format, _expression);                      \
+}                                                                      \
+struct veth_port_attribute veth_port_attr_##_name = __ATTR_RO(_name)
+
+#define SIMPLE_PORT_ATTR(_name)        \
+       CUSTOM_PORT_ATTR(_name, "%lu\n", (unsigned long)port->_name)
+
+SIMPLE_PORT_ATTR(promiscuous);
+SIMPLE_PORT_ATTR(num_mcast);
+CUSTOM_PORT_ATTR(lpar_map, "0x%X\n", port->lpar_map);
+CUSTOM_PORT_ATTR(stopped_map, "0x%X\n", port->stopped_map);
+CUSTOM_PORT_ATTR(mac_addr, "0x%lX\n", port->mac_addr);
+
+#define GET_PORT_ATTR(_name)   (&veth_port_attr_##_name.attr)
+static struct attribute *veth_port_default_attrs[] = {
+       GET_PORT_ATTR(mac_addr),
+       GET_PORT_ATTR(lpar_map),
+       GET_PORT_ATTR(stopped_map),
+       GET_PORT_ATTR(promiscuous),
+       GET_PORT_ATTR(num_mcast),
+       NULL
+};
+
+static struct sysfs_ops veth_port_sysfs_ops = {
+       .show = veth_port_attribute_show
+};
+
+static struct kobj_type veth_port_ktype = {
+       .sysfs_ops      = &veth_port_sysfs_ops,
+       .default_attrs  = veth_port_default_attrs
+};
+
 /*
  * LPAR connection code
  */
@@ -266,7 +460,7 @@ static inline void veth_kick_statemachine(struct veth_lpar_connection *cnx)
 }
 
 static void veth_take_cap(struct veth_lpar_connection *cnx,
-                         struct VethLpEvent *event)
+                         struct veth_lpevent *event)
 {
        unsigned long flags;
 
@@ -278,7 +472,7 @@ static void veth_take_cap(struct veth_lpar_connection *cnx,
                                                  HvLpEvent_Type_VirtualLan);
 
        if (cnx->state & VETH_STATE_GOTCAPS) {
-               veth_error("Received a second capabilities from lpar %d\n",
+               veth_error("Received a second capabilities from LPAR %d.\n",
                           cnx->remote_lp);
                event->base_event.xRc = HvLpEvent_Rc_BufferNotAvailable;
                HvCallEvent_ackLpEvent((struct HvLpEvent *) event);
@@ -291,13 +485,13 @@ static void veth_take_cap(struct veth_lpar_connection *cnx,
 }
 
 static void veth_take_cap_ack(struct veth_lpar_connection *cnx,
-                             struct VethLpEvent *event)
+                             struct veth_lpevent *event)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&cnx->lock, flags);
        if (cnx->state & VETH_STATE_GOTCAPACK) {
-               veth_error("Received a second capabilities ack from lpar %d\n",
+               veth_error("Received a second capabilities ack from LPAR %d.\n",
                           cnx->remote_lp);
        } else {
                memcpy(&cnx->cap_ack_event, event,
@@ -309,19 +503,24 @@ static void veth_take_cap_ack(struct veth_lpar_connection *cnx,
 }
 
 static void veth_take_monitor_ack(struct veth_lpar_connection *cnx,
-                                 struct VethLpEvent *event)
+                                 struct veth_lpevent *event)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&cnx->lock, flags);
-       veth_printk(KERN_DEBUG, "Monitor ack returned for lpar %d\n",
-                   cnx->remote_lp);
-       cnx->state |= VETH_STATE_RESET;
-       veth_kick_statemachine(cnx);
+       veth_debug("cnx %d: lost connection.\n", cnx->remote_lp);
+
+       /* Avoid kicking the statemachine once we're shutdown.
+        * It's unnecessary and it could break veth_stop_connection(). */
+
+       if (! (cnx->state & VETH_STATE_SHUTDOWN)) {
+               cnx->state |= VETH_STATE_RESET;
+               veth_kick_statemachine(cnx);
+       }
        spin_unlock_irqrestore(&cnx->lock, flags);
 }
 
-static void veth_handle_ack(struct VethLpEvent *event)
+static void veth_handle_ack(struct veth_lpevent *event)
 {
        HvLpIndex rlp = event->base_event.xTargetLp;
        struct veth_lpar_connection *cnx = veth_cnx[rlp];
@@ -329,58 +528,67 @@ static void veth_handle_ack(struct VethLpEvent *event)
        BUG_ON(! cnx);
 
        switch (event->base_event.xSubtype) {
-       case VethEventTypeCap:
+       case VETH_EVENT_CAP:
                veth_take_cap_ack(cnx, event);
                break;
-       case VethEventTypeMonitor:
+       case VETH_EVENT_MONITOR:
                veth_take_monitor_ack(cnx, event);
                break;
        default:
-               veth_error("Unknown ack type %d from lpar %d\n",
-                          event->base_event.xSubtype, rlp);
+               veth_error("Unknown ack type %d from LPAR %d.\n",
+                               event->base_event.xSubtype, rlp);
        };
 }
 
-static void veth_handle_int(struct VethLpEvent *event)
+static void veth_handle_int(struct veth_lpevent *event)
 {
        HvLpIndex rlp = event->base_event.xSourceLp;
        struct veth_lpar_connection *cnx = veth_cnx[rlp];
        unsigned long flags;
-       int i;
+       int i, acked = 0;
 
        BUG_ON(! cnx);
 
        switch (event->base_event.xSubtype) {
-       case VethEventTypeCap:
+       case VETH_EVENT_CAP:
                veth_take_cap(cnx, event);
                break;
-       case VethEventTypeMonitor:
+       case VETH_EVENT_MONITOR:
                /* do nothing... this'll hang out here til we're dead,
                 * and the hypervisor will return it for us. */
                break;
-       case VethEventTypeFramesAck:
+       case VETH_EVENT_FRAMES_ACK:
                spin_lock_irqsave(&cnx->lock, flags);
+
                for (i = 0; i < VETH_MAX_ACKS_PER_MSG; ++i) {
                        u16 msgnum = event->u.frames_ack_data.token[i];
 
-                       if (msgnum < VETH_NUMBUFFERS)
+                       if (msgnum < VETH_NUMBUFFERS) {
                                veth_recycle_msg(cnx, cnx->msgs + msgnum);
+                               cnx->outstanding_tx--;
+                               acked++;
+                       }
+               }
+
+               if (acked > 0) {
+                       cnx->last_contact = jiffies;
+                       veth_wake_queues(cnx);
                }
+
                spin_unlock_irqrestore(&cnx->lock, flags);
-               veth_flush_pending(cnx);
                break;
-       case VethEventTypeFrames:
+       case VETH_EVENT_FRAMES:
                veth_receive(cnx, event);
                break;
        default:
-               veth_error("Unknown interrupt type %d from lpar %d\n",
-                          event->base_event.xSubtype, rlp);
+               veth_error("Unknown interrupt type %d from LPAR %d.\n",
+                               event->base_event.xSubtype, rlp);
        };
 }
 
 static void veth_handle_event(struct HvLpEvent *event, struct pt_regs *regs)
 {
-       struct VethLpEvent *veth_event = (struct VethLpEvent *)event;
+       struct veth_lpevent *veth_event = (struct veth_lpevent *)event;
 
        if (event->xFlags.xFunction == HvLpEvent_Function_Ack)
                veth_handle_ack(veth_event);
@@ -390,7 +598,7 @@ static void veth_handle_event(struct HvLpEvent *event, struct pt_regs *regs)
 
 static int veth_process_caps(struct veth_lpar_connection *cnx)
 {
-       struct VethCapData *remote_caps = &cnx->remote_caps;
+       struct veth_cap_data *remote_caps = &cnx->remote_caps;
        int num_acks_needed;
 
        /* Convert timer to jiffies */
@@ -400,8 +608,8 @@ static int veth_process_caps(struct veth_lpar_connection *cnx)
             || (remote_caps->ack_threshold > VETH_MAX_ACKS_PER_MSG)
             || (remote_caps->ack_threshold == 0)
             || (cnx->ack_timeout == 0) ) {
-               veth_error("Received incompatible capabilities from lpar %d\n",
-                          cnx->remote_lp);
+               veth_error("Received incompatible capabilities from LPAR %d.\n",
+                               cnx->remote_lp);
                return HvLpEvent_Rc_InvalidSubtypeData;
        }
 
@@ -418,8 +626,8 @@ static int veth_process_caps(struct veth_lpar_connection *cnx)
                        cnx->num_ack_events += num;
 
                if (cnx->num_ack_events < num_acks_needed) {
-                       veth_error("Couldn't allocate enough ack events for lpar %d\n",
-                                  cnx->remote_lp);
+                       veth_error("Couldn't allocate enough ack events "
+                                       "for LPAR %d.\n", cnx->remote_lp);
 
                        return HvLpEvent_Rc_BufferNotAvailable;
                }
@@ -440,15 +648,15 @@ static void veth_statemachine(void *p)
 
  restart:
        if (cnx->state & VETH_STATE_RESET) {
-               int i;
-
-               del_timer(&cnx->ack_timer);
-
                if (cnx->state & VETH_STATE_OPEN)
                        HvCallEvent_closeLpEventPath(cnx->remote_lp,
                                                     HvLpEvent_Type_VirtualLan);
 
-               /* reset ack data */
+               /*
+                * Reset ack data. This prevents the ack_timer actually
+                * doing anything, even if it runs one more time when
+                * we drop the lock below.
+                */
                memset(&cnx->pending_acks, 0xff, sizeof (cnx->pending_acks));
                cnx->num_pending_acks = 0;
 
@@ -458,14 +666,32 @@ static void veth_statemachine(void *p)
                                | VETH_STATE_SENTCAPACK | VETH_STATE_READY);
 
                /* Clean up any leftover messages */
-               if (cnx->msgs)
+               if (cnx->msgs) {
+                       int i;
                        for (i = 0; i < VETH_NUMBUFFERS; ++i)
                                veth_recycle_msg(cnx, cnx->msgs + i);
+               }
+
+               cnx->outstanding_tx = 0;
+               veth_wake_queues(cnx);
+
+               /* Drop the lock so we can do stuff that might sleep or
+                * take other locks. */
                spin_unlock_irq(&cnx->lock);
-               veth_flush_pending(cnx);
+
+               del_timer_sync(&cnx->ack_timer);
+               del_timer_sync(&cnx->reset_timer);
+
                spin_lock_irq(&cnx->lock);
+
                if (cnx->state & VETH_STATE_RESET)
                        goto restart;
+
+               /* Hack, wait for the other end to reset itself. */
+               if (! (cnx->state & VETH_STATE_SHUTDOWN)) {
+                       schedule_delayed_work(&cnx->statemachine_wq, 5 * HZ);
+                       goto out;
+               }
        }
 
        if (cnx->state & VETH_STATE_SHUTDOWN)
@@ -488,7 +714,7 @@ static void veth_statemachine(void *p)
 
        if ( (cnx->state & VETH_STATE_OPEN)
             && !(cnx->state & VETH_STATE_SENTMON) ) {
-               rc = veth_signalevent(cnx, VethEventTypeMonitor,
+               rc = veth_signalevent(cnx, VETH_EVENT_MONITOR,
                                      HvLpEvent_AckInd_DoAck,
                                      HvLpEvent_AckType_DeferredAck,
                                      0, 0, 0, 0, 0, 0);
@@ -498,9 +724,8 @@ static void veth_statemachine(void *p)
                } else {
                        if ( (rc != HvLpEvent_Rc_PartitionDead)
                             && (rc != HvLpEvent_Rc_PathClosed) )
-                               veth_error("Error sending monitor to "
-                                          "lpar %d, rc=%x\n",
-                                          rlp, (int) rc);
+                               veth_error("Error sending monitor to LPAR %d, "
+                                               "rc = %d\n", rlp, rc);
 
                        /* Oh well, hope we get a cap from the other
                         * end and do better when that kicks us */
@@ -512,7 +737,7 @@ static void veth_statemachine(void *p)
             && !(cnx->state & VETH_STATE_SENTCAPS)) {
                u64 *rawcap = (u64 *)&cnx->local_caps;
 
-               rc = veth_signalevent(cnx, VethEventTypeCap,
+               rc = veth_signalevent(cnx, VETH_EVENT_CAP,
                                      HvLpEvent_AckInd_DoAck,
                                      HvLpEvent_AckType_ImmediateAck,
                                      0, rawcap[0], rawcap[1], rawcap[2],
@@ -523,9 +748,9 @@ static void veth_statemachine(void *p)
                } else {
                        if ( (rc != HvLpEvent_Rc_PartitionDead)
                             && (rc != HvLpEvent_Rc_PathClosed) )
-                               veth_error("Error sending caps to "
-                                          "lpar %d, rc=%x\n",
-                                          rlp, (int) rc);
+                               veth_error("Error sending caps to LPAR %d, "
+                                               "rc = %d\n", rlp, rc);
+
                        /* Oh well, hope we get a cap from the other
                         * end and do better when that kicks us */
                        goto out;
@@ -534,7 +759,7 @@ static void veth_statemachine(void *p)
 
        if ((cnx->state & VETH_STATE_GOTCAPS)
            && !(cnx->state & VETH_STATE_SENTCAPACK)) {
-               struct VethCapData *remote_caps = &cnx->remote_caps;
+               struct veth_cap_data *remote_caps = &cnx->remote_caps;
 
                memcpy(remote_caps, &cnx->cap_event.u.caps_data,
                       sizeof(*remote_caps));
@@ -565,10 +790,8 @@ static void veth_statemachine(void *p)
                        add_timer(&cnx->ack_timer);
                        cnx->state |= VETH_STATE_READY;
                } else {
-                       veth_printk(KERN_ERR, "Caps rejected (rc=%d) by "
-                                   "lpar %d\n",
-                                   cnx->cap_ack_event.base_event.xRc,
-                                   rlp);
+                       veth_error("Caps rejected by LPAR %d, rc = %d\n",
+                                       rlp, cnx->cap_ack_event.base_event.xRc);
                        goto cant_cope;
                }
        }
@@ -581,8 +804,8 @@ static void veth_statemachine(void *p)
        /* FIXME: we get here if something happens we really can't
         * cope with.  The link will never work once we get here, and
         * all we can do is not lock the rest of the system up */
-       veth_error("Badness on connection to lpar %d (state=%04lx) "
-                  " - shutting down\n", rlp, cnx->state);
+       veth_error("Unrecoverable error on connection to LPAR %d, shutting down"
+                       " (state = 0x%04lx)\n", rlp, cnx->state);
        cnx->state |= VETH_STATE_SHUTDOWN;
        spin_unlock_irq(&cnx->lock);
 }
@@ -591,7 +814,7 @@ static int veth_init_connection(u8 rlp)
 {
        struct veth_lpar_connection *cnx;
        struct veth_msg *msgs;
-       int i;
+       int i, rc;
 
        if ( (rlp == this_lp)
             || ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) )
@@ -605,22 +828,36 @@ static int veth_init_connection(u8 rlp)
        cnx->remote_lp = rlp;
        spin_lock_init(&cnx->lock);
        INIT_WORK(&cnx->statemachine_wq, veth_statemachine, cnx);
+
        init_timer(&cnx->ack_timer);
        cnx->ack_timer.function = veth_timed_ack;
        cnx->ack_timer.data = (unsigned long) cnx;
+
+       init_timer(&cnx->reset_timer);
+       cnx->reset_timer.function = veth_timed_reset;
+       cnx->reset_timer.data = (unsigned long) cnx;
+       cnx->reset_timeout = 5 * HZ * (VETH_ACKTIMEOUT / 1000000);
+
        memset(&cnx->pending_acks, 0xff, sizeof (cnx->pending_acks));
 
        veth_cnx[rlp] = cnx;
 
+       /* This gets us 1 reference, which is held on behalf of the driver
+        * infrastructure. It's released at module unload. */
+       kobject_init(&cnx->kobject);
+       cnx->kobject.ktype = &veth_lpar_connection_ktype;
+       rc = kobject_set_name(&cnx->kobject, "cnx%.2d", rlp);
+       if (rc != 0)
+               return rc;
+
        msgs = kmalloc(VETH_NUMBUFFERS * sizeof(struct veth_msg), GFP_KERNEL);
        if (! msgs) {
-               veth_error("Can't allocate buffers for lpar %d\n", rlp);
+               veth_error("Can't allocate buffers for LPAR %d.\n", rlp);
                return -ENOMEM;
        }
 
        cnx->msgs = msgs;
        memset(msgs, 0, VETH_NUMBUFFERS * sizeof(struct veth_msg));
-       spin_lock_init(&cnx->msg_stack_lock);
 
        for (i = 0; i < VETH_NUMBUFFERS; i++) {
                msgs[i].token = i;
@@ -630,8 +867,7 @@ static int veth_init_connection(u8 rlp)
        cnx->num_events = veth_allocate_events(rlp, 2 + VETH_NUMBUFFERS);
 
        if (cnx->num_events < (2 + VETH_NUMBUFFERS)) {
-               veth_error("Can't allocate events for lpar %d, only got %d\n",
-                          rlp, cnx->num_events);
+               veth_error("Can't allocate enough events for LPAR %d.\n", rlp);
                return -ENOMEM;
        }
 
@@ -642,11 +878,9 @@ static int veth_init_connection(u8 rlp)
        return 0;
 }
 
-static void veth_stop_connection(u8 rlp)
+static void veth_stop_connection(struct veth_lpar_connection *cnx)
 {
-       struct veth_lpar_connection *cnx = veth_cnx[rlp];
-
-       if (! cnx)
+       if (!cnx)
                return;
 
        spin_lock_irq(&cnx->lock);
@@ -654,12 +888,23 @@ static void veth_stop_connection(u8 rlp)
        veth_kick_statemachine(cnx);
        spin_unlock_irq(&cnx->lock);
 
+       /* There's a slim chance the reset code has just queued the
+        * statemachine to run in five seconds. If so we need to cancel
+        * that and requeue the work to run now. */
+       if (cancel_delayed_work(&cnx->statemachine_wq)) {
+               spin_lock_irq(&cnx->lock);
+               veth_kick_statemachine(cnx);
+               spin_unlock_irq(&cnx->lock);
+       }
+
+       /* Wait for the state machine to run. */
        flush_scheduled_work();
+}
 
-       /* FIXME: not sure if this is necessary - will already have
-        * been deleted by the state machine, just want to make sure
-        * its not running any more */
-       del_timer_sync(&cnx->ack_timer);
+static void veth_destroy_connection(struct veth_lpar_connection *cnx)
+{
+       if (!cnx)
+               return;
 
        if (cnx->num_events > 0)
                mf_deallocate_lp_events(cnx->remote_lp,
@@ -671,18 +916,18 @@ static void veth_stop_connection(u8 rlp)
                                      HvLpEvent_Type_VirtualLan,
                                      cnx->num_ack_events,
                                      NULL, NULL);
-}
-
-static void veth_destroy_connection(u8 rlp)
-{
-       struct veth_lpar_connection *cnx = veth_cnx[rlp];
-
-       if (! cnx)
-               return;
 
        kfree(cnx->msgs);
+       veth_cnx[cnx->remote_lp] = NULL;
        kfree(cnx);
-       veth_cnx[rlp] = NULL;
+}
+
+static void veth_release_connection(struct kobject *kobj)
+{
+       struct veth_lpar_connection *cnx;
+       cnx = container_of(kobj, struct veth_lpar_connection, kobject);
+       veth_stop_connection(cnx);
+       veth_destroy_connection(cnx);
 }
 
 /*
@@ -726,17 +971,15 @@ static void veth_set_multicast_list(struct net_device *dev)
 
        write_lock_irqsave(&port->mcast_gate, flags);
 
-       if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */
-               printk(KERN_INFO "%s: Promiscuous mode enabled.\n",
-                      dev->name);
+       if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
+                       (dev->mc_count > VETH_MAX_MCAST)) {
                port->promiscuous = 1;
-       } else if ( (dev->flags & IFF_ALLMULTI)
-                   || (dev->mc_count > VETH_MAX_MCAST) ) {
-               port->all_mcast = 1;
        } else {
                struct dev_mc_list *dmi = dev->mc_list;
                int i;
 
+               port->promiscuous = 0;
+
                /* Update table */
                port->num_mcast = 0;
 
@@ -758,9 +1001,10 @@ static void veth_set_multicast_list(struct net_device *dev)
 
 static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       strncpy(info->driver, "veth", sizeof(info->driver) - 1);
+       strncpy(info->driver, DRV_NAME, sizeof(info->driver) - 1);
        info->driver[sizeof(info->driver) - 1] = '\0';
-       strncpy(info->version, "1.0", sizeof(info->version) - 1);
+       strncpy(info->version, DRV_VERSION, sizeof(info->version) - 1);
+       info->version[sizeof(info->version) - 1] = '\0';
 }
 
 static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
@@ -791,49 +1035,6 @@ static struct ethtool_ops ops = {
        .get_link = veth_get_link,
 };
 
-static void veth_tx_timeout(struct net_device *dev)
-{
-       struct veth_port *port = (struct veth_port *)dev->priv;
-       struct net_device_stats *stats = &port->stats;
-       unsigned long flags;
-       int i;
-
-       stats->tx_errors++;
-
-       spin_lock_irqsave(&port->pending_gate, flags);
-
-       if (!port->pending_lpmask) {
-               spin_unlock_irqrestore(&port->pending_gate, flags);
-               return;
-       }
-
-       printk(KERN_WARNING "%s: Tx timeout!  Resetting lp connections: %08x\n",
-              dev->name, port->pending_lpmask);
-
-       for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
-               struct veth_lpar_connection *cnx = veth_cnx[i];
-
-               if (! (port->pending_lpmask & (1<<i)))
-                       continue;
-
-               /* If we're pending on it, we must be connected to it,
-                * so we should certainly have a structure for it. */
-               BUG_ON(! cnx);
-
-               /* Theoretically we could be kicking a connection
-                * which doesn't deserve it, but in practice if we've
-                * had a Tx timeout, the pending_lpmask will have
-                * exactly one bit set - the connection causing the
-                * problem. */
-               spin_lock(&cnx->lock);
-               cnx->state |= VETH_STATE_RESET;
-               veth_kick_statemachine(cnx);
-               spin_unlock(&cnx->lock);
-       }
-
-       spin_unlock_irqrestore(&port->pending_gate, flags);
-}
-
 static struct net_device * __init veth_probe_one(int vlan, struct device *vdev)
 {
        struct net_device *dev;
@@ -848,8 +1049,9 @@ static struct net_device * __init veth_probe_one(int vlan, struct device *vdev)
 
        port = (struct veth_port *) dev->priv;
 
-       spin_lock_init(&port->pending_gate);
+       spin_lock_init(&port->queue_lock);
        rwlock_init(&port->mcast_gate);
+       port->stopped_map = 0;
 
        for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
                HvLpVirtualLanIndexMap map;
@@ -882,22 +1084,24 @@ static struct net_device * __init veth_probe_one(int vlan, struct device *vdev)
        dev->set_multicast_list = veth_set_multicast_list;
        SET_ETHTOOL_OPS(dev, &ops);
 
-       dev->watchdog_timeo = 2 * (VETH_ACKTIMEOUT * HZ / 1000000);
-       dev->tx_timeout = veth_tx_timeout;
-
        SET_NETDEV_DEV(dev, vdev);
 
        rc = register_netdev(dev);
        if (rc != 0) {
-               veth_printk(KERN_ERR,
-                           "Failed to register ethernet device for vlan %d\n",
-                           vlan);
+               veth_error("Failed registering net device for vlan%d.\n", vlan);
                free_netdev(dev);
                return NULL;
        }
 
-       veth_printk(KERN_DEBUG, "%s attached to iSeries vlan %d (lpar_map=0x%04x)\n",
-                   dev->name, vlan, port->lpar_map);
+       kobject_init(&port->kobject);
+       port->kobject.parent = &dev->class_dev.kobj;
+       port->kobject.ktype  = &veth_port_ktype;
+       kobject_set_name(&port->kobject, "veth_port");
+       if (0 != kobject_add(&port->kobject))
+               veth_error("Failed adding port for %s to sysfs.\n", dev->name);
+
+       veth_info("%s attached to iSeries vlan %d (LPAR map = 0x%.4X)\n",
+                       dev->name, vlan, port->lpar_map);
 
        return dev;
 }
@@ -912,98 +1116,95 @@ static int veth_transmit_to_one(struct sk_buff *skb, HvLpIndex rlp,
        struct veth_lpar_connection *cnx = veth_cnx[rlp];
        struct veth_port *port = (struct veth_port *) dev->priv;
        HvLpEvent_Rc rc;
-       u32 dma_address, dma_length;
        struct veth_msg *msg = NULL;
-       int err = 0;
        unsigned long flags;
 
-       if (! cnx) {
-               port->stats.tx_errors++;
-               dev_kfree_skb(skb);
+       if (! cnx)
                return 0;
-       }
 
        spin_lock_irqsave(&cnx->lock, flags);
 
        if (! (cnx->state & VETH_STATE_READY))
-               goto drop;
+               goto no_error;
 
-       if ((skb->len - 14) > VETH_MAX_MTU)
+       if ((skb->len - ETH_HLEN) > VETH_MAX_MTU)
                goto drop;
 
        msg = veth_stack_pop(cnx);
-
-       if (! msg) {
-               err = 1;
+       if (! msg)
                goto drop;
-       }
 
-       dma_length = skb->len;
-       dma_address = dma_map_single(port->dev, skb->data,
-                                    dma_length, DMA_TO_DEVICE);
+       msg->in_use = 1;
+       msg->skb = skb_get(skb);
+
+       msg->data.addr[0] = dma_map_single(port->dev, skb->data,
+                               skb->len, DMA_TO_DEVICE);
 
-       if (dma_mapping_error(dma_address))
+       if (dma_mapping_error(msg->data.addr[0]))
                goto recycle_and_drop;
 
-       /* Is it really necessary to check the length and address
-        * fields of the first entry here? */
-       msg->skb = skb;
        msg->dev = port->dev;
-       msg->data.addr[0] = dma_address;
-       msg->data.len[0] = dma_length;
+       msg->data.len[0] = skb->len;
        msg->data.eofmask = 1 << VETH_EOF_SHIFT;
-       set_bit(0, &(msg->in_use));
-       rc = veth_signaldata(cnx, VethEventTypeFrames, msg->token, &msg->data);
+
+       rc = veth_signaldata(cnx, VETH_EVENT_FRAMES, msg->token, &msg->data);
 
        if (rc != HvLpEvent_Rc_Good)
                goto recycle_and_drop;
 
+       /* If the timer's not already running, start it now. */
+       if (0 == cnx->outstanding_tx)
+               mod_timer(&cnx->reset_timer, jiffies + cnx->reset_timeout);
+
+       cnx->last_contact = jiffies;
+       cnx->outstanding_tx++;
+
+       if (veth_stack_is_empty(cnx))
+               veth_stop_queues(cnx);
+
+ no_error:
        spin_unlock_irqrestore(&cnx->lock, flags);
        return 0;
 
  recycle_and_drop:
-       msg->skb = NULL;
-       /* need to set in use to make veth_recycle_msg in case this
-        * was a mapping failure */
-       set_bit(0, &msg->in_use);
        veth_recycle_msg(cnx, msg);
  drop:
-       port->stats.tx_errors++;
-       dev_kfree_skb(skb);
        spin_unlock_irqrestore(&cnx->lock, flags);
-       return err;
+       return 1;
 }
 
-static HvLpIndexMap veth_transmit_to_many(struct sk_buff *skb,
+static void veth_transmit_to_many(struct sk_buff *skb,
                                          HvLpIndexMap lpmask,
                                          struct net_device *dev)
 {
        struct veth_port *port = (struct veth_port *) dev->priv;
-       int i;
-       int rc;
+       int i, success, error;
+
+       success = error = 0;
 
        for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
                if ((lpmask & (1 << i)) == 0)
                        continue;
 
-               rc = veth_transmit_to_one(skb_get(skb), i, dev);
-               if (! rc)
-                       lpmask &= ~(1<<i);
+               if (veth_transmit_to_one(skb, i, dev))
+                       error = 1;
+               else
+                       success = 1;
        }
 
-       if (! lpmask) {
+       if (error)
+               port->stats.tx_errors++;
+
+       if (success) {
                port->stats.tx_packets++;
                port->stats.tx_bytes += skb->len;
        }
-
-       return lpmask;
 }
 
 static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        unsigned char *frame = skb->data;
        struct veth_port *port = (struct veth_port *) dev->priv;
-       unsigned long flags;
        HvLpIndexMap lpmask;
 
        if (! (frame[0] & 0x01)) {
@@ -1020,44 +1221,27 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
                lpmask = port->lpar_map;
        }
 
-       spin_lock_irqsave(&port->pending_gate, flags);
-
-       lpmask = veth_transmit_to_many(skb, lpmask, dev);
-
-       dev->trans_start = jiffies;
+       veth_transmit_to_many(skb, lpmask, dev);
 
-       if (! lpmask) {
-               dev_kfree_skb(skb);
-       } else {
-               if (port->pending_skb) {
-                       veth_error("%s: Tx while skb was pending!\n",
-                                  dev->name);
-                       dev_kfree_skb(skb);
-                       spin_unlock_irqrestore(&port->pending_gate, flags);
-                       return 1;
-               }
-
-               port->pending_skb = skb;
-               port->pending_lpmask = lpmask;
-               netif_stop_queue(dev);
-       }
-
-       spin_unlock_irqrestore(&port->pending_gate, flags);
+       dev_kfree_skb(skb);
 
        return 0;
 }
 
+/* You must hold the connection's lock when you call this function. */
 static void veth_recycle_msg(struct veth_lpar_connection *cnx,
                             struct veth_msg *msg)
 {
        u32 dma_address, dma_length;
 
-       if (test_and_clear_bit(0, &msg->in_use)) {
+       if (msg->in_use) {
+               msg->in_use = 0;
                dma_address = msg->data.addr[0];
                dma_length = msg->data.len[0];
 
-               dma_unmap_single(msg->dev, dma_address, dma_length,
-                                DMA_TO_DEVICE);
+               if (!dma_mapping_error(dma_address))
+                       dma_unmap_single(msg->dev, dma_address, dma_length,
+                                       DMA_TO_DEVICE);
 
                if (msg->skb) {
                        dev_kfree_skb_any(msg->skb);
@@ -1066,15 +1250,16 @@ static void veth_recycle_msg(struct veth_lpar_connection *cnx,
 
                memset(&msg->data, 0, sizeof(msg->data));
                veth_stack_push(cnx, msg);
-       } else
-               if (cnx->state & VETH_STATE_OPEN)
-                       veth_error("Bogus frames ack from lpar %d (#%d)\n",
-                                  cnx->remote_lp, msg->token);
+       } else if (cnx->state & VETH_STATE_OPEN) {
+               veth_error("Non-pending frame (# %d) acked by LPAR %d.\n",
+                               cnx->remote_lp, msg->token);
+       }
 }
 
-static void veth_flush_pending(struct veth_lpar_connection *cnx)
+static void veth_wake_queues(struct veth_lpar_connection *cnx)
 {
        int i;
+
        for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
                struct net_device *dev = veth_dev[i];
                struct veth_port *port;
@@ -1088,20 +1273,77 @@ static void veth_flush_pending(struct veth_lpar_connection *cnx)
                if (! (port->lpar_map & (1<<cnx->remote_lp)))
                        continue;
 
-               spin_lock_irqsave(&port->pending_gate, flags);
-               if (port->pending_skb) {
-                       port->pending_lpmask =
-                               veth_transmit_to_many(port->pending_skb,
-                                                     port->pending_lpmask,
-                                                     dev);
-                       if (! port->pending_lpmask) {
-                               dev_kfree_skb_any(port->pending_skb);
-                               port->pending_skb = NULL;
-                               netif_wake_queue(dev);
-                       }
+               spin_lock_irqsave(&port->queue_lock, flags);
+
+               port->stopped_map &= ~(1 << cnx->remote_lp);
+
+               if (0 == port->stopped_map && netif_queue_stopped(dev)) {
+                       veth_debug("cnx %d: woke queue for %s.\n",
+                                       cnx->remote_lp, dev->name);
+                       netif_wake_queue(dev);
+               }
+               spin_unlock_irqrestore(&port->queue_lock, flags);
+       }
+}
+
+static void veth_stop_queues(struct veth_lpar_connection *cnx)
+{
+       int i;
+
+       for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
+               struct net_device *dev = veth_dev[i];
+               struct veth_port *port;
+
+               if (! dev)
+                       continue;
+
+               port = (struct veth_port *)dev->priv;
+
+               /* If this cnx is not on the vlan for this port, continue */
+               if (! (port->lpar_map & (1 << cnx->remote_lp)))
+                       continue;
+
+               spin_lock(&port->queue_lock);
+
+               netif_stop_queue(dev);
+               port->stopped_map |= (1 << cnx->remote_lp);
+
+               veth_debug("cnx %d: stopped queue for %s, map = 0x%x.\n",
+                               cnx->remote_lp, dev->name, port->stopped_map);
+
+               spin_unlock(&port->queue_lock);
+       }
+}
+
+static void veth_timed_reset(unsigned long ptr)
+{
+       struct veth_lpar_connection *cnx = (struct veth_lpar_connection *)ptr;
+       unsigned long trigger_time, flags;
+
+       /* FIXME is it possible this fires after veth_stop_connection()?
+        * That would reschedule the statemachine for 5 seconds and probably
+        * execute it after the module's been unloaded. Hmm. */
+
+       spin_lock_irqsave(&cnx->lock, flags);
+
+       if (cnx->outstanding_tx > 0) {
+               trigger_time = cnx->last_contact + cnx->reset_timeout;
+
+               if (trigger_time < jiffies) {
+                       cnx->state |= VETH_STATE_RESET;
+                       veth_kick_statemachine(cnx);
+                       veth_error("%d packets not acked by LPAR %d within %d "
+                                       "seconds, resetting.\n",
+                                       cnx->outstanding_tx, cnx->remote_lp,
+                                       cnx->reset_timeout / HZ);
+               } else {
+                       /* Reschedule the timer */
+                       trigger_time = jiffies + cnx->reset_timeout;
+                       mod_timer(&cnx->reset_timer, trigger_time);
                }
-               spin_unlock_irqrestore(&port->pending_gate, flags);
        }
+
+       spin_unlock_irqrestore(&cnx->lock, flags);
 }
 
 /*
@@ -1117,12 +1359,9 @@ static inline int veth_frame_wanted(struct veth_port *port, u64 mac_addr)
        if ( (mac_addr == port->mac_addr) || (mac_addr == 0xffffffffffff0000) )
                return 1;
 
-       if (! (((char *) &mac_addr)[0] & 0x01))
-               return 0;
-
        read_lock_irqsave(&port->mcast_gate, flags);
 
-       if (port->promiscuous || port->all_mcast) {
+       if (port->promiscuous) {
                wanted = 1;
                goto out;
        }
@@ -1175,21 +1414,21 @@ static void veth_flush_acks(struct veth_lpar_connection *cnx)
 {
        HvLpEvent_Rc rc;
 
-       rc = veth_signaldata(cnx, VethEventTypeFramesAck,
+       rc = veth_signaldata(cnx, VETH_EVENT_FRAMES_ACK,
                             0, &cnx->pending_acks);
 
        if (rc != HvLpEvent_Rc_Good)
-               veth_error("Error 0x%x acking frames from lpar %d!\n",
-                          (unsigned)rc, cnx->remote_lp);
+               veth_error("Failed acking frames from LPAR %d, rc = %d\n",
+                               cnx->remote_lp, (int)rc);
 
        cnx->num_pending_acks = 0;
        memset(&cnx->pending_acks, 0xff, sizeof(cnx->pending_acks));
 }
 
 static void veth_receive(struct veth_lpar_connection *cnx,
-                        struct VethLpEvent *event)
+                        struct veth_lpevent *event)
 {
-       struct VethFramesData *senddata = &event->u.frames_data;
+       struct veth_frames_data *senddata = &event->u.frames_data;
        int startchunk = 0;
        int nchunks;
        unsigned long flags;
@@ -1216,9 +1455,10 @@ static void veth_receive(struct veth_lpar_connection *cnx,
                /* make sure that we have at least 1 EOF entry in the
                 * remaining entries */
                if (! (senddata->eofmask >> (startchunk + VETH_EOF_SHIFT))) {
-                       veth_error("missing EOF frag in event "
-                                  "eofmask=0x%x startchunk=%d\n",
-                                  (unsigned) senddata->eofmask, startchunk);
+                       veth_error("Missing EOF fragment in event "
+                                       "eofmask = 0x%x startchunk = %d\n",
+                                       (unsigned)senddata->eofmask,
+                                       startchunk);
                        break;
                }
 
@@ -1237,8 +1477,9 @@ static void veth_receive(struct veth_lpar_connection *cnx,
                /* nchunks == # of chunks in this frame */
 
                if ((length - ETH_HLEN) > VETH_MAX_MTU) {
-                       veth_error("Received oversize frame from lpar %d "
-                                  "(length=%d)\n", cnx->remote_lp, length);
+                       veth_error("Received oversize frame from LPAR %d "
+                                       "(length = %d)\n",
+                                       cnx->remote_lp, length);
                        continue;
                }
 
@@ -1331,15 +1572,33 @@ static void veth_timed_ack(unsigned long ptr)
 
 static int veth_remove(struct vio_dev *vdev)
 {
-       int i = vdev->unit_address;
+       struct veth_lpar_connection *cnx;
        struct net_device *dev;
+       struct veth_port *port;
+       int i;
 
-       dev = veth_dev[i];
-       if (dev != NULL) {
-               veth_dev[i] = NULL;
-               unregister_netdev(dev);
-               free_netdev(dev);
+       dev = veth_dev[vdev->unit_address];
+
+       if (! dev)
+               return 0;
+
+       port = netdev_priv(dev);
+
+       for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
+               cnx = veth_cnx[i];
+
+               if (cnx && (port->lpar_map & (1 << i))) {
+                       /* Drop our reference to connections on our VLAN */
+                       kobject_put(&cnx->kobject);
+               }
        }
+
+       veth_dev[vdev->unit_address] = NULL;
+       kobject_del(&port->kobject);
+       kobject_put(&port->kobject);
+       unregister_netdev(dev);
+       free_netdev(dev);
+
        return 0;
 }
 
@@ -1347,6 +1606,7 @@ static int veth_probe(struct vio_dev *vdev, const struct vio_device_id *id)
 {
        int i = vdev->unit_address;
        struct net_device *dev;
+       struct veth_port *port;
 
        dev = veth_probe_one(i, &vdev->dev);
        if (dev == NULL) {
@@ -1355,11 +1615,23 @@ static int veth_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        }
        veth_dev[i] = dev;
 
-       /* Start the state machine on each connection, to commence
-        * link negotiation */
-       for (i = 0; i < HVMAXARCHITECTEDLPS; i++)
-               if (veth_cnx[i])
-                       veth_kick_statemachine(veth_cnx[i]);
+       port = (struct veth_port*)netdev_priv(dev);
+
+       /* Start the state machine on each connection on this vlan. If we're
+        * the first dev to do so this will commence link negotiation */
+       for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
+               struct veth_lpar_connection *cnx;
+
+               if (! (port->lpar_map & (1 << i)))
+                       continue;
+
+               cnx = veth_cnx[i];
+               if (!cnx)
+                       continue;
+
+               kobject_get(&cnx->kobject);
+               veth_kick_statemachine(cnx);
+       }
 
        return 0;
 }
@@ -1370,12 +1642,12 @@ static int veth_probe(struct vio_dev *vdev, const struct vio_device_id *id)
  */
 static struct vio_device_id veth_device_table[] __devinitdata = {
        { "vlan", "" },
-       { NULL, NULL }
+       { "", "" }
 };
 MODULE_DEVICE_TABLE(vio, veth_device_table);
 
 static struct vio_driver veth_driver = {
-       .name = "iseries_veth",
+       .name = DRV_NAME,
        .id_table = veth_device_table,
        .probe = veth_probe,
        .remove = veth_remove
@@ -1388,29 +1660,29 @@ static struct vio_driver veth_driver = {
 void __exit veth_module_cleanup(void)
 {
        int i;
+       struct veth_lpar_connection *cnx;
 
-       /* Stop the queues first to stop any new packets being sent. */
-       for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++)
-               if (veth_dev[i])
-                       netif_stop_queue(veth_dev[i]);
-
-       /* Stop the connections before we unregister the driver. This
-        * ensures there's no skbs lying around holding the device open. */
-       for (i = 0; i < HVMAXARCHITECTEDLPS; ++i)
-               veth_stop_connection(i);
-
+       /* Disconnect our "irq" to stop events coming from the Hypervisor. */
        HvLpEvent_unregisterHandler(HvLpEvent_Type_VirtualLan);
 
-       /* Hypervisor callbacks may have scheduled more work while we
-        * were stoping connections. Now that we've disconnected from
-        * the hypervisor make sure everything's finished. */
+       /* Make sure any work queued from Hypervisor callbacks is finished. */
        flush_scheduled_work();
 
-       vio_unregister_driver(&veth_driver);
+       for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
+               cnx = veth_cnx[i];
+
+               if (!cnx)
+                       continue;
 
-       for (i = 0; i < HVMAXARCHITECTEDLPS; ++i)
-               veth_destroy_connection(i);
+               /* Remove the connection from sysfs */
+               kobject_del(&cnx->kobject);
+               /* Drop the driver's reference to the connection */
+               kobject_put(&cnx->kobject);
+       }
 
+       /* Unregister the driver, which will close all the netdevs and stop
+        * the connections when they're no longer referenced. */
+       vio_unregister_driver(&veth_driver);
 }
 module_exit(veth_module_cleanup);
 
@@ -1423,15 +1695,37 @@ int __init veth_module_init(void)
 
        for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
                rc = veth_init_connection(i);
-               if (rc != 0) {
-                       veth_module_cleanup();
-                       return rc;
-               }
+               if (rc != 0)
+                       goto error;
        }
 
        HvLpEvent_registerHandler(HvLpEvent_Type_VirtualLan,
                                  &veth_handle_event);
 
-       return vio_register_driver(&veth_driver);
+       rc = vio_register_driver(&veth_driver);
+       if (rc != 0)
+               goto error;
+
+       for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
+               struct kobject *kobj;
+
+               if (!veth_cnx[i])
+                       continue;
+
+               kobj = &veth_cnx[i]->kobject;
+               kobj->parent = &veth_driver.driver.kobj;
+               /* If the add failes, complain but otherwise continue */
+               if (0 != kobject_add(kobj))
+                       veth_error("cnx %d: Failed adding to sysfs.\n", i);
+       }
+
+       return 0;
+
+error:
+       for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
+               veth_destroy_connection(veth_cnx[i]);
+       }
+
+       return rc;
 }
 module_init(veth_module_init);
diff --git a/drivers/net/iseries_veth.h b/drivers/net/iseries_veth.h
deleted file mode 100644 (file)
index d9370f7..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/* File veth.h created by Kyle A. Lucke on Mon Aug  7 2000. */
-
-#ifndef _ISERIES_VETH_H
-#define _ISERIES_VETH_H
-
-#define VethEventTypeCap       (0)
-#define VethEventTypeFrames    (1)
-#define VethEventTypeMonitor   (2)
-#define VethEventTypeFramesAck (3)
-
-#define VETH_MAX_ACKS_PER_MSG  (20)
-#define VETH_MAX_FRAMES_PER_MSG        (6)
-
-struct VethFramesData {
-       u32 addr[VETH_MAX_FRAMES_PER_MSG];
-       u16 len[VETH_MAX_FRAMES_PER_MSG];
-       u32 eofmask;
-};
-#define VETH_EOF_SHIFT         (32-VETH_MAX_FRAMES_PER_MSG)
-
-struct VethFramesAckData {
-       u16 token[VETH_MAX_ACKS_PER_MSG];
-};
-
-struct VethCapData {
-       u8 caps_version;
-       u8 rsvd1;
-       u16 num_buffers;
-       u16 ack_threshold;
-       u16 rsvd2;
-       u32 ack_timeout;
-       u32 rsvd3;
-       u64 rsvd4[3];
-};
-
-struct VethLpEvent {
-       struct HvLpEvent base_event;
-       union {
-               struct VethCapData caps_data;
-               struct VethFramesData frames_data;
-               struct VethFramesAckData frames_ack_data;
-       } u;
-
-};
-
-#endif /* _ISERIES_VETH_H */
index f8d3385c7842d3fe6f34b6d672da43353ce139a4..c83271b386215cefef859df73572f34bc535fa17 100644 (file)
@@ -119,7 +119,7 @@ struct ixgb_adapter;
  * so a DMA handle can be stored along with the buffer */
 struct ixgb_buffer {
        struct sk_buff *skb;
-       uint64_t dma;
+       dma_addr_t dma;
        unsigned long time_stamp;
        uint16_t length;
        uint16_t next_to_watch;
index 3aae110c55606ced13769acddf7d87c2649d1a4f..661a46b95a61e4a73a88f1774d8a3cc3564d8734 100644 (file)
@@ -565,24 +565,6 @@ ixgb_get_ee_mac_addr(struct ixgb_hw *hw,
        }
 }
 
-/******************************************************************************
- * return the compatibility flags from EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Returns:
- *          compatibility flags if EEPROM contents are valid, 0 otherwise
- ******************************************************************************/
-uint16_t
-ixgb_get_ee_compatibility(struct ixgb_hw *hw)
-{
-       struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
-
-       if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-               return (le16_to_cpu(ee_map->compatibility));
-
-       return(0);
-}
 
 /******************************************************************************
  * return the Printed Board Assembly number from EEPROM
@@ -602,81 +584,6 @@ ixgb_get_ee_pba_number(struct ixgb_hw *hw)
        return(0);
 }
 
-/******************************************************************************
- * return the Initialization Control Word 1 from EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Returns:
- *          Initialization Control Word 1 if EEPROM contents are valid, 0 otherwise
- ******************************************************************************/
-uint16_t
-ixgb_get_ee_init_ctrl_reg_1(struct ixgb_hw *hw)
-{
-       struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
-
-       if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-               return (le16_to_cpu(ee_map->init_ctrl_reg_1));
-
-       return(0);
-}
-
-/******************************************************************************
- * return the Initialization Control Word 2 from EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Returns:
- *          Initialization Control Word 2 if EEPROM contents are valid, 0 otherwise
- ******************************************************************************/
-uint16_t
-ixgb_get_ee_init_ctrl_reg_2(struct ixgb_hw *hw)
-{
-       struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
-
-       if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-               return (le16_to_cpu(ee_map->init_ctrl_reg_2));
-
-       return(0);
-}
-
-/******************************************************************************
- * return the Subsystem Id from EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Returns:
- *          Subsystem Id if EEPROM contents are valid, 0 otherwise
- ******************************************************************************/
-uint16_t
-ixgb_get_ee_subsystem_id(struct ixgb_hw *hw)
-{
-       struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
-
-       if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-               return (le16_to_cpu(ee_map->subsystem_id));
-
-       return(0);
-}
-
-/******************************************************************************
- * return the Sub Vendor Id from EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Returns:
- *          Sub Vendor Id if EEPROM contents are valid, 0 otherwise
- ******************************************************************************/
-uint16_t
-ixgb_get_ee_subvendor_id(struct ixgb_hw *hw)
-{
-       struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
-
-       if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-               return (le16_to_cpu(ee_map->subvendor_id));
-
-       return(0);
-}
 
 /******************************************************************************
  * return the Device Id from EEPROM
@@ -694,81 +601,6 @@ ixgb_get_ee_device_id(struct ixgb_hw *hw)
        if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
                return (le16_to_cpu(ee_map->device_id));
 
-       return(0);
-}
-
-/******************************************************************************
- * return the Vendor Id from EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Returns:
- *          Device Id if EEPROM contents are valid, 0 otherwise
- ******************************************************************************/
-uint16_t
-ixgb_get_ee_vendor_id(struct ixgb_hw *hw)
-{
-       struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
-
-       if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-               return (le16_to_cpu(ee_map->vendor_id));
-
-       return(0);
-}
-
-/******************************************************************************
- * return the Software Defined Pins Register from EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Returns:
- *          SDP Register if EEPROM contents are valid, 0 otherwise
- ******************************************************************************/
-uint16_t
-ixgb_get_ee_swdpins_reg(struct ixgb_hw *hw)
-{
-       struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
-
-       if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-               return (le16_to_cpu(ee_map->swdpins_reg));
-
-       return(0);
+       return (0);
 }
 
-/******************************************************************************
- * return the D3 Power Management Bits from EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Returns:
- *          D3 Power Management Bits if EEPROM contents are valid, 0 otherwise
- ******************************************************************************/
-uint8_t
-ixgb_get_ee_d3_power(struct ixgb_hw *hw)
-{
-       struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
-
-       if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-               return (le16_to_cpu(ee_map->d3_power));
-
-       return(0);
-}
-
-/******************************************************************************
- * return the D0 Power Management Bits from EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Returns:
- *          D0 Power Management Bits if EEPROM contents are valid, 0 otherwise
- ******************************************************************************/
-uint8_t
-ixgb_get_ee_d0_power(struct ixgb_hw *hw)
-{
-       struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
-
-       if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-               return (le16_to_cpu(ee_map->d0_power));
-
-       return(0);
-}
index 3fa113854eebc3d27c8cda25e0d5600a30a48e0e..9d026ed77ddd4250660ad117d76c2e319e6d3eda 100644 (file)
@@ -98,10 +98,10 @@ static struct ixgb_stats ixgb_gstrings_stats[] = {
 static int
 ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
 
        ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
-       ecmd->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
+       ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
        ecmd->port = PORT_FIBRE;
        ecmd->transceiver = XCVR_EXTERNAL;
 
@@ -120,7 +120,7 @@ ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 static int
 ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
 
        if(ecmd->autoneg == AUTONEG_ENABLE ||
           ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)
@@ -130,6 +130,12 @@ ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
                ixgb_down(adapter, TRUE);
                ixgb_reset(adapter);
                ixgb_up(adapter);
+               /* be optimistic about our link, since we were up before */
+               adapter->link_speed = 10000;
+               adapter->link_duplex = FULL_DUPLEX;
+               netif_carrier_on(netdev);
+               netif_wake_queue(netdev);
+               
        } else
                ixgb_reset(adapter);
 
@@ -140,7 +146,7 @@ static void
 ixgb_get_pauseparam(struct net_device *netdev,
                         struct ethtool_pauseparam *pause)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_hw *hw = &adapter->hw;
        
        pause->autoneg = AUTONEG_DISABLE;
@@ -159,7 +165,7 @@ static int
 ixgb_set_pauseparam(struct net_device *netdev,
                         struct ethtool_pauseparam *pause)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_hw *hw = &adapter->hw;
        
        if(pause->autoneg == AUTONEG_ENABLE)
@@ -177,6 +183,11 @@ ixgb_set_pauseparam(struct net_device *netdev,
        if(netif_running(adapter->netdev)) {
                ixgb_down(adapter, TRUE);
                ixgb_up(adapter);
+               /* be optimistic about our link, since we were up before */
+               adapter->link_speed = 10000;
+               adapter->link_duplex = FULL_DUPLEX;
+               netif_carrier_on(netdev);
+               netif_wake_queue(netdev);
        } else
                ixgb_reset(adapter);
                
@@ -186,19 +197,26 @@ ixgb_set_pauseparam(struct net_device *netdev,
 static uint32_t
 ixgb_get_rx_csum(struct net_device *netdev)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
+
        return adapter->rx_csum;
 }
 
 static int
 ixgb_set_rx_csum(struct net_device *netdev, uint32_t data)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
+
        adapter->rx_csum = data;
 
        if(netif_running(netdev)) {
                ixgb_down(adapter,TRUE);
                ixgb_up(adapter);
+               /* be optimistic about our link, since we were up before */
+               adapter->link_speed = 10000;
+               adapter->link_duplex = FULL_DUPLEX;
+               netif_carrier_on(netdev);
+               netif_wake_queue(netdev);
        } else
                ixgb_reset(adapter);
        return 0;
@@ -246,14 +264,15 @@ static void
 ixgb_get_regs(struct net_device *netdev,
                   struct ethtool_regs *regs, void *p)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_hw *hw = &adapter->hw;
        uint32_t *reg = p;
        uint32_t *reg_start = reg;
        uint8_t i;
 
        /* the 1 (one) below indicates an attempt at versioning, if the
-        * interface in ethtool or the driver this 1 should be incremented */
+        * interface in ethtool or the driver changes, this 1 should be
+        * incremented */
        regs->version = (1<<24) | hw->revision_id << 16 | hw->device_id;
 
        /* General Registers */
@@ -283,7 +302,8 @@ ixgb_get_regs(struct net_device *netdev,
        *reg++ = IXGB_READ_REG(hw, RAIDC);      /*  19 */
        *reg++ = IXGB_READ_REG(hw, RXCSUM);     /*  20 */
 
-       for (i = 0; i < IXGB_RAR_ENTRIES; i++) {
+       /* there are 16 RAR entries in hardware, we only use 3 */
+       for(i = 0; i < 16; i++) {
                *reg++ = IXGB_READ_REG_ARRAY(hw, RAL, (i << 1)); /*21,...,51 */
                *reg++ = IXGB_READ_REG_ARRAY(hw, RAH, (i << 1)); /*22,...,52 */
        }
@@ -391,7 +411,7 @@ static int
 ixgb_get_eeprom(struct net_device *netdev,
                  struct ethtool_eeprom *eeprom, uint8_t *bytes)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_hw *hw = &adapter->hw;
        uint16_t *eeprom_buff;
        int i, max_len, first_word, last_word;
@@ -439,7 +459,7 @@ static int
 ixgb_set_eeprom(struct net_device *netdev,
                  struct ethtool_eeprom *eeprom, uint8_t *bytes)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_hw *hw = &adapter->hw;
        uint16_t *eeprom_buff;
        void *ptr;
@@ -497,7 +517,7 @@ static void
 ixgb_get_drvinfo(struct net_device *netdev,
                   struct ethtool_drvinfo *drvinfo)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
 
        strncpy(drvinfo->driver,  ixgb_driver_name, 32);
        strncpy(drvinfo->version, ixgb_driver_version, 32);
@@ -512,7 +532,7 @@ static void
 ixgb_get_ringparam(struct net_device *netdev,
                struct ethtool_ringparam *ring)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_desc_ring *txdr = &adapter->tx_ring;
        struct ixgb_desc_ring *rxdr = &adapter->rx_ring;
 
@@ -530,7 +550,7 @@ static int
 ixgb_set_ringparam(struct net_device *netdev,
                struct ethtool_ringparam *ring)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_desc_ring *txdr = &adapter->tx_ring;
        struct ixgb_desc_ring *rxdr = &adapter->rx_ring;
        struct ixgb_desc_ring tx_old, tx_new, rx_old, rx_new;
@@ -573,6 +593,11 @@ ixgb_set_ringparam(struct net_device *netdev,
                adapter->tx_ring = tx_new;
                if((err = ixgb_up(adapter)))
                        return err;
+               /* be optimistic about our link, since we were up before */
+               adapter->link_speed = 10000;
+               adapter->link_duplex = FULL_DUPLEX;
+               netif_carrier_on(netdev);
+               netif_wake_queue(netdev);
        }
 
        return 0;
@@ -607,7 +632,7 @@ ixgb_led_blink_callback(unsigned long data)
 static int
 ixgb_phys_id(struct net_device *netdev, uint32_t data)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
 
        if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ))
                data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ);
@@ -643,7 +668,7 @@ static void
 ixgb_get_ethtool_stats(struct net_device *netdev, 
                struct ethtool_stats *stats, uint64_t *data)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        int i;
 
        ixgb_update_stats(adapter);
index 97898efe7cc8075698ee51f7f35e7cd6a4cd63d1..8bcf31ed10c221ad5609f57f6fecc155d5fbc81a 100644 (file)
@@ -822,17 +822,8 @@ extern void ixgb_clear_vfta(struct ixgb_hw *hw);
 
 /* Access functions to eeprom data */
 void ixgb_get_ee_mac_addr(struct ixgb_hw *hw, uint8_t *mac_addr);
-uint16_t ixgb_get_ee_compatibility(struct ixgb_hw *hw);
 uint32_t ixgb_get_ee_pba_number(struct ixgb_hw *hw);
-uint16_t ixgb_get_ee_init_ctrl_reg_1(struct ixgb_hw *hw);
-uint16_t ixgb_get_ee_init_ctrl_reg_2(struct ixgb_hw *hw);
-uint16_t ixgb_get_ee_subsystem_id(struct ixgb_hw *hw);
-uint16_t ixgb_get_ee_subvendor_id(struct ixgb_hw *hw);
 uint16_t ixgb_get_ee_device_id(struct ixgb_hw *hw);
-uint16_t ixgb_get_ee_vendor_id(struct ixgb_hw *hw);
-uint16_t ixgb_get_ee_swdpins_reg(struct ixgb_hw *hw);
-uint8_t ixgb_get_ee_d3_power(struct ixgb_hw *hw);
-uint8_t ixgb_get_ee_d0_power(struct ixgb_hw *hw);
 boolean_t ixgb_get_eeprom_data(struct ixgb_hw *hw);
 uint16_t ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index);
 
index 097b90ccf575b2d17e8f6f67458bcd6003dba96c..5c555373adbe5802054b2ed3558219269d0e9ca5 100644 (file)
 #include "ixgb.h"
 
 /* Change Log
+ * 1.0.96 04/19/05
+ * - Make needlessly global code static -- bunk@stusta.de
+ * - ethtool cleanup -- shemminger@osdl.org
+ * - Support for MODULE_VERSION -- linville@tuxdriver.com
+ * - add skb_header_cloned check to the tso path -- herbert@apana.org.au
  * 1.0.88 01/05/05
  * - include fix to the condition that determines when to quit NAPI - Robert Olsson
  * - use netif_poll_{disable/enable} to synchronize between NAPI and i/f up/down
@@ -47,10 +52,9 @@ char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver";
 #else
 #define DRIVERNAPI "-NAPI"
 #endif
-
-#define DRV_VERSION "1.0.95-k2"DRIVERNAPI
+#define DRV_VERSION            "1.0.100-k2"DRIVERNAPI
 char ixgb_driver_version[] = DRV_VERSION;
-char ixgb_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
+static char ixgb_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
 
 /* ixgb_pci_tbl - PCI Device ID Table
  *
@@ -145,10 +149,12 @@ MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
 /* some defines for controlling descriptor fetches in h/w */
-#define RXDCTL_PTHRESH_DEFAULT 128     /* chip considers prefech below this */
-#define RXDCTL_HTHRESH_DEFAULT 16      /* chip will only prefetch if tail is 
-                                          pushed this many descriptors from head */
 #define RXDCTL_WTHRESH_DEFAULT 16      /* chip writes back at this many or RXT0 */
+#define RXDCTL_PTHRESH_DEFAULT 0               /* chip considers prefech below
+                                                * this */
+#define RXDCTL_HTHRESH_DEFAULT 0               /* chip will only prefetch if tail
+                                                * is pushed this many descriptors
+                                                * from head */
 
 /**
  * ixgb_init_module - Driver Registration Routine
@@ -376,7 +382,7 @@ ixgb_probe(struct pci_dev *pdev,
        SET_NETDEV_DEV(netdev, &pdev->dev);
 
        pci_set_drvdata(pdev, netdev);
-       adapter = netdev->priv;
+       adapter = netdev_priv(netdev);
        adapter->netdev = netdev;
        adapter->pdev = pdev;
        adapter->hw.back = adapter;
@@ -512,7 +518,7 @@ static void __devexit
 ixgb_remove(struct pci_dev *pdev)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
 
        unregister_netdev(netdev);
 
@@ -583,7 +589,7 @@ ixgb_sw_init(struct ixgb_adapter *adapter)
 static int
 ixgb_open(struct net_device *netdev)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        int err;
 
        /* allocate transmit descriptors */
@@ -626,7 +632,7 @@ err_setup_tx:
 static int
 ixgb_close(struct net_device *netdev)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
 
        ixgb_down(adapter, TRUE);
 
@@ -1017,7 +1023,7 @@ ixgb_clean_rx_ring(struct ixgb_adapter *adapter)
 static int
 ixgb_set_mac(struct net_device *netdev, void *p)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct sockaddr *addr = p;
 
        if(!is_valid_ether_addr(addr->sa_data))
@@ -1043,7 +1049,7 @@ ixgb_set_mac(struct net_device *netdev, void *p)
 static void
 ixgb_set_multi(struct net_device *netdev)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_hw *hw = &adapter->hw;
        struct dev_mc_list *mc_ptr;
        uint32_t rctl;
@@ -1371,7 +1377,7 @@ ixgb_tx_queue(struct ixgb_adapter *adapter, int count, int vlan_id,int tx_flags)
 static int
 ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        unsigned int first;
        unsigned int tx_flags = 0;
        unsigned long flags;
@@ -1425,7 +1431,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 static void
 ixgb_tx_timeout(struct net_device *netdev)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
 
        /* Do the reset outside of interrupt context */
        schedule_work(&adapter->tx_timeout_task);
@@ -1434,7 +1440,7 @@ ixgb_tx_timeout(struct net_device *netdev)
 static void
 ixgb_tx_timeout_task(struct net_device *netdev)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
 
        ixgb_down(adapter, TRUE);
        ixgb_up(adapter);
@@ -1451,7 +1457,7 @@ ixgb_tx_timeout_task(struct net_device *netdev)
 static struct net_device_stats *
 ixgb_get_stats(struct net_device *netdev)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
 
        return &adapter->net_stats;
 }
@@ -1467,7 +1473,7 @@ ixgb_get_stats(struct net_device *netdev)
 static int
 ixgb_change_mtu(struct net_device *netdev, int new_mtu)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        int max_frame = new_mtu + ENET_HEADER_SIZE + ENET_FCS_LENGTH;
        int old_max_frame = netdev->mtu + ENET_HEADER_SIZE + ENET_FCS_LENGTH;
 
@@ -1522,7 +1528,8 @@ ixgb_update_stats(struct ixgb_adapter *adapter)
 
                multi |= ((u64)IXGB_READ_REG(&adapter->hw, MPRCH) << 32);
                /* fix up multicast stats by removing broadcasts */
-               multi -= bcast;
+               if(multi >= bcast)
+                       multi -= bcast;
                
                adapter->stats.mprcl += (multi & 0xFFFFFFFF);
                adapter->stats.mprch += (multi >> 32);
@@ -1641,7 +1648,7 @@ static irqreturn_t
 ixgb_intr(int irq, void *data, struct pt_regs *regs)
 {
        struct net_device *netdev = data;
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_hw *hw = &adapter->hw;
        uint32_t icr = IXGB_READ_REG(hw, ICR);
 #ifndef CONFIG_IXGB_NAPI
@@ -1688,7 +1695,7 @@ ixgb_intr(int irq, void *data, struct pt_regs *regs)
 static int
 ixgb_clean(struct net_device *netdev, int *budget)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        int work_to_do = min(*budget, netdev->quota);
        int tx_cleaned;
        int work_done = 0;
@@ -2017,7 +2024,7 @@ ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter)
 static void
 ixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        uint32_t ctrl, rctl;
 
        ixgb_irq_disable(adapter);
@@ -2055,7 +2062,7 @@ ixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
 static void
 ixgb_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        uint32_t vfta, index;
 
        /* add VID to filter table */
@@ -2069,7 +2076,7 @@ ixgb_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
 static void
 ixgb_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        uint32_t vfta, index;
 
        ixgb_irq_disable(adapter);
index 7fec613e1675496167be6fb2c7777209d7e0fe84..8423cb6875f06d75ac38f18881199a5f2b8acb41 100644 (file)
@@ -1,5 +1,10 @@
 /*
- * sonic.c
+ * jazzsonic.c
+ *
+ * (C) 2005 Finn Thain
+ *
+ * Converted to DMA API, and (from the mac68k project) introduced
+ * dhd's support for 16-bit cards.
  *
  * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de)
  * 
@@ -28,8 +33,8 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#include <linux/bitops.h>
 #include <linux/device.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/bootinfo.h>
 #include <asm/system.h>
@@ -44,22 +49,20 @@ static struct platform_device *jazz_sonic_device;
 
 #define SONIC_MEM_SIZE 0x100
 
-#define SREGS_PAD(n)    u16 n;
-
 #include "sonic.h"
 
 /*
  * Macros to access SONIC registers
  */
-#define SONIC_READ(reg) (*((volatile unsigned int *)base_addr+reg))
+#define SONIC_READ(reg) (*((volatile unsigned int *)dev->base_addr+reg))
 
 #define SONIC_WRITE(reg,val)                                           \
 do {                                                                   \
-       *((volatile unsigned int *)base_addr+(reg)) = (val);            \
+       *((volatile unsigned int *)dev->base_addr+(reg)) = (val);               \
 } while (0)
 
 
-/* use 0 for production, 1 for verification, >2 for debug */
+/* use 0 for production, 1 for verification, >1 for debug */
 #ifdef SONIC_DEBUG
 static unsigned int sonic_debug = SONIC_DEBUG;
 #else 
@@ -85,18 +88,18 @@ static unsigned short known_revisions[] =
        0xffff                  /* end of list */
 };
 
-static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr,
-                               unsigned int irq)
+static int __init sonic_probe1(struct net_device *dev)
 {
        static unsigned version_printed;
        unsigned int silicon_revision;
        unsigned int val;
-       struct sonic_local *lp;
+       struct sonic_local *lp = netdev_priv(dev);
        int err = -ENODEV;
        int i;
 
-       if (!request_mem_region(base_addr, SONIC_MEM_SIZE, jazz_sonic_string))
+       if (!request_mem_region(dev->base_addr, SONIC_MEM_SIZE, jazz_sonic_string))
                return -EBUSY;
+
        /*
         * get the Silicon Revision ID. If this is one of the known
         * one assume that we found a SONIC ethernet controller at
@@ -120,11 +123,7 @@ static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr,
        if (sonic_debug  &&  version_printed++ == 0)
                printk(version);
 
-       printk("%s: Sonic ethernet found at 0x%08lx, ", dev->name, base_addr);
-
-       /* Fill in the 'dev' fields. */
-       dev->base_addr = base_addr;
-       dev->irq = irq;
+       printk(KERN_INFO "%s: Sonic ethernet found at 0x%08lx, ", lp->device->bus_id, dev->base_addr);
 
        /*
         * Put the sonic into software reset, then
@@ -138,84 +137,44 @@ static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr,
                dev->dev_addr[i*2+1] = val >> 8;
        }
 
-       printk("HW Address ");
-       for (i = 0; i < 6; i++) {
-               printk("%2.2x", dev->dev_addr[i]);
-               if (i<5)
-                       printk(":");
-       }
-
-       printk(" IRQ %d\n", irq);
-
        err = -ENOMEM;
     
        /* Initialize the device structure. */
-       if (dev->priv == NULL) {
-               /*
-                * the memory be located in the same 64kb segment
-                */
-               lp = NULL;
-               i = 0;
-               do {
-                       lp = kmalloc(sizeof(*lp), GFP_KERNEL);
-                       if ((unsigned long) lp >> 16
-                           != ((unsigned long)lp + sizeof(*lp) ) >> 16) {
-                               /* FIXME, free the memory later */
-                               kfree(lp);
-                               lp = NULL;
-                       }
-               } while (lp == NULL && i++ < 20);
-
-               if (lp == NULL) {
-                       printk("%s: couldn't allocate memory for descriptors\n",
-                              dev->name);
-                       goto out;
-               }
 
-               memset(lp, 0, sizeof(struct sonic_local));
-
-               /* get the virtual dma address */
-               lp->cda_laddr = vdma_alloc(CPHYSADDR(lp),sizeof(*lp));
-               if (lp->cda_laddr == ~0UL) {
-                       printk("%s: couldn't get DMA page entry for "
-                              "descriptors\n", dev->name);
-                       goto out1;
-               }
-
-               lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda);
-               lp->rra_laddr = lp->tda_laddr + sizeof (lp->tda);
-               lp->rda_laddr = lp->rra_laddr + sizeof (lp->rra);
-       
-               /* allocate receive buffer area */
-               /* FIXME, maybe we should use skbs */
-               lp->rba = kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL);
-               if (!lp->rba) {
-                       printk("%s: couldn't allocate receive buffers\n",
-                              dev->name);
-                       goto out2;
-               }
+       lp->dma_bitmode = SONIC_BITMODE32;
 
-               /* get virtual dma address */
-               lp->rba_laddr = vdma_alloc(CPHYSADDR(lp->rba),
-                                          SONIC_NUM_RRS * SONIC_RBSIZE);
-               if (lp->rba_laddr == ~0UL) {
-                       printk("%s: couldn't get DMA page entry for receive "
-                              "buffers\n",dev->name);
-                       goto out3;
-               }
-
-               /* now convert pointer to KSEG1 pointer */
-               lp->rba = (char *)KSEG1ADDR(lp->rba);
-               flush_cache_all();
-               dev->priv = (struct sonic_local *)KSEG1ADDR(lp);
+       /* Allocate the entire chunk of memory for the descriptors.
+           Note that this cannot cross a 64K boundary. */
+       if ((lp->descriptors = dma_alloc_coherent(lp->device,
+                               SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
+                               &lp->descriptors_laddr, GFP_KERNEL)) == NULL) {
+               printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", lp->device->bus_id);
+               goto out;
        }
 
-       lp = (struct sonic_local *)dev->priv;
+       /* Now set up the pointers to point to the appropriate places */
+       lp->cda = lp->descriptors;
+       lp->tda = lp->cda + (SIZEOF_SONIC_CDA
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+       lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+       lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+
+       lp->cda_laddr = lp->descriptors_laddr;
+       lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+       lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+       lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+
        dev->open = sonic_open;
        dev->stop = sonic_close;
        dev->hard_start_xmit = sonic_send_packet;
-       dev->get_stats  = sonic_get_stats;
+       dev->get_stats = sonic_get_stats;
        dev->set_multicast_list = &sonic_multicast_list;
+       dev->tx_timeout = sonic_tx_timeout;
        dev->watchdog_timeo = TX_TIMEOUT;
 
        /*
@@ -226,14 +185,8 @@ static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr,
        SONIC_WRITE(SONIC_MPT,0xffff);
 
        return 0;
-out3:
-       kfree(lp->rba);
-out2:
-       vdma_free(lp->cda_laddr);
-out1:
-       kfree(lp);
 out:
-       release_region(base_addr, SONIC_MEM_SIZE);
+       release_region(dev->base_addr, SONIC_MEM_SIZE);
        return err;
 }
 
@@ -245,7 +198,6 @@ static int __init jazz_sonic_probe(struct device *device)
 {
        struct net_device *dev;
        struct sonic_local *lp;
-       unsigned long base_addr;
        int err = 0;
        int i;
 
@@ -255,21 +207,26 @@ static int __init jazz_sonic_probe(struct device *device)
        if (mips_machgroup != MACH_GROUP_JAZZ)
                return -ENODEV;
 
-       dev = alloc_etherdev(0);
+       dev = alloc_etherdev(sizeof(struct sonic_local));
        if (!dev)
                return -ENOMEM;
 
+       lp = netdev_priv(dev);
+       lp->device = device;
+       SET_NETDEV_DEV(dev, device);
+       SET_MODULE_OWNER(dev);
+
        netdev_boot_setup_check(dev);
-       base_addr = dev->base_addr;
 
-       if (base_addr >= KSEG0) { /* Check a single specified location. */
-               err = sonic_probe1(dev, base_addr, dev->irq);
-       } else if (base_addr != 0) { /* Don't probe at all. */
+       if (dev->base_addr >= KSEG0) { /* Check a single specified location. */
+               err = sonic_probe1(dev);
+       } else if (dev->base_addr != 0) { /* Don't probe at all. */
                err = -ENXIO;
        } else {
                for (i = 0; sonic_portlist[i].port; i++) {
-                       int io = sonic_portlist[i].port;
-                       if (sonic_probe1(dev, io, sonic_portlist[i].irq) == 0)
+                       dev->base_addr = sonic_portlist[i].port;
+                       dev->irq = sonic_portlist[i].irq;
+                       if (sonic_probe1(dev) == 0)
                                break;
                }
                if (!sonic_portlist[i].port)
@@ -281,14 +238,17 @@ static int __init jazz_sonic_probe(struct device *device)
        if (err)
                goto out1;
 
+       printk("%s: MAC ", dev->name);
+       for (i = 0; i < 6; i++) {
+               printk("%2.2x", dev->dev_addr[i]);
+               if (i < 5)
+                       printk(":");
+       }
+       printk(" IRQ %d\n", dev->irq);
+
        return 0;
 
 out1:
-       lp = dev->priv;
-       vdma_free(lp->rba_laddr);
-       kfree(lp->rba);
-       vdma_free(lp->cda_laddr);
-       kfree(lp);
        release_region(dev->base_addr, SONIC_MEM_SIZE);
 out:
        free_netdev(dev);
@@ -296,21 +256,22 @@ out:
        return err;
 }
 
-/*
- *      SONIC uses a normal IRQ
- */
-#define sonic_request_irq       request_irq
-#define sonic_free_irq          free_irq
+MODULE_DESCRIPTION("Jazz SONIC ethernet driver");
+module_param(sonic_debug, int, 0);
+MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)");
 
-#define sonic_chiptomem(x)      KSEG1ADDR(vdma_log2phys(x))
+#define SONIC_IRQ_FLAG SA_INTERRUPT
 
 #include "sonic.c"
 
 static int __devexit jazz_sonic_device_remove (struct device *device)
 {
        struct net_device *dev = device->driver_data;
+       struct sonic_local* lp = netdev_priv(dev);
 
        unregister_netdev (dev);
+       dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
+                         lp->descriptors, lp->descriptors_laddr);
        release_region (dev->base_addr, SONIC_MEM_SIZE);
        free_netdev (dev);
 
@@ -323,7 +284,7 @@ static struct device_driver jazz_sonic_driver = {
        .probe  = jazz_sonic_probe,
        .remove = __devexit_p(jazz_sonic_device_remove),
 };
-                                                                                
+
 static void jazz_sonic_platform_release (struct device *device)
 {
        struct platform_device *pldev;
@@ -336,10 +297,11 @@ static void jazz_sonic_platform_release (struct device *device)
 static int __init jazz_sonic_init_module(void)
 {
        struct platform_device *pldev;
+       int err;
 
-       if (driver_register(&jazz_sonic_driver)) {
+       if ((err = driver_register(&jazz_sonic_driver))) {
                printk(KERN_ERR "Driver registration failed\n");
-               return -ENOMEM;
+               return err;
        }
 
        jazz_sonic_device = NULL;
index 1f61f0cc95d81238a4120df48dc8a9afe2e067c0..690a1aae0b34705c6d04cb08bc31f1c3dbc72c0d 100644 (file)
@@ -68,6 +68,7 @@ static DEFINE_PER_CPU(struct net_device_stats, loopback_stats);
  * of largesending device modulo TCP checksum, which is ignored for loopback.
  */
 
+#ifdef LOOPBACK_TSO
 static void emulate_large_send_offload(struct sk_buff *skb)
 {
        struct iphdr *iph = skb->nh.iph;
@@ -119,6 +120,7 @@ static void emulate_large_send_offload(struct sk_buff *skb)
 
        dev_kfree_skb(skb);
 }
+#endif /* LOOPBACK_TSO */
 
 /*
  * The higher levels take care of making this non-reentrant (it's
@@ -130,12 +132,13 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
 
        skb_orphan(skb);
 
-       skb->protocol=eth_type_trans(skb,dev);
-       skb->dev=dev;
+       skb->protocol = eth_type_trans(skb,dev);
+       skb->dev = dev;
 #ifndef LOOPBACK_MUST_CHECKSUM
        skb->ip_summed = CHECKSUM_UNNECESSARY;
 #endif
 
+#ifdef LOOPBACK_TSO
        if (skb_shinfo(skb)->tso_size) {
                BUG_ON(skb->protocol != htons(ETH_P_IP));
                BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);
@@ -143,14 +146,14 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
                emulate_large_send_offload(skb);
                return 0;
        }
-
+#endif
        dev->last_rx = jiffies;
 
        lb_stats = &per_cpu(loopback_stats, get_cpu());
        lb_stats->rx_bytes += skb->len;
-       lb_stats->tx_bytes += skb->len;
+       lb_stats->tx_bytes = lb_stats->rx_bytes;
        lb_stats->rx_packets++;
-       lb_stats->tx_packets++;
+       lb_stats->tx_packets = lb_stats->rx_packets;
        put_cpu();
 
        netif_rx(skb);
@@ -208,9 +211,12 @@ struct net_device loopback_dev = {
        .type                   = ARPHRD_LOOPBACK,      /* 0x0001*/
        .rebuild_header         = eth_rebuild_header,
        .flags                  = IFF_LOOPBACK,
-       .features               = NETIF_F_SG|NETIF_F_FRAGLIST
-                                 |NETIF_F_NO_CSUM|NETIF_F_HIGHDMA
-                                 |NETIF_F_LLTX,
+       .features               = NETIF_F_SG | NETIF_F_FRAGLIST
+#ifdef LOOPBACK_TSO
+                                 | NETIF_F_TSO
+#endif
+                                 | NETIF_F_NO_CSUM | NETIF_F_HIGHDMA
+                                 | NETIF_F_LLTX,
        .ethtool_ops            = &loopback_ethtool_ops,
 };
 
index be28c65de729e5b4682b80788a70d48ebf3d9c7d..405e18365edef4c353b681937ebf63eb3971def7 100644 (file)
@@ -1,6 +1,12 @@
 /*
  * macsonic.c
  *
+ * (C) 2005 Finn Thain
+ *
+ * Converted to DMA API, converted to unified driver model, made it work as
+ * a module again, and from the mac68k project, introduced more 32-bit cards
+ * and dhd's support for 16-bit cards.
+ *
  * (C) 1998 Alan Cox
  *
  * Debugging Andreas Ehliar, Michael Schmitz
@@ -26,8 +32,8 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/types.h>
-#include <linux/ctype.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -41,8 +47,8 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#include <linux/module.h>
-#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/bootinfo.h>
 #include <asm/system.h>
 #include <asm/macints.h>
 #include <asm/mac_via.h>
 
-#define SREGS_PAD(n)    u16 n;
+static char mac_sonic_string[] = "macsonic";
+static struct platform_device *mac_sonic_device;
 
 #include "sonic.h"
 
-#define SONIC_READ(reg) \
-       nubus_readl(base_addr+(reg))
-#define SONIC_WRITE(reg,val) \
-       nubus_writel((val), base_addr+(reg))
-#define sonic_read(dev, reg) \
-       nubus_readl((dev)->base_addr+(reg))
-#define sonic_write(dev, reg, val) \
-       nubus_writel((val), (dev)->base_addr+(reg))
-
+/* These should basically be bus-size and endian independent (since
+   the SONIC is at least smart enough that it uses the same endianness
+   as the host, unlike certain less enlightened Macintosh NICs) */
+#define SONIC_READ(reg) (nubus_readw(dev->base_addr + (reg * 4) \
+             + lp->reg_offset))
+#define SONIC_WRITE(reg,val) (nubus_writew(val, dev->base_addr + (reg * 4) \
+             + lp->reg_offset))
+
+/* use 0 for production, 1 for verification, >1 for debug */
+#ifdef SONIC_DEBUG
+static unsigned int sonic_debug = SONIC_DEBUG;
+#else 
+static unsigned int sonic_debug = 1;
+#endif
 
-static int sonic_debug;
 static int sonic_version_printed;
 
-static int reg_offset;
-
 extern int mac_onboard_sonic_probe(struct net_device* dev);
 extern int mac_nubus_sonic_probe(struct net_device* dev);
 
@@ -108,40 +117,6 @@ enum macsonic_type {
 
 #define SONIC_READ_PROM(addr) nubus_readb(prom_addr+addr)
 
-struct net_device * __init macsonic_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(0);
-       int err;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       if (unit >= 0)
-               sprintf(dev->name, "eth%d", unit);
-
-       SET_MODULE_OWNER(dev);
-
-       /* This will catch fatal stuff like -ENOMEM as well as success */
-       err = mac_onboard_sonic_probe(dev);
-       if (err == 0)
-               goto found;
-       if (err != -ENODEV)
-               goto out;
-       err = mac_nubus_sonic_probe(dev);
-       if (err)
-               goto out;
-found:
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
-       return dev;
-out1:
-       kfree(dev->priv);
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
 /*
  * For reversing the PROM address
  */
@@ -160,103 +135,55 @@ static inline void bit_reverse_addr(unsigned char addr[6])
 
 int __init macsonic_init(struct net_device* dev)
 {
-       struct sonic_local* lp = NULL;
-       int i;
+       struct sonic_local* lp = netdev_priv(dev);
 
        /* Allocate the entire chunk of memory for the descriptors.
            Note that this cannot cross a 64K boundary. */
-       for (i = 0; i < 20; i++) {
-               unsigned long desc_base, desc_top;
-               if((lp = kmalloc(sizeof(struct sonic_local), GFP_KERNEL | GFP_DMA)) == NULL) {
-                       printk(KERN_ERR "%s: couldn't allocate descriptor buffers\n", dev->name);
-                       return -ENOMEM;
-               }
-
-               desc_base = (unsigned long) lp;
-               desc_top = desc_base + sizeof(struct sonic_local);
-               if ((desc_top & 0xffff) >= (desc_base & 0xffff))
-                       break;
-               /* Hmm. try again (FIXME: does this actually work?) */
-               kfree(lp);
-               printk(KERN_DEBUG
-                      "%s: didn't get continguous chunk [%08lx - %08lx], trying again\n",
-                      dev->name, desc_base, desc_top);
-       }
-
-       if (lp == NULL) {
-               printk(KERN_ERR "%s: tried 20 times to allocate descriptor buffers, giving up.\n",
-                      dev->name);
+       if ((lp->descriptors = dma_alloc_coherent(lp->device,
+                   SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
+                   &lp->descriptors_laddr, GFP_KERNEL)) == NULL) {
+               printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", lp->device->bus_id);
                return -ENOMEM;
-       }                      
-
-       dev->priv = lp;
-
-#if 0
-       /* this code is only here as a curiousity...   mainly, where the 
-          fuck did SONIC_BUS_SCALE come from, and what was it supposed
-          to do?  the normal allocation works great for 32 bit stuffs..  */
+       }
 
        /* Now set up the pointers to point to the appropriate places */
-       lp->cda = lp->sonic_desc;
-       lp->tda = lp->cda + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode));
+       lp->cda = lp->descriptors;
+       lp->tda = lp->cda + (SIZEOF_SONIC_CDA
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
        lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
-                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
        lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
-                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
 
-#endif
-       
-       memset(lp, 0, sizeof(struct sonic_local));
-
-       lp->cda_laddr = (unsigned int)&(lp->cda);
-       lp->tda_laddr = (unsigned int)lp->tda;
-       lp->rra_laddr = (unsigned int)lp->rra;
-       lp->rda_laddr = (unsigned int)lp->rda;
-
-       /* FIXME, maybe we should use skbs */
-       if ((lp->rba = (char *)
-            kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL | GFP_DMA)) == NULL) {
-               printk(KERN_ERR "%s: couldn't allocate receive buffers\n", dev->name);
-               dev->priv = NULL;
-               kfree(lp);
-               return -ENOMEM;
-       }
-
-       lp->rba_laddr = (unsigned int)lp->rba;
-
-       {
-               int rs, ds;
-
-               /* almost always 12*4096, but let's not take chances */
-               rs = ((SONIC_NUM_RRS * SONIC_RBSIZE + 4095) / 4096) * 4096;
-               /* almost always under a page, but let's not take chances */
-               ds = ((sizeof(struct sonic_local) + 4095) / 4096) * 4096;
-               kernel_set_cachemode(lp->rba, rs, IOMAP_NOCACHE_SER);
-               kernel_set_cachemode(lp, ds, IOMAP_NOCACHE_SER);
-       }
-       
-#if 0
-       flush_cache_all();
-#endif
+       lp->cda_laddr = lp->descriptors_laddr;
+       lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+       lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+       lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
 
        dev->open = sonic_open;
        dev->stop = sonic_close;
        dev->hard_start_xmit = sonic_send_packet;
        dev->get_stats = sonic_get_stats;
        dev->set_multicast_list = &sonic_multicast_list;
+       dev->tx_timeout = sonic_tx_timeout;
+       dev->watchdog_timeo = TX_TIMEOUT;
 
        /*
         * clear tally counter
         */
-       sonic_write(dev, SONIC_CRCT, 0xffff);
-       sonic_write(dev, SONIC_FAET, 0xffff);
-       sonic_write(dev, SONIC_MPT, 0xffff);
+       SONIC_WRITE(SONIC_CRCT, 0xffff);
+       SONIC_WRITE(SONIC_FAET, 0xffff);
+       SONIC_WRITE(SONIC_MPT, 0xffff);
 
        return 0;
 }
 
 int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
 {
+       struct sonic_local *lp = netdev_priv(dev);
        const int prom_addr = ONBOARD_SONIC_PROM_BASE;
        int i;
 
@@ -270,6 +197,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
           why this is so. */
        if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
            memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
+           memcmp(dev->dev_addr, "\x00\x80\x19", 3) &&
            memcmp(dev->dev_addr, "\x00\x05\x02", 3))
                bit_reverse_addr(dev->dev_addr);
        else
@@ -281,22 +209,23 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
            the card... */
        if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
            memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
+           memcmp(dev->dev_addr, "\x00\x80\x19", 3) &&
            memcmp(dev->dev_addr, "\x00\x05\x02", 3))
        {
                unsigned short val;
 
                printk(KERN_INFO "macsonic: PROM seems to be wrong, trying CAM entry 15\n");
                
-               sonic_write(dev, SONIC_CMD, SONIC_CR_RST);
-               sonic_write(dev, SONIC_CEP, 15);
+               SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
+               SONIC_WRITE(SONIC_CEP, 15);
 
-               val = sonic_read(dev, SONIC_CAP2);
+               val = SONIC_READ(SONIC_CAP2);
                dev->dev_addr[5] = val >> 8;
                dev->dev_addr[4] = val & 0xff;
-               val = sonic_read(dev, SONIC_CAP1);
+               val = SONIC_READ(SONIC_CAP1);
                dev->dev_addr[3] = val >> 8;
                dev->dev_addr[2] = val & 0xff;
-               val = sonic_read(dev, SONIC_CAP0);
+               val = SONIC_READ(SONIC_CAP0);
                dev->dev_addr[1] = val >> 8;
                dev->dev_addr[0] = val & 0xff;
                
@@ -311,6 +240,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
 
        if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
            memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
+           memcmp(dev->dev_addr, "\x00\x80\x19", 3) &&
            memcmp(dev->dev_addr, "\x00\x05\x02", 3))
        {
                /*
@@ -325,8 +255,9 @@ int __init mac_onboard_sonic_probe(struct net_device* dev)
 {
        /* Bwahahaha */
        static int once_is_more_than_enough;
-       int i;
-       int dma_bitmode;
+       struct sonic_local* lp = netdev_priv(dev);
+       int sr;
+       int commslot = 0;
        
        if (once_is_more_than_enough)
                return -ENODEV;
@@ -335,20 +266,18 @@ int __init mac_onboard_sonic_probe(struct net_device* dev)
        if (!MACH_IS_MAC)
                return -ENODEV;
 
-       printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. ");
-
        if (macintosh_config->ether_type != MAC_ETHER_SONIC)
-       {
-               printk("none.\n");
                return -ENODEV;
-       }
-
+       
+       printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. ");
+       
        /* Bogus probing, on the models which may or may not have
           Ethernet (BTW, the Ethernet *is* always at the same
           address, and nothing else lives there, at least if Apple's
           documentation is to be believed) */
        if (macintosh_config->ident == MAC_MODEL_Q630 ||
            macintosh_config->ident == MAC_MODEL_P588 ||
+           macintosh_config->ident == MAC_MODEL_P575 ||
            macintosh_config->ident == MAC_MODEL_C610) {
                unsigned long flags;
                int card_present;
@@ -361,13 +290,13 @@ int __init mac_onboard_sonic_probe(struct net_device* dev)
                        printk("none.\n");
                        return -ENODEV;
                }
+               commslot = 1;
        }
 
        printk("yes\n");        
 
-       /* Danger!  My arms are flailing wildly!  You *must* set this
-           before using sonic_read() */
-
+       /* Danger!  My arms are flailing wildly!  You *must* set lp->reg_offset
+        * and dev->base_addr before using SONIC_READ() or SONIC_WRITE() */
        dev->base_addr = ONBOARD_SONIC_REGISTERS;
        if (via_alt_mapping)
                dev->irq = IRQ_AUTO_3;
@@ -379,84 +308,66 @@ int __init mac_onboard_sonic_probe(struct net_device* dev)
                sonic_version_printed = 1;
        }
        printk(KERN_INFO "%s: onboard / comm-slot SONIC at 0x%08lx\n",
-              dev->name, dev->base_addr);
-
-       /* Now do a song and dance routine in an attempt to determine
-           the bus width */
+              lp->device->bus_id, dev->base_addr);
 
        /* The PowerBook's SONIC is 16 bit always. */
        if (macintosh_config->ident == MAC_MODEL_PB520) {
-               reg_offset = 0;
-               dma_bitmode = 0;
-       } else if (macintosh_config->ident == MAC_MODEL_C610) {
-               reg_offset = 0;
-               dma_bitmode = 1;
-       } else {
+               lp->reg_offset = 0;
+               lp->dma_bitmode = SONIC_BITMODE16;
+               sr = SONIC_READ(SONIC_SR);
+       } else if (commslot) {
                /* Some of the comm-slot cards are 16 bit.  But some
-                   of them are not.  The 32-bit cards use offset 2 and
-                   pad with zeroes or sometimes ones (I think...)
-                   Therefore, if we try offset 0 and get a silicon
-                   revision of 0, we assume 16 bit. */
-               int sr;
-
-               /* Technically this is not necessary since we zeroed
-                   it above */
-               reg_offset = 0;
-               dma_bitmode = 0;
-               sr = sonic_read(dev, SONIC_SR);
-               if (sr == 0 || sr == 0xffff) {
-                       reg_offset = 2;
-                       /* 83932 is 0x0004, 83934 is 0x0100 or 0x0101 */
-                       sr = sonic_read(dev, SONIC_SR);
-                       dma_bitmode = 1;
-                       
+                  of them are not.  The 32-bit cards use offset 2 and
+                  have known revisions, we try reading the revision
+                  register at offset 2, if we don't get a known revision
+                  we assume 16 bit at offset 0.  */
+               lp->reg_offset = 2;
+               lp->dma_bitmode = SONIC_BITMODE16;
+
+               sr = SONIC_READ(SONIC_SR);
+               if (sr == 0x0004 || sr == 0x0006 || sr == 0x0100 || sr == 0x0101) 
+                       /* 83932 is 0x0004 or 0x0006, 83934 is 0x0100 or 0x0101 */
+                       lp->dma_bitmode = SONIC_BITMODE32;
+               else {
+                       lp->dma_bitmode = SONIC_BITMODE16;
+                       lp->reg_offset = 0;
+                       sr = SONIC_READ(SONIC_SR);
                }
-               printk(KERN_INFO
-                      "%s: revision 0x%04x, using %d bit DMA and register offset %d\n",
-                      dev->name, sr, dma_bitmode?32:16, reg_offset);
+       } else {
+               /* All onboard cards are at offset 2 with 32 bit DMA. */
+               lp->reg_offset = 2;
+               lp->dma_bitmode = SONIC_BITMODE32;
+               sr = SONIC_READ(SONIC_SR);
        }
-       
+       printk(KERN_INFO
+              "%s: revision 0x%04x, using %d bit DMA and register offset %d\n",
+              lp->device->bus_id, sr, lp->dma_bitmode?32:16, lp->reg_offset);
 
-       /* this carries my sincere apologies -- by the time I got to updating
-          the driver, support for "reg_offsets" appeares nowhere in the sonic
-          code, going back for over a year.  Fortunately, my Mac does't seem
-          to use whatever this was.
+#if 0 /* This is sometimes useful to find out how MacOS configured the card. */
+       printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", lp->device->bus_id,
+              SONIC_READ(SONIC_DCR) & 0xffff, SONIC_READ(SONIC_DCR2) & 0xffff);
+#endif
 
-          If you know how this is supposed to be implemented, either fix it,
-          or contact me (sammy@oh.verio.com) to explain what it is. --Sam */
-          
-       if(reg_offset) {
-               printk("%s: register offset unsupported.  please fix this if you know what it is.\n", dev->name);
-               return -ENODEV;
-       }
-       
        /* Software reset, then initialize control registers. */
-       sonic_write(dev, SONIC_CMD, SONIC_CR_RST);
-       sonic_write(dev, SONIC_DCR, SONIC_DCR_BMS |
-                   SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS |
-                   (dma_bitmode ? SONIC_DCR_DW : 0));
+       SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
+
+       SONIC_WRITE(SONIC_DCR, SONIC_DCR_EXBUS | SONIC_DCR_BMS |
+                              SONIC_DCR_RFT1  | SONIC_DCR_TFT0 |
+                              (lp->dma_bitmode ? SONIC_DCR_DW : 0));
 
        /* This *must* be written back to in order to restore the
-           extended programmable output bits */
-       sonic_write(dev, SONIC_DCR2, 0);
+        * extended programmable output bits, as it may not have been
+        * initialised since the hardware reset. */
+       SONIC_WRITE(SONIC_DCR2, 0);
 
        /* Clear *and* disable interrupts to be on the safe side */
-       sonic_write(dev, SONIC_ISR,0x7fff);
-       sonic_write(dev, SONIC_IMR,0);
+       SONIC_WRITE(SONIC_IMR, 0);
+       SONIC_WRITE(SONIC_ISR, 0x7fff);
 
        /* Now look for the MAC address. */
        if (mac_onboard_sonic_ethernet_addr(dev) != 0)
                return -ENODEV;
 
-       printk(KERN_INFO "MAC ");
-       for (i = 0; i < 6; i++) {
-               printk("%2.2x", dev->dev_addr[i]);
-               if (i < 5)
-                       printk(":");
-       }
-
-       printk(" IRQ %d\n", dev->irq);
-
        /* Shared init code */
        return macsonic_init(dev);
 }
@@ -468,8 +379,10 @@ int __init mac_nubus_sonic_ethernet_addr(struct net_device* dev,
        int i;
        for(i = 0; i < 6; i++)
                dev->dev_addr[i] = SONIC_READ_PROM(i);
-       /* For now we are going to assume that they're all bit-reversed */
-       bit_reverse_addr(dev->dev_addr);
+
+       /* Some of the addresses are bit-reversed */
+       if (id != MACSONIC_DAYNA)
+               bit_reverse_addr(dev->dev_addr);
 
        return 0;
 }
@@ -487,6 +400,15 @@ int __init macsonic_ident(struct nubus_dev* ndev)
                else
                        return MACSONIC_APPLE;
        }
+       
+       if (ndev->dr_hw == NUBUS_DRHW_SMC9194 &&
+           ndev->dr_sw == NUBUS_DRSW_DAYNA)
+               return MACSONIC_DAYNA;
+       
+       if (ndev->dr_hw == NUBUS_DRHW_SONIC_LC &&
+           ndev->dr_sw == 0) { /* huh? */
+               return MACSONIC_APPLE16;
+       }
        return -1;
 }
 
@@ -494,12 +416,12 @@ int __init mac_nubus_sonic_probe(struct net_device* dev)
 {
        static int slots;
        struct nubus_dev* ndev = NULL;
+       struct sonic_local* lp = netdev_priv(dev);
        unsigned long base_addr, prom_addr;
        u16 sonic_dcr;
-       int id;
-       int i;
-       int dma_bitmode;
-
+       int id = -1;
+       int reg_offset, dma_bitmode;
+       
        /* Find the first SONIC that hasn't been initialized already */
        while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK,
                                       NUBUS_TYPE_ETHERNET, ndev)) != NULL)
@@ -521,51 +443,52 @@ int __init mac_nubus_sonic_probe(struct net_device* dev)
        case MACSONIC_DUODOCK:
                base_addr = ndev->board->slot_addr + DUODOCK_SONIC_REGISTERS;
                prom_addr = ndev->board->slot_addr + DUODOCK_SONIC_PROM_BASE;
-               sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT0 | SONIC_DCR_RFT1
-                       | SONIC_DCR_TFT0;
+               sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT0 | SONIC_DCR_RFT1 |
+                           SONIC_DCR_TFT0;
                reg_offset = 2;
-               dma_bitmode = 1;
+               dma_bitmode = SONIC_BITMODE32;
                break;
        case MACSONIC_APPLE:
                base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
                prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE;
                sonic_dcr = SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0;
                reg_offset = 0;
-               dma_bitmode = 1;
+               dma_bitmode = SONIC_BITMODE32;
                break;
        case MACSONIC_APPLE16:
                base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
                prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE;
-               sonic_dcr = SONIC_DCR_EXBUS
-                       | SONIC_DCR_RFT1 | SONIC_DCR_TFT0
-                       | SONIC_DCR_PO1 | SONIC_DCR_BMS; 
+               sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 |
+                           SONIC_DCR_PO1 | SONIC_DCR_BMS; 
                reg_offset = 0;
-               dma_bitmode = 0;
+               dma_bitmode = SONIC_BITMODE16;
                break;
        case MACSONIC_DAYNALINK:
                base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
                prom_addr = ndev->board->slot_addr + DAYNALINK_PROM_BASE;
-               sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0
-                       | SONIC_DCR_PO1 | SONIC_DCR_BMS; 
+               sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0 |
+                           SONIC_DCR_PO1 | SONIC_DCR_BMS; 
                reg_offset = 0;
-               dma_bitmode = 0;
+               dma_bitmode = SONIC_BITMODE16;
                break;
        case MACSONIC_DAYNA:
                base_addr = ndev->board->slot_addr + DAYNA_SONIC_REGISTERS;
                prom_addr = ndev->board->slot_addr + DAYNA_SONIC_MAC_ADDR;
-               sonic_dcr = SONIC_DCR_BMS
-                       | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1;
+               sonic_dcr = SONIC_DCR_BMS |
+                           SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1;
                reg_offset = 0;
-               dma_bitmode = 0;
+               dma_bitmode = SONIC_BITMODE16;
                break;
        default:
                printk(KERN_ERR "macsonic: WTF, id is %d\n", id);
                return -ENODEV;
        }
 
-       /* Danger!  My arms are flailing wildly!  You *must* set this
-           before using sonic_read() */
+       /* Danger!  My arms are flailing wildly!  You *must* set lp->reg_offset
+        * and dev->base_addr before using SONIC_READ() or SONIC_WRITE() */
        dev->base_addr = base_addr;
+       lp->reg_offset = reg_offset;
+       lp->dma_bitmode = dma_bitmode;
        dev->irq = SLOT2IRQ(ndev->board->slot);
 
        if (!sonic_version_printed) {
@@ -573,29 +496,66 @@ int __init mac_nubus_sonic_probe(struct net_device* dev)
                sonic_version_printed = 1;
        }
        printk(KERN_INFO "%s: %s in slot %X\n",
-              dev->name, ndev->board->name, ndev->board->slot);
+              lp->device->bus_id, ndev->board->name, ndev->board->slot);
        printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n",
-              dev->name, sonic_read(dev, SONIC_SR), dma_bitmode?32:16, reg_offset);
+              lp->device->bus_id, SONIC_READ(SONIC_SR), dma_bitmode?32:16, reg_offset);
 
-       if(reg_offset) {
-               printk("%s: register offset unsupported.  please fix this if you know what it is.\n", dev->name);
-               return -ENODEV;
-       }
+#if 0 /* This is sometimes useful to find out how MacOS configured the card. */
+       printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", lp->device->bus_id,
+              SONIC_READ(SONIC_DCR) & 0xffff, SONIC_READ(SONIC_DCR2) & 0xffff);
+#endif
 
        /* Software reset, then initialize control registers. */
-       sonic_write(dev, SONIC_CMD, SONIC_CR_RST);
-       sonic_write(dev, SONIC_DCR, sonic_dcr
-                   | (dma_bitmode ? SONIC_DCR_DW : 0));
+       SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
+       SONIC_WRITE(SONIC_DCR, sonic_dcr | (dma_bitmode ? SONIC_DCR_DW : 0));
+       /* This *must* be written back to in order to restore the
+        * extended programmable output bits, since it may not have been
+        * initialised since the hardware reset. */
+       SONIC_WRITE(SONIC_DCR2, 0);
 
        /* Clear *and* disable interrupts to be on the safe side */
-       sonic_write(dev, SONIC_ISR,0x7fff);
-       sonic_write(dev, SONIC_IMR,0);
+       SONIC_WRITE(SONIC_IMR, 0);
+       SONIC_WRITE(SONIC_ISR, 0x7fff);
 
        /* Now look for the MAC address. */
        if (mac_nubus_sonic_ethernet_addr(dev, prom_addr, id) != 0)
                return -ENODEV;
 
-       printk(KERN_INFO "MAC ");
+       /* Shared init code */
+       return macsonic_init(dev);
+}
+
+static int __init mac_sonic_probe(struct device *device)
+{
+       struct net_device *dev;
+       struct sonic_local *lp;
+       int err;
+       int i;
+
+       dev = alloc_etherdev(sizeof(struct sonic_local));
+       if (!dev)
+               return -ENOMEM;
+
+       lp = netdev_priv(dev);
+       lp->device = device;
+       SET_NETDEV_DEV(dev, device);
+       SET_MODULE_OWNER(dev);
+
+       /* This will catch fatal stuff like -ENOMEM as well as success */
+       err = mac_onboard_sonic_probe(dev);
+       if (err == 0)
+               goto found;
+       if (err != -ENODEV)
+               goto out;
+       err = mac_nubus_sonic_probe(dev);
+       if (err)
+               goto out;
+found:
+       err = register_netdev(dev);
+       if (err)
+               goto out;
+
+       printk("%s: MAC ", dev->name);
        for (i = 0; i < 6; i++) {
                printk("%2.2x", dev->dev_addr[i]);
                if (i < 5)
@@ -603,55 +563,95 @@ int __init mac_nubus_sonic_probe(struct net_device* dev)
        }
        printk(" IRQ %d\n", dev->irq);
 
-       /* Shared init code */
-       return macsonic_init(dev);
-}
+       return 0;
 
-#ifdef MODULE
-static struct net_device *dev_macsonic;
+out:
+       free_netdev(dev);
 
-MODULE_PARM(sonic_debug, "i");
+       return err;
+}
+
+MODULE_DESCRIPTION("Macintosh SONIC ethernet driver");
+module_param(sonic_debug, int, 0);
 MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)");
 
-int
-init_module(void)
+#define SONIC_IRQ_FLAG IRQ_FLG_FAST
+
+#include "sonic.c"
+
+static int __devexit mac_sonic_device_remove (struct device *device)
 {
-        dev_macsonic = macsonic_probe(-1);
-       if (IS_ERR(dev_macsonic)) {
-                printk(KERN_WARNING "macsonic.c: No card found\n");
-               return PTR_ERR(dev_macsonic);
-       }
+       struct net_device *dev = device->driver_data;
+       struct sonic_local* lp = netdev_priv(dev);
+
+       unregister_netdev (dev);
+       dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
+                         lp->descriptors, lp->descriptors_laddr);
+       free_netdev (dev);
+
        return 0;
 }
 
-void
-cleanup_module(void)
+static struct device_driver mac_sonic_driver = {
+       .name   = mac_sonic_string,
+       .bus    = &platform_bus_type,
+       .probe  = mac_sonic_probe,
+       .remove = __devexit_p(mac_sonic_device_remove),
+};
+
+static void mac_sonic_platform_release(struct device *device)
 {
-       unregister_netdev(dev_macsonic);
-       kfree(dev_macsonic->priv);
-       free_netdev(dev_macsonic);
+       struct platform_device *pldev;
+
+       /* free device */
+       pldev = to_platform_device (device);
+       kfree (pldev);
 }
-#endif /* MODULE */
 
+static int __init mac_sonic_init_module(void)
+{
+       struct platform_device *pldev;
+       int err;
 
-#define vdma_alloc(foo, bar) ((u32)foo)
-#define vdma_free(baz)
-#define sonic_chiptomem(bat) (bat)
-#define PHYSADDR(quux) (quux)
-#define CPHYSADDR(quux) (quux)
+       if ((err = driver_register(&mac_sonic_driver))) {
+               printk(KERN_ERR "Driver registration failed\n");
+               return err;
+       }
 
-#define sonic_request_irq       request_irq
-#define sonic_free_irq          free_irq
+       mac_sonic_device = NULL;
 
-#include "sonic.c"
+       if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) {
+               goto out_unregister;
+       }
 
-/*
- * Local variables:
- *  compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h   -c -o macsonic.o macsonic.c"
- *  version-control: t
- *  kept-new-versions: 5
- *  c-indent-level: 8
- *  tab-width: 8
- * End:
- *
- */
+       memset(pldev, 0, sizeof (*pldev));
+       pldev->name             = mac_sonic_string;
+       pldev->id               = 0;
+       pldev->dev.release      = mac_sonic_platform_release;
+       mac_sonic_device        = pldev;
+
+       if (platform_device_register (pldev)) {
+               kfree(pldev);
+               mac_sonic_device = NULL;
+       }
+
+       return 0;
+
+out_unregister:
+       platform_device_unregister(pldev);
+
+       return -ENOMEM;
+}
+
+static void __exit mac_sonic_cleanup_module(void)
+{
+       driver_unregister(&mac_sonic_driver);
+
+       if (mac_sonic_device) {
+               platform_device_unregister(mac_sonic_device);
+               mac_sonic_device = NULL;
+       }
+}
+
+module_init(mac_sonic_init_module);
+module_exit(mac_sonic_cleanup_module);
index 0405e1f0d3df183fe004173091aed6ca103751e4..7c9dbc8c9423ae005a5be12175dc3c33397b367c 100644 (file)
 
 #define INT_CAUSE_UNMASK_ALL           0x0007ffff
 #define INT_CAUSE_UNMASK_ALL_EXT       0x0011ffff
-#ifdef MV643XX_RX_QUEUE_FILL_ON_TASK
 #define INT_CAUSE_MASK_ALL             0x00000000
+#define INT_CAUSE_MASK_ALL_EXT         0x00000000
 #define INT_CAUSE_CHECK_BITS           INT_CAUSE_UNMASK_ALL
 #define INT_CAUSE_CHECK_BITS_EXT       INT_CAUSE_UNMASK_ALL_EXT
-#endif
 
 #ifdef MV643XX_CHECKSUM_OFFLOAD_TX
 #define MAX_DESCS_PER_SKB      (MAX_SKB_FRAGS + 1)
@@ -259,14 +258,13 @@ static void mv643xx_eth_update_mac_address(struct net_device *dev)
 static void mv643xx_eth_set_rx_mode(struct net_device *dev)
 {
        struct mv643xx_private *mp = netdev_priv(dev);
-       u32 config_reg;
 
-       config_reg = ethernet_get_config_reg(mp->port_num);
        if (dev->flags & IFF_PROMISC)
-               config_reg |= (u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
+               mp->port_config |= (u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
        else
-               config_reg &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
-       ethernet_set_config_reg(mp->port_num, config_reg);
+               mp->port_config &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
+
+       mv_write(MV643XX_ETH_PORT_CONFIG_REG(mp->port_num), mp->port_config);
 }
 
 /*
@@ -369,15 +367,6 @@ static int mv643xx_eth_free_tx_queue(struct net_device *dev,
 
                        dev_kfree_skb_irq(pkt_info.return_info);
                        released = 0;
-
-                       /*
-                        * Decrement the number of outstanding skbs counter on
-                        * the TX queue.
-                        */
-                       if (mp->tx_ring_skbs == 0)
-                               panic("ERROR - TX outstanding SKBs"
-                                               " counter is corrupted");
-                       mp->tx_ring_skbs--;
                } else
                        dma_unmap_page(NULL, pkt_info.buf_ptr,
                                        pkt_info.byte_cnt, DMA_TO_DEVICE);
@@ -412,15 +401,13 @@ static int mv643xx_eth_receive_queue(struct net_device *dev)
        struct pkt_info pkt_info;
 
 #ifdef MV643XX_NAPI
-       while (eth_port_receive(mp, &pkt_info) == ETH_OK && budget > 0) {
+       while (budget-- > 0 && eth_port_receive(mp, &pkt_info) == ETH_OK) {
 #else
        while (eth_port_receive(mp, &pkt_info) == ETH_OK) {
 #endif
                mp->rx_ring_skbs--;
                received_packets++;
-#ifdef MV643XX_NAPI
-               budget--;
-#endif
+
                /* Update statistics. Note byte count includes 4 byte CRC count */
                stats->rx_packets++;
                stats->rx_bytes += pkt_info.byte_cnt;
@@ -1044,9 +1031,6 @@ static void mv643xx_tx(struct net_device *dev)
                                                DMA_TO_DEVICE);
 
                        dev_kfree_skb_irq(pkt_info.return_info);
-
-                       if (mp->tx_ring_skbs)
-                               mp->tx_ring_skbs--;
                } else
                        dma_unmap_page(NULL, pkt_info.buf_ptr,
                                        pkt_info.byte_cnt, DMA_TO_DEVICE);
@@ -1157,16 +1141,20 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (!skb_shinfo(skb)->nr_frags) {
 linear:
                if (skb->ip_summed != CHECKSUM_HW) {
+                       /* Errata BTS #50, IHL must be 5 if no HW checksum */
                        pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT |
-                                       ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC;
+                                          ETH_TX_FIRST_DESC |
+                                          ETH_TX_LAST_DESC |
+                                          5 << ETH_TX_IHL_SHIFT;
                        pkt_info.l4i_chk = 0;
                } else {
-                       u32 ipheader = skb->nh.iph->ihl << 11;
 
                        pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT |
-                                       ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC |
-                                       ETH_GEN_TCP_UDP_CHECKSUM |
-                                       ETH_GEN_IP_V_4_CHECKSUM | ipheader;
+                                          ETH_TX_FIRST_DESC |
+                                          ETH_TX_LAST_DESC |
+                                          ETH_GEN_TCP_UDP_CHECKSUM |
+                                          ETH_GEN_IP_V_4_CHECKSUM |
+                                          skb->nh.iph->ihl << ETH_TX_IHL_SHIFT;
                        /* CPU already calculated pseudo header checksum. */
                        if (skb->nh.iph->protocol == IPPROTO_UDP) {
                                pkt_info.cmd_sts |= ETH_UDP_FRAME;
@@ -1185,7 +1173,6 @@ linear:
                pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len,
                                                        DMA_TO_DEVICE);
                pkt_info.return_info = skb;
-               mp->tx_ring_skbs++;
                status = eth_port_send(mp, &pkt_info);
                if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL))
                        printk(KERN_ERR "%s: Error on transmitting packet\n",
@@ -1193,7 +1180,6 @@ linear:
                stats->tx_bytes += pkt_info.byte_cnt;
        } else {
                unsigned int frag;
-               u32 ipheader;
 
                /* Since hardware can't handle unaligned fragments smaller
                 * than 9 bytes, if we find any, we linearize the skb
@@ -1222,12 +1208,16 @@ linear:
                                                        DMA_TO_DEVICE);
                pkt_info.l4i_chk = 0;
                pkt_info.return_info = 0;
-               pkt_info.cmd_sts = ETH_TX_FIRST_DESC;
 
-               if (skb->ip_summed == CHECKSUM_HW) {
-                       ipheader = skb->nh.iph->ihl << 11;
-                       pkt_info.cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM |
-                                       ETH_GEN_IP_V_4_CHECKSUM | ipheader;
+               if (skb->ip_summed != CHECKSUM_HW)
+                       /* Errata BTS #50, IHL must be 5 if no HW checksum */
+                       pkt_info.cmd_sts = ETH_TX_FIRST_DESC |
+                                          5 << ETH_TX_IHL_SHIFT;
+               else {
+                       pkt_info.cmd_sts = ETH_TX_FIRST_DESC |
+                                          ETH_GEN_TCP_UDP_CHECKSUM |
+                                          ETH_GEN_IP_V_4_CHECKSUM |
+                                          skb->nh.iph->ihl << ETH_TX_IHL_SHIFT;
                        /* CPU already calculated pseudo header checksum. */
                        if (skb->nh.iph->protocol == IPPROTO_UDP) {
                                pkt_info.cmd_sts |= ETH_UDP_FRAME;
@@ -1267,7 +1257,6 @@ linear:
                                pkt_info.cmd_sts |= ETH_TX_ENABLE_INTERRUPT |
                                                        ETH_TX_LAST_DESC;
                                pkt_info.return_info = skb;
-                               mp->tx_ring_skbs++;
                        } else {
                                pkt_info.return_info = 0;
                        }
@@ -1304,7 +1293,6 @@ linear:
        pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len,
                                                                DMA_TO_DEVICE);
        pkt_info.return_info = skb;
-       mp->tx_ring_skbs++;
        status = eth_port_send(mp, &pkt_info);
        if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL))
                printk(KERN_ERR "%s: Error on transmitting packet\n",
@@ -1349,6 +1337,43 @@ static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev)
        return &mp->stats;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static inline void mv643xx_enable_irq(struct mv643xx_private *mp)
+{
+       int port_num = mp->port_num;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mp->lock, flags);
+       mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
+                                       INT_CAUSE_UNMASK_ALL);
+       mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num),
+                                       INT_CAUSE_UNMASK_ALL_EXT);
+       spin_unlock_irqrestore(&mp->lock, flags);
+}
+
+static inline void mv643xx_disable_irq(struct mv643xx_private *mp)
+{
+       int port_num = mp->port_num;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mp->lock, flags);
+       mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
+                                       INT_CAUSE_MASK_ALL);
+       mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num),
+                                       INT_CAUSE_MASK_ALL_EXT);
+       spin_unlock_irqrestore(&mp->lock, flags);
+}
+
+static void mv643xx_netpoll(struct net_device *netdev)
+{
+       struct mv643xx_private *mp = netdev_priv(netdev);
+
+       mv643xx_disable_irq(mp);
+       mv643xx_eth_int_handler(netdev->irq, netdev, NULL);
+       mv643xx_enable_irq(mp);
+}
+#endif
+
 /*/
  * mv643xx_eth_probe
  *
@@ -1399,6 +1424,10 @@ static int mv643xx_eth_probe(struct device *ddev)
        dev->weight = 64;
 #endif
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       dev->poll_controller = mv643xx_netpoll;
+#endif
+
        dev->watchdog_timeo = 2 * HZ;
        dev->tx_queue_len = mp->tx_ring_size;
        dev->base_addr = 0;
@@ -1876,6 +1905,9 @@ static void eth_port_start(struct mv643xx_private *mp)
        /* Enable port Rx. */
        mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num),
                                                mp->port_rx_queue_command);
+
+       /* Disable port bandwidth limits by clearing MTU register */
+       mv_write(MV643XX_ETH_MAXIMUM_TRANSMIT_UNIT(port_num), 0);
 }
 
 /*
@@ -2285,34 +2317,6 @@ static void eth_port_reset(unsigned int port_num)
        mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), reg_data);
 }
 
-/*
- * ethernet_set_config_reg - Set specified bits in configuration register.
- *
- * DESCRIPTION:
- *     This function sets specified bits in the given ethernet
- *     configuration register.
- *
- * INPUT:
- *     unsigned int    eth_port_num    Ethernet Port number.
- *     unsigned int    value           32 bit value.
- *
- * OUTPUT:
- *     The set bits in the value parameter are set in the configuration
- *     register.
- *
- * RETURN:
- *     None.
- *
- */
-static void ethernet_set_config_reg(unsigned int eth_port_num,
-                                                       unsigned int value)
-{
-       unsigned int eth_config_reg;
-
-       eth_config_reg = mv_read(MV643XX_ETH_PORT_CONFIG_REG(eth_port_num));
-       eth_config_reg |= value;
-       mv_write(MV643XX_ETH_PORT_CONFIG_REG(eth_port_num), eth_config_reg);
-}
 
 static int eth_port_autoneg_supported(unsigned int eth_port_num)
 {
@@ -2338,31 +2342,6 @@ static int eth_port_link_is_up(unsigned int eth_port_num)
        return 0;
 }
 
-/*
- * ethernet_get_config_reg - Get the port configuration register
- *
- * DESCRIPTION:
- *     This function returns the configuration register value of the given
- *     ethernet port.
- *
- * INPUT:
- *     unsigned int    eth_port_num    Ethernet Port number.
- *
- * OUTPUT:
- *     None.
- *
- * RETURN:
- *     Port configuration register value.
- */
-static unsigned int ethernet_get_config_reg(unsigned int eth_port_num)
-{
-       unsigned int eth_config_reg;
-
-       eth_config_reg = mv_read(MV643XX_ETH_PORT_CONFIG_EXTEND_REG
-                                                               (eth_port_num));
-       return eth_config_reg;
-}
-
 /*
  * eth_port_read_smi_reg - Read PHY registers
  *
@@ -2521,6 +2500,9 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
                return ETH_ERROR;
        }
 
+       mp->tx_ring_skbs++;
+       BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size);
+
        /* Get the Tx Desc ring indexes */
        tx_desc_curr = mp->tx_curr_desc_q;
        tx_desc_used = mp->tx_used_desc_q;
@@ -2587,6 +2569,9 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
        if (mp->tx_resource_err)
                return ETH_QUEUE_FULL;
 
+       mp->tx_ring_skbs++;
+       BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size);
+
        /* Get the Tx Desc ring indexes */
        tx_desc_curr = mp->tx_curr_desc_q;
        tx_desc_used = mp->tx_used_desc_q;
@@ -2687,6 +2672,9 @@ static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp,
        /* Any Tx return cancels the Tx resource error status */
        mp->tx_resource_err = 0;
 
+       BUG_ON(mp->tx_ring_skbs == 0);
+       mp->tx_ring_skbs--;
+
        return ETH_OK;
 }
 
index 57c4f8fbfdb62648cee570b4dab6553c4f4c8da9..bcfda5192da02ef83fbe86e9a61c6a375221984b 100644 (file)
@@ -49,7 +49,7 @@
 /* Checksum offload for Tx works for most packets, but
  * fails if previous packet sent did not use hw csum
  */
-#undef MV643XX_CHECKSUM_OFFLOAD_TX
+#define        MV643XX_CHECKSUM_OFFLOAD_TX
 #define        MV643XX_NAPI
 #define        MV643XX_TX_FAST_REFILL
 #undef MV643XX_RX_QUEUE_FILL_ON_TASK   /* Does not work, yet */
 #define ETH_TX_ENABLE_INTERRUPT                        (BIT23)
 #define ETH_AUTO_MODE                          (BIT30)
 
+#define ETH_TX_IHL_SHIFT                       11
+
 /* typedefs */
 
 typedef enum _eth_func_ret_status {
@@ -406,10 +408,6 @@ static void eth_port_init(struct mv643xx_private *mp);
 static void eth_port_reset(unsigned int eth_port_num);
 static void eth_port_start(struct mv643xx_private *mp);
 
-static void ethernet_set_config_reg(unsigned int eth_port_num,
-                                   unsigned int value);
-static unsigned int ethernet_get_config_reg(unsigned int eth_port_num);
-
 /* Port MAC address routines */
 static void eth_port_uc_addr_set(unsigned int eth_port_num,
                                 unsigned char *p_addr);
index 6c92f09690151cbb4233fd4a56b6ec9a2e165314..73501d846588bb58126e3eb59edb9b92d567be96 100644 (file)
@@ -26,9 +26,6 @@
        Updated to EISA probing API 5/2003 by Marc Zyngier.
 */
 
-static const char *version =
-       "ne3210.c: Driver revision v0.03, 30/09/98\n";
-
 #include <linux/module.h>
 #include <linux/eisa.h>
 #include <linux/kernel.h>
@@ -197,7 +194,7 @@ static int __init ne3210_eisa_probe (struct device *device)
        ei_status.priv = phys_mem;
 
        if (ei_debug > 0)
-               printk(version);
+               printk("ne3210 loaded.\n");
 
        ei_status.reset_8390 = &ne3210_reset_8390;
        ei_status.block_input = &ne3210_block_input;
@@ -360,12 +357,12 @@ MODULE_DESCRIPTION("NE3210 EISA Ethernet driver");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(eisa, ne3210_ids);
 
-int ne3210_init(void)
+static int ne3210_init(void)
 {
        return eisa_driver_register (&ne3210_eisa_driver);
 }
 
-void ne3210_cleanup(void)
+static void ne3210_cleanup(void)
 {
        eisa_driver_unregister (&ne3210_eisa_driver);
 }
index 4a391ea0f58aaa4771975a5eff2e0ce338e9dd54..a1ac4bd1696eae7d909729aaca014edbf919cedf 100644 (file)
@@ -486,9 +486,9 @@ struct netdrv_private {
 MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
 MODULE_DESCRIPTION ("Skeleton for a PCI Fast Ethernet driver");
 MODULE_LICENSE("GPL");
-MODULE_PARM (multicast_filter_limit, "i");
-MODULE_PARM (max_interrupt_work, "i");
-MODULE_PARM (media, "1-" __MODULE_STRING(8) "i");
+module_param(multicast_filter_limit, int, 0);
+module_param(max_interrupt_work, int, 0);
+module_param_array(media, int, NULL, 0);
 MODULE_PARM_DESC (multicast_filter_limit, "pci-skeleton maximum number of filtered multicast addresses");
 MODULE_PARM_DESC (max_interrupt_work, "pci-skeleton maximum events handled per interrupt");
 MODULE_PARM_DESC (media, "pci-skeleton: Bits 0-3: media type, bit 17: full duplex");
index 9d8197bb293ac74b39c315ca42302d2c9d051300..384a736a0d2f820f5c6a7fcce3306d8e6ff04264 100644 (file)
@@ -134,7 +134,7 @@ typedef struct local_info_t {
     u_char mc_filter[8];
 } local_info_t;
 
-#define MC_FILTERBREAK 64
+#define MC_FILTERBREAK 8
 
 /*====================================================================*/
 /* 
@@ -1012,7 +1012,7 @@ static void fjn_reset(struct net_device *dev)
        outb(BANK_1U, ioaddr + CONFIG_1);
 
     /* set the multicast table to accept none. */
-    for (i = 0; i < 6; i++) 
+    for (i = 0; i < 8; i++) 
         outb(0x00, ioaddr + MAR_ADR + i);
 
     /* Switch to bank 2 (runtime mode) */
@@ -1269,6 +1269,16 @@ static void set_rx_mode(struct net_device *dev)
     u_long flags;
     int i;
     
+    int saved_config_0 = inb(ioaddr + CONFIG_0);
+     
+    local_irq_save(flags); 
+
+    /* Disable Tx and Rx */
+    if (sram_config == 0) 
+       outb(CONFIG0_RST, ioaddr + CONFIG_0);
+    else
+       outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
+
     if (dev->flags & IFF_PROMISC) {
        /* Unconditionally log net taps. */
        printk("%s: Promiscuous mode enabled.\n", dev->name);
@@ -1290,20 +1300,23 @@ static void set_rx_mode(struct net_device *dev)
        for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
             i++, mclist = mclist->next) {
            unsigned int bit =
-               ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f;
-           mc_filter[bit >> 3] |= (1 << bit);
+               ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 26;
+           mc_filter[bit >> 3] |= (1 << (bit & 7));
        }
+       outb(2, ioaddr + RX_MODE);      /* Use normal mode. */
     }
 
-    local_irq_save(flags); 
     if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) {
        int saved_bank = inb(ioaddr + CONFIG_1);
        /* Switch to bank 1 and set the multicast table. */
        outb(0xe4, ioaddr + CONFIG_1);
        for (i = 0; i < 8; i++)
-           outb(mc_filter[i], ioaddr + 8 + i);
+           outb(mc_filter[i], ioaddr + MAR_ADR + i);
        memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter));
        outb(saved_bank, ioaddr + CONFIG_1);
     }
+
+    outb(saved_config_0, ioaddr + CONFIG_0);
+
     local_irq_restore(flags);
 }
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
new file mode 100644 (file)
index 0000000..14f4de1
--- /dev/null
@@ -0,0 +1,57 @@
+#
+# PHY Layer Configuration
+#
+
+menu "PHY device support"
+
+config PHYLIB
+       tristate "PHY Device support and infrastructure"
+       depends on NET_ETHERNET && (BROKEN || !ARCH_S390)
+       help
+         Ethernet controllers are usually attached to PHY
+         devices.  This option provides infrastructure for
+         managing PHY devices.
+
+config PHYCONTROL
+       bool "  Support for automatically handling PHY state changes"
+       depends on PHYLIB
+       help
+         Adds code to perform all the work for keeping PHY link
+         state (speed/duplex/etc) up-to-date.  Also handles
+         interrupts.
+
+comment "MII PHY device drivers"
+       depends on PHYLIB
+
+config MARVELL_PHY
+       tristate "Drivers for Marvell PHYs"
+       depends on PHYLIB
+       ---help---
+         Currently has a driver for the 88E1011S
+       
+config DAVICOM_PHY
+       tristate "Drivers for Davicom PHYs"
+       depends on PHYLIB
+       ---help---
+         Currently supports dm9161e and dm9131
+
+config QSEMI_PHY
+       tristate "Drivers for Quality Semiconductor PHYs"
+       depends on PHYLIB
+       ---help---
+         Currently supports the qs6612
+
+config LXT_PHY
+       tristate "Drivers for the Intel LXT PHYs"
+       depends on PHYLIB
+       ---help---
+         Currently supports the lxt970, lxt971
+
+config CICADA_PHY
+       tristate "Drivers for the Cicada PHYs"
+       depends on PHYLIB
+       ---help---
+         Currently supports the cis8204
+
+endmenu
+
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
new file mode 100644 (file)
index 0000000..e4116a5
--- /dev/null
@@ -0,0 +1,10 @@
+# Makefile for Linux PHY drivers
+
+libphy-objs                    := phy.o phy_device.o mdio_bus.o
+
+obj-$(CONFIG_PHYLIB)           += libphy.o
+obj-$(CONFIG_MARVELL_PHY)      += marvell.o
+obj-$(CONFIG_DAVICOM_PHY)      += davicom.o
+obj-$(CONFIG_CICADA_PHY)       += cicada.o
+obj-$(CONFIG_LXT_PHY)          += lxt.o
+obj-$(CONFIG_QSEMI_PHY)                += qsemi.o
diff --git a/drivers/net/phy/cicada.c b/drivers/net/phy/cicada.c
new file mode 100644 (file)
index 0000000..c47fb2e
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * drivers/net/phy/cicada.c
+ *
+ * Driver for Cicada PHYs
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/* Cicada Extended Control Register 1 */
+#define MII_CIS8201_EXT_CON1           0x17
+#define MII_CIS8201_EXTCON1_INIT       0x0000
+
+/* Cicada Interrupt Mask Register */
+#define MII_CIS8201_IMASK              0x19
+#define MII_CIS8201_IMASK_IEN          0x8000
+#define MII_CIS8201_IMASK_SPEED        0x4000
+#define MII_CIS8201_IMASK_LINK         0x2000
+#define MII_CIS8201_IMASK_DUPLEX       0x1000
+#define MII_CIS8201_IMASK_MASK         0xf000
+
+/* Cicada Interrupt Status Register */
+#define MII_CIS8201_ISTAT              0x1a
+#define MII_CIS8201_ISTAT_STATUS       0x8000
+#define MII_CIS8201_ISTAT_SPEED        0x4000
+#define MII_CIS8201_ISTAT_LINK         0x2000
+#define MII_CIS8201_ISTAT_DUPLEX       0x1000
+
+/* Cicada Auxiliary Control/Status Register */
+#define MII_CIS8201_AUX_CONSTAT        0x1c
+#define MII_CIS8201_AUXCONSTAT_INIT    0x0004
+#define MII_CIS8201_AUXCONSTAT_DUPLEX  0x0020
+#define MII_CIS8201_AUXCONSTAT_SPEED   0x0018
+#define MII_CIS8201_AUXCONSTAT_GBIT    0x0010
+#define MII_CIS8201_AUXCONSTAT_100     0x0008
+
+MODULE_DESCRIPTION("Cicadia PHY driver");
+MODULE_AUTHOR("Andy Fleming");
+MODULE_LICENSE("GPL");
+
+static int cis820x_config_init(struct phy_device *phydev)
+{
+       int err;
+
+       err = phy_write(phydev, MII_CIS8201_AUX_CONSTAT,
+                       MII_CIS8201_AUXCONSTAT_INIT);
+
+       if (err < 0)
+               return err;
+
+       err = phy_write(phydev, MII_CIS8201_EXT_CON1,
+                       MII_CIS8201_EXTCON1_INIT);
+
+       return err;
+}
+
+static int cis820x_ack_interrupt(struct phy_device *phydev)
+{
+       int err = phy_read(phydev, MII_CIS8201_ISTAT);
+
+       return (err < 0) ? err : 0;
+}
+
+static int cis820x_config_intr(struct phy_device *phydev)
+{
+       int err;
+
+       if(phydev->interrupts == PHY_INTERRUPT_ENABLED)
+               err = phy_write(phydev, MII_CIS8201_IMASK, 
+                               MII_CIS8201_IMASK_MASK);
+       else
+               err = phy_write(phydev, MII_CIS8201_IMASK, 0);
+
+       return err;
+}
+
+/* Cicada 820x */
+static struct phy_driver cis8204_driver = {
+       .phy_id         = 0x000fc440,
+       .name           = "Cicada Cis8204",
+       .phy_id_mask    = 0x000fffc0,
+       .features       = PHY_GBIT_FEATURES,
+       .flags          = PHY_HAS_INTERRUPT,
+       .config_init    = &cis820x_config_init,
+       .config_aneg    = &genphy_config_aneg,
+       .read_status    = &genphy_read_status,
+       .ack_interrupt  = &cis820x_ack_interrupt,
+       .config_intr    = &cis820x_config_intr,
+       .driver         = { .owner = THIS_MODULE,},
+};
+
+static int __init cis8204_init(void)
+{
+       return phy_driver_register(&cis8204_driver);
+}
+
+static void __exit cis8204_exit(void)
+{
+       phy_driver_unregister(&cis8204_driver);
+}
+
+module_init(cis8204_init);
+module_exit(cis8204_exit);
diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c
new file mode 100644 (file)
index 0000000..6caf499
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * drivers/net/phy/davicom.c
+ *
+ * Driver for Davicom PHYs
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#define MII_DM9161_SCR         0x10
+#define MII_DM9161_SCR_INIT    0x0610
+
+/* DM9161 Interrupt Register */
+#define MII_DM9161_INTR        0x15
+#define MII_DM9161_INTR_PEND           0x8000
+#define MII_DM9161_INTR_DPLX_MASK      0x0800
+#define MII_DM9161_INTR_SPD_MASK       0x0400
+#define MII_DM9161_INTR_LINK_MASK      0x0200
+#define MII_DM9161_INTR_MASK           0x0100
+#define MII_DM9161_INTR_DPLX_CHANGE    0x0010
+#define MII_DM9161_INTR_SPD_CHANGE     0x0008
+#define MII_DM9161_INTR_LINK_CHANGE    0x0004
+#define MII_DM9161_INTR_INIT           0x0000
+#define MII_DM9161_INTR_STOP   \
+(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \
+ | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
+
+/* DM9161 10BT Configuration/Status */
+#define MII_DM9161_10BTCSR     0x12
+#define MII_DM9161_10BTCSR_INIT        0x7800
+
+MODULE_DESCRIPTION("Davicom PHY driver");
+MODULE_AUTHOR("Andy Fleming");
+MODULE_LICENSE("GPL");
+
+
+#define DM9161_DELAY 1
+static int dm9161_config_intr(struct phy_device *phydev)
+{
+       int temp;
+
+       temp = phy_read(phydev, MII_DM9161_INTR);
+
+       if (temp < 0)
+               return temp;
+
+       if(PHY_INTERRUPT_ENABLED == phydev->interrupts )
+               temp &= ~(MII_DM9161_INTR_STOP);
+       else
+               temp |= MII_DM9161_INTR_STOP;
+
+       temp = phy_write(phydev, MII_DM9161_INTR, temp);
+
+       return temp;
+}
+
+static int dm9161_config_aneg(struct phy_device *phydev)
+{
+       int err;
+
+       /* Isolate the PHY */
+       err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE);
+
+       if (err < 0)
+               return err;
+
+       /* Configure the new settings */
+       err = genphy_config_aneg(phydev);
+
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int dm9161_config_init(struct phy_device *phydev)
+{
+       int err;
+
+       /* Isolate the PHY */
+       err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE);
+
+       if (err < 0)
+               return err;
+
+       /* Do not bypass the scrambler/descrambler */
+       err = phy_write(phydev, MII_DM9161_SCR, MII_DM9161_SCR_INIT);
+
+       if (err < 0)
+               return err;
+
+       /* Clear 10BTCSR to default */
+       err = phy_write(phydev, MII_DM9161_10BTCSR, MII_DM9161_10BTCSR_INIT);
+
+       if (err < 0)
+               return err;
+
+       /* Reconnect the PHY, and enable Autonegotiation */
+       err = phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
+
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int dm9161_ack_interrupt(struct phy_device *phydev)
+{
+       int err = phy_read(phydev, MII_DM9161_INTR);
+
+       return (err < 0) ? err : 0;
+}
+
+static struct phy_driver dm9161_driver = {
+       .phy_id         = 0x0181b880,
+       .name           = "Davicom DM9161E",
+       .phy_id_mask    = 0x0ffffff0,
+       .features       = PHY_BASIC_FEATURES,
+       .config_init    = dm9161_config_init,
+       .config_aneg    = dm9161_config_aneg,
+       .read_status    = genphy_read_status,
+       .driver         = { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver dm9131_driver = {
+       .phy_id         = 0x00181b80,
+       .name           = "Davicom DM9131",
+       .phy_id_mask    = 0x0ffffff0,
+       .features       = PHY_BASIC_FEATURES,
+       .flags          = PHY_HAS_INTERRUPT,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .ack_interrupt  = dm9161_ack_interrupt,
+       .config_intr    = dm9161_config_intr,
+       .driver         = { .owner = THIS_MODULE,},
+};
+
+static int __init davicom_init(void)
+{
+       int ret;
+
+       ret = phy_driver_register(&dm9161_driver);
+       if (ret)
+               goto err1;
+
+       ret = phy_driver_register(&dm9131_driver);
+       if (ret)
+               goto err2;
+       return 0;
+
+ err2: 
+       phy_driver_unregister(&dm9161_driver);
+ err1:
+       return ret;
+}
+
+static void __exit davicom_exit(void)
+{
+       phy_driver_unregister(&dm9161_driver);
+       phy_driver_unregister(&dm9131_driver);
+}
+
+module_init(davicom_init);
+module_exit(davicom_exit);
diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c
new file mode 100644 (file)
index 0000000..4c84044
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * drivers/net/phy/lxt.c
+ *
+ * Driver for Intel LXT PHYs
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/* The Level one LXT970 is used by many boards                              */
+
+#define MII_LXT970_IER       17  /* Interrupt Enable Register */
+
+#define MII_LXT970_IER_IEN     0x0002
+
+#define MII_LXT970_ISR       18  /* Interrupt Status Register */
+
+#define MII_LXT970_CONFIG    19  /* Configuration Register    */
+
+/* ------------------------------------------------------------------------- */
+/* The Level one LXT971 is used on some of my custom boards                  */
+
+/* register definitions for the 971 */
+#define MII_LXT971_IER         18  /* Interrupt Enable Register */
+#define MII_LXT971_IER_IEN     0x00f2
+
+#define MII_LXT971_ISR         19  /* Interrupt Status Register */
+
+
+MODULE_DESCRIPTION("Intel LXT PHY driver");
+MODULE_AUTHOR("Andy Fleming");
+MODULE_LICENSE("GPL");
+
+static int lxt970_ack_interrupt(struct phy_device *phydev)
+{
+       int err;
+
+       err = phy_read(phydev, MII_BMSR);
+
+       if (err < 0)
+               return err;
+
+       err = phy_read(phydev, MII_LXT970_ISR);
+
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int lxt970_config_intr(struct phy_device *phydev)
+{
+       int err;
+
+       if(phydev->interrupts == PHY_INTERRUPT_ENABLED)
+               err = phy_write(phydev, MII_LXT970_IER, MII_LXT970_IER_IEN);
+       else
+               err = phy_write(phydev, MII_LXT970_IER, 0);
+
+       return err;
+}
+
+static int lxt970_config_init(struct phy_device *phydev)
+{
+       int err;
+
+       err = phy_write(phydev, MII_LXT970_CONFIG, 0);
+
+       return err;
+}
+
+
+static int lxt971_ack_interrupt(struct phy_device *phydev)
+{
+       int err = phy_read(phydev, MII_LXT971_ISR);
+
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int lxt971_config_intr(struct phy_device *phydev)
+{
+       int err;
+
+       if(phydev->interrupts == PHY_INTERRUPT_ENABLED)
+               err = phy_write(phydev, MII_LXT971_IER, MII_LXT971_IER_IEN);
+       else
+               err = phy_write(phydev, MII_LXT971_IER, 0);
+
+       return err;
+}
+
+static struct phy_driver lxt970_driver = {
+       .phy_id         = 0x07810000,
+       .name           = "LXT970",
+       .phy_id_mask    = 0x0fffffff,
+       .features       = PHY_BASIC_FEATURES,
+       .flags          = PHY_HAS_INTERRUPT,
+       .config_init    = lxt970_config_init,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .ack_interrupt  = lxt970_ack_interrupt,
+       .config_intr    = lxt970_config_intr,
+       .driver         = { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver lxt971_driver = {
+       .phy_id         = 0x0001378e,
+       .name           = "LXT971",
+       .phy_id_mask    = 0x0fffffff,
+       .features       = PHY_BASIC_FEATURES,
+       .flags          = PHY_HAS_INTERRUPT,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .ack_interrupt  = lxt971_ack_interrupt,
+       .config_intr    = lxt971_config_intr,
+       .driver         = { .owner = THIS_MODULE,},
+};
+
+static int __init lxt_init(void)
+{
+       int ret;
+
+       ret = phy_driver_register(&lxt970_driver);
+       if (ret)
+               goto err1;
+
+       ret = phy_driver_register(&lxt971_driver);
+       if (ret)
+               goto err2;
+       return 0;
+
+ err2: 
+       phy_driver_unregister(&lxt970_driver);
+ err1:
+       return ret;
+}
+
+static void __exit lxt_exit(void)
+{
+       phy_driver_unregister(&lxt970_driver);
+       phy_driver_unregister(&lxt971_driver);
+}
+
+module_init(lxt_init);
+module_exit(lxt_exit);
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
new file mode 100644 (file)
index 0000000..4a72b02
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * drivers/net/phy/marvell.c
+ *
+ * Driver for Marvell PHYs
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#define MII_M1011_IEVENT               0x13
+#define MII_M1011_IEVENT_CLEAR         0x0000
+
+#define MII_M1011_IMASK                        0x12
+#define MII_M1011_IMASK_INIT           0x6400
+#define MII_M1011_IMASK_CLEAR          0x0000
+
+MODULE_DESCRIPTION("Marvell PHY driver");
+MODULE_AUTHOR("Andy Fleming");
+MODULE_LICENSE("GPL");
+
+static int marvell_ack_interrupt(struct phy_device *phydev)
+{
+       int err;
+
+       /* Clear the interrupts by reading the reg */
+       err = phy_read(phydev, MII_M1011_IEVENT);
+
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int marvell_config_intr(struct phy_device *phydev)
+{
+       int err;
+
+       if(phydev->interrupts == PHY_INTERRUPT_ENABLED)
+               err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
+       else
+               err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
+
+       return err;
+}
+
+static int marvell_config_aneg(struct phy_device *phydev)
+{
+       int err;
+
+       /* The Marvell PHY has an errata which requires
+        * that certain registers get written in order
+        * to restart autonegotiation */
+       err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+
+       if (err < 0)
+               return err;
+
+       err = phy_write(phydev, 0x1d, 0x1f);
+       if (err < 0)
+               return err;
+
+       err = phy_write(phydev, 0x1e, 0x200c);
+       if (err < 0)
+               return err;
+
+       err = phy_write(phydev, 0x1d, 0x5);
+       if (err < 0)
+               return err;
+
+       err = phy_write(phydev, 0x1e, 0);
+       if (err < 0)
+               return err;
+
+       err = phy_write(phydev, 0x1e, 0x100);
+       if (err < 0)
+               return err;
+
+
+       err = genphy_config_aneg(phydev);
+
+       return err;
+}
+
+
+static struct phy_driver m88e1101_driver = {
+       .phy_id         = 0x01410c00,
+       .phy_id_mask    = 0xffffff00,
+       .name           = "Marvell 88E1101",
+       .features       = PHY_GBIT_FEATURES,
+       .flags          = PHY_HAS_INTERRUPT,
+       .config_aneg    = &marvell_config_aneg,
+       .read_status    = &genphy_read_status,
+       .ack_interrupt  = &marvell_ack_interrupt,
+       .config_intr    = &marvell_config_intr,
+       .driver         = { .owner = THIS_MODULE,},
+};
+
+static int __init marvell_init(void)
+{
+       return phy_driver_register(&m88e1101_driver);
+}
+
+static void __exit marvell_exit(void)
+{
+       phy_driver_unregister(&m88e1101_driver);
+}
+
+module_init(marvell_init);
+module_exit(marvell_exit);
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
new file mode 100644 (file)
index 0000000..9063067
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * drivers/net/phy/mdio_bus.c
+ *
+ * MDIO Bus interface
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/* mdiobus_register 
+ *
+ * description: Called by a bus driver to bring up all the PHYs
+ *   on a given bus, and attach them to the bus
+ */
+int mdiobus_register(struct mii_bus *bus)
+{
+       int i;
+       int err = 0;
+
+       spin_lock_init(&bus->mdio_lock);
+
+       if (NULL == bus || NULL == bus->name ||
+                       NULL == bus->read ||
+                       NULL == bus->write)
+               return -EINVAL;
+
+       if (bus->reset)
+               bus->reset(bus);
+
+       for (i = 0; i < PHY_MAX_ADDR; i++) {
+               struct phy_device *phydev;
+
+               phydev = get_phy_device(bus, i);
+
+               if (IS_ERR(phydev))
+                       return PTR_ERR(phydev);
+
+               /* There's a PHY at this address
+                * We need to set:
+                * 1) IRQ
+                * 2) bus_id
+                * 3) parent
+                * 4) bus
+                * 5) mii_bus
+                * And, we need to register it */
+               if (phydev) {
+                       phydev->irq = bus->irq[i];
+
+                       phydev->dev.parent = bus->dev;
+                       phydev->dev.bus = &mdio_bus_type;
+                       sprintf(phydev->dev.bus_id, "phy%d:%d", bus->id, i);
+
+                       phydev->bus = bus;
+
+                       err = device_register(&phydev->dev);
+
+                       if (err)
+                               printk(KERN_ERR "phy %d failed to register\n",
+                                               i);
+               }
+
+               bus->phy_map[i] = phydev;
+       }
+
+       pr_info("%s: probed\n", bus->name);
+
+       return err;
+}
+EXPORT_SYMBOL(mdiobus_register);
+
+void mdiobus_unregister(struct mii_bus *bus)
+{
+       int i;
+
+       for (i = 0; i < PHY_MAX_ADDR; i++) {
+               if (bus->phy_map[i]) {
+                       device_unregister(&bus->phy_map[i]->dev);
+                       kfree(bus->phy_map[i]);
+               }
+       }
+}
+EXPORT_SYMBOL(mdiobus_unregister);
+
+/* mdio_bus_match
+ *
+ * description: Given a PHY device, and a PHY driver, return 1 if
+ *   the driver supports the device.  Otherwise, return 0
+ */
+static int mdio_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct phy_device *phydev = to_phy_device(dev);
+       struct phy_driver *phydrv = to_phy_driver(drv);
+
+       return (phydrv->phy_id == (phydev->phy_id & phydrv->phy_id_mask));
+}
+
+/* Suspend and resume.  Copied from platform_suspend and
+ * platform_resume
+ */
+static int mdio_bus_suspend(struct device * dev, pm_message_t state)
+{
+       int ret = 0;
+       struct device_driver *drv = dev->driver;
+
+       if (drv && drv->suspend) {
+               ret = drv->suspend(dev, state, SUSPEND_DISABLE);
+               if (ret == 0)
+                       ret = drv->suspend(dev, state, SUSPEND_SAVE_STATE);
+               if (ret == 0)
+                       ret = drv->suspend(dev, state, SUSPEND_POWER_DOWN);
+       }
+       return ret;
+}
+
+static int mdio_bus_resume(struct device * dev)
+{
+       int ret = 0;
+       struct device_driver *drv = dev->driver;
+
+       if (drv && drv->resume) {
+               ret = drv->resume(dev, RESUME_POWER_ON);
+               if (ret == 0)
+                       ret = drv->resume(dev, RESUME_RESTORE_STATE);
+               if (ret == 0)
+                       ret = drv->resume(dev, RESUME_ENABLE);
+       }
+       return ret;
+}
+
+struct bus_type mdio_bus_type = {
+       .name           = "mdio_bus",
+       .match          = mdio_bus_match,
+       .suspend        = mdio_bus_suspend,
+       .resume         = mdio_bus_resume,
+};
+
+int __init mdio_bus_init(void)
+{
+       return bus_register(&mdio_bus_type);
+}
+
+void mdio_bus_exit(void)
+{
+       bus_unregister(&mdio_bus_type);
+}
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
new file mode 100644 (file)
index 0000000..d9e11f9
--- /dev/null
@@ -0,0 +1,871 @@
+/*
+ * drivers/net/phy/phy.c
+ *
+ * Framework for configuring and reading PHY devices
+ * Based on code in sungem_phy.c and gianfar_phy.c
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/* Convenience function to print out the current phy status
+ */
+void phy_print_status(struct phy_device *phydev)
+{
+       pr_info("%s: Link is %s", phydev->dev.bus_id,
+                       phydev->link ? "Up" : "Down");
+       if (phydev->link)
+               printk(" - %d/%s", phydev->speed,
+                               DUPLEX_FULL == phydev->duplex ?
+                               "Full" : "Half");
+
+       printk("\n");
+}
+EXPORT_SYMBOL(phy_print_status);
+
+
+/* Convenience functions for reading/writing a given PHY
+ * register. They MUST NOT be called from interrupt context,
+ * because the bus read/write functions may wait for an interrupt
+ * to conclude the operation. */
+int phy_read(struct phy_device *phydev, u16 regnum)
+{
+       int retval;
+       struct mii_bus *bus = phydev->bus;
+
+       spin_lock_bh(&bus->mdio_lock);
+       retval = bus->read(bus, phydev->addr, regnum);
+       spin_unlock_bh(&bus->mdio_lock);
+
+       return retval;
+}
+EXPORT_SYMBOL(phy_read);
+
+int phy_write(struct phy_device *phydev, u16 regnum, u16 val)
+{
+       int err;
+       struct mii_bus *bus = phydev->bus;
+
+       spin_lock_bh(&bus->mdio_lock);
+       err = bus->write(bus, phydev->addr, regnum, val);
+       spin_unlock_bh(&bus->mdio_lock);
+
+       return err;
+}
+EXPORT_SYMBOL(phy_write);
+
+
+int phy_clear_interrupt(struct phy_device *phydev)
+{
+       int err = 0;
+
+       if (phydev->drv->ack_interrupt)
+               err = phydev->drv->ack_interrupt(phydev);
+
+       return err;
+}
+
+
+int phy_config_interrupt(struct phy_device *phydev, u32 interrupts)
+{
+       int err = 0;
+
+       phydev->interrupts = interrupts;
+       if (phydev->drv->config_intr)
+               err = phydev->drv->config_intr(phydev);
+
+       return err;
+}
+
+
+/* phy_aneg_done
+ *
+ * description: Reads the status register and returns 0 either if
+ *   auto-negotiation is incomplete, or if there was an error.
+ *   Returns BMSR_ANEGCOMPLETE if auto-negotiation is done.
+ */
+static inline int phy_aneg_done(struct phy_device *phydev)
+{
+       int retval;
+
+       retval = phy_read(phydev, MII_BMSR);
+
+       return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE);
+}
+
+/* A structure for mapping a particular speed and duplex
+ * combination to a particular SUPPORTED and ADVERTISED value */
+struct phy_setting {
+       int speed;
+       int duplex;
+       u32 setting;
+};
+
+/* A mapping of all SUPPORTED settings to speed/duplex */
+static struct phy_setting settings[] = {
+       {
+               .speed = 10000,
+               .duplex = DUPLEX_FULL,
+               .setting = SUPPORTED_10000baseT_Full,
+       },
+       {
+               .speed = SPEED_1000,
+               .duplex = DUPLEX_FULL,
+               .setting = SUPPORTED_1000baseT_Full,
+       },
+       {
+               .speed = SPEED_1000,
+               .duplex = DUPLEX_HALF,
+               .setting = SUPPORTED_1000baseT_Half,
+       },
+       {
+               .speed = SPEED_100,
+               .duplex = DUPLEX_FULL,
+               .setting = SUPPORTED_100baseT_Full,
+       },
+       {
+               .speed = SPEED_100,
+               .duplex = DUPLEX_HALF,
+               .setting = SUPPORTED_100baseT_Half,
+       },
+       {
+               .speed = SPEED_10,
+               .duplex = DUPLEX_FULL,
+               .setting = SUPPORTED_10baseT_Full,
+       },
+       {
+               .speed = SPEED_10,
+               .duplex = DUPLEX_HALF,
+               .setting = SUPPORTED_10baseT_Half,
+       },
+};
+
+#define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting))
+
+/* phy_find_setting
+ *
+ * description: Searches the settings array for the setting which
+ *   matches the desired speed and duplex, and returns the index
+ *   of that setting.  Returns the index of the last setting if
+ *   none of the others match.
+ */
+static inline int phy_find_setting(int speed, int duplex)
+{
+       int idx = 0;
+
+       while (idx < ARRAY_SIZE(settings) &&
+                       (settings[idx].speed != speed ||
+                       settings[idx].duplex != duplex))
+               idx++;
+
+       return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
+}
+
+/* phy_find_valid
+ * idx: The first index in settings[] to search
+ * features: A mask of the valid settings
+ *
+ * description: Returns the index of the first valid setting less
+ *   than or equal to the one pointed to by idx, as determined by
+ *   the mask in features.  Returns the index of the last setting
+ *   if nothing else matches.
+ */
+static inline int phy_find_valid(int idx, u32 features)
+{
+       while (idx < MAX_NUM_SETTINGS && !(settings[idx].setting & features))
+               idx++;
+
+       return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
+}
+
+/* phy_sanitize_settings
+ *
+ * description: Make sure the PHY is set to supported speeds and
+ *   duplexes.  Drop down by one in this order:  1000/FULL,
+ *   1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF
+ */
+void phy_sanitize_settings(struct phy_device *phydev)
+{
+       u32 features = phydev->supported;
+       int idx;
+
+       /* Sanitize settings based on PHY capabilities */
+       if ((features & SUPPORTED_Autoneg) == 0)
+               phydev->autoneg = 0;
+
+       idx = phy_find_valid(phy_find_setting(phydev->speed, phydev->duplex),
+                       features);
+
+       phydev->speed = settings[idx].speed;
+       phydev->duplex = settings[idx].duplex;
+}
+EXPORT_SYMBOL(phy_sanitize_settings);
+
+/* phy_ethtool_sset:
+ * A generic ethtool sset function.  Handles all the details
+ *
+ * A few notes about parameter checking:
+ * - We don't set port or transceiver, so we don't care what they
+ *   were set to.
+ * - phy_start_aneg() will make sure forced settings are sane, and
+ *   choose the next best ones from the ones selected, so we don't
+ *   care if ethtool tries to give us bad values
+ *
+ * A note about the PHYCONTROL Layer.  If you turn off
+ * CONFIG_PHYCONTROL, you will need to read the PHY status
+ * registers after this function completes, and update your
+ * controller manually.
+ */
+int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
+{
+       if (cmd->phy_address != phydev->addr)
+               return -EINVAL;
+
+       /* We make sure that we don't pass unsupported
+        * values in to the PHY */
+       cmd->advertising &= phydev->supported;
+
+       /* Verify the settings we care about. */
+       if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE)
+               return -EINVAL;
+
+       if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0)
+               return -EINVAL;
+
+       if (cmd->autoneg == AUTONEG_DISABLE
+                       && ((cmd->speed != SPEED_1000
+                                       && cmd->speed != SPEED_100
+                                       && cmd->speed != SPEED_10)
+                               || (cmd->duplex != DUPLEX_HALF
+                                       && cmd->duplex != DUPLEX_FULL)))
+               return -EINVAL;
+
+       phydev->autoneg = cmd->autoneg;
+
+       phydev->speed = cmd->speed;
+
+       phydev->advertising = cmd->advertising;
+
+       if (AUTONEG_ENABLE == cmd->autoneg)
+               phydev->advertising |= ADVERTISED_Autoneg;
+       else
+               phydev->advertising &= ~ADVERTISED_Autoneg;
+
+       phydev->duplex = cmd->duplex;
+
+       /* Restart the PHY */
+       phy_start_aneg(phydev);
+
+       return 0;
+}
+
+int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
+{
+       cmd->supported = phydev->supported;
+
+       cmd->advertising = phydev->advertising;
+
+       cmd->speed = phydev->speed;
+       cmd->duplex = phydev->duplex;
+       cmd->port = PORT_MII;
+       cmd->phy_address = phydev->addr;
+       cmd->transceiver = XCVR_EXTERNAL;
+       cmd->autoneg = phydev->autoneg;
+
+       return 0;
+}
+
+
+/* Note that this function is currently incompatible with the
+ * PHYCONTROL layer.  It changes registers without regard to
+ * current state.  Use at own risk
+ */
+int phy_mii_ioctl(struct phy_device *phydev,
+               struct mii_ioctl_data *mii_data, int cmd)
+{
+       u16 val = mii_data->val_in;
+
+       switch (cmd) {
+       case SIOCGMIIPHY:
+               mii_data->phy_id = phydev->addr;
+               break;
+       case SIOCGMIIREG:
+               mii_data->val_out = phy_read(phydev, mii_data->reg_num);
+               break;
+
+       case SIOCSMIIREG:
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+
+               if (mii_data->phy_id == phydev->addr) {
+                       switch(mii_data->reg_num) {
+                       case MII_BMCR:
+                               if (val & (BMCR_RESET|BMCR_ANENABLE))
+                                       phydev->autoneg = AUTONEG_DISABLE;
+                               else
+                                       phydev->autoneg = AUTONEG_ENABLE;
+                               if ((!phydev->autoneg) && (val & BMCR_FULLDPLX))
+                                       phydev->duplex = DUPLEX_FULL;
+                               else
+                                       phydev->duplex = DUPLEX_HALF;
+                               break;
+                       case MII_ADVERTISE:
+                               phydev->advertising = val;
+                               break;
+                       default:
+                               /* do nothing */
+                               break;
+                       }
+               }
+
+               phy_write(phydev, mii_data->reg_num, val);
+               
+               if (mii_data->reg_num == MII_BMCR 
+                               && val & BMCR_RESET
+                               && phydev->drv->config_init)
+                       phydev->drv->config_init(phydev);
+               break;
+       }
+
+       return 0;
+}
+
+/* phy_start_aneg
+ *
+ * description: Sanitizes the settings (if we're not
+ *   autonegotiating them), and then calls the driver's
+ *   config_aneg function.  If the PHYCONTROL Layer is operating,
+ *   we change the state to reflect the beginning of
+ *   Auto-negotiation or forcing.
+ */
+int phy_start_aneg(struct phy_device *phydev)
+{
+       int err;
+
+       spin_lock(&phydev->lock);
+
+       if (AUTONEG_DISABLE == phydev->autoneg)
+               phy_sanitize_settings(phydev);
+
+       err = phydev->drv->config_aneg(phydev);
+
+#ifdef CONFIG_PHYCONTROL
+       if (err < 0)
+               goto out_unlock;
+
+       if (phydev->state != PHY_HALTED) {
+               if (AUTONEG_ENABLE == phydev->autoneg) {
+                       phydev->state = PHY_AN;
+                       phydev->link_timeout = PHY_AN_TIMEOUT;
+               } else {
+                       phydev->state = PHY_FORCING;
+                       phydev->link_timeout = PHY_FORCE_TIMEOUT;
+               }
+       }
+
+out_unlock:
+#endif
+       spin_unlock(&phydev->lock);
+       return err;
+}
+EXPORT_SYMBOL(phy_start_aneg);
+
+
+#ifdef CONFIG_PHYCONTROL
+static void phy_change(void *data);
+static void phy_timer(unsigned long data);
+
+/* phy_start_machine:
+ *
+ * description: The PHY infrastructure can run a state machine
+ *   which tracks whether the PHY is starting up, negotiating,
+ *   etc.  This function starts the timer which tracks the state
+ *   of the PHY.  If you want to be notified when the state
+ *   changes, pass in the callback, otherwise, pass NULL.  If you
+ *   want to maintain your own state machine, do not call this
+ *   function. */
+void phy_start_machine(struct phy_device *phydev,
+               void (*handler)(struct net_device *))
+{
+       phydev->adjust_state = handler;
+
+       init_timer(&phydev->phy_timer);
+       phydev->phy_timer.function = &phy_timer;
+       phydev->phy_timer.data = (unsigned long) phydev;
+       mod_timer(&phydev->phy_timer, jiffies + HZ);
+}
+
+/* phy_stop_machine
+ *
+ * description: Stops the state machine timer, sets the state to
+ *   UP (unless it wasn't up yet), and then frees the interrupt,
+ *   if it is in use. This function must be called BEFORE
+ *   phy_detach.
+ */
+void phy_stop_machine(struct phy_device *phydev)
+{
+       del_timer_sync(&phydev->phy_timer);
+
+       spin_lock(&phydev->lock);
+       if (phydev->state > PHY_UP)
+               phydev->state = PHY_UP;
+       spin_unlock(&phydev->lock);
+
+       if (phydev->irq != PHY_POLL)
+               phy_stop_interrupts(phydev);
+
+       phydev->adjust_state = NULL;
+}
+
+/* phy_force_reduction
+ *
+ * description: Reduces the speed/duplex settings by
+ *   one notch.  The order is so:
+ *   1000/FULL, 1000/HALF, 100/FULL, 100/HALF,
+ *   10/FULL, 10/HALF.  The function bottoms out at 10/HALF.
+ */
+static void phy_force_reduction(struct phy_device *phydev)
+{
+       int idx;
+
+       idx = phy_find_setting(phydev->speed, phydev->duplex);
+       
+       idx++;
+
+       idx = phy_find_valid(idx, phydev->supported);
+
+       phydev->speed = settings[idx].speed;
+       phydev->duplex = settings[idx].duplex;
+
+       pr_info("Trying %d/%s\n", phydev->speed,
+                       DUPLEX_FULL == phydev->duplex ?
+                       "FULL" : "HALF");
+}
+
+
+/* phy_error:
+ *
+ * Moves the PHY to the HALTED state in response to a read
+ * or write error, and tells the controller the link is down.
+ * Must not be called from interrupt context, or while the
+ * phydev->lock is held.
+ */
+void phy_error(struct phy_device *phydev)
+{
+       spin_lock(&phydev->lock);
+       phydev->state = PHY_HALTED;
+       spin_unlock(&phydev->lock);
+}
+
+/* phy_interrupt
+ *
+ * description: When a PHY interrupt occurs, the handler disables
+ * interrupts, and schedules a work task to clear the interrupt.
+ */
+static irqreturn_t phy_interrupt(int irq, void *phy_dat, struct pt_regs *regs)
+{
+       struct phy_device *phydev = phy_dat;
+
+       /* The MDIO bus is not allowed to be written in interrupt
+        * context, so we need to disable the irq here.  A work
+        * queue will write the PHY to disable and clear the
+        * interrupt, and then reenable the irq line. */
+       disable_irq_nosync(irq);
+
+       schedule_work(&phydev->phy_queue);
+
+       return IRQ_HANDLED;
+}
+
+/* Enable the interrupts from the PHY side */
+int phy_enable_interrupts(struct phy_device *phydev)
+{
+       int err;
+
+       err = phy_clear_interrupt(phydev);
+
+       if (err < 0)
+               return err;
+
+       err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED);
+
+       return err;
+}
+EXPORT_SYMBOL(phy_enable_interrupts);
+
+/* Disable the PHY interrupts from the PHY side */
+int phy_disable_interrupts(struct phy_device *phydev)
+{
+       int err;
+
+       /* Disable PHY interrupts */
+       err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
+
+       if (err)
+               goto phy_err;
+
+       /* Clear the interrupt */
+       err = phy_clear_interrupt(phydev);
+
+       if (err)
+               goto phy_err;
+
+       return 0;
+
+phy_err:
+       phy_error(phydev);
+
+       return err;
+}
+EXPORT_SYMBOL(phy_disable_interrupts);
+
+/* phy_start_interrupts
+ *
+ * description: Request the interrupt for the given PHY.  If
+ *   this fails, then we set irq to PHY_POLL.
+ *   Otherwise, we enable the interrupts in the PHY.
+ *   Returns 0 on success.
+ *   This should only be called with a valid IRQ number.
+ */
+int phy_start_interrupts(struct phy_device *phydev)
+{
+       int err = 0;
+
+       INIT_WORK(&phydev->phy_queue, phy_change, phydev);
+
+       if (request_irq(phydev->irq, phy_interrupt,
+                               SA_SHIRQ,
+                               "phy_interrupt",
+                               phydev) < 0) {
+               printk(KERN_WARNING "%s: Can't get IRQ %d (PHY)\n",
+                               phydev->bus->name,
+                               phydev->irq);
+               phydev->irq = PHY_POLL;
+               return 0;
+       }
+
+       err = phy_enable_interrupts(phydev);
+
+       return err;
+}
+EXPORT_SYMBOL(phy_start_interrupts);
+
+int phy_stop_interrupts(struct phy_device *phydev)
+{
+       int err;
+
+       err = phy_disable_interrupts(phydev);
+
+       if (err)
+               phy_error(phydev);
+
+       free_irq(phydev->irq, phydev);
+
+       return err;
+}
+EXPORT_SYMBOL(phy_stop_interrupts);
+
+
+/* Scheduled by the phy_interrupt/timer to handle PHY changes */
+static void phy_change(void *data)
+{
+       int err;
+       struct phy_device *phydev = data;
+
+       err = phy_disable_interrupts(phydev);
+
+       if (err)
+               goto phy_err;
+
+       spin_lock(&phydev->lock);
+       if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
+               phydev->state = PHY_CHANGELINK;
+       spin_unlock(&phydev->lock);
+
+       enable_irq(phydev->irq);
+
+       /* Reenable interrupts */
+       err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED);
+
+       if (err)
+               goto irq_enable_err;
+
+       return;
+
+irq_enable_err:
+       disable_irq(phydev->irq);
+phy_err:
+       phy_error(phydev);
+}
+
+/* Bring down the PHY link, and stop checking the status. */
+void phy_stop(struct phy_device *phydev)
+{
+       spin_lock(&phydev->lock);
+
+       if (PHY_HALTED == phydev->state)
+               goto out_unlock;
+
+       if (phydev->irq != PHY_POLL) {
+               /* Clear any pending interrupts */
+               phy_clear_interrupt(phydev);
+
+               /* Disable PHY Interrupts */
+               phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
+       }
+
+       phydev->state = PHY_HALTED;
+
+out_unlock:
+       spin_unlock(&phydev->lock);
+}
+
+
+/* phy_start
+ *
+ * description: Indicates the attached device's readiness to
+ *   handle PHY-related work.  Used during startup to start the
+ *   PHY, and after a call to phy_stop() to resume operation.
+ *   Also used to indicate the MDIO bus has cleared an error
+ *   condition.
+ */
+void phy_start(struct phy_device *phydev)
+{
+       spin_lock(&phydev->lock);
+
+       switch (phydev->state) {
+               case PHY_STARTING:
+                       phydev->state = PHY_PENDING;
+                       break;
+               case PHY_READY:
+                       phydev->state = PHY_UP;
+                       break;
+               case PHY_HALTED:
+                       phydev->state = PHY_RESUMING;
+               default:
+                       break;
+       }
+       spin_unlock(&phydev->lock);
+}
+EXPORT_SYMBOL(phy_stop);
+EXPORT_SYMBOL(phy_start);
+
+/* PHY timer which handles the state machine */
+static void phy_timer(unsigned long data)
+{
+       struct phy_device *phydev = (struct phy_device *)data;
+       int needs_aneg = 0;
+       int err = 0;
+
+       spin_lock(&phydev->lock);
+
+       if (phydev->adjust_state)
+               phydev->adjust_state(phydev->attached_dev);
+
+       switch(phydev->state) {
+               case PHY_DOWN:
+               case PHY_STARTING:
+               case PHY_READY:
+               case PHY_PENDING:
+                       break;
+               case PHY_UP:
+                       needs_aneg = 1;
+
+                       phydev->link_timeout = PHY_AN_TIMEOUT;
+
+                       break;
+               case PHY_AN:
+                       /* Check if negotiation is done.  Break
+                        * if there's an error */
+                       err = phy_aneg_done(phydev);
+                       if (err < 0)
+                               break;
+
+                       /* If auto-negotiation is done, we change to
+                        * either RUNNING, or NOLINK */
+                       if (err > 0) {
+                               err = phy_read_status(phydev);
+
+                               if (err)
+                                       break;
+
+                               if (phydev->link) {
+                                       phydev->state = PHY_RUNNING;
+                                       netif_carrier_on(phydev->attached_dev);
+                               } else {
+                                       phydev->state = PHY_NOLINK;
+                                       netif_carrier_off(phydev->attached_dev);
+                               }
+
+                               phydev->adjust_link(phydev->attached_dev);
+
+                       } else if (0 == phydev->link_timeout--) {
+                               /* The counter expired, so either we
+                                * switch to forced mode, or the
+                                * magic_aneg bit exists, and we try aneg
+                                * again */
+                               if (!(phydev->drv->flags & PHY_HAS_MAGICANEG)) {
+                                       int idx;
+
+                                       /* We'll start from the
+                                        * fastest speed, and work
+                                        * our way down */
+                                       idx = phy_find_valid(0,
+                                                       phydev->supported);
+
+                                       phydev->speed = settings[idx].speed;
+                                       phydev->duplex = settings[idx].duplex;
+                                       
+                                       phydev->autoneg = AUTONEG_DISABLE;
+                                       phydev->state = PHY_FORCING;
+                                       phydev->link_timeout =
+                                               PHY_FORCE_TIMEOUT;
+
+                                       pr_info("Trying %d/%s\n",
+                                                       phydev->speed,
+                                                       DUPLEX_FULL ==
+                                                       phydev->duplex ?
+                                                       "FULL" : "HALF");
+                               }
+
+                               needs_aneg = 1;
+                       }
+                       break;
+               case PHY_NOLINK:
+                       err = phy_read_status(phydev);
+
+                       if (err)
+                               break;
+
+                       if (phydev->link) {
+                               phydev->state = PHY_RUNNING;
+                               netif_carrier_on(phydev->attached_dev);
+                               phydev->adjust_link(phydev->attached_dev);
+                       }
+                       break;
+               case PHY_FORCING:
+                       err = phy_read_status(phydev);
+
+                       if (err)
+                               break;
+
+                       if (phydev->link) {
+                               phydev->state = PHY_RUNNING;
+                               netif_carrier_on(phydev->attached_dev);
+                       } else {
+                               if (0 == phydev->link_timeout--) {
+                                       phy_force_reduction(phydev);
+                                       needs_aneg = 1;
+                               }
+                       }
+
+                       phydev->adjust_link(phydev->attached_dev);
+                       break;
+               case PHY_RUNNING:
+                       /* Only register a CHANGE if we are
+                        * polling */
+                       if (PHY_POLL == phydev->irq)
+                               phydev->state = PHY_CHANGELINK;
+                       break;
+               case PHY_CHANGELINK:
+                       err = phy_read_status(phydev);
+
+                       if (err)
+                               break;
+
+                       if (phydev->link) {
+                               phydev->state = PHY_RUNNING;
+                               netif_carrier_on(phydev->attached_dev);
+                       } else {
+                               phydev->state = PHY_NOLINK;
+                               netif_carrier_off(phydev->attached_dev);
+                       }
+
+                       phydev->adjust_link(phydev->attached_dev);
+
+                       if (PHY_POLL != phydev->irq)
+                               err = phy_config_interrupt(phydev,
+                                               PHY_INTERRUPT_ENABLED);
+                       break;
+               case PHY_HALTED:
+                       if (phydev->link) {
+                               phydev->link = 0;
+                               netif_carrier_off(phydev->attached_dev);
+                               phydev->adjust_link(phydev->attached_dev);
+                       }
+                       break;
+               case PHY_RESUMING:
+
+                       err = phy_clear_interrupt(phydev);
+
+                       if (err)
+                               break;
+
+                       err = phy_config_interrupt(phydev,
+                                       PHY_INTERRUPT_ENABLED);
+
+                       if (err)
+                               break;
+
+                       if (AUTONEG_ENABLE == phydev->autoneg) {
+                               err = phy_aneg_done(phydev);
+                               if (err < 0)
+                                       break;
+
+                               /* err > 0 if AN is done.
+                                * Otherwise, it's 0, and we're
+                                * still waiting for AN */
+                               if (err > 0) {
+                                       phydev->state = PHY_RUNNING;
+                               } else {
+                                       phydev->state = PHY_AN;
+                                       phydev->link_timeout = PHY_AN_TIMEOUT;
+                               }
+                       } else
+                               phydev->state = PHY_RUNNING;
+                       break;
+       }
+
+       spin_unlock(&phydev->lock);
+
+       if (needs_aneg)
+               err = phy_start_aneg(phydev);
+
+       if (err < 0)
+               phy_error(phydev);
+
+       mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ);
+}
+
+#endif /* CONFIG_PHYCONTROL */
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
new file mode 100644 (file)
index 0000000..33f7bdb
--- /dev/null
@@ -0,0 +1,696 @@
+/*
+ * drivers/net/phy/phy_device.c
+ *
+ * Framework for finding and configuring PHYs.
+ * Also contains generic PHY driver
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+static struct phy_driver genphy_driver;
+extern int mdio_bus_init(void);
+extern void mdio_bus_exit(void);
+
+/* get_phy_device
+ *
+ * description: Reads the ID registers of the PHY at addr on the
+ *   bus, then allocates and returns the phy_device to
+ *   represent it.
+ */
+struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
+{
+       int phy_reg;
+       u32 phy_id;
+       struct phy_device *dev = NULL;
+
+       /* Grab the bits from PHYIR1, and put them
+        * in the upper half */
+       phy_reg = bus->read(bus, addr, MII_PHYSID1);
+
+       if (phy_reg < 0)
+               return ERR_PTR(phy_reg);
+
+       phy_id = (phy_reg & 0xffff) << 16;
+
+       /* Grab the bits from PHYIR2, and put them in the lower half */
+       phy_reg = bus->read(bus, addr, MII_PHYSID2);
+
+       if (phy_reg < 0)
+               return ERR_PTR(phy_reg);
+
+       phy_id |= (phy_reg & 0xffff);
+
+       /* If the phy_id is all Fs, there is no device there */
+       if (0xffffffff == phy_id)
+               return NULL;
+
+       /* Otherwise, we allocate the device, and initialize the
+        * default values */
+       dev = kcalloc(1, sizeof(*dev), GFP_KERNEL);
+
+       if (NULL == dev)
+               return ERR_PTR(-ENOMEM);
+
+       dev->speed = 0;
+       dev->duplex = -1;
+       dev->pause = dev->asym_pause = 0;
+       dev->link = 1;
+
+       dev->autoneg = AUTONEG_ENABLE;
+
+       dev->addr = addr;
+       dev->phy_id = phy_id;
+       dev->bus = bus;
+
+       dev->state = PHY_DOWN;
+
+       spin_lock_init(&dev->lock);
+
+       return dev;
+}
+
+#ifdef CONFIG_PHYCONTROL
+/* phy_prepare_link:
+ *
+ * description: Tells the PHY infrastructure to handle the
+ *   gory details on monitoring link status (whether through
+ *   polling or an interrupt), and to call back to the
+ *   connected device driver when the link status changes.
+ *   If you want to monitor your own link state, don't call
+ *   this function */
+void phy_prepare_link(struct phy_device *phydev,
+               void (*handler)(struct net_device *))
+{
+       phydev->adjust_link = handler;
+}
+
+/* phy_connect:
+ *
+ * description: Convenience function for connecting ethernet
+ *   devices to PHY devices.  The default behavior is for
+ *   the PHY infrastructure to handle everything, and only notify
+ *   the connected driver when the link status changes.  If you
+ *   don't want, or can't use the provided functionality, you may
+ *   choose to call only the subset of functions which provide
+ *   the desired functionality.
+ */
+struct phy_device * phy_connect(struct net_device *dev, const char *phy_id,
+               void (*handler)(struct net_device *), u32 flags)
+{
+       struct phy_device *phydev;
+
+       phydev = phy_attach(dev, phy_id, flags);
+
+       if (IS_ERR(phydev))
+               return phydev;
+
+       phy_prepare_link(phydev, handler);
+
+       phy_start_machine(phydev, NULL);
+
+       if (phydev->irq > 0)
+               phy_start_interrupts(phydev);
+
+       return phydev;
+}
+EXPORT_SYMBOL(phy_connect);
+
+void phy_disconnect(struct phy_device *phydev)
+{
+       if (phydev->irq > 0)
+               phy_stop_interrupts(phydev);
+
+       phy_stop_machine(phydev);
+       
+       phydev->adjust_link = NULL;
+
+       phy_detach(phydev);
+}
+EXPORT_SYMBOL(phy_disconnect);
+
+#endif /* CONFIG_PHYCONTROL */
+
+/* phy_attach:
+ *
+ *   description: Called by drivers to attach to a particular PHY
+ *     device. The phy_device is found, and properly hooked up
+ *     to the phy_driver.  If no driver is attached, then the
+ *     genphy_driver is used.  The phy_device is given a ptr to
+ *     the attaching device, and given a callback for link status
+ *     change.  The phy_device is returned to the attaching
+ *     driver.
+ */
+static int phy_compare_id(struct device *dev, void *data)
+{
+       return strcmp((char *)data, dev->bus_id) ? 0 : 1;
+}
+
+struct phy_device *phy_attach(struct net_device *dev,
+               const char *phy_id, u32 flags)
+{
+       struct bus_type *bus = &mdio_bus_type;
+       struct phy_device *phydev;
+       struct device *d;
+
+       /* Search the list of PHY devices on the mdio bus for the
+        * PHY with the requested name */
+       d = bus_find_device(bus, NULL, (void *)phy_id, phy_compare_id);
+
+       if (d) {
+               phydev = to_phy_device(d);
+       } else {
+               printk(KERN_ERR "%s not found\n", phy_id);
+               return ERR_PTR(-ENODEV);
+       }
+
+       /* Assume that if there is no driver, that it doesn't
+        * exist, and we should use the genphy driver. */
+       if (NULL == d->driver) {
+               int err;
+               down_write(&d->bus->subsys.rwsem);
+               d->driver = &genphy_driver.driver;
+
+               err = d->driver->probe(d);
+
+               if (err < 0)
+                       return ERR_PTR(err);
+
+               device_bind_driver(d);
+               up_write(&d->bus->subsys.rwsem);
+       }
+
+       if (phydev->attached_dev) {
+               printk(KERN_ERR "%s: %s already attached\n",
+                               dev->name, phy_id);
+               return ERR_PTR(-EBUSY);
+       }
+
+       phydev->attached_dev = dev;
+
+       phydev->dev_flags = flags;
+
+       return phydev;
+}
+EXPORT_SYMBOL(phy_attach);
+
+void phy_detach(struct phy_device *phydev)
+{
+       phydev->attached_dev = NULL;
+
+       /* If the device had no specific driver before (i.e. - it
+        * was using the generic driver), we unbind the device
+        * from the generic driver so that there's a chance a
+        * real driver could be loaded */
+       if (phydev->dev.driver == &genphy_driver.driver) {
+               down_write(&phydev->dev.bus->subsys.rwsem);
+               device_release_driver(&phydev->dev);
+               up_write(&phydev->dev.bus->subsys.rwsem);
+       }
+}
+EXPORT_SYMBOL(phy_detach);
+
+
+/* Generic PHY support and helper functions */
+
+/* genphy_config_advert
+ *
+ * description: Writes MII_ADVERTISE with the appropriate values,
+ *   after sanitizing the values to make sure we only advertise
+ *   what is supported
+ */
+int genphy_config_advert(struct phy_device *phydev)
+{
+       u32 advertise;
+       int adv;
+       int err;
+
+       /* Only allow advertising what
+        * this PHY supports */
+       phydev->advertising &= phydev->supported;
+       advertise = phydev->advertising;
+
+       /* Setup standard advertisement */
+       adv = phy_read(phydev, MII_ADVERTISE);
+
+       if (adv < 0)
+               return adv;
+
+       adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | 
+                ADVERTISE_PAUSE_ASYM);
+       if (advertise & ADVERTISED_10baseT_Half)
+               adv |= ADVERTISE_10HALF;
+       if (advertise & ADVERTISED_10baseT_Full)
+               adv |= ADVERTISE_10FULL;
+       if (advertise & ADVERTISED_100baseT_Half)
+               adv |= ADVERTISE_100HALF;
+       if (advertise & ADVERTISED_100baseT_Full)
+               adv |= ADVERTISE_100FULL;
+       if (advertise & ADVERTISED_Pause)
+               adv |= ADVERTISE_PAUSE_CAP;
+       if (advertise & ADVERTISED_Asym_Pause)
+               adv |= ADVERTISE_PAUSE_ASYM;
+
+       err = phy_write(phydev, MII_ADVERTISE, adv);
+
+       if (err < 0)
+               return err;
+
+       /* Configure gigabit if it's supported */
+       if (phydev->supported & (SUPPORTED_1000baseT_Half |
+                               SUPPORTED_1000baseT_Full)) {
+               adv = phy_read(phydev, MII_CTRL1000);
+
+               if (adv < 0)
+                       return adv;
+
+               adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+               if (advertise & SUPPORTED_1000baseT_Half)
+                       adv |= ADVERTISE_1000HALF;
+               if (advertise & SUPPORTED_1000baseT_Full)
+                       adv |= ADVERTISE_1000FULL;
+               err = phy_write(phydev, MII_CTRL1000, adv);
+
+               if (err < 0)
+                       return err;
+       }
+
+       return adv;
+}
+EXPORT_SYMBOL(genphy_config_advert);
+
+/* genphy_setup_forced
+ *
+ * description: Configures MII_BMCR to force speed/duplex
+ *   to the values in phydev. Assumes that the values are valid.
+ *   Please see phy_sanitize_settings() */
+int genphy_setup_forced(struct phy_device *phydev)
+{
+       int ctl = BMCR_RESET;
+
+       phydev->pause = phydev->asym_pause = 0;
+
+       if (SPEED_1000 == phydev->speed)
+               ctl |= BMCR_SPEED1000;
+       else if (SPEED_100 == phydev->speed)
+               ctl |= BMCR_SPEED100;
+
+       if (DUPLEX_FULL == phydev->duplex)
+               ctl |= BMCR_FULLDPLX;
+       
+       ctl = phy_write(phydev, MII_BMCR, ctl);
+
+       if (ctl < 0)
+               return ctl;
+
+       /* We just reset the device, so we'd better configure any
+        * settings the PHY requires to operate */
+       if (phydev->drv->config_init)
+               ctl = phydev->drv->config_init(phydev);
+
+       return ctl;
+}
+
+
+/* Enable and Restart Autonegotiation */
+int genphy_restart_aneg(struct phy_device *phydev)
+{
+       int ctl;
+
+       ctl = phy_read(phydev, MII_BMCR);
+
+       if (ctl < 0)
+               return ctl;
+
+       ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+
+       /* Don't isolate the PHY if we're negotiating */
+       ctl &= ~(BMCR_ISOLATE);
+
+       ctl = phy_write(phydev, MII_BMCR, ctl);
+
+       return ctl;
+}
+
+
+/* genphy_config_aneg
+ *
+ * description: If auto-negotiation is enabled, we configure the
+ *   advertising, and then restart auto-negotiation.  If it is not
+ *   enabled, then we write the BMCR
+ */
+int genphy_config_aneg(struct phy_device *phydev)
+{
+       int err = 0;
+
+       if (AUTONEG_ENABLE == phydev->autoneg) {
+               err = genphy_config_advert(phydev);
+
+               if (err < 0)
+                       return err;
+
+               err = genphy_restart_aneg(phydev);
+       } else
+               err = genphy_setup_forced(phydev);
+
+       return err;
+}
+EXPORT_SYMBOL(genphy_config_aneg);
+
+/* genphy_update_link
+ *
+ * description: Update the value in phydev->link to reflect the
+ *   current link value.  In order to do this, we need to read
+ *   the status register twice, keeping the second value
+ */
+int genphy_update_link(struct phy_device *phydev)
+{
+       int status;
+
+       /* Do a fake read */
+       status = phy_read(phydev, MII_BMSR);
+
+       if (status < 0)
+               return status;
+
+       /* Read link and autonegotiation status */
+       status = phy_read(phydev, MII_BMSR);
+
+       if (status < 0)
+               return status;
+
+       if ((status & BMSR_LSTATUS) == 0)
+               phydev->link = 0;
+       else
+               phydev->link = 1;
+
+       return 0;
+}
+
+/* genphy_read_status
+ *
+ * description: Check the link, then figure out the current state
+ *   by comparing what we advertise with what the link partner
+ *   advertises.  Start by checking the gigabit possibilities,
+ *   then move on to 10/100.
+ */
+int genphy_read_status(struct phy_device *phydev)
+{
+       int adv;
+       int err;
+       int lpa;
+       int lpagb = 0;
+
+       /* Update the link, but return if there
+        * was an error */
+       err = genphy_update_link(phydev);
+       if (err)
+               return err;
+
+       if (AUTONEG_ENABLE == phydev->autoneg) {
+               if (phydev->supported & (SUPPORTED_1000baseT_Half
+                                       | SUPPORTED_1000baseT_Full)) {
+                       lpagb = phy_read(phydev, MII_STAT1000);
+
+                       if (lpagb < 0)
+                               return lpagb;
+
+                       adv = phy_read(phydev, MII_CTRL1000);
+
+                       if (adv < 0)
+                               return adv;
+
+                       lpagb &= adv << 2;
+               }
+
+               lpa = phy_read(phydev, MII_LPA);
+
+               if (lpa < 0)
+                       return lpa;
+
+               adv = phy_read(phydev, MII_ADVERTISE);
+
+               if (adv < 0)
+                       return adv;
+
+               lpa &= adv;
+
+               phydev->speed = SPEED_10;
+               phydev->duplex = DUPLEX_HALF;
+               phydev->pause = phydev->asym_pause = 0;
+
+               if (lpagb & (LPA_1000FULL | LPA_1000HALF)) {
+                       phydev->speed = SPEED_1000;
+
+                       if (lpagb & LPA_1000FULL)
+                               phydev->duplex = DUPLEX_FULL;
+               } else if (lpa & (LPA_100FULL | LPA_100HALF)) {
+                       phydev->speed = SPEED_100;
+                       
+                       if (lpa & LPA_100FULL)
+                               phydev->duplex = DUPLEX_FULL;
+               } else
+                       if (lpa & LPA_10FULL)
+                               phydev->duplex = DUPLEX_FULL;
+
+               if (phydev->duplex == DUPLEX_FULL){
+                       phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
+                       phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
+               }
+       } else {
+               int bmcr = phy_read(phydev, MII_BMCR);
+               if (bmcr < 0)
+                       return bmcr;
+
+               if (bmcr & BMCR_FULLDPLX)
+                       phydev->duplex = DUPLEX_FULL;
+               else
+                       phydev->duplex = DUPLEX_HALF;
+
+               if (bmcr & BMCR_SPEED1000)
+                       phydev->speed = SPEED_1000;
+               else if (bmcr & BMCR_SPEED100)
+                       phydev->speed = SPEED_100;
+               else
+                       phydev->speed = SPEED_10;
+
+               phydev->pause = phydev->asym_pause = 0;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(genphy_read_status);
+
+static int genphy_config_init(struct phy_device *phydev)
+{
+       u32 val;
+       u32 features;
+
+       /* For now, I'll claim that the generic driver supports
+        * all possible port types */
+       features = (SUPPORTED_TP | SUPPORTED_MII
+                       | SUPPORTED_AUI | SUPPORTED_FIBRE |
+                       SUPPORTED_BNC);
+
+       /* Do we support autonegotiation? */
+       val = phy_read(phydev, MII_BMSR);
+
+       if (val < 0)
+               return val;
+
+       if (val & BMSR_ANEGCAPABLE)
+               features |= SUPPORTED_Autoneg;
+
+       if (val & BMSR_100FULL)
+               features |= SUPPORTED_100baseT_Full;
+       if (val & BMSR_100HALF)
+               features |= SUPPORTED_100baseT_Half;
+       if (val & BMSR_10FULL)
+               features |= SUPPORTED_10baseT_Full;
+       if (val & BMSR_10HALF)
+               features |= SUPPORTED_10baseT_Half;
+
+       if (val & BMSR_ESTATEN) {
+               val = phy_read(phydev, MII_ESTATUS);
+
+               if (val < 0)
+                       return val;
+
+               if (val & ESTATUS_1000_TFULL)
+                       features |= SUPPORTED_1000baseT_Full;
+               if (val & ESTATUS_1000_THALF)
+                       features |= SUPPORTED_1000baseT_Half;
+       }
+
+       phydev->supported = features;
+       phydev->advertising = features;
+
+       return 0;
+}
+
+
+/* phy_probe
+ *
+ * description: Take care of setting up the phy_device structure,
+ *   set the state to READY (the driver's init function should
+ *   set it to STARTING if needed).
+ */
+static int phy_probe(struct device *dev)
+{
+       struct phy_device *phydev;
+       struct phy_driver *phydrv;
+       struct device_driver *drv;
+       int err = 0;
+
+       phydev = to_phy_device(dev);
+
+       /* Make sure the driver is held.
+        * XXX -- Is this correct? */
+       drv = get_driver(phydev->dev.driver);
+       phydrv = to_phy_driver(drv);
+       phydev->drv = phydrv;
+
+       /* Disable the interrupt if the PHY doesn't support it */
+       if (!(phydrv->flags & PHY_HAS_INTERRUPT))
+               phydev->irq = PHY_POLL;
+
+       spin_lock(&phydev->lock);
+
+       /* Start out supporting everything. Eventually,
+        * a controller will attach, and may modify one
+        * or both of these values */
+       phydev->supported = phydrv->features;
+       phydev->advertising = phydrv->features;
+
+       /* Set the state to READY by default */
+       phydev->state = PHY_READY;
+
+       if (phydev->drv->probe)
+               err = phydev->drv->probe(phydev);
+
+       spin_unlock(&phydev->lock);
+
+       if (err < 0)
+               return err;
+
+       if (phydev->drv->config_init)
+               err = phydev->drv->config_init(phydev);
+
+       return err;
+}
+
+static int phy_remove(struct device *dev)
+{
+       struct phy_device *phydev;
+
+       phydev = to_phy_device(dev);
+
+       spin_lock(&phydev->lock);
+       phydev->state = PHY_DOWN;
+       spin_unlock(&phydev->lock);
+
+       if (phydev->drv->remove)
+               phydev->drv->remove(phydev);
+
+       put_driver(dev->driver);
+       phydev->drv = NULL;
+
+       return 0;
+}
+
+int phy_driver_register(struct phy_driver *new_driver)
+{
+       int retval;
+
+       memset(&new_driver->driver, 0, sizeof(new_driver->driver));
+       new_driver->driver.name = new_driver->name;
+       new_driver->driver.bus = &mdio_bus_type;
+       new_driver->driver.probe = phy_probe;
+       new_driver->driver.remove = phy_remove;
+
+       retval = driver_register(&new_driver->driver);
+
+       if (retval) {
+               printk(KERN_ERR "%s: Error %d in registering driver\n",
+                               new_driver->name, retval);
+
+               return retval;
+       }
+
+       pr_info("%s: Registered new driver\n", new_driver->name);
+
+       return 0;
+}
+EXPORT_SYMBOL(phy_driver_register);
+
+void phy_driver_unregister(struct phy_driver *drv)
+{
+       driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL(phy_driver_unregister);
+
+static struct phy_driver genphy_driver = {
+       .phy_id         = 0xffffffff,
+       .phy_id_mask    = 0xffffffff,
+       .name           = "Generic PHY",
+       .config_init    = genphy_config_init,
+       .features       = 0,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .driver         = {.owner= THIS_MODULE, },
+};
+
+static int __init phy_init(void)
+{
+       int rc;
+
+       rc = mdio_bus_init();
+       if (rc)
+               return rc;
+
+       rc = phy_driver_register(&genphy_driver);
+       if (rc)
+               mdio_bus_exit();
+
+       return rc;
+}
+
+static void __exit phy_exit(void)
+{
+       phy_driver_unregister(&genphy_driver);
+       mdio_bus_exit();
+}
+
+subsys_initcall(phy_init);
+module_exit(phy_exit);
diff --git a/drivers/net/phy/qsemi.c b/drivers/net/phy/qsemi.c
new file mode 100644 (file)
index 0000000..d461ba4
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * drivers/net/phy/qsemi.c
+ *
+ * Driver for Quality Semiconductor PHYs
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/* ------------------------------------------------------------------------- */
+/* The Quality Semiconductor QS6612 is used on the RPX CLLF                  */
+
+/* register definitions */
+
+#define MII_QS6612_MCR         17  /* Mode Control Register      */
+#define MII_QS6612_FTR         27  /* Factory Test Register      */
+#define MII_QS6612_MCO         28  /* Misc. Control Register     */
+#define MII_QS6612_ISR         29  /* Interrupt Source Register  */
+#define MII_QS6612_IMR         30  /* Interrupt Mask Register    */
+#define MII_QS6612_IMR_INIT    0x003a
+#define MII_QS6612_PCR         31  /* 100BaseTx PHY Control Reg. */
+
+#define QS6612_PCR_AN_COMPLETE 0x1000
+#define QS6612_PCR_RLBEN       0x0200
+#define QS6612_PCR_DCREN       0x0100
+#define QS6612_PCR_4B5BEN      0x0040
+#define QS6612_PCR_TX_ISOLATE  0x0020
+#define QS6612_PCR_MLT3_DIS    0x0002
+#define QS6612_PCR_SCRM_DESCRM 0x0001
+
+MODULE_DESCRIPTION("Quality Semiconductor PHY driver");
+MODULE_AUTHOR("Andy Fleming");
+MODULE_LICENSE("GPL");
+
+/* Returns 0, unless there's a write error */
+static int qs6612_config_init(struct phy_device *phydev)
+{
+       /* The PHY powers up isolated on the RPX,
+        * so send a command to allow operation.
+        * XXX - My docs indicate this should be 0x0940
+        * ...or something.  The current value sets three
+        * reserved bits, bit 11, which specifies it should be
+        * set to one, bit 10, which specifies it should be set
+        * to 0, and bit 7, which doesn't specify.  However, my
+        * docs are preliminary, and I will leave it like this
+        * until someone more knowledgable corrects me or it.
+        * -- Andy Fleming
+        */
+       return phy_write(phydev, MII_QS6612_PCR, 0x0dc0);
+}
+
+static int qs6612_ack_interrupt(struct phy_device *phydev)
+{
+       int err;
+
+       err = phy_read(phydev, MII_QS6612_ISR);
+
+       if (err < 0)
+               return err;
+
+       err = phy_read(phydev, MII_BMSR);
+
+       if (err < 0)
+               return err;
+
+       err = phy_read(phydev, MII_EXPANSION);
+
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int qs6612_config_intr(struct phy_device *phydev)
+{
+       int err;
+       if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+               err = phy_write(phydev, MII_QS6612_IMR,
+                               MII_QS6612_IMR_INIT);
+       else
+               err = phy_write(phydev, MII_QS6612_IMR, 0);
+
+       return err;
+
+}
+
+static struct phy_driver qs6612_driver = {
+       .phy_id         = 0x00181440,
+       .name           = "QS6612",
+       .phy_id_mask    = 0xfffffff0,
+       .features       = PHY_BASIC_FEATURES,
+       .flags          = PHY_HAS_INTERRUPT,
+       .config_init    = qs6612_config_init,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .ack_interrupt  = qs6612_ack_interrupt,
+       .config_intr    = qs6612_config_intr,
+       .driver         = { .owner = THIS_MODULE,},
+};
+
+static int __init qs6612_init(void)
+{
+       return phy_driver_register(&qs6612_driver);
+}
+
+static void __exit qs6612_exit(void)
+{
+       phy_driver_unregister(&qs6612_driver);
+}
+
+module_init(qs6612_init);
+module_exit(qs6612_exit);
index a32668e88e09fc2a157e3ac5500c94ae158c9529..bb71638a7c4484a6dfe5b6ba19ad7512ea4e911d 100644 (file)
@@ -1657,7 +1657,6 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
                        skb->dev = ppp->dev;
                        skb->protocol = htons(npindex_to_ethertype[npi]);
                        skb->mac.raw = skb->data;
-                       skb->input_dev = ppp->dev;
                        netif_rx(skb);
                        ppp->dev->last_rx = jiffies;
                }
index ce1a9bf7b9a76ee1d2d0172c4092de0473a653c7..82f236cc3b9b31e4aa9df662a639456d519ea103 100644 (file)
@@ -377,7 +377,8 @@ abort_kfree:
  ***********************************************************************/
 static int pppoe_rcv(struct sk_buff *skb,
                     struct net_device *dev,
-                    struct packet_type *pt)
+                    struct packet_type *pt,
+                    struct net_device *orig_dev)
 
 {
        struct pppoe_hdr *ph;
@@ -426,7 +427,8 @@ out:
  ***********************************************************************/
 static int pppoe_disc_rcv(struct sk_buff *skb,
                          struct net_device *dev,
-                         struct packet_type *pt)
+                         struct packet_type *pt,
+                         struct net_device *orig_dev)
 
 {
        struct pppoe_hdr *ph;
index d5afe05cd8267de3b9e3e308f28bf711d5efc093..f0471d102e3c61bcfc6089c483009e52b2427cfb 100644 (file)
@@ -187,6 +187,7 @@ static struct pci_device_id rtl8169_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8169), },
        { PCI_DEVICE(PCI_VENDOR_ID_DLINK,       0x4300), },
        { PCI_DEVICE(0x16ec,                    0x0116), },
+       { PCI_VENDOR_ID_LINKSYS,                0x1032, PCI_ANY_ID, 0x0024, },
        {0,},
 };
 
index 12a86f96d973d42af9c52a0916a90cfbc86d84d3..ec1a18d189a129a816c2c194bb56e489b20245d6 100644 (file)
@@ -1429,6 +1429,7 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct rr_private *rrpriv = netdev_priv(dev);
        struct rr_regs __iomem *regs = rrpriv->regs;
+       struct hippi_cb *hcb = (struct hippi_cb *) skb->cb;
        struct ring_ctrl *txctrl;
        unsigned long flags;
        u32 index, len = skb->len;
@@ -1460,7 +1461,7 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev)
        ifield = (u32 *)skb_push(skb, 8);
 
        ifield[0] = 0;
-       ifield[1] = skb->private.ifield;
+       ifield[1] = hcb->ifield;
 
        /*
         * We don't need the lock before we are actually going to start
index 7092ca6b277e31cace6f06cbfa4396a425576055..7cefe5507b9e128bef1f621aeb29837105c254cf 100644 (file)
@@ -1,5 +1,5 @@
 /************************************************************************
- * regs.h: A Linux PCI-X Ethernet driver for S2IO 10GbE Server NIC
+ * regs.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
  * Copyright(c) 2002-2005 Neterion Inc.
 
  * This software may be used and distributed according to the terms of
@@ -62,6 +62,7 @@ typedef struct _XENA_dev_config {
 #define ADAPTER_STATUS_RMAC_REMOTE_FAULT   BIT(6)
 #define ADAPTER_STATUS_RMAC_LOCAL_FAULT    BIT(7)
 #define ADAPTER_STATUS_RMAC_PCC_IDLE       vBIT(0xFF,8,8)
+#define ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE  vBIT(0x0F,8,8)
 #define ADAPTER_STATUS_RC_PRC_QUIESCENT    vBIT(0xFF,16,8)
 #define ADAPTER_STATUS_MC_DRAM_READY       BIT(24)
 #define ADAPTER_STATUS_MC_QUEUES_READY     BIT(25)
@@ -77,21 +78,34 @@ typedef struct _XENA_dev_config {
 #define ADAPTER_ECC_EN                     BIT(55)
 
        u64 serr_source;
-#define SERR_SOURCE_PIC                                        BIT(0)
-#define SERR_SOURCE_TXDMA                              BIT(1)
-#define SERR_SOURCE_RXDMA                              BIT(2)
+#define SERR_SOURCE_PIC                        BIT(0)
+#define SERR_SOURCE_TXDMA              BIT(1)
+#define SERR_SOURCE_RXDMA              BIT(2)
 #define SERR_SOURCE_MAC                 BIT(3)
 #define SERR_SOURCE_MC                  BIT(4)
 #define SERR_SOURCE_XGXS                BIT(5)
-#define        SERR_SOURCE_ANY                                 (SERR_SOURCE_PIC                | \
-                                                                               SERR_SOURCE_TXDMA       | \
-                                                                               SERR_SOURCE_RXDMA       | \
-                                                                               SERR_SOURCE_MAC         | \
-                                                                               SERR_SOURCE_MC      | \
-                                                                               SERR_SOURCE_XGXS)
-
-
-       u8 unused_0[0x800 - 0x120];
+#define        SERR_SOURCE_ANY                 (SERR_SOURCE_PIC        | \
+                                       SERR_SOURCE_TXDMA       | \
+                                       SERR_SOURCE_RXDMA       | \
+                                       SERR_SOURCE_MAC         | \
+                                       SERR_SOURCE_MC          | \
+                                       SERR_SOURCE_XGXS)
+
+       u64 pci_mode;
+#define        GET_PCI_MODE(val)               ((val & vBIT(0xF, 0, 4)) >> 60)
+#define        PCI_MODE_PCI_33                 0
+#define        PCI_MODE_PCI_66                 0x1
+#define        PCI_MODE_PCIX_M1_66             0x2
+#define        PCI_MODE_PCIX_M1_100            0x3
+#define        PCI_MODE_PCIX_M1_133            0x4
+#define        PCI_MODE_PCIX_M2_66             0x5
+#define        PCI_MODE_PCIX_M2_100            0x6
+#define        PCI_MODE_PCIX_M2_133            0x7
+#define        PCI_MODE_UNSUPPORTED            BIT(0)
+#define        PCI_MODE_32_BITS                BIT(8)
+#define        PCI_MODE_UNKNOWN_MODE           BIT(9)
+
+       u8 unused_0[0x800 - 0x128];
 
 /* PCI-X Controller registers */
        u64 pic_int_status;
@@ -153,7 +167,11 @@ typedef struct _XENA_dev_config {
        u8 unused4[0x08];
 
        u64 gpio_int_reg;
+#define GPIO_INT_REG_LINK_DOWN                 BIT(1)
+#define GPIO_INT_REG_LINK_UP                   BIT(2)
        u64 gpio_int_mask;
+#define GPIO_INT_MASK_LINK_DOWN                BIT(1)
+#define GPIO_INT_MASK_LINK_UP                  BIT(2)
        u64 gpio_alarms;
 
        u8 unused5[0x38];
@@ -223,19 +241,16 @@ typedef struct _XENA_dev_config {
        u64 xmsi_data;
 
        u64 rx_mat;
+#define RX_MAT_SET(ring, msi)                  vBIT(msi, (8 * ring), 8)
 
        u8 unused6[0x8];
 
-       u64 tx_mat0_7;
-       u64 tx_mat8_15;
-       u64 tx_mat16_23;
-       u64 tx_mat24_31;
-       u64 tx_mat32_39;
-       u64 tx_mat40_47;
-       u64 tx_mat48_55;
-       u64 tx_mat56_63;
+       u64 tx_mat0_n[0x8];
+#define TX_MAT_SET(fifo, msi)                  vBIT(msi, (8 * fifo), 8)
 
-       u8 unused_1[0x10];
+       u8 unused_1[0x8];
+       u64 stat_byte_cnt;
+#define STAT_BC(n)                              vBIT(n,4,12)
 
        /* Automated statistics collection */
        u64 stat_cfg;
@@ -246,6 +261,7 @@ typedef struct _XENA_dev_config {
 #define STAT_TRSF_PER(n)           TBD
 #define        PER_SEC                                    0x208d5
 #define        SET_UPDT_PERIOD(n)                 vBIT((PER_SEC*n),32,32)
+#define        SET_UPDT_CLICKS(val)               vBIT(val, 32, 32)
 
        u64 stat_addr;
 
@@ -267,8 +283,15 @@ typedef struct _XENA_dev_config {
 
        u64 gpio_control;
 #define GPIO_CTRL_GPIO_0               BIT(8)
+       u64 misc_control;
+#define MISC_LINK_STABILITY_PRD(val)   vBIT(val,29,3)
+
+       u8 unused7_1[0x240 - 0x208];
+
+       u64 wreq_split_mask;
+#define        WREQ_SPLIT_MASK_SET_MASK(val)   vBIT(val, 52, 12)
 
-       u8 unused7[0x600];
+       u8 unused7_2[0x800 - 0x248];
 
 /* TxDMA registers */
        u64 txdma_int_status;
@@ -290,6 +313,7 @@ typedef struct _XENA_dev_config {
 
        u64 pcc_err_reg;
 #define PCC_FB_ECC_DB_ERR              vBIT(0xFF, 16, 8)
+#define PCC_ENABLE_FOUR                        vBIT(0x0F,0,8)
 
        u64 pcc_err_mask;
        u64 pcc_err_alarm;
@@ -468,6 +492,7 @@ typedef struct _XENA_dev_config {
 #define PRC_CTRL_NO_SNOOP                      (BIT(22)|BIT(23))
 #define PRC_CTRL_NO_SNOOP_DESC                 BIT(22)
 #define PRC_CTRL_NO_SNOOP_BUFF                 BIT(23)
+#define PRC_CTRL_BIMODAL_INTERRUPT             BIT(37)
 #define PRC_CTRL_RXD_BACKOFF_INTERVAL(val)     vBIT(val,40,24)
 
        u64 prc_alarm_action;
@@ -688,9 +713,16 @@ typedef struct _XENA_dev_config {
        u64 mc_err_reg;
 #define MC_ERR_REG_ECC_DB_ERR_L            BIT(14)
 #define MC_ERR_REG_ECC_DB_ERR_U            BIT(15)
+#define MC_ERR_REG_MIRI_ECC_DB_ERR_0       BIT(18)
+#define MC_ERR_REG_MIRI_ECC_DB_ERR_1       BIT(20)
 #define MC_ERR_REG_MIRI_CRI_ERR_0          BIT(22)
 #define MC_ERR_REG_MIRI_CRI_ERR_1          BIT(23)
 #define MC_ERR_REG_SM_ERR                  BIT(31)
+#define MC_ERR_REG_ECC_ALL_SNG            (BIT(2) | BIT(3) | BIT(4) | BIT(5) |\
+                                           BIT(6) | BIT(7) | BIT(17) | BIT(19))
+#define MC_ERR_REG_ECC_ALL_DBL            (BIT(10) | BIT(11) | BIT(12) |\
+                                           BIT(13) | BIT(14) | BIT(15) |\
+                                           BIT(18) | BIT(20))
        u64 mc_err_mask;
        u64 mc_err_alarm;
 
@@ -736,7 +768,19 @@ typedef struct _XENA_dev_config {
        u64 mc_rldram_test_d1;
        u8 unused24[0x300 - 0x288];
        u64 mc_rldram_test_d2;
-       u8 unused25[0x700 - 0x308];
+
+       u8 unused24_1[0x360 - 0x308];
+       u64 mc_rldram_ctrl;
+#define        MC_RLDRAM_ENABLE_ODT            BIT(7)
+
+       u8 unused24_2[0x640 - 0x368];
+       u64 mc_rldram_ref_per_herc;
+#define        MC_RLDRAM_SET_REF_PERIOD(val)   vBIT(val, 0, 16)
+
+       u8 unused24_3[0x660 - 0x648];
+       u64 mc_rldram_mrs_herc;
+
+       u8 unused25[0x700 - 0x668];
        u64 mc_debug_ctrl;
 
        u8 unused26[0x3000 - 0x2f08];
index ea638b162d3f09223cd16ca8b97f16073650f354..c829e6a2e8a681242b03fbcb6f26210c633aeb2e 100644 (file)
@@ -1,5 +1,5 @@
 /************************************************************************
- * s2io.c: A Linux PCI-X Ethernet driver for S2IO 10GbE Server NIC
+ * s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
  * Copyright(c) 2002-2005 Neterion Inc.
 
  * This software may be used and distributed according to the terms of
  * See the file COPYING in this distribution for more information.
  *
  * Credits:
- * Jeff Garzik         : For pointing out the improper error condition 
- *                       check in the s2io_xmit routine and also some 
- *                       issues in the Tx watch dog function. Also for
- *                       patiently answering all those innumerable 
+ * Jeff Garzik         : For pointing out the improper error condition
+ *                       check in the s2io_xmit routine and also some
+ *                       issues in the Tx watch dog function. Also for
+ *                       patiently answering all those innumerable
  *                       questions regaring the 2.6 porting issues.
  * Stephen Hemminger   : Providing proper 2.6 porting mechanism for some
  *                       macros available only in 2.6 Kernel.
- * Francois Romieu     : For pointing out all code part that were 
+ * Francois Romieu     : For pointing out all code part that were
  *                       deprecated and also styling related comments.
- * Grant Grundler      : For helping me get rid of some Architecture 
+ * Grant Grundler      : For helping me get rid of some Architecture
  *                       dependent code.
  * Christopher Hellwig : Some more 2.6 specific issues in the driver.
- *                             
+ *
  * The module loadable parameters that are supported by the driver and a brief
  * explaination of all the variables.
- * rx_ring_num : This can be used to program the number of receive rings used 
- * in the driver.                                      
- * rx_ring_len: This defines the number of descriptors each ring can have. This 
+ * rx_ring_num : This can be used to program the number of receive rings used
+ * in the driver.
+ * rx_ring_sz: This defines the number of descriptors each ring can have. This
  * is also an array of size 8.
  * tx_fifo_num: This defines the number of Tx FIFOs thats used int the driver.
- * tx_fifo_len: This too is an array of 8. Each element defines the number of 
+ * tx_fifo_len: This too is an array of 8. Each element defines the number of
  * Tx descriptors that can be associated with each corresponding FIFO.
- * in PCI Configuration space.
  ************************************************************************/
 
 #include <linux/config.h>
 #include <linux/ethtool.h>
 #include <linux/version.h>
 #include <linux/workqueue.h>
+#include <linux/if_vlan.h>
 
-#include <asm/io.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/io.h>
 
 /* local include */
 #include "s2io.h"
 #include "s2io-regs.h"
 
 /* S2io Driver name & version. */
-static char s2io_driver_name[] = "s2io";
-static char s2io_driver_version[] = "Version 1.7.7.1";
+static char s2io_driver_name[] = "Neterion";
+static char s2io_driver_version[] = "Version 2.0.8.1";
+
+static inline int RXD_IS_UP2DT(RxD_t *rxdp)
+{
+       int ret;
+
+       ret = ((!(rxdp->Control_1 & RXD_OWN_XENA)) &&
+               (GET_RXD_MARKER(rxdp->Control_2) != THE_RXD_MARK));
+
+       return ret;
+}
 
-/* 
+/*
  * Cards with following subsystem_id have a link state indication
  * problem, 600B, 600C, 600D, 640B, 640C and 640D.
  * macro below identifies these cards given the subsystem_id.
  */
-#define CARDS_WITH_FAULTY_LINK_INDICATORS(subid) \
-               (((subid >= 0x600B) && (subid <= 0x600D)) || \
-                ((subid >= 0x640B) && (subid <= 0x640D))) ? 1 : 0
+#define CARDS_WITH_FAULTY_LINK_INDICATORS(dev_type, subid) \
+       (dev_type == XFRAME_I_DEVICE) ?                 \
+               ((((subid >= 0x600B) && (subid <= 0x600D)) || \
+                ((subid >= 0x640B) && (subid <= 0x640D))) ? 1 : 0) : 0
 
 #define LINK_IS_UP(val64) (!(val64 & (ADAPTER_STATUS_RMAC_REMOTE_FAULT | \
                                      ADAPTER_STATUS_RMAC_LOCAL_FAULT)))
@@ -86,9 +97,12 @@ static char s2io_driver_version[] = "Version 1.7.7.1";
 static inline int rx_buffer_level(nic_t * sp, int rxb_size, int ring)
 {
        int level = 0;
-       if ((sp->pkt_cnt[ring] - rxb_size) > 16) {
+       mac_info_t *mac_control;
+
+       mac_control = &sp->mac_control;
+       if ((mac_control->rings[ring].pkt_cnt - rxb_size) > 16) {
                level = LOW;
-               if ((sp->pkt_cnt[ring] - rxb_size) < MAX_RXDS_PER_BLOCK) {
+               if (rxb_size <= MAX_RXDS_PER_BLOCK) {
                        level = PANIC;
                }
        }
@@ -145,6 +159,9 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
        {"rmac_pause_cnt"},
        {"rmac_accepted_ip"},
        {"rmac_err_tcp"},
+       {"\n DRIVER STATISTICS"},
+       {"single_bit_ecc_errs"},
+       {"double_bit_ecc_errs"},
 };
 
 #define S2IO_STAT_LEN sizeof(ethtool_stats_keys)/ ETH_GSTRING_LEN
@@ -153,8 +170,37 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
 #define S2IO_TEST_LEN  sizeof(s2io_gstrings) / ETH_GSTRING_LEN
 #define S2IO_STRINGS_LEN       S2IO_TEST_LEN * ETH_GSTRING_LEN
 
+#define S2IO_TIMER_CONF(timer, handle, arg, exp)               \
+                       init_timer(&timer);                     \
+                       timer.function = handle;                \
+                       timer.data = (unsigned long) arg;       \
+                       mod_timer(&timer, (jiffies + exp))      \
+
+/* Add the vlan */
+static void s2io_vlan_rx_register(struct net_device *dev,
+                                       struct vlan_group *grp)
+{
+       nic_t *nic = dev->priv;
+       unsigned long flags;
+
+       spin_lock_irqsave(&nic->tx_lock, flags);
+       nic->vlgrp = grp;
+       spin_unlock_irqrestore(&nic->tx_lock, flags);
+}
+
+/* Unregister the vlan */
+static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
+{
+       nic_t *nic = dev->priv;
+       unsigned long flags;
+
+       spin_lock_irqsave(&nic->tx_lock, flags);
+       if (nic->vlgrp)
+               nic->vlgrp->vlan_devices[vid] = NULL;
+       spin_unlock_irqrestore(&nic->tx_lock, flags);
+}
 
-/* 
+/*
  * Constants to be programmed into the Xena's registers, to configure
  * the XAUI.
  */
@@ -162,7 +208,28 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
 #define SWITCH_SIGN    0xA5A5A5A5A5A5A5A5ULL
 #define        END_SIGN        0x0
 
-static u64 default_mdio_cfg[] = {
+static u64 herc_act_dtx_cfg[] = {
+       /* Set address */
+       0x8000051536750000ULL, 0x80000515367500E0ULL,
+       /* Write data */
+       0x8000051536750004ULL, 0x80000515367500E4ULL,
+       /* Set address */
+       0x80010515003F0000ULL, 0x80010515003F00E0ULL,
+       /* Write data */
+       0x80010515003F0004ULL, 0x80010515003F00E4ULL,
+       /* Set address */
+       0x801205150D440000ULL, 0x801205150D4400E0ULL,
+       /* Write data */
+       0x801205150D440004ULL, 0x801205150D4400E4ULL,
+       /* Set address */
+       0x80020515F2100000ULL, 0x80020515F21000E0ULL,
+       /* Write data */
+       0x80020515F2100004ULL, 0x80020515F21000E4ULL,
+       /* Done */
+       END_SIGN
+};
+
+static u64 xena_mdio_cfg[] = {
        /* Reset PMA PLL */
        0xC001010000000000ULL, 0xC0010100000000E0ULL,
        0xC0010100008000E4ULL,
@@ -172,7 +239,7 @@ static u64 default_mdio_cfg[] = {
        END_SIGN
 };
 
-static u64 default_dtx_cfg[] = {
+static u64 xena_dtx_cfg[] = {
        0x8000051500000000ULL, 0x80000515000000E0ULL,
        0x80000515D93500E4ULL, 0x8001051500000000ULL,
        0x80010515000000E0ULL, 0x80010515001E00E4ULL,
@@ -196,8 +263,7 @@ static u64 default_dtx_cfg[] = {
        END_SIGN
 };
 
-
-/* 
+/*
  * Constants for Fixing the MacAddress problem seen mostly on
  * Alpha machines.
  */
@@ -226,20 +292,25 @@ static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
 static unsigned int rx_ring_num = 1;
 static unsigned int rx_ring_sz[MAX_RX_RINGS] =
     {[0 ...(MAX_RX_RINGS - 1)] = 0 };
-static unsigned int Stats_refresh_time = 4;
+static unsigned int rts_frm_len[MAX_RX_RINGS] =
+    {[0 ...(MAX_RX_RINGS - 1)] = 0 };
+static unsigned int use_continuous_tx_intrs = 1;
 static unsigned int rmac_pause_time = 65535;
 static unsigned int mc_pause_threshold_q0q3 = 187;
 static unsigned int mc_pause_threshold_q4q7 = 187;
 static unsigned int shared_splits;
 static unsigned int tmac_util_period = 5;
 static unsigned int rmac_util_period = 5;
+static unsigned int bimodal = 0;
 #ifndef CONFIG_S2IO_NAPI
 static unsigned int indicate_max_pkts;
 #endif
+/* Frequency of Rx desc syncs expressed as power of 2 */
+static unsigned int rxsync_frequency = 3;
 
-/* 
+/*
  * S2IO device table.
- * This table lists all the devices that this driver supports. 
+ * This table lists all the devices that this driver supports.
  */
 static struct pci_device_id s2io_tbl[] __devinitdata = {
        {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_WIN,
@@ -247,9 +318,9 @@ static struct pci_device_id s2io_tbl[] __devinitdata = {
        {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI,
         PCI_ANY_ID, PCI_ANY_ID},
        {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_WIN,
-        PCI_ANY_ID, PCI_ANY_ID},
-       {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI,
-        PCI_ANY_ID, PCI_ANY_ID},
+         PCI_ANY_ID, PCI_ANY_ID},
+        {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI,
+         PCI_ANY_ID, PCI_ANY_ID},
        {0,}
 };
 
@@ -268,8 +339,8 @@ static struct pci_driver s2io_driver = {
 /**
  * init_shared_mem - Allocation and Initialization of Memory
  * @nic: Device private variable.
- * Description: The function allocates all the memory areas shared 
- * between the NIC and the driver. This includes Tx descriptors, 
+ * Description: The function allocates all the memory areas shared
+ * between the NIC and the driver. This includes Tx descriptors,
  * Rx descriptors and the statistics block.
  */
 
@@ -279,7 +350,7 @@ static int init_shared_mem(struct s2io_nic *nic)
        void *tmp_v_addr, *tmp_v_addr_next;
        dma_addr_t tmp_p_addr, tmp_p_addr_next;
        RxD_block_t *pre_rxd_blk = NULL;
-       int i, j, blk_cnt;
+       int i, j, blk_cnt, rx_sz, tx_sz;
        int lst_size, lst_per_page;
        struct net_device *dev = nic->dev;
 #ifdef CONFIG_2BUFF_MODE
@@ -300,36 +371,41 @@ static int init_shared_mem(struct s2io_nic *nic)
                size += config->tx_cfg[i].fifo_len;
        }
        if (size > MAX_AVAILABLE_TXDS) {
-               DBG_PRINT(ERR_DBG, "%s: Total number of Tx FIFOs ",
-                         dev->name);
-               DBG_PRINT(ERR_DBG, "exceeds the maximum value ");
-               DBG_PRINT(ERR_DBG, "that can be used\n");
+               DBG_PRINT(ERR_DBG, "%s: Requested TxDs too high, ",
+                         __FUNCTION__);
+               DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", size);
                return FAILURE;
        }
 
        lst_size = (sizeof(TxD_t) * config->max_txds);
+       tx_sz = lst_size * size;
        lst_per_page = PAGE_SIZE / lst_size;
 
        for (i = 0; i < config->tx_fifo_num; i++) {
                int fifo_len = config->tx_cfg[i].fifo_len;
                int list_holder_size = fifo_len * sizeof(list_info_hold_t);
-               nic->list_info[i] = kmalloc(list_holder_size, GFP_KERNEL);
-               if (!nic->list_info[i]) {
+               mac_control->fifos[i].list_info = kmalloc(list_holder_size,
+                                                         GFP_KERNEL);
+               if (!mac_control->fifos[i].list_info) {
                        DBG_PRINT(ERR_DBG,
                                  "Malloc failed for list_info\n");
                        return -ENOMEM;
                }
-               memset(nic->list_info[i], 0, list_holder_size);
+               memset(mac_control->fifos[i].list_info, 0, list_holder_size);
        }
        for (i = 0; i < config->tx_fifo_num; i++) {
                int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
                                                lst_per_page);
-               mac_control->tx_curr_put_info[i].offset = 0;
-               mac_control->tx_curr_put_info[i].fifo_len =
+               mac_control->fifos[i].tx_curr_put_info.offset = 0;
+               mac_control->fifos[i].tx_curr_put_info.fifo_len =
                    config->tx_cfg[i].fifo_len - 1;
-               mac_control->tx_curr_get_info[i].offset = 0;
-               mac_control->tx_curr_get_info[i].fifo_len =
+               mac_control->fifos[i].tx_curr_get_info.offset = 0;
+               mac_control->fifos[i].tx_curr_get_info.fifo_len =
                    config->tx_cfg[i].fifo_len - 1;
+               mac_control->fifos[i].fifo_no = i;
+               mac_control->fifos[i].nic = nic;
+               mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 1;
+
                for (j = 0; j < page_num; j++) {
                        int k = 0;
                        dma_addr_t tmp_p;
@@ -342,19 +418,38 @@ static int init_shared_mem(struct s2io_nic *nic)
                                DBG_PRINT(ERR_DBG, "failed for TxDL\n");
                                return -ENOMEM;
                        }
+                       /* If we got a zero DMA address(can happen on
+                        * certain platforms like PPC), reallocate.
+                        * Store virtual address of page we don't want,
+                        * to be freed later.
+                        */
+                       if (!tmp_p) {
+                               mac_control->zerodma_virt_addr = tmp_v;
+                               DBG_PRINT(INIT_DBG, 
+                               "%s: Zero DMA address for TxDL. ", dev->name);
+                               DBG_PRINT(INIT_DBG, 
+                               "Virtual address %llx\n", (u64)tmp_v);
+                               tmp_v = pci_alloc_consistent(nic->pdev,
+                                                    PAGE_SIZE, &tmp_p);
+                               if (!tmp_v) {
+                                       DBG_PRINT(ERR_DBG,
+                                         "pci_alloc_consistent ");
+                                       DBG_PRINT(ERR_DBG, "failed for TxDL\n");
+                                       return -ENOMEM;
+                               }
+                       }
                        while (k < lst_per_page) {
                                int l = (j * lst_per_page) + k;
                                if (l == config->tx_cfg[i].fifo_len)
-                                       goto end_txd_alloc;
-                               nic->list_info[i][l].list_virt_addr =
+                                       break;
+                               mac_control->fifos[i].list_info[l].list_virt_addr =
                                    tmp_v + (k * lst_size);
-                               nic->list_info[i][l].list_phy_addr =
+                               mac_control->fifos[i].list_info[l].list_phy_addr =
                                    tmp_p + (k * lst_size);
                                k++;
                        }
                }
        }
-      end_txd_alloc:
 
        /* Allocation and initialization of RXDs in Rings */
        size = 0;
@@ -367,21 +462,26 @@ static int init_shared_mem(struct s2io_nic *nic)
                        return FAILURE;
                }
                size += config->rx_cfg[i].num_rxd;
-               nic->block_count[i] =
+               mac_control->rings[i].block_count =
                    config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1);
-               nic->pkt_cnt[i] =
-                   config->rx_cfg[i].num_rxd - nic->block_count[i];
+               mac_control->rings[i].pkt_cnt =
+                   config->rx_cfg[i].num_rxd - mac_control->rings[i].block_count;
        }
+       size = (size * (sizeof(RxD_t)));
+       rx_sz = size;
 
        for (i = 0; i < config->rx_ring_num; i++) {
-               mac_control->rx_curr_get_info[i].block_index = 0;
-               mac_control->rx_curr_get_info[i].offset = 0;
-               mac_control->rx_curr_get_info[i].ring_len =
+               mac_control->rings[i].rx_curr_get_info.block_index = 0;
+               mac_control->rings[i].rx_curr_get_info.offset = 0;
+               mac_control->rings[i].rx_curr_get_info.ring_len =
                    config->rx_cfg[i].num_rxd - 1;
-               mac_control->rx_curr_put_info[i].block_index = 0;
-               mac_control->rx_curr_put_info[i].offset = 0;
-               mac_control->rx_curr_put_info[i].ring_len =
+               mac_control->rings[i].rx_curr_put_info.block_index = 0;
+               mac_control->rings[i].rx_curr_put_info.offset = 0;
+               mac_control->rings[i].rx_curr_put_info.ring_len =
                    config->rx_cfg[i].num_rxd - 1;
+               mac_control->rings[i].nic = nic;
+               mac_control->rings[i].ring_no = i;
+
                blk_cnt =
                    config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1);
                /*  Allocating all the Rx blocks */
@@ -395,32 +495,36 @@ static int init_shared_mem(struct s2io_nic *nic)
                                                          &tmp_p_addr);
                        if (tmp_v_addr == NULL) {
                                /*
-                                * In case of failure, free_shared_mem() 
-                                * is called, which should free any 
-                                * memory that was alloced till the 
+                                * In case of failure, free_shared_mem()
+                                * is called, which should free any
+                                * memory that was alloced till the
                                 * failure happened.
                                 */
-                               nic->rx_blocks[i][j].block_virt_addr =
+                               mac_control->rings[i].rx_blocks[j].block_virt_addr =
                                    tmp_v_addr;
                                return -ENOMEM;
                        }
                        memset(tmp_v_addr, 0, size);
-                       nic->rx_blocks[i][j].block_virt_addr = tmp_v_addr;
-                       nic->rx_blocks[i][j].block_dma_addr = tmp_p_addr;
+                       mac_control->rings[i].rx_blocks[j].block_virt_addr =
+                               tmp_v_addr;
+                       mac_control->rings[i].rx_blocks[j].block_dma_addr =
+                               tmp_p_addr;
                }
                /* Interlinking all Rx Blocks */
                for (j = 0; j < blk_cnt; j++) {
-                       tmp_v_addr = nic->rx_blocks[i][j].block_virt_addr;
+                       tmp_v_addr =
+                               mac_control->rings[i].rx_blocks[j].block_virt_addr;
                        tmp_v_addr_next =
-                           nic->rx_blocks[i][(j + 1) %
+                               mac_control->rings[i].rx_blocks[(j + 1) %
                                              blk_cnt].block_virt_addr;
-                       tmp_p_addr = nic->rx_blocks[i][j].block_dma_addr;
+                       tmp_p_addr =
+                               mac_control->rings[i].rx_blocks[j].block_dma_addr;
                        tmp_p_addr_next =
-                           nic->rx_blocks[i][(j + 1) %
+                               mac_control->rings[i].rx_blocks[(j + 1) %
                                              blk_cnt].block_dma_addr;
 
                        pre_rxd_blk = (RxD_block_t *) tmp_v_addr;
-                       pre_rxd_blk->reserved_1 = END_OF_BLOCK; /* last RxD 
+                       pre_rxd_blk->reserved_1 = END_OF_BLOCK; /* last RxD
                                                                 * marker.
                                                                 */
 #ifndef        CONFIG_2BUFF_MODE
@@ -433,28 +537,28 @@ static int init_shared_mem(struct s2io_nic *nic)
        }
 
 #ifdef CONFIG_2BUFF_MODE
-       /* 
+       /*
         * Allocation of Storages for buffer addresses in 2BUFF mode
         * and the buffers as well.
         */
        for (i = 0; i < config->rx_ring_num; i++) {
                blk_cnt =
                    config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1);
-               nic->ba[i] = kmalloc((sizeof(buffAdd_t *) * blk_cnt),
+               mac_control->rings[i].ba = kmalloc((sizeof(buffAdd_t *) * blk_cnt),
                                     GFP_KERNEL);
-               if (!nic->ba[i])
+               if (!mac_control->rings[i].ba)
                        return -ENOMEM;
                for (j = 0; j < blk_cnt; j++) {
                        int k = 0;
-                       nic->ba[i][j] = kmalloc((sizeof(buffAdd_t) *
+                       mac_control->rings[i].ba[j] = kmalloc((sizeof(buffAdd_t) *
                                                 (MAX_RXDS_PER_BLOCK + 1)),
                                                GFP_KERNEL);
-                       if (!nic->ba[i][j])
+                       if (!mac_control->rings[i].ba[j])
                                return -ENOMEM;
                        while (k != MAX_RXDS_PER_BLOCK) {
-                               ba = &nic->ba[i][j][k];
+                               ba = &mac_control->rings[i].ba[j][k];
 
-                               ba->ba_0_org = kmalloc
+                               ba->ba_0_org = (void *) kmalloc
                                    (BUF0_LEN + ALIGN_SIZE, GFP_KERNEL);
                                if (!ba->ba_0_org)
                                        return -ENOMEM;
@@ -463,7 +567,7 @@ static int init_shared_mem(struct s2io_nic *nic)
                                tmp &= ~((unsigned long) ALIGN_SIZE);
                                ba->ba_0 = (void *) tmp;
 
-                               ba->ba_1_org = kmalloc
+                               ba->ba_1_org = (void *) kmalloc
                                    (BUF1_LEN + ALIGN_SIZE, GFP_KERNEL);
                                if (!ba->ba_1_org)
                                        return -ENOMEM;
@@ -483,9 +587,9 @@ static int init_shared_mem(struct s2io_nic *nic)
            (nic->pdev, size, &mac_control->stats_mem_phy);
 
        if (!mac_control->stats_mem) {
-               /* 
-                * In case of failure, free_shared_mem() is called, which 
-                * should free any memory that was alloced till the 
+               /*
+                * In case of failure, free_shared_mem() is called, which
+                * should free any memory that was alloced till the
                 * failure happened.
                 */
                return -ENOMEM;
@@ -495,15 +599,14 @@ static int init_shared_mem(struct s2io_nic *nic)
        tmp_v_addr = mac_control->stats_mem;
        mac_control->stats_info = (StatInfo_t *) tmp_v_addr;
        memset(tmp_v_addr, 0, size);
-
        DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name,
                  (unsigned long long) tmp_p_addr);
 
        return SUCCESS;
 }
 
-/**  
- * free_shared_mem - Free the allocated Memory 
+/**
+ * free_shared_mem - Free the allocated Memory
  * @nic:  Device private variable.
  * Description: This function is to free all memory locations allocated by
  * the init_shared_mem() function and return it to the kernel.
@@ -517,7 +620,7 @@ static void free_shared_mem(struct s2io_nic *nic)
        mac_info_t *mac_control;
        struct config_param *config;
        int lst_size, lst_per_page;
-
+       struct net_device *dev = nic->dev;
 
        if (!nic)
                return;
@@ -533,15 +636,32 @@ static void free_shared_mem(struct s2io_nic *nic)
                                                lst_per_page);
                for (j = 0; j < page_num; j++) {
                        int mem_blks = (j * lst_per_page);
-                       if (!nic->list_info[i][mem_blks].list_virt_addr)
+                       if (!mac_control->fifos[i].list_info)
+                               return; 
+                       if (!mac_control->fifos[i].list_info[mem_blks].
+                                list_virt_addr)
                                break;
                        pci_free_consistent(nic->pdev, PAGE_SIZE,
-                                           nic->list_info[i][mem_blks].
+                                           mac_control->fifos[i].
+                                           list_info[mem_blks].
                                            list_virt_addr,
-                                           nic->list_info[i][mem_blks].
+                                           mac_control->fifos[i].
+                                           list_info[mem_blks].
                                            list_phy_addr);
                }
-               kfree(nic->list_info[i]);
+               /* If we got a zero DMA address during allocation,
+                * free the page now
+                */
+               if (mac_control->zerodma_virt_addr) {
+                       pci_free_consistent(nic->pdev, PAGE_SIZE,
+                                           mac_control->zerodma_virt_addr,
+                                           (dma_addr_t)0);
+                       DBG_PRINT(INIT_DBG, 
+                       "%s: Freeing TxDL with zero DMA addr. ", dev->name);
+                       DBG_PRINT(INIT_DBG, "Virtual address %llx\n",
+                       (u64)(mac_control->zerodma_virt_addr));
+               }
+               kfree(mac_control->fifos[i].list_info);
        }
 
 #ifndef CONFIG_2BUFF_MODE
@@ -550,10 +670,12 @@ static void free_shared_mem(struct s2io_nic *nic)
        size = SIZE_OF_BLOCK;
 #endif
        for (i = 0; i < config->rx_ring_num; i++) {
-               blk_cnt = nic->block_count[i];
+               blk_cnt = mac_control->rings[i].block_count;
                for (j = 0; j < blk_cnt; j++) {
-                       tmp_v_addr = nic->rx_blocks[i][j].block_virt_addr;
-                       tmp_p_addr = nic->rx_blocks[i][j].block_dma_addr;
+                       tmp_v_addr = mac_control->rings[i].rx_blocks[j].
+                               block_virt_addr;
+                       tmp_p_addr = mac_control->rings[i].rx_blocks[j].
+                               block_dma_addr;
                        if (tmp_v_addr == NULL)
                                break;
                        pci_free_consistent(nic->pdev, size,
@@ -566,35 +688,21 @@ static void free_shared_mem(struct s2io_nic *nic)
        for (i = 0; i < config->rx_ring_num; i++) {
                blk_cnt =
                    config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1);
-               if (!nic->ba[i])
-                       goto end_free;
                for (j = 0; j < blk_cnt; j++) {
                        int k = 0;
-                       if (!nic->ba[i][j]) {
-                               kfree(nic->ba[i]);
-                               goto end_free;
-                       }
+                       if (!mac_control->rings[i].ba[j])
+                               continue;
                        while (k != MAX_RXDS_PER_BLOCK) {
-                               buffAdd_t *ba = &nic->ba[i][j][k];
-                               if (!ba || !ba->ba_0_org || !ba->ba_1_org)
-                               {
-                                       kfree(nic->ba[i]);
-                                       kfree(nic->ba[i][j]);
-                                       if(ba->ba_0_org)
-                                               kfree(ba->ba_0_org);
-                                       if(ba->ba_1_org)
-                                               kfree(ba->ba_1_org);
-                                       goto end_free;
-                               }
+                               buffAdd_t *ba = &mac_control->rings[i].ba[j][k];
                                kfree(ba->ba_0_org);
                                kfree(ba->ba_1_org);
                                k++;
                        }
-                       kfree(nic->ba[i][j]);
+                       kfree(mac_control->rings[i].ba[j]);
                }
-               kfree(nic->ba[i]);
+               if (mac_control->rings[i].ba)
+                       kfree(mac_control->rings[i].ba);
        }
-end_free:
 #endif
 
        if (mac_control->stats_mem) {
@@ -605,12 +713,93 @@ end_free:
        }
 }
 
-/**  
- *  init_nic - Initialization of hardware 
+/**
+ * s2io_verify_pci_mode -
+ */
+
+static int s2io_verify_pci_mode(nic_t *nic)
+{
+       XENA_dev_config_t __iomem *bar0 = nic->bar0;
+       register u64 val64 = 0;
+       int     mode;
+
+       val64 = readq(&bar0->pci_mode);
+       mode = (u8)GET_PCI_MODE(val64);
+
+       if ( val64 & PCI_MODE_UNKNOWN_MODE)
+               return -1;      /* Unknown PCI mode */
+       return mode;
+}
+
+
+/**
+ * s2io_print_pci_mode -
+ */
+static int s2io_print_pci_mode(nic_t *nic)
+{
+       XENA_dev_config_t __iomem *bar0 = nic->bar0;
+       register u64 val64 = 0;
+       int     mode;
+       struct config_param *config = &nic->config;
+
+       val64 = readq(&bar0->pci_mode);
+       mode = (u8)GET_PCI_MODE(val64);
+
+       if ( val64 & PCI_MODE_UNKNOWN_MODE)
+               return -1;      /* Unknown PCI mode */
+
+       if (val64 & PCI_MODE_32_BITS) {
+               DBG_PRINT(ERR_DBG, "%s: Device is on 32 bit ", nic->dev->name);
+       } else {
+               DBG_PRINT(ERR_DBG, "%s: Device is on 64 bit ", nic->dev->name);
+       }
+
+       switch(mode) {
+               case PCI_MODE_PCI_33:
+                       DBG_PRINT(ERR_DBG, "33MHz PCI bus\n");
+                       config->bus_speed = 33;
+                       break;
+               case PCI_MODE_PCI_66:
+                       DBG_PRINT(ERR_DBG, "66MHz PCI bus\n");
+                       config->bus_speed = 133;
+                       break;
+               case PCI_MODE_PCIX_M1_66:
+                       DBG_PRINT(ERR_DBG, "66MHz PCIX(M1) bus\n");
+                       config->bus_speed = 133; /* Herc doubles the clock rate */
+                       break;
+               case PCI_MODE_PCIX_M1_100:
+                       DBG_PRINT(ERR_DBG, "100MHz PCIX(M1) bus\n");
+                       config->bus_speed = 200;
+                       break;
+               case PCI_MODE_PCIX_M1_133:
+                       DBG_PRINT(ERR_DBG, "133MHz PCIX(M1) bus\n");
+                       config->bus_speed = 266;
+                       break;
+               case PCI_MODE_PCIX_M2_66:
+                       DBG_PRINT(ERR_DBG, "133MHz PCIX(M2) bus\n");
+                       config->bus_speed = 133;
+                       break;
+               case PCI_MODE_PCIX_M2_100:
+                       DBG_PRINT(ERR_DBG, "200MHz PCIX(M2) bus\n");
+                       config->bus_speed = 200;
+                       break;
+               case PCI_MODE_PCIX_M2_133:
+                       DBG_PRINT(ERR_DBG, "266MHz PCIX(M2) bus\n");
+                       config->bus_speed = 266;
+                       break;
+               default:
+                       return -1;      /* Unsupported bus speed */
+       }
+
+       return mode;
+}
+
+/**
+ *  init_nic - Initialization of hardware
  *  @nic: device peivate variable
- *  Description: The function sequentially configures every block 
- *  of the H/W from their reset values. 
- *  Return Value:  SUCCESS on success and 
+ *  Description: The function sequentially configures every block
+ *  of the H/W from their reset values.
+ *  Return Value:  SUCCESS on success and
  *  '-1' on failure (endian settings incorrect).
  */
 
@@ -626,21 +815,32 @@ static int init_nic(struct s2io_nic *nic)
        struct config_param *config;
        int mdio_cnt = 0, dtx_cnt = 0;
        unsigned long long mem_share;
+       int mem_size;
 
        mac_control = &nic->mac_control;
        config = &nic->config;
 
-       /* Initialize swapper control register */
-       if (s2io_set_swapper(nic)) {
+       /* to set the swapper controle on the card */
+       if(s2io_set_swapper(nic)) {
                DBG_PRINT(ERR_DBG,"ERROR: Setting Swapper failed\n");
                return -1;
        }
 
+       /*
+        * Herc requires EOI to be removed from reset before XGXS, so..
+        */
+       if (nic->device_type & XFRAME_II_DEVICE) {
+               val64 = 0xA500000000ULL;
+               writeq(val64, &bar0->sw_reset);
+               msleep(500);
+               val64 = readq(&bar0->sw_reset);
+       }
+
        /* Remove XGXS from reset state */
        val64 = 0;
        writeq(val64, &bar0->sw_reset);
-       val64 = readq(&bar0->sw_reset);
        msleep(500);
+       val64 = readq(&bar0->sw_reset);
 
        /*  Enable Receiving broadcasts */
        add = &bar0->mac_cfg;
@@ -660,48 +860,58 @@ static int init_nic(struct s2io_nic *nic)
        val64 = dev->mtu;
        writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
 
-       /* 
-        * Configuring the XAUI Interface of Xena. 
+       /*
+        * Configuring the XAUI Interface of Xena.
         * ***************************************
-        * To Configure the Xena's XAUI, one has to write a series 
-        * of 64 bit values into two registers in a particular 
-        * sequence. Hence a macro 'SWITCH_SIGN' has been defined 
-        * which will be defined in the array of configuration values 
-        * (default_dtx_cfg & default_mdio_cfg) at appropriate places 
-        * to switch writing from one regsiter to another. We continue 
+        * To Configure the Xena's XAUI, one has to write a series
+        * of 64 bit values into two registers in a particular
+        * sequence. Hence a macro 'SWITCH_SIGN' has been defined
+        * which will be defined in the array of configuration values
+        * (xena_dtx_cfg & xena_mdio_cfg) at appropriate places
+        * to switch writing from one regsiter to another. We continue
         * writing these values until we encounter the 'END_SIGN' macro.
-        * For example, After making a series of 21 writes into 
-        * dtx_control register the 'SWITCH_SIGN' appears and hence we 
+        * For example, After making a series of 21 writes into
+        * dtx_control register the 'SWITCH_SIGN' appears and hence we
         * start writing into mdio_control until we encounter END_SIGN.
         */
-       while (1) {
-             dtx_cfg:
-               while (default_dtx_cfg[dtx_cnt] != END_SIGN) {
-                       if (default_dtx_cfg[dtx_cnt] == SWITCH_SIGN) {
-                               dtx_cnt++;
-                               goto mdio_cfg;
-                       }
-                       SPECIAL_REG_WRITE(default_dtx_cfg[dtx_cnt],
+       if (nic->device_type & XFRAME_II_DEVICE) {
+               while (herc_act_dtx_cfg[dtx_cnt] != END_SIGN) {
+                       SPECIAL_REG_WRITE(herc_act_dtx_cfg[dtx_cnt],
                                          &bar0->dtx_control, UF);
-                       val64 = readq(&bar0->dtx_control);
+                       if (dtx_cnt & 0x1)
+                               msleep(1); /* Necessary!! */
                        dtx_cnt++;
                }
-             mdio_cfg:
-               while (default_mdio_cfg[mdio_cnt] != END_SIGN) {
-                       if (default_mdio_cfg[mdio_cnt] == SWITCH_SIGN) {
+       } else {
+               while (1) {
+                     dtx_cfg:
+                       while (xena_dtx_cfg[dtx_cnt] != END_SIGN) {
+                               if (xena_dtx_cfg[dtx_cnt] == SWITCH_SIGN) {
+                                       dtx_cnt++;
+                                       goto mdio_cfg;
+                               }
+                               SPECIAL_REG_WRITE(xena_dtx_cfg[dtx_cnt],
+                                                 &bar0->dtx_control, UF);
+                               val64 = readq(&bar0->dtx_control);
+                               dtx_cnt++;
+                       }
+                     mdio_cfg:
+                       while (xena_mdio_cfg[mdio_cnt] != END_SIGN) {
+                               if (xena_mdio_cfg[mdio_cnt] == SWITCH_SIGN) {
+                                       mdio_cnt++;
+                                       goto dtx_cfg;
+                               }
+                               SPECIAL_REG_WRITE(xena_mdio_cfg[mdio_cnt],
+                                                 &bar0->mdio_control, UF);
+                               val64 = readq(&bar0->mdio_control);
                                mdio_cnt++;
+                       }
+                       if ((xena_dtx_cfg[dtx_cnt] == END_SIGN) &&
+                           (xena_mdio_cfg[mdio_cnt] == END_SIGN)) {
+                               break;
+                       } else {
                                goto dtx_cfg;
                        }
-                       SPECIAL_REG_WRITE(default_mdio_cfg[mdio_cnt],
-                                         &bar0->mdio_control, UF);
-                       val64 = readq(&bar0->mdio_control);
-                       mdio_cnt++;
-               }
-               if ((default_dtx_cfg[dtx_cnt] == END_SIGN) &&
-                   (default_mdio_cfg[mdio_cnt] == END_SIGN)) {
-                       break;
-               } else {
-                       goto dtx_cfg;
                }
        }
 
@@ -748,12 +958,20 @@ static int init_nic(struct s2io_nic *nic)
        val64 |= BIT(0);        /* To enable the FIFO partition. */
        writeq(val64, &bar0->tx_fifo_partition_0);
 
+       /*
+        * Disable 4 PCCs for Xena1, 2 and 3 as per H/W bug
+        * SXE-008 TRANSMIT DMA ARBITRATION ISSUE.
+        */
+       if ((nic->device_type == XFRAME_I_DEVICE) &&
+               (get_xena_rev_id(nic->pdev) < 4))
+               writeq(PCC_ENABLE_FOUR, &bar0->pcc_enable);
+
        val64 = readq(&bar0->tx_fifo_partition_0);
        DBG_PRINT(INIT_DBG, "Fifo partition at: 0x%p is: 0x%llx\n",
                  &bar0->tx_fifo_partition_0, (unsigned long long) val64);
 
-       /* 
-        * Initialization of Tx_PA_CONFIG register to ignore packet 
+       /*
+        * Initialization of Tx_PA_CONFIG register to ignore packet
         * integrity checking.
         */
        val64 = readq(&bar0->tx_pa_cfg);
@@ -770,85 +988,304 @@ static int init_nic(struct s2io_nic *nic)
        }
        writeq(val64, &bar0->rx_queue_priority);
 
-       /* 
-        * Allocating equal share of memory to all the 
+       /*
+        * Allocating equal share of memory to all the
         * configured Rings.
         */
        val64 = 0;
+       if (nic->device_type & XFRAME_II_DEVICE)
+               mem_size = 32;
+       else
+               mem_size = 64;
+
        for (i = 0; i < config->rx_ring_num; i++) {
                switch (i) {
                case 0:
-                       mem_share = (64 / config->rx_ring_num +
-                                    64 % config->rx_ring_num);
+                       mem_share = (mem_size / config->rx_ring_num +
+                                    mem_size % config->rx_ring_num);
                        val64 |= RX_QUEUE_CFG_Q0_SZ(mem_share);
                        continue;
                case 1:
-                       mem_share = (64 / config->rx_ring_num);
+                       mem_share = (mem_size / config->rx_ring_num);
                        val64 |= RX_QUEUE_CFG_Q1_SZ(mem_share);
                        continue;
                case 2:
-                       mem_share = (64 / config->rx_ring_num);
+                       mem_share = (mem_size / config->rx_ring_num);
                        val64 |= RX_QUEUE_CFG_Q2_SZ(mem_share);
                        continue;
                case 3:
-                       mem_share = (64 / config->rx_ring_num);
+                       mem_share = (mem_size / config->rx_ring_num);
                        val64 |= RX_QUEUE_CFG_Q3_SZ(mem_share);
                        continue;
                case 4:
-                       mem_share = (64 / config->rx_ring_num);
+                       mem_share = (mem_size / config->rx_ring_num);
                        val64 |= RX_QUEUE_CFG_Q4_SZ(mem_share);
                        continue;
                case 5:
-                       mem_share = (64 / config->rx_ring_num);
+                       mem_share = (mem_size / config->rx_ring_num);
                        val64 |= RX_QUEUE_CFG_Q5_SZ(mem_share);
                        continue;
                case 6:
-                       mem_share = (64 / config->rx_ring_num);
+                       mem_share = (mem_size / config->rx_ring_num);
                        val64 |= RX_QUEUE_CFG_Q6_SZ(mem_share);
                        continue;
                case 7:
-                       mem_share = (64 / config->rx_ring_num);
+                       mem_share = (mem_size / config->rx_ring_num);
                        val64 |= RX_QUEUE_CFG_Q7_SZ(mem_share);
                        continue;
                }
        }
        writeq(val64, &bar0->rx_queue_cfg);
 
-       /* 
-        * Initializing the Tx round robin registers to 0.
-        * Filling Tx and Rx round robin registers as per the 
-        * number of FIFOs and Rings is still TODO.
-        */
-       writeq(0, &bar0->tx_w_round_robin_0);
-       writeq(0, &bar0->tx_w_round_robin_1);
-       writeq(0, &bar0->tx_w_round_robin_2);
-       writeq(0, &bar0->tx_w_round_robin_3);
-       writeq(0, &bar0->tx_w_round_robin_4);
-
-       /* 
-        * TODO
-        * Disable Rx steering. Hard coding all packets be steered to
-        * Queue 0 for now. 
+       /*
+        * Filling Tx round robin registers
+        * as per the number of FIFOs
         */
-       val64 = 0x8080808080808080ULL;
-       writeq(val64, &bar0->rts_qos_steering);
+       switch (config->tx_fifo_num) {
+       case 1:
+               val64 = 0x0000000000000000ULL;
+               writeq(val64, &bar0->tx_w_round_robin_0);
+               writeq(val64, &bar0->tx_w_round_robin_1);
+               writeq(val64, &bar0->tx_w_round_robin_2);
+               writeq(val64, &bar0->tx_w_round_robin_3);
+               writeq(val64, &bar0->tx_w_round_robin_4);
+               break;
+       case 2:
+               val64 = 0x0000010000010000ULL;
+               writeq(val64, &bar0->tx_w_round_robin_0);
+               val64 = 0x0100000100000100ULL;
+               writeq(val64, &bar0->tx_w_round_robin_1);
+               val64 = 0x0001000001000001ULL;
+               writeq(val64, &bar0->tx_w_round_robin_2);
+               val64 = 0x0000010000010000ULL;
+               writeq(val64, &bar0->tx_w_round_robin_3);
+               val64 = 0x0100000000000000ULL;
+               writeq(val64, &bar0->tx_w_round_robin_4);
+               break;
+       case 3:
+               val64 = 0x0001000102000001ULL;
+               writeq(val64, &bar0->tx_w_round_robin_0);
+               val64 = 0x0001020000010001ULL;
+               writeq(val64, &bar0->tx_w_round_robin_1);
+               val64 = 0x0200000100010200ULL;
+               writeq(val64, &bar0->tx_w_round_robin_2);
+               val64 = 0x0001000102000001ULL;
+               writeq(val64, &bar0->tx_w_round_robin_3);
+               val64 = 0x0001020000000000ULL;
+               writeq(val64, &bar0->tx_w_round_robin_4);
+               break;
+       case 4:
+               val64 = 0x0001020300010200ULL;
+               writeq(val64, &bar0->tx_w_round_robin_0);
+               val64 = 0x0100000102030001ULL;
+               writeq(val64, &bar0->tx_w_round_robin_1);
+               val64 = 0x0200010000010203ULL;
+               writeq(val64, &bar0->tx_w_round_robin_2);
+               val64 = 0x0001020001000001ULL;
+               writeq(val64, &bar0->tx_w_round_robin_3);
+               val64 = 0x0203000100000000ULL;
+               writeq(val64, &bar0->tx_w_round_robin_4);
+               break;
+       case 5:
+               val64 = 0x0001000203000102ULL;
+               writeq(val64, &bar0->tx_w_round_robin_0);
+               val64 = 0x0001020001030004ULL;
+               writeq(val64, &bar0->tx_w_round_robin_1);
+               val64 = 0x0001000203000102ULL;
+               writeq(val64, &bar0->tx_w_round_robin_2);
+               val64 = 0x0001020001030004ULL;
+               writeq(val64, &bar0->tx_w_round_robin_3);
+               val64 = 0x0001000000000000ULL;
+               writeq(val64, &bar0->tx_w_round_robin_4);
+               break;
+       case 6:
+               val64 = 0x0001020304000102ULL;
+               writeq(val64, &bar0->tx_w_round_robin_0);
+               val64 = 0x0304050001020001ULL;
+               writeq(val64, &bar0->tx_w_round_robin_1);
+               val64 = 0x0203000100000102ULL;
+               writeq(val64, &bar0->tx_w_round_robin_2);
+               val64 = 0x0304000102030405ULL;
+               writeq(val64, &bar0->tx_w_round_robin_3);
+               val64 = 0x0001000200000000ULL;
+               writeq(val64, &bar0->tx_w_round_robin_4);
+               break;
+       case 7:
+               val64 = 0x0001020001020300ULL;
+               writeq(val64, &bar0->tx_w_round_robin_0);
+               val64 = 0x0102030400010203ULL;
+               writeq(val64, &bar0->tx_w_round_robin_1);
+               val64 = 0x0405060001020001ULL;
+               writeq(val64, &bar0->tx_w_round_robin_2);
+               val64 = 0x0304050000010200ULL;
+               writeq(val64, &bar0->tx_w_round_robin_3);
+               val64 = 0x0102030000000000ULL;
+               writeq(val64, &bar0->tx_w_round_robin_4);
+               break;
+       case 8:
+               val64 = 0x0001020300040105ULL;
+               writeq(val64, &bar0->tx_w_round_robin_0);
+               val64 = 0x0200030106000204ULL;
+               writeq(val64, &bar0->tx_w_round_robin_1);
+               val64 = 0x0103000502010007ULL;
+               writeq(val64, &bar0->tx_w_round_robin_2);
+               val64 = 0x0304010002060500ULL;
+               writeq(val64, &bar0->tx_w_round_robin_3);
+               val64 = 0x0103020400000000ULL;
+               writeq(val64, &bar0->tx_w_round_robin_4);
+               break;
+       }
+
+       /* Filling the Rx round robin registers as per the
+        * number of Rings and steering based on QoS.
+         */
+       switch (config->rx_ring_num) {
+       case 1:
+               val64 = 0x8080808080808080ULL;
+               writeq(val64, &bar0->rts_qos_steering);
+               break;
+       case 2:
+               val64 = 0x0000010000010000ULL;
+               writeq(val64, &bar0->rx_w_round_robin_0);
+               val64 = 0x0100000100000100ULL;
+               writeq(val64, &bar0->rx_w_round_robin_1);
+               val64 = 0x0001000001000001ULL;
+               writeq(val64, &bar0->rx_w_round_robin_2);
+               val64 = 0x0000010000010000ULL;
+               writeq(val64, &bar0->rx_w_round_robin_3);
+               val64 = 0x0100000000000000ULL;
+               writeq(val64, &bar0->rx_w_round_robin_4);
+
+               val64 = 0x8080808040404040ULL;
+               writeq(val64, &bar0->rts_qos_steering);
+               break;
+       case 3:
+               val64 = 0x0001000102000001ULL;
+               writeq(val64, &bar0->rx_w_round_robin_0);
+               val64 = 0x0001020000010001ULL;
+               writeq(val64, &bar0->rx_w_round_robin_1);
+               val64 = 0x0200000100010200ULL;
+               writeq(val64, &bar0->rx_w_round_robin_2);
+               val64 = 0x0001000102000001ULL;
+               writeq(val64, &bar0->rx_w_round_robin_3);
+               val64 = 0x0001020000000000ULL;
+               writeq(val64, &bar0->rx_w_round_robin_4);
+
+               val64 = 0x8080804040402020ULL;
+               writeq(val64, &bar0->rts_qos_steering);
+               break;
+       case 4:
+               val64 = 0x0001020300010200ULL;
+               writeq(val64, &bar0->rx_w_round_robin_0);
+               val64 = 0x0100000102030001ULL;
+               writeq(val64, &bar0->rx_w_round_robin_1);
+               val64 = 0x0200010000010203ULL;
+               writeq(val64, &bar0->rx_w_round_robin_2);
+               val64 = 0x0001020001000001ULL;  
+               writeq(val64, &bar0->rx_w_round_robin_3);
+               val64 = 0x0203000100000000ULL;
+               writeq(val64, &bar0->rx_w_round_robin_4);
+
+               val64 = 0x8080404020201010ULL;
+               writeq(val64, &bar0->rts_qos_steering);
+               break;
+       case 5:
+               val64 = 0x0001000203000102ULL;
+               writeq(val64, &bar0->rx_w_round_robin_0);
+               val64 = 0x0001020001030004ULL;
+               writeq(val64, &bar0->rx_w_round_robin_1);
+               val64 = 0x0001000203000102ULL;
+               writeq(val64, &bar0->rx_w_round_robin_2);
+               val64 = 0x0001020001030004ULL;
+               writeq(val64, &bar0->rx_w_round_robin_3);
+               val64 = 0x0001000000000000ULL;
+               writeq(val64, &bar0->rx_w_round_robin_4);
+
+               val64 = 0x8080404020201008ULL;
+               writeq(val64, &bar0->rts_qos_steering);
+               break;
+       case 6:
+               val64 = 0x0001020304000102ULL;
+               writeq(val64, &bar0->rx_w_round_robin_0);
+               val64 = 0x0304050001020001ULL;
+               writeq(val64, &bar0->rx_w_round_robin_1);
+               val64 = 0x0203000100000102ULL;
+               writeq(val64, &bar0->rx_w_round_robin_2);
+               val64 = 0x0304000102030405ULL;
+               writeq(val64, &bar0->rx_w_round_robin_3);
+               val64 = 0x0001000200000000ULL;
+               writeq(val64, &bar0->rx_w_round_robin_4);
+
+               val64 = 0x8080404020100804ULL;
+               writeq(val64, &bar0->rts_qos_steering);
+               break;
+       case 7:
+               val64 = 0x0001020001020300ULL;
+               writeq(val64, &bar0->rx_w_round_robin_0);
+               val64 = 0x0102030400010203ULL;
+               writeq(val64, &bar0->rx_w_round_robin_1);
+               val64 = 0x0405060001020001ULL;
+               writeq(val64, &bar0->rx_w_round_robin_2);
+               val64 = 0x0304050000010200ULL;
+               writeq(val64, &bar0->rx_w_round_robin_3);
+               val64 = 0x0102030000000000ULL;
+               writeq(val64, &bar0->rx_w_round_robin_4);
+
+               val64 = 0x8080402010080402ULL;
+               writeq(val64, &bar0->rts_qos_steering);
+               break;
+       case 8:
+               val64 = 0x0001020300040105ULL;
+               writeq(val64, &bar0->rx_w_round_robin_0);
+               val64 = 0x0200030106000204ULL;
+               writeq(val64, &bar0->rx_w_round_robin_1);
+               val64 = 0x0103000502010007ULL;
+               writeq(val64, &bar0->rx_w_round_robin_2);
+               val64 = 0x0304010002060500ULL;
+               writeq(val64, &bar0->rx_w_round_robin_3);
+               val64 = 0x0103020400000000ULL;
+               writeq(val64, &bar0->rx_w_round_robin_4);
+
+               val64 = 0x8040201008040201ULL;
+               writeq(val64, &bar0->rts_qos_steering);
+               break;
+       }
 
        /* UDP Fix */
        val64 = 0;
-       for (i = 1; i < 8; i++)
+       for (i = 0; i < 8; i++)
+               writeq(val64, &bar0->rts_frm_len_n[i]);
+
+       /* Set the default rts frame length for the rings configured */
+       val64 = MAC_RTS_FRM_LEN_SET(dev->mtu+22);
+       for (i = 0 ; i < config->rx_ring_num ; i++)
                writeq(val64, &bar0->rts_frm_len_n[i]);
 
-       /* Set rts_frm_len register for fifo 0 */
-       writeq(MAC_RTS_FRM_LEN_SET(dev->mtu + 22),
-              &bar0->rts_frm_len_n[0]);
+       /* Set the frame length for the configured rings
+        * desired by the user
+        */
+       for (i = 0; i < config->rx_ring_num; i++) {
+               /* If rts_frm_len[i] == 0 then it is assumed that user not
+                * specified frame length steering.
+                * If the user provides the frame length then program
+                * the rts_frm_len register for those values or else
+                * leave it as it is.
+                */
+               if (rts_frm_len[i] != 0) {
+                       writeq(MAC_RTS_FRM_LEN_SET(rts_frm_len[i]),
+                               &bar0->rts_frm_len_n[i]);
+               }
+       }
 
-       /* Enable statistics */
+       /* Program statistics memory */
        writeq(mac_control->stats_mem_phy, &bar0->stat_addr);
-       val64 = SET_UPDT_PERIOD(Stats_refresh_time) |
-           STAT_CFG_STAT_RO | STAT_CFG_STAT_EN;
-       writeq(val64, &bar0->stat_cfg);
 
-       /* 
+       if (nic->device_type == XFRAME_II_DEVICE) {
+               val64 = STAT_BC(0x320);
+               writeq(val64, &bar0->stat_byte_cnt);
+       }
+
+       /*
         * Initializing the sampling rate for the device to calculate the
         * bandwidth utilization.
         */
@@ -857,30 +1294,38 @@ static int init_nic(struct s2io_nic *nic)
        writeq(val64, &bar0->mac_link_util);
 
 
-       /* 
-        * Initializing the Transmit and Receive Traffic Interrupt 
+       /*
+        * Initializing the Transmit and Receive Traffic Interrupt
         * Scheme.
         */
-       /* TTI Initialization. Default Tx timer gets us about
+       /*
+        * TTI Initialization. Default Tx timer gets us about
         * 250 interrupts per sec. Continuous interrupts are enabled
         * by default.
         */
-       val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078) |
-           TTI_DATA1_MEM_TX_URNG_A(0xA) |
+       if (nic->device_type == XFRAME_II_DEVICE) {
+               int count = (nic->config.bus_speed * 125)/2;
+               val64 = TTI_DATA1_MEM_TX_TIMER_VAL(count);
+       } else {
+
+               val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078);
+       }
+       val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) |
            TTI_DATA1_MEM_TX_URNG_B(0x10) |
-           TTI_DATA1_MEM_TX_URNG_C(0x30) | TTI_DATA1_MEM_TX_TIMER_AC_EN |
-               TTI_DATA1_MEM_TX_TIMER_CI_EN;
+           TTI_DATA1_MEM_TX_URNG_C(0x30) | TTI_DATA1_MEM_TX_TIMER_AC_EN;
+               if (use_continuous_tx_intrs)
+                       val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN;
        writeq(val64, &bar0->tti_data1_mem);
 
        val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
            TTI_DATA2_MEM_TX_UFC_B(0x20) |
-           TTI_DATA2_MEM_TX_UFC_C(0x40) | TTI_DATA2_MEM_TX_UFC_D(0x80);
+           TTI_DATA2_MEM_TX_UFC_C(0x70) | TTI_DATA2_MEM_TX_UFC_D(0x80);
        writeq(val64, &bar0->tti_data2_mem);
 
        val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
        writeq(val64, &bar0->tti_command_mem);
 
-       /* 
+       /*
         * Once the operation completes, the Strobe bit of the command
         * register will be reset. We poll for this particular condition
         * We wait for a maximum of 500ms for the operation to complete,
@@ -901,45 +1346,90 @@ static int init_nic(struct s2io_nic *nic)
                time++;
        }
 
-       /* RTI Initialization */
-       val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF) |
-           RTI_DATA1_MEM_RX_URNG_A(0xA) |
-           RTI_DATA1_MEM_RX_URNG_B(0x10) |
-           RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN;
+       if (nic->config.bimodal) {
+               int k = 0;
+               for (k = 0; k < config->rx_ring_num; k++) {
+                       val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
+                       val64 |= TTI_CMD_MEM_OFFSET(0x38+k);
+                       writeq(val64, &bar0->tti_command_mem);
+
+               /*
+                * Once the operation completes, the Strobe bit of the command
+                * register will be reset. We poll for this particular condition
+                * We wait for a maximum of 500ms for the operation to complete,
+                * if it's not complete by then we return error.
+               */
+                       time = 0;
+                       while (TRUE) {
+                               val64 = readq(&bar0->tti_command_mem);
+                               if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
+                                       break;
+                               }
+                               if (time > 10) {
+                                       DBG_PRINT(ERR_DBG,
+                                               "%s: TTI init Failed\n",
+                                       dev->name);
+                                       return -1;
+                               }
+                               time++;
+                               msleep(50);
+                       }
+               }
+       } else {
 
-       writeq(val64, &bar0->rti_data1_mem);
+               /* RTI Initialization */
+               if (nic->device_type == XFRAME_II_DEVICE) {
+                       /*
+                        * Programmed to generate Apprx 500 Intrs per
+                        * second
+                        */
+                       int count = (nic->config.bus_speed * 125)/4;
+                       val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count);
+               } else {
+                       val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF);
+               }
+               val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) |
+                   RTI_DATA1_MEM_RX_URNG_B(0x10) |
+                   RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN;
 
-       val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) |
-           RTI_DATA2_MEM_RX_UFC_B(0x2) |
-           RTI_DATA2_MEM_RX_UFC_C(0x40) | RTI_DATA2_MEM_RX_UFC_D(0x80);
-       writeq(val64, &bar0->rti_data2_mem);
+               writeq(val64, &bar0->rti_data1_mem);
 
-       val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD;
-       writeq(val64, &bar0->rti_command_mem);
+               val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) |
+                   RTI_DATA2_MEM_RX_UFC_B(0x2) |
+                   RTI_DATA2_MEM_RX_UFC_C(0x40) | RTI_DATA2_MEM_RX_UFC_D(0x80);
+               writeq(val64, &bar0->rti_data2_mem);
 
-       /* 
-        * Once the operation completes, the Strobe bit of the command
-        * register will be reset. We poll for this particular condition
-        * We wait for a maximum of 500ms for the operation to complete,
-        * if it's not complete by then we return error.
-        */
-       time = 0;
-       while (TRUE) {
-               val64 = readq(&bar0->rti_command_mem);
-               if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
-                       break;
-               }
-               if (time > 10) {
-                       DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n",
-                                 dev->name);
-                       return -1;
+               for (i = 0; i < config->rx_ring_num; i++) {
+                       val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD
+                                       | RTI_CMD_MEM_OFFSET(i);
+                       writeq(val64, &bar0->rti_command_mem);
+
+                       /*
+                        * Once the operation completes, the Strobe bit of the
+                        * command register will be reset. We poll for this
+                        * particular condition. We wait for a maximum of 500ms
+                        * for the operation to complete, if it's not complete
+                        * by then we return error.
+                        */
+                       time = 0;
+                       while (TRUE) {
+                               val64 = readq(&bar0->rti_command_mem);
+                               if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) {
+                                       break;
+                               }
+                               if (time > 10) {
+                                       DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n",
+                                                 dev->name);
+                                       return -1;
+                               }
+                               time++;
+                               msleep(50);
+                       }
                }
-               time++;
-               msleep(50);
        }
 
-       /* 
-        * Initializing proper values as Pause threshold into all 
+       /*
+        * Initializing proper values as Pause threshold into all
         * the 8 Queues on Rx side.
         */
        writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q0q3);
@@ -955,8 +1445,8 @@ static int init_nic(struct s2io_nic *nic)
        writel((u32) (val64 >> 32), (add + 4));
        val64 = readq(&bar0->mac_cfg);
 
-       /* 
-        * Set the time value to be inserted in the pause frame 
+       /*
+        * Set the time value to be inserted in the pause frame
         * generated by xena.
         */
        val64 = readq(&bar0->rmac_pause_cfg);
@@ -964,7 +1454,7 @@ static int init_nic(struct s2io_nic *nic)
        val64 |= RMAC_PAUSE_HG_PTIME(nic->mac_control.rmac_pause_time);
        writeq(val64, &bar0->rmac_pause_cfg);
 
-       /* 
+       /*
         * Set the Threshold Limit for Generating the pause frame
         * If the amount of data in any Queue exceeds ratio of
         * (mac_control.mc_pause_threshold_q0q3 or q4q7)/256
@@ -988,25 +1478,54 @@ static int init_nic(struct s2io_nic *nic)
        }
        writeq(val64, &bar0->mc_pause_thresh_q4q7);
 
-       /* 
-        * TxDMA will stop Read request if the number of read split has 
+       /*
+        * TxDMA will stop Read request if the number of read split has
         * exceeded the limit pointed by shared_splits
         */
        val64 = readq(&bar0->pic_control);
        val64 |= PIC_CNTL_SHARED_SPLITS(shared_splits);
        writeq(val64, &bar0->pic_control);
 
+       /*
+        * Programming the Herc to split every write transaction
+        * that does not start on an ADB to reduce disconnects.
+        */
+       if (nic->device_type == XFRAME_II_DEVICE) {
+               val64 = WREQ_SPLIT_MASK_SET_MASK(255);
+               writeq(val64, &bar0->wreq_split_mask);
+       }
+
+       /* Setting Link stability period to 64 ms */ 
+       if (nic->device_type == XFRAME_II_DEVICE) {
+               val64 = MISC_LINK_STABILITY_PRD(3);
+               writeq(val64, &bar0->misc_control);
+       }
+
        return SUCCESS;
 }
+#define LINK_UP_DOWN_INTERRUPT         1
+#define MAC_RMAC_ERR_TIMER             2
+
+#if defined(CONFIG_MSI_MODE) || defined(CONFIG_MSIX_MODE)
+#define s2io_link_fault_indication(x) MAC_RMAC_ERR_TIMER
+#else
+int s2io_link_fault_indication(nic_t *nic)
+{
+       if (nic->device_type == XFRAME_II_DEVICE)
+               return LINK_UP_DOWN_INTERRUPT;
+       else
+               return MAC_RMAC_ERR_TIMER;
+}
+#endif
 
-/**  
- *  en_dis_able_nic_intrs - Enable or Disable the interrupts 
+/**
+ *  en_dis_able_nic_intrs - Enable or Disable the interrupts
  *  @nic: device private variable,
  *  @mask: A mask indicating which Intr block must be modified and,
  *  @flag: A flag indicating whether to enable or disable the Intrs.
  *  Description: This function will either disable or enable the interrupts
- *  depending on the flag argument. The mask argument can be used to 
- *  enable/disable any Intr block. 
+ *  depending on the flag argument. The mask argument can be used to
+ *  enable/disable any Intr block.
  *  Return Value: NONE.
  */
 
@@ -1024,20 +1543,31 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
                        temp64 = readq(&bar0->general_int_mask);
                        temp64 &= ~((u64) val64);
                        writeq(temp64, &bar0->general_int_mask);
-                       /*  
-                        * Disabled all PCIX, Flash, MDIO, IIC and GPIO
-                        * interrupts for now. 
-                        * TODO 
+                       /*
+                        * If Hercules adapter enable GPIO otherwise
+                        * disabled all PCIX, Flash, MDIO, IIC and GPIO
+                        * interrupts for now.
+                        * TODO
                         */
-                       writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
-                       /* 
+                       if (s2io_link_fault_indication(nic) ==
+                                       LINK_UP_DOWN_INTERRUPT ) {
+                               temp64 = readq(&bar0->pic_int_mask);
+                               temp64 &= ~((u64) PIC_INT_GPIO);
+                               writeq(temp64, &bar0->pic_int_mask);
+                               temp64 = readq(&bar0->gpio_int_mask);
+                               temp64 &= ~((u64) GPIO_INT_MASK_LINK_UP);
+                               writeq(temp64, &bar0->gpio_int_mask);
+                       } else {
+                               writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
+                       }
+                       /*
                         * No MSI Support is available presently, so TTI and
                         * RTI interrupts are also disabled.
                         */
                } else if (flag == DISABLE_INTRS) {
-                       /*  
-                        * Disable PIC Intrs in the general 
-                        * intr mask register 
+                       /*
+                        * Disable PIC Intrs in the general
+                        * intr mask register
                         */
                        writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
                        temp64 = readq(&bar0->general_int_mask);
@@ -1055,27 +1585,27 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
                        temp64 = readq(&bar0->general_int_mask);
                        temp64 &= ~((u64) val64);
                        writeq(temp64, &bar0->general_int_mask);
-                       /* 
-                        * Keep all interrupts other than PFC interrupt 
+                       /*
+                        * Keep all interrupts other than PFC interrupt
                         * and PCC interrupt disabled in DMA level.
                         */
                        val64 = DISABLE_ALL_INTRS & ~(TXDMA_PFC_INT_M |
                                                      TXDMA_PCC_INT_M);
                        writeq(val64, &bar0->txdma_int_mask);
-                       /* 
-                        * Enable only the MISC error 1 interrupt in PFC block 
+                       /*
+                        * Enable only the MISC error 1 interrupt in PFC block
                         */
                        val64 = DISABLE_ALL_INTRS & (~PFC_MISC_ERR_1);
                        writeq(val64, &bar0->pfc_err_mask);
-                       /* 
-                        * Enable only the FB_ECC error interrupt in PCC block 
+                       /*
+                        * Enable only the FB_ECC error interrupt in PCC block
                         */
                        val64 = DISABLE_ALL_INTRS & (~PCC_FB_ECC_ERR);
                        writeq(val64, &bar0->pcc_err_mask);
                } else if (flag == DISABLE_INTRS) {
-                       /* 
-                        * Disable TxDMA Intrs in the general intr mask 
-                        * register 
+                       /*
+                        * Disable TxDMA Intrs in the general intr mask
+                        * register
                         */
                        writeq(DISABLE_ALL_INTRS, &bar0->txdma_int_mask);
                        writeq(DISABLE_ALL_INTRS, &bar0->pfc_err_mask);
@@ -1093,15 +1623,15 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
                        temp64 = readq(&bar0->general_int_mask);
                        temp64 &= ~((u64) val64);
                        writeq(temp64, &bar0->general_int_mask);
-                       /* 
-                        * All RxDMA block interrupts are disabled for now 
-                        * TODO 
+                       /*
+                        * All RxDMA block interrupts are disabled for now
+                        * TODO
                         */
                        writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
                } else if (flag == DISABLE_INTRS) {
-                       /*  
-                        * Disable RxDMA Intrs in the general intr mask 
-                        * register 
+                       /*
+                        * Disable RxDMA Intrs in the general intr mask
+                        * register
                         */
                        writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
                        temp64 = readq(&bar0->general_int_mask);
@@ -1118,22 +1648,13 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
                        temp64 = readq(&bar0->general_int_mask);
                        temp64 &= ~((u64) val64);
                        writeq(temp64, &bar0->general_int_mask);
-                       /* 
-                        * All MAC block error interrupts are disabled for now 
-                        * except the link status change interrupt.
+                       /*
+                        * All MAC block error interrupts are disabled for now
                         * TODO
                         */
-                       val64 = MAC_INT_STATUS_RMAC_INT;
-                       temp64 = readq(&bar0->mac_int_mask);
-                       temp64 &= ~((u64) val64);
-                       writeq(temp64, &bar0->mac_int_mask);
-
-                       val64 = readq(&bar0->mac_rmac_err_mask);
-                       val64 &= ~((u64) RMAC_LINK_STATE_CHANGE_INT);
-                       writeq(val64, &bar0->mac_rmac_err_mask);
                } else if (flag == DISABLE_INTRS) {
-                       /*  
-                        * Disable MAC Intrs in the general intr mask register 
+                       /*
+                        * Disable MAC Intrs in the general intr mask register
                         */
                        writeq(DISABLE_ALL_INTRS, &bar0->mac_int_mask);
                        writeq(DISABLE_ALL_INTRS,
@@ -1152,14 +1673,14 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
                        temp64 = readq(&bar0->general_int_mask);
                        temp64 &= ~((u64) val64);
                        writeq(temp64, &bar0->general_int_mask);
-                       /* 
+                       /*
                         * All XGXS block error interrupts are disabled for now
-                        * TODO 
+                        * TODO
                         */
                        writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
                } else if (flag == DISABLE_INTRS) {
-                       /*  
-                        * Disable MC Intrs in the general intr mask register 
+                       /*
+                        * Disable MC Intrs in the general intr mask register
                         */
                        writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
                        temp64 = readq(&bar0->general_int_mask);
@@ -1175,11 +1696,11 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
                        temp64 = readq(&bar0->general_int_mask);
                        temp64 &= ~((u64) val64);
                        writeq(temp64, &bar0->general_int_mask);
-                       /* 
-                        * All MC block error interrupts are disabled for now
-                        * TODO 
+                       /*
+                        * Enable all MC Intrs.
                         */
-                       writeq(DISABLE_ALL_INTRS, &bar0->mc_int_mask);
+                       writeq(0x0, &bar0->mc_int_mask);
+                       writeq(0x0, &bar0->mc_err_mask);
                } else if (flag == DISABLE_INTRS) {
                        /*
                         * Disable MC Intrs in the general intr mask register
@@ -1199,14 +1720,14 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
                        temp64 = readq(&bar0->general_int_mask);
                        temp64 &= ~((u64) val64);
                        writeq(temp64, &bar0->general_int_mask);
-                       /* 
+                       /*
                         * Enable all the Tx side interrupts
-                        * writing 0 Enables all 64 TX interrupt levels 
+                        * writing 0 Enables all 64 TX interrupt levels
                         */
                        writeq(0x0, &bar0->tx_traffic_mask);
                } else if (flag == DISABLE_INTRS) {
-                       /* 
-                        * Disable Tx Traffic Intrs in the general intr mask 
+                       /*
+                        * Disable Tx Traffic Intrs in the general intr mask
                         * register.
                         */
                        writeq(DISABLE_ALL_INTRS, &bar0->tx_traffic_mask);
@@ -1226,8 +1747,8 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
                        /* writing 0 Enables all 8 RX interrupt levels */
                        writeq(0x0, &bar0->rx_traffic_mask);
                } else if (flag == DISABLE_INTRS) {
-                       /*  
-                        * Disable Rx Traffic Intrs in the general intr mask 
+                       /*
+                        * Disable Rx Traffic Intrs in the general intr mask
                         * register.
                         */
                        writeq(DISABLE_ALL_INTRS, &bar0->rx_traffic_mask);
@@ -1238,64 +1759,88 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
        }
 }
 
-/**  
- *  verify_xena_quiescence - Checks whether the H/W is ready 
- *  @val64 :  Value read from adapter status register.
- *  @flag : indicates if the adapter enable bit was ever written once
- *  before.
- *  Description: Returns whether the H/W is ready to go or not. Depending
- *  on whether adapter enable bit was written or not the comparison 
- *  differs and the calling function passes the input argument flag to
- *  indicate this.
- *  Return: 1 If xena is quiescence 
- *          0 If Xena is not quiescence
- */
-
-static int verify_xena_quiescence(u64 val64, int flag)
+static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc)
 {
        int ret = 0;
-       u64 tmp64 = ~((u64) val64);
 
-       if (!
-           (tmp64 &
-            (ADAPTER_STATUS_TDMA_READY | ADAPTER_STATUS_RDMA_READY |
-             ADAPTER_STATUS_PFC_READY | ADAPTER_STATUS_TMAC_BUF_EMPTY |
-             ADAPTER_STATUS_PIC_QUIESCENT | ADAPTER_STATUS_MC_DRAM_READY |
-             ADAPTER_STATUS_MC_QUEUES_READY | ADAPTER_STATUS_M_PLL_LOCK |
-             ADAPTER_STATUS_P_PLL_LOCK))) {
-               if (flag == FALSE) {
+       if (flag == FALSE) {
+               if ((!herc && (rev_id >= 4)) || herc) {
                        if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) &&
                            ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
                             ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
-
                                ret = 1;
-
                        }
-               } else {
+               }else {
+                       if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
+                           ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
+                            ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
+                               ret = 1;
+                       }
+               }
+       } else {
+               if ((!herc && (rev_id >= 4)) || herc) {
                        if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) ==
                             ADAPTER_STATUS_RMAC_PCC_IDLE) &&
                            (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
                             ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
                              ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
-
                                ret = 1;
-
                        }
-               }
-       }
-
+               } else {
+                       if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) ==
+                            ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
+                           (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
+                            ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
+                             ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
+                               ret = 1;
+                       }
+               }
+       }
+
+       return ret;
+}
+/**
+ *  verify_xena_quiescence - Checks whether the H/W is ready
+ *  @val64 :  Value read from adapter status register.
+ *  @flag : indicates if the adapter enable bit was ever written once
+ *  before.
+ *  Description: Returns whether the H/W is ready to go or not. Depending
+ *  on whether adapter enable bit was written or not the comparison
+ *  differs and the calling function passes the input argument flag to
+ *  indicate this.
+ *  Return: 1 If xena is quiescence
+ *          0 If Xena is not quiescence
+ */
+
+static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag)
+{
+       int ret = 0, herc;
+       u64 tmp64 = ~((u64) val64);
+       int rev_id = get_xena_rev_id(sp->pdev);
+
+       herc = (sp->device_type == XFRAME_II_DEVICE);
+       if (!
+           (tmp64 &
+            (ADAPTER_STATUS_TDMA_READY | ADAPTER_STATUS_RDMA_READY |
+             ADAPTER_STATUS_PFC_READY | ADAPTER_STATUS_TMAC_BUF_EMPTY |
+             ADAPTER_STATUS_PIC_QUIESCENT | ADAPTER_STATUS_MC_DRAM_READY |
+             ADAPTER_STATUS_MC_QUEUES_READY | ADAPTER_STATUS_M_PLL_LOCK |
+             ADAPTER_STATUS_P_PLL_LOCK))) {
+               ret = check_prc_pcc_state(val64, flag, rev_id, herc);
+       }
+
        return ret;
 }
 
 /**
  * fix_mac_address -  Fix for Mac addr problem on Alpha platforms
  * @sp: Pointer to device specifc structure
- * Description : 
+ * Description :
  * New procedure to clear mac address reading  problems on Alpha platforms
  *
  */
 
-static void fix_mac_address(nic_t * sp)
+void fix_mac_address(nic_t * sp)
 {
        XENA_dev_config_t __iomem *bar0 = sp->bar0;
        u64 val64;
@@ -1303,20 +1848,21 @@ static void fix_mac_address(nic_t * sp)
 
        while (fix_mac[i] != END_SIGN) {
                writeq(fix_mac[i++], &bar0->gpio_control);
+               udelay(10);
                val64 = readq(&bar0->gpio_control);
        }
 }
 
 /**
- *  start_nic - Turns the device on   
+ *  start_nic - Turns the device on
  *  @nic : device private variable.
- *  Description: 
- *  This function actually turns the device on. Before this  function is 
- *  called,all Registers are configured from their reset states 
- *  and shared memory is allocated but the NIC is still quiescent. On 
+ *  Description:
+ *  This function actually turns the device on. Before this  function is
+ *  called,all Registers are configured from their reset states
+ *  and shared memory is allocated but the NIC is still quiescent. On
  *  calling this function, the device interrupts are cleared and the NIC is
  *  literally switched on by writing into the adapter control register.
- *  Return Value: 
+ *  Return Value:
  *  SUCCESS on success and -1 on failure.
  */
 
@@ -1325,8 +1871,8 @@ static int start_nic(struct s2io_nic *nic)
        XENA_dev_config_t __iomem *bar0 = nic->bar0;
        struct net_device *dev = nic->dev;
        register u64 val64 = 0;
-       u16 interruptible, i;
-       u16 subid;
+       u16 interruptible;
+       u16 subid, i;
        mac_info_t *mac_control;
        struct config_param *config;
 
@@ -1335,10 +1881,12 @@ static int start_nic(struct s2io_nic *nic)
 
        /*  PRC Initialization and configuration */
        for (i = 0; i < config->rx_ring_num; i++) {
-               writeq((u64) nic->rx_blocks[i][0].block_dma_addr,
+               writeq((u64) mac_control->rings[i].rx_blocks[0].block_dma_addr,
                       &bar0->prc_rxd0_n[i]);
 
                val64 = readq(&bar0->prc_ctrl_n[i]);
+               if (nic->config.bimodal)
+                       val64 |= PRC_CTRL_BIMODAL_INTERRUPT;
 #ifndef CONFIG_2BUFF_MODE
                val64 |= PRC_CTRL_RC_ENABLED;
 #else
@@ -1354,7 +1902,7 @@ static int start_nic(struct s2io_nic *nic)
        writeq(val64, &bar0->rx_pa_cfg);
 #endif
 
-       /* 
+       /*
         * Enabling MC-RLDRAM. After enabling the device, we timeout
         * for around 100ms, which is approximately the time required
         * for the device to be ready for operation.
@@ -1364,27 +1912,27 @@ static int start_nic(struct s2io_nic *nic)
        SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
        val64 = readq(&bar0->mc_rldram_mrs);
 
-       msleep(100);                    /* Delay by around 100 ms. */
+       msleep(100);    /* Delay by around 100 ms. */
 
        /* Enabling ECC Protection. */
        val64 = readq(&bar0->adapter_control);
        val64 &= ~ADAPTER_ECC_EN;
        writeq(val64, &bar0->adapter_control);
 
-       /* 
-        * Clearing any possible Link state change interrupts that 
+       /*
+        * Clearing any possible Link state change interrupts that
         * could have popped up just before Enabling the card.
         */
        val64 = readq(&bar0->mac_rmac_err_reg);
        if (val64)
                writeq(val64, &bar0->mac_rmac_err_reg);
 
-       /* 
-        * Verify if the device is ready to be enabled, if so enable 
+       /*
+        * Verify if the device is ready to be enabled, if so enable
         * it.
         */
        val64 = readq(&bar0->adapter_status);
-       if (!verify_xena_quiescence(val64, nic->device_enabled_once)) {
+       if (!verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
                DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name);
                DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n",
                          (unsigned long long) val64);
@@ -1392,16 +1940,18 @@ static int start_nic(struct s2io_nic *nic)
        }
 
        /*  Enable select interrupts */
-       interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR | TX_MAC_INTR |
-           RX_MAC_INTR;
+       interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
+       interruptible |= TX_PIC_INTR | RX_PIC_INTR;
+       interruptible |= TX_MAC_INTR | RX_MAC_INTR;
+
        en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS);
 
-       /* 
+       /*
         * With some switches, link might be already up at this point.
-        * Because of this weird behavior, when we enable laser, 
-        * we may not get link. We need to handle this. We cannot 
-        * figure out which switch is misbehaving. So we are forced to 
-        * make a global change. 
+        * Because of this weird behavior, when we enable laser,
+        * we may not get link. We need to handle this. We cannot
+        * figure out which switch is misbehaving. So we are forced to
+        * make a global change.
         */
 
        /* Enabling Laser. */
@@ -1411,44 +1961,30 @@ static int start_nic(struct s2io_nic *nic)
 
        /* SXE-002: Initialize link and activity LED */
        subid = nic->pdev->subsystem_device;
-       if ((subid & 0xFF) >= 0x07) {
+       if (((subid & 0xFF) >= 0x07) &&
+           (nic->device_type == XFRAME_I_DEVICE)) {
                val64 = readq(&bar0->gpio_control);
                val64 |= 0x0000800000000000ULL;
                writeq(val64, &bar0->gpio_control);
                val64 = 0x0411040400000000ULL;
-               writeq(val64, (void __iomem *) bar0 + 0x2700);
+               writeq(val64, (void __iomem *)bar0 + 0x2700);
        }
 
-       /* 
-        * Don't see link state interrupts on certain switches, so 
+       /*
+        * Don't see link state interrupts on certain switches, so
         * directly scheduling a link state task from here.
         */
        schedule_work(&nic->set_link_task);
 
-       /* 
-        * Here we are performing soft reset on XGXS to 
-        * force link down. Since link is already up, we will get
-        * link state change interrupt after this reset
-        */
-       SPECIAL_REG_WRITE(0x80010515001E0000ULL, &bar0->dtx_control, UF);
-       val64 = readq(&bar0->dtx_control);
-       udelay(50);
-       SPECIAL_REG_WRITE(0x80010515001E00E0ULL, &bar0->dtx_control, UF);
-       val64 = readq(&bar0->dtx_control);
-       udelay(50);
-       SPECIAL_REG_WRITE(0x80070515001F00E4ULL, &bar0->dtx_control, UF);
-       val64 = readq(&bar0->dtx_control);
-       udelay(50);
-
        return SUCCESS;
 }
 
-/** 
- *  free_tx_buffers - Free all queued Tx buffers 
+/**
+ *  free_tx_buffers - Free all queued Tx buffers
  *  @nic : device private variable.
- *  Description: 
+ *  Description:
  *  Free all queued Tx buffers.
- *  Return Value: void 
+ *  Return Value: void
 */
 
 static void free_tx_buffers(struct s2io_nic *nic)
@@ -1459,39 +1995,61 @@ static void free_tx_buffers(struct s2io_nic *nic)
        int i, j;
        mac_info_t *mac_control;
        struct config_param *config;
-       int cnt = 0;
+       int cnt = 0, frg_cnt;
 
        mac_control = &nic->mac_control;
        config = &nic->config;
 
        for (i = 0; i < config->tx_fifo_num; i++) {
                for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
-                       txdp = (TxD_t *) nic->list_info[i][j].
+                       txdp = (TxD_t *) mac_control->fifos[i].list_info[j].
                            list_virt_addr;
                        skb =
                            (struct sk_buff *) ((unsigned long) txdp->
                                                Host_Control);
                        if (skb == NULL) {
-                               memset(txdp, 0, sizeof(TxD_t));
+                               memset(txdp, 0, sizeof(TxD_t) *
+                                      config->max_txds);
                                continue;
                        }
+                       frg_cnt = skb_shinfo(skb)->nr_frags;
+                       pci_unmap_single(nic->pdev, (dma_addr_t)
+                                        txdp->Buffer_Pointer,
+                                        skb->len - skb->data_len,
+                                        PCI_DMA_TODEVICE);
+                       if (frg_cnt) {
+                               TxD_t *temp;
+                               temp = txdp;
+                               txdp++;
+                               for (j = 0; j < frg_cnt; j++, txdp++) {
+                                       skb_frag_t *frag =
+                                           &skb_shinfo(skb)->frags[j];
+                                       pci_unmap_page(nic->pdev,
+                                                      (dma_addr_t)
+                                                      txdp->
+                                                      Buffer_Pointer,
+                                                      frag->size,
+                                                      PCI_DMA_TODEVICE);
+                               }
+                               txdp = temp;
+                       }
                        dev_kfree_skb(skb);
-                       memset(txdp, 0, sizeof(TxD_t));
+                       memset(txdp, 0, sizeof(TxD_t) * config->max_txds);
                        cnt++;
                }
                DBG_PRINT(INTR_DBG,
                          "%s:forcibly freeing %d skbs on FIFO%d\n",
                          dev->name, cnt, i);
-               mac_control->tx_curr_get_info[i].offset = 0;
-               mac_control->tx_curr_put_info[i].offset = 0;
+               mac_control->fifos[i].tx_curr_get_info.offset = 0;
+               mac_control->fifos[i].tx_curr_put_info.offset = 0;
        }
 }
 
-/**  
- *   stop_nic -  To stop the nic  
+/**
+ *   stop_nic -  To stop the nic
  *   @nic ; device private variable.
- *   Description: 
- *   This function does exactly the opposite of what the start_nic() 
+ *   Description:
+ *   This function does exactly the opposite of what the start_nic()
  *   function does. This function is called to stop the device.
  *   Return Value:
  *   void.
@@ -1509,8 +2067,9 @@ static void stop_nic(struct s2io_nic *nic)
        config = &nic->config;
 
        /*  Disable all interrupts */
-       interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR | TX_MAC_INTR |
-           RX_MAC_INTR;
+       interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
+       interruptible |= TX_PIC_INTR | RX_PIC_INTR;
+       interruptible |= TX_MAC_INTR | RX_MAC_INTR;
        en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS);
 
        /*  Disable PRCs */
@@ -1521,11 +2080,11 @@ static void stop_nic(struct s2io_nic *nic)
        }
 }
 
-/**  
- *  fill_rx_buffers - Allocates the Rx side skbs 
+/**
+ *  fill_rx_buffers - Allocates the Rx side skbs
  *  @nic:  device private variable
- *  @ring_no: ring number 
- *  Description: 
+ *  @ring_no: ring number
+ *  Description:
  *  The function allocates Rx side skbs and puts the physical
  *  address of these buffers into the RxD buffer pointers, so that the NIC
  *  can DMA the received frame into these locations.
@@ -1533,8 +2092,8 @@ static void stop_nic(struct s2io_nic *nic)
  *  1. single buffer,
  *  2. three buffer and
  *  3. Five buffer modes.
- *  Each mode defines how many fragments the received frame will be split 
- *  up into by the NIC. The frame is split into L3 header, L4 Header, 
+ *  Each mode defines how many fragments the received frame will be split
+ *  up into by the NIC. The frame is split into L3 header, L4 Header,
  *  L4 payload in three buffer mode and in 5 buffer mode, L4 payload itself
  *  is split into 3 fragments. As of now only single buffer mode is
  *  supported.
@@ -1542,7 +2101,7 @@ static void stop_nic(struct s2io_nic *nic)
  *  SUCCESS on success or an appropriate -ve value on failure.
  */
 
-static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
+int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
 {
        struct net_device *dev = nic->dev;
        struct sk_buff *skb;
@@ -1550,34 +2109,35 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
        int off, off1, size, block_no, block_no1;
        int offset, offset1;
        u32 alloc_tab = 0;
-       u32 alloc_cnt = nic->pkt_cnt[ring_no] -
-           atomic_read(&nic->rx_bufs_left[ring_no]);
+       u32 alloc_cnt;
        mac_info_t *mac_control;
        struct config_param *config;
 #ifdef CONFIG_2BUFF_MODE
        RxD_t *rxdpnext;
        int nextblk;
-       unsigned long tmp;
+       u64 tmp;
        buffAdd_t *ba;
        dma_addr_t rxdpphys;
 #endif
 #ifndef CONFIG_S2IO_NAPI
        unsigned long flags;
 #endif
+       RxD_t *first_rxdp = NULL;
 
        mac_control = &nic->mac_control;
        config = &nic->config;
-
+       alloc_cnt = mac_control->rings[ring_no].pkt_cnt -
+           atomic_read(&nic->rx_bufs_left[ring_no]);
        size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
            HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
 
        while (alloc_tab < alloc_cnt) {
-               block_no = mac_control->rx_curr_put_info[ring_no].
+               block_no = mac_control->rings[ring_no].rx_curr_put_info.
                    block_index;
-               block_no1 = mac_control->rx_curr_get_info[ring_no].
+               block_no1 = mac_control->rings[ring_no].rx_curr_get_info.
                    block_index;
-               off = mac_control->rx_curr_put_info[ring_no].offset;
-               off1 = mac_control->rx_curr_get_info[ring_no].offset;
+               off = mac_control->rings[ring_no].rx_curr_put_info.offset;
+               off1 = mac_control->rings[ring_no].rx_curr_get_info.offset;
 #ifndef CONFIG_2BUFF_MODE
                offset = block_no * (MAX_RXDS_PER_BLOCK + 1) + off;
                offset1 = block_no1 * (MAX_RXDS_PER_BLOCK + 1) + off1;
@@ -1586,7 +2146,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
                offset1 = block_no1 * (MAX_RXDS_PER_BLOCK) + off1;
 #endif
 
-               rxdp = nic->rx_blocks[ring_no][block_no].
+               rxdp = mac_control->rings[ring_no].rx_blocks[block_no].
                    block_virt_addr + off;
                if ((offset == offset1) && (rxdp->Host_Control)) {
                        DBG_PRINT(INTR_DBG, "%s: Get and Put", dev->name);
@@ -1595,15 +2155,15 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
                }
 #ifndef        CONFIG_2BUFF_MODE
                if (rxdp->Control_1 == END_OF_BLOCK) {
-                       mac_control->rx_curr_put_info[ring_no].
+                       mac_control->rings[ring_no].rx_curr_put_info.
                            block_index++;
-                       mac_control->rx_curr_put_info[ring_no].
-                           block_index %= nic->block_count[ring_no];
-                       block_no = mac_control->rx_curr_put_info
-                           [ring_no].block_index;
+                       mac_control->rings[ring_no].rx_curr_put_info.
+                           block_index %= mac_control->rings[ring_no].block_count;
+                       block_no = mac_control->rings[ring_no].rx_curr_put_info.
+                               block_index;
                        off++;
                        off %= (MAX_RXDS_PER_BLOCK + 1);
-                       mac_control->rx_curr_put_info[ring_no].offset =
+                       mac_control->rings[ring_no].rx_curr_put_info.offset =
                            off;
                        rxdp = (RxD_t *) ((unsigned long) rxdp->Control_2);
                        DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
@@ -1611,30 +2171,30 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
                }
 #ifndef CONFIG_S2IO_NAPI
                spin_lock_irqsave(&nic->put_lock, flags);
-               nic->put_pos[ring_no] =
+               mac_control->rings[ring_no].put_pos =
                    (block_no * (MAX_RXDS_PER_BLOCK + 1)) + off;
                spin_unlock_irqrestore(&nic->put_lock, flags);
 #endif
 #else
                if (rxdp->Host_Control == END_OF_BLOCK) {
-                       mac_control->rx_curr_put_info[ring_no].
+                       mac_control->rings[ring_no].rx_curr_put_info.
                            block_index++;
-                       mac_control->rx_curr_put_info[ring_no].
-                           block_index %= nic->block_count[ring_no];
-                       block_no = mac_control->rx_curr_put_info
-                           [ring_no].block_index;
+                       mac_control->rings[ring_no].rx_curr_put_info.block_index
+                           %= mac_control->rings[ring_no].block_count;
+                       block_no = mac_control->rings[ring_no].rx_curr_put_info
+                           .block_index;
                        off = 0;
                        DBG_PRINT(INTR_DBG, "%s: block%d at: 0x%llx\n",
                                  dev->name, block_no,
                                  (unsigned long long) rxdp->Control_1);
-                       mac_control->rx_curr_put_info[ring_no].offset =
+                       mac_control->rings[ring_no].rx_curr_put_info.offset =
                            off;
-                       rxdp = nic->rx_blocks[ring_no][block_no].
+                       rxdp = mac_control->rings[ring_no].rx_blocks[block_no].
                            block_virt_addr;
                }
 #ifndef CONFIG_S2IO_NAPI
                spin_lock_irqsave(&nic->put_lock, flags);
-               nic->put_pos[ring_no] = (block_no *
+               mac_control->rings[ring_no].put_pos = (block_no *
                                         (MAX_RXDS_PER_BLOCK + 1)) + off;
                spin_unlock_irqrestore(&nic->put_lock, flags);
 #endif
@@ -1646,27 +2206,27 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
                if (rxdp->Control_2 & BIT(0))
 #endif
                {
-                       mac_control->rx_curr_put_info[ring_no].
+                       mac_control->rings[ring_no].rx_curr_put_info.
                            offset = off;
                        goto end;
                }
 #ifdef CONFIG_2BUFF_MODE
-               /* 
-                * RxDs Spanning cache lines will be replenished only 
-                * if the succeeding RxD is also owned by Host. It 
-                * will always be the ((8*i)+3) and ((8*i)+6) 
-                * descriptors for the 48 byte descriptor. The offending 
+               /*
+                * RxDs Spanning cache lines will be replenished only
+                * if the succeeding RxD is also owned by Host. It
+                * will always be the ((8*i)+3) and ((8*i)+6)
+                * descriptors for the 48 byte descriptor. The offending
                 * decsriptor is of-course the 3rd descriptor.
                 */
-               rxdpphys = nic->rx_blocks[ring_no][block_no].
+               rxdpphys = mac_control->rings[ring_no].rx_blocks[block_no].
                    block_dma_addr + (off * sizeof(RxD_t));
                if (((u64) (rxdpphys)) % 128 > 80) {
-                       rxdpnext = nic->rx_blocks[ring_no][block_no].
+                       rxdpnext = mac_control->rings[ring_no].rx_blocks[block_no].
                            block_virt_addr + (off + 1);
                        if (rxdpnext->Host_Control == END_OF_BLOCK) {
                                nextblk = (block_no + 1) %
-                                   (nic->block_count[ring_no]);
-                               rxdpnext = nic->rx_blocks[ring_no]
+                                   (mac_control->rings[ring_no].block_count);
+                               rxdpnext = mac_control->rings[ring_no].rx_blocks
                                    [nextblk].block_virt_addr;
                        }
                        if (rxdpnext->Control_2 & BIT(0))
@@ -1682,6 +2242,10 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
                if (!skb) {
                        DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
                        DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
+                       if (first_rxdp) {
+                               wmb();
+                               first_rxdp->Control_1 |= RXD_OWN_XENA;
+                       }
                        return -ENOMEM;
                }
 #ifndef        CONFIG_2BUFF_MODE
@@ -1692,12 +2256,13 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
                rxdp->Control_2 &= (~MASK_BUFFER0_SIZE);
                rxdp->Control_2 |= SET_BUFFER0_SIZE(size);
                rxdp->Host_Control = (unsigned long) (skb);
-               rxdp->Control_1 |= RXD_OWN_XENA;
+               if (alloc_tab & ((1 << rxsync_frequency) - 1))
+                       rxdp->Control_1 |= RXD_OWN_XENA;
                off++;
                off %= (MAX_RXDS_PER_BLOCK + 1);
-               mac_control->rx_curr_put_info[ring_no].offset = off;
+               mac_control->rings[ring_no].rx_curr_put_info.offset = off;
 #else
-               ba = &nic->ba[ring_no][block_no][off];
+               ba = &mac_control->rings[ring_no].ba[block_no][off];
                skb_reserve(skb, BUF0_LEN);
                tmp = ((unsigned long) skb->data & ALIGN_SIZE);
                if (tmp)
@@ -1719,22 +2284,41 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
                rxdp->Control_2 |= SET_BUFFER1_SIZE(1); /* dummy. */
                rxdp->Control_2 |= BIT(0);      /* Set Buffer_Empty bit. */
                rxdp->Host_Control = (u64) ((unsigned long) (skb));
-               rxdp->Control_1 |= RXD_OWN_XENA;
+               if (alloc_tab & ((1 << rxsync_frequency) - 1))
+                       rxdp->Control_1 |= RXD_OWN_XENA;
                off++;
-               mac_control->rx_curr_put_info[ring_no].offset = off;
+               mac_control->rings[ring_no].rx_curr_put_info.offset = off;
 #endif
+               rxdp->Control_2 |= SET_RXD_MARKER;
+
+               if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) {
+                       if (first_rxdp) {
+                               wmb();
+                               first_rxdp->Control_1 |= RXD_OWN_XENA;
+                       }
+                       first_rxdp = rxdp;
+               }
                atomic_inc(&nic->rx_bufs_left[ring_no]);
                alloc_tab++;
        }
 
       end:
+       /* Transfer ownership of first descriptor to adapter just before
+        * exiting. Before that, use memory barrier so that ownership
+        * and other fields are seen by adapter correctly.
+        */
+       if (first_rxdp) {
+               wmb();
+               first_rxdp->Control_1 |= RXD_OWN_XENA;
+       }
+
        return SUCCESS;
 }
 
 /**
- *  free_rx_buffers - Frees all Rx buffers   
+ *  free_rx_buffers - Frees all Rx buffers
  *  @sp: device private variable.
- *  Description: 
+ *  Description:
  *  This function will free all Rx buffers allocated by host.
  *  Return Value:
  *  NONE.
@@ -1758,7 +2342,8 @@ static void free_rx_buffers(struct s2io_nic *sp)
        for (i = 0; i < config->rx_ring_num; i++) {
                for (j = 0, blk = 0; j < config->rx_cfg[i].num_rxd; j++) {
                        off = j % (MAX_RXDS_PER_BLOCK + 1);
-                       rxdp = sp->rx_blocks[i][blk].block_virt_addr + off;
+                       rxdp = mac_control->rings[i].rx_blocks[blk].
+                               block_virt_addr + off;
 
 #ifndef CONFIG_2BUFF_MODE
                        if (rxdp->Control_1 == END_OF_BLOCK) {
@@ -1793,7 +2378,7 @@ static void free_rx_buffers(struct s2io_nic *sp)
                                                 HEADER_SNAP_SIZE,
                                                 PCI_DMA_FROMDEVICE);
 #else
-                               ba = &sp->ba[i][blk][off];
+                               ba = &mac_control->rings[i].ba[blk][off];
                                pci_unmap_single(sp->pdev, (dma_addr_t)
                                                 rxdp->Buffer0_ptr,
                                                 BUF0_LEN,
@@ -1813,10 +2398,10 @@ static void free_rx_buffers(struct s2io_nic *sp)
                        }
                        memset(rxdp, 0, sizeof(RxD_t));
                }
-               mac_control->rx_curr_put_info[i].block_index = 0;
-               mac_control->rx_curr_get_info[i].block_index = 0;
-               mac_control->rx_curr_put_info[i].offset = 0;
-               mac_control->rx_curr_get_info[i].offset = 0;
+               mac_control->rings[i].rx_curr_put_info.block_index = 0;
+               mac_control->rings[i].rx_curr_get_info.block_index = 0;
+               mac_control->rings[i].rx_curr_put_info.offset = 0;
+               mac_control->rings[i].rx_curr_get_info.offset = 0;
                atomic_set(&sp->rx_bufs_left[i], 0);
                DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n",
                          dev->name, buf_cnt, i);
@@ -1826,7 +2411,7 @@ static void free_rx_buffers(struct s2io_nic *sp)
 /**
  * s2io_poll - Rx interrupt handler for NAPI support
  * @dev : pointer to the device structure.
- * @budget : The number of packets that were budgeted to be processed 
+ * @budget : The number of packets that were budgeted to be processed
  * during  one pass through the 'Poll" function.
  * Description:
  * Comes into picture only if NAPI support has been incorporated. It does
@@ -1836,160 +2421,36 @@ static void free_rx_buffers(struct s2io_nic *sp)
  * 0 on success and 1 if there are No Rx packets to be processed.
  */
 
-#ifdef CONFIG_S2IO_NAPI
+#if defined(CONFIG_S2IO_NAPI)
 static int s2io_poll(struct net_device *dev, int *budget)
 {
        nic_t *nic = dev->priv;
-       XENA_dev_config_t __iomem *bar0 = nic->bar0;
-       int pkts_to_process = *budget, pkt_cnt = 0;
-       register u64 val64 = 0;
-       rx_curr_get_info_t get_info, put_info;
-       int i, get_block, put_block, get_offset, put_offset, ring_bufs;
-#ifndef CONFIG_2BUFF_MODE
-       u16 val16, cksum;
-#endif
-       struct sk_buff *skb;
-       RxD_t *rxdp;
+       int pkt_cnt = 0, org_pkts_to_process;
        mac_info_t *mac_control;
        struct config_param *config;
-#ifdef CONFIG_2BUFF_MODE
-       buffAdd_t *ba;
-#endif
+       XENA_dev_config_t __iomem *bar0 = nic->bar0;
+       u64 val64;
+       int i;
 
+       atomic_inc(&nic->isr_cnt);
        mac_control = &nic->mac_control;
        config = &nic->config;
 
-       if (pkts_to_process > dev->quota)
-               pkts_to_process = dev->quota;
+       nic->pkts_to_process = *budget;
+       if (nic->pkts_to_process > dev->quota)
+               nic->pkts_to_process = dev->quota;
+       org_pkts_to_process = nic->pkts_to_process;
 
        val64 = readq(&bar0->rx_traffic_int);
        writeq(val64, &bar0->rx_traffic_int);
 
        for (i = 0; i < config->rx_ring_num; i++) {
-               get_info = mac_control->rx_curr_get_info[i];
-               get_block = get_info.block_index;
-               put_info = mac_control->rx_curr_put_info[i];
-               put_block = put_info.block_index;
-               ring_bufs = config->rx_cfg[i].num_rxd;
-               rxdp = nic->rx_blocks[i][get_block].block_virt_addr +
-                   get_info.offset;
-#ifndef        CONFIG_2BUFF_MODE
-               get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) +
-                   get_info.offset;
-               put_offset = (put_block * (MAX_RXDS_PER_BLOCK + 1)) +
-                   put_info.offset;
-               while ((!(rxdp->Control_1 & RXD_OWN_XENA)) &&
-                      (((get_offset + 1) % ring_bufs) != put_offset)) {
-                       if (--pkts_to_process < 0) {
-                               goto no_rx;
-                       }
-                       if (rxdp->Control_1 == END_OF_BLOCK) {
-                               rxdp =
-                                   (RxD_t *) ((unsigned long) rxdp->
-                                              Control_2);
-                               get_info.offset++;
-                               get_info.offset %=
-                                   (MAX_RXDS_PER_BLOCK + 1);
-                               get_block++;
-                               get_block %= nic->block_count[i];
-                               mac_control->rx_curr_get_info[i].
-                                   offset = get_info.offset;
-                               mac_control->rx_curr_get_info[i].
-                                   block_index = get_block;
-                               continue;
-                       }
-                       get_offset =
-                           (get_block * (MAX_RXDS_PER_BLOCK + 1)) +
-                           get_info.offset;
-                       skb =
-                           (struct sk_buff *) ((unsigned long) rxdp->
-                                               Host_Control);
-                       if (skb == NULL) {
-                               DBG_PRINT(ERR_DBG, "%s: The skb is ",
-                                         dev->name);
-                               DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
-                               goto no_rx;
-                       }
-                       val64 = RXD_GET_BUFFER0_SIZE(rxdp->Control_2);
-                       val16 = (u16) (val64 >> 48);
-                       cksum = RXD_GET_L4_CKSUM(rxdp->Control_1);
-                       pci_unmap_single(nic->pdev, (dma_addr_t)
-                                        rxdp->Buffer0_ptr,
-                                        dev->mtu +
-                                        HEADER_ETHERNET_II_802_3_SIZE +
-                                        HEADER_802_2_SIZE +
-                                        HEADER_SNAP_SIZE,
-                                        PCI_DMA_FROMDEVICE);
-                       rx_osm_handler(nic, val16, rxdp, i);
-                       pkt_cnt++;
-                       get_info.offset++;
-                       get_info.offset %= (MAX_RXDS_PER_BLOCK + 1);
-                       rxdp =
-                           nic->rx_blocks[i][get_block].block_virt_addr +
-                           get_info.offset;
-                       mac_control->rx_curr_get_info[i].offset =
-                           get_info.offset;
-               }
-#else
-               get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) +
-                   get_info.offset;
-               put_offset = (put_block * (MAX_RXDS_PER_BLOCK + 1)) +
-                   put_info.offset;
-               while (((!(rxdp->Control_1 & RXD_OWN_XENA)) &&
-                       !(rxdp->Control_2 & BIT(0))) &&
-                      (((get_offset + 1) % ring_bufs) != put_offset)) {
-                       if (--pkts_to_process < 0) {
-                               goto no_rx;
-                       }
-                       skb = (struct sk_buff *) ((unsigned long)
-                                                 rxdp->Host_Control);
-                       if (skb == NULL) {
-                               DBG_PRINT(ERR_DBG, "%s: The skb is ",
-                                         dev->name);
-                               DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
-                               goto no_rx;
-                       }
-
-                       pci_unmap_single(nic->pdev, (dma_addr_t)
-                                        rxdp->Buffer0_ptr,
-                                        BUF0_LEN, PCI_DMA_FROMDEVICE);
-                       pci_unmap_single(nic->pdev, (dma_addr_t)
-                                        rxdp->Buffer1_ptr,
-                                        BUF1_LEN, PCI_DMA_FROMDEVICE);
-                       pci_unmap_single(nic->pdev, (dma_addr_t)
-                                        rxdp->Buffer2_ptr,
-                                        dev->mtu + BUF0_LEN + 4,
-                                        PCI_DMA_FROMDEVICE);
-                       ba = &nic->ba[i][get_block][get_info.offset];
-
-                       rx_osm_handler(nic, rxdp, i, ba);
-
-                       get_info.offset++;
-                       mac_control->rx_curr_get_info[i].offset =
-                           get_info.offset;
-                       rxdp =
-                           nic->rx_blocks[i][get_block].block_virt_addr +
-                           get_info.offset;
-
-                       if (get_info.offset &&
-                           (!(get_info.offset % MAX_RXDS_PER_BLOCK))) {
-                               get_info.offset = 0;
-                               mac_control->rx_curr_get_info[i].
-                                   offset = get_info.offset;
-                               get_block++;
-                               get_block %= nic->block_count[i];
-                               mac_control->rx_curr_get_info[i].
-                                   block_index = get_block;
-                               rxdp =
-                                   nic->rx_blocks[i][get_block].
-                                   block_virt_addr;
-                       }
-                       get_offset =
-                           (get_block * (MAX_RXDS_PER_BLOCK + 1)) +
-                           get_info.offset;
-                       pkt_cnt++;
+               rx_intr_handler(&mac_control->rings[i]);
+               pkt_cnt = org_pkts_to_process - nic->pkts_to_process;
+               if (!nic->pkts_to_process) {
+                       /* Quota for the current iteration has been met */
+                       goto no_rx;
                }
-#endif
        }
        if (!pkt_cnt)
                pkt_cnt = 1;
@@ -2007,9 +2468,10 @@ static int s2io_poll(struct net_device *dev, int *budget)
        }
        /* Re enable the Rx interrupts. */
        en_dis_able_nic_intrs(nic, RX_TRAFFIC_INTR, ENABLE_INTRS);
+       atomic_dec(&nic->isr_cnt);
        return 0;
 
-      no_rx:
+no_rx:
        dev->quota -= pkt_cnt;
        *budget -= pkt_cnt;
 
@@ -2020,279 +2482,211 @@ static int s2io_poll(struct net_device *dev, int *budget)
                        break;
                }
        }
+       atomic_dec(&nic->isr_cnt);
        return 1;
 }
-#else
-/**  
+#endif
+
+/**
  *  rx_intr_handler - Rx interrupt handler
  *  @nic: device private variable.
- *  Description: 
- *  If the interrupt is because of a received frame or if the 
+ *  Description:
+ *  If the interrupt is because of a received frame or if the
  *  receive ring contains fresh as yet un-processed frames,this function is
- *  called. It picks out the RxD at which place the last Rx processing had 
- *  stopped and sends the skb to the OSM's Rx handler and then increments 
+ *  called. It picks out the RxD at which place the last Rx processing had
+ *  stopped and sends the skb to the OSM's Rx handler and then increments
  *  the offset.
  *  Return Value:
  *  NONE.
  */
-
-static void rx_intr_handler(struct s2io_nic *nic)
+static void rx_intr_handler(ring_info_t *ring_data)
 {
+       nic_t *nic = ring_data->nic;
        struct net_device *dev = (struct net_device *) nic->dev;
-       XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+       int get_block, get_offset, put_block, put_offset, ring_bufs;
        rx_curr_get_info_t get_info, put_info;
        RxD_t *rxdp;
        struct sk_buff *skb;
-#ifndef CONFIG_2BUFF_MODE
-       u16 val16, cksum;
-#endif
-       register u64 val64 = 0;
-       int get_block, get_offset, put_block, put_offset, ring_bufs;
-       int i, pkt_cnt = 0;
-       mac_info_t *mac_control;
-       struct config_param *config;
-#ifdef CONFIG_2BUFF_MODE
-       buffAdd_t *ba;
+#ifndef CONFIG_S2IO_NAPI
+       int pkt_cnt = 0;
 #endif
+       spin_lock(&nic->rx_lock);
+       if (atomic_read(&nic->card_state) == CARD_DOWN) {
+               DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n",
+                         __FUNCTION__, dev->name);
+               spin_unlock(&nic->rx_lock);
+               return;
+       }
 
-       mac_control = &nic->mac_control;
-       config = &nic->config;
-
-       /* 
-        * rx_traffic_int reg is an R1 register, hence we read and write back 
-        * the samevalue in the register to clear it.
-        */
-       val64 = readq(&bar0->rx_traffic_int);
-       writeq(val64, &bar0->rx_traffic_int);
-
-       for (i = 0; i < config->rx_ring_num; i++) {
-               get_info = mac_control->rx_curr_get_info[i];
-               get_block = get_info.block_index;
-               put_info = mac_control->rx_curr_put_info[i];
-               put_block = put_info.block_index;
-               ring_bufs = config->rx_cfg[i].num_rxd;
-               rxdp = nic->rx_blocks[i][get_block].block_virt_addr +
+       get_info = ring_data->rx_curr_get_info;
+       get_block = get_info.block_index;
+       put_info = ring_data->rx_curr_put_info;
+       put_block = put_info.block_index;
+       ring_bufs = get_info.ring_len+1;
+       rxdp = ring_data->rx_blocks[get_block].block_virt_addr +
                    get_info.offset;
-#ifndef        CONFIG_2BUFF_MODE
-               get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) +
-                   get_info.offset;
-               spin_lock(&nic->put_lock);
-               put_offset = nic->put_pos[i];
-               spin_unlock(&nic->put_lock);
-               while ((!(rxdp->Control_1 & RXD_OWN_XENA)) &&
-                      (((get_offset + 1) % ring_bufs) != put_offset)) {
-                       if (rxdp->Control_1 == END_OF_BLOCK) {
-                               rxdp = (RxD_t *) ((unsigned long)
-                                                 rxdp->Control_2);
-                               get_info.offset++;
-                               get_info.offset %=
-                                   (MAX_RXDS_PER_BLOCK + 1);
-                               get_block++;
-                               get_block %= nic->block_count[i];
-                               mac_control->rx_curr_get_info[i].
-                                   offset = get_info.offset;
-                               mac_control->rx_curr_get_info[i].
-                                   block_index = get_block;
-                               continue;
-                       }
-                       get_offset =
-                           (get_block * (MAX_RXDS_PER_BLOCK + 1)) +
-                           get_info.offset;
-                       skb = (struct sk_buff *) ((unsigned long)
-                                                 rxdp->Host_Control);
-                       if (skb == NULL) {
-                               DBG_PRINT(ERR_DBG, "%s: The skb is ",
-                                         dev->name);
-                               DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
-                               return;
-                       }
-                       val64 = RXD_GET_BUFFER0_SIZE(rxdp->Control_2);
-                       val16 = (u16) (val64 >> 48);
-                       cksum = RXD_GET_L4_CKSUM(rxdp->Control_1);
-                       pci_unmap_single(nic->pdev, (dma_addr_t)
-                                        rxdp->Buffer0_ptr,
-                                        dev->mtu +
-                                        HEADER_ETHERNET_II_802_3_SIZE +
-                                        HEADER_802_2_SIZE +
-                                        HEADER_SNAP_SIZE,
-                                        PCI_DMA_FROMDEVICE);
-                       rx_osm_handler(nic, val16, rxdp, i);
-                       get_info.offset++;
-                       get_info.offset %= (MAX_RXDS_PER_BLOCK + 1);
-                       rxdp =
-                           nic->rx_blocks[i][get_block].block_virt_addr +
-                           get_info.offset;
-                       mac_control->rx_curr_get_info[i].offset =
-                           get_info.offset;
-                       pkt_cnt++;
-                       if ((indicate_max_pkts)
-                           && (pkt_cnt > indicate_max_pkts))
-                               break;
+       get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) +
+               get_info.offset;
+#ifndef CONFIG_S2IO_NAPI
+       spin_lock(&nic->put_lock);
+       put_offset = ring_data->put_pos;
+       spin_unlock(&nic->put_lock);
+#else
+       put_offset = (put_block * (MAX_RXDS_PER_BLOCK + 1)) +
+               put_info.offset;
+#endif
+       while (RXD_IS_UP2DT(rxdp) &&
+              (((get_offset + 1) % ring_bufs) != put_offset)) {
+               skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control);
+               if (skb == NULL) {
+                       DBG_PRINT(ERR_DBG, "%s: The skb is ",
+                                 dev->name);
+                       DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
+                       spin_unlock(&nic->rx_lock);
+                       return;
                }
+#ifndef CONFIG_2BUFF_MODE
+               pci_unmap_single(nic->pdev, (dma_addr_t)
+                                rxdp->Buffer0_ptr,
+                                dev->mtu +
+                                HEADER_ETHERNET_II_802_3_SIZE +
+                                HEADER_802_2_SIZE +
+                                HEADER_SNAP_SIZE,
+                                PCI_DMA_FROMDEVICE);
 #else
-               get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) +
+               pci_unmap_single(nic->pdev, (dma_addr_t)
+                                rxdp->Buffer0_ptr,
+                                BUF0_LEN, PCI_DMA_FROMDEVICE);
+               pci_unmap_single(nic->pdev, (dma_addr_t)
+                                rxdp->Buffer1_ptr,
+                                BUF1_LEN, PCI_DMA_FROMDEVICE);
+               pci_unmap_single(nic->pdev, (dma_addr_t)
+                                rxdp->Buffer2_ptr,
+                                dev->mtu + BUF0_LEN + 4,
+                                PCI_DMA_FROMDEVICE);
+#endif
+               rx_osm_handler(ring_data, rxdp);
+               get_info.offset++;
+               ring_data->rx_curr_get_info.offset =
                    get_info.offset;
-               spin_lock(&nic->put_lock);
-               put_offset = nic->put_pos[i];
-               spin_unlock(&nic->put_lock);
-               while (((!(rxdp->Control_1 & RXD_OWN_XENA)) &&
-                       !(rxdp->Control_2 & BIT(0))) &&
-                      (((get_offset + 1) % ring_bufs) != put_offset)) {
-                       skb = (struct sk_buff *) ((unsigned long)
-                                                 rxdp->Host_Control);
-                       if (skb == NULL) {
-                               DBG_PRINT(ERR_DBG, "%s: The skb is ",
-                                         dev->name);
-                               DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
-                               return;
-                       }
-
-                       pci_unmap_single(nic->pdev, (dma_addr_t)
-                                        rxdp->Buffer0_ptr,
-                                        BUF0_LEN, PCI_DMA_FROMDEVICE);
-                       pci_unmap_single(nic->pdev, (dma_addr_t)
-                                        rxdp->Buffer1_ptr,
-                                        BUF1_LEN, PCI_DMA_FROMDEVICE);
-                       pci_unmap_single(nic->pdev, (dma_addr_t)
-                                        rxdp->Buffer2_ptr,
-                                        dev->mtu + BUF0_LEN + 4,
-                                        PCI_DMA_FROMDEVICE);
-                       ba = &nic->ba[i][get_block][get_info.offset];
-
-                       rx_osm_handler(nic, rxdp, i, ba);
-
-                       get_info.offset++;
-                       mac_control->rx_curr_get_info[i].offset =
-                           get_info.offset;
-                       rxdp =
-                           nic->rx_blocks[i][get_block].block_virt_addr +
-                           get_info.offset;
+               rxdp = ring_data->rx_blocks[get_block].block_virt_addr +
+                   get_info.offset;
+               if (get_info.offset &&
+                   (!(get_info.offset % MAX_RXDS_PER_BLOCK))) {
+                       get_info.offset = 0;
+                       ring_data->rx_curr_get_info.offset
+                           = get_info.offset;
+                       get_block++;
+                       get_block %= ring_data->block_count;
+                       ring_data->rx_curr_get_info.block_index
+                           = get_block;
+                       rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
+               }
 
-                       if (get_info.offset &&
-                           (!(get_info.offset % MAX_RXDS_PER_BLOCK))) {
-                               get_info.offset = 0;
-                               mac_control->rx_curr_get_info[i].
-                                   offset = get_info.offset;
-                               get_block++;
-                               get_block %= nic->block_count[i];
-                               mac_control->rx_curr_get_info[i].
-                                   block_index = get_block;
-                               rxdp =
-                                   nic->rx_blocks[i][get_block].
-                                   block_virt_addr;
-                       }
-                       get_offset =
-                           (get_block * (MAX_RXDS_PER_BLOCK + 1)) +
+               get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) +
                            get_info.offset;
-                       pkt_cnt++;
-                       if ((indicate_max_pkts)
-                           && (pkt_cnt > indicate_max_pkts))
-                               break;
-               }
-#endif
+#ifdef CONFIG_S2IO_NAPI
+               nic->pkts_to_process -= 1;
+               if (!nic->pkts_to_process)
+                       break;
+#else
+               pkt_cnt++;
                if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
                        break;
+#endif
        }
+       spin_unlock(&nic->rx_lock);
 }
-#endif
-/**  
+
+/**
  *  tx_intr_handler - Transmit interrupt handler
  *  @nic : device private variable
- *  Description: 
- *  If an interrupt was raised to indicate DMA complete of the 
- *  Tx packet, this function is called. It identifies the last TxD 
- *  whose buffer was freed and frees all skbs whose data have already 
+ *  Description:
+ *  If an interrupt was raised to indicate DMA complete of the
+ *  Tx packet, this function is called. It identifies the last TxD
+ *  whose buffer was freed and frees all skbs whose data have already
  *  DMA'ed into the NICs internal memory.
  *  Return Value:
  *  NONE
  */
 
-static void tx_intr_handler(struct s2io_nic *nic)
+static void tx_intr_handler(fifo_info_t *fifo_data)
 {
-       XENA_dev_config_t __iomem *bar0 = nic->bar0;
+       nic_t *nic = fifo_data->nic;
        struct net_device *dev = (struct net_device *) nic->dev;
        tx_curr_get_info_t get_info, put_info;
        struct sk_buff *skb;
        TxD_t *txdlp;
-       register u64 val64 = 0;
-       int i;
        u16 j, frg_cnt;
-       mac_info_t *mac_control;
-       struct config_param *config;
-
-       mac_control = &nic->mac_control;
-       config = &nic->config;
-
-       /* 
-        * tx_traffic_int reg is an R1 register, hence we read and write 
-        * back the samevalue in the register to clear it.
-        */
-       val64 = readq(&bar0->tx_traffic_int);
-       writeq(val64, &bar0->tx_traffic_int);
 
-       for (i = 0; i < config->tx_fifo_num; i++) {
-               get_info = mac_control->tx_curr_get_info[i];
-               put_info = mac_control->tx_curr_put_info[i];
-               txdlp = (TxD_t *) nic->list_info[i][get_info.offset].
-                   list_virt_addr;
-               while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) &&
-                      (get_info.offset != put_info.offset) &&
-                      (txdlp->Host_Control)) {
-                       /* Check for TxD errors */
-                       if (txdlp->Control_1 & TXD_T_CODE) {
-                               unsigned long long err;
-                               err = txdlp->Control_1 & TXD_T_CODE;
-                               DBG_PRINT(ERR_DBG, "***TxD error %llx\n",
-                                         err);
+       get_info = fifo_data->tx_curr_get_info;
+       put_info = fifo_data->tx_curr_put_info;
+       txdlp = (TxD_t *) fifo_data->list_info[get_info.offset].
+           list_virt_addr;
+       while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) &&
+              (get_info.offset != put_info.offset) &&
+              (txdlp->Host_Control)) {
+               /* Check for TxD errors */
+               if (txdlp->Control_1 & TXD_T_CODE) {
+                       unsigned long long err;
+                       err = txdlp->Control_1 & TXD_T_CODE;
+                       if ((err >> 48) == 0xA) {
+                               DBG_PRINT(TX_DBG, "TxD returned due \
+                                               to loss of link\n");
                        }
-
-                       skb = (struct sk_buff *) ((unsigned long)
-                                                 txdlp->Host_Control);
-                       if (skb == NULL) {
-                               DBG_PRINT(ERR_DBG, "%s: Null skb ",
-                                         dev->name);
-                               DBG_PRINT(ERR_DBG, "in Tx Free Intr\n");
-                               return;
+                       else {
+                               DBG_PRINT(ERR_DBG, "***TxD error \
+                                               %llx\n", err);
                        }
-                       nic->tx_pkt_count++;
+               }
 
-                       frg_cnt = skb_shinfo(skb)->nr_frags;
+               skb = (struct sk_buff *) ((unsigned long)
+                               txdlp->Host_Control);
+               if (skb == NULL) {
+                       DBG_PRINT(ERR_DBG, "%s: Null skb ",
+                       __FUNCTION__);
+                       DBG_PRINT(ERR_DBG, "in Tx Free Intr\n");
+                       return;
+               }
 
-                       /*  For unfragmented skb */
-                       pci_unmap_single(nic->pdev, (dma_addr_t)
-                                        txdlp->Buffer_Pointer,
-                                        skb->len - skb->data_len,
-                                        PCI_DMA_TODEVICE);
-                       if (frg_cnt) {
-                               TxD_t *temp = txdlp;
-                               txdlp++;
-                               for (j = 0; j < frg_cnt; j++, txdlp++) {
-                                       skb_frag_t *frag =
-                                           &skb_shinfo(skb)->frags[j];
-                                       pci_unmap_page(nic->pdev,
-                                                      (dma_addr_t)
-                                                      txdlp->
-                                                      Buffer_Pointer,
-                                                      frag->size,
-                                                      PCI_DMA_TODEVICE);
-                               }
-                               txdlp = temp;
+               frg_cnt = skb_shinfo(skb)->nr_frags;
+               nic->tx_pkt_count++;
+
+               pci_unmap_single(nic->pdev, (dma_addr_t)
+                                txdlp->Buffer_Pointer,
+                                skb->len - skb->data_len,
+                                PCI_DMA_TODEVICE);
+               if (frg_cnt) {
+                       TxD_t *temp;
+                       temp = txdlp;
+                       txdlp++;
+                       for (j = 0; j < frg_cnt; j++, txdlp++) {
+                               skb_frag_t *frag =
+                                   &skb_shinfo(skb)->frags[j];
+                               if (!txdlp->Buffer_Pointer)
+                                       break;
+                               pci_unmap_page(nic->pdev,
+                                              (dma_addr_t)
+                                              txdlp->
+                                              Buffer_Pointer,
+                                              frag->size,
+                                              PCI_DMA_TODEVICE);
                        }
-                       memset(txdlp, 0,
-                              (sizeof(TxD_t) * config->max_txds));
-
-                       /* Updating the statistics block */
-                       nic->stats.tx_packets++;
-                       nic->stats.tx_bytes += skb->len;
-                       dev_kfree_skb_irq(skb);
-
-                       get_info.offset++;
-                       get_info.offset %= get_info.fifo_len + 1;
-                       txdlp = (TxD_t *) nic->list_info[i]
-                           [get_info.offset].list_virt_addr;
-                       mac_control->tx_curr_get_info[i].offset =
-                           get_info.offset;
+                       txdlp = temp;
                }
+               memset(txdlp, 0,
+                      (sizeof(TxD_t) * fifo_data->max_txds));
+
+               /* Updating the statistics block */
+               nic->stats.tx_bytes += skb->len;
+               dev_kfree_skb_irq(skb);
+
+               get_info.offset++;
+               get_info.offset %= get_info.fifo_len + 1;
+               txdlp = (TxD_t *) fifo_data->list_info
+                   [get_info.offset].list_virt_addr;
+               fifo_data->tx_curr_get_info.offset =
+                   get_info.offset;
        }
 
        spin_lock(&nic->tx_lock);
@@ -2301,13 +2695,13 @@ static void tx_intr_handler(struct s2io_nic *nic)
        spin_unlock(&nic->tx_lock);
 }
 
-/**  
+/**
  *  alarm_intr_handler - Alarm Interrrupt handler
  *  @nic: device private variable
- *  Description: If the interrupt was neither because of Rx packet or Tx 
+ *  Description: If the interrupt was neither because of Rx packet or Tx
  *  complete, this function is called. If the interrupt was to indicate
- *  a loss of link, the OSM link status handler is invoked for any other 
- *  alarm interrupt the block that raised the interrupt is displayed 
+ *  a loss of link, the OSM link status handler is invoked for any other
+ *  alarm interrupt the block that raised the interrupt is displayed
  *  and a H/W reset is issued.
  *  Return Value:
  *  NONE
@@ -2320,17 +2714,44 @@ static void alarm_intr_handler(struct s2io_nic *nic)
        register u64 val64 = 0, err_reg = 0;
 
        /* Handling link status change error Intr */
-       err_reg = readq(&bar0->mac_rmac_err_reg);
-       writeq(err_reg, &bar0->mac_rmac_err_reg);
-       if (err_reg & RMAC_LINK_STATE_CHANGE_INT) {
-               schedule_work(&nic->set_link_task);
+       if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
+               err_reg = readq(&bar0->mac_rmac_err_reg);
+               writeq(err_reg, &bar0->mac_rmac_err_reg);
+               if (err_reg & RMAC_LINK_STATE_CHANGE_INT) {
+                       schedule_work(&nic->set_link_task);
+               }
+       }
+
+       /* Handling Ecc errors */
+       val64 = readq(&bar0->mc_err_reg);
+       writeq(val64, &bar0->mc_err_reg);
+       if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
+               if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
+                       nic->mac_control.stats_info->sw_stat.
+                               double_ecc_errs++;
+                       DBG_PRINT(INIT_DBG, "%s: Device indicates ",
+                                 dev->name);
+                       DBG_PRINT(INIT_DBG, "double ECC error!!\n");
+                       if (nic->device_type != XFRAME_II_DEVICE) {
+                               /* Reset XframeI only if critical error */
+                               if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
+                                            MC_ERR_REG_MIRI_ECC_DB_ERR_1)) {
+                                       netif_stop_queue(dev);
+                                       schedule_work(&nic->rst_timer_task);
+                               }
+                       }
+               } else {
+                       nic->mac_control.stats_info->sw_stat.
+                               single_ecc_errs++;
+               }
        }
 
        /* In case of a serious error, the device will be Reset. */
        val64 = readq(&bar0->serr_source);
        if (val64 & SERR_SOURCE_ANY) {
                DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
-               DBG_PRINT(ERR_DBG, "serious error!!\n");
+               DBG_PRINT(ERR_DBG, "serious error %llx!!\n", 
+                         (unsigned long long)val64);
                netif_stop_queue(dev);
                schedule_work(&nic->rst_timer_task);
        }
@@ -2338,7 +2759,7 @@ static void alarm_intr_handler(struct s2io_nic *nic)
        /*
         * Also as mentioned in the latest Errata sheets if the PCC_FB_ECC
         * Error occurs, the adapter will be recycled by disabling the
-        * adapter enable bit and enabling it again after the device 
+        * adapter enable bit and enabling it again after the device
         * becomes Quiescent.
         */
        val64 = readq(&bar0->pcc_err_reg);
@@ -2354,18 +2775,18 @@ static void alarm_intr_handler(struct s2io_nic *nic)
        /* Other type of interrupts are not being handled now,  TODO */
 }
 
-/** 
+/**
  *  wait_for_cmd_complete - waits for a command to complete.
- *  @sp : private member of the device structure, which is a pointer to the 
+ *  @sp : private member of the device structure, which is a pointer to the
  *  s2io_nic structure.
- *  Description: Function that waits for a command to Write into RMAC 
- *  ADDR DATA registers to be completed and returns either success or 
- *  error depending on whether the command was complete or not. 
+ *  Description: Function that waits for a command to Write into RMAC
+ *  ADDR DATA registers to be completed and returns either success or
+ *  error depending on whether the command was complete or not.
  *  Return value:
  *   SUCCESS on success and FAILURE on failure.
  */
 
-static int wait_for_cmd_complete(nic_t * sp)
+int wait_for_cmd_complete(nic_t * sp)
 {
        XENA_dev_config_t __iomem *bar0 = sp->bar0;
        int ret = FAILURE, cnt = 0;
@@ -2385,29 +2806,32 @@ static int wait_for_cmd_complete(nic_t * sp)
        return ret;
 }
 
-/** 
- *  s2io_reset - Resets the card. 
+/**
+ *  s2io_reset - Resets the card.
  *  @sp : private member of the device structure.
  *  Description: Function to Reset the card. This function then also
- *  restores the previously saved PCI configuration space registers as 
+ *  restores the previously saved PCI configuration space registers as
  *  the card reset also resets the configuration space.
  *  Return value:
  *  void.
  */
 
-static void s2io_reset(nic_t * sp)
+void s2io_reset(nic_t * sp)
 {
        XENA_dev_config_t __iomem *bar0 = sp->bar0;
        u64 val64;
-       u16 subid;
+       u16 subid, pci_cmd;
+
+       /* Back up  the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
+       pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
 
        val64 = SW_RESET_ALL;
        writeq(val64, &bar0->sw_reset);
 
-       /* 
-        * At this stage, if the PCI write is indeed completed, the 
-        * card is reset and so is the PCI Config space of the device. 
-        * So a read cannot be issued at this stage on any of the 
+       /*
+        * At this stage, if the PCI write is indeed completed, the
+        * card is reset and so is the PCI Config space of the device.
+        * So a read cannot be issued at this stage on any of the
         * registers to ensure the write into "sw_reset" register
         * has gone through.
         * Question: Is there any system call that will explicitly force
@@ -2418,42 +2842,72 @@ static void s2io_reset(nic_t * sp)
         */
        msleep(250);
 
-       /* Restore the PCI state saved during initializarion. */
+       /* Restore the PCI state saved during initialization. */
        pci_restore_state(sp->pdev);
+       pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
+                                    pci_cmd);
        s2io_init_pci(sp);
 
        msleep(250);
 
+       /* Set swapper to enable I/O register access */
+       s2io_set_swapper(sp);
+
+       /* Clear certain PCI/PCI-X fields after reset */
+       if (sp->device_type == XFRAME_II_DEVICE) {
+               /* Clear parity err detect bit */
+               pci_write_config_word(sp->pdev, PCI_STATUS, 0x8000);
+
+               /* Clearing PCIX Ecc status register */
+               pci_write_config_dword(sp->pdev, 0x68, 0x7C);
+
+               /* Clearing PCI_STATUS error reflected here */
+               writeq(BIT(62), &bar0->txpic_int_reg);
+       }
+
+       /* Reset device statistics maintained by OS */
+       memset(&sp->stats, 0, sizeof (struct net_device_stats));
+
        /* SXE-002: Configure link and activity LED to turn it off */
        subid = sp->pdev->subsystem_device;
-       if ((subid & 0xFF) >= 0x07) {
+       if (((subid & 0xFF) >= 0x07) &&
+           (sp->device_type == XFRAME_I_DEVICE)) {
                val64 = readq(&bar0->gpio_control);
                val64 |= 0x0000800000000000ULL;
                writeq(val64, &bar0->gpio_control);
                val64 = 0x0411040400000000ULL;
-               writeq(val64, (void __iomem *) bar0 + 0x2700);
+               writeq(val64, (void __iomem *)bar0 + 0x2700);
+       }
+
+       /*
+        * Clear spurious ECC interrupts that would have occured on
+        * XFRAME II cards after reset.
+        */
+       if (sp->device_type == XFRAME_II_DEVICE) {
+               val64 = readq(&bar0->pcc_err_reg);
+               writeq(val64, &bar0->pcc_err_reg);
        }
 
        sp->device_enabled_once = FALSE;
 }
 
 /**
- *  s2io_set_swapper - to set the swapper controle on the card 
- *  @sp : private member of the device structure, 
+ *  s2io_set_swapper - to set the swapper controle on the card
+ *  @sp : private member of the device structure,
  *  pointer to the s2io_nic structure.
- *  Description: Function to set the swapper control on the card 
+ *  Description: Function to set the swapper control on the card
  *  correctly depending on the 'endianness' of the system.
  *  Return value:
  *  SUCCESS on success and FAILURE on failure.
  */
 
-static int s2io_set_swapper(nic_t * sp)
+int s2io_set_swapper(nic_t * sp)
 {
        struct net_device *dev = sp->dev;
        XENA_dev_config_t __iomem *bar0 = sp->bar0;
        u64 val64, valt, valr;
 
-       /* 
+       /*
         * Set proper endian settings and verify the same by reading
         * the PIF Feed-back register.
         */
@@ -2505,8 +2959,9 @@ static int s2io_set_swapper(nic_t * sp)
                        i++;
                }
                if(i == 4) {
+                       unsigned long long x = val64;
                        DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr ");
-                       DBG_PRINT(ERR_DBG, "reads:0x%llx\n",val64);
+                       DBG_PRINT(ERR_DBG, "reads:0x%llx\n", x);
                        return FAILURE;
                }
        }
@@ -2514,8 +2969,8 @@ static int s2io_set_swapper(nic_t * sp)
        val64 &= 0xFFFF000000000000ULL;
 
 #ifdef  __BIG_ENDIAN
-       /* 
-        * The device by default set to a big endian format, so a 
+       /*
+        * The device by default set to a big endian format, so a
         * big endian driver need not set anything.
         */
        val64 |= (SWAPPER_CTRL_TXP_FE |
@@ -2531,9 +2986,9 @@ static int s2io_set_swapper(nic_t * sp)
                 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
        writeq(val64, &bar0->swapper_ctrl);
 #else
-       /* 
+       /*
         * Initially we enable all bits to make it accessible by the
-        * driver, then we selectively enable only those bits that 
+        * driver, then we selectively enable only those bits that
         * we want to set.
         */
        val64 |= (SWAPPER_CTRL_TXP_FE |
@@ -2555,8 +3010,8 @@ static int s2io_set_swapper(nic_t * sp)
 #endif
        val64 = readq(&bar0->swapper_ctrl);
 
-       /* 
-        * Verifying if endian settings are accurate by reading a 
+       /*
+        * Verifying if endian settings are accurate by reading a
         * feedback register.
         */
        val64 = readq(&bar0->pif_rd_swapper_fb);
@@ -2576,55 +3031,63 @@ static int s2io_set_swapper(nic_t * sp)
  * Functions defined below concern the OS part of the driver *
  * ********************************************************* */
 
-/**  
+/**
  *  s2io_open - open entry point of the driver
  *  @dev : pointer to the device structure.
  *  Description:
  *  This function is the open entry point of the driver. It mainly calls a
  *  function to allocate Rx buffers and inserts them into the buffer
- *  descriptors and then enables the Rx part of the NIC. 
+ *  descriptors and then enables the Rx part of the NIC.
  *  Return value:
  *  0 on success and an appropriate (-)ve integer as defined in errno.h
  *   file on failure.
  */
 
-static int s2io_open(struct net_device *dev)
+int s2io_open(struct net_device *dev)
 {
        nic_t *sp = dev->priv;
        int err = 0;
 
-       /* 
-        * Make sure you have link off by default every time 
+       /*
+        * Make sure you have link off by default every time
         * Nic is initialized
         */
        netif_carrier_off(dev);
-       sp->last_link_state = LINK_DOWN;
+       sp->last_link_state = 0;
 
        /* Initialize H/W and enable interrupts */
        if (s2io_card_up(sp)) {
                DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
                          dev->name);
-               return -ENODEV;
+               err = -ENODEV;
+               goto hw_init_failed;
        }
 
        /* After proper initialization of H/W, register ISR */
-       err = request_irq((int) sp->irq, s2io_isr, SA_SHIRQ,
+       err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ,
                          sp->name, dev);
        if (err) {
-               s2io_reset(sp);
                DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
                          dev->name);
-               return err;
+               goto isr_registration_failed;
        }
 
        if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
                DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
-               s2io_reset(sp);
-               return -ENODEV;
+               err = -ENODEV;
+               goto setting_mac_address_failed;
        }
 
        netif_start_queue(dev);
        return 0;
+
+setting_mac_address_failed:
+       free_irq(sp->pdev->irq, dev);
+isr_registration_failed:
+       del_timer_sync(&sp->alarm_timer);
+       s2io_reset(sp);
+hw_init_failed:
+       return err;
 }
 
 /**
@@ -2640,16 +3103,15 @@ static int s2io_open(struct net_device *dev)
  *  file on failure.
  */
 
-static int s2io_close(struct net_device *dev)
+int s2io_close(struct net_device *dev)
 {
        nic_t *sp = dev->priv;
-
        flush_scheduled_work();
        netif_stop_queue(dev);
        /* Reset card, kill tasklet and free Tx and Rx buffers. */
        s2io_card_down(sp);
 
-       free_irq(dev->irq, dev);
+       free_irq(sp->pdev->irq, dev);
        sp->device_close_flag = TRUE;   /* Device is shut down. */
        return 0;
 }
@@ -2667,7 +3129,7 @@ static int s2io_close(struct net_device *dev)
  *  0 on success & 1 on failure.
  */
 
-static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
+int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        nic_t *sp = dev->priv;
        u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
@@ -2678,37 +3140,56 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 #ifdef NETIF_F_TSO
        int mss;
 #endif
+       u16 vlan_tag = 0;
+       int vlan_priority = 0;
        mac_info_t *mac_control;
        struct config_param *config;
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
 
        mac_control = &sp->mac_control;
        config = &sp->config;
 
-       DBG_PRINT(TX_DBG, "%s: In S2IO Tx routine\n", dev->name);
+       DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name);
        spin_lock_irqsave(&sp->tx_lock, flags);
-
        if (atomic_read(&sp->card_state) == CARD_DOWN) {
-               DBG_PRINT(ERR_DBG, "%s: Card going down for reset\n",
+               DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
                          dev->name);
                spin_unlock_irqrestore(&sp->tx_lock, flags);
-               return 1;
+               dev_kfree_skb(skb);
+               return 0;
        }
 
        queue = 0;
-       put_off = (u16) mac_control->tx_curr_put_info[queue].offset;
-       get_off = (u16) mac_control->tx_curr_get_info[queue].offset;
-       txdp = (TxD_t *) sp->list_info[queue][put_off].list_virt_addr;
 
-       queue_len = mac_control->tx_curr_put_info[queue].fifo_len + 1;
+       /* Get Fifo number to Transmit based on vlan priority */
+       if (sp->vlgrp && vlan_tx_tag_present(skb)) {
+               vlan_tag = vlan_tx_tag_get(skb);
+               vlan_priority = vlan_tag >> 13;
+               queue = config->fifo_mapping[vlan_priority];
+       }
+
+       put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset;
+       get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset;
+       txdp = (TxD_t *) mac_control->fifos[queue].list_info[put_off].
+               list_virt_addr;
+
+       queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
        /* Avoid "put" pointer going beyond "get" pointer */
        if (txdp->Host_Control || (((put_off + 1) % queue_len) == get_off)) {
-               DBG_PRINT(ERR_DBG, "Error in xmit, No free TXDs.\n");
+               DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
                netif_stop_queue(dev);
                dev_kfree_skb(skb);
                spin_unlock_irqrestore(&sp->tx_lock, flags);
                return 0;
        }
+
+       /* A buffer with no data will be dropped */
+       if (!skb->len) {
+               DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
+               dev_kfree_skb(skb);
+               spin_unlock_irqrestore(&sp->tx_lock, flags);
+               return 0;
+       }
+
 #ifdef NETIF_F_TSO
        mss = skb_shinfo(skb)->tso_size;
        if (mss) {
@@ -2720,9 +3201,9 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
        frg_cnt = skb_shinfo(skb)->nr_frags;
        frg_len = skb->len - skb->data_len;
 
-       txdp->Host_Control = (unsigned long) skb;
        txdp->Buffer_Pointer = pci_map_single
            (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
+       txdp->Host_Control = (unsigned long) skb;
        if (skb->ip_summed == CHECKSUM_HW) {
                txdp->Control_2 |=
                    (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
@@ -2731,6 +3212,11 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 
        txdp->Control_2 |= config->tx_intr_type;
 
+       if (sp->vlgrp && vlan_tx_tag_present(skb)) {
+               txdp->Control_2 |= TXD_VLAN_ENABLE;
+               txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag);
+       }
+
        txdp->Control_1 |= (TXD_BUFFER0_SIZE(frg_len) |
                            TXD_GATHER_CODE_FIRST);
        txdp->Control_1 |= TXD_LIST_OWN_XENA;
@@ -2738,6 +3224,9 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
        /* For fragmented SKB. */
        for (i = 0; i < frg_cnt; i++) {
                skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+               /* A '0' length fragment will be ignored */
+               if (!frag->size)
+                       continue;
                txdp++;
                txdp->Buffer_Pointer = (u64) pci_map_page
                    (sp->pdev, frag->page, frag->page_offset,
@@ -2747,23 +3236,23 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
        txdp->Control_1 |= TXD_GATHER_CODE_LAST;
 
        tx_fifo = mac_control->tx_FIFO_start[queue];
-       val64 = sp->list_info[queue][put_off].list_phy_addr;
+       val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr;
        writeq(val64, &tx_fifo->TxDL_Pointer);
 
        val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST |
                 TX_FIFO_LAST_LIST);
+
 #ifdef NETIF_F_TSO
        if (mss)
                val64 |= TX_FIFO_SPECIAL_FUNC;
 #endif
        writeq(val64, &tx_fifo->List_Control);
 
-       /* Perform a PCI read to flush previous writes */
-       val64 = readq(&bar0->general_int_status);
+       mmiowb();
 
        put_off++;
-       put_off %= mac_control->tx_curr_put_info[queue].fifo_len + 1;
-       mac_control->tx_curr_put_info[queue].offset = put_off;
+       put_off %= mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
+       mac_control->fifos[queue].tx_curr_put_info.offset = put_off;
 
        /* Avoid "put" pointer going beyond "get" pointer */
        if (((put_off + 1) % queue_len) == get_off) {
@@ -2779,18 +3268,74 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
        return 0;
 }
 
+static void
+s2io_alarm_handle(unsigned long data)
+{
+       nic_t *sp = (nic_t *)data;
+
+       alarm_intr_handler(sp);
+       mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
+}
+
+static void s2io_txpic_intr_handle(nic_t *sp)
+{
+       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       u64 val64;
+
+       val64 = readq(&bar0->pic_int_status);
+       if (val64 & PIC_INT_GPIO) {
+               val64 = readq(&bar0->gpio_int_reg);
+               if ((val64 & GPIO_INT_REG_LINK_DOWN) &&
+                   (val64 & GPIO_INT_REG_LINK_UP)) {
+                       val64 |=  GPIO_INT_REG_LINK_DOWN;
+                       val64 |= GPIO_INT_REG_LINK_UP;
+                       writeq(val64, &bar0->gpio_int_reg);
+                       goto masking;
+               }
+
+               if (((sp->last_link_state == LINK_UP) &&
+                       (val64 & GPIO_INT_REG_LINK_DOWN)) ||
+               ((sp->last_link_state == LINK_DOWN) &&
+               (val64 & GPIO_INT_REG_LINK_UP))) {
+                       val64 = readq(&bar0->gpio_int_mask);
+                       val64 |=  GPIO_INT_MASK_LINK_DOWN;
+                       val64 |= GPIO_INT_MASK_LINK_UP;
+                       writeq(val64, &bar0->gpio_int_mask);
+                       s2io_set_link((unsigned long)sp);
+               }
+masking:
+               if (sp->last_link_state == LINK_UP) {
+                       /*enable down interrupt */
+                       val64 = readq(&bar0->gpio_int_mask);
+                       /* unmasks link down intr */
+                       val64 &=  ~GPIO_INT_MASK_LINK_DOWN;
+                       /* masks link up intr */
+                       val64 |= GPIO_INT_MASK_LINK_UP;
+                       writeq(val64, &bar0->gpio_int_mask);
+               } else {
+                       /*enable UP Interrupt */
+                       val64 = readq(&bar0->gpio_int_mask);
+                       /* unmasks link up interrupt */
+                       val64 &= ~GPIO_INT_MASK_LINK_UP;
+                       /* masks link down interrupt */
+                       val64 |=  GPIO_INT_MASK_LINK_DOWN;
+                       writeq(val64, &bar0->gpio_int_mask);
+               }
+       }
+}
+
 /**
  *  s2io_isr - ISR handler of the device .
  *  @irq: the irq of the device.
  *  @dev_id: a void pointer to the dev structure of the NIC.
  *  @pt_regs: pointer to the registers pushed on the stack.
- *  Description:  This function is the ISR handler of the device. It 
- *  identifies the reason for the interrupt and calls the relevant 
- *  service routines. As a contongency measure, this ISR allocates the 
+ *  Description:  This function is the ISR handler of the device. It
+ *  identifies the reason for the interrupt and calls the relevant
+ *  service routines. As a contongency measure, this ISR allocates the
  *  recv buffers, if their numbers are below the panic value which is
  *  presently set to 25% of the original number of rcv buffers allocated.
  *  Return value:
- *   IRQ_HANDLED: will be returned if IRQ was handled by this routine 
+ *   IRQ_HANDLED: will be returned if IRQ was handled by this routine
  *   IRQ_NONE: will be returned if interrupt is not from our device
  */
 static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
@@ -2798,40 +3343,31 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
        struct net_device *dev = (struct net_device *) dev_id;
        nic_t *sp = dev->priv;
        XENA_dev_config_t __iomem *bar0 = sp->bar0;
-#ifndef CONFIG_S2IO_NAPI
-       int i, ret;
-#endif
-       u64 reason = 0;
+       int i;
+       u64 reason = 0, val64;
        mac_info_t *mac_control;
        struct config_param *config;
 
+       atomic_inc(&sp->isr_cnt);
        mac_control = &sp->mac_control;
        config = &sp->config;
 
-       /* 
+       /*
         * Identify the cause for interrupt and call the appropriate
         * interrupt handler. Causes for the interrupt could be;
         * 1. Rx of packet.
         * 2. Tx complete.
         * 3. Link down.
-        * 4. Error in any functional blocks of the NIC. 
+        * 4. Error in any functional blocks of the NIC.
         */
        reason = readq(&bar0->general_int_status);
 
        if (!reason) {
                /* The interrupt was not raised by Xena. */
+               atomic_dec(&sp->isr_cnt);
                return IRQ_NONE;
        }
 
-       /* If Intr is because of Tx Traffic */
-       if (reason & GEN_INTR_TXTRAFFIC) {
-               tx_intr_handler(sp);
-       }
-
-       /* If Intr is because of an error */
-       if (reason & (GEN_ERROR_INTR))
-               alarm_intr_handler(sp);
-
 #ifdef CONFIG_S2IO_NAPI
        if (reason & GEN_INTR_RXTRAFFIC) {
                if (netif_rx_schedule_prep(dev)) {
@@ -2843,17 +3379,43 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
 #else
        /* If Intr is because of Rx Traffic */
        if (reason & GEN_INTR_RXTRAFFIC) {
-               rx_intr_handler(sp);
+               /*
+                * rx_traffic_int reg is an R1 register, writing all 1's
+                * will ensure that the actual interrupt causing bit get's
+                * cleared and hence a read can be avoided.
+                */
+               val64 = 0xFFFFFFFFFFFFFFFFULL;
+               writeq(val64, &bar0->rx_traffic_int);
+               for (i = 0; i < config->rx_ring_num; i++) {
+                       rx_intr_handler(&mac_control->rings[i]);
+               }
        }
 #endif
 
-       /* 
-        * If the Rx buffer count is below the panic threshold then 
-        * reallocate the buffers from the interrupt handler itself, 
+       /* If Intr is because of Tx Traffic */
+       if (reason & GEN_INTR_TXTRAFFIC) {
+               /*
+                * tx_traffic_int reg is an R1 register, writing all 1's
+                * will ensure that the actual interrupt causing bit get's
+                * cleared and hence a read can be avoided.
+                */
+               val64 = 0xFFFFFFFFFFFFFFFFULL;
+               writeq(val64, &bar0->tx_traffic_int);
+
+               for (i = 0; i < config->tx_fifo_num; i++)
+                       tx_intr_handler(&mac_control->fifos[i]);
+       }
+
+       if (reason & GEN_INTR_TXPIC)
+               s2io_txpic_intr_handle(sp);
+       /*
+        * If the Rx buffer count is below the panic threshold then
+        * reallocate the buffers from the interrupt handler itself,
         * else schedule a tasklet to reallocate the buffers.
         */
 #ifndef CONFIG_S2IO_NAPI
        for (i = 0; i < config->rx_ring_num; i++) {
+               int ret;
                int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
                int level = rx_buffer_level(sp, rxb_size, i);
 
@@ -2865,6 +3427,7 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
                                          dev->name);
                                DBG_PRINT(ERR_DBG, " in ISR!!\n");
                                clear_bit(0, (&sp->tasklet_status));
+                               atomic_dec(&sp->isr_cnt);
                                return IRQ_HANDLED;
                        }
                        clear_bit(0, (&sp->tasklet_status));
@@ -2874,33 +3437,69 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
        }
 #endif
 
+       atomic_dec(&sp->isr_cnt);
        return IRQ_HANDLED;
 }
 
 /**
- *  s2io_get_stats - Updates the device statistics structure. 
+ * s2io_updt_stats -
+ */
+static void s2io_updt_stats(nic_t *sp)
+{
+       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       u64 val64;
+       int cnt = 0;
+
+       if (atomic_read(&sp->card_state) == CARD_UP) {
+               /* Apprx 30us on a 133 MHz bus */
+               val64 = SET_UPDT_CLICKS(10) |
+                       STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN;
+               writeq(val64, &bar0->stat_cfg);
+               do {
+                       udelay(100);
+                       val64 = readq(&bar0->stat_cfg);
+                       if (!(val64 & BIT(0)))
+                               break;
+                       cnt++;
+                       if (cnt == 5)
+                               break; /* Updt failed */
+               } while(1);
+       }
+}
+
+/**
+ *  s2io_get_stats - Updates the device statistics structure.
  *  @dev : pointer to the device structure.
  *  Description:
- *  This function updates the device statistics structure in the s2io_nic 
+ *  This function updates the device statistics structure in the s2io_nic
  *  structure and returns a pointer to the same.
  *  Return value:
  *  pointer to the updated net_device_stats structure.
  */
 
-static struct net_device_stats *s2io_get_stats(struct net_device *dev)
+struct net_device_stats *s2io_get_stats(struct net_device *dev)
 {
        nic_t *sp = dev->priv;
        mac_info_t *mac_control;
        struct config_param *config;
 
+
        mac_control = &sp->mac_control;
        config = &sp->config;
 
-       sp->stats.tx_errors = mac_control->stats_info->tmac_any_err_frms;
-       sp->stats.rx_errors = mac_control->stats_info->rmac_drop_frms;
-       sp->stats.multicast = mac_control->stats_info->rmac_vld_mcst_frms;
+       /* Configure Stats for immediate updt */
+       s2io_updt_stats(sp);
+
+       sp->stats.tx_packets =
+               le32_to_cpu(mac_control->stats_info->tmac_frms);
+       sp->stats.tx_errors =
+               le32_to_cpu(mac_control->stats_info->tmac_any_err_frms);
+       sp->stats.rx_errors =
+               le32_to_cpu(mac_control->stats_info->rmac_drop_frms);
+       sp->stats.multicast =
+               le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms);
        sp->stats.rx_length_errors =
-           mac_control->stats_info->rmac_long_frms;
+               le32_to_cpu(mac_control->stats_info->rmac_long_frms);
 
        return (&sp->stats);
 }
@@ -2909,8 +3508,8 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev)
  *  s2io_set_multicast - entry point for multicast address enable/disable.
  *  @dev : pointer to the device structure
  *  Description:
- *  This function is a driver entry point which gets called by the kernel 
- *  whenever multicast addresses must be enabled/disabled. This also gets 
+ *  This function is a driver entry point which gets called by the kernel
+ *  whenever multicast addresses must be enabled/disabled. This also gets
  *  called to set/reset promiscuous mode. Depending on the deivce flag, we
  *  determine, if multicast address must be enabled or if promiscuous mode
  *  is to be disabled etc.
@@ -2948,6 +3547,8 @@ static void s2io_set_multicast(struct net_device *dev)
                /*  Disable all Multicast addresses */
                writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
                       &bar0->rmac_addr_data0_mem);
+               writeq(RMAC_ADDR_DATA1_MEM_MASK(0x0),
+                      &bar0->rmac_addr_data1_mem);
                val64 = RMAC_ADDR_CMD_MEM_WE |
                    RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
                    RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos);
@@ -2972,7 +3573,7 @@ static void s2io_set_multicast(struct net_device *dev)
 
                val64 = readq(&bar0->mac_cfg);
                sp->promisc_flg = 1;
-               DBG_PRINT(ERR_DBG, "%s: entered promiscuous mode\n",
+               DBG_PRINT(INFO_DBG, "%s: entered promiscuous mode\n",
                          dev->name);
        } else if (!(dev->flags & IFF_PROMISC) && (sp->promisc_flg)) {
                /*  Remove the NIC from promiscuous mode */
@@ -2987,7 +3588,7 @@ static void s2io_set_multicast(struct net_device *dev)
 
                val64 = readq(&bar0->mac_cfg);
                sp->promisc_flg = 0;
-               DBG_PRINT(ERR_DBG, "%s: left promiscuous mode\n",
+               DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n",
                          dev->name);
        }
 
@@ -3010,7 +3611,7 @@ static void s2io_set_multicast(struct net_device *dev)
                        writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
                               &bar0->rmac_addr_data0_mem);
                        writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
-                               &bar0->rmac_addr_data1_mem);
+                               &bar0->rmac_addr_data1_mem);
                        val64 = RMAC_ADDR_CMD_MEM_WE |
                            RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
                            RMAC_ADDR_CMD_MEM_OFFSET
@@ -3039,8 +3640,7 @@ static void s2io_set_multicast(struct net_device *dev)
                        writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
                               &bar0->rmac_addr_data0_mem);
                        writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
-                               &bar0->rmac_addr_data1_mem);
-
+                               &bar0->rmac_addr_data1_mem);
                        val64 = RMAC_ADDR_CMD_MEM_WE |
                            RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
                            RMAC_ADDR_CMD_MEM_OFFSET
@@ -3059,12 +3659,12 @@ static void s2io_set_multicast(struct net_device *dev)
 }
 
 /**
- *  s2io_set_mac_addr - Programs the Xframe mac address 
+ *  s2io_set_mac_addr - Programs the Xframe mac address
  *  @dev : pointer to the device structure.
  *  @addr: a uchar pointer to the new mac address which is to be set.
- *  Description : This procedure will program the Xframe to receive 
+ *  Description : This procedure will program the Xframe to receive
  *  frames with new Mac Address
- *  Return value: SUCCESS on success and an appropriate (-)ve integer 
+ *  Return value: SUCCESS on success and an appropriate (-)ve integer
  *  as defined in errno.h file on failure.
  */
 
@@ -3075,10 +3675,10 @@ int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
        register u64 val64, mac_addr = 0;
        int i;
 
-       /* 
+       /*
         * Set the new MAC address as the new unicast filter and reflect this
         * change on the device address registered with the OS. It will be
-        * at offset 0. 
+        * at offset 0.
         */
        for (i = 0; i < ETH_ALEN; i++) {
                mac_addr <<= 8;
@@ -3102,12 +3702,12 @@ int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
 }
 
 /**
- * s2io_ethtool_sset - Sets different link parameters. 
+ * s2io_ethtool_sset - Sets different link parameters.
  * @sp : private member of the device structure, which is a pointer to the  * s2io_nic structure.
  * @info: pointer to the structure with parameters given by ethtool to set
  * link information.
  * Description:
- * The function sets different link parameters provided by the user onto 
+ * The function sets different link parameters provided by the user onto
  * the NIC.
  * Return value:
  * 0 on success.
@@ -3129,7 +3729,7 @@ static int s2io_ethtool_sset(struct net_device *dev,
 }
 
 /**
- * s2io_ethtol_gset - Return link specific information. 
+ * s2io_ethtol_gset - Return link specific information.
  * @sp : private member of the device structure, pointer to the
  *      s2io_nic structure.
  * @info : pointer to the structure with parameters given by ethtool
@@ -3161,8 +3761,8 @@ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
 }
 
 /**
- * s2io_ethtool_gdrvinfo - Returns driver specific information. 
- * @sp : private member of the device structure, which is a pointer to the 
+ * s2io_ethtool_gdrvinfo - Returns driver specific information.
+ * @sp : private member of the device structure, which is a pointer to the
  * s2io_nic structure.
  * @info : pointer to the structure with parameters given by ethtool to
  * return driver information.
@@ -3190,9 +3790,9 @@ static void s2io_ethtool_gdrvinfo(struct net_device *dev,
 
 /**
  *  s2io_ethtool_gregs - dumps the entire space of Xfame into the buffer.
- *  @sp: private member of the device structure, which is a pointer to the 
+ *  @sp: private member of the device structure, which is a pointer to the
  *  s2io_nic structure.
- *  @regs : pointer to the structure with parameters given by ethtool for 
+ *  @regs : pointer to the structure with parameters given by ethtool for
  *  dumping the registers.
  *  @reg_space: The input argumnet into which all the registers are dumped.
  *  Description:
@@ -3221,11 +3821,11 @@ static void s2io_ethtool_gregs(struct net_device *dev,
 
 /**
  *  s2io_phy_id  - timer function that alternates adapter LED.
- *  @data : address of the private member of the device structure, which 
+ *  @data : address of the private member of the device structure, which
  *  is a pointer to the s2io_nic structure, provided as an u32.
- * Description: This is actually the timer function that alternates the 
- * adapter LED bit of the adapter control bit to set/reset every time on 
- * invocation. The timer is set for 1/2 a second, hence tha NIC blinks 
+ * Description: This is actually the timer function that alternates the
+ * adapter LED bit of the adapter control bit to set/reset every time on
+ * invocation. The timer is set for 1/2 a second, hence tha NIC blinks
  *  once every second.
 */
 static void s2io_phy_id(unsigned long data)
@@ -3236,7 +3836,8 @@ static void s2io_phy_id(unsigned long data)
        u16 subid;
 
        subid = sp->pdev->subsystem_device;
-       if ((subid & 0xFF) >= 0x07) {
+       if ((sp->device_type == XFRAME_II_DEVICE) ||
+                  ((subid & 0xFF) >= 0x07)) {
                val64 = readq(&bar0->gpio_control);
                val64 ^= GPIO_CTRL_GPIO_0;
                writeq(val64, &bar0->gpio_control);
@@ -3253,12 +3854,12 @@ static void s2io_phy_id(unsigned long data)
  * s2io_ethtool_idnic - To physically identify the nic on the system.
  * @sp : private member of the device structure, which is a pointer to the
  * s2io_nic structure.
- * @id : pointer to the structure with identification parameters given by 
+ * @id : pointer to the structure with identification parameters given by
  * ethtool.
  * Description: Used to physically identify the NIC on the system.
- * The Link LED will blink for a time specified by the user for 
+ * The Link LED will blink for a time specified by the user for
  * identification.
- * NOTE: The Link has to be Up to be able to blink the LED. Hence 
+ * NOTE: The Link has to be Up to be able to blink the LED. Hence
  * identification is possible only if it's link is up.
  * Return value:
  * int , returns 0 on success
@@ -3273,7 +3874,8 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
 
        subid = sp->pdev->subsystem_device;
        last_gpio_ctrl_val = readq(&bar0->gpio_control);
-       if ((subid & 0xFF) < 0x07) {
+       if ((sp->device_type == XFRAME_I_DEVICE) &&
+               ((subid & 0xFF) < 0x07)) {
                val64 = readq(&bar0->adapter_control);
                if (!(val64 & ADAPTER_CNTL_EN)) {
                        printk(KERN_ERR
@@ -3288,12 +3890,12 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
        }
        mod_timer(&sp->id_timer, jiffies);
        if (data)
-               msleep(data * 1000);
+               msleep_interruptible(data * HZ);
        else
-               msleep(0xFFFFFFFF);
+               msleep_interruptible(MAX_FLICKER_TIME);
        del_timer_sync(&sp->id_timer);
 
-       if (CARDS_WITH_FAULTY_LINK_INDICATORS(subid)) {
+       if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) {
                writeq(last_gpio_ctrl_val, &bar0->gpio_control);
                last_gpio_ctrl_val = readq(&bar0->gpio_control);
        }
@@ -3303,7 +3905,8 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
 
 /**
  * s2io_ethtool_getpause_data -Pause frame frame generation and reception.
- * @sp : private member of the device structure, which is a pointer to the  * s2io_nic structure.
+ * @sp : private member of the device structure, which is a pointer to the
+ *     s2io_nic structure.
  * @ep : pointer to the structure with pause parameters given by ethtool.
  * Description:
  * Returns the Pause frame generation and reception capability of the NIC.
@@ -3327,7 +3930,7 @@ static void s2io_ethtool_getpause_data(struct net_device *dev,
 
 /**
  * s2io_ethtool_setpause_data -  set/reset pause frame generation.
- * @sp : private member of the device structure, which is a pointer to the 
+ * @sp : private member of the device structure, which is a pointer to the
  *      s2io_nic structure.
  * @ep : pointer to the structure with pause parameters given by ethtool.
  * Description:
@@ -3338,7 +3941,7 @@ static void s2io_ethtool_getpause_data(struct net_device *dev,
  */
 
 static int s2io_ethtool_setpause_data(struct net_device *dev,
-                                     struct ethtool_pauseparam *ep)
+                              struct ethtool_pauseparam *ep)
 {
        u64 val64;
        nic_t *sp = dev->priv;
@@ -3359,13 +3962,13 @@ static int s2io_ethtool_setpause_data(struct net_device *dev,
 
 /**
  * read_eeprom - reads 4 bytes of data from user given offset.
- * @sp : private member of the device structure, which is a pointer to the 
+ * @sp : private member of the device structure, which is a pointer to the
  *      s2io_nic structure.
  * @off : offset at which the data must be written
  * @data : Its an output parameter where the data read at the given
- *     offset is stored.
+ *     offset is stored.
  * Description:
- * Will read 4 bytes of data from the user given offset and return the 
+ * Will read 4 bytes of data from the user given offset and return the
  * read data.
  * NOTE: Will allow to read only part of the EEPROM visible through the
  *   I2C bus.
@@ -3406,7 +4009,7 @@ static int read_eeprom(nic_t * sp, int off, u32 * data)
  *       s2io_nic structure.
  *  @off : offset at which the data must be written
  *  @data : The data that is to be written
- *  @cnt : Number of bytes of the data that are actually to be written into 
+ *  @cnt : Number of bytes of the data that are actually to be written into
  *  the Eeprom. (max of 3)
  * Description:
  *  Actually writes the relevant part of the data value into the Eeprom
@@ -3443,7 +4046,7 @@ static int write_eeprom(nic_t * sp, int off, u32 data, int cnt)
 /**
  *  s2io_ethtool_geeprom  - reads the value stored in the Eeprom.
  *  @sp : private member of the device structure, which is a pointer to the *       s2io_nic structure.
- *  @eeprom : pointer to the user level structure provided by ethtool, 
+ *  @eeprom : pointer to the user level structure provided by ethtool,
  *  containing all relevant information.
  *  @data_buf : user defined value to be written into Eeprom.
  *  Description: Reads the values stored in the Eeprom at given offset
@@ -3454,7 +4057,7 @@ static int write_eeprom(nic_t * sp, int off, u32 data, int cnt)
  */
 
 static int s2io_ethtool_geeprom(struct net_device *dev,
-                               struct ethtool_eeprom *eeprom, u8 * data_buf)
+                        struct ethtool_eeprom *eeprom, u8 * data_buf)
 {
        u32 data, i, valid;
        nic_t *sp = dev->priv;
@@ -3479,7 +4082,7 @@ static int s2io_ethtool_geeprom(struct net_device *dev,
  *  s2io_ethtool_seeprom - tries to write the user provided value in Eeprom
  *  @sp : private member of the device structure, which is a pointer to the
  *  s2io_nic structure.
- *  @eeprom : pointer to the user level structure provided by ethtool, 
+ *  @eeprom : pointer to the user level structure provided by ethtool,
  *  containing all relevant information.
  *  @data_buf ; user defined value to be written into Eeprom.
  *  Description:
@@ -3527,8 +4130,8 @@ static int s2io_ethtool_seeprom(struct net_device *dev,
 }
 
 /**
- * s2io_register_test - reads and writes into all clock domains. 
- * @sp : private member of the device structure, which is a pointer to the 
+ * s2io_register_test - reads and writes into all clock domains.
+ * @sp : private member of the device structure, which is a pointer to the
  * s2io_nic structure.
  * @data : variable that returns the result of each of the test conducted b
  * by the driver.
@@ -3545,8 +4148,8 @@ static int s2io_register_test(nic_t * sp, uint64_t * data)
        u64 val64 = 0;
        int fail = 0;
 
-       val64 = readq(&bar0->pcc_enable);
-       if (val64 != 0xff00000000000000ULL) {
+       val64 = readq(&bar0->pif_rd_swapper_fb);
+       if (val64 != 0x123456789abcdefULL) {
                fail = 1;
                DBG_PRINT(INFO_DBG, "Read Test level 1 fails\n");
        }
@@ -3590,13 +4193,13 @@ static int s2io_register_test(nic_t * sp, uint64_t * data)
 }
 
 /**
- * s2io_eeprom_test - to verify that EEprom in the xena can be programmed. 
+ * s2io_eeprom_test - to verify that EEprom in the xena can be programmed.
  * @sp : private member of the device structure, which is a pointer to the
  * s2io_nic structure.
  * @data:variable that returns the result of each of the test conducted by
  * the driver.
  * Description:
- * Verify that EEPROM in the xena can be programmed using I2C_CONTROL 
+ * Verify that EEPROM in the xena can be programmed using I2C_CONTROL
  * register.
  * Return value:
  * 0 on success.
@@ -3661,14 +4264,14 @@ static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
 
 /**
  * s2io_bist_test - invokes the MemBist test of the card .
- * @sp : private member of the device structure, which is a pointer to the 
+ * @sp : private member of the device structure, which is a pointer to the
  * s2io_nic structure.
- * @data:variable that returns the result of each of the test conducted by 
+ * @data:variable that returns the result of each of the test conducted by
  * the driver.
  * Description:
  * This invokes the MemBist test of the card. We give around
  * 2 secs time for the Test to complete. If it's still not complete
- * within this peiod, we consider that the test failed. 
+ * within this peiod, we consider that the test failed.
  * Return value:
  * 0 on success and -1 on failure.
  */
@@ -3697,13 +4300,13 @@ static int s2io_bist_test(nic_t * sp, uint64_t * data)
 }
 
 /**
- * s2io-link_test - verifies the link state of the nic  
- * @sp ; private member of the device structure, which is a pointer to the 
+ * s2io-link_test - verifies the link state of the nic
+ * @sp ; private member of the device structure, which is a pointer to the
  * s2io_nic structure.
  * @data: variable that returns the result of each of the test conducted by
  * the driver.
  * Description:
- * The function verifies the link state of the NIC and updates the input 
+ * The function verifies the link state of the NIC and updates the input
  * argument 'data' appropriately.
  * Return value:
  * 0 on success.
@@ -3722,13 +4325,13 @@ static int s2io_link_test(nic_t * sp, uint64_t * data)
 }
 
 /**
- * s2io_rldram_test - offline test for access to the RldRam chip on the NIC 
- * @sp - private member of the device structure, which is a pointer to the  
+ * s2io_rldram_test - offline test for access to the RldRam chip on the NIC
+ * @sp - private member of the device structure, which is a pointer to the
  * s2io_nic structure.
- * @data - variable that returns the result of each of the test 
+ * @data - variable that returns the result of each of the test
  * conducted by the driver.
  * Description:
- *  This is one of the offline test that tests the read and write 
+ *  This is one of the offline test that tests the read and write
  *  access to the RldRam chip on the NIC.
  * Return value:
  *  0 on success.
@@ -3833,7 +4436,7 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data)
  *  s2io_nic structure.
  *  @ethtest : pointer to a ethtool command specific structure that will be
  *  returned to the user.
- *  @data : variable that returns the result of each of the test 
+ *  @data : variable that returns the result of each of the test
  * conducted by the driver.
  * Description:
  *  This function conducts 6 tests ( 4 offline and 2 online) to determine
@@ -3851,23 +4454,18 @@ static void s2io_ethtool_test(struct net_device *dev,
 
        if (ethtest->flags == ETH_TEST_FL_OFFLINE) {
                /* Offline Tests. */
-               if (orig_state) {
+               if (orig_state)
                        s2io_close(sp->dev);
-                       s2io_set_swapper(sp);
-               } else
-                       s2io_set_swapper(sp);
 
                if (s2io_register_test(sp, &data[0]))
                        ethtest->flags |= ETH_TEST_FL_FAILED;
 
                s2io_reset(sp);
-               s2io_set_swapper(sp);
 
                if (s2io_rldram_test(sp, &data[3]))
                        ethtest->flags |= ETH_TEST_FL_FAILED;
 
                s2io_reset(sp);
-               s2io_set_swapper(sp);
 
                if (s2io_eeprom_test(sp, &data[1]))
                        ethtest->flags |= ETH_TEST_FL_FAILED;
@@ -3910,61 +4508,111 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
        nic_t *sp = dev->priv;
        StatInfo_t *stat_info = sp->mac_control.stats_info;
 
-       tmp_stats[i++] = le32_to_cpu(stat_info->tmac_frms);
-       tmp_stats[i++] = le32_to_cpu(stat_info->tmac_data_octets);
+       s2io_updt_stats(sp);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->tmac_frms_oflow) << 32  |
+               le32_to_cpu(stat_info->tmac_frms);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->tmac_data_octets_oflow) << 32 |
+               le32_to_cpu(stat_info->tmac_data_octets);
        tmp_stats[i++] = le64_to_cpu(stat_info->tmac_drop_frms);
-       tmp_stats[i++] = le32_to_cpu(stat_info->tmac_mcst_frms);
-       tmp_stats[i++] = le32_to_cpu(stat_info->tmac_bcst_frms);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->tmac_mcst_frms_oflow) << 32 |
+               le32_to_cpu(stat_info->tmac_mcst_frms);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->tmac_bcst_frms_oflow) << 32 |
+               le32_to_cpu(stat_info->tmac_bcst_frms);
        tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms);
-       tmp_stats[i++] = le32_to_cpu(stat_info->tmac_any_err_frms);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->tmac_any_err_frms_oflow) << 32 |
+               le32_to_cpu(stat_info->tmac_any_err_frms);
        tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets);
-       tmp_stats[i++] = le32_to_cpu(stat_info->tmac_vld_ip);
-       tmp_stats[i++] = le32_to_cpu(stat_info->tmac_drop_ip);
-       tmp_stats[i++] = le32_to_cpu(stat_info->tmac_icmp);
-       tmp_stats[i++] = le32_to_cpu(stat_info->tmac_rst_tcp);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->tmac_vld_ip_oflow) << 32 |
+               le32_to_cpu(stat_info->tmac_vld_ip);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->tmac_drop_ip_oflow) << 32 |
+               le32_to_cpu(stat_info->tmac_drop_ip);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->tmac_icmp_oflow) << 32 |
+               le32_to_cpu(stat_info->tmac_icmp);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->tmac_rst_tcp_oflow) << 32 |
+               le32_to_cpu(stat_info->tmac_rst_tcp);
        tmp_stats[i++] = le64_to_cpu(stat_info->tmac_tcp);
-       tmp_stats[i++] = le32_to_cpu(stat_info->tmac_udp);
-       tmp_stats[i++] = le32_to_cpu(stat_info->rmac_vld_frms);
-       tmp_stats[i++] = le32_to_cpu(stat_info->rmac_data_octets);
+       tmp_stats[i++] = (u64)le32_to_cpu(stat_info->tmac_udp_oflow) << 32 |
+               le32_to_cpu(stat_info->tmac_udp);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->rmac_vld_frms_oflow) << 32 |
+               le32_to_cpu(stat_info->rmac_vld_frms);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->rmac_data_octets_oflow) << 32 |
+               le32_to_cpu(stat_info->rmac_data_octets);
        tmp_stats[i++] = le64_to_cpu(stat_info->rmac_fcs_err_frms);
        tmp_stats[i++] = le64_to_cpu(stat_info->rmac_drop_frms);
-       tmp_stats[i++] = le32_to_cpu(stat_info->rmac_vld_mcst_frms);
-       tmp_stats[i++] = le32_to_cpu(stat_info->rmac_vld_bcst_frms);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->rmac_vld_mcst_frms_oflow) << 32 |
+               le32_to_cpu(stat_info->rmac_vld_mcst_frms);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->rmac_vld_bcst_frms_oflow) << 32 |
+               le32_to_cpu(stat_info->rmac_vld_bcst_frms);
        tmp_stats[i++] = le32_to_cpu(stat_info->rmac_in_rng_len_err_frms);
        tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms);
        tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms);
-       tmp_stats[i++] = le32_to_cpu(stat_info->rmac_discarded_frms);
-       tmp_stats[i++] = le32_to_cpu(stat_info->rmac_usized_frms);
-       tmp_stats[i++] = le32_to_cpu(stat_info->rmac_osized_frms);
-       tmp_stats[i++] = le32_to_cpu(stat_info->rmac_frag_frms);
-       tmp_stats[i++] = le32_to_cpu(stat_info->rmac_jabber_frms);
-       tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ip);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->rmac_discarded_frms_oflow) << 32 |
+               le32_to_cpu(stat_info->rmac_discarded_frms);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->rmac_usized_frms_oflow) << 32 |
+               le32_to_cpu(stat_info->rmac_usized_frms);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->rmac_osized_frms_oflow) << 32 |
+               le32_to_cpu(stat_info->rmac_osized_frms);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->rmac_frag_frms_oflow) << 32 |
+               le32_to_cpu(stat_info->rmac_frag_frms);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->rmac_jabber_frms_oflow) << 32 |
+               le32_to_cpu(stat_info->rmac_jabber_frms);
+       tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_ip_oflow) << 32 |
+               le32_to_cpu(stat_info->rmac_ip);
        tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ip_octets);
        tmp_stats[i++] = le32_to_cpu(stat_info->rmac_hdr_err_ip);
-       tmp_stats[i++] = le32_to_cpu(stat_info->rmac_drop_ip);
-       tmp_stats[i++] = le32_to_cpu(stat_info->rmac_icmp);
+       tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_drop_ip_oflow) << 32 |
+               le32_to_cpu(stat_info->rmac_drop_ip);
+       tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_icmp_oflow) << 32 |
+               le32_to_cpu(stat_info->rmac_icmp);
        tmp_stats[i++] = le64_to_cpu(stat_info->rmac_tcp);
-       tmp_stats[i++] = le32_to_cpu(stat_info->rmac_udp);
-       tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_drp_udp);
-       tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pause_cnt);
-       tmp_stats[i++] = le32_to_cpu(stat_info->rmac_accepted_ip);
+       tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_udp_oflow) << 32 |
+               le32_to_cpu(stat_info->rmac_udp);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->rmac_err_drp_udp_oflow) << 32 |
+               le32_to_cpu(stat_info->rmac_err_drp_udp);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->rmac_pause_cnt_oflow) << 32 |
+               le32_to_cpu(stat_info->rmac_pause_cnt);
+       tmp_stats[i++] =
+               (u64)le32_to_cpu(stat_info->rmac_accepted_ip_oflow) << 32 |
+               le32_to_cpu(stat_info->rmac_accepted_ip);
        tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_tcp);
+       tmp_stats[i++] = 0;
+       tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs;
+       tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs;
 }
 
-static int s2io_ethtool_get_regs_len(struct net_device *dev)
+int s2io_ethtool_get_regs_len(struct net_device *dev)
 {
        return (XENA_REG_SPACE);
 }
 
 
-static u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
+u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
 {
        nic_t *sp = dev->priv;
 
        return (sp->rx_csum);
 }
-
-static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
+int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
 {
        nic_t *sp = dev->priv;
 
@@ -3975,19 +4623,17 @@ static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
 
        return 0;
 }
-
-static int s2io_get_eeprom_len(struct net_device *dev)
+int s2io_get_eeprom_len(struct net_device *dev)
 {
        return (XENA_EEPROM_SPACE);
 }
 
-static int s2io_ethtool_self_test_count(struct net_device *dev)
+int s2io_ethtool_self_test_count(struct net_device *dev)
 {
        return (S2IO_TEST_LEN);
 }
-
-static void s2io_ethtool_get_strings(struct net_device *dev,
-                                    u32 stringset, u8 * data)
+void s2io_ethtool_get_strings(struct net_device *dev,
+                             u32 stringset, u8 * data)
 {
        switch (stringset) {
        case ETH_SS_TEST:
@@ -3998,13 +4644,12 @@ static void s2io_ethtool_get_strings(struct net_device *dev,
                       sizeof(ethtool_stats_keys));
        }
 }
-
 static int s2io_ethtool_get_stats_count(struct net_device *dev)
 {
        return (S2IO_STAT_LEN);
 }
 
-static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
+int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
 {
        if (data)
                dev->features |= NETIF_F_IP_CSUM;
@@ -4046,21 +4691,18 @@ static struct ethtool_ops netdev_ethtool_ops = {
 };
 
 /**
- *  s2io_ioctl - Entry point for the Ioctl 
+ *  s2io_ioctl - Entry point for the Ioctl
  *  @dev :  Device pointer.
  *  @ifr :  An IOCTL specefic structure, that can contain a pointer to
  *  a proprietary structure used to pass information to the driver.
  *  @cmd :  This is used to distinguish between the different commands that
  *  can be passed to the IOCTL functions.
  *  Description:
- *  This function has support for ethtool, adding multiple MAC addresses on 
- *  the NIC and some DBG commands for the util tool.
- *  Return value:
- *  Currently the IOCTL supports no operations, hence by default this
- *  function returns OP NOT SUPPORTED value.
+ *  Currently there are no special functionality supported in IOCTL, hence
+ *  function always return EOPNOTSUPPORTED
  */
 
-static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
        return -EOPNOTSUPP;
 }
@@ -4076,17 +4718,9 @@ static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
  *   file on failure.
  */
 
-static int s2io_change_mtu(struct net_device *dev, int new_mtu)
+int s2io_change_mtu(struct net_device *dev, int new_mtu)
 {
        nic_t *sp = dev->priv;
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
-       register u64 val64;
-
-       if (netif_running(dev)) {
-               DBG_PRINT(ERR_DBG, "%s: Must be stopped to ", dev->name);
-               DBG_PRINT(ERR_DBG, "change its MTU \n");
-               return -EBUSY;
-       }
 
        if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
                DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n",
@@ -4094,11 +4728,22 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu)
                return -EPERM;
        }
 
-       /* Set the new MTU into the PYLD register of the NIC */
-       val64 = new_mtu;
-       writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
-
        dev->mtu = new_mtu;
+       if (netif_running(dev)) {
+               s2io_card_down(sp);
+               netif_stop_queue(dev);
+               if (s2io_card_up(sp)) {
+                       DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
+                                 __FUNCTION__);
+               }
+               if (netif_queue_stopped(dev))
+                       netif_wake_queue(dev);
+       } else { /* Device is down */
+               XENA_dev_config_t __iomem *bar0 = sp->bar0;
+               u64 val64 = new_mtu;
+
+               writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
+       }
 
        return 0;
 }
@@ -4108,9 +4753,9 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu)
  *  @dev_adr : address of the device structure in dma_addr_t format.
  *  Description:
  *  This is the tasklet or the bottom half of the ISR. This is
- *  an extension of the ISR which is scheduled by the scheduler to be run 
+ *  an extension of the ISR which is scheduled by the scheduler to be run
  *  when the load on the CPU is low. All low priority tasks of the ISR can
- *  be pushed into the tasklet. For now the tasklet is used only to 
+ *  be pushed into the tasklet. For now the tasklet is used only to
  *  replenish the Rx buffers in the Rx buffer descriptors.
  *  Return value:
  *  void.
@@ -4166,19 +4811,22 @@ static void s2io_set_link(unsigned long data)
        }
 
        subid = nic->pdev->subsystem_device;
-       /* 
-        * Allow a small delay for the NICs self initiated 
-        * cleanup to complete.
-        */
-       msleep(100);
+       if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
+               /*
+                * Allow a small delay for the NICs self initiated
+                * cleanup to complete.
+                */
+               msleep(100);
+       }
 
        val64 = readq(&bar0->adapter_status);
-       if (verify_xena_quiescence(val64, nic->device_enabled_once)) {
+       if (verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
                if (LINK_IS_UP(val64)) {
                        val64 = readq(&bar0->adapter_control);
                        val64 |= ADAPTER_CNTL_EN;
                        writeq(val64, &bar0->adapter_control);
-                       if (CARDS_WITH_FAULTY_LINK_INDICATORS(subid)) {
+                       if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
+                                                            subid)) {
                                val64 = readq(&bar0->gpio_control);
                                val64 |= GPIO_CTRL_GPIO_0;
                                writeq(val64, &bar0->gpio_control);
@@ -4187,20 +4835,24 @@ static void s2io_set_link(unsigned long data)
                                val64 |= ADAPTER_LED_ON;
                                writeq(val64, &bar0->adapter_control);
                        }
-                       val64 = readq(&bar0->adapter_status);
-                       if (!LINK_IS_UP(val64)) {
-                               DBG_PRINT(ERR_DBG, "%s:", dev->name);
-                               DBG_PRINT(ERR_DBG, " Link down");
-                               DBG_PRINT(ERR_DBG, "after ");
-                               DBG_PRINT(ERR_DBG, "enabling ");
-                               DBG_PRINT(ERR_DBG, "device \n");
+                       if (s2io_link_fault_indication(nic) ==
+                                               MAC_RMAC_ERR_TIMER) {
+                               val64 = readq(&bar0->adapter_status);
+                               if (!LINK_IS_UP(val64)) {
+                                       DBG_PRINT(ERR_DBG, "%s:", dev->name);
+                                       DBG_PRINT(ERR_DBG, " Link down");
+                                       DBG_PRINT(ERR_DBG, "after ");
+                                       DBG_PRINT(ERR_DBG, "enabling ");
+                                       DBG_PRINT(ERR_DBG, "device \n");
+                               }
                        }
                        if (nic->device_enabled_once == FALSE) {
                                nic->device_enabled_once = TRUE;
                        }
                        s2io_link(nic, LINK_UP);
                } else {
-                       if (CARDS_WITH_FAULTY_LINK_INDICATORS(subid)) {
+                       if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
+                                                             subid)) {
                                val64 = readq(&bar0->gpio_control);
                                val64 &= ~GPIO_CTRL_GPIO_0;
                                writeq(val64, &bar0->gpio_control);
@@ -4223,9 +4875,11 @@ static void s2io_card_down(nic_t * sp)
        unsigned long flags;
        register u64 val64 = 0;
 
+       del_timer_sync(&sp->alarm_timer);
        /* If s2io_set_link task is executing, wait till it completes. */
-       while (test_and_set_bit(0, &(sp->link_state)))
+       while (test_and_set_bit(0, &(sp->link_state))) {
                msleep(50);
+       }
        atomic_set(&sp->card_state, CARD_DOWN);
 
        /* disable Tx and Rx traffic on the NIC */
@@ -4237,7 +4891,7 @@ static void s2io_card_down(nic_t * sp)
        /* Check if the device is Quiescent and then Reset the NIC */
        do {
                val64 = readq(&bar0->adapter_status);
-               if (verify_xena_quiescence(val64, sp->device_enabled_once)) {
+               if (verify_xena_quiescence(sp, val64, sp->device_enabled_once)) {
                        break;
                }
 
@@ -4251,14 +4905,27 @@ static void s2io_card_down(nic_t * sp)
                        break;
                }
        } while (1);
-       spin_lock_irqsave(&sp->tx_lock, flags);
        s2io_reset(sp);
 
-       /* Free all unused Tx and Rx buffers */
+       /* Waiting till all Interrupt handlers are complete */
+       cnt = 0;
+       do {
+               msleep(10);
+               if (!atomic_read(&sp->isr_cnt))
+                       break;
+               cnt++;
+       } while(cnt < 5);
+
+       spin_lock_irqsave(&sp->tx_lock, flags);
+       /* Free all Tx buffers */
        free_tx_buffers(sp);
+       spin_unlock_irqrestore(&sp->tx_lock, flags);
+
+       /* Free all Rx buffers */
+       spin_lock_irqsave(&sp->rx_lock, flags);
        free_rx_buffers(sp);
+       spin_unlock_irqrestore(&sp->rx_lock, flags);
 
-       spin_unlock_irqrestore(&sp->tx_lock, flags);
        clear_bit(0, &(sp->link_state));
 }
 
@@ -4276,8 +4943,8 @@ static int s2io_card_up(nic_t * sp)
                return -ENODEV;
        }
 
-       /* 
-        * Initializing the Rx buffers. For now we are considering only 1 
+       /*
+        * Initializing the Rx buffers. For now we are considering only 1
         * Rx ring and initializing buffers into 30 Rx blocks
         */
        mac_control = &sp->mac_control;
@@ -4311,16 +4978,18 @@ static int s2io_card_up(nic_t * sp)
                return -ENODEV;
        }
 
+       S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2));
+
        atomic_set(&sp->card_state, CARD_UP);
        return 0;
 }
 
-/** 
+/**
  * s2io_restart_nic - Resets the NIC.
  * @data : long pointer to the device private structure
  * Description:
  * This function is scheduled to be run by the s2io_tx_watchdog
- * function after 0.5 secs to reset the NIC. The idea is to reduce 
+ * function after 0.5 secs to reset the NIC. The idea is to reduce
  * the run time of the watch dog routine which is run holding a
  * spin lock.
  */
@@ -4338,10 +5007,11 @@ static void s2io_restart_nic(unsigned long data)
        netif_wake_queue(dev);
        DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n",
                  dev->name);
+
 }
 
-/** 
- *  s2io_tx_watchdog - Watchdog for transmit side. 
+/**
+ *  s2io_tx_watchdog - Watchdog for transmit side.
  *  @dev : Pointer to net device structure
  *  Description:
  *  This function is triggered if the Tx Queue is stopped
@@ -4369,7 +5039,7 @@ static void s2io_tx_watchdog(struct net_device *dev)
  *   @len : length of the packet
  *   @cksum : FCS checksum of the frame.
  *   @ring_no : the ring from which this RxD was extracted.
- *   Description: 
+ *   Description:
  *   This function is called by the Tx interrupt serivce routine to perform
  *   some OS related operations on the SKB before passing it to the upper
  *   layers. It mainly checks if the checksum is OK, if so adds it to the
@@ -4379,35 +5049,68 @@ static void s2io_tx_watchdog(struct net_device *dev)
  *   Return value:
  *   SUCCESS on success and -1 on failure.
  */
-#ifndef CONFIG_2BUFF_MODE
-static int rx_osm_handler(nic_t * sp, u16 len, RxD_t * rxdp, int ring_no)
-#else
-static int rx_osm_handler(nic_t * sp, RxD_t * rxdp, int ring_no,
-                         buffAdd_t * ba)
-#endif
+static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
 {
+       nic_t *sp = ring_data->nic;
        struct net_device *dev = (struct net_device *) sp->dev;
-       struct sk_buff *skb =
-           (struct sk_buff *) ((unsigned long) rxdp->Host_Control);
+       struct sk_buff *skb = (struct sk_buff *)
+               ((unsigned long) rxdp->Host_Control);
+       int ring_no = ring_data->ring_no;
        u16 l3_csum, l4_csum;
 #ifdef CONFIG_2BUFF_MODE
-       int buf0_len, buf2_len;
+       int buf0_len = RXD_GET_BUFFER0_SIZE(rxdp->Control_2);
+       int buf2_len = RXD_GET_BUFFER2_SIZE(rxdp->Control_2);
+       int get_block = ring_data->rx_curr_get_info.block_index;
+       int get_off = ring_data->rx_curr_get_info.offset;
+       buffAdd_t *ba = &ring_data->ba[get_block][get_off];
        unsigned char *buff;
+#else
+       u16 len = (u16) ((RXD_GET_BUFFER0_SIZE(rxdp->Control_2)) >> 48);;
+#endif
+       skb->dev = dev;
+       if (rxdp->Control_1 & RXD_T_CODE) {
+               unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
+               DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%llx\n",
+                         dev->name, err);
+               dev_kfree_skb(skb);
+               sp->stats.rx_crc_errors++;
+               atomic_dec(&sp->rx_bufs_left[ring_no]);
+               rxdp->Host_Control = 0;
+               return 0;
+       }
+
+       /* Updating statistics */
+       rxdp->Host_Control = 0;
+       sp->rx_pkt_count++;
+       sp->stats.rx_packets++;
+#ifndef CONFIG_2BUFF_MODE
+       sp->stats.rx_bytes += len;
+#else
+       sp->stats.rx_bytes += buf0_len + buf2_len;
+#endif
+
+#ifndef CONFIG_2BUFF_MODE
+       skb_put(skb, len);
+#else
+       buff = skb_push(skb, buf0_len);
+       memcpy(buff, ba->ba_0, buf0_len);
+       skb_put(skb, buf2_len);
 #endif
 
-       l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
-       if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && (sp->rx_csum)) {
+       if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) &&
+           (sp->rx_csum)) {
+               l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
                l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
                if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) {
-                       /* 
+                       /*
                         * NIC verifies if the Checksum of the received
                         * frame is Ok or not and accordingly returns
                         * a flag in the RxD.
                         */
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                } else {
-                       /* 
-                        * Packet with erroneous checksum, let the 
+                       /*
+                        * Packet with erroneous checksum, let the
                         * upper layers deal with it.
                         */
                        skb->ip_summed = CHECKSUM_NONE;
@@ -4416,44 +5119,26 @@ static int rx_osm_handler(nic_t * sp, RxD_t * rxdp, int ring_no,
                skb->ip_summed = CHECKSUM_NONE;
        }
 
-       if (rxdp->Control_1 & RXD_T_CODE) {
-               unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
-               DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%llx\n",
-                         dev->name, err);
-       }
-#ifdef CONFIG_2BUFF_MODE
-       buf0_len = RXD_GET_BUFFER0_SIZE(rxdp->Control_2);
-       buf2_len = RXD_GET_BUFFER2_SIZE(rxdp->Control_2);
-#endif
-
-       skb->dev = dev;
-#ifndef CONFIG_2BUFF_MODE
-       skb_put(skb, len);
        skb->protocol = eth_type_trans(skb, dev);
-#else
-       buff = skb_push(skb, buf0_len);
-       memcpy(buff, ba->ba_0, buf0_len);
-       skb_put(skb, buf2_len);
-       skb->protocol = eth_type_trans(skb, dev);
-#endif
-
 #ifdef CONFIG_S2IO_NAPI
-       netif_receive_skb(skb);
+       if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
+               /* Queueing the vlan frame to the upper layer */
+               vlan_hwaccel_receive_skb(skb, sp->vlgrp,
+                       RXD_GET_VLAN_TAG(rxdp->Control_2));
+       } else {
+               netif_receive_skb(skb);
+       }
 #else
-       netif_rx(skb);
+       if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
+               /* Queueing the vlan frame to the upper layer */
+               vlan_hwaccel_rx(skb, sp->vlgrp,
+                       RXD_GET_VLAN_TAG(rxdp->Control_2));
+       } else {
+               netif_rx(skb);
+       }
 #endif
-
        dev->last_rx = jiffies;
-       sp->rx_pkt_count++;
-       sp->stats.rx_packets++;
-#ifndef CONFIG_2BUFF_MODE
-       sp->stats.rx_bytes += len;
-#else
-       sp->stats.rx_bytes += buf0_len + buf2_len;
-#endif
-
        atomic_dec(&sp->rx_bufs_left[ring_no]);
-       rxdp->Host_Control = 0;
        return SUCCESS;
 }
 
@@ -4464,13 +5149,13 @@ static int rx_osm_handler(nic_t * sp, RxD_t * rxdp, int ring_no,
  *  @link : inidicates whether link is UP/DOWN.
  *  Description:
  *  This function stops/starts the Tx queue depending on whether the link
- *  status of the NIC is is down or up. This is called by the Alarm 
- *  interrupt handler whenever a link change interrupt comes up. 
+ *  status of the NIC is is down or up. This is called by the Alarm
+ *  interrupt handler whenever a link change interrupt comes up.
  *  Return value:
  *  void.
  */
 
-static void s2io_link(nic_t * sp, int link)
+void s2io_link(nic_t * sp, int link)
 {
        struct net_device *dev = (struct net_device *) sp->dev;
 
@@ -4487,8 +5172,25 @@ static void s2io_link(nic_t * sp, int link)
 }
 
 /**
- *  s2io_init_pci -Initialization of PCI and PCI-X configuration registers . 
- *  @sp : private member of the device structure, which is a pointer to the 
+ *  get_xena_rev_id - to identify revision ID of xena.
+ *  @pdev : PCI Dev structure
+ *  Description:
+ *  Function to identify the Revision ID of xena.
+ *  Return value:
+ *  returns the revision ID of the device.
+ */
+
+int get_xena_rev_id(struct pci_dev *pdev)
+{
+       u8 id = 0;
+       int ret;
+       ret = pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) & id);
+       return id;
+}
+
+/**
+ *  s2io_init_pci -Initialization of PCI and PCI-X configuration registers .
+ *  @sp : private member of the device structure, which is a pointer to the
  *  s2io_nic structure.
  *  Description:
  *  This function initializes a few of the PCI and PCI-X configuration registers
@@ -4499,15 +5201,15 @@ static void s2io_link(nic_t * sp, int link)
 
 static void s2io_init_pci(nic_t * sp)
 {
-       u16 pci_cmd = 0;
+       u16 pci_cmd = 0, pcix_cmd = 0;
 
        /* Enable Data Parity Error Recovery in PCI-X command register. */
        pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
-                            &(sp->pcix_cmd));
+                            &(pcix_cmd));
        pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
-                             (sp->pcix_cmd | 1));
+                             (pcix_cmd | 1));
        pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
-                            &(sp->pcix_cmd));
+                            &(pcix_cmd));
 
        /* Set the PErr Response bit in PCI command register. */
        pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
@@ -4515,53 +5217,43 @@ static void s2io_init_pci(nic_t * sp)
                              (pci_cmd | PCI_COMMAND_PARITY));
        pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
 
-       /* Set MMRB count to 1024 in PCI-X Command register. */
-       sp->pcix_cmd &= 0xFFF3;
-       pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, (sp->pcix_cmd | (0x1 << 2)));    /* MMRBC 1K */
-       pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
-                            &(sp->pcix_cmd));
-
-       /*  Setting Maximum outstanding splits based on system type. */
-       sp->pcix_cmd &= 0xFF8F;
-
-       sp->pcix_cmd |= XENA_MAX_OUTSTANDING_SPLITS(0x1);       /* 2 splits. */
-       pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
-                             sp->pcix_cmd);
-       pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
-                            &(sp->pcix_cmd));
        /* Forcibly disabling relaxed ordering capability of the card. */
-       sp->pcix_cmd &= 0xfffd;
+       pcix_cmd &= 0xfffd;
        pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
-                             sp->pcix_cmd);
+                             pcix_cmd);
        pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
-                            &(sp->pcix_cmd));
+                            &(pcix_cmd));
 }
 
 MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
 MODULE_LICENSE("GPL");
 module_param(tx_fifo_num, int, 0);
-module_param_array(tx_fifo_len, int, NULL, 0);
 module_param(rx_ring_num, int, 0);
-module_param_array(rx_ring_sz, int, NULL, 0);
-module_param(Stats_refresh_time, int, 0);
+module_param_array(tx_fifo_len, uint, NULL, 0);
+module_param_array(rx_ring_sz, uint, NULL, 0);
+module_param_array(rts_frm_len, uint, NULL, 0);
+module_param(use_continuous_tx_intrs, int, 1);
 module_param(rmac_pause_time, int, 0);
 module_param(mc_pause_threshold_q0q3, int, 0);
 module_param(mc_pause_threshold_q4q7, int, 0);
 module_param(shared_splits, int, 0);
 module_param(tmac_util_period, int, 0);
 module_param(rmac_util_period, int, 0);
+module_param(bimodal, bool, 0);
 #ifndef CONFIG_S2IO_NAPI
 module_param(indicate_max_pkts, int, 0);
 #endif
+module_param(rxsync_frequency, int, 0);
+
 /**
- *  s2io_init_nic - Initialization of the adapter . 
+ *  s2io_init_nic - Initialization of the adapter .
  *  @pdev : structure containing the PCI related information of the device.
  *  @pre: List of PCI devices supported by the driver listed in s2io_tbl.
  *  Description:
  *  The function initializes an adapter identified by the pci_dec structure.
- *  All OS related initialization including memory and device structure and 
- *  initlaization of the device private variable is done. Also the swapper 
- *  control register is initialized to enable read and write into the I/O 
+ *  All OS related initialization including memory and device structure and
+ *  initlaization of the device private variable is done. Also the swapper
+ *  control register is initialized to enable read and write into the I/O
  *  registers of the device.
  *  Return value:
  *  returns 0 on success and negative on failure.
@@ -4572,7 +5264,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
 {
        nic_t *sp;
        struct net_device *dev;
-       char *dev_name = "S2IO 10GE NIC";
        int i, j, ret;
        int dma_flag = FALSE;
        u32 mac_up, mac_down;
@@ -4581,10 +5272,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        u16 subid;
        mac_info_t *mac_control;
        struct config_param *config;
+       int mode;
 
-
-       DBG_PRINT(ERR_DBG, "Loading S2IO driver with %s\n",
-               s2io_driver_version);
+#ifdef CONFIG_S2IO_NAPI
+       DBG_PRINT(ERR_DBG, "NAPI support has been enabled\n");
+#endif
 
        if ((ret = pci_enable_device(pdev))) {
                DBG_PRINT(ERR_DBG,
@@ -4595,7 +5287,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
                DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n");
                dma_flag = TRUE;
-
                if (pci_set_consistent_dma_mask
                    (pdev, DMA_64BIT_MASK)) {
                        DBG_PRINT(ERR_DBG,
@@ -4635,34 +5326,41 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        memset(sp, 0, sizeof(nic_t));
        sp->dev = dev;
        sp->pdev = pdev;
-       sp->vendor_id = pdev->vendor;
-       sp->device_id = pdev->device;
        sp->high_dma_flag = dma_flag;
-       sp->irq = pdev->irq;
        sp->device_enabled_once = FALSE;
-       strcpy(sp->name, dev_name);
+
+       if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) ||
+               (pdev->device == PCI_DEVICE_ID_HERC_UNI))
+               sp->device_type = XFRAME_II_DEVICE;
+       else
+               sp->device_type = XFRAME_I_DEVICE;
 
        /* Initialize some PCI/PCI-X fields of the NIC. */
        s2io_init_pci(sp);
 
-       /* 
+       /*
         * Setting the device configuration parameters.
-        * Most of these parameters can be specified by the user during 
-        * module insertion as they are module loadable parameters. If 
-        * these parameters are not not specified during load time, they 
+        * Most of these parameters can be specified by the user during
+        * module insertion as they are module loadable parameters. If
+        * these parameters are not not specified during load time, they
         * are initialized with default values.
         */
        mac_control = &sp->mac_control;
        config = &sp->config;
 
        /* Tx side parameters. */
-       tx_fifo_len[0] = DEFAULT_FIFO_LEN;      /* Default value. */
+       if (tx_fifo_len[0] == 0)
+               tx_fifo_len[0] = DEFAULT_FIFO_LEN; /* Default value. */
        config->tx_fifo_num = tx_fifo_num;
        for (i = 0; i < MAX_TX_FIFOS; i++) {
                config->tx_cfg[i].fifo_len = tx_fifo_len[i];
                config->tx_cfg[i].fifo_priority = i;
        }
 
+       /* mapping the QoS priority to the configured fifos */
+       for (i = 0; i < MAX_TX_FIFOS; i++)
+               config->fifo_mapping[i] = fifo_map[config->tx_fifo_num][i];
+
        config->tx_intr_type = TXD_INT_TYPE_UTILZ;
        for (i = 0; i < config->tx_fifo_num; i++) {
                config->tx_cfg[i].f_no_snoop =
@@ -4672,10 +5370,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
                        break;
                }
        }
-       config->max_txds = MAX_SKB_FRAGS;
+       config->max_txds = MAX_SKB_FRAGS + 1;
 
        /* Rx side parameters. */
-       rx_ring_sz[0] = SMALL_BLK_CNT;  /* Default value. */
+       if (rx_ring_sz[0] == 0)
+               rx_ring_sz[0] = SMALL_BLK_CNT; /* Default value. */
        config->rx_ring_num = rx_ring_num;
        for (i = 0; i < MAX_RX_RINGS; i++) {
                config->rx_cfg[i].num_rxd = rx_ring_sz[i] *
@@ -4699,10 +5398,13 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        for (i = 0; i < config->rx_ring_num; i++)
                atomic_set(&sp->rx_bufs_left[i], 0);
 
+       /* Initialize the number of ISRs currently running */
+       atomic_set(&sp->isr_cnt, 0);
+
        /*  initialize the shared memory used by the NIC and the host */
        if (init_shared_mem(sp)) {
                DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
-                         dev->name);
+                         __FUNCTION__);
                ret = -ENOMEM;
                goto mem_alloc_failed;
        }
@@ -4743,13 +5445,17 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        dev->do_ioctl = &s2io_ioctl;
        dev->change_mtu = &s2io_change_mtu;
        SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
+       dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+       dev->vlan_rx_register = s2io_vlan_rx_register;
+       dev->vlan_rx_kill_vid = (void *)s2io_vlan_rx_kill_vid;
+
        /*
         * will use eth_mac_addr() for  dev->set_mac_address
         * mac address will be set every time dev->open() is called
         */
-#ifdef CONFIG_S2IO_NAPI
+#if defined(CONFIG_S2IO_NAPI)
        dev->poll = s2io_poll;
-       dev->weight = 90;
+       dev->weight = 32;
 #endif
 
        dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
@@ -4776,22 +5482,28 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
                goto set_swap_failed;
        }
 
-       /* Fix for all "FFs" MAC address problems observed on Alpha platforms */
-       fix_mac_address(sp);
-       s2io_reset(sp);
+       /* Verify if the Herc works on the slot its placed into */
+       if (sp->device_type & XFRAME_II_DEVICE) {
+               mode = s2io_verify_pci_mode(sp);
+               if (mode < 0) {
+                       DBG_PRINT(ERR_DBG, "%s: ", __FUNCTION__);
+                       DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
+                       ret = -EBADSLT;
+                       goto set_swap_failed;
+               }
+       }
 
-       /*
-        * Setting swapper control on the NIC, so the MAC address can be read.
-        */
-       if (s2io_set_swapper(sp)) {
-               DBG_PRINT(ERR_DBG,
-                         "%s: S2IO: swapper settings are wrong\n",
-                         dev->name);
-               ret = -EAGAIN;
-               goto set_swap_failed;
+       /* Not needed for Herc */
+       if (sp->device_type & XFRAME_I_DEVICE) {
+               /*
+                * Fix for all "FFs" MAC address problems observed on
+                * Alpha platforms
+                */
+               fix_mac_address(sp);
+               s2io_reset(sp);
        }
 
-       /*  
+       /*
         * MAC address initialization.
         * For now only one mac address will be read and used.
         */
@@ -4814,37 +5526,28 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_down >> 16);
        sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_down >> 24);
 
-       DBG_PRINT(INIT_DBG,
-                 "DEFAULT MAC ADDR:0x%02x-%02x-%02x-%02x-%02x-%02x\n",
-                 sp->def_mac_addr[0].mac_addr[0],
-                 sp->def_mac_addr[0].mac_addr[1],
-                 sp->def_mac_addr[0].mac_addr[2],
-                 sp->def_mac_addr[0].mac_addr[3],
-                 sp->def_mac_addr[0].mac_addr[4],
-                 sp->def_mac_addr[0].mac_addr[5]);
-
        /*  Set the factory defined MAC address initially   */
        dev->addr_len = ETH_ALEN;
        memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
 
        /*
-        * Initialize the tasklet status and link state flags 
-        * and the card statte parameter
+        * Initialize the tasklet status and link state flags
+        * and the card state parameter
         */
        atomic_set(&(sp->card_state), 0);
        sp->tasklet_status = 0;
        sp->link_state = 0;
 
-
        /* Initialize spinlocks */
        spin_lock_init(&sp->tx_lock);
 #ifndef CONFIG_S2IO_NAPI
        spin_lock_init(&sp->put_lock);
 #endif
+       spin_lock_init(&sp->rx_lock);
 
-       /* 
-        * SXE-002: Configure link and activity LED to init state 
-        * on driver load. 
+       /*
+        * SXE-002: Configure link and activity LED to init state
+        * on driver load.
         */
        subid = sp->pdev->subsystem_device;
        if ((subid & 0xFF) >= 0x07) {
@@ -4864,13 +5567,70 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
                goto register_failed;
        }
 
-       /* 
-        * Make Link state as off at this point, when the Link change 
-        * interrupt comes the state will be automatically changed to 
+       if (sp->device_type & XFRAME_II_DEVICE) {
+               DBG_PRINT(ERR_DBG, "%s: Neterion Xframe II 10GbE adapter ",
+                         dev->name);
+               DBG_PRINT(ERR_DBG, "(rev %d), %s",
+                               get_xena_rev_id(sp->pdev),
+                               s2io_driver_version);
+#ifdef CONFIG_2BUFF_MODE
+               DBG_PRINT(ERR_DBG, ", Buffer mode %d",2);
+#endif
+
+               DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n");
+               DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
+                         sp->def_mac_addr[0].mac_addr[0],
+                         sp->def_mac_addr[0].mac_addr[1],
+                         sp->def_mac_addr[0].mac_addr[2],
+                         sp->def_mac_addr[0].mac_addr[3],
+                         sp->def_mac_addr[0].mac_addr[4],
+                         sp->def_mac_addr[0].mac_addr[5]);
+               mode = s2io_print_pci_mode(sp);
+               if (mode < 0) {
+                       DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode ");
+                       ret = -EBADSLT;
+                       goto set_swap_failed;
+               }
+       } else {
+               DBG_PRINT(ERR_DBG, "%s: Neterion Xframe I 10GbE adapter ",
+                         dev->name);
+               DBG_PRINT(ERR_DBG, "(rev %d), %s",
+                                       get_xena_rev_id(sp->pdev),
+                                       s2io_driver_version);
+#ifdef CONFIG_2BUFF_MODE
+               DBG_PRINT(ERR_DBG, ", Buffer mode %d",2);
+#endif
+               DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n");
+               DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
+                         sp->def_mac_addr[0].mac_addr[0],
+                         sp->def_mac_addr[0].mac_addr[1],
+                         sp->def_mac_addr[0].mac_addr[2],
+                         sp->def_mac_addr[0].mac_addr[3],
+                         sp->def_mac_addr[0].mac_addr[4],
+                         sp->def_mac_addr[0].mac_addr[5]);
+       }
+
+       /* Initialize device name */
+       strcpy(sp->name, dev->name);
+       if (sp->device_type & XFRAME_II_DEVICE)
+               strcat(sp->name, ": Neterion Xframe II 10GbE adapter");
+       else
+               strcat(sp->name, ": Neterion Xframe I 10GbE adapter");
+
+       /* Initialize bimodal Interrupts */
+       sp->config.bimodal = bimodal;
+       if (!(sp->device_type & XFRAME_II_DEVICE) && bimodal) {
+               sp->config.bimodal = 0;
+               DBG_PRINT(ERR_DBG,"%s:Bimodal intr not supported by Xframe I\n",
+                       dev->name);
+       }
+
+       /*
+        * Make Link state as off at this point, when the Link change
+        * interrupt comes the state will be automatically changed to
         * the right state.
         */
        netif_carrier_off(dev);
-       sp->last_link_state = LINK_DOWN;
 
        return 0;
 
@@ -4891,11 +5651,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
 }
 
 /**
- * s2io_rem_nic - Free the PCI device 
+ * s2io_rem_nic - Free the PCI device
  * @pdev: structure containing the PCI related information of the device.
- * Description: This function is called by the Pci subsystem to release a 
+ * Description: This function is called by the Pci subsystem to release a
  * PCI device and free up all resource held up by the device. This could
- * be in response to a Hot plug event or when the driver is to be removed 
+ * be in response to a Hot plug event or when the driver is to be removed
  * from memory.
  */
 
@@ -4919,7 +5679,6 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
        pci_disable_device(pdev);
        pci_release_regions(pdev);
        pci_set_drvdata(pdev, NULL);
-
        free_netdev(dev);
 }
 
@@ -4935,11 +5694,11 @@ int __init s2io_starter(void)
 }
 
 /**
- * s2io_closer - Cleanup routine for the driver 
+ * s2io_closer - Cleanup routine for the driver
  * Description: This function is the cleanup routine for the driver. It unregist * ers the driver.
  */
 
-static void s2io_closer(void)
+void s2io_closer(void)
 {
        pci_unregister_driver(&s2io_driver);
        DBG_PRINT(INIT_DBG, "cleanup done\n");
index 1711c8c3dc99f02c50e627e08144f5d6d5ea685e..89151cb5218132414efae178eddb05f6f0515d26 100644 (file)
@@ -1,5 +1,5 @@
 /************************************************************************
- * s2io.h: A Linux PCI-X Ethernet driver for S2IO 10GbE Server NIC
+ * s2io.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
  * Copyright(c) 2002-2005 Neterion Inc.
 
  * This software may be used and distributed according to the terms of
@@ -31,6 +31,9 @@
 #define SUCCESS 0
 #define FAILURE -1
 
+/* Maximum time to flicker LED when asked to identify NIC using ethtool */
+#define MAX_FLICKER_TIME       60000 /* 60 Secs */
+
 /* Maximum outstanding splits to be configured into xena. */
 typedef enum xena_max_outstanding_splits {
        XENA_ONE_SPLIT_TRANSACTION = 0,
@@ -45,10 +48,10 @@ typedef enum xena_max_outstanding_splits {
 #define XENA_MAX_OUTSTANDING_SPLITS(n) (n << 4)
 
 /*  OS concerned variables and constants */
-#define WATCH_DOG_TIMEOUT      5*HZ
-#define EFILL                          0x1234
-#define ALIGN_SIZE                     127
-#define        PCIX_COMMAND_REGISTER   0x62
+#define WATCH_DOG_TIMEOUT              15*HZ
+#define EFILL                          0x1234
+#define ALIGN_SIZE                     127
+#define        PCIX_COMMAND_REGISTER           0x62
 
 /*
  * Debug related variables.
@@ -61,7 +64,7 @@ typedef enum xena_max_outstanding_splits {
 #define        INTR_DBG        4
 
 /* Global variable that defines the present debug level of the driver. */
-static int debug_level = ERR_DBG;      /* Default level. */
+int debug_level = ERR_DBG;     /* Default level. */
 
 /* DEBUG message print. */
 #define DBG_PRINT(dbg_level, args...)  if(!(debug_level<dbg_level)) printk(args)
@@ -71,6 +74,12 @@ static int debug_level = ERR_DBG;    /* Default level. */
 #define L4_CKSUM_OK 0xFFFF
 #define S2IO_JUMBO_SIZE 9600
 
+/* Driver statistics maintained by driver */
+typedef struct {
+       unsigned long long single_ecc_errs;
+       unsigned long long double_ecc_errs;
+} swStat_t;
+
 /* The statistics block of Xena */
 typedef struct stat_block {
 /* Tx MAC statistics counters. */
@@ -186,12 +195,90 @@ typedef struct stat_block {
        u32 rxd_rd_cnt;
        u32 rxf_wr_cnt;
        u32 txf_rd_cnt;
+
+/* Tx MAC statistics overflow counters. */
+       u32 tmac_data_octets_oflow;
+       u32 tmac_frms_oflow;
+       u32 tmac_bcst_frms_oflow;
+       u32 tmac_mcst_frms_oflow;
+       u32 tmac_ucst_frms_oflow;
+       u32 tmac_ttl_octets_oflow;
+       u32 tmac_any_err_frms_oflow;
+       u32 tmac_nucst_frms_oflow;
+       u64 tmac_vlan_frms;
+       u32 tmac_drop_ip_oflow;
+       u32 tmac_vld_ip_oflow;
+       u32 tmac_rst_tcp_oflow;
+       u32 tmac_icmp_oflow;
+       u32 tpa_unknown_protocol;
+       u32 tmac_udp_oflow;
+       u32 reserved_10;
+       u32 tpa_parse_failure;
+
+/* Rx MAC Statistics overflow counters. */
+       u32 rmac_data_octets_oflow;
+       u32 rmac_vld_frms_oflow;
+       u32 rmac_vld_bcst_frms_oflow;
+       u32 rmac_vld_mcst_frms_oflow;
+       u32 rmac_accepted_ucst_frms_oflow;
+       u32 rmac_ttl_octets_oflow;
+       u32 rmac_discarded_frms_oflow;
+       u32 rmac_accepted_nucst_frms_oflow;
+       u32 rmac_usized_frms_oflow;
+       u32 rmac_drop_events_oflow;
+       u32 rmac_frag_frms_oflow;
+       u32 rmac_osized_frms_oflow;
+       u32 rmac_ip_oflow;
+       u32 rmac_jabber_frms_oflow;
+       u32 rmac_icmp_oflow;
+       u32 rmac_drop_ip_oflow;
+       u32 rmac_err_drp_udp_oflow;
+       u32 rmac_udp_oflow;
+       u32 reserved_11;
+       u32 rmac_pause_cnt_oflow;
+       u64 rmac_ttl_1519_4095_frms;
+       u64 rmac_ttl_4096_8191_frms;
+       u64 rmac_ttl_8192_max_frms;
+       u64 rmac_ttl_gt_max_frms;
+       u64 rmac_osized_alt_frms;
+       u64 rmac_jabber_alt_frms;
+       u64 rmac_gt_max_alt_frms;
+       u64 rmac_vlan_frms;
+       u32 rmac_len_discard;
+       u32 rmac_fcs_discard;
+       u32 rmac_pf_discard;
+       u32 rmac_da_discard;
+       u32 rmac_red_discard;
+       u32 rmac_rts_discard;
+       u32 reserved_12;
+       u32 rmac_ingm_full_discard;
+       u32 reserved_13;
+       u32 rmac_accepted_ip_oflow;
+       u32 reserved_14;
+       u32 link_fault_cnt;
+       swStat_t sw_stat;
 } StatInfo_t;
 
-/* Structures representing different init time configuration
+/*
+ * Structures representing different init time configuration
  * parameters of the NIC.
  */
 
+#define MAX_TX_FIFOS 8
+#define MAX_RX_RINGS 8
+
+/* FIFO mappings for all possible number of fifos configured */
+int fifo_map[][MAX_TX_FIFOS] = {
+       {0, 0, 0, 0, 0, 0, 0, 0},
+       {0, 0, 0, 0, 1, 1, 1, 1},
+       {0, 0, 0, 1, 1, 1, 2, 2},
+       {0, 0, 1, 1, 2, 2, 3, 3},
+       {0, 0, 1, 1, 2, 2, 3, 4},
+       {0, 0, 1, 1, 2, 3, 4, 5},
+       {0, 0, 1, 2, 3, 4, 5, 6},
+       {0, 1, 2, 3, 4, 5, 6, 7},
+};
+
 /* Maintains Per FIFO related information. */
 typedef struct tx_fifo_config {
 #define        MAX_AVAILABLE_TXDS      8192
@@ -237,14 +324,14 @@ typedef struct rx_ring_config {
 #define NO_SNOOP_RXD_BUFFER         0x02
 } rx_ring_config_t;
 
-/* This structure provides contains values of the tunable parameters 
- * of the H/W 
+/* This structure provides contains values of the tunable parameters
+ * of the H/W
  */
 struct config_param {
 /* Tx Side */
        u32 tx_fifo_num;        /*Number of Tx FIFOs */
-#define MAX_TX_FIFOS 8
 
+       u8 fifo_mapping[MAX_TX_FIFOS];
        tx_fifo_config_t tx_cfg[MAX_TX_FIFOS];  /*Per-Tx FIFO config */
        u32 max_txds;           /*Max no. of Tx buffer descriptor per TxDL */
        u64 tx_intr_type;
@@ -252,10 +339,10 @@ struct config_param {
 
 /* Rx Side */
        u32 rx_ring_num;        /*Number of receive rings */
-#define MAX_RX_RINGS 8
 #define MAX_RX_BLOCKS_PER_RING  150
 
        rx_ring_config_t rx_cfg[MAX_RX_RINGS];  /*Per-Rx Ring config */
+       u8 bimodal;             /*Flag for setting bimodal interrupts*/
 
 #define HEADER_ETHERNET_II_802_3_SIZE 14
 #define HEADER_802_2_SIZE              3
@@ -269,6 +356,7 @@ struct config_param {
 #define MAX_PYLD_JUMBO              9600
 #define MAX_MTU_JUMBO               (MAX_PYLD_JUMBO+18)
 #define MAX_MTU_JUMBO_VLAN          (MAX_PYLD_JUMBO+22)
+       u16 bus_speed;
 };
 
 /* Structure representing MAC Addrs */
@@ -277,7 +365,7 @@ typedef struct mac_addr {
 } macaddr_t;
 
 /* Structure that represent every FIFO element in the BAR1
- * Address location. 
+ * Address location.
  */
 typedef struct _TxFIFO_element {
        u64 TxDL_Pointer;
@@ -339,6 +427,7 @@ typedef struct _RxD_t {
 #define RXD_FRAME_PROTO         vBIT(0xFFFF,24,8)
 #define RXD_FRAME_PROTO_IPV4    BIT(27)
 #define RXD_FRAME_PROTO_IPV6    BIT(28)
+#define RXD_FRAME_IP_FRAG      BIT(29)
 #define RXD_FRAME_PROTO_TCP     BIT(30)
 #define RXD_FRAME_PROTO_UDP     BIT(31)
 #define TCP_OR_UDP_FRAME        (RXD_FRAME_PROTO_TCP | RXD_FRAME_PROTO_UDP)
@@ -346,11 +435,15 @@ typedef struct _RxD_t {
 #define RXD_GET_L4_CKSUM(val)   ((u16)(val) & 0xFFFF)
 
        u64 Control_2;
+#define        THE_RXD_MARK            0x3
+#define        SET_RXD_MARKER          vBIT(THE_RXD_MARK, 0, 2)
+#define        GET_RXD_MARKER(ctrl)    ((ctrl & SET_RXD_MARKER) >> 62)
+
 #ifndef CONFIG_2BUFF_MODE
-#define MASK_BUFFER0_SIZE       vBIT(0xFFFF,0,16)
-#define SET_BUFFER0_SIZE(val)   vBIT(val,0,16)
+#define MASK_BUFFER0_SIZE       vBIT(0x3FFF,2,14)
+#define SET_BUFFER0_SIZE(val)   vBIT(val,2,14)
 #else
-#define MASK_BUFFER0_SIZE       vBIT(0xFF,0,16)
+#define MASK_BUFFER0_SIZE       vBIT(0xFF,2,14)
 #define MASK_BUFFER1_SIZE       vBIT(0xFFFF,16,16)
 #define MASK_BUFFER2_SIZE       vBIT(0xFFFF,32,16)
 #define SET_BUFFER0_SIZE(val)   vBIT(val,8,8)
@@ -363,7 +456,7 @@ typedef struct _RxD_t {
 #define SET_NUM_TAG(val)       vBIT(val,16,32)
 
 #ifndef CONFIG_2BUFF_MODE
-#define RXD_GET_BUFFER0_SIZE(Control_2) (u64)((Control_2 & vBIT(0xFFFF,0,16)))
+#define RXD_GET_BUFFER0_SIZE(Control_2) (u64)((Control_2 & vBIT(0x3FFF,2,14)))
 #else
 #define RXD_GET_BUFFER0_SIZE(Control_2) (u8)((Control_2 & MASK_BUFFER0_SIZE) \
                                                        >> 48)
@@ -382,7 +475,7 @@ typedef struct _RxD_t {
 #endif
 } RxD_t;
 
-/* Structure that represents the Rx descriptor block which contains 
+/* Structure that represents the Rx descriptor block which contains
  * 128 Rx descriptors.
  */
 #ifndef CONFIG_2BUFF_MODE
@@ -392,11 +485,11 @@ typedef struct _RxD_block {
 
        u64 reserved_0;
 #define END_OF_BLOCK    0xFEFFFFFFFFFFFFFFULL
-       u64 reserved_1;         /* 0xFEFFFFFFFFFFFFFF to mark last 
+       u64 reserved_1;         /* 0xFEFFFFFFFFFFFFFF to mark last
                                 * Rxd in this blk */
        u64 reserved_2_pNext_RxD_block; /* Logical ptr to next */
        u64 pNext_RxD_Blk_physical;     /* Buff0_ptr.In a 32 bit arch
-                                        * the upper 32 bits should 
+                                        * the upper 32 bits should
                                         * be 0 */
 } RxD_block_t;
 #else
@@ -405,13 +498,13 @@ typedef struct _RxD_block {
        RxD_t rxd[MAX_RXDS_PER_BLOCK];
 
 #define END_OF_BLOCK    0xFEFFFFFFFFFFFFFFULL
-       u64 reserved_1;         /* 0xFEFFFFFFFFFFFFFF to mark last Rxd 
+       u64 reserved_1;         /* 0xFEFFFFFFFFFFFFFF to mark last Rxd
                                 * in this blk */
        u64 pNext_RxD_Blk_physical;     /* Phy ponter to next blk. */
 } RxD_block_t;
 #define SIZE_OF_BLOCK  4096
 
-/* Structure to hold virtual addresses of Buf0 and Buf1 in 
+/* Structure to hold virtual addresses of Buf0 and Buf1 in
  * 2buf mode. */
 typedef struct bufAdd {
        void *ba_0_org;
@@ -423,8 +516,8 @@ typedef struct bufAdd {
 
 /* Structure which stores all the MAC control parameters */
 
-/* This structure stores the offset of the RxD in the ring 
- * from which the Rx Interrupt processor can start picking 
+/* This structure stores the offset of the RxD in the ring
+ * from which the Rx Interrupt processor can start picking
  * up the RxDs for processing.
  */
 typedef struct _rx_curr_get_info_t {
@@ -436,7 +529,7 @@ typedef struct _rx_curr_get_info_t {
 typedef rx_curr_get_info_t rx_curr_put_info_t;
 
 /* This structure stores the offset of the TxDl in the FIFO
- * from which the Tx Interrupt processor can start picking 
+ * from which the Tx Interrupt processor can start picking
  * up the TxDLs for send complete interrupt processing.
  */
 typedef struct {
@@ -446,32 +539,99 @@ typedef struct {
 
 typedef tx_curr_get_info_t tx_curr_put_info_t;
 
-/* Infomation related to the Tx and Rx FIFOs and Rings of Xena
- * is maintained in this structure.
- */
-typedef struct mac_info {
-/* rx side stuff */
-       /* Put pointer info which indictes which RxD has to be replenished 
+/* Structure that holds the Phy and virt addresses of the Blocks */
+typedef struct rx_block_info {
+       RxD_t *block_virt_addr;
+       dma_addr_t block_dma_addr;
+} rx_block_info_t;
+
+/* pre declaration of the nic structure */
+typedef struct s2io_nic nic_t;
+
+/* Ring specific structure */
+typedef struct ring_info {
+       /* The ring number */
+       int ring_no;
+
+       /*
+        *  Place holders for the virtual and physical addresses of
+        *  all the Rx Blocks
+        */
+       rx_block_info_t rx_blocks[MAX_RX_BLOCKS_PER_RING];
+       int block_count;
+       int pkt_cnt;
+
+       /*
+        * Put pointer info which indictes which RxD has to be replenished
         * with a new buffer.
         */
-       rx_curr_put_info_t rx_curr_put_info[MAX_RX_RINGS];
+       rx_curr_put_info_t rx_curr_put_info;
 
-       /* Get pointer info which indictes which is the last RxD that was 
+       /*
+        * Get pointer info which indictes which is the last RxD that was
         * processed by the driver.
         */
-       rx_curr_get_info_t rx_curr_get_info[MAX_RX_RINGS];
+       rx_curr_get_info_t rx_curr_get_info;
 
-       u16 rmac_pause_time;
-       u16 mc_pause_threshold_q0q3;
-       u16 mc_pause_threshold_q4q7;
+#ifndef CONFIG_S2IO_NAPI
+       /* Index to the absolute position of the put pointer of Rx ring */
+       int put_pos;
+#endif
+
+#ifdef CONFIG_2BUFF_MODE
+       /* Buffer Address store. */
+       buffAdd_t **ba;
+#endif
+       nic_t *nic;
+} ring_info_t;
 
+/* Fifo specific structure */
+typedef struct fifo_info {
+       /* FIFO number */
+       int fifo_no;
+
+       /* Maximum TxDs per TxDL */
+       int max_txds;
+
+       /* Place holder of all the TX List's Phy and Virt addresses. */
+       list_info_hold_t *list_info;
+
+       /*
+        * Current offset within the tx FIFO where driver would write
+        * new Tx frame
+        */
+       tx_curr_put_info_t tx_curr_put_info;
+
+       /*
+        * Current offset within tx FIFO from where the driver would start freeing
+        * the buffers
+        */
+       tx_curr_get_info_t tx_curr_get_info;
+
+       nic_t *nic;
+}fifo_info_t;
+
+/* Infomation related to the Tx and Rx FIFOs and Rings of Xena
+ * is maintained in this structure.
+ */
+typedef struct mac_info {
 /* tx side stuff */
        /* logical pointer of start of each Tx FIFO */
        TxFIFO_element_t __iomem *tx_FIFO_start[MAX_TX_FIFOS];
 
-/* Current offset within tx_FIFO_start, where driver would write new Tx frame*/
-       tx_curr_put_info_t tx_curr_put_info[MAX_TX_FIFOS];
-       tx_curr_get_info_t tx_curr_get_info[MAX_TX_FIFOS];
+       /* Fifo specific structure */
+       fifo_info_t fifos[MAX_TX_FIFOS];
+
+       /* Save virtual address of TxD page with zero DMA addr(if any) */
+       void *zerodma_virt_addr;
+
+/* rx side stuff */
+       /* Ring specific structure */
+       ring_info_t rings[MAX_RX_RINGS];
+
+       u16 rmac_pause_time;
+       u16 mc_pause_threshold_q0q3;
+       u16 mc_pause_threshold_q4q7;
 
        void *stats_mem;        /* orignal pointer to allocated mem */
        dma_addr_t stats_mem_phy;       /* Physical address of the stat block */
@@ -485,12 +645,6 @@ typedef struct {
        int usage_cnt;
 } usr_addr_t;
 
-/* Structure that holds the Phy and virt addresses of the Blocks */
-typedef struct rx_block_info {
-       RxD_t *block_virt_addr;
-       dma_addr_t block_dma_addr;
-} rx_block_info_t;
-
 /* Default Tunable parameters of the NIC. */
 #define DEFAULT_FIFO_LEN 4096
 #define SMALL_RXD_CNT  30 * (MAX_RXDS_PER_BLOCK+1)
@@ -499,7 +653,20 @@ typedef struct rx_block_info {
 #define LARGE_BLK_CNT  100
 
 /* Structure representing one instance of the NIC */
-typedef struct s2io_nic {
+struct s2io_nic {
+#ifdef CONFIG_S2IO_NAPI
+       /*
+        * Count of packets to be processed in a given iteration, it will be indicated
+        * by the quota field of the device structure when NAPI is enabled.
+        */
+       int pkts_to_process;
+#endif
+       struct net_device *dev;
+       mac_info_t mac_control;
+       struct config_param config;
+       struct pci_dev *pdev;
+       void __iomem *bar0;
+       void __iomem *bar1;
 #define MAX_MAC_SUPPORTED   16
 #define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED
 
@@ -507,33 +674,20 @@ typedef struct s2io_nic {
        macaddr_t pre_mac_addr[MAX_MAC_SUPPORTED];
 
        struct net_device_stats stats;
-       void __iomem *bar0;
-       void __iomem *bar1;
-       struct config_param config;
-       mac_info_t mac_control;
        int high_dma_flag;
        int device_close_flag;
        int device_enabled_once;
 
-       char name[32];
+       char name[50];
        struct tasklet_struct task;
        volatile unsigned long tasklet_status;
-       struct timer_list timer;
-       struct net_device *dev;
-       struct pci_dev *pdev;
 
-       u16 vendor_id;
-       u16 device_id;
-       u16 ccmd;
-       u32 cbar0_1;
-       u32 cbar0_2;
-       u32 cbar1_1;
-       u32 cbar1_2;
-       u32 cirq;
-       u8 cache_line;
-       u32 rom_expansion;
-       u16 pcix_cmd;
-       u32 irq;
+       /* Timer that handles I/O errors/exceptions */
+       struct timer_list alarm_timer;
+
+       /* Space to back up the PCI config space */
+       u32 config_space[256 / sizeof(u32)];
+
        atomic_t rx_bufs_left[MAX_RX_RINGS];
 
        spinlock_t tx_lock;
@@ -558,27 +712,11 @@ typedef struct s2io_nic {
        u16 tx_err_count;
        u16 rx_err_count;
 
-#ifndef CONFIG_S2IO_NAPI
-       /* Index to the absolute position of the put pointer of Rx ring. */
-       int put_pos[MAX_RX_RINGS];
-#endif
-
-       /*
-        *  Place holders for the virtual and physical addresses of 
-        *  all the Rx Blocks
-        */
-       rx_block_info_t rx_blocks[MAX_RX_RINGS][MAX_RX_BLOCKS_PER_RING];
-       int block_count[MAX_RX_RINGS];
-       int pkt_cnt[MAX_RX_RINGS];
-
-       /* Place holder of all the TX List's Phy and Virt addresses. */
-       list_info_hold_t *list_info[MAX_TX_FIFOS];
-
        /*  Id timer, used to blink NIC to physically identify NIC. */
        struct timer_list id_timer;
 
        /*  Restart timer, used to restart NIC if the device is stuck and
-        *  a schedule task that will set the correct Link state once the 
+        *  a schedule task that will set the correct Link state once the
         *  NIC's PHY has stabilized after a state change.
         */
 #ifdef INIT_TQUEUE
@@ -589,12 +727,12 @@ typedef struct s2io_nic {
        struct work_struct set_link_task;
 #endif
 
-       /* Flag that can be used to turn on or turn off the Rx checksum 
+       /* Flag that can be used to turn on or turn off the Rx checksum
         * offload feature.
         */
        int rx_csum;
 
-       /*  after blink, the adapter must be restored with original 
+       /*  after blink, the adapter must be restored with original
         *  values.
         */
        u64 adapt_ctrl_org;
@@ -604,16 +742,19 @@ typedef struct s2io_nic {
 #define        LINK_DOWN       1
 #define        LINK_UP         2
 
-#ifdef CONFIG_2BUFF_MODE
-       /* Buffer Address store. */
-       buffAdd_t **ba[MAX_RX_RINGS];
-#endif
        int task_flag;
 #define CARD_DOWN 1
 #define CARD_UP 2
        atomic_t card_state;
        volatile unsigned long link_state;
-} nic_t;
+       struct vlan_group *vlgrp;
+#define XFRAME_I_DEVICE                1
+#define XFRAME_II_DEVICE       2
+       u8 device_type;
+
+       spinlock_t      rx_lock;
+       atomic_t        isr_cnt;
+};
 
 #define RESET_ERROR 1;
 #define CMD_ERROR   2;
@@ -622,7 +763,8 @@ typedef struct s2io_nic {
 #ifndef readq
 static inline u64 readq(void __iomem *addr)
 {
-       u64 ret = readl(addr + 4);
+       u64 ret = 0;
+       ret = readl(addr + 4);
        ret <<= 32;
        ret |= readl(addr);
 
@@ -637,10 +779,10 @@ static inline void writeq(u64 val, void __iomem *addr)
        writel((u32) (val >> 32), (addr + 4));
 }
 
-/* In 32 bit modes, some registers have to be written in a 
+/* In 32 bit modes, some registers have to be written in a
  * particular order to expect correct hardware operation. The
- * macro SPECIAL_REG_WRITE is used to perform such ordered 
- * writes. Defines UF (Upper First) and LF (Lower First) will 
+ * macro SPECIAL_REG_WRITE is used to perform such ordered
+ * writes. Defines UF (Upper First) and LF (Lower First) will
  * be used to specify the required write order.
  */
 #define UF     1
@@ -716,6 +858,7 @@ static inline void SPECIAL_REG_WRITE(u64 val, void __iomem *addr, int order)
 #define        PCC_FB_ECC_ERR     vBIT(0xff, 16, 8)    /* Interrupt to indicate
                                                   PCC_FB_ECC Error. */
 
+#define RXD_GET_VLAN_TAG(Control_2) (u16)(Control_2 & MASK_VLAN_TAG)
 /*
  * Prototype declaration.
  */
@@ -725,36 +868,30 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev);
 static int init_shared_mem(struct s2io_nic *sp);
 static void free_shared_mem(struct s2io_nic *sp);
 static int init_nic(struct s2io_nic *nic);
-#ifndef CONFIG_S2IO_NAPI
-static void rx_intr_handler(struct s2io_nic *sp);
-#endif
-static void tx_intr_handler(struct s2io_nic *sp);
+static void rx_intr_handler(ring_info_t *ring_data);
+static void tx_intr_handler(fifo_info_t *fifo_data);
 static void alarm_intr_handler(struct s2io_nic *sp);
 
 static int s2io_starter(void);
-static void s2io_closer(void);
+void s2io_closer(void);
 static void s2io_tx_watchdog(struct net_device *dev);
 static void s2io_tasklet(unsigned long dev_addr);
 static void s2io_set_multicast(struct net_device *dev);
-#ifndef CONFIG_2BUFF_MODE
-static int rx_osm_handler(nic_t * sp, u16 len, RxD_t * rxdp, int ring_no);
-#else
-static int rx_osm_handler(nic_t * sp, RxD_t * rxdp, int ring_no,
-                         buffAdd_t * ba);
-#endif
-static void s2io_link(nic_t * sp, int link);
-static void s2io_reset(nic_t * sp);
-#ifdef CONFIG_S2IO_NAPI
+static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp);
+void s2io_link(nic_t * sp, int link);
+void s2io_reset(nic_t * sp);
+#if defined(CONFIG_S2IO_NAPI)
 static int s2io_poll(struct net_device *dev, int *budget);
 #endif
 static void s2io_init_pci(nic_t * sp);
-static int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
+int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
+static void s2io_alarm_handle(unsigned long data);
 static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs);
-static int verify_xena_quiescence(u64 val64, int flag);
+static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag);
 static struct ethtool_ops netdev_ethtool_ops;
 static void s2io_set_link(unsigned long data);
-static int s2io_set_swapper(nic_t * sp);
-static void s2io_card_down(nic_t * nic);
-static int s2io_card_up(nic_t * nic);
-
+int s2io_set_swapper(nic_t * sp);
+static void s2io_card_down(nic_t *nic);
+static int s2io_card_up(nic_t *nic);
+int get_xena_rev_id(struct pci_dev *pdev);
 #endif                         /* _S2IO_H */
index 3ad0b6751f6fb3c432ea883d8f753b7831a5c8e4..221354eea21f9a9257771e68074821ea7ea64c2f 100644 (file)
@@ -156,52 +156,6 @@ static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
         
        SHAPERCB(skb)->shapelen= shaper_clocks(shaper,skb);
        
-#ifdef SHAPER_COMPLEX /* and broken.. */
-
-       while(ptr && ptr!=(struct sk_buff *)&shaper->sendq)
-       {
-               if(ptr->pri<skb->pri 
-                       && jiffies - SHAPERCB(ptr)->shapeclock < SHAPER_MAXSLIP)
-               {
-                       struct sk_buff *tmp=ptr->prev;
-
-                       /*
-                        *      It goes before us therefore we slip the length
-                        *      of the new frame.
-                        */
-
-                       SHAPERCB(ptr)->shapeclock+=SHAPERCB(skb)->shapelen;
-                       SHAPERCB(ptr)->shapelatency+=SHAPERCB(skb)->shapelen;
-
-                       /*
-                        *      The packet may have slipped so far back it
-                        *      fell off.
-                        */
-                       if(SHAPERCB(ptr)->shapelatency > SHAPER_LATENCY)
-                       {
-                               skb_unlink(ptr);
-                               dev_kfree_skb(ptr);
-                       }
-                       ptr=tmp;
-               }
-               else
-                       break;
-       }
-       if(ptr==NULL || ptr==(struct sk_buff *)&shaper->sendq)
-               skb_queue_head(&shaper->sendq,skb);
-       else
-       {
-               struct sk_buff *tmp;
-               /*
-                *      Set the packet clock out time according to the
-                *      frames ahead. Im sure a bit of thought could drop
-                *      this loop.
-                */
-               for(tmp=skb_peek(&shaper->sendq); tmp!=NULL && tmp!=ptr; tmp=tmp->next)
-                       SHAPERCB(skb)->shapeclock+=tmp->shapelen;
-               skb_append(ptr,skb);
-       }
-#else
        {
                struct sk_buff *tmp;
                /*
@@ -220,7 +174,7 @@ static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
                } else
                        skb_queue_tail(&shaper->sendq, skb);
        }
-#endif         
+
        if(sh_debug)
                printk("Frame queued.\n");
        if(skb_queue_len(&shaper->sendq)>SHAPER_QLEN)
@@ -302,7 +256,7 @@ static void shaper_kick(struct shaper *shaper)
                         *      Pull the frame and get interrupts back on.
                         */
                         
-                       skb_unlink(skb);
+                       skb_unlink(skb, &shaper->sendq);
                        if (shaper->recovery < 
                            SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen)
                                shaper->recovery = SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen;
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
new file mode 100644 (file)
index 0000000..92f7552
--- /dev/null
@@ -0,0 +1,1884 @@
+/*
+   sis190.c: Silicon Integrated Systems SiS190 ethernet driver
+
+   Copyright (c) 2003 K.M. Liu <kmliu@sis.com>
+   Copyright (c) 2003, 2004 Jeff Garzik <jgarzik@pobox.com>
+   Copyright (c) 2003, 2004, 2005 Francois Romieu <romieu@fr.zoreil.com>
+
+   Based on r8169.c, tg3.c, 8139cp.c, skge.c, epic100.c and SiS 190/191
+   genuine driver.
+
+   This software may be used and distributed according to the terms of
+   the GNU General Public License (GPL), incorporated herein by reference.
+   Drivers based on or derived from this code fall under the GPL and must
+   retain the authorship, copyright and license notice.  This file is not
+   a complete program and may only be used when the entire operating
+   system is licensed under the GPL.
+
+   See the file COPYING in this distribution for more information.
+
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/pci.h>
+#include <linux/mii.h>
+#include <linux/delay.h>
+#include <linux/crc32.h>
+#include <linux/dma-mapping.h>
+#include <asm/irq.h>
+
+#define net_drv(p, arg...)     if (netif_msg_drv(p)) \
+                                       printk(arg)
+#define net_probe(p, arg...)   if (netif_msg_probe(p)) \
+                                       printk(arg)
+#define net_link(p, arg...)    if (netif_msg_link(p)) \
+                                       printk(arg)
+#define net_intr(p, arg...)    if (netif_msg_intr(p)) \
+                                       printk(arg)
+#define net_tx_err(p, arg...)  if (netif_msg_tx_err(p)) \
+                                       printk(arg)
+
+#define PHY_MAX_ADDR           32
+#define PHY_ID_ANY             0x1f
+#define MII_REG_ANY            0x1f
+
+#ifdef CONFIG_SIS190_NAPI
+#define NAPI_SUFFIX    "-NAPI"
+#else
+#define NAPI_SUFFIX    ""
+#endif
+
+#define DRV_VERSION            "1.2" NAPI_SUFFIX
+#define DRV_NAME               "sis190"
+#define SIS190_DRIVER_NAME     DRV_NAME " Gigabit Ethernet driver " DRV_VERSION
+#define PFX DRV_NAME ": "
+
+#ifdef CONFIG_SIS190_NAPI
+#define sis190_rx_skb                  netif_receive_skb
+#define sis190_rx_quota(count, quota)  min(count, quota)
+#else
+#define sis190_rx_skb                  netif_rx
+#define sis190_rx_quota(count, quota)  count
+#endif
+
+#define MAC_ADDR_LEN           6
+
+#define NUM_TX_DESC            64      /* [8..1024] */
+#define NUM_RX_DESC            64      /* [8..8192] */
+#define TX_RING_BYTES          (NUM_TX_DESC * sizeof(struct TxDesc))
+#define RX_RING_BYTES          (NUM_RX_DESC * sizeof(struct RxDesc))
+#define RX_BUF_SIZE            1536
+#define RX_BUF_MASK            0xfff8
+
+#define SIS190_REGS_SIZE       0x80
+#define SIS190_TX_TIMEOUT      (6*HZ)
+#define SIS190_PHY_TIMEOUT     (10*HZ)
+#define SIS190_MSG_DEFAULT     (NETIF_MSG_DRV | NETIF_MSG_PROBE | \
+                                NETIF_MSG_LINK | NETIF_MSG_IFUP | \
+                                NETIF_MSG_IFDOWN)
+
+/* Enhanced PHY access register bit definitions */
+#define EhnMIIread             0x0000
+#define EhnMIIwrite            0x0020
+#define EhnMIIdataShift                16
+#define EhnMIIpmdShift         6       /* 7016 only */
+#define EhnMIIregShift         11
+#define EhnMIIreq              0x0010
+#define EhnMIInotDone          0x0010
+
+/* Write/read MMIO register */
+#define SIS_W8(reg, val)       writeb ((val), ioaddr + (reg))
+#define SIS_W16(reg, val)      writew ((val), ioaddr + (reg))
+#define SIS_W32(reg, val)      writel ((val), ioaddr + (reg))
+#define SIS_R8(reg)            readb (ioaddr + (reg))
+#define SIS_R16(reg)           readw (ioaddr + (reg))
+#define SIS_R32(reg)           readl (ioaddr + (reg))
+
+#define SIS_PCI_COMMIT()       SIS_R32(IntrControl)
+
+enum sis190_registers {
+       TxControl               = 0x00,
+       TxDescStartAddr         = 0x04,
+       rsv0                    = 0x08, // reserved
+       TxSts                   = 0x0c, // unused (Control/Status)
+       RxControl               = 0x10,
+       RxDescStartAddr         = 0x14,
+       rsv1                    = 0x18, // reserved
+       RxSts                   = 0x1c, // unused
+       IntrStatus              = 0x20,
+       IntrMask                = 0x24,
+       IntrControl             = 0x28,
+       IntrTimer               = 0x2c, // unused (Interupt Timer)
+       PMControl               = 0x30, // unused (Power Mgmt Control/Status)
+       rsv2                    = 0x34, // reserved
+       ROMControl              = 0x38,
+       ROMInterface            = 0x3c,
+       StationControl          = 0x40,
+       GMIIControl             = 0x44,
+       GIoCR                   = 0x48, // unused (GMAC IO Compensation)
+       GIoCtrl                 = 0x4c, // unused (GMAC IO Control)
+       TxMacControl            = 0x50,
+       TxLimit                 = 0x54, // unused (Tx MAC Timer/TryLimit)
+       RGDelay                 = 0x58, // unused (RGMII Tx Internal Delay)
+       rsv3                    = 0x5c, // reserved
+       RxMacControl            = 0x60,
+       RxMacAddr               = 0x62,
+       RxHashTable             = 0x68,
+       // Undocumented         = 0x6c,
+       RxWolCtrl               = 0x70,
+       RxWolData               = 0x74, // unused (Rx WOL Data Access)
+       RxMPSControl            = 0x78, // unused (Rx MPS Control)
+       rsv4                    = 0x7c, // reserved
+};
+
+enum sis190_register_content {
+       /* IntrStatus */
+       SoftInt                 = 0x40000000,   // unused
+       Timeup                  = 0x20000000,   // unused
+       PauseFrame              = 0x00080000,   // unused
+       MagicPacket             = 0x00040000,   // unused
+       WakeupFrame             = 0x00020000,   // unused
+       LinkChange              = 0x00010000,
+       RxQEmpty                = 0x00000080,
+       RxQInt                  = 0x00000040,
+       TxQ1Empty               = 0x00000020,   // unused
+       TxQ1Int                 = 0x00000010,
+       TxQ0Empty               = 0x00000008,   // unused
+       TxQ0Int                 = 0x00000004,
+       RxHalt                  = 0x00000002,
+       TxHalt                  = 0x00000001,
+
+       /* {Rx/Tx}CmdBits */
+       CmdReset                = 0x10,
+       CmdRxEnb                = 0x08,         // unused
+       CmdTxEnb                = 0x01,
+       RxBufEmpty              = 0x01,         // unused
+
+       /* Cfg9346Bits */
+       Cfg9346_Lock            = 0x00,         // unused
+       Cfg9346_Unlock          = 0xc0,         // unused
+
+       /* RxMacControl */
+       AcceptErr               = 0x20,         // unused
+       AcceptRunt              = 0x10,         // unused
+       AcceptBroadcast         = 0x0800,
+       AcceptMulticast         = 0x0400,
+       AcceptMyPhys            = 0x0200,
+       AcceptAllPhys           = 0x0100,
+
+       /* RxConfigBits */
+       RxCfgFIFOShift          = 13,
+       RxCfgDMAShift           = 8,            // 0x1a in RxControl ?
+
+       /* TxConfigBits */
+       TxInterFrameGapShift    = 24,
+       TxDMAShift              = 8, /* DMA burst value (0-7) is shift this many bits */
+
+       LinkStatus              = 0x02,         // unused
+       FullDup                 = 0x01,         // unused
+
+       /* TBICSRBit */
+       TBILinkOK               = 0x02000000,   // unused
+};
+
+struct TxDesc {
+       __le32 PSize;
+       __le32 status;
+       __le32 addr;
+       __le32 size;
+};
+
+struct RxDesc {
+       __le32 PSize;
+       __le32 status;
+       __le32 addr;
+       __le32 size;
+};
+
+enum _DescStatusBit {
+       /* _Desc.status */
+       OWNbit          = 0x80000000, // RXOWN/TXOWN
+       INTbit          = 0x40000000, // RXINT/TXINT
+       CRCbit          = 0x00020000, // CRCOFF/CRCEN
+       PADbit          = 0x00010000, // PREADD/PADEN
+       /* _Desc.size */
+       RingEnd         = 0x80000000,
+       /* TxDesc.status */
+       LSEN            = 0x08000000, // TSO ? -- FR
+       IPCS            = 0x04000000,
+       TCPCS           = 0x02000000,
+       UDPCS           = 0x01000000,
+       BSTEN           = 0x00800000,
+       EXTEN           = 0x00400000,
+       DEFEN           = 0x00200000,
+       BKFEN           = 0x00100000,
+       CRSEN           = 0x00080000,
+       COLEN           = 0x00040000,
+       THOL3           = 0x30000000,
+       THOL2           = 0x20000000,
+       THOL1           = 0x10000000,
+       THOL0           = 0x00000000,
+       /* RxDesc.status */
+       IPON            = 0x20000000,
+       TCPON           = 0x10000000,
+       UDPON           = 0x08000000,
+       Wakup           = 0x00400000,
+       Magic           = 0x00200000,
+       Pause           = 0x00100000,
+       DEFbit          = 0x00200000,
+       BCAST           = 0x000c0000,
+       MCAST           = 0x00080000,
+       UCAST           = 0x00040000,
+       /* RxDesc.PSize */
+       TAGON           = 0x80000000,
+       RxDescCountMask = 0x7f000000, // multi-desc pkt when > 1 ? -- FR
+       ABORT           = 0x00800000,
+       SHORT           = 0x00400000,
+       LIMIT           = 0x00200000,
+       MIIER           = 0x00100000,
+       OVRUN           = 0x00080000,
+       NIBON           = 0x00040000,
+       COLON           = 0x00020000,
+       CRCOK           = 0x00010000,
+       RxSizeMask      = 0x0000ffff
+       /*
+        * The asic could apparently do vlan, TSO, jumbo (sis191 only) and
+        * provide two (unused with Linux) Tx queues. No publically
+        * available documentation alas.
+        */
+};
+
+enum sis190_eeprom_access_register_bits {
+       EECS    = 0x00000001,   // unused
+       EECLK   = 0x00000002,   // unused
+       EEDO    = 0x00000008,   // unused
+       EEDI    = 0x00000004,   // unused
+       EEREQ   = 0x00000080,
+       EEROP   = 0x00000200,
+       EEWOP   = 0x00000100    // unused
+};
+
+/* EEPROM Addresses */
+enum sis190_eeprom_address {
+       EEPROMSignature = 0x00,
+       EEPROMCLK       = 0x01, // unused
+       EEPROMInfo      = 0x02,
+       EEPROMMACAddr   = 0x03
+};
+
+enum sis190_feature {
+       F_HAS_RGMII     = 1,
+       F_PHY_88E1111   = 2,
+       F_PHY_BCM5461   = 4
+};
+
+struct sis190_private {
+       void __iomem *mmio_addr;
+       struct pci_dev *pci_dev;
+       struct net_device_stats stats;
+       spinlock_t lock;
+       u32 rx_buf_sz;
+       u32 cur_rx;
+       u32 cur_tx;
+       u32 dirty_rx;
+       u32 dirty_tx;
+       dma_addr_t rx_dma;
+       dma_addr_t tx_dma;
+       struct RxDesc *RxDescRing;
+       struct TxDesc *TxDescRing;
+       struct sk_buff *Rx_skbuff[NUM_RX_DESC];
+       struct sk_buff *Tx_skbuff[NUM_TX_DESC];
+       struct work_struct phy_task;
+       struct timer_list timer;
+       u32 msg_enable;
+       struct mii_if_info mii_if;
+       struct list_head first_phy;
+       u32 features;
+};
+
+struct sis190_phy {
+       struct list_head list;
+       int phy_id;
+       u16 id[2];
+       u16 status;
+       u8  type;
+};
+
+enum sis190_phy_type {
+       UNKNOWN = 0x00,
+       HOME    = 0x01,
+       LAN     = 0x02,
+       MIX     = 0x03
+};
+
+static struct mii_chip_info {
+        const char *name;
+        u16 id[2];
+        unsigned int type;
+       u32 feature;
+} mii_chip_table[] = {
+       { "Broadcom PHY BCM5461", { 0x0020, 0x60c0 }, LAN, F_PHY_BCM5461 },
+       { "Agere PHY ET1101B",    { 0x0282, 0xf010 }, LAN, 0 },
+       { "Marvell PHY 88E1111",  { 0x0141, 0x0cc0 }, LAN, F_PHY_88E1111 },
+       { "Realtek PHY RTL8201",  { 0x0000, 0x8200 }, LAN, 0 },
+       { NULL, }
+};
+
+const static struct {
+       const char *name;
+} sis_chip_info[] = {
+       { "SiS 190 PCI Fast Ethernet adapter" },
+       { "SiS 191 PCI Gigabit Ethernet adapter" },
+};
+
+static struct pci_device_id sis190_pci_tbl[] __devinitdata = {
+       { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0190), 0, 0, 0 },
+       { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0191), 0, 0, 1 },
+       { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, sis190_pci_tbl);
+
+static int rx_copybreak = 200;
+
+static struct {
+       u32 msg_enable;
+} debug = { -1 };
+
+MODULE_DESCRIPTION("SiS sis190 Gigabit Ethernet driver");
+module_param(rx_copybreak, int, 0);
+MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
+module_param_named(debug, debug.msg_enable, int, 0);
+MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)");
+MODULE_AUTHOR("K.M. Liu <kmliu@sis.com>, Ueimor <romieu@fr.zoreil.com>");
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+
+static const u32 sis190_intr_mask =
+       RxQEmpty | RxQInt | TxQ1Int | TxQ0Int | RxHalt | TxHalt | LinkChange;
+
+/*
+ * Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
+ * The chips use a 64 element hash table based on the Ethernet CRC.
+ */
+static int multicast_filter_limit = 32;
+
+static void __mdio_cmd(void __iomem *ioaddr, u32 ctl)
+{
+       unsigned int i;
+
+       SIS_W32(GMIIControl, ctl);
+
+       msleep(1);
+
+       for (i = 0; i < 100; i++) {
+               if (!(SIS_R32(GMIIControl) & EhnMIInotDone))
+                       break;
+               msleep(1);
+       }
+
+       if (i > 999)
+               printk(KERN_ERR PFX "PHY command failed !\n");
+}
+
+static void mdio_write(void __iomem *ioaddr, int phy_id, int reg, int val)
+{
+       __mdio_cmd(ioaddr, EhnMIIreq | EhnMIIwrite |
+               (((u32) reg) << EhnMIIregShift) | (phy_id << EhnMIIpmdShift) |
+               (((u32) val) << EhnMIIdataShift));
+}
+
+static int mdio_read(void __iomem *ioaddr, int phy_id, int reg)
+{
+       __mdio_cmd(ioaddr, EhnMIIreq | EhnMIIread |
+               (((u32) reg) << EhnMIIregShift) | (phy_id << EhnMIIpmdShift));
+
+       return (u16) (SIS_R32(GMIIControl) >> EhnMIIdataShift);
+}
+
+static void __mdio_write(struct net_device *dev, int phy_id, int reg, int val)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+
+       mdio_write(tp->mmio_addr, phy_id, reg, val);
+}
+
+static int __mdio_read(struct net_device *dev, int phy_id, int reg)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+
+       return mdio_read(tp->mmio_addr, phy_id, reg);
+}
+
+static u16 mdio_read_latched(void __iomem *ioaddr, int phy_id, int reg)
+{
+       mdio_read(ioaddr, phy_id, reg);
+       return mdio_read(ioaddr, phy_id, reg);
+}
+
+static u16 __devinit sis190_read_eeprom(void __iomem *ioaddr, u32 reg)
+{
+       u16 data = 0xffff;
+       unsigned int i;
+
+       if (!(SIS_R32(ROMControl) & 0x0002))
+               return 0;
+
+       SIS_W32(ROMInterface, EEREQ | EEROP | (reg << 10));
+
+       for (i = 0; i < 200; i++) {
+               if (!(SIS_R32(ROMInterface) & EEREQ)) {
+                       data = (SIS_R32(ROMInterface) & 0xffff0000) >> 16;
+                       break;
+               }
+               msleep(1);
+       }
+
+       return data;
+}
+
+static void sis190_irq_mask_and_ack(void __iomem *ioaddr)
+{
+       SIS_W32(IntrMask, 0x00);
+       SIS_W32(IntrStatus, 0xffffffff);
+       SIS_PCI_COMMIT();
+}
+
+static void sis190_asic_down(void __iomem *ioaddr)
+{
+       /* Stop the chip's Tx and Rx DMA processes. */
+
+       SIS_W32(TxControl, 0x1a00);
+       SIS_W32(RxControl, 0x1a00);
+
+       sis190_irq_mask_and_ack(ioaddr);
+}
+
+static void sis190_mark_as_last_descriptor(struct RxDesc *desc)
+{
+       desc->size |= cpu_to_le32(RingEnd);
+}
+
+static inline void sis190_give_to_asic(struct RxDesc *desc, u32 rx_buf_sz)
+{
+       u32 eor = le32_to_cpu(desc->size) & RingEnd;
+
+       desc->PSize = 0x0;
+       desc->size = cpu_to_le32((rx_buf_sz & RX_BUF_MASK) | eor);
+       wmb();
+       desc->status = cpu_to_le32(OWNbit | INTbit);
+}
+
+static inline void sis190_map_to_asic(struct RxDesc *desc, dma_addr_t mapping,
+                                     u32 rx_buf_sz)
+{
+       desc->addr = cpu_to_le32(mapping);
+       sis190_give_to_asic(desc, rx_buf_sz);
+}
+
+static inline void sis190_make_unusable_by_asic(struct RxDesc *desc)
+{
+       desc->PSize = 0x0;
+       desc->addr = 0xdeadbeef;
+       desc->size &= cpu_to_le32(RingEnd);
+       wmb();
+       desc->status = 0x0;
+}
+
+static int sis190_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
+                              struct RxDesc *desc, u32 rx_buf_sz)
+{
+       struct sk_buff *skb;
+       dma_addr_t mapping;
+       int ret = 0;
+
+       skb = dev_alloc_skb(rx_buf_sz);
+       if (!skb)
+               goto err_out;
+
+       *sk_buff = skb;
+
+       mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
+                                PCI_DMA_FROMDEVICE);
+
+       sis190_map_to_asic(desc, mapping, rx_buf_sz);
+out:
+       return ret;
+
+err_out:
+       ret = -ENOMEM;
+       sis190_make_unusable_by_asic(desc);
+       goto out;
+}
+
+static u32 sis190_rx_fill(struct sis190_private *tp, struct net_device *dev,
+                         u32 start, u32 end)
+{
+       u32 cur;
+
+       for (cur = start; cur < end; cur++) {
+               int ret, i = cur % NUM_RX_DESC;
+
+               if (tp->Rx_skbuff[i])
+                       continue;
+
+               ret = sis190_alloc_rx_skb(tp->pci_dev, tp->Rx_skbuff + i,
+                                         tp->RxDescRing + i, tp->rx_buf_sz);
+               if (ret < 0)
+                       break;
+       }
+       return cur - start;
+}
+
+static inline int sis190_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
+                                    struct RxDesc *desc, int rx_buf_sz)
+{
+       int ret = -1;
+
+       if (pkt_size < rx_copybreak) {
+               struct sk_buff *skb;
+
+               skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN);
+               if (skb) {
+                       skb_reserve(skb, NET_IP_ALIGN);
+                       eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0);
+                       *sk_buff = skb;
+                       sis190_give_to_asic(desc, rx_buf_sz);
+                       ret = 0;
+               }
+       }
+       return ret;
+}
+
+static inline int sis190_rx_pkt_err(u32 status, struct net_device_stats *stats)
+{
+#define ErrMask        (OVRUN | SHORT | LIMIT | MIIER | NIBON | COLON | ABORT)
+
+       if ((status & CRCOK) && !(status & ErrMask))
+               return 0;
+
+       if (!(status & CRCOK))
+               stats->rx_crc_errors++;
+       else if (status & OVRUN)
+               stats->rx_over_errors++;
+       else if (status & (SHORT | LIMIT))
+               stats->rx_length_errors++;
+       else if (status & (MIIER | NIBON | COLON))
+               stats->rx_frame_errors++;
+
+       stats->rx_errors++;
+       return -1;
+}
+
+static int sis190_rx_interrupt(struct net_device *dev,
+                              struct sis190_private *tp, void __iomem *ioaddr)
+{
+       struct net_device_stats *stats = &tp->stats;
+       u32 rx_left, cur_rx = tp->cur_rx;
+       u32 delta, count;
+
+       rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
+       rx_left = sis190_rx_quota(rx_left, (u32) dev->quota);
+
+       for (; rx_left > 0; rx_left--, cur_rx++) {
+               unsigned int entry = cur_rx % NUM_RX_DESC;
+               struct RxDesc *desc = tp->RxDescRing + entry;
+               u32 status;
+
+               if (desc->status & OWNbit)
+                       break;
+
+               status = le32_to_cpu(desc->PSize);
+
+               // net_intr(tp, KERN_INFO "%s: Rx PSize = %08x.\n", dev->name,
+               //       status);
+
+               if (sis190_rx_pkt_err(status, stats) < 0)
+                       sis190_give_to_asic(desc, tp->rx_buf_sz);
+               else {
+                       struct sk_buff *skb = tp->Rx_skbuff[entry];
+                       int pkt_size = (status & RxSizeMask) - 4;
+                       void (*pci_action)(struct pci_dev *, dma_addr_t,
+                               size_t, int) = pci_dma_sync_single_for_device;
+
+                       if (unlikely(pkt_size > tp->rx_buf_sz)) {
+                               net_intr(tp, KERN_INFO
+                                        "%s: (frag) status = %08x.\n",
+                                        dev->name, status);
+                               stats->rx_dropped++;
+                               stats->rx_length_errors++;
+                               sis190_give_to_asic(desc, tp->rx_buf_sz);
+                               continue;
+                       }
+
+                       pci_dma_sync_single_for_cpu(tp->pci_dev,
+                               le32_to_cpu(desc->addr), tp->rx_buf_sz,
+                               PCI_DMA_FROMDEVICE);
+
+                       if (sis190_try_rx_copy(&skb, pkt_size, desc,
+                                              tp->rx_buf_sz)) {
+                               pci_action = pci_unmap_single;
+                               tp->Rx_skbuff[entry] = NULL;
+                               sis190_make_unusable_by_asic(desc);
+                       }
+
+                       pci_action(tp->pci_dev, le32_to_cpu(desc->addr),
+                                  tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+
+                       skb->dev = dev;
+                       skb_put(skb, pkt_size);
+                       skb->protocol = eth_type_trans(skb, dev);
+
+                       sis190_rx_skb(skb);
+
+                       dev->last_rx = jiffies;
+                       stats->rx_packets++;
+                       stats->rx_bytes += pkt_size;
+                       if ((status & BCAST) == MCAST)
+                               stats->multicast++;
+               }
+       }
+       count = cur_rx - tp->cur_rx;
+       tp->cur_rx = cur_rx;
+
+       delta = sis190_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx);
+       if (!delta && count && netif_msg_intr(tp))
+               printk(KERN_INFO "%s: no Rx buffer allocated.\n", dev->name);
+       tp->dirty_rx += delta;
+
+       if (((tp->dirty_rx + NUM_RX_DESC) == tp->cur_rx) && netif_msg_intr(tp))
+               printk(KERN_EMERG "%s: Rx buffers exhausted.\n", dev->name);
+
+       return count;
+}
+
+static void sis190_unmap_tx_skb(struct pci_dev *pdev, struct sk_buff *skb,
+                               struct TxDesc *desc)
+{
+       unsigned int len;
+
+       len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
+
+       pci_unmap_single(pdev, le32_to_cpu(desc->addr), len, PCI_DMA_TODEVICE);
+
+       memset(desc, 0x00, sizeof(*desc));
+}
+
+static void sis190_tx_interrupt(struct net_device *dev,
+                               struct sis190_private *tp, void __iomem *ioaddr)
+{
+       u32 pending, dirty_tx = tp->dirty_tx;
+       /*
+        * It would not be needed if queueing was allowed to be enabled
+        * again too early (hint: think preempt and unclocked smp systems).
+        */
+       unsigned int queue_stopped;
+
+       smp_rmb();
+       pending = tp->cur_tx - dirty_tx;
+       queue_stopped = (pending == NUM_TX_DESC);
+
+       for (; pending; pending--, dirty_tx++) {
+               unsigned int entry = dirty_tx % NUM_TX_DESC;
+               struct TxDesc *txd = tp->TxDescRing + entry;
+               struct sk_buff *skb;
+
+               if (le32_to_cpu(txd->status) & OWNbit)
+                       break;
+
+               skb = tp->Tx_skbuff[entry];
+
+               tp->stats.tx_packets++;
+               tp->stats.tx_bytes += skb->len;
+
+               sis190_unmap_tx_skb(tp->pci_dev, skb, txd);
+               tp->Tx_skbuff[entry] = NULL;
+               dev_kfree_skb_irq(skb);
+       }
+
+       if (tp->dirty_tx != dirty_tx) {
+               tp->dirty_tx = dirty_tx;
+               smp_wmb();
+               if (queue_stopped)
+                       netif_wake_queue(dev);
+       }
+}
+
+/*
+ * The interrupt handler does all of the Rx thread work and cleans up after
+ * the Tx thread.
+ */
+static irqreturn_t sis190_interrupt(int irq, void *__dev, struct pt_regs *regs)
+{
+       struct net_device *dev = __dev;
+       struct sis190_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       unsigned int handled = 0;
+       u32 status;
+
+       status = SIS_R32(IntrStatus);
+
+       if ((status == 0xffffffff) || !status)
+               goto out;
+
+       handled = 1;
+
+       if (unlikely(!netif_running(dev))) {
+               sis190_asic_down(ioaddr);
+               goto out;
+       }
+
+       SIS_W32(IntrStatus, status);
+
+       // net_intr(tp, KERN_INFO "%s: status = %08x.\n", dev->name, status);
+
+       if (status & LinkChange) {
+               net_intr(tp, KERN_INFO "%s: link change.\n", dev->name);
+               schedule_work(&tp->phy_task);
+       }
+
+       if (status & RxQInt)
+               sis190_rx_interrupt(dev, tp, ioaddr);
+
+       if (status & TxQ0Int)
+               sis190_tx_interrupt(dev, tp, ioaddr);
+out:
+       return IRQ_RETVAL(handled);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void sis190_netpoll(struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+       struct pci_dev *pdev = tp->pci_dev;
+
+       disable_irq(pdev->irq);
+       sis190_interrupt(pdev->irq, dev, NULL);
+       enable_irq(pdev->irq);
+}
+#endif
+
+static void sis190_free_rx_skb(struct sis190_private *tp,
+                              struct sk_buff **sk_buff, struct RxDesc *desc)
+{
+       struct pci_dev *pdev = tp->pci_dev;
+
+       pci_unmap_single(pdev, le32_to_cpu(desc->addr), tp->rx_buf_sz,
+                        PCI_DMA_FROMDEVICE);
+       dev_kfree_skb(*sk_buff);
+       *sk_buff = NULL;
+       sis190_make_unusable_by_asic(desc);
+}
+
+static void sis190_rx_clear(struct sis190_private *tp)
+{
+       unsigned int i;
+
+       for (i = 0; i < NUM_RX_DESC; i++) {
+               if (!tp->Rx_skbuff[i])
+                       continue;
+               sis190_free_rx_skb(tp, tp->Rx_skbuff + i, tp->RxDescRing + i);
+       }
+}
+
+static void sis190_init_ring_indexes(struct sis190_private *tp)
+{
+       tp->dirty_tx = tp->dirty_rx = tp->cur_tx = tp->cur_rx = 0;
+}
+
+static int sis190_init_ring(struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+
+       sis190_init_ring_indexes(tp);
+
+       memset(tp->Tx_skbuff, 0x0, NUM_TX_DESC * sizeof(struct sk_buff *));
+       memset(tp->Rx_skbuff, 0x0, NUM_RX_DESC * sizeof(struct sk_buff *));
+
+       if (sis190_rx_fill(tp, dev, 0, NUM_RX_DESC) != NUM_RX_DESC)
+               goto err_rx_clear;
+
+       sis190_mark_as_last_descriptor(tp->RxDescRing + NUM_RX_DESC - 1);
+
+       return 0;
+
+err_rx_clear:
+       sis190_rx_clear(tp);
+       return -ENOMEM;
+}
+
+static void sis190_set_rx_mode(struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       unsigned long flags;
+       u32 mc_filter[2];       /* Multicast hash filter */
+       u16 rx_mode;
+
+       if (dev->flags & IFF_PROMISC) {
+               /* Unconditionally log net taps. */
+               net_drv(tp, KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+                       dev->name);
+               rx_mode =
+                       AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+                       AcceptAllPhys;
+               mc_filter[1] = mc_filter[0] = 0xffffffff;
+       } else if ((dev->mc_count > multicast_filter_limit) ||
+                  (dev->flags & IFF_ALLMULTI)) {
+               /* Too many to filter perfectly -- accept all multicasts. */
+               rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+               mc_filter[1] = mc_filter[0] = 0xffffffff;
+       } else {
+               struct dev_mc_list *mclist;
+               unsigned int i;
+
+               rx_mode = AcceptBroadcast | AcceptMyPhys;
+               mc_filter[1] = mc_filter[0] = 0;
+               for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+                    i++, mclist = mclist->next) {
+                       int bit_nr =
+                               ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+                       mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+                       rx_mode |= AcceptMulticast;
+               }
+       }
+
+       spin_lock_irqsave(&tp->lock, flags);
+
+       SIS_W16(RxMacControl, rx_mode | 0x2);
+       SIS_W32(RxHashTable, mc_filter[0]);
+       SIS_W32(RxHashTable + 4, mc_filter[1]);
+
+       spin_unlock_irqrestore(&tp->lock, flags);
+}
+
+static void sis190_soft_reset(void __iomem *ioaddr)
+{
+       SIS_W32(IntrControl, 0x8000);
+       SIS_PCI_COMMIT();
+       msleep(1);
+       SIS_W32(IntrControl, 0x0);
+       sis190_asic_down(ioaddr);
+       msleep(1);
+}
+
+static void sis190_hw_start(struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+
+       sis190_soft_reset(ioaddr);
+
+       SIS_W32(TxDescStartAddr, tp->tx_dma);
+       SIS_W32(RxDescStartAddr, tp->rx_dma);
+
+       SIS_W32(IntrStatus, 0xffffffff);
+       SIS_W32(IntrMask, 0x0);
+       SIS_W32(GMIIControl, 0x0);
+       SIS_W32(TxMacControl, 0x60);
+       SIS_W16(RxMacControl, 0x02);
+       SIS_W32(RxHashTable, 0x0);
+       SIS_W32(0x6c, 0x0);
+       SIS_W32(RxWolCtrl, 0x0);
+       SIS_W32(RxWolData, 0x0);
+
+       SIS_PCI_COMMIT();
+
+       sis190_set_rx_mode(dev);
+
+       /* Enable all known interrupts by setting the interrupt mask. */
+       SIS_W32(IntrMask, sis190_intr_mask);
+
+       SIS_W32(TxControl, 0x1a00 | CmdTxEnb);
+       SIS_W32(RxControl, 0x1a1d);
+
+       netif_start_queue(dev);
+}
+
+static void sis190_phy_task(void * data)
+{
+       struct net_device *dev = data;
+       struct sis190_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       int phy_id = tp->mii_if.phy_id;
+       u16 val;
+
+       rtnl_lock();
+
+       val = mdio_read(ioaddr, phy_id, MII_BMCR);
+       if (val & BMCR_RESET) {
+               // FIXME: needlessly high ?  -- FR 02/07/2005
+               mod_timer(&tp->timer, jiffies + HZ/10);
+       } else if (!(mdio_read_latched(ioaddr, phy_id, MII_BMSR) &
+                    BMSR_ANEGCOMPLETE)) {
+               net_link(tp, KERN_WARNING "%s: PHY reset until link up.\n",
+                        dev->name);
+               netif_carrier_off(dev);
+               mdio_write(ioaddr, phy_id, MII_BMCR, val | BMCR_RESET);
+               mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT);
+       } else {
+               /* Rejoice ! */
+               struct {
+                       int val;
+                       u32 ctl;
+                       const char *msg;
+               } reg31[] = {
+                       { LPA_1000XFULL | LPA_SLCT, 0x07000c00 | 0x00001000,
+                               "1000 Mbps Full Duplex" },
+                       { LPA_1000XHALF | LPA_SLCT, 0x07000c00,
+                               "1000 Mbps Half Duplex" },
+                       { LPA_100FULL, 0x04000800 | 0x00001000,
+                               "100 Mbps Full Duplex" },
+                       { LPA_100HALF, 0x04000800,
+                               "100 Mbps Half Duplex" },
+                       { LPA_10FULL, 0x04000400 | 0x00001000,
+                               "10 Mbps Full Duplex" },
+                       { LPA_10HALF, 0x04000400,
+                               "10 Mbps Half Duplex" },
+                       { 0, 0x04000400, "unknown" }
+               }, *p;
+               u16 adv;
+
+               val = mdio_read(ioaddr, phy_id, 0x1f);
+               net_link(tp, KERN_INFO "%s: mii ext = %04x.\n", dev->name, val);
+
+               val = mdio_read(ioaddr, phy_id, MII_LPA);
+               adv = mdio_read(ioaddr, phy_id, MII_ADVERTISE);
+               net_link(tp, KERN_INFO "%s: mii lpa = %04x adv = %04x.\n",
+                        dev->name, val, adv);
+
+               val &= adv;
+
+               for (p = reg31; p->val; p++) {
+                       if ((val & p->val) == p->val)
+                               break;
+               }
+
+               p->ctl |= SIS_R32(StationControl) & ~0x0f001c00;
+
+               if ((tp->features & F_HAS_RGMII) &&
+                   (tp->features & F_PHY_BCM5461)) {
+                       // Set Tx Delay in RGMII mode.
+                       mdio_write(ioaddr, phy_id, 0x18, 0xf1c7);
+                       udelay(200);
+                       mdio_write(ioaddr, phy_id, 0x1c, 0x8c00);
+                       p->ctl |= 0x03000000;
+               }
+
+               SIS_W32(StationControl, p->ctl);
+
+               if (tp->features & F_HAS_RGMII) {
+                       SIS_W32(RGDelay, 0x0441);
+                       SIS_W32(RGDelay, 0x0440);
+               }
+
+               net_link(tp, KERN_INFO "%s: link on %s mode.\n", dev->name,
+                        p->msg);
+               netif_carrier_on(dev);
+       }
+
+       rtnl_unlock();
+}
+
+static void sis190_phy_timer(unsigned long __opaque)
+{
+       struct net_device *dev = (struct net_device *)__opaque;
+       struct sis190_private *tp = netdev_priv(dev);
+
+       if (likely(netif_running(dev)))
+               schedule_work(&tp->phy_task);
+}
+
+static inline void sis190_delete_timer(struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+
+       del_timer_sync(&tp->timer);
+}
+
+static inline void sis190_request_timer(struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+       struct timer_list *timer = &tp->timer;
+
+       init_timer(timer);
+       timer->expires = jiffies + SIS190_PHY_TIMEOUT;
+       timer->data = (unsigned long)dev;
+       timer->function = sis190_phy_timer;
+       add_timer(timer);
+}
+
+static void sis190_set_rxbufsize(struct sis190_private *tp,
+                                struct net_device *dev)
+{
+       unsigned int mtu = dev->mtu;
+
+       tp->rx_buf_sz = (mtu > RX_BUF_SIZE) ? mtu + ETH_HLEN + 8 : RX_BUF_SIZE;
+       /* RxDesc->size has a licence to kill the lower bits */
+       if (tp->rx_buf_sz & 0x07) {
+               tp->rx_buf_sz += 8;
+               tp->rx_buf_sz &= RX_BUF_MASK;
+       }
+}
+
+static int sis190_open(struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+       struct pci_dev *pdev = tp->pci_dev;
+       int rc = -ENOMEM;
+
+       sis190_set_rxbufsize(tp, dev);
+
+       /*
+        * Rx and Tx descriptors need 256 bytes alignment.
+        * pci_alloc_consistent() guarantees a stronger alignment.
+        */
+       tp->TxDescRing = pci_alloc_consistent(pdev, TX_RING_BYTES, &tp->tx_dma);
+       if (!tp->TxDescRing)
+               goto out;
+
+       tp->RxDescRing = pci_alloc_consistent(pdev, RX_RING_BYTES, &tp->rx_dma);
+       if (!tp->RxDescRing)
+               goto err_free_tx_0;
+
+       rc = sis190_init_ring(dev);
+       if (rc < 0)
+               goto err_free_rx_1;
+
+       INIT_WORK(&tp->phy_task, sis190_phy_task, dev);
+
+       sis190_request_timer(dev);
+
+       rc = request_irq(dev->irq, sis190_interrupt, SA_SHIRQ, dev->name, dev);
+       if (rc < 0)
+               goto err_release_timer_2;
+
+       sis190_hw_start(dev);
+out:
+       return rc;
+
+err_release_timer_2:
+       sis190_delete_timer(dev);
+       sis190_rx_clear(tp);
+err_free_rx_1:
+       pci_free_consistent(tp->pci_dev, RX_RING_BYTES, tp->RxDescRing,
+               tp->rx_dma);
+err_free_tx_0:
+       pci_free_consistent(tp->pci_dev, TX_RING_BYTES, tp->TxDescRing,
+               tp->tx_dma);
+       goto out;
+}
+
+static void sis190_tx_clear(struct sis190_private *tp)
+{
+       unsigned int i;
+
+       for (i = 0; i < NUM_TX_DESC; i++) {
+               struct sk_buff *skb = tp->Tx_skbuff[i];
+
+               if (!skb)
+                       continue;
+
+               sis190_unmap_tx_skb(tp->pci_dev, skb, tp->TxDescRing + i);
+               tp->Tx_skbuff[i] = NULL;
+               dev_kfree_skb(skb);
+
+               tp->stats.tx_dropped++;
+       }
+       tp->cur_tx = tp->dirty_tx = 0;
+}
+
+static void sis190_down(struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       unsigned int poll_locked = 0;
+
+       sis190_delete_timer(dev);
+
+       netif_stop_queue(dev);
+
+       flush_scheduled_work();
+
+       do {
+               spin_lock_irq(&tp->lock);
+
+               sis190_asic_down(ioaddr);
+
+               spin_unlock_irq(&tp->lock);
+
+               synchronize_irq(dev->irq);
+
+               if (!poll_locked) {
+                       netif_poll_disable(dev);
+                       poll_locked++;
+               }
+
+               synchronize_sched();
+
+       } while (SIS_R32(IntrMask));
+
+       sis190_tx_clear(tp);
+       sis190_rx_clear(tp);
+}
+
+static int sis190_close(struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+       struct pci_dev *pdev = tp->pci_dev;
+
+       sis190_down(dev);
+
+       free_irq(dev->irq, dev);
+
+       netif_poll_enable(dev);
+
+       pci_free_consistent(pdev, TX_RING_BYTES, tp->TxDescRing, tp->tx_dma);
+       pci_free_consistent(pdev, RX_RING_BYTES, tp->RxDescRing, tp->rx_dma);
+
+       tp->TxDescRing = NULL;
+       tp->RxDescRing = NULL;
+
+       return 0;
+}
+
+static int sis190_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       u32 len, entry, dirty_tx;
+       struct TxDesc *desc;
+       dma_addr_t mapping;
+
+       if (unlikely(skb->len < ETH_ZLEN)) {
+               skb = skb_padto(skb, ETH_ZLEN);
+               if (!skb) {
+                       tp->stats.tx_dropped++;
+                       goto out;
+               }
+               len = ETH_ZLEN;
+       } else {
+               len = skb->len;
+       }
+
+       entry = tp->cur_tx % NUM_TX_DESC;
+       desc = tp->TxDescRing + entry;
+
+       if (unlikely(le32_to_cpu(desc->status) & OWNbit)) {
+               netif_stop_queue(dev);
+               net_tx_err(tp, KERN_ERR PFX
+                          "%s: BUG! Tx Ring full when queue awake!\n",
+                          dev->name);
+               return NETDEV_TX_BUSY;
+       }
+
+       mapping = pci_map_single(tp->pci_dev, skb->data, len, PCI_DMA_TODEVICE);
+
+       tp->Tx_skbuff[entry] = skb;
+
+       desc->PSize = cpu_to_le32(len);
+       desc->addr = cpu_to_le32(mapping);
+
+       desc->size = cpu_to_le32(len);
+       if (entry == (NUM_TX_DESC - 1))
+               desc->size |= cpu_to_le32(RingEnd);
+
+       wmb();
+
+       desc->status = cpu_to_le32(OWNbit | INTbit | DEFbit | CRCbit | PADbit);
+
+       tp->cur_tx++;
+
+       smp_wmb();
+
+       SIS_W32(TxControl, 0x1a00 | CmdReset | CmdTxEnb);
+
+       dev->trans_start = jiffies;
+
+       dirty_tx = tp->dirty_tx;
+       if ((tp->cur_tx - NUM_TX_DESC) == dirty_tx) {
+               netif_stop_queue(dev);
+               smp_rmb();
+               if (dirty_tx != tp->dirty_tx)
+                       netif_wake_queue(dev);
+       }
+out:
+       return NETDEV_TX_OK;
+}
+
+static struct net_device_stats *sis190_get_stats(struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+
+       return &tp->stats;
+}
+
+static void sis190_free_phy(struct list_head *first_phy)
+{
+       struct sis190_phy *cur, *next;
+
+       list_for_each_entry_safe(cur, next, first_phy, list) {
+               kfree(cur);
+       }
+}
+
+/**
+ *     sis190_default_phy - Select default PHY for sis190 mac.
+ *     @dev: the net device to probe for
+ *
+ *     Select first detected PHY with link as default.
+ *     If no one is link on, select PHY whose types is HOME as default.
+ *     If HOME doesn't exist, select LAN.
+ */
+static u16 sis190_default_phy(struct net_device *dev)
+{
+       struct sis190_phy *phy, *phy_home, *phy_default, *phy_lan;
+       struct sis190_private *tp = netdev_priv(dev);
+       struct mii_if_info *mii_if = &tp->mii_if;
+       void __iomem *ioaddr = tp->mmio_addr;
+       u16 status;
+
+       phy_home = phy_default = phy_lan = NULL;
+
+       list_for_each_entry(phy, &tp->first_phy, list) {
+               status = mdio_read_latched(ioaddr, phy->phy_id, MII_BMSR);
+
+               // Link ON & Not select default PHY & not ghost PHY.
+               if ((status & BMSR_LSTATUS) &&
+                   !phy_default &&
+                   (phy->type != UNKNOWN)) {
+                       phy_default = phy;
+               } else {
+                       status = mdio_read(ioaddr, phy->phy_id, MII_BMCR);
+                       mdio_write(ioaddr, phy->phy_id, MII_BMCR,
+                                  status | BMCR_ANENABLE | BMCR_ISOLATE);
+                       if (phy->type == HOME)
+                               phy_home = phy;
+                       else if (phy->type == LAN)
+                               phy_lan = phy;
+               }
+       }
+
+       if (!phy_default) {
+               if (phy_home)
+                       phy_default = phy_home;
+               else if (phy_lan)
+                       phy_default = phy_lan;
+               else
+                       phy_default = list_entry(&tp->first_phy,
+                                                struct sis190_phy, list);
+       }
+
+       if (mii_if->phy_id != phy_default->phy_id) {
+               mii_if->phy_id = phy_default->phy_id;
+               net_probe(tp, KERN_INFO
+                      "%s: Using transceiver at address %d as default.\n",
+                      pci_name(tp->pci_dev), mii_if->phy_id);
+       }
+
+       status = mdio_read(ioaddr, mii_if->phy_id, MII_BMCR);
+       status &= (~BMCR_ISOLATE);
+
+       mdio_write(ioaddr, mii_if->phy_id, MII_BMCR, status);
+       status = mdio_read_latched(ioaddr, mii_if->phy_id, MII_BMSR);
+
+       return status;
+}
+
+static void sis190_init_phy(struct net_device *dev, struct sis190_private *tp,
+                           struct sis190_phy *phy, unsigned int phy_id,
+                           u16 mii_status)
+{
+       void __iomem *ioaddr = tp->mmio_addr;
+       struct mii_chip_info *p;
+
+       INIT_LIST_HEAD(&phy->list);
+       phy->status = mii_status;
+       phy->phy_id = phy_id;
+
+       phy->id[0] = mdio_read(ioaddr, phy_id, MII_PHYSID1);
+       phy->id[1] = mdio_read(ioaddr, phy_id, MII_PHYSID2);
+
+       for (p = mii_chip_table; p->type; p++) {
+               if ((p->id[0] == phy->id[0]) &&
+                   (p->id[1] == (phy->id[1] & 0xfff0))) {
+                       break;
+               }
+       }
+
+       if (p->id[1]) {
+               phy->type = (p->type == MIX) ?
+                       ((mii_status & (BMSR_100FULL | BMSR_100HALF)) ?
+                               LAN : HOME) : p->type;
+               tp->features |= p->feature;
+       } else
+               phy->type = UNKNOWN;
+
+       net_probe(tp, KERN_INFO "%s: %s transceiver at address %d.\n",
+                 pci_name(tp->pci_dev),
+                 (phy->type == UNKNOWN) ? "Unknown PHY" : p->name, phy_id);
+}
+
+static void sis190_mii_probe_88e1111_fixup(struct sis190_private *tp)
+{
+       if (tp->features & F_PHY_88E1111) {
+               void __iomem *ioaddr = tp->mmio_addr;
+               int phy_id = tp->mii_if.phy_id;
+               u16 reg[2][2] = {
+                       { 0x808b, 0x0ce1 },
+                       { 0x808f, 0x0c60 }
+               }, *p;
+
+               p = (tp->features & F_HAS_RGMII) ? reg[0] : reg[1];
+
+               mdio_write(ioaddr, phy_id, 0x1b, p[0]);
+               udelay(200);
+               mdio_write(ioaddr, phy_id, 0x14, p[1]);
+               udelay(200);
+       }
+}
+
+/**
+ *     sis190_mii_probe - Probe MII PHY for sis190
+ *     @dev: the net device to probe for
+ *
+ *     Search for total of 32 possible mii phy addresses.
+ *     Identify and set current phy if found one,
+ *     return error if it failed to found.
+ */
+static int __devinit sis190_mii_probe(struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+       struct mii_if_info *mii_if = &tp->mii_if;
+       void __iomem *ioaddr = tp->mmio_addr;
+       int phy_id;
+       int rc = 0;
+
+       INIT_LIST_HEAD(&tp->first_phy);
+
+       for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) {
+               struct sis190_phy *phy;
+               u16 status;
+
+               status = mdio_read_latched(ioaddr, phy_id, MII_BMSR);
+
+               // Try next mii if the current one is not accessible.
+               if (status == 0xffff || status == 0x0000)
+                       continue;
+
+               phy = kmalloc(sizeof(*phy), GFP_KERNEL);
+               if (!phy) {
+                       sis190_free_phy(&tp->first_phy);
+                       rc = -ENOMEM;
+                       goto out;
+               }
+
+               sis190_init_phy(dev, tp, phy, phy_id, status);
+
+               list_add(&tp->first_phy, &phy->list);
+       }
+
+       if (list_empty(&tp->first_phy)) {
+               net_probe(tp, KERN_INFO "%s: No MII transceivers found!\n",
+                         pci_name(tp->pci_dev));
+               rc = -EIO;
+               goto out;
+       }
+
+       /* Select default PHY for mac */
+       sis190_default_phy(dev);
+
+       sis190_mii_probe_88e1111_fixup(tp);
+
+       mii_if->dev = dev;
+       mii_if->mdio_read = __mdio_read;
+       mii_if->mdio_write = __mdio_write;
+       mii_if->phy_id_mask = PHY_ID_ANY;
+       mii_if->reg_num_mask = MII_REG_ANY;
+out:
+       return rc;
+}
+
+static void __devexit sis190_mii_remove(struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+
+       sis190_free_phy(&tp->first_phy);
+}
+
+static void sis190_release_board(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct sis190_private *tp = netdev_priv(dev);
+
+       iounmap(tp->mmio_addr);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       free_netdev(dev);
+}
+
+static struct net_device * __devinit sis190_init_board(struct pci_dev *pdev)
+{
+       struct sis190_private *tp;
+       struct net_device *dev;
+       void __iomem *ioaddr;
+       int rc;
+
+       dev = alloc_etherdev(sizeof(*tp));
+       if (!dev) {
+               net_drv(&debug, KERN_ERR PFX "unable to alloc new ethernet\n");
+               rc = -ENOMEM;
+               goto err_out_0;
+       }
+
+       SET_MODULE_OWNER(dev);
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       tp = netdev_priv(dev);
+       tp->msg_enable = netif_msg_init(debug.msg_enable, SIS190_MSG_DEFAULT);
+
+       rc = pci_enable_device(pdev);
+       if (rc < 0) {
+               net_probe(tp, KERN_ERR "%s: enable failure\n", pci_name(pdev));
+               goto err_free_dev_1;
+       }
+
+       rc = -ENODEV;
+
+       if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+               net_probe(tp, KERN_ERR "%s: region #0 is no MMIO resource.\n",
+                         pci_name(pdev));
+               goto err_pci_disable_2;
+       }
+       if (pci_resource_len(pdev, 0) < SIS190_REGS_SIZE) {
+               net_probe(tp, KERN_ERR "%s: invalid PCI region size(s).\n",
+                         pci_name(pdev));
+               goto err_pci_disable_2;
+       }
+
+       rc = pci_request_regions(pdev, DRV_NAME);
+       if (rc < 0) {
+               net_probe(tp, KERN_ERR PFX "%s: could not request regions.\n",
+                         pci_name(pdev));
+               goto err_pci_disable_2;
+       }
+
+       rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+       if (rc < 0) {
+               net_probe(tp, KERN_ERR "%s: DMA configuration failed.\n",
+                         pci_name(pdev));
+               goto err_free_res_3;
+       }
+
+       pci_set_master(pdev);
+
+       ioaddr = ioremap(pci_resource_start(pdev, 0), SIS190_REGS_SIZE);
+       if (!ioaddr) {
+               net_probe(tp, KERN_ERR "%s: cannot remap MMIO, aborting\n",
+                         pci_name(pdev));
+               rc = -EIO;
+               goto err_free_res_3;
+       }
+
+       tp->pci_dev = pdev;
+       tp->mmio_addr = ioaddr;
+
+       sis190_irq_mask_and_ack(ioaddr);
+
+       sis190_soft_reset(ioaddr);
+out:
+       return dev;
+
+err_free_res_3:
+       pci_release_regions(pdev);
+err_pci_disable_2:
+       pci_disable_device(pdev);
+err_free_dev_1:
+       free_netdev(dev);
+err_out_0:
+       dev = ERR_PTR(rc);
+       goto out;
+}
+
+static void sis190_tx_timeout(struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       u8 tmp8;
+
+       /* Disable Tx, if not already */
+       tmp8 = SIS_R8(TxControl);
+       if (tmp8 & CmdTxEnb)
+               SIS_W8(TxControl, tmp8 & ~CmdTxEnb);
+
+
+       net_tx_err(tp, KERN_INFO "%s: Transmit timeout, status %08x %08x.\n",
+                  dev->name, SIS_R32(TxControl), SIS_R32(TxSts));
+
+       /* Disable interrupts by clearing the interrupt mask. */
+       SIS_W32(IntrMask, 0x0000);
+
+       /* Stop a shared interrupt from scavenging while we are. */
+       spin_lock_irq(&tp->lock);
+       sis190_tx_clear(tp);
+       spin_unlock_irq(&tp->lock);
+
+       /* ...and finally, reset everything. */
+       sis190_hw_start(dev);
+
+       netif_wake_queue(dev);
+}
+
+static void sis190_set_rgmii(struct sis190_private *tp, u8 reg)
+{
+       tp->features |= (reg & 0x80) ? F_HAS_RGMII : 0;
+}
+
+static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev,
+                                                    struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       u16 sig;
+       int i;
+
+       net_probe(tp, KERN_INFO "%s: Read MAC address from EEPROM\n",
+                 pci_name(pdev));
+
+       /* Check to see if there is a sane EEPROM */
+       sig = (u16) sis190_read_eeprom(ioaddr, EEPROMSignature);
+
+       if ((sig == 0xffff) || (sig == 0x0000)) {
+               net_probe(tp, KERN_INFO "%s: Error EEPROM read %x.\n",
+                         pci_name(pdev), sig);
+               return -EIO;
+       }
+
+       /* Get MAC address from EEPROM */
+       for (i = 0; i < MAC_ADDR_LEN / 2; i++) {
+               __le16 w = sis190_read_eeprom(ioaddr, EEPROMMACAddr + i);
+
+               ((u16 *)dev->dev_addr)[0] = le16_to_cpu(w);
+       }
+
+       sis190_set_rgmii(tp, sis190_read_eeprom(ioaddr, EEPROMInfo));
+
+       return 0;
+}
+
+/**
+ *     sis190_get_mac_addr_from_apc - Get MAC address for SiS965 model
+ *     @pdev: PCI device
+ *     @dev:  network device to get address for
+ *
+ *     SiS965 model, use APC CMOS RAM to store MAC address.
+ *     APC CMOS RAM is accessed through ISA bridge.
+ *     MAC address is read into @net_dev->dev_addr.
+ */
+static int __devinit sis190_get_mac_addr_from_apc(struct pci_dev *pdev,
+                                                 struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+       struct pci_dev *isa_bridge;
+       u8 reg, tmp8;
+       int i;
+
+       net_probe(tp, KERN_INFO "%s: Read MAC address from APC.\n",
+                 pci_name(pdev));
+
+       isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0965, NULL);
+       if (!isa_bridge) {
+               net_probe(tp, KERN_INFO "%s: Can not find ISA bridge.\n",
+                         pci_name(pdev));
+               return -EIO;
+       }
+
+       /* Enable port 78h & 79h to access APC Registers. */
+       pci_read_config_byte(isa_bridge, 0x48, &tmp8);
+       reg = (tmp8 & ~0x02);
+       pci_write_config_byte(isa_bridge, 0x48, reg);
+       udelay(50);
+       pci_read_config_byte(isa_bridge, 0x48, &reg);
+
+        for (i = 0; i < MAC_ADDR_LEN; i++) {
+                outb(0x9 + i, 0x78);
+                dev->dev_addr[i] = inb(0x79);
+        }
+
+       outb(0x12, 0x78);
+       reg = inb(0x79);
+
+       sis190_set_rgmii(tp, reg);
+
+       /* Restore the value to ISA Bridge */
+       pci_write_config_byte(isa_bridge, 0x48, tmp8);
+       pci_dev_put(isa_bridge);
+
+       return 0;
+}
+
+/**
+ *      sis190_init_rxfilter - Initialize the Rx filter
+ *      @dev: network device to initialize
+ *
+ *      Set receive filter address to our MAC address
+ *      and enable packet filtering.
+ */
+static inline void sis190_init_rxfilter(struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       u16 ctl;
+       int i;
+
+       ctl = SIS_R16(RxMacControl);
+       /*
+        * Disable packet filtering before setting filter.
+        * Note: SiS's driver writes 32 bits but RxMacControl is 16 bits
+        * only and followed by RxMacAddr (6 bytes). Strange. -- FR
+        */
+       SIS_W16(RxMacControl, ctl & ~0x0f00);
+
+       for (i = 0; i < MAC_ADDR_LEN; i++)
+               SIS_W8(RxMacAddr + i, dev->dev_addr[i]);
+
+       SIS_W16(RxMacControl, ctl);
+       SIS_PCI_COMMIT();
+}
+
+static int sis190_get_mac_addr(struct pci_dev *pdev, struct net_device *dev)
+{
+       u8 from;
+
+       pci_read_config_byte(pdev, 0x73, &from);
+
+       return (from & 0x00000001) ?
+               sis190_get_mac_addr_from_apc(pdev, dev) :
+               sis190_get_mac_addr_from_eeprom(pdev, dev);
+}
+
+static void sis190_set_speed_auto(struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       int phy_id = tp->mii_if.phy_id;
+       int val;
+
+       net_link(tp, KERN_INFO "%s: Enabling Auto-negotiation.\n", dev->name);
+
+       val = mdio_read(ioaddr, phy_id, MII_ADVERTISE);
+
+       // Enable 10/100 Full/Half Mode, leave MII_ADVERTISE bit4:0
+       // unchanged.
+       mdio_write(ioaddr, phy_id, MII_ADVERTISE, (val & ADVERTISE_SLCT) |
+                  ADVERTISE_100FULL | ADVERTISE_10FULL |
+                  ADVERTISE_100HALF | ADVERTISE_10HALF);
+
+       // Enable 1000 Full Mode.
+       mdio_write(ioaddr, phy_id, MII_CTRL1000, ADVERTISE_1000FULL);
+
+       // Enable auto-negotiation and restart auto-negotiation.
+       mdio_write(ioaddr, phy_id, MII_BMCR,
+                  BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET);
+}
+
+static int sis190_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+
+       return mii_ethtool_gset(&tp->mii_if, cmd);
+}
+
+static int sis190_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+
+       return mii_ethtool_sset(&tp->mii_if, cmd);
+}
+
+static void sis190_get_drvinfo(struct net_device *dev,
+                              struct ethtool_drvinfo *info)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+
+       strcpy(info->driver, DRV_NAME);
+       strcpy(info->version, DRV_VERSION);
+       strcpy(info->bus_info, pci_name(tp->pci_dev));
+}
+
+static int sis190_get_regs_len(struct net_device *dev)
+{
+       return SIS190_REGS_SIZE;
+}
+
+static void sis190_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+                           void *p)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+       unsigned long flags;
+
+       if (regs->len > SIS190_REGS_SIZE)
+               regs->len = SIS190_REGS_SIZE;
+
+       spin_lock_irqsave(&tp->lock, flags);
+       memcpy_fromio(p, tp->mmio_addr, regs->len);
+       spin_unlock_irqrestore(&tp->lock, flags);
+}
+
+static int sis190_nway_reset(struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+
+       return mii_nway_restart(&tp->mii_if);
+}
+
+static u32 sis190_get_msglevel(struct net_device *dev)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+
+       return tp->msg_enable;
+}
+
+static void sis190_set_msglevel(struct net_device *dev, u32 value)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+
+       tp->msg_enable = value;
+}
+
+static struct ethtool_ops sis190_ethtool_ops = {
+       .get_settings   = sis190_get_settings,
+       .set_settings   = sis190_set_settings,
+       .get_drvinfo    = sis190_get_drvinfo,
+       .get_regs_len   = sis190_get_regs_len,
+       .get_regs       = sis190_get_regs,
+       .get_link       = ethtool_op_get_link,
+       .get_msglevel   = sis190_get_msglevel,
+       .set_msglevel   = sis190_set_msglevel,
+       .nway_reset     = sis190_nway_reset,
+};
+
+static int sis190_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       struct sis190_private *tp = netdev_priv(dev);
+
+       return !netif_running(dev) ? -EINVAL :
+               generic_mii_ioctl(&tp->mii_if, if_mii(ifr), cmd, NULL);
+}
+
+static int __devinit sis190_init_one(struct pci_dev *pdev,
+                                    const struct pci_device_id *ent)
+{
+       static int printed_version = 0;
+       struct sis190_private *tp;
+       struct net_device *dev;
+       void __iomem *ioaddr;
+       int rc;
+
+       if (!printed_version) {
+               net_drv(&debug, KERN_INFO SIS190_DRIVER_NAME " loaded.\n");
+               printed_version = 1;
+       }
+
+       dev = sis190_init_board(pdev);
+       if (IS_ERR(dev)) {
+               rc = PTR_ERR(dev);
+               goto out;
+       }
+
+       tp = netdev_priv(dev);
+       ioaddr = tp->mmio_addr;
+
+       rc = sis190_get_mac_addr(pdev, dev);
+       if (rc < 0)
+               goto err_release_board;
+
+       sis190_init_rxfilter(dev);
+
+       INIT_WORK(&tp->phy_task, sis190_phy_task, dev);
+
+       dev->open = sis190_open;
+       dev->stop = sis190_close;
+       dev->do_ioctl = sis190_ioctl;
+       dev->get_stats = sis190_get_stats;
+       dev->tx_timeout = sis190_tx_timeout;
+       dev->watchdog_timeo = SIS190_TX_TIMEOUT;
+       dev->hard_start_xmit = sis190_start_xmit;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       dev->poll_controller = sis190_netpoll;
+#endif
+       dev->set_multicast_list = sis190_set_rx_mode;
+       SET_ETHTOOL_OPS(dev, &sis190_ethtool_ops);
+       dev->irq = pdev->irq;
+       dev->base_addr = (unsigned long) 0xdead;
+
+       spin_lock_init(&tp->lock);
+
+       rc = sis190_mii_probe(dev);
+       if (rc < 0)
+               goto err_release_board;
+
+       rc = register_netdev(dev);
+       if (rc < 0)
+               goto err_remove_mii;
+
+       pci_set_drvdata(pdev, dev);
+
+       net_probe(tp, KERN_INFO "%s: %s at %p (IRQ: %d), "
+              "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
+              pci_name(pdev), sis_chip_info[ent->driver_data].name,
+              ioaddr, dev->irq,
+              dev->dev_addr[0], dev->dev_addr[1],
+              dev->dev_addr[2], dev->dev_addr[3],
+              dev->dev_addr[4], dev->dev_addr[5]);
+
+       net_probe(tp, KERN_INFO "%s: %s mode.\n", dev->name,
+                 (tp->features & F_HAS_RGMII) ? "RGMII" : "GMII");
+
+       netif_carrier_off(dev);
+
+       sis190_set_speed_auto(dev);
+out:
+       return rc;
+
+err_remove_mii:
+       sis190_mii_remove(dev);
+err_release_board:
+       sis190_release_board(pdev);
+       goto out;
+}
+
+static void __devexit sis190_remove_one(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+
+       sis190_mii_remove(dev);
+       unregister_netdev(dev);
+       sis190_release_board(pdev);
+       pci_set_drvdata(pdev, NULL);
+}
+
+static struct pci_driver sis190_pci_driver = {
+       .name           = DRV_NAME,
+       .id_table       = sis190_pci_tbl,
+       .probe          = sis190_init_one,
+       .remove         = __devexit_p(sis190_remove_one),
+};
+
+static int __init sis190_init_module(void)
+{
+       return pci_module_init(&sis190_pci_driver);
+}
+
+static void __exit sis190_cleanup_module(void)
+{
+       pci_unregister_driver(&sis190_pci_driver);
+}
+
+module_init(sis190_init_module);
+module_exit(sis190_cleanup_module);
index f15739481d628f641850bb1b46f9a8b31f62263f..d7c98515fdfdd55d91cdd3fb54b1ca252ce2ec09 100644 (file)
@@ -42,7 +42,7 @@
 #include "skge.h"
 
 #define DRV_NAME               "skge"
-#define DRV_VERSION            "0.8"
+#define DRV_VERSION            "0.9"
 #define PFX                    DRV_NAME " "
 
 #define DEFAULT_TX_RING_SIZE   128
@@ -79,8 +79,8 @@ static const struct pci_device_id skge_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) },
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */
        { PCI_DEVICE(PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD) },
-       { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1032) },
        { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1064) },
+       { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015, },
        { 0 }
 };
 MODULE_DEVICE_TABLE(pci, skge_id_table);
@@ -189,7 +189,7 @@ static u32 skge_supported_modes(const struct skge_hw *hw)
 {
        u32 supported;
 
-       if (iscopper(hw)) {
+       if (hw->copper) {
                supported = SUPPORTED_10baseT_Half
                        | SUPPORTED_10baseT_Full
                        | SUPPORTED_100baseT_Half
@@ -222,7 +222,7 @@ static int skge_get_settings(struct net_device *dev,
        ecmd->transceiver = XCVR_INTERNAL;
        ecmd->supported = skge_supported_modes(hw);
 
-       if (iscopper(hw)) {
+       if (hw->copper) {
                ecmd->port = PORT_TP;
                ecmd->phy_address = hw->phy_addr;
        } else
@@ -876,6 +876,9 @@ static int skge_rx_fill(struct skge_port *skge)
 
 static void skge_link_up(struct skge_port *skge)
 {
+       skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), 
+                   LED_BLK_OFF|LED_SYNC_OFF|LED_ON);
+
        netif_carrier_on(skge->netdev);
        if (skge->tx_avail > MAX_SKB_FRAGS + 1)
                netif_wake_queue(skge->netdev);
@@ -894,6 +897,7 @@ static void skge_link_up(struct skge_port *skge)
 
 static void skge_link_down(struct skge_port *skge)
 {
+       skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF);
        netif_carrier_off(skge->netdev);
        netif_stop_queue(skge->netdev);
 
@@ -1599,7 +1603,7 @@ static void yukon_init(struct skge_hw *hw, int port)
        adv = PHY_AN_CSMA;
 
        if (skge->autoneg == AUTONEG_ENABLE) {
-               if (iscopper(hw)) {
+               if (hw->copper) {
                        if (skge->advertising & ADVERTISED_1000baseT_Full)
                                ct1000 |= PHY_M_1000C_AFD;
                        if (skge->advertising & ADVERTISED_1000baseT_Half)
@@ -1691,7 +1695,7 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
        /* Set hardware config mode */
        reg = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP |
                GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE;
-       reg |= iscopper(hw) ? GPC_HWCFG_GMII_COP : GPC_HWCFG_GMII_FIB;
+       reg |= hw->copper ? GPC_HWCFG_GMII_COP : GPC_HWCFG_GMII_FIB;
 
        /* Clear GMC reset */
        skge_write32(hw, SK_REG(port, GPHY_CTRL), reg | GPC_RST_SET);
@@ -1780,7 +1784,12 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
                reg &= ~GMF_RX_F_FL_ON;
        skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
        skge_write16(hw, SK_REG(port, RX_GMF_CTRL_T), reg);
-       skge_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF);
+       /*
+        * because Pause Packet Truncation in GMAC is not working
+        * we have to increase the Flush Threshold to 64 bytes
+        * in order to flush pause packets in Rx FIFO on Yukon-1
+        */
+       skge_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF+1);
 
        /* Configure Tx MAC FIFO */
        skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
@@ -2670,18 +2679,6 @@ static void skge_error_irq(struct skge_hw *hw)
                /* Timestamp (unused) overflow */
                if (hwstatus & IS_IRQ_TIST_OV)
                        skge_write8(hw, GMAC_TI_ST_CTRL, GMT_ST_CLR_IRQ);
-
-               if (hwstatus & IS_IRQ_SENSOR) {
-                       /* no sensors on 32-bit Yukon */
-                       if (!(skge_read16(hw, B0_CTST) & CS_BUS_SLOT_SZ)) {
-                               printk(KERN_ERR PFX "ignoring bogus sensor interrups\n");
-                               skge_write32(hw, B0_HWE_IMSK,
-                                            IS_ERR_MSK & ~IS_IRQ_SENSOR);
-                       } else
-                               printk(KERN_WARNING PFX "sensor interrupt\n");
-               }
-
-
        }
 
        if (hwstatus & IS_RAM_RD_PAR) {
@@ -2712,9 +2709,10 @@ static void skge_error_irq(struct skge_hw *hw)
 
                skge_pci_clear(hw);
 
+               /* if error still set then just ignore it */
                hwstatus = skge_read32(hw, B0_HWE_ISRC);
                if (hwstatus & IS_IRQ_STAT) {
-                       printk(KERN_WARNING PFX "IRQ status %x: still set ignoring hardware errors\n",
+                       pr_debug("IRQ status %x: still set ignoring hardware errors\n",
                               hwstatus);
                        hw->intr_mask &= ~IS_HW_ERR;
                }
@@ -2876,7 +2874,7 @@ static const char *skge_board_name(const struct skge_hw *hw)
 static int skge_reset(struct skge_hw *hw)
 {
        u16 ctst;
-       u8 t8, mac_cfg;
+       u8 t8, mac_cfg, pmd_type, phy_type;
        int i;
 
        ctst = skge_read16(hw, B0_CTST);
@@ -2895,18 +2893,19 @@ static int skge_reset(struct skge_hw *hw)
                     ctst & (CS_CLK_RUN_HOT|CS_CLK_RUN_RST|CS_CLK_RUN_ENA));
 
        hw->chip_id = skge_read8(hw, B2_CHIP_ID);
-       hw->phy_type = skge_read8(hw, B2_E_1) & 0xf;
-       hw->pmd_type = skge_read8(hw, B2_PMD_TYP);
+       phy_type = skge_read8(hw, B2_E_1) & 0xf;
+       pmd_type = skge_read8(hw, B2_PMD_TYP);
+       hw->copper = (pmd_type == 'T' || pmd_type == '1');
 
        switch (hw->chip_id) {
        case CHIP_ID_GENESIS:
-               switch (hw->phy_type) {
+               switch (phy_type) {
                case SK_PHY_BCOM:
                        hw->phy_addr = PHY_ADDR_BCOM;
                        break;
                default:
                        printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n",
-                              pci_name(hw->pdev), hw->phy_type);
+                              pci_name(hw->pdev), phy_type);
                        return -EOPNOTSUPP;
                }
                break;
@@ -2914,13 +2913,10 @@ static int skge_reset(struct skge_hw *hw)
        case CHIP_ID_YUKON:
        case CHIP_ID_YUKON_LITE:
        case CHIP_ID_YUKON_LP:
-               if (hw->phy_type < SK_PHY_MARV_COPPER && hw->pmd_type != 'S')
-                       hw->phy_type = SK_PHY_MARV_COPPER;
+               if (phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S')
+                       hw->copper = 1;
 
                hw->phy_addr = PHY_ADDR_MARV;
-               if (!iscopper(hw))
-                       hw->phy_type = SK_PHY_MARV_FIBER;
-
                break;
 
        default:
@@ -2948,12 +2944,20 @@ static int skge_reset(struct skge_hw *hw)
        else
                hw->ram_size = t8 * 4096;
 
+       hw->intr_mask = IS_HW_ERR | IS_EXT_REG;
        if (hw->chip_id == CHIP_ID_GENESIS)
                genesis_init(hw);
        else {
                /* switch power to VCC (WA for VAUX problem) */
                skge_write8(hw, B0_POWER_CTRL,
                            PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
+               /* avoid boards with stuck Hardware error bits */
+               if ((skge_read32(hw, B0_ISRC) & IS_HW_ERR) &&
+                   (skge_read32(hw, B0_HWE_ISRC) & IS_IRQ_SENSOR)) {
+                       printk(KERN_WARNING PFX "stuck hardware sensor bit\n");
+                       hw->intr_mask &= ~IS_HW_ERR;
+               }
+
                for (i = 0; i < hw->ports; i++) {
                        skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
                        skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
@@ -2994,7 +2998,6 @@ static int skge_reset(struct skge_hw *hw)
        skge_write32(hw, B2_IRQM_INI, skge_usecs2clk(hw, 100));
        skge_write32(hw, B2_IRQM_CTRL, TIM_START);
 
-       hw->intr_mask = IS_HW_ERR | IS_EXT_REG;
        skge_write32(hw, B0_IMSK, hw->intr_mask);
 
        if (hw->chip_id != CHIP_ID_GENESIS)
index b432f1bb816815745b0f36f0a470c7a59d500c85..f1680beb8e68a903d22228755bc84526656d4b1e 100644 (file)
@@ -214,8 +214,6 @@ enum {
 
 /*     B2_IRQM_HWE_MSK 32 bit  IRQ Moderation HW Error Mask */
 enum {
-       IS_ERR_MSK      = 0x00003fff,/*                 All Error bits */
-
        IS_IRQ_TIST_OV  = 1<<13, /* Time Stamp Timer Overflow (YUKON only) */
        IS_IRQ_SENSOR   = 1<<12, /* IRQ from Sensor (YUKON only) */
        IS_IRQ_MST_ERR  = 1<<11, /* IRQ master error detected */
@@ -230,6 +228,12 @@ enum {
        IS_M2_PAR_ERR   = 1<<2, /* MAC 2 Parity Error */
        IS_R1_PAR_ERR   = 1<<1, /* Queue R1 Parity Error */
        IS_R2_PAR_ERR   = 1<<0, /* Queue R2 Parity Error */
+
+       IS_ERR_MSK      = IS_IRQ_MST_ERR | IS_IRQ_STAT
+                       | IS_NO_STAT_M1 | IS_NO_STAT_M2
+                       | IS_RAM_RD_PAR | IS_RAM_WR_PAR
+                       | IS_M1_PAR_ERR | IS_M2_PAR_ERR
+                       | IS_R1_PAR_ERR | IS_R2_PAR_ERR,
 };
 
 /*     B2_TST_CTRL1     8 bit  Test Control Register 1 */
@@ -2456,24 +2460,17 @@ struct skge_hw {
 
        u8                   chip_id;
        u8                   chip_rev;
-       u8                   phy_type;
-       u8                   pmd_type;
-       u16                  phy_addr;
+       u8                   copper;
        u8                   ports;
 
        u32                  ram_size;
        u32                  ram_offset;
+       u16                  phy_addr;
 
        struct tasklet_struct ext_tasklet;
        spinlock_t           phy_lock;
 };
 
-
-static inline int iscopper(const struct skge_hw *hw)
-{
-       return (hw->pmd_type == 'T');
-}
-
 enum {
        FLOW_MODE_NONE          = 0, /* No Flow-Control */
        FLOW_MODE_LOC_SEND      = 1, /* Local station sends PAUSE */
index 6d9dae60a697050c1d7d1e8f4665420f0ac65074..ba8593ac3f8ab8d690eac367207298bb662099ca 100644 (file)
@@ -68,6 +68,7 @@ static const char version[] =
 #include <linux/etherdevice.h>
 
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <asm/system.h>
 
 #include "8390.h"
index a9b06b8d8e3ff185ffbd9cb90ff00e1ee0528fc3..ac9ce6509eee78af13c014d184b27bb0f5922e64 100644 (file)
@@ -986,7 +986,7 @@ static const char * chip_ids[ 16 ] =  {
        })
 #endif
 
-#if SMC_CAN_USE_DATACS
+#ifdef SMC_CAN_USE_DATACS
 #define SMC_PUSH_DATA(p, l)                                            \
        if ( lp->datacs ) {                                             \
                unsigned char *__ptr = (p);                             \
index cdc9cc873e067452b75f95b0806863770c887b25..90b818a8de6e41ca6d7f0863525e87c057ce6cfb 100644 (file)
@@ -1,6 +1,11 @@
 /*
  * sonic.c
  *
+ * (C) 2005 Finn Thain
+ *
+ * Converted to DMA API, added zero-copy buffer handling, and
+ * (from the mac68k project) introduced dhd's support for 16-bit cards.
+ *
  * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de)
  * 
  * This driver is based on work from Andreas Busse, but most of
  * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de)
  *
  *    Core code included by system sonic drivers
+ *
+ * And... partially rewritten again by David Huggins-Daines in order
+ * to cope with screwed up Macintosh NICs that may or may not use
+ * 16-bit DMA.
+ *
+ * (C) 1999 David Huggins-Daines <dhd@debian.org>
+ *
  */
 
 /*
  * Sources: Olivetti M700-10 Risc Personal Computer hardware handbook,
  * National Semiconductors data sheet for the DP83932B Sonic Ethernet
  * controller, and the files "8390.c" and "skeleton.c" in this directory.
+ *
+ * Additional sources: Nat Semi data sheet for the DP83932C and Nat Semi
+ * Application Note AN-746, the files "lance.c" and "ibmlana.c". See also
+ * the NetBSD file "sys/arch/mac68k/dev/if_sn.c".
  */
 
 
@@ -28,6 +44,9 @@
  */
 static int sonic_open(struct net_device *dev)
 {
+       struct sonic_local *lp = netdev_priv(dev);
+       int i;
+       
        if (sonic_debug > 2)
                printk("sonic_open: initializing sonic driver.\n");
 
@@ -40,14 +59,59 @@ static int sonic_open(struct net_device *dev)
  * This means that during execution of the handler interrupt are disabled
  * covering another bug otherwise corrupting data.  This doesn't mean
  * this glue works ok under all situations.
+ *
+ * Note (dhd): this also appears to prevent lockups on the Macintrash
+ * when more than one Ethernet card is installed (knock on wood)
+ *
+ * Note (fthain): whether the above is still true is anyones guess. Certainly
+ * the buffer handling algorithms will not tolerate re-entrance without some
+ * mutual exclusion added. Anyway, the memcpy has now been eliminated from the
+ * rx code to make this a faster "fast interrupt".
  */
-//    if (sonic_request_irq(dev->irq, &sonic_interrupt, 0, "sonic", dev)) {
-       if (sonic_request_irq(dev->irq, &sonic_interrupt, SA_INTERRUPT,
-                             "sonic", dev)) {
-               printk("\n%s: unable to get IRQ %d .\n", dev->name, dev->irq);
+       if (request_irq(dev->irq, &sonic_interrupt, SONIC_IRQ_FLAG, "sonic", dev)) {
+               printk(KERN_ERR "\n%s: unable to get IRQ %d .\n", dev->name, dev->irq);
                return -EAGAIN;
        }
 
+       for (i = 0; i < SONIC_NUM_RRS; i++) {
+               struct sk_buff *skb = dev_alloc_skb(SONIC_RBSIZE + 2);
+               if (skb == NULL) {
+                       while(i > 0) { /* free any that were allocated successfully */
+                               i--;
+                               dev_kfree_skb(lp->rx_skb[i]);
+                               lp->rx_skb[i] = NULL;
+                       }
+                       printk(KERN_ERR "%s: couldn't allocate receive buffers\n",
+                              dev->name);
+                       return -ENOMEM;
+               }
+               skb->dev = dev;
+               /* align IP header unless DMA requires otherwise */
+               if (SONIC_BUS_SCALE(lp->dma_bitmode) == 2)
+                       skb_reserve(skb, 2);
+               lp->rx_skb[i] = skb;
+       }
+
+       for (i = 0; i < SONIC_NUM_RRS; i++) {
+               dma_addr_t laddr = dma_map_single(lp->device, skb_put(lp->rx_skb[i], SONIC_RBSIZE),
+                                                 SONIC_RBSIZE, DMA_FROM_DEVICE);
+               if (!laddr) {
+                       while(i > 0) { /* free any that were mapped successfully */
+                               i--;
+                               dma_unmap_single(lp->device, lp->rx_laddr[i], SONIC_RBSIZE, DMA_FROM_DEVICE);
+                               lp->rx_laddr[i] = (dma_addr_t)0;
+                       }
+                       for (i = 0; i < SONIC_NUM_RRS; i++) {
+                               dev_kfree_skb(lp->rx_skb[i]);
+                               lp->rx_skb[i] = NULL;
+                       }
+                       printk(KERN_ERR "%s: couldn't map rx DMA buffers\n",
+                              dev->name);
+                       return -ENOMEM;
+               }
+               lp->rx_laddr[i] = laddr;
+       }
+
        /*
         * Initialize the SONIC
         */
@@ -67,7 +131,8 @@ static int sonic_open(struct net_device *dev)
  */
 static int sonic_close(struct net_device *dev)
 {
-       unsigned int base_addr = dev->base_addr;
+       struct sonic_local *lp = netdev_priv(dev);
+       int i;
 
        if (sonic_debug > 2)
                printk("sonic_close\n");
@@ -77,20 +142,56 @@ static int sonic_close(struct net_device *dev)
        /*
         * stop the SONIC, disable interrupts
         */
-       SONIC_WRITE(SONIC_ISR, 0x7fff);
        SONIC_WRITE(SONIC_IMR, 0);
+       SONIC_WRITE(SONIC_ISR, 0x7fff);
        SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
 
-       sonic_free_irq(dev->irq, dev);  /* release the IRQ */
+       /* unmap and free skbs that haven't been transmitted */
+       for (i = 0; i < SONIC_NUM_TDS; i++) {
+               if(lp->tx_laddr[i]) {
+                       dma_unmap_single(lp->device, lp->tx_laddr[i], lp->tx_len[i], DMA_TO_DEVICE);
+                       lp->tx_laddr[i] = (dma_addr_t)0;
+               }
+               if(lp->tx_skb[i]) {
+                       dev_kfree_skb(lp->tx_skb[i]);
+                       lp->tx_skb[i] = NULL;
+               }
+       }
+
+       /* unmap and free the receive buffers */
+       for (i = 0; i < SONIC_NUM_RRS; i++) {
+               if(lp->rx_laddr[i]) {
+                       dma_unmap_single(lp->device, lp->rx_laddr[i], SONIC_RBSIZE, DMA_FROM_DEVICE);
+                       lp->rx_laddr[i] = (dma_addr_t)0;
+               }
+               if(lp->rx_skb[i]) {
+                       dev_kfree_skb(lp->rx_skb[i]);
+                       lp->rx_skb[i] = NULL;
+               }
+       }
+
+       free_irq(dev->irq, dev);        /* release the IRQ */
 
        return 0;
 }
 
 static void sonic_tx_timeout(struct net_device *dev)
 {
-       struct sonic_local *lp = (struct sonic_local *) dev->priv;
-       printk("%s: transmit timed out.\n", dev->name);
-
+       struct sonic_local *lp = netdev_priv(dev);
+       int i;
+       /* Stop the interrupts for this */
+       SONIC_WRITE(SONIC_IMR, 0);
+       /* We could resend the original skbs. Easier to re-initialise. */
+       for (i = 0; i < SONIC_NUM_TDS; i++) {
+               if(lp->tx_laddr[i]) {
+                       dma_unmap_single(lp->device, lp->tx_laddr[i], lp->tx_len[i], DMA_TO_DEVICE);
+                       lp->tx_laddr[i] = (dma_addr_t)0;
+               }
+               if(lp->tx_skb[i]) {
+                       dev_kfree_skb(lp->tx_skb[i]);
+                       lp->tx_skb[i] = NULL;
+               }
+       }
        /* Try to restart the adaptor. */
        sonic_init(dev);
        lp->stats.tx_errors++;
@@ -100,60 +201,92 @@ static void sonic_tx_timeout(struct net_device *dev)
 
 /*
  * transmit packet
+ *
+ * Appends new TD during transmission thus avoiding any TX interrupts
+ * until we run out of TDs.
+ * This routine interacts closely with the ISR in that it may,
+ *   set tx_skb[i]
+ *   reset the status flags of the new TD
+ *   set and reset EOL flags
+ *   stop the tx queue
+ * The ISR interacts with this routine in various ways. It may,
+ *   reset tx_skb[i]
+ *   test the EOL and status flags of the TDs
+ *   wake the tx queue
+ * Concurrently with all of this, the SONIC is potentially writing to
+ * the status flags of the TDs.
+ * Until some mutual exclusion is added, this code will not work with SMP. However,
+ * MIPS Jazz machines and m68k Macs were all uni-processor machines.
  */
+
 static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-       struct sonic_local *lp = (struct sonic_local *) dev->priv;
-       unsigned int base_addr = dev->base_addr;
-       unsigned int laddr;
-       int entry, length;
-
-       netif_stop_queue(dev);
+       struct sonic_local *lp = netdev_priv(dev);
+       dma_addr_t laddr;
+       int length;
+       int entry = lp->next_tx;
 
        if (sonic_debug > 2)
                printk("sonic_send_packet: skb=%p, dev=%p\n", skb, dev);
 
+       length = skb->len;
+       if (length < ETH_ZLEN) {
+               skb = skb_padto(skb, ETH_ZLEN);
+               if (skb == NULL)
+                       return 0;
+               length = ETH_ZLEN;
+       }
+
        /*
         * Map the packet data into the logical DMA address space
         */
-       if ((laddr = vdma_alloc(CPHYSADDR(skb->data), skb->len)) == ~0UL) {
-               printk("%s: no VDMA entry for transmit available.\n",
-                      dev->name);
+
+       laddr = dma_map_single(lp->device, skb->data, length, DMA_TO_DEVICE);
+       if (!laddr) {
+               printk(KERN_ERR "%s: failed to map tx DMA buffer.\n", dev->name);
                dev_kfree_skb(skb);
-               netif_start_queue(dev);
                return 1;
        }
-       entry = lp->cur_tx & SONIC_TDS_MASK;
+   
+       sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0);       /* clear status */
+       sonic_tda_put(dev, entry, SONIC_TD_FRAG_COUNT, 1);   /* single fragment */
+       sonic_tda_put(dev, entry, SONIC_TD_PKTSIZE, length); /* length of packet */
+       sonic_tda_put(dev, entry, SONIC_TD_FRAG_PTR_L, laddr & 0xffff);
+       sonic_tda_put(dev, entry, SONIC_TD_FRAG_PTR_H, laddr >> 16);
+       sonic_tda_put(dev, entry, SONIC_TD_FRAG_SIZE, length);
+       sonic_tda_put(dev, entry, SONIC_TD_LINK,
+               sonic_tda_get(dev, entry, SONIC_TD_LINK) | SONIC_EOL);
+
+       /*
+        * Must set tx_skb[entry] only after clearing status, and
+        * before clearing EOL and before stopping queue
+        */
+       wmb();
+       lp->tx_len[entry] = length;
        lp->tx_laddr[entry] = laddr;
        lp->tx_skb[entry] = skb;
 
-       length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
-       flush_cache_all();
+       wmb();
+       sonic_tda_put(dev, lp->eol_tx, SONIC_TD_LINK,
+                                 sonic_tda_get(dev, lp->eol_tx, SONIC_TD_LINK) & ~SONIC_EOL);
+       lp->eol_tx = entry;
 
-       /*
-        * Setup the transmit descriptor and issue the transmit command.
-        */
-       lp->tda[entry].tx_status = 0;   /* clear status */
-       lp->tda[entry].tx_frag_count = 1;       /* single fragment */
-       lp->tda[entry].tx_pktsize = length;     /* length of packet */
-       lp->tda[entry].tx_frag_ptr_l = laddr & 0xffff;
-       lp->tda[entry].tx_frag_ptr_h = laddr >> 16;
-       lp->tda[entry].tx_frag_size = length;
-       lp->cur_tx++;
-       lp->stats.tx_bytes += length;
+       lp->next_tx = (entry + 1) & SONIC_TDS_MASK;
+       if (lp->tx_skb[lp->next_tx] != NULL) {
+               /* The ring is full, the ISR has yet to process the next TD. */
+               if (sonic_debug > 3)
+                       printk("%s: stopping queue\n", dev->name);
+               netif_stop_queue(dev);
+               /* after this packet, wait for ISR to free up some TDAs */
+       } else netif_start_queue(dev);
 
        if (sonic_debug > 2)
-               printk("sonic_send_packet: issueing Tx command\n");
+               printk("sonic_send_packet: issuing Tx command\n");
 
        SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP);
 
        dev->trans_start = jiffies;
 
-       if (lp->cur_tx < lp->dirty_tx + SONIC_NUM_TDS)
-               netif_start_queue(dev);
-       else
-               lp->tx_full = 1;
-
        return 0;
 }
 
@@ -164,175 +297,199 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
 static irqreturn_t sonic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        struct net_device *dev = (struct net_device *) dev_id;
-       unsigned int base_addr = dev->base_addr;
-       struct sonic_local *lp;
+       struct sonic_local *lp = netdev_priv(dev);
        int status;
 
        if (dev == NULL) {
-               printk("sonic_interrupt: irq %d for unknown device.\n", irq);
+               printk(KERN_ERR "sonic_interrupt: irq %d for unknown device.\n", irq);
                return IRQ_NONE;
        }
 
-       lp = (struct sonic_local *) dev->priv;
-
-       status = SONIC_READ(SONIC_ISR);
-       SONIC_WRITE(SONIC_ISR, 0x7fff); /* clear all bits */
-
-       if (sonic_debug > 2)
-               printk("sonic_interrupt: ISR=%x\n", status);
-
-       if (status & SONIC_INT_PKTRX) {
-               sonic_rx(dev);  /* got packet(s) */
-       }
-
-       if (status & SONIC_INT_TXDN) {
-               int dirty_tx = lp->dirty_tx;
-
-               while (dirty_tx < lp->cur_tx) {
-                       int entry = dirty_tx & SONIC_TDS_MASK;
-                       int status = lp->tda[entry].tx_status;
+       if (!(status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT))
+               return IRQ_NONE;
 
-                       if (sonic_debug > 3)
-                               printk
-                                   ("sonic_interrupt: status %d, cur_tx %d, dirty_tx %d\n",
-                                    status, lp->cur_tx, lp->dirty_tx);
+       do {
+               if (status & SONIC_INT_PKTRX) {
+                       if (sonic_debug > 2)
+                               printk("%s: packet rx\n", dev->name);
+                       sonic_rx(dev);  /* got packet(s) */
+                       SONIC_WRITE(SONIC_ISR, SONIC_INT_PKTRX); /* clear the interrupt */
+               }
 
-                       if (status == 0) {
-                               /* It still hasn't been Txed, kick the sonic again */
-                               SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP);
-                               break;
-                       }
+               if (status & SONIC_INT_TXDN) {
+                       int entry = lp->cur_tx;
+                       int td_status;
+                       int freed_some = 0;
 
-                       /* put back EOL and free descriptor */
-                       lp->tda[entry].tx_frag_count = 0;
-                       lp->tda[entry].tx_status = 0;
-
-                       if (status & 0x0001)
-                               lp->stats.tx_packets++;
-                       else {
-                               lp->stats.tx_errors++;
-                               if (status & 0x0642)
-                                       lp->stats.tx_aborted_errors++;
-                               if (status & 0x0180)
-                                       lp->stats.tx_carrier_errors++;
-                               if (status & 0x0020)
-                                       lp->stats.tx_window_errors++;
-                               if (status & 0x0004)
-                                       lp->stats.tx_fifo_errors++;
-                       }
+                       /* At this point, cur_tx is the index of a TD that is one of:
+                        *   unallocated/freed                          (status set   & tx_skb[entry] clear)
+                        *   allocated and sent                         (status set   & tx_skb[entry] set  )
+                        *   allocated and not yet sent                 (status clear & tx_skb[entry] set  )
+                        *   still being allocated by sonic_send_packet (status clear & tx_skb[entry] clear)
+                        */
 
-                       /* We must free the original skb */
-                       if (lp->tx_skb[entry]) {
+                       if (sonic_debug > 2)
+                               printk("%s: tx done\n", dev->name);
+
+                       while (lp->tx_skb[entry] != NULL) {
+                               if ((td_status = sonic_tda_get(dev, entry, SONIC_TD_STATUS)) == 0)
+                                       break;
+
+                               if (td_status & 0x0001) {
+                                       lp->stats.tx_packets++;
+                                       lp->stats.tx_bytes += sonic_tda_get(dev, entry, SONIC_TD_PKTSIZE);
+                               } else {
+                                       lp->stats.tx_errors++;
+                                       if (td_status & 0x0642)
+                                               lp->stats.tx_aborted_errors++;
+                                       if (td_status & 0x0180)
+                                               lp->stats.tx_carrier_errors++;
+                                       if (td_status & 0x0020)
+                                               lp->stats.tx_window_errors++;
+                                       if (td_status & 0x0004)
+                                               lp->stats.tx_fifo_errors++;
+                               }
+
+                               /* We must free the original skb */
                                dev_kfree_skb_irq(lp->tx_skb[entry]);
-                               lp->tx_skb[entry] = 0;
+                               lp->tx_skb[entry] = NULL;
+                               /* and unmap DMA buffer */
+                               dma_unmap_single(lp->device, lp->tx_laddr[entry], lp->tx_len[entry], DMA_TO_DEVICE);
+                               lp->tx_laddr[entry] = (dma_addr_t)0;
+                               freed_some = 1;
+
+                               if (sonic_tda_get(dev, entry, SONIC_TD_LINK) & SONIC_EOL) {
+                                       entry = (entry + 1) & SONIC_TDS_MASK;
+                                       break;
+                               }
+                               entry = (entry + 1) & SONIC_TDS_MASK;
                        }
-                       /* and the VDMA address */
-                       vdma_free(lp->tx_laddr[entry]);
-                       dirty_tx++;
-               }
 
-               if (lp->tx_full
-                   && dirty_tx + SONIC_NUM_TDS > lp->cur_tx + 2) {
-                       /* The ring is no longer full, clear tbusy. */
-                       lp->tx_full = 0;
-                       netif_wake_queue(dev);
+                       if (freed_some || lp->tx_skb[entry] == NULL)
+                               netif_wake_queue(dev);  /* The ring is no longer full */
+                       lp->cur_tx = entry;
+                       SONIC_WRITE(SONIC_ISR, SONIC_INT_TXDN); /* clear the interrupt */
                }
 
-               lp->dirty_tx = dirty_tx;
-       }
+               /*
+                * check error conditions
+                */
+               if (status & SONIC_INT_RFO) {
+                       if (sonic_debug > 1)
+                               printk("%s: rx fifo overrun\n", dev->name);
+                       lp->stats.rx_fifo_errors++;
+                       SONIC_WRITE(SONIC_ISR, SONIC_INT_RFO); /* clear the interrupt */
+               }
+               if (status & SONIC_INT_RDE) {
+                       if (sonic_debug > 1)
+                               printk("%s: rx descriptors exhausted\n", dev->name);
+                       lp->stats.rx_dropped++;
+                       SONIC_WRITE(SONIC_ISR, SONIC_INT_RDE); /* clear the interrupt */
+               }
+               if (status & SONIC_INT_RBAE) {
+                       if (sonic_debug > 1)
+                               printk("%s: rx buffer area exceeded\n", dev->name);
+                       lp->stats.rx_dropped++;
+                       SONIC_WRITE(SONIC_ISR, SONIC_INT_RBAE); /* clear the interrupt */
+               }
 
-       /*
-        * check error conditions
-        */
-       if (status & SONIC_INT_RFO) {
-               printk("%s: receive fifo underrun\n", dev->name);
-               lp->stats.rx_fifo_errors++;
-       }
-       if (status & SONIC_INT_RDE) {
-               printk("%s: receive descriptors exhausted\n", dev->name);
-               lp->stats.rx_dropped++;
-       }
-       if (status & SONIC_INT_RBE) {
-               printk("%s: receive buffer exhausted\n", dev->name);
-               lp->stats.rx_dropped++;
-       }
-       if (status & SONIC_INT_RBAE) {
-               printk("%s: receive buffer area exhausted\n", dev->name);
-               lp->stats.rx_dropped++;
-       }
+               /* counter overruns; all counters are 16bit wide */
+               if (status & SONIC_INT_FAE) {
+                       lp->stats.rx_frame_errors += 65536;
+                       SONIC_WRITE(SONIC_ISR, SONIC_INT_FAE); /* clear the interrupt */
+               }
+               if (status & SONIC_INT_CRC) {
+                       lp->stats.rx_crc_errors += 65536;
+                       SONIC_WRITE(SONIC_ISR, SONIC_INT_CRC); /* clear the interrupt */
+               }
+               if (status & SONIC_INT_MP) {
+                       lp->stats.rx_missed_errors += 65536;
+                       SONIC_WRITE(SONIC_ISR, SONIC_INT_MP); /* clear the interrupt */
+               }
 
-       /* counter overruns; all counters are 16bit wide */
-       if (status & SONIC_INT_FAE)
-               lp->stats.rx_frame_errors += 65536;
-       if (status & SONIC_INT_CRC)
-               lp->stats.rx_crc_errors += 65536;
-       if (status & SONIC_INT_MP)
-               lp->stats.rx_missed_errors += 65536;
+               /* transmit error */
+               if (status & SONIC_INT_TXER) {
+                       if ((SONIC_READ(SONIC_TCR) & SONIC_TCR_FU) && (sonic_debug > 2))
+                               printk(KERN_ERR "%s: tx fifo underrun\n", dev->name);
+                       SONIC_WRITE(SONIC_ISR, SONIC_INT_TXER); /* clear the interrupt */
+               }
 
-       /* transmit error */
-       if (status & SONIC_INT_TXER)
-               lp->stats.tx_errors++;
+               /* bus retry */
+               if (status & SONIC_INT_BR) {
+                       printk(KERN_ERR "%s: Bus retry occurred! Device interrupt disabled.\n",
+                               dev->name);
+                       /* ... to help debug DMA problems causing endless interrupts. */
+                       /* Bounce the eth interface to turn on the interrupt again. */
+                       SONIC_WRITE(SONIC_IMR, 0);
+                       SONIC_WRITE(SONIC_ISR, SONIC_INT_BR); /* clear the interrupt */
+               }
 
-       /*
-        * clear interrupt bits and return
-        */
-       SONIC_WRITE(SONIC_ISR, status);
+               /* load CAM done */
+               if (status & SONIC_INT_LCD)
+                       SONIC_WRITE(SONIC_ISR, SONIC_INT_LCD); /* clear the interrupt */
+       } while((status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT));
        return IRQ_HANDLED;
 }
 
 /*
- * We have a good packet(s), get it/them out of the buffers.
+ * We have a good packet(s), pass it/them up the network stack.
  */
 static void sonic_rx(struct net_device *dev)
 {
-       unsigned int base_addr = dev->base_addr;
-       struct sonic_local *lp = (struct sonic_local *) dev->priv;
-       sonic_rd_t *rd = &lp->rda[lp->cur_rx & SONIC_RDS_MASK];
+       struct sonic_local *lp = netdev_priv(dev);
        int status;
-
-       while (rd->in_use == 0) {
-               struct sk_buff *skb;
+       int entry = lp->cur_rx;
+
+       while (sonic_rda_get(dev, entry, SONIC_RD_IN_USE) == 0) {
+               struct sk_buff *used_skb;
+               struct sk_buff *new_skb;
+               dma_addr_t new_laddr;
+               u16 bufadr_l;
+               u16 bufadr_h;
                int pkt_len;
-               unsigned char *pkt_ptr;
 
-               status = rd->rx_status;
-               if (sonic_debug > 3)
-                       printk("status %x, cur_rx %d, cur_rra %x\n",
-                              status, lp->cur_rx, lp->cur_rra);
+               status = sonic_rda_get(dev, entry, SONIC_RD_STATUS);
                if (status & SONIC_RCR_PRX) {
-                       pkt_len = rd->rx_pktlen;
-                       pkt_ptr =
-                           (char *)
-                           sonic_chiptomem((rd->rx_pktptr_h << 16) +
-                                           rd->rx_pktptr_l);
-
-                       if (sonic_debug > 3)
-                               printk
-                                   ("pktptr %p (rba %p) h:%x l:%x, bsize h:%x l:%x\n",
-                                    pkt_ptr, lp->rba, rd->rx_pktptr_h,
-                                    rd->rx_pktptr_l,
-                                    SONIC_READ(SONIC_RBWC1),
-                                    SONIC_READ(SONIC_RBWC0));
-
                        /* Malloc up new buffer. */
-                       skb = dev_alloc_skb(pkt_len + 2);
-                       if (skb == NULL) {
-                               printk
-                                   ("%s: Memory squeeze, dropping packet.\n",
-                                    dev->name);
+                       new_skb = dev_alloc_skb(SONIC_RBSIZE + 2);
+                       if (new_skb == NULL) {
+                               printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name);
+                               lp->stats.rx_dropped++;
+                               break;
+                       }
+                       new_skb->dev = dev;
+                       /* provide 16 byte IP header alignment unless DMA requires otherwise */
+                       if(SONIC_BUS_SCALE(lp->dma_bitmode) == 2)
+                               skb_reserve(new_skb, 2); 
+
+                       new_laddr = dma_map_single(lp->device, skb_put(new_skb, SONIC_RBSIZE),
+                                              SONIC_RBSIZE, DMA_FROM_DEVICE);
+                       if (!new_laddr) {
+                               dev_kfree_skb(new_skb);
+                               printk(KERN_ERR "%s: Failed to map rx buffer, dropping packet.\n", dev->name);
                                lp->stats.rx_dropped++;
                                break;
                        }
-                       skb->dev = dev;
-                       skb_reserve(skb, 2);    /* 16 byte align */
-                       skb_put(skb, pkt_len);  /* Make room */
-                       eth_copy_and_sum(skb, pkt_ptr, pkt_len, 0);
-                       skb->protocol = eth_type_trans(skb, dev);
-                       netif_rx(skb);  /* pass the packet to upper layers */
+
+                       /* now we have a new skb to replace it, pass the used one up the stack */
+                       dma_unmap_single(lp->device, lp->rx_laddr[entry], SONIC_RBSIZE, DMA_FROM_DEVICE);
+                       used_skb = lp->rx_skb[entry];
+                       pkt_len = sonic_rda_get(dev, entry, SONIC_RD_PKTLEN);
+                       skb_trim(used_skb, pkt_len);
+                       used_skb->protocol = eth_type_trans(used_skb, dev);
+                       netif_rx(used_skb);
                        dev->last_rx = jiffies;
                        lp->stats.rx_packets++;
                        lp->stats.rx_bytes += pkt_len;
 
+                       /* and insert the new skb */
+                       lp->rx_laddr[entry] = new_laddr;
+                       lp->rx_skb[entry] = new_skb;
+
+                       bufadr_l = (unsigned long)new_laddr & 0xffff;
+                       bufadr_h = (unsigned long)new_laddr >> 16;
+                       sonic_rra_put(dev, entry, SONIC_RR_BUFADR_L, bufadr_l);
+                       sonic_rra_put(dev, entry, SONIC_RR_BUFADR_H, bufadr_h);
                } else {
                        /* This should only happen, if we enable accepting broken packets. */
                        lp->stats.rx_errors++;
@@ -341,29 +498,35 @@ static void sonic_rx(struct net_device *dev)
                        if (status & SONIC_RCR_CRCR)
                                lp->stats.rx_crc_errors++;
                }
-
-               rd->in_use = 1;
-               rd = &lp->rda[(++lp->cur_rx) & SONIC_RDS_MASK];
-               /* now give back the buffer to the receive buffer area */
                if (status & SONIC_RCR_LPKT) {
                        /*
-                        * this was the last packet out of the current receice buffer
+                        * this was the last packet out of the current receive buffer
                         * give the buffer back to the SONIC
                         */
-                       lp->cur_rra += sizeof(sonic_rr_t);
-                       if (lp->cur_rra >
-                           (lp->rra_laddr +
-                            (SONIC_NUM_RRS -
-                             1) * sizeof(sonic_rr_t))) lp->cur_rra =
-                                   lp->rra_laddr;
-                       SONIC_WRITE(SONIC_RWP, lp->cur_rra & 0xffff);
+                       lp->cur_rwp += SIZEOF_SONIC_RR * SONIC_BUS_SCALE(lp->dma_bitmode);
+                       if (lp->cur_rwp >= lp->rra_end) lp->cur_rwp = lp->rra_laddr & 0xffff;
+                       SONIC_WRITE(SONIC_RWP, lp->cur_rwp);
+                       if (SONIC_READ(SONIC_ISR) & SONIC_INT_RBE) {
+                               if (sonic_debug > 2)
+                                       printk("%s: rx buffer exhausted\n", dev->name);
+                               SONIC_WRITE(SONIC_ISR, SONIC_INT_RBE); /* clear the flag */
+                       }
                } else
-                       printk
-                           ("%s: rx desc without RCR_LPKT. Shouldn't happen !?\n",
+                       printk(KERN_ERR "%s: rx desc without RCR_LPKT. Shouldn't happen !?\n",
                             dev->name);
+               /*
+                * give back the descriptor
+                */
+               sonic_rda_put(dev, entry, SONIC_RD_LINK,
+                       sonic_rda_get(dev, entry, SONIC_RD_LINK) | SONIC_EOL);
+               sonic_rda_put(dev, entry, SONIC_RD_IN_USE, 1);
+               sonic_rda_put(dev, lp->eol_rx, SONIC_RD_LINK,
+                       sonic_rda_get(dev, lp->eol_rx, SONIC_RD_LINK) & ~SONIC_EOL);
+               lp->eol_rx = entry;
+               lp->cur_rx = entry = (entry + 1) & SONIC_RDS_MASK;
        }
        /*
-        * If any worth-while packets have been received, dev_rint()
+        * If any worth-while packets have been received, netif_rx()
         * has done a mark_bh(NET_BH) for us and will work on them
         * when we get to the bottom-half routine.
         */
@@ -376,8 +539,7 @@ static void sonic_rx(struct net_device *dev)
  */
 static struct net_device_stats *sonic_get_stats(struct net_device *dev)
 {
-       struct sonic_local *lp = (struct sonic_local *) dev->priv;
-       unsigned int base_addr = dev->base_addr;
+       struct sonic_local *lp = netdev_priv(dev);
 
        /* read the tally counter from the SONIC and reset them */
        lp->stats.rx_crc_errors += SONIC_READ(SONIC_CRCT);
@@ -396,8 +558,7 @@ static struct net_device_stats *sonic_get_stats(struct net_device *dev)
  */
 static void sonic_multicast_list(struct net_device *dev)
 {
-       struct sonic_local *lp = (struct sonic_local *) dev->priv;
-       unsigned int base_addr = dev->base_addr;
+       struct sonic_local *lp = netdev_priv(dev);
        unsigned int rcr;
        struct dev_mc_list *dmi = dev->mc_list;
        unsigned char *addr;
@@ -413,20 +574,15 @@ static void sonic_multicast_list(struct net_device *dev)
                        rcr |= SONIC_RCR_AMC;
                } else {
                        if (sonic_debug > 2)
-                               printk
-                                   ("sonic_multicast_list: mc_count %d\n",
-                                    dev->mc_count);
-                       lp->cda.cam_enable = 1; /* always enable our own address */
+                               printk("sonic_multicast_list: mc_count %d\n", dev->mc_count);
+                       sonic_set_cam_enable(dev, 1);  /* always enable our own address */
                        for (i = 1; i <= dev->mc_count; i++) {
                                addr = dmi->dmi_addr;
                                dmi = dmi->next;
-                               lp->cda.cam_desc[i].cam_cap0 =
-                                   addr[1] << 8 | addr[0];
-                               lp->cda.cam_desc[i].cam_cap1 =
-                                   addr[3] << 8 | addr[2];
-                               lp->cda.cam_desc[i].cam_cap2 =
-                                   addr[5] << 8 | addr[4];
-                               lp->cda.cam_enable |= (1 << i);
+                               sonic_cda_put(dev, i, SONIC_CD_CAP0, addr[1] << 8 | addr[0]);
+                               sonic_cda_put(dev, i, SONIC_CD_CAP1, addr[3] << 8 | addr[2]);
+                               sonic_cda_put(dev, i, SONIC_CD_CAP2, addr[5] << 8 | addr[4]);
+                               sonic_set_cam_enable(dev, sonic_get_cam_enable(dev) | (1 << i));
                        }
                        SONIC_WRITE(SONIC_CDC, 16);
                        /* issue Load CAM command */
@@ -447,19 +603,16 @@ static void sonic_multicast_list(struct net_device *dev)
  */
 static int sonic_init(struct net_device *dev)
 {
-       unsigned int base_addr = dev->base_addr;
        unsigned int cmd;
-       struct sonic_local *lp = (struct sonic_local *) dev->priv;
-       unsigned int rra_start;
-       unsigned int rra_end;
+       struct sonic_local *lp = netdev_priv(dev);
        int i;
 
        /*
         * put the Sonic into software-reset mode and
         * disable all interrupts
         */
-       SONIC_WRITE(SONIC_ISR, 0x7fff);
        SONIC_WRITE(SONIC_IMR, 0);
+       SONIC_WRITE(SONIC_ISR, 0x7fff);
        SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
 
        /*
@@ -475,34 +628,32 @@ static int sonic_init(struct net_device *dev)
        if (sonic_debug > 2)
                printk("sonic_init: initialize receive resource area\n");
 
-       rra_start = lp->rra_laddr & 0xffff;
-       rra_end =
-           (rra_start + (SONIC_NUM_RRS * sizeof(sonic_rr_t))) & 0xffff;
-
        for (i = 0; i < SONIC_NUM_RRS; i++) {
-               lp->rra[i].rx_bufadr_l =
-                   (lp->rba_laddr + i * SONIC_RBSIZE) & 0xffff;
-               lp->rra[i].rx_bufadr_h =
-                   (lp->rba_laddr + i * SONIC_RBSIZE) >> 16;
-               lp->rra[i].rx_bufsize_l = SONIC_RBSIZE >> 1;
-               lp->rra[i].rx_bufsize_h = 0;
+               u16 bufadr_l = (unsigned long)lp->rx_laddr[i] & 0xffff;
+               u16 bufadr_h = (unsigned long)lp->rx_laddr[i] >> 16;
+               sonic_rra_put(dev, i, SONIC_RR_BUFADR_L, bufadr_l);
+               sonic_rra_put(dev, i, SONIC_RR_BUFADR_H, bufadr_h);
+               sonic_rra_put(dev, i, SONIC_RR_BUFSIZE_L, SONIC_RBSIZE >> 1);
+               sonic_rra_put(dev, i, SONIC_RR_BUFSIZE_H, 0);
        }
 
        /* initialize all RRA registers */
-       SONIC_WRITE(SONIC_RSA, rra_start);
-       SONIC_WRITE(SONIC_REA, rra_end);
-       SONIC_WRITE(SONIC_RRP, rra_start);
-       SONIC_WRITE(SONIC_RWP, rra_end);
+       lp->rra_end = (lp->rra_laddr + SONIC_NUM_RRS * SIZEOF_SONIC_RR *
+                                       SONIC_BUS_SCALE(lp->dma_bitmode)) & 0xffff;
+       lp->cur_rwp = (lp->rra_laddr + (SONIC_NUM_RRS - 1) * SIZEOF_SONIC_RR *
+                                       SONIC_BUS_SCALE(lp->dma_bitmode)) & 0xffff;
+  
+       SONIC_WRITE(SONIC_RSA, lp->rra_laddr & 0xffff);
+       SONIC_WRITE(SONIC_REA, lp->rra_end);
+       SONIC_WRITE(SONIC_RRP, lp->rra_laddr & 0xffff);
+       SONIC_WRITE(SONIC_RWP, lp->cur_rwp);
        SONIC_WRITE(SONIC_URRA, lp->rra_laddr >> 16);
-       SONIC_WRITE(SONIC_EOBC, (SONIC_RBSIZE - 2) >> 1);
-
-       lp->cur_rra =
-           lp->rra_laddr + (SONIC_NUM_RRS - 1) * sizeof(sonic_rr_t);
+       SONIC_WRITE(SONIC_EOBC, (SONIC_RBSIZE >> 1) - (lp->dma_bitmode ? 2 : 1));
 
        /* load the resource pointers */
        if (sonic_debug > 3)
-               printk("sonic_init: issueing RRRA command\n");
-
+               printk("sonic_init: issuing RRRA command\n");
+  
        SONIC_WRITE(SONIC_CMD, SONIC_CR_RRRA);
        i = 0;
        while (i++ < 100) {
@@ -511,27 +662,30 @@ static int sonic_init(struct net_device *dev)
        }
 
        if (sonic_debug > 2)
-               printk("sonic_init: status=%x\n", SONIC_READ(SONIC_CMD));
-
+               printk("sonic_init: status=%x i=%d\n", SONIC_READ(SONIC_CMD), i);
+    
        /*
         * Initialize the receive descriptors so that they
         * become a circular linked list, ie. let the last
         * descriptor point to the first again.
         */
        if (sonic_debug > 2)
-               printk("sonic_init: initialize receive descriptors\n");
-       for (i = 0; i < SONIC_NUM_RDS; i++) {
-               lp->rda[i].rx_status = 0;
-               lp->rda[i].rx_pktlen = 0;
-               lp->rda[i].rx_pktptr_l = 0;
-               lp->rda[i].rx_pktptr_h = 0;
-               lp->rda[i].rx_seqno = 0;
-               lp->rda[i].in_use = 1;
-               lp->rda[i].link =
-                   lp->rda_laddr + (i + 1) * sizeof(sonic_rd_t);
+               printk("sonic_init: initialize receive descriptors\n");      
+       for (i=0; i<SONIC_NUM_RDS; i++) {
+               sonic_rda_put(dev, i, SONIC_RD_STATUS, 0);
+               sonic_rda_put(dev, i, SONIC_RD_PKTLEN, 0);
+               sonic_rda_put(dev, i, SONIC_RD_PKTPTR_L, 0);
+               sonic_rda_put(dev, i, SONIC_RD_PKTPTR_H, 0);
+               sonic_rda_put(dev, i, SONIC_RD_SEQNO, 0);
+               sonic_rda_put(dev, i, SONIC_RD_IN_USE, 1);
+               sonic_rda_put(dev, i, SONIC_RD_LINK,
+                       lp->rda_laddr +
+                       ((i+1) * SIZEOF_SONIC_RD * SONIC_BUS_SCALE(lp->dma_bitmode)));
        }
        /* fix last descriptor */
-       lp->rda[SONIC_NUM_RDS - 1].link = lp->rda_laddr;
+       sonic_rda_put(dev, SONIC_NUM_RDS - 1, SONIC_RD_LINK,
+               (lp->rda_laddr & 0xffff) | SONIC_EOL);
+       lp->eol_rx = SONIC_NUM_RDS - 1;
        lp->cur_rx = 0;
        SONIC_WRITE(SONIC_URDA, lp->rda_laddr >> 16);
        SONIC_WRITE(SONIC_CRDA, lp->rda_laddr & 0xffff);
@@ -542,34 +696,34 @@ static int sonic_init(struct net_device *dev)
        if (sonic_debug > 2)
                printk("sonic_init: initialize transmit descriptors\n");
        for (i = 0; i < SONIC_NUM_TDS; i++) {
-               lp->tda[i].tx_status = 0;
-               lp->tda[i].tx_config = 0;
-               lp->tda[i].tx_pktsize = 0;
-               lp->tda[i].tx_frag_count = 0;
-               lp->tda[i].link =
-                   (lp->tda_laddr +
-                    (i + 1) * sizeof(sonic_td_t)) | SONIC_END_OF_LINKS;
+               sonic_tda_put(dev, i, SONIC_TD_STATUS, 0);
+               sonic_tda_put(dev, i, SONIC_TD_CONFIG, 0);
+               sonic_tda_put(dev, i, SONIC_TD_PKTSIZE, 0);
+               sonic_tda_put(dev, i, SONIC_TD_FRAG_COUNT, 0);
+               sonic_tda_put(dev, i, SONIC_TD_LINK,
+                       (lp->tda_laddr & 0xffff) +
+                       (i + 1) * SIZEOF_SONIC_TD * SONIC_BUS_SCALE(lp->dma_bitmode));
+               lp->tx_skb[i] = NULL;
        }
-       lp->tda[SONIC_NUM_TDS - 1].link =
-           (lp->tda_laddr & 0xffff) | SONIC_END_OF_LINKS;
+       /* fix last descriptor */
+       sonic_tda_put(dev, SONIC_NUM_TDS - 1, SONIC_TD_LINK,
+               (lp->tda_laddr & 0xffff));
 
        SONIC_WRITE(SONIC_UTDA, lp->tda_laddr >> 16);
        SONIC_WRITE(SONIC_CTDA, lp->tda_laddr & 0xffff);
-       lp->cur_tx = lp->dirty_tx = 0;
-
+       lp->cur_tx = lp->next_tx = 0;
+       lp->eol_tx = SONIC_NUM_TDS - 1;
+    
        /*
         * put our own address to CAM desc[0]
         */
-       lp->cda.cam_desc[0].cam_cap0 =
-           dev->dev_addr[1] << 8 | dev->dev_addr[0];
-       lp->cda.cam_desc[0].cam_cap1 =
-           dev->dev_addr[3] << 8 | dev->dev_addr[2];
-       lp->cda.cam_desc[0].cam_cap2 =
-           dev->dev_addr[5] << 8 | dev->dev_addr[4];
-       lp->cda.cam_enable = 1;
+       sonic_cda_put(dev, 0, SONIC_CD_CAP0, dev->dev_addr[1] << 8 | dev->dev_addr[0]);
+       sonic_cda_put(dev, 0, SONIC_CD_CAP1, dev->dev_addr[3] << 8 | dev->dev_addr[2]);
+       sonic_cda_put(dev, 0, SONIC_CD_CAP2, dev->dev_addr[5] << 8 | dev->dev_addr[4]);
+       sonic_set_cam_enable(dev, 1);
 
        for (i = 0; i < 16; i++)
-               lp->cda.cam_desc[i].cam_entry_pointer = i;
+               sonic_cda_put(dev, i, SONIC_CD_ENTRY_POINTER, i);
 
        /*
         * initialize CAM registers
@@ -588,8 +742,8 @@ static int sonic_init(struct net_device *dev)
                        break;
        }
        if (sonic_debug > 2) {
-               printk("sonic_init: CMD=%x, ISR=%x\n",
-                      SONIC_READ(SONIC_CMD), SONIC_READ(SONIC_ISR));
+               printk("sonic_init: CMD=%x, ISR=%x\n, i=%d",
+                      SONIC_READ(SONIC_CMD), SONIC_READ(SONIC_ISR), i);
        }
 
        /*
@@ -604,7 +758,7 @@ static int sonic_init(struct net_device *dev)
 
        cmd = SONIC_READ(SONIC_CMD);
        if ((cmd & SONIC_CR_RXEN) == 0 || (cmd & SONIC_CR_STP) == 0)
-               printk("sonic_init: failed, status=%x\n", cmd);
+               printk(KERN_ERR "sonic_init: failed, status=%x\n", cmd);
 
        if (sonic_debug > 2)
                printk("sonic_init: new status=%x\n",
index c4a6d58e4afbfd592caa466aaddbf699ea5b3a6f..cede969a8baae88fcfc0a8083a049999d84cb11d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Helpfile for sonic.c
+ * Header file for sonic.c
  *
  * (C) Waldorf Electronics, Germany
  * Written by Andreas Busse
@@ -9,10 +9,16 @@
  * and pad structure members must be exchanged. Also, the structures
  * need to be changed accordingly to the bus size. 
  *
- * 981229 MSch:        did just that for the 68k Mac port (32 bit, big endian),
- *             see CONFIG_MACSONIC branch below.
+ * 981229 MSch:        did just that for the 68k Mac port (32 bit, big endian)
  *
+ * 990611 David Huggins-Daines <dhd@debian.org>: This machine abstraction
+ * does not cope with 16-bit bus sizes very well.  Therefore I have
+ * rewritten it with ugly macros and evil inlines.
+ *
+ * 050625 Finn Thain: introduced more 32-bit cards and dhd's support
+ *        for 16-bit cards (from the mac68k project).
  */
+
 #ifndef SONIC_H
 #define SONIC_H
 
@@ -83,6 +89,7 @@
 /*
  * Error counters
  */
+
 #define SONIC_CRCT              0x2c
 #define SONIC_FAET              0x2d
 #define SONIC_MPT               0x2e
 
 #define SONIC_INT_BR           0x4000
 #define SONIC_INT_HBL          0x2000
-#define SONIC_INT_LCD           0x1000
-#define SONIC_INT_PINT          0x0800
-#define SONIC_INT_PKTRX         0x0400
-#define SONIC_INT_TXDN          0x0200
-#define SONIC_INT_TXER          0x0100
-#define SONIC_INT_TC            0x0080
-#define SONIC_INT_RDE           0x0040
-#define SONIC_INT_RBE           0x0020
+#define SONIC_INT_LCD          0x1000
+#define SONIC_INT_PINT         0x0800
+#define SONIC_INT_PKTRX                0x0400
+#define SONIC_INT_TXDN         0x0200
+#define SONIC_INT_TXER         0x0100
+#define SONIC_INT_TC           0x0080
+#define SONIC_INT_RDE          0x0040
+#define SONIC_INT_RBE          0x0020
 #define SONIC_INT_RBAE         0x0010
 #define SONIC_INT_CRC          0x0008
 #define SONIC_INT_FAE          0x0004
  * The interrupts we allow.
  */
 
-#define SONIC_IMR_DEFAULT      (SONIC_INT_BR | \
-                               SONIC_INT_LCD | \
-                                SONIC_INT_PINT | \
+#define SONIC_IMR_DEFAULT     SONIC_INT_BR | \
+                                SONIC_INT_LCD | \
+                                SONIC_INT_RFO | \
                                 SONIC_INT_PKTRX | \
                                 SONIC_INT_TXDN | \
                                 SONIC_INT_TXER | \
                                 SONIC_INT_RDE | \
-                                SONIC_INT_RBE | \
                                 SONIC_INT_RBAE | \
                                 SONIC_INT_CRC | \
                                 SONIC_INT_FAE | \
                                 SONIC_INT_MP)
 
 
-#define        SONIC_END_OF_LINKS      0x0001
-
-
-#ifdef CONFIG_MACSONIC
-/*
- * Big endian like structures on 680x0 Macs
- */
-
-typedef struct {
-       u32 rx_bufadr_l;        /* receive buffer ptr */
-       u32 rx_bufadr_h;
-
-       u32 rx_bufsize_l;       /* no. of words in the receive buffer */
-       u32 rx_bufsize_h;
-} sonic_rr_t;
-
-/*
- * Sonic receive descriptor. Receive descriptors are
- * kept in a linked list of these structures.
- */
-
-typedef struct {
-       SREGS_PAD(pad0);
-       u16 rx_status;          /* status after reception of a packet */
-        SREGS_PAD(pad1);
-       u16 rx_pktlen;          /* length of the packet incl. CRC */
-
-       /*
-        * Pointers to the location in the receive buffer area (RBA)
-        * where the packet resides. A packet is always received into
-        * a contiguous piece of memory.
-        */
-        SREGS_PAD(pad2);
-       u16 rx_pktptr_l;
-        SREGS_PAD(pad3);
-       u16 rx_pktptr_h;
-
-        SREGS_PAD(pad4);
-       u16 rx_seqno;           /* sequence no. */
-
-        SREGS_PAD(pad5);
-       u16 link;               /* link to next RDD (end if EOL bit set) */
-
-       /*
-        * Owner of this descriptor, 0= driver, 1=sonic
-        */
-
-        SREGS_PAD(pad6);
-       u16 in_use;
-
-       caddr_t rda_next;       /* pointer to next RD */
-} sonic_rd_t;
-
-
-/*
- * Describes a Transmit Descriptor
- */
-typedef struct {
-       SREGS_PAD(pad0);
-       u16 tx_status;          /* status after transmission of a packet */
-        SREGS_PAD(pad1);
-       u16 tx_config;          /* transmit configuration for this packet */
-        SREGS_PAD(pad2);
-       u16 tx_pktsize;         /* size of the packet to be transmitted */
-        SREGS_PAD(pad3);
-       u16 tx_frag_count;      /* no. of fragments */
-
-        SREGS_PAD(pad4);
-       u16 tx_frag_ptr_l;
-        SREGS_PAD(pad5);
-       u16 tx_frag_ptr_h;
-        SREGS_PAD(pad6);
-       u16 tx_frag_size;
-
-        SREGS_PAD(pad7);
-       u16 link;               /* ptr to next descriptor */
-} sonic_td_t;
-
-
-/*
- * Describes an entry in the CAM Descriptor Area.
- */
-
-typedef struct {
-       SREGS_PAD(pad0);
-       u16 cam_entry_pointer;
-        SREGS_PAD(pad1);
-       u16 cam_cap0;
-        SREGS_PAD(pad2);
-       u16 cam_cap1;
-        SREGS_PAD(pad3);
-       u16 cam_cap2;
-} sonic_cd_t;
-
+#define SONIC_EOL       0x0001
 #define CAM_DESCRIPTORS 16
 
-
-typedef struct {
-       sonic_cd_t cam_desc[CAM_DESCRIPTORS];
-        SREGS_PAD(pad);
-       u16 cam_enable;
-} sonic_cda_t;
-
-#else                          /* original declarations, little endian 32 bit */
-
-/*
- * structure definitions
- */
-
-typedef struct {
-       u32 rx_bufadr_l;        /* receive buffer ptr */
-       u32 rx_bufadr_h;
-
-       u32 rx_bufsize_l;       /* no. of words in the receive buffer */
-       u32 rx_bufsize_h;
-} sonic_rr_t;
-
-/*
- * Sonic receive descriptor. Receive descriptors are
- * kept in a linked list of these structures.
- */
-
-typedef struct {
-       u16 rx_status;          /* status after reception of a packet */
-        SREGS_PAD(pad0);
-       u16 rx_pktlen;          /* length of the packet incl. CRC */
-        SREGS_PAD(pad1);
-
-       /*
-        * Pointers to the location in the receive buffer area (RBA)
-        * where the packet resides. A packet is always received into
-        * a contiguous piece of memory.
-        */
-       u16 rx_pktptr_l;
-        SREGS_PAD(pad2);
-       u16 rx_pktptr_h;
-        SREGS_PAD(pad3);
-
-       u16 rx_seqno;           /* sequence no. */
-        SREGS_PAD(pad4);
-
-       u16 link;               /* link to next RDD (end if EOL bit set) */
-        SREGS_PAD(pad5);
-
-       /*
-        * Owner of this descriptor, 0= driver, 1=sonic
-        */
-
-       u16 in_use;
-        SREGS_PAD(pad6);
-
-       caddr_t rda_next;       /* pointer to next RD */
-} sonic_rd_t;
-
-
-/*
- * Describes a Transmit Descriptor
- */
-typedef struct {
-       u16 tx_status;          /* status after transmission of a packet */
-        SREGS_PAD(pad0);
-       u16 tx_config;          /* transmit configuration for this packet */
-        SREGS_PAD(pad1);
-       u16 tx_pktsize;         /* size of the packet to be transmitted */
-        SREGS_PAD(pad2);
-       u16 tx_frag_count;      /* no. of fragments */
-        SREGS_PAD(pad3);
-
-       u16 tx_frag_ptr_l;
-        SREGS_PAD(pad4);
-       u16 tx_frag_ptr_h;
-        SREGS_PAD(pad5);
-       u16 tx_frag_size;
-        SREGS_PAD(pad6);
-
-       u16 link;               /* ptr to next descriptor */
-        SREGS_PAD(pad7);
-} sonic_td_t;
-
-
-/*
- * Describes an entry in the CAM Descriptor Area.
- */
-
-typedef struct {
-       u16 cam_entry_pointer;
-        SREGS_PAD(pad0);
-       u16 cam_cap0;
-        SREGS_PAD(pad1);
-       u16 cam_cap1;
-        SREGS_PAD(pad2);
-       u16 cam_cap2;
-        SREGS_PAD(pad3);
-} sonic_cd_t;
-
-#define CAM_DESCRIPTORS 16
-
-
-typedef struct {
-       sonic_cd_t cam_desc[CAM_DESCRIPTORS];
-       u16 cam_enable;
-        SREGS_PAD(pad);
-} sonic_cda_t;
-#endif                         /* endianness */
+/* Offsets in the various DMA buffers accessed by the SONIC */
+
+#define SONIC_BITMODE16 0
+#define SONIC_BITMODE32 1
+#define SONIC_BUS_SCALE(bitmode) ((bitmode) ? 4 : 2)
+/* Note!  These are all measured in bus-size units, so use SONIC_BUS_SCALE */
+#define SIZEOF_SONIC_RR 4
+#define SONIC_RR_BUFADR_L  0
+#define SONIC_RR_BUFADR_H  1
+#define SONIC_RR_BUFSIZE_L 2
+#define SONIC_RR_BUFSIZE_H 3
+
+#define SIZEOF_SONIC_RD 7
+#define SONIC_RD_STATUS   0
+#define SONIC_RD_PKTLEN   1
+#define SONIC_RD_PKTPTR_L 2
+#define SONIC_RD_PKTPTR_H 3
+#define SONIC_RD_SEQNO    4
+#define SONIC_RD_LINK     5
+#define SONIC_RD_IN_USE   6
+
+#define SIZEOF_SONIC_TD 8
+#define SONIC_TD_STATUS       0
+#define SONIC_TD_CONFIG       1
+#define SONIC_TD_PKTSIZE      2
+#define SONIC_TD_FRAG_COUNT   3
+#define SONIC_TD_FRAG_PTR_L   4
+#define SONIC_TD_FRAG_PTR_H   5
+#define SONIC_TD_FRAG_SIZE    6
+#define SONIC_TD_LINK         7
+
+#define SIZEOF_SONIC_CD 4
+#define SONIC_CD_ENTRY_POINTER 0
+#define SONIC_CD_CAP0          1
+#define SONIC_CD_CAP1          2
+#define SONIC_CD_CAP2          3
+
+#define SIZEOF_SONIC_CDA ((CAM_DESCRIPTORS * SIZEOF_SONIC_CD) + 1)
+#define SONIC_CDA_CAM_ENABLE   (CAM_DESCRIPTORS * SIZEOF_SONIC_CD)
 
 /*
  * Some tunables for the buffer areas. Power of 2 is required
@@ -426,44 +270,60 @@ typedef struct {
  *
  * MSch: use more buffer space for the slow m68k Macs!
  */
-#ifdef CONFIG_MACSONIC
-#define SONIC_NUM_RRS    32    /* number of receive resources */
-#define SONIC_NUM_RDS    SONIC_NUM_RRS /* number of receive descriptors */
-#define SONIC_NUM_TDS    32    /* number of transmit descriptors */
-#else
-#define SONIC_NUM_RRS    16    /* number of receive resources */
-#define SONIC_NUM_RDS    SONIC_NUM_RRS /* number of receive descriptors */
-#define SONIC_NUM_TDS    16    /* number of transmit descriptors */
-#endif
-#define SONIC_RBSIZE   1520    /* size of one resource buffer */
+#define SONIC_NUM_RRS   16            /* number of receive resources */
+#define SONIC_NUM_RDS   SONIC_NUM_RRS /* number of receive descriptors */
+#define SONIC_NUM_TDS   16            /* number of transmit descriptors */
 
-#define SONIC_RDS_MASK   (SONIC_NUM_RDS-1)
-#define SONIC_TDS_MASK   (SONIC_NUM_TDS-1)
+#define SONIC_RDS_MASK  (SONIC_NUM_RDS-1)
+#define SONIC_TDS_MASK  (SONIC_NUM_TDS-1)
 
+#define SONIC_RBSIZE   1520          /* size of one resource buffer */
+
+/* Again, measured in bus size units! */
+#define SIZEOF_SONIC_DESC (SIZEOF_SONIC_CDA    \
+       + (SIZEOF_SONIC_TD * SONIC_NUM_TDS)     \
+       + (SIZEOF_SONIC_RD * SONIC_NUM_RDS)     \
+       + (SIZEOF_SONIC_RR * SONIC_NUM_RRS))
 
 /* Information that need to be kept for each board. */
 struct sonic_local {
-       sonic_cda_t cda;        /* virtual CPU address of CDA */
-       sonic_td_t tda[SONIC_NUM_TDS];  /* transmit descriptor area */
-       sonic_rr_t rra[SONIC_NUM_RRS];  /* receive resource area */
-       sonic_rd_t rda[SONIC_NUM_RDS];  /* receive descriptor area */
-       struct sk_buff *tx_skb[SONIC_NUM_TDS];  /* skbuffs for packets to transmit */
-       unsigned int tx_laddr[SONIC_NUM_TDS];   /* logical DMA address fro skbuffs */
-       unsigned char *rba;     /* start of receive buffer areas */
-       unsigned int cda_laddr; /* logical DMA address of CDA */
-       unsigned int tda_laddr; /* logical DMA address of TDA */
-       unsigned int rra_laddr; /* logical DMA address of RRA */
-       unsigned int rda_laddr; /* logical DMA address of RDA */
-       unsigned int rba_laddr; /* logical DMA address of RBA */
-       unsigned int cur_rra;   /* current indexes to resource areas */
+       /* Bus size.  0 == 16 bits, 1 == 32 bits. */
+       int dma_bitmode;
+       /* Register offset within the longword (independent of endianness,
+          and varies from one type of Macintosh SONIC to another
+          (Aarrgh)) */
+       int reg_offset;
+       void *descriptors;
+       /* Crud.  These areas have to be within the same 64K.  Therefore
+       we allocate a desriptors page, and point these to places within it. */
+       void *cda;  /* CAM descriptor area */
+       void *tda;  /* Transmit descriptor area */
+       void *rra;  /* Receive resource area */
+       void *rda;  /* Receive descriptor area */
+       struct sk_buff* volatile rx_skb[SONIC_NUM_RRS]; /* packets to be received */
+       struct sk_buff* volatile tx_skb[SONIC_NUM_TDS]; /* packets to be transmitted */
+       unsigned int tx_len[SONIC_NUM_TDS]; /* lengths of tx DMA mappings */
+       /* Logical DMA addresses on MIPS, bus addresses on m68k
+        * (so "laddr" is a bit misleading) */
+       dma_addr_t descriptors_laddr;
+       u32 cda_laddr;              /* logical DMA address of CDA */
+       u32 tda_laddr;              /* logical DMA address of TDA */
+       u32 rra_laddr;              /* logical DMA address of RRA */
+       u32 rda_laddr;              /* logical DMA address of RDA */
+       dma_addr_t rx_laddr[SONIC_NUM_RRS]; /* logical DMA addresses of rx skbuffs */
+       dma_addr_t tx_laddr[SONIC_NUM_TDS]; /* logical DMA addresses of tx skbuffs */
+       unsigned int rra_end;
+       unsigned int cur_rwp;
        unsigned int cur_rx;
-       unsigned int cur_tx;
-       unsigned int dirty_tx;  /* last unacked transmit packet */
-       char tx_full;
+       unsigned int cur_tx;           /* first unacked transmit packet */
+       unsigned int eol_rx;
+       unsigned int eol_tx;           /* last unacked transmit packet */
+       unsigned int next_tx;          /* next free TD */
+       struct device *device;         /* generic device */
        struct net_device_stats stats;
 };
 
-#define TX_TIMEOUT 6
+#define TX_TIMEOUT (3 * HZ)
 
 /* Index to functions, as function prototypes. */
 
@@ -477,6 +337,114 @@ static void sonic_multicast_list(struct net_device *dev);
 static int sonic_init(struct net_device *dev);
 static void sonic_tx_timeout(struct net_device *dev);
 
+/* Internal inlines for reading/writing DMA buffers.  Note that bus
+   size and endianness matter here, whereas they don't for registers,
+   as far as we can tell. */
+/* OpenBSD calls this "SWO".  I'd like to think that sonic_buf_put()
+   is a much better name. */
+static inline void sonic_buf_put(void* base, int bitmode,
+                                int offset, __u16 val)
+{
+       if (bitmode)
+#ifdef __BIG_ENDIAN
+               ((__u16 *) base + (offset*2))[1] = val;
+#else
+               ((__u16 *) base + (offset*2))[0] = val;
+#endif
+       else
+               ((__u16 *) base)[offset] = val;
+}
+
+static inline __u16 sonic_buf_get(void* base, int bitmode,
+                                 int offset)
+{
+       if (bitmode)
+#ifdef __BIG_ENDIAN
+               return ((volatile __u16 *) base + (offset*2))[1];
+#else
+               return ((volatile __u16 *) base + (offset*2))[0];
+#endif
+       else
+               return ((volatile __u16 *) base)[offset];
+}
+
+/* Inlines that you should actually use for reading/writing DMA buffers */
+static inline void sonic_cda_put(struct net_device* dev, int entry,
+                                int offset, __u16 val)
+{
+       struct sonic_local* lp = (struct sonic_local *) dev->priv;
+       sonic_buf_put(lp->cda, lp->dma_bitmode,
+                     (entry * SIZEOF_SONIC_CD) + offset, val);
+}
+
+static inline __u16 sonic_cda_get(struct net_device* dev, int entry,
+                                 int offset)
+{
+       struct sonic_local* lp = (struct sonic_local *) dev->priv;
+       return sonic_buf_get(lp->cda, lp->dma_bitmode,
+                            (entry * SIZEOF_SONIC_CD) + offset);
+}
+
+static inline void sonic_set_cam_enable(struct net_device* dev, __u16 val)
+{
+       struct sonic_local* lp = (struct sonic_local *) dev->priv;
+       sonic_buf_put(lp->cda, lp->dma_bitmode, SONIC_CDA_CAM_ENABLE, val);
+}
+
+static inline __u16 sonic_get_cam_enable(struct net_device* dev)
+{
+       struct sonic_local* lp = (struct sonic_local *) dev->priv;
+       return sonic_buf_get(lp->cda, lp->dma_bitmode, SONIC_CDA_CAM_ENABLE);
+}
+
+static inline void sonic_tda_put(struct net_device* dev, int entry,
+                                int offset, __u16 val)
+{
+       struct sonic_local* lp = (struct sonic_local *) dev->priv;
+       sonic_buf_put(lp->tda, lp->dma_bitmode,
+                     (entry * SIZEOF_SONIC_TD) + offset, val);
+}
+
+static inline __u16 sonic_tda_get(struct net_device* dev, int entry,
+                                 int offset)
+{
+       struct sonic_local* lp = (struct sonic_local *) dev->priv;
+       return sonic_buf_get(lp->tda, lp->dma_bitmode,
+                            (entry * SIZEOF_SONIC_TD) + offset);
+}
+
+static inline void sonic_rda_put(struct net_device* dev, int entry,
+                                int offset, __u16 val)
+{
+       struct sonic_local* lp = (struct sonic_local *) dev->priv;
+       sonic_buf_put(lp->rda, lp->dma_bitmode,
+                     (entry * SIZEOF_SONIC_RD) + offset, val);
+}
+
+static inline __u16 sonic_rda_get(struct net_device* dev, int entry,
+                                 int offset)
+{
+       struct sonic_local* lp = (struct sonic_local *) dev->priv;
+       return sonic_buf_get(lp->rda, lp->dma_bitmode,
+                            (entry * SIZEOF_SONIC_RD) + offset);
+}
+
+static inline void sonic_rra_put(struct net_device* dev, int entry,
+                                int offset, __u16 val)
+{
+       struct sonic_local* lp = (struct sonic_local *) dev->priv;
+       sonic_buf_put(lp->rra, lp->dma_bitmode,
+                     (entry * SIZEOF_SONIC_RR) + offset, val);
+}
+
+static inline __u16 sonic_rra_get(struct net_device* dev, int entry,
+                                 int offset)
+{
+       struct sonic_local* lp = (struct sonic_local *) dev->priv;
+       return sonic_buf_get(lp->rra, lp->dma_bitmode,
+                            (entry * SIZEOF_SONIC_RR) + offset);
+}
+
 static const char *version =
     "sonic.c:v0.92 20.9.98 tsbogend@alpha.franken.de\n";
 
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
new file mode 100644 (file)
index 0000000..4e19220
--- /dev/null
@@ -0,0 +1,2334 @@
+/*
+ * Network device driver for Cell Processor-Based Blade
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Authors : Utz Bacher <utz.bacher@de.ibm.com>
+ *           Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+
+#include <linux/compiler.h>
+#include <linux/crc32.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/firmware.h>
+#include <linux/if_vlan.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <asm/bitops.h>
+#include <asm/pci-bridge.h>
+#include <net/checksum.h>
+
+#include "spider_net.h"
+
+MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com> and Jens Osterkamp " \
+             "<Jens.Osterkamp@de.ibm.com>");
+MODULE_DESCRIPTION("Spider Southbridge Gigabit Ethernet driver");
+MODULE_LICENSE("GPL");
+
+static int rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_DEFAULT;
+static int tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_DEFAULT;
+
+module_param(rx_descriptors, int, 0644);
+module_param(tx_descriptors, int, 0644);
+
+MODULE_PARM_DESC(rx_descriptors, "number of descriptors used " \
+                "in rx chains");
+MODULE_PARM_DESC(tx_descriptors, "number of descriptors used " \
+                "in tx chain");
+
+char spider_net_driver_name[] = "spidernet";
+
+static struct pci_device_id spider_net_pci_tbl[] = {
+       { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SPIDER_NET,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, spider_net_pci_tbl);
+
+/**
+ * spider_net_read_reg - reads an SMMIO register of a card
+ * @card: device structure
+ * @reg: register to read from
+ *
+ * returns the content of the specified SMMIO register.
+ */
+static u32
+spider_net_read_reg(struct spider_net_card *card, u32 reg)
+{
+       u32 value;
+
+       value = readl(card->regs + reg);
+       value = le32_to_cpu(value);
+
+       return value;
+}
+
+/**
+ * spider_net_write_reg - writes to an SMMIO register of a card
+ * @card: device structure
+ * @reg: register to write to
+ * @value: value to write into the specified SMMIO register
+ */
+static void
+spider_net_write_reg(struct spider_net_card *card, u32 reg, u32 value)
+{
+       value = cpu_to_le32(value);
+       writel(value, card->regs + reg);
+}
+
+/**
+ * spider_net_write_reg_sync - writes to an SMMIO register of a card
+ * @card: device structure
+ * @reg: register to write to
+ * @value: value to write into the specified SMMIO register
+ *
+ * Unlike spider_net_write_reg, this will also make sure the
+ * data arrives on the card by reading the reg again.
+ */
+static void
+spider_net_write_reg_sync(struct spider_net_card *card, u32 reg, u32 value)
+{
+       value = cpu_to_le32(value);
+       writel(value, card->regs + reg);
+       (void)readl(card->regs + reg);
+}
+
+/**
+ * spider_net_rx_irq_off - switch off rx irq on this spider card
+ * @card: device structure
+ *
+ * switches off rx irq by masking them out in the GHIINTnMSK register
+ */
+static void
+spider_net_rx_irq_off(struct spider_net_card *card)
+{
+       u32 regvalue;
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->intmask_lock, flags);
+       regvalue = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK);
+       regvalue &= ~SPIDER_NET_RXINT;
+       spider_net_write_reg_sync(card, SPIDER_NET_GHIINT0MSK, regvalue);
+       spin_unlock_irqrestore(&card->intmask_lock, flags);
+}
+
+/** spider_net_write_phy - write to phy register
+ * @netdev: adapter to be written to
+ * @mii_id: id of MII
+ * @reg: PHY register
+ * @val: value to be written to phy register
+ *
+ * spider_net_write_phy_register writes to an arbitrary PHY
+ * register via the spider GPCWOPCMD register. We assume the queue does
+ * not run full (not more than 15 commands outstanding).
+ **/
+static void
+spider_net_write_phy(struct net_device *netdev, int mii_id,
+                    int reg, int val)
+{
+       struct spider_net_card *card = netdev_priv(netdev);
+       u32 writevalue;
+
+       writevalue = ((u32)mii_id << 21) |
+               ((u32)reg << 16) | ((u32)val);
+
+       spider_net_write_reg(card, SPIDER_NET_GPCWOPCMD, writevalue);
+}
+
+/** spider_net_read_phy - read from phy register
+ * @netdev: network device to be read from
+ * @mii_id: id of MII
+ * @reg: PHY register
+ *
+ * Returns value read from PHY register
+ *
+ * spider_net_write_phy reads from an arbitrary PHY
+ * register via the spider GPCROPCMD register
+ **/
+static int
+spider_net_read_phy(struct net_device *netdev, int mii_id, int reg)
+{
+       struct spider_net_card *card = netdev_priv(netdev);
+       u32 readvalue;
+
+       readvalue = ((u32)mii_id << 21) | ((u32)reg << 16);
+       spider_net_write_reg(card, SPIDER_NET_GPCROPCMD, readvalue);
+
+       /* we don't use semaphores to wait for an SPIDER_NET_GPROPCMPINT
+        * interrupt, as we poll for the completion of the read operation
+        * in spider_net_read_phy. Should take about 50 us */
+       do {
+               readvalue = spider_net_read_reg(card, SPIDER_NET_GPCROPCMD);
+       } while (readvalue & SPIDER_NET_GPREXEC);
+
+       readvalue &= SPIDER_NET_GPRDAT_MASK;
+
+       return readvalue;
+}
+
+/**
+ * spider_net_rx_irq_on - switch on rx irq on this spider card
+ * @card: device structure
+ *
+ * switches on rx irq by enabling them in the GHIINTnMSK register
+ */
+static void
+spider_net_rx_irq_on(struct spider_net_card *card)
+{
+       u32 regvalue;
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->intmask_lock, flags);
+       regvalue = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK);
+       regvalue |= SPIDER_NET_RXINT;
+       spider_net_write_reg_sync(card, SPIDER_NET_GHIINT0MSK, regvalue);
+       spin_unlock_irqrestore(&card->intmask_lock, flags);
+}
+
+/**
+ * spider_net_tx_irq_off - switch off tx irq on this spider card
+ * @card: device structure
+ *
+ * switches off tx irq by masking them out in the GHIINTnMSK register
+ */
+static void
+spider_net_tx_irq_off(struct spider_net_card *card)
+{
+       u32 regvalue;
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->intmask_lock, flags);
+       regvalue = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK);
+       regvalue &= ~SPIDER_NET_TXINT;
+       spider_net_write_reg_sync(card, SPIDER_NET_GHIINT0MSK, regvalue);
+       spin_unlock_irqrestore(&card->intmask_lock, flags);
+}
+
+/**
+ * spider_net_tx_irq_on - switch on tx irq on this spider card
+ * @card: device structure
+ *
+ * switches on tx irq by enabling them in the GHIINTnMSK register
+ */
+static void
+spider_net_tx_irq_on(struct spider_net_card *card)
+{
+       u32 regvalue;
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->intmask_lock, flags);
+       regvalue = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK);
+       regvalue |= SPIDER_NET_TXINT;
+       spider_net_write_reg_sync(card, SPIDER_NET_GHIINT0MSK, regvalue);
+       spin_unlock_irqrestore(&card->intmask_lock, flags);
+}
+
+/**
+ * spider_net_set_promisc - sets the unicast address or the promiscuous mode
+ * @card: card structure
+ *
+ * spider_net_set_promisc sets the unicast destination address filter and
+ * thus either allows for non-promisc mode or promisc mode
+ */
+static void
+spider_net_set_promisc(struct spider_net_card *card)
+{
+       u32 macu, macl;
+       struct net_device *netdev = card->netdev;
+
+       if (netdev->flags & IFF_PROMISC) {
+               /* clear destination entry 0 */
+               spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR, 0);
+               spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR + 0x04, 0);
+               spider_net_write_reg(card, SPIDER_NET_GMRUA0FIL15R,
+                                    SPIDER_NET_PROMISC_VALUE);
+       } else {
+               macu = netdev->dev_addr[0];
+               macu <<= 8;
+               macu |= netdev->dev_addr[1];
+               memcpy(&macl, &netdev->dev_addr[2], sizeof(macl));
+
+               macu |= SPIDER_NET_UA_DESCR_VALUE;
+               spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR, macu);
+               spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR + 0x04, macl);
+               spider_net_write_reg(card, SPIDER_NET_GMRUA0FIL15R,
+                                    SPIDER_NET_NONPROMISC_VALUE);
+       }
+}
+
+/**
+ * spider_net_get_mac_address - read mac address from spider card
+ * @card: device structure
+ *
+ * reads MAC address from GMACUNIMACU and GMACUNIMACL registers
+ */
+static int
+spider_net_get_mac_address(struct net_device *netdev)
+{
+       struct spider_net_card *card = netdev_priv(netdev);
+       u32 macl, macu;
+
+       macl = spider_net_read_reg(card, SPIDER_NET_GMACUNIMACL);
+       macu = spider_net_read_reg(card, SPIDER_NET_GMACUNIMACU);
+
+       netdev->dev_addr[0] = (macu >> 24) & 0xff;
+       netdev->dev_addr[1] = (macu >> 16) & 0xff;
+       netdev->dev_addr[2] = (macu >> 8) & 0xff;
+       netdev->dev_addr[3] = macu & 0xff;
+       netdev->dev_addr[4] = (macl >> 8) & 0xff;
+       netdev->dev_addr[5] = macl & 0xff;
+
+       if (!is_valid_ether_addr(&netdev->dev_addr[0]))
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * spider_net_get_descr_status -- returns the status of a descriptor
+ * @descr: descriptor to look at
+ *
+ * returns the status as in the dmac_cmd_status field of the descriptor
+ */
+static enum spider_net_descr_status
+spider_net_get_descr_status(struct spider_net_descr *descr)
+{
+       u32 cmd_status;
+       rmb();
+       cmd_status = descr->dmac_cmd_status;
+       rmb();
+       cmd_status >>= SPIDER_NET_DESCR_IND_PROC_SHIFT;
+       /* no need to mask out any bits, as cmd_status is 32 bits wide only
+        * (and unsigned) */
+       return cmd_status;
+}
+
+/**
+ * spider_net_set_descr_status -- sets the status of a descriptor
+ * @descr: descriptor to change
+ * @status: status to set in the descriptor
+ *
+ * changes the status to the specified value. Doesn't change other bits
+ * in the status
+ */
+static void
+spider_net_set_descr_status(struct spider_net_descr *descr,
+                           enum spider_net_descr_status status)
+{
+       u32 cmd_status;
+       /* read the status */
+       mb();
+       cmd_status = descr->dmac_cmd_status;
+       /* clean the upper 4 bits */
+       cmd_status &= SPIDER_NET_DESCR_IND_PROC_MASKO;
+       /* add the status to it */
+       cmd_status |= ((u32)status)<<SPIDER_NET_DESCR_IND_PROC_SHIFT;
+       /* and write it back */
+       descr->dmac_cmd_status = cmd_status;
+       wmb();
+}
+
+/**
+ * spider_net_free_chain - free descriptor chain
+ * @card: card structure
+ * @chain: address of chain
+ *
+ */
+static void
+spider_net_free_chain(struct spider_net_card *card,
+                     struct spider_net_descr_chain *chain)
+{
+       struct spider_net_descr *descr;
+
+       for (descr = chain->tail; !descr->bus_addr; descr = descr->next) {
+               pci_unmap_single(card->pdev, descr->bus_addr,
+                                SPIDER_NET_DESCR_SIZE, PCI_DMA_BIDIRECTIONAL);
+               descr->bus_addr = 0;
+       }
+}
+
+/**
+ * spider_net_init_chain - links descriptor chain
+ * @card: card structure
+ * @chain: address of chain
+ * @start_descr: address of descriptor array
+ * @no: number of descriptors
+ *
+ * we manage a circular list that mirrors the hardware structure,
+ * except that the hardware uses bus addresses.
+ *
+ * returns 0 on success, <0 on failure
+ */
+static int
+spider_net_init_chain(struct spider_net_card *card,
+                      struct spider_net_descr_chain *chain,
+                      struct spider_net_descr *start_descr, int no)
+{
+       int i;
+       struct spider_net_descr *descr;
+
+       spin_lock_init(&card->chain_lock);
+
+       descr = start_descr;
+       memset(descr, 0, sizeof(*descr) * no);
+
+       /* set up the hardware pointers in each descriptor */
+       for (i=0; i<no; i++, descr++) {
+               spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE);
+
+               descr->bus_addr =
+                       pci_map_single(card->pdev, descr,
+                                      SPIDER_NET_DESCR_SIZE,
+                                      PCI_DMA_BIDIRECTIONAL);
+
+               if (descr->bus_addr == DMA_ERROR_CODE)
+                       goto iommu_error;
+
+               descr->next = descr + 1;
+               descr->prev = descr - 1;
+
+       }
+       /* do actual circular list */
+       (descr-1)->next = start_descr;
+       start_descr->prev = descr-1;
+
+       descr = start_descr;
+       for (i=0; i < no; i++, descr++) {
+               descr->next_descr_addr = descr->next->bus_addr;
+       }
+
+       chain->head = start_descr;
+       chain->tail = start_descr;
+
+       return 0;
+
+iommu_error:
+       descr = start_descr;
+       for (i=0; i < no; i++, descr++)
+               if (descr->bus_addr)
+                       pci_unmap_single(card->pdev, descr->bus_addr,
+                                        SPIDER_NET_DESCR_SIZE, PCI_DMA_BIDIRECTIONAL);
+       return -ENOMEM;
+}
+
+/**
+ * spider_net_free_rx_chain_contents - frees descr contents in rx chain
+ * @card: card structure
+ *
+ * returns 0 on success, <0 on failure
+ */
+static void
+spider_net_free_rx_chain_contents(struct spider_net_card *card)
+{
+       struct spider_net_descr *descr;
+
+       descr = card->rx_chain.head;
+       while (descr->next != card->rx_chain.head) {
+               if (descr->skb) {
+                       dev_kfree_skb(descr->skb);
+                       pci_unmap_single(card->pdev, descr->buf_addr,
+                                        SPIDER_NET_MAX_MTU,
+                                        PCI_DMA_BIDIRECTIONAL);
+               }
+               descr = descr->next;
+       }
+}
+
+/**
+ * spider_net_prepare_rx_descr - reinitializes a rx descriptor
+ * @card: card structure
+ * @descr: descriptor to re-init
+ *
+ * return 0 on succes, <0 on failure
+ *
+ * allocates a new rx skb, iommu-maps it and attaches it to the descriptor.
+ * Activate the descriptor state-wise
+ */
+static int
+spider_net_prepare_rx_descr(struct spider_net_card *card,
+                           struct spider_net_descr *descr)
+{
+       int error = 0;
+       int offset;
+       int bufsize;
+
+       /* we need to round up the buffer size to a multiple of 128 */
+       bufsize = (SPIDER_NET_MAX_MTU + SPIDER_NET_RXBUF_ALIGN - 1) &
+               (~(SPIDER_NET_RXBUF_ALIGN - 1));
+
+       /* and we need to have it 128 byte aligned, therefore we allocate a
+        * bit more */
+       /* allocate an skb */
+       descr->skb = dev_alloc_skb(bufsize + SPIDER_NET_RXBUF_ALIGN - 1);
+       if (!descr->skb) {
+               if (net_ratelimit())
+                       if (netif_msg_rx_err(card))
+                               pr_err("Not enough memory to allocate "
+                                       "rx buffer\n");
+               return -ENOMEM;
+       }
+       descr->buf_size = bufsize;
+       descr->result_size = 0;
+       descr->valid_size = 0;
+       descr->data_status = 0;
+       descr->data_error = 0;
+
+       offset = ((unsigned long)descr->skb->data) &
+               (SPIDER_NET_RXBUF_ALIGN - 1);
+       if (offset)
+               skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset);
+       /* io-mmu-map the skb */
+       descr->buf_addr = pci_map_single(card->pdev, descr->skb->data,
+                                        SPIDER_NET_MAX_MTU,
+                                        PCI_DMA_BIDIRECTIONAL);
+       if (descr->buf_addr == DMA_ERROR_CODE) {
+               dev_kfree_skb_any(descr->skb);
+               if (netif_msg_rx_err(card))
+                       pr_err("Could not iommu-map rx buffer\n");
+               spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE);
+       } else {
+               descr->dmac_cmd_status = SPIDER_NET_DMAC_RX_CARDOWNED;
+       }
+
+       return error;
+}
+
+/**
+ * spider_net_enable_rxctails - sets RX dmac chain tail addresses
+ * @card: card structure
+ *
+ * spider_net_enable_rxctails sets the RX DMAC chain tail adresses in the
+ * chip by writing to the appropriate register. DMA is enabled in
+ * spider_net_enable_rxdmac.
+ */
+static void
+spider_net_enable_rxchtails(struct spider_net_card *card)
+{
+       /* assume chain is aligned correctly */
+       spider_net_write_reg(card, SPIDER_NET_GDADCHA ,
+                            card->rx_chain.tail->bus_addr);
+}
+
+/**
+ * spider_net_enable_rxdmac - enables a receive DMA controller
+ * @card: card structure
+ *
+ * spider_net_enable_rxdmac enables the DMA controller by setting RX_DMA_EN
+ * in the GDADMACCNTR register
+ */
+static void
+spider_net_enable_rxdmac(struct spider_net_card *card)
+{
+       spider_net_write_reg(card, SPIDER_NET_GDADMACCNTR,
+                            SPIDER_NET_DMA_RX_VALUE);
+}
+
+/**
+ * spider_net_refill_rx_chain - refills descriptors/skbs in the rx chains
+ * @card: card structure
+ *
+ * refills descriptors in all chains (last used chain first): allocates skbs
+ * and iommu-maps them.
+ */
+static void
+spider_net_refill_rx_chain(struct spider_net_card *card)
+{
+       struct spider_net_descr_chain *chain;
+       int count = 0;
+       unsigned long flags;
+
+       chain = &card->rx_chain;
+
+       spin_lock_irqsave(&card->chain_lock, flags);
+       while (spider_net_get_descr_status(chain->head) ==
+                               SPIDER_NET_DESCR_NOT_IN_USE) {
+               if (spider_net_prepare_rx_descr(card, chain->head))
+                       break;
+               count++;
+               chain->head = chain->head->next;
+       }
+       spin_unlock_irqrestore(&card->chain_lock, flags);
+
+       /* could be optimized, only do that, if we know the DMA processing
+        * has terminated */
+       if (count)
+               spider_net_enable_rxdmac(card);
+}
+
+/**
+ * spider_net_alloc_rx_skbs - allocates rx skbs in rx descriptor chains
+ * @card: card structure
+ *
+ * returns 0 on success, <0 on failure
+ */
+static int
+spider_net_alloc_rx_skbs(struct spider_net_card *card)
+{
+       int result;
+       struct spider_net_descr_chain *chain;
+
+       result = -ENOMEM;
+
+       chain = &card->rx_chain;
+       /* put at least one buffer into the chain. if this fails,
+        * we've got a problem. if not, spider_net_refill_rx_chain
+        * will do the rest at the end of this function */
+       if (spider_net_prepare_rx_descr(card, chain->head))
+               goto error;
+       else
+               chain->head = chain->head->next;
+
+       /* this will allocate the rest of the rx buffers; if not, it's
+        * business as usual later on */
+       spider_net_refill_rx_chain(card);
+       return 0;
+
+error:
+       spider_net_free_rx_chain_contents(card);
+       return result;
+}
+
+/**
+ * spider_net_release_tx_descr - processes a used tx descriptor
+ * @card: card structure
+ * @descr: descriptor to release
+ *
+ * releases a used tx descriptor (unmapping, freeing of skb)
+ */
+static void
+spider_net_release_tx_descr(struct spider_net_card *card,
+                           struct spider_net_descr *descr)
+{
+       struct sk_buff *skb;
+
+       /* unmap the skb */
+       skb = descr->skb;
+       pci_unmap_single(card->pdev, descr->buf_addr, skb->len,
+                        PCI_DMA_BIDIRECTIONAL);
+
+       dev_kfree_skb_any(skb);
+
+       /* set status to not used */
+       spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE);
+}
+
+/**
+ * spider_net_release_tx_chain - processes sent tx descriptors
+ * @card: adapter structure
+ * @brutal: if set, don't care about whether descriptor seems to be in use
+ *
+ * releases the tx descriptors that spider has finished with (if non-brutal)
+ * or simply release tx descriptors (if brutal)
+ */
+static void
+spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
+{
+       struct spider_net_descr_chain *tx_chain = &card->tx_chain;
+       enum spider_net_descr_status status;
+
+       spider_net_tx_irq_off(card);
+
+       /* no lock for chain needed, if this is only executed once at a time */
+again:
+       for (;;) {
+               status = spider_net_get_descr_status(tx_chain->tail);
+               switch (status) {
+               case SPIDER_NET_DESCR_CARDOWNED:
+                       if (!brutal) goto out;
+                       /* fallthrough, if we release the descriptors
+                        * brutally (then we don't care about
+                        * SPIDER_NET_DESCR_CARDOWNED) */
+               case SPIDER_NET_DESCR_RESPONSE_ERROR:
+               case SPIDER_NET_DESCR_PROTECTION_ERROR:
+               case SPIDER_NET_DESCR_FORCE_END:
+                       if (netif_msg_tx_err(card))
+                               pr_err("%s: forcing end of tx descriptor "
+                                      "with status x%02x\n",
+                                      card->netdev->name, status);
+                       card->netdev_stats.tx_dropped++;
+                       break;
+
+               case SPIDER_NET_DESCR_COMPLETE:
+                       card->netdev_stats.tx_packets++;
+                       card->netdev_stats.tx_bytes +=
+                               tx_chain->tail->skb->len;
+                       break;
+
+               default: /* any other value (== SPIDER_NET_DESCR_NOT_IN_USE) */
+                       goto out;
+               }
+               spider_net_release_tx_descr(card, tx_chain->tail);
+               tx_chain->tail = tx_chain->tail->next;
+       }
+out:
+       netif_wake_queue(card->netdev);
+
+       if (!brutal) {
+               /* switch on tx irqs (while we are still in the interrupt
+                * handler, so we don't get an interrupt), check again
+                * for done descriptors. This results in fewer interrupts */
+               spider_net_tx_irq_on(card);
+               status = spider_net_get_descr_status(tx_chain->tail);
+               switch (status) {
+                       case SPIDER_NET_DESCR_RESPONSE_ERROR:
+                       case SPIDER_NET_DESCR_PROTECTION_ERROR:
+                       case SPIDER_NET_DESCR_FORCE_END:
+                       case SPIDER_NET_DESCR_COMPLETE:
+                               goto again;
+                       default:
+                               break;
+               }
+       }
+
+}
+
+/**
+ * spider_net_get_multicast_hash - generates hash for multicast filter table
+ * @addr: multicast address
+ *
+ * returns the hash value.
+ *
+ * spider_net_get_multicast_hash calculates a hash value for a given multicast
+ * address, that is used to set the multicast filter tables
+ */
+static u8
+spider_net_get_multicast_hash(struct net_device *netdev, __u8 *addr)
+{
+       /* FIXME: an addr of 01:00:5e:00:00:01 must result in 0xa9,
+        * ff:ff:ff:ff:ff:ff must result in 0xfd */
+       u32 crc;
+       u8 hash;
+
+       crc = crc32_be(~0, addr, netdev->addr_len);
+
+       hash = (crc >> 27);
+       hash <<= 3;
+       hash |= crc & 7;
+
+       return hash;
+}
+
+/**
+ * spider_net_set_multi - sets multicast addresses and promisc flags
+ * @netdev: interface device structure
+ *
+ * spider_net_set_multi configures multicast addresses as needed for the
+ * netdev interface. It also sets up multicast, allmulti and promisc
+ * flags appropriately
+ */
+static void
+spider_net_set_multi(struct net_device *netdev)
+{
+       struct dev_mc_list *mc;
+       u8 hash;
+       int i;
+       u32 reg;
+       struct spider_net_card *card = netdev_priv(netdev);
+       unsigned long bitmask[SPIDER_NET_MULTICAST_HASHES / BITS_PER_LONG] =
+               {0, };
+
+       spider_net_set_promisc(card);
+
+       if (netdev->flags & IFF_ALLMULTI) {
+               for (i = 0; i < SPIDER_NET_MULTICAST_HASHES; i++) {
+                       set_bit(i, bitmask);
+               }
+               goto write_hash;
+       }
+
+       /* well, we know, what the broadcast hash value is: it's xfd
+       hash = spider_net_get_multicast_hash(netdev, netdev->broadcast); */
+       set_bit(0xfd, bitmask);
+
+       for (mc = netdev->mc_list; mc; mc = mc->next) {
+               hash = spider_net_get_multicast_hash(netdev, mc->dmi_addr);
+               set_bit(hash, bitmask);
+       }
+
+write_hash:
+       for (i = 0; i < SPIDER_NET_MULTICAST_HASHES / 4; i++) {
+               reg = 0;
+               if (test_bit(i * 4, bitmask))
+                       reg += 0x08;
+               reg <<= 8;
+               if (test_bit(i * 4 + 1, bitmask))
+                       reg += 0x08;
+               reg <<= 8;
+               if (test_bit(i * 4 + 2, bitmask))
+                       reg += 0x08;
+               reg <<= 8;
+               if (test_bit(i * 4 + 3, bitmask))
+                       reg += 0x08;
+
+               spider_net_write_reg(card, SPIDER_NET_GMRMHFILnR + i * 4, reg);
+       }
+}
+
+/**
+ * spider_net_disable_rxdmac - disables the receive DMA controller
+ * @card: card structure
+ *
+ * spider_net_disable_rxdmac terminates processing on the DMA controller by
+ * turing off DMA and issueing a force end
+ */
+static void
+spider_net_disable_rxdmac(struct spider_net_card *card)
+{
+       spider_net_write_reg(card, SPIDER_NET_GDADMACCNTR,
+                            SPIDER_NET_DMA_RX_FEND_VALUE);
+}
+
+/**
+ * spider_net_stop - called upon ifconfig down
+ * @netdev: interface device structure
+ *
+ * always returns 0
+ */
+int
+spider_net_stop(struct net_device *netdev)
+{
+       struct spider_net_card *card = netdev_priv(netdev);
+
+       netif_poll_disable(netdev);
+       netif_carrier_off(netdev);
+       netif_stop_queue(netdev);
+
+       /* disable/mask all interrupts */
+       spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0);
+       spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0);
+       spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0);
+
+       /* free_irq(netdev->irq, netdev);*/
+       free_irq(to_pci_dev(netdev->class_dev.dev)->irq, netdev);
+
+       spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
+                            SPIDER_NET_DMA_TX_FEND_VALUE);
+
+       /* turn off DMA, force end */
+       spider_net_disable_rxdmac(card);
+
+       /* release chains */
+       spider_net_release_tx_chain(card, 1);
+
+       spider_net_free_chain(card, &card->tx_chain);
+       spider_net_free_chain(card, &card->rx_chain);
+
+       return 0;
+}
+
+/**
+ * spider_net_get_next_tx_descr - returns the next available tx descriptor
+ * @card: device structure to get descriptor from
+ *
+ * returns the address of the next descriptor, or NULL if not available.
+ */
+static struct spider_net_descr *
+spider_net_get_next_tx_descr(struct spider_net_card *card)
+{
+       /* check, if head points to not-in-use descr */
+       if ( spider_net_get_descr_status(card->tx_chain.head) ==
+            SPIDER_NET_DESCR_NOT_IN_USE ) {
+               return card->tx_chain.head;
+       } else {
+               return NULL;
+       }
+}
+
+/**
+ * spider_net_set_txdescr_cmdstat - sets the tx descriptor command field
+ * @descr: descriptor structure to fill out
+ * @skb: packet to consider
+ *
+ * fills out the command and status field of the descriptor structure,
+ * depending on hardware checksum settings. This function assumes a wmb()
+ * has executed before.
+ */
+static void
+spider_net_set_txdescr_cmdstat(struct spider_net_descr *descr,
+                              struct sk_buff *skb)
+{
+       if (skb->ip_summed != CHECKSUM_HW) {
+               descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_NOCS;
+               return;
+       }
+
+       /* is packet ip?
+        * if yes: tcp? udp? */
+       if (skb->protocol == htons(ETH_P_IP)) {
+               if (skb->nh.iph->protocol == IPPROTO_TCP) {
+                       descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_TCPCS;
+               } else if (skb->nh.iph->protocol == IPPROTO_UDP) {
+                       descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_UDPCS;
+               } else { /* the stack should checksum non-tcp and non-udp
+                           packets on his own: NETIF_F_IP_CSUM */
+                       descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_NOCS;
+               }
+       }
+}
+
+/**
+ * spider_net_prepare_tx_descr - fill tx descriptor with skb data
+ * @card: card structure
+ * @descr: descriptor structure to fill out
+ * @skb: packet to use
+ *
+ * returns 0 on success, <0 on failure.
+ *
+ * fills out the descriptor structure with skb data and len. Copies data,
+ * if needed (32bit DMA!)
+ */
+static int
+spider_net_prepare_tx_descr(struct spider_net_card *card,
+                           struct spider_net_descr *descr,
+                           struct sk_buff *skb)
+{
+       descr->buf_addr = pci_map_single(card->pdev, skb->data,
+                                        skb->len, PCI_DMA_BIDIRECTIONAL);
+       if (descr->buf_addr == DMA_ERROR_CODE) {
+               if (netif_msg_tx_err(card))
+                       pr_err("could not iommu-map packet (%p, %i). "
+                                 "Dropping packet\n", skb->data, skb->len);
+               return -ENOMEM;
+       }
+
+       descr->buf_size = skb->len;
+       descr->skb = skb;
+       descr->data_status = 0;
+
+       /* make sure the above values are in memory before we change the
+        * status */
+       wmb();
+
+       spider_net_set_txdescr_cmdstat(descr,skb);
+
+       return 0;
+}
+
+/**
+ * spider_net_kick_tx_dma - enables TX DMA processing
+ * @card: card structure
+ * @descr: descriptor address to enable TX processing at
+ *
+ * spider_net_kick_tx_dma writes the current tx chain head as start address
+ * of the tx descriptor chain and enables the transmission DMA engine
+ */
+static void
+spider_net_kick_tx_dma(struct spider_net_card *card,
+                      struct spider_net_descr *descr)
+{
+       /* this is the only descriptor in the output chain.
+        * Enable TX DMA */
+
+       spider_net_write_reg(card, SPIDER_NET_GDTDCHA,
+                            descr->bus_addr);
+
+       spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
+                            SPIDER_NET_DMA_TX_VALUE);
+}
+
+/**
+ * spider_net_xmit - transmits a frame over the device
+ * @skb: packet to send out
+ * @netdev: interface device structure
+ *
+ * returns 0 on success, <0 on failure
+ */
+static int
+spider_net_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct spider_net_card *card = netdev_priv(netdev);
+       struct spider_net_descr *descr;
+       int result;
+
+       descr = spider_net_get_next_tx_descr(card);
+
+       if (!descr) {
+               netif_stop_queue(netdev);
+
+               descr = spider_net_get_next_tx_descr(card);
+               if (!descr)
+                       goto error;
+               else
+                       netif_start_queue(netdev);
+       }
+
+       result = spider_net_prepare_tx_descr(card, descr, skb);
+       if (result)
+               goto error;
+
+       card->tx_chain.head = card->tx_chain.head->next;
+
+       /* make sure the status from spider_net_prepare_tx_descr is in
+        * memory before we check out the previous descriptor */
+       wmb();
+
+       if (spider_net_get_descr_status(descr->prev) !=
+           SPIDER_NET_DESCR_CARDOWNED)
+               spider_net_kick_tx_dma(card, descr);
+
+       return NETDEV_TX_OK;
+
+error:
+       card->netdev_stats.tx_dropped++;
+       return NETDEV_TX_LOCKED;
+}
+
+/**
+ * spider_net_do_ioctl - called for device ioctls
+ * @netdev: interface device structure
+ * @ifr: request parameter structure for ioctl
+ * @cmd: command code for ioctl
+ *
+ * returns 0 on success, <0 on failure. Currently, we have no special ioctls.
+ * -EOPNOTSUPP is returned, if an unknown ioctl was requested
+ */
+static int
+spider_net_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+       switch (cmd) {
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+/**
+ * spider_net_pass_skb_up - takes an skb from a descriptor and passes it on
+ * @descr: descriptor to process
+ * @card: card structure
+ *
+ * returns 1 on success, 0 if no packet was passed to the stack
+ *
+ * iommu-unmaps the skb, fills out skb structure and passes the data to the
+ * stack. The descriptor state is not changed.
+ */
+static int
+spider_net_pass_skb_up(struct spider_net_descr *descr,
+                      struct spider_net_card *card)
+{
+       struct sk_buff *skb;
+       struct net_device *netdev;
+       u32 data_status, data_error;
+
+       data_status = descr->data_status;
+       data_error = descr->data_error;
+
+       netdev = card->netdev;
+
+       /* check for errors in the data_error flag */
+       if ((data_error & SPIDER_NET_DATA_ERROR_MASK) &&
+           netif_msg_rx_err(card))
+               pr_err("error in received descriptor found, "
+                      "data_status=x%08x, data_error=x%08x\n",
+                      data_status, data_error);
+
+       /* prepare skb, unmap descriptor */
+       skb = descr->skb;
+       pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_MTU,
+                        PCI_DMA_BIDIRECTIONAL);
+
+       /* the cases we'll throw away the packet immediately */
+       if (data_error & SPIDER_NET_DESTROY_RX_FLAGS)
+               return 0;
+
+       skb->dev = netdev;
+       skb_put(skb, descr->valid_size);
+
+       /* the card seems to add 2 bytes of junk in front
+        * of the ethernet frame */
+#define SPIDER_MISALIGN                2
+       skb_pull(skb, SPIDER_MISALIGN);
+       skb->protocol = eth_type_trans(skb, netdev);
+
+       /* checksum offload */
+       if (card->options.rx_csum) {
+               if ( (data_status & SPIDER_NET_DATA_STATUS_CHK_MASK) &&
+                    (!(data_error & SPIDER_NET_DATA_ERROR_CHK_MASK)) )
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+               else
+                       skb->ip_summed = CHECKSUM_NONE;
+       } else {
+               skb->ip_summed = CHECKSUM_NONE;
+       }
+
+       if (data_status & SPIDER_NET_VLAN_PACKET) {
+               /* further enhancements: HW-accel VLAN
+                * vlan_hwaccel_receive_skb
+                */
+       }
+
+       /* pass skb up to stack */
+       netif_receive_skb(skb);
+
+       /* update netdevice statistics */
+       card->netdev_stats.rx_packets++;
+       card->netdev_stats.rx_bytes += skb->len;
+
+       return 1;
+}
+
+/**
+ * spider_net_decode_descr - processes an rx descriptor
+ * @card: card structure
+ *
+ * returns 1 if a packet has been sent to the stack, otherwise 0
+ *
+ * processes an rx descriptor by iommu-unmapping the data buffer and passing
+ * the packet up to the stack
+ */
+static int
+spider_net_decode_one_descr(struct spider_net_card *card)
+{
+       enum spider_net_descr_status status;
+       struct spider_net_descr *descr;
+       struct spider_net_descr_chain *chain;
+       int result;
+
+       chain = &card->rx_chain;
+       descr = chain->tail;
+
+       status = spider_net_get_descr_status(descr);
+
+       if (status == SPIDER_NET_DESCR_CARDOWNED) {
+               /* nothing in the descriptor yet */
+               return 0;
+       }
+
+       if (status == SPIDER_NET_DESCR_NOT_IN_USE) {
+               /* not initialized yet, I bet chain->tail == chain->head
+                * and the ring is empty */
+               spider_net_refill_rx_chain(card);
+               return 0;
+       }
+
+       /* descriptor definitively used -- move on head */
+       chain->tail = descr->next;
+
+       result = 0;
+       if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) ||
+            (status == SPIDER_NET_DESCR_PROTECTION_ERROR) ||
+            (status == SPIDER_NET_DESCR_FORCE_END) ) {
+               if (netif_msg_rx_err(card))
+                       pr_err("%s: dropping RX descriptor with state %d\n",
+                              card->netdev->name, status);
+               card->netdev_stats.rx_dropped++;
+               goto refill;
+       }
+
+       if ( (status != SPIDER_NET_DESCR_COMPLETE) &&
+            (status != SPIDER_NET_DESCR_FRAME_END) ) {
+               if (netif_msg_rx_err(card))
+                       pr_err("%s: RX descriptor with state %d\n",
+                              card->netdev->name, status);
+               goto refill;
+       }
+
+       /* ok, we've got a packet in descr */
+       result = spider_net_pass_skb_up(descr, card);
+refill:
+       spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE);
+       /* change the descriptor state: */
+       spider_net_refill_rx_chain(card);
+
+       return result;
+}
+
+/**
+ * spider_net_poll - NAPI poll function called by the stack to return packets
+ * @netdev: interface device structure
+ * @budget: number of packets we can pass to the stack at most
+ *
+ * returns 0 if no more packets available to the driver/stack. Returns 1,
+ * if the quota is exceeded, but the driver has still packets.
+ *
+ * spider_net_poll returns all packets from the rx descriptors to the stack
+ * (using netif_receive_skb). If all/enough packets are up, the driver
+ * reenables interrupts and returns 0. If not, 1 is returned.
+ */
+static int
+spider_net_poll(struct net_device *netdev, int *budget)
+{
+       struct spider_net_card *card = netdev_priv(netdev);
+       int packets_to_do, packets_done = 0;
+       int no_more_packets = 0;
+
+       packets_to_do = min(*budget, netdev->quota);
+
+       while (packets_to_do) {
+               if (spider_net_decode_one_descr(card)) {
+                       packets_done++;
+                       packets_to_do--;
+               } else {
+                       /* no more packets for the stack */
+                       no_more_packets = 1;
+                       break;
+               }
+       }
+
+       netdev->quota -= packets_done;
+       *budget -= packets_done;
+
+       /* if all packets are in the stack, enable interrupts and return 0 */
+       /* if not, return 1 */
+       if (no_more_packets) {
+               netif_rx_complete(netdev);
+               spider_net_rx_irq_on(card);
+               return 0;
+       }
+
+       return 1;
+}
+
+/**
+ * spider_net_vlan_rx_reg - initializes VLAN structures in the driver and card
+ * @netdev: interface device structure
+ * @grp: vlan_group structure that is registered (NULL on destroying interface)
+ */
+static void
+spider_net_vlan_rx_reg(struct net_device *netdev, struct vlan_group *grp)
+{
+       /* further enhancement... yet to do */
+       return;
+}
+
+/**
+ * spider_net_vlan_rx_add - adds VLAN id to the card filter
+ * @netdev: interface device structure
+ * @vid: VLAN id to add
+ */
+static void
+spider_net_vlan_rx_add(struct net_device *netdev, uint16_t vid)
+{
+       /* further enhancement... yet to do */
+       /* add vid to card's VLAN filter table */
+       return;
+}
+
+/**
+ * spider_net_vlan_rx_kill - removes VLAN id to the card filter
+ * @netdev: interface device structure
+ * @vid: VLAN id to remove
+ */
+static void
+spider_net_vlan_rx_kill(struct net_device *netdev, uint16_t vid)
+{
+       /* further enhancement... yet to do */
+       /* remove vid from card's VLAN filter table */
+}
+
+/**
+ * spider_net_get_stats - get interface statistics
+ * @netdev: interface device structure
+ *
+ * returns the interface statistics residing in the spider_net_card struct
+ */
+static struct net_device_stats *
+spider_net_get_stats(struct net_device *netdev)
+{
+       struct spider_net_card *card = netdev_priv(netdev);
+       struct net_device_stats *stats = &card->netdev_stats;
+       return stats;
+}
+
+/**
+ * spider_net_change_mtu - changes the MTU of an interface
+ * @netdev: interface device structure
+ * @new_mtu: new MTU value
+ *
+ * returns 0 on success, <0 on failure
+ */
+static int
+spider_net_change_mtu(struct net_device *netdev, int new_mtu)
+{
+       /* no need to re-alloc skbs or so -- the max mtu is about 2.3k
+        * and mtu is outbound only anyway */
+       if ( (new_mtu < SPIDER_NET_MIN_MTU ) ||
+               (new_mtu > SPIDER_NET_MAX_MTU) )
+               return -EINVAL;
+       netdev->mtu = new_mtu;
+       return 0;
+}
+
+/**
+ * spider_net_set_mac - sets the MAC of an interface
+ * @netdev: interface device structure
+ * @ptr: pointer to new MAC address
+ *
+ * Returns 0 on success, <0 on failure. Currently, we don't support this
+ * and will always return EOPNOTSUPP.
+ */
+static int
+spider_net_set_mac(struct net_device *netdev, void *p)
+{
+       struct spider_net_card *card = netdev_priv(netdev);
+       u32 macl, macu, regvalue;
+       struct sockaddr *addr = p;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       /* switch off GMACTPE and GMACRPE */
+       regvalue = spider_net_read_reg(card, SPIDER_NET_GMACOPEMD);
+       regvalue &= ~((1 << 5) | (1 << 6));
+       spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, regvalue);
+
+       /* write mac */
+       macu = (addr->sa_data[0]<<24) + (addr->sa_data[1]<<16) +
+               (addr->sa_data[2]<<8) + (addr->sa_data[3]);
+       macl = (addr->sa_data[4]<<8) + (addr->sa_data[5]);
+       spider_net_write_reg(card, SPIDER_NET_GMACUNIMACU, macu);
+       spider_net_write_reg(card, SPIDER_NET_GMACUNIMACL, macl);
+
+       /* switch GMACTPE and GMACRPE back on */
+       regvalue = spider_net_read_reg(card, SPIDER_NET_GMACOPEMD);
+       regvalue |= ((1 << 5) | (1 << 6));
+       spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, regvalue);
+
+       spider_net_set_promisc(card);
+
+       /* look up, whether we have been successful */
+       if (spider_net_get_mac_address(netdev))
+               return -EADDRNOTAVAIL;
+       if (memcmp(netdev->dev_addr,addr->sa_data,netdev->addr_len))
+               return -EADDRNOTAVAIL;
+
+       return 0;
+}
+
+/**
+ * spider_net_enable_txdmac - enables a TX DMA controller
+ * @card: card structure
+ *
+ * spider_net_enable_txdmac enables the TX DMA controller by setting the
+ * descriptor chain tail address
+ */
+static void
+spider_net_enable_txdmac(struct spider_net_card *card)
+{
+       /* assume chain is aligned correctly */
+       spider_net_write_reg(card, SPIDER_NET_GDTDCHA,
+                            card->tx_chain.tail->bus_addr);
+}
+
+/**
+ * spider_net_handle_error_irq - handles errors raised by an interrupt
+ * @card: card structure
+ * @status_reg: interrupt status register 0 (GHIINT0STS)
+ *
+ * spider_net_handle_error_irq treats or ignores all error conditions
+ * found when an interrupt is presented
+ */
+static void
+spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
+{
+       u32 error_reg1, error_reg2;
+       u32 i;
+       int show_error = 1;
+
+       error_reg1 = spider_net_read_reg(card, SPIDER_NET_GHIINT1STS);
+       error_reg2 = spider_net_read_reg(card, SPIDER_NET_GHIINT2STS);
+
+       /* check GHIINT0STS ************************************/
+       if (status_reg)
+               for (i = 0; i < 32; i++)
+                       if (status_reg & (1<<i))
+                               switch (i)
+       {
+       /* let error_reg1 and error_reg2 evaluation decide, what to do
+       case SPIDER_NET_PHYINT:
+       case SPIDER_NET_GMAC2INT:
+       case SPIDER_NET_GMAC1INT:
+       case SPIDER_NET_GIPSINT:
+       case SPIDER_NET_GFIFOINT:
+       case SPIDER_NET_DMACINT:
+       case SPIDER_NET_GSYSINT:
+               break; */
+
+       case SPIDER_NET_GPWOPCMPINT:
+               /* PHY write operation completed */
+               show_error = 0;
+               break;
+       case SPIDER_NET_GPROPCMPINT:
+               /* PHY read operation completed */
+               /* we don't use semaphores, as we poll for the completion
+                * of the read operation in spider_net_read_phy. Should take
+                * about 50 us */
+               show_error = 0;
+               break;
+       case SPIDER_NET_GPWFFINT:
+               /* PHY command queue full */
+               if (netif_msg_intr(card))
+                       pr_err("PHY write queue full\n");
+               show_error = 0;
+               break;
+
+       /* case SPIDER_NET_GRMDADRINT: not used. print a message */
+       /* case SPIDER_NET_GRMARPINT: not used. print a message */
+       /* case SPIDER_NET_GRMMPINT: not used. print a message */
+
+       case SPIDER_NET_GDTDEN0INT:
+               /* someone has set TX_DMA_EN to 0 */
+               show_error = 0;
+               break;
+
+       case SPIDER_NET_GDDDEN0INT: /* fallthrough */
+       case SPIDER_NET_GDCDEN0INT: /* fallthrough */
+       case SPIDER_NET_GDBDEN0INT: /* fallthrough */
+       case SPIDER_NET_GDADEN0INT:
+               /* someone has set RX_DMA_EN to 0 */
+               show_error = 0;
+               break;
+
+       /* RX interrupts */
+       case SPIDER_NET_GDDFDCINT:
+       case SPIDER_NET_GDCFDCINT:
+       case SPIDER_NET_GDBFDCINT:
+       case SPIDER_NET_GDAFDCINT:
+       /* case SPIDER_NET_GDNMINT: not used. print a message */
+       /* case SPIDER_NET_GCNMINT: not used. print a message */
+       /* case SPIDER_NET_GBNMINT: not used. print a message */
+       /* case SPIDER_NET_GANMINT: not used. print a message */
+       /* case SPIDER_NET_GRFNMINT: not used. print a message */
+               show_error = 0;
+               break;
+
+       /* TX interrupts */
+       case SPIDER_NET_GDTFDCINT:
+               show_error = 0;
+               break;
+       case SPIDER_NET_GTTEDINT:
+               show_error = 0;
+               break;
+       case SPIDER_NET_GDTDCEINT:
+               /* chain end. If a descriptor should be sent, kick off
+                * tx dma
+               if (card->tx_chain.tail == card->tx_chain.head)
+                       spider_net_kick_tx_dma(card);
+               show_error = 0; */
+               break;
+
+       /* case SPIDER_NET_G1TMCNTINT: not used. print a message */
+       /* case SPIDER_NET_GFREECNTINT: not used. print a message */
+       }
+
+       /* check GHIINT1STS ************************************/
+       if (error_reg1)
+               for (i = 0; i < 32; i++)
+                       if (error_reg1 & (1<<i))
+                               switch (i)
+       {
+       case SPIDER_NET_GTMFLLINT:
+               if (netif_msg_intr(card))
+                       pr_err("Spider TX RAM full\n");
+               show_error = 0;
+               break;
+       case SPIDER_NET_GRMFLLINT:
+               if (netif_msg_intr(card))
+                       pr_err("Spider RX RAM full, incoming packets "
+                              "might be discarded !\n");
+               netif_rx_schedule(card->netdev);
+               spider_net_enable_rxchtails(card);
+               spider_net_enable_rxdmac(card);
+               break;
+
+       /* case SPIDER_NET_GTMSHTINT: problem, print a message */
+       case SPIDER_NET_GDTINVDINT:
+               /* allrighty. tx from previous descr ok */
+               show_error = 0;
+               break;
+       /* case SPIDER_NET_GRFDFLLINT: print a message down there */
+       /* case SPIDER_NET_GRFCFLLINT: print a message down there */
+       /* case SPIDER_NET_GRFBFLLINT: print a message down there */
+       /* case SPIDER_NET_GRFAFLLINT: print a message down there */
+
+       /* chain end */
+       case SPIDER_NET_GDDDCEINT: /* fallthrough */
+       case SPIDER_NET_GDCDCEINT: /* fallthrough */
+       case SPIDER_NET_GDBDCEINT: /* fallthrough */
+       case SPIDER_NET_GDADCEINT:
+               if (netif_msg_intr(card))
+                       pr_err("got descriptor chain end interrupt, "
+                              "restarting DMAC %c.\n",
+                              'D'+i-SPIDER_NET_GDDDCEINT);
+               spider_net_refill_rx_chain(card);
+               show_error = 0;
+               break;
+
+       /* invalid descriptor */
+       case SPIDER_NET_GDDINVDINT: /* fallthrough */
+       case SPIDER_NET_GDCINVDINT: /* fallthrough */
+       case SPIDER_NET_GDBINVDINT: /* fallthrough */
+       case SPIDER_NET_GDAINVDINT:
+               /* could happen when rx chain is full */
+               spider_net_refill_rx_chain(card);
+               show_error = 0;
+               break;
+
+       /* case SPIDER_NET_GDTRSERINT: problem, print a message */
+       /* case SPIDER_NET_GDDRSERINT: problem, print a message */
+       /* case SPIDER_NET_GDCRSERINT: problem, print a message */
+       /* case SPIDER_NET_GDBRSERINT: problem, print a message */
+       /* case SPIDER_NET_GDARSERINT: problem, print a message */
+       /* case SPIDER_NET_GDSERINT: problem, print a message */
+       /* case SPIDER_NET_GDTPTERINT: problem, print a message */
+       /* case SPIDER_NET_GDDPTERINT: problem, print a message */
+       /* case SPIDER_NET_GDCPTERINT: problem, print a message */
+       /* case SPIDER_NET_GDBPTERINT: problem, print a message */
+       /* case SPIDER_NET_GDAPTERINT: problem, print a message */
+       default:
+               show_error = 1;
+               break;
+       }
+
+       /* check GHIINT2STS ************************************/
+       if (error_reg2)
+               for (i = 0; i < 32; i++)
+                       if (error_reg2 & (1<<i))
+                               switch (i)
+       {
+       /* there is nothing we can (want  to) do at this time. Log a
+        * message, we can switch on and off the specific values later on
+       case SPIDER_NET_GPROPERINT:
+       case SPIDER_NET_GMCTCRSNGINT:
+       case SPIDER_NET_GMCTLCOLINT:
+       case SPIDER_NET_GMCTTMOTINT:
+       case SPIDER_NET_GMCRCAERINT:
+       case SPIDER_NET_GMCRCALERINT:
+       case SPIDER_NET_GMCRALNERINT:
+       case SPIDER_NET_GMCROVRINT:
+       case SPIDER_NET_GMCRRNTINT:
+       case SPIDER_NET_GMCRRXERINT:
+       case SPIDER_NET_GTITCSERINT:
+       case SPIDER_NET_GTIFMTERINT:
+       case SPIDER_NET_GTIPKTRVKINT:
+       case SPIDER_NET_GTISPINGINT:
+       case SPIDER_NET_GTISADNGINT:
+       case SPIDER_NET_GTISPDNGINT:
+       case SPIDER_NET_GRIFMTERINT:
+       case SPIDER_NET_GRIPKTRVKINT:
+       case SPIDER_NET_GRISPINGINT:
+       case SPIDER_NET_GRISADNGINT:
+       case SPIDER_NET_GRISPDNGINT:
+               break;
+       */
+               default:
+                       break;
+       }
+
+       if ((show_error) && (netif_msg_intr(card)))
+               pr_err("Got error interrupt, GHIINT0STS = 0x%08x, "
+                      "GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n",
+                      status_reg, error_reg1, error_reg2);
+
+       /* clear interrupt sources */
+       spider_net_write_reg(card, SPIDER_NET_GHIINT1STS, error_reg1);
+       spider_net_write_reg(card, SPIDER_NET_GHIINT2STS, error_reg2);
+}
+
+/**
+ * spider_net_interrupt - interrupt handler for spider_net
+ * @irq: interupt number
+ * @ptr: pointer to net_device
+ * @regs: PU registers
+ *
+ * returns IRQ_HANDLED, if interrupt was for driver, or IRQ_NONE, if no
+ * interrupt found raised by card.
+ *
+ * This is the interrupt handler, that turns off
+ * interrupts for this device and makes the stack poll the driver
+ */
+static irqreturn_t
+spider_net_interrupt(int irq, void *ptr, struct pt_regs *regs)
+{
+       struct net_device *netdev = ptr;
+       struct spider_net_card *card = netdev_priv(netdev);
+       u32 status_reg;
+
+       status_reg = spider_net_read_reg(card, SPIDER_NET_GHIINT0STS);
+
+       if (!status_reg)
+               return IRQ_NONE;
+
+       if (status_reg & SPIDER_NET_TXINT)
+               spider_net_release_tx_chain(card, 0);
+
+       if (status_reg & SPIDER_NET_RXINT ) {
+               spider_net_rx_irq_off(card);
+               netif_rx_schedule(netdev);
+       }
+
+       /* we do this after rx and tx processing, as we want the tx chain
+        * processed to see, whether we should restart tx dma processing */
+       spider_net_handle_error_irq(card, status_reg);
+
+       /* clear interrupt sources */
+       spider_net_write_reg(card, SPIDER_NET_GHIINT0STS, status_reg);
+
+       return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/**
+ * spider_net_poll_controller - artificial interrupt for netconsole etc.
+ * @netdev: interface device structure
+ *
+ * see Documentation/networking/netconsole.txt
+ */
+static void
+spider_net_poll_controller(struct net_device *netdev)
+{
+       disable_irq(netdev->irq);
+       spider_net_interrupt(netdev->irq, netdev, NULL);
+       enable_irq(netdev->irq);
+}
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+
+/**
+ * spider_net_init_card - initializes the card
+ * @card: card structure
+ *
+ * spider_net_init_card initializes the card so that other registers can
+ * be used
+ */
+static void
+spider_net_init_card(struct spider_net_card *card)
+{
+       spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
+                            SPIDER_NET_CKRCTRL_STOP_VALUE);
+
+       spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
+                            SPIDER_NET_CKRCTRL_RUN_VALUE);
+}
+
+/**
+ * spider_net_enable_card - enables the card by setting all kinds of regs
+ * @card: card structure
+ *
+ * spider_net_enable_card sets a lot of SMMIO registers to enable the device
+ */
+static void
+spider_net_enable_card(struct spider_net_card *card)
+{
+       int i;
+       /* the following array consists of (register),(value) pairs
+        * that are set in this function. A register of 0 ends the list */
+       u32 regs[][2] = {
+               { SPIDER_NET_GRESUMINTNUM, 0 },
+               { SPIDER_NET_GREINTNUM, 0 },
+
+               /* set interrupt frame number registers */
+               /* clear the single DMA engine registers first */
+               { SPIDER_NET_GFAFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
+               { SPIDER_NET_GFBFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
+               { SPIDER_NET_GFCFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
+               { SPIDER_NET_GFDFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
+               /* then set, what we really need */
+               { SPIDER_NET_GFFRMNUM, SPIDER_NET_FRAMENUM_VALUE },
+
+               /* timer counter registers and stuff */
+               { SPIDER_NET_GFREECNNUM, 0 },
+               { SPIDER_NET_GONETIMENUM, 0 },
+               { SPIDER_NET_GTOUTFRMNUM, 0 },
+
+               /* RX mode setting */
+               { SPIDER_NET_GRXMDSET, SPIDER_NET_RXMODE_VALUE },
+               /* TX mode setting */
+               { SPIDER_NET_GTXMDSET, SPIDER_NET_TXMODE_VALUE },
+               /* IPSEC mode setting */
+               { SPIDER_NET_GIPSECINIT, SPIDER_NET_IPSECINIT_VALUE },
+
+               { SPIDER_NET_GFTRESTRT, SPIDER_NET_RESTART_VALUE },
+
+               { SPIDER_NET_GMRWOLCTRL, 0 },
+               { SPIDER_NET_GTESTMD, 0 },
+
+               { SPIDER_NET_GMACINTEN, 0 },
+
+               /* flow control stuff */
+               { SPIDER_NET_GMACAPAUSE, SPIDER_NET_MACAPAUSE_VALUE },
+               { SPIDER_NET_GMACTXPAUSE, SPIDER_NET_TXPAUSE_VALUE },
+
+               { SPIDER_NET_GMACBSTLMT, SPIDER_NET_BURSTLMT_VALUE },
+               { 0, 0}
+       };
+
+       i = 0;
+       while (regs[i][0]) {
+               spider_net_write_reg(card, regs[i][0], regs[i][1]);
+               i++;
+       }
+
+       /* clear unicast filter table entries 1 to 14 */
+       for (i = 1; i <= 14; i++) {
+               spider_net_write_reg(card,
+                                    SPIDER_NET_GMRUAFILnR + i * 8,
+                                    0x00080000);
+               spider_net_write_reg(card,
+                                    SPIDER_NET_GMRUAFILnR + i * 8 + 4,
+                                    0x00000000);
+       }
+
+       spider_net_write_reg(card, SPIDER_NET_GMRUA0FIL15R, 0x08080000);
+
+       spider_net_write_reg(card, SPIDER_NET_ECMODE, SPIDER_NET_ECMODE_VALUE);
+
+       /* set chain tail adress for RX chains and
+        * enable DMA */
+       spider_net_enable_rxchtails(card);
+       spider_net_enable_rxdmac(card);
+
+       spider_net_write_reg(card, SPIDER_NET_GRXDMAEN, SPIDER_NET_WOL_VALUE);
+
+       /* set chain tail adress for TX chain */
+       spider_net_enable_txdmac(card);
+
+       spider_net_write_reg(card, SPIDER_NET_GMACLENLMT,
+                            SPIDER_NET_LENLMT_VALUE);
+       spider_net_write_reg(card, SPIDER_NET_GMACMODE,
+                            SPIDER_NET_MACMODE_VALUE);
+       spider_net_write_reg(card, SPIDER_NET_GMACOPEMD,
+                            SPIDER_NET_OPMODE_VALUE);
+
+       /* set interrupt mask registers */
+       spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK,
+                            SPIDER_NET_INT0_MASK_VALUE);
+       spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK,
+                            SPIDER_NET_INT1_MASK_VALUE);
+       spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK,
+                            SPIDER_NET_INT2_MASK_VALUE);
+}
+
+/**
+ * spider_net_open - called upon ifonfig up
+ * @netdev: interface device structure
+ *
+ * returns 0 on success, <0 on failure
+ *
+ * spider_net_open allocates all the descriptors and memory needed for
+ * operation, sets up multicast list and enables interrupts
+ */
+int
+spider_net_open(struct net_device *netdev)
+{
+       struct spider_net_card *card = netdev_priv(netdev);
+       int result;
+
+       result = -ENOMEM;
+       if (spider_net_init_chain(card, &card->tx_chain,
+                         card->descr, tx_descriptors))
+               goto alloc_tx_failed;
+       if (spider_net_init_chain(card, &card->rx_chain,
+                         card->descr + tx_descriptors, rx_descriptors))
+               goto alloc_rx_failed;
+
+       /* allocate rx skbs */
+       if (spider_net_alloc_rx_skbs(card))
+               goto alloc_skbs_failed;
+
+       spider_net_set_multi(netdev);
+
+       /* further enhancement: setup hw vlan, if needed */
+
+       result = -EBUSY;
+       if (request_irq(netdev->irq, spider_net_interrupt,
+                            SA_SHIRQ, netdev->name, netdev))
+               goto register_int_failed;
+
+       spider_net_enable_card(card);
+
+       netif_start_queue(netdev);
+       netif_carrier_on(netdev);
+       netif_poll_enable(netdev);
+
+       return 0;
+
+register_int_failed:
+       spider_net_free_rx_chain_contents(card);
+alloc_skbs_failed:
+       spider_net_free_chain(card, &card->rx_chain);
+alloc_rx_failed:
+       spider_net_free_chain(card, &card->tx_chain);
+alloc_tx_failed:
+       return result;
+}
+
+/**
+ * spider_net_setup_phy - setup PHY
+ * @card: card structure
+ *
+ * returns 0 on success, <0 on failure
+ *
+ * spider_net_setup_phy is used as part of spider_net_probe. Sets
+ * the PHY to 1000 Mbps
+ **/
+static int
+spider_net_setup_phy(struct spider_net_card *card)
+{
+       struct mii_phy *phy = &card->phy;
+
+       spider_net_write_reg(card, SPIDER_NET_GDTDMASEL,
+                            SPIDER_NET_DMASEL_VALUE);
+       spider_net_write_reg(card, SPIDER_NET_GPCCTRL,
+                            SPIDER_NET_PHY_CTRL_VALUE);
+       phy->mii_id = 1;
+       phy->dev = card->netdev;
+       phy->mdio_read = spider_net_read_phy;
+       phy->mdio_write = spider_net_write_phy;
+
+       mii_phy_probe(phy, phy->mii_id);
+
+       if (phy->def->ops->setup_forced)
+               phy->def->ops->setup_forced(phy, SPEED_1000, DUPLEX_FULL);
+
+       /* the following two writes could be moved to sungem_phy.c */
+       /* enable fiber mode */
+       spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0x9020);
+       /* LEDs active in both modes, autosense prio = fiber */
+       spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0x945f);
+
+       phy->def->ops->read_link(phy);
+       pr_info("Found %s with %i Mbps, %s-duplex.\n", phy->def->name,
+               phy->speed, phy->duplex==1 ? "Full" : "Half");
+
+       return 0;
+}
+
+/**
+ * spider_net_download_firmware - loads firmware into the adapter
+ * @card: card structure
+ * @firmware: firmware pointer
+ *
+ * spider_net_download_firmware loads the firmware opened by
+ * spider_net_init_firmware into the adapter.
+ */
+static void
+spider_net_download_firmware(struct spider_net_card *card,
+                            const struct firmware *firmware)
+{
+       int sequencer, i;
+       u32 *fw_ptr = (u32 *)firmware->data;
+
+       /* stop sequencers */
+       spider_net_write_reg(card, SPIDER_NET_GSINIT,
+                            SPIDER_NET_STOP_SEQ_VALUE);
+
+       for (sequencer = 0; sequencer < 6; sequencer++) {
+               spider_net_write_reg(card,
+                                    SPIDER_NET_GSnPRGADR + sequencer * 8, 0);
+               for (i = 0; i < SPIDER_NET_FIRMWARE_LEN; i++) {
+                       spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT +
+                                            sequencer * 8, *fw_ptr);
+                       fw_ptr++;
+               }
+       }
+
+       spider_net_write_reg(card, SPIDER_NET_GSINIT,
+                            SPIDER_NET_RUN_SEQ_VALUE);
+}
+
+/**
+ * spider_net_init_firmware - reads in firmware parts
+ * @card: card structure
+ *
+ * Returns 0 on success, <0 on failure
+ *
+ * spider_net_init_firmware opens the sequencer firmware and does some basic
+ * checks. This function opens and releases the firmware structure. A call
+ * to download the firmware is performed before the release.
+ *
+ * Firmware format
+ * ===============
+ * spider_fw.bin is expected to be a file containing 6*1024*4 bytes, 4k being
+ * the program for each sequencer. Use the command
+ *    tail -q -n +2 Seq_code1_0x088.txt Seq_code2_0x090.txt              \
+ *         Seq_code3_0x098.txt Seq_code4_0x0A0.txt Seq_code5_0x0A8.txt   \
+ *         Seq_code6_0x0B0.txt | xxd -r -p -c4 > spider_fw.bin
+ *
+ * to generate spider_fw.bin, if you have sequencer programs with something
+ * like the following contents for each sequencer:
+ *    <ONE LINE COMMENT>
+ *    <FIRST 4-BYTES-WORD FOR SEQUENCER>
+ *    <SECOND 4-BYTES-WORD FOR SEQUENCER>
+ *     ...
+ *    <1024th 4-BYTES-WORD FOR SEQUENCER>
+ */
+static int
+spider_net_init_firmware(struct spider_net_card *card)
+{
+       const struct firmware *firmware;
+       int err = -EIO;
+
+       if (request_firmware(&firmware,
+                            SPIDER_NET_FIRMWARE_NAME, &card->pdev->dev) < 0) {
+               if (netif_msg_probe(card))
+                       pr_err("Couldn't read in sequencer data file %s.\n",
+                              SPIDER_NET_FIRMWARE_NAME);
+               firmware = NULL;
+               goto out;
+       }
+
+       if (firmware->size != 6 * SPIDER_NET_FIRMWARE_LEN * sizeof(u32)) {
+               if (netif_msg_probe(card))
+                       pr_err("Invalid size of sequencer data file %s.\n",
+                              SPIDER_NET_FIRMWARE_NAME);
+               goto out;
+       }
+
+       spider_net_download_firmware(card, firmware);
+
+       err = 0;
+out:
+       release_firmware(firmware);
+
+       return err;
+}
+
+/**
+ * spider_net_workaround_rxramfull - work around firmware bug
+ * @card: card structure
+ *
+ * no return value
+ **/
+static void
+spider_net_workaround_rxramfull(struct spider_net_card *card)
+{
+       int i, sequencer = 0;
+
+       /* cancel reset */
+       spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
+                            SPIDER_NET_CKRCTRL_RUN_VALUE);
+
+       /* empty sequencer data */
+       for (sequencer = 0; sequencer < 6; sequencer++) {
+               spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT +
+                                    sequencer * 8, 0x0);
+               for (i = 0; i < SPIDER_NET_FIRMWARE_LEN; i++) {
+                       spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT +
+                                            sequencer * 8, 0x0);
+               }
+       }
+
+       /* set sequencer operation */
+       spider_net_write_reg(card, SPIDER_NET_GSINIT, 0x000000fe);
+
+       /* reset */
+       spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
+                            SPIDER_NET_CKRCTRL_STOP_VALUE);
+}
+
+/**
+ * spider_net_tx_timeout_task - task scheduled by the watchdog timeout
+ * function (to be called not under interrupt status)
+ * @data: data, is interface device structure
+ *
+ * called as task when tx hangs, resets interface (if interface is up)
+ */
+static void
+spider_net_tx_timeout_task(void *data)
+{
+       struct net_device *netdev = data;
+       struct spider_net_card *card = netdev_priv(netdev);
+
+       if (!(netdev->flags & IFF_UP))
+               goto out;
+
+       netif_device_detach(netdev);
+       spider_net_stop(netdev);
+
+       spider_net_workaround_rxramfull(card);
+       spider_net_init_card(card);
+
+       if (spider_net_setup_phy(card))
+               goto out;
+       if (spider_net_init_firmware(card))
+               goto out;
+
+       spider_net_open(netdev);
+       spider_net_kick_tx_dma(card, card->tx_chain.head);
+       netif_device_attach(netdev);
+
+out:
+       atomic_dec(&card->tx_timeout_task_counter);
+}
+
+/**
+ * spider_net_tx_timeout - called when the tx timeout watchdog kicks in.
+ * @netdev: interface device structure
+ *
+ * called, if tx hangs. Schedules a task that resets the interface
+ */
+static void
+spider_net_tx_timeout(struct net_device *netdev)
+{
+       struct spider_net_card *card;
+
+       card = netdev_priv(netdev);
+       atomic_inc(&card->tx_timeout_task_counter);
+       if (netdev->flags & IFF_UP)
+               schedule_work(&card->tx_timeout_task);
+       else
+               atomic_dec(&card->tx_timeout_task_counter);
+}
+
+/**
+ * spider_net_setup_netdev_ops - initialization of net_device operations
+ * @netdev: net_device structure
+ *
+ * fills out function pointers in the net_device structure
+ */
+static void
+spider_net_setup_netdev_ops(struct net_device *netdev)
+{
+       netdev->open = &spider_net_open;
+       netdev->stop = &spider_net_stop;
+       netdev->hard_start_xmit = &spider_net_xmit;
+       netdev->get_stats = &spider_net_get_stats;
+       netdev->set_multicast_list = &spider_net_set_multi;
+       netdev->set_mac_address = &spider_net_set_mac;
+       netdev->change_mtu = &spider_net_change_mtu;
+       netdev->do_ioctl = &spider_net_do_ioctl;
+       /* tx watchdog */
+       netdev->tx_timeout = &spider_net_tx_timeout;
+       netdev->watchdog_timeo = SPIDER_NET_WATCHDOG_TIMEOUT;
+       /* NAPI */
+       netdev->poll = &spider_net_poll;
+       netdev->weight = SPIDER_NET_NAPI_WEIGHT;
+       /* HW VLAN */
+       netdev->vlan_rx_register = &spider_net_vlan_rx_reg;
+       netdev->vlan_rx_add_vid = &spider_net_vlan_rx_add;
+       netdev->vlan_rx_kill_vid = &spider_net_vlan_rx_kill;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       /* poll controller */
+       netdev->poll_controller = &spider_net_poll_controller;
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+       /* ethtool ops */
+       netdev->ethtool_ops = &spider_net_ethtool_ops;
+}
+
+/**
+ * spider_net_setup_netdev - initialization of net_device
+ * @card: card structure
+ *
+ * Returns 0 on success or <0 on failure
+ *
+ * spider_net_setup_netdev initializes the net_device structure
+ **/
+static int
+spider_net_setup_netdev(struct spider_net_card *card)
+{
+       int result;
+       struct net_device *netdev = card->netdev;
+       struct device_node *dn;
+       struct sockaddr addr;
+       u8 *mac;
+
+       SET_MODULE_OWNER(netdev);
+       SET_NETDEV_DEV(netdev, &card->pdev->dev);
+
+       pci_set_drvdata(card->pdev, netdev);
+       spin_lock_init(&card->intmask_lock);
+       netdev->irq = card->pdev->irq;
+
+       card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;
+
+       spider_net_setup_netdev_ops(netdev);
+
+       netdev->features = 0;
+       /* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
+        *              NETIF_F_HW_VLAN_FILTER */
+
+       netdev->irq = card->pdev->irq;
+
+       dn = pci_device_to_OF_node(card->pdev);
+       if (!dn)
+               return -EIO;
+
+       mac = (u8 *)get_property(dn, "local-mac-address", NULL);
+       if (!mac)
+               return -EIO;
+       memcpy(addr.sa_data, mac, ETH_ALEN);
+
+       result = spider_net_set_mac(netdev, &addr);
+       if ((result) && (netif_msg_probe(card)))
+               pr_err("Failed to set MAC address: %i\n", result);
+
+       result = register_netdev(netdev);
+       if (result) {
+               if (netif_msg_probe(card))
+                       pr_err("Couldn't register net_device: %i\n",
+                                 result);
+               return result;
+       }
+
+       if (netif_msg_probe(card))
+               pr_info("Initialized device %s.\n", netdev->name);
+
+       return 0;
+}
+
+/**
+ * spider_net_alloc_card - allocates net_device and card structure
+ *
+ * returns the card structure or NULL in case of errors
+ *
+ * the card and net_device structures are linked to each other
+ */
+static struct spider_net_card *
+spider_net_alloc_card(void)
+{
+       struct net_device *netdev;
+       struct spider_net_card *card;
+       size_t alloc_size;
+
+       alloc_size = sizeof (*card) +
+               sizeof (struct spider_net_descr) * rx_descriptors +
+               sizeof (struct spider_net_descr) * tx_descriptors;
+       netdev = alloc_etherdev(alloc_size);
+       if (!netdev)
+               return NULL;
+
+       card = netdev_priv(netdev);
+       card->netdev = netdev;
+       card->msg_enable = SPIDER_NET_DEFAULT_MSG;
+       INIT_WORK(&card->tx_timeout_task, spider_net_tx_timeout_task, netdev);
+       init_waitqueue_head(&card->waitq);
+       atomic_set(&card->tx_timeout_task_counter, 0);
+
+       return card;
+}
+
+/**
+ * spider_net_undo_pci_setup - releases PCI ressources
+ * @card: card structure
+ *
+ * spider_net_undo_pci_setup releases the mapped regions
+ */
+static void
+spider_net_undo_pci_setup(struct spider_net_card *card)
+{
+       iounmap(card->regs);
+       pci_release_regions(card->pdev);
+}
+
+/**
+ * spider_net_setup_pci_dev - sets up the device in terms of PCI operations
+ * @card: card structure
+ * @pdev: PCI device
+ *
+ * Returns the card structure or NULL if any errors occur
+ *
+ * spider_net_setup_pci_dev initializes pdev and together with the
+ * functions called in spider_net_open configures the device so that
+ * data can be transferred over it
+ * The net_device structure is attached to the card structure, if the
+ * function returns without error.
+ **/
+static struct spider_net_card *
+spider_net_setup_pci_dev(struct pci_dev *pdev)
+{
+       struct spider_net_card *card;
+       unsigned long mmio_start, mmio_len;
+
+       if (pci_enable_device(pdev)) {
+               pr_err("Couldn't enable PCI device\n");
+               return NULL;
+       }
+
+       if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+               pr_err("Couldn't find proper PCI device base address.\n");
+               goto out_disable_dev;
+       }
+
+       if (pci_request_regions(pdev, spider_net_driver_name)) {
+               pr_err("Couldn't obtain PCI resources, aborting.\n");
+               goto out_disable_dev;
+       }
+
+       pci_set_master(pdev);
+
+       card = spider_net_alloc_card();
+       if (!card) {
+               pr_err("Couldn't allocate net_device structure, "
+                         "aborting.\n");
+               goto out_release_regions;
+       }
+       card->pdev = pdev;
+
+       /* fetch base address and length of first resource */
+       mmio_start = pci_resource_start(pdev, 0);
+       mmio_len = pci_resource_len(pdev, 0);
+
+       card->netdev->mem_start = mmio_start;
+       card->netdev->mem_end = mmio_start + mmio_len;
+       card->regs = ioremap(mmio_start, mmio_len);
+
+       if (!card->regs) {
+               pr_err("Couldn't obtain PCI resources, aborting.\n");
+               goto out_release_regions;
+       }
+
+       return card;
+
+out_release_regions:
+       pci_release_regions(pdev);
+out_disable_dev:
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+       return NULL;
+}
+
+/**
+ * spider_net_probe - initialization of a device
+ * @pdev: PCI device
+ * @ent: entry in the device id list
+ *
+ * Returns 0 on success, <0 on failure
+ *
+ * spider_net_probe initializes pdev and registers a net_device
+ * structure for it. After that, the device can be ifconfig'ed up
+ **/
+static int __devinit
+spider_net_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       int err = -EIO;
+       struct spider_net_card *card;
+
+       card = spider_net_setup_pci_dev(pdev);
+       if (!card)
+               goto out;
+
+       spider_net_workaround_rxramfull(card);
+       spider_net_init_card(card);
+
+       err = spider_net_setup_phy(card);
+       if (err)
+               goto out_undo_pci;
+
+       err = spider_net_init_firmware(card);
+       if (err)
+               goto out_undo_pci;
+
+       err = spider_net_setup_netdev(card);
+       if (err)
+               goto out_undo_pci;
+
+       return 0;
+
+out_undo_pci:
+       spider_net_undo_pci_setup(card);
+       free_netdev(card->netdev);
+out:
+       return err;
+}
+
+/**
+ * spider_net_remove - removal of a device
+ * @pdev: PCI device
+ *
+ * Returns 0 on success, <0 on failure
+ *
+ * spider_net_remove is called to remove the device and unregisters the
+ * net_device
+ **/
+static void __devexit
+spider_net_remove(struct pci_dev *pdev)
+{
+       struct net_device *netdev;
+       struct spider_net_card *card;
+
+       netdev = pci_get_drvdata(pdev);
+       card = netdev_priv(netdev);
+
+       wait_event(card->waitq,
+                  atomic_read(&card->tx_timeout_task_counter) == 0);
+
+       unregister_netdev(netdev);
+
+       /* switch off card */
+       spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
+                            SPIDER_NET_CKRCTRL_STOP_VALUE);
+       spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
+                            SPIDER_NET_CKRCTRL_RUN_VALUE);
+
+       spider_net_undo_pci_setup(card);
+       free_netdev(netdev);
+}
+
+static struct pci_driver spider_net_driver = {
+       .owner          = THIS_MODULE,
+       .name           = spider_net_driver_name,
+       .id_table       = spider_net_pci_tbl,
+       .probe          = spider_net_probe,
+       .remove         = __devexit_p(spider_net_remove)
+};
+
+/**
+ * spider_net_init - init function when the driver is loaded
+ *
+ * spider_net_init registers the device driver
+ */
+static int __init spider_net_init(void)
+{
+       if (rx_descriptors < SPIDER_NET_RX_DESCRIPTORS_MIN) {
+               rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_MIN;
+               pr_info("adjusting rx descriptors to %i.\n", rx_descriptors);
+       }
+       if (rx_descriptors > SPIDER_NET_RX_DESCRIPTORS_MAX) {
+               rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_MAX;
+               pr_info("adjusting rx descriptors to %i.\n", rx_descriptors);
+       }
+       if (tx_descriptors < SPIDER_NET_TX_DESCRIPTORS_MIN) {
+               tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_MIN;
+               pr_info("adjusting tx descriptors to %i.\n", tx_descriptors);
+       }
+       if (tx_descriptors > SPIDER_NET_TX_DESCRIPTORS_MAX) {
+               tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_MAX;
+               pr_info("adjusting tx descriptors to %i.\n", tx_descriptors);
+       }
+
+       return pci_register_driver(&spider_net_driver);
+}
+
+/**
+ * spider_net_cleanup - exit function when driver is unloaded
+ *
+ * spider_net_cleanup unregisters the device driver
+ */
+static void __exit spider_net_cleanup(void)
+{
+       pci_unregister_driver(&spider_net_driver);
+}
+
+module_init(spider_net_init);
+module_exit(spider_net_cleanup);
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h
new file mode 100644 (file)
index 0000000..22b2f23
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * Network device driver for Cell Processor-Based Blade
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Authors : Utz Bacher <utz.bacher@de.ibm.com>
+ *           Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _SPIDER_NET_H
+#define _SPIDER_NET_H
+
+#include "sungem_phy.h"
+
+extern int spider_net_stop(struct net_device *netdev);
+extern int spider_net_open(struct net_device *netdev);
+
+extern struct ethtool_ops spider_net_ethtool_ops;
+
+extern char spider_net_driver_name[];
+
+#define SPIDER_NET_MAX_MTU                     2308
+#define SPIDER_NET_MIN_MTU                     64
+
+#define SPIDER_NET_RXBUF_ALIGN                 128
+
+#define SPIDER_NET_RX_DESCRIPTORS_DEFAULT      64
+#define SPIDER_NET_RX_DESCRIPTORS_MIN          16
+#define SPIDER_NET_RX_DESCRIPTORS_MAX          256
+
+#define SPIDER_NET_TX_DESCRIPTORS_DEFAULT      64
+#define SPIDER_NET_TX_DESCRIPTORS_MIN          16
+#define SPIDER_NET_TX_DESCRIPTORS_MAX          256
+
+#define SPIDER_NET_RX_CSUM_DEFAULT             1
+
+#define SPIDER_NET_WATCHDOG_TIMEOUT 5*HZ
+#define SPIDER_NET_NAPI_WEIGHT 64
+
+#define SPIDER_NET_FIRMWARE_LEN                1024
+#define SPIDER_NET_FIRMWARE_NAME       "spider_fw.bin"
+
+/** spider_net SMMIO registers */
+#define SPIDER_NET_GHIINT0STS          0x00000000
+#define SPIDER_NET_GHIINT1STS          0x00000004
+#define SPIDER_NET_GHIINT2STS          0x00000008
+#define SPIDER_NET_GHIINT0MSK          0x00000010
+#define SPIDER_NET_GHIINT1MSK          0x00000014
+#define SPIDER_NET_GHIINT2MSK          0x00000018
+
+#define SPIDER_NET_GRESUMINTNUM                0x00000020
+#define SPIDER_NET_GREINTNUM           0x00000024
+
+#define SPIDER_NET_GFFRMNUM            0x00000028
+#define SPIDER_NET_GFAFRMNUM           0x0000002c
+#define SPIDER_NET_GFBFRMNUM           0x00000030
+#define SPIDER_NET_GFCFRMNUM           0x00000034
+#define SPIDER_NET_GFDFRMNUM           0x00000038
+
+/* clear them (don't use it) */
+#define SPIDER_NET_GFREECNNUM          0x0000003c
+#define SPIDER_NET_GONETIMENUM         0x00000040
+
+#define SPIDER_NET_GTOUTFRMNUM         0x00000044
+
+#define SPIDER_NET_GTXMDSET            0x00000050
+#define SPIDER_NET_GPCCTRL             0x00000054
+#define SPIDER_NET_GRXMDSET            0x00000058
+#define SPIDER_NET_GIPSECINIT          0x0000005c
+#define SPIDER_NET_GFTRESTRT           0x00000060
+#define SPIDER_NET_GRXDMAEN            0x00000064
+#define SPIDER_NET_GMRWOLCTRL          0x00000068
+#define SPIDER_NET_GPCWOPCMD           0x0000006c
+#define SPIDER_NET_GPCROPCMD           0x00000070
+#define SPIDER_NET_GTTFRMCNT           0x00000078
+#define SPIDER_NET_GTESTMD             0x0000007c
+
+#define SPIDER_NET_GSINIT              0x00000080
+#define SPIDER_NET_GSnPRGADR           0x00000084
+#define SPIDER_NET_GSnPRGDAT           0x00000088
+
+#define SPIDER_NET_GMACOPEMD           0x00000100
+#define SPIDER_NET_GMACLENLMT          0x00000108
+#define SPIDER_NET_GMACINTEN           0x00000118
+#define SPIDER_NET_GMACPHYCTRL         0x00000120
+
+#define SPIDER_NET_GMACAPAUSE          0x00000154
+#define SPIDER_NET_GMACTXPAUSE         0x00000164
+
+#define SPIDER_NET_GMACMODE            0x000001b0
+#define SPIDER_NET_GMACBSTLMT          0x000001b4
+
+#define SPIDER_NET_GMACUNIMACU         0x000001c0
+#define SPIDER_NET_GMACUNIMACL         0x000001c8
+
+#define SPIDER_NET_GMRMHFILnR          0x00000400
+#define SPIDER_NET_MULTICAST_HASHES    256
+
+#define SPIDER_NET_GMRUAFILnR          0x00000500
+#define SPIDER_NET_GMRUA0FIL15R                0x00000578
+
+/* RX DMA controller registers, all 0x00000a.. are for DMA controller A,
+ * 0x00000b.. for DMA controller B, etc. */
+#define SPIDER_NET_GDADCHA             0x00000a00
+#define SPIDER_NET_GDADMACCNTR         0x00000a04
+#define SPIDER_NET_GDACTDPA            0x00000a08
+#define SPIDER_NET_GDACTDCNT           0x00000a0c
+#define SPIDER_NET_GDACDBADDR          0x00000a20
+#define SPIDER_NET_GDACDBSIZE          0x00000a24
+#define SPIDER_NET_GDACNEXTDA          0x00000a28
+#define SPIDER_NET_GDACCOMST           0x00000a2c
+#define SPIDER_NET_GDAWBCOMST          0x00000a30
+#define SPIDER_NET_GDAWBRSIZE          0x00000a34
+#define SPIDER_NET_GDAWBVSIZE          0x00000a38
+#define SPIDER_NET_GDAWBTRST           0x00000a3c
+#define SPIDER_NET_GDAWBTRERR          0x00000a40
+
+/* TX DMA controller registers */
+#define SPIDER_NET_GDTDCHA             0x00000e00
+#define SPIDER_NET_GDTDMACCNTR         0x00000e04
+#define SPIDER_NET_GDTCDPA             0x00000e08
+#define SPIDER_NET_GDTDMASEL           0x00000e14
+
+#define SPIDER_NET_ECMODE              0x00000f00
+/* clock and reset control register */
+#define SPIDER_NET_CKRCTRL             0x00000ff0
+
+/** SCONFIG registers */
+#define SPIDER_NET_SCONFIG_IOACTE      0x00002810
+
+/** hardcoded register values */
+#define SPIDER_NET_INT0_MASK_VALUE     0x3f7fe3ff
+#define SPIDER_NET_INT1_MASK_VALUE     0xffffffff
+/* no MAC aborts -> auto retransmission */
+#define SPIDER_NET_INT2_MASK_VALUE     0xfffffff1
+
+/* clear counter when interrupt sources are cleared
+#define SPIDER_NET_FRAMENUM_VALUE      0x0001f001 */
+/* we rely on flagged descriptor interrupts */
+#define SPIDER_NET_FRAMENUM_VALUE      0x00000000
+/* set this first, then the FRAMENUM_VALUE */
+#define SPIDER_NET_GFXFRAMES_VALUE     0x00000000
+
+#define SPIDER_NET_STOP_SEQ_VALUE      0x00000000
+#define SPIDER_NET_RUN_SEQ_VALUE       0x0000007e
+
+#define SPIDER_NET_PHY_CTRL_VALUE      0x00040040
+/* #define SPIDER_NET_PHY_CTRL_VALUE   0x01070080*/
+#define SPIDER_NET_RXMODE_VALUE                0x00000011
+/* auto retransmission in case of MAC aborts */
+#define SPIDER_NET_TXMODE_VALUE                0x00010000
+#define SPIDER_NET_RESTART_VALUE       0x00000000
+#define SPIDER_NET_WOL_VALUE           0x00001111
+#if 0
+#define SPIDER_NET_WOL_VALUE           0x00000000
+#endif
+#define SPIDER_NET_IPSECINIT_VALUE     0x00f000f8
+
+/* pause frames: automatic, no upper retransmission count */
+/* outside loopback mode: ETOMOD signal dont matter, not connected */
+#define SPIDER_NET_OPMODE_VALUE                0x00000063
+/*#define SPIDER_NET_OPMODE_VALUE              0x001b0062*/
+#define SPIDER_NET_LENLMT_VALUE                0x00000908
+
+#define SPIDER_NET_MACAPAUSE_VALUE     0x00000800 /* about 1 ms */
+#define SPIDER_NET_TXPAUSE_VALUE       0x00000000
+
+#define SPIDER_NET_MACMODE_VALUE       0x00000001
+#define SPIDER_NET_BURSTLMT_VALUE      0x00000200 /* about 16 us */
+
+/* 1(0)                                        enable r/tx dma
+ *  0000000                            fixed to 0
+ *
+ *         000000                      fixed to 0
+ *               0(1)                  en/disable descr writeback on force end
+ *                0(1)                 force end
+ *
+ *                 000000              fixed to 0
+ *                       00            burst alignment: 128 bytes
+ *
+ *                         00000       fixed to 0
+ *                              0      descr writeback size 32 bytes
+ *                               0(1)  descr chain end interrupt enable
+ *                                0(1) descr status writeback enable */
+
+/* to set RX_DMA_EN */
+#define SPIDER_NET_DMA_RX_VALUE                0x80000000
+#define SPIDER_NET_DMA_RX_FEND_VALUE   0x00030003
+/* to set TX_DMA_EN */
+#define SPIDER_NET_DMA_TX_VALUE                0x80000000
+#define SPIDER_NET_DMA_TX_FEND_VALUE   0x00030003
+
+/* SPIDER_NET_UA_DESCR_VALUE is OR'ed with the unicast address */
+#define SPIDER_NET_UA_DESCR_VALUE      0x00080000
+#define SPIDER_NET_PROMISC_VALUE       0x00080000
+#define SPIDER_NET_NONPROMISC_VALUE    0x00000000
+
+#define SPIDER_NET_DMASEL_VALUE                0x00000001
+
+#define SPIDER_NET_ECMODE_VALUE                0x00000000
+
+#define SPIDER_NET_CKRCTRL_RUN_VALUE   0x1fff010f
+#define SPIDER_NET_CKRCTRL_STOP_VALUE  0x0000010f
+
+#define SPIDER_NET_SBIMSTATE_VALUE     0x00000000
+#define SPIDER_NET_SBTMSTATE_VALUE     0x00000000
+
+/* SPIDER_NET_GHIINT0STS bits, in reverse order so that they can be used
+ * with 1 << SPIDER_NET_... */
+enum spider_net_int0_status {
+       SPIDER_NET_GPHYINT = 0,
+       SPIDER_NET_GMAC2INT,
+       SPIDER_NET_GMAC1INT,
+       SPIDER_NET_GIPSINT,
+       SPIDER_NET_GFIFOINT,
+       SPIDER_NET_GDMACINT,
+       SPIDER_NET_GSYSINT,
+       SPIDER_NET_GPWOPCMPINT,
+       SPIDER_NET_GPROPCMPINT,
+       SPIDER_NET_GPWFFINT,
+       SPIDER_NET_GRMDADRINT,
+       SPIDER_NET_GRMARPINT,
+       SPIDER_NET_GRMMPINT,
+       SPIDER_NET_GDTDEN0INT,
+       SPIDER_NET_GDDDEN0INT,
+       SPIDER_NET_GDCDEN0INT,
+       SPIDER_NET_GDBDEN0INT,
+       SPIDER_NET_GDADEN0INT,
+       SPIDER_NET_GDTFDCINT,
+       SPIDER_NET_GDDFDCINT,
+       SPIDER_NET_GDCFDCINT,
+       SPIDER_NET_GDBFDCINT,
+       SPIDER_NET_GDAFDCINT,
+       SPIDER_NET_GTTEDINT,
+       SPIDER_NET_GDTDCEINT,
+       SPIDER_NET_GRFDNMINT,
+       SPIDER_NET_GRFCNMINT,
+       SPIDER_NET_GRFBNMINT,
+       SPIDER_NET_GRFANMINT,
+       SPIDER_NET_GRFNMINT,
+       SPIDER_NET_G1TMCNTINT,
+       SPIDER_NET_GFREECNTINT
+};
+/* GHIINT1STS bits */
+enum spider_net_int1_status {
+       SPIDER_NET_GTMFLLINT = 0,
+       SPIDER_NET_GRMFLLINT,
+       SPIDER_NET_GTMSHTINT,
+       SPIDER_NET_GDTINVDINT,
+       SPIDER_NET_GRFDFLLINT,
+       SPIDER_NET_GDDDCEINT,
+       SPIDER_NET_GDDINVDINT,
+       SPIDER_NET_GRFCFLLINT,
+       SPIDER_NET_GDCDCEINT,
+       SPIDER_NET_GDCINVDINT,
+       SPIDER_NET_GRFBFLLINT,
+       SPIDER_NET_GDBDCEINT,
+       SPIDER_NET_GDBINVDINT,
+       SPIDER_NET_GRFAFLLINT,
+       SPIDER_NET_GDADCEINT,
+       SPIDER_NET_GDAINVDINT,
+       SPIDER_NET_GDTRSERINT,
+       SPIDER_NET_GDDRSERINT,
+       SPIDER_NET_GDCRSERINT,
+       SPIDER_NET_GDBRSERINT,
+       SPIDER_NET_GDARSERINT,
+       SPIDER_NET_GDSERINT,
+       SPIDER_NET_GDTPTERINT,
+       SPIDER_NET_GDDPTERINT,
+       SPIDER_NET_GDCPTERINT,
+       SPIDER_NET_GDBPTERINT,
+       SPIDER_NET_GDAPTERINT
+};
+/* GHIINT2STS bits */
+enum spider_net_int2_status {
+       SPIDER_NET_GPROPERINT = 0,
+       SPIDER_NET_GMCTCRSNGINT,
+       SPIDER_NET_GMCTLCOLINT,
+       SPIDER_NET_GMCTTMOTINT,
+       SPIDER_NET_GMCRCAERINT,
+       SPIDER_NET_GMCRCALERINT,
+       SPIDER_NET_GMCRALNERINT,
+       SPIDER_NET_GMCROVRINT,
+       SPIDER_NET_GMCRRNTINT,
+       SPIDER_NET_GMCRRXERINT,
+       SPIDER_NET_GTITCSERINT,
+       SPIDER_NET_GTIFMTERINT,
+       SPIDER_NET_GTIPKTRVKINT,
+       SPIDER_NET_GTISPINGINT,
+       SPIDER_NET_GTISADNGINT,
+       SPIDER_NET_GTISPDNGINT,
+       SPIDER_NET_GRIFMTERINT,
+       SPIDER_NET_GRIPKTRVKINT,
+       SPIDER_NET_GRISPINGINT,
+       SPIDER_NET_GRISADNGINT,
+       SPIDER_NET_GRISPDNGINT
+};
+
+#define SPIDER_NET_TXINT       ( (1 << SPIDER_NET_GTTEDINT) | \
+                                 (1 << SPIDER_NET_GDTDCEINT) | \
+                                 (1 << SPIDER_NET_GDTFDCINT) )
+
+/* we rely on flagged descriptor interrupts*/
+#define SPIDER_NET_RXINT       ( (1 << SPIDER_NET_GDAFDCINT) | \
+                                 (1 << SPIDER_NET_GRMFLLINT) )
+
+#define SPIDER_NET_GPREXEC             0x80000000
+#define SPIDER_NET_GPRDAT_MASK         0x0000ffff
+
+/* descriptor bits
+ *
+ * 1010                                        descriptor ready
+ *     0                               descr in middle of chain
+ *      000                            fixed to 0
+ *
+ *         0                           no interrupt on completion
+ *          000                                fixed to 0
+ *             1                       no ipsec processing
+ *              1                      last descriptor for this frame
+ *               00                    no checksum
+ *               10                    tcp checksum
+ *               11                    udp checksum
+ *
+ *                 00                  fixed to 0
+ *                   0                 fixed to 0
+ *                    0                        no interrupt on response errors
+ *                     0               no interrupt on invalid descr
+ *                      0              no interrupt on dma process termination
+ *                       0             no interrupt on descr chain end
+ *                        0            no interrupt on descr complete
+ *
+ *                         000         fixed to 0
+ *                            0                response error interrupt status
+ *                             0       invalid descr status
+ *                              0      dma termination status
+ *                               0     descr chain end status
+ *                                0    descr complete status */
+#define SPIDER_NET_DMAC_CMDSTAT_NOCS   0xa00c0000
+#define SPIDER_NET_DMAC_CMDSTAT_TCPCS  0xa00e0000
+#define SPIDER_NET_DMAC_CMDSTAT_UDPCS  0xa00f0000
+#define SPIDER_NET_DESCR_IND_PROC_SHIFT        28
+#define SPIDER_NET_DESCR_IND_PROC_MASKO        0x0fffffff
+
+/* descr ready, descr is in middle of chain, get interrupt on completion */
+#define SPIDER_NET_DMAC_RX_CARDOWNED   0xa0800000
+
+/* multicast is no problem */
+#define SPIDER_NET_DATA_ERROR_MASK     0xffffbfff
+
+enum spider_net_descr_status {
+       SPIDER_NET_DESCR_COMPLETE               = 0x00, /* used in rx and tx */
+       SPIDER_NET_DESCR_RESPONSE_ERROR         = 0x01, /* used in rx and tx */
+       SPIDER_NET_DESCR_PROTECTION_ERROR       = 0x02, /* used in rx and tx */
+       SPIDER_NET_DESCR_FRAME_END              = 0x04, /* used in rx */
+       SPIDER_NET_DESCR_FORCE_END              = 0x05, /* used in rx and tx */
+       SPIDER_NET_DESCR_CARDOWNED              = 0x0a, /* used in rx and tx */
+       SPIDER_NET_DESCR_NOT_IN_USE /* any other value */
+};
+
+struct spider_net_descr {
+       /* as defined by the hardware */
+       dma_addr_t buf_addr;
+       u32 buf_size;
+       dma_addr_t next_descr_addr;
+       u32 dmac_cmd_status;
+       u32 result_size;
+       u32 valid_size; /* all zeroes for tx */
+       u32 data_status;
+       u32 data_error; /* all zeroes for tx */
+
+       /* used in the driver */
+       struct sk_buff *skb;
+       dma_addr_t bus_addr;
+       struct spider_net_descr *next;
+       struct spider_net_descr *prev;
+} __attribute__((aligned(32)));
+
+struct spider_net_descr_chain {
+       /* we walk from tail to head */
+       struct spider_net_descr *head;
+       struct spider_net_descr *tail;
+};
+
+/* descriptor data_status bits */
+#define SPIDER_NET_RXIPCHK             29
+#define SPIDER_NET_TCPUDPIPCHK         28
+#define SPIDER_NET_DATA_STATUS_CHK_MASK        (1 << SPIDER_NET_RXIPCHK | \
+                                        1 << SPIDER_NET_TCPUDPIPCHK)
+
+#define SPIDER_NET_VLAN_PACKET         21
+
+/* descriptor data_error bits */
+#define SPIDER_NET_RXIPCHKERR          27
+#define SPIDER_NET_RXTCPCHKERR         26
+#define SPIDER_NET_DATA_ERROR_CHK_MASK (1 << SPIDER_NET_RXIPCHKERR | \
+                                        1 << SPIDER_NET_RXTCPCHKERR)
+
+/* the cases we don't pass the packet to the stack */
+#define SPIDER_NET_DESTROY_RX_FLAGS    0x70138000
+
+#define SPIDER_NET_DESCR_SIZE          32
+
+/* this will be bigger some time */
+struct spider_net_options {
+       int rx_csum; /* for rx: if 0 ip_summed=NONE,
+                       if 1 and hw has verified, ip_summed=UNNECESSARY */
+};
+
+#define SPIDER_NET_DEFAULT_MSG         ( NETIF_MSG_DRV | \
+                                         NETIF_MSG_PROBE | \
+                                         NETIF_MSG_LINK | \
+                                         NETIF_MSG_TIMER | \
+                                         NETIF_MSG_IFDOWN | \
+                                         NETIF_MSG_IFUP | \
+                                         NETIF_MSG_RX_ERR | \
+                                         NETIF_MSG_TX_ERR | \
+                                         NETIF_MSG_TX_QUEUED | \
+                                         NETIF_MSG_INTR | \
+                                         NETIF_MSG_TX_DONE | \
+                                         NETIF_MSG_RX_STATUS | \
+                                         NETIF_MSG_PKTDATA | \
+                                         NETIF_MSG_HW | \
+                                         NETIF_MSG_WOL )
+
+struct spider_net_card {
+       struct net_device *netdev;
+       struct pci_dev *pdev;
+       struct mii_phy phy;
+
+       void __iomem *regs;
+
+       struct spider_net_descr_chain tx_chain;
+       struct spider_net_descr_chain rx_chain;
+       spinlock_t chain_lock;
+
+       struct net_device_stats netdev_stats;
+
+       struct spider_net_options options;
+
+       spinlock_t intmask_lock;
+
+       struct work_struct tx_timeout_task;
+       atomic_t tx_timeout_task_counter;
+       wait_queue_head_t waitq;
+
+       /* for ethtool */
+       int msg_enable;
+
+       struct spider_net_descr descr[0];
+};
+
+#define pr_err(fmt,arg...) \
+       printk(KERN_ERR fmt ,##arg)
+
+#endif
diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c
new file mode 100644 (file)
index 0000000..d42e60b
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Network device driver for Cell Processor-Based Blade
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Authors : Utz Bacher <utz.bacher@de.ibm.com>
+ *           Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/pci.h>
+
+#include "spider_net.h"
+
+static int
+spider_net_ethtool_get_settings(struct net_device *netdev,
+                              struct ethtool_cmd *cmd)
+{
+       struct spider_net_card *card;
+       card = netdev_priv(netdev);
+
+       cmd->supported   = (SUPPORTED_1000baseT_Full |
+                            SUPPORTED_FIBRE);
+       cmd->advertising = (ADVERTISED_1000baseT_Full |
+                            ADVERTISED_FIBRE);
+       cmd->port = PORT_FIBRE;
+       cmd->speed = card->phy.speed;
+       cmd->duplex = DUPLEX_FULL;
+
+       return 0;
+}
+
+static void
+spider_net_ethtool_get_drvinfo(struct net_device *netdev,
+                              struct ethtool_drvinfo *drvinfo)
+{
+       struct spider_net_card *card;
+       card = netdev_priv(netdev);
+
+       /* clear and fill out info */
+       memset(drvinfo, 0, sizeof(struct ethtool_drvinfo));
+       strncpy(drvinfo->driver, spider_net_driver_name, 32);
+       strncpy(drvinfo->version, "0.1", 32);
+       strcpy(drvinfo->fw_version, "no information");
+       strncpy(drvinfo->bus_info, pci_name(card->pdev), 32);
+}
+
+static void
+spider_net_ethtool_get_wol(struct net_device *netdev,
+                          struct ethtool_wolinfo *wolinfo)
+{
+       /* no support for wol */
+       wolinfo->supported = 0;
+       wolinfo->wolopts = 0;
+}
+
+static u32
+spider_net_ethtool_get_msglevel(struct net_device *netdev)
+{
+       struct spider_net_card *card;
+       card = netdev_priv(netdev);
+       return card->msg_enable;
+}
+
+static void
+spider_net_ethtool_set_msglevel(struct net_device *netdev,
+                               u32 level)
+{
+       struct spider_net_card *card;
+       card = netdev_priv(netdev);
+       card->msg_enable = level;
+}
+
+static int
+spider_net_ethtool_nway_reset(struct net_device *netdev)
+{
+       if (netif_running(netdev)) {
+               spider_net_stop(netdev);
+               spider_net_open(netdev);
+       }
+       return 0;
+}
+
+static u32
+spider_net_ethtool_get_rx_csum(struct net_device *netdev)
+{
+       struct spider_net_card *card = netdev->priv;
+
+       return card->options.rx_csum;
+}
+
+static int
+spider_net_ethtool_set_rx_csum(struct net_device *netdev, u32 n)
+{
+       struct spider_net_card *card = netdev->priv;
+
+       card->options.rx_csum = n;
+       return 0;
+}
+
+struct ethtool_ops spider_net_ethtool_ops = {
+       .get_settings           = spider_net_ethtool_get_settings,
+       .get_drvinfo            = spider_net_ethtool_get_drvinfo,
+       .get_wol                = spider_net_ethtool_get_wol,
+       .get_msglevel           = spider_net_ethtool_get_msglevel,
+       .set_msglevel           = spider_net_ethtool_set_msglevel,
+       .nway_reset             = spider_net_ethtool_nway_reset,
+       .get_rx_csum            = spider_net_ethtool_get_rx_csum,
+       .set_rx_csum            = spider_net_ethtool_set_rx_csum,
+};
+
index 1f43bbfbc1c78af3a95902ed37d602623b1ab292..5c8fcd40ef4d29936fad6828d3fda9d9df58ffcd 100644 (file)
@@ -162,7 +162,7 @@ struct lance_private {
 #define        MEM     lp->mem
 #define        DREG    lp->iobase[0]
 #define        AREG    lp->iobase[1]
-#define        REGA(a) ( AREG = (a), DREG )
+#define        REGA(a) (*( AREG = (a), &DREG ))
 
 /* Definitions for the Lance */
 
index 2608e7a3d214b280d8d1ec12a265612a477bd14a..3f67a42e8503f2f3ee243324023fe41319d63ae4 100644 (file)
@@ -948,6 +948,7 @@ static irqreturn_t gem_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                u32 gem_status = readl(gp->regs + GREG_STAT);
 
                if (gem_status == 0) {
+                       netif_poll_enable(dev);
                        spin_unlock_irqrestore(&gp->lock, flags);
                        return IRQ_NONE;
                }
index 7143fd7cf3f84fd3fbf5867ee482a2e35037bd66..ff8ae5f7997001f3725a0d943f89e5937dc57f87 100644 (file)
@@ -1020,7 +1020,7 @@ struct gem {
                
        struct gem_init_block   *init_block;
        struct sk_buff          *rx_skbs[RX_RING_SIZE];
-       struct sk_buff          *tx_skbs[RX_RING_SIZE];
+       struct sk_buff          *tx_skbs[TX_RING_SIZE];
        dma_addr_t              gblock_dvma;
 
        struct pci_dev          *pdev;
index 6d4ab1e333b55a6579baa4362501a873f86899c2..dc57352e5a974e8f7c64433e71cda98728ac5d0b 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/workqueue.h>
+#include <linux/prefetch.h>
 
 #include <net/checksum.h>
 
@@ -66,8 +67,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.37"
-#define DRV_MODULE_RELDATE     "August 25, 2005"
+#define DRV_MODULE_VERSION     "3.39"
+#define DRV_MODULE_RELDATE     "September 5, 2005"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
                                   TG3_RX_RCB_RING_SIZE(tp))
 #define TG3_TX_RING_BYTES      (sizeof(struct tg3_tx_buffer_desc) * \
                                 TG3_TX_RING_SIZE)
-#define TX_RING_GAP(TP)        \
-       (TG3_TX_RING_SIZE - (TP)->tx_pending)
 #define TX_BUFFS_AVAIL(TP)                                             \
-       (((TP)->tx_cons <= (TP)->tx_prod) ?                             \
-         (TP)->tx_cons + (TP)->tx_pending - (TP)->tx_prod :            \
-         (TP)->tx_cons - (TP)->tx_prod - TX_RING_GAP(TP))
+       ((TP)->tx_pending -                                             \
+        (((TP)->tx_prod - (TP)->tx_cons) & (TG3_TX_RING_SIZE - 1)))
 #define NEXT_TX(N)             (((N) + 1) & (TG3_TX_RING_SIZE - 1))
 
 #define RX_PKT_BUF_SZ          (1536 + tp->rx_offset + 64)
@@ -340,41 +338,92 @@ static struct {
 
 static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
 {
-       if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) {
-               spin_lock_bh(&tp->indirect_lock);
-               pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off);
-               pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val);
-               spin_unlock_bh(&tp->indirect_lock);
-       } else {
-               writel(val, tp->regs + off);
-               if ((tp->tg3_flags & TG3_FLAG_5701_REG_WRITE_BUG) != 0)
-                       readl(tp->regs + off);
+       unsigned long flags;
+
+       spin_lock_irqsave(&tp->indirect_lock, flags);
+       pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off);
+       pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val);
+       spin_unlock_irqrestore(&tp->indirect_lock, flags);
+}
+
+static void tg3_write_flush_reg32(struct tg3 *tp, u32 off, u32 val)
+{
+       writel(val, tp->regs + off);
+       readl(tp->regs + off);
+}
+
+static u32 tg3_read_indirect_reg32(struct tg3 *tp, u32 off)
+{
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&tp->indirect_lock, flags);
+       pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off);
+       pci_read_config_dword(tp->pdev, TG3PCI_REG_DATA, &val);
+       spin_unlock_irqrestore(&tp->indirect_lock, flags);
+       return val;
+}
+
+static void tg3_write_indirect_mbox(struct tg3 *tp, u32 off, u32 val)
+{
+       unsigned long flags;
+
+       if (off == (MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW)) {
+               pci_write_config_dword(tp->pdev, TG3PCI_RCV_RET_RING_CON_IDX +
+                                      TG3_64BIT_REG_LOW, val);
+               return;
        }
+       if (off == (MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW)) {
+               pci_write_config_dword(tp->pdev, TG3PCI_STD_RING_PROD_IDX +
+                                      TG3_64BIT_REG_LOW, val);
+               return;
+       }
+
+       spin_lock_irqsave(&tp->indirect_lock, flags);
+       pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off + 0x5600);
+       pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val);
+       spin_unlock_irqrestore(&tp->indirect_lock, flags);
+
+       /* In indirect mode when disabling interrupts, we also need
+        * to clear the interrupt bit in the GRC local ctrl register.
+        */
+       if ((off == (MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW)) &&
+           (val == 0x1)) {
+               pci_write_config_dword(tp->pdev, TG3PCI_MISC_LOCAL_CTRL,
+                                      tp->grc_local_ctrl|GRC_LCLCTRL_CLEARINT);
+       }
+}
+
+static u32 tg3_read_indirect_mbox(struct tg3 *tp, u32 off)
+{
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&tp->indirect_lock, flags);
+       pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off + 0x5600);
+       pci_read_config_dword(tp->pdev, TG3PCI_REG_DATA, &val);
+       spin_unlock_irqrestore(&tp->indirect_lock, flags);
+       return val;
 }
 
 static void _tw32_flush(struct tg3 *tp, u32 off, u32 val)
 {
-       if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) {
-               spin_lock_bh(&tp->indirect_lock);
-               pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off);
-               pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val);
-               spin_unlock_bh(&tp->indirect_lock);
-       } else {
-               void __iomem *dest = tp->regs + off;
-               writel(val, dest);
-               readl(dest);    /* always flush PCI write */
-       }
+       tp->write32(tp, off, val);
+       if (!(tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) &&
+           !(tp->tg3_flags & TG3_FLAG_5701_REG_WRITE_BUG) &&
+           !(tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND))
+               tp->read32(tp, off);    /* flush */
 }
 
-static inline void _tw32_rx_mbox(struct tg3 *tp, u32 off, u32 val)
+static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val)
 {
-       void __iomem *mbox = tp->regs + off;
-       writel(val, mbox);
-       if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
-               readl(mbox);
+       tp->write32_mbox(tp, off, val);
+       if (!(tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) &&
+           !(tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND))
+               tp->read32_mbox(tp, off);
 }
 
-static inline void _tw32_tx_mbox(struct tg3 *tp, u32 off, u32 val)
+static void tg3_write32_tx_mbox(struct tg3 *tp, u32 off, u32 val)
 {
        void __iomem *mbox = tp->regs + off;
        writel(val, mbox);
@@ -384,51 +433,63 @@ static inline void _tw32_tx_mbox(struct tg3 *tp, u32 off, u32 val)
                readl(mbox);
 }
 
-#define tw32_mailbox(reg, val)  writel(((val) & 0xffffffff), tp->regs + (reg))
-#define tw32_rx_mbox(reg, val)  _tw32_rx_mbox(tp, reg, val)
-#define tw32_tx_mbox(reg, val)  _tw32_tx_mbox(tp, reg, val)
+static void tg3_write32(struct tg3 *tp, u32 off, u32 val)
+{
+       writel(val, tp->regs + off);
+}
+
+static u32 tg3_read32(struct tg3 *tp, u32 off)
+{
+       return (readl(tp->regs + off)); 
+}
 
-#define tw32(reg,val)          tg3_write_indirect_reg32(tp,(reg),(val))
+#define tw32_mailbox(reg, val) tp->write32_mbox(tp, reg, val)
+#define tw32_mailbox_f(reg, val)       tw32_mailbox_flush(tp, (reg), (val))
+#define tw32_rx_mbox(reg, val) tp->write32_rx_mbox(tp, reg, val)
+#define tw32_tx_mbox(reg, val) tp->write32_tx_mbox(tp, reg, val)
+#define tr32_mailbox(reg)      tp->read32_mbox(tp, reg)
+
+#define tw32(reg,val)          tp->write32(tp, reg, val)
 #define tw32_f(reg,val)                _tw32_flush(tp,(reg),(val))
-#define tw16(reg,val)          writew(((val) & 0xffff), tp->regs + (reg))
-#define tw8(reg,val)           writeb(((val) & 0xff), tp->regs + (reg))
-#define tr32(reg)              readl(tp->regs + (reg))
-#define tr16(reg)              readw(tp->regs + (reg))
-#define tr8(reg)               readb(tp->regs + (reg))
+#define tr32(reg)              tp->read32(tp, reg)
 
 static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val)
 {
-       spin_lock_bh(&tp->indirect_lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&tp->indirect_lock, flags);
        pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
        pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
 
        /* Always leave this as zero. */
        pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
-       spin_unlock_bh(&tp->indirect_lock);
+       spin_unlock_irqrestore(&tp->indirect_lock, flags);
 }
 
 static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
 {
-       spin_lock_bh(&tp->indirect_lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&tp->indirect_lock, flags);
        pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
        pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
 
        /* Always leave this as zero. */
        pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
-       spin_unlock_bh(&tp->indirect_lock);
+       spin_unlock_irqrestore(&tp->indirect_lock, flags);
 }
 
 static void tg3_disable_ints(struct tg3 *tp)
 {
        tw32(TG3PCI_MISC_HOST_CTRL,
             (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
-       tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
-       tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
+       tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
 }
 
 static inline void tg3_cond_int(struct tg3 *tp)
 {
-       if (tp->hw_status->status & SD_STATUS_UPDATED)
+       if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) &&
+           (tp->hw_status->status & SD_STATUS_UPDATED))
                tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
 }
 
@@ -439,9 +500,8 @@ static void tg3_enable_ints(struct tg3 *tp)
 
        tw32(TG3PCI_MISC_HOST_CTRL,
             (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
-       tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
-                    (tp->last_tag << 24));
-       tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
+       tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+                      (tp->last_tag << 24));
        tg3_cond_int(tp);
 }
 
@@ -472,8 +532,6 @@ static inline unsigned int tg3_has_work(struct tg3 *tp)
  */
 static void tg3_restart_ints(struct tg3 *tp)
 {
-       tw32(TG3PCI_MISC_HOST_CTRL,
-               (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
        tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
                     tp->last_tag << 24);
        mmiowb();
@@ -2821,9 +2879,13 @@ static void tg3_tx(struct tg3 *tp)
 
        tp->tx_cons = sw_idx;
 
-       if (netif_queue_stopped(tp->dev) &&
-           (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH))
-               netif_wake_queue(tp->dev);
+       if (unlikely(netif_queue_stopped(tp->dev))) {
+               spin_lock(&tp->tx_lock);
+               if (netif_queue_stopped(tp->dev) &&
+                   (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH))
+                       netif_wake_queue(tp->dev);
+               spin_unlock(&tp->tx_lock);
+       }
 }
 
 /* Returns size of skb allocated or < 0 on error.
@@ -3139,9 +3201,7 @@ static int tg3_poll(struct net_device *netdev, int *budget)
 
        /* run TX completion thread */
        if (sblk->idx[0].tx_consumer != tp->tx_cons) {
-               spin_lock(&tp->tx_lock);
                tg3_tx(tp);
-               spin_unlock(&tp->tx_lock);
        }
 
        /* run RX thread, within the bounds set by NAPI.
@@ -3161,18 +3221,17 @@ static int tg3_poll(struct net_device *netdev, int *budget)
                netdev->quota -= work_done;
        }
 
-       if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
+       if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
                tp->last_tag = sblk->status_tag;
-       rmb();
-       sblk->status &= ~SD_STATUS_UPDATED;
+               rmb();
+       } else
+               sblk->status &= ~SD_STATUS_UPDATED;
 
        /* if no more work, tell net stack and NIC we're done */
        done = !tg3_has_work(tp);
        if (done) {
-               spin_lock(&tp->lock);
                netif_rx_complete(netdev);
                tg3_restart_ints(tp);
-               spin_unlock(&tp->lock);
        }
 
        return (done ? 0 : 1);
@@ -3220,8 +3279,9 @@ static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs)
 {
        struct net_device *dev = dev_id;
        struct tg3 *tp = netdev_priv(dev);
-       struct tg3_hw_status *sblk = tp->hw_status;
 
+       prefetch(tp->hw_status);
+       prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
        /*
         * Writing any value to intr-mbox-0 clears PCI INTA# and
         * chip-internal interrupt pending events.
@@ -3230,19 +3290,9 @@ static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs)
         * event coalescing.
         */
        tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
-       tp->last_tag = sblk->status_tag;
-       rmb();
-       if (tg3_irq_sync(tp))
-               goto out;
-       sblk->status &= ~SD_STATUS_UPDATED;
-       if (likely(tg3_has_work(tp)))
+       if (likely(!tg3_irq_sync(tp)))
                netif_rx_schedule(dev);         /* schedule NAPI poll */
-       else {
-               /* No work, re-enable interrupts.  */
-               tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
-                            tp->last_tag << 24);
-       }
-out:
+
        return IRQ_RETVAL(1);
 }
 
@@ -3272,15 +3322,15 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                if (tg3_irq_sync(tp))
                        goto out;
                sblk->status &= ~SD_STATUS_UPDATED;
-               if (likely(tg3_has_work(tp)))
+               if (likely(tg3_has_work(tp))) {
+                       prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
                        netif_rx_schedule(dev);         /* schedule NAPI poll */
-               else {
+               else {
                        /* No work, shared interrupt perhaps?  re-enable
                         * interrupts, and flush that PCI write
                         */
-                       tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+                       tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
                                0x00000000);
-                       tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
                }
        } else {        /* shared interrupt */
                handled = 0;
@@ -3301,7 +3351,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *r
         * Reading the PCI State register will confirm whether the
         * interrupt is ours and will flush the status block.
         */
-       if ((sblk->status & SD_STATUS_UPDATED) ||
+       if ((sblk->status_tag != tp->last_tag) ||
            !(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) {
                /*
                 * writing any value to intr-mbox-0 clears PCI INTA# and
@@ -3312,20 +3362,17 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *r
                 */
                tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
                             0x00000001);
-               tp->last_tag = sblk->status_tag;
-               rmb();
                if (tg3_irq_sync(tp))
                        goto out;
-               sblk->status &= ~SD_STATUS_UPDATED;
-               if (likely(tg3_has_work(tp)))
-                       netif_rx_schedule(dev);         /* schedule NAPI poll */
-               else {
-                       /* no work, shared interrupt perhaps?  re-enable
-                        * interrupts, and flush that PCI write
+               if (netif_rx_schedule_prep(dev)) {
+                       prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
+                       /* Update last_tag to mark that this status has been
+                        * seen. Because interrupt may be shared, we may be
+                        * racing with tg3_poll(), so only update last_tag
+                        * if tg3_poll() is not scheduled.
                         */
-                       tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
-                                    tp->last_tag << 24);
-                       tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
+                       tp->last_tag = sblk->status_tag;
+                       __netif_rx_schedule(dev);
                }
        } else {        /* shared interrupt */
                handled = 0;
@@ -3659,8 +3706,11 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
        tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry);
 
        tp->tx_prod = entry;
-       if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1))
+       if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1)) {
                netif_stop_queue(dev);
+               if (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH)
+                       netif_wake_queue(tp->dev);
+       }
 
 out_unlock:
        mmiowb();
@@ -4216,7 +4266,7 @@ static void tg3_stop_fw(struct tg3 *);
 static int tg3_chip_reset(struct tg3 *tp)
 {
        u32 val;
-       u32 flags_save;
+       void (*write_op)(struct tg3 *, u32, u32);
        int i;
 
        if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X))
@@ -4228,8 +4278,9 @@ static int tg3_chip_reset(struct tg3 *tp)
         * fun things.  So, temporarily disable the 5701
         * hardware workaround, while we do the reset.
         */
-       flags_save = tp->tg3_flags;
-       tp->tg3_flags &= ~TG3_FLAG_5701_REG_WRITE_BUG;
+       write_op = tp->write32;
+       if (write_op == tg3_write_flush_reg32)
+               tp->write32 = tg3_write32;
 
        /* do the reset */
        val = GRC_MISC_CFG_CORECLK_RESET;
@@ -4248,8 +4299,8 @@ static int tg3_chip_reset(struct tg3 *tp)
                val |= GRC_MISC_CFG_KEEP_GPHY_POWER;
        tw32(GRC_MISC_CFG, val);
 
-       /* restore 5701 hardware bug workaround flag */
-       tp->tg3_flags = flags_save;
+       /* restore 5701 hardware bug workaround write method */
+       tp->write32 = write_op;
 
        /* Unfortunately, we have to delay before the PCI read back.
         * Some 575X chips even will not respond to a PCI cfg access
@@ -4635,7 +4686,6 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_b
                                 int cpu_scratch_size, struct fw_info *info)
 {
        int err, i;
-       u32 orig_tg3_flags = tp->tg3_flags;
        void (*write_op)(struct tg3 *, u32, u32);
 
        if (cpu_base == TX_CPU_BASE &&
@@ -4651,11 +4701,6 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_b
        else
                write_op = tg3_write_indirect_reg32;
 
-       /* Force use of PCI config space for indirect register
-        * write calls.
-        */
-       tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
-
        /* It is possible that bootcode is still loading at this point.
         * Get the nvram lock first before halting the cpu.
         */
@@ -4691,7 +4736,6 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_b
        err = 0;
 
 out:
-       tp->tg3_flags = orig_tg3_flags;
        return err;
 }
 
@@ -5808,8 +5852,7 @@ static int tg3_reset_hw(struct tg3 *tp)
        tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
        udelay(100);
 
-       tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0);
-       tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
+       tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0);
        tp->last_tag = 0;
 
        if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
@@ -5910,7 +5953,7 @@ static int tg3_reset_hw(struct tg3 *tp)
        tw32(MAC_LED_CTRL, tp->led_ctrl);
 
        tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
-       if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
+       if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) {
                tw32_f(MAC_RX_MODE, RX_MODE_RESET);
                udelay(10);
        }
@@ -6192,13 +6235,15 @@ static int tg3_test_interrupt(struct tg3 *tp)
        if (err)
                return err;
 
+       tp->hw_status->status &= ~SD_STATUS_UPDATED;
        tg3_enable_ints(tp);
 
        tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE |
               HOSTCC_MODE_NOW);
 
        for (i = 0; i < 5; i++) {
-               int_mbox = tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
+               int_mbox = tr32_mailbox(MAILBOX_INTERRUPT_0 +
+                                       TG3_64BIT_REG_LOW);
                if (int_mbox != 0)
                        break;
                msleep(10);
@@ -6598,10 +6643,10 @@ static int tg3_open(struct net_device *dev)
 
        /* Mailboxes */
        printk("DEBUG: SNDHOST_PROD[%08x%08x] SNDNIC_PROD[%08x%08x]\n",
-              tr32(MAILBOX_SNDHOST_PROD_IDX_0 + 0x0),
-              tr32(MAILBOX_SNDHOST_PROD_IDX_0 + 0x4),
-              tr32(MAILBOX_SNDNIC_PROD_IDX_0 + 0x0),
-              tr32(MAILBOX_SNDNIC_PROD_IDX_0 + 0x4));
+              tr32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + 0x0),
+              tr32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + 0x4),
+              tr32_mailbox(MAILBOX_SNDNIC_PROD_IDX_0 + 0x0),
+              tr32_mailbox(MAILBOX_SNDNIC_PROD_IDX_0 + 0x4));
 
        /* NIC side send descriptors. */
        for (i = 0; i < 6; i++) {
@@ -7506,6 +7551,38 @@ static void tg3_get_strings (struct net_device *dev, u32 stringset, u8 *buf)
        }
 }
 
+static int tg3_phys_id(struct net_device *dev, u32 data)
+{
+       struct tg3 *tp = netdev_priv(dev);
+       int i;
+
+       if (!netif_running(tp->dev))
+               return -EAGAIN;
+
+       if (data == 0)
+               data = 2;
+
+       for (i = 0; i < (data * 2); i++) {
+               if ((i % 2) == 0)
+                       tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE |
+                                          LED_CTRL_1000MBPS_ON |
+                                          LED_CTRL_100MBPS_ON |
+                                          LED_CTRL_10MBPS_ON |
+                                          LED_CTRL_TRAFFIC_OVERRIDE |
+                                          LED_CTRL_TRAFFIC_BLINK |
+                                          LED_CTRL_TRAFFIC_LED);
+       
+               else
+                       tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE |
+                                          LED_CTRL_TRAFFIC_OVERRIDE);
+
+               if (msleep_interruptible(500))
+                       break;
+       }
+       tw32(MAC_LED_CTRL, tp->led_ctrl);
+       return 0;
+}
+
 static void tg3_get_ethtool_stats (struct net_device *dev,
                                   struct ethtool_stats *estats, u64 *tmp_stats)
 {
@@ -7565,7 +7642,7 @@ static int tg3_test_link(struct tg3 *tp)
        if (!netif_running(tp->dev))
                return -ENODEV;
 
-       if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+       if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
                max = TG3_SERDES_TIMEOUT_SEC;
        else
                max = TG3_COPPER_TIMEOUT_SEC;
@@ -7850,9 +7927,12 @@ static int tg3_test_memory(struct tg3 *tp)
        return err;
 }
 
-static int tg3_test_loopback(struct tg3 *tp)
+#define TG3_MAC_LOOPBACK       0
+#define TG3_PHY_LOOPBACK       1
+
+static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
 {
-       u32 mac_mode, send_idx, rx_start_idx, rx_idx, tx_idx, opaque_key;
+       u32 mac_mode, rx_start_idx, rx_idx, tx_idx, opaque_key;
        u32 desc_idx;
        struct sk_buff *skb, *rx_skb;
        u8 *tx_data;
@@ -7860,18 +7940,26 @@ static int tg3_test_loopback(struct tg3 *tp)
        int num_pkts, tx_len, rx_len, i, err;
        struct tg3_rx_buffer_desc *desc;
 
-       if (!netif_running(tp->dev))
-               return -ENODEV;
+       if (loopback_mode == TG3_MAC_LOOPBACK) {
+               mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
+                          MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY |
+                          MAC_MODE_PORT_MODE_GMII;
+               tw32(MAC_MODE, mac_mode);
+       } else if (loopback_mode == TG3_PHY_LOOPBACK) {
+               mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
+                          MAC_MODE_LINK_POLARITY | MAC_MODE_PORT_MODE_GMII;
+               if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)
+                       mac_mode &= ~MAC_MODE_LINK_POLARITY;
+               tw32(MAC_MODE, mac_mode);
+
+               tg3_writephy(tp, MII_BMCR, BMCR_LOOPBACK | BMCR_FULLDPLX |
+                                          BMCR_SPEED1000);
+       }
+       else
+               return -EINVAL;
 
        err = -EIO;
 
-       tg3_reset_hw(tp);
-
-       mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
-                  MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY |
-                  MAC_MODE_PORT_MODE_GMII;
-       tw32(MAC_MODE, mac_mode);
-
        tx_len = 1514;
        skb = dev_alloc_skb(tx_len);
        tx_data = skb_put(skb, tx_len);
@@ -7892,16 +7980,16 @@ static int tg3_test_loopback(struct tg3 *tp)
 
        rx_start_idx = tp->hw_status->idx[0].rx_producer;
 
-       send_idx = 0;
        num_pkts = 0;
 
-       tg3_set_txd(tp, send_idx, map, tx_len, 0, 1);
+       tg3_set_txd(tp, tp->tx_prod, map, tx_len, 0, 1);
 
-       send_idx++;
+       tp->tx_prod++;
        num_pkts++;
 
-       tw32_tx_mbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, send_idx);
-       tr32(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW);
+       tw32_tx_mbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW,
+                    tp->tx_prod);
+       tr32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW);
 
        udelay(10);
 
@@ -7913,7 +8001,7 @@ static int tg3_test_loopback(struct tg3 *tp)
 
                tx_idx = tp->hw_status->idx[0].tx_consumer;
                rx_idx = tp->hw_status->idx[0].rx_producer;
-               if ((tx_idx == send_idx) &&
+               if ((tx_idx == tp->tx_prod) &&
                    (rx_idx == (rx_start_idx + num_pkts)))
                        break;
        }
@@ -7921,7 +8009,7 @@ static int tg3_test_loopback(struct tg3 *tp)
        pci_unmap_single(tp->pdev, map, tx_len, PCI_DMA_TODEVICE);
        dev_kfree_skb(skb);
 
-       if (tx_idx != send_idx)
+       if (tx_idx != tp->tx_prod)
                goto out;
 
        if (rx_idx != rx_start_idx + num_pkts)
@@ -7957,6 +8045,30 @@ out:
        return err;
 }
 
+#define TG3_MAC_LOOPBACK_FAILED                1
+#define TG3_PHY_LOOPBACK_FAILED                2
+#define TG3_LOOPBACK_FAILED            (TG3_MAC_LOOPBACK_FAILED |      \
+                                        TG3_PHY_LOOPBACK_FAILED)
+
+static int tg3_test_loopback(struct tg3 *tp)
+{
+       int err = 0;
+
+       if (!netif_running(tp->dev))
+               return TG3_LOOPBACK_FAILED;
+
+       tg3_reset_hw(tp);
+
+       if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK))
+               err |= TG3_MAC_LOOPBACK_FAILED;
+       if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
+               if (tg3_run_loopback(tp, TG3_PHY_LOOPBACK))
+                       err |= TG3_PHY_LOOPBACK_FAILED;
+       }
+
+       return err;
+}
+
 static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
                          u64 *data)
 {
@@ -7997,10 +8109,8 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
                        etest->flags |= ETH_TEST_FL_FAILED;
                        data[3] = 1;
                }
-               if (tg3_test_loopback(tp) != 0) {
+               if ((data[4] = tg3_test_loopback(tp)) != 0)
                        etest->flags |= ETH_TEST_FL_FAILED;
-                       data[4] = 1;
-               }
 
                tg3_full_unlock(tp);
 
@@ -8188,6 +8298,7 @@ static struct ethtool_ops tg3_ethtool_ops = {
        .self_test_count        = tg3_get_test_count,
        .self_test              = tg3_self_test,
        .get_strings            = tg3_get_strings,
+       .phys_id                = tg3_phys_id,
        .get_stats_count        = tg3_get_stats_count,
        .get_ethtool_stats      = tg3_get_ethtool_stats,
        .get_coalesce           = tg3_get_coalesce,
@@ -8252,7 +8363,8 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp)
                tw32(NVRAM_CFG1, nvcfg1);
        }
 
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+       if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) ||
+           (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780)) {
                switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) {
                        case FLASH_VENDOR_ATMEL_FLASH_BUFFERED:
                                tp->nvram_jedecnum = JEDEC_ATMEL;
@@ -8666,8 +8778,9 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
                if (i == (len - 4))
                        nvram_cmd |= NVRAM_CMD_LAST;
 
-               if ((tp->nvram_jedecnum == JEDEC_ST) &&
-                       (nvram_cmd & NVRAM_CMD_FIRST)) {
+               if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) &&
+                   (tp->nvram_jedecnum == JEDEC_ST) &&
+                   (nvram_cmd & NVRAM_CMD_FIRST)) {
 
                        if ((ret = tg3_nvram_exec_cmd(tp,
                                NVRAM_CMD_WREN | NVRAM_CMD_GO |
@@ -9153,14 +9266,6 @@ static int __devinit tg3_is_sun_570X(struct tg3 *tp)
 static int __devinit tg3_get_invariants(struct tg3 *tp)
 {
        static struct pci_device_id write_reorder_chipsets[] = {
-               { PCI_DEVICE(PCI_VENDOR_ID_INTEL,
-                            PCI_DEVICE_ID_INTEL_82801AA_8) },
-               { PCI_DEVICE(PCI_VENDOR_ID_INTEL,
-                            PCI_DEVICE_ID_INTEL_82801AB_8) },
-               { PCI_DEVICE(PCI_VENDOR_ID_INTEL,
-                            PCI_DEVICE_ID_INTEL_82801BA_11) },
-               { PCI_DEVICE(PCI_VENDOR_ID_INTEL,
-                            PCI_DEVICE_ID_INTEL_82801BA_6) },
                { PCI_DEVICE(PCI_VENDOR_ID_AMD,
                             PCI_DEVICE_ID_AMD_FE_GATE_700C) },
                { },
@@ -9177,7 +9282,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                tp->tg3_flags2 |= TG3_FLG2_SUN_570X;
 #endif
 
-       /* If we have an AMD 762 or Intel ICH/ICH0/ICH2 chipset, write
+       /* If we have an AMD 762 chipset, write
         * reordering to the mailbox registers done by the host
         * controller can cause major troubles.  We read back from
         * every mailbox register write to force the writes to be
@@ -9215,6 +9320,69 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        if (tp->pci_chip_rev_id == CHIPREV_ID_5752_A0_HW)
                tp->pci_chip_rev_id = CHIPREV_ID_5752_A0;
 
+       /* If we have 5702/03 A1 or A2 on certain ICH chipsets,
+        * we need to disable memory and use config. cycles
+        * only to access all registers. The 5702/03 chips
+        * can mistakenly decode the special cycles from the
+        * ICH chipsets as memory write cycles, causing corruption
+        * of register and memory space. Only certain ICH bridges
+        * will drive special cycles with non-zero data during the
+        * address phase which can fall within the 5703's address
+        * range. This is not an ICH bug as the PCI spec allows
+        * non-zero address during special cycles. However, only
+        * these ICH bridges are known to drive non-zero addresses
+        * during special cycles.
+        *
+        * Since special cycles do not cross PCI bridges, we only
+        * enable this workaround if the 5703 is on the secondary
+        * bus of these ICH bridges.
+        */
+       if ((tp->pci_chip_rev_id == CHIPREV_ID_5703_A1) ||
+           (tp->pci_chip_rev_id == CHIPREV_ID_5703_A2)) {
+               static struct tg3_dev_id {
+                       u32     vendor;
+                       u32     device;
+                       u32     rev;
+               } ich_chipsets[] = {
+                       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_8,
+                         PCI_ANY_ID },
+                       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_8,
+                         PCI_ANY_ID },
+                       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_11,
+                         0xa },
+                       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_6,
+                         PCI_ANY_ID },
+                       { },
+               };
+               struct tg3_dev_id *pci_id = &ich_chipsets[0];
+               struct pci_dev *bridge = NULL;
+
+               while (pci_id->vendor != 0) {
+                       bridge = pci_get_device(pci_id->vendor, pci_id->device,
+                                               bridge);
+                       if (!bridge) {
+                               pci_id++;
+                               continue;
+                       }
+                       if (pci_id->rev != PCI_ANY_ID) {
+                               u8 rev;
+
+                               pci_read_config_byte(bridge, PCI_REVISION_ID,
+                                                    &rev);
+                               if (rev > pci_id->rev)
+                                       continue;
+                       }
+                       if (bridge->subordinate &&
+                           (bridge->subordinate->number ==
+                            tp->pdev->bus->number)) {
+
+                               tp->tg3_flags2 |= TG3_FLG2_ICH_WORKAROUND;
+                               pci_dev_put(bridge);
+                               break;
+                       }
+               }
+       }
+
        /* Find msi capability. */
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780)
                tp->msi_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_MSI);
@@ -9302,6 +9470,12 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                }
        }
 
+       /* 5700 BX chips need to have their TX producer index mailboxes
+        * written twice to workaround a bug.
+        */
+       if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX)
+               tp->tg3_flags |= TG3_FLAG_TXD_MBOX_HWBUG;
+
        /* Back to back register writes can cause problems on this chip,
         * the workaround is to read back all reg writes except those to
         * mailbox regs.  See tg3_write_indirect_reg32().
@@ -9325,6 +9499,43 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, pci_state_reg);
        }
 
+       /* Default fast path register access methods */
+       tp->read32 = tg3_read32;
+       tp->write32 = tg3_write32;
+       tp->read32_mbox = tg3_read32;
+       tp->write32_mbox = tg3_write32;
+       tp->write32_tx_mbox = tg3_write32;
+       tp->write32_rx_mbox = tg3_write32;
+
+       /* Various workaround register access methods */
+       if (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG)
+               tp->write32 = tg3_write_indirect_reg32;
+       else if (tp->tg3_flags & TG3_FLAG_5701_REG_WRITE_BUG)
+               tp->write32 = tg3_write_flush_reg32;
+
+       if ((tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) ||
+           (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)) {
+               tp->write32_tx_mbox = tg3_write32_tx_mbox;
+               if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+                       tp->write32_rx_mbox = tg3_write_flush_reg32;
+       }
+
+       if (tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND) {
+               tp->read32 = tg3_read_indirect_reg32;
+               tp->write32 = tg3_write_indirect_reg32;
+               tp->read32_mbox = tg3_read_indirect_mbox;
+               tp->write32_mbox = tg3_write_indirect_mbox;
+               tp->write32_tx_mbox = tg3_write_indirect_mbox;
+               tp->write32_rx_mbox = tg3_write_indirect_mbox;
+
+               iounmap(tp->regs);
+               tp->regs = 0;
+
+               pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd);
+               pci_cmd &= ~PCI_COMMAND_MEMORY;
+               pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
+       }
+
        /* Get eeprom hw config before calling tg3_set_power_state().
         * In particular, the TG3_FLAG_EEPROM_WRITE_PROT flag must be
         * determined before calling tg3_set_power_state() so that
@@ -9539,14 +9750,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        else
                tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES;
 
-       /* 5700 BX chips need to have their TX producer index mailboxes
-        * written twice to workaround a bug.
-        */
-       if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX)
-               tp->tg3_flags |= TG3_FLAG_TXD_MBOX_HWBUG;
-       else
-               tp->tg3_flags &= ~TG3_FLAG_TXD_MBOX_HWBUG;
-
        /* It seems all chips can get confused if TX buffers
         * straddle the 4GB address boundary in some cases.
         */
@@ -10469,7 +10672,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
        return 0;
 
 err_out_iounmap:
-       iounmap(tp->regs);
+       if (tp->regs) {
+               iounmap(tp->regs);
+               tp->regs = 0;
+       }
 
 err_out_free_dev:
        free_netdev(dev);
@@ -10491,7 +10697,10 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
                struct tg3 *tp = netdev_priv(dev);
 
                unregister_netdev(dev);
-               iounmap(tp->regs);
+               if (tp->regs) {
+                       iounmap(tp->regs);
+                       tp->regs = 0;
+               }
                free_netdev(dev);
                pci_release_regions(pdev);
                pci_disable_device(pdev);
index 5c4433c147fa46ed891af4b425ea41078a1ffeeb..c184b773e58543be34027d65810b7fdb2f4f1539 100644 (file)
@@ -2049,6 +2049,11 @@ struct tg3 {
        spinlock_t                      lock;
        spinlock_t                      indirect_lock;
 
+       u32                             (*read32) (struct tg3 *, u32);
+       void                            (*write32) (struct tg3 *, u32, u32);
+       u32                             (*read32_mbox) (struct tg3 *, u32);
+       void                            (*write32_mbox) (struct tg3 *, u32,
+                                                        u32);
        void __iomem                    *regs;
        struct net_device               *dev;
        struct pci_dev                  *pdev;
@@ -2060,6 +2065,8 @@ struct tg3 {
        u32                             msg_enable;
 
        /* begin "tx thread" cacheline section */
+       void                            (*write32_tx_mbox) (struct tg3 *, u32,
+                                                           u32);
        u32                             tx_prod;
        u32                             tx_cons;
        u32                             tx_pending;
@@ -2071,6 +2078,8 @@ struct tg3 {
        dma_addr_t                      tx_desc_mapping;
 
        /* begin "rx thread" cacheline section */
+       void                            (*write32_rx_mbox) (struct tg3 *, u32,
+                                                           u32);
        u32                             rx_rcb_ptr;
        u32                             rx_std_ptr;
        u32                             rx_jumbo_ptr;
@@ -2165,6 +2174,7 @@ struct tg3 {
 #define TG3_FLG2_ANY_SERDES            (TG3_FLG2_PHY_SERDES |  \
                                        TG3_FLG2_MII_SERDES)
 #define TG3_FLG2_PARALLEL_DETECT       0x01000000
+#define TG3_FLG2_ICH_WORKAROUND                0x02000000
 
        u32                             split_mode_max_reqs;
 #define SPLIT_MODE_5704_MAX_REQ                3
index 7e99e9f8045e176213949a534178ada137b342d9..e4cfc80b283b74a4ead414593340520f5be9554c 100644 (file)
@@ -84,7 +84,7 @@ config 3C359
 
 config TMS380TR
        tristate "Generic TMS380 Token Ring ISA/PCI adapter support"
-       depends on TR && (PCI || ISA && ISA_DMA_API)
+       depends on TR && (PCI || ISA && ISA_DMA_API || MCA)
        select FW_LOADER
        ---help---
          This driver provides generic support for token ring adapters
@@ -158,7 +158,7 @@ config ABYSS
 
 config MADGEMC
        tristate "Madge Smart 16/4 Ringnode MicroChannel"
-       depends on TR && TMS380TR && MCA_LEGACY
+       depends on TR && TMS380TR && MCA
        help
          This tms380 module supports the Madge Smart 16/4 MC16 and MC32
          MicroChannel adapters.
index 87103c400999dea48045e60fc8fb62311c39294c..9345e68c451eb4af5111f27ba40b5eb0bbd254d2 100644 (file)
@@ -139,7 +139,7 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_
         */
        dev->base_addr += 0x10;
                
-       ret = tmsdev_init(dev, PCI_MAX_ADDRESS, pdev);
+       ret = tmsdev_init(dev, &pdev->dev);
        if (ret) {
                printk("%s: unable to get memory for dev->priv.\n", 
                       dev->name);
index 659cbdbef7f380e4299f44a6cd157bca53cc6eb6..3a25d191ea4af322ae851edd38f5128afb40cd88 100644 (file)
@@ -20,7 +20,7 @@
 static const char version[] = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n";
 
 #include <linux/module.h>
-#include <linux/mca-legacy.h>
+#include <linux/mca.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/pci.h>
@@ -38,9 +38,7 @@ static const char version[] = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n";
 #define MADGEMC_IO_EXTENT 32
 #define MADGEMC_SIF_OFFSET 0x08
 
-struct madgemc_card {
-       struct net_device *dev;
-
+struct card_info {
        /*
         * These are read from the BIA ROM.
         */
@@ -57,16 +55,12 @@ struct madgemc_card {
        unsigned int arblevel:4;
        unsigned int ringspeed:2; /* 0 = 4mb, 1 = 16, 2 = Auto/none */
        unsigned int cabletype:1; /* 0 = RJ45, 1 = DB9 */
-
-       struct madgemc_card *next;
 };
-static struct madgemc_card *madgemc_card_list;
-
 
 static int madgemc_open(struct net_device *dev);
 static int madgemc_close(struct net_device *dev);
 static int madgemc_chipset_init(struct net_device *dev);
-static void madgemc_read_rom(struct madgemc_card *card);
+static void madgemc_read_rom(struct net_device *dev, struct card_info *card);
 static unsigned short madgemc_setnselout_pins(struct net_device *dev);
 static void madgemc_setcabletype(struct net_device *dev, int type);
 
@@ -151,261 +145,237 @@ static void madgemc_sifwritew(struct net_device *dev, unsigned short val, unsign
 
 
 
-static int __init madgemc_probe(void)
+static int __devinit madgemc_probe(struct device *device)
 {      
        static int versionprinted;
        struct net_device *dev;
        struct net_local *tp;
-       struct madgemc_card *card;
-       int i,slot = 0;
-       __u8 posreg[4];
-
-       if (!MCA_bus)
-               return -1;      
-       while (slot != MCA_NOTFOUND) {
-               /*
-                * Currently we only support the MC16/32 (MCA ID 002d)
-                */
-               slot = mca_find_unused_adapter(0x002d, slot);
-               if (slot == MCA_NOTFOUND)
-                       break;
-
-               /*
-                * If we get here, we have an adapter.
-                */
-               if (versionprinted++ == 0)
-                       printk("%s", version);
-
-               dev = alloc_trdev(sizeof(struct net_local));
-               if (dev == NULL) {
-                       printk("madgemc: unable to allocate dev space\n");
-                       if (madgemc_card_list)
-                               return 0;
-                       return -1;
-               }
+       struct card_info *card;
+       struct mca_device *mdev = to_mca_device(device);
+       int ret = 0, i = 0;
+
+       if (versionprinted++ == 0)
+               printk("%s", version);
+
+       if(mca_device_claimed(mdev))
+               return -EBUSY;
+       mca_device_set_claim(mdev, 1);
+
+       dev = alloc_trdev(sizeof(struct net_local));
+       if (!dev) {
+               printk("madgemc: unable to allocate dev space\n");
+               mca_device_set_claim(mdev, 0);
+               ret = -ENOMEM;
+               goto getout;
+       }
 
-               SET_MODULE_OWNER(dev);
-               dev->dma = 0;
+       SET_MODULE_OWNER(dev);
+       dev->dma = 0;
 
-               /*
-                * Fetch MCA config registers
-                */
-               for(i=0;i<4;i++)
-                       posreg[i] = mca_read_stored_pos(slot, i+2);
-               
-               card = kmalloc(sizeof(struct madgemc_card), GFP_KERNEL);
-               if (card==NULL) {
-                       printk("madgemc: unable to allocate card struct\n");
-                       free_netdev(dev);
-                       if (madgemc_card_list)
-                               return 0;
-                       return -1;
-               }
-               card->dev = dev;
-
-               /*
-                * Parse configuration information.  This all comes
-                * directly from the publicly available @002d.ADF.
-                * Get it from Madge or your local ADF library.
-                */
-
-               /*
-                * Base address 
-                */
-               dev->base_addr = 0x0a20 + 
-                       ((posreg[2] & MC16_POS2_ADDR2)?0x0400:0) +
-                       ((posreg[0] & MC16_POS0_ADDR1)?0x1000:0) +
-                       ((posreg[3] & MC16_POS3_ADDR3)?0x2000:0);
-
-               /*
-                * Interrupt line
-                */
-               switch(posreg[0] >> 6) { /* upper two bits */
+       card = kmalloc(sizeof(struct card_info), GFP_KERNEL);
+       if (card==NULL) {
+               printk("madgemc: unable to allocate card struct\n");
+               ret = -ENOMEM;
+               goto getout1;
+       }
+
+       /*
+        * Parse configuration information.  This all comes
+        * directly from the publicly available @002d.ADF.
+        * Get it from Madge or your local ADF library.
+        */
+
+       /*
+        * Base address 
+        */
+       dev->base_addr = 0x0a20 + 
+               ((mdev->pos[2] & MC16_POS2_ADDR2)?0x0400:0) +
+               ((mdev->pos[0] & MC16_POS0_ADDR1)?0x1000:0) +
+               ((mdev->pos[3] & MC16_POS3_ADDR3)?0x2000:0);
+
+       /*
+        * Interrupt line
+        */
+       switch(mdev->pos[0] >> 6) { /* upper two bits */
                case 0x1: dev->irq = 3; break;
                case 0x2: dev->irq = 9; break; /* IRQ 2 = IRQ 9 */
                case 0x3: dev->irq = 10; break;
                default: dev->irq = 0; break;
-               }
+       }
 
-               if (dev->irq == 0) {
-                       printk("%s: invalid IRQ\n", dev->name);
-                       goto getout1;
-               }
+       if (dev->irq == 0) {
+               printk("%s: invalid IRQ\n", dev->name);
+               ret = -EBUSY;
+               goto getout2;
+       }
 
-               if (!request_region(dev->base_addr, MADGEMC_IO_EXTENT, 
-                                  "madgemc")) {
-                       printk(KERN_INFO "madgemc: unable to setup Smart MC in slot %d because of I/O base conflict at 0x%04lx\n", slot, dev->base_addr);
-                       dev->base_addr += MADGEMC_SIF_OFFSET;
-                       goto getout1;
-               }
+       if (!request_region(dev->base_addr, MADGEMC_IO_EXTENT, 
+                          "madgemc")) {
+               printk(KERN_INFO "madgemc: unable to setup Smart MC in slot %d because of I/O base conflict at 0x%04lx\n", mdev->slot, dev->base_addr);
                dev->base_addr += MADGEMC_SIF_OFFSET;
+               ret = -EBUSY;
+               goto getout2;
+       }
+       dev->base_addr += MADGEMC_SIF_OFFSET;
+       
+       /*
+        * Arbitration Level
+        */
+       card->arblevel = ((mdev->pos[0] >> 1) & 0x7) + 8;
+
+       /*
+        * Burst mode and Fairness
+        */
+       card->burstmode = ((mdev->pos[2] >> 6) & 0x3);
+       card->fairness = ((mdev->pos[2] >> 4) & 0x1);
+
+       /*
+        * Ring Speed
+        */
+       if ((mdev->pos[1] >> 2)&0x1)
+               card->ringspeed = 2; /* not selected */
+       else if ((mdev->pos[2] >> 5) & 0x1)
+               card->ringspeed = 1; /* 16Mb */
+       else
+               card->ringspeed = 0; /* 4Mb */
+
+       /* 
+        * Cable type
+        */
+       if ((mdev->pos[1] >> 6)&0x1)
+               card->cabletype = 1; /* STP/DB9 */
+       else
+               card->cabletype = 0; /* UTP/RJ-45 */
+
+
+       /* 
+        * ROM Info. This requires us to actually twiddle
+        * bits on the card, so we must ensure above that 
+        * the base address is free of conflict (request_region above).
+        */
+       madgemc_read_rom(dev, card);
                
-               /*
-                * Arbitration Level
-                */
-               card->arblevel = ((posreg[0] >> 1) & 0x7) + 8;
-
-               /*
-                * Burst mode and Fairness
-                */
-               card->burstmode = ((posreg[2] >> 6) & 0x3);
-               card->fairness = ((posreg[2] >> 4) & 0x1);
-
-               /*
-                * Ring Speed
-                */
-               if ((posreg[1] >> 2)&0x1)
-                       card->ringspeed = 2; /* not selected */
-               else if ((posreg[2] >> 5) & 0x1)
-                       card->ringspeed = 1; /* 16Mb */
-               else
-                       card->ringspeed = 0; /* 4Mb */
-
-               /* 
-                * Cable type
-                */
-               if ((posreg[1] >> 6)&0x1)
-                       card->cabletype = 1; /* STP/DB9 */
-               else
-                       card->cabletype = 0; /* UTP/RJ-45 */
-
-
-               /* 
-                * ROM Info. This requires us to actually twiddle
-                * bits on the card, so we must ensure above that 
-                * the base address is free of conflict (request_region above).
-                */
-               madgemc_read_rom(card);
-               
-               if (card->manid != 0x4d) { /* something went wrong */
-                       printk(KERN_INFO "%s: Madge MC ROM read failed (unknown manufacturer ID %02x)\n", dev->name, card->manid);
-                       goto getout;
-               }
+       if (card->manid != 0x4d) { /* something went wrong */
+               printk(KERN_INFO "%s: Madge MC ROM read failed (unknown manufacturer ID %02x)\n", dev->name, card->manid);
+               goto getout3;
+       }
                
-               if ((card->cardtype != 0x08) && (card->cardtype != 0x0d)) {
-                       printk(KERN_INFO "%s: Madge MC ROM read failed (unknown card ID %02x)\n", dev->name, card->cardtype);
-                       goto getout;
-               }
+       if ((card->cardtype != 0x08) && (card->cardtype != 0x0d)) {
+               printk(KERN_INFO "%s: Madge MC ROM read failed (unknown card ID %02x)\n", dev->name, card->cardtype);
+               ret = -EIO;
+               goto getout3;
+       }
               
-               /* All cards except Rev 0 and 1 MC16's have 256kb of RAM */
-               if ((card->cardtype == 0x08) && (card->cardrev <= 0x01))
-                       card->ramsize = 128;
-               else
-                       card->ramsize = 256;
-
-               printk("%s: %s Rev %d at 0x%04lx IRQ %d\n", 
-                      dev->name, 
-                      (card->cardtype == 0x08)?MADGEMC16_CARDNAME:
-                      MADGEMC32_CARDNAME, card->cardrev, 
-                      dev->base_addr, dev->irq);
-
-               if (card->cardtype == 0x0d)
-                       printk("%s:     Warning: MC32 support is experimental and highly untested\n", dev->name);
-               
-               if (card->ringspeed==2) { /* Unknown */
-                       printk("%s:     Warning: Ring speed not set in POS -- Please run the reference disk and set it!\n", dev->name);
-                       card->ringspeed = 1; /* default to 16mb */
-               }
+       /* All cards except Rev 0 and 1 MC16's have 256kb of RAM */
+       if ((card->cardtype == 0x08) && (card->cardrev <= 0x01))
+               card->ramsize = 128;
+       else
+               card->ramsize = 256;
+
+       printk("%s: %s Rev %d at 0x%04lx IRQ %d\n", 
+              dev->name, 
+              (card->cardtype == 0x08)?MADGEMC16_CARDNAME:
+              MADGEMC32_CARDNAME, card->cardrev, 
+              dev->base_addr, dev->irq);
+
+       if (card->cardtype == 0x0d)
+               printk("%s:     Warning: MC32 support is experimental and highly untested\n", dev->name);
+       
+       if (card->ringspeed==2) { /* Unknown */
+               printk("%s:     Warning: Ring speed not set in POS -- Please run the reference disk and set it!\n", dev->name);
+               card->ringspeed = 1; /* default to 16mb */
+       }
                
-               printk("%s:     RAM Size: %dKB\n", dev->name, card->ramsize);
+       printk("%s:     RAM Size: %dKB\n", dev->name, card->ramsize);
 
-               printk("%s:     Ring Speed: %dMb/sec on %s\n", dev->name, 
-                      (card->ringspeed)?16:4, 
-                      card->cabletype?"STP/DB9":"UTP/RJ-45");
-               printk("%s:     Arbitration Level: %d\n", dev->name, 
-                      card->arblevel);
+       printk("%s:     Ring Speed: %dMb/sec on %s\n", dev->name, 
+              (card->ringspeed)?16:4, 
+              card->cabletype?"STP/DB9":"UTP/RJ-45");
+       printk("%s:     Arbitration Level: %d\n", dev->name, 
+              card->arblevel);
 
-               printk("%s:     Burst Mode: ", dev->name);
-               switch(card->burstmode) {
+       printk("%s:     Burst Mode: ", dev->name);
+       switch(card->burstmode) {
                case 0: printk("Cycle steal"); break;
                case 1: printk("Limited burst"); break;
                case 2: printk("Delayed release"); break;
                case 3: printk("Immediate release"); break;
-               }
-               printk(" (%s)\n", (card->fairness)?"Unfair":"Fair");
-
-
-               /* 
-                * Enable SIF before we assign the interrupt handler,
-                * just in case we get spurious interrupts that need
-                * handling.
-                */ 
-               outb(0, dev->base_addr + MC_CONTROL_REG0); /* sanity */
-               madgemc_setsifsel(dev, 1);
-               if (request_irq(dev->irq, madgemc_interrupt, SA_SHIRQ,
-                              "madgemc", dev)) 
-                       goto getout;
-               
-               madgemc_chipset_init(dev); /* enables interrupts! */
-               madgemc_setcabletype(dev, card->cabletype);
+       }
+       printk(" (%s)\n", (card->fairness)?"Unfair":"Fair");
 
-               /* Setup MCA structures */
-               mca_set_adapter_name(slot, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME);
-               mca_set_adapter_procfn(slot, madgemc_mcaproc, dev);
-               mca_mark_as_used(slot);
 
-               printk("%s:     Ring Station Address: ", dev->name);
-               printk("%2.2x", dev->dev_addr[0]);
-               for (i = 1; i < 6; i++)
-                       printk(":%2.2x", dev->dev_addr[i]);
-               printk("\n");
-
-               /* XXX is ISA_MAX_ADDRESS correct here? */
-               if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) {
-                       printk("%s: unable to get memory for dev->priv.\n", 
-                              dev->name);
-                       release_region(dev->base_addr-MADGEMC_SIF_OFFSET, 
-                              MADGEMC_IO_EXTENT); 
-                       
-                       kfree(card);
-                       tmsdev_term(dev);
-                       free_netdev(dev);
-                       if (madgemc_card_list)
-                               return 0;
-                       return -1;
-               }
-               tp = netdev_priv(dev);
-
-               /* 
-                * The MC16 is physically a 32bit card.  However, Madge
-                * insists on calling it 16bit, so I'll assume here that
-                * they know what they're talking about.  Cut off DMA
-                * at 16mb.
-                */
-               tp->setnselout = madgemc_setnselout_pins;
-               tp->sifwriteb = madgemc_sifwriteb;
-               tp->sifreadb = madgemc_sifreadb;
-               tp->sifwritew = madgemc_sifwritew;
-               tp->sifreadw = madgemc_sifreadw;
-               tp->DataRate = (card->ringspeed)?SPEED_16:SPEED_4;
-
-               memcpy(tp->ProductID, "Madge MCA 16/4    ", PROD_ID_SIZE + 1);
-
-               dev->open = madgemc_open;
-               dev->stop = madgemc_close;
-
-               if (register_netdev(dev) == 0) {
-                       /* Enlist in the card list */
-                       card->next = madgemc_card_list;
-                       madgemc_card_list = card;
-                       slot++;
-                       continue; /* successful, try to find another */
-               }
-               
-               free_irq(dev->irq, dev);
-       getout:
-               release_region(dev->base_addr-MADGEMC_SIF_OFFSET, 
-                              MADGEMC_IO_EXTENT); 
-       getout1:
-               kfree(card);
-               free_netdev(dev);
-               slot++;
+       /* 
+        * Enable SIF before we assign the interrupt handler,
+        * just in case we get spurious interrupts that need
+        * handling.
+        */ 
+       outb(0, dev->base_addr + MC_CONTROL_REG0); /* sanity */
+       madgemc_setsifsel(dev, 1);
+       if (request_irq(dev->irq, madgemc_interrupt, SA_SHIRQ,
+                      "madgemc", dev)) {
+               ret = -EBUSY;
+               goto getout3;
        }
 
-       if (madgemc_card_list)
+       madgemc_chipset_init(dev); /* enables interrupts! */
+       madgemc_setcabletype(dev, card->cabletype);
+
+       /* Setup MCA structures */
+       mca_device_set_name(mdev, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME);
+       mca_set_adapter_procfn(mdev->slot, madgemc_mcaproc, dev);
+
+       printk("%s:     Ring Station Address: ", dev->name);
+       printk("%2.2x", dev->dev_addr[0]);
+       for (i = 1; i < 6; i++)
+               printk(":%2.2x", dev->dev_addr[i]);
+       printk("\n");
+
+       if (tmsdev_init(dev, device)) {
+               printk("%s: unable to get memory for dev->priv.\n", 
+                      dev->name);
+               ret = -ENOMEM;
+               goto getout4;
+       }
+       tp = netdev_priv(dev);
+
+       /* 
+        * The MC16 is physically a 32bit card.  However, Madge
+        * insists on calling it 16bit, so I'll assume here that
+        * they know what they're talking about.  Cut off DMA
+        * at 16mb.
+        */
+       tp->setnselout = madgemc_setnselout_pins;
+       tp->sifwriteb = madgemc_sifwriteb;
+       tp->sifreadb = madgemc_sifreadb;
+       tp->sifwritew = madgemc_sifwritew;
+       tp->sifreadw = madgemc_sifreadw;
+       tp->DataRate = (card->ringspeed)?SPEED_16:SPEED_4;
+
+       memcpy(tp->ProductID, "Madge MCA 16/4    ", PROD_ID_SIZE + 1);
+
+       dev->open = madgemc_open;
+       dev->stop = madgemc_close;
+
+       tp->tmspriv = card;
+       dev_set_drvdata(device, dev);
+
+       if (register_netdev(dev) == 0)
                return 0;
-       return -1;
+
+       dev_set_drvdata(device, NULL);
+       ret = -ENOMEM;
+getout4:
+       free_irq(dev->irq, dev);
+getout3:
+       release_region(dev->base_addr-MADGEMC_SIF_OFFSET, 
+                      MADGEMC_IO_EXTENT); 
+getout2:
+       kfree(card);
+getout1:
+       free_netdev(dev);
+getout:
+       mca_device_set_claim(mdev, 0);
+       return ret;
 }
 
 /*
@@ -664,12 +634,12 @@ static void madgemc_chipset_close(struct net_device *dev)
  * is complete.
  *
  */
-static void madgemc_read_rom(struct madgemc_card *card)
+static void madgemc_read_rom(struct net_device *dev, struct card_info *card)
 {
        unsigned long ioaddr;
        unsigned char reg0, reg1, tmpreg0, i;
 
-       ioaddr = card->dev->base_addr;
+       ioaddr = dev->base_addr;
 
        reg0 = inb(ioaddr + MC_CONTROL_REG0);
        reg1 = inb(ioaddr + MC_CONTROL_REG1);
@@ -686,9 +656,9 @@ static void madgemc_read_rom(struct madgemc_card *card)
        outb(tmpreg0 | MC_CONTROL_REG0_PAGE, ioaddr + MC_CONTROL_REG0);
 
        /* Read BIA */
-       card->dev->addr_len = 6;
+       dev->addr_len = 6;
        for (i = 0; i < 6; i++)
-               card->dev->dev_addr[i] = inb(ioaddr + MC_ROM_BIA_START + i);
+               dev->dev_addr[i] = inb(ioaddr + MC_ROM_BIA_START + i);
        
        /* Restore original register values */
        outb(reg0, ioaddr + MC_CONTROL_REG0);
@@ -721,14 +691,10 @@ static int madgemc_close(struct net_device *dev)
 static int madgemc_mcaproc(char *buf, int slot, void *d) 
 {      
        struct net_device *dev = (struct net_device *)d;
-       struct madgemc_card *curcard = madgemc_card_list;
+       struct net_local *tp = dev->priv;
+       struct card_info *curcard = tp->tmspriv;
        int len = 0;
        
-       while (curcard) { /* search for card struct */
-               if (curcard->dev == dev)
-                       break;
-               curcard = curcard->next;
-       }
        len += sprintf(buf+len, "-------\n");
        if (curcard) {
                struct net_local *tp = netdev_priv(dev);
@@ -763,25 +729,56 @@ static int madgemc_mcaproc(char *buf, int slot, void *d)
        return len;
 }
 
-static void __exit madgemc_exit(void)
+static int __devexit madgemc_remove(struct device *device)
 {
-       struct net_device *dev;
-       struct madgemc_card *this_card;
-       
-       while (madgemc_card_list) {
-               dev = madgemc_card_list->dev;
-               unregister_netdev(dev);
-               release_region(dev->base_addr-MADGEMC_SIF_OFFSET, MADGEMC_IO_EXTENT);
-               free_irq(dev->irq, dev);
-               tmsdev_term(dev);
-               free_netdev(dev);
-               this_card = madgemc_card_list;
-               madgemc_card_list = this_card->next;
-               kfree(this_card);
-       }
+       struct net_device *dev = dev_get_drvdata(device);
+       struct net_local *tp;
+        struct card_info *card;
+
+       if (!dev)
+               BUG();
+
+       tp = dev->priv;
+       card = tp->tmspriv;
+       kfree(card);
+       tp->tmspriv = NULL;
+
+       unregister_netdev(dev);
+       release_region(dev->base_addr-MADGEMC_SIF_OFFSET, MADGEMC_IO_EXTENT);
+       free_irq(dev->irq, dev);
+       tmsdev_term(dev);
+       free_netdev(dev);
+       dev_set_drvdata(device, NULL);
+
+       return 0;
+}
+
+static short madgemc_adapter_ids[] __initdata = {
+       0x002d,
+       0x0000
+};
+
+static struct mca_driver madgemc_driver = {
+       .id_table = madgemc_adapter_ids,
+       .driver = {
+               .name = "madgemc",
+               .bus = &mca_bus_type,
+               .probe = madgemc_probe,
+               .remove = __devexit_p(madgemc_remove),
+       },
+};
+
+static int __init madgemc_init (void)
+{
+       return mca_register_driver (&madgemc_driver);
+}
+
+static void __exit madgemc_exit (void)
+{
+       mca_unregister_driver (&madgemc_driver);
 }
 
-module_init(madgemc_probe);
+module_init(madgemc_init);
 module_exit(madgemc_exit);
 
 MODULE_LICENSE("GPL");
index 40ad0fde28afc071fdf48562350d6c04a9fd1e35..eb1423ede75cae8032a0729fdb115e54fa9e7c86 100644 (file)
@@ -62,8 +62,7 @@ static int dmalist[] __initdata = {
 };
 
 static char cardname[] = "Proteon 1392\0";
-
-struct net_device *proteon_probe(int unit);
+static u64 dma_mask = ISA_MAX_ADDRESS;
 static int proteon_open(struct net_device *dev);
 static void proteon_read_eeprom(struct net_device *dev);
 static unsigned short proteon_setnselout_pins(struct net_device *dev);
@@ -116,7 +115,7 @@ nodev:
        return -ENODEV;
 }
 
-static int __init setup_card(struct net_device *dev)
+static int __init setup_card(struct net_device *dev, struct device *pdev)
 {
        struct net_local *tp;
         static int versionprinted;
@@ -137,7 +136,7 @@ static int __init setup_card(struct net_device *dev)
                }
        }
        if (err)
-               goto out4;
+               goto out5;
 
        /* At this point we have found a valid card. */
 
@@ -145,14 +144,15 @@ static int __init setup_card(struct net_device *dev)
                printk(KERN_DEBUG "%s", version);
 
        err = -EIO;
-       if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL))
+       pdev->dma_mask = &dma_mask;
+       if (tmsdev_init(dev, pdev))
                goto out4;
 
        dev->base_addr &= ~3; 
                
        proteon_read_eeprom(dev);
 
-       printk(KERN_DEBUG "%s:    Ring Station Address: ", dev->name);
+       printk(KERN_DEBUG "proteon.c:    Ring Station Address: ");
        printk("%2.2x", dev->dev_addr[0]);
        for (j = 1; j < 6; j++)
                printk(":%2.2x", dev->dev_addr[j]);
@@ -185,7 +185,7 @@ static int __init setup_card(struct net_device *dev)
                
                 if(irqlist[j] == 0)
                 {
-                        printk(KERN_INFO "%s: AutoSelect no IRQ available\n", dev->name);
+                        printk(KERN_INFO "proteon.c: AutoSelect no IRQ available\n");
                        goto out3;
                }
        }
@@ -196,15 +196,15 @@ static int __init setup_card(struct net_device *dev)
                                break;
                if (irqlist[j] == 0)
                {
-                       printk(KERN_INFO "%s: Illegal IRQ %d specified\n",
-                               dev->name, dev->irq);
+                       printk(KERN_INFO "proteon.c: Illegal IRQ %d specified\n",
+                               dev->irq);
                        goto out3;
                }
                if (request_irq(dev->irq, tms380tr_interrupt, 0, 
                        cardname, dev))
                {
-                        printk(KERN_INFO "%s: Selected IRQ %d not available\n", 
-                               dev->name, dev->irq);
+                        printk(KERN_INFO "proteon.c: Selected IRQ %d not available\n",
+                               dev->irq);
                        goto out3;
                }
        }
@@ -220,7 +220,7 @@ static int __init setup_card(struct net_device *dev)
 
                if(dmalist[j] == 0)
                {
-                       printk(KERN_INFO "%s: AutoSelect no DMA available\n", dev->name);
+                       printk(KERN_INFO "proteon.c: AutoSelect no DMA available\n");
                        goto out2;
                }
        }
@@ -231,25 +231,25 @@ static int __init setup_card(struct net_device *dev)
                                break;
                if (dmalist[j] == 0)
                {
-                        printk(KERN_INFO "%s: Illegal DMA %d specified\n", 
-                               dev->name, dev->dma);
+                        printk(KERN_INFO "proteon.c: Illegal DMA %d specified\n",
+                               dev->dma);
                        goto out2;
                }
                if (request_dma(dev->dma, cardname))
                {
-                        printk(KERN_INFO "%s: Selected DMA %d not available\n", 
-                               dev->name, dev->dma);
+                        printk(KERN_INFO "proteon.c: Selected DMA %d not available\n",
+                               dev->dma);
                        goto out2;
                }
        }
 
-       printk(KERN_DEBUG "%s:    IO: %#4lx  IRQ: %d  DMA: %d\n",
-              dev->name, dev->base_addr, dev->irq, dev->dma);
-               
        err = register_netdev(dev);
        if (err)
                goto out;
 
+       printk(KERN_DEBUG "%s:    IO: %#4lx  IRQ: %d  DMA: %d\n",
+              dev->name, dev->base_addr, dev->irq, dev->dma);
+
        return 0;
 out:
        free_dma(dev->dma);
@@ -258,34 +258,11 @@ out2:
 out3:
        tmsdev_term(dev);
 out4:
-       release_region(dev->base_addr, PROTEON_IO_EXTENT); 
+       release_region(dev->base_addr, PROTEON_IO_EXTENT);
+out5:
        return err;
 }
 
-struct net_device * __init proteon_probe(int unit)
-{
-       struct net_device *dev = alloc_trdev(sizeof(struct net_local));
-       int err = 0;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       if (unit >= 0) {
-               sprintf(dev->name, "tr%d", unit);
-               netdev_boot_setup_check(dev);
-       }
-
-       err = setup_card(dev);
-       if (err)
-               goto out;
-
-       return dev;
-
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
 /*
  * Reads MAC address from adapter RAM, which should've read it from
  * the onboard ROM.  
@@ -352,8 +329,6 @@ static int proteon_open(struct net_device *dev)
        return tms380tr_open(dev);
 }
 
-#ifdef MODULE
-
 #define ISATR_MAX_ADAPTERS 3
 
 static int io[ISATR_MAX_ADAPTERS];
@@ -366,13 +341,23 @@ module_param_array(io, int, NULL, 0);
 module_param_array(irq, int, NULL, 0);
 module_param_array(dma, int, NULL, 0);
 
-static struct net_device *proteon_dev[ISATR_MAX_ADAPTERS];
+static struct platform_device *proteon_dev[ISATR_MAX_ADAPTERS];
+
+static struct device_driver proteon_driver = {
+       .name           = "proteon",
+       .bus            = &platform_bus_type,
+};
 
-int init_module(void)
+static int __init proteon_init(void)
 {
        struct net_device *dev;
+       struct platform_device *pdev;
        int i, num = 0, err = 0;
 
+       err = driver_register(&proteon_driver);
+       if (err)
+               return err;
+
        for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) {
                dev = alloc_trdev(sizeof(struct net_local));
                if (!dev)
@@ -381,11 +366,15 @@ int init_module(void)
                dev->base_addr = io[i];
                dev->irq = irq[i];
                dev->dma = dma[i];
-               err = setup_card(dev);
+               pdev = platform_device_register_simple("proteon",
+                       i, NULL, 0);
+               err = setup_card(dev, &pdev->dev);
                if (!err) {
-                       proteon_dev[i] = dev;
+                       proteon_dev[i] = pdev;
+                       dev_set_drvdata(&pdev->dev, dev);
                        ++num;
                } else {
+                       platform_device_unregister(pdev);
                        free_netdev(dev);
                }
        }
@@ -399,23 +388,28 @@ int init_module(void)
        return (0);
 }
 
-void cleanup_module(void)
+static void __exit proteon_cleanup(void)
 {
+       struct net_device *dev;
        int i;
 
        for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) {
-               struct net_device *dev = proteon_dev[i];
+               struct platform_device *pdev = proteon_dev[i];
                
-               if (!dev) 
+               if (!pdev)
                        continue;
-               
+               dev = dev_get_drvdata(&pdev->dev);
                unregister_netdev(dev);
                release_region(dev->base_addr, PROTEON_IO_EXTENT);
                free_irq(dev->irq, dev);
                free_dma(dev->dma);
                tmsdev_term(dev);
                free_netdev(dev);
+               dev_set_drvdata(&pdev->dev, NULL);
+               platform_device_unregister(pdev);
        }
+       driver_unregister(&proteon_driver);
 }
-#endif /* MODULE */
 
+module_init(proteon_init);
+module_exit(proteon_cleanup);
index f26796e2d0e5f4cb0ee2a4a74872779d7d625fca..3c7c66204f7474d0005021afc7fe740698fc2d3a 100644 (file)
@@ -68,8 +68,7 @@ static int dmalist[] __initdata = {
 };
 
 static char isa_cardname[] = "SK NET TR 4/16 ISA\0";
-
-struct net_device *sk_isa_probe(int unit);
+static u64 dma_mask = ISA_MAX_ADDRESS;
 static int sk_isa_open(struct net_device *dev);
 static void sk_isa_read_eeprom(struct net_device *dev);
 static unsigned short sk_isa_setnselout_pins(struct net_device *dev);
@@ -133,7 +132,7 @@ static int __init sk_isa_probe1(struct net_device *dev, int ioaddr)
        return 0;
 }
 
-static int __init setup_card(struct net_device *dev)
+static int __init setup_card(struct net_device *dev, struct device *pdev)
 {
        struct net_local *tp;
         static int versionprinted;
@@ -154,7 +153,7 @@ static int __init setup_card(struct net_device *dev)
                }
        }
        if (err)
-               goto out4;
+               goto out5;
 
        /* At this point we have found a valid card. */
 
@@ -162,14 +161,15 @@ static int __init setup_card(struct net_device *dev)
                printk(KERN_DEBUG "%s", version);
 
        err = -EIO;
-       if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL))
+       pdev->dma_mask = &dma_mask;
+       if (tmsdev_init(dev, pdev))
                goto out4;
 
        dev->base_addr &= ~3; 
                
        sk_isa_read_eeprom(dev);
 
-       printk(KERN_DEBUG "%s:    Ring Station Address: ", dev->name);
+       printk(KERN_DEBUG "skisa.c:    Ring Station Address: ");
        printk("%2.2x", dev->dev_addr[0]);
        for (j = 1; j < 6; j++)
                printk(":%2.2x", dev->dev_addr[j]);
@@ -202,7 +202,7 @@ static int __init setup_card(struct net_device *dev)
                
                 if(irqlist[j] == 0)
                 {
-                        printk(KERN_INFO "%s: AutoSelect no IRQ available\n", dev->name);
+                        printk(KERN_INFO "skisa.c: AutoSelect no IRQ available\n");
                        goto out3;
                }
        }
@@ -213,15 +213,15 @@ static int __init setup_card(struct net_device *dev)
                                break;
                if (irqlist[j] == 0)
                {
-                       printk(KERN_INFO "%s: Illegal IRQ %d specified\n",
-                               dev->name, dev->irq);
+                       printk(KERN_INFO "skisa.c: Illegal IRQ %d specified\n",
+                               dev->irq);
                        goto out3;
                }
                if (request_irq(dev->irq, tms380tr_interrupt, 0, 
                        isa_cardname, dev))
                {
-                        printk(KERN_INFO "%s: Selected IRQ %d not available\n", 
-                               dev->name, dev->irq);
+                        printk(KERN_INFO "skisa.c: Selected IRQ %d not available\n",
+                               dev->irq);
                        goto out3;
                }
        }
@@ -237,7 +237,7 @@ static int __init setup_card(struct net_device *dev)
 
                if(dmalist[j] == 0)
                {
-                       printk(KERN_INFO "%s: AutoSelect no DMA available\n", dev->name);
+                       printk(KERN_INFO "skisa.c: AutoSelect no DMA available\n");
                        goto out2;
                }
        }
@@ -248,25 +248,25 @@ static int __init setup_card(struct net_device *dev)
                                break;
                if (dmalist[j] == 0)
                {
-                        printk(KERN_INFO "%s: Illegal DMA %d specified\n", 
-                               dev->name, dev->dma);
+                        printk(KERN_INFO "skisa.c: Illegal DMA %d specified\n",
+                               dev->dma);
                        goto out2;
                }
                if (request_dma(dev->dma, isa_cardname))
                {
-                        printk(KERN_INFO "%s: Selected DMA %d not available\n", 
-                               dev->name, dev->dma);
+                        printk(KERN_INFO "skisa.c: Selected DMA %d not available\n",
+                               dev->dma);
                        goto out2;
                }
        }
 
-       printk(KERN_DEBUG "%s:    IO: %#4lx  IRQ: %d  DMA: %d\n",
-              dev->name, dev->base_addr, dev->irq, dev->dma);
-               
        err = register_netdev(dev);
        if (err)
                goto out;
 
+       printk(KERN_DEBUG "%s:    IO: %#4lx  IRQ: %d  DMA: %d\n",
+              dev->name, dev->base_addr, dev->irq, dev->dma);
+
        return 0;
 out:
        free_dma(dev->dma);
@@ -275,33 +275,11 @@ out2:
 out3:
        tmsdev_term(dev);
 out4:
-       release_region(dev->base_addr, SK_ISA_IO_EXTENT); 
+       release_region(dev->base_addr, SK_ISA_IO_EXTENT);
+out5:
        return err;
 }
 
-struct net_device * __init sk_isa_probe(int unit)
-{
-       struct net_device *dev = alloc_trdev(sizeof(struct net_local));
-       int err = 0;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       if (unit >= 0) {
-               sprintf(dev->name, "tr%d", unit);
-               netdev_boot_setup_check(dev);
-       }
-
-       err = setup_card(dev);
-       if (err)
-               goto out;
-
-       return dev;
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
 /*
  * Reads MAC address from adapter RAM, which should've read it from
  * the onboard ROM.  
@@ -361,8 +339,6 @@ static int sk_isa_open(struct net_device *dev)
        return tms380tr_open(dev);
 }
 
-#ifdef MODULE
-
 #define ISATR_MAX_ADAPTERS 3
 
 static int io[ISATR_MAX_ADAPTERS];
@@ -375,13 +351,23 @@ module_param_array(io, int, NULL, 0);
 module_param_array(irq, int, NULL, 0);
 module_param_array(dma, int, NULL, 0);
 
-static struct net_device *sk_isa_dev[ISATR_MAX_ADAPTERS];
+static struct platform_device *sk_isa_dev[ISATR_MAX_ADAPTERS];
 
-int init_module(void)
+static struct device_driver sk_isa_driver = {
+       .name           = "skisa",
+       .bus            = &platform_bus_type,
+};
+
+static int __init sk_isa_init(void)
 {
        struct net_device *dev;
+       struct platform_device *pdev;
        int i, num = 0, err = 0;
 
+       err = driver_register(&sk_isa_driver);
+       if (err)
+               return err;
+
        for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) {
                dev = alloc_trdev(sizeof(struct net_local));
                if (!dev)
@@ -390,12 +376,15 @@ int init_module(void)
                dev->base_addr = io[i];
                dev->irq = irq[i];
                dev->dma = dma[i];
-               err = setup_card(dev);
-
+               pdev = platform_device_register_simple("skisa",
+                       i, NULL, 0);
+               err = setup_card(dev, &pdev->dev);
                if (!err) {
-                       sk_isa_dev[i] = dev;
+                       sk_isa_dev[i] = pdev;
+                       dev_set_drvdata(&sk_isa_dev[i]->dev, dev);
                        ++num;
                } else {
+                       platform_device_unregister(pdev);
                        free_netdev(dev);
                }
        }
@@ -409,23 +398,28 @@ int init_module(void)
        return (0);
 }
 
-void cleanup_module(void)
+static void __exit sk_isa_cleanup(void)
 {
+       struct net_device *dev;
        int i;
 
        for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) {
-               struct net_device *dev = sk_isa_dev[i];
+               struct platform_device *pdev = sk_isa_dev[i];
 
-               if (!dev) 
+               if (!pdev)
                        continue;
-               
+               dev = dev_get_drvdata(&pdev->dev);
                unregister_netdev(dev);
                release_region(dev->base_addr, SK_ISA_IO_EXTENT);
                free_irq(dev->irq, dev);
                free_dma(dev->dma);
                tmsdev_term(dev);
                free_netdev(dev);
+               dev_set_drvdata(&pdev->dev, NULL);
+               platform_device_unregister(pdev);
        }
+       driver_unregister(&sk_isa_driver);
 }
-#endif /* MODULE */
 
+module_init(sk_isa_init);
+module_exit(sk_isa_cleanup);
index 5e0b0ce98ed7fbe44383c604171bfeaa30b1d6d9..2e39bf1f74620f88cf5d03fce1a71ac0f1e107fb 100644 (file)
@@ -62,6 +62,7 @@
  *                             normal operation.
  *     30-Dec-02       JF      Removed incorrect __init from 
  *                             tms380tr_init_card.
+ *     22-Jul-05       JF      Converted to dma-mapping.
  *                             
  *  To do:
  *    1. Multi/Broadcast packet handling (this may have fixed itself)
@@ -89,7 +90,7 @@ static const char version[] = "tms380tr.c: v1.10 30/12/2002 by Christoph Goos, A
 #include <linux/time.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -114,8 +115,6 @@ static const char version[] = "tms380tr.c: v1.10 30/12/2002 by Christoph Goos, A
 #endif
 static unsigned int tms380tr_debug = TMS380TR_DEBUG;
 
-static struct device tms_device;
-
 /* Index to functions, as function prototypes.
  * Alphabetical by function name.
  */
@@ -434,7 +433,7 @@ static void tms380tr_init_net_local(struct net_device *dev)
                        skb_put(tp->Rpl[i].Skb, tp->MaxPacketSize);
 
                        /* data unreachable for DMA ? then use local buffer */
-                       dmabuf = pci_map_single(tp->pdev, tp->Rpl[i].Skb->data, tp->MaxPacketSize, PCI_DMA_FROMDEVICE);
+                       dmabuf = dma_map_single(tp->pdev, tp->Rpl[i].Skb->data, tp->MaxPacketSize, DMA_FROM_DEVICE);
                        if(tp->dmalimit && (dmabuf + tp->MaxPacketSize > tp->dmalimit))
                        {
                                tp->Rpl[i].SkbStat = SKB_DATA_COPY;
@@ -638,10 +637,10 @@ static int tms380tr_hardware_send_packet(struct sk_buff *skb, struct net_device
        /* Is buffer reachable for Busmaster-DMA? */
 
        length  = skb->len;
-       dmabuf = pci_map_single(tp->pdev, skb->data, length, PCI_DMA_TODEVICE);
+       dmabuf = dma_map_single(tp->pdev, skb->data, length, DMA_TO_DEVICE);
        if(tp->dmalimit && (dmabuf + length > tp->dmalimit)) {
                /* Copy frame to local buffer */
-               pci_unmap_single(tp->pdev, dmabuf, length, PCI_DMA_TODEVICE);
+               dma_unmap_single(tp->pdev, dmabuf, length, DMA_TO_DEVICE);
                dmabuf  = 0;
                i       = tp->TplFree->TPLIndex;
                buf     = tp->LocalTxBuffers[i];
@@ -1284,9 +1283,7 @@ static int tms380tr_reset_adapter(struct net_device *dev)
        unsigned short count, c, count2;
        const struct firmware *fw_entry = NULL;
 
-       strncpy(tms_device.bus_id,dev->name, BUS_ID_SIZE);
-
-       if (request_firmware(&fw_entry, "tms380tr.bin", &tms_device) != 0) {
+       if (request_firmware(&fw_entry, "tms380tr.bin", tp->pdev) != 0) {
                printk(KERN_ALERT "%s: firmware %s is missing, cannot start.\n",
                        dev->name, "tms380tr.bin");
                return (-1);
@@ -2021,7 +2018,7 @@ static void tms380tr_cancel_tx_queue(struct net_local* tp)
 
                printk(KERN_INFO "Cancel tx (%08lXh).\n", (unsigned long)tpl);
                if (tpl->DMABuff)
-                       pci_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, PCI_DMA_TODEVICE);
+                       dma_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, DMA_TO_DEVICE);
                dev_kfree_skb_any(tpl->Skb);
        }
 
@@ -2090,7 +2087,7 @@ static void tms380tr_tx_status_irq(struct net_device *dev)
 
                tp->MacStat.tx_packets++;
                if (tpl->DMABuff)
-                       pci_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, PCI_DMA_TODEVICE);
+                       dma_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, DMA_TO_DEVICE);
                dev_kfree_skb_irq(tpl->Skb);
                tpl->BusyFlag = 0;      /* "free" TPL */
        }
@@ -2209,7 +2206,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev)
                                tp->MacStat.rx_errors++;
                }
                if (rpl->DMABuff)
-                       pci_unmap_single(tp->pdev, rpl->DMABuff, tp->MaxPacketSize, PCI_DMA_TODEVICE);
+                       dma_unmap_single(tp->pdev, rpl->DMABuff, tp->MaxPacketSize, DMA_TO_DEVICE);
                rpl->DMABuff = 0;
 
                /* Allocate new skb for rpl */
@@ -2227,7 +2224,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev)
                        skb_put(rpl->Skb, tp->MaxPacketSize);
 
                        /* Data unreachable for DMA ? then use local buffer */
-                       dmabuf = pci_map_single(tp->pdev, rpl->Skb->data, tp->MaxPacketSize, PCI_DMA_FROMDEVICE);
+                       dmabuf = dma_map_single(tp->pdev, rpl->Skb->data, tp->MaxPacketSize, DMA_FROM_DEVICE);
                        if(tp->dmalimit && (dmabuf + tp->MaxPacketSize > tp->dmalimit))
                        {
                                rpl->SkbStat = SKB_DATA_COPY;
@@ -2332,23 +2329,26 @@ void tmsdev_term(struct net_device *dev)
        struct net_local *tp;
 
        tp = netdev_priv(dev);
-       pci_unmap_single(tp->pdev, tp->dmabuffer, sizeof(struct net_local),
-               PCI_DMA_BIDIRECTIONAL);
+       dma_unmap_single(tp->pdev, tp->dmabuffer, sizeof(struct net_local),
+               DMA_BIDIRECTIONAL);
 }
 
-int tmsdev_init(struct net_device *dev, unsigned long dmalimit, 
-               struct pci_dev *pdev)
+int tmsdev_init(struct net_device *dev, struct device *pdev)
 {
        struct net_local *tms_local;
 
        memset(dev->priv, 0, sizeof(struct net_local));
        tms_local = netdev_priv(dev);
        init_waitqueue_head(&tms_local->wait_for_tok_int);
-       tms_local->dmalimit = dmalimit;
+       if (pdev->dma_mask)
+               tms_local->dmalimit = *pdev->dma_mask;
+       else
+               return -ENOMEM;
        tms_local->pdev = pdev;
-       tms_local->dmabuffer = pci_map_single(pdev, (void *)tms_local,
-           sizeof(struct net_local), PCI_DMA_BIDIRECTIONAL);
-       if (tms_local->dmabuffer + sizeof(struct net_local) > dmalimit)
+       tms_local->dmabuffer = dma_map_single(pdev, (void *)tms_local,
+           sizeof(struct net_local), DMA_BIDIRECTIONAL);
+       if (tms_local->dmabuffer + sizeof(struct net_local) > 
+                       tms_local->dmalimit)
        {
                printk(KERN_INFO "%s: Memory not accessible for DMA\n",
                        dev->name);
@@ -2370,8 +2370,6 @@ int tmsdev_init(struct net_device *dev, unsigned long dmalimit,
        return 0;
 }
 
-#ifdef MODULE
-
 EXPORT_SYMBOL(tms380tr_open);
 EXPORT_SYMBOL(tms380tr_close);
 EXPORT_SYMBOL(tms380tr_interrupt);
@@ -2379,6 +2377,8 @@ EXPORT_SYMBOL(tmsdev_init);
 EXPORT_SYMBOL(tmsdev_term);
 EXPORT_SYMBOL(tms380tr_wait);
 
+#ifdef MODULE
+
 static struct module *TMS380_module = NULL;
 
 int init_module(void)
index f2c5ba0f37a550a009483cdc6887fde76136cbc0..30452c67bb68517cfba3236458c35d5c1557cfb4 100644 (file)
@@ -17,8 +17,7 @@
 int tms380tr_open(struct net_device *dev);
 int tms380tr_close(struct net_device *dev);
 irqreturn_t tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-int tmsdev_init(struct net_device *dev, unsigned long dmalimit,
-               struct pci_dev *pdev);
+int tmsdev_init(struct net_device *dev, struct device *pdev);
 void tmsdev_term(struct net_device *dev);
 void tms380tr_wait(unsigned long time);
 
@@ -719,7 +718,7 @@ struct s_TPL {      /* Transmit Parameter List (align on even word boundaries) */
        struct sk_buff *Skb;
        unsigned char TPLIndex;
        volatile unsigned char BusyFlag;/* Flag: TPL busy? */
-       dma_addr_t DMABuff;             /* DMA IO bus address from pci_map */
+       dma_addr_t DMABuff;             /* DMA IO bus address from dma_map */
 };
 
 /* ---------------------Receive Functions-------------------------------*
@@ -1060,7 +1059,7 @@ struct s_RPL {    /* Receive Parameter List */
        struct sk_buff *Skb;
        SKB_STAT SkbStat;
        int RPLIndex;
-       dma_addr_t DMABuff;             /* DMA IO bus address from pci_map */
+       dma_addr_t DMABuff;             /* DMA IO bus address from dma_map */
 };
 
 /* Information that need to be kept for each board. */
@@ -1091,7 +1090,7 @@ typedef struct net_local {
        RPL *RplTail;
        unsigned char LocalRxBuffers[RPL_NUM][DEFAULT_PACKET_SIZE];
 
-       struct pci_dev *pdev;
+       struct device *pdev;
        int DataRate;
        unsigned char ScbInUse;
        unsigned short CMDqueue;
index 2e18c0a464828f60960b30c48b1d8873cb28b513..ab47c0547a3ba0ada36f835a7a6a88d5b2ba39a4 100644 (file)
@@ -100,7 +100,7 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic
        unsigned int pci_irq_line;
        unsigned long pci_ioaddr;
        struct card_info *cardinfo = &card_info_table[ent->driver_data];
-               
+
        if (versionprinted++ == 0)
                printk("%s", version);
 
@@ -143,7 +143,7 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic
                printk(":%2.2x", dev->dev_addr[i]);
        printk("\n");
                
-       ret = tmsdev_init(dev, PCI_MAX_ADDRESS, pdev);
+       ret = tmsdev_init(dev, &pdev->dev);
        if (ret) {
                printk("%s: unable to get memory for dev->priv.\n", dev->name);
                goto err_out_irq;
index e2cdaf876201d80ead250cc2136c2d6cb6293dca..8c9634a98c111f92aee2cf674e7a856de3dd48a1 100644 (file)
@@ -135,6 +135,18 @@ config DM9102
          <file:Documentation/networking/net-modules.txt>.  The module will
          be called dmfe.
 
+config ULI526X
+       tristate "ULi M526x controller support"
+       depends on NET_TULIP && PCI
+       select CRC32
+       ---help---
+         This driver is for ULi M5261/M5263 10/100M Ethernet Controller
+         (<http://www.uli.com.tw/>).
+
+         To compile this driver as a module, choose M here and read
+         <file:Documentation/networking/net-modules.txt>.  The module will
+         be called uli526x.
+         
 config PCMCIA_XIRCOM
        tristate "Xircom CardBus support (new driver)"
        depends on NET_TULIP && CARDBUS
index 8bb9b4683979bb5df1d0900bb777af240f6e9e46..451090d6fcca29e0a773bb125fb6ea18b72ac6ae 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_WINBOND_840)       += winbond-840.o
 obj-$(CONFIG_DE2104X)          += de2104x.o
 obj-$(CONFIG_TULIP)            += tulip.o
 obj-$(CONFIG_DE4X5)            += de4x5.o
+obj-$(CONFIG_ULI526X)          += uli526x.o
 
 # Declare multi-part drivers.
 
index fc353e348f9aeaab909b216d8301706d014178af..a22d00198e4d6b5cde5b46ebff6cb1e569e6f68e 100644 (file)
@@ -1934,7 +1934,7 @@ static int __init de_init_one (struct pci_dev *pdev,
        struct de_private *de;
        int rc;
        void __iomem *regs;
-       long pciaddr;
+       unsigned long pciaddr;
        static int board_idx = -1;
 
        board_idx++;
index e26c31f944bf1622f8eb77933ac6623de6056cfe..f53396fe79c9f95d296dc3995208f0f66c3da8b8 100644 (file)
@@ -81,25 +81,6 @@ int tulip_mdio_read(struct net_device *dev, int phy_id, int location)
                return retval & 0xffff;
        }
 
-       if(tp->chip_id == ULI526X && tp->revision >= 0x40) {
-               int value;
-               int i = 1000;
-               
-               value = ioread32(ioaddr + CSR9);
-               iowrite32(value & 0xFFEFFFFF, ioaddr + CSR9);
-               
-               value = (phy_id << 21) | (location << 16) | 0x08000000;
-               iowrite32(value, ioaddr + CSR10);
-               
-               while(--i > 0) {
-                       mdio_delay();
-                       if(ioread32(ioaddr + CSR10) & 0x10000000)
-                               break;
-               }
-               retval = ioread32(ioaddr + CSR10);
-               spin_unlock_irqrestore(&tp->mii_lock, flags);
-               return retval & 0xFFFF;
-       }
        /* Establish sync by sending at least 32 logic ones. */
        for (i = 32; i >= 0; i--) {
                iowrite32(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
@@ -159,23 +140,6 @@ void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int val)
                spin_unlock_irqrestore(&tp->mii_lock, flags);
                return;
        }
-       if (tp->chip_id == ULI526X && tp->revision >= 0x40) {
-               int value;
-               int i = 1000;
-               
-               value = ioread32(ioaddr + CSR9);
-               iowrite32(value & 0xFFEFFFFF, ioaddr + CSR9);
-               
-               value = (phy_id << 21) | (location << 16) | 0x04000000 | (val & 0xFFFF);
-               iowrite32(value, ioaddr + CSR10);
-               
-               while(--i > 0) {
-                       if (ioread32(ioaddr + CSR10) & 0x10000000)
-                               break;
-               }
-               spin_unlock_irqrestore(&tp->mii_lock, flags);
-               return;
-       }
                
        /* Establish sync by sending 32 logic ones. */
        for (i = 32; i >= 0; i--) {
index 691568283553b48e1c4744a9cd3393a3f2093c7d..e058a9fbfe884414308b005926e9d81a33e94392 100644 (file)
@@ -39,7 +39,6 @@ void tulip_timer(unsigned long data)
        case MX98713:
        case COMPEX9881:
        case DM910X:
-       case ULI526X:
        default: {
                struct medialeaf *mleaf;
                unsigned char *p;
index 20346d847d9e176f888728129d65b6e93ba2aec7..05d2d96f7be26858c3c66a8f9fbacaf170c8e1bc 100644 (file)
@@ -88,7 +88,6 @@ enum chips {
        I21145,
        DM910X,
        CONEXANT,
-       ULI526X
 };
 
 
@@ -482,11 +481,8 @@ static inline void tulip_stop_rxtx(struct tulip_private *tp)
 
 static inline void tulip_restart_rxtx(struct tulip_private *tp)
 {
-       if(!(tp->chip_id == ULI526X && 
-               (tp->revision == 0x40 || tp->revision == 0x50))) {
-               tulip_stop_rxtx(tp);
-               udelay(5);
-       }
+       tulip_stop_rxtx(tp);
+       udelay(5);
        tulip_start_rxtx(tp);
 }
 
index d45d8f56e5b4a3df298aa6ae3b42b602db2f5b55..6266a9a7e6e3a36430b33039af682f3dbdd15607 100644 (file)
@@ -199,9 +199,6 @@ struct tulip_chip_table tulip_tbl[] = {
   { "Conexant LANfinity", 256, 0x0001ebef,
        HAS_MII | HAS_ACPI, tulip_timer },
 
-   /* ULi526X */
-   { "ULi M5261/M5263", 128, 0x0001ebef,
-        HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_ACPI, tulip_timer },
 };
 
 
@@ -239,10 +236,9 @@ static struct pci_device_id tulip_pci_tbl[] = {
        { 0x1737, 0xAB09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
        { 0x1737, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
        { 0x17B3, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
-       { 0x10b9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ULI526X },      /* ALi 1563 integrated ethernet */
-       { 0x10b9, 0x5263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ULI526X },      /* ALi 1563 integrated ethernet */
        { 0x10b7, 0x9300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* 3Com 3CSOHO100B-TX */
        { 0x14ea, 0xab08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* Planex FNW-3602-TX */
+       { 0x1414, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
        { } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, tulip_pci_tbl);
@@ -522,7 +518,7 @@ static void tulip_tx_timeout(struct net_device *dev)
                                   dev->name);
        } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142
                           || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881
-                          || tp->chip_id == DM910X || tp->chip_id == ULI526X) {
+                          || tp->chip_id == DM910X) {
                printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
                           "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
                           dev->name, ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12),
@@ -1103,18 +1099,16 @@ static void set_rx_mode(struct net_device *dev)
                        entry = tp->cur_tx++ % TX_RING_SIZE;
 
                        if (entry != 0) {
-                               /* Avoid a chip errata by prefixing a dummy entry. Don't do
-                                  this on the ULI526X as it triggers a different problem */
-                               if (!(tp->chip_id == ULI526X && (tp->revision == 0x40 || tp->revision == 0x50))) {
-                                       tp->tx_buffers[entry].skb = NULL;
-                                       tp->tx_buffers[entry].mapping = 0;
-                                       tp->tx_ring[entry].length =
-                                               (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0;
-                                       tp->tx_ring[entry].buffer1 = 0;
-                                       /* Must set DescOwned later to avoid race with chip */
-                                       dummy = entry;
-                                       entry = tp->cur_tx++ % TX_RING_SIZE;
-                               }
+                               /* Avoid a chip errata by prefixing a dummy entry. */
+                               tp->tx_buffers[entry].skb = NULL;
+                               tp->tx_buffers[entry].mapping = 0;
+                               tp->tx_ring[entry].length =
+                                       (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0;
+                               tp->tx_ring[entry].buffer1 = 0;
+                               /* Must set DescOwned later to avoid race with chip */
+                               dummy = entry;
+                               entry = tp->cur_tx++ % TX_RING_SIZE;
+
                        }
 
                        tp->tx_buffers[entry].skb = NULL;
@@ -1235,10 +1229,6 @@ static int tulip_uli_dm_quirk(struct pci_dev *pdev)
 {
        if (pdev->vendor == 0x1282 && pdev->device == 0x9102)
                return 1;
-       if (pdev->vendor == 0x10b9 && pdev->device == 0x5261)
-               return 1;
-       if (pdev->vendor == 0x10b9 && pdev->device == 0x5263)
-               return 1;
        return 0;
 }
 
@@ -1680,7 +1670,6 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        switch (chip_idx) {
        case DC21140:
        case DM910X:
-       case ULI526X:
        default:
                if (tp->mtable)
                        iowrite32(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
new file mode 100644 (file)
index 0000000..1a43163
--- /dev/null
@@ -0,0 +1,1749 @@
+/*
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License
+    as published by the Free Software Foundation; either version 2
+    of the License, or (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    
+*/
+
+#define DRV_NAME       "uli526x"
+#define DRV_VERSION    "0.9.3"
+#define DRV_RELDATE    "2005-7-29"
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/processor.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+
+
+/* Board/System/Debug information/definition ---------------- */
+#define PCI_ULI5261_ID  0x526110B9     /* ULi M5261 ID*/
+#define PCI_ULI5263_ID  0x526310B9     /* ULi M5263 ID*/
+
+#define ULI526X_IO_SIZE 0x100
+#define TX_DESC_CNT     0x20            /* Allocated Tx descriptors */
+#define RX_DESC_CNT     0x30            /* Allocated Rx descriptors */
+#define TX_FREE_DESC_CNT (TX_DESC_CNT - 2)     /* Max TX packet count */
+#define TX_WAKE_DESC_CNT (TX_DESC_CNT - 3)     /* TX wakeup count */
+#define DESC_ALL_CNT    (TX_DESC_CNT + RX_DESC_CNT)
+#define TX_BUF_ALLOC    0x600
+#define RX_ALLOC_SIZE   0x620
+#define ULI526X_RESET    1
+#define CR0_DEFAULT     0
+#define CR6_DEFAULT     0x22200000
+#define CR7_DEFAULT     0x180c1
+#define CR15_DEFAULT    0x06            /* TxJabber RxWatchdog */
+#define TDES0_ERR_MASK  0x4302          /* TXJT, LC, EC, FUE */
+#define MAX_PACKET_SIZE 1514
+#define ULI5261_MAX_MULTICAST 14
+#define RX_COPY_SIZE   100
+#define MAX_CHECK_PACKET 0x8000
+
+#define ULI526X_10MHF      0
+#define ULI526X_100MHF     1
+#define ULI526X_10MFD      4
+#define ULI526X_100MFD     5
+#define ULI526X_AUTO       8
+
+#define ULI526X_TXTH_72        0x400000        /* TX TH 72 byte */
+#define ULI526X_TXTH_96        0x404000        /* TX TH 96 byte */
+#define ULI526X_TXTH_128       0x0000          /* TX TH 128 byte */
+#define ULI526X_TXTH_256       0x4000          /* TX TH 256 byte */
+#define ULI526X_TXTH_512       0x8000          /* TX TH 512 byte */
+#define ULI526X_TXTH_1K        0xC000          /* TX TH 1K  byte */
+
+#define ULI526X_TIMER_WUT  (jiffies + HZ * 1)/* timer wakeup time : 1 second */
+#define ULI526X_TX_TIMEOUT ((16*HZ)/2) /* tx packet time-out time 8 s" */
+#define ULI526X_TX_KICK        (4*HZ/2)        /* tx packet Kick-out time 2 s" */
+
+#define ULI526X_DBUG(dbug_now, msg, value) if (uli526x_debug || (dbug_now)) printk(KERN_ERR DRV_NAME ": %s %lx\n", (msg), (long) (value))
+
+#define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR DRV_NAME ": Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half");
+
+
+/* CR9 definition: SROM/MII */
+#define CR9_SROM_READ   0x4800
+#define CR9_SRCS        0x1
+#define CR9_SRCLK       0x2
+#define CR9_CRDOUT      0x8
+#define SROM_DATA_0     0x0
+#define SROM_DATA_1     0x4
+#define PHY_DATA_1      0x20000
+#define PHY_DATA_0      0x00000
+#define MDCLKH          0x10000
+
+#define PHY_POWER_DOWN 0x800
+
+#define SROM_V41_CODE   0x14
+
+#define SROM_CLK_WRITE(data, ioaddr)                                   \
+               outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);               \
+               udelay(5);                                              \
+               outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr);     \
+               udelay(5);                                              \
+               outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);               \
+               udelay(5);
+
+/* Structure/enum declaration ------------------------------- */
+struct tx_desc {
+        u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */
+        char *tx_buf_ptr;               /* Data for us */
+        struct tx_desc *next_tx_desc;
+} __attribute__(( aligned(32) ));
+
+struct rx_desc {
+       u32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */
+       struct sk_buff *rx_skb_ptr;     /* Data for us */
+       struct rx_desc *next_rx_desc;
+} __attribute__(( aligned(32) ));
+
+struct uli526x_board_info {
+       u32 chip_id;                    /* Chip vendor/Device ID */
+       struct net_device *next_dev;    /* next device */
+       struct pci_dev *pdev;           /* PCI device */
+       spinlock_t lock;
+
+       long ioaddr;                    /* I/O base address */
+       u32 cr0_data;
+       u32 cr5_data;
+       u32 cr6_data;
+       u32 cr7_data;
+       u32 cr15_data;
+
+       /* pointer for memory physical address */
+       dma_addr_t buf_pool_dma_ptr;    /* Tx buffer pool memory */
+       dma_addr_t buf_pool_dma_start;  /* Tx buffer pool align dword */
+       dma_addr_t desc_pool_dma_ptr;   /* descriptor pool memory */
+       dma_addr_t first_tx_desc_dma;
+       dma_addr_t first_rx_desc_dma;
+
+       /* descriptor pointer */
+       unsigned char *buf_pool_ptr;    /* Tx buffer pool memory */
+       unsigned char *buf_pool_start;  /* Tx buffer pool align dword */
+       unsigned char *desc_pool_ptr;   /* descriptor pool memory */
+       struct tx_desc *first_tx_desc;
+       struct tx_desc *tx_insert_ptr;
+       struct tx_desc *tx_remove_ptr;
+       struct rx_desc *first_rx_desc;
+       struct rx_desc *rx_insert_ptr;
+       struct rx_desc *rx_ready_ptr;   /* packet come pointer */
+       unsigned long tx_packet_cnt;    /* transmitted packet count */
+       unsigned long rx_avail_cnt;     /* available rx descriptor count */
+       unsigned long interval_rx_cnt;  /* rx packet count a callback time */
+
+       u16 dbug_cnt;
+       u16 NIC_capability;             /* NIC media capability */
+       u16 PHY_reg4;                   /* Saved Phyxcer register 4 value */
+
+       u8 media_mode;                  /* user specify media mode */
+       u8 op_mode;                     /* real work media mode */
+       u8 phy_addr;
+       u8 link_failed;                 /* Ever link failed */
+       u8 wait_reset;                  /* Hardware failed, need to reset */
+       struct timer_list timer;
+
+       /* System defined statistic counter */
+       struct net_device_stats stats;
+
+       /* Driver defined statistic counter */
+       unsigned long tx_fifo_underrun;
+       unsigned long tx_loss_carrier;
+       unsigned long tx_no_carrier;
+       unsigned long tx_late_collision;
+       unsigned long tx_excessive_collision;
+       unsigned long tx_jabber_timeout;
+       unsigned long reset_count;
+       unsigned long reset_cr8;
+       unsigned long reset_fatal;
+       unsigned long reset_TXtimeout;
+
+       /* NIC SROM data */
+       unsigned char srom[128];
+       u8 init;        
+};
+
+enum uli526x_offsets {
+       DCR0 = 0x00, DCR1 = 0x08, DCR2 = 0x10, DCR3 = 0x18, DCR4 = 0x20,
+       DCR5 = 0x28, DCR6 = 0x30, DCR7 = 0x38, DCR8 = 0x40, DCR9 = 0x48,
+       DCR10 = 0x50, DCR11 = 0x58, DCR12 = 0x60, DCR13 = 0x68, DCR14 = 0x70,
+       DCR15 = 0x78
+};
+
+enum uli526x_CR6_bits {
+       CR6_RXSC = 0x2, CR6_PBF = 0x8, CR6_PM = 0x40, CR6_PAM = 0x80,
+       CR6_FDM = 0x200, CR6_TXSC = 0x2000, CR6_STI = 0x100000,
+       CR6_SFT = 0x200000, CR6_RXA = 0x40000000, CR6_NO_PURGE = 0x20000000
+};
+
+/* Global variable declaration ----------------------------- */
+static int __devinitdata printed_version;
+static char version[] __devinitdata =
+       KERN_INFO DRV_NAME ": ULi M5261/M5263 net driver, version "
+       DRV_VERSION " (" DRV_RELDATE ")\n";
+
+static int uli526x_debug;
+static unsigned char uli526x_media_mode = ULI526X_AUTO;
+static u32 uli526x_cr6_user_set;
+
+/* For module input parameter */
+static int debug;
+static u32 cr6set;
+static unsigned char mode = 8;
+
+/* function declaration ------------------------------------- */
+static int uli526x_open(struct net_device *);
+static int uli526x_start_xmit(struct sk_buff *, struct net_device *);
+static int uli526x_stop(struct net_device *);
+static struct net_device_stats * uli526x_get_stats(struct net_device *);
+static void uli526x_set_filter_mode(struct net_device *);
+static struct ethtool_ops netdev_ethtool_ops;
+static u16 read_srom_word(long, int);
+static irqreturn_t uli526x_interrupt(int, void *, struct pt_regs *);
+static void uli526x_descriptor_init(struct uli526x_board_info *, unsigned long);
+static void allocate_rx_buffer(struct uli526x_board_info *);
+static void update_cr6(u32, unsigned long);
+static void send_filter_frame(struct net_device *, int);
+static u16 phy_read(unsigned long, u8, u8, u32);
+static u16 phy_readby_cr10(unsigned long, u8, u8);
+static void phy_write(unsigned long, u8, u8, u16, u32);
+static void phy_writeby_cr10(unsigned long, u8, u8, u16);
+static void phy_write_1bit(unsigned long, u32, u32);
+static u16 phy_read_1bit(unsigned long, u32);
+static u8 uli526x_sense_speed(struct uli526x_board_info *);
+static void uli526x_process_mode(struct uli526x_board_info *);
+static void uli526x_timer(unsigned long);
+static void uli526x_rx_packet(struct net_device *, struct uli526x_board_info *);
+static void uli526x_free_tx_pkt(struct net_device *, struct uli526x_board_info *);
+static void uli526x_reuse_skb(struct uli526x_board_info *, struct sk_buff *);
+static void uli526x_dynamic_reset(struct net_device *);
+static void uli526x_free_rxbuffer(struct uli526x_board_info *);
+static void uli526x_init(struct net_device *);
+static void uli526x_set_phyxcer(struct uli526x_board_info *);
+
+/* ULI526X network board routine ---------------------------- */
+
+/*
+ *     Search ULI526X board, allocate space and register it
+ */
+
+static int __devinit uli526x_init_one (struct pci_dev *pdev,
+                                   const struct pci_device_id *ent)
+{
+       struct uli526x_board_info *db;  /* board information structure */
+       struct net_device *dev;
+       int i, err;
+       
+       ULI526X_DBUG(0, "uli526x_init_one()", 0);
+
+       if (!printed_version++)
+               printk(version);
+
+       /* Init network device */
+       dev = alloc_etherdev(sizeof(*db));
+       if (dev == NULL)
+               return -ENOMEM;
+       SET_MODULE_OWNER(dev);
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
+               printk(KERN_WARNING DRV_NAME ": 32-bit PCI DMA not available.\n");
+               err = -ENODEV;
+               goto err_out_free;
+       }
+
+       /* Enable Master/IO access, Disable memory access */
+       err = pci_enable_device(pdev);
+       if (err)
+               goto err_out_free;
+
+       if (!pci_resource_start(pdev, 0)) {
+               printk(KERN_ERR DRV_NAME ": I/O base is zero\n");
+               err = -ENODEV;
+               goto err_out_disable;
+       }
+
+       if (pci_resource_len(pdev, 0) < (ULI526X_IO_SIZE) ) {
+               printk(KERN_ERR DRV_NAME ": Allocated I/O size too small\n");
+               err = -ENODEV;
+               goto err_out_disable;
+       }
+
+       if (pci_request_regions(pdev, DRV_NAME)) {
+               printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n");
+               err = -ENODEV;
+               goto err_out_disable;
+       }
+
+       /* Init system & device */
+       db = netdev_priv(dev);
+
+       /* Allocate Tx/Rx descriptor memory */
+       db->desc_pool_ptr = pci_alloc_consistent(pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, &db->desc_pool_dma_ptr);
+       if(db->desc_pool_ptr == NULL)
+       {
+               err = -ENOMEM;
+               goto err_out_nomem;
+       }
+       db->buf_pool_ptr = pci_alloc_consistent(pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4, &db->buf_pool_dma_ptr);
+       if(db->buf_pool_ptr == NULL)
+       {
+               err = -ENOMEM;
+               goto err_out_nomem;
+       }
+       
+       db->first_tx_desc = (struct tx_desc *) db->desc_pool_ptr;
+       db->first_tx_desc_dma = db->desc_pool_dma_ptr;
+       db->buf_pool_start = db->buf_pool_ptr;
+       db->buf_pool_dma_start = db->buf_pool_dma_ptr;
+
+       db->chip_id = ent->driver_data;
+       db->ioaddr = pci_resource_start(pdev, 0);
+       
+       db->pdev = pdev;
+       db->init = 1;
+       
+       dev->base_addr = db->ioaddr;
+       dev->irq = pdev->irq;
+       pci_set_drvdata(pdev, dev);
+       
+       /* Register some necessary functions */
+       dev->open = &uli526x_open;
+       dev->hard_start_xmit = &uli526x_start_xmit;
+       dev->stop = &uli526x_stop;
+       dev->get_stats = &uli526x_get_stats;
+       dev->set_multicast_list = &uli526x_set_filter_mode;
+       dev->ethtool_ops = &netdev_ethtool_ops;
+       spin_lock_init(&db->lock);
+
+               
+       /* read 64 word srom data */
+       for (i = 0; i < 64; i++)
+               ((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i));
+
+       /* Set Node address */
+       if(((u16 *) db->srom)[0] == 0xffff || ((u16 *) db->srom)[0] == 0)               /* SROM absent, so read MAC address from ID Table */
+       {
+               outl(0x10000, db->ioaddr + DCR0);       //Diagnosis mode
+               outl(0x1c0, db->ioaddr + DCR13);        //Reset dianostic pointer port
+               outl(0, db->ioaddr + DCR14);            //Clear reset port
+               outl(0x10, db->ioaddr + DCR14);         //Reset ID Table pointer
+               outl(0, db->ioaddr + DCR14);            //Clear reset port
+               outl(0, db->ioaddr + DCR13);            //Clear CR13
+               outl(0x1b0, db->ioaddr + DCR13);        //Select ID Table access port
+               //Read MAC address from CR14
+               for (i = 0; i < 6; i++)
+                       dev->dev_addr[i] = inl(db->ioaddr + DCR14);
+               //Read end
+               outl(0, db->ioaddr + DCR13);    //Clear CR13
+               outl(0, db->ioaddr + DCR0);             //Clear CR0
+               udelay(10);
+       }
+       else            /*Exist SROM*/
+       {
+               for (i = 0; i < 6; i++)
+                       dev->dev_addr[i] = db->srom[20 + i];
+       }
+       err = register_netdev (dev);
+       if (err)
+               goto err_out_res;
+
+       printk(KERN_INFO "%s: ULi M%04lx at pci%s,",dev->name,ent->driver_data >> 16,pci_name(pdev));
+       
+       for (i = 0; i < 6; i++)
+               printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
+       printk(", irq %d.\n", dev->irq);
+
+       pci_set_master(pdev);
+
+       return 0;
+
+err_out_res:
+       pci_release_regions(pdev);
+err_out_nomem:
+       if(db->desc_pool_ptr)
+               pci_free_consistent(pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20,
+                       db->desc_pool_ptr, db->desc_pool_dma_ptr);
+                       
+       if(db->buf_pool_ptr != NULL)
+               pci_free_consistent(pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4,
+                       db->buf_pool_ptr, db->buf_pool_dma_ptr);
+err_out_disable:
+       pci_disable_device(pdev);
+err_out_free:
+       pci_set_drvdata(pdev, NULL);
+       free_netdev(dev);
+
+       return err;
+}
+
+
+static void __devexit uli526x_remove_one (struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct uli526x_board_info *db = netdev_priv(dev);
+
+       ULI526X_DBUG(0, "uli526x_remove_one()", 0);
+
+       pci_free_consistent(db->pdev, sizeof(struct tx_desc) *
+                               DESC_ALL_CNT + 0x20, db->desc_pool_ptr,
+                               db->desc_pool_dma_ptr);
+       pci_free_consistent(db->pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4,
+                               db->buf_pool_ptr, db->buf_pool_dma_ptr);
+       unregister_netdev(dev);
+       pci_release_regions(pdev);
+       free_netdev(dev);       /* free board information */
+       pci_set_drvdata(pdev, NULL);
+       pci_disable_device(pdev);
+       ULI526X_DBUG(0, "uli526x_remove_one() exit", 0);
+}
+
+
+/*
+ *     Open the interface.
+ *     The interface is opened whenever "ifconfig" activates it.
+ */
+
+static int uli526x_open(struct net_device *dev)
+{
+       int ret;
+       struct uli526x_board_info *db = netdev_priv(dev);
+       
+       ULI526X_DBUG(0, "uli526x_open", 0);
+
+       ret = request_irq(dev->irq, &uli526x_interrupt, SA_SHIRQ, dev->name, dev);
+       if (ret)
+               return ret;
+
+       /* system variable init */
+       db->cr6_data = CR6_DEFAULT | uli526x_cr6_user_set;
+       db->tx_packet_cnt = 0;
+       db->rx_avail_cnt = 0;
+       db->link_failed = 1;
+       netif_carrier_off(dev);
+       db->wait_reset = 0;
+
+       db->NIC_capability = 0xf;       /* All capability*/
+       db->PHY_reg4 = 0x1e0;
+
+       /* CR6 operation mode decision */
+       db->cr6_data |= ULI526X_TXTH_256;
+       db->cr0_data = CR0_DEFAULT;
+       
+       /* Initialize ULI526X board */
+       uli526x_init(dev);
+
+       /* Active System Interface */
+       netif_wake_queue(dev);
+
+       /* set and active a timer process */
+       init_timer(&db->timer);
+       db->timer.expires = ULI526X_TIMER_WUT + HZ * 2;
+       db->timer.data = (unsigned long)dev;
+       db->timer.function = &uli526x_timer;
+       add_timer(&db->timer);
+
+       return 0;
+}
+
+
+/*     Initialize ULI526X board
+ *     Reset ULI526X board
+ *     Initialize TX/Rx descriptor chain structure
+ *     Send the set-up frame
+ *     Enable Tx/Rx machine
+ */
+
+static void uli526x_init(struct net_device *dev)
+{
+       struct uli526x_board_info *db = netdev_priv(dev);
+       unsigned long ioaddr = db->ioaddr;
+       u8      phy_tmp;
+       u16     phy_value;
+       u16 phy_reg_reset;
+
+       ULI526X_DBUG(0, "uli526x_init()", 0);
+
+       /* Reset M526x MAC controller */
+       outl(ULI526X_RESET, ioaddr + DCR0);     /* RESET MAC */
+       udelay(100);
+       outl(db->cr0_data, ioaddr + DCR0);
+       udelay(5);
+
+       /* Phy addr : In some boards,M5261/M5263 phy address != 1 */
+       db->phy_addr = 1;
+       for(phy_tmp=0;phy_tmp<32;phy_tmp++)
+       {
+               phy_value=phy_read(db->ioaddr,phy_tmp,3,db->chip_id);//peer add
+               if(phy_value != 0xffff&&phy_value!=0)
+               {
+                       db->phy_addr = phy_tmp;
+                       break;
+               }
+       }
+       if(phy_tmp == 32)
+               printk(KERN_WARNING "Can not find the phy address!!!");
+       /* Parser SROM and media mode */
+       db->media_mode = uli526x_media_mode;
+
+       /* Phyxcer capability setting */
+       phy_reg_reset = phy_read(db->ioaddr, db->phy_addr, 0, db->chip_id);
+       phy_reg_reset = (phy_reg_reset | 0x8000);
+       phy_write(db->ioaddr, db->phy_addr, 0, phy_reg_reset, db->chip_id);
+       udelay(500);
+
+       /* Process Phyxcer Media Mode */
+       uli526x_set_phyxcer(db);
+
+       /* Media Mode Process */
+       if ( !(db->media_mode & ULI526X_AUTO) )
+               db->op_mode = db->media_mode;   /* Force Mode */
+
+       /* Initialize Transmit/Receive decriptor and CR3/4 */
+       uli526x_descriptor_init(db, ioaddr);
+
+       /* Init CR6 to program M526X operation */
+       update_cr6(db->cr6_data, ioaddr);
+
+       /* Send setup frame */
+       send_filter_frame(dev, dev->mc_count);  /* M5261/M5263 */
+
+       /* Init CR7, interrupt active bit */
+       db->cr7_data = CR7_DEFAULT;
+       outl(db->cr7_data, ioaddr + DCR7);
+
+       /* Init CR15, Tx jabber and Rx watchdog timer */
+       outl(db->cr15_data, ioaddr + DCR15);
+
+       /* Enable ULI526X Tx/Rx function */
+       db->cr6_data |= CR6_RXSC | CR6_TXSC;
+       update_cr6(db->cr6_data, ioaddr);
+}
+
+
+/*
+ *     Hardware start transmission.
+ *     Send a packet to media from the upper layer.
+ */
+
+static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct uli526x_board_info *db = netdev_priv(dev);
+       struct tx_desc *txptr;
+       unsigned long flags;
+
+       ULI526X_DBUG(0, "uli526x_start_xmit", 0);
+
+       /* Resource flag check */
+       netif_stop_queue(dev);
+
+       /* Too large packet check */
+       if (skb->len > MAX_PACKET_SIZE) {
+               printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len);
+               dev_kfree_skb(skb);
+               return 0;
+       }
+
+       spin_lock_irqsave(&db->lock, flags);
+
+       /* No Tx resource check, it never happen nromally */
+       if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) {
+               spin_unlock_irqrestore(&db->lock, flags);
+               printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_packet_cnt);
+               return 1;
+       }
+
+       /* Disable NIC interrupt */
+       outl(0, dev->base_addr + DCR7);
+
+       /* transmit this packet */
+       txptr = db->tx_insert_ptr;
+       memcpy(txptr->tx_buf_ptr, skb->data, skb->len);
+       txptr->tdes1 = cpu_to_le32(0xe1000000 | skb->len);
+
+       /* Point to next transmit free descriptor */
+       db->tx_insert_ptr = txptr->next_tx_desc;
+
+       /* Transmit Packet Process */
+       if ( (db->tx_packet_cnt < TX_DESC_CNT) ) {
+               txptr->tdes0 = cpu_to_le32(0x80000000); /* Set owner bit */
+               db->tx_packet_cnt++;                    /* Ready to send */
+               outl(0x1, dev->base_addr + DCR1);       /* Issue Tx polling */
+               dev->trans_start = jiffies;             /* saved time stamp */
+       }
+
+       /* Tx resource check */
+       if ( db->tx_packet_cnt < TX_FREE_DESC_CNT )
+               netif_wake_queue(dev);
+
+       /* Restore CR7 to enable interrupt */
+       spin_unlock_irqrestore(&db->lock, flags);
+       outl(db->cr7_data, dev->base_addr + DCR7);
+       
+       /* free this SKB */
+       dev_kfree_skb(skb);
+
+       return 0;
+}
+
+
+/*
+ *     Stop the interface.
+ *     The interface is stopped when it is brought.
+ */
+
+static int uli526x_stop(struct net_device *dev)
+{
+       struct uli526x_board_info *db = netdev_priv(dev);
+       unsigned long ioaddr = dev->base_addr;
+
+       ULI526X_DBUG(0, "uli526x_stop", 0);
+
+       /* disable system */
+       netif_stop_queue(dev);
+
+       /* deleted timer */
+       del_timer_sync(&db->timer);
+
+       /* Reset & stop ULI526X board */
+       outl(ULI526X_RESET, ioaddr + DCR0);
+       udelay(5);
+       phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);
+
+       /* free interrupt */
+       free_irq(dev->irq, dev);
+
+       /* free allocated rx buffer */
+       uli526x_free_rxbuffer(db);
+
+#if 0
+       /* show statistic counter */
+       printk(DRV_NAME ": FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n",
+               db->tx_fifo_underrun, db->tx_excessive_collision,
+               db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier,
+               db->tx_jabber_timeout, db->reset_count, db->reset_cr8,
+               db->reset_fatal, db->reset_TXtimeout);
+#endif
+
+       return 0;
+}
+
+
+/*
+ *     M5261/M5263 insterrupt handler
+ *     receive the packet to upper layer, free the transmitted packet
+ */
+
+static irqreturn_t uli526x_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct net_device *dev = dev_id;
+       struct uli526x_board_info *db = netdev_priv(dev);
+       unsigned long ioaddr = dev->base_addr;
+       unsigned long flags;
+
+       if (!dev) {
+               ULI526X_DBUG(1, "uli526x_interrupt() without DEVICE arg", 0);
+               return IRQ_NONE;
+       }
+
+       spin_lock_irqsave(&db->lock, flags);
+       outl(0, ioaddr + DCR7);
+
+       /* Got ULI526X status */
+       db->cr5_data = inl(ioaddr + DCR5);
+       outl(db->cr5_data, ioaddr + DCR5);
+       if ( !(db->cr5_data & 0x180c1) ) {
+               spin_unlock_irqrestore(&db->lock, flags);
+               outl(db->cr7_data, ioaddr + DCR7);
+               return IRQ_HANDLED;
+       }
+
+       /* Check system status */
+       if (db->cr5_data & 0x2000) {
+               /* system bus error happen */
+               ULI526X_DBUG(1, "System bus error happen. CR5=", db->cr5_data);
+               db->reset_fatal++;
+               db->wait_reset = 1;     /* Need to RESET */
+               spin_unlock_irqrestore(&db->lock, flags);
+               return IRQ_HANDLED;
+       }
+
+        /* Received the coming packet */
+       if ( (db->cr5_data & 0x40) && db->rx_avail_cnt )
+               uli526x_rx_packet(dev, db);
+
+       /* reallocate rx descriptor buffer */
+       if (db->rx_avail_cnt<RX_DESC_CNT)
+               allocate_rx_buffer(db);
+
+       /* Free the transmitted descriptor */
+       if ( db->cr5_data & 0x01)
+               uli526x_free_tx_pkt(dev, db);
+
+       /* Restore CR7 to enable interrupt mask */
+       outl(db->cr7_data, ioaddr + DCR7);
+
+       spin_unlock_irqrestore(&db->lock, flags);
+       return IRQ_HANDLED;
+}
+
+
+/*
+ *     Free TX resource after TX complete
+ */
+
+static void uli526x_free_tx_pkt(struct net_device *dev, struct uli526x_board_info * db)
+{
+       struct tx_desc *txptr;
+       u32 tdes0;
+
+       txptr = db->tx_remove_ptr;
+       while(db->tx_packet_cnt) {
+               tdes0 = le32_to_cpu(txptr->tdes0);
+               /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */
+               if (tdes0 & 0x80000000)
+                       break;
+
+               /* A packet sent completed */
+               db->tx_packet_cnt--;
+               db->stats.tx_packets++;
+
+               /* Transmit statistic counter */
+               if ( tdes0 != 0x7fffffff ) {
+                       /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */
+                       db->stats.collisions += (tdes0 >> 3) & 0xf;
+                       db->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff;
+                       if (tdes0 & TDES0_ERR_MASK) {
+                               db->stats.tx_errors++;
+                               if (tdes0 & 0x0002) {   /* UnderRun */
+                                       db->tx_fifo_underrun++;
+                                       if ( !(db->cr6_data & CR6_SFT) ) {
+                                               db->cr6_data = db->cr6_data | CR6_SFT;
+                                               update_cr6(db->cr6_data, db->ioaddr);
+                                       }
+                               }
+                               if (tdes0 & 0x0100)
+                                       db->tx_excessive_collision++;
+                               if (tdes0 & 0x0200)
+                                       db->tx_late_collision++;
+                               if (tdes0 & 0x0400)
+                                       db->tx_no_carrier++;
+                               if (tdes0 & 0x0800)
+                                       db->tx_loss_carrier++;
+                               if (tdes0 & 0x4000)
+                                       db->tx_jabber_timeout++;
+                       }
+               }
+
+               txptr = txptr->next_tx_desc;
+       }/* End of while */
+
+       /* Update TX remove pointer to next */
+       db->tx_remove_ptr = txptr;
+
+       /* Resource available check */
+       if ( db->tx_packet_cnt < TX_WAKE_DESC_CNT )
+               netif_wake_queue(dev);  /* Active upper layer, send again */
+}
+
+
+/*
+ *     Receive the come packet and pass to upper layer
+ */
+
+static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info * db)
+{
+       struct rx_desc *rxptr;
+       struct sk_buff *skb;
+       int rxlen;
+       u32 rdes0;
+       
+       rxptr = db->rx_ready_ptr;
+
+       while(db->rx_avail_cnt) {
+               rdes0 = le32_to_cpu(rxptr->rdes0);
+               if (rdes0 & 0x80000000) /* packet owner check */
+               {
+                       break;
+               }
+
+               db->rx_avail_cnt--;
+               db->interval_rx_cnt++;
+
+               pci_unmap_single(db->pdev, le32_to_cpu(rxptr->rdes2), RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE);
+               if ( (rdes0 & 0x300) != 0x300) {
+                       /* A packet without First/Last flag */
+                       /* reuse this SKB */
+                       ULI526X_DBUG(0, "Reuse SK buffer, rdes0", rdes0);
+                       uli526x_reuse_skb(db, rxptr->rx_skb_ptr);
+               } else {
+                       /* A packet with First/Last flag */
+                       rxlen = ( (rdes0 >> 16) & 0x3fff) - 4;
+
+                       /* error summary bit check */
+                       if (rdes0 & 0x8000) {
+                               /* This is a error packet */
+                               //printk(DRV_NAME ": rdes0: %lx\n", rdes0);
+                               db->stats.rx_errors++;
+                               if (rdes0 & 1)
+                                       db->stats.rx_fifo_errors++;
+                               if (rdes0 & 2)
+                                       db->stats.rx_crc_errors++;
+                               if (rdes0 & 0x80)
+                                       db->stats.rx_length_errors++;
+                       }
+
+                       if ( !(rdes0 & 0x8000) ||
+                               ((db->cr6_data & CR6_PM) && (rxlen>6)) ) {
+                               skb = rxptr->rx_skb_ptr;
+               
+                               /* Good packet, send to upper layer */
+                               /* Shorst packet used new SKB */
+                               if ( (rxlen < RX_COPY_SIZE) &&
+                                       ( (skb = dev_alloc_skb(rxlen + 2) )
+                                       != NULL) ) {
+                                       /* size less than COPY_SIZE, allocate a rxlen SKB */
+                                       skb->dev = dev;
+                                       skb_reserve(skb, 2); /* 16byte align */
+                                       memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->tail, rxlen);
+                                       uli526x_reuse_skb(db, rxptr->rx_skb_ptr);
+                               } else {
+                                       skb->dev = dev;
+                                       skb_put(skb, rxlen);
+                               }
+                               skb->protocol = eth_type_trans(skb, dev);
+                               netif_rx(skb);
+                               dev->last_rx = jiffies;
+                               db->stats.rx_packets++;
+                               db->stats.rx_bytes += rxlen;
+                               
+                       } else {
+                               /* Reuse SKB buffer when the packet is error */
+                               ULI526X_DBUG(0, "Reuse SK buffer, rdes0", rdes0);
+                               uli526x_reuse_skb(db, rxptr->rx_skb_ptr);
+                       }
+               }
+
+               rxptr = rxptr->next_rx_desc;
+       }
+
+       db->rx_ready_ptr = rxptr;
+}
+
+
+/*
+ *     Get statistics from driver.
+ */
+
+static struct net_device_stats * uli526x_get_stats(struct net_device *dev)
+{
+       struct uli526x_board_info *db = netdev_priv(dev);
+
+       ULI526X_DBUG(0, "uli526x_get_stats", 0);
+       return &db->stats;
+}
+
+
+/*
+ * Set ULI526X multicast address
+ */
+
+static void uli526x_set_filter_mode(struct net_device * dev)
+{
+       struct uli526x_board_info *db = dev->priv;
+       unsigned long flags;
+
+       ULI526X_DBUG(0, "uli526x_set_filter_mode()", 0);
+       spin_lock_irqsave(&db->lock, flags);
+
+       if (dev->flags & IFF_PROMISC) {
+               ULI526X_DBUG(0, "Enable PROM Mode", 0);
+               db->cr6_data |= CR6_PM | CR6_PBF;
+               update_cr6(db->cr6_data, db->ioaddr);
+               spin_unlock_irqrestore(&db->lock, flags);
+               return;
+       }
+
+       if (dev->flags & IFF_ALLMULTI || dev->mc_count > ULI5261_MAX_MULTICAST) {
+               ULI526X_DBUG(0, "Pass all multicast address", dev->mc_count);
+               db->cr6_data &= ~(CR6_PM | CR6_PBF);
+               db->cr6_data |= CR6_PAM;
+               spin_unlock_irqrestore(&db->lock, flags);
+               return;
+       }
+
+       ULI526X_DBUG(0, "Set multicast address", dev->mc_count);
+       send_filter_frame(dev, dev->mc_count);  /* M5261/M5263 */
+       spin_unlock_irqrestore(&db->lock, flags);
+}
+
+static void
+ULi_ethtool_gset(struct uli526x_board_info *db, struct ethtool_cmd *ecmd)
+{
+       ecmd->supported = (SUPPORTED_10baseT_Half |
+                          SUPPORTED_10baseT_Full |
+                          SUPPORTED_100baseT_Half |
+                          SUPPORTED_100baseT_Full |
+                          SUPPORTED_Autoneg |
+                          SUPPORTED_MII);
+               
+       ecmd->advertising = (ADVERTISED_10baseT_Half |
+                          ADVERTISED_10baseT_Full |
+                          ADVERTISED_100baseT_Half |
+                          ADVERTISED_100baseT_Full |
+                          ADVERTISED_Autoneg |
+                          ADVERTISED_MII);
+
+
+       ecmd->port = PORT_MII;
+       ecmd->phy_address = db->phy_addr;
+
+       ecmd->transceiver = XCVR_EXTERNAL;
+               
+       ecmd->speed = 10;
+       ecmd->duplex = DUPLEX_HALF;
+       
+       if(db->op_mode==ULI526X_100MHF || db->op_mode==ULI526X_100MFD)
+       {
+               ecmd->speed = 100;               
+       }
+       if(db->op_mode==ULI526X_10MFD || db->op_mode==ULI526X_100MFD)
+       {
+               ecmd->duplex = DUPLEX_FULL;
+       }
+       if(db->link_failed)
+       {
+               ecmd->speed = -1;
+               ecmd->duplex = -1;      
+       }
+       
+       if (db->media_mode & ULI526X_AUTO)
+       {       
+               ecmd->autoneg = AUTONEG_ENABLE;
+       }
+}
+
+static void netdev_get_drvinfo(struct net_device *dev,
+                              struct ethtool_drvinfo *info)
+{
+       struct uli526x_board_info *np = netdev_priv(dev);
+
+       strcpy(info->driver, DRV_NAME);
+       strcpy(info->version, DRV_VERSION);
+       if (np->pdev)
+               strcpy(info->bus_info, pci_name(np->pdev));
+       else
+               sprintf(info->bus_info, "EISA 0x%lx %d",
+                       dev->base_addr, dev->irq);
+}
+
+static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) {
+       struct uli526x_board_info *np = netdev_priv(dev);
+       
+       ULi_ethtool_gset(np, cmd);
+       
+       return 0;
+}
+
+static u32 netdev_get_link(struct net_device *dev) {
+       struct uli526x_board_info *np = netdev_priv(dev);
+               
+       if(np->link_failed)
+               return 0;
+       else
+               return 1;
+}
+
+static void uli526x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+       wol->supported = WAKE_PHY | WAKE_MAGIC;
+       wol->wolopts = 0;
+}
+
+static struct ethtool_ops netdev_ethtool_ops = {
+       .get_drvinfo            = netdev_get_drvinfo,
+       .get_settings           = netdev_get_settings,
+       .get_link               = netdev_get_link,
+       .get_wol                = uli526x_get_wol,
+};
+
+/*
+ *     A periodic timer routine
+ *     Dynamic media sense, allocate Rx buffer...
+ */
+
+static void uli526x_timer(unsigned long data)
+{
+       u32 tmp_cr8;
+       unsigned char tmp_cr12=0;
+       struct net_device *dev = (struct net_device *) data;
+       struct uli526x_board_info *db = netdev_priv(dev);
+       unsigned long flags;
+       u8 TmpSpeed=10;
+       
+       //ULI526X_DBUG(0, "uli526x_timer()", 0);
+       spin_lock_irqsave(&db->lock, flags);
+
+       
+       /* Dynamic reset ULI526X : system error or transmit time-out */
+       tmp_cr8 = inl(db->ioaddr + DCR8);
+       if ( (db->interval_rx_cnt==0) && (tmp_cr8) ) {
+               db->reset_cr8++;
+               db->wait_reset = 1;
+       }
+       db->interval_rx_cnt = 0;
+
+       /* TX polling kick monitor */
+       if ( db->tx_packet_cnt &&
+            time_after(jiffies, dev->trans_start + ULI526X_TX_KICK) ) {
+               outl(0x1, dev->base_addr + DCR1);   // Tx polling again 
+
+               // TX Timeout 
+               if ( time_after(jiffies, dev->trans_start + ULI526X_TX_TIMEOUT) ) {
+                       db->reset_TXtimeout++;
+                       db->wait_reset = 1;
+                       printk( "%s: Tx timeout - resetting\n",
+                              dev->name);
+               }
+       }
+
+       if (db->wait_reset) {
+               ULI526X_DBUG(0, "Dynamic Reset device", db->tx_packet_cnt);
+               db->reset_count++;
+               uli526x_dynamic_reset(dev);
+               db->timer.expires = ULI526X_TIMER_WUT;
+               add_timer(&db->timer);
+               spin_unlock_irqrestore(&db->lock, flags);
+               return;
+       }
+
+       /* Link status check, Dynamic media type change */
+       if((phy_read(db->ioaddr, db->phy_addr, 5, db->chip_id) & 0x01e0)!=0)
+               tmp_cr12 = 3;
+
+       if ( !(tmp_cr12 & 0x3) && !db->link_failed ) {
+               /* Link Failed */
+               ULI526X_DBUG(0, "Link Failed", tmp_cr12);
+               netif_carrier_off(dev);
+               printk(KERN_INFO "uli526x: %s NIC Link is Down\n",dev->name);
+               db->link_failed = 1;
+
+               /* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */
+               /* AUTO don't need */
+               if ( !(db->media_mode & 0x8) )
+                       phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
+
+               /* AUTO mode, if INT phyxcer link failed, select EXT device */
+               if (db->media_mode & ULI526X_AUTO) {
+                       db->cr6_data&=~0x00000200;      /* bit9=0, HD mode */
+                       update_cr6(db->cr6_data, db->ioaddr);
+               }
+       } else
+               if ((tmp_cr12 & 0x3) && db->link_failed) {
+                       ULI526X_DBUG(0, "Link link OK", tmp_cr12);
+                       db->link_failed = 0;
+
+                       /* Auto Sense Speed */
+                       if ( (db->media_mode & ULI526X_AUTO) &&
+                               uli526x_sense_speed(db) )
+                               db->link_failed = 1;
+                       uli526x_process_mode(db);
+                       
+                       if(db->link_failed==0)
+                       {
+                               if(db->op_mode==ULI526X_100MHF || db->op_mode==ULI526X_100MFD)
+                               {
+                                       TmpSpeed = 100;
+                               }
+                               if(db->op_mode==ULI526X_10MFD || db->op_mode==ULI526X_100MFD)
+                               {
+                                       printk(KERN_INFO "uli526x: %s NIC Link is Up %d Mbps Full duplex\n",dev->name,TmpSpeed);
+                               }
+                               else
+                               {
+                                       printk(KERN_INFO "uli526x: %s NIC Link is Up %d Mbps Half duplex\n",dev->name,TmpSpeed);
+                               }
+                               netif_carrier_on(dev);
+                       }
+                       /* SHOW_MEDIA_TYPE(db->op_mode); */
+               }
+               else if(!(tmp_cr12 & 0x3) && db->link_failed)
+               {
+                       if(db->init==1)
+                       {
+                               printk(KERN_INFO "uli526x: %s NIC Link is Down\n",dev->name);
+                               netif_carrier_off(dev);
+                       }
+               }
+               db->init=0;
+
+       /* Timer active again */
+       db->timer.expires = ULI526X_TIMER_WUT;
+       add_timer(&db->timer);
+       spin_unlock_irqrestore(&db->lock, flags);
+}
+
+
+/*
+ *     Dynamic reset the ULI526X board
+ *     Stop ULI526X board
+ *     Free Tx/Rx allocated memory
+ *     Reset ULI526X board
+ *     Re-initialize ULI526X board
+ */
+
+static void uli526x_dynamic_reset(struct net_device *dev)
+{
+       struct uli526x_board_info *db = netdev_priv(dev);
+
+       ULI526X_DBUG(0, "uli526x_dynamic_reset()", 0);
+
+       /* Sopt MAC controller */
+       db->cr6_data &= ~(CR6_RXSC | CR6_TXSC); /* Disable Tx/Rx */
+       update_cr6(db->cr6_data, dev->base_addr);
+       outl(0, dev->base_addr + DCR7);         /* Disable Interrupt */
+       outl(inl(dev->base_addr + DCR5), dev->base_addr + DCR5);
+
+       /* Disable upper layer interface */
+       netif_stop_queue(dev);
+
+       /* Free Rx Allocate buffer */
+       uli526x_free_rxbuffer(db);
+
+       /* system variable init */
+       db->tx_packet_cnt = 0;
+       db->rx_avail_cnt = 0;
+       db->link_failed = 1;
+       db->init=1;
+       db->wait_reset = 0;
+
+       /* Re-initialize ULI526X board */
+       uli526x_init(dev);
+
+       /* Restart upper layer interface */
+       netif_wake_queue(dev);
+}
+
+
+/*
+ *     free all allocated rx buffer
+ */
+
+static void uli526x_free_rxbuffer(struct uli526x_board_info * db)
+{
+       ULI526X_DBUG(0, "uli526x_free_rxbuffer()", 0);
+
+       /* free allocated rx buffer */
+       while (db->rx_avail_cnt) {
+               dev_kfree_skb(db->rx_ready_ptr->rx_skb_ptr);
+               db->rx_ready_ptr = db->rx_ready_ptr->next_rx_desc;
+               db->rx_avail_cnt--;
+       }
+}
+
+
+/*
+ *     Reuse the SK buffer
+ */
+
+static void uli526x_reuse_skb(struct uli526x_board_info *db, struct sk_buff * skb)
+{
+       struct rx_desc *rxptr = db->rx_insert_ptr;
+
+       if (!(rxptr->rdes0 & cpu_to_le32(0x80000000))) {
+               rxptr->rx_skb_ptr = skb;
+               rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
+               wmb();
+               rxptr->rdes0 = cpu_to_le32(0x80000000);
+               db->rx_avail_cnt++;
+               db->rx_insert_ptr = rxptr->next_rx_desc;
+       } else
+               ULI526X_DBUG(0, "SK Buffer reuse method error", db->rx_avail_cnt);
+}
+
+
+/*
+ *     Initialize transmit/Receive descriptor
+ *     Using Chain structure, and allocate Tx/Rx buffer
+ */
+
+static void uli526x_descriptor_init(struct uli526x_board_info *db, unsigned long ioaddr)
+{
+       struct tx_desc *tmp_tx;
+       struct rx_desc *tmp_rx;
+       unsigned char *tmp_buf;
+       dma_addr_t tmp_tx_dma, tmp_rx_dma;
+       dma_addr_t tmp_buf_dma;
+       int i;
+
+       ULI526X_DBUG(0, "uli526x_descriptor_init()", 0);
+
+       /* tx descriptor start pointer */
+       db->tx_insert_ptr = db->first_tx_desc;
+       db->tx_remove_ptr = db->first_tx_desc;
+       outl(db->first_tx_desc_dma, ioaddr + DCR4);     /* TX DESC address */
+
+       /* rx descriptor start pointer */
+       db->first_rx_desc = (void *)db->first_tx_desc + sizeof(struct tx_desc) * TX_DESC_CNT;
+       db->first_rx_desc_dma =  db->first_tx_desc_dma + sizeof(struct tx_desc) * TX_DESC_CNT;
+       db->rx_insert_ptr = db->first_rx_desc;
+       db->rx_ready_ptr = db->first_rx_desc;
+       outl(db->first_rx_desc_dma, ioaddr + DCR3);     /* RX DESC address */
+
+       /* Init Transmit chain */
+       tmp_buf = db->buf_pool_start;
+       tmp_buf_dma = db->buf_pool_dma_start;
+       tmp_tx_dma = db->first_tx_desc_dma;
+       for (tmp_tx = db->first_tx_desc, i = 0; i < TX_DESC_CNT; i++, tmp_tx++) {
+               tmp_tx->tx_buf_ptr = tmp_buf;
+               tmp_tx->tdes0 = cpu_to_le32(0);
+               tmp_tx->tdes1 = cpu_to_le32(0x81000000);        /* IC, chain */
+               tmp_tx->tdes2 = cpu_to_le32(tmp_buf_dma);
+               tmp_tx_dma += sizeof(struct tx_desc);
+               tmp_tx->tdes3 = cpu_to_le32(tmp_tx_dma);
+               tmp_tx->next_tx_desc = tmp_tx + 1;
+               tmp_buf = tmp_buf + TX_BUF_ALLOC;
+               tmp_buf_dma = tmp_buf_dma + TX_BUF_ALLOC;
+       }
+       (--tmp_tx)->tdes3 = cpu_to_le32(db->first_tx_desc_dma);
+       tmp_tx->next_tx_desc = db->first_tx_desc;
+
+        /* Init Receive descriptor chain */
+       tmp_rx_dma=db->first_rx_desc_dma;
+       for (tmp_rx = db->first_rx_desc, i = 0; i < RX_DESC_CNT; i++, tmp_rx++) {
+               tmp_rx->rdes0 = cpu_to_le32(0);
+               tmp_rx->rdes1 = cpu_to_le32(0x01000600);
+               tmp_rx_dma += sizeof(struct rx_desc);
+               tmp_rx->rdes3 = cpu_to_le32(tmp_rx_dma);
+               tmp_rx->next_rx_desc = tmp_rx + 1;
+       }
+       (--tmp_rx)->rdes3 = cpu_to_le32(db->first_rx_desc_dma);
+       tmp_rx->next_rx_desc = db->first_rx_desc;
+
+       /* pre-allocate Rx buffer */
+       allocate_rx_buffer(db);
+}
+
+
+/*
+ *     Update CR6 value
+ *     Firstly stop ULI526X, then written value and start
+ */
+
+static void update_cr6(u32 cr6_data, unsigned long ioaddr)
+{
+
+       outl(cr6_data, ioaddr + DCR6);
+       udelay(5);
+}
+
+
+/*
+ *     Send a setup frame for M5261/M5263
+ *     This setup frame initialize ULI526X address filter mode
+ */
+
+static void send_filter_frame(struct net_device *dev, int mc_cnt)
+{
+       struct uli526x_board_info *db = netdev_priv(dev);
+       struct dev_mc_list *mcptr;
+       struct tx_desc *txptr;
+       u16 * addrptr;
+       u32 * suptr;
+       int i;
+
+       ULI526X_DBUG(0, "send_filter_frame()", 0);
+
+       txptr = db->tx_insert_ptr;
+       suptr = (u32 *) txptr->tx_buf_ptr;
+
+       /* Node address */
+       addrptr = (u16 *) dev->dev_addr;
+       *suptr++ = addrptr[0];
+       *suptr++ = addrptr[1];
+       *suptr++ = addrptr[2];
+
+       /* broadcast address */
+       *suptr++ = 0xffff;
+       *suptr++ = 0xffff;
+       *suptr++ = 0xffff;
+
+       /* fit the multicast address */
+       for (mcptr = dev->mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
+               addrptr = (u16 *) mcptr->dmi_addr;
+               *suptr++ = addrptr[0];
+               *suptr++ = addrptr[1];
+               *suptr++ = addrptr[2];
+       }
+
+       for (; i<14; i++) {
+               *suptr++ = 0xffff;
+               *suptr++ = 0xffff;
+               *suptr++ = 0xffff;
+       }
+
+       /* prepare the setup frame */
+       db->tx_insert_ptr = txptr->next_tx_desc;
+       txptr->tdes1 = cpu_to_le32(0x890000c0);
+
+       /* Resource Check and Send the setup packet */
+       if (db->tx_packet_cnt < TX_DESC_CNT) {
+               /* Resource Empty */
+               db->tx_packet_cnt++;
+               txptr->tdes0 = cpu_to_le32(0x80000000);
+               update_cr6(db->cr6_data | 0x2000, dev->base_addr);
+               outl(0x1, dev->base_addr + DCR1);       /* Issue Tx polling */
+               update_cr6(db->cr6_data, dev->base_addr);
+               dev->trans_start = jiffies;
+       } else
+               printk(KERN_ERR DRV_NAME ": No Tx resource - Send_filter_frame!\n");
+}
+
+
+/*
+ *     Allocate rx buffer,
+ *     As possible as allocate maxiumn Rx buffer
+ */
+
+static void allocate_rx_buffer(struct uli526x_board_info *db)
+{
+       struct rx_desc *rxptr;
+       struct sk_buff *skb;
+
+       rxptr = db->rx_insert_ptr;
+
+       while(db->rx_avail_cnt < RX_DESC_CNT) {
+               if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL )
+                       break;
+               rxptr->rx_skb_ptr = skb; /* FIXME (?) */
+               rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
+               wmb();
+               rxptr->rdes0 = cpu_to_le32(0x80000000);
+               rxptr = rxptr->next_rx_desc;
+               db->rx_avail_cnt++;
+       }
+
+       db->rx_insert_ptr = rxptr;
+}
+
+
+/*
+ *     Read one word data from the serial ROM
+ */
+
+static u16 read_srom_word(long ioaddr, int offset)
+{
+       int i;
+       u16 srom_data = 0;
+       long cr9_ioaddr = ioaddr + DCR9;
+
+       outl(CR9_SROM_READ, cr9_ioaddr);
+       outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
+
+       /* Send the Read Command 110b */
+       SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);
+       SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);
+       SROM_CLK_WRITE(SROM_DATA_0, cr9_ioaddr);
+
+       /* Send the offset */
+       for (i = 5; i >= 0; i--) {
+               srom_data = (offset & (1 << i)) ? SROM_DATA_1 : SROM_DATA_0;
+               SROM_CLK_WRITE(srom_data, cr9_ioaddr);
+       }
+
+       outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
+
+       for (i = 16; i > 0; i--) {
+               outl(CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, cr9_ioaddr);
+               udelay(5);
+               srom_data = (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT) ? 1 : 0);
+               outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
+               udelay(5);
+       }
+
+       outl(CR9_SROM_READ, cr9_ioaddr);
+       return srom_data;
+}
+
+
+/*
+ *     Auto sense the media mode
+ */
+
+static u8 uli526x_sense_speed(struct uli526x_board_info * db)
+{
+       u8 ErrFlag = 0;
+       u16 phy_mode;
+
+       phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
+       phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
+
+       if ( (phy_mode & 0x24) == 0x24 ) {
+               
+               phy_mode = ((phy_read(db->ioaddr, db->phy_addr, 5, db->chip_id) & 0x01e0)<<7);
+               if(phy_mode&0x8000)
+                       phy_mode = 0x8000;
+               else if(phy_mode&0x4000)
+                       phy_mode = 0x4000;
+               else if(phy_mode&0x2000)
+                       phy_mode = 0x2000;
+               else
+                       phy_mode = 0x1000;
+               
+               /* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */
+               switch (phy_mode) {
+               case 0x1000: db->op_mode = ULI526X_10MHF; break;
+               case 0x2000: db->op_mode = ULI526X_10MFD; break;
+               case 0x4000: db->op_mode = ULI526X_100MHF; break;
+               case 0x8000: db->op_mode = ULI526X_100MFD; break;
+               default: db->op_mode = ULI526X_10MHF; ErrFlag = 1; break;
+               }
+       } else {
+               db->op_mode = ULI526X_10MHF;
+               ULI526X_DBUG(0, "Link Failed :", phy_mode);
+               ErrFlag = 1;
+       }
+
+       return ErrFlag;
+}
+
+
+/*
+ *     Set 10/100 phyxcer capability
+ *     AUTO mode : phyxcer register4 is NIC capability
+ *     Force mode: phyxcer register4 is the force media
+ */
+
+static void uli526x_set_phyxcer(struct uli526x_board_info *db)
+{
+       u16 phy_reg;
+       
+       /* Phyxcer capability setting */
+       phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0;
+
+       if (db->media_mode & ULI526X_AUTO) {
+               /* AUTO Mode */
+               phy_reg |= db->PHY_reg4;
+       } else {
+               /* Force Mode */
+               switch(db->media_mode) {
+               case ULI526X_10MHF: phy_reg |= 0x20; break;
+               case ULI526X_10MFD: phy_reg |= 0x40; break;
+               case ULI526X_100MHF: phy_reg |= 0x80; break;
+               case ULI526X_100MFD: phy_reg |= 0x100; break;
+               }
+               
+       }
+
+       /* Write new capability to Phyxcer Reg4 */
+       if ( !(phy_reg & 0x01e0)) {
+               phy_reg|=db->PHY_reg4;
+               db->media_mode|=ULI526X_AUTO;
+       }
+       phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
+
+       /* Restart Auto-Negotiation */
+       phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id);
+       udelay(50);
+}
+
+
+/*
+ *     Process op-mode
+       AUTO mode : PHY controller in Auto-negotiation Mode
+ *     Force mode: PHY controller in force mode with HUB
+ *                     N-way force capability with SWITCH
+ */
+
+static void uli526x_process_mode(struct uli526x_board_info *db)
+{
+       u16 phy_reg;
+
+       /* Full Duplex Mode Check */
+       if (db->op_mode & 0x4)
+               db->cr6_data |= CR6_FDM;        /* Set Full Duplex Bit */
+       else
+               db->cr6_data &= ~CR6_FDM;       /* Clear Full Duplex Bit */
+
+       update_cr6(db->cr6_data, db->ioaddr);
+
+       /* 10/100M phyxcer force mode need */
+       if ( !(db->media_mode & 0x8)) {
+               /* Forece Mode */
+               phy_reg = phy_read(db->ioaddr, db->phy_addr, 6, db->chip_id);
+               if ( !(phy_reg & 0x1) ) {
+                       /* parter without N-Way capability */
+                       phy_reg = 0x0;
+                       switch(db->op_mode) {
+                       case ULI526X_10MHF: phy_reg = 0x0; break;
+                       case ULI526X_10MFD: phy_reg = 0x100; break;
+                       case ULI526X_100MHF: phy_reg = 0x2000; break;
+                       case ULI526X_100MFD: phy_reg = 0x2100; break;
+                       }
+                       phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
+                               phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
+               }
+       }
+}
+
+
+/*
+ *     Write a word to Phy register
+ */
+
+static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id)
+{
+       u16 i;
+       unsigned long ioaddr;
+
+       if(chip_id == PCI_ULI5263_ID)
+       {
+               phy_writeby_cr10(iobase, phy_addr, offset, phy_data);
+               return;
+       }
+       /* M5261/M5263 Chip */
+       ioaddr = iobase + DCR9;
+
+       /* Send 33 synchronization clock to Phy controller */
+       for (i = 0; i < 35; i++)
+               phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+
+       /* Send start command(01) to Phy */
+       phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
+       phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+
+       /* Send write command(01) to Phy */
+       phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
+       phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+
+       /* Send Phy address */
+       for (i = 0x10; i > 0; i = i >> 1)
+               phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0, chip_id);
+
+       /* Send register address */
+       for (i = 0x10; i > 0; i = i >> 1)
+               phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0, chip_id);
+
+       /* written trasnition */
+       phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+       phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
+
+       /* Write a word data to PHY controller */
+       for ( i = 0x8000; i > 0; i >>= 1)
+               phy_write_1bit(ioaddr, phy_data & i ? PHY_DATA_1 : PHY_DATA_0, chip_id);
+       
+}
+
+
+/*
+ *     Read a word data from phy register
+ */
+
+static u16 phy_read(unsigned long iobase, u8 phy_addr, u8 offset, u32 chip_id)
+{
+       int i;
+       u16 phy_data;
+       unsigned long ioaddr;
+
+       if(chip_id == PCI_ULI5263_ID)
+               return phy_readby_cr10(iobase, phy_addr, offset);
+       /* M5261/M5263 Chip */
+       ioaddr = iobase + DCR9;
+       
+       /* Send 33 synchronization clock to Phy controller */
+       for (i = 0; i < 35; i++)
+               phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+
+       /* Send start command(01) to Phy */
+       phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
+       phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+
+       /* Send read command(10) to Phy */
+       phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+       phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
+
+       /* Send Phy address */
+       for (i = 0x10; i > 0; i = i >> 1)
+               phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0, chip_id);
+
+       /* Send register address */
+       for (i = 0x10; i > 0; i = i >> 1)
+               phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0, chip_id);
+
+       /* Skip transition state */
+       phy_read_1bit(ioaddr, chip_id);
+
+       /* read 16bit data */
+       for (phy_data = 0, i = 0; i < 16; i++) {
+               phy_data <<= 1;
+               phy_data |= phy_read_1bit(ioaddr, chip_id);
+       }
+
+       return phy_data;
+}
+
+static u16 phy_readby_cr10(unsigned long iobase, u8 phy_addr, u8 offset)
+{
+       unsigned long ioaddr,cr10_value;
+       
+       ioaddr = iobase + DCR10;
+       cr10_value = phy_addr;
+       cr10_value = (cr10_value<<5) + offset;
+       cr10_value = (cr10_value<<16) + 0x08000000;
+       outl(cr10_value,ioaddr);
+       udelay(1);
+       while(1)
+       {
+               cr10_value = inl(ioaddr);
+               if(cr10_value&0x10000000)
+                       break;
+       }
+       return (cr10_value&0x0ffff);
+}
+
+static void phy_writeby_cr10(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data)
+{
+       unsigned long ioaddr,cr10_value;
+       
+       ioaddr = iobase + DCR10;
+       cr10_value = phy_addr;
+       cr10_value = (cr10_value<<5) + offset;
+       cr10_value = (cr10_value<<16) + 0x04000000 + phy_data;
+       outl(cr10_value,ioaddr);
+       udelay(1);
+}
+/*
+ *     Write one bit data to Phy Controller
+ */
+
+static void phy_write_1bit(unsigned long ioaddr, u32 phy_data, u32 chip_id)
+{
+       outl(phy_data , ioaddr);                        /* MII Clock Low */
+       udelay(1);
+       outl(phy_data  | MDCLKH, ioaddr);       /* MII Clock High */
+       udelay(1);
+       outl(phy_data , ioaddr);                        /* MII Clock Low */
+       udelay(1);
+}
+
+
+/*
+ *     Read one bit phy data from PHY controller
+ */
+
+static u16 phy_read_1bit(unsigned long ioaddr, u32 chip_id)
+{
+       u16 phy_data;
+       
+       outl(0x50000 , ioaddr);
+       udelay(1);
+       phy_data = ( inl(ioaddr) >> 19 ) & 0x1;
+       outl(0x40000 , ioaddr);
+       udelay(1);
+
+       return phy_data;
+}
+
+
+static struct pci_device_id uli526x_pci_tbl[] = {
+       { 0x10B9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ULI5261_ID },
+       { 0x10B9, 0x5263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ULI5263_ID },
+       { 0, }
+};
+MODULE_DEVICE_TABLE(pci, uli526x_pci_tbl);
+
+
+static struct pci_driver uli526x_driver = {
+       .name           = "uli526x",
+       .id_table       = uli526x_pci_tbl,
+       .probe          = uli526x_init_one,
+       .remove         = __devexit_p(uli526x_remove_one),
+};
+
+MODULE_AUTHOR("Peer Chen, peer.chen@uli.com.tw");
+MODULE_DESCRIPTION("ULi M5261/M5263 fast ethernet driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM(mode, "i");
+MODULE_PARM(cr6set, "i");
+MODULE_PARM_DESC(debug, "ULi M5261/M5263 enable debugging (0-1)");
+MODULE_PARM_DESC(mode, "ULi M5261/M5263: Bit 0: 10/100Mbps, bit 2: duplex, bit 8: HomePNA");
+
+/*     Description:
+ *     when user used insmod to add module, system invoked init_module()
+ *     to register the services.
+ */
+
+static int __init uli526x_init_module(void)
+{
+       int rc;
+
+       printk(version);
+       printed_version = 1;
+
+       ULI526X_DBUG(0, "init_module() ", debug);
+
+       if (debug)
+               uli526x_debug = debug;  /* set debug flag */
+       if (cr6set)
+               uli526x_cr6_user_set = cr6set;
+
+       switch(mode) {
+       case ULI526X_10MHF:
+       case ULI526X_100MHF:
+       case ULI526X_10MFD:
+       case ULI526X_100MFD:
+               uli526x_media_mode = mode;
+               break;
+       default:uli526x_media_mode = ULI526X_AUTO;
+               break;
+       }
+
+       rc = pci_module_init(&uli526x_driver);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+
+/*
+ *     Description:
+ *     when user used rmmod to delete module, system invoked clean_module()
+ *     to un-register all registered services.
+ */
+
+static void __exit uli526x_cleanup_module(void)
+{
+       ULI526X_DBUG(0, "uli526x_clean_module() ", debug);
+       pci_unregister_driver(&uli526x_driver);
+}
+
+module_init(uli526x_init_module);
+module_exit(uli526x_cleanup_module);
index effab0b9adca176b6b6a3b9fd553b256d9f1c850..50b8c6754b1ef333a225406a7465e9fdd2985dd6 100644 (file)
@@ -18,6 +18,9 @@
 /*
  *  Changes:
  *
+ *  Mike Kershaw <dragorn@kismetwireless.net> 2005/08/14
+ *    Add TUNSETLINK ioctl to set the link encapsulation
+ *
  *  Mark Smith <markzzzsmith@yahoo.com.au>
  *   Use random_ether_addr() for tap MAC address.
  *
@@ -612,6 +615,18 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file,
                DBG(KERN_INFO "%s: owner set to %d\n", tun->dev->name, tun->owner);
                break;
 
+       case TUNSETLINK:
+               /* Only allow setting the type when the interface is down */
+               if (tun->dev->flags & IFF_UP) {
+                       DBG(KERN_INFO "%s: Linktype set failed because interface is up\n",
+                               tun->dev->name);
+                       return -EBUSY;
+               } else {
+                       tun->dev->type = (int) arg;
+                       DBG(KERN_INFO "%s: linktype set to %d\n", tun->dev->name, tun->dev->type);
+               }
+               break;
+
 #ifdef TUN_DEBUG
        case TUNSETDEBUG:
                tun->debug = arg;
index 6e74af62ca08c73cd53f27e4d73945a4ee1387ad..9e56fc346ba4f72b53e0031167803165bf0dde1d 100644 (file)
@@ -56,7 +56,7 @@
 #include <linux/sched.h>       /* for jiffies, HZ, etc. */
 #include <linux/cycx_drv.h>    /* API definitions */
 #include <linux/cycx_cfm.h>    /* CYCX firmware module definitions */
-#include <linux/delay.h>       /* udelay */
+#include <linux/delay.h>       /* udelay, msleep_interruptible */
 #include <asm/io.h>            /* read[wl], write[wl], ioremap, iounmap */
 
 #define        MOD_VERSION     0
@@ -74,7 +74,6 @@ static int reset_cyc2x(void __iomem *addr);
 static int detect_cyc2x(void __iomem *addr);
 
 /* Miscellaneous functions */
-static void delay_cycx(int sec);
 static int get_option_index(long *optlist, long optval);
 static u16 checksum(u8 *buf, u32 len);
 
@@ -259,7 +258,7 @@ static int memory_exists(void __iomem *addr)
                        if (readw(addr + 0x10) == TEST_PATTERN)
                                return 1;
 
-               delay_cycx(1);
+               msleep_interruptible(1 * 1000);
        }
 
        return 0;
@@ -316,7 +315,7 @@ static void cycx_reset_boot(void __iomem *addr, u8 *code, u32 len)
 
        /* 80186 was in hold, go */
        writeb(0, addr + START_CPU);
-       delay_cycx(1);
+       msleep_interruptible(1 * 1000);
 }
 
 /* Load data.bin file through boot (reset) interface. */
@@ -462,13 +461,13 @@ static int load_cyc2x(struct cycx_hw *hw, struct cycx_firmware *cfm, u32 len)
                cycx_reset_boot(hw->dpmbase, reset_image, img_hdr->reset_size);
                /* reset is waiting for boot */
                writew(GEN_POWER_ON, pt_cycld);
-               delay_cycx(1);
+               msleep_interruptible(1 * 1000);
 
                for (j = 0 ; j < 3 ; j++)
                        if (!readw(pt_cycld))
                                goto reset_loaded;
                        else
-                               delay_cycx(1);
+                               msleep_interruptible(1 * 1000);
        }
 
        printk(KERN_ERR "%s: reset not started.\n", modname);
@@ -495,7 +494,7 @@ reset_loaded:
 
        /* Arthur Ganzert's tip: wait a while after the firmware loading...
           seg abr 26 17:17:12 EST 1999 - acme */
-       delay_cycx(7);
+       msleep_interruptible(7 * 1000);
        printk(KERN_INFO "%s: firmware loaded!\n", modname);
 
        /* enable interrupts */
@@ -547,20 +546,13 @@ static int get_option_index(long *optlist, long optval)
 static int reset_cyc2x(void __iomem *addr)
 {
        writeb(0, addr + RST_ENABLE);
-       delay_cycx(2);
+       msleep_interruptible(2 * 1000);
        writeb(0, addr + RST_DISABLE);
-       delay_cycx(2);
+       msleep_interruptible(2 * 1000);
 
        return memory_exists(addr);
 }
 
-/* Delay */
-static void delay_cycx(int sec)
-{
-       set_current_state(TASK_INTERRUPTIBLE);
-       schedule_timeout(sec * HZ);
-}
-
 /* Calculate 16-bit CRC using CCITT polynomial. */
 static u16 checksum(u8 *buf, u32 len)
 {
index a63f6a2cc4f7d75746a8ba3869c7a62d649fad91..cdd4c09c2d90355adee28e09d42f560ab42d040f 100644 (file)
@@ -61,7 +61,7 @@ static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
 
 
 static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
-                   struct packet_type *p)
+                   struct packet_type *p, struct net_device *orig_dev)
 {
        hdlc_device *hdlc = dev_to_hdlc(dev);
        if (hdlc->proto.netif_rx)
index 7f2e3653c5e5b5dcfad4da1c4642786b9486f593..6c302e9dbca2e2ee2aeabf570e0c37cca193c88b 100644 (file)
@@ -86,7 +86,7 @@ static __inline__ int dev_is_ethdev(struct net_device *dev)
 /*
  *     Receive a LAPB frame via an ethernet interface.
  */
-static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype)
+static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev)
 {
        int len, err;
        struct lapbethdev *lapbeth;
index c5f5e62aab8b8c31814fea2fa900799db0c061c3..0497dbdb8631fe379c7f952dc2c50ee7c21bd814 100644 (file)
@@ -445,7 +445,7 @@ void        s508_s514_unlock(sdla_t *card, unsigned long *smp_flags);
 void   s508_s514_lock(sdla_t *card, unsigned long *smp_flags);
 
 unsigned short calc_checksum (char *, int);
-static int setup_fr_header(struct sk_buff** skb,
+static int setup_fr_header(struct sk_buff *skb,
                           struct net_device* dev, char op_mode);
 
 
@@ -1372,7 +1372,7 @@ static int if_send(struct sk_buff* skb, struct net_device* dev)
        /* Move the if_header() code to here. By inserting frame
         * relay header in if_header() we would break the
         * tcpdump and other packet sniffers */
-       chan->fr_header_len = setup_fr_header(&skb,dev,chan->common.usedby);
+       chan->fr_header_len = setup_fr_header(skb,dev,chan->common.usedby);
        if (chan->fr_header_len < 0 ){
                ++chan->ifstats.tx_dropped;
                ++card->wandev.stats.tx_dropped;
@@ -1597,8 +1597,6 @@ static int setup_for_delayed_transmit(struct net_device* dev,
                return 1;
        }
 
-       skb_unlink(skb);
-       
         chan->transmit_length = len;
        chan->delay_skb = skb;
         
@@ -4871,18 +4869,15 @@ static void unconfig_fr (sdla_t *card)
        }
 }
 
-static int setup_fr_header(struct sk_buff **skb_orig, struct net_device* dev,
+static int setup_fr_header(struct sk_buff *skb, struct net_device* dev,
                           char op_mode)
 {
-       struct sk_buff *skb = *skb_orig;
        fr_channel_t *chan=dev->priv;
 
-       if (op_mode == WANPIPE){
-
+       if (op_mode == WANPIPE) {
                chan->fr_header[0]=Q922_UI;
                
                switch (htons(skb->protocol)){
-                       
                case ETH_P_IP:
                        chan->fr_header[1]=NLPID_IP;
                        break;
@@ -4894,16 +4889,14 @@ static int setup_fr_header(struct sk_buff **skb_orig, struct net_device* dev,
        }
 
        /* If we are in bridging mode, we must apply
-        * an Ethernet header */
-       if (op_mode == BRIDGE || op_mode == BRIDGE_NODE){
-
-
+        * an Ethernet header
+        */
+       if (op_mode == BRIDGE || op_mode == BRIDGE_NODE) {
                /* Encapsulate the packet as a bridged Ethernet frame. */
 #ifdef DEBUG
                printk(KERN_INFO "%s: encapsulating skb for frame relay\n", 
                        dev->name);
 #endif
-               
                chan->fr_header[0] = 0x03;
                chan->fr_header[1] = 0x00;
                chan->fr_header[2] = 0x80;
@@ -4916,7 +4909,6 @@ static int setup_fr_header(struct sk_buff **skb_orig, struct net_device* dev,
                /* Yuck. */
                skb->protocol = ETH_P_802_3;
                return 8;
-
        }
                
        return 0;
index 84b65c60c799689bd772a5cd33939920dd4acebe..b56a7b516d2479a228598bb3a3651f333f9ac89c 100644 (file)
@@ -1440,6 +1440,7 @@ static void sppp_print_bytes (u_char *p, u16 len)
  *     @skb:   The buffer to process
  *     @dev:   The device it arrived on
  *     @p: Unused
+ *     @orig_dev: Unused
  *
  *     Protocol glue. This drives the deferred processing mode the poorer
  *     cards use. This can be called directly by cards that do not have
@@ -1447,7 +1448,7 @@ static void sppp_print_bytes (u_char *p, u16 len)
  *     after interrupt servicing to process frames queued via netif_rx.
  */
 
-static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p)
+static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev)
 {
        if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
                return NET_RX_DROP;
index ec3f75a030d2073248791d443d9f432027dd35bf..00a07f32a81e292c056a8a6bea9d973d747c4076 100644 (file)
@@ -137,6 +137,110 @@ config PCMCIA_RAYCS
 comment "Wireless 802.11b ISA/PCI cards support"
        depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA)
 
+config IPW2100
+       tristate "Intel PRO/Wireless 2100 Network Connection"
+       depends on NET_RADIO && PCI && IEEE80211
+       select FW_LOADER
+       ---help---
+          A driver for the Intel PRO/Wireless 2100 Network 
+         Connection 802.11b wireless network adapter.
+
+          See <file:Documentation/networking/README.ipw2100> for information on
+          the capabilities currently enabled in this driver and for tips
+          for debugging issues and problems.
+
+         In order to use this driver, you will need a firmware image for it.
+          You can obtain the firmware from
+         <http://ipw2100.sf.net/>.  Once you have the firmware image, you 
+         will need to place it in /etc/firmware.
+
+          You will also very likely need the Wireless Tools in order to
+          configure your card:
+
+          <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
+          If you want to compile the driver as a module ( = code which can be
+          inserted in and remvoed from the running kernel whenever you want),
+          say M here and read <file:Documentation/modules.txt>.  The module
+          will be called ipw2100.ko.
+       
+config IPW2100_MONITOR
+        bool "Enable promiscuous mode"
+        depends on IPW2100
+        ---help---
+         Enables promiscuous/monitor mode support for the ipw2100 driver.
+         With this feature compiled into the driver, you can switch to 
+         promiscuous mode via the Wireless Tool's Monitor mode.  While in this
+         mode, no packets can be sent.
+
+config IPW_DEBUG
+       bool "Enable full debugging output in IPW2100 module."
+       depends on IPW2100
+       ---help---
+         This option will enable debug tracing output for the IPW2100.  
+
+         This will result in the kernel module being ~60k larger.  You can 
+         control which debug output is sent to the kernel log by setting the 
+         value in 
+
+         /sys/bus/pci/drivers/ipw2100/debug_level
+
+         This entry will only exist if this option is enabled.
+
+         If you are not trying to debug or develop the IPW2100 driver, you 
+         most likely want to say N here.
+
+config IPW2200
+       tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
+       depends on IEEE80211 && PCI
+       select FW_LOADER
+       ---help---
+          A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network
+         Connection adapters. 
+
+          See <file:Documentation/networking/README.ipw2200> for 
+         information on the capabilities currently enabled in this 
+         driver and for tips for debugging issues and problems.
+
+         In order to use this driver, you will need a firmware image for it.
+          You can obtain the firmware from
+         <http://ipw2200.sf.net/>.  See the above referenced README.ipw2200 
+         for information on where to install the firmare images.
+
+          You will also very likely need the Wireless Tools in order to
+          configure your card:
+
+          <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
+          If you want to compile the driver as a module ( = code which can be
+          inserted in and remvoed from the running kernel whenever you want),
+          say M here and read <file:Documentation/modules.txt>.  The module
+          will be called ipw2200.ko.
+
+config IPW_DEBUG
+       bool "Enable full debugging output in IPW2200 module."
+       depends on IPW2200
+       ---help---
+         This option will enable debug tracing output for the IPW2200.  
+
+         This will result in the kernel module being ~100k larger.  You can 
+         control which debug output is sent to the kernel log by setting the 
+         value in 
+
+         /sys/bus/pci/drivers/ipw2200/debug_level
+
+         This entry will only exist if this option is enabled.
+
+         To set a value, simply echo an 8-byte hex value to the same file:
+
+         % echo 0x00000FFO > /sys/bus/pci/drivers/ipw2200/debug_level
+
+         You can find the list of debug mask values in 
+         drivers/net/wireless/ipw2200.h
+
+         If you are not trying to debug or develop the IPW2200 driver, you 
+         most likely want to say N here.
+
 config AIRO
        tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
        depends on NET_RADIO && ISA && (PCI || BROKEN)
@@ -185,8 +289,8 @@ config APPLE_AIRPORT
          a non-standard interface
 
 config PLX_HERMES
-       tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.) (EXPERIMENTAL)"
-       depends on PCI && HERMES && EXPERIMENTAL
+       tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)"
+       depends on PCI && HERMES
        help
          Enable support for PCMCIA cards supported by the "Hermes" (aka
          orinoco) driver when used in PLX9052 based PCI adaptors.  These
@@ -195,12 +299,9 @@ config PLX_HERMES
          802.11b PCMCIA cards can be used in desktop machines.  The Netgear
          MA301 is such an adaptor.
 
-         Support for these adaptors is so far still incomplete and buggy.
-         You have been warned.
-
 config TMD_HERMES
-       tristate "Hermes in TMD7160 based PCI adaptor support (EXPERIMENTAL)"
-       depends on PCI && HERMES && EXPERIMENTAL
+       tristate "Hermes in TMD7160 based PCI adaptor support"
+       depends on PCI && HERMES
        help
          Enable support for PCMCIA cards supported by the "Hermes" (aka
          orinoco) driver when used in TMD7160 based PCI adaptors.  These
@@ -208,12 +309,18 @@ config TMD_HERMES
          PCI <-> PCMCIA bridge.  Several vendors sell such adaptors so that
          802.11b PCMCIA cards can be used in desktop machines.
 
-         Support for these adaptors is so far still incomplete and buggy.
-         You have been warned.
+config NORTEL_HERMES
+       tristate "Nortel emobility PCI adaptor support"
+       depends on PCI && HERMES
+       help
+         Enable support for PCMCIA cards supported by the "Hermes" (aka
+         orinoco) driver when used in Nortel emobility PCI adaptors.  These
+         adaptors are not full PCMCIA controllers, but act as a more limited
+         PCI <-> PCMCIA bridge.
 
 config PCI_HERMES
-       tristate "Prism 2.5 PCI 802.11b adaptor support (EXPERIMENTAL)"
-       depends on PCI && HERMES && EXPERIMENTAL
+       tristate "Prism 2.5 PCI 802.11b adaptor support"
+       depends on PCI && HERMES
        help
          Enable support for PCI and mini-PCI 802.11b wireless NICs based on
          the Prism 2.5 chipset.  These are true PCI cards, not the 802.11b
@@ -268,6 +375,19 @@ config PCMCIA_HERMES
          configure your card and that /etc/pcmcia/wireless.opts works:
          <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
 
+config PCMCIA_SPECTRUM
+       tristate "Symbol Spectrum24 Trilogy PCMCIA card support"
+       depends on NET_RADIO && PCMCIA && HERMES
+       ---help---
+
+         This is a driver for 802.11b cards using RAM-loadable Symbol
+         firmware, such as Symbol Wireless Networker LA4100, CompactFlash
+         cards by Socket Communications and Intel PRO/Wireless 2011B.
+
+         This driver requires firmware download on startup.  Utilities
+         for downloading Symbol firmware are available at
+         <http://sourceforge.net/projects/orinoco/>
+
 config AIRO_CS
        tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards"
        depends on NET_RADIO && PCMCIA && (BROKEN || !M32R)
@@ -355,6 +475,8 @@ config PRISM54
          say M here and read <file:Documentation/modules.txt>.  The module
          will be called prism54.ko.
 
+source "drivers/net/wireless/hostap/Kconfig"
+
 # yes, this works even when no drivers are selected
 config NET_WIRELESS
        bool
index 2b87841322cc8f7d27fac0a36bdb063d204d7420..3a6f7ba326cab35fb735f407b79e31a97bcc2ac4 100644 (file)
@@ -2,6 +2,10 @@
 # Makefile for the Linux Wireless network device drivers.
 #
 
+obj-$(CONFIG_IPW2100) += ipw2100.o
+
+obj-$(CONFIG_IPW2200) += ipw2200.o
+
 obj-$(CONFIG_STRIP) += strip.o
 obj-$(CONFIG_ARLAN) += arlan.o 
 
@@ -18,6 +22,8 @@ obj-$(CONFIG_APPLE_AIRPORT)   += airport.o
 obj-$(CONFIG_PLX_HERMES)       += orinoco_plx.o
 obj-$(CONFIG_PCI_HERMES)       += orinoco_pci.o
 obj-$(CONFIG_TMD_HERMES)       += orinoco_tmd.o
+obj-$(CONFIG_NORTEL_HERMES)    += orinoco_nortel.o
+obj-$(CONFIG_PCMCIA_SPECTRUM)  += spectrum_cs.o
 
 obj-$(CONFIG_AIRO)             += airo.o
 obj-$(CONFIG_AIRO_CS)          += airo_cs.o airo.o
@@ -28,6 +34,8 @@ obj-$(CONFIG_PCMCIA_ATMEL)      += atmel_cs.o
 
 obj-$(CONFIG_PRISM54)          += prism54/
 
+obj-$(CONFIG_HOSTAP)           += hostap/
+
 # 16-bit wireless PCMCIA client drivers
 obj-$(CONFIG_PCMCIA_RAYCS)     += ray_cs.o
 obj-$(CONFIG_PCMCIA_WL3501)    += wl3501_cs.o
index df20adcd0730aa1cf5fb899d7b2017209782fb6c..2be65d308fbeab14e24f759a2da5ebca6b90c8bf 100644 (file)
@@ -1040,7 +1040,7 @@ typedef struct {
        u16 status;
 } WifiCtlHdr;
 
-WifiCtlHdr wifictlhdr8023 = {
+static WifiCtlHdr wifictlhdr8023 = {
        .ctlhdr = {
                .ctl    = HOST_DONT_RLSE,
        }
@@ -1111,13 +1111,13 @@ static int airo_thread(void *data);
 static void timer_func( struct net_device *dev );
 static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 #ifdef WIRELESS_EXT
-struct iw_statistics *airo_get_wireless_stats (struct net_device *dev);
+static struct iw_statistics *airo_get_wireless_stats (struct net_device *dev);
 static void airo_read_wireless_stats (struct airo_info *local);
 #endif /* WIRELESS_EXT */
 #ifdef CISCO_EXT
 static int readrids(struct net_device *dev, aironet_ioctl *comp);
 static int writerids(struct net_device *dev, aironet_ioctl *comp);
-int flashcard(struct net_device *dev, aironet_ioctl *comp);
+static int flashcard(struct net_device *dev, aironet_ioctl *comp);
 #endif /* CISCO_EXT */
 #ifdef MICSUPPORT
 static void micinit(struct airo_info *ai);
@@ -1226,6 +1226,12 @@ static int setup_proc_entry( struct net_device *dev,
 static int takedown_proc_entry( struct net_device *dev,
                                struct airo_info *apriv );
 
+static int cmdreset(struct airo_info *ai);
+static int setflashmode (struct airo_info *ai);
+static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime);
+static int flashputbuf(struct airo_info *ai);
+static int flashrestart(struct airo_info *ai,struct net_device *dev);
+
 #ifdef MICSUPPORT
 /***********************************************************************
  *                              MIC ROUTINES                           *
@@ -1234,10 +1240,11 @@ static int takedown_proc_entry( struct net_device *dev,
 
 static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq);
 static void MoveWindow(miccntx *context, u32 micSeq);
-void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *);
-void emmh32_init(emmh32_context *context);
-void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
-void emmh32_final(emmh32_context *context, u8 digest[4]);
+static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *);
+static void emmh32_init(emmh32_context *context);
+static void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
+static void emmh32_final(emmh32_context *context, u8 digest[4]);
+static int flashpchar(struct airo_info *ai,int byte,int dwelltime);
 
 /* micinit - Initialize mic seed */
 
@@ -1301,7 +1308,7 @@ static int micsetup(struct airo_info *ai) {
        int i;
 
        if (ai->tfm == NULL)
-               ai->tfm = crypto_alloc_tfm("aes", 0);
+               ai->tfm = crypto_alloc_tfm("aes", CRYPTO_TFM_REQ_MAY_SLEEP);
 
         if (ai->tfm == NULL) {
                 printk(KERN_ERR "airo: failed to load transform for AES\n");
@@ -1315,7 +1322,7 @@ static int micsetup(struct airo_info *ai) {
        return SUCCESS;
 }
 
-char micsnap[]= {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02};
+static char micsnap[] = {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02};
 
 /*===========================================================================
  * Description: Mic a packet
@@ -1570,7 +1577,7 @@ static void MoveWindow(miccntx *context, u32 micSeq)
 static unsigned char aes_counter[16];
 
 /* expand the key to fill the MMH coefficient array */
-void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *tfm)
+static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *tfm)
 {
   /* take the keying material, expand if necessary, truncate at 16-bytes */
   /* run through AES counter mode to generate context->coeff[] */
@@ -1602,7 +1609,7 @@ void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto
 }
 
 /* prepare for calculation of a new mic */
-void emmh32_init(emmh32_context *context)
+static void emmh32_init(emmh32_context *context)
 {
        /* prepare for new mic calculation */
        context->accum = 0;
@@ -1610,7 +1617,7 @@ void emmh32_init(emmh32_context *context)
 }
 
 /* add some bytes to the mic calculation */
-void emmh32_update(emmh32_context *context, u8 *pOctets, int len)
+static void emmh32_update(emmh32_context *context, u8 *pOctets, int len)
 {
        int     coeff_position, byte_position;
   
@@ -1652,7 +1659,7 @@ void emmh32_update(emmh32_context *context, u8 *pOctets, int len)
 static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L };
 
 /* calculate the mic */
-void emmh32_final(emmh32_context *context, u8 digest[4])
+static void emmh32_final(emmh32_context *context, u8 digest[4])
 {
        int     coeff_position, byte_position;
        u32     val;
@@ -2232,7 +2239,7 @@ static void airo_read_stats(struct airo_info *ai) {
        u32 *vals = stats_rid.vals;
 
        clear_bit(JOB_STATS, &ai->flags);
-       if (ai->power) {
+       if (ai->power.event) {
                up(&ai->sem);
                return;
        }
@@ -2255,7 +2262,7 @@ static void airo_read_stats(struct airo_info *ai) {
        ai->stats.rx_fifo_errors = vals[0];
 }
 
-struct net_device_stats *airo_get_stats(struct net_device *dev)
+static struct net_device_stats *airo_get_stats(struct net_device *dev)
 {
        struct airo_info *local =  dev->priv;
 
@@ -2403,8 +2410,7 @@ void stop_airo_card( struct net_device *dev, int freeres )
                }
         }
 #ifdef MICSUPPORT
-       if (ai->tfm)
-               crypto_free_tfm(ai->tfm);
+       crypto_free_tfm(ai->tfm);
 #endif
        del_airo_dev( dev );
        free_netdev( dev );
@@ -2414,7 +2420,7 @@ EXPORT_SYMBOL(stop_airo_card);
 
 static int add_airo_dev( struct net_device *dev );
 
-int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
+static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
 {
        memcpy(haddr, skb->mac.raw + 10, ETH_ALEN);
        return ETH_ALEN;
@@ -2681,7 +2687,7 @@ static struct net_device *init_wifidev(struct airo_info *ai,
        return dev;
 }
 
-int reset_card( struct net_device *dev , int lock) {
+static int reset_card( struct net_device *dev , int lock) {
        struct airo_info *ai = dev->priv;
 
        if (lock && down_interruptible(&ai->sem))
@@ -2696,9 +2702,9 @@ int reset_card( struct net_device *dev , int lock) {
        return 0;
 }
 
-struct net_device *_init_airo_card( unsigned short irq, int port,
-                                   int is_pcmcia, struct pci_dev *pci,
-                                   struct device *dmdev )
+static struct net_device *_init_airo_card( unsigned short irq, int port,
+                                          int is_pcmcia, struct pci_dev *pci,
+                                          struct device *dmdev )
 {
        struct net_device *dev;
        struct airo_info *ai;
@@ -2962,7 +2968,7 @@ static int airo_thread(void *data) {
                        break;
                }
 
-               if (ai->power || test_bit(FLAG_FLASHING, &ai->flags)) {
+               if (ai->power.event || test_bit(FLAG_FLASHING, &ai->flags)) {
                        up(&ai->sem);
                        continue;
                }
@@ -3252,7 +3258,7 @@ badrx:
                                wstats.noise = apriv->wstats.qual.noise;
                                wstats.updated = IW_QUAL_LEVEL_UPDATED
                                        | IW_QUAL_QUAL_UPDATED
-                                       | IW_QUAL_NOISE_UPDATED;
+                                       | IW_QUAL_DBM;
                                /* Update spy records */
                                wireless_spy_update(dev, sa, &wstats);
                        }
@@ -3598,7 +3604,7 @@ void mpi_receive_802_11 (struct airo_info *ai)
                wstats.noise = ai->wstats.qual.noise;
                wstats.updated = IW_QUAL_QUAL_UPDATED
                        | IW_QUAL_LEVEL_UPDATED
-                       | IW_QUAL_NOISE_UPDATED;
+                       | IW_QUAL_DBM;
                /* Update spy records */
                wireless_spy_update(ai->dev, sa, &wstats);
        }
@@ -5514,7 +5520,7 @@ static int airo_pci_resume(struct pci_dev *pdev)
        pci_restore_state(pdev);
        pci_enable_wake(pdev, pci_choose_state(pdev, ai->power), 0);
 
-       if (ai->power > 1) {
+       if (ai->power.event > 1) {
                reset_card(dev, 0);
                mpi_init_descriptors(ai);
                setup_card(ai, dev->dev_addr, 0);
@@ -6483,22 +6489,20 @@ static int airo_get_range(struct net_device *dev,
                range->max_qual.qual = 100;     /* % */
        else
                range->max_qual.qual = airo_get_max_quality(&cap_rid);
-       range->max_qual.level = 0;      /* 0 means we use dBm  */
-       range->max_qual.noise = 0;
-       range->max_qual.updated = 0;
+       range->max_qual.level = 0x100 - 120;    /* -120 dBm */
+       range->max_qual.noise = 0x100 - 120;    /* -120 dBm */
 
        /* Experimental measurements - boundary 11/5.5 Mb/s */
        /* Note : with or without the (local->rssi), results
         * are somewhat different. - Jean II */
        if (local->rssi) {
-               range->avg_qual.qual = 50;      /* % */
-               range->avg_qual.level = 186;    /* -70 dBm */
+               range->avg_qual.qual = 50;              /* % */
+               range->avg_qual.level = 0x100 - 70;     /* -70 dBm */
        } else {
                range->avg_qual.qual = airo_get_avg_quality(&cap_rid);
-               range->avg_qual.level = 176;    /* -80 dBm */
+               range->avg_qual.level = 0x100 - 80;     /* -80 dBm */
        }
-       range->avg_qual.noise = 0;
-       range->avg_qual.updated = 0;
+       range->avg_qual.noise = 0x100 - 85;             /* -85 dBm */
 
        for(i = 0 ; i < 8 ; i++) {
                range->bitrate[i] = cap_rid.supportedRates[i] * 500000;
@@ -6721,15 +6725,17 @@ static int airo_get_aplist(struct net_device *dev,
                if (local->rssi) {
                        qual[i].level = 0x100 - BSSList.dBm;
                        qual[i].qual = airo_dbm_to_pct( local->rssi, BSSList.dBm );
-                       qual[i].updated = IW_QUAL_QUAL_UPDATED;
+                       qual[i].updated = IW_QUAL_QUAL_UPDATED
+                                       | IW_QUAL_LEVEL_UPDATED
+                                       | IW_QUAL_DBM;
                } else {
                        qual[i].level = (BSSList.dBm + 321) / 2;
                        qual[i].qual = 0;
-                       qual[i].updated = IW_QUAL_QUAL_INVALID;
+                       qual[i].updated = IW_QUAL_QUAL_INVALID
+                                       | IW_QUAL_LEVEL_UPDATED
+                                       | IW_QUAL_DBM;
                }
                qual[i].noise = local->wstats.qual.noise;
-               qual[i].updated = IW_QUAL_LEVEL_UPDATED
-                               | IW_QUAL_NOISE_UPDATED;
                if (BSSList.index == 0xffff)
                        break;
        }
@@ -6855,15 +6861,17 @@ static inline char *airo_translate_scan(struct net_device *dev,
        if (ai->rssi) {
                iwe.u.qual.level = 0x100 - bss->dBm;
                iwe.u.qual.qual = airo_dbm_to_pct( ai->rssi, bss->dBm );
-               iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED;
+               iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
+                               | IW_QUAL_LEVEL_UPDATED
+                               | IW_QUAL_DBM;
        } else {
                iwe.u.qual.level = (bss->dBm + 321) / 2;
                iwe.u.qual.qual = 0;
-               iwe.u.qual.updated = IW_QUAL_QUAL_INVALID;
+               iwe.u.qual.updated = IW_QUAL_QUAL_INVALID
+                               | IW_QUAL_LEVEL_UPDATED
+                               | IW_QUAL_DBM;
        }
        iwe.u.qual.noise = ai->wstats.qual.noise;
-       iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED
-                       | IW_QUAL_NOISE_UPDATED;
        current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
 
        /* Add encryption capability */
@@ -7116,7 +7124,7 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        int rc = 0;
        struct airo_info *ai = (struct airo_info *)dev->priv;
 
-       if (ai->power)
+       if (ai->power.event)
                return 0;
 
        switch (cmd) {
@@ -7195,7 +7203,7 @@ static void airo_read_wireless_stats(struct airo_info *local)
 
        /* Get stats out of the card */
        clear_bit(JOB_WSTATS, &local->flags);
-       if (local->power) {
+       if (local->power.event) {
                up(&local->sem);
                return;
        }
@@ -7216,13 +7224,12 @@ static void airo_read_wireless_stats(struct airo_info *local)
                local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2;
                local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid);
        }
-       local->wstats.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED;
        if (status_rid.len >= 124) {
                local->wstats.qual.noise = 0x100 - status_rid.noisedBm;
-               local->wstats.qual.updated |= IW_QUAL_NOISE_UPDATED;
+               local->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
        } else {
                local->wstats.qual.noise = 0;
-               local->wstats.qual.updated |= IW_QUAL_NOISE_INVALID;
+               local->wstats.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID | IW_QUAL_DBM;
        }
 
        /* Packets discarded in the wireless adapter due to wireless
@@ -7235,7 +7242,7 @@ static void airo_read_wireless_stats(struct airo_info *local)
        local->wstats.miss.beacon = vals[34];
 }
 
-struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
+static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
 {
        struct airo_info *local =  dev->priv;
 
@@ -7450,14 +7457,8 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
  * Flash command switch table
  */
 
-int flashcard(struct net_device *dev, aironet_ioctl *comp) {
+static int flashcard(struct net_device *dev, aironet_ioctl *comp) {
        int z;
-       int cmdreset(struct airo_info *);
-       int setflashmode(struct airo_info *);
-       int flashgchar(struct airo_info *,int,int);
-       int flashpchar(struct airo_info *,int,int);
-       int flashputbuf(struct airo_info *);
-       int flashrestart(struct airo_info *,struct net_device *);
 
        /* Only super-user can modify flash */
        if (!capable(CAP_NET_ADMIN))
@@ -7515,7 +7516,7 @@ int flashcard(struct net_device *dev, aironet_ioctl *comp) {
  * card.
  */
 
-int cmdreset(struct airo_info *ai) {
+static int cmdreset(struct airo_info *ai) {
        disable_MAC(ai, 1);
 
        if(!waitbusy (ai)){
@@ -7539,7 +7540,7 @@ int cmdreset(struct airo_info *ai) {
  * mode
  */
 
-int setflashmode (struct airo_info *ai) {
+static int setflashmode (struct airo_info *ai) {
        set_bit (FLAG_FLASHING, &ai->flags);
 
        OUT4500(ai, SWS0, FLASH_COMMAND);
@@ -7566,7 +7567,7 @@ int setflashmode (struct airo_info *ai) {
  * x 50us for  echo .
  */
 
-int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
+static int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
        int echo;
        int waittime;
 
@@ -7606,7 +7607,7 @@ int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
  * Get a character from the card matching matchbyte
  * Step 3)
  */
-int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){
+static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){
        int           rchar;
        unsigned char rbyte=0;
 
@@ -7637,7 +7638,7 @@ int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){
  * send to the card
  */
 
-int flashputbuf(struct airo_info *ai){
+static int flashputbuf(struct airo_info *ai){
        int            nwords;
 
        /* Write stuff */
@@ -7659,7 +7660,7 @@ int flashputbuf(struct airo_info *ai){
 /*
  *
  */
-int flashrestart(struct airo_info *ai,struct net_device *dev){
+static int flashrestart(struct airo_info *ai,struct net_device *dev){
        int    i,status;
 
        ssleep(1);                      /* Added 12/7/00 */
index 18a7d38d2a1301f833dd36eb4ed587d73390e109..587869d86eeea1ea195137619db5ec316bd4f774 100644 (file)
@@ -68,7 +68,7 @@
 #include <linux/device.h>
 #include <linux/moduleparam.h>
 #include <linux/firmware.h>
-#include "ieee802_11.h"
+#include <net/ieee80211.h>
 #include "atmel.h"
 
 #define DRIVER_MAJOR 0
@@ -618,12 +618,12 @@ static int atmel_lock_mac(struct atmel_private *priv);
 static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data);
 static void atmel_command_irq(struct atmel_private *priv);
 static int atmel_validate_channel(struct atmel_private *priv, int channel);
-static void atmel_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, 
+static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header, 
                                   u16 frame_len, u8 rssi);
 static void atmel_management_timer(u_long a);
 static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size);
 static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size);
-static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header,
+static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header,
                                            u8 *body, int body_len);
 
 static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index);
@@ -827,7 +827,7 @@ static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, u16 l
 static int start_tx (struct sk_buff *skb, struct net_device *dev)
 {
        struct atmel_private *priv = netdev_priv(dev);
-       struct ieee802_11_hdr header;
+       struct ieee80211_hdr header;
        unsigned long flags;
        u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
        u8 SNAP_RFC1024[6] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
@@ -863,17 +863,17 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev)
                return 1;
        }
        
-       frame_ctl = IEEE802_11_FTYPE_DATA;
+       frame_ctl = IEEE80211_FTYPE_DATA;
        header.duration_id = 0;
        header.seq_ctl = 0;
        if (priv->wep_is_on)
-               frame_ctl |= IEEE802_11_FCTL_WEP;
+               frame_ctl |= IEEE80211_FCTL_PROTECTED;
        if (priv->operating_mode == IW_MODE_ADHOC) {
                memcpy(&header.addr1, skb->data, 6);
                memcpy(&header.addr2, dev->dev_addr, 6);
                memcpy(&header.addr3, priv->BSSID, 6);
        } else {
-               frame_ctl |= IEEE802_11_FCTL_TODS;
+               frame_ctl |= IEEE80211_FCTL_TODS;
                memcpy(&header.addr1, priv->CurrentBSSID, 6);
                memcpy(&header.addr2, dev->dev_addr, 6);
                memcpy(&header.addr3, skb->data, 6);
@@ -902,7 +902,7 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev)
 }
 
 static void atmel_transmit_management_frame(struct atmel_private *priv, 
-                                           struct ieee802_11_hdr *header,
+                                           struct ieee80211_hdr *header,
                                            u8 *body, int body_len)
 {
        u16 buff;
@@ -917,7 +917,7 @@ static void atmel_transmit_management_frame(struct atmel_private *priv,
        tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT);
 }
        
-static void fast_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *header, 
+static void fast_rx_path(struct atmel_private *priv, struct ieee80211_hdr *header, 
                         u16 msdu_size, u16 rx_packet_loc, u32 crc)
 {
        /* fast path: unfragmented packet copy directly into skbuf */
@@ -955,7 +955,7 @@ static void fast_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *head
        }
        
        memcpy(skbp, header->addr1, 6); /* destination address */
-       if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) 
+       if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS) 
                memcpy(&skbp[6], header->addr3, 6);
        else
                memcpy(&skbp[6], header->addr2, 6); /* source address */
@@ -990,14 +990,14 @@ static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size)
        return (crc ^ 0xffffffff) == netcrc;
 }
 
-static void frag_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *header, 
+static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr *header, 
                         u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, u8 frag_no, int more_frags)
 {
        u8 mac4[6]; 
        u8 source[6];
        struct sk_buff *skb;
 
-       if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) 
+       if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS) 
                memcpy(source, header->addr3, 6);
        else
                memcpy(source, header->addr2, 6); 
@@ -1082,7 +1082,7 @@ static void frag_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *head
 static void rx_done_irq(struct atmel_private *priv)
 {
        int i;
-       struct ieee802_11_hdr header;
+       struct ieee80211_hdr header;
        
        for (i = 0; 
             atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID &&
@@ -1117,7 +1117,7 @@ static void rx_done_irq(struct atmel_private *priv)
                /* probe for CRC use here if needed  once five packets have arrived with
                   the same crc status, we assume we know what's happening and stop probing */
                if (priv->probe_crc) {
-                       if (!priv->wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP)) {
+                       if (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED)) {
                                priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size);
                        } else {
                                priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24);
@@ -1132,16 +1132,16 @@ static void rx_done_irq(struct atmel_private *priv)
                }
                    
                /* don't CRC header when WEP in use */
-               if (priv->do_rx_crc && (!priv->wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP))) {
+               if (priv->do_rx_crc && (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED))) {
                        crc = crc32_le(0xffffffff, (unsigned char *)&header, 24);
                }
                msdu_size -= 24; /* header */
 
-               if ((frame_ctl & IEEE802_11_FCTL_FTYPE) == IEEE802_11_FTYPE_DATA) { 
+               if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { 
                        
-                       int more_fragments = frame_ctl & IEEE802_11_FCTL_MOREFRAGS;
-                       u8 packet_fragment_no = seq_control & IEEE802_11_SCTL_FRAG;
-                       u16 packet_sequence_no = (seq_control & IEEE802_11_SCTL_SEQ) >> 4;
+                       int more_fragments = frame_ctl & IEEE80211_FCTL_MOREFRAGS;
+                       u8 packet_fragment_no = seq_control & IEEE80211_SCTL_FRAG;
+                       u16 packet_sequence_no = (seq_control & IEEE80211_SCTL_SEQ) >> 4;
                        
                        if (!more_fragments && packet_fragment_no == 0 ) {
                                fast_rx_path(priv, &header, msdu_size, rx_packet_loc, crc);
@@ -1151,7 +1151,7 @@ static void rx_done_irq(struct atmel_private *priv)
                        }
                }
                
-               if ((frame_ctl & IEEE802_11_FCTL_FTYPE) == IEEE802_11_FTYPE_MGMT) {
+               if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
                        /* copy rest of packet into buffer */
                        atmel_copy_to_host(priv->dev, (unsigned char *)&priv->rx_buf, rx_packet_loc + 24, msdu_size);
                        
@@ -1593,7 +1593,6 @@ struct net_device *init_atmel_card( unsigned short irq, int port, const AtmelFWT
        dev->set_mac_address = atmel_set_mac_address;
        dev->hard_start_xmit = start_tx;
        dev->get_stats = atmel_get_stats;
-       dev->get_wireless_stats = atmel_get_wireless_stats;
        dev->wireless_handlers = (struct iw_handler_def *)&atmel_handler_def;
        dev->do_ioctl = atmel_ioctl;
        dev->irq = irq;
@@ -2411,7 +2410,8 @@ static const struct iw_handler_def        atmel_handler_def =
        .num_private_args = sizeof(atmel_private_args)/sizeof(struct iw_priv_args), 
        .standard       = (iw_handler *) atmel_handler,
        .private        = (iw_handler *) atmel_private_handler, 
-       .private_args   = (struct iw_priv_args *) atmel_private_args
+       .private_args   = (struct iw_priv_args *) atmel_private_args,
+       .get_wireless_stats = atmel_get_wireless_stats
 };
 
 static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -2424,19 +2424,6 @@ static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        char domain[REGDOMAINSZ+1];
 
        switch (cmd) {
-       case SIOCGIWPRIV:
-               if(wrq->u.data.pointer) {
-                       /* Set the number of ioctl available */
-                       wrq->u.data.length = sizeof(atmel_private_args) / sizeof(atmel_private_args[0]);
-                       
-                       /* Copy structure to the user buffer */
-                       if (copy_to_user(wrq->u.data.pointer,
-                                        (u_char *) atmel_private_args,
-                                        sizeof(atmel_private_args)))
-                               rc = -EFAULT;
-               }
-               break;
-
        case ATMELIDIFC:
                wrq->u.param.value = ATMELMAGIC;                
                break;
@@ -2663,10 +2650,10 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability, u8 c
  
 static void send_authentication_request(struct atmel_private *priv, u8 *challenge, int challenge_len)
 {
-       struct ieee802_11_hdr header;
+       struct ieee80211_hdr header;
        struct auth_body auth;
        
-       header.frame_ctl = cpu_to_le16(IEEE802_11_FTYPE_MGMT | IEEE802_11_STYPE_AUTH); 
+       header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); 
        header.duration_id      = cpu_to_le16(0x8000);  
        header.seq_ctl = 0;
        memcpy(header.addr1, priv->CurrentBSSID, 6);
@@ -2677,7 +2664,7 @@ static void send_authentication_request(struct atmel_private *priv, u8 *challeng
                auth.alg = cpu_to_le16(C80211_MGMT_AAN_SHAREDKEY); 
                /* no WEP for authentication frames with TrSeqNo 1 */
                if (priv->CurrentAuthentTransactionSeqNum != 1)
-                       header.frame_ctl |=  cpu_to_le16(IEEE802_11_FCTL_WEP); 
+                       header.frame_ctl |=  cpu_to_le16(IEEE80211_FCTL_PROTECTED);
        } else {
                auth.alg = cpu_to_le16(C80211_MGMT_AAN_OPENSYSTEM);
        }
@@ -2701,7 +2688,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
 {
        u8 *ssid_el_p;
        int bodysize;
-       struct ieee802_11_hdr header;
+       struct ieee80211_hdr header;
        struct ass_req_format {
                u16 capability;
                u16 listen_interval; 
@@ -2714,8 +2701,8 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
                u8 rates[4];
        } body;
                
-       header.frame_ctl = cpu_to_le16(IEEE802_11_FTYPE_MGMT | 
-               (is_reassoc ? IEEE802_11_STYPE_REASSOC_REQ : IEEE802_11_STYPE_ASSOC_REQ));
+       header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | 
+               (is_reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ));
        header.duration_id = cpu_to_le16(0x8000);
        header.seq_ctl = 0;
 
@@ -2751,9 +2738,9 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
        atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize);
 }
 
-static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee802_11_hdr *header)
+static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee80211_hdr *header)
 {
-       if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS)
+       if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
                return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0;
        else
                return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0;
@@ -2801,7 +2788,7 @@ static int retrieve_bss(struct atmel_private *priv)
 }
 
 
-static void store_bss_info(struct atmel_private *priv, struct ieee802_11_hdr *header,
+static void store_bss_info(struct atmel_private *priv, struct ieee80211_hdr *header,
                           u16 capability, u16 beacon_period, u8 channel, u8 rssi, 
                           u8 ssid_len, u8 *ssid, int is_beacon)
 {
@@ -3085,12 +3072,12 @@ static void atmel_smooth_qual(struct atmel_private *priv)
 }
 
 /* deals with incoming managment frames. */
-static void atmel_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, 
+static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header, 
                      u16 frame_len, u8 rssi)
 {
        u16 subtype;
        
-       switch (subtype = le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_STYPE) {
+       switch (subtype = le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_STYPE) {
        case C80211_SUBTYPE_MGMT_BEACON :
        case C80211_SUBTYPE_MGMT_ProbeResponse:
                
diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig
new file mode 100644 (file)
index 0000000..56f41c7
--- /dev/null
@@ -0,0 +1,73 @@
+config HOSTAP
+       tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)"
+       depends on NET_RADIO
+       select IEEE80211
+       select IEEE80211_CRYPT_WEP
+       ---help---
+       Shared driver code for IEEE 802.11b wireless cards based on
+       Intersil Prism2/2.5/3 chipset. This driver supports so called
+       Host AP mode that allows the card to act as an IEEE 802.11
+       access point.
+
+       See <http://hostap.epitest.fi/> for more information about the
+       Host AP driver configuration and tools. This site includes
+       information and tools (hostapd and wpa_supplicant) for WPA/WPA2
+       support.
+
+       This option includes the base Host AP driver code that is shared by
+       different hardware models. You will also need to enable support for
+       PLX/PCI/CS version of the driver to actually use the driver.
+
+       The driver can be compiled as a module and it will be called
+       "hostap.ko".
+
+config HOSTAP_FIRMWARE
+       bool "Support downloading firmware images with Host AP driver"
+       depends on HOSTAP
+       ---help---
+       Configure Host AP driver to include support for firmware image
+       download. Current version supports only downloading to volatile, i.e.,
+       RAM memory. Flash upgrade is not yet supported.
+
+       Firmware image downloading needs user space tool, prism2_srec. It is
+       available from http://hostap.epitest.fi/.
+
+config HOSTAP_PLX
+       tristate "Host AP driver for Prism2/2.5/3 in PLX9052 PCI adaptors"
+       depends on PCI && HOSTAP
+       ---help---
+       Host AP driver's version for Prism2/2.5/3 PC Cards in PLX9052 based
+       PCI adaptors.
+
+       "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
+       driver and its help text includes more information about the Host AP
+       driver.
+
+       The driver can be compiled as a module and will be named
+       "hostap_plx.ko".
+
+config HOSTAP_PCI
+       tristate "Host AP driver for Prism2.5 PCI adaptors"
+       depends on PCI && HOSTAP
+       ---help---
+       Host AP driver's version for Prism2.5 PCI adaptors.
+
+       "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
+       driver and its help text includes more information about the Host AP
+       driver.
+
+       The driver can be compiled as a module and will be named
+       "hostap_pci.ko".
+
+config HOSTAP_CS
+       tristate "Host AP driver for Prism2/2.5/3 PC Cards"
+       depends on PCMCIA!=n && HOSTAP
+       ---help---
+       Host AP driver's version for Prism2/2.5/3 PC Cards.
+
+       "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
+       driver and its help text includes more information about the Host AP
+       driver.
+
+       The driver can be compiled as a module and will be named
+       "hostap_cs.ko".
diff --git a/drivers/net/wireless/hostap/Makefile b/drivers/net/wireless/hostap/Makefile
new file mode 100644 (file)
index 0000000..fc62235
--- /dev/null
@@ -0,0 +1,5 @@
+obj-$(CONFIG_HOSTAP) += hostap.o
+
+obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o
+obj-$(CONFIG_HOSTAP_PLX) += hostap_plx.o
+obj-$(CONFIG_HOSTAP_PCI) += hostap_pci.o
diff --git a/drivers/net/wireless/hostap/hostap.c b/drivers/net/wireless/hostap/hostap.c
new file mode 100644 (file)
index 0000000..e7f5821
--- /dev/null
@@ -0,0 +1,1198 @@
+/*
+ * Host AP (software wireless LAN access point) driver for
+ * Intersil Prism2/2.5/3 - hostap.o module, common routines
+ *
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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. See README and COPYING for
+ * more details.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/if_arp.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/workqueue.h>
+#include <linux/kmod.h>
+#include <linux/rtnetlink.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <net/ieee80211.h>
+#include <net/ieee80211_crypt.h>
+#include <asm/uaccess.h>
+
+#include "hostap_wlan.h"
+#include "hostap_80211.h"
+#include "hostap_ap.h"
+#include "hostap.h"
+
+MODULE_AUTHOR("Jouni Malinen");
+MODULE_DESCRIPTION("Host AP common routines");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(PRISM2_VERSION);
+
+#define TX_TIMEOUT (2 * HZ)
+
+#define PRISM2_MAX_FRAME_SIZE 2304
+#define PRISM2_MIN_MTU 256
+/* FIX: */
+#define PRISM2_MAX_MTU (PRISM2_MAX_FRAME_SIZE - (6 /* LLC */ + 8 /* WEP */))
+
+
+/* hostap.c */
+static int prism2_wds_add(local_info_t *local, u8 *remote_addr,
+                         int rtnl_locked);
+static int prism2_wds_del(local_info_t *local, u8 *remote_addr,
+                         int rtnl_locked, int do_not_remove);
+
+/* hostap_ap.c */
+static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
+                                 struct iw_quality qual[], int buf_size,
+                                 int aplist);
+static int prism2_ap_translate_scan(struct net_device *dev, char *buffer);
+static int prism2_hostapd(struct ap_data *ap,
+                         struct prism2_hostapd_param *param);
+static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
+                               struct ieee80211_crypt_data ***crypt);
+static void ap_control_kickall(struct ap_data *ap);
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+static int ap_control_add_mac(struct mac_restrictions *mac_restrictions,
+                             u8 *mac);
+static int ap_control_del_mac(struct mac_restrictions *mac_restrictions,
+                             u8 *mac);
+static void ap_control_flush_macs(struct mac_restrictions *mac_restrictions);
+static int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev,
+                              u8 *mac);
+#endif /* !PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+static const long freq_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+                                 2447, 2452, 2457, 2462, 2467, 2472, 2484 };
+#define FREQ_COUNT (sizeof(freq_list) / sizeof(freq_list[0]))
+
+
+/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
+/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
+static unsigned char rfc1042_header[] =
+{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
+static unsigned char bridge_tunnel_header[] =
+{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
+/* No encapsulation header if EtherType < 0x600 (=length) */
+
+
+/* FIX: these could be compiled separately and linked together to hostap.o */
+#include "hostap_ap.c"
+#include "hostap_info.c"
+#include "hostap_ioctl.c"
+#include "hostap_proc.c"
+#include "hostap_80211_rx.c"
+#include "hostap_80211_tx.c"
+
+
+struct net_device * hostap_add_interface(struct local_info *local,
+                                        int type, int rtnl_locked,
+                                        const char *prefix,
+                                        const char *name)
+{
+       struct net_device *dev, *mdev;
+       struct hostap_interface *iface;
+       int ret;
+
+       dev = alloc_etherdev(sizeof(struct hostap_interface));
+       if (dev == NULL)
+               return NULL;
+
+       iface = netdev_priv(dev);
+       iface->dev = dev;
+       iface->local = local;
+       iface->type = type;
+       list_add(&iface->list, &local->hostap_interfaces);
+
+       mdev = local->dev;
+       memcpy(dev->dev_addr, mdev->dev_addr, ETH_ALEN);
+       dev->base_addr = mdev->base_addr;
+       dev->irq = mdev->irq;
+       dev->mem_start = mdev->mem_start;
+       dev->mem_end = mdev->mem_end;
+
+       hostap_setup_dev(dev, local, 0);
+       dev->destructor = free_netdev;
+
+       sprintf(dev->name, "%s%s", prefix, name);
+       if (!rtnl_locked)
+               rtnl_lock();
+
+       ret = 0;
+       if (strchr(dev->name, '%'))
+               ret = dev_alloc_name(dev, dev->name);
+
+       SET_NETDEV_DEV(dev, mdev->class_dev.dev);
+       if (ret >= 0)
+               ret = register_netdevice(dev);
+
+       if (!rtnl_locked)
+               rtnl_unlock();
+
+       if (ret < 0) {
+               printk(KERN_WARNING "%s: failed to add new netdevice!\n",
+                      dev->name);
+               free_netdev(dev);
+               return NULL;
+       }
+
+       printk(KERN_DEBUG "%s: registered netdevice %s\n",
+              mdev->name, dev->name);
+
+       return dev;
+}
+
+
+void hostap_remove_interface(struct net_device *dev, int rtnl_locked,
+                            int remove_from_list)
+{
+       struct hostap_interface *iface;
+
+       if (!dev)
+               return;
+
+       iface = netdev_priv(dev);
+
+       if (remove_from_list) {
+               list_del(&iface->list);
+       }
+
+       if (dev == iface->local->ddev)
+               iface->local->ddev = NULL;
+       else if (dev == iface->local->apdev)
+               iface->local->apdev = NULL;
+       else if (dev == iface->local->stadev)
+               iface->local->stadev = NULL;
+
+       if (rtnl_locked)
+               unregister_netdevice(dev);
+       else
+               unregister_netdev(dev);
+
+       /* dev->destructor = free_netdev() will free the device data, including
+        * private data, when removing the device */
+}
+
+
+static inline int prism2_wds_special_addr(u8 *addr)
+{
+       if (addr[0] || addr[1] || addr[2] || addr[3] || addr[4] || addr[5])
+               return 0;
+
+       return 1;
+}
+
+
+static int prism2_wds_add(local_info_t *local, u8 *remote_addr,
+                         int rtnl_locked)
+{
+       struct net_device *dev;
+       struct list_head *ptr;
+       struct hostap_interface *iface, *empty, *match;
+
+       empty = match = NULL;
+       read_lock_bh(&local->iface_lock);
+       list_for_each(ptr, &local->hostap_interfaces) {
+               iface = list_entry(ptr, struct hostap_interface, list);
+               if (iface->type != HOSTAP_INTERFACE_WDS)
+                       continue;
+
+               if (prism2_wds_special_addr(iface->u.wds.remote_addr))
+                       empty = iface;
+               else if (memcmp(iface->u.wds.remote_addr, remote_addr,
+                               ETH_ALEN) == 0) {
+                       match = iface;
+                       break;
+               }
+       }
+       if (!match && empty && !prism2_wds_special_addr(remote_addr)) {
+               /* take pre-allocated entry into use */
+               memcpy(empty->u.wds.remote_addr, remote_addr, ETH_ALEN);
+               read_unlock_bh(&local->iface_lock);
+               printk(KERN_DEBUG "%s: using pre-allocated WDS netdevice %s\n",
+                      local->dev->name, empty->dev->name);
+               return 0;
+       }
+       read_unlock_bh(&local->iface_lock);
+
+       if (!prism2_wds_special_addr(remote_addr)) {
+               if (match)
+                       return -EEXIST;
+               hostap_add_sta(local->ap, remote_addr);
+       }
+
+       if (local->wds_connections >= local->wds_max_connections)
+               return -ENOBUFS;
+
+       /* verify that there is room for wds# postfix in the interface name */
+       if (strlen(local->dev->name) > IFNAMSIZ - 5) {
+               printk(KERN_DEBUG "'%s' too long base device name\n",
+                      local->dev->name);
+               return -EINVAL;
+       }
+
+       dev = hostap_add_interface(local, HOSTAP_INTERFACE_WDS, rtnl_locked,
+                                  local->ddev->name, "wds%d");
+       if (dev == NULL)
+               return -ENOMEM;
+
+       iface = netdev_priv(dev);
+       memcpy(iface->u.wds.remote_addr, remote_addr, ETH_ALEN);
+
+       local->wds_connections++;
+
+       return 0;
+}
+
+
+static int prism2_wds_del(local_info_t *local, u8 *remote_addr,
+                         int rtnl_locked, int do_not_remove)
+{
+       unsigned long flags;
+       struct list_head *ptr;
+       struct hostap_interface *iface, *selected = NULL;
+
+       write_lock_irqsave(&local->iface_lock, flags);
+       list_for_each(ptr, &local->hostap_interfaces) {
+               iface = list_entry(ptr, struct hostap_interface, list);
+               if (iface->type != HOSTAP_INTERFACE_WDS)
+                       continue;
+
+               if (memcmp(iface->u.wds.remote_addr, remote_addr,
+                          ETH_ALEN) == 0) {
+                       selected = iface;
+                       break;
+               }
+       }
+       if (selected && !do_not_remove)
+               list_del(&selected->list);
+       write_unlock_irqrestore(&local->iface_lock, flags);
+
+       if (selected) {
+               if (do_not_remove)
+                       memset(selected->u.wds.remote_addr, 0, ETH_ALEN);
+               else {
+                       hostap_remove_interface(selected->dev, rtnl_locked, 0);
+                       local->wds_connections--;
+               }
+       }
+
+       return selected ? 0 : -ENODEV;
+}
+
+
+u16 hostap_tx_callback_register(local_info_t *local,
+                               void (*func)(struct sk_buff *, int ok, void *),
+                               void *data)
+{
+       unsigned long flags;
+       struct hostap_tx_callback_info *entry;
+
+       entry = (struct hostap_tx_callback_info *) kmalloc(sizeof(*entry),
+                                                          GFP_ATOMIC);
+       if (entry == NULL)
+               return 0;
+
+       entry->func = func;
+       entry->data = data;
+
+       spin_lock_irqsave(&local->lock, flags);
+       entry->idx = local->tx_callback ? local->tx_callback->idx + 1 : 1;
+       entry->next = local->tx_callback;
+       local->tx_callback = entry;
+       spin_unlock_irqrestore(&local->lock, flags);
+
+       return entry->idx;
+}
+
+
+int hostap_tx_callback_unregister(local_info_t *local, u16 idx)
+{
+       unsigned long flags;
+       struct hostap_tx_callback_info *cb, *prev = NULL;
+
+       spin_lock_irqsave(&local->lock, flags);
+       cb = local->tx_callback;
+       while (cb != NULL && cb->idx != idx) {
+               prev = cb;
+               cb = cb->next;
+       }
+       if (cb) {
+               if (prev == NULL)
+                       local->tx_callback = cb->next;
+               else
+                       prev->next = cb->next;
+               kfree(cb);
+       }
+       spin_unlock_irqrestore(&local->lock, flags);
+
+       return cb ? 0 : -1;
+}
+
+
+/* val is in host byte order */
+int hostap_set_word(struct net_device *dev, int rid, u16 val)
+{
+       struct hostap_interface *iface;
+       u16 tmp = cpu_to_le16(val);
+       iface = netdev_priv(dev);
+       return iface->local->func->set_rid(dev, rid, &tmp, 2);
+}
+
+
+int hostap_set_string(struct net_device *dev, int rid, const char *val)
+{
+       struct hostap_interface *iface;
+       char buf[MAX_SSID_LEN + 2];
+       int len;
+
+       iface = netdev_priv(dev);
+       len = strlen(val);
+       if (len > MAX_SSID_LEN)
+               return -1;
+       memset(buf, 0, sizeof(buf));
+       buf[0] = len; /* little endian 16 bit word */
+       memcpy(buf + 2, val, len);
+
+       return iface->local->func->set_rid(dev, rid, &buf, MAX_SSID_LEN + 2);
+}
+
+
+u16 hostap_get_porttype(local_info_t *local)
+{
+       if (local->iw_mode == IW_MODE_ADHOC && local->pseudo_adhoc)
+               return HFA384X_PORTTYPE_PSEUDO_IBSS;
+       if (local->iw_mode == IW_MODE_ADHOC)
+               return HFA384X_PORTTYPE_IBSS;
+       if (local->iw_mode == IW_MODE_INFRA)
+               return HFA384X_PORTTYPE_BSS;
+       if (local->iw_mode == IW_MODE_REPEAT)
+               return HFA384X_PORTTYPE_WDS;
+       if (local->iw_mode == IW_MODE_MONITOR)
+               return HFA384X_PORTTYPE_PSEUDO_IBSS;
+       return HFA384X_PORTTYPE_HOSTAP;
+}
+
+
+int hostap_set_encryption(local_info_t *local)
+{
+       u16 val, old_val;
+       int i, keylen, len, idx;
+       char keybuf[WEP_KEY_LEN + 1];
+       enum { NONE, WEP, OTHER } encrypt_type;
+
+       idx = local->tx_keyidx;
+       if (local->crypt[idx] == NULL || local->crypt[idx]->ops == NULL)
+               encrypt_type = NONE;
+       else if (strcmp(local->crypt[idx]->ops->name, "WEP") == 0)
+               encrypt_type = WEP;
+       else
+               encrypt_type = OTHER;
+
+       if (local->func->get_rid(local->dev, HFA384X_RID_CNFWEPFLAGS, &val, 2,
+                                1) < 0) {
+               printk(KERN_DEBUG "Could not read current WEP flags.\n");
+               goto fail;
+       }
+       le16_to_cpus(&val);
+       old_val = val;
+
+       if (encrypt_type != NONE || local->privacy_invoked)
+               val |= HFA384X_WEPFLAGS_PRIVACYINVOKED;
+       else
+               val &= ~HFA384X_WEPFLAGS_PRIVACYINVOKED;
+
+       if (local->open_wep || encrypt_type == NONE ||
+           ((local->ieee_802_1x || local->wpa) && local->host_decrypt))
+               val &= ~HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED;
+       else
+               val |= HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED;
+
+       if ((encrypt_type != NONE || local->privacy_invoked) &&
+           (encrypt_type == OTHER || local->host_encrypt))
+               val |= HFA384X_WEPFLAGS_HOSTENCRYPT;
+       else
+               val &= ~HFA384X_WEPFLAGS_HOSTENCRYPT;
+       if ((encrypt_type != NONE || local->privacy_invoked) &&
+           (encrypt_type == OTHER || local->host_decrypt))
+               val |= HFA384X_WEPFLAGS_HOSTDECRYPT;
+       else
+               val &= ~HFA384X_WEPFLAGS_HOSTDECRYPT;
+
+       if (val != old_val &&
+           hostap_set_word(local->dev, HFA384X_RID_CNFWEPFLAGS, val)) {
+               printk(KERN_DEBUG "Could not write new WEP flags (0x%x)\n",
+                      val);
+               goto fail;
+       }
+
+       if (encrypt_type != WEP)
+               return 0;
+
+       /* 104-bit support seems to require that all the keys are set to the
+        * same keylen */
+       keylen = 6; /* first 5 octets */
+       len = local->crypt[idx]->ops->get_key(keybuf, sizeof(keybuf),
+                                             NULL, local->crypt[idx]->priv);
+       if (idx >= 0 && idx < WEP_KEYS && len > 5)
+               keylen = WEP_KEY_LEN + 1; /* first 13 octets */
+
+       for (i = 0; i < WEP_KEYS; i++) {
+               memset(keybuf, 0, sizeof(keybuf));
+               if (local->crypt[i]) {
+                       (void) local->crypt[i]->ops->get_key(
+                               keybuf, sizeof(keybuf),
+                               NULL, local->crypt[i]->priv);
+               }
+               if (local->func->set_rid(local->dev,
+                                        HFA384X_RID_CNFDEFAULTKEY0 + i,
+                                        keybuf, keylen)) {
+                       printk(KERN_DEBUG "Could not set key %d (len=%d)\n",
+                              i, keylen);
+                       goto fail;
+               }
+       }
+       if (hostap_set_word(local->dev, HFA384X_RID_CNFWEPDEFAULTKEYID, idx)) {
+               printk(KERN_DEBUG "Could not set default keyid %d\n", idx);
+               goto fail;
+       }
+
+       return 0;
+
+ fail:
+       printk(KERN_DEBUG "%s: encryption setup failed\n", local->dev->name);
+       return -1;
+}
+
+
+int hostap_set_antsel(local_info_t *local)
+{
+       u16 val;
+       int ret = 0;
+
+       if (local->antsel_tx != HOSTAP_ANTSEL_DO_NOT_TOUCH &&
+           local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF,
+                            HFA386X_CR_TX_CONFIGURE,
+                            NULL, &val) == 0) {
+               val &= ~(BIT(2) | BIT(1));
+               switch (local->antsel_tx) {
+               case HOSTAP_ANTSEL_DIVERSITY:
+                       val |= BIT(1);
+                       break;
+               case HOSTAP_ANTSEL_LOW:
+                       break;
+               case HOSTAP_ANTSEL_HIGH:
+                       val |= BIT(2);
+                       break;
+               }
+
+               if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF,
+                                    HFA386X_CR_TX_CONFIGURE, &val, NULL)) {
+                       printk(KERN_INFO "%s: setting TX AntSel failed\n",
+                              local->dev->name);
+                       ret = -1;
+               }
+       }
+
+       if (local->antsel_rx != HOSTAP_ANTSEL_DO_NOT_TOUCH &&
+           local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF,
+                            HFA386X_CR_RX_CONFIGURE,
+                            NULL, &val) == 0) {
+               val &= ~(BIT(1) | BIT(0));
+               switch (local->antsel_rx) {
+               case HOSTAP_ANTSEL_DIVERSITY:
+                       break;
+               case HOSTAP_ANTSEL_LOW:
+                       val |= BIT(0);
+                       break;
+               case HOSTAP_ANTSEL_HIGH:
+                       val |= BIT(0) | BIT(1);
+                       break;
+               }
+
+               if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF,
+                                    HFA386X_CR_RX_CONFIGURE, &val, NULL)) {
+                       printk(KERN_INFO "%s: setting RX AntSel failed\n",
+                              local->dev->name);
+                       ret = -1;
+               }
+       }
+
+       return ret;
+}
+
+
+int hostap_set_roaming(local_info_t *local)
+{
+       u16 val;
+
+       switch (local->host_roaming) {
+       case 1:
+               val = HFA384X_ROAMING_HOST;
+               break;
+       case 2:
+               val = HFA384X_ROAMING_DISABLED;
+               break;
+       case 0:
+       default:
+               val = HFA384X_ROAMING_FIRMWARE;
+               break;
+       }
+
+       return hostap_set_word(local->dev, HFA384X_RID_CNFROAMINGMODE, val);
+}
+
+
+int hostap_set_auth_algs(local_info_t *local)
+{
+       int val = local->auth_algs;
+       /* At least STA f/w v0.6.2 seems to have issues with cnfAuthentication
+        * set to include both Open and Shared Key flags. It tries to use
+        * Shared Key authentication in that case even if WEP keys are not
+        * configured.. STA f/w v0.7.6 is able to handle such configuration,
+        * but it is unknown when this was fixed between 0.6.2 .. 0.7.6. */
+       if (local->sta_fw_ver < PRISM2_FW_VER(0,7,0) &&
+           val != PRISM2_AUTH_OPEN && val != PRISM2_AUTH_SHARED_KEY)
+               val = PRISM2_AUTH_OPEN;
+
+       if (hostap_set_word(local->dev, HFA384X_RID_CNFAUTHENTICATION, val)) {
+               printk(KERN_INFO "%s: cnfAuthentication setting to 0x%x "
+                      "failed\n", local->dev->name, local->auth_algs);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
+void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx)
+{
+       u16 status, fc;
+
+       status = __le16_to_cpu(rx->status);
+
+       printk(KERN_DEBUG "%s: RX status=0x%04x (port=%d, type=%d, "
+              "fcserr=%d) silence=%d signal=%d rate=%d rxflow=%d; "
+              "jiffies=%ld\n",
+              name, status, (status >> 8) & 0x07, status >> 13, status & 1,
+              rx->silence, rx->signal, rx->rate, rx->rxflow, jiffies);
+
+       fc = __le16_to_cpu(rx->frame_control);
+       printk(KERN_DEBUG "   FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x "
+              "data_len=%d%s%s\n",
+              fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4,
+              __le16_to_cpu(rx->duration_id), __le16_to_cpu(rx->seq_ctrl),
+              __le16_to_cpu(rx->data_len),
+              fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
+              fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
+
+       printk(KERN_DEBUG "   A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4="
+              MACSTR "\n",
+              MAC2STR(rx->addr1), MAC2STR(rx->addr2), MAC2STR(rx->addr3),
+              MAC2STR(rx->addr4));
+
+       printk(KERN_DEBUG "   dst=" MACSTR " src=" MACSTR " len=%d\n",
+              MAC2STR(rx->dst_addr), MAC2STR(rx->src_addr),
+              __be16_to_cpu(rx->len));
+}
+
+
+void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx)
+{
+       u16 fc;
+
+       printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d "
+              "tx_control=0x%04x; jiffies=%ld\n",
+              name, __le16_to_cpu(tx->status), tx->retry_count, tx->tx_rate,
+              __le16_to_cpu(tx->tx_control), jiffies);
+
+       fc = __le16_to_cpu(tx->frame_control);
+       printk(KERN_DEBUG "   FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x "
+              "data_len=%d%s%s\n",
+              fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4,
+              __le16_to_cpu(tx->duration_id), __le16_to_cpu(tx->seq_ctrl),
+              __le16_to_cpu(tx->data_len),
+              fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
+              fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
+
+       printk(KERN_DEBUG "   A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4="
+              MACSTR "\n",
+              MAC2STR(tx->addr1), MAC2STR(tx->addr2), MAC2STR(tx->addr3),
+              MAC2STR(tx->addr4));
+
+       printk(KERN_DEBUG "   dst=" MACSTR " src=" MACSTR " len=%d\n",
+              MAC2STR(tx->dst_addr), MAC2STR(tx->src_addr),
+              __be16_to_cpu(tx->len));
+}
+
+
+int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr)
+{
+       memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); /* addr2 */
+       return ETH_ALEN;
+}
+
+
+int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr)
+{
+       if (*(u32 *)skb->mac.raw == LWNG_CAP_DID_BASE) {
+               memcpy(haddr, skb->mac.raw +
+                      sizeof(struct linux_wlan_ng_prism_hdr) + 10,
+                      ETH_ALEN); /* addr2 */
+       } else { /* (*(u32 *)skb->mac.raw == htonl(LWNG_CAPHDR_VERSION)) */
+               memcpy(haddr, skb->mac.raw +
+                      sizeof(struct linux_wlan_ng_cap_hdr) + 10,
+                      ETH_ALEN); /* addr2 */
+       }
+       return ETH_ALEN;
+}
+
+
+int hostap_80211_get_hdrlen(u16 fc)
+{
+       int hdrlen = 24;
+
+       switch (WLAN_FC_GET_TYPE(fc)) {
+       case IEEE80211_FTYPE_DATA:
+               if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
+                       hdrlen = 30; /* Addr4 */
+               break;
+       case IEEE80211_FTYPE_CTL:
+               switch (WLAN_FC_GET_STYPE(fc)) {
+               case IEEE80211_STYPE_CTS:
+               case IEEE80211_STYPE_ACK:
+                       hdrlen = 10;
+                       break;
+               default:
+                       hdrlen = 16;
+                       break;
+               }
+               break;
+       }
+
+       return hdrlen;
+}
+
+
+struct net_device_stats *hostap_get_stats(struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       iface = netdev_priv(dev);
+       return &iface->stats;
+}
+
+
+static int prism2_close(struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       PDEBUG(DEBUG_FLOW, "%s: prism2_close\n", dev->name);
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (dev == local->ddev) {
+               prism2_sta_deauth(local, WLAN_REASON_DEAUTH_LEAVING);
+       }
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+       if (!local->hostapd && dev == local->dev &&
+           (!local->func->card_present || local->func->card_present(local)) &&
+           local->hw_ready && local->ap && local->iw_mode == IW_MODE_MASTER)
+               hostap_deauth_all_stas(dev, local->ap, 1);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+       if (local->func->dev_close && local->func->dev_close(local))
+               return 0;
+
+       if (dev == local->dev) {
+               local->func->hw_shutdown(dev, HOSTAP_HW_ENABLE_CMDCOMPL);
+       }
+
+       if (netif_running(dev)) {
+               netif_stop_queue(dev);
+               netif_device_detach(dev);
+       }
+
+       flush_scheduled_work();
+
+       module_put(local->hw_module);
+
+       local->num_dev_open--;
+
+       if (dev != local->dev && local->dev->flags & IFF_UP &&
+           local->master_dev_auto_open && local->num_dev_open == 1) {
+               /* Close master radio interface automatically if it was also
+                * opened automatically and we are now closing the last
+                * remaining non-master device. */
+               dev_close(local->dev);
+       }
+
+       return 0;
+}
+
+
+static int prism2_open(struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       PDEBUG(DEBUG_FLOW, "%s: prism2_open\n", dev->name);
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->no_pri) {
+               printk(KERN_DEBUG "%s: could not set interface UP - no PRI "
+                      "f/w\n", dev->name);
+               return 1;
+       }
+
+       if ((local->func->card_present && !local->func->card_present(local)) ||
+           local->hw_downloading)
+               return -ENODEV;
+
+       if (local->func->dev_open && local->func->dev_open(local))
+               return 1;
+
+       if (!try_module_get(local->hw_module))
+               return -ENODEV;
+       local->num_dev_open++;
+
+       if (!local->dev_enabled && local->func->hw_enable(dev, 1)) {
+               printk(KERN_WARNING "%s: could not enable MAC port\n",
+                      dev->name);
+               prism2_close(dev);
+               return 1;
+       }
+       if (!local->dev_enabled)
+               prism2_callback(local, PRISM2_CALLBACK_ENABLE);
+       local->dev_enabled = 1;
+
+       if (dev != local->dev && !(local->dev->flags & IFF_UP)) {
+               /* Master radio interface is needed for all operation, so open
+                * it automatically when any virtual net_device is opened. */
+               local->master_dev_auto_open = 1;
+               dev_open(local->dev);
+       }
+
+       netif_device_attach(dev);
+       netif_start_queue(dev);
+
+       return 0;
+}
+
+
+static int prism2_set_mac_address(struct net_device *dev, void *p)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       struct list_head *ptr;
+       struct sockaddr *addr = p;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->func->set_rid(dev, HFA384X_RID_CNFOWNMACADDR, addr->sa_data,
+                                ETH_ALEN) < 0 || local->func->reset_port(dev))
+               return -EINVAL;
+
+       read_lock_bh(&local->iface_lock);
+       list_for_each(ptr, &local->hostap_interfaces) {
+               iface = list_entry(ptr, struct hostap_interface, list);
+               memcpy(iface->dev->dev_addr, addr->sa_data, ETH_ALEN);
+       }
+       memcpy(local->dev->dev_addr, addr->sa_data, ETH_ALEN);
+       read_unlock_bh(&local->iface_lock);
+
+       return 0;
+}
+
+
+/* TODO: to be further implemented as soon as Prism2 fully supports
+ *       GroupAddresses and correct documentation is available */
+void hostap_set_multicast_list_queue(void *data)
+{
+       struct net_device *dev = (struct net_device *) data;
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+       if (hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE,
+                           local->is_promisc)) {
+               printk(KERN_INFO "%s: %sabling promiscuous mode failed\n",
+                      dev->name, local->is_promisc ? "en" : "dis");
+       }
+}
+
+
+static void hostap_set_multicast_list(struct net_device *dev)
+{
+#if 0
+       /* FIX: promiscuous mode seems to be causing a lot of problems with
+        * some station firmware versions (FCSErr frames, invalid MACPort, etc.
+        * corrupted incoming frames). This code is now commented out while the
+        * problems are investigated. */
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+       if ((dev->flags & IFF_ALLMULTI) || (dev->flags & IFF_PROMISC)) {
+               local->is_promisc = 1;
+       } else {
+               local->is_promisc = 0;
+       }
+
+       schedule_work(&local->set_multicast_list_queue);
+#endif
+}
+
+
+static int prism2_change_mtu(struct net_device *dev, int new_mtu)
+{
+       if (new_mtu < PRISM2_MIN_MTU || new_mtu > PRISM2_MAX_MTU)
+               return -EINVAL;
+
+       dev->mtu = new_mtu;
+       return 0;
+}
+
+
+static void prism2_tx_timeout(struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       struct hfa384x_regs regs;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       printk(KERN_WARNING "%s Tx timed out! Resetting card\n", dev->name);
+       netif_stop_queue(local->dev);
+
+       local->func->read_regs(dev, &regs);
+       printk(KERN_DEBUG "%s: CMD=%04x EVSTAT=%04x "
+              "OFFSET0=%04x OFFSET1=%04x SWSUPPORT0=%04x\n",
+              dev->name, regs.cmd, regs.evstat, regs.offset0, regs.offset1,
+              regs.swsupport0);
+
+       local->func->schedule_reset(local);
+}
+
+
+void hostap_setup_dev(struct net_device *dev, local_info_t *local,
+                     int main_dev)
+{
+       struct hostap_interface *iface;
+
+       iface = netdev_priv(dev);
+       ether_setup(dev);
+
+       /* kernel callbacks */
+       dev->get_stats = hostap_get_stats;
+       if (iface) {
+               /* Currently, we point to the proper spy_data only on
+                * the main_dev. This could be fixed. Jean II */
+               iface->wireless_data.spy_data = &iface->spy_data;
+               dev->wireless_data = &iface->wireless_data;
+       }
+       dev->wireless_handlers =
+               (struct iw_handler_def *) &hostap_iw_handler_def;
+       dev->do_ioctl = hostap_ioctl;
+       dev->open = prism2_open;
+       dev->stop = prism2_close;
+       dev->hard_start_xmit = hostap_data_start_xmit;
+       dev->set_mac_address = prism2_set_mac_address;
+       dev->set_multicast_list = hostap_set_multicast_list;
+       dev->change_mtu = prism2_change_mtu;
+       dev->tx_timeout = prism2_tx_timeout;
+       dev->watchdog_timeo = TX_TIMEOUT;
+
+       dev->mtu = local->mtu;
+       if (!main_dev) {
+               /* use main radio device queue */
+               dev->tx_queue_len = 0;
+       }
+
+       SET_ETHTOOL_OPS(dev, &prism2_ethtool_ops);
+
+       netif_stop_queue(dev);
+}
+
+
+static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked)
+{
+       struct net_device *dev = local->dev;
+
+       if (local->apdev)
+               return -EEXIST;
+
+       printk(KERN_DEBUG "%s: enabling hostapd mode\n", dev->name);
+
+       local->apdev = hostap_add_interface(local, HOSTAP_INTERFACE_AP,
+                                           rtnl_locked, local->ddev->name,
+                                           "ap");
+       if (local->apdev == NULL)
+               return -ENOMEM;
+
+       local->apdev->hard_start_xmit = hostap_mgmt_start_xmit;
+       local->apdev->type = ARPHRD_IEEE80211;
+       local->apdev->hard_header_parse = hostap_80211_header_parse;
+
+       return 0;
+}
+
+
+static int hostap_disable_hostapd(local_info_t *local, int rtnl_locked)
+{
+       struct net_device *dev = local->dev;
+
+       printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name);
+
+       hostap_remove_interface(local->apdev, rtnl_locked, 1);
+       local->apdev = NULL;
+
+       return 0;
+}
+
+
+static int hostap_enable_hostapd_sta(local_info_t *local, int rtnl_locked)
+{
+       struct net_device *dev = local->dev;
+
+       if (local->stadev)
+               return -EEXIST;
+
+       printk(KERN_DEBUG "%s: enabling hostapd STA mode\n", dev->name);
+
+       local->stadev = hostap_add_interface(local, HOSTAP_INTERFACE_STA,
+                                            rtnl_locked, local->ddev->name,
+                                            "sta");
+       if (local->stadev == NULL)
+               return -ENOMEM;
+
+       return 0;
+}
+
+
+static int hostap_disable_hostapd_sta(local_info_t *local, int rtnl_locked)
+{
+       struct net_device *dev = local->dev;
+
+       printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name);
+
+       hostap_remove_interface(local->stadev, rtnl_locked, 1);
+       local->stadev = NULL;
+
+       return 0;
+}
+
+
+int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked)
+{
+       int ret;
+
+       if (val < 0 || val > 1)
+               return -EINVAL;
+
+       if (local->hostapd == val)
+               return 0;
+
+       if (val) {
+               ret = hostap_enable_hostapd(local, rtnl_locked);
+               if (ret == 0)
+                       local->hostapd = 1;
+       } else {
+               local->hostapd = 0;
+               ret = hostap_disable_hostapd(local, rtnl_locked);
+               if (ret != 0)
+                       local->hostapd = 1;
+       }
+
+       return ret;
+}
+
+
+int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked)
+{
+       int ret;
+
+       if (val < 0 || val > 1)
+               return -EINVAL;
+
+       if (local->hostapd_sta == val)
+               return 0;
+
+       if (val) {
+               ret = hostap_enable_hostapd_sta(local, rtnl_locked);
+               if (ret == 0)
+                       local->hostapd_sta = 1;
+       } else {
+               local->hostapd_sta = 0;
+               ret = hostap_disable_hostapd_sta(local, rtnl_locked);
+               if (ret != 0)
+                       local->hostapd_sta = 1;
+       }
+
+
+       return ret;
+}
+
+
+int prism2_update_comms_qual(struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int ret = 0;
+       struct hfa384x_comms_quality sq;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+       if (!local->sta_fw_ver)
+               ret = -1;
+       else if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) {
+               if (local->func->get_rid(local->dev,
+                                        HFA384X_RID_DBMCOMMSQUALITY,
+                                        &sq, sizeof(sq), 1) >= 0) {
+                       local->comms_qual = (s16) le16_to_cpu(sq.comm_qual);
+                       local->avg_signal = (s16) le16_to_cpu(sq.signal_level);
+                       local->avg_noise = (s16) le16_to_cpu(sq.noise_level);
+                       local->last_comms_qual_update = jiffies;
+               } else
+                       ret = -1;
+       } else {
+               if (local->func->get_rid(local->dev, HFA384X_RID_COMMSQUALITY,
+                                        &sq, sizeof(sq), 1) >= 0) {
+                       local->comms_qual = le16_to_cpu(sq.comm_qual);
+                       local->avg_signal = HFA384X_LEVEL_TO_dBm(
+                               le16_to_cpu(sq.signal_level));
+                       local->avg_noise = HFA384X_LEVEL_TO_dBm(
+                               le16_to_cpu(sq.noise_level));
+                       local->last_comms_qual_update = jiffies;
+               } else
+                       ret = -1;
+       }
+
+       return ret;
+}
+
+
+int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype,
+                        u8 *body, size_t bodylen)
+{
+       struct sk_buff *skb;
+       struct hostap_ieee80211_mgmt *mgmt;
+       struct hostap_skb_tx_data *meta;
+       struct net_device *dev = local->dev;
+
+       skb = dev_alloc_skb(IEEE80211_MGMT_HDR_LEN + bodylen);
+       if (skb == NULL)
+               return -ENOMEM;
+
+       mgmt = (struct hostap_ieee80211_mgmt *)
+               skb_put(skb, IEEE80211_MGMT_HDR_LEN);
+       memset(mgmt, 0, IEEE80211_MGMT_HDR_LEN);
+       mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
+       memcpy(mgmt->da, dst, ETH_ALEN);
+       memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->bssid, dst, ETH_ALEN);
+       if (body)
+               memcpy(skb_put(skb, bodylen), body, bodylen);
+
+       meta = (struct hostap_skb_tx_data *) skb->cb;
+       memset(meta, 0, sizeof(*meta));
+       meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
+       meta->iface = netdev_priv(dev);
+
+       skb->dev = dev;
+       skb->mac.raw = skb->nh.raw = skb->data;
+       dev_queue_xmit(skb);
+
+       return 0;
+}
+
+
+int prism2_sta_deauth(local_info_t *local, u16 reason)
+{
+       union iwreq_data wrqu;
+       int ret;
+
+       if (local->iw_mode != IW_MODE_INFRA ||
+           memcmp(local->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0 ||
+           memcmp(local->bssid, "\x44\x44\x44\x44\x44\x44", ETH_ALEN) == 0)
+               return 0;
+
+       reason = cpu_to_le16(reason);
+       ret = prism2_sta_send_mgmt(local, local->bssid, IEEE80211_STYPE_DEAUTH,
+                                  (u8 *) &reason, 2);
+       memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+       wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL);
+       return ret;
+}
+
+
+struct proc_dir_entry *hostap_proc;
+
+static int __init hostap_init(void)
+{
+       if (proc_net != NULL) {
+               hostap_proc = proc_mkdir("hostap", proc_net);
+               if (!hostap_proc)
+                       printk(KERN_WARNING "Failed to mkdir "
+                              "/proc/net/hostap\n");
+       } else
+               hostap_proc = NULL;
+
+       return 0;
+}
+
+
+static void __exit hostap_exit(void)
+{
+       if (hostap_proc != NULL) {
+               hostap_proc = NULL;
+               remove_proc_entry("hostap", proc_net);
+       }
+}
+
+
+EXPORT_SYMBOL(hostap_set_word);
+EXPORT_SYMBOL(hostap_set_string);
+EXPORT_SYMBOL(hostap_get_porttype);
+EXPORT_SYMBOL(hostap_set_encryption);
+EXPORT_SYMBOL(hostap_set_antsel);
+EXPORT_SYMBOL(hostap_set_roaming);
+EXPORT_SYMBOL(hostap_set_auth_algs);
+EXPORT_SYMBOL(hostap_dump_rx_header);
+EXPORT_SYMBOL(hostap_dump_tx_header);
+EXPORT_SYMBOL(hostap_80211_header_parse);
+EXPORT_SYMBOL(hostap_80211_prism_header_parse);
+EXPORT_SYMBOL(hostap_80211_get_hdrlen);
+EXPORT_SYMBOL(hostap_get_stats);
+EXPORT_SYMBOL(hostap_setup_dev);
+EXPORT_SYMBOL(hostap_proc);
+EXPORT_SYMBOL(hostap_set_multicast_list_queue);
+EXPORT_SYMBOL(hostap_set_hostapd);
+EXPORT_SYMBOL(hostap_set_hostapd_sta);
+EXPORT_SYMBOL(hostap_add_interface);
+EXPORT_SYMBOL(hostap_remove_interface);
+EXPORT_SYMBOL(prism2_update_comms_qual);
+
+module_init(hostap_init);
+module_exit(hostap_exit);
diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h
new file mode 100644 (file)
index 0000000..5fac89b
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef HOSTAP_H
+#define HOSTAP_H
+
+/* hostap.c */
+
+extern struct proc_dir_entry *hostap_proc;
+
+u16 hostap_tx_callback_register(local_info_t *local,
+                               void (*func)(struct sk_buff *, int ok, void *),
+                               void *data);
+int hostap_tx_callback_unregister(local_info_t *local, u16 idx);
+int hostap_set_word(struct net_device *dev, int rid, u16 val);
+int hostap_set_string(struct net_device *dev, int rid, const char *val);
+u16 hostap_get_porttype(local_info_t *local);
+int hostap_set_encryption(local_info_t *local);
+int hostap_set_antsel(local_info_t *local);
+int hostap_set_roaming(local_info_t *local);
+int hostap_set_auth_algs(local_info_t *local);
+void hostap_dump_rx_header(const char *name,
+                          const struct hfa384x_rx_frame *rx);
+void hostap_dump_tx_header(const char *name,
+                          const struct hfa384x_tx_frame *tx);
+int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr);
+int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr);
+int hostap_80211_get_hdrlen(u16 fc);
+struct net_device_stats *hostap_get_stats(struct net_device *dev);
+void hostap_setup_dev(struct net_device *dev, local_info_t *local,
+                     int main_dev);
+void hostap_set_multicast_list_queue(void *data);
+int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked);
+int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked);
+void hostap_cleanup(local_info_t *local);
+void hostap_cleanup_handler(void *data);
+struct net_device * hostap_add_interface(struct local_info *local,
+                                        int type, int rtnl_locked,
+                                        const char *prefix, const char *name);
+void hostap_remove_interface(struct net_device *dev, int rtnl_locked,
+                            int remove_from_list);
+int prism2_update_comms_qual(struct net_device *dev);
+int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype,
+                        u8 *body, size_t bodylen);
+int prism2_sta_deauth(local_info_t *local, u16 reason);
+
+
+/* hostap_proc.c */
+
+void hostap_init_proc(local_info_t *local);
+void hostap_remove_proc(local_info_t *local);
+
+
+/* hostap_info.c */
+
+void hostap_info_init(local_info_t *local);
+void hostap_info_process(local_info_t *local, struct sk_buff *skb);
+
+
+#endif /* HOSTAP_H */
diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h
new file mode 100644 (file)
index 0000000..bf506f5
--- /dev/null
@@ -0,0 +1,96 @@
+#ifndef HOSTAP_80211_H
+#define HOSTAP_80211_H
+
+struct hostap_ieee80211_mgmt {
+       u16 frame_control;
+       u16 duration;
+       u8 da[6];
+       u8 sa[6];
+       u8 bssid[6];
+       u16 seq_ctrl;
+       union {
+               struct {
+                       u16 auth_alg;
+                       u16 auth_transaction;
+                       u16 status_code;
+                       /* possibly followed by Challenge text */
+                       u8 variable[0];
+               } __attribute__ ((packed)) auth;
+               struct {
+                       u16 reason_code;
+               } __attribute__ ((packed)) deauth;
+               struct {
+                       u16 capab_info;
+                       u16 listen_interval;
+                       /* followed by SSID and Supported rates */
+                       u8 variable[0];
+               } __attribute__ ((packed)) assoc_req;
+               struct {
+                       u16 capab_info;
+                       u16 status_code;
+                       u16 aid;
+                       /* followed by Supported rates */
+                       u8 variable[0];
+               } __attribute__ ((packed)) assoc_resp, reassoc_resp;
+               struct {
+                       u16 capab_info;
+                       u16 listen_interval;
+                       u8 current_ap[6];
+                       /* followed by SSID and Supported rates */
+                       u8 variable[0];
+               } __attribute__ ((packed)) reassoc_req;
+               struct {
+                       u16 reason_code;
+               } __attribute__ ((packed)) disassoc;
+               struct {
+               } __attribute__ ((packed)) probe_req;
+               struct {
+                       u8 timestamp[8];
+                       u16 beacon_int;
+                       u16 capab_info;
+                       /* followed by some of SSID, Supported rates,
+                        * FH Params, DS Params, CF Params, IBSS Params, TIM */
+                       u8 variable[0];
+               } __attribute__ ((packed)) beacon, probe_resp;
+       } u;
+} __attribute__ ((packed));
+
+
+#define IEEE80211_MGMT_HDR_LEN 24
+#define IEEE80211_DATA_HDR3_LEN 24
+#define IEEE80211_DATA_HDR4_LEN 30
+
+
+struct hostap_80211_rx_status {
+       u32 mac_time;
+       u8 signal;
+       u8 noise;
+       u16 rate; /* in 100 kbps */
+};
+
+
+void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
+                    struct hostap_80211_rx_status *rx_stats);
+
+
+/* prism2_rx_80211 'type' argument */
+enum {
+       PRISM2_RX_MONITOR, PRISM2_RX_MGMT, PRISM2_RX_NON_ASSOC,
+       PRISM2_RX_NULLFUNC_ACK
+};
+
+int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
+                   struct hostap_80211_rx_status *rx_stats, int type);
+void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
+                    struct hostap_80211_rx_status *rx_stats);
+void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
+                         struct hostap_80211_rx_status *rx_stats);
+
+void hostap_dump_tx_80211(const char *name, struct sk_buff *skb);
+int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev);
+int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev);
+struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
+                                  struct ieee80211_crypt_data *crypt);
+int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
+
+#endif /* HOSTAP_80211_H */
diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c
new file mode 100644 (file)
index 0000000..b050124
--- /dev/null
@@ -0,0 +1,1091 @@
+#include <linux/etherdevice.h>
+
+#include "hostap_80211.h"
+#include "hostap.h"
+
+void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
+                         struct hostap_80211_rx_status *rx_stats)
+{
+       struct ieee80211_hdr *hdr;
+       u16 fc;
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+
+       printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d "
+              "jiffies=%ld\n",
+              name, rx_stats->signal, rx_stats->noise, rx_stats->rate,
+              skb->len, jiffies);
+
+       if (skb->len < 2)
+               return;
+
+       fc = le16_to_cpu(hdr->frame_ctl);
+       printk(KERN_DEBUG "   FC=0x%04x (type=%d:%d)%s%s",
+              fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4,
+              fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
+              fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
+
+       if (skb->len < IEEE80211_DATA_HDR3_LEN) {
+               printk("\n");
+               return;
+       }
+
+       printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
+              le16_to_cpu(hdr->seq_ctl));
+
+       printk(KERN_DEBUG "   A1=" MACSTR " A2=" MACSTR " A3=" MACSTR,
+              MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3));
+       if (skb->len >= 30)
+               printk(" A4=" MACSTR, MAC2STR(hdr->addr4));
+       printk("\n");
+}
+
+
+/* Send RX frame to netif with 802.11 (and possible prism) header.
+ * Called from hardware or software IRQ context. */
+int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
+                   struct hostap_80211_rx_status *rx_stats, int type)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int hdrlen, phdrlen, head_need, tail_need;
+       u16 fc;
+       int prism_header, ret;
+       struct ieee80211_hdr *hdr;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+       dev->last_rx = jiffies;
+
+       if (dev->type == ARPHRD_IEEE80211_PRISM) {
+               if (local->monitor_type == PRISM2_MONITOR_PRISM) {
+                       prism_header = 1;
+                       phdrlen = sizeof(struct linux_wlan_ng_prism_hdr);
+               } else { /* local->monitor_type == PRISM2_MONITOR_CAPHDR */
+                       prism_header = 2;
+                       phdrlen = sizeof(struct linux_wlan_ng_cap_hdr);
+               }
+       } else {
+               prism_header = 0;
+               phdrlen = 0;
+       }
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       fc = le16_to_cpu(hdr->frame_ctl);
+
+       if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) {
+               printk(KERN_DEBUG "%s: dropped management frame with header "
+                      "version %d\n", dev->name, fc & IEEE80211_FCTL_VERS);
+               dev_kfree_skb_any(skb);
+               return 0;
+       }
+
+       hdrlen = hostap_80211_get_hdrlen(fc);
+
+       /* check if there is enough room for extra data; if not, expand skb
+        * buffer to be large enough for the changes */
+       head_need = phdrlen;
+       tail_need = 0;
+#ifdef PRISM2_ADD_BOGUS_CRC
+       tail_need += 4;
+#endif /* PRISM2_ADD_BOGUS_CRC */
+
+       head_need -= skb_headroom(skb);
+       tail_need -= skb_tailroom(skb);
+
+       if (head_need > 0 || tail_need > 0) {
+               if (pskb_expand_head(skb, head_need > 0 ? head_need : 0,
+                                    tail_need > 0 ? tail_need : 0,
+                                    GFP_ATOMIC)) {
+                       printk(KERN_DEBUG "%s: prism2_rx_80211 failed to "
+                              "reallocate skb buffer\n", dev->name);
+                       dev_kfree_skb_any(skb);
+                       return 0;
+               }
+       }
+
+       /* We now have an skb with enough head and tail room, so just insert
+        * the extra data */
+
+#ifdef PRISM2_ADD_BOGUS_CRC
+       memset(skb_put(skb, 4), 0xff, 4); /* Prism2 strips CRC */
+#endif /* PRISM2_ADD_BOGUS_CRC */
+
+       if (prism_header == 1) {
+               struct linux_wlan_ng_prism_hdr *hdr;
+               hdr = (struct linux_wlan_ng_prism_hdr *)
+                       skb_push(skb, phdrlen);
+               memset(hdr, 0, phdrlen);
+               hdr->msgcode = LWNG_CAP_DID_BASE;
+               hdr->msglen = sizeof(*hdr);
+               memcpy(hdr->devname, dev->name, sizeof(hdr->devname));
+#define LWNG_SETVAL(f,i,s,l,d) \
+hdr->f.did = LWNG_CAP_DID_BASE | (i << 12); \
+hdr->f.status = s; hdr->f.len = l; hdr->f.data = d
+               LWNG_SETVAL(hosttime, 1, 0, 4, jiffies);
+               LWNG_SETVAL(mactime, 2, 0, 4, rx_stats->mac_time);
+               LWNG_SETVAL(channel, 3, 1 /* no value */, 4, 0);
+               LWNG_SETVAL(rssi, 4, 1 /* no value */, 4, 0);
+               LWNG_SETVAL(sq, 5, 1 /* no value */, 4, 0);
+               LWNG_SETVAL(signal, 6, 0, 4, rx_stats->signal);
+               LWNG_SETVAL(noise, 7, 0, 4, rx_stats->noise);
+               LWNG_SETVAL(rate, 8, 0, 4, rx_stats->rate / 5);
+               LWNG_SETVAL(istx, 9, 0, 4, 0);
+               LWNG_SETVAL(frmlen, 10, 0, 4, skb->len - phdrlen);
+#undef LWNG_SETVAL
+       } else if (prism_header == 2) {
+               struct linux_wlan_ng_cap_hdr *hdr;
+               hdr = (struct linux_wlan_ng_cap_hdr *)
+                       skb_push(skb, phdrlen);
+               memset(hdr, 0, phdrlen);
+               hdr->version    = htonl(LWNG_CAPHDR_VERSION);
+               hdr->length     = htonl(phdrlen);
+               hdr->mactime    = __cpu_to_be64(rx_stats->mac_time);
+               hdr->hosttime   = __cpu_to_be64(jiffies);
+               hdr->phytype    = htonl(4); /* dss_dot11_b */
+               hdr->channel    = htonl(local->channel);
+               hdr->datarate   = htonl(rx_stats->rate);
+               hdr->antenna    = htonl(0); /* unknown */
+               hdr->priority   = htonl(0); /* unknown */
+               hdr->ssi_type   = htonl(3); /* raw */
+               hdr->ssi_signal = htonl(rx_stats->signal);
+               hdr->ssi_noise  = htonl(rx_stats->noise);
+               hdr->preamble   = htonl(0); /* unknown */
+               hdr->encoding   = htonl(1); /* cck */
+       }
+
+       ret = skb->len - phdrlen;
+       skb->dev = dev;
+       skb->mac.raw = skb->data;
+       skb_pull(skb, hdrlen);
+       if (prism_header)
+               skb_pull(skb, phdrlen);
+       skb->pkt_type = PACKET_OTHERHOST;
+       skb->protocol = __constant_htons(ETH_P_802_2);
+       memset(skb->cb, 0, sizeof(skb->cb));
+       netif_rx(skb);
+
+       return ret;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void monitor_rx(struct net_device *dev, struct sk_buff *skb,
+                      struct hostap_80211_rx_status *rx_stats)
+{
+       struct net_device_stats *stats;
+       int len;
+
+       len = prism2_rx_80211(dev, skb, rx_stats, PRISM2_RX_MONITOR);
+       stats = hostap_get_stats(dev);
+       stats->rx_packets++;
+       stats->rx_bytes += len;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static struct prism2_frag_entry *
+prism2_frag_cache_find(local_info_t *local, unsigned int seq,
+                      unsigned int frag, u8 *src, u8 *dst)
+{
+       struct prism2_frag_entry *entry;
+       int i;
+
+       for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) {
+               entry = &local->frag_cache[i];
+               if (entry->skb != NULL &&
+                   time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
+                       printk(KERN_DEBUG "%s: expiring fragment cache entry "
+                              "seq=%u last_frag=%u\n",
+                              local->dev->name, entry->seq, entry->last_frag);
+                       dev_kfree_skb(entry->skb);
+                       entry->skb = NULL;
+               }
+
+               if (entry->skb != NULL && entry->seq == seq &&
+                   (entry->last_frag + 1 == frag || frag == -1) &&
+                   memcmp(entry->src_addr, src, ETH_ALEN) == 0 &&
+                   memcmp(entry->dst_addr, dst, ETH_ALEN) == 0)
+                       return entry;
+       }
+
+       return NULL;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static struct sk_buff *
+prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr)
+{
+       struct sk_buff *skb = NULL;
+       u16 sc;
+       unsigned int frag, seq;
+       struct prism2_frag_entry *entry;
+
+       sc = le16_to_cpu(hdr->seq_ctl);
+       frag = WLAN_GET_SEQ_FRAG(sc);
+       seq = WLAN_GET_SEQ_SEQ(sc) >> 4;
+
+       if (frag == 0) {
+               /* Reserve enough space to fit maximum frame length */
+               skb = dev_alloc_skb(local->dev->mtu +
+                                   sizeof(struct ieee80211_hdr) +
+                                   8 /* LLC */ +
+                                   2 /* alignment */ +
+                                   8 /* WEP */ + ETH_ALEN /* WDS */);
+               if (skb == NULL)
+                       return NULL;
+
+               entry = &local->frag_cache[local->frag_next_idx];
+               local->frag_next_idx++;
+               if (local->frag_next_idx >= PRISM2_FRAG_CACHE_LEN)
+                       local->frag_next_idx = 0;
+
+               if (entry->skb != NULL)
+                       dev_kfree_skb(entry->skb);
+
+               entry->first_frag_time = jiffies;
+               entry->seq = seq;
+               entry->last_frag = frag;
+               entry->skb = skb;
+               memcpy(entry->src_addr, hdr->addr2, ETH_ALEN);
+               memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN);
+       } else {
+               /* received a fragment of a frame for which the head fragment
+                * should have already been received */
+               entry = prism2_frag_cache_find(local, seq, frag, hdr->addr2,
+                                              hdr->addr1);
+               if (entry != NULL) {
+                       entry->last_frag = frag;
+                       skb = entry->skb;
+               }
+       }
+
+       return skb;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static int prism2_frag_cache_invalidate(local_info_t *local,
+                                       struct ieee80211_hdr *hdr)
+{
+       u16 sc;
+       unsigned int seq;
+       struct prism2_frag_entry *entry;
+
+       sc = le16_to_cpu(hdr->seq_ctl);
+       seq = WLAN_GET_SEQ_SEQ(sc) >> 4;
+
+       entry = prism2_frag_cache_find(local, seq, -1, hdr->addr2, hdr->addr1);
+
+       if (entry == NULL) {
+               printk(KERN_DEBUG "%s: could not invalidate fragment cache "
+                      "entry (seq=%u)\n",
+                      local->dev->name, seq);
+               return -1;
+       }
+
+       entry->skb = NULL;
+       return 0;
+}
+
+
+static struct hostap_bss_info *__hostap_get_bss(local_info_t *local, u8 *bssid,
+                                               u8 *ssid, size_t ssid_len)
+{
+       struct list_head *ptr;
+       struct hostap_bss_info *bss;
+
+       list_for_each(ptr, &local->bss_list) {
+               bss = list_entry(ptr, struct hostap_bss_info, list);
+               if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
+                   (ssid == NULL ||
+                    (ssid_len == bss->ssid_len &&
+                     memcmp(ssid, bss->ssid, ssid_len) == 0))) {
+                       list_move(&bss->list, &local->bss_list);
+                       return bss;
+               }
+       }
+
+       return NULL;
+}
+
+
+static struct hostap_bss_info *__hostap_add_bss(local_info_t *local, u8 *bssid,
+                                               u8 *ssid, size_t ssid_len)
+{
+       struct hostap_bss_info *bss;
+
+       if (local->num_bss_info >= HOSTAP_MAX_BSS_COUNT) {
+               bss = list_entry(local->bss_list.prev,
+                                struct hostap_bss_info, list);
+               list_del(&bss->list);
+               local->num_bss_info--;
+       } else {
+               bss = (struct hostap_bss_info *)
+                       kmalloc(sizeof(*bss), GFP_ATOMIC);
+               if (bss == NULL)
+                       return NULL;
+       }
+
+       memset(bss, 0, sizeof(*bss));
+       memcpy(bss->bssid, bssid, ETH_ALEN);
+       memcpy(bss->ssid, ssid, ssid_len);
+       bss->ssid_len = ssid_len;
+       local->num_bss_info++;
+       list_add(&bss->list, &local->bss_list);
+       return bss;
+}
+
+
+static void __hostap_expire_bss(local_info_t *local)
+{
+       struct hostap_bss_info *bss;
+
+       while (local->num_bss_info > 0) {
+               bss = list_entry(local->bss_list.prev,
+                                struct hostap_bss_info, list);
+               if (!time_after(jiffies, bss->last_update + 60 * HZ))
+                       break;
+
+               list_del(&bss->list);
+               local->num_bss_info--;
+               kfree(bss);
+       }
+}
+
+
+/* Both IEEE 802.11 Beacon and Probe Response frames have similar structure, so
+ * the same routine can be used to parse both of them. */
+static void hostap_rx_sta_beacon(local_info_t *local, struct sk_buff *skb,
+                                int stype)
+{
+       struct hostap_ieee80211_mgmt *mgmt;
+       int left, chan = 0;
+       u8 *pos;
+       u8 *ssid = NULL, *wpa = NULL, *rsn = NULL;
+       size_t ssid_len = 0, wpa_len = 0, rsn_len = 0;
+       struct hostap_bss_info *bss;
+
+       if (skb->len < IEEE80211_MGMT_HDR_LEN + sizeof(mgmt->u.beacon))
+               return;
+
+       mgmt = (struct hostap_ieee80211_mgmt *) skb->data;
+       pos = mgmt->u.beacon.variable;
+       left = skb->len - (pos - skb->data);
+
+       while (left >= 2) {
+               if (2 + pos[1] > left)
+                       return; /* parse failed */
+               switch (*pos) {
+               case WLAN_EID_SSID:
+                       ssid = pos + 2;
+                       ssid_len = pos[1];
+                       break;
+               case WLAN_EID_GENERIC:
+                       if (pos[1] >= 4 &&
+                           pos[2] == 0x00 && pos[3] == 0x50 &&
+                           pos[4] == 0xf2 && pos[5] == 1) {
+                               wpa = pos;
+                               wpa_len = pos[1] + 2;
+                       }
+                       break;
+               case WLAN_EID_RSN:
+                       rsn = pos;
+                       rsn_len = pos[1] + 2;
+                       break;
+               case WLAN_EID_DS_PARAMS:
+                       if (pos[1] >= 1)
+                               chan = pos[2];
+                       break;
+               }
+               left -= 2 + pos[1];
+               pos += 2 + pos[1];
+       }
+
+       if (wpa_len > MAX_WPA_IE_LEN)
+               wpa_len = MAX_WPA_IE_LEN;
+       if (rsn_len > MAX_WPA_IE_LEN)
+               rsn_len = MAX_WPA_IE_LEN;
+       if (ssid_len > sizeof(bss->ssid))
+               ssid_len = sizeof(bss->ssid);
+
+       spin_lock(&local->lock);
+       bss = __hostap_get_bss(local, mgmt->bssid, ssid, ssid_len);
+       if (bss == NULL)
+               bss = __hostap_add_bss(local, mgmt->bssid, ssid, ssid_len);
+       if (bss) {
+               bss->last_update = jiffies;
+               bss->count++;
+               bss->capab_info = le16_to_cpu(mgmt->u.beacon.capab_info);
+               if (wpa) {
+                       memcpy(bss->wpa_ie, wpa, wpa_len);
+                       bss->wpa_ie_len = wpa_len;
+               } else
+                       bss->wpa_ie_len = 0;
+               if (rsn) {
+                       memcpy(bss->rsn_ie, rsn, rsn_len);
+                       bss->rsn_ie_len = rsn_len;
+               } else
+                       bss->rsn_ie_len = 0;
+               bss->chan = chan;
+       }
+       __hostap_expire_bss(local);
+       spin_unlock(&local->lock);
+}
+
+
+static inline int
+hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb,
+                    struct hostap_80211_rx_status *rx_stats, u16 type,
+                    u16 stype)
+{
+       if (local->iw_mode == IW_MODE_MASTER) {
+               hostap_update_sta_ps(local, (struct ieee80211_hdr *)
+                                    skb->data);
+       }
+
+       if (local->hostapd && type == IEEE80211_FTYPE_MGMT) {
+               if (stype == IEEE80211_STYPE_BEACON &&
+                   local->iw_mode == IW_MODE_MASTER) {
+                       struct sk_buff *skb2;
+                       /* Process beacon frames also in kernel driver to
+                        * update STA(AP) table statistics */
+                       skb2 = skb_clone(skb, GFP_ATOMIC);
+                       if (skb2)
+                               hostap_rx(skb2->dev, skb2, rx_stats);
+               }
+
+               /* send management frames to the user space daemon for
+                * processing */
+               local->apdevstats.rx_packets++;
+               local->apdevstats.rx_bytes += skb->len;
+               if (local->apdev == NULL)
+                       return -1;
+               prism2_rx_80211(local->apdev, skb, rx_stats, PRISM2_RX_MGMT);
+               return 0;
+       }
+
+       if (local->iw_mode == IW_MODE_MASTER) {
+               if (type != IEEE80211_FTYPE_MGMT &&
+                   type != IEEE80211_FTYPE_CTL) {
+                       printk(KERN_DEBUG "%s: unknown management frame "
+                              "(type=0x%02x, stype=0x%02x) dropped\n",
+                              skb->dev->name, type >> 2, stype >> 4);
+                       return -1;
+               }
+
+               hostap_rx(skb->dev, skb, rx_stats);
+               return 0;
+       } else if (type == IEEE80211_FTYPE_MGMT &&
+                  (stype == IEEE80211_STYPE_BEACON ||
+                   stype == IEEE80211_STYPE_PROBE_RESP)) {
+               hostap_rx_sta_beacon(local, skb, stype);
+               return -1;
+       } else if (type == IEEE80211_FTYPE_MGMT &&
+                  (stype == IEEE80211_STYPE_ASSOC_RESP ||
+                   stype == IEEE80211_STYPE_REASSOC_RESP)) {
+               /* Ignore (Re)AssocResp silently since these are not currently
+                * needed but are still received when WPA/RSN mode is enabled.
+                */
+               return -1;
+       } else {
+               printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: dropped unhandled"
+                      " management frame in non-Host AP mode (type=%d:%d)\n",
+                      skb->dev->name, type >> 2, stype >> 4);
+               return -1;
+       }
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static inline struct net_device *prism2_rx_get_wds(local_info_t *local,
+                                                  u8 *addr)
+{
+       struct hostap_interface *iface = NULL;
+       struct list_head *ptr;
+
+       read_lock_bh(&local->iface_lock);
+       list_for_each(ptr, &local->hostap_interfaces) {
+               iface = list_entry(ptr, struct hostap_interface, list);
+               if (iface->type == HOSTAP_INTERFACE_WDS &&
+                   memcmp(iface->u.wds.remote_addr, addr, ETH_ALEN) == 0)
+                       break;
+               iface = NULL;
+       }
+       read_unlock_bh(&local->iface_lock);
+
+       return iface ? iface->dev : NULL;
+}
+
+
+static inline int
+hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr *hdr,
+                   u16 fc, struct net_device **wds)
+{
+       /* FIX: is this really supposed to accept WDS frames only in Master
+        * mode? What about Repeater or Managed with WDS frames? */
+       if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) !=
+           (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS) &&
+           (local->iw_mode != IW_MODE_MASTER || !(fc & IEEE80211_FCTL_TODS)))
+               return 0; /* not a WDS frame */
+
+       /* Possible WDS frame: either IEEE 802.11 compliant (if FromDS)
+        * or own non-standard frame with 4th address after payload */
+       if (memcmp(hdr->addr1, local->dev->dev_addr, ETH_ALEN) != 0 &&
+           (hdr->addr1[0] != 0xff || hdr->addr1[1] != 0xff ||
+            hdr->addr1[2] != 0xff || hdr->addr1[3] != 0xff ||
+            hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) {
+               /* RA (or BSSID) is not ours - drop */
+               PDEBUG(DEBUG_EXTRA, "%s: received WDS frame with "
+                      "not own or broadcast %s=" MACSTR "\n",
+                      local->dev->name,
+                      fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID",
+                      MAC2STR(hdr->addr1));
+               return -1;
+       }
+
+       /* check if the frame came from a registered WDS connection */
+       *wds = prism2_rx_get_wds(local, hdr->addr2);
+       if (*wds == NULL && fc & IEEE80211_FCTL_FROMDS &&
+           (local->iw_mode != IW_MODE_INFRA ||
+            !(local->wds_type & HOSTAP_WDS_AP_CLIENT) ||
+            memcmp(hdr->addr2, local->bssid, ETH_ALEN) != 0)) {
+               /* require that WDS link has been registered with TA or the
+                * frame is from current AP when using 'AP client mode' */
+               PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame "
+                      "from unknown TA=" MACSTR "\n",
+                      local->dev->name, MAC2STR(hdr->addr2));
+               if (local->ap && local->ap->autom_ap_wds)
+                       hostap_wds_link_oper(local, hdr->addr2, WDS_ADD);
+               return -1;
+       }
+
+       if (*wds && !(fc & IEEE80211_FCTL_FROMDS) && local->ap &&
+           hostap_is_sta_assoc(local->ap, hdr->addr2)) {
+               /* STA is actually associated with us even though it has a
+                * registered WDS link. Assume it is in 'AP client' mode.
+                * Since this is a 3-addr frame, assume it is not (bogus) WDS
+                * frame and process it like any normal ToDS frame from
+                * associated STA. */
+               *wds = NULL;
+       }
+
+       return 0;
+}
+
+
+static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb)
+{
+       struct net_device *dev = local->dev;
+       u16 fc, ethertype;
+       struct ieee80211_hdr *hdr;
+       u8 *pos;
+
+       if (skb->len < 24)
+               return 0;
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       fc = le16_to_cpu(hdr->frame_ctl);
+
+       /* check that the frame is unicast frame to us */
+       if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+           IEEE80211_FCTL_TODS &&
+           memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 &&
+           memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) {
+               /* ToDS frame with own addr BSSID and DA */
+       } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+                  IEEE80211_FCTL_FROMDS &&
+                  memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) {
+               /* FromDS frame with own addr as DA */
+       } else
+               return 0;
+
+       if (skb->len < 24 + 8)
+               return 0;
+
+       /* check for port access entity Ethernet type */
+       pos = skb->data + 24;
+       ethertype = (pos[6] << 8) | pos[7];
+       if (ethertype == ETH_P_PAE)
+               return 1;
+
+       return 0;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static inline int
+hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
+                       struct ieee80211_crypt_data *crypt)
+{
+       struct ieee80211_hdr *hdr;
+       int res, hdrlen;
+
+       if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
+               return 0;
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+
+       if (local->tkip_countermeasures &&
+           strcmp(crypt->ops->name, "TKIP") == 0) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
+                              "received packet from " MACSTR "\n",
+                              local->dev->name, MAC2STR(hdr->addr2));
+               }
+               return -1;
+       }
+
+       atomic_inc(&crypt->refcnt);
+       res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
+       atomic_dec(&crypt->refcnt);
+       if (res < 0) {
+               printk(KERN_DEBUG "%s: decryption failed (SA=" MACSTR
+                      ") res=%d\n",
+                      local->dev->name, MAC2STR(hdr->addr2), res);
+               local->comm_tallies.rx_discards_wep_undecryptable++;
+               return -1;
+       }
+
+       return res;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static inline int
+hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb,
+                            int keyidx, struct ieee80211_crypt_data *crypt)
+{
+       struct ieee80211_hdr *hdr;
+       int res, hdrlen;
+
+       if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
+               return 0;
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+
+       atomic_inc(&crypt->refcnt);
+       res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);
+       atomic_dec(&crypt->refcnt);
+       if (res < 0) {
+               printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
+                      " (SA=" MACSTR " keyidx=%d)\n",
+                      local->dev->name, MAC2STR(hdr->addr2), keyidx);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+/* All received frames are sent to this function. @skb contains the frame in
+ * IEEE 802.11 format, i.e., in the format it was sent over air.
+ * This function is called only as a tasklet (software IRQ). */
+void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
+                    struct hostap_80211_rx_status *rx_stats)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       struct ieee80211_hdr *hdr;
+       size_t hdrlen;
+       u16 fc, type, stype, sc;
+       struct net_device *wds = NULL;
+       struct net_device_stats *stats;
+       unsigned int frag;
+       u8 *payload;
+       struct sk_buff *skb2 = NULL;
+       u16 ethertype;
+       int frame_authorized = 0;
+       int from_assoc_ap = 0;
+       u8 dst[ETH_ALEN];
+       u8 src[ETH_ALEN];
+       struct ieee80211_crypt_data *crypt = NULL;
+       void *sta = NULL;
+       int keyidx = 0;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+       iface->stats.rx_packets++;
+       iface->stats.rx_bytes += skb->len;
+
+       /* dev is the master radio device; change this to be the default
+        * virtual interface (this may be changed to WDS device below) */
+       dev = local->ddev;
+       iface = netdev_priv(dev);
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       stats = hostap_get_stats(dev);
+
+       if (skb->len < 10)
+               goto rx_dropped;
+
+       fc = le16_to_cpu(hdr->frame_ctl);
+       type = WLAN_FC_GET_TYPE(fc);
+       stype = WLAN_FC_GET_STYPE(fc);
+       sc = le16_to_cpu(hdr->seq_ctl);
+       frag = WLAN_GET_SEQ_FRAG(sc);
+       hdrlen = hostap_80211_get_hdrlen(fc);
+
+       /* Put this code here so that we avoid duplicating it in all
+        * Rx paths. - Jean II */
+#ifdef IW_WIRELESS_SPY         /* defined in iw_handler.h */
+       /* If spy monitoring on */
+       if (iface->spy_data.spy_number > 0) {
+               struct iw_quality wstats;
+               wstats.level = rx_stats->signal;
+               wstats.noise = rx_stats->noise;
+               wstats.updated = 6;     /* No qual value */
+               /* Update spy records */
+               wireless_spy_update(dev, hdr->addr2, &wstats);
+       }
+#endif /* IW_WIRELESS_SPY */
+       hostap_update_rx_stats(local->ap, hdr, rx_stats);
+
+       if (local->iw_mode == IW_MODE_MONITOR) {
+               monitor_rx(dev, skb, rx_stats);
+               return;
+       }
+
+       if (local->host_decrypt) {
+               int idx = 0;
+               if (skb->len >= hdrlen + 3)
+                       idx = skb->data[hdrlen + 3] >> 6;
+               crypt = local->crypt[idx];
+               sta = NULL;
+
+               /* Use station specific key to override default keys if the
+                * receiver address is a unicast address ("individual RA"). If
+                * bcrx_sta_key parameter is set, station specific key is used
+                * even with broad/multicast targets (this is against IEEE
+                * 802.11, but makes it easier to use different keys with
+                * stations that do not support WEP key mapping). */
+
+               if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key)
+                       (void) hostap_handle_sta_crypto(local, hdr, &crypt,
+                                                       &sta);
+
+               /* allow NULL decrypt to indicate an station specific override
+                * for default encryption */
+               if (crypt && (crypt->ops == NULL ||
+                             crypt->ops->decrypt_mpdu == NULL))
+                       crypt = NULL;
+
+               if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) {
+#if 0
+                       /* This seems to be triggered by some (multicast?)
+                        * frames from other than current BSS, so just drop the
+                        * frames silently instead of filling system log with
+                        * these reports. */
+                       printk(KERN_DEBUG "%s: WEP decryption failed (not set)"
+                              " (SA=" MACSTR ")\n",
+                              local->dev->name, MAC2STR(hdr->addr2));
+#endif
+                       local->comm_tallies.rx_discards_wep_undecryptable++;
+                       goto rx_dropped;
+               }
+       }
+
+       if (type != IEEE80211_FTYPE_DATA) {
+               if (type == IEEE80211_FTYPE_MGMT &&
+                   stype == IEEE80211_STYPE_AUTH &&
+                   fc & IEEE80211_FCTL_PROTECTED && local->host_decrypt &&
+                   (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0)
+               {
+                       printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
+                              "from " MACSTR "\n", dev->name,
+                              MAC2STR(hdr->addr2));
+                       /* TODO: could inform hostapd about this so that it
+                        * could send auth failure report */
+                       goto rx_dropped;
+               }
+
+               if (hostap_rx_frame_mgmt(local, skb, rx_stats, type, stype))
+                       goto rx_dropped;
+               else
+                       goto rx_exit;
+       }
+
+       /* Data frame - extract src/dst addresses */
+       if (skb->len < IEEE80211_DATA_HDR3_LEN)
+               goto rx_dropped;
+
+       switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
+       case IEEE80211_FCTL_FROMDS:
+               memcpy(dst, hdr->addr1, ETH_ALEN);
+               memcpy(src, hdr->addr3, ETH_ALEN);
+               break;
+       case IEEE80211_FCTL_TODS:
+               memcpy(dst, hdr->addr3, ETH_ALEN);
+               memcpy(src, hdr->addr2, ETH_ALEN);
+               break;
+       case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
+               if (skb->len < IEEE80211_DATA_HDR4_LEN)
+                       goto rx_dropped;
+               memcpy(dst, hdr->addr3, ETH_ALEN);
+               memcpy(src, hdr->addr4, ETH_ALEN);
+               break;
+       case 0:
+               memcpy(dst, hdr->addr1, ETH_ALEN);
+               memcpy(src, hdr->addr2, ETH_ALEN);
+               break;
+       }
+
+       if (hostap_rx_frame_wds(local, hdr, fc, &wds))
+               goto rx_dropped;
+       if (wds) {
+               skb->dev = dev = wds;
+               stats = hostap_get_stats(dev);
+       }
+
+       if (local->iw_mode == IW_MODE_MASTER && !wds &&
+           (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+           IEEE80211_FCTL_FROMDS &&
+           local->stadev &&
+           memcmp(hdr->addr2, local->assoc_ap_addr, ETH_ALEN) == 0) {
+               /* Frame from BSSID of the AP for which we are a client */
+               skb->dev = dev = local->stadev;
+               stats = hostap_get_stats(dev);
+               from_assoc_ap = 1;
+       }
+
+       dev->last_rx = jiffies;
+
+       if ((local->iw_mode == IW_MODE_MASTER ||
+            local->iw_mode == IW_MODE_REPEAT) &&
+           !from_assoc_ap) {
+               switch (hostap_handle_sta_rx(local, dev, skb, rx_stats,
+                                            wds != NULL)) {
+               case AP_RX_CONTINUE_NOT_AUTHORIZED:
+                       frame_authorized = 0;
+                       break;
+               case AP_RX_CONTINUE:
+                       frame_authorized = 1;
+                       break;
+               case AP_RX_DROP:
+                       goto rx_dropped;
+               case AP_RX_EXIT:
+                       goto rx_exit;
+               }
+       }
+
+       /* Nullfunc frames may have PS-bit set, so they must be passed to
+        * hostap_handle_sta_rx() before being dropped here. */
+       if (stype != IEEE80211_STYPE_DATA &&
+           stype != IEEE80211_STYPE_DATA_CFACK &&
+           stype != IEEE80211_STYPE_DATA_CFPOLL &&
+           stype != IEEE80211_STYPE_DATA_CFACKPOLL) {
+               if (stype != IEEE80211_STYPE_NULLFUNC)
+                       printk(KERN_DEBUG "%s: RX: dropped data frame "
+                              "with no data (type=0x%02x, subtype=0x%02x)\n",
+                              dev->name, type >> 2, stype >> 4);
+               goto rx_dropped;
+       }
+
+       /* skb: hdr + (possibly fragmented, possibly encrypted) payload */
+
+       if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+           (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0)
+               goto rx_dropped;
+       hdr = (struct ieee80211_hdr *) skb->data;
+
+       /* skb: hdr + (possibly fragmented) plaintext payload */
+
+       if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+           (frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) {
+               int flen;
+               struct sk_buff *frag_skb =
+                       prism2_frag_cache_get(local, hdr);
+               if (!frag_skb) {
+                       printk(KERN_DEBUG "%s: Rx cannot get skb from "
+                              "fragment cache (morefrag=%d seq=%u frag=%u)\n",
+                              dev->name, (fc & IEEE80211_FCTL_MOREFRAGS) != 0,
+                              WLAN_GET_SEQ_SEQ(sc) >> 4, frag);
+                       goto rx_dropped;
+               }
+
+               flen = skb->len;
+               if (frag != 0)
+                       flen -= hdrlen;
+
+               if (frag_skb->tail + flen > frag_skb->end) {
+                       printk(KERN_WARNING "%s: host decrypted and "
+                              "reassembled frame did not fit skb\n",
+                              dev->name);
+                       prism2_frag_cache_invalidate(local, hdr);
+                       goto rx_dropped;
+               }
+
+               if (frag == 0) {
+                       /* copy first fragment (including full headers) into
+                        * beginning of the fragment cache skb */
+                       memcpy(skb_put(frag_skb, flen), skb->data, flen);
+               } else {
+                       /* append frame payload to the end of the fragment
+                        * cache skb */
+                       memcpy(skb_put(frag_skb, flen), skb->data + hdrlen,
+                              flen);
+               }
+               dev_kfree_skb(skb);
+               skb = NULL;
+
+               if (fc & IEEE80211_FCTL_MOREFRAGS) {
+                       /* more fragments expected - leave the skb in fragment
+                        * cache for now; it will be delivered to upper layers
+                        * after all fragments have been received */
+                       goto rx_exit;
+               }
+
+               /* this was the last fragment and the frame will be
+                * delivered, so remove skb from fragment cache */
+               skb = frag_skb;
+               hdr = (struct ieee80211_hdr *) skb->data;
+               prism2_frag_cache_invalidate(local, hdr);
+       }
+
+       /* skb: hdr + (possible reassembled) full MSDU payload; possibly still
+        * encrypted/authenticated */
+
+       if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+           hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt))
+               goto rx_dropped;
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !local->open_wep) {
+               if (local->ieee_802_1x &&
+                   hostap_is_eapol_frame(local, skb)) {
+                       /* pass unencrypted EAPOL frames even if encryption is
+                        * configured */
+                       PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X - passing "
+                              "unencrypted EAPOL frame\n", local->dev->name);
+               } else {
+                       printk(KERN_DEBUG "%s: encryption configured, but RX "
+                              "frame not encrypted (SA=" MACSTR ")\n",
+                              local->dev->name, MAC2STR(hdr->addr2));
+                       goto rx_dropped;
+               }
+       }
+
+       if (local->drop_unencrypted && !(fc & IEEE80211_FCTL_PROTECTED) &&
+           !hostap_is_eapol_frame(local, skb)) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: dropped unencrypted RX data "
+                              "frame from " MACSTR " (drop_unencrypted=1)\n",
+                              dev->name, MAC2STR(hdr->addr2));
+               }
+               goto rx_dropped;
+       }
+
+       /* skb: hdr + (possible reassembled) full plaintext payload */
+
+       payload = skb->data + hdrlen;
+       ethertype = (payload[6] << 8) | payload[7];
+
+       /* If IEEE 802.1X is used, check whether the port is authorized to send
+        * the received frame. */
+       if (local->ieee_802_1x && local->iw_mode == IW_MODE_MASTER) {
+               if (ethertype == ETH_P_PAE) {
+                       PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X frame\n",
+                              dev->name);
+                       if (local->hostapd && local->apdev) {
+                               /* Send IEEE 802.1X frames to the user
+                                * space daemon for processing */
+                               prism2_rx_80211(local->apdev, skb, rx_stats,
+                                               PRISM2_RX_MGMT);
+                               local->apdevstats.rx_packets++;
+                               local->apdevstats.rx_bytes += skb->len;
+                               goto rx_exit;
+                       }
+               } else if (!frame_authorized) {
+                       printk(KERN_DEBUG "%s: dropped frame from "
+                              "unauthorized port (IEEE 802.1X): "
+                              "ethertype=0x%04x\n",
+                              dev->name, ethertype);
+                       goto rx_dropped;
+               }
+       }
+
+       /* convert hdr + possible LLC headers into Ethernet header */
+       if (skb->len - hdrlen >= 8 &&
+           ((memcmp(payload, rfc1042_header, 6) == 0 &&
+             ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
+            memcmp(payload, bridge_tunnel_header, 6) == 0)) {
+               /* remove RFC1042 or Bridge-Tunnel encapsulation and
+                * replace EtherType */
+               skb_pull(skb, hdrlen + 6);
+               memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
+               memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+       } else {
+               u16 len;
+               /* Leave Ethernet header part of hdr and full payload */
+               skb_pull(skb, hdrlen);
+               len = htons(skb->len);
+               memcpy(skb_push(skb, 2), &len, 2);
+               memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
+               memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+       }
+
+       if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+                   IEEE80211_FCTL_TODS) &&
+           skb->len >= ETH_HLEN + ETH_ALEN) {
+               /* Non-standard frame: get addr4 from its bogus location after
+                * the payload */
+               memcpy(skb->data + ETH_ALEN,
+                      skb->data + skb->len - ETH_ALEN, ETH_ALEN);
+               skb_trim(skb, skb->len - ETH_ALEN);
+       }
+
+       stats->rx_packets++;
+       stats->rx_bytes += skb->len;
+
+       if (local->iw_mode == IW_MODE_MASTER && !wds &&
+           local->ap->bridge_packets) {
+               if (dst[0] & 0x01) {
+                       /* copy multicast frame both to the higher layers and
+                        * to the wireless media */
+                       local->ap->bridged_multicast++;
+                       skb2 = skb_clone(skb, GFP_ATOMIC);
+                       if (skb2 == NULL)
+                               printk(KERN_DEBUG "%s: skb_clone failed for "
+                                      "multicast frame\n", dev->name);
+               } else if (hostap_is_sta_authorized(local->ap, dst)) {
+                       /* send frame directly to the associated STA using
+                        * wireless media and not passing to higher layers */
+                       local->ap->bridged_unicast++;
+                       skb2 = skb;
+                       skb = NULL;
+               }
+       }
+
+       if (skb2 != NULL) {
+               /* send to wireless media */
+               skb2->protocol = __constant_htons(ETH_P_802_3);
+               skb2->mac.raw = skb2->nh.raw = skb2->data;
+               /* skb2->nh.raw = skb2->data + ETH_HLEN; */
+               skb2->dev = dev;
+               dev_queue_xmit(skb2);
+       }
+
+       if (skb) {
+               skb->protocol = eth_type_trans(skb, dev);
+               memset(skb->cb, 0, sizeof(skb->cb));
+               skb->dev = dev;
+               netif_rx(skb);
+       }
+
+ rx_exit:
+       if (sta)
+               hostap_handle_sta_release(sta);
+       return;
+
+ rx_dropped:
+       dev_kfree_skb(skb);
+
+       stats->rx_dropped++;
+       goto rx_exit;
+}
+
+
+EXPORT_SYMBOL(hostap_80211_rx);
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c
new file mode 100644 (file)
index 0000000..6358015
--- /dev/null
@@ -0,0 +1,524 @@
+void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr;
+       u16 fc;
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+
+       printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n",
+              name, skb->len, jiffies);
+
+       if (skb->len < 2)
+               return;
+
+       fc = le16_to_cpu(hdr->frame_ctl);
+       printk(KERN_DEBUG "   FC=0x%04x (type=%d:%d)%s%s",
+              fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4,
+              fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
+              fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
+
+       if (skb->len < IEEE80211_DATA_HDR3_LEN) {
+               printk("\n");
+               return;
+       }
+
+       printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
+              le16_to_cpu(hdr->seq_ctl));
+
+       printk(KERN_DEBUG "   A1=" MACSTR " A2=" MACSTR " A3=" MACSTR,
+              MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3));
+       if (skb->len >= 30)
+               printk(" A4=" MACSTR, MAC2STR(hdr->addr4));
+       printk("\n");
+}
+
+
+/* hard_start_xmit function for data interfaces (wlan#, wlan#wds#, wlan#sta)
+ * Convert Ethernet header into a suitable IEEE 802.11 header depending on
+ * device configuration. */
+int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int need_headroom, need_tailroom = 0;
+       struct ieee80211_hdr hdr;
+       u16 fc, ethertype = 0;
+       enum {
+               WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME
+       } use_wds = WDS_NO;
+       u8 *encaps_data;
+       int hdr_len, encaps_len, skip_header_bytes;
+       int to_assoc_ap = 0;
+       struct hostap_skb_tx_data *meta;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (skb->len < ETH_HLEN) {
+               printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb "
+                      "(len=%d)\n", dev->name, skb->len);
+               kfree_skb(skb);
+               return 0;
+       }
+
+       if (local->ddev != dev) {
+               use_wds = (local->iw_mode == IW_MODE_MASTER &&
+                          !(local->wds_type & HOSTAP_WDS_STANDARD_FRAME)) ?
+                       WDS_OWN_FRAME : WDS_COMPLIANT_FRAME;
+               if (dev == local->stadev) {
+                       to_assoc_ap = 1;
+                       use_wds = WDS_NO;
+               } else if (dev == local->apdev) {
+                       printk(KERN_DEBUG "%s: prism2_tx: trying to use "
+                              "AP device with Ethernet net dev\n", dev->name);
+                       kfree_skb(skb);
+                       return 0;
+               }
+       } else {
+               if (local->iw_mode == IW_MODE_REPEAT) {
+                       printk(KERN_DEBUG "%s: prism2_tx: trying to use "
+                              "non-WDS link in Repeater mode\n", dev->name);
+                       kfree_skb(skb);
+                       return 0;
+               } else if (local->iw_mode == IW_MODE_INFRA &&
+                          (local->wds_type & HOSTAP_WDS_AP_CLIENT) &&
+                          memcmp(skb->data + ETH_ALEN, dev->dev_addr,
+                                 ETH_ALEN) != 0) {
+                       /* AP client mode: send frames with foreign src addr
+                        * using 4-addr WDS frames */
+                       use_wds = WDS_COMPLIANT_FRAME;
+               }
+       }
+
+       /* Incoming skb->data: dst_addr[6], src_addr[6], proto[2], payload
+        * ==>
+        * Prism2 TX frame with 802.11 header:
+        * txdesc (address order depending on used mode; includes dst_addr and
+        * src_addr), possible encapsulation (RFC1042/Bridge-Tunnel;
+        * proto[2], payload {, possible addr4[6]} */
+
+       ethertype = (skb->data[12] << 8) | skb->data[13];
+
+       memset(&hdr, 0, sizeof(hdr));
+
+       /* Length of data after IEEE 802.11 header */
+       encaps_data = NULL;
+       encaps_len = 0;
+       skip_header_bytes = ETH_HLEN;
+       if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
+               encaps_data = bridge_tunnel_header;
+               encaps_len = sizeof(bridge_tunnel_header);
+               skip_header_bytes -= 2;
+       } else if (ethertype >= 0x600) {
+               encaps_data = rfc1042_header;
+               encaps_len = sizeof(rfc1042_header);
+               skip_header_bytes -= 2;
+       }
+
+       fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
+       hdr_len = IEEE80211_DATA_HDR3_LEN;
+
+       if (use_wds != WDS_NO) {
+               /* Note! Prism2 station firmware has problems with sending real
+                * 802.11 frames with four addresses; until these problems can
+                * be fixed or worked around, 4-addr frames needed for WDS are
+                * using incompatible format: FromDS flag is not set and the
+                * fourth address is added after the frame payload; it is
+                * assumed, that the receiving station knows how to handle this
+                * frame format */
+
+               if (use_wds == WDS_COMPLIANT_FRAME) {
+                       fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
+                       /* From&To DS: Addr1 = RA, Addr2 = TA, Addr3 = DA,
+                        * Addr4 = SA */
+                       memcpy(&hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
+                       hdr_len += ETH_ALEN;
+               } else {
+                       /* bogus 4-addr format to workaround Prism2 station
+                        * f/w bug */
+                       fc |= IEEE80211_FCTL_TODS;
+                       /* From DS: Addr1 = DA (used as RA),
+                        * Addr2 = BSSID (used as TA), Addr3 = SA (used as DA),
+                        */
+
+                       /* SA from skb->data + ETH_ALEN will be added after
+                        * frame payload; use hdr.addr4 as a temporary buffer
+                        */
+                       memcpy(&hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
+                       need_tailroom += ETH_ALEN;
+               }
+
+               /* send broadcast and multicast frames to broadcast RA, if
+                * configured; otherwise, use unicast RA of the WDS link */
+               if ((local->wds_type & HOSTAP_WDS_BROADCAST_RA) &&
+                   skb->data[0] & 0x01)
+                       memset(&hdr.addr1, 0xff, ETH_ALEN);
+               else if (iface->type == HOSTAP_INTERFACE_WDS)
+                       memcpy(&hdr.addr1, iface->u.wds.remote_addr,
+                              ETH_ALEN);
+               else
+                       memcpy(&hdr.addr1, local->bssid, ETH_ALEN);
+               memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN);
+               memcpy(&hdr.addr3, skb->data, ETH_ALEN);
+       } else if (local->iw_mode == IW_MODE_MASTER && !to_assoc_ap) {
+               fc |= IEEE80211_FCTL_FROMDS;
+               /* From DS: Addr1 = DA, Addr2 = BSSID, Addr3 = SA */
+               memcpy(&hdr.addr1, skb->data, ETH_ALEN);
+               memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN);
+               memcpy(&hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
+       } else if (local->iw_mode == IW_MODE_INFRA || to_assoc_ap) {
+               fc |= IEEE80211_FCTL_TODS;
+               /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */
+               memcpy(&hdr.addr1, to_assoc_ap ?
+                      local->assoc_ap_addr : local->bssid, ETH_ALEN);
+               memcpy(&hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+               memcpy(&hdr.addr3, skb->data, ETH_ALEN);
+       } else if (local->iw_mode == IW_MODE_ADHOC) {
+               /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */
+               memcpy(&hdr.addr1, skb->data, ETH_ALEN);
+               memcpy(&hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+               memcpy(&hdr.addr3, local->bssid, ETH_ALEN);
+       }
+
+       hdr.frame_ctl = cpu_to_le16(fc);
+
+       skb_pull(skb, skip_header_bytes);
+       need_headroom = local->func->need_tx_headroom + hdr_len + encaps_len;
+       if (skb_tailroom(skb) < need_tailroom) {
+               skb = skb_unshare(skb, GFP_ATOMIC);
+               if (skb == NULL) {
+                       iface->stats.tx_dropped++;
+                       return 0;
+               }
+               if (pskb_expand_head(skb, need_headroom, need_tailroom,
+                                    GFP_ATOMIC)) {
+                       kfree_skb(skb);
+                       iface->stats.tx_dropped++;
+                       return 0;
+               }
+       } else if (skb_headroom(skb) < need_headroom) {
+               struct sk_buff *tmp = skb;
+               skb = skb_realloc_headroom(skb, need_headroom);
+               kfree_skb(tmp);
+               if (skb == NULL) {
+                       iface->stats.tx_dropped++;
+                       return 0;
+               }
+       } else {
+               skb = skb_unshare(skb, GFP_ATOMIC);
+               if (skb == NULL) {
+                       iface->stats.tx_dropped++;
+                       return 0;
+               }
+       }
+
+       if (encaps_data)
+               memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
+       memcpy(skb_push(skb, hdr_len), &hdr, hdr_len);
+       if (use_wds == WDS_OWN_FRAME) {
+               memcpy(skb_put(skb, ETH_ALEN), &hdr.addr4, ETH_ALEN);
+       }
+
+       iface->stats.tx_packets++;
+       iface->stats.tx_bytes += skb->len;
+
+       skb->mac.raw = skb->data;
+       meta = (struct hostap_skb_tx_data *) skb->cb;
+       memset(meta, 0, sizeof(*meta));
+       meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
+       if (use_wds)
+               meta->flags |= HOSTAP_TX_FLAGS_WDS;
+       meta->ethertype = ethertype;
+       meta->iface = iface;
+
+       /* Send IEEE 802.11 encapsulated frame using the master radio device */
+       skb->dev = local->dev;
+       dev_queue_xmit(skb);
+       return 0;
+}
+
+
+/* hard_start_xmit function for hostapd wlan#ap interfaces */
+int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       struct hostap_skb_tx_data *meta;
+       struct ieee80211_hdr *hdr;
+       u16 fc;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (skb->len < 10) {
+               printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb "
+                      "(len=%d)\n", dev->name, skb->len);
+               kfree_skb(skb);
+               return 0;
+       }
+
+       iface->stats.tx_packets++;
+       iface->stats.tx_bytes += skb->len;
+
+       meta = (struct hostap_skb_tx_data *) skb->cb;
+       memset(meta, 0, sizeof(*meta));
+       meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
+       meta->iface = iface;
+
+       if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) {
+               hdr = (struct ieee80211_hdr *) skb->data;
+               fc = le16_to_cpu(hdr->frame_ctl);
+               if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&
+                   WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_DATA) {
+                       u8 *pos = &skb->data[IEEE80211_DATA_HDR3_LEN +
+                                            sizeof(rfc1042_header)];
+                       meta->ethertype = (pos[0] << 8) | pos[1];
+               }
+       }
+
+       /* Send IEEE 802.11 encapsulated frame using the master radio device */
+       skb->dev = local->dev;
+       dev_queue_xmit(skb);
+       return 0;
+}
+
+
+/* Called only from software IRQ */
+struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
+                                  struct ieee80211_crypt_data *crypt)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       struct ieee80211_hdr *hdr;
+       u16 fc;
+       int hdr_len, res;
+
+       iface = netdev_priv(skb->dev);
+       local = iface->local;
+
+       if (skb->len < IEEE80211_DATA_HDR3_LEN) {
+               kfree_skb(skb);
+               return NULL;
+       }
+
+       if (local->tkip_countermeasures &&
+           crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) {
+               hdr = (struct ieee80211_hdr *) skb->data;
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
+                              "TX packet to " MACSTR "\n",
+                              local->dev->name, MAC2STR(hdr->addr1));
+               }
+               kfree_skb(skb);
+               return NULL;
+       }
+
+       skb = skb_unshare(skb, GFP_ATOMIC);
+       if (skb == NULL)
+               return NULL;
+
+       if ((skb_headroom(skb) < crypt->ops->extra_prefix_len ||
+            skb_tailroom(skb) < crypt->ops->extra_postfix_len) &&
+           pskb_expand_head(skb, crypt->ops->extra_prefix_len,
+                            crypt->ops->extra_postfix_len, GFP_ATOMIC)) {
+               kfree_skb(skb);
+               return NULL;
+       }
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       fc = le16_to_cpu(hdr->frame_ctl);
+       hdr_len = hostap_80211_get_hdrlen(fc);
+
+       /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so
+        * call both MSDU and MPDU encryption functions from here. */
+       atomic_inc(&crypt->refcnt);
+       res = 0;
+       if (crypt->ops->encrypt_msdu)
+               res = crypt->ops->encrypt_msdu(skb, hdr_len, crypt->priv);
+       if (res == 0 && crypt->ops->encrypt_mpdu)
+               res = crypt->ops->encrypt_mpdu(skb, hdr_len, crypt->priv);
+       atomic_dec(&crypt->refcnt);
+       if (res < 0) {
+               kfree_skb(skb);
+               return NULL;
+       }
+
+       return skb;
+}
+
+
+/* hard_start_xmit function for master radio interface wifi#.
+ * AP processing (TX rate control, power save buffering, etc.).
+ * Use hardware TX function to send the frame. */
+int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int ret = 1;
+       u16 fc;
+       struct hostap_tx_data tx;
+       ap_tx_ret tx_ret;
+       struct hostap_skb_tx_data *meta;
+       int no_encrypt = 0;
+       struct ieee80211_hdr *hdr;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       tx.skb = skb;
+       tx.sta_ptr = NULL;
+
+       meta = (struct hostap_skb_tx_data *) skb->cb;
+       if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) {
+               printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "
+                      "expected 0x%08x)\n",
+                      dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC);
+               ret = 0;
+               iface->stats.tx_dropped++;
+               goto fail;
+       }
+
+       if (local->host_encrypt) {
+               /* Set crypt to default algorithm and key; will be replaced in
+                * AP code if STA has own alg/key */
+               tx.crypt = local->crypt[local->tx_keyidx];
+               tx.host_encrypt = 1;
+       } else {
+               tx.crypt = NULL;
+               tx.host_encrypt = 0;
+       }
+
+       if (skb->len < 24) {
+               printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb "
+                      "(len=%d)\n", dev->name, skb->len);
+               ret = 0;
+               iface->stats.tx_dropped++;
+               goto fail;
+       }
+
+       /* FIX (?):
+        * Wi-Fi 802.11b test plan suggests that AP should ignore power save
+        * bit in authentication and (re)association frames and assume tha
+        * STA remains awake for the response. */
+       tx_ret = hostap_handle_sta_tx(local, &tx);
+       skb = tx.skb;
+       meta = (struct hostap_skb_tx_data *) skb->cb;
+       hdr = (struct ieee80211_hdr *) skb->data;
+       fc = le16_to_cpu(hdr->frame_ctl);
+       switch (tx_ret) {
+       case AP_TX_CONTINUE:
+               break;
+       case AP_TX_CONTINUE_NOT_AUTHORIZED:
+               if (local->ieee_802_1x &&
+                   WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&
+                   meta->ethertype != ETH_P_PAE &&
+                   !(meta->flags & HOSTAP_TX_FLAGS_WDS)) {
+                       printk(KERN_DEBUG "%s: dropped frame to unauthorized "
+                              "port (IEEE 802.1X): ethertype=0x%04x\n",
+                              dev->name, meta->ethertype);
+                       hostap_dump_tx_80211(dev->name, skb);
+
+                       ret = 0; /* drop packet */
+                       iface->stats.tx_dropped++;
+                       goto fail;
+               }
+               break;
+       case AP_TX_DROP:
+               ret = 0; /* drop packet */
+               iface->stats.tx_dropped++;
+               goto fail;
+       case AP_TX_RETRY:
+               goto fail;
+       case AP_TX_BUFFERED:
+               /* do not free skb here, it will be freed when the
+                * buffered frame is sent/timed out */
+               ret = 0;
+               goto tx_exit;
+       }
+
+       /* Request TX callback if protocol version is 2 in 802.11 header;
+        * this version 2 is a special case used between hostapd and kernel
+        * driver */
+       if (((fc & IEEE80211_FCTL_VERS) == BIT(1)) &&
+           local->ap && local->ap->tx_callback_idx && meta->tx_cb_idx == 0) {
+               meta->tx_cb_idx = local->ap->tx_callback_idx;
+
+               /* remove special version from the frame header */
+               fc &= ~IEEE80211_FCTL_VERS;
+               hdr->frame_ctl = cpu_to_le16(fc);
+       }
+
+       if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_DATA) {
+               no_encrypt = 1;
+               tx.crypt = NULL;
+       }
+
+       if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt &&
+           !(fc & IEEE80211_FCTL_VERS)) {
+               no_encrypt = 1;
+               PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing "
+                      "unencrypted EAPOL frame\n", dev->name);
+               tx.crypt = NULL; /* no encryption for IEEE 802.1X frames */
+       }
+
+       if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu))
+               tx.crypt = NULL;
+       else if ((tx.crypt || local->crypt[local->tx_keyidx]) && !no_encrypt) {
+               /* Add ISWEP flag both for firmware and host based encryption
+                */
+               fc |= IEEE80211_FCTL_PROTECTED;
+               hdr->frame_ctl = cpu_to_le16(fc);
+       } else if (local->drop_unencrypted &&
+                  WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&
+                  meta->ethertype != ETH_P_PAE) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: dropped unencrypted TX data "
+                              "frame (drop_unencrypted=1)\n", dev->name);
+               }
+               iface->stats.tx_dropped++;
+               ret = 0;
+               goto fail;
+       }
+
+       if (tx.crypt) {
+               skb = hostap_tx_encrypt(skb, tx.crypt);
+               if (skb == NULL) {
+                       printk(KERN_DEBUG "%s: TX - encryption failed\n",
+                              dev->name);
+                       ret = 0;
+                       goto fail;
+               }
+               meta = (struct hostap_skb_tx_data *) skb->cb;
+               if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) {
+                       printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "
+                              "expected 0x%08x) after hostap_tx_encrypt\n",
+                              dev->name, meta->magic,
+                              HOSTAP_SKB_TX_DATA_MAGIC);
+                       ret = 0;
+                       iface->stats.tx_dropped++;
+                       goto fail;
+               }
+       }
+
+       if (local->func->tx == NULL || local->func->tx(skb, dev)) {
+               ret = 0;
+               iface->stats.tx_dropped++;
+       } else {
+               ret = 0;
+               iface->stats.tx_packets++;
+               iface->stats.tx_bytes += skb->len;
+       }
+
+ fail:
+       if (!ret && skb)
+               dev_kfree_skb(skb);
+ tx_exit:
+       if (tx.sta_ptr)
+               hostap_handle_sta_release(tx.sta_ptr);
+       return ret;
+}
+
+
+EXPORT_SYMBOL(hostap_dump_tx_80211);
+EXPORT_SYMBOL(hostap_tx_encrypt);
+EXPORT_SYMBOL(hostap_master_start_xmit);
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
new file mode 100644 (file)
index 0000000..930cef8
--- /dev/null
@@ -0,0 +1,3288 @@
+/*
+ * Intersil Prism2 driver with Host AP (software access point) support
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * This file is to be included into hostap.c when S/W AP functionality is
+ * compiled.
+ *
+ * AP:  FIX:
+ * - if unicast Class 2 (assoc,reassoc,disassoc) frame received from
+ *   unauthenticated STA, send deauth. frame (8802.11: 5.5)
+ * - if unicast Class 3 (data with to/from DS,deauth,pspoll) frame received
+ *   from authenticated, but unassoc STA, send disassoc frame (8802.11: 5.5)
+ * - if unicast Class 3 received from unauthenticated STA, send deauth. frame
+ *   (8802.11: 5.5)
+ */
+
+static int other_ap_policy[MAX_PARM_DEVICES] = { AP_OTHER_AP_SKIP_ALL,
+                                                DEF_INTS };
+module_param_array(other_ap_policy, int, NULL, 0444);
+MODULE_PARM_DESC(other_ap_policy, "Other AP beacon monitoring policy (0-3)");
+
+static int ap_max_inactivity[MAX_PARM_DEVICES] = { AP_MAX_INACTIVITY_SEC,
+                                                  DEF_INTS };
+module_param_array(ap_max_inactivity, int, NULL, 0444);
+MODULE_PARM_DESC(ap_max_inactivity, "AP timeout (in seconds) for station "
+                "inactivity");
+
+static int ap_bridge_packets[MAX_PARM_DEVICES] = { 1, DEF_INTS };
+module_param_array(ap_bridge_packets, int, NULL, 0444);
+MODULE_PARM_DESC(ap_bridge_packets, "Bridge packets directly between "
+                "stations");
+
+static int autom_ap_wds[MAX_PARM_DEVICES] = { 0, DEF_INTS };
+module_param_array(autom_ap_wds, int, NULL, 0444);
+MODULE_PARM_DESC(autom_ap_wds, "Add WDS connections to other APs "
+                "automatically");
+
+
+static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta);
+static void hostap_event_expired_sta(struct net_device *dev,
+                                    struct sta_info *sta);
+static void handle_add_proc_queue(void *data);
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+static void handle_wds_oper_queue(void *data);
+static void prism2_send_mgmt(struct net_device *dev,
+                            u16 type_subtype, char *body,
+                            int body_len, u8 *addr, u16 tx_cb_idx);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+#ifndef PRISM2_NO_PROCFS_DEBUG
+static int ap_debug_proc_read(char *page, char **start, off_t off,
+                             int count, int *eof, void *data)
+{
+       char *p = page;
+       struct ap_data *ap = (struct ap_data *) data;
+
+       if (off != 0) {
+               *eof = 1;
+               return 0;
+       }
+
+       p += sprintf(p, "BridgedUnicastFrames=%u\n", ap->bridged_unicast);
+       p += sprintf(p, "BridgedMulticastFrames=%u\n", ap->bridged_multicast);
+       p += sprintf(p, "max_inactivity=%u\n", ap->max_inactivity / HZ);
+       p += sprintf(p, "bridge_packets=%u\n", ap->bridge_packets);
+       p += sprintf(p, "nullfunc_ack=%u\n", ap->nullfunc_ack);
+       p += sprintf(p, "autom_ap_wds=%u\n", ap->autom_ap_wds);
+       p += sprintf(p, "auth_algs=%u\n", ap->local->auth_algs);
+       p += sprintf(p, "tx_drop_nonassoc=%u\n", ap->tx_drop_nonassoc);
+
+       return (p - page);
+}
+#endif /* PRISM2_NO_PROCFS_DEBUG */
+
+
+static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta)
+{
+       sta->hnext = ap->sta_hash[STA_HASH(sta->addr)];
+       ap->sta_hash[STA_HASH(sta->addr)] = sta;
+}
+
+static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta)
+{
+       struct sta_info *s;
+
+       s = ap->sta_hash[STA_HASH(sta->addr)];
+       if (s == NULL) return;
+       if (memcmp(s->addr, sta->addr, ETH_ALEN) == 0) {
+               ap->sta_hash[STA_HASH(sta->addr)] = s->hnext;
+               return;
+       }
+
+       while (s->hnext != NULL && memcmp(s->hnext->addr, sta->addr, ETH_ALEN)
+              != 0)
+               s = s->hnext;
+       if (s->hnext != NULL)
+               s->hnext = s->hnext->hnext;
+       else
+               printk("AP: could not remove STA " MACSTR " from hash table\n",
+                      MAC2STR(sta->addr));
+}
+
+static void ap_free_sta(struct ap_data *ap, struct sta_info *sta)
+{
+       if (sta->ap && sta->local)
+               hostap_event_expired_sta(sta->local->dev, sta);
+
+       if (ap->proc != NULL) {
+               char name[20];
+               sprintf(name, MACSTR, MAC2STR(sta->addr));
+               remove_proc_entry(name, ap->proc);
+       }
+
+       if (sta->crypt) {
+               sta->crypt->ops->deinit(sta->crypt->priv);
+               kfree(sta->crypt);
+               sta->crypt = NULL;
+       }
+
+       skb_queue_purge(&sta->tx_buf);
+
+       ap->num_sta--;
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+       if (sta->aid > 0)
+               ap->sta_aid[sta->aid - 1] = NULL;
+
+       if (!sta->ap && sta->u.sta.challenge)
+               kfree(sta->u.sta.challenge);
+       del_timer(&sta->timer);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+       kfree(sta);
+}
+
+
+static void hostap_set_tim(local_info_t *local, int aid, int set)
+{
+       if (local->func->set_tim)
+               local->func->set_tim(local->dev, aid, set);
+}
+
+
+static void hostap_event_new_sta(struct net_device *dev, struct sta_info *sta)
+{
+       union iwreq_data wrqu;
+       memset(&wrqu, 0, sizeof(wrqu));
+       memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN);
+       wrqu.addr.sa_family = ARPHRD_ETHER;
+       wireless_send_event(dev, IWEVREGISTERED, &wrqu, NULL);
+}
+
+
+static void hostap_event_expired_sta(struct net_device *dev,
+                                    struct sta_info *sta)
+{
+       union iwreq_data wrqu;
+       memset(&wrqu, 0, sizeof(wrqu));
+       memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN);
+       wrqu.addr.sa_family = ARPHRD_ETHER;
+       wireless_send_event(dev, IWEVEXPIRED, &wrqu, NULL);
+}
+
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+
+static void ap_handle_timer(unsigned long data)
+{
+       struct sta_info *sta = (struct sta_info *) data;
+       local_info_t *local;
+       struct ap_data *ap;
+       unsigned long next_time = 0;
+       int was_assoc;
+
+       if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) {
+               PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n");
+               return;
+       }
+
+       local = sta->local;
+       ap = local->ap;
+       was_assoc = sta->flags & WLAN_STA_ASSOC;
+
+       if (atomic_read(&sta->users) != 0)
+               next_time = jiffies + HZ;
+       else if ((sta->flags & WLAN_STA_PERM) && !(sta->flags & WLAN_STA_AUTH))
+               next_time = jiffies + ap->max_inactivity;
+
+       if (time_before(jiffies, sta->last_rx + ap->max_inactivity)) {
+               /* station activity detected; reset timeout state */
+               sta->timeout_next = STA_NULLFUNC;
+               next_time = sta->last_rx + ap->max_inactivity;
+       } else if (sta->timeout_next == STA_DISASSOC &&
+                  !(sta->flags & WLAN_STA_PENDING_POLL)) {
+               /* STA ACKed data nullfunc frame poll */
+               sta->timeout_next = STA_NULLFUNC;
+               next_time = jiffies + ap->max_inactivity;
+       }
+
+       if (next_time) {
+               sta->timer.expires = next_time;
+               add_timer(&sta->timer);
+               return;
+       }
+
+       if (sta->ap)
+               sta->timeout_next = STA_DEAUTH;
+
+       if (sta->timeout_next == STA_DEAUTH && !(sta->flags & WLAN_STA_PERM)) {
+               spin_lock(&ap->sta_table_lock);
+               ap_sta_hash_del(ap, sta);
+               list_del(&sta->list);
+               spin_unlock(&ap->sta_table_lock);
+               sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+       } else if (sta->timeout_next == STA_DISASSOC)
+               sta->flags &= ~WLAN_STA_ASSOC;
+
+       if (was_assoc && !(sta->flags & WLAN_STA_ASSOC) && !sta->ap)
+               hostap_event_expired_sta(local->dev, sta);
+
+       if (sta->timeout_next == STA_DEAUTH && sta->aid > 0 &&
+           !skb_queue_empty(&sta->tx_buf)) {
+               hostap_set_tim(local, sta->aid, 0);
+               sta->flags &= ~WLAN_STA_TIM;
+       }
+
+       if (sta->ap) {
+               if (ap->autom_ap_wds) {
+                       PDEBUG(DEBUG_AP, "%s: removing automatic WDS "
+                              "connection to AP " MACSTR "\n",
+                              local->dev->name, MAC2STR(sta->addr));
+                       hostap_wds_link_oper(local, sta->addr, WDS_DEL);
+               }
+       } else if (sta->timeout_next == STA_NULLFUNC) {
+               /* send data frame to poll STA and check whether this frame
+                * is ACKed */
+               /* FIX: IEEE80211_STYPE_NULLFUNC would be more appropriate, but
+                * it is apparently not retried so TX Exc events are not
+                * received for it */
+               sta->flags |= WLAN_STA_PENDING_POLL;
+               prism2_send_mgmt(local->dev, IEEE80211_FTYPE_DATA |
+                                IEEE80211_STYPE_DATA, NULL, 0,
+                                sta->addr, ap->tx_callback_poll);
+       } else {
+               int deauth = sta->timeout_next == STA_DEAUTH;
+               u16 resp;
+               PDEBUG(DEBUG_AP, "%s: sending %s info to STA " MACSTR
+                      "(last=%lu, jiffies=%lu)\n",
+                      local->dev->name,
+                      deauth ? "deauthentication" : "disassociation",
+                      MAC2STR(sta->addr), sta->last_rx, jiffies);
+
+               resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID :
+                                  WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
+               prism2_send_mgmt(local->dev, IEEE80211_FTYPE_MGMT |
+                                (deauth ? IEEE80211_STYPE_DEAUTH :
+                                 IEEE80211_STYPE_DISASSOC),
+                                (char *) &resp, 2, sta->addr, 0);
+       }
+
+       if (sta->timeout_next == STA_DEAUTH) {
+               if (sta->flags & WLAN_STA_PERM) {
+                       PDEBUG(DEBUG_AP, "%s: STA " MACSTR " would have been "
+                              "removed, but it has 'perm' flag\n",
+                              local->dev->name, MAC2STR(sta->addr));
+               } else
+                       ap_free_sta(ap, sta);
+               return;
+       }
+
+       if (sta->timeout_next == STA_NULLFUNC) {
+               sta->timeout_next = STA_DISASSOC;
+               sta->timer.expires = jiffies + AP_DISASSOC_DELAY;
+       } else {
+               sta->timeout_next = STA_DEAUTH;
+               sta->timer.expires = jiffies + AP_DEAUTH_DELAY;
+       }
+
+       add_timer(&sta->timer);
+}
+
+
+void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap,
+                           int resend)
+{
+       u8 addr[ETH_ALEN];
+       u16 resp;
+       int i;
+
+       PDEBUG(DEBUG_AP, "%s: Deauthenticate all stations\n", dev->name);
+       memset(addr, 0xff, ETH_ALEN);
+
+       resp = __constant_cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+
+       /* deauth message sent; try to resend it few times; the message is
+        * broadcast, so it may be delayed until next DTIM; there is not much
+        * else we can do at this point since the driver is going to be shut
+        * down */
+       for (i = 0; i < 5; i++) {
+               prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT |
+                                IEEE80211_STYPE_DEAUTH,
+                                (char *) &resp, 2, addr, 0);
+
+               if (!resend || ap->num_sta <= 0)
+                       return;
+
+               mdelay(50);
+       }
+}
+
+
+static int ap_control_proc_read(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+       char *p = page;
+       struct ap_data *ap = (struct ap_data *) data;
+       char *policy_txt;
+       struct list_head *ptr;
+       struct mac_entry *entry;
+
+       if (off != 0) {
+               *eof = 1;
+               return 0;
+       }
+
+       switch (ap->mac_restrictions.policy) {
+       case MAC_POLICY_OPEN:
+               policy_txt = "open";
+               break;
+       case MAC_POLICY_ALLOW:
+               policy_txt = "allow";
+               break;
+       case MAC_POLICY_DENY:
+               policy_txt = "deny";
+               break;
+       default:
+               policy_txt = "unknown";
+               break;
+       };
+       p += sprintf(p, "MAC policy: %s\n", policy_txt);
+       p += sprintf(p, "MAC entries: %u\n", ap->mac_restrictions.entries);
+       p += sprintf(p, "MAC list:\n");
+       spin_lock_bh(&ap->mac_restrictions.lock);
+       for (ptr = ap->mac_restrictions.mac_list.next;
+            ptr != &ap->mac_restrictions.mac_list; ptr = ptr->next) {
+               if (p - page > PAGE_SIZE - 80) {
+                       p += sprintf(p, "All entries did not fit one page.\n");
+                       break;
+               }
+
+               entry = list_entry(ptr, struct mac_entry, list);
+               p += sprintf(p, MACSTR "\n", MAC2STR(entry->addr));
+       }
+       spin_unlock_bh(&ap->mac_restrictions.lock);
+
+       return (p - page);
+}
+
+
+static int ap_control_add_mac(struct mac_restrictions *mac_restrictions,
+                             u8 *mac)
+{
+       struct mac_entry *entry;
+
+       entry = kmalloc(sizeof(struct mac_entry), GFP_KERNEL);
+       if (entry == NULL)
+               return -1;
+
+       memcpy(entry->addr, mac, ETH_ALEN);
+
+       spin_lock_bh(&mac_restrictions->lock);
+       list_add_tail(&entry->list, &mac_restrictions->mac_list);
+       mac_restrictions->entries++;
+       spin_unlock_bh(&mac_restrictions->lock);
+
+       return 0;
+}
+
+
+static int ap_control_del_mac(struct mac_restrictions *mac_restrictions,
+                             u8 *mac)
+{
+       struct list_head *ptr;
+       struct mac_entry *entry;
+
+       spin_lock_bh(&mac_restrictions->lock);
+       for (ptr = mac_restrictions->mac_list.next;
+            ptr != &mac_restrictions->mac_list; ptr = ptr->next) {
+               entry = list_entry(ptr, struct mac_entry, list);
+
+               if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {
+                       list_del(ptr);
+                       kfree(entry);
+                       mac_restrictions->entries--;
+                       spin_unlock_bh(&mac_restrictions->lock);
+                       return 0;
+               }
+       }
+       spin_unlock_bh(&mac_restrictions->lock);
+       return -1;
+}
+
+
+static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions,
+                              u8 *mac)
+{
+       struct list_head *ptr;
+       struct mac_entry *entry;
+       int found = 0;
+
+       if (mac_restrictions->policy == MAC_POLICY_OPEN)
+               return 0;
+
+       spin_lock_bh(&mac_restrictions->lock);
+       for (ptr = mac_restrictions->mac_list.next;
+            ptr != &mac_restrictions->mac_list; ptr = ptr->next) {
+               entry = list_entry(ptr, struct mac_entry, list);
+
+               if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {
+                       found = 1;
+                       break;
+               }
+       }
+       spin_unlock_bh(&mac_restrictions->lock);
+
+       if (mac_restrictions->policy == MAC_POLICY_ALLOW)
+               return !found;
+       else
+               return found;
+}
+
+
+static void ap_control_flush_macs(struct mac_restrictions *mac_restrictions)
+{
+       struct list_head *ptr, *n;
+       struct mac_entry *entry;
+
+       if (mac_restrictions->entries == 0)
+               return;
+
+       spin_lock_bh(&mac_restrictions->lock);
+       for (ptr = mac_restrictions->mac_list.next, n = ptr->next;
+            ptr != &mac_restrictions->mac_list;
+            ptr = n, n = ptr->next) {
+               entry = list_entry(ptr, struct mac_entry, list);
+               list_del(ptr);
+               kfree(entry);
+       }
+       mac_restrictions->entries = 0;
+       spin_unlock_bh(&mac_restrictions->lock);
+}
+
+
+static int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev,
+                              u8 *mac)
+{
+       struct sta_info *sta;
+       u16 resp;
+
+       spin_lock_bh(&ap->sta_table_lock);
+       sta = ap_get_sta(ap, mac);
+       if (sta) {
+               ap_sta_hash_del(ap, sta);
+               list_del(&sta->list);
+       }
+       spin_unlock_bh(&ap->sta_table_lock);
+
+       if (!sta)
+               return -EINVAL;
+
+       resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+       prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH,
+                        (char *) &resp, 2, sta->addr, 0);
+
+       if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap)
+               hostap_event_expired_sta(dev, sta);
+
+       ap_free_sta(ap, sta);
+
+       return 0;
+}
+
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+static void ap_control_kickall(struct ap_data *ap)
+{
+       struct list_head *ptr, *n;
+       struct sta_info *sta;
+
+       spin_lock_bh(&ap->sta_table_lock);
+       for (ptr = ap->sta_list.next, n = ptr->next; ptr != &ap->sta_list;
+            ptr = n, n = ptr->next) {
+               sta = list_entry(ptr, struct sta_info, list);
+               ap_sta_hash_del(ap, sta);
+               list_del(&sta->list);
+               if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
+                       hostap_event_expired_sta(sta->local->dev, sta);
+               ap_free_sta(ap, sta);
+       }
+       spin_unlock_bh(&ap->sta_table_lock);
+}
+
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+
+#define PROC_LIMIT (PAGE_SIZE - 80)
+
+static int prism2_ap_proc_read(char *page, char **start, off_t off,
+                              int count, int *eof, void *data)
+{
+       char *p = page;
+       struct ap_data *ap = (struct ap_data *) data;
+       struct list_head *ptr;
+       int i;
+
+       if (off > PROC_LIMIT) {
+               *eof = 1;
+               return 0;
+       }
+
+       p += sprintf(p, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n");
+       spin_lock_bh(&ap->sta_table_lock);
+       for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) {
+               struct sta_info *sta = (struct sta_info *) ptr;
+
+               if (!sta->ap)
+                       continue;
+
+               p += sprintf(p, MACSTR " %d %d %d %d '", MAC2STR(sta->addr),
+                            sta->u.ap.channel, sta->last_rx_signal,
+                            sta->last_rx_silence, sta->last_rx_rate);
+               for (i = 0; i < sta->u.ap.ssid_len; i++)
+                       p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 &&
+                                         sta->u.ap.ssid[i] < 127) ?
+                                        "%c" : "<%02x>"),
+                                    sta->u.ap.ssid[i]);
+               p += sprintf(p, "'");
+               if (sta->capability & WLAN_CAPABILITY_ESS)
+                       p += sprintf(p, " [ESS]");
+               if (sta->capability & WLAN_CAPABILITY_IBSS)
+                       p += sprintf(p, " [IBSS]");
+               if (sta->capability & WLAN_CAPABILITY_PRIVACY)
+                       p += sprintf(p, " [WEP]");
+               p += sprintf(p, "\n");
+
+               if ((p - page) > PROC_LIMIT) {
+                       printk(KERN_DEBUG "hostap: ap proc did not fit\n");
+                       break;
+               }
+       }
+       spin_unlock_bh(&ap->sta_table_lock);
+
+       if ((p - page) <= off) {
+               *eof = 1;
+               return 0;
+       }
+
+       *start = page + off;
+
+       return (p - page - off);
+}
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver)
+{
+       if (!ap)
+               return;
+
+       if (sta_fw_ver == PRISM2_FW_VER(0,8,0)) {
+               PDEBUG(DEBUG_AP, "Using data::nullfunc ACK workaround - "
+                      "firmware upgrade recommended\n");
+               ap->nullfunc_ack = 1;
+       } else
+               ap->nullfunc_ack = 0;
+
+       if (sta_fw_ver == PRISM2_FW_VER(1,4,2)) {
+               printk(KERN_WARNING "%s: Warning: secondary station firmware "
+                      "version 1.4.2 does not seem to work in Host AP mode\n",
+                      ap->local->dev->name);
+       }
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data)
+{
+       struct ap_data *ap = data;
+       u16 fc;
+       struct ieee80211_hdr *hdr;
+
+       if (!ap->local->hostapd || !ap->local->apdev) {
+               dev_kfree_skb(skb);
+               return;
+       }
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       fc = le16_to_cpu(hdr->frame_ctl);
+
+       /* Pass the TX callback frame to the hostapd; use 802.11 header version
+        * 1 to indicate failure (no ACK) and 2 success (frame ACKed) */
+
+       fc &= ~IEEE80211_FCTL_VERS;
+       fc |= ok ? BIT(1) : BIT(0);
+       hdr->frame_ctl = cpu_to_le16(fc);
+
+       skb->dev = ap->local->apdev;
+       skb_pull(skb, hostap_80211_get_hdrlen(fc));
+       skb->pkt_type = PACKET_OTHERHOST;
+       skb->protocol = __constant_htons(ETH_P_802_2);
+       memset(skb->cb, 0, sizeof(skb->cb));
+       netif_rx(skb);
+}
+
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+/* Called only as a tasklet (software IRQ) */
+static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data)
+{
+       struct ap_data *ap = data;
+       struct net_device *dev = ap->local->dev;
+       struct ieee80211_hdr *hdr;
+       u16 fc, *pos, auth_alg, auth_transaction, status;
+       struct sta_info *sta = NULL;
+       char *txt = NULL;
+
+       if (ap->local->hostapd) {
+               dev_kfree_skb(skb);
+               return;
+       }
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       fc = le16_to_cpu(hdr->frame_ctl);
+       if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT ||
+           WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_AUTH ||
+           skb->len < IEEE80211_MGMT_HDR_LEN + 6) {
+               printk(KERN_DEBUG "%s: hostap_ap_tx_cb_auth received invalid "
+                      "frame\n", dev->name);
+               dev_kfree_skb(skb);
+               return;
+       }
+
+       pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
+       auth_alg = le16_to_cpu(*pos++);
+       auth_transaction = le16_to_cpu(*pos++);
+       status = le16_to_cpu(*pos++);
+
+       if (!ok) {
+               txt = "frame was not ACKed";
+               goto done;
+       }
+
+       spin_lock(&ap->sta_table_lock);
+       sta = ap_get_sta(ap, hdr->addr1);
+       if (sta)
+               atomic_inc(&sta->users);
+       spin_unlock(&ap->sta_table_lock);
+
+       if (!sta) {
+               txt = "STA not found";
+               goto done;
+       }
+
+       if (status == WLAN_STATUS_SUCCESS &&
+           ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
+            (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
+               txt = "STA authenticated";
+               sta->flags |= WLAN_STA_AUTH;
+               sta->last_auth = jiffies;
+       } else if (status != WLAN_STATUS_SUCCESS)
+               txt = "authentication failed";
+
+ done:
+       if (sta)
+               atomic_dec(&sta->users);
+       if (txt) {
+               PDEBUG(DEBUG_AP, "%s: " MACSTR " auth_cb - alg=%d trans#=%d "
+                      "status=%d - %s\n",
+                      dev->name, MAC2STR(hdr->addr1), auth_alg,
+                      auth_transaction, status, txt);
+       }
+       dev_kfree_skb(skb);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
+{
+       struct ap_data *ap = data;
+       struct net_device *dev = ap->local->dev;
+       struct ieee80211_hdr *hdr;
+       u16 fc, *pos, status;
+       struct sta_info *sta = NULL;
+       char *txt = NULL;
+
+       if (ap->local->hostapd) {
+               dev_kfree_skb(skb);
+               return;
+       }
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       fc = le16_to_cpu(hdr->frame_ctl);
+       if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT ||
+           (WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_ASSOC_RESP &&
+            WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_REASSOC_RESP) ||
+           skb->len < IEEE80211_MGMT_HDR_LEN + 4) {
+               printk(KERN_DEBUG "%s: hostap_ap_tx_cb_assoc received invalid "
+                      "frame\n", dev->name);
+               dev_kfree_skb(skb);
+               return;
+       }
+
+       if (!ok) {
+               txt = "frame was not ACKed";
+               goto done;
+       }
+
+       spin_lock(&ap->sta_table_lock);
+       sta = ap_get_sta(ap, hdr->addr1);
+       if (sta)
+               atomic_inc(&sta->users);
+       spin_unlock(&ap->sta_table_lock);
+
+       if (!sta) {
+               txt = "STA not found";
+               goto done;
+       }
+
+       pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
+       pos++;
+       status = le16_to_cpu(*pos++);
+       if (status == WLAN_STATUS_SUCCESS) {
+               if (!(sta->flags & WLAN_STA_ASSOC))
+                       hostap_event_new_sta(dev, sta);
+               txt = "STA associated";
+               sta->flags |= WLAN_STA_ASSOC;
+               sta->last_assoc = jiffies;
+       } else
+               txt = "association failed";
+
+ done:
+       if (sta)
+               atomic_dec(&sta->users);
+       if (txt) {
+               PDEBUG(DEBUG_AP, "%s: " MACSTR " assoc_cb - %s\n",
+                      dev->name, MAC2STR(hdr->addr1), txt);
+       }
+       dev_kfree_skb(skb);
+}
+
+/* Called only as a tasklet (software IRQ); TX callback for poll frames used
+ * in verifying whether the STA is still present. */
+static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data)
+{
+       struct ap_data *ap = data;
+       struct ieee80211_hdr *hdr;
+       struct sta_info *sta;
+
+       if (skb->len < 24)
+               goto fail;
+       hdr = (struct ieee80211_hdr *) skb->data;
+       if (ok) {
+               spin_lock(&ap->sta_table_lock);
+               sta = ap_get_sta(ap, hdr->addr1);
+               if (sta)
+                       sta->flags &= ~WLAN_STA_PENDING_POLL;
+               spin_unlock(&ap->sta_table_lock);
+       } else {
+               PDEBUG(DEBUG_AP, "%s: STA " MACSTR " did not ACK activity "
+                      "poll frame\n", ap->local->dev->name,
+                      MAC2STR(hdr->addr1));
+       }
+
+ fail:
+       dev_kfree_skb(skb);
+}
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+void hostap_init_data(local_info_t *local)
+{
+       struct ap_data *ap = local->ap;
+
+       if (ap == NULL) {
+               printk(KERN_WARNING "hostap_init_data: ap == NULL\n");
+               return;
+       }
+       memset(ap, 0, sizeof(struct ap_data));
+       ap->local = local;
+
+       ap->ap_policy = GET_INT_PARM(other_ap_policy, local->card_idx);
+       ap->bridge_packets = GET_INT_PARM(ap_bridge_packets, local->card_idx);
+       ap->max_inactivity =
+               GET_INT_PARM(ap_max_inactivity, local->card_idx) * HZ;
+       ap->autom_ap_wds = GET_INT_PARM(autom_ap_wds, local->card_idx);
+
+       spin_lock_init(&ap->sta_table_lock);
+       INIT_LIST_HEAD(&ap->sta_list);
+
+       /* Initialize task queue structure for AP management */
+       INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue, ap);
+
+       ap->tx_callback_idx =
+               hostap_tx_callback_register(local, hostap_ap_tx_cb, ap);
+       if (ap->tx_callback_idx == 0)
+               printk(KERN_WARNING "%s: failed to register TX callback for "
+                      "AP\n", local->dev->name);
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+       INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue, local);
+
+       ap->tx_callback_auth =
+               hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap);
+       ap->tx_callback_assoc =
+               hostap_tx_callback_register(local, hostap_ap_tx_cb_assoc, ap);
+       ap->tx_callback_poll =
+               hostap_tx_callback_register(local, hostap_ap_tx_cb_poll, ap);
+       if (ap->tx_callback_auth == 0 || ap->tx_callback_assoc == 0 ||
+               ap->tx_callback_poll == 0)
+               printk(KERN_WARNING "%s: failed to register TX callback for "
+                      "AP\n", local->dev->name);
+
+       spin_lock_init(&ap->mac_restrictions.lock);
+       INIT_LIST_HEAD(&ap->mac_restrictions.mac_list);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+       ap->initialized = 1;
+}
+
+
+void hostap_init_ap_proc(local_info_t *local)
+{
+       struct ap_data *ap = local->ap;
+
+       ap->proc = local->proc;
+       if (ap->proc == NULL)
+               return;
+
+#ifndef PRISM2_NO_PROCFS_DEBUG
+       create_proc_read_entry("ap_debug", 0, ap->proc,
+                              ap_debug_proc_read, ap);
+#endif /* PRISM2_NO_PROCFS_DEBUG */
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+       create_proc_read_entry("ap_control", 0, ap->proc,
+                              ap_control_proc_read, ap);
+       create_proc_read_entry("ap", 0, ap->proc,
+                              prism2_ap_proc_read, ap);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+}
+
+
+void hostap_free_data(struct ap_data *ap)
+{
+       struct list_head *n, *ptr;
+
+       if (ap == NULL || !ap->initialized) {
+               printk(KERN_DEBUG "hostap_free_data: ap has not yet been "
+                      "initialized - skip resource freeing\n");
+               return;
+       }
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+       if (ap->crypt)
+               ap->crypt->deinit(ap->crypt_priv);
+       ap->crypt = ap->crypt_priv = NULL;
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+       list_for_each_safe(ptr, n, &ap->sta_list) {
+               struct sta_info *sta = list_entry(ptr, struct sta_info, list);
+               ap_sta_hash_del(ap, sta);
+               list_del(&sta->list);
+               if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
+                       hostap_event_expired_sta(sta->local->dev, sta);
+               ap_free_sta(ap, sta);
+       }
+
+#ifndef PRISM2_NO_PROCFS_DEBUG
+       if (ap->proc != NULL) {
+               remove_proc_entry("ap_debug", ap->proc);
+       }
+#endif /* PRISM2_NO_PROCFS_DEBUG */
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+       if (ap->proc != NULL) {
+         remove_proc_entry("ap", ap->proc);
+               remove_proc_entry("ap_control", ap->proc);
+       }
+       ap_control_flush_macs(&ap->mac_restrictions);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+       ap->initialized = 0;
+}
+
+
+/* caller should have mutex for AP STA list handling */
+static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta)
+{
+       struct sta_info *s;
+
+       s = ap->sta_hash[STA_HASH(sta)];
+       while (s != NULL && memcmp(s->addr, sta, ETH_ALEN) != 0)
+               s = s->hnext;
+       return s;
+}
+
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+
+/* Called from timer handler and from scheduled AP queue handlers */
+static void prism2_send_mgmt(struct net_device *dev,
+                            u16 type_subtype, char *body,
+                            int body_len, u8 *addr, u16 tx_cb_idx)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       struct ieee80211_hdr *hdr;
+       u16 fc;
+       struct sk_buff *skb;
+       struct hostap_skb_tx_data *meta;
+       int hdrlen;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+       dev = local->dev; /* always use master radio device */
+       iface = netdev_priv(dev);
+
+       if (!(dev->flags & IFF_UP)) {
+               PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt - device is not UP - "
+                      "cannot send frame\n", dev->name);
+               return;
+       }
+
+       skb = dev_alloc_skb(sizeof(*hdr) + body_len);
+       if (skb == NULL) {
+               PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt failed to allocate "
+                      "skb\n", dev->name);
+               return;
+       }
+
+       fc = type_subtype;
+       hdrlen = hostap_80211_get_hdrlen(fc);
+       hdr = (struct ieee80211_hdr *) skb_put(skb, hdrlen);
+       if (body)
+               memcpy(skb_put(skb, body_len), body, body_len);
+
+       memset(hdr, 0, hdrlen);
+
+       /* FIX: ctrl::ack sending used special HFA384X_TX_CTRL_802_11
+        * tx_control instead of using local->tx_control */
+
+
+       memcpy(hdr->addr1, addr, ETH_ALEN); /* DA / RA */
+       if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) {
+               fc |= IEEE80211_FCTL_FROMDS;
+               memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* BSSID */
+               memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* SA */
+       } else if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_CTL) {
+               /* control:ACK does not have addr2 or addr3 */
+               memset(hdr->addr2, 0, ETH_ALEN);
+               memset(hdr->addr3, 0, ETH_ALEN);
+       } else {
+               memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* SA */
+               memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* BSSID */
+       }
+
+       hdr->frame_ctl = cpu_to_le16(fc);
+
+       meta = (struct hostap_skb_tx_data *) skb->cb;
+       memset(meta, 0, sizeof(*meta));
+       meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
+       meta->iface = iface;
+       meta->tx_cb_idx = tx_cb_idx;
+
+       skb->dev = dev;
+       skb->mac.raw = skb->nh.raw = skb->data;
+       dev_queue_xmit(skb);
+}
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+static int prism2_sta_proc_read(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+       char *p = page;
+       struct sta_info *sta = (struct sta_info *) data;
+       int i;
+
+       /* FIX: possible race condition.. the STA data could have just expired,
+        * but proc entry was still here so that the read could have started;
+        * some locking should be done here.. */
+
+       if (off != 0) {
+               *eof = 1;
+               return 0;
+       }
+
+       p += sprintf(p, "%s=" MACSTR "\nusers=%d\naid=%d\n"
+                    "flags=0x%04x%s%s%s%s%s%s%s\n"
+                    "capability=0x%02x\nlisten_interval=%d\nsupported_rates=",
+                    sta->ap ? "AP" : "STA",
+                    MAC2STR(sta->addr), atomic_read(&sta->users), sta->aid,
+                    sta->flags,
+                    sta->flags & WLAN_STA_AUTH ? " AUTH" : "",
+                    sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "",
+                    sta->flags & WLAN_STA_PS ? " PS" : "",
+                    sta->flags & WLAN_STA_TIM ? " TIM" : "",
+                    sta->flags & WLAN_STA_PERM ? " PERM" : "",
+                    sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "",
+                    sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "",
+                    sta->capability, sta->listen_interval);
+       /* supported_rates: 500 kbit/s units with msb ignored */
+       for (i = 0; i < sizeof(sta->supported_rates); i++)
+               if (sta->supported_rates[i] != 0)
+                       p += sprintf(p, "%d%sMbps ",
+                                    (sta->supported_rates[i] & 0x7f) / 2,
+                                    sta->supported_rates[i] & 1 ? ".5" : "");
+       p += sprintf(p, "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n"
+                    "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n"
+                    "tx_packets=%lu\n"
+                    "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n"
+                    "last_rx: silence=%d dBm signal=%d dBm rate=%d%s Mbps\n"
+                    "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n"
+                    "tx[11M]=%d\n"
+                    "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n",
+                    jiffies, sta->last_auth, sta->last_assoc, sta->last_rx,
+                    sta->last_tx,
+                    sta->rx_packets, sta->tx_packets, sta->rx_bytes,
+                    sta->tx_bytes, skb_queue_len(&sta->tx_buf),
+                    sta->last_rx_silence,
+                    sta->last_rx_signal, sta->last_rx_rate / 10,
+                    sta->last_rx_rate % 10 ? ".5" : "",
+                    sta->tx_rate, sta->tx_count[0], sta->tx_count[1],
+                    sta->tx_count[2], sta->tx_count[3],  sta->rx_count[0],
+                    sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]);
+       if (sta->crypt && sta->crypt->ops && sta->crypt->ops->print_stats)
+               p = sta->crypt->ops->print_stats(p, sta->crypt->priv);
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+       if (sta->ap) {
+               if (sta->u.ap.channel >= 0)
+                       p += sprintf(p, "channel=%d\n", sta->u.ap.channel);
+               p += sprintf(p, "ssid=");
+               for (i = 0; i < sta->u.ap.ssid_len; i++)
+                       p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 &&
+                                         sta->u.ap.ssid[i] < 127) ?
+                                        "%c" : "<%02x>"),
+                                    sta->u.ap.ssid[i]);
+               p += sprintf(p, "\n");
+       }
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+       return (p - page);
+}
+
+
+static void handle_add_proc_queue(void *data)
+{
+       struct ap_data *ap = (struct ap_data *) data;
+       struct sta_info *sta;
+       char name[20];
+       struct add_sta_proc_data *entry, *prev;
+
+       entry = ap->add_sta_proc_entries;
+       ap->add_sta_proc_entries = NULL;
+
+       while (entry) {
+               spin_lock_bh(&ap->sta_table_lock);
+               sta = ap_get_sta(ap, entry->addr);
+               if (sta)
+                       atomic_inc(&sta->users);
+               spin_unlock_bh(&ap->sta_table_lock);
+
+               if (sta) {
+                       sprintf(name, MACSTR, MAC2STR(sta->addr));
+                       sta->proc = create_proc_read_entry(
+                               name, 0, ap->proc,
+                               prism2_sta_proc_read, sta);
+
+                       atomic_dec(&sta->users);
+               }
+
+               prev = entry;
+               entry = entry->next;
+               kfree(prev);
+       }
+}
+
+
+static struct sta_info * ap_add_sta(struct ap_data *ap, u8 *addr)
+{
+       struct sta_info *sta;
+
+       sta = (struct sta_info *)
+               kmalloc(sizeof(struct sta_info), GFP_ATOMIC);
+       if (sta == NULL) {
+               PDEBUG(DEBUG_AP, "AP: kmalloc failed\n");
+               return NULL;
+       }
+
+       /* initialize STA info data */
+       memset(sta, 0, sizeof(struct sta_info));
+       sta->local = ap->local;
+       skb_queue_head_init(&sta->tx_buf);
+       memcpy(sta->addr, addr, ETH_ALEN);
+
+       atomic_inc(&sta->users);
+       spin_lock_bh(&ap->sta_table_lock);
+       list_add(&sta->list, &ap->sta_list);
+       ap->num_sta++;
+       ap_sta_hash_add(ap, sta);
+       spin_unlock_bh(&ap->sta_table_lock);
+
+       if (ap->proc) {
+               struct add_sta_proc_data *entry;
+               /* schedule a non-interrupt context process to add a procfs
+                * entry for the STA since procfs code use GFP_KERNEL */
+               entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+               if (entry) {
+                       memcpy(entry->addr, sta->addr, ETH_ALEN);
+                       entry->next = ap->add_sta_proc_entries;
+                       ap->add_sta_proc_entries = entry;
+                       schedule_work(&ap->add_sta_proc_queue);
+               } else
+                       printk(KERN_DEBUG "Failed to add STA proc data\n");
+       }
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+       init_timer(&sta->timer);
+       sta->timer.expires = jiffies + ap->max_inactivity;
+       sta->timer.data = (unsigned long) sta;
+       sta->timer.function = ap_handle_timer;
+       if (!ap->local->hostapd)
+               add_timer(&sta->timer);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+       return sta;
+}
+
+
+static int ap_tx_rate_ok(int rateidx, struct sta_info *sta,
+                        local_info_t *local)
+{
+       if (rateidx > sta->tx_max_rate ||
+           !(sta->tx_supp_rates & (1 << rateidx)))
+               return 0;
+
+       if (local->tx_rate_control != 0 &&
+           !(local->tx_rate_control & (1 << rateidx)))
+               return 0;
+
+       return 1;
+}
+
+
+static void prism2_check_tx_rates(struct sta_info *sta)
+{
+       int i;
+
+       sta->tx_supp_rates = 0;
+       for (i = 0; i < sizeof(sta->supported_rates); i++) {
+               if ((sta->supported_rates[i] & 0x7f) == 2)
+                       sta->tx_supp_rates |= WLAN_RATE_1M;
+               if ((sta->supported_rates[i] & 0x7f) == 4)
+                       sta->tx_supp_rates |= WLAN_RATE_2M;
+               if ((sta->supported_rates[i] & 0x7f) == 11)
+                       sta->tx_supp_rates |= WLAN_RATE_5M5;
+               if ((sta->supported_rates[i] & 0x7f) == 22)
+                       sta->tx_supp_rates |= WLAN_RATE_11M;
+       }
+       sta->tx_max_rate = sta->tx_rate = sta->tx_rate_idx = 0;
+       if (sta->tx_supp_rates & WLAN_RATE_1M) {
+               sta->tx_max_rate = 0;
+               if (ap_tx_rate_ok(0, sta, sta->local)) {
+                       sta->tx_rate = 10;
+                       sta->tx_rate_idx = 0;
+               }
+       }
+       if (sta->tx_supp_rates & WLAN_RATE_2M) {
+               sta->tx_max_rate = 1;
+               if (ap_tx_rate_ok(1, sta, sta->local)) {
+                       sta->tx_rate = 20;
+                       sta->tx_rate_idx = 1;
+               }
+       }
+       if (sta->tx_supp_rates & WLAN_RATE_5M5) {
+               sta->tx_max_rate = 2;
+               if (ap_tx_rate_ok(2, sta, sta->local)) {
+                       sta->tx_rate = 55;
+                       sta->tx_rate_idx = 2;
+               }
+       }
+       if (sta->tx_supp_rates & WLAN_RATE_11M) {
+               sta->tx_max_rate = 3;
+               if (ap_tx_rate_ok(3, sta, sta->local)) {
+                       sta->tx_rate = 110;
+                       sta->tx_rate_idx = 3;
+               }
+       }
+}
+
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+
+static void ap_crypt_init(struct ap_data *ap)
+{
+       ap->crypt = ieee80211_get_crypto_ops("WEP");
+
+       if (ap->crypt) {
+               if (ap->crypt->init) {
+                       ap->crypt_priv = ap->crypt->init(0);
+                       if (ap->crypt_priv == NULL)
+                               ap->crypt = NULL;
+                       else {
+                               u8 key[WEP_KEY_LEN];
+                               get_random_bytes(key, WEP_KEY_LEN);
+                               ap->crypt->set_key(key, WEP_KEY_LEN, NULL,
+                                                  ap->crypt_priv);
+                       }
+               }
+       }
+
+       if (ap->crypt == NULL) {
+               printk(KERN_WARNING "AP could not initialize WEP: load module "
+                      "ieee80211_crypt_wep.ko\n");
+       }
+}
+
+
+/* Generate challenge data for shared key authentication. IEEE 802.11 specifies
+ * that WEP algorithm is used for generating challange. This should be unique,
+ * but otherwise there is not really need for randomness etc. Initialize WEP
+ * with pseudo random key and then use increasing IV to get unique challenge
+ * streams.
+ *
+ * Called only as a scheduled task for pending AP frames.
+ */
+static char * ap_auth_make_challenge(struct ap_data *ap)
+{
+       char *tmpbuf;
+       struct sk_buff *skb;
+
+       if (ap->crypt == NULL) {
+               ap_crypt_init(ap);
+               if (ap->crypt == NULL)
+                       return NULL;
+       }
+
+       tmpbuf = (char *) kmalloc(WLAN_AUTH_CHALLENGE_LEN, GFP_ATOMIC);
+       if (tmpbuf == NULL) {
+               PDEBUG(DEBUG_AP, "AP: kmalloc failed for challenge\n");
+               return NULL;
+       }
+
+       skb = dev_alloc_skb(WLAN_AUTH_CHALLENGE_LEN +
+                           ap->crypt->extra_prefix_len +
+                           ap->crypt->extra_postfix_len);
+       if (skb == NULL) {
+               kfree(tmpbuf);
+               return NULL;
+       }
+
+       skb_reserve(skb, ap->crypt->extra_prefix_len);
+       memset(skb_put(skb, WLAN_AUTH_CHALLENGE_LEN), 0,
+              WLAN_AUTH_CHALLENGE_LEN);
+       if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) {
+               dev_kfree_skb(skb);
+               kfree(tmpbuf);
+               return NULL;
+       }
+
+       memcpy(tmpbuf, skb->data + ap->crypt->extra_prefix_len,
+              WLAN_AUTH_CHALLENGE_LEN);
+       dev_kfree_skb(skb);
+
+       return tmpbuf;
+}
+
+
+/* Called only as a scheduled task for pending AP frames. */
+static void handle_authen(local_info_t *local, struct sk_buff *skb,
+                         struct hostap_80211_rx_status *rx_stats)
+{
+       struct net_device *dev = local->dev;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       size_t hdrlen;
+       struct ap_data *ap = local->ap;
+       char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL;
+       int len, olen;
+       u16 auth_alg, auth_transaction, status_code, *pos;
+       u16 resp = WLAN_STATUS_SUCCESS, fc;
+       struct sta_info *sta = NULL;
+       struct ieee80211_crypt_data *crypt;
+       char *txt = "";
+
+       len = skb->len - IEEE80211_MGMT_HDR_LEN;
+
+       fc = le16_to_cpu(hdr->frame_ctl);
+       hdrlen = hostap_80211_get_hdrlen(fc);
+
+       if (len < 6) {
+               PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload "
+                      "(len=%d) from " MACSTR "\n", dev->name, len,
+                      MAC2STR(hdr->addr2));
+               return;
+       }
+
+       spin_lock_bh(&local->ap->sta_table_lock);
+       sta = ap_get_sta(local->ap, hdr->addr2);
+       if (sta)
+               atomic_inc(&sta->users);
+       spin_unlock_bh(&local->ap->sta_table_lock);
+
+       if (sta && sta->crypt)
+               crypt = sta->crypt;
+       else {
+               int idx = 0;
+               if (skb->len >= hdrlen + 3)
+                       idx = skb->data[hdrlen + 3] >> 6;
+               crypt = local->crypt[idx];
+       }
+
+       pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
+       auth_alg = __le16_to_cpu(*pos);
+       pos++;
+       auth_transaction = __le16_to_cpu(*pos);
+       pos++;
+       status_code = __le16_to_cpu(*pos);
+       pos++;
+
+       if (memcmp(dev->dev_addr, hdr->addr2, ETH_ALEN) == 0 ||
+           ap_control_mac_deny(&ap->mac_restrictions, hdr->addr2)) {
+               txt = "authentication denied";
+               resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+               goto fail;
+       }
+
+       if (((local->auth_algs & PRISM2_AUTH_OPEN) &&
+            auth_alg == WLAN_AUTH_OPEN) ||
+           ((local->auth_algs & PRISM2_AUTH_SHARED_KEY) &&
+            crypt && auth_alg == WLAN_AUTH_SHARED_KEY)) {
+       } else {
+               txt = "unsupported algorithm";
+               resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
+               goto fail;
+       }
+
+       if (len >= 8) {
+               u8 *u = (u8 *) pos;
+               if (*u == WLAN_EID_CHALLENGE) {
+                       if (*(u + 1) != WLAN_AUTH_CHALLENGE_LEN) {
+                               txt = "invalid challenge len";
+                               resp = WLAN_STATUS_CHALLENGE_FAIL;
+                               goto fail;
+                       }
+                       if (len - 8 < WLAN_AUTH_CHALLENGE_LEN) {
+                               txt = "challenge underflow";
+                               resp = WLAN_STATUS_CHALLENGE_FAIL;
+                               goto fail;
+                       }
+                       challenge = (char *) (u + 2);
+               }
+       }
+
+       if (sta && sta->ap) {
+               if (time_after(jiffies, sta->u.ap.last_beacon +
+                              (10 * sta->listen_interval * HZ) / 1024)) {
+                       PDEBUG(DEBUG_AP, "%s: no beacons received for a while,"
+                              " assuming AP " MACSTR " is now STA\n",
+                              dev->name, MAC2STR(sta->addr));
+                       sta->ap = 0;
+                       sta->flags = 0;
+                       sta->u.sta.challenge = NULL;
+               } else {
+                       txt = "AP trying to authenticate?";
+                       resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                       goto fail;
+               }
+       }
+
+       if ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) ||
+           (auth_alg == WLAN_AUTH_SHARED_KEY &&
+            (auth_transaction == 1 ||
+             (auth_transaction == 3 && sta != NULL &&
+              sta->u.sta.challenge != NULL)))) {
+       } else {
+               txt = "unknown authentication transaction number";
+               resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+               goto fail;
+       }
+
+       if (sta == NULL) {
+               txt = "new STA";
+
+               if (local->ap->num_sta >= MAX_STA_COUNT) {
+                       /* FIX: might try to remove some old STAs first? */
+                       txt = "no more room for new STAs";
+                       resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                       goto fail;
+               }
+
+               sta = ap_add_sta(local->ap, hdr->addr2);
+               if (sta == NULL) {
+                       txt = "ap_add_sta failed";
+                       resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                       goto fail;
+               }
+       }
+
+       switch (auth_alg) {
+       case WLAN_AUTH_OPEN:
+               txt = "authOK";
+               /* IEEE 802.11 standard is not completely clear about
+                * whether STA is considered authenticated after
+                * authentication OK frame has been send or after it
+                * has been ACKed. In order to reduce interoperability
+                * issues, mark the STA authenticated before ACK. */
+               sta->flags |= WLAN_STA_AUTH;
+               break;
+
+       case WLAN_AUTH_SHARED_KEY:
+               if (auth_transaction == 1) {
+                       if (sta->u.sta.challenge == NULL) {
+                               sta->u.sta.challenge =
+                                       ap_auth_make_challenge(local->ap);
+                               if (sta->u.sta.challenge == NULL) {
+                                       resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                                       goto fail;
+                               }
+                       }
+               } else {
+                       if (sta->u.sta.challenge == NULL ||
+                           challenge == NULL ||
+                           memcmp(sta->u.sta.challenge, challenge,
+                                  WLAN_AUTH_CHALLENGE_LEN) != 0 ||
+                           !(fc & IEEE80211_FCTL_PROTECTED)) {
+                               txt = "challenge response incorrect";
+                               resp = WLAN_STATUS_CHALLENGE_FAIL;
+                               goto fail;
+                       }
+
+                       txt = "challenge OK - authOK";
+                       /* IEEE 802.11 standard is not completely clear about
+                        * whether STA is considered authenticated after
+                        * authentication OK frame has been send or after it
+                        * has been ACKed. In order to reduce interoperability
+                        * issues, mark the STA authenticated before ACK. */
+                       sta->flags |= WLAN_STA_AUTH;
+                       kfree(sta->u.sta.challenge);
+                       sta->u.sta.challenge = NULL;
+               }
+               break;
+       }
+
+ fail:
+       pos = (u16 *) body;
+       *pos = cpu_to_le16(auth_alg);
+       pos++;
+       *pos = cpu_to_le16(auth_transaction + 1);
+       pos++;
+       *pos = cpu_to_le16(resp); /* status_code */
+       pos++;
+       olen = 6;
+
+       if (resp == WLAN_STATUS_SUCCESS && sta != NULL &&
+           sta->u.sta.challenge != NULL &&
+           auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 1) {
+               u8 *tmp = (u8 *) pos;
+               *tmp++ = WLAN_EID_CHALLENGE;
+               *tmp++ = WLAN_AUTH_CHALLENGE_LEN;
+               pos++;
+               memcpy(pos, sta->u.sta.challenge, WLAN_AUTH_CHALLENGE_LEN);
+               olen += 2 + WLAN_AUTH_CHALLENGE_LEN;
+       }
+
+       prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH,
+                        body, olen, hdr->addr2, ap->tx_callback_auth);
+
+       if (sta) {
+               sta->last_rx = jiffies;
+               atomic_dec(&sta->users);
+       }
+
+       if (resp) {
+               PDEBUG(DEBUG_AP, "%s: " MACSTR " auth (alg=%d trans#=%d "
+                      "stat=%d len=%d fc=%04x) ==> %d (%s)\n",
+                      dev->name, MAC2STR(hdr->addr2), auth_alg,
+                      auth_transaction, status_code, len, fc, resp, txt);
+       }
+}
+
+
+/* Called only as a scheduled task for pending AP frames. */
+static void handle_assoc(local_info_t *local, struct sk_buff *skb,
+                        struct hostap_80211_rx_status *rx_stats, int reassoc)
+{
+       struct net_device *dev = local->dev;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       char body[12], *p, *lpos;
+       int len, left;
+       u16 *pos;
+       u16 resp = WLAN_STATUS_SUCCESS;
+       struct sta_info *sta = NULL;
+       int send_deauth = 0;
+       char *txt = "";
+       u8 prev_ap[ETH_ALEN];
+
+       left = len = skb->len - IEEE80211_MGMT_HDR_LEN;
+
+       if (len < (reassoc ? 10 : 4)) {
+               PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload "
+                      "(len=%d, reassoc=%d) from " MACSTR "\n",
+                      dev->name, len, reassoc, MAC2STR(hdr->addr2));
+               return;
+       }
+
+       spin_lock_bh(&local->ap->sta_table_lock);
+       sta = ap_get_sta(local->ap, hdr->addr2);
+       if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
+               spin_unlock_bh(&local->ap->sta_table_lock);
+               txt = "trying to associate before authentication";
+               send_deauth = 1;
+               resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+               sta = NULL; /* do not decrement sta->users */
+               goto fail;
+       }
+       atomic_inc(&sta->users);
+       spin_unlock_bh(&local->ap->sta_table_lock);
+
+       pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
+       sta->capability = __le16_to_cpu(*pos);
+       pos++; left -= 2;
+       sta->listen_interval = __le16_to_cpu(*pos);
+       pos++; left -= 2;
+
+       if (reassoc) {
+               memcpy(prev_ap, pos, ETH_ALEN);
+               pos++; pos++; pos++; left -= 6;
+       } else
+               memset(prev_ap, 0, ETH_ALEN);
+
+       if (left >= 2) {
+               unsigned int ileft;
+               unsigned char *u = (unsigned char *) pos;
+
+               if (*u == WLAN_EID_SSID) {
+                       u++; left--;
+                       ileft = *u;
+                       u++; left--;
+
+                       if (ileft > left || ileft > MAX_SSID_LEN) {
+                               txt = "SSID overflow";
+                               resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                               goto fail;
+                       }
+
+                       if (ileft != strlen(local->essid) ||
+                           memcmp(local->essid, u, ileft) != 0) {
+                               txt = "not our SSID";
+                               resp = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+                               goto fail;
+                       }
+
+                       u += ileft;
+                       left -= ileft;
+               }
+
+               if (left >= 2 && *u == WLAN_EID_SUPP_RATES) {
+                       u++; left--;
+                       ileft = *u;
+                       u++; left--;
+
+                       if (ileft > left || ileft == 0 ||
+                           ileft > WLAN_SUPP_RATES_MAX) {
+                               txt = "SUPP_RATES len error";
+                               resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                               goto fail;
+                       }
+
+                       memset(sta->supported_rates, 0,
+                              sizeof(sta->supported_rates));
+                       memcpy(sta->supported_rates, u, ileft);
+                       prism2_check_tx_rates(sta);
+
+                       u += ileft;
+                       left -= ileft;
+               }
+
+               if (left > 0) {
+                       PDEBUG(DEBUG_AP, "%s: assoc from " MACSTR " with extra"
+                              " data (%d bytes) [",
+                              dev->name, MAC2STR(hdr->addr2), left);
+                       while (left > 0) {
+                               PDEBUG2(DEBUG_AP, "<%02x>", *u);
+                               u++; left--;
+                       }
+                       PDEBUG2(DEBUG_AP, "]\n");
+               }
+       } else {
+               txt = "frame underflow";
+               resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+               goto fail;
+       }
+
+       /* get a unique AID */
+       if (sta->aid > 0)
+               txt = "OK, old AID";
+       else {
+               spin_lock_bh(&local->ap->sta_table_lock);
+               for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++)
+                       if (local->ap->sta_aid[sta->aid - 1] == NULL)
+                               break;
+               if (sta->aid > MAX_AID_TABLE_SIZE) {
+                       sta->aid = 0;
+                       spin_unlock_bh(&local->ap->sta_table_lock);
+                       resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+                       txt = "no room for more AIDs";
+               } else {
+                       local->ap->sta_aid[sta->aid - 1] = sta;
+                       spin_unlock_bh(&local->ap->sta_table_lock);
+                       txt = "OK, new AID";
+               }
+       }
+
+ fail:
+       pos = (u16 *) body;
+
+       if (send_deauth) {
+               *pos = __constant_cpu_to_le16(
+                       WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH);
+               pos++;
+       } else {
+               /* FIX: CF-Pollable and CF-PollReq should be set to match the
+                * values in beacons/probe responses */
+               /* FIX: how about privacy and WEP? */
+               /* capability */
+               *pos = __constant_cpu_to_le16(WLAN_CAPABILITY_ESS);
+               pos++;
+
+               /* status_code */
+               *pos = __cpu_to_le16(resp);
+               pos++;
+
+               *pos = __cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) |
+                                    BIT(14) | BIT(15)); /* AID */
+               pos++;
+
+               /* Supported rates (Information element) */
+               p = (char *) pos;
+               *p++ = WLAN_EID_SUPP_RATES;
+               lpos = p;
+               *p++ = 0; /* len */
+               if (local->tx_rate_control & WLAN_RATE_1M) {
+                       *p++ = local->basic_rates & WLAN_RATE_1M ? 0x82 : 0x02;
+                       (*lpos)++;
+               }
+               if (local->tx_rate_control & WLAN_RATE_2M) {
+                       *p++ = local->basic_rates & WLAN_RATE_2M ? 0x84 : 0x04;
+                       (*lpos)++;
+               }
+               if (local->tx_rate_control & WLAN_RATE_5M5) {
+                       *p++ = local->basic_rates & WLAN_RATE_5M5 ?
+                               0x8b : 0x0b;
+                       (*lpos)++;
+               }
+               if (local->tx_rate_control & WLAN_RATE_11M) {
+                       *p++ = local->basic_rates & WLAN_RATE_11M ?
+                               0x96 : 0x16;
+                       (*lpos)++;
+               }
+               pos = (u16 *) p;
+       }
+
+       prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT |
+                        (send_deauth ? IEEE80211_STYPE_DEAUTH :
+                         (reassoc ? IEEE80211_STYPE_REASSOC_RESP :
+                          IEEE80211_STYPE_ASSOC_RESP)),
+                        body, (u8 *) pos - (u8 *) body,
+                        hdr->addr2,
+                        send_deauth ? 0 : local->ap->tx_callback_assoc);
+
+       if (sta) {
+               if (resp == WLAN_STATUS_SUCCESS) {
+                       sta->last_rx = jiffies;
+                       /* STA will be marked associated from TX callback, if
+                        * AssocResp is ACKed */
+               }
+               atomic_dec(&sta->users);
+       }
+
+#if 0
+       PDEBUG(DEBUG_AP, "%s: " MACSTR " %sassoc (len=%d prev_ap=" MACSTR
+              ") => %d(%d) (%s)\n",
+              dev->name, MAC2STR(hdr->addr2), reassoc ? "re" : "", len,
+              MAC2STR(prev_ap), resp, send_deauth, txt);
+#endif
+}
+
+
+/* Called only as a scheduled task for pending AP frames. */
+static void handle_deauth(local_info_t *local, struct sk_buff *skb,
+                         struct hostap_80211_rx_status *rx_stats)
+{
+       struct net_device *dev = local->dev;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN);
+       int len;
+       u16 reason_code, *pos;
+       struct sta_info *sta = NULL;
+
+       len = skb->len - IEEE80211_MGMT_HDR_LEN;
+
+       if (len < 2) {
+               printk("handle_deauth - too short payload (len=%d)\n", len);
+               return;
+       }
+
+       pos = (u16 *) body;
+       reason_code = __le16_to_cpu(*pos);
+
+       PDEBUG(DEBUG_AP, "%s: deauthentication: " MACSTR " len=%d, "
+              "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len,
+              reason_code);
+
+       spin_lock_bh(&local->ap->sta_table_lock);
+       sta = ap_get_sta(local->ap, hdr->addr2);
+       if (sta != NULL) {
+               if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap)
+                       hostap_event_expired_sta(local->dev, sta);
+               sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+       }
+       spin_unlock_bh(&local->ap->sta_table_lock);
+       if (sta == NULL) {
+               printk("%s: deauthentication from " MACSTR ", "
+              "reason_code=%d, but STA not authenticated\n", dev->name,
+                      MAC2STR(hdr->addr2), reason_code);
+       }
+}
+
+
+/* Called only as a scheduled task for pending AP frames. */
+static void handle_disassoc(local_info_t *local, struct sk_buff *skb,
+                           struct hostap_80211_rx_status *rx_stats)
+{
+       struct net_device *dev = local->dev;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       char *body = skb->data + IEEE80211_MGMT_HDR_LEN;
+       int len;
+       u16 reason_code, *pos;
+       struct sta_info *sta = NULL;
+
+       len = skb->len - IEEE80211_MGMT_HDR_LEN;
+
+       if (len < 2) {
+               printk("handle_disassoc - too short payload (len=%d)\n", len);
+               return;
+       }
+
+       pos = (u16 *) body;
+       reason_code = __le16_to_cpu(*pos);
+
+       PDEBUG(DEBUG_AP, "%s: disassociation: " MACSTR " len=%d, "
+              "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len,
+              reason_code);
+
+       spin_lock_bh(&local->ap->sta_table_lock);
+       sta = ap_get_sta(local->ap, hdr->addr2);
+       if (sta != NULL) {
+               if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap)
+                       hostap_event_expired_sta(local->dev, sta);
+               sta->flags &= ~WLAN_STA_ASSOC;
+       }
+       spin_unlock_bh(&local->ap->sta_table_lock);
+       if (sta == NULL) {
+               printk("%s: disassociation from " MACSTR ", "
+                      "reason_code=%d, but STA not authenticated\n",
+                      dev->name, MAC2STR(hdr->addr2), reason_code);
+       }
+}
+
+
+/* Called only as a scheduled task for pending AP frames. */
+static void ap_handle_data_nullfunc(local_info_t *local,
+                                   struct ieee80211_hdr *hdr)
+{
+       struct net_device *dev = local->dev;
+
+       /* some STA f/w's seem to require control::ACK frame for
+        * data::nullfunc, but at least Prism2 station f/w version 0.8.0 does
+        * not send this..
+        * send control::ACK for the data::nullfunc */
+
+       printk(KERN_DEBUG "Sending control::ACK for data::nullfunc\n");
+       prism2_send_mgmt(dev, IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK,
+                        NULL, 0, hdr->addr2, 0);
+}
+
+
+/* Called only as a scheduled task for pending AP frames. */
+static void ap_handle_dropped_data(local_info_t *local,
+                                  struct ieee80211_hdr *hdr)
+{
+       struct net_device *dev = local->dev;
+       struct sta_info *sta;
+       u16 reason;
+
+       spin_lock_bh(&local->ap->sta_table_lock);
+       sta = ap_get_sta(local->ap, hdr->addr2);
+       if (sta)
+               atomic_inc(&sta->users);
+       spin_unlock_bh(&local->ap->sta_table_lock);
+
+       if (sta != NULL && (sta->flags & WLAN_STA_ASSOC)) {
+               PDEBUG(DEBUG_AP, "ap_handle_dropped_data: STA is now okay?\n");
+               atomic_dec(&sta->users);
+               return;
+       }
+
+       reason = __constant_cpu_to_le16(
+               WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+       prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT |
+                        ((sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) ?
+                         IEEE80211_STYPE_DEAUTH : IEEE80211_STYPE_DISASSOC),
+                        (char *) &reason, sizeof(reason), hdr->addr2, 0);
+
+       if (sta)
+               atomic_dec(&sta->users);
+}
+
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+/* Called only as a scheduled task for pending AP frames. */
+static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta,
+                                struct sk_buff *skb)
+{
+       struct hostap_skb_tx_data *meta;
+
+       if (!(sta->flags & WLAN_STA_PS)) {
+               /* Station has moved to non-PS mode, so send all buffered
+                * frames using normal device queue. */
+               dev_queue_xmit(skb);
+               return;
+       }
+
+       /* add a flag for hostap_handle_sta_tx() to know that this skb should
+        * be passed through even though STA is using PS */
+       meta = (struct hostap_skb_tx_data *) skb->cb;
+       meta->flags |= HOSTAP_TX_FLAGS_BUFFERED_FRAME;
+       if (!skb_queue_empty(&sta->tx_buf)) {
+               /* indicate to STA that more frames follow */
+               meta->flags |= HOSTAP_TX_FLAGS_ADD_MOREDATA;
+       }
+       dev_queue_xmit(skb);
+}
+
+
+/* Called only as a scheduled task for pending AP frames. */
+static void handle_pspoll(local_info_t *local,
+                         struct ieee80211_hdr *hdr,
+                         struct hostap_80211_rx_status *rx_stats)
+{
+       struct net_device *dev = local->dev;
+       struct sta_info *sta;
+       u16 aid;
+       struct sk_buff *skb;
+
+       PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=" MACSTR ", TA=" MACSTR
+              " PWRMGT=%d\n",
+              MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
+              !!(le16_to_cpu(hdr->frame_ctl) & IEEE80211_FCTL_PM));
+
+       if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
+               PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=" MACSTR
+                      " not own MAC\n", MAC2STR(hdr->addr1));
+               return;
+       }
+
+       aid = __le16_to_cpu(hdr->duration_id);
+       if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) {
+               PDEBUG(DEBUG_PS, "   PSPOLL and AID[15:14] not set\n");
+               return;
+       }
+       aid &= ~BIT(15) & ~BIT(14);
+       if (aid == 0 || aid > MAX_AID_TABLE_SIZE) {
+               PDEBUG(DEBUG_PS, "   invalid aid=%d\n", aid);
+               return;
+       }
+       PDEBUG(DEBUG_PS2, "   aid=%d\n", aid);
+
+       spin_lock_bh(&local->ap->sta_table_lock);
+       sta = ap_get_sta(local->ap, hdr->addr2);
+       if (sta)
+               atomic_inc(&sta->users);
+       spin_unlock_bh(&local->ap->sta_table_lock);
+
+       if (sta == NULL) {
+               PDEBUG(DEBUG_PS, "   STA not found\n");
+               return;
+       }
+       if (sta->aid != aid) {
+               PDEBUG(DEBUG_PS, "   received aid=%i does not match with "
+                      "assoc.aid=%d\n", aid, sta->aid);
+               return;
+       }
+
+       /* FIX: todo:
+        * - add timeout for buffering (clear aid in TIM vector if buffer timed
+        *   out (expiry time must be longer than ListenInterval for
+        *   the corresponding STA; "8802-11: 11.2.1.9 AP aging function"
+        * - what to do, if buffered, pspolled, and sent frame is not ACKed by
+        *   sta; store buffer for later use and leave TIM aid bit set? use
+        *   TX event to check whether frame was ACKed?
+        */
+
+       while ((skb = skb_dequeue(&sta->tx_buf)) != NULL) {
+               /* send buffered frame .. */
+               PDEBUG(DEBUG_PS2, "Sending buffered frame to STA after PS POLL"
+                      " (buffer_count=%d)\n", skb_queue_len(&sta->tx_buf));
+
+               pspoll_send_buffered(local, sta, skb);
+
+               if (sta->flags & WLAN_STA_PS) {
+                       /* send only one buffered packet per PS Poll */
+                       /* FIX: should ignore further PS Polls until the
+                        * buffered packet that was just sent is acknowledged
+                        * (Tx or TxExc event) */
+                       break;
+               }
+       }
+
+       if (skb_queue_empty(&sta->tx_buf)) {
+               /* try to clear aid from TIM */
+               if (!(sta->flags & WLAN_STA_TIM))
+                       PDEBUG(DEBUG_PS2,  "Re-unsetting TIM for aid %d\n",
+                              aid);
+               hostap_set_tim(local, aid, 0);
+               sta->flags &= ~WLAN_STA_TIM;
+       }
+
+       atomic_dec(&sta->users);
+}
+
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+
+static void handle_wds_oper_queue(void *data)
+{
+       local_info_t *local = data;
+       struct wds_oper_data *entry, *prev;
+
+       spin_lock_bh(&local->lock);
+       entry = local->ap->wds_oper_entries;
+       local->ap->wds_oper_entries = NULL;
+       spin_unlock_bh(&local->lock);
+
+       while (entry) {
+               PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection "
+                      "to AP " MACSTR "\n",
+                      local->dev->name,
+                      entry->type == WDS_ADD ? "adding" : "removing",
+                      MAC2STR(entry->addr));
+               if (entry->type == WDS_ADD)
+                       prism2_wds_add(local, entry->addr, 0);
+               else if (entry->type == WDS_DEL)
+                       prism2_wds_del(local, entry->addr, 0, 1);
+
+               prev = entry;
+               entry = entry->next;
+               kfree(prev);
+       }
+}
+
+
+/* Called only as a scheduled task for pending AP frames. */
+static void handle_beacon(local_info_t *local, struct sk_buff *skb,
+                         struct hostap_80211_rx_status *rx_stats)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       char *body = skb->data + IEEE80211_MGMT_HDR_LEN;
+       int len, left;
+       u16 *pos, beacon_int, capability;
+       char *ssid = NULL;
+       unsigned char *supp_rates = NULL;
+       int ssid_len = 0, supp_rates_len = 0;
+       struct sta_info *sta = NULL;
+       int new_sta = 0, channel = -1;
+
+       len = skb->len - IEEE80211_MGMT_HDR_LEN;
+
+       if (len < 8 + 2 + 2) {
+               printk(KERN_DEBUG "handle_beacon - too short payload "
+                      "(len=%d)\n", len);
+               return;
+       }
+
+       pos = (u16 *) body;
+       left = len;
+
+       /* Timestamp (8 octets) */
+       pos += 4; left -= 8;
+       /* Beacon interval (2 octets) */
+       beacon_int = __le16_to_cpu(*pos);
+       pos++; left -= 2;
+       /* Capability information (2 octets) */
+       capability = __le16_to_cpu(*pos);
+       pos++; left -= 2;
+
+       if (local->ap->ap_policy != AP_OTHER_AP_EVEN_IBSS &&
+           capability & WLAN_CAPABILITY_IBSS)
+               return;
+
+       if (left >= 2) {
+               unsigned int ileft;
+               unsigned char *u = (unsigned char *) pos;
+
+               if (*u == WLAN_EID_SSID) {
+                       u++; left--;
+                       ileft = *u;
+                       u++; left--;
+
+                       if (ileft > left || ileft > MAX_SSID_LEN) {
+                               PDEBUG(DEBUG_AP, "SSID: overflow\n");
+                               return;
+                       }
+
+                       if (local->ap->ap_policy == AP_OTHER_AP_SAME_SSID &&
+                           (ileft != strlen(local->essid) ||
+                            memcmp(local->essid, u, ileft) != 0)) {
+                               /* not our SSID */
+                               return;
+                       }
+
+                       ssid = u;
+                       ssid_len = ileft;
+
+                       u += ileft;
+                       left -= ileft;
+               }
+
+               if (*u == WLAN_EID_SUPP_RATES) {
+                       u++; left--;
+                       ileft = *u;
+                       u++; left--;
+
+                       if (ileft > left || ileft == 0 || ileft > 8) {
+                               PDEBUG(DEBUG_AP, " - SUPP_RATES len error\n");
+                               return;
+                       }
+
+                       supp_rates = u;
+                       supp_rates_len = ileft;
+
+                       u += ileft;
+                       left -= ileft;
+               }
+
+               if (*u == WLAN_EID_DS_PARAMS) {
+                       u++; left--;
+                       ileft = *u;
+                       u++; left--;
+
+                       if (ileft > left || ileft != 1) {
+                               PDEBUG(DEBUG_AP, " - DS_PARAMS len error\n");
+                               return;
+                       }
+
+                       channel = *u;
+
+                       u += ileft;
+                       left -= ileft;
+               }
+       }
+
+       spin_lock_bh(&local->ap->sta_table_lock);
+       sta = ap_get_sta(local->ap, hdr->addr2);
+       if (sta != NULL)
+               atomic_inc(&sta->users);
+       spin_unlock_bh(&local->ap->sta_table_lock);
+
+       if (sta == NULL) {
+               /* add new AP */
+               new_sta = 1;
+               sta = ap_add_sta(local->ap, hdr->addr2);
+               if (sta == NULL) {
+                       printk(KERN_INFO "prism2: kmalloc failed for AP "
+                              "data structure\n");
+                       return;
+               }
+               hostap_event_new_sta(local->dev, sta);
+
+               /* mark APs authentication and associated for pseudo ad-hoc
+                * style communication */
+               sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
+
+               if (local->ap->autom_ap_wds) {
+                       hostap_wds_link_oper(local, sta->addr, WDS_ADD);
+               }
+       }
+
+       sta->ap = 1;
+       if (ssid) {
+               sta->u.ap.ssid_len = ssid_len;
+               memcpy(sta->u.ap.ssid, ssid, ssid_len);
+               sta->u.ap.ssid[ssid_len] = '\0';
+       } else {
+               sta->u.ap.ssid_len = 0;
+               sta->u.ap.ssid[0] = '\0';
+       }
+       sta->u.ap.channel = channel;
+       sta->rx_packets++;
+       sta->rx_bytes += len;
+       sta->u.ap.last_beacon = sta->last_rx = jiffies;
+       sta->capability = capability;
+       sta->listen_interval = beacon_int;
+
+       atomic_dec(&sta->users);
+
+       if (new_sta) {
+               memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
+               memcpy(sta->supported_rates, supp_rates, supp_rates_len);
+               prism2_check_tx_rates(sta);
+       }
+}
+
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+/* Called only as a tasklet. */
+static void handle_ap_item(local_info_t *local, struct sk_buff *skb,
+                          struct hostap_80211_rx_status *rx_stats)
+{
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+       struct net_device *dev = local->dev;
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+       u16 fc, type, stype;
+       struct ieee80211_hdr *hdr;
+
+       /* FIX: should give skb->len to handler functions and check that the
+        * buffer is long enough */
+       hdr = (struct ieee80211_hdr *) skb->data;
+       fc = le16_to_cpu(hdr->frame_ctl);
+       type = WLAN_FC_GET_TYPE(fc);
+       stype = WLAN_FC_GET_STYPE(fc);
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+       if (!local->hostapd && type == IEEE80211_FTYPE_DATA) {
+               PDEBUG(DEBUG_AP, "handle_ap_item - data frame\n");
+
+               if (!(fc & IEEE80211_FCTL_TODS) ||
+                   (fc & IEEE80211_FCTL_FROMDS)) {
+                       if (stype == IEEE80211_STYPE_NULLFUNC) {
+                               /* no ToDS nullfunc seems to be used to check
+                                * AP association; so send reject message to
+                                * speed up re-association */
+                               ap_handle_dropped_data(local, hdr);
+                               goto done;
+                       }
+                       PDEBUG(DEBUG_AP, "   not ToDS frame (fc=0x%04x)\n",
+                              fc);
+                       goto done;
+               }
+
+               if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
+                       PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)="
+                              MACSTR " not own MAC\n",
+                              MAC2STR(hdr->addr1));
+                       goto done;
+               }
+
+               if (local->ap->nullfunc_ack &&
+                   stype == IEEE80211_STYPE_NULLFUNC)
+                       ap_handle_data_nullfunc(local, hdr);
+               else
+                       ap_handle_dropped_data(local, hdr);
+               goto done;
+       }
+
+       if (type == IEEE80211_FTYPE_MGMT && stype == IEEE80211_STYPE_BEACON) {
+               handle_beacon(local, skb, rx_stats);
+               goto done;
+       }
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+       if (type == IEEE80211_FTYPE_CTL && stype == IEEE80211_STYPE_PSPOLL) {
+               handle_pspoll(local, hdr, rx_stats);
+               goto done;
+       }
+
+       if (local->hostapd) {
+               PDEBUG(DEBUG_AP, "Unknown frame in AP queue: type=0x%02x "
+                      "subtype=0x%02x\n", type, stype);
+               goto done;
+       }
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+       if (type != IEEE80211_FTYPE_MGMT) {
+               PDEBUG(DEBUG_AP, "handle_ap_item - not a management frame?\n");
+               goto done;
+       }
+
+       if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
+               PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=" MACSTR
+                      " not own MAC\n", MAC2STR(hdr->addr1));
+               goto done;
+       }
+
+       if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) {
+               PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=" MACSTR
+                      " not own MAC\n", MAC2STR(hdr->addr3));
+               goto done;
+       }
+
+       switch (stype) {
+       case IEEE80211_STYPE_ASSOC_REQ:
+               handle_assoc(local, skb, rx_stats, 0);
+               break;
+       case IEEE80211_STYPE_ASSOC_RESP:
+               PDEBUG(DEBUG_AP, "==> ASSOC RESP (ignored)\n");
+               break;
+       case IEEE80211_STYPE_REASSOC_REQ:
+               handle_assoc(local, skb, rx_stats, 1);
+               break;
+       case IEEE80211_STYPE_REASSOC_RESP:
+               PDEBUG(DEBUG_AP, "==> REASSOC RESP (ignored)\n");
+               break;
+       case IEEE80211_STYPE_ATIM:
+               PDEBUG(DEBUG_AP, "==> ATIM (ignored)\n");
+               break;
+       case IEEE80211_STYPE_DISASSOC:
+               handle_disassoc(local, skb, rx_stats);
+               break;
+       case IEEE80211_STYPE_AUTH:
+               handle_authen(local, skb, rx_stats);
+               break;
+       case IEEE80211_STYPE_DEAUTH:
+               handle_deauth(local, skb, rx_stats);
+               break;
+       default:
+               PDEBUG(DEBUG_AP, "Unknown mgmt frame subtype 0x%02x\n",
+                      stype >> 4);
+               break;
+       }
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+ done:
+       dev_kfree_skb(skb);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+void hostap_rx(struct net_device *dev, struct sk_buff *skb,
+              struct hostap_80211_rx_status *rx_stats)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       u16 fc;
+       struct ieee80211_hdr *hdr;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (skb->len < 16)
+               goto drop;
+
+       local->stats.rx_packets++;
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       fc = le16_to_cpu(hdr->frame_ctl);
+
+       if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL &&
+           WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT &&
+           WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_BEACON)
+               goto drop;
+
+       skb->protocol = __constant_htons(ETH_P_HOSTAP);
+       handle_ap_item(local, skb, rx_stats);
+       return;
+
+ drop:
+       dev_kfree_skb(skb);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void schedule_packet_send(local_info_t *local, struct sta_info *sta)
+{
+       struct sk_buff *skb;
+       struct ieee80211_hdr *hdr;
+       struct hostap_80211_rx_status rx_stats;
+
+       if (skb_queue_empty(&sta->tx_buf))
+               return;
+
+       skb = dev_alloc_skb(16);
+       if (skb == NULL) {
+               printk(KERN_DEBUG "%s: schedule_packet_send: skb alloc "
+                      "failed\n", local->dev->name);
+               return;
+       }
+
+       hdr = (struct ieee80211_hdr *) skb_put(skb, 16);
+
+       /* Generate a fake pspoll frame to start packet delivery */
+       hdr->frame_ctl = __constant_cpu_to_le16(
+               IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
+       memcpy(hdr->addr1, local->dev->dev_addr, ETH_ALEN);
+       memcpy(hdr->addr2, sta->addr, ETH_ALEN);
+       hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14));
+
+       PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for "
+              "STA " MACSTR "\n", local->dev->name, MAC2STR(sta->addr));
+
+       skb->dev = local->dev;
+
+       memset(&rx_stats, 0, sizeof(rx_stats));
+       hostap_rx(local->dev, skb, &rx_stats);
+}
+
+
+static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
+                                 struct iw_quality qual[], int buf_size,
+                                 int aplist)
+{
+       struct ap_data *ap = local->ap;
+       struct list_head *ptr;
+       int count = 0;
+
+       spin_lock_bh(&ap->sta_table_lock);
+
+       for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list;
+            ptr = ptr->next) {
+               struct sta_info *sta = (struct sta_info *) ptr;
+
+               if (aplist && !sta->ap)
+                       continue;
+               addr[count].sa_family = ARPHRD_ETHER;
+               memcpy(addr[count].sa_data, sta->addr, ETH_ALEN);
+               if (sta->last_rx_silence == 0)
+                       qual[count].qual = sta->last_rx_signal < 27 ?
+                               0 : (sta->last_rx_signal - 27) * 92 / 127;
+               else
+                       qual[count].qual = sta->last_rx_signal -
+                               sta->last_rx_silence - 35;
+               qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal);
+               qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence);
+               qual[count].updated = sta->last_rx_updated;
+
+               sta->last_rx_updated = 0;
+
+               count++;
+               if (count >= buf_size)
+                       break;
+       }
+       spin_unlock_bh(&ap->sta_table_lock);
+
+       return count;
+}
+
+
+/* Translate our list of Access Points & Stations to a card independant
+ * format that the Wireless Tools will understand - Jean II */
+static int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       struct ap_data *ap;
+       struct list_head *ptr;
+       struct iw_event iwe;
+       char *current_ev = buffer;
+       char *end_buf = buffer + IW_SCAN_MAX_DATA;
+#if !defined(PRISM2_NO_KERNEL_IEEE80211_MGMT)
+       char buf[64];
+#endif
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+       ap = local->ap;
+
+       spin_lock_bh(&ap->sta_table_lock);
+
+       for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list;
+            ptr = ptr->next) {
+               struct sta_info *sta = (struct sta_info *) ptr;
+
+               /* First entry *MUST* be the AP MAC address */
+               memset(&iwe, 0, sizeof(iwe));
+               iwe.cmd = SIOCGIWAP;
+               iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+               memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN);
+               iwe.len = IW_EV_ADDR_LEN;
+               current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+                                                 IW_EV_ADDR_LEN);
+
+               /* Use the mode to indicate if it's a station or
+                * an Access Point */
+               memset(&iwe, 0, sizeof(iwe));
+               iwe.cmd = SIOCGIWMODE;
+               if (sta->ap)
+                       iwe.u.mode = IW_MODE_MASTER;
+               else
+                       iwe.u.mode = IW_MODE_INFRA;
+               iwe.len = IW_EV_UINT_LEN;
+               current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+                                                 IW_EV_UINT_LEN);
+
+               /* Some quality */
+               memset(&iwe, 0, sizeof(iwe));
+               iwe.cmd = IWEVQUAL;
+               if (sta->last_rx_silence == 0)
+                       iwe.u.qual.qual = sta->last_rx_signal < 27 ?
+                               0 : (sta->last_rx_signal - 27) * 92 / 127;
+               else
+                       iwe.u.qual.qual = sta->last_rx_signal -
+                               sta->last_rx_silence - 35;
+               iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal);
+               iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence);
+               iwe.u.qual.updated = sta->last_rx_updated;
+               iwe.len = IW_EV_QUAL_LEN;
+               current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+                                                 IW_EV_QUAL_LEN);
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+               if (sta->ap) {
+                       memset(&iwe, 0, sizeof(iwe));
+                       iwe.cmd = SIOCGIWESSID;
+                       iwe.u.data.length = sta->u.ap.ssid_len;
+                       iwe.u.data.flags = 1;
+                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                                                         &iwe,
+                                                         sta->u.ap.ssid);
+
+                       memset(&iwe, 0, sizeof(iwe));
+                       iwe.cmd = SIOCGIWENCODE;
+                       if (sta->capability & WLAN_CAPABILITY_PRIVACY)
+                               iwe.u.data.flags =
+                                       IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+                       else
+                               iwe.u.data.flags = IW_ENCODE_DISABLED;
+                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                                                         &iwe,
+                                                         sta->u.ap.ssid
+                                                         /* 0 byte memcpy */);
+
+                       if (sta->u.ap.channel > 0 &&
+                           sta->u.ap.channel <= FREQ_COUNT) {
+                               memset(&iwe, 0, sizeof(iwe));
+                               iwe.cmd = SIOCGIWFREQ;
+                               iwe.u.freq.m = freq_list[sta->u.ap.channel - 1]
+                                       * 100000;
+                               iwe.u.freq.e = 1;
+                               current_ev = iwe_stream_add_event(
+                                       current_ev, end_buf, &iwe,
+                                       IW_EV_FREQ_LEN);
+                       }
+
+                       memset(&iwe, 0, sizeof(iwe));
+                       iwe.cmd = IWEVCUSTOM;
+                       sprintf(buf, "beacon_interval=%d",
+                               sta->listen_interval);
+                       iwe.u.data.length = strlen(buf);
+                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                                                         &iwe, buf);
+               }
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+               sta->last_rx_updated = 0;
+
+               /* To be continued, we should make good use of IWEVCUSTOM */
+       }
+
+       spin_unlock_bh(&ap->sta_table_lock);
+
+       return current_ev - buffer;
+}
+
+
+static int prism2_hostapd_add_sta(struct ap_data *ap,
+                                 struct prism2_hostapd_param *param)
+{
+       struct sta_info *sta;
+
+       spin_lock_bh(&ap->sta_table_lock);
+       sta = ap_get_sta(ap, param->sta_addr);
+       if (sta)
+               atomic_inc(&sta->users);
+       spin_unlock_bh(&ap->sta_table_lock);
+
+       if (sta == NULL) {
+               sta = ap_add_sta(ap, param->sta_addr);
+               if (sta == NULL)
+                       return -1;
+       }
+
+       if (!(sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
+               hostap_event_new_sta(sta->local->dev, sta);
+
+       sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
+       sta->last_rx = jiffies;
+       sta->aid = param->u.add_sta.aid;
+       sta->capability = param->u.add_sta.capability;
+       sta->tx_supp_rates = param->u.add_sta.tx_supp_rates;
+       if (sta->tx_supp_rates & WLAN_RATE_1M)
+               sta->supported_rates[0] = 2;
+       if (sta->tx_supp_rates & WLAN_RATE_2M)
+               sta->supported_rates[1] = 4;
+       if (sta->tx_supp_rates & WLAN_RATE_5M5)
+               sta->supported_rates[2] = 11;
+       if (sta->tx_supp_rates & WLAN_RATE_11M)
+               sta->supported_rates[3] = 22;
+       prism2_check_tx_rates(sta);
+       atomic_dec(&sta->users);
+       return 0;
+}
+
+
+static int prism2_hostapd_remove_sta(struct ap_data *ap,
+                                    struct prism2_hostapd_param *param)
+{
+       struct sta_info *sta;
+
+       spin_lock_bh(&ap->sta_table_lock);
+       sta = ap_get_sta(ap, param->sta_addr);
+       if (sta) {
+               ap_sta_hash_del(ap, sta);
+               list_del(&sta->list);
+       }
+       spin_unlock_bh(&ap->sta_table_lock);
+
+       if (!sta)
+               return -ENOENT;
+
+       if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
+               hostap_event_expired_sta(sta->local->dev, sta);
+       ap_free_sta(ap, sta);
+
+       return 0;
+}
+
+
+static int prism2_hostapd_get_info_sta(struct ap_data *ap,
+                                      struct prism2_hostapd_param *param)
+{
+       struct sta_info *sta;
+
+       spin_lock_bh(&ap->sta_table_lock);
+       sta = ap_get_sta(ap, param->sta_addr);
+       if (sta)
+               atomic_inc(&sta->users);
+       spin_unlock_bh(&ap->sta_table_lock);
+
+       if (!sta)
+               return -ENOENT;
+
+       param->u.get_info_sta.inactive_sec = (jiffies - sta->last_rx) / HZ;
+
+       atomic_dec(&sta->users);
+
+       return 1;
+}
+
+
+static int prism2_hostapd_set_flags_sta(struct ap_data *ap,
+                                       struct prism2_hostapd_param *param)
+{
+       struct sta_info *sta;
+
+       spin_lock_bh(&ap->sta_table_lock);
+       sta = ap_get_sta(ap, param->sta_addr);
+       if (sta) {
+               sta->flags |= param->u.set_flags_sta.flags_or;
+               sta->flags &= param->u.set_flags_sta.flags_and;
+       }
+       spin_unlock_bh(&ap->sta_table_lock);
+
+       if (!sta)
+               return -ENOENT;
+
+       return 0;
+}
+
+
+static int prism2_hostapd_sta_clear_stats(struct ap_data *ap,
+                                         struct prism2_hostapd_param *param)
+{
+       struct sta_info *sta;
+       int rate;
+
+       spin_lock_bh(&ap->sta_table_lock);
+       sta = ap_get_sta(ap, param->sta_addr);
+       if (sta) {
+               sta->rx_packets = sta->tx_packets = 0;
+               sta->rx_bytes = sta->tx_bytes = 0;
+               for (rate = 0; rate < WLAN_RATE_COUNT; rate++) {
+                       sta->tx_count[rate] = 0;
+                       sta->rx_count[rate] = 0;
+               }
+       }
+       spin_unlock_bh(&ap->sta_table_lock);
+
+       if (!sta)
+               return -ENOENT;
+
+       return 0;
+}
+
+
+static int prism2_hostapd(struct ap_data *ap,
+                         struct prism2_hostapd_param *param)
+{
+       switch (param->cmd) {
+       case PRISM2_HOSTAPD_FLUSH:
+               ap_control_kickall(ap);
+               return 0;
+       case PRISM2_HOSTAPD_ADD_STA:
+               return prism2_hostapd_add_sta(ap, param);
+       case PRISM2_HOSTAPD_REMOVE_STA:
+               return prism2_hostapd_remove_sta(ap, param);
+       case PRISM2_HOSTAPD_GET_INFO_STA:
+               return prism2_hostapd_get_info_sta(ap, param);
+       case PRISM2_HOSTAPD_SET_FLAGS_STA:
+               return prism2_hostapd_set_flags_sta(ap, param);
+       case PRISM2_HOSTAPD_STA_CLEAR_STATS:
+               return prism2_hostapd_sta_clear_stats(ap, param);
+       default:
+               printk(KERN_WARNING "prism2_hostapd: unknown cmd=%d\n",
+                      param->cmd);
+               return -EOPNOTSUPP;
+       }
+}
+
+
+/* Update station info for host-based TX rate control and return current
+ * TX rate */
+static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev)
+{
+       int ret = sta->tx_rate;
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       sta->tx_count[sta->tx_rate_idx]++;
+       sta->tx_since_last_failure++;
+       sta->tx_consecutive_exc = 0;
+       if (sta->tx_since_last_failure >= WLAN_RATE_UPDATE_COUNT &&
+           sta->tx_rate_idx < sta->tx_max_rate) {
+               /* use next higher rate */
+               int old_rate, new_rate;
+               old_rate = new_rate = sta->tx_rate_idx;
+               while (new_rate < sta->tx_max_rate) {
+                       new_rate++;
+                       if (ap_tx_rate_ok(new_rate, sta, local)) {
+                               sta->tx_rate_idx = new_rate;
+                               break;
+                       }
+               }
+               if (old_rate != sta->tx_rate_idx) {
+                       switch (sta->tx_rate_idx) {
+                       case 0: sta->tx_rate = 10; break;
+                       case 1: sta->tx_rate = 20; break;
+                       case 2: sta->tx_rate = 55; break;
+                       case 3: sta->tx_rate = 110; break;
+                       default: sta->tx_rate = 0; break;
+                       }
+                       PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate raised to"
+                              " %d\n", dev->name, MAC2STR(sta->addr),
+                              sta->tx_rate);
+               }
+               sta->tx_since_last_failure = 0;
+       }
+
+       return ret;
+}
+
+
+/* Called only from software IRQ. Called for each TX frame prior possible
+ * encryption and transmit. */
+ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
+{
+       struct sta_info *sta = NULL;
+       struct sk_buff *skb = tx->skb;
+       int set_tim, ret;
+       struct ieee80211_hdr *hdr;
+       struct hostap_skb_tx_data *meta;
+
+       meta = (struct hostap_skb_tx_data *) skb->cb;
+       ret = AP_TX_CONTINUE;
+       if (local->ap == NULL || skb->len < 10 ||
+           meta->iface->type == HOSTAP_INTERFACE_STA)
+               goto out;
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+
+       if (hdr->addr1[0] & 0x01) {
+               /* broadcast/multicast frame - no AP related processing */
+               goto out;
+       }
+
+       /* unicast packet - check whether destination STA is associated */
+       spin_lock(&local->ap->sta_table_lock);
+       sta = ap_get_sta(local->ap, hdr->addr1);
+       if (sta)
+               atomic_inc(&sta->users);
+       spin_unlock(&local->ap->sta_table_lock);
+
+       if (local->iw_mode == IW_MODE_MASTER && sta == NULL &&
+           !(meta->flags & HOSTAP_TX_FLAGS_WDS) &&
+           meta->iface->type != HOSTAP_INTERFACE_MASTER &&
+           meta->iface->type != HOSTAP_INTERFACE_AP) {
+#if 0
+               /* This can happen, e.g., when wlan0 is added to a bridge and
+                * bridging code does not know which port is the correct target
+                * for a unicast frame. In this case, the packet is send to all
+                * ports of the bridge. Since this is a valid scenario, do not
+                * print out any errors here. */
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "AP: drop packet to non-associated "
+                              "STA " MACSTR "\n", MAC2STR(hdr->addr1));
+               }
+#endif
+               local->ap->tx_drop_nonassoc++;
+               ret = AP_TX_DROP;
+               goto out;
+       }
+
+       if (sta == NULL)
+               goto out;
+
+       if (!(sta->flags & WLAN_STA_AUTHORIZED))
+               ret = AP_TX_CONTINUE_NOT_AUTHORIZED;
+
+       /* Set tx_rate if using host-based TX rate control */
+       if (!local->fw_tx_rate_control)
+               local->ap->last_tx_rate = meta->rate =
+                       ap_update_sta_tx_rate(sta, local->dev);
+
+       if (local->iw_mode != IW_MODE_MASTER)
+               goto out;
+
+       if (!(sta->flags & WLAN_STA_PS))
+               goto out;
+
+       if (meta->flags & HOSTAP_TX_FLAGS_ADD_MOREDATA) {
+               /* indicate to STA that more frames follow */
+               hdr->frame_ctl |=
+                       __constant_cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+       }
+
+       if (meta->flags & HOSTAP_TX_FLAGS_BUFFERED_FRAME) {
+               /* packet was already buffered and now send due to
+                * PS poll, so do not rebuffer it */
+               goto out;
+       }
+
+       if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) {
+               PDEBUG(DEBUG_PS, "%s: No more space in STA (" MACSTR ")'s PS "
+                      "mode buffer\n", local->dev->name, MAC2STR(sta->addr));
+               /* Make sure that TIM is set for the station (it might not be
+                * after AP wlan hw reset). */
+               /* FIX: should fix hw reset to restore bits based on STA
+                * buffer state.. */
+               hostap_set_tim(local, sta->aid, 1);
+               sta->flags |= WLAN_STA_TIM;
+               ret = AP_TX_DROP;
+               goto out;
+       }
+
+       /* STA in PS mode, buffer frame for later delivery */
+       set_tim = skb_queue_empty(&sta->tx_buf);
+       skb_queue_tail(&sta->tx_buf, skb);
+       /* FIX: could save RX time to skb and expire buffered frames after
+        * some time if STA does not poll for them */
+
+       if (set_tim) {
+               if (sta->flags & WLAN_STA_TIM)
+                       PDEBUG(DEBUG_PS2, "Re-setting TIM for aid %d\n",
+                              sta->aid);
+               hostap_set_tim(local, sta->aid, 1);
+               sta->flags |= WLAN_STA_TIM;
+       }
+
+       ret = AP_TX_BUFFERED;
+
+ out:
+       if (sta != NULL) {
+               if (ret == AP_TX_CONTINUE ||
+                   ret == AP_TX_CONTINUE_NOT_AUTHORIZED) {
+                       sta->tx_packets++;
+                       sta->tx_bytes += skb->len;
+                       sta->last_tx = jiffies;
+               }
+
+               if ((ret == AP_TX_CONTINUE ||
+                    ret == AP_TX_CONTINUE_NOT_AUTHORIZED) &&
+                   sta->crypt && tx->host_encrypt) {
+                       tx->crypt = sta->crypt;
+                       tx->sta_ptr = sta; /* hostap_handle_sta_release() will
+                                           * be called to release sta info
+                                           * later */
+               } else
+                       atomic_dec(&sta->users);
+       }
+
+       return ret;
+}
+
+
+void hostap_handle_sta_release(void *ptr)
+{
+       struct sta_info *sta = ptr;
+       atomic_dec(&sta->users);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb)
+{
+       struct sta_info *sta;
+       struct ieee80211_hdr *hdr;
+       struct hostap_skb_tx_data *meta;
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       meta = (struct hostap_skb_tx_data *) skb->cb;
+
+       spin_lock(&local->ap->sta_table_lock);
+       sta = ap_get_sta(local->ap, hdr->addr1);
+       if (!sta) {
+               spin_unlock(&local->ap->sta_table_lock);
+               PDEBUG(DEBUG_AP, "%s: Could not find STA " MACSTR " for this "
+                      "TX error (@%lu)\n",
+                      local->dev->name, MAC2STR(hdr->addr1), jiffies);
+               return;
+       }
+
+       sta->tx_since_last_failure = 0;
+       sta->tx_consecutive_exc++;
+
+       if (sta->tx_consecutive_exc >= WLAN_RATE_DECREASE_THRESHOLD &&
+           sta->tx_rate_idx > 0 && meta->rate <= sta->tx_rate) {
+               /* use next lower rate */
+               int old, rate;
+               old = rate = sta->tx_rate_idx;
+               while (rate > 0) {
+                       rate--;
+                       if (ap_tx_rate_ok(rate, sta, local)) {
+                               sta->tx_rate_idx = rate;
+                               break;
+                       }
+               }
+               if (old != sta->tx_rate_idx) {
+                       switch (sta->tx_rate_idx) {
+                       case 0: sta->tx_rate = 10; break;
+                       case 1: sta->tx_rate = 20; break;
+                       case 2: sta->tx_rate = 55; break;
+                       case 3: sta->tx_rate = 110; break;
+                       default: sta->tx_rate = 0; break;
+                       }
+                       PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate lowered "
+                              "to %d\n", local->dev->name, MAC2STR(sta->addr),
+                              sta->tx_rate);
+               }
+               sta->tx_consecutive_exc = 0;
+       }
+       spin_unlock(&local->ap->sta_table_lock);
+}
+
+
+static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta,
+                                 int pwrmgt, int type, int stype)
+{
+       if (pwrmgt && !(sta->flags & WLAN_STA_PS)) {
+               sta->flags |= WLAN_STA_PS;
+               PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to use PS "
+                      "mode (type=0x%02X, stype=0x%02X)\n",
+                      MAC2STR(sta->addr), type >> 2, stype >> 4);
+       } else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) {
+               sta->flags &= ~WLAN_STA_PS;
+               PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to not use "
+                      "PS mode (type=0x%02X, stype=0x%02X)\n",
+                      MAC2STR(sta->addr), type >> 2, stype >> 4);
+               if (type != IEEE80211_FTYPE_CTL ||
+                   stype != IEEE80211_STYPE_PSPOLL)
+                       schedule_packet_send(local, sta);
+       }
+}
+
+
+/* Called only as a tasklet (software IRQ). Called for each RX frame to update
+ * STA power saving state. pwrmgt is a flag from 802.11 frame_ctl field. */
+int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr)
+{
+       struct sta_info *sta;
+       u16 fc;
+
+       spin_lock(&local->ap->sta_table_lock);
+       sta = ap_get_sta(local->ap, hdr->addr2);
+       if (sta)
+               atomic_inc(&sta->users);
+       spin_unlock(&local->ap->sta_table_lock);
+
+       if (!sta)
+               return -1;
+
+       fc = le16_to_cpu(hdr->frame_ctl);
+       hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM,
+                             WLAN_FC_GET_TYPE(fc), WLAN_FC_GET_STYPE(fc));
+
+       atomic_dec(&sta->users);
+       return 0;
+}
+
+
+/* Called only as a tasklet (software IRQ). Called for each RX frame after
+ * getting RX header and payload from hardware. */
+ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
+                              struct sk_buff *skb,
+                              struct hostap_80211_rx_status *rx_stats,
+                              int wds)
+{
+       int ret;
+       struct sta_info *sta;
+       u16 fc, type, stype;
+       struct ieee80211_hdr *hdr;
+
+       if (local->ap == NULL)
+               return AP_RX_CONTINUE;
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+
+       fc = le16_to_cpu(hdr->frame_ctl);
+       type = WLAN_FC_GET_TYPE(fc);
+       stype = WLAN_FC_GET_STYPE(fc);
+
+       spin_lock(&local->ap->sta_table_lock);
+       sta = ap_get_sta(local->ap, hdr->addr2);
+       if (sta)
+               atomic_inc(&sta->users);
+       spin_unlock(&local->ap->sta_table_lock);
+
+       if (sta && !(sta->flags & WLAN_STA_AUTHORIZED))
+               ret = AP_RX_CONTINUE_NOT_AUTHORIZED;
+       else
+               ret = AP_RX_CONTINUE;
+
+
+       if (fc & IEEE80211_FCTL_TODS) {
+               if (!wds && (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
+                       if (local->hostapd) {
+                               prism2_rx_80211(local->apdev, skb, rx_stats,
+                                               PRISM2_RX_NON_ASSOC);
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+                       } else {
+                               printk(KERN_DEBUG "%s: dropped received packet"
+                                      " from non-associated STA " MACSTR
+                                      " (type=0x%02x, subtype=0x%02x)\n",
+                                      dev->name, MAC2STR(hdr->addr2),
+                                      type >> 2, stype >> 4);
+                               hostap_rx(dev, skb, rx_stats);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+                       }
+                       ret = AP_RX_EXIT;
+                       goto out;
+               }
+       } else if (fc & IEEE80211_FCTL_FROMDS) {
+               if (!wds) {
+                       /* FromDS frame - not for us; probably
+                        * broadcast/multicast in another BSS - drop */
+                       if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) {
+                               printk(KERN_DEBUG "Odd.. FromDS packet "
+                                      "received with own BSSID\n");
+                               hostap_dump_rx_80211(dev->name, skb, rx_stats);
+                       }
+                       ret = AP_RX_DROP;
+                       goto out;
+               }
+       } else if (stype == IEEE80211_STYPE_NULLFUNC && sta == NULL &&
+                  memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) {
+
+               if (local->hostapd) {
+                       prism2_rx_80211(local->apdev, skb, rx_stats,
+                                       PRISM2_RX_NON_ASSOC);
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+               } else {
+                       /* At least Lucent f/w seems to send data::nullfunc
+                        * frames with no ToDS flag when the current AP returns
+                        * after being unavailable for some time. Speed up
+                        * re-association by informing the station about it not
+                        * being associated. */
+                       printk(KERN_DEBUG "%s: rejected received nullfunc "
+                              "frame without ToDS from not associated STA "
+                              MACSTR "\n",
+                              dev->name, MAC2STR(hdr->addr2));
+                       hostap_rx(dev, skb, rx_stats);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+               }
+               ret = AP_RX_EXIT;
+               goto out;
+       } else if (stype == IEEE80211_STYPE_NULLFUNC) {
+               /* At least Lucent cards seem to send periodic nullfunc
+                * frames with ToDS. Let these through to update SQ
+                * stats and PS state. Nullfunc frames do not contain
+                * any data and they will be dropped below. */
+       } else {
+               /* If BSSID (Addr3) is foreign, this frame is a normal
+                * broadcast frame from an IBSS network. Drop it silently.
+                * If BSSID is own, report the dropping of this frame. */
+               if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) {
+                       printk(KERN_DEBUG "%s: dropped received packet from "
+                              MACSTR " with no ToDS flag (type=0x%02x, "
+                              "subtype=0x%02x)\n", dev->name,
+                              MAC2STR(hdr->addr2), type >> 2, stype >> 4);
+                       hostap_dump_rx_80211(dev->name, skb, rx_stats);
+               }
+               ret = AP_RX_DROP;
+               goto out;
+       }
+
+       if (sta) {
+               hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM,
+                                     type, stype);
+
+               sta->rx_packets++;
+               sta->rx_bytes += skb->len;
+               sta->last_rx = jiffies;
+       }
+
+       if (local->ap->nullfunc_ack && stype == IEEE80211_STYPE_NULLFUNC &&
+           fc & IEEE80211_FCTL_TODS) {
+               if (local->hostapd) {
+                       prism2_rx_80211(local->apdev, skb, rx_stats,
+                                       PRISM2_RX_NULLFUNC_ACK);
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+               } else {
+                       /* some STA f/w's seem to require control::ACK frame
+                        * for data::nullfunc, but Prism2 f/w 0.8.0 (at least
+                        * from Compaq) does not send this.. Try to generate
+                        * ACK for these frames from the host driver to make
+                        * power saving work with, e.g., Lucent WaveLAN f/w */
+                       hostap_rx(dev, skb, rx_stats);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+               }
+               ret = AP_RX_EXIT;
+               goto out;
+       }
+
+ out:
+       if (sta)
+               atomic_dec(&sta->users);
+
+       return ret;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+int hostap_handle_sta_crypto(local_info_t *local,
+                            struct ieee80211_hdr *hdr,
+                            struct ieee80211_crypt_data **crypt,
+                            void **sta_ptr)
+{
+       struct sta_info *sta;
+
+       spin_lock(&local->ap->sta_table_lock);
+       sta = ap_get_sta(local->ap, hdr->addr2);
+       if (sta)
+               atomic_inc(&sta->users);
+       spin_unlock(&local->ap->sta_table_lock);
+
+       if (!sta)
+               return -1;
+
+       if (sta->crypt) {
+               *crypt = sta->crypt;
+               *sta_ptr = sta;
+               /* hostap_handle_sta_release() will be called to release STA
+                * info */
+       } else
+               atomic_dec(&sta->users);
+
+       return 0;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr)
+{
+       struct sta_info *sta;
+       int ret = 0;
+
+       spin_lock(&ap->sta_table_lock);
+       sta = ap_get_sta(ap, sta_addr);
+       if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap)
+               ret = 1;
+       spin_unlock(&ap->sta_table_lock);
+
+       return ret;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr)
+{
+       struct sta_info *sta;
+       int ret = 0;
+
+       spin_lock(&ap->sta_table_lock);
+       sta = ap_get_sta(ap, sta_addr);
+       if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap &&
+           ((sta->flags & WLAN_STA_AUTHORIZED) ||
+            ap->local->ieee_802_1x == 0))
+               ret = 1;
+       spin_unlock(&ap->sta_table_lock);
+
+       return ret;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+int hostap_add_sta(struct ap_data *ap, u8 *sta_addr)
+{
+       struct sta_info *sta;
+       int ret = 1;
+
+       if (!ap)
+               return -1;
+
+       spin_lock(&ap->sta_table_lock);
+       sta = ap_get_sta(ap, sta_addr);
+       if (sta)
+               ret = 0;
+       spin_unlock(&ap->sta_table_lock);
+
+       if (ret == 1) {
+               sta = ap_add_sta(ap, sta_addr);
+               if (!sta)
+                       ret = -1;
+               sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
+               sta->ap = 1;
+               memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
+               /* No way of knowing which rates are supported since we did not
+                * get supported rates element from beacon/assoc req. Assume
+                * that remote end supports all 802.11b rates. */
+               sta->supported_rates[0] = 0x82;
+               sta->supported_rates[1] = 0x84;
+               sta->supported_rates[2] = 0x0b;
+               sta->supported_rates[3] = 0x16;
+               sta->tx_supp_rates = WLAN_RATE_1M | WLAN_RATE_2M |
+                       WLAN_RATE_5M5 | WLAN_RATE_11M;
+               sta->tx_rate = 110;
+               sta->tx_max_rate = sta->tx_rate_idx = 3;
+       }
+
+       return ret;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+int hostap_update_rx_stats(struct ap_data *ap,
+                          struct ieee80211_hdr *hdr,
+                          struct hostap_80211_rx_status *rx_stats)
+{
+       struct sta_info *sta;
+
+       if (!ap)
+               return -1;
+
+       spin_lock(&ap->sta_table_lock);
+       sta = ap_get_sta(ap, hdr->addr2);
+       if (sta) {
+               sta->last_rx_silence = rx_stats->noise;
+               sta->last_rx_signal = rx_stats->signal;
+               sta->last_rx_rate = rx_stats->rate;
+               sta->last_rx_updated = 7;
+               if (rx_stats->rate == 10)
+                       sta->rx_count[0]++;
+               else if (rx_stats->rate == 20)
+                       sta->rx_count[1]++;
+               else if (rx_stats->rate == 55)
+                       sta->rx_count[2]++;
+               else if (rx_stats->rate == 110)
+                       sta->rx_count[3]++;
+       }
+       spin_unlock(&ap->sta_table_lock);
+
+       return sta ? 0 : -1;
+}
+
+
+void hostap_update_rates(local_info_t *local)
+{
+       struct list_head *ptr;
+       struct ap_data *ap = local->ap;
+
+       if (!ap)
+               return;
+
+       spin_lock_bh(&ap->sta_table_lock);
+       for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) {
+               struct sta_info *sta = (struct sta_info *) ptr;
+               prism2_check_tx_rates(sta);
+       }
+       spin_unlock_bh(&ap->sta_table_lock);
+}
+
+
+static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
+                               struct ieee80211_crypt_data ***crypt)
+{
+       struct sta_info *sta;
+
+       spin_lock_bh(&ap->sta_table_lock);
+       sta = ap_get_sta(ap, addr);
+       if (sta)
+               atomic_inc(&sta->users);
+       spin_unlock_bh(&ap->sta_table_lock);
+
+       if (!sta && permanent)
+               sta = ap_add_sta(ap, addr);
+
+       if (!sta)
+               return NULL;
+
+       if (permanent)
+               sta->flags |= WLAN_STA_PERM;
+
+       *crypt = &sta->crypt;
+
+       return sta;
+}
+
+
+void hostap_add_wds_links(local_info_t *local)
+{
+       struct ap_data *ap = local->ap;
+       struct list_head *ptr;
+
+       spin_lock_bh(&ap->sta_table_lock);
+       list_for_each(ptr, &ap->sta_list) {
+               struct sta_info *sta = list_entry(ptr, struct sta_info, list);
+               if (sta->ap)
+                       hostap_wds_link_oper(local, sta->addr, WDS_ADD);
+       }
+       spin_unlock_bh(&ap->sta_table_lock);
+
+       schedule_work(&local->ap->wds_oper_queue);
+}
+
+
+void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type)
+{
+       struct wds_oper_data *entry;
+
+       entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+       if (!entry)
+               return;
+       memcpy(entry->addr, addr, ETH_ALEN);
+       entry->type = type;
+       spin_lock_bh(&local->lock);
+       entry->next = local->ap->wds_oper_entries;
+       local->ap->wds_oper_entries = entry;
+       spin_unlock_bh(&local->lock);
+
+       schedule_work(&local->ap->wds_oper_queue);
+}
+
+
+EXPORT_SYMBOL(hostap_init_data);
+EXPORT_SYMBOL(hostap_init_ap_proc);
+EXPORT_SYMBOL(hostap_free_data);
+EXPORT_SYMBOL(hostap_check_sta_fw_version);
+EXPORT_SYMBOL(hostap_handle_sta_tx);
+EXPORT_SYMBOL(hostap_handle_sta_release);
+EXPORT_SYMBOL(hostap_handle_sta_tx_exc);
+EXPORT_SYMBOL(hostap_update_sta_ps);
+EXPORT_SYMBOL(hostap_handle_sta_rx);
+EXPORT_SYMBOL(hostap_is_sta_assoc);
+EXPORT_SYMBOL(hostap_is_sta_authorized);
+EXPORT_SYMBOL(hostap_add_sta);
+EXPORT_SYMBOL(hostap_update_rates);
+EXPORT_SYMBOL(hostap_add_wds_links);
+EXPORT_SYMBOL(hostap_wds_link_oper);
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+EXPORT_SYMBOL(hostap_deauth_all_stas);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
diff --git a/drivers/net/wireless/hostap/hostap_ap.h b/drivers/net/wireless/hostap/hostap_ap.h
new file mode 100644 (file)
index 0000000..816a52b
--- /dev/null
@@ -0,0 +1,261 @@
+#ifndef HOSTAP_AP_H
+#define HOSTAP_AP_H
+
+/* AP data structures for STAs */
+
+/* maximum number of frames to buffer per STA */
+#define STA_MAX_TX_BUFFER 32
+
+/* STA flags */
+#define WLAN_STA_AUTH BIT(0)
+#define WLAN_STA_ASSOC BIT(1)
+#define WLAN_STA_PS BIT(2)
+#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */
+#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */
+#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is
+                                   * controlling whether STA is authorized to
+                                   * send and receive non-IEEE 802.1X frames
+                                   */
+#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
+
+#define WLAN_RATE_1M BIT(0)
+#define WLAN_RATE_2M BIT(1)
+#define WLAN_RATE_5M5 BIT(2)
+#define WLAN_RATE_11M BIT(3)
+#define WLAN_RATE_COUNT 4
+
+/* Maximum size of Supported Rates info element. IEEE 802.11 has a limit of 8,
+ * but some pre-standard IEEE 802.11g products use longer elements. */
+#define WLAN_SUPP_RATES_MAX 32
+
+/* Try to increase TX rate after # successfully sent consecutive packets */
+#define WLAN_RATE_UPDATE_COUNT 50
+
+/* Decrease TX rate after # consecutive dropped packets */
+#define WLAN_RATE_DECREASE_THRESHOLD 2
+
+struct sta_info {
+       struct list_head list;
+       struct sta_info *hnext; /* next entry in hash table list */
+       atomic_t users; /* number of users (do not remove if > 0) */
+       struct proc_dir_entry *proc;
+
+       u8 addr[6];
+       u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
+       u32 flags;
+       u16 capability;
+       u16 listen_interval; /* or beacon_int for APs */
+       u8 supported_rates[WLAN_SUPP_RATES_MAX];
+
+       unsigned long last_auth;
+       unsigned long last_assoc;
+       unsigned long last_rx;
+       unsigned long last_tx;
+       unsigned long rx_packets, tx_packets;
+       unsigned long rx_bytes, tx_bytes;
+       struct sk_buff_head tx_buf;
+       /* FIX: timeout buffers with an expiry time somehow derived from
+        * listen_interval */
+
+       s8 last_rx_silence; /* Noise in dBm */
+       s8 last_rx_signal; /* Signal strength in dBm */
+       u8 last_rx_rate; /* TX rate in 0.1 Mbps */
+       u8 last_rx_updated; /* IWSPY's struct iw_quality::updated */
+
+       u8 tx_supp_rates; /* bit field of supported TX rates */
+       u8 tx_rate; /* current TX rate (in 0.1 Mbps) */
+       u8 tx_rate_idx; /* current TX rate (WLAN_RATE_*) */
+       u8 tx_max_rate; /* max TX rate (WLAN_RATE_*) */
+       u32 tx_count[WLAN_RATE_COUNT]; /* number of frames sent (per rate) */
+       u32 rx_count[WLAN_RATE_COUNT]; /* number of frames received (per rate)
+                                       */
+       u32 tx_since_last_failure;
+       u32 tx_consecutive_exc;
+
+       struct ieee80211_crypt_data *crypt;
+
+       int ap; /* whether this station is an AP */
+
+       local_info_t *local;
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+       union {
+               struct {
+                       char *challenge; /* shared key authentication
+                                         * challenge */
+               } sta;
+               struct {
+                       int ssid_len;
+                       unsigned char ssid[MAX_SSID_LEN + 1]; /* AP's ssid */
+                       int channel;
+                       unsigned long last_beacon; /* last RX beacon time */
+               } ap;
+       } u;
+
+       struct timer_list timer;
+       enum { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH } timeout_next;
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+};
+
+
+#define MAX_STA_COUNT 1024
+
+/* Maximum number of AIDs to use for STAs; must be 2007 or lower
+ * (8802.11 limitation) */
+#define MAX_AID_TABLE_SIZE 128
+
+#define STA_HASH_SIZE 256
+#define STA_HASH(sta) (sta[5])
+
+
+/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY_SEC
+ * has passed since last received frame from the station, a nullfunc data
+ * frame is sent to the station. If this frame is not acknowledged and no other
+ * frames have been received, the station will be disassociated after
+ * AP_DISASSOC_DELAY. Similarily, a the station will be deauthenticated after
+ * AP_DEAUTH_DELAY. AP_TIMEOUT_RESOLUTION is the resolution that is used with
+ * max inactivity timer. */
+#define AP_MAX_INACTIVITY_SEC (5 * 60)
+#define AP_DISASSOC_DELAY (HZ)
+#define AP_DEAUTH_DELAY (HZ)
+
+/* ap_policy: whether to accept frames to/from other APs/IBSS */
+typedef enum {
+       AP_OTHER_AP_SKIP_ALL = 0,
+       AP_OTHER_AP_SAME_SSID = 1,
+       AP_OTHER_AP_ALL = 2,
+       AP_OTHER_AP_EVEN_IBSS = 3
+} ap_policy_enum;
+
+#define PRISM2_AUTH_OPEN BIT(0)
+#define PRISM2_AUTH_SHARED_KEY BIT(1)
+
+
+/* MAC address-based restrictions */
+struct mac_entry {
+       struct list_head list;
+       u8 addr[6];
+};
+
+struct mac_restrictions {
+       enum { MAC_POLICY_OPEN = 0, MAC_POLICY_ALLOW, MAC_POLICY_DENY } policy;
+       unsigned int entries;
+       struct list_head mac_list;
+       spinlock_t lock;
+};
+
+
+struct add_sta_proc_data {
+       u8 addr[ETH_ALEN];
+       struct add_sta_proc_data *next;
+};
+
+
+typedef enum { WDS_ADD, WDS_DEL } wds_oper_type;
+struct wds_oper_data {
+       wds_oper_type type;
+       u8 addr[ETH_ALEN];
+       struct wds_oper_data *next;
+};
+
+
+struct ap_data {
+       int initialized; /* whether ap_data has been initialized */
+       local_info_t *local;
+       int bridge_packets; /* send packet to associated STAs directly to the
+                            * wireless media instead of higher layers in the
+                            * kernel */
+       unsigned int bridged_unicast; /* number of unicast frames bridged on
+                                      * wireless media */
+       unsigned int bridged_multicast; /* number of non-unicast frames
+                                        * bridged on wireless media */
+       unsigned int tx_drop_nonassoc; /* number of unicast TX packets dropped
+                                       * because they were to an address that
+                                       * was not associated */
+       int nullfunc_ack; /* use workaround for nullfunc frame ACKs */
+
+       spinlock_t sta_table_lock;
+       int num_sta; /* number of entries in sta_list */
+       struct list_head sta_list; /* STA info list head */
+       struct sta_info *sta_hash[STA_HASH_SIZE];
+
+       struct proc_dir_entry *proc;
+
+       ap_policy_enum ap_policy;
+       unsigned int max_inactivity;
+       int autom_ap_wds;
+
+       struct mac_restrictions mac_restrictions; /* MAC-based auth */
+       int last_tx_rate;
+
+       struct work_struct add_sta_proc_queue;
+       struct add_sta_proc_data *add_sta_proc_entries;
+
+       struct work_struct wds_oper_queue;
+       struct wds_oper_data *wds_oper_entries;
+
+       u16 tx_callback_idx;
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+       /* pointers to STA info; based on allocated AID or NULL if AID free
+        * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1
+        * and so on
+        */
+       struct sta_info *sta_aid[MAX_AID_TABLE_SIZE];
+
+       u16 tx_callback_auth, tx_callback_assoc, tx_callback_poll;
+
+       /* WEP operations for generating challenges to be used with shared key
+        * authentication */
+       struct ieee80211_crypto_ops *crypt;
+       void *crypt_priv;
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+};
+
+
+void hostap_rx(struct net_device *dev, struct sk_buff *skb,
+              struct hostap_80211_rx_status *rx_stats);
+void hostap_init_data(local_info_t *local);
+void hostap_init_ap_proc(local_info_t *local);
+void hostap_free_data(struct ap_data *ap);
+void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver);
+
+typedef enum {
+       AP_TX_CONTINUE, AP_TX_DROP, AP_TX_RETRY, AP_TX_BUFFERED,
+       AP_TX_CONTINUE_NOT_AUTHORIZED
+} ap_tx_ret;
+struct hostap_tx_data {
+       struct sk_buff *skb;
+       int host_encrypt;
+       struct ieee80211_crypt_data *crypt;
+       void *sta_ptr;
+};
+ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx);
+void hostap_handle_sta_release(void *ptr);
+void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb);
+int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr);
+typedef enum {
+       AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED
+} ap_rx_ret;
+ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
+                              struct sk_buff *skb,
+                              struct hostap_80211_rx_status *rx_stats,
+                              int wds);
+int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr *hdr,
+                            struct ieee80211_crypt_data **crypt,
+                            void **sta_ptr);
+int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr);
+int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr);
+int hostap_add_sta(struct ap_data *ap, u8 *sta_addr);
+int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr *hdr,
+                          struct hostap_80211_rx_status *rx_stats);
+void hostap_update_rates(local_info_t *local);
+void hostap_add_wds_links(local_info_t *local);
+void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type);
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap,
+                           int resend);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+#endif /* HOSTAP_AP_H */
diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h
new file mode 100644 (file)
index 0000000..6f4fa9d
--- /dev/null
@@ -0,0 +1,435 @@
+#ifndef HOSTAP_COMMON_H
+#define HOSTAP_COMMON_H
+
+#define BIT(x) (1 << (x))
+
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+
+
+/* IEEE 802.11 defines */
+
+/* Information Element IDs */
+#define WLAN_EID_SSID 0
+#define WLAN_EID_SUPP_RATES 1
+#define WLAN_EID_FH_PARAMS 2
+#define WLAN_EID_DS_PARAMS 3
+#define WLAN_EID_CF_PARAMS 4
+#define WLAN_EID_TIM 5
+#define WLAN_EID_IBSS_PARAMS 6
+#define WLAN_EID_CHALLENGE 16
+#define WLAN_EID_RSN 48
+#define WLAN_EID_GENERIC 221
+
+
+/* HFA384X Configuration RIDs */
+#define HFA384X_RID_CNFPORTTYPE 0xFC00
+#define HFA384X_RID_CNFOWNMACADDR 0xFC01
+#define HFA384X_RID_CNFDESIREDSSID 0xFC02
+#define HFA384X_RID_CNFOWNCHANNEL 0xFC03
+#define HFA384X_RID_CNFOWNSSID 0xFC04
+#define HFA384X_RID_CNFOWNATIMWINDOW 0xFC05
+#define HFA384X_RID_CNFSYSTEMSCALE 0xFC06
+#define HFA384X_RID_CNFMAXDATALEN 0xFC07
+#define HFA384X_RID_CNFWDSADDRESS 0xFC08
+#define HFA384X_RID_CNFPMENABLED 0xFC09
+#define HFA384X_RID_CNFPMEPS 0xFC0A
+#define HFA384X_RID_CNFMULTICASTRECEIVE 0xFC0B
+#define HFA384X_RID_CNFMAXSLEEPDURATION 0xFC0C
+#define HFA384X_RID_CNFPMHOLDOVERDURATION 0xFC0D
+#define HFA384X_RID_CNFOWNNAME 0xFC0E
+#define HFA384X_RID_CNFOWNDTIMPERIOD 0xFC10
+#define HFA384X_RID_CNFWDSADDRESS1 0xFC11 /* AP f/w only */
+#define HFA384X_RID_CNFWDSADDRESS2 0xFC12 /* AP f/w only */
+#define HFA384X_RID_CNFWDSADDRESS3 0xFC13 /* AP f/w only */
+#define HFA384X_RID_CNFWDSADDRESS4 0xFC14 /* AP f/w only */
+#define HFA384X_RID_CNFWDSADDRESS5 0xFC15 /* AP f/w only */
+#define HFA384X_RID_CNFWDSADDRESS6 0xFC16 /* AP f/w only */
+#define HFA384X_RID_CNFMULTICASTPMBUFFERING 0xFC17 /* AP f/w only */
+#define HFA384X_RID_UNKNOWN1 0xFC20
+#define HFA384X_RID_UNKNOWN2 0xFC21
+#define HFA384X_RID_CNFWEPDEFAULTKEYID 0xFC23
+#define HFA384X_RID_CNFDEFAULTKEY0 0xFC24
+#define HFA384X_RID_CNFDEFAULTKEY1 0xFC25
+#define HFA384X_RID_CNFDEFAULTKEY2 0xFC26
+#define HFA384X_RID_CNFDEFAULTKEY3 0xFC27
+#define HFA384X_RID_CNFWEPFLAGS 0xFC28
+#define HFA384X_RID_CNFWEPKEYMAPPINGTABLE 0xFC29
+#define HFA384X_RID_CNFAUTHENTICATION 0xFC2A
+#define HFA384X_RID_CNFMAXASSOCSTA 0xFC2B /* AP f/w only */
+#define HFA384X_RID_CNFTXCONTROL 0xFC2C
+#define HFA384X_RID_CNFROAMINGMODE 0xFC2D
+#define HFA384X_RID_CNFHOSTAUTHENTICATION 0xFC2E /* AP f/w only */
+#define HFA384X_RID_CNFRCVCRCERROR 0xFC30
+#define HFA384X_RID_CNFMMLIFE 0xFC31
+#define HFA384X_RID_CNFALTRETRYCOUNT 0xFC32
+#define HFA384X_RID_CNFBEACONINT 0xFC33
+#define HFA384X_RID_CNFAPPCFINFO 0xFC34 /* AP f/w only */
+#define HFA384X_RID_CNFSTAPCFINFO 0xFC35
+#define HFA384X_RID_CNFPRIORITYQUSAGE 0xFC37
+#define HFA384X_RID_CNFTIMCTRL 0xFC40
+#define HFA384X_RID_UNKNOWN3 0xFC41 /* added in STA f/w 0.7.x */
+#define HFA384X_RID_CNFTHIRTY2TALLY 0xFC42 /* added in STA f/w 0.8.0 */
+#define HFA384X_RID_CNFENHSECURITY 0xFC43 /* AP f/w or STA f/w >= 1.6.3 */
+#define HFA384X_RID_CNFDBMADJUST 0xFC46 /* added in STA f/w 1.3.1 */
+#define HFA384X_RID_GENERICELEMENT 0xFC48 /* added in STA f/w 1.7.0;
+                                          * write only */
+#define HFA384X_RID_PROPAGATIONDELAY 0xFC49 /* added in STA f/w 1.7.6 */
+#define HFA384X_RID_GROUPADDRESSES 0xFC80
+#define HFA384X_RID_CREATEIBSS 0xFC81
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD 0xFC82
+#define HFA384X_RID_RTSTHRESHOLD 0xFC83
+#define HFA384X_RID_TXRATECONTROL 0xFC84
+#define HFA384X_RID_PROMISCUOUSMODE 0xFC85
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD0 0xFC90 /* AP f/w only */
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD1 0xFC91 /* AP f/w only */
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD2 0xFC92 /* AP f/w only */
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD3 0xFC93 /* AP f/w only */
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD4 0xFC94 /* AP f/w only */
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD5 0xFC95 /* AP f/w only */
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD6 0xFC96 /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD0 0xFC97 /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD1 0xFC98 /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD2 0xFC99 /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD3 0xFC9A /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD4 0xFC9B /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD5 0xFC9C /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD6 0xFC9D /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL0 0xFC9E /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL1 0xFC9F /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL2 0xFCA0 /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL3 0xFCA1 /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL4 0xFCA2 /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL5 0xFCA3 /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL6 0xFCA4 /* AP f/w only */
+#define HFA384X_RID_CNFSHORTPREAMBLE 0xFCB0
+#define HFA384X_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1
+#define HFA384X_RID_CNFAUTHENTICATIONRSPTO 0xFCB2
+#define HFA384X_RID_CNFBASICRATES 0xFCB3
+#define HFA384X_RID_CNFSUPPORTEDRATES 0xFCB4
+#define HFA384X_RID_CNFFALLBACKCTRL 0xFCB5 /* added in STA f/w 1.3.1 */
+#define HFA384X_RID_WEPKEYDISABLE 0xFCB6 /* added in STA f/w 1.3.1 */
+#define HFA384X_RID_WEPKEYMAPINDEX 0xFCB7 /* ? */
+#define HFA384X_RID_BROADCASTKEYID 0xFCB8 /* ? */
+#define HFA384X_RID_ENTSECFLAGEYID 0xFCB9 /* ? */
+#define HFA384X_RID_CNFPASSIVESCANCTRL 0xFCBA /* added in STA f/w 1.5.0 */
+#define HFA384X_RID_SSNHANDLINGMODE 0xFCBB /* added in STA f/w 1.7.0 */
+#define HFA384X_RID_MDCCONTROL 0xFCBC /* added in STA f/w 1.7.0 */
+#define HFA384X_RID_MDCCOUNTRY 0xFCBD /* added in STA f/w 1.7.0 */
+#define HFA384X_RID_TXPOWERMAX 0xFCBE /* added in STA f/w 1.7.0 */
+#define HFA384X_RID_CNFLFOENABLED 0xFCBF /* added in STA f/w 1.6.3 */
+#define HFA384X_RID_CAPINFO 0xFCC0 /* added in STA f/w 1.7.0 */
+#define HFA384X_RID_LISTENINTERVAL 0xFCC1 /* added in STA f/w 1.7.0 */
+#define HFA384X_RID_SW_ANT_DIV 0xFCC2 /* added in STA f/w 1.7.0; Prism3 */
+#define HFA384X_RID_LED_CTRL 0xFCC4 /* added in STA f/w 1.7.6 */
+#define HFA384X_RID_HFODELAY 0xFCC5 /* added in STA f/w 1.7.6 */
+#define HFA384X_RID_DISALLOWEDBSSID 0xFCC6 /* added in STA f/w 1.8.0 */
+#define HFA384X_RID_TICKTIME 0xFCE0
+#define HFA384X_RID_SCANREQUEST 0xFCE1
+#define HFA384X_RID_JOINREQUEST 0xFCE2
+#define HFA384X_RID_AUTHENTICATESTATION 0xFCE3 /* AP f/w only */
+#define HFA384X_RID_CHANNELINFOREQUEST 0xFCE4 /* AP f/w only */
+#define HFA384X_RID_HOSTSCAN 0xFCE5 /* added in STA f/w 1.3.1 */
+
+/* HFA384X Information RIDs */
+#define HFA384X_RID_MAXLOADTIME 0xFD00
+#define HFA384X_RID_DOWNLOADBUFFER 0xFD01
+#define HFA384X_RID_PRIID 0xFD02
+#define HFA384X_RID_PRISUPRANGE 0xFD03
+#define HFA384X_RID_CFIACTRANGES 0xFD04
+#define HFA384X_RID_NICSERNUM 0xFD0A
+#define HFA384X_RID_NICID 0xFD0B
+#define HFA384X_RID_MFISUPRANGE 0xFD0C
+#define HFA384X_RID_CFISUPRANGE 0xFD0D
+#define HFA384X_RID_CHANNELLIST 0xFD10
+#define HFA384X_RID_REGULATORYDOMAINS 0xFD11
+#define HFA384X_RID_TEMPTYPE 0xFD12
+#define HFA384X_RID_CIS 0xFD13
+#define HFA384X_RID_STAID 0xFD20
+#define HFA384X_RID_STASUPRANGE 0xFD21
+#define HFA384X_RID_MFIACTRANGES 0xFD22
+#define HFA384X_RID_CFIACTRANGES2 0xFD23
+#define HFA384X_RID_PRODUCTNAME 0xFD24 /* added in STA f/w 1.3.1;
+                                       * only Prism2.5(?) */
+#define HFA384X_RID_PORTSTATUS 0xFD40
+#define HFA384X_RID_CURRENTSSID 0xFD41
+#define HFA384X_RID_CURRENTBSSID 0xFD42
+#define HFA384X_RID_COMMSQUALITY 0xFD43
+#define HFA384X_RID_CURRENTTXRATE 0xFD44
+#define HFA384X_RID_CURRENTBEACONINTERVAL 0xFD45
+#define HFA384X_RID_CURRENTSCALETHRESHOLDS 0xFD46
+#define HFA384X_RID_PROTOCOLRSPTIME 0xFD47
+#define HFA384X_RID_SHORTRETRYLIMIT 0xFD48
+#define HFA384X_RID_LONGRETRYLIMIT 0xFD49
+#define HFA384X_RID_MAXTRANSMITLIFETIME 0xFD4A
+#define HFA384X_RID_MAXRECEIVELIFETIME 0xFD4B
+#define HFA384X_RID_CFPOLLABLE 0xFD4C
+#define HFA384X_RID_AUTHENTICATIONALGORITHMS 0xFD4D
+#define HFA384X_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F
+#define HFA384X_RID_DBMCOMMSQUALITY 0xFD51 /* added in STA f/w 1.3.1 */
+#define HFA384X_RID_CURRENTTXRATE1 0xFD80 /* AP f/w only */
+#define HFA384X_RID_CURRENTTXRATE2 0xFD81 /* AP f/w only */
+#define HFA384X_RID_CURRENTTXRATE3 0xFD82 /* AP f/w only */
+#define HFA384X_RID_CURRENTTXRATE4 0xFD83 /* AP f/w only */
+#define HFA384X_RID_CURRENTTXRATE5 0xFD84 /* AP f/w only */
+#define HFA384X_RID_CURRENTTXRATE6 0xFD85 /* AP f/w only */
+#define HFA384X_RID_OWNMACADDR 0xFD86 /* AP f/w only */
+#define HFA384X_RID_SCANRESULTSTABLE 0xFD88 /* added in STA f/w 0.8.3 */
+#define HFA384X_RID_HOSTSCANRESULTS 0xFD89 /* added in STA f/w 1.3.1 */
+#define HFA384X_RID_AUTHENTICATIONUSED 0xFD8A /* added in STA f/w 1.3.4 */
+#define HFA384X_RID_CNFFAASWITCHCTRL 0xFD8B /* added in STA f/w 1.6.3 */
+#define HFA384X_RID_ASSOCIATIONFAILURE 0xFD8D /* added in STA f/w 1.8.0 */
+#define HFA384X_RID_PHYTYPE 0xFDC0
+#define HFA384X_RID_CURRENTCHANNEL 0xFDC1
+#define HFA384X_RID_CURRENTPOWERSTATE 0xFDC2
+#define HFA384X_RID_CCAMODE 0xFDC3
+#define HFA384X_RID_SUPPORTEDDATARATES 0xFDC6
+#define HFA384X_RID_LFO_VOLT_REG_TEST_RES 0xFDC7 /* added in STA f/w 1.7.1 */
+#define HFA384X_RID_BUILDSEQ 0xFFFE
+#define HFA384X_RID_FWID 0xFFFF
+
+
+struct hfa384x_comp_ident
+{
+       u16 id;
+       u16 variant;
+       u16 major;
+       u16 minor;
+} __attribute__ ((packed));
+
+#define HFA384X_COMP_ID_PRI 0x15
+#define HFA384X_COMP_ID_STA 0x1f
+#define HFA384X_COMP_ID_FW_AP 0x14b
+
+struct hfa384x_sup_range
+{
+       u16 role;
+       u16 id;
+       u16 variant;
+       u16 bottom;
+       u16 top;
+} __attribute__ ((packed));
+
+
+struct hfa384x_build_id
+{
+       u16 pri_seq;
+       u16 sec_seq;
+} __attribute__ ((packed));
+
+/* FD01 - Download Buffer */
+struct hfa384x_rid_download_buffer
+{
+       u16 page;
+       u16 offset;
+       u16 length;
+} __attribute__ ((packed));
+
+/* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */
+struct hfa384x_comms_quality {
+       u16 comm_qual; /* 0 .. 92 */
+       u16 signal_level; /* 27 .. 154 */
+       u16 noise_level; /* 27 .. 154 */
+} __attribute__ ((packed));
+
+
+/* netdevice private ioctls (used, e.g., with iwpriv from user space) */
+
+/* New wireless extensions API - SET/GET convention (even ioctl numbers are
+ * root only)
+ */
+#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
+#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
+#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2)
+#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3)
+#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4)
+#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
+#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8)
+#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10)
+#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12)
+#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14)
+#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16)
+#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18)
+#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20)
+#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22)
+
+/* following are not in SIOCGIWPRIV list; check permission in the driver code
+ */
+#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13)
+#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14)
+
+
+/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */
+enum {
+       /* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */
+       PRISM2_PARAM_TXRATECTRL = 2,
+       PRISM2_PARAM_BEACON_INT = 3,
+       PRISM2_PARAM_PSEUDO_IBSS = 4,
+       PRISM2_PARAM_ALC = 5,
+       /* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */
+       PRISM2_PARAM_DUMP = 7,
+       PRISM2_PARAM_OTHER_AP_POLICY = 8,
+       PRISM2_PARAM_AP_MAX_INACTIVITY = 9,
+       PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
+       PRISM2_PARAM_DTIM_PERIOD = 11,
+       PRISM2_PARAM_AP_NULLFUNC_ACK = 12,
+       PRISM2_PARAM_MAX_WDS = 13,
+       PRISM2_PARAM_AP_AUTOM_AP_WDS = 14,
+       PRISM2_PARAM_AP_AUTH_ALGS = 15,
+       PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16,
+       PRISM2_PARAM_HOST_ENCRYPT = 17,
+       PRISM2_PARAM_HOST_DECRYPT = 18,
+       /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19, REMOVED 2005-08-14 */
+       /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20, REMOVED 2005-08-14 */
+       PRISM2_PARAM_HOST_ROAMING = 21,
+       PRISM2_PARAM_BCRX_STA_KEY = 22,
+       PRISM2_PARAM_IEEE_802_1X = 23,
+       PRISM2_PARAM_ANTSEL_TX = 24,
+       PRISM2_PARAM_ANTSEL_RX = 25,
+       PRISM2_PARAM_MONITOR_TYPE = 26,
+       PRISM2_PARAM_WDS_TYPE = 27,
+       PRISM2_PARAM_HOSTSCAN = 28,
+       PRISM2_PARAM_AP_SCAN = 29,
+       PRISM2_PARAM_ENH_SEC = 30,
+       PRISM2_PARAM_IO_DEBUG = 31,
+       PRISM2_PARAM_BASIC_RATES = 32,
+       PRISM2_PARAM_OPER_RATES = 33,
+       PRISM2_PARAM_HOSTAPD = 34,
+       PRISM2_PARAM_HOSTAPD_STA = 35,
+       PRISM2_PARAM_WPA = 36,
+       PRISM2_PARAM_PRIVACY_INVOKED = 37,
+       PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
+       PRISM2_PARAM_DROP_UNENCRYPTED = 39,
+       PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
+};
+
+enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1,
+       HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 };
+
+
+/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */
+enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1,
+       AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3,
+       AP_MAC_CMD_KICKALL = 4 };
+
+
+/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */
+enum {
+       PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */,
+       /* Note! Old versions of prism2_srec have a fatal error in CRC-16
+        * calculation, which will corrupt all non-volatile downloads.
+        * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to
+        * prevent use of old versions of prism2_srec for non-volatile
+        * download. */
+       PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */,
+       PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */,
+       /* Persistent versions of volatile download commands (keep firmware
+        * data in memory and automatically re-download after hw_reset */
+       PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5,
+       PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6,
+};
+
+struct prism2_download_param {
+       u32 dl_cmd;
+       u32 start_addr;
+       u32 num_areas;
+       struct prism2_download_area {
+               u32 addr; /* wlan card address */
+               u32 len;
+               void __user *ptr; /* pointer to data in user space */
+       } data[0];
+};
+
+#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072
+#define PRISM2_MAX_DOWNLOAD_LEN 262144
+
+
+/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */
+enum {
+       PRISM2_HOSTAPD_FLUSH = 1,
+       PRISM2_HOSTAPD_ADD_STA = 2,
+       PRISM2_HOSTAPD_REMOVE_STA = 3,
+       PRISM2_HOSTAPD_GET_INFO_STA = 4,
+       /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
+       PRISM2_SET_ENCRYPTION = 6,
+       PRISM2_GET_ENCRYPTION = 7,
+       PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
+       PRISM2_HOSTAPD_GET_RID = 9,
+       PRISM2_HOSTAPD_SET_RID = 10,
+       PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
+       PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
+       PRISM2_HOSTAPD_MLME = 13,
+       PRISM2_HOSTAPD_SCAN_REQ = 14,
+       PRISM2_HOSTAPD_STA_CLEAR_STATS = 15,
+};
+
+#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
+#define PRISM2_HOSTAPD_RID_HDR_LEN \
+((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
+#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
+((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+
+/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
+ */
+#define HOSTAP_CRYPT_ALG_NAME_LEN 16
+
+
+struct prism2_hostapd_param {
+       u32 cmd;
+       u8 sta_addr[ETH_ALEN];
+       union {
+               struct {
+                       u16 aid;
+                       u16 capability;
+                       u8 tx_supp_rates;
+               } add_sta;
+               struct {
+                       u32 inactive_sec;
+               } get_info_sta;
+               struct {
+                       u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
+                       u32 flags;
+                       u32 err;
+                       u8 idx;
+                       u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+                       u16 key_len;
+                       u8 key[0];
+               } crypt;
+               struct {
+                       u32 flags_and;
+                       u32 flags_or;
+               } set_flags_sta;
+               struct {
+                       u16 rid;
+                       u16 len;
+                       u8 data[0];
+               } rid;
+               struct {
+                       u8 len;
+                       u8 data[0];
+               } generic_elem;
+               struct {
+#define MLME_STA_DEAUTH 0
+#define MLME_STA_DISASSOC 1
+                       u16 cmd;
+                       u16 reason_code;
+               } mlme;
+               struct {
+                       u8 ssid_len;
+                       u8 ssid[32];
+               } scan_req;
+       } u;
+};
+
+#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0)
+#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1)
+
+#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2
+#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3
+#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4
+#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5
+#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6
+#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7
+
+
+#endif /* HOSTAP_COMMON_H */
diff --git a/drivers/net/wireless/hostap/hostap_config.h b/drivers/net/wireless/hostap/hostap_config.h
new file mode 100644 (file)
index 0000000..7ed3425
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef HOSTAP_CONFIG_H
+#define HOSTAP_CONFIG_H
+
+#define PRISM2_VERSION "0.4.4-kernel"
+
+/* In the previous versions of Host AP driver, support for user space version
+ * of IEEE 802.11 management (hostapd) used to be disabled in the default
+ * configuration. From now on, support for hostapd is always included and it is
+ * possible to disable kernel driver version of IEEE 802.11 management with a
+ * separate define, PRISM2_NO_KERNEL_IEEE80211_MGMT. */
+/* #define PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+/* Maximum number of events handler per one interrupt */
+#define PRISM2_MAX_INTERRUPT_EVENTS 20
+
+/* Include code for downloading firmware images into volatile RAM. */
+#define PRISM2_DOWNLOAD_SUPPORT
+
+/* Allow kernel configuration to enable download support. */
+#if !defined(PRISM2_DOWNLOAD_SUPPORT) && defined(CONFIG_HOSTAP_FIRMWARE)
+#define PRISM2_DOWNLOAD_SUPPORT
+#endif
+
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+/* Allow writing firmware images into flash, i.e., to non-volatile storage.
+ * Before you enable this option, you should make absolutely sure that you are
+ * using prism2_srec utility that comes with THIS version of the driver!
+ * In addition, please note that it is possible to kill your card with
+ * non-volatile download if you are using incorrect image. This feature has not
+ * been fully tested, so please be careful with it. */
+/* #define PRISM2_NON_VOLATILE_DOWNLOAD */
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+
+/* Save low-level I/O for debugging. This should not be enabled in normal use.
+ */
+/* #define PRISM2_IO_DEBUG */
+
+/* Following defines can be used to remove unneeded parts of the driver, e.g.,
+ * to limit the size of the kernel module. Definitions can be added here in
+ * hostap_config.h or they can be added to make command with EXTRA_CFLAGS,
+ * e.g.,
+ * 'make pccard EXTRA_CFLAGS="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"'
+ */
+
+/* Do not include debug messages into the driver */
+/* #define PRISM2_NO_DEBUG */
+
+/* Do not include /proc/net/prism2/wlan#/{registers,debug} */
+/* #define PRISM2_NO_PROCFS_DEBUG */
+
+/* Do not include station functionality (i.e., allow only Master (Host AP) mode
+ */
+/* #define PRISM2_NO_STATION_MODES */
+
+#endif /* HOSTAP_CONFIG_H */
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
new file mode 100644 (file)
index 0000000..faa83ba
--- /dev/null
@@ -0,0 +1,1030 @@
+#define PRISM2_PCCARD
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/if.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/workqueue.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+
+#include <asm/io.h>
+
+#include "hostap_wlan.h"
+
+
+static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static dev_info_t dev_info = "hostap_cs";
+static dev_link_t *dev_list = NULL;
+
+MODULE_AUTHOR("Jouni Malinen");
+MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
+                  "cards (PC Card).");
+MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PC Card)");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(PRISM2_VERSION);
+
+
+static int ignore_cis_vcc;
+module_param(ignore_cis_vcc, int, 0444);
+MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry");
+
+
+/* struct local_info::hw_priv */
+struct hostap_cs_priv {
+       dev_node_t node;
+       dev_link_t *link;
+       int sandisk_connectplus;
+};
+
+
+#ifdef PRISM2_IO_DEBUG
+
+static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       unsigned long flags;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+       spin_lock_irqsave(&local->lock, flags);
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
+       outb(v, dev->base_addr + a);
+       spin_unlock_irqrestore(&local->lock, flags);
+}
+
+static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       unsigned long flags;
+       u8 v;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+       spin_lock_irqsave(&local->lock, flags);
+       v = inb(dev->base_addr + a);
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
+       spin_unlock_irqrestore(&local->lock, flags);
+       return v;
+}
+
+static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       unsigned long flags;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+       spin_lock_irqsave(&local->lock, flags);
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
+       outw(v, dev->base_addr + a);
+       spin_unlock_irqrestore(&local->lock, flags);
+}
+
+static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       unsigned long flags;
+       u16 v;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+       spin_lock_irqsave(&local->lock, flags);
+       v = inw(dev->base_addr + a);
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
+       spin_unlock_irqrestore(&local->lock, flags);
+       return v;
+}
+
+static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
+                                      u8 *buf, int wc)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       unsigned long flags;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+       spin_lock_irqsave(&local->lock, flags);
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
+       outsw(dev->base_addr + a, buf, wc);
+       spin_unlock_irqrestore(&local->lock, flags);
+}
+
+static inline void hfa384x_insw_debug(struct net_device *dev, int a,
+                                     u8 *buf, int wc)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       unsigned long flags;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+       spin_lock_irqsave(&local->lock, flags);
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
+       insw(dev->base_addr + a, buf, wc);
+       spin_unlock_irqrestore(&local->lock, flags);
+}
+
+#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
+#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
+#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
+#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
+#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
+#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
+
+#else /* PRISM2_IO_DEBUG */
+
+#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
+#define HFA384X_INB(a) inb(dev->base_addr + (a))
+#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
+#define HFA384X_INW(a) inw(dev->base_addr + (a))
+#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
+#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
+
+#endif /* PRISM2_IO_DEBUG */
+
+
+static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
+                           int len)
+{
+       u16 d_off;
+       u16 *pos;
+
+       d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
+       pos = (u16 *) buf;
+
+       if (len / 2)
+               HFA384X_INSW(d_off, buf, len / 2);
+       pos += len / 2;
+
+       if (len & 1)
+               *((char *) pos) = HFA384X_INB(d_off);
+
+       return 0;
+}
+
+
+static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
+{
+       u16 d_off;
+       u16 *pos;
+
+       d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
+       pos = (u16 *) buf;
+
+       if (len / 2)
+               HFA384X_OUTSW(d_off, buf, len / 2);
+       pos += len / 2;
+
+       if (len & 1)
+               HFA384X_OUTB(*((char *) pos), d_off);
+
+       return 0;
+}
+
+
+/* FIX: This might change at some point.. */
+#include "hostap_hw.c"
+
+
+
+static void prism2_detach(dev_link_t *link);
+static void prism2_release(u_long arg);
+static int prism2_event(event_t event, int priority,
+                       event_callback_args_t *args);
+
+
+static int prism2_pccard_card_present(local_info_t *local)
+{
+       struct hostap_cs_priv *hw_priv = local->hw_priv;
+       if (hw_priv != NULL && hw_priv->link != NULL &&
+           ((hw_priv->link->state & (DEV_PRESENT | DEV_CONFIG)) ==
+            (DEV_PRESENT | DEV_CONFIG)))
+               return 1;
+       return 0;
+}
+
+
+/*
+ * SanDisk CompactFlash WLAN Flashcard - Product Manual v1.0
+ * Document No. 20-10-00058, January 2004
+ * http://www.sandisk.com/pdf/industrial/ProdManualCFWLANv1.0.pdf
+ */
+#define SANDISK_WLAN_ACTIVATION_OFF 0x40
+#define SANDISK_HCR_OFF 0x42
+
+
+static void sandisk_set_iobase(local_info_t *local)
+{
+       int res;
+       conf_reg_t reg;
+       struct hostap_cs_priv *hw_priv = local->hw_priv;
+
+       reg.Function = 0;
+       reg.Action = CS_WRITE;
+       reg.Offset = 0x10; /* 0x3f0 IO base 1 */
+       reg.Value = hw_priv->link->io.BasePort1 & 0x00ff;
+       res = pcmcia_access_configuration_register(hw_priv->link->handle,
+                                                  &reg);
+       if (res != CS_SUCCESS) {
+               printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -"
+                      " res=%d\n", res);
+       }
+       udelay(10);
+
+       reg.Function = 0;
+       reg.Action = CS_WRITE;
+       reg.Offset = 0x12; /* 0x3f2 IO base 2 */
+       reg.Value = (hw_priv->link->io.BasePort1 & 0xff00) >> 8;
+       res = pcmcia_access_configuration_register(hw_priv->link->handle,
+                                                  &reg);
+       if (res != CS_SUCCESS) {
+               printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -"
+                      " res=%d\n", res);
+       }
+}
+
+
+static void sandisk_write_hcr(local_info_t *local, int hcr)
+{
+       struct net_device *dev = local->dev;
+       int i;
+
+       HFA384X_OUTB(0x80, SANDISK_WLAN_ACTIVATION_OFF);
+       udelay(50);
+       for (i = 0; i < 10; i++) {
+               HFA384X_OUTB(hcr, SANDISK_HCR_OFF);
+       }
+       udelay(55);
+       HFA384X_OUTB(0x45, SANDISK_WLAN_ACTIVATION_OFF);
+}
+
+
+static int sandisk_enable_wireless(struct net_device *dev)
+{
+       int res, ret = 0;
+       conf_reg_t reg;
+       struct hostap_interface *iface = dev->priv;
+       local_info_t *local = iface->local;
+       tuple_t tuple;
+       cisparse_t *parse = NULL;
+       u_char buf[64];
+       struct hostap_cs_priv *hw_priv = local->hw_priv;
+
+       if (hw_priv->link->io.NumPorts1 < 0x42) {
+               /* Not enough ports to be SanDisk multi-function card */
+               ret = -ENODEV;
+               goto done;
+       }
+
+       parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL);
+       if (parse == NULL) {
+               ret = -ENOMEM;
+               goto done;
+       }
+
+       tuple.DesiredTuple = CISTPL_MANFID;
+       tuple.Attributes = TUPLE_RETURN_COMMON;
+       tuple.TupleData = buf;
+       tuple.TupleDataMax = sizeof(buf);
+       tuple.TupleOffset = 0;
+       if (pcmcia_get_first_tuple(hw_priv->link->handle, &tuple) ||
+           pcmcia_get_tuple_data(hw_priv->link->handle, &tuple) ||
+           pcmcia_parse_tuple(hw_priv->link->handle, &tuple, parse) ||
+           parse->manfid.manf != 0xd601 || parse->manfid.card != 0x0101) {
+               /* No SanDisk manfid found */
+               ret = -ENODEV;
+               goto done;
+       }
+
+       tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
+       if (pcmcia_get_first_tuple(hw_priv->link->handle, &tuple) ||
+           pcmcia_get_tuple_data(hw_priv->link->handle, &tuple) ||
+           pcmcia_parse_tuple(hw_priv->link->handle, &tuple, parse) ||
+               parse->longlink_mfc.nfn < 2) {
+               /* No multi-function links found */
+               ret = -ENODEV;
+               goto done;
+       }
+
+       printk(KERN_DEBUG "%s: Multi-function SanDisk ConnectPlus detected"
+              " - using vendor-specific initialization\n", dev->name);
+       hw_priv->sandisk_connectplus = 1;
+
+       reg.Function = 0;
+       reg.Action = CS_WRITE;
+       reg.Offset = CISREG_COR;
+       reg.Value = COR_SOFT_RESET;
+       res = pcmcia_access_configuration_register(hw_priv->link->handle,
+                                                  &reg);
+       if (res != CS_SUCCESS) {
+               printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
+                      dev->name, res);
+               goto done;
+       }
+       mdelay(5);
+
+       reg.Function = 0;
+       reg.Action = CS_WRITE;
+       reg.Offset = CISREG_COR;
+       /*
+        * Do not enable interrupts here to avoid some bogus events. Interrupts
+        * will be enabled during the first cor_sreset call.
+        */
+       reg.Value = COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE | COR_FUNC_ENA;
+       res = pcmcia_access_configuration_register(hw_priv->link->handle,
+                                                  &reg);
+       if (res != CS_SUCCESS) {
+               printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
+                      dev->name, res);
+               goto done;
+       }
+       mdelay(5);
+
+       sandisk_set_iobase(local);
+
+       HFA384X_OUTB(0xc5, SANDISK_WLAN_ACTIVATION_OFF);
+       udelay(10);
+       HFA384X_OUTB(0x4b, SANDISK_WLAN_ACTIVATION_OFF);
+       udelay(10);
+
+done:
+       kfree(parse);
+       return ret;
+}
+
+
+static void prism2_pccard_cor_sreset(local_info_t *local)
+{
+       int res;
+       conf_reg_t reg;
+       struct hostap_cs_priv *hw_priv = local->hw_priv;
+
+       if (!prism2_pccard_card_present(local))
+              return;
+
+       reg.Function = 0;
+       reg.Action = CS_READ;
+       reg.Offset = CISREG_COR;
+       reg.Value = 0;
+       res = pcmcia_access_configuration_register(hw_priv->link->handle,
+                                                  &reg);
+       if (res != CS_SUCCESS) {
+               printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n",
+                      res);
+               return;
+       }
+       printk(KERN_DEBUG "prism2_pccard_cor_sreset: original COR %02x\n",
+              reg.Value);
+
+       reg.Action = CS_WRITE;
+       reg.Value |= COR_SOFT_RESET;
+       res = pcmcia_access_configuration_register(hw_priv->link->handle,
+                                                  &reg);
+       if (res != CS_SUCCESS) {
+               printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n",
+                      res);
+               return;
+       }
+
+       mdelay(hw_priv->sandisk_connectplus ? 5 : 2);
+
+       reg.Value &= ~COR_SOFT_RESET;
+       if (hw_priv->sandisk_connectplus)
+               reg.Value |= COR_IREQ_ENA;
+       res = pcmcia_access_configuration_register(hw_priv->link->handle,
+                                                  &reg);
+       if (res != CS_SUCCESS) {
+               printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n",
+                      res);
+               return;
+       }
+
+       mdelay(hw_priv->sandisk_connectplus ? 5 : 2);
+
+       if (hw_priv->sandisk_connectplus)
+               sandisk_set_iobase(local);
+}
+
+
+static void prism2_pccard_genesis_reset(local_info_t *local, int hcr)
+{
+       int res;
+       conf_reg_t reg;
+       int old_cor;
+       struct hostap_cs_priv *hw_priv = local->hw_priv;
+
+       if (!prism2_pccard_card_present(local))
+              return;
+
+       if (hw_priv->sandisk_connectplus) {
+               sandisk_write_hcr(local, hcr);
+               return;
+       }
+
+       reg.Function = 0;
+       reg.Action = CS_READ;
+       reg.Offset = CISREG_COR;
+       reg.Value = 0;
+       res = pcmcia_access_configuration_register(hw_priv->link->handle,
+                                                  &reg);
+       if (res != CS_SUCCESS) {
+               printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 1 "
+                      "(%d)\n", res);
+               return;
+       }
+       printk(KERN_DEBUG "prism2_pccard_genesis_sreset: original COR %02x\n",
+              reg.Value);
+       old_cor = reg.Value;
+
+       reg.Action = CS_WRITE;
+       reg.Value |= COR_SOFT_RESET;
+       res = pcmcia_access_configuration_register(hw_priv->link->handle,
+                                                  &reg);
+       if (res != CS_SUCCESS) {
+               printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 2 "
+                      "(%d)\n", res);
+               return;
+       }
+
+       mdelay(10);
+
+       /* Setup Genesis mode */
+       reg.Action = CS_WRITE;
+       reg.Value = hcr;
+       reg.Offset = CISREG_CCSR;
+       res = pcmcia_access_configuration_register(hw_priv->link->handle,
+                                                  &reg);
+       if (res != CS_SUCCESS) {
+               printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 3 "
+                      "(%d)\n", res);
+               return;
+       }
+       mdelay(10);
+
+       reg.Action = CS_WRITE;
+       reg.Offset = CISREG_COR;
+       reg.Value = old_cor & ~COR_SOFT_RESET;
+       res = pcmcia_access_configuration_register(hw_priv->link->handle,
+                                                  &reg);
+       if (res != CS_SUCCESS) {
+               printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 4 "
+                      "(%d)\n", res);
+               return;
+       }
+
+       mdelay(10);
+}
+
+
+static int prism2_pccard_dev_open(local_info_t *local)
+{
+       struct hostap_cs_priv *hw_priv = local->hw_priv;
+       hw_priv->link->open++;
+       return 0;
+}
+
+
+static int prism2_pccard_dev_close(local_info_t *local)
+{
+       struct hostap_cs_priv *hw_priv;
+
+       if (local == NULL || local->hw_priv == NULL)
+               return 1;
+       hw_priv = local->hw_priv;
+       if (hw_priv->link == NULL)
+               return 1;
+
+       if (!hw_priv->link->open) {
+               printk(KERN_WARNING "%s: prism2_pccard_dev_close(): "
+                      "link not open?!\n", local->dev->name);
+               return 1;
+       }
+
+       hw_priv->link->open--;
+
+       return 0;
+}
+
+
+static struct prism2_helper_functions prism2_pccard_funcs =
+{
+       .card_present   = prism2_pccard_card_present,
+       .cor_sreset     = prism2_pccard_cor_sreset,
+       .dev_open       = prism2_pccard_dev_open,
+       .dev_close      = prism2_pccard_dev_close,
+       .genesis_reset  = prism2_pccard_genesis_reset,
+       .hw_type        = HOSTAP_HW_PCCARD,
+};
+
+
+/* allocate local data and register with CardServices
+ * initialize dev_link structure, but do not configure the card yet */
+static dev_link_t *prism2_attach(void)
+{
+       dev_link_t *link;
+       client_reg_t client_reg;
+       int ret;
+
+       link = kmalloc(sizeof(dev_link_t), GFP_KERNEL);
+       if (link == NULL)
+               return NULL;
+
+       memset(link, 0, sizeof(dev_link_t));
+
+       PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info);
+       link->conf.Vcc = 33;
+       link->conf.IntType = INT_MEMORY_AND_IO;
+
+       /* register with CardServices */
+       link->next = dev_list;
+       dev_list = link;
+       client_reg.dev_info = &dev_info;
+       client_reg.Version = 0x0210;
+       client_reg.event_callback_args.client_data = link;
+       ret = pcmcia_register_client(&link->handle, &client_reg);
+       if (ret != CS_SUCCESS) {
+               cs_error(link->handle, RegisterClient, ret);
+               prism2_detach(link);
+               return NULL;
+       }
+       return link;
+}
+
+
+static void prism2_detach(dev_link_t *link)
+{
+       dev_link_t **linkp;
+
+       PDEBUG(DEBUG_FLOW, "prism2_detach\n");
+
+       for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+               if (*linkp == link)
+                       break;
+       if (*linkp == NULL) {
+               printk(KERN_WARNING "%s: Attempt to detach non-existing "
+                      "PCMCIA client\n", dev_info);
+               return;
+       }
+
+       if (link->state & DEV_CONFIG) {
+               prism2_release((u_long)link);
+       }
+
+       if (link->handle) {
+               int res = pcmcia_deregister_client(link->handle);
+               if (res) {
+                       printk("CardService(DeregisterClient) => %d\n", res);
+                       cs_error(link->handle, DeregisterClient, res);
+               }
+       }
+
+       *linkp = link->next;
+       /* release net devices */
+       if (link->priv) {
+               struct net_device *dev;
+               struct hostap_interface *iface;
+               dev = link->priv;
+               iface = netdev_priv(dev);
+               kfree(iface->local->hw_priv);
+               iface->local->hw_priv = NULL;
+               prism2_free_local_data(dev);
+       }
+       kfree(link);
+}
+
+
+#define CS_CHECK(fn, ret) \
+do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+
+#define CFG_CHECK2(fn, retf) \
+do { int ret = (retf); \
+if (ret != 0) { \
+       PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", ret); \
+       cs_error(link->handle, fn, ret); \
+       goto next_entry; \
+} \
+} while (0)
+
+
+/* run after a CARD_INSERTION event is received to configure the PCMCIA
+ * socket and make the device available to the system */
+static int prism2_config(dev_link_t *link)
+{
+       struct net_device *dev;
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int ret = 1;
+       tuple_t tuple;
+       cisparse_t *parse;
+       int last_fn, last_ret;
+       u_char buf[64];
+       config_info_t conf;
+       cistpl_cftable_entry_t dflt = { 0 };
+       struct hostap_cs_priv *hw_priv;
+
+       PDEBUG(DEBUG_FLOW, "prism2_config()\n");
+
+       parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL);
+       hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL);
+       if (parse == NULL || hw_priv == NULL) {
+               kfree(parse);
+               kfree(hw_priv);
+               ret = -ENOMEM;
+               goto failed;
+       }
+       memset(hw_priv, 0, sizeof(*hw_priv));
+
+       tuple.DesiredTuple = CISTPL_CONFIG;
+       tuple.Attributes = 0;
+       tuple.TupleData = buf;
+       tuple.TupleDataMax = sizeof(buf);
+       tuple.TupleOffset = 0;
+       CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link->handle, &tuple));
+       CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link->handle, &tuple));
+       CS_CHECK(ParseTuple, pcmcia_parse_tuple(link->handle, &tuple, parse));
+       link->conf.ConfigBase = parse->config.base;
+       link->conf.Present = parse->config.rmask[0];
+
+       CS_CHECK(GetConfigurationInfo,
+                pcmcia_get_configuration_info(link->handle, &conf));
+       PDEBUG(DEBUG_HW, "%s: %s Vcc=%d (from config)\n", dev_info,
+              ignore_cis_vcc ? "ignoring" : "setting", conf.Vcc);
+       link->conf.Vcc = conf.Vcc;
+
+       /* Look for an appropriate configuration table entry in the CIS */
+       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+       CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link->handle, &tuple));
+       for (;;) {
+               cistpl_cftable_entry_t *cfg = &(parse->cftable_entry);
+               CFG_CHECK2(GetTupleData,
+                          pcmcia_get_tuple_data(link->handle, &tuple));
+               CFG_CHECK2(ParseTuple,
+                          pcmcia_parse_tuple(link->handle, &tuple, parse));
+
+               if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
+                       dflt = *cfg;
+               if (cfg->index == 0)
+                       goto next_entry;
+               link->conf.ConfigIndex = cfg->index;
+               PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X "
+                      "(default 0x%02X)\n", cfg->index, dflt.index);
+
+               /* Does this card need audio output? */
+               if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+                       link->conf.Attributes |= CONF_ENABLE_SPKR;
+                       link->conf.Status = CCSR_AUDIO_ENA;
+               }
+
+               /* Use power settings for Vcc and Vpp if present */
+               /*  Note that the CIS values need to be rescaled */
+               if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+                       if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] /
+                           10000 && !ignore_cis_vcc) {
+                               PDEBUG(DEBUG_EXTRA, "  Vcc mismatch - skipping"
+                                      " this entry\n");
+                               goto next_entry;
+                       }
+               } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
+                       if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] /
+                           10000 && !ignore_cis_vcc) {
+                               PDEBUG(DEBUG_EXTRA, "  Vcc (default) mismatch "
+                                      "- skipping this entry\n");
+                               goto next_entry;
+                       }
+               }
+
+               if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+                       link->conf.Vpp1 = link->conf.Vpp2 =
+                               cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+               else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
+                       link->conf.Vpp1 = link->conf.Vpp2 =
+                               dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+               /* Do we need to allocate an interrupt? */
+               if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
+                       link->conf.Attributes |= CONF_ENABLE_IRQ;
+               else if (!(link->conf.Attributes & CONF_ENABLE_IRQ)) {
+                       /* At least Compaq WL200 does not have IRQInfo1 set,
+                        * but it does not work without interrupts.. */
+                       printk("Config has no IRQ info, but trying to enable "
+                              "IRQ anyway..\n");
+                       link->conf.Attributes |= CONF_ENABLE_IRQ;
+               }
+
+               /* IO window settings */
+               PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d "
+                      "dflt.io.nwin=%d\n",
+                      cfg->io.nwin, dflt.io.nwin);
+               link->io.NumPorts1 = link->io.NumPorts2 = 0;
+               if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+                       cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+                       link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+                       PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, "
+                              "io.base=0x%04x, len=%d\n", io->flags,
+                              io->win[0].base, io->win[0].len);
+                       if (!(io->flags & CISTPL_IO_8BIT))
+                               link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+                       if (!(io->flags & CISTPL_IO_16BIT))
+                               link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+                       link->io.IOAddrLines = io->flags &
+                               CISTPL_IO_LINES_MASK;
+                       link->io.BasePort1 = io->win[0].base;
+                       link->io.NumPorts1 = io->win[0].len;
+                       if (io->nwin > 1) {
+                               link->io.Attributes2 = link->io.Attributes1;
+                               link->io.BasePort2 = io->win[1].base;
+                               link->io.NumPorts2 = io->win[1].len;
+                       }
+               }
+
+               /* This reserves IO space but doesn't actually enable it */
+               CFG_CHECK2(RequestIO,
+                          pcmcia_request_io(link->handle, &link->io));
+
+               /* This configuration table entry is OK */
+               break;
+
+       next_entry:
+               CS_CHECK(GetNextTuple,
+                        pcmcia_get_next_tuple(link->handle, &tuple));
+       }
+
+       /* Need to allocate net_device before requesting IRQ handler */
+       dev = prism2_init_local_data(&prism2_pccard_funcs, 0,
+                                    &handle_to_dev(link->handle));
+       if (dev == NULL)
+               goto failed;
+       link->priv = dev;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+       local->hw_priv = hw_priv;
+       hw_priv->link = link;
+       strcpy(hw_priv->node.dev_name, dev->name);
+       link->dev = &hw_priv->node;
+
+       /*
+        * Allocate an interrupt line.  Note that this does not assign a
+        * handler to the interrupt, unless the 'Handler' member of the
+        * irq structure is initialized.
+        */
+       if (link->conf.Attributes & CONF_ENABLE_IRQ) {
+               link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+               link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+               link->irq.Handler = prism2_interrupt;
+               link->irq.Instance = dev;
+               CS_CHECK(RequestIRQ,
+                        pcmcia_request_irq(link->handle, &link->irq));
+       }
+
+       /*
+        * This actually configures the PCMCIA socket -- setting up
+        * the I/O windows and the interrupt mapping, and putting the
+        * card and host interface into "Memory and IO" mode.
+        */
+       CS_CHECK(RequestConfiguration,
+                pcmcia_request_configuration(link->handle, &link->conf));
+
+       dev->irq = link->irq.AssignedIRQ;
+       dev->base_addr = link->io.BasePort1;
+
+       /* Finally, report what we've done */
+       printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
+              dev_info, link->conf.ConfigIndex,
+              link->conf.Vcc / 10, link->conf.Vcc % 10);
+       if (link->conf.Vpp1)
+               printk(", Vpp %d.%d", link->conf.Vpp1 / 10,
+                      link->conf.Vpp1 % 10);
+       if (link->conf.Attributes & CONF_ENABLE_IRQ)
+               printk(", irq %d", link->irq.AssignedIRQ);
+       if (link->io.NumPorts1)
+               printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+                      link->io.BasePort1+link->io.NumPorts1-1);
+       if (link->io.NumPorts2)
+               printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+                      link->io.BasePort2+link->io.NumPorts2-1);
+       printk("\n");
+
+       link->state |= DEV_CONFIG;
+       link->state &= ~DEV_CONFIG_PENDING;
+
+       local->shutdown = 0;
+
+       sandisk_enable_wireless(dev);
+
+       ret = prism2_hw_config(dev, 1);
+       if (!ret) {
+               ret = hostap_hw_ready(dev);
+               if (ret == 0 && local->ddev)
+                       strcpy(hw_priv->node.dev_name, local->ddev->name);
+       }
+       kfree(parse);
+       return ret;
+
+ cs_failed:
+       cs_error(link->handle, last_fn, last_ret);
+
+ failed:
+       kfree(parse);
+       kfree(hw_priv);
+       prism2_release((u_long)link);
+       return ret;
+}
+
+
+static void prism2_release(u_long arg)
+{
+       dev_link_t *link = (dev_link_t *)arg;
+
+       PDEBUG(DEBUG_FLOW, "prism2_release\n");
+
+       if (link->priv) {
+               struct net_device *dev = link->priv;
+               struct hostap_interface *iface;
+
+               iface = netdev_priv(dev);
+               if (link->state & DEV_CONFIG)
+                       prism2_hw_shutdown(dev, 0);
+               iface->local->shutdown = 1;
+       }
+
+       if (link->win)
+               pcmcia_release_window(link->win);
+       pcmcia_release_configuration(link->handle);
+       if (link->io.NumPorts1)
+               pcmcia_release_io(link->handle, &link->io);
+       if (link->irq.AssignedIRQ)
+               pcmcia_release_irq(link->handle, &link->irq);
+
+       link->state &= ~DEV_CONFIG;
+
+       PDEBUG(DEBUG_FLOW, "release - done\n");
+}
+
+
+static int prism2_event(event_t event, int priority,
+                       event_callback_args_t *args)
+{
+       dev_link_t *link = args->client_data;
+       struct net_device *dev = (struct net_device *) link->priv;
+
+       switch (event) {
+       case CS_EVENT_CARD_INSERTION:
+               PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_INSERTION\n", dev_info);
+               link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+               if (prism2_config(link)) {
+                       PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n");
+               }
+               break;
+
+       case CS_EVENT_CARD_REMOVAL:
+               PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_REMOVAL\n", dev_info);
+               link->state &= ~DEV_PRESENT;
+               if (link->state & DEV_CONFIG) {
+                       netif_stop_queue(dev);
+                       netif_device_detach(dev);
+                       prism2_release((u_long) link);
+               }
+               break;
+
+       case CS_EVENT_PM_SUSPEND:
+               PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info);
+               link->state |= DEV_SUSPEND;
+               /* fall through */
+
+       case CS_EVENT_RESET_PHYSICAL:
+               PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_RESET_PHYSICAL\n", dev_info);
+               if (link->state & DEV_CONFIG) {
+                       if (link->open) {
+                               netif_stop_queue(dev);
+                               netif_device_detach(dev);
+                       }
+                       prism2_suspend(dev);
+                       pcmcia_release_configuration(link->handle);
+               }
+               break;
+
+       case CS_EVENT_PM_RESUME:
+               PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info);
+               link->state &= ~DEV_SUSPEND;
+               /* fall through */
+
+       case CS_EVENT_CARD_RESET:
+               PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_RESET\n", dev_info);
+               if (link->state & DEV_CONFIG) {
+                       pcmcia_request_configuration(link->handle,
+                                                    &link->conf);
+                       prism2_hw_shutdown(dev, 1);
+                       prism2_hw_config(dev, link->open ? 0 : 1);
+                       if (link->open) {
+                               netif_device_attach(dev);
+                               netif_start_queue(dev);
+                       }
+               }
+               break;
+
+       default:
+               PDEBUG(DEBUG_EXTRA, "%s: prism2_event() - unknown event %d\n",
+                      dev_info, event);
+               break;
+       }
+       return 0;
+}
+
+
+static struct pcmcia_device_id hostap_cs_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100),
+       PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
+       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777),
+       PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000),
+       PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b),
+       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612),
+       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613),
+       PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001),
+       PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001),
+       PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300),
+       PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000),
+       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
+       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010),
+       PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus",
+                                   0x7a954bd9, 0x74be00c6),
+       PCMCIA_DEVICE_PROD_ID1234(
+               "Intersil", "PRISM 2_5 PCMCIA ADAPTER", "ISL37300P",
+               "Eval-RevA",
+               0x4b801a17, 0x6345a0bf, 0xc9049a39, 0xc23adc0e),
+       PCMCIA_DEVICE_PROD_ID123(
+               "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02",
+               0xe6ec52ce, 0x08649af2, 0x4b74baa0),
+       PCMCIA_DEVICE_PROD_ID123(
+               "D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02",
+               0x71b18589, 0xb6f1b0ab, 0x4b74baa0),
+       PCMCIA_DEVICE_PROD_ID123(
+               "Instant Wireless ", " Network PC CARD", "Version 01.02",
+               0x11d901af, 0x6e9bd926, 0x4b74baa0),
+       PCMCIA_DEVICE_PROD_ID123(
+               "SMC", "SMC2632W", "Version 01.02",
+               0xc4f8b18b, 0x474a1f2a, 0x4b74baa0),
+       PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 
+                               0x2decece3, 0x82067c18),
+       PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card",
+                               0x54f7c49c, 0x15a75e5b),
+       PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE",
+                               0x74c5e40d, 0xdb472a18),
+       PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card",
+                               0x0733cc81, 0x0c52f395),
+       PCMCIA_DEVICE_PROD_ID12(
+               "ZoomAir 11Mbps High", "Rate wireless Networking",
+               0x273fe3db, 0x32a1eaee),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);
+
+
+static struct pcmcia_driver hostap_driver = {
+       .drv            = {
+               .name   = "hostap_cs",
+       },
+       .attach         = prism2_attach,
+       .detach         = prism2_detach,
+       .owner          = THIS_MODULE,
+       .event          = prism2_event,
+       .id_table       = hostap_cs_ids,
+};
+
+static int __init init_prism2_pccard(void)
+{
+       printk(KERN_INFO "%s: %s\n", dev_info, version);
+       return pcmcia_register_driver(&hostap_driver);
+}
+
+static void __exit exit_prism2_pccard(void)
+{
+       pcmcia_unregister_driver(&hostap_driver);
+       printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
+}
+
+
+module_init(init_prism2_pccard);
+module_exit(exit_prism2_pccard);
diff --git a/drivers/net/wireless/hostap/hostap_download.c b/drivers/net/wireless/hostap/hostap_download.c
new file mode 100644 (file)
index 0000000..ab26b52
--- /dev/null
@@ -0,0 +1,766 @@
+static int prism2_enable_aux_port(struct net_device *dev, int enable)
+{
+       u16 val, reg;
+       int i, tries;
+       unsigned long flags;
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->no_pri) {
+               if (enable) {
+                       PDEBUG(DEBUG_EXTRA2, "%s: no PRI f/w - assuming Aux "
+                              "port is already enabled\n", dev->name);
+               }
+               return 0;
+       }
+
+       spin_lock_irqsave(&local->cmdlock, flags);
+
+       /* wait until busy bit is clear */
+       tries = HFA384X_CMD_BUSY_TIMEOUT;
+       while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
+               tries--;
+               udelay(1);
+       }
+       if (tries == 0) {
+               reg = HFA384X_INW(HFA384X_CMD_OFF);
+               spin_unlock_irqrestore(&local->cmdlock, flags);
+               printk("%s: prism2_enable_aux_port - timeout - reg=0x%04x\n",
+                      dev->name, reg);
+               return -ETIMEDOUT;
+       }
+
+       val = HFA384X_INW(HFA384X_CONTROL_OFF);
+
+       if (enable) {
+               HFA384X_OUTW(HFA384X_AUX_MAGIC0, HFA384X_PARAM0_OFF);
+               HFA384X_OUTW(HFA384X_AUX_MAGIC1, HFA384X_PARAM1_OFF);
+               HFA384X_OUTW(HFA384X_AUX_MAGIC2, HFA384X_PARAM2_OFF);
+
+               if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_DISABLED)
+                       printk("prism2_enable_aux_port: was not disabled!?\n");
+               val &= ~HFA384X_AUX_PORT_MASK;
+               val |= HFA384X_AUX_PORT_ENABLE;
+       } else {
+               HFA384X_OUTW(0, HFA384X_PARAM0_OFF);
+               HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
+               HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
+
+               if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_ENABLED)
+                       printk("prism2_enable_aux_port: was not enabled!?\n");
+               val &= ~HFA384X_AUX_PORT_MASK;
+               val |= HFA384X_AUX_PORT_DISABLE;
+       }
+       HFA384X_OUTW(val, HFA384X_CONTROL_OFF);
+
+       udelay(5);
+
+       i = 10000;
+       while (i > 0) {
+               val = HFA384X_INW(HFA384X_CONTROL_OFF);
+               val &= HFA384X_AUX_PORT_MASK;
+
+               if ((enable && val == HFA384X_AUX_PORT_ENABLED) ||
+                   (!enable && val == HFA384X_AUX_PORT_DISABLED))
+                       break;
+
+               udelay(10);
+               i--;
+       }
+
+       spin_unlock_irqrestore(&local->cmdlock, flags);
+
+       if (i == 0) {
+               printk("prism2_enable_aux_port(%d) timed out\n",
+                      enable);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+
+static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len,
+                           void *buf)
+{
+       u16 page, offset;
+       if (addr & 1 || len & 1)
+               return -1;
+
+       page = addr >> 7;
+       offset = addr & 0x7f;
+
+       HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
+       HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
+
+       udelay(5);
+
+#ifdef PRISM2_PCI
+       {
+               u16 *pos = (u16 *) buf;
+               while (len > 0) {
+                       *pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF);
+                       len -= 2;
+               }
+       }
+#else /* PRISM2_PCI */
+       HFA384X_INSW(HFA384X_AUXDATA_OFF, buf, len / 2);
+#endif /* PRISM2_PCI */
+
+       return 0;
+}
+
+
+static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len,
+                         void *buf)
+{
+       u16 page, offset;
+       if (addr & 1 || len & 1)
+               return -1;
+
+       page = addr >> 7;
+       offset = addr & 0x7f;
+
+       HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
+       HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
+
+       udelay(5);
+
+#ifdef PRISM2_PCI
+       {
+               u16 *pos = (u16 *) buf;
+               while (len > 0) {
+                       HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF);
+                       len -= 2;
+               }
+       }
+#else /* PRISM2_PCI */
+       HFA384X_OUTSW(HFA384X_AUXDATA_OFF, buf, len / 2);
+#endif /* PRISM2_PCI */
+
+       return 0;
+}
+
+
+static int prism2_pda_ok(u8 *buf)
+{
+       u16 *pda = (u16 *) buf;
+       int pos;
+       u16 len, pdr;
+
+       if (buf[0] == 0xff && buf[1] == 0x00 && buf[2] == 0xff &&
+           buf[3] == 0x00)
+               return 0;
+
+       pos = 0;
+       while (pos + 1 < PRISM2_PDA_SIZE / 2) {
+               len = le16_to_cpu(pda[pos]);
+               pdr = le16_to_cpu(pda[pos + 1]);
+               if (len == 0 || pos + len > PRISM2_PDA_SIZE / 2)
+                       return 0;
+
+               if (pdr == 0x0000 && len == 2) {
+                       /* PDA end found */
+                       return 1;
+               }
+
+               pos += len + 1;
+       }
+
+       return 0;
+}
+
+
+static int prism2_download_aux_dump(struct net_device *dev,
+                                    unsigned int addr, int len, u8 *buf)
+{
+       int res;
+
+       prism2_enable_aux_port(dev, 1);
+       res = hfa384x_from_aux(dev, addr, len, buf);
+       prism2_enable_aux_port(dev, 0);
+       if (res)
+               return -1;
+
+       return 0;
+}
+
+
+static u8 * prism2_read_pda(struct net_device *dev)
+{
+       u8 *buf;
+       int res, i, found = 0;
+#define NUM_PDA_ADDRS 4
+       unsigned int pda_addr[NUM_PDA_ADDRS] = {
+               0x7f0000 /* others than HFA3841 */,
+               0x3f0000 /* HFA3841 */,
+               0x390000 /* apparently used in older cards */,
+               0x7f0002 /* Intel PRO/Wireless 2011B (PCI) */,
+       };
+
+       buf = (u8 *) kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL);
+       if (buf == NULL)
+               return NULL;
+
+       /* Note: wlan card should be in initial state (just after init cmd)
+        * and no other operations should be performed concurrently. */
+
+       prism2_enable_aux_port(dev, 1);
+
+       for (i = 0; i < NUM_PDA_ADDRS; i++) {
+               PDEBUG(DEBUG_EXTRA2, "%s: trying to read PDA from 0x%08x",
+                      dev->name, pda_addr[i]);
+               res = hfa384x_from_aux(dev, pda_addr[i], PRISM2_PDA_SIZE, buf);
+               if (res)
+                       continue;
+               if (res == 0 && prism2_pda_ok(buf)) {
+                       PDEBUG2(DEBUG_EXTRA2, ": OK\n");
+                       found = 1;
+                       break;
+               } else {
+                       PDEBUG2(DEBUG_EXTRA2, ": failed\n");
+               }
+       }
+
+       prism2_enable_aux_port(dev, 0);
+
+       if (!found) {
+               printk(KERN_DEBUG "%s: valid PDA not found\n", dev->name);
+               kfree(buf);
+               buf = NULL;
+       }
+
+       return buf;
+}
+
+
+static int prism2_download_volatile(local_info_t *local,
+                                   struct prism2_download_data *param)
+{
+       struct net_device *dev = local->dev;
+       int ret = 0, i;
+       u16 param0, param1;
+
+       if (local->hw_downloading) {
+               printk(KERN_WARNING "%s: Already downloading - aborting new "
+                      "request\n", dev->name);
+               return -1;
+       }
+
+       local->hw_downloading = 1;
+       if (local->pri_only) {
+               hfa384x_disable_interrupts(dev);
+       } else {
+               prism2_hw_shutdown(dev, 0);
+
+               if (prism2_hw_init(dev, 0)) {
+                       printk(KERN_WARNING "%s: Could not initialize card for"
+                              " download\n", dev->name);
+                       ret = -1;
+                       goto out;
+               }
+       }
+
+       if (prism2_enable_aux_port(dev, 1)) {
+               printk(KERN_WARNING "%s: Could not enable AUX port\n",
+                      dev->name);
+               ret = -1;
+               goto out;
+       }
+
+       param0 = param->start_addr & 0xffff;
+       param1 = param->start_addr >> 16;
+
+       HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
+       HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
+       if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
+                            (HFA384X_PROGMODE_ENABLE_VOLATILE << 8),
+                            param0)) {
+               printk(KERN_WARNING "%s: Download command execution failed\n",
+                      dev->name);
+               ret = -1;
+               goto out;
+       }
+
+       for (i = 0; i < param->num_areas; i++) {
+               PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n",
+                      dev->name, param->data[i].len, param->data[i].addr);
+               if (hfa384x_to_aux(dev, param->data[i].addr,
+                                  param->data[i].len, param->data[i].data)) {
+                       printk(KERN_WARNING "%s: RAM download at 0x%08x "
+                              "(len=%d) failed\n", dev->name,
+                              param->data[i].addr, param->data[i].len);
+                       ret = -1;
+                       goto out;
+               }
+       }
+
+       HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
+       HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
+       if (hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
+                               (HFA384X_PROGMODE_DISABLE << 8), param0)) {
+               printk(KERN_WARNING "%s: Download command execution failed\n",
+                      dev->name);
+               ret = -1;
+               goto out;
+       }
+       /* ProgMode disable causes the hardware to restart itself from the
+        * given starting address. Give hw some time and ACK command just in
+        * case restart did not happen. */
+       mdelay(5);
+       HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
+
+       if (prism2_enable_aux_port(dev, 0)) {
+               printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
+                      dev->name);
+               /* continue anyway.. restart should have taken care of this */
+       }
+
+       mdelay(5);
+       local->hw_downloading = 0;
+       if (prism2_hw_config(dev, 2)) {
+               printk(KERN_WARNING "%s: Card configuration after RAM "
+                      "download failed\n", dev->name);
+               ret = -1;
+               goto out;
+       }
+
+ out:
+       local->hw_downloading = 0;
+       return ret;
+}
+
+
+static int prism2_enable_genesis(local_info_t *local, int hcr)
+{
+       struct net_device *dev = local->dev;
+       u8 initseq[4] = { 0x00, 0xe1, 0xa1, 0xff };
+       u8 readbuf[4];
+
+       printk(KERN_DEBUG "%s: test Genesis mode with HCR 0x%02x\n",
+              dev->name, hcr);
+       local->func->cor_sreset(local);
+       hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
+       local->func->genesis_reset(local, hcr);
+
+       /* Readback test */
+       hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
+       hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
+       hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
+
+       if (memcmp(initseq, readbuf, sizeof(initseq)) == 0) {
+               printk(KERN_DEBUG "Readback test succeeded, HCR 0x%02x\n",
+                      hcr);
+               return 0;
+       } else {
+               printk(KERN_DEBUG "Readback test failed, HCR 0x%02x "
+                      "write %02x %02x %02x %02x read %02x %02x %02x %02x\n",
+                      hcr, initseq[0], initseq[1], initseq[2], initseq[3],
+                      readbuf[0], readbuf[1], readbuf[2], readbuf[3]);
+               return 1;
+       }
+}
+
+
+static int prism2_get_ram_size(local_info_t *local)
+{
+       int ret;
+
+       /* Try to enable genesis mode; 0x1F for x8 SRAM or 0x0F for x16 SRAM */
+       if (prism2_enable_genesis(local, 0x1f) == 0)
+               ret = 8;
+       else if (prism2_enable_genesis(local, 0x0f) == 0)
+               ret = 16;
+       else
+               ret = -1;
+
+       /* Disable genesis mode */
+       local->func->genesis_reset(local, ret == 16 ? 0x07 : 0x17);
+
+       return ret;
+}
+
+
+static int prism2_download_genesis(local_info_t *local,
+                                  struct prism2_download_data *param)
+{
+       struct net_device *dev = local->dev;
+       int ram16 = 0, i;
+       int ret = 0;
+
+       if (local->hw_downloading) {
+               printk(KERN_WARNING "%s: Already downloading - aborting new "
+                      "request\n", dev->name);
+               return -EBUSY;
+       }
+
+       if (!local->func->genesis_reset || !local->func->cor_sreset) {
+               printk(KERN_INFO "%s: Genesis mode downloading not supported "
+                      "with this hwmodel\n", dev->name);
+               return -EOPNOTSUPP;
+       }
+
+       local->hw_downloading = 1;
+
+       if (prism2_enable_aux_port(dev, 1)) {
+               printk(KERN_DEBUG "%s: failed to enable AUX port\n",
+                      dev->name);
+               ret = -EIO;
+               goto out;
+       }
+
+       if (local->sram_type == -1) {
+               /* 0x1F for x8 SRAM or 0x0F for x16 SRAM */
+               if (prism2_enable_genesis(local, 0x1f) == 0) {
+                       ram16 = 0;
+                       PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x8 "
+                              "SRAM\n", dev->name);
+               } else if (prism2_enable_genesis(local, 0x0f) == 0) {
+                       ram16 = 1;
+                       PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x16 "
+                              "SRAM\n", dev->name);
+               } else {
+                       printk(KERN_DEBUG "%s: Could not initiate genesis "
+                              "mode\n", dev->name);
+                       ret = -EIO;
+                       goto out;
+               }
+       } else {
+               if (prism2_enable_genesis(local, local->sram_type == 8 ?
+                                         0x1f : 0x0f)) {
+                       printk(KERN_DEBUG "%s: Failed to set Genesis "
+                              "mode (sram_type=%d)\n", dev->name,
+                              local->sram_type);
+                       ret = -EIO;
+                       goto out;
+               }
+               ram16 = local->sram_type != 8;
+       }
+
+       for (i = 0; i < param->num_areas; i++) {
+               PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n",
+                      dev->name, param->data[i].len, param->data[i].addr);
+               if (hfa384x_to_aux(dev, param->data[i].addr,
+                                  param->data[i].len, param->data[i].data)) {
+                       printk(KERN_WARNING "%s: RAM download at 0x%08x "
+                              "(len=%d) failed\n", dev->name,
+                              param->data[i].addr, param->data[i].len);
+                       ret = -EIO;
+                       goto out;
+               }
+       }
+
+       PDEBUG(DEBUG_EXTRA2, "Disable genesis mode\n");
+       local->func->genesis_reset(local, ram16 ? 0x07 : 0x17);
+       if (prism2_enable_aux_port(dev, 0)) {
+               printk(KERN_DEBUG "%s: Failed to disable AUX port\n",
+                      dev->name);
+       }
+
+       mdelay(5);
+       local->hw_downloading = 0;
+
+       PDEBUG(DEBUG_EXTRA2, "Trying to initialize card\n");
+       /*
+        * Make sure the INIT command does not generate a command completion
+        * event by disabling interrupts.
+        */
+       hfa384x_disable_interrupts(dev);
+       if (prism2_hw_init(dev, 1)) {
+               printk(KERN_DEBUG "%s: Initialization after genesis mode "
+                      "download failed\n", dev->name);
+               ret = -EIO;
+               goto out;
+       }
+
+       PDEBUG(DEBUG_EXTRA2, "Card initialized - running PRI only\n");
+       if (prism2_hw_init2(dev, 1)) {
+               printk(KERN_DEBUG "%s: Initialization(2) after genesis mode "
+                      "download failed\n", dev->name);
+               ret = -EIO;
+               goto out;
+       }
+
+ out:
+       local->hw_downloading = 0;
+       return ret;
+}
+
+
+#ifdef PRISM2_NON_VOLATILE_DOWNLOAD
+/* Note! Non-volatile downloading functionality has not yet been tested
+ * thoroughly and it may corrupt flash image and effectively kill the card that
+ * is being updated. You have been warned. */
+
+static inline int prism2_download_block(struct net_device *dev,
+                                       u32 addr, u8 *data,
+                                       u32 bufaddr, int rest_len)
+{
+       u16 param0, param1;
+       int block_len;
+
+       block_len = rest_len < 4096 ? rest_len : 4096;
+
+       param0 = addr & 0xffff;
+       param1 = addr >> 16;
+
+       HFA384X_OUTW(block_len, HFA384X_PARAM2_OFF);
+       HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
+
+       if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
+                            (HFA384X_PROGMODE_ENABLE_NON_VOLATILE << 8),
+                            param0)) {
+               printk(KERN_WARNING "%s: Flash download command execution "
+                      "failed\n", dev->name);
+               return -1;
+       }
+
+       if (hfa384x_to_aux(dev, bufaddr, block_len, data)) {
+               printk(KERN_WARNING "%s: flash download at 0x%08x "
+                      "(len=%d) failed\n", dev->name, addr, block_len);
+               return -1;
+       }
+
+       HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
+       HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
+       if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
+                            (HFA384X_PROGMODE_PROGRAM_NON_VOLATILE << 8),
+                            0)) {
+               printk(KERN_WARNING "%s: Flash write command execution "
+                      "failed\n", dev->name);
+               return -1;
+       }
+
+       return block_len;
+}
+
+
+static int prism2_download_nonvolatile(local_info_t *local,
+                                      struct prism2_download_data *dl)
+{
+       struct net_device *dev = local->dev;
+       int ret = 0, i;
+       struct {
+               u16 page;
+               u16 offset;
+               u16 len;
+       } dlbuffer;
+       u32 bufaddr;
+
+       if (local->hw_downloading) {
+               printk(KERN_WARNING "%s: Already downloading - aborting new "
+                      "request\n", dev->name);
+               return -1;
+       }
+
+       ret = local->func->get_rid(dev, HFA384X_RID_DOWNLOADBUFFER,
+                                  &dlbuffer, 6, 0);
+
+       if (ret < 0) {
+               printk(KERN_WARNING "%s: Could not read download buffer "
+                      "parameters\n", dev->name);
+               goto out;
+       }
+
+       dlbuffer.page = le16_to_cpu(dlbuffer.page);
+       dlbuffer.offset = le16_to_cpu(dlbuffer.offset);
+       dlbuffer.len = le16_to_cpu(dlbuffer.len);
+
+       printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n",
+              dlbuffer.len, dlbuffer.page, dlbuffer.offset);
+
+       bufaddr = (dlbuffer.page << 7) + dlbuffer.offset;
+
+       local->hw_downloading = 1;
+
+       if (!local->pri_only) {
+               prism2_hw_shutdown(dev, 0);
+
+               if (prism2_hw_init(dev, 0)) {
+                       printk(KERN_WARNING "%s: Could not initialize card for"
+                              " download\n", dev->name);
+                       ret = -1;
+                       goto out;
+               }
+       }
+
+       hfa384x_disable_interrupts(dev);
+
+       if (prism2_enable_aux_port(dev, 1)) {
+               printk(KERN_WARNING "%s: Could not enable AUX port\n",
+                      dev->name);
+               ret = -1;
+               goto out;
+       }
+
+       printk(KERN_DEBUG "%s: starting flash download\n", dev->name);
+       for (i = 0; i < dl->num_areas; i++) {
+               int rest_len = dl->data[i].len;
+               int data_off = 0;
+
+               while (rest_len > 0) {
+                       int block_len;
+
+                       block_len = prism2_download_block(
+                               dev, dl->data[i].addr + data_off,
+                               dl->data[i].data + data_off, bufaddr,
+                               rest_len);
+
+                       if (block_len < 0) {
+                               ret = -1;
+                               goto out;
+                       }
+
+                       rest_len -= block_len;
+                       data_off += block_len;
+               }
+       }
+
+       HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
+       HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
+       if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
+                               (HFA384X_PROGMODE_DISABLE << 8), 0)) {
+               printk(KERN_WARNING "%s: Download command execution failed\n",
+                      dev->name);
+               ret = -1;
+               goto out;
+       }
+
+       if (prism2_enable_aux_port(dev, 0)) {
+               printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
+                      dev->name);
+               /* continue anyway.. restart should have taken care of this */
+       }
+
+       mdelay(5);
+
+       local->func->hw_reset(dev);
+       local->hw_downloading = 0;
+       if (prism2_hw_config(dev, 2)) {
+               printk(KERN_WARNING "%s: Card configuration after flash "
+                      "download failed\n", dev->name);
+               ret = -1;
+       } else {
+               printk(KERN_INFO "%s: Card initialized successfully after "
+                      "flash download\n", dev->name);
+       }
+
+ out:
+       local->hw_downloading = 0;
+       return ret;
+}
+#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
+
+
+static void prism2_download_free_data(struct prism2_download_data *dl)
+{
+       int i;
+
+       if (dl == NULL)
+               return;
+
+       for (i = 0; i < dl->num_areas; i++)
+               kfree(dl->data[i].data);
+       kfree(dl);
+}
+
+
+static int prism2_download(local_info_t *local,
+                          struct prism2_download_param *param)
+{
+       int ret = 0;
+       int i;
+       u32 total_len = 0;
+       struct prism2_download_data *dl = NULL;
+
+       printk(KERN_DEBUG "prism2_download: dl_cmd=%d start_addr=0x%08x "
+              "num_areas=%d\n",
+              param->dl_cmd, param->start_addr, param->num_areas);
+
+       if (param->num_areas > 100) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       dl = kmalloc(sizeof(*dl) + param->num_areas *
+                    sizeof(struct prism2_download_data_area), GFP_KERNEL);
+       if (dl == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       memset(dl, 0, sizeof(*dl) + param->num_areas *
+              sizeof(struct prism2_download_data_area));
+       dl->dl_cmd = param->dl_cmd;
+       dl->start_addr = param->start_addr;
+       dl->num_areas = param->num_areas;
+       for (i = 0; i < param->num_areas; i++) {
+               PDEBUG(DEBUG_EXTRA2,
+                      "  area %d: addr=0x%08x len=%d ptr=0x%p\n",
+                      i, param->data[i].addr, param->data[i].len,
+                      param->data[i].ptr);
+
+               dl->data[i].addr = param->data[i].addr;
+               dl->data[i].len = param->data[i].len;
+
+               total_len += param->data[i].len;
+               if (param->data[i].len > PRISM2_MAX_DOWNLOAD_AREA_LEN ||
+                   total_len > PRISM2_MAX_DOWNLOAD_LEN) {
+                       ret = -E2BIG;
+                       goto out;
+               }
+
+               dl->data[i].data = kmalloc(dl->data[i].len, GFP_KERNEL);
+               if (dl->data[i].data == NULL) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
+               if (copy_from_user(dl->data[i].data, param->data[i].ptr,
+                                  param->data[i].len)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+       }
+
+       switch (param->dl_cmd) {
+       case PRISM2_DOWNLOAD_VOLATILE:
+       case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT:
+               ret = prism2_download_volatile(local, dl);
+               break;
+       case PRISM2_DOWNLOAD_VOLATILE_GENESIS:
+       case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT:
+               ret = prism2_download_genesis(local, dl);
+               break;
+       case PRISM2_DOWNLOAD_NON_VOLATILE:
+#ifdef PRISM2_NON_VOLATILE_DOWNLOAD
+               ret = prism2_download_nonvolatile(local, dl);
+#else /* PRISM2_NON_VOLATILE_DOWNLOAD */
+               printk(KERN_INFO "%s: non-volatile downloading not enabled\n",
+                      local->dev->name);
+               ret = -EOPNOTSUPP;
+#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
+               break;
+       default:
+               printk(KERN_DEBUG "%s: unsupported download command %d\n",
+                      local->dev->name, param->dl_cmd);
+               ret = -EINVAL;
+               break;
+       };
+
+ out:
+       if (ret == 0 && dl &&
+           param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT) {
+               prism2_download_free_data(local->dl_pri);
+               local->dl_pri = dl;
+       } else if (ret == 0 && dl &&
+                  param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_PERSISTENT) {
+               prism2_download_free_data(local->dl_sec);
+               local->dl_sec = dl;
+       } else
+               prism2_download_free_data(dl);
+
+       return ret;
+}
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
new file mode 100644 (file)
index 0000000..e533a66
--- /dev/null
@@ -0,0 +1,3445 @@
+/*
+ * Host AP (software wireless LAN access point) driver for
+ * Intersil Prism2/2.5/3.
+ *
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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. See README and COPYING for
+ * more details.
+ *
+ * FIX:
+ * - there is currently no way of associating TX packets to correct wds device
+ *   when TX Exc/OK event occurs, so all tx_packets and some
+ *   tx_errors/tx_dropped are added to the main netdevice; using sw_support
+ *   field in txdesc might be used to fix this (using Alloc event to increment
+ *   tx_packets would need some further info in txfid table)
+ *
+ * Buffer Access Path (BAP) usage:
+ *   Prism2 cards have two separate BAPs for accessing the card memory. These
+ *   should allow concurrent access to two different frames and the driver
+ *   previously used BAP0 for sending data and BAP1 for receiving data.
+ *   However, there seems to be number of issues with concurrent access and at
+ *   least one know hardware bug in using BAP0 and BAP1 concurrently with PCI
+ *   Prism2.5. Therefore, the driver now only uses BAP0 for moving data between
+ *   host and card memories. BAP0 accesses are protected with local->baplock
+ *   (spin_lock_bh) to prevent concurrent use.
+ */
+
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include <asm/delay.h>
+#include <asm/uaccess.h>
+
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/if_arp.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/rtnetlink.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <net/ieee80211.h>
+#include <net/ieee80211_crypt.h>
+#include <asm/irq.h>
+
+#include "hostap_80211.h"
+#include "hostap.h"
+#include "hostap_ap.h"
+
+
+/* #define final_version */
+
+static int mtu = 1500;
+module_param(mtu, int, 0444);
+MODULE_PARM_DESC(mtu, "Maximum transfer unit");
+
+static int channel[MAX_PARM_DEVICES] = { 3, DEF_INTS };
+module_param_array(channel, int, NULL, 0444);
+MODULE_PARM_DESC(channel, "Initial channel");
+
+static char essid[33] = "test";
+module_param_string(essid, essid, sizeof(essid), 0444);
+MODULE_PARM_DESC(essid, "Host AP's ESSID");
+
+static int iw_mode[MAX_PARM_DEVICES] = { IW_MODE_MASTER, DEF_INTS };
+module_param_array(iw_mode, int, NULL, 0444);
+MODULE_PARM_DESC(iw_mode, "Initial operation mode");
+
+static int beacon_int[MAX_PARM_DEVICES] = { 100, DEF_INTS };
+module_param_array(beacon_int, int, NULL, 0444);
+MODULE_PARM_DESC(beacon_int, "Beacon interval (1 = 1024 usec)");
+
+static int dtim_period[MAX_PARM_DEVICES] = { 1, DEF_INTS };
+module_param_array(dtim_period, int, NULL, 0444);
+MODULE_PARM_DESC(dtim_period, "DTIM period");
+
+static char dev_template[16] = "wlan%d";
+module_param_string(dev_template, dev_template, sizeof(dev_template), 0444);
+MODULE_PARM_DESC(dev_template, "Prefix for network device name (default: "
+                "wlan%d)");
+
+#ifdef final_version
+#define EXTRA_EVENTS_WTERR 0
+#else
+/* check WTERR events (Wait Time-out) in development versions */
+#define EXTRA_EVENTS_WTERR HFA384X_EV_WTERR
+#endif
+
+/* Events that will be using BAP0 */
+#define HFA384X_BAP0_EVENTS \
+       (HFA384X_EV_TXEXC | HFA384X_EV_RX | HFA384X_EV_INFO | HFA384X_EV_TX)
+
+/* event mask, i.e., events that will result in an interrupt */
+#define HFA384X_EVENT_MASK \
+       (HFA384X_BAP0_EVENTS | HFA384X_EV_ALLOC | HFA384X_EV_INFDROP | \
+       HFA384X_EV_CMD | HFA384X_EV_TICK | \
+       EXTRA_EVENTS_WTERR)
+
+/* Default TX control flags: use 802.11 headers and request interrupt for
+ * failed transmits. Frames that request ACK callback, will add
+ * _TX_OK flag and _ALT_RTRY flag may be used to select different retry policy.
+ */
+#define HFA384X_TX_CTRL_FLAGS \
+       (HFA384X_TX_CTRL_802_11 | HFA384X_TX_CTRL_TX_EX)
+
+
+/* ca. 1 usec */
+#define HFA384X_CMD_BUSY_TIMEOUT 5000
+#define HFA384X_BAP_BUSY_TIMEOUT 50000
+
+/* ca. 10 usec */
+#define HFA384X_CMD_COMPL_TIMEOUT 20000
+#define HFA384X_DL_COMPL_TIMEOUT 1000000
+
+/* Wait times for initialization; yield to other processes to avoid busy
+ * waiting for long time. */
+#define HFA384X_INIT_TIMEOUT (HZ / 2) /* 500 ms */
+#define HFA384X_ALLOC_COMPL_TIMEOUT (HZ / 20) /* 50 ms */
+
+
+static void prism2_hw_reset(struct net_device *dev);
+static void prism2_check_sta_fw_version(local_info_t *local);
+
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+/* hostap_download.c */
+static int prism2_download_aux_dump(struct net_device *dev,
+                                   unsigned int addr, int len, u8 *buf);
+static u8 * prism2_read_pda(struct net_device *dev);
+static int prism2_download(local_info_t *local,
+                          struct prism2_download_param *param);
+static void prism2_download_free_data(struct prism2_download_data *dl);
+static int prism2_download_volatile(local_info_t *local,
+                                   struct prism2_download_data *param);
+static int prism2_download_genesis(local_info_t *local,
+                                  struct prism2_download_data *param);
+static int prism2_get_ram_size(local_info_t *local);
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+
+
+
+
+#ifndef final_version
+/* magic value written to SWSUPPORT0 reg. for detecting whether card is still
+ * present */
+#define HFA384X_MAGIC 0x8A32
+#endif
+
+
+static u16 hfa384x_read_reg(struct net_device *dev, u16 reg)
+{
+       return HFA384X_INW(reg);
+}
+
+
+static void hfa384x_read_regs(struct net_device *dev,
+                             struct hfa384x_regs *regs)
+{
+       regs->cmd = HFA384X_INW(HFA384X_CMD_OFF);
+       regs->evstat = HFA384X_INW(HFA384X_EVSTAT_OFF);
+       regs->offset0 = HFA384X_INW(HFA384X_OFFSET0_OFF);
+       regs->offset1 = HFA384X_INW(HFA384X_OFFSET1_OFF);
+       regs->swsupport0 = HFA384X_INW(HFA384X_SWSUPPORT0_OFF);
+}
+
+
+/**
+ * __hostap_cmd_queue_free - Free Prism2 command queue entry (private)
+ * @local: pointer to private Host AP driver data
+ * @entry: Prism2 command queue entry to be freed
+ * @del_req: request the entry to be removed
+ *
+ * Internal helper function for freeing Prism2 command queue entries.
+ * Caller must have acquired local->cmdlock before calling this function.
+ */
+static inline void __hostap_cmd_queue_free(local_info_t *local,
+                                          struct hostap_cmd_queue *entry,
+                                          int del_req)
+{
+       if (del_req) {
+               entry->del_req = 1;
+               if (!list_empty(&entry->list)) {
+                       list_del_init(&entry->list);
+                       local->cmd_queue_len--;
+               }
+       }
+
+       if (atomic_dec_and_test(&entry->usecnt) && entry->del_req)
+               kfree(entry);
+}
+
+
+/**
+ * hostap_cmd_queue_free - Free Prism2 command queue entry
+ * @local: pointer to private Host AP driver data
+ * @entry: Prism2 command queue entry to be freed
+ * @del_req: request the entry to be removed
+ *
+ * Free a Prism2 command queue entry.
+ */
+static inline void hostap_cmd_queue_free(local_info_t *local,
+                                        struct hostap_cmd_queue *entry,
+                                        int del_req)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&local->cmdlock, flags);
+       __hostap_cmd_queue_free(local, entry, del_req);
+       spin_unlock_irqrestore(&local->cmdlock, flags);
+}
+
+
+/**
+ * prism2_clear_cmd_queue - Free all pending Prism2 command queue entries
+ * @local: pointer to private Host AP driver data
+ */
+static void prism2_clear_cmd_queue(local_info_t *local)
+{
+       struct list_head *ptr, *n;
+       unsigned long flags;
+       struct hostap_cmd_queue *entry;
+
+       spin_lock_irqsave(&local->cmdlock, flags);
+       list_for_each_safe(ptr, n, &local->cmd_queue) {
+               entry = list_entry(ptr, struct hostap_cmd_queue, list);
+               atomic_inc(&entry->usecnt);
+               printk(KERN_DEBUG "%s: removed pending cmd_queue entry "
+                      "(type=%d, cmd=0x%04x, param0=0x%04x)\n",
+                      local->dev->name, entry->type, entry->cmd,
+                      entry->param0);
+               __hostap_cmd_queue_free(local, entry, 1);
+       }
+       if (local->cmd_queue_len) {
+               /* This should not happen; print debug message and clear
+                * queue length. */
+               printk(KERN_DEBUG "%s: cmd_queue_len (%d) not zero after "
+                      "flush\n", local->dev->name, local->cmd_queue_len);
+               local->cmd_queue_len = 0;
+       }
+       spin_unlock_irqrestore(&local->cmdlock, flags);
+}
+
+
+/**
+ * hfa384x_cmd_issue - Issue a Prism2 command to the hardware
+ * @dev: pointer to net_device
+ * @entry: Prism2 command queue entry to be issued
+ */
+static inline int hfa384x_cmd_issue(struct net_device *dev,
+                                   struct hostap_cmd_queue *entry)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int tries;
+       u16 reg;
+       unsigned long flags;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->func->card_present && !local->func->card_present(local))
+               return -ENODEV;
+
+       if (entry->issued) {
+               printk(KERN_DEBUG "%s: driver bug - re-issuing command @%p\n",
+                      dev->name, entry);
+       }
+
+       /* wait until busy bit is clear; this should always be clear since the
+        * commands are serialized */
+       tries = HFA384X_CMD_BUSY_TIMEOUT;
+       while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
+               tries--;
+               udelay(1);
+       }
+#ifndef final_version
+       if (tries != HFA384X_CMD_BUSY_TIMEOUT) {
+               prism2_io_debug_error(dev, 1);
+               printk(KERN_DEBUG "%s: hfa384x_cmd_issue: cmd reg was busy "
+                      "for %d usec\n", dev->name,
+                      HFA384X_CMD_BUSY_TIMEOUT - tries);
+       }
+#endif
+       if (tries == 0) {
+               reg = HFA384X_INW(HFA384X_CMD_OFF);
+               prism2_io_debug_error(dev, 2);
+               printk(KERN_DEBUG "%s: hfa384x_cmd_issue - timeout - "
+                      "reg=0x%04x\n", dev->name, reg);
+               return -ETIMEDOUT;
+       }
+
+       /* write command */
+       spin_lock_irqsave(&local->cmdlock, flags);
+       HFA384X_OUTW(entry->param0, HFA384X_PARAM0_OFF);
+       HFA384X_OUTW(entry->param1, HFA384X_PARAM1_OFF);
+       HFA384X_OUTW(entry->cmd, HFA384X_CMD_OFF);
+       entry->issued = 1;
+       spin_unlock_irqrestore(&local->cmdlock, flags);
+
+       return 0;
+}
+
+
+/**
+ * hfa384x_cmd - Issue a Prism2 command and wait (sleep) for completion
+ * @dev: pointer to net_device
+ * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
+ * @param0: value for Param0 register
+ * @param1: value for Param1 register (pointer; %NULL if not used)
+ * @resp0: pointer for Resp0 data or %NULL if Resp0 is not needed
+ *
+ * Issue given command (possibly after waiting in command queue) and sleep
+ * until the command is completed (or timed out or interrupted). This can be
+ * called only from user process context.
+ */
+static int hfa384x_cmd(struct net_device *dev, u16 cmd, u16 param0,
+                      u16 *param1, u16 *resp0)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int err, res, issue, issued = 0;
+       unsigned long flags;
+       struct hostap_cmd_queue *entry;
+       DECLARE_WAITQUEUE(wait, current);
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (in_interrupt()) {
+               printk(KERN_DEBUG "%s: hfa384x_cmd called from interrupt "
+                      "context\n", dev->name);
+               return -1;
+       }
+
+       if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN) {
+               printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n",
+                      dev->name);
+               return -1;
+       }
+
+       if (signal_pending(current))
+               return -EINTR;
+
+       entry = (struct hostap_cmd_queue *)
+               kmalloc(sizeof(*entry), GFP_ATOMIC);
+       if (entry == NULL) {
+               printk(KERN_DEBUG "%s: hfa384x_cmd - kmalloc failed\n",
+                      dev->name);
+               return -ENOMEM;
+       }
+       memset(entry, 0, sizeof(*entry));
+       atomic_set(&entry->usecnt, 1);
+       entry->type = CMD_SLEEP;
+       entry->cmd = cmd;
+       entry->param0 = param0;
+       if (param1)
+               entry->param1 = *param1;
+       init_waitqueue_head(&entry->compl);
+
+       /* prepare to wait for command completion event, but do not sleep yet
+        */
+       add_wait_queue(&entry->compl, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+
+       spin_lock_irqsave(&local->cmdlock, flags);
+       issue = list_empty(&local->cmd_queue);
+       if (issue)
+               entry->issuing = 1;
+       list_add_tail(&entry->list, &local->cmd_queue);
+       local->cmd_queue_len++;
+       spin_unlock_irqrestore(&local->cmdlock, flags);
+
+       err = 0;
+       if (!issue)
+               goto wait_completion;
+
+       if (signal_pending(current))
+               err = -EINTR;
+
+       if (!err) {
+               if (hfa384x_cmd_issue(dev, entry))
+                       err = -ETIMEDOUT;
+               else
+                       issued = 1;
+       }
+
+ wait_completion:
+       if (!err && entry->type != CMD_COMPLETED) {
+               /* sleep until command is completed or timed out */
+               res = schedule_timeout(2 * HZ);
+       } else
+               res = -1;
+
+       if (!err && signal_pending(current))
+               err = -EINTR;
+
+       if (err && issued) {
+               /* the command was issued, so a CmdCompl event should occur
+                * soon; however, there's a pending signal and
+                * schedule_timeout() would be interrupted; wait a short period
+                * of time to avoid removing entry from the list before
+                * CmdCompl event */
+               udelay(300);
+       }
+
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&entry->compl, &wait);
+
+       /* If entry->list is still in the list, it must be removed
+        * first and in this case prism2_cmd_ev() does not yet have
+        * local reference to it, and the data can be kfree()'d
+        * here. If the command completion event is still generated,
+        * it will be assigned to next (possibly) pending command, but
+        * the driver will reset the card anyway due to timeout
+        *
+        * If the entry is not in the list prism2_cmd_ev() has a local
+        * reference to it, but keeps cmdlock as long as the data is
+        * needed, so the data can be kfree()'d here. */
+
+       /* FIX: if the entry->list is in the list, it has not been completed
+        * yet, so removing it here is somewhat wrong.. this could cause
+        * references to freed memory and next list_del() causing NULL pointer
+        * dereference.. it would probably be better to leave the entry in the
+        * list and the list should be emptied during hw reset */
+
+       spin_lock_irqsave(&local->cmdlock, flags);
+       if (!list_empty(&entry->list)) {
+               printk(KERN_DEBUG "%s: hfa384x_cmd: entry still in list? "
+                      "(entry=%p, type=%d, res=%d)\n", dev->name, entry,
+                      entry->type, res);
+               list_del_init(&entry->list);
+               local->cmd_queue_len--;
+       }
+       spin_unlock_irqrestore(&local->cmdlock, flags);
+
+       if (err) {
+               printk(KERN_DEBUG "%s: hfa384x_cmd: interrupted; err=%d\n",
+                      dev->name, err);
+               res = err;
+               goto done;
+       }
+
+       if (entry->type != CMD_COMPLETED) {
+               u16 reg = HFA384X_INW(HFA384X_EVSTAT_OFF);
+               printk(KERN_DEBUG "%s: hfa384x_cmd: command was not "
+                      "completed (res=%d, entry=%p, type=%d, cmd=0x%04x, "
+                      "param0=0x%04x, EVSTAT=%04x INTEN=%04x)\n", dev->name,
+                      res, entry, entry->type, entry->cmd, entry->param0, reg,
+                      HFA384X_INW(HFA384X_INTEN_OFF));
+               if (reg & HFA384X_EV_CMD) {
+                       /* Command completion event is pending, but the
+                        * interrupt was not delivered - probably an issue
+                        * with pcmcia-cs configuration. */
+                       printk(KERN_WARNING "%s: interrupt delivery does not "
+                              "seem to work\n", dev->name);
+               }
+               prism2_io_debug_error(dev, 3);
+               res = -ETIMEDOUT;
+               goto done;
+       }
+
+       if (resp0 != NULL)
+               *resp0 = entry->resp0;
+#ifndef final_version
+       if (entry->res) {
+               printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x, "
+                      "resp0=0x%04x\n",
+                      dev->name, cmd, entry->res, entry->resp0);
+       }
+#endif /* final_version */
+
+       res = entry->res;
+ done:
+       hostap_cmd_queue_free(local, entry, 1);
+       return res;
+}
+
+
+/**
+ * hfa384x_cmd_callback - Issue a Prism2 command; callback when completed
+ * @dev: pointer to net_device
+ * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
+ * @param0: value for Param0 register
+ * @callback: command completion callback function (%NULL = no callback)
+ * @context: context data to be given to the callback function
+ *
+ * Issue given command (possibly after waiting in command queue) and use
+ * callback function to indicate command completion. This can be called both
+ * from user and interrupt context. The callback function will be called in
+ * hardware IRQ context. It can be %NULL, when no function is called when
+ * command is completed.
+ */
+static int hfa384x_cmd_callback(struct net_device *dev, u16 cmd, u16 param0,
+                               void (*callback)(struct net_device *dev,
+                                                long context, u16 resp0,
+                                                u16 status),
+                               long context)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int issue, ret;
+       unsigned long flags;
+       struct hostap_cmd_queue *entry;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN + 2) {
+               printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n",
+                      dev->name);
+               return -1;
+       }
+
+       entry = (struct hostap_cmd_queue *)
+               kmalloc(sizeof(*entry), GFP_ATOMIC);
+       if (entry == NULL) {
+               printk(KERN_DEBUG "%s: hfa384x_cmd_callback - kmalloc "
+                      "failed\n", dev->name);
+               return -ENOMEM;
+       }
+       memset(entry, 0, sizeof(*entry));
+       atomic_set(&entry->usecnt, 1);
+       entry->type = CMD_CALLBACK;
+       entry->cmd = cmd;
+       entry->param0 = param0;
+       entry->callback = callback;
+       entry->context = context;
+
+       spin_lock_irqsave(&local->cmdlock, flags);
+       issue = list_empty(&local->cmd_queue);
+       if (issue)
+               entry->issuing = 1;
+       list_add_tail(&entry->list, &local->cmd_queue);
+       local->cmd_queue_len++;
+       spin_unlock_irqrestore(&local->cmdlock, flags);
+
+       if (issue && hfa384x_cmd_issue(dev, entry))
+               ret = -ETIMEDOUT;
+       else
+               ret = 0;
+
+       hostap_cmd_queue_free(local, entry, ret);
+
+       return ret;
+}
+
+
+/**
+ * __hfa384x_cmd_no_wait - Issue a Prism2 command (private)
+ * @dev: pointer to net_device
+ * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
+ * @param0: value for Param0 register
+ * @io_debug_num: I/O debug error number
+ *
+ * Shared helper function for hfa384x_cmd_wait() and hfa384x_cmd_no_wait().
+ */
+static int __hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, u16 param0,
+                                int io_debug_num)
+{
+       int tries;
+       u16 reg;
+
+       /* wait until busy bit is clear; this should always be clear since the
+        * commands are serialized */
+       tries = HFA384X_CMD_BUSY_TIMEOUT;
+       while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
+               tries--;
+               udelay(1);
+       }
+       if (tries == 0) {
+               reg = HFA384X_INW(HFA384X_CMD_OFF);
+               prism2_io_debug_error(dev, io_debug_num);
+               printk(KERN_DEBUG "%s: __hfa384x_cmd_no_wait(%d) - timeout - "
+                      "reg=0x%04x\n", dev->name, io_debug_num, reg);
+               return -ETIMEDOUT;
+       }
+
+       /* write command */
+       HFA384X_OUTW(param0, HFA384X_PARAM0_OFF);
+       HFA384X_OUTW(cmd, HFA384X_CMD_OFF);
+
+       return 0;
+}
+
+
+/**
+ * hfa384x_cmd_wait - Issue a Prism2 command and busy wait for completion
+ * @dev: pointer to net_device
+ * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
+ * @param0: value for Param0 register
+ */
+static int hfa384x_cmd_wait(struct net_device *dev, u16 cmd, u16 param0)
+{
+       int res, tries;
+       u16 reg;
+
+       res = __hfa384x_cmd_no_wait(dev, cmd, param0, 4);
+       if (res)
+               return res;
+
+        /* wait for command completion */
+       if ((cmd & HFA384X_CMDCODE_MASK) == HFA384X_CMDCODE_DOWNLOAD)
+               tries = HFA384X_DL_COMPL_TIMEOUT;
+       else
+               tries = HFA384X_CMD_COMPL_TIMEOUT;
+
+        while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) &&
+               tries > 0) {
+                tries--;
+                udelay(10);
+        }
+        if (tries == 0) {
+                reg = HFA384X_INW(HFA384X_EVSTAT_OFF);
+               prism2_io_debug_error(dev, 5);
+                printk(KERN_DEBUG "%s: hfa384x_cmd_wait - timeout2 - "
+                      "reg=0x%04x\n", dev->name, reg);
+                return -ETIMEDOUT;
+        }
+
+        res = (HFA384X_INW(HFA384X_STATUS_OFF) &
+               (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) |
+                BIT(8))) >> 8;
+#ifndef final_version
+       if (res) {
+               printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x\n",
+                      dev->name, cmd, res);
+       }
+#endif
+
+       HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
+
+       return res;
+}
+
+
+/**
+ * hfa384x_cmd_no_wait - Issue a Prism2 command; do not wait for completion
+ * @dev: pointer to net_device
+ * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
+ * @param0: value for Param0 register
+ */
+static inline int hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd,
+                                     u16 param0)
+{
+       return __hfa384x_cmd_no_wait(dev, cmd, param0, 6);
+}
+
+
+/**
+ * prism2_cmd_ev - Prism2 command completion event handler
+ * @dev: pointer to net_device
+ *
+ * Interrupt handler for command completion events. Called by the main
+ * interrupt handler in hardware IRQ context. Read Resp0 and status registers
+ * from the hardware and ACK the event. Depending on the issued command type
+ * either wake up the sleeping process that is waiting for command completion
+ * or call the callback function. Issue the next command, if one is pending.
+ */
+static void prism2_cmd_ev(struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       struct hostap_cmd_queue *entry = NULL;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       spin_lock(&local->cmdlock);
+       if (!list_empty(&local->cmd_queue)) {
+               entry = list_entry(local->cmd_queue.next,
+                                  struct hostap_cmd_queue, list);
+               atomic_inc(&entry->usecnt);
+               list_del_init(&entry->list);
+               local->cmd_queue_len--;
+
+               if (!entry->issued) {
+                       printk(KERN_DEBUG "%s: Command completion event, but "
+                              "cmd not issued\n", dev->name);
+                       __hostap_cmd_queue_free(local, entry, 1);
+                       entry = NULL;
+               }
+       }
+       spin_unlock(&local->cmdlock);
+
+       if (!entry) {
+               HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
+               printk(KERN_DEBUG "%s: Command completion event, but no "
+                      "pending commands\n", dev->name);
+               return;
+       }
+
+       entry->resp0 = HFA384X_INW(HFA384X_RESP0_OFF);
+       entry->res = (HFA384X_INW(HFA384X_STATUS_OFF) &
+                     (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) |
+                      BIT(9) | BIT(8))) >> 8;
+       HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
+
+       /* TODO: rest of the CmdEv handling could be moved to tasklet */
+       if (entry->type == CMD_SLEEP) {
+               entry->type = CMD_COMPLETED;
+               wake_up_interruptible(&entry->compl);
+       } else if (entry->type == CMD_CALLBACK) {
+               if (entry->callback)
+                       entry->callback(dev, entry->context, entry->resp0,
+                                       entry->res);
+       } else {
+               printk(KERN_DEBUG "%s: Invalid command completion type %d\n",
+                      dev->name, entry->type);
+       }
+       hostap_cmd_queue_free(local, entry, 1);
+
+       /* issue next command, if pending */
+       entry = NULL;
+       spin_lock(&local->cmdlock);
+       if (!list_empty(&local->cmd_queue)) {
+               entry = list_entry(local->cmd_queue.next,
+                                  struct hostap_cmd_queue, list);
+               if (entry->issuing) {
+                       /* hfa384x_cmd() has already started issuing this
+                        * command, so do not start here */
+                       entry = NULL;
+               }
+               if (entry)
+                       atomic_inc(&entry->usecnt);
+       }
+       spin_unlock(&local->cmdlock);
+
+       if (entry) {
+               /* issue next command; if command issuing fails, remove the
+                * entry from cmd_queue */
+               int res = hfa384x_cmd_issue(dev, entry);
+               spin_lock(&local->cmdlock);
+               __hostap_cmd_queue_free(local, entry, res);
+               spin_unlock(&local->cmdlock);
+       }
+}
+
+
+static inline int hfa384x_wait_offset(struct net_device *dev, u16 o_off)
+{
+       int tries = HFA384X_BAP_BUSY_TIMEOUT;
+       int res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY;
+
+       while (res && tries > 0) {
+               tries--;
+               udelay(1);
+               res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY;
+       }
+       return res;
+}
+
+
+/* Offset must be even */
+static int hfa384x_setup_bap(struct net_device *dev, u16 bap, u16 id,
+                            int offset)
+{
+       u16 o_off, s_off;
+       int ret = 0;
+
+       if (offset % 2 || bap > 1)
+               return -EINVAL;
+
+       if (bap == BAP1) {
+               o_off = HFA384X_OFFSET1_OFF;
+               s_off = HFA384X_SELECT1_OFF;
+       } else {
+               o_off = HFA384X_OFFSET0_OFF;
+               s_off = HFA384X_SELECT0_OFF;
+       }
+
+       if (hfa384x_wait_offset(dev, o_off)) {
+               prism2_io_debug_error(dev, 7);
+               printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout before\n",
+                      dev->name);
+               ret = -ETIMEDOUT;
+               goto out;
+       }
+
+       HFA384X_OUTW(id, s_off);
+       HFA384X_OUTW(offset, o_off);
+
+       if (hfa384x_wait_offset(dev, o_off)) {
+               prism2_io_debug_error(dev, 8);
+               printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout after\n",
+                      dev->name);
+               ret = -ETIMEDOUT;
+               goto out;
+       }
+#ifndef final_version
+       if (HFA384X_INW(o_off) & HFA384X_OFFSET_ERR) {
+               prism2_io_debug_error(dev, 9);
+               printk(KERN_DEBUG "%s: hfa384x_setup_bap - offset error "
+                      "(%d,0x04%x,%d); reg=0x%04x\n",
+                      dev->name, bap, id, offset, HFA384X_INW(o_off));
+               ret = -EINVAL;
+       }
+#endif
+
+ out:
+       return ret;
+}
+
+
+static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len,
+                          int exact_len)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int res, rlen = 0;
+       struct hfa384x_rid_hdr rec;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->no_pri) {
+               printk(KERN_DEBUG "%s: cannot get RID %04x (len=%d) - no PRI "
+                      "f/w\n", dev->name, rid, len);
+               return -ENOTTY; /* Well.. not really correct, but return
+                                * something unique enough.. */
+       }
+
+       if ((local->func->card_present && !local->func->card_present(local)) ||
+           local->hw_downloading)
+               return -ENODEV;
+
+       res = down_interruptible(&local->rid_bap_sem);
+       if (res)
+               return res;
+
+       res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS, rid, NULL, NULL);
+       if (res) {
+               printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed "
+                      "(res=%d, rid=%04x, len=%d)\n",
+                      dev->name, res, rid, len);
+               up(&local->rid_bap_sem);
+               return res;
+       }
+
+       spin_lock_bh(&local->baplock);
+
+       res = hfa384x_setup_bap(dev, BAP0, rid, 0);
+       if (!res)
+               res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec));
+
+       if (le16_to_cpu(rec.len) == 0) {
+               /* RID not available */
+               res = -ENODATA;
+       }
+
+       rlen = (le16_to_cpu(rec.len) - 1) * 2;
+       if (!res && exact_len && rlen != len) {
+               printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: "
+                      "rid=0x%04x, len=%d (expected %d)\n",
+                      dev->name, rid, rlen, len);
+               res = -ENODATA;
+       }
+
+       if (!res)
+               res = hfa384x_from_bap(dev, BAP0, buf, len);
+
+       spin_unlock_bh(&local->baplock);
+       up(&local->rid_bap_sem);
+
+       if (res) {
+               if (res != -ENODATA)
+                       printk(KERN_DEBUG "%s: hfa384x_get_rid (rid=%04x, "
+                              "len=%d) - failed - res=%d\n", dev->name, rid,
+                              len, res);
+               if (res == -ETIMEDOUT)
+                       prism2_hw_reset(dev);
+               return res;
+       }
+
+       return rlen;
+}
+
+
+static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       struct hfa384x_rid_hdr rec;
+       int res;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->no_pri) {
+               printk(KERN_DEBUG "%s: cannot set RID %04x (len=%d) - no PRI "
+                      "f/w\n", dev->name, rid, len);
+               return -ENOTTY; /* Well.. not really correct, but return
+                                * something unique enough.. */
+       }
+
+       if ((local->func->card_present && !local->func->card_present(local)) ||
+           local->hw_downloading)
+               return -ENODEV;
+
+       rec.rid = cpu_to_le16(rid);
+       /* RID len in words and +1 for rec.rid */
+       rec.len = cpu_to_le16(len / 2 + len % 2 + 1);
+
+       res = down_interruptible(&local->rid_bap_sem);
+       if (res)
+               return res;
+
+       spin_lock_bh(&local->baplock);
+       res = hfa384x_setup_bap(dev, BAP0, rid, 0);
+       if (!res)
+               res = hfa384x_to_bap(dev, BAP0, &rec, sizeof(rec));
+       if (!res)
+               res = hfa384x_to_bap(dev, BAP0, buf, len);
+       spin_unlock_bh(&local->baplock);
+
+       if (res) {
+               printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - "
+                      "failed - res=%d\n", dev->name, rid, len, res);
+               up(&local->rid_bap_sem);
+               return res;
+       }
+
+       res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL);
+       up(&local->rid_bap_sem);
+       if (res) {
+               printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE "
+                      "failed (res=%d, rid=%04x, len=%d)\n",
+                      dev->name, res, rid, len);
+               return res;
+       }
+
+       if (res == -ETIMEDOUT)
+               prism2_hw_reset(dev);
+
+       return res;
+}
+
+
+static void hfa384x_disable_interrupts(struct net_device *dev)
+{
+       /* disable interrupts and clear event status */
+       HFA384X_OUTW(0, HFA384X_INTEN_OFF);
+       HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF);
+}
+
+
+static void hfa384x_enable_interrupts(struct net_device *dev)
+{
+       /* ack pending events and enable interrupts from selected events */
+       HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF);
+       HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF);
+}
+
+
+static void hfa384x_events_no_bap0(struct net_device *dev)
+{
+       HFA384X_OUTW(HFA384X_EVENT_MASK & ~HFA384X_BAP0_EVENTS,
+                    HFA384X_INTEN_OFF);
+}
+
+
+static void hfa384x_events_all(struct net_device *dev)
+{
+       HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF);
+}
+
+
+static void hfa384x_events_only_cmd(struct net_device *dev)
+{
+       HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_INTEN_OFF);
+}
+
+
+static u16 hfa384x_allocate_fid(struct net_device *dev, int len)
+{
+       u16 fid;
+       unsigned long delay;
+
+       /* FIX: this could be replace with hfa384x_cmd() if the Alloc event
+        * below would be handled like CmdCompl event (sleep here, wake up from
+        * interrupt handler */
+       if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_ALLOC, len)) {
+               printk(KERN_DEBUG "%s: cannot allocate fid, len=%d\n",
+                      dev->name, len);
+               return 0xffff;
+       }
+
+       delay = jiffies + HFA384X_ALLOC_COMPL_TIMEOUT;
+       while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC) &&
+              time_before(jiffies, delay))
+               yield();
+       if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC)) {
+               printk("%s: fid allocate, len=%d - timeout\n", dev->name, len);
+               return 0xffff;
+       }
+
+       fid = HFA384X_INW(HFA384X_ALLOCFID_OFF);
+       HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF);
+
+       return fid;
+}
+
+
+static int prism2_reset_port(struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int res;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (!local->dev_enabled)
+               return 0;
+
+       res = hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0,
+                         NULL, NULL);
+       if (res)
+               printk(KERN_DEBUG "%s: reset port failed to disable port\n",
+                      dev->name);
+       else {
+               res = hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0,
+                                 NULL, NULL);
+               if (res)
+                       printk(KERN_DEBUG "%s: reset port failed to enable "
+                              "port\n", dev->name);
+       }
+
+       /* It looks like at least some STA firmware versions reset
+        * fragmentation threshold back to 2346 after enable command. Restore
+        * the configured value, if it differs from this default. */
+       if (local->fragm_threshold != 2346 &&
+           hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD,
+                           local->fragm_threshold)) {
+               printk(KERN_DEBUG "%s: failed to restore fragmentation "
+                      "threshold (%d) after Port0 enable\n",
+                      dev->name, local->fragm_threshold);
+       }
+
+       return res;
+}
+
+
+static int prism2_get_version_info(struct net_device *dev, u16 rid,
+                                  const char *txt)
+{
+       struct hfa384x_comp_ident comp;
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->no_pri) {
+               /* PRI f/w not yet available - cannot read RIDs */
+               return -1;
+       }
+       if (hfa384x_get_rid(dev, rid, &comp, sizeof(comp), 1) < 0) {
+               printk(KERN_DEBUG "Could not get RID for component %s\n", txt);
+               return -1;
+       }
+
+       printk(KERN_INFO "%s: %s: id=0x%02x v%d.%d.%d\n", dev->name, txt,
+              __le16_to_cpu(comp.id), __le16_to_cpu(comp.major),
+              __le16_to_cpu(comp.minor), __le16_to_cpu(comp.variant));
+       return 0;
+}
+
+
+static int prism2_setup_rids(struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       u16 tmp;
+       int ret = 0;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       hostap_set_word(dev, HFA384X_RID_TICKTIME, 2000);
+
+       if (!local->fw_ap) {
+               tmp = hostap_get_porttype(local);
+               ret = hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, tmp);
+               if (ret) {
+                       printk("%s: Port type setting to %d failed\n",
+                              dev->name, tmp);
+                       goto fail;
+               }
+       }
+
+       /* Setting SSID to empty string seems to kill the card in Host AP mode
+        */
+       if (local->iw_mode != IW_MODE_MASTER || local->essid[0] != '\0') {
+               ret = hostap_set_string(dev, HFA384X_RID_CNFOWNSSID,
+                                       local->essid);
+               if (ret) {
+                       printk("%s: AP own SSID setting failed\n", dev->name);
+                       goto fail;
+               }
+       }
+
+       ret = hostap_set_word(dev, HFA384X_RID_CNFMAXDATALEN,
+                             PRISM2_DATA_MAXLEN);
+       if (ret) {
+               printk("%s: MAC data length setting to %d failed\n",
+                      dev->name, PRISM2_DATA_MAXLEN);
+               goto fail;
+       }
+
+       if (hfa384x_get_rid(dev, HFA384X_RID_CHANNELLIST, &tmp, 2, 1) < 0) {
+               printk("%s: Channel list read failed\n", dev->name);
+               ret = -EINVAL;
+               goto fail;
+       }
+       local->channel_mask = __le16_to_cpu(tmp);
+
+       if (local->channel < 1 || local->channel > 14 ||
+           !(local->channel_mask & (1 << (local->channel - 1)))) {
+               printk(KERN_WARNING "%s: Channel setting out of range "
+                      "(%d)!\n", dev->name, local->channel);
+               ret = -EBUSY;
+               goto fail;
+       }
+
+       ret = hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel);
+       if (ret) {
+               printk("%s: Channel setting to %d failed\n",
+                      dev->name, local->channel);
+               goto fail;
+       }
+
+       ret = hostap_set_word(dev, HFA384X_RID_CNFBEACONINT,
+                             local->beacon_int);
+       if (ret) {
+               printk("%s: Beacon interval setting to %d failed\n",
+                      dev->name, local->beacon_int);
+               /* this may fail with Symbol/Lucent firmware */
+               if (ret == -ETIMEDOUT)
+                       goto fail;
+       }
+
+       ret = hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD,
+                             local->dtim_period);
+       if (ret) {
+               printk("%s: DTIM period setting to %d failed\n",
+                      dev->name, local->dtim_period);
+               /* this may fail with Symbol/Lucent firmware */
+               if (ret == -ETIMEDOUT)
+                       goto fail;
+       }
+
+       ret = hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE,
+                             local->is_promisc);
+       if (ret)
+               printk(KERN_INFO "%s: Setting promiscuous mode (%d) failed\n",
+                      dev->name, local->is_promisc);
+
+       if (!local->fw_ap) {
+               ret = hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID,
+                                       local->essid);
+               if (ret) {
+                       printk("%s: Desired SSID setting failed\n", dev->name);
+                       goto fail;
+               }
+       }
+
+       /* Setup TXRateControl, defaults to allow use of 1, 2, 5.5, and
+        * 11 Mbps in automatic TX rate fallback and 1 and 2 Mbps as basic
+        * rates */
+       if (local->tx_rate_control == 0) {
+               local->tx_rate_control =
+                       HFA384X_RATES_1MBPS |
+                       HFA384X_RATES_2MBPS |
+                       HFA384X_RATES_5MBPS |
+                       HFA384X_RATES_11MBPS;
+       }
+       if (local->basic_rates == 0)
+               local->basic_rates = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS;
+
+       if (!local->fw_ap) {
+               ret = hostap_set_word(dev, HFA384X_RID_TXRATECONTROL,
+                                     local->tx_rate_control);
+               if (ret) {
+                       printk("%s: TXRateControl setting to %d failed\n",
+                              dev->name, local->tx_rate_control);
+                       goto fail;
+               }
+
+               ret = hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES,
+                                     local->tx_rate_control);
+               if (ret) {
+                       printk("%s: cnfSupportedRates setting to %d failed\n",
+                              dev->name, local->tx_rate_control);
+               }
+
+               ret = hostap_set_word(dev, HFA384X_RID_CNFBASICRATES,
+                                     local->basic_rates);
+               if (ret) {
+                       printk("%s: cnfBasicRates setting to %d failed\n",
+                              dev->name, local->basic_rates);
+               }
+
+               ret = hostap_set_word(dev, HFA384X_RID_CREATEIBSS, 1);
+               if (ret) {
+                       printk("%s: Create IBSS setting to 1 failed\n",
+                              dev->name);
+               }
+       }
+
+       if (local->name_set)
+               (void) hostap_set_string(dev, HFA384X_RID_CNFOWNNAME,
+                                        local->name);
+
+       if (hostap_set_encryption(local)) {
+               printk(KERN_INFO "%s: could not configure encryption\n",
+                      dev->name);
+       }
+
+       (void) hostap_set_antsel(local);
+
+       if (hostap_set_roaming(local)) {
+               printk(KERN_INFO "%s: could not set host roaming\n",
+                      dev->name);
+       }
+
+       if (local->sta_fw_ver >= PRISM2_FW_VER(1,6,3) &&
+           hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, local->enh_sec))
+               printk(KERN_INFO "%s: cnfEnhSecurity setting to 0x%x failed\n",
+                      dev->name, local->enh_sec);
+
+       /* 32-bit tallies were added in STA f/w 0.8.0, but they were apparently
+        * not working correctly (last seven counters report bogus values).
+        * This has been fixed in 0.8.2, so enable 32-bit tallies only
+        * beginning with that firmware version. Another bug fix for 32-bit
+        * tallies in 1.4.0; should 16-bit tallies be used for some other
+        * versions, too? */
+       if (local->sta_fw_ver >= PRISM2_FW_VER(0,8,2)) {
+               if (hostap_set_word(dev, HFA384X_RID_CNFTHIRTY2TALLY, 1)) {
+                       printk(KERN_INFO "%s: cnfThirty2Tally setting "
+                              "failed\n", dev->name);
+                       local->tallies32 = 0;
+               } else
+                       local->tallies32 = 1;
+       } else
+               local->tallies32 = 0;
+
+       hostap_set_auth_algs(local);
+
+       if (hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD,
+                           local->fragm_threshold)) {
+               printk(KERN_INFO "%s: setting FragmentationThreshold to %d "
+                      "failed\n", dev->name, local->fragm_threshold);
+       }
+
+       if (hostap_set_word(dev, HFA384X_RID_RTSTHRESHOLD,
+                           local->rts_threshold)) {
+               printk(KERN_INFO "%s: setting RTSThreshold to %d failed\n",
+                      dev->name, local->rts_threshold);
+       }
+
+       if (local->manual_retry_count >= 0 &&
+           hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT,
+                           local->manual_retry_count)) {
+               printk(KERN_INFO "%s: setting cnfAltRetryCount to %d failed\n",
+                      dev->name, local->manual_retry_count);
+       }
+
+       if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1) &&
+           hfa384x_get_rid(dev, HFA384X_RID_CNFDBMADJUST, &tmp, 2, 1) == 2) {
+               local->rssi_to_dBm = le16_to_cpu(tmp);
+       }
+
+       if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->wpa &&
+           hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1)) {
+               printk(KERN_INFO "%s: setting ssnHandlingMode to 1 failed\n",
+                      dev->name);
+       }
+
+       if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->generic_elem &&
+           hfa384x_set_rid(dev, HFA384X_RID_GENERICELEMENT,
+                           local->generic_elem, local->generic_elem_len)) {
+               printk(KERN_INFO "%s: setting genericElement failed\n",
+                      dev->name);
+       }
+
+ fail:
+       return ret;
+}
+
+
+static int prism2_hw_init(struct net_device *dev, int initial)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int ret, first = 1;
+       unsigned long start, delay;
+
+       PDEBUG(DEBUG_FLOW, "prism2_hw_init()\n");
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits);
+
+ init:
+       /* initialize HFA 384x */
+       ret = hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_INIT, 0);
+       if (ret) {
+               printk(KERN_INFO "%s: first command failed - assuming card "
+                      "does not have primary firmware\n", dev_info);
+       }
+
+       if (first && (HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) {
+               /* EvStat has Cmd bit set in some cases, so retry once if no
+                * wait was needed */
+               HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
+               printk(KERN_DEBUG "%s: init command completed too quickly - "
+                      "retrying\n", dev->name);
+               first = 0;
+               goto init;
+       }
+
+       start = jiffies;
+       delay = jiffies + HFA384X_INIT_TIMEOUT;
+       while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) &&
+              time_before(jiffies, delay))
+               yield();
+       if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) {
+               printk(KERN_DEBUG "%s: assuming no Primary image in "
+                      "flash - card initialization not completed\n",
+                      dev_info);
+               local->no_pri = 1;
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+                       if (local->sram_type == -1)
+                               local->sram_type = prism2_get_ram_size(local);
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+               return 1;
+       }
+       local->no_pri = 0;
+       printk(KERN_DEBUG "prism2_hw_init: initialized in %lu ms\n",
+              (jiffies - start) * 1000 / HZ);
+       HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
+       return 0;
+}
+
+
+static int prism2_hw_init2(struct net_device *dev, int initial)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int i;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+       kfree(local->pda);
+       if (local->no_pri)
+               local->pda = NULL;
+       else
+               local->pda = prism2_read_pda(dev);
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+
+       hfa384x_disable_interrupts(dev);
+
+#ifndef final_version
+       HFA384X_OUTW(HFA384X_MAGIC, HFA384X_SWSUPPORT0_OFF);
+       if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) {
+               printk("SWSUPPORT0 write/read failed: %04X != %04X\n",
+                      HFA384X_INW(HFA384X_SWSUPPORT0_OFF), HFA384X_MAGIC);
+               goto failed;
+       }
+#endif
+
+       if (initial || local->pri_only) {
+               hfa384x_events_only_cmd(dev);
+               /* get card version information */
+               if (prism2_get_version_info(dev, HFA384X_RID_NICID, "NIC") ||
+                   prism2_get_version_info(dev, HFA384X_RID_PRIID, "PRI")) {
+                       hfa384x_disable_interrupts(dev);
+                       goto failed;
+               }
+
+               if (prism2_get_version_info(dev, HFA384X_RID_STAID, "STA")) {
+                       printk(KERN_DEBUG "%s: Failed to read STA f/w version "
+                              "- only Primary f/w present\n", dev->name);
+                       local->pri_only = 1;
+                       return 0;
+               }
+               local->pri_only = 0;
+               hfa384x_disable_interrupts(dev);
+       }
+
+       /* FIX: could convert allocate_fid to use sleeping CmdCompl wait and
+        * enable interrupts before this. This would also require some sort of
+        * sleeping AllocEv waiting */
+
+       /* allocate TX FIDs */
+       local->txfid_len = PRISM2_TXFID_LEN;
+       for (i = 0; i < PRISM2_TXFID_COUNT; i++) {
+               local->txfid[i] = hfa384x_allocate_fid(dev, local->txfid_len);
+               if (local->txfid[i] == 0xffff && local->txfid_len > 1600) {
+                       local->txfid[i] = hfa384x_allocate_fid(dev, 1600);
+                       if (local->txfid[i] != 0xffff) {
+                               printk(KERN_DEBUG "%s: Using shorter TX FID "
+                                      "(1600 bytes)\n", dev->name);
+                               local->txfid_len = 1600;
+                       }
+               }
+               if (local->txfid[i] == 0xffff)
+                       goto failed;
+               local->intransmitfid[i] = PRISM2_TXFID_EMPTY;
+       }
+
+       hfa384x_events_only_cmd(dev);
+
+       if (initial) {
+               struct list_head *ptr;
+               prism2_check_sta_fw_version(local);
+
+               if (hfa384x_get_rid(dev, HFA384X_RID_CNFOWNMACADDR,
+                                   &dev->dev_addr, 6, 1) < 0) {
+                       printk("%s: could not get own MAC address\n",
+                              dev->name);
+               }
+               list_for_each(ptr, &local->hostap_interfaces) {
+                       iface = list_entry(ptr, struct hostap_interface, list);
+                       memcpy(iface->dev->dev_addr, dev->dev_addr, ETH_ALEN);
+               }
+       } else if (local->fw_ap)
+               prism2_check_sta_fw_version(local);
+
+       prism2_setup_rids(dev);
+
+       /* MAC is now configured, but port 0 is not yet enabled */
+       return 0;
+
+ failed:
+       if (!local->no_pri)
+               printk(KERN_WARNING "%s: Initialization failed\n", dev_info);
+       return 1;
+}
+
+
+static int prism2_hw_enable(struct net_device *dev, int initial)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int was_resetting;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+       was_resetting = local->hw_resetting;
+
+       if (hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, NULL)) {
+               printk("%s: MAC port 0 enabling failed\n", dev->name);
+               return 1;
+       }
+
+       local->hw_ready = 1;
+       local->hw_reset_tries = 0;
+       local->hw_resetting = 0;
+       hfa384x_enable_interrupts(dev);
+
+       /* at least D-Link DWL-650 seems to require additional port reset
+        * before it starts acting as an AP, so reset port automatically
+        * here just in case */
+       if (initial && prism2_reset_port(dev)) {
+               printk("%s: MAC port 0 reseting failed\n", dev->name);
+               return 1;
+       }
+
+       if (was_resetting && netif_queue_stopped(dev)) {
+               /* If hw_reset() was called during pending transmit, netif
+                * queue was stopped. Wake it up now since the wlan card has
+                * been resetted. */
+               netif_wake_queue(dev);
+       }
+
+       return 0;
+}
+
+
+static int prism2_hw_config(struct net_device *dev, int initial)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->hw_downloading)
+               return 1;
+
+       if (prism2_hw_init(dev, initial)) {
+               return local->no_pri ? 0 : 1;
+       }
+
+       if (prism2_hw_init2(dev, initial))
+               return 1;
+
+       /* Enable firmware if secondary image is loaded and at least one of the
+        * netdevices is up. */
+       if (!local->pri_only &&
+           (initial == 0 || (initial == 2 && local->num_dev_open > 0))) {
+               if (!local->dev_enabled)
+                       prism2_callback(local, PRISM2_CALLBACK_ENABLE);
+               local->dev_enabled = 1;
+               return prism2_hw_enable(dev, initial);
+       }
+
+       return 0;
+}
+
+
+static void prism2_hw_shutdown(struct net_device *dev, int no_disable)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       /* Allow only command completion events during disable */
+       hfa384x_events_only_cmd(dev);
+
+       local->hw_ready = 0;
+       if (local->dev_enabled)
+               prism2_callback(local, PRISM2_CALLBACK_DISABLE);
+       local->dev_enabled = 0;
+
+       if (local->func->card_present && !local->func->card_present(local)) {
+               printk(KERN_DEBUG "%s: card already removed or not configured "
+                      "during shutdown\n", dev->name);
+               return;
+       }
+
+       if ((no_disable & HOSTAP_HW_NO_DISABLE) == 0 &&
+           hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, NULL))
+               printk(KERN_WARNING "%s: Shutdown failed\n", dev_info);
+
+       hfa384x_disable_interrupts(dev);
+
+       if (no_disable & HOSTAP_HW_ENABLE_CMDCOMPL)
+               hfa384x_events_only_cmd(dev);
+       else
+               prism2_clear_cmd_queue(local);
+}
+
+
+static void prism2_hw_reset(struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+#if 0
+       static long last_reset = 0;
+
+       /* do not reset card more than once per second to avoid ending up in a
+        * busy loop reseting the card */
+       if (time_before_eq(jiffies, last_reset + HZ))
+               return;
+       last_reset = jiffies;
+#endif
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (in_interrupt()) {
+               printk(KERN_DEBUG "%s: driver bug - prism2_hw_reset() called "
+                      "in interrupt context\n", dev->name);
+               return;
+       }
+
+       if (local->hw_downloading)
+               return;
+
+       if (local->hw_resetting) {
+               printk(KERN_WARNING "%s: %s: already resetting card - "
+                      "ignoring reset request\n", dev_info, dev->name);
+               return;
+       }
+
+       local->hw_reset_tries++;
+       if (local->hw_reset_tries > 10) {
+               printk(KERN_WARNING "%s: too many reset tries, skipping\n",
+                      dev->name);
+               return;
+       }
+
+       printk(KERN_WARNING "%s: %s: resetting card\n", dev_info, dev->name);
+       hfa384x_disable_interrupts(dev);
+       local->hw_resetting = 1;
+       if (local->func->cor_sreset) {
+               /* Host system seems to hang in some cases with high traffic
+                * load or shared interrupts during COR sreset. Disable shared
+                * interrupts during reset to avoid these crashes. COS sreset
+                * takes quite a long time, so it is unfortunate that this
+                * seems to be needed. Anyway, I do not know of any better way
+                * of avoiding the crash. */
+               disable_irq(dev->irq);
+               local->func->cor_sreset(local);
+               enable_irq(dev->irq);
+       }
+       prism2_hw_shutdown(dev, 1);
+       prism2_hw_config(dev, 0);
+       local->hw_resetting = 0;
+
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+       if (local->dl_pri) {
+               printk(KERN_DEBUG "%s: persistent download of primary "
+                      "firmware\n", dev->name);
+               if (prism2_download_genesis(local, local->dl_pri) < 0)
+                       printk(KERN_WARNING "%s: download (PRI) failed\n",
+                              dev->name);
+       }
+
+       if (local->dl_sec) {
+               printk(KERN_DEBUG "%s: persistent download of secondary "
+                      "firmware\n", dev->name);
+               if (prism2_download_volatile(local, local->dl_sec) < 0)
+                       printk(KERN_WARNING "%s: download (SEC) failed\n",
+                              dev->name);
+       }
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+
+       /* TODO: restore beacon TIM bits for STAs that have buffered frames */
+}
+
+
+static void prism2_schedule_reset(local_info_t *local)
+{
+       schedule_work(&local->reset_queue);
+}
+
+
+/* Called only as scheduled task after noticing card timeout in interrupt
+ * context */
+static void handle_reset_queue(void *data)
+{
+       local_info_t *local = (local_info_t *) data;
+
+       printk(KERN_DEBUG "%s: scheduled card reset\n", local->dev->name);
+       prism2_hw_reset(local->dev);
+
+       if (netif_queue_stopped(local->dev)) {
+               int i;
+
+               for (i = 0; i < PRISM2_TXFID_COUNT; i++)
+                       if (local->intransmitfid[i] == PRISM2_TXFID_EMPTY) {
+                               PDEBUG(DEBUG_EXTRA, "prism2_tx_timeout: "
+                                      "wake up queue\n");
+                               netif_wake_queue(local->dev);
+                               break;
+                       }
+       }
+}
+
+
+static int prism2_get_txfid_idx(local_info_t *local)
+{
+       int idx, end;
+       unsigned long flags;
+
+       spin_lock_irqsave(&local->txfidlock, flags);
+       end = idx = local->next_txfid;
+       do {
+               if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) {
+                       local->intransmitfid[idx] = PRISM2_TXFID_RESERVED;
+                       spin_unlock_irqrestore(&local->txfidlock, flags);
+                       return idx;
+               }
+               idx++;
+               if (idx >= PRISM2_TXFID_COUNT)
+                       idx = 0;
+       } while (idx != end);
+       spin_unlock_irqrestore(&local->txfidlock, flags);
+
+       PDEBUG(DEBUG_EXTRA2, "prism2_get_txfid_idx: no room in txfid buf: "
+              "packet dropped\n");
+       local->stats.tx_dropped++;
+
+       return -1;
+}
+
+
+/* Called only from hardware IRQ */
+static void prism2_transmit_cb(struct net_device *dev, long context,
+                              u16 resp0, u16 res)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int idx = (int) context;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (res) {
+               printk(KERN_DEBUG "%s: prism2_transmit_cb - res=0x%02x\n",
+                      dev->name, res);
+               return;
+       }
+
+       if (idx < 0 || idx >= PRISM2_TXFID_COUNT) {
+               printk(KERN_DEBUG "%s: prism2_transmit_cb called with invalid "
+                      "idx=%d\n", dev->name, idx);
+               return;
+       }
+
+       if (!test_and_clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) {
+               printk(KERN_DEBUG "%s: driver bug: prism2_transmit_cb called "
+                      "with no pending transmit\n", dev->name);
+       }
+
+       if (netif_queue_stopped(dev)) {
+               /* ready for next TX, so wake up queue that was stopped in
+                * prism2_transmit() */
+               netif_wake_queue(dev);
+       }
+
+       spin_lock(&local->txfidlock);
+
+       /* With reclaim, Resp0 contains new txfid for transmit; the old txfid
+        * will be automatically allocated for the next TX frame */
+       local->intransmitfid[idx] = resp0;
+
+       PDEBUG(DEBUG_FID, "%s: prism2_transmit_cb: txfid[%d]=0x%04x, "
+              "resp0=0x%04x, transmit_txfid=0x%04x\n",
+              dev->name, idx, local->txfid[idx],
+              resp0, local->intransmitfid[local->next_txfid]);
+
+       idx++;
+       if (idx >= PRISM2_TXFID_COUNT)
+               idx = 0;
+       local->next_txfid = idx;
+
+       /* check if all TX buffers are occupied */
+       do {
+               if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) {
+                       spin_unlock(&local->txfidlock);
+                       return;
+               }
+               idx++;
+               if (idx >= PRISM2_TXFID_COUNT)
+                       idx = 0;
+       } while (idx != local->next_txfid);
+       spin_unlock(&local->txfidlock);
+
+       /* no empty TX buffers, stop queue */
+       netif_stop_queue(dev);
+}
+
+
+/* Called only from software IRQ if PCI bus master is not used (with bus master
+ * this can be called both from software and hardware IRQ) */
+static int prism2_transmit(struct net_device *dev, int idx)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int res;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       /* The driver tries to stop netif queue so that there would not be
+        * more than one attempt to transmit frames going on; check that this
+        * is really the case */
+
+       if (test_and_set_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) {
+               printk(KERN_DEBUG "%s: driver bug - prism2_transmit() called "
+                      "when previous TX was pending\n", dev->name);
+               return -1;
+       }
+
+       /* stop the queue for the time that transmit is pending */
+       netif_stop_queue(dev);
+
+       /* transmit packet */
+       res = hfa384x_cmd_callback(
+               dev,
+               HFA384X_CMDCODE_TRANSMIT | HFA384X_CMD_TX_RECLAIM,
+               local->txfid[idx],
+               prism2_transmit_cb, (long) idx);
+
+       if (res) {
+               struct net_device_stats *stats;
+               printk(KERN_DEBUG "%s: prism2_transmit: CMDCODE_TRANSMIT "
+                      "failed (res=%d)\n", dev->name, res);
+               stats = hostap_get_stats(dev);
+               stats->tx_dropped++;
+               netif_wake_queue(dev);
+               return -1;
+       }
+       dev->trans_start = jiffies;
+
+       /* Since we did not wait for command completion, the card continues
+        * to process on the background and we will finish handling when
+        * command completion event is handled (prism2_cmd_ev() function) */
+
+       return 0;
+}
+
+
+/* Send IEEE 802.11 frame (convert the header into Prism2 TX descriptor and
+ * send the payload with this descriptor) */
+/* Called only from software IRQ */
+static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       struct hfa384x_tx_frame txdesc;
+       struct hostap_skb_tx_data *meta;
+       int hdr_len, data_len, idx, res, ret = -1;
+       u16 tx_control, fc;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       meta = (struct hostap_skb_tx_data *) skb->cb;
+
+       prism2_callback(local, PRISM2_CALLBACK_TX_START);
+
+       if ((local->func->card_present && !local->func->card_present(local)) ||
+           !local->hw_ready || local->hw_downloading || local->pri_only) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: prism2_tx_80211: hw not ready -"
+                              " skipping\n", dev->name);
+               }
+               goto fail;
+       }
+
+       memset(&txdesc, 0, sizeof(txdesc));
+
+       /* skb->data starts with txdesc->frame_control */
+       hdr_len = 24;
+       memcpy(&txdesc.frame_control, skb->data, hdr_len);
+       fc = le16_to_cpu(txdesc.frame_control);
+       if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&
+           (fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS) &&
+           skb->len >= 30) {
+               /* Addr4 */
+               memcpy(txdesc.addr4, skb->data + hdr_len, ETH_ALEN);
+               hdr_len += ETH_ALEN;
+       }
+
+       tx_control = local->tx_control;
+       if (meta->tx_cb_idx) {
+               tx_control |= HFA384X_TX_CTRL_TX_OK;
+               txdesc.sw_support = cpu_to_le16(meta->tx_cb_idx);
+       }
+       txdesc.tx_control = cpu_to_le16(tx_control);
+       txdesc.tx_rate = meta->rate;
+
+       data_len = skb->len - hdr_len;
+       txdesc.data_len = cpu_to_le16(data_len);
+       txdesc.len = cpu_to_be16(data_len);
+
+       idx = prism2_get_txfid_idx(local);
+       if (idx < 0)
+               goto fail;
+
+       if (local->frame_dump & PRISM2_DUMP_TX_HDR)
+               hostap_dump_tx_header(dev->name, &txdesc);
+
+       spin_lock(&local->baplock);
+       res = hfa384x_setup_bap(dev, BAP0, local->txfid[idx], 0);
+
+       if (!res)
+               res = hfa384x_to_bap(dev, BAP0, &txdesc, sizeof(txdesc));
+       if (!res)
+               res = hfa384x_to_bap(dev, BAP0, skb->data + hdr_len,
+                                    skb->len - hdr_len);
+       spin_unlock(&local->baplock);
+
+       if (!res)
+               res = prism2_transmit(dev, idx);
+       if (res) {
+               printk(KERN_DEBUG "%s: prism2_tx_80211 - to BAP0 failed\n",
+                      dev->name);
+               local->intransmitfid[idx] = PRISM2_TXFID_EMPTY;
+               schedule_work(&local->reset_queue);
+               goto fail;
+       }
+
+       ret = 0;
+
+fail:
+       prism2_callback(local, PRISM2_CALLBACK_TX_END);
+       return ret;
+}
+
+
+/* Some SMP systems have reported number of odd errors with hostap_pci. fid
+ * register has changed values between consecutive reads for an unknown reason.
+ * This should really not happen, so more debugging is needed. This test
+ * version is a big slower, but it will detect most of such register changes
+ * and will try to get the correct fid eventually. */
+#define EXTRA_FID_READ_TESTS
+
+static inline u16 prism2_read_fid_reg(struct net_device *dev, u16 reg)
+{
+#ifdef EXTRA_FID_READ_TESTS
+       u16 val, val2, val3;
+       int i;
+
+       for (i = 0; i < 10; i++) {
+               val = HFA384X_INW(reg);
+               val2 = HFA384X_INW(reg);
+               val3 = HFA384X_INW(reg);
+
+               if (val == val2 && val == val3)
+                       return val;
+
+               printk(KERN_DEBUG "%s: detected fid change (try=%d, reg=%04x):"
+                      " %04x %04x %04x\n",
+                      dev->name, i, reg, val, val2, val3);
+               if ((val == val2 || val == val3) && val != 0)
+                       return val;
+               if (val2 == val3 && val2 != 0)
+                       return val2;
+       }
+       printk(KERN_WARNING "%s: Uhhuh.. could not read good fid from reg "
+              "%04x (%04x %04x %04x)\n", dev->name, reg, val, val2, val3);
+       return val;
+#else /* EXTRA_FID_READ_TESTS */
+       return HFA384X_INW(reg);
+#endif /* EXTRA_FID_READ_TESTS */
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_rx(local_info_t *local)
+{
+       struct net_device *dev = local->dev;
+       int res, rx_pending = 0;
+       u16 len, hdr_len, rxfid, status, macport;
+       struct net_device_stats *stats;
+       struct hfa384x_rx_frame rxdesc;
+       struct sk_buff *skb = NULL;
+
+       prism2_callback(local, PRISM2_CALLBACK_RX_START);
+       stats = hostap_get_stats(dev);
+
+       rxfid = prism2_read_fid_reg(dev, HFA384X_RXFID_OFF);
+#ifndef final_version
+       if (rxfid == 0) {
+               rxfid = HFA384X_INW(HFA384X_RXFID_OFF);
+               printk(KERN_DEBUG "prism2_rx: rxfid=0 (next 0x%04x)\n",
+                      rxfid);
+               if (rxfid == 0) {
+                       schedule_work(&local->reset_queue);
+                       goto rx_dropped;
+               }
+               /* try to continue with the new rxfid value */
+       }
+#endif
+
+       spin_lock(&local->baplock);
+       res = hfa384x_setup_bap(dev, BAP0, rxfid, 0);
+       if (!res)
+               res = hfa384x_from_bap(dev, BAP0, &rxdesc, sizeof(rxdesc));
+
+       if (res) {
+               spin_unlock(&local->baplock);
+               printk(KERN_DEBUG "%s: copy from BAP0 failed %d\n", dev->name,
+                      res);
+               if (res == -ETIMEDOUT) {
+                       schedule_work(&local->reset_queue);
+               }
+               goto rx_dropped;
+       }
+
+       len = le16_to_cpu(rxdesc.data_len);
+       hdr_len = sizeof(rxdesc);
+       status = le16_to_cpu(rxdesc.status);
+       macport = (status >> 8) & 0x07;
+
+       /* Drop frames with too large reported payload length. Monitor mode
+        * seems to sometimes pass frames (e.g., ctrl::ack) with signed and
+        * negative value, so allow also values 65522 .. 65534 (-14 .. -2) for
+        * macport 7 */
+       if (len > PRISM2_DATA_MAXLEN + 8 /* WEP */) {
+               if (macport == 7 && local->iw_mode == IW_MODE_MONITOR) {
+                       if (len >= (u16) -14) {
+                               hdr_len -= 65535 - len;
+                               hdr_len--;
+                       }
+                       len = 0;
+               } else {
+                       spin_unlock(&local->baplock);
+                       printk(KERN_DEBUG "%s: Received frame with invalid "
+                              "length 0x%04x\n", dev->name, len);
+                       hostap_dump_rx_header(dev->name, &rxdesc);
+                       goto rx_dropped;
+               }
+       }
+
+       skb = dev_alloc_skb(len + hdr_len);
+       if (!skb) {
+               spin_unlock(&local->baplock);
+               printk(KERN_DEBUG "%s: RX failed to allocate skb\n",
+                      dev->name);
+               goto rx_dropped;
+       }
+       skb->dev = dev;
+       memcpy(skb_put(skb, hdr_len), &rxdesc, hdr_len);
+
+       if (len > 0)
+               res = hfa384x_from_bap(dev, BAP0, skb_put(skb, len), len);
+       spin_unlock(&local->baplock);
+       if (res) {
+               printk(KERN_DEBUG "%s: RX failed to read "
+                      "frame data\n", dev->name);
+               goto rx_dropped;
+       }
+
+       skb_queue_tail(&local->rx_list, skb);
+       tasklet_schedule(&local->rx_tasklet);
+
+ rx_exit:
+       prism2_callback(local, PRISM2_CALLBACK_RX_END);
+       if (!rx_pending) {
+               HFA384X_OUTW(HFA384X_EV_RX, HFA384X_EVACK_OFF);
+       }
+
+       return;
+
+ rx_dropped:
+       stats->rx_dropped++;
+       if (skb)
+               dev_kfree_skb(skb);
+       goto rx_exit;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void hostap_rx_skb(local_info_t *local, struct sk_buff *skb)
+{
+       struct hfa384x_rx_frame *rxdesc;
+       struct net_device *dev = skb->dev;
+       struct hostap_80211_rx_status stats;
+       int hdrlen, rx_hdrlen;
+
+       rx_hdrlen = sizeof(*rxdesc);
+       if (skb->len < sizeof(*rxdesc)) {
+               /* Allow monitor mode to receive shorter frames */
+               if (local->iw_mode == IW_MODE_MONITOR &&
+                   skb->len >= sizeof(*rxdesc) - 30) {
+                       rx_hdrlen = skb->len;
+               } else {
+                       dev_kfree_skb(skb);
+                       return;
+               }
+       }
+
+       rxdesc = (struct hfa384x_rx_frame *) skb->data;
+
+       if (local->frame_dump & PRISM2_DUMP_RX_HDR &&
+           skb->len >= sizeof(*rxdesc))
+               hostap_dump_rx_header(dev->name, rxdesc);
+
+       if (le16_to_cpu(rxdesc->status) & HFA384X_RX_STATUS_FCSERR &&
+           (!local->monitor_allow_fcserr ||
+            local->iw_mode != IW_MODE_MONITOR))
+               goto drop;
+
+       if (skb->len > PRISM2_DATA_MAXLEN) {
+               printk(KERN_DEBUG "%s: RX: len(%d) > MAX(%d)\n",
+                      dev->name, skb->len, PRISM2_DATA_MAXLEN);
+               goto drop;
+       }
+
+       stats.mac_time = le32_to_cpu(rxdesc->time);
+       stats.signal = rxdesc->signal - local->rssi_to_dBm;
+       stats.noise = rxdesc->silence - local->rssi_to_dBm;
+       stats.rate = rxdesc->rate;
+
+       /* Convert Prism2 RX structure into IEEE 802.11 header */
+       hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(rxdesc->frame_control));
+       if (hdrlen > rx_hdrlen)
+               hdrlen = rx_hdrlen;
+
+       memmove(skb_pull(skb, rx_hdrlen - hdrlen),
+               &rxdesc->frame_control, hdrlen);
+
+       hostap_80211_rx(dev, skb, &stats);
+       return;
+
+ drop:
+       dev_kfree_skb(skb);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void hostap_rx_tasklet(unsigned long data)
+{
+       local_info_t *local = (local_info_t *) data;
+       struct sk_buff *skb;
+
+       while ((skb = skb_dequeue(&local->rx_list)) != NULL)
+               hostap_rx_skb(local, skb);
+}
+
+
+/* Called only from hardware IRQ */
+static void prism2_alloc_ev(struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int idx;
+       u16 fid;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       fid = prism2_read_fid_reg(dev, HFA384X_ALLOCFID_OFF);
+
+       PDEBUG(DEBUG_FID, "FID: interrupt: ALLOC - fid=0x%04x\n", fid);
+
+       spin_lock(&local->txfidlock);
+       idx = local->next_alloc;
+
+       do {
+               if (local->txfid[idx] == fid) {
+                       PDEBUG(DEBUG_FID, "FID: found matching txfid[%d]\n",
+                              idx);
+
+#ifndef final_version
+                       if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY)
+                               printk("Already released txfid found at idx "
+                                      "%d\n", idx);
+                       if (local->intransmitfid[idx] == PRISM2_TXFID_RESERVED)
+                               printk("Already reserved txfid found at idx "
+                                      "%d\n", idx);
+#endif
+                       local->intransmitfid[idx] = PRISM2_TXFID_EMPTY;
+                       idx++;
+                       local->next_alloc = idx >= PRISM2_TXFID_COUNT ? 0 :
+                               idx;
+
+                       if (!test_bit(HOSTAP_BITS_TRANSMIT, &local->bits) &&
+                           netif_queue_stopped(dev))
+                               netif_wake_queue(dev);
+
+                       spin_unlock(&local->txfidlock);
+                       return;
+               }
+
+               idx++;
+               if (idx >= PRISM2_TXFID_COUNT)
+                       idx = 0;
+       } while (idx != local->next_alloc);
+
+       printk(KERN_WARNING "%s: could not find matching txfid (0x%04x, new "
+              "read 0x%04x) for alloc event\n", dev->name, fid,
+              HFA384X_INW(HFA384X_ALLOCFID_OFF));
+       printk(KERN_DEBUG "TXFIDs:");
+       for (idx = 0; idx < PRISM2_TXFID_COUNT; idx++)
+               printk(" %04x[%04x]", local->txfid[idx],
+                      local->intransmitfid[idx]);
+       printk("\n");
+       spin_unlock(&local->txfidlock);
+
+       /* FIX: should probably schedule reset; reference to one txfid was lost
+        * completely.. Bad things will happen if we run out of txfids
+        * Actually, this will cause netdev watchdog to notice TX timeout and
+        * then card reset after all txfids have been leaked. */
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void hostap_tx_callback(local_info_t *local,
+                              struct hfa384x_tx_frame *txdesc, int ok,
+                              char *payload)
+{
+       u16 sw_support, hdrlen, len;
+       struct sk_buff *skb;
+       struct hostap_tx_callback_info *cb;
+
+       /* Make sure that frame was from us. */
+       if (memcmp(txdesc->addr2, local->dev->dev_addr, ETH_ALEN)) {
+               printk(KERN_DEBUG "%s: TX callback - foreign frame\n",
+                      local->dev->name);
+               return;
+       }
+
+       sw_support = le16_to_cpu(txdesc->sw_support);
+
+       spin_lock(&local->lock);
+       cb = local->tx_callback;
+       while (cb != NULL && cb->idx != sw_support)
+               cb = cb->next;
+       spin_unlock(&local->lock);
+
+       if (cb == NULL) {
+               printk(KERN_DEBUG "%s: could not find TX callback (idx %d)\n",
+                      local->dev->name, sw_support);
+               return;
+       }
+
+       hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(txdesc->frame_control));
+       len = le16_to_cpu(txdesc->data_len);
+       skb = dev_alloc_skb(hdrlen + len);
+       if (skb == NULL) {
+               printk(KERN_DEBUG "%s: hostap_tx_callback failed to allocate "
+                      "skb\n", local->dev->name);
+               return;
+       }
+
+       memcpy(skb_put(skb, hdrlen), (void *) &txdesc->frame_control, hdrlen);
+       if (payload)
+               memcpy(skb_put(skb, len), payload, len);
+
+       skb->dev = local->dev;
+       skb->mac.raw = skb->data;
+
+       cb->func(skb, ok, cb->data);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static int hostap_tx_compl_read(local_info_t *local, int error,
+                               struct hfa384x_tx_frame *txdesc,
+                               char **payload)
+{
+       u16 fid, len;
+       int res, ret = 0;
+       struct net_device *dev = local->dev;
+
+       fid = prism2_read_fid_reg(dev, HFA384X_TXCOMPLFID_OFF);
+
+       PDEBUG(DEBUG_FID, "interrupt: TX (err=%d) - fid=0x%04x\n", fid, error);
+
+       spin_lock(&local->baplock);
+       res = hfa384x_setup_bap(dev, BAP0, fid, 0);
+       if (!res)
+               res = hfa384x_from_bap(dev, BAP0, txdesc, sizeof(*txdesc));
+       if (res) {
+               PDEBUG(DEBUG_EXTRA, "%s: TX (err=%d) - fid=0x%04x - could not "
+                      "read txdesc\n", dev->name, error, fid);
+               if (res == -ETIMEDOUT) {
+                       schedule_work(&local->reset_queue);
+               }
+               ret = -1;
+               goto fail;
+       }
+       if (txdesc->sw_support) {
+               len = le16_to_cpu(txdesc->data_len);
+               if (len < PRISM2_DATA_MAXLEN) {
+                       *payload = (char *) kmalloc(len, GFP_ATOMIC);
+                       if (*payload == NULL ||
+                           hfa384x_from_bap(dev, BAP0, *payload, len)) {
+                               PDEBUG(DEBUG_EXTRA, "%s: could not read TX "
+                                      "frame payload\n", dev->name);
+                               kfree(*payload);
+                               *payload = NULL;
+                               ret = -1;
+                               goto fail;
+                       }
+               }
+       }
+
+ fail:
+       spin_unlock(&local->baplock);
+
+       return ret;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_tx_ev(local_info_t *local)
+{
+       struct net_device *dev = local->dev;
+       char *payload = NULL;
+       struct hfa384x_tx_frame txdesc;
+
+       if (hostap_tx_compl_read(local, 0, &txdesc, &payload))
+               goto fail;
+
+       if (local->frame_dump & PRISM2_DUMP_TX_HDR) {
+               PDEBUG(DEBUG_EXTRA, "%s: TX - status=0x%04x "
+                      "retry_count=%d tx_rate=%d seq_ctrl=%d "
+                      "duration_id=%d\n",
+                      dev->name, le16_to_cpu(txdesc.status),
+                      txdesc.retry_count, txdesc.tx_rate,
+                      le16_to_cpu(txdesc.seq_ctrl),
+                      le16_to_cpu(txdesc.duration_id));
+       }
+
+       if (txdesc.sw_support)
+               hostap_tx_callback(local, &txdesc, 1, payload);
+       kfree(payload);
+
+ fail:
+       HFA384X_OUTW(HFA384X_EV_TX, HFA384X_EVACK_OFF);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void hostap_sta_tx_exc_tasklet(unsigned long data)
+{
+       local_info_t *local = (local_info_t *) data;
+       struct sk_buff *skb;
+
+       while ((skb = skb_dequeue(&local->sta_tx_exc_list)) != NULL) {
+               struct hfa384x_tx_frame *txdesc =
+                       (struct hfa384x_tx_frame *) skb->data;
+
+               if (skb->len >= sizeof(*txdesc)) {
+                       /* Convert Prism2 RX structure into IEEE 802.11 header
+                        */
+                       u16 fc = le16_to_cpu(txdesc->frame_control);
+                       int hdrlen = hostap_80211_get_hdrlen(fc);
+                       memmove(skb_pull(skb, sizeof(*txdesc) - hdrlen),
+                               &txdesc->frame_control, hdrlen);
+
+                       hostap_handle_sta_tx_exc(local, skb);
+               }
+               dev_kfree_skb(skb);
+       }
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_txexc(local_info_t *local)
+{
+       struct net_device *dev = local->dev;
+       u16 status, fc;
+       int show_dump, res;
+       char *payload = NULL;
+       struct hfa384x_tx_frame txdesc;
+
+       show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR;
+       local->stats.tx_errors++;
+
+       res = hostap_tx_compl_read(local, 1, &txdesc, &payload);
+       HFA384X_OUTW(HFA384X_EV_TXEXC, HFA384X_EVACK_OFF);
+       if (res)
+               return;
+
+       status = le16_to_cpu(txdesc.status);
+
+       /* We produce a TXDROP event only for retry or lifetime
+        * exceeded, because that's the only status that really mean
+        * that this particular node went away.
+        * Other errors means that *we* screwed up. - Jean II */
+       if (status & (HFA384X_TX_STATUS_RETRYERR | HFA384X_TX_STATUS_AGEDERR))
+       {
+               union iwreq_data wrqu;
+
+               /* Copy 802.11 dest address. */
+               memcpy(wrqu.addr.sa_data, txdesc.addr1, ETH_ALEN);
+               wrqu.addr.sa_family = ARPHRD_ETHER;
+               wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
+       } else
+               show_dump = 1;
+
+       if (local->iw_mode == IW_MODE_MASTER ||
+           local->iw_mode == IW_MODE_REPEAT ||
+           local->wds_type & HOSTAP_WDS_AP_CLIENT) {
+               struct sk_buff *skb;
+               skb = dev_alloc_skb(sizeof(txdesc));
+               if (skb) {
+                       memcpy(skb_put(skb, sizeof(txdesc)), &txdesc,
+                              sizeof(txdesc));
+                       skb_queue_tail(&local->sta_tx_exc_list, skb);
+                       tasklet_schedule(&local->sta_tx_exc_tasklet);
+               }
+       }
+
+       if (txdesc.sw_support)
+               hostap_tx_callback(local, &txdesc, 0, payload);
+       kfree(payload);
+
+       if (!show_dump)
+               return;
+
+       PDEBUG(DEBUG_EXTRA, "%s: TXEXC - status=0x%04x (%s%s%s%s)"
+              " tx_control=%04x\n",
+              dev->name, status,
+              status & HFA384X_TX_STATUS_RETRYERR ? "[RetryErr]" : "",
+              status & HFA384X_TX_STATUS_AGEDERR ? "[AgedErr]" : "",
+              status & HFA384X_TX_STATUS_DISCON ? "[Discon]" : "",
+              status & HFA384X_TX_STATUS_FORMERR ? "[FormErr]" : "",
+              le16_to_cpu(txdesc.tx_control));
+
+       fc = le16_to_cpu(txdesc.frame_control);
+       PDEBUG(DEBUG_EXTRA, "   retry_count=%d tx_rate=%d fc=0x%04x "
+              "(%s%s%s::%d%s%s)\n",
+              txdesc.retry_count, txdesc.tx_rate, fc,
+              WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT ? "Mgmt" : "",
+              WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_CTL ? "Ctrl" : "",
+              WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA ? "Data" : "",
+              WLAN_FC_GET_STYPE(fc) >> 4,
+              fc & IEEE80211_FCTL_TODS ? " ToDS" : "",
+              fc & IEEE80211_FCTL_FROMDS ? " FromDS" : "");
+       PDEBUG(DEBUG_EXTRA, "   A1=" MACSTR " A2=" MACSTR " A3="
+              MACSTR " A4=" MACSTR "\n",
+              MAC2STR(txdesc.addr1), MAC2STR(txdesc.addr2),
+              MAC2STR(txdesc.addr3), MAC2STR(txdesc.addr4));
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void hostap_info_tasklet(unsigned long data)
+{
+       local_info_t *local = (local_info_t *) data;
+       struct sk_buff *skb;
+
+       while ((skb = skb_dequeue(&local->info_list)) != NULL) {
+               hostap_info_process(local, skb);
+               dev_kfree_skb(skb);
+       }
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_info(local_info_t *local)
+{
+       struct net_device *dev = local->dev;
+       u16 fid;
+       int res, left;
+       struct hfa384x_info_frame info;
+       struct sk_buff *skb;
+
+       fid = HFA384X_INW(HFA384X_INFOFID_OFF);
+
+       spin_lock(&local->baplock);
+       res = hfa384x_setup_bap(dev, BAP0, fid, 0);
+       if (!res)
+               res = hfa384x_from_bap(dev, BAP0, &info, sizeof(info));
+       if (res) {
+               spin_unlock(&local->baplock);
+               printk(KERN_DEBUG "Could not get info frame (fid=0x%04x)\n",
+                      fid);
+               if (res == -ETIMEDOUT) {
+                       schedule_work(&local->reset_queue);
+               }
+               goto out;
+       }
+
+       le16_to_cpus(&info.len);
+       le16_to_cpus(&info.type);
+       left = (info.len - 1) * 2;
+
+       if (info.len & 0x8000 || info.len == 0 || left > 2060) {
+               /* data register seems to give 0x8000 in some error cases even
+                * though busy bit is not set in offset register;
+                * in addition, length must be at least 1 due to type field */
+               spin_unlock(&local->baplock);
+               printk(KERN_DEBUG "%s: Received info frame with invalid "
+                      "length 0x%04x (type 0x%04x)\n", dev->name, info.len,
+                      info.type);
+               goto out;
+       }
+
+       skb = dev_alloc_skb(sizeof(info) + left);
+       if (skb == NULL) {
+               spin_unlock(&local->baplock);
+               printk(KERN_DEBUG "%s: Could not allocate skb for info "
+                      "frame\n", dev->name);
+               goto out;
+       }
+
+       memcpy(skb_put(skb, sizeof(info)), &info, sizeof(info));
+       if (left > 0 && hfa384x_from_bap(dev, BAP0, skb_put(skb, left), left))
+       {
+               spin_unlock(&local->baplock);
+               printk(KERN_WARNING "%s: Info frame read failed (fid=0x%04x, "
+                      "len=0x%04x, type=0x%04x\n",
+                      dev->name, fid, info.len, info.type);
+               dev_kfree_skb(skb);
+               goto out;
+       }
+       spin_unlock(&local->baplock);
+
+       skb_queue_tail(&local->info_list, skb);
+       tasklet_schedule(&local->info_tasklet);
+
+ out:
+       HFA384X_OUTW(HFA384X_EV_INFO, HFA384X_EVACK_OFF);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void hostap_bap_tasklet(unsigned long data)
+{
+       local_info_t *local = (local_info_t *) data;
+       struct net_device *dev = local->dev;
+       u16 ev;
+       int frames = 30;
+
+       if (local->func->card_present && !local->func->card_present(local))
+               return;
+
+       set_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits);
+
+       /* Process all pending BAP events without generating new interrupts
+        * for them */
+       while (frames-- > 0) {
+               ev = HFA384X_INW(HFA384X_EVSTAT_OFF);
+               if (ev == 0xffff || !(ev & HFA384X_BAP0_EVENTS))
+                       break;
+               if (ev & HFA384X_EV_RX)
+                       prism2_rx(local);
+               if (ev & HFA384X_EV_INFO)
+                       prism2_info(local);
+               if (ev & HFA384X_EV_TX)
+                       prism2_tx_ev(local);
+               if (ev & HFA384X_EV_TXEXC)
+                       prism2_txexc(local);
+       }
+
+       set_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits);
+       clear_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits);
+
+       /* Enable interrupts for new BAP events */
+       hfa384x_events_all(dev);
+       clear_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits);
+}
+
+
+/* Called only from hardware IRQ */
+static void prism2_infdrop(struct net_device *dev)
+{
+       static unsigned long last_inquire = 0;
+
+       PDEBUG(DEBUG_EXTRA, "%s: INFDROP event\n", dev->name);
+
+       /* some firmware versions seem to get stuck with
+        * full CommTallies in high traffic load cases; every
+        * packet will then cause INFDROP event and CommTallies
+        * info frame will not be sent automatically. Try to
+        * get out of this state by inquiring CommTallies. */
+       if (!last_inquire || time_after(jiffies, last_inquire + HZ)) {
+               hfa384x_cmd_callback(dev, HFA384X_CMDCODE_INQUIRE,
+                                    HFA384X_INFO_COMMTALLIES, NULL, 0);
+               last_inquire = jiffies;
+       }
+}
+
+
+/* Called only from hardware IRQ */
+static void prism2_ev_tick(struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       u16 evstat, inten;
+       static int prev_stuck = 0;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (time_after(jiffies, local->last_tick_timer + 5 * HZ) &&
+           local->last_tick_timer) {
+               evstat = HFA384X_INW(HFA384X_EVSTAT_OFF);
+               inten = HFA384X_INW(HFA384X_INTEN_OFF);
+               if (!prev_stuck) {
+                       printk(KERN_INFO "%s: SW TICK stuck? "
+                              "bits=0x%lx EvStat=%04x IntEn=%04x\n",
+                              dev->name, local->bits, evstat, inten);
+               }
+               local->sw_tick_stuck++;
+               if ((evstat & HFA384X_BAP0_EVENTS) &&
+                   (inten & HFA384X_BAP0_EVENTS)) {
+                       printk(KERN_INFO "%s: trying to recover from IRQ "
+                              "hang\n", dev->name);
+                       hfa384x_events_no_bap0(dev);
+               }
+               prev_stuck = 1;
+       } else
+               prev_stuck = 0;
+}
+
+
+/* Called only from hardware IRQ */
+static inline void prism2_check_magic(local_info_t *local)
+{
+       /* at least PCI Prism2.5 with bus mastering seems to sometimes
+        * return 0x0000 in SWSUPPORT0 for unknown reason, but re-reading the
+        * register once or twice seems to get the correct value.. PCI cards
+        * cannot anyway be removed during normal operation, so there is not
+        * really any need for this verification with them. */
+
+#ifndef PRISM2_PCI
+#ifndef final_version
+       static unsigned long last_magic_err = 0;
+       struct net_device *dev = local->dev;
+
+       if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) {
+               if (!local->hw_ready)
+                       return;
+               HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF);
+               if (time_after(jiffies, last_magic_err + 10 * HZ)) {
+                       printk("%s: Interrupt, but SWSUPPORT0 does not match: "
+                              "%04X != %04X - card removed?\n", dev->name,
+                              HFA384X_INW(HFA384X_SWSUPPORT0_OFF),
+                              HFA384X_MAGIC);
+                       last_magic_err = jiffies;
+               } else if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: interrupt - SWSUPPORT0=%04x "
+                              "MAGIC=%04x\n", dev->name,
+                              HFA384X_INW(HFA384X_SWSUPPORT0_OFF),
+                              HFA384X_MAGIC);
+               }
+               if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != 0xffff)
+                       schedule_work(&local->reset_queue);
+               return;
+       }
+#endif /* final_version */
+#endif /* !PRISM2_PCI */
+}
+
+
+/* Called only from hardware IRQ */
+static irqreturn_t prism2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct net_device *dev = (struct net_device *) dev_id;
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int events = 0;
+       u16 ev;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0);
+
+       if (local->func->card_present && !local->func->card_present(local)) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: Interrupt, but dev not OK\n",
+                              dev->name);
+               }
+               return IRQ_HANDLED;
+       }
+
+       prism2_check_magic(local);
+
+       for (;;) {
+               ev = HFA384X_INW(HFA384X_EVSTAT_OFF);
+               if (ev == 0xffff) {
+                       if (local->shutdown)
+                               return IRQ_HANDLED;
+                       HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF);
+                       printk(KERN_DEBUG "%s: prism2_interrupt: ev=0xffff\n",
+                              dev->name);
+                       return IRQ_HANDLED;
+               }
+
+               ev &= HFA384X_INW(HFA384X_INTEN_OFF);
+               if (ev == 0)
+                       break;
+
+               if (ev & HFA384X_EV_CMD) {
+                       prism2_cmd_ev(dev);
+               }
+
+               /* Above events are needed even before hw is ready, but other
+                * events should be skipped during initialization. This may
+                * change for AllocEv if allocate_fid is implemented without
+                * busy waiting. */
+               if (!local->hw_ready || local->hw_resetting ||
+                   !local->dev_enabled) {
+                       ev = HFA384X_INW(HFA384X_EVSTAT_OFF);
+                       if (ev & HFA384X_EV_CMD)
+                               goto next_event;
+                       if ((ev & HFA384X_EVENT_MASK) == 0)
+                               return IRQ_HANDLED;
+                       if (local->dev_enabled && (ev & ~HFA384X_EV_TICK) &&
+                           net_ratelimit()) {
+                               printk(KERN_DEBUG "%s: prism2_interrupt: hw "
+                                      "not ready; skipping events 0x%04x "
+                                      "(IntEn=0x%04x)%s%s%s\n",
+                                      dev->name, ev,
+                                      HFA384X_INW(HFA384X_INTEN_OFF),
+                                      !local->hw_ready ? " (!hw_ready)" : "",
+                                      local->hw_resetting ?
+                                      " (hw_resetting)" : "",
+                                      !local->dev_enabled ?
+                                      " (!dev_enabled)" : "");
+                       }
+                       HFA384X_OUTW(ev, HFA384X_EVACK_OFF);
+                       return IRQ_HANDLED;
+               }
+
+               if (ev & HFA384X_EV_TICK) {
+                       prism2_ev_tick(dev);
+                       HFA384X_OUTW(HFA384X_EV_TICK, HFA384X_EVACK_OFF);
+               }
+
+               if (ev & HFA384X_EV_ALLOC) {
+                       prism2_alloc_ev(dev);
+                       HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF);
+               }
+
+               /* Reading data from the card is quite time consuming, so do it
+                * in tasklets. TX, TXEXC, RX, and INFO events will be ACKed
+                * and unmasked after needed data has been read completely. */
+               if (ev & HFA384X_BAP0_EVENTS) {
+                       hfa384x_events_no_bap0(dev);
+                       tasklet_schedule(&local->bap_tasklet);
+               }
+
+#ifndef final_version
+               if (ev & HFA384X_EV_WTERR) {
+                       PDEBUG(DEBUG_EXTRA, "%s: WTERR event\n", dev->name);
+                       HFA384X_OUTW(HFA384X_EV_WTERR, HFA384X_EVACK_OFF);
+               }
+#endif /* final_version */
+
+               if (ev & HFA384X_EV_INFDROP) {
+                       prism2_infdrop(dev);
+                       HFA384X_OUTW(HFA384X_EV_INFDROP, HFA384X_EVACK_OFF);
+               }
+
+       next_event:
+               events++;
+               if (events >= PRISM2_MAX_INTERRUPT_EVENTS) {
+                       PDEBUG(DEBUG_EXTRA, "prism2_interrupt: >%d events "
+                              "(EvStat=0x%04x)\n",
+                              PRISM2_MAX_INTERRUPT_EVENTS,
+                              HFA384X_INW(HFA384X_EVSTAT_OFF));
+                       break;
+               }
+       }
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 1);
+       return IRQ_RETVAL(events);
+}
+
+
+static void prism2_check_sta_fw_version(local_info_t *local)
+{
+       struct hfa384x_comp_ident comp;
+       int id, variant, major, minor;
+
+       if (hfa384x_get_rid(local->dev, HFA384X_RID_STAID,
+                           &comp, sizeof(comp), 1) < 0)
+               return;
+
+       local->fw_ap = 0;
+       id = le16_to_cpu(comp.id);
+       if (id != HFA384X_COMP_ID_STA) {
+               if (id == HFA384X_COMP_ID_FW_AP)
+                       local->fw_ap = 1;
+               return;
+       }
+
+       major = __le16_to_cpu(comp.major);
+       minor = __le16_to_cpu(comp.minor);
+       variant = __le16_to_cpu(comp.variant);
+       local->sta_fw_ver = PRISM2_FW_VER(major, minor, variant);
+
+       /* Station firmware versions before 1.4.x seem to have a bug in
+        * firmware-based WEP encryption when using Host AP mode, so use
+        * host_encrypt as a default for them. Firmware version 1.4.9 is the
+        * first one that has been seen to produce correct encryption, but the
+        * bug might be fixed before that (although, at least 1.4.2 is broken).
+        */
+       local->fw_encrypt_ok = local->sta_fw_ver >= PRISM2_FW_VER(1,4,9);
+
+       if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt &&
+           !local->fw_encrypt_ok) {
+               printk(KERN_DEBUG "%s: defaulting to host-based encryption as "
+                      "a workaround for firmware bug in Host AP mode WEP\n",
+                      local->dev->name);
+               local->host_encrypt = 1;
+       }
+
+       /* IEEE 802.11 standard compliant WDS frames (4 addresses) were broken
+        * in station firmware versions before 1.5.x. With these versions, the
+        * driver uses a workaround with bogus frame format (4th address after
+        * the payload). This is not compatible with other AP devices. Since
+        * the firmware bug is fixed in the latest station firmware versions,
+        * automatically enable standard compliant mode for cards using station
+        * firmware version 1.5.0 or newer. */
+       if (local->sta_fw_ver >= PRISM2_FW_VER(1,5,0))
+               local->wds_type |= HOSTAP_WDS_STANDARD_FRAME;
+       else {
+               printk(KERN_DEBUG "%s: defaulting to bogus WDS frame as a "
+                      "workaround for firmware bug in Host AP mode WDS\n",
+                      local->dev->name);
+       }
+
+       hostap_check_sta_fw_version(local->ap, local->sta_fw_ver);
+}
+
+
+static void prism2_crypt_deinit_entries(local_info_t *local, int force)
+{
+       struct list_head *ptr, *n;
+       struct ieee80211_crypt_data *entry;
+
+       for (ptr = local->crypt_deinit_list.next, n = ptr->next;
+            ptr != &local->crypt_deinit_list; ptr = n, n = ptr->next) {
+               entry = list_entry(ptr, struct ieee80211_crypt_data, list);
+
+               if (atomic_read(&entry->refcnt) != 0 && !force)
+                       continue;
+
+               list_del(ptr);
+
+               if (entry->ops)
+                       entry->ops->deinit(entry->priv);
+               kfree(entry);
+       }
+}
+
+
+static void prism2_crypt_deinit_handler(unsigned long data)
+{
+       local_info_t *local = (local_info_t *) data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&local->lock, flags);
+       prism2_crypt_deinit_entries(local, 0);
+       if (!list_empty(&local->crypt_deinit_list)) {
+               printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
+                      "deletion list\n", local->dev->name);
+               local->crypt_deinit_timer.expires = jiffies + HZ;
+               add_timer(&local->crypt_deinit_timer);
+       }
+       spin_unlock_irqrestore(&local->lock, flags);
+
+}
+
+
+static void hostap_passive_scan(unsigned long data)
+{
+       local_info_t *local = (local_info_t *) data;
+       struct net_device *dev = local->dev;
+       u16 channel;
+
+       if (local->passive_scan_interval <= 0)
+               return;
+
+       if (local->passive_scan_state == PASSIVE_SCAN_LISTEN) {
+               int max_tries = 16;
+
+               /* Even though host system does not really know when the WLAN
+                * MAC is sending frames, try to avoid changing channels for
+                * passive scanning when a host-generated frame is being
+                * transmitted */
+               if (test_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) {
+                       printk(KERN_DEBUG "%s: passive scan detected pending "
+                              "TX - delaying\n", dev->name);
+                       local->passive_scan_timer.expires = jiffies + HZ / 10;
+                       add_timer(&local->passive_scan_timer);
+                       return;
+               }
+
+               do {
+                       local->passive_scan_channel++;
+                       if (local->passive_scan_channel > 14)
+                               local->passive_scan_channel = 1;
+                       max_tries--;
+               } while (!(local->channel_mask &
+                          (1 << (local->passive_scan_channel - 1))) &&
+                        max_tries > 0);
+
+               if (max_tries == 0) {
+                       printk(KERN_INFO "%s: no allowed passive scan channels"
+                              " found\n", dev->name);
+                       return;
+               }
+
+               printk(KERN_DEBUG "%s: passive scan channel %d\n",
+                      dev->name, local->passive_scan_channel);
+               channel = local->passive_scan_channel;
+               local->passive_scan_state = PASSIVE_SCAN_WAIT;
+               local->passive_scan_timer.expires = jiffies + HZ / 10;
+       } else {
+               channel = local->channel;
+               local->passive_scan_state = PASSIVE_SCAN_LISTEN;
+               local->passive_scan_timer.expires = jiffies +
+                       local->passive_scan_interval * HZ;
+       }
+
+       if (hfa384x_cmd_callback(dev, HFA384X_CMDCODE_TEST |
+                                (HFA384X_TEST_CHANGE_CHANNEL << 8),
+                                channel, NULL, 0))
+               printk(KERN_ERR "%s: passive scan channel set %d "
+                      "failed\n", dev->name, channel);
+
+       add_timer(&local->passive_scan_timer);
+}
+
+
+/* Called only as a scheduled task when communications quality values should
+ * be updated. */
+static void handle_comms_qual_update(void *data)
+{
+       local_info_t *local = data;
+       prism2_update_comms_qual(local->dev);
+}
+
+
+/* Software watchdog - called as a timer. Hardware interrupt (Tick event) is
+ * used to monitor that local->last_tick_timer is being updated. If not,
+ * interrupt busy-loop is assumed and driver tries to recover by masking out
+ * some events. */
+static void hostap_tick_timer(unsigned long data)
+{
+       static unsigned long last_inquire = 0;
+       local_info_t *local = (local_info_t *) data;
+       local->last_tick_timer = jiffies;
+
+       /* Inquire CommTallies every 10 seconds to keep the statistics updated
+        * more often during low load and when using 32-bit tallies. */
+       if ((!last_inquire || time_after(jiffies, last_inquire + 10 * HZ)) &&
+           !local->hw_downloading && local->hw_ready &&
+           !local->hw_resetting && local->dev_enabled) {
+               hfa384x_cmd_callback(local->dev, HFA384X_CMDCODE_INQUIRE,
+                                    HFA384X_INFO_COMMTALLIES, NULL, 0);
+               last_inquire = jiffies;
+       }
+
+       if ((local->last_comms_qual_update == 0 ||
+            time_after(jiffies, local->last_comms_qual_update + 10 * HZ)) &&
+           (local->iw_mode == IW_MODE_INFRA ||
+            local->iw_mode == IW_MODE_ADHOC)) {
+               schedule_work(&local->comms_qual_update);
+       }
+
+       local->tick_timer.expires = jiffies + 2 * HZ;
+       add_timer(&local->tick_timer);
+}
+
+
+#ifndef PRISM2_NO_PROCFS_DEBUG
+static int prism2_registers_proc_read(char *page, char **start, off_t off,
+                                     int count, int *eof, void *data)
+{
+       char *p = page;
+       local_info_t *local = (local_info_t *) data;
+
+       if (off != 0) {
+               *eof = 1;
+               return 0;
+       }
+
+#define SHOW_REG(n) \
+p += sprintf(p, #n "=%04x\n", hfa384x_read_reg(local->dev, HFA384X_##n##_OFF))
+
+       SHOW_REG(CMD);
+       SHOW_REG(PARAM0);
+       SHOW_REG(PARAM1);
+       SHOW_REG(PARAM2);
+       SHOW_REG(STATUS);
+       SHOW_REG(RESP0);
+       SHOW_REG(RESP1);
+       SHOW_REG(RESP2);
+       SHOW_REG(INFOFID);
+       SHOW_REG(CONTROL);
+       SHOW_REG(SELECT0);
+       SHOW_REG(SELECT1);
+       SHOW_REG(OFFSET0);
+       SHOW_REG(OFFSET1);
+       SHOW_REG(RXFID);
+       SHOW_REG(ALLOCFID);
+       SHOW_REG(TXCOMPLFID);
+       SHOW_REG(SWSUPPORT0);
+       SHOW_REG(SWSUPPORT1);
+       SHOW_REG(SWSUPPORT2);
+       SHOW_REG(EVSTAT);
+       SHOW_REG(INTEN);
+       SHOW_REG(EVACK);
+       /* Do not read data registers, because they change the state of the
+        * MAC (offset += 2) */
+       /* SHOW_REG(DATA0); */
+       /* SHOW_REG(DATA1); */
+       SHOW_REG(AUXPAGE);
+       SHOW_REG(AUXOFFSET);
+       /* SHOW_REG(AUXDATA); */
+#ifdef PRISM2_PCI
+       SHOW_REG(PCICOR);
+       SHOW_REG(PCIHCR);
+       SHOW_REG(PCI_M0_ADDRH);
+       SHOW_REG(PCI_M0_ADDRL);
+       SHOW_REG(PCI_M0_LEN);
+       SHOW_REG(PCI_M0_CTL);
+       SHOW_REG(PCI_STATUS);
+       SHOW_REG(PCI_M1_ADDRH);
+       SHOW_REG(PCI_M1_ADDRL);
+       SHOW_REG(PCI_M1_LEN);
+       SHOW_REG(PCI_M1_CTL);
+#endif /* PRISM2_PCI */
+
+       return (p - page);
+}
+#endif /* PRISM2_NO_PROCFS_DEBUG */
+
+
+struct set_tim_data {
+       struct list_head list;
+       int aid;
+       int set;
+};
+
+static int prism2_set_tim(struct net_device *dev, int aid, int set)
+{
+       struct list_head *ptr;
+       struct set_tim_data *new_entry;
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       new_entry = (struct set_tim_data *)
+               kmalloc(sizeof(*new_entry), GFP_ATOMIC);
+       if (new_entry == NULL) {
+               printk(KERN_DEBUG "%s: prism2_set_tim: kmalloc failed\n",
+                      local->dev->name);
+               return -ENOMEM;
+       }
+       memset(new_entry, 0, sizeof(*new_entry));
+       new_entry->aid = aid;
+       new_entry->set = set;
+
+       spin_lock_bh(&local->set_tim_lock);
+       list_for_each(ptr, &local->set_tim_list) {
+               struct set_tim_data *entry =
+                       list_entry(ptr, struct set_tim_data, list);
+               if (entry->aid == aid) {
+                       PDEBUG(DEBUG_PS2, "%s: prism2_set_tim: aid=%d "
+                              "set=%d ==> %d\n",
+                              local->dev->name, aid, entry->set, set);
+                       entry->set = set;
+                       kfree(new_entry);
+                       new_entry = NULL;
+                       break;
+               }
+       }
+       if (new_entry)
+               list_add_tail(&new_entry->list, &local->set_tim_list);
+       spin_unlock_bh(&local->set_tim_lock);
+
+       schedule_work(&local->set_tim_queue);
+
+       return 0;
+}
+
+
+static void handle_set_tim_queue(void *data)
+{
+       local_info_t *local = (local_info_t *) data;
+       struct set_tim_data *entry;
+       u16 val;
+
+       for (;;) {
+               entry = NULL;
+               spin_lock_bh(&local->set_tim_lock);
+               if (!list_empty(&local->set_tim_list)) {
+                       entry = list_entry(local->set_tim_list.next,
+                                          struct set_tim_data, list);
+                       list_del(&entry->list);
+               }
+               spin_unlock_bh(&local->set_tim_lock);
+               if (!entry)
+                       break;
+
+               PDEBUG(DEBUG_PS2, "%s: handle_set_tim_queue: aid=%d set=%d\n",
+                      local->dev->name, entry->aid, entry->set);
+
+               val = entry->aid;
+               if (entry->set)
+                       val |= 0x8000;
+               if (hostap_set_word(local->dev, HFA384X_RID_CNFTIMCTRL, val)) {
+                       printk(KERN_DEBUG "%s: set_tim failed (aid=%d "
+                              "set=%d)\n",
+                              local->dev->name, entry->aid, entry->set);
+               }
+
+               kfree(entry);
+       }
+}
+
+
+static void prism2_clear_set_tim_queue(local_info_t *local)
+{
+       struct list_head *ptr, *n;
+
+       list_for_each_safe(ptr, n, &local->set_tim_list) {
+               struct set_tim_data *entry;
+               entry = list_entry(ptr, struct set_tim_data, list);
+               list_del(&entry->list);
+               kfree(entry);
+       }
+}
+
+
+static struct net_device *
+prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx,
+                      struct device *sdev)
+{
+       struct net_device *dev;
+       struct hostap_interface *iface;
+       struct local_info *local;
+       int len, i, ret;
+
+       if (funcs == NULL)
+               return NULL;
+
+       len = strlen(dev_template);
+       if (len >= IFNAMSIZ || strstr(dev_template, "%d") == NULL) {
+               printk(KERN_WARNING "hostap: Invalid dev_template='%s'\n",
+                      dev_template);
+               return NULL;
+       }
+
+       len = sizeof(struct hostap_interface) +
+               3 + sizeof(struct local_info) +
+               3 + sizeof(struct ap_data);
+
+       dev = alloc_etherdev(len);
+       if (dev == NULL)
+               return NULL;
+
+       iface = netdev_priv(dev);
+       local = (struct local_info *) ((((long) (iface + 1)) + 3) & ~3);
+       local->ap = (struct ap_data *) ((((long) (local + 1)) + 3) & ~3);
+       local->dev = iface->dev = dev;
+       iface->local = local;
+       iface->type = HOSTAP_INTERFACE_MASTER;
+       INIT_LIST_HEAD(&local->hostap_interfaces);
+
+       local->hw_module = THIS_MODULE;
+
+#ifdef PRISM2_IO_DEBUG
+       local->io_debug_enabled = 1;
+#endif /* PRISM2_IO_DEBUG */
+
+       local->func = funcs;
+       local->func->cmd = hfa384x_cmd;
+       local->func->read_regs = hfa384x_read_regs;
+       local->func->get_rid = hfa384x_get_rid;
+       local->func->set_rid = hfa384x_set_rid;
+       local->func->hw_enable = prism2_hw_enable;
+       local->func->hw_config = prism2_hw_config;
+       local->func->hw_reset = prism2_hw_reset;
+       local->func->hw_shutdown = prism2_hw_shutdown;
+       local->func->reset_port = prism2_reset_port;
+       local->func->schedule_reset = prism2_schedule_reset;
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+       local->func->read_aux = prism2_download_aux_dump;
+       local->func->download = prism2_download;
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+       local->func->tx = prism2_tx_80211;
+       local->func->set_tim = prism2_set_tim;
+       local->func->need_tx_headroom = 0; /* no need to add txdesc in
+                                           * skb->data (FIX: maybe for DMA bus
+                                           * mastering? */
+
+       local->mtu = mtu;
+
+       rwlock_init(&local->iface_lock);
+       spin_lock_init(&local->txfidlock);
+       spin_lock_init(&local->cmdlock);
+       spin_lock_init(&local->baplock);
+       spin_lock_init(&local->lock);
+       init_MUTEX(&local->rid_bap_sem);
+
+       if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES)
+               card_idx = 0;
+       local->card_idx = card_idx;
+
+       len = strlen(essid);
+       memcpy(local->essid, essid,
+              len > MAX_SSID_LEN ? MAX_SSID_LEN : len);
+       local->essid[MAX_SSID_LEN] = '\0';
+       i = GET_INT_PARM(iw_mode, card_idx);
+       if ((i >= IW_MODE_ADHOC && i <= IW_MODE_REPEAT) ||
+           i == IW_MODE_MONITOR) {
+               local->iw_mode = i;
+       } else {
+               printk(KERN_WARNING "prism2: Unknown iw_mode %d; using "
+                      "IW_MODE_MASTER\n", i);
+               local->iw_mode = IW_MODE_MASTER;
+       }
+       local->channel = GET_INT_PARM(channel, card_idx);
+       local->beacon_int = GET_INT_PARM(beacon_int, card_idx);
+       local->dtim_period = GET_INT_PARM(dtim_period, card_idx);
+       local->wds_max_connections = 16;
+       local->tx_control = HFA384X_TX_CTRL_FLAGS;
+       local->manual_retry_count = -1;
+       local->rts_threshold = 2347;
+       local->fragm_threshold = 2346;
+       local->rssi_to_dBm = 100; /* default; to be overriden by
+                                  * cnfDbmAdjust, if available */
+       local->auth_algs = PRISM2_AUTH_OPEN | PRISM2_AUTH_SHARED_KEY;
+       local->sram_type = -1;
+       local->scan_channel_mask = 0xffff;
+
+       /* Initialize task queue structures */
+       INIT_WORK(&local->reset_queue, handle_reset_queue, local);
+       INIT_WORK(&local->set_multicast_list_queue,
+                 hostap_set_multicast_list_queue, local->dev);
+
+       INIT_WORK(&local->set_tim_queue, handle_set_tim_queue, local);
+       INIT_LIST_HEAD(&local->set_tim_list);
+       spin_lock_init(&local->set_tim_lock);
+
+       INIT_WORK(&local->comms_qual_update, handle_comms_qual_update, local);
+
+       /* Initialize tasklets for handling hardware IRQ related operations
+        * outside hw IRQ handler */
+#define HOSTAP_TASKLET_INIT(q, f, d) \
+do { memset((q), 0, sizeof(*(q))); (q)->func = (f); (q)->data = (d); } \
+while (0)
+       HOSTAP_TASKLET_INIT(&local->bap_tasklet, hostap_bap_tasklet,
+                           (unsigned long) local);
+
+       HOSTAP_TASKLET_INIT(&local->info_tasklet, hostap_info_tasklet,
+                           (unsigned long) local);
+       hostap_info_init(local);
+
+       HOSTAP_TASKLET_INIT(&local->rx_tasklet,
+                           hostap_rx_tasklet, (unsigned long) local);
+       skb_queue_head_init(&local->rx_list);
+
+       HOSTAP_TASKLET_INIT(&local->sta_tx_exc_tasklet,
+                           hostap_sta_tx_exc_tasklet, (unsigned long) local);
+       skb_queue_head_init(&local->sta_tx_exc_list);
+
+       INIT_LIST_HEAD(&local->cmd_queue);
+       init_waitqueue_head(&local->hostscan_wq);
+       INIT_LIST_HEAD(&local->crypt_deinit_list);
+       init_timer(&local->crypt_deinit_timer);
+       local->crypt_deinit_timer.data = (unsigned long) local;
+       local->crypt_deinit_timer.function = prism2_crypt_deinit_handler;
+
+       init_timer(&local->passive_scan_timer);
+       local->passive_scan_timer.data = (unsigned long) local;
+       local->passive_scan_timer.function = hostap_passive_scan;
+
+       init_timer(&local->tick_timer);
+       local->tick_timer.data = (unsigned long) local;
+       local->tick_timer.function = hostap_tick_timer;
+       local->tick_timer.expires = jiffies + 2 * HZ;
+       add_timer(&local->tick_timer);
+
+       INIT_LIST_HEAD(&local->bss_list);
+
+       hostap_setup_dev(dev, local, 1);
+       local->saved_eth_header_parse = dev->hard_header_parse;
+
+       dev->hard_start_xmit = hostap_master_start_xmit;
+       dev->type = ARPHRD_IEEE80211;
+       dev->hard_header_parse = hostap_80211_header_parse;
+
+       rtnl_lock();
+       ret = dev_alloc_name(dev, "wifi%d");
+       SET_NETDEV_DEV(dev, sdev);
+       if (ret >= 0)
+               ret = register_netdevice(dev);
+       rtnl_unlock();
+       if (ret < 0) {
+               printk(KERN_WARNING "%s: register netdevice failed!\n",
+                      dev_info);
+               goto fail;
+       }
+       printk(KERN_INFO "%s: Registered netdevice %s\n", dev_info, dev->name);
+
+#ifndef PRISM2_NO_PROCFS_DEBUG
+       create_proc_read_entry("registers", 0, local->proc,
+                              prism2_registers_proc_read, local);
+#endif /* PRISM2_NO_PROCFS_DEBUG */
+
+       hostap_init_data(local);
+       return dev;
+
+ fail:
+       free_netdev(dev);
+       return NULL;
+}
+
+
+static int hostap_hw_ready(struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       struct local_info *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+       local->ddev = hostap_add_interface(local, HOSTAP_INTERFACE_MAIN, 0,
+                                          "", dev_template);
+
+       if (local->ddev) {
+               if (local->iw_mode == IW_MODE_INFRA ||
+                   local->iw_mode == IW_MODE_ADHOC) {
+                       netif_carrier_off(local->dev);
+                       netif_carrier_off(local->ddev);
+               }
+               hostap_init_proc(local);
+               hostap_init_ap_proc(local);
+               return 0;
+       }
+
+       return -1;
+}
+
+
+static void prism2_free_local_data(struct net_device *dev)
+{
+       struct hostap_tx_callback_info *tx_cb, *tx_cb_prev;
+       int i;
+       struct hostap_interface *iface;
+       struct local_info *local;
+       struct list_head *ptr, *n;
+
+       if (dev == NULL)
+               return;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       flush_scheduled_work();
+
+       if (timer_pending(&local->crypt_deinit_timer))
+               del_timer(&local->crypt_deinit_timer);
+       prism2_crypt_deinit_entries(local, 1);
+
+       if (timer_pending(&local->passive_scan_timer))
+               del_timer(&local->passive_scan_timer);
+
+       if (timer_pending(&local->tick_timer))
+               del_timer(&local->tick_timer);
+
+       prism2_clear_cmd_queue(local);
+
+       skb_queue_purge(&local->info_list);
+       skb_queue_purge(&local->rx_list);
+       skb_queue_purge(&local->sta_tx_exc_list);
+
+       if (local->dev_enabled)
+               prism2_callback(local, PRISM2_CALLBACK_DISABLE);
+
+       for (i = 0; i < WEP_KEYS; i++) {
+               struct ieee80211_crypt_data *crypt = local->crypt[i];
+               if (crypt) {
+                       if (crypt->ops)
+                               crypt->ops->deinit(crypt->priv);
+                       kfree(crypt);
+                       local->crypt[i] = NULL;
+               }
+       }
+
+       if (local->ap != NULL)
+               hostap_free_data(local->ap);
+
+#ifndef PRISM2_NO_PROCFS_DEBUG
+       if (local->proc != NULL)
+               remove_proc_entry("registers", local->proc);
+#endif /* PRISM2_NO_PROCFS_DEBUG */
+       hostap_remove_proc(local);
+
+       tx_cb = local->tx_callback;
+       while (tx_cb != NULL) {
+               tx_cb_prev = tx_cb;
+               tx_cb = tx_cb->next;
+               kfree(tx_cb_prev);
+       }
+
+       hostap_set_hostapd(local, 0, 0);
+       hostap_set_hostapd_sta(local, 0, 0);
+
+       for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) {
+               if (local->frag_cache[i].skb != NULL)
+                       dev_kfree_skb(local->frag_cache[i].skb);
+       }
+
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+       prism2_download_free_data(local->dl_pri);
+       prism2_download_free_data(local->dl_sec);
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+
+       list_for_each_safe(ptr, n, &local->hostap_interfaces) {
+               iface = list_entry(ptr, struct hostap_interface, list);
+               if (iface->type == HOSTAP_INTERFACE_MASTER) {
+                       /* special handling for this interface below */
+                       continue;
+               }
+               hostap_remove_interface(iface->dev, 0, 1);
+       }
+
+       prism2_clear_set_tim_queue(local);
+
+       list_for_each_safe(ptr, n, &local->bss_list) {
+               struct hostap_bss_info *bss =
+                       list_entry(ptr, struct hostap_bss_info, list);
+               kfree(bss);
+       }
+
+       kfree(local->pda);
+       kfree(local->last_scan_results);
+       kfree(local->generic_elem);
+
+       unregister_netdev(local->dev);
+       free_netdev(local->dev);
+}
+
+
+#ifndef PRISM2_PLX
+static void prism2_suspend(struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       struct local_info *local;
+       union iwreq_data wrqu;
+
+       iface = dev->priv;
+       local = iface->local;
+
+       /* Send disconnect event, e.g., to trigger reassociation after resume
+        * if wpa_supplicant is used. */
+       memset(&wrqu, 0, sizeof(wrqu));
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+       wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL);
+
+       /* Disable hardware and firmware */
+       prism2_hw_shutdown(dev, 0);
+}
+#endif /* PRISM2_PLX */
+
+
+/* These might at some point be compiled separately and used as separate
+ * kernel modules or linked into one */
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+#include "hostap_download.c"
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+
+#ifdef PRISM2_CALLBACK
+/* External hostap_callback.c file can be used to, e.g., blink activity led.
+ * This can use platform specific code and must define prism2_callback()
+ * function (if PRISM2_CALLBACK is not defined, these function calls are not
+ * used. */
+#include "hostap_callback.c"
+#endif /* PRISM2_CALLBACK */
diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c
new file mode 100644 (file)
index 0000000..5aa998f
--- /dev/null
@@ -0,0 +1,499 @@
+/* Host AP driver Info Frame processing (part of hostap.o module) */
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_info_commtallies16(local_info_t *local, unsigned char *buf,
+                                     int left)
+{
+       struct hfa384x_comm_tallies *tallies;
+
+       if (left < sizeof(struct hfa384x_comm_tallies)) {
+               printk(KERN_DEBUG "%s: too short (len=%d) commtallies "
+                      "info frame\n", local->dev->name, left);
+               return;
+       }
+
+       tallies = (struct hfa384x_comm_tallies *) buf;
+#define ADD_COMM_TALLIES(name) \
+local->comm_tallies.name += le16_to_cpu(tallies->name)
+       ADD_COMM_TALLIES(tx_unicast_frames);
+       ADD_COMM_TALLIES(tx_multicast_frames);
+       ADD_COMM_TALLIES(tx_fragments);
+       ADD_COMM_TALLIES(tx_unicast_octets);
+       ADD_COMM_TALLIES(tx_multicast_octets);
+       ADD_COMM_TALLIES(tx_deferred_transmissions);
+       ADD_COMM_TALLIES(tx_single_retry_frames);
+       ADD_COMM_TALLIES(tx_multiple_retry_frames);
+       ADD_COMM_TALLIES(tx_retry_limit_exceeded);
+       ADD_COMM_TALLIES(tx_discards);
+       ADD_COMM_TALLIES(rx_unicast_frames);
+       ADD_COMM_TALLIES(rx_multicast_frames);
+       ADD_COMM_TALLIES(rx_fragments);
+       ADD_COMM_TALLIES(rx_unicast_octets);
+       ADD_COMM_TALLIES(rx_multicast_octets);
+       ADD_COMM_TALLIES(rx_fcs_errors);
+       ADD_COMM_TALLIES(rx_discards_no_buffer);
+       ADD_COMM_TALLIES(tx_discards_wrong_sa);
+       ADD_COMM_TALLIES(rx_discards_wep_undecryptable);
+       ADD_COMM_TALLIES(rx_message_in_msg_fragments);
+       ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments);
+#undef ADD_COMM_TALLIES
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_info_commtallies32(local_info_t *local, unsigned char *buf,
+                                     int left)
+{
+       struct hfa384x_comm_tallies32 *tallies;
+
+       if (left < sizeof(struct hfa384x_comm_tallies32)) {
+               printk(KERN_DEBUG "%s: too short (len=%d) commtallies32 "
+                      "info frame\n", local->dev->name, left);
+               return;
+       }
+
+       tallies = (struct hfa384x_comm_tallies32 *) buf;
+#define ADD_COMM_TALLIES(name) \
+local->comm_tallies.name += le32_to_cpu(tallies->name)
+       ADD_COMM_TALLIES(tx_unicast_frames);
+       ADD_COMM_TALLIES(tx_multicast_frames);
+       ADD_COMM_TALLIES(tx_fragments);
+       ADD_COMM_TALLIES(tx_unicast_octets);
+       ADD_COMM_TALLIES(tx_multicast_octets);
+       ADD_COMM_TALLIES(tx_deferred_transmissions);
+       ADD_COMM_TALLIES(tx_single_retry_frames);
+       ADD_COMM_TALLIES(tx_multiple_retry_frames);
+       ADD_COMM_TALLIES(tx_retry_limit_exceeded);
+       ADD_COMM_TALLIES(tx_discards);
+       ADD_COMM_TALLIES(rx_unicast_frames);
+       ADD_COMM_TALLIES(rx_multicast_frames);
+       ADD_COMM_TALLIES(rx_fragments);
+       ADD_COMM_TALLIES(rx_unicast_octets);
+       ADD_COMM_TALLIES(rx_multicast_octets);
+       ADD_COMM_TALLIES(rx_fcs_errors);
+       ADD_COMM_TALLIES(rx_discards_no_buffer);
+       ADD_COMM_TALLIES(tx_discards_wrong_sa);
+       ADD_COMM_TALLIES(rx_discards_wep_undecryptable);
+       ADD_COMM_TALLIES(rx_message_in_msg_fragments);
+       ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments);
+#undef ADD_COMM_TALLIES
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_info_commtallies(local_info_t *local, unsigned char *buf,
+                                   int left)
+{
+       if (local->tallies32)
+               prism2_info_commtallies32(local, buf, left);
+       else
+               prism2_info_commtallies16(local, buf, left);
+}
+
+
+#ifndef PRISM2_NO_STATION_MODES
+#ifndef PRISM2_NO_DEBUG
+static const char* hfa384x_linkstatus_str(u16 linkstatus)
+{
+       switch (linkstatus) {
+       case HFA384X_LINKSTATUS_CONNECTED:
+               return "Connected";
+       case HFA384X_LINKSTATUS_DISCONNECTED:
+               return "Disconnected";
+       case HFA384X_LINKSTATUS_AP_CHANGE:
+               return "Access point change";
+       case HFA384X_LINKSTATUS_AP_OUT_OF_RANGE:
+               return "Access point out of range";
+       case HFA384X_LINKSTATUS_AP_IN_RANGE:
+               return "Access point in range";
+       case HFA384X_LINKSTATUS_ASSOC_FAILED:
+               return "Association failed";
+       default:
+               return "Unknown";
+       }
+}
+#endif /* PRISM2_NO_DEBUG */
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_info_linkstatus(local_info_t *local, unsigned char *buf,
+                                   int left)
+{
+       u16 val;
+       int non_sta_mode;
+
+       /* Alloc new JoinRequests to occur since LinkStatus for the previous
+        * has been received */
+       local->last_join_time = 0;
+
+       if (left != 2) {
+               printk(KERN_DEBUG "%s: invalid linkstatus info frame "
+                      "length %d\n", local->dev->name, left);
+               return;
+       }
+
+       non_sta_mode = local->iw_mode == IW_MODE_MASTER ||
+               local->iw_mode == IW_MODE_REPEAT ||
+               local->iw_mode == IW_MODE_MONITOR;
+
+       val = buf[0] | (buf[1] << 8);
+       if (!non_sta_mode || val != HFA384X_LINKSTATUS_DISCONNECTED) {
+               PDEBUG(DEBUG_EXTRA, "%s: LinkStatus=%d (%s)\n",
+                      local->dev->name, val, hfa384x_linkstatus_str(val));
+       }
+
+       if (non_sta_mode) {
+               netif_carrier_on(local->dev);
+               netif_carrier_on(local->ddev);
+               return;
+       }
+
+       /* Get current BSSID later in scheduled task */
+       set_bit(PRISM2_INFO_PENDING_LINKSTATUS, &local->pending_info);
+       local->prev_link_status = val;
+       schedule_work(&local->info_queue);
+}
+
+
+static void prism2_host_roaming(local_info_t *local)
+{
+       struct hfa384x_join_request req;
+       struct net_device *dev = local->dev;
+       struct hfa384x_hostscan_result *selected, *entry;
+       int i;
+       unsigned long flags;
+
+       if (local->last_join_time &&
+           time_before(jiffies, local->last_join_time + 10 * HZ)) {
+               PDEBUG(DEBUG_EXTRA, "%s: last join request has not yet been "
+                      "completed - waiting for it before issuing new one\n",
+                      dev->name);
+               return;
+       }
+
+       /* ScanResults are sorted: first ESS results in decreasing signal
+        * quality then IBSS results in similar order.
+        * Trivial roaming policy: just select the first entry.
+        * This could probably be improved by adding hysteresis to limit
+        * number of handoffs, etc.
+        *
+        * Could do periodic RID_SCANREQUEST or Inquire F101 to get new
+        * ScanResults */
+       spin_lock_irqsave(&local->lock, flags);
+       if (local->last_scan_results == NULL ||
+           local->last_scan_results_count == 0) {
+               spin_unlock_irqrestore(&local->lock, flags);
+               PDEBUG(DEBUG_EXTRA, "%s: no scan results for host roaming\n",
+                      dev->name);
+               return;
+       }
+
+       selected = &local->last_scan_results[0];
+
+       if (local->preferred_ap[0] || local->preferred_ap[1] ||
+           local->preferred_ap[2] || local->preferred_ap[3] ||
+           local->preferred_ap[4] || local->preferred_ap[5]) {
+               /* Try to find preferred AP */
+               PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID " MACSTR "\n",
+                      dev->name, MAC2STR(local->preferred_ap));
+               for (i = 0; i < local->last_scan_results_count; i++) {
+                       entry = &local->last_scan_results[i];
+                       if (memcmp(local->preferred_ap, entry->bssid, 6) == 0)
+                       {
+                               PDEBUG(DEBUG_EXTRA, "%s: using preferred AP "
+                                      "selection\n", dev->name);
+                               selected = entry;
+                               break;
+                       }
+               }
+       }
+
+       memcpy(req.bssid, selected->bssid, 6);
+       req.channel = selected->chid;
+       spin_unlock_irqrestore(&local->lock, flags);
+
+       PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=" MACSTR " channel=%d\n",
+              dev->name, MAC2STR(req.bssid), le16_to_cpu(req.channel));
+       if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
+                                sizeof(req))) {
+               printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name);
+       }
+       local->last_join_time = jiffies;
+}
+
+
+static void hostap_report_scan_complete(local_info_t *local)
+{
+       union iwreq_data wrqu;
+
+       /* Inform user space about new scan results (just empty event,
+        * SIOCGIWSCAN can be used to fetch data */
+       wrqu.data.length = 0;
+       wrqu.data.flags = 0;
+       wireless_send_event(local->dev, SIOCGIWSCAN, &wrqu, NULL);
+
+       /* Allow SIOCGIWSCAN handling to occur since we have received
+        * scanning result */
+       local->scan_timestamp = 0;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_info_scanresults(local_info_t *local, unsigned char *buf,
+                                   int left)
+{
+       u16 *pos;
+       int new_count, i;
+       unsigned long flags;
+       struct hfa384x_scan_result *res;
+       struct hfa384x_hostscan_result *results, *prev;
+
+       if (left < 4) {
+               printk(KERN_DEBUG "%s: invalid scanresult info frame "
+                      "length %d\n", local->dev->name, left);
+               return;
+       }
+
+       pos = (u16 *) buf;
+       pos++;
+       pos++;
+       left -= 4;
+
+       new_count = left / sizeof(struct hfa384x_scan_result);
+       results = kmalloc(new_count * sizeof(struct hfa384x_hostscan_result),
+                         GFP_ATOMIC);
+       if (results == NULL)
+               return;
+
+       /* Convert to hostscan result format. */
+       res = (struct hfa384x_scan_result *) pos;
+       for (i = 0; i < new_count; i++) {
+               memcpy(&results[i], &res[i],
+                      sizeof(struct hfa384x_scan_result));
+               results[i].atim = 0;
+       }
+
+       spin_lock_irqsave(&local->lock, flags);
+       local->last_scan_type = PRISM2_SCAN;
+       prev = local->last_scan_results;
+       local->last_scan_results = results;
+       local->last_scan_results_count = new_count;
+       spin_unlock_irqrestore(&local->lock, flags);
+       kfree(prev);
+
+       hostap_report_scan_complete(local);
+
+       /* Perform rest of ScanResults handling later in scheduled task */
+       set_bit(PRISM2_INFO_PENDING_SCANRESULTS, &local->pending_info);
+       schedule_work(&local->info_queue);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_info_hostscanresults(local_info_t *local,
+                                       unsigned char *buf, int left)
+{
+       int i, result_size, copy_len, new_count;
+       struct hfa384x_hostscan_result *results, *prev;
+       unsigned long flags;
+       u16 *pos;
+       u8 *ptr;
+
+       wake_up_interruptible(&local->hostscan_wq);
+
+       if (left < 4) {
+               printk(KERN_DEBUG "%s: invalid hostscanresult info frame "
+                      "length %d\n", local->dev->name, left);
+               return;
+       }
+
+       pos = (u16 *) buf;
+       copy_len = result_size = le16_to_cpu(*pos);
+       if (result_size == 0) {
+               printk(KERN_DEBUG "%s: invalid result_size (0) in "
+                      "hostscanresults\n", local->dev->name);
+               return;
+       }
+       if (copy_len > sizeof(struct hfa384x_hostscan_result))
+               copy_len = sizeof(struct hfa384x_hostscan_result);
+
+       pos++;
+       pos++;
+       left -= 4;
+       ptr = (u8 *) pos;
+
+       new_count = left / result_size;
+       results = kmalloc(new_count * sizeof(struct hfa384x_hostscan_result),
+                         GFP_ATOMIC);
+       if (results == NULL)
+               return;
+       memset(results, 0, new_count * sizeof(struct hfa384x_hostscan_result));
+
+       for (i = 0; i < new_count; i++) {
+               memcpy(&results[i], ptr, copy_len);
+               ptr += result_size;
+               left -= result_size;
+       }
+
+       if (left) {
+               printk(KERN_DEBUG "%s: short HostScan result entry (%d/%d)\n",
+                      local->dev->name, left, result_size);
+       }
+
+       spin_lock_irqsave(&local->lock, flags);
+       local->last_scan_type = PRISM2_HOSTSCAN;
+       prev = local->last_scan_results;
+       local->last_scan_results = results;
+       local->last_scan_results_count = new_count;
+       spin_unlock_irqrestore(&local->lock, flags);
+       kfree(prev);
+
+       hostap_report_scan_complete(local);
+}
+#endif /* PRISM2_NO_STATION_MODES */
+
+
+/* Called only as a tasklet (software IRQ) */
+void hostap_info_process(local_info_t *local, struct sk_buff *skb)
+{
+       struct hfa384x_info_frame *info;
+       unsigned char *buf;
+       int left;
+#ifndef PRISM2_NO_DEBUG
+       int i;
+#endif /* PRISM2_NO_DEBUG */
+
+       info = (struct hfa384x_info_frame *) skb->data;
+       buf = skb->data + sizeof(*info);
+       left = skb->len - sizeof(*info);
+
+       switch (info->type) {
+       case HFA384X_INFO_COMMTALLIES:
+               prism2_info_commtallies(local, buf, left);
+               break;
+
+#ifndef PRISM2_NO_STATION_MODES
+       case HFA384X_INFO_LINKSTATUS:
+               prism2_info_linkstatus(local, buf, left);
+               break;
+
+       case HFA384X_INFO_SCANRESULTS:
+               prism2_info_scanresults(local, buf, left);
+               break;
+
+       case HFA384X_INFO_HOSTSCANRESULTS:
+               prism2_info_hostscanresults(local, buf, left);
+               break;
+#endif /* PRISM2_NO_STATION_MODES */
+
+#ifndef PRISM2_NO_DEBUG
+       default:
+               PDEBUG(DEBUG_EXTRA, "%s: INFO - len=%d type=0x%04x\n",
+                      local->dev->name, info->len, info->type);
+               PDEBUG(DEBUG_EXTRA, "Unknown info frame:");
+               for (i = 0; i < (left < 100 ? left : 100); i++)
+                       PDEBUG2(DEBUG_EXTRA, " %02x", buf[i]);
+               PDEBUG2(DEBUG_EXTRA, "\n");
+               break;
+#endif /* PRISM2_NO_DEBUG */
+       }
+}
+
+
+#ifndef PRISM2_NO_STATION_MODES
+static void handle_info_queue_linkstatus(local_info_t *local)
+{
+       int val = local->prev_link_status;
+       int connected;
+       union iwreq_data wrqu;
+
+       connected =
+               val == HFA384X_LINKSTATUS_CONNECTED ||
+               val == HFA384X_LINKSTATUS_AP_CHANGE ||
+               val == HFA384X_LINKSTATUS_AP_IN_RANGE;
+
+       if (local->func->get_rid(local->dev, HFA384X_RID_CURRENTBSSID,
+                                local->bssid, ETH_ALEN, 1) < 0) {
+               printk(KERN_DEBUG "%s: could not read CURRENTBSSID after "
+                      "LinkStatus event\n", local->dev->name);
+       } else {
+               PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=" MACSTR "\n",
+                      local->dev->name,
+                      MAC2STR((unsigned char *) local->bssid));
+               if (local->wds_type & HOSTAP_WDS_AP_CLIENT)
+                       hostap_add_sta(local->ap, local->bssid);
+       }
+
+       /* Get BSSID if we have a valid AP address */
+       if (connected) {
+               netif_carrier_on(local->dev);
+               netif_carrier_on(local->ddev);
+               memcpy(wrqu.ap_addr.sa_data, local->bssid, ETH_ALEN);
+       } else {
+               netif_carrier_off(local->dev);
+               netif_carrier_off(local->ddev);
+               memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+       }
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+       /*
+        * Filter out sequential disconnect events in order not to cause a
+        * flood of SIOCGIWAP events that have a race condition with EAPOL
+        * frames and can confuse wpa_supplicant about the current association
+        * status.
+        */
+       if (connected || local->prev_linkstatus_connected)
+               wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL);
+       local->prev_linkstatus_connected = connected;
+}
+
+
+static void handle_info_queue_scanresults(local_info_t *local)
+{
+       if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA)
+               prism2_host_roaming(local);
+
+       if (local->host_roaming == 2 && local->iw_mode == IW_MODE_INFRA &&
+           memcmp(local->preferred_ap, "\x00\x00\x00\x00\x00\x00",
+                  ETH_ALEN) != 0) {
+               /*
+                * Firmware seems to be getting into odd state in host_roaming
+                * mode 2 when hostscan is used without join command, so try
+                * to fix this by re-joining the current AP. This does not
+                * actually trigger a new association if the current AP is
+                * still in the scan results.
+                */
+               prism2_host_roaming(local);
+       }
+}
+
+
+/* Called only as scheduled task after receiving info frames (used to avoid
+ * pending too much time in HW IRQ handler). */
+static void handle_info_queue(void *data)
+{
+       local_info_t *local = (local_info_t *) data;
+
+       if (test_and_clear_bit(PRISM2_INFO_PENDING_LINKSTATUS,
+                              &local->pending_info))
+               handle_info_queue_linkstatus(local);
+
+       if (test_and_clear_bit(PRISM2_INFO_PENDING_SCANRESULTS,
+                              &local->pending_info))
+               handle_info_queue_scanresults(local);
+}
+#endif /* PRISM2_NO_STATION_MODES */
+
+
+void hostap_info_init(local_info_t *local)
+{
+       skb_queue_head_init(&local->info_list);
+#ifndef PRISM2_NO_STATION_MODES
+       INIT_WORK(&local->info_queue, handle_info_queue, local);
+#endif /* PRISM2_NO_STATION_MODES */
+}
+
+
+EXPORT_SYMBOL(hostap_info_init);
+EXPORT_SYMBOL(hostap_info_process);
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
new file mode 100644 (file)
index 0000000..e720369
--- /dev/null
@@ -0,0 +1,4102 @@
+/* ioctl() (mostly Linux Wireless Extensions) routines for Host AP driver */
+
+#ifdef in_atomic
+/* Get kernel_locked() for in_atomic() */
+#include <linux/smp_lock.h>
+#endif
+#include <linux/ethtool.h>
+
+
+static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       struct iw_statistics *wstats;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       /* Why are we doing that ? Jean II */
+       if (iface->type != HOSTAP_INTERFACE_MAIN)
+               return NULL;
+
+       wstats = &local->wstats;
+
+       wstats->status = 0;
+       wstats->discard.code =
+               local->comm_tallies.rx_discards_wep_undecryptable;
+       wstats->discard.misc =
+               local->comm_tallies.rx_fcs_errors +
+               local->comm_tallies.rx_discards_no_buffer +
+               local->comm_tallies.tx_discards_wrong_sa;
+
+       wstats->discard.retries =
+               local->comm_tallies.tx_retry_limit_exceeded;
+       wstats->discard.fragment =
+               local->comm_tallies.rx_message_in_bad_msg_fragments;
+
+       if (local->iw_mode != IW_MODE_MASTER &&
+           local->iw_mode != IW_MODE_REPEAT) {
+               int update = 1;
+#ifdef in_atomic
+               /* RID reading might sleep and it must not be called in
+                * interrupt context or while atomic. However, this
+                * function seems to be called while atomic (at least in Linux
+                * 2.5.59). Update signal quality values only if in suitable
+                * context. Otherwise, previous values read from tick timer
+                * will be used. */
+               if (in_atomic())
+                       update = 0;
+#endif /* in_atomic */
+
+               if (update && prism2_update_comms_qual(dev) == 0)
+                       wstats->qual.updated = 7;
+
+               wstats->qual.qual = local->comms_qual;
+               wstats->qual.level = local->avg_signal;
+               wstats->qual.noise = local->avg_noise;
+       } else {
+               wstats->qual.qual = 0;
+               wstats->qual.level = 0;
+               wstats->qual.noise = 0;
+               wstats->qual.updated = 0;
+       }
+
+       return wstats;
+}
+
+
+static int prism2_get_datarates(struct net_device *dev, u8 *rates)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       u8 buf[12];
+       int len;
+       u16 val;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       len = local->func->get_rid(dev, HFA384X_RID_SUPPORTEDDATARATES, buf,
+                                  sizeof(buf), 0);
+       if (len < 2)
+               return 0;
+
+       val = le16_to_cpu(*(u16 *) buf); /* string length */
+
+       if (len - 2 < val || val > 10)
+               return 0;
+
+       memcpy(rates, buf + 2, val);
+       return val;
+}
+
+
+static int prism2_get_name(struct net_device *dev,
+                          struct iw_request_info *info,
+                          char *name, char *extra)
+{
+       u8 rates[10];
+       int len, i, over2 = 0;
+
+       len = prism2_get_datarates(dev, rates);
+
+       for (i = 0; i < len; i++) {
+               if (rates[i] == 0x0b || rates[i] == 0x16) {
+                       over2 = 1;
+                       break;
+               }
+       }
+
+       strcpy(name, over2 ? "IEEE 802.11b" : "IEEE 802.11-DS");
+
+       return 0;
+}
+
+
+static void prism2_crypt_delayed_deinit(local_info_t *local,
+                                       struct ieee80211_crypt_data **crypt)
+{
+       struct ieee80211_crypt_data *tmp;
+       unsigned long flags;
+
+       tmp = *crypt;
+       *crypt = NULL;
+
+       if (tmp == NULL)
+               return;
+
+       /* must not run ops->deinit() while there may be pending encrypt or
+        * decrypt operations. Use a list of delayed deinits to avoid needing
+        * locking. */
+
+       spin_lock_irqsave(&local->lock, flags);
+       list_add(&tmp->list, &local->crypt_deinit_list);
+       if (!timer_pending(&local->crypt_deinit_timer)) {
+               local->crypt_deinit_timer.expires = jiffies + HZ;
+               add_timer(&local->crypt_deinit_timer);
+       }
+       spin_unlock_irqrestore(&local->lock, flags);
+}
+
+
+static int prism2_ioctl_siwencode(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_point *erq, char *keybuf)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int i;
+       struct ieee80211_crypt_data **crypt;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       i = erq->flags & IW_ENCODE_INDEX;
+       if (i < 1 || i > 4)
+               i = local->tx_keyidx;
+       else
+               i--;
+       if (i < 0 || i >= WEP_KEYS)
+               return -EINVAL;
+
+       crypt = &local->crypt[i];
+
+       if (erq->flags & IW_ENCODE_DISABLED) {
+               if (*crypt)
+                       prism2_crypt_delayed_deinit(local, crypt);
+               goto done;
+       }
+
+       if (*crypt != NULL && (*crypt)->ops != NULL &&
+           strcmp((*crypt)->ops->name, "WEP") != 0) {
+               /* changing to use WEP; deinit previously used algorithm */
+               prism2_crypt_delayed_deinit(local, crypt);
+       }
+
+       if (*crypt == NULL) {
+               struct ieee80211_crypt_data *new_crypt;
+
+               /* take WEP into use */
+               new_crypt = (struct ieee80211_crypt_data *)
+                       kmalloc(sizeof(struct ieee80211_crypt_data),
+                               GFP_KERNEL);
+               if (new_crypt == NULL)
+                       return -ENOMEM;
+               memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
+               new_crypt->ops = ieee80211_get_crypto_ops("WEP");
+               if (!new_crypt->ops) {
+                       request_module("ieee80211_crypt_wep");
+                       new_crypt->ops = ieee80211_get_crypto_ops("WEP");
+               }
+               if (new_crypt->ops)
+                       new_crypt->priv = new_crypt->ops->init(i);
+               if (!new_crypt->ops || !new_crypt->priv) {
+                       kfree(new_crypt);
+                       new_crypt = NULL;
+
+                       printk(KERN_WARNING "%s: could not initialize WEP: "
+                              "load module hostap_crypt_wep.o\n",
+                              dev->name);
+                       return -EOPNOTSUPP;
+               }
+               *crypt = new_crypt;
+       }
+
+       if (erq->length > 0) {
+               int len = erq->length <= 5 ? 5 : 13;
+               int first = 1, j;
+               if (len > erq->length)
+                       memset(keybuf + erq->length, 0, len - erq->length);
+               (*crypt)->ops->set_key(keybuf, len, NULL, (*crypt)->priv);
+               for (j = 0; j < WEP_KEYS; j++) {
+                       if (j != i && local->crypt[j]) {
+                               first = 0;
+                               break;
+                       }
+               }
+               if (first)
+                       local->tx_keyidx = i;
+       } else {
+               /* No key data - just set the default TX key index */
+               local->tx_keyidx = i;
+       }
+
+ done:
+       local->open_wep = erq->flags & IW_ENCODE_OPEN;
+
+       if (hostap_set_encryption(local)) {
+               printk(KERN_DEBUG "%s: set_encryption failed\n", dev->name);
+               return -EINVAL;
+       }
+
+       /* Do not reset port0 if card is in Managed mode since resetting will
+        * generate new IEEE 802.11 authentication which may end up in looping
+        * with IEEE 802.1X. Prism2 documentation seem to require port reset
+        * after WEP configuration. However, keys are apparently changed at
+        * least in Managed mode. */
+       if (local->iw_mode != IW_MODE_INFRA && local->func->reset_port(dev)) {
+               printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
+static int prism2_ioctl_giwencode(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_point *erq, char *key)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int i, len;
+       u16 val;
+       struct ieee80211_crypt_data *crypt;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       i = erq->flags & IW_ENCODE_INDEX;
+       if (i < 1 || i > 4)
+               i = local->tx_keyidx;
+       else
+               i--;
+       if (i < 0 || i >= WEP_KEYS)
+               return -EINVAL;
+
+       crypt = local->crypt[i];
+       erq->flags = i + 1;
+
+       if (crypt == NULL || crypt->ops == NULL) {
+               erq->length = 0;
+               erq->flags |= IW_ENCODE_DISABLED;
+               return 0;
+       }
+
+       if (strcmp(crypt->ops->name, "WEP") != 0) {
+               /* only WEP is supported with wireless extensions, so just
+                * report that encryption is used */
+               erq->length = 0;
+               erq->flags |= IW_ENCODE_ENABLED;
+               return 0;
+       }
+
+       /* Reads from HFA384X_RID_CNFDEFAULTKEY* return bogus values, so show
+        * the keys from driver buffer */
+       len = crypt->ops->get_key(key, WEP_KEY_LEN, NULL, crypt->priv);
+       erq->length = (len >= 0 ? len : 0);
+
+       if (local->func->get_rid(dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, 1) < 0)
+       {
+               printk("CNFWEPFLAGS reading failed\n");
+               return -EOPNOTSUPP;
+       }
+       le16_to_cpus(&val);
+       if (val & HFA384X_WEPFLAGS_PRIVACYINVOKED)
+               erq->flags |= IW_ENCODE_ENABLED;
+       else
+               erq->flags |= IW_ENCODE_DISABLED;
+       if (val & HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED)
+               erq->flags |= IW_ENCODE_RESTRICTED;
+       else
+               erq->flags |= IW_ENCODE_OPEN;
+
+       return 0;
+}
+
+
+static int hostap_set_rate(struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int ret, basic_rates;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       basic_rates = local->basic_rates & local->tx_rate_control;
+       if (!basic_rates || basic_rates != local->basic_rates) {
+               printk(KERN_INFO "%s: updating basic rate set automatically "
+                      "to match with the new supported rate set\n",
+                      dev->name);
+               if (!basic_rates)
+                       basic_rates = local->tx_rate_control;
+
+               local->basic_rates = basic_rates;
+               if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES,
+                                   basic_rates))
+                       printk(KERN_WARNING "%s: failed to set "
+                              "cnfBasicRates\n", dev->name);
+       }
+
+       ret = (hostap_set_word(dev, HFA384X_RID_TXRATECONTROL,
+                              local->tx_rate_control) ||
+              hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES,
+                              local->tx_rate_control) ||
+              local->func->reset_port(dev));
+
+       if (ret) {
+               printk(KERN_WARNING "%s: TXRateControl/cnfSupportedRates "
+                      "setting to 0x%x failed\n",
+                      dev->name, local->tx_rate_control);
+       }
+
+       /* Update TX rate configuration for all STAs based on new operational
+        * rate set. */
+       hostap_update_rates(local);
+
+       return ret;
+}
+
+
+static int prism2_ioctl_siwrate(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_param *rrq, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (rrq->fixed) {
+               switch (rrq->value) {
+               case 11000000:
+                       local->tx_rate_control = HFA384X_RATES_11MBPS;
+                       break;
+               case 5500000:
+                       local->tx_rate_control = HFA384X_RATES_5MBPS;
+                       break;
+               case 2000000:
+                       local->tx_rate_control = HFA384X_RATES_2MBPS;
+                       break;
+               case 1000000:
+                       local->tx_rate_control = HFA384X_RATES_1MBPS;
+                       break;
+               default:
+                       local->tx_rate_control = HFA384X_RATES_1MBPS |
+                               HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS |
+                               HFA384X_RATES_11MBPS;
+                       break;
+               }
+       } else {
+               switch (rrq->value) {
+               case 11000000:
+                       local->tx_rate_control = HFA384X_RATES_1MBPS |
+                               HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS |
+                               HFA384X_RATES_11MBPS;
+                       break;
+               case 5500000:
+                       local->tx_rate_control = HFA384X_RATES_1MBPS |
+                               HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS;
+                       break;
+               case 2000000:
+                       local->tx_rate_control = HFA384X_RATES_1MBPS |
+                               HFA384X_RATES_2MBPS;
+                       break;
+               case 1000000:
+                       local->tx_rate_control = HFA384X_RATES_1MBPS;
+                       break;
+               default:
+                       local->tx_rate_control = HFA384X_RATES_1MBPS |
+                               HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS |
+                               HFA384X_RATES_11MBPS;
+                       break;
+               }
+       }
+
+       return hostap_set_rate(dev);
+}
+
+
+static int prism2_ioctl_giwrate(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_param *rrq, char *extra)
+{
+       u16 val;
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int ret = 0;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->func->get_rid(dev, HFA384X_RID_TXRATECONTROL, &val, 2, 1) <
+           0)
+               return -EINVAL;
+
+       if ((val & 0x1) && (val > 1))
+               rrq->fixed = 0;
+       else
+               rrq->fixed = 1;
+
+       if (local->iw_mode == IW_MODE_MASTER && local->ap != NULL &&
+           !local->fw_tx_rate_control) {
+               /* HFA384X_RID_CURRENTTXRATE seems to always be 2 Mbps in
+                * Host AP mode, so use the recorded TX rate of the last sent
+                * frame */
+               rrq->value = local->ap->last_tx_rate > 0 ?
+                       local->ap->last_tx_rate * 100000 : 11000000;
+               return 0;
+       }
+
+       if (local->func->get_rid(dev, HFA384X_RID_CURRENTTXRATE, &val, 2, 1) <
+           0)
+               return -EINVAL;
+
+       switch (val) {
+       case HFA384X_RATES_1MBPS:
+               rrq->value = 1000000;
+               break;
+       case HFA384X_RATES_2MBPS:
+               rrq->value = 2000000;
+               break;
+       case HFA384X_RATES_5MBPS:
+               rrq->value = 5500000;
+               break;
+       case HFA384X_RATES_11MBPS:
+               rrq->value = 11000000;
+               break;
+       default:
+               /* should not happen */
+               rrq->value = 11000000;
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+
+static int prism2_ioctl_siwsens(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_param *sens, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       /* Set the desired AP density */
+       if (sens->value < 1 || sens->value > 3)
+               return -EINVAL;
+
+       if (hostap_set_word(dev, HFA384X_RID_CNFSYSTEMSCALE, sens->value) ||
+           local->func->reset_port(dev))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int prism2_ioctl_giwsens(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_param *sens, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       u16 val;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       /* Get the current AP density */
+       if (local->func->get_rid(dev, HFA384X_RID_CNFSYSTEMSCALE, &val, 2, 1) <
+           0)
+               return -EINVAL;
+
+       sens->value = __le16_to_cpu(val);
+       sens->fixed = 1;
+
+       return 0;
+}
+
+
+/* Deprecated in new wireless extension API */
+static int prism2_ioctl_giwaplist(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_point *data, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       struct sockaddr *addr;
+       struct iw_quality *qual;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->iw_mode != IW_MODE_MASTER) {
+               printk(KERN_DEBUG "SIOCGIWAPLIST is currently only supported "
+                      "in Host AP mode\n");
+               data->length = 0;
+               return -EOPNOTSUPP;
+       }
+
+       addr = kmalloc(sizeof(struct sockaddr) * IW_MAX_AP, GFP_KERNEL);
+       qual = kmalloc(sizeof(struct iw_quality) * IW_MAX_AP, GFP_KERNEL);
+       if (addr == NULL || qual == NULL) {
+               kfree(addr);
+               kfree(qual);
+               data->length = 0;
+               return -ENOMEM;
+       }
+
+       data->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_AP, 1);
+
+       memcpy(extra, &addr, sizeof(struct sockaddr) * data->length);
+       data->flags = 1; /* has quality information */
+       memcpy(extra + sizeof(struct sockaddr) * data->length, &qual,
+              sizeof(struct iw_quality) * data->length);
+
+       kfree(addr);
+       kfree(qual);
+
+       return 0;
+}
+
+
+static int prism2_ioctl_siwrts(struct net_device *dev,
+                              struct iw_request_info *info,
+                              struct iw_param *rts, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       u16 val;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (rts->disabled)
+               val = __constant_cpu_to_le16(2347);
+       else if (rts->value < 0 || rts->value > 2347)
+               return -EINVAL;
+       else
+               val = __cpu_to_le16(rts->value);
+
+       if (local->func->set_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2) ||
+           local->func->reset_port(dev))
+               return -EINVAL;
+
+       local->rts_threshold = rts->value;
+
+       return 0;
+}
+
+static int prism2_ioctl_giwrts(struct net_device *dev,
+                              struct iw_request_info *info,
+                              struct iw_param *rts, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       u16 val;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->func->get_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2, 1) <
+           0)
+               return -EINVAL;
+
+       rts->value = __le16_to_cpu(val);
+       rts->disabled = (rts->value == 2347);
+       rts->fixed = 1;
+
+       return 0;
+}
+
+
+static int prism2_ioctl_siwfrag(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_param *rts, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       u16 val;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (rts->disabled)
+               val = __constant_cpu_to_le16(2346);
+       else if (rts->value < 256 || rts->value > 2346)
+               return -EINVAL;
+       else
+               val = __cpu_to_le16(rts->value & ~0x1); /* even numbers only */
+
+       local->fragm_threshold = rts->value & ~0x1;
+       if (local->func->set_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, &val,
+                                2)
+           || local->func->reset_port(dev))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int prism2_ioctl_giwfrag(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_param *rts, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       u16 val;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->func->get_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD,
+                                &val, 2, 1) < 0)
+               return -EINVAL;
+
+       rts->value = __le16_to_cpu(val);
+       rts->disabled = (rts->value == 2346);
+       rts->fixed = 1;
+
+       return 0;
+}
+
+
+#ifndef PRISM2_NO_STATION_MODES
+static int hostap_join_ap(struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       struct hfa384x_join_request req;
+       unsigned long flags;
+       int i;
+       struct hfa384x_hostscan_result *entry;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       memcpy(req.bssid, local->preferred_ap, ETH_ALEN);
+       req.channel = 0;
+
+       spin_lock_irqsave(&local->lock, flags);
+       for (i = 0; i < local->last_scan_results_count; i++) {
+               if (!local->last_scan_results)
+                       break;
+               entry = &local->last_scan_results[i];
+               if (memcmp(local->preferred_ap, entry->bssid, ETH_ALEN) == 0) {
+                       req.channel = entry->chid;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&local->lock, flags);
+
+       if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
+                                sizeof(req))) {
+               printk(KERN_DEBUG "%s: JoinRequest " MACSTR
+                      " failed\n",
+                      dev->name, MAC2STR(local->preferred_ap));
+               return -1;
+       }
+
+       printk(KERN_DEBUG "%s: Trying to join BSSID " MACSTR "\n",
+              dev->name, MAC2STR(local->preferred_ap));
+
+       return 0;
+}
+#endif /* PRISM2_NO_STATION_MODES */
+
+
+static int prism2_ioctl_siwap(struct net_device *dev,
+                             struct iw_request_info *info,
+                             struct sockaddr *ap_addr, char *extra)
+{
+#ifdef PRISM2_NO_STATION_MODES
+       return -EOPNOTSUPP;
+#else /* PRISM2_NO_STATION_MODES */
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       memcpy(local->preferred_ap, &ap_addr->sa_data, ETH_ALEN);
+
+       if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) {
+               struct hfa384x_scan_request scan_req;
+               memset(&scan_req, 0, sizeof(scan_req));
+               scan_req.channel_list = __constant_cpu_to_le16(0x3fff);
+               scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS);
+               if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST,
+                                        &scan_req, sizeof(scan_req))) {
+                       printk(KERN_DEBUG "%s: ScanResults request failed - "
+                              "preferred AP delayed to next unsolicited "
+                              "scan\n", dev->name);
+               }
+       } else if (local->host_roaming == 2 &&
+                  local->iw_mode == IW_MODE_INFRA) {
+               if (hostap_join_ap(dev))
+                       return -EINVAL;
+       } else {
+               printk(KERN_DEBUG "%s: Preferred AP (SIOCSIWAP) is used only "
+                      "in Managed mode when host_roaming is enabled\n",
+                      dev->name);
+       }
+
+       return 0;
+#endif /* PRISM2_NO_STATION_MODES */
+}
+
+static int prism2_ioctl_giwap(struct net_device *dev,
+                             struct iw_request_info *info,
+                             struct sockaddr *ap_addr, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       ap_addr->sa_family = ARPHRD_ETHER;
+       switch (iface->type) {
+       case HOSTAP_INTERFACE_AP:
+               memcpy(&ap_addr->sa_data, dev->dev_addr, ETH_ALEN);
+               break;
+       case HOSTAP_INTERFACE_STA:
+               memcpy(&ap_addr->sa_data, local->assoc_ap_addr, ETH_ALEN);
+               break;
+       case HOSTAP_INTERFACE_WDS:
+               memcpy(&ap_addr->sa_data, iface->u.wds.remote_addr, ETH_ALEN);
+               break;
+       default:
+               if (local->func->get_rid(dev, HFA384X_RID_CURRENTBSSID,
+                                        &ap_addr->sa_data, ETH_ALEN, 1) < 0)
+                       return -EOPNOTSUPP;
+
+               /* local->bssid is also updated in LinkStatus handler when in
+                * station mode */
+               memcpy(local->bssid, &ap_addr->sa_data, ETH_ALEN);
+               break;
+       }
+
+       return 0;
+}
+
+
+static int prism2_ioctl_siwnickn(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_point *data, char *nickname)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       memset(local->name, 0, sizeof(local->name));
+       memcpy(local->name, nickname, data->length);
+       local->name_set = 1;
+
+       if (hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, local->name) ||
+           local->func->reset_port(dev))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int prism2_ioctl_giwnickn(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_point *data, char *nickname)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int len;
+       char name[MAX_NAME_LEN + 3];
+       u16 val;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       len = local->func->get_rid(dev, HFA384X_RID_CNFOWNNAME,
+                                  &name, MAX_NAME_LEN + 2, 0);
+       val = __le16_to_cpu(*(u16 *) name);
+       if (len > MAX_NAME_LEN + 2 || len < 0 || val > MAX_NAME_LEN)
+               return -EOPNOTSUPP;
+
+       name[val + 2] = '\0';
+       data->length = val + 1;
+       memcpy(nickname, name + 2, val + 1);
+
+       return 0;
+}
+
+
+static int prism2_ioctl_siwfreq(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_freq *freq, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       /* freq => chan. */
+       if (freq->e == 1 &&
+           freq->m / 100000 >= freq_list[0] &&
+           freq->m / 100000 <= freq_list[FREQ_COUNT - 1]) {
+               int ch;
+               int fr = freq->m / 100000;
+               for (ch = 0; ch < FREQ_COUNT; ch++) {
+                       if (fr == freq_list[ch]) {
+                               freq->e = 0;
+                               freq->m = ch + 1;
+                               break;
+                       }
+               }
+       }
+
+       if (freq->e != 0 || freq->m < 1 || freq->m > FREQ_COUNT ||
+           !(local->channel_mask & (1 << (freq->m - 1))))
+               return -EINVAL;
+
+       local->channel = freq->m; /* channel is used in prism2_setup_rids() */
+       if (hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel) ||
+           local->func->reset_port(dev))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int prism2_ioctl_giwfreq(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_freq *freq, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       u16 val;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->func->get_rid(dev, HFA384X_RID_CURRENTCHANNEL, &val, 2, 1) <
+           0)
+               return -EINVAL;
+
+       le16_to_cpus(&val);
+       if (val < 1 || val > FREQ_COUNT)
+               return -EINVAL;
+
+       freq->m = freq_list[val - 1] * 100000;
+       freq->e = 1;
+
+       return 0;
+}
+
+
+static void hostap_monitor_set_type(local_info_t *local)
+{
+       struct net_device *dev = local->ddev;
+
+       if (dev == NULL)
+               return;
+
+       if (local->monitor_type == PRISM2_MONITOR_PRISM ||
+           local->monitor_type == PRISM2_MONITOR_CAPHDR) {
+               dev->type = ARPHRD_IEEE80211_PRISM;
+               dev->hard_header_parse =
+                       hostap_80211_prism_header_parse;
+       } else {
+               dev->type = ARPHRD_IEEE80211;
+               dev->hard_header_parse = hostap_80211_header_parse;
+       }
+}
+
+
+static int prism2_ioctl_siwessid(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_point *data, char *ssid)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (iface->type == HOSTAP_INTERFACE_WDS)
+               return -EOPNOTSUPP;
+
+       if (data->flags == 0)
+               ssid[0] = '\0'; /* ANY */
+
+       if (local->iw_mode == IW_MODE_MASTER && ssid[0] == '\0') {
+               /* Setting SSID to empty string seems to kill the card in
+                * Host AP mode */
+               printk(KERN_DEBUG "%s: Host AP mode does not support "
+                      "'Any' essid\n", dev->name);
+               return -EINVAL;
+       }
+
+       memcpy(local->essid, ssid, data->length);
+       local->essid[data->length] = '\0';
+
+       if ((!local->fw_ap &&
+            hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, local->essid))
+           || hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, local->essid) ||
+           local->func->reset_port(dev))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int prism2_ioctl_giwessid(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_point *data, char *essid)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       u16 val;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (iface->type == HOSTAP_INTERFACE_WDS)
+               return -EOPNOTSUPP;
+
+       data->flags = 1; /* active */
+       if (local->iw_mode == IW_MODE_MASTER) {
+               data->length = strlen(local->essid);
+               memcpy(essid, local->essid, IW_ESSID_MAX_SIZE);
+       } else {
+               int len;
+               char ssid[MAX_SSID_LEN + 2];
+               memset(ssid, 0, sizeof(ssid));
+               len = local->func->get_rid(dev, HFA384X_RID_CURRENTSSID,
+                                          &ssid, MAX_SSID_LEN + 2, 0);
+               val = __le16_to_cpu(*(u16 *) ssid);
+               if (len > MAX_SSID_LEN + 2 || len < 0 || val > MAX_SSID_LEN) {
+                       return -EOPNOTSUPP;
+               }
+               data->length = val;
+               memcpy(essid, ssid + 2, IW_ESSID_MAX_SIZE);
+       }
+
+       return 0;
+}
+
+
+static int prism2_ioctl_giwrange(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_point *data, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       struct iw_range *range = (struct iw_range *) extra;
+       u8 rates[10];
+       u16 val;
+       int i, len, over2;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       data->length = sizeof(struct iw_range);
+       memset(range, 0, sizeof(struct iw_range));
+
+       /* TODO: could fill num_txpower and txpower array with
+        * something; however, there are 128 different values.. */
+
+       range->txpower_capa = IW_TXPOW_DBM;
+
+       if (local->iw_mode == IW_MODE_INFRA || local->iw_mode == IW_MODE_ADHOC)
+       {
+               range->min_pmp = 1 * 1024;
+               range->max_pmp = 65535 * 1024;
+               range->min_pmt = 1 * 1024;
+               range->max_pmt = 1000 * 1024;
+               range->pmp_flags = IW_POWER_PERIOD;
+               range->pmt_flags = IW_POWER_TIMEOUT;
+               range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT |
+                       IW_POWER_UNICAST_R | IW_POWER_ALL_R;
+       }
+
+       range->we_version_compiled = WIRELESS_EXT;
+       range->we_version_source = 18;
+
+       range->retry_capa = IW_RETRY_LIMIT;
+       range->retry_flags = IW_RETRY_LIMIT;
+       range->min_retry = 0;
+       range->max_retry = 255;
+
+       range->num_channels = FREQ_COUNT;
+
+       val = 0;
+       for (i = 0; i < FREQ_COUNT; i++) {
+               if (local->channel_mask & (1 << i)) {
+                       range->freq[val].i = i + 1;
+                       range->freq[val].m = freq_list[i] * 100000;
+                       range->freq[val].e = 1;
+                       val++;
+               }
+               if (val == IW_MAX_FREQUENCIES)
+                       break;
+       }
+       range->num_frequency = val;
+
+       if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) {
+               range->max_qual.qual = 70; /* what is correct max? This was not
+                                           * documented exactly. At least
+                                           * 69 has been observed. */
+               range->max_qual.level = 0; /* dB */
+               range->max_qual.noise = 0; /* dB */
+
+               /* What would be suitable values for "average/typical" qual? */
+               range->avg_qual.qual = 20;
+               range->avg_qual.level = -60;
+               range->avg_qual.noise = -95;
+       } else {
+               range->max_qual.qual = 92; /* 0 .. 92 */
+               range->max_qual.level = 154; /* 27 .. 154 */
+               range->max_qual.noise = 154; /* 27 .. 154 */
+       }
+       range->sensitivity = 3;
+
+       range->max_encoding_tokens = WEP_KEYS;
+       range->num_encoding_sizes = 2;
+       range->encoding_size[0] = 5;
+       range->encoding_size[1] = 13;
+
+       over2 = 0;
+       len = prism2_get_datarates(dev, rates);
+       range->num_bitrates = 0;
+       for (i = 0; i < len; i++) {
+               if (range->num_bitrates < IW_MAX_BITRATES) {
+                       range->bitrate[range->num_bitrates] =
+                               rates[i] * 500000;
+                       range->num_bitrates++;
+               }
+               if (rates[i] == 0x0b || rates[i] == 0x16)
+                       over2 = 1;
+       }
+       /* estimated maximum TCP throughput values (bps) */
+       range->throughput = over2 ? 5500000 : 1500000;
+
+       range->min_rts = 0;
+       range->max_rts = 2347;
+       range->min_frag = 256;
+       range->max_frag = 2346;
+
+       /* Event capability (kernel + driver) */
+       range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
+                               IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
+                               IW_EVENT_CAPA_MASK(SIOCGIWAP) |
+                               IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
+       range->event_capa[1] = IW_EVENT_CAPA_K_1;
+       range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVTXDROP) |
+                               IW_EVENT_CAPA_MASK(IWEVCUSTOM) |
+                               IW_EVENT_CAPA_MASK(IWEVREGISTERED) |
+                               IW_EVENT_CAPA_MASK(IWEVEXPIRED));
+
+       range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+               IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+
+       return 0;
+}
+
+
+static int hostap_monitor_mode_enable(local_info_t *local)
+{
+       struct net_device *dev = local->dev;
+
+       printk(KERN_DEBUG "Enabling monitor mode\n");
+       hostap_monitor_set_type(local);
+
+       if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
+                           HFA384X_PORTTYPE_PSEUDO_IBSS)) {
+               printk(KERN_DEBUG "Port type setting for monitor mode "
+                      "failed\n");
+               return -EOPNOTSUPP;
+       }
+
+       /* Host decrypt is needed to get the IV and ICV fields;
+        * however, monitor mode seems to remove WEP flag from frame
+        * control field */
+       if (hostap_set_word(dev, HFA384X_RID_CNFWEPFLAGS,
+                           HFA384X_WEPFLAGS_HOSTENCRYPT |
+                           HFA384X_WEPFLAGS_HOSTDECRYPT)) {
+               printk(KERN_DEBUG "WEP flags setting failed\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (local->func->reset_port(dev) ||
+           local->func->cmd(dev, HFA384X_CMDCODE_TEST |
+                            (HFA384X_TEST_MONITOR << 8),
+                            0, NULL, NULL)) {
+               printk(KERN_DEBUG "Setting monitor mode failed\n");
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+
+static int hostap_monitor_mode_disable(local_info_t *local)
+{
+       struct net_device *dev = local->ddev;
+
+       if (dev == NULL)
+               return -1;
+
+       printk(KERN_DEBUG "%s: Disabling monitor mode\n", dev->name);
+       dev->type = ARPHRD_ETHER;
+       dev->hard_header_parse = local->saved_eth_header_parse;
+       if (local->func->cmd(dev, HFA384X_CMDCODE_TEST |
+                            (HFA384X_TEST_STOP << 8),
+                            0, NULL, NULL))
+               return -1;
+       return hostap_set_encryption(local);
+}
+
+
+static int prism2_ioctl_siwmode(struct net_device *dev,
+                               struct iw_request_info *info,
+                               __u32 *mode, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int double_reset = 0;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA &&
+           *mode != IW_MODE_MASTER && *mode != IW_MODE_REPEAT &&
+           *mode != IW_MODE_MONITOR)
+               return -EOPNOTSUPP;
+
+#ifdef PRISM2_NO_STATION_MODES
+       if (*mode == IW_MODE_ADHOC || *mode == IW_MODE_INFRA)
+               return -EOPNOTSUPP;
+#endif /* PRISM2_NO_STATION_MODES */
+
+       if (*mode == local->iw_mode)
+               return 0;
+
+       if (*mode == IW_MODE_MASTER && local->essid[0] == '\0') {
+               printk(KERN_WARNING "%s: empty SSID not allowed in Master "
+                      "mode\n", dev->name);
+               return -EINVAL;
+       }
+
+       if (local->iw_mode == IW_MODE_MONITOR)
+               hostap_monitor_mode_disable(local);
+
+       if ((local->iw_mode == IW_MODE_ADHOC ||
+            local->iw_mode == IW_MODE_MONITOR) && *mode == IW_MODE_MASTER) {
+               /* There seems to be a firmware bug in at least STA f/w v1.5.6
+                * that leaves beacon frames to use IBSS type when moving from
+                * IBSS to Host AP mode. Doing double Port0 reset seems to be
+                * enough to workaround this. */
+               double_reset = 1;
+       }
+
+       printk(KERN_DEBUG "prism2: %s: operating mode changed "
+              "%d -> %d\n", dev->name, local->iw_mode, *mode);
+       local->iw_mode = *mode;
+
+       if (local->iw_mode == IW_MODE_MONITOR)
+               hostap_monitor_mode_enable(local);
+       else if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt &&
+                !local->fw_encrypt_ok) {
+               printk(KERN_DEBUG "%s: defaulting to host-based encryption as "
+                      "a workaround for firmware bug in Host AP mode WEP\n",
+                      dev->name);
+               local->host_encrypt = 1;
+       }
+
+       if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
+                           hostap_get_porttype(local)))
+               return -EOPNOTSUPP;
+
+       if (local->func->reset_port(dev))
+               return -EINVAL;
+       if (double_reset && local->func->reset_port(dev))
+               return -EINVAL;
+
+       if (local->iw_mode != IW_MODE_INFRA && local->iw_mode != IW_MODE_ADHOC)
+       {
+               /* netif_carrier is used only in client modes for now, so make
+                * sure carrier is on when moving to non-client modes. */
+               netif_carrier_on(local->dev);
+               netif_carrier_on(local->ddev);
+       }
+       return 0;
+}
+
+
+static int prism2_ioctl_giwmode(struct net_device *dev,
+                               struct iw_request_info *info,
+                               __u32 *mode, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       switch (iface->type) {
+       case HOSTAP_INTERFACE_STA:
+               *mode = IW_MODE_INFRA;
+               break;
+       case HOSTAP_INTERFACE_WDS:
+               *mode = IW_MODE_REPEAT;
+               break;
+       default:
+               *mode = local->iw_mode;
+               break;
+       }
+       return 0;
+}
+
+
+static int prism2_ioctl_siwpower(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *wrq, char *extra)
+{
+#ifdef PRISM2_NO_STATION_MODES
+       return -EOPNOTSUPP;
+#else /* PRISM2_NO_STATION_MODES */
+       int ret = 0;
+
+       if (wrq->disabled)
+               return hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 0);
+
+       switch (wrq->flags & IW_POWER_MODE) {
+       case IW_POWER_UNICAST_R:
+               ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 0);
+               if (ret)
+                       return ret;
+               ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
+               if (ret)
+                       return ret;
+               break;
+       case IW_POWER_ALL_R:
+               ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 1);
+               if (ret)
+                       return ret;
+               ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
+               if (ret)
+                       return ret;
+               break;
+       case IW_POWER_ON:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (wrq->flags & IW_POWER_TIMEOUT) {
+               ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
+               if (ret)
+                       return ret;
+               ret = hostap_set_word(dev, HFA384X_RID_CNFPMHOLDOVERDURATION,
+                                     wrq->value / 1024);
+               if (ret)
+                       return ret;
+       }
+       if (wrq->flags & IW_POWER_PERIOD) {
+               ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
+               if (ret)
+                       return ret;
+               ret = hostap_set_word(dev, HFA384X_RID_CNFMAXSLEEPDURATION,
+                                     wrq->value / 1024);
+               if (ret)
+                       return ret;
+       }
+
+       return ret;
+#endif /* PRISM2_NO_STATION_MODES */
+}
+
+
+static int prism2_ioctl_giwpower(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *rrq, char *extra)
+{
+#ifdef PRISM2_NO_STATION_MODES
+       return -EOPNOTSUPP;
+#else /* PRISM2_NO_STATION_MODES */
+       struct hostap_interface *iface;
+       local_info_t *local;
+       u16 enable, mcast;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->func->get_rid(dev, HFA384X_RID_CNFPMENABLED, &enable, 2, 1)
+           < 0)
+               return -EINVAL;
+
+       if (!__le16_to_cpu(enable)) {
+               rrq->disabled = 1;
+               return 0;
+       }
+
+       rrq->disabled = 0;
+
+       if ((rrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+               u16 timeout;
+               if (local->func->get_rid(dev,
+                                        HFA384X_RID_CNFPMHOLDOVERDURATION,
+                                        &timeout, 2, 1) < 0)
+                       return -EINVAL;
+
+               rrq->flags = IW_POWER_TIMEOUT;
+               rrq->value = __le16_to_cpu(timeout) * 1024;
+       } else {
+               u16 period;
+               if (local->func->get_rid(dev, HFA384X_RID_CNFMAXSLEEPDURATION,
+                                        &period, 2, 1) < 0)
+                       return -EINVAL;
+
+               rrq->flags = IW_POWER_PERIOD;
+               rrq->value = __le16_to_cpu(period) * 1024;
+       }
+
+       if (local->func->get_rid(dev, HFA384X_RID_CNFMULTICASTRECEIVE, &mcast,
+                                2, 1) < 0)
+               return -EINVAL;
+
+       if (__le16_to_cpu(mcast))
+               rrq->flags |= IW_POWER_ALL_R;
+       else
+               rrq->flags |= IW_POWER_UNICAST_R;
+
+       return 0;
+#endif /* PRISM2_NO_STATION_MODES */
+}
+
+
+static int prism2_ioctl_siwretry(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *rrq, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (rrq->disabled)
+               return -EINVAL;
+
+       /* setting retry limits is not supported with the current station
+        * firmware code; simulate this with alternative retry count for now */
+       if (rrq->flags == IW_RETRY_LIMIT) {
+               if (rrq->value < 0) {
+                       /* disable manual retry count setting and use firmware
+                        * defaults */
+                       local->manual_retry_count = -1;
+                       local->tx_control &= ~HFA384X_TX_CTRL_ALT_RTRY;
+               } else {
+                       if (hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT,
+                                           rrq->value)) {
+                               printk(KERN_DEBUG "%s: Alternate retry count "
+                                      "setting to %d failed\n",
+                                      dev->name, rrq->value);
+                               return -EOPNOTSUPP;
+                       }
+
+                       local->manual_retry_count = rrq->value;
+                       local->tx_control |= HFA384X_TX_CTRL_ALT_RTRY;
+               }
+               return 0;
+       }
+
+       return -EOPNOTSUPP;
+
+#if 0
+       /* what could be done, if firmware would support this.. */
+
+       if (rrq->flags & IW_RETRY_LIMIT) {
+               if (rrq->flags & IW_RETRY_MAX)
+                       HFA384X_RID_LONGRETRYLIMIT = rrq->value;
+               else if (rrq->flags & IW_RETRY_MIN)
+                       HFA384X_RID_SHORTRETRYLIMIT = rrq->value;
+               else {
+                       HFA384X_RID_LONGRETRYLIMIT = rrq->value;
+                       HFA384X_RID_SHORTRETRYLIMIT = rrq->value;
+               }
+
+       }
+
+       if (rrq->flags & IW_RETRY_LIFETIME) {
+               HFA384X_RID_MAXTRANSMITLIFETIME = rrq->value / 1024;
+       }
+
+       return 0;
+#endif /* 0 */
+}
+
+static int prism2_ioctl_giwretry(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *rrq, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       u16 shortretry, longretry, lifetime, altretry;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->func->get_rid(dev, HFA384X_RID_SHORTRETRYLIMIT, &shortretry,
+                                2, 1) < 0 ||
+           local->func->get_rid(dev, HFA384X_RID_LONGRETRYLIMIT, &longretry,
+                                2, 1) < 0 ||
+           local->func->get_rid(dev, HFA384X_RID_MAXTRANSMITLIFETIME,
+                                &lifetime, 2, 1) < 0)
+               return -EINVAL;
+
+       le16_to_cpus(&shortretry);
+       le16_to_cpus(&longretry);
+       le16_to_cpus(&lifetime);
+
+       rrq->disabled = 0;
+
+       if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+               rrq->flags = IW_RETRY_LIFETIME;
+               rrq->value = lifetime * 1024;
+       } else {
+               if (local->manual_retry_count >= 0) {
+                       rrq->flags = IW_RETRY_LIMIT;
+                       if (local->func->get_rid(dev,
+                                                HFA384X_RID_CNFALTRETRYCOUNT,
+                                                &altretry, 2, 1) >= 0)
+                               rrq->value = le16_to_cpu(altretry);
+                       else
+                               rrq->value = local->manual_retry_count;
+               } else if ((rrq->flags & IW_RETRY_MAX)) {
+                       rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+                       rrq->value = longretry;
+               } else {
+                       rrq->flags = IW_RETRY_LIMIT;
+                       rrq->value = shortretry;
+                       if (shortretry != longretry)
+                               rrq->flags |= IW_RETRY_MIN;
+               }
+       }
+       return 0;
+}
+
+
+/* Note! This TX power controlling is experimental and should not be used in
+ * production use. It just sets raw power register and does not use any kind of
+ * feedback information from the measured TX power (CR58). This is now
+ * commented out to make sure that it is not used by accident. TX power
+ * configuration will be enabled again after proper algorithm using feedback
+ * has been implemented. */
+
+#ifdef RAW_TXPOWER_SETTING
+/* Map HFA386x's CR31 to and from dBm with some sort of ad hoc mapping..
+ * This version assumes following mapping:
+ * CR31 is 7-bit value with -64 to +63 range.
+ * -64 is mapped into +20dBm and +63 into -43dBm.
+ * This is certainly not an exact mapping for every card, but at least
+ * increasing dBm value should correspond to increasing TX power.
+ */
+
+static int prism2_txpower_hfa386x_to_dBm(u16 val)
+{
+       signed char tmp;
+
+       if (val > 255)
+               val = 255;
+
+       tmp = val;
+       tmp >>= 2;
+
+       return -12 - tmp;
+}
+
+static u16 prism2_txpower_dBm_to_hfa386x(int val)
+{
+       signed char tmp;
+
+       if (val > 20)
+               return 128;
+       else if (val < -43)
+               return 127;
+
+       tmp = val;
+       tmp = -12 - tmp;
+       tmp <<= 2;
+
+       return (unsigned char) tmp;
+}
+#endif /* RAW_TXPOWER_SETTING */
+
+
+static int prism2_ioctl_siwtxpow(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *rrq, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+#ifdef RAW_TXPOWER_SETTING
+       char *tmp;
+#endif
+       u16 val;
+       int ret = 0;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (rrq->disabled) {
+               if (local->txpower_type != PRISM2_TXPOWER_OFF) {
+                       val = 0xff; /* use all standby and sleep modes */
+                       ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
+                                              HFA386X_CR_A_D_TEST_MODES2,
+                                              &val, NULL);
+                       printk(KERN_DEBUG "%s: Turning radio off: %s\n",
+                              dev->name, ret ? "failed" : "OK");
+                       local->txpower_type = PRISM2_TXPOWER_OFF;
+               }
+               return (ret ? -EOPNOTSUPP : 0);
+       }
+
+       if (local->txpower_type == PRISM2_TXPOWER_OFF) {
+               val = 0; /* disable all standby and sleep modes */
+               ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
+                                      HFA386X_CR_A_D_TEST_MODES2, &val, NULL);
+               printk(KERN_DEBUG "%s: Turning radio on: %s\n",
+                      dev->name, ret ? "failed" : "OK");
+               local->txpower_type = PRISM2_TXPOWER_UNKNOWN;
+       }
+
+#ifdef RAW_TXPOWER_SETTING
+       if (!rrq->fixed && local->txpower_type != PRISM2_TXPOWER_AUTO) {
+               printk(KERN_DEBUG "Setting ALC on\n");
+               val = HFA384X_TEST_CFG_BIT_ALC;
+               local->func->cmd(dev, HFA384X_CMDCODE_TEST |
+                                (HFA384X_TEST_CFG_BITS << 8), 1, &val, NULL);
+               local->txpower_type = PRISM2_TXPOWER_AUTO;
+               return 0;
+       }
+
+       if (local->txpower_type != PRISM2_TXPOWER_FIXED) {
+               printk(KERN_DEBUG "Setting ALC off\n");
+               val = HFA384X_TEST_CFG_BIT_ALC;
+               local->func->cmd(dev, HFA384X_CMDCODE_TEST |
+                                (HFA384X_TEST_CFG_BITS << 8), 0, &val, NULL);
+                       local->txpower_type = PRISM2_TXPOWER_FIXED;
+       }
+
+       if (rrq->flags == IW_TXPOW_DBM)
+               tmp = "dBm";
+       else if (rrq->flags == IW_TXPOW_MWATT)
+               tmp = "mW";
+       else
+               tmp = "UNKNOWN";
+       printk(KERN_DEBUG "Setting TX power to %d %s\n", rrq->value, tmp);
+
+       if (rrq->flags != IW_TXPOW_DBM) {
+               printk("SIOCSIWTXPOW with mW is not supported; use dBm\n");
+               return -EOPNOTSUPP;
+       }
+
+       local->txpower = rrq->value;
+       val = prism2_txpower_dBm_to_hfa386x(local->txpower);
+       if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
+                            HFA386X_CR_MANUAL_TX_POWER, &val, NULL))
+               ret = -EOPNOTSUPP;
+#else /* RAW_TXPOWER_SETTING */
+       if (rrq->fixed)
+               ret = -EOPNOTSUPP;
+#endif /* RAW_TXPOWER_SETTING */
+
+       return ret;
+}
+
+static int prism2_ioctl_giwtxpow(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *rrq, char *extra)
+{
+#ifdef RAW_TXPOWER_SETTING
+       struct hostap_interface *iface;
+       local_info_t *local;
+       u16 resp0;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       rrq->flags = IW_TXPOW_DBM;
+       rrq->disabled = 0;
+       rrq->fixed = 0;
+
+       if (local->txpower_type == PRISM2_TXPOWER_AUTO) {
+               if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF,
+                                    HFA386X_CR_MANUAL_TX_POWER,
+                                    NULL, &resp0) == 0) {
+                       rrq->value = prism2_txpower_hfa386x_to_dBm(resp0);
+               } else {
+                       /* Could not get real txpower; guess 15 dBm */
+                       rrq->value = 15;
+               }
+       } else if (local->txpower_type == PRISM2_TXPOWER_OFF) {
+               rrq->value = 0;
+               rrq->disabled = 1;
+       } else if (local->txpower_type == PRISM2_TXPOWER_FIXED) {
+               rrq->value = local->txpower;
+               rrq->fixed = 1;
+       } else {
+               printk("SIOCGIWTXPOW - unknown txpower_type=%d\n",
+                      local->txpower_type);
+       }
+       return 0;
+#else /* RAW_TXPOWER_SETTING */
+       return -EOPNOTSUPP;
+#endif /* RAW_TXPOWER_SETTING */
+}
+
+
+#ifndef PRISM2_NO_STATION_MODES
+
+/* HostScan request works with and without host_roaming mode. In addition, it
+ * does not break current association. However, it requires newer station
+ * firmware version (>= 1.3.1) than scan request. */
+static int prism2_request_hostscan(struct net_device *dev,
+                                  u8 *ssid, u8 ssid_len)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       struct hfa384x_hostscan_request scan_req;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       memset(&scan_req, 0, sizeof(scan_req));
+       scan_req.channel_list = cpu_to_le16(local->channel_mask &
+                                           local->scan_channel_mask);
+       scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS);
+       if (ssid) {
+               if (ssid_len > 32)
+                       return -EINVAL;
+               scan_req.target_ssid_len = cpu_to_le16(ssid_len);
+               memcpy(scan_req.target_ssid, ssid, ssid_len);
+       }
+
+       if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req,
+                                sizeof(scan_req))) {
+               printk(KERN_DEBUG "%s: HOSTSCAN failed\n", dev->name);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+
+static int prism2_request_scan(struct net_device *dev)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       struct hfa384x_scan_request scan_req;
+       int ret = 0;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       memset(&scan_req, 0, sizeof(scan_req));
+       scan_req.channel_list = cpu_to_le16(local->channel_mask &
+                                           local->scan_channel_mask);
+       scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS);
+
+       /* FIX:
+        * It seems to be enough to set roaming mode for a short moment to
+        * host-based and then setup scanrequest data and return the mode to
+        * firmware-based.
+        *
+        * Master mode would need to drop to Managed mode for a short while
+        * to make scanning work.. Or sweep through the different channels and
+        * use passive scan based on beacons. */
+
+       if (!local->host_roaming)
+               hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE,
+                               HFA384X_ROAMING_HOST);
+
+       if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, &scan_req,
+                                sizeof(scan_req))) {
+               printk(KERN_DEBUG "SCANREQUEST failed\n");
+               ret = -EINVAL;
+       }
+
+       if (!local->host_roaming)
+               hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE,
+                               HFA384X_ROAMING_FIRMWARE);
+
+       return 0;
+}
+
+#else /* !PRISM2_NO_STATION_MODES */
+
+static inline int prism2_request_hostscan(struct net_device *dev,
+                                         u8 *ssid, u8 ssid_len)
+{
+       return -EOPNOTSUPP;
+}
+
+
+static inline int prism2_request_scan(struct net_device *dev)
+{
+       return -EOPNOTSUPP;
+}
+
+#endif /* !PRISM2_NO_STATION_MODES */
+
+
+static int prism2_ioctl_siwscan(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_point *data, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int ret;
+       u8 *ssid = NULL, ssid_len = 0;
+       struct iw_scan_req *req = (struct iw_scan_req *) extra;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (data->length < sizeof(struct iw_scan_req))
+               req = NULL;
+
+       if (local->iw_mode == IW_MODE_MASTER) {
+               /* In master mode, we just return the results of our local
+                * tables, so we don't need to start anything...
+                * Jean II */
+               data->length = 0;
+               return 0;
+       }
+
+       if (!local->dev_enabled)
+               return -ENETDOWN;
+
+       if (req && data->flags & IW_SCAN_THIS_ESSID) {
+               ssid = req->essid;
+               ssid_len = req->essid_len;
+
+               if (ssid_len &&
+                   ((local->iw_mode != IW_MODE_INFRA &&
+                     local->iw_mode != IW_MODE_ADHOC) ||
+                    (local->sta_fw_ver < PRISM2_FW_VER(1,3,1))))
+                       return -EOPNOTSUPP;
+       }
+
+       if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1))
+               ret = prism2_request_hostscan(dev, ssid, ssid_len);
+       else
+               ret = prism2_request_scan(dev);
+
+       if (ret == 0)
+               local->scan_timestamp = jiffies;
+
+       /* Could inquire F101, F103 or wait for SIOCGIWSCAN and read RID */
+
+       return ret;
+}
+
+
+#ifndef PRISM2_NO_STATION_MODES
+static char * __prism2_translate_scan(local_info_t *local,
+                                     struct hfa384x_hostscan_result *scan,
+                                     struct hostap_bss_info *bss,
+                                     char *current_ev, char *end_buf)
+{
+       int i, chan;
+       struct iw_event iwe;
+       char *current_val;
+       u16 capabilities;
+       u8 *pos;
+       u8 *ssid, *bssid;
+       size_t ssid_len;
+       char *buf;
+
+       if (bss) {
+               ssid = bss->ssid;
+               ssid_len = bss->ssid_len;
+               bssid = bss->bssid;
+       } else {
+               ssid = scan->ssid;
+               ssid_len = le16_to_cpu(scan->ssid_len);
+               bssid = scan->bssid;
+       }
+       if (ssid_len > 32)
+               ssid_len = 32;
+
+       /* First entry *MUST* be the AP MAC address */
+       memset(&iwe, 0, sizeof(iwe));
+       iwe.cmd = SIOCGIWAP;
+       iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+       memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN);
+       /* FIX:
+        * I do not know how this is possible, but iwe_stream_add_event
+        * seems to re-order memcpy execution so that len is set only
+        * after copying.. Pre-setting len here "fixes" this, but real
+        * problems should be solved (after which these iwe.len
+        * settings could be removed from this function). */
+       iwe.len = IW_EV_ADDR_LEN;
+       current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+                                         IW_EV_ADDR_LEN);
+
+       /* Other entries will be displayed in the order we give them */
+
+       memset(&iwe, 0, sizeof(iwe));
+       iwe.cmd = SIOCGIWESSID;
+       iwe.u.data.length = ssid_len;
+       iwe.u.data.flags = 1;
+       iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+       current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ssid);
+
+       memset(&iwe, 0, sizeof(iwe));
+       iwe.cmd = SIOCGIWMODE;
+       if (bss) {
+               capabilities = bss->capab_info;
+       } else {
+               capabilities = le16_to_cpu(scan->capability);
+       }
+       if (capabilities & (WLAN_CAPABILITY_ESS |
+                           WLAN_CAPABILITY_IBSS)) {
+               if (capabilities & WLAN_CAPABILITY_ESS)
+                       iwe.u.mode = IW_MODE_MASTER;
+               else
+                       iwe.u.mode = IW_MODE_ADHOC;
+               iwe.len = IW_EV_UINT_LEN;
+               current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+                                                 IW_EV_UINT_LEN);
+       }
+
+       memset(&iwe, 0, sizeof(iwe));
+       iwe.cmd = SIOCGIWFREQ;
+       if (scan) {
+               chan = scan->chid;
+       } else if (bss) {
+               chan = bss->chan;
+       } else {
+               chan = 0;
+       }
+
+       if (chan > 0) {
+               iwe.u.freq.m = freq_list[le16_to_cpu(chan - 1)] * 100000;
+               iwe.u.freq.e = 1;
+               iwe.len = IW_EV_FREQ_LEN;
+               current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+                                                 IW_EV_FREQ_LEN);
+       }
+
+       if (scan) {
+               memset(&iwe, 0, sizeof(iwe));
+               iwe.cmd = IWEVQUAL;
+               if (local->last_scan_type == PRISM2_HOSTSCAN) {
+                       iwe.u.qual.level = le16_to_cpu(scan->sl);
+                       iwe.u.qual.noise = le16_to_cpu(scan->anl);
+               } else {
+                       iwe.u.qual.level =
+                               HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->sl));
+                       iwe.u.qual.noise =
+                               HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->anl));
+               }
+               iwe.len = IW_EV_QUAL_LEN;
+               current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+                                                 IW_EV_QUAL_LEN);
+       }
+
+       memset(&iwe, 0, sizeof(iwe));
+       iwe.cmd = SIOCGIWENCODE;
+       if (capabilities & WLAN_CAPABILITY_PRIVACY)
+               iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+       else
+               iwe.u.data.flags = IW_ENCODE_DISABLED;
+       iwe.u.data.length = 0;
+       iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+       current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, "");
+
+       /* TODO: add SuppRates into BSS table */
+       if (scan) {
+               memset(&iwe, 0, sizeof(iwe));
+               iwe.cmd = SIOCGIWRATE;
+               current_val = current_ev + IW_EV_LCP_LEN;
+               pos = scan->sup_rates;
+               for (i = 0; i < sizeof(scan->sup_rates); i++) {
+                       if (pos[i] == 0)
+                               break;
+                       /* Bit rate given in 500 kb/s units (+ 0x80) */
+                       iwe.u.bitrate.value = ((pos[i] & 0x7f) * 500000);
+                       current_val = iwe_stream_add_value(
+                               current_ev, current_val, end_buf, &iwe,
+                               IW_EV_PARAM_LEN);
+               }
+               /* Check if we added any event */
+               if ((current_val - current_ev) > IW_EV_LCP_LEN)
+                       current_ev = current_val;
+       }
+
+       /* TODO: add BeaconInt,resp_rate,atim into BSS table */
+       buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_KERNEL);
+       if (buf && scan) {
+               memset(&iwe, 0, sizeof(iwe));
+               iwe.cmd = IWEVCUSTOM;
+               sprintf(buf, "bcn_int=%d", le16_to_cpu(scan->beacon_interval));
+               iwe.u.data.length = strlen(buf);
+               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+                                                 buf);
+
+               memset(&iwe, 0, sizeof(iwe));
+               iwe.cmd = IWEVCUSTOM;
+               sprintf(buf, "resp_rate=%d", le16_to_cpu(scan->rate));
+               iwe.u.data.length = strlen(buf);
+               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+                                                 buf);
+
+               if (local->last_scan_type == PRISM2_HOSTSCAN &&
+                   (capabilities & WLAN_CAPABILITY_IBSS)) {
+                       memset(&iwe, 0, sizeof(iwe));
+                       iwe.cmd = IWEVCUSTOM;
+                       sprintf(buf, "atim=%d", le16_to_cpu(scan->atim));
+                       iwe.u.data.length = strlen(buf);
+                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                                                         &iwe, buf);
+               }
+       }
+       kfree(buf);
+
+       if (bss && bss->wpa_ie_len > 0 && bss->wpa_ie_len <= MAX_WPA_IE_LEN) {
+               memset(&iwe, 0, sizeof(iwe));
+               iwe.cmd = IWEVGENIE;
+               iwe.u.data.length = bss->wpa_ie_len;
+               current_ev = iwe_stream_add_point(
+                       current_ev, end_buf, &iwe, bss->wpa_ie);
+       }
+
+       if (bss && bss->rsn_ie_len > 0 && bss->rsn_ie_len <= MAX_WPA_IE_LEN) {
+               memset(&iwe, 0, sizeof(iwe));
+               iwe.cmd = IWEVGENIE;
+               iwe.u.data.length = bss->rsn_ie_len;
+               current_ev = iwe_stream_add_point(
+                       current_ev, end_buf, &iwe, bss->rsn_ie);
+       }
+
+       return current_ev;
+}
+
+
+/* Translate scan data returned from the card to a card independant
+ * format that the Wireless Tools will understand - Jean II */
+static inline int prism2_translate_scan(local_info_t *local,
+                                       char *buffer, int buflen)
+{
+       struct hfa384x_hostscan_result *scan;
+       int entry, hostscan;
+       char *current_ev = buffer;
+       char *end_buf = buffer + buflen;
+       struct list_head *ptr;
+
+       spin_lock_bh(&local->lock);
+
+       list_for_each(ptr, &local->bss_list) {
+               struct hostap_bss_info *bss;
+               bss = list_entry(ptr, struct hostap_bss_info, list);
+               bss->included = 0;
+       }
+
+       hostscan = local->last_scan_type == PRISM2_HOSTSCAN;
+       for (entry = 0; entry < local->last_scan_results_count; entry++) {
+               int found = 0;
+               scan = &local->last_scan_results[entry];
+
+               /* Report every SSID if the AP is using multiple SSIDs. If no
+                * BSS record is found (e.g., when WPA mode is disabled),
+                * report the AP once. */
+               list_for_each(ptr, &local->bss_list) {
+                       struct hostap_bss_info *bss;
+                       bss = list_entry(ptr, struct hostap_bss_info, list);
+                       if (memcmp(bss->bssid, scan->bssid, ETH_ALEN) == 0) {
+                               bss->included = 1;
+                               current_ev = __prism2_translate_scan(
+                                       local, scan, bss, current_ev, end_buf);
+                               found++;
+                       }
+               }
+               if (!found) {
+                       current_ev = __prism2_translate_scan(
+                               local, scan, NULL, current_ev, end_buf);
+               }
+               /* Check if there is space for one more entry */
+               if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) {
+                       /* Ask user space to try again with a bigger buffer */
+                       spin_unlock_bh(&local->lock);
+                       return -E2BIG;
+               }
+       }
+
+       /* Prism2 firmware has limits (32 at least in some versions) for number
+        * of BSSes in scan results. Extend this limit by using local BSS list.
+        */
+       list_for_each(ptr, &local->bss_list) {
+               struct hostap_bss_info *bss;
+               bss = list_entry(ptr, struct hostap_bss_info, list);
+               if (bss->included)
+                       continue;
+               current_ev = __prism2_translate_scan(local, NULL, bss,
+                                                    current_ev, end_buf);
+               /* Check if there is space for one more entry */
+               if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) {
+                       /* Ask user space to try again with a bigger buffer */
+                       spin_unlock_bh(&local->lock);
+                       return -E2BIG;
+               }
+       }
+
+       spin_unlock_bh(&local->lock);
+
+       return current_ev - buffer;
+}
+#endif /* PRISM2_NO_STATION_MODES */
+
+
+static inline int prism2_ioctl_giwscan_sta(struct net_device *dev,
+                                          struct iw_request_info *info,
+                                          struct iw_point *data, char *extra)
+{
+#ifdef PRISM2_NO_STATION_MODES
+       return -EOPNOTSUPP;
+#else /* PRISM2_NO_STATION_MODES */
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int res;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       /* Wait until the scan is finished. We can probably do better
+        * than that - Jean II */
+       if (local->scan_timestamp &&
+           time_before(jiffies, local->scan_timestamp + 3 * HZ)) {
+               /* Important note : we don't want to block the caller
+                * until results are ready for various reasons.
+                * First, managing wait queues is complex and racy
+                * (there may be multiple simultaneous callers).
+                * Second, we grab some rtnetlink lock before comming
+                * here (in dev_ioctl()).
+                * Third, the caller can wait on the Wireless Event
+                * - Jean II */
+               return -EAGAIN;
+       }
+       local->scan_timestamp = 0;
+
+       res = prism2_translate_scan(local, extra, data->length);
+
+       if (res >= 0) {
+               data->length = res;
+               return 0;
+       } else {
+               data->length = 0;
+               return res;
+       }
+#endif /* PRISM2_NO_STATION_MODES */
+}
+
+
+static int prism2_ioctl_giwscan(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_point *data, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int res;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->iw_mode == IW_MODE_MASTER) {
+               /* In MASTER mode, it doesn't make sense to go around
+                * scanning the frequencies and make the stations we serve
+                * wait when what the user is really interested about is the
+                * list of stations and access points we are talking to.
+                * So, just extract results from our cache...
+                * Jean II */
+
+               /* Translate to WE format */
+               res = prism2_ap_translate_scan(dev, extra);
+               if (res >= 0) {
+                       printk(KERN_DEBUG "Scan result translation succeeded "
+                              "(length=%d)\n", res);
+                       data->length = res;
+                       return 0;
+               } else {
+                       printk(KERN_DEBUG
+                              "Scan result translation failed (res=%d)\n",
+                              res);
+                       data->length = 0;
+                       return res;
+               }
+       } else {
+               /* Station mode */
+               return prism2_ioctl_giwscan_sta(dev, info, data, extra);
+       }
+}
+
+
+static const struct iw_priv_args prism2_priv[] = {
+       { PRISM2_IOCTL_MONITOR,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor" },
+       { PRISM2_IOCTL_READMIF,
+         IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+         IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "readmif" },
+       { PRISM2_IOCTL_WRITEMIF,
+         IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 2, 0, "writemif" },
+       { PRISM2_IOCTL_RESET,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "reset" },
+       { PRISM2_IOCTL_INQUIRE,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "inquire" },
+       { PRISM2_IOCTL_SET_RID_WORD,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_rid_word" },
+       { PRISM2_IOCTL_MACCMD,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maccmd" },
+       { PRISM2_IOCTL_WDS_ADD,
+         IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_add" },
+       { PRISM2_IOCTL_WDS_DEL,
+         IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_del" },
+       { PRISM2_IOCTL_ADDMAC,
+         IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "addmac" },
+       { PRISM2_IOCTL_DELMAC,
+         IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "delmac" },
+       { PRISM2_IOCTL_KICKMAC,
+         IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "kickmac" },
+       /* --- raw access to sub-ioctls --- */
+       { PRISM2_IOCTL_PRISM2_PARAM,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "prism2_param" },
+       { PRISM2_IOCTL_GET_PRISM2_PARAM,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprism2_param" },
+       /* --- sub-ioctls handlers --- */
+       { PRISM2_IOCTL_PRISM2_PARAM,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" },
+       { PRISM2_IOCTL_GET_PRISM2_PARAM,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" },
+       /* --- sub-ioctls definitions --- */
+       { PRISM2_PARAM_TXRATECTRL,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "txratectrl" },
+       { PRISM2_PARAM_TXRATECTRL,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettxratectrl" },
+       { PRISM2_PARAM_BEACON_INT,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "beacon_int" },
+       { PRISM2_PARAM_BEACON_INT,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbeacon_int" },
+#ifndef PRISM2_NO_STATION_MODES
+       { PRISM2_PARAM_PSEUDO_IBSS,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "pseudo_ibss" },
+       { PRISM2_PARAM_PSEUDO_IBSS,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getpseudo_ibss" },
+#endif /* PRISM2_NO_STATION_MODES */
+       { PRISM2_PARAM_ALC,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "alc" },
+       { PRISM2_PARAM_ALC,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getalc" },
+       { PRISM2_PARAM_DUMP,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dump" },
+       { PRISM2_PARAM_DUMP,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdump" },
+       { PRISM2_PARAM_OTHER_AP_POLICY,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "other_ap_policy" },
+       { PRISM2_PARAM_OTHER_AP_POLICY,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getother_ap_pol" },
+       { PRISM2_PARAM_AP_MAX_INACTIVITY,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_inactivity" },
+       { PRISM2_PARAM_AP_MAX_INACTIVITY,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_inactivi" },
+       { PRISM2_PARAM_AP_BRIDGE_PACKETS,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bridge_packets" },
+       { PRISM2_PARAM_AP_BRIDGE_PACKETS,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbridge_packe" },
+       { PRISM2_PARAM_DTIM_PERIOD,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dtim_period" },
+       { PRISM2_PARAM_DTIM_PERIOD,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdtim_period" },
+       { PRISM2_PARAM_AP_NULLFUNC_ACK,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "nullfunc_ack" },
+       { PRISM2_PARAM_AP_NULLFUNC_ACK,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getnullfunc_ack" },
+       { PRISM2_PARAM_MAX_WDS,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_wds" },
+       { PRISM2_PARAM_MAX_WDS,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_wds" },
+       { PRISM2_PARAM_AP_AUTOM_AP_WDS,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "autom_ap_wds" },
+       { PRISM2_PARAM_AP_AUTOM_AP_WDS,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getautom_ap_wds" },
+       { PRISM2_PARAM_AP_AUTH_ALGS,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_auth_algs" },
+       { PRISM2_PARAM_AP_AUTH_ALGS,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_auth_algs" },
+       { PRISM2_PARAM_MONITOR_ALLOW_FCSERR,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "allow_fcserr" },
+       { PRISM2_PARAM_MONITOR_ALLOW_FCSERR,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getallow_fcserr" },
+       { PRISM2_PARAM_HOST_ENCRYPT,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_encrypt" },
+       { PRISM2_PARAM_HOST_ENCRYPT,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_encrypt" },
+       { PRISM2_PARAM_HOST_DECRYPT,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_decrypt" },
+       { PRISM2_PARAM_HOST_DECRYPT,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_decrypt" },
+#ifndef PRISM2_NO_STATION_MODES
+       { PRISM2_PARAM_HOST_ROAMING,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_roaming" },
+       { PRISM2_PARAM_HOST_ROAMING,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_roaming" },
+#endif /* PRISM2_NO_STATION_MODES */
+       { PRISM2_PARAM_BCRX_STA_KEY,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bcrx_sta_key" },
+       { PRISM2_PARAM_BCRX_STA_KEY,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbcrx_sta_key" },
+       { PRISM2_PARAM_IEEE_802_1X,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ieee_802_1x" },
+       { PRISM2_PARAM_IEEE_802_1X,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getieee_802_1x" },
+       { PRISM2_PARAM_ANTSEL_TX,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_tx" },
+       { PRISM2_PARAM_ANTSEL_TX,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_tx" },
+       { PRISM2_PARAM_ANTSEL_RX,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_rx" },
+       { PRISM2_PARAM_ANTSEL_RX,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_rx" },
+       { PRISM2_PARAM_MONITOR_TYPE,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor_type" },
+       { PRISM2_PARAM_MONITOR_TYPE,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmonitor_type" },
+       { PRISM2_PARAM_WDS_TYPE,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wds_type" },
+       { PRISM2_PARAM_WDS_TYPE,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwds_type" },
+       { PRISM2_PARAM_HOSTSCAN,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostscan" },
+       { PRISM2_PARAM_HOSTSCAN,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostscan" },
+       { PRISM2_PARAM_AP_SCAN,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_scan" },
+       { PRISM2_PARAM_AP_SCAN,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_scan" },
+       { PRISM2_PARAM_ENH_SEC,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "enh_sec" },
+       { PRISM2_PARAM_ENH_SEC,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getenh_sec" },
+#ifdef PRISM2_IO_DEBUG
+       { PRISM2_PARAM_IO_DEBUG,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "io_debug" },
+       { PRISM2_PARAM_IO_DEBUG,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getio_debug" },
+#endif /* PRISM2_IO_DEBUG */
+       { PRISM2_PARAM_BASIC_RATES,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "basic_rates" },
+       { PRISM2_PARAM_BASIC_RATES,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbasic_rates" },
+       { PRISM2_PARAM_OPER_RATES,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "oper_rates" },
+       { PRISM2_PARAM_OPER_RATES,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getoper_rates" },
+       { PRISM2_PARAM_HOSTAPD,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd" },
+       { PRISM2_PARAM_HOSTAPD,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd" },
+       { PRISM2_PARAM_HOSTAPD_STA,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd_sta" },
+       { PRISM2_PARAM_HOSTAPD_STA,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd_sta" },
+       { PRISM2_PARAM_WPA,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wpa" },
+       { PRISM2_PARAM_WPA,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwpa" },
+       { PRISM2_PARAM_PRIVACY_INVOKED,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "privacy_invoked" },
+       { PRISM2_PARAM_PRIVACY_INVOKED,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprivacy_invo" },
+       { PRISM2_PARAM_TKIP_COUNTERMEASURES,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "tkip_countermea" },
+       { PRISM2_PARAM_TKIP_COUNTERMEASURES,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettkip_counter" },
+       { PRISM2_PARAM_DROP_UNENCRYPTED,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "drop_unencrypte" },
+       { PRISM2_PARAM_DROP_UNENCRYPTED,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdrop_unencry" },
+       { PRISM2_PARAM_SCAN_CHANNEL_MASK,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "scan_channels" },
+       { PRISM2_PARAM_SCAN_CHANNEL_MASK,
+         0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getscan_channel" },
+};
+
+
+static int prism2_ioctl_priv_inquire(struct net_device *dev, int *i)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->func->cmd(dev, HFA384X_CMDCODE_INQUIRE, *i, NULL, NULL))
+               return -EOPNOTSUPP;
+
+       return 0;
+}
+
+
+static int prism2_ioctl_priv_prism2_param(struct net_device *dev,
+                                         struct iw_request_info *info,
+                                         void *wrqu, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int *i = (int *) extra;
+       int param = *i;
+       int value = *(i + 1);
+       int ret = 0;
+       u16 val;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       switch (param) {
+       case PRISM2_PARAM_TXRATECTRL:
+               local->fw_tx_rate_control = value;
+               break;
+
+       case PRISM2_PARAM_BEACON_INT:
+               if (hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, value) ||
+                   local->func->reset_port(dev))
+                       ret = -EINVAL;
+               else
+                       local->beacon_int = value;
+               break;
+
+#ifndef PRISM2_NO_STATION_MODES
+       case PRISM2_PARAM_PSEUDO_IBSS:
+               if (value == local->pseudo_adhoc)
+                       break;
+
+               if (value != 0 && value != 1) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               printk(KERN_DEBUG "prism2: %s: pseudo IBSS change %d -> %d\n",
+                      dev->name, local->pseudo_adhoc, value);
+               local->pseudo_adhoc = value;
+               if (local->iw_mode != IW_MODE_ADHOC)
+                       break;
+
+               if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
+                                   hostap_get_porttype(local))) {
+                       ret = -EOPNOTSUPP;
+                       break;
+               }
+
+               if (local->func->reset_port(dev))
+                       ret = -EINVAL;
+               break;
+#endif /* PRISM2_NO_STATION_MODES */
+
+       case PRISM2_PARAM_ALC:
+               printk(KERN_DEBUG "%s: %s ALC\n", dev->name,
+                      value == 0 ? "Disabling" : "Enabling");
+               val = HFA384X_TEST_CFG_BIT_ALC;
+               local->func->cmd(dev, HFA384X_CMDCODE_TEST |
+                                (HFA384X_TEST_CFG_BITS << 8),
+                                value == 0 ? 0 : 1, &val, NULL);
+               break;
+
+       case PRISM2_PARAM_DUMP:
+               local->frame_dump = value;
+               break;
+
+       case PRISM2_PARAM_OTHER_AP_POLICY:
+               if (value < 0 || value > 3) {
+                       ret = -EINVAL;
+                       break;
+               }
+               if (local->ap != NULL)
+                       local->ap->ap_policy = value;
+               break;
+
+       case PRISM2_PARAM_AP_MAX_INACTIVITY:
+               if (value < 0 || value > 7 * 24 * 60 * 60) {
+                       ret = -EINVAL;
+                       break;
+               }
+               if (local->ap != NULL)
+                       local->ap->max_inactivity = value * HZ;
+               break;
+
+       case PRISM2_PARAM_AP_BRIDGE_PACKETS:
+               if (local->ap != NULL)
+                       local->ap->bridge_packets = value;
+               break;
+
+       case PRISM2_PARAM_DTIM_PERIOD:
+               if (value < 0 || value > 65535) {
+                       ret = -EINVAL;
+                       break;
+               }
+               if (hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, value)
+                   || local->func->reset_port(dev))
+                       ret = -EINVAL;
+               else
+                       local->dtim_period = value;
+               break;
+
+       case PRISM2_PARAM_AP_NULLFUNC_ACK:
+               if (local->ap != NULL)
+                       local->ap->nullfunc_ack = value;
+               break;
+
+       case PRISM2_PARAM_MAX_WDS:
+               local->wds_max_connections = value;
+               break;
+
+       case PRISM2_PARAM_AP_AUTOM_AP_WDS:
+               if (local->ap != NULL) {
+                       if (!local->ap->autom_ap_wds && value) {
+                               /* add WDS link to all APs in STA table */
+                               hostap_add_wds_links(local);
+                       }
+                       local->ap->autom_ap_wds = value;
+               }
+               break;
+
+       case PRISM2_PARAM_AP_AUTH_ALGS:
+               local->auth_algs = value;
+               if (hostap_set_auth_algs(local))
+                       ret = -EINVAL;
+               break;
+
+       case PRISM2_PARAM_MONITOR_ALLOW_FCSERR:
+               local->monitor_allow_fcserr = value;
+               break;
+
+       case PRISM2_PARAM_HOST_ENCRYPT:
+               local->host_encrypt = value;
+               if (hostap_set_encryption(local) ||
+                   local->func->reset_port(dev))
+                       ret = -EINVAL;
+               break;
+
+       case PRISM2_PARAM_HOST_DECRYPT:
+               local->host_decrypt = value;
+               if (hostap_set_encryption(local) ||
+                   local->func->reset_port(dev))
+                       ret = -EINVAL;
+               break;
+
+#ifndef PRISM2_NO_STATION_MODES
+       case PRISM2_PARAM_HOST_ROAMING:
+               if (value < 0 || value > 2) {
+                       ret = -EINVAL;
+                       break;
+               }
+               local->host_roaming = value;
+               if (hostap_set_roaming(local) || local->func->reset_port(dev))
+                       ret = -EINVAL;
+               break;
+#endif /* PRISM2_NO_STATION_MODES */
+
+       case PRISM2_PARAM_BCRX_STA_KEY:
+               local->bcrx_sta_key = value;
+               break;
+
+       case PRISM2_PARAM_IEEE_802_1X:
+               local->ieee_802_1x = value;
+               break;
+
+       case PRISM2_PARAM_ANTSEL_TX:
+               if (value < 0 || value > HOSTAP_ANTSEL_HIGH) {
+                       ret = -EINVAL;
+                       break;
+               }
+               local->antsel_tx = value;
+               hostap_set_antsel(local);
+               break;
+
+       case PRISM2_PARAM_ANTSEL_RX:
+               if (value < 0 || value > HOSTAP_ANTSEL_HIGH) {
+                       ret = -EINVAL;
+                       break;
+               }
+               local->antsel_rx = value;
+               hostap_set_antsel(local);
+               break;
+
+       case PRISM2_PARAM_MONITOR_TYPE:
+               if (value != PRISM2_MONITOR_80211 &&
+                   value != PRISM2_MONITOR_CAPHDR &&
+                   value != PRISM2_MONITOR_PRISM) {
+                       ret = -EINVAL;
+                       break;
+               }
+               local->monitor_type = value;
+               if (local->iw_mode == IW_MODE_MONITOR)
+                       hostap_monitor_set_type(local);
+               break;
+
+       case PRISM2_PARAM_WDS_TYPE:
+               local->wds_type = value;
+               break;
+
+       case PRISM2_PARAM_HOSTSCAN:
+       {
+               struct hfa384x_hostscan_request scan_req;
+               u16 rate;
+
+               memset(&scan_req, 0, sizeof(scan_req));
+               scan_req.channel_list = __constant_cpu_to_le16(0x3fff);
+               switch (value) {
+               case 1: rate = HFA384X_RATES_1MBPS; break;
+               case 2: rate = HFA384X_RATES_2MBPS; break;
+               case 3: rate = HFA384X_RATES_5MBPS; break;
+               case 4: rate = HFA384X_RATES_11MBPS; break;
+               default: rate = HFA384X_RATES_1MBPS; break;
+               }
+               scan_req.txrate = cpu_to_le16(rate);
+               /* leave SSID empty to accept all SSIDs */
+
+               if (local->iw_mode == IW_MODE_MASTER) {
+                       if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
+                                           HFA384X_PORTTYPE_BSS) ||
+                           local->func->reset_port(dev))
+                               printk(KERN_DEBUG "Leaving Host AP mode "
+                                      "for HostScan failed\n");
+               }
+
+               if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req,
+                                        sizeof(scan_req))) {
+                       printk(KERN_DEBUG "HOSTSCAN failed\n");
+                       ret = -EINVAL;
+               }
+               if (local->iw_mode == IW_MODE_MASTER) {
+                       wait_queue_t __wait;
+                       init_waitqueue_entry(&__wait, current);
+                       add_wait_queue(&local->hostscan_wq, &__wait);
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(HZ);
+                       if (signal_pending(current))
+                               ret = -EINTR;
+                       set_current_state(TASK_RUNNING);
+                       remove_wait_queue(&local->hostscan_wq, &__wait);
+
+                       if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
+                                           HFA384X_PORTTYPE_HOSTAP) ||
+                           local->func->reset_port(dev))
+                               printk(KERN_DEBUG "Returning to Host AP mode "
+                                      "after HostScan failed\n");
+               }
+               break;
+       }
+
+       case PRISM2_PARAM_AP_SCAN:
+               local->passive_scan_interval = value;
+               if (timer_pending(&local->passive_scan_timer))
+                       del_timer(&local->passive_scan_timer);
+               if (value > 0) {
+                       local->passive_scan_timer.expires = jiffies +
+                               local->passive_scan_interval * HZ;
+                       add_timer(&local->passive_scan_timer);
+               }
+               break;
+
+       case PRISM2_PARAM_ENH_SEC:
+               if (value < 0 || value > 3) {
+                       ret = -EINVAL;
+                       break;
+               }
+               local->enh_sec = value;
+               if (hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY,
+                                   local->enh_sec) ||
+                   local->func->reset_port(dev)) {
+                       printk(KERN_INFO "%s: cnfEnhSecurity requires STA f/w "
+                              "1.6.3 or newer\n", dev->name);
+                       ret = -EOPNOTSUPP;
+               }
+               break;
+
+#ifdef PRISM2_IO_DEBUG
+       case PRISM2_PARAM_IO_DEBUG:
+               local->io_debug_enabled = value;
+               break;
+#endif /* PRISM2_IO_DEBUG */
+
+       case PRISM2_PARAM_BASIC_RATES:
+               if ((value & local->tx_rate_control) != value || value == 0) {
+                       printk(KERN_INFO "%s: invalid basic rate set - basic "
+                              "rates must be in supported rate set\n",
+                              dev->name);
+                       ret = -EINVAL;
+                       break;
+               }
+               local->basic_rates = value;
+               if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES,
+                                   local->basic_rates) ||
+                   local->func->reset_port(dev))
+                       ret = -EINVAL;
+               break;
+
+       case PRISM2_PARAM_OPER_RATES:
+               local->tx_rate_control = value;
+               if (hostap_set_rate(dev))
+                       ret = -EINVAL;
+               break;
+
+       case PRISM2_PARAM_HOSTAPD:
+               ret = hostap_set_hostapd(local, value, 1);
+               break;
+
+       case PRISM2_PARAM_HOSTAPD_STA:
+               ret = hostap_set_hostapd_sta(local, value, 1);
+               break;
+
+       case PRISM2_PARAM_WPA:
+               local->wpa = value;
+               if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0))
+                       ret = -EOPNOTSUPP;
+               else if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE,
+                                        value ? 1 : 0))
+                       ret = -EINVAL;
+               break;
+
+       case PRISM2_PARAM_PRIVACY_INVOKED:
+               local->privacy_invoked = value;
+               if (hostap_set_encryption(local) ||
+                   local->func->reset_port(dev))
+                       ret = -EINVAL;
+               break;
+
+       case PRISM2_PARAM_TKIP_COUNTERMEASURES:
+               local->tkip_countermeasures = value;
+               break;
+
+       case PRISM2_PARAM_DROP_UNENCRYPTED:
+               local->drop_unencrypted = value;
+               break;
+
+       case PRISM2_PARAM_SCAN_CHANNEL_MASK:
+               local->scan_channel_mask = value;
+               break;
+
+       default:
+               printk(KERN_DEBUG "%s: prism2_param: unknown param %d\n",
+                      dev->name, param);
+               ret = -EOPNOTSUPP;
+               break;
+       }
+
+       return ret;
+}
+
+
+static int prism2_ioctl_priv_get_prism2_param(struct net_device *dev,
+                                             struct iw_request_info *info,
+                                             void *wrqu, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int *param = (int *) extra;
+       int ret = 0;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       switch (*param) {
+       case PRISM2_PARAM_TXRATECTRL:
+               *param = local->fw_tx_rate_control;
+               break;
+
+       case PRISM2_PARAM_BEACON_INT:
+               *param = local->beacon_int;
+               break;
+
+       case PRISM2_PARAM_PSEUDO_IBSS:
+               *param = local->pseudo_adhoc;
+               break;
+
+       case PRISM2_PARAM_ALC:
+               ret = -EOPNOTSUPP; /* FIX */
+               break;
+
+       case PRISM2_PARAM_DUMP:
+               *param = local->frame_dump;
+               break;
+
+       case PRISM2_PARAM_OTHER_AP_POLICY:
+               if (local->ap != NULL)
+                       *param = local->ap->ap_policy;
+               else
+                       ret = -EOPNOTSUPP;
+               break;
+
+       case PRISM2_PARAM_AP_MAX_INACTIVITY:
+               if (local->ap != NULL)
+                       *param = local->ap->max_inactivity / HZ;
+               else
+                       ret = -EOPNOTSUPP;
+               break;
+
+       case PRISM2_PARAM_AP_BRIDGE_PACKETS:
+               if (local->ap != NULL)
+                       *param = local->ap->bridge_packets;
+               else
+                       ret = -EOPNOTSUPP;
+               break;
+
+       case PRISM2_PARAM_DTIM_PERIOD:
+               *param = local->dtim_period;
+               break;
+
+       case PRISM2_PARAM_AP_NULLFUNC_ACK:
+               if (local->ap != NULL)
+                       *param = local->ap->nullfunc_ack;
+               else
+                       ret = -EOPNOTSUPP;
+               break;
+
+       case PRISM2_PARAM_MAX_WDS:
+               *param = local->wds_max_connections;
+               break;
+
+       case PRISM2_PARAM_AP_AUTOM_AP_WDS:
+               if (local->ap != NULL)
+                       *param = local->ap->autom_ap_wds;
+               else
+                       ret = -EOPNOTSUPP;
+               break;
+
+       case PRISM2_PARAM_AP_AUTH_ALGS:
+               *param = local->auth_algs;
+               break;
+
+       case PRISM2_PARAM_MONITOR_ALLOW_FCSERR:
+               *param = local->monitor_allow_fcserr;
+               break;
+
+       case PRISM2_PARAM_HOST_ENCRYPT:
+               *param = local->host_encrypt;
+               break;
+
+       case PRISM2_PARAM_HOST_DECRYPT:
+               *param = local->host_decrypt;
+               break;
+
+       case PRISM2_PARAM_HOST_ROAMING:
+               *param = local->host_roaming;
+               break;
+
+       case PRISM2_PARAM_BCRX_STA_KEY:
+               *param = local->bcrx_sta_key;
+               break;
+
+       case PRISM2_PARAM_IEEE_802_1X:
+               *param = local->ieee_802_1x;
+               break;
+
+       case PRISM2_PARAM_ANTSEL_TX:
+               *param = local->antsel_tx;
+               break;
+
+       case PRISM2_PARAM_ANTSEL_RX:
+               *param = local->antsel_rx;
+               break;
+
+       case PRISM2_PARAM_MONITOR_TYPE:
+               *param = local->monitor_type;
+               break;
+
+       case PRISM2_PARAM_WDS_TYPE:
+               *param = local->wds_type;
+               break;
+
+       case PRISM2_PARAM_HOSTSCAN:
+               ret = -EOPNOTSUPP;
+               break;
+
+       case PRISM2_PARAM_AP_SCAN:
+               *param = local->passive_scan_interval;
+               break;
+
+       case PRISM2_PARAM_ENH_SEC:
+               *param = local->enh_sec;
+               break;
+
+#ifdef PRISM2_IO_DEBUG
+       case PRISM2_PARAM_IO_DEBUG:
+               *param = local->io_debug_enabled;
+               break;
+#endif /* PRISM2_IO_DEBUG */
+
+       case PRISM2_PARAM_BASIC_RATES:
+               *param = local->basic_rates;
+               break;
+
+       case PRISM2_PARAM_OPER_RATES:
+               *param = local->tx_rate_control;
+               break;
+
+       case PRISM2_PARAM_HOSTAPD:
+               *param = local->hostapd;
+               break;
+
+       case PRISM2_PARAM_HOSTAPD_STA:
+               *param = local->hostapd_sta;
+               break;
+
+       case PRISM2_PARAM_WPA:
+               if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0))
+                       ret = -EOPNOTSUPP;
+               *param = local->wpa;
+               break;
+
+       case PRISM2_PARAM_PRIVACY_INVOKED:
+               *param = local->privacy_invoked;
+               break;
+
+       case PRISM2_PARAM_TKIP_COUNTERMEASURES:
+               *param = local->tkip_countermeasures;
+               break;
+
+       case PRISM2_PARAM_DROP_UNENCRYPTED:
+               *param = local->drop_unencrypted;
+               break;
+
+       case PRISM2_PARAM_SCAN_CHANNEL_MASK:
+               *param = local->scan_channel_mask;
+               break;
+
+       default:
+               printk(KERN_DEBUG "%s: get_prism2_param: unknown param %d\n",
+                      dev->name, *param);
+               ret = -EOPNOTSUPP;
+               break;
+       }
+
+       return ret;
+}
+
+
+static int prism2_ioctl_priv_readmif(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    void *wrqu, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       u16 resp0;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, *extra, NULL,
+                            &resp0))
+               return -EOPNOTSUPP;
+       else
+               *extra = resp0;
+
+       return 0;
+}
+
+
+static int prism2_ioctl_priv_writemif(struct net_device *dev,
+                                     struct iw_request_info *info,
+                                     void *wrqu, char *extra)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       u16 cr, val;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       cr = *extra;
+       val = *(extra + 1);
+       if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, cr, &val, NULL))
+               return -EOPNOTSUPP;
+
+       return 0;
+}
+
+
+static int prism2_ioctl_priv_monitor(struct net_device *dev, int *i)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int ret = 0;
+       u32 mode;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       printk(KERN_DEBUG "%s: process %d (%s) used deprecated iwpriv monitor "
+              "- update software to use iwconfig mode monitor\n",
+              dev->name, current->pid, current->comm);
+
+       /* Backward compatibility code - this can be removed at some point */
+
+       if (*i == 0) {
+               /* Disable monitor mode - old mode was not saved, so go to
+                * Master mode */
+               mode = IW_MODE_MASTER;
+               ret = prism2_ioctl_siwmode(dev, NULL, &mode, NULL);
+       } else if (*i == 1) {
+               /* netlink socket mode is not supported anymore since it did
+                * not separate different devices from each other and was not
+                * best method for delivering large amount of packets to
+                * user space */
+               ret = -EOPNOTSUPP;
+       } else if (*i == 2 || *i == 3) {
+               switch (*i) {
+               case 2:
+                       local->monitor_type = PRISM2_MONITOR_80211;
+                       break;
+               case 3:
+                       local->monitor_type = PRISM2_MONITOR_PRISM;
+                       break;
+               }
+               mode = IW_MODE_MONITOR;
+               ret = prism2_ioctl_siwmode(dev, NULL, &mode, NULL);
+               hostap_monitor_mode_enable(local);
+       } else
+               ret = -EINVAL;
+
+       return ret;
+}
+
+
+static int prism2_ioctl_priv_reset(struct net_device *dev, int *i)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       printk(KERN_DEBUG "%s: manual reset request(%d)\n", dev->name, *i);
+       switch (*i) {
+       case 0:
+               /* Disable and enable card */
+               local->func->hw_shutdown(dev, 1);
+               local->func->hw_config(dev, 0);
+               break;
+
+       case 1:
+               /* COR sreset */
+               local->func->hw_reset(dev);
+               break;
+
+       case 2:
+               /* Disable and enable port 0 */
+               local->func->reset_port(dev);
+               break;
+
+       case 3:
+               prism2_sta_deauth(local, WLAN_REASON_DEAUTH_LEAVING);
+               if (local->func->cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL,
+                                    NULL))
+                       return -EINVAL;
+               break;
+
+       case 4:
+               if (local->func->cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL,
+                                    NULL))
+                       return -EINVAL;
+               break;
+
+       default:
+               printk(KERN_DEBUG "Unknown reset request %d\n", *i);
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+
+static int prism2_ioctl_priv_set_rid_word(struct net_device *dev, int *i)
+{
+       int rid = *i;
+       int value = *(i + 1);
+
+       printk(KERN_DEBUG "%s: Set RID[0x%X] = %d\n", dev->name, rid, value);
+
+       if (hostap_set_word(dev, rid, value))
+               return -EINVAL;
+
+       return 0;
+}
+
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+static int ap_mac_cmd_ioctl(local_info_t *local, int *cmd)
+{
+       int ret = 0;
+
+       switch (*cmd) {
+       case AP_MAC_CMD_POLICY_OPEN:
+               local->ap->mac_restrictions.policy = MAC_POLICY_OPEN;
+               break;
+       case AP_MAC_CMD_POLICY_ALLOW:
+               local->ap->mac_restrictions.policy = MAC_POLICY_ALLOW;
+               break;
+       case AP_MAC_CMD_POLICY_DENY:
+               local->ap->mac_restrictions.policy = MAC_POLICY_DENY;
+               break;
+       case AP_MAC_CMD_FLUSH:
+               ap_control_flush_macs(&local->ap->mac_restrictions);
+               break;
+       case AP_MAC_CMD_KICKALL:
+               ap_control_kickall(local->ap);
+               hostap_deauth_all_stas(local->dev, local->ap, 0);
+               break;
+       default:
+               ret = -EOPNOTSUPP;
+               break;
+       }
+
+       return ret;
+}
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p)
+{
+       struct prism2_download_param *param;
+       int ret = 0;
+
+       if (p->length < sizeof(struct prism2_download_param) ||
+           p->length > 1024 || !p->pointer)
+               return -EINVAL;
+
+       param = (struct prism2_download_param *)
+               kmalloc(p->length, GFP_KERNEL);
+       if (param == NULL)
+               return -ENOMEM;
+
+       if (copy_from_user(param, p->pointer, p->length)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       if (p->length < sizeof(struct prism2_download_param) +
+           param->num_areas * sizeof(struct prism2_download_area)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = local->func->download(local, param);
+
+ out:
+       if (param != NULL)
+               kfree(param);
+
+       return ret;
+}
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+
+
+static int prism2_set_genericelement(struct net_device *dev, u8 *elem,
+                                    size_t len)
+{
+       struct hostap_interface *iface = dev->priv;
+       local_info_t *local = iface->local;
+       u8 *buf;
+
+       /*
+        * Add 16-bit length in the beginning of the buffer because Prism2 RID
+        * includes it.
+        */
+       buf = kmalloc(len + 2, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
+
+       *((u16 *) buf) = cpu_to_le16(len);
+       memcpy(buf + 2, elem, len);
+
+       kfree(local->generic_elem);
+       local->generic_elem = buf;
+       local->generic_elem_len = len + 2;
+
+       return local->func->set_rid(local->dev, HFA384X_RID_GENERICELEMENT,
+                                   buf, len + 2);
+}
+
+
+static int prism2_ioctl_siwauth(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_param *data, char *extra)
+{
+       struct hostap_interface *iface = dev->priv;
+       local_info_t *local = iface->local;
+
+       switch (data->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_WPA_VERSION:
+       case IW_AUTH_CIPHER_PAIRWISE:
+       case IW_AUTH_CIPHER_GROUP:
+       case IW_AUTH_KEY_MGMT:
+               /*
+                * Host AP driver does not use these parameters and allows
+                * wpa_supplicant to control them internally.
+                */
+               break;
+       case IW_AUTH_TKIP_COUNTERMEASURES:
+               local->tkip_countermeasures = data->value;
+               break;
+       case IW_AUTH_DROP_UNENCRYPTED:
+               local->drop_unencrypted = data->value;
+               break;
+       case IW_AUTH_80211_AUTH_ALG:
+               local->auth_algs = data->value;
+               break;
+       case IW_AUTH_WPA_ENABLED:
+               if (data->value == 0) {
+                       local->wpa = 0;
+                       if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0))
+                               break;
+                       prism2_set_genericelement(dev, "", 0);
+                       local->host_roaming = 0;
+                       local->privacy_invoked = 0;
+                       if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE,
+                                           0) ||
+                           hostap_set_roaming(local) ||
+                           hostap_set_encryption(local) ||
+                           local->func->reset_port(dev))
+                               return -EINVAL;
+                       break;
+               }
+               if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0))
+                       return -EOPNOTSUPP;
+               local->host_roaming = 2;
+               local->privacy_invoked = 1;
+               local->wpa = 1;
+               if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1) ||
+                   hostap_set_roaming(local) ||
+                   hostap_set_encryption(local) ||
+                   local->func->reset_port(dev))
+                       return -EINVAL;
+               break;
+       case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+               local->ieee_802_1x = data->value;
+               break;
+       case IW_AUTH_PRIVACY_INVOKED:
+               local->privacy_invoked = data->value;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+
+static int prism2_ioctl_giwauth(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_param *data, char *extra)
+{
+       struct hostap_interface *iface = dev->priv;
+       local_info_t *local = iface->local;
+
+       switch (data->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_WPA_VERSION:
+       case IW_AUTH_CIPHER_PAIRWISE:
+       case IW_AUTH_CIPHER_GROUP:
+       case IW_AUTH_KEY_MGMT:
+               /*
+                * Host AP driver does not use these parameters and allows
+                * wpa_supplicant to control them internally.
+                */
+               return -EOPNOTSUPP;
+       case IW_AUTH_TKIP_COUNTERMEASURES:
+               data->value = local->tkip_countermeasures;
+               break;
+       case IW_AUTH_DROP_UNENCRYPTED:
+               data->value = local->drop_unencrypted;
+               break;
+       case IW_AUTH_80211_AUTH_ALG:
+               data->value = local->auth_algs;
+               break;
+       case IW_AUTH_WPA_ENABLED:
+               data->value = local->wpa;
+               break;
+       case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+               data->value = local->ieee_802_1x;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+
+static int prism2_ioctl_siwencodeext(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    struct iw_point *erq, char *extra)
+{
+       struct hostap_interface *iface = dev->priv;
+       local_info_t *local = iface->local;
+       struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
+       int i, ret = 0;
+       struct ieee80211_crypto_ops *ops;
+       struct ieee80211_crypt_data **crypt;
+       void *sta_ptr;
+       u8 *addr;
+       const char *alg, *module;
+
+       i = erq->flags & IW_ENCODE_INDEX;
+       if (i > WEP_KEYS)
+               return -EINVAL;
+       if (i < 1 || i > WEP_KEYS)
+               i = local->tx_keyidx;
+       else
+               i--;
+       if (i < 0 || i >= WEP_KEYS)
+               return -EINVAL;
+
+       addr = ext->addr.sa_data;
+       if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff &&
+           addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) {
+               sta_ptr = NULL;
+               crypt = &local->crypt[i];
+       } else {
+               if (i != 0)
+                       return -EINVAL;
+               sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt);
+               if (sta_ptr == NULL) {
+                       if (local->iw_mode == IW_MODE_INFRA) {
+                               /*
+                                * TODO: add STA entry for the current AP so
+                                * that unicast key can be used. For now, this
+                                * is emulated by using default key idx 0.
+                                */
+                               i = 0;
+                               crypt = &local->crypt[i];
+                       } else
+                               return -EINVAL;
+               }
+       }
+
+       if ((erq->flags & IW_ENCODE_DISABLED) ||
+           ext->alg == IW_ENCODE_ALG_NONE) {
+               if (*crypt)
+                       prism2_crypt_delayed_deinit(local, crypt);
+               goto done;
+       }
+
+       switch (ext->alg) {
+       case IW_ENCODE_ALG_WEP:
+               alg = "WEP";
+               module = "ieee80211_crypt_wep";
+               break;
+       case IW_ENCODE_ALG_TKIP:
+               alg = "TKIP";
+               module = "ieee80211_crypt_tkip";
+               break;
+       case IW_ENCODE_ALG_CCMP:
+               alg = "CCMP";
+               module = "ieee80211_crypt_ccmp";
+               break;
+       default:
+               printk(KERN_DEBUG "%s: unsupported algorithm %d\n",
+                      local->dev->name, ext->alg);
+               ret = -EOPNOTSUPP;
+               goto done;
+       }
+
+       ops = ieee80211_get_crypto_ops(alg);
+       if (ops == NULL) {
+               request_module(module);
+               ops = ieee80211_get_crypto_ops(alg);
+       }
+       if (ops == NULL) {
+               printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n",
+                      local->dev->name, alg);
+               ret = -EOPNOTSUPP;
+               goto done;
+       }
+
+       if (sta_ptr || ext->alg != IW_ENCODE_ALG_WEP) {
+               /*
+                * Per station encryption and other than WEP algorithms
+                * require host-based encryption, so force them on
+                * automatically.
+                */
+               local->host_decrypt = local->host_encrypt = 1;
+       }
+
+       if (*crypt == NULL || (*crypt)->ops != ops) {
+               struct ieee80211_crypt_data *new_crypt;
+
+               prism2_crypt_delayed_deinit(local, crypt);
+
+               new_crypt = (struct ieee80211_crypt_data *)
+                       kmalloc(sizeof(struct ieee80211_crypt_data),
+                               GFP_KERNEL);
+               if (new_crypt == NULL) {
+                       ret = -ENOMEM;
+                       goto done;
+               }
+               memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
+               new_crypt->ops = ops;
+               new_crypt->priv = new_crypt->ops->init(i);
+               if (new_crypt->priv == NULL) {
+                       kfree(new_crypt);
+                       ret = -EINVAL;
+                       goto done;
+               }
+
+               *crypt = new_crypt;
+       }
+
+       /*
+        * TODO: if ext_flags does not have IW_ENCODE_EXT_RX_SEQ_VALID, the
+        * existing seq# should not be changed.
+        * TODO: if ext_flags has IW_ENCODE_EXT_TX_SEQ_VALID, next TX seq#
+        * should be changed to something else than zero.
+        */
+       if ((!(ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) || ext->key_len > 0)
+           && (*crypt)->ops->set_key &&
+           (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
+                                  (*crypt)->priv) < 0) {
+               printk(KERN_DEBUG "%s: key setting failed\n",
+                      local->dev->name);
+               ret = -EINVAL;
+               goto done;
+       }
+
+       if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+               if (!sta_ptr)
+                       local->tx_keyidx = i;
+               else if (i) {
+                       ret = -EINVAL;
+                       goto done;
+               }
+       }
+
+
+       if (sta_ptr == NULL && ext->key_len > 0) {
+               int first = 1, j;
+               for (j = 0; j < WEP_KEYS; j++) {
+                       if (j != i && local->crypt[j]) {
+                               first = 0;
+                               break;
+                       }
+               }
+               if (first)
+                       local->tx_keyidx = i;
+       }
+
+ done:
+       if (sta_ptr)
+               hostap_handle_sta_release(sta_ptr);
+
+       local->open_wep = erq->flags & IW_ENCODE_OPEN;
+
+       /*
+        * Do not reset port0 if card is in Managed mode since resetting will
+        * generate new IEEE 802.11 authentication which may end up in looping
+        * with IEEE 802.1X. Prism2 documentation seem to require port reset
+        * after WEP configuration. However, keys are apparently changed at
+        * least in Managed mode.
+        */
+       if (ret == 0 &&
+           (hostap_set_encryption(local) ||
+            (local->iw_mode != IW_MODE_INFRA &&
+             local->func->reset_port(local->dev))))
+               ret = -EINVAL;
+
+       return ret;
+}
+
+
+static int prism2_ioctl_giwencodeext(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    struct iw_point *erq, char *extra)
+{
+       struct hostap_interface *iface = dev->priv;
+       local_info_t *local = iface->local;
+       struct ieee80211_crypt_data **crypt;
+       void *sta_ptr;
+       int max_key_len, i;
+       struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
+       u8 *addr;
+
+       max_key_len = erq->length - sizeof(*ext);
+       if (max_key_len < 0)
+               return -EINVAL;
+
+       i = erq->flags & IW_ENCODE_INDEX;
+       if (i < 1 || i > WEP_KEYS)
+               i = local->tx_keyidx;
+       else
+               i--;
+
+       addr = ext->addr.sa_data;
+       if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff &&
+           addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) {
+               sta_ptr = NULL;
+               crypt = &local->crypt[i];
+       } else {
+               i = 0;
+               sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt);
+               if (sta_ptr == NULL)
+                       return -EINVAL;
+       }
+       erq->flags = i + 1;
+       memset(ext, 0, sizeof(*ext));
+
+       if (*crypt == NULL || (*crypt)->ops == NULL) {
+               ext->alg = IW_ENCODE_ALG_NONE;
+               ext->key_len = 0;
+               erq->flags |= IW_ENCODE_DISABLED;
+       } else {
+               if (strcmp((*crypt)->ops->name, "WEP") == 0)
+                       ext->alg = IW_ENCODE_ALG_WEP;
+               else if (strcmp((*crypt)->ops->name, "TKIP") == 0)
+                       ext->alg = IW_ENCODE_ALG_TKIP;
+               else if (strcmp((*crypt)->ops->name, "CCMP") == 0)
+                       ext->alg = IW_ENCODE_ALG_CCMP;
+               else
+                       return -EINVAL;
+
+               if ((*crypt)->ops->get_key) {
+                       ext->key_len =
+                               (*crypt)->ops->get_key(ext->key,
+                                                      max_key_len,
+                                                      ext->tx_seq,
+                                                      (*crypt)->priv);
+                       if (ext->key_len &&
+                           (ext->alg == IW_ENCODE_ALG_TKIP ||
+                            ext->alg == IW_ENCODE_ALG_CCMP))
+                               ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
+               }
+       }
+
+       if (sta_ptr)
+               hostap_handle_sta_release(sta_ptr);
+
+       return 0;
+}
+
+
+static int prism2_ioctl_set_encryption(local_info_t *local,
+                                      struct prism2_hostapd_param *param,
+                                      int param_len)
+{
+       int ret = 0;
+       struct ieee80211_crypto_ops *ops;
+       struct ieee80211_crypt_data **crypt;
+       void *sta_ptr;
+
+       param->u.crypt.err = 0;
+       param->u.crypt.alg[HOSTAP_CRYPT_ALG_NAME_LEN - 1] = '\0';
+
+       if (param_len !=
+           (int) ((char *) param->u.crypt.key - (char *) param) +
+           param->u.crypt.key_len)
+               return -EINVAL;
+
+       if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+           param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+           param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+               if (param->u.crypt.idx >= WEP_KEYS)
+                       return -EINVAL;
+               sta_ptr = NULL;
+               crypt = &local->crypt[param->u.crypt.idx];
+       } else {
+               if (param->u.crypt.idx)
+                       return -EINVAL;
+               sta_ptr = ap_crypt_get_ptrs(
+                       local->ap, param->sta_addr,
+                       (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_PERMANENT),
+                       &crypt);
+
+               if (sta_ptr == NULL) {
+                       param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
+                       return -EINVAL;
+               }
+       }
+
+       if (strcmp(param->u.crypt.alg, "none") == 0) {
+               if (crypt)
+                       prism2_crypt_delayed_deinit(local, crypt);
+               goto done;
+       }
+
+       ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+       if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) {
+               request_module("ieee80211_crypt_wep");
+               ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+       } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) {
+               request_module("ieee80211_crypt_tkip");
+               ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+       } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) {
+               request_module("ieee80211_crypt_ccmp");
+               ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+       }
+       if (ops == NULL) {
+               printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n",
+                      local->dev->name, param->u.crypt.alg);
+               param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ALG;
+               ret = -EINVAL;
+               goto done;
+       }
+
+       /* station based encryption and other than WEP algorithms require
+        * host-based encryption, so force them on automatically */
+       local->host_decrypt = local->host_encrypt = 1;
+
+       if (*crypt == NULL || (*crypt)->ops != ops) {
+               struct ieee80211_crypt_data *new_crypt;
+
+               prism2_crypt_delayed_deinit(local, crypt);
+
+               new_crypt = (struct ieee80211_crypt_data *)
+                       kmalloc(sizeof(struct ieee80211_crypt_data),
+                               GFP_KERNEL);
+               if (new_crypt == NULL) {
+                       ret = -ENOMEM;
+                       goto done;
+               }
+               memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
+               new_crypt->ops = ops;
+               new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx);
+               if (new_crypt->priv == NULL) {
+                       kfree(new_crypt);
+                       param->u.crypt.err =
+                               HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED;
+                       ret = -EINVAL;
+                       goto done;
+               }
+
+               *crypt = new_crypt;
+       }
+
+       if ((!(param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) ||
+            param->u.crypt.key_len > 0) && (*crypt)->ops->set_key &&
+           (*crypt)->ops->set_key(param->u.crypt.key,
+                                  param->u.crypt.key_len, param->u.crypt.seq,
+                                  (*crypt)->priv) < 0) {
+               printk(KERN_DEBUG "%s: key setting failed\n",
+                      local->dev->name);
+               param->u.crypt.err = HOSTAP_CRYPT_ERR_KEY_SET_FAILED;
+               ret = -EINVAL;
+               goto done;
+       }
+
+       if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) {
+               if (!sta_ptr)
+                       local->tx_keyidx = param->u.crypt.idx;
+               else if (param->u.crypt.idx) {
+                       printk(KERN_DEBUG "%s: TX key idx setting failed\n",
+                              local->dev->name);
+                       param->u.crypt.err =
+                               HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED;
+                       ret = -EINVAL;
+                       goto done;
+               }
+       }
+
+ done:
+       if (sta_ptr)
+               hostap_handle_sta_release(sta_ptr);
+
+       /* Do not reset port0 if card is in Managed mode since resetting will
+        * generate new IEEE 802.11 authentication which may end up in looping
+        * with IEEE 802.1X. Prism2 documentation seem to require port reset
+        * after WEP configuration. However, keys are apparently changed at
+        * least in Managed mode. */
+       if (ret == 0 &&
+           (hostap_set_encryption(local) ||
+            (local->iw_mode != IW_MODE_INFRA &&
+             local->func->reset_port(local->dev)))) {
+               param->u.crypt.err = HOSTAP_CRYPT_ERR_CARD_CONF_FAILED;
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
+
+static int prism2_ioctl_get_encryption(local_info_t *local,
+                                      struct prism2_hostapd_param *param,
+                                      int param_len)
+{
+       struct ieee80211_crypt_data **crypt;
+       void *sta_ptr;
+       int max_key_len;
+
+       param->u.crypt.err = 0;
+
+       max_key_len = param_len -
+               (int) ((char *) param->u.crypt.key - (char *) param);
+       if (max_key_len < 0)
+               return -EINVAL;
+
+       if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+           param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+           param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+               sta_ptr = NULL;
+               if (param->u.crypt.idx >= WEP_KEYS)
+                       param->u.crypt.idx = local->tx_keyidx;
+               crypt = &local->crypt[param->u.crypt.idx];
+       } else {
+               param->u.crypt.idx = 0;
+               sta_ptr = ap_crypt_get_ptrs(local->ap, param->sta_addr, 0,
+                                           &crypt);
+
+               if (sta_ptr == NULL) {
+                       param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
+                       return -EINVAL;
+               }
+       }
+
+       if (*crypt == NULL || (*crypt)->ops == NULL) {
+               memcpy(param->u.crypt.alg, "none", 5);
+               param->u.crypt.key_len = 0;
+               param->u.crypt.idx = 0xff;
+       } else {
+               strncpy(param->u.crypt.alg, (*crypt)->ops->name,
+                       HOSTAP_CRYPT_ALG_NAME_LEN);
+               param->u.crypt.key_len = 0;
+
+               memset(param->u.crypt.seq, 0, 8);
+               if ((*crypt)->ops->get_key) {
+                       param->u.crypt.key_len =
+                               (*crypt)->ops->get_key(param->u.crypt.key,
+                                                      max_key_len,
+                                                      param->u.crypt.seq,
+                                                      (*crypt)->priv);
+               }
+       }
+
+       if (sta_ptr)
+               hostap_handle_sta_release(sta_ptr);
+
+       return 0;
+}
+
+
+static int prism2_ioctl_get_rid(local_info_t *local,
+                               struct prism2_hostapd_param *param,
+                               int param_len)
+{
+       int max_len, res;
+
+       max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN;
+       if (max_len < 0)
+               return -EINVAL;
+
+       res = local->func->get_rid(local->dev, param->u.rid.rid,
+                                  param->u.rid.data, param->u.rid.len, 0);
+       if (res >= 0) {
+               param->u.rid.len = res;
+               return 0;
+       }
+
+       return res;
+}
+
+
+static int prism2_ioctl_set_rid(local_info_t *local,
+                               struct prism2_hostapd_param *param,
+                               int param_len)
+{
+       int max_len;
+
+       max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN;
+       if (max_len < 0 || max_len < param->u.rid.len)
+               return -EINVAL;
+
+       return local->func->set_rid(local->dev, param->u.rid.rid,
+                                   param->u.rid.data, param->u.rid.len);
+}
+
+
+static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local,
+                                         struct prism2_hostapd_param *param,
+                                         int param_len)
+{
+       printk(KERN_DEBUG "%ssta: associated as client with AP " MACSTR "\n",
+              local->dev->name, MAC2STR(param->sta_addr));
+       memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN);
+       return 0;
+}
+
+
+static int prism2_ioctl_siwgenie(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_point *data, char *extra)
+{
+       return prism2_set_genericelement(dev, extra, data->length);
+}
+
+
+static int prism2_ioctl_giwgenie(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_point *data, char *extra)
+{
+       struct hostap_interface *iface = dev->priv;
+       local_info_t *local = iface->local;
+       int len = local->generic_elem_len - 2;
+
+       if (len <= 0 || local->generic_elem == NULL) {
+               data->length = 0;
+               return 0;
+       }
+
+       if (data->length < len)
+               return -E2BIG;
+
+       data->length = len;
+       memcpy(extra, local->generic_elem + 2, len);
+
+       return 0;
+}
+
+
+static int prism2_ioctl_set_generic_element(local_info_t *local,
+                                           struct prism2_hostapd_param *param,
+                                           int param_len)
+{
+       int max_len, len;
+
+       len = param->u.generic_elem.len;
+       max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
+       if (max_len < 0 || max_len < len)
+               return -EINVAL;
+
+       return prism2_set_genericelement(local->dev,
+                                        param->u.generic_elem.data, len);
+}
+
+
+static int prism2_ioctl_siwmlme(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_point *data, char *extra)
+{
+       struct hostap_interface *iface = dev->priv;
+       local_info_t *local = iface->local;
+       struct iw_mlme *mlme = (struct iw_mlme *) extra;
+       u16 reason;
+
+       reason = cpu_to_le16(mlme->reason_code);
+
+       switch (mlme->cmd) {
+       case IW_MLME_DEAUTH:
+               return prism2_sta_send_mgmt(local, mlme->addr.sa_data,
+                                           IEEE80211_STYPE_DEAUTH,
+                                           (u8 *) &reason, 2);
+       case IW_MLME_DISASSOC:
+               return prism2_sta_send_mgmt(local, mlme->addr.sa_data,
+                                           IEEE80211_STYPE_DISASSOC,
+                                           (u8 *) &reason, 2);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+
+static int prism2_ioctl_mlme(local_info_t *local,
+                            struct prism2_hostapd_param *param)
+{
+       u16 reason;
+
+       reason = cpu_to_le16(param->u.mlme.reason_code);
+       switch (param->u.mlme.cmd) {
+       case MLME_STA_DEAUTH:
+               return prism2_sta_send_mgmt(local, param->sta_addr,
+                                           IEEE80211_STYPE_DEAUTH,
+                                           (u8 *) &reason, 2);
+       case MLME_STA_DISASSOC:
+               return prism2_sta_send_mgmt(local, param->sta_addr,
+                                           IEEE80211_STYPE_DISASSOC,
+                                           (u8 *) &reason, 2);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+
+static int prism2_ioctl_scan_req(local_info_t *local,
+                                struct prism2_hostapd_param *param)
+{
+#ifndef PRISM2_NO_STATION_MODES
+       if ((local->iw_mode != IW_MODE_INFRA &&
+            local->iw_mode != IW_MODE_ADHOC) ||
+           (local->sta_fw_ver < PRISM2_FW_VER(1,3,1)))
+               return -EOPNOTSUPP;
+
+       if (!local->dev_enabled)
+               return -ENETDOWN;
+
+       return prism2_request_hostscan(local->dev, param->u.scan_req.ssid,
+                                      param->u.scan_req.ssid_len);
+#else /* PRISM2_NO_STATION_MODES */
+       return -EOPNOTSUPP;
+#endif /* PRISM2_NO_STATION_MODES */
+}
+
+
+static int prism2_ioctl_priv_hostapd(local_info_t *local, struct iw_point *p)
+{
+       struct prism2_hostapd_param *param;
+       int ret = 0;
+       int ap_ioctl = 0;
+
+       if (p->length < sizeof(struct prism2_hostapd_param) ||
+           p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
+               return -EINVAL;
+
+       param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL);
+       if (param == NULL)
+               return -ENOMEM;
+
+       if (copy_from_user(param, p->pointer, p->length)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       switch (param->cmd) {
+       case PRISM2_SET_ENCRYPTION:
+               ret = prism2_ioctl_set_encryption(local, param, p->length);
+               break;
+       case PRISM2_GET_ENCRYPTION:
+               ret = prism2_ioctl_get_encryption(local, param, p->length);
+               break;
+       case PRISM2_HOSTAPD_GET_RID:
+               ret = prism2_ioctl_get_rid(local, param, p->length);
+               break;
+       case PRISM2_HOSTAPD_SET_RID:
+               ret = prism2_ioctl_set_rid(local, param, p->length);
+               break;
+       case PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR:
+               ret = prism2_ioctl_set_assoc_ap_addr(local, param, p->length);
+               break;
+       case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT:
+               ret = prism2_ioctl_set_generic_element(local, param,
+                                                      p->length);
+               break;
+       case PRISM2_HOSTAPD_MLME:
+               ret = prism2_ioctl_mlme(local, param);
+               break;
+       case PRISM2_HOSTAPD_SCAN_REQ:
+               ret = prism2_ioctl_scan_req(local, param);
+               break;
+       default:
+               ret = prism2_hostapd(local->ap, param);
+               ap_ioctl = 1;
+               break;
+       }
+
+       if (ret == 1 || !ap_ioctl) {
+               if (copy_to_user(p->pointer, param, p->length)) {
+                       ret = -EFAULT;
+                       goto out;
+               } else if (ap_ioctl)
+                       ret = 0;
+       }
+
+ out:
+       if (param != NULL)
+               kfree(param);
+
+       return ret;
+}
+
+
+static void prism2_get_drvinfo(struct net_device *dev,
+                              struct ethtool_drvinfo *info)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       strncpy(info->driver, "hostap", sizeof(info->driver) - 1);
+       strncpy(info->version, PRISM2_VERSION,
+               sizeof(info->version) - 1);
+       snprintf(info->fw_version, sizeof(info->fw_version) - 1,
+                "%d.%d.%d", (local->sta_fw_ver >> 16) & 0xff,
+                (local->sta_fw_ver >> 8) & 0xff,
+                local->sta_fw_ver & 0xff);
+}
+
+static struct ethtool_ops prism2_ethtool_ops = {
+       .get_drvinfo = prism2_get_drvinfo
+};
+
+
+/* Structures to export the Wireless Handlers */
+
+static const iw_handler prism2_handler[] =
+{
+       (iw_handler) NULL,                              /* SIOCSIWCOMMIT */
+       (iw_handler) prism2_get_name,                   /* SIOCGIWNAME */
+       (iw_handler) NULL,                              /* SIOCSIWNWID */
+       (iw_handler) NULL,                              /* SIOCGIWNWID */
+       (iw_handler) prism2_ioctl_siwfreq,              /* SIOCSIWFREQ */
+       (iw_handler) prism2_ioctl_giwfreq,              /* SIOCGIWFREQ */
+       (iw_handler) prism2_ioctl_siwmode,              /* SIOCSIWMODE */
+       (iw_handler) prism2_ioctl_giwmode,              /* SIOCGIWMODE */
+       (iw_handler) prism2_ioctl_siwsens,              /* SIOCSIWSENS */
+       (iw_handler) prism2_ioctl_giwsens,              /* SIOCGIWSENS */
+       (iw_handler) NULL /* not used */,               /* SIOCSIWRANGE */
+       (iw_handler) prism2_ioctl_giwrange,             /* SIOCGIWRANGE */
+       (iw_handler) NULL /* not used */,               /* SIOCSIWPRIV */
+       (iw_handler) NULL /* kernel code */,            /* SIOCGIWPRIV */
+       (iw_handler) NULL /* not used */,               /* SIOCSIWSTATS */
+       (iw_handler) NULL /* kernel code */,            /* SIOCGIWSTATS */
+       iw_handler_set_spy,                             /* SIOCSIWSPY */
+       iw_handler_get_spy,                             /* SIOCGIWSPY */
+       iw_handler_set_thrspy,                          /* SIOCSIWTHRSPY */
+       iw_handler_get_thrspy,                          /* SIOCGIWTHRSPY */
+       (iw_handler) prism2_ioctl_siwap,                /* SIOCSIWAP */
+       (iw_handler) prism2_ioctl_giwap,                /* SIOCGIWAP */
+       (iw_handler) prism2_ioctl_siwmlme,              /* SIOCSIWMLME */
+       (iw_handler) prism2_ioctl_giwaplist,            /* SIOCGIWAPLIST */
+       (iw_handler) prism2_ioctl_siwscan,              /* SIOCSIWSCAN */
+       (iw_handler) prism2_ioctl_giwscan,              /* SIOCGIWSCAN */
+       (iw_handler) prism2_ioctl_siwessid,             /* SIOCSIWESSID */
+       (iw_handler) prism2_ioctl_giwessid,             /* SIOCGIWESSID */
+       (iw_handler) prism2_ioctl_siwnickn,             /* SIOCSIWNICKN */
+       (iw_handler) prism2_ioctl_giwnickn,             /* SIOCGIWNICKN */
+       (iw_handler) NULL,                              /* -- hole -- */
+       (iw_handler) NULL,                              /* -- hole -- */
+       (iw_handler) prism2_ioctl_siwrate,              /* SIOCSIWRATE */
+       (iw_handler) prism2_ioctl_giwrate,              /* SIOCGIWRATE */
+       (iw_handler) prism2_ioctl_siwrts,               /* SIOCSIWRTS */
+       (iw_handler) prism2_ioctl_giwrts,               /* SIOCGIWRTS */
+       (iw_handler) prism2_ioctl_siwfrag,              /* SIOCSIWFRAG */
+       (iw_handler) prism2_ioctl_giwfrag,              /* SIOCGIWFRAG */
+       (iw_handler) prism2_ioctl_siwtxpow,             /* SIOCSIWTXPOW */
+       (iw_handler) prism2_ioctl_giwtxpow,             /* SIOCGIWTXPOW */
+       (iw_handler) prism2_ioctl_siwretry,             /* SIOCSIWRETRY */
+       (iw_handler) prism2_ioctl_giwretry,             /* SIOCGIWRETRY */
+       (iw_handler) prism2_ioctl_siwencode,            /* SIOCSIWENCODE */
+       (iw_handler) prism2_ioctl_giwencode,            /* SIOCGIWENCODE */
+       (iw_handler) prism2_ioctl_siwpower,             /* SIOCSIWPOWER */
+       (iw_handler) prism2_ioctl_giwpower,             /* SIOCGIWPOWER */
+       (iw_handler) NULL,                              /* -- hole -- */
+       (iw_handler) NULL,                              /* -- hole -- */
+       (iw_handler) prism2_ioctl_siwgenie,             /* SIOCSIWGENIE */
+       (iw_handler) prism2_ioctl_giwgenie,             /* SIOCGIWGENIE */
+       (iw_handler) prism2_ioctl_siwauth,              /* SIOCSIWAUTH */
+       (iw_handler) prism2_ioctl_giwauth,              /* SIOCGIWAUTH */
+       (iw_handler) prism2_ioctl_siwencodeext,         /* SIOCSIWENCODEEXT */
+       (iw_handler) prism2_ioctl_giwencodeext,         /* SIOCGIWENCODEEXT */
+       (iw_handler) NULL,                              /* SIOCSIWPMKSA */
+       (iw_handler) NULL,                              /* -- hole -- */
+};
+
+static const iw_handler prism2_private_handler[] =
+{                                                      /* SIOCIWFIRSTPRIV + */
+       (iw_handler) prism2_ioctl_priv_prism2_param,    /* 0 */
+       (iw_handler) prism2_ioctl_priv_get_prism2_param, /* 1 */
+       (iw_handler) prism2_ioctl_priv_writemif,        /* 2 */
+       (iw_handler) prism2_ioctl_priv_readmif,         /* 3 */
+};
+
+static const struct iw_handler_def hostap_iw_handler_def =
+{
+       .num_standard   = sizeof(prism2_handler) / sizeof(iw_handler),
+       .num_private    = sizeof(prism2_private_handler) / sizeof(iw_handler),
+       .num_private_args = sizeof(prism2_priv) / sizeof(struct iw_priv_args),
+       .standard       = (iw_handler *) prism2_handler,
+       .private        = (iw_handler *) prism2_private_handler,
+       .private_args   = (struct iw_priv_args *) prism2_priv,
+       .get_wireless_stats = hostap_get_wireless_stats,
+};
+
+
+int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       struct iwreq *wrq = (struct iwreq *) ifr;
+       struct hostap_interface *iface;
+       local_info_t *local;
+       int ret = 0;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       switch (cmd) {
+               /* Private ioctls (iwpriv) that have not yet been converted
+                * into new wireless extensions API */
+
+       case PRISM2_IOCTL_INQUIRE:
+               if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+               else ret = prism2_ioctl_priv_inquire(dev, (int *) wrq->u.name);
+               break;
+
+       case PRISM2_IOCTL_MONITOR:
+               if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+               else ret = prism2_ioctl_priv_monitor(dev, (int *) wrq->u.name);
+               break;
+
+       case PRISM2_IOCTL_RESET:
+               if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+               else ret = prism2_ioctl_priv_reset(dev, (int *) wrq->u.name);
+               break;
+
+       case PRISM2_IOCTL_WDS_ADD:
+               if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+               else ret = prism2_wds_add(local, wrq->u.ap_addr.sa_data, 1);
+               break;
+
+       case PRISM2_IOCTL_WDS_DEL:
+               if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+               else ret = prism2_wds_del(local, wrq->u.ap_addr.sa_data, 1, 0);
+               break;
+
+       case PRISM2_IOCTL_SET_RID_WORD:
+               if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+               else ret = prism2_ioctl_priv_set_rid_word(dev,
+                                                         (int *) wrq->u.name);
+               break;
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+       case PRISM2_IOCTL_MACCMD:
+               if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+               else ret = ap_mac_cmd_ioctl(local, (int *) wrq->u.name);
+               break;
+
+       case PRISM2_IOCTL_ADDMAC:
+               if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+               else ret = ap_control_add_mac(&local->ap->mac_restrictions,
+                                             wrq->u.ap_addr.sa_data);
+               break;
+       case PRISM2_IOCTL_DELMAC:
+               if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+               else ret = ap_control_del_mac(&local->ap->mac_restrictions,
+                                             wrq->u.ap_addr.sa_data);
+               break;
+       case PRISM2_IOCTL_KICKMAC:
+               if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+               else ret = ap_control_kick_mac(local->ap, local->dev,
+                                              wrq->u.ap_addr.sa_data);
+               break;
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+               /* Private ioctls that are not used with iwpriv;
+                * in SIOCDEVPRIVATE range */
+
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+       case PRISM2_IOCTL_DOWNLOAD:
+               if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+               else ret = prism2_ioctl_priv_download(local, &wrq->u.data);
+               break;
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+
+       case PRISM2_IOCTL_HOSTAPD:
+               if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+               else ret = prism2_ioctl_priv_hostapd(local, &wrq->u.data);
+               break;
+
+       default:
+               ret = -EOPNOTSUPP;
+               break;
+       }
+
+       return ret;
+}
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
new file mode 100644 (file)
index 0000000..025f8cd
--- /dev/null
@@ -0,0 +1,473 @@
+#define PRISM2_PCI
+
+/* Host AP driver's support for Intersil Prism2.5 PCI cards is based on
+ * driver patches from Reyk Floeter <reyk@vantronix.net> and
+ * Andy Warner <andyw@pobox.com> */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/if.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/workqueue.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include "hostap_wlan.h"
+
+
+static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *dev_info = "hostap_pci";
+
+
+MODULE_AUTHOR("Jouni Malinen");
+MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN "
+                  "PCI cards.");
+MODULE_SUPPORTED_DEVICE("Intersil Prism2.5-based WLAN PCI cards");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(PRISM2_VERSION);
+
+
+/* struct local_info::hw_priv */
+struct hostap_pci_priv {
+       void __iomem *mem_start;
+};
+
+
+/* FIX: do we need mb/wmb/rmb with memory operations? */
+
+
+static struct pci_device_id prism2_pci_id_table[] __devinitdata = {
+       /* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */
+       { 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID },
+       /* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */
+       { 0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID },
+       /* Samsung MagicLAN SWL-2210P */
+       { 0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID },
+       { 0 }
+};
+
+
+#ifdef PRISM2_IO_DEBUG
+
+static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       unsigned long flags;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       spin_lock_irqsave(&local->lock, flags);
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
+       writeb(v, hw_priv->mem_start + a);
+       spin_unlock_irqrestore(&local->lock, flags);
+}
+
+static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       unsigned long flags;
+       u8 v;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       spin_lock_irqsave(&local->lock, flags);
+       v = readb(hw_priv->mem_start + a);
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
+       spin_unlock_irqrestore(&local->lock, flags);
+       return v;
+}
+
+static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       unsigned long flags;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       spin_lock_irqsave(&local->lock, flags);
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
+       writew(v, hw_priv->mem_start + a);
+       spin_unlock_irqrestore(&local->lock, flags);
+}
+
+static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       unsigned long flags;
+       u16 v;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       spin_lock_irqsave(&local->lock, flags);
+       v = readw(hw_priv->mem_start + a);
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
+       spin_unlock_irqrestore(&local->lock, flags);
+       return v;
+}
+
+#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
+#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
+#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
+#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
+#define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), cpu_to_le16((v)))
+#define HFA384X_INW_DATA(a) (u16) le16_to_cpu(hfa384x_inw_debug(dev, (a)))
+
+#else /* PRISM2_IO_DEBUG */
+
+static inline void hfa384x_outb(struct net_device *dev, int a, u8 v)
+{
+       struct hostap_interface *iface;
+       struct hostap_pci_priv *hw_priv;
+       iface = netdev_priv(dev);
+       hw_priv = iface->local->hw_priv;
+       writeb(v, hw_priv->mem_start + a);
+}
+
+static inline u8 hfa384x_inb(struct net_device *dev, int a)
+{
+       struct hostap_interface *iface;
+       struct hostap_pci_priv *hw_priv;
+       iface = netdev_priv(dev);
+       hw_priv = iface->local->hw_priv;
+       return readb(hw_priv->mem_start + a);
+}
+
+static inline void hfa384x_outw(struct net_device *dev, int a, u16 v)
+{
+       struct hostap_interface *iface;
+       struct hostap_pci_priv *hw_priv;
+       iface = netdev_priv(dev);
+       hw_priv = iface->local->hw_priv;
+       writew(v, hw_priv->mem_start + a);
+}
+
+static inline u16 hfa384x_inw(struct net_device *dev, int a)
+{
+       struct hostap_interface *iface;
+       struct hostap_pci_priv *hw_priv;
+       iface = netdev_priv(dev);
+       hw_priv = iface->local->hw_priv;
+       return readw(hw_priv->mem_start + a);
+}
+
+#define HFA384X_OUTB(v,a) hfa384x_outb(dev, (a), (v))
+#define HFA384X_INB(a) hfa384x_inb(dev, (a))
+#define HFA384X_OUTW(v,a) hfa384x_outw(dev, (a), (v))
+#define HFA384X_INW(a) hfa384x_inw(dev, (a))
+#define HFA384X_OUTW_DATA(v,a) hfa384x_outw(dev, (a), cpu_to_le16((v)))
+#define HFA384X_INW_DATA(a) (u16) le16_to_cpu(hfa384x_inw(dev, (a)))
+
+#endif /* PRISM2_IO_DEBUG */
+
+
+static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
+                           int len)
+{
+       u16 d_off;
+       u16 *pos;
+
+       d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
+       pos = (u16 *) buf;
+
+       for ( ; len > 1; len -= 2)
+               *pos++ = HFA384X_INW_DATA(d_off);
+
+       if (len & 1)
+               *((char *) pos) = HFA384X_INB(d_off);
+
+       return 0;
+}
+
+
+static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
+{
+       u16 d_off;
+       u16 *pos;
+
+       d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
+       pos = (u16 *) buf;
+
+       for ( ; len > 1; len -= 2)
+               HFA384X_OUTW_DATA(*pos++, d_off);
+
+       if (len & 1)
+               HFA384X_OUTB(*((char *) pos), d_off);
+
+       return 0;
+}
+
+
+/* FIX: This might change at some point.. */
+#include "hostap_hw.c"
+
+static void prism2_pci_cor_sreset(local_info_t *local)
+{
+       struct net_device *dev = local->dev;
+       u16 reg;
+
+       reg = HFA384X_INB(HFA384X_PCICOR_OFF);
+       printk(KERN_DEBUG "%s: Original COR value: 0x%0x\n", dev->name, reg);
+
+       /* linux-wlan-ng uses extremely long hold and settle times for
+        * COR sreset. A comment in the driver code mentions that the long
+        * delays appear to be necessary. However, at least IBM 22P6901 seems
+        * to work fine with shorter delays.
+        *
+        * Longer delays can be configured by uncommenting following line: */
+/* #define PRISM2_PCI_USE_LONG_DELAYS */
+
+#ifdef PRISM2_PCI_USE_LONG_DELAYS
+       int i;
+
+       HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF);
+       mdelay(250);
+
+       HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF);
+       mdelay(500);
+
+       /* Wait for f/w to complete initialization (CMD:BUSY == 0) */
+       i = 2000000 / 10;
+       while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && --i)
+               udelay(10);
+
+#else /* PRISM2_PCI_USE_LONG_DELAYS */
+
+       HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF);
+       mdelay(2);
+       HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF);
+       mdelay(2);
+
+#endif /* PRISM2_PCI_USE_LONG_DELAYS */
+
+       if (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) {
+               printk(KERN_DEBUG "%s: COR sreset timeout\n", dev->name);
+       }
+}
+
+
+static void prism2_pci_genesis_reset(local_info_t *local, int hcr)
+{
+       struct net_device *dev = local->dev;
+
+       HFA384X_OUTW(0x00C5, HFA384X_PCICOR_OFF);
+       mdelay(10);
+       HFA384X_OUTW(hcr, HFA384X_PCIHCR_OFF);
+       mdelay(10);
+       HFA384X_OUTW(0x0045, HFA384X_PCICOR_OFF);
+       mdelay(10);
+}
+
+
+static struct prism2_helper_functions prism2_pci_funcs =
+{
+       .card_present   = NULL,
+       .cor_sreset     = prism2_pci_cor_sreset,
+       .dev_open       = NULL,
+       .dev_close      = NULL,
+       .genesis_reset  = prism2_pci_genesis_reset,
+       .hw_type        = HOSTAP_HW_PCI,
+};
+
+
+static int prism2_pci_probe(struct pci_dev *pdev,
+                           const struct pci_device_id *id)
+{
+       unsigned long phymem;
+       void __iomem *mem = NULL;
+       local_info_t *local = NULL;
+       struct net_device *dev = NULL;
+       static int cards_found /* = 0 */;
+       int irq_registered = 0;
+       struct hostap_interface *iface;
+       struct hostap_pci_priv *hw_priv;
+
+       hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL);
+       if (hw_priv == NULL)
+               return -ENOMEM;
+       memset(hw_priv, 0, sizeof(*hw_priv));
+
+       if (pci_enable_device(pdev))
+               return -EIO;
+
+       phymem = pci_resource_start(pdev, 0);
+
+       if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) {
+               printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n");
+               goto err_out_disable;
+       }
+
+       mem = ioremap(phymem, pci_resource_len(pdev, 0));
+       if (mem == NULL) {
+               printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ;
+               goto fail;
+       }
+
+       dev = prism2_init_local_data(&prism2_pci_funcs, cards_found,
+                                    &pdev->dev);
+       if (dev == NULL)
+               goto fail;
+       iface = netdev_priv(dev);
+       local = iface->local;
+       local->hw_priv = hw_priv;
+       cards_found++;
+
+        dev->irq = pdev->irq;
+        hw_priv->mem_start = mem;
+
+       prism2_pci_cor_sreset(local);
+
+       pci_set_drvdata(pdev, dev);
+
+       if (request_irq(dev->irq, prism2_interrupt, SA_SHIRQ, dev->name,
+                       dev)) {
+               printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
+               goto fail;
+       } else
+               irq_registered = 1;
+
+       if (!local->pri_only && prism2_hw_config(dev, 1)) {
+               printk(KERN_DEBUG "%s: hardware initialization failed\n",
+                      dev_info);
+               goto fail;
+       }
+
+       printk(KERN_INFO "%s: Intersil Prism2.5 PCI: "
+              "mem=0x%lx, irq=%d\n", dev->name, phymem, dev->irq);
+
+       return hostap_hw_ready(dev);
+
+ fail:
+       kfree(hw_priv);
+
+       if (irq_registered && dev)
+               free_irq(dev->irq, dev);
+
+       if (mem)
+               iounmap(mem);
+
+       release_mem_region(phymem, pci_resource_len(pdev, 0));
+
+ err_out_disable:
+       pci_disable_device(pdev);
+       kfree(hw_priv);
+       if (local)
+               local->hw_priv = NULL;
+       prism2_free_local_data(dev);
+
+       return -ENODEV;
+}
+
+
+static void prism2_pci_remove(struct pci_dev *pdev)
+{
+       struct net_device *dev;
+       struct hostap_interface *iface;
+       void __iomem *mem_start;
+       struct hostap_pci_priv *hw_priv;
+
+       dev = pci_get_drvdata(pdev);
+       iface = netdev_priv(dev);
+       hw_priv = iface->local->hw_priv;
+
+       /* Reset the hardware, and ensure interrupts are disabled. */
+       prism2_pci_cor_sreset(iface->local);
+       hfa384x_disable_interrupts(dev);
+
+       if (dev->irq)
+               free_irq(dev->irq, dev);
+
+       mem_start = hw_priv->mem_start;
+       kfree(hw_priv);
+       iface->local->hw_priv = NULL;
+       prism2_free_local_data(dev);
+
+       iounmap(mem_start);
+
+       release_mem_region(pci_resource_start(pdev, 0),
+                          pci_resource_len(pdev, 0));
+       pci_disable_device(pdev);
+}
+
+
+#ifdef CONFIG_PM
+static int prism2_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+
+       if (netif_running(dev)) {
+               netif_stop_queue(dev);
+               netif_device_detach(dev);
+       }
+       prism2_suspend(dev);
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, PCI_D3hot);
+
+       return 0;
+}
+
+static int prism2_pci_resume(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+
+       pci_enable_device(pdev);
+       pci_restore_state(pdev);
+       prism2_hw_config(dev, 0);
+       if (netif_running(dev)) {
+               netif_device_attach(dev);
+               netif_start_queue(dev);
+       }
+
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+
+MODULE_DEVICE_TABLE(pci, prism2_pci_id_table);
+
+static struct pci_driver prism2_pci_drv_id = {
+       .name           = "prism2_pci",
+       .id_table       = prism2_pci_id_table,
+       .probe          = prism2_pci_probe,
+       .remove         = prism2_pci_remove,
+#ifdef CONFIG_PM
+       .suspend        = prism2_pci_suspend,
+       .resume         = prism2_pci_resume,
+#endif /* CONFIG_PM */
+       /* Linux 2.4.6 added save_state and enable_wake that are not used here
+        */
+};
+
+
+static int __init init_prism2_pci(void)
+{
+       printk(KERN_INFO "%s: %s\n", dev_info, version);
+
+       return pci_register_driver(&prism2_pci_drv_id);
+}
+
+
+static void __exit exit_prism2_pci(void)
+{
+       pci_unregister_driver(&prism2_pci_drv_id);
+       printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
+}
+
+
+module_init(init_prism2_pci);
+module_exit(exit_prism2_pci);
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
new file mode 100644 (file)
index 0000000..474ef83
--- /dev/null
@@ -0,0 +1,645 @@
+#define PRISM2_PLX
+
+/* Host AP driver's support for PC Cards on PCI adapters using PLX9052 is
+ * based on:
+ * - Host AP driver patch from james@madingley.org
+ * - linux-wlan-ng driver, Copyright (C) AbsoluteValue Systems, Inc.
+ */
+
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/if.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/workqueue.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include "hostap_wlan.h"
+
+
+static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *dev_info = "hostap_plx";
+
+
+MODULE_AUTHOR("Jouni Malinen");
+MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
+                  "cards (PLX).");
+MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PLX)");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(PRISM2_VERSION);
+
+
+static int ignore_cis;
+module_param(ignore_cis, int, 0444);
+MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS");
+
+
+/* struct local_info::hw_priv */
+struct hostap_plx_priv {
+       void __iomem *attr_mem;
+       unsigned int cor_offset;
+};
+
+
+#define PLX_MIN_ATTR_LEN 512   /* at least 2 x 256 is needed for CIS */
+#define COR_SRESET       0x80
+#define COR_LEVLREQ      0x40
+#define COR_ENABLE_FUNC  0x01
+/* PCI Configuration Registers */
+#define PLX_PCIIPR       0x3d   /* PCI Interrupt Pin */
+/* Local Configuration Registers */
+#define PLX_INTCSR       0x4c   /* Interrupt Control/Status Register */
+#define PLX_INTCSR_PCI_INTEN BIT(6) /* PCI Interrupt Enable */
+#define PLX_CNTRL        0x50
+#define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28)
+
+
+#define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID }
+
+static struct pci_device_id prism2_plx_id_table[] __devinitdata = {
+       PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
+       PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
+       PLXDEV(0x126c, 0x8030, "Nortel emobility"),
+       PLXDEV(0x1385, 0x4100, "Netgear MA301"),
+       PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
+       PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
+       PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
+       PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
+       PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
+       PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
+       PLXDEV(0x16ec, 0x3685, "US Robotics USR2415"),
+       PLXDEV(0xec80, 0xec00, "Belkin F5D6000"),
+       { 0 }
+};
+
+
+/* Array of known Prism2/2.5 PC Card manufactured ids. If your card's manfid
+ * is not listed here, you will need to add it here to get the driver
+ * initialized. */
+static struct prism2_plx_manfid {
+       u16 manfid1, manfid2;
+} prism2_plx_known_manfids[] = {
+       { 0x000b, 0x7110 } /* D-Link DWL-650 Rev. P1 */,
+       { 0x000b, 0x7300 } /* Philips 802.11b WLAN PCMCIA */,
+       { 0x0101, 0x0777 } /* 3Com AirConnect PCI 777A */,
+       { 0x0126, 0x8000 } /* Proxim RangeLAN */,
+       { 0x0138, 0x0002 } /* Compaq WL100 */,
+       { 0x0156, 0x0002 } /* Intersil Prism II Ref. Design (and others) */,
+       { 0x026f, 0x030b } /* Buffalo WLI-CF-S11G */,
+       { 0x0274, 0x1612 } /* Linksys WPC11 Ver 2.5 */,
+       { 0x0274, 0x1613 } /* Linksys WPC11 Ver 3 */,
+       { 0x028a, 0x0002 } /* D-Link DRC-650 */,
+       { 0x0250, 0x0002 } /* Samsung SWL2000-N */,
+       { 0xc250, 0x0002 } /* EMTAC A2424i */,
+       { 0xd601, 0x0002 } /* Z-Com XI300 */,
+       { 0xd601, 0x0005 } /* Zcomax XI-325H 200mW */,
+       { 0, 0}
+};
+
+
+#ifdef PRISM2_IO_DEBUG
+
+static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       unsigned long flags;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       spin_lock_irqsave(&local->lock, flags);
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
+       outb(v, dev->base_addr + a);
+       spin_unlock_irqrestore(&local->lock, flags);
+}
+
+static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       unsigned long flags;
+       u8 v;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       spin_lock_irqsave(&local->lock, flags);
+       v = inb(dev->base_addr + a);
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
+       spin_unlock_irqrestore(&local->lock, flags);
+       return v;
+}
+
+static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       unsigned long flags;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       spin_lock_irqsave(&local->lock, flags);
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
+       outw(v, dev->base_addr + a);
+       spin_unlock_irqrestore(&local->lock, flags);
+}
+
+static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       unsigned long flags;
+       u16 v;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       spin_lock_irqsave(&local->lock, flags);
+       v = inw(dev->base_addr + a);
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
+       spin_unlock_irqrestore(&local->lock, flags);
+       return v;
+}
+
+static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
+                                      u8 *buf, int wc)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       unsigned long flags;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       spin_lock_irqsave(&local->lock, flags);
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
+       outsw(dev->base_addr + a, buf, wc);
+       spin_unlock_irqrestore(&local->lock, flags);
+}
+
+static inline void hfa384x_insw_debug(struct net_device *dev, int a,
+                                     u8 *buf, int wc)
+{
+       struct hostap_interface *iface;
+       local_info_t *local;
+       unsigned long flags;
+
+       iface = netdev_priv(dev);
+       local = iface->local;
+
+       spin_lock_irqsave(&local->lock, flags);
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
+       insw(dev->base_addr + a, buf, wc);
+       spin_unlock_irqrestore(&local->lock, flags);
+}
+
+#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
+#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
+#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
+#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
+#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
+#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
+
+#else /* PRISM2_IO_DEBUG */
+
+#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
+#define HFA384X_INB(a) inb(dev->base_addr + (a))
+#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
+#define HFA384X_INW(a) inw(dev->base_addr + (a))
+#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
+#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
+
+#endif /* PRISM2_IO_DEBUG */
+
+
+static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
+                           int len)
+{
+       u16 d_off;
+       u16 *pos;
+
+       d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
+       pos = (u16 *) buf;
+
+       if (len / 2)
+               HFA384X_INSW(d_off, buf, len / 2);
+       pos += len / 2;
+
+       if (len & 1)
+               *((char *) pos) = HFA384X_INB(d_off);
+
+       return 0;
+}
+
+
+static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
+{
+       u16 d_off;
+       u16 *pos;
+
+       d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
+       pos = (u16 *) buf;
+
+       if (len / 2)
+               HFA384X_OUTSW(d_off, buf, len / 2);
+       pos += len / 2;
+
+       if (len & 1)
+               HFA384X_OUTB(*((char *) pos), d_off);
+
+       return 0;
+}
+
+
+/* FIX: This might change at some point.. */
+#include "hostap_hw.c"
+
+
+static void prism2_plx_cor_sreset(local_info_t *local)
+{
+       unsigned char corsave;
+       struct hostap_plx_priv *hw_priv = local->hw_priv;
+
+       printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n",
+              dev_info);
+
+       /* Set sreset bit of COR and clear it after hold time */
+
+       if (hw_priv->attr_mem == NULL) {
+               /* TMD7160 - COR at card's first I/O addr */
+               corsave = inb(hw_priv->cor_offset);
+               outb(corsave | COR_SRESET, hw_priv->cor_offset);
+               mdelay(2);
+               outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
+               mdelay(2);
+       } else {
+               /* PLX9052 */
+               corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
+               writeb(corsave | COR_SRESET,
+                      hw_priv->attr_mem + hw_priv->cor_offset);
+               mdelay(2);
+               writeb(corsave & ~COR_SRESET,
+                      hw_priv->attr_mem + hw_priv->cor_offset);
+               mdelay(2);
+       }
+}
+
+
+static void prism2_plx_genesis_reset(local_info_t *local, int hcr)
+{
+       unsigned char corsave;
+       struct hostap_plx_priv *hw_priv = local->hw_priv;
+
+       if (hw_priv->attr_mem == NULL) {
+               /* TMD7160 - COR at card's first I/O addr */
+               corsave = inb(hw_priv->cor_offset);
+               outb(corsave | COR_SRESET, hw_priv->cor_offset);
+               mdelay(10);
+               outb(hcr, hw_priv->cor_offset + 2);
+               mdelay(10);
+               outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
+               mdelay(10);
+       } else {
+               /* PLX9052 */
+               corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
+               writeb(corsave | COR_SRESET,
+                      hw_priv->attr_mem + hw_priv->cor_offset);
+               mdelay(10);
+               writeb(hcr, hw_priv->attr_mem + hw_priv->cor_offset + 2);
+               mdelay(10);
+               writeb(corsave & ~COR_SRESET,
+                      hw_priv->attr_mem + hw_priv->cor_offset);
+               mdelay(10);
+       }
+}
+
+
+static struct prism2_helper_functions prism2_plx_funcs =
+{
+       .card_present   = NULL,
+       .cor_sreset     = prism2_plx_cor_sreset,
+       .dev_open       = NULL,
+       .dev_close      = NULL,
+       .genesis_reset  = prism2_plx_genesis_reset,
+       .hw_type        = HOSTAP_HW_PLX,
+};
+
+
+static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len,
+                               unsigned int *cor_offset,
+                               unsigned int *cor_index)
+{
+#define CISTPL_CONFIG 0x1A
+#define CISTPL_MANFID 0x20
+#define CISTPL_END 0xFF
+#define CIS_MAX_LEN 256
+       u8 *cis;
+       int i, pos;
+       unsigned int rmsz, rasz, manfid1, manfid2;
+       struct prism2_plx_manfid *manfid;
+
+       cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL);
+       if (cis == NULL)
+               return -ENOMEM;
+
+       /* read CIS; it is in even offsets in the beginning of attr_mem */
+       for (i = 0; i < CIS_MAX_LEN; i++)
+               cis[i] = readb(attr_mem + 2 * i);
+       printk(KERN_DEBUG "%s: CIS: %02x %02x %02x %02x %02x %02x ...\n",
+              dev_info, cis[0], cis[1], cis[2], cis[3], cis[4], cis[5]);
+
+       /* set reasonable defaults for Prism2 cards just in case CIS parsing
+        * fails */
+       *cor_offset = 0x3e0;
+       *cor_index = 0x01;
+       manfid1 = manfid2 = 0;
+
+       pos = 0;
+       while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) {
+               if (pos + cis[pos + 1] >= CIS_MAX_LEN)
+                       goto cis_error;
+
+               switch (cis[pos]) {
+               case CISTPL_CONFIG:
+                       if (cis[pos + 1] < 1)
+                               goto cis_error;
+                       rmsz = (cis[pos + 2] & 0x3c) >> 2;
+                       rasz = cis[pos + 2] & 0x03;
+                       if (4 + rasz + rmsz > cis[pos + 1])
+                               goto cis_error;
+                       *cor_index = cis[pos + 3] & 0x3F;
+                       *cor_offset = 0;
+                       for (i = 0; i <= rasz; i++)
+                               *cor_offset += cis[pos + 4 + i] << (8 * i);
+                       printk(KERN_DEBUG "%s: cor_index=0x%x "
+                              "cor_offset=0x%x\n", dev_info,
+                              *cor_index, *cor_offset);
+                       if (*cor_offset > attr_len) {
+                               printk(KERN_ERR "%s: COR offset not within "
+                                      "attr_mem\n", dev_info);
+                               kfree(cis);
+                               return -1;
+                       }
+                       break;
+
+               case CISTPL_MANFID:
+                       if (cis[pos + 1] < 4)
+                               goto cis_error;
+                       manfid1 = cis[pos + 2] + (cis[pos + 3] << 8);
+                       manfid2 = cis[pos + 4] + (cis[pos + 5] << 8);
+                       printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n",
+                              dev_info, manfid1, manfid2);
+                       break;
+               }
+
+               pos += cis[pos + 1] + 2;
+       }
+
+       if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END)
+               goto cis_error;
+
+       for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++)
+               if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) {
+                       kfree(cis);
+                       return 0;
+               }
+
+       printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is"
+              " not supported card\n", dev_info, manfid1, manfid2);
+       goto fail;
+
+ cis_error:
+       printk(KERN_WARNING "%s: invalid CIS data\n", dev_info);
+
+ fail:
+       kfree(cis);
+       if (ignore_cis) {
+               printk(KERN_INFO "%s: ignore_cis parameter set - ignoring "
+                      "errors during CIS verification\n", dev_info);
+               return 0;
+       }
+       return -1;
+}
+
+
+static int prism2_plx_probe(struct pci_dev *pdev,
+                           const struct pci_device_id *id)
+{
+       unsigned int pccard_ioaddr, plx_ioaddr;
+       unsigned long pccard_attr_mem;
+       unsigned int pccard_attr_len;
+       void __iomem *attr_mem = NULL;
+       unsigned int cor_offset, cor_index;
+       u32 reg;
+       local_info_t *local = NULL;
+       struct net_device *dev = NULL;
+       struct hostap_interface *iface;
+       static int cards_found /* = 0 */;
+       int irq_registered = 0;
+       int tmd7160;
+       struct hostap_plx_priv *hw_priv;
+
+       hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL);
+       if (hw_priv == NULL)
+               return -ENOMEM;
+       memset(hw_priv, 0, sizeof(*hw_priv));
+
+       if (pci_enable_device(pdev))
+               return -EIO;
+
+       /* National Datacomm NCP130 based on TMD7160, not PLX9052. */
+       tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131);
+
+       plx_ioaddr = pci_resource_start(pdev, 1);
+       pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3);
+
+       if (tmd7160) {
+               /* TMD7160 */
+               attr_mem = NULL; /* no access to PC Card attribute memory */
+
+               printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, "
+                      "irq=%d, pccard_io=0x%x\n",
+                      plx_ioaddr, pdev->irq, pccard_ioaddr);
+
+               cor_offset = plx_ioaddr;
+               cor_index = 0x04;
+
+               outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr);
+               mdelay(1);
+               reg = inb(plx_ioaddr);
+               if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) {
+                       printk(KERN_ERR "%s: Error setting COR (expected="
+                              "0x%02x, was=0x%02x)\n", dev_info,
+                              cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg);
+                       goto fail;
+               }
+       } else {
+               /* PLX9052 */
+               pccard_attr_mem = pci_resource_start(pdev, 2);
+               pccard_attr_len = pci_resource_len(pdev, 2);
+               if (pccard_attr_len < PLX_MIN_ATTR_LEN)
+                       goto fail;
+
+
+               attr_mem = ioremap(pccard_attr_mem, pccard_attr_len);
+               if (attr_mem == NULL) {
+                       printk(KERN_ERR "%s: cannot remap attr_mem\n",
+                              dev_info);
+                       goto fail;
+               }
+
+               printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: "
+                      "mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n",
+                      pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr);
+
+               if (prism2_plx_check_cis(attr_mem, pccard_attr_len,
+                                        &cor_offset, &cor_index)) {
+                       printk(KERN_INFO "Unknown PC Card CIS - not a "
+                              "Prism2/2.5 card?\n");
+                       goto fail;
+               }
+
+               printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 "
+                      "adapter\n");
+
+               /* Write COR to enable PC Card */
+               writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC,
+                      attr_mem + cor_offset);
+
+               /* Enable PCI interrupts if they are not already enabled */
+               reg = inl(plx_ioaddr + PLX_INTCSR);
+               printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg);
+               if (!(reg & PLX_INTCSR_PCI_INTEN)) {
+                       outl(reg | PLX_INTCSR_PCI_INTEN,
+                            plx_ioaddr + PLX_INTCSR);
+                       if (!(inl(plx_ioaddr + PLX_INTCSR) &
+                             PLX_INTCSR_PCI_INTEN)) {
+                               printk(KERN_WARNING "%s: Could not enable "
+                                      "Local Interrupts\n", dev_info);
+                               goto fail;
+                       }
+               }
+
+               reg = inl(plx_ioaddr + PLX_CNTRL);
+               printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM "
+                      "present=%d)\n",
+                      reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0);
+               /* should set PLX_PCIIPR to 0x01 (INTA#) if Serial EEPROM is
+                * not present; but are there really such cards in use(?) */
+       }
+
+       dev = prism2_init_local_data(&prism2_plx_funcs, cards_found,
+                                    &pdev->dev);
+       if (dev == NULL)
+               goto fail;
+       iface = netdev_priv(dev);
+       local = iface->local;
+       local->hw_priv = hw_priv;
+       cards_found++;
+
+       dev->irq = pdev->irq;
+       dev->base_addr = pccard_ioaddr;
+       hw_priv->attr_mem = attr_mem;
+       hw_priv->cor_offset = cor_offset;
+
+       pci_set_drvdata(pdev, dev);
+
+       if (request_irq(dev->irq, prism2_interrupt, SA_SHIRQ, dev->name,
+                       dev)) {
+               printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
+               goto fail;
+       } else
+               irq_registered = 1;
+
+       if (prism2_hw_config(dev, 1)) {
+               printk(KERN_DEBUG "%s: hardware initialization failed\n",
+                      dev_info);
+               goto fail;
+       }
+
+       return hostap_hw_ready(dev);
+
+ fail:
+       kfree(hw_priv);
+       if (local)
+               local->hw_priv = NULL;
+       prism2_free_local_data(dev);
+
+       if (irq_registered && dev)
+               free_irq(dev->irq, dev);
+
+       if (attr_mem)
+               iounmap(attr_mem);
+
+       pci_disable_device(pdev);
+
+       return -ENODEV;
+}
+
+
+static void prism2_plx_remove(struct pci_dev *pdev)
+{
+       struct net_device *dev;
+       struct hostap_interface *iface;
+       struct hostap_plx_priv *hw_priv;
+
+       dev = pci_get_drvdata(pdev);
+       iface = netdev_priv(dev);
+       hw_priv = iface->local->hw_priv;
+
+       /* Reset the hardware, and ensure interrupts are disabled. */
+       prism2_plx_cor_sreset(iface->local);
+       hfa384x_disable_interrupts(dev);
+
+       if (hw_priv->attr_mem)
+               iounmap(hw_priv->attr_mem);
+       if (dev->irq)
+               free_irq(dev->irq, dev);
+
+       kfree(iface->local->hw_priv);
+       iface->local->hw_priv = NULL;
+       prism2_free_local_data(dev);
+       pci_disable_device(pdev);
+}
+
+
+MODULE_DEVICE_TABLE(pci, prism2_plx_id_table);
+
+static struct pci_driver prism2_plx_drv_id = {
+       .name           = "prism2_plx",
+       .id_table       = prism2_plx_id_table,
+       .probe          = prism2_plx_probe,
+       .remove         = prism2_plx_remove,
+       .suspend        = NULL,
+       .resume         = NULL,
+       .enable_wake    = NULL
+};
+
+
+static int __init init_prism2_plx(void)
+{
+       printk(KERN_INFO "%s: %s\n", dev_info, version);
+
+       return pci_register_driver(&prism2_plx_drv_id);
+}
+
+
+static void __exit exit_prism2_plx(void)
+{
+       pci_unregister_driver(&prism2_plx_drv_id);
+       printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
+}
+
+
+module_init(init_prism2_plx);
+module_exit(exit_prism2_plx);
diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c
new file mode 100644 (file)
index 0000000..a0a4cbd
--- /dev/null
@@ -0,0 +1,448 @@
+/* /proc routines for Host AP driver */
+
+#define PROC_LIMIT (PAGE_SIZE - 80)
+
+
+#ifndef PRISM2_NO_PROCFS_DEBUG
+static int prism2_debug_proc_read(char *page, char **start, off_t off,
+                                 int count, int *eof, void *data)
+{
+       char *p = page;
+       local_info_t *local = (local_info_t *) data;
+       int i;
+
+       if (off != 0) {
+               *eof = 1;
+               return 0;
+       }
+
+       p += sprintf(p, "next_txfid=%d next_alloc=%d\n",
+                    local->next_txfid, local->next_alloc);
+       for (i = 0; i < PRISM2_TXFID_COUNT; i++)
+               p += sprintf(p, "FID: tx=%04X intransmit=%04X\n",
+                            local->txfid[i], local->intransmitfid[i]);
+       p += sprintf(p, "FW TX rate control: %d\n", local->fw_tx_rate_control);
+       p += sprintf(p, "beacon_int=%d\n", local->beacon_int);
+       p += sprintf(p, "dtim_period=%d\n", local->dtim_period);
+       p += sprintf(p, "wds_max_connections=%d\n",
+                    local->wds_max_connections);
+       p += sprintf(p, "dev_enabled=%d\n", local->dev_enabled);
+       p += sprintf(p, "sw_tick_stuck=%d\n", local->sw_tick_stuck);
+       for (i = 0; i < WEP_KEYS; i++) {
+               if (local->crypt[i] && local->crypt[i]->ops) {
+                       p += sprintf(p, "crypt[%d]=%s\n",
+                                    i, local->crypt[i]->ops->name);
+               }
+       }
+       p += sprintf(p, "pri_only=%d\n", local->pri_only);
+       p += sprintf(p, "pci=%d\n", local->func->hw_type == HOSTAP_HW_PCI);
+       p += sprintf(p, "sram_type=%d\n", local->sram_type);
+       p += sprintf(p, "no_pri=%d\n", local->no_pri);
+
+       return (p - page);
+}
+#endif /* PRISM2_NO_PROCFS_DEBUG */
+
+
+static int prism2_stats_proc_read(char *page, char **start, off_t off,
+                                 int count, int *eof, void *data)
+{
+       char *p = page;
+       local_info_t *local = (local_info_t *) data;
+       struct comm_tallies_sums *sums = (struct comm_tallies_sums *)
+               &local->comm_tallies;
+
+       if (off != 0) {
+               *eof = 1;
+               return 0;
+       }
+
+       p += sprintf(p, "TxUnicastFrames=%u\n", sums->tx_unicast_frames);
+       p += sprintf(p, "TxMulticastframes=%u\n", sums->tx_multicast_frames);
+       p += sprintf(p, "TxFragments=%u\n", sums->tx_fragments);
+       p += sprintf(p, "TxUnicastOctets=%u\n", sums->tx_unicast_octets);
+       p += sprintf(p, "TxMulticastOctets=%u\n", sums->tx_multicast_octets);
+       p += sprintf(p, "TxDeferredTransmissions=%u\n",
+                    sums->tx_deferred_transmissions);
+       p += sprintf(p, "TxSingleRetryFrames=%u\n",
+                    sums->tx_single_retry_frames);
+       p += sprintf(p, "TxMultipleRetryFrames=%u\n",
+                    sums->tx_multiple_retry_frames);
+       p += sprintf(p, "TxRetryLimitExceeded=%u\n",
+                    sums->tx_retry_limit_exceeded);
+       p += sprintf(p, "TxDiscards=%u\n", sums->tx_discards);
+       p += sprintf(p, "RxUnicastFrames=%u\n", sums->rx_unicast_frames);
+       p += sprintf(p, "RxMulticastFrames=%u\n", sums->rx_multicast_frames);
+       p += sprintf(p, "RxFragments=%u\n", sums->rx_fragments);
+       p += sprintf(p, "RxUnicastOctets=%u\n", sums->rx_unicast_octets);
+       p += sprintf(p, "RxMulticastOctets=%u\n", sums->rx_multicast_octets);
+       p += sprintf(p, "RxFCSErrors=%u\n", sums->rx_fcs_errors);
+       p += sprintf(p, "RxDiscardsNoBuffer=%u\n",
+                    sums->rx_discards_no_buffer);
+       p += sprintf(p, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa);
+       p += sprintf(p, "RxDiscardsWEPUndecryptable=%u\n",
+                    sums->rx_discards_wep_undecryptable);
+       p += sprintf(p, "RxMessageInMsgFragments=%u\n",
+                    sums->rx_message_in_msg_fragments);
+       p += sprintf(p, "RxMessageInBadMsgFragments=%u\n",
+                    sums->rx_message_in_bad_msg_fragments);
+       /* FIX: this may grow too long for one page(?) */
+
+       return (p - page);
+}
+
+
+static int prism2_wds_proc_read(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+       char *p = page;
+       local_info_t *local = (local_info_t *) data;
+       struct list_head *ptr;
+       struct hostap_interface *iface;
+
+       if (off > PROC_LIMIT) {
+               *eof = 1;
+               return 0;
+       }
+
+       read_lock_bh(&local->iface_lock);
+       list_for_each(ptr, &local->hostap_interfaces) {
+               iface = list_entry(ptr, struct hostap_interface, list);
+               if (iface->type != HOSTAP_INTERFACE_WDS)
+                       continue;
+               p += sprintf(p, "%s\t" MACSTR "\n",
+                            iface->dev->name,
+                            MAC2STR(iface->u.wds.remote_addr));
+               if ((p - page) > PROC_LIMIT) {
+                       printk(KERN_DEBUG "%s: wds proc did not fit\n",
+                              local->dev->name);
+                       break;
+               }
+       }
+       read_unlock_bh(&local->iface_lock);
+
+       if ((p - page) <= off) {
+               *eof = 1;
+               return 0;
+       }
+
+       *start = page + off;
+
+       return (p - page - off);
+}
+
+
+static int prism2_bss_list_proc_read(char *page, char **start, off_t off,
+                                    int count, int *eof, void *data)
+{
+       char *p = page;
+       local_info_t *local = (local_info_t *) data;
+       struct list_head *ptr;
+       struct hostap_bss_info *bss;
+       int i;
+
+       if (off > PROC_LIMIT) {
+               *eof = 1;
+               return 0;
+       }
+
+       p += sprintf(p, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t"
+                    "SSID(hex)\tWPA IE\n");
+       spin_lock_bh(&local->lock);
+       list_for_each(ptr, &local->bss_list) {
+               bss = list_entry(ptr, struct hostap_bss_info, list);
+               p += sprintf(p, MACSTR "\t%lu\t%u\t0x%x\t",
+                            MAC2STR(bss->bssid), bss->last_update,
+                            bss->count, bss->capab_info);
+               for (i = 0; i < bss->ssid_len; i++) {
+                       p += sprintf(p, "%c",
+                                    bss->ssid[i] >= 32 && bss->ssid[i] < 127 ?
+                                    bss->ssid[i] : '_');
+               }
+               p += sprintf(p, "\t");
+               for (i = 0; i < bss->ssid_len; i++) {
+                       p += sprintf(p, "%02x", bss->ssid[i]);
+               }
+               p += sprintf(p, "\t");
+               for (i = 0; i < bss->wpa_ie_len; i++) {
+                       p += sprintf(p, "%02x", bss->wpa_ie[i]);
+               }
+               p += sprintf(p, "\n");
+               if ((p - page) > PROC_LIMIT) {
+                       printk(KERN_DEBUG "%s: BSS proc did not fit\n",
+                              local->dev->name);
+                       break;
+               }
+       }
+       spin_unlock_bh(&local->lock);
+
+       if ((p - page) <= off) {
+               *eof = 1;
+               return 0;
+       }
+
+       *start = page + off;
+
+       return (p - page - off);
+}
+
+
+static int prism2_crypt_proc_read(char *page, char **start, off_t off,
+                                 int count, int *eof, void *data)
+{
+       char *p = page;
+       local_info_t *local = (local_info_t *) data;
+       int i;
+
+       if (off > PROC_LIMIT) {
+               *eof = 1;
+               return 0;
+       }
+
+       p += sprintf(p, "tx_keyidx=%d\n", local->tx_keyidx);
+       for (i = 0; i < WEP_KEYS; i++) {
+               if (local->crypt[i] && local->crypt[i]->ops &&
+                   local->crypt[i]->ops->print_stats) {
+                       p = local->crypt[i]->ops->print_stats(
+                               p, local->crypt[i]->priv);
+               }
+       }
+
+       if ((p - page) <= off) {
+               *eof = 1;
+               return 0;
+       }
+
+       *start = page + off;
+
+       return (p - page - off);
+}
+
+
+static int prism2_pda_proc_read(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+       local_info_t *local = (local_info_t *) data;
+
+       if (local->pda == NULL || off >= PRISM2_PDA_SIZE) {
+               *eof = 1;
+               return 0;
+       }
+
+       if (off + count > PRISM2_PDA_SIZE)
+               count = PRISM2_PDA_SIZE - off;
+
+       memcpy(page, local->pda + off, count);
+       return count;
+}
+
+
+static int prism2_aux_dump_proc_read(char *page, char **start, off_t off,
+                                    int count, int *eof, void *data)
+{
+       local_info_t *local = (local_info_t *) data;
+
+       if (local->func->read_aux == NULL) {
+               *eof = 1;
+               return 0;
+       }
+
+       if (local->func->read_aux(local->dev, off, count, page)) {
+               *eof = 1;
+               return 0;
+       }
+       *start = page;
+
+       return count;
+}
+
+
+#ifdef PRISM2_IO_DEBUG
+static int prism2_io_debug_proc_read(char *page, char **start, off_t off,
+                                    int count, int *eof, void *data)
+{
+       local_info_t *local = (local_info_t *) data;
+       int head = local->io_debug_head;
+       int start_bytes, left, copy, copied;
+
+       if (off + count > PRISM2_IO_DEBUG_SIZE * 4) {
+               *eof = 1;
+               if (off >= PRISM2_IO_DEBUG_SIZE * 4)
+                       return 0;
+               count = PRISM2_IO_DEBUG_SIZE * 4 - off;
+       }
+
+       copied = 0;
+       start_bytes = (PRISM2_IO_DEBUG_SIZE - head) * 4;
+       left = count;
+
+       if (off < start_bytes) {
+               copy = start_bytes - off;
+               if (copy > count)
+                       copy = count;
+               memcpy(page, ((u8 *) &local->io_debug[head]) + off, copy);
+               left -= copy;
+               if (left > 0)
+                       memcpy(&page[copy], local->io_debug, left);
+       } else {
+               memcpy(page, ((u8 *) local->io_debug) + (off - start_bytes),
+                      left);
+       }
+
+       *start = page;
+
+       return count;
+}
+#endif /* PRISM2_IO_DEBUG */
+
+
+#ifndef PRISM2_NO_STATION_MODES
+static int prism2_scan_results_proc_read(char *page, char **start, off_t off,
+                                        int count, int *eof, void *data)
+{
+       char *p = page;
+       local_info_t *local = (local_info_t *) data;
+       int entry, i, len, total = 0;
+       struct hfa384x_hostscan_result *scanres;
+       u8 *pos;
+
+       p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates "
+                    "SSID\n");
+
+       spin_lock_bh(&local->lock);
+       for (entry = 0; entry < local->last_scan_results_count; entry++) {
+               scanres = &local->last_scan_results[entry];
+
+               if (total + (p - page) <= off) {
+                       total += p - page;
+                       p = page;
+               }
+               if (total + (p - page) > off + count)
+                       break;
+               if ((p - page) > (PAGE_SIZE - 200))
+                       break;
+
+               p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR " %d ",
+                            le16_to_cpu(scanres->chid),
+                            (s16) le16_to_cpu(scanres->anl),
+                            (s16) le16_to_cpu(scanres->sl),
+                            le16_to_cpu(scanres->beacon_interval),
+                            le16_to_cpu(scanres->capability),
+                            le16_to_cpu(scanres->rate),
+                            MAC2STR(scanres->bssid),
+                            le16_to_cpu(scanres->atim));
+
+               pos = scanres->sup_rates;
+               for (i = 0; i < sizeof(scanres->sup_rates); i++) {
+                       if (pos[i] == 0)
+                               break;
+                       p += sprintf(p, "<%02x>", pos[i]);
+               }
+               p += sprintf(p, " ");
+
+               pos = scanres->ssid;
+               len = le16_to_cpu(scanres->ssid_len);
+               if (len > 32)
+                       len = 32;
+               for (i = 0; i < len; i++) {
+                       unsigned char c = pos[i];
+                       if (c >= 32 && c < 127)
+                               p += sprintf(p, "%c", c);
+                       else
+                               p += sprintf(p, "<%02x>", c);
+               }
+               p += sprintf(p, "\n");
+       }
+       spin_unlock_bh(&local->lock);
+
+       total += (p - page);
+       if (total >= off + count)
+               *eof = 1;
+
+       if (total < off) {
+               *eof = 1;
+               return 0;
+       }
+
+       len = total - off;
+       if (len > (p - page))
+               len = p - page;
+       *start = p - len;
+       if (len > count)
+               len = count;
+
+       return len;
+}
+#endif /* PRISM2_NO_STATION_MODES */
+
+
+void hostap_init_proc(local_info_t *local)
+{
+       local->proc = NULL;
+
+       if (hostap_proc == NULL) {
+               printk(KERN_WARNING "%s: hostap proc directory not created\n",
+                      local->dev->name);
+               return;
+       }
+
+       local->proc = proc_mkdir(local->ddev->name, hostap_proc);
+       if (local->proc == NULL) {
+               printk(KERN_INFO "/proc/net/hostap/%s creation failed\n",
+                      local->ddev->name);
+               return;
+       }
+
+#ifndef PRISM2_NO_PROCFS_DEBUG
+       create_proc_read_entry("debug", 0, local->proc,
+                              prism2_debug_proc_read, local);
+#endif /* PRISM2_NO_PROCFS_DEBUG */
+       create_proc_read_entry("stats", 0, local->proc,
+                              prism2_stats_proc_read, local);
+       create_proc_read_entry("wds", 0, local->proc,
+                              prism2_wds_proc_read, local);
+       create_proc_read_entry("pda", 0, local->proc,
+                              prism2_pda_proc_read, local);
+       create_proc_read_entry("aux_dump", 0, local->proc,
+                              prism2_aux_dump_proc_read, local);
+       create_proc_read_entry("bss_list", 0, local->proc,
+                              prism2_bss_list_proc_read, local);
+       create_proc_read_entry("crypt", 0, local->proc,
+                              prism2_crypt_proc_read, local);
+#ifdef PRISM2_IO_DEBUG
+       create_proc_read_entry("io_debug", 0, local->proc,
+                              prism2_io_debug_proc_read, local);
+#endif /* PRISM2_IO_DEBUG */
+#ifndef PRISM2_NO_STATION_MODES
+       create_proc_read_entry("scan_results", 0, local->proc,
+                              prism2_scan_results_proc_read, local);
+#endif /* PRISM2_NO_STATION_MODES */
+}
+
+
+void hostap_remove_proc(local_info_t *local)
+{
+       if (local->proc != NULL) {
+#ifndef PRISM2_NO_STATION_MODES
+               remove_proc_entry("scan_results", local->proc);
+#endif /* PRISM2_NO_STATION_MODES */
+#ifdef PRISM2_IO_DEBUG
+               remove_proc_entry("io_debug", local->proc);
+#endif /* PRISM2_IO_DEBUG */
+               remove_proc_entry("pda", local->proc);
+               remove_proc_entry("aux_dump", local->proc);
+               remove_proc_entry("wds", local->proc);
+               remove_proc_entry("stats", local->proc);
+               remove_proc_entry("bss_list", local->proc);
+               remove_proc_entry("crypt", local->proc);
+#ifndef PRISM2_NO_PROCFS_DEBUG
+               remove_proc_entry("debug", local->proc);
+#endif /* PRISM2_NO_PROCFS_DEBUG */
+               if (hostap_proc != NULL)
+                       remove_proc_entry(local->proc->name, hostap_proc);
+       }
+}
+
+
+EXPORT_SYMBOL(hostap_init_proc);
+EXPORT_SYMBOL(hostap_remove_proc);
diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h
new file mode 100644 (file)
index 0000000..cc061e1
--- /dev/null
@@ -0,0 +1,1033 @@
+#ifndef HOSTAP_WLAN_H
+#define HOSTAP_WLAN_H
+
+#include "hostap_config.h"
+#include "hostap_common.h"
+
+#define MAX_PARM_DEVICES 8
+#define PARM_MIN_MAX "1-" __MODULE_STRING(MAX_PARM_DEVICES)
+#define DEF_INTS -1, -1, -1, -1, -1, -1, -1
+#define GET_INT_PARM(var,idx) var[var[idx] < 0 ? 0 : idx]
+
+
+/* Specific skb->protocol value that indicates that the packet already contains
+ * txdesc header.
+ * FIX: This might need own value that would be allocated especially for Prism2
+ * txdesc; ETH_P_CONTROL is commented as "Card specific control frames".
+ * However, these skb's should have only minimal path in the kernel side since
+ * prism2_send_mgmt() sends these with dev_queue_xmit() to prism2_tx(). */
+#define ETH_P_HOSTAP ETH_P_CONTROL
+
+/* ARPHRD_IEEE80211_PRISM uses a bloated version of Prism2 RX frame header
+ * (from linux-wlan-ng) */
+struct linux_wlan_ng_val {
+       u32 did;
+       u16 status, len;
+       u32 data;
+} __attribute__ ((packed));
+
+struct linux_wlan_ng_prism_hdr {
+       u32 msgcode, msglen;
+       char devname[16];
+       struct linux_wlan_ng_val hosttime, mactime, channel, rssi, sq, signal,
+               noise, rate, istx, frmlen;
+} __attribute__ ((packed));
+
+struct linux_wlan_ng_cap_hdr {
+       u32 version;
+       u32 length;
+       u64 mactime;
+       u64 hosttime;
+       u32 phytype;
+       u32 channel;
+       u32 datarate;
+       u32 antenna;
+       u32 priority;
+       u32 ssi_type;
+       s32 ssi_signal;
+       s32 ssi_noise;
+       u32 preamble;
+       u32 encoding;
+} __attribute__ ((packed));
+
+#define LWNG_CAP_DID_BASE   (4 | (1 << 6)) /* section 4, group 1 */
+#define LWNG_CAPHDR_VERSION 0x80211001
+
+struct hfa384x_rx_frame {
+       /* HFA384X RX frame descriptor */
+       u16 status; /* HFA384X_RX_STATUS_ flags */
+       u32 time; /* timestamp, 1 microsecond resolution */
+       u8 silence; /* 27 .. 154; seems to be 0 */
+       u8 signal; /* 27 .. 154 */
+       u8 rate; /* 10, 20, 55, or 110 */
+       u8 rxflow;
+       u32 reserved;
+
+       /* 802.11 */
+       u16 frame_control;
+       u16 duration_id;
+       u8 addr1[6];
+       u8 addr2[6];
+       u8 addr3[6];
+       u16 seq_ctrl;
+       u8 addr4[6];
+       u16 data_len;
+
+       /* 802.3 */
+       u8 dst_addr[6];
+       u8 src_addr[6];
+       u16 len;
+
+       /* followed by frame data; max 2304 bytes */
+} __attribute__ ((packed));
+
+
+struct hfa384x_tx_frame {
+       /* HFA384X TX frame descriptor */
+       u16 status; /* HFA384X_TX_STATUS_ flags */
+       u16 reserved1;
+       u16 reserved2;
+       u32 sw_support;
+       u8 retry_count; /* not yet implemented */
+       u8 tx_rate; /* Host AP only; 0 = firmware, or 10, 20, 55, 110 */
+       u16 tx_control; /* HFA384X_TX_CTRL_ flags */
+
+       /* 802.11 */
+       u16 frame_control; /* parts not used */
+       u16 duration_id;
+       u8 addr1[6];
+       u8 addr2[6]; /* filled by firmware */
+       u8 addr3[6];
+       u16 seq_ctrl; /* filled by firmware */
+       u8 addr4[6];
+       u16 data_len;
+
+       /* 802.3 */
+       u8 dst_addr[6];
+       u8 src_addr[6];
+       u16 len;
+
+       /* followed by frame data; max 2304 bytes */
+} __attribute__ ((packed));
+
+
+struct hfa384x_rid_hdr
+{
+       u16 len;
+       u16 rid;
+} __attribute__ ((packed));
+
+
+/* Macro for converting signal levels (range 27 .. 154) to wireless ext
+ * dBm value with some accuracy */
+#define HFA384X_LEVEL_TO_dBm(v) 0x100 + (v) * 100 / 255 - 100
+
+#define HFA384X_LEVEL_TO_dBm_sign(v) (v) * 100 / 255 - 100
+
+struct hfa384x_scan_request {
+       u16 channel_list;
+       u16 txrate; /* HFA384X_RATES_* */
+} __attribute__ ((packed));
+
+struct hfa384x_hostscan_request {
+       u16 channel_list;
+       u16 txrate;
+       u16 target_ssid_len;
+       u8 target_ssid[32];
+} __attribute__ ((packed));
+
+struct hfa384x_join_request {
+       u8 bssid[6];
+       u16 channel;
+} __attribute__ ((packed));
+
+struct hfa384x_info_frame {
+       u16 len;
+       u16 type;
+} __attribute__ ((packed));
+
+struct hfa384x_comm_tallies {
+       u16 tx_unicast_frames;
+       u16 tx_multicast_frames;
+       u16 tx_fragments;
+       u16 tx_unicast_octets;
+       u16 tx_multicast_octets;
+       u16 tx_deferred_transmissions;
+       u16 tx_single_retry_frames;
+       u16 tx_multiple_retry_frames;
+       u16 tx_retry_limit_exceeded;
+       u16 tx_discards;
+       u16 rx_unicast_frames;
+       u16 rx_multicast_frames;
+       u16 rx_fragments;
+       u16 rx_unicast_octets;
+       u16 rx_multicast_octets;
+       u16 rx_fcs_errors;
+       u16 rx_discards_no_buffer;
+       u16 tx_discards_wrong_sa;
+       u16 rx_discards_wep_undecryptable;
+       u16 rx_message_in_msg_fragments;
+       u16 rx_message_in_bad_msg_fragments;
+} __attribute__ ((packed));
+
+struct hfa384x_comm_tallies32 {
+       u32 tx_unicast_frames;
+       u32 tx_multicast_frames;
+       u32 tx_fragments;
+       u32 tx_unicast_octets;
+       u32 tx_multicast_octets;
+       u32 tx_deferred_transmissions;
+       u32 tx_single_retry_frames;
+       u32 tx_multiple_retry_frames;
+       u32 tx_retry_limit_exceeded;
+       u32 tx_discards;
+       u32 rx_unicast_frames;
+       u32 rx_multicast_frames;
+       u32 rx_fragments;
+       u32 rx_unicast_octets;
+       u32 rx_multicast_octets;
+       u32 rx_fcs_errors;
+       u32 rx_discards_no_buffer;
+       u32 tx_discards_wrong_sa;
+       u32 rx_discards_wep_undecryptable;
+       u32 rx_message_in_msg_fragments;
+       u32 rx_message_in_bad_msg_fragments;
+} __attribute__ ((packed));
+
+struct hfa384x_scan_result_hdr {
+       u16 reserved;
+       u16 scan_reason;
+#define HFA384X_SCAN_IN_PROGRESS 0 /* no results available yet */
+#define HFA384X_SCAN_HOST_INITIATED 1
+#define HFA384X_SCAN_FIRMWARE_INITIATED 2
+#define HFA384X_SCAN_INQUIRY_FROM_HOST 3
+} __attribute__ ((packed));
+
+#define HFA384X_SCAN_MAX_RESULTS 32
+
+struct hfa384x_scan_result {
+       u16 chid;
+       u16 anl;
+       u16 sl;
+       u8 bssid[6];
+       u16 beacon_interval;
+       u16 capability;
+       u16 ssid_len;
+       u8 ssid[32];
+       u8 sup_rates[10];
+       u16 rate;
+} __attribute__ ((packed));
+
+struct hfa384x_hostscan_result {
+       u16 chid;
+       u16 anl;
+       u16 sl;
+       u8 bssid[6];
+       u16 beacon_interval;
+       u16 capability;
+       u16 ssid_len;
+       u8 ssid[32];
+       u8 sup_rates[10];
+       u16 rate;
+       u16 atim;
+} __attribute__ ((packed));
+
+struct comm_tallies_sums {
+       unsigned int tx_unicast_frames;
+       unsigned int tx_multicast_frames;
+       unsigned int tx_fragments;
+       unsigned int tx_unicast_octets;
+       unsigned int tx_multicast_octets;
+       unsigned int tx_deferred_transmissions;
+       unsigned int tx_single_retry_frames;
+       unsigned int tx_multiple_retry_frames;
+       unsigned int tx_retry_limit_exceeded;
+       unsigned int tx_discards;
+       unsigned int rx_unicast_frames;
+       unsigned int rx_multicast_frames;
+       unsigned int rx_fragments;
+       unsigned int rx_unicast_octets;
+       unsigned int rx_multicast_octets;
+       unsigned int rx_fcs_errors;
+       unsigned int rx_discards_no_buffer;
+       unsigned int tx_discards_wrong_sa;
+       unsigned int rx_discards_wep_undecryptable;
+       unsigned int rx_message_in_msg_fragments;
+       unsigned int rx_message_in_bad_msg_fragments;
+};
+
+
+struct hfa384x_regs {
+       u16 cmd;
+       u16 evstat;
+       u16 offset0;
+       u16 offset1;
+       u16 swsupport0;
+};
+
+
+#if defined(PRISM2_PCCARD) || defined(PRISM2_PLX)
+/* I/O ports for HFA384X Controller access */
+#define HFA384X_CMD_OFF 0x00
+#define HFA384X_PARAM0_OFF 0x02
+#define HFA384X_PARAM1_OFF 0x04
+#define HFA384X_PARAM2_OFF 0x06
+#define HFA384X_STATUS_OFF 0x08
+#define HFA384X_RESP0_OFF 0x0A
+#define HFA384X_RESP1_OFF 0x0C
+#define HFA384X_RESP2_OFF 0x0E
+#define HFA384X_INFOFID_OFF 0x10
+#define HFA384X_CONTROL_OFF 0x14
+#define HFA384X_SELECT0_OFF 0x18
+#define HFA384X_SELECT1_OFF 0x1A
+#define HFA384X_OFFSET0_OFF 0x1C
+#define HFA384X_OFFSET1_OFF 0x1E
+#define HFA384X_RXFID_OFF 0x20
+#define HFA384X_ALLOCFID_OFF 0x22
+#define HFA384X_TXCOMPLFID_OFF 0x24
+#define HFA384X_SWSUPPORT0_OFF 0x28
+#define HFA384X_SWSUPPORT1_OFF 0x2A
+#define HFA384X_SWSUPPORT2_OFF 0x2C
+#define HFA384X_EVSTAT_OFF 0x30
+#define HFA384X_INTEN_OFF 0x32
+#define HFA384X_EVACK_OFF 0x34
+#define HFA384X_DATA0_OFF 0x36
+#define HFA384X_DATA1_OFF 0x38
+#define HFA384X_AUXPAGE_OFF 0x3A
+#define HFA384X_AUXOFFSET_OFF 0x3C
+#define HFA384X_AUXDATA_OFF 0x3E
+#endif /* PRISM2_PCCARD || PRISM2_PLX */
+
+#ifdef PRISM2_PCI
+/* Memory addresses for ISL3874 controller access */
+#define HFA384X_CMD_OFF 0x00
+#define HFA384X_PARAM0_OFF 0x04
+#define HFA384X_PARAM1_OFF 0x08
+#define HFA384X_PARAM2_OFF 0x0C
+#define HFA384X_STATUS_OFF 0x10
+#define HFA384X_RESP0_OFF 0x14
+#define HFA384X_RESP1_OFF 0x18
+#define HFA384X_RESP2_OFF 0x1C
+#define HFA384X_INFOFID_OFF 0x20
+#define HFA384X_CONTROL_OFF 0x28
+#define HFA384X_SELECT0_OFF 0x30
+#define HFA384X_SELECT1_OFF 0x34
+#define HFA384X_OFFSET0_OFF 0x38
+#define HFA384X_OFFSET1_OFF 0x3C
+#define HFA384X_RXFID_OFF 0x40
+#define HFA384X_ALLOCFID_OFF 0x44
+#define HFA384X_TXCOMPLFID_OFF 0x48
+#define HFA384X_PCICOR_OFF 0x4C
+#define HFA384X_SWSUPPORT0_OFF 0x50
+#define HFA384X_SWSUPPORT1_OFF 0x54
+#define HFA384X_SWSUPPORT2_OFF 0x58
+#define HFA384X_PCIHCR_OFF 0x5C
+#define HFA384X_EVSTAT_OFF 0x60
+#define HFA384X_INTEN_OFF 0x64
+#define HFA384X_EVACK_OFF 0x68
+#define HFA384X_DATA0_OFF 0x6C
+#define HFA384X_DATA1_OFF 0x70
+#define HFA384X_AUXPAGE_OFF 0x74
+#define HFA384X_AUXOFFSET_OFF 0x78
+#define HFA384X_AUXDATA_OFF 0x7C
+#define HFA384X_PCI_M0_ADDRH_OFF 0x80
+#define HFA384X_PCI_M0_ADDRL_OFF 0x84
+#define HFA384X_PCI_M0_LEN_OFF 0x88
+#define HFA384X_PCI_M0_CTL_OFF 0x8C
+#define HFA384X_PCI_STATUS_OFF 0x98
+#define HFA384X_PCI_M1_ADDRH_OFF 0xA0
+#define HFA384X_PCI_M1_ADDRL_OFF 0xA4
+#define HFA384X_PCI_M1_LEN_OFF 0xA8
+#define HFA384X_PCI_M1_CTL_OFF 0xAC
+
+/* PCI bus master control bits (these are undocumented; based on guessing and
+ * experimenting..) */
+#define HFA384X_PCI_CTL_FROM_BAP (BIT(5) | BIT(1) | BIT(0))
+#define HFA384X_PCI_CTL_TO_BAP (BIT(5) | BIT(0))
+
+#endif /* PRISM2_PCI */
+
+
+/* Command codes for CMD reg. */
+#define HFA384X_CMDCODE_INIT 0x00
+#define HFA384X_CMDCODE_ENABLE 0x01
+#define HFA384X_CMDCODE_DISABLE 0x02
+#define HFA384X_CMDCODE_ALLOC 0x0A
+#define HFA384X_CMDCODE_TRANSMIT 0x0B
+#define HFA384X_CMDCODE_INQUIRE 0x11
+#define HFA384X_CMDCODE_ACCESS 0x21
+#define HFA384X_CMDCODE_ACCESS_WRITE (0x21 | BIT(8))
+#define HFA384X_CMDCODE_DOWNLOAD 0x22
+#define HFA384X_CMDCODE_READMIF 0x30
+#define HFA384X_CMDCODE_WRITEMIF 0x31
+#define HFA384X_CMDCODE_TEST 0x38
+
+#define HFA384X_CMDCODE_MASK 0x3F
+
+/* Test mode operations */
+#define HFA384X_TEST_CHANGE_CHANNEL 0x08
+#define HFA384X_TEST_MONITOR 0x0B
+#define HFA384X_TEST_STOP 0x0F
+#define HFA384X_TEST_CFG_BITS 0x15
+#define HFA384X_TEST_CFG_BIT_ALC BIT(3)
+
+#define HFA384X_CMD_BUSY BIT(15)
+
+#define HFA384X_CMD_TX_RECLAIM BIT(8)
+
+#define HFA384X_OFFSET_ERR BIT(14)
+#define HFA384X_OFFSET_BUSY BIT(15)
+
+
+/* ProgMode for download command */
+#define HFA384X_PROGMODE_DISABLE 0
+#define HFA384X_PROGMODE_ENABLE_VOLATILE 1
+#define HFA384X_PROGMODE_ENABLE_NON_VOLATILE 2
+#define HFA384X_PROGMODE_PROGRAM_NON_VOLATILE 3
+
+#define HFA384X_AUX_MAGIC0 0xfe01
+#define HFA384X_AUX_MAGIC1 0xdc23
+#define HFA384X_AUX_MAGIC2 0xba45
+
+#define HFA384X_AUX_PORT_DISABLED 0
+#define HFA384X_AUX_PORT_DISABLE BIT(14)
+#define HFA384X_AUX_PORT_ENABLE BIT(15)
+#define HFA384X_AUX_PORT_ENABLED (BIT(14) | BIT(15))
+#define HFA384X_AUX_PORT_MASK (BIT(14) | BIT(15))
+
+#define PRISM2_PDA_SIZE 1024
+
+
+/* Events; EvStat, Interrupt mask (IntEn), and acknowledge bits (EvAck) */
+#define HFA384X_EV_TICK BIT(15)
+#define HFA384X_EV_WTERR BIT(14)
+#define HFA384X_EV_INFDROP BIT(13)
+#ifdef PRISM2_PCI
+#define HFA384X_EV_PCI_M1 BIT(9)
+#define HFA384X_EV_PCI_M0 BIT(8)
+#endif /* PRISM2_PCI */
+#define HFA384X_EV_INFO BIT(7)
+#define HFA384X_EV_DTIM BIT(5)
+#define HFA384X_EV_CMD BIT(4)
+#define HFA384X_EV_ALLOC BIT(3)
+#define HFA384X_EV_TXEXC BIT(2)
+#define HFA384X_EV_TX BIT(1)
+#define HFA384X_EV_RX BIT(0)
+
+
+/* HFA384X Information frames */
+#define HFA384X_INFO_HANDOVERADDR 0xF000 /* AP f/w ? */
+#define HFA384X_INFO_HANDOVERDEAUTHADDR 0xF001 /* AP f/w 1.3.7 */
+#define HFA384X_INFO_COMMTALLIES 0xF100
+#define HFA384X_INFO_SCANRESULTS 0xF101
+#define HFA384X_INFO_CHANNELINFORESULTS 0xF102 /* AP f/w only */
+#define HFA384X_INFO_HOSTSCANRESULTS 0xF103
+#define HFA384X_INFO_LINKSTATUS 0xF200
+#define HFA384X_INFO_ASSOCSTATUS 0xF201 /* ? */
+#define HFA384X_INFO_AUTHREQ 0xF202 /* ? */
+#define HFA384X_INFO_PSUSERCNT 0xF203 /* ? */
+#define HFA384X_INFO_KEYIDCHANGED 0xF204 /* ? */
+
+enum { HFA384X_LINKSTATUS_CONNECTED = 1,
+       HFA384X_LINKSTATUS_DISCONNECTED = 2,
+       HFA384X_LINKSTATUS_AP_CHANGE = 3,
+       HFA384X_LINKSTATUS_AP_OUT_OF_RANGE = 4,
+       HFA384X_LINKSTATUS_AP_IN_RANGE = 5,
+       HFA384X_LINKSTATUS_ASSOC_FAILED = 6 };
+
+enum { HFA384X_PORTTYPE_BSS = 1, HFA384X_PORTTYPE_WDS = 2,
+       HFA384X_PORTTYPE_PSEUDO_IBSS = 3, HFA384X_PORTTYPE_IBSS = 0,
+       HFA384X_PORTTYPE_HOSTAP = 6 };
+
+#define HFA384X_RATES_1MBPS BIT(0)
+#define HFA384X_RATES_2MBPS BIT(1)
+#define HFA384X_RATES_5MBPS BIT(2)
+#define HFA384X_RATES_11MBPS BIT(3)
+
+#define HFA384X_ROAMING_FIRMWARE 1
+#define HFA384X_ROAMING_HOST 2
+#define HFA384X_ROAMING_DISABLED 3
+
+#define HFA384X_WEPFLAGS_PRIVACYINVOKED BIT(0)
+#define HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED BIT(1)
+#define HFA384X_WEPFLAGS_HOSTENCRYPT BIT(4)
+#define HFA384X_WEPFLAGS_HOSTDECRYPT BIT(7)
+
+#define HFA384X_RX_STATUS_MSGTYPE (BIT(15) | BIT(14) | BIT(13))
+#define HFA384X_RX_STATUS_PCF BIT(12)
+#define HFA384X_RX_STATUS_MACPORT (BIT(10) | BIT(9) | BIT(8))
+#define HFA384X_RX_STATUS_UNDECR BIT(1)
+#define HFA384X_RX_STATUS_FCSERR BIT(0)
+
+#define HFA384X_RX_STATUS_GET_MSGTYPE(s) \
+(((s) & HFA384X_RX_STATUS_MSGTYPE) >> 13)
+#define HFA384X_RX_STATUS_GET_MACPORT(s) \
+(((s) & HFA384X_RX_STATUS_MACPORT) >> 8)
+
+enum { HFA384X_RX_MSGTYPE_NORMAL = 0, HFA384X_RX_MSGTYPE_RFC1042 = 1,
+       HFA384X_RX_MSGTYPE_BRIDGETUNNEL = 2, HFA384X_RX_MSGTYPE_MGMT = 4 };
+
+
+#define HFA384X_TX_CTRL_ALT_RTRY BIT(5)
+#define HFA384X_TX_CTRL_802_11 BIT(3)
+#define HFA384X_TX_CTRL_802_3 0
+#define HFA384X_TX_CTRL_TX_EX BIT(2)
+#define HFA384X_TX_CTRL_TX_OK BIT(1)
+
+#define HFA384X_TX_STATUS_RETRYERR BIT(0)
+#define HFA384X_TX_STATUS_AGEDERR BIT(1)
+#define HFA384X_TX_STATUS_DISCON BIT(2)
+#define HFA384X_TX_STATUS_FORMERR BIT(3)
+
+/* HFA3861/3863 (BBP) Control Registers */
+#define HFA386X_CR_TX_CONFIGURE 0x12 /* CR9 */
+#define HFA386X_CR_RX_CONFIGURE 0x14 /* CR10 */
+#define HFA386X_CR_A_D_TEST_MODES2 0x1A /* CR13 */
+#define HFA386X_CR_MANUAL_TX_POWER 0x3E /* CR31 */
+#define HFA386X_CR_MEASURED_TX_POWER 0x74 /* CR58 */
+
+
+#ifdef __KERNEL__
+
+#define PRISM2_TXFID_COUNT 8
+#define PRISM2_DATA_MAXLEN 2304
+#define PRISM2_TXFID_LEN (PRISM2_DATA_MAXLEN + sizeof(struct hfa384x_tx_frame))
+#define PRISM2_TXFID_EMPTY 0xffff
+#define PRISM2_TXFID_RESERVED 0xfffe
+#define PRISM2_DUMMY_FID 0xffff
+#define MAX_SSID_LEN 32
+#define MAX_NAME_LEN 32 /* this is assumed to be equal to MAX_SSID_LEN */
+
+#define PRISM2_DUMP_RX_HDR BIT(0)
+#define PRISM2_DUMP_TX_HDR BIT(1)
+#define PRISM2_DUMP_TXEXC_HDR BIT(2)
+
+struct hostap_tx_callback_info {
+       u16 idx;
+       void (*func)(struct sk_buff *, int ok, void *);
+       void *data;
+       struct hostap_tx_callback_info *next;
+};
+
+
+/* IEEE 802.11 requires that STA supports concurrent reception of at least
+ * three fragmented frames. This define can be increased to support more
+ * concurrent frames, but it should be noted that each entry can consume about
+ * 2 kB of RAM and increasing cache size will slow down frame reassembly. */
+#define PRISM2_FRAG_CACHE_LEN 4
+
+struct prism2_frag_entry {
+       unsigned long first_frag_time;
+       unsigned int seq;
+       unsigned int last_frag;
+       struct sk_buff *skb;
+       u8 src_addr[ETH_ALEN];
+       u8 dst_addr[ETH_ALEN];
+};
+
+
+struct hostap_cmd_queue {
+       struct list_head list;
+       wait_queue_head_t compl;
+       volatile enum { CMD_SLEEP, CMD_CALLBACK, CMD_COMPLETED } type;
+       void (*callback)(struct net_device *dev, long context, u16 resp0,
+                        u16 res);
+       long context;
+       u16 cmd, param0, param1;
+       u16 resp0, res;
+       volatile int issued, issuing;
+
+       atomic_t usecnt;
+       int del_req;
+};
+
+/* options for hw_shutdown */
+#define HOSTAP_HW_NO_DISABLE BIT(0)
+#define HOSTAP_HW_ENABLE_CMDCOMPL BIT(1)
+
+typedef struct local_info local_info_t;
+
+struct prism2_helper_functions {
+       /* these functions are defined in hardware model specific files
+        * (hostap_{cs,plx,pci}.c */
+       int (*card_present)(local_info_t *local);
+       void (*cor_sreset)(local_info_t *local);
+       int (*dev_open)(local_info_t *local);
+       int (*dev_close)(local_info_t *local);
+       void (*genesis_reset)(local_info_t *local, int hcr);
+
+       /* the following functions are from hostap_hw.c, but they may have some
+        * hardware model specific code */
+
+       /* FIX: low-level commands like cmd might disappear at some point to
+        * make it easier to change them if needed (e.g., cmd would be replaced
+        * with write_mif/read_mif/testcmd/inquire); at least get_rid and
+        * set_rid might move to hostap_{cs,plx,pci}.c */
+       int (*cmd)(struct net_device *dev, u16 cmd, u16 param0, u16 *param1,
+                  u16 *resp0);
+       void (*read_regs)(struct net_device *dev, struct hfa384x_regs *regs);
+       int (*get_rid)(struct net_device *dev, u16 rid, void *buf, int len,
+                      int exact_len);
+       int (*set_rid)(struct net_device *dev, u16 rid, void *buf, int len);
+       int (*hw_enable)(struct net_device *dev, int initial);
+       int (*hw_config)(struct net_device *dev, int initial);
+       void (*hw_reset)(struct net_device *dev);
+       void (*hw_shutdown)(struct net_device *dev, int no_disable);
+       int (*reset_port)(struct net_device *dev);
+       void (*schedule_reset)(local_info_t *local);
+       int (*download)(local_info_t *local,
+                       struct prism2_download_param *param);
+       int (*tx)(struct sk_buff *skb, struct net_device *dev);
+       int (*set_tim)(struct net_device *dev, int aid, int set);
+       int (*read_aux)(struct net_device *dev, unsigned addr, int len,
+                       u8 *buf);
+
+       int need_tx_headroom; /* number of bytes of headroom needed before
+                              * IEEE 802.11 header */
+       enum { HOSTAP_HW_PCCARD, HOSTAP_HW_PLX, HOSTAP_HW_PCI } hw_type;
+};
+
+
+struct prism2_download_data {
+       u32 dl_cmd;
+       u32 start_addr;
+       u32 num_areas;
+       struct prism2_download_data_area {
+               u32 addr; /* wlan card address */
+               u32 len;
+               u8 *data; /* allocated data */
+       } data[0];
+};
+
+
+#define HOSTAP_MAX_BSS_COUNT 64
+#define MAX_WPA_IE_LEN 64
+
+struct hostap_bss_info {
+       struct list_head list;
+       unsigned long last_update;
+       unsigned int count;
+       u8 bssid[ETH_ALEN];
+       u16 capab_info;
+       u8 ssid[32];
+       size_t ssid_len;
+       u8 wpa_ie[MAX_WPA_IE_LEN];
+       size_t wpa_ie_len;
+       u8 rsn_ie[MAX_WPA_IE_LEN];
+       size_t rsn_ie_len;
+       int chan;
+       int included;
+};
+
+
+/* Per radio private Host AP data - shared by all net devices interfaces used
+ * by each radio (wlan#, wlan#ap, wlan#sta, WDS).
+ * ((struct hostap_interface *) netdev_priv(dev))->local points to this
+ * structure. */
+struct local_info {
+       struct module *hw_module;
+       int card_idx;
+       int dev_enabled;
+       int master_dev_auto_open; /* was master device opened automatically */
+       int num_dev_open; /* number of open devices */
+       struct net_device *dev; /* master radio device */
+       struct net_device *ddev; /* main data device */
+       struct list_head hostap_interfaces; /* Host AP interface list (contains
+                                            * struct hostap_interface entries)
+                                            */
+       rwlock_t iface_lock; /* hostap_interfaces read lock; use write lock
+                             * when removing entries from the list.
+                             * TX and RX paths can use read lock. */
+       spinlock_t cmdlock, baplock, lock;
+       struct semaphore rid_bap_sem;
+       u16 infofid; /* MAC buffer id for info frame */
+       /* txfid, intransmitfid, next_txtid, and next_alloc are protected by
+        * txfidlock */
+       spinlock_t txfidlock;
+       int txfid_len; /* length of allocated TX buffers */
+       u16 txfid[PRISM2_TXFID_COUNT]; /* buffer IDs for TX frames */
+       /* buffer IDs for intransmit frames or PRISM2_TXFID_EMPTY if
+        * corresponding txfid is free for next TX frame */
+       u16 intransmitfid[PRISM2_TXFID_COUNT];
+       int next_txfid; /* index to the next txfid to be checked for
+                        * availability */
+       int next_alloc; /* index to the next intransmitfid to be checked for
+                        * allocation events */
+
+       /* bitfield for atomic bitops */
+#define HOSTAP_BITS_TRANSMIT 0
+#define HOSTAP_BITS_BAP_TASKLET 1
+#define HOSTAP_BITS_BAP_TASKLET2 2
+       long bits;
+
+       struct ap_data *ap;
+
+       char essid[MAX_SSID_LEN + 1];
+       char name[MAX_NAME_LEN + 1];
+       int name_set;
+       u16 channel_mask; /* mask of allowed channels */
+       u16 scan_channel_mask; /* mask of channels to be scanned */
+       struct comm_tallies_sums comm_tallies;
+       struct net_device_stats stats;
+       struct proc_dir_entry *proc;
+       int iw_mode; /* operating mode (IW_MODE_*) */
+       int pseudo_adhoc; /* 0: IW_MODE_ADHOC is real 802.11 compliant IBSS
+                          * 1: IW_MODE_ADHOC is "pseudo IBSS" */
+       char bssid[ETH_ALEN];
+       int channel;
+       int beacon_int;
+       int dtim_period;
+       int mtu;
+       int frame_dump; /* dump RX/TX frame headers, PRISM2_DUMP_ flags */
+       int fw_tx_rate_control;
+       u16 tx_rate_control;
+       u16 basic_rates;
+       int hw_resetting;
+       int hw_ready;
+       int hw_reset_tries; /* how many times reset has been tried */
+       int hw_downloading;
+       int shutdown;
+       int pri_only;
+       int no_pri; /* no PRI f/w present */
+       int sram_type; /* 8 = x8 SRAM, 16 = x16 SRAM, -1 = unknown */
+
+       enum {
+               PRISM2_TXPOWER_AUTO = 0, PRISM2_TXPOWER_OFF,
+               PRISM2_TXPOWER_FIXED, PRISM2_TXPOWER_UNKNOWN
+       } txpower_type;
+       int txpower; /* if txpower_type == PRISM2_TXPOWER_FIXED */
+
+       /* command queue for hfa384x_cmd(); protected with cmdlock */
+       struct list_head cmd_queue;
+       /* max_len for cmd_queue; in addition, cmd_callback can use two
+        * additional entries to prevent sleeping commands from stopping
+        * transmits */
+#define HOSTAP_CMD_QUEUE_MAX_LEN 16
+       int cmd_queue_len; /* number of entries in cmd_queue */
+
+       /* if card timeout is detected in interrupt context, reset_queue is
+        * used to schedule card reseting to be done in user context */
+       struct work_struct reset_queue;
+
+       /* For scheduling a change of the promiscuous mode RID */
+       int is_promisc;
+       struct work_struct set_multicast_list_queue;
+
+       struct work_struct set_tim_queue;
+       struct list_head set_tim_list;
+       spinlock_t set_tim_lock;
+
+       int wds_max_connections;
+       int wds_connections;
+#define HOSTAP_WDS_BROADCAST_RA BIT(0)
+#define HOSTAP_WDS_AP_CLIENT BIT(1)
+#define HOSTAP_WDS_STANDARD_FRAME BIT(2)
+       u32 wds_type;
+       u16 tx_control; /* flags to be used in TX description */
+       int manual_retry_count; /* -1 = use f/w default; otherwise retry count
+                                * to be used with all frames */
+
+       struct iw_statistics wstats;
+       unsigned long scan_timestamp; /* Time started to scan */
+       enum {
+               PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1,
+               PRISM2_MONITOR_CAPHDR = 2
+       } monitor_type;
+       int (*saved_eth_header_parse)(struct sk_buff *skb,
+                                     unsigned char *haddr);
+       int monitor_allow_fcserr;
+
+       int hostapd; /* whether user space daemon, hostapd, is used for AP
+                     * management */
+       int hostapd_sta; /* whether hostapd is used with an extra STA interface
+                         */
+       struct net_device *apdev;
+       struct net_device_stats apdevstats;
+
+       char assoc_ap_addr[ETH_ALEN];
+       struct net_device *stadev;
+       struct net_device_stats stadevstats;
+
+#define WEP_KEYS 4
+#define WEP_KEY_LEN 13
+       struct ieee80211_crypt_data *crypt[WEP_KEYS];
+       int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */
+       struct timer_list crypt_deinit_timer;
+       struct list_head crypt_deinit_list;
+
+       int open_wep; /* allow unencrypted frames */
+       int host_encrypt;
+       int host_decrypt;
+       int privacy_invoked; /* force privacy invoked flag even if no keys are
+                             * configured */
+       int fw_encrypt_ok; /* whether firmware-based WEP encrypt is working
+                           * in Host AP mode (STA f/w 1.4.9 or newer) */
+       int bcrx_sta_key; /* use individual keys to override default keys even
+                          * with RX of broad/multicast frames */
+
+       struct prism2_frag_entry frag_cache[PRISM2_FRAG_CACHE_LEN];
+       unsigned int frag_next_idx;
+
+       int ieee_802_1x; /* is IEEE 802.1X used */
+
+       int antsel_tx, antsel_rx;
+       int rts_threshold; /* dot11RTSThreshold */
+       int fragm_threshold; /* dot11FragmentationThreshold */
+       int auth_algs; /* PRISM2_AUTH_ flags */
+
+       int enh_sec; /* cnfEnhSecurity options (broadcast SSID hide/ignore) */
+       int tallies32; /* 32-bit tallies in use */
+
+       struct prism2_helper_functions *func;
+
+       u8 *pda;
+       int fw_ap;
+#define PRISM2_FW_VER(major, minor, variant) \
+(((major) << 16) | ((minor) << 8) | variant)
+       u32 sta_fw_ver;
+
+       /* Tasklets for handling hardware IRQ related operations outside hw IRQ
+        * handler */
+       struct tasklet_struct bap_tasklet;
+
+       struct tasklet_struct info_tasklet;
+       struct sk_buff_head info_list; /* info frames as skb's for
+                                       * info_tasklet */
+
+       struct hostap_tx_callback_info *tx_callback; /* registered TX callbacks
+                                                     */
+
+       struct tasklet_struct rx_tasklet;
+       struct sk_buff_head rx_list;
+
+       struct tasklet_struct sta_tx_exc_tasklet;
+       struct sk_buff_head sta_tx_exc_list;
+
+       int host_roaming;
+       unsigned long last_join_time; /* time of last JoinRequest */
+       struct hfa384x_hostscan_result *last_scan_results;
+       int last_scan_results_count;
+       enum { PRISM2_SCAN, PRISM2_HOSTSCAN } last_scan_type;
+       struct work_struct info_queue;
+       long pending_info; /* bit field of pending info_queue items */
+#define PRISM2_INFO_PENDING_LINKSTATUS 0
+#define PRISM2_INFO_PENDING_SCANRESULTS 1
+       int prev_link_status; /* previous received LinkStatus info */
+       int prev_linkstatus_connected;
+       u8 preferred_ap[6]; /* use this AP if possible */
+
+#ifdef PRISM2_CALLBACK
+       void *callback_data; /* Can be used in callbacks; e.g., allocate
+                             * on enable event and free on disable event.
+                             * Host AP driver code does not touch this. */
+#endif /* PRISM2_CALLBACK */
+
+       wait_queue_head_t hostscan_wq;
+
+       /* Passive scan in Host AP mode */
+       struct timer_list passive_scan_timer;
+       int passive_scan_interval; /* in seconds, 0 = disabled */
+       int passive_scan_channel;
+       enum { PASSIVE_SCAN_WAIT, PASSIVE_SCAN_LISTEN } passive_scan_state;
+
+       struct timer_list tick_timer;
+       unsigned long last_tick_timer;
+       unsigned int sw_tick_stuck;
+
+       /* commsQuality / dBmCommsQuality data from periodic polling; only
+        * valid for Managed and Ad-hoc modes */
+       unsigned long last_comms_qual_update;
+       int comms_qual; /* in some odd unit.. */
+       int avg_signal; /* in dB (note: negative) */
+       int avg_noise; /* in dB (note: negative) */
+       struct work_struct comms_qual_update;
+
+       /* RSSI to dBm adjustment (for RX descriptor fields) */
+       int rssi_to_dBm; /* substract from RSSI to get approximate dBm value */
+
+       /* BSS list / protected by local->lock */
+       struct list_head bss_list;
+       int num_bss_info;
+       int wpa; /* WPA support enabled */
+       int tkip_countermeasures;
+       int drop_unencrypted;
+       /* Generic IEEE 802.11 info element to be added to
+        * ProbeResp/Beacon/(Re)AssocReq */
+       u8 *generic_elem;
+       size_t generic_elem_len;
+
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+       /* Persistent volatile download data */
+       struct prism2_download_data *dl_pri;
+       struct prism2_download_data *dl_sec;
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+
+#ifdef PRISM2_IO_DEBUG
+#define PRISM2_IO_DEBUG_SIZE 10000
+       u32 io_debug[PRISM2_IO_DEBUG_SIZE];
+       int io_debug_head;
+       int io_debug_enabled;
+#endif /* PRISM2_IO_DEBUG */
+
+       /* Pointer to hardware model specific (cs,pci,plx) private data. */
+       void *hw_priv;
+};
+
+
+/* Per interface private Host AP data
+ * Allocated for each net device that Host AP uses (wlan#, wlan#ap, wlan#sta,
+ * WDS) and netdev_priv(dev) points to this structure. */
+struct hostap_interface {
+       struct list_head list; /* list entry in Host AP interface list */
+       struct net_device *dev; /* pointer to this device */
+       struct local_info *local; /* pointer to shared private data */
+       struct net_device_stats stats;
+       struct iw_spy_data spy_data; /* iwspy support */
+       struct iw_public_data wireless_data;
+
+       enum {
+               HOSTAP_INTERFACE_MASTER,
+               HOSTAP_INTERFACE_MAIN,
+               HOSTAP_INTERFACE_AP,
+               HOSTAP_INTERFACE_STA,
+               HOSTAP_INTERFACE_WDS,
+       } type;
+
+       union {
+               struct hostap_interface_wds {
+                       u8 remote_addr[ETH_ALEN];
+               } wds;
+       } u;
+};
+
+
+#define HOSTAP_SKB_TX_DATA_MAGIC 0xf08a36a2
+
+/*
+ * TX meta data - stored in skb->cb buffer, so this must not be increased over
+ * the 40-byte limit
+ */
+struct hostap_skb_tx_data {
+       u32 magic; /* HOSTAP_SKB_TX_DATA_MAGIC */
+       u8 rate; /* transmit rate */
+#define HOSTAP_TX_FLAGS_WDS BIT(0)
+#define HOSTAP_TX_FLAGS_BUFFERED_FRAME BIT(1)
+#define HOSTAP_TX_FLAGS_ADD_MOREDATA BIT(2)
+       u8 flags; /* HOSTAP_TX_FLAGS_* */
+       u16 tx_cb_idx;
+       struct hostap_interface *iface;
+       unsigned long jiffies; /* queueing timestamp */
+       unsigned short ethertype;
+};
+
+
+#ifndef PRISM2_NO_DEBUG
+
+#define DEBUG_FID BIT(0)
+#define DEBUG_PS BIT(1)
+#define DEBUG_FLOW BIT(2)
+#define DEBUG_AP BIT(3)
+#define DEBUG_HW BIT(4)
+#define DEBUG_EXTRA BIT(5)
+#define DEBUG_EXTRA2 BIT(6)
+#define DEBUG_PS2 BIT(7)
+#define DEBUG_MASK (DEBUG_PS | DEBUG_AP | DEBUG_HW | DEBUG_EXTRA)
+#define PDEBUG(n, args...) \
+do { if ((n) & DEBUG_MASK) printk(KERN_DEBUG args); } while (0)
+#define PDEBUG2(n, args...) \
+do { if ((n) & DEBUG_MASK) printk(args); } while (0)
+
+#else /* PRISM2_NO_DEBUG */
+
+#define PDEBUG(n, args...)
+#define PDEBUG2(n, args...)
+
+#endif /* PRISM2_NO_DEBUG */
+
+enum { BAP0 = 0, BAP1 = 1 };
+
+#define PRISM2_IO_DEBUG_CMD_INB 0
+#define PRISM2_IO_DEBUG_CMD_INW 1
+#define PRISM2_IO_DEBUG_CMD_INSW 2
+#define PRISM2_IO_DEBUG_CMD_OUTB 3
+#define PRISM2_IO_DEBUG_CMD_OUTW 4
+#define PRISM2_IO_DEBUG_CMD_OUTSW 5
+#define PRISM2_IO_DEBUG_CMD_ERROR 6
+#define PRISM2_IO_DEBUG_CMD_INTERRUPT 7
+
+#ifdef PRISM2_IO_DEBUG
+
+#define PRISM2_IO_DEBUG_ENTRY(cmd, reg, value) \
+(((cmd) << 24) | ((reg) << 16) | value)
+
+static inline void prism2_io_debug_add(struct net_device *dev, int cmd,
+                                      int reg, int value)
+{
+       struct hostap_interface *iface = netdev_priv(dev);
+       local_info_t *local = iface->local;
+
+       if (!local->io_debug_enabled)
+               return;
+
+       local->io_debug[local->io_debug_head] = jiffies & 0xffffffff;
+       if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE)
+               local->io_debug_head = 0;
+       local->io_debug[local->io_debug_head] =
+               PRISM2_IO_DEBUG_ENTRY(cmd, reg, value);
+       if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE)
+               local->io_debug_head = 0;
+}
+
+
+static inline void prism2_io_debug_error(struct net_device *dev, int err)
+{
+       struct hostap_interface *iface = netdev_priv(dev);
+       local_info_t *local = iface->local;
+       unsigned long flags;
+
+       if (!local->io_debug_enabled)
+               return;
+
+       spin_lock_irqsave(&local->lock, flags);
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_ERROR, 0, err);
+       if (local->io_debug_enabled == 1) {
+               local->io_debug_enabled = 0;
+               printk(KERN_DEBUG "%s: I/O debug stopped\n", dev->name);
+       }
+       spin_unlock_irqrestore(&local->lock, flags);
+}
+
+#else /* PRISM2_IO_DEBUG */
+
+static inline void prism2_io_debug_add(struct net_device *dev, int cmd,
+                                      int reg, int value)
+{
+}
+
+static inline void prism2_io_debug_error(struct net_device *dev, int err)
+{
+}
+
+#endif /* PRISM2_IO_DEBUG */
+
+
+#ifdef PRISM2_CALLBACK
+enum {
+       /* Called when card is enabled */
+       PRISM2_CALLBACK_ENABLE,
+
+       /* Called when card is disabled */
+       PRISM2_CALLBACK_DISABLE,
+
+       /* Called when RX/TX starts/ends */
+       PRISM2_CALLBACK_RX_START, PRISM2_CALLBACK_RX_END,
+       PRISM2_CALLBACK_TX_START, PRISM2_CALLBACK_TX_END
+};
+void prism2_callback(local_info_t *local, int event);
+#else /* PRISM2_CALLBACK */
+#define prism2_callback(d, e) do { } while (0)
+#endif /* PRISM2_CALLBACK */
+
+#endif /* __KERNEL__ */
+
+#endif /* HOSTAP_WLAN_H */
diff --git a/drivers/net/wireless/ieee802_11.h b/drivers/net/wireless/ieee802_11.h
deleted file mode 100644 (file)
index 53dd524..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#ifndef _IEEE802_11_H
-#define _IEEE802_11_H
-
-#define IEEE802_11_DATA_LEN            2304
-/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
-   6.2.1.1.2.
-
-   The figure in section 7.1.2 suggests a body size of up to 2312
-   bytes is allowed, which is a bit confusing, I suspect this
-   represents the 2304 bytes of real data, plus a possible 8 bytes of
-   WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
-
-
-#define IEEE802_11_HLEN                        30
-#define IEEE802_11_FRAME_LEN           (IEEE802_11_DATA_LEN + IEEE802_11_HLEN)
-
-struct ieee802_11_hdr {
-       u16 frame_ctl;
-       u16 duration_id;
-       u8 addr1[ETH_ALEN];
-       u8 addr2[ETH_ALEN];
-       u8 addr3[ETH_ALEN];
-       u16 seq_ctl;
-       u8 addr4[ETH_ALEN];
-} __attribute__ ((packed));
-
-/* Frame control field constants */
-#define IEEE802_11_FCTL_VERS           0x0002
-#define IEEE802_11_FCTL_FTYPE          0x000c
-#define IEEE802_11_FCTL_STYPE          0x00f0
-#define IEEE802_11_FCTL_TODS           0x0100
-#define IEEE802_11_FCTL_FROMDS         0x0200
-#define IEEE802_11_FCTL_MOREFRAGS      0x0400
-#define IEEE802_11_FCTL_RETRY          0x0800
-#define IEEE802_11_FCTL_PM             0x1000
-#define IEEE802_11_FCTL_MOREDATA       0x2000
-#define IEEE802_11_FCTL_WEP            0x4000
-#define IEEE802_11_FCTL_ORDER          0x8000
-
-#define IEEE802_11_FTYPE_MGMT          0x0000
-#define IEEE802_11_FTYPE_CTL           0x0004
-#define IEEE802_11_FTYPE_DATA          0x0008
-
-/* management */
-#define IEEE802_11_STYPE_ASSOC_REQ     0x0000
-#define IEEE802_11_STYPE_ASSOC_RESP    0x0010
-#define IEEE802_11_STYPE_REASSOC_REQ   0x0020
-#define IEEE802_11_STYPE_REASSOC_RESP  0x0030
-#define IEEE802_11_STYPE_PROBE_REQ     0x0040
-#define IEEE802_11_STYPE_PROBE_RESP    0x0050
-#define IEEE802_11_STYPE_BEACON                0x0080
-#define IEEE802_11_STYPE_ATIM          0x0090
-#define IEEE802_11_STYPE_DISASSOC      0x00A0
-#define IEEE802_11_STYPE_AUTH          0x00B0
-#define IEEE802_11_STYPE_DEAUTH                0x00C0
-
-/* control */
-#define IEEE802_11_STYPE_PSPOLL                0x00A0
-#define IEEE802_11_STYPE_RTS           0x00B0
-#define IEEE802_11_STYPE_CTS           0x00C0
-#define IEEE802_11_STYPE_ACK           0x00D0
-#define IEEE802_11_STYPE_CFEND         0x00E0
-#define IEEE802_11_STYPE_CFENDACK      0x00F0
-
-/* data */
-#define IEEE802_11_STYPE_DATA          0x0000
-#define IEEE802_11_STYPE_DATA_CFACK    0x0010
-#define IEEE802_11_STYPE_DATA_CFPOLL   0x0020
-#define IEEE802_11_STYPE_DATA_CFACKPOLL        0x0030
-#define IEEE802_11_STYPE_NULLFUNC      0x0040
-#define IEEE802_11_STYPE_CFACK         0x0050
-#define IEEE802_11_STYPE_CFPOLL                0x0060
-#define IEEE802_11_STYPE_CFACKPOLL     0x0070
-
-#define IEEE802_11_SCTL_FRAG           0x000F
-#define IEEE802_11_SCTL_SEQ            0xFFF0
-
-#endif /* _IEEE802_11_H */
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
new file mode 100644 (file)
index 0000000..2414e64
--- /dev/null
@@ -0,0 +1,8680 @@
+/******************************************************************************
+
+  Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+
+  Contact Information:
+  James P. Ketrenos <ipw2100-admin@linux.intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+  Portions of this file are based on the sample_* files provided by Wireless
+  Extensions 0.26 package and copyright (c) 1997-2003 Jean Tourrilhes
+  <jt@hpl.hp.com>
+
+  Portions of this file are based on the Host AP project,
+  Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+    <jkmaline@cc.hut.fi>
+  Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+
+  Portions of ipw2100_mod_firmware_load, ipw2100_do_mod_firmware_load, and
+  ipw2100_fw_load are loosely based on drivers/sound/sound_firmware.c
+  available in the 2.4.25 kernel sources, and are copyright (c) Alan Cox
+
+******************************************************************************/
+/*
+
+ Initial driver on which this is based was developed by Janusz Gorycki,
+ Maciej Urbaniak, and Maciej Sosnowski.
+
+ Promiscuous mode support added by Jacek Wysoczynski and Maciej Urbaniak.
+
+Theory of Operation
+
+Tx - Commands and Data
+
+Firmware and host share a circular queue of Transmit Buffer Descriptors (TBDs)
+Each TBD contains a pointer to the physical (dma_addr_t) address of data being
+sent to the firmware as well as the length of the data.
+
+The host writes to the TBD queue at the WRITE index.  The WRITE index points
+to the _next_ packet to be written and is advanced when after the TBD has been
+filled.
+
+The firmware pulls from the TBD queue at the READ index.  The READ index points
+to the currently being read entry, and is advanced once the firmware is
+done with a packet.
+
+When data is sent to the firmware, the first TBD is used to indicate to the
+firmware if a Command or Data is being sent.  If it is Command, all of the
+command information is contained within the physical address referred to by the
+TBD.  If it is Data, the first TBD indicates the type of data packet, number
+of fragments, etc.  The next TBD then referrs to the actual packet location.
+
+The Tx flow cycle is as follows:
+
+1) ipw2100_tx() is called by kernel with SKB to transmit
+2) Packet is move from the tx_free_list and appended to the transmit pending
+   list (tx_pend_list)
+3) work is scheduled to move pending packets into the shared circular queue.
+4) when placing packet in the circular queue, the incoming SKB is DMA mapped
+   to a physical address.  That address is entered into a TBD.  Two TBDs are
+   filled out.  The first indicating a data packet, the second referring to the
+   actual payload data.
+5) the packet is removed from tx_pend_list and placed on the end of the
+   firmware pending list (fw_pend_list)
+6) firmware is notified that the WRITE index has
+7) Once the firmware has processed the TBD, INTA is triggered.
+8) For each Tx interrupt received from the firmware, the READ index is checked
+   to see which TBDs are done being processed.
+9) For each TBD that has been processed, the ISR pulls the oldest packet
+   from the fw_pend_list.
+10)The packet structure contained in the fw_pend_list is then used
+   to unmap the DMA address and to free the SKB originally passed to the driver
+   from the kernel.
+11)The packet structure is placed onto the tx_free_list
+
+The above steps are the same for commands, only the msg_free_list/msg_pend_list
+are used instead of tx_free_list/tx_pend_list
+
+...
+
+Critical Sections / Locking :
+
+There are two locks utilized.  The first is the low level lock (priv->low_lock)
+that protects the following:
+
+- Access to the Tx/Rx queue lists via priv->low_lock. The lists are as follows:
+
+  tx_free_list : Holds pre-allocated Tx buffers.
+    TAIL modified in __ipw2100_tx_process()
+    HEAD modified in ipw2100_tx()
+
+  tx_pend_list : Holds used Tx buffers waiting to go into the TBD ring
+    TAIL modified ipw2100_tx()
+    HEAD modified by ipw2100_tx_send_data()
+
+  msg_free_list : Holds pre-allocated Msg (Command) buffers
+    TAIL modified in __ipw2100_tx_process()
+    HEAD modified in ipw2100_hw_send_command()
+
+  msg_pend_list : Holds used Msg buffers waiting to go into the TBD ring
+    TAIL modified in ipw2100_hw_send_command()
+    HEAD modified in ipw2100_tx_send_commands()
+
+  The flow of data on the TX side is as follows:
+
+  MSG_FREE_LIST + COMMAND => MSG_PEND_LIST => TBD => MSG_FREE_LIST
+  TX_FREE_LIST + DATA => TX_PEND_LIST => TBD => TX_FREE_LIST
+
+  The methods that work on the TBD ring are protected via priv->low_lock.
+
+- The internal data state of the device itself
+- Access to the firmware read/write indexes for the BD queues
+  and associated logic
+
+All external entry functions are locked with the priv->action_lock to ensure
+that only one external action is invoked at a time.
+
+
+*/
+
+#include <linux/compiler.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/in6.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#define __KERNEL_SYSCALLS__
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/unistd.h>
+#include <linux/stringify.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/time.h>
+#include <linux/firmware.h>
+#include <linux/acpi.h>
+#include <linux/ctype.h>
+
+#include "ipw2100.h"
+
+#define IPW2100_VERSION "1.1.0"
+
+#define DRV_NAME       "ipw2100"
+#define DRV_VERSION    IPW2100_VERSION
+#define DRV_DESCRIPTION        "Intel(R) PRO/Wireless 2100 Network Driver"
+#define DRV_COPYRIGHT  "Copyright(c) 2003-2004 Intel Corporation"
+
+
+/* Debugging stuff */
+#ifdef CONFIG_IPW_DEBUG
+#define CONFIG_IPW2100_RX_DEBUG   /* Reception debugging */
+#endif
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_LICENSE("GPL");
+
+static int debug = 0;
+static int mode = 0;
+static int channel = 0;
+static int associate = 1;
+static int disable = 0;
+#ifdef CONFIG_PM
+static struct ipw2100_fw ipw2100_firmware;
+#endif
+
+#include <linux/moduleparam.h>
+module_param(debug, int, 0444);
+module_param(mode, int, 0444);
+module_param(channel, int, 0444);
+module_param(associate, int, 0444);
+module_param(disable, int, 0444);
+
+MODULE_PARM_DESC(debug, "debug level");
+MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
+MODULE_PARM_DESC(channel, "channel");
+MODULE_PARM_DESC(associate, "auto associate when scanning (default on)");
+MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
+
+static u32 ipw2100_debug_level = IPW_DL_NONE;
+
+#ifdef CONFIG_IPW_DEBUG
+#define IPW_DEBUG(level, message...) \
+do { \
+       if (ipw2100_debug_level & (level)) { \
+               printk(KERN_DEBUG "ipw2100: %c %s ", \
+                       in_interrupt() ? 'I' : 'U',  __FUNCTION__); \
+               printk(message); \
+       } \
+} while (0)
+#else
+#define IPW_DEBUG(level, message...) do {} while (0)
+#endif /* CONFIG_IPW_DEBUG */
+
+#ifdef CONFIG_IPW_DEBUG
+static const char *command_types[] = {
+       "undefined",
+       "unused", /* HOST_ATTENTION */
+       "HOST_COMPLETE",
+       "unused", /* SLEEP */
+       "unused", /* HOST_POWER_DOWN */
+       "unused",
+       "SYSTEM_CONFIG",
+       "unused", /* SET_IMR */
+       "SSID",
+       "MANDATORY_BSSID",
+       "AUTHENTICATION_TYPE",
+       "ADAPTER_ADDRESS",
+       "PORT_TYPE",
+       "INTERNATIONAL_MODE",
+       "CHANNEL",
+       "RTS_THRESHOLD",
+       "FRAG_THRESHOLD",
+       "POWER_MODE",
+       "TX_RATES",
+       "BASIC_TX_RATES",
+       "WEP_KEY_INFO",
+       "unused",
+       "unused",
+       "unused",
+       "unused",
+       "WEP_KEY_INDEX",
+       "WEP_FLAGS",
+       "ADD_MULTICAST",
+       "CLEAR_ALL_MULTICAST",
+       "BEACON_INTERVAL",
+       "ATIM_WINDOW",
+       "CLEAR_STATISTICS",
+       "undefined",
+       "undefined",
+       "undefined",
+       "undefined",
+       "TX_POWER_INDEX",
+       "undefined",
+       "undefined",
+       "undefined",
+       "undefined",
+       "undefined",
+       "undefined",
+       "BROADCAST_SCAN",
+       "CARD_DISABLE",
+       "PREFERRED_BSSID",
+       "SET_SCAN_OPTIONS",
+       "SCAN_DWELL_TIME",
+       "SWEEP_TABLE",
+       "AP_OR_STATION_TABLE",
+       "GROUP_ORDINALS",
+       "SHORT_RETRY_LIMIT",
+       "LONG_RETRY_LIMIT",
+       "unused", /* SAVE_CALIBRATION */
+       "unused", /* RESTORE_CALIBRATION */
+       "undefined",
+       "undefined",
+       "undefined",
+       "HOST_PRE_POWER_DOWN",
+       "unused", /* HOST_INTERRUPT_COALESCING */
+       "undefined",
+       "CARD_DISABLE_PHY_OFF",
+       "MSDU_TX_RATES"
+       "undefined",
+       "undefined",
+       "SET_STATION_STAT_BITS",
+       "CLEAR_STATIONS_STAT_BITS",
+       "LEAP_ROGUE_MODE",
+       "SET_SECURITY_INFORMATION",
+       "DISASSOCIATION_BSSID",
+       "SET_WPA_ASS_IE"
+};
+#endif
+
+
+/* Pre-decl until we get the code solid and then we can clean it up */
+static void ipw2100_tx_send_commands(struct ipw2100_priv *priv);
+static void ipw2100_tx_send_data(struct ipw2100_priv *priv);
+static int ipw2100_adapter_setup(struct ipw2100_priv *priv);
+
+static void ipw2100_queues_initialize(struct ipw2100_priv *priv);
+static void ipw2100_queues_free(struct ipw2100_priv *priv);
+static int ipw2100_queues_allocate(struct ipw2100_priv *priv);
+
+static int ipw2100_fw_download(struct ipw2100_priv *priv,
+                              struct ipw2100_fw *fw);
+static int ipw2100_get_firmware(struct ipw2100_priv *priv,
+                               struct ipw2100_fw *fw);
+static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
+                                size_t max);
+static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
+                                   size_t max);
+static void ipw2100_release_firmware(struct ipw2100_priv *priv,
+                                    struct ipw2100_fw *fw);
+static int ipw2100_ucode_download(struct ipw2100_priv *priv,
+                                 struct ipw2100_fw *fw);
+static void ipw2100_wx_event_work(struct ipw2100_priv *priv);
+static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev);
+static struct iw_handler_def ipw2100_wx_handler_def;
+
+
+static inline void read_register(struct net_device *dev, u32 reg, u32 *val)
+{
+       *val = readl((void __iomem *)(dev->base_addr + reg));
+       IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val);
+}
+
+static inline void write_register(struct net_device *dev, u32 reg, u32 val)
+{
+       writel(val, (void __iomem *)(dev->base_addr + reg));
+       IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val);
+}
+
+static inline void read_register_word(struct net_device *dev, u32 reg, u16 *val)
+{
+       *val = readw((void __iomem *)(dev->base_addr + reg));
+       IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val);
+}
+
+static inline void read_register_byte(struct net_device *dev, u32 reg, u8 *val)
+{
+       *val = readb((void __iomem *)(dev->base_addr + reg));
+       IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val);
+}
+
+static inline void write_register_word(struct net_device *dev, u32 reg, u16 val)
+{
+       writew(val, (void __iomem *)(dev->base_addr + reg));
+       IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val);
+}
+
+
+static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val)
+{
+       writeb(val, (void __iomem *)(dev->base_addr + reg));
+       IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val);
+}
+
+static inline void read_nic_dword(struct net_device *dev, u32 addr, u32 *val)
+{
+       write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
+                      addr & IPW_REG_INDIRECT_ADDR_MASK);
+       read_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
+}
+
+static inline void write_nic_dword(struct net_device *dev, u32 addr, u32 val)
+{
+       write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
+                      addr & IPW_REG_INDIRECT_ADDR_MASK);
+       write_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
+}
+
+static inline void read_nic_word(struct net_device *dev, u32 addr, u16 *val)
+{
+       write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
+                      addr & IPW_REG_INDIRECT_ADDR_MASK);
+       read_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
+}
+
+static inline void write_nic_word(struct net_device *dev, u32 addr, u16 val)
+{
+       write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
+                      addr & IPW_REG_INDIRECT_ADDR_MASK);
+       write_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
+}
+
+static inline void read_nic_byte(struct net_device *dev, u32 addr, u8 *val)
+{
+       write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
+                      addr & IPW_REG_INDIRECT_ADDR_MASK);
+       read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
+}
+
+static inline void write_nic_byte(struct net_device *dev, u32 addr, u8 val)
+{
+       write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
+                      addr & IPW_REG_INDIRECT_ADDR_MASK);
+       write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
+}
+
+static inline void write_nic_auto_inc_address(struct net_device *dev, u32 addr)
+{
+       write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS,
+                      addr & IPW_REG_INDIRECT_ADDR_MASK);
+}
+
+static inline void write_nic_dword_auto_inc(struct net_device *dev, u32 val)
+{
+       write_register(dev, IPW_REG_AUTOINCREMENT_DATA, val);
+}
+
+static inline void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
+                                   const u8 *buf)
+{
+       u32 aligned_addr;
+       u32 aligned_len;
+       u32 dif_len;
+       u32 i;
+
+       /* read first nibble byte by byte */
+       aligned_addr = addr & (~0x3);
+       dif_len = addr - aligned_addr;
+       if (dif_len) {
+               /* Start reading at aligned_addr + dif_len */
+               write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
+                              aligned_addr);
+               for (i = dif_len; i < 4; i++, buf++)
+                       write_register_byte(
+                               dev, IPW_REG_INDIRECT_ACCESS_DATA + i,
+                               *buf);
+
+               len -= dif_len;
+               aligned_addr += 4;
+       }
+
+       /* read DWs through autoincrement registers */
+       write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS,
+                      aligned_addr);
+       aligned_len = len & (~0x3);
+       for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
+               write_register(
+                       dev, IPW_REG_AUTOINCREMENT_DATA, *(u32 *)buf);
+
+       /* copy the last nibble */
+       dif_len = len - aligned_len;
+       write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
+       for (i = 0; i < dif_len; i++, buf++)
+               write_register_byte(
+                       dev, IPW_REG_INDIRECT_ACCESS_DATA + i, *buf);
+}
+
+static inline void read_nic_memory(struct net_device *dev, u32 addr, u32 len,
+                                  u8 *buf)
+{
+       u32 aligned_addr;
+       u32 aligned_len;
+       u32 dif_len;
+       u32 i;
+
+       /* read first nibble byte by byte */
+       aligned_addr = addr & (~0x3);
+       dif_len = addr - aligned_addr;
+       if (dif_len) {
+               /* Start reading at aligned_addr + dif_len */
+               write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
+                              aligned_addr);
+               for (i = dif_len; i < 4; i++, buf++)
+                       read_register_byte(
+                               dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf);
+
+               len -= dif_len;
+               aligned_addr += 4;
+       }
+
+       /* read DWs through autoincrement registers */
+       write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS,
+                      aligned_addr);
+       aligned_len = len & (~0x3);
+       for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
+               read_register(dev, IPW_REG_AUTOINCREMENT_DATA,
+                             (u32 *)buf);
+
+       /* copy the last nibble */
+       dif_len = len - aligned_len;
+       write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
+                      aligned_addr);
+       for (i = 0; i < dif_len; i++, buf++)
+               read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA +
+                                  i, buf);
+}
+
+static inline int ipw2100_hw_is_adapter_in_system(struct net_device *dev)
+{
+       return (dev->base_addr &&
+               (readl((void __iomem *)(dev->base_addr + IPW_REG_DOA_DEBUG_AREA_START))
+                == IPW_DATA_DOA_DEBUG_VALUE));
+}
+
+static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord,
+                              void *val, u32 *len)
+{
+       struct ipw2100_ordinals *ordinals = &priv->ordinals;
+       u32 addr;
+       u32 field_info;
+       u16 field_len;
+       u16 field_count;
+       u32 total_length;
+
+       if (ordinals->table1_addr == 0) {
+               printk(KERN_WARNING DRV_NAME ": attempt to use fw ordinals "
+                      "before they have been loaded.\n");
+               return -EINVAL;
+       }
+
+       if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {
+               if (*len < IPW_ORD_TAB_1_ENTRY_SIZE) {
+                       *len = IPW_ORD_TAB_1_ENTRY_SIZE;
+
+                       printk(KERN_WARNING DRV_NAME
+                              ": ordinal buffer length too small, need %zd\n",
+                              IPW_ORD_TAB_1_ENTRY_SIZE);
+
+                       return -EINVAL;
+               }
+
+               read_nic_dword(priv->net_dev, ordinals->table1_addr + (ord << 2),
+                              &addr);
+               read_nic_dword(priv->net_dev, addr, val);
+
+               *len = IPW_ORD_TAB_1_ENTRY_SIZE;
+
+               return 0;
+       }
+
+       if (IS_ORDINAL_TABLE_TWO(ordinals, ord)) {
+
+               ord -= IPW_START_ORD_TAB_2;
+
+               /* get the address of statistic */
+               read_nic_dword(priv->net_dev, ordinals->table2_addr + (ord << 3),
+                              &addr);
+
+               /* get the second DW of statistics ;
+                * two 16-bit words - first is length, second is count */
+               read_nic_dword(priv->net_dev,
+                              ordinals->table2_addr + (ord << 3) + sizeof(u32),
+                              &field_info);
+
+               /* get each entry length */
+               field_len = *((u16 *)&field_info);
+
+               /* get number of entries */
+               field_count = *(((u16 *)&field_info) + 1);
+
+               /* abort if no enought memory */
+               total_length = field_len * field_count;
+               if (total_length > *len) {
+                       *len = total_length;
+                       return -EINVAL;
+               }
+
+               *len = total_length;
+               if (!total_length)
+                       return 0;
+
+               /* read the ordinal data from the SRAM */
+               read_nic_memory(priv->net_dev, addr, total_length, val);
+
+               return 0;
+       }
+
+       printk(KERN_WARNING DRV_NAME ": ordinal %d neither in table 1 nor "
+              "in table 2\n", ord);
+
+       return -EINVAL;
+}
+
+static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 *val,
+                              u32 *len)
+{
+       struct ipw2100_ordinals *ordinals = &priv->ordinals;
+       u32 addr;
+
+       if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {
+               if (*len != IPW_ORD_TAB_1_ENTRY_SIZE) {
+                       *len = IPW_ORD_TAB_1_ENTRY_SIZE;
+                       IPW_DEBUG_INFO("wrong size\n");
+                       return -EINVAL;
+               }
+
+               read_nic_dword(priv->net_dev, ordinals->table1_addr + (ord << 2),
+                              &addr);
+
+               write_nic_dword(priv->net_dev, addr, *val);
+
+               *len = IPW_ORD_TAB_1_ENTRY_SIZE;
+
+               return 0;
+       }
+
+       IPW_DEBUG_INFO("wrong table\n");
+       if (IS_ORDINAL_TABLE_TWO(ordinals, ord))
+               return -EINVAL;
+
+       return -EINVAL;
+}
+
+static char *snprint_line(char *buf, size_t count,
+                         const u8 *data, u32 len, u32 ofs)
+{
+       int out, i, j, l;
+       char c;
+
+       out = snprintf(buf, count, "%08X", ofs);
+
+       for (l = 0, i = 0; i < 2; i++) {
+               out += snprintf(buf + out, count - out, " ");
+               for (j = 0; j < 8 && l < len; j++, l++)
+                       out += snprintf(buf + out, count - out, "%02X ",
+                                       data[(i * 8 + j)]);
+               for (; j < 8; j++)
+                       out += snprintf(buf + out, count - out, "   ");
+       }
+
+       out += snprintf(buf + out, count - out, " ");
+       for (l = 0, i = 0; i < 2; i++) {
+               out += snprintf(buf + out, count - out, " ");
+               for (j = 0; j < 8 && l < len; j++, l++) {
+                       c = data[(i * 8 + j)];
+                       if (!isascii(c) || !isprint(c))
+                               c = '.';
+
+                       out += snprintf(buf + out, count - out, "%c", c);
+               }
+
+               for (; j < 8; j++)
+                       out += snprintf(buf + out, count - out, " ");
+       }
+
+       return buf;
+}
+
+static void printk_buf(int level, const u8 *data, u32 len)
+{
+       char line[81];
+       u32 ofs = 0;
+       if (!(ipw2100_debug_level & level))
+               return;
+
+       while (len) {
+               printk(KERN_DEBUG "%s\n",
+                      snprint_line(line, sizeof(line), &data[ofs],
+                                   min(len, 16U), ofs));
+               ofs += 16;
+               len -= min(len, 16U);
+       }
+}
+
+
+
+#define MAX_RESET_BACKOFF 10
+
+static inline void schedule_reset(struct ipw2100_priv *priv)
+{
+       unsigned long now = get_seconds();
+
+       /* If we haven't received a reset request within the backoff period,
+        * then we can reset the backoff interval so this reset occurs
+        * immediately */
+       if (priv->reset_backoff &&
+           (now - priv->last_reset > priv->reset_backoff))
+               priv->reset_backoff = 0;
+
+       priv->last_reset = get_seconds();
+
+       if (!(priv->status & STATUS_RESET_PENDING)) {
+               IPW_DEBUG_INFO("%s: Scheduling firmware restart (%ds).\n",
+                              priv->net_dev->name, priv->reset_backoff);
+               netif_carrier_off(priv->net_dev);
+               netif_stop_queue(priv->net_dev);
+               priv->status |= STATUS_RESET_PENDING;
+               if (priv->reset_backoff)
+                       queue_delayed_work(priv->workqueue, &priv->reset_work,
+                                          priv->reset_backoff * HZ);
+               else
+                       queue_work(priv->workqueue, &priv->reset_work);
+
+               if (priv->reset_backoff < MAX_RESET_BACKOFF)
+                       priv->reset_backoff++;
+
+               wake_up_interruptible(&priv->wait_command_queue);
+       } else
+               IPW_DEBUG_INFO("%s: Firmware restart already in progress.\n",
+                              priv->net_dev->name);
+
+}
+
+#define HOST_COMPLETE_TIMEOUT (2 * HZ)
+static int ipw2100_hw_send_command(struct ipw2100_priv *priv,
+                                  struct host_command * cmd)
+{
+       struct list_head *element;
+       struct ipw2100_tx_packet *packet;
+       unsigned long flags;
+       int err = 0;
+
+       IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n",
+                    command_types[cmd->host_command], cmd->host_command,
+                    cmd->host_command_length);
+       printk_buf(IPW_DL_HC, (u8*)cmd->host_command_parameters,
+                  cmd->host_command_length);
+
+       spin_lock_irqsave(&priv->low_lock, flags);
+
+       if (priv->fatal_error) {
+               IPW_DEBUG_INFO("Attempt to send command while hardware in fatal error condition.\n");
+               err = -EIO;
+               goto fail_unlock;
+       }
+
+       if (!(priv->status & STATUS_RUNNING)) {
+               IPW_DEBUG_INFO("Attempt to send command while hardware is not running.\n");
+               err = -EIO;
+               goto fail_unlock;
+       }
+
+       if (priv->status & STATUS_CMD_ACTIVE) {
+               IPW_DEBUG_INFO("Attempt to send command while another command is pending.\n");
+               err = -EBUSY;
+               goto fail_unlock;
+       }
+
+       if (list_empty(&priv->msg_free_list)) {
+               IPW_DEBUG_INFO("no available msg buffers\n");
+               goto fail_unlock;
+       }
+
+       priv->status |= STATUS_CMD_ACTIVE;
+       priv->messages_sent++;
+
+       element = priv->msg_free_list.next;
+
+       packet = list_entry(element, struct ipw2100_tx_packet, list);
+       packet->jiffy_start = jiffies;
+
+       /* initialize the firmware command packet */
+       packet->info.c_struct.cmd->host_command_reg = cmd->host_command;
+       packet->info.c_struct.cmd->host_command_reg1 = cmd->host_command1;
+       packet->info.c_struct.cmd->host_command_len_reg = cmd->host_command_length;
+       packet->info.c_struct.cmd->sequence = cmd->host_command_sequence;
+
+       memcpy(packet->info.c_struct.cmd->host_command_params_reg,
+              cmd->host_command_parameters,
+              sizeof(packet->info.c_struct.cmd->host_command_params_reg));
+
+       list_del(element);
+       DEC_STAT(&priv->msg_free_stat);
+
+       list_add_tail(element, &priv->msg_pend_list);
+       INC_STAT(&priv->msg_pend_stat);
+
+       ipw2100_tx_send_commands(priv);
+       ipw2100_tx_send_data(priv);
+
+       spin_unlock_irqrestore(&priv->low_lock, flags);
+
+       /*
+        * We must wait for this command to complete before another
+        * command can be sent...  but if we wait more than 3 seconds
+        * then there is a problem.
+        */
+
+       err = wait_event_interruptible_timeout(
+               priv->wait_command_queue, !(priv->status & STATUS_CMD_ACTIVE),
+               HOST_COMPLETE_TIMEOUT);
+
+       if (err == 0) {
+               IPW_DEBUG_INFO("Command completion failed out after %dms.\n",
+                              HOST_COMPLETE_TIMEOUT / (HZ / 100));
+               priv->fatal_error = IPW2100_ERR_MSG_TIMEOUT;
+               priv->status &= ~STATUS_CMD_ACTIVE;
+               schedule_reset(priv);
+               return -EIO;
+       }
+
+       if (priv->fatal_error) {
+               printk(KERN_WARNING DRV_NAME ": %s: firmware fatal error\n",
+                      priv->net_dev->name);
+               return -EIO;
+       }
+
+       /* !!!!! HACK TEST !!!!!
+        * When lots of debug trace statements are enabled, the driver
+        * doesn't seem to have as many firmware restart cycles...
+        *
+        * As a test, we're sticking in a 1/100s delay here */
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout(HZ / 100);
+
+       return 0;
+
+ fail_unlock:
+       spin_unlock_irqrestore(&priv->low_lock, flags);
+
+       return err;
+}
+
+
+/*
+ * Verify the values and data access of the hardware
+ * No locks needed or used.  No functions called.
+ */
+static int ipw2100_verify(struct ipw2100_priv *priv)
+{
+       u32 data1, data2;
+       u32 address;
+
+       u32 val1 = 0x76543210;
+       u32 val2 = 0xFEDCBA98;
+
+       /* Domain 0 check - all values should be DOA_DEBUG */
+       for (address = IPW_REG_DOA_DEBUG_AREA_START;
+            address < IPW_REG_DOA_DEBUG_AREA_END;
+            address += sizeof(u32)) {
+               read_register(priv->net_dev, address, &data1);
+               if (data1 != IPW_DATA_DOA_DEBUG_VALUE)
+                       return -EIO;
+       }
+
+       /* Domain 1 check - use arbitrary read/write compare  */
+       for (address = 0; address < 5; address++) {
+               /* The memory area is not used now */
+               write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,
+                              val1);
+               write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,
+                              val2);
+               read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,
+                             &data1);
+               read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,
+                             &data2);
+               if (val1 == data1 && val2 == data2)
+                       return 0;
+       }
+
+       return -EIO;
+}
+
+/*
+ *
+ * Loop until the CARD_DISABLED bit is the same value as the
+ * supplied parameter
+ *
+ * TODO: See if it would be more efficient to do a wait/wake
+ *       cycle and have the completion event trigger the wakeup
+ *
+ */
+#define IPW_CARD_DISABLE_COMPLETE_WAIT             100 // 100 milli
+static int ipw2100_wait_for_card_state(struct ipw2100_priv *priv, int state)
+{
+       int i;
+       u32 card_state;
+       u32 len = sizeof(card_state);
+       int err;
+
+       for (i = 0; i <= IPW_CARD_DISABLE_COMPLETE_WAIT * 1000; i += 50) {
+               err = ipw2100_get_ordinal(priv, IPW_ORD_CARD_DISABLED,
+                                         &card_state, &len);
+               if (err) {
+                       IPW_DEBUG_INFO("Query of CARD_DISABLED ordinal "
+                                      "failed.\n");
+                       return 0;
+               }
+
+               /* We'll break out if either the HW state says it is
+                * in the state we want, or if HOST_COMPLETE command
+                * finishes */
+               if ((card_state == state) ||
+                   ((priv->status & STATUS_ENABLED) ?
+                    IPW_HW_STATE_ENABLED : IPW_HW_STATE_DISABLED) == state) {
+                       if (state == IPW_HW_STATE_ENABLED)
+                               priv->status |= STATUS_ENABLED;
+                       else
+                               priv->status &= ~STATUS_ENABLED;
+
+                       return 0;
+               }
+
+               udelay(50);
+       }
+
+       IPW_DEBUG_INFO("ipw2100_wait_for_card_state to %s state timed out\n",
+                      state ? "DISABLED" : "ENABLED");
+       return -EIO;
+}
+
+
+/*********************************************************************
+    Procedure   :   sw_reset_and_clock
+    Purpose     :   Asserts s/w reset, asserts clock initialization
+                    and waits for clock stabilization
+ ********************************************************************/
+static int sw_reset_and_clock(struct ipw2100_priv *priv)
+{
+       int i;
+       u32 r;
+
+       // assert s/w reset
+       write_register(priv->net_dev, IPW_REG_RESET_REG,
+                      IPW_AUX_HOST_RESET_REG_SW_RESET);
+
+       // wait for clock stabilization
+       for (i = 0; i < 1000; i++) {
+               udelay(IPW_WAIT_RESET_ARC_COMPLETE_DELAY);
+
+               // check clock ready bit
+               read_register(priv->net_dev, IPW_REG_RESET_REG, &r);
+               if (r & IPW_AUX_HOST_RESET_REG_PRINCETON_RESET)
+                       break;
+       }
+
+       if (i == 1000)
+               return -EIO;    // TODO: better error value
+
+       /* set "initialization complete" bit to move adapter to
+        * D0 state */
+       write_register(priv->net_dev, IPW_REG_GP_CNTRL,
+                      IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE);
+
+       /* wait for clock stabilization */
+       for (i = 0; i < 10000; i++) {
+               udelay(IPW_WAIT_CLOCK_STABILIZATION_DELAY * 4);
+
+               /* check clock ready bit */
+               read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);
+               if (r & IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY)
+                       break;
+       }
+
+       if (i == 10000)
+               return -EIO;    /* TODO: better error value */
+
+       /* set D0 standby bit */
+       read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);
+       write_register(priv->net_dev, IPW_REG_GP_CNTRL,
+                      r | IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);
+
+       return 0;
+}
+
+/*********************************************************************
+    Procedure   :   ipw2100_download_firmware
+    Purpose     :   Initiaze adapter after power on.
+                    The sequence is:
+                    1. assert s/w reset first!
+                    2. awake clocks & wait for clock stabilization
+                    3. hold ARC (don't ask me why...)
+                    4. load Dino ucode and reset/clock init again
+                    5. zero-out shared mem
+                    6. download f/w
+ *******************************************************************/
+static int ipw2100_download_firmware(struct ipw2100_priv *priv)
+{
+       u32 address;
+       int err;
+
+#ifndef CONFIG_PM
+       /* Fetch the firmware and microcode */
+       struct ipw2100_fw ipw2100_firmware;
+#endif
+
+       if (priv->fatal_error) {
+               IPW_DEBUG_ERROR("%s: ipw2100_download_firmware called after "
+                      "fatal error %d.  Interface must be brought down.\n",
+                      priv->net_dev->name, priv->fatal_error);
+               return -EINVAL;
+       }
+
+#ifdef CONFIG_PM
+       if (!ipw2100_firmware.version) {
+               err = ipw2100_get_firmware(priv, &ipw2100_firmware);
+               if (err) {
+                       IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
+                              priv->net_dev->name, err);
+                       priv->fatal_error = IPW2100_ERR_FW_LOAD;
+                       goto fail;
+               }
+       }
+#else
+       err = ipw2100_get_firmware(priv, &ipw2100_firmware);
+       if (err) {
+               IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
+                      priv->net_dev->name, err);
+               priv->fatal_error = IPW2100_ERR_FW_LOAD;
+               goto fail;
+       }
+#endif
+       priv->firmware_version = ipw2100_firmware.version;
+
+       /* s/w reset and clock stabilization */
+       err = sw_reset_and_clock(priv);
+       if (err) {
+               IPW_DEBUG_ERROR("%s: sw_reset_and_clock failed: %d\n",
+                      priv->net_dev->name, err);
+               goto fail;
+       }
+
+       err = ipw2100_verify(priv);
+       if (err) {
+               IPW_DEBUG_ERROR("%s: ipw2100_verify failed: %d\n",
+                      priv->net_dev->name, err);
+               goto fail;
+       }
+
+       /* Hold ARC */
+       write_nic_dword(priv->net_dev,
+                       IPW_INTERNAL_REGISTER_HALT_AND_RESET,
+                       0x80000000);
+
+       /* allow ARC to run */
+       write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
+
+       /* load microcode */
+       err = ipw2100_ucode_download(priv, &ipw2100_firmware);
+       if (err) {
+               printk(KERN_ERR DRV_NAME ": %s: Error loading microcode: %d\n",
+                      priv->net_dev->name, err);
+               goto fail;
+       }
+
+       /* release ARC */
+       write_nic_dword(priv->net_dev,
+                       IPW_INTERNAL_REGISTER_HALT_AND_RESET,
+                       0x00000000);
+
+       /* s/w reset and clock stabilization (again!!!) */
+       err = sw_reset_and_clock(priv);
+       if (err) {
+               printk(KERN_ERR DRV_NAME ": %s: sw_reset_and_clock failed: %d\n",
+                      priv->net_dev->name, err);
+               goto fail;
+       }
+
+       /* load f/w */
+       err = ipw2100_fw_download(priv, &ipw2100_firmware);
+       if (err) {
+               IPW_DEBUG_ERROR("%s: Error loading firmware: %d\n",
+                      priv->net_dev->name, err);
+               goto fail;
+       }
+
+#ifndef CONFIG_PM
+       /*
+        * When the .resume method of the driver is called, the other
+        * part of the system, i.e. the ide driver could still stay in
+        * the suspend stage. This prevents us from loading the firmware
+        * from the disk.  --YZ
+        */
+
+       /* free any storage allocated for firmware image */
+       ipw2100_release_firmware(priv, &ipw2100_firmware);
+#endif
+
+       /* zero out Domain 1 area indirectly (Si requirement) */
+       for (address = IPW_HOST_FW_SHARED_AREA0;
+            address < IPW_HOST_FW_SHARED_AREA0_END; address += 4)
+               write_nic_dword(priv->net_dev, address, 0);
+       for (address = IPW_HOST_FW_SHARED_AREA1;
+            address < IPW_HOST_FW_SHARED_AREA1_END; address += 4)
+               write_nic_dword(priv->net_dev, address, 0);
+       for (address = IPW_HOST_FW_SHARED_AREA2;
+            address < IPW_HOST_FW_SHARED_AREA2_END; address += 4)
+               write_nic_dword(priv->net_dev, address, 0);
+       for (address = IPW_HOST_FW_SHARED_AREA3;
+            address < IPW_HOST_FW_SHARED_AREA3_END; address += 4)
+               write_nic_dword(priv->net_dev, address, 0);
+       for (address = IPW_HOST_FW_INTERRUPT_AREA;
+            address < IPW_HOST_FW_INTERRUPT_AREA_END; address += 4)
+               write_nic_dword(priv->net_dev, address, 0);
+
+       return 0;
+
+ fail:
+       ipw2100_release_firmware(priv, &ipw2100_firmware);
+       return err;
+}
+
+static inline void ipw2100_enable_interrupts(struct ipw2100_priv *priv)
+{
+       if (priv->status & STATUS_INT_ENABLED)
+               return;
+       priv->status |= STATUS_INT_ENABLED;
+       write_register(priv->net_dev, IPW_REG_INTA_MASK, IPW_INTERRUPT_MASK);
+}
+
+static inline void ipw2100_disable_interrupts(struct ipw2100_priv *priv)
+{
+       if (!(priv->status & STATUS_INT_ENABLED))
+               return;
+       priv->status &= ~STATUS_INT_ENABLED;
+       write_register(priv->net_dev, IPW_REG_INTA_MASK, 0x0);
+}
+
+
+static void ipw2100_initialize_ordinals(struct ipw2100_priv *priv)
+{
+       struct ipw2100_ordinals *ord = &priv->ordinals;
+
+       IPW_DEBUG_INFO("enter\n");
+
+       read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1,
+                     &ord->table1_addr);
+
+       read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2,
+                     &ord->table2_addr);
+
+       read_nic_dword(priv->net_dev, ord->table1_addr, &ord->table1_size);
+       read_nic_dword(priv->net_dev, ord->table2_addr, &ord->table2_size);
+
+       ord->table2_size &= 0x0000FFFF;
+
+       IPW_DEBUG_INFO("table 1 size: %d\n", ord->table1_size);
+       IPW_DEBUG_INFO("table 2 size: %d\n", ord->table2_size);
+       IPW_DEBUG_INFO("exit\n");
+}
+
+static inline void ipw2100_hw_set_gpio(struct ipw2100_priv *priv)
+{
+       u32 reg = 0;
+       /*
+        * Set GPIO 3 writable by FW; GPIO 1 writable
+        * by driver and enable clock
+        */
+       reg = (IPW_BIT_GPIO_GPIO3_MASK | IPW_BIT_GPIO_GPIO1_ENABLE |
+              IPW_BIT_GPIO_LED_OFF);
+       write_register(priv->net_dev, IPW_REG_GPIO, reg);
+}
+
+static inline int rf_kill_active(struct ipw2100_priv *priv)
+{
+#define MAX_RF_KILL_CHECKS 5
+#define RF_KILL_CHECK_DELAY 40
+
+       unsigned short value = 0;
+       u32 reg = 0;
+       int i;
+
+       if (!(priv->hw_features & HW_FEATURE_RFKILL)) {
+               priv->status &= ~STATUS_RF_KILL_HW;
+               return 0;
+       }
+
+       for (i = 0; i < MAX_RF_KILL_CHECKS; i++) {
+               udelay(RF_KILL_CHECK_DELAY);
+               read_register(priv->net_dev, IPW_REG_GPIO, &reg);
+               value = (value << 1) | ((reg & IPW_BIT_GPIO_RF_KILL) ? 0 : 1);
+       }
+
+       if (value == 0)
+               priv->status |= STATUS_RF_KILL_HW;
+       else
+               priv->status &= ~STATUS_RF_KILL_HW;
+
+       return (value == 0);
+}
+
+static int ipw2100_get_hw_features(struct ipw2100_priv *priv)
+{
+       u32 addr, len;
+       u32 val;
+
+       /*
+        * EEPROM_SRAM_DB_START_ADDRESS using ordinal in ordinal table 1
+        */
+       len = sizeof(addr);
+       if (ipw2100_get_ordinal(
+                   priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS,
+                   &addr, &len)) {
+               IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
+                      __LINE__);
+               return -EIO;
+       }
+
+       IPW_DEBUG_INFO("EEPROM address: %08X\n", addr);
+
+       /*
+        * EEPROM version is the byte at offset 0xfd in firmware
+        * We read 4 bytes, then shift out the byte we actually want */
+       read_nic_dword(priv->net_dev, addr + 0xFC, &val);
+       priv->eeprom_version = (val >> 24) & 0xFF;
+       IPW_DEBUG_INFO("EEPROM version: %d\n", priv->eeprom_version);
+
+        /*
+        *  HW RF Kill enable is bit 0 in byte at offset 0x21 in firmware
+        *
+        *  notice that the EEPROM bit is reverse polarity, i.e.
+        *     bit = 0  signifies HW RF kill switch is supported
+        *     bit = 1  signifies HW RF kill switch is NOT supported
+        */
+       read_nic_dword(priv->net_dev, addr + 0x20, &val);
+       if (!((val >> 24) & 0x01))
+               priv->hw_features |= HW_FEATURE_RFKILL;
+
+       IPW_DEBUG_INFO("HW RF Kill: %ssupported.\n",
+                          (priv->hw_features & HW_FEATURE_RFKILL) ?
+                          "" : "not ");
+
+       return 0;
+}
+
+/*
+ * Start firmware execution after power on and intialization
+ * The sequence is:
+ *  1. Release ARC
+ *  2. Wait for f/w initialization completes;
+ */
+static int ipw2100_start_adapter(struct ipw2100_priv *priv)
+{
+       int i;
+       u32 inta, inta_mask, gpio;
+
+       IPW_DEBUG_INFO("enter\n");
+
+       if (priv->status & STATUS_RUNNING)
+               return 0;
+
+       /*
+        * Initialize the hw - drive adapter to DO state by setting
+        * init_done bit. Wait for clk_ready bit and Download
+        * fw & dino ucode
+        */
+       if (ipw2100_download_firmware(priv)) {
+               printk(KERN_ERR DRV_NAME ": %s: Failed to power on the adapter.\n",
+                      priv->net_dev->name);
+               return -EIO;
+       }
+
+       /* Clear the Tx, Rx and Msg queues and the r/w indexes
+        * in the firmware RBD and TBD ring queue */
+       ipw2100_queues_initialize(priv);
+
+       ipw2100_hw_set_gpio(priv);
+
+       /* TODO -- Look at disabling interrupts here to make sure none
+        * get fired during FW initialization */
+
+       /* Release ARC - clear reset bit */
+       write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
+
+       /* wait for f/w intialization complete */
+       IPW_DEBUG_FW("Waiting for f/w initialization to complete...\n");
+       i = 5000;
+       do {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(40 * HZ / 1000);
+               /* Todo... wait for sync command ... */
+
+               read_register(priv->net_dev, IPW_REG_INTA, &inta);
+
+               /* check "init done" bit */
+               if (inta & IPW2100_INTA_FW_INIT_DONE) {
+                       /* reset "init done" bit */
+                       write_register(priv->net_dev, IPW_REG_INTA,
+                                      IPW2100_INTA_FW_INIT_DONE);
+                       break;
+               }
+
+               /* check error conditions : we check these after the firmware
+                * check so that if there is an error, the interrupt handler
+                * will see it and the adapter will be reset */
+               if (inta &
+                   (IPW2100_INTA_FATAL_ERROR | IPW2100_INTA_PARITY_ERROR)) {
+                       /* clear error conditions */
+                       write_register(priv->net_dev, IPW_REG_INTA,
+                                      IPW2100_INTA_FATAL_ERROR |
+                                      IPW2100_INTA_PARITY_ERROR);
+               }
+       } while (i--);
+
+       /* Clear out any pending INTAs since we aren't supposed to have
+        * interrupts enabled at this point... */
+       read_register(priv->net_dev, IPW_REG_INTA, &inta);
+       read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
+       inta &= IPW_INTERRUPT_MASK;
+       /* Clear out any pending interrupts */
+       if (inta & inta_mask)
+               write_register(priv->net_dev, IPW_REG_INTA, inta);
+
+       IPW_DEBUG_FW("f/w initialization complete: %s\n",
+                    i ? "SUCCESS" : "FAILED");
+
+       if (!i) {
+               printk(KERN_WARNING DRV_NAME ": %s: Firmware did not initialize.\n",
+                      priv->net_dev->name);
+               return -EIO;
+       }
+
+       /* allow firmware to write to GPIO1 & GPIO3 */
+       read_register(priv->net_dev, IPW_REG_GPIO, &gpio);
+
+       gpio |= (IPW_BIT_GPIO_GPIO1_MASK | IPW_BIT_GPIO_GPIO3_MASK);
+
+       write_register(priv->net_dev, IPW_REG_GPIO, gpio);
+
+       /* Ready to receive commands */
+       priv->status |= STATUS_RUNNING;
+
+       /* The adapter has been reset; we are not associated */
+       priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
+
+       IPW_DEBUG_INFO("exit\n");
+
+       return 0;
+}
+
+static inline void ipw2100_reset_fatalerror(struct ipw2100_priv *priv)
+{
+       if (!priv->fatal_error)
+               return;
+
+       priv->fatal_errors[priv->fatal_index++] = priv->fatal_error;
+       priv->fatal_index %= IPW2100_ERROR_QUEUE;
+       priv->fatal_error = 0;
+}
+
+
+/* NOTE: Our interrupt is disabled when this method is called */
+static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv)
+{
+       u32 reg;
+       int i;
+
+       IPW_DEBUG_INFO("Power cycling the hardware.\n");
+
+       ipw2100_hw_set_gpio(priv);
+
+       /* Step 1. Stop Master Assert */
+       write_register(priv->net_dev, IPW_REG_RESET_REG,
+                      IPW_AUX_HOST_RESET_REG_STOP_MASTER);
+
+       /* Step 2. Wait for stop Master Assert
+        *         (not more then 50us, otherwise ret error */
+       i = 5;
+       do {
+               udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
+               read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
+
+               if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
+                       break;
+       }  while(i--);
+
+       priv->status &= ~STATUS_RESET_PENDING;
+
+       if (!i) {
+               IPW_DEBUG_INFO("exit - waited too long for master assert stop\n");
+               return -EIO;
+       }
+
+       write_register(priv->net_dev, IPW_REG_RESET_REG,
+                      IPW_AUX_HOST_RESET_REG_SW_RESET);
+
+
+       /* Reset any fatal_error conditions */
+       ipw2100_reset_fatalerror(priv);
+
+       /* At this point, the adapter is now stopped and disabled */
+       priv->status &= ~(STATUS_RUNNING | STATUS_ASSOCIATING |
+                         STATUS_ASSOCIATED | STATUS_ENABLED);
+
+       return 0;
+}
+
+/*
+ * Send the CARD_DISABLE_PHY_OFF comamnd to the card to disable it
+ *
+ * After disabling, if the card was associated, a STATUS_ASSN_LOST will be sent.
+ *
+ * STATUS_CARD_DISABLE_NOTIFICATION will be sent regardless of
+ * if STATUS_ASSN_LOST is sent.
+ */
+static int ipw2100_hw_phy_off(struct ipw2100_priv *priv)
+{
+
+#define HW_PHY_OFF_LOOP_DELAY (HZ / 5000)
+
+       struct host_command cmd = {
+               .host_command = CARD_DISABLE_PHY_OFF,
+               .host_command_sequence = 0,
+               .host_command_length = 0,
+       };
+       int err, i;
+       u32 val1, val2;
+
+       IPW_DEBUG_HC("CARD_DISABLE_PHY_OFF\n");
+
+       /* Turn off the radio */
+       err = ipw2100_hw_send_command(priv, &cmd);
+       if (err)
+               return err;
+
+       for (i = 0; i < 2500; i++) {
+               read_nic_dword(priv->net_dev, IPW2100_CONTROL_REG, &val1);
+               read_nic_dword(priv->net_dev, IPW2100_COMMAND, &val2);
+
+               if ((val1 & IPW2100_CONTROL_PHY_OFF) &&
+                   (val2 & IPW2100_COMMAND_PHY_OFF))
+                       return 0;
+
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(HW_PHY_OFF_LOOP_DELAY);
+       }
+
+       return -EIO;
+}
+
+
+static int ipw2100_enable_adapter(struct ipw2100_priv *priv)
+{
+       struct host_command cmd = {
+               .host_command = HOST_COMPLETE,
+               .host_command_sequence = 0,
+               .host_command_length = 0
+       };
+       int err = 0;
+
+       IPW_DEBUG_HC("HOST_COMPLETE\n");
+
+       if (priv->status & STATUS_ENABLED)
+               return 0;
+
+       down(&priv->adapter_sem);
+
+       if (rf_kill_active(priv)) {
+               IPW_DEBUG_HC("Command aborted due to RF kill active.\n");
+               goto fail_up;
+       }
+
+       err = ipw2100_hw_send_command(priv, &cmd);
+       if (err) {
+               IPW_DEBUG_INFO("Failed to send HOST_COMPLETE command\n");
+               goto fail_up;
+       }
+
+       err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_ENABLED);
+       if (err) {
+               IPW_DEBUG_INFO(
+                      "%s: card not responding to init command.\n",
+                      priv->net_dev->name);
+               goto fail_up;
+       }
+
+       if (priv->stop_hang_check) {
+               priv->stop_hang_check = 0;
+               queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2);
+       }
+
+fail_up:
+       up(&priv->adapter_sem);
+       return err;
+}
+
+static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv)
+{
+#define HW_POWER_DOWN_DELAY (HZ / 10)
+
+       struct host_command cmd = {
+               .host_command = HOST_PRE_POWER_DOWN,
+               .host_command_sequence = 0,
+               .host_command_length = 0,
+       };
+       int err, i;
+       u32 reg;
+
+       if (!(priv->status & STATUS_RUNNING))
+               return 0;
+
+       priv->status |= STATUS_STOPPING;
+
+       /* We can only shut down the card if the firmware is operational.  So,
+        * if we haven't reset since a fatal_error, then we can not send the
+        * shutdown commands. */
+       if (!priv->fatal_error) {
+               /* First, make sure the adapter is enabled so that the PHY_OFF
+                * command can shut it down */
+               ipw2100_enable_adapter(priv);
+
+               err = ipw2100_hw_phy_off(priv);
+               if (err)
+                       printk(KERN_WARNING DRV_NAME ": Error disabling radio %d\n", err);
+
+               /*
+                * If in D0-standby mode going directly to D3 may cause a
+                * PCI bus violation.  Therefore we must change out of the D0
+                * state.
+                *
+                * Sending the PREPARE_FOR_POWER_DOWN will restrict the
+                * hardware from going into standby mode and will transition
+                * out of D0-standy if it is already in that state.
+                *
+                * STATUS_PREPARE_POWER_DOWN_COMPLETE will be sent by the
+                * driver upon completion.  Once received, the driver can
+                * proceed to the D3 state.
+                *
+                * Prepare for power down command to fw.  This command would
+                * take HW out of D0-standby and prepare it for D3 state.
+                *
+                * Currently FW does not support event notification for this
+                * event. Therefore, skip waiting for it.  Just wait a fixed
+                * 100ms
+                */
+               IPW_DEBUG_HC("HOST_PRE_POWER_DOWN\n");
+
+               err = ipw2100_hw_send_command(priv, &cmd);
+               if (err)
+                       printk(KERN_WARNING DRV_NAME ": "
+                              "%s: Power down command failed: Error %d\n",
+                              priv->net_dev->name, err);
+               else {
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule_timeout(HW_POWER_DOWN_DELAY);
+               }
+       }
+
+       priv->status &= ~STATUS_ENABLED;
+
+       /*
+        * Set GPIO 3 writable by FW; GPIO 1 writable
+        * by driver and enable clock
+        */
+       ipw2100_hw_set_gpio(priv);
+
+       /*
+        * Power down adapter.  Sequence:
+        * 1. Stop master assert (RESET_REG[9]=1)
+        * 2. Wait for stop master (RESET_REG[8]==1)
+        * 3. S/w reset assert (RESET_REG[7] = 1)
+        */
+
+       /* Stop master assert */
+       write_register(priv->net_dev, IPW_REG_RESET_REG,
+                      IPW_AUX_HOST_RESET_REG_STOP_MASTER);
+
+       /* wait stop master not more than 50 usec.
+        * Otherwise return error. */
+       for (i = 5; i > 0; i--) {
+               udelay(10);
+
+               /* Check master stop bit */
+               read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
+
+               if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
+                       break;
+       }
+
+       if (i == 0)
+               printk(KERN_WARNING DRV_NAME
+                      ": %s: Could now power down adapter.\n",
+                      priv->net_dev->name);
+
+       /* assert s/w reset */
+       write_register(priv->net_dev, IPW_REG_RESET_REG,
+                      IPW_AUX_HOST_RESET_REG_SW_RESET);
+
+       priv->status &= ~(STATUS_RUNNING | STATUS_STOPPING);
+
+       return 0;
+}
+
+
+static int ipw2100_disable_adapter(struct ipw2100_priv *priv)
+{
+       struct host_command cmd = {
+               .host_command = CARD_DISABLE,
+               .host_command_sequence = 0,
+               .host_command_length = 0
+       };
+       int err = 0;
+
+       IPW_DEBUG_HC("CARD_DISABLE\n");
+
+       if (!(priv->status & STATUS_ENABLED))
+               return 0;
+
+       /* Make sure we clear the associated state */
+       priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
+
+       if (!priv->stop_hang_check) {
+               priv->stop_hang_check = 1;
+               cancel_delayed_work(&priv->hang_check);
+       }
+
+       down(&priv->adapter_sem);
+
+       err = ipw2100_hw_send_command(priv, &cmd);
+       if (err) {
+               printk(KERN_WARNING DRV_NAME ": exit - failed to send CARD_DISABLE command\n");
+               goto fail_up;
+       }
+
+       err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_DISABLED);
+       if (err) {
+               printk(KERN_WARNING DRV_NAME ": exit - card failed to change to DISABLED\n");
+               goto fail_up;
+       }
+
+       IPW_DEBUG_INFO("TODO: implement scan state machine\n");
+
+fail_up:
+       up(&priv->adapter_sem);
+       return err;
+}
+
+static int ipw2100_set_scan_options(struct ipw2100_priv *priv)
+{
+       struct host_command cmd = {
+               .host_command = SET_SCAN_OPTIONS,
+               .host_command_sequence = 0,
+               .host_command_length = 8
+       };
+       int err;
+
+       IPW_DEBUG_INFO("enter\n");
+
+       IPW_DEBUG_SCAN("setting scan options\n");
+
+       cmd.host_command_parameters[0] = 0;
+
+       if (!(priv->config & CFG_ASSOCIATE))
+               cmd.host_command_parameters[0] |= IPW_SCAN_NOASSOCIATE;
+       if ((priv->sec.flags & SEC_ENABLED) && priv->sec.enabled)
+               cmd.host_command_parameters[0] |= IPW_SCAN_MIXED_CELL;
+       if (priv->config & CFG_PASSIVE_SCAN)
+               cmd.host_command_parameters[0] |= IPW_SCAN_PASSIVE;
+
+       cmd.host_command_parameters[1] = priv->channel_mask;
+
+       err = ipw2100_hw_send_command(priv, &cmd);
+
+       IPW_DEBUG_HC("SET_SCAN_OPTIONS 0x%04X\n",
+                    cmd.host_command_parameters[0]);
+
+       return err;
+}
+
+static int ipw2100_start_scan(struct ipw2100_priv *priv)
+{
+       struct host_command cmd = {
+               .host_command = BROADCAST_SCAN,
+               .host_command_sequence = 0,
+               .host_command_length = 4
+       };
+       int err;
+
+       IPW_DEBUG_HC("START_SCAN\n");
+
+       cmd.host_command_parameters[0] = 0;
+
+       /* No scanning if in monitor mode */
+       if (priv->ieee->iw_mode == IW_MODE_MONITOR)
+               return 1;
+
+       if (priv->status & STATUS_SCANNING) {
+               IPW_DEBUG_SCAN("Scan requested while already in scan...\n");
+               return 0;
+       }
+
+       IPW_DEBUG_INFO("enter\n");
+
+       /* Not clearing here; doing so makes iwlist always return nothing...
+        *
+        * We should modify the table logic to use aging tables vs. clearing
+        * the table on each scan start.
+        */
+       IPW_DEBUG_SCAN("starting scan\n");
+
+       priv->status |= STATUS_SCANNING;
+       err = ipw2100_hw_send_command(priv, &cmd);
+       if (err)
+               priv->status &= ~STATUS_SCANNING;
+
+       IPW_DEBUG_INFO("exit\n");
+
+       return err;
+}
+
+static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
+{
+       unsigned long flags;
+       int rc = 0;
+       u32 lock;
+       u32 ord_len = sizeof(lock);
+
+       /* Quite if manually disabled. */
+       if (priv->status & STATUS_RF_KILL_SW) {
+               IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable "
+                              "switch\n", priv->net_dev->name);
+               return 0;
+       }
+
+       /* If the interrupt is enabled, turn it off... */
+       spin_lock_irqsave(&priv->low_lock, flags);
+       ipw2100_disable_interrupts(priv);
+
+       /* Reset any fatal_error conditions */
+       ipw2100_reset_fatalerror(priv);
+       spin_unlock_irqrestore(&priv->low_lock, flags);
+
+       if (priv->status & STATUS_POWERED ||
+           (priv->status & STATUS_RESET_PENDING)) {
+               /* Power cycle the card ... */
+               if (ipw2100_power_cycle_adapter(priv)) {
+                       printk(KERN_WARNING DRV_NAME ": %s: Could not cycle adapter.\n",
+                                         priv->net_dev->name);
+                       rc = 1;
+                       goto exit;
+               }
+       } else
+               priv->status |= STATUS_POWERED;
+
+       /* Load the firmware, start the clocks, etc. */
+       if (ipw2100_start_adapter(priv)) {
+               printk(KERN_ERR DRV_NAME ": %s: Failed to start the firmware.\n",
+                               priv->net_dev->name);
+               rc = 1;
+               goto exit;
+       }
+
+       ipw2100_initialize_ordinals(priv);
+
+       /* Determine capabilities of this particular HW configuration */
+       if (ipw2100_get_hw_features(priv)) {
+               printk(KERN_ERR DRV_NAME ": %s: Failed to determine HW features.\n",
+                               priv->net_dev->name);
+               rc = 1;
+               goto exit;
+       }
+
+       lock = LOCK_NONE;
+       if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) {
+               printk(KERN_ERR DRV_NAME ": %s: Failed to clear ordinal lock.\n",
+                               priv->net_dev->name);
+               rc = 1;
+               goto exit;
+       }
+
+       priv->status &= ~STATUS_SCANNING;
+
+       if (rf_kill_active(priv)) {
+               printk(KERN_INFO "%s: Radio is disabled by RF switch.\n",
+                      priv->net_dev->name);
+
+               if (priv->stop_rf_kill) {
+                       priv->stop_rf_kill = 0;
+                       queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ);
+               }
+
+               deferred = 1;
+       }
+
+       /* Turn on the interrupt so that commands can be processed */
+       ipw2100_enable_interrupts(priv);
+
+       /* Send all of the commands that must be sent prior to
+        * HOST_COMPLETE */
+       if (ipw2100_adapter_setup(priv)) {
+               printk(KERN_ERR DRV_NAME ": %s: Failed to start the card.\n",
+                               priv->net_dev->name);
+               rc = 1;
+               goto exit;
+       }
+
+       if (!deferred) {
+               /* Enable the adapter - sends HOST_COMPLETE */
+               if (ipw2100_enable_adapter(priv)) {
+                       printk(KERN_ERR DRV_NAME ": "
+                               "%s: failed in call to enable adapter.\n",
+                               priv->net_dev->name);
+                       ipw2100_hw_stop_adapter(priv);
+                       rc = 1;
+                       goto exit;
+               }
+
+
+               /* Start a scan . . . */
+               ipw2100_set_scan_options(priv);
+               ipw2100_start_scan(priv);
+       }
+
+ exit:
+       return rc;
+}
+
+/* Called by register_netdev() */
+static int ipw2100_net_init(struct net_device *dev)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       return ipw2100_up(priv, 1);
+}
+
+static void ipw2100_down(struct ipw2100_priv *priv)
+{
+       unsigned long flags;
+       union iwreq_data wrqu = {
+               .ap_addr = {
+                       .sa_family = ARPHRD_ETHER
+               }
+       };
+       int associated = priv->status & STATUS_ASSOCIATED;
+
+       /* Kill the RF switch timer */
+       if (!priv->stop_rf_kill) {
+               priv->stop_rf_kill = 1;
+               cancel_delayed_work(&priv->rf_kill);
+       }
+
+       /* Kill the firmare hang check timer */
+       if (!priv->stop_hang_check) {
+               priv->stop_hang_check = 1;
+               cancel_delayed_work(&priv->hang_check);
+       }
+
+       /* Kill any pending resets */
+       if (priv->status & STATUS_RESET_PENDING)
+               cancel_delayed_work(&priv->reset_work);
+
+       /* Make sure the interrupt is on so that FW commands will be
+        * processed correctly */
+       spin_lock_irqsave(&priv->low_lock, flags);
+       ipw2100_enable_interrupts(priv);
+       spin_unlock_irqrestore(&priv->low_lock, flags);
+
+       if (ipw2100_hw_stop_adapter(priv))
+               printk(KERN_ERR DRV_NAME ": %s: Error stopping adapter.\n",
+                      priv->net_dev->name);
+
+       /* Do not disable the interrupt until _after_ we disable
+        * the adaptor.  Otherwise the CARD_DISABLE command will never
+        * be ack'd by the firmware */
+       spin_lock_irqsave(&priv->low_lock, flags);
+       ipw2100_disable_interrupts(priv);
+       spin_unlock_irqrestore(&priv->low_lock, flags);
+
+#ifdef ACPI_CSTATE_LIMIT_DEFINED
+       if (priv->config & CFG_C3_DISABLED) {
+               IPW_DEBUG_INFO(DRV_NAME ": Resetting C3 transitions.\n");
+               acpi_set_cstate_limit(priv->cstate_limit);
+               priv->config &= ~CFG_C3_DISABLED;
+       }
+#endif
+
+       /* We have to signal any supplicant if we are disassociating */
+       if (associated)
+               wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
+
+       priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
+       netif_carrier_off(priv->net_dev);
+       netif_stop_queue(priv->net_dev);
+}
+
+static void ipw2100_reset_adapter(struct ipw2100_priv *priv)
+{
+       unsigned long flags;
+       union iwreq_data wrqu = {
+               .ap_addr = {
+                       .sa_family = ARPHRD_ETHER
+               }
+       };
+       int associated = priv->status & STATUS_ASSOCIATED;
+
+       spin_lock_irqsave(&priv->low_lock, flags);
+       IPW_DEBUG_INFO(DRV_NAME ": %s: Restarting adapter.\n",
+                      priv->net_dev->name);
+       priv->resets++;
+       priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
+       priv->status |= STATUS_SECURITY_UPDATED;
+
+       /* Force a power cycle even if interface hasn't been opened
+        * yet */
+       cancel_delayed_work(&priv->reset_work);
+       priv->status |= STATUS_RESET_PENDING;
+       spin_unlock_irqrestore(&priv->low_lock, flags);
+
+       down(&priv->action_sem);
+       /* stop timed checks so that they don't interfere with reset */
+       priv->stop_hang_check = 1;
+       cancel_delayed_work(&priv->hang_check);
+
+       /* We have to signal any supplicant if we are disassociating */
+       if (associated)
+               wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
+
+       ipw2100_up(priv, 0);
+       up(&priv->action_sem);
+
+}
+
+
+static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
+{
+
+#define MAC_ASSOCIATION_READ_DELAY (HZ)
+       int ret, len, essid_len;
+       char essid[IW_ESSID_MAX_SIZE];
+       u32 txrate;
+       u32 chan;
+       char *txratename;
+       u8 bssid[ETH_ALEN];
+
+       /*
+        * TBD: BSSID is usually 00:00:00:00:00:00 here and not
+        *      an actual MAC of the AP. Seems like FW sets this
+        *      address too late. Read it later and expose through
+        *      /proc or schedule a later task to query and update
+        */
+
+       essid_len = IW_ESSID_MAX_SIZE;
+       ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID,
+                                 essid, &essid_len);
+       if (ret) {
+               IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
+                                  __LINE__);
+               return;
+       }
+
+       len = sizeof(u32);
+       ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE,
+                                 &txrate, &len);
+       if (ret) {
+               IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
+                                  __LINE__);
+               return;
+       }
+
+       len = sizeof(u32);
+       ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &len);
+       if (ret) {
+               IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
+                                  __LINE__);
+               return;
+       }
+       len = ETH_ALEN;
+        ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid,  &len);
+       if (ret) {
+               IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
+                                  __LINE__);
+               return;
+       }
+       memcpy(priv->ieee->bssid, bssid, ETH_ALEN);
+
+
+       switch (txrate) {
+       case TX_RATE_1_MBIT:
+               txratename = "1Mbps";
+               break;
+       case TX_RATE_2_MBIT:
+               txratename = "2Mbsp";
+               break;
+       case TX_RATE_5_5_MBIT:
+               txratename = "5.5Mbps";
+               break;
+       case TX_RATE_11_MBIT:
+               txratename = "11Mbps";
+               break;
+       default:
+               IPW_DEBUG_INFO("Unknown rate: %d\n", txrate);
+               txratename = "unknown rate";
+               break;
+       }
+
+       IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID="
+                      MAC_FMT ")\n",
+                      priv->net_dev->name, escape_essid(essid, essid_len),
+                      txratename, chan, MAC_ARG(bssid));
+
+       /* now we copy read ssid into dev */
+       if (!(priv->config & CFG_STATIC_ESSID)) {
+               priv->essid_len = min((u8)essid_len, (u8)IW_ESSID_MAX_SIZE);
+               memcpy(priv->essid, essid, priv->essid_len);
+       }
+       priv->channel = chan;
+       memcpy(priv->bssid, bssid, ETH_ALEN);
+
+       priv->status |= STATUS_ASSOCIATING;
+       priv->connect_start = get_seconds();
+
+       queue_delayed_work(priv->workqueue, &priv->wx_event_work, HZ / 10);
+}
+
+
+static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
+                            int length, int batch_mode)
+{
+       int ssid_len = min(length, IW_ESSID_MAX_SIZE);
+       struct host_command cmd = {
+               .host_command = SSID,
+               .host_command_sequence = 0,
+               .host_command_length = ssid_len
+       };
+       int err;
+
+       IPW_DEBUG_HC("SSID: '%s'\n", escape_essid(essid, ssid_len));
+
+       if (ssid_len)
+               memcpy((char*)cmd.host_command_parameters,
+                      essid, ssid_len);
+
+       if (!batch_mode) {
+               err = ipw2100_disable_adapter(priv);
+               if (err)
+                       return err;
+       }
+
+       /* Bug in FW currently doesn't honor bit 0 in SET_SCAN_OPTIONS to
+        * disable auto association -- so we cheat by setting a bogus SSID */
+       if (!ssid_len && !(priv->config & CFG_ASSOCIATE)) {
+               int i;
+               u8 *bogus = (u8*)cmd.host_command_parameters;
+               for (i = 0; i < IW_ESSID_MAX_SIZE; i++)
+                       bogus[i] = 0x18 + i;
+               cmd.host_command_length = IW_ESSID_MAX_SIZE;
+       }
+
+       /* NOTE:  We always send the SSID command even if the provided ESSID is
+        * the same as what we currently think is set. */
+
+       err = ipw2100_hw_send_command(priv, &cmd);
+       if (!err) {
+               memset(priv->essid + ssid_len, 0,
+                      IW_ESSID_MAX_SIZE - ssid_len);
+               memcpy(priv->essid, essid, ssid_len);
+               priv->essid_len = ssid_len;
+       }
+
+       if (!batch_mode) {
+               if (ipw2100_enable_adapter(priv))
+                       err = -EIO;
+       }
+
+       return err;
+}
+
+static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
+{
+       IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
+                 "disassociated: '%s' " MAC_FMT " \n",
+                 escape_essid(priv->essid, priv->essid_len),
+                 MAC_ARG(priv->bssid));
+
+       priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
+
+       if (priv->status & STATUS_STOPPING) {
+               IPW_DEBUG_INFO("Card is stopping itself, discard ASSN_LOST.\n");
+               return;
+       }
+
+       memset(priv->bssid, 0, ETH_ALEN);
+       memset(priv->ieee->bssid, 0, ETH_ALEN);
+
+       netif_carrier_off(priv->net_dev);
+       netif_stop_queue(priv->net_dev);
+
+       if (!(priv->status & STATUS_RUNNING))
+               return;
+
+       if (priv->status & STATUS_SECURITY_UPDATED)
+               queue_work(priv->workqueue, &priv->security_work);
+
+       queue_work(priv->workqueue, &priv->wx_event_work);
+}
+
+static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
+{
+       IPW_DEBUG_INFO("%s: RF Kill state changed to radio OFF.\n",
+              priv->net_dev->name);
+
+       /* RF_KILL is now enabled (else we wouldn't be here) */
+       priv->status |= STATUS_RF_KILL_HW;
+
+#ifdef ACPI_CSTATE_LIMIT_DEFINED
+       if (priv->config & CFG_C3_DISABLED) {
+               IPW_DEBUG_INFO(DRV_NAME ": Resetting C3 transitions.\n");
+               acpi_set_cstate_limit(priv->cstate_limit);
+               priv->config &= ~CFG_C3_DISABLED;
+       }
+#endif
+
+       /* Make sure the RF Kill check timer is running */
+       priv->stop_rf_kill = 0;
+       cancel_delayed_work(&priv->rf_kill);
+       queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ);
+}
+
+static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
+{
+       IPW_DEBUG_SCAN("scan complete\n");
+       /* Age the scan results... */
+       priv->ieee->scans++;
+       priv->status &= ~STATUS_SCANNING;
+}
+
+#ifdef CONFIG_IPW_DEBUG
+#define IPW2100_HANDLER(v, f) { v, f, # v }
+struct ipw2100_status_indicator {
+       int status;
+       void (*cb)(struct ipw2100_priv *priv, u32 status);
+       char *name;
+};
+#else
+#define IPW2100_HANDLER(v, f) { v, f }
+struct ipw2100_status_indicator {
+       int status;
+       void (*cb)(struct ipw2100_priv *priv, u32 status);
+};
+#endif /* CONFIG_IPW_DEBUG */
+
+static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status)
+{
+       IPW_DEBUG_SCAN("Scanning...\n");
+       priv->status |= STATUS_SCANNING;
+}
+
+static const struct ipw2100_status_indicator status_handlers[] = {
+       IPW2100_HANDLER(IPW_STATE_INITIALIZED, NULL),
+       IPW2100_HANDLER(IPW_STATE_COUNTRY_FOUND, NULL),
+       IPW2100_HANDLER(IPW_STATE_ASSOCIATED, isr_indicate_associated),
+       IPW2100_HANDLER(IPW_STATE_ASSN_LOST, isr_indicate_association_lost),
+       IPW2100_HANDLER(IPW_STATE_ASSN_CHANGED, NULL),
+       IPW2100_HANDLER(IPW_STATE_SCAN_COMPLETE, isr_scan_complete),
+       IPW2100_HANDLER(IPW_STATE_ENTERED_PSP, NULL),
+       IPW2100_HANDLER(IPW_STATE_LEFT_PSP, NULL),
+       IPW2100_HANDLER(IPW_STATE_RF_KILL, isr_indicate_rf_kill),
+       IPW2100_HANDLER(IPW_STATE_DISABLED, NULL),
+       IPW2100_HANDLER(IPW_STATE_POWER_DOWN, NULL),
+       IPW2100_HANDLER(IPW_STATE_SCANNING, isr_indicate_scanning),
+       IPW2100_HANDLER(-1, NULL)
+};
+
+
+static void isr_status_change(struct ipw2100_priv *priv, int status)
+{
+       int i;
+
+       if (status == IPW_STATE_SCANNING &&
+           priv->status & STATUS_ASSOCIATED &&
+           !(priv->status & STATUS_SCANNING)) {
+               IPW_DEBUG_INFO("Scan detected while associated, with "
+                              "no scan request.  Restarting firmware.\n");
+
+               /* Wake up any sleeping jobs */
+               schedule_reset(priv);
+       }
+
+       for (i = 0; status_handlers[i].status != -1; i++) {
+               if (status == status_handlers[i].status) {
+                       IPW_DEBUG_NOTIF("Status change: %s\n",
+                                        status_handlers[i].name);
+                       if (status_handlers[i].cb)
+                               status_handlers[i].cb(priv, status);
+                       priv->wstats.status = status;
+                       return;
+               }
+       }
+
+       IPW_DEBUG_NOTIF("unknown status received: %04x\n", status);
+}
+
+static void isr_rx_complete_command(
+       struct ipw2100_priv *priv,
+       struct ipw2100_cmd_header *cmd)
+{
+#ifdef CONFIG_IPW_DEBUG
+       if (cmd->host_command_reg < ARRAY_SIZE(command_types)) {
+               IPW_DEBUG_HC("Command completed '%s (%d)'\n",
+                            command_types[cmd->host_command_reg],
+                            cmd->host_command_reg);
+       }
+#endif
+       if (cmd->host_command_reg == HOST_COMPLETE)
+               priv->status |= STATUS_ENABLED;
+
+       if (cmd->host_command_reg == CARD_DISABLE)
+               priv->status &= ~STATUS_ENABLED;
+
+       priv->status &= ~STATUS_CMD_ACTIVE;
+
+       wake_up_interruptible(&priv->wait_command_queue);
+}
+
+#ifdef CONFIG_IPW_DEBUG
+static const char *frame_types[] = {
+       "COMMAND_STATUS_VAL",
+       "STATUS_CHANGE_VAL",
+       "P80211_DATA_VAL",
+       "P8023_DATA_VAL",
+       "HOST_NOTIFICATION_VAL"
+};
+#endif
+
+
+static inline int ipw2100_alloc_skb(
+       struct ipw2100_priv *priv,
+       struct ipw2100_rx_packet *packet)
+{
+       packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx));
+       if (!packet->skb)
+               return -ENOMEM;
+
+       packet->rxp = (struct ipw2100_rx *)packet->skb->data;
+       packet->dma_addr = pci_map_single(priv->pci_dev, packet->skb->data,
+                                         sizeof(struct ipw2100_rx),
+                                         PCI_DMA_FROMDEVICE);
+       /* NOTE: pci_map_single does not return an error code, and 0 is a valid
+        *       dma_addr */
+
+       return 0;
+}
+
+
+#define SEARCH_ERROR   0xffffffff
+#define SEARCH_FAIL    0xfffffffe
+#define SEARCH_SUCCESS 0xfffffff0
+#define SEARCH_DISCARD 0
+#define SEARCH_SNAPSHOT 1
+
+#define SNAPSHOT_ADDR(ofs) (priv->snapshot[((ofs) >> 12) & 0xff] + ((ofs) & 0xfff))
+static inline int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
+{
+       int i;
+       if (priv->snapshot[0])
+               return 1;
+       for (i = 0; i < 0x30; i++) {
+               priv->snapshot[i] = (u8*)kmalloc(0x1000, GFP_ATOMIC);
+               if (!priv->snapshot[i]) {
+                       IPW_DEBUG_INFO("%s: Error allocating snapshot "
+                              "buffer %d\n", priv->net_dev->name, i);
+                       while (i > 0)
+                               kfree(priv->snapshot[--i]);
+                       priv->snapshot[0] = NULL;
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
+static inline void ipw2100_snapshot_free(struct ipw2100_priv *priv)
+{
+       int i;
+       if (!priv->snapshot[0])
+               return;
+       for (i = 0; i < 0x30; i++)
+               kfree(priv->snapshot[i]);
+       priv->snapshot[0] = NULL;
+}
+
+static inline u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 *in_buf,
+                                   size_t len, int mode)
+{
+       u32 i, j;
+       u32 tmp;
+       u8 *s, *d;
+       u32 ret;
+
+       s = in_buf;
+       if (mode == SEARCH_SNAPSHOT) {
+               if (!ipw2100_snapshot_alloc(priv))
+                       mode = SEARCH_DISCARD;
+       }
+
+       for (ret = SEARCH_FAIL, i = 0; i < 0x30000; i += 4) {
+               read_nic_dword(priv->net_dev, i, &tmp);
+               if (mode == SEARCH_SNAPSHOT)
+                       *(u32 *)SNAPSHOT_ADDR(i) = tmp;
+               if (ret == SEARCH_FAIL) {
+                       d = (u8*)&tmp;
+                       for (j = 0; j < 4; j++) {
+                               if (*s != *d) {
+                                       s = in_buf;
+                                       continue;
+                               }
+
+                               s++;
+                               d++;
+
+                               if ((s - in_buf) == len)
+                                       ret = (i + j) - len + 1;
+                       }
+               } else if (mode == SEARCH_DISCARD)
+                       return ret;
+       }
+
+       return ret;
+}
+
+/*
+ *
+ * 0) Disconnect the SKB from the firmware (just unmap)
+ * 1) Pack the ETH header into the SKB
+ * 2) Pass the SKB to the network stack
+ *
+ * When packet is provided by the firmware, it contains the following:
+ *
+ * .  ieee80211_hdr
+ * .  ieee80211_snap_hdr
+ *
+ * The size of the constructed ethernet
+ *
+ */
+#ifdef CONFIG_IPW2100_RX_DEBUG
+static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
+#endif
+
+static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv,
+                                              int i)
+{
+#ifdef CONFIG_IPW_DEBUG_C3
+       struct ipw2100_status *status = &priv->status_queue.drv[i];
+       u32 match, reg;
+       int j;
+#endif
+#ifdef ACPI_CSTATE_LIMIT_DEFINED
+       int limit;
+#endif
+
+       IPW_DEBUG_INFO(DRV_NAME ": PCI latency error detected at "
+                      "0x%04zX.\n", i * sizeof(struct ipw2100_status));
+
+#ifdef ACPI_CSTATE_LIMIT_DEFINED
+       IPW_DEBUG_INFO(DRV_NAME ": Disabling C3 transitions.\n");
+       limit = acpi_get_cstate_limit();
+       if (limit > 2) {
+               priv->cstate_limit = limit;
+               acpi_set_cstate_limit(2);
+               priv->config |= CFG_C3_DISABLED;
+       }
+#endif
+
+#ifdef CONFIG_IPW_DEBUG_C3
+       /* Halt the fimrware so we can get a good image */
+       write_register(priv->net_dev, IPW_REG_RESET_REG,
+                      IPW_AUX_HOST_RESET_REG_STOP_MASTER);
+       j = 5;
+       do {
+               udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
+               read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
+
+               if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
+                       break;
+       }  while (j--);
+
+       match = ipw2100_match_buf(priv, (u8*)status,
+                                 sizeof(struct ipw2100_status),
+                                 SEARCH_SNAPSHOT);
+       if (match < SEARCH_SUCCESS)
+               IPW_DEBUG_INFO("%s: DMA status match in Firmware at "
+                              "offset 0x%06X, length %d:\n",
+                              priv->net_dev->name, match,
+                              sizeof(struct ipw2100_status));
+       else
+               IPW_DEBUG_INFO("%s: No DMA status match in "
+                              "Firmware.\n", priv->net_dev->name);
+
+       printk_buf((u8*)priv->status_queue.drv,
+                  sizeof(struct ipw2100_status) * RX_QUEUE_LENGTH);
+#endif
+
+       priv->fatal_error = IPW2100_ERR_C3_CORRUPTION;
+       priv->ieee->stats.rx_errors++;
+       schedule_reset(priv);
+}
+
+static inline void isr_rx(struct ipw2100_priv *priv, int i,
+                         struct ieee80211_rx_stats *stats)
+{
+       struct ipw2100_status *status = &priv->status_queue.drv[i];
+       struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
+
+       IPW_DEBUG_RX("Handler...\n");
+
+       if (unlikely(status->frame_size > skb_tailroom(packet->skb))) {
+               IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
+                              "  Dropping.\n",
+                              priv->net_dev->name,
+                              status->frame_size, skb_tailroom(packet->skb));
+               priv->ieee->stats.rx_errors++;
+               return;
+       }
+
+       if (unlikely(!netif_running(priv->net_dev))) {
+               priv->ieee->stats.rx_errors++;
+               priv->wstats.discard.misc++;
+               IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
+               return;
+       }
+
+       if (unlikely(priv->ieee->iw_mode == IW_MODE_MONITOR &&
+                    status->flags & IPW_STATUS_FLAG_CRC_ERROR)) {
+               IPW_DEBUG_RX("CRC error in packet.  Dropping.\n");
+               priv->ieee->stats.rx_errors++;
+               return;
+       }
+
+       if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR &&
+               !(priv->status & STATUS_ASSOCIATED))) {
+               IPW_DEBUG_DROP("Dropping packet while not associated.\n");
+               priv->wstats.discard.misc++;
+               return;
+       }
+
+
+       pci_unmap_single(priv->pci_dev,
+                        packet->dma_addr,
+                        sizeof(struct ipw2100_rx),
+                        PCI_DMA_FROMDEVICE);
+
+       skb_put(packet->skb, status->frame_size);
+
+#ifdef CONFIG_IPW2100_RX_DEBUG
+       /* Make a copy of the frame so we can dump it to the logs if
+        * ieee80211_rx fails */
+       memcpy(packet_data, packet->skb->data,
+              min_t(u32, status->frame_size, IPW_RX_NIC_BUFFER_LENGTH));
+#endif
+
+       if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
+#ifdef CONFIG_IPW2100_RX_DEBUG
+               IPW_DEBUG_DROP("%s: Non consumed packet:\n",
+                              priv->net_dev->name);
+               printk_buf(IPW_DL_DROP, packet_data, status->frame_size);
+#endif
+               priv->ieee->stats.rx_errors++;
+
+               /* ieee80211_rx failed, so it didn't free the SKB */
+               dev_kfree_skb_any(packet->skb);
+               packet->skb = NULL;
+       }
+
+       /* We need to allocate a new SKB and attach it to the RDB. */
+       if (unlikely(ipw2100_alloc_skb(priv, packet))) {
+               printk(KERN_WARNING DRV_NAME ": "
+                       "%s: Unable to allocate SKB onto RBD ring - disabling "
+                       "adapter.\n", priv->net_dev->name);
+               /* TODO: schedule adapter shutdown */
+               IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
+       }
+
+       /* Update the RDB entry */
+       priv->rx_queue.drv[i].host_addr = packet->dma_addr;
+}
+
+static inline int ipw2100_corruption_check(struct ipw2100_priv *priv, int i)
+{
+       struct ipw2100_status *status = &priv->status_queue.drv[i];
+       struct ipw2100_rx *u = priv->rx_buffers[i].rxp;
+       u16 frame_type = status->status_fields & STATUS_TYPE_MASK;
+
+       switch (frame_type) {
+       case COMMAND_STATUS_VAL:
+               return (status->frame_size != sizeof(u->rx_data.command));
+       case STATUS_CHANGE_VAL:
+               return (status->frame_size != sizeof(u->rx_data.status));
+       case HOST_NOTIFICATION_VAL:
+               return (status->frame_size < sizeof(u->rx_data.notification));
+       case P80211_DATA_VAL:
+       case P8023_DATA_VAL:
+#ifdef CONFIG_IPW2100_MONITOR
+               return 0;
+#else
+               switch (WLAN_FC_GET_TYPE(u->rx_data.header.frame_ctl)) {
+               case IEEE80211_FTYPE_MGMT:
+               case IEEE80211_FTYPE_CTL:
+                       return 0;
+               case IEEE80211_FTYPE_DATA:
+                       return (status->frame_size >
+                               IPW_MAX_802_11_PAYLOAD_LENGTH);
+               }
+#endif
+       }
+
+       return 1;
+}
+
+/*
+ * ipw2100 interrupts are disabled at this point, and the ISR
+ * is the only code that calls this method.  So, we do not need
+ * to play with any locks.
+ *
+ * RX Queue works as follows:
+ *
+ * Read index - firmware places packet in entry identified by the
+ *              Read index and advances Read index.  In this manner,
+ *              Read index will always point to the next packet to
+ *              be filled--but not yet valid.
+ *
+ * Write index - driver fills this entry with an unused RBD entry.
+ *               This entry has not filled by the firmware yet.
+ *
+ * In between the W and R indexes are the RBDs that have been received
+ * but not yet processed.
+ *
+ * The process of handling packets will start at WRITE + 1 and advance
+ * until it reaches the READ index.
+ *
+ * The WRITE index is cached in the variable 'priv->rx_queue.next'.
+ *
+ */
+static inline void __ipw2100_rx_process(struct ipw2100_priv *priv)
+{
+       struct ipw2100_bd_queue *rxq = &priv->rx_queue;
+       struct ipw2100_status_queue *sq = &priv->status_queue;
+       struct ipw2100_rx_packet *packet;
+       u16 frame_type;
+       u32 r, w, i, s;
+       struct ipw2100_rx *u;
+       struct ieee80211_rx_stats stats = {
+               .mac_time = jiffies,
+       };
+
+       read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_READ_INDEX, &r);
+       read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, &w);
+
+       if (r >= rxq->entries) {
+               IPW_DEBUG_RX("exit - bad read index\n");
+               return;
+       }
+
+       i = (rxq->next + 1) % rxq->entries;
+       s = i;
+       while (i != r) {
+               /* IPW_DEBUG_RX("r = %d : w = %d : processing = %d\n",
+                  r, rxq->next, i); */
+
+               packet = &priv->rx_buffers[i];
+
+               /* Sync the DMA for the STATUS buffer so CPU is sure to get
+                * the correct values */
+               pci_dma_sync_single_for_cpu(
+                       priv->pci_dev,
+                       sq->nic + sizeof(struct ipw2100_status) * i,
+                       sizeof(struct ipw2100_status),
+                       PCI_DMA_FROMDEVICE);
+
+               /* Sync the DMA for the RX buffer so CPU is sure to get
+                * the correct values */
+               pci_dma_sync_single_for_cpu(priv->pci_dev, packet->dma_addr,
+                                           sizeof(struct ipw2100_rx),
+                                           PCI_DMA_FROMDEVICE);
+
+               if (unlikely(ipw2100_corruption_check(priv, i))) {
+                       ipw2100_corruption_detected(priv, i);
+                       goto increment;
+               }
+
+               u = packet->rxp;
+               frame_type = sq->drv[i].status_fields &
+                       STATUS_TYPE_MASK;
+               stats.rssi = sq->drv[i].rssi + IPW2100_RSSI_TO_DBM;
+               stats.len = sq->drv[i].frame_size;
+
+               stats.mask = 0;
+               if (stats.rssi != 0)
+                       stats.mask |= IEEE80211_STATMASK_RSSI;
+               stats.freq = IEEE80211_24GHZ_BAND;
+
+               IPW_DEBUG_RX(
+                       "%s: '%s' frame type received (%d).\n",
+                       priv->net_dev->name, frame_types[frame_type],
+                       stats.len);
+
+               switch (frame_type) {
+               case COMMAND_STATUS_VAL:
+                       /* Reset Rx watchdog */
+                       isr_rx_complete_command(
+                               priv, &u->rx_data.command);
+                       break;
+
+               case STATUS_CHANGE_VAL:
+                       isr_status_change(priv, u->rx_data.status);
+                       break;
+
+               case P80211_DATA_VAL:
+               case P8023_DATA_VAL:
+#ifdef CONFIG_IPW2100_MONITOR
+                       if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+                               isr_rx(priv, i, &stats);
+                               break;
+                       }
+#endif
+                       if (stats.len < sizeof(u->rx_data.header))
+                               break;
+                       switch (WLAN_FC_GET_TYPE(u->rx_data.header.
+                                                frame_ctl)) {
+                       case IEEE80211_FTYPE_MGMT:
+                               ieee80211_rx_mgt(priv->ieee,
+                                                &u->rx_data.header,
+                                                &stats);
+                               break;
+
+                       case IEEE80211_FTYPE_CTL:
+                               break;
+
+                       case IEEE80211_FTYPE_DATA:
+                               isr_rx(priv, i, &stats);
+                               break;
+
+                       }
+                       break;
+               }
+
+       increment:
+               /* clear status field associated with this RBD */
+               rxq->drv[i].status.info.field = 0;
+
+               i = (i + 1) % rxq->entries;
+       }
+
+       if (i != s) {
+               /* backtrack one entry, wrapping to end if at 0 */
+               rxq->next = (i ? i : rxq->entries) - 1;
+
+               write_register(priv->net_dev,
+                              IPW_MEM_HOST_SHARED_RX_WRITE_INDEX,
+                              rxq->next);
+       }
+}
+
+
+/*
+ * __ipw2100_tx_process
+ *
+ * This routine will determine whether the next packet on
+ * the fw_pend_list has been processed by the firmware yet.
+ *
+ * If not, then it does nothing and returns.
+ *
+ * If so, then it removes the item from the fw_pend_list, frees
+ * any associated storage, and places the item back on the
+ * free list of its source (either msg_free_list or tx_free_list)
+ *
+ * TX Queue works as follows:
+ *
+ * Read index - points to the next TBD that the firmware will
+ *              process.  The firmware will read the data, and once
+ *              done processing, it will advance the Read index.
+ *
+ * Write index - driver fills this entry with an constructed TBD
+ *               entry.  The Write index is not advanced until the
+ *               packet has been configured.
+ *
+ * In between the W and R indexes are the TBDs that have NOT been
+ * processed.  Lagging behind the R index are packets that have
+ * been processed but have not been freed by the driver.
+ *
+ * In order to free old storage, an internal index will be maintained
+ * that points to the next packet to be freed.  When all used
+ * packets have been freed, the oldest index will be the same as the
+ * firmware's read index.
+ *
+ * The OLDEST index is cached in the variable 'priv->tx_queue.oldest'
+ *
+ * Because the TBD structure can not contain arbitrary data, the
+ * driver must keep an internal queue of cached allocations such that
+ * it can put that data back into the tx_free_list and msg_free_list
+ * for use by future command and data packets.
+ *
+ */
+static inline int __ipw2100_tx_process(struct ipw2100_priv *priv)
+{
+       struct ipw2100_bd_queue *txq = &priv->tx_queue;
+        struct ipw2100_bd *tbd;
+       struct list_head *element;
+       struct ipw2100_tx_packet *packet;
+       int descriptors_used;
+       int e, i;
+       u32 r, w, frag_num = 0;
+
+       if (list_empty(&priv->fw_pend_list))
+               return 0;
+
+       element = priv->fw_pend_list.next;
+
+       packet = list_entry(element, struct ipw2100_tx_packet, list);
+        tbd = &txq->drv[packet->index];
+
+       /* Determine how many TBD entries must be finished... */
+       switch (packet->type) {
+       case COMMAND:
+               /* COMMAND uses only one slot; don't advance */
+               descriptors_used = 1;
+               e = txq->oldest;
+               break;
+
+       case DATA:
+               /* DATA uses two slots; advance and loop position. */
+               descriptors_used = tbd->num_fragments;
+                frag_num = tbd->num_fragments - 1;
+               e = txq->oldest + frag_num;
+               e %= txq->entries;
+               break;
+
+       default:
+               printk(KERN_WARNING DRV_NAME ": %s: Bad fw_pend_list entry!\n",
+                                  priv->net_dev->name);
+               return 0;
+       }
+
+       /* if the last TBD is not done by NIC yet, then packet is
+        * not ready to be released.
+        *
+        */
+       read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
+                     &r);
+       read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
+                     &w);
+       if (w != txq->next)
+               printk(KERN_WARNING DRV_NAME ": %s: write index mismatch\n",
+                      priv->net_dev->name);
+
+        /*
+        * txq->next is the index of the last packet written txq->oldest is
+        * the index of the r is the index of the next packet to be read by
+        * firmware
+        */
+
+
+       /*
+        * Quick graphic to help you visualize the following
+        * if / else statement
+        *
+        * ===>|                     s---->|===============
+        *                               e>|
+        * | a | b | c | d | e | f | g | h | i | j | k | l
+        *       r---->|
+        *               w
+        *
+        * w - updated by driver
+        * r - updated by firmware
+        * s - start of oldest BD entry (txq->oldest)
+        * e - end of oldest BD entry
+        *
+        */
+       if (!((r <= w && (e < r || e >= w)) || (e < r && e >= w))) {
+               IPW_DEBUG_TX("exit - no processed packets ready to release.\n");
+               return 0;
+       }
+
+       list_del(element);
+       DEC_STAT(&priv->fw_pend_stat);
+
+#ifdef CONFIG_IPW_DEBUG
+       {
+               int i = txq->oldest;
+               IPW_DEBUG_TX(
+                       "TX%d V=%p P=%04X T=%04X L=%d\n", i,
+                       &txq->drv[i],
+                       (u32)(txq->nic + i * sizeof(struct ipw2100_bd)),
+                       txq->drv[i].host_addr,
+                       txq->drv[i].buf_length);
+
+               if (packet->type == DATA) {
+                       i = (i + 1) % txq->entries;
+
+                       IPW_DEBUG_TX(
+                               "TX%d V=%p P=%04X T=%04X L=%d\n", i,
+                               &txq->drv[i],
+                               (u32)(txq->nic + i *
+                               sizeof(struct ipw2100_bd)),
+                               (u32)txq->drv[i].host_addr,
+                               txq->drv[i].buf_length);
+               }
+       }
+#endif
+
+       switch (packet->type) {
+       case DATA:
+               if (txq->drv[txq->oldest].status.info.fields.txType != 0)
+                       printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch.  "
+                              "Expecting DATA TBD but pulled "
+                              "something else: ids %d=%d.\n",
+                              priv->net_dev->name, txq->oldest, packet->index);
+
+               /* DATA packet; we have to unmap and free the SKB */
+               priv->ieee->stats.tx_packets++;
+               for (i = 0; i < frag_num; i++) {
+                       tbd = &txq->drv[(packet->index + 1 + i) %
+                                       txq->entries];
+
+                       IPW_DEBUG_TX(
+                               "TX%d P=%08x L=%d\n",
+                               (packet->index + 1 + i) % txq->entries,
+                               tbd->host_addr, tbd->buf_length);
+
+                       pci_unmap_single(priv->pci_dev,
+                                        tbd->host_addr,
+                                        tbd->buf_length,
+                                        PCI_DMA_TODEVICE);
+               }
+
+               priv->ieee->stats.tx_bytes += packet->info.d_struct.txb->payload_size;
+               ieee80211_txb_free(packet->info.d_struct.txb);
+               packet->info.d_struct.txb = NULL;
+
+               list_add_tail(element, &priv->tx_free_list);
+               INC_STAT(&priv->tx_free_stat);
+
+               /* We have a free slot in the Tx queue, so wake up the
+                * transmit layer if it is stopped. */
+               if (priv->status & STATUS_ASSOCIATED &&
+                   netif_queue_stopped(priv->net_dev)) {
+                       IPW_DEBUG_INFO(KERN_INFO
+                                          "%s: Waking net queue.\n",
+                                          priv->net_dev->name);
+                       netif_wake_queue(priv->net_dev);
+               }
+
+               /* A packet was processed by the hardware, so update the
+                * watchdog */
+               priv->net_dev->trans_start = jiffies;
+
+               break;
+
+       case COMMAND:
+               if (txq->drv[txq->oldest].status.info.fields.txType != 1)
+                       printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch.  "
+                              "Expecting COMMAND TBD but pulled "
+                              "something else: ids %d=%d.\n",
+                              priv->net_dev->name, txq->oldest, packet->index);
+
+#ifdef CONFIG_IPW_DEBUG
+               if (packet->info.c_struct.cmd->host_command_reg <
+                   sizeof(command_types) / sizeof(*command_types))
+                       IPW_DEBUG_TX(
+                               "Command '%s (%d)' processed: %d.\n",
+                               command_types[packet->info.c_struct.cmd->host_command_reg],
+                               packet->info.c_struct.cmd->host_command_reg,
+                               packet->info.c_struct.cmd->cmd_status_reg);
+#endif
+
+               list_add_tail(element, &priv->msg_free_list);
+               INC_STAT(&priv->msg_free_stat);
+               break;
+       }
+
+       /* advance oldest used TBD pointer to start of next entry */
+       txq->oldest = (e + 1) % txq->entries;
+       /* increase available TBDs number */
+       txq->available += descriptors_used;
+       SET_STAT(&priv->txq_stat, txq->available);
+
+       IPW_DEBUG_TX("packet latency (send to process)  %ld jiffies\n",
+                        jiffies - packet->jiffy_start);
+
+       return (!list_empty(&priv->fw_pend_list));
+}
+
+
+static inline void __ipw2100_tx_complete(struct ipw2100_priv *priv)
+{
+       int i = 0;
+
+       while (__ipw2100_tx_process(priv) && i < 200) i++;
+
+       if (i == 200) {
+               printk(KERN_WARNING DRV_NAME ": "
+                      "%s: Driver is running slow (%d iters).\n",
+                      priv->net_dev->name, i);
+       }
+}
+
+
+static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
+{
+       struct list_head *element;
+       struct ipw2100_tx_packet *packet;
+       struct ipw2100_bd_queue *txq = &priv->tx_queue;
+       struct ipw2100_bd *tbd;
+       int next = txq->next;
+
+       while (!list_empty(&priv->msg_pend_list)) {
+               /* if there isn't enough space in TBD queue, then
+                * don't stuff a new one in.
+                * NOTE: 3 are needed as a command will take one,
+                *       and there is a minimum of 2 that must be
+                *       maintained between the r and w indexes
+                */
+               if (txq->available <= 3) {
+                       IPW_DEBUG_TX("no room in tx_queue\n");
+                       break;
+               }
+
+               element = priv->msg_pend_list.next;
+               list_del(element);
+               DEC_STAT(&priv->msg_pend_stat);
+
+               packet = list_entry(element,
+                                   struct ipw2100_tx_packet, list);
+
+               IPW_DEBUG_TX("using TBD at virt=%p, phys=%p\n",
+                                &txq->drv[txq->next],
+                                (void*)(txq->nic + txq->next *
+                                        sizeof(struct ipw2100_bd)));
+
+               packet->index = txq->next;
+
+               tbd = &txq->drv[txq->next];
+
+               /* initialize TBD */
+               tbd->host_addr = packet->info.c_struct.cmd_phys;
+               tbd->buf_length = sizeof(struct ipw2100_cmd_header);
+               /* not marking number of fragments causes problems
+                * with f/w debug version */
+               tbd->num_fragments = 1;
+               tbd->status.info.field =
+                       IPW_BD_STATUS_TX_FRAME_COMMAND |
+                       IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
+
+               /* update TBD queue counters */
+               txq->next++;
+               txq->next %= txq->entries;
+               txq->available--;
+               DEC_STAT(&priv->txq_stat);
+
+               list_add_tail(element, &priv->fw_pend_list);
+               INC_STAT(&priv->fw_pend_stat);
+       }
+
+       if (txq->next != next) {
+               /* kick off the DMA by notifying firmware the
+                * write index has moved; make sure TBD stores are sync'd */
+               wmb();
+               write_register(priv->net_dev,
+                              IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
+                              txq->next);
+       }
+}
+
+
+/*
+ * ipw2100_tx_send_data
+ *
+ */
+static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
+{
+       struct list_head *element;
+       struct ipw2100_tx_packet *packet;
+       struct ipw2100_bd_queue *txq = &priv->tx_queue;
+       struct ipw2100_bd *tbd;
+       int next = txq->next;
+        int i = 0;
+       struct ipw2100_data_header *ipw_hdr;
+       struct ieee80211_hdr *hdr;
+
+       while (!list_empty(&priv->tx_pend_list)) {
+               /* if there isn't enough space in TBD queue, then
+                * don't stuff a new one in.
+                * NOTE: 4 are needed as a data will take two,
+                *       and there is a minimum of 2 that must be
+                *       maintained between the r and w indexes
+                */
+               element = priv->tx_pend_list.next;
+                packet = list_entry(element, struct ipw2100_tx_packet, list);
+
+               if (unlikely(1 + packet->info.d_struct.txb->nr_frags >
+                            IPW_MAX_BDS)) {
+                       /* TODO: Support merging buffers if more than
+                        * IPW_MAX_BDS are used */
+                       IPW_DEBUG_INFO(
+                              "%s: Maximum BD theshold exceeded.  "
+                              "Increase fragmentation level.\n",
+                              priv->net_dev->name);
+               }
+
+               if (txq->available <= 3 +
+                   packet->info.d_struct.txb->nr_frags) {
+                       IPW_DEBUG_TX("no room in tx_queue\n");
+                       break;
+               }
+
+               list_del(element);
+               DEC_STAT(&priv->tx_pend_stat);
+
+               tbd = &txq->drv[txq->next];
+
+               packet->index = txq->next;
+
+               ipw_hdr = packet->info.d_struct.data;
+               hdr = (struct ieee80211_hdr *)packet->info.d_struct.txb->
+                       fragments[0]->data;
+
+               if (priv->ieee->iw_mode == IW_MODE_INFRA) {
+                       /* To DS: Addr1 = BSSID, Addr2 = SA,
+                          Addr3 = DA */
+                       memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
+                       memcpy(ipw_hdr->dst_addr, hdr->addr3, ETH_ALEN);
+               } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+                       /* not From/To DS: Addr1 = DA, Addr2 = SA,
+                          Addr3 = BSSID */
+                       memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
+                       memcpy(ipw_hdr->dst_addr, hdr->addr1, ETH_ALEN);
+               }
+
+               ipw_hdr->host_command_reg = SEND;
+               ipw_hdr->host_command_reg1 = 0;
+
+               /* For now we only support host based encryption */
+               ipw_hdr->needs_encryption = 0;
+               ipw_hdr->encrypted = packet->info.d_struct.txb->encrypted;
+               if (packet->info.d_struct.txb->nr_frags > 1)
+                       ipw_hdr->fragment_size =
+                               packet->info.d_struct.txb->frag_size - IEEE80211_3ADDR_LEN;
+               else
+                       ipw_hdr->fragment_size = 0;
+
+               tbd->host_addr = packet->info.d_struct.data_phys;
+               tbd->buf_length = sizeof(struct ipw2100_data_header);
+               tbd->num_fragments = 1 + packet->info.d_struct.txb->nr_frags;
+               tbd->status.info.field =
+                       IPW_BD_STATUS_TX_FRAME_802_3 |
+                       IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
+               txq->next++;
+               txq->next %= txq->entries;
+
+               IPW_DEBUG_TX(
+                       "data header tbd TX%d P=%08x L=%d\n",
+                       packet->index, tbd->host_addr,
+                       tbd->buf_length);
+#ifdef CONFIG_IPW_DEBUG
+               if (packet->info.d_struct.txb->nr_frags > 1)
+                       IPW_DEBUG_FRAG("fragment Tx: %d frames\n",
+                                      packet->info.d_struct.txb->nr_frags);
+#endif
+
+                for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) {
+                       tbd = &txq->drv[txq->next];
+                       if (i == packet->info.d_struct.txb->nr_frags - 1)
+                               tbd->status.info.field =
+                                       IPW_BD_STATUS_TX_FRAME_802_3 |
+                                       IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
+                       else
+                               tbd->status.info.field =
+                                       IPW_BD_STATUS_TX_FRAME_802_3 |
+                                       IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
+
+                       tbd->buf_length = packet->info.d_struct.txb->
+                               fragments[i]->len - IEEE80211_3ADDR_LEN;
+
+                        tbd->host_addr = pci_map_single(
+                               priv->pci_dev,
+                               packet->info.d_struct.txb->fragments[i]->data +
+                               IEEE80211_3ADDR_LEN,
+                               tbd->buf_length,
+                               PCI_DMA_TODEVICE);
+
+                       IPW_DEBUG_TX(
+                               "data frag tbd TX%d P=%08x L=%d\n",
+                               txq->next, tbd->host_addr, tbd->buf_length);
+
+                       pci_dma_sync_single_for_device(
+                               priv->pci_dev, tbd->host_addr,
+                               tbd->buf_length,
+                               PCI_DMA_TODEVICE);
+
+                       txq->next++;
+                       txq->next %= txq->entries;
+                }
+
+               txq->available -= 1 + packet->info.d_struct.txb->nr_frags;
+               SET_STAT(&priv->txq_stat, txq->available);
+
+               list_add_tail(element, &priv->fw_pend_list);
+               INC_STAT(&priv->fw_pend_stat);
+       }
+
+       if (txq->next != next) {
+               /* kick off the DMA by notifying firmware the
+                * write index has moved; make sure TBD stores are sync'd */
+               write_register(priv->net_dev,
+                              IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
+                              txq->next);
+       }
+        return;
+}
+
+static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
+{
+       struct net_device *dev = priv->net_dev;
+       unsigned long flags;
+       u32 inta, tmp;
+
+       spin_lock_irqsave(&priv->low_lock, flags);
+       ipw2100_disable_interrupts(priv);
+
+       read_register(dev, IPW_REG_INTA, &inta);
+
+       IPW_DEBUG_ISR("enter - INTA: 0x%08lX\n",
+                     (unsigned long)inta & IPW_INTERRUPT_MASK);
+
+       priv->in_isr++;
+       priv->interrupts++;
+
+       /* We do not loop and keep polling for more interrupts as this
+        * is frowned upon and doesn't play nicely with other potentially
+        * chained IRQs */
+       IPW_DEBUG_ISR("INTA: 0x%08lX\n",
+                     (unsigned long)inta & IPW_INTERRUPT_MASK);
+
+       if (inta & IPW2100_INTA_FATAL_ERROR) {
+               printk(KERN_WARNING DRV_NAME
+                                 ": Fatal interrupt. Scheduling firmware restart.\n");
+               priv->inta_other++;
+               write_register(
+                       dev, IPW_REG_INTA,
+                       IPW2100_INTA_FATAL_ERROR);
+
+               read_nic_dword(dev, IPW_NIC_FATAL_ERROR, &priv->fatal_error);
+               IPW_DEBUG_INFO("%s: Fatal error value: 0x%08X\n",
+                              priv->net_dev->name, priv->fatal_error);
+
+               read_nic_dword(dev, IPW_ERROR_ADDR(priv->fatal_error), &tmp);
+               IPW_DEBUG_INFO("%s: Fatal error address value: 0x%08X\n",
+                              priv->net_dev->name, tmp);
+
+               /* Wake up any sleeping jobs */
+               schedule_reset(priv);
+       }
+
+       if (inta & IPW2100_INTA_PARITY_ERROR) {
+               printk(KERN_ERR DRV_NAME ": ***** PARITY ERROR INTERRUPT !!!! \n");
+               priv->inta_other++;
+               write_register(
+                       dev, IPW_REG_INTA,
+                       IPW2100_INTA_PARITY_ERROR);
+       }
+
+       if (inta & IPW2100_INTA_RX_TRANSFER) {
+               IPW_DEBUG_ISR("RX interrupt\n");
+
+               priv->rx_interrupts++;
+
+               write_register(
+                       dev, IPW_REG_INTA,
+                       IPW2100_INTA_RX_TRANSFER);
+
+               __ipw2100_rx_process(priv);
+               __ipw2100_tx_complete(priv);
+       }
+
+       if (inta & IPW2100_INTA_TX_TRANSFER) {
+               IPW_DEBUG_ISR("TX interrupt\n");
+
+               priv->tx_interrupts++;
+
+               write_register(dev, IPW_REG_INTA,
+                              IPW2100_INTA_TX_TRANSFER);
+
+               __ipw2100_tx_complete(priv);
+               ipw2100_tx_send_commands(priv);
+               ipw2100_tx_send_data(priv);
+       }
+
+       if (inta & IPW2100_INTA_TX_COMPLETE) {
+               IPW_DEBUG_ISR("TX complete\n");
+               priv->inta_other++;
+               write_register(
+                       dev, IPW_REG_INTA,
+                       IPW2100_INTA_TX_COMPLETE);
+
+               __ipw2100_tx_complete(priv);
+       }
+
+       if (inta & IPW2100_INTA_EVENT_INTERRUPT) {
+               /* ipw2100_handle_event(dev); */
+               priv->inta_other++;
+               write_register(
+                       dev, IPW_REG_INTA,
+                       IPW2100_INTA_EVENT_INTERRUPT);
+       }
+
+       if (inta & IPW2100_INTA_FW_INIT_DONE) {
+               IPW_DEBUG_ISR("FW init done interrupt\n");
+               priv->inta_other++;
+
+               read_register(dev, IPW_REG_INTA, &tmp);
+               if (tmp & (IPW2100_INTA_FATAL_ERROR |
+                          IPW2100_INTA_PARITY_ERROR)) {
+                       write_register(
+                               dev, IPW_REG_INTA,
+                               IPW2100_INTA_FATAL_ERROR |
+                               IPW2100_INTA_PARITY_ERROR);
+               }
+
+               write_register(dev, IPW_REG_INTA,
+                              IPW2100_INTA_FW_INIT_DONE);
+       }
+
+       if (inta & IPW2100_INTA_STATUS_CHANGE) {
+               IPW_DEBUG_ISR("Status change interrupt\n");
+               priv->inta_other++;
+               write_register(
+                       dev, IPW_REG_INTA,
+                       IPW2100_INTA_STATUS_CHANGE);
+       }
+
+       if (inta & IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE) {
+               IPW_DEBUG_ISR("slave host mode interrupt\n");
+               priv->inta_other++;
+               write_register(
+                       dev, IPW_REG_INTA,
+                       IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE);
+       }
+
+       priv->in_isr--;
+       ipw2100_enable_interrupts(priv);
+
+       spin_unlock_irqrestore(&priv->low_lock, flags);
+
+       IPW_DEBUG_ISR("exit\n");
+}
+
+
+static irqreturn_t ipw2100_interrupt(int irq, void *data,
+                                    struct pt_regs *regs)
+{
+       struct ipw2100_priv *priv = data;
+       u32 inta, inta_mask;
+
+       if (!data)
+               return IRQ_NONE;
+
+       spin_lock(&priv->low_lock);
+
+       /* We check to see if we should be ignoring interrupts before
+        * we touch the hardware.  During ucode load if we try and handle
+        * an interrupt we can cause keyboard problems as well as cause
+        * the ucode to fail to initialize */
+       if (!(priv->status & STATUS_INT_ENABLED)) {
+               /* Shared IRQ */
+               goto none;
+       }
+
+       read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
+       read_register(priv->net_dev, IPW_REG_INTA, &inta);
+
+       if (inta == 0xFFFFFFFF) {
+               /* Hardware disappeared */
+               printk(KERN_WARNING DRV_NAME ": IRQ INTA == 0xFFFFFFFF\n");
+               goto none;
+       }
+
+       inta &= IPW_INTERRUPT_MASK;
+
+       if (!(inta & inta_mask)) {
+               /* Shared interrupt */
+               goto none;
+       }
+
+       /* We disable the hardware interrupt here just to prevent unneeded
+        * calls to be made.  We disable this again within the actual
+        * work tasklet, so if another part of the code re-enables the
+        * interrupt, that is fine */
+       ipw2100_disable_interrupts(priv);
+
+       tasklet_schedule(&priv->irq_tasklet);
+       spin_unlock(&priv->low_lock);
+
+       return IRQ_HANDLED;
+ none:
+       spin_unlock(&priv->low_lock);
+       return IRQ_NONE;
+}
+
+static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       struct list_head *element;
+       struct ipw2100_tx_packet *packet;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->low_lock, flags);
+
+       if (!(priv->status & STATUS_ASSOCIATED)) {
+               IPW_DEBUG_INFO("Can not transmit when not connected.\n");
+               priv->ieee->stats.tx_carrier_errors++;
+               netif_stop_queue(dev);
+               goto fail_unlock;
+       }
+
+       if (list_empty(&priv->tx_free_list))
+               goto fail_unlock;
+
+       element = priv->tx_free_list.next;
+       packet = list_entry(element, struct ipw2100_tx_packet, list);
+
+       packet->info.d_struct.txb = txb;
+
+       IPW_DEBUG_TX("Sending fragment (%d bytes):\n",
+                        txb->fragments[0]->len);
+       printk_buf(IPW_DL_TX, txb->fragments[0]->data,
+                  txb->fragments[0]->len);
+
+       packet->jiffy_start = jiffies;
+
+       list_del(element);
+       DEC_STAT(&priv->tx_free_stat);
+
+       list_add_tail(element, &priv->tx_pend_list);
+       INC_STAT(&priv->tx_pend_stat);
+
+       ipw2100_tx_send_data(priv);
+
+       spin_unlock_irqrestore(&priv->low_lock, flags);
+       return 0;
+
+ fail_unlock:
+       netif_stop_queue(dev);
+       spin_unlock_irqrestore(&priv->low_lock, flags);
+       return 1;
+}
+
+
+static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
+{
+       int i, j, err = -EINVAL;
+       void *v;
+       dma_addr_t p;
+
+       priv->msg_buffers = (struct ipw2100_tx_packet *)kmalloc(
+               IPW_COMMAND_POOL_SIZE * sizeof(struct ipw2100_tx_packet),
+               GFP_KERNEL);
+       if (!priv->msg_buffers) {
+               printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for msg "
+                      "buffers.\n", priv->net_dev->name);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
+               v = pci_alloc_consistent(
+                       priv->pci_dev,
+                       sizeof(struct ipw2100_cmd_header),
+                       &p);
+               if (!v) {
+                       printk(KERN_ERR DRV_NAME ": "
+                              "%s: PCI alloc failed for msg "
+                              "buffers.\n",
+                              priv->net_dev->name);
+                       err = -ENOMEM;
+                       break;
+               }
+
+               memset(v, 0, sizeof(struct ipw2100_cmd_header));
+
+               priv->msg_buffers[i].type = COMMAND;
+               priv->msg_buffers[i].info.c_struct.cmd =
+                       (struct ipw2100_cmd_header*)v;
+               priv->msg_buffers[i].info.c_struct.cmd_phys = p;
+       }
+
+       if (i == IPW_COMMAND_POOL_SIZE)
+               return 0;
+
+       for (j = 0; j < i; j++) {
+               pci_free_consistent(
+                       priv->pci_dev,
+                       sizeof(struct ipw2100_cmd_header),
+                       priv->msg_buffers[j].info.c_struct.cmd,
+                       priv->msg_buffers[j].info.c_struct.cmd_phys);
+       }
+
+       kfree(priv->msg_buffers);
+       priv->msg_buffers = NULL;
+
+       return err;
+}
+
+static int ipw2100_msg_initialize(struct ipw2100_priv *priv)
+{
+       int i;
+
+       INIT_LIST_HEAD(&priv->msg_free_list);
+       INIT_LIST_HEAD(&priv->msg_pend_list);
+
+       for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++)
+               list_add_tail(&priv->msg_buffers[i].list, &priv->msg_free_list);
+       SET_STAT(&priv->msg_free_stat, i);
+
+       return 0;
+}
+
+static void ipw2100_msg_free(struct ipw2100_priv *priv)
+{
+       int i;
+
+       if (!priv->msg_buffers)
+               return;
+
+       for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
+               pci_free_consistent(priv->pci_dev,
+                                   sizeof(struct ipw2100_cmd_header),
+                                   priv->msg_buffers[i].info.c_struct.cmd,
+                                   priv->msg_buffers[i].info.c_struct.cmd_phys);
+       }
+
+       kfree(priv->msg_buffers);
+       priv->msg_buffers = NULL;
+}
+
+static ssize_t show_pci(struct device *d, struct device_attribute *attr,
+                       char *buf)
+{
+       struct pci_dev *pci_dev = container_of(d, struct pci_dev, dev);
+       char *out = buf;
+       int i, j;
+       u32 val;
+
+       for (i = 0; i < 16; i++) {
+               out += sprintf(out, "[%08X] ", i * 16);
+               for (j = 0; j < 16; j += 4) {
+                       pci_read_config_dword(pci_dev, i * 16 + j, &val);
+                       out += sprintf(out, "%08X ", val);
+               }
+               out += sprintf(out, "\n");
+       }
+
+       return out - buf;
+}
+static DEVICE_ATTR(pci, S_IRUGO, show_pci, NULL);
+
+static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
+                       char *buf)
+{
+       struct ipw2100_priv *p = d->driver_data;
+       return sprintf(buf, "0x%08x\n", (int)p->config);
+}
+static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL);
+
+static ssize_t show_status(struct device *d, struct device_attribute *attr,
+                       char *buf)
+{
+       struct ipw2100_priv *p = d->driver_data;
+       return sprintf(buf, "0x%08x\n", (int)p->status);
+}
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+
+static ssize_t show_capability(struct device *d, struct device_attribute *attr,
+                               char *buf)
+{
+       struct ipw2100_priv *p = d->driver_data;
+       return sprintf(buf, "0x%08x\n", (int)p->capability);
+}
+static DEVICE_ATTR(capability, S_IRUGO, show_capability, NULL);
+
+
+#define IPW2100_REG(x) { IPW_ ##x, #x }
+static const struct {
+       u32 addr;
+       const char *name;
+} hw_data[] = {
+       IPW2100_REG(REG_GP_CNTRL),
+       IPW2100_REG(REG_GPIO),
+       IPW2100_REG(REG_INTA),
+       IPW2100_REG(REG_INTA_MASK),
+       IPW2100_REG(REG_RESET_REG),
+};
+#define IPW2100_NIC(x, s) { x, #x, s }
+static const struct {
+       u32 addr;
+       const char *name;
+       size_t size;
+} nic_data[] = {
+       IPW2100_NIC(IPW2100_CONTROL_REG, 2),
+       IPW2100_NIC(0x210014, 1),
+       IPW2100_NIC(0x210000, 1),
+};
+#define IPW2100_ORD(x, d) { IPW_ORD_ ##x, #x, d }
+static const struct {
+       u8 index;
+       const char *name;
+       const char *desc;
+} ord_data[] = {
+       IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"),
+       IPW2100_ORD(STAT_TX_HOST_COMPLETE, "successful Host Tx's (MSDU)"),
+       IPW2100_ORD(STAT_TX_DIR_DATA,      "successful Directed Tx's (MSDU)"),
+       IPW2100_ORD(STAT_TX_DIR_DATA1,     "successful Directed Tx's (MSDU) @ 1MB"),
+       IPW2100_ORD(STAT_TX_DIR_DATA2,     "successful Directed Tx's (MSDU) @ 2MB"),
+       IPW2100_ORD(STAT_TX_DIR_DATA5_5,   "successful Directed Tx's (MSDU) @ 5_5MB"),
+       IPW2100_ORD(STAT_TX_DIR_DATA11,    "successful Directed Tx's (MSDU) @ 11MB"),
+       IPW2100_ORD(STAT_TX_NODIR_DATA1,   "successful Non_Directed Tx's (MSDU) @ 1MB"),
+       IPW2100_ORD(STAT_TX_NODIR_DATA2,   "successful Non_Directed Tx's (MSDU) @ 2MB"),
+       IPW2100_ORD(STAT_TX_NODIR_DATA5_5, "successful Non_Directed Tx's (MSDU) @ 5.5MB"),
+       IPW2100_ORD(STAT_TX_NODIR_DATA11,  "successful Non_Directed Tx's (MSDU) @ 11MB"),
+       IPW2100_ORD(STAT_NULL_DATA,        "successful NULL data Tx's"),
+       IPW2100_ORD(STAT_TX_RTS,           "successful Tx RTS"),
+       IPW2100_ORD(STAT_TX_CTS,           "successful Tx CTS"),
+       IPW2100_ORD(STAT_TX_ACK,           "successful Tx ACK"),
+       IPW2100_ORD(STAT_TX_ASSN,          "successful Association Tx's"),
+       IPW2100_ORD(STAT_TX_ASSN_RESP,     "successful Association response Tx's"),
+       IPW2100_ORD(STAT_TX_REASSN,        "successful Reassociation Tx's"),
+       IPW2100_ORD(STAT_TX_REASSN_RESP,   "successful Reassociation response Tx's"),
+       IPW2100_ORD(STAT_TX_PROBE,         "probes successfully transmitted"),
+       IPW2100_ORD(STAT_TX_PROBE_RESP,    "probe responses successfully transmitted"),
+       IPW2100_ORD(STAT_TX_BEACON,        "tx beacon"),
+       IPW2100_ORD(STAT_TX_ATIM,          "Tx ATIM"),
+       IPW2100_ORD(STAT_TX_DISASSN,       "successful Disassociation TX"),
+       IPW2100_ORD(STAT_TX_AUTH,          "successful Authentication Tx"),
+       IPW2100_ORD(STAT_TX_DEAUTH,        "successful Deauthentication TX"),
+       IPW2100_ORD(STAT_TX_TOTAL_BYTES,   "Total successful Tx data bytes"),
+       IPW2100_ORD(STAT_TX_RETRIES,       "Tx retries"),
+       IPW2100_ORD(STAT_TX_RETRY1,        "Tx retries at 1MBPS"),
+       IPW2100_ORD(STAT_TX_RETRY2,        "Tx retries at 2MBPS"),
+       IPW2100_ORD(STAT_TX_RETRY5_5,      "Tx retries at 5.5MBPS"),
+       IPW2100_ORD(STAT_TX_RETRY11,       "Tx retries at 11MBPS"),
+       IPW2100_ORD(STAT_TX_FAILURES,      "Tx Failures"),
+       IPW2100_ORD(STAT_TX_MAX_TRIES_IN_HOP,"times max tries in a hop failed"),
+       IPW2100_ORD(STAT_TX_DISASSN_FAIL,       "times disassociation failed"),
+       IPW2100_ORD(STAT_TX_ERR_CTS,         "missed/bad CTS frames"),
+       IPW2100_ORD(STAT_TX_ERR_ACK,    "tx err due to acks"),
+       IPW2100_ORD(STAT_RX_HOST,       "packets passed to host"),
+       IPW2100_ORD(STAT_RX_DIR_DATA,   "directed packets"),
+       IPW2100_ORD(STAT_RX_DIR_DATA1,  "directed packets at 1MB"),
+       IPW2100_ORD(STAT_RX_DIR_DATA2,  "directed packets at 2MB"),
+       IPW2100_ORD(STAT_RX_DIR_DATA5_5,        "directed packets at 5.5MB"),
+       IPW2100_ORD(STAT_RX_DIR_DATA11, "directed packets at 11MB"),
+       IPW2100_ORD(STAT_RX_NODIR_DATA,"nondirected packets"),
+       IPW2100_ORD(STAT_RX_NODIR_DATA1,        "nondirected packets at 1MB"),
+       IPW2100_ORD(STAT_RX_NODIR_DATA2,        "nondirected packets at 2MB"),
+       IPW2100_ORD(STAT_RX_NODIR_DATA5_5,      "nondirected packets at 5.5MB"),
+       IPW2100_ORD(STAT_RX_NODIR_DATA11,       "nondirected packets at 11MB"),
+       IPW2100_ORD(STAT_RX_NULL_DATA,  "null data rx's"),
+       IPW2100_ORD(STAT_RX_RTS,        "Rx RTS"),
+       IPW2100_ORD(STAT_RX_CTS,        "Rx CTS"),
+       IPW2100_ORD(STAT_RX_ACK,        "Rx ACK"),
+       IPW2100_ORD(STAT_RX_CFEND,      "Rx CF End"),
+       IPW2100_ORD(STAT_RX_CFEND_ACK,  "Rx CF End + CF Ack"),
+       IPW2100_ORD(STAT_RX_ASSN,       "Association Rx's"),
+       IPW2100_ORD(STAT_RX_ASSN_RESP,  "Association response Rx's"),
+       IPW2100_ORD(STAT_RX_REASSN,     "Reassociation Rx's"),
+       IPW2100_ORD(STAT_RX_REASSN_RESP,        "Reassociation response Rx's"),
+       IPW2100_ORD(STAT_RX_PROBE,      "probe Rx's"),
+       IPW2100_ORD(STAT_RX_PROBE_RESP, "probe response Rx's"),
+       IPW2100_ORD(STAT_RX_BEACON,     "Rx beacon"),
+       IPW2100_ORD(STAT_RX_ATIM,       "Rx ATIM"),
+       IPW2100_ORD(STAT_RX_DISASSN,    "disassociation Rx"),
+       IPW2100_ORD(STAT_RX_AUTH,       "authentication Rx"),
+       IPW2100_ORD(STAT_RX_DEAUTH,     "deauthentication Rx"),
+       IPW2100_ORD(STAT_RX_TOTAL_BYTES,"Total rx data bytes received"),
+       IPW2100_ORD(STAT_RX_ERR_CRC,     "packets with Rx CRC error"),
+       IPW2100_ORD(STAT_RX_ERR_CRC1,    "Rx CRC errors at 1MB"),
+       IPW2100_ORD(STAT_RX_ERR_CRC2,    "Rx CRC errors at 2MB"),
+       IPW2100_ORD(STAT_RX_ERR_CRC5_5,  "Rx CRC errors at 5.5MB"),
+       IPW2100_ORD(STAT_RX_ERR_CRC11,   "Rx CRC errors at 11MB"),
+       IPW2100_ORD(STAT_RX_DUPLICATE1, "duplicate rx packets at 1MB"),
+       IPW2100_ORD(STAT_RX_DUPLICATE2,  "duplicate rx packets at 2MB"),
+       IPW2100_ORD(STAT_RX_DUPLICATE5_5,        "duplicate rx packets at 5.5MB"),
+       IPW2100_ORD(STAT_RX_DUPLICATE11,         "duplicate rx packets at 11MB"),
+       IPW2100_ORD(STAT_RX_DUPLICATE, "duplicate rx packets"),
+       IPW2100_ORD(PERS_DB_LOCK,       "locking fw permanent  db"),
+       IPW2100_ORD(PERS_DB_SIZE,       "size of fw permanent  db"),
+       IPW2100_ORD(PERS_DB_ADDR,       "address of fw permanent  db"),
+       IPW2100_ORD(STAT_RX_INVALID_PROTOCOL,   "rx frames with invalid protocol"),
+       IPW2100_ORD(SYS_BOOT_TIME,      "Boot time"),
+       IPW2100_ORD(STAT_RX_NO_BUFFER,  "rx frames rejected due to no buffer"),
+       IPW2100_ORD(STAT_RX_MISSING_FRAG,       "rx frames dropped due to missing fragment"),
+       IPW2100_ORD(STAT_RX_ORPHAN_FRAG,        "rx frames dropped due to non-sequential fragment"),
+       IPW2100_ORD(STAT_RX_ORPHAN_FRAME,       "rx frames dropped due to unmatched 1st frame"),
+       IPW2100_ORD(STAT_RX_FRAG_AGEOUT,        "rx frames dropped due to uncompleted frame"),
+       IPW2100_ORD(STAT_RX_ICV_ERRORS, "ICV errors during decryption"),
+       IPW2100_ORD(STAT_PSP_SUSPENSION,"times adapter suspended"),
+       IPW2100_ORD(STAT_PSP_BCN_TIMEOUT,       "beacon timeout"),
+       IPW2100_ORD(STAT_PSP_POLL_TIMEOUT,      "poll response timeouts"),
+       IPW2100_ORD(STAT_PSP_NONDIR_TIMEOUT, "timeouts waiting for last {broad,multi}cast pkt"),
+       IPW2100_ORD(STAT_PSP_RX_DTIMS,  "PSP DTIMs received"),
+       IPW2100_ORD(STAT_PSP_RX_TIMS,   "PSP TIMs received"),
+       IPW2100_ORD(STAT_PSP_STATION_ID,"PSP Station ID"),
+       IPW2100_ORD(LAST_ASSN_TIME,     "RTC time of last association"),
+       IPW2100_ORD(STAT_PERCENT_MISSED_BCNS,"current calculation of % missed beacons"),
+       IPW2100_ORD(STAT_PERCENT_RETRIES,"current calculation of % missed tx retries"),
+       IPW2100_ORD(ASSOCIATED_AP_PTR,  "0 if not associated, else pointer to AP table entry"),
+       IPW2100_ORD(AVAILABLE_AP_CNT,   "AP's decsribed in the AP table"),
+       IPW2100_ORD(AP_LIST_PTR,        "Ptr to list of available APs"),
+       IPW2100_ORD(STAT_AP_ASSNS,      "associations"),
+       IPW2100_ORD(STAT_ASSN_FAIL,     "association failures"),
+       IPW2100_ORD(STAT_ASSN_RESP_FAIL,"failures due to response fail"),
+       IPW2100_ORD(STAT_FULL_SCANS,    "full scans"),
+       IPW2100_ORD(CARD_DISABLED,      "Card Disabled"),
+       IPW2100_ORD(STAT_ROAM_INHIBIT,  "times roaming was inhibited due to activity"),
+       IPW2100_ORD(RSSI_AT_ASSN,       "RSSI of associated AP at time of association"),
+       IPW2100_ORD(STAT_ASSN_CAUSE1,   "reassociation: no probe response or TX on hop"),
+       IPW2100_ORD(STAT_ASSN_CAUSE2,   "reassociation: poor tx/rx quality"),
+       IPW2100_ORD(STAT_ASSN_CAUSE3,   "reassociation: tx/rx quality (excessive AP load"),
+       IPW2100_ORD(STAT_ASSN_CAUSE4,   "reassociation: AP RSSI level"),
+       IPW2100_ORD(STAT_ASSN_CAUSE5,   "reassociations due to load leveling"),
+       IPW2100_ORD(STAT_AUTH_FAIL,     "times authentication failed"),
+       IPW2100_ORD(STAT_AUTH_RESP_FAIL,"times authentication response failed"),
+       IPW2100_ORD(STATION_TABLE_CNT,  "entries in association table"),
+       IPW2100_ORD(RSSI_AVG_CURR,      "Current avg RSSI"),
+       IPW2100_ORD(POWER_MGMT_MODE,    "Power mode - 0=CAM, 1=PSP"),
+       IPW2100_ORD(COUNTRY_CODE,       "IEEE country code as recv'd from beacon"),
+       IPW2100_ORD(COUNTRY_CHANNELS,   "channels suported by country"),
+       IPW2100_ORD(RESET_CNT,  "adapter resets (warm)"),
+       IPW2100_ORD(BEACON_INTERVAL,    "Beacon interval"),
+       IPW2100_ORD(ANTENNA_DIVERSITY,  "TRUE if antenna diversity is disabled"),
+       IPW2100_ORD(DTIM_PERIOD,        "beacon intervals between DTIMs"),
+       IPW2100_ORD(OUR_FREQ,   "current radio freq lower digits - channel ID"),
+       IPW2100_ORD(RTC_TIME,   "current RTC time"),
+       IPW2100_ORD(PORT_TYPE,  "operating mode"),
+       IPW2100_ORD(CURRENT_TX_RATE,    "current tx rate"),
+       IPW2100_ORD(SUPPORTED_RATES,    "supported tx rates"),
+       IPW2100_ORD(ATIM_WINDOW,        "current ATIM Window"),
+       IPW2100_ORD(BASIC_RATES,        "basic tx rates"),
+       IPW2100_ORD(NIC_HIGHEST_RATE,   "NIC highest tx rate"),
+       IPW2100_ORD(AP_HIGHEST_RATE,    "AP highest tx rate"),
+       IPW2100_ORD(CAPABILITIES,       "Management frame capability field"),
+       IPW2100_ORD(AUTH_TYPE,  "Type of authentication"),
+       IPW2100_ORD(RADIO_TYPE, "Adapter card platform type"),
+       IPW2100_ORD(RTS_THRESHOLD,      "Min packet length for RTS handshaking"),
+       IPW2100_ORD(INT_MODE,   "International mode"),
+       IPW2100_ORD(FRAGMENTATION_THRESHOLD,    "protocol frag threshold"),
+       IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_START_ADDRESS, "EEPROM offset in SRAM"),
+       IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_SIZE,  "EEPROM size in SRAM"),
+       IPW2100_ORD(EEPROM_SKU_CAPABILITY,      "EEPROM SKU Capability"),
+       IPW2100_ORD(EEPROM_IBSS_11B_CHANNELS,   "EEPROM IBSS 11b channel set"),
+       IPW2100_ORD(MAC_VERSION,        "MAC Version"),
+       IPW2100_ORD(MAC_REVISION,       "MAC Revision"),
+       IPW2100_ORD(RADIO_VERSION,      "Radio Version"),
+       IPW2100_ORD(NIC_MANF_DATE_TIME, "MANF Date/Time STAMP"),
+       IPW2100_ORD(UCODE_VERSION,      "Ucode Version"),
+};
+
+
+static ssize_t show_registers(struct device *d, struct device_attribute *attr,
+                               char *buf)
+{
+       int i;
+       struct ipw2100_priv *priv = dev_get_drvdata(d);
+       struct net_device *dev = priv->net_dev;
+       char * out = buf;
+       u32 val = 0;
+
+       out += sprintf(out, "%30s [Address ] : Hex\n", "Register");
+
+       for (i = 0; i < (sizeof(hw_data) / sizeof(*hw_data)); i++) {
+               read_register(dev, hw_data[i].addr, &val);
+               out += sprintf(out, "%30s [%08X] : %08X\n",
+                              hw_data[i].name, hw_data[i].addr, val);
+       }
+
+       return out - buf;
+}
+static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL);
+
+
+static ssize_t show_hardware(struct device *d, struct device_attribute *attr,
+                               char *buf)
+{
+       struct ipw2100_priv *priv = dev_get_drvdata(d);
+       struct net_device *dev = priv->net_dev;
+       char * out = buf;
+       int i;
+
+       out += sprintf(out, "%30s [Address ] : Hex\n", "NIC entry");
+
+       for (i = 0; i < (sizeof(nic_data) / sizeof(*nic_data)); i++) {
+               u8 tmp8;
+               u16 tmp16;
+               u32 tmp32;
+
+               switch (nic_data[i].size) {
+               case 1:
+                       read_nic_byte(dev, nic_data[i].addr, &tmp8);
+                       out += sprintf(out, "%30s [%08X] : %02X\n",
+                                      nic_data[i].name, nic_data[i].addr,
+                                      tmp8);
+                       break;
+               case 2:
+                       read_nic_word(dev, nic_data[i].addr, &tmp16);
+                       out += sprintf(out, "%30s [%08X] : %04X\n",
+                                      nic_data[i].name, nic_data[i].addr,
+                                      tmp16);
+                       break;
+               case 4:
+                       read_nic_dword(dev, nic_data[i].addr, &tmp32);
+                       out += sprintf(out, "%30s [%08X] : %08X\n",
+                                      nic_data[i].name, nic_data[i].addr,
+                                      tmp32);
+                       break;
+               }
+       }
+       return out - buf;
+}
+static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL);
+
+
+static ssize_t show_memory(struct device *d, struct device_attribute *attr,
+                               char *buf)
+{
+       struct ipw2100_priv *priv = dev_get_drvdata(d);
+       struct net_device *dev = priv->net_dev;
+       static unsigned long loop = 0;
+       int len = 0;
+       u32 buffer[4];
+       int i;
+       char line[81];
+
+       if (loop >= 0x30000)
+               loop = 0;
+
+       /* sysfs provides us PAGE_SIZE buffer */
+       while (len < PAGE_SIZE - 128 && loop < 0x30000) {
+
+               if (priv->snapshot[0]) for (i = 0; i < 4; i++)
+                       buffer[i] = *(u32 *)SNAPSHOT_ADDR(loop + i * 4);
+               else for (i = 0; i < 4; i++)
+                       read_nic_dword(dev, loop + i * 4, &buffer[i]);
+
+               if (priv->dump_raw)
+                       len += sprintf(buf + len,
+                                      "%c%c%c%c"
+                                      "%c%c%c%c"
+                                      "%c%c%c%c"
+                                      "%c%c%c%c",
+                                      ((u8*)buffer)[0x0],
+                                      ((u8*)buffer)[0x1],
+                                      ((u8*)buffer)[0x2],
+                                      ((u8*)buffer)[0x3],
+                                      ((u8*)buffer)[0x4],
+                                      ((u8*)buffer)[0x5],
+                                      ((u8*)buffer)[0x6],
+                                      ((u8*)buffer)[0x7],
+                                      ((u8*)buffer)[0x8],
+                                      ((u8*)buffer)[0x9],
+                                      ((u8*)buffer)[0xa],
+                                      ((u8*)buffer)[0xb],
+                                      ((u8*)buffer)[0xc],
+                                      ((u8*)buffer)[0xd],
+                                      ((u8*)buffer)[0xe],
+                                      ((u8*)buffer)[0xf]);
+               else
+                       len += sprintf(buf + len, "%s\n",
+                                      snprint_line(line, sizeof(line),
+                                                   (u8*)buffer, 16, loop));
+               loop += 16;
+       }
+
+       return len;
+}
+
+static ssize_t store_memory(struct device *d, struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct ipw2100_priv *priv = dev_get_drvdata(d);
+       struct net_device *dev = priv->net_dev;
+       const char *p = buf;
+
+       if (count < 1)
+               return count;
+
+       if (p[0] == '1' ||
+           (count >= 2 && tolower(p[0]) == 'o' && tolower(p[1]) == 'n')) {
+               IPW_DEBUG_INFO("%s: Setting memory dump to RAW mode.\n",
+                      dev->name);
+               priv->dump_raw = 1;
+
+       } else if (p[0] == '0' || (count >= 2 && tolower(p[0]) == 'o' &&
+                                 tolower(p[1]) == 'f')) {
+               IPW_DEBUG_INFO("%s: Setting memory dump to HEX mode.\n",
+                      dev->name);
+               priv->dump_raw = 0;
+
+       } else if (tolower(p[0]) == 'r') {
+               IPW_DEBUG_INFO("%s: Resetting firmware snapshot.\n",
+                      dev->name);
+               ipw2100_snapshot_free(priv);
+
+       } else
+               IPW_DEBUG_INFO("%s: Usage: 0|on = HEX, 1|off = RAW, "
+                      "reset = clear memory snapshot\n",
+                      dev->name);
+
+       return count;
+}
+static DEVICE_ATTR(memory, S_IWUSR|S_IRUGO, show_memory, store_memory);
+
+
+static ssize_t show_ordinals(struct device *d, struct device_attribute *attr,
+                               char *buf)
+{
+       struct ipw2100_priv *priv = dev_get_drvdata(d);
+       u32 val = 0;
+       int len = 0;
+       u32 val_len;
+       static int loop = 0;
+
+       if (loop >= sizeof(ord_data) / sizeof(*ord_data))
+               loop = 0;
+
+       /* sysfs provides us PAGE_SIZE buffer */
+       while (len < PAGE_SIZE - 128 &&
+              loop < (sizeof(ord_data) / sizeof(*ord_data))) {
+
+               val_len = sizeof(u32);
+
+               if (ipw2100_get_ordinal(priv, ord_data[loop].index, &val,
+                                       &val_len))
+                       len += sprintf(buf + len, "[0x%02X] = ERROR    %s\n",
+                                      ord_data[loop].index,
+                                      ord_data[loop].desc);
+               else
+                       len += sprintf(buf + len, "[0x%02X] = 0x%08X %s\n",
+                                      ord_data[loop].index, val,
+                                      ord_data[loop].desc);
+               loop++;
+       }
+
+       return len;
+}
+static DEVICE_ATTR(ordinals, S_IRUGO, show_ordinals, NULL);
+
+
+static ssize_t show_stats(struct device *d, struct device_attribute *attr,
+                               char *buf)
+{
+       struct ipw2100_priv *priv = dev_get_drvdata(d);
+       char * out = buf;
+
+       out += sprintf(out, "interrupts: %d {tx: %d, rx: %d, other: %d}\n",
+                      priv->interrupts, priv->tx_interrupts,
+                      priv->rx_interrupts, priv->inta_other);
+       out += sprintf(out, "firmware resets: %d\n", priv->resets);
+       out += sprintf(out, "firmware hangs: %d\n", priv->hangs);
+#ifdef CONFIG_IPW_DEBUG
+       out += sprintf(out, "packet mismatch image: %s\n",
+                      priv->snapshot[0] ? "YES" : "NO");
+#endif
+
+       return out - buf;
+}
+static DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL);
+
+
+static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode)
+{
+       int err;
+
+       if (mode == priv->ieee->iw_mode)
+               return 0;
+
+       err = ipw2100_disable_adapter(priv);
+       if (err) {
+               printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
+                      priv->net_dev->name, err);
+               return err;
+       }
+
+       switch (mode) {
+       case IW_MODE_INFRA:
+               priv->net_dev->type = ARPHRD_ETHER;
+               break;
+       case IW_MODE_ADHOC:
+               priv->net_dev->type = ARPHRD_ETHER;
+               break;
+#ifdef CONFIG_IPW2100_MONITOR
+       case IW_MODE_MONITOR:
+               priv->last_mode = priv->ieee->iw_mode;
+               priv->net_dev->type = ARPHRD_IEEE80211;
+               break;
+#endif /* CONFIG_IPW2100_MONITOR */
+       }
+
+       priv->ieee->iw_mode = mode;
+
+#ifdef CONFIG_PM
+        /* Indicate ipw2100_download_firmware download firmware
+        * from disk instead of memory. */
+       ipw2100_firmware.version = 0;
+#endif
+
+       printk(KERN_INFO "%s: Reseting on mode change.\n",
+               priv->net_dev->name);
+       priv->reset_backoff = 0;
+       schedule_reset(priv);
+
+       return 0;
+}
+
+static ssize_t show_internals(struct device *d, struct device_attribute *attr,
+                               char *buf)
+{
+       struct ipw2100_priv *priv = dev_get_drvdata(d);
+       int len = 0;
+
+#define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" # y "\n", priv-> x)
+
+       if (priv->status & STATUS_ASSOCIATED)
+               len += sprintf(buf + len, "connected: %lu\n",
+                              get_seconds() - priv->connect_start);
+       else
+               len += sprintf(buf + len, "not connected\n");
+
+       DUMP_VAR(ieee->crypt[priv->ieee->tx_keyidx], p);
+       DUMP_VAR(status, 08lx);
+       DUMP_VAR(config, 08lx);
+       DUMP_VAR(capability, 08lx);
+
+       len += sprintf(buf + len, "last_rtc: %lu\n", (unsigned long)priv->last_rtc);
+
+       DUMP_VAR(fatal_error, d);
+       DUMP_VAR(stop_hang_check, d);
+       DUMP_VAR(stop_rf_kill, d);
+       DUMP_VAR(messages_sent, d);
+
+       DUMP_VAR(tx_pend_stat.value, d);
+       DUMP_VAR(tx_pend_stat.hi, d);
+
+       DUMP_VAR(tx_free_stat.value, d);
+       DUMP_VAR(tx_free_stat.lo, d);
+
+       DUMP_VAR(msg_free_stat.value, d);
+       DUMP_VAR(msg_free_stat.lo, d);
+
+       DUMP_VAR(msg_pend_stat.value, d);
+       DUMP_VAR(msg_pend_stat.hi, d);
+
+       DUMP_VAR(fw_pend_stat.value, d);
+       DUMP_VAR(fw_pend_stat.hi, d);
+
+       DUMP_VAR(txq_stat.value, d);
+       DUMP_VAR(txq_stat.lo, d);
+
+       DUMP_VAR(ieee->scans, d);
+       DUMP_VAR(reset_backoff, d);
+
+       return len;
+}
+static DEVICE_ATTR(internals, S_IRUGO, show_internals, NULL);
+
+
+static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
+                               char *buf)
+{
+       struct ipw2100_priv *priv = dev_get_drvdata(d);
+       char essid[IW_ESSID_MAX_SIZE + 1];
+       u8 bssid[ETH_ALEN];
+       u32 chan = 0;
+       char * out = buf;
+       int length;
+       int ret;
+
+       memset(essid, 0, sizeof(essid));
+       memset(bssid, 0, sizeof(bssid));
+
+       length = IW_ESSID_MAX_SIZE;
+       ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID, essid, &length);
+       if (ret)
+               IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
+                              __LINE__);
+
+       length = sizeof(bssid);
+       ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
+                                 bssid, &length);
+       if (ret)
+               IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
+                              __LINE__);
+
+       length = sizeof(u32);
+       ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &length);
+       if (ret)
+               IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
+                              __LINE__);
+
+       out += sprintf(out, "ESSID: %s\n", essid);
+       out += sprintf(out, "BSSID:   %02x:%02x:%02x:%02x:%02x:%02x\n",
+                      bssid[0], bssid[1], bssid[2],
+                      bssid[3], bssid[4], bssid[5]);
+       out += sprintf(out, "Channel: %d\n", chan);
+
+       return out - buf;
+}
+static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL);
+
+
+#ifdef CONFIG_IPW_DEBUG
+static ssize_t show_debug_level(struct device_driver *d, char *buf)
+{
+       return sprintf(buf, "0x%08X\n", ipw2100_debug_level);
+}
+
+static ssize_t store_debug_level(struct device_driver *d, const char *buf,
+                                size_t count)
+{
+       char *p = (char *)buf;
+       u32 val;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+               p++;
+               if (p[0] == 'x' || p[0] == 'X')
+                       p++;
+               val = simple_strtoul(p, &p, 16);
+       } else
+               val = simple_strtoul(p, &p, 10);
+       if (p == buf)
+               IPW_DEBUG_INFO(DRV_NAME
+                      ": %s is not in hex or decimal form.\n", buf);
+       else
+               ipw2100_debug_level = val;
+
+       return strnlen(buf, count);
+}
+static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level,
+                  store_debug_level);
+#endif /* CONFIG_IPW_DEBUG */
+
+
+static ssize_t show_fatal_error(struct device *d,
+                       struct device_attribute *attr, char *buf)
+{
+       struct ipw2100_priv *priv = dev_get_drvdata(d);
+       char *out = buf;
+       int i;
+
+       if (priv->fatal_error)
+               out += sprintf(out, "0x%08X\n",
+                              priv->fatal_error);
+       else
+               out += sprintf(out, "0\n");
+
+       for (i = 1; i <= IPW2100_ERROR_QUEUE; i++) {
+               if (!priv->fatal_errors[(priv->fatal_index - i) %
+                                       IPW2100_ERROR_QUEUE])
+                       continue;
+
+               out += sprintf(out, "%d. 0x%08X\n", i,
+                              priv->fatal_errors[(priv->fatal_index - i) %
+                                                 IPW2100_ERROR_QUEUE]);
+       }
+
+       return out - buf;
+}
+
+static ssize_t store_fatal_error(struct device *d,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct ipw2100_priv *priv = dev_get_drvdata(d);
+       schedule_reset(priv);
+       return count;
+}
+static DEVICE_ATTR(fatal_error, S_IWUSR|S_IRUGO, show_fatal_error, store_fatal_error);
+
+
+static ssize_t show_scan_age(struct device *d, struct device_attribute *attr,
+                               char *buf)
+{
+       struct ipw2100_priv *priv = dev_get_drvdata(d);
+       return sprintf(buf, "%d\n", priv->ieee->scan_age);
+}
+
+static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct ipw2100_priv *priv = dev_get_drvdata(d);
+       struct net_device *dev = priv->net_dev;
+       char buffer[] = "00000000";
+       unsigned long len =
+           (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1;
+       unsigned long val;
+       char *p = buffer;
+
+       IPW_DEBUG_INFO("enter\n");
+
+       strncpy(buffer, buf, len);
+       buffer[len] = 0;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+               p++;
+               if (p[0] == 'x' || p[0] == 'X')
+                       p++;
+               val = simple_strtoul(p, &p, 16);
+       } else
+               val = simple_strtoul(p, &p, 10);
+       if (p == buffer) {
+               IPW_DEBUG_INFO("%s: user supplied invalid value.\n",
+                      dev->name);
+       } else {
+               priv->ieee->scan_age = val;
+               IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age);
+       }
+
+       IPW_DEBUG_INFO("exit\n");
+       return len;
+}
+static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age);
+
+
+static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr,
+                               char *buf)
+{
+       /* 0 - RF kill not enabled
+          1 - SW based RF kill active (sysfs)
+          2 - HW based RF kill active
+          3 - Both HW and SW baed RF kill active */
+       struct ipw2100_priv *priv = (struct ipw2100_priv *)d->driver_data;
+       int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) |
+               (rf_kill_active(priv) ? 0x2 : 0x0);
+       return sprintf(buf, "%i\n", val);
+}
+
+static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio)
+{
+       if ((disable_radio ? 1 : 0) ==
+           (priv->status & STATUS_RF_KILL_SW ? 1 : 0))
+               return 0 ;
+
+       IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO  %s\n",
+                         disable_radio ? "OFF" : "ON");
+
+       down(&priv->action_sem);
+
+       if (disable_radio) {
+               priv->status |= STATUS_RF_KILL_SW;
+               ipw2100_down(priv);
+       } else {
+               priv->status &= ~STATUS_RF_KILL_SW;
+               if (rf_kill_active(priv)) {
+                       IPW_DEBUG_RF_KILL("Can not turn radio back on - "
+                                         "disabled by HW switch\n");
+                       /* Make sure the RF_KILL check timer is running */
+                       priv->stop_rf_kill = 0;
+                       cancel_delayed_work(&priv->rf_kill);
+                       queue_delayed_work(priv->workqueue, &priv->rf_kill,
+                                          HZ);
+               } else
+                       schedule_reset(priv);
+       }
+
+       up(&priv->action_sem);
+       return 1;
+}
+
+static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct ipw2100_priv *priv = dev_get_drvdata(d);
+       ipw_radio_kill_sw(priv, buf[0] == '1');
+       return count;
+}
+static DEVICE_ATTR(rf_kill, S_IWUSR|S_IRUGO, show_rf_kill, store_rf_kill);
+
+
+static struct attribute *ipw2100_sysfs_entries[] = {
+       &dev_attr_hardware.attr,
+       &dev_attr_registers.attr,
+       &dev_attr_ordinals.attr,
+       &dev_attr_pci.attr,
+       &dev_attr_stats.attr,
+       &dev_attr_internals.attr,
+       &dev_attr_bssinfo.attr,
+       &dev_attr_memory.attr,
+       &dev_attr_scan_age.attr,
+       &dev_attr_fatal_error.attr,
+       &dev_attr_rf_kill.attr,
+       &dev_attr_cfg.attr,
+       &dev_attr_status.attr,
+       &dev_attr_capability.attr,
+       NULL,
+};
+
+static struct attribute_group ipw2100_attribute_group = {
+       .attrs = ipw2100_sysfs_entries,
+};
+
+
+static int status_queue_allocate(struct ipw2100_priv *priv, int entries)
+{
+       struct ipw2100_status_queue *q = &priv->status_queue;
+
+       IPW_DEBUG_INFO("enter\n");
+
+       q->size = entries * sizeof(struct ipw2100_status);
+       q->drv = (struct ipw2100_status *)pci_alloc_consistent(
+               priv->pci_dev, q->size, &q->nic);
+       if (!q->drv) {
+               IPW_DEBUG_WARNING(
+                      "Can not allocate status queue.\n");
+               return -ENOMEM;
+       }
+
+       memset(q->drv, 0, q->size);
+
+       IPW_DEBUG_INFO("exit\n");
+
+       return 0;
+}
+
+static void status_queue_free(struct ipw2100_priv *priv)
+{
+       IPW_DEBUG_INFO("enter\n");
+
+       if (priv->status_queue.drv) {
+               pci_free_consistent(
+                       priv->pci_dev, priv->status_queue.size,
+                       priv->status_queue.drv, priv->status_queue.nic);
+               priv->status_queue.drv = NULL;
+       }
+
+       IPW_DEBUG_INFO("exit\n");
+}
+
+static int bd_queue_allocate(struct ipw2100_priv *priv,
+                            struct ipw2100_bd_queue *q, int entries)
+{
+       IPW_DEBUG_INFO("enter\n");
+
+       memset(q, 0, sizeof(struct ipw2100_bd_queue));
+
+       q->entries = entries;
+       q->size = entries * sizeof(struct ipw2100_bd);
+       q->drv = pci_alloc_consistent(priv->pci_dev, q->size, &q->nic);
+       if (!q->drv) {
+               IPW_DEBUG_INFO("can't allocate shared memory for buffer descriptors\n");
+               return -ENOMEM;
+       }
+       memset(q->drv, 0, q->size);
+
+       IPW_DEBUG_INFO("exit\n");
+
+       return 0;
+}
+
+static void bd_queue_free(struct ipw2100_priv *priv,
+                         struct ipw2100_bd_queue *q)
+{
+       IPW_DEBUG_INFO("enter\n");
+
+       if (!q)
+               return;
+
+       if (q->drv) {
+               pci_free_consistent(priv->pci_dev,
+                                   q->size, q->drv, q->nic);
+               q->drv = NULL;
+       }
+
+       IPW_DEBUG_INFO("exit\n");
+}
+
+static void bd_queue_initialize(
+       struct ipw2100_priv *priv, struct ipw2100_bd_queue * q,
+       u32 base, u32 size, u32 r, u32 w)
+{
+       IPW_DEBUG_INFO("enter\n");
+
+       IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv, (u32)q->nic);
+
+       write_register(priv->net_dev, base, q->nic);
+       write_register(priv->net_dev, size, q->entries);
+       write_register(priv->net_dev, r, q->oldest);
+       write_register(priv->net_dev, w, q->next);
+
+       IPW_DEBUG_INFO("exit\n");
+}
+
+static void ipw2100_kill_workqueue(struct ipw2100_priv *priv)
+{
+       if (priv->workqueue) {
+               priv->stop_rf_kill = 1;
+               priv->stop_hang_check = 1;
+               cancel_delayed_work(&priv->reset_work);
+               cancel_delayed_work(&priv->security_work);
+               cancel_delayed_work(&priv->wx_event_work);
+               cancel_delayed_work(&priv->hang_check);
+               cancel_delayed_work(&priv->rf_kill);
+               destroy_workqueue(priv->workqueue);
+               priv->workqueue = NULL;
+       }
+}
+
+static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
+{
+       int i, j, err = -EINVAL;
+       void *v;
+       dma_addr_t p;
+
+       IPW_DEBUG_INFO("enter\n");
+
+       err = bd_queue_allocate(priv, &priv->tx_queue, TX_QUEUE_LENGTH);
+       if (err) {
+               IPW_DEBUG_ERROR("%s: failed bd_queue_allocate\n",
+                      priv->net_dev->name);
+               return err;
+       }
+
+       priv->tx_buffers = (struct ipw2100_tx_packet *)kmalloc(
+               TX_PENDED_QUEUE_LENGTH * sizeof(struct ipw2100_tx_packet),
+               GFP_ATOMIC);
+       if (!priv->tx_buffers) {
+               printk(KERN_ERR DRV_NAME ": %s: alloc failed form tx buffers.\n",
+                      priv->net_dev->name);
+               bd_queue_free(priv, &priv->tx_queue);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
+               v = pci_alloc_consistent(
+                       priv->pci_dev, sizeof(struct ipw2100_data_header), &p);
+               if (!v) {
+                       printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for tx "
+                              "buffers.\n", priv->net_dev->name);
+                       err = -ENOMEM;
+                       break;
+               }
+
+               priv->tx_buffers[i].type = DATA;
+               priv->tx_buffers[i].info.d_struct.data = (struct ipw2100_data_header*)v;
+               priv->tx_buffers[i].info.d_struct.data_phys = p;
+               priv->tx_buffers[i].info.d_struct.txb = NULL;
+       }
+
+       if (i == TX_PENDED_QUEUE_LENGTH)
+               return 0;
+
+       for (j = 0; j < i; j++) {
+               pci_free_consistent(
+                       priv->pci_dev,
+                       sizeof(struct ipw2100_data_header),
+                       priv->tx_buffers[j].info.d_struct.data,
+                       priv->tx_buffers[j].info.d_struct.data_phys);
+       }
+
+       kfree(priv->tx_buffers);
+       priv->tx_buffers = NULL;
+
+       return err;
+}
+
+static void ipw2100_tx_initialize(struct ipw2100_priv *priv)
+{
+       int i;
+
+       IPW_DEBUG_INFO("enter\n");
+
+       /*
+        * reinitialize packet info lists
+        */
+       INIT_LIST_HEAD(&priv->fw_pend_list);
+       INIT_STAT(&priv->fw_pend_stat);
+
+       /*
+        * reinitialize lists
+        */
+       INIT_LIST_HEAD(&priv->tx_pend_list);
+       INIT_LIST_HEAD(&priv->tx_free_list);
+       INIT_STAT(&priv->tx_pend_stat);
+       INIT_STAT(&priv->tx_free_stat);
+
+       for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
+               /* We simply drop any SKBs that have been queued for
+                * transmit */
+               if (priv->tx_buffers[i].info.d_struct.txb) {
+                       ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.txb);
+                       priv->tx_buffers[i].info.d_struct.txb = NULL;
+               }
+
+               list_add_tail(&priv->tx_buffers[i].list, &priv->tx_free_list);
+       }
+
+       SET_STAT(&priv->tx_free_stat, i);
+
+       priv->tx_queue.oldest = 0;
+       priv->tx_queue.available = priv->tx_queue.entries;
+       priv->tx_queue.next = 0;
+       INIT_STAT(&priv->txq_stat);
+       SET_STAT(&priv->txq_stat, priv->tx_queue.available);
+
+       bd_queue_initialize(priv, &priv->tx_queue,
+                           IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE,
+                           IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE,
+                           IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
+                           IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX);
+
+       IPW_DEBUG_INFO("exit\n");
+
+}
+
+static void ipw2100_tx_free(struct ipw2100_priv *priv)
+{
+       int i;
+
+       IPW_DEBUG_INFO("enter\n");
+
+       bd_queue_free(priv, &priv->tx_queue);
+
+       if (!priv->tx_buffers)
+               return;
+
+       for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
+               if (priv->tx_buffers[i].info.d_struct.txb) {
+                       ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.txb);
+                       priv->tx_buffers[i].info.d_struct.txb = NULL;
+               }
+               if (priv->tx_buffers[i].info.d_struct.data)
+                       pci_free_consistent(
+                               priv->pci_dev,
+                               sizeof(struct ipw2100_data_header),
+                               priv->tx_buffers[i].info.d_struct.data,
+                               priv->tx_buffers[i].info.d_struct.data_phys);
+       }
+
+       kfree(priv->tx_buffers);
+       priv->tx_buffers = NULL;
+
+       IPW_DEBUG_INFO("exit\n");
+}
+
+
+
+static int ipw2100_rx_allocate(struct ipw2100_priv *priv)
+{
+       int i, j, err = -EINVAL;
+
+       IPW_DEBUG_INFO("enter\n");
+
+       err = bd_queue_allocate(priv, &priv->rx_queue, RX_QUEUE_LENGTH);
+       if (err) {
+               IPW_DEBUG_INFO("failed bd_queue_allocate\n");
+               return err;
+       }
+
+       err = status_queue_allocate(priv, RX_QUEUE_LENGTH);
+       if (err) {
+               IPW_DEBUG_INFO("failed status_queue_allocate\n");
+               bd_queue_free(priv, &priv->rx_queue);
+               return err;
+       }
+
+       /*
+        * allocate packets
+        */
+       priv->rx_buffers = (struct ipw2100_rx_packet *)
+           kmalloc(RX_QUEUE_LENGTH * sizeof(struct ipw2100_rx_packet),
+                   GFP_KERNEL);
+       if (!priv->rx_buffers) {
+               IPW_DEBUG_INFO("can't allocate rx packet buffer table\n");
+
+               bd_queue_free(priv, &priv->rx_queue);
+
+               status_queue_free(priv);
+
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < RX_QUEUE_LENGTH; i++) {
+               struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
+
+               err = ipw2100_alloc_skb(priv, packet);
+               if (unlikely(err)) {
+                       err = -ENOMEM;
+                       break;
+               }
+
+               /* The BD holds the cache aligned address */
+               priv->rx_queue.drv[i].host_addr = packet->dma_addr;
+               priv->rx_queue.drv[i].buf_length = IPW_RX_NIC_BUFFER_LENGTH;
+               priv->status_queue.drv[i].status_fields = 0;
+       }
+
+       if (i == RX_QUEUE_LENGTH)
+               return 0;
+
+       for (j = 0; j < i; j++) {
+               pci_unmap_single(priv->pci_dev, priv->rx_buffers[j].dma_addr,
+                                sizeof(struct ipw2100_rx_packet),
+                                PCI_DMA_FROMDEVICE);
+               dev_kfree_skb(priv->rx_buffers[j].skb);
+       }
+
+       kfree(priv->rx_buffers);
+       priv->rx_buffers = NULL;
+
+       bd_queue_free(priv, &priv->rx_queue);
+
+       status_queue_free(priv);
+
+       return err;
+}
+
+static void ipw2100_rx_initialize(struct ipw2100_priv *priv)
+{
+       IPW_DEBUG_INFO("enter\n");
+
+       priv->rx_queue.oldest = 0;
+       priv->rx_queue.available = priv->rx_queue.entries - 1;
+       priv->rx_queue.next = priv->rx_queue.entries - 1;
+
+       INIT_STAT(&priv->rxq_stat);
+       SET_STAT(&priv->rxq_stat, priv->rx_queue.available);
+
+       bd_queue_initialize(priv, &priv->rx_queue,
+                           IPW_MEM_HOST_SHARED_RX_BD_BASE,
+                           IPW_MEM_HOST_SHARED_RX_BD_SIZE,
+                           IPW_MEM_HOST_SHARED_RX_READ_INDEX,
+                           IPW_MEM_HOST_SHARED_RX_WRITE_INDEX);
+
+       /* set up the status queue */
+       write_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_STATUS_BASE,
+                      priv->status_queue.nic);
+
+       IPW_DEBUG_INFO("exit\n");
+}
+
+static void ipw2100_rx_free(struct ipw2100_priv *priv)
+{
+       int i;
+
+       IPW_DEBUG_INFO("enter\n");
+
+       bd_queue_free(priv, &priv->rx_queue);
+       status_queue_free(priv);
+
+       if (!priv->rx_buffers)
+               return;
+
+       for (i = 0; i < RX_QUEUE_LENGTH; i++) {
+               if (priv->rx_buffers[i].rxp) {
+                       pci_unmap_single(priv->pci_dev,
+                                        priv->rx_buffers[i].dma_addr,
+                                        sizeof(struct ipw2100_rx),
+                                        PCI_DMA_FROMDEVICE);
+                       dev_kfree_skb(priv->rx_buffers[i].skb);
+               }
+       }
+
+       kfree(priv->rx_buffers);
+       priv->rx_buffers = NULL;
+
+       IPW_DEBUG_INFO("exit\n");
+}
+
+static int ipw2100_read_mac_address(struct ipw2100_priv *priv)
+{
+       u32 length = ETH_ALEN;
+       u8 mac[ETH_ALEN];
+
+       int err;
+
+       err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC,
+                                 mac, &length);
+       if (err) {
+               IPW_DEBUG_INFO("MAC address read failed\n");
+               return -EIO;
+       }
+       IPW_DEBUG_INFO("card MAC is %02X:%02X:%02X:%02X:%02X:%02X\n",
+              mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+       memcpy(priv->net_dev->dev_addr, mac, ETH_ALEN);
+
+       return 0;
+}
+
+/********************************************************************
+ *
+ * Firmware Commands
+ *
+ ********************************************************************/
+
+static int ipw2100_set_mac_address(struct ipw2100_priv *priv, int batch_mode)
+{
+       struct host_command cmd = {
+               .host_command = ADAPTER_ADDRESS,
+               .host_command_sequence = 0,
+               .host_command_length = ETH_ALEN
+       };
+       int err;
+
+       IPW_DEBUG_HC("SET_MAC_ADDRESS\n");
+
+       IPW_DEBUG_INFO("enter\n");
+
+       if (priv->config & CFG_CUSTOM_MAC) {
+               memcpy(cmd.host_command_parameters, priv->mac_addr,
+                      ETH_ALEN);
+               memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
+       } else
+               memcpy(cmd.host_command_parameters, priv->net_dev->dev_addr,
+                      ETH_ALEN);
+
+       err = ipw2100_hw_send_command(priv, &cmd);
+
+       IPW_DEBUG_INFO("exit\n");
+       return err;
+}
+
+static int ipw2100_set_port_type(struct ipw2100_priv *priv, u32 port_type,
+                                int batch_mode)
+{
+       struct host_command cmd = {
+               .host_command = PORT_TYPE,
+               .host_command_sequence = 0,
+               .host_command_length = sizeof(u32)
+       };
+       int err;
+
+       switch (port_type) {
+       case IW_MODE_INFRA:
+               cmd.host_command_parameters[0] = IPW_BSS;
+               break;
+       case IW_MODE_ADHOC:
+               cmd.host_command_parameters[0] = IPW_IBSS;
+               break;
+       }
+
+       IPW_DEBUG_HC("PORT_TYPE: %s\n",
+                    port_type == IPW_IBSS ? "Ad-Hoc" : "Managed");
+
+       if (!batch_mode) {
+               err = ipw2100_disable_adapter(priv);
+               if (err) {
+                       printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
+                              priv->net_dev->name, err);
+                       return err;
+               }
+       }
+
+       /* send cmd to firmware */
+       err = ipw2100_hw_send_command(priv, &cmd);
+
+       if (!batch_mode)
+               ipw2100_enable_adapter(priv);
+
+       return err;
+}
+
+
+static int ipw2100_set_channel(struct ipw2100_priv *priv, u32 channel,
+                              int batch_mode)
+{
+       struct host_command cmd = {
+               .host_command = CHANNEL,
+               .host_command_sequence = 0,
+               .host_command_length = sizeof(u32)
+       };
+       int err;
+
+       cmd.host_command_parameters[0] = channel;
+
+       IPW_DEBUG_HC("CHANNEL: %d\n", channel);
+
+       /* If BSS then we don't support channel selection */
+       if (priv->ieee->iw_mode == IW_MODE_INFRA)
+               return 0;
+
+       if ((channel != 0) &&
+           ((channel < REG_MIN_CHANNEL) || (channel > REG_MAX_CHANNEL)))
+               return -EINVAL;
+
+       if (!batch_mode) {
+               err = ipw2100_disable_adapter(priv);
+               if (err)
+                       return err;
+       }
+
+       err = ipw2100_hw_send_command(priv, &cmd);
+       if (err) {
+               IPW_DEBUG_INFO("Failed to set channel to %d",
+                              channel);
+               return err;
+       }
+
+       if (channel)
+               priv->config |= CFG_STATIC_CHANNEL;
+       else
+               priv->config &= ~CFG_STATIC_CHANNEL;
+
+       priv->channel = channel;
+
+       if (!batch_mode) {
+               err = ipw2100_enable_adapter(priv);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int ipw2100_system_config(struct ipw2100_priv *priv, int batch_mode)
+{
+       struct host_command cmd = {
+               .host_command = SYSTEM_CONFIG,
+               .host_command_sequence = 0,
+               .host_command_length = 12,
+       };
+       u32 ibss_mask, len = sizeof(u32);
+       int err;
+
+       /* Set system configuration */
+
+       if (!batch_mode) {
+               err = ipw2100_disable_adapter(priv);
+               if (err)
+                       return err;
+       }
+
+       if (priv->ieee->iw_mode == IW_MODE_ADHOC)
+               cmd.host_command_parameters[0] |= IPW_CFG_IBSS_AUTO_START;
+
+       cmd.host_command_parameters[0] |= IPW_CFG_IBSS_MASK |
+               IPW_CFG_BSS_MASK |
+               IPW_CFG_802_1x_ENABLE;
+
+       if (!(priv->config & CFG_LONG_PREAMBLE))
+               cmd.host_command_parameters[0] |= IPW_CFG_PREAMBLE_AUTO;
+
+       err = ipw2100_get_ordinal(priv,
+                                 IPW_ORD_EEPROM_IBSS_11B_CHANNELS,
+                                 &ibss_mask,  &len);
+       if (err)
+               ibss_mask = IPW_IBSS_11B_DEFAULT_MASK;
+
+       cmd.host_command_parameters[1] = REG_CHANNEL_MASK;
+       cmd.host_command_parameters[2] = REG_CHANNEL_MASK & ibss_mask;
+
+       /* 11b only */
+       /*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A;*/
+
+       err = ipw2100_hw_send_command(priv, &cmd);
+       if (err)
+               return err;
+
+/* If IPv6 is configured in the kernel then we don't want to filter out all
+ * of the multicast packets as IPv6 needs some. */
+#if !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE)
+       cmd.host_command = ADD_MULTICAST;
+       cmd.host_command_sequence = 0;
+       cmd.host_command_length = 0;
+
+       ipw2100_hw_send_command(priv, &cmd);
+#endif
+       if (!batch_mode) {
+               err = ipw2100_enable_adapter(priv);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int ipw2100_set_tx_rates(struct ipw2100_priv *priv, u32 rate,
+                               int batch_mode)
+{
+       struct host_command cmd = {
+               .host_command = BASIC_TX_RATES,
+               .host_command_sequence = 0,
+               .host_command_length = 4
+       };
+       int err;
+
+       cmd.host_command_parameters[0] = rate & TX_RATE_MASK;
+
+       if (!batch_mode) {
+               err = ipw2100_disable_adapter(priv);
+               if (err)
+                       return err;
+       }
+
+       /* Set BASIC TX Rate first */
+       ipw2100_hw_send_command(priv, &cmd);
+
+       /* Set TX Rate */
+       cmd.host_command = TX_RATES;
+       ipw2100_hw_send_command(priv, &cmd);
+
+       /* Set MSDU TX Rate */
+       cmd.host_command = MSDU_TX_RATES;
+       ipw2100_hw_send_command(priv, &cmd);
+
+       if (!batch_mode) {
+               err = ipw2100_enable_adapter(priv);
+               if (err)
+                       return err;
+       }
+
+       priv->tx_rates = rate;
+
+       return 0;
+}
+
+static int ipw2100_set_power_mode(struct ipw2100_priv *priv,
+                                 int power_level)
+{
+       struct host_command cmd = {
+               .host_command = POWER_MODE,
+               .host_command_sequence = 0,
+               .host_command_length = 4
+       };
+       int err;
+
+       cmd.host_command_parameters[0] = power_level;
+
+       err = ipw2100_hw_send_command(priv, &cmd);
+       if (err)
+               return err;
+
+       if (power_level == IPW_POWER_MODE_CAM)
+               priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
+       else
+               priv->power_mode = IPW_POWER_ENABLED | power_level;
+
+#ifdef CONFIG_IPW2100_TX_POWER
+       if (priv->port_type == IBSS &&
+           priv->adhoc_power != DFTL_IBSS_TX_POWER) {
+               /* Set beacon interval */
+               cmd.host_command = TX_POWER_INDEX;
+               cmd.host_command_parameters[0] = (u32)priv->adhoc_power;
+
+               err = ipw2100_hw_send_command(priv, &cmd);
+               if (err)
+                       return err;
+       }
+#endif
+
+       return 0;
+}
+
+
+static int ipw2100_set_rts_threshold(struct ipw2100_priv *priv, u32 threshold)
+{
+       struct host_command cmd = {
+               .host_command = RTS_THRESHOLD,
+               .host_command_sequence = 0,
+               .host_command_length = 4
+       };
+       int err;
+
+       if (threshold & RTS_DISABLED)
+               cmd.host_command_parameters[0] = MAX_RTS_THRESHOLD;
+       else
+               cmd.host_command_parameters[0] = threshold & ~RTS_DISABLED;
+
+       err = ipw2100_hw_send_command(priv, &cmd);
+       if (err)
+               return err;
+
+       priv->rts_threshold = threshold;
+
+       return 0;
+}
+
+#if 0
+int ipw2100_set_fragmentation_threshold(struct ipw2100_priv *priv,
+                                       u32 threshold, int batch_mode)
+{
+       struct host_command cmd = {
+               .host_command = FRAG_THRESHOLD,
+               .host_command_sequence = 0,
+               .host_command_length = 4,
+               .host_command_parameters[0] = 0,
+       };
+       int err;
+
+       if (!batch_mode) {
+               err = ipw2100_disable_adapter(priv);
+               if (err)
+                       return err;
+       }
+
+       if (threshold == 0)
+               threshold = DEFAULT_FRAG_THRESHOLD;
+       else {
+               threshold = max(threshold, MIN_FRAG_THRESHOLD);
+               threshold = min(threshold, MAX_FRAG_THRESHOLD);
+       }
+
+       cmd.host_command_parameters[0] = threshold;
+
+       IPW_DEBUG_HC("FRAG_THRESHOLD: %u\n", threshold);
+
+       err = ipw2100_hw_send_command(priv, &cmd);
+
+       if (!batch_mode)
+               ipw2100_enable_adapter(priv);
+
+       if (!err)
+               priv->frag_threshold = threshold;
+
+       return err;
+}
+#endif
+
+static int ipw2100_set_short_retry(struct ipw2100_priv *priv, u32 retry)
+{
+       struct host_command cmd = {
+               .host_command = SHORT_RETRY_LIMIT,
+               .host_command_sequence = 0,
+               .host_command_length = 4
+       };
+       int err;
+
+       cmd.host_command_parameters[0] = retry;
+
+       err = ipw2100_hw_send_command(priv, &cmd);
+       if (err)
+               return err;
+
+       priv->short_retry_limit = retry;
+
+       return 0;
+}
+
+static int ipw2100_set_long_retry(struct ipw2100_priv *priv, u32 retry)
+{
+       struct host_command cmd = {
+               .host_command = LONG_RETRY_LIMIT,
+               .host_command_sequence = 0,
+               .host_command_length = 4
+       };
+       int err;
+
+       cmd.host_command_parameters[0] = retry;
+
+       err = ipw2100_hw_send_command(priv, &cmd);
+       if (err)
+               return err;
+
+       priv->long_retry_limit = retry;
+
+       return 0;
+}
+
+
+static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 *bssid,
+                                      int batch_mode)
+{
+       struct host_command cmd = {
+               .host_command = MANDATORY_BSSID,
+               .host_command_sequence = 0,
+               .host_command_length = (bssid == NULL) ? 0 : ETH_ALEN
+       };
+       int err;
+
+#ifdef CONFIG_IPW_DEBUG
+       if (bssid != NULL)
+               IPW_DEBUG_HC(
+                       "MANDATORY_BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n",
+                       bssid[0], bssid[1], bssid[2], bssid[3], bssid[4],
+                       bssid[5]);
+       else
+               IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
+#endif
+       /* if BSSID is empty then we disable mandatory bssid mode */
+       if (bssid != NULL)
+               memcpy((u8 *)cmd.host_command_parameters, bssid, ETH_ALEN);
+
+       if (!batch_mode) {
+               err = ipw2100_disable_adapter(priv);
+               if (err)
+                       return err;
+       }
+
+       err = ipw2100_hw_send_command(priv, &cmd);
+
+       if (!batch_mode)
+               ipw2100_enable_adapter(priv);
+
+       return err;
+}
+
+#ifdef CONFIG_IEEE80211_WPA
+static int ipw2100_disassociate_bssid(struct ipw2100_priv *priv)
+{
+       struct host_command cmd = {
+               .host_command = DISASSOCIATION_BSSID,
+               .host_command_sequence = 0,
+               .host_command_length = ETH_ALEN
+       };
+       int err;
+       int len;
+
+       IPW_DEBUG_HC("DISASSOCIATION_BSSID\n");
+
+       len = ETH_ALEN;
+       /* The Firmware currently ignores the BSSID and just disassociates from
+        * the currently associated AP -- but in the off chance that a future
+        * firmware does use the BSSID provided here, we go ahead and try and
+        * set it to the currently associated AP's BSSID */
+       memcpy(cmd.host_command_parameters, priv->bssid, ETH_ALEN);
+
+       err = ipw2100_hw_send_command(priv, &cmd);
+
+       return err;
+}
+#endif
+
+/*
+ * Pseudo code for setting up wpa_frame:
+ */
+#if 0
+void x(struct ieee80211_assoc_frame *wpa_assoc)
+{
+       struct ipw2100_wpa_assoc_frame frame;
+       frame->fixed_ie_mask = IPW_WPA_CAPABILTIES |
+               IPW_WPA_LISTENINTERVAL |
+               IPW_WPA_AP_ADDRESS;
+       frame->capab_info = wpa_assoc->capab_info;
+       frame->lisen_interval = wpa_assoc->listent_interval;
+       memcpy(frame->current_ap, wpa_assoc->current_ap, ETH_ALEN);
+
+       /* UNKNOWN -- I'm not postivive about this part; don't have any WPA
+        * setup here to test it with.
+        *
+        * Walk the IEs in the wpa_assoc and figure out the total size of all
+        * that data.  Stick that into frame->var_ie_len.  Then memcpy() all of
+        * the IEs from wpa_frame into frame.
+        */
+       frame->var_ie_len = calculate_ie_len(wpa_assoc);
+       memcpy(frame->var_ie,  wpa_assoc->variable, frame->var_ie_len);
+
+       ipw2100_set_wpa_ie(priv, &frame, 0);
+}
+#endif
+
+
+
+
+static int ipw2100_set_wpa_ie(struct ipw2100_priv *,
+                             struct ipw2100_wpa_assoc_frame *, int)
+__attribute__ ((unused));
+
+static int ipw2100_set_wpa_ie(struct ipw2100_priv *priv,
+                             struct ipw2100_wpa_assoc_frame *wpa_frame,
+                             int batch_mode)
+{
+       struct host_command cmd = {
+               .host_command = SET_WPA_IE,
+               .host_command_sequence = 0,
+               .host_command_length = sizeof(struct ipw2100_wpa_assoc_frame),
+       };
+       int err;
+
+       IPW_DEBUG_HC("SET_WPA_IE\n");
+
+       if (!batch_mode) {
+               err = ipw2100_disable_adapter(priv);
+               if (err)
+                       return err;
+       }
+
+       memcpy(cmd.host_command_parameters, wpa_frame,
+              sizeof(struct ipw2100_wpa_assoc_frame));
+
+       err = ipw2100_hw_send_command(priv, &cmd);
+
+       if (!batch_mode) {
+               if (ipw2100_enable_adapter(priv))
+                       err = -EIO;
+       }
+
+       return err;
+}
+
+struct security_info_params {
+       u32 allowed_ciphers;
+       u16 version;
+       u8 auth_mode;
+       u8 replay_counters_number;
+       u8 unicast_using_group;
+} __attribute__ ((packed));
+
+static int ipw2100_set_security_information(struct ipw2100_priv *priv,
+                                           int auth_mode,
+                                           int security_level,
+                                           int unicast_using_group,
+                                           int batch_mode)
+{
+       struct host_command cmd = {
+               .host_command = SET_SECURITY_INFORMATION,
+               .host_command_sequence = 0,
+               .host_command_length = sizeof(struct security_info_params)
+       };
+       struct security_info_params *security =
+               (struct security_info_params *)&cmd.host_command_parameters;
+       int err;
+       memset(security, 0, sizeof(*security));
+
+       /* If shared key AP authentication is turned on, then we need to
+        * configure the firmware to try and use it.
+        *
+        * Actual data encryption/decryption is handled by the host. */
+       security->auth_mode = auth_mode;
+       security->unicast_using_group = unicast_using_group;
+
+       switch (security_level) {
+       default:
+       case SEC_LEVEL_0:
+               security->allowed_ciphers = IPW_NONE_CIPHER;
+               break;
+       case SEC_LEVEL_1:
+               security->allowed_ciphers = IPW_WEP40_CIPHER |
+                       IPW_WEP104_CIPHER;
+               break;
+       case SEC_LEVEL_2:
+               security->allowed_ciphers = IPW_WEP40_CIPHER |
+                       IPW_WEP104_CIPHER | IPW_TKIP_CIPHER;
+               break;
+       case SEC_LEVEL_2_CKIP:
+               security->allowed_ciphers = IPW_WEP40_CIPHER |
+                       IPW_WEP104_CIPHER | IPW_CKIP_CIPHER;
+               break;
+       case SEC_LEVEL_3:
+               security->allowed_ciphers = IPW_WEP40_CIPHER |
+                       IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER;
+               break;
+       }
+
+       IPW_DEBUG_HC(
+               "SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n",
+               security->auth_mode, security->allowed_ciphers, security_level);
+
+       security->replay_counters_number = 0;
+
+       if (!batch_mode) {
+               err = ipw2100_disable_adapter(priv);
+               if (err)
+                       return err;
+       }
+
+       err = ipw2100_hw_send_command(priv, &cmd);
+
+       if (!batch_mode)
+               ipw2100_enable_adapter(priv);
+
+       return err;
+}
+
+static int ipw2100_set_tx_power(struct ipw2100_priv *priv,
+                               u32 tx_power)
+{
+       struct host_command cmd = {
+               .host_command = TX_POWER_INDEX,
+               .host_command_sequence = 0,
+               .host_command_length = 4
+       };
+       int err = 0;
+
+       cmd.host_command_parameters[0] = tx_power;
+
+       if (priv->ieee->iw_mode == IW_MODE_ADHOC)
+               err = ipw2100_hw_send_command(priv, &cmd);
+       if (!err)
+               priv->tx_power = tx_power;
+
+       return 0;
+}
+
+static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv,
+                                           u32 interval, int batch_mode)
+{
+       struct host_command cmd = {
+               .host_command = BEACON_INTERVAL,
+               .host_command_sequence = 0,
+               .host_command_length = 4
+       };
+       int err;
+
+       cmd.host_command_parameters[0] = interval;
+
+       IPW_DEBUG_INFO("enter\n");
+
+       if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+               if (!batch_mode) {
+                       err = ipw2100_disable_adapter(priv);
+                       if (err)
+                               return err;
+               }
+
+               ipw2100_hw_send_command(priv, &cmd);
+
+               if (!batch_mode) {
+                       err = ipw2100_enable_adapter(priv);
+                       if (err)
+                               return err;
+               }
+       }
+
+       IPW_DEBUG_INFO("exit\n");
+
+       return 0;
+}
+
+
+void ipw2100_queues_initialize(struct ipw2100_priv *priv)
+{
+       ipw2100_tx_initialize(priv);
+       ipw2100_rx_initialize(priv);
+       ipw2100_msg_initialize(priv);
+}
+
+void ipw2100_queues_free(struct ipw2100_priv *priv)
+{
+       ipw2100_tx_free(priv);
+       ipw2100_rx_free(priv);
+       ipw2100_msg_free(priv);
+}
+
+int ipw2100_queues_allocate(struct ipw2100_priv *priv)
+{
+       if (ipw2100_tx_allocate(priv) ||
+           ipw2100_rx_allocate(priv) ||
+           ipw2100_msg_allocate(priv))
+               goto fail;
+
+       return 0;
+
+ fail:
+       ipw2100_tx_free(priv);
+       ipw2100_rx_free(priv);
+       ipw2100_msg_free(priv);
+       return -ENOMEM;
+}
+
+#define IPW_PRIVACY_CAPABLE 0x0008
+
+static int ipw2100_set_wep_flags(struct ipw2100_priv *priv, u32 flags,
+                                int batch_mode)
+{
+       struct host_command cmd = {
+               .host_command = WEP_FLAGS,
+               .host_command_sequence = 0,
+               .host_command_length = 4
+       };
+       int err;
+
+       cmd.host_command_parameters[0] = flags;
+
+       IPW_DEBUG_HC("WEP_FLAGS: flags = 0x%08X\n", flags);
+
+       if (!batch_mode) {
+               err = ipw2100_disable_adapter(priv);
+               if (err) {
+                       printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
+                              priv->net_dev->name, err);
+                       return err;
+               }
+       }
+
+       /* send cmd to firmware */
+       err = ipw2100_hw_send_command(priv, &cmd);
+
+       if (!batch_mode)
+               ipw2100_enable_adapter(priv);
+
+       return err;
+}
+
+struct ipw2100_wep_key {
+       u8 idx;
+       u8 len;
+       u8 key[13];
+};
+
+/* Macros to ease up priting WEP keys */
+#define WEP_FMT_64  "%02X%02X%02X%02X-%02X"
+#define WEP_FMT_128 "%02X%02X%02X%02X-%02X%02X%02X%02X-%02X%02X%02X"
+#define WEP_STR_64(x) x[0],x[1],x[2],x[3],x[4]
+#define WEP_STR_128(x) x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10]
+
+
+/**
+ * Set a the wep key
+ *
+ * @priv: struct to work on
+ * @idx: index of the key we want to set
+ * @key: ptr to the key data to set
+ * @len: length of the buffer at @key
+ * @batch_mode: FIXME perform the operation in batch mode, not
+ *              disabling the device.
+ *
+ * @returns 0 if OK, < 0 errno code on error.
+ *
+ * Fill out a command structure with the new wep key, length an
+ * index and send it down the wire.
+ */
+static int ipw2100_set_key(struct ipw2100_priv *priv,
+                          int idx, char *key, int len, int batch_mode)
+{
+       int keylen = len ? (len <= 5 ? 5 : 13) : 0;
+       struct host_command cmd = {
+               .host_command = WEP_KEY_INFO,
+               .host_command_sequence = 0,
+               .host_command_length = sizeof(struct ipw2100_wep_key),
+       };
+       struct ipw2100_wep_key *wep_key = (void*)cmd.host_command_parameters;
+       int err;
+
+       IPW_DEBUG_HC("WEP_KEY_INFO: index = %d, len = %d/%d\n",
+                                idx, keylen, len);
+
+       /* NOTE: We don't check cached values in case the firmware was reset
+        * or some other problem is occuring.  If the user is setting the key,
+        * then we push the change */
+
+       wep_key->idx = idx;
+       wep_key->len = keylen;
+
+       if (keylen) {
+               memcpy(wep_key->key, key, len);
+               memset(wep_key->key + len, 0, keylen - len);
+       }
+
+       /* Will be optimized out on debug not being configured in */
+       if (keylen == 0)
+               IPW_DEBUG_WEP("%s: Clearing key %d\n",
+                                 priv->net_dev->name, wep_key->idx);
+       else if (keylen == 5)
+               IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_64 "\n",
+                                 priv->net_dev->name, wep_key->idx, wep_key->len,
+                                 WEP_STR_64(wep_key->key));
+       else
+               IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_128
+                                 "\n",
+                                 priv->net_dev->name, wep_key->idx, wep_key->len,
+                                 WEP_STR_128(wep_key->key));
+
+       if (!batch_mode) {
+               err = ipw2100_disable_adapter(priv);
+               /* FIXME: IPG: shouldn't this prink be in _disable_adapter()? */
+               if (err) {
+                       printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
+                              priv->net_dev->name, err);
+                       return err;
+               }
+       }
+
+       /* send cmd to firmware */
+       err = ipw2100_hw_send_command(priv, &cmd);
+
+       if (!batch_mode) {
+               int err2 = ipw2100_enable_adapter(priv);
+               if (err == 0)
+                       err = err2;
+       }
+       return err;
+}
+
+static int ipw2100_set_key_index(struct ipw2100_priv *priv,
+                                int idx, int batch_mode)
+{
+       struct host_command cmd = {
+               .host_command = WEP_KEY_INDEX,
+               .host_command_sequence = 0,
+               .host_command_length = 4,
+               .host_command_parameters = { idx },
+       };
+       int err;
+
+       IPW_DEBUG_HC("WEP_KEY_INDEX: index = %d\n", idx);
+
+       if (idx < 0 || idx > 3)
+               return -EINVAL;
+
+       if (!batch_mode) {
+               err = ipw2100_disable_adapter(priv);
+               if (err) {
+                       printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
+                              priv->net_dev->name, err);
+                       return err;
+               }
+       }
+
+       /* send cmd to firmware */
+       err = ipw2100_hw_send_command(priv, &cmd);
+
+       if (!batch_mode)
+               ipw2100_enable_adapter(priv);
+
+       return err;
+}
+
+
+static int ipw2100_configure_security(struct ipw2100_priv *priv,
+                                     int batch_mode)
+{
+       int i, err, auth_mode, sec_level, use_group;
+
+       if (!(priv->status & STATUS_RUNNING))
+               return 0;
+
+       if (!batch_mode) {
+               err = ipw2100_disable_adapter(priv);
+               if (err)
+                       return err;
+       }
+
+       if (!priv->sec.enabled) {
+               err = ipw2100_set_security_information(
+                       priv, IPW_AUTH_OPEN, SEC_LEVEL_0, 0, 1);
+       } else {
+               auth_mode = IPW_AUTH_OPEN;
+               if ((priv->sec.flags & SEC_AUTH_MODE) &&
+                   (priv->sec.auth_mode == WLAN_AUTH_SHARED_KEY))
+                       auth_mode = IPW_AUTH_SHARED;
+
+               sec_level = SEC_LEVEL_0;
+               if (priv->sec.flags & SEC_LEVEL)
+                       sec_level = priv->sec.level;
+
+               use_group = 0;
+               if (priv->sec.flags & SEC_UNICAST_GROUP)
+                       use_group = priv->sec.unicast_uses_group;
+
+               err = ipw2100_set_security_information(
+                           priv, auth_mode, sec_level, use_group, 1);
+       }
+
+       if (err)
+               goto exit;
+
+       if (priv->sec.enabled) {
+               for (i = 0; i < 4; i++) {
+                       if (!(priv->sec.flags & (1 << i))) {
+                               memset(priv->sec.keys[i], 0, WEP_KEY_LEN);
+                               priv->sec.key_sizes[i] = 0;
+                       } else {
+                               err = ipw2100_set_key(priv, i,
+                                                     priv->sec.keys[i],
+                                                     priv->sec.key_sizes[i],
+                                                     1);
+                               if (err)
+                                       goto exit;
+                       }
+               }
+
+               ipw2100_set_key_index(priv, priv->ieee->tx_keyidx, 1);
+       }
+
+       /* Always enable privacy so the Host can filter WEP packets if
+        * encrypted data is sent up */
+       err = ipw2100_set_wep_flags(
+               priv, priv->sec.enabled ? IPW_PRIVACY_CAPABLE : 0, 1);
+       if (err)
+               goto exit;
+
+       priv->status &= ~STATUS_SECURITY_UPDATED;
+
+ exit:
+       if (!batch_mode)
+               ipw2100_enable_adapter(priv);
+
+       return err;
+}
+
+static void ipw2100_security_work(struct ipw2100_priv *priv)
+{
+       /* If we happen to have reconnected before we get a chance to
+        * process this, then update the security settings--which causes
+        * a disassociation to occur */
+       if (!(priv->status & STATUS_ASSOCIATED) &&
+           priv->status & STATUS_SECURITY_UPDATED)
+               ipw2100_configure_security(priv, 0);
+}
+
+static void shim__set_security(struct net_device *dev,
+                              struct ieee80211_security *sec)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       int i, force_update = 0;
+
+       down(&priv->action_sem);
+       if (!(priv->status & STATUS_INITIALIZED))
+               goto done;
+
+       for (i = 0; i < 4; i++) {
+               if (sec->flags & (1 << i)) {
+                       priv->sec.key_sizes[i] = sec->key_sizes[i];
+                       if (sec->key_sizes[i] == 0)
+                               priv->sec.flags &= ~(1 << i);
+                       else
+                               memcpy(priv->sec.keys[i], sec->keys[i],
+                                      sec->key_sizes[i]);
+                       priv->sec.flags |= (1 << i);
+                       priv->status |= STATUS_SECURITY_UPDATED;
+               }
+       }
+
+       if ((sec->flags & SEC_ACTIVE_KEY) &&
+           priv->sec.active_key != sec->active_key) {
+               if (sec->active_key <= 3) {
+                       priv->sec.active_key = sec->active_key;
+                       priv->sec.flags |= SEC_ACTIVE_KEY;
+               } else
+                       priv->sec.flags &= ~SEC_ACTIVE_KEY;
+
+               priv->status |= STATUS_SECURITY_UPDATED;
+       }
+
+       if ((sec->flags & SEC_AUTH_MODE) &&
+           (priv->sec.auth_mode != sec->auth_mode)) {
+               priv->sec.auth_mode = sec->auth_mode;
+               priv->sec.flags |= SEC_AUTH_MODE;
+               priv->status |= STATUS_SECURITY_UPDATED;
+       }
+
+       if (sec->flags & SEC_ENABLED &&
+           priv->sec.enabled != sec->enabled) {
+               priv->sec.flags |= SEC_ENABLED;
+               priv->sec.enabled = sec->enabled;
+               priv->status |= STATUS_SECURITY_UPDATED;
+               force_update = 1;
+       }
+
+       if (sec->flags & SEC_LEVEL &&
+           priv->sec.level != sec->level) {
+               priv->sec.level = sec->level;
+               priv->sec.flags |= SEC_LEVEL;
+               priv->status |= STATUS_SECURITY_UPDATED;
+       }
+
+       IPW_DEBUG_WEP("Security flags: %c %c%c%c%c %c%c%c%c\n",
+                         priv->sec.flags & (1<<8) ? '1' : '0',
+                         priv->sec.flags & (1<<7) ? '1' : '0',
+                         priv->sec.flags & (1<<6) ? '1' : '0',
+                         priv->sec.flags & (1<<5) ? '1' : '0',
+                         priv->sec.flags & (1<<4) ? '1' : '0',
+                         priv->sec.flags & (1<<3) ? '1' : '0',
+                         priv->sec.flags & (1<<2) ? '1' : '0',
+                         priv->sec.flags & (1<<1) ? '1' : '0',
+                         priv->sec.flags & (1<<0) ? '1' : '0');
+
+/* As a temporary work around to enable WPA until we figure out why
+ * wpa_supplicant toggles the security capability of the driver, which
+ * forces a disassocation with force_update...
+ *
+ *     if (force_update || !(priv->status & STATUS_ASSOCIATED))*/
+       if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
+               ipw2100_configure_security(priv, 0);
+done:
+       up(&priv->action_sem);
+}
+
+static int ipw2100_adapter_setup(struct ipw2100_priv *priv)
+{
+       int err;
+       int batch_mode = 1;
+       u8 *bssid;
+
+       IPW_DEBUG_INFO("enter\n");
+
+       err = ipw2100_disable_adapter(priv);
+       if (err)
+               return err;
+#ifdef CONFIG_IPW2100_MONITOR
+       if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+               err = ipw2100_set_channel(priv, priv->channel, batch_mode);
+               if (err)
+                       return err;
+
+               IPW_DEBUG_INFO("exit\n");
+
+               return 0;
+       }
+#endif /* CONFIG_IPW2100_MONITOR */
+
+       err = ipw2100_read_mac_address(priv);
+       if (err)
+               return -EIO;
+
+       err = ipw2100_set_mac_address(priv, batch_mode);
+       if (err)
+               return err;
+
+       err = ipw2100_set_port_type(priv, priv->ieee->iw_mode, batch_mode);
+       if (err)
+               return err;
+
+       if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+               err = ipw2100_set_channel(priv, priv->channel, batch_mode);
+               if (err)
+                       return err;
+       }
+
+       err  = ipw2100_system_config(priv, batch_mode);
+       if (err)
+               return err;
+
+       err = ipw2100_set_tx_rates(priv, priv->tx_rates, batch_mode);
+       if (err)
+               return err;
+
+       /* Default to power mode OFF */
+       err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
+       if (err)
+               return err;
+
+       err = ipw2100_set_rts_threshold(priv, priv->rts_threshold);
+       if (err)
+               return err;
+
+       if (priv->config & CFG_STATIC_BSSID)
+               bssid = priv->bssid;
+       else
+               bssid = NULL;
+       err = ipw2100_set_mandatory_bssid(priv, bssid, batch_mode);
+       if (err)
+               return err;
+
+       if (priv->config & CFG_STATIC_ESSID)
+               err = ipw2100_set_essid(priv, priv->essid, priv->essid_len,
+                                       batch_mode);
+       else
+               err = ipw2100_set_essid(priv, NULL, 0, batch_mode);
+       if (err)
+               return err;
+
+       err = ipw2100_configure_security(priv, batch_mode);
+       if (err)
+               return err;
+
+       if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+               err = ipw2100_set_ibss_beacon_interval(
+                       priv, priv->beacon_interval, batch_mode);
+               if (err)
+                       return err;
+
+               err = ipw2100_set_tx_power(priv, priv->tx_power);
+               if (err)
+                       return err;
+       }
+
+       /*
+         err = ipw2100_set_fragmentation_threshold(
+         priv, priv->frag_threshold, batch_mode);
+         if (err)
+         return err;
+       */
+
+       IPW_DEBUG_INFO("exit\n");
+
+       return 0;
+}
+
+
+/*************************************************************************
+ *
+ * EXTERNALLY CALLED METHODS
+ *
+ *************************************************************************/
+
+/* This method is called by the network layer -- not to be confused with
+ * ipw2100_set_mac_address() declared above called by this driver (and this
+ * method as well) to talk to the firmware */
+static int ipw2100_set_address(struct net_device *dev, void *p)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       struct sockaddr *addr = p;
+       int err = 0;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       down(&priv->action_sem);
+
+       priv->config |= CFG_CUSTOM_MAC;
+       memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
+
+       err = ipw2100_set_mac_address(priv, 0);
+       if (err)
+               goto done;
+
+       priv->reset_backoff = 0;
+       up(&priv->action_sem);
+       ipw2100_reset_adapter(priv);
+       return 0;
+
+ done:
+       up(&priv->action_sem);
+       return err;
+}
+
+static int ipw2100_open(struct net_device *dev)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       unsigned long flags;
+       IPW_DEBUG_INFO("dev->open\n");
+
+       spin_lock_irqsave(&priv->low_lock, flags);
+       if (priv->status & STATUS_ASSOCIATED) {
+               netif_carrier_on(dev);
+               netif_start_queue(dev);
+       }
+       spin_unlock_irqrestore(&priv->low_lock, flags);
+
+       return 0;
+}
+
+static int ipw2100_close(struct net_device *dev)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       unsigned long flags;
+       struct list_head *element;
+       struct ipw2100_tx_packet *packet;
+
+       IPW_DEBUG_INFO("enter\n");
+
+       spin_lock_irqsave(&priv->low_lock, flags);
+
+       if (priv->status & STATUS_ASSOCIATED)
+               netif_carrier_off(dev);
+       netif_stop_queue(dev);
+
+       /* Flush the TX queue ... */
+       while (!list_empty(&priv->tx_pend_list)) {
+               element = priv->tx_pend_list.next;
+                packet = list_entry(element, struct ipw2100_tx_packet, list);
+
+               list_del(element);
+               DEC_STAT(&priv->tx_pend_stat);
+
+               ieee80211_txb_free(packet->info.d_struct.txb);
+               packet->info.d_struct.txb = NULL;
+
+               list_add_tail(element, &priv->tx_free_list);
+               INC_STAT(&priv->tx_free_stat);
+       }
+       spin_unlock_irqrestore(&priv->low_lock, flags);
+
+       IPW_DEBUG_INFO("exit\n");
+
+       return 0;
+}
+
+
+
+/*
+ * TODO:  Fix this function... its just wrong
+ */
+static void ipw2100_tx_timeout(struct net_device *dev)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+       priv->ieee->stats.tx_errors++;
+
+#ifdef CONFIG_IPW2100_MONITOR
+       if (priv->ieee->iw_mode == IW_MODE_MONITOR)
+               return;
+#endif
+
+       IPW_DEBUG_INFO("%s: TX timed out.  Scheduling firmware restart.\n",
+                      dev->name);
+       schedule_reset(priv);
+}
+
+
+/*
+ * TODO: reimplement it so that it reads statistics
+ *       from the adapter using ordinal tables
+ *       instead of/in addition to collecting them
+ *       in the driver
+ */
+static struct net_device_stats *ipw2100_stats(struct net_device *dev)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+       return &priv->ieee->stats;
+}
+
+/* Support for wpa_supplicant. Will be replaced with WEXT once
+ * they get WPA support. */
+#ifdef CONFIG_IEEE80211_WPA
+
+/* following definitions must match definitions in driver_ipw2100.c */
+
+#define IPW2100_IOCTL_WPA_SUPPLICANT           SIOCIWFIRSTPRIV+30
+
+#define IPW2100_CMD_SET_WPA_PARAM              1
+#define        IPW2100_CMD_SET_WPA_IE                  2
+#define IPW2100_CMD_SET_ENCRYPTION             3
+#define IPW2100_CMD_MLME                       4
+
+#define IPW2100_PARAM_WPA_ENABLED              1
+#define IPW2100_PARAM_TKIP_COUNTERMEASURES     2
+#define IPW2100_PARAM_DROP_UNENCRYPTED         3
+#define IPW2100_PARAM_PRIVACY_INVOKED          4
+#define IPW2100_PARAM_AUTH_ALGS                        5
+#define IPW2100_PARAM_IEEE_802_1X              6
+
+#define IPW2100_MLME_STA_DEAUTH                        1
+#define IPW2100_MLME_STA_DISASSOC              2
+
+#define IPW2100_CRYPT_ERR_UNKNOWN_ALG          2
+#define IPW2100_CRYPT_ERR_UNKNOWN_ADDR         3
+#define IPW2100_CRYPT_ERR_CRYPT_INIT_FAILED    4
+#define IPW2100_CRYPT_ERR_KEY_SET_FAILED       5
+#define IPW2100_CRYPT_ERR_TX_KEY_SET_FAILED    6
+#define IPW2100_CRYPT_ERR_CARD_CONF_FAILED     7
+
+#define        IPW2100_CRYPT_ALG_NAME_LEN              16
+
+struct ipw2100_param {
+       u32 cmd;
+       u8 sta_addr[ETH_ALEN];
+        union {
+               struct {
+                       u8 name;
+                       u32 value;
+               } wpa_param;
+               struct {
+                       u32 len;
+                       u8 *data;
+               } wpa_ie;
+               struct{
+                       int command;
+                       int reason_code;
+               } mlme;
+               struct {
+                       u8 alg[IPW2100_CRYPT_ALG_NAME_LEN];
+                       u8 set_tx;
+                       u32 err;
+                       u8 idx;
+                       u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+                       u16 key_len;
+                       u8 key[0];
+               } crypt;
+
+       } u;
+};
+
+/* end of driver_ipw2100.c code */
+
+static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value){
+
+       struct ieee80211_device *ieee = priv->ieee;
+       struct ieee80211_security sec = {
+               .flags = SEC_LEVEL | SEC_ENABLED,
+       };
+       int ret = 0;
+
+       ieee->wpa_enabled = value;
+
+       if (value){
+               sec.level = SEC_LEVEL_3;
+               sec.enabled = 1;
+       } else {
+               sec.level = SEC_LEVEL_0;
+               sec.enabled = 0;
+       }
+
+       if (ieee->set_security)
+               ieee->set_security(ieee->dev, &sec);
+       else
+               ret = -EOPNOTSUPP;
+
+       return ret;
+}
+
+#define AUTH_ALG_OPEN_SYSTEM                   0x1
+#define AUTH_ALG_SHARED_KEY                    0x2
+
+static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value){
+
+       struct ieee80211_device *ieee = priv->ieee;
+       struct ieee80211_security sec = {
+               .flags = SEC_AUTH_MODE,
+       };
+       int ret = 0;
+
+       if (value & AUTH_ALG_SHARED_KEY){
+               sec.auth_mode = WLAN_AUTH_SHARED_KEY;
+               ieee->open_wep = 0;
+       } else {
+               sec.auth_mode = WLAN_AUTH_OPEN;
+               ieee->open_wep = 1;
+       }
+
+       if (ieee->set_security)
+               ieee->set_security(ieee->dev, &sec);
+       else
+               ret = -EOPNOTSUPP;
+
+       return ret;
+}
+
+
+static int ipw2100_wpa_set_param(struct net_device *dev, u8 name, u32 value){
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       int ret=0;
+
+       switch(name){
+               case IPW2100_PARAM_WPA_ENABLED:
+                       ret = ipw2100_wpa_enable(priv, value);
+                       break;
+
+               case IPW2100_PARAM_TKIP_COUNTERMEASURES:
+                       priv->ieee->tkip_countermeasures=value;
+                       break;
+
+               case IPW2100_PARAM_DROP_UNENCRYPTED:
+                       priv->ieee->drop_unencrypted=value;
+                       break;
+
+               case IPW2100_PARAM_PRIVACY_INVOKED:
+                       priv->ieee->privacy_invoked=value;
+                       break;
+
+               case IPW2100_PARAM_AUTH_ALGS:
+                       ret = ipw2100_wpa_set_auth_algs(priv, value);
+                       break;
+
+               case IPW2100_PARAM_IEEE_802_1X:
+                       priv->ieee->ieee802_1x=value;
+                       break;
+
+               default:
+                       printk(KERN_ERR DRV_NAME ": %s: Unknown WPA param: %d\n",
+                                           dev->name, name);
+                       ret = -EOPNOTSUPP;
+       }
+
+       return ret;
+}
+
+static int ipw2100_wpa_mlme(struct net_device *dev, int command, int reason){
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       int ret=0;
+
+       switch(command){
+               case IPW2100_MLME_STA_DEAUTH:
+                       // silently ignore
+                       break;
+
+               case IPW2100_MLME_STA_DISASSOC:
+                       ipw2100_disassociate_bssid(priv);
+                       break;
+
+               default:
+                       printk(KERN_ERR DRV_NAME ": %s: Unknown MLME request: %d\n",
+                                           dev->name, command);
+                       ret = -EOPNOTSUPP;
+       }
+
+       return ret;
+}
+
+
+void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv,
+                            char *wpa_ie, int wpa_ie_len){
+
+       struct ipw2100_wpa_assoc_frame frame;
+
+       frame.fixed_ie_mask = 0;
+
+       /* copy WPA IE */
+       memcpy(frame.var_ie, wpa_ie, wpa_ie_len);
+       frame.var_ie_len = wpa_ie_len;
+
+       /* make sure WPA is enabled */
+       ipw2100_wpa_enable(priv, 1);
+       ipw2100_set_wpa_ie(priv, &frame, 0);
+}
+
+
+static int ipw2100_wpa_set_wpa_ie(struct net_device *dev,
+                               struct ipw2100_param *param, int plen){
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       struct ieee80211_device *ieee = priv->ieee;
+       u8 *buf;
+
+       if (! ieee->wpa_enabled)
+           return -EOPNOTSUPP;
+
+       if (param->u.wpa_ie.len > MAX_WPA_IE_LEN ||
+          (param->u.wpa_ie.len &&
+               param->u.wpa_ie.data==NULL))
+               return -EINVAL;
+
+       if (param->u.wpa_ie.len){
+               buf = kmalloc(param->u.wpa_ie.len, GFP_KERNEL);
+               if (buf == NULL)
+                       return -ENOMEM;
+
+               memcpy(buf, param->u.wpa_ie.data, param->u.wpa_ie.len);
+
+               kfree(ieee->wpa_ie);
+               ieee->wpa_ie = buf;
+               ieee->wpa_ie_len = param->u.wpa_ie.len;
+
+       } else {
+               kfree(ieee->wpa_ie);
+               ieee->wpa_ie = NULL;
+               ieee->wpa_ie_len = 0;
+       }
+
+       ipw2100_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
+
+       return 0;
+}
+
+/* implementation borrowed from hostap driver */
+
+static int ipw2100_wpa_set_encryption(struct net_device *dev,
+                               struct ipw2100_param *param, int param_len){
+
+       int ret = 0;
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       struct ieee80211_device *ieee = priv->ieee;
+       struct ieee80211_crypto_ops *ops;
+       struct ieee80211_crypt_data **crypt;
+
+       struct ieee80211_security sec = {
+               .flags = 0,
+       };
+
+       param->u.crypt.err = 0;
+       param->u.crypt.alg[IPW2100_CRYPT_ALG_NAME_LEN - 1] = '\0';
+
+       if (param_len !=
+           (int) ((char *) param->u.crypt.key - (char *) param) +
+           param->u.crypt.key_len){
+               IPW_DEBUG_INFO("Len mismatch %d, %d\n", param_len, param->u.crypt.key_len);
+               return -EINVAL;
+       }
+       if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+           param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+           param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+               if (param->u.crypt.idx >= WEP_KEYS)
+                       return -EINVAL;
+               crypt = &ieee->crypt[param->u.crypt.idx];
+       } else {
+               return -EINVAL;
+       }
+
+       if (strcmp(param->u.crypt.alg, "none") == 0) {
+               if (crypt){
+                       sec.enabled = 0;
+                       sec.level = SEC_LEVEL_0;
+                       sec.flags |= SEC_ENABLED | SEC_LEVEL;
+                       ieee80211_crypt_delayed_deinit(ieee, crypt);
+               }
+               goto done;
+       }
+       sec.enabled = 1;
+       sec.flags |= SEC_ENABLED;
+
+       ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+       if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) {
+               request_module("ieee80211_crypt_wep");
+               ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+       } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) {
+               request_module("ieee80211_crypt_tkip");
+               ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+       } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) {
+               request_module("ieee80211_crypt_ccmp");
+               ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+       }
+       if (ops == NULL) {
+               IPW_DEBUG_INFO("%s: unknown crypto alg '%s'\n",
+                      dev->name, param->u.crypt.alg);
+               param->u.crypt.err = IPW2100_CRYPT_ERR_UNKNOWN_ALG;
+               ret = -EINVAL;
+               goto done;
+       }
+
+       if (*crypt == NULL || (*crypt)->ops != ops) {
+               struct ieee80211_crypt_data *new_crypt;
+
+               ieee80211_crypt_delayed_deinit(ieee, crypt);
+
+               new_crypt = (struct ieee80211_crypt_data *)
+                       kmalloc(sizeof(struct ieee80211_crypt_data), GFP_KERNEL);
+               if (new_crypt == NULL) {
+                       ret = -ENOMEM;
+                       goto done;
+               }
+               memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
+               new_crypt->ops = ops;
+               if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
+                       new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx);
+
+               if (new_crypt->priv == NULL) {
+                       kfree(new_crypt);
+                       param->u.crypt.err =
+                               IPW2100_CRYPT_ERR_CRYPT_INIT_FAILED;
+                       ret = -EINVAL;
+                       goto done;
+               }
+
+               *crypt = new_crypt;
+       }
+
+       if (param->u.crypt.key_len > 0 && (*crypt)->ops->set_key &&
+           (*crypt)->ops->set_key(param->u.crypt.key,
+                                  param->u.crypt.key_len, param->u.crypt.seq,
+                                  (*crypt)->priv) < 0) {
+               IPW_DEBUG_INFO("%s: key setting failed\n",
+                      dev->name);
+               param->u.crypt.err = IPW2100_CRYPT_ERR_KEY_SET_FAILED;
+               ret = -EINVAL;
+               goto done;
+       }
+
+       if (param->u.crypt.set_tx){
+               ieee->tx_keyidx = param->u.crypt.idx;
+               sec.active_key = param->u.crypt.idx;
+               sec.flags |= SEC_ACTIVE_KEY;
+       }
+
+       if (ops->name != NULL){
+
+               if (strcmp(ops->name, "WEP") == 0) {
+                       memcpy(sec.keys[param->u.crypt.idx], param->u.crypt.key, param->u.crypt.key_len);
+                       sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len;
+                       sec.flags |= (1 << param->u.crypt.idx);
+                       sec.flags |= SEC_LEVEL;
+                       sec.level = SEC_LEVEL_1;
+               } else if (strcmp(ops->name, "TKIP") == 0) {
+                       sec.flags |= SEC_LEVEL;
+                       sec.level = SEC_LEVEL_2;
+               } else if (strcmp(ops->name, "CCMP") == 0) {
+                       sec.flags |= SEC_LEVEL;
+                       sec.level = SEC_LEVEL_3;
+               }
+       }
+ done:
+       if (ieee->set_security)
+               ieee->set_security(ieee->dev, &sec);
+
+       /* Do not reset port if card is in Managed mode since resetting will
+        * generate new IEEE 802.11 authentication which may end up in looping
+        * with IEEE 802.1X.  If your hardware requires a reset after WEP
+        * configuration (for example... Prism2), implement the reset_port in
+        * the callbacks structures used to initialize the 802.11 stack. */
+       if (ieee->reset_on_keychange &&
+           ieee->iw_mode != IW_MODE_INFRA &&
+           ieee->reset_port &&
+           ieee->reset_port(dev)) {
+               IPW_DEBUG_INFO("%s: reset_port failed\n", dev->name);
+               param->u.crypt.err = IPW2100_CRYPT_ERR_CARD_CONF_FAILED;
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
+
+static int ipw2100_wpa_supplicant(struct net_device *dev, struct iw_point *p){
+
+       struct ipw2100_param *param;
+       int ret=0;
+
+       IPW_DEBUG_IOCTL("wpa_supplicant: len=%d\n", p->length);
+
+       if (p->length < sizeof(struct ipw2100_param) || !p->pointer)
+               return -EINVAL;
+
+       param = (struct ipw2100_param *)kmalloc(p->length, GFP_KERNEL);
+       if (param == NULL)
+               return -ENOMEM;
+
+       if (copy_from_user(param, p->pointer, p->length)){
+               kfree(param);
+               return -EFAULT;
+       }
+
+       switch (param->cmd){
+
+       case IPW2100_CMD_SET_WPA_PARAM:
+               ret = ipw2100_wpa_set_param(dev, param->u.wpa_param.name,
+                                           param->u.wpa_param.value);
+               break;
+
+       case IPW2100_CMD_SET_WPA_IE:
+               ret = ipw2100_wpa_set_wpa_ie(dev, param, p->length);
+               break;
+
+       case IPW2100_CMD_SET_ENCRYPTION:
+               ret = ipw2100_wpa_set_encryption(dev, param, p->length);
+               break;
+
+       case IPW2100_CMD_MLME:
+               ret = ipw2100_wpa_mlme(dev, param->u.mlme.command,
+                                      param->u.mlme.reason_code);
+               break;
+
+       default:
+               printk(KERN_ERR DRV_NAME ": %s: Unknown WPA supplicant request: %d\n",
+                               dev->name, param->cmd);
+               ret = -EOPNOTSUPP;
+
+       }
+
+       if (ret == 0 && copy_to_user(p->pointer, param, p->length))
+               ret = -EFAULT;
+
+       kfree(param);
+       return ret;
+}
+#endif /* CONFIG_IEEE80211_WPA */
+
+static int ipw2100_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+#ifdef CONFIG_IEEE80211_WPA
+       struct iwreq *wrq = (struct iwreq *) rq;
+       int ret=-1;
+       switch (cmd){
+           case IPW2100_IOCTL_WPA_SUPPLICANT:
+               ret = ipw2100_wpa_supplicant(dev, &wrq->u.data);
+               return ret;
+
+           default:
+               return -EOPNOTSUPP;
+       }
+
+#endif /* CONFIG_IEEE80211_WPA */
+
+       return -EOPNOTSUPP;
+}
+
+
+static void ipw_ethtool_get_drvinfo(struct net_device *dev,
+                                   struct ethtool_drvinfo *info)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       char fw_ver[64], ucode_ver[64];
+
+       strcpy(info->driver, DRV_NAME);
+       strcpy(info->version, DRV_VERSION);
+
+       ipw2100_get_fwversion(priv, fw_ver, sizeof(fw_ver));
+       ipw2100_get_ucodeversion(priv, ucode_ver, sizeof(ucode_ver));
+
+       snprintf(info->fw_version, sizeof(info->fw_version), "%s:%d:%s",
+                fw_ver, priv->eeprom_version, ucode_ver);
+
+       strcpy(info->bus_info, pci_name(priv->pci_dev));
+}
+
+static u32 ipw2100_ethtool_get_link(struct net_device *dev)
+{
+    struct ipw2100_priv *priv = ieee80211_priv(dev);
+    return (priv->status & STATUS_ASSOCIATED) ? 1 : 0;
+}
+
+
+static struct ethtool_ops ipw2100_ethtool_ops = {
+    .get_link        = ipw2100_ethtool_get_link,
+    .get_drvinfo     = ipw_ethtool_get_drvinfo,
+};
+
+static void ipw2100_hang_check(void *adapter)
+{
+       struct ipw2100_priv *priv = adapter;
+       unsigned long flags;
+       u32 rtc = 0xa5a5a5a5;
+       u32 len = sizeof(rtc);
+       int restart = 0;
+
+       spin_lock_irqsave(&priv->low_lock, flags);
+
+       if (priv->fatal_error != 0) {
+               /* If fatal_error is set then we need to restart */
+               IPW_DEBUG_INFO("%s: Hardware fatal error detected.\n",
+                              priv->net_dev->name);
+
+               restart = 1;
+       } else if (ipw2100_get_ordinal(priv, IPW_ORD_RTC_TIME, &rtc, &len) ||
+                  (rtc == priv->last_rtc)) {
+               /* Check if firmware is hung */
+               IPW_DEBUG_INFO("%s: Firmware RTC stalled.\n",
+                              priv->net_dev->name);
+
+               restart = 1;
+       }
+
+       if (restart) {
+               /* Kill timer */
+               priv->stop_hang_check = 1;
+               priv->hangs++;
+
+               /* Restart the NIC */
+               schedule_reset(priv);
+       }
+
+       priv->last_rtc = rtc;
+
+       if (!priv->stop_hang_check)
+               queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2);
+
+       spin_unlock_irqrestore(&priv->low_lock, flags);
+}
+
+
+static void ipw2100_rf_kill(void *adapter)
+{
+       struct ipw2100_priv *priv = adapter;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->low_lock, flags);
+
+       if (rf_kill_active(priv)) {
+               IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
+               if (!priv->stop_rf_kill)
+                       queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ);
+               goto exit_unlock;
+       }
+
+       /* RF Kill is now disabled, so bring the device back up */
+
+       if (!(priv->status & STATUS_RF_KILL_MASK)) {
+               IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting "
+                                 "device\n");
+               schedule_reset(priv);
+       } else
+               IPW_DEBUG_RF_KILL("HW RF Kill deactivated.  SW RF Kill still "
+                                 "enabled\n");
+
+ exit_unlock:
+       spin_unlock_irqrestore(&priv->low_lock, flags);
+}
+
+static void ipw2100_irq_tasklet(struct ipw2100_priv *priv);
+
+/* Look into using netdev destructor to shutdown ieee80211? */
+
+static struct net_device *ipw2100_alloc_device(
+       struct pci_dev *pci_dev,
+       void __iomem *base_addr,
+       unsigned long mem_start,
+       unsigned long mem_len)
+{
+       struct ipw2100_priv *priv;
+       struct net_device *dev;
+
+       dev = alloc_ieee80211(sizeof(struct ipw2100_priv));
+       if (!dev)
+               return NULL;
+       priv = ieee80211_priv(dev);
+       priv->ieee = netdev_priv(dev);
+       priv->pci_dev = pci_dev;
+       priv->net_dev = dev;
+
+       priv->ieee->hard_start_xmit = ipw2100_tx;
+       priv->ieee->set_security = shim__set_security;
+
+       dev->open = ipw2100_open;
+       dev->stop = ipw2100_close;
+       dev->init = ipw2100_net_init;
+       dev->do_ioctl = ipw2100_ioctl;
+       dev->get_stats = ipw2100_stats;
+       dev->ethtool_ops = &ipw2100_ethtool_ops;
+       dev->tx_timeout = ipw2100_tx_timeout;
+       dev->wireless_handlers = &ipw2100_wx_handler_def;
+       dev->get_wireless_stats = ipw2100_wx_wireless_stats;
+       dev->set_mac_address = ipw2100_set_address;
+       dev->watchdog_timeo = 3*HZ;
+       dev->irq = 0;
+
+       dev->base_addr = (unsigned long)base_addr;
+       dev->mem_start = mem_start;
+       dev->mem_end = dev->mem_start + mem_len - 1;
+
+       /* NOTE: We don't use the wireless_handlers hook
+        * in dev as the system will start throwing WX requests
+        * to us before we're actually initialized and it just
+        * ends up causing problems.  So, we just handle
+        * the WX extensions through the ipw2100_ioctl interface */
+
+
+       /* memset() puts everything to 0, so we only have explicitely set
+        * those values that need to be something else */
+
+       /* If power management is turned on, default to AUTO mode */
+       priv->power_mode = IPW_POWER_AUTO;
+
+
+
+#ifdef CONFIG_IEEE80211_WPA
+       priv->ieee->wpa_enabled = 0;
+       priv->ieee->tkip_countermeasures = 0;
+       priv->ieee->drop_unencrypted = 0;
+       priv->ieee->privacy_invoked = 0;
+       priv->ieee->ieee802_1x = 1;
+#endif /* CONFIG_IEEE80211_WPA */
+
+       /* Set module parameters */
+       switch (mode) {
+       case 1:
+               priv->ieee->iw_mode = IW_MODE_ADHOC;
+               break;
+#ifdef CONFIG_IPW2100_MONITOR
+       case 2:
+               priv->ieee->iw_mode = IW_MODE_MONITOR;
+               break;
+#endif
+       default:
+       case 0:
+               priv->ieee->iw_mode = IW_MODE_INFRA;
+               break;
+       }
+
+       if (disable == 1)
+               priv->status |= STATUS_RF_KILL_SW;
+
+       if (channel != 0 &&
+           ((channel >= REG_MIN_CHANNEL) &&
+            (channel <= REG_MAX_CHANNEL))) {
+               priv->config |= CFG_STATIC_CHANNEL;
+               priv->channel = channel;
+       }
+
+       if (associate)
+               priv->config |= CFG_ASSOCIATE;
+
+       priv->beacon_interval = DEFAULT_BEACON_INTERVAL;
+       priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT;
+       priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT;
+       priv->rts_threshold = DEFAULT_RTS_THRESHOLD | RTS_DISABLED;
+       priv->frag_threshold = DEFAULT_FTS | FRAG_DISABLED;
+       priv->tx_power = IPW_TX_POWER_DEFAULT;
+       priv->tx_rates = DEFAULT_TX_RATES;
+
+       strcpy(priv->nick, "ipw2100");
+
+       spin_lock_init(&priv->low_lock);
+       sema_init(&priv->action_sem, 1);
+       sema_init(&priv->adapter_sem, 1);
+
+       init_waitqueue_head(&priv->wait_command_queue);
+
+       netif_carrier_off(dev);
+
+       INIT_LIST_HEAD(&priv->msg_free_list);
+       INIT_LIST_HEAD(&priv->msg_pend_list);
+       INIT_STAT(&priv->msg_free_stat);
+       INIT_STAT(&priv->msg_pend_stat);
+
+       INIT_LIST_HEAD(&priv->tx_free_list);
+       INIT_LIST_HEAD(&priv->tx_pend_list);
+       INIT_STAT(&priv->tx_free_stat);
+       INIT_STAT(&priv->tx_pend_stat);
+
+       INIT_LIST_HEAD(&priv->fw_pend_list);
+       INIT_STAT(&priv->fw_pend_stat);
+
+
+#ifdef CONFIG_SOFTWARE_SUSPEND2
+       priv->workqueue = create_workqueue(DRV_NAME, 0);
+#else
+       priv->workqueue = create_workqueue(DRV_NAME);
+#endif
+       INIT_WORK(&priv->reset_work,
+                 (void (*)(void *))ipw2100_reset_adapter, priv);
+       INIT_WORK(&priv->security_work,
+                 (void (*)(void *))ipw2100_security_work, priv);
+       INIT_WORK(&priv->wx_event_work,
+                 (void (*)(void *))ipw2100_wx_event_work, priv);
+       INIT_WORK(&priv->hang_check, ipw2100_hang_check, priv);
+       INIT_WORK(&priv->rf_kill, ipw2100_rf_kill, priv);
+
+       tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+                    ipw2100_irq_tasklet, (unsigned long)priv);
+
+       /* NOTE:  We do not start the deferred work for status checks yet */
+       priv->stop_rf_kill = 1;
+       priv->stop_hang_check = 1;
+
+       return dev;
+}
+
+static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
+                               const struct pci_device_id *ent)
+{
+       unsigned long mem_start, mem_len, mem_flags;
+       void __iomem *base_addr = NULL;
+       struct net_device *dev = NULL;
+       struct ipw2100_priv *priv = NULL;
+       int err = 0;
+       int registered = 0;
+       u32 val;
+
+       IPW_DEBUG_INFO("enter\n");
+
+       mem_start = pci_resource_start(pci_dev, 0);
+       mem_len = pci_resource_len(pci_dev, 0);
+       mem_flags = pci_resource_flags(pci_dev, 0);
+
+       if ((mem_flags & IORESOURCE_MEM) != IORESOURCE_MEM) {
+               IPW_DEBUG_INFO("weird - resource type is not memory\n");
+               err = -ENODEV;
+               goto fail;
+       }
+
+       base_addr = ioremap_nocache(mem_start, mem_len);
+       if (!base_addr) {
+               printk(KERN_WARNING DRV_NAME
+                      "Error calling ioremap_nocache.\n");
+               err = -EIO;
+               goto fail;
+       }
+
+       /* allocate and initialize our net_device */
+       dev = ipw2100_alloc_device(pci_dev, base_addr, mem_start, mem_len);
+       if (!dev) {
+               printk(KERN_WARNING DRV_NAME
+                      "Error calling ipw2100_alloc_device.\n");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       /* set up PCI mappings for device */
+       err = pci_enable_device(pci_dev);
+       if (err) {
+               printk(KERN_WARNING DRV_NAME
+                      "Error calling pci_enable_device.\n");
+               return err;
+       }
+
+       priv = ieee80211_priv(dev);
+
+       pci_set_master(pci_dev);
+       pci_set_drvdata(pci_dev, priv);
+
+       err = pci_set_dma_mask(pci_dev, DMA_32BIT_MASK);
+       if (err) {
+               printk(KERN_WARNING DRV_NAME
+                      "Error calling pci_set_dma_mask.\n");
+               pci_disable_device(pci_dev);
+               return err;
+       }
+
+       err = pci_request_regions(pci_dev, DRV_NAME);
+       if (err) {
+               printk(KERN_WARNING DRV_NAME
+                      "Error calling pci_request_regions.\n");
+               pci_disable_device(pci_dev);
+               return err;
+       }
+
+        /* We disable the RETRY_TIMEOUT register (0x41) to keep
+        * PCI Tx retries from interfering with C3 CPU state */
+       pci_read_config_dword(pci_dev, 0x40, &val);
+       if ((val & 0x0000ff00) != 0)
+               pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
+
+       pci_set_power_state(pci_dev, PCI_D0);
+
+       if (!ipw2100_hw_is_adapter_in_system(dev)) {
+               printk(KERN_WARNING DRV_NAME
+                      "Device not found via register read.\n");
+               err = -ENODEV;
+               goto fail;
+       }
+
+       SET_NETDEV_DEV(dev, &pci_dev->dev);
+
+       /* Force interrupts to be shut off on the device */
+       priv->status |= STATUS_INT_ENABLED;
+       ipw2100_disable_interrupts(priv);
+
+       /* Allocate and initialize the Tx/Rx queues and lists */
+       if (ipw2100_queues_allocate(priv)) {
+               printk(KERN_WARNING DRV_NAME
+                      "Error calilng ipw2100_queues_allocate.\n");
+               err = -ENOMEM;
+               goto fail;
+       }
+       ipw2100_queues_initialize(priv);
+
+       err = request_irq(pci_dev->irq,
+                         ipw2100_interrupt, SA_SHIRQ,
+                         dev->name, priv);
+       if (err) {
+               printk(KERN_WARNING DRV_NAME
+                      "Error calling request_irq: %d.\n",
+                      pci_dev->irq);
+               goto fail;
+       }
+       dev->irq = pci_dev->irq;
+
+       IPW_DEBUG_INFO("Attempting to register device...\n");
+
+       SET_MODULE_OWNER(dev);
+
+       printk(KERN_INFO DRV_NAME
+              ": Detected Intel PRO/Wireless 2100 Network Connection\n");
+
+       /* Bring up the interface.  Pre 0.46, after we registered the
+        * network device we would call ipw2100_up.  This introduced a race
+        * condition with newer hotplug configurations (network was coming
+        * up and making calls before the device was initialized).
+        *
+        * If we called ipw2100_up before we registered the device, then the
+        * device name wasn't registered.  So, we instead use the net_dev->init
+        * member to call a function that then just turns and calls ipw2100_up.
+        * net_dev->init is called after name allocation but before the
+        * notifier chain is called */
+       down(&priv->action_sem);
+       err = register_netdev(dev);
+       if (err) {
+               printk(KERN_WARNING DRV_NAME
+                      "Error calling register_netdev.\n");
+               goto fail_unlock;
+       }
+       registered = 1;
+
+       IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev));
+
+       /* perform this after register_netdev so that dev->name is set */
+       sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
+       netif_carrier_off(dev);
+
+       /* If the RF Kill switch is disabled, go ahead and complete the
+        * startup sequence */
+       if (!(priv->status & STATUS_RF_KILL_MASK)) {
+               /* Enable the adapter - sends HOST_COMPLETE */
+               if (ipw2100_enable_adapter(priv)) {
+                       printk(KERN_WARNING DRV_NAME
+                              ": %s: failed in call to enable adapter.\n",
+                              priv->net_dev->name);
+                       ipw2100_hw_stop_adapter(priv);
+                       err = -EIO;
+                       goto fail_unlock;
+               }
+
+               /* Start a scan . . . */
+               ipw2100_set_scan_options(priv);
+               ipw2100_start_scan(priv);
+       }
+
+       IPW_DEBUG_INFO("exit\n");
+
+       priv->status |= STATUS_INITIALIZED;
+
+       up(&priv->action_sem);
+
+       return 0;
+
+ fail_unlock:
+       up(&priv->action_sem);
+
+ fail:
+       if (dev) {
+               if (registered)
+                       unregister_netdev(dev);
+
+               ipw2100_hw_stop_adapter(priv);
+
+               ipw2100_disable_interrupts(priv);
+
+               if (dev->irq)
+                       free_irq(dev->irq, priv);
+
+               ipw2100_kill_workqueue(priv);
+
+               /* These are safe to call even if they weren't allocated */
+               ipw2100_queues_free(priv);
+               sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
+
+               free_ieee80211(dev);
+               pci_set_drvdata(pci_dev, NULL);
+       }
+
+       if (base_addr)
+               iounmap(base_addr);
+
+       pci_release_regions(pci_dev);
+       pci_disable_device(pci_dev);
+
+       return err;
+}
+
+static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev)
+{
+       struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
+       struct net_device *dev;
+
+       if (priv) {
+               down(&priv->action_sem);
+
+               priv->status &= ~STATUS_INITIALIZED;
+
+               dev = priv->net_dev;
+               sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
+
+#ifdef CONFIG_PM
+               if (ipw2100_firmware.version)
+                       ipw2100_release_firmware(priv, &ipw2100_firmware);
+#endif
+               /* Take down the hardware */
+               ipw2100_down(priv);
+
+               /* Release the semaphore so that the network subsystem can
+                * complete any needed calls into the driver... */
+               up(&priv->action_sem);
+
+               /* Unregister the device first - this results in close()
+                * being called if the device is open.  If we free storage
+                * first, then close() will crash. */
+               unregister_netdev(dev);
+
+               /* ipw2100_down will ensure that there is no more pending work
+                * in the workqueue's, so we can safely remove them now. */
+               ipw2100_kill_workqueue(priv);
+
+               ipw2100_queues_free(priv);
+
+               /* Free potential debugging firmware snapshot */
+               ipw2100_snapshot_free(priv);
+
+               if (dev->irq)
+                       free_irq(dev->irq, priv);
+
+               if (dev->base_addr)
+                       iounmap((void __iomem *)dev->base_addr);
+
+               free_ieee80211(dev);
+       }
+
+       pci_release_regions(pci_dev);
+       pci_disable_device(pci_dev);
+
+       IPW_DEBUG_INFO("exit\n");
+}
+
+
+#ifdef CONFIG_PM
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
+static int ipw2100_suspend(struct pci_dev *pci_dev, u32 state)
+#else
+static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state)
+#endif
+{
+       struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
+       struct net_device *dev = priv->net_dev;
+
+       IPW_DEBUG_INFO("%s: Going into suspend...\n",
+              dev->name);
+
+       down(&priv->action_sem);
+       if (priv->status & STATUS_INITIALIZED) {
+               /* Take down the device; powers it off, etc. */
+               ipw2100_down(priv);
+       }
+
+       /* Remove the PRESENT state of the device */
+       netif_device_detach(dev);
+
+       pci_save_state(pci_dev);
+       pci_disable_device (pci_dev);
+       pci_set_power_state(pci_dev, PCI_D3hot);
+
+       up(&priv->action_sem);
+
+       return 0;
+}
+
+static int ipw2100_resume(struct pci_dev *pci_dev)
+{
+       struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
+       struct net_device *dev = priv->net_dev;
+       u32 val;
+
+       if (IPW2100_PM_DISABLED)
+               return 0;
+
+       down(&priv->action_sem);
+
+       IPW_DEBUG_INFO("%s: Coming out of suspend...\n",
+              dev->name);
+
+       pci_set_power_state(pci_dev, PCI_D0);
+       pci_enable_device(pci_dev);
+       pci_restore_state(pci_dev);
+
+       /*
+        * Suspend/Resume resets the PCI configuration space, so we have to
+        * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
+        * from interfering with C3 CPU state. pci_restore_state won't help
+        * here since it only restores the first 64 bytes pci config header.
+        */
+       pci_read_config_dword(pci_dev, 0x40, &val);
+       if ((val & 0x0000ff00) != 0)
+               pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
+
+       /* Set the device back into the PRESENT state; this will also wake
+        * the queue of needed */
+       netif_device_attach(dev);
+
+        /* Bring the device back up */
+        if (!(priv->status & STATUS_RF_KILL_SW))
+                ipw2100_up(priv, 0);
+
+       up(&priv->action_sem);
+
+       return 0;
+}
+#endif
+
+
+#define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x }
+
+static struct pci_device_id ipw2100_pci_id_table[] __devinitdata = {
+       IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */
+       IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */
+       IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */
+       IPW2100_DEV_ID(0x2525), /* IN 2100A mPCI 3B */
+       IPW2100_DEV_ID(0x2526), /* IN 2100A mPCI Gen A3 */
+       IPW2100_DEV_ID(0x2522), /* IN 2100 mPCI 3B */
+       IPW2100_DEV_ID(0x2523), /* IN 2100 mPCI 3A */
+       IPW2100_DEV_ID(0x2527), /* IN 2100 mPCI 3B */
+       IPW2100_DEV_ID(0x2528), /* IN 2100 mPCI 3B */
+       IPW2100_DEV_ID(0x2529), /* IN 2100 mPCI 3B */
+       IPW2100_DEV_ID(0x252B), /* IN 2100 mPCI 3A */
+       IPW2100_DEV_ID(0x252C), /* IN 2100 mPCI 3A */
+       IPW2100_DEV_ID(0x252D), /* IN 2100 mPCI 3A */
+
+       IPW2100_DEV_ID(0x2550), /* IB 2100A mPCI 3B */
+       IPW2100_DEV_ID(0x2551), /* IB 2100 mPCI 3B */
+       IPW2100_DEV_ID(0x2553), /* IB 2100 mPCI 3B */
+       IPW2100_DEV_ID(0x2554), /* IB 2100 mPCI 3B */
+       IPW2100_DEV_ID(0x2555), /* IB 2100 mPCI 3B */
+
+       IPW2100_DEV_ID(0x2560), /* DE 2100A mPCI 3A */
+       IPW2100_DEV_ID(0x2562), /* DE 2100A mPCI 3A */
+       IPW2100_DEV_ID(0x2563), /* DE 2100A mPCI 3A */
+       IPW2100_DEV_ID(0x2561), /* DE 2100 mPCI 3A */
+       IPW2100_DEV_ID(0x2565), /* DE 2100 mPCI 3A */
+       IPW2100_DEV_ID(0x2566), /* DE 2100 mPCI 3A */
+       IPW2100_DEV_ID(0x2567), /* DE 2100 mPCI 3A */
+
+       IPW2100_DEV_ID(0x2570), /* GA 2100 mPCI 3B */
+
+       IPW2100_DEV_ID(0x2580), /* TO 2100A mPCI 3B */
+       IPW2100_DEV_ID(0x2582), /* TO 2100A mPCI 3B */
+       IPW2100_DEV_ID(0x2583), /* TO 2100A mPCI 3B */
+       IPW2100_DEV_ID(0x2581), /* TO 2100 mPCI 3B */
+       IPW2100_DEV_ID(0x2585), /* TO 2100 mPCI 3B */
+       IPW2100_DEV_ID(0x2586), /* TO 2100 mPCI 3B */
+       IPW2100_DEV_ID(0x2587), /* TO 2100 mPCI 3B */
+
+       IPW2100_DEV_ID(0x2590), /* SO 2100A mPCI 3B */
+       IPW2100_DEV_ID(0x2592), /* SO 2100A mPCI 3B */
+       IPW2100_DEV_ID(0x2591), /* SO 2100 mPCI 3B */
+       IPW2100_DEV_ID(0x2593), /* SO 2100 mPCI 3B */
+       IPW2100_DEV_ID(0x2596), /* SO 2100 mPCI 3B */
+       IPW2100_DEV_ID(0x2598), /* SO 2100 mPCI 3B */
+
+       IPW2100_DEV_ID(0x25A0), /* HP 2100 mPCI 3B */
+       {0,},
+};
+
+MODULE_DEVICE_TABLE(pci, ipw2100_pci_id_table);
+
+static struct pci_driver ipw2100_pci_driver = {
+       .name = DRV_NAME,
+       .id_table = ipw2100_pci_id_table,
+       .probe = ipw2100_pci_init_one,
+       .remove = __devexit_p(ipw2100_pci_remove_one),
+#ifdef CONFIG_PM
+       .suspend = ipw2100_suspend,
+       .resume = ipw2100_resume,
+#endif
+};
+
+
+/**
+ * Initialize the ipw2100 driver/module
+ *
+ * @returns 0 if ok, < 0 errno node con error.
+ *
+ * Note: we cannot init the /proc stuff until the PCI driver is there,
+ * or we risk an unlikely race condition on someone accessing
+ * uninitialized data in the PCI dev struct through /proc.
+ */
+static int __init ipw2100_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
+       printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
+
+#ifdef CONFIG_IEEE80211_NOWEP
+       IPW_DEBUG_INFO(DRV_NAME ": Compiled with WEP disabled.\n");
+#endif
+
+       ret = pci_module_init(&ipw2100_pci_driver);
+
+#ifdef CONFIG_IPW_DEBUG
+       ipw2100_debug_level = debug;
+       driver_create_file(&ipw2100_pci_driver.driver,
+                          &driver_attr_debug_level);
+#endif
+
+       return ret;
+}
+
+
+/**
+ * Cleanup ipw2100 driver registration
+ */
+static void __exit ipw2100_exit(void)
+{
+       /* FIXME: IPG: check that we have no instances of the devices open */
+#ifdef CONFIG_IPW_DEBUG
+       driver_remove_file(&ipw2100_pci_driver.driver,
+                          &driver_attr_debug_level);
+#endif
+       pci_unregister_driver(&ipw2100_pci_driver);
+}
+
+module_init(ipw2100_init);
+module_exit(ipw2100_exit);
+
+#define WEXT_USECHANNELS 1
+
+static const long ipw2100_frequencies[] = {
+       2412, 2417, 2422, 2427,
+       2432, 2437, 2442, 2447,
+       2452, 2457, 2462, 2467,
+       2472, 2484
+};
+
+#define FREQ_COUNT (sizeof(ipw2100_frequencies) / \
+                    sizeof(ipw2100_frequencies[0]))
+
+static const long ipw2100_rates_11b[] = {
+       1000000,
+       2000000,
+       5500000,
+       11000000
+};
+
+#define RATE_COUNT (sizeof(ipw2100_rates_11b) / sizeof(ipw2100_rates_11b[0]))
+
+static int ipw2100_wx_get_name(struct net_device *dev,
+                              struct iw_request_info *info,
+                              union iwreq_data *wrqu, char *extra)
+{
+       /*
+        * This can be called at any time.  No action lock required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       if (!(priv->status & STATUS_ASSOCIATED))
+               strcpy(wrqu->name, "unassociated");
+       else
+               snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b");
+
+       IPW_DEBUG_WX("Name: %s\n", wrqu->name);
+       return 0;
+}
+
+
+static int ipw2100_wx_set_freq(struct net_device *dev,
+                              struct iw_request_info *info,
+                              union iwreq_data *wrqu, char *extra)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       struct iw_freq *fwrq = &wrqu->freq;
+       int err = 0;
+
+       if (priv->ieee->iw_mode == IW_MODE_INFRA)
+               return -EOPNOTSUPP;
+
+       down(&priv->action_sem);
+       if (!(priv->status & STATUS_INITIALIZED)) {
+               err = -EIO;
+               goto done;
+       }
+
+       /* if setting by freq convert to channel */
+       if (fwrq->e == 1) {
+               if ((fwrq->m >= (int) 2.412e8 &&
+                    fwrq->m <= (int) 2.487e8)) {
+                       int f = fwrq->m / 100000;
+                       int c = 0;
+
+                       while ((c < REG_MAX_CHANNEL) &&
+                              (f != ipw2100_frequencies[c]))
+                               c++;
+
+                       /* hack to fall through */
+                       fwrq->e = 0;
+                       fwrq->m = c + 1;
+               }
+       }
+
+       if (fwrq->e > 0 || fwrq->m > 1000)
+               return -EOPNOTSUPP;
+       else { /* Set the channel */
+               IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m);
+               err = ipw2100_set_channel(priv, fwrq->m, 0);
+       }
+
+ done:
+       up(&priv->action_sem);
+       return err;
+}
+
+
+static int ipw2100_wx_get_freq(struct net_device *dev,
+                              struct iw_request_info *info,
+                              union iwreq_data *wrqu, char *extra)
+{
+       /*
+        * This can be called at any time.  No action lock required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+       wrqu->freq.e = 0;
+
+       /* If we are associated, trying to associate, or have a statically
+        * configured CHANNEL then return that; otherwise return ANY */
+       if (priv->config & CFG_STATIC_CHANNEL ||
+           priv->status & STATUS_ASSOCIATED)
+               wrqu->freq.m = priv->channel;
+       else
+               wrqu->freq.m = 0;
+
+       IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel);
+       return 0;
+
+}
+
+static int ipw2100_wx_set_mode(struct net_device *dev,
+                              struct iw_request_info *info,
+                              union iwreq_data *wrqu, char *extra)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       int err = 0;
+
+       IPW_DEBUG_WX("SET Mode -> %d \n", wrqu->mode);
+
+       if (wrqu->mode == priv->ieee->iw_mode)
+               return 0;
+
+       down(&priv->action_sem);
+       if (!(priv->status & STATUS_INITIALIZED)) {
+               err = -EIO;
+               goto done;
+       }
+
+       switch (wrqu->mode) {
+#ifdef CONFIG_IPW2100_MONITOR
+       case IW_MODE_MONITOR:
+               err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
+               break;
+#endif /* CONFIG_IPW2100_MONITOR */
+       case IW_MODE_ADHOC:
+               err = ipw2100_switch_mode(priv, IW_MODE_ADHOC);
+               break;
+       case IW_MODE_INFRA:
+       case IW_MODE_AUTO:
+       default:
+               err = ipw2100_switch_mode(priv, IW_MODE_INFRA);
+               break;
+       }
+
+done:
+       up(&priv->action_sem);
+       return err;
+}
+
+static int ipw2100_wx_get_mode(struct net_device *dev,
+                              struct iw_request_info *info,
+                              union iwreq_data *wrqu, char *extra)
+{
+       /*
+        * This can be called at any time.  No action lock required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+       wrqu->mode = priv->ieee->iw_mode;
+       IPW_DEBUG_WX("GET Mode -> %d\n", wrqu->mode);
+
+       return 0;
+}
+
+
+#define POWER_MODES 5
+
+/* Values are in microsecond */
+static const s32 timeout_duration[POWER_MODES] = {
+       350000,
+       250000,
+       75000,
+       37000,
+       25000,
+};
+
+static const s32 period_duration[POWER_MODES] = {
+       400000,
+       700000,
+       1000000,
+       1000000,
+       1000000
+};
+
+static int ipw2100_wx_get_range(struct net_device *dev,
+                               struct iw_request_info *info,
+                               union iwreq_data *wrqu, char *extra)
+{
+       /*
+        * This can be called at any time.  No action lock required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       struct iw_range *range = (struct iw_range *)extra;
+       u16 val;
+       int i, level;
+
+       wrqu->data.length = sizeof(*range);
+       memset(range, 0, sizeof(*range));
+
+       /* Let's try to keep this struct in the same order as in
+        * linux/include/wireless.h
+        */
+
+       /* TODO: See what values we can set, and remove the ones we can't
+        * set, or fill them with some default data.
+        */
+
+       /* ~5 Mb/s real (802.11b) */
+       range->throughput = 5 * 1000 * 1000;
+
+//     range->sensitivity;     /* signal level threshold range */
+
+       range->max_qual.qual = 100;
+       /* TODO: Find real max RSSI and stick here */
+       range->max_qual.level = 0;
+       range->max_qual.noise = 0;
+       range->max_qual.updated = 7; /* Updated all three */
+
+       range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */
+       /* TODO: Find real 'good' to 'bad' threshol value for RSSI */
+       range->avg_qual.level = 20 + IPW2100_RSSI_TO_DBM;
+       range->avg_qual.noise = 0;
+       range->avg_qual.updated = 7; /* Updated all three */
+
+       range->num_bitrates = RATE_COUNT;
+
+       for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) {
+               range->bitrate[i] = ipw2100_rates_11b[i];
+       }
+
+       range->min_rts = MIN_RTS_THRESHOLD;
+       range->max_rts = MAX_RTS_THRESHOLD;
+       range->min_frag = MIN_FRAG_THRESHOLD;
+       range->max_frag = MAX_FRAG_THRESHOLD;
+
+       range->min_pmp = period_duration[0];    /* Minimal PM period */
+       range->max_pmp = period_duration[POWER_MODES-1];/* Maximal PM period */
+       range->min_pmt = timeout_duration[POWER_MODES-1];       /* Minimal PM timeout */
+       range->max_pmt = timeout_duration[0];/* Maximal PM timeout */
+
+        /* How to decode max/min PM period */
+       range->pmp_flags = IW_POWER_PERIOD;
+        /* How to decode max/min PM period */
+       range->pmt_flags = IW_POWER_TIMEOUT;
+       /* What PM options are supported */
+       range->pm_capa = IW_POWER_TIMEOUT | IW_POWER_PERIOD;
+
+       range->encoding_size[0] = 5;
+       range->encoding_size[1] = 13;           /* Different token sizes */
+       range->num_encoding_sizes = 2;          /* Number of entry in the list */
+       range->max_encoding_tokens = WEP_KEYS;  /* Max number of tokens */
+//     range->encoding_login_index;            /* token index for login token */
+
+       if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+               range->txpower_capa = IW_TXPOW_DBM;
+               range->num_txpower = IW_MAX_TXPOWER;
+               for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16); i < IW_MAX_TXPOWER;
+                    i++, level -= ((IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM) * 16) /
+                            (IW_MAX_TXPOWER - 1))
+                       range->txpower[i] = level / 16;
+       } else {
+               range->txpower_capa = 0;
+               range->num_txpower = 0;
+       }
+
+
+       /* Set the Wireless Extension versions */
+       range->we_version_compiled = WIRELESS_EXT;
+       range->we_version_source = 16;
+
+//     range->retry_capa;      /* What retry options are supported */
+//     range->retry_flags;     /* How to decode max/min retry limit */
+//     range->r_time_flags;    /* How to decode max/min retry life */
+//     range->min_retry;       /* Minimal number of retries */
+//     range->max_retry;       /* Maximal number of retries */
+//     range->min_r_time;      /* Minimal retry lifetime */
+//     range->max_r_time;      /* Maximal retry lifetime */
+
+        range->num_channels = FREQ_COUNT;
+
+       val = 0;
+       for (i = 0; i < FREQ_COUNT; i++) {
+               // TODO: Include only legal frequencies for some countries
+//             if (local->channel_mask & (1 << i)) {
+                       range->freq[val].i = i + 1;
+                       range->freq[val].m = ipw2100_frequencies[i] * 100000;
+                       range->freq[val].e = 1;
+                       val++;
+//             }
+               if (val == IW_MAX_FREQUENCIES)
+               break;
+       }
+       range->num_frequency = val;
+
+       IPW_DEBUG_WX("GET Range\n");
+
+       return 0;
+}
+
+static int ipw2100_wx_set_wap(struct net_device *dev,
+                             struct iw_request_info *info,
+                             union iwreq_data *wrqu, char *extra)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       int err = 0;
+
+       static const unsigned char any[] = {
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+       };
+       static const unsigned char off[] = {
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+
+       // sanity checks
+       if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
+               return -EINVAL;
+
+       down(&priv->action_sem);
+       if (!(priv->status & STATUS_INITIALIZED)) {
+               err = -EIO;
+               goto done;
+       }
+
+       if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) ||
+           !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) {
+               /* we disable mandatory BSSID association */
+               IPW_DEBUG_WX("exit - disable mandatory BSSID\n");
+               priv->config &= ~CFG_STATIC_BSSID;
+               err = ipw2100_set_mandatory_bssid(priv, NULL, 0);
+               goto done;
+       }
+
+       priv->config |= CFG_STATIC_BSSID;
+       memcpy(priv->mandatory_bssid_mac, wrqu->ap_addr.sa_data, ETH_ALEN);
+
+       err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0);
+
+       IPW_DEBUG_WX("SET BSSID -> %02X:%02X:%02X:%02X:%02X:%02X\n",
+                    wrqu->ap_addr.sa_data[0] & 0xff,
+                    wrqu->ap_addr.sa_data[1] & 0xff,
+                    wrqu->ap_addr.sa_data[2] & 0xff,
+                    wrqu->ap_addr.sa_data[3] & 0xff,
+                    wrqu->ap_addr.sa_data[4] & 0xff,
+                    wrqu->ap_addr.sa_data[5] & 0xff);
+
+ done:
+       up(&priv->action_sem);
+       return err;
+}
+
+static int ipw2100_wx_get_wap(struct net_device *dev,
+                             struct iw_request_info *info,
+                             union iwreq_data *wrqu, char *extra)
+{
+       /*
+        * This can be called at any time.  No action lock required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+       /* If we are associated, trying to associate, or have a statically
+        * configured BSSID then return that; otherwise return ANY */
+       if (priv->config & CFG_STATIC_BSSID ||
+           priv->status & STATUS_ASSOCIATED) {
+               wrqu->ap_addr.sa_family = ARPHRD_ETHER;
+               memcpy(wrqu->ap_addr.sa_data, &priv->bssid, ETH_ALEN);
+       } else
+               memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
+
+       IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n",
+                    MAC_ARG(wrqu->ap_addr.sa_data));
+       return 0;
+}
+
+static int ipw2100_wx_set_essid(struct net_device *dev,
+                               struct iw_request_info *info,
+                               union iwreq_data *wrqu, char *extra)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       char *essid = ""; /* ANY */
+       int length = 0;
+       int err = 0;
+
+       down(&priv->action_sem);
+       if (!(priv->status & STATUS_INITIALIZED)) {
+               err = -EIO;
+               goto done;
+       }
+
+       if (wrqu->essid.flags && wrqu->essid.length) {
+               length = wrqu->essid.length - 1;
+               essid = extra;
+       }
+
+       if (length == 0) {
+               IPW_DEBUG_WX("Setting ESSID to ANY\n");
+               priv->config &= ~CFG_STATIC_ESSID;
+               err = ipw2100_set_essid(priv, NULL, 0, 0);
+               goto done;
+       }
+
+       length = min(length, IW_ESSID_MAX_SIZE);
+
+       priv->config |= CFG_STATIC_ESSID;
+
+       if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) {
+               IPW_DEBUG_WX("ESSID set to current ESSID.\n");
+               err = 0;
+               goto done;
+       }
+
+       IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(essid, length),
+                    length);
+
+       priv->essid_len = length;
+       memcpy(priv->essid, essid, priv->essid_len);
+
+       err = ipw2100_set_essid(priv, essid, length, 0);
+
+ done:
+       up(&priv->action_sem);
+       return err;
+}
+
+static int ipw2100_wx_get_essid(struct net_device *dev,
+                               struct iw_request_info *info,
+                               union iwreq_data *wrqu, char *extra)
+{
+       /*
+        * This can be called at any time.  No action lock required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+       /* If we are associated, trying to associate, or have a statically
+        * configured ESSID then return that; otherwise return ANY */
+       if (priv->config & CFG_STATIC_ESSID ||
+           priv->status & STATUS_ASSOCIATED) {
+               IPW_DEBUG_WX("Getting essid: '%s'\n",
+                            escape_essid(priv->essid, priv->essid_len));
+               memcpy(extra, priv->essid, priv->essid_len);
+               wrqu->essid.length = priv->essid_len;
+               wrqu->essid.flags = 1; /* active */
+       } else {
+               IPW_DEBUG_WX("Getting essid: ANY\n");
+               wrqu->essid.length = 0;
+               wrqu->essid.flags = 0; /* active */
+       }
+
+       return 0;
+}
+
+static int ipw2100_wx_set_nick(struct net_device *dev,
+                              struct iw_request_info *info,
+                              union iwreq_data *wrqu, char *extra)
+{
+       /*
+        * This can be called at any time.  No action lock required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+       if (wrqu->data.length > IW_ESSID_MAX_SIZE)
+               return -E2BIG;
+
+       wrqu->data.length = min((size_t)wrqu->data.length, sizeof(priv->nick));
+       memset(priv->nick, 0, sizeof(priv->nick));
+       memcpy(priv->nick, extra,  wrqu->data.length);
+
+       IPW_DEBUG_WX("SET Nickname -> %s \n", priv->nick);
+
+       return 0;
+}
+
+static int ipw2100_wx_get_nick(struct net_device *dev,
+                              struct iw_request_info *info,
+                              union iwreq_data *wrqu, char *extra)
+{
+       /*
+        * This can be called at any time.  No action lock required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+       wrqu->data.length = strlen(priv->nick) + 1;
+       memcpy(extra, priv->nick, wrqu->data.length);
+       wrqu->data.flags = 1; /* active */
+
+       IPW_DEBUG_WX("GET Nickname -> %s \n", extra);
+
+       return 0;
+}
+
+static int ipw2100_wx_set_rate(struct net_device *dev,
+                              struct iw_request_info *info,
+                              union iwreq_data *wrqu, char *extra)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       u32 target_rate = wrqu->bitrate.value;
+       u32 rate;
+       int err = 0;
+
+       down(&priv->action_sem);
+       if (!(priv->status & STATUS_INITIALIZED)) {
+               err = -EIO;
+               goto done;
+       }
+
+       rate = 0;
+
+       if (target_rate == 1000000 ||
+           (!wrqu->bitrate.fixed && target_rate > 1000000))
+               rate |= TX_RATE_1_MBIT;
+       if (target_rate == 2000000 ||
+           (!wrqu->bitrate.fixed && target_rate > 2000000))
+               rate |= TX_RATE_2_MBIT;
+       if (target_rate == 5500000 ||
+           (!wrqu->bitrate.fixed && target_rate > 5500000))
+               rate |= TX_RATE_5_5_MBIT;
+       if (target_rate == 11000000 ||
+           (!wrqu->bitrate.fixed && target_rate > 11000000))
+               rate |= TX_RATE_11_MBIT;
+       if (rate == 0)
+               rate = DEFAULT_TX_RATES;
+
+       err = ipw2100_set_tx_rates(priv, rate, 0);
+
+       IPW_DEBUG_WX("SET Rate -> %04X \n", rate);
+ done:
+       up(&priv->action_sem);
+       return err;
+}
+
+
+static int ipw2100_wx_get_rate(struct net_device *dev,
+                              struct iw_request_info *info,
+                              union iwreq_data *wrqu, char *extra)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       int val;
+       int len = sizeof(val);
+       int err = 0;
+
+       if (!(priv->status & STATUS_ENABLED) ||
+           priv->status & STATUS_RF_KILL_MASK ||
+           !(priv->status & STATUS_ASSOCIATED)) {
+               wrqu->bitrate.value = 0;
+               return 0;
+       }
+
+       down(&priv->action_sem);
+       if (!(priv->status & STATUS_INITIALIZED)) {
+               err = -EIO;
+               goto done;
+       }
+
+       err = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &val, &len);
+       if (err) {
+               IPW_DEBUG_WX("failed querying ordinals.\n");
+               return err;
+       }
+
+       switch (val & TX_RATE_MASK) {
+       case TX_RATE_1_MBIT:
+               wrqu->bitrate.value = 1000000;
+               break;
+       case TX_RATE_2_MBIT:
+               wrqu->bitrate.value = 2000000;
+               break;
+       case TX_RATE_5_5_MBIT:
+               wrqu->bitrate.value = 5500000;
+               break;
+       case TX_RATE_11_MBIT:
+               wrqu->bitrate.value = 11000000;
+               break;
+       default:
+               wrqu->bitrate.value = 0;
+       }
+
+       IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value);
+
+ done:
+       up(&priv->action_sem);
+       return err;
+}
+
+static int ipw2100_wx_set_rts(struct net_device *dev,
+                             struct iw_request_info *info,
+                             union iwreq_data *wrqu, char *extra)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       int value, err;
+
+       /* Auto RTS not yet supported */
+       if (wrqu->rts.fixed == 0)
+               return -EINVAL;
+
+       down(&priv->action_sem);
+       if (!(priv->status & STATUS_INITIALIZED)) {
+               err = -EIO;
+               goto done;
+       }
+
+       if (wrqu->rts.disabled)
+               value = priv->rts_threshold | RTS_DISABLED;
+       else {
+               if (wrqu->rts.value < 1 ||
+                   wrqu->rts.value > 2304) {
+                       err = -EINVAL;
+                       goto done;
+               }
+               value = wrqu->rts.value;
+       }
+
+       err = ipw2100_set_rts_threshold(priv, value);
+
+       IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X \n", value);
+ done:
+       up(&priv->action_sem);
+       return err;
+}
+
+static int ipw2100_wx_get_rts(struct net_device *dev,
+                             struct iw_request_info *info,
+                             union iwreq_data *wrqu, char *extra)
+{
+       /*
+        * This can be called at any time.  No action lock required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+       wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED;
+       wrqu->rts.fixed = 1; /* no auto select */
+
+       /* If RTS is set to the default value, then it is disabled */
+       wrqu->rts.disabled = (priv->rts_threshold & RTS_DISABLED) ? 1 : 0;
+
+       IPW_DEBUG_WX("GET RTS Threshold -> 0x%08X \n", wrqu->rts.value);
+
+       return 0;
+}
+
+static int ipw2100_wx_set_txpow(struct net_device *dev,
+                               struct iw_request_info *info,
+                               union iwreq_data *wrqu, char *extra)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       int err = 0, value;
+
+       if (priv->ieee->iw_mode != IW_MODE_ADHOC)
+               return -EINVAL;
+
+       if (wrqu->txpower.disabled == 1 || wrqu->txpower.fixed == 0)
+               value = IPW_TX_POWER_DEFAULT;
+       else {
+               if (wrqu->txpower.value < IPW_TX_POWER_MIN_DBM ||
+                   wrqu->txpower.value > IPW_TX_POWER_MAX_DBM)
+                       return -EINVAL;
+
+               value = (wrqu->txpower.value - IPW_TX_POWER_MIN_DBM) * 16 /
+                       (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM);
+       }
+
+       down(&priv->action_sem);
+       if (!(priv->status & STATUS_INITIALIZED)) {
+               err = -EIO;
+               goto done;
+       }
+
+       err = ipw2100_set_tx_power(priv, value);
+
+       IPW_DEBUG_WX("SET TX Power -> %d \n", value);
+
+ done:
+       up(&priv->action_sem);
+       return err;
+}
+
+static int ipw2100_wx_get_txpow(struct net_device *dev,
+                               struct iw_request_info *info,
+                               union iwreq_data *wrqu, char *extra)
+{
+       /*
+        * This can be called at any time.  No action lock required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+       if (priv->ieee->iw_mode != IW_MODE_ADHOC) {
+               wrqu->power.disabled = 1;
+               return 0;
+       }
+
+       if (priv->tx_power == IPW_TX_POWER_DEFAULT) {
+               wrqu->power.fixed = 0;
+               wrqu->power.value = IPW_TX_POWER_MAX_DBM;
+               wrqu->power.disabled = 1;
+       } else {
+               wrqu->power.disabled = 0;
+               wrqu->power.fixed = 1;
+               wrqu->power.value =
+                       (priv->tx_power *
+                        (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM)) /
+                       (IPW_TX_POWER_MAX - IPW_TX_POWER_MIN) +
+                       IPW_TX_POWER_MIN_DBM;
+       }
+
+       wrqu->power.flags = IW_TXPOW_DBM;
+
+       IPW_DEBUG_WX("GET TX Power -> %d \n", wrqu->power.value);
+
+       return 0;
+}
+
+static int ipw2100_wx_set_frag(struct net_device *dev,
+                              struct iw_request_info *info,
+                              union iwreq_data *wrqu, char *extra)
+{
+       /*
+        * This can be called at any time.  No action lock required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+       if (!wrqu->frag.fixed)
+               return -EINVAL;
+
+       if (wrqu->frag.disabled) {
+               priv->frag_threshold |= FRAG_DISABLED;
+               priv->ieee->fts = DEFAULT_FTS;
+       } else {
+               if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
+                   wrqu->frag.value > MAX_FRAG_THRESHOLD)
+                       return -EINVAL;
+
+               priv->ieee->fts = wrqu->frag.value & ~0x1;
+               priv->frag_threshold = priv->ieee->fts;
+       }
+
+       IPW_DEBUG_WX("SET Frag Threshold -> %d \n", priv->ieee->fts);
+
+       return 0;
+}
+
+static int ipw2100_wx_get_frag(struct net_device *dev,
+                              struct iw_request_info *info,
+                              union iwreq_data *wrqu, char *extra)
+{
+       /*
+        * This can be called at any time.  No action lock required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       wrqu->frag.value = priv->frag_threshold & ~FRAG_DISABLED;
+       wrqu->frag.fixed = 0;   /* no auto select */
+       wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0;
+
+       IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value);
+
+       return 0;
+}
+
+static int ipw2100_wx_set_retry(struct net_device *dev,
+                               struct iw_request_info *info,
+                               union iwreq_data *wrqu, char *extra)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       int err = 0;
+
+       if (wrqu->retry.flags & IW_RETRY_LIFETIME ||
+           wrqu->retry.disabled)
+               return -EINVAL;
+
+       if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
+               return 0;
+
+       down(&priv->action_sem);
+       if (!(priv->status & STATUS_INITIALIZED)) {
+               err = -EIO;
+               goto done;
+       }
+
+       if (wrqu->retry.flags & IW_RETRY_MIN) {
+               err = ipw2100_set_short_retry(priv, wrqu->retry.value);
+               IPW_DEBUG_WX("SET Short Retry Limit -> %d \n",
+                      wrqu->retry.value);
+               goto done;
+       }
+
+       if (wrqu->retry.flags & IW_RETRY_MAX) {
+               err = ipw2100_set_long_retry(priv, wrqu->retry.value);
+               IPW_DEBUG_WX("SET Long Retry Limit -> %d \n",
+                      wrqu->retry.value);
+               goto done;
+       }
+
+       err = ipw2100_set_short_retry(priv, wrqu->retry.value);
+       if (!err)
+               err = ipw2100_set_long_retry(priv, wrqu->retry.value);
+
+       IPW_DEBUG_WX("SET Both Retry Limits -> %d \n", wrqu->retry.value);
+
+ done:
+       up(&priv->action_sem);
+       return err;
+}
+
+static int ipw2100_wx_get_retry(struct net_device *dev,
+                               struct iw_request_info *info,
+                               union iwreq_data *wrqu, char *extra)
+{
+       /*
+        * This can be called at any time.  No action lock required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+       wrqu->retry.disabled = 0; /* can't be disabled */
+
+       if ((wrqu->retry.flags & IW_RETRY_TYPE) ==
+           IW_RETRY_LIFETIME)
+               return -EINVAL;
+
+       if (wrqu->retry.flags & IW_RETRY_MAX) {
+               wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MAX;
+               wrqu->retry.value = priv->long_retry_limit;
+       } else {
+               wrqu->retry.flags =
+                   (priv->short_retry_limit !=
+                    priv->long_retry_limit) ?
+                   IW_RETRY_LIMIT & IW_RETRY_MIN : IW_RETRY_LIMIT;
+
+               wrqu->retry.value = priv->short_retry_limit;
+       }
+
+       IPW_DEBUG_WX("GET Retry -> %d \n", wrqu->retry.value);
+
+       return 0;
+}
+
+static int ipw2100_wx_set_scan(struct net_device *dev,
+                              struct iw_request_info *info,
+                              union iwreq_data *wrqu, char *extra)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       int err = 0;
+
+       down(&priv->action_sem);
+       if (!(priv->status & STATUS_INITIALIZED)) {
+               err = -EIO;
+               goto done;
+       }
+
+       IPW_DEBUG_WX("Initiating scan...\n");
+       if (ipw2100_set_scan_options(priv) ||
+           ipw2100_start_scan(priv)) {
+               IPW_DEBUG_WX("Start scan failed.\n");
+
+               /* TODO: Mark a scan as pending so when hardware initialized
+                *       a scan starts */
+       }
+
+ done:
+       up(&priv->action_sem);
+       return err;
+}
+
+static int ipw2100_wx_get_scan(struct net_device *dev,
+                              struct iw_request_info *info,
+                              union iwreq_data *wrqu, char *extra)
+{
+       /*
+        * This can be called at any time.  No action lock required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra);
+}
+
+
+/*
+ * Implementation based on code in hostap-driver v0.1.3 hostap_ioctl.c
+ */
+static int ipw2100_wx_set_encode(struct net_device *dev,
+                                struct iw_request_info *info,
+                                union iwreq_data *wrqu, char *key)
+{
+       /*
+        * No check of STATUS_INITIALIZED required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       return ieee80211_wx_set_encode(priv->ieee, info, wrqu, key);
+}
+
+static int ipw2100_wx_get_encode(struct net_device *dev,
+                                struct iw_request_info *info,
+                                union iwreq_data *wrqu, char *key)
+{
+       /*
+        * This can be called at any time.  No action lock required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key);
+}
+
+static int ipw2100_wx_set_power(struct net_device *dev,
+                               struct iw_request_info *info,
+                               union iwreq_data *wrqu, char *extra)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       int err = 0;
+
+       down(&priv->action_sem);
+       if (!(priv->status & STATUS_INITIALIZED)) {
+               err = -EIO;
+               goto done;
+       }
+
+       if (wrqu->power.disabled) {
+               priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
+               err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
+               IPW_DEBUG_WX("SET Power Management Mode -> off\n");
+               goto done;
+       }
+
+       switch (wrqu->power.flags & IW_POWER_MODE) {
+       case IW_POWER_ON:    /* If not specified */
+       case IW_POWER_MODE:  /* If set all mask */
+       case IW_POWER_ALL_R: /* If explicitely state all */
+               break;
+       default: /* Otherwise we don't support it */
+               IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
+                            wrqu->power.flags);
+               err = -EOPNOTSUPP;
+               goto done;
+       }
+
+       /* If the user hasn't specified a power management mode yet, default
+        * to BATTERY */
+       priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
+       err = ipw2100_set_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
+
+       IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n",
+                    priv->power_mode);
+
+ done:
+       up(&priv->action_sem);
+       return err;
+
+}
+
+static int ipw2100_wx_get_power(struct net_device *dev,
+                               struct iw_request_info *info,
+                               union iwreq_data *wrqu, char *extra)
+{
+       /*
+        * This can be called at any time.  No action lock required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+       if (!(priv->power_mode & IPW_POWER_ENABLED)) {
+               wrqu->power.disabled = 1;
+       } else {
+               wrqu->power.disabled = 0;
+               wrqu->power.flags = 0;
+       }
+
+       IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode);
+
+       return 0;
+}
+
+
+/*
+ *
+ * IWPRIV handlers
+ *
+ */
+#ifdef CONFIG_IPW2100_MONITOR
+static int ipw2100_wx_set_promisc(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 union iwreq_data *wrqu, char *extra)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       int *parms = (int *)extra;
+       int enable = (parms[0] > 0);
+       int err = 0;
+
+       down(&priv->action_sem);
+       if (!(priv->status & STATUS_INITIALIZED)) {
+               err = -EIO;
+               goto done;
+       }
+
+       if (enable) {
+               if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+                       err = ipw2100_set_channel(priv, parms[1], 0);
+                       goto done;
+               }
+               priv->channel = parms[1];
+               err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
+       } else {
+               if (priv->ieee->iw_mode == IW_MODE_MONITOR)
+                       err = ipw2100_switch_mode(priv, priv->last_mode);
+       }
+ done:
+       up(&priv->action_sem);
+       return err;
+}
+
+static int ipw2100_wx_reset(struct net_device *dev,
+                           struct iw_request_info *info,
+                           union iwreq_data *wrqu, char *extra)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       if (priv->status & STATUS_INITIALIZED)
+               schedule_reset(priv);
+       return 0;
+}
+
+#endif
+
+static int ipw2100_wx_set_powermode(struct net_device *dev,
+                                   struct iw_request_info *info,
+                                   union iwreq_data *wrqu, char *extra)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       int err = 0, mode = *(int *)extra;
+
+       down(&priv->action_sem);
+       if (!(priv->status & STATUS_INITIALIZED)) {
+               err = -EIO;
+               goto done;
+       }
+
+       if ((mode < 1) || (mode > POWER_MODES))
+               mode = IPW_POWER_AUTO;
+
+       if (priv->power_mode != mode)
+               err = ipw2100_set_power_mode(priv, mode);
+ done:
+       up(&priv->action_sem);
+       return err;
+}
+
+#define MAX_POWER_STRING 80
+static int ipw2100_wx_get_powermode(struct net_device *dev,
+                                   struct iw_request_info *info,
+                                   union iwreq_data *wrqu, char *extra)
+{
+       /*
+        * This can be called at any time.  No action lock required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       int level = IPW_POWER_LEVEL(priv->power_mode);
+       s32 timeout, period;
+
+       if (!(priv->power_mode & IPW_POWER_ENABLED)) {
+               snprintf(extra, MAX_POWER_STRING,
+                        "Power save level: %d (Off)", level);
+       } else {
+               switch (level) {
+               case IPW_POWER_MODE_CAM:
+                       snprintf(extra, MAX_POWER_STRING,
+                                "Power save level: %d (None)", level);
+                       break;
+               case IPW_POWER_AUTO:
+               snprintf(extra, MAX_POWER_STRING,
+                        "Power save level: %d (Auto)", 0);
+                       break;
+               default:
+                       timeout = timeout_duration[level - 1] / 1000;
+                       period = period_duration[level - 1] / 1000;
+                       snprintf(extra, MAX_POWER_STRING,
+                                "Power save level: %d "
+                                "(Timeout %dms, Period %dms)",
+                                level, timeout, period);
+               }
+       }
+
+       wrqu->data.length = strlen(extra) + 1;
+
+       return 0;
+}
+
+
+static int ipw2100_wx_set_preamble(struct net_device *dev,
+                                  struct iw_request_info *info,
+                                  union iwreq_data *wrqu, char *extra)
+{
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       int err, mode = *(int *)extra;
+
+       down(&priv->action_sem);
+       if (!(priv->status & STATUS_INITIALIZED)) {
+               err = -EIO;
+               goto done;
+       }
+
+       if (mode == 1)
+               priv->config |= CFG_LONG_PREAMBLE;
+       else if (mode == 0)
+               priv->config &= ~CFG_LONG_PREAMBLE;
+       else {
+               err = -EINVAL;
+               goto done;
+       }
+
+       err = ipw2100_system_config(priv, 0);
+
+done:
+       up(&priv->action_sem);
+       return err;
+}
+
+static int ipw2100_wx_get_preamble(struct net_device *dev,
+                                   struct iw_request_info *info,
+                                   union iwreq_data *wrqu, char *extra)
+{
+       /*
+        * This can be called at any time.  No action lock required
+        */
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+       if (priv->config & CFG_LONG_PREAMBLE)
+               snprintf(wrqu->name, IFNAMSIZ, "long (1)");
+       else
+               snprintf(wrqu->name, IFNAMSIZ, "auto (0)");
+
+       return 0;
+}
+
+static iw_handler ipw2100_wx_handlers[] =
+{
+        NULL,                     /* SIOCSIWCOMMIT */
+        ipw2100_wx_get_name,      /* SIOCGIWNAME */
+        NULL,                     /* SIOCSIWNWID */
+        NULL,                     /* SIOCGIWNWID */
+        ipw2100_wx_set_freq,      /* SIOCSIWFREQ */
+        ipw2100_wx_get_freq,      /* SIOCGIWFREQ */
+        ipw2100_wx_set_mode,      /* SIOCSIWMODE */
+        ipw2100_wx_get_mode,      /* SIOCGIWMODE */
+        NULL,                     /* SIOCSIWSENS */
+        NULL,                     /* SIOCGIWSENS */
+        NULL,                     /* SIOCSIWRANGE */
+        ipw2100_wx_get_range,     /* SIOCGIWRANGE */
+        NULL,                     /* SIOCSIWPRIV */
+        NULL,                     /* SIOCGIWPRIV */
+        NULL,                     /* SIOCSIWSTATS */
+        NULL,                     /* SIOCGIWSTATS */
+        NULL,                     /* SIOCSIWSPY */
+        NULL,                     /* SIOCGIWSPY */
+        NULL,                     /* SIOCGIWTHRSPY */
+        NULL,                     /* SIOCWIWTHRSPY */
+        ipw2100_wx_set_wap,       /* SIOCSIWAP */
+        ipw2100_wx_get_wap,       /* SIOCGIWAP */
+        NULL,                     /* -- hole -- */
+        NULL,                     /* SIOCGIWAPLIST -- deprecated */
+        ipw2100_wx_set_scan,      /* SIOCSIWSCAN */
+        ipw2100_wx_get_scan,      /* SIOCGIWSCAN */
+        ipw2100_wx_set_essid,     /* SIOCSIWESSID */
+        ipw2100_wx_get_essid,     /* SIOCGIWESSID */
+        ipw2100_wx_set_nick,      /* SIOCSIWNICKN */
+        ipw2100_wx_get_nick,      /* SIOCGIWNICKN */
+        NULL,                     /* -- hole -- */
+        NULL,                     /* -- hole -- */
+        ipw2100_wx_set_rate,      /* SIOCSIWRATE */
+        ipw2100_wx_get_rate,      /* SIOCGIWRATE */
+        ipw2100_wx_set_rts,       /* SIOCSIWRTS */
+        ipw2100_wx_get_rts,       /* SIOCGIWRTS */
+        ipw2100_wx_set_frag,      /* SIOCSIWFRAG */
+        ipw2100_wx_get_frag,      /* SIOCGIWFRAG */
+        ipw2100_wx_set_txpow,     /* SIOCSIWTXPOW */
+        ipw2100_wx_get_txpow,     /* SIOCGIWTXPOW */
+        ipw2100_wx_set_retry,     /* SIOCSIWRETRY */
+        ipw2100_wx_get_retry,     /* SIOCGIWRETRY */
+        ipw2100_wx_set_encode,    /* SIOCSIWENCODE */
+        ipw2100_wx_get_encode,    /* SIOCGIWENCODE */
+        ipw2100_wx_set_power,     /* SIOCSIWPOWER */
+        ipw2100_wx_get_power,     /* SIOCGIWPOWER */
+};
+
+#define IPW2100_PRIV_SET_MONITOR       SIOCIWFIRSTPRIV
+#define IPW2100_PRIV_RESET             SIOCIWFIRSTPRIV+1
+#define IPW2100_PRIV_SET_POWER         SIOCIWFIRSTPRIV+2
+#define IPW2100_PRIV_GET_POWER         SIOCIWFIRSTPRIV+3
+#define IPW2100_PRIV_SET_LONGPREAMBLE  SIOCIWFIRSTPRIV+4
+#define IPW2100_PRIV_GET_LONGPREAMBLE  SIOCIWFIRSTPRIV+5
+
+static const struct iw_priv_args ipw2100_private_args[] = {
+
+#ifdef CONFIG_IPW2100_MONITOR
+       {
+               IPW2100_PRIV_SET_MONITOR,
+               IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"
+       },
+       {
+               IPW2100_PRIV_RESET,
+               IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"
+       },
+#endif /* CONFIG_IPW2100_MONITOR */
+
+       {
+               IPW2100_PRIV_SET_POWER,
+               IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power"
+       },
+       {
+               IPW2100_PRIV_GET_POWER,
+               0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING, "get_power"
+       },
+       {
+               IPW2100_PRIV_SET_LONGPREAMBLE,
+               IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"
+       },
+       {
+               IPW2100_PRIV_GET_LONGPREAMBLE,
+               0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble"
+       },
+};
+
+static iw_handler ipw2100_private_handler[] = {
+#ifdef CONFIG_IPW2100_MONITOR
+       ipw2100_wx_set_promisc,
+       ipw2100_wx_reset,
+#else /* CONFIG_IPW2100_MONITOR */
+       NULL,
+       NULL,
+#endif /* CONFIG_IPW2100_MONITOR */
+       ipw2100_wx_set_powermode,
+       ipw2100_wx_get_powermode,
+       ipw2100_wx_set_preamble,
+       ipw2100_wx_get_preamble,
+};
+
+static struct iw_handler_def ipw2100_wx_handler_def =
+{
+       .standard = ipw2100_wx_handlers,
+       .num_standard = sizeof(ipw2100_wx_handlers) / sizeof(iw_handler),
+       .num_private = sizeof(ipw2100_private_handler) / sizeof(iw_handler),
+       .num_private_args = sizeof(ipw2100_private_args) /
+       sizeof(struct iw_priv_args),
+       .private = (iw_handler *)ipw2100_private_handler,
+       .private_args = (struct iw_priv_args *)ipw2100_private_args,
+};
+
+/*
+ * Get wireless statistics.
+ * Called by /proc/net/wireless
+ * Also called by SIOCGIWSTATS
+ */
+static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev)
+{
+       enum {
+               POOR = 30,
+               FAIR = 60,
+               GOOD = 80,
+               VERY_GOOD = 90,
+               EXCELLENT = 95,
+               PERFECT = 100
+       };
+       int rssi_qual;
+       int tx_qual;
+       int beacon_qual;
+
+       struct ipw2100_priv *priv = ieee80211_priv(dev);
+       struct iw_statistics *wstats;
+       u32 rssi, quality, tx_retries, missed_beacons, tx_failures;
+       u32 ord_len = sizeof(u32);
+
+       if (!priv)
+               return (struct iw_statistics *) NULL;
+
+       wstats = &priv->wstats;
+
+       /* if hw is disabled, then ipw2100_get_ordinal() can't be called.
+        * ipw2100_wx_wireless_stats seems to be called before fw is
+        * initialized.  STATUS_ASSOCIATED will only be set if the hw is up
+        * and associated; if not associcated, the values are all meaningless
+        * anyway, so set them all to NULL and INVALID */
+       if (!(priv->status & STATUS_ASSOCIATED)) {
+               wstats->miss.beacon = 0;
+               wstats->discard.retries = 0;
+               wstats->qual.qual = 0;
+               wstats->qual.level = 0;
+               wstats->qual.noise = 0;
+               wstats->qual.updated = 7;
+               wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
+                       IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
+               return wstats;
+       }
+
+       if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_MISSED_BCNS,
+                               &missed_beacons, &ord_len))
+               goto fail_get_ordinal;
+
+        /* If we don't have a connection the quality and level is 0*/
+       if (!(priv->status & STATUS_ASSOCIATED)) {
+               wstats->qual.qual = 0;
+               wstats->qual.level = 0;
+       } else {
+               if (ipw2100_get_ordinal(priv, IPW_ORD_RSSI_AVG_CURR,
+                                       &rssi, &ord_len))
+                       goto fail_get_ordinal;
+               wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
+               if (rssi < 10)
+                       rssi_qual = rssi * POOR / 10;
+               else if (rssi < 15)
+                       rssi_qual = (rssi - 10) * (FAIR - POOR) / 5 + POOR;
+               else if (rssi < 20)
+                       rssi_qual = (rssi - 15) * (GOOD - FAIR) / 5 + FAIR;
+               else if (rssi < 30)
+                       rssi_qual = (rssi - 20) * (VERY_GOOD - GOOD) /
+                               10 + GOOD;
+               else
+                       rssi_qual = (rssi - 30) * (PERFECT - VERY_GOOD) /
+                               10 + VERY_GOOD;
+
+               if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_RETRIES,
+                                       &tx_retries, &ord_len))
+                       goto fail_get_ordinal;
+
+               if (tx_retries > 75)
+                       tx_qual = (90 - tx_retries) * POOR / 15;
+               else if (tx_retries > 70)
+                       tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
+               else if (tx_retries > 65)
+                       tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
+               else if (tx_retries > 50)
+                       tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
+                               15 + GOOD;
+               else
+                       tx_qual = (50 - tx_retries) *
+                               (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
+
+               if (missed_beacons > 50)
+                       beacon_qual = (60 - missed_beacons) * POOR / 10;
+               else if (missed_beacons > 40)
+                       beacon_qual = (50 - missed_beacons) * (FAIR - POOR) /
+                               10 + POOR;
+               else if (missed_beacons > 32)
+                       beacon_qual = (40 - missed_beacons) * (GOOD - FAIR) /
+                               18 + FAIR;
+               else if (missed_beacons > 20)
+                       beacon_qual = (32 - missed_beacons) *
+                               (VERY_GOOD - GOOD) / 20 + GOOD;
+               else
+                       beacon_qual = (20 - missed_beacons) *
+                               (PERFECT - VERY_GOOD) / 20 + VERY_GOOD;
+
+               quality = min(beacon_qual, min(tx_qual, rssi_qual));
+
+#ifdef CONFIG_IPW_DEBUG
+               if (beacon_qual == quality)
+                       IPW_DEBUG_WX("Quality clamped by Missed Beacons\n");
+               else if (tx_qual == quality)
+                       IPW_DEBUG_WX("Quality clamped by Tx Retries\n");
+               else if (quality != 100)
+                       IPW_DEBUG_WX("Quality clamped by Signal Strength\n");
+               else
+                       IPW_DEBUG_WX("Quality not clamped.\n");
+#endif
+
+               wstats->qual.qual = quality;
+               wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
+       }
+
+       wstats->qual.noise = 0;
+       wstats->qual.updated = 7;
+       wstats->qual.updated |= IW_QUAL_NOISE_INVALID;
+
+        /* FIXME: this is percent and not a # */
+       wstats->miss.beacon = missed_beacons;
+
+       if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURES,
+                               &tx_failures, &ord_len))
+               goto fail_get_ordinal;
+       wstats->discard.retries = tx_failures;
+
+       return wstats;
+
+ fail_get_ordinal:
+       IPW_DEBUG_WX("failed querying ordinals.\n");
+
+       return (struct iw_statistics *) NULL;
+}
+
+static void ipw2100_wx_event_work(struct ipw2100_priv *priv)
+{
+       union iwreq_data wrqu;
+       int len = ETH_ALEN;
+
+       if (priv->status & STATUS_STOPPING)
+               return;
+
+       down(&priv->action_sem);
+
+       IPW_DEBUG_WX("enter\n");
+
+       up(&priv->action_sem);
+
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+       /* Fetch BSSID from the hardware */
+       if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) ||
+           priv->status & STATUS_RF_KILL_MASK ||
+           ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
+                               &priv->bssid,  &len)) {
+               memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+       } else {
+               /* We now have the BSSID, so can finish setting to the full
+                * associated state */
+               memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
+               memcpy(&priv->ieee->bssid, priv->bssid, ETH_ALEN);
+               priv->status &= ~STATUS_ASSOCIATING;
+               priv->status |= STATUS_ASSOCIATED;
+               netif_carrier_on(priv->net_dev);
+               if (netif_queue_stopped(priv->net_dev)) {
+                       IPW_DEBUG_INFO("Waking net queue.\n");
+                       netif_wake_queue(priv->net_dev);
+               } else {
+                       IPW_DEBUG_INFO("Starting net queue.\n");
+                       netif_start_queue(priv->net_dev);
+               }
+       }
+
+       if (!(priv->status & STATUS_ASSOCIATED)) {
+               IPW_DEBUG_WX("Configuring ESSID\n");
+               down(&priv->action_sem);
+               /* This is a disassociation event, so kick the firmware to
+                * look for another AP */
+               if (priv->config & CFG_STATIC_ESSID)
+                       ipw2100_set_essid(priv, priv->essid, priv->essid_len, 0);
+               else
+                       ipw2100_set_essid(priv, NULL, 0, 0);
+               up(&priv->action_sem);
+       }
+
+       wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
+}
+
+#define IPW2100_FW_MAJOR_VERSION 1
+#define IPW2100_FW_MINOR_VERSION 3
+
+#define IPW2100_FW_MINOR(x) ((x & 0xff) >> 8)
+#define IPW2100_FW_MAJOR(x) (x & 0xff)
+
+#define IPW2100_FW_VERSION ((IPW2100_FW_MINOR_VERSION << 8) | \
+                             IPW2100_FW_MAJOR_VERSION)
+
+#define IPW2100_FW_PREFIX "ipw2100-" __stringify(IPW2100_FW_MAJOR_VERSION) \
+"." __stringify(IPW2100_FW_MINOR_VERSION)
+
+#define IPW2100_FW_NAME(x) IPW2100_FW_PREFIX "" x ".fw"
+
+
+/*
+
+BINARY FIRMWARE HEADER FORMAT
+
+offset      length   desc
+0           2        version
+2           2        mode == 0:BSS,1:IBSS,2:MONITOR
+4           4        fw_len
+8           4        uc_len
+C           fw_len   firmware data
+12 + fw_len uc_len   microcode data
+
+*/
+
+struct ipw2100_fw_header {
+       short version;
+       short mode;
+       unsigned int fw_size;
+       unsigned int uc_size;
+} __attribute__ ((packed));
+
+
+
+static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw)
+{
+       struct ipw2100_fw_header *h =
+               (struct ipw2100_fw_header *)fw->fw_entry->data;
+
+       if (IPW2100_FW_MAJOR(h->version) != IPW2100_FW_MAJOR_VERSION) {
+               printk(KERN_WARNING DRV_NAME ": Firmware image not compatible "
+                      "(detected version id of %u). "
+                      "See Documentation/networking/README.ipw2100\n",
+                      h->version);
+               return 1;
+       }
+
+       fw->version = h->version;
+       fw->fw.data = fw->fw_entry->data + sizeof(struct ipw2100_fw_header);
+       fw->fw.size = h->fw_size;
+       fw->uc.data = fw->fw.data + h->fw_size;
+       fw->uc.size = h->uc_size;
+
+       return 0;
+}
+
+
+static int ipw2100_get_firmware(struct ipw2100_priv *priv,
+                               struct ipw2100_fw *fw)
+{
+       char *fw_name;
+       int rc;
+
+       IPW_DEBUG_INFO("%s: Using hotplug firmware load.\n",
+              priv->net_dev->name);
+
+       switch (priv->ieee->iw_mode) {
+       case IW_MODE_ADHOC:
+               fw_name = IPW2100_FW_NAME("-i");
+               break;
+#ifdef CONFIG_IPW2100_MONITOR
+       case IW_MODE_MONITOR:
+               fw_name = IPW2100_FW_NAME("-p");
+               break;
+#endif
+       case IW_MODE_INFRA:
+       default:
+               fw_name = IPW2100_FW_NAME("");
+               break;
+       }
+
+       rc = request_firmware(&fw->fw_entry, fw_name, &priv->pci_dev->dev);
+
+       if (rc < 0) {
+               printk(KERN_ERR DRV_NAME ": "
+                      "%s: Firmware '%s' not available or load failed.\n",
+                      priv->net_dev->name, fw_name);
+               return rc;
+       }
+       IPW_DEBUG_INFO("firmware data %p size %zd\n", fw->fw_entry->data,
+                          fw->fw_entry->size);
+
+       ipw2100_mod_firmware_load(fw);
+
+       return 0;
+}
+
+static void ipw2100_release_firmware(struct ipw2100_priv *priv,
+                                    struct ipw2100_fw *fw)
+{
+       fw->version = 0;
+       if (fw->fw_entry)
+               release_firmware(fw->fw_entry);
+       fw->fw_entry = NULL;
+}
+
+
+static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
+                                size_t max)
+{
+       char ver[MAX_FW_VERSION_LEN];
+       u32 len = MAX_FW_VERSION_LEN;
+       u32 tmp;
+       int i;
+       /* firmware version is an ascii string (max len of 14) */
+       if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM,
+                               ver, &len))
+               return -EIO;
+       tmp = max;
+       if (len >= max)
+               len = max - 1;
+       for (i = 0; i < len; i++)
+               buf[i] = ver[i];
+       buf[i] = '\0';
+       return tmp;
+}
+
+static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
+                                   size_t max)
+{
+       u32 ver;
+       u32 len = sizeof(ver);
+       /* microcode version is a 32 bit integer */
+       if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION,
+                               &ver, &len))
+               return -EIO;
+       return snprintf(buf, max, "%08X", ver);
+}
+
+/*
+ * On exit, the firmware will have been freed from the fw list
+ */
+static int ipw2100_fw_download(struct ipw2100_priv *priv,
+                              struct ipw2100_fw *fw)
+{
+       /* firmware is constructed of N contiguous entries, each entry is
+        * structured as:
+        *
+        * offset    sie         desc
+        * 0         4           address to write to
+        * 4         2           length of data run
+         * 6         length      data
+        */
+       unsigned int addr;
+       unsigned short len;
+
+       const unsigned char *firmware_data = fw->fw.data;
+       unsigned int firmware_data_left = fw->fw.size;
+
+       while (firmware_data_left > 0) {
+               addr = *(u32 *)(firmware_data);
+               firmware_data      += 4;
+               firmware_data_left -= 4;
+
+               len = *(u16 *)(firmware_data);
+               firmware_data      += 2;
+               firmware_data_left -= 2;
+
+               if (len > 32) {
+                       printk(KERN_ERR DRV_NAME ": "
+                              "Invalid firmware run-length of %d bytes\n",
+                              len);
+                       return -EINVAL;
+               }
+
+               write_nic_memory(priv->net_dev, addr, len, firmware_data);
+               firmware_data      += len;
+               firmware_data_left -= len;
+       }
+
+       return 0;
+}
+
+struct symbol_alive_response {
+       u8 cmd_id;
+       u8 seq_num;
+       u8 ucode_rev;
+       u8 eeprom_valid;
+       u16 valid_flags;
+       u8 IEEE_addr[6];
+       u16 flags;
+       u16 pcb_rev;
+       u16 clock_settle_time;  // 1us LSB
+       u16 powerup_settle_time;        // 1us LSB
+       u16 hop_settle_time;    // 1us LSB
+       u8 date[3];             // month, day, year
+       u8 time[2];             // hours, minutes
+       u8 ucode_valid;
+};
+
+static int ipw2100_ucode_download(struct ipw2100_priv *priv,
+                                 struct ipw2100_fw *fw)
+{
+       struct net_device *dev = priv->net_dev;
+       const unsigned char *microcode_data = fw->uc.data;
+       unsigned int microcode_data_left = fw->uc.size;
+       void __iomem *reg = (void __iomem *)dev->base_addr;
+
+       struct symbol_alive_response response;
+       int i, j;
+       u8 data;
+
+       /* Symbol control */
+       write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
+       readl(reg);
+       write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
+       readl(reg);
+
+       /* HW config */
+       write_nic_byte(dev, 0x210014, 0x72);    /* fifo width =16 */
+       readl(reg);
+       write_nic_byte(dev, 0x210014, 0x72);    /* fifo width =16 */
+       readl(reg);
+
+       /* EN_CS_ACCESS bit to reset control store pointer */
+       write_nic_byte(dev, 0x210000, 0x40);
+       readl(reg);
+       write_nic_byte(dev, 0x210000, 0x0);
+       readl(reg);
+       write_nic_byte(dev, 0x210000, 0x40);
+       readl(reg);
+
+       /* copy microcode from buffer into Symbol */
+
+       while (microcode_data_left > 0) {
+               write_nic_byte(dev, 0x210010, *microcode_data++);
+               write_nic_byte(dev, 0x210010, *microcode_data++);
+               microcode_data_left -= 2;
+       }
+
+       /* EN_CS_ACCESS bit to reset the control store pointer */
+       write_nic_byte(dev, 0x210000, 0x0);
+       readl(reg);
+
+       /* Enable System (Reg 0)
+        * first enable causes garbage in RX FIFO */
+       write_nic_byte(dev, 0x210000, 0x0);
+       readl(reg);
+       write_nic_byte(dev, 0x210000, 0x80);
+       readl(reg);
+
+       /* Reset External Baseband Reg */
+       write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
+       readl(reg);
+       write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
+       readl(reg);
+
+       /* HW Config (Reg 5) */
+       write_nic_byte(dev, 0x210014, 0x72);    // fifo width =16
+       readl(reg);
+       write_nic_byte(dev, 0x210014, 0x72);    // fifo width =16
+       readl(reg);
+
+       /* Enable System (Reg 0)
+        * second enable should be OK */
+       write_nic_byte(dev, 0x210000, 0x00);    // clear enable system
+       readl(reg);
+       write_nic_byte(dev, 0x210000, 0x80);    // set enable system
+
+       /* check Symbol is enabled - upped this from 5 as it wasn't always
+        * catching the update */
+       for (i = 0; i < 10; i++) {
+               udelay(10);
+
+               /* check Dino is enabled bit */
+               read_nic_byte(dev, 0x210000, &data);
+               if (data & 0x1)
+                       break;
+       }
+
+       if (i == 10) {
+               printk(KERN_ERR DRV_NAME ": %s: Error initializing Symbol\n",
+                      dev->name);
+               return -EIO;
+       }
+
+       /* Get Symbol alive response */
+       for (i = 0; i < 30; i++) {
+               /* Read alive response structure */
+               for (j = 0;
+                    j < (sizeof(struct symbol_alive_response) >> 1);
+                    j++)
+                       read_nic_word(dev, 0x210004,
+                                     ((u16 *)&response) + j);
+
+               if ((response.cmd_id == 1) &&
+                   (response.ucode_valid == 0x1))
+                       break;
+               udelay(10);
+       }
+
+       if (i == 30) {
+               printk(KERN_ERR DRV_NAME ": %s: No response from Symbol - hw not alive\n",
+                      dev->name);
+               printk_buf(IPW_DL_ERROR, (u8*)&response, sizeof(response));
+               return -EIO;
+       }
+
+       return 0;
+}
diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h
new file mode 100644 (file)
index 0000000..2a3cdbd
--- /dev/null
@@ -0,0 +1,1167 @@
+/******************************************************************************
+
+  Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+
+  Contact Information:
+  James P. Ketrenos <ipw2100-admin@linux.intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+******************************************************************************/
+#ifndef _IPW2100_H
+#define _IPW2100_H
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <asm/io.h>
+#include <linux/socket.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <linux/version.h>
+#include <net/iw_handler.h>    // new driver API
+
+#include <net/ieee80211.h>
+
+#include <linux/workqueue.h>
+
+struct ipw2100_priv;
+struct ipw2100_tx_packet;
+struct ipw2100_rx_packet;
+
+#define IPW_DL_UNINIT    0x80000000
+#define IPW_DL_NONE      0x00000000
+#define IPW_DL_ALL       0x7FFFFFFF
+
+/*
+ * To use the debug system;
+ *
+ * If you are defining a new debug classification, simply add it to the #define
+ * list here in the form of:
+ *
+ * #define IPW_DL_xxxx VALUE
+ *
+ * shifting value to the left one bit from the previous entry.  xxxx should be
+ * the name of the classification (for example, WEP)
+ *
+ * You then need to either add a IPW2100_xxxx_DEBUG() macro definition for your
+ * classification, or use IPW_DEBUG(IPW_DL_xxxx, ...) whenever you want
+ * to send output to that classification.
+ *
+ * To add your debug level to the list of levels seen when you perform
+ *
+ * % cat /proc/net/ipw2100/debug_level
+ *
+ * you simply need to add your entry to the ipw2100_debug_levels array.
+ *
+ * If you do not see debug_level in /proc/net/ipw2100 then you do not have
+ * CONFIG_IPW_DEBUG defined in your kernel configuration
+ *
+ */
+
+#define IPW_DL_ERROR         (1<<0)
+#define IPW_DL_WARNING       (1<<1)
+#define IPW_DL_INFO          (1<<2)
+#define IPW_DL_WX            (1<<3)
+#define IPW_DL_HC            (1<<5)
+#define IPW_DL_STATE         (1<<6)
+
+#define IPW_DL_NOTIF         (1<<10)
+#define IPW_DL_SCAN          (1<<11)
+#define IPW_DL_ASSOC         (1<<12)
+#define IPW_DL_DROP          (1<<13)
+
+#define IPW_DL_IOCTL         (1<<14)
+#define IPW_DL_RF_KILL       (1<<17)
+
+
+#define IPW_DL_MANAGE        (1<<15)
+#define IPW_DL_FW            (1<<16)
+
+#define IPW_DL_FRAG          (1<<21)
+#define IPW_DL_WEP           (1<<22)
+#define IPW_DL_TX            (1<<23)
+#define IPW_DL_RX            (1<<24)
+#define IPW_DL_ISR           (1<<25)
+#define IPW_DL_IO            (1<<26)
+#define IPW_DL_TRACE         (1<<28)
+
+#define IPW_DEBUG_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
+#define IPW_DEBUG_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
+#define IPW_DEBUG_INFO(f...)    IPW_DEBUG(IPW_DL_INFO, ## f)
+#define IPW_DEBUG_WX(f...)     IPW_DEBUG(IPW_DL_WX, ## f)
+#define IPW_DEBUG_SCAN(f...)   IPW_DEBUG(IPW_DL_SCAN, ## f)
+#define IPW_DEBUG_NOTIF(f...) IPW_DEBUG(IPW_DL_NOTIF, ## f)
+#define IPW_DEBUG_TRACE(f...)  IPW_DEBUG(IPW_DL_TRACE, ## f)
+#define IPW_DEBUG_RX(f...)     IPW_DEBUG(IPW_DL_RX, ## f)
+#define IPW_DEBUG_TX(f...)     IPW_DEBUG(IPW_DL_TX, ## f)
+#define IPW_DEBUG_ISR(f...)    IPW_DEBUG(IPW_DL_ISR, ## f)
+#define IPW_DEBUG_MANAGEMENT(f...) IPW_DEBUG(IPW_DL_MANAGE, ## f)
+#define IPW_DEBUG_WEP(f...)    IPW_DEBUG(IPW_DL_WEP, ## f)
+#define IPW_DEBUG_HC(f...) IPW_DEBUG(IPW_DL_HC, ## f)
+#define IPW_DEBUG_FRAG(f...) IPW_DEBUG(IPW_DL_FRAG, ## f)
+#define IPW_DEBUG_FW(f...) IPW_DEBUG(IPW_DL_FW, ## f)
+#define IPW_DEBUG_RF_KILL(f...) IPW_DEBUG(IPW_DL_RF_KILL, ## f)
+#define IPW_DEBUG_DROP(f...) IPW_DEBUG(IPW_DL_DROP, ## f)
+#define IPW_DEBUG_IO(f...) IPW_DEBUG(IPW_DL_IO, ## f)
+#define IPW_DEBUG_IOCTL(f...) IPW_DEBUG(IPW_DL_IOCTL, ## f)
+#define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
+#define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
+
+enum {
+       IPW_HW_STATE_DISABLED = 1,
+       IPW_HW_STATE_ENABLED = 0
+};
+
+struct ssid_context {
+       char ssid[IW_ESSID_MAX_SIZE + 1];
+       int ssid_len;
+       unsigned char bssid[ETH_ALEN];
+       int port_type;
+       int channel;
+
+};
+
+extern const char *port_type_str[];
+extern const char *band_str[];
+
+#define NUMBER_OF_BD_PER_COMMAND_PACKET                1
+#define NUMBER_OF_BD_PER_DATA_PACKET           2
+
+#define IPW_MAX_BDS 6
+#define NUMBER_OF_OVERHEAD_BDS_PER_PACKETR     2
+#define NUMBER_OF_BDS_TO_LEAVE_FOR_COMMANDS    1
+
+#define REQUIRED_SPACE_IN_RING_FOR_COMMAND_PACKET \
+    (IPW_BD_QUEUE_W_R_MIN_SPARE + NUMBER_OF_BD_PER_COMMAND_PACKET)
+
+struct bd_status {
+       union {
+               struct { u8 nlf:1, txType:2, intEnabled:1, reserved:4;} fields;
+               u8 field;
+       } info;
+} __attribute__ ((packed));
+
+struct ipw2100_bd {
+       u32 host_addr;
+       u32 buf_length;
+       struct bd_status status;
+        /* number of fragments for frame (should be set only for
+        * 1st TBD) */
+       u8 num_fragments;
+       u8 reserved[6];
+} __attribute__ ((packed));
+
+#define IPW_BD_QUEUE_LENGTH(n) (1<<n)
+#define IPW_BD_ALIGNMENT(L)    (L*sizeof(struct ipw2100_bd))
+
+#define IPW_BD_STATUS_TX_FRAME_802_3             0x00
+#define IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT 0x01
+#define IPW_BD_STATUS_TX_FRAME_COMMAND          0x02
+#define IPW_BD_STATUS_TX_FRAME_802_11           0x04
+#define IPW_BD_STATUS_TX_INTERRUPT_ENABLE       0x08
+
+struct ipw2100_bd_queue {
+       /* driver (virtual) pointer to queue */
+       struct ipw2100_bd *drv;
+
+       /* firmware (physical) pointer to queue */
+       dma_addr_t nic;
+
+       /* Length of phy memory allocated for BDs */
+       u32 size;
+
+       /* Number of BDs in queue (and in array) */
+       u32 entries;
+
+       /* Number of available BDs (invalid for NIC BDs) */
+       u32 available;
+
+       /* Offset of oldest used BD in array (next one to
+        * check for completion) */
+       u32 oldest;
+
+       /* Offset of next available (unused) BD */
+       u32 next;
+};
+
+#define RX_QUEUE_LENGTH 256
+#define TX_QUEUE_LENGTH 256
+#define HW_QUEUE_LENGTH 256
+
+#define TX_PENDED_QUEUE_LENGTH (TX_QUEUE_LENGTH / NUMBER_OF_BD_PER_DATA_PACKET)
+
+#define STATUS_TYPE_MASK       0x0000000f
+#define COMMAND_STATUS_VAL     0
+#define STATUS_CHANGE_VAL      1
+#define P80211_DATA_VAL        2
+#define P8023_DATA_VAL         3
+#define HOST_NOTIFICATION_VAL  4
+
+#define IPW2100_RSSI_TO_DBM (-98)
+
+struct ipw2100_status {
+       u32 frame_size;
+       u16 status_fields;
+       u8 flags;
+#define IPW_STATUS_FLAG_DECRYPTED      (1<<0)
+#define IPW_STATUS_FLAG_WEP_ENCRYPTED  (1<<1)
+#define IPW_STATUS_FLAG_CRC_ERROR       (1<<2)
+       u8 rssi;
+} __attribute__ ((packed));
+
+struct ipw2100_status_queue {
+       /* driver (virtual) pointer to queue */
+       struct ipw2100_status *drv;
+
+       /* firmware (physical) pointer to queue */
+       dma_addr_t nic;
+
+       /* Length of phy memory allocated for BDs */
+       u32 size;
+};
+
+#define HOST_COMMAND_PARAMS_REG_LEN    100
+#define CMD_STATUS_PARAMS_REG_LEN      3
+
+#define IPW_WPA_CAPABILITIES   0x1
+#define IPW_WPA_LISTENINTERVAL 0x2
+#define IPW_WPA_AP_ADDRESS     0x4
+
+#define IPW_MAX_VAR_IE_LEN ((HOST_COMMAND_PARAMS_REG_LEN - 4) * sizeof(u32))
+
+struct ipw2100_wpa_assoc_frame {
+       u16 fixed_ie_mask;
+       struct {
+               u16 capab_info;
+               u16 listen_interval;
+               u8 current_ap[ETH_ALEN];
+       } fixed_ies;
+       u32 var_ie_len;
+       u8 var_ie[IPW_MAX_VAR_IE_LEN];
+};
+
+#define IPW_BSS     1
+#define IPW_MONITOR 2
+#define IPW_IBSS    3
+
+/**
+ * @struct _tx_cmd - HWCommand
+ * @brief H/W command structure.
+ */
+struct ipw2100_cmd_header {
+       u32 host_command_reg;
+       u32 host_command_reg1;
+       u32 sequence;
+       u32 host_command_len_reg;
+       u32 host_command_params_reg[HOST_COMMAND_PARAMS_REG_LEN];
+       u32 cmd_status_reg;
+       u32 cmd_status_params_reg[CMD_STATUS_PARAMS_REG_LEN];
+       u32 rxq_base_ptr;
+       u32 rxq_next_ptr;
+       u32 rxq_host_ptr;
+       u32 txq_base_ptr;
+       u32 txq_next_ptr;
+       u32 txq_host_ptr;
+       u32 tx_status_reg;
+       u32 reserved;
+       u32 status_change_reg;
+       u32 reserved1[3];
+       u32 *ordinal1_ptr;
+       u32 *ordinal2_ptr;
+} __attribute__ ((packed));
+
+struct ipw2100_data_header {
+       u32 host_command_reg;
+       u32 host_command_reg1;
+       u8 encrypted;   // BOOLEAN in win! TRUE if frame is enc by driver
+       u8 needs_encryption;    // BOOLEAN in win! TRUE if frma need to be enc in NIC
+       u8 wep_index;           // 0 no key, 1-4 key index, 0xff immediate key
+       u8 key_size;    // 0 no imm key, 0x5 64bit encr, 0xd 128bit encr, 0x10 128bit encr and 128bit IV
+       u8 key[16];
+       u8 reserved[10];        // f/w reserved
+       u8 src_addr[ETH_ALEN];
+       u8 dst_addr[ETH_ALEN];
+       u16 fragment_size;
+} __attribute__ ((packed));
+
+/* Host command data structure */
+struct host_command {
+       u32 host_command;               // COMMAND ID
+       u32 host_command1;              // COMMAND ID
+       u32 host_command_sequence;      // UNIQUE COMMAND NUMBER (ID)
+       u32 host_command_length;        // LENGTH
+       u32 host_command_parameters[HOST_COMMAND_PARAMS_REG_LEN];       // COMMAND PARAMETERS
+} __attribute__ ((packed));
+
+
+typedef enum {
+       POWER_ON_RESET,
+       EXIT_POWER_DOWN_RESET,
+       SW_RESET,
+       EEPROM_RW,
+       SW_RE_INIT
+} ipw2100_reset_event;
+
+enum {
+       COMMAND = 0xCAFE,
+       DATA,
+       RX
+};
+
+
+struct ipw2100_tx_packet {
+       int type;
+       int index;
+       union {
+               struct { /* COMMAND */
+                       struct ipw2100_cmd_header* cmd;
+                       dma_addr_t cmd_phys;
+               } c_struct;
+               struct { /* DATA */
+                       struct ipw2100_data_header* data;
+                       dma_addr_t data_phys;
+                       struct ieee80211_txb *txb;
+               } d_struct;
+       } info;
+       int jiffy_start;
+
+       struct list_head list;
+};
+
+
+struct ipw2100_rx_packet {
+       struct ipw2100_rx *rxp;
+       dma_addr_t dma_addr;
+       int jiffy_start;
+       struct sk_buff *skb;
+       struct list_head list;
+};
+
+#define FRAG_DISABLED             (1<<31)
+#define RTS_DISABLED              (1<<31)
+#define MAX_RTS_THRESHOLD         2304U
+#define MIN_RTS_THRESHOLD         1U
+#define DEFAULT_RTS_THRESHOLD     1000U
+
+#define DEFAULT_BEACON_INTERVAL   100U
+#define        DEFAULT_SHORT_RETRY_LIMIT 7U
+#define        DEFAULT_LONG_RETRY_LIMIT  4U
+
+struct ipw2100_ordinals {
+       u32 table1_addr;
+       u32 table2_addr;
+       u32 table1_size;
+       u32 table2_size;
+};
+
+/* Host Notification header */
+struct ipw2100_notification {
+       u32 hnhdr_subtype;      /* type of host notification */
+       u32 hnhdr_size;         /* size in bytes of data
+                                  or number of entries, if table.
+                                  Does NOT include header */
+} __attribute__ ((packed));
+
+#define MAX_KEY_SIZE   16
+#define        MAX_KEYS        8
+
+#define IPW2100_WEP_ENABLE     (1<<1)
+#define IPW2100_WEP_DROP_CLEAR (1<<2)
+
+#define IPW_NONE_CIPHER   (1<<0)
+#define IPW_WEP40_CIPHER  (1<<1)
+#define IPW_TKIP_CIPHER   (1<<2)
+#define IPW_CCMP_CIPHER   (1<<4)
+#define IPW_WEP104_CIPHER (1<<5)
+#define IPW_CKIP_CIPHER   (1<<6)
+
+#define        IPW_AUTH_OPEN     0
+#define        IPW_AUTH_SHARED   1
+
+struct statistic {
+       int value;
+       int hi;
+       int lo;
+};
+
+#define INIT_STAT(x) do {  \
+  (x)->value = (x)->hi = 0; \
+  (x)->lo = 0x7fffffff; \
+} while (0)
+#define SET_STAT(x,y) do { \
+  (x)->value = y; \
+  if ((x)->value > (x)->hi) (x)->hi = (x)->value; \
+  if ((x)->value < (x)->lo) (x)->lo = (x)->value; \
+} while (0)
+#define INC_STAT(x) do { if (++(x)->value > (x)->hi) (x)->hi = (x)->value; } \
+while (0)
+#define DEC_STAT(x) do { if (--(x)->value < (x)->lo) (x)->lo = (x)->value; } \
+while (0)
+
+#define IPW2100_ERROR_QUEUE 5
+
+/* Power management code: enable or disable? */
+enum {
+#ifdef CONFIG_PM
+       IPW2100_PM_DISABLED = 0,
+       PM_STATE_SIZE = 16,
+#else
+       IPW2100_PM_DISABLED = 1,
+       PM_STATE_SIZE = 0,
+#endif
+};
+
+#define STATUS_POWERED          (1<<0)
+#define STATUS_CMD_ACTIVE       (1<<1)  /**< host command in progress */
+#define STATUS_RUNNING          (1<<2)  /* Card initialized, but not enabled */
+#define STATUS_ENABLED          (1<<3)  /* Card enabled -- can scan,Tx,Rx */
+#define STATUS_STOPPING         (1<<4)  /* Card is in shutdown phase */
+#define STATUS_INITIALIZED      (1<<5)  /* Card is ready for external calls */
+#define STATUS_ASSOCIATING      (1<<9)  /* Associated, but no BSSID yet */
+#define STATUS_ASSOCIATED       (1<<10) /* Associated and BSSID valid */
+#define STATUS_INT_ENABLED      (1<<11)
+#define STATUS_RF_KILL_HW       (1<<12)
+#define STATUS_RF_KILL_SW       (1<<13)
+#define STATUS_RF_KILL_MASK     (STATUS_RF_KILL_HW | STATUS_RF_KILL_SW)
+#define STATUS_EXIT_PENDING     (1<<14)
+
+#define STATUS_SCAN_PENDING     (1<<23)
+#define STATUS_SCANNING         (1<<24)
+#define STATUS_SCAN_ABORTING    (1<<25)
+#define STATUS_SCAN_COMPLETE    (1<<26)
+#define STATUS_WX_EVENT_PENDING (1<<27)
+#define STATUS_RESET_PENDING    (1<<29)
+#define STATUS_SECURITY_UPDATED (1<<30) /* Security sync needed */
+
+
+
+/* Internal NIC states */
+#define IPW_STATE_INITIALIZED  (1<<0)
+#define IPW_STATE_COUNTRY_FOUND        (1<<1)
+#define IPW_STATE_ASSOCIATED    (1<<2)
+#define IPW_STATE_ASSN_LOST    (1<<3)
+#define IPW_STATE_ASSN_CHANGED         (1<<4)
+#define IPW_STATE_SCAN_COMPLETE        (1<<5)
+#define IPW_STATE_ENTERED_PSP  (1<<6)
+#define IPW_STATE_LEFT_PSP     (1<<7)
+#define IPW_STATE_RF_KILL       (1<<8)
+#define IPW_STATE_DISABLED     (1<<9)
+#define IPW_STATE_POWER_DOWN   (1<<10)
+#define IPW_STATE_SCANNING      (1<<11)
+
+
+
+#define CFG_STATIC_CHANNEL      (1<<0) /* Restrict assoc. to single channel */
+#define CFG_STATIC_ESSID        (1<<1) /* Restrict assoc. to single SSID */
+#define CFG_STATIC_BSSID        (1<<2) /* Restrict assoc. to single BSSID */
+#define CFG_CUSTOM_MAC          (1<<3)
+#define CFG_LONG_PREAMBLE       (1<<4)
+#define CFG_ASSOCIATE           (1<<6)
+#define CFG_FIXED_RATE          (1<<7)
+#define CFG_ADHOC_CREATE        (1<<8)
+#define CFG_C3_DISABLED         (1<<9)
+#define CFG_PASSIVE_SCAN        (1<<10)
+
+#define CAP_SHARED_KEY          (1<<0) /* Off = OPEN */
+#define CAP_PRIVACY_ON          (1<<1) /* Off = No privacy */
+
+struct ipw2100_priv {
+
+       int stop_hang_check; /* Set 1 when shutting down to kill hang_check */
+       int stop_rf_kill; /* Set 1 when shutting down to kill rf_kill */
+
+       struct ieee80211_device *ieee;
+       unsigned long status;
+       unsigned long config;
+       unsigned long capability;
+
+       /* Statistics */
+       int resets;
+       int reset_backoff;
+
+       /* Context */
+       u8 essid[IW_ESSID_MAX_SIZE];
+       u8 essid_len;
+       u8 bssid[ETH_ALEN];
+       u8 channel;
+       int last_mode;
+       int cstate_limit;
+
+       unsigned long connect_start;
+       unsigned long last_reset;
+
+       u32 channel_mask;
+       u32 fatal_error;
+       u32 fatal_errors[IPW2100_ERROR_QUEUE];
+       u32 fatal_index;
+       int eeprom_version;
+       int firmware_version;
+       unsigned long hw_features;
+       int hangs;
+       u32 last_rtc;
+       int dump_raw; /* 1 to dump raw bytes in /sys/.../memory */
+       u8* snapshot[0x30];
+
+       u8 mandatory_bssid_mac[ETH_ALEN];
+       u8 mac_addr[ETH_ALEN];
+
+       int power_mode;
+
+       /* WEP data */
+       struct ieee80211_security sec;
+       int messages_sent;
+
+
+       int short_retry_limit;
+       int long_retry_limit;
+
+       u32 rts_threshold;
+       u32 frag_threshold;
+
+       int in_isr;
+
+       u32 tx_rates;
+       int tx_power;
+       u32 beacon_interval;
+
+       char nick[IW_ESSID_MAX_SIZE + 1];
+
+       struct ipw2100_status_queue status_queue;
+
+       struct statistic txq_stat;
+       struct statistic rxq_stat;
+       struct ipw2100_bd_queue rx_queue;
+       struct ipw2100_bd_queue tx_queue;
+       struct ipw2100_rx_packet *rx_buffers;
+
+       struct statistic fw_pend_stat;
+       struct list_head fw_pend_list;
+
+       struct statistic msg_free_stat;
+       struct statistic msg_pend_stat;
+       struct list_head msg_free_list;
+       struct list_head msg_pend_list;
+       struct ipw2100_tx_packet *msg_buffers;
+
+       struct statistic tx_free_stat;
+       struct statistic tx_pend_stat;
+       struct list_head tx_free_list;
+       struct list_head tx_pend_list;
+       struct ipw2100_tx_packet *tx_buffers;
+
+       struct ipw2100_ordinals ordinals;
+
+       struct pci_dev *pci_dev;
+
+       struct proc_dir_entry *dir_dev;
+
+       struct net_device *net_dev;
+       struct iw_statistics wstats;
+
+       struct tasklet_struct irq_tasklet;
+
+       struct workqueue_struct *workqueue;
+       struct work_struct reset_work;
+       struct work_struct security_work;
+       struct work_struct wx_event_work;
+       struct work_struct hang_check;
+       struct work_struct rf_kill;
+
+       u32 interrupts;
+       int tx_interrupts;
+       int rx_interrupts;
+       int inta_other;
+
+       spinlock_t low_lock;
+       struct semaphore action_sem;
+       struct semaphore adapter_sem;
+
+       wait_queue_head_t wait_command_queue;
+};
+
+
+/*********************************************************
+ * Host Command -> From Driver to FW
+ *********************************************************/
+
+/**
+ * Host command identifiers
+ */
+#define HOST_COMPLETE           2
+#define SYSTEM_CONFIG           6
+#define SSID                    8
+#define MANDATORY_BSSID         9
+#define AUTHENTICATION_TYPE    10
+#define ADAPTER_ADDRESS        11
+#define PORT_TYPE              12
+#define INTERNATIONAL_MODE     13
+#define CHANNEL                14
+#define RTS_THRESHOLD          15
+#define FRAG_THRESHOLD         16
+#define POWER_MODE             17
+#define TX_RATES               18
+#define BASIC_TX_RATES         19
+#define WEP_KEY_INFO           20
+#define WEP_KEY_INDEX          25
+#define WEP_FLAGS              26
+#define ADD_MULTICAST          27
+#define CLEAR_ALL_MULTICAST    28
+#define BEACON_INTERVAL        29
+#define ATIM_WINDOW            30
+#define CLEAR_STATISTICS       31
+#define SEND                  33
+#define TX_POWER_INDEX         36
+#define BROADCAST_SCAN         43
+#define CARD_DISABLE           44
+#define PREFERRED_BSSID        45
+#define SET_SCAN_OPTIONS       46
+#define SCAN_DWELL_TIME        47
+#define SWEEP_TABLE            48
+#define AP_OR_STATION_TABLE    49
+#define GROUP_ORDINALS         50
+#define SHORT_RETRY_LIMIT      51
+#define LONG_RETRY_LIMIT       52
+
+#define HOST_PRE_POWER_DOWN    58
+#define CARD_DISABLE_PHY_OFF   61
+#define MSDU_TX_RATES          62
+
+
+/* Rogue AP Detection */
+#define SET_STATION_STAT_BITS      64
+#define CLEAR_STATIONS_STAT_BITS   65
+#define LEAP_ROGUE_MODE            66  //TODO tbw replaced by CFG_LEAP_ROGUE_AP
+#define SET_SECURITY_INFORMATION   67
+#define DISASSOCIATION_BSSID      68
+#define SET_WPA_IE                 69
+
+
+
+/* system configuration bit mask: */
+#define IPW_CFG_MONITOR               0x00004
+#define IPW_CFG_PREAMBLE_AUTO        0x00010
+#define IPW_CFG_IBSS_AUTO_START     0x00020
+#define IPW_CFG_LOOPBACK            0x00100
+#define IPW_CFG_ANSWER_BCSSID_PROBE 0x00800
+#define IPW_CFG_BT_SIDEBAND_SIGNAL     0x02000
+#define IPW_CFG_802_1x_ENABLE       0x04000
+#define IPW_CFG_BSS_MASK               0x08000
+#define IPW_CFG_IBSS_MASK              0x10000
+
+#define IPW_SCAN_NOASSOCIATE (1<<0)
+#define IPW_SCAN_MIXED_CELL (1<<1)
+/* RESERVED (1<<2) */
+#define IPW_SCAN_PASSIVE (1<<3)
+
+#define IPW_NIC_FATAL_ERROR 0x2A7F0
+#define IPW_ERROR_ADDR(x) (x & 0x3FFFF)
+#define IPW_ERROR_CODE(x) ((x & 0xFF000000) >> 24)
+#define IPW2100_ERR_C3_CORRUPTION (0x10 << 24)
+#define IPW2100_ERR_MSG_TIMEOUT   (0x11 << 24)
+#define IPW2100_ERR_FW_LOAD       (0x12 << 24)
+
+#define IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND                   0x200
+#define IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND   IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x0D80
+
+#define IPW_MEM_HOST_SHARED_RX_BD_BASE                  (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x40)
+#define IPW_MEM_HOST_SHARED_RX_STATUS_BASE              (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x44)
+#define IPW_MEM_HOST_SHARED_RX_BD_SIZE                  (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x48)
+#define IPW_MEM_HOST_SHARED_RX_READ_INDEX               (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0xa0)
+
+#define IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE          (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x00)
+#define IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE          (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x04)
+#define IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX       (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x80)
+
+#define IPW_MEM_HOST_SHARED_RX_WRITE_INDEX \
+    (IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND + 0x20)
+
+#define IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX \
+    (IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND)
+
+#define IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1   (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x180)
+#define IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2   (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x184)
+
+#define IPW2100_INTA_TX_TRANSFER               (0x00000001)    // Bit 0 (LSB)
+#define IPW2100_INTA_RX_TRANSFER               (0x00000002)    // Bit 1
+#define IPW2100_INTA_TX_COMPLETE              (0x00000004)     // Bit 2
+#define IPW2100_INTA_EVENT_INTERRUPT           (0x00000008)     // Bit 3
+#define IPW2100_INTA_STATUS_CHANGE             (0x00000010)    // Bit 4
+#define IPW2100_INTA_BEACON_PERIOD_EXPIRED     (0x00000020)    // Bit 5
+#define IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE  (0x00010000)        // Bit 16
+#define IPW2100_INTA_FW_INIT_DONE              (0x01000000)    // Bit 24
+#define IPW2100_INTA_FW_CALIBRATION_CALC       (0x02000000)    // Bit 25
+#define IPW2100_INTA_FATAL_ERROR               (0x40000000)    // Bit 30
+#define IPW2100_INTA_PARITY_ERROR              (0x80000000)    // Bit 31 (MSB)
+
+#define IPW_AUX_HOST_RESET_REG_PRINCETON_RESET              (0x00000001)
+#define IPW_AUX_HOST_RESET_REG_FORCE_NMI                    (0x00000002)
+#define IPW_AUX_HOST_RESET_REG_PCI_HOST_CLUSTER_FATAL_NMI   (0x00000004)
+#define IPW_AUX_HOST_RESET_REG_CORE_FATAL_NMI               (0x00000008)
+#define IPW_AUX_HOST_RESET_REG_SW_RESET                     (0x00000080)
+#define IPW_AUX_HOST_RESET_REG_MASTER_DISABLED              (0x00000100)
+#define IPW_AUX_HOST_RESET_REG_STOP_MASTER                  (0x00000200)
+
+#define IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY           (0x00000001)   // Bit 0 (LSB)
+#define IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY   (0x00000002)   // Bit 1
+#define IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE             (0x00000004)   // Bit 2
+#define IPW_AUX_HOST_GP_CNTRL_BITS_SYS_CONFIG           (0x000007c0)   // Bits 6-10
+#define IPW_AUX_HOST_GP_CNTRL_BIT_BUS_TYPE              (0x00000200)   // Bit 9
+#define IPW_AUX_HOST_GP_CNTRL_BIT_BAR0_BLOCK_SIZE       (0x00000400)   // Bit 10
+#define IPW_AUX_HOST_GP_CNTRL_BIT_USB_MODE              (0x20000000)   // Bit 29
+#define IPW_AUX_HOST_GP_CNTRL_BIT_HOST_FORCES_SYS_CLK   (0x40000000)   // Bit 30
+#define IPW_AUX_HOST_GP_CNTRL_BIT_FW_FORCES_SYS_CLK     (0x80000000)   // Bit 31 (MSB)
+
+#define IPW_BIT_GPIO_GPIO1_MASK         0x0000000C
+#define IPW_BIT_GPIO_GPIO3_MASK         0x000000C0
+#define IPW_BIT_GPIO_GPIO1_ENABLE       0x00000008
+#define IPW_BIT_GPIO_RF_KILL            0x00010000
+
+#define IPW_BIT_GPIO_LED_OFF            0x00002000     // Bit 13 = 1
+
+#define IPW_REG_DOMAIN_0_OFFSET        0x0000
+#define IPW_REG_DOMAIN_1_OFFSET        IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND
+
+#define IPW_REG_INTA                   IPW_REG_DOMAIN_0_OFFSET + 0x0008
+#define IPW_REG_INTA_MASK              IPW_REG_DOMAIN_0_OFFSET + 0x000C
+#define IPW_REG_INDIRECT_ACCESS_ADDRESS        IPW_REG_DOMAIN_0_OFFSET + 0x0010
+#define IPW_REG_INDIRECT_ACCESS_DATA   IPW_REG_DOMAIN_0_OFFSET + 0x0014
+#define IPW_REG_AUTOINCREMENT_ADDRESS  IPW_REG_DOMAIN_0_OFFSET + 0x0018
+#define IPW_REG_AUTOINCREMENT_DATA     IPW_REG_DOMAIN_0_OFFSET + 0x001C
+#define IPW_REG_RESET_REG              IPW_REG_DOMAIN_0_OFFSET + 0x0020
+#define IPW_REG_GP_CNTRL               IPW_REG_DOMAIN_0_OFFSET + 0x0024
+#define IPW_REG_GPIO                   IPW_REG_DOMAIN_0_OFFSET + 0x0030
+#define IPW_REG_FW_TYPE                 IPW_REG_DOMAIN_1_OFFSET + 0x0188
+#define IPW_REG_FW_VERSION             IPW_REG_DOMAIN_1_OFFSET + 0x018C
+#define IPW_REG_FW_COMPATABILITY_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x0190
+
+#define IPW_REG_INDIRECT_ADDR_MASK     0x00FFFFFC
+
+#define IPW_INTERRUPT_MASK             0xC1010013
+
+#define IPW2100_CONTROL_REG             0x220000
+#define IPW2100_CONTROL_PHY_OFF         0x8
+
+#define IPW2100_COMMAND                        0x00300004
+#define IPW2100_COMMAND_PHY_ON         0x0
+#define IPW2100_COMMAND_PHY_OFF                0x1
+
+/* in DEBUG_AREA, values of memory always 0xd55555d5 */
+#define IPW_REG_DOA_DEBUG_AREA_START    IPW_REG_DOMAIN_0_OFFSET + 0x0090
+#define IPW_REG_DOA_DEBUG_AREA_END      IPW_REG_DOMAIN_0_OFFSET + 0x00FF
+#define IPW_DATA_DOA_DEBUG_VALUE        0xd55555d5
+
+#define IPW_INTERNAL_REGISTER_HALT_AND_RESET   0x003000e0
+
+#define IPW_WAIT_CLOCK_STABILIZATION_DELAY         50  // micro seconds
+#define IPW_WAIT_RESET_ARC_COMPLETE_DELAY          10  // micro seconds
+#define IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY 10 // micro seconds
+
+// BD ring queue read/write difference
+#define IPW_BD_QUEUE_W_R_MIN_SPARE 2
+
+#define IPW_CACHE_LINE_LENGTH_DEFAULT              0x80
+
+#define IPW_CARD_DISABLE_PHY_OFF_COMPLETE_WAIT     100 // 100 milli
+#define IPW_PREPARE_POWER_DOWN_COMPLETE_WAIT       100 // 100 milli
+
+
+
+
+#define IPW_HEADER_802_11_SIZE          sizeof(struct ieee80211_hdr_3addr)
+#define IPW_MAX_80211_PAYLOAD_SIZE              2304U
+#define IPW_MAX_802_11_PAYLOAD_LENGTH          2312
+#define IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH     1536
+#define IPW_MIN_ACCEPTABLE_RX_FRAME_LENGTH     60
+#define IPW_MAX_ACCEPTABLE_RX_FRAME_LENGTH \
+       (IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH + IPW_HEADER_802_11_SIZE - \
+        sizeof(struct ethhdr))
+
+#define IPW_802_11_FCS_LENGTH 4
+#define IPW_RX_NIC_BUFFER_LENGTH \
+        (IPW_MAX_802_11_PAYLOAD_LENGTH + IPW_HEADER_802_11_SIZE + \
+               IPW_802_11_FCS_LENGTH)
+
+#define IPW_802_11_PAYLOAD_OFFSET \
+        (sizeof(struct ieee80211_hdr_3addr) + \
+         sizeof(struct ieee80211_snap_hdr))
+
+struct ipw2100_rx {
+       union {
+               unsigned char payload[IPW_RX_NIC_BUFFER_LENGTH];
+               struct ieee80211_hdr header;
+               u32 status;
+               struct ipw2100_notification notification;
+               struct ipw2100_cmd_header command;
+       } rx_data;
+} __attribute__ ((packed));
+
+/* Bit 0-7 are for 802.11b tx rates - .  Bit 5-7 are reserved */
+#define TX_RATE_1_MBIT              0x0001
+#define TX_RATE_2_MBIT              0x0002
+#define TX_RATE_5_5_MBIT            0x0004
+#define TX_RATE_11_MBIT             0x0008
+#define TX_RATE_MASK                0x000F
+#define DEFAULT_TX_RATES            0x000F
+
+#define IPW_POWER_MODE_CAM           0x00      //(always on)
+#define IPW_POWER_INDEX_1            0x01
+#define IPW_POWER_INDEX_2            0x02
+#define IPW_POWER_INDEX_3            0x03
+#define IPW_POWER_INDEX_4            0x04
+#define IPW_POWER_INDEX_5            0x05
+#define IPW_POWER_AUTO               0x06
+#define IPW_POWER_MASK               0x0F
+#define IPW_POWER_ENABLED            0x10
+#define IPW_POWER_LEVEL(x)           ((x) & IPW_POWER_MASK)
+
+#define IPW_TX_POWER_AUTO            0
+#define IPW_TX_POWER_ENHANCED        1
+
+#define IPW_TX_POWER_DEFAULT         32
+#define IPW_TX_POWER_MIN             0
+#define IPW_TX_POWER_MAX             16
+#define IPW_TX_POWER_MIN_DBM         (-12)
+#define IPW_TX_POWER_MAX_DBM         16
+
+#define FW_SCAN_DONOT_ASSOCIATE     0x0001 // Dont Attempt to Associate after Scan
+#define FW_SCAN_PASSIVE             0x0008 // Force PASSSIVE Scan
+
+#define REG_MIN_CHANNEL             0
+#define REG_MAX_CHANNEL             14
+
+#define REG_CHANNEL_MASK            0x00003FFF
+#define IPW_IBSS_11B_DEFAULT_MASK   0x87ff
+
+#define DIVERSITY_EITHER            0  // Use both antennas
+#define DIVERSITY_ANTENNA_A         1  // Use antenna A
+#define DIVERSITY_ANTENNA_B         2  // Use antenna B
+
+
+#define HOST_COMMAND_WAIT 0
+#define HOST_COMMAND_NO_WAIT 1
+
+#define LOCK_NONE 0
+#define LOCK_DRIVER 1
+#define LOCK_FW 2
+
+#define TYPE_SWEEP_ORD                  0x000D
+#define TYPE_IBSS_STTN_ORD              0x000E
+#define TYPE_BSS_AP_ORD                 0x000F
+#define TYPE_RAW_BEACON_ENTRY           0x0010
+#define TYPE_CALIBRATION_DATA           0x0011
+#define TYPE_ROGUE_AP_DATA              0x0012
+#define TYPE_ASSOCIATION_REQUEST       0x0013
+#define TYPE_REASSOCIATION_REQUEST     0x0014
+
+
+#define HW_FEATURE_RFKILL (0x0001)
+#define RF_KILLSWITCH_OFF (1)
+#define RF_KILLSWITCH_ON  (0)
+
+#define IPW_COMMAND_POOL_SIZE        40
+
+#define IPW_START_ORD_TAB_1                    1
+#define IPW_START_ORD_TAB_2                    1000
+
+#define IPW_ORD_TAB_1_ENTRY_SIZE               sizeof(u32)
+
+#define IS_ORDINAL_TABLE_ONE(mgr,id) \
+    ((id >= IPW_START_ORD_TAB_1) && (id < mgr->table1_size))
+#define IS_ORDINAL_TABLE_TWO(mgr,id) \
+    ((id >= IPW_START_ORD_TAB_2) && (id < (mgr->table2_size + IPW_START_ORD_TAB_2)))
+
+#define BSS_ID_LENGTH               6
+
+// Fixed size data: Ordinal Table 1
+typedef enum _ORDINAL_TABLE_1 {        // NS - means Not Supported by FW
+// Transmit statistics
+       IPW_ORD_STAT_TX_HOST_REQUESTS = 1,// # of requested Host Tx's (MSDU)
+       IPW_ORD_STAT_TX_HOST_COMPLETE,  // # of successful Host Tx's (MSDU)
+       IPW_ORD_STAT_TX_DIR_DATA,       // # of successful Directed Tx's (MSDU)
+
+       IPW_ORD_STAT_TX_DIR_DATA1 = 4,  // # of successful Directed Tx's (MSDU) @ 1MB
+       IPW_ORD_STAT_TX_DIR_DATA2,      // # of successful Directed Tx's (MSDU) @ 2MB
+       IPW_ORD_STAT_TX_DIR_DATA5_5,    // # of successful Directed Tx's (MSDU) @ 5_5MB
+       IPW_ORD_STAT_TX_DIR_DATA11,     // # of successful Directed Tx's (MSDU) @ 11MB
+       IPW_ORD_STAT_TX_DIR_DATA22,     // # of successful Directed Tx's (MSDU) @ 22MB
+
+       IPW_ORD_STAT_TX_NODIR_DATA1 = 13,// # of successful Non_Directed Tx's (MSDU) @ 1MB
+       IPW_ORD_STAT_TX_NODIR_DATA2,    // # of successful Non_Directed Tx's (MSDU) @ 2MB
+       IPW_ORD_STAT_TX_NODIR_DATA5_5,  // # of successful Non_Directed Tx's (MSDU) @ 5.5MB
+       IPW_ORD_STAT_TX_NODIR_DATA11,   // # of successful Non_Directed Tx's (MSDU) @ 11MB
+
+       IPW_ORD_STAT_NULL_DATA = 21,    // # of successful NULL data Tx's
+       IPW_ORD_STAT_TX_RTS,            // # of successful Tx RTS
+       IPW_ORD_STAT_TX_CTS,            // # of successful Tx CTS
+       IPW_ORD_STAT_TX_ACK,            // # of successful Tx ACK
+       IPW_ORD_STAT_TX_ASSN,           // # of successful Association Tx's
+       IPW_ORD_STAT_TX_ASSN_RESP,      // # of successful Association response Tx's
+       IPW_ORD_STAT_TX_REASSN,         // # of successful Reassociation Tx's
+       IPW_ORD_STAT_TX_REASSN_RESP,    // # of successful Reassociation response Tx's
+       IPW_ORD_STAT_TX_PROBE,          // # of probes successfully transmitted
+       IPW_ORD_STAT_TX_PROBE_RESP,     // # of probe responses successfully transmitted
+       IPW_ORD_STAT_TX_BEACON,         // # of tx beacon
+       IPW_ORD_STAT_TX_ATIM,           // # of Tx ATIM
+       IPW_ORD_STAT_TX_DISASSN,        // # of successful Disassociation TX
+       IPW_ORD_STAT_TX_AUTH,           // # of successful Authentication Tx
+       IPW_ORD_STAT_TX_DEAUTH,         // # of successful Deauthentication TX
+
+       IPW_ORD_STAT_TX_TOTAL_BYTES = 41,// Total successful Tx data bytes
+       IPW_ORD_STAT_TX_RETRIES,         // # of Tx retries
+       IPW_ORD_STAT_TX_RETRY1,          // # of Tx retries at 1MBPS
+       IPW_ORD_STAT_TX_RETRY2,          // # of Tx retries at 2MBPS
+       IPW_ORD_STAT_TX_RETRY5_5,        // # of Tx retries at 5.5MBPS
+       IPW_ORD_STAT_TX_RETRY11,         // # of Tx retries at 11MBPS
+
+       IPW_ORD_STAT_TX_FAILURES = 51,  // # of Tx Failures
+       IPW_ORD_STAT_TX_ABORT_AT_HOP,   //NS // # of Tx's aborted at hop time
+       IPW_ORD_STAT_TX_MAX_TRIES_IN_HOP,// # of times max tries in a hop failed
+       IPW_ORD_STAT_TX_ABORT_LATE_DMA, //NS // # of times tx aborted due to late dma setup
+       IPW_ORD_STAT_TX_ABORT_STX,      //NS // # of times backoff aborted
+       IPW_ORD_STAT_TX_DISASSN_FAIL,   // # of times disassociation failed
+       IPW_ORD_STAT_TX_ERR_CTS,         // # of missed/bad CTS frames
+       IPW_ORD_STAT_TX_BPDU,           //NS // # of spanning tree BPDUs sent
+       IPW_ORD_STAT_TX_ERR_ACK,        // # of tx err due to acks
+
+       // Receive statistics
+       IPW_ORD_STAT_RX_HOST = 61,      // # of packets passed to host
+       IPW_ORD_STAT_RX_DIR_DATA,       // # of directed packets
+       IPW_ORD_STAT_RX_DIR_DATA1,      // # of directed packets at 1MB
+       IPW_ORD_STAT_RX_DIR_DATA2,      // # of directed packets at 2MB
+       IPW_ORD_STAT_RX_DIR_DATA5_5,    // # of directed packets at 5.5MB
+       IPW_ORD_STAT_RX_DIR_DATA11,     // # of directed packets at 11MB
+       IPW_ORD_STAT_RX_DIR_DATA22,     // # of directed packets at 22MB
+
+       IPW_ORD_STAT_RX_NODIR_DATA = 71,// # of nondirected packets
+       IPW_ORD_STAT_RX_NODIR_DATA1,    // # of nondirected packets at 1MB
+       IPW_ORD_STAT_RX_NODIR_DATA2,    // # of nondirected packets at 2MB
+       IPW_ORD_STAT_RX_NODIR_DATA5_5,  // # of nondirected packets at 5.5MB
+       IPW_ORD_STAT_RX_NODIR_DATA11,   // # of nondirected packets at 11MB
+
+       IPW_ORD_STAT_RX_NULL_DATA = 80, // # of null data rx's
+       IPW_ORD_STAT_RX_POLL,   //NS // # of poll rx
+       IPW_ORD_STAT_RX_RTS,    // # of Rx RTS
+       IPW_ORD_STAT_RX_CTS,    // # of Rx CTS
+       IPW_ORD_STAT_RX_ACK,    // # of Rx ACK
+       IPW_ORD_STAT_RX_CFEND,  // # of Rx CF End
+       IPW_ORD_STAT_RX_CFEND_ACK,      // # of Rx CF End + CF Ack
+       IPW_ORD_STAT_RX_ASSN,   // # of Association Rx's
+       IPW_ORD_STAT_RX_ASSN_RESP,      // # of Association response Rx's
+       IPW_ORD_STAT_RX_REASSN, // # of Reassociation Rx's
+       IPW_ORD_STAT_RX_REASSN_RESP,    // # of Reassociation response Rx's
+       IPW_ORD_STAT_RX_PROBE,  // # of probe Rx's
+       IPW_ORD_STAT_RX_PROBE_RESP,     // # of probe response Rx's
+       IPW_ORD_STAT_RX_BEACON, // # of Rx beacon
+       IPW_ORD_STAT_RX_ATIM,   // # of Rx ATIM
+       IPW_ORD_STAT_RX_DISASSN,        // # of disassociation Rx
+       IPW_ORD_STAT_RX_AUTH,   // # of authentication Rx
+       IPW_ORD_STAT_RX_DEAUTH, // # of deauthentication Rx
+
+       IPW_ORD_STAT_RX_TOTAL_BYTES = 101,// Total rx data bytes received
+       IPW_ORD_STAT_RX_ERR_CRC,         // # of packets with Rx CRC error
+       IPW_ORD_STAT_RX_ERR_CRC1,        // # of Rx CRC errors at 1MB
+       IPW_ORD_STAT_RX_ERR_CRC2,        // # of Rx CRC errors at 2MB
+       IPW_ORD_STAT_RX_ERR_CRC5_5,      // # of Rx CRC errors at 5.5MB
+       IPW_ORD_STAT_RX_ERR_CRC11,       // # of Rx CRC errors at 11MB
+
+       IPW_ORD_STAT_RX_DUPLICATE1 = 112, // # of duplicate rx packets at 1MB
+       IPW_ORD_STAT_RX_DUPLICATE2,      // # of duplicate rx packets at 2MB
+       IPW_ORD_STAT_RX_DUPLICATE5_5,    // # of duplicate rx packets at 5.5MB
+       IPW_ORD_STAT_RX_DUPLICATE11,     // # of duplicate rx packets at 11MB
+       IPW_ORD_STAT_RX_DUPLICATE = 119, // # of duplicate rx packets
+
+       IPW_ORD_PERS_DB_LOCK = 120,     // # locking fw permanent  db
+       IPW_ORD_PERS_DB_SIZE,   // # size of fw permanent  db
+       IPW_ORD_PERS_DB_ADDR,   // # address of fw permanent  db
+       IPW_ORD_STAT_RX_INVALID_PROTOCOL,       // # of rx frames with invalid protocol
+       IPW_ORD_SYS_BOOT_TIME,  // # Boot time
+       IPW_ORD_STAT_RX_NO_BUFFER,      // # of rx frames rejected due to no buffer
+       IPW_ORD_STAT_RX_ABORT_LATE_DMA, //NS // # of rx frames rejected due to dma setup too late
+       IPW_ORD_STAT_RX_ABORT_AT_HOP,   //NS // # of rx frames aborted due to hop
+       IPW_ORD_STAT_RX_MISSING_FRAG,   // # of rx frames dropped due to missing fragment
+       IPW_ORD_STAT_RX_ORPHAN_FRAG,    // # of rx frames dropped due to non-sequential fragment
+       IPW_ORD_STAT_RX_ORPHAN_FRAME,   // # of rx frames dropped due to unmatched 1st frame
+       IPW_ORD_STAT_RX_FRAG_AGEOUT,    // # of rx frames dropped due to uncompleted frame
+       IPW_ORD_STAT_RX_BAD_SSID,       //NS // Bad SSID (unused)
+       IPW_ORD_STAT_RX_ICV_ERRORS,     // # of ICV errors during decryption
+
+// PSP Statistics
+       IPW_ORD_STAT_PSP_SUSPENSION = 137,// # of times adapter suspended
+       IPW_ORD_STAT_PSP_BCN_TIMEOUT,   // # of beacon timeout
+       IPW_ORD_STAT_PSP_POLL_TIMEOUT,  // # of poll response timeouts
+       IPW_ORD_STAT_PSP_NONDIR_TIMEOUT,// # of timeouts waiting for last broadcast/muticast pkt
+       IPW_ORD_STAT_PSP_RX_DTIMS,      // # of PSP DTIMs received
+       IPW_ORD_STAT_PSP_RX_TIMS,       // # of PSP TIMs received
+       IPW_ORD_STAT_PSP_STATION_ID,    // PSP Station ID
+
+// Association and roaming
+       IPW_ORD_LAST_ASSN_TIME = 147,   // RTC time of last association
+       IPW_ORD_STAT_PERCENT_MISSED_BCNS,// current calculation of % missed beacons
+       IPW_ORD_STAT_PERCENT_RETRIES,   // current calculation of % missed tx retries
+       IPW_ORD_ASSOCIATED_AP_PTR,      // If associated, this is ptr to the associated
+       // AP table entry. set to 0 if not associated
+       IPW_ORD_AVAILABLE_AP_CNT,       // # of AP's decsribed in the AP table
+       IPW_ORD_AP_LIST_PTR,    // Ptr to list of available APs
+       IPW_ORD_STAT_AP_ASSNS,  // # of associations
+       IPW_ORD_STAT_ASSN_FAIL, // # of association failures
+       IPW_ORD_STAT_ASSN_RESP_FAIL,    // # of failuresdue to response fail
+       IPW_ORD_STAT_FULL_SCANS,        // # of full scans
+
+       IPW_ORD_CARD_DISABLED,  // # Card Disabled
+       IPW_ORD_STAT_ROAM_INHIBIT,      // # of times roaming was inhibited due to ongoing activity
+       IPW_FILLER_40,
+       IPW_ORD_RSSI_AT_ASSN = 160,     // RSSI of associated AP at time of association
+       IPW_ORD_STAT_ASSN_CAUSE1,       // # of reassociations due to no tx from AP in last N
+       // hops or no prob_ responses in last 3 minutes
+       IPW_ORD_STAT_ASSN_CAUSE2,       // # of reassociations due to poor tx/rx quality
+       IPW_ORD_STAT_ASSN_CAUSE3,       // # of reassociations due to tx/rx quality with excessive
+       // load at the AP
+       IPW_ORD_STAT_ASSN_CAUSE4,       // # of reassociations due to AP RSSI level fell below
+       // eligible group
+       IPW_ORD_STAT_ASSN_CAUSE5,       // # of reassociations due to load leveling
+       IPW_ORD_STAT_ASSN_CAUSE6,       //NS // # of reassociations due to dropped by Ap
+       IPW_FILLER_41,
+       IPW_FILLER_42,
+       IPW_FILLER_43,
+       IPW_ORD_STAT_AUTH_FAIL, // # of times authentication failed
+       IPW_ORD_STAT_AUTH_RESP_FAIL,    // # of times authentication response failed
+       IPW_ORD_STATION_TABLE_CNT,      // # of entries in association table
+
+// Other statistics
+       IPW_ORD_RSSI_AVG_CURR = 173,    // Current avg RSSI
+       IPW_ORD_STEST_RESULTS_CURR,     //NS // Current self test results word
+       IPW_ORD_STEST_RESULTS_CUM,      //NS // Cummulative self test results word
+       IPW_ORD_SELF_TEST_STATUS,       //NS //
+       IPW_ORD_POWER_MGMT_MODE,        // Power mode - 0=CAM, 1=PSP
+       IPW_ORD_POWER_MGMT_INDEX,       //NS //
+       IPW_ORD_COUNTRY_CODE,   // IEEE country code as recv'd from beacon
+       IPW_ORD_COUNTRY_CHANNELS,       // channels suported by country
+// IPW_ORD_COUNTRY_CHANNELS:
+// For 11b the lower 2-byte are used for channels from 1-14
+//   and the higher 2-byte are not used.
+       IPW_ORD_RESET_CNT,      // # of adapter resets (warm)
+       IPW_ORD_BEACON_INTERVAL,        // Beacon interval
+
+       IPW_ORD_PRINCETON_VERSION = 184,        //NS // Princeton Version
+       IPW_ORD_ANTENNA_DIVERSITY,      // TRUE if antenna diversity is disabled
+       IPW_ORD_CCA_RSSI,       //NS // CCA RSSI value (factory programmed)
+       IPW_ORD_STAT_EEPROM_UPDATE,     //NS // # of times config EEPROM updated
+       IPW_ORD_DTIM_PERIOD,    // # of beacon intervals between DTIMs
+       IPW_ORD_OUR_FREQ,       // current radio freq lower digits - channel ID
+
+       IPW_ORD_RTC_TIME = 190, // current RTC time
+       IPW_ORD_PORT_TYPE,      // operating mode
+       IPW_ORD_CURRENT_TX_RATE,        // current tx rate
+       IPW_ORD_SUPPORTED_RATES,        // Bitmap of supported tx rates
+       IPW_ORD_ATIM_WINDOW,    // current ATIM Window
+       IPW_ORD_BASIC_RATES,    // bitmap of basic tx rates
+       IPW_ORD_NIC_HIGHEST_RATE,       // bitmap of basic tx rates
+       IPW_ORD_AP_HIGHEST_RATE,        // bitmap of basic tx rates
+       IPW_ORD_CAPABILITIES,   // Management frame capability field
+       IPW_ORD_AUTH_TYPE,      // Type of authentication
+       IPW_ORD_RADIO_TYPE,     // Adapter card platform type
+       IPW_ORD_RTS_THRESHOLD = 201,    // Min length of packet after which RTS handshaking is used
+       IPW_ORD_INT_MODE,       // International mode
+       IPW_ORD_FRAGMENTATION_THRESHOLD,        // protocol frag threshold
+       IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS,     // EEPROM offset in SRAM
+       IPW_ORD_EEPROM_SRAM_DB_BLOCK_SIZE,      // EEPROM size in SRAM
+       IPW_ORD_EEPROM_SKU_CAPABILITY,  // EEPROM SKU Capability    206 =
+       IPW_ORD_EEPROM_IBSS_11B_CHANNELS,       // EEPROM IBSS 11b channel set
+
+       IPW_ORD_MAC_VERSION = 209,      // MAC Version
+       IPW_ORD_MAC_REVISION,   // MAC Revision
+       IPW_ORD_RADIO_VERSION,  // Radio Version
+       IPW_ORD_NIC_MANF_DATE_TIME,     // MANF Date/Time STAMP
+       IPW_ORD_UCODE_VERSION,  // Ucode Version
+       IPW_ORD_HW_RF_SWITCH_STATE = 214,       // HW RF Kill Switch State
+} ORDINALTABLE1;
+
+// ordinal table 2
+// Variable length data:
+#define IPW_FIRST_VARIABLE_LENGTH_ORDINAL   1001
+
+typedef enum _ORDINAL_TABLE_2 {        // NS - means Not Supported by FW
+       IPW_ORD_STAT_BASE = 1000,       // contains number of variable ORDs
+       IPW_ORD_STAT_ADAPTER_MAC = 1001,        // 6 bytes: our adapter MAC address
+       IPW_ORD_STAT_PREFERRED_BSSID = 1002,    // 6 bytes: BSSID of the preferred AP
+       IPW_ORD_STAT_MANDATORY_BSSID = 1003,    // 6 bytes: BSSID of the mandatory AP
+       IPW_FILL_1,             //NS //
+       IPW_ORD_STAT_COUNTRY_TEXT = 1005,       // 36 bytes: Country name text, First two bytes are Country code
+       IPW_ORD_STAT_ASSN_SSID = 1006,  // 32 bytes: ESSID String
+       IPW_ORD_STATION_TABLE = 1007,   // ? bytes: Station/AP table (via Direct SSID Scans)
+       IPW_ORD_STAT_SWEEP_TABLE = 1008,        // ? bytes: Sweep/Host Table table (via Broadcast Scans)
+       IPW_ORD_STAT_ROAM_LOG = 1009,   // ? bytes: Roaming log
+       IPW_ORD_STAT_RATE_LOG = 1010,   //NS // 0 bytes: Rate log
+       IPW_ORD_STAT_FIFO = 1011,       //NS // 0 bytes: Fifo buffer data structures
+       IPW_ORD_STAT_FW_VER_NUM = 1012, // 14 bytes: fw version ID string as in (a.bb.ccc; "0.08.011")
+       IPW_ORD_STAT_FW_DATE = 1013,    // 14 bytes: fw date string (mmm dd yyyy; "Mar 13 2002")
+       IPW_ORD_STAT_ASSN_AP_BSSID = 1014,      // 6 bytes: MAC address of associated AP
+       IPW_ORD_STAT_DEBUG = 1015,      //NS // ? bytes:
+       IPW_ORD_STAT_NIC_BPA_NUM = 1016,        // 11 bytes: NIC BPA number in ASCII
+       IPW_ORD_STAT_UCODE_DATE = 1017, // 5 bytes: uCode date
+       IPW_ORD_SECURITY_NGOTIATION_RESULT = 1018,
+} ORDINALTABLE2;               // NS - means Not Supported by FW
+
+#define IPW_LAST_VARIABLE_LENGTH_ORDINAL   1018
+
+#ifndef WIRELESS_SPY
+#define WIRELESS_SPY           // enable iwspy support
+#endif
+
+#define IPW_HOST_FW_SHARED_AREA0       0x0002f200
+#define IPW_HOST_FW_SHARED_AREA0_END   0x0002f510      // 0x310 bytes
+
+#define IPW_HOST_FW_SHARED_AREA1       0x0002f610
+#define IPW_HOST_FW_SHARED_AREA1_END   0x0002f630      // 0x20 bytes
+
+#define IPW_HOST_FW_SHARED_AREA2       0x0002fa00
+#define IPW_HOST_FW_SHARED_AREA2_END   0x0002fa20      // 0x20 bytes
+
+#define IPW_HOST_FW_SHARED_AREA3       0x0002fc00
+#define IPW_HOST_FW_SHARED_AREA3_END   0x0002fc10      // 0x10 bytes
+
+#define IPW_HOST_FW_INTERRUPT_AREA     0x0002ff80
+#define IPW_HOST_FW_INTERRUPT_AREA_END         0x00030000      // 0x80 bytes
+
+struct ipw2100_fw_chunk {
+       unsigned char *buf;
+       long len;
+       long pos;
+       struct list_head list;
+};
+
+struct ipw2100_fw_chunk_set {
+       const void *data;
+       unsigned long size;
+};
+
+struct ipw2100_fw {
+       int version;
+       struct ipw2100_fw_chunk_set fw;
+       struct ipw2100_fw_chunk_set uc;
+       const struct firmware *fw_entry;
+};
+
+#define MAX_FW_VERSION_LEN 14
+
+#endif /* _IPW2100_H */
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
new file mode 100644 (file)
index 0000000..b7f275c
--- /dev/null
@@ -0,0 +1,7383 @@
+/******************************************************************************
+
+  Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved.
+
+  802.11 status code portion of this file from ethereal-0.10.6:
+    Copyright 2000, Axis Communications AB
+    Ethereal - Network traffic analyzer
+    By Gerald Combs <gerald@ethereal.com>
+    Copyright 1998 Gerald Combs
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+
+  Contact Information:
+  James P. Ketrenos <ipw2100-admin@linux.intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+******************************************************************************/
+
+#include "ipw2200.h"
+
+#define IPW2200_VERSION "1.0.0"
+#define DRV_DESCRIPTION        "Intel(R) PRO/Wireless 2200/2915 Network Driver"
+#define DRV_COPYRIGHT  "Copyright(c) 2003-2004 Intel Corporation"
+#define DRV_VERSION     IPW2200_VERSION
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_LICENSE("GPL");
+
+static int debug = 0;
+static int channel = 0;
+static char *ifname;
+static int mode = 0;
+
+static u32 ipw_debug_level;
+static int associate = 1;
+static int auto_create = 1;
+static int disable = 0;
+static const char ipw_modes[] = {
+       'a', 'b', 'g', '?'
+};
+
+static void ipw_rx(struct ipw_priv *priv);
+static int ipw_queue_tx_reclaim(struct ipw_priv *priv,
+                               struct clx2_tx_queue *txq, int qindex);
+static int ipw_queue_reset(struct ipw_priv *priv);
+
+static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, void *buf,
+                            int len, int sync);
+
+static void ipw_tx_queue_free(struct ipw_priv *);
+
+static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *);
+static void ipw_rx_queue_free(struct ipw_priv *, struct ipw_rx_queue *);
+static void ipw_rx_queue_replenish(void *);
+
+static int ipw_up(struct ipw_priv *);
+static void ipw_down(struct ipw_priv *);
+static int ipw_config(struct ipw_priv *);
+static int init_supported_rates(struct ipw_priv *priv,
+                               struct ipw_supported_rates *prates);
+
+static u8 band_b_active_channel[MAX_B_CHANNELS] = {
+       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0
+};
+static u8 band_a_active_channel[MAX_A_CHANNELS] = {
+       36, 40, 44, 48, 149, 153, 157, 161, 165, 52, 56, 60, 64, 0
+};
+
+static int is_valid_channel(int mode_mask, int channel)
+{
+       int i;
+
+       if (!channel)
+               return 0;
+
+       if (mode_mask & IEEE_A)
+               for (i = 0; i < MAX_A_CHANNELS; i++)
+                       if (band_a_active_channel[i] == channel)
+                               return IEEE_A;
+
+       if (mode_mask & (IEEE_B | IEEE_G))
+               for (i = 0; i < MAX_B_CHANNELS; i++)
+                       if (band_b_active_channel[i] == channel)
+                               return mode_mask & (IEEE_B | IEEE_G);
+
+       return 0;
+}
+
+static char *snprint_line(char *buf, size_t count,
+                         const u8 * data, u32 len, u32 ofs)
+{
+       int out, i, j, l;
+       char c;
+
+       out = snprintf(buf, count, "%08X", ofs);
+
+       for (l = 0, i = 0; i < 2; i++) {
+               out += snprintf(buf + out, count - out, " ");
+               for (j = 0; j < 8 && l < len; j++, l++)
+                       out += snprintf(buf + out, count - out, "%02X ",
+                                       data[(i * 8 + j)]);
+               for (; j < 8; j++)
+                       out += snprintf(buf + out, count - out, "   ");
+       }
+
+       out += snprintf(buf + out, count - out, " ");
+       for (l = 0, i = 0; i < 2; i++) {
+               out += snprintf(buf + out, count - out, " ");
+               for (j = 0; j < 8 && l < len; j++, l++) {
+                       c = data[(i * 8 + j)];
+                       if (!isascii(c) || !isprint(c))
+                               c = '.';
+
+                       out += snprintf(buf + out, count - out, "%c", c);
+               }
+
+               for (; j < 8; j++)
+                       out += snprintf(buf + out, count - out, " ");
+       }
+
+       return buf;
+}
+
+static void printk_buf(int level, const u8 * data, u32 len)
+{
+       char line[81];
+       u32 ofs = 0;
+       if (!(ipw_debug_level & level))
+               return;
+
+       while (len) {
+               printk(KERN_DEBUG "%s\n",
+                      snprint_line(line, sizeof(line), &data[ofs],
+                                   min(len, 16U), ofs));
+               ofs += 16;
+               len -= min(len, 16U);
+       }
+}
+
+static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg);
+#define ipw_read_reg32(a, b) _ipw_read_reg32(a, b)
+
+static u8 _ipw_read_reg8(struct ipw_priv *ipw, u32 reg);
+#define ipw_read_reg8(a, b) _ipw_read_reg8(a, b)
+
+static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value);
+static inline void ipw_write_reg8(struct ipw_priv *a, u32 b, u8 c)
+{
+       IPW_DEBUG_IO("%s %d: write_indirect8(0x%08X, 0x%08X)\n", __FILE__,
+                    __LINE__, (u32) (b), (u32) (c));
+       _ipw_write_reg8(a, b, c);
+}
+
+static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value);
+static inline void ipw_write_reg16(struct ipw_priv *a, u32 b, u16 c)
+{
+       IPW_DEBUG_IO("%s %d: write_indirect16(0x%08X, 0x%08X)\n", __FILE__,
+                    __LINE__, (u32) (b), (u32) (c));
+       _ipw_write_reg16(a, b, c);
+}
+
+static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value);
+static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c)
+{
+       IPW_DEBUG_IO("%s %d: write_indirect32(0x%08X, 0x%08X)\n", __FILE__,
+                    __LINE__, (u32) (b), (u32) (c));
+       _ipw_write_reg32(a, b, c);
+}
+
+#define _ipw_write8(ipw, ofs, val) writeb((val), (ipw)->hw_base + (ofs))
+#define ipw_write8(ipw, ofs, val) \
+ IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \
+ _ipw_write8(ipw, ofs, val)
+
+#define _ipw_write16(ipw, ofs, val) writew((val), (ipw)->hw_base + (ofs))
+#define ipw_write16(ipw, ofs, val) \
+ IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \
+ _ipw_write16(ipw, ofs, val)
+
+#define _ipw_write32(ipw, ofs, val) writel((val), (ipw)->hw_base + (ofs))
+#define ipw_write32(ipw, ofs, val) \
+ IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \
+ _ipw_write32(ipw, ofs, val)
+
+#define _ipw_read8(ipw, ofs) readb((ipw)->hw_base + (ofs))
+static inline u8 __ipw_read8(char *f, u32 l, struct ipw_priv *ipw, u32 ofs)
+{
+       IPW_DEBUG_IO("%s %d: read_direct8(0x%08X)\n", f, l, (u32) (ofs));
+       return _ipw_read8(ipw, ofs);
+}
+
+#define ipw_read8(ipw, ofs) __ipw_read8(__FILE__, __LINE__, ipw, ofs)
+
+#define _ipw_read16(ipw, ofs) readw((ipw)->hw_base + (ofs))
+static inline u16 __ipw_read16(char *f, u32 l, struct ipw_priv *ipw, u32 ofs)
+{
+       IPW_DEBUG_IO("%s %d: read_direct16(0x%08X)\n", f, l, (u32) (ofs));
+       return _ipw_read16(ipw, ofs);
+}
+
+#define ipw_read16(ipw, ofs) __ipw_read16(__FILE__, __LINE__, ipw, ofs)
+
+#define _ipw_read32(ipw, ofs) readl((ipw)->hw_base + (ofs))
+static inline u32 __ipw_read32(char *f, u32 l, struct ipw_priv *ipw, u32 ofs)
+{
+       IPW_DEBUG_IO("%s %d: read_direct32(0x%08X)\n", f, l, (u32) (ofs));
+       return _ipw_read32(ipw, ofs);
+}
+
+#define ipw_read32(ipw, ofs) __ipw_read32(__FILE__, __LINE__, ipw, ofs)
+
+static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int);
+#define ipw_read_indirect(a, b, c, d) \
+       IPW_DEBUG_IO("%s %d: read_inddirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \
+       _ipw_read_indirect(a, b, c, d)
+
+static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data,
+                               int num);
+#define ipw_write_indirect(a, b, c, d) \
+       IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \
+        _ipw_write_indirect(a, b, c, d)
+
+/* indirect write s */
+static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value)
+{
+       IPW_DEBUG_IO(" %p : reg = 0x%8X : value = 0x%8X\n", priv, reg, value);
+       _ipw_write32(priv, CX2_INDIRECT_ADDR, reg);
+       _ipw_write32(priv, CX2_INDIRECT_DATA, value);
+}
+
+static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value)
+{
+       IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value);
+       _ipw_write32(priv, CX2_INDIRECT_ADDR, reg & CX2_INDIRECT_ADDR_MASK);
+       _ipw_write8(priv, CX2_INDIRECT_DATA, value);
+       IPW_DEBUG_IO(" reg = 0x%8lX : value = 0x%8X\n",
+                    (unsigned long)(priv->hw_base + CX2_INDIRECT_DATA), value);
+}
+
+static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value)
+{
+       IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value);
+       _ipw_write32(priv, CX2_INDIRECT_ADDR, reg & CX2_INDIRECT_ADDR_MASK);
+       _ipw_write16(priv, CX2_INDIRECT_DATA, value);
+}
+
+/* indirect read s */
+
+static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg)
+{
+       u32 word;
+       _ipw_write32(priv, CX2_INDIRECT_ADDR, reg & CX2_INDIRECT_ADDR_MASK);
+       IPW_DEBUG_IO(" reg = 0x%8X : \n", reg);
+       word = _ipw_read32(priv, CX2_INDIRECT_DATA);
+       return (word >> ((reg & 0x3) * 8)) & 0xff;
+}
+
+static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg)
+{
+       u32 value;
+
+       IPW_DEBUG_IO("%p : reg = 0x%08x\n", priv, reg);
+
+       _ipw_write32(priv, CX2_INDIRECT_ADDR, reg);
+       value = _ipw_read32(priv, CX2_INDIRECT_DATA);
+       IPW_DEBUG_IO(" reg = 0x%4X : value = 0x%4x \n", reg, value);
+       return value;
+}
+
+/* iterative/auto-increment 32 bit reads and writes */
+static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf,
+                              int num)
+{
+       u32 aligned_addr = addr & CX2_INDIRECT_ADDR_MASK;
+       u32 dif_len = addr - aligned_addr;
+       u32 aligned_len;
+       u32 i;
+
+       IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num);
+
+       /* Read the first nibble byte by byte */
+       if (unlikely(dif_len)) {
+               /* Start reading at aligned_addr + dif_len */
+               _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr);
+               for (i = dif_len; i < 4; i++, buf++)
+                       *buf = _ipw_read8(priv, CX2_INDIRECT_DATA + i);
+               num -= dif_len;
+               aligned_addr += 4;
+       }
+
+       /* Read DWs through autoinc register */
+       _ipw_write32(priv, CX2_AUTOINC_ADDR, aligned_addr);
+       aligned_len = num & CX2_INDIRECT_ADDR_MASK;
+       for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
+               *(u32 *) buf = ipw_read32(priv, CX2_AUTOINC_DATA);
+
+       /* Copy the last nibble */
+       dif_len = num - aligned_len;
+       _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr);
+       for (i = 0; i < dif_len; i++, buf++)
+               *buf = ipw_read8(priv, CX2_INDIRECT_DATA + i);
+}
+
+static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf,
+                               int num)
+{
+       u32 aligned_addr = addr & CX2_INDIRECT_ADDR_MASK;
+       u32 dif_len = addr - aligned_addr;
+       u32 aligned_len;
+       u32 i;
+
+       IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num);
+
+       /* Write the first nibble byte by byte */
+       if (unlikely(dif_len)) {
+               /* Start writing at aligned_addr + dif_len */
+               _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr);
+               for (i = dif_len; i < 4; i++, buf++)
+                       _ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf);
+               num -= dif_len;
+               aligned_addr += 4;
+       }
+
+       /* Write DWs through autoinc register */
+       _ipw_write32(priv, CX2_AUTOINC_ADDR, aligned_addr);
+       aligned_len = num & CX2_INDIRECT_ADDR_MASK;
+       for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
+               _ipw_write32(priv, CX2_AUTOINC_DATA, *(u32 *) buf);
+
+       /* Copy the last nibble */
+       dif_len = num - aligned_len;
+       _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr);
+       for (i = 0; i < dif_len; i++, buf++)
+               _ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf);
+}
+
+static void ipw_write_direct(struct ipw_priv *priv, u32 addr, void *buf,
+                            int num)
+{
+       memcpy_toio((priv->hw_base + addr), buf, num);
+}
+
+static inline void ipw_set_bit(struct ipw_priv *priv, u32 reg, u32 mask)
+{
+       ipw_write32(priv, reg, ipw_read32(priv, reg) | mask);
+}
+
+static inline void ipw_clear_bit(struct ipw_priv *priv, u32 reg, u32 mask)
+{
+       ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask);
+}
+
+static inline void ipw_enable_interrupts(struct ipw_priv *priv)
+{
+       if (priv->status & STATUS_INT_ENABLED)
+               return;
+       priv->status |= STATUS_INT_ENABLED;
+       ipw_write32(priv, CX2_INTA_MASK_R, CX2_INTA_MASK_ALL);
+}
+
+static inline void ipw_disable_interrupts(struct ipw_priv *priv)
+{
+       if (!(priv->status & STATUS_INT_ENABLED))
+               return;
+       priv->status &= ~STATUS_INT_ENABLED;
+       ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL);
+}
+
+static char *ipw_error_desc(u32 val)
+{
+       switch (val) {
+       case IPW_FW_ERROR_OK:
+               return "ERROR_OK";
+       case IPW_FW_ERROR_FAIL:
+               return "ERROR_FAIL";
+       case IPW_FW_ERROR_MEMORY_UNDERFLOW:
+               return "MEMORY_UNDERFLOW";
+       case IPW_FW_ERROR_MEMORY_OVERFLOW:
+               return "MEMORY_OVERFLOW";
+       case IPW_FW_ERROR_BAD_PARAM:
+               return "ERROR_BAD_PARAM";
+       case IPW_FW_ERROR_BAD_CHECKSUM:
+               return "ERROR_BAD_CHECKSUM";
+       case IPW_FW_ERROR_NMI_INTERRUPT:
+               return "ERROR_NMI_INTERRUPT";
+       case IPW_FW_ERROR_BAD_DATABASE:
+               return "ERROR_BAD_DATABASE";
+       case IPW_FW_ERROR_ALLOC_FAIL:
+               return "ERROR_ALLOC_FAIL";
+       case IPW_FW_ERROR_DMA_UNDERRUN:
+               return "ERROR_DMA_UNDERRUN";
+       case IPW_FW_ERROR_DMA_STATUS:
+               return "ERROR_DMA_STATUS";
+       case IPW_FW_ERROR_DINOSTATUS_ERROR:
+               return "ERROR_DINOSTATUS_ERROR";
+       case IPW_FW_ERROR_EEPROMSTATUS_ERROR:
+               return "ERROR_EEPROMSTATUS_ERROR";
+       case IPW_FW_ERROR_SYSASSERT:
+               return "ERROR_SYSASSERT";
+       case IPW_FW_ERROR_FATAL_ERROR:
+               return "ERROR_FATALSTATUS_ERROR";
+       default:
+               return "UNKNOWNSTATUS_ERROR";
+       }
+}
+
+static void ipw_dump_nic_error_log(struct ipw_priv *priv)
+{
+       u32 desc, time, blink1, blink2, ilink1, ilink2, idata, i, count, base;
+
+       base = ipw_read32(priv, IPWSTATUS_ERROR_LOG);
+       count = ipw_read_reg32(priv, base);
+
+       if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+               IPW_ERROR("Start IPW Error Log Dump:\n");
+               IPW_ERROR("Status: 0x%08X, Config: %08X\n",
+                         priv->status, priv->config);
+       }
+
+       for (i = ERROR_START_OFFSET;
+            i <= count * ERROR_ELEM_SIZE; i += ERROR_ELEM_SIZE) {
+               desc = ipw_read_reg32(priv, base + i);
+               time = ipw_read_reg32(priv, base + i + 1 * sizeof(u32));
+               blink1 = ipw_read_reg32(priv, base + i + 2 * sizeof(u32));
+               blink2 = ipw_read_reg32(priv, base + i + 3 * sizeof(u32));
+               ilink1 = ipw_read_reg32(priv, base + i + 4 * sizeof(u32));
+               ilink2 = ipw_read_reg32(priv, base + i + 5 * sizeof(u32));
+               idata = ipw_read_reg32(priv, base + i + 6 * sizeof(u32));
+
+               IPW_ERROR("%s %i 0x%08x  0x%08x  0x%08x  0x%08x  0x%08x\n",
+                         ipw_error_desc(desc), time, blink1, blink2,
+                         ilink1, ilink2, idata);
+       }
+}
+
+static void ipw_dump_nic_event_log(struct ipw_priv *priv)
+{
+       u32 ev, time, data, i, count, base;
+
+       base = ipw_read32(priv, IPW_EVENT_LOG);
+       count = ipw_read_reg32(priv, base);
+
+       if (EVENT_START_OFFSET <= count * EVENT_ELEM_SIZE)
+               IPW_ERROR("Start IPW Event Log Dump:\n");
+
+       for (i = EVENT_START_OFFSET;
+            i <= count * EVENT_ELEM_SIZE; i += EVENT_ELEM_SIZE) {
+               ev = ipw_read_reg32(priv, base + i);
+               time = ipw_read_reg32(priv, base + i + 1 * sizeof(u32));
+               data = ipw_read_reg32(priv, base + i + 2 * sizeof(u32));
+
+#ifdef CONFIG_IPW_DEBUG
+               IPW_ERROR("%i\t0x%08x\t%i\n", time, data, ev);
+#endif
+       }
+}
+
+static int ipw_get_ordinal(struct ipw_priv *priv, u32 ord, void *val, u32 * len)
+{
+       u32 addr, field_info, field_len, field_count, total_len;
+
+       IPW_DEBUG_ORD("ordinal = %i\n", ord);
+
+       if (!priv || !val || !len) {
+               IPW_DEBUG_ORD("Invalid argument\n");
+               return -EINVAL;
+       }
+
+       /* verify device ordinal tables have been initialized */
+       if (!priv->table0_addr || !priv->table1_addr || !priv->table2_addr) {
+               IPW_DEBUG_ORD("Access ordinals before initialization\n");
+               return -EINVAL;
+       }
+
+       switch (IPW_ORD_TABLE_ID_MASK & ord) {
+       case IPW_ORD_TABLE_0_MASK:
+               /*
+                * TABLE 0: Direct access to a table of 32 bit values
+                *
+                * This is a very simple table with the data directly
+                * read from the table
+                */
+
+               /* remove the table id from the ordinal */
+               ord &= IPW_ORD_TABLE_VALUE_MASK;
+
+               /* boundary check */
+               if (ord > priv->table0_len) {
+                       IPW_DEBUG_ORD("ordinal value (%i) longer then "
+                                     "max (%i)\n", ord, priv->table0_len);
+                       return -EINVAL;
+               }
+
+               /* verify we have enough room to store the value */
+               if (*len < sizeof(u32)) {
+                       IPW_DEBUG_ORD("ordinal buffer length too small, "
+                                     "need %zd\n", sizeof(u32));
+                       return -EINVAL;
+               }
+
+               IPW_DEBUG_ORD("Reading TABLE0[%i] from offset 0x%08x\n",
+                             ord, priv->table0_addr + (ord << 2));
+
+               *len = sizeof(u32);
+               ord <<= 2;
+               *((u32 *) val) = ipw_read32(priv, priv->table0_addr + ord);
+               break;
+
+       case IPW_ORD_TABLE_1_MASK:
+               /*
+                * TABLE 1: Indirect access to a table of 32 bit values
+                *
+                * This is a fairly large table of u32 values each
+                * representing starting addr for the data (which is
+                * also a u32)
+                */
+
+               /* remove the table id from the ordinal */
+               ord &= IPW_ORD_TABLE_VALUE_MASK;
+
+               /* boundary check */
+               if (ord > priv->table1_len) {
+                       IPW_DEBUG_ORD("ordinal value too long\n");
+                       return -EINVAL;
+               }
+
+               /* verify we have enough room to store the value */
+               if (*len < sizeof(u32)) {
+                       IPW_DEBUG_ORD("ordinal buffer length too small, "
+                                     "need %zd\n", sizeof(u32));
+                       return -EINVAL;
+               }
+
+               *((u32 *) val) =
+                   ipw_read_reg32(priv, (priv->table1_addr + (ord << 2)));
+               *len = sizeof(u32);
+               break;
+
+       case IPW_ORD_TABLE_2_MASK:
+               /*
+                * TABLE 2: Indirect access to a table of variable sized values
+                *
+                * This table consist of six values, each containing
+                *     - dword containing the starting offset of the data
+                *     - dword containing the lengh in the first 16bits
+                *       and the count in the second 16bits
+                */
+
+               /* remove the table id from the ordinal */
+               ord &= IPW_ORD_TABLE_VALUE_MASK;
+
+               /* boundary check */
+               if (ord > priv->table2_len) {
+                       IPW_DEBUG_ORD("ordinal value too long\n");
+                       return -EINVAL;
+               }
+
+               /* get the address of statistic */
+               addr = ipw_read_reg32(priv, priv->table2_addr + (ord << 3));
+
+               /* get the second DW of statistics ;
+                * two 16-bit words - first is length, second is count */
+               field_info =
+                   ipw_read_reg32(priv,
+                                  priv->table2_addr + (ord << 3) +
+                                  sizeof(u32));
+
+               /* get each entry length */
+               field_len = *((u16 *) & field_info);
+
+               /* get number of entries */
+               field_count = *(((u16 *) & field_info) + 1);
+
+               /* abort if not enought memory */
+               total_len = field_len * field_count;
+               if (total_len > *len) {
+                       *len = total_len;
+                       return -EINVAL;
+               }
+
+               *len = total_len;
+               if (!total_len)
+                       return 0;
+
+               IPW_DEBUG_ORD("addr = 0x%08x, total_len = %i, "
+                             "field_info = 0x%08x\n",
+                             addr, total_len, field_info);
+               ipw_read_indirect(priv, addr, val, total_len);
+               break;
+
+       default:
+               IPW_DEBUG_ORD("Invalid ordinal!\n");
+               return -EINVAL;
+
+       }
+
+       return 0;
+}
+
+static void ipw_init_ordinals(struct ipw_priv *priv)
+{
+       priv->table0_addr = IPW_ORDINALS_TABLE_LOWER;
+       priv->table0_len = ipw_read32(priv, priv->table0_addr);
+
+       IPW_DEBUG_ORD("table 0 offset at 0x%08x, len = %i\n",
+                     priv->table0_addr, priv->table0_len);
+
+       priv->table1_addr = ipw_read32(priv, IPW_ORDINALS_TABLE_1);
+       priv->table1_len = ipw_read_reg32(priv, priv->table1_addr);
+
+       IPW_DEBUG_ORD("table 1 offset at 0x%08x, len = %i\n",
+                     priv->table1_addr, priv->table1_len);
+
+       priv->table2_addr = ipw_read32(priv, IPW_ORDINALS_TABLE_2);
+       priv->table2_len = ipw_read_reg32(priv, priv->table2_addr);
+       priv->table2_len &= 0x0000ffff; /* use first two bytes */
+
+       IPW_DEBUG_ORD("table 2 offset at 0x%08x, len = %i\n",
+                     priv->table2_addr, priv->table2_len);
+
+}
+
+/*
+ * The following adds a new attribute to the sysfs representation
+ * of this device driver (i.e. a new file in /sys/bus/pci/drivers/ipw/)
+ * used for controling the debug level.
+ *
+ * See the level definitions in ipw for details.
+ */
+static ssize_t show_debug_level(struct device_driver *d, char *buf)
+{
+       return sprintf(buf, "0x%08X\n", ipw_debug_level);
+}
+static ssize_t store_debug_level(struct device_driver *d,
+                                const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+       u32 val;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+               p++;
+               if (p[0] == 'x' || p[0] == 'X')
+                       p++;
+               val = simple_strtoul(p, &p, 16);
+       } else
+               val = simple_strtoul(p, &p, 10);
+       if (p == buf)
+               printk(KERN_INFO DRV_NAME
+                      ": %s is not in hex or decimal form.\n", buf);
+       else
+               ipw_debug_level = val;
+
+       return strnlen(buf, count);
+}
+
+static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
+                  show_debug_level, store_debug_level);
+
+static ssize_t show_status(struct device *d,
+                          struct device_attribute *attr, char *buf)
+{
+       struct ipw_priv *p = d->driver_data;
+       return sprintf(buf, "0x%08x\n", (int)p->status);
+}
+
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+
+static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
+                       char *buf)
+{
+       struct ipw_priv *p = d->driver_data;
+       return sprintf(buf, "0x%08x\n", (int)p->config);
+}
+
+static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL);
+
+static ssize_t show_nic_type(struct device *d,
+                            struct device_attribute *attr, char *buf)
+{
+       struct ipw_priv *p = d->driver_data;
+       u8 type = p->eeprom[EEPROM_NIC_TYPE];
+
+       switch (type) {
+       case EEPROM_NIC_TYPE_STANDARD:
+               return sprintf(buf, "STANDARD\n");
+       case EEPROM_NIC_TYPE_DELL:
+               return sprintf(buf, "DELL\n");
+       case EEPROM_NIC_TYPE_FUJITSU:
+               return sprintf(buf, "FUJITSU\n");
+       case EEPROM_NIC_TYPE_IBM:
+               return sprintf(buf, "IBM\n");
+       case EEPROM_NIC_TYPE_HP:
+               return sprintf(buf, "HP\n");
+       }
+
+       return sprintf(buf, "UNKNOWN\n");
+}
+
+static DEVICE_ATTR(nic_type, S_IRUGO, show_nic_type, NULL);
+
+static ssize_t dump_error_log(struct device *d,
+                             struct device_attribute *attr, const char *buf,
+                             size_t count)
+{
+       char *p = (char *)buf;
+
+       if (p[0] == '1')
+               ipw_dump_nic_error_log((struct ipw_priv *)d->driver_data);
+
+       return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log);
+
+static ssize_t dump_event_log(struct device *d,
+                             struct device_attribute *attr, const char *buf,
+                             size_t count)
+{
+       char *p = (char *)buf;
+
+       if (p[0] == '1')
+               ipw_dump_nic_event_log((struct ipw_priv *)d->driver_data);
+
+       return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
+
+static ssize_t show_ucode_version(struct device *d,
+                                 struct device_attribute *attr, char *buf)
+{
+       u32 len = sizeof(u32), tmp = 0;
+       struct ipw_priv *p = d->driver_data;
+
+       if (ipw_get_ordinal(p, IPW_ORD_STAT_UCODE_VERSION, &tmp, &len))
+               return 0;
+
+       return sprintf(buf, "0x%08x\n", tmp);
+}
+
+static DEVICE_ATTR(ucode_version, S_IWUSR | S_IRUGO, show_ucode_version, NULL);
+
+static ssize_t show_rtc(struct device *d, struct device_attribute *attr,
+                       char *buf)
+{
+       u32 len = sizeof(u32), tmp = 0;
+       struct ipw_priv *p = d->driver_data;
+
+       if (ipw_get_ordinal(p, IPW_ORD_STAT_RTC, &tmp, &len))
+               return 0;
+
+       return sprintf(buf, "0x%08x\n", tmp);
+}
+
+static DEVICE_ATTR(rtc, S_IWUSR | S_IRUGO, show_rtc, NULL);
+
+/*
+ * Add a device attribute to view/control the delay between eeprom
+ * operations.
+ */
+static ssize_t show_eeprom_delay(struct device *d,
+                                struct device_attribute *attr, char *buf)
+{
+       int n = ((struct ipw_priv *)d->driver_data)->eeprom_delay;
+       return sprintf(buf, "%i\n", n);
+}
+static ssize_t store_eeprom_delay(struct device *d,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct ipw_priv *p = d->driver_data;
+       sscanf(buf, "%i", &p->eeprom_delay);
+       return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(eeprom_delay, S_IWUSR | S_IRUGO,
+                  show_eeprom_delay, store_eeprom_delay);
+
+static ssize_t show_command_event_reg(struct device *d,
+                                     struct device_attribute *attr, char *buf)
+{
+       u32 reg = 0;
+       struct ipw_priv *p = d->driver_data;
+
+       reg = ipw_read_reg32(p, CX2_INTERNAL_CMD_EVENT);
+       return sprintf(buf, "0x%08x\n", reg);
+}
+static ssize_t store_command_event_reg(struct device *d,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t count)
+{
+       u32 reg;
+       struct ipw_priv *p = d->driver_data;
+
+       sscanf(buf, "%x", &reg);
+       ipw_write_reg32(p, CX2_INTERNAL_CMD_EVENT, reg);
+       return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(command_event_reg, S_IWUSR | S_IRUGO,
+                  show_command_event_reg, store_command_event_reg);
+
+static ssize_t show_mem_gpio_reg(struct device *d,
+                                struct device_attribute *attr, char *buf)
+{
+       u32 reg = 0;
+       struct ipw_priv *p = d->driver_data;
+
+       reg = ipw_read_reg32(p, 0x301100);
+       return sprintf(buf, "0x%08x\n", reg);
+}
+static ssize_t store_mem_gpio_reg(struct device *d,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       u32 reg;
+       struct ipw_priv *p = d->driver_data;
+
+       sscanf(buf, "%x", &reg);
+       ipw_write_reg32(p, 0x301100, reg);
+       return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(mem_gpio_reg, S_IWUSR | S_IRUGO,
+                  show_mem_gpio_reg, store_mem_gpio_reg);
+
+static ssize_t show_indirect_dword(struct device *d,
+                                  struct device_attribute *attr, char *buf)
+{
+       u32 reg = 0;
+       struct ipw_priv *priv = d->driver_data;
+       if (priv->status & STATUS_INDIRECT_DWORD)
+               reg = ipw_read_reg32(priv, priv->indirect_dword);
+       else
+               reg = 0;
+
+       return sprintf(buf, "0x%08x\n", reg);
+}
+static ssize_t store_indirect_dword(struct device *d,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       struct ipw_priv *priv = d->driver_data;
+
+       sscanf(buf, "%x", &priv->indirect_dword);
+       priv->status |= STATUS_INDIRECT_DWORD;
+       return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(indirect_dword, S_IWUSR | S_IRUGO,
+                  show_indirect_dword, store_indirect_dword);
+
+static ssize_t show_indirect_byte(struct device *d,
+                                 struct device_attribute *attr, char *buf)
+{
+       u8 reg = 0;
+       struct ipw_priv *priv = d->driver_data;
+       if (priv->status & STATUS_INDIRECT_BYTE)
+               reg = ipw_read_reg8(priv, priv->indirect_byte);
+       else
+               reg = 0;
+
+       return sprintf(buf, "0x%02x\n", reg);
+}
+static ssize_t store_indirect_byte(struct device *d,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count)
+{
+       struct ipw_priv *priv = d->driver_data;
+
+       sscanf(buf, "%x", &priv->indirect_byte);
+       priv->status |= STATUS_INDIRECT_BYTE;
+       return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(indirect_byte, S_IWUSR | S_IRUGO,
+                  show_indirect_byte, store_indirect_byte);
+
+static ssize_t show_direct_dword(struct device *d,
+                                struct device_attribute *attr, char *buf)
+{
+       u32 reg = 0;
+       struct ipw_priv *priv = d->driver_data;
+
+       if (priv->status & STATUS_DIRECT_DWORD)
+               reg = ipw_read32(priv, priv->direct_dword);
+       else
+               reg = 0;
+
+       return sprintf(buf, "0x%08x\n", reg);
+}
+static ssize_t store_direct_dword(struct device *d,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct ipw_priv *priv = d->driver_data;
+
+       sscanf(buf, "%x", &priv->direct_dword);
+       priv->status |= STATUS_DIRECT_DWORD;
+       return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(direct_dword, S_IWUSR | S_IRUGO,
+                  show_direct_dword, store_direct_dword);
+
+static inline int rf_kill_active(struct ipw_priv *priv)
+{
+       if (0 == (ipw_read32(priv, 0x30) & 0x10000))
+               priv->status |= STATUS_RF_KILL_HW;
+       else
+               priv->status &= ~STATUS_RF_KILL_HW;
+
+       return (priv->status & STATUS_RF_KILL_HW) ? 1 : 0;
+}
+
+static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr,
+                           char *buf)
+{
+       /* 0 - RF kill not enabled
+          1 - SW based RF kill active (sysfs)
+          2 - HW based RF kill active
+          3 - Both HW and SW baed RF kill active */
+       struct ipw_priv *priv = d->driver_data;
+       int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) |
+           (rf_kill_active(priv) ? 0x2 : 0x0);
+       return sprintf(buf, "%i\n", val);
+}
+
+static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio)
+{
+       if ((disable_radio ? 1 : 0) ==
+           (priv->status & STATUS_RF_KILL_SW ? 1 : 0))
+               return 0;
+
+       IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO  %s\n",
+                         disable_radio ? "OFF" : "ON");
+
+       if (disable_radio) {
+               priv->status |= STATUS_RF_KILL_SW;
+
+               if (priv->workqueue) {
+                       cancel_delayed_work(&priv->request_scan);
+               }
+               wake_up_interruptible(&priv->wait_command_queue);
+               queue_work(priv->workqueue, &priv->down);
+       } else {
+               priv->status &= ~STATUS_RF_KILL_SW;
+               if (rf_kill_active(priv)) {
+                       IPW_DEBUG_RF_KILL("Can not turn radio back on - "
+                                         "disabled by HW switch\n");
+                       /* Make sure the RF_KILL check timer is running */
+                       cancel_delayed_work(&priv->rf_kill);
+                       queue_delayed_work(priv->workqueue, &priv->rf_kill,
+                                          2 * HZ);
+               } else
+                       queue_work(priv->workqueue, &priv->up);
+       }
+
+       return 1;
+}
+
+static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+       struct ipw_priv *priv = d->driver_data;
+
+       ipw_radio_kill_sw(priv, buf[0] == '1');
+
+       return count;
+}
+
+static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
+
+static void ipw_irq_tasklet(struct ipw_priv *priv)
+{
+       u32 inta, inta_mask, handled = 0;
+       unsigned long flags;
+       int rc = 0;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       inta = ipw_read32(priv, CX2_INTA_RW);
+       inta_mask = ipw_read32(priv, CX2_INTA_MASK_R);
+       inta &= (CX2_INTA_MASK_ALL & inta_mask);
+
+       /* Add any cached INTA values that need to be handled */
+       inta |= priv->isr_inta;
+
+       /* handle all the justifications for the interrupt */
+       if (inta & CX2_INTA_BIT_RX_TRANSFER) {
+               ipw_rx(priv);
+               handled |= CX2_INTA_BIT_RX_TRANSFER;
+       }
+
+       if (inta & CX2_INTA_BIT_TX_CMD_QUEUE) {
+               IPW_DEBUG_HC("Command completed.\n");
+               rc = ipw_queue_tx_reclaim(priv, &priv->txq_cmd, -1);
+               priv->status &= ~STATUS_HCMD_ACTIVE;
+               wake_up_interruptible(&priv->wait_command_queue);
+               handled |= CX2_INTA_BIT_TX_CMD_QUEUE;
+       }
+
+       if (inta & CX2_INTA_BIT_TX_QUEUE_1) {
+               IPW_DEBUG_TX("TX_QUEUE_1\n");
+               rc = ipw_queue_tx_reclaim(priv, &priv->txq[0], 0);
+               handled |= CX2_INTA_BIT_TX_QUEUE_1;
+       }
+
+       if (inta & CX2_INTA_BIT_TX_QUEUE_2) {
+               IPW_DEBUG_TX("TX_QUEUE_2\n");
+               rc = ipw_queue_tx_reclaim(priv, &priv->txq[1], 1);
+               handled |= CX2_INTA_BIT_TX_QUEUE_2;
+       }
+
+       if (inta & CX2_INTA_BIT_TX_QUEUE_3) {
+               IPW_DEBUG_TX("TX_QUEUE_3\n");
+               rc = ipw_queue_tx_reclaim(priv, &priv->txq[2], 2);
+               handled |= CX2_INTA_BIT_TX_QUEUE_3;
+       }
+
+       if (inta & CX2_INTA_BIT_TX_QUEUE_4) {
+               IPW_DEBUG_TX("TX_QUEUE_4\n");
+               rc = ipw_queue_tx_reclaim(priv, &priv->txq[3], 3);
+               handled |= CX2_INTA_BIT_TX_QUEUE_4;
+       }
+
+       if (inta & CX2_INTA_BIT_STATUS_CHANGE) {
+               IPW_WARNING("STATUS_CHANGE\n");
+               handled |= CX2_INTA_BIT_STATUS_CHANGE;
+       }
+
+       if (inta & CX2_INTA_BIT_BEACON_PERIOD_EXPIRED) {
+               IPW_WARNING("TX_PERIOD_EXPIRED\n");
+               handled |= CX2_INTA_BIT_BEACON_PERIOD_EXPIRED;
+       }
+
+       if (inta & CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE) {
+               IPW_WARNING("HOST_CMD_DONE\n");
+               handled |= CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE;
+       }
+
+       if (inta & CX2_INTA_BIT_FW_INITIALIZATION_DONE) {
+               IPW_WARNING("FW_INITIALIZATION_DONE\n");
+               handled |= CX2_INTA_BIT_FW_INITIALIZATION_DONE;
+       }
+
+       if (inta & CX2_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE) {
+               IPW_WARNING("PHY_OFF_DONE\n");
+               handled |= CX2_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE;
+       }
+
+       if (inta & CX2_INTA_BIT_RF_KILL_DONE) {
+               IPW_DEBUG_RF_KILL("RF_KILL_DONE\n");
+               priv->status |= STATUS_RF_KILL_HW;
+               wake_up_interruptible(&priv->wait_command_queue);
+               netif_carrier_off(priv->net_dev);
+               netif_stop_queue(priv->net_dev);
+               cancel_delayed_work(&priv->request_scan);
+               queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ);
+               handled |= CX2_INTA_BIT_RF_KILL_DONE;
+       }
+
+       if (inta & CX2_INTA_BIT_FATAL_ERROR) {
+               IPW_ERROR("Firmware error detected.  Restarting.\n");
+#ifdef CONFIG_IPW_DEBUG
+               if (ipw_debug_level & IPW_DL_FW_ERRORS) {
+                       ipw_dump_nic_error_log(priv);
+                       ipw_dump_nic_event_log(priv);
+               }
+#endif
+               queue_work(priv->workqueue, &priv->adapter_restart);
+               handled |= CX2_INTA_BIT_FATAL_ERROR;
+       }
+
+       if (inta & CX2_INTA_BIT_PARITY_ERROR) {
+               IPW_ERROR("Parity error\n");
+               handled |= CX2_INTA_BIT_PARITY_ERROR;
+       }
+
+       if (handled != inta) {
+               IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled);
+       }
+
+       /* enable all interrupts */
+       ipw_enable_interrupts(priv);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+#ifdef CONFIG_IPW_DEBUG
+#define IPW_CMD(x) case IPW_CMD_ ## x : return #x
+static char *get_cmd_string(u8 cmd)
+{
+       switch (cmd) {
+               IPW_CMD(HOST_COMPLETE);
+               IPW_CMD(POWER_DOWN);
+               IPW_CMD(SYSTEM_CONFIG);
+               IPW_CMD(MULTICAST_ADDRESS);
+               IPW_CMD(SSID);
+               IPW_CMD(ADAPTER_ADDRESS);
+               IPW_CMD(PORT_TYPE);
+               IPW_CMD(RTS_THRESHOLD);
+               IPW_CMD(FRAG_THRESHOLD);
+               IPW_CMD(POWER_MODE);
+               IPW_CMD(WEP_KEY);
+               IPW_CMD(TGI_TX_KEY);
+               IPW_CMD(SCAN_REQUEST);
+               IPW_CMD(SCAN_REQUEST_EXT);
+               IPW_CMD(ASSOCIATE);
+               IPW_CMD(SUPPORTED_RATES);
+               IPW_CMD(SCAN_ABORT);
+               IPW_CMD(TX_FLUSH);
+               IPW_CMD(QOS_PARAMETERS);
+               IPW_CMD(DINO_CONFIG);
+               IPW_CMD(RSN_CAPABILITIES);
+               IPW_CMD(RX_KEY);
+               IPW_CMD(CARD_DISABLE);
+               IPW_CMD(SEED_NUMBER);
+               IPW_CMD(TX_POWER);
+               IPW_CMD(COUNTRY_INFO);
+               IPW_CMD(AIRONET_INFO);
+               IPW_CMD(AP_TX_POWER);
+               IPW_CMD(CCKM_INFO);
+               IPW_CMD(CCX_VER_INFO);
+               IPW_CMD(SET_CALIBRATION);
+               IPW_CMD(SENSITIVITY_CALIB);
+               IPW_CMD(RETRY_LIMIT);
+               IPW_CMD(IPW_PRE_POWER_DOWN);
+               IPW_CMD(VAP_BEACON_TEMPLATE);
+               IPW_CMD(VAP_DTIM_PERIOD);
+               IPW_CMD(EXT_SUPPORTED_RATES);
+               IPW_CMD(VAP_LOCAL_TX_PWR_CONSTRAINT);
+               IPW_CMD(VAP_QUIET_INTERVALS);
+               IPW_CMD(VAP_CHANNEL_SWITCH);
+               IPW_CMD(VAP_MANDATORY_CHANNELS);
+               IPW_CMD(VAP_CELL_PWR_LIMIT);
+               IPW_CMD(VAP_CF_PARAM_SET);
+               IPW_CMD(VAP_SET_BEACONING_STATE);
+               IPW_CMD(MEASUREMENT);
+               IPW_CMD(POWER_CAPABILITY);
+               IPW_CMD(SUPPORTED_CHANNELS);
+               IPW_CMD(TPC_REPORT);
+               IPW_CMD(WME_INFO);
+               IPW_CMD(PRODUCTION_COMMAND);
+       default:
+               return "UNKNOWN";
+       }
+}
+#endif                         /* CONFIG_IPW_DEBUG */
+
+#define HOST_COMPLETE_TIMEOUT HZ
+static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd)
+{
+       int rc = 0;
+
+       if (priv->status & STATUS_HCMD_ACTIVE) {
+               IPW_ERROR("Already sending a command\n");
+               return -1;
+       }
+
+       priv->status |= STATUS_HCMD_ACTIVE;
+
+       IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n",
+                    get_cmd_string(cmd->cmd), cmd->cmd, cmd->len);
+       printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len);
+
+       rc = ipw_queue_tx_hcmd(priv, cmd->cmd, &cmd->param, cmd->len, 0);
+       if (rc)
+               return rc;
+
+       rc = wait_event_interruptible_timeout(priv->wait_command_queue,
+                                             !(priv->
+                                               status & STATUS_HCMD_ACTIVE),
+                                             HOST_COMPLETE_TIMEOUT);
+       if (rc == 0) {
+               IPW_DEBUG_INFO("Command completion failed out after %dms.\n",
+                              jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
+               priv->status &= ~STATUS_HCMD_ACTIVE;
+               return -EIO;
+       }
+       if (priv->status & STATUS_RF_KILL_MASK) {
+               IPW_DEBUG_INFO("Command aborted due to RF Kill Switch\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int ipw_send_host_complete(struct ipw_priv *priv)
+{
+       struct host_cmd cmd = {
+               .cmd = IPW_CMD_HOST_COMPLETE,
+               .len = 0
+       };
+
+       if (!priv) {
+               IPW_ERROR("Invalid args\n");
+               return -1;
+       }
+
+       if (ipw_send_cmd(priv, &cmd)) {
+               IPW_ERROR("failed to send HOST_COMPLETE command\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int ipw_send_system_config(struct ipw_priv *priv,
+                                 struct ipw_sys_config *config)
+{
+       struct host_cmd cmd = {
+               .cmd = IPW_CMD_SYSTEM_CONFIG,
+               .len = sizeof(*config)
+       };
+
+       if (!priv || !config) {
+               IPW_ERROR("Invalid args\n");
+               return -1;
+       }
+
+       memcpy(&cmd.param, config, sizeof(*config));
+       if (ipw_send_cmd(priv, &cmd)) {
+               IPW_ERROR("failed to send SYSTEM_CONFIG command\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len)
+{
+       struct host_cmd cmd = {
+               .cmd = IPW_CMD_SSID,
+               .len = min(len, IW_ESSID_MAX_SIZE)
+       };
+
+       if (!priv || !ssid) {
+               IPW_ERROR("Invalid args\n");
+               return -1;
+       }
+
+       memcpy(&cmd.param, ssid, cmd.len);
+       if (ipw_send_cmd(priv, &cmd)) {
+               IPW_ERROR("failed to send SSID command\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac)
+{
+       struct host_cmd cmd = {
+               .cmd = IPW_CMD_ADAPTER_ADDRESS,
+               .len = ETH_ALEN
+       };
+
+       if (!priv || !mac) {
+               IPW_ERROR("Invalid args\n");
+               return -1;
+       }
+
+       IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n",
+                      priv->net_dev->name, MAC_ARG(mac));
+
+       memcpy(&cmd.param, mac, ETH_ALEN);
+
+       if (ipw_send_cmd(priv, &cmd)) {
+               IPW_ERROR("failed to send ADAPTER_ADDRESS command\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static void ipw_adapter_restart(void *adapter)
+{
+       struct ipw_priv *priv = adapter;
+
+       if (priv->status & STATUS_RF_KILL_MASK)
+               return;
+
+       ipw_down(priv);
+       if (ipw_up(priv)) {
+               IPW_ERROR("Failed to up device\n");
+               return;
+       }
+}
+
+#define IPW_SCAN_CHECK_WATCHDOG (5 * HZ)
+
+static void ipw_scan_check(void *data)
+{
+       struct ipw_priv *priv = data;
+       if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) {
+               IPW_DEBUG_SCAN("Scan completion watchdog resetting "
+                              "adapter (%dms).\n",
+                              IPW_SCAN_CHECK_WATCHDOG / 100);
+               ipw_adapter_restart(priv);
+       }
+}
+
+static int ipw_send_scan_request_ext(struct ipw_priv *priv,
+                                    struct ipw_scan_request_ext *request)
+{
+       struct host_cmd cmd = {
+               .cmd = IPW_CMD_SCAN_REQUEST_EXT,
+               .len = sizeof(*request)
+       };
+
+       if (!priv || !request) {
+               IPW_ERROR("Invalid args\n");
+               return -1;
+       }
+
+       memcpy(&cmd.param, request, sizeof(*request));
+       if (ipw_send_cmd(priv, &cmd)) {
+               IPW_ERROR("failed to send SCAN_REQUEST_EXT command\n");
+               return -1;
+       }
+
+       queue_delayed_work(priv->workqueue, &priv->scan_check,
+                          IPW_SCAN_CHECK_WATCHDOG);
+       return 0;
+}
+
+static int ipw_send_scan_abort(struct ipw_priv *priv)
+{
+       struct host_cmd cmd = {
+               .cmd = IPW_CMD_SCAN_ABORT,
+               .len = 0
+       };
+
+       if (!priv) {
+               IPW_ERROR("Invalid args\n");
+               return -1;
+       }
+
+       if (ipw_send_cmd(priv, &cmd)) {
+               IPW_ERROR("failed to send SCAN_ABORT command\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens)
+{
+       struct host_cmd cmd = {
+               .cmd = IPW_CMD_SENSITIVITY_CALIB,
+               .len = sizeof(struct ipw_sensitivity_calib)
+       };
+       struct ipw_sensitivity_calib *calib = (struct ipw_sensitivity_calib *)
+           &cmd.param;
+       calib->beacon_rssi_raw = sens;
+       if (ipw_send_cmd(priv, &cmd)) {
+               IPW_ERROR("failed to send SENSITIVITY CALIB command\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int ipw_send_associate(struct ipw_priv *priv,
+                             struct ipw_associate *associate)
+{
+       struct host_cmd cmd = {
+               .cmd = IPW_CMD_ASSOCIATE,
+               .len = sizeof(*associate)
+       };
+
+       if (!priv || !associate) {
+               IPW_ERROR("Invalid args\n");
+               return -1;
+       }
+
+       memcpy(&cmd.param, associate, sizeof(*associate));
+       if (ipw_send_cmd(priv, &cmd)) {
+               IPW_ERROR("failed to send ASSOCIATE command\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int ipw_send_supported_rates(struct ipw_priv *priv,
+                                   struct ipw_supported_rates *rates)
+{
+       struct host_cmd cmd = {
+               .cmd = IPW_CMD_SUPPORTED_RATES,
+               .len = sizeof(*rates)
+       };
+
+       if (!priv || !rates) {
+               IPW_ERROR("Invalid args\n");
+               return -1;
+       }
+
+       memcpy(&cmd.param, rates, sizeof(*rates));
+       if (ipw_send_cmd(priv, &cmd)) {
+               IPW_ERROR("failed to send SUPPORTED_RATES command\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int ipw_set_random_seed(struct ipw_priv *priv)
+{
+       struct host_cmd cmd = {
+               .cmd = IPW_CMD_SEED_NUMBER,
+               .len = sizeof(u32)
+       };
+
+       if (!priv) {
+               IPW_ERROR("Invalid args\n");
+               return -1;
+       }
+
+       get_random_bytes(&cmd.param, sizeof(u32));
+
+       if (ipw_send_cmd(priv, &cmd)) {
+               IPW_ERROR("failed to send SEED_NUMBER command\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+#if 0
+static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off)
+{
+       struct host_cmd cmd = {
+               .cmd = IPW_CMD_CARD_DISABLE,
+               .len = sizeof(u32)
+       };
+
+       if (!priv) {
+               IPW_ERROR("Invalid args\n");
+               return -1;
+       }
+
+       *((u32 *) & cmd.param) = phy_off;
+
+       if (ipw_send_cmd(priv, &cmd)) {
+               IPW_ERROR("failed to send CARD_DISABLE command\n");
+               return -1;
+       }
+
+       return 0;
+}
+#endif
+
+static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power)
+{
+       struct host_cmd cmd = {
+               .cmd = IPW_CMD_TX_POWER,
+               .len = sizeof(*power)
+       };
+
+       if (!priv || !power) {
+               IPW_ERROR("Invalid args\n");
+               return -1;
+       }
+
+       memcpy(&cmd.param, power, sizeof(*power));
+       if (ipw_send_cmd(priv, &cmd)) {
+               IPW_ERROR("failed to send TX_POWER command\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts)
+{
+       struct ipw_rts_threshold rts_threshold = {
+               .rts_threshold = rts,
+       };
+       struct host_cmd cmd = {
+               .cmd = IPW_CMD_RTS_THRESHOLD,
+               .len = sizeof(rts_threshold)
+       };
+
+       if (!priv) {
+               IPW_ERROR("Invalid args\n");
+               return -1;
+       }
+
+       memcpy(&cmd.param, &rts_threshold, sizeof(rts_threshold));
+       if (ipw_send_cmd(priv, &cmd)) {
+               IPW_ERROR("failed to send RTS_THRESHOLD command\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag)
+{
+       struct ipw_frag_threshold frag_threshold = {
+               .frag_threshold = frag,
+       };
+       struct host_cmd cmd = {
+               .cmd = IPW_CMD_FRAG_THRESHOLD,
+               .len = sizeof(frag_threshold)
+       };
+
+       if (!priv) {
+               IPW_ERROR("Invalid args\n");
+               return -1;
+       }
+
+       memcpy(&cmd.param, &frag_threshold, sizeof(frag_threshold));
+       if (ipw_send_cmd(priv, &cmd)) {
+               IPW_ERROR("failed to send FRAG_THRESHOLD command\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode)
+{
+       struct host_cmd cmd = {
+               .cmd = IPW_CMD_POWER_MODE,
+               .len = sizeof(u32)
+       };
+       u32 *param = (u32 *) (&cmd.param);
+
+       if (!priv) {
+               IPW_ERROR("Invalid args\n");
+               return -1;
+       }
+
+       /* If on battery, set to 3, if AC set to CAM, else user
+        * level */
+       switch (mode) {
+       case IPW_POWER_BATTERY:
+               *param = IPW_POWER_INDEX_3;
+               break;
+       case IPW_POWER_AC:
+               *param = IPW_POWER_MODE_CAM;
+               break;
+       default:
+               *param = mode;
+               break;
+       }
+
+       if (ipw_send_cmd(priv, &cmd)) {
+               IPW_ERROR("failed to send POWER_MODE command\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * The IPW device contains a Microwire compatible EEPROM that stores
+ * various data like the MAC address.  Usually the firmware has exclusive
+ * access to the eeprom, but during device initialization (before the
+ * device driver has sent the HostComplete command to the firmware) the
+ * device driver has read access to the EEPROM by way of indirect addressing
+ * through a couple of memory mapped registers.
+ *
+ * The following is a simplified implementation for pulling data out of the
+ * the eeprom, along with some helper functions to find information in
+ * the per device private data's copy of the eeprom.
+ *
+ * NOTE: To better understand how these functions work (i.e what is a chip
+ *       select and why do have to keep driving the eeprom clock?), read
+ *       just about any data sheet for a Microwire compatible EEPROM.
+ */
+
+/* write a 32 bit value into the indirect accessor register */
+static inline void eeprom_write_reg(struct ipw_priv *p, u32 data)
+{
+       ipw_write_reg32(p, FW_MEM_REG_EEPROM_ACCESS, data);
+
+       /* the eeprom requires some time to complete the operation */
+       udelay(p->eeprom_delay);
+
+       return;
+}
+
+/* perform a chip select operation */
+static inline void eeprom_cs(struct ipw_priv *priv)
+{
+       eeprom_write_reg(priv, 0);
+       eeprom_write_reg(priv, EEPROM_BIT_CS);
+       eeprom_write_reg(priv, EEPROM_BIT_CS | EEPROM_BIT_SK);
+       eeprom_write_reg(priv, EEPROM_BIT_CS);
+}
+
+/* perform a chip select operation */
+static inline void eeprom_disable_cs(struct ipw_priv *priv)
+{
+       eeprom_write_reg(priv, EEPROM_BIT_CS);
+       eeprom_write_reg(priv, 0);
+       eeprom_write_reg(priv, EEPROM_BIT_SK);
+}
+
+/* push a single bit down to the eeprom */
+static inline void eeprom_write_bit(struct ipw_priv *p, u8 bit)
+{
+       int d = (bit ? EEPROM_BIT_DI : 0);
+       eeprom_write_reg(p, EEPROM_BIT_CS | d);
+       eeprom_write_reg(p, EEPROM_BIT_CS | d | EEPROM_BIT_SK);
+}
+
+/* push an opcode followed by an address down to the eeprom */
+static void eeprom_op(struct ipw_priv *priv, u8 op, u8 addr)
+{
+       int i;
+
+       eeprom_cs(priv);
+       eeprom_write_bit(priv, 1);
+       eeprom_write_bit(priv, op & 2);
+       eeprom_write_bit(priv, op & 1);
+       for (i = 7; i >= 0; i--) {
+               eeprom_write_bit(priv, addr & (1 << i));
+       }
+}
+
+/* pull 16 bits off the eeprom, one bit at a time */
+static u16 eeprom_read_u16(struct ipw_priv *priv, u8 addr)
+{
+       int i;
+       u16 r = 0;
+
+       /* Send READ Opcode */
+       eeprom_op(priv, EEPROM_CMD_READ, addr);
+
+       /* Send dummy bit */
+       eeprom_write_reg(priv, EEPROM_BIT_CS);
+
+       /* Read the byte off the eeprom one bit at a time */
+       for (i = 0; i < 16; i++) {
+               u32 data = 0;
+               eeprom_write_reg(priv, EEPROM_BIT_CS | EEPROM_BIT_SK);
+               eeprom_write_reg(priv, EEPROM_BIT_CS);
+               data = ipw_read_reg32(priv, FW_MEM_REG_EEPROM_ACCESS);
+               r = (r << 1) | ((data & EEPROM_BIT_DO) ? 1 : 0);
+       }
+
+       /* Send another dummy bit */
+       eeprom_write_reg(priv, 0);
+       eeprom_disable_cs(priv);
+
+       return r;
+}
+
+/* helper function for pulling the mac address out of the private */
+/* data's copy of the eeprom data                                 */
+static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac)
+{
+       u8 *ee = (u8 *) priv->eeprom;
+       memcpy(mac, &ee[EEPROM_MAC_ADDRESS], 6);
+}
+
+/*
+ * Either the device driver (i.e. the host) or the firmware can
+ * load eeprom data into the designated region in SRAM.  If neither
+ * happens then the FW will shutdown with a fatal error.
+ *
+ * In order to signal the FW to load the EEPROM, the EEPROM_LOAD_DISABLE
+ * bit needs region of shared SRAM needs to be non-zero.
+ */
+static void ipw_eeprom_init_sram(struct ipw_priv *priv)
+{
+       int i;
+       u16 *eeprom = (u16 *) priv->eeprom;
+
+       IPW_DEBUG_TRACE(">>\n");
+
+       /* read entire contents of eeprom into private buffer */
+       for (i = 0; i < 128; i++)
+               eeprom[i] = eeprom_read_u16(priv, (u8) i);
+
+       /*
+          If the data looks correct, then copy it to our private
+          copy.  Otherwise let the firmware know to perform the operation
+          on it's own
+        */
+       if ((priv->eeprom + EEPROM_VERSION) != 0) {
+               IPW_DEBUG_INFO("Writing EEPROM data into SRAM\n");
+
+               /* write the eeprom data to sram */
+               for (i = 0; i < CX2_EEPROM_IMAGE_SIZE; i++)
+                       ipw_write8(priv, IPW_EEPROM_DATA + i, priv->eeprom[i]);
+
+               /* Do not load eeprom data on fatal error or suspend */
+               ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0);
+       } else {
+               IPW_DEBUG_INFO("Enabling FW initializationg of SRAM\n");
+
+               /* Load eeprom data on fatal error or suspend */
+               ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 1);
+       }
+
+       IPW_DEBUG_TRACE("<<\n");
+}
+
+static inline void ipw_zero_memory(struct ipw_priv *priv, u32 start, u32 count)
+{
+       count >>= 2;
+       if (!count)
+               return;
+       _ipw_write32(priv, CX2_AUTOINC_ADDR, start);
+       while (count--)
+               _ipw_write32(priv, CX2_AUTOINC_DATA, 0);
+}
+
+static inline void ipw_fw_dma_reset_command_blocks(struct ipw_priv *priv)
+{
+       ipw_zero_memory(priv, CX2_SHARED_SRAM_DMA_CONTROL,
+                       CB_NUMBER_OF_ELEMENTS_SMALL *
+                       sizeof(struct command_block));
+}
+
+static int ipw_fw_dma_enable(struct ipw_priv *priv)
+{                              /* start dma engine but no transfers yet */
+
+       IPW_DEBUG_FW(">> : \n");
+
+       /* Start the dma */
+       ipw_fw_dma_reset_command_blocks(priv);
+
+       /* Write CB base address */
+       ipw_write_reg32(priv, CX2_DMA_I_CB_BASE, CX2_SHARED_SRAM_DMA_CONTROL);
+
+       IPW_DEBUG_FW("<< : \n");
+       return 0;
+}
+
+static void ipw_fw_dma_abort(struct ipw_priv *priv)
+{
+       u32 control = 0;
+
+       IPW_DEBUG_FW(">> :\n");
+
+       //set the Stop and Abort bit
+       control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT;
+       ipw_write_reg32(priv, CX2_DMA_I_DMA_CONTROL, control);
+       priv->sram_desc.last_cb_index = 0;
+
+       IPW_DEBUG_FW("<< \n");
+}
+
+static int ipw_fw_dma_write_command_block(struct ipw_priv *priv, int index,
+                                         struct command_block *cb)
+{
+       u32 address =
+           CX2_SHARED_SRAM_DMA_CONTROL +
+           (sizeof(struct command_block) * index);
+       IPW_DEBUG_FW(">> :\n");
+
+       ipw_write_indirect(priv, address, (u8 *) cb,
+                          (int)sizeof(struct command_block));
+
+       IPW_DEBUG_FW("<< :\n");
+       return 0;
+
+}
+
+static int ipw_fw_dma_kick(struct ipw_priv *priv)
+{
+       u32 control = 0;
+       u32 index = 0;
+
+       IPW_DEBUG_FW(">> :\n");
+
+       for (index = 0; index < priv->sram_desc.last_cb_index; index++)
+               ipw_fw_dma_write_command_block(priv, index,
+                                              &priv->sram_desc.cb_list[index]);
+
+       /* Enable the DMA in the CSR register */
+       ipw_clear_bit(priv, CX2_RESET_REG,
+                     CX2_RESET_REG_MASTER_DISABLED |
+                     CX2_RESET_REG_STOP_MASTER);
+
+       /* Set the Start bit. */
+       control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_START;
+       ipw_write_reg32(priv, CX2_DMA_I_DMA_CONTROL, control);
+
+       IPW_DEBUG_FW("<< :\n");
+       return 0;
+}
+
+static void ipw_fw_dma_dump_command_block(struct ipw_priv *priv)
+{
+       u32 address;
+       u32 register_value = 0;
+       u32 cb_fields_address = 0;
+
+       IPW_DEBUG_FW(">> :\n");
+       address = ipw_read_reg32(priv, CX2_DMA_I_CURRENT_CB);
+       IPW_DEBUG_FW_INFO("Current CB is 0x%x \n", address);
+
+       /* Read the DMA Controlor register */
+       register_value = ipw_read_reg32(priv, CX2_DMA_I_DMA_CONTROL);
+       IPW_DEBUG_FW_INFO("CX2_DMA_I_DMA_CONTROL is 0x%x \n", register_value);
+
+       /* Print the CB values */
+       cb_fields_address = address;
+       register_value = ipw_read_reg32(priv, cb_fields_address);
+       IPW_DEBUG_FW_INFO("Current CB ControlField is 0x%x \n", register_value);
+
+       cb_fields_address += sizeof(u32);
+       register_value = ipw_read_reg32(priv, cb_fields_address);
+       IPW_DEBUG_FW_INFO("Current CB Source Field is 0x%x \n", register_value);
+
+       cb_fields_address += sizeof(u32);
+       register_value = ipw_read_reg32(priv, cb_fields_address);
+       IPW_DEBUG_FW_INFO("Current CB Destination Field is 0x%x \n",
+                         register_value);
+
+       cb_fields_address += sizeof(u32);
+       register_value = ipw_read_reg32(priv, cb_fields_address);
+       IPW_DEBUG_FW_INFO("Current CB Status Field is 0x%x \n", register_value);
+
+       IPW_DEBUG_FW(">> :\n");
+}
+
+static int ipw_fw_dma_command_block_index(struct ipw_priv *priv)
+{
+       u32 current_cb_address = 0;
+       u32 current_cb_index = 0;
+
+       IPW_DEBUG_FW("<< :\n");
+       current_cb_address = ipw_read_reg32(priv, CX2_DMA_I_CURRENT_CB);
+
+       current_cb_index = (current_cb_address - CX2_SHARED_SRAM_DMA_CONTROL) /
+           sizeof(struct command_block);
+
+       IPW_DEBUG_FW_INFO("Current CB index 0x%x address = 0x%X \n",
+                         current_cb_index, current_cb_address);
+
+       IPW_DEBUG_FW(">> :\n");
+       return current_cb_index;
+
+}
+
+static int ipw_fw_dma_add_command_block(struct ipw_priv *priv,
+                                       u32 src_address,
+                                       u32 dest_address,
+                                       u32 length,
+                                       int interrupt_enabled, int is_last)
+{
+
+       u32 control = CB_VALID | CB_SRC_LE | CB_DEST_LE | CB_SRC_AUTOINC |
+           CB_SRC_IO_GATED | CB_DEST_AUTOINC | CB_SRC_SIZE_LONG |
+           CB_DEST_SIZE_LONG;
+       struct command_block *cb;
+       u32 last_cb_element = 0;
+
+       IPW_DEBUG_FW_INFO("src_address=0x%x dest_address=0x%x length=0x%x\n",
+                         src_address, dest_address, length);
+
+       if (priv->sram_desc.last_cb_index >= CB_NUMBER_OF_ELEMENTS_SMALL)
+               return -1;
+
+       last_cb_element = priv->sram_desc.last_cb_index;
+       cb = &priv->sram_desc.cb_list[last_cb_element];
+       priv->sram_desc.last_cb_index++;
+
+       /* Calculate the new CB control word */
+       if (interrupt_enabled)
+               control |= CB_INT_ENABLED;
+
+       if (is_last)
+               control |= CB_LAST_VALID;
+
+       control |= length;
+
+       /* Calculate the CB Element's checksum value */
+       cb->status = control ^ src_address ^ dest_address;
+
+       /* Copy the Source and Destination addresses */
+       cb->dest_addr = dest_address;
+       cb->source_addr = src_address;
+
+       /* Copy the Control Word last */
+       cb->control = control;
+
+       return 0;
+}
+
+static int ipw_fw_dma_add_buffer(struct ipw_priv *priv,
+                                u32 src_phys, u32 dest_address, u32 length)
+{
+       u32 bytes_left = length;
+       u32 src_offset = 0;
+       u32 dest_offset = 0;
+       int status = 0;
+       IPW_DEBUG_FW(">> \n");
+       IPW_DEBUG_FW_INFO("src_phys=0x%x dest_address=0x%x length=0x%x\n",
+                         src_phys, dest_address, length);
+       while (bytes_left > CB_MAX_LENGTH) {
+               status = ipw_fw_dma_add_command_block(priv,
+                                                     src_phys + src_offset,
+                                                     dest_address +
+                                                     dest_offset,
+                                                     CB_MAX_LENGTH, 0, 0);
+               if (status) {
+                       IPW_DEBUG_FW_INFO(": Failed\n");
+                       return -1;
+               } else
+                       IPW_DEBUG_FW_INFO(": Added new cb\n");
+
+               src_offset += CB_MAX_LENGTH;
+               dest_offset += CB_MAX_LENGTH;
+               bytes_left -= CB_MAX_LENGTH;
+       }
+
+       /* add the buffer tail */
+       if (bytes_left > 0) {
+               status =
+                   ipw_fw_dma_add_command_block(priv, src_phys + src_offset,
+                                                dest_address + dest_offset,
+                                                bytes_left, 0, 0);
+               if (status) {
+                       IPW_DEBUG_FW_INFO(": Failed on the buffer tail\n");
+                       return -1;
+               } else
+                       IPW_DEBUG_FW_INFO
+                           (": Adding new cb - the buffer tail\n");
+       }
+
+       IPW_DEBUG_FW("<< \n");
+       return 0;
+}
+
+static int ipw_fw_dma_wait(struct ipw_priv *priv)
+{
+       u32 current_index = 0;
+       u32 watchdog = 0;
+
+       IPW_DEBUG_FW(">> : \n");
+
+       current_index = ipw_fw_dma_command_block_index(priv);
+       IPW_DEBUG_FW_INFO("sram_desc.last_cb_index:0x%8X\n",
+                         (int)priv->sram_desc.last_cb_index);
+
+       while (current_index < priv->sram_desc.last_cb_index) {
+               udelay(50);
+               current_index = ipw_fw_dma_command_block_index(priv);
+
+               watchdog++;
+
+               if (watchdog > 400) {
+                       IPW_DEBUG_FW_INFO("Timeout\n");
+                       ipw_fw_dma_dump_command_block(priv);
+                       ipw_fw_dma_abort(priv);
+                       return -1;
+               }
+       }
+
+       ipw_fw_dma_abort(priv);
+
+       /*Disable the DMA in the CSR register */
+       ipw_set_bit(priv, CX2_RESET_REG,
+                   CX2_RESET_REG_MASTER_DISABLED | CX2_RESET_REG_STOP_MASTER);
+
+       IPW_DEBUG_FW("<< dmaWaitSync \n");
+       return 0;
+}
+
+static void ipw_remove_current_network(struct ipw_priv *priv)
+{
+       struct list_head *element, *safe;
+       struct ieee80211_network *network = NULL;
+       list_for_each_safe(element, safe, &priv->ieee->network_list) {
+               network = list_entry(element, struct ieee80211_network, list);
+               if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
+                       list_del(element);
+                       list_add_tail(&network->list,
+                                     &priv->ieee->network_free_list);
+               }
+       }
+}
+
+/**
+ * Check that card is still alive.
+ * Reads debug register from domain0.
+ * If card is present, pre-defined value should
+ * be found there.
+ *
+ * @param priv
+ * @return 1 if card is present, 0 otherwise
+ */
+static inline int ipw_alive(struct ipw_priv *priv)
+{
+       return ipw_read32(priv, 0x90) == 0xd55555d5;
+}
+
+static inline int ipw_poll_bit(struct ipw_priv *priv, u32 addr, u32 mask,
+                              int timeout)
+{
+       int i = 0;
+
+       do {
+               if ((ipw_read32(priv, addr) & mask) == mask)
+                       return i;
+               mdelay(10);
+               i += 10;
+       } while (i < timeout);
+
+       return -ETIME;
+}
+
+/* These functions load the firmware and micro code for the operation of
+ * the ipw hardware.  It assumes the buffer has all the bits for the
+ * image and the caller is handling the memory allocation and clean up.
+ */
+
+static int ipw_stop_master(struct ipw_priv *priv)
+{
+       int rc;
+
+       IPW_DEBUG_TRACE(">> \n");
+       /* stop master. typical delay - 0 */
+       ipw_set_bit(priv, CX2_RESET_REG, CX2_RESET_REG_STOP_MASTER);
+
+       rc = ipw_poll_bit(priv, CX2_RESET_REG,
+                         CX2_RESET_REG_MASTER_DISABLED, 100);
+       if (rc < 0) {
+               IPW_ERROR("stop master failed in 10ms\n");
+               return -1;
+       }
+
+       IPW_DEBUG_INFO("stop master %dms\n", rc);
+
+       return rc;
+}
+
+static void ipw_arc_release(struct ipw_priv *priv)
+{
+       IPW_DEBUG_TRACE(">> \n");
+       mdelay(5);
+
+       ipw_clear_bit(priv, CX2_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
+
+       /* no one knows timing, for safety add some delay */
+       mdelay(5);
+}
+
+struct fw_header {
+       u32 version;
+       u32 mode;
+};
+
+struct fw_chunk {
+       u32 address;
+       u32 length;
+};
+
+#define IPW_FW_MAJOR_VERSION 2
+#define IPW_FW_MINOR_VERSION 2
+
+#define IPW_FW_MINOR(x) ((x & 0xff) >> 8)
+#define IPW_FW_MAJOR(x) (x & 0xff)
+
+#define IPW_FW_VERSION ((IPW_FW_MINOR_VERSION << 8) | \
+                         IPW_FW_MAJOR_VERSION)
+
+#define IPW_FW_PREFIX "ipw-" __stringify(IPW_FW_MAJOR_VERSION) \
+"." __stringify(IPW_FW_MINOR_VERSION) "-"
+
+#if IPW_FW_MAJOR_VERSION >= 2 && IPW_FW_MINOR_VERSION > 0
+#define IPW_FW_NAME(x) IPW_FW_PREFIX "" x ".fw"
+#else
+#define IPW_FW_NAME(x) "ipw2200_" x ".fw"
+#endif
+
+static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
+{
+       int rc = 0, i, addr;
+       u8 cr = 0;
+       u16 *image;
+
+       image = (u16 *) data;
+
+       IPW_DEBUG_TRACE(">> \n");
+
+       rc = ipw_stop_master(priv);
+
+       if (rc < 0)
+               return rc;
+
+//      spin_lock_irqsave(&priv->lock, flags);
+
+       for (addr = CX2_SHARED_LOWER_BOUND;
+            addr < CX2_REGISTER_DOMAIN1_END; addr += 4) {
+               ipw_write32(priv, addr, 0);
+       }
+
+       /* no ucode (yet) */
+       memset(&priv->dino_alive, 0, sizeof(priv->dino_alive));
+       /* destroy DMA queues */
+       /* reset sequence */
+
+       ipw_write_reg32(priv, CX2_MEM_HALT_AND_RESET, CX2_BIT_HALT_RESET_ON);
+       ipw_arc_release(priv);
+       ipw_write_reg32(priv, CX2_MEM_HALT_AND_RESET, CX2_BIT_HALT_RESET_OFF);
+       mdelay(1);
+
+       /* reset PHY */
+       ipw_write_reg32(priv, CX2_INTERNAL_CMD_EVENT, CX2_BASEBAND_POWER_DOWN);
+       mdelay(1);
+
+       ipw_write_reg32(priv, CX2_INTERNAL_CMD_EVENT, 0);
+       mdelay(1);
+
+       /* enable ucode store */
+       ipw_write_reg8(priv, DINO_CONTROL_REG, 0x0);
+       ipw_write_reg8(priv, DINO_CONTROL_REG, DINO_ENABLE_CS);
+       mdelay(1);
+
+       /* write ucode */
+       /**
+        * @bug
+        * Do NOT set indirect address register once and then
+        * store data to indirect data register in the loop.
+        * It seems very reasonable, but in this case DINO do not
+        * accept ucode. It is essential to set address each time.
+        */
+       /* load new ipw uCode */
+       for (i = 0; i < len / 2; i++)
+               ipw_write_reg16(priv, CX2_BASEBAND_CONTROL_STORE, image[i]);
+
+       /* enable DINO */
+       ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, 0);
+       ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, DINO_ENABLE_SYSTEM);
+
+       /* this is where the igx / win driver deveates from the VAP driver. */
+
+       /* wait for alive response */
+       for (i = 0; i < 100; i++) {
+               /* poll for incoming data */
+               cr = ipw_read_reg8(priv, CX2_BASEBAND_CONTROL_STATUS);
+               if (cr & DINO_RXFIFO_DATA)
+                       break;
+               mdelay(1);
+       }
+
+       if (cr & DINO_RXFIFO_DATA) {
+               /* alive_command_responce size is NOT multiple of 4 */
+               u32 response_buffer[(sizeof(priv->dino_alive) + 3) / 4];
+
+               for (i = 0; i < ARRAY_SIZE(response_buffer); i++)
+                       response_buffer[i] =
+                           ipw_read_reg32(priv, CX2_BASEBAND_RX_FIFO_READ);
+               memcpy(&priv->dino_alive, response_buffer,
+                      sizeof(priv->dino_alive));
+               if (priv->dino_alive.alive_command == 1
+                   && priv->dino_alive.ucode_valid == 1) {
+                       rc = 0;
+                       IPW_DEBUG_INFO
+                           ("Microcode OK, rev. %d (0x%x) dev. %d (0x%x) "
+                            "of %02d/%02d/%02d %02d:%02d\n",
+                            priv->dino_alive.software_revision,
+                            priv->dino_alive.software_revision,
+                            priv->dino_alive.device_identifier,
+                            priv->dino_alive.device_identifier,
+                            priv->dino_alive.time_stamp[0],
+                            priv->dino_alive.time_stamp[1],
+                            priv->dino_alive.time_stamp[2],
+                            priv->dino_alive.time_stamp[3],
+                            priv->dino_alive.time_stamp[4]);
+               } else {
+                       IPW_DEBUG_INFO("Microcode is not alive\n");
+                       rc = -EINVAL;
+               }
+       } else {
+               IPW_DEBUG_INFO("No alive response from DINO\n");
+               rc = -ETIME;
+       }
+
+       /* disable DINO, otherwise for some reason
+          firmware have problem getting alive resp. */
+       ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, 0);
+
+//      spin_unlock_irqrestore(&priv->lock, flags);
+
+       return rc;
+}
+
+static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len)
+{
+       int rc = -1;
+       int offset = 0;
+       struct fw_chunk *chunk;
+       dma_addr_t shared_phys;
+       u8 *shared_virt;
+
+       IPW_DEBUG_TRACE("<< : \n");
+       shared_virt = pci_alloc_consistent(priv->pci_dev, len, &shared_phys);
+
+       if (!shared_virt)
+               return -ENOMEM;
+
+       memmove(shared_virt, data, len);
+
+       /* Start the Dma */
+       rc = ipw_fw_dma_enable(priv);
+
+       if (priv->sram_desc.last_cb_index > 0) {
+               /* the DMA is already ready this would be a bug. */
+               BUG();
+               goto out;
+       }
+
+       do {
+               chunk = (struct fw_chunk *)(data + offset);
+               offset += sizeof(struct fw_chunk);
+               /* build DMA packet and queue up for sending */
+               /* dma to chunk->address, the chunk->length bytes from data +
+                * offeset*/
+               /* Dma loading */
+               rc = ipw_fw_dma_add_buffer(priv, shared_phys + offset,
+                                          chunk->address, chunk->length);
+               if (rc) {
+                       IPW_DEBUG_INFO("dmaAddBuffer Failed\n");
+                       goto out;
+               }
+
+               offset += chunk->length;
+       } while (offset < len);
+
+       /* Run the DMA and wait for the answer */
+       rc = ipw_fw_dma_kick(priv);
+       if (rc) {
+               IPW_ERROR("dmaKick Failed\n");
+               goto out;
+       }
+
+       rc = ipw_fw_dma_wait(priv);
+       if (rc) {
+               IPW_ERROR("dmaWaitSync Failed\n");
+               goto out;
+       }
+      out:
+       pci_free_consistent(priv->pci_dev, len, shared_virt, shared_phys);
+       return rc;
+}
+
+/* stop nic */
+static int ipw_stop_nic(struct ipw_priv *priv)
+{
+       int rc = 0;
+
+       /* stop */
+       ipw_write32(priv, CX2_RESET_REG, CX2_RESET_REG_STOP_MASTER);
+
+       rc = ipw_poll_bit(priv, CX2_RESET_REG,
+                         CX2_RESET_REG_MASTER_DISABLED, 500);
+       if (rc < 0) {
+               IPW_ERROR("wait for reg master disabled failed\n");
+               return rc;
+       }
+
+       ipw_set_bit(priv, CX2_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
+
+       return rc;
+}
+
+static void ipw_start_nic(struct ipw_priv *priv)
+{
+       IPW_DEBUG_TRACE(">>\n");
+
+       /* prvHwStartNic  release ARC */
+       ipw_clear_bit(priv, CX2_RESET_REG,
+                     CX2_RESET_REG_MASTER_DISABLED |
+                     CX2_RESET_REG_STOP_MASTER |
+                     CBD_RESET_REG_PRINCETON_RESET);
+
+       /* enable power management */
+       ipw_set_bit(priv, CX2_GP_CNTRL_RW,
+                   CX2_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);
+
+       IPW_DEBUG_TRACE("<<\n");
+}
+
+static int ipw_init_nic(struct ipw_priv *priv)
+{
+       int rc;
+
+       IPW_DEBUG_TRACE(">>\n");
+       /* reset */
+       /*prvHwInitNic */
+       /* set "initialization complete" bit to move adapter to D0 state */
+       ipw_set_bit(priv, CX2_GP_CNTRL_RW, CX2_GP_CNTRL_BIT_INIT_DONE);
+
+       /* low-level PLL activation */
+       ipw_write32(priv, CX2_READ_INT_REGISTER,
+                   CX2_BIT_INT_HOST_SRAM_READ_INT_REGISTER);
+
+       /* wait for clock stabilization */
+       rc = ipw_poll_bit(priv, CX2_GP_CNTRL_RW,
+                         CX2_GP_CNTRL_BIT_CLOCK_READY, 250);
+       if (rc < 0)
+               IPW_DEBUG_INFO("FAILED wait for clock stablization\n");
+
+       /* assert SW reset */
+       ipw_set_bit(priv, CX2_RESET_REG, CX2_RESET_REG_SW_RESET);
+
+       udelay(10);
+
+       /* set "initialization complete" bit to move adapter to D0 state */
+       ipw_set_bit(priv, CX2_GP_CNTRL_RW, CX2_GP_CNTRL_BIT_INIT_DONE);
+
+       IPW_DEBUG_TRACE(">>\n");
+       return 0;
+}
+
+/* Call this function from process context, it will sleep in request_firmware.
+ * Probe is an ok place to call this from.
+ */
+static int ipw_reset_nic(struct ipw_priv *priv)
+{
+       int rc = 0;
+
+       IPW_DEBUG_TRACE(">>\n");
+
+       rc = ipw_init_nic(priv);
+
+       /* Clear the 'host command active' bit... */
+       priv->status &= ~STATUS_HCMD_ACTIVE;
+       wake_up_interruptible(&priv->wait_command_queue);
+
+       IPW_DEBUG_TRACE("<<\n");
+       return rc;
+}
+
+static int ipw_get_fw(struct ipw_priv *priv,
+                     const struct firmware **fw, const char *name)
+{
+       struct fw_header *header;
+       int rc;
+
+       /* ask firmware_class module to get the boot firmware off disk */
+       rc = request_firmware(fw, name, &priv->pci_dev->dev);
+       if (rc < 0) {
+               IPW_ERROR("%s load failed: Reason %d\n", name, rc);
+               return rc;
+       }
+
+       header = (struct fw_header *)(*fw)->data;
+       if (IPW_FW_MAJOR(header->version) != IPW_FW_MAJOR_VERSION) {
+               IPW_ERROR("'%s' firmware version not compatible (%d != %d)\n",
+                         name,
+                         IPW_FW_MAJOR(header->version), IPW_FW_MAJOR_VERSION);
+               return -EINVAL;
+       }
+
+       IPW_DEBUG_INFO("Loading firmware '%s' file v%d.%d (%zd bytes)\n",
+                      name,
+                      IPW_FW_MAJOR(header->version),
+                      IPW_FW_MINOR(header->version),
+                      (*fw)->size - sizeof(struct fw_header));
+       return 0;
+}
+
+#define CX2_RX_BUF_SIZE (3000)
+
+static inline void ipw_rx_queue_reset(struct ipw_priv *priv,
+                                     struct ipw_rx_queue *rxq)
+{
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&rxq->lock, flags);
+
+       INIT_LIST_HEAD(&rxq->rx_free);
+       INIT_LIST_HEAD(&rxq->rx_used);
+
+       /* Fill the rx_used queue with _all_ of the Rx buffers */
+       for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+               /* In the reset function, these buffers may have been allocated
+                * to an SKB, so we need to unmap and free potential storage */
+               if (rxq->pool[i].skb != NULL) {
+                       pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr,
+                                        CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                       dev_kfree_skb(rxq->pool[i].skb);
+               }
+               list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+       }
+
+       /* Set us so that we have processed and used all buffers, but have
+        * not restocked the Rx queue with fresh buffers */
+       rxq->read = rxq->write = 0;
+       rxq->processed = RX_QUEUE_SIZE - 1;
+       rxq->free_count = 0;
+       spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+#ifdef CONFIG_PM
+static int fw_loaded = 0;
+static const struct firmware *bootfw = NULL;
+static const struct firmware *firmware = NULL;
+static const struct firmware *ucode = NULL;
+#endif
+
+static int ipw_load(struct ipw_priv *priv)
+{
+#ifndef CONFIG_PM
+       const struct firmware *bootfw = NULL;
+       const struct firmware *firmware = NULL;
+       const struct firmware *ucode = NULL;
+#endif
+       int rc = 0, retries = 3;
+
+#ifdef CONFIG_PM
+       if (!fw_loaded) {
+#endif
+               rc = ipw_get_fw(priv, &bootfw, IPW_FW_NAME("boot"));
+               if (rc)
+                       goto error;
+
+               switch (priv->ieee->iw_mode) {
+               case IW_MODE_ADHOC:
+                       rc = ipw_get_fw(priv, &ucode,
+                                       IPW_FW_NAME("ibss_ucode"));
+                       if (rc)
+                               goto error;
+
+                       rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("ibss"));
+                       break;
+
+#ifdef CONFIG_IPW_PROMISC
+               case IW_MODE_MONITOR:
+                       rc = ipw_get_fw(priv, &ucode,
+                                       IPW_FW_NAME("ibss_ucode"));
+                       if (rc)
+                               goto error;
+
+                       rc = ipw_get_fw(priv, &firmware,
+                                       IPW_FW_NAME("sniffer"));
+                       break;
+#endif
+               case IW_MODE_INFRA:
+                       rc = ipw_get_fw(priv, &ucode, IPW_FW_NAME("bss_ucode"));
+                       if (rc)
+                               goto error;
+
+                       rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("bss"));
+                       break;
+
+               default:
+                       rc = -EINVAL;
+               }
+
+               if (rc)
+                       goto error;
+
+#ifdef CONFIG_PM
+               fw_loaded = 1;
+       }
+#endif
+
+       if (!priv->rxq)
+               priv->rxq = ipw_rx_queue_alloc(priv);
+       else
+               ipw_rx_queue_reset(priv, priv->rxq);
+       if (!priv->rxq) {
+               IPW_ERROR("Unable to initialize Rx queue\n");
+               goto error;
+       }
+
+      retry:
+       /* Ensure interrupts are disabled */
+       ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL);
+       priv->status &= ~STATUS_INT_ENABLED;
+
+       /* ack pending interrupts */
+       ipw_write32(priv, CX2_INTA_RW, CX2_INTA_MASK_ALL);
+
+       ipw_stop_nic(priv);
+
+       rc = ipw_reset_nic(priv);
+       if (rc) {
+               IPW_ERROR("Unable to reset NIC\n");
+               goto error;
+       }
+
+       ipw_zero_memory(priv, CX2_NIC_SRAM_LOWER_BOUND,
+                       CX2_NIC_SRAM_UPPER_BOUND - CX2_NIC_SRAM_LOWER_BOUND);
+
+       /* DMA the initial boot firmware into the device */
+       rc = ipw_load_firmware(priv, bootfw->data + sizeof(struct fw_header),
+                              bootfw->size - sizeof(struct fw_header));
+       if (rc < 0) {
+               IPW_ERROR("Unable to load boot firmware\n");
+               goto error;
+       }
+
+       /* kick start the device */
+       ipw_start_nic(priv);
+
+       /* wait for the device to finish it's initial startup sequence */
+       rc = ipw_poll_bit(priv, CX2_INTA_RW,
+                         CX2_INTA_BIT_FW_INITIALIZATION_DONE, 500);
+       if (rc < 0) {
+               IPW_ERROR("device failed to boot initial fw image\n");
+               goto error;
+       }
+       IPW_DEBUG_INFO("initial device response after %dms\n", rc);
+
+       /* ack fw init done interrupt */
+       ipw_write32(priv, CX2_INTA_RW, CX2_INTA_BIT_FW_INITIALIZATION_DONE);
+
+       /* DMA the ucode into the device */
+       rc = ipw_load_ucode(priv, ucode->data + sizeof(struct fw_header),
+                           ucode->size - sizeof(struct fw_header));
+       if (rc < 0) {
+               IPW_ERROR("Unable to load ucode\n");
+               goto error;
+       }
+
+       /* stop nic */
+       ipw_stop_nic(priv);
+
+       /* DMA bss firmware into the device */
+       rc = ipw_load_firmware(priv, firmware->data +
+                              sizeof(struct fw_header),
+                              firmware->size - sizeof(struct fw_header));
+       if (rc < 0) {
+               IPW_ERROR("Unable to load firmware\n");
+               goto error;
+       }
+
+       ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0);
+
+       rc = ipw_queue_reset(priv);
+       if (rc) {
+               IPW_ERROR("Unable to initialize queues\n");
+               goto error;
+       }
+
+       /* Ensure interrupts are disabled */
+       ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL);
+
+       /* kick start the device */
+       ipw_start_nic(priv);
+
+       if (ipw_read32(priv, CX2_INTA_RW) & CX2_INTA_BIT_PARITY_ERROR) {
+               if (retries > 0) {
+                       IPW_WARNING("Parity error.  Retrying init.\n");
+                       retries--;
+                       goto retry;
+               }
+
+               IPW_ERROR("TODO: Handle parity error -- schedule restart?\n");
+               rc = -EIO;
+               goto error;
+       }
+
+       /* wait for the device */
+       rc = ipw_poll_bit(priv, CX2_INTA_RW,
+                         CX2_INTA_BIT_FW_INITIALIZATION_DONE, 500);
+       if (rc < 0) {
+               IPW_ERROR("device failed to start after 500ms\n");
+               goto error;
+       }
+       IPW_DEBUG_INFO("device response after %dms\n", rc);
+
+       /* ack fw init done interrupt */
+       ipw_write32(priv, CX2_INTA_RW, CX2_INTA_BIT_FW_INITIALIZATION_DONE);
+
+       /* read eeprom data and initialize the eeprom region of sram */
+       priv->eeprom_delay = 1;
+       ipw_eeprom_init_sram(priv);
+
+       /* enable interrupts */
+       ipw_enable_interrupts(priv);
+
+       /* Ensure our queue has valid packets */
+       ipw_rx_queue_replenish(priv);
+
+       ipw_write32(priv, CX2_RX_READ_INDEX, priv->rxq->read);
+
+       /* ack pending interrupts */
+       ipw_write32(priv, CX2_INTA_RW, CX2_INTA_MASK_ALL);
+
+#ifndef CONFIG_PM
+       release_firmware(bootfw);
+       release_firmware(ucode);
+       release_firmware(firmware);
+#endif
+       return 0;
+
+      error:
+       if (priv->rxq) {
+               ipw_rx_queue_free(priv, priv->rxq);
+               priv->rxq = NULL;
+       }
+       ipw_tx_queue_free(priv);
+       if (bootfw)
+               release_firmware(bootfw);
+       if (ucode)
+               release_firmware(ucode);
+       if (firmware)
+               release_firmware(firmware);
+#ifdef CONFIG_PM
+       fw_loaded = 0;
+       bootfw = ucode = firmware = NULL;
+#endif
+
+       return rc;
+}
+
+/**
+ * DMA services
+ *
+ * Theory of operation
+ *
+ * A queue is a circular buffers with 'Read' and 'Write' pointers.
+ * 2 empty entries always kept in the buffer to protect from overflow.
+ *
+ * For Tx queue, there are low mark and high mark limits. If, after queuing
+ * the packet for Tx, free space become < low mark, Tx queue stopped. When
+ * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
+ * Tx queue resumed.
+ *
+ * The IPW operates with six queues, one receive queue in the device's
+ * sram, one transmit queue for sending commands to the device firmware,
+ * and four transmit queues for data.
+ *
+ * The four transmit queues allow for performing quality of service (qos)
+ * transmissions as per the 802.11 protocol.  Currently Linux does not
+ * provide a mechanism to the user for utilizing prioritized queues, so
+ * we only utilize the first data transmit queue (queue1).
+ */
+
+/**
+ * Driver allocates buffers of this size for Rx
+ */
+
+static inline int ipw_queue_space(const struct clx2_queue *q)
+{
+       int s = q->last_used - q->first_empty;
+       if (s <= 0)
+               s += q->n_bd;
+       s -= 2;                 /* keep some reserve to not confuse empty and full situations */
+       if (s < 0)
+               s = 0;
+       return s;
+}
+
+static inline int ipw_queue_inc_wrap(int index, int n_bd)
+{
+       return (++index == n_bd) ? 0 : index;
+}
+
+/**
+ * Initialize common DMA queue structure
+ *
+ * @param q                queue to init
+ * @param count            Number of BD's to allocate. Should be power of 2
+ * @param read_register    Address for 'read' register
+ *                         (not offset within BAR, full address)
+ * @param write_register   Address for 'write' register
+ *                         (not offset within BAR, full address)
+ * @param base_register    Address for 'base' register
+ *                         (not offset within BAR, full address)
+ * @param size             Address for 'size' register
+ *                         (not offset within BAR, full address)
+ */
+static void ipw_queue_init(struct ipw_priv *priv, struct clx2_queue *q,
+                          int count, u32 read, u32 write, u32 base, u32 size)
+{
+       q->n_bd = count;
+
+       q->low_mark = q->n_bd / 4;
+       if (q->low_mark < 4)
+               q->low_mark = 4;
+
+       q->high_mark = q->n_bd / 8;
+       if (q->high_mark < 2)
+               q->high_mark = 2;
+
+       q->first_empty = q->last_used = 0;
+       q->reg_r = read;
+       q->reg_w = write;
+
+       ipw_write32(priv, base, q->dma_addr);
+       ipw_write32(priv, size, count);
+       ipw_write32(priv, read, 0);
+       ipw_write32(priv, write, 0);
+
+       _ipw_read32(priv, 0x90);
+}
+
+static int ipw_queue_tx_init(struct ipw_priv *priv,
+                            struct clx2_tx_queue *q,
+                            int count, u32 read, u32 write, u32 base, u32 size)
+{
+       struct pci_dev *dev = priv->pci_dev;
+
+       q->txb = kmalloc(sizeof(q->txb[0]) * count, GFP_KERNEL);
+       if (!q->txb) {
+               IPW_ERROR("vmalloc for auxilary BD structures failed\n");
+               return -ENOMEM;
+       }
+
+       q->bd =
+           pci_alloc_consistent(dev, sizeof(q->bd[0]) * count, &q->q.dma_addr);
+       if (!q->bd) {
+               IPW_ERROR("pci_alloc_consistent(%zd) failed\n",
+                         sizeof(q->bd[0]) * count);
+               kfree(q->txb);
+               q->txb = NULL;
+               return -ENOMEM;
+       }
+
+       ipw_queue_init(priv, &q->q, count, read, write, base, size);
+       return 0;
+}
+
+/**
+ * Free one TFD, those at index [txq->q.last_used].
+ * Do NOT advance any indexes
+ *
+ * @param dev
+ * @param txq
+ */
+static void ipw_queue_tx_free_tfd(struct ipw_priv *priv,
+                                 struct clx2_tx_queue *txq)
+{
+       struct tfd_frame *bd = &txq->bd[txq->q.last_used];
+       struct pci_dev *dev = priv->pci_dev;
+       int i;
+
+       /* classify bd */
+       if (bd->control_flags.message_type == TX_HOST_COMMAND_TYPE)
+               /* nothing to cleanup after for host commands */
+               return;
+
+       /* sanity check */
+       if (bd->u.data.num_chunks > NUM_TFD_CHUNKS) {
+               IPW_ERROR("Too many chunks: %i\n", bd->u.data.num_chunks);
+               /** @todo issue fatal error, it is quite serious situation */
+               return;
+       }
+
+       /* unmap chunks if any */
+       for (i = 0; i < bd->u.data.num_chunks; i++) {
+               pci_unmap_single(dev, bd->u.data.chunk_ptr[i],
+                                bd->u.data.chunk_len[i], PCI_DMA_TODEVICE);
+               if (txq->txb[txq->q.last_used]) {
+                       ieee80211_txb_free(txq->txb[txq->q.last_used]);
+                       txq->txb[txq->q.last_used] = NULL;
+               }
+       }
+}
+
+/**
+ * Deallocate DMA queue.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers.
+ *
+ * @param dev
+ * @param q
+ */
+static void ipw_queue_tx_free(struct ipw_priv *priv, struct clx2_tx_queue *txq)
+{
+       struct clx2_queue *q = &txq->q;
+       struct pci_dev *dev = priv->pci_dev;
+
+       if (q->n_bd == 0)
+               return;
+
+       /* first, empty all BD's */
+       for (; q->first_empty != q->last_used;
+            q->last_used = ipw_queue_inc_wrap(q->last_used, q->n_bd)) {
+               ipw_queue_tx_free_tfd(priv, txq);
+       }
+
+       /* free buffers belonging to queue itself */
+       pci_free_consistent(dev, sizeof(txq->bd[0]) * q->n_bd, txq->bd,
+                           q->dma_addr);
+       kfree(txq->txb);
+
+       /* 0 fill whole structure */
+       memset(txq, 0, sizeof(*txq));
+}
+
+/**
+ * Destroy all DMA queues and structures
+ *
+ * @param priv
+ */
+static void ipw_tx_queue_free(struct ipw_priv *priv)
+{
+       /* Tx CMD queue */
+       ipw_queue_tx_free(priv, &priv->txq_cmd);
+
+       /* Tx queues */
+       ipw_queue_tx_free(priv, &priv->txq[0]);
+       ipw_queue_tx_free(priv, &priv->txq[1]);
+       ipw_queue_tx_free(priv, &priv->txq[2]);
+       ipw_queue_tx_free(priv, &priv->txq[3]);
+}
+
+static void inline __maybe_wake_tx(struct ipw_priv *priv)
+{
+       if (netif_running(priv->net_dev)) {
+               switch (priv->port_type) {
+               case DCR_TYPE_MU_BSS:
+               case DCR_TYPE_MU_IBSS:
+                       if (!(priv->status & STATUS_ASSOCIATED)) {
+                               return;
+                       }
+               }
+               netif_wake_queue(priv->net_dev);
+       }
+
+}
+
+static inline void ipw_create_bssid(struct ipw_priv *priv, u8 * bssid)
+{
+       /* First 3 bytes are manufacturer */
+       bssid[0] = priv->mac_addr[0];
+       bssid[1] = priv->mac_addr[1];
+       bssid[2] = priv->mac_addr[2];
+
+       /* Last bytes are random */
+       get_random_bytes(&bssid[3], ETH_ALEN - 3);
+
+       bssid[0] &= 0xfe;       /* clear multicast bit */
+       bssid[0] |= 0x02;       /* set local assignment bit (IEEE802) */
+}
+
+static inline u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid)
+{
+       struct ipw_station_entry entry;
+       int i;
+
+       for (i = 0; i < priv->num_stations; i++) {
+               if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) {
+                       /* Another node is active in network */
+                       priv->missed_adhoc_beacons = 0;
+                       if (!(priv->config & CFG_STATIC_CHANNEL))
+                               /* when other nodes drop out, we drop out */
+                               priv->config &= ~CFG_ADHOC_PERSIST;
+
+                       return i;
+               }
+       }
+
+       if (i == MAX_STATIONS)
+               return IPW_INVALID_STATION;
+
+       IPW_DEBUG_SCAN("Adding AdHoc station: " MAC_FMT "\n", MAC_ARG(bssid));
+
+       entry.reserved = 0;
+       entry.support_mode = 0;
+       memcpy(entry.mac_addr, bssid, ETH_ALEN);
+       memcpy(priv->stations[i], bssid, ETH_ALEN);
+       ipw_write_direct(priv, IPW_STATION_TABLE_LOWER + i * sizeof(entry),
+                        &entry, sizeof(entry));
+       priv->num_stations++;
+
+       return i;
+}
+
+static inline u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid)
+{
+       int i;
+
+       for (i = 0; i < priv->num_stations; i++)
+               if (!memcmp(priv->stations[i], bssid, ETH_ALEN))
+                       return i;
+
+       return IPW_INVALID_STATION;
+}
+
+static void ipw_send_disassociate(struct ipw_priv *priv, int quiet)
+{
+       int err;
+
+       if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED))) {
+               IPW_DEBUG_ASSOC("Disassociating while not associated.\n");
+               return;
+       }
+
+       IPW_DEBUG_ASSOC("Disassocation attempt from " MAC_FMT " "
+                       "on channel %d.\n",
+                       MAC_ARG(priv->assoc_request.bssid),
+                       priv->assoc_request.channel);
+
+       priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
+       priv->status |= STATUS_DISASSOCIATING;
+
+       if (quiet)
+               priv->assoc_request.assoc_type = HC_DISASSOC_QUIET;
+       else
+               priv->assoc_request.assoc_type = HC_DISASSOCIATE;
+       err = ipw_send_associate(priv, &priv->assoc_request);
+       if (err) {
+               IPW_DEBUG_HC("Attempt to send [dis]associate command "
+                            "failed.\n");
+               return;
+       }
+
+}
+
+static void ipw_disassociate(void *data)
+{
+       ipw_send_disassociate(data, 0);
+}
+
+static void notify_wx_assoc_event(struct ipw_priv *priv)
+{
+       union iwreq_data wrqu;
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+       if (priv->status & STATUS_ASSOCIATED)
+               memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
+       else
+               memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+       wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
+}
+
+struct ipw_status_code {
+       u16 status;
+       const char *reason;
+};
+
+static const struct ipw_status_code ipw_status_codes[] = {
+       {0x00, "Successful"},
+       {0x01, "Unspecified failure"},
+       {0x0A, "Cannot support all requested capabilities in the "
+        "Capability information field"},
+       {0x0B, "Reassociation denied due to inability to confirm that "
+        "association exists"},
+       {0x0C, "Association denied due to reason outside the scope of this "
+        "standard"},
+       {0x0D,
+        "Responding station does not support the specified authentication "
+        "algorithm"},
+       {0x0E,
+        "Received an Authentication frame with authentication sequence "
+        "transaction sequence number out of expected sequence"},
+       {0x0F, "Authentication rejected because of challenge failure"},
+       {0x10, "Authentication rejected due to timeout waiting for next "
+        "frame in sequence"},
+       {0x11, "Association denied because AP is unable to handle additional "
+        "associated stations"},
+       {0x12,
+        "Association denied due to requesting station not supporting all "
+        "of the datarates in the BSSBasicServiceSet Parameter"},
+       {0x13,
+        "Association denied due to requesting station not supporting "
+        "short preamble operation"},
+       {0x14,
+        "Association denied due to requesting station not supporting "
+        "PBCC encoding"},
+       {0x15,
+        "Association denied due to requesting station not supporting "
+        "channel agility"},
+       {0x19,
+        "Association denied due to requesting station not supporting "
+        "short slot operation"},
+       {0x1A,
+        "Association denied due to requesting station not supporting "
+        "DSSS-OFDM operation"},
+       {0x28, "Invalid Information Element"},
+       {0x29, "Group Cipher is not valid"},
+       {0x2A, "Pairwise Cipher is not valid"},
+       {0x2B, "AKMP is not valid"},
+       {0x2C, "Unsupported RSN IE version"},
+       {0x2D, "Invalid RSN IE Capabilities"},
+       {0x2E, "Cipher suite is rejected per security policy"},
+};
+
+#ifdef CONFIG_IPW_DEBUG
+static const char *ipw_get_status_code(u16 status)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(ipw_status_codes); i++)
+               if (ipw_status_codes[i].status == status)
+                       return ipw_status_codes[i].reason;
+       return "Unknown status value.";
+}
+#endif
+
+static void inline average_init(struct average *avg)
+{
+       memset(avg, 0, sizeof(*avg));
+}
+
+static void inline average_add(struct average *avg, s16 val)
+{
+       avg->sum -= avg->entries[avg->pos];
+       avg->sum += val;
+       avg->entries[avg->pos++] = val;
+       if (unlikely(avg->pos == AVG_ENTRIES)) {
+               avg->init = 1;
+               avg->pos = 0;
+       }
+}
+
+static s16 inline average_value(struct average *avg)
+{
+       if (!unlikely(avg->init)) {
+               if (avg->pos)
+                       return avg->sum / avg->pos;
+               return 0;
+       }
+
+       return avg->sum / AVG_ENTRIES;
+}
+
+static void ipw_reset_stats(struct ipw_priv *priv)
+{
+       u32 len = sizeof(u32);
+
+       priv->quality = 0;
+
+       average_init(&priv->average_missed_beacons);
+       average_init(&priv->average_rssi);
+       average_init(&priv->average_noise);
+
+       priv->last_rate = 0;
+       priv->last_missed_beacons = 0;
+       priv->last_rx_packets = 0;
+       priv->last_tx_packets = 0;
+       priv->last_tx_failures = 0;
+
+       /* Firmware managed, reset only when NIC is restarted, so we have to
+        * normalize on the current value */
+       ipw_get_ordinal(priv, IPW_ORD_STAT_RX_ERR_CRC,
+                       &priv->last_rx_err, &len);
+       ipw_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURE,
+                       &priv->last_tx_failures, &len);
+
+       /* Driver managed, reset with each association */
+       priv->missed_adhoc_beacons = 0;
+       priv->missed_beacons = 0;
+       priv->tx_packets = 0;
+       priv->rx_packets = 0;
+
+}
+
+static inline u32 ipw_get_max_rate(struct ipw_priv *priv)
+{
+       u32 i = 0x80000000;
+       u32 mask = priv->rates_mask;
+       /* If currently associated in B mode, restrict the maximum
+        * rate match to B rates */
+       if (priv->assoc_request.ieee_mode == IPW_B_MODE)
+               mask &= IEEE80211_CCK_RATES_MASK;
+
+       /* TODO: Verify that the rate is supported by the current rates
+        * list. */
+
+       while (i && !(mask & i))
+               i >>= 1;
+       switch (i) {
+       case IEEE80211_CCK_RATE_1MB_MASK:       return 1000000;
+       case IEEE80211_CCK_RATE_2MB_MASK:       return 2000000;
+       case IEEE80211_CCK_RATE_5MB_MASK:       return 5500000;
+       case IEEE80211_OFDM_RATE_6MB_MASK:      return 6000000;
+       case IEEE80211_OFDM_RATE_9MB_MASK:      return 9000000;
+       case IEEE80211_CCK_RATE_11MB_MASK:      return 11000000;
+       case IEEE80211_OFDM_RATE_12MB_MASK:     return 12000000;
+       case IEEE80211_OFDM_RATE_18MB_MASK:     return 18000000;
+       case IEEE80211_OFDM_RATE_24MB_MASK:     return 24000000;
+       case IEEE80211_OFDM_RATE_36MB_MASK:     return 36000000;
+       case IEEE80211_OFDM_RATE_48MB_MASK:     return 48000000;
+       case IEEE80211_OFDM_RATE_54MB_MASK:     return 54000000;
+       }
+
+       if (priv->ieee->mode == IEEE_B)
+               return 11000000;
+       else
+               return 54000000;
+}
+
+static u32 ipw_get_current_rate(struct ipw_priv *priv)
+{
+       u32 rate, len = sizeof(rate);
+       int err;
+
+       if (!(priv->status & STATUS_ASSOCIATED))
+               return 0;
+
+       if (priv->tx_packets > IPW_REAL_RATE_RX_PACKET_THRESHOLD) {
+               err = ipw_get_ordinal(priv, IPW_ORD_STAT_TX_CURR_RATE, &rate,
+                                     &len);
+               if (err) {
+                       IPW_DEBUG_INFO("failed querying ordinals.\n");
+                       return 0;
+               }
+       } else
+               return ipw_get_max_rate(priv);
+
+       switch (rate) {
+       case IPW_TX_RATE_1MB:   return 1000000;
+       case IPW_TX_RATE_2MB:   return 2000000;
+       case IPW_TX_RATE_5MB:   return 5500000;
+       case IPW_TX_RATE_6MB:   return 6000000;
+       case IPW_TX_RATE_9MB:   return 9000000;
+       case IPW_TX_RATE_11MB:  return 11000000;
+       case IPW_TX_RATE_12MB:  return 12000000;
+       case IPW_TX_RATE_18MB:  return 18000000;
+       case IPW_TX_RATE_24MB:  return 24000000;
+       case IPW_TX_RATE_36MB:  return 36000000;
+       case IPW_TX_RATE_48MB:  return 48000000;
+       case IPW_TX_RATE_54MB:  return 54000000;
+       }
+
+       return 0;
+}
+
+#define PERFECT_RSSI (-50)
+#define WORST_RSSI   (-85)
+#define IPW_STATS_INTERVAL (2 * HZ)
+static void ipw_gather_stats(struct ipw_priv *priv)
+{
+       u32 rx_err, rx_err_delta, rx_packets_delta;
+       u32 tx_failures, tx_failures_delta, tx_packets_delta;
+       u32 missed_beacons_percent, missed_beacons_delta;
+       u32 quality = 0;
+       u32 len = sizeof(u32);
+       s16 rssi;
+       u32 beacon_quality, signal_quality, tx_quality, rx_quality,
+           rate_quality;
+
+       if (!(priv->status & STATUS_ASSOCIATED)) {
+               priv->quality = 0;
+               return;
+       }
+
+       /* Update the statistics */
+       ipw_get_ordinal(priv, IPW_ORD_STAT_MISSED_BEACONS,
+                       &priv->missed_beacons, &len);
+       missed_beacons_delta = priv->missed_beacons - priv->last_missed_beacons;
+       priv->last_missed_beacons = priv->missed_beacons;
+       if (priv->assoc_request.beacon_interval) {
+               missed_beacons_percent = missed_beacons_delta *
+                   (HZ * priv->assoc_request.beacon_interval) /
+                   (IPW_STATS_INTERVAL * 10);
+       } else {
+               missed_beacons_percent = 0;
+       }
+       average_add(&priv->average_missed_beacons, missed_beacons_percent);
+
+       ipw_get_ordinal(priv, IPW_ORD_STAT_RX_ERR_CRC, &rx_err, &len);
+       rx_err_delta = rx_err - priv->last_rx_err;
+       priv->last_rx_err = rx_err;
+
+       ipw_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURE, &tx_failures, &len);
+       tx_failures_delta = tx_failures - priv->last_tx_failures;
+       priv->last_tx_failures = tx_failures;
+
+       rx_packets_delta = priv->rx_packets - priv->last_rx_packets;
+       priv->last_rx_packets = priv->rx_packets;
+
+       tx_packets_delta = priv->tx_packets - priv->last_tx_packets;
+       priv->last_tx_packets = priv->tx_packets;
+
+       /* Calculate quality based on the following:
+        *
+        * Missed beacon: 100% = 0, 0% = 70% missed
+        * Rate: 60% = 1Mbs, 100% = Max
+        * Rx and Tx errors represent a straight % of total Rx/Tx
+        * RSSI: 100% = > -50,  0% = < -80
+        * Rx errors: 100% = 0, 0% = 50% missed
+        *
+        * The lowest computed quality is used.
+        *
+        */
+#define BEACON_THRESHOLD 5
+       beacon_quality = 100 - missed_beacons_percent;
+       if (beacon_quality < BEACON_THRESHOLD)
+               beacon_quality = 0;
+       else
+               beacon_quality = (beacon_quality - BEACON_THRESHOLD) * 100 /
+                   (100 - BEACON_THRESHOLD);
+       IPW_DEBUG_STATS("Missed beacon: %3d%% (%d%%)\n",
+                       beacon_quality, missed_beacons_percent);
+
+       priv->last_rate = ipw_get_current_rate(priv);
+       rate_quality = priv->last_rate * 40 / priv->last_rate + 60;
+       IPW_DEBUG_STATS("Rate quality : %3d%% (%dMbs)\n",
+                       rate_quality, priv->last_rate / 1000000);
+
+       if (rx_packets_delta > 100 && rx_packets_delta + rx_err_delta)
+               rx_quality = 100 - (rx_err_delta * 100) /
+                   (rx_packets_delta + rx_err_delta);
+       else
+               rx_quality = 100;
+       IPW_DEBUG_STATS("Rx quality   : %3d%% (%u errors, %u packets)\n",
+                       rx_quality, rx_err_delta, rx_packets_delta);
+
+       if (tx_packets_delta > 100 && tx_packets_delta + tx_failures_delta)
+               tx_quality = 100 - (tx_failures_delta * 100) /
+                   (tx_packets_delta + tx_failures_delta);
+       else
+               tx_quality = 100;
+       IPW_DEBUG_STATS("Tx quality   : %3d%% (%u errors, %u packets)\n",
+                       tx_quality, tx_failures_delta, tx_packets_delta);
+
+       rssi = average_value(&priv->average_rssi);
+       if (rssi > PERFECT_RSSI)
+               signal_quality = 100;
+       else if (rssi < WORST_RSSI)
+               signal_quality = 0;
+       else
+               signal_quality = (rssi - WORST_RSSI) * 100 /
+                   (PERFECT_RSSI - WORST_RSSI);
+       IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n",
+                       signal_quality, rssi);
+
+       quality = min(beacon_quality,
+                     min(rate_quality,
+                         min(tx_quality, min(rx_quality, signal_quality))));
+       if (quality == beacon_quality)
+               IPW_DEBUG_STATS("Quality (%d%%): Clamped to missed beacons.\n",
+                               quality);
+       if (quality == rate_quality)
+               IPW_DEBUG_STATS("Quality (%d%%): Clamped to rate quality.\n",
+                               quality);
+       if (quality == tx_quality)
+               IPW_DEBUG_STATS("Quality (%d%%): Clamped to Tx quality.\n",
+                               quality);
+       if (quality == rx_quality)
+               IPW_DEBUG_STATS("Quality (%d%%): Clamped to Rx quality.\n",
+                               quality);
+       if (quality == signal_quality)
+               IPW_DEBUG_STATS("Quality (%d%%): Clamped to signal quality.\n",
+                               quality);
+
+       priv->quality = quality;
+
+       queue_delayed_work(priv->workqueue, &priv->gather_stats,
+                          IPW_STATS_INTERVAL);
+}
+
+/**
+ * Handle host notification packet.
+ * Called from interrupt routine
+ */
+static inline void ipw_rx_notification(struct ipw_priv *priv,
+                                      struct ipw_rx_notification *notif)
+{
+       IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, notif->size);
+
+       switch (notif->subtype) {
+       case HOST_NOTIFICATION_STATUS_ASSOCIATED:{
+                       struct notif_association *assoc = &notif->u.assoc;
+
+                       switch (assoc->state) {
+                       case CMAS_ASSOCIATED:{
+                                       IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+                                                 IPW_DL_ASSOC,
+                                                 "associated: '%s' " MAC_FMT
+                                                 " \n",
+                                                 escape_essid(priv->essid,
+                                                              priv->essid_len),
+                                                 MAC_ARG(priv->bssid));
+
+                                       switch (priv->ieee->iw_mode) {
+                                       case IW_MODE_INFRA:
+                                               memcpy(priv->ieee->bssid,
+                                                      priv->bssid, ETH_ALEN);
+                                               break;
+
+                                       case IW_MODE_ADHOC:
+                                               memcpy(priv->ieee->bssid,
+                                                      priv->bssid, ETH_ALEN);
+
+                                               /* clear out the station table */
+                                               priv->num_stations = 0;
+
+                                               IPW_DEBUG_ASSOC
+                                                   ("queueing adhoc check\n");
+                                               queue_delayed_work(priv->
+                                                                  workqueue,
+                                                                  &priv->
+                                                                  adhoc_check,
+                                                                  priv->
+                                                                  assoc_request.
+                                                                  beacon_interval);
+                                               break;
+                                       }
+
+                                       priv->status &= ~STATUS_ASSOCIATING;
+                                       priv->status |= STATUS_ASSOCIATED;
+
+                                       netif_carrier_on(priv->net_dev);
+                                       if (netif_queue_stopped(priv->net_dev)) {
+                                               IPW_DEBUG_NOTIF
+                                                   ("waking queue\n");
+                                               netif_wake_queue(priv->net_dev);
+                                       } else {
+                                               IPW_DEBUG_NOTIF
+                                                   ("starting queue\n");
+                                               netif_start_queue(priv->
+                                                                 net_dev);
+                                       }
+
+                                       ipw_reset_stats(priv);
+                                       /* Ensure the rate is updated immediately */
+                                       priv->last_rate =
+                                           ipw_get_current_rate(priv);
+                                       schedule_work(&priv->gather_stats);
+                                       notify_wx_assoc_event(priv);
+
+/*                     queue_delayed_work(priv->workqueue,
+                                          &priv->request_scan,
+                                          SCAN_ASSOCIATED_INTERVAL);
+*/
+                                       break;
+                               }
+
+                       case CMAS_AUTHENTICATED:{
+                                       if (priv->
+                                           status & (STATUS_ASSOCIATED |
+                                                     STATUS_AUTH)) {
+#ifdef CONFIG_IPW_DEBUG
+                                               struct notif_authenticate *auth
+                                                   = &notif->u.auth;
+                                               IPW_DEBUG(IPW_DL_NOTIF |
+                                                         IPW_DL_STATE |
+                                                         IPW_DL_ASSOC,
+                                                         "deauthenticated: '%s' "
+                                                         MAC_FMT
+                                                         ": (0x%04X) - %s \n",
+                                                         escape_essid(priv->
+                                                                      essid,
+                                                                      priv->
+                                                                      essid_len),
+                                                         MAC_ARG(priv->bssid),
+                                                         ntohs(auth->status),
+                                                         ipw_get_status_code
+                                                         (ntohs
+                                                          (auth->status)));
+#endif
+
+                                               priv->status &=
+                                                   ~(STATUS_ASSOCIATING |
+                                                     STATUS_AUTH |
+                                                     STATUS_ASSOCIATED);
+
+                                               netif_carrier_off(priv->
+                                                                 net_dev);
+                                               netif_stop_queue(priv->net_dev);
+                                               queue_work(priv->workqueue,
+                                                          &priv->request_scan);
+                                               notify_wx_assoc_event(priv);
+                                               break;
+                                       }
+
+                                       IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+                                                 IPW_DL_ASSOC,
+                                                 "authenticated: '%s' " MAC_FMT
+                                                 "\n",
+                                                 escape_essid(priv->essid,
+                                                              priv->essid_len),
+                                                 MAC_ARG(priv->bssid));
+                                       break;
+                               }
+
+                       case CMAS_INIT:{
+                                       IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+                                                 IPW_DL_ASSOC,
+                                                 "disassociated: '%s' " MAC_FMT
+                                                 " \n",
+                                                 escape_essid(priv->essid,
+                                                              priv->essid_len),
+                                                 MAC_ARG(priv->bssid));
+
+                                       priv->status &=
+                                           ~(STATUS_DISASSOCIATING |
+                                             STATUS_ASSOCIATING |
+                                             STATUS_ASSOCIATED | STATUS_AUTH);
+
+                                       netif_stop_queue(priv->net_dev);
+                                       if (!(priv->status & STATUS_ROAMING)) {
+                                               netif_carrier_off(priv->
+                                                                 net_dev);
+                                               notify_wx_assoc_event(priv);
+
+                                               /* Cancel any queued work ... */
+                                               cancel_delayed_work(&priv->
+                                                                   request_scan);
+                                               cancel_delayed_work(&priv->
+                                                                   adhoc_check);
+
+                                               /* Queue up another scan... */
+                                               queue_work(priv->workqueue,
+                                                          &priv->request_scan);
+
+                                               cancel_delayed_work(&priv->
+                                                                   gather_stats);
+                                       } else {
+                                               priv->status |= STATUS_ROAMING;
+                                               queue_work(priv->workqueue,
+                                                          &priv->request_scan);
+                                       }
+
+                                       ipw_reset_stats(priv);
+                                       break;
+                               }
+
+                       default:
+                               IPW_ERROR("assoc: unknown (%d)\n",
+                                         assoc->state);
+                               break;
+                       }
+
+                       break;
+               }
+
+       case HOST_NOTIFICATION_STATUS_AUTHENTICATE:{
+                       struct notif_authenticate *auth = &notif->u.auth;
+                       switch (auth->state) {
+                       case CMAS_AUTHENTICATED:
+                               IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
+                                         "authenticated: '%s' " MAC_FMT " \n",
+                                         escape_essid(priv->essid,
+                                                      priv->essid_len),
+                                         MAC_ARG(priv->bssid));
+                               priv->status |= STATUS_AUTH;
+                               break;
+
+                       case CMAS_INIT:
+                               if (priv->status & STATUS_AUTH) {
+                                       IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+                                                 IPW_DL_ASSOC,
+                                                 "authentication failed (0x%04X): %s\n",
+                                                 ntohs(auth->status),
+                                                 ipw_get_status_code(ntohs
+                                                                     (auth->
+                                                                      status)));
+                               }
+                               IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+                                         IPW_DL_ASSOC,
+                                         "deauthenticated: '%s' " MAC_FMT "\n",
+                                         escape_essid(priv->essid,
+                                                      priv->essid_len),
+                                         MAC_ARG(priv->bssid));
+
+                               priv->status &= ~(STATUS_ASSOCIATING |
+                                                 STATUS_AUTH |
+                                                 STATUS_ASSOCIATED);
+
+                               netif_carrier_off(priv->net_dev);
+                               netif_stop_queue(priv->net_dev);
+                               queue_work(priv->workqueue,
+                                          &priv->request_scan);
+                               notify_wx_assoc_event(priv);
+                               break;
+
+                       case CMAS_TX_AUTH_SEQ_1:
+                               IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+                                         IPW_DL_ASSOC, "AUTH_SEQ_1\n");
+                               break;
+                       case CMAS_RX_AUTH_SEQ_2:
+                               IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+                                         IPW_DL_ASSOC, "AUTH_SEQ_2\n");
+                               break;
+                       case CMAS_AUTH_SEQ_1_PASS:
+                               IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+                                         IPW_DL_ASSOC, "AUTH_SEQ_1_PASS\n");
+                               break;
+                       case CMAS_AUTH_SEQ_1_FAIL:
+                               IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+                                         IPW_DL_ASSOC, "AUTH_SEQ_1_FAIL\n");
+                               break;
+                       case CMAS_TX_AUTH_SEQ_3:
+                               IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+                                         IPW_DL_ASSOC, "AUTH_SEQ_3\n");
+                               break;
+                       case CMAS_RX_AUTH_SEQ_4:
+                               IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+                                         IPW_DL_ASSOC, "RX_AUTH_SEQ_4\n");
+                               break;
+                       case CMAS_AUTH_SEQ_2_PASS:
+                               IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+                                         IPW_DL_ASSOC, "AUTH_SEQ_2_PASS\n");
+                               break;
+                       case CMAS_AUTH_SEQ_2_FAIL:
+                               IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+                                         IPW_DL_ASSOC, "AUT_SEQ_2_FAIL\n");
+                               break;
+                       case CMAS_TX_ASSOC:
+                               IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+                                         IPW_DL_ASSOC, "TX_ASSOC\n");
+                               break;
+                       case CMAS_RX_ASSOC_RESP:
+                               IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+                                         IPW_DL_ASSOC, "RX_ASSOC_RESP\n");
+                               break;
+                       case CMAS_ASSOCIATED:
+                               IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+                                         IPW_DL_ASSOC, "ASSOCIATED\n");
+                               break;
+                       default:
+                               IPW_DEBUG_NOTIF("auth: failure - %d\n",
+                                               auth->state);
+                               break;
+                       }
+                       break;
+               }
+
+       case HOST_NOTIFICATION_STATUS_SCAN_CHANNEL_RESULT:{
+                       struct notif_channel_result *x =
+                           &notif->u.channel_result;
+
+                       if (notif->size == sizeof(*x)) {
+                               IPW_DEBUG_SCAN("Scan result for channel %d\n",
+                                              x->channel_num);
+                       } else {
+                               IPW_DEBUG_SCAN("Scan result of wrong size %d "
+                                              "(should be %zd)\n",
+                                              notif->size, sizeof(*x));
+                       }
+                       break;
+               }
+
+       case HOST_NOTIFICATION_STATUS_SCAN_COMPLETED:{
+                       struct notif_scan_complete *x = &notif->u.scan_complete;
+                       if (notif->size == sizeof(*x)) {
+                               IPW_DEBUG_SCAN
+                                   ("Scan completed: type %d, %d channels, "
+                                    "%d status\n", x->scan_type,
+                                    x->num_channels, x->status);
+                       } else {
+                               IPW_ERROR("Scan completed of wrong size %d "
+                                         "(should be %zd)\n",
+                                         notif->size, sizeof(*x));
+                       }
+
+                       priv->status &=
+                           ~(STATUS_SCANNING | STATUS_SCAN_ABORTING);
+
+                       cancel_delayed_work(&priv->scan_check);
+
+                       if (!(priv->status & (STATUS_ASSOCIATED |
+                                             STATUS_ASSOCIATING |
+                                             STATUS_ROAMING |
+                                             STATUS_DISASSOCIATING)))
+                               queue_work(priv->workqueue, &priv->associate);
+                       else if (priv->status & STATUS_ROAMING) {
+                               /* If a scan completed and we are in roam mode, then
+                                * the scan that completed was the one requested as a
+                                * result of entering roam... so, schedule the
+                                * roam work */
+                               queue_work(priv->workqueue, &priv->roam);
+                       } else if (priv->status & STATUS_SCAN_PENDING)
+                               queue_work(priv->workqueue,
+                                          &priv->request_scan);
+
+                       priv->ieee->scans++;
+                       break;
+               }
+
+       case HOST_NOTIFICATION_STATUS_FRAG_LENGTH:{
+                       struct notif_frag_length *x = &notif->u.frag_len;
+
+                       if (notif->size == sizeof(*x)) {
+                               IPW_ERROR("Frag length: %d\n", x->frag_length);
+                       } else {
+                               IPW_ERROR("Frag length of wrong size %d "
+                                         "(should be %zd)\n",
+                                         notif->size, sizeof(*x));
+                       }
+                       break;
+               }
+
+       case HOST_NOTIFICATION_STATUS_LINK_DETERIORATION:{
+                       struct notif_link_deterioration *x =
+                           &notif->u.link_deterioration;
+                       if (notif->size == sizeof(*x)) {
+                               IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
+                                         "link deterioration: '%s' " MAC_FMT
+                                         " \n", escape_essid(priv->essid,
+                                                             priv->essid_len),
+                                         MAC_ARG(priv->bssid));
+                               memcpy(&priv->last_link_deterioration, x,
+                                      sizeof(*x));
+                       } else {
+                               IPW_ERROR("Link Deterioration of wrong size %d "
+                                         "(should be %zd)\n",
+                                         notif->size, sizeof(*x));
+                       }
+                       break;
+               }
+
+       case HOST_NOTIFICATION_DINO_CONFIG_RESPONSE:{
+                       IPW_ERROR("Dino config\n");
+                       if (priv->hcmd
+                           && priv->hcmd->cmd == HOST_CMD_DINO_CONFIG) {
+                               /* TODO: Do anything special? */
+                       } else {
+                               IPW_ERROR("Unexpected DINO_CONFIG_RESPONSE\n");
+                       }
+                       break;
+               }
+
+       case HOST_NOTIFICATION_STATUS_BEACON_STATE:{
+                       struct notif_beacon_state *x = &notif->u.beacon_state;
+                       if (notif->size != sizeof(*x)) {
+                               IPW_ERROR
+                                   ("Beacon state of wrong size %d (should "
+                                    "be %zd)\n", notif->size, sizeof(*x));
+                               break;
+                       }
+
+                       if (x->state == HOST_NOTIFICATION_STATUS_BEACON_MISSING) {
+                               if (priv->status & STATUS_SCANNING) {
+                                       /* Stop scan to keep fw from getting
+                                        * stuck... */
+                                       queue_work(priv->workqueue,
+                                                  &priv->abort_scan);
+                               }
+
+                               if (x->number > priv->missed_beacon_threshold &&
+                                   priv->status & STATUS_ASSOCIATED) {
+                                       IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
+                                                 IPW_DL_STATE,
+                                                 "Missed beacon: %d - disassociate\n",
+                                                 x->number);
+                                       queue_work(priv->workqueue,
+                                                  &priv->disassociate);
+                               } else if (x->number > priv->roaming_threshold) {
+                                       IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
+                                                 "Missed beacon: %d - initiate "
+                                                 "roaming\n", x->number);
+                                       queue_work(priv->workqueue,
+                                                  &priv->roam);
+                               } else {
+                                       IPW_DEBUG_NOTIF("Missed beacon: %d\n",
+                                                       x->number);
+                               }
+
+                               priv->notif_missed_beacons = x->number;
+
+                       }
+
+                       break;
+               }
+
+       case HOST_NOTIFICATION_STATUS_TGI_TX_KEY:{
+                       struct notif_tgi_tx_key *x = &notif->u.tgi_tx_key;
+                       if (notif->size == sizeof(*x)) {
+                               IPW_ERROR("TGi Tx Key: state 0x%02x sec type "
+                                         "0x%02x station %d\n",
+                                         x->key_state, x->security_type,
+                                         x->station_index);
+                               break;
+                       }
+
+                       IPW_ERROR
+                           ("TGi Tx Key of wrong size %d (should be %zd)\n",
+                            notif->size, sizeof(*x));
+                       break;
+               }
+
+       case HOST_NOTIFICATION_CALIB_KEEP_RESULTS:{
+                       struct notif_calibration *x = &notif->u.calibration;
+
+                       if (notif->size == sizeof(*x)) {
+                               memcpy(&priv->calib, x, sizeof(*x));
+                               IPW_DEBUG_INFO("TODO: Calibration\n");
+                               break;
+                       }
+
+                       IPW_ERROR
+                           ("Calibration of wrong size %d (should be %zd)\n",
+                            notif->size, sizeof(*x));
+                       break;
+               }
+
+       case HOST_NOTIFICATION_NOISE_STATS:{
+                       if (notif->size == sizeof(u32)) {
+                               priv->last_noise =
+                                   (u8) (notif->u.noise.value & 0xff);
+                               average_add(&priv->average_noise,
+                                           priv->last_noise);
+                               break;
+                       }
+
+                       IPW_ERROR
+                           ("Noise stat is wrong size %d (should be %zd)\n",
+                            notif->size, sizeof(u32));
+                       break;
+               }
+
+       default:
+               IPW_ERROR("Unknown notification: "
+                         "subtype=%d,flags=0x%2x,size=%d\n",
+                         notif->subtype, notif->flags, notif->size);
+       }
+}
+
+/**
+ * Destroys all DMA structures and initialise them again
+ *
+ * @param priv
+ * @return error code
+ */
+static int ipw_queue_reset(struct ipw_priv *priv)
+{
+       int rc = 0;
+       /** @todo customize queue sizes */
+       int nTx = 64, nTxCmd = 8;
+       ipw_tx_queue_free(priv);
+       /* Tx CMD queue */
+       rc = ipw_queue_tx_init(priv, &priv->txq_cmd, nTxCmd,
+                              CX2_TX_CMD_QUEUE_READ_INDEX,
+                              CX2_TX_CMD_QUEUE_WRITE_INDEX,
+                              CX2_TX_CMD_QUEUE_BD_BASE,
+                              CX2_TX_CMD_QUEUE_BD_SIZE);
+       if (rc) {
+               IPW_ERROR("Tx Cmd queue init failed\n");
+               goto error;
+       }
+       /* Tx queue(s) */
+       rc = ipw_queue_tx_init(priv, &priv->txq[0], nTx,
+                              CX2_TX_QUEUE_0_READ_INDEX,
+                              CX2_TX_QUEUE_0_WRITE_INDEX,
+                              CX2_TX_QUEUE_0_BD_BASE, CX2_TX_QUEUE_0_BD_SIZE);
+       if (rc) {
+               IPW_ERROR("Tx 0 queue init failed\n");
+               goto error;
+       }
+       rc = ipw_queue_tx_init(priv, &priv->txq[1], nTx,
+                              CX2_TX_QUEUE_1_READ_INDEX,
+                              CX2_TX_QUEUE_1_WRITE_INDEX,
+                              CX2_TX_QUEUE_1_BD_BASE, CX2_TX_QUEUE_1_BD_SIZE);
+       if (rc) {
+               IPW_ERROR("Tx 1 queue init failed\n");
+               goto error;
+       }
+       rc = ipw_queue_tx_init(priv, &priv->txq[2], nTx,
+                              CX2_TX_QUEUE_2_READ_INDEX,
+                              CX2_TX_QUEUE_2_WRITE_INDEX,
+                              CX2_TX_QUEUE_2_BD_BASE, CX2_TX_QUEUE_2_BD_SIZE);
+       if (rc) {
+               IPW_ERROR("Tx 2 queue init failed\n");
+               goto error;
+       }
+       rc = ipw_queue_tx_init(priv, &priv->txq[3], nTx,
+                              CX2_TX_QUEUE_3_READ_INDEX,
+                              CX2_TX_QUEUE_3_WRITE_INDEX,
+                              CX2_TX_QUEUE_3_BD_BASE, CX2_TX_QUEUE_3_BD_SIZE);
+       if (rc) {
+               IPW_ERROR("Tx 3 queue init failed\n");
+               goto error;
+       }
+       /* statistics */
+       priv->rx_bufs_min = 0;
+       priv->rx_pend_max = 0;
+       return rc;
+
+      error:
+       ipw_tx_queue_free(priv);
+       return rc;
+}
+
+/**
+ * Reclaim Tx queue entries no more used by NIC.
+ *
+ * When FW adwances 'R' index, all entries between old and
+ * new 'R' index need to be reclaimed. As result, some free space
+ * forms. If there is enough free space (> low mark), wake Tx queue.
+ *
+ * @note Need to protect against garbage in 'R' index
+ * @param priv
+ * @param txq
+ * @param qindex
+ * @return Number of used entries remains in the queue
+ */
+static int ipw_queue_tx_reclaim(struct ipw_priv *priv,
+                               struct clx2_tx_queue *txq, int qindex)
+{
+       u32 hw_tail;
+       int used;
+       struct clx2_queue *q = &txq->q;
+
+       hw_tail = ipw_read32(priv, q->reg_r);
+       if (hw_tail >= q->n_bd) {
+               IPW_ERROR
+                   ("Read index for DMA queue (%d) is out of range [0-%d)\n",
+                    hw_tail, q->n_bd);
+               goto done;
+       }
+       for (; q->last_used != hw_tail;
+            q->last_used = ipw_queue_inc_wrap(q->last_used, q->n_bd)) {
+               ipw_queue_tx_free_tfd(priv, txq);
+               priv->tx_packets++;
+       }
+      done:
+       if (ipw_queue_space(q) > q->low_mark && qindex >= 0) {
+               __maybe_wake_tx(priv);
+       }
+       used = q->first_empty - q->last_used;
+       if (used < 0)
+               used += q->n_bd;
+
+       return used;
+}
+
+static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, void *buf,
+                            int len, int sync)
+{
+       struct clx2_tx_queue *txq = &priv->txq_cmd;
+       struct clx2_queue *q = &txq->q;
+       struct tfd_frame *tfd;
+
+       if (ipw_queue_space(q) < (sync ? 1 : 2)) {
+               IPW_ERROR("No space for Tx\n");
+               return -EBUSY;
+       }
+
+       tfd = &txq->bd[q->first_empty];
+       txq->txb[q->first_empty] = NULL;
+
+       memset(tfd, 0, sizeof(*tfd));
+       tfd->control_flags.message_type = TX_HOST_COMMAND_TYPE;
+       tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK;
+       priv->hcmd_seq++;
+       tfd->u.cmd.index = hcmd;
+       tfd->u.cmd.length = len;
+       memcpy(tfd->u.cmd.payload, buf, len);
+       q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd);
+       ipw_write32(priv, q->reg_w, q->first_empty);
+       _ipw_read32(priv, 0x90);
+
+       return 0;
+}
+
+/*
+ * Rx theory of operation
+ *
+ * The host allocates 32 DMA target addresses and passes the host address
+ * to the firmware at register CX2_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
+ * 0 to 31
+ *
+ * Rx Queue Indexes
+ * The host/firmware share two index registers for managing the Rx buffers.
+ *
+ * The READ index maps to the first position that the firmware may be writing
+ * to -- the driver can read up to (but not including) this position and get
+ * good data.
+ * The READ index is managed by the firmware once the card is enabled.
+ *
+ * The WRITE index maps to the last position the driver has read from -- the
+ * position preceding WRITE is the last slot the firmware can place a packet.
+ *
+ * The queue is empty (no good data) if WRITE = READ - 1, and is full if
+ * WRITE = READ.
+ *
+ * During initialization the host sets up the READ queue position to the first
+ * INDEX position, and WRITE to the last (READ - 1 wrapped)
+ *
+ * When the firmware places a packet in a buffer it will advance the READ index
+ * and fire the RX interrupt.  The driver can then query the READ index and
+ * process as many packets as possible, moving the WRITE index forward as it
+ * resets the Rx queue buffers with new memory.
+ *
+ * The management in the driver is as follows:
+ * + A list of pre-allocated SKBs is stored in ipw->rxq->rx_free.  When
+ *   ipw->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
+ *   to replensish the ipw->rxq->rx_free.
+ * + In ipw_rx_queue_replenish (scheduled) if 'processed' != 'read' then the
+ *   ipw->rxq is replenished and the READ INDEX is updated (updating the
+ *   'processed' and 'read' driver indexes as well)
+ * + A received packet is processed and handed to the kernel network stack,
+ *   detached from the ipw->rxq.  The driver 'processed' index is updated.
+ * + The Host/Firmware ipw->rxq is replenished at tasklet time from the rx_free
+ *   list. If there are no allocated buffers in ipw->rxq->rx_free, the READ
+ *   INDEX is not incremented and ipw->status(RX_STALLED) is set.  If there
+ *   were enough free buffers and RX_STALLED is set it is cleared.
+ *
+ *
+ * Driver sequence:
+ *
+ * ipw_rx_queue_alloc()       Allocates rx_free
+ * ipw_rx_queue_replenish()   Replenishes rx_free list from rx_used, and calls
+ *                            ipw_rx_queue_restock
+ * ipw_rx_queue_restock()     Moves available buffers from rx_free into Rx
+ *                            queue, updates firmware pointers, and updates
+ *                            the WRITE index.  If insufficient rx_free buffers
+ *                            are available, schedules ipw_rx_queue_replenish
+ *
+ * -- enable interrupts --
+ * ISR - ipw_rx()             Detach ipw_rx_mem_buffers from pool up to the
+ *                            READ INDEX, detaching the SKB from the pool.
+ *                            Moves the packet buffer from queue to rx_used.
+ *                            Calls ipw_rx_queue_restock to refill any empty
+ *                            slots.
+ * ...
+ *
+ */
+
+/*
+ * If there are slots in the RX queue that  need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+static void ipw_rx_queue_restock(struct ipw_priv *priv)
+{
+       struct ipw_rx_queue *rxq = priv->rxq;
+       struct list_head *element;
+       struct ipw_rx_mem_buffer *rxb;
+       unsigned long flags;
+       int write;
+
+       spin_lock_irqsave(&rxq->lock, flags);
+       write = rxq->write;
+       while ((rxq->write != rxq->processed) && (rxq->free_count)) {
+               element = rxq->rx_free.next;
+               rxb = list_entry(element, struct ipw_rx_mem_buffer, list);
+               list_del(element);
+
+               ipw_write32(priv, CX2_RFDS_TABLE_LOWER + rxq->write * RFD_SIZE,
+                           rxb->dma_addr);
+               rxq->queue[rxq->write] = rxb;
+               rxq->write = (rxq->write + 1) % RX_QUEUE_SIZE;
+               rxq->free_count--;
+       }
+       spin_unlock_irqrestore(&rxq->lock, flags);
+
+       /* If the pre-allocated buffer pool is dropping low, schedule to
+        * refill it */
+       if (rxq->free_count <= RX_LOW_WATERMARK)
+               queue_work(priv->workqueue, &priv->rx_replenish);
+
+       /* If we've added more space for the firmware to place data, tell it */
+       if (write != rxq->write)
+               ipw_write32(priv, CX2_RX_WRITE_INDEX, rxq->write);
+}
+
+/*
+ * Move all used packet from rx_used to rx_free, allocating a new SKB for each.
+ * Also restock the Rx queue via ipw_rx_queue_restock.
+ *
+ * This is called as a scheduled work item (except for during intialization)
+ */
+static void ipw_rx_queue_replenish(void *data)
+{
+       struct ipw_priv *priv = data;
+       struct ipw_rx_queue *rxq = priv->rxq;
+       struct list_head *element;
+       struct ipw_rx_mem_buffer *rxb;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rxq->lock, flags);
+       while (!list_empty(&rxq->rx_used)) {
+               element = rxq->rx_used.next;
+               rxb = list_entry(element, struct ipw_rx_mem_buffer, list);
+               rxb->skb = alloc_skb(CX2_RX_BUF_SIZE, GFP_ATOMIC);
+               if (!rxb->skb) {
+                       printk(KERN_CRIT "%s: Can not allocate SKB buffers.\n",
+                              priv->net_dev->name);
+                       /* We don't reschedule replenish work here -- we will
+                        * call the restock method and if it still needs
+                        * more buffers it will schedule replenish */
+                       break;
+               }
+               list_del(element);
+
+               rxb->rxb = (struct ipw_rx_buffer *)rxb->skb->data;
+               rxb->dma_addr =
+                   pci_map_single(priv->pci_dev, rxb->skb->data,
+                                  CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+
+               list_add_tail(&rxb->list, &rxq->rx_free);
+               rxq->free_count++;
+       }
+       spin_unlock_irqrestore(&rxq->lock, flags);
+
+       ipw_rx_queue_restock(priv);
+}
+
+/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
+ * If an SKB has been detached, the POOL needs to have it's SKB set to NULL
+ * This free routine walks the list of POOL entries and if SKB is set to
+ * non NULL it is unmapped and freed
+ */
+static void ipw_rx_queue_free(struct ipw_priv *priv, struct ipw_rx_queue *rxq)
+{
+       int i;
+
+       if (!rxq)
+               return;
+
+       for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
+               if (rxq->pool[i].skb != NULL) {
+                       pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr,
+                                        CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                       dev_kfree_skb(rxq->pool[i].skb);
+               }
+       }
+
+       kfree(rxq);
+}
+
+static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *priv)
+{
+       struct ipw_rx_queue *rxq;
+       int i;
+
+       rxq = (struct ipw_rx_queue *)kmalloc(sizeof(*rxq), GFP_KERNEL);
+       memset(rxq, 0, sizeof(*rxq));
+       spin_lock_init(&rxq->lock);
+       INIT_LIST_HEAD(&rxq->rx_free);
+       INIT_LIST_HEAD(&rxq->rx_used);
+
+       /* Fill the rx_used queue with _all_ of the Rx buffers */
+       for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
+               list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+
+       /* Set us so that we have processed and used all buffers, but have
+        * not restocked the Rx queue with fresh buffers */
+       rxq->read = rxq->write = 0;
+       rxq->processed = RX_QUEUE_SIZE - 1;
+       rxq->free_count = 0;
+
+       return rxq;
+}
+
+static int ipw_is_rate_in_mask(struct ipw_priv *priv, int ieee_mode, u8 rate)
+{
+       rate &= ~IEEE80211_BASIC_RATE_MASK;
+       if (ieee_mode == IEEE_A) {
+               switch (rate) {
+               case IEEE80211_OFDM_RATE_6MB:
+                       return priv->rates_mask & IEEE80211_OFDM_RATE_6MB_MASK ?
+                           1 : 0;
+               case IEEE80211_OFDM_RATE_9MB:
+                       return priv->rates_mask & IEEE80211_OFDM_RATE_9MB_MASK ?
+                           1 : 0;
+               case IEEE80211_OFDM_RATE_12MB:
+                       return priv->
+                           rates_mask & IEEE80211_OFDM_RATE_12MB_MASK ? 1 : 0;
+               case IEEE80211_OFDM_RATE_18MB:
+                       return priv->
+                           rates_mask & IEEE80211_OFDM_RATE_18MB_MASK ? 1 : 0;
+               case IEEE80211_OFDM_RATE_24MB:
+                       return priv->
+                           rates_mask & IEEE80211_OFDM_RATE_24MB_MASK ? 1 : 0;
+               case IEEE80211_OFDM_RATE_36MB:
+                       return priv->
+                           rates_mask & IEEE80211_OFDM_RATE_36MB_MASK ? 1 : 0;
+               case IEEE80211_OFDM_RATE_48MB:
+                       return priv->
+                           rates_mask & IEEE80211_OFDM_RATE_48MB_MASK ? 1 : 0;
+               case IEEE80211_OFDM_RATE_54MB:
+                       return priv->
+                           rates_mask & IEEE80211_OFDM_RATE_54MB_MASK ? 1 : 0;
+               default:
+                       return 0;
+               }
+       }
+
+       /* B and G mixed */
+       switch (rate) {
+       case IEEE80211_CCK_RATE_1MB:
+               return priv->rates_mask & IEEE80211_CCK_RATE_1MB_MASK ? 1 : 0;
+       case IEEE80211_CCK_RATE_2MB:
+               return priv->rates_mask & IEEE80211_CCK_RATE_2MB_MASK ? 1 : 0;
+       case IEEE80211_CCK_RATE_5MB:
+               return priv->rates_mask & IEEE80211_CCK_RATE_5MB_MASK ? 1 : 0;
+       case IEEE80211_CCK_RATE_11MB:
+               return priv->rates_mask & IEEE80211_CCK_RATE_11MB_MASK ? 1 : 0;
+       }
+
+       /* If we are limited to B modulations, bail at this point */
+       if (ieee_mode == IEEE_B)
+               return 0;
+
+       /* G */
+       switch (rate) {
+       case IEEE80211_OFDM_RATE_6MB:
+               return priv->rates_mask & IEEE80211_OFDM_RATE_6MB_MASK ? 1 : 0;
+       case IEEE80211_OFDM_RATE_9MB:
+               return priv->rates_mask & IEEE80211_OFDM_RATE_9MB_MASK ? 1 : 0;
+       case IEEE80211_OFDM_RATE_12MB:
+               return priv->rates_mask & IEEE80211_OFDM_RATE_12MB_MASK ? 1 : 0;
+       case IEEE80211_OFDM_RATE_18MB:
+               return priv->rates_mask & IEEE80211_OFDM_RATE_18MB_MASK ? 1 : 0;
+       case IEEE80211_OFDM_RATE_24MB:
+               return priv->rates_mask & IEEE80211_OFDM_RATE_24MB_MASK ? 1 : 0;
+       case IEEE80211_OFDM_RATE_36MB:
+               return priv->rates_mask & IEEE80211_OFDM_RATE_36MB_MASK ? 1 : 0;
+       case IEEE80211_OFDM_RATE_48MB:
+               return priv->rates_mask & IEEE80211_OFDM_RATE_48MB_MASK ? 1 : 0;
+       case IEEE80211_OFDM_RATE_54MB:
+               return priv->rates_mask & IEEE80211_OFDM_RATE_54MB_MASK ? 1 : 0;
+       }
+
+       return 0;
+}
+
+static int ipw_compatible_rates(struct ipw_priv *priv,
+                               const struct ieee80211_network *network,
+                               struct ipw_supported_rates *rates)
+{
+       int num_rates, i;
+
+       memset(rates, 0, sizeof(*rates));
+       num_rates = min(network->rates_len, (u8) IPW_MAX_RATES);
+       rates->num_rates = 0;
+       for (i = 0; i < num_rates; i++) {
+               if (!ipw_is_rate_in_mask
+                   (priv, network->mode, network->rates[i])) {
+                       IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n",
+                                      network->rates[i], priv->rates_mask);
+                       continue;
+               }
+
+               rates->supported_rates[rates->num_rates++] = network->rates[i];
+       }
+
+       num_rates =
+           min(network->rates_ex_len, (u8) (IPW_MAX_RATES - num_rates));
+       for (i = 0; i < num_rates; i++) {
+               if (!ipw_is_rate_in_mask
+                   (priv, network->mode, network->rates_ex[i])) {
+                       IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n",
+                                      network->rates_ex[i], priv->rates_mask);
+                       continue;
+               }
+
+               rates->supported_rates[rates->num_rates++] =
+                   network->rates_ex[i];
+       }
+
+       return rates->num_rates;
+}
+
+static inline void ipw_copy_rates(struct ipw_supported_rates *dest,
+                                 const struct ipw_supported_rates *src)
+{
+       u8 i;
+       for (i = 0; i < src->num_rates; i++)
+               dest->supported_rates[i] = src->supported_rates[i];
+       dest->num_rates = src->num_rates;
+}
+
+/* TODO: Look at sniffed packets in the air to determine if the basic rate
+ * mask should ever be used -- right now all callers to add the scan rates are
+ * set with the modulation = CCK, so BASIC_RATE_MASK is never set... */
+static void ipw_add_cck_scan_rates(struct ipw_supported_rates *rates,
+                                  u8 modulation, u32 rate_mask)
+{
+       u8 basic_mask = (IEEE80211_OFDM_MODULATION == modulation) ?
+           IEEE80211_BASIC_RATE_MASK : 0;
+
+       if (rate_mask & IEEE80211_CCK_RATE_1MB_MASK)
+               rates->supported_rates[rates->num_rates++] =
+                   IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
+
+       if (rate_mask & IEEE80211_CCK_RATE_2MB_MASK)
+               rates->supported_rates[rates->num_rates++] =
+                   IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
+
+       if (rate_mask & IEEE80211_CCK_RATE_5MB_MASK)
+               rates->supported_rates[rates->num_rates++] = basic_mask |
+                   IEEE80211_CCK_RATE_5MB;
+
+       if (rate_mask & IEEE80211_CCK_RATE_11MB_MASK)
+               rates->supported_rates[rates->num_rates++] = basic_mask |
+                   IEEE80211_CCK_RATE_11MB;
+}
+
+static void ipw_add_ofdm_scan_rates(struct ipw_supported_rates *rates,
+                                   u8 modulation, u32 rate_mask)
+{
+       u8 basic_mask = (IEEE80211_OFDM_MODULATION == modulation) ?
+           IEEE80211_BASIC_RATE_MASK : 0;
+
+       if (rate_mask & IEEE80211_OFDM_RATE_6MB_MASK)
+               rates->supported_rates[rates->num_rates++] = basic_mask |
+                   IEEE80211_OFDM_RATE_6MB;
+
+       if (rate_mask & IEEE80211_OFDM_RATE_9MB_MASK)
+               rates->supported_rates[rates->num_rates++] =
+                   IEEE80211_OFDM_RATE_9MB;
+
+       if (rate_mask & IEEE80211_OFDM_RATE_12MB_MASK)
+               rates->supported_rates[rates->num_rates++] = basic_mask |
+                   IEEE80211_OFDM_RATE_12MB;
+
+       if (rate_mask & IEEE80211_OFDM_RATE_18MB_MASK)
+               rates->supported_rates[rates->num_rates++] =
+                   IEEE80211_OFDM_RATE_18MB;
+
+       if (rate_mask & IEEE80211_OFDM_RATE_24MB_MASK)
+               rates->supported_rates[rates->num_rates++] = basic_mask |
+                   IEEE80211_OFDM_RATE_24MB;
+
+       if (rate_mask & IEEE80211_OFDM_RATE_36MB_MASK)
+               rates->supported_rates[rates->num_rates++] =
+                   IEEE80211_OFDM_RATE_36MB;
+
+       if (rate_mask & IEEE80211_OFDM_RATE_48MB_MASK)
+               rates->supported_rates[rates->num_rates++] =
+                   IEEE80211_OFDM_RATE_48MB;
+
+       if (rate_mask & IEEE80211_OFDM_RATE_54MB_MASK)
+               rates->supported_rates[rates->num_rates++] =
+                   IEEE80211_OFDM_RATE_54MB;
+}
+
+struct ipw_network_match {
+       struct ieee80211_network *network;
+       struct ipw_supported_rates rates;
+};
+
+static int ipw_best_network(struct ipw_priv *priv,
+                           struct ipw_network_match *match,
+                           struct ieee80211_network *network, int roaming)
+{
+       struct ipw_supported_rates rates;
+
+       /* Verify that this network's capability is compatible with the
+        * current mode (AdHoc or Infrastructure) */
+       if ((priv->ieee->iw_mode == IW_MODE_INFRA &&
+            !(network->capability & WLAN_CAPABILITY_ESS)) ||
+           (priv->ieee->iw_mode == IW_MODE_ADHOC &&
+            !(network->capability & WLAN_CAPABILITY_IBSS))) {
+               IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded due to "
+                               "capability mismatch.\n",
+                               escape_essid(network->ssid, network->ssid_len),
+                               MAC_ARG(network->bssid));
+               return 0;
+       }
+
+       /* If we do not have an ESSID for this AP, we can not associate with
+        * it */
+       if (network->flags & NETWORK_EMPTY_ESSID) {
+               IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+                               "because of hidden ESSID.\n",
+                               escape_essid(network->ssid, network->ssid_len),
+                               MAC_ARG(network->bssid));
+               return 0;
+       }
+
+       if (unlikely(roaming)) {
+               /* If we are roaming, then ensure check if this is a valid
+                * network to try and roam to */
+               if ((network->ssid_len != match->network->ssid_len) ||
+                   memcmp(network->ssid, match->network->ssid,
+                          network->ssid_len)) {
+                       IPW_DEBUG_ASSOC("Netowrk '%s (" MAC_FMT ")' excluded "
+                                       "because of non-network ESSID.\n",
+                                       escape_essid(network->ssid,
+                                                    network->ssid_len),
+                                       MAC_ARG(network->bssid));
+                       return 0;
+               }
+       } else {
+               /* If an ESSID has been configured then compare the broadcast
+                * ESSID to ours */
+               if ((priv->config & CFG_STATIC_ESSID) &&
+                   ((network->ssid_len != priv->essid_len) ||
+                    memcmp(network->ssid, priv->essid,
+                           min(network->ssid_len, priv->essid_len)))) {
+                       char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+                       strncpy(escaped,
+                               escape_essid(network->ssid, network->ssid_len),
+                               sizeof(escaped));
+                       IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+                                       "because of ESSID mismatch: '%s'.\n",
+                                       escaped, MAC_ARG(network->bssid),
+                                       escape_essid(priv->essid,
+                                                    priv->essid_len));
+                       return 0;
+               }
+       }
+
+       /* If the old network rate is better than this one, don't bother
+        * testing everything else. */
+       if (match->network && match->network->stats.rssi > network->stats.rssi) {
+               char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+               strncpy(escaped,
+                       escape_essid(network->ssid, network->ssid_len),
+                       sizeof(escaped));
+               IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded because "
+                               "'%s (" MAC_FMT ")' has a stronger signal.\n",
+                               escaped, MAC_ARG(network->bssid),
+                               escape_essid(match->network->ssid,
+                                            match->network->ssid_len),
+                               MAC_ARG(match->network->bssid));
+               return 0;
+       }
+
+       /* If this network has already had an association attempt within the
+        * last 3 seconds, do not try and associate again... */
+       if (network->last_associate &&
+           time_after(network->last_associate + (HZ * 5UL), jiffies)) {
+               IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+                               "because of storming (%lu since last "
+                               "assoc attempt).\n",
+                               escape_essid(network->ssid, network->ssid_len),
+                               MAC_ARG(network->bssid),
+                               (jiffies - network->last_associate) / HZ);
+               return 0;
+       }
+
+       /* Now go through and see if the requested network is valid... */
+       if (priv->ieee->scan_age != 0 &&
+           jiffies - network->last_scanned > priv->ieee->scan_age) {
+               IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+                               "because of age: %lums.\n",
+                               escape_essid(network->ssid, network->ssid_len),
+                               MAC_ARG(network->bssid),
+                               (jiffies - network->last_scanned) / (HZ / 100));
+               return 0;
+       }
+
+       if ((priv->config & CFG_STATIC_CHANNEL) &&
+           (network->channel != priv->channel)) {
+               IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+                               "because of channel mismatch: %d != %d.\n",
+                               escape_essid(network->ssid, network->ssid_len),
+                               MAC_ARG(network->bssid),
+                               network->channel, priv->channel);
+               return 0;
+       }
+
+       /* Verify privacy compatability */
+       if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
+           ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
+               IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+                               "because of privacy mismatch: %s != %s.\n",
+                               escape_essid(network->ssid, network->ssid_len),
+                               MAC_ARG(network->bssid),
+                               priv->capability & CAP_PRIVACY_ON ? "on" :
+                               "off",
+                               network->capability &
+                               WLAN_CAPABILITY_PRIVACY ? "on" : "off");
+               return 0;
+       }
+
+       if ((priv->config & CFG_STATIC_BSSID) &&
+           memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
+               IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+                               "because of BSSID mismatch: " MAC_FMT ".\n",
+                               escape_essid(network->ssid, network->ssid_len),
+                               MAC_ARG(network->bssid), MAC_ARG(priv->bssid));
+               return 0;
+       }
+
+       /* Filter out any incompatible freq / mode combinations */
+       if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) {
+               IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+                               "because of invalid frequency/mode "
+                               "combination.\n",
+                               escape_essid(network->ssid, network->ssid_len),
+                               MAC_ARG(network->bssid));
+               return 0;
+       }
+
+       ipw_compatible_rates(priv, network, &rates);
+       if (rates.num_rates == 0) {
+               IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+                               "because of no compatible rates.\n",
+                               escape_essid(network->ssid, network->ssid_len),
+                               MAC_ARG(network->bssid));
+               return 0;
+       }
+
+       /* TODO: Perform any further minimal comparititive tests.  We do not
+        * want to put too much policy logic here; intelligent scan selection
+        * should occur within a generic IEEE 802.11 user space tool.  */
+
+       /* Set up 'new' AP to this network */
+       ipw_copy_rates(&match->rates, &rates);
+       match->network = network;
+
+       IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' is a viable match.\n",
+                       escape_essid(network->ssid, network->ssid_len),
+                       MAC_ARG(network->bssid));
+
+       return 1;
+}
+
+static void ipw_adhoc_create(struct ipw_priv *priv,
+                            struct ieee80211_network *network)
+{
+       /*
+        * For the purposes of scanning, we can set our wireless mode
+        * to trigger scans across combinations of bands, but when it
+        * comes to creating a new ad-hoc network, we have tell the FW
+        * exactly which band to use.
+        *
+        * We also have the possibility of an invalid channel for the
+        * chossen band.  Attempting to create a new ad-hoc network
+        * with an invalid channel for wireless mode will trigger a
+        * FW fatal error.
+        */
+       network->mode = is_valid_channel(priv->ieee->mode, priv->channel);
+       if (network->mode) {
+               network->channel = priv->channel;
+       } else {
+               IPW_WARNING("Overriding invalid channel\n");
+               if (priv->ieee->mode & IEEE_A) {
+                       network->mode = IEEE_A;
+                       priv->channel = band_a_active_channel[0];
+               } else if (priv->ieee->mode & IEEE_G) {
+                       network->mode = IEEE_G;
+                       priv->channel = band_b_active_channel[0];
+               } else {
+                       network->mode = IEEE_B;
+                       priv->channel = band_b_active_channel[0];
+               }
+       }
+
+       network->channel = priv->channel;
+       priv->config |= CFG_ADHOC_PERSIST;
+       ipw_create_bssid(priv, network->bssid);
+       network->ssid_len = priv->essid_len;
+       memcpy(network->ssid, priv->essid, priv->essid_len);
+       memset(&network->stats, 0, sizeof(network->stats));
+       network->capability = WLAN_CAPABILITY_IBSS;
+       if (priv->capability & CAP_PRIVACY_ON)
+               network->capability |= WLAN_CAPABILITY_PRIVACY;
+       network->rates_len = min(priv->rates.num_rates, MAX_RATES_LENGTH);
+       memcpy(network->rates, priv->rates.supported_rates, network->rates_len);
+       network->rates_ex_len = priv->rates.num_rates - network->rates_len;
+       memcpy(network->rates_ex,
+              &priv->rates.supported_rates[network->rates_len],
+              network->rates_ex_len);
+       network->last_scanned = 0;
+       network->flags = 0;
+       network->last_associate = 0;
+       network->time_stamp[0] = 0;
+       network->time_stamp[1] = 0;
+       network->beacon_interval = 100; /* Default */
+       network->listen_interval = 10;  /* Default */
+       network->atim_window = 0;       /* Default */
+#ifdef CONFIG_IEEE80211_WPA
+       network->wpa_ie_len = 0;
+       network->rsn_ie_len = 0;
+#endif                         /* CONFIG_IEEE80211_WPA */
+}
+
+static void ipw_send_wep_keys(struct ipw_priv *priv)
+{
+       struct ipw_wep_key *key;
+       int i;
+       struct host_cmd cmd = {
+               .cmd = IPW_CMD_WEP_KEY,
+               .len = sizeof(*key)
+       };
+
+       key = (struct ipw_wep_key *)&cmd.param;
+       key->cmd_id = DINO_CMD_WEP_KEY;
+       key->seq_num = 0;
+
+       for (i = 0; i < 4; i++) {
+               key->key_index = i;
+               if (!(priv->sec.flags & (1 << i))) {
+                       key->key_size = 0;
+               } else {
+                       key->key_size = priv->sec.key_sizes[i];
+                       memcpy(key->key, priv->sec.keys[i], key->key_size);
+               }
+
+               if (ipw_send_cmd(priv, &cmd)) {
+                       IPW_ERROR("failed to send WEP_KEY command\n");
+                       return;
+               }
+       }
+}
+
+static void ipw_adhoc_check(void *data)
+{
+       struct ipw_priv *priv = data;
+
+       if (priv->missed_adhoc_beacons++ > priv->missed_beacon_threshold &&
+           !(priv->config & CFG_ADHOC_PERSIST)) {
+               IPW_DEBUG_SCAN("Disassociating due to missed beacons\n");
+               ipw_remove_current_network(priv);
+               ipw_disassociate(priv);
+               return;
+       }
+
+       queue_delayed_work(priv->workqueue, &priv->adhoc_check,
+                          priv->assoc_request.beacon_interval);
+}
+
+#ifdef CONFIG_IPW_DEBUG
+static void ipw_debug_config(struct ipw_priv *priv)
+{
+       IPW_DEBUG_INFO("Scan completed, no valid APs matched "
+                      "[CFG 0x%08X]\n", priv->config);
+       if (priv->config & CFG_STATIC_CHANNEL)
+               IPW_DEBUG_INFO("Channel locked to %d\n", priv->channel);
+       else
+               IPW_DEBUG_INFO("Channel unlocked.\n");
+       if (priv->config & CFG_STATIC_ESSID)
+               IPW_DEBUG_INFO("ESSID locked to '%s'\n",
+                              escape_essid(priv->essid, priv->essid_len));
+       else
+               IPW_DEBUG_INFO("ESSID unlocked.\n");
+       if (priv->config & CFG_STATIC_BSSID)
+               IPW_DEBUG_INFO("BSSID locked to %d\n", priv->channel);
+       else
+               IPW_DEBUG_INFO("BSSID unlocked.\n");
+       if (priv->capability & CAP_PRIVACY_ON)
+               IPW_DEBUG_INFO("PRIVACY on\n");
+       else
+               IPW_DEBUG_INFO("PRIVACY off\n");
+       IPW_DEBUG_INFO("RATE MASK: 0x%08X\n", priv->rates_mask);
+}
+#else
+#define ipw_debug_config(x) do {} while (0)
+#endif
+
+static inline void ipw_set_fixed_rate(struct ipw_priv *priv,
+                                     struct ieee80211_network *network)
+{
+       /* TODO: Verify that this works... */
+       struct ipw_fixed_rate fr = {
+               .tx_rates = priv->rates_mask
+       };
+       u32 reg;
+       u16 mask = 0;
+
+       /* Identify 'current FW band' and match it with the fixed
+        * Tx rates */
+
+       switch (priv->ieee->freq_band) {
+       case IEEE80211_52GHZ_BAND:      /* A only */
+               /* IEEE_A */
+               if (priv->rates_mask & ~IEEE80211_OFDM_RATES_MASK) {
+                       /* Invalid fixed rate mask */
+                       fr.tx_rates = 0;
+                       break;
+               }
+
+               fr.tx_rates >>= IEEE80211_OFDM_SHIFT_MASK_A;
+               break;
+
+       default:                /* 2.4Ghz or Mixed */
+               /* IEEE_B */
+               if (network->mode == IEEE_B) {
+                       if (fr.tx_rates & ~IEEE80211_CCK_RATES_MASK) {
+                               /* Invalid fixed rate mask */
+                               fr.tx_rates = 0;
+                       }
+                       break;
+               }
+
+               /* IEEE_G */
+               if (fr.tx_rates & ~(IEEE80211_CCK_RATES_MASK |
+                                   IEEE80211_OFDM_RATES_MASK)) {
+                       /* Invalid fixed rate mask */
+                       fr.tx_rates = 0;
+                       break;
+               }
+
+               if (IEEE80211_OFDM_RATE_6MB_MASK & fr.tx_rates) {
+                       mask |= (IEEE80211_OFDM_RATE_6MB_MASK >> 1);
+                       fr.tx_rates &= ~IEEE80211_OFDM_RATE_6MB_MASK;
+               }
+
+               if (IEEE80211_OFDM_RATE_9MB_MASK & fr.tx_rates) {
+                       mask |= (IEEE80211_OFDM_RATE_9MB_MASK >> 1);
+                       fr.tx_rates &= ~IEEE80211_OFDM_RATE_9MB_MASK;
+               }
+
+               if (IEEE80211_OFDM_RATE_12MB_MASK & fr.tx_rates) {
+                       mask |= (IEEE80211_OFDM_RATE_12MB_MASK >> 1);
+                       fr.tx_rates &= ~IEEE80211_OFDM_RATE_12MB_MASK;
+               }
+
+               fr.tx_rates |= mask;
+               break;
+       }
+
+       reg = ipw_read32(priv, IPW_MEM_FIXED_OVERRIDE);
+       ipw_write_reg32(priv, reg, *(u32 *) & fr);
+}
+
+static int ipw_associate_network(struct ipw_priv *priv,
+                                struct ieee80211_network *network,
+                                struct ipw_supported_rates *rates, int roaming)
+{
+       int err;
+
+       if (priv->config & CFG_FIXED_RATE)
+               ipw_set_fixed_rate(priv, network);
+
+       if (!(priv->config & CFG_STATIC_ESSID)) {
+               priv->essid_len = min(network->ssid_len,
+                                     (u8) IW_ESSID_MAX_SIZE);
+               memcpy(priv->essid, network->ssid, priv->essid_len);
+       }
+
+       network->last_associate = jiffies;
+
+       memset(&priv->assoc_request, 0, sizeof(priv->assoc_request));
+       priv->assoc_request.channel = network->channel;
+       if ((priv->capability & CAP_PRIVACY_ON) &&
+           (priv->capability & CAP_SHARED_KEY)) {
+               priv->assoc_request.auth_type = AUTH_SHARED_KEY;
+               priv->assoc_request.auth_key = priv->sec.active_key;
+       } else {
+               priv->assoc_request.auth_type = AUTH_OPEN;
+               priv->assoc_request.auth_key = 0;
+       }
+
+       if (priv->capability & CAP_PRIVACY_ON)
+               ipw_send_wep_keys(priv);
+
+       /*
+        * It is valid for our ieee device to support multiple modes, but
+        * when it comes to associating to a given network we have to choose
+        * just one mode.
+        */
+       if (network->mode & priv->ieee->mode & IEEE_A)
+               priv->assoc_request.ieee_mode = IPW_A_MODE;
+       else if (network->mode & priv->ieee->mode & IEEE_G)
+               priv->assoc_request.ieee_mode = IPW_G_MODE;
+       else if (network->mode & priv->ieee->mode & IEEE_B)
+               priv->assoc_request.ieee_mode = IPW_B_MODE;
+
+       IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, "
+                       "802.11%c [%d], enc=%s%s%s%c%c\n",
+                       roaming ? "Rea" : "A",
+                       escape_essid(priv->essid, priv->essid_len),
+                       network->channel,
+                       ipw_modes[priv->assoc_request.ieee_mode],
+                       rates->num_rates,
+                       priv->capability & CAP_PRIVACY_ON ? "on " : "off",
+                       priv->capability & CAP_PRIVACY_ON ?
+                       (priv->capability & CAP_SHARED_KEY ? "(shared)" :
+                        "(open)") : "",
+                       priv->capability & CAP_PRIVACY_ON ? " key=" : "",
+                       priv->capability & CAP_PRIVACY_ON ?
+                       '1' + priv->sec.active_key : '.',
+                       priv->capability & CAP_PRIVACY_ON ? '.' : ' ');
+
+       priv->assoc_request.beacon_interval = network->beacon_interval;
+       if ((priv->ieee->iw_mode == IW_MODE_ADHOC) &&
+           (network->time_stamp[0] == 0) && (network->time_stamp[1] == 0)) {
+               priv->assoc_request.assoc_type = HC_IBSS_START;
+               priv->assoc_request.assoc_tsf_msw = 0;
+               priv->assoc_request.assoc_tsf_lsw = 0;
+       } else {
+               if (unlikely(roaming))
+                       priv->assoc_request.assoc_type = HC_REASSOCIATE;
+               else
+                       priv->assoc_request.assoc_type = HC_ASSOCIATE;
+               priv->assoc_request.assoc_tsf_msw = network->time_stamp[1];
+               priv->assoc_request.assoc_tsf_lsw = network->time_stamp[0];
+       }
+
+       memcpy(&priv->assoc_request.bssid, network->bssid, ETH_ALEN);
+
+       if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+               memset(&priv->assoc_request.dest, 0xFF, ETH_ALEN);
+               priv->assoc_request.atim_window = network->atim_window;
+       } else {
+               memcpy(&priv->assoc_request.dest, network->bssid, ETH_ALEN);
+               priv->assoc_request.atim_window = 0;
+       }
+
+       priv->assoc_request.capability = network->capability;
+       priv->assoc_request.listen_interval = network->listen_interval;
+
+       err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
+       if (err) {
+               IPW_DEBUG_HC("Attempt to send SSID command failed.\n");
+               return err;
+       }
+
+       rates->ieee_mode = priv->assoc_request.ieee_mode;
+       rates->purpose = IPW_RATE_CONNECT;
+       ipw_send_supported_rates(priv, rates);
+
+       if (priv->assoc_request.ieee_mode == IPW_G_MODE)
+               priv->sys_config.dot11g_auto_detection = 1;
+       else
+               priv->sys_config.dot11g_auto_detection = 0;
+       err = ipw_send_system_config(priv, &priv->sys_config);
+       if (err) {
+               IPW_DEBUG_HC("Attempt to send sys config command failed.\n");
+               return err;
+       }
+
+       IPW_DEBUG_ASSOC("Association sensitivity: %d\n", network->stats.rssi);
+       err = ipw_set_sensitivity(priv, network->stats.rssi);
+       if (err) {
+               IPW_DEBUG_HC("Attempt to send associate command failed.\n");
+               return err;
+       }
+
+       /*
+        * If preemption is enabled, it is possible for the association
+        * to complete before we return from ipw_send_associate.  Therefore
+        * we have to be sure and update our priviate data first.
+        */
+       priv->channel = network->channel;
+       memcpy(priv->bssid, network->bssid, ETH_ALEN);
+       priv->status |= STATUS_ASSOCIATING;
+       priv->status &= ~STATUS_SECURITY_UPDATED;
+
+       priv->assoc_network = network;
+
+       err = ipw_send_associate(priv, &priv->assoc_request);
+       if (err) {
+               IPW_DEBUG_HC("Attempt to send associate command failed.\n");
+               return err;
+       }
+
+       IPW_DEBUG(IPW_DL_STATE, "associating: '%s' " MAC_FMT " \n",
+                 escape_essid(priv->essid, priv->essid_len),
+                 MAC_ARG(priv->bssid));
+
+       return 0;
+}
+
+static void ipw_roam(void *data)
+{
+       struct ipw_priv *priv = data;
+       struct ieee80211_network *network = NULL;
+       struct ipw_network_match match = {
+               .network = priv->assoc_network
+       };
+
+       /* The roaming process is as follows:
+        *
+        * 1.  Missed beacon threshold triggers the roaming process by
+        *     setting the status ROAM bit and requesting a scan.
+        * 2.  When the scan completes, it schedules the ROAM work
+        * 3.  The ROAM work looks at all of the known networks for one that
+        *     is a better network than the currently associated.  If none
+        *     found, the ROAM process is over (ROAM bit cleared)
+        * 4.  If a better network is found, a disassociation request is
+        *     sent.
+        * 5.  When the disassociation completes, the roam work is again
+        *     scheduled.  The second time through, the driver is no longer
+        *     associated, and the newly selected network is sent an
+        *     association request.
+        * 6.  At this point ,the roaming process is complete and the ROAM
+        *     status bit is cleared.
+        */
+
+       /* If we are no longer associated, and the roaming bit is no longer
+        * set, then we are not actively roaming, so just return */
+       if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ROAMING)))
+               return;
+
+       if (priv->status & STATUS_ASSOCIATED) {
+               /* First pass through ROAM process -- look for a better
+                * network */
+               u8 rssi = priv->assoc_network->stats.rssi;
+               priv->assoc_network->stats.rssi = -128;
+               list_for_each_entry(network, &priv->ieee->network_list, list) {
+                       if (network != priv->assoc_network)
+                               ipw_best_network(priv, &match, network, 1);
+               }
+               priv->assoc_network->stats.rssi = rssi;
+
+               if (match.network == priv->assoc_network) {
+                       IPW_DEBUG_ASSOC("No better APs in this network to "
+                                       "roam to.\n");
+                       priv->status &= ~STATUS_ROAMING;
+                       ipw_debug_config(priv);
+                       return;
+               }
+
+               ipw_send_disassociate(priv, 1);
+               priv->assoc_network = match.network;
+
+               return;
+       }
+
+       /* Second pass through ROAM process -- request association */
+       ipw_compatible_rates(priv, priv->assoc_network, &match.rates);
+       ipw_associate_network(priv, priv->assoc_network, &match.rates, 1);
+       priv->status &= ~STATUS_ROAMING;
+}
+
+static void ipw_associate(void *data)
+{
+       struct ipw_priv *priv = data;
+
+       struct ieee80211_network *network = NULL;
+       struct ipw_network_match match = {
+               .network = NULL
+       };
+       struct ipw_supported_rates *rates;
+       struct list_head *element;
+
+       if (!(priv->config & CFG_ASSOCIATE) &&
+           !(priv->config & (CFG_STATIC_ESSID |
+                             CFG_STATIC_CHANNEL | CFG_STATIC_BSSID))) {
+               IPW_DEBUG_ASSOC("Not attempting association (associate=0)\n");
+               return;
+       }
+
+       list_for_each_entry(network, &priv->ieee->network_list, list)
+           ipw_best_network(priv, &match, network, 0);
+
+       network = match.network;
+       rates = &match.rates;
+
+       if (network == NULL &&
+           priv->ieee->iw_mode == IW_MODE_ADHOC &&
+           priv->config & CFG_ADHOC_CREATE &&
+           priv->config & CFG_STATIC_ESSID &&
+           !list_empty(&priv->ieee->network_free_list)) {
+               element = priv->ieee->network_free_list.next;
+               network = list_entry(element, struct ieee80211_network, list);
+               ipw_adhoc_create(priv, network);
+               rates = &priv->rates;
+               list_del(element);
+               list_add_tail(&network->list, &priv->ieee->network_list);
+       }
+
+       /* If we reached the end of the list, then we don't have any valid
+        * matching APs */
+       if (!network) {
+               ipw_debug_config(priv);
+
+               queue_delayed_work(priv->workqueue, &priv->request_scan,
+                                  SCAN_INTERVAL);
+
+               return;
+       }
+
+       ipw_associate_network(priv, network, rates, 0);
+}
+
+static inline void ipw_handle_data_packet(struct ipw_priv *priv,
+                                         struct ipw_rx_mem_buffer *rxb,
+                                         struct ieee80211_rx_stats *stats)
+{
+       struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
+
+       /* We received data from the HW, so stop the watchdog */
+       priv->net_dev->trans_start = jiffies;
+
+       /* We only process data packets if the
+        * interface is open */
+       if (unlikely((pkt->u.frame.length + IPW_RX_FRAME_SIZE) >
+                    skb_tailroom(rxb->skb))) {
+               priv->ieee->stats.rx_errors++;
+               priv->wstats.discard.misc++;
+               IPW_DEBUG_DROP("Corruption detected! Oh no!\n");
+               return;
+       } else if (unlikely(!netif_running(priv->net_dev))) {
+               priv->ieee->stats.rx_dropped++;
+               priv->wstats.discard.misc++;
+               IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
+               return;
+       }
+
+       /* Advance skb->data to the start of the actual payload */
+       skb_reserve(rxb->skb, offsetof(struct ipw_rx_packet, u.frame.data));
+
+       /* Set the size of the skb to the size of the frame */
+       skb_put(rxb->skb, pkt->u.frame.length);
+
+       IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
+
+       if (!ieee80211_rx(priv->ieee, rxb->skb, stats))
+               priv->ieee->stats.rx_errors++;
+       else                    /* ieee80211_rx succeeded, so it now owns the SKB */
+               rxb->skb = NULL;
+}
+
+/*
+ * Main entry function for recieving a packet with 80211 headers.  This
+ * should be called when ever the FW has notified us that there is a new
+ * skb in the recieve queue.
+ */
+static void ipw_rx(struct ipw_priv *priv)
+{
+       struct ipw_rx_mem_buffer *rxb;
+       struct ipw_rx_packet *pkt;
+       struct ieee80211_hdr *header;
+       u32 r, w, i;
+       u8 network_packet;
+
+       r = ipw_read32(priv, CX2_RX_READ_INDEX);
+       w = ipw_read32(priv, CX2_RX_WRITE_INDEX);
+       i = (priv->rxq->processed + 1) % RX_QUEUE_SIZE;
+
+       while (i != r) {
+               rxb = priv->rxq->queue[i];
+#ifdef CONFIG_IPW_DEBUG
+               if (unlikely(rxb == NULL)) {
+                       printk(KERN_CRIT "Queue not allocated!\n");
+                       break;
+               }
+#endif
+               priv->rxq->queue[i] = NULL;
+
+               pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
+                                           CX2_RX_BUF_SIZE,
+                                           PCI_DMA_FROMDEVICE);
+
+               pkt = (struct ipw_rx_packet *)rxb->skb->data;
+               IPW_DEBUG_RX("Packet: type=%02X seq=%02X bits=%02X\n",
+                            pkt->header.message_type,
+                            pkt->header.rx_seq_num, pkt->header.control_bits);
+
+               switch (pkt->header.message_type) {
+               case RX_FRAME_TYPE:     /* 802.11 frame */  {
+                               struct ieee80211_rx_stats stats = {
+                                       .rssi = pkt->u.frame.rssi_dbm -
+                                           IPW_RSSI_TO_DBM,
+                                       .signal = pkt->u.frame.signal,
+                                       .rate = pkt->u.frame.rate,
+                                       .mac_time = jiffies,
+                                       .received_channel =
+                                           pkt->u.frame.received_channel,
+                                       .freq =
+                                           (pkt->u.frame.
+                                            control & (1 << 0)) ?
+                                           IEEE80211_24GHZ_BAND :
+                                           IEEE80211_52GHZ_BAND,
+                                       .len = pkt->u.frame.length,
+                               };
+
+                               if (stats.rssi != 0)
+                                       stats.mask |= IEEE80211_STATMASK_RSSI;
+                               if (stats.signal != 0)
+                                       stats.mask |= IEEE80211_STATMASK_SIGNAL;
+                               if (stats.rate != 0)
+                                       stats.mask |= IEEE80211_STATMASK_RATE;
+
+                               priv->rx_packets++;
+
+#ifdef CONFIG_IPW_PROMISC
+                               if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+                                       ipw_handle_data_packet(priv, rxb,
+                                                              &stats);
+                                       break;
+                               }
+#endif
+
+                               header =
+                                   (struct ieee80211_hdr *)(rxb->skb->data +
+                                                            IPW_RX_FRAME_SIZE);
+                               /* TODO: Check Ad-Hoc dest/source and make sure
+                                * that we are actually parsing these packets
+                                * correctly -- we should probably use the
+                                * frame control of the packet and disregard
+                                * the current iw_mode */
+                               switch (priv->ieee->iw_mode) {
+                               case IW_MODE_ADHOC:
+                                       network_packet =
+                                           !memcmp(header->addr1,
+                                                   priv->net_dev->dev_addr,
+                                                   ETH_ALEN) ||
+                                           !memcmp(header->addr3,
+                                                   priv->bssid, ETH_ALEN) ||
+                                           is_broadcast_ether_addr(header->
+                                                                   addr1)
+                                           || is_multicast_ether_addr(header->
+                                                                      addr1);
+                                       break;
+
+                               case IW_MODE_INFRA:
+                               default:
+                                       network_packet =
+                                           !memcmp(header->addr3,
+                                                   priv->bssid, ETH_ALEN) ||
+                                           !memcmp(header->addr1,
+                                                   priv->net_dev->dev_addr,
+                                                   ETH_ALEN) ||
+                                           is_broadcast_ether_addr(header->
+                                                                   addr1)
+                                           || is_multicast_ether_addr(header->
+                                                                      addr1);
+                                       break;
+                               }
+
+                               if (network_packet && priv->assoc_network) {
+                                       priv->assoc_network->stats.rssi =
+                                           stats.rssi;
+                                       average_add(&priv->average_rssi,
+                                                   stats.rssi);
+                                       priv->last_rx_rssi = stats.rssi;
+                               }
+
+                               IPW_DEBUG_RX("Frame: len=%u\n",
+                                            pkt->u.frame.length);
+
+                               if (pkt->u.frame.length < frame_hdr_len(header)) {
+                                       IPW_DEBUG_DROP
+                                           ("Received packet is too small. "
+                                            "Dropping.\n");
+                                       priv->ieee->stats.rx_errors++;
+                                       priv->wstats.discard.misc++;
+                                       break;
+                               }
+
+                               switch (WLAN_FC_GET_TYPE(header->frame_ctl)) {
+                               case IEEE80211_FTYPE_MGMT:
+                                       ieee80211_rx_mgt(priv->ieee, header,
+                                                        &stats);
+                                       if (priv->ieee->iw_mode == IW_MODE_ADHOC
+                                           &&
+                                           ((WLAN_FC_GET_STYPE
+                                             (header->frame_ctl) ==
+                                             IEEE80211_STYPE_PROBE_RESP)
+                                            ||
+                                            (WLAN_FC_GET_STYPE
+                                             (header->frame_ctl) ==
+                                             IEEE80211_STYPE_BEACON))
+                                           && !memcmp(header->addr3,
+                                                      priv->bssid, ETH_ALEN))
+                                               ipw_add_station(priv,
+                                                               header->addr2);
+                                       break;
+
+                               case IEEE80211_FTYPE_CTL:
+                                       break;
+
+                               case IEEE80211_FTYPE_DATA:
+                                       if (network_packet)
+                                               ipw_handle_data_packet(priv,
+                                                                      rxb,
+                                                                      &stats);
+                                       else
+                                               IPW_DEBUG_DROP("Dropping: "
+                                                              MAC_FMT ", "
+                                                              MAC_FMT ", "
+                                                              MAC_FMT "\n",
+                                                              MAC_ARG(header->
+                                                                      addr1),
+                                                              MAC_ARG(header->
+                                                                      addr2),
+                                                              MAC_ARG(header->
+                                                                      addr3));
+                                       break;
+                               }
+                               break;
+                       }
+
+               case RX_HOST_NOTIFICATION_TYPE:{
+                               IPW_DEBUG_RX
+                                   ("Notification: subtype=%02X flags=%02X size=%d\n",
+                                    pkt->u.notification.subtype,
+                                    pkt->u.notification.flags,
+                                    pkt->u.notification.size);
+                               ipw_rx_notification(priv, &pkt->u.notification);
+                               break;
+                       }
+
+               default:
+                       IPW_DEBUG_RX("Bad Rx packet of type %d\n",
+                                    pkt->header.message_type);
+                       break;
+               }
+
+               /* For now we just don't re-use anything.  We can tweak this
+                * later to try and re-use notification packets and SKBs that
+                * fail to Rx correctly */
+               if (rxb->skb != NULL) {
+                       dev_kfree_skb_any(rxb->skb);
+                       rxb->skb = NULL;
+               }
+
+               pci_unmap_single(priv->pci_dev, rxb->dma_addr,
+                                CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+               list_add_tail(&rxb->list, &priv->rxq->rx_used);
+
+               i = (i + 1) % RX_QUEUE_SIZE;
+       }
+
+       /* Backtrack one entry */
+       priv->rxq->processed = (i ? i : RX_QUEUE_SIZE) - 1;
+
+       ipw_rx_queue_restock(priv);
+}
+
+static void ipw_abort_scan(struct ipw_priv *priv)
+{
+       int err;
+
+       if (priv->status & STATUS_SCAN_ABORTING) {
+               IPW_DEBUG_HC("Ignoring concurrent scan abort request.\n");
+               return;
+       }
+       priv->status |= STATUS_SCAN_ABORTING;
+
+       err = ipw_send_scan_abort(priv);
+       if (err)
+               IPW_DEBUG_HC("Request to abort scan failed.\n");
+}
+
+static int ipw_request_scan(struct ipw_priv *priv)
+{
+       struct ipw_scan_request_ext scan;
+       int channel_index = 0;
+       int i, err, scan_type;
+
+       if (priv->status & STATUS_EXIT_PENDING) {
+               IPW_DEBUG_SCAN("Aborting scan due to device shutdown\n");
+               priv->status |= STATUS_SCAN_PENDING;
+               return 0;
+       }
+
+       if (priv->status & STATUS_SCANNING) {
+               IPW_DEBUG_HC("Concurrent scan requested.  Aborting first.\n");
+               priv->status |= STATUS_SCAN_PENDING;
+               ipw_abort_scan(priv);
+               return 0;
+       }
+
+       if (priv->status & STATUS_SCAN_ABORTING) {
+               IPW_DEBUG_HC("Scan request while abort pending.  Queuing.\n");
+               priv->status |= STATUS_SCAN_PENDING;
+               return 0;
+       }
+
+       if (priv->status & STATUS_RF_KILL_MASK) {
+               IPW_DEBUG_HC("Aborting scan due to RF Kill activation\n");
+               priv->status |= STATUS_SCAN_PENDING;
+               return 0;
+       }
+
+       memset(&scan, 0, sizeof(scan));
+
+       scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = 20;
+       scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = 20;
+       scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = 20;
+
+       scan.full_scan_index = ieee80211_get_scans(priv->ieee);
+       /* If we are roaming, then make this a directed scan for the current
+        * network.  Otherwise, ensure that every other scan is a fast
+        * channel hop scan */
+       if ((priv->status & STATUS_ROAMING)
+           || (!(priv->status & STATUS_ASSOCIATED)
+               && (priv->config & CFG_STATIC_ESSID)
+               && (scan.full_scan_index % 2))) {
+               err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
+               if (err) {
+                       IPW_DEBUG_HC("Attempt to send SSID command failed.\n");
+                       return err;
+               }
+
+               scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN;
+       } else {
+               scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN;
+       }
+
+       if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) {
+               int start = channel_index;
+               for (i = 0; i < MAX_A_CHANNELS; i++) {
+                       if (band_a_active_channel[i] == 0)
+                               break;
+                       if ((priv->status & STATUS_ASSOCIATED) &&
+                           band_a_active_channel[i] == priv->channel)
+                               continue;
+                       channel_index++;
+                       scan.channels_list[channel_index] =
+                           band_a_active_channel[i];
+                       ipw_set_scan_type(&scan, channel_index, scan_type);
+               }
+
+               if (start != channel_index) {
+                       scan.channels_list[start] = (u8) (IPW_A_MODE << 6) |
+                           (channel_index - start);
+                       channel_index++;
+               }
+       }
+
+       if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) {
+               int start = channel_index;
+               for (i = 0; i < MAX_B_CHANNELS; i++) {
+                       if (band_b_active_channel[i] == 0)
+                               break;
+                       if ((priv->status & STATUS_ASSOCIATED) &&
+                           band_b_active_channel[i] == priv->channel)
+                               continue;
+                       channel_index++;
+                       scan.channels_list[channel_index] =
+                           band_b_active_channel[i];
+                       ipw_set_scan_type(&scan, channel_index, scan_type);
+               }
+
+               if (start != channel_index) {
+                       scan.channels_list[start] = (u8) (IPW_B_MODE << 6) |
+                           (channel_index - start);
+               }
+       }
+
+       err = ipw_send_scan_request_ext(priv, &scan);
+       if (err) {
+               IPW_DEBUG_HC("Sending scan command failed: %08X\n", err);
+               return -EIO;
+       }
+
+       priv->status |= STATUS_SCANNING;
+       priv->status &= ~STATUS_SCAN_PENDING;
+
+       return 0;
+}
+
+/*
+ * This file defines the Wireless Extension handlers.  It does not
+ * define any methods of hardware manipulation and relies on the
+ * functions defined in ipw_main to provide the HW interaction.
+ *
+ * The exception to this is the use of the ipw_get_ordinal()
+ * function used to poll the hardware vs. making unecessary calls.
+ *
+ */
+
+static int ipw_wx_get_name(struct net_device *dev,
+                          struct iw_request_info *info,
+                          union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       if (!(priv->status & STATUS_ASSOCIATED))
+               strcpy(wrqu->name, "unassociated");
+       else
+               snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c",
+                        ipw_modes[priv->assoc_request.ieee_mode]);
+       IPW_DEBUG_WX("Name: %s\n", wrqu->name);
+       return 0;
+}
+
+static int ipw_set_channel(struct ipw_priv *priv, u8 channel)
+{
+       if (channel == 0) {
+               IPW_DEBUG_INFO("Setting channel to ANY (0)\n");
+               priv->config &= ~CFG_STATIC_CHANNEL;
+               if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED |
+                                     STATUS_ASSOCIATING))) {
+                       IPW_DEBUG_ASSOC("Attempting to associate with new "
+                                       "parameters.\n");
+                       ipw_associate(priv);
+               }
+
+               return 0;
+       }
+
+       priv->config |= CFG_STATIC_CHANNEL;
+
+       if (priv->channel == channel) {
+               IPW_DEBUG_INFO("Request to set channel to current value (%d)\n",
+                              channel);
+               return 0;
+       }
+
+       IPW_DEBUG_INFO("Setting channel to %i\n", (int)channel);
+       priv->channel = channel;
+
+       /* If we are currently associated, or trying to associate
+        * then see if this is a new channel (causing us to disassociate) */
+       if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
+               IPW_DEBUG_ASSOC("Disassociating due to channel change.\n");
+               ipw_disassociate(priv);
+       } else {
+               ipw_associate(priv);
+       }
+
+       return 0;
+}
+
+static int ipw_wx_set_freq(struct net_device *dev,
+                          struct iw_request_info *info,
+                          union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       struct iw_freq *fwrq = &wrqu->freq;
+
+       /* if setting by freq convert to channel */
+       if (fwrq->e == 1) {
+               if ((fwrq->m >= (int)2.412e8 && fwrq->m <= (int)2.487e8)) {
+                       int f = fwrq->m / 100000;
+                       int c = 0;
+
+                       while ((c < REG_MAX_CHANNEL) &&
+                              (f != ipw_frequencies[c]))
+                               c++;
+
+                       /* hack to fall through */
+                       fwrq->e = 0;
+                       fwrq->m = c + 1;
+               }
+       }
+
+       if (fwrq->e > 0 || fwrq->m > 1000)
+               return -EOPNOTSUPP;
+
+       IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m);
+       return ipw_set_channel(priv, (u8) fwrq->m);
+
+       return 0;
+}
+
+static int ipw_wx_get_freq(struct net_device *dev,
+                          struct iw_request_info *info,
+                          union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+
+       wrqu->freq.e = 0;
+
+       /* If we are associated, trying to associate, or have a statically
+        * configured CHANNEL then return that; otherwise return ANY */
+       if (priv->config & CFG_STATIC_CHANNEL ||
+           priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED))
+               wrqu->freq.m = priv->channel;
+       else
+               wrqu->freq.m = 0;
+
+       IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel);
+       return 0;
+}
+
+static int ipw_wx_set_mode(struct net_device *dev,
+                          struct iw_request_info *info,
+                          union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       int err = 0;
+
+       IPW_DEBUG_WX("Set MODE: %d\n", wrqu->mode);
+
+       if (wrqu->mode == priv->ieee->iw_mode)
+               return 0;
+
+       switch (wrqu->mode) {
+#ifdef CONFIG_IPW_PROMISC
+       case IW_MODE_MONITOR:
+#endif
+       case IW_MODE_ADHOC:
+       case IW_MODE_INFRA:
+               break;
+       case IW_MODE_AUTO:
+               wrqu->mode = IW_MODE_INFRA;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+#ifdef CONFIG_IPW_PROMISC
+       if (priv->ieee->iw_mode == IW_MODE_MONITOR)
+               priv->net_dev->type = ARPHRD_ETHER;
+
+       if (wrqu->mode == IW_MODE_MONITOR)
+               priv->net_dev->type = ARPHRD_IEEE80211;
+#endif                         /* CONFIG_IPW_PROMISC */
+
+#ifdef CONFIG_PM
+       /* Free the existing firmware and reset the fw_loaded
+        * flag so ipw_load() will bring in the new firmawre */
+       if (fw_loaded) {
+               fw_loaded = 0;
+       }
+
+       release_firmware(bootfw);
+       release_firmware(ucode);
+       release_firmware(firmware);
+       bootfw = ucode = firmware = NULL;
+#endif
+
+       priv->ieee->iw_mode = wrqu->mode;
+       ipw_adapter_restart(priv);
+
+       return err;
+}
+
+static int ipw_wx_get_mode(struct net_device *dev,
+                          struct iw_request_info *info,
+                          union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+
+       wrqu->mode = priv->ieee->iw_mode;
+       IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode);
+
+       return 0;
+}
+
+#define DEFAULT_RTS_THRESHOLD     2304U
+#define MIN_RTS_THRESHOLD         1U
+#define MAX_RTS_THRESHOLD         2304U
+#define DEFAULT_BEACON_INTERVAL   100U
+#define        DEFAULT_SHORT_RETRY_LIMIT 7U
+#define        DEFAULT_LONG_RETRY_LIMIT  4U
+
+/* Values are in microsecond */
+static const s32 timeout_duration[] = {
+       350000,
+       250000,
+       75000,
+       37000,
+       25000,
+};
+
+static const s32 period_duration[] = {
+       400000,
+       700000,
+       1000000,
+       1000000,
+       1000000
+};
+
+static int ipw_wx_get_range(struct net_device *dev,
+                           struct iw_request_info *info,
+                           union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       struct iw_range *range = (struct iw_range *)extra;
+       u16 val;
+       int i;
+
+       wrqu->data.length = sizeof(*range);
+       memset(range, 0, sizeof(*range));
+
+       /* 54Mbs == ~27 Mb/s real (802.11g) */
+       range->throughput = 27 * 1000 * 1000;
+
+       range->max_qual.qual = 100;
+       /* TODO: Find real max RSSI and stick here */
+       range->max_qual.level = 0;
+       range->max_qual.noise = 0;
+       range->max_qual.updated = 7;    /* Updated all three */
+
+       range->avg_qual.qual = 70;
+       /* TODO: Find real 'good' to 'bad' threshol value for RSSI */
+       range->avg_qual.level = 0;      /* FIXME to real average level */
+       range->avg_qual.noise = 0;
+       range->avg_qual.updated = 7;    /* Updated all three */
+
+       range->num_bitrates = min(priv->rates.num_rates, (u8) IW_MAX_BITRATES);
+
+       for (i = 0; i < range->num_bitrates; i++)
+               range->bitrate[i] = (priv->rates.supported_rates[i] & 0x7F) *
+                   500000;
+
+       range->max_rts = DEFAULT_RTS_THRESHOLD;
+       range->min_frag = MIN_FRAG_THRESHOLD;
+       range->max_frag = MAX_FRAG_THRESHOLD;
+
+       range->encoding_size[0] = 5;
+       range->encoding_size[1] = 13;
+       range->num_encoding_sizes = 2;
+       range->max_encoding_tokens = WEP_KEYS;
+
+       /* Set the Wireless Extension versions */
+       range->we_version_compiled = WIRELESS_EXT;
+       range->we_version_source = 16;
+
+       range->num_channels = FREQ_COUNT;
+
+       val = 0;
+       for (i = 0; i < FREQ_COUNT; i++) {
+               range->freq[val].i = i + 1;
+               range->freq[val].m = ipw_frequencies[i] * 100000;
+               range->freq[val].e = 1;
+               val++;
+
+               if (val == IW_MAX_FREQUENCIES)
+                       break;
+       }
+       range->num_frequency = val;
+
+       IPW_DEBUG_WX("GET Range\n");
+       return 0;
+}
+
+static int ipw_wx_set_wap(struct net_device *dev,
+                         struct iw_request_info *info,
+                         union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+
+       static const unsigned char any[] = {
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+       };
+       static const unsigned char off[] = {
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+
+       if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
+               return -EINVAL;
+
+       if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) ||
+           !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) {
+               /* we disable mandatory BSSID association */
+               IPW_DEBUG_WX("Setting AP BSSID to ANY\n");
+               priv->config &= ~CFG_STATIC_BSSID;
+               if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED |
+                                     STATUS_ASSOCIATING))) {
+                       IPW_DEBUG_ASSOC("Attempting to associate with new "
+                                       "parameters.\n");
+                       ipw_associate(priv);
+               }
+
+               return 0;
+       }
+
+       priv->config |= CFG_STATIC_BSSID;
+       if (!memcmp(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN)) {
+               IPW_DEBUG_WX("BSSID set to current BSSID.\n");
+               return 0;
+       }
+
+       IPW_DEBUG_WX("Setting mandatory BSSID to " MAC_FMT "\n",
+                    MAC_ARG(wrqu->ap_addr.sa_data));
+
+       memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN);
+
+       /* If we are currently associated, or trying to associate
+        * then see if this is a new BSSID (causing us to disassociate) */
+       if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
+               IPW_DEBUG_ASSOC("Disassociating due to BSSID change.\n");
+               ipw_disassociate(priv);
+       } else {
+               ipw_associate(priv);
+       }
+
+       return 0;
+}
+
+static int ipw_wx_get_wap(struct net_device *dev,
+                         struct iw_request_info *info,
+                         union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       /* If we are associated, trying to associate, or have a statically
+        * configured BSSID then return that; otherwise return ANY */
+       if (priv->config & CFG_STATIC_BSSID ||
+           priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
+               wrqu->ap_addr.sa_family = ARPHRD_ETHER;
+               memcpy(wrqu->ap_addr.sa_data, &priv->bssid, ETH_ALEN);
+       } else
+               memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
+
+       IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n",
+                    MAC_ARG(wrqu->ap_addr.sa_data));
+       return 0;
+}
+
+static int ipw_wx_set_essid(struct net_device *dev,
+                           struct iw_request_info *info,
+                           union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       char *essid = "";       /* ANY */
+       int length = 0;
+
+       if (wrqu->essid.flags && wrqu->essid.length) {
+               length = wrqu->essid.length - 1;
+               essid = extra;
+       }
+       if (length == 0) {
+               IPW_DEBUG_WX("Setting ESSID to ANY\n");
+               priv->config &= ~CFG_STATIC_ESSID;
+               if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED |
+                                     STATUS_ASSOCIATING))) {
+                       IPW_DEBUG_ASSOC("Attempting to associate with new "
+                                       "parameters.\n");
+                       ipw_associate(priv);
+               }
+
+               return 0;
+       }
+
+       length = min(length, IW_ESSID_MAX_SIZE);
+
+       priv->config |= CFG_STATIC_ESSID;
+
+       if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) {
+               IPW_DEBUG_WX("ESSID set to current ESSID.\n");
+               return 0;
+       }
+
+       IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(essid, length),
+                    length);
+
+       priv->essid_len = length;
+       memcpy(priv->essid, essid, priv->essid_len);
+
+       /* If we are currently associated, or trying to associate
+        * then see if this is a new ESSID (causing us to disassociate) */
+       if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
+               IPW_DEBUG_ASSOC("Disassociating due to ESSID change.\n");
+               ipw_disassociate(priv);
+       } else {
+               ipw_associate(priv);
+       }
+
+       return 0;
+}
+
+static int ipw_wx_get_essid(struct net_device *dev,
+                           struct iw_request_info *info,
+                           union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+
+       /* If we are associated, trying to associate, or have a statically
+        * configured ESSID then return that; otherwise return ANY */
+       if (priv->config & CFG_STATIC_ESSID ||
+           priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
+               IPW_DEBUG_WX("Getting essid: '%s'\n",
+                            escape_essid(priv->essid, priv->essid_len));
+               memcpy(extra, priv->essid, priv->essid_len);
+               wrqu->essid.length = priv->essid_len;
+               wrqu->essid.flags = 1;  /* active */
+       } else {
+               IPW_DEBUG_WX("Getting essid: ANY\n");
+               wrqu->essid.length = 0;
+               wrqu->essid.flags = 0;  /* active */
+       }
+
+       return 0;
+}
+
+static int ipw_wx_set_nick(struct net_device *dev,
+                          struct iw_request_info *info,
+                          union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+
+       IPW_DEBUG_WX("Setting nick to '%s'\n", extra);
+       if (wrqu->data.length > IW_ESSID_MAX_SIZE)
+               return -E2BIG;
+
+       wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
+       memset(priv->nick, 0, sizeof(priv->nick));
+       memcpy(priv->nick, extra, wrqu->data.length);
+       IPW_DEBUG_TRACE("<<\n");
+       return 0;
+
+}
+
+static int ipw_wx_get_nick(struct net_device *dev,
+                          struct iw_request_info *info,
+                          union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       IPW_DEBUG_WX("Getting nick\n");
+       wrqu->data.length = strlen(priv->nick) + 1;
+       memcpy(extra, priv->nick, wrqu->data.length);
+       wrqu->data.flags = 1;   /* active */
+       return 0;
+}
+
+static int ipw_wx_set_rate(struct net_device *dev,
+                          struct iw_request_info *info,
+                          union iwreq_data *wrqu, char *extra)
+{
+       IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu);
+       return -EOPNOTSUPP;
+}
+
+static int ipw_wx_get_rate(struct net_device *dev,
+                          struct iw_request_info *info,
+                          union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       wrqu->bitrate.value = priv->last_rate;
+
+       IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value);
+       return 0;
+}
+
+static int ipw_wx_set_rts(struct net_device *dev,
+                         struct iw_request_info *info,
+                         union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+
+       if (wrqu->rts.disabled)
+               priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
+       else {
+               if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
+                   wrqu->rts.value > MAX_RTS_THRESHOLD)
+                       return -EINVAL;
+
+               priv->rts_threshold = wrqu->rts.value;
+       }
+
+       ipw_send_rts_threshold(priv, priv->rts_threshold);
+       IPW_DEBUG_WX("SET RTS Threshold -> %d \n", priv->rts_threshold);
+       return 0;
+}
+
+static int ipw_wx_get_rts(struct net_device *dev,
+                         struct iw_request_info *info,
+                         union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       wrqu->rts.value = priv->rts_threshold;
+       wrqu->rts.fixed = 0;    /* no auto select */
+       wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
+
+       IPW_DEBUG_WX("GET RTS Threshold -> %d \n", wrqu->rts.value);
+       return 0;
+}
+
+static int ipw_wx_set_txpow(struct net_device *dev,
+                           struct iw_request_info *info,
+                           union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       struct ipw_tx_power tx_power;
+       int i;
+
+       if (ipw_radio_kill_sw(priv, wrqu->power.disabled))
+               return -EINPROGRESS;
+
+       if (wrqu->power.flags != IW_TXPOW_DBM)
+               return -EINVAL;
+
+       if ((wrqu->power.value > 20) || (wrqu->power.value < -12))
+               return -EINVAL;
+
+       priv->tx_power = wrqu->power.value;
+
+       memset(&tx_power, 0, sizeof(tx_power));
+
+       /* configure device for 'G' band */
+       tx_power.ieee_mode = IPW_G_MODE;
+       tx_power.num_channels = 11;
+       for (i = 0; i < 11; i++) {
+               tx_power.channels_tx_power[i].channel_number = i + 1;
+               tx_power.channels_tx_power[i].tx_power = priv->tx_power;
+       }
+       if (ipw_send_tx_power(priv, &tx_power))
+               goto error;
+
+       /* configure device to also handle 'B' band */
+       tx_power.ieee_mode = IPW_B_MODE;
+       if (ipw_send_tx_power(priv, &tx_power))
+               goto error;
+
+       return 0;
+
+      error:
+       return -EIO;
+}
+
+static int ipw_wx_get_txpow(struct net_device *dev,
+                           struct iw_request_info *info,
+                           union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+
+       wrqu->power.value = priv->tx_power;
+       wrqu->power.fixed = 1;
+       wrqu->power.flags = IW_TXPOW_DBM;
+       wrqu->power.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
+
+       IPW_DEBUG_WX("GET TX Power -> %s %d \n",
+                    wrqu->power.disabled ? "ON" : "OFF", wrqu->power.value);
+
+       return 0;
+}
+
+static int ipw_wx_set_frag(struct net_device *dev,
+                          struct iw_request_info *info,
+                          union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+
+       if (wrqu->frag.disabled)
+               priv->ieee->fts = DEFAULT_FTS;
+       else {
+               if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
+                   wrqu->frag.value > MAX_FRAG_THRESHOLD)
+                       return -EINVAL;
+
+               priv->ieee->fts = wrqu->frag.value & ~0x1;
+       }
+
+       ipw_send_frag_threshold(priv, wrqu->frag.value);
+       IPW_DEBUG_WX("SET Frag Threshold -> %d \n", wrqu->frag.value);
+       return 0;
+}
+
+static int ipw_wx_get_frag(struct net_device *dev,
+                          struct iw_request_info *info,
+                          union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       wrqu->frag.value = priv->ieee->fts;
+       wrqu->frag.fixed = 0;   /* no auto select */
+       wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FTS);
+
+       IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value);
+
+       return 0;
+}
+
+static int ipw_wx_set_retry(struct net_device *dev,
+                           struct iw_request_info *info,
+                           union iwreq_data *wrqu, char *extra)
+{
+       IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu);
+       return -EOPNOTSUPP;
+}
+
+static int ipw_wx_get_retry(struct net_device *dev,
+                           struct iw_request_info *info,
+                           union iwreq_data *wrqu, char *extra)
+{
+       IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu);
+       return -EOPNOTSUPP;
+}
+
+static int ipw_wx_set_scan(struct net_device *dev,
+                          struct iw_request_info *info,
+                          union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       IPW_DEBUG_WX("Start scan\n");
+       if (ipw_request_scan(priv))
+               return -EIO;
+       return 0;
+}
+
+static int ipw_wx_get_scan(struct net_device *dev,
+                          struct iw_request_info *info,
+                          union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra);
+}
+
+static int ipw_wx_set_encode(struct net_device *dev,
+                            struct iw_request_info *info,
+                            union iwreq_data *wrqu, char *key)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       return ieee80211_wx_set_encode(priv->ieee, info, wrqu, key);
+}
+
+static int ipw_wx_get_encode(struct net_device *dev,
+                            struct iw_request_info *info,
+                            union iwreq_data *wrqu, char *key)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key);
+}
+
+static int ipw_wx_set_power(struct net_device *dev,
+                           struct iw_request_info *info,
+                           union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       int err;
+
+       if (wrqu->power.disabled) {
+               priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
+               err = ipw_send_power_mode(priv, IPW_POWER_MODE_CAM);
+               if (err) {
+                       IPW_DEBUG_WX("failed setting power mode.\n");
+                       return err;
+               }
+
+               IPW_DEBUG_WX("SET Power Management Mode -> off\n");
+
+               return 0;
+       }
+
+       switch (wrqu->power.flags & IW_POWER_MODE) {
+       case IW_POWER_ON:       /* If not specified */
+       case IW_POWER_MODE:     /* If set all mask */
+       case IW_POWER_ALL_R:    /* If explicitely state all */
+               break;
+       default:                /* Otherwise we don't support it */
+               IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
+                            wrqu->power.flags);
+               return -EOPNOTSUPP;
+       }
+
+       /* If the user hasn't specified a power management mode yet, default
+        * to BATTERY */
+       if (IPW_POWER_LEVEL(priv->power_mode) == IPW_POWER_AC)
+               priv->power_mode = IPW_POWER_ENABLED | IPW_POWER_BATTERY;
+       else
+               priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
+       err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
+       if (err) {
+               IPW_DEBUG_WX("failed setting power mode.\n");
+               return err;
+       }
+
+       IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
+
+       return 0;
+}
+
+static int ipw_wx_get_power(struct net_device *dev,
+                           struct iw_request_info *info,
+                           union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+
+       if (!(priv->power_mode & IPW_POWER_ENABLED)) {
+               wrqu->power.disabled = 1;
+       } else {
+               wrqu->power.disabled = 0;
+       }
+
+       IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode);
+
+       return 0;
+}
+
+static int ipw_wx_set_powermode(struct net_device *dev,
+                               struct iw_request_info *info,
+                               union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       int mode = *(int *)extra;
+       int err;
+
+       if ((mode < 1) || (mode > IPW_POWER_LIMIT)) {
+               mode = IPW_POWER_AC;
+               priv->power_mode = mode;
+       } else {
+               priv->power_mode = IPW_POWER_ENABLED | mode;
+       }
+
+       if (priv->power_mode != mode) {
+               err = ipw_send_power_mode(priv, mode);
+
+               if (err) {
+                       IPW_DEBUG_WX("failed setting power mode.\n");
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+#define MAX_WX_STRING 80
+static int ipw_wx_get_powermode(struct net_device *dev,
+                               struct iw_request_info *info,
+                               union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       int level = IPW_POWER_LEVEL(priv->power_mode);
+       char *p = extra;
+
+       p += snprintf(p, MAX_WX_STRING, "Power save level: %d ", level);
+
+       switch (level) {
+       case IPW_POWER_AC:
+               p += snprintf(p, MAX_WX_STRING - (p - extra), "(AC)");
+               break;
+       case IPW_POWER_BATTERY:
+               p += snprintf(p, MAX_WX_STRING - (p - extra), "(BATTERY)");
+               break;
+       default:
+               p += snprintf(p, MAX_WX_STRING - (p - extra),
+                             "(Timeout %dms, Period %dms)",
+                             timeout_duration[level - 1] / 1000,
+                             period_duration[level - 1] / 1000);
+       }
+
+       if (!(priv->power_mode & IPW_POWER_ENABLED))
+               p += snprintf(p, MAX_WX_STRING - (p - extra), " OFF");
+
+       wrqu->data.length = p - extra + 1;
+
+       return 0;
+}
+
+static int ipw_wx_set_wireless_mode(struct net_device *dev,
+                                   struct iw_request_info *info,
+                                   union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       int mode = *(int *)extra;
+       u8 band = 0, modulation = 0;
+
+       if (mode == 0 || mode & ~IEEE_MODE_MASK) {
+               IPW_WARNING("Attempt to set invalid wireless mode: %d\n", mode);
+               return -EINVAL;
+       }
+
+       if (priv->adapter == IPW_2915ABG) {
+               priv->ieee->abg_ture = 1;
+               if (mode & IEEE_A) {
+                       band |= IEEE80211_52GHZ_BAND;
+                       modulation |= IEEE80211_OFDM_MODULATION;
+               } else
+                       priv->ieee->abg_ture = 0;
+       } else {
+               if (mode & IEEE_A) {
+                       IPW_WARNING("Attempt to set 2200BG into "
+                                   "802.11a mode\n");
+                       return -EINVAL;
+               }
+
+               priv->ieee->abg_ture = 0;
+       }
+
+       if (mode & IEEE_B) {
+               band |= IEEE80211_24GHZ_BAND;
+               modulation |= IEEE80211_CCK_MODULATION;
+       } else
+               priv->ieee->abg_ture = 0;
+
+       if (mode & IEEE_G) {
+               band |= IEEE80211_24GHZ_BAND;
+               modulation |= IEEE80211_OFDM_MODULATION;
+       } else
+               priv->ieee->abg_ture = 0;
+
+       priv->ieee->mode = mode;
+       priv->ieee->freq_band = band;
+       priv->ieee->modulation = modulation;
+       init_supported_rates(priv, &priv->rates);
+
+       /* If we are currently associated, or trying to associate
+        * then see if this is a new configuration (causing us to
+        * disassociate) */
+       if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
+               /* The resulting association will trigger
+                * the new rates to be sent to the device */
+               IPW_DEBUG_ASSOC("Disassociating due to mode change.\n");
+               ipw_disassociate(priv);
+       } else
+               ipw_send_supported_rates(priv, &priv->rates);
+
+       IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n",
+                    mode & IEEE_A ? 'a' : '.',
+                    mode & IEEE_B ? 'b' : '.', mode & IEEE_G ? 'g' : '.');
+       return 0;
+}
+
+static int ipw_wx_get_wireless_mode(struct net_device *dev,
+                                   struct iw_request_info *info,
+                                   union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+
+       switch (priv->ieee->freq_band) {
+       case IEEE80211_24GHZ_BAND:
+               switch (priv->ieee->modulation) {
+               case IEEE80211_CCK_MODULATION:
+                       strncpy(extra, "802.11b (2)", MAX_WX_STRING);
+                       break;
+               case IEEE80211_OFDM_MODULATION:
+                       strncpy(extra, "802.11g (4)", MAX_WX_STRING);
+                       break;
+               default:
+                       strncpy(extra, "802.11bg (6)", MAX_WX_STRING);
+                       break;
+               }
+               break;
+
+       case IEEE80211_52GHZ_BAND:
+               strncpy(extra, "802.11a (1)", MAX_WX_STRING);
+               break;
+
+       default:                /* Mixed Band */
+               switch (priv->ieee->modulation) {
+               case IEEE80211_CCK_MODULATION:
+                       strncpy(extra, "802.11ab (3)", MAX_WX_STRING);
+                       break;
+               case IEEE80211_OFDM_MODULATION:
+                       strncpy(extra, "802.11ag (5)", MAX_WX_STRING);
+                       break;
+               default:
+                       strncpy(extra, "802.11abg (7)", MAX_WX_STRING);
+                       break;
+               }
+               break;
+       }
+
+       IPW_DEBUG_WX("PRIV GET MODE: %s\n", extra);
+
+       wrqu->data.length = strlen(extra) + 1;
+
+       return 0;
+}
+
+#ifdef CONFIG_IPW_PROMISC
+static int ipw_wx_set_promisc(struct net_device *dev,
+                             struct iw_request_info *info,
+                             union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       int *parms = (int *)extra;
+       int enable = (parms[0] > 0);
+
+       IPW_DEBUG_WX("SET PROMISC: %d %d\n", enable, parms[1]);
+       if (enable) {
+               if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
+                       priv->net_dev->type = ARPHRD_IEEE80211;
+                       ipw_adapter_restart(priv);
+               }
+
+               ipw_set_channel(priv, parms[1]);
+       } else {
+               if (priv->ieee->iw_mode != IW_MODE_MONITOR)
+                       return 0;
+               priv->net_dev->type = ARPHRD_ETHER;
+               ipw_adapter_restart(priv);
+       }
+       return 0;
+}
+
+static int ipw_wx_reset(struct net_device *dev,
+                       struct iw_request_info *info,
+                       union iwreq_data *wrqu, char *extra)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       IPW_DEBUG_WX("RESET\n");
+       ipw_adapter_restart(priv);
+       return 0;
+}
+#endif                         // CONFIG_IPW_PROMISC
+
+/* Rebase the WE IOCTLs to zero for the handler array */
+#define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT]
+static iw_handler ipw_wx_handlers[] = {
+       IW_IOCTL(SIOCGIWNAME)   = ipw_wx_get_name,
+       IW_IOCTL(SIOCSIWFREQ)   = ipw_wx_set_freq,
+       IW_IOCTL(SIOCGIWFREQ)   = ipw_wx_get_freq,
+       IW_IOCTL(SIOCSIWMODE)   = ipw_wx_set_mode,
+       IW_IOCTL(SIOCGIWMODE)   = ipw_wx_get_mode,
+       IW_IOCTL(SIOCGIWRANGE)  = ipw_wx_get_range,
+       IW_IOCTL(SIOCSIWAP)     = ipw_wx_set_wap,
+       IW_IOCTL(SIOCGIWAP)     = ipw_wx_get_wap,
+       IW_IOCTL(SIOCSIWSCAN)   = ipw_wx_set_scan,
+       IW_IOCTL(SIOCGIWSCAN)   = ipw_wx_get_scan,
+       IW_IOCTL(SIOCSIWESSID)  = ipw_wx_set_essid,
+       IW_IOCTL(SIOCGIWESSID)  = ipw_wx_get_essid,
+       IW_IOCTL(SIOCSIWNICKN)  = ipw_wx_set_nick,
+       IW_IOCTL(SIOCGIWNICKN)  = ipw_wx_get_nick,
+       IW_IOCTL(SIOCSIWRATE)   = ipw_wx_set_rate,
+       IW_IOCTL(SIOCGIWRATE)   = ipw_wx_get_rate,
+       IW_IOCTL(SIOCSIWRTS)    = ipw_wx_set_rts,
+       IW_IOCTL(SIOCGIWRTS)    = ipw_wx_get_rts,
+       IW_IOCTL(SIOCSIWFRAG)   = ipw_wx_set_frag,
+       IW_IOCTL(SIOCGIWFRAG)   = ipw_wx_get_frag,
+       IW_IOCTL(SIOCSIWTXPOW)  = ipw_wx_set_txpow,
+       IW_IOCTL(SIOCGIWTXPOW)  = ipw_wx_get_txpow,
+       IW_IOCTL(SIOCSIWRETRY)  = ipw_wx_set_retry,
+       IW_IOCTL(SIOCGIWRETRY)  = ipw_wx_get_retry,
+       IW_IOCTL(SIOCSIWENCODE) = ipw_wx_set_encode,
+       IW_IOCTL(SIOCGIWENCODE) = ipw_wx_get_encode,
+       IW_IOCTL(SIOCSIWPOWER)  = ipw_wx_set_power,
+       IW_IOCTL(SIOCGIWPOWER)  = ipw_wx_get_power,
+};
+
+#define IPW_PRIV_SET_POWER     SIOCIWFIRSTPRIV
+#define IPW_PRIV_GET_POWER     SIOCIWFIRSTPRIV+1
+#define IPW_PRIV_SET_MODE      SIOCIWFIRSTPRIV+2
+#define IPW_PRIV_GET_MODE      SIOCIWFIRSTPRIV+3
+#define IPW_PRIV_SET_PROMISC   SIOCIWFIRSTPRIV+4
+#define IPW_PRIV_RESET         SIOCIWFIRSTPRIV+5
+
+static struct iw_priv_args ipw_priv_args[] = {
+       {
+        .cmd = IPW_PRIV_SET_POWER,
+        .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        .name = "set_power"},
+       {
+        .cmd = IPW_PRIV_GET_POWER,
+        .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
+        .name = "get_power"},
+       {
+        .cmd = IPW_PRIV_SET_MODE,
+        .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        .name = "set_mode"},
+       {
+        .cmd = IPW_PRIV_GET_MODE,
+        .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
+        .name = "get_mode"},
+#ifdef CONFIG_IPW_PROMISC
+       {
+        IPW_PRIV_SET_PROMISC,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
+       {
+        IPW_PRIV_RESET,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"},
+#endif                         /* CONFIG_IPW_PROMISC */
+};
+
+static iw_handler ipw_priv_handler[] = {
+       ipw_wx_set_powermode,
+       ipw_wx_get_powermode,
+       ipw_wx_set_wireless_mode,
+       ipw_wx_get_wireless_mode,
+#ifdef CONFIG_IPW_PROMISC
+       ipw_wx_set_promisc,
+       ipw_wx_reset,
+#endif
+};
+
+static struct iw_handler_def ipw_wx_handler_def = {
+       .standard               = ipw_wx_handlers,
+       .num_standard           = ARRAY_SIZE(ipw_wx_handlers),
+       .num_private            = ARRAY_SIZE(ipw_priv_handler),
+       .num_private_args       = ARRAY_SIZE(ipw_priv_args),
+       .private                = ipw_priv_handler,
+       .private_args           = ipw_priv_args,
+};
+
+/*
+ * Get wireless statistics.
+ * Called by /proc/net/wireless
+ * Also called by SIOCGIWSTATS
+ */
+static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       struct iw_statistics *wstats;
+
+       wstats = &priv->wstats;
+
+       /* if hw is disabled, then ipw2100_get_ordinal() can't be called.
+        * ipw2100_wx_wireless_stats seems to be called before fw is
+        * initialized.  STATUS_ASSOCIATED will only be set if the hw is up
+        * and associated; if not associcated, the values are all meaningless
+        * anyway, so set them all to NULL and INVALID */
+       if (!(priv->status & STATUS_ASSOCIATED)) {
+               wstats->miss.beacon = 0;
+               wstats->discard.retries = 0;
+               wstats->qual.qual = 0;
+               wstats->qual.level = 0;
+               wstats->qual.noise = 0;
+               wstats->qual.updated = 7;
+               wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
+                   IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
+               return wstats;
+       }
+
+       wstats->qual.qual = priv->quality;
+       wstats->qual.level = average_value(&priv->average_rssi);
+       wstats->qual.noise = average_value(&priv->average_noise);
+       wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
+           IW_QUAL_NOISE_UPDATED;
+
+       wstats->miss.beacon = average_value(&priv->average_missed_beacons);
+       wstats->discard.retries = priv->last_tx_failures;
+       wstats->discard.code = priv->ieee->ieee_stats.rx_discards_undecryptable;
+
+/*     if (ipw_get_ordinal(priv, IPW_ORD_STAT_TX_RETRY, &tx_retry, &len))
+       goto fail_get_ordinal;
+       wstats->discard.retries += tx_retry; */
+
+       return wstats;
+}
+
+/* net device stuff */
+
+static inline void init_sys_config(struct ipw_sys_config *sys_config)
+{
+       memset(sys_config, 0, sizeof(struct ipw_sys_config));
+       sys_config->bt_coexistence = 1; /* We may need to look into prvStaBtConfig */
+       sys_config->answer_broadcast_ssid_probe = 0;
+       sys_config->accept_all_data_frames = 0;
+       sys_config->accept_non_directed_frames = 1;
+       sys_config->exclude_unicast_unencrypted = 0;
+       sys_config->disable_unicast_decryption = 1;
+       sys_config->exclude_multicast_unencrypted = 0;
+       sys_config->disable_multicast_decryption = 1;
+       sys_config->antenna_diversity = CFG_SYS_ANTENNA_BOTH;
+       sys_config->pass_crc_to_host = 0;       /* TODO: See if 1 gives us FCS */
+       sys_config->dot11g_auto_detection = 0;
+       sys_config->enable_cts_to_self = 0;
+       sys_config->bt_coexist_collision_thr = 0;
+       sys_config->pass_noise_stats_to_host = 1;
+}
+
+static int ipw_net_open(struct net_device *dev)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       IPW_DEBUG_INFO("dev->open\n");
+       /* we should be verifying the device is ready to be opened */
+       if (!(priv->status & STATUS_RF_KILL_MASK) &&
+           (priv->status & STATUS_ASSOCIATED))
+               netif_start_queue(dev);
+       return 0;
+}
+
+static int ipw_net_stop(struct net_device *dev)
+{
+       IPW_DEBUG_INFO("dev->close\n");
+       netif_stop_queue(dev);
+       return 0;
+}
+
+/*
+todo:
+
+modify to send one tfd per fragment instead of using chunking.  otherwise
+we need to heavily modify the ieee80211_skb_to_txb.
+*/
+
+static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)
+           txb->fragments[0]->data;
+       int i = 0;
+       struct tfd_frame *tfd;
+       struct clx2_tx_queue *txq = &priv->txq[0];
+       struct clx2_queue *q = &txq->q;
+       u8 id, hdr_len, unicast;
+       u16 remaining_bytes;
+
+       switch (priv->ieee->iw_mode) {
+       case IW_MODE_ADHOC:
+               hdr_len = IEEE80211_3ADDR_LEN;
+               unicast = !is_broadcast_ether_addr(hdr->addr1) &&
+                   !is_multicast_ether_addr(hdr->addr1);
+               id = ipw_find_station(priv, hdr->addr1);
+               if (id == IPW_INVALID_STATION) {
+                       id = ipw_add_station(priv, hdr->addr1);
+                       if (id == IPW_INVALID_STATION) {
+                               IPW_WARNING("Attempt to send data to "
+                                           "invalid cell: " MAC_FMT "\n",
+                                           MAC_ARG(hdr->addr1));
+                               goto drop;
+                       }
+               }
+               break;
+
+       case IW_MODE_INFRA:
+       default:
+               unicast = !is_broadcast_ether_addr(hdr->addr3) &&
+                   !is_multicast_ether_addr(hdr->addr3);
+               hdr_len = IEEE80211_3ADDR_LEN;
+               id = 0;
+               break;
+       }
+
+       tfd = &txq->bd[q->first_empty];
+       txq->txb[q->first_empty] = txb;
+       memset(tfd, 0, sizeof(*tfd));
+       tfd->u.data.station_number = id;
+
+       tfd->control_flags.message_type = TX_FRAME_TYPE;
+       tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK;
+
+       tfd->u.data.cmd_id = DINO_CMD_TX;
+       tfd->u.data.len = txb->payload_size;
+       remaining_bytes = txb->payload_size;
+       if (unlikely(!unicast))
+               tfd->u.data.tx_flags = DCT_FLAG_NO_WEP;
+       else
+               tfd->u.data.tx_flags = DCT_FLAG_NO_WEP | DCT_FLAG_ACK_REQD;
+
+       if (priv->assoc_request.ieee_mode == IPW_B_MODE)
+               tfd->u.data.tx_flags_ext = DCT_FLAG_EXT_MODE_CCK;
+       else
+               tfd->u.data.tx_flags_ext = DCT_FLAG_EXT_MODE_OFDM;
+
+       if (priv->config & CFG_PREAMBLE)
+               tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREMBL;
+
+       memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len);
+
+       /* payload */
+       tfd->u.data.num_chunks = min((u8) (NUM_TFD_CHUNKS - 2), txb->nr_frags);
+       for (i = 0; i < tfd->u.data.num_chunks; i++) {
+               IPW_DEBUG_TX("Dumping TX packet frag %i of %i (%d bytes):\n",
+                            i, tfd->u.data.num_chunks,
+                            txb->fragments[i]->len - hdr_len);
+               printk_buf(IPW_DL_TX, txb->fragments[i]->data + hdr_len,
+                          txb->fragments[i]->len - hdr_len);
+
+               tfd->u.data.chunk_ptr[i] =
+                   pci_map_single(priv->pci_dev,
+                                  txb->fragments[i]->data + hdr_len,
+                                  txb->fragments[i]->len - hdr_len,
+                                  PCI_DMA_TODEVICE);
+               tfd->u.data.chunk_len[i] = txb->fragments[i]->len - hdr_len;
+       }
+
+       if (i != txb->nr_frags) {
+               struct sk_buff *skb;
+               u16 remaining_bytes = 0;
+               int j;
+
+               for (j = i; j < txb->nr_frags; j++)
+                       remaining_bytes += txb->fragments[j]->len - hdr_len;
+
+               printk(KERN_INFO "Trying to reallocate for %d bytes\n",
+                      remaining_bytes);
+               skb = alloc_skb(remaining_bytes, GFP_ATOMIC);
+               if (skb != NULL) {
+                       tfd->u.data.chunk_len[i] = remaining_bytes;
+                       for (j = i; j < txb->nr_frags; j++) {
+                               int size = txb->fragments[j]->len - hdr_len;
+                               printk(KERN_INFO "Adding frag %d %d...\n",
+                                      j, size);
+                               memcpy(skb_put(skb, size),
+                                      txb->fragments[j]->data + hdr_len, size);
+                       }
+                       dev_kfree_skb_any(txb->fragments[i]);
+                       txb->fragments[i] = skb;
+                       tfd->u.data.chunk_ptr[i] =
+                           pci_map_single(priv->pci_dev, skb->data,
+                                          tfd->u.data.chunk_len[i],
+                                          PCI_DMA_TODEVICE);
+                       tfd->u.data.num_chunks++;
+               }
+       }
+
+       /* kick DMA */
+       q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd);
+       ipw_write32(priv, q->reg_w, q->first_empty);
+
+       if (ipw_queue_space(q) < q->high_mark)
+               netif_stop_queue(priv->net_dev);
+
+       return;
+
+      drop:
+       IPW_DEBUG_DROP("Silently dropping Tx packet.\n");
+       ieee80211_txb_free(txb);
+}
+
+static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb,
+                                  struct net_device *dev)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       unsigned long flags;
+
+       IPW_DEBUG_TX("dev->xmit(%d bytes)\n", txb->payload_size);
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       if (!(priv->status & STATUS_ASSOCIATED)) {
+               IPW_DEBUG_INFO("Tx attempt while not associated.\n");
+               priv->ieee->stats.tx_carrier_errors++;
+               netif_stop_queue(dev);
+               goto fail_unlock;
+       }
+
+       ipw_tx_skb(priv, txb);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return 0;
+
+      fail_unlock:
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return 1;
+}
+
+static struct net_device_stats *ipw_net_get_stats(struct net_device *dev)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+
+       priv->ieee->stats.tx_packets = priv->tx_packets;
+       priv->ieee->stats.rx_packets = priv->rx_packets;
+       return &priv->ieee->stats;
+}
+
+static void ipw_net_set_multicast_list(struct net_device *dev)
+{
+
+}
+
+static int ipw_net_set_mac_address(struct net_device *dev, void *p)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       struct sockaddr *addr = p;
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+       priv->config |= CFG_CUSTOM_MAC;
+       memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
+       printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n",
+              priv->net_dev->name, MAC_ARG(priv->mac_addr));
+       ipw_adapter_restart(priv);
+       return 0;
+}
+
+static void ipw_ethtool_get_drvinfo(struct net_device *dev,
+                                   struct ethtool_drvinfo *info)
+{
+       struct ipw_priv *p = ieee80211_priv(dev);
+       char vers[64];
+       char date[32];
+       u32 len;
+
+       strcpy(info->driver, DRV_NAME);
+       strcpy(info->version, DRV_VERSION);
+
+       len = sizeof(vers);
+       ipw_get_ordinal(p, IPW_ORD_STAT_FW_VERSION, vers, &len);
+       len = sizeof(date);
+       ipw_get_ordinal(p, IPW_ORD_STAT_FW_DATE, date, &len);
+
+       snprintf(info->fw_version, sizeof(info->fw_version), "%s (%s)",
+                vers, date);
+       strcpy(info->bus_info, pci_name(p->pci_dev));
+       info->eedump_len = CX2_EEPROM_IMAGE_SIZE;
+}
+
+static u32 ipw_ethtool_get_link(struct net_device *dev)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       return (priv->status & STATUS_ASSOCIATED) != 0;
+}
+
+static int ipw_ethtool_get_eeprom_len(struct net_device *dev)
+{
+       return CX2_EEPROM_IMAGE_SIZE;
+}
+
+static int ipw_ethtool_get_eeprom(struct net_device *dev,
+                                 struct ethtool_eeprom *eeprom, u8 * bytes)
+{
+       struct ipw_priv *p = ieee80211_priv(dev);
+
+       if (eeprom->offset + eeprom->len > CX2_EEPROM_IMAGE_SIZE)
+               return -EINVAL;
+
+       memcpy(bytes, &((u8 *) p->eeprom)[eeprom->offset], eeprom->len);
+       return 0;
+}
+
+static int ipw_ethtool_set_eeprom(struct net_device *dev,
+                                 struct ethtool_eeprom *eeprom, u8 * bytes)
+{
+       struct ipw_priv *p = ieee80211_priv(dev);
+       int i;
+
+       if (eeprom->offset + eeprom->len > CX2_EEPROM_IMAGE_SIZE)
+               return -EINVAL;
+
+       memcpy(&((u8 *) p->eeprom)[eeprom->offset], bytes, eeprom->len);
+       for (i = IPW_EEPROM_DATA;
+            i < IPW_EEPROM_DATA + CX2_EEPROM_IMAGE_SIZE; i++)
+               ipw_write8(p, i, p->eeprom[i]);
+
+       return 0;
+}
+
+static struct ethtool_ops ipw_ethtool_ops = {
+       .get_link       = ipw_ethtool_get_link,
+       .get_drvinfo    = ipw_ethtool_get_drvinfo,
+       .get_eeprom_len = ipw_ethtool_get_eeprom_len,
+       .get_eeprom     = ipw_ethtool_get_eeprom,
+       .set_eeprom     = ipw_ethtool_set_eeprom,
+};
+
+static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs)
+{
+       struct ipw_priv *priv = data;
+       u32 inta, inta_mask;
+
+       if (!priv)
+               return IRQ_NONE;
+
+       spin_lock(&priv->lock);
+
+       if (!(priv->status & STATUS_INT_ENABLED)) {
+               /* Shared IRQ */
+               goto none;
+       }
+
+       inta = ipw_read32(priv, CX2_INTA_RW);
+       inta_mask = ipw_read32(priv, CX2_INTA_MASK_R);
+
+       if (inta == 0xFFFFFFFF) {
+               /* Hardware disappeared */
+               IPW_WARNING("IRQ INTA == 0xFFFFFFFF\n");
+               goto none;
+       }
+
+       if (!(inta & (CX2_INTA_MASK_ALL & inta_mask))) {
+               /* Shared interrupt */
+               goto none;
+       }
+
+       /* tell the device to stop sending interrupts */
+       ipw_disable_interrupts(priv);
+
+       /* ack current interrupts */
+       inta &= (CX2_INTA_MASK_ALL & inta_mask);
+       ipw_write32(priv, CX2_INTA_RW, inta);
+
+       /* Cache INTA value for our tasklet */
+       priv->isr_inta = inta;
+
+       tasklet_schedule(&priv->irq_tasklet);
+
+       spin_unlock(&priv->lock);
+
+       return IRQ_HANDLED;
+      none:
+       spin_unlock(&priv->lock);
+       return IRQ_NONE;
+}
+
+static void ipw_rf_kill(void *adapter)
+{
+       struct ipw_priv *priv = adapter;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       if (rf_kill_active(priv)) {
+               IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
+               if (priv->workqueue)
+                       queue_delayed_work(priv->workqueue,
+                                          &priv->rf_kill, 2 * HZ);
+               goto exit_unlock;
+       }
+
+       /* RF Kill is now disabled, so bring the device back up */
+
+       if (!(priv->status & STATUS_RF_KILL_MASK)) {
+               IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting "
+                                 "device\n");
+
+               /* we can not do an adapter restart while inside an irq lock */
+               queue_work(priv->workqueue, &priv->adapter_restart);
+       } else
+               IPW_DEBUG_RF_KILL("HW RF Kill deactivated.  SW RF Kill still "
+                                 "enabled\n");
+
+      exit_unlock:
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int ipw_setup_deferred_work(struct ipw_priv *priv)
+{
+       int ret = 0;
+
+       priv->workqueue = create_workqueue(DRV_NAME);
+       init_waitqueue_head(&priv->wait_command_queue);
+
+       INIT_WORK(&priv->adhoc_check, ipw_adhoc_check, priv);
+       INIT_WORK(&priv->associate, ipw_associate, priv);
+       INIT_WORK(&priv->disassociate, ipw_disassociate, priv);
+       INIT_WORK(&priv->rx_replenish, ipw_rx_queue_replenish, priv);
+       INIT_WORK(&priv->adapter_restart, ipw_adapter_restart, priv);
+       INIT_WORK(&priv->rf_kill, ipw_rf_kill, priv);
+       INIT_WORK(&priv->up, (void (*)(void *))ipw_up, priv);
+       INIT_WORK(&priv->down, (void (*)(void *))ipw_down, priv);
+       INIT_WORK(&priv->request_scan,
+                 (void (*)(void *))ipw_request_scan, priv);
+       INIT_WORK(&priv->gather_stats,
+                 (void (*)(void *))ipw_gather_stats, priv);
+       INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_abort_scan, priv);
+       INIT_WORK(&priv->roam, ipw_roam, priv);
+       INIT_WORK(&priv->scan_check, ipw_scan_check, priv);
+
+       tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+                    ipw_irq_tasklet, (unsigned long)priv);
+
+       return ret;
+}
+
+static void shim__set_security(struct net_device *dev,
+                              struct ieee80211_security *sec)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               if (sec->flags & (1 << i)) {
+                       priv->sec.key_sizes[i] = sec->key_sizes[i];
+                       if (sec->key_sizes[i] == 0)
+                               priv->sec.flags &= ~(1 << i);
+                       else
+                               memcpy(priv->sec.keys[i], sec->keys[i],
+                                      sec->key_sizes[i]);
+                       priv->sec.flags |= (1 << i);
+                       priv->status |= STATUS_SECURITY_UPDATED;
+               }
+       }
+
+       if ((sec->flags & SEC_ACTIVE_KEY) &&
+           priv->sec.active_key != sec->active_key) {
+               if (sec->active_key <= 3) {
+                       priv->sec.active_key = sec->active_key;
+                       priv->sec.flags |= SEC_ACTIVE_KEY;
+               } else
+                       priv->sec.flags &= ~SEC_ACTIVE_KEY;
+               priv->status |= STATUS_SECURITY_UPDATED;
+       }
+
+       if ((sec->flags & SEC_AUTH_MODE) &&
+           (priv->sec.auth_mode != sec->auth_mode)) {
+               priv->sec.auth_mode = sec->auth_mode;
+               priv->sec.flags |= SEC_AUTH_MODE;
+               if (sec->auth_mode == WLAN_AUTH_SHARED_KEY)
+                       priv->capability |= CAP_SHARED_KEY;
+               else
+                       priv->capability &= ~CAP_SHARED_KEY;
+               priv->status |= STATUS_SECURITY_UPDATED;
+       }
+
+       if (sec->flags & SEC_ENABLED && priv->sec.enabled != sec->enabled) {
+               priv->sec.flags |= SEC_ENABLED;
+               priv->sec.enabled = sec->enabled;
+               priv->status |= STATUS_SECURITY_UPDATED;
+               if (sec->enabled)
+                       priv->capability |= CAP_PRIVACY_ON;
+               else
+                       priv->capability &= ~CAP_PRIVACY_ON;
+       }
+
+       if (sec->flags & SEC_LEVEL && priv->sec.level != sec->level) {
+               priv->sec.level = sec->level;
+               priv->sec.flags |= SEC_LEVEL;
+               priv->status |= STATUS_SECURITY_UPDATED;
+       }
+
+       /* To match current functionality of ipw2100 (which works well w/
+        * various supplicants, we don't force a disassociate if the
+        * privacy capability changes ... */
+#if 0
+       if ((priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) &&
+           (((priv->assoc_request.capability &
+              WLAN_CAPABILITY_PRIVACY) && !sec->enabled) ||
+            (!(priv->assoc_request.capability &
+               WLAN_CAPABILITY_PRIVACY) && sec->enabled))) {
+               IPW_DEBUG_ASSOC("Disassociating due to capability "
+                               "change.\n");
+               ipw_disassociate(priv);
+       }
+#endif
+}
+
+static int init_supported_rates(struct ipw_priv *priv,
+                               struct ipw_supported_rates *rates)
+{
+       /* TODO: Mask out rates based on priv->rates_mask */
+
+       memset(rates, 0, sizeof(*rates));
+       /* configure supported rates */
+       switch (priv->ieee->freq_band) {
+       case IEEE80211_52GHZ_BAND:
+               rates->ieee_mode = IPW_A_MODE;
+               rates->purpose = IPW_RATE_CAPABILITIES;
+               ipw_add_ofdm_scan_rates(rates, IEEE80211_CCK_MODULATION,
+                                       IEEE80211_OFDM_DEFAULT_RATES_MASK);
+               break;
+
+       default:                /* Mixed or 2.4Ghz */
+               rates->ieee_mode = IPW_G_MODE;
+               rates->purpose = IPW_RATE_CAPABILITIES;
+               ipw_add_cck_scan_rates(rates, IEEE80211_CCK_MODULATION,
+                                      IEEE80211_CCK_DEFAULT_RATES_MASK);
+               if (priv->ieee->modulation & IEEE80211_OFDM_MODULATION) {
+                       ipw_add_ofdm_scan_rates(rates, IEEE80211_CCK_MODULATION,
+                                               IEEE80211_OFDM_DEFAULT_RATES_MASK);
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static int ipw_config(struct ipw_priv *priv)
+{
+       int i;
+       struct ipw_tx_power tx_power;
+
+       memset(&priv->sys_config, 0, sizeof(priv->sys_config));
+       memset(&tx_power, 0, sizeof(tx_power));
+
+       /* This is only called from ipw_up, which resets/reloads the firmware
+          so, we don't need to first disable the card before we configure
+          it */
+
+       /* configure device for 'G' band */
+       tx_power.ieee_mode = IPW_G_MODE;
+       tx_power.num_channels = 11;
+       for (i = 0; i < 11; i++) {
+               tx_power.channels_tx_power[i].channel_number = i + 1;
+               tx_power.channels_tx_power[i].tx_power = priv->tx_power;
+       }
+       if (ipw_send_tx_power(priv, &tx_power))
+               goto error;
+
+       /* configure device to also handle 'B' band */
+       tx_power.ieee_mode = IPW_B_MODE;
+       if (ipw_send_tx_power(priv, &tx_power))
+               goto error;
+
+       /* initialize adapter address */
+       if (ipw_send_adapter_address(priv, priv->net_dev->dev_addr))
+               goto error;
+
+       /* set basic system config settings */
+       init_sys_config(&priv->sys_config);
+       if (ipw_send_system_config(priv, &priv->sys_config))
+               goto error;
+
+       init_supported_rates(priv, &priv->rates);
+       if (ipw_send_supported_rates(priv, &priv->rates))
+               goto error;
+
+       /* Set request-to-send threshold */
+       if (priv->rts_threshold) {
+               if (ipw_send_rts_threshold(priv, priv->rts_threshold))
+                       goto error;
+       }
+
+       if (ipw_set_random_seed(priv))
+               goto error;
+
+       /* final state transition to the RUN state */
+       if (ipw_send_host_complete(priv))
+               goto error;
+
+       /* If configured to try and auto-associate, kick off a scan */
+       if ((priv->config & CFG_ASSOCIATE) && ipw_request_scan(priv))
+               goto error;
+
+       return 0;
+
+      error:
+       return -EIO;
+}
+
+#define MAX_HW_RESTARTS 5
+static int ipw_up(struct ipw_priv *priv)
+{
+       int rc, i;
+
+       if (priv->status & STATUS_EXIT_PENDING)
+               return -EIO;
+
+       for (i = 0; i < MAX_HW_RESTARTS; i++) {
+               /* Load the microcode, firmware, and eeprom.
+                * Also start the clocks. */
+               rc = ipw_load(priv);
+               if (rc) {
+                       IPW_ERROR("Unable to load firmware: 0x%08X\n", rc);
+                       return rc;
+               }
+
+               ipw_init_ordinals(priv);
+               if (!(priv->config & CFG_CUSTOM_MAC))
+                       eeprom_parse_mac(priv, priv->mac_addr);
+               memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
+
+               if (priv->status & STATUS_RF_KILL_MASK)
+                       return 0;
+
+               rc = ipw_config(priv);
+               if (!rc) {
+                       IPW_DEBUG_INFO("Configured device on count %i\n", i);
+                       priv->notif_missed_beacons = 0;
+                       netif_start_queue(priv->net_dev);
+                       return 0;
+               } else {
+                       IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n",
+                                      rc);
+               }
+
+               IPW_DEBUG_INFO("Failed to config device on retry %d of %d\n",
+                              i, MAX_HW_RESTARTS);
+
+               /* We had an error bringing up the hardware, so take it
+                * all the way back down so we can try again */
+               ipw_down(priv);
+       }
+
+       /* tried to restart and config the device for as long as our
+        * patience could withstand */
+       IPW_ERROR("Unable to initialize device after %d attempts.\n", i);
+       return -EIO;
+}
+
+static void ipw_down(struct ipw_priv *priv)
+{
+       /* Attempt to disable the card */
+#if 0
+       ipw_send_card_disable(priv, 0);
+#endif
+
+       /* tell the device to stop sending interrupts */
+       ipw_disable_interrupts(priv);
+
+       /* Clear all bits but the RF Kill */
+       priv->status &= STATUS_RF_KILL_MASK;
+
+       netif_carrier_off(priv->net_dev);
+       netif_stop_queue(priv->net_dev);
+
+       ipw_stop_nic(priv);
+}
+
+/* Called by register_netdev() */
+static int ipw_net_init(struct net_device *dev)
+{
+       struct ipw_priv *priv = ieee80211_priv(dev);
+
+       if (priv->status & STATUS_RF_KILL_SW) {
+               IPW_WARNING("Radio disabled by module parameter.\n");
+               return 0;
+       } else if (rf_kill_active(priv)) {
+               IPW_WARNING("Radio Frequency Kill Switch is On:\n"
+                           "Kill switch must be turned off for "
+                           "wireless networking to work.\n");
+               queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ);
+               return 0;
+       }
+
+       if (ipw_up(priv))
+               return -EIO;
+
+       return 0;
+}
+
+/* PCI driver stuff */
+static struct pci_device_id card_ids[] = {
+       {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2701, 0, 0, 0},
+       {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2702, 0, 0, 0},
+       {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2711, 0, 0, 0},
+       {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2712, 0, 0, 0},
+       {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2721, 0, 0, 0},
+       {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2722, 0, 0, 0},
+       {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2731, 0, 0, 0},
+       {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2732, 0, 0, 0},
+       {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2741, 0, 0, 0},
+       {PCI_VENDOR_ID_INTEL, 0x1043, 0x103c, 0x2741, 0, 0, 0},
+       {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2742, 0, 0, 0},
+       {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2751, 0, 0, 0},
+       {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2752, 0, 0, 0},
+       {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2753, 0, 0, 0},
+       {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2754, 0, 0, 0},
+       {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2761, 0, 0, 0},
+       {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0},
+       {PCI_VENDOR_ID_INTEL, 0x104f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VENDOR_ID_INTEL, 0x4220, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */
+       {PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* 2225BG */
+       {PCI_VENDOR_ID_INTEL, 0x4223, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */
+       {PCI_VENDOR_ID_INTEL, 0x4224, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */
+
+       /* required last entry */
+       {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, card_ids);
+
+static struct attribute *ipw_sysfs_entries[] = {
+       &dev_attr_rf_kill.attr,
+       &dev_attr_direct_dword.attr,
+       &dev_attr_indirect_byte.attr,
+       &dev_attr_indirect_dword.attr,
+       &dev_attr_mem_gpio_reg.attr,
+       &dev_attr_command_event_reg.attr,
+       &dev_attr_nic_type.attr,
+       &dev_attr_status.attr,
+       &dev_attr_cfg.attr,
+       &dev_attr_dump_errors.attr,
+       &dev_attr_dump_events.attr,
+       &dev_attr_eeprom_delay.attr,
+       &dev_attr_ucode_version.attr,
+       &dev_attr_rtc.attr,
+       NULL
+};
+
+static struct attribute_group ipw_attribute_group = {
+       .name = NULL,           /* put in device directory */
+       .attrs = ipw_sysfs_entries,
+};
+
+static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       int err = 0;
+       struct net_device *net_dev;
+       void __iomem *base;
+       u32 length, val;
+       struct ipw_priv *priv;
+       int band, modulation;
+
+       net_dev = alloc_ieee80211(sizeof(struct ipw_priv));
+       if (net_dev == NULL) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       priv = ieee80211_priv(net_dev);
+       priv->ieee = netdev_priv(net_dev);
+       priv->net_dev = net_dev;
+       priv->pci_dev = pdev;
+#ifdef CONFIG_IPW_DEBUG
+       ipw_debug_level = debug;
+#endif
+       spin_lock_init(&priv->lock);
+
+       if (pci_enable_device(pdev)) {
+               err = -ENODEV;
+               goto out_free_ieee80211;
+       }
+
+       pci_set_master(pdev);
+
+       err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+       if (!err)
+               err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+       if (err) {
+               printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n");
+               goto out_pci_disable_device;
+       }
+
+       pci_set_drvdata(pdev, priv);
+
+       err = pci_request_regions(pdev, DRV_NAME);
+       if (err)
+               goto out_pci_disable_device;
+
+       /* We disable the RETRY_TIMEOUT register (0x41) to keep
+        * PCI Tx retries from interfering with C3 CPU state */
+       pci_read_config_dword(pdev, 0x40, &val);
+       if ((val & 0x0000ff00) != 0)
+               pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
+
+       length = pci_resource_len(pdev, 0);
+       priv->hw_len = length;
+
+       base = ioremap_nocache(pci_resource_start(pdev, 0), length);
+       if (!base) {
+               err = -ENODEV;
+               goto out_pci_release_regions;
+       }
+
+       priv->hw_base = base;
+       IPW_DEBUG_INFO("pci_resource_len = 0x%08x\n", length);
+       IPW_DEBUG_INFO("pci_resource_base = %p\n", base);
+
+       err = ipw_setup_deferred_work(priv);
+       if (err) {
+               IPW_ERROR("Unable to setup deferred work\n");
+               goto out_iounmap;
+       }
+
+       /* Initialize module parameter values here */
+       if (ifname)
+               strncpy(net_dev->name, ifname, IFNAMSIZ);
+
+       if (associate)
+               priv->config |= CFG_ASSOCIATE;
+       else
+               IPW_DEBUG_INFO("Auto associate disabled.\n");
+
+       if (auto_create)
+               priv->config |= CFG_ADHOC_CREATE;
+       else
+               IPW_DEBUG_INFO("Auto adhoc creation disabled.\n");
+
+       if (disable) {
+               priv->status |= STATUS_RF_KILL_SW;
+               IPW_DEBUG_INFO("Radio disabled.\n");
+       }
+
+       if (channel != 0) {
+               priv->config |= CFG_STATIC_CHANNEL;
+               priv->channel = channel;
+               IPW_DEBUG_INFO("Bind to static channel %d\n", channel);
+               IPW_DEBUG_INFO("Bind to static channel %d\n", channel);
+               /* TODO: Validate that provided channel is in range */
+       }
+
+       switch (mode) {
+       case 1:
+               priv->ieee->iw_mode = IW_MODE_ADHOC;
+               break;
+#ifdef CONFIG_IPW_PROMISC
+       case 2:
+               priv->ieee->iw_mode = IW_MODE_MONITOR;
+               break;
+#endif
+       default:
+       case 0:
+               priv->ieee->iw_mode = IW_MODE_INFRA;
+               break;
+       }
+
+       if ((priv->pci_dev->device == 0x4223) ||
+           (priv->pci_dev->device == 0x4224)) {
+               printk(KERN_INFO DRV_NAME
+                      ": Detected Intel PRO/Wireless 2915ABG Network "
+                      "Connection\n");
+               priv->ieee->abg_ture = 1;
+               band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND;
+               modulation = IEEE80211_OFDM_MODULATION |
+                   IEEE80211_CCK_MODULATION;
+               priv->adapter = IPW_2915ABG;
+               priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B;
+       } else {
+               if (priv->pci_dev->device == 0x4221)
+                       printk(KERN_INFO DRV_NAME
+                              ": Detected Intel PRO/Wireless 2225BG Network "
+                              "Connection\n");
+               else
+                       printk(KERN_INFO DRV_NAME
+                              ": Detected Intel PRO/Wireless 2200BG Network "
+                              "Connection\n");
+
+               priv->ieee->abg_ture = 0;
+               band = IEEE80211_24GHZ_BAND;
+               modulation = IEEE80211_OFDM_MODULATION |
+                   IEEE80211_CCK_MODULATION;
+               priv->adapter = IPW_2200BG;
+               priv->ieee->mode = IEEE_G | IEEE_B;
+       }
+
+       priv->ieee->freq_band = band;
+       priv->ieee->modulation = modulation;
+
+       priv->rates_mask = IEEE80211_DEFAULT_RATES_MASK;
+
+       priv->missed_beacon_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT;
+       priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT;
+
+       priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
+
+       /* If power management is turned on, default to AC mode */
+       priv->power_mode = IPW_POWER_AC;
+       priv->tx_power = IPW_DEFAULT_TX_POWER;
+
+       err = request_irq(pdev->irq, ipw_isr, SA_SHIRQ, DRV_NAME, priv);
+       if (err) {
+               IPW_ERROR("Error allocating IRQ %d\n", pdev->irq);
+               goto out_destroy_workqueue;
+       }
+
+       SET_MODULE_OWNER(net_dev);
+       SET_NETDEV_DEV(net_dev, &pdev->dev);
+
+       priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit;
+       priv->ieee->set_security = shim__set_security;
+
+       net_dev->open = ipw_net_open;
+       net_dev->stop = ipw_net_stop;
+       net_dev->init = ipw_net_init;
+       net_dev->get_stats = ipw_net_get_stats;
+       net_dev->set_multicast_list = ipw_net_set_multicast_list;
+       net_dev->set_mac_address = ipw_net_set_mac_address;
+       net_dev->get_wireless_stats = ipw_get_wireless_stats;
+       net_dev->wireless_handlers = &ipw_wx_handler_def;
+       net_dev->ethtool_ops = &ipw_ethtool_ops;
+       net_dev->irq = pdev->irq;
+       net_dev->base_addr = (unsigned long)priv->hw_base;
+       net_dev->mem_start = pci_resource_start(pdev, 0);
+       net_dev->mem_end = net_dev->mem_start + pci_resource_len(pdev, 0) - 1;
+
+       err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group);
+       if (err) {
+               IPW_ERROR("failed to create sysfs device attributes\n");
+               goto out_release_irq;
+       }
+
+       err = register_netdev(net_dev);
+       if (err) {
+               IPW_ERROR("failed to register network device\n");
+               goto out_remove_group;
+       }
+
+       return 0;
+
+      out_remove_group:
+       sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
+      out_release_irq:
+       free_irq(pdev->irq, priv);
+      out_destroy_workqueue:
+       destroy_workqueue(priv->workqueue);
+       priv->workqueue = NULL;
+      out_iounmap:
+       iounmap(priv->hw_base);
+      out_pci_release_regions:
+       pci_release_regions(pdev);
+      out_pci_disable_device:
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+      out_free_ieee80211:
+       free_ieee80211(priv->net_dev);
+      out:
+       return err;
+}
+
+static void ipw_pci_remove(struct pci_dev *pdev)
+{
+       struct ipw_priv *priv = pci_get_drvdata(pdev);
+       if (!priv)
+               return;
+
+       priv->status |= STATUS_EXIT_PENDING;
+
+       sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
+
+       ipw_down(priv);
+
+       unregister_netdev(priv->net_dev);
+
+       if (priv->rxq) {
+               ipw_rx_queue_free(priv, priv->rxq);
+               priv->rxq = NULL;
+       }
+       ipw_tx_queue_free(priv);
+
+       /* ipw_down will ensure that there is no more pending work
+        * in the workqueue's, so we can safely remove them now. */
+       if (priv->workqueue) {
+               cancel_delayed_work(&priv->adhoc_check);
+               cancel_delayed_work(&priv->gather_stats);
+               cancel_delayed_work(&priv->request_scan);
+               cancel_delayed_work(&priv->rf_kill);
+               cancel_delayed_work(&priv->scan_check);
+               destroy_workqueue(priv->workqueue);
+               priv->workqueue = NULL;
+       }
+
+       free_irq(pdev->irq, priv);
+       iounmap(priv->hw_base);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+       free_ieee80211(priv->net_dev);
+
+#ifdef CONFIG_PM
+       if (fw_loaded) {
+               release_firmware(bootfw);
+               release_firmware(ucode);
+               release_firmware(firmware);
+               fw_loaded = 0;
+       }
+#endif
+}
+
+#ifdef CONFIG_PM
+static int ipw_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct ipw_priv *priv = pci_get_drvdata(pdev);
+       struct net_device *dev = priv->net_dev;
+
+       printk(KERN_INFO "%s: Going into suspend...\n", dev->name);
+
+       /* Take down the device; powers it off, etc. */
+       ipw_down(priv);
+
+       /* Remove the PRESENT state of the device */
+       netif_device_detach(dev);
+
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+       return 0;
+}
+
+static int ipw_pci_resume(struct pci_dev *pdev)
+{
+       struct ipw_priv *priv = pci_get_drvdata(pdev);
+       struct net_device *dev = priv->net_dev;
+       u32 val;
+
+       printk(KERN_INFO "%s: Coming out of suspend...\n", dev->name);
+
+       pci_set_power_state(pdev, 0);
+       pci_enable_device(pdev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+       pci_restore_state(pdev, priv->pm_state);
+#else
+       pci_restore_state(pdev);
+#endif
+       /*
+        * Suspend/Resume resets the PCI configuration space, so we have to
+        * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
+        * from interfering with C3 CPU state. pci_restore_state won't help
+        * here since it only restores the first 64 bytes pci config header.
+        */
+       pci_read_config_dword(pdev, 0x40, &val);
+       if ((val & 0x0000ff00) != 0)
+               pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
+
+       /* Set the device back into the PRESENT state; this will also wake
+        * the queue of needed */
+       netif_device_attach(dev);
+
+       /* Bring the device back up */
+       queue_work(priv->workqueue, &priv->up);
+
+       return 0;
+}
+#endif
+
+/* driver initialization stuff */
+static struct pci_driver ipw_driver = {
+       .name = DRV_NAME,
+       .id_table = card_ids,
+       .probe = ipw_pci_probe,
+       .remove = __devexit_p(ipw_pci_remove),
+#ifdef CONFIG_PM
+       .suspend = ipw_pci_suspend,
+       .resume = ipw_pci_resume,
+#endif
+};
+
+static int __init ipw_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
+       printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+
+       ret = pci_module_init(&ipw_driver);
+       if (ret) {
+               IPW_ERROR("Unable to initialize PCI module\n");
+               return ret;
+       }
+
+       ret = driver_create_file(&ipw_driver.driver, &driver_attr_debug_level);
+       if (ret) {
+               IPW_ERROR("Unable to create driver sysfs file\n");
+               pci_unregister_driver(&ipw_driver);
+               return ret;
+       }
+
+       return ret;
+}
+
+static void __exit ipw_exit(void)
+{
+       driver_remove_file(&ipw_driver.driver, &driver_attr_debug_level);
+       pci_unregister_driver(&ipw_driver);
+}
+
+module_param(disable, int, 0444);
+MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
+
+module_param(associate, int, 0444);
+MODULE_PARM_DESC(associate, "auto associate when scanning (default on)");
+
+module_param(auto_create, int, 0444);
+MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)");
+
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "debug output mask");
+
+module_param(channel, int, 0444);
+MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])");
+
+module_param(ifname, charp, 0444);
+MODULE_PARM_DESC(ifname, "network device name (default eth%d)");
+
+#ifdef CONFIG_IPW_PROMISC
+module_param(mode, int, 0444);
+MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
+#else
+module_param(mode, int, 0444);
+MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)");
+#endif
+
+module_exit(ipw_exit);
+module_init(ipw_init);
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
new file mode 100644 (file)
index 0000000..5b00882
--- /dev/null
@@ -0,0 +1,1680 @@
+/******************************************************************************
+
+  Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+
+  Contact Information:
+  James P. Ketrenos <ipw2100-admin@linux.intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+******************************************************************************/
+
+#ifndef __ipw2200_h__
+#define __ipw2200_h__
+
+#define WEXT_USECHANNELS 1
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/firmware.h>
+#include <linux/wireless.h>
+#include <linux/dma-mapping.h>
+#include <asm/io.h>
+
+#include <net/ieee80211.h>
+
+#define DRV_NAME       "ipw2200"
+
+#include <linux/workqueue.h>
+
+/* Authentication  and Association States */
+enum connection_manager_assoc_states {
+       CMAS_INIT = 0,
+       CMAS_TX_AUTH_SEQ_1,
+       CMAS_RX_AUTH_SEQ_2,
+       CMAS_AUTH_SEQ_1_PASS,
+       CMAS_AUTH_SEQ_1_FAIL,
+       CMAS_TX_AUTH_SEQ_3,
+       CMAS_RX_AUTH_SEQ_4,
+       CMAS_AUTH_SEQ_2_PASS,
+       CMAS_AUTH_SEQ_2_FAIL,
+       CMAS_AUTHENTICATED,
+       CMAS_TX_ASSOC,
+       CMAS_RX_ASSOC_RESP,
+       CMAS_ASSOCIATED,
+       CMAS_LAST
+};
+
+#define IPW_WAIT                     (1<<0)
+#define IPW_QUIET                    (1<<1)
+#define IPW_ROAMING                  (1<<2)
+
+#define IPW_POWER_MODE_CAM           0x00      //(always on)
+#define IPW_POWER_INDEX_1            0x01
+#define IPW_POWER_INDEX_2            0x02
+#define IPW_POWER_INDEX_3            0x03
+#define IPW_POWER_INDEX_4            0x04
+#define IPW_POWER_INDEX_5            0x05
+#define IPW_POWER_AC                 0x06
+#define IPW_POWER_BATTERY            0x07
+#define IPW_POWER_LIMIT              0x07
+#define IPW_POWER_MASK               0x0F
+#define IPW_POWER_ENABLED            0x10
+#define IPW_POWER_LEVEL(x)           ((x) & IPW_POWER_MASK)
+
+#define IPW_CMD_HOST_COMPLETE                 2
+#define IPW_CMD_POWER_DOWN                    4
+#define IPW_CMD_SYSTEM_CONFIG                 6
+#define IPW_CMD_MULTICAST_ADDRESS             7
+#define IPW_CMD_SSID                          8
+#define IPW_CMD_ADAPTER_ADDRESS              11
+#define IPW_CMD_PORT_TYPE                    12
+#define IPW_CMD_RTS_THRESHOLD                15
+#define IPW_CMD_FRAG_THRESHOLD               16
+#define IPW_CMD_POWER_MODE                   17
+#define IPW_CMD_WEP_KEY                      18
+#define IPW_CMD_TGI_TX_KEY                   19
+#define IPW_CMD_SCAN_REQUEST                 20
+#define IPW_CMD_ASSOCIATE                    21
+#define IPW_CMD_SUPPORTED_RATES              22
+#define IPW_CMD_SCAN_ABORT                   23
+#define IPW_CMD_TX_FLUSH                     24
+#define IPW_CMD_QOS_PARAMETERS               25
+#define IPW_CMD_SCAN_REQUEST_EXT             26
+#define IPW_CMD_DINO_CONFIG                  30
+#define IPW_CMD_RSN_CAPABILITIES             31
+#define IPW_CMD_RX_KEY                       32
+#define IPW_CMD_CARD_DISABLE                 33
+#define IPW_CMD_SEED_NUMBER                  34
+#define IPW_CMD_TX_POWER                     35
+#define IPW_CMD_COUNTRY_INFO                 36
+#define IPW_CMD_AIRONET_INFO                 37
+#define IPW_CMD_AP_TX_POWER                  38
+#define IPW_CMD_CCKM_INFO                    39
+#define IPW_CMD_CCX_VER_INFO                 40
+#define IPW_CMD_SET_CALIBRATION              41
+#define IPW_CMD_SENSITIVITY_CALIB            42
+#define IPW_CMD_RETRY_LIMIT                  51
+#define IPW_CMD_IPW_PRE_POWER_DOWN           58
+#define IPW_CMD_VAP_BEACON_TEMPLATE          60
+#define IPW_CMD_VAP_DTIM_PERIOD              61
+#define IPW_CMD_EXT_SUPPORTED_RATES          62
+#define IPW_CMD_VAP_LOCAL_TX_PWR_CONSTRAINT  63
+#define IPW_CMD_VAP_QUIET_INTERVALS          64
+#define IPW_CMD_VAP_CHANNEL_SWITCH           65
+#define IPW_CMD_VAP_MANDATORY_CHANNELS       66
+#define IPW_CMD_VAP_CELL_PWR_LIMIT           67
+#define IPW_CMD_VAP_CF_PARAM_SET             68
+#define IPW_CMD_VAP_SET_BEACONING_STATE      69
+#define IPW_CMD_MEASUREMENT                  80
+#define IPW_CMD_POWER_CAPABILITY             81
+#define IPW_CMD_SUPPORTED_CHANNELS           82
+#define IPW_CMD_TPC_REPORT                   83
+#define IPW_CMD_WME_INFO                     84
+#define IPW_CMD_PRODUCTION_COMMAND          85
+#define IPW_CMD_LINKSYS_EOU_INFO             90
+
+#define RFD_SIZE                              4
+#define NUM_TFD_CHUNKS                        6
+
+#define TX_QUEUE_SIZE                        32
+#define RX_QUEUE_SIZE                        32
+
+#define DINO_CMD_WEP_KEY                   0x08
+#define DINO_CMD_TX                        0x0B
+#define DCT_ANTENNA_A                      0x01
+#define DCT_ANTENNA_B                      0x02
+
+#define IPW_A_MODE                         0
+#define IPW_B_MODE                         1
+#define IPW_G_MODE                         2
+
+/*
+ * TX Queue Flag Definitions
+ */
+
+/* abort attempt if mgmt frame is rx'd */
+#define DCT_FLAG_ABORT_MGMT                0x01
+
+/* require CTS */
+#define DCT_FLAG_CTS_REQUIRED              0x02
+
+/* use short preamble */
+#define DCT_FLAG_SHORT_PREMBL              0x04
+
+/* RTS/CTS first */
+#define DCT_FLAG_RTS_REQD                  0x08
+
+/* dont calculate duration field */
+#define DCT_FLAG_DUR_SET                   0x10
+
+/* even if MAC WEP set (allows pre-encrypt) */
+#define DCT_FLAG_NO_WEP              0x20
+
+/* overwrite TSF field */
+#define DCT_FLAG_TSF_REQD                  0x40
+
+/* ACK rx is expected to follow */
+#define DCT_FLAG_ACK_REQD                  0x80
+
+#define DCT_FLAG_EXT_MODE_CCK  0x01
+#define DCT_FLAG_EXT_MODE_OFDM 0x00
+
+#define TX_RX_TYPE_MASK                    0xFF
+#define TX_FRAME_TYPE                      0x00
+#define TX_HOST_COMMAND_TYPE               0x01
+#define RX_FRAME_TYPE                      0x09
+#define RX_HOST_NOTIFICATION_TYPE          0x03
+#define RX_HOST_CMD_RESPONSE_TYPE          0x04
+#define RX_TX_FRAME_RESPONSE_TYPE          0x05
+#define TFD_NEED_IRQ_MASK                  0x04
+
+#define HOST_CMD_DINO_CONFIG               30
+
+#define HOST_NOTIFICATION_STATUS_ASSOCIATED             10
+#define HOST_NOTIFICATION_STATUS_AUTHENTICATE           11
+#define HOST_NOTIFICATION_STATUS_SCAN_CHANNEL_RESULT    12
+#define HOST_NOTIFICATION_STATUS_SCAN_COMPLETED         13
+#define HOST_NOTIFICATION_STATUS_FRAG_LENGTH            14
+#define HOST_NOTIFICATION_STATUS_LINK_DETERIORATION     15
+#define HOST_NOTIFICATION_DINO_CONFIG_RESPONSE          16
+#define HOST_NOTIFICATION_STATUS_BEACON_STATE           17
+#define HOST_NOTIFICATION_STATUS_TGI_TX_KEY             18
+#define HOST_NOTIFICATION_TX_STATUS                     19
+#define HOST_NOTIFICATION_CALIB_KEEP_RESULTS            20
+#define HOST_NOTIFICATION_MEASUREMENT_STARTED           21
+#define HOST_NOTIFICATION_MEASUREMENT_ENDED             22
+#define HOST_NOTIFICATION_CHANNEL_SWITCHED              23
+#define HOST_NOTIFICATION_RX_DURING_QUIET_PERIOD        24
+#define HOST_NOTIFICATION_NOISE_STATS                  25
+#define HOST_NOTIFICATION_S36_MEASUREMENT_ACCEPTED      30
+#define HOST_NOTIFICATION_S36_MEASUREMENT_REFUSED       31
+
+#define HOST_NOTIFICATION_STATUS_BEACON_MISSING         1
+#define IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT           24
+#define IPW_MB_ROAMING_THRESHOLD_DEFAULT                8
+#define IPW_REAL_RATE_RX_PACKET_THRESHOLD               300
+
+#define MACADRR_BYTE_LEN                     6
+
+#define DCR_TYPE_AP                       0x01
+#define DCR_TYPE_WLAP                     0x02
+#define DCR_TYPE_MU_ESS                   0x03
+#define DCR_TYPE_MU_IBSS                  0x04
+#define DCR_TYPE_MU_PIBSS                 0x05
+#define DCR_TYPE_SNIFFER                  0x06
+#define DCR_TYPE_MU_BSS        DCR_TYPE_MU_ESS
+
+/**
+ * Generic queue structure
+ *
+ * Contains common data for Rx and Tx queues
+ */
+struct clx2_queue {
+       int n_bd;                      /**< number of BDs in this queue */
+       int first_empty;               /**< 1-st empty entry (index) */
+       int last_used;                 /**< last used entry (index) */
+       u32 reg_w;                   /**< 'write' reg (queue head), addr in domain 1 */
+       u32 reg_r;                   /**< 'read' reg (queue tail), addr in domain 1 */
+       dma_addr_t dma_addr;            /**< physical addr for BD's */
+       int low_mark;                  /**< low watermark, resume queue if free space more than this */
+       int high_mark;                 /**< high watermark, stop queue if free space less than this */
+} __attribute__ ((packed));
+
+struct machdr32 {
+       u16 frame_ctl;
+       u16 duration;           // watch out for endians!
+       u8 addr1[MACADRR_BYTE_LEN];
+       u8 addr2[MACADRR_BYTE_LEN];
+       u8 addr3[MACADRR_BYTE_LEN];
+       u16 seq_ctrl;           // more endians!
+       u8 addr4[MACADRR_BYTE_LEN];
+       u16 qos_ctrl;
+} __attribute__ ((packed));
+
+struct machdr30 {
+       u16 frame_ctl;
+       u16 duration;           // watch out for endians!
+       u8 addr1[MACADRR_BYTE_LEN];
+       u8 addr2[MACADRR_BYTE_LEN];
+       u8 addr3[MACADRR_BYTE_LEN];
+       u16 seq_ctrl;           // more endians!
+       u8 addr4[MACADRR_BYTE_LEN];
+} __attribute__ ((packed));
+
+struct machdr26 {
+       u16 frame_ctl;
+       u16 duration;           // watch out for endians!
+       u8 addr1[MACADRR_BYTE_LEN];
+       u8 addr2[MACADRR_BYTE_LEN];
+       u8 addr3[MACADRR_BYTE_LEN];
+       u16 seq_ctrl;           // more endians!
+       u16 qos_ctrl;
+} __attribute__ ((packed));
+
+struct machdr24 {
+       u16 frame_ctl;
+       u16 duration;           // watch out for endians!
+       u8 addr1[MACADRR_BYTE_LEN];
+       u8 addr2[MACADRR_BYTE_LEN];
+       u8 addr3[MACADRR_BYTE_LEN];
+       u16 seq_ctrl;           // more endians!
+} __attribute__ ((packed));
+
+// TX TFD with 32 byte MAC Header
+struct tx_tfd_32 {
+       struct machdr32 mchdr;  // 32
+       u32 uivplaceholder[2];  // 8
+} __attribute__ ((packed));
+
+// TX TFD with 30 byte MAC Header
+struct tx_tfd_30 {
+       struct machdr30 mchdr;  // 30
+       u8 reserved[2];         // 2
+       u32 uivplaceholder[2];  // 8
+} __attribute__ ((packed));
+
+// tx tfd with 26 byte mac header
+struct tx_tfd_26 {
+       struct machdr26 mchdr;  // 26
+       u8 reserved1[2];        // 2
+       u32 uivplaceholder[2];  // 8
+       u8 reserved2[4];        // 4
+} __attribute__ ((packed));
+
+// tx tfd with 24 byte mac header
+struct tx_tfd_24 {
+       struct machdr24 mchdr;  // 24
+       u32 uivplaceholder[2];  // 8
+       u8 reserved[8];         // 8
+} __attribute__ ((packed));
+
+#define DCT_WEP_KEY_FIELD_LENGTH 16
+
+struct tfd_command {
+       u8 index;
+       u8 length;
+       u16 reserved;
+       u8 payload[0];
+} __attribute__ ((packed));
+
+struct tfd_data {
+       /* Header */
+       u32 work_area_ptr;
+       u8 station_number;      /* 0 for BSS */
+       u8 reserved1;
+       u16 reserved2;
+
+       /* Tx Parameters */
+       u8 cmd_id;
+       u8 seq_num;
+       u16 len;
+       u8 priority;
+       u8 tx_flags;
+       u8 tx_flags_ext;
+       u8 key_index;
+       u8 wepkey[DCT_WEP_KEY_FIELD_LENGTH];
+       u8 rate;
+       u8 antenna;
+       u16 next_packet_duration;
+       u16 next_frag_len;
+       u16 back_off_counter;   //////txop;
+       u8 retrylimit;
+       u16 cwcurrent;
+       u8 reserved3;
+
+       /* 802.11 MAC Header */
+       union {
+               struct tx_tfd_24 tfd_24;
+               struct tx_tfd_26 tfd_26;
+               struct tx_tfd_30 tfd_30;
+               struct tx_tfd_32 tfd_32;
+       } tfd;
+
+       /* Payload DMA info */
+       u32 num_chunks;
+       u32 chunk_ptr[NUM_TFD_CHUNKS];
+       u16 chunk_len[NUM_TFD_CHUNKS];
+} __attribute__ ((packed));
+
+struct txrx_control_flags {
+       u8 message_type;
+       u8 rx_seq_num;
+       u8 control_bits;
+       u8 reserved;
+} __attribute__ ((packed));
+
+#define  TFD_SIZE                           128
+#define  TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH   (TFD_SIZE - sizeof(struct txrx_control_flags))
+
+struct tfd_frame {
+       struct txrx_control_flags control_flags;
+       union {
+               struct tfd_data data;
+               struct tfd_command cmd;
+               u8 raw[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH];
+       } u;
+} __attribute__ ((packed));
+
+typedef void destructor_func(const void *);
+
+/**
+ * Tx Queue for DMA. Queue consists of circular buffer of
+ * BD's and required locking structures.
+ */
+struct clx2_tx_queue {
+       struct clx2_queue q;
+       struct tfd_frame *bd;
+       struct ieee80211_txb **txb;
+};
+
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 32
+#define RX_LOW_WATERMARK 8
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS  (8)
+#define SUP_RATE_11B_MAX_NUM_CHANNELS  (4)
+#define SUP_RATE_11G_MAX_NUM_CHANNELS  (12)
+
+// Used for passing to driver number of successes and failures per rate
+struct rate_histogram {
+       union {
+               u32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+               u32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+               u32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+       } success;
+       union {
+               u32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+               u32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+               u32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+       } failed;
+} __attribute__ ((packed));
+
+/* statistics command response */
+struct ipw_cmd_stats {
+       u8 cmd_id;
+       u8 seq_num;
+       u16 good_sfd;
+       u16 bad_plcp;
+       u16 wrong_bssid;
+       u16 valid_mpdu;
+       u16 bad_mac_header;
+       u16 reserved_frame_types;
+       u16 rx_ina;
+       u16 bad_crc32;
+       u16 invalid_cts;
+       u16 invalid_acks;
+       u16 long_distance_ina_fina;
+       u16 dsp_silence_unreachable;
+       u16 accumulated_rssi;
+       u16 rx_ovfl_frame_tossed;
+       u16 rssi_silence_threshold;
+       u16 rx_ovfl_frame_supplied;
+       u16 last_rx_frame_signal;
+       u16 last_rx_frame_noise;
+       u16 rx_autodetec_no_ofdm;
+       u16 rx_autodetec_no_barker;
+       u16 reserved;
+} __attribute__ ((packed));
+
+struct notif_channel_result {
+       u8 channel_num;
+       struct ipw_cmd_stats stats;
+       u8 uReserved;
+} __attribute__ ((packed));
+
+struct notif_scan_complete {
+       u8 scan_type;
+       u8 num_channels;
+       u8 status;
+       u8 reserved;
+} __attribute__ ((packed));
+
+struct notif_frag_length {
+       u16 frag_length;
+       u16 reserved;
+} __attribute__ ((packed));
+
+struct notif_beacon_state {
+       u32 state;
+       u32 number;
+} __attribute__ ((packed));
+
+struct notif_tgi_tx_key {
+       u8 key_state;
+       u8 security_type;
+       u8 station_index;
+       u8 reserved;
+} __attribute__ ((packed));
+
+struct notif_link_deterioration {
+       struct ipw_cmd_stats stats;
+       u8 rate;
+       u8 modulation;
+       struct rate_histogram histogram;
+       u8 reserved1;
+       u16 reserved2;
+} __attribute__ ((packed));
+
+struct notif_association {
+       u8 state;
+} __attribute__ ((packed));
+
+struct notif_authenticate {
+       u8 state;
+       struct machdr24 addr;
+       u16 status;
+} __attribute__ ((packed));
+
+struct notif_calibration {
+       u8 data[104];
+} __attribute__ ((packed));
+
+struct notif_noise {
+       u32 value;
+} __attribute__ ((packed));
+
+struct ipw_rx_notification {
+       u8 reserved[8];
+       u8 subtype;
+       u8 flags;
+       u16 size;
+       union {
+               struct notif_association assoc;
+               struct notif_authenticate auth;
+               struct notif_channel_result channel_result;
+               struct notif_scan_complete scan_complete;
+               struct notif_frag_length frag_len;
+               struct notif_beacon_state beacon_state;
+               struct notif_tgi_tx_key tgi_tx_key;
+               struct notif_link_deterioration link_deterioration;
+               struct notif_calibration calibration;
+               struct notif_noise noise;
+               u8 raw[0];
+       } u;
+} __attribute__ ((packed));
+
+struct ipw_rx_frame {
+       u32 reserved1;
+       u8 parent_tsf[4];       // fw_use[0] is boolean for OUR_TSF_IS_GREATER
+       u8 received_channel;    // The channel that this frame was received on.
+       // Note that for .11b this does not have to be
+       // the same as the channel that it was sent.
+       // Filled by LMAC
+       u8 frameStatus;
+       u8 rate;
+       u8 rssi;
+       u8 agc;
+       u8 rssi_dbm;
+       u16 signal;
+       u16 noise;
+       u8 antennaAndPhy;
+       u8 control;             // control bit should be on in bg
+       u8 rtscts_rate;         // rate of rts or cts (in rts cts sequence rate
+       // is identical)
+       u8 rtscts_seen;         // 0x1 RTS seen ; 0x2 CTS seen
+       u16 length;
+       u8 data[0];
+} __attribute__ ((packed));
+
+struct ipw_rx_header {
+       u8 message_type;
+       u8 rx_seq_num;
+       u8 control_bits;
+       u8 reserved;
+} __attribute__ ((packed));
+
+struct ipw_rx_packet {
+       struct ipw_rx_header header;
+       union {
+               struct ipw_rx_frame frame;
+               struct ipw_rx_notification notification;
+       } u;
+} __attribute__ ((packed));
+
+#define IPW_RX_NOTIFICATION_SIZE sizeof(struct ipw_rx_header) + 12
+#define IPW_RX_FRAME_SIZE        sizeof(struct ipw_rx_header) + \
+                                 sizeof(struct ipw_rx_frame)
+
+struct ipw_rx_mem_buffer {
+       dma_addr_t dma_addr;
+       struct ipw_rx_buffer *rxb;
+       struct sk_buff *skb;
+       struct list_head list;
+};                             /* Not transferred over network, so not  __attribute__ ((packed)) */
+
+struct ipw_rx_queue {
+       struct ipw_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
+       struct ipw_rx_mem_buffer *queue[RX_QUEUE_SIZE];
+       u32 processed;          /* Internal index to last handled Rx packet */
+       u32 read;               /* Shared index to newest available Rx buffer */
+       u32 write;              /* Shared index to oldest written Rx packet */
+       u32 free_count;         /* Number of pre-allocated buffers in rx_free */
+       /* Each of these lists is used as a FIFO for ipw_rx_mem_buffers */
+       struct list_head rx_free;       /* Own an SKBs */
+       struct list_head rx_used;       /* No SKB allocated */
+       spinlock_t lock;
+};                             /* Not transferred over network, so not  __attribute__ ((packed)) */
+
+struct alive_command_responce {
+       u8 alive_command;
+       u8 sequence_number;
+       u16 software_revision;
+       u8 device_identifier;
+       u8 reserved1[5];
+       u16 reserved2;
+       u16 reserved3;
+       u16 clock_settle_time;
+       u16 powerup_settle_time;
+       u16 reserved4;
+       u8 time_stamp[5];       /* month, day, year, hours, minutes */
+       u8 ucode_valid;
+} __attribute__ ((packed));
+
+#define IPW_MAX_RATES 12
+
+struct ipw_rates {
+       u8 num_rates;
+       u8 rates[IPW_MAX_RATES];
+} __attribute__ ((packed));
+
+struct command_block {
+       unsigned int control;
+       u32 source_addr;
+       u32 dest_addr;
+       unsigned int status;
+} __attribute__ ((packed));
+
+#define CB_NUMBER_OF_ELEMENTS_SMALL 64
+struct fw_image_desc {
+       unsigned long last_cb_index;
+       unsigned long current_cb_index;
+       struct command_block cb_list[CB_NUMBER_OF_ELEMENTS_SMALL];
+       void *v_addr;
+       unsigned long p_addr;
+       unsigned long len;
+};
+
+struct ipw_sys_config {
+       u8 bt_coexistence;
+       u8 reserved1;
+       u8 answer_broadcast_ssid_probe;
+       u8 accept_all_data_frames;
+       u8 accept_non_directed_frames;
+       u8 exclude_unicast_unencrypted;
+       u8 disable_unicast_decryption;
+       u8 exclude_multicast_unencrypted;
+       u8 disable_multicast_decryption;
+       u8 antenna_diversity;
+       u8 pass_crc_to_host;
+       u8 dot11g_auto_detection;
+       u8 enable_cts_to_self;
+       u8 enable_multicast_filtering;
+       u8 bt_coexist_collision_thr;
+       u8 reserved2;
+       u8 accept_all_mgmt_bcpr;
+       u8 accept_all_mgtm_frames;
+       u8 pass_noise_stats_to_host;
+       u8 reserved3;
+} __attribute__ ((packed));
+
+struct ipw_multicast_addr {
+       u8 num_of_multicast_addresses;
+       u8 reserved[3];
+       u8 mac1[6];
+       u8 mac2[6];
+       u8 mac3[6];
+       u8 mac4[6];
+} __attribute__ ((packed));
+
+struct ipw_wep_key {
+       u8 cmd_id;
+       u8 seq_num;
+       u8 key_index;
+       u8 key_size;
+       u8 key[16];
+} __attribute__ ((packed));
+
+struct ipw_tgi_tx_key {
+       u8 key_id;
+       u8 security_type;
+       u8 station_index;
+       u8 flags;
+       u8 key[16];
+       u32 tx_counter[2];
+} __attribute__ ((packed));
+
+#define IPW_SCAN_CHANNELS 54
+
+struct ipw_scan_request {
+       u8 scan_type;
+       u16 dwell_time;
+       u8 channels_list[IPW_SCAN_CHANNELS];
+       u8 channels_reserved[3];
+} __attribute__ ((packed));
+
+enum {
+       IPW_SCAN_PASSIVE_TILL_FIRST_BEACON_SCAN = 0,
+       IPW_SCAN_PASSIVE_FULL_DWELL_SCAN,
+       IPW_SCAN_ACTIVE_DIRECT_SCAN,
+       IPW_SCAN_ACTIVE_BROADCAST_SCAN,
+       IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN,
+       IPW_SCAN_TYPES
+};
+
+struct ipw_scan_request_ext {
+       u32 full_scan_index;
+       u8 channels_list[IPW_SCAN_CHANNELS];
+       u8 scan_type[IPW_SCAN_CHANNELS / 2];
+       u8 reserved;
+       u16 dwell_time[IPW_SCAN_TYPES];
+} __attribute__ ((packed));
+
+extern inline u8 ipw_get_scan_type(struct ipw_scan_request_ext *scan, u8 index)
+{
+       if (index % 2)
+               return scan->scan_type[index / 2] & 0x0F;
+       else
+               return (scan->scan_type[index / 2] & 0xF0) >> 4;
+}
+
+extern inline void ipw_set_scan_type(struct ipw_scan_request_ext *scan,
+                                    u8 index, u8 scan_type)
+{
+       if (index % 2)
+               scan->scan_type[index / 2] =
+                   (scan->scan_type[index / 2] & 0xF0) | (scan_type & 0x0F);
+       else
+               scan->scan_type[index / 2] =
+                   (scan->scan_type[index / 2] & 0x0F) |
+                   ((scan_type & 0x0F) << 4);
+}
+
+struct ipw_associate {
+       u8 channel;
+       u8 auth_type:4, auth_key:4;
+       u8 assoc_type;
+       u8 reserved;
+       u16 policy_support;
+       u8 preamble_length;
+       u8 ieee_mode;
+       u8 bssid[ETH_ALEN];
+       u32 assoc_tsf_msw;
+       u32 assoc_tsf_lsw;
+       u16 capability;
+       u16 listen_interval;
+       u16 beacon_interval;
+       u8 dest[ETH_ALEN];
+       u16 atim_window;
+       u8 smr;
+       u8 reserved1;
+       u16 reserved2;
+} __attribute__ ((packed));
+
+struct ipw_supported_rates {
+       u8 ieee_mode;
+       u8 num_rates;
+       u8 purpose;
+       u8 reserved;
+       u8 supported_rates[IPW_MAX_RATES];
+} __attribute__ ((packed));
+
+struct ipw_rts_threshold {
+       u16 rts_threshold;
+       u16 reserved;
+} __attribute__ ((packed));
+
+struct ipw_frag_threshold {
+       u16 frag_threshold;
+       u16 reserved;
+} __attribute__ ((packed));
+
+struct ipw_retry_limit {
+       u8 short_retry_limit;
+       u8 long_retry_limit;
+       u16 reserved;
+} __attribute__ ((packed));
+
+struct ipw_dino_config {
+       u32 dino_config_addr;
+       u16 dino_config_size;
+       u8 dino_response;
+       u8 reserved;
+} __attribute__ ((packed));
+
+struct ipw_aironet_info {
+       u8 id;
+       u8 length;
+       u16 reserved;
+} __attribute__ ((packed));
+
+struct ipw_rx_key {
+       u8 station_index;
+       u8 key_type;
+       u8 key_id;
+       u8 key_flag;
+       u8 key[16];
+       u8 station_address[6];
+       u8 key_index;
+       u8 reserved;
+} __attribute__ ((packed));
+
+struct ipw_country_channel_info {
+       u8 first_channel;
+       u8 no_channels;
+       s8 max_tx_power;
+} __attribute__ ((packed));
+
+struct ipw_country_info {
+       u8 id;
+       u8 length;
+       u8 country_str[3];
+       struct ipw_country_channel_info groups[7];
+} __attribute__ ((packed));
+
+struct ipw_channel_tx_power {
+       u8 channel_number;
+       s8 tx_power;
+} __attribute__ ((packed));
+
+#define SCAN_ASSOCIATED_INTERVAL (HZ)
+#define SCAN_INTERVAL (HZ / 10)
+#define MAX_A_CHANNELS  37
+#define MAX_B_CHANNELS  14
+
+struct ipw_tx_power {
+       u8 num_channels;
+       u8 ieee_mode;
+       struct ipw_channel_tx_power channels_tx_power[MAX_A_CHANNELS];
+} __attribute__ ((packed));
+
+struct ipw_qos_parameters {
+       u16 cw_min[4];
+       u16 cw_max[4];
+       u8 aifs[4];
+       u8 flag[4];
+       u16 tx_op_limit[4];
+} __attribute__ ((packed));
+
+struct ipw_rsn_capabilities {
+       u8 id;
+       u8 length;
+       u16 version;
+} __attribute__ ((packed));
+
+struct ipw_sensitivity_calib {
+       u16 beacon_rssi_raw;
+       u16 reserved;
+} __attribute__ ((packed));
+
+/**
+ * Host command structure.
+ *
+ * On input, the following fields should be filled:
+ * - cmd
+ * - len
+ * - status_len
+ * - param (if needed)
+ *
+ * On output,
+ * - \a status contains status;
+ * - \a param filled with status parameters.
+ */
+struct ipw_cmd {
+       u32 cmd;   /**< Host command */
+       u32 status;/**< Status */
+       u32 status_len;
+                  /**< How many 32 bit parameters in the status */
+       u32 len;   /**< incoming parameters length, bytes */
+  /**
+   * command parameters.
+   * There should be enough space for incoming and
+   * outcoming parameters.
+   * Incoming parameters listed 1-st, followed by outcoming params.
+   * nParams=(len+3)/4+status_len
+   */
+       u32 param[0];
+} __attribute__ ((packed));
+
+#define STATUS_HCMD_ACTIVE      (1<<0) /**< host command in progress */
+
+#define STATUS_INT_ENABLED      (1<<1)
+#define STATUS_RF_KILL_HW       (1<<2)
+#define STATUS_RF_KILL_SW       (1<<3)
+#define STATUS_RF_KILL_MASK     (STATUS_RF_KILL_HW | STATUS_RF_KILL_SW)
+
+#define STATUS_INIT             (1<<5)
+#define STATUS_AUTH             (1<<6)
+#define STATUS_ASSOCIATED       (1<<7)
+#define STATUS_STATE_MASK       (STATUS_INIT | STATUS_AUTH | STATUS_ASSOCIATED)
+
+#define STATUS_ASSOCIATING      (1<<8)
+#define STATUS_DISASSOCIATING   (1<<9)
+#define STATUS_ROAMING          (1<<10)
+#define STATUS_EXIT_PENDING     (1<<11)
+#define STATUS_DISASSOC_PENDING (1<<12)
+#define STATUS_STATE_PENDING    (1<<13)
+
+#define STATUS_SCAN_PENDING     (1<<20)
+#define STATUS_SCANNING         (1<<21)
+#define STATUS_SCAN_ABORTING    (1<<22)
+
+#define STATUS_INDIRECT_BYTE    (1<<28)        /* sysfs entry configured for access */
+#define STATUS_INDIRECT_DWORD   (1<<29)        /* sysfs entry configured for access */
+#define STATUS_DIRECT_DWORD     (1<<30)        /* sysfs entry configured for access */
+
+#define STATUS_SECURITY_UPDATED (1<<31)        /* Security sync needed */
+
+#define CFG_STATIC_CHANNEL      (1<<0) /* Restrict assoc. to single channel */
+#define CFG_STATIC_ESSID        (1<<1) /* Restrict assoc. to single SSID */
+#define CFG_STATIC_BSSID        (1<<2) /* Restrict assoc. to single BSSID */
+#define CFG_CUSTOM_MAC          (1<<3)
+#define CFG_PREAMBLE            (1<<4)
+#define CFG_ADHOC_PERSIST       (1<<5)
+#define CFG_ASSOCIATE           (1<<6)
+#define CFG_FIXED_RATE          (1<<7)
+#define CFG_ADHOC_CREATE        (1<<8)
+
+#define CAP_SHARED_KEY          (1<<0) /* Off = OPEN */
+#define CAP_PRIVACY_ON          (1<<1) /* Off = No privacy */
+
+#define MAX_STATIONS            32
+#define IPW_INVALID_STATION     (0xff)
+
+struct ipw_station_entry {
+       u8 mac_addr[ETH_ALEN];
+       u8 reserved;
+       u8 support_mode;
+};
+
+#define AVG_ENTRIES 8
+struct average {
+       s16 entries[AVG_ENTRIES];
+       u8 pos;
+       u8 init;
+       s32 sum;
+};
+
+struct ipw_priv {
+       /* ieee device used by generic ieee processing code */
+       struct ieee80211_device *ieee;
+       struct ieee80211_security sec;
+
+       /* spinlock */
+       spinlock_t lock;
+
+       /* basic pci-network driver stuff */
+       struct pci_dev *pci_dev;
+       struct net_device *net_dev;
+
+       /* pci hardware address support */
+       void __iomem *hw_base;
+       unsigned long hw_len;
+
+       struct fw_image_desc sram_desc;
+
+       /* result of ucode download */
+       struct alive_command_responce dino_alive;
+
+       wait_queue_head_t wait_command_queue;
+       wait_queue_head_t wait_state;
+
+       /* Rx and Tx DMA processing queues */
+       struct ipw_rx_queue *rxq;
+       struct clx2_tx_queue txq_cmd;
+       struct clx2_tx_queue txq[4];
+       u32 status;
+       u32 config;
+       u32 capability;
+
+       u8 last_rx_rssi;
+       u8 last_noise;
+       struct average average_missed_beacons;
+       struct average average_rssi;
+       struct average average_noise;
+       u32 port_type;
+       int rx_bufs_min;          /**< minimum number of bufs in Rx queue */
+       int rx_pend_max;          /**< maximum pending buffers for one IRQ */
+       u32 hcmd_seq;             /**< sequence number for hcmd */
+       u32 missed_beacon_threshold;
+       u32 roaming_threshold;
+
+       struct ipw_associate assoc_request;
+       struct ieee80211_network *assoc_network;
+
+       unsigned long ts_scan_abort;
+       struct ipw_supported_rates rates;
+       struct ipw_rates phy[3];           /**< PHY restrictions, per band */
+       struct ipw_rates supp;             /**< software defined */
+       struct ipw_rates extended;         /**< use for corresp. IE, AP only */
+
+       struct notif_link_deterioration last_link_deterioration; /** for statistics */
+       struct ipw_cmd *hcmd; /**< host command currently executed */
+
+       wait_queue_head_t hcmd_wq;     /**< host command waits for execution */
+       u32 tsf_bcn[2];              /**< TSF from latest beacon */
+
+       struct notif_calibration calib; /**< last calibration */
+
+       /* ordinal interface with firmware */
+       u32 table0_addr;
+       u32 table0_len;
+       u32 table1_addr;
+       u32 table1_len;
+       u32 table2_addr;
+       u32 table2_len;
+
+       /* context information */
+       u8 essid[IW_ESSID_MAX_SIZE];
+       u8 essid_len;
+       u8 nick[IW_ESSID_MAX_SIZE];
+       u16 rates_mask;
+       u8 channel;
+       struct ipw_sys_config sys_config;
+       u32 power_mode;
+       u8 bssid[ETH_ALEN];
+       u16 rts_threshold;
+       u8 mac_addr[ETH_ALEN];
+       u8 num_stations;
+       u8 stations[MAX_STATIONS][ETH_ALEN];
+
+       u32 notif_missed_beacons;
+
+       /* Statistics and counters normalized with each association */
+       u32 last_missed_beacons;
+       u32 last_tx_packets;
+       u32 last_rx_packets;
+       u32 last_tx_failures;
+       u32 last_rx_err;
+       u32 last_rate;
+
+       u32 missed_adhoc_beacons;
+       u32 missed_beacons;
+       u32 rx_packets;
+       u32 tx_packets;
+       u32 quality;
+
+       /* eeprom */
+       u8 eeprom[0x100];       /* 256 bytes of eeprom */
+       int eeprom_delay;
+
+       struct iw_statistics wstats;
+
+       struct workqueue_struct *workqueue;
+
+       struct work_struct adhoc_check;
+       struct work_struct associate;
+       struct work_struct disassociate;
+       struct work_struct rx_replenish;
+       struct work_struct request_scan;
+       struct work_struct adapter_restart;
+       struct work_struct rf_kill;
+       struct work_struct up;
+       struct work_struct down;
+       struct work_struct gather_stats;
+       struct work_struct abort_scan;
+       struct work_struct roam;
+       struct work_struct scan_check;
+
+       struct tasklet_struct irq_tasklet;
+
+#define IPW_2200BG  1
+#define IPW_2915ABG 2
+       u8 adapter;
+
+#define IPW_DEFAULT_TX_POWER 0x14
+       u8 tx_power;
+
+#ifdef CONFIG_PM
+       u32 pm_state[16];
+#endif
+
+       /* network state */
+
+       /* Used to pass the current INTA value from ISR to Tasklet */
+       u32 isr_inta;
+
+       /* debugging info */
+       u32 indirect_dword;
+       u32 direct_dword;
+       u32 indirect_byte;
+};                             /*ipw_priv */
+
+/* debug macros */
+
+#ifdef CONFIG_IPW_DEBUG
+#define IPW_DEBUG(level, fmt, args...) \
+do { if (ipw_debug_level & (level)) \
+  printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \
+         in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+#else
+#define IPW_DEBUG(level, fmt, args...) do {} while (0)
+#endif                         /* CONFIG_IPW_DEBUG */
+
+/*
+ * To use the debug system;
+ *
+ * If you are defining a new debug classification, simply add it to the #define
+ * list here in the form of:
+ *
+ * #define IPW_DL_xxxx VALUE
+ *
+ * shifting value to the left one bit from the previous entry.  xxxx should be
+ * the name of the classification (for example, WEP)
+ *
+ * You then need to either add a IPW_xxxx_DEBUG() macro definition for your
+ * classification, or use IPW_DEBUG(IPW_DL_xxxx, ...) whenever you want
+ * to send output to that classification.
+ *
+ * To add your debug level to the list of levels seen when you perform
+ *
+ * % cat /proc/net/ipw/debug_level
+ *
+ * you simply need to add your entry to the ipw_debug_levels array.
+ *
+ * If you do not see debug_level in /proc/net/ipw then you do not have
+ * CONFIG_IPW_DEBUG defined in your kernel configuration
+ *
+ */
+
+#define IPW_DL_ERROR         (1<<0)
+#define IPW_DL_WARNING       (1<<1)
+#define IPW_DL_INFO          (1<<2)
+#define IPW_DL_WX            (1<<3)
+#define IPW_DL_HOST_COMMAND  (1<<5)
+#define IPW_DL_STATE         (1<<6)
+
+#define IPW_DL_NOTIF         (1<<10)
+#define IPW_DL_SCAN          (1<<11)
+#define IPW_DL_ASSOC         (1<<12)
+#define IPW_DL_DROP          (1<<13)
+#define IPW_DL_IOCTL         (1<<14)
+
+#define IPW_DL_MANAGE        (1<<15)
+#define IPW_DL_FW            (1<<16)
+#define IPW_DL_RF_KILL       (1<<17)
+#define IPW_DL_FW_ERRORS     (1<<18)
+
+#define IPW_DL_ORD           (1<<20)
+
+#define IPW_DL_FRAG          (1<<21)
+#define IPW_DL_WEP           (1<<22)
+#define IPW_DL_TX            (1<<23)
+#define IPW_DL_RX            (1<<24)
+#define IPW_DL_ISR           (1<<25)
+#define IPW_DL_FW_INFO       (1<<26)
+#define IPW_DL_IO            (1<<27)
+#define IPW_DL_TRACE         (1<<28)
+
+#define IPW_DL_STATS         (1<<29)
+
+#define IPW_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
+#define IPW_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
+#define IPW_DEBUG_INFO(f, a...)    IPW_DEBUG(IPW_DL_INFO, f, ## a)
+
+#define IPW_DEBUG_WX(f, a...)     IPW_DEBUG(IPW_DL_WX, f, ## a)
+#define IPW_DEBUG_SCAN(f, a...)   IPW_DEBUG(IPW_DL_SCAN, f, ## a)
+#define IPW_DEBUG_STATUS(f, a...) IPW_DEBUG(IPW_DL_STATUS, f, ## a)
+#define IPW_DEBUG_TRACE(f, a...)  IPW_DEBUG(IPW_DL_TRACE, f, ## a)
+#define IPW_DEBUG_RX(f, a...)     IPW_DEBUG(IPW_DL_RX, f, ## a)
+#define IPW_DEBUG_TX(f, a...)     IPW_DEBUG(IPW_DL_TX, f, ## a)
+#define IPW_DEBUG_ISR(f, a...)    IPW_DEBUG(IPW_DL_ISR, f, ## a)
+#define IPW_DEBUG_MANAGEMENT(f, a...) IPW_DEBUG(IPW_DL_MANAGE, f, ## a)
+#define IPW_DEBUG_WEP(f, a...)    IPW_DEBUG(IPW_DL_WEP, f, ## a)
+#define IPW_DEBUG_HC(f, a...) IPW_DEBUG(IPW_DL_HOST_COMMAND, f, ## a)
+#define IPW_DEBUG_FRAG(f, a...) IPW_DEBUG(IPW_DL_FRAG, f, ## a)
+#define IPW_DEBUG_FW(f, a...) IPW_DEBUG(IPW_DL_FW, f, ## a)
+#define IPW_DEBUG_RF_KILL(f, a...) IPW_DEBUG(IPW_DL_RF_KILL, f, ## a)
+#define IPW_DEBUG_DROP(f, a...) IPW_DEBUG(IPW_DL_DROP, f, ## a)
+#define IPW_DEBUG_IO(f, a...) IPW_DEBUG(IPW_DL_IO, f, ## a)
+#define IPW_DEBUG_ORD(f, a...) IPW_DEBUG(IPW_DL_ORD, f, ## a)
+#define IPW_DEBUG_FW_INFO(f, a...) IPW_DEBUG(IPW_DL_FW_INFO, f, ## a)
+#define IPW_DEBUG_NOTIF(f, a...) IPW_DEBUG(IPW_DL_NOTIF, f, ## a)
+#define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
+#define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
+#define IPW_DEBUG_STATS(f, a...) IPW_DEBUG(IPW_DL_STATS, f, ## a)
+
+#include <linux/ctype.h>
+
+/*
+* Register bit definitions
+*/
+
+/* Dino control registers bits */
+
+#define DINO_ENABLE_SYSTEM 0x80
+#define DINO_ENABLE_CS     0x40
+#define DINO_RXFIFO_DATA   0x01
+#define DINO_CONTROL_REG   0x00200000
+
+#define CX2_INTA_RW       0x00000008
+#define CX2_INTA_MASK_R   0x0000000C
+#define CX2_INDIRECT_ADDR 0x00000010
+#define CX2_INDIRECT_DATA 0x00000014
+#define CX2_AUTOINC_ADDR  0x00000018
+#define CX2_AUTOINC_DATA  0x0000001C
+#define CX2_RESET_REG     0x00000020
+#define CX2_GP_CNTRL_RW   0x00000024
+
+#define CX2_READ_INT_REGISTER 0xFF4
+
+#define CX2_GP_CNTRL_BIT_INIT_DONE     0x00000004
+
+#define CX2_REGISTER_DOMAIN1_END        0x00001000
+#define CX2_SRAM_READ_INT_REGISTER     0x00000ff4
+
+#define CX2_SHARED_LOWER_BOUND          0x00000200
+#define CX2_INTERRUPT_AREA_LOWER_BOUND  0x00000f80
+
+#define CX2_NIC_SRAM_LOWER_BOUND        0x00000000
+#define CX2_NIC_SRAM_UPPER_BOUND        0x00030000
+
+#define CX2_BIT_INT_HOST_SRAM_READ_INT_REGISTER (1 << 29)
+#define CX2_GP_CNTRL_BIT_CLOCK_READY    0x00000001
+#define CX2_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY 0x00000002
+
+/*
+ * RESET Register Bit Indexes
+ */
+#define CBD_RESET_REG_PRINCETON_RESET 0x00000001       /* Bit 0 (LSB) */
+#define CX2_RESET_REG_SW_RESET        0x00000080       /* Bit 7       */
+#define CX2_RESET_REG_MASTER_DISABLED 0x00000100       /* Bit 8       */
+#define CX2_RESET_REG_STOP_MASTER     0x00000200       /* Bit 9       */
+#define CX2_ARC_KESHET_CONFIG         0x08000000       /* Bit 27      */
+#define CX2_START_STANDBY             0x00000004       /* Bit 2       */
+
+#define CX2_CSR_CIS_UPPER_BOUND        0x00000200
+#define CX2_DOMAIN_0_END 0x1000
+#define CLX_MEM_BAR_SIZE 0x1000
+
+#define CX2_BASEBAND_CONTROL_STATUS    0X00200000
+#define CX2_BASEBAND_TX_FIFO_WRITE     0X00200004
+#define CX2_BASEBAND_RX_FIFO_READ      0X00200004
+#define CX2_BASEBAND_CONTROL_STORE     0X00200010
+
+#define CX2_INTERNAL_CMD_EVENT         0X00300004
+#define CX2_BASEBAND_POWER_DOWN 0x00000001
+
+#define CX2_MEM_HALT_AND_RESET  0x003000e0
+
+/* defgroup bits_halt_reset MEM_HALT_AND_RESET register bits */
+#define CX2_BIT_HALT_RESET_ON  0x80000000
+#define CX2_BIT_HALT_RESET_OFF         0x00000000
+
+#define CB_LAST_VALID     0x20000000
+#define CB_INT_ENABLED    0x40000000
+#define CB_VALID          0x80000000
+#define CB_SRC_LE         0x08000000
+#define CB_DEST_LE        0x04000000
+#define CB_SRC_AUTOINC    0x00800000
+#define CB_SRC_IO_GATED   0x00400000
+#define CB_DEST_AUTOINC   0x00080000
+#define CB_SRC_SIZE_LONG  0x00200000
+#define CB_DEST_SIZE_LONG 0x00020000
+
+/* DMA DEFINES */
+
+#define DMA_CONTROL_SMALL_CB_CONST_VALUE 0x00540000
+#define DMA_CB_STOP_AND_ABORT            0x00000C00
+#define DMA_CB_START                     0x00000100
+
+#define CX2_SHARED_SRAM_SIZE               0x00030000
+#define CX2_SHARED_SRAM_DMA_CONTROL        0x00027000
+#define CB_MAX_LENGTH                      0x1FFF
+
+#define CX2_HOST_EEPROM_DATA_SRAM_SIZE 0xA18
+#define CX2_EEPROM_IMAGE_SIZE          0x100
+
+/* DMA defs */
+#define CX2_DMA_I_CURRENT_CB  0x003000D0
+#define CX2_DMA_O_CURRENT_CB  0x003000D4
+#define CX2_DMA_I_DMA_CONTROL 0x003000A4
+#define CX2_DMA_I_CB_BASE     0x003000A0
+
+#define CX2_TX_CMD_QUEUE_BD_BASE        (0x00000200)
+#define CX2_TX_CMD_QUEUE_BD_SIZE        (0x00000204)
+#define CX2_TX_QUEUE_0_BD_BASE          (0x00000208)
+#define CX2_TX_QUEUE_0_BD_SIZE          (0x0000020C)
+#define CX2_TX_QUEUE_1_BD_BASE          (0x00000210)
+#define CX2_TX_QUEUE_1_BD_SIZE          (0x00000214)
+#define CX2_TX_QUEUE_2_BD_BASE          (0x00000218)
+#define CX2_TX_QUEUE_2_BD_SIZE          (0x0000021C)
+#define CX2_TX_QUEUE_3_BD_BASE          (0x00000220)
+#define CX2_TX_QUEUE_3_BD_SIZE          (0x00000224)
+#define CX2_RX_BD_BASE                  (0x00000240)
+#define CX2_RX_BD_SIZE                  (0x00000244)
+#define CX2_RFDS_TABLE_LOWER            (0x00000500)
+
+#define CX2_TX_CMD_QUEUE_READ_INDEX     (0x00000280)
+#define CX2_TX_QUEUE_0_READ_INDEX       (0x00000284)
+#define CX2_TX_QUEUE_1_READ_INDEX       (0x00000288)
+#define CX2_TX_QUEUE_2_READ_INDEX       (0x0000028C)
+#define CX2_TX_QUEUE_3_READ_INDEX       (0x00000290)
+#define CX2_RX_READ_INDEX               (0x000002A0)
+
+#define CX2_TX_CMD_QUEUE_WRITE_INDEX    (0x00000F80)
+#define CX2_TX_QUEUE_0_WRITE_INDEX      (0x00000F84)
+#define CX2_TX_QUEUE_1_WRITE_INDEX      (0x00000F88)
+#define CX2_TX_QUEUE_2_WRITE_INDEX      (0x00000F8C)
+#define CX2_TX_QUEUE_3_WRITE_INDEX      (0x00000F90)
+#define CX2_RX_WRITE_INDEX              (0x00000FA0)
+
+/*
+ * EEPROM Related Definitions
+ */
+
+#define IPW_EEPROM_DATA_SRAM_ADDRESS (CX2_SHARED_LOWER_BOUND + 0x814)
+#define IPW_EEPROM_DATA_SRAM_SIZE    (CX2_SHARED_LOWER_BOUND + 0x818)
+#define IPW_EEPROM_LOAD_DISABLE      (CX2_SHARED_LOWER_BOUND + 0x81C)
+#define IPW_EEPROM_DATA              (CX2_SHARED_LOWER_BOUND + 0x820)
+#define IPW_EEPROM_UPPER_ADDRESS     (CX2_SHARED_LOWER_BOUND + 0x9E0)
+
+#define IPW_STATION_TABLE_LOWER      (CX2_SHARED_LOWER_BOUND + 0xA0C)
+#define IPW_STATION_TABLE_UPPER      (CX2_SHARED_LOWER_BOUND + 0xB0C)
+#define IPW_REQUEST_ATIM             (CX2_SHARED_LOWER_BOUND + 0xB0C)
+#define IPW_ATIM_SENT                (CX2_SHARED_LOWER_BOUND + 0xB10)
+#define IPW_WHO_IS_AWAKE             (CX2_SHARED_LOWER_BOUND + 0xB14)
+#define IPW_DURING_ATIM_WINDOW       (CX2_SHARED_LOWER_BOUND + 0xB18)
+
+#define MSB                             1
+#define LSB                             0
+#define WORD_TO_BYTE(_word)             ((_word) * sizeof(u16))
+
+#define GET_EEPROM_ADDR(_wordoffset,_byteoffset) \
+    ( WORD_TO_BYTE(_wordoffset) + (_byteoffset) )
+
+/* EEPROM access by BYTE */
+#define EEPROM_PME_CAPABILITY   (GET_EEPROM_ADDR(0x09,MSB))    /* 1 byte   */
+#define EEPROM_MAC_ADDRESS      (GET_EEPROM_ADDR(0x21,LSB))    /* 6 byte   */
+#define EEPROM_VERSION          (GET_EEPROM_ADDR(0x24,MSB))    /* 1 byte   */
+#define EEPROM_NIC_TYPE         (GET_EEPROM_ADDR(0x25,LSB))    /* 1 byte   */
+#define EEPROM_SKU_CAPABILITY   (GET_EEPROM_ADDR(0x25,MSB))    /* 1 byte   */
+#define EEPROM_COUNTRY_CODE     (GET_EEPROM_ADDR(0x26,LSB))    /* 3 bytes  */
+#define EEPROM_IBSS_CHANNELS_BG (GET_EEPROM_ADDR(0x28,LSB))    /* 2 bytes  */
+#define EEPROM_IBSS_CHANNELS_A  (GET_EEPROM_ADDR(0x29,MSB))    /* 5 bytes  */
+#define EEPROM_BSS_CHANNELS_BG  (GET_EEPROM_ADDR(0x2c,LSB))    /* 2 bytes  */
+#define EEPROM_HW_VERSION       (GET_EEPROM_ADDR(0x72,LSB))    /* 2 bytes  */
+
+/* NIC type as found in the one byte EEPROM_NIC_TYPE  offset*/
+#define EEPROM_NIC_TYPE_STANDARD        0
+#define EEPROM_NIC_TYPE_DELL            1
+#define EEPROM_NIC_TYPE_FUJITSU         2
+#define EEPROM_NIC_TYPE_IBM             3
+#define EEPROM_NIC_TYPE_HP              4
+
+#define FW_MEM_REG_LOWER_BOUND          0x00300000
+#define FW_MEM_REG_EEPROM_ACCESS        (FW_MEM_REG_LOWER_BOUND + 0x40)
+
+#define EEPROM_BIT_SK                   (1<<0)
+#define EEPROM_BIT_CS                   (1<<1)
+#define EEPROM_BIT_DI                   (1<<2)
+#define EEPROM_BIT_DO                   (1<<4)
+
+#define EEPROM_CMD_READ                 0x2
+
+/* Interrupts masks */
+#define CX2_INTA_NONE   0x00000000
+
+#define CX2_INTA_BIT_RX_TRANSFER                   0x00000002
+#define CX2_INTA_BIT_STATUS_CHANGE                 0x00000010
+#define CX2_INTA_BIT_BEACON_PERIOD_EXPIRED         0x00000020
+
+//Inta Bits for CF
+#define CX2_INTA_BIT_TX_CMD_QUEUE                  0x00000800
+#define CX2_INTA_BIT_TX_QUEUE_1                    0x00001000
+#define CX2_INTA_BIT_TX_QUEUE_2                    0x00002000
+#define CX2_INTA_BIT_TX_QUEUE_3                    0x00004000
+#define CX2_INTA_BIT_TX_QUEUE_4                    0x00008000
+
+#define CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE      0x00010000
+
+#define CX2_INTA_BIT_PREPARE_FOR_POWER_DOWN        0x00100000
+#define CX2_INTA_BIT_POWER_DOWN                    0x00200000
+
+#define CX2_INTA_BIT_FW_INITIALIZATION_DONE        0x01000000
+#define CX2_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE  0x02000000
+#define CX2_INTA_BIT_RF_KILL_DONE                  0x04000000
+#define CX2_INTA_BIT_FATAL_ERROR             0x40000000
+#define CX2_INTA_BIT_PARITY_ERROR            0x80000000
+
+/* Interrupts enabled at init time. */
+#define CX2_INTA_MASK_ALL                        \
+        (CX2_INTA_BIT_TX_QUEUE_1               | \
+        CX2_INTA_BIT_TX_QUEUE_2               | \
+        CX2_INTA_BIT_TX_QUEUE_3               | \
+        CX2_INTA_BIT_TX_QUEUE_4               | \
+        CX2_INTA_BIT_TX_CMD_QUEUE             | \
+        CX2_INTA_BIT_RX_TRANSFER              | \
+        CX2_INTA_BIT_FATAL_ERROR              | \
+        CX2_INTA_BIT_PARITY_ERROR             | \
+        CX2_INTA_BIT_STATUS_CHANGE            | \
+        CX2_INTA_BIT_FW_INITIALIZATION_DONE   | \
+        CX2_INTA_BIT_BEACON_PERIOD_EXPIRED    | \
+        CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE | \
+        CX2_INTA_BIT_PREPARE_FOR_POWER_DOWN   | \
+        CX2_INTA_BIT_POWER_DOWN               | \
+         CX2_INTA_BIT_RF_KILL_DONE )
+
+#define IPWSTATUS_ERROR_LOG     (CX2_SHARED_LOWER_BOUND + 0x410)
+#define IPW_EVENT_LOG     (CX2_SHARED_LOWER_BOUND + 0x414)
+
+/* FW event log definitions */
+#define EVENT_ELEM_SIZE     (3 * sizeof(u32))
+#define EVENT_START_OFFSET  (1 * sizeof(u32) + 2 * sizeof(u16))
+
+/* FW error log definitions */
+#define ERROR_ELEM_SIZE     (7 * sizeof(u32))
+#define ERROR_START_OFFSET  (1 * sizeof(u32))
+
+enum {
+       IPW_FW_ERROR_OK = 0,
+       IPW_FW_ERROR_FAIL,
+       IPW_FW_ERROR_MEMORY_UNDERFLOW,
+       IPW_FW_ERROR_MEMORY_OVERFLOW,
+       IPW_FW_ERROR_BAD_PARAM,
+       IPW_FW_ERROR_BAD_CHECKSUM,
+       IPW_FW_ERROR_NMI_INTERRUPT,
+       IPW_FW_ERROR_BAD_DATABASE,
+       IPW_FW_ERROR_ALLOC_FAIL,
+       IPW_FW_ERROR_DMA_UNDERRUN,
+       IPW_FW_ERROR_DMA_STATUS,
+       IPW_FW_ERROR_DINOSTATUS_ERROR,
+       IPW_FW_ERROR_EEPROMSTATUS_ERROR,
+       IPW_FW_ERROR_SYSASSERT,
+       IPW_FW_ERROR_FATAL_ERROR
+};
+
+#define AUTH_OPEN       0
+#define AUTH_SHARED_KEY 1
+#define AUTH_IGNORE     3
+
+#define HC_ASSOCIATE      0
+#define HC_REASSOCIATE    1
+#define HC_DISASSOCIATE   2
+#define HC_IBSS_START     3
+#define HC_IBSS_RECONF    4
+#define HC_DISASSOC_QUIET 5
+
+#define IPW_RATE_CAPABILITIES 1
+#define IPW_RATE_CONNECT      0
+
+/*
+ * Rate values and masks
+ */
+#define IPW_TX_RATE_1MB  0x0A
+#define IPW_TX_RATE_2MB  0x14
+#define IPW_TX_RATE_5MB  0x37
+#define IPW_TX_RATE_6MB  0x0D
+#define IPW_TX_RATE_9MB  0x0F
+#define IPW_TX_RATE_11MB 0x6E
+#define IPW_TX_RATE_12MB 0x05
+#define IPW_TX_RATE_18MB 0x07
+#define IPW_TX_RATE_24MB 0x09
+#define IPW_TX_RATE_36MB 0x0B
+#define IPW_TX_RATE_48MB 0x01
+#define IPW_TX_RATE_54MB 0x03
+
+#define IPW_ORD_TABLE_ID_MASK             0x0000FF00
+#define IPW_ORD_TABLE_VALUE_MASK          0x000000FF
+
+#define IPW_ORD_TABLE_0_MASK              0x0000F000
+#define IPW_ORD_TABLE_1_MASK              0x0000F100
+#define IPW_ORD_TABLE_2_MASK              0x0000F200
+#define IPW_ORD_TABLE_3_MASK              0x0000F300
+#define IPW_ORD_TABLE_4_MASK              0x0000F400
+#define IPW_ORD_TABLE_5_MASK              0x0000F500
+#define IPW_ORD_TABLE_6_MASK              0x0000F600
+#define IPW_ORD_TABLE_7_MASK              0x0000F700
+
+/*
+ * Table 0 Entries (all entries are 32 bits)
+ */
+enum {
+       IPW_ORD_STAT_TX_CURR_RATE = IPW_ORD_TABLE_0_MASK + 1,
+       IPW_ORD_STAT_FRAG_TRESHOLD,
+       IPW_ORD_STAT_RTS_THRESHOLD,
+       IPW_ORD_STAT_TX_HOST_REQUESTS,
+       IPW_ORD_STAT_TX_HOST_COMPLETE,
+       IPW_ORD_STAT_TX_DIR_DATA,
+       IPW_ORD_STAT_TX_DIR_DATA_B_1,
+       IPW_ORD_STAT_TX_DIR_DATA_B_2,
+       IPW_ORD_STAT_TX_DIR_DATA_B_5_5,
+       IPW_ORD_STAT_TX_DIR_DATA_B_11,
+       /* Hole */
+
+       IPW_ORD_STAT_TX_DIR_DATA_G_1 = IPW_ORD_TABLE_0_MASK + 19,
+       IPW_ORD_STAT_TX_DIR_DATA_G_2,
+       IPW_ORD_STAT_TX_DIR_DATA_G_5_5,
+       IPW_ORD_STAT_TX_DIR_DATA_G_6,
+       IPW_ORD_STAT_TX_DIR_DATA_G_9,
+       IPW_ORD_STAT_TX_DIR_DATA_G_11,
+       IPW_ORD_STAT_TX_DIR_DATA_G_12,
+       IPW_ORD_STAT_TX_DIR_DATA_G_18,
+       IPW_ORD_STAT_TX_DIR_DATA_G_24,
+       IPW_ORD_STAT_TX_DIR_DATA_G_36,
+       IPW_ORD_STAT_TX_DIR_DATA_G_48,
+       IPW_ORD_STAT_TX_DIR_DATA_G_54,
+       IPW_ORD_STAT_TX_NON_DIR_DATA,
+       IPW_ORD_STAT_TX_NON_DIR_DATA_B_1,
+       IPW_ORD_STAT_TX_NON_DIR_DATA_B_2,
+       IPW_ORD_STAT_TX_NON_DIR_DATA_B_5_5,
+       IPW_ORD_STAT_TX_NON_DIR_DATA_B_11,
+       /* Hole */
+
+       IPW_ORD_STAT_TX_NON_DIR_DATA_G_1 = IPW_ORD_TABLE_0_MASK + 44,
+       IPW_ORD_STAT_TX_NON_DIR_DATA_G_2,
+       IPW_ORD_STAT_TX_NON_DIR_DATA_G_5_5,
+       IPW_ORD_STAT_TX_NON_DIR_DATA_G_6,
+       IPW_ORD_STAT_TX_NON_DIR_DATA_G_9,
+       IPW_ORD_STAT_TX_NON_DIR_DATA_G_11,
+       IPW_ORD_STAT_TX_NON_DIR_DATA_G_12,
+       IPW_ORD_STAT_TX_NON_DIR_DATA_G_18,
+       IPW_ORD_STAT_TX_NON_DIR_DATA_G_24,
+       IPW_ORD_STAT_TX_NON_DIR_DATA_G_36,
+       IPW_ORD_STAT_TX_NON_DIR_DATA_G_48,
+       IPW_ORD_STAT_TX_NON_DIR_DATA_G_54,
+       IPW_ORD_STAT_TX_RETRY,
+       IPW_ORD_STAT_TX_FAILURE,
+       IPW_ORD_STAT_RX_ERR_CRC,
+       IPW_ORD_STAT_RX_ERR_ICV,
+       IPW_ORD_STAT_RX_NO_BUFFER,
+       IPW_ORD_STAT_FULL_SCANS,
+       IPW_ORD_STAT_PARTIAL_SCANS,
+       IPW_ORD_STAT_TGH_ABORTED_SCANS,
+       IPW_ORD_STAT_TX_TOTAL_BYTES,
+       IPW_ORD_STAT_CURR_RSSI_RAW,
+       IPW_ORD_STAT_RX_BEACON,
+       IPW_ORD_STAT_MISSED_BEACONS,
+       IPW_ORD_TABLE_0_LAST
+};
+
+#define IPW_RSSI_TO_DBM 112
+
+/* Table 1 Entries
+ */
+enum {
+       IPW_ORD_TABLE_1_LAST = IPW_ORD_TABLE_1_MASK | 1,
+};
+
+/*
+ * Table 2 Entries
+ *
+ * FW_VERSION:    16 byte string
+ * FW_DATE:       16 byte string (only 14 bytes used)
+ * UCODE_VERSION: 4 byte version code
+ * UCODE_DATE:    5 bytes code code
+ * ADDAPTER_MAC:  6 byte MAC address
+ * RTC:           4 byte clock
+ */
+enum {
+       IPW_ORD_STAT_FW_VERSION = IPW_ORD_TABLE_2_MASK | 1,
+       IPW_ORD_STAT_FW_DATE,
+       IPW_ORD_STAT_UCODE_VERSION,
+       IPW_ORD_STAT_UCODE_DATE,
+       IPW_ORD_STAT_ADAPTER_MAC,
+       IPW_ORD_STAT_RTC,
+       IPW_ORD_TABLE_2_LAST
+};
+
+/* Table 3 */
+enum {
+       IPW_ORD_STAT_TX_PACKET = IPW_ORD_TABLE_3_MASK | 0,
+       IPW_ORD_STAT_TX_PACKET_FAILURE,
+       IPW_ORD_STAT_TX_PACKET_SUCCESS,
+       IPW_ORD_STAT_TX_PACKET_ABORTED,
+       IPW_ORD_TABLE_3_LAST
+};
+
+/* Table 4 */
+enum {
+       IPW_ORD_TABLE_4_LAST = IPW_ORD_TABLE_4_MASK
+};
+
+/* Table 5 */
+enum {
+       IPW_ORD_STAT_AVAILABLE_AP_COUNT = IPW_ORD_TABLE_5_MASK,
+       IPW_ORD_STAT_AP_ASSNS,
+       IPW_ORD_STAT_ROAM,
+       IPW_ORD_STAT_ROAM_CAUSE_MISSED_BEACONS,
+       IPW_ORD_STAT_ROAM_CAUSE_UNASSOC,
+       IPW_ORD_STAT_ROAM_CAUSE_RSSI,
+       IPW_ORD_STAT_ROAM_CAUSE_LINK_QUALITY,
+       IPW_ORD_STAT_ROAM_CAUSE_AP_LOAD_BALANCE,
+       IPW_ORD_STAT_ROAM_CAUSE_AP_NO_TX,
+       IPW_ORD_STAT_LINK_UP,
+       IPW_ORD_STAT_LINK_DOWN,
+       IPW_ORD_ANTENNA_DIVERSITY,
+       IPW_ORD_CURR_FREQ,
+       IPW_ORD_TABLE_5_LAST
+};
+
+/* Table 6 */
+enum {
+       IPW_ORD_COUNTRY_CODE = IPW_ORD_TABLE_6_MASK,
+       IPW_ORD_CURR_BSSID,
+       IPW_ORD_CURR_SSID,
+       IPW_ORD_TABLE_6_LAST
+};
+
+/* Table 7 */
+enum {
+       IPW_ORD_STAT_PERCENT_MISSED_BEACONS = IPW_ORD_TABLE_7_MASK,
+       IPW_ORD_STAT_PERCENT_TX_RETRIES,
+       IPW_ORD_STAT_PERCENT_LINK_QUALITY,
+       IPW_ORD_STAT_CURR_RSSI_DBM,
+       IPW_ORD_TABLE_7_LAST
+};
+
+#define IPW_ORDINALS_TABLE_LOWER        (CX2_SHARED_LOWER_BOUND + 0x500)
+#define IPW_ORDINALS_TABLE_0            (CX2_SHARED_LOWER_BOUND + 0x180)
+#define IPW_ORDINALS_TABLE_1            (CX2_SHARED_LOWER_BOUND + 0x184)
+#define IPW_ORDINALS_TABLE_2            (CX2_SHARED_LOWER_BOUND + 0x188)
+#define IPW_MEM_FIXED_OVERRIDE          (CX2_SHARED_LOWER_BOUND + 0x41C)
+
+struct ipw_fixed_rate {
+       u16 tx_rates;
+       u16 reserved;
+} __attribute__ ((packed));
+
+#define CX2_INDIRECT_ADDR_MASK (~0x3ul)
+
+struct host_cmd {
+       u8 cmd;
+       u8 len;
+       u16 reserved;
+       u32 param[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH];
+} __attribute__ ((packed));
+
+#define CFG_BT_COEXISTENCE_MIN                  0x00
+#define CFG_BT_COEXISTENCE_DEFER                0x02
+#define CFG_BT_COEXISTENCE_KILL                 0x04
+#define CFG_BT_COEXISTENCE_WME_OVER_BT          0x08
+#define CFG_BT_COEXISTENCE_OOB                  0x10
+#define CFG_BT_COEXISTENCE_MAX                  0xFF
+#define CFG_BT_COEXISTENCE_DEF                  0x80   /* read Bt from EEPROM */
+
+#define CFG_CTS_TO_ITSELF_ENABLED_MIN  0x0
+#define CFG_CTS_TO_ITSELF_ENABLED_MAX  0x1
+#define CFG_CTS_TO_ITSELF_ENABLED_DEF  CFG_CTS_TO_ITSELF_ENABLED_MIN
+
+#define CFG_SYS_ANTENNA_BOTH                      0x000
+#define CFG_SYS_ANTENNA_A                         0x001
+#define CFG_SYS_ANTENNA_B                         0x003
+
+/*
+ * The definitions below were lifted off the ipw2100 driver, which only
+ * supports 'b' mode, so I'm sure these are not exactly correct.
+ *
+ * Somebody fix these!!
+ */
+#define REG_MIN_CHANNEL             0
+#define REG_MAX_CHANNEL             14
+
+#define REG_CHANNEL_MASK            0x00003FFF
+#define IPW_IBSS_11B_DEFAULT_MASK   0x87ff
+
+static const long ipw_frequencies[] = {
+       2412, 2417, 2422, 2427,
+       2432, 2437, 2442, 2447,
+       2452, 2457, 2462, 2467,
+       2472, 2484
+};
+
+#define FREQ_COUNT ARRAY_SIZE(ipw_frequencies)
+
+#define IPW_MAX_CONFIG_RETRIES 10
+
+static inline u32 frame_hdr_len(struct ieee80211_hdr *hdr)
+{
+       u32 retval;
+       u16 fc;
+
+       retval = sizeof(struct ieee80211_hdr);
+       fc = le16_to_cpu(hdr->frame_ctl);
+
+       /*
+        * Function     ToDS    FromDS
+        * IBSS         0       0
+        * To AP        1       0
+        * From AP      0       1
+        * WDS (bridge) 1       1
+        *
+        * Only WDS frames use Address4 among them. --YZ
+        */
+       if (!(fc & IEEE80211_FCTL_TODS) || !(fc & IEEE80211_FCTL_FROMDS))
+               retval -= ETH_ALEN;
+
+       return retval;
+}
+
+#endif                         /* __ipw2200_h__ */
index 5f507c49907b34c80b466374aa42180c6541a101..ca6c03c89926ca89605c5b881a2ccabc0cb81411 100644 (file)
@@ -471,12 +471,12 @@ static dev_link_t *netwave_attach(void)
     dev->get_stats  = &netwave_get_stats;
     dev->set_multicast_list = &set_multicast_list;
     /* wireless extensions */
-#ifdef WIRELESS_EXT
+#if WIRELESS_EXT <= 16
     dev->get_wireless_stats = &netwave_get_wireless_stats;
+#endif /* WIRELESS_EXT <= 16 */
 #if WIRELESS_EXT > 12
     dev->wireless_handlers = (struct iw_handler_def *)&netwave_handler_def;
 #endif /* WIRELESS_EXT > 12 */
-#endif /* WIRELESS_EXT */
     dev->do_ioctl = &netwave_ioctl;
 
     dev->tx_timeout = &netwave_watchdog;
@@ -839,6 +839,9 @@ static const struct iw_handler_def  netwave_handler_def =
        .standard       = (iw_handler *) netwave_handler,
        .private        = (iw_handler *) netwave_private_handler,
        .private_args   = (struct iw_priv_args *) netwave_private_args,
+#if WIRELESS_EXT > 16
+       .get_wireless_stats = netwave_get_wireless_stats,
+#endif /* WIRELESS_EXT > 16 */
 };
 #endif /* WIRELESS_EXT > 12 */
 
index aabcdc2be05ea925fee9d685bbc4d38bcd8c5e0f..8de49fe57233504ffdbf62cf310a9c34c22b286e 100644 (file)
@@ -94,6 +94,8 @@
 #include <net/iw_handler.h>
 #include <net/ieee80211.h>
 
+#include <net/ieee80211.h>
+
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include "hermes.h"
 #include "hermes_rid.h"
 #include "orinoco.h"
-#include "ieee802_11.h"
 
 /********************************************************************/
 /* Module information                                               */
@@ -150,7 +151,7 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
 #define ENCAPS_OVERHEAD                (sizeof(encaps_hdr) + 2)
 
 #define ORINOCO_MIN_MTU                256
-#define ORINOCO_MAX_MTU                (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)
+#define ORINOCO_MAX_MTU                (IEEE80211_DATA_LEN - ENCAPS_OVERHEAD)
 
 #define SYMBOL_MAX_VER_LEN     (14)
 #define USER_BAP               0
@@ -442,7 +443,7 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
        if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) )
                return -EINVAL;
 
-       if ( (new_mtu + ENCAPS_OVERHEAD + IEEE802_11_HLEN) >
+       if ( (new_mtu + ENCAPS_OVERHEAD + IEEE80211_HLEN) >
             (priv->nicbuf_size - ETH_HLEN) )
                return -EINVAL;
 
@@ -918,7 +919,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
                    data. */
                return;
        }
-       if (length > IEEE802_11_DATA_LEN) {
+       if (length > IEEE80211_DATA_LEN) {
                printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
                       dev->name, length);
                stats->rx_length_errors++;
@@ -1052,8 +1053,9 @@ static void orinoco_join_ap(struct net_device *dev)
                u16 channel;
        } __attribute__ ((packed)) req;
        const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
-       struct prism2_scan_apinfo *atom;
+       struct prism2_scan_apinfo *atom = NULL;
        int offset = 4;
+       int found = 0;
        u8 *buf;
        u16 len;
 
@@ -1088,15 +1090,18 @@ static void orinoco_join_ap(struct net_device *dev)
         * we were requested to join */
        for (; offset + atom_len <= len; offset += atom_len) {
                atom = (struct prism2_scan_apinfo *) (buf + offset);
-               if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0)
-                       goto found;
+               if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) {
+                       found = 1;
+                       break;
+               }
        }
 
-       DEBUG(1, "%s: Requested AP not found in scan results\n",
-             dev->name);
-       goto out;
+       if (! found) {
+               DEBUG(1, "%s: Requested AP not found in scan results\n",
+                     dev->name);
+               goto out;
+       }
 
- found:
        memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
        req.channel = atom->channel;    /* both are little-endian */
        err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
@@ -1283,8 +1288,10 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                /* Read scan data */
                err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
                                       infofid, sizeof(info));
-               if (err)
+               if (err) {
+                       kfree(buf);
                        break;
+               }
 
 #ifdef ORINOCO_DEBUG
                {
@@ -2272,7 +2279,7 @@ static int orinoco_init(struct net_device *dev)
 
        /* No need to lock, the hw_unavailable flag is already set in
         * alloc_orinocodev() */
-       priv->nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN;
+       priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN;
 
        /* Initialize the firmware */
        err = orinoco_reinit_firmware(dev);
@@ -4020,7 +4027,8 @@ static int orinoco_ioctl_setscan(struct net_device *dev,
 }
 
 /* Translate scan data returned from the card to a card independant
- * format that the Wireless Tools will understand - Jean II */
+ * format that the Wireless Tools will understand - Jean II
+ * Return message length or -errno for fatal errors */
 static inline int orinoco_translate_scan(struct net_device *dev,
                                         char *buffer,
                                         char *scan,
@@ -4060,13 +4068,19 @@ static inline int orinoco_translate_scan(struct net_device *dev,
                break;
        case FIRMWARE_TYPE_INTERSIL:
                offset = 4;
-               if (priv->has_hostscan)
-                       atom_len = scan[0] + (scan[1] << 8);
-               else
+               if (priv->has_hostscan) {
+                       atom_len = le16_to_cpup((u16 *)scan);
+                       /* Sanity check for atom_len */
+                       if (atom_len < sizeof(struct prism2_scan_apinfo)) {
+                               printk(KERN_ERR "%s: Invalid atom_len in scan data: %d\n",
+                               dev->name, atom_len);
+                               return -EIO;
+                       }
+               } else
                        atom_len = offsetof(struct prism2_scan_apinfo, atim);
                break;
        default:
-               return 0;
+               return -EOPNOTSUPP;
        }
 
        /* Check that we got an whole number of atoms */
@@ -4074,7 +4088,7 @@ static inline int orinoco_translate_scan(struct net_device *dev,
                printk(KERN_ERR "%s: Unexpected scan data length %d, "
                       "atom_len %d, offset %d\n", dev->name, scan_len,
                       atom_len, offset);
-               return 0;
+               return -EIO;
        }
 
        /* Read the entries one by one */
@@ -4209,33 +4223,41 @@ static int orinoco_ioctl_getscan(struct net_device *dev,
                /* We have some results to push back to user space */
 
                /* Translate to WE format */
-               srq->length = orinoco_translate_scan(dev, extra,
-                                                    priv->scan_result,
-                                                    priv->scan_len);
-
-               /* Return flags */
-               srq->flags = (__u16) priv->scan_mode;
+               int ret = orinoco_translate_scan(dev, extra,
+                                                priv->scan_result,
+                                                priv->scan_len);
+
+               if (ret < 0) {
+                       err = ret;
+                       kfree(priv->scan_result);
+                       priv->scan_result = NULL;
+               } else {
+                       srq->length = ret;
 
-               /* Results are here, so scan no longer in progress */
-               priv->scan_inprogress = 0;
+                       /* Return flags */
+                       srq->flags = (__u16) priv->scan_mode;
 
-               /* In any case, Scan results will be cleaned up in the
-                * reset function and when exiting the driver.
-                * The person triggering the scanning may never come to
-                * pick the results, so we need to do it in those places.
-                * Jean II */
+                       /* In any case, Scan results will be cleaned up in the
+                        * reset function and when exiting the driver.
+                        * The person triggering the scanning may never come to
+                        * pick the results, so we need to do it in those places.
+                        * Jean II */
 
 #ifdef SCAN_SINGLE_READ
-               /* If you enable this option, only one client (the first
-                * one) will be able to read the result (and only one
-                * time). If there is multiple concurent clients that
-                * want to read scan results, this behavior is not
-                * advisable - Jean II */
-               kfree(priv->scan_result);
-               priv->scan_result = NULL;
+                       /* If you enable this option, only one client (the first
+                        * one) will be able to read the result (and only one
+                        * time). If there is multiple concurent clients that
+                        * want to read scan results, this behavior is not
+                        * advisable - Jean II */
+                       kfree(priv->scan_result);
+                       priv->scan_result = NULL;
 #endif /* SCAN_SINGLE_READ */
-               /* Here, if too much time has elapsed since last scan,
-                * we may want to clean up scan results... - Jean II */
+                       /* Here, if too much time has elapsed since last scan,
+                        * we may want to clean up scan results... - Jean II */
+               }
+
+               /* Scan is no longer in progress */
+               priv->scan_inprogress = 0;
        }
          
        orinoco_unlock(priv, &flags);
@@ -4322,36 +4344,36 @@ static const struct iw_priv_args orinoco_privtab[] = {
  */
 
 static const iw_handler        orinoco_handler[] = {
-       [SIOCSIWCOMMIT-SIOCIWFIRST] (iw_handler) orinoco_ioctl_commit,
-       [SIOCGIWNAME  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getname,
-       [SIOCSIWFREQ  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfreq,
-       [SIOCGIWFREQ  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfreq,
-       [SIOCSIWMODE  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setmode,
-       [SIOCGIWMODE  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getmode,
-       [SIOCSIWSENS  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setsens,
-       [SIOCGIWSENS  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getsens,
-       [SIOCGIWRANGE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwrange,
-       [SIOCSIWSPY   -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setspy,
-       [SIOCGIWSPY   -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getspy,
-       [SIOCSIWAP    -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setwap,
-       [SIOCGIWAP    -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getwap,
-       [SIOCSIWSCAN  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setscan,
-       [SIOCGIWSCAN  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getscan,
-       [SIOCSIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setessid,
-       [SIOCGIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getessid,
-       [SIOCSIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setnick,
-       [SIOCGIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getnick,
-       [SIOCSIWRATE  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrate,
-       [SIOCGIWRATE  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrate,
-       [SIOCSIWRTS   -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrts,
-       [SIOCGIWRTS   -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrts,
-       [SIOCSIWFRAG  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfrag,
-       [SIOCGIWFRAG  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfrag,
-       [SIOCGIWRETRY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getretry,
-       [SIOCSIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_setiwencode,
-       [SIOCGIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwencode,
-       [SIOCSIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setpower,
-       [SIOCGIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getpower,
+       [SIOCSIWCOMMIT-SIOCIWFIRST] (iw_handler) orinoco_ioctl_commit,
+       [SIOCGIWNAME  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getname,
+       [SIOCSIWFREQ  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfreq,
+       [SIOCGIWFREQ  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfreq,
+       [SIOCSIWMODE  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setmode,
+       [SIOCGIWMODE  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getmode,
+       [SIOCSIWSENS  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setsens,
+       [SIOCGIWSENS  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getsens,
+       [SIOCGIWRANGE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwrange,
+       [SIOCSIWSPY   -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setspy,
+       [SIOCGIWSPY   -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getspy,
+       [SIOCSIWAP    -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setwap,
+       [SIOCGIWAP    -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getwap,
+       [SIOCSIWSCAN  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setscan,
+       [SIOCGIWSCAN  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getscan,
+       [SIOCSIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setessid,
+       [SIOCGIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getessid,
+       [SIOCSIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setnick,
+       [SIOCGIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getnick,
+       [SIOCSIWRATE  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrate,
+       [SIOCGIWRATE  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrate,
+       [SIOCSIWRTS   -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrts,
+       [SIOCGIWRTS   -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrts,
+       [SIOCSIWFRAG  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfrag,
+       [SIOCGIWFRAG  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfrag,
+       [SIOCGIWRETRY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getretry,
+       [SIOCSIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_setiwencode,
+       [SIOCGIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwencode,
+       [SIOCSIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setpower,
+       [SIOCGIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getpower,
 };
 
 
@@ -4359,15 +4381,15 @@ static const iw_handler orinoco_handler[] = {
   Added typecasting since we no longer use iwreq_data -- Moustafa
  */
 static const iw_handler        orinoco_private_handler[] = {
-       [0] (iw_handler) orinoco_ioctl_reset,
-       [1] (iw_handler) orinoco_ioctl_reset,
-       [2] (iw_handler) orinoco_ioctl_setport3,
-       [3] (iw_handler) orinoco_ioctl_getport3,
-       [4] (iw_handler) orinoco_ioctl_setpreamble,
-       [5] (iw_handler) orinoco_ioctl_getpreamble,
-       [6] (iw_handler) orinoco_ioctl_setibssport,
-       [7] (iw_handler) orinoco_ioctl_getibssport,
-       [9] (iw_handler) orinoco_ioctl_getrid,
+       [0] (iw_handler) orinoco_ioctl_reset,
+       [1] (iw_handler) orinoco_ioctl_reset,
+       [2] (iw_handler) orinoco_ioctl_setport3,
+       [3] (iw_handler) orinoco_ioctl_getport3,
+       [4] (iw_handler) orinoco_ioctl_setpreamble,
+       [5] (iw_handler) orinoco_ioctl_getpreamble,
+       [6] (iw_handler) orinoco_ioctl_setibssport,
+       [7] (iw_handler) orinoco_ioctl_getibssport,
+       [9] (iw_handler) orinoco_ioctl_getrid,
 };
 
 static const struct iw_handler_def orinoco_handler_def = {
index 1cc1492083c9589630f05914dbbabe3a3ec31d09..d1fb1bab8aa879c2322398f493fba934355bb848 100644 (file)
@@ -604,7 +604,6 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
 
 static struct pcmcia_device_id orinoco_cs_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
-       PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0001),
        PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
        PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002),
        PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a),
diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c
new file mode 100644 (file)
index 0000000..86fa58e
--- /dev/null
@@ -0,0 +1,324 @@
+/* orinoco_nortel.c
+ * 
+ * Driver for Prism II devices which would usually be driven by orinoco_cs,
+ * but are connected to the PCI bus by a Nortel PCI-PCMCIA-Adapter. 
+ *
+ * Copyright (C) 2002 Tobias Hoffmann
+ *           (C) 2003 Christoph Jungegger <disdos@traum404.de>
+ *
+ * Some of this code is borrowed from orinoco_plx.c
+ *     Copyright (C) 2001 Daniel Barlow
+ * Some of this code is borrowed from orinoco_pci.c 
+ *  Copyright (C) 2001 Jean Tourrilhes
+ * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
+ * has been copied from it. linux-wlan-ng-0.1.10 is originally :
+ *     Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
+ * 
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#define DRIVER_NAME "orinoco_nortel"
+#define PFX DRIVER_NAME ": "
+
+#include <linux/config.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/fcntl.h>
+
+#include <pcmcia/cisreg.h>
+
+#include "hermes.h"
+#include "orinoco.h"
+
+#define COR_OFFSET    (0xe0)   /* COR attribute offset of Prism2 PC card */
+#define COR_VALUE     (COR_LEVEL_REQ | COR_FUNC_ENA)   /* Enable PC card with interrupt in level trigger */
+
+
+/* Nortel specific data */
+struct nortel_pci_card {
+       unsigned long iobase1;
+       unsigned long iobase2;
+};
+
+/*
+ * Do a soft reset of the PCI card using the Configuration Option Register
+ * We need this to get going...
+ * This is the part of the code that is strongly inspired from wlan-ng
+ *
+ * Note bis : Don't try to access HERMES_CMD during the reset phase.
+ * It just won't work !
+ */
+static int nortel_pci_cor_reset(struct orinoco_private *priv)
+{
+       struct nortel_pci_card *card = priv->card;
+
+       /* Assert the reset until the card notice */
+       outw_p(8, card->iobase1 + 2);
+       inw(card->iobase2 + COR_OFFSET);
+       outw_p(0x80, card->iobase2 + COR_OFFSET);
+       mdelay(1);
+
+       /* Give time for the card to recover from this hard effort */
+       outw_p(0, card->iobase2 + COR_OFFSET);
+       outw_p(0, card->iobase2 + COR_OFFSET);
+       mdelay(1);
+
+       /* set COR as usual */
+       outw_p(COR_VALUE, card->iobase2 + COR_OFFSET);
+       outw_p(COR_VALUE, card->iobase2 + COR_OFFSET);
+       mdelay(1);
+
+       outw_p(0x228, card->iobase1 + 2);
+
+       return 0;
+}
+
+int nortel_pci_hw_init(struct nortel_pci_card *card)
+{
+       int i;
+       u32 reg;
+
+       /* setup bridge */
+       if (inw(card->iobase1) & 1) {
+               printk(KERN_ERR PFX "brg1 answer1 wrong\n");
+               return -EBUSY;
+       }
+       outw_p(0x118, card->iobase1 + 2);
+       outw_p(0x108, card->iobase1 + 2);
+       mdelay(30);
+       outw_p(0x8, card->iobase1 + 2);
+       for (i = 0; i < 30; i++) {
+               mdelay(30);
+               if (inw(card->iobase1) & 0x10) {
+                       break;
+               }
+       }
+       if (i == 30) {
+               printk(KERN_ERR PFX "brg1 timed out\n");
+               return -EBUSY;
+       }
+       if (inw(card->iobase2 + 0xe0) & 1) {
+               printk(KERN_ERR PFX "brg2 answer1 wrong\n");
+               return -EBUSY;
+       }
+       if (inw(card->iobase2 + 0xe2) & 1) {
+               printk(KERN_ERR PFX "brg2 answer2 wrong\n");
+               return -EBUSY;
+       }
+       if (inw(card->iobase2 + 0xe4) & 1) {
+               printk(KERN_ERR PFX "brg2 answer3 wrong\n");
+               return -EBUSY;
+       }
+
+       /* set the PCMCIA COR-Register */
+       outw_p(COR_VALUE, card->iobase2 + COR_OFFSET);
+       mdelay(1);
+       reg = inw(card->iobase2 + COR_OFFSET);
+       if (reg != COR_VALUE) {
+               printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n",
+                      reg);
+               return -EBUSY;
+       }
+
+       /* set leds */
+       outw_p(1, card->iobase1 + 10);
+       return 0;
+}
+
+static int nortel_pci_init_one(struct pci_dev *pdev,
+                              const struct pci_device_id *ent)
+{
+       int err;
+       struct orinoco_private *priv;
+       struct nortel_pci_card *card;
+       struct net_device *dev;
+       void __iomem *iomem;
+
+       err = pci_enable_device(pdev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot enable PCI device\n");
+               return err;
+       }
+
+       err = pci_request_regions(pdev, DRIVER_NAME);
+       if (err != 0) {
+               printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
+               goto fail_resources;
+       }
+
+       iomem = pci_iomap(pdev, 3, 0);
+       if (!iomem) {
+               err = -ENOMEM;
+               goto fail_map_io;
+       }
+
+       /* Allocate network device */
+       dev = alloc_orinocodev(sizeof(*card), nortel_pci_cor_reset);
+       if (!dev) {
+               printk(KERN_ERR PFX "Cannot allocate network device\n");
+               err = -ENOMEM;
+               goto fail_alloc;
+       }
+
+       priv = netdev_priv(dev);
+       card = priv->card;
+       card->iobase1 = pci_resource_start(pdev, 0);
+       card->iobase2 = pci_resource_start(pdev, 1);
+       dev->base_addr = pci_resource_start(pdev, 2);
+       SET_MODULE_OWNER(dev);
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       hermes_struct_init(&priv->hw, iomem, HERMES_16BIT_REGSPACING);
+
+       printk(KERN_DEBUG PFX "Detected Nortel PCI device at %s irq:%d, "
+              "io addr:0x%lx\n", pci_name(pdev), pdev->irq, dev->base_addr);
+
+       err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
+                         dev->name, dev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
+               err = -EBUSY;
+               goto fail_irq;
+       }
+       dev->irq = pdev->irq;
+
+       err = nortel_pci_hw_init(card);
+       if (err) {
+               printk(KERN_ERR PFX "Hardware initialization failed\n");
+               goto fail;
+       }
+
+       err = nortel_pci_cor_reset(priv);
+       if (err) {
+               printk(KERN_ERR PFX "Initial reset failed\n");
+               goto fail;
+       }
+
+
+       err = register_netdev(dev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot register network device\n");
+               goto fail;
+       }
+
+       pci_set_drvdata(pdev, dev);
+
+       return 0;
+
+ fail:
+       free_irq(pdev->irq, dev);
+
+ fail_irq:
+       pci_set_drvdata(pdev, NULL);
+       free_orinocodev(dev);
+
+ fail_alloc:
+       pci_iounmap(pdev, iomem);
+
+ fail_map_io:
+       pci_release_regions(pdev);
+
+ fail_resources:
+       pci_disable_device(pdev);
+
+       return err;
+}
+
+static void __devexit nortel_pci_remove_one(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct nortel_pci_card *card = priv->card;
+
+       /* clear leds */
+       outw_p(0, card->iobase1 + 10);
+
+       unregister_netdev(dev);
+       free_irq(dev->irq, dev);
+       pci_set_drvdata(pdev, NULL);
+       free_orinocodev(dev);
+       pci_iounmap(pdev, priv->hw.iobase);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+}
+
+
+static struct pci_device_id nortel_pci_id_table[] = {
+       /* Nortel emobility PCI */
+       {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,},
+       {0,},
+};
+
+MODULE_DEVICE_TABLE(pci, nortel_pci_id_table);
+
+static struct pci_driver nortel_pci_driver = {
+       .name = DRIVER_NAME,
+       .id_table = nortel_pci_id_table,
+       .probe = nortel_pci_init_one,
+       .remove = __devexit_p(nortel_pci_remove_one),
+};
+
+static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
+       " (Tobias Hoffmann & Christoph Jungegger <disdos@traum404.de>)";
+MODULE_AUTHOR("Christoph Jungegger <disdos@traum404.de>");
+MODULE_DESCRIPTION
+    ("Driver for wireless LAN cards using the Nortel PCI bridge");
+MODULE_LICENSE("Dual MPL/GPL");
+
+static int __init nortel_pci_init(void)
+{
+       printk(KERN_DEBUG "%s\n", version);
+       return pci_module_init(&nortel_pci_driver);
+}
+
+static void __exit nortel_pci_exit(void)
+{
+       pci_unregister_driver(&nortel_pci_driver);
+       ssleep(1);
+}
+
+module_init(nortel_pci_init);
+module_exit(nortel_pci_exit);
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
index 7a6f52ea7faa306ac5f4af3525528d5754a5fe4e..42e03438291b8e3ad7967ea93198c996211434ed 100644 (file)
@@ -301,8 +301,6 @@ static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        unsigned long flags;
        int err;
        
-       printk(KERN_DEBUG "%s: Orinoco-PCI entering sleep mode (state=%d)\n",
-              dev->name, state);
 
        err = orinoco_lock(priv, &flags);
        if (err) {
index 0f29a9c7bc2cd6ded382198d06254f767f4e6e58..9a8790e3580c648d33f948717c38bc0d94a29728 100644 (file)
@@ -2727,6 +2727,9 @@ const struct iw_handler_def prism54_handler_def = {
        .standard = (iw_handler *) prism54_handler,
        .private = (iw_handler *) prism54_private_handler,
        .private_args = (struct iw_priv_args *) prism54_private_args,
+#if WIRELESS_EXT > 16
+       .get_wireless_stats = prism54_get_wireless_stats,
+#endif /* WIRELESS_EXT > 16 */
 #if WIRELESS_EXT == 16
        .spy_offset = offsetof(islpci_private, spy_data),
 #endif /* WIRELESS_EXT == 16 */
index efab07e9e24e0a37cfa624b57aa49060c9432e39..6f13d4a8e2d33805b93952d1663459afb7cd8995 100644 (file)
@@ -815,7 +815,6 @@ islpci_setup(struct pci_dev *pdev)
        ndev->open = &islpci_open;
        ndev->stop = &islpci_close;
        ndev->get_stats = &islpci_statistics;
-       ndev->get_wireless_stats = &prism54_get_wireless_stats;
        ndev->do_ioctl = &prism54_ioctl;
        ndev->wireless_handlers =
            (struct iw_handler_def *) &prism54_handler_def;
@@ -844,6 +843,8 @@ islpci_setup(struct pci_dev *pdev)
        /* Add pointers to enable iwspy support. */
        priv->wireless_data.spy_data = &priv->spy_data;
        ndev->wireless_data = &priv->wireless_data;
+#else  /* WIRELESS_EXT > 16 */
+       ndev->get_wireless_stats = &prism54_get_wireless_stats;
 #endif /* WIRELESS_EXT > 16 */
 
        /* save the start and end address of the PCI memory area */
index c17391d947f31a30460d50b6ae56a072dd24b5aa..dc040caab7d746e61a8c4c87c6149f33924e07cc 100644 (file)
@@ -267,8 +267,6 @@ prism54_suspend(struct pci_dev *pdev, pm_message_t state)
        islpci_private *priv = ndev ? netdev_priv(ndev) : NULL;
        BUG_ON(!priv);
 
-       printk(KERN_NOTICE "%s: got suspend request (state %d)\n",
-              ndev->name, state);
 
        pci_save_state(pdev);
 
index 0e0ba614259af78415767017af7e3e65c5890946..e9c5ea0f5535dada4e4416fdad26d81caa6de948 100644 (file)
@@ -53,6 +53,7 @@
 #include <pcmcia/ds.h>
 #include <pcmcia/mem_op.h>
 
+#include <net/ieee80211.h>
 #include <linux/wireless.h>
 
 #include <asm/io.h>
@@ -64,7 +65,6 @@
 #define WIRELESS_SPY           /* Enable spying addresses */
 /* Definitions we need for spy */
 typedef struct iw_statistics   iw_stats;
-typedef struct iw_quality      iw_qual;
 typedef u_char mac_addr[ETH_ALEN];     /* Hardware address */
 
 #include "rayctl.h"
@@ -101,7 +101,6 @@ static int ray_dev_close(struct net_device *dev);
 static int ray_dev_config(struct net_device *dev, struct ifmap *map);
 static struct net_device_stats *ray_get_stats(struct net_device *dev);
 static int ray_dev_init(struct net_device *dev);
-static int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 
 static struct ethtool_ops netdev_ethtool_ops;
 
@@ -114,9 +113,8 @@ static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx,
 static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx, UCHAR msg_type,
                 unsigned char *data);
 static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len);
-#if WIRELESS_EXT > 7   /* If wireless extension exist in the kernel */
 static iw_stats * ray_get_wireless_stats(struct net_device *   dev);
-#endif /* WIRELESS_EXT > 7 */
+static const struct iw_handler_def     ray_handler_def;
 
 /***** Prototypes for raylink functions **************************************/
 static int asc_to_int(char a);
@@ -373,11 +371,12 @@ static dev_link_t *ray_attach(void)
     dev->hard_start_xmit = &ray_dev_start_xmit;
     dev->set_config = &ray_dev_config;
     dev->get_stats  = &ray_get_stats;
-    dev->do_ioctl = &ray_dev_ioctl;
     SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
-#if WIRELESS_EXT > 7   /* If wireless extension exist in the kernel */
-    dev->get_wireless_stats = ray_get_wireless_stats;
-#endif
+    dev->wireless_handlers = &ray_handler_def;
+#ifdef WIRELESS_SPY
+    local->wireless_data.spy_data = &local->spy_data;
+    dev->wireless_data = &local->wireless_data;
+#endif /* WIRELESS_SPY */
 
     dev->set_multicast_list = &set_multicast_list;
 
@@ -1201,436 +1200,420 @@ static struct ethtool_ops netdev_ethtool_ops = {
 
 /*====================================================================*/
 
-static int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get protocol name
+ */
+static int ray_get_name(struct net_device *dev,
+                       struct iw_request_info *info,
+                       char *cwrq,
+                       char *extra)
 {
-    ray_dev_t *local = (ray_dev_t *)dev->priv;
-    dev_link_t *link = local->finder;
-    int err = 0;
-#if WIRELESS_EXT > 7
-    struct iwreq *wrq = (struct iwreq *) ifr;
-#endif /* WIRELESS_EXT > 7 */
-#ifdef WIRELESS_SPY
-    struct sockaddr    address[IW_MAX_SPY];
-#endif /* WIRELESS_SPY */
+       strcpy(cwrq, "IEEE 802.11-FH");
+       return 0;
+}
 
-    if (!(link->state & DEV_PRESENT)) {
-        DEBUG(2,"ray_dev_ioctl - device not present\n");
-        return -1;
-    }
-    DEBUG(2,"ray_cs IOCTL dev=%p, ifr=%p, cmd = 0x%x\n",dev,ifr,cmd);
-    /* Validate the command */
-    switch (cmd)
-    {
-#if WIRELESS_EXT > 7
-      /* --------------- WIRELESS EXTENSIONS --------------- */
-      /* Get name */
-    case SIOCGIWNAME:
-      strcpy(wrq->u.name, "IEEE 802.11-FH");
-      break;
-
-      /* Get frequency/channel */
-    case SIOCGIWFREQ:
-      wrq->u.freq.m = local->sparm.b5.a_hop_pattern;
-      wrq->u.freq.e = 0;
-      break;
-
-      /* Set frequency/channel */
-    case SIOCSIWFREQ:
-      /* Reject if card is already initialised */
-      if(local->card_status != CARD_AWAITING_PARAM)
-       {
-         err = -EBUSY;
-         break;
-       }
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set frequency
+ */
+static int ray_set_freq(struct net_device *dev,
+                       struct iw_request_info *info,
+                       struct iw_freq *fwrq,
+                       char *extra)
+{
+       ray_dev_t *local = (ray_dev_t *)dev->priv;
+       int err = -EINPROGRESS;         /* Call commit handler */
 
-      /* Setting by channel number */
-      if ((wrq->u.freq.m > USA_HOP_MOD) || (wrq->u.freq.e > 0))
-       err = -EOPNOTSUPP;
-      else
-         local->sparm.b5.a_hop_pattern = wrq->u.freq.m;
-      break;
+       /* Reject if card is already initialised */
+       if(local->card_status != CARD_AWAITING_PARAM)
+               return -EBUSY;
 
-      /* Get current network name (ESSID) */
-    case SIOCGIWESSID:
-      if (wrq->u.data.pointer)
-       {
-         char essid[IW_ESSID_MAX_SIZE + 1];
-         /* Get the essid that was set */
-         memcpy(essid, local->sparm.b5.a_current_ess_id,
-                IW_ESSID_MAX_SIZE);
-         essid[IW_ESSID_MAX_SIZE] = '\0';
-
-         /* Push it out ! */
-         wrq->u.data.length = strlen(essid) + 1;
-         wrq->u.data.flags = 1; /* active */
-         if (copy_to_user(wrq->u.data.pointer, essid, sizeof(essid)))
-                 err = -EFAULT;
-       }
-      break;
+       /* Setting by channel number */
+       if ((fwrq->m > USA_HOP_MOD) || (fwrq->e > 0))
+               err = -EOPNOTSUPP;
+       else
+               local->sparm.b5.a_hop_pattern = fwrq->m;
 
-      /* Set desired network name (ESSID) */
-    case SIOCSIWESSID:
-      /* Reject if card is already initialised */
-      if(local->card_status != CARD_AWAITING_PARAM)
-       {
-         err = -EBUSY;
-         break;
-       }
+       return err;
+}
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get frequency
+ */
+static int ray_get_freq(struct net_device *dev,
+                       struct iw_request_info *info,
+                       struct iw_freq *fwrq,
+                       char *extra)
+{
+       ray_dev_t *local = (ray_dev_t *)dev->priv;
 
-       if (wrq->u.data.pointer)
-       {
-           char        card_essid[IW_ESSID_MAX_SIZE + 1];
-           
-           /* Check if we asked for `any' */
-           if(wrq->u.data.flags == 0)
-           {
+       fwrq->m = local->sparm.b5.a_hop_pattern;
+       fwrq->e = 0;
+       return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set ESSID
+ */
+static int ray_set_essid(struct net_device *dev,
+                        struct iw_request_info *info,
+                        struct iw_point *dwrq,
+                        char *extra)
+{
+       ray_dev_t *local = (ray_dev_t *)dev->priv;
+
+       /* Reject if card is already initialised */
+       if(local->card_status != CARD_AWAITING_PARAM)
+               return -EBUSY;
+
+       /* Check if we asked for `any' */
+       if(dwrq->flags == 0) {
                /* Corey : can you do that ? */
-               err = -EOPNOTSUPP;
-           }
-           else
-           {
+               return -EOPNOTSUPP;
+       } else {
                /* Check the size of the string */
-               if(wrq->u.data.length >
-                  IW_ESSID_MAX_SIZE + 1)
-               {
-                   err = -E2BIG;
-                   break;
-               }
-               if (copy_from_user(card_essid,
-                                  wrq->u.data.pointer,
-                                  wrq->u.data.length)) {
-                       err = -EFAULT;
-                       break;
+               if(dwrq->length > IW_ESSID_MAX_SIZE + 1) {
+                       return -E2BIG;
                }
-               card_essid[IW_ESSID_MAX_SIZE] = '\0';
 
                /* Set the ESSID in the card */
-               memcpy(local->sparm.b5.a_current_ess_id, card_essid,
-                      IW_ESSID_MAX_SIZE);
-           }
+               memset(local->sparm.b5.a_current_ess_id, 0, IW_ESSID_MAX_SIZE);
+               memcpy(local->sparm.b5.a_current_ess_id, extra, dwrq->length);
        }
-       break;
-
-      /* Get current Access Point (BSSID in our case) */
-    case SIOCGIWAP:
-      memcpy(wrq->u.ap_addr.sa_data, local->bss_id, ETH_ALEN);
-      wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
-      break;
-
-      /* Get the current bit-rate */
-    case SIOCGIWRATE:
-      if(local->net_default_tx_rate == 3)
-       wrq->u.bitrate.value = 2000000;         /* Hum... */
-      else
-       wrq->u.bitrate.value = local->net_default_tx_rate * 500000;
-      wrq->u.bitrate.fixed = 0;                /* We are in auto mode */
-      break;
-
-      /* Set the desired bit-rate */
-    case SIOCSIWRATE:
-      /* Check if rate is in range */
-      if((wrq->u.bitrate.value != 1000000) &&
-        (wrq->u.bitrate.value != 2000000))
-       {
-         err = -EINVAL;
-         break;
-       }
-      /* Hack for 1.5 Mb/s instead of 2 Mb/s */
-      if((local->fw_ver == 0x55) &&            /* Please check */
-        (wrq->u.bitrate.value == 2000000))
-       local->net_default_tx_rate = 3;
-      else
-       local->net_default_tx_rate = wrq->u.bitrate.value/500000;
-      break;
-
-      /* Get the current RTS threshold */
-    case SIOCGIWRTS:
-      wrq->u.rts.value = (local->sparm.b5.a_rts_threshold[0] << 8)
-       + local->sparm.b5.a_rts_threshold[1];
-#if WIRELESS_EXT > 8
-      wrq->u.rts.disabled = (wrq->u.rts.value == 32767);
-#endif /* WIRELESS_EXT > 8 */
-      wrq->u.rts.fixed = 1;
-      break;
-
-      /* Set the desired RTS threshold */
-    case SIOCSIWRTS:
-    {
-       int rthr = wrq->u.rts.value;
 
-      /* Reject if card is already initialised */
-      if(local->card_status != CARD_AWAITING_PARAM)
-       {
-         err = -EBUSY;
-         break;
-       }
+       return -EINPROGRESS;            /* Call commit handler */
+}
 
-       /* if(wrq->u.rts.fixed == 0) we should complain */
-#if WIRELESS_EXT > 8
-       if(wrq->u.rts.disabled)
-           rthr = 32767;
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get ESSID
+ */
+static int ray_get_essid(struct net_device *dev,
+                        struct iw_request_info *info,
+                        struct iw_point *dwrq,
+                        char *extra)
+{
+       ray_dev_t *local = (ray_dev_t *)dev->priv;
+
+       /* Get the essid that was set */
+       memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
+       extra[IW_ESSID_MAX_SIZE] = '\0';
+
+       /* Push it out ! */
+       dwrq->length = strlen(extra) + 1;
+       dwrq->flags = 1; /* active */
+
+       return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get AP address
+ */
+static int ray_get_wap(struct net_device *dev,
+                       struct iw_request_info *info,
+                       struct sockaddr *awrq,
+                       char *extra)
+{
+       ray_dev_t *local = (ray_dev_t *)dev->priv;
+
+       memcpy(awrq->sa_data, local->bss_id, ETH_ALEN);
+       awrq->sa_family = ARPHRD_ETHER;
+
+       return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set Bit-Rate
+ */
+static int ray_set_rate(struct net_device *dev,
+                       struct iw_request_info *info,
+                       struct iw_param *vwrq,
+                       char *extra)
+{
+       ray_dev_t *local = (ray_dev_t *)dev->priv;
+
+       /* Reject if card is already initialised */
+       if(local->card_status != CARD_AWAITING_PARAM)
+               return -EBUSY;
+
+       /* Check if rate is in range */
+       if((vwrq->value != 1000000) && (vwrq->value != 2000000))
+               return -EINVAL;
+
+       /* Hack for 1.5 Mb/s instead of 2 Mb/s */
+       if((local->fw_ver == 0x55) &&           /* Please check */
+          (vwrq->value == 2000000))
+               local->net_default_tx_rate = 3;
        else
-#endif /* WIRELESS_EXT > 8 */
-           if((rthr < 0) || (rthr > 2347)) /* What's the max packet size ??? */
-           {
-               err = -EINVAL;
-               break;
-           }
+               local->net_default_tx_rate = vwrq->value/500000;
+
+       return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get Bit-Rate
+ */
+static int ray_get_rate(struct net_device *dev,
+                       struct iw_request_info *info,
+                       struct iw_param *vwrq,
+                       char *extra)
+{
+       ray_dev_t *local = (ray_dev_t *)dev->priv;
+
+       if(local->net_default_tx_rate == 3)
+               vwrq->value = 2000000;          /* Hum... */
+       else
+               vwrq->value = local->net_default_tx_rate * 500000;
+       vwrq->fixed = 0;                /* We are in auto mode */
+
+       return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set RTS threshold
+ */
+static int ray_set_rts(struct net_device *dev,
+                      struct iw_request_info *info,
+                      struct iw_param *vwrq,
+                      char *extra)
+{
+       ray_dev_t *local = (ray_dev_t *)dev->priv;
+       int rthr = vwrq->value;
+
+       /* Reject if card is already initialised */
+       if(local->card_status != CARD_AWAITING_PARAM)
+               return -EBUSY;
+
+       /* if(wrq->u.rts.fixed == 0) we should complain */
+       if(vwrq->disabled)
+               rthr = 32767;
+       else {
+               if((rthr < 0) || (rthr > 2347)) /* What's the max packet size ??? */
+                       return -EINVAL;
+       }
        local->sparm.b5.a_rts_threshold[0] = (rthr >> 8) & 0xFF;
        local->sparm.b5.a_rts_threshold[1] = rthr & 0xFF;
-    }
-    break;
 
-      /* Get the current fragmentation threshold */
-    case SIOCGIWFRAG:
-      wrq->u.frag.value = (local->sparm.b5.a_frag_threshold[0] << 8)
-       + local->sparm.b5.a_frag_threshold[1];
-#if WIRELESS_EXT > 8
-      wrq->u.frag.disabled = (wrq->u.frag.value == 32767);
-#endif /* WIRELESS_EXT > 8 */
-      wrq->u.frag.fixed = 1;
-      break;
+       return -EINPROGRESS;            /* Call commit handler */
+}
 
-      /* Set the desired fragmentation threshold */
-    case SIOCSIWFRAG:
-    {
-       int fthr = wrq->u.frag.value;
 
-      /* Reject if card is already initialised */
-      if(local->card_status != CARD_AWAITING_PARAM)
-       {
-         err = -EBUSY;
-         break;
-       }
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get RTS threshold
+ */
+static int ray_get_rts(struct net_device *dev,
+                      struct iw_request_info *info,
+                      struct iw_param *vwrq,
+                      char *extra)
+{
+       ray_dev_t *local = (ray_dev_t *)dev->priv;
+
+       vwrq->value = (local->sparm.b5.a_rts_threshold[0] << 8)
+               + local->sparm.b5.a_rts_threshold[1];
+       vwrq->disabled = (vwrq->value == 32767);
+       vwrq->fixed = 1;
+
+       return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set Fragmentation threshold
+ */
+static int ray_set_frag(struct net_device *dev,
+                       struct iw_request_info *info,
+                       struct iw_param *vwrq,
+                       char *extra)
+{
+       ray_dev_t *local = (ray_dev_t *)dev->priv;
+       int fthr = vwrq->value;
+
+       /* Reject if card is already initialised */
+       if(local->card_status != CARD_AWAITING_PARAM)
+               return -EBUSY;
 
        /* if(wrq->u.frag.fixed == 0) should complain */
-#if WIRELESS_EXT > 8
-       if(wrq->u.frag.disabled)
-           fthr = 32767;
-       else
-#endif /* WIRELESS_EXT > 8 */
-           if((fthr < 256) || (fthr > 2347)) /* To check out ! */
-           {
-               err = -EINVAL;
-               break;
-           }
+       if(vwrq->disabled)
+               fthr = 32767;
+       else {
+               if((fthr < 256) || (fthr > 2347)) /* To check out ! */
+                       return -EINVAL;
+       }
        local->sparm.b5.a_frag_threshold[0] = (fthr >> 8) & 0xFF;
        local->sparm.b5.a_frag_threshold[1] = fthr & 0xFF;
-    }
-    break;
 
-#endif /* WIRELESS_EXT > 7 */
-#if WIRELESS_EXT > 8
+       return -EINPROGRESS;            /* Call commit handler */
+}
 
-      /* Get the current mode of operation */
-    case SIOCGIWMODE:
-      if(local->sparm.b5.a_network_type)
-       wrq->u.mode = IW_MODE_INFRA;
-      else
-       wrq->u.mode = IW_MODE_ADHOC;
-      break;
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get Fragmentation threshold
+ */
+static int ray_get_frag(struct net_device *dev,
+                       struct iw_request_info *info,
+                       struct iw_param *vwrq,
+                       char *extra)
+{
+       ray_dev_t *local = (ray_dev_t *)dev->priv;
 
-      /* Set the current mode of operation */
-    case SIOCSIWMODE:
-    {
+       vwrq->value = (local->sparm.b5.a_frag_threshold[0] << 8)
+               + local->sparm.b5.a_frag_threshold[1];
+       vwrq->disabled = (vwrq->value == 32767);
+       vwrq->fixed = 1;
+
+       return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set Mode of Operation
+ */
+static int ray_set_mode(struct net_device *dev,
+                       struct iw_request_info *info,
+                       __u32 *uwrq,
+                       char *extra)
+{
+       ray_dev_t *local = (ray_dev_t *)dev->priv;
+       int err = -EINPROGRESS;         /* Call commit handler */
        char card_mode = 1;
-       
-      /* Reject if card is already initialised */
-      if(local->card_status != CARD_AWAITING_PARAM)
-       {
-         err = -EBUSY;
-         break;
-       }
 
-       switch (wrq->u.mode)
+       /* Reject if card is already initialised */
+       if(local->card_status != CARD_AWAITING_PARAM)
+               return -EBUSY;
+
+       switch (*uwrq)
        {
        case IW_MODE_ADHOC:
-           card_mode = 0;
-           // Fall through
+               card_mode = 0;
+               // Fall through
        case IW_MODE_INFRA:
-           local->sparm.b5.a_network_type = card_mode;
-           break;
+               local->sparm.b5.a_network_type = card_mode;
+               break;
        default:
-           err = -EINVAL;
+               err = -EINVAL;
        }
-    }
-    break;
 
-#endif /* WIRELESS_EXT > 8 */
-#if WIRELESS_EXT > 7
-      /* ------------------ IWSPY SUPPORT ------------------ */
-      /* Define the range (variations) of above parameters */
-    case SIOCGIWRANGE:
-      /* Basic checking... */
-      if(wrq->u.data.pointer != (caddr_t) 0)
-       {
-         struct iw_range       range;
-         memset((char *) &range, 0, sizeof(struct iw_range));
-
-         /* Set the length (very important for backward compatibility) */
-         wrq->u.data.length = sizeof(struct iw_range);
-
-#if WIRELESS_EXT > 10
-         /* Set the Wireless Extension versions */
-         range.we_version_compiled = WIRELESS_EXT;
-         range.we_version_source = 9;
-#endif /* WIRELESS_EXT > 10 */
-
-         /* Set information in the range struct */
-         range.throughput = 1.1 * 1000 * 1000; /* Put the right number here */
-         range.num_channels = hop_pattern_length[(int)country]; 
-         range.num_frequency = 0;
-         range.max_qual.qual = 0;
-         range.max_qual.level = 255;   /* What's the correct value ? */
-         range.max_qual.noise = 255;   /* Idem */
-         range.num_bitrates = 2;
-         range.bitrate[0] = 1000000;   /* 1 Mb/s */
-         range.bitrate[1] = 2000000;   /* 2 Mb/s */
-
-         /* Copy structure to the user buffer */
-         if(copy_to_user(wrq->u.data.pointer, &range,
-                         sizeof(struct iw_range)))
-           err = -EFAULT;
-       }
-      break;
+       return err;
+}
 
-#ifdef WIRELESS_SPY
-      /* Set addresses to spy */
-    case SIOCSIWSPY:
     /* Check the number of addresses */
-      if(wrq->u.data.length > IW_MAX_SPY)
-       {
-         err = -E2BIG;
-         break;
-       }
-      local->spy_number = wrq->u.data.length;
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get Mode of Operation
+ */
+static int ray_get_mode(struct net_device *dev,
+                       struct iw_request_info *info,
+                       __u32 *uwrq,
+                       char *extra)
+{
+       ray_dev_t *local = (ray_dev_t *)dev->priv;
 
-      /* If there is some addresses to copy */
-      if(local->spy_number > 0)
-       {
-         int                   i;
-
-         /* Copy addresses to the driver */
-         if(copy_from_user(address, wrq->u.data.pointer,
-                           sizeof(struct sockaddr) * local->spy_number))
-           {
-             err = -EFAULT;
-             break;
-           }
-
-         /* Copy addresses to the lp structure */
-         for(i = 0; i < local->spy_number; i++)
-           memcpy(local->spy_address[i], address[i].sa_data, ETH_ALEN);
-
-         /* Reset structure... */
-         memset(local->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
-
-#ifdef DEBUG_IOCTL_INFO
-         printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n");
-         for(i = 0; i < local->spy_number; i++)
-           printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X\n",
-                  local->spy_address[i][0],
-                  local->spy_address[i][1],
-                  local->spy_address[i][2],
-                  local->spy_address[i][3],
-                  local->spy_address[i][4],
-                  local->spy_address[i][5]);
-#endif /* DEBUG_IOCTL_INFO */
-       }
-      break;
+       if(local->sparm.b5.a_network_type)
+               *uwrq = IW_MODE_INFRA;
+       else
+               *uwrq = IW_MODE_ADHOC;
 
-      /* Get the spy list and spy stats */
-    case SIOCGIWSPY:
-      /* Set the number of addresses */
-      wrq->u.data.length = local->spy_number;
+       return 0;
+}
 
-      /* If the user want to have the addresses back... */
-      if((local->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
-       {
-         int                   i;
-
-         /* Copy addresses from the lp structure */
-         for(i = 0; i < local->spy_number; i++)
-           {
-             memcpy(address[i].sa_data, local->spy_address[i], ETH_ALEN);
-             address[i].sa_family = ARPHRD_ETHER;
-           }
-
-         /* Copy addresses to the user buffer */
-         if(copy_to_user(wrq->u.data.pointer, address,
-                      sizeof(struct sockaddr) * local->spy_number))
-           {
-             err = -EFAULT;
-             break;
-           }
-
-         /* Copy stats to the user buffer (just after) */
-         if(copy_to_user(wrq->u.data.pointer +
-                      (sizeof(struct sockaddr) * local->spy_number),
-                      local->spy_stat, sizeof(iw_qual) * local->spy_number))
-           {
-             err = -EFAULT;
-             break;
-           }
-
-         /* Reset updated flags */
-         for(i = 0; i < local->spy_number; i++)
-           local->spy_stat[i].updated = 0x0;
-       }       /* if(pointer != NULL) */
-
-      break;
-#endif /* WIRELESS_SPY */
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get range info
+ */
+static int ray_get_range(struct net_device *dev,
+                        struct iw_request_info *info,
+                        struct iw_point *dwrq,
+                        char *extra)
+{
+       struct iw_range *range = (struct iw_range *) extra;
+
+       memset((char *) range, 0, sizeof(struct iw_range));
+
+       /* Set the length (very important for backward compatibility) */
+       dwrq->length = sizeof(struct iw_range);
+
+       /* Set the Wireless Extension versions */
+       range->we_version_compiled = WIRELESS_EXT;
+       range->we_version_source = 9;
+
+       /* Set information in the range struct */
+       range->throughput = 1.1 * 1000 * 1000;  /* Put the right number here */
+       range->num_channels = hop_pattern_length[(int)country]; 
+       range->num_frequency = 0;
+       range->max_qual.qual = 0;
+       range->max_qual.level = 255;    /* What's the correct value ? */
+       range->max_qual.noise = 255;    /* Idem */
+       range->num_bitrates = 2;
+       range->bitrate[0] = 1000000;    /* 1 Mb/s */
+       range->bitrate[1] = 2000000;    /* 2 Mb/s */
+       return 0;
+}
 
-      /* ------------------ PRIVATE IOCTL ------------------ */
-#ifndef SIOCIWFIRSTPRIV
-#define SIOCIWFIRSTPRIV        SIOCDEVPRIVATE
-#endif /* SIOCIWFIRSTPRIV */
-#define SIOCSIPFRAMING SIOCIWFIRSTPRIV         /* Set framing mode */
-#define SIOCGIPFRAMING SIOCIWFIRSTPRIV + 1     /* Get framing mode */
-#define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3     /* Get country code */
-    case SIOCSIPFRAMING:
-      if(!capable(CAP_NET_ADMIN))      /* For private IOCTLs, we need to check permissions */
-       {
-         err = -EPERM;
-         break;
-       }
-      translate = *(wrq->u.name);      /* Set framing mode */
-      break;
-    case SIOCGIPFRAMING:
-      *(wrq->u.name) = translate;
-      break;
-    case SIOCGIPCOUNTRY:
-      *(wrq->u.name) = country;
-      break;
-    case SIOCGIWPRIV:
-      /* Export our "private" intercace */
-      if(wrq->u.data.pointer != (caddr_t) 0)
-       {
-         struct iw_priv_args   priv[] =
-         {     /* cmd,         set_args,       get_args,       name */
-           { SIOCSIPFRAMING, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "set_framing" },
-           { SIOCGIPFRAMING, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "get_framing" },
-           { SIOCGIPCOUNTRY, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "get_country" },
-         };
-         /* Set the number of ioctl available */
-         wrq->u.data.length = 3;
-         /* Copy structure to the user buffer */
-         if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
-                      sizeof(priv)))
-           err = -EFAULT;
-       }
-      break;
-#endif /* WIRELESS_EXT > 7 */
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Private Handler : set framing mode
+ */
+static int ray_set_framing(struct net_device *dev,
+                          struct iw_request_info *info,
+                          union iwreq_data *wrqu,
+                          char *extra)
+{
+       translate = *(extra);   /* Set framing mode */
 
+       return 0;
+}
 
-        default:
-            DEBUG(0,"ray_dev_ioctl cmd = 0x%x\n", cmd);
-            err = -EOPNOTSUPP;
-    }
-    return err;
-} /* end ray_dev_ioctl */
-/*===========================================================================*/
-#if WIRELESS_EXT > 7   /* If wireless extension exist in the kernel */
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Private Handler : get framing mode
+ */
+static int ray_get_framing(struct net_device *dev,
+                          struct iw_request_info *info,
+                          union iwreq_data *wrqu,
+                          char *extra)
+{
+       *(extra) = translate;
+
+       return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Private Handler : get country
+ */
+static int ray_get_country(struct net_device *dev,
+                          struct iw_request_info *info,
+                          union iwreq_data *wrqu,
+                          char *extra)
+{
+       *(extra) = country;
+
+       return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Commit handler : called after a bunch of SET operations
+ */
+static int ray_commit(struct net_device *dev,
+                     struct iw_request_info *info,     /* NULL */
+                     void *zwrq,                       /* NULL */
+                     char *extra)                      /* NULL */
+{
+       return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Stats handler : return Wireless Stats
+ */
 static iw_stats * ray_get_wireless_stats(struct net_device *   dev)
 {
   ray_dev_t *  local = (ray_dev_t *) dev->priv;
@@ -1642,13 +1625,13 @@ static iw_stats * ray_get_wireless_stats(struct net_device *    dev)
 
   local->wstats.status = local->card_status;
 #ifdef WIRELESS_SPY
-  if((local->spy_number > 0) && (local->sparm.b5.a_network_type == 0))
+  if((local->spy_data.spy_number > 0) && (local->sparm.b5.a_network_type == 0))
     {
       /* Get it from the first node in spy list */
-      local->wstats.qual.qual = local->spy_stat[0].qual;
-      local->wstats.qual.level = local->spy_stat[0].level;
-      local->wstats.qual.noise = local->spy_stat[0].noise;
-      local->wstats.qual.updated = local->spy_stat[0].updated;
+      local->wstats.qual.qual = local->spy_data.spy_stat[0].qual;
+      local->wstats.qual.level = local->spy_data.spy_stat[0].level;
+      local->wstats.qual.noise = local->spy_data.spy_stat[0].noise;
+      local->wstats.qual.updated = local->spy_data.spy_stat[0].updated;
     }
 #endif /* WIRELESS_SPY */
 
@@ -1659,7 +1642,65 @@ static iw_stats * ray_get_wireless_stats(struct net_device *     dev)
 
   return &local->wstats;
 } /* end ray_get_wireless_stats */
-#endif /* WIRELESS_EXT > 7 */
+
+/*------------------------------------------------------------------*/
+/*
+ * Structures to export the Wireless Handlers
+ */
+
+static const iw_handler        ray_handler[] = {
+       [SIOCSIWCOMMIT-SIOCIWFIRST] (iw_handler) ray_commit,
+       [SIOCGIWNAME  -SIOCIWFIRST] (iw_handler) ray_get_name,
+       [SIOCSIWFREQ  -SIOCIWFIRST] (iw_handler) ray_set_freq,
+       [SIOCGIWFREQ  -SIOCIWFIRST] (iw_handler) ray_get_freq,
+       [SIOCSIWMODE  -SIOCIWFIRST] (iw_handler) ray_set_mode,
+       [SIOCGIWMODE  -SIOCIWFIRST] (iw_handler) ray_get_mode,
+       [SIOCGIWRANGE -SIOCIWFIRST] (iw_handler) ray_get_range,
+#ifdef WIRELESS_SPY
+       [SIOCSIWSPY   -SIOCIWFIRST] (iw_handler) iw_handler_set_spy,
+       [SIOCGIWSPY   -SIOCIWFIRST] (iw_handler) iw_handler_get_spy,
+       [SIOCSIWTHRSPY-SIOCIWFIRST] (iw_handler) iw_handler_set_thrspy,
+       [SIOCGIWTHRSPY-SIOCIWFIRST] (iw_handler) iw_handler_get_thrspy,
+#endif /* WIRELESS_SPY */
+       [SIOCGIWAP    -SIOCIWFIRST] (iw_handler) ray_get_wap,
+       [SIOCSIWESSID -SIOCIWFIRST] (iw_handler) ray_set_essid,
+       [SIOCGIWESSID -SIOCIWFIRST] (iw_handler) ray_get_essid,
+       [SIOCSIWRATE  -SIOCIWFIRST] (iw_handler) ray_set_rate,
+       [SIOCGIWRATE  -SIOCIWFIRST] (iw_handler) ray_get_rate,
+       [SIOCSIWRTS   -SIOCIWFIRST] (iw_handler) ray_set_rts,
+       [SIOCGIWRTS   -SIOCIWFIRST] (iw_handler) ray_get_rts,
+       [SIOCSIWFRAG  -SIOCIWFIRST] (iw_handler) ray_set_frag,
+       [SIOCGIWFRAG  -SIOCIWFIRST] (iw_handler) ray_get_frag,
+};
+
+#define SIOCSIPFRAMING SIOCIWFIRSTPRIV         /* Set framing mode */
+#define SIOCGIPFRAMING SIOCIWFIRSTPRIV + 1     /* Get framing mode */
+#define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3     /* Get country code */
+
+static const iw_handler        ray_private_handler[] = {
+       [0] (iw_handler) ray_set_framing,
+       [1] (iw_handler) ray_get_framing,
+       [3] (iw_handler) ray_get_country,
+};
+
+static const struct iw_priv_args       ray_private_args[] = {
+/* cmd,                set_args,       get_args,       name */
+{ SIOCSIPFRAMING, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "set_framing" },
+{ SIOCGIPFRAMING, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "get_framing" },
+{ SIOCGIPCOUNTRY, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "get_country" },
+};
+
+static const struct iw_handler_def     ray_handler_def =
+{
+       .num_standard   = sizeof(ray_handler)/sizeof(iw_handler),
+       .num_private    = sizeof(ray_private_handler)/sizeof(iw_handler),
+       .num_private_args = sizeof(ray_private_args)/sizeof(struct iw_priv_args),
+       .standard       = ray_handler,
+       .private        = ray_private_handler,
+       .private_args   = ray_private_args,
+       .get_wireless_stats = ray_get_wireless_stats,
+};
+
 /*===========================================================================*/
 static int ray_open(struct net_device *dev)
 {
@@ -2392,20 +2433,15 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned i
        /*local->wstats.qual.noise = none ? */
        local->wstats.qual.updated = 0x2;
       }
-    /* Now, for the addresses in the spy list */
+    /* Now, update the spy stuff */
     {
-      int      i;
-      /* Look all addresses */
-      for(i = 0; i < local->spy_number; i++)
-       /* If match */
-       if(!memcmp(linksrcaddr, local->spy_address[i], ETH_ALEN))
-         {
-           /* Update statistics */
-           /*local->spy_stat[i].qual = none ? */
-           local->spy_stat[i].level = siglev;
-           /*local->spy_stat[i].noise = none ? */
-           local->spy_stat[i].updated = 0x2;
-         }
+       struct iw_quality wstats;
+       wstats.level = siglev;
+       /* wstats.noise = none ? */
+       /* wstats.qual = none ? */
+       wstats.updated = 0x2;
+       /* Update spy records */
+       wireless_spy_update(dev, linksrcaddr, &wstats);
     }
 #endif /* WIRELESS_SPY */
 } /* end rx_data */
index c77afa14fa86347a4eabc1eeffde559cecaa7367..42660fe64bfd900e8755a4a62dc8641581e13d4b 100644 (file)
@@ -63,13 +63,10 @@ typedef struct ray_dev_t {
     UCHAR last_rsl;
     int beacon_rxed;
     struct beacon_rx last_bcn;
-#ifdef WIRELESS_EXT
     iw_stats   wstats;         /* Wireless specific stats */
-#endif
 #ifdef WIRELESS_SPY
-    int                spy_number;             /* Number of addresses to spy */
-    mac_addr   spy_address[IW_MAX_SPY + 1];    /* The addresses to spy */
-    iw_qual    spy_stat[IW_MAX_SPY + 1];       /* Statistics gathered */
+    struct iw_spy_data         spy_data;
+    struct iw_public_data      wireless_data;
 #endif /* WIRELESS_SPY */
 
 } ray_dev_t;
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
new file mode 100644 (file)
index 0000000..39c6cdf
--- /dev/null
@@ -0,0 +1,1120 @@
+/*
+ * Driver for 802.11b cards using RAM-loadable Symbol firmware, such as
+ * Symbol Wireless Networker LA4100, CompactFlash cards by Socket
+ * Communications and Intel PRO/Wireless 2011B.
+ *
+ * The driver implements Symbol firmware download.  The rest is handled
+ * in hermes.c and orinoco.c.
+ *
+ * Utilities for downloading the Symbol firmware are available at
+ * http://sourceforge.net/projects/orinoco/
+ *
+ * Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org>
+ * Portions based on orinoco_cs.c:
+ *     Copyright (C) David Gibson, Linuxcare Australia
+ * Portions based on Spectrum24tDnld.c from original spectrum24 driver:
+ *     Copyright (C) Symbol Technologies.
+ *
+ * See copyright notice in file orinoco.c.
+ */
+
+#define DRIVER_NAME "spectrum_cs"
+#define PFX DRIVER_NAME ": "
+
+#include <linux/config.h>
+#ifdef  __IN_PCMCIA_PACKAGE__
+#include <pcmcia/k_compat.h>
+#endif /* __IN_PCMCIA_PACKAGE__ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include "orinoco.h"
+
+/*
+ * If SPECTRUM_FW_INCLUDED is defined, the firmware is hardcoded into
+ * the driver.  Use get_symbol_fw script to generate spectrum_fw.h and
+ * copy it to the same directory as spectrum_cs.c.
+ *
+ * If SPECTRUM_FW_INCLUDED is not defined, the firmware is loaded at the
+ * runtime using hotplug.  Use the same get_symbol_fw script to generate
+ * files symbol_sp24t_prim_fw symbol_sp24t_sec_fw, copy them to the
+ * hotplug firmware directory (typically /usr/lib/hotplug/firmware) and
+ * make sure that you have hotplug installed and enabled in the kernel.
+ */
+/* #define SPECTRUM_FW_INCLUDED 1 */
+
+#ifdef SPECTRUM_FW_INCLUDED
+/* Header with the firmware */
+#include "spectrum_fw.h"
+#else  /* !SPECTRUM_FW_INCLUDED */
+#include <linux/firmware.h>
+static unsigned char *primsym;
+static unsigned char *secsym;
+static const char primary_fw_name[] = "symbol_sp24t_prim_fw";
+static const char secondary_fw_name[] = "symbol_sp24t_sec_fw";
+#endif /* !SPECTRUM_FW_INCLUDED */
+
+/********************************************************************/
+/* Module stuff                                                            */
+/********************************************************************/
+
+MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>");
+MODULE_DESCRIPTION("Driver for Symbol Spectrum24 Trilogy cards with firmware downloader");
+MODULE_LICENSE("Dual MPL/GPL");
+
+/* Module parameters */
+
+/* Some D-Link cards have buggy CIS. They do work at 5v properly, but
+ * don't have any CIS entry for it. This workaround it... */
+static int ignore_cis_vcc; /* = 0 */
+module_param(ignore_cis_vcc, int, 0);
+MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket");
+
+/********************************************************************/
+/* Magic constants                                                 */
+/********************************************************************/
+
+/*
+ * The dev_info variable is the "key" that is used to match up this
+ * device driver with appropriate cards, through the card
+ * configuration database.
+ */
+static dev_info_t dev_info = DRIVER_NAME;
+
+/********************************************************************/
+/* Data structures                                                 */
+/********************************************************************/
+
+/* PCMCIA specific device information (goes in the card field of
+ * struct orinoco_private */
+struct orinoco_pccard {
+       dev_link_t link;
+       dev_node_t node;
+};
+
+/*
+ * A linked list of "instances" of the device.  Each actual PCMCIA
+ * card corresponds to one device instance, and is described by one
+ * dev_link_t structure (defined in ds.h).
+ */
+static dev_link_t *dev_list; /* = NULL */
+
+/********************************************************************/
+/* Function prototypes                                             */
+/********************************************************************/
+
+/* device methods */
+static int spectrum_cs_hard_reset(struct orinoco_private *priv);
+
+/* PCMCIA gumpf */
+static void spectrum_cs_config(dev_link_t * link);
+static void spectrum_cs_release(dev_link_t * link);
+static int spectrum_cs_event(event_t event, int priority,
+                           event_callback_args_t * args);
+
+static dev_link_t *spectrum_cs_attach(void);
+static void spectrum_cs_detach(dev_link_t *);
+
+/********************************************************************/
+/* Firmware downloader                                             */
+/********************************************************************/
+
+/* Position of PDA in the adapter memory */
+#define EEPROM_ADDR    0x3000
+#define EEPROM_LEN     0x200
+#define PDA_OFFSET     0x100
+
+#define PDA_ADDR       (EEPROM_ADDR + PDA_OFFSET)
+#define PDA_WORDS      ((EEPROM_LEN - PDA_OFFSET) / 2)
+
+/* Constants for the CISREG_CCSR register */
+#define HCR_RUN                0x07    /* run firmware after reset */
+#define HCR_IDLE       0x0E    /* don't run firmware after reset */
+#define HCR_MEM16      0x10    /* memory width bit, should be preserved */
+
+/*
+ * AUX port access.  To unlock the AUX port write the access keys to the
+ * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
+ * register.  Then read it and make sure it's HERMES_AUX_ENABLED.
+ */
+#define HERMES_AUX_ENABLE      0x8000  /* Enable auxiliary port access */
+#define HERMES_AUX_DISABLE     0x4000  /* Disable to auxiliary port access */
+#define HERMES_AUX_ENABLED     0xC000  /* Auxiliary port is open */
+
+#define HERMES_AUX_PW0 0xFE01
+#define HERMES_AUX_PW1 0xDC23
+#define HERMES_AUX_PW2 0xBA45
+
+/* End markers */
+#define PDI_END                0x00000000      /* End of PDA */
+#define BLOCK_END      0xFFFFFFFF      /* Last image block */
+#define TEXT_END       0x1A            /* End of text header */
+
+/*
+ * The following structures have little-endian fields denoted by
+ * the leading underscore.  Don't access them directly - use inline
+ * functions defined below.
+ */
+
+/*
+ * The binary image to be downloaded consists of series of data blocks.
+ * Each block has the following structure.
+ */
+struct dblock {
+       u32 _addr;              /* adapter address where to write the block */
+       u16 _len;               /* length of the data only, in bytes */
+       char data[0];           /* data to be written */
+} __attribute__ ((packed));
+
+/*
+ * Plug Data References are located in in the image after the last data
+ * block.  They refer to areas in the adapter memory where the plug data
+ * items with matching ID should be written.
+ */
+struct pdr {
+       u32 _id;                /* record ID */
+       u32 _addr;              /* adapter address where to write the data */
+       u32 _len;               /* expected length of the data, in bytes */
+       char next[0];           /* next PDR starts here */
+} __attribute__ ((packed));
+
+
+/*
+ * Plug Data Items are located in the EEPROM read from the adapter by
+ * primary firmware.  They refer to the device-specific data that should
+ * be plugged into the secondary firmware.
+ */
+struct pdi {
+       u16 _len;               /* length of ID and data, in words */
+       u16 _id;                /* record ID */
+       char data[0];           /* plug data */
+} __attribute__ ((packed));;
+
+
+/* Functions for access to little-endian data */
+static inline u32
+dblock_addr(const struct dblock *blk)
+{
+       return le32_to_cpu(blk->_addr);
+}
+
+static inline u32
+dblock_len(const struct dblock *blk)
+{
+       return le16_to_cpu(blk->_len);
+}
+
+static inline u32
+pdr_id(const struct pdr *pdr)
+{
+       return le32_to_cpu(pdr->_id);
+}
+
+static inline u32
+pdr_addr(const struct pdr *pdr)
+{
+       return le32_to_cpu(pdr->_addr);
+}
+
+static inline u32
+pdr_len(const struct pdr *pdr)
+{
+       return le32_to_cpu(pdr->_len);
+}
+
+static inline u32
+pdi_id(const struct pdi *pdi)
+{
+       return le16_to_cpu(pdi->_id);
+}
+
+/* Return length of the data only, in bytes */
+static inline u32
+pdi_len(const struct pdi *pdi)
+{
+       return 2 * (le16_to_cpu(pdi->_len) - 1);
+}
+
+
+/* Set address of the auxiliary port */
+static inline void
+spectrum_aux_setaddr(hermes_t *hw, u32 addr)
+{
+       hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
+       hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
+}
+
+
+/* Open access to the auxiliary port */
+static int
+spectrum_aux_open(hermes_t *hw)
+{
+       int i;
+
+       /* Already open? */
+       if (hermes_read_reg(hw, HERMES_CONTROL) == HERMES_AUX_ENABLED)
+               return 0;
+
+       hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
+       hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
+       hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
+       hermes_write_reg(hw, HERMES_CONTROL, HERMES_AUX_ENABLE);
+
+       for (i = 0; i < 20; i++) {
+               udelay(10);
+               if (hermes_read_reg(hw, HERMES_CONTROL) ==
+                   HERMES_AUX_ENABLED)
+                       return 0;
+       }
+
+       return -EBUSY;
+}
+
+
+#define CS_CHECK(fn, ret) \
+  do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+
+/*
+ * Reset the card using configuration registers COR and CCSR.
+ * If IDLE is 1, stop the firmware, so that it can be safely rewritten.
+ */
+static int
+spectrum_reset(dev_link_t *link, int idle)
+{
+       int last_ret, last_fn;
+       conf_reg_t reg;
+       u_int save_cor;
+
+       /* Doing it if hardware is gone is guaranteed crash */
+       if (!(link->state & DEV_CONFIG))
+               return -ENODEV;
+
+       /* Save original COR value */
+       reg.Function = 0;
+       reg.Action = CS_READ;
+       reg.Offset = CISREG_COR;
+       CS_CHECK(AccessConfigurationRegister,
+                pcmcia_access_configuration_register(link->handle, &reg));
+       save_cor = reg.Value;
+
+       /* Soft-Reset card */
+       reg.Action = CS_WRITE;
+       reg.Offset = CISREG_COR;
+       reg.Value = (save_cor | COR_SOFT_RESET);
+       CS_CHECK(AccessConfigurationRegister,
+                pcmcia_access_configuration_register(link->handle, &reg));
+       udelay(1000);
+
+       /* Read CCSR */
+       reg.Action = CS_READ;
+       reg.Offset = CISREG_CCSR;
+       CS_CHECK(AccessConfigurationRegister,
+                pcmcia_access_configuration_register(link->handle, &reg));
+
+       /*
+        * Start or stop the firmware.  Memory width bit should be
+        * preserved from the value we've just read.
+        */
+       reg.Action = CS_WRITE;
+       reg.Offset = CISREG_CCSR;
+       reg.Value = (idle ? HCR_IDLE : HCR_RUN) | (reg.Value & HCR_MEM16);
+       CS_CHECK(AccessConfigurationRegister,
+                pcmcia_access_configuration_register(link->handle, &reg));
+       udelay(1000);
+
+       /* Restore original COR configuration index */
+       reg.Action = CS_WRITE;
+       reg.Offset = CISREG_COR;
+       reg.Value = (save_cor & ~COR_SOFT_RESET);
+       CS_CHECK(AccessConfigurationRegister,
+                pcmcia_access_configuration_register(link->handle, &reg));
+       udelay(1000);
+       return 0;
+
+      cs_failed:
+       cs_error(link->handle, last_fn, last_ret);
+       return -ENODEV;
+}
+
+
+/*
+ * Scan PDR for the record with the specified RECORD_ID.
+ * If it's not found, return NULL.
+ */
+static struct pdr *
+spectrum_find_pdr(struct pdr *first_pdr, u32 record_id)
+{
+       struct pdr *pdr = first_pdr;
+
+       while (pdr_id(pdr) != PDI_END) {
+               /*
+                * PDR area is currently not terminated by PDI_END.
+                * It's followed by CRC records, which have the type
+                * field where PDR has length.  The type can be 0 or 1.
+                */
+               if (pdr_len(pdr) < 2)
+                       return NULL;
+
+               /* If the record ID matches, we are done */
+               if (pdr_id(pdr) == record_id)
+                       return pdr;
+
+               pdr = (struct pdr *) pdr->next;
+       }
+       return NULL;
+}
+
+
+/* Process one Plug Data Item - find corresponding PDR and plug it */
+static int
+spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi)
+{
+       struct pdr *pdr;
+
+       /* Find the PDI corresponding to this PDR */
+       pdr = spectrum_find_pdr(first_pdr, pdi_id(pdi));
+
+       /* No match is found, safe to ignore */
+       if (!pdr)
+               return 0;
+
+       /* Lengths of the data in PDI and PDR must match */
+       if (pdi_len(pdi) != pdr_len(pdr))
+               return -EINVAL;
+
+       /* do the actual plugging */
+       spectrum_aux_setaddr(hw, pdr_addr(pdr));
+       hermes_write_words(hw, HERMES_AUXDATA, pdi->data,
+                          pdi_len(pdi) / 2);
+
+       return 0;
+}
+
+
+/* Read PDA from the adapter */
+static int
+spectrum_read_pda(hermes_t *hw, u16 *pda, int pda_len)
+{
+       int ret;
+       int pda_size;
+
+       /* Issue command to read EEPROM */
+       ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
+       if (ret)
+               return ret;
+
+       /* Open auxiliary port */
+       ret = spectrum_aux_open(hw);
+       if (ret)
+               return ret;
+
+       /* read PDA from EEPROM */
+       spectrum_aux_setaddr(hw, PDA_ADDR);
+       hermes_read_words(hw, HERMES_AUXDATA, pda, pda_len / 2);
+
+       /* Check PDA length */
+       pda_size = le16_to_cpu(pda[0]);
+       if (pda_size > pda_len)
+               return -EINVAL;
+
+       return 0;
+}
+
+
+/* Parse PDA and write the records into the adapter */
+static int
+spectrum_apply_pda(hermes_t *hw, const struct dblock *first_block,
+                  u16 *pda)
+{
+       int ret;
+       struct pdi *pdi;
+       struct pdr *first_pdr;
+       const struct dblock *blk = first_block;
+
+       /* Skip all blocks to locate Plug Data References */
+       while (dblock_addr(blk) != BLOCK_END)
+               blk = (struct dblock *) &blk->data[dblock_len(blk)];
+
+       first_pdr = (struct pdr *) blk;
+
+       /* Go through every PDI and plug them into the adapter */
+       pdi = (struct pdi *) (pda + 2);
+       while (pdi_id(pdi) != PDI_END) {
+               ret = spectrum_plug_pdi(hw, first_pdr, pdi);
+               if (ret)
+                       return ret;
+
+               /* Increment to the next PDI */
+               pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
+       }
+       return 0;
+}
+
+
+/* Load firmware blocks into the adapter */
+static int
+spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block)
+{
+       const struct dblock *blk;
+       u32 blkaddr;
+       u32 blklen;
+
+       blk = first_block;
+       blkaddr = dblock_addr(blk);
+       blklen = dblock_len(blk);
+
+       while (dblock_addr(blk) != BLOCK_END) {
+               spectrum_aux_setaddr(hw, blkaddr);
+               hermes_write_words(hw, HERMES_AUXDATA, blk->data,
+                                  blklen / 2);
+
+               blk = (struct dblock *) &blk->data[blklen];
+               blkaddr = dblock_addr(blk);
+               blklen = dblock_len(blk);
+       }
+       return 0;
+}
+
+
+/*
+ * Process a firmware image - stop the card, load the firmware, reset
+ * the card and make sure it responds.  For the secondary firmware take
+ * care of the PDA - read it and then write it on top of the firmware.
+ */
+static int
+spectrum_dl_image(hermes_t *hw, dev_link_t *link,
+                 const unsigned char *image)
+{
+       int ret;
+       const unsigned char *ptr;
+       const struct dblock *first_block;
+
+       /* Plug Data Area (PDA) */
+       u16 pda[PDA_WORDS];
+
+       /* Binary block begins after the 0x1A marker */
+       ptr = image;
+       while (*ptr++ != TEXT_END);
+       first_block = (const struct dblock *) ptr;
+
+       /* Read the PDA */
+       if (image != primsym) {
+               ret = spectrum_read_pda(hw, pda, sizeof(pda));
+               if (ret)
+                       return ret;
+       }
+
+       /* Stop the firmware, so that it can be safely rewritten */
+       ret = spectrum_reset(link, 1);
+       if (ret)
+               return ret;
+
+       /* Program the adapter with new firmware */
+       ret = spectrum_load_blocks(hw, first_block);
+       if (ret)
+               return ret;
+
+       /* Write the PDA to the adapter */
+       if (image != primsym) {
+               ret = spectrum_apply_pda(hw, first_block, pda);
+               if (ret)
+                       return ret;
+       }
+
+       /* Run the firmware */
+       ret = spectrum_reset(link, 0);
+       if (ret)
+               return ret;
+
+       /* Reset hermes chip and make sure it responds */
+       ret = hermes_init(hw);
+
+       /* hermes_reset() should return 0 with the secondary firmware */
+       if (image != primsym && ret != 0)
+               return -ENODEV;
+
+       /* And this should work with any firmware */
+       if (!hermes_present(hw))
+               return -ENODEV;
+
+       return 0;
+}
+
+
+/*
+ * Download the firmware into the card, this also does a PCMCIA soft
+ * reset on the card, to make sure it's in a sane state.
+ */
+static int
+spectrum_dl_firmware(hermes_t *hw, dev_link_t *link)
+{
+       int ret;
+       client_handle_t handle = link->handle;
+
+#ifndef SPECTRUM_FW_INCLUDED
+       const struct firmware *fw_entry;
+
+       if (request_firmware(&fw_entry, primary_fw_name,
+                            &handle_to_dev(handle)) == 0) {
+               primsym = fw_entry->data;
+       } else {
+               printk(KERN_ERR PFX "Cannot find firmware: %s\n",
+                      primary_fw_name);
+               return -ENOENT;
+       }
+
+       if (request_firmware(&fw_entry, secondary_fw_name,
+                            &handle_to_dev(handle)) == 0) {
+               secsym = fw_entry->data;
+       } else {
+               printk(KERN_ERR PFX "Cannot find firmware: %s\n",
+                      secondary_fw_name);
+               return -ENOENT;
+       }
+#endif
+
+       /* Load primary firmware */
+       ret = spectrum_dl_image(hw, link, primsym);
+       if (ret) {
+               printk(KERN_ERR PFX "Primary firmware download failed\n");
+               return ret;
+       }
+
+       /* Load secondary firmware */
+       ret = spectrum_dl_image(hw, link, secsym);
+
+       if (ret) {
+               printk(KERN_ERR PFX "Secondary firmware download failed\n");
+       }
+
+       return ret;
+}
+
+/********************************************************************/
+/* Device methods                                                  */
+/********************************************************************/
+
+static int
+spectrum_cs_hard_reset(struct orinoco_private *priv)
+{
+       struct orinoco_pccard *card = priv->card;
+       dev_link_t *link = &card->link;
+       int err;
+
+       if (!hermes_present(&priv->hw)) {
+               /* The firmware needs to be reloaded */
+               if (spectrum_dl_firmware(&priv->hw, &card->link) != 0) {
+                       printk(KERN_ERR PFX "Firmware download failed\n");
+                       err = -ENODEV;
+               }
+       } else {
+               /* Soft reset using COR and HCR */
+               spectrum_reset(link, 0);
+       }
+
+       return 0;
+}
+
+/********************************************************************/
+/* PCMCIA stuff                                                    */
+/********************************************************************/
+
+/*
+ * This creates an "instance" of the driver, allocating local data
+ * structures for one device.  The device is registered with Card
+ * Services.
+ * 
+ * The dev_link structure is initialized, but we don't actually
+ * configure the card at this point -- we wait until we receive a card
+ * insertion event.  */
+static dev_link_t *
+spectrum_cs_attach(void)
+{
+       struct net_device *dev;
+       struct orinoco_private *priv;
+       struct orinoco_pccard *card;
+       dev_link_t *link;
+       client_reg_t client_reg;
+       int ret;
+
+       dev = alloc_orinocodev(sizeof(*card), spectrum_cs_hard_reset);
+       if (! dev)
+               return NULL;
+       priv = netdev_priv(dev);
+       card = priv->card;
+
+       /* Link both structures together */
+       link = &card->link;
+       link->priv = dev;
+
+       /* Interrupt setup */
+       link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+       link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+       link->irq.Handler = orinoco_interrupt;
+       link->irq.Instance = dev; 
+
+       /* General socket configuration defaults can go here.  In this
+        * client, we assume very little, and rely on the CIS for
+        * almost everything.  In most clients, many details (i.e.,
+        * number, sizes, and attributes of IO windows) are fixed by
+        * the nature of the device, and can be hard-wired here. */
+       link->conf.Attributes = 0;
+       link->conf.IntType = INT_MEMORY_AND_IO;
+
+       /* Register with Card Services */
+       /* FIXME: need a lock? */
+       link->next = dev_list;
+       dev_list = link;
+
+       client_reg.dev_info = &dev_info;
+       client_reg.Version = 0x0210; /* FIXME: what does this mean? */
+       client_reg.event_callback_args.client_data = link;
+
+       ret = pcmcia_register_client(&link->handle, &client_reg);
+       if (ret != CS_SUCCESS) {
+               cs_error(link->handle, RegisterClient, ret);
+               spectrum_cs_detach(link);
+               return NULL;
+       }
+
+       return link;
+}                              /* spectrum_cs_attach */
+
+/*
+ * This deletes a driver "instance".  The device is de-registered with
+ * Card Services.  If it has been released, all local data structures
+ * are freed.  Otherwise, the structures will be freed when the device
+ * is released.
+ */
+static void spectrum_cs_detach(dev_link_t *link)
+{
+       dev_link_t **linkp;
+       struct net_device *dev = link->priv;
+
+       /* Locate device structure */
+       for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+               if (*linkp == link)
+                       break;
+
+       BUG_ON(*linkp == NULL);
+
+       if (link->state & DEV_CONFIG)
+               spectrum_cs_release(link);
+
+       /* Break the link with Card Services */
+       if (link->handle)
+               pcmcia_deregister_client(link->handle);
+
+       /* Unlink device structure, and free it */
+       *linkp = link->next;
+       DEBUG(0, PFX "detach: link=%p link->dev=%p\n", link, link->dev);
+       if (link->dev) {
+               DEBUG(0, PFX "About to unregister net device %p\n",
+                     dev);
+               unregister_netdev(dev);
+       }
+       free_orinocodev(dev);
+}                              /* spectrum_cs_detach */
+
+/*
+ * spectrum_cs_config() is scheduled to run after a CARD_INSERTION
+ * event is received, to configure the PCMCIA socket, and to make the
+ * device available to the system.
+ */
+
+static void
+spectrum_cs_config(dev_link_t *link)
+{
+       struct net_device *dev = link->priv;
+       client_handle_t handle = link->handle;
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_pccard *card = priv->card;
+       hermes_t *hw = &priv->hw;
+       int last_fn, last_ret;
+       u_char buf[64];
+       config_info_t conf;
+       cisinfo_t info;
+       tuple_t tuple;
+       cisparse_t parse;
+       void __iomem *mem;
+
+       CS_CHECK(ValidateCIS, pcmcia_validate_cis(handle, &info));
+
+       /*
+        * This reads the card's CONFIG tuple to find its
+        * configuration registers.
+        */
+       tuple.DesiredTuple = CISTPL_CONFIG;
+       tuple.Attributes = 0;
+       tuple.TupleData = buf;
+       tuple.TupleDataMax = sizeof(buf);
+       tuple.TupleOffset = 0;
+       CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+       CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+       CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+       link->conf.ConfigBase = parse.config.base;
+       link->conf.Present = parse.config.rmask[0];
+
+       /* Configure card */
+       link->state |= DEV_CONFIG;
+
+       /* Look up the current Vcc */
+       CS_CHECK(GetConfigurationInfo,
+                pcmcia_get_configuration_info(handle, &conf));
+       link->conf.Vcc = conf.Vcc;
+
+       /*
+        * In this loop, we scan the CIS for configuration table
+        * entries, each of which describes a valid card
+        * configuration, including voltage, IO window, memory window,
+        * and interrupt settings.
+        *
+        * We make no assumptions about the card to be configured: we
+        * use just the information available in the CIS.  In an ideal
+        * world, this would work for any PCMCIA card, but it requires
+        * a complete and accurate CIS.  In practice, a driver usually
+        * "knows" most of these things without consulting the CIS,
+        * and most client drivers will only use the CIS to fill in
+        * implementation-defined details.
+        */
+       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+       CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+       while (1) {
+               cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+               cistpl_cftable_entry_t dflt = { .index = 0 };
+
+               if ( (pcmcia_get_tuple_data(handle, &tuple) != 0)
+                   || (pcmcia_parse_tuple(handle, &tuple, &parse) != 0))
+                       goto next_entry;
+
+               if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
+                       dflt = *cfg;
+               if (cfg->index == 0)
+                       goto next_entry;
+               link->conf.ConfigIndex = cfg->index;
+
+               /* Does this card need audio output? */
+               if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+                       link->conf.Attributes |= CONF_ENABLE_SPKR;
+                       link->conf.Status = CCSR_AUDIO_ENA;
+               }
+
+               /* Use power settings for Vcc and Vpp if present */
+               /* Note that the CIS values need to be rescaled */
+               if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+                       if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
+                               DEBUG(2, "spectrum_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
+                               if (!ignore_cis_vcc)
+                                       goto next_entry;
+                       }
+               } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
+                       if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) {
+                               DEBUG(2, "spectrum_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
+                               if(!ignore_cis_vcc)
+                                       goto next_entry;
+                       }
+               }
+
+               if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+                       link->conf.Vpp1 = link->conf.Vpp2 =
+                           cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+               else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
+                       link->conf.Vpp1 = link->conf.Vpp2 =
+                           dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
+               
+               /* Do we need to allocate an interrupt? */
+               link->conf.Attributes |= CONF_ENABLE_IRQ;
+
+               /* IO window settings */
+               link->io.NumPorts1 = link->io.NumPorts2 = 0;
+               if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+                       cistpl_io_t *io =
+                           (cfg->io.nwin) ? &cfg->io : &dflt.io;
+                       link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+                       if (!(io->flags & CISTPL_IO_8BIT))
+                               link->io.Attributes1 =
+                                   IO_DATA_PATH_WIDTH_16;
+                       if (!(io->flags & CISTPL_IO_16BIT))
+                               link->io.Attributes1 =
+                                   IO_DATA_PATH_WIDTH_8;
+                       link->io.IOAddrLines =
+                           io->flags & CISTPL_IO_LINES_MASK;
+                       link->io.BasePort1 = io->win[0].base;
+                       link->io.NumPorts1 = io->win[0].len;
+                       if (io->nwin > 1) {
+                               link->io.Attributes2 =
+                                   link->io.Attributes1;
+                               link->io.BasePort2 = io->win[1].base;
+                               link->io.NumPorts2 = io->win[1].len;
+                       }
+
+                       /* This reserves IO space but doesn't actually enable it */
+                       if (pcmcia_request_io(link->handle, &link->io) != 0)
+                               goto next_entry;
+               }
+
+
+               /* If we got this far, we're cool! */
+
+               break;
+               
+       next_entry:
+               if (link->io.NumPorts1)
+                       pcmcia_release_io(link->handle, &link->io);
+               last_ret = pcmcia_get_next_tuple(handle, &tuple);
+               if (last_ret  == CS_NO_MORE_ITEMS) {
+                       printk(KERN_ERR PFX "GetNextTuple(): No matching "
+                              "CIS configuration.  Maybe you need the "
+                              "ignore_cis_vcc=1 parameter.\n");
+                       goto cs_failed;
+               }
+       }
+
+       /*
+        * Allocate an interrupt line.  Note that this does not assign
+        * a handler to the interrupt, unless the 'Handler' member of
+        * the irq structure is initialized.
+        */
+       CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+
+       /* We initialize the hermes structure before completing PCMCIA
+        * configuration just in case the interrupt handler gets
+        * called. */
+       mem = ioport_map(link->io.BasePort1, link->io.NumPorts1);
+       if (!mem)
+               goto cs_failed;
+
+       hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
+
+       /*
+        * This actually configures the PCMCIA socket -- setting up
+        * the I/O windows and the interrupt mapping, and putting the
+        * card and host interface into "Memory and IO" mode.
+        */
+       CS_CHECK(RequestConfiguration,
+                pcmcia_request_configuration(link->handle, &link->conf));
+
+       /* Ok, we have the configuration, prepare to register the netdev */
+       dev->base_addr = link->io.BasePort1;
+       dev->irq = link->irq.AssignedIRQ;
+       SET_MODULE_OWNER(dev);
+       card->node.major = card->node.minor = 0;
+
+       /* Reset card and download firmware */
+       if (spectrum_cs_hard_reset(priv) != 0) {
+               goto failed;
+       }
+
+       SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+       /* Tell the stack we exist */
+       if (register_netdev(dev) != 0) {
+               printk(KERN_ERR PFX "register_netdev() failed\n");
+               goto failed;
+       }
+
+       /* At this point, the dev_node_t structure(s) needs to be
+        * initialized and arranged in a linked list at link->dev. */
+       strcpy(card->node.dev_name, dev->name);
+       link->dev = &card->node; /* link->dev being non-NULL is also
+                                    used to indicate that the
+                                    net_device has been registered */
+       link->state &= ~DEV_CONFIG_PENDING;
+
+       /* Finally, report what we've done */
+       printk(KERN_DEBUG "%s: index 0x%02x: Vcc %d.%d",
+              dev->name, link->conf.ConfigIndex,
+              link->conf.Vcc / 10, link->conf.Vcc % 10);
+       if (link->conf.Vpp1)
+               printk(", Vpp %d.%d", link->conf.Vpp1 / 10,
+                      link->conf.Vpp1 % 10);
+       printk(", irq %d", link->irq.AssignedIRQ);
+       if (link->io.NumPorts1)
+               printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+                      link->io.BasePort1 + link->io.NumPorts1 - 1);
+       if (link->io.NumPorts2)
+               printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+                      link->io.BasePort2 + link->io.NumPorts2 - 1);
+       printk("\n");
+
+       return;
+
+ cs_failed:
+       cs_error(link->handle, last_fn, last_ret);
+
+ failed:
+       spectrum_cs_release(link);
+}                              /* spectrum_cs_config */
+
+/*
+ * After a card is removed, spectrum_cs_release() will unregister the
+ * device, and release the PCMCIA configuration.  If the device is
+ * still open, this will be postponed until it is closed.
+ */
+static void
+spectrum_cs_release(dev_link_t *link)
+{
+       struct net_device *dev = link->priv;
+       struct orinoco_private *priv = netdev_priv(dev);
+       unsigned long flags;
+
+       /* We're committed to taking the device away now, so mark the
+        * hardware as unavailable */
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->hw_unavailable++;
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       /* Don't bother checking to see if these succeed or not */
+       pcmcia_release_configuration(link->handle);
+       if (link->io.NumPorts1)
+               pcmcia_release_io(link->handle, &link->io);
+       if (link->irq.AssignedIRQ)
+               pcmcia_release_irq(link->handle, &link->irq);
+       link->state &= ~DEV_CONFIG;
+       if (priv->hw.iobase)
+               ioport_unmap(priv->hw.iobase);
+}                              /* spectrum_cs_release */
+
+/*
+ * The card status event handler.  Mostly, this schedules other stuff
+ * to run after an event is received.
+ */
+static int
+spectrum_cs_event(event_t event, int priority,
+                      event_callback_args_t * args)
+{
+       dev_link_t *link = args->client_data;
+       struct net_device *dev = link->priv;
+       struct orinoco_private *priv = netdev_priv(dev);
+       int err = 0;
+       unsigned long flags;
+
+       switch (event) {
+       case CS_EVENT_CARD_REMOVAL:
+               link->state &= ~DEV_PRESENT;
+               if (link->state & DEV_CONFIG) {
+                       unsigned long flags;
+
+                       spin_lock_irqsave(&priv->lock, flags);
+                       netif_device_detach(dev);
+                       priv->hw_unavailable++;
+                       spin_unlock_irqrestore(&priv->lock, flags);
+               }
+               break;
+
+       case CS_EVENT_CARD_INSERTION:
+               link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+               spectrum_cs_config(link);
+               break;
+
+       case CS_EVENT_PM_SUSPEND:
+               link->state |= DEV_SUSPEND;
+               /* Fall through... */
+       case CS_EVENT_RESET_PHYSICAL:
+               /* Mark the device as stopped, to block IO until later */
+               if (link->state & DEV_CONFIG) {
+                       /* This is probably racy, but I can't think of
+                           a better way, short of rewriting the PCMCIA
+                           layer to not suck :-( */
+                       spin_lock_irqsave(&priv->lock, flags);
+
+                       err = __orinoco_down(dev);
+                       if (err)
+                               printk(KERN_WARNING "%s: %s: Error %d downing interface\n",
+                                      dev->name,
+                                      event == CS_EVENT_PM_SUSPEND ? "SUSPEND" : "RESET_PHYSICAL",
+                                      err);
+
+                       netif_device_detach(dev);
+                       priv->hw_unavailable++;
+
+                       spin_unlock_irqrestore(&priv->lock, flags);
+
+                       pcmcia_release_configuration(link->handle);
+               }
+               break;
+
+       case CS_EVENT_PM_RESUME:
+               link->state &= ~DEV_SUSPEND;
+               /* Fall through... */
+       case CS_EVENT_CARD_RESET:
+               if (link->state & DEV_CONFIG) {
+                       /* FIXME: should we double check that this is
+                        * the same card as we had before */
+                       pcmcia_request_configuration(link->handle, &link->conf);
+                       netif_device_attach(dev);
+                       priv->hw_unavailable--;
+                       schedule_work(&priv->reset_work);
+               }
+               break;
+       }
+
+       return err;
+}                              /* spectrum_cs_event */
+
+/********************************************************************/
+/* Module initialization                                           */
+/********************************************************************/
+
+/* Can't be declared "const" or the whole __initdata section will
+ * become const */
+static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
+       " (Pavel Roskin <proski@gnu.org>,"
+       " David Gibson <hermes@gibson.dropbear.id.au>, et al)";
+
+static struct pcmcia_device_id spectrum_cs_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4100 */
+       PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */
+       PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0001), /* Intel PRO/Wireless 2011B */
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids);
+
+static struct pcmcia_driver orinoco_driver = {
+       .owner          = THIS_MODULE,
+       .drv            = {
+               .name   = DRIVER_NAME,
+       },
+       .attach         = spectrum_cs_attach,
+       .event          = spectrum_cs_event,
+       .detach         = spectrum_cs_detach,
+       .id_table       = spectrum_cs_ids,
+};
+
+static int __init
+init_spectrum_cs(void)
+{
+       printk(KERN_DEBUG "%s\n", version);
+
+       return pcmcia_register_driver(&orinoco_driver);
+}
+
+static void __exit
+exit_spectrum_cs(void)
+{
+       pcmcia_unregister_driver(&orinoco_driver);
+       BUG_ON(dev_list != NULL);
+}
+
+module_init(init_spectrum_cs);
+module_exit(exit_spectrum_cs);
index 6c42b573a95a9138fb407df50eb5ef12ad797b57..4b0acae22b0d67e01d11f3b1c2f3ee991222d9f4 100644 (file)
@@ -209,7 +209,7 @@ enum {
        NoStructure = 0,        /* Really old firmware */
        StructuredMessages = 1, /* Parsable AT response msgs */
        ChecksummedMessages = 2 /* Parsable AT response msgs with checksums */
-} FirmwareLevel;
+};
 
 struct strip {
        int magic;
index f6130a53b7966fe7f9ba5d267b120c9b4f08eff5..183c4732ef65ca0eb24e99c79d1b43197a3f8930 100644 (file)
 /* Do *NOT* add other headers here, you are guaranteed to be wrong - Jean II */
 #include "wavelan_cs.p.h"              /* Private header */
 
+#ifdef WAVELAN_ROAMING
+static void wl_cell_expiry(unsigned long data);
+static void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp);
+static void wv_nwid_filter(unsigned char mode, net_local *lp);
+#endif  /*  WAVELAN_ROAMING  */
+
 /************************* MISC SUBROUTINES **************************/
 /*
  * Subroutines which won't fit in one of the following category
@@ -500,9 +506,9 @@ fee_write(u_long    base,   /* i/o port of the card */
 
 #ifdef WAVELAN_ROAMING /* Conditional compile, see wavelan_cs.h */
 
-unsigned char WAVELAN_BEACON_ADDRESS[]= {0x09,0x00,0x0e,0x20,0x03,0x00};
+static unsigned char WAVELAN_BEACON_ADDRESS[] = {0x09,0x00,0x0e,0x20,0x03,0x00};
   
-void wv_roam_init(struct net_device *dev)
+static void wv_roam_init(struct net_device *dev)
 {
   net_local  *lp= netdev_priv(dev);
 
@@ -531,7 +537,7 @@ void wv_roam_init(struct net_device *dev)
   printk(KERN_DEBUG "WaveLAN: Roaming enabled on device %s\n",dev->name);
 }
  
-void wv_roam_cleanup(struct net_device *dev)
+static void wv_roam_cleanup(struct net_device *dev)
 {
   wavepoint_history *ptr,*old_ptr;
   net_local *lp= netdev_priv(dev);
@@ -550,7 +556,7 @@ void wv_roam_cleanup(struct net_device *dev)
 }
 
 /* Enable/Disable NWID promiscuous mode on a given device */
-void wv_nwid_filter(unsigned char mode, net_local *lp)
+static void wv_nwid_filter(unsigned char mode, net_local *lp)
 {
   mm_t                  m;
   unsigned long         flags;
@@ -575,7 +581,7 @@ void wv_nwid_filter(unsigned char mode, net_local *lp)
 }
 
 /* Find a record in the WavePoint table matching a given NWID */
-wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp)
+static wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp)
 {
   wavepoint_history    *ptr=lp->wavepoint_table.head;
   
@@ -588,7 +594,7 @@ wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp)
 }
 
 /* Create a new wavepoint table entry */
-wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp)
+static wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp)
 {
   wavepoint_history *new_wavepoint;
 
@@ -624,7 +630,7 @@ wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_
 }
 
 /* Remove a wavepoint entry from WavePoint table */
-void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp)
+static void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp)
 {
   if(wavepoint==NULL)
     return;
@@ -646,7 +652,7 @@ void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp)
 }
 
 /* Timer callback function - checks WavePoint table for stale entries */ 
-void wl_cell_expiry(unsigned long data)
+static void wl_cell_expiry(unsigned long data)
 {
   net_local *lp=(net_local *)data;
   wavepoint_history *wavepoint=lp->wavepoint_table.head,*old_point;
@@ -686,7 +692,7 @@ void wl_cell_expiry(unsigned long data)
 }
 
 /* Update SNR history of a wavepoint */
-void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq) 
+static void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq)  
 {
   int i=0,num_missed=0,ptr=0;
   int average_fast=0,average_slow=0;
@@ -723,7 +729,7 @@ void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsi
 }
 
 /* Perform a handover to a new WavePoint */
-void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
+static void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
 {
   kio_addr_t           base = lp->dev->base_addr;
   mm_t                  m;
index 29cff6daf860af6c8c5b8ec1ef190a0f750762fe..fabc63ee153c7c8de715dc51f212055f35de8efa 100644 (file)
@@ -62,7 +62,7 @@
  * like DEC RoamAbout, or Digital Ocean, Epson, ...), you must modify this
  * part to accommodate your hardware...
  */
-const unsigned char    MAC_ADDRESSES[][3] =
+static const unsigned char     MAC_ADDRESSES[][3] =
 {
   { 0x08, 0x00, 0x0E },                /* AT&T Wavelan (standard) & DEC RoamAbout */
   { 0x08, 0x00, 0x6A },                /* AT&T Wavelan (alternate) */
@@ -79,14 +79,14 @@ const unsigned char MAC_ADDRESSES[][3] =
  * (as read in the offset register of the dac area).
  * Used to map channel numbers used by `wfreqsel' to frequencies
  */
-const short    channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8,
+static const short     channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8,
                                    0xD0, 0xF0, 0xF8, 0x150 };
 
 /* Frequencies of the 1.0 modem (fixed frequencies).
  * Use to map the PSA `subband' to a frequency
  * Note : all frequencies apart from the first one need to be multiplied by 10
  */
-const int      fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 };
+static const int       fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 };
 
 
 /*************************** PC INTERFACE ****************************/
index 677ff71883cb826a1e81eafdc4b8d9e9befabfad..01d882be8790c1b9c8d2b81d71fcc64248210dad 100644 (file)
@@ -647,23 +647,6 @@ struct net_local
   void __iomem *mem;
 };
 
-/**************************** PROTOTYPES ****************************/
-
-#ifdef WAVELAN_ROAMING
-/* ---------------------- ROAMING SUBROUTINES -----------------------*/
-
-wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp);
-wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local *lp);
-void wl_del_wavepoint(wavepoint_history *wavepoint, net_local *lp);
-void wl_cell_expiry(unsigned long data);
-wavepoint_history *wl_best_sigqual(int fast_search, net_local *lp);
-void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq);
-void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp);
-void wv_nwid_filter(unsigned char mode, net_local *lp);
-void wv_roam_init(struct net_device *dev);
-void wv_roam_cleanup(struct net_device *dev);
-#endif /* WAVELAN_ROAMING */
-
 /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
 static inline u_char           /* data */
        hasr_read(u_long);      /* Read the host interface : base address */
index 8636d93067854bbeb30ce0868369f0cd121e625a..7fcbe589c3f2bf4808284e1dfc595c8127fb6589 100644 (file)
@@ -2,7 +2,7 @@
 #define __WL3501_H__
 
 #include <linux/spinlock.h>
-#include "ieee802_11.h"
+#include <net/ieee80211.h>
 
 /* define for WLA 2.0 */
 #define WL3501_BLKSZ 256
@@ -548,7 +548,7 @@ struct wl3501_80211_tx_plcp_hdr {
 
 struct wl3501_80211_tx_hdr {
        struct wl3501_80211_tx_plcp_hdr pclp_hdr;
-       struct ieee802_11_hdr           mac_hdr;
+       struct ieee80211_hdr            mac_hdr;
 } __attribute__ ((packed));
 
 /*
@@ -609,6 +609,7 @@ struct wl3501_card {
        struct net_device_stats         stats;
        struct iw_statistics            wstats;
        struct iw_spy_data              spy_data;
+       struct iw_public_data           wireless_data;
        struct dev_node_t               node;
 };
 #endif
index dd902126d0183aec8f5439a834e4d8ba51b3b3cd..3f8c27f0871be01905cf61458845304e8e4e210d 100644 (file)
@@ -296,7 +296,8 @@ static int wl3501_get_flash_mac_addr(struct wl3501_card *this)
  *
  * Move 'size' bytes from PC to card. (Shouldn't be interrupted)
  */
-void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, int size)
+static void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src,
+                             int size)
 {
        /* switch to SRAM Page 0 */
        wl3501_switch_page(this, (dest & 0x8000) ? WL3501_BSS_SPAGE1 :
@@ -317,8 +318,8 @@ void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, int size)
  *
  * Move 'size' bytes from card to PC. (Shouldn't be interrupted)
  */
-void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest,
-                        int size)
+static void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest,
+                               int size)
 {
        /* switch to SRAM Page 0 */
        wl3501_switch_page(this, (src & 0x8000) ? WL3501_BSS_SPAGE1 :
@@ -1438,14 +1439,14 @@ fail:
        goto out;
 }
 
-struct net_device_stats *wl3501_get_stats(struct net_device *dev)
+static struct net_device_stats *wl3501_get_stats(struct net_device *dev)
 {
        struct wl3501_card *this = dev->priv;
 
        return &this->stats;
 }
 
-struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev)
+static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev)
 {
        struct wl3501_card *this = dev->priv;
        struct iw_statistics *wstats = &this->wstats;
@@ -1943,7 +1944,7 @@ static const iw_handler   wl3501_handler[] = {
 static const struct iw_handler_def wl3501_handler_def = {
        .num_standard   = sizeof(wl3501_handler) / sizeof(iw_handler),
        .standard       = (iw_handler *)wl3501_handler,
-       .spy_offset     = offsetof(struct wl3501_card, spy_data),
+       .get_wireless_stats = wl3501_get_wireless_stats,
 };
 
 /**
@@ -1960,6 +1961,7 @@ static dev_link_t *wl3501_attach(void)
        client_reg_t client_reg;
        dev_link_t *link;
        struct net_device *dev;
+       struct wl3501_card *this;
        int ret;
 
        /* Initialize the dev_link_t structure */
@@ -1994,7 +1996,9 @@ static dev_link_t *wl3501_attach(void)
        dev->tx_timeout         = wl3501_tx_timeout;
        dev->watchdog_timeo     = 5 * HZ;
        dev->get_stats          = wl3501_get_stats;
-       dev->get_wireless_stats = wl3501_get_wireless_stats;
+       this = dev->priv;
+       this->wireless_data.spy_data = &this->spy_data;
+       dev->wireless_data      = &this->wireless_data;
        dev->wireless_handlers  = (struct iw_handler_def *)&wl3501_handler_def;
        SET_ETHTOOL_OPS(dev, &ops);
        netif_stop_queue(dev);
index 4598c6a9212df977024db0fd43311a0f7dcf1530..97f723179f621d15ed3f9283a8a80446aa4a2cb0 100644 (file)
@@ -2739,6 +2739,7 @@ enum parport_pc_pci_cards {
        syba_2p_epp,
        syba_1p_ecp,
        titan_010l,
+       titan_1284p1,
        titan_1284p2,
        avlab_1p,
        avlab_2p,
@@ -2811,6 +2812,7 @@ static struct parport_pc_pci {
        /* syba_2p_epp AP138B */        { 2, { { 0, 0x078 }, { 0, 0x178 }, } },
        /* syba_1p_ecp W83787 */        { 1, { { 0, 0x078 }, } },
        /* titan_010l */                { 1, { { 3, -1 }, } },
+       /* titan_1284p1 */              { 1, { { 0, 1 }, } },
        /* titan_1284p2 */              { 2, { { 0, 1 }, { 2, 3 }, } },
        /* avlab_1p             */      { 1, { { 0, 1}, } },
        /* avlab_2p             */      { 2, { { 0, 1}, { 2, 3 },} },
@@ -2884,6 +2886,7 @@ static struct pci_device_id parport_pc_pci_tbl[] = {
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, syba_1p_ecp },
        { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_010L,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_010l },
+       { 0x9710, 0x9805, 0x1000, 0x0010, 0, 0, titan_1284p1 },
        { 0x9710, 0x9815, 0x1000, 0x0020, 0, 0, titan_1284p2 },
        /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/
        { 0x14db, 0x2120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1p}, /* AFAVLAB_TK9902 */
index 00498e2f12059f1cce74a37f008236ae8e6fc98e..d3dad0aac7cb88aafeb71474d4a225b9af703cce 100644 (file)
 #include <linux/pci.h>
 #include <linux/parport.h>
 #include <linux/parport_pc.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/list.h>
 #include <linux/8250_pci.h>
 
-#include <asm/serial.h>
-
 enum parport_pc_pci_cards {
        titan_110l = 0,
        titan_210l,
@@ -168,182 +163,147 @@ static struct pci_device_id parport_serial_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl);
 
-struct pci_board_no_ids {
-       int flags;
-       int num_ports;
-       int base_baud;
-       int uart_offset;
-       int reg_shift;
-       int (*init_fn)(struct pci_dev *dev, struct pci_board_no_ids *board,
-                       int enable);
-       int first_uart_offset;
-};
-
-static int __devinit siig10x_init_fn(struct pci_dev *dev, struct pci_board_no_ids *board, int enable)
-{
-       return pci_siig10x_fn(dev, enable);
-}
-
-static int __devinit siig20x_init_fn(struct pci_dev *dev, struct pci_board_no_ids *board, int enable)
-{
-       return pci_siig20x_fn(dev, enable);
-}
-
-static int __devinit netmos_serial_init(struct pci_dev *dev, struct pci_board_no_ids *board, int enable)
-{
-       board->num_ports = dev->subsystem_device & 0xf;
-       return 0;
-}
-
-static struct pci_board_no_ids pci_boards[] __devinitdata = {
-       /*
-        * PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
-        * Offset to get to next UART's registers,
-        * Register shift to use for memory-mapped I/O,
-        * Initialization function, first UART offset
-        */
-
-// Cards not tested are marked n/t
-// If you have one of these cards and it works for you, please tell me..
-
-/* titan_110l */       { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 1, 921600 },
-/* titan_210l */       { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 },
-/* netmos_9xx5_combo */        { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200, 0, 0, netmos_serial_init },
-/* netmos_9855 */      { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200, 0, 0, netmos_serial_init },
-/* avlab_1s1p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
-/* avlab_1s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
-/* avlab_1s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
-/* avlab_1s2p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
-/* avlab_1s2p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
-/* avlab_1s2p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
-/* avlab_2s1p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
-/* avlab_2s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
-/* avlab_2s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
-/* siig_1s1p_10x */    { SPCI_FL_BASE2, 1, 460800, 0, 0, siig10x_init_fn },
-/* siig_2s1p_10x */    { SPCI_FL_BASE2, 1, 921600, 0, 0, siig10x_init_fn },
-/* siig_2p1s_20x */    { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn },
-/* siig_1s1p_20x */    { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn },
-/* siig_2s1p_20x */    { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn },
+/*
+ * This table describes the serial "geometry" of these boards.  Any
+ * quirks for these can be found in drivers/serial/8250_pci.c
+ *
+ * Cards not tested are marked n/t
+ * If you have one of these cards and it works for you, please tell me..
+ */
+static struct pciserial_board pci_parport_serial_boards[] __devinitdata = {
+       [titan_110l] = {
+               .flags          = FL_BASE1 | FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [titan_210l] = {
+               .flags          = FL_BASE1 | FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [netmos_9xx5_combo] = {
+               .flags          = FL_BASE0 | FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [netmos_9855] = {
+               .flags          = FL_BASE2 | FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [avlab_1s1p] = { /* n/t */
+               .flags          = FL_BASE0 | FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [avlab_1s1p_650] = { /* nt */
+               .flags          = FL_BASE0 | FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [avlab_1s1p_850] = { /* nt */
+               .flags          = FL_BASE0 | FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [avlab_1s2p] = { /* n/t */
+               .flags          = FL_BASE0 | FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [avlab_1s2p_650] = { /* nt */
+               .flags          = FL_BASE0 | FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [avlab_1s2p_850] = { /* nt */
+               .flags          = FL_BASE0 | FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [avlab_2s1p] = { /* n/t */
+               .flags          = FL_BASE0 | FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [avlab_2s1p_650] = { /* nt */
+               .flags          = FL_BASE0 | FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [avlab_2s1p_850] = { /* nt */
+               .flags          = FL_BASE0 | FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [siig_1s1p_10x] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 1,
+               .base_baud      = 460800,
+               .uart_offset    = 8,
+       },
+       [siig_2s1p_10x] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 1,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [siig_2p1s_20x] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [siig_1s1p_20x] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [siig_2s1p_20x] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
 };
 
 struct parport_serial_private {
-       int num_ser;
-       int line[20];
-       struct pci_board_no_ids ser;
+       struct serial_private   *serial;
        int num_par;
        struct parport *port[PARPORT_MAX];
        struct parport_pc_pci par;
 };
 
-static int __devinit get_pci_port (struct pci_dev *dev,
-                                  struct pci_board_no_ids *board,
-                                  struct serial_struct *req,
-                                  int idx)
-{
-       unsigned long port;
-       int base_idx;
-       int max_port;
-       int offset;
-
-       base_idx = SPCI_FL_GET_BASE(board->flags);
-       if (board->flags & SPCI_FL_BASE_TABLE)
-               base_idx += idx;
-
-       if (board->flags & SPCI_FL_REGION_SZ_CAP) {
-               max_port = pci_resource_len(dev, base_idx) / 8;
-               if (idx >= max_port)
-                       return 1;
-       }
-                       
-       offset = board->first_uart_offset;
-
-       /* Timedia/SUNIX uses a mixture of BARs and offsets */
-       /* Ugh, this is ugly as all hell --- TYT */
-       if(dev->vendor == PCI_VENDOR_ID_TIMEDIA )  /* 0x1409 */
-               switch(idx) {
-                       case 0: base_idx=0;
-                               break;
-                       case 1: base_idx=0; offset=8;
-                               break;
-                       case 2: base_idx=1; 
-                               break;
-                       case 3: base_idx=1; offset=8;
-                               break;
-                       case 4: /* BAR 2*/
-                       case 5: /* BAR 3 */
-                       case 6: /* BAR 4*/
-                       case 7: base_idx=idx-2; /* BAR 5*/
-               }
-  
-       port =  pci_resource_start(dev, base_idx) + offset;
-
-       if ((board->flags & SPCI_FL_BASE_TABLE) == 0)
-               port += idx * (board->uart_offset ? board->uart_offset : 8);
-
-       if (pci_resource_flags (dev, base_idx) & IORESOURCE_IO) {
-               int high_bits_offset = ((sizeof(long)-sizeof(int))*8);
-               req->port = port;
-               if (high_bits_offset)
-                       req->port_high = port >> high_bits_offset;
-               else
-                       req->port_high = 0;
-               return 0;
-       }
-       req->io_type = SERIAL_IO_MEM;
-       req->iomem_base = ioremap(port, board->uart_offset);
-       req->iomem_reg_shift = board->reg_shift;
-       req->port = 0;
-       return req->iomem_base ? 0 : 1;
-}
-
 /* Register the serial port(s) of a PCI card. */
 static int __devinit serial_register (struct pci_dev *dev,
                                      const struct pci_device_id *id)
 {
-       struct pci_board_no_ids *board;
        struct parport_serial_private *priv = pci_get_drvdata (dev);
-       struct serial_struct serial_req;
-       int base_baud;
-       int k;
-       int success = 0;
-
-       priv->ser = pci_boards[id->driver_data];
-       board = &priv->ser;
-       if (board->init_fn && ((board->init_fn) (dev, board, 1) != 0))
-               return 1;
-
-       base_baud = board->base_baud;
-       if (!base_baud)
-               base_baud = BASE_BAUD;
-       memset (&serial_req, 0, sizeof (serial_req));
-
-       for (k = 0; k < board->num_ports; k++) {
-               int line;
+       struct pciserial_board *board;
+       struct serial_private *serial;
 
-               if (priv->num_ser == ARRAY_SIZE (priv->line)) {
-                       printk (KERN_WARNING
-                               "parport_serial: %s: only %u serial lines "
-                               "supported (%d reported)\n", pci_name (dev),
-                               ARRAY_SIZE (priv->line), board->num_ports);
-                       break;
-               }
+       board = &pci_parport_serial_boards[id->driver_data];
+       serial = pciserial_init_ports(dev, board);
 
-               serial_req.irq = dev->irq;
-               if (get_pci_port (dev, board, &serial_req, k))
-                       break;
-               serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE;
-               serial_req.baud_base = base_baud;
-               line = register_serial (&serial_req);
-               if (line < 0) {
-                       printk (KERN_DEBUG
-                               "parport_serial: register_serial failed\n");
-                       continue;
-               }
-               priv->line[priv->num_ser++] = line;
-               success = 1;
-       }
+       if (IS_ERR(serial))
+               return PTR_ERR(serial);
 
-       return success ? 0 : 1;
+       priv->serial = serial;
+       return 0;
 }
 
 /* Register the parallel port(s) of a PCI card. */
@@ -411,7 +371,7 @@ static int __devinit parport_serial_pci_probe (struct pci_dev *dev,
        priv = kmalloc (sizeof *priv, GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
-       priv->num_ser = priv->num_par = 0;
+       memset(priv, 0, sizeof(struct parport_serial_private));
        pci_set_drvdata (dev, priv);
 
        err = pci_enable_device (dev);
@@ -444,15 +404,12 @@ static void __devexit parport_serial_pci_remove (struct pci_dev *dev)
        struct parport_serial_private *priv = pci_get_drvdata (dev);
        int i;
 
+       pci_set_drvdata(dev, NULL);
+
        // Serial ports
-       for (i = 0; i < priv->num_ser; i++) {
-               unregister_serial (priv->line[i]);
+       if (priv->serial)
+               pciserial_remove_ports(priv->serial);
 
-               if (priv->ser.init_fn)
-                       (priv->ser.init_fn) (dev, &priv->ser, 0);
-       }
-       pci_set_drvdata (dev, NULL);
-       
        // Parallel ports
        for (i = 0; i < priv->num_par; i++)
                parport_pc_unregister_port (priv->port[i]);
@@ -461,11 +418,47 @@ static void __devexit parport_serial_pci_remove (struct pci_dev *dev)
        return;
 }
 
+static int parport_serial_pci_suspend(struct pci_dev *dev, pm_message_t state)
+{
+       struct parport_serial_private *priv = pci_get_drvdata(dev);
+
+       if (priv->serial)
+               pciserial_suspend_ports(priv->serial);
+
+       /* FIXME: What about parport? */
+
+       pci_save_state(dev);
+       pci_set_power_state(dev, pci_choose_state(dev, state));
+       return 0;
+}
+
+static int parport_serial_pci_resume(struct pci_dev *dev)
+{
+       struct parport_serial_private *priv = pci_get_drvdata(dev);
+
+       pci_set_power_state(dev, PCI_D0);
+       pci_restore_state(dev);
+
+       /*
+        * The device may have been disabled.  Re-enable it.
+        */
+       pci_enable_device(dev);
+
+       if (priv->serial)
+               pciserial_resume_ports(priv->serial);
+
+       /* FIXME: What about parport? */
+
+       return 0;
+}
+
 static struct pci_driver parport_serial_pci_driver = {
        .name           = "parport_serial",
        .id_table       = parport_serial_pci_tbl,
        .probe          = parport_serial_pci_probe,
        .remove         = __devexit_p(parport_serial_pci_remove),
+       .suspend        = parport_serial_pci_suspend,
+       .resume         = parport_serial_pci_resume,
 };
 
 
index 2b85aa39f9544dd4069f5f9ef2b2abaca4ee145b..532f73bb2224af802af190aa0a38ea66242aa188 100644 (file)
@@ -91,6 +91,7 @@ static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
 {
        struct msi_desc *entry;
        struct msg_address address;
+       unsigned int irq = vector;
 
        entry = (struct msi_desc *)msi_desc[vector];
        if (!entry || !entry->dev)
@@ -112,6 +113,7 @@ static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
                entry->msi_attrib.current_cpu = cpu_mask_to_apicid(cpu_mask);
                pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
                        address.lo_address.value);
+               set_native_irq_info(irq, cpu_mask);
                break;
        }
        case PCI_CAP_ID_MSIX:
@@ -125,22 +127,13 @@ static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
                        MSI_TARGET_CPU_SHIFT);
                entry->msi_attrib.current_cpu = cpu_mask_to_apicid(cpu_mask);
                writel(address.lo_address.value, entry->mask_base + offset);
+               set_native_irq_info(irq, cpu_mask);
                break;
        }
        default:
                break;
        }
 }
-
-#ifdef CONFIG_IRQBALANCE
-static inline void move_msi(int vector)
-{
-       if (!cpus_empty(pending_irq_balance_cpumask[vector])) {
-               set_msi_affinity(vector, pending_irq_balance_cpumask[vector]);
-               cpus_clear(pending_irq_balance_cpumask[vector]);
-       }
-}
-#endif /* CONFIG_IRQBALANCE */
 #endif /* CONFIG_SMP */
 
 static void mask_MSI_irq(unsigned int vector)
@@ -191,13 +184,13 @@ static void shutdown_msi_irq(unsigned int vector)
 
 static void end_msi_irq_wo_maskbit(unsigned int vector)
 {
-       move_msi(vector);
+       move_native_irq(vector);
        ack_APIC_irq();
 }
 
 static void end_msi_irq_w_maskbit(unsigned int vector)
 {
-       move_msi(vector);
+       move_native_irq(vector);
        unmask_MSI_irq(vector);
        ack_APIC_irq();
 }
index 390f1851c0f11b4d88206f13f720bd0b8c1b5ffa..402136a5c9e43c1af7ff107e8e20cd992657c30c 100644 (file)
@@ -19,7 +19,6 @@
 #define NR_HP_RESERVED_VECTORS         20
 
 extern int vector_irq[NR_VECTORS];
-extern cpumask_t pending_irq_balance_cpumask[NR_IRQS];
 extern void (*interrupt[NR_IRQS])(void);
 extern int pci_vector_resources(int last, int nr_released);
 
@@ -29,10 +28,6 @@ extern int pci_vector_resources(int last, int nr_released);
 #define set_msi_irq_affinity   NULL
 #endif
 
-#ifndef CONFIG_IRQBALANCE
-static inline void move_msi(int vector) {}
-#endif
-
 /*
  * MSI-X Address Register
  */
index 1b34fc56067ed8ae0ba9b32f46679e13068bb86c..c62d2f04339714cbf5380aa68dbdddf4aaba46c0 100644 (file)
@@ -333,13 +333,17 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
        if (platform_pci_choose_state) {
                ret = platform_pci_choose_state(dev, state);
                if (ret >= 0)
-                       state = ret;
+                       state.event = ret;
        }
-       switch (state) {
-       case 0: return PCI_D0;
-       case 3: return PCI_D3hot;
+
+       switch (state.event) {
+       case PM_EVENT_ON:
+               return PCI_D0;
+       case PM_EVENT_FREEZE:
+       case PM_EVENT_SUSPEND:
+               return PCI_D3hot;
        default:
-               printk("They asked me for state %d\n", state);
+               printk("They asked me for state %d\n", state.event);
                BUG();
        }
        return PCI_D0;
index bb36bb69803f44dfee260410aa2f2bf89c712c0c..140354a2aa72a7534281619f5c53dd8b707fd5f1 100644 (file)
@@ -421,6 +421,25 @@ static void __devinit quirk_via_ioapic(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C686,       quirk_via_ioapic );
 
+/*
+ * VIA 8237: Some BIOSs don't set the 'Bypass APIC De-Assert Message' Bit.
+ * This leads to doubled level interrupt rates.
+ * Set this bit to get rid of cycle wastage.
+ * Otherwise uncritical.
+ */
+static void __devinit quirk_via_vt8237_bypass_apic_deassert(struct pci_dev *dev)
+{
+       u8 misc_control2;
+#define BYPASS_APIC_DEASSERT 8
+
+       pci_read_config_byte(dev, 0x5B, &misc_control2);
+       if (!(misc_control2 & BYPASS_APIC_DEASSERT)) {
+               printk(KERN_INFO "PCI: Bypassing VIA 8237 APIC De-Assert Message\n");
+               pci_write_config_byte(dev, 0x5B, misc_control2|BYPASS_APIC_DEASSERT);
+       }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_8237,         quirk_via_vt8237_bypass_apic_deassert);
+
 /*
  * The AMD io apic can hang the box when an apic irq is masked.
  * We check all revs >= B0 (yet not in the pre production!) as the bug
index 713c78f3a65d22950adccf6a5111ecc03a328778..49bd21702314ccda11e716c1b99aa2e2d1229ade 100644 (file)
  * between the ROM and other resources, so enabling it may disable access
  * to MMIO registers or other card memory.
  */
-static void pci_enable_rom(struct pci_dev *pdev)
+static int pci_enable_rom(struct pci_dev *pdev)
 {
+       struct resource *res = pdev->resource + PCI_ROM_RESOURCE;
+       struct pci_bus_region region;
        u32 rom_addr;
 
+       if (!res->flags)
+               return -1;
+
+       pcibios_resource_to_bus(pdev, &region, res);
        pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
-       rom_addr |= PCI_ROM_ADDRESS_ENABLE;
+       rom_addr &= ~PCI_ROM_ADDRESS_MASK;
+       rom_addr |= region.start | PCI_ROM_ADDRESS_ENABLE;
        pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr);
+       return 0;
 }
 
 /**
@@ -71,19 +79,21 @@ 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 *)pci_resource_start(pdev,
+                                                            PCI_ROM_RESOURCE);
                } else {
                        /* assign the ROM an address if it doesn't have one */
-                       if (res->parent == NULL)
-                               pci_assign_resource(pdev, PCI_ROM_RESOURCE);
-
+                       if (res->parent == NULL &&
+                           pci_assign_resource(pdev,PCI_ROM_RESOURCE))
+                               return NULL;
                        start = pci_resource_start(pdev, PCI_ROM_RESOURCE);
                        *size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
                        if (*size == 0)
                                return NULL;
 
                        /* Enable ROM space decodes */
-                       pci_enable_rom(pdev);
+                       if (pci_enable_rom(pdev))
+                               return NULL;
                }
        }
 
index 6d864c502a1f71f7c1ce57ab14718bc81b11fe9c..6b0e6464eb391130d1751be13620ae38fd7d5635 100644 (file)
@@ -40,7 +40,7 @@
  * FIXME: IO should be max 256 bytes.  However, since we may
  * have a P2P bridge below a cardbus bridge, we need 4K.
  */
-#define CARDBUS_IO_SIZE                (256)
+#define CARDBUS_IO_SIZE                (4*1024)
 #define CARDBUS_MEM_SIZE       (32*1024*1024)
 
 static void __devinit
index 3e23cd461fb1e48b5ccaffbaf9efd75a81ec4f41..325c992f7d8f3804726e5024d85101919225a3cb 100644 (file)
@@ -246,7 +246,7 @@ static void __exit pxa2xx_pcmcia_exit(void)
        driver_unregister(&pxa2xx_pcmcia_driver);
 }
 
-module_init(pxa2xx_pcmcia_init);
+fs_initcall(pxa2xx_pcmcia_init);
 module_exit(pxa2xx_pcmcia_exit);
 
 MODULE_AUTHOR("Stefan Eletzhofer <stefan.eletzhofer@inquant.de> and Ian Molton <spyro@f2s.com>");
index 5309734e16875ece7ddf48974e2f1ec59049d4e4..bbe69b07ce50406a1ab6fb3b23901cdca40b90ec 100644 (file)
@@ -196,7 +196,7 @@ static void __exit mst_pcmcia_exit(void)
        platform_device_unregister(mst_pcmcia_device);
 }
 
-module_init(mst_pcmcia_init);
+fs_initcall(mst_pcmcia_init);
 module_exit(mst_pcmcia_exit);
 
 MODULE_LICENSE("GPL");
index 42efe218867a19d0fc4c8737711e37f409ea4c09..a1178a600e3c13540577df7b3eb3f268557f324b 100644 (file)
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-
 #include <asm/hardware/scoop.h>
-#include <asm/arch/corgi.h>
 #include <asm/arch/pxa-regs.h>
 
 #include "soc_common.h"
 
 #define        NO_KEEP_VS 0x0001
 
-static unsigned char keep_vs;
-static unsigned char keep_rd;
-
-static struct pcmcia_irqs irqs[] = {
-       { 0, CORGI_IRQ_GPIO_CF_CD, "PCMCIA0 CD"},
-};
-
-static void sharpsl_pcmcia_init_reset(void)
+static void sharpsl_pcmcia_init_reset(struct scoop_pcmcia_dev *scoopdev)
 {
-       reset_scoop(&corgiscoop_device.dev);
-       keep_vs = NO_KEEP_VS;
-       keep_rd = 0;
+       reset_scoop(scoopdev->dev);
+       scoopdev->keep_vs = NO_KEEP_VS;
+       scoopdev->keep_rd = 0;
 }
 
 static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
@@ -71,29 +62,35 @@ static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
        pxa_gpio_mode(GPIO57_nIOIS16_MD);
 
        /* Register interrupts */
-       ret = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-
-       if (ret) {
-               printk(KERN_ERR "Request for Compact Flash IRQ failed\n");
-               return ret;
+       if (scoop_devs[skt->nr].cd_irq >= 0) {
+               struct pcmcia_irqs cd_irq;
+
+               cd_irq.sock = skt->nr;
+               cd_irq.irq  = scoop_devs[skt->nr].cd_irq;
+               cd_irq.str  = scoop_devs[skt->nr].cd_irq_str;
+               ret = soc_pcmcia_request_irqs(skt, &cd_irq, 1);
+
+               if (ret) {
+                       printk(KERN_ERR "Request for Compact Flash IRQ failed\n");
+                       return ret;
+               }
        }
 
-       /* Enable interrupt */
-       write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, 0x00C0);
-       write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, 0x0101);
-       keep_vs = NO_KEEP_VS;
-
-       skt->irq = CORGI_IRQ_GPIO_CF_IRQ;
+       skt->irq = scoop_devs[skt->nr].irq;
 
        return 0;
 }
 
 static void sharpsl_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 {
-       soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+       if (scoop_devs[skt->nr].cd_irq >= 0) {
+               struct pcmcia_irqs cd_irq;
 
-       /* CF_BUS_OFF */
-       sharpsl_pcmcia_init_reset();
+               cd_irq.sock = skt->nr;
+               cd_irq.irq  = scoop_devs[skt->nr].cd_irq;
+               cd_irq.str  = scoop_devs[skt->nr].cd_irq_str;
+               soc_pcmcia_free_irqs(skt, &cd_irq, 1);
+       }
 }
 
 
@@ -101,31 +98,32 @@ static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                                    struct pcmcia_state *state)
 {
        unsigned short cpr, csr;
+       struct device *scoop = scoop_devs[skt->nr].dev;
 
-       cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR);
+       cpr = read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR);
 
-       write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x00FF);
-       write_scoop_reg(&corgiscoop_device.dev, SCOOP_ISR, 0x0000);
-       write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x0000);
-       csr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CSR);
+       write_scoop_reg(scoop, SCOOP_IRM, 0x00FF);
+       write_scoop_reg(scoop, SCOOP_ISR, 0x0000);
+       write_scoop_reg(scoop, SCOOP_IRM, 0x0000);
+       csr = read_scoop_reg(scoop, SCOOP_CSR);
        if (csr & 0x0004) {
                /* card eject */
-               write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000);
-               keep_vs = NO_KEEP_VS;
+               write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
+               scoop_devs[skt->nr].keep_vs = NO_KEEP_VS;
        }
-       else if (!(keep_vs & NO_KEEP_VS)) {
+       else if (!(scoop_devs[skt->nr].keep_vs & NO_KEEP_VS)) {
                /* keep vs1,vs2 */
-               write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000);
-               csr |= keep_vs;
+               write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
+               csr |= scoop_devs[skt->nr].keep_vs;
        }
        else if (cpr & 0x0003) {
                /* power on */
-               write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000);
-               keep_vs = (csr & 0x00C0);
+               write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
+               scoop_devs[skt->nr].keep_vs = (csr & 0x00C0);
        }
        else {
                /* card detect */
-               write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0002);
+               write_scoop_reg(scoop, SCOOP_CDR, 0x0002);
        }
 
        state->detect = (csr & 0x0004) ? 0 : 1;
@@ -147,6 +145,7 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
                                       const socket_state_t *state)
 {
        unsigned long flags;
+       struct device *scoop = scoop_devs[skt->nr].dev;
 
        unsigned short cpr, ncpr, ccr, nccr, mcr, nmcr, imr, nimr;
 
@@ -166,10 +165,10 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
 
        local_irq_save(flags);
 
-       nmcr = (mcr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR)) & ~0x0010;
-       ncpr = (cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR)) & ~0x0083;
-       nccr = (ccr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR)) & ~0x0080;
-       nimr = (imr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR)) & ~0x003E;
+       nmcr = (mcr = read_scoop_reg(scoop, SCOOP_MCR)) & ~0x0010;
+       ncpr = (cpr = read_scoop_reg(scoop, SCOOP_CPR)) & ~0x0083;
+       nccr = (ccr = read_scoop_reg(scoop, SCOOP_CCR)) & ~0x0080;
+       nimr = (imr = read_scoop_reg(scoop, SCOOP_IMR)) & ~0x003E;
 
        ncpr |= (state->Vcc == 33) ? 0x0001 :
                                (state->Vcc == 50) ? 0x0002 : 0;
@@ -184,22 +183,22 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
                        ((skt->status&SS_WRPROT) ? 0x0008 : 0);
 
        if (!(ncpr & 0x0003)) {
-               keep_rd = 0;
-       } else if (!keep_rd) {
+               scoop_devs[skt->nr].keep_rd = 0;
+       } else if (!scoop_devs[skt->nr].keep_rd) {
                if (nccr & 0x0080)
-                       keep_rd = 1;
+                       scoop_devs[skt->nr].keep_rd = 1;
                else
                        nccr |= 0x0080;
        }
 
        if (mcr != nmcr)
-               write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, nmcr);
+               write_scoop_reg(scoop, SCOOP_MCR, nmcr);
        if (cpr != ncpr)
-               write_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR, ncpr);
+               write_scoop_reg(scoop, SCOOP_CPR, ncpr);
        if (ccr != nccr)
-               write_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR, nccr);
+               write_scoop_reg(scoop, SCOOP_CCR, nccr);
        if (imr != nimr)
-               write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, nimr);
+               write_scoop_reg(scoop, SCOOP_IMR, nimr);
 
        local_irq_restore(flags);
 
@@ -208,10 +207,18 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
 
 static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
 {
+       sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]);
+
+       /* Enable interrupt */
+       write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_IMR, 0x00C0);
+       write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_MCR, 0x0101);
+       scoop_devs[skt->nr].keep_vs = NO_KEEP_VS;
 }
 
 static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 {
+       /* CF_BUS_OFF */
+       sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]);
 }
 
 static struct pcmcia_low_level sharpsl_pcmcia_ops = {
@@ -223,7 +230,7 @@ static struct pcmcia_low_level sharpsl_pcmcia_ops = {
        .socket_init            = sharpsl_pcmcia_socket_init,
        .socket_suspend         = sharpsl_pcmcia_socket_suspend,
        .first                          = 0,
-       .nr                                     = 1,
+       .nr                                     = 0,
 };
 
 static struct platform_device *sharpsl_pcmcia_device;
@@ -232,12 +239,15 @@ static int __init sharpsl_pcmcia_init(void)
 {
        int ret;
 
+       sharpsl_pcmcia_ops.nr=scoop_num;
        sharpsl_pcmcia_device = kmalloc(sizeof(*sharpsl_pcmcia_device), GFP_KERNEL);
        if (!sharpsl_pcmcia_device)
                return -ENOMEM;
+
        memset(sharpsl_pcmcia_device, 0, sizeof(*sharpsl_pcmcia_device));
        sharpsl_pcmcia_device->name = "pxa2xx-pcmcia";
        sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops;
+       sharpsl_pcmcia_device->dev.parent=scoop_devs[0].dev;
 
        ret = platform_device_register(sharpsl_pcmcia_device);
        if (ret)
@@ -257,7 +267,7 @@ static void __exit sharpsl_pcmcia_exit(void)
        platform_device_unregister(sharpsl_pcmcia_device);
 }
 
-module_init(sharpsl_pcmcia_init);
+fs_initcall(sharpsl_pcmcia_init);
 module_exit(sharpsl_pcmcia_exit);
 
 MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support");
index e98bb3d80e7c30f086f1c7346128cc744793cbf8..d4ed508b38be5ea07f2ca96e0064a27e3896136b 100644 (file)
@@ -126,5 +126,5 @@ MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
 MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11x0 Socket Controller");
 MODULE_LICENSE("Dual MPL/GPL");
 
-module_init(sa11x0_pcmcia_init);
+fs_initcall(sa11x0_pcmcia_init);
 module_exit(sa11x0_pcmcia_exit);
index b441f43a6a55fdd00917fa1b281de6a4509d428b..bb90a1448a53d0995b3067c07cd10015c8e3754a 100644 (file)
@@ -189,7 +189,7 @@ static void __exit sa1111_drv_pcmcia_exit(void)
        sa1111_driver_unregister(&pcmcia_driver);
 }
 
-module_init(sa1111_drv_pcmcia_init);
+fs_initcall(sa1111_drv_pcmcia_init);
 module_exit(sa1111_drv_pcmcia_exit);
 
 MODULE_DESCRIPTION("SA1111 PCMCIA card socket driver");
index db04ffb6f68c564cca51f335c81b92686229364e..59c5d968e9f67c00111dcf25f9aacc8802acbb06 100644 (file)
@@ -189,7 +189,7 @@ static int __init sa11xx_pcmcia_init(void)
 {
        return 0;
 }
-module_init(sa11xx_pcmcia_init);
+fs_initcall(sa11xx_pcmcia_init);
 
 static void __exit sa11xx_pcmcia_exit(void) {}
 
index be420bb291135a8cee511c9df3edf91e79b1ea27..edccfa5bb40087b0a0b9cbefae7bdbae5d781348 100644 (file)
 #define  TOPIC97_AVS_AUDIO_CONTROL     0x02
 #define  TOPIC97_AVS_VIDEO_CONTROL     0x01
 
+#define TOPIC_EXCA_IF_CONTROL          0x3e    /* 8 bit */
+#define TOPIC_EXCA_IFC_33V_ENA         0x01
 
 static void topic97_zoom_video(struct pcmcia_socket *sock, int onoff)
 {
@@ -137,4 +139,19 @@ static int topic97_override(struct yenta_socket *socket)
        return 0;
 }
 
+
+static int topic95_override(struct yenta_socket *socket)
+{
+       u8 fctrl;
+
+       /* enable 3.3V support for 16bit cards */
+       fctrl = exca_readb(socket, TOPIC_EXCA_IF_CONTROL);
+       exca_writeb(socket, TOPIC_EXCA_IF_CONTROL, fctrl | TOPIC_EXCA_IFC_33V_ENA);
+
+       /* tell yenta to use exca registers to power 16bit cards */
+       socket->flags |= YENTA_16BIT_POWER_EXCA | YENTA_16BIT_POWER_DF;
+
+       return 0;
+}
+
 #endif /* _LINUX_TOPIC_H */
index 62fd705203fb0d48ecc55d16b8c68b6376fa852a..0347a29f297bea94f55df5f1ecc3db6795bb648f 100644 (file)
@@ -184,22 +184,52 @@ static int yenta_get_status(struct pcmcia_socket *sock, unsigned int *value)
        return 0;
 }
 
-static int yenta_Vcc_power(u32 control)
+static void yenta_get_power(struct yenta_socket *socket, socket_state_t *state)
 {
-       switch (control & CB_SC_VCC_MASK) {
-       case CB_SC_VCC_5V: return 50;
-       case CB_SC_VCC_3V: return 33;
-       default: return 0;
-       }
-}
+       if (!(cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) &&
+           (socket->flags & YENTA_16BIT_POWER_EXCA)) {
+               u8 reg, vcc, vpp;
+
+               reg = exca_readb(socket, I365_POWER);
+               vcc = reg & I365_VCC_MASK;
+               vpp = reg & I365_VPP1_MASK;
+               state->Vcc = state->Vpp = 0;
+
+               if (socket->flags & YENTA_16BIT_POWER_DF) {
+                       if (vcc == I365_VCC_3V)
+                               state->Vcc = 33;
+                       if (vcc == I365_VCC_5V)
+                               state->Vcc = 50;
+                       if (vpp == I365_VPP1_5V)
+                               state->Vpp = state->Vcc;
+                       if (vpp == I365_VPP1_12V)
+                               state->Vpp = 120;
+               } else {
+                       if (reg & I365_VCC_5V) {
+                               state->Vcc = 50;
+                               if (vpp == I365_VPP1_5V)
+                                       state->Vpp = 50;
+                               if (vpp == I365_VPP1_12V)
+                                       state->Vpp = 120;
+                       }
+               }
+       } else {
+               u32 control;
 
-static int yenta_Vpp_power(u32 control)
-{
-       switch (control & CB_SC_VPP_MASK) {
-       case CB_SC_VPP_12V: return 120;
-       case CB_SC_VPP_5V: return 50;
-       case CB_SC_VPP_3V: return 33;
-       default: return 0;
+               control = cb_readl(socket, CB_SOCKET_CONTROL);
+
+               switch (control & CB_SC_VCC_MASK) {
+               case CB_SC_VCC_5V: state->Vcc = 50; break;
+               case CB_SC_VCC_3V: state->Vcc = 33; break;
+               default: state->Vcc = 0;
+               }
+
+               switch (control & CB_SC_VPP_MASK) {
+               case CB_SC_VPP_12V: state->Vpp = 120; break;
+               case CB_SC_VPP_5V: state->Vpp = 50; break;
+               case CB_SC_VPP_3V: state->Vpp = 33; break;
+               default: state->Vpp = 0;
+               }
        }
 }
 
@@ -211,8 +241,7 @@ static int yenta_get_socket(struct pcmcia_socket *sock, socket_state_t *state)
 
        control = cb_readl(socket, CB_SOCKET_CONTROL);
 
-       state->Vcc = yenta_Vcc_power(control);
-       state->Vpp = yenta_Vpp_power(control);
+       yenta_get_power(socket, state);
        state->io_irq = socket->io_irq;
 
        if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) {
@@ -246,19 +275,54 @@ static int yenta_get_socket(struct pcmcia_socket *sock, socket_state_t *state)
 
 static void yenta_set_power(struct yenta_socket *socket, socket_state_t *state)
 {
-       u32 reg = 0;    /* CB_SC_STPCLK? */
-       switch (state->Vcc) {
-       case 33: reg = CB_SC_VCC_3V; break;
-       case 50: reg = CB_SC_VCC_5V; break;
-       default: reg = 0; break;
-       }
-       switch (state->Vpp) {
-       case 33:  reg |= CB_SC_VPP_3V; break;
-       case 50:  reg |= CB_SC_VPP_5V; break;
-       case 120: reg |= CB_SC_VPP_12V; break;
+       /* some birdges require to use the ExCA registers to power 16bit cards */
+       if (!(cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) &&
+           (socket->flags & YENTA_16BIT_POWER_EXCA)) {
+               u8 reg, old;
+               reg = old = exca_readb(socket, I365_POWER);
+               reg &= ~(I365_VCC_MASK | I365_VPP1_MASK | I365_VPP2_MASK);
+
+               /* i82365SL-DF style */
+               if (socket->flags & YENTA_16BIT_POWER_DF) {
+                       switch (state->Vcc) {
+                       case 33: reg |= I365_VCC_3V; break;
+                       case 50: reg |= I365_VCC_5V; break;
+                       default: reg = 0; break;
+                       }
+                       switch (state->Vpp) {
+                       case 33:
+                       case 50: reg |= I365_VPP1_5V; break;
+                       case 120: reg |= I365_VPP1_12V; break;
+                       }
+               } else {
+                       /* i82365SL-B style */
+                       switch (state->Vcc) {
+                       case 50: reg |= I365_VCC_5V; break;
+                       default: reg = 0; break;
+                       }
+                       switch (state->Vpp) {
+                       case 50: reg |= I365_VPP1_5V | I365_VPP2_5V; break;
+                       case 120: reg |= I365_VPP1_12V | I365_VPP2_12V; break;
+                       }
+               }
+
+               if (reg != old)
+                       exca_writeb(socket, I365_POWER, reg);
+       } else {
+               u32 reg = 0;    /* CB_SC_STPCLK? */
+               switch (state->Vcc) {
+               case 33: reg = CB_SC_VCC_3V; break;
+               case 50: reg = CB_SC_VCC_5V; break;
+               default: reg = 0; break;
+               }
+               switch (state->Vpp) {
+               case 33:  reg |= CB_SC_VPP_3V; break;
+               case 50:  reg |= CB_SC_VPP_5V; break;
+               case 120: reg |= CB_SC_VPP_12V; break;
+               }
+               if (reg != cb_readl(socket, CB_SOCKET_CONTROL))
+                       cb_writel(socket, CB_SOCKET_CONTROL, reg);
        }
-       if (reg != cb_readl(socket, CB_SOCKET_CONTROL))
-               cb_writel(socket, CB_SOCKET_CONTROL, reg);
 }
 
 static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
@@ -751,6 +815,7 @@ enum {
        CARDBUS_TYPE_TI12XX,
        CARDBUS_TYPE_TI1250,
        CARDBUS_TYPE_RICOH,
+       CARDBUS_TYPE_TOPIC95,
        CARDBUS_TYPE_TOPIC97,
        CARDBUS_TYPE_O2MICRO,
 };
@@ -789,6 +854,9 @@ static struct cardbus_type cardbus_type[] = {
                .save_state     = ricoh_save_state,
                .restore_state  = ricoh_restore_state,
        },
+       [CARDBUS_TYPE_TOPIC95]  = {
+               .override       = topic95_override,
+       },
        [CARDBUS_TYPE_TOPIC97]  = {
                .override       = topic97_override,
        },
@@ -1196,6 +1264,7 @@ static struct pci_device_id yenta_table [] = {
        CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, RICOH),
        CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C478, RICOH),
 
+       CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95, TOPIC95),
        CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC97, TOPIC97),
        CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC100, TOPIC97),
 
index 4e637eef207652a33beaa752d1c6d6fdd2367ea3..4e75e9e258cd1419e105439ae7b995f79e2cff68 100644 (file)
  */
 #define CB_MEM_PAGE(map)       (0x40 + (map))
 
+
+/* control how 16bit cards are powered */
+#define YENTA_16BIT_POWER_EXCA 0x00000001
+#define YENTA_16BIT_POWER_DF   0x00000002
+
+
 struct yenta_socket;
 
 struct cardbus_type {
@@ -113,6 +119,8 @@ struct yenta_socket {
        struct pcmcia_socket socket;
        struct cardbus_type *type;
 
+       u32 flags;
+
        /* for PCI interrupt probing */
        unsigned int probe_status;
 
index 6e5229e92fbc7bc9fa6a443a9f78fff7f9867b32..e95ed67d4f050afddf5918d34628e4586ba70951 100644 (file)
@@ -8,13 +8,6 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-
-#ifdef CONFIG_PNP_DEBUG
-       #define DEBUG
-#else
-       #undef DEBUG
-#endif
-
 #include <linux/pnp.h>
 #include "base.h"
 
index 1d037c2a82acb0a5bfbd8002ae0274128fb01ee3..33da25f3213f4614a6dc338b9743034452dab3de 100644 (file)
 #include <linux/module.h>
 #include <linux/ctype.h>
 #include <linux/slab.h>
-
-#ifdef CONFIG_PNP_DEBUG
-       #define DEBUG
-#else
-       #undef DEBUG
-#endif
-
 #include <linux/pnp.h>
 #include "base.h"
 
index 82c5edd5b9ee016795b00116cd64f02f7f526dab..beedd86800f4e26093643ec765961a2fbd6f0e25 100644 (file)
@@ -142,17 +142,6 @@ static void isapnp_write_word(unsigned char idx, unsigned short val)
        isapnp_write_byte(idx+1, val);
 }
 
-static void *isapnp_alloc(long size)
-{
-       void *result;
-
-       result = kmalloc(size, GFP_KERNEL);
-       if (!result)
-               return NULL;
-       memset(result, 0, size);
-       return result;
-}
-
 static void isapnp_key(void)
 {
        unsigned char code = 0x6a, msb;
@@ -406,7 +395,7 @@ static void isapnp_parse_id(struct pnp_dev * dev, unsigned short vendor, unsigne
        struct pnp_id * id;
        if (!dev)
                return;
-       id = isapnp_alloc(sizeof(struct pnp_id));
+       id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
        if (!id)
                return;
        sprintf(id->id, "%c%c%c%x%x%x%x",
@@ -430,7 +419,7 @@ static struct pnp_dev * __init isapnp_parse_device(struct pnp_card *card, int si
        struct pnp_dev *dev;
 
        isapnp_peek(tmp, size);
-       dev = isapnp_alloc(sizeof(struct pnp_dev));
+       dev = kcalloc(1, sizeof(struct pnp_dev), GFP_KERNEL);
        if (!dev)
                return NULL;
        dev->number = number;
@@ -461,7 +450,7 @@ static void __init isapnp_parse_irq_resource(struct pnp_option *option,
        unsigned long bits;
 
        isapnp_peek(tmp, size);
-       irq = isapnp_alloc(sizeof(struct pnp_irq));
+       irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
        if (!irq)
                return;
        bits = (tmp[1] << 8) | tmp[0];
@@ -485,7 +474,7 @@ static void __init isapnp_parse_dma_resource(struct pnp_option *option,
        struct pnp_dma *dma;
 
        isapnp_peek(tmp, size);
-       dma = isapnp_alloc(sizeof(struct pnp_dma));
+       dma = kcalloc(1, sizeof(struct pnp_dma), GFP_KERNEL);
        if (!dma)
                return;
        dma->map = tmp[0];
@@ -505,7 +494,7 @@ static void __init isapnp_parse_port_resource(struct pnp_option *option,
        struct pnp_port *port;
 
        isapnp_peek(tmp, size);
-       port = isapnp_alloc(sizeof(struct pnp_port));
+       port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
        if (!port)
                return;
        port->min = (tmp[2] << 8) | tmp[1];
@@ -528,7 +517,7 @@ static void __init isapnp_parse_fixed_port_resource(struct pnp_option *option,
        struct pnp_port *port;
 
        isapnp_peek(tmp, size);
-       port = isapnp_alloc(sizeof(struct pnp_port));
+       port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
        if (!port)
                return;
        port->min = port->max = (tmp[1] << 8) | tmp[0];
@@ -550,7 +539,7 @@ static void __init isapnp_parse_mem_resource(struct pnp_option *option,
        struct pnp_mem *mem;
 
        isapnp_peek(tmp, size);
-       mem = isapnp_alloc(sizeof(struct pnp_mem));
+       mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
        if (!mem)
                return;
        mem->min = ((tmp[2] << 8) | tmp[1]) << 8;
@@ -573,7 +562,7 @@ static void __init isapnp_parse_mem32_resource(struct pnp_option *option,
        struct pnp_mem *mem;
 
        isapnp_peek(tmp, size);
-       mem = isapnp_alloc(sizeof(struct pnp_mem));
+       mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
        if (!mem)
                return;
        mem->min = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
@@ -595,7 +584,7 @@ static void __init isapnp_parse_fixed_mem32_resource(struct pnp_option *option,
        struct pnp_mem *mem;
 
        isapnp_peek(tmp, size);
-       mem = isapnp_alloc(sizeof(struct pnp_mem));
+       mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
        if (!mem)
                return;
        mem->min = mem->max = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
@@ -838,7 +827,7 @@ static unsigned char __init isapnp_checksum(unsigned char *data)
 
 static void isapnp_parse_card_id(struct pnp_card * card, unsigned short vendor, unsigned short device)
 {
-       struct pnp_id * id = isapnp_alloc(sizeof(struct pnp_id));
+       struct pnp_id * id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
        if (!id)
                return;
        sprintf(id->id, "%c%c%c%x%x%x%x",
@@ -874,7 +863,7 @@ static int __init isapnp_build_device_list(void)
                        header[4], header[5], header[6], header[7], header[8]);
                printk(KERN_DEBUG "checksum = 0x%x\n", checksum);
 #endif
-               if ((card = isapnp_alloc(sizeof(struct pnp_card))) == NULL)
+               if ((card = kcalloc(1, sizeof(struct pnp_card), GFP_KERNEL)) == NULL)
                        continue;
 
                card->number = csn;
index 6c510c19ad7d9097581d70ac25fd5983b13df76d..94442ffd4aeddcd100ba9d573c6a8866fdb21b1b 100644 (file)
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-
-#ifdef CONFIG_PNP_DEBUG
-       #define DEBUG
-#else
-       #undef DEBUG
-#endif
-
 #include <linux/pnp.h>
 #include "base.h"
 
index 8655dd2e5b83cea720d98b0c0e9d4e02220fb6b0..1a8915e74160bba5b0b4a94f2ecbe6322168b8e6 100644 (file)
@@ -19,6 +19,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
  
+#include <linux/config.h>
 #include <linux/acpi.h>
 #include <linux/pnp.h>
 #include <acpi/acpi_bus.h>
@@ -41,14 +42,6 @@ static inline int is_exclusive_device(struct acpi_device *dev)
        return (!acpi_match_ids(dev, excluded_id_list));
 }
 
-void *pnpacpi_kmalloc(size_t size, int f)
-{
-       void *p = kmalloc(size, f);
-       if (p)
-               memset(p, 0, size);
-       return p;
-}
-
 /*
  * Compatible Device IDs
  */
@@ -143,7 +136,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
                return 0;
 
        pnp_dbg("ACPI device : hid %s", acpi_device_hid(device));
-       dev =  pnpacpi_kmalloc(sizeof(struct pnp_dev), GFP_KERNEL);
+       dev =  kcalloc(1, sizeof(struct pnp_dev), GFP_KERNEL);
        if (!dev) {
                pnp_err("Out of memory");
                return -ENOMEM;
@@ -173,7 +166,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
        dev->number = num;
        
        /* set the initial values for the PnP device */
-       dev_id = pnpacpi_kmalloc(sizeof(struct pnp_id), GFP_KERNEL);
+       dev_id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
        if (!dev_id)
                goto err;
        pnpidacpi_to_pnpid(acpi_device_hid(device), dev_id->id);
@@ -205,8 +198,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
                for (i = 0; i < cid_list->count; i++) {
                        if (!ispnpidacpi(cid_list->id[i].value))
                                continue;
-                       dev_id = pnpacpi_kmalloc(sizeof(struct pnp_id), 
-                               GFP_KERNEL);
+                       dev_id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
                        if (!dev_id)
                                continue;
 
index 76f907e09ee62af18e53c574e72c48efecdae2d9..f28e2ed66fa34e6e1d2de9fa8ea1262ad703103d 100644 (file)
@@ -5,7 +5,6 @@
 #include <linux/acpi.h>
 #include <linux/pnp.h>
 
-void *pnpacpi_kmalloc(size_t size, int f);
 acpi_status pnpacpi_parse_allocated_resource(acpi_handle, struct pnp_resource_table*);
 acpi_status pnpacpi_parse_resource_option_data(acpi_handle, struct pnp_dev*);
 int pnpacpi_encode_resources(struct pnp_resource_table *, struct acpi_buffer *);
index 75575f6c349c65919871f32afe3dc8e83fbc3219..675b76a42403fdf8b39f01ab28b65ba2408fa519 100644 (file)
@@ -244,7 +244,7 @@ static void pnpacpi_parse_dma_option(struct pnp_option *option, struct acpi_reso
 
        if (p->number_of_channels == 0)
                return;
-       dma = pnpacpi_kmalloc(sizeof(struct pnp_dma), GFP_KERNEL);
+       dma = kcalloc(1, sizeof(struct pnp_dma), GFP_KERNEL);
        if (!dma)
                return;
 
@@ -300,7 +300,7 @@ static void pnpacpi_parse_irq_option(struct pnp_option *option,
        
        if (p->number_of_interrupts == 0)
                return;
-       irq = pnpacpi_kmalloc(sizeof(struct pnp_irq), GFP_KERNEL);
+       irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
        if (!irq)
                return;
 
@@ -321,7 +321,7 @@ static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
 
        if (p->number_of_interrupts == 0)
                return;
-       irq = pnpacpi_kmalloc(sizeof(struct pnp_irq), GFP_KERNEL);
+       irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
        if (!irq)
                return;
 
@@ -342,7 +342,7 @@ pnpacpi_parse_port_option(struct pnp_option *option,
 
        if (io->range_length == 0)
                return;
-       port = pnpacpi_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
+       port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
        if (!port)
                return;
        port->min = io->min_base_address;
@@ -363,7 +363,7 @@ pnpacpi_parse_fixed_port_option(struct pnp_option *option,
 
        if (io->range_length == 0)
                return;
-       port = pnpacpi_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
+       port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
        if (!port)
                return;
        port->min = port->max = io->base_address;
@@ -382,7 +382,7 @@ pnpacpi_parse_mem24_option(struct pnp_option *option,
 
        if (p->range_length == 0)
                return;
-       mem = pnpacpi_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+       mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
        if (!mem)
                return;
        mem->min = p->min_base_address;
@@ -405,7 +405,7 @@ pnpacpi_parse_mem32_option(struct pnp_option *option,
 
        if (p->range_length == 0)
                return;
-       mem = pnpacpi_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+       mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
        if (!mem)
                return;
        mem->min = p->min_base_address;
@@ -428,7 +428,7 @@ pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
 
        if (p->range_length == 0)
                return;
-       mem = pnpacpi_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+       mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
        if (!mem)
                return;
        mem->min = mem->max = p->range_base_address;
@@ -612,7 +612,7 @@ int pnpacpi_build_resource_template(acpi_handle handle,
        if (!res_cnt)
                return -EINVAL;
        buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1;
-       buffer->pointer = pnpacpi_kmalloc(buffer->length - 1, GFP_KERNEL);
+       buffer->pointer = kcalloc(1, buffer->length - 1, GFP_KERNEL);
        if (!buffer->pointer)
                return -ENOMEM;
        pnp_dbg("Res cnt %d", res_cnt);
index 778a324028f4135bdb90bb4e655bac513c17e43d..f49674f07949bcf505632d3d4c842a7c4b542e50 100644 (file)
@@ -86,16 +86,6 @@ int pnp_bios_present(void)
 
 struct pnp_dev_node_info node_info;
 
-void *pnpbios_kmalloc(size_t size, int f)
-{
-       void *p = kmalloc( size, f );
-       if ( p == NULL )
-               printk(KERN_ERR "PnPBIOS: kmalloc() failed\n");
-       else
-               memset(p, 0, size);
-       return p;
-}
-
 /*
  *
  * DOCKING FUNCTIONS
@@ -121,10 +111,10 @@ static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
        if (!current->fs->root) {
                return -EAGAIN;
        }
-       if (!(envp = (char **) pnpbios_kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
+       if (!(envp = (char **) kcalloc (20, sizeof (char *), GFP_KERNEL))) {
                return -ENOMEM;
        }
-       if (!(buf = pnpbios_kmalloc (256, GFP_KERNEL))) {
+       if (!(buf = kcalloc (1, 256, GFP_KERNEL))) {
                kfree (envp);
                return -ENOMEM;
        }
@@ -231,7 +221,7 @@ static int pnpbios_get_resources(struct pnp_dev * dev, struct pnp_resource_table
        if(!pnpbios_is_dynamic(dev))
                return -EPERM;
 
-       node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+       node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
        if (!node)
                return -1;
        if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
@@ -254,7 +244,7 @@ static int pnpbios_set_resources(struct pnp_dev * dev, struct pnp_resource_table
        if (!pnpbios_is_dynamic(dev))
                return -EPERM;
 
-       node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+       node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
        if (!node)
                return -1;
        if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
@@ -305,7 +295,7 @@ static int pnpbios_disable_resources(struct pnp_dev *dev)
        if(dev->flags & PNPBIOS_NO_DISABLE || !pnpbios_is_dynamic(dev))
                return -EPERM;
 
-       node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+       node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
        if (!node)
                return -ENOMEM;
 
@@ -347,7 +337,7 @@ static int insert_device(struct pnp_dev *dev, struct pnp_bios_node * node)
        }
 
        /* set the initial values for the PnP device */
-       dev_id = pnpbios_kmalloc(sizeof(struct pnp_id), GFP_KERNEL);
+       dev_id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
        if (!dev_id)
                return -1;
        pnpid32_to_pnpid(node->eisa_id,id);
@@ -385,7 +375,7 @@ static void __init build_devlist(void)
        struct pnp_bios_node *node;
        struct pnp_dev *dev;
 
-       node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+       node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
        if (!node)
                return;
 
@@ -402,7 +392,7 @@ static void __init build_devlist(void)
                                break;
                }
                nodes_got++;
-               dev =  pnpbios_kmalloc(sizeof (struct pnp_dev), GFP_KERNEL);
+               dev =  kcalloc(1, sizeof (struct pnp_dev), GFP_KERNEL);
                if (!dev)
                        break;
                if(insert_device(dev,node)<0)
index 01896e705ed45ad91348e34b60a27d7c6ad2fd40..d8cb2fd1f127a98a10673e937889802cf7d6b79b 100644 (file)
@@ -26,7 +26,6 @@ union pnp_bios_install_struct {
 
 extern int pnp_bios_present(void);
 extern int  pnpbios_dont_use_current_config;
-extern void *pnpbios_kmalloc(size_t size, int f);
 
 extern int pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node * node);
 extern int pnpbios_read_resources_from_node(struct pnp_resource_table *res, struct pnp_bios_node * node);
index 6bb8e1973fd497a8807992336ebd089c8ac7b3f0..5a3dfc97f5e90ef655aac0ce5a7c6576a6274a70 100644 (file)
@@ -87,7 +87,7 @@ static int proc_read_escd(char *buf, char **start, off_t pos,
                return -EFBIG;
        }
 
-       tmpbuf = pnpbios_kmalloc(escd.escd_size, GFP_KERNEL);
+       tmpbuf = kcalloc(1, escd.escd_size, GFP_KERNEL);
        if (!tmpbuf) return -ENOMEM;
 
        if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base)) {
@@ -133,7 +133,7 @@ static int proc_read_devices(char *buf, char **start, off_t pos,
        if (pos >= 0xff)
                return 0;
 
-       node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+       node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
        if (!node) return -ENOMEM;
 
        for (nodenum=pos; nodenum<0xff; ) {
@@ -168,7 +168,7 @@ static int proc_read_node(char *buf, char **start, off_t pos,
        u8 nodenum = (long)data;
        int len;
 
-       node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+       node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
        if (!node) return -ENOMEM;
        if (pnp_bios_get_dev_node(&nodenum, boot, node)) {
                kfree(node);
@@ -188,7 +188,7 @@ static int proc_write_node(struct file *file, const char __user *buf,
        u8 nodenum = (long)data;
        int ret = count;
 
-       node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+       node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
        if (!node)
                return -ENOMEM;
        if (pnp_bios_get_dev_node(&nodenum, boot, node)) {
index e305bb132c24e30eb418b656e6a1e4118b68928d..b0ca65b68645624e1ddd78ac1f4de6d71c4156e4 100644 (file)
@@ -247,7 +247,7 @@ static void
 pnpbios_parse_mem_option(unsigned char *p, int size, struct pnp_option *option)
 {
        struct pnp_mem * mem;
-       mem = pnpbios_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+       mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
        if (!mem)
                return;
        mem->min = ((p[5] << 8) | p[4]) << 8;
@@ -263,7 +263,7 @@ static void
 pnpbios_parse_mem32_option(unsigned char *p, int size, struct pnp_option *option)
 {
        struct pnp_mem * mem;
-       mem = pnpbios_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+       mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
        if (!mem)
                return;
        mem->min = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
@@ -279,7 +279,7 @@ static void
 pnpbios_parse_fixed_mem32_option(unsigned char *p, int size, struct pnp_option *option)
 {
        struct pnp_mem * mem;
-       mem = pnpbios_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+       mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
        if (!mem)
                return;
        mem->min = mem->max = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
@@ -296,7 +296,7 @@ pnpbios_parse_irq_option(unsigned char *p, int size, struct pnp_option *option)
        struct pnp_irq * irq;
        unsigned long bits;
 
-       irq = pnpbios_kmalloc(sizeof(struct pnp_irq), GFP_KERNEL);
+       irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
        if (!irq)
                return;
        bits = (p[2] << 8) | p[1];
@@ -313,7 +313,7 @@ static void
 pnpbios_parse_dma_option(unsigned char *p, int size, struct pnp_option *option)
 {
        struct pnp_dma * dma;
-       dma = pnpbios_kmalloc(sizeof(struct pnp_dma), GFP_KERNEL);
+       dma = kcalloc(1, sizeof(struct pnp_dma), GFP_KERNEL);
        if (!dma)
                return;
        dma->map = p[1];
@@ -326,7 +326,7 @@ static void
 pnpbios_parse_port_option(unsigned char *p, int size, struct pnp_option *option)
 {
        struct pnp_port * port;
-       port = pnpbios_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
+       port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
        if (!port)
                return;
        port->min = (p[3] << 8) | p[2];
@@ -342,7 +342,7 @@ static void
 pnpbios_parse_fixed_port_option(unsigned char *p, int size, struct pnp_option *option)
 {
        struct pnp_port * port;
-       port = pnpbios_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
+       port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
        if (!port)
                return;
        port->min = port->max = (p[2] << 8) | p[1];
@@ -530,7 +530,7 @@ pnpbios_parse_compatible_ids(unsigned char *p, unsigned char *end, struct pnp_de
                case SMALL_TAG_COMPATDEVID: /* compatible ID */
                        if (len != 4)
                                goto len_err;
-                       dev_id =  pnpbios_kmalloc(sizeof (struct pnp_id), GFP_KERNEL);
+                       dev_id =  kcalloc(1, sizeof (struct pnp_id), GFP_KERNEL);
                        if (!dev_id)
                                return NULL;
                        memset(dev_id, 0, sizeof(struct pnp_id));
index 596a02d7e03d12308a6c6992f155eb73548cf101..8936b0cb2ec3718bc60937efcace3bc22c27b2fb 100644 (file)
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/slab.h>
-
-#ifdef CONFIG_PNP_DEBUG
-       #define DEBUG
-#else
-       #undef DEBUG
-#endif
-
 #include <linux/pnp.h>
 #include "base.h"
 
index b952aec491899b7698dd0b808befd2945a0a8ed1..61fe998944bd1ce0d0f6816687f964861e8d8934 100644 (file)
@@ -8,13 +8,6 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/ctype.h>
-
-#ifdef CONFIG_PNP_DEBUG
-       #define DEBUG
-#else
-       #undef DEBUG
-#endif
-
 #include <linux/pnp.h>
 #include "base.h"
 
index dc1c89dbdb8f57a470cd1bb811ac889654087231..6e7d7b06421d233f1521568656bd193a6b9f7bee 100644 (file)
@@ -49,7 +49,7 @@ config DASD_FBA
 
 config DASD_DIAG
        tristate "Support for DIAG access to Disks"
-       depends on DASD && ARCH_S390X = 'n'
+       depends on DASD && ( ARCH_S390X = 'n' || EXPERIMENTAL)
        help
          Select this option if you want to use Diagnose250 command to access
          Disks under VM.  If you are not running under VM or unsure what it is,
index d5f53980749b5cabf8f9ba4dc4d8120e0d0d79b9..8fc891a9d47f569b823c02ed7dc85855f464fd0c 100644 (file)
@@ -7,7 +7,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
  *
- * $Revision: 1.165 $
+ * $Revision: 1.167 $
  */
 
 #include <linux/config.h>
@@ -1131,17 +1131,13 @@ __dasd_process_blk_queue(struct dasd_device * device)
        request_queue_t *queue;
        struct request *req;
        struct dasd_ccw_req *cqr;
-       int nr_queued, feature_ro;
+       int nr_queued;
 
        queue = device->request_queue;
        /* No queue ? Then there is nothing to do. */
        if (queue == NULL)
                return;
 
-       feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
-       if (feature_ro < 0)     /* no devmap */
-               return;
-
        /*
         * We requeue request from the block device queue to the ccw
         * queue only in two states. In state DASD_STATE_READY the
@@ -1162,7 +1158,8 @@ __dasd_process_blk_queue(struct dasd_device * device)
                nr_queued < DASD_CHANQ_MAX_SIZE) {
                req = elv_next_request(queue);
 
-               if (feature_ro && rq_data_dir(req) == WRITE) {
+               if (device->features & DASD_FEATURE_READONLY &&
+                   rq_data_dir(req) == WRITE) {
                        DBF_DEV_EVENT(DBF_ERR, device,
                                      "Rejecting write request %p",
                                      req);
@@ -1814,17 +1811,13 @@ dasd_generic_set_online (struct ccw_device *cdev,
 
 {
        struct dasd_device *device;
-       int feature_diag, rc;
+       int rc;
 
        device = dasd_create_device(cdev);
        if (IS_ERR(device))
                return PTR_ERR(device);
 
-       feature_diag = dasd_get_feature(cdev, DASD_FEATURE_USEDIAG);
-       if (feature_diag < 0)
-               return feature_diag;
-
-       if (feature_diag) {
+       if (device->features & DASD_FEATURE_USEDIAG) {
                if (!dasd_diag_discipline_pointer) {
                        printk (KERN_WARNING
                                "dasd_generic couldn't online device %s "
index d948566bb24a32e211797259d92af82fed6f50b1..bda896d9d788f3b4ab83a694324c641a8b02223d 100644 (file)
@@ -11,7 +11,7 @@
  * functions may not be called from interrupt context. In particular
  * dasd_get_device is a no-no from interrupt context.
  *
- * $Revision: 1.40 $
+ * $Revision: 1.43 $
  */
 
 #include <linux/config.h>
@@ -513,6 +513,7 @@ dasd_create_device(struct ccw_device *cdev)
        if (!devmap->device) {
                devmap->device = device;
                device->devindex = devmap->devindex;
+               device->features = devmap->features;
                get_device(&cdev->dev);
                device->cdev = cdev;
                rc = 0;
@@ -643,6 +644,8 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr, const char *buf
                devmap->features |= DASD_FEATURE_READONLY;
        else
                devmap->features &= ~DASD_FEATURE_READONLY;
+       if (devmap->device)
+               devmap->device->features = devmap->features;
        if (devmap->device && devmap->device->gdp)
                set_disk_ro(devmap->device->gdp, ro_flag);
        spin_unlock(&dasd_devmap_lock);
@@ -758,7 +761,8 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag)
                devmap->features |= feature;
        else
                devmap->features &= ~feature;
-
+       if (devmap->device)
+               devmap->device->features = devmap->features;
        spin_unlock(&dasd_devmap_lock);
        return 0;
 }
index 127699830fa18a46ee98836af72ebdbf16d89f1e..7478423b53bb2e6b1ae09f4296466c0998344e08 100644 (file)
@@ -6,17 +6,18 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
- * $Revision: 1.42 $
+ * $Revision: 1.49 $
  */
 
 #include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/hdreg.h>       /* HDIO_GETGEO                      */
+#include <linux/hdreg.h>
 #include <linux/bio.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/jiffies.h>
 
 #include <asm/dasd.h>
 #include <asm/debug.h>
 #include "dasd_int.h"
 #include "dasd_diag.h"
 
-#ifdef PRINTK_HEADER
-#undef PRINTK_HEADER
-#endif                         /* PRINTK_HEADER */
 #define PRINTK_HEADER "dasd(diag):"
 
 MODULE_LICENSE("GPL");
 
+/* The maximum number of blocks per request (max_blocks) is dependent on the
+ * amount of storage that is available in the static I/O buffer for each
+ * device. Currently each device gets 2 pages. We want to fit two requests
+ * into the available memory so that we can immediately start the next if one
+ * finishes. */
+#define DIAG_MAX_BLOCKS        (((2 * PAGE_SIZE - sizeof(struct dasd_ccw_req) - \
+                          sizeof(struct dasd_diag_req)) / \
+                          sizeof(struct dasd_diag_bio)) / 2)
+#define DIAG_MAX_RETRIES       32
+#define DIAG_TIMEOUT           50 * HZ
+
 struct dasd_discipline dasd_diag_discipline;
 
 struct dasd_diag_private {
        struct dasd_diag_characteristics rdc_data;
        struct dasd_diag_rw_io iob;
        struct dasd_diag_init_io iib;
-       unsigned int pt_block;
+       blocknum_t pt_block;
 };
 
 struct dasd_diag_req {
-       int block_count;
+       unsigned int block_count;
        struct dasd_diag_bio bio[0];
 };
 
+static const u8 DASD_DIAG_CMS1[] = { 0xc3, 0xd4, 0xe2, 0xf1 };/* EBCDIC CMS1 */
+
+/* Perform DIAG250 call with block I/O parameter list iob (input and output)
+ * and function code cmd.
+ * In case of an exception return 3. Otherwise return result of bitwise OR of
+ * resulting condition code and DIAG return code. */
 static __inline__ int
 dia250(void *iob, int cmd)
 {
+       typedef struct {
+               char _[max(sizeof (struct dasd_diag_init_io),
+                          sizeof (struct dasd_diag_rw_io))];
+       } addr_type;
        int rc;
 
-       __asm__ __volatile__("    lhi   %0,3\n"
-                            "    lr    0,%2\n"
-                            "    diag  0,%1,0x250\n"
-                            "0:  ipm   %0\n"
-                            "    srl   %0,28\n"
-                            "    or    %0,1\n"
-                            "1:\n"
-#ifndef CONFIG_ARCH_S390X
-                            ".section __ex_table,\"a\"\n"
-                            "    .align 4\n"
-                            "    .long 0b,1b\n"
-                            ".previous\n"
+       __asm__ __volatile__(
+#ifdef CONFIG_ARCH_S390X
+               "       lghi    %0,3\n"
+               "       lgr     0,%3\n"
+               "       diag    0,%2,0x250\n"
+               "0:     ipm     %0\n"
+               "       srl     %0,28\n"
+               "       or      %0,1\n"
+               "1:\n"
+               ".section __ex_table,\"a\"\n"
+               "       .align 8\n"
+               "       .quad  0b,1b\n"
+               ".previous\n"
 #else
-                            ".section __ex_table,\"a\"\n"
-                            "    .align 8\n"
-                            "    .quad  0b,1b\n"
-                            ".previous\n"
+               "       lhi     %0,3\n"
+               "       lr      0,%3\n"
+               "       diag    0,%2,0x250\n"
+               "0:     ipm     %0\n"
+               "       srl     %0,28\n"
+               "       or      %0,1\n"
+               "1:\n"
+               ".section __ex_table,\"a\"\n"
+               "       .align 4\n"
+               "       .long 0b,1b\n"
+               ".previous\n"
 #endif
-                            : "=&d" (rc)
-                            : "d" (cmd), "d" ((void *) __pa(iob))
-                            : "0", "1", "cc");
+               : "=&d" (rc), "=m" (*(addr_type *) iob)
+               : "d" (cmd), "d" (iob), "m" (*(addr_type *) iob)
+               : "0", "1", "cc");
        return rc;
 }
 
+/* Initialize block I/O to DIAG device using the specified blocksize and
+ * block offset. On success, return zero and set end_block to contain the
+ * number of blocks on the device minus the specified offset. Return non-zero
+ * otherwise. */
 static __inline__ int
-mdsk_init_io(struct dasd_device * device, int blocksize, int offset, int size)
+mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
+            blocknum_t offset, blocknum_t *end_block)
 {
        struct dasd_diag_private *private;
        struct dasd_diag_init_io *iib;
@@ -92,14 +124,18 @@ mdsk_init_io(struct dasd_device * device, int blocksize, int offset, int size)
        iib->dev_nr = _ccw_device_get_device_number(device->cdev);
        iib->block_size = blocksize;
        iib->offset = offset;
-       iib->start_block = 0;
-       iib->end_block = size;
+       iib->flaga = DASD_DIAG_FLAGA_DEFAULT;
 
        rc = dia250(iib, INIT_BIO);
 
-       return rc & 3;
+       if ((rc & 3) == 0 && end_block)
+               *end_block = iib->end_block;
+
+       return rc;
 }
 
+/* Remove block I/O environment for device. Return zero on success, non-zero
+ * otherwise. */
 static __inline__ int
 mdsk_term_io(struct dasd_device * device)
 {
@@ -112,9 +148,25 @@ mdsk_term_io(struct dasd_device * device)
        memset(iib, 0, sizeof (struct dasd_diag_init_io));
        iib->dev_nr = _ccw_device_get_device_number(device->cdev);
        rc = dia250(iib, TERM_BIO);
-       return rc & 3;
+       return rc;
+}
+
+/* Error recovery for failed DIAG requests - try to reestablish the DIAG
+ * environment. */
+static void
+dasd_diag_erp(struct dasd_device *device)
+{
+       int rc;
+
+       mdsk_term_io(device);
+       rc = mdsk_init_io(device, device->bp_block, 0, NULL);
+       if (rc)
+               DEV_MESSAGE(KERN_WARNING, device, "DIAG ERP unsuccessful, "
+                           "rc=%d", rc);
 }
 
+/* Start a given request at the device. Return zero on success, non-zero
+ * otherwise. */
 static int
 dasd_start_diag(struct dasd_ccw_req * cqr)
 {
@@ -124,32 +176,66 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
        int rc;
 
        device = cqr->device;
+       if (cqr->retries < 0) {
+               DEV_MESSAGE(KERN_WARNING, device, "DIAG start_IO: request %p "
+                           "- no retry left)", cqr);
+               cqr->status = DASD_CQR_FAILED;
+               return -EIO;
+       }
        private = (struct dasd_diag_private *) device->private;
        dreq = (struct dasd_diag_req *) cqr->data;
 
        private->iob.dev_nr = _ccw_device_get_device_number(device->cdev);
        private->iob.key = 0;
-       private->iob.flags = 2; /* do asynchronous io */
+       private->iob.flags = DASD_DIAG_RWFLAG_ASYNC;
        private->iob.block_count = dreq->block_count;
-       private->iob.interrupt_params = (u32)(addr_t) cqr;
+       private->iob.interrupt_params = (addr_t) cqr;
        private->iob.bio_list = __pa(dreq->bio);
+       private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;
 
        cqr->startclk = get_clock();
+       cqr->starttime = jiffies;
+       cqr->retries--;
 
        rc = dia250(&private->iob, RW_BIO);
-       if (rc > 8) {
-               DEV_MESSAGE(KERN_WARNING, device, "dia250 returned CC %d", rc);
-               cqr->status = DASD_CQR_ERROR;
-       } else if (rc == 0) {
+       switch (rc) {
+       case 0: /* Synchronous I/O finished successfully */
+               cqr->stopclk = get_clock();
                cqr->status = DASD_CQR_DONE;
-               dasd_schedule_bh(device);
-       } else {
+               /* Indicate to calling function that only a dasd_schedule_bh()
+                  and no timer is needed */
+                rc = -EACCES;
+               break;
+       case 8: /* Asynchronous I/O was started */
                cqr->status = DASD_CQR_IN_IO;
                rc = 0;
+               break;
+       default: /* Error condition */
+               cqr->status = DASD_CQR_QUEUED;
+               DEV_MESSAGE(KERN_WARNING, device, "dia250 returned rc=%d", rc);
+               dasd_diag_erp(device);
+               rc = -EIO;
+               break;
        }
        return rc;
 }
 
+/* Terminate given request at the device. */
+static int
+dasd_diag_term_IO(struct dasd_ccw_req * cqr)
+{
+       struct dasd_device *device;
+
+       device = cqr->device;
+       mdsk_term_io(device);
+       mdsk_init_io(device, device->bp_block, 0, NULL);
+       cqr->status = DASD_CQR_CLEAR;
+       cqr->stopclk = get_clock();
+       dasd_schedule_bh(device);
+       return 0;
+}
+
+/* Handle external interruption. */
 static void
 dasd_ext_handler(struct pt_regs *regs, __u16 code)
 {
@@ -157,25 +243,27 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
        struct dasd_device *device;
        unsigned long long expires;
        unsigned long flags;
-       char status;
-       int ip;
-
-       /*
-        * Get the external interruption subcode. VM stores
-        * this in the 'cpu address' field associated with
-        * the external interrupt. For diag 250 the subcode
-        * needs to be 3.
-        */
-       if ((S390_lowcore.cpu_addr & 0xff00) != 0x0300)
-               return;
-       status = *((char *) &S390_lowcore.ext_params + 5);
-       ip = S390_lowcore.ext_params;
+       u8 int_code, status;
+       addr_t ip;
+       int rc;
 
+       int_code = *((u8 *) DASD_DIAG_LC_INT_CODE);
+       status = *((u8 *) DASD_DIAG_LC_INT_STATUS);
+       switch (int_code) {
+       case DASD_DIAG_CODE_31BIT:
+               ip = (addr_t) *((u32 *) DASD_DIAG_LC_INT_PARM_31BIT);
+               break;
+       case DASD_DIAG_CODE_64BIT:
+               ip = (addr_t) *((u64 *) DASD_DIAG_LC_INT_PARM_64BIT);
+               break;
+       default:
+               return;
+       }
        if (!ip) {              /* no intparm: unsolicited interrupt */
                MESSAGE(KERN_DEBUG, "%s", "caught unsolicited interrupt");
                return;
        }
-       cqr = (struct dasd_ccw_req *)(addr_t) ip;
+       cqr = (struct dasd_ccw_req *) ip;
        device = (struct dasd_device *) cqr->device;
        if (strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
                DEV_MESSAGE(KERN_WARNING, device,
@@ -188,6 +276,15 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
        /* get irq lock to modify request queue */
        spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
 
+       /* Check for a pending clear operation */
+       if (cqr->status == DASD_CQR_CLEAR) {
+               cqr->status = DASD_CQR_QUEUED;
+               dasd_clear_timer(device);
+               dasd_schedule_bh(device);
+               spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+               return;
+       }
+
        cqr->stopclk = get_clock();
 
        expires = 0;
@@ -198,16 +295,22 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
                        next = list_entry(device->ccw_queue.next,
                                          struct dasd_ccw_req, list);
                        if (next->status == DASD_CQR_QUEUED) {
-                               if (dasd_start_diag(next) == 0)
+                               rc = dasd_start_diag(next);
+                               if (rc == 0)
                                        expires = next->expires;
-                               else
+                               else if (rc != -EACCES)
                                        DEV_MESSAGE(KERN_WARNING, device, "%s",
                                                    "Interrupt fastpath "
                                                    "failed!");
                        }
                }
-       } else 
-               cqr->status = DASD_CQR_FAILED;
+       } else {
+               cqr->status = DASD_CQR_QUEUED;
+               DEV_MESSAGE(KERN_WARNING, device, "interrupt status for "
+                           "request %p was %d (%d retries left)", cqr, status,
+                           cqr->retries);
+               dasd_diag_erp(device);
+       }
 
        if (expires != 0)
                dasd_set_timer(device, expires);
@@ -218,14 +321,17 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
        spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 }
 
+/* Check whether device can be controlled by DIAG discipline. Return zero on
+ * success, non-zero otherwise. */
 static int
 dasd_diag_check_device(struct dasd_device *device)
 {
        struct dasd_diag_private *private;
        struct dasd_diag_characteristics *rdc_data;
        struct dasd_diag_bio bio;
-       long *label;
-       int sb, bsize;
+       struct dasd_diag_cms_label *label;
+       blocknum_t end_block;
+       unsigned int sb, bsize;
        int rc;
 
        private = (struct dasd_diag_private *) device->private;
@@ -244,8 +350,11 @@ dasd_diag_check_device(struct dasd_device *device)
        rdc_data->rdc_len = sizeof (struct dasd_diag_characteristics);
 
        rc = diag210((struct diag210 *) rdc_data);
-       if (rc)
+       if (rc) {
+               DEV_MESSAGE(KERN_WARNING, device, "failed to retrieve device "
+                           "information (rc=%d)", rc);
                return -ENOTSUPP;
+       }
 
        /* Figure out position of label block */
        switch (private->rdc_data.vdev_class) {
@@ -256,6 +365,8 @@ dasd_diag_check_device(struct dasd_device *device)
                private->pt_block = 2;
                break;
        default:
+               DEV_MESSAGE(KERN_WARNING, device, "unsupported device class "
+                           "(class=%d)", private->rdc_data.vdev_class);
                return -ENOTSUPP;
        }
 
@@ -269,15 +380,17 @@ dasd_diag_check_device(struct dasd_device *device)
        mdsk_term_io(device);
 
        /* figure out blocksize of device */
-       label = (long *) get_zeroed_page(GFP_KERNEL);
+       label = (struct dasd_diag_cms_label *) get_zeroed_page(GFP_KERNEL);
        if (label == NULL)  {
                DEV_MESSAGE(KERN_WARNING, device, "%s",
                            "No memory to allocate initialization request");
                return -ENOMEM;
        }
+       rc = 0;
+       end_block = 0;
        /* try all sizes - needed for ECKD devices */
        for (bsize = 512; bsize <= PAGE_SIZE; bsize <<= 1) {
-               mdsk_init_io(device, bsize, 0, 64);
+               mdsk_init_io(device, bsize, 0, &end_block);
                memset(&bio, 0, sizeof (struct dasd_diag_bio));
                bio.type = MDSK_READ_REQ;
                bio.block_number = private->pt_block + 1;
@@ -289,37 +402,45 @@ dasd_diag_check_device(struct dasd_device *device)
                private->iob.block_count = 1;
                private->iob.interrupt_params = 0;
                private->iob.bio_list = __pa(&bio);
-               if (dia250(&private->iob, RW_BIO) == 0)
+               private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;
+               rc = dia250(&private->iob, RW_BIO);
+               if (rc == 0 || rc == 3)
                        break;
                mdsk_term_io(device);
        }
-       if (bsize <= PAGE_SIZE && label[0] == 0xc3d4e2f1) {
-               /* get formatted blocksize from label block */
-               bsize = (int) label[3];
-               device->blocks = label[7];
+       if (rc == 3) {
+               DEV_MESSAGE(KERN_WARNING, device, "%s", "DIAG call failed");
+               rc = -EOPNOTSUPP;
+       } else if (rc != 0) {
+               DEV_MESSAGE(KERN_WARNING, device, "device access failed "
+                           "(rc=%d)", rc);
+               rc = -EIO;
+       } else {
+               if (memcmp(label->label_id, DASD_DIAG_CMS1,
+                         sizeof(DASD_DIAG_CMS1)) == 0) {
+                       /* get formatted blocksize from label block */
+                       bsize = (unsigned int) label->block_size;
+                       device->blocks = (unsigned long) label->block_count;
+               } else
+                       device->blocks = end_block;
                device->bp_block = bsize;
                device->s2b_shift = 0;  /* bits to shift 512 to get a block */
                for (sb = 512; sb < bsize; sb = sb << 1)
                        device->s2b_shift++;
                
                DEV_MESSAGE(KERN_INFO, device,
-                           "capacity (%dkB blks): %ldkB",
-                           (device->bp_block >> 10),
-                           (device->blocks << device->s2b_shift) >> 1);
+                           "(%ld B/blk): %ldkB",
+                           (unsigned long) device->bp_block,
+                           (unsigned long) (device->blocks <<
+                               device->s2b_shift) >> 1);
                rc = 0;
-       } else {
-               if (bsize > PAGE_SIZE)
-                       DEV_MESSAGE(KERN_WARNING, device, "%s",
-                                   "DIAG access failed");
-               else
-                       DEV_MESSAGE(KERN_WARNING, device, "%s",
-                                   "volume is not CMS formatted");
-               rc = -EMEDIUMTYPE;
        }
        free_page((long) label);
        return rc;
 }
 
+/* Fill in virtual disk geometry for device. Return zero on success, non-zero
+ * otherwise. */
 static int
 dasd_diag_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
 {
@@ -349,6 +470,8 @@ dasd_diag_erp_postaction(struct dasd_ccw_req * cqr)
        return dasd_default_erp_postaction;
 }
 
+/* Create DASD request from block device request. Return pointer to new
+ * request on success, ERR_PTR otherwise. */
 static struct dasd_ccw_req *
 dasd_diag_build_cp(struct dasd_device * device, struct request *req)
 {
@@ -358,9 +481,9 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
        struct bio *bio;
        struct bio_vec *bv;
        char *dst;
-       int count, datasize;
+       unsigned int count, datasize;
        sector_t recid, first_rec, last_rec;
-       unsigned blksize, off;
+       unsigned int blksize, off;
        unsigned char rw_cmd;
        int i;
 
@@ -413,13 +536,16 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
                        }
                }
        }
+       cqr->retries = DIAG_MAX_RETRIES;
        cqr->buildclk = get_clock();
        cqr->device = device;
-       cqr->expires = 50 * HZ; /* 50 seconds */
+       cqr->expires = DIAG_TIMEOUT;
        cqr->status = DASD_CQR_FILLED;
        return cqr;
 }
 
+/* Release DASD request. Return non-zero if request was successful, zero
+ * otherwise. */
 static int
 dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req)
 {
@@ -430,6 +556,7 @@ dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req)
        return status;
 }
 
+/* Fill in IOCTL data for device. */
 static int
 dasd_diag_fill_info(struct dasd_device * device,
                    struct dasd_information2_t * info)
@@ -437,7 +564,7 @@ dasd_diag_fill_info(struct dasd_device * device,
        struct dasd_diag_private *private;
 
        private = (struct dasd_diag_private *) device->private;
-       info->label_block = private->pt_block;
+       info->label_block = (unsigned int) private->pt_block;
        info->FBA_layout = 1;
        info->format = DASD_FORMAT_LDL;
        info->characteristics_size = sizeof (struct dasd_diag_characteristics);
@@ -456,26 +583,15 @@ dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                    "dump sense not available for DIAG data");
 }
 
-/*
- * max_blocks is dependent on the amount of storage that is available
- * in the static io buffer for each device. Currently each device has
- * 8192 bytes (=2 pages). dasd diag is only relevant for 31 bit.
- * The struct dasd_ccw_req has 96 bytes, the struct dasd_diag_req has
- * 8 bytes and the struct dasd_diag_bio for each block has 16 bytes. 
- * That makes:
- * (8192 - 96 - 8) / 16 = 505.5 blocks at maximum.
- * We want to fit two into the available memory so that we can immediately
- * start the next request if one finishes off. That makes 252.75 blocks
- * for one request. Give a little safety and the result is 240.
- */
 struct dasd_discipline dasd_diag_discipline = {
        .owner = THIS_MODULE,
        .name = "DIAG",
        .ebcname = "DIAG",
-       .max_blocks = 240,
+       .max_blocks = DIAG_MAX_BLOCKS,
        .check_device = dasd_diag_check_device,
        .fill_geometry = dasd_diag_fill_geometry,
        .start_IO = dasd_start_diag,
+       .term_IO = dasd_diag_term_IO,
        .examine_error = dasd_diag_examine_error,
        .erp_action = dasd_diag_erp_action,
        .erp_postaction = dasd_diag_erp_postaction,
@@ -493,7 +609,7 @@ dasd_diag_init(void)
                            "Machine is not VM: %s "
                            "discipline not initializing",
                            dasd_diag_discipline.name);
-               return -EINVAL;
+               return -ENODEV;
        }
        ASCEBC(dasd_diag_discipline.ebcname, 4);
 
@@ -506,13 +622,6 @@ dasd_diag_init(void)
 static void __exit
 dasd_diag_cleanup(void)
 {
-       if (!MACHINE_IS_VM) {
-               MESSAGE_LOG(KERN_INFO,
-                           "Machine is not VM: %s "
-                           "discipline not cleaned",
-                           dasd_diag_discipline.name);
-               return;
-       }
        unregister_external_interrupt(0x2603, dasd_ext_handler);
        ctl_clear_bit(0, 9);
        dasd_diag_discipline_pointer = NULL;
@@ -520,22 +629,3 @@ dasd_diag_cleanup(void)
 
 module_init(dasd_diag_init);
 module_exit(dasd_diag_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 a0c38e3039798527cc5ffbf13065af9a2c555b67..b26eb28df4bf093e4b6816275ba46d91d4236896 100644 (file)
@@ -6,7 +6,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
- * $Revision: 1.6 $
+ * $Revision: 1.7 $
  */
 
 #define MDSK_WRITE_REQ 0x01
 #define DEV_CLASS_FBA  0x01
 #define DEV_CLASS_ECKD 0x04
 
+#define DASD_DIAG_LC_INT_CODE          132
+#define DASD_DIAG_LC_INT_STATUS                133
+#define DASD_DIAG_LC_INT_PARM_31BIT    128
+#define DASD_DIAG_LC_INT_PARM_64BIT    4536
+#define DASD_DIAG_CODE_31BIT           0x03
+#define DASD_DIAG_CODE_64BIT           0x07
+
+#define DASD_DIAG_RWFLAG_ASYNC         0x02
+#define DASD_DIAG_RWFLAG_NOCACHE       0x01
+
+#define DASD_DIAG_FLAGA_FORMAT_64BIT   0x80
+
 struct dasd_diag_characteristics {
        u16 dev_nr;
        u16 rdc_len;
@@ -32,35 +44,106 @@ struct dasd_diag_characteristics {
        u8 rdev_features;
 } __attribute__ ((packed, aligned(4)));
 
+struct dasd_diag_cms_label {
+       u8 label_id[4];
+       u8 vol_id[6];
+       u16 version_id;
+       u32 block_size;
+       u32 origin_ptr;
+       u32 usable_count;
+       u32 formatted_count;
+       u32 block_count;
+       u32 used_count;
+       u32 fst_size;
+       u32 fst_count;
+       u8 format_date[6];
+       u8 reserved1[2];
+       u32 disk_offset;
+       u32 map_block;
+       u32 hblk_disp;
+       u32 user_disp;
+       u8 reserved2[4];
+       u8 segment_name[8];
+} __attribute__ ((packed));
+
+#ifdef CONFIG_ARCH_S390X
+#define DASD_DIAG_FLAGA_DEFAULT                DASD_DIAG_FLAGA_FORMAT_64BIT
+
+typedef u64 blocknum_t;
+typedef s64 sblocknum_t;
+
+struct dasd_diag_bio {
+       u8 type;
+       u8 status;
+       u8 spare1[2];
+       u32 alet;
+       blocknum_t block_number;
+       u64 buffer;
+} __attribute__ ((packed, aligned(8)));
+
+struct dasd_diag_init_io {
+       u16 dev_nr;
+       u8 flaga;
+       u8 spare1[21];
+       u32 block_size;
+       u8 spare2[4];
+       blocknum_t offset;
+       sblocknum_t start_block;
+       blocknum_t end_block;
+       u8  spare3[8];
+} __attribute__ ((packed, aligned(8)));
+
+struct dasd_diag_rw_io {
+       u16 dev_nr;
+       u8  flaga;
+       u8  spare1[21];
+       u8  key;
+       u8  flags;
+       u8  spare2[2];
+       u32 block_count;
+       u32 alet;
+       u8  spare3[4];
+       u64 interrupt_params;
+       u64 bio_list;
+       u8  spare4[8];
+} __attribute__ ((packed, aligned(8)));
+#else /* CONFIG_ARCH_S390X */
+#define DASD_DIAG_FLAGA_DEFAULT                0x0
+
+typedef u32 blocknum_t;
+typedef s32 sblocknum_t;
+
 struct dasd_diag_bio {
        u8 type;
        u8 status;
        u16 spare1;
-       u32 block_number;
+       blocknum_t block_number;
        u32 alet;
        u32 buffer;
 } __attribute__ ((packed, aligned(8)));
 
 struct dasd_diag_init_io {
        u16 dev_nr;
-       u16 spare1[11];
+       u8 flaga;
+       u8 spare1[21];
        u32 block_size;
-       u32 offset;
-       u32 start_block;
-       u32 end_block;
-       u32 spare2[6];
+       blocknum_t offset;
+       sblocknum_t start_block;
+       blocknum_t end_block;
+       u8 spare2[24];
 } __attribute__ ((packed, aligned(8)));
 
 struct dasd_diag_rw_io {
        u16 dev_nr;
-       u16 spare1[11];
+       u8 flaga;
+       u8 spare1[21];
        u8 key;
        u8 flags;
-       u16 spare2;
+       u8 spare2[2];
        u32 block_count;
        u32 alet;
        u32 bio_list;
        u32 interrupt_params;
-       u32 spare3[5];
+       u8 spare3[20];
 } __attribute__ ((packed, aligned(8)));
-
+#endif /* CONFIG_ARCH_S390X */
index 96c49349701f9f092b71e226bbf6bf5f4dde03b4..a601c9a33541cb7362223fee666de8f5a54d7284 100644 (file)
@@ -9,7 +9,7 @@
  *
  * gendisk related functions for the dasd driver.
  *
- * $Revision: 1.50 $
+ * $Revision: 1.51 $
  */
 
 #include <linux/config.h>
@@ -31,16 +31,12 @@ int
 dasd_gendisk_alloc(struct dasd_device *device)
 {
        struct gendisk *gdp;
-       int len, feature_ro;
+       int len;
 
        /* Make sure the minor for this device exists. */
        if (device->devindex >= DASD_PER_MAJOR)
                return -EBUSY;
 
-       feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
-       if (feature_ro < 0)
-               return feature_ro;
-
        gdp = alloc_disk(1 << DASD_PARTN_BITS);
        if (!gdp)
                return -ENOMEM;
@@ -75,7 +71,7 @@ dasd_gendisk_alloc(struct dasd_device *device)
 
        sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id);
 
-       if (feature_ro)
+       if (device->features & DASD_FEATURE_READONLY)
                set_disk_ro(gdp, 1);
        gdp->private_data = device;
        gdp->queue = device->request_queue;
index a9f38b235981897ac73b35cb5f3e261fe1203ed5..9fab04f3056d6742fe7be6c68a4e2b8719f471ab 100644 (file)
@@ -6,7 +6,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
- * $Revision: 1.64 $
+ * $Revision: 1.65 $
  */
 
 #ifndef DASD_INT_H
@@ -286,6 +286,7 @@ struct dasd_device {
        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!) */
 
        /* Device discipline stuff. */
        struct dasd_discipline *discipline;
index 980c555aa538791687d7c1c8d26d7ddb9e080db0..789595b3fa09ced145a698bfbd11f83fceb848ef 100644 (file)
@@ -7,7 +7,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
  *
- * $Revision: 1.45 $
+ * $Revision: 1.47 $
  *
  * i/o controls for the dasd driver.
  */
@@ -296,7 +296,6 @@ dasd_ioctl_format(struct block_device *bdev, int no, long args)
 {
        struct dasd_device *device;
        struct format_data_t fdata;
-       int feature_ro;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
@@ -308,10 +307,7 @@ dasd_ioctl_format(struct block_device *bdev, int no, long args)
        if (device == NULL)
                return -ENODEV;
 
-       feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
-       if (feature_ro < 0)
-               return feature_ro;
-       if (feature_ro)
+       if (device->features & DASD_FEATURE_READONLY)
                return -EROFS;
        if (copy_from_user(&fdata, (void __user *) args,
                           sizeof (struct format_data_t)))
@@ -384,7 +380,7 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args)
        struct dasd_device *device;
        struct dasd_information2_t *dasd_info;
        unsigned long flags;
-       int rc, feature_ro;
+       int rc;
        struct ccw_device *cdev;
 
        device = bdev->bd_disk->private_data;
@@ -394,10 +390,6 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args)
        if (!device->discipline->fill_info)
                return -EINVAL;
 
-       feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
-       if (feature_ro < 0)
-               return feature_ro;
-
        dasd_info = kmalloc(sizeof(struct dasd_information2_t), GFP_KERNEL);
        if (dasd_info == NULL)
                return -ENOMEM;
@@ -427,7 +419,8 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args)
            (dasd_check_blocksize(device->bp_block)))
                dasd_info->format = DASD_FORMAT_NONE;
 
-       dasd_info->features |= feature_ro;
+       dasd_info->features |=
+               ((device->features & DASD_FEATURE_READONLY) != 0);
 
        if (device->discipline)
                memcpy(dasd_info->type, device->discipline->name, 4);
index 43c34f8c5e685336daeaf87021d4a683720adaa8..fff9020d48866bd2910fad640f105a9ccd0032e4 100644 (file)
@@ -9,7 +9,7 @@
  *
  * /proc interface for the dasd driver.
  *
- * $Revision: 1.32 $
+ * $Revision: 1.33 $
  */
 
 #include <linux/config.h>
@@ -55,7 +55,6 @@ dasd_devices_show(struct seq_file *m, void *v)
 {
        struct dasd_device *device;
        char *substr;
-       int feature;
 
        device = dasd_device_from_devindex((unsigned long) v - 1);
        if (IS_ERR(device))
@@ -79,10 +78,7 @@ dasd_devices_show(struct seq_file *m, void *v)
        else
                seq_printf(m, " is ????????");
        /* Print devices features. */
-       feature = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
-       if (feature < 0)
-               return 0;
-       substr = feature ? "(ro)" : " ";
+       substr = (device->features & DASD_FEATURE_READONLY) ? "(ro)" : " ";
        seq_printf(m, "%4s: ", substr);
        /* Print device status information. */
        switch ((device != NULL) ? device->state : -1) {
index d5eefeaba50ca209834c4d9c10879b9fe23f4c7f..328d9cbc56a37f0b064c94ceb61b7f37a81921bb 100644 (file)
@@ -632,12 +632,9 @@ __raw3270_size_device(struct raw3270 *rp)
        raw3270_init_request.ccw.cda = (__u32) __pa(raw3270_init_data);
 
        rc = raw3270_start_init(rp, &raw3270_init_view, &raw3270_init_request);
-       if (rc) {
+       if (rc)
                /* Check error cases: -ERESTARTSYS, -EIO and -EOPNOTSUPP */
-               if (rc == -EOPNOTSUPP && MACHINE_IS_VM)
-                       return __raw3270_size_device_vm(rp);
                return rc;
-       }
 
        /* Wait for attention interrupt. */
 #ifdef CONFIG_TN3270_CONSOLE
@@ -695,7 +692,10 @@ raw3270_size_device(struct raw3270 *rp)
        down(&raw3270_init_sem);
        rp->view = &raw3270_init_view;
        raw3270_init_view.dev = rp;
-       rc = __raw3270_size_device(rp);
+       if (MACHINE_IS_VM)
+               rc = __raw3270_size_device_vm(rp);
+       else
+               rc = __raw3270_size_device(rp);
        raw3270_init_view.dev = 0;
        rp->view = 0;
        up(&raw3270_init_sem);
@@ -710,6 +710,12 @@ raw3270_size_device(struct raw3270 *rp)
                        rp->model = 4;
                if (rp->rows == 27 && rp->cols == 132)
                        rp->model = 5;
+       } else {
+               /* Couldn't detect size. Use default model 2. */
+               rp->model = 2;
+               rp->rows = 24;
+               rp->cols = 80;
+               return 0;
        }
        return rc;
 }
index ea813bdce1d63a8617ddb2881b98a679bfb17445..185bc73c3ecde9c64717729a40b2591260302d25 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/cio.c
  *   S/390 common I/O routines -- low level i/o calls
- *   $Revision: 1.134 $
+ *   $Revision: 1.135 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *                           IBM Corporation
@@ -815,8 +815,9 @@ __clear_subchannel_easy(unsigned int schid)
                struct tpi_info ti;
 
                if (tpi(&ti)) {
-                       tsch(schid, (struct irb *)__LC_IRB);
-                       return 0;
+                       tsch(ti.irq, (struct irb *)__LC_IRB);
+                       if (ti.irq == schid)
+                               return 0;
                }
                udelay(100);
        }
index ee7a05e0c3baf60a5e0effd52ca5c9b26b8989ea..fbe4202a3f6f462e2104e7acf84368f5cd15198f 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/init.h>
 
 #include <asm/ccwdev.h>
-#include <asm/qdio.h>
+#include <asm/cio.h>
 
 #include "cio.h"
 #include "cio_debug.h"
@@ -21,7 +21,6 @@
 #include "device.h"
 #include "chsc.h"
 #include "ioasm.h"
-#include "qdio.h"
 
 int
 device_is_online(struct subchannel *sch)
index 02d01a0de16c4e476e415cac49fc584726ab132a..ad3fe5aeb663a01d3f034cba4db8a879ec65e374 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/device_ops.c
  *
- *   $Revision: 1.56 $
+ *   $Revision: 1.57 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                      IBM Corporation
 
 #include <asm/ccwdev.h>
 #include <asm/idals.h>
-#include <asm/qdio.h>
 
 #include "cio.h"
 #include "cio_debug.h"
 #include "css.h"
 #include "chsc.h"
 #include "device.h"
-#include "qdio.h"
 
 int
 ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
index c874607d9a806ec9fccbe908a5569198c0351ae3..45480a2bc4c0ab534f2b156f8f71bcf66ae411c3 100644 (file)
@@ -21,7 +21,7 @@ struct tpi_info {
  * Some S390 specific IO instructions as inline
  */
 
-extern __inline__ int stsch(int irq, volatile struct schib *addr)
+static inline int stsch(int irq, volatile struct schib *addr)
 {
        int ccode;
 
@@ -36,7 +36,7 @@ extern __inline__ int stsch(int irq, volatile struct schib *addr)
        return ccode;
 }
 
-extern __inline__ int msch(int irq, volatile struct schib *addr)
+static inline int msch(int irq, volatile struct schib *addr)
 {
        int ccode;
 
@@ -51,7 +51,7 @@ extern __inline__ int msch(int irq, volatile struct schib *addr)
        return ccode;
 }
 
-extern __inline__ int msch_err(int irq, volatile struct schib *addr)
+static inline int msch_err(int irq, volatile struct schib *addr)
 {
        int ccode;
 
@@ -79,7 +79,7 @@ extern __inline__ int msch_err(int irq, volatile struct schib *addr)
        return ccode;
 }
 
-extern __inline__ int tsch(int irq, volatile struct irb *addr)
+static inline int tsch(int irq, volatile struct irb *addr)
 {
        int ccode;
 
@@ -94,7 +94,7 @@ extern __inline__ int tsch(int irq, volatile struct irb *addr)
        return ccode;
 }
 
-extern __inline__ int tpi( volatile struct tpi_info *addr)
+static inline int tpi( volatile struct tpi_info *addr)
 {
        int ccode;
 
@@ -108,7 +108,7 @@ extern __inline__ int tpi( volatile struct tpi_info *addr)
        return ccode;
 }
 
-extern __inline__ int ssch(int irq, volatile struct orb *addr)
+static inline int ssch(int irq, volatile struct orb *addr)
 {
        int ccode;
 
@@ -123,7 +123,7 @@ extern __inline__ int ssch(int irq, volatile struct orb *addr)
        return ccode;
 }
 
-extern __inline__ int rsch(int irq)
+static inline int rsch(int irq)
 {
        int ccode;
 
@@ -138,7 +138,7 @@ extern __inline__ int rsch(int irq)
        return ccode;
 }
 
-extern __inline__ int csch(int irq)
+static inline int csch(int irq)
 {
        int ccode;
 
@@ -153,7 +153,7 @@ extern __inline__ int csch(int irq)
        return ccode;
 }
 
-extern __inline__ int hsch(int irq)
+static inline int hsch(int irq)
 {
        int ccode;
 
@@ -168,7 +168,7 @@ extern __inline__ int hsch(int irq)
        return ccode;
 }
 
-extern __inline__ int xsch(int irq)
+static inline int xsch(int irq)
 {
        int ccode;
 
@@ -183,7 +183,7 @@ extern __inline__ int xsch(int irq)
        return ccode;
 }
 
-extern __inline__ int chsc(void *chsc_area)
+static inline int chsc(void *chsc_area)
 {
        int cc;
 
@@ -198,7 +198,7 @@ extern __inline__ int chsc(void *chsc_area)
        return cc;
 }
 
-extern __inline__ int iac( void)
+static inline int iac( void)
 {
        int ccode;
 
@@ -210,7 +210,7 @@ extern __inline__ int iac( void)
        return ccode;
 }
 
-extern __inline__ int rchp(int chpid)
+static inline int rchp(int chpid)
 {
        int ccode;
 
index bcabac7a7c460960f865c73ac2a723e170ac9df2..e319e78b5ea2374a26fd9894f6c3732796beb31d 100644 (file)
@@ -27,7 +27,7 @@
 #ifndef _Z90COMMON_H_
 #define _Z90COMMON_H_
 
-#define VERSION_Z90COMMON_H "$Revision: 1.16 $"
+#define VERSION_Z90COMMON_H "$Revision: 1.17 $"
 
 
 #define RESPBUFFSIZE 256
@@ -164,5 +164,4 @@ struct CPRBX {
 #define UMIN(a,b) ((a) < (b) ? (a) : (b))
 #define IS_EVEN(x) ((x) == (2 * ((x) / 2)))
 
-
 #endif
index beb6a5e0da2267508a70d845c6e81643ca41825b..c215e088973625087daf5985afd5cb97e0794976 100644 (file)
@@ -32,7 +32,7 @@
 #include "z90crypt.h"
 #include "z90common.h"
 
-#define VERSION_Z90HARDWARE_C "$Revision: 1.33 $"
+#define VERSION_Z90HARDWARE_C "$Revision: 1.34 $"
 
 char z90hardware_version[] __initdata =
        "z90hardware.o (" VERSION_Z90HARDWARE_C "/"
@@ -283,48 +283,6 @@ struct type6_msg {
        struct CPRB      CPRB;
 };
 
-union request_msg {
-       union  type4_msg t4msg;
-       struct type6_msg t6msg;
-};
-
-struct request_msg_ext {
-       int               q_nr;
-       unsigned char     *psmid;
-       union request_msg reqMsg;
-};
-
-struct type82_hdr {
-       unsigned char reserved1;
-       unsigned char type;
-       unsigned char reserved2[2];
-       unsigned char reply_code;
-       unsigned char reserved3[3];
-};
-
-#define TYPE82_RSP_CODE 0x82
-
-#define REPLY_ERROR_MACHINE_FAILURE  0x10
-#define REPLY_ERROR_PREEMPT_FAILURE  0x12
-#define REPLY_ERROR_CHECKPT_FAILURE  0x14
-#define REPLY_ERROR_MESSAGE_TYPE     0x20
-#define REPLY_ERROR_INVALID_COMM_CD  0x21
-#define REPLY_ERROR_INVALID_MSG_LEN  0x23
-#define REPLY_ERROR_RESERVD_FIELD    0x24
-#define REPLY_ERROR_FORMAT_FIELD     0x29
-#define REPLY_ERROR_INVALID_COMMAND  0x30
-#define REPLY_ERROR_MALFORMED_MSG    0x40
-#define REPLY_ERROR_RESERVED_FIELDO  0x50
-#define REPLY_ERROR_WORD_ALIGNMENT   0x60
-#define REPLY_ERROR_MESSAGE_LENGTH   0x80
-#define REPLY_ERROR_OPERAND_INVALID  0x82
-#define REPLY_ERROR_OPERAND_SIZE     0x84
-#define REPLY_ERROR_EVEN_MOD_IN_OPND 0x85
-#define REPLY_ERROR_RESERVED_FIELD   0x88
-#define REPLY_ERROR_TRANSPORT_FAIL   0x90
-#define REPLY_ERROR_PACKET_TRUNCATED 0xA0
-#define REPLY_ERROR_ZERO_BUFFER_LEN  0xB0
-
 struct type86_hdr {
        unsigned char reserved1;
        unsigned char type;
@@ -338,7 +296,7 @@ struct type86_hdr {
 #define TYPE86_FMT2    0x02
 
 struct type86_fmt2_msg {
-       struct type86_hdr hdr;
+       struct type86_hdr header;
        unsigned char     reserved[4];
        unsigned char     apfs[4];
        unsigned int      count1;
@@ -538,6 +496,8 @@ static struct function_and_rules_block static_pke_function_and_rulesX = {
        {'M','R','P',' ',' ',' ',' ',' '}
 };
 
+static unsigned char static_PKE_function_code[2] = {0x50, 0x4B};
+
 struct T6_keyBlock_hdrX {
        unsigned short blen;
        unsigned short ulen;
@@ -688,9 +648,38 @@ static struct cca_public_sec static_cca_pub_sec = {
 #define RESPONSE_CPRB_SIZE  0x000006B8
 #define RESPONSE_CPRBX_SIZE 0x00000724
 
-#define CALLER_HEADER 12
+struct error_hdr {
+       unsigned char reserved1;
+       unsigned char type;
+       unsigned char reserved2[2];
+       unsigned char reply_code;
+       unsigned char reserved3[3];
+};
 
-static unsigned char static_PKE_function_code[2] = {0x50, 0x4B};
+#define TYPE82_RSP_CODE 0x82
+
+#define REP82_ERROR_MACHINE_FAILURE  0x10
+#define REP82_ERROR_PREEMPT_FAILURE  0x12
+#define REP82_ERROR_CHECKPT_FAILURE  0x14
+#define REP82_ERROR_MESSAGE_TYPE     0x20
+#define REP82_ERROR_INVALID_COMM_CD  0x21
+#define REP82_ERROR_INVALID_MSG_LEN  0x23
+#define REP82_ERROR_RESERVD_FIELD    0x24
+#define REP82_ERROR_FORMAT_FIELD     0x29
+#define REP82_ERROR_INVALID_COMMAND  0x30
+#define REP82_ERROR_MALFORMED_MSG    0x40
+#define REP82_ERROR_RESERVED_FIELDO  0x50
+#define REP82_ERROR_WORD_ALIGNMENT   0x60
+#define REP82_ERROR_MESSAGE_LENGTH   0x80
+#define REP82_ERROR_OPERAND_INVALID  0x82
+#define REP82_ERROR_OPERAND_SIZE     0x84
+#define REP82_ERROR_EVEN_MOD_IN_OPND 0x85
+#define REP82_ERROR_RESERVED_FIELD   0x88
+#define REP82_ERROR_TRANSPORT_FAIL   0x90
+#define REP82_ERROR_PACKET_TRUNCATED 0xA0
+#define REP82_ERROR_ZERO_BUFFER_LEN  0xB0
+
+#define CALLER_HEADER 12
 
 static inline int
 testq(int q_nr, int *q_depth, int *dev_type, struct ap_status_word *stat)
@@ -1212,9 +1201,9 @@ send_to_AP(int dev_nr, int cdx, int msg_len, unsigned char *msg_ext)
        struct ap_status_word stat_word;
        enum devstat stat;
        int ccode;
+       u32 *q_nr_p = (u32 *)msg_ext;
 
-       ((struct request_msg_ext *) msg_ext)->q_nr =
-               (dev_nr << SKIP_BITL) + cdx;
+       *q_nr_p = (dev_nr << SKIP_BITL) + cdx;
        PDEBUG("msg_len passed to sen: %d\n", msg_len);
        PDEBUG("q number passed to sen: %02x%02x%02x%02x\n",
               msg_ext[0], msg_ext[1], msg_ext[2], msg_ext[3]);
@@ -2104,7 +2093,7 @@ convert_response(unsigned char *response, unsigned char *buffer,
                 int *respbufflen_p, unsigned char *resp_buff)
 {
        struct ica_rsa_modexpo *icaMsg_p = (struct ica_rsa_modexpo *) buffer;
-       struct type82_hdr *t82h_p = (struct type82_hdr *) response;
+       struct error_hdr *errh_p = (struct error_hdr *) response;
        struct type84_hdr *t84h_p = (struct type84_hdr *) response;
        struct type86_fmt2_msg *t86m_p =  (struct type86_fmt2_msg *) response;
        int reply_code, service_rc, service_rs, src_l;
@@ -2117,12 +2106,13 @@ convert_response(unsigned char *response, unsigned char *buffer,
        service_rc = 0;
        service_rs = 0;
        src_l = 0;
-       switch (t82h_p->type) {
+       switch (errh_p->type) {
        case TYPE82_RSP_CODE:
-               reply_code = t82h_p->reply_code;
-               src_p = (unsigned char *)t82h_p;
-               PRINTK("Hardware error: Type 82 Message Header: "
+               reply_code = errh_p->reply_code;
+               src_p = (unsigned char *)errh_p;
+               PRINTK("Hardware error: Type %02X Message Header: "
                       "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+                      errh_p->type,
                       src_p[0], src_p[1], src_p[2], src_p[3],
                       src_p[4], src_p[5], src_p[6], src_p[7]);
                break;
@@ -2131,7 +2121,7 @@ convert_response(unsigned char *response, unsigned char *buffer,
                src_p = response + (int)t84h_p->len - src_l;
                break;
        case TYPE86_RSP_CODE:
-               reply_code = t86m_p->hdr.reply_code;
+               reply_code = t86m_p->header.reply_code;
                if (reply_code != 0)
                        break;
                cprb_p = (struct CPRB *)
@@ -2143,6 +2133,9 @@ convert_response(unsigned char *response, unsigned char *buffer,
                                le2toI(cprb_p->ccp_rscode, &service_rs);
                                if ((service_rc == 8) && (service_rs == 66))
                                        PDEBUG("Bad block format on PCICC\n");
+                               else if ((service_rc == 8) && (service_rs == 65))
+                                       PDEBUG("Probably an even modulus on "
+                                              "PCICC\n");
                                else if ((service_rc == 8) && (service_rs == 770)) {
                                        PDEBUG("Invalid key length on PCICC\n");
                                        unset_ext_bitlens();
@@ -2155,7 +2148,7 @@ convert_response(unsigned char *response, unsigned char *buffer,
                                        return REC_USE_PCICA;
                                }
                                else
-                                       PRINTK("service rc/rs: %d/%d\n",
+                                       PRINTK("service rc/rs (PCICC): %d/%d\n",
                                               service_rc, service_rs);
                                return REC_OPERAND_INV;
                        }
@@ -2169,7 +2162,10 @@ convert_response(unsigned char *response, unsigned char *buffer,
                        if (service_rc != 0) {
                                service_rs = (int) cprbx_p->ccp_rscode;
                                if ((service_rc == 8) && (service_rs == 66))
-                                       PDEBUG("Bad block format on PCXICC\n");
+                                       PDEBUG("Bad block format on PCIXCC\n");
+                               else if ((service_rc == 8) && (service_rs == 65))
+                                       PDEBUG("Probably an even modulus on "
+                                              "PCIXCC\n");
                                else if ((service_rc == 8) && (service_rs == 770)) {
                                        PDEBUG("Invalid key length on PCIXCC\n");
                                        unset_ext_bitlens();
@@ -2182,7 +2178,7 @@ convert_response(unsigned char *response, unsigned char *buffer,
                                        return REC_USE_PCICA;
                                }
                                else
-                                       PRINTK("service rc/rs: %d/%d\n",
+                                       PRINTK("service rc/rs (PCIXCC): %d/%d\n",
                                               service_rc, service_rs);
                                return REC_OPERAND_INV;
                        }
@@ -2195,20 +2191,25 @@ convert_response(unsigned char *response, unsigned char *buffer,
                }
                break;
        default:
+               src_p = (unsigned char *)errh_p;
+               PRINTK("Unrecognized Message Header: "
+                      "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+                      src_p[0], src_p[1], src_p[2], src_p[3],
+                      src_p[4], src_p[5], src_p[6], src_p[7]);
                return REC_BAD_MESSAGE;
        }
 
        if (reply_code)
                switch (reply_code) {
-               case REPLY_ERROR_OPERAND_INVALID:
+               case REP82_ERROR_OPERAND_INVALID:
                        return REC_OPERAND_INV;
-               case REPLY_ERROR_OPERAND_SIZE:
+               case REP82_ERROR_OPERAND_SIZE:
                        return REC_OPERAND_SIZE;
-               case REPLY_ERROR_EVEN_MOD_IN_OPND:
+               case REP82_ERROR_EVEN_MOD_IN_OPND:
                        return REC_EVEN_MOD;
-               case REPLY_ERROR_MESSAGE_TYPE:
+               case REP82_ERROR_MESSAGE_TYPE:
                        return WRONG_DEVICE_TYPE;
-               case REPLY_ERROR_TRANSPORT_FAIL:
+               case REP82_ERROR_TRANSPORT_FAIL:
                        PRINTKW("Transport failed (APFS = %02X%02X%02X%02X)\n",
                                t86m_p->apfs[0], t86m_p->apfs[1],
                                t86m_p->apfs[2], t86m_p->apfs[3]);
@@ -2229,7 +2230,7 @@ convert_response(unsigned char *response, unsigned char *buffer,
        PDEBUG("Length returned = %d\n", src_l);
        tgt_p = resp_buff + icaMsg_p->outputdatalength - src_l;
        memcpy(tgt_p, src_p, src_l);
-       if ((t82h_p->type == TYPE86_RSP_CODE) && (resp_buff < tgt_p)) {
+       if ((errh_p->type == TYPE86_RSP_CODE) && (resp_buff < tgt_p)) {
                memset(resp_buff, 0, icaMsg_p->outputdatalength - src_l);
                if (pad_msg(resp_buff, icaMsg_p->outputdatalength, src_l))
                        return REC_INVALID_PAD;
index 9ec29bb41b28b522bd7eab5d2e08b72b98221f18..6aeef3bacc3345407c1fa0b061585feb003722b9 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>   // for tasklets
 #include <linux/ioctl32.h>
+#include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kobject_uevent.h>
 #include <linux/version.h>
 #include "z90crypt.h"
 #include "z90common.h"
-#ifndef Z90CRYPT_USE_HOTPLUG
-#include <linux/miscdevice.h>
-#endif
-
-#define VERSION_CODE(vers, rel, seq) (((vers)<<16) | ((rel)<<8) | (seq))
-#if LINUX_VERSION_CODE < VERSION_CODE(2,4,0) /* version < 2.4 */
-#  error "This kernel is too old: not supported"
-#endif
-#if LINUX_VERSION_CODE > VERSION_CODE(2,7,0) /* version > 2.6 */
-#  error "This kernel is too recent: not supported by this file"
-#endif
 
-#define VERSION_Z90MAIN_C "$Revision: 1.57 $"
+#define VERSION_Z90MAIN_C "$Revision: 1.62 $"
 
 static char z90main_version[] __initdata =
        "z90main.o (" VERSION_Z90MAIN_C "/"
@@ -63,21 +53,12 @@ extern char z90hardware_version[];
  * Defaults that may be modified.
  */
 
-#ifndef Z90CRYPT_USE_HOTPLUG
 /**
  * You can specify a different minor at compile time.
  */
 #ifndef Z90CRYPT_MINOR
 #define Z90CRYPT_MINOR MISC_DYNAMIC_MINOR
 #endif
-#else
-/**
- * You can specify a different major at compile time.
- */
-#ifndef Z90CRYPT_MAJOR
-#define Z90CRYPT_MAJOR 0
-#endif
-#endif
 
 /**
  * You can specify a different domain at compile time or on the insmod
@@ -97,7 +78,7 @@ extern char z90hardware_version[];
  * older than CLEANUPTIME seconds in the past.
  */
 #ifndef CLEANUPTIME
-#define CLEANUPTIME 20
+#define CLEANUPTIME 15
 #endif
 
 /**
@@ -298,6 +279,10 @@ struct z90crypt {
  * it contains the request; at READ, the response. The function
  * send_to_crypto_device converts the request to device-dependent
  * form and use the caller's OPEN-allocated buffer for the response.
+ *
+ * For the contents of caller_dev_dep_req and caller_dev_dep_req_p
+ * because that points to it, see the discussion in z90hardware.c.
+ * Search for "extended request message block".
  */
 struct caller {
        int              caller_buf_l;           // length of original request
@@ -397,25 +382,10 @@ static int z90crypt_status(char *, char **, off_t, int, int *, void *);
 static int z90crypt_status_write(struct file *, const char __user *,
                                 unsigned long, void *);
 
-/**
- * Hotplug support
- */
-
-#ifdef Z90CRYPT_USE_HOTPLUG
-#define Z90CRYPT_HOTPLUG_ADD    1
-#define Z90CRYPT_HOTPLUG_REMOVE         2
-
-static void z90crypt_hotplug_event(int, int, int);
-#endif
-
 /**
  * Storage allocated at initialization and used throughout the life of
  * this insmod
  */
-#ifdef Z90CRYPT_USE_HOTPLUG
-static int z90crypt_major = Z90CRYPT_MAJOR;
-#endif
-
 static int domain = DOMAIN_INDEX;
 static struct z90crypt z90crypt;
 static int quiesce_z90crypt;
@@ -444,14 +414,12 @@ static struct file_operations z90crypt_fops = {
        .release        = z90crypt_release
 };
 
-#ifndef Z90CRYPT_USE_HOTPLUG
 static struct miscdevice z90crypt_misc_device = {
        .minor      = Z90CRYPT_MINOR,
        .name       = DEV_NAME,
        .fops       = &z90crypt_fops,
        .devfs_name = DEV_NAME
 };
-#endif
 
 /**
  * Documentation values.
@@ -603,7 +571,6 @@ z90crypt_init_module(void)
                return -EINVAL;
        }
 
-#ifndef Z90CRYPT_USE_HOTPLUG
        /* Register as misc device with given minor (or get a dynamic one). */
        result = misc_register(&z90crypt_misc_device);
        if (result < 0) {
@@ -611,18 +578,6 @@ z90crypt_init_module(void)
                        z90crypt_misc_device.minor, result);
                return result;
        }
-#else
-       /* Register the major (or get a dynamic one). */
-       result = register_chrdev(z90crypt_major, REG_NAME, &z90crypt_fops);
-       if (result < 0) {
-               PRINTKW("register_chrdev (major %d) failed with %d.\n",
-                       z90crypt_major, result);
-               return result;
-       }
-
-       if (z90crypt_major == 0)
-               z90crypt_major = result;
-#endif
 
        PDEBUG("Registered " DEV_NAME " with result %d\n", result);
 
@@ -645,11 +600,6 @@ z90crypt_init_module(void)
        } else
                PRINTK("No devices at startup\n");
 
-#ifdef Z90CRYPT_USE_HOTPLUG
-       /* generate hotplug event for device node generation */
-       z90crypt_hotplug_event(z90crypt_major, 0, Z90CRYPT_HOTPLUG_ADD);
-#endif
-
        /* Initialize globals. */
        spin_lock_init(&queuespinlock);
 
@@ -701,17 +651,10 @@ z90crypt_init_module(void)
        return 0; // success
 
 init_module_cleanup:
-#ifndef Z90CRYPT_USE_HOTPLUG
        if ((nresult = misc_deregister(&z90crypt_misc_device)))
                PRINTK("misc_deregister failed with %d.\n", nresult);
        else
                PDEBUG("misc_deregister successful.\n");
-#else
-       if ((nresult = unregister_chrdev(z90crypt_major, REG_NAME)))
-               PRINTK("unregister_chrdev failed with %d.\n", nresult);
-       else
-               PDEBUG("unregister_chrdev successful.\n");
-#endif
 
        return result; // failure
 }
@@ -728,19 +671,10 @@ z90crypt_cleanup_module(void)
 
        remove_proc_entry("driver/z90crypt", 0);
 
-#ifndef Z90CRYPT_USE_HOTPLUG
        if ((nresult = misc_deregister(&z90crypt_misc_device)))
                PRINTK("misc_deregister failed with %d.\n", nresult);
        else
                PDEBUG("misc_deregister successful.\n");
-#else
-       z90crypt_hotplug_event(z90crypt_major, 0, Z90CRYPT_HOTPLUG_REMOVE);
-
-       if ((nresult = unregister_chrdev(z90crypt_major, REG_NAME)))
-               PRINTK("unregister_chrdev failed with %d.\n", nresult);
-       else
-               PDEBUG("unregister_chrdev successful.\n");
-#endif
 
        /* Remove the tasks */
        tasklet_kill(&reader_tasklet);
@@ -748,6 +682,9 @@ z90crypt_cleanup_module(void)
        del_timer(&config_timer);
        del_timer(&cleanup_timer);
 
+       if (z90_device_work)
+               destroy_workqueue(z90_device_work);
+
        destroy_z90crypt();
 
        PRINTKN("Unloaded.\n");
@@ -766,8 +703,6 @@ z90crypt_cleanup_module(void)
  *     z90crypt_status_write
  *      disable_card
  *      enable_card
- *      scan_char
- *      scan_string
  *
  * Helper functions:
  *     z90crypt_rsa
@@ -1057,9 +992,10 @@ remove_device(struct device *device_p)
  * The MCL must be applied and the newer bitlengths enabled for these to work.
  *
  * Card Type    Old limit    New limit
+ * PCICA          ??-2048     same (the lower limit is less than 128 bit...)
  * PCICC         512-1024     512-2048
- * PCIXCC_MCL2   512-2048     no change (applying this MCL == card is MCL3+)
- * PCIXCC_MCL3   512-2048     128-2048
+ * PCIXCC_MCL2   512-2048     ----- (applying any GA LIC will make an MCL3 card)
+ * PCIXCC_MCL3   -----        128-2048
  * CEX2C         512-2048     128-2048
  *
  * ext_bitlens (extended bitlengths) is a global, since you should not apply an
@@ -1104,7 +1040,7 @@ select_device_type(int *dev_type_p, int bytelength)
        if (PCICA_avail || PCIXCC_MCL3_avail || CEX2C_avail) {
                /**
                 * bitlength is a factor, PCICA is the most capable, even with
-                * the new MCL.
+                * the new MCL for PCIXCC.
                 */
                if ((bytelength < PCIXCC_MIN_MOD_SIZE) ||
                    (!ext_bitlens && (bytelength < OLD_PCIXCC_MIN_MOD_SIZE))) {
@@ -2144,73 +2080,15 @@ enable_card(int card_index)
        z90crypt.hdware_info->type_mask[devp->dev_type].user_disabled_count--;
 }
 
-static inline int
-scan_char(unsigned char *bf, unsigned int len,
-         unsigned int *offs, unsigned int *p_eof, unsigned char c)
-{
-       unsigned int i, found;
-
-       found = 0;
-       for (i = 0; i < len; i++) {
-               if (bf[i] == c) {
-                       found = 1;
-                       break;
-               }
-               if (bf[i] == '\0') {
-                       *p_eof = 1;
-                       break;
-               }
-               if (bf[i] == '\n') {
-                       break;
-               }
-       }
-       *offs = i+1;
-       return found;
-}
-
-static inline int
-scan_string(unsigned char *bf, unsigned int len,
-           unsigned int *offs, unsigned int *p_eof, unsigned char *s)
-{
-       unsigned int temp_len, temp_offs, found, eof;
-
-       temp_len = temp_offs = found = eof = 0;
-       while (!eof && !found) {
-               found = scan_char(bf+temp_len, len-temp_len,
-                                 &temp_offs, &eof, *s);
-
-               temp_len += temp_offs;
-               if (eof) {
-                       found = 0;
-                       break;
-               }
-
-               if (found) {
-                       if (len >= temp_offs+strlen(s)) {
-                               found = !strncmp(bf+temp_len-1, s, strlen(s));
-                               if (found) {
-                                       *offs = temp_len+strlen(s)-1;
-                                       break;
-                               }
-                       } else {
-                               found = 0;
-                               *p_eof = 1;
-                               break;
-                       }
-               }
-       }
-       return found;
-}
-
 static int
 z90crypt_status_write(struct file *file, const char __user *buffer,
                      unsigned long count, void *data)
 {
-       int i, j, len, offs, found, eof;
-       unsigned char *lbuf;
+       int j, eol;
+       unsigned char *lbuf, *ptr;
        unsigned int local_count;
 
-#define LBUFSIZE 600
+#define LBUFSIZE 1200
        lbuf = kmalloc(LBUFSIZE, GFP_KERNEL);
        if (!lbuf) {
                PRINTK("kmalloc failed!\n");
@@ -2227,49 +2105,46 @@ z90crypt_status_write(struct file *file, const char __user *buffer,
                return -EFAULT;
        }
 
-       lbuf[local_count-1] = '\0';
+       lbuf[local_count] = '\0';
 
-       len = 0;
-       eof = 0;
-       found = 0;
-       while (!eof) {
-               found = scan_string(lbuf+len, local_count-len, &offs, &eof,
-                                   "Online devices");
-               len += offs;
-               if (found == 1)
-                       break;
+       ptr = strstr(lbuf, "Online devices");
+       if (ptr == 0) {
+               PRINTK("Unable to parse data (missing \"Online devices\")\n");
+               kfree(lbuf);
+               return count;
        }
 
-       if (eof) {
+       ptr = strstr(ptr, "\n");
+       if (ptr == 0) {
+               PRINTK("Unable to parse data (missing newline after \"Online devices\")\n");
                kfree(lbuf);
                return count;
        }
+       ptr++;
 
-       if (found)
-               found = scan_char(lbuf+len, local_count-len, &offs, &eof, '\n');
-
-       if (!found || eof) {
+       if (strstr(ptr, "Waiting work element counts") == NULL) {
+               PRINTK("Unable to parse data (missing \"Waiting work element counts\")\n");
                kfree(lbuf);
                return count;
        }
 
-       len += offs;
        j = 0;
-       for (i = 0; i < 80; i++) {
-               switch (*(lbuf+len+i)) {
+       eol = 0;
+       while ((j < 64) && (*ptr != '\0')) {
+               switch (*ptr) {
                case '\t':
                case ' ':
                        break;
                case '\n':
                default:
-                       eof = 1;
+                       eol = 1;
                        break;
-               case '0':
-               case '1':
-               case '2':
-               case '3':
-               case '4':
-               case '5':
+               case '0':       // no device
+               case '1':       // PCICA
+               case '2':       // PCICC
+               case '3':       // PCIXCC_MCL2
+               case '4':       // PCIXCC_MCL3
+               case '5':       // CEX2C
                        j++;
                        break;
                case 'd':
@@ -2283,8 +2158,9 @@ z90crypt_status_write(struct file *file, const char __user *buffer,
                        j++;
                        break;
                }
-               if (eof)
+               if (eol)
                        break;
+               ptr++;
        }
 
        kfree(lbuf);
@@ -3479,45 +3355,5 @@ probe_PCIXCC_type(struct device *devPtr)
        return rv;
 }
 
-#ifdef Z90CRYPT_USE_HOTPLUG
-static void
-z90crypt_hotplug_event(int dev_major, int dev_minor, int action)
-{
-#ifdef CONFIG_HOTPLUG
-       char *argv[3];
-       char *envp[6];
-       char  major[20];
-       char  minor[20];
-
-       sprintf(major, "MAJOR=%d", dev_major);
-       sprintf(minor, "MINOR=%d", dev_minor);
-
-       argv[0] = hotplug_path;
-       argv[1] = "z90crypt";
-       argv[2] = 0;
-
-       envp[0] = "HOME=/";
-       envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-
-       switch (action) {
-       case Z90CRYPT_HOTPLUG_ADD:
-               envp[2] = "ACTION=add";
-               break;
-       case Z90CRYPT_HOTPLUG_REMOVE:
-               envp[2] = "ACTION=remove";
-               break;
-       default:
-               BUG();
-               break;
-       }
-       envp[3] = major;
-       envp[4] = minor;
-       envp[5] = 0;
-
-       call_usermodehelper(argv[0], argv, envp, 0);
-#endif
-}
-#endif
-
 module_init(z90crypt_init_module);
 module_exit(z90crypt_cleanup_module);
index 24c0af49c25c8f416615b4a009af21e6045b5043..3092473991a7f7a934a7e242bd432de79c110b24 100644 (file)
@@ -2,9 +2,9 @@
  *  drivers/s390/net/claw.c
  *    ESCON CLAW network driver
  *
- *    $Revision: 1.35 $ $Date: 2005/03/24 12:25:38 $
+ *    $Revision: 1.38 $ $Date: 2005/08/29 09:47:04 $
  *
- *  Linux fo zSeries version
+ *  Linux for zSeries version
  *    Copyright (C) 2002,2005 IBM Corporation
  *  Author(s) Original code written by:
  *              Kazuo Iimura (iimura@jp.ibm.com)
@@ -431,12 +431,12 @@ claw_pack_skb(struct claw_privbk *privptr)
        if (!skb_queue_empty(&p_ch->collect_queue)) {
        /* some data */
                held_skb = skb_dequeue(&p_ch->collect_queue);
-               if (p_env->packing != DO_PACKED)
-                       return held_skb;
                if (held_skb)
-                       atomic_dec(&held_skb->users);
+                       dev_kfree_skb_any(held_skb);
                else
                        return NULL;
+               if (p_env->packing != DO_PACKED)
+                       return held_skb;
                /* get a new SKB we will pack at least one */
                new_skb = dev_alloc_skb(p_env->write_size);
                if (new_skb == NULL) {
@@ -455,7 +455,7 @@ claw_pack_skb(struct claw_privbk *privptr)
                                privptr->stats.tx_packets++;
                                so_far += held_skb->len;
                                pkt_cnt++;
-                               dev_kfree_skb_irq(held_skb);
+                               dev_kfree_skb_any(held_skb);
                                held_skb = skb_dequeue(&p_ch->collect_queue);
                                if (held_skb)
                                        atomic_dec(&held_skb->users);
@@ -1092,7 +1092,7 @@ claw_release(struct net_device *dev)
                 }
         }
        if (privptr->pk_skb != NULL) {
-               dev_kfree_skb(privptr->pk_skb);
+               dev_kfree_skb_any(privptr->pk_skb);
                privptr->pk_skb = NULL;
        }
        if(privptr->buffs_alloc != 1) {
@@ -2016,7 +2016,7 @@ claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid)
         p_buf=(struct ccwbk*)privptr->p_end_ccw;
         dumpit((char *)p_buf, sizeof(struct endccw));
 #endif
-        dev_kfree_skb(skb);
+        dev_kfree_skb_any(skb);
        if (linkid==0) {
                lock=LOCK_NO;
         }
@@ -4061,7 +4061,7 @@ claw_purge_skb_queue(struct sk_buff_head *q)
 
         while ((skb = skb_dequeue(q))) {
                 atomic_dec(&skb->users);
-                dev_kfree_skb_irq(skb);
+                dev_kfree_skb_any(skb);
         }
 }
 
@@ -4410,7 +4410,7 @@ claw_init(void)
 #else
                 "compiled into kernel "
 #endif
-                " $Revision: 1.35 $ $Date: 2005/03/24 12:25:38 $ \n");
+                " $Revision: 1.38 $ $Date: 2005/08/29 09:47:04 $ \n");
 
 
 #ifdef FUNCTRACE
index 5bb255e02acc653f9f93b0ba1e0bcc4392aa83d1..4191fd9d4d11b564ae6e92e862b5623c7d55d77d 100644 (file)
@@ -240,7 +240,7 @@ s390_revalidate_registers(struct mci *mci)
                         * Floating point control register can't be restored.
                         * Task will be terminated.
                         */
-                       asm volatile ("lfpc 0(%0)" : : "a" (&zero));
+                       asm volatile ("lfpc 0(%0)" : : "a" (&zero), "m" (zero));
                        kill_task = 1;
 
                }
index 6fed4a532ca3f6f097824f093f3e0e4c3c3e3874..bfe3ba73bc0f65310f58caa67e2b46412992d0c1 100644 (file)
@@ -1403,15 +1403,14 @@ zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status,
 void
 zfcp_port_dequeue(struct zfcp_port *port)
 {
-       struct fc_port *rport;
-
        zfcp_port_wait(port);
        write_lock_irq(&zfcp_data.config_lock);
        list_del(&port->list);
        port->adapter->ports--;
        write_unlock_irq(&zfcp_data.config_lock);
        if (port->rport)
-               fc_remote_port_delete(rport);
+               fc_remote_port_delete(port->rport);
+       port->rport = NULL;
        zfcp_adapter_put(port->adapter);
        zfcp_sysfs_port_remove_files(&port->sysfs_device,
                                     atomic_read(&port->status));
index 3c65aedaa97fab645645d5f85be2c821160d16ae..b30abab77da39841b8c0db3f37545fd3ae540b07 100644 (file)
@@ -203,7 +203,7 @@ zfcp_ccw_set_offline(struct ccw_device *ccw_device)
 {
        struct zfcp_adapter *adapter;
        struct zfcp_port *port;
-       struct fc_port *rport;
+       struct fc_rport *rport;
 
        down(&zfcp_data.config_sema);
        adapter = dev_get_drvdata(&ccw_device->dev);
index 7a84c7d474d961e25985a9cfefa8417ad0e7d6f1..c55e82d91deb103133047d823ce3b122de097271 100644 (file)
@@ -67,7 +67,6 @@ static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_port_##_name##_show, NULL);
 ZFCP_DEFINE_PORT_ATTR(status, "0x%08x\n", atomic_read(&port->status));
 ZFCP_DEFINE_PORT_ATTR(wwnn, "0x%016llx\n", port->wwnn);
 ZFCP_DEFINE_PORT_ATTR(d_id, "0x%06x\n", port->d_id);
-ZFCP_DEFINE_PORT_ATTR(scsi_id, "0x%x\n", port->scsi_id);
 ZFCP_DEFINE_PORT_ATTR(in_recovery, "%d\n", atomic_test_mask
                      (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status));
 ZFCP_DEFINE_PORT_ATTR(access_denied, "%d\n", atomic_test_mask
@@ -263,7 +262,6 @@ static struct attribute_group zfcp_port_common_attr_group = {
 static struct attribute *zfcp_port_no_ns_attrs[] = {
        &dev_attr_unit_add.attr,
        &dev_attr_unit_remove.attr,
-       &dev_attr_scsi_id.attr,
        NULL
 };
 
index a41778a490d600e9de43829e927430c9ea849f7b..3a8152906bf64edb7f343282269d6ead81614e18 100644 (file)
@@ -69,11 +69,40 @@ config SUN_JSFLASH
          If you say Y here, you will be able to boot from your JavaStation's
          Flash memory.
 
-# XXX Why don't we do "source drivers/char/Config.in" somewhere?
-# no shit
-config RTC
-       tristate "PC-style Real Time Clock Support"
-       depends on PCI && EXPERIMENTAL && SPARC32
+config BBC_I2C
+       tristate "UltraSPARC-III bootbus i2c controller driver"
+       depends on PCI && SPARC64
+       help
+         The BBC devices on the UltraSPARC III have two I2C controllers.  The
+         first I2C controller connects mainly to configuration PROMs (NVRAM,
+         CPU configuration, DIMM types, etc.).  The second I2C controller
+         connects to environmental control devices such as fans and
+         temperature sensors.  The second controller also connects to the
+         smartcard reader, if present.  Say Y to enable support for these.
+
+config ENVCTRL
+       tristate "SUNW, envctrl support"
+       depends on PCI && SPARC64
+       help
+         Kernel support for temperature and fan monitoring on Sun SME
+         machines.
+
+         To compile this driver as a module, choose M here: the
+         module will be called envctrl.
+
+config DISPLAY7SEG
+       tristate "7-Segment Display support"
+       depends on PCI && SPARC64
+       ---help---
+         This is the driver for the 7-segment display and LED present on
+         Sun Microsystems CompactPCI models CP1400 and CP1500.
+
+         To compile this driver as a module, choose M here: the
+         module will be called display7seg.
+
+         If you do not have a CompactPCI model CP1400 or CP1500, or
+         another UltraSPARC-IIi-cEngine boardset with a 7-segment display,
+         you should say N to this option.
 
 endmenu
 
index b3ae796eb62485faa023ded387b67a8efc4d57b9..2d21265e650b2abc0d79bd1f2c50ef212d9b977b 100644 (file)
@@ -256,7 +256,7 @@ config SCSI_DECNCR
 
 config SCSI_DECSII
        tristate "DEC SII Scsi Driver"
-       depends on MACH_DECSTATION && SCSI && MIPS32
+       depends on MACH_DECSTATION && SCSI && 32BIT
 
 config BLK_DEV_3W_XXXX_RAID
        tristate "3ware 5/6/7/8xxx ATA-RAID support"
@@ -465,6 +465,15 @@ config SCSI_ATA_PIIX
 
          If unsure, say N.
 
+config SCSI_SATA_MV
+       tristate "Marvell SATA support"
+       depends on SCSI_SATA && PCI && EXPERIMENTAL
+       help
+         This option enables support for the Marvell Serial ATA family.
+         Currently supports 88SX[56]0[48][01] chips.
+
+         If unsure, say N.
+
 config SCSI_SATA_NV
        tristate "NVIDIA SATA support"
        depends on SCSI_SATA && PCI && EXPERIMENTAL
index 85f9e6bb34b9b71fefed5abf36e2701ba6b70443..4b4fd94c2674cf6f3ac0b6c727ef2cd52f3d7be1 100644 (file)
@@ -134,6 +134,7 @@ obj-$(CONFIG_SCSI_SATA_SIS) += libata.o sata_sis.o
 obj-$(CONFIG_SCSI_SATA_SX4)    += libata.o sata_sx4.o
 obj-$(CONFIG_SCSI_SATA_NV)     += libata.o sata_nv.o
 obj-$(CONFIG_SCSI_SATA_ULI)    += libata.o sata_uli.o
+obj-$(CONFIG_SCSI_SATA_MV)     += libata.o sata_mv.o
 
 obj-$(CONFIG_ARM)              += arm/
 
index f8ec6fe7d85855a03457b0dabb80104f9f7d838f..d40ba0bd68a3b776699f62ff56e9b9ba89059950 100644 (file)
  */
 #include <scsi/scsi_dbg.h>
 
+#ifndef NDEBUG
+#define NDEBUG 0
+#endif
+#ifndef NDEBUG
+#define NDEBUG_ABORT 0
+#endif
+
 #if (NDEBUG & NDEBUG_LISTS)
 #define LIST(x,y) {printk("LINE:%d   Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); if ((x)==(y)) udelay(5); }
 #define REMOVE(w,x,y,z) {printk("LINE:%d   Removing: %p->%p  %p->%p \n", __LINE__, (void*)(w), (void*)(x), (void*)(y), (void*)(z)); if ((x)==(y)) udelay(5); }
@@ -359,7 +366,7 @@ static struct {
        {PHASE_UNKNOWN, "UNKNOWN"}
 };
 
-#ifdef NDEBUG
+#if NDEBUG
 static struct {
        unsigned char mask;
        const char *name;
index 79ae73b2368029bb3fe35f3ce8ff0a5a3e0b93b0..e1f2246ee7cda1ca97360e913b9982b599f496a3 100644 (file)
@@ -62,7 +62,7 @@
 
 #define SYNC_MODE 0            /* Synchronous transfer mode */
 
-#if DEBUG
+#ifdef DEBUG
 #undef NCR53C406A_DEBUG
 #define NCR53C406A_DEBUG 1
 #endif
index e3b9692b9688063e28e098617fed3980645a3f9b..320df6cd3defd6195ffd3eb759ac11906b377586 100644 (file)
@@ -1,26 +1,34 @@
 /*
  *  ahci.c - AHCI SATA support
  *
- *  Copyright 2004 Red Hat, Inc.
+ *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
+ *                 Please ALWAYS copy linux-ide@vger.kernel.org
+ *                 on emails.
  *
- *  The contents of this file are subject to the Open
- *  Software License version 1.1 that can be found at
- *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
- *  by reference.
+ *  Copyright 2004-2005 Red Hat, Inc.
  *
- *  Alternatively, the contents of this file may be used under the terms
- *  of the GNU General Public License version 2 (the "GPL") as distributed
- *  in the kernel source COPYING file, in which case the provisions of
- *  the GPL are applicable instead of the above.  If you wish to allow
- *  the use of your version of this file only under the terms of the
- *  GPL and not to allow others to use your version of this file under
- *  the OSL, indicate your decision by deleting the provisions above and
- *  replace them with the notice and other provisions required by the GPL.
- *  If you do not delete the provisions above, a recipient may use your
- *  version of this file under either the OSL or the GPL.
  *
- * Version 1.0 of the AHCI specification:
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * AHCI hardware documentation:
  * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
+ * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
  *
  */
 
@@ -181,7 +189,6 @@ static void ahci_irq_clear(struct ata_port *ap);
 static void ahci_eng_timeout(struct ata_port *ap);
 static int ahci_port_start(struct ata_port *ap);
 static void ahci_port_stop(struct ata_port *ap);
-static void ahci_host_stop(struct ata_host_set *host_set);
 static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 static void ahci_qc_prep(struct ata_queued_cmd *qc);
 static u8 ahci_check_status(struct ata_port *ap);
@@ -234,7 +241,6 @@ static struct ata_port_operations ahci_ops = {
 
        .port_start             = ahci_port_start,
        .port_stop              = ahci_port_stop,
-       .host_stop              = ahci_host_stop,
 };
 
 static struct ata_port_info ahci_port_info[] = {
@@ -244,7 +250,7 @@ static struct ata_port_info ahci_port_info[] = {
                .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
                                  ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
                                  ATA_FLAG_PIO_DMA,
-               .pio_mask       = 0x03, /* pio3-4 */
+               .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
                .port_ops       = &ahci_ops,
        },
@@ -269,6 +275,8 @@ static struct pci_device_id ahci_pci_tbl[] = {
          board_ahci }, /* ESB2 */
        { PCI_VENDOR_ID_INTEL, 0x2683, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
          board_ahci }, /* ESB2 */
+       { PCI_VENDOR_ID_INTEL, 0x27c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_ahci }, /* ICH7-M DH */
        { }     /* terminate list */
 };
 
@@ -286,17 +294,9 @@ static inline unsigned long ahci_port_base_ul (unsigned long base, unsigned int
        return base + 0x100 + (port * 0x80);
 }
 
-static inline void *ahci_port_base (void *base, unsigned int port)
+static inline void __iomem *ahci_port_base (void __iomem *base, unsigned int port)
 {
-       return (void *) ahci_port_base_ul((unsigned long)base, port);
-}
-
-static void ahci_host_stop(struct ata_host_set *host_set)
-{
-       struct ahci_host_priv *hpriv = host_set->private_data;
-       kfree(hpriv);
-
-       ata_host_stop(host_set);
+       return (void __iomem *) ahci_port_base_ul((unsigned long)base, port);
 }
 
 static int ahci_port_start(struct ata_port *ap)
@@ -304,8 +304,9 @@ static int ahci_port_start(struct ata_port *ap)
        struct device *dev = ap->host_set->dev;
        struct ahci_host_priv *hpriv = ap->host_set->private_data;
        struct ahci_port_priv *pp;
-       void *mem, *mmio = ap->host_set->mmio_base;
-       void *port_mmio = ahci_port_base(mmio, ap->port_no);
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       void *mem;
        dma_addr_t mem_dma;
 
        pp = kmalloc(sizeof(*pp), GFP_KERNEL);
@@ -373,8 +374,8 @@ static void ahci_port_stop(struct ata_port *ap)
 {
        struct device *dev = ap->host_set->dev;
        struct ahci_port_priv *pp = ap->private_data;
-       void *mmio = ap->host_set->mmio_base;
-       void *port_mmio = ahci_port_base(mmio, ap->port_no);
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        u32 tmp;
 
        tmp = readl(port_mmio + PORT_CMD);
@@ -536,8 +537,8 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
 
 static void ahci_intr_error(struct ata_port *ap, u32 irq_stat)
 {
-       void *mmio = ap->host_set->mmio_base;
-       void *port_mmio = ahci_port_base(mmio, ap->port_no);
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        u32 tmp;
        int work;
 
@@ -584,12 +585,16 @@ static void ahci_intr_error(struct ata_port *ap, u32 irq_stat)
 
 static void ahci_eng_timeout(struct ata_port *ap)
 {
-       void *mmio = ap->host_set->mmio_base;
-       void *port_mmio = ahci_port_base(mmio, ap->port_no);
+       struct ata_host_set *host_set = ap->host_set;
+       void __iomem *mmio = host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        struct ata_queued_cmd *qc;
+       unsigned long flags;
 
        DPRINTK("ENTER\n");
 
+       spin_lock_irqsave(&host_set->lock, flags);
+
        ahci_intr_error(ap, readl(port_mmio + PORT_IRQ_STAT));
 
        qc = ata_qc_from_tag(ap, ap->active_tag);
@@ -607,12 +612,13 @@ static void ahci_eng_timeout(struct ata_port *ap)
                ata_qc_complete(qc, ATA_ERR);
        }
 
+       spin_unlock_irqrestore(&host_set->lock, flags);
 }
 
 static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
 {
-       void *mmio = ap->host_set->mmio_base;
-       void *port_mmio = ahci_port_base(mmio, ap->port_no);
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        u32 status, serr, ci;
 
        serr = readl(port_mmio + PORT_SCR_ERR);
@@ -648,7 +654,7 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *
        struct ata_host_set *host_set = dev_instance;
        struct ahci_host_priv *hpriv;
        unsigned int i, handled = 0;
-       void *mmio;
+       void __iomem *mmio;
        u32 irq_stat, irq_ack = 0;
 
        VPRINTK("ENTER\n");
@@ -694,10 +700,7 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *
 static int ahci_qc_issue(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
-       void *port_mmio = (void *) ap->ioaddr.cmd_addr;
-
-       writel(1, port_mmio + PORT_SCR_ACT);
-       readl(port_mmio + PORT_SCR_ACT);        /* flush */
+       void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
 
        writel(1, port_mmio + PORT_CMD_ISSUE);
        readl(port_mmio + PORT_CMD_ISSUE);      /* flush */
@@ -882,7 +885,7 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent)
 {
        struct ahci_host_priv *hpriv = probe_ent->private_data;
        struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
-       void *mmio = probe_ent->mmio_base;
+       void __iomem *mmio = probe_ent->mmio_base;
        u32 vers, cap, impl, speed;
        const char *speed_s;
        u16 cc;
@@ -955,7 +958,7 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        struct ata_probe_ent *probe_ent = NULL;
        struct ahci_host_priv *hpriv;
        unsigned long base;
-       void *mmio_base;
+       void __iomem *mmio_base;
        unsigned int board_idx = (unsigned int) ent->driver_data;
        int have_msi, pci_dev_busy = 0;
        int rc;
@@ -992,8 +995,7 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        probe_ent->dev = pci_dev_to_dev(pdev);
        INIT_LIST_HEAD(&probe_ent->node);
 
-       mmio_base = ioremap(pci_resource_start(pdev, AHCI_PCI_BAR),
-                           pci_resource_len(pdev, AHCI_PCI_BAR));
+       mmio_base = pci_iomap(pdev, AHCI_PCI_BAR, 0);
        if (mmio_base == NULL) {
                rc = -ENOMEM;
                goto err_out_free_ent;
@@ -1037,7 +1039,7 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 err_out_hpriv:
        kfree(hpriv);
 err_out_iounmap:
-       iounmap(mmio_base);
+       pci_iounmap(pdev, mmio_base);
 err_out_free_ent:
        kfree(probe_ent);
 err_out_msi:
@@ -1077,7 +1079,8 @@ static void ahci_remove_one (struct pci_dev *pdev)
                scsi_host_put(ap->host);
        }
 
-       host_set->ops->host_stop(host_set);
+       kfree(hpriv);
+       pci_iounmap(pdev, host_set->mmio_base);
        kfree(host_set);
 
        if (have_msi)
@@ -1094,7 +1097,6 @@ static int __init ahci_init(void)
        return pci_module_init(&ahci_pci_driver);
 }
 
-
 static void __exit ahci_exit(void)
 {
        pci_unregister_driver(&ahci_pci_driver);
index d96ebf9d22280944dccefbb78e2e60f2029694d6..deec0cef88d92bcb007c9b28c514948b3c700758 100644 (file)
@@ -1,24 +1,42 @@
 /*
-
-    ata_piix.c - Intel PATA/SATA controllers
-
-    Maintained by:  Jeff Garzik <jgarzik@pobox.com>
-                   Please ALWAYS copy linux-ide@vger.kernel.org
-                   on emails.
-
-
-       Copyright 2003-2004 Red Hat Inc
-       Copyright 2003-2004 Jeff Garzik
-
-
-       Copyright header from piix.c:
-
-    Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
-    Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
-    Copyright (C) 2003 Red Hat Inc <alan@redhat.com>
-
-    May be copied or modified under the terms of the GNU General Public License
-
+ *    ata_piix.c - Intel PATA/SATA controllers
+ *
+ *    Maintained by:  Jeff Garzik <jgarzik@pobox.com>
+ *                 Please ALWAYS copy linux-ide@vger.kernel.org
+ *                 on emails.
+ *
+ *
+ *     Copyright 2003-2005 Red Hat Inc
+ *     Copyright 2003-2005 Jeff Garzik
+ *
+ *
+ *     Copyright header from piix.c:
+ *
+ *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
+ *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2003 Red Hat Inc <alan@redhat.com>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
+ *  Hardware documentation available at http://developer.intel.com/
+ *
  */
 
 #include <linux/kernel.h>
@@ -565,8 +583,7 @@ static void pci_enable_intx(struct pci_dev *pdev)
 #define AHCI_ENABLE (1 << 31)
 static int piix_disable_ahci(struct pci_dev *pdev)
 {
-       void *mmio;
-       unsigned long addr;
+       void __iomem *mmio;
        u32 tmp;
        int rc = 0;
 
@@ -574,11 +591,11 @@ static int piix_disable_ahci(struct pci_dev *pdev)
         * works because this device is usually set up by BIOS.
         */
 
-       addr = pci_resource_start(pdev, AHCI_PCI_BAR);
-       if (!addr || !pci_resource_len(pdev, AHCI_PCI_BAR))
+       if (!pci_resource_start(pdev, AHCI_PCI_BAR) ||
+           !pci_resource_len(pdev, AHCI_PCI_BAR))
                return 0;
 
-       mmio = ioremap(addr, 64);
+       mmio = pci_iomap(pdev, AHCI_PCI_BAR, 64);
        if (!mmio)
                return -ENOMEM;
 
@@ -592,7 +609,7 @@ static int piix_disable_ahci(struct pci_dev *pdev)
                        rc = -EIO;
        }
 
-       iounmap(mmio);
+       pci_iounmap(pdev, mmio);
        return rc;
 }
 
@@ -629,13 +646,13 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        port_info[1] = NULL;
 
        if (port_info[0]->host_flags & PIIX_FLAG_AHCI) {
-               u8 tmp;
-               pci_read_config_byte(pdev, PIIX_SCC, &tmp);
-               if (tmp == PIIX_AHCI_DEVICE) {
-                       int rc = piix_disable_ahci(pdev);
-                       if (rc)
-                           return rc;
-               }
+               u8 tmp;
+               pci_read_config_byte(pdev, PIIX_SCC, &tmp);
+               if (tmp == PIIX_AHCI_DEVICE) {
+                       int rc = piix_disable_ahci(pdev);
+                       if (rc)
+                               return rc;
+               }
        }
 
        if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) {
index 1b911dadf64bbfbc2408191e4a7c4f56b2b96580..5b14934ba861f0f119a9c48e809b0aea8340ebbc 100644 (file)
@@ -1531,7 +1531,7 @@ static int ibmvscsi_remove(struct vio_dev *vdev)
  */
 static struct vio_device_id ibmvscsi_device_table[] __devinitdata = {
        {"vscsi", "IBM,v-scsi"},
-       {0,}
+       { "", "" }
 };
 
 MODULE_DEVICE_TABLE(vio, ibmvscsi_device_table);
index 035f615817d74362bbbed9a767b9d92044ac4ebd..8bf5652f106090ab75ec922a747e11bf0d1b2ad0 100644 (file)
@@ -28,6 +28,7 @@
  */
 
 #include <asm/vio.h>
+#include <asm/prom.h>
 #include <asm/iommu.h>
 #include <asm/hvcall.h>
 #include <linux/dma-mapping.h>
index f4e7dcb6492bcdbfed7d9dced994caf44d24d38b..5cc53cd9323e5a9416fc7baf2ff22d8f233af653 100644 (file)
@@ -1,25 +1,35 @@
 /*
-   libata-core.c - helper library for ATA
-
-   Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
-   Copyright 2003-2004 Jeff Garzik
-
-   The contents of this file are subject to the Open
-   Software License version 1.1 that can be found at
-   http://www.opensource.org/licenses/osl-1.1.txt and is included herein
-   by reference.
-
-   Alternatively, the contents of this file may be used under the terms
-   of the GNU General Public License version 2 (the "GPL") as distributed
-   in the kernel source COPYING file, in which case the provisions of
-   the GPL are applicable instead of the above.  If you wish to allow
-   the use of your version of this file only under the terms of the
-   GPL and not to allow others to use your version of this file under
-   the OSL, indicate your decision by deleting the provisions above and
-   replace them with the notice and other provisions required by the GPL.
-   If you do not delete the provisions above, a recipient may use your
-   version of this file under either the OSL or the GPL.
-
+ *  libata-core.c - helper library for ATA
+ *
+ *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
+ *                 Please ALWAYS copy linux-ide@vger.kernel.org
+ *                 on emails.
+ *
+ *  Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+ *  Copyright 2003-2004 Jeff Garzik
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
+ *  Hardware documentation available from http://www.t13.org/ and
+ *  http://www.sata-io.org/
+ *
  */
 
 #include <linux/config.h>
@@ -65,6 +75,10 @@ static void __ata_qc_complete(struct ata_queued_cmd *qc);
 static unsigned int ata_unique_id = 1;
 static struct workqueue_struct *ata_wq;
 
+int atapi_enabled = 0;
+module_param(atapi_enabled, int, 0444);
+MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)");
+
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("Library module for ATA devices");
 MODULE_LICENSE("GPL");
@@ -1304,12 +1318,12 @@ static inline u8 ata_dev_knobble(struct ata_port *ap)
 /**
  *     ata_dev_config - Run device specific handlers and check for
  *                      SATA->PATA bridges
- *     @ap: Bus 
+ *     @ap: Bus
  *     @i:  Device
  *
  *     LOCKING:
  */
+
 void ata_dev_config(struct ata_port *ap, unsigned int i)
 {
        /* limit bridge transfers to udma5, 200 sectors */
@@ -2376,6 +2390,27 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
        return 0;
 }
 
+/**
+ *     ata_poll_qc_complete - turn irq back on and finish qc
+ *     @qc: Command to complete
+ *     @drv_stat: ATA status register content
+ *
+ *     LOCKING:
+ *     None.  (grabs host lock)
+ */
+
+void ata_poll_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
+{
+       struct ata_port *ap = qc->ap;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ap->host_set->lock, flags);
+       ap->flags &= ~ATA_FLAG_NOINTR;
+       ata_irq_on(ap);
+       ata_qc_complete(qc, drv_stat);
+       spin_unlock_irqrestore(&ap->host_set->lock, flags);
+}
+
 /**
  *     ata_pio_poll -
  *     @ap:
@@ -2438,11 +2473,10 @@ static void ata_pio_complete (struct ata_port *ap)
        u8 drv_stat;
 
        /*
-        * This is purely hueristic.  This is a fast path.
-        * Sometimes when we enter, BSY will be cleared in
-        * a chk-status or two.  If not, the drive is probably seeking
-        * or something.  Snooze for a couple msecs, then
-        * chk-status again.  If still busy, fall back to
+        * This is purely heuristic.  This is a fast path.  Sometimes when
+        * we enter, BSY will be cleared in a chk-status or two.  If not,
+        * the drive is probably seeking or something.  Snooze for a couple
+        * msecs, then chk-status again.  If still busy, fall back to
         * PIO_ST_POLL state.
         */
        drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
@@ -2467,9 +2501,7 @@ static void ata_pio_complete (struct ata_port *ap)
 
        ap->pio_task_state = PIO_ST_IDLE;
 
-       ata_irq_on(ap);
-
-       ata_qc_complete(qc, drv_stat);
+       ata_poll_qc_complete(qc, drv_stat);
 }
 
 
@@ -2494,6 +2526,20 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
 #endif /* __BIG_ENDIAN */
 }
 
+/**
+ *     ata_mmio_data_xfer - Transfer data by MMIO
+ *     @ap: port to read/write
+ *     @buf: data buffer
+ *     @buflen: buffer length
+ *     @write_data: read/write
+ *
+ *     Transfer data from/to the device data register by MMIO.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ *
+ */
+
 static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf,
                               unsigned int buflen, int write_data)
 {
@@ -2502,6 +2548,7 @@ static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf,
        u16 *buf16 = (u16 *) buf;
        void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr;
 
+       /* Transfer multiple of 2 bytes */
        if (write_data) {
                for (i = 0; i < words; i++)
                        writew(le16_to_cpu(buf16[i]), mmio);
@@ -2509,19 +2556,76 @@ static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf,
                for (i = 0; i < words; i++)
                        buf16[i] = cpu_to_le16(readw(mmio));
        }
+
+       /* Transfer trailing 1 byte, if any. */
+       if (unlikely(buflen & 0x01)) {
+               u16 align_buf[1] = { 0 };
+               unsigned char *trailing_buf = buf + buflen - 1;
+
+               if (write_data) {
+                       memcpy(align_buf, trailing_buf, 1);
+                       writew(le16_to_cpu(align_buf[0]), mmio);
+               } else {
+                       align_buf[0] = cpu_to_le16(readw(mmio));
+                       memcpy(trailing_buf, align_buf, 1);
+               }
+       }
 }
 
+/**
+ *     ata_pio_data_xfer - Transfer data by PIO
+ *     @ap: port to read/write
+ *     @buf: data buffer
+ *     @buflen: buffer length
+ *     @write_data: read/write
+ *
+ *     Transfer data from/to the device data register by PIO.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ *
+ */
+
 static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf,
                              unsigned int buflen, int write_data)
 {
-       unsigned int dwords = buflen >> 1;
+       unsigned int words = buflen >> 1;
 
+       /* Transfer multiple of 2 bytes */
        if (write_data)
-               outsw(ap->ioaddr.data_addr, buf, dwords);
+               outsw(ap->ioaddr.data_addr, buf, words);
        else
-               insw(ap->ioaddr.data_addr, buf, dwords);
+               insw(ap->ioaddr.data_addr, buf, words);
+
+       /* Transfer trailing 1 byte, if any. */
+       if (unlikely(buflen & 0x01)) {
+               u16 align_buf[1] = { 0 };
+               unsigned char *trailing_buf = buf + buflen - 1;
+
+               if (write_data) {
+                       memcpy(align_buf, trailing_buf, 1);
+                       outw(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr);
+               } else {
+                       align_buf[0] = cpu_to_le16(inw(ap->ioaddr.data_addr));
+                       memcpy(trailing_buf, align_buf, 1);
+               }
+       }
 }
 
+/**
+ *     ata_data_xfer - Transfer data from/to the data register.
+ *     @ap: port to read/write
+ *     @buf: data buffer
+ *     @buflen: buffer length
+ *     @do_write: read/write
+ *
+ *     Transfer data from/to the device data register.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ *
+ */
+
 static void ata_data_xfer(struct ata_port *ap, unsigned char *buf,
                          unsigned int buflen, int do_write)
 {
@@ -2531,6 +2635,16 @@ static void ata_data_xfer(struct ata_port *ap, unsigned char *buf,
                ata_pio_data_xfer(ap, buf, buflen, do_write);
 }
 
+/**
+ *     ata_pio_sector - Transfer ATA_SECT_SIZE (512 bytes) of data.
+ *     @qc: Command on going
+ *
+ *     Transfer ATA_SECT_SIZE of data from/to the ATA device.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
 static void ata_pio_sector(struct ata_queued_cmd *qc)
 {
        int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
@@ -2569,6 +2683,18 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
        kunmap(page);
 }
 
+/**
+ *     __atapi_pio_bytes - Transfer data from/to the ATAPI device.
+ *     @qc: Command on going
+ *     @bytes: number of bytes
+ *
+ *     Transfer Transfer data from/to the ATAPI device.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ *
+ */
+
 static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes)
 {
        int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
@@ -2578,10 +2704,33 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes)
        unsigned char *buf;
        unsigned int offset, count;
 
-       if (qc->curbytes == qc->nbytes - bytes)
+       if (qc->curbytes + bytes >= qc->nbytes)
                ap->pio_task_state = PIO_ST_LAST;
 
 next_sg:
+       if (unlikely(qc->cursg >= qc->n_elem)) {
+               /* 
+                * The end of qc->sg is reached and the device expects
+                * more data to transfer. In order not to overrun qc->sg
+                * and fulfill length specified in the byte count register,
+                *    - for read case, discard trailing data from the device
+                *    - for write case, padding zero data to the device
+                */
+               u16 pad_buf[1] = { 0 };
+               unsigned int words = bytes >> 1;
+               unsigned int i;
+
+               if (words) /* warning if bytes > 1 */
+                       printk(KERN_WARNING "ata%u: %u bytes trailing data\n", 
+                              ap->id, bytes);
+
+               for (i = 0; i < words; i++)
+                       ata_data_xfer(ap, (unsigned char*)pad_buf, 2, do_write);
+
+               ap->pio_task_state = PIO_ST_LAST;
+               return;
+       }
+
        sg = &qc->sg[qc->cursg];
 
        page = sg->page;
@@ -2615,11 +2764,21 @@ next_sg:
 
        kunmap(page);
 
-       if (bytes) {
+       if (bytes)
                goto next_sg;
-       }
 }
 
+/**
+ *     atapi_pio_bytes - Transfer data from/to the ATAPI device.
+ *     @qc: Command on going
+ *
+ *     Transfer Transfer data from/to the ATAPI device.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ *
+ */
+
 static void atapi_pio_bytes(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
@@ -2692,9 +2851,7 @@ static void ata_pio_block(struct ata_port *ap)
                if ((status & ATA_DRQ) == 0) {
                        ap->pio_task_state = PIO_ST_IDLE;
 
-                       ata_irq_on(ap);
-
-                       ata_qc_complete(qc, status);
+                       ata_poll_qc_complete(qc, status);
                        return;
                }
 
@@ -2724,9 +2881,7 @@ static void ata_pio_error(struct ata_port *ap)
 
        ap->pio_task_state = PIO_ST_IDLE;
 
-       ata_irq_on(ap);
-
-       ata_qc_complete(qc, drv_stat | ATA_ERR);
+       ata_poll_qc_complete(qc, drv_stat | ATA_ERR);
 }
 
 static void ata_pio_task(void *_data)
@@ -2832,8 +2987,10 @@ static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev,
 static void ata_qc_timeout(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
+       struct ata_host_set *host_set = ap->host_set;
        struct ata_device *dev = qc->dev;
        u8 host_stat = 0, drv_stat;
+       unsigned long flags;
 
        DPRINTK("ENTER\n");
 
@@ -2844,7 +3001,9 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
                if (!(cmd->eh_eflags & SCSI_EH_CANCEL_CMD)) {
 
                        /* finish completing original command */
+                       spin_lock_irqsave(&host_set->lock, flags);
                        __ata_qc_complete(qc);
+                       spin_unlock_irqrestore(&host_set->lock, flags);
 
                        atapi_request_sense(ap, dev, cmd);
 
@@ -2855,6 +3014,8 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
                }
        }
 
+       spin_lock_irqsave(&host_set->lock, flags);
+
        /* hack alert!  We cannot use the supplied completion
         * function from inside the ->eh_strategy_handler() thread.
         * libata is the only user of ->eh_strategy_handler() in
@@ -2870,7 +3031,7 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
                host_stat = ap->ops->bmdma_status(ap);
 
                /* before we do anything else, clear DMA-Start bit */
-               ap->ops->bmdma_stop(ap);
+               ap->ops->bmdma_stop(qc);
 
                /* fall through */
 
@@ -2888,6 +3049,9 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
                ata_qc_complete(qc, drv_stat);
                break;
        }
+
+       spin_unlock_irqrestore(&host_set->lock, flags);
+
 out:
        DPRINTK("EXIT\n");
 }
@@ -3061,9 +3225,14 @@ void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
        if (likely(qc->flags & ATA_QCFLAG_DMAMAP))
                ata_sg_clean(qc);
 
+       /* atapi: mark qc as inactive to prevent the interrupt handler
+        * from completing the command twice later, before the error handler
+        * is called. (when rc != 0 and atapi request sense is needed)
+        */
+       qc->flags &= ~ATA_QCFLAG_ACTIVE;
+
        /* call completion callback */
        rc = qc->complete_fn(qc, drv_stat);
-       qc->flags &= ~ATA_QCFLAG_ACTIVE;
 
        /* if callback indicates not to complete command (non-zero),
         * return immediately
@@ -3193,11 +3362,13 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc)
                break;
 
        case ATA_PROT_ATAPI_NODATA:
+               ap->flags |= ATA_FLAG_NOINTR;
                ata_tf_to_host_nolock(ap, &qc->tf);
                queue_work(ata_wq, &ap->packet_task);
                break;
 
        case ATA_PROT_ATAPI_DMA:
+               ap->flags |= ATA_FLAG_NOINTR;
                ap->ops->tf_load(ap, &qc->tf);   /* load tf registers */
                ap->ops->bmdma_setup(qc);           /* set up bmdma */
                queue_work(ata_wq, &ap->packet_task);
@@ -3242,7 +3413,7 @@ static void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc)
 }
 
 /**
- *     ata_bmdma_start - Start a PCI IDE BMDMA transaction
+ *     ata_bmdma_start_mmio - Start a PCI IDE BMDMA transaction
  *     @qc: Info associated with this ATA transaction.
  *
  *     LOCKING:
@@ -3413,7 +3584,7 @@ u8 ata_bmdma_status(struct ata_port *ap)
 
 /**
  *     ata_bmdma_stop - Stop PCI IDE BMDMA transfer
- *     @ap: Port associated with this ATA transaction.
+ *     @qc: Command we are ending DMA for
  *
  *     Clears the ATA_DMA_START flag in the dma control register
  *
@@ -3423,8 +3594,9 @@ u8 ata_bmdma_status(struct ata_port *ap)
  *     spin_lock_irqsave(host_set lock)
  */
 
-void ata_bmdma_stop(struct ata_port *ap)
+void ata_bmdma_stop(struct ata_queued_cmd *qc)
 {
+       struct ata_port *ap = qc->ap;
        if (ap->flags & ATA_FLAG_MMIO) {
                void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
 
@@ -3476,7 +3648,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap,
                        goto idle_irq;
 
                /* before we do anything else, clear DMA-Start bit */
-               ap->ops->bmdma_stop(ap);
+               ap->ops->bmdma_stop(qc);
 
                /* fall through */
 
@@ -3551,7 +3723,8 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
                struct ata_port *ap;
 
                ap = host_set->ports[i];
-               if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+               if (ap &&
+                   !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
                        struct ata_queued_cmd *qc;
 
                        qc = ata_qc_from_tag(ap, ap->active_tag);
@@ -3603,19 +3776,27 @@ static void atapi_packet_task(void *_data)
        /* send SCSI cdb */
        DPRINTK("send cdb\n");
        assert(ap->cdb_len >= 12);
-       ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
 
-       /* if we are DMA'ing, irq handler takes over from here */
-       if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
-               ap->ops->bmdma_start(qc);           /* initiate bmdma */
+       if (qc->tf.protocol == ATA_PROT_ATAPI_DMA ||
+           qc->tf.protocol == ATA_PROT_ATAPI_NODATA) {
+               unsigned long flags;
 
-       /* non-data commands are also handled via irq */
-       else if (qc->tf.protocol == ATA_PROT_ATAPI_NODATA) {
-               /* do nothing */
-       }
+               /* Once we're done issuing command and kicking bmdma,
+                * irq handler takes over.  To not lose irq, we need
+                * to clear NOINTR flag before sending cdb, but
+                * interrupt handler shouldn't be invoked before we're
+                * finished.  Hence, the following locking.
+                */
+               spin_lock_irqsave(&ap->host_set->lock, flags);
+               ap->flags &= ~ATA_FLAG_NOINTR;
+               ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
+               if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
+                       ap->ops->bmdma_start(qc);       /* initiate bmdma */
+               spin_unlock_irqrestore(&ap->host_set->lock, flags);
+       } else {
+               ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
 
-       /* PIO commands are handled by polling */
-       else {
+               /* PIO commands are handled by polling */
                ap->pio_task_state = PIO_ST;
                queue_work(ata_wq, &ap->pio_task);
        }
@@ -3623,7 +3804,7 @@ static void atapi_packet_task(void *_data)
        return;
 
 err_out:
-       ata_qc_complete(qc, ATA_ERR);
+       ata_poll_qc_complete(qc, ATA_ERR);
 }
 
 
@@ -4023,6 +4204,15 @@ ata_probe_ent_alloc(struct device *dev, struct ata_port_info *port)
 
 
 
+#ifdef CONFIG_PCI
+
+void ata_pci_host_stop (struct ata_host_set *host_set)
+{
+       struct pci_dev *pdev = to_pci_dev(host_set->dev);
+
+       pci_iounmap(pdev, host_set->mmio_base);
+}
+
 /**
  *     ata_pci_init_native_mode - Initialize native-mode driver
  *     @pdev:  pci device to be initialized
@@ -4035,7 +4225,6 @@ ata_probe_ent_alloc(struct device *dev, struct ata_port_info *port)
  *     ata_probe_ent structure should then be freed with kfree().
  */
 
-#ifdef CONFIG_PCI
 struct ata_probe_ent *
 ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port)
 {
@@ -4418,6 +4607,7 @@ EXPORT_SYMBOL_GPL(ata_scsi_simulate);
 
 #ifdef CONFIG_PCI
 EXPORT_SYMBOL_GPL(pci_test_config_bits);
+EXPORT_SYMBOL_GPL(ata_pci_host_stop);
 EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
 EXPORT_SYMBOL_GPL(ata_pci_init_one);
 EXPORT_SYMBOL_GPL(ata_pci_remove_one);
index 6a75ec2187fde5451b1ae77443ecc8aceb96e319..104fd9a63e734ddc752f68de92215a208242a0d1 100644 (file)
@@ -1,25 +1,36 @@
 /*
-   libata-scsi.c - helper library for ATA
-
-   Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
-   Copyright 2003-2004 Jeff Garzik
-
-   The contents of this file are subject to the Open
-   Software License version 1.1 that can be found at
-   http://www.opensource.org/licenses/osl-1.1.txt and is included herein
-   by reference.
-
-   Alternatively, the contents of this file may be used under the terms
-   of the GNU General Public License version 2 (the "GPL") as distributed
-   in the kernel source COPYING file, in which case the provisions of
-   the GPL are applicable instead of the above.  If you wish to allow
-   the use of your version of this file only under the terms of the
-   GPL and not to allow others to use your version of this file under
-   the OSL, indicate your decision by deleting the provisions above and
-   replace them with the notice and other provisions required by the GPL.
-   If you do not delete the provisions above, a recipient may use your
-   version of this file under either the OSL or the GPL.
-
+ *  libata-scsi.c - helper library for ATA
+ *
+ *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
+ *                 Please ALWAYS copy linux-ide@vger.kernel.org
+ *                 on emails.
+ *
+ *  Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+ *  Copyright 2003-2004 Jeff Garzik
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
+ *  Hardware documentation available from
+ *  - http://www.t10.org/
+ *  - http://www.t13.org/
+ *
  */
 
 #include <linux/kernel.h>
@@ -391,6 +402,60 @@ int ata_scsi_error(struct Scsi_Host *host)
        return 0;
 }
 
+/**
+ *     ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
+ *     @qc: Storage for translated ATA taskfile
+ *     @scsicmd: SCSI command to translate
+ *
+ *     Sets up an ATA taskfile to issue STANDBY (to stop) or READ VERIFY
+ *     (to start). Perhaps these commands should be preceded by
+ *     CHECK POWER MODE to see what power mode the device is already in.
+ *     [See SAT revision 5 at www.t10.org]
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ *
+ *     RETURNS:
+ *     Zero on success, non-zero on error.
+ */
+
+static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc,
+                                            u8 *scsicmd)
+{
+       struct ata_taskfile *tf = &qc->tf;
+
+       tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+       tf->protocol = ATA_PROT_NODATA;
+       if (scsicmd[1] & 0x1) {
+               ;       /* ignore IMMED bit, violates sat-r05 */
+       }
+       if (scsicmd[4] & 0x2)
+               return 1;       /* LOEJ bit set not supported */
+       if (((scsicmd[4] >> 4) & 0xf) != 0)
+               return 1;       /* power conditions not supported */
+       if (scsicmd[4] & 0x1) {
+               tf->nsect = 1;  /* 1 sector, lba=0 */
+               tf->lbah = 0x0;
+               tf->lbam = 0x0;
+               tf->lbal = 0x0;
+               tf->device |= ATA_LBA;
+               tf->command = ATA_CMD_VERIFY;   /* READ VERIFY */
+       } else {
+               tf->nsect = 0;  /* time period value (0 implies now) */
+               tf->command = ATA_CMD_STANDBY;
+               /* Consider: ATA STANDBY IMMEDIATE command */
+       }
+       /*
+        * Standby and Idle condition timers could be implemented but that
+        * would require libata to implement the Power condition mode page
+        * and allow the user to change it. Changing mode pages requires
+        * MODE SELECT to be implemented.
+        */
+
+       return 0;
+}
+
+
 /**
  *     ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command
  *     @qc: Storage for translated ATA taskfile
@@ -576,11 +641,19 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
                tf->lbah = scsicmd[3];
 
                VPRINTK("ten-byte command\n");
+               if (qc->nsect == 0) /* we don't support length==0 cmds */
+                       return 1;
                return 0;
        }
 
        if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) {
                qc->nsect = tf->nsect = scsicmd[4];
+               if (!qc->nsect) {
+                       qc->nsect = 256;
+                       if (lba48)
+                               tf->hob_nsect = 1;
+               }
+
                tf->lbal = scsicmd[3];
                tf->lbam = scsicmd[2];
                tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */
@@ -620,6 +693,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
                tf->lbah = scsicmd[7];
 
                VPRINTK("sixteen-byte command\n");
+               if (qc->nsect == 0) /* we don't support length==0 cmds */
+                       return 1;
                return 0;
        }
 
@@ -1395,10 +1470,10 @@ ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev)
        if (unlikely(!ata_dev_present(dev)))
                return NULL;
 
-#ifndef ATA_ENABLE_ATAPI
-       if (unlikely(dev->class == ATA_DEV_ATAPI))
-               return NULL;
-#endif
+       if (!atapi_enabled) {
+               if (unlikely(dev->class == ATA_DEV_ATAPI))
+                       return NULL;
+       }
 
        return dev;
 }
@@ -1435,6 +1510,8 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
        case VERIFY:
        case VERIFY_16:
                return ata_scsi_verify_xlat;
+       case START_STOP:
+               return ata_scsi_start_stop_xlat;
        }
 
        return NULL;
index 3e7f4843020f50eb58744d6dbacc1d9cb592aeb6..d608b3a0f6fe6897d108cd8f6557c8e4d53c1820 100644 (file)
@@ -1,25 +1,28 @@
 /*
-   libata.h - helper library for ATA
-
-   Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
-   Copyright 2003-2004 Jeff Garzik
-
-   The contents of this file are subject to the Open
-   Software License version 1.1 that can be found at
-   http://www.opensource.org/licenses/osl-1.1.txt and is included herein
-   by reference.
-
-   Alternatively, the contents of this file may be used under the terms
-   of the GNU General Public License version 2 (the "GPL") as distributed
-   in the kernel source COPYING file, in which case the provisions of
-   the GPL are applicable instead of the above.  If you wish to allow
-   the use of your version of this file only under the terms of the
-   GPL and not to allow others to use your version of this file under
-   the OSL, indicate your decision by deleting the provisions above and
-   replace them with the notice and other provisions required by the GPL.
-   If you do not delete the provisions above, a recipient may use your
-   version of this file under either the OSL or the GPL.
-
+ *  libata.h - helper library for ATA
+ *
+ *  Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+ *  Copyright 2003-2004 Jeff Garzik
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
  */
 
 #ifndef __LIBATA_H__
@@ -35,6 +38,7 @@ struct ata_scsi_args {
 };
 
 /* libata-core.c */
+extern int atapi_enabled;
 extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
                                      struct ata_device *dev);
 extern void ata_qc_free(struct ata_queued_cmd *qc);
@@ -72,7 +76,7 @@ extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
 extern void ata_scsi_badcmd(struct scsi_cmnd *cmd,
                            void (*done)(struct scsi_cmnd *),
                            u8 asc, u8 ascq);
-extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, 
+extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
                         unsigned int (*actor) (struct ata_scsi_args *args,
                                            u8 *rbuf, unsigned int buflen));
 
index ff1933298da682c5f1b0704cbee9c4b81f6d083a..a4857db4f9b8033f2ff16785dc94244e997489a6 100644 (file)
@@ -1766,7 +1766,7 @@ static int mesh_suspend(struct macio_dev *mdev, pm_message_t state)
        struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
        unsigned long flags;
 
-       if (state == mdev->ofdev.dev.power.power_state || state < 2)
+       if (state.event == mdev->ofdev.dev.power.power_state.event || state.event < 2)
                return 0;
 
        scsi_block_requests(ms->host);
@@ -1791,7 +1791,7 @@ static int mesh_resume(struct macio_dev *mdev)
        struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
        unsigned long flags;
 
-       if (mdev->ofdev.dev.power.power_state == 0)
+       if (mdev->ofdev.dev.power.power_state.event == PM_EVENT_ON)
                return 0;
 
        set_mesh_power(ms, 1);
@@ -1802,7 +1802,7 @@ static int mesh_resume(struct macio_dev *mdev)
        enable_irq(ms->meshintr);
        scsi_unblock_requests(ms->host);
 
-       mdev->ofdev.dev.power.power_state = 0;
+       mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON;
 
        return 0;
 }
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
new file mode 100644 (file)
index 0000000..f97e3af
--- /dev/null
@@ -0,0 +1,843 @@
+/*
+ * sata_mv.c - Marvell SATA support
+ *
+ * Copyright 2005: EMC Corporation, all rights reserved. 
+ *
+ * Please ALWAYS copy linux-ide@vger.kernel.org on emails.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/dma-mapping.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <asm/io.h>
+
+#define DRV_NAME       "sata_mv"
+#define DRV_VERSION    "0.12"
+
+enum {
+       /* BAR's are enumerated in terms of pci_resource_start() terms */
+       MV_PRIMARY_BAR          = 0,    /* offset 0x10: memory space */
+       MV_IO_BAR               = 2,    /* offset 0x18: IO space */
+       MV_MISC_BAR             = 3,    /* offset 0x1c: FLASH, NVRAM, SRAM */
+
+       MV_MAJOR_REG_AREA_SZ    = 0x10000,      /* 64KB */
+       MV_MINOR_REG_AREA_SZ    = 0x2000,       /* 8KB */
+
+       MV_PCI_REG_BASE         = 0,
+       MV_IRQ_COAL_REG_BASE    = 0x18000,      /* 6xxx part only */
+       MV_SATAHC0_REG_BASE     = 0x20000,
+
+       MV_PCI_REG_SZ           = MV_MAJOR_REG_AREA_SZ,
+       MV_SATAHC_REG_SZ        = MV_MAJOR_REG_AREA_SZ,
+       MV_SATAHC_ARBTR_REG_SZ  = MV_MINOR_REG_AREA_SZ,         /* arbiter */
+       MV_PORT_REG_SZ          = MV_MINOR_REG_AREA_SZ,
+
+       MV_Q_CT                 = 32,
+       MV_CRQB_SZ              = 32,
+       MV_CRPB_SZ              = 8,
+
+       MV_DMA_BOUNDARY         = 0xffffffffU,
+       SATAHC_MASK             = (~(MV_SATAHC_REG_SZ - 1)),
+
+       MV_PORTS_PER_HC         = 4,
+       /* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
+       MV_PORT_HC_SHIFT        = 2,
+       /* == (port % MV_PORTS_PER_HC) to determine port from 0-7 port */
+       MV_PORT_MASK            = 3,
+
+       /* Host Flags */
+       MV_FLAG_DUAL_HC         = (1 << 30),  /* two SATA Host Controllers */
+       MV_FLAG_IRQ_COALESCE    = (1 << 29),  /* IRQ coalescing capability */
+       MV_FLAG_BDMA            = (1 << 28),  /* Basic DMA */
+
+       chip_504x               = 0,
+       chip_508x               = 1,
+       chip_604x               = 2,
+       chip_608x               = 3,
+
+       /* PCI interface registers */
+
+       PCI_MAIN_CMD_STS_OFS    = 0xd30,
+       STOP_PCI_MASTER         = (1 << 2),
+       PCI_MASTER_EMPTY        = (1 << 3),
+       GLOB_SFT_RST            = (1 << 4),
+
+       PCI_IRQ_CAUSE_OFS       = 0x1d58,
+       PCI_IRQ_MASK_OFS        = 0x1d5c,
+       PCI_UNMASK_ALL_IRQS     = 0x7fffff,     /* bits 22-0 */
+
+       HC_MAIN_IRQ_CAUSE_OFS   = 0x1d60,
+       HC_MAIN_IRQ_MASK_OFS    = 0x1d64,
+       PORT0_ERR               = (1 << 0),     /* shift by port # */
+       PORT0_DONE              = (1 << 1),     /* shift by port # */
+       HC0_IRQ_PEND            = 0x1ff,        /* bits 0-8 = HC0's ports */
+       HC_SHIFT                = 9,            /* bits 9-17 = HC1's ports */
+       PCI_ERR                 = (1 << 18),
+       TRAN_LO_DONE            = (1 << 19),    /* 6xxx: IRQ coalescing */
+       TRAN_HI_DONE            = (1 << 20),    /* 6xxx: IRQ coalescing */
+       PORTS_0_7_COAL_DONE     = (1 << 21),    /* 6xxx: IRQ coalescing */
+       GPIO_INT                = (1 << 22),
+       SELF_INT                = (1 << 23),
+       TWSI_INT                = (1 << 24),
+       HC_MAIN_RSVD            = (0x7f << 25), /* bits 31-25 */
+       HC_MAIN_MASKED_IRQS     = (TRAN_LO_DONE | TRAN_HI_DONE | 
+                                  PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
+                                  HC_MAIN_RSVD),
+
+       /* SATAHC registers */
+       HC_CFG_OFS              = 0,
+
+       HC_IRQ_CAUSE_OFS        = 0x14,
+       CRBP_DMA_DONE           = (1 << 0),     /* shift by port # */
+       HC_IRQ_COAL             = (1 << 4),     /* IRQ coalescing */
+       DEV_IRQ                 = (1 << 8),     /* shift by port # */
+
+       /* Shadow block registers */
+       SHD_PIO_DATA_OFS        = 0x100,
+       SHD_FEA_ERR_OFS         = 0x104,
+       SHD_SECT_CNT_OFS        = 0x108,
+       SHD_LBA_L_OFS           = 0x10C,
+       SHD_LBA_M_OFS           = 0x110,
+       SHD_LBA_H_OFS           = 0x114,
+       SHD_DEV_HD_OFS          = 0x118,
+       SHD_CMD_STA_OFS         = 0x11C,
+       SHD_CTL_AST_OFS         = 0x120,
+
+       /* SATA registers */
+       SATA_STATUS_OFS         = 0x300,  /* ctrl, err regs follow status */
+       SATA_ACTIVE_OFS         = 0x350,
+
+       /* Port registers */
+       EDMA_CFG_OFS            = 0,
+
+       EDMA_ERR_IRQ_CAUSE_OFS  = 0x8,
+       EDMA_ERR_IRQ_MASK_OFS   = 0xc,
+       EDMA_ERR_D_PAR          = (1 << 0),
+       EDMA_ERR_PRD_PAR        = (1 << 1),
+       EDMA_ERR_DEV            = (1 << 2),
+       EDMA_ERR_DEV_DCON       = (1 << 3),
+       EDMA_ERR_DEV_CON        = (1 << 4),
+       EDMA_ERR_SERR           = (1 << 5),
+       EDMA_ERR_SELF_DIS       = (1 << 7),
+       EDMA_ERR_BIST_ASYNC     = (1 << 8),
+       EDMA_ERR_CRBQ_PAR       = (1 << 9),
+       EDMA_ERR_CRPB_PAR       = (1 << 10),
+       EDMA_ERR_INTRL_PAR      = (1 << 11),
+       EDMA_ERR_IORDY          = (1 << 12),
+       EDMA_ERR_LNK_CTRL_RX    = (0xf << 13),
+       EDMA_ERR_LNK_CTRL_RX_2  = (1 << 15),
+       EDMA_ERR_LNK_DATA_RX    = (0xf << 17),
+       EDMA_ERR_LNK_CTRL_TX    = (0x1f << 21),
+       EDMA_ERR_LNK_DATA_TX    = (0x1f << 26),
+       EDMA_ERR_TRANS_PROTO    = (1 << 31),
+       EDMA_ERR_FATAL          = (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR | 
+                                  EDMA_ERR_DEV_DCON | EDMA_ERR_CRBQ_PAR |
+                                  EDMA_ERR_CRPB_PAR | EDMA_ERR_INTRL_PAR |
+                                  EDMA_ERR_IORDY | EDMA_ERR_LNK_CTRL_RX_2 | 
+                                  EDMA_ERR_LNK_DATA_RX |
+                                  EDMA_ERR_LNK_DATA_TX | 
+                                  EDMA_ERR_TRANS_PROTO),
+
+       EDMA_CMD_OFS            = 0x28,
+       EDMA_EN                 = (1 << 0),
+       EDMA_DS                 = (1 << 1),
+       ATA_RST                 = (1 << 2),
+
+       /* BDMA is 6xxx part only */
+       BDMA_CMD_OFS            = 0x224,
+       BDMA_START              = (1 << 0),
+
+       MV_UNDEF                = 0,
+};
+
+struct mv_port_priv {
+
+};
+
+struct mv_host_priv {
+
+};
+
+static void mv_irq_clear(struct ata_port *ap);
+static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
+static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static void mv_phy_reset(struct ata_port *ap);
+static int mv_master_reset(void __iomem *mmio_base);
+static irqreturn_t mv_interrupt(int irq, void *dev_instance,
+                               struct pt_regs *regs);
+static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+
+static Scsi_Host_Template mv_sht = {
+       .module                 = THIS_MODULE,
+       .name                   = DRV_NAME,
+       .ioctl                  = ata_scsi_ioctl,
+       .queuecommand           = ata_scsi_queuecmd,
+       .eh_strategy_handler    = ata_scsi_error,
+       .can_queue              = ATA_DEF_QUEUE,
+       .this_id                = ATA_SHT_THIS_ID,
+       .sg_tablesize           = MV_UNDEF,
+       .max_sectors            = ATA_MAX_SECTORS,
+       .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
+       .emulated               = ATA_SHT_EMULATED,
+       .use_clustering         = MV_UNDEF,
+       .proc_name              = DRV_NAME,
+       .dma_boundary           = MV_DMA_BOUNDARY,
+       .slave_configure        = ata_scsi_slave_config,
+       .bios_param             = ata_std_bios_param,
+       .ordered_flush          = 1,
+};
+
+static struct ata_port_operations mv_ops = {
+       .port_disable           = ata_port_disable,
+
+       .tf_load                = ata_tf_load,
+       .tf_read                = ata_tf_read,
+       .check_status           = ata_check_status,
+       .exec_command           = ata_exec_command,
+       .dev_select             = ata_std_dev_select,
+
+       .phy_reset              = mv_phy_reset,
+
+       .qc_prep                = ata_qc_prep,
+       .qc_issue               = ata_qc_issue_prot,
+
+       .eng_timeout            = ata_eng_timeout,
+
+       .irq_handler            = mv_interrupt,
+       .irq_clear              = mv_irq_clear,
+
+       .scr_read               = mv_scr_read,
+       .scr_write              = mv_scr_write,
+
+       .port_start             = ata_port_start,
+       .port_stop              = ata_port_stop,
+       .host_stop              = ata_host_stop,
+};
+
+static struct ata_port_info mv_port_info[] = {
+       {  /* chip_504x */
+               .sht            = &mv_sht,
+               .host_flags     = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+                                  ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO),
+               .pio_mask       = 0x1f, /* pio4-0 */
+               .udma_mask      = 0,    /* 0x7f (udma6-0 disabled for now) */
+               .port_ops       = &mv_ops,
+       },
+       {  /* chip_508x */
+               .sht            = &mv_sht,
+               .host_flags     = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+                                  ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | 
+                                  MV_FLAG_DUAL_HC),
+               .pio_mask       = 0x1f, /* pio4-0 */
+               .udma_mask      = 0,    /* 0x7f (udma6-0 disabled for now) */
+               .port_ops       = &mv_ops,
+       },
+       {  /* chip_604x */
+               .sht            = &mv_sht,
+               .host_flags     = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+                                  ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | 
+                                  MV_FLAG_IRQ_COALESCE | MV_FLAG_BDMA),
+               .pio_mask       = 0x1f, /* pio4-0 */
+               .udma_mask      = 0,    /* 0x7f (udma6-0 disabled for now) */
+               .port_ops       = &mv_ops,
+       },
+       {  /* chip_608x */
+               .sht            = &mv_sht,
+               .host_flags     = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+                                  ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
+                                  MV_FLAG_IRQ_COALESCE | MV_FLAG_DUAL_HC |
+                                  MV_FLAG_BDMA),
+               .pio_mask       = 0x1f, /* pio4-0 */
+               .udma_mask      = 0,    /* 0x7f (udma6-0 disabled for now) */
+               .port_ops       = &mv_ops,
+       },
+};
+
+static struct pci_device_id mv_pci_tbl[] = {
+       {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5040), 0, 0, chip_504x},
+       {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5041), 0, 0, chip_504x},
+       {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5080), 0, 0, chip_508x},
+       {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5081), 0, 0, chip_508x},
+
+       {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6040), 0, 0, chip_604x},
+       {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6041), 0, 0, chip_604x},
+       {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6080), 0, 0, chip_608x},
+       {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6081), 0, 0, chip_608x},
+       {}                      /* terminate list */
+};
+
+static struct pci_driver mv_pci_driver = {
+       .name                   = DRV_NAME,
+       .id_table               = mv_pci_tbl,
+       .probe                  = mv_init_one,
+       .remove                 = ata_pci_remove_one,
+};
+
+/*
+ * Functions
+ */
+
+static inline void writelfl(unsigned long data, void __iomem *addr)
+{
+       writel(data, addr);
+       (void) readl(addr);     /* flush to avoid PCI posted write */
+}
+
+static inline void __iomem *mv_port_addr_to_hc_base(void __iomem *port_mmio)
+{
+       return ((void __iomem *)((unsigned long)port_mmio & 
+                                (unsigned long)SATAHC_MASK));
+}
+
+static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
+{
+       return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
+}
+
+static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
+{
+       return (mv_hc_base(base, port >> MV_PORT_HC_SHIFT) +
+               MV_SATAHC_ARBTR_REG_SZ + 
+               ((port & MV_PORT_MASK) * MV_PORT_REG_SZ));
+}
+
+static inline void __iomem *mv_ap_base(struct ata_port *ap)
+{
+       return mv_port_base(ap->host_set->mmio_base, ap->port_no);
+}
+
+static inline int mv_get_hc_count(unsigned long flags)
+{
+       return ((flags & MV_FLAG_DUAL_HC) ? 2 : 1);
+}
+
+static inline int mv_is_edma_active(struct ata_port *ap)
+{
+       void __iomem *port_mmio = mv_ap_base(ap);
+       return (EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
+}
+
+static inline int mv_port_bdma_capable(struct ata_port *ap)
+{
+       return (ap->flags & MV_FLAG_BDMA);
+}
+
+static void mv_irq_clear(struct ata_port *ap)
+{
+}
+
+static unsigned int mv_scr_offset(unsigned int sc_reg_in)
+{
+       unsigned int ofs;
+
+       switch (sc_reg_in) {
+       case SCR_STATUS:
+       case SCR_CONTROL:
+       case SCR_ERROR:
+               ofs = SATA_STATUS_OFS + (sc_reg_in * sizeof(u32));
+               break;
+       case SCR_ACTIVE:
+               ofs = SATA_ACTIVE_OFS;   /* active is not with the others */
+               break;
+       default:
+               ofs = 0xffffffffU;
+               break;
+       }
+       return ofs;
+}
+
+static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+{
+       unsigned int ofs = mv_scr_offset(sc_reg_in);
+
+       if (0xffffffffU != ofs) {
+               return readl(mv_ap_base(ap) + ofs);
+       } else {
+               return (u32) ofs;
+       }
+}
+
+static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+{
+       unsigned int ofs = mv_scr_offset(sc_reg_in);
+
+       if (0xffffffffU != ofs) {
+               writelfl(val, mv_ap_base(ap) + ofs);
+       }
+}
+
+static int mv_master_reset(void __iomem *mmio_base)
+{
+       void __iomem *reg = mmio_base + PCI_MAIN_CMD_STS_OFS;
+       int i, rc = 0;
+       u32 t;
+
+       VPRINTK("ENTER\n");
+
+       /* Following procedure defined in PCI "main command and status
+        * register" table.
+        */
+       t = readl(reg);
+       writel(t | STOP_PCI_MASTER, reg);
+
+       for (i = 0; i < 100; i++) {
+               msleep(10);
+               t = readl(reg);
+               if (PCI_MASTER_EMPTY & t) {
+                       break;
+               }
+       }
+       if (!(PCI_MASTER_EMPTY & t)) {
+               printk(KERN_ERR DRV_NAME "PCI master won't flush\n");
+               rc = 1;         /* broken HW? */
+               goto done;
+       }
+
+       /* set reset */
+       i = 5;
+       do {
+               writel(t | GLOB_SFT_RST, reg);
+               t = readl(reg);
+               udelay(1);
+       } while (!(GLOB_SFT_RST & t) && (i-- > 0));
+
+       if (!(GLOB_SFT_RST & t)) {
+               printk(KERN_ERR DRV_NAME "can't set global reset\n");
+               rc = 1;         /* broken HW? */
+               goto done;
+       }
+
+       /* clear reset */
+       i = 5;
+       do {
+               writel(t & ~GLOB_SFT_RST, reg);
+               t = readl(reg);
+               udelay(1);
+       } while ((GLOB_SFT_RST & t) && (i-- > 0));
+
+       if (GLOB_SFT_RST & t) {
+               printk(KERN_ERR DRV_NAME "can't clear global reset\n");
+               rc = 1;         /* broken HW? */
+       }
+
+ done:
+       VPRINTK("EXIT, rc = %i\n", rc);
+       return rc;
+}
+
+static void mv_err_intr(struct ata_port *ap)
+{
+       void __iomem *port_mmio;
+       u32 edma_err_cause, serr = 0;
+
+       /* bug here b/c we got an err int on a port we don't know about,
+        * so there's no way to clear it
+        */
+       BUG_ON(NULL == ap);
+       port_mmio = mv_ap_base(ap);
+
+       edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+
+       if (EDMA_ERR_SERR & edma_err_cause) {
+               serr = scr_read(ap, SCR_ERROR);
+               scr_write_flush(ap, SCR_ERROR, serr);
+       }
+       DPRINTK("port %u error; EDMA err cause: 0x%08x SERR: 0x%08x\n", 
+               ap->port_no, edma_err_cause, serr);
+
+       /* Clear EDMA now that SERR cleanup done */
+       writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+
+       /* check for fatal here and recover if needed */
+       if (EDMA_ERR_FATAL & edma_err_cause) {
+               mv_phy_reset(ap);
+       }
+}
+
+/* Handle any outstanding interrupts in a single SATAHC 
+ */
+static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
+                        unsigned int hc)
+{
+       void __iomem *mmio = host_set->mmio_base;
+       void __iomem *hc_mmio = mv_hc_base(mmio, hc);
+       struct ata_port *ap;
+       struct ata_queued_cmd *qc;
+       u32 hc_irq_cause;
+       int shift, port, port0, hard_port;
+       u8 ata_status;
+
+       if (hc == 0) {
+               port0 = 0;
+       } else {
+               port0 = MV_PORTS_PER_HC;
+       }
+
+       /* we'll need the HC success int register in most cases */
+       hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
+       if (hc_irq_cause) {
+               writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
+       }
+
+       VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
+               hc,relevant,hc_irq_cause);
+
+       for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
+               ap = host_set->ports[port];
+               hard_port = port & MV_PORT_MASK;        /* range 0-3 */
+               ata_status = 0xffU;
+
+               if (((CRBP_DMA_DONE | DEV_IRQ) << hard_port) & hc_irq_cause) {
+                       BUG_ON(NULL == ap);
+                       /* rcv'd new resp, basic DMA complete, or ATA IRQ */
+                       /* This is needed to clear the ATA INTRQ.
+                        * FIXME: don't read the status reg in EDMA mode!
+                        */
+                       ata_status = readb((void __iomem *)
+                                          ap->ioaddr.status_addr);
+               }
+
+               shift = port * 2;
+               if (port >= MV_PORTS_PER_HC) {
+                       shift++;        /* skip bit 8 in the HC Main IRQ reg */
+               }
+               if ((PORT0_ERR << shift) & relevant) {
+                       mv_err_intr(ap);
+                       /* FIXME: smart to OR in ATA_ERR? */
+                       ata_status = readb((void __iomem *)
+                                          ap->ioaddr.status_addr) | ATA_ERR;
+               }
+               
+               if (ap) {
+                       qc = ata_qc_from_tag(ap, ap->active_tag);
+                       if (NULL != qc) {
+                               VPRINTK("port %u IRQ found for qc, "
+                                       "ata_status 0x%x\n", port,ata_status);
+                               BUG_ON(0xffU == ata_status);
+                               /* mark qc status appropriately */
+                               ata_qc_complete(qc, ata_status);
+                       }
+               }
+       }
+       VPRINTK("EXIT\n");
+}
+
+static irqreturn_t mv_interrupt(int irq, void *dev_instance,
+                               struct pt_regs *regs)
+{
+       struct ata_host_set *host_set = dev_instance;
+       unsigned int hc, handled = 0, n_hcs;
+       void __iomem *mmio;
+       u32 irq_stat;
+
+       mmio = host_set->mmio_base;
+       irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
+       n_hcs = mv_get_hc_count(host_set->ports[0]->flags);
+
+       /* check the cases where we either have nothing pending or have read
+        * a bogus register value which can indicate HW removal or PCI fault
+        */
+       if (!irq_stat || (0xffffffffU == irq_stat)) {
+               return IRQ_NONE;
+       }
+
+       spin_lock(&host_set->lock);
+
+       for (hc = 0; hc < n_hcs; hc++) {
+               u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT));
+               if (relevant) {
+                       mv_host_intr(host_set, relevant, hc);
+                       handled = 1;
+               }
+       }
+       if (PCI_ERR & irq_stat) {
+               /* FIXME: these are all masked by default, but still need
+                * to recover from them properly.
+                */
+       }
+
+       spin_unlock(&host_set->lock);
+
+       return IRQ_RETVAL(handled);
+}
+
+static void mv_phy_reset(struct ata_port *ap)
+{
+       void __iomem *port_mmio = mv_ap_base(ap);
+       struct ata_taskfile tf;
+       struct ata_device *dev = &ap->device[0];
+       u32 edma = 0, bdma;
+
+       VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
+
+       edma = readl(port_mmio + EDMA_CMD_OFS);
+       if (EDMA_EN & edma) {
+               /* disable EDMA if active */
+               edma &= ~EDMA_EN;
+               writelfl(edma | EDMA_DS, port_mmio + EDMA_CMD_OFS);
+               udelay(1);
+       } else if (mv_port_bdma_capable(ap) &&
+                  (bdma = readl(port_mmio + BDMA_CMD_OFS)) & BDMA_START) {
+               /* disable BDMA if active */
+               writelfl(bdma & ~BDMA_START, port_mmio + BDMA_CMD_OFS);
+       }
+
+       writelfl(edma | ATA_RST, port_mmio + EDMA_CMD_OFS);
+       udelay(25);             /* allow reset propagation */
+
+       /* Spec never mentions clearing the bit.  Marvell's driver does
+        * clear the bit, however.
+        */
+       writelfl(edma & ~ATA_RST, port_mmio + EDMA_CMD_OFS);
+
+       VPRINTK("Done.  Now calling __sata_phy_reset()\n");
+
+       /* proceed to init communications via the scr_control reg */
+       __sata_phy_reset(ap);
+
+       if (ap->flags & ATA_FLAG_PORT_DISABLED) {
+               VPRINTK("Port disabled pre-sig.  Exiting.\n");
+               return;
+       }
+
+       tf.lbah = readb((void __iomem *) ap->ioaddr.lbah_addr);
+       tf.lbam = readb((void __iomem *) ap->ioaddr.lbam_addr);
+       tf.lbal = readb((void __iomem *) ap->ioaddr.lbal_addr);
+       tf.nsect = readb((void __iomem *) ap->ioaddr.nsect_addr);
+
+       dev->class = ata_dev_classify(&tf);
+       if (!ata_dev_present(dev)) {
+               VPRINTK("Port disabled post-sig: No device present.\n");
+               ata_port_disable(ap);
+       }
+       VPRINTK("EXIT\n");
+}
+
+static void mv_port_init(struct ata_ioports *port, unsigned long base)
+{
+       /* PIO related setup */
+       port->data_addr = base + SHD_PIO_DATA_OFS;
+       port->error_addr = port->feature_addr = base + SHD_FEA_ERR_OFS;
+       port->nsect_addr = base + SHD_SECT_CNT_OFS;
+       port->lbal_addr = base + SHD_LBA_L_OFS;
+       port->lbam_addr = base + SHD_LBA_M_OFS;
+       port->lbah_addr = base + SHD_LBA_H_OFS;
+       port->device_addr = base + SHD_DEV_HD_OFS;
+       port->status_addr = port->command_addr = base + SHD_CMD_STA_OFS;
+       port->altstatus_addr = port->ctl_addr = base + SHD_CTL_AST_OFS;
+       /* unused */
+       port->cmd_addr = port->bmdma_addr = port->scr_addr = 0;
+
+       /* unmask all EDMA error interrupts */
+       writel(~0, (void __iomem *)base + EDMA_ERR_IRQ_MASK_OFS);
+
+       VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n", 
+               readl((void __iomem *)base + EDMA_CFG_OFS),
+               readl((void __iomem *)base + EDMA_ERR_IRQ_CAUSE_OFS),
+               readl((void __iomem *)base + EDMA_ERR_IRQ_MASK_OFS));
+}
+
+static int mv_host_init(struct ata_probe_ent *probe_ent)
+{
+       int rc = 0, n_hc, port, hc;
+       void __iomem *mmio = probe_ent->mmio_base;
+       void __iomem *port_mmio;
+
+       if (mv_master_reset(probe_ent->mmio_base)) {
+               rc = 1;
+               goto done;
+       }
+
+       n_hc = mv_get_hc_count(probe_ent->host_flags);
+       probe_ent->n_ports = MV_PORTS_PER_HC * n_hc;
+
+       for (port = 0; port < probe_ent->n_ports; port++) {
+               port_mmio = mv_port_base(mmio, port);
+               mv_port_init(&probe_ent->port[port], (unsigned long)port_mmio);
+       }
+
+       for (hc = 0; hc < n_hc; hc++) {
+               VPRINTK("HC%i: HC config=0x%08x HC IRQ cause=0x%08x\n", hc,
+                       readl(mv_hc_base(mmio, hc) + HC_CFG_OFS),
+                       readl(mv_hc_base(mmio, hc) + HC_IRQ_CAUSE_OFS));
+       }
+
+       writel(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
+       writel(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS);
+
+       VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
+               "PCI int cause/mask=0x%08x/0x%08x\n", 
+               readl(mmio + HC_MAIN_IRQ_CAUSE_OFS),
+               readl(mmio + HC_MAIN_IRQ_MASK_OFS),
+               readl(mmio + PCI_IRQ_CAUSE_OFS),
+               readl(mmio + PCI_IRQ_MASK_OFS));
+
+ done:
+       return rc;
+}
+
+/* move to PCI layer, integrate w/ MSI stuff */
+static void pci_intx(struct pci_dev *pdev, int enable)
+{
+       u16 pci_command, new;
+
+       pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+
+       if (enable)
+               new = pci_command & ~PCI_COMMAND_INTX_DISABLE;
+       else
+               new = pci_command | PCI_COMMAND_INTX_DISABLE;
+
+       if (new != pci_command)
+               pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+}
+
+static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       static int printed_version = 0;
+       struct ata_probe_ent *probe_ent = NULL;
+       struct mv_host_priv *hpriv;
+       unsigned int board_idx = (unsigned int)ent->driver_data;
+       void __iomem *mmio_base;
+       int pci_dev_busy = 0;
+       int rc;
+
+       if (!printed_version++) {
+               printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+       }
+
+       VPRINTK("ENTER for PCI Bus:Slot.Func=%u:%u.%u\n", pdev->bus->number,
+               PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+
+       rc = pci_enable_device(pdev);
+       if (rc) {
+               return rc;
+       }
+
+       rc = pci_request_regions(pdev, DRV_NAME);
+       if (rc) {
+               pci_dev_busy = 1;
+               goto err_out;
+       }
+
+       pci_intx(pdev, 1);
+
+       probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+       if (probe_ent == NULL) {
+               rc = -ENOMEM;
+               goto err_out_regions;
+       }
+
+       memset(probe_ent, 0, sizeof(*probe_ent));
+       probe_ent->dev = pci_dev_to_dev(pdev);
+       INIT_LIST_HEAD(&probe_ent->node);
+
+       mmio_base = ioremap_nocache(pci_resource_start(pdev, MV_PRIMARY_BAR),
+                                   pci_resource_len(pdev, MV_PRIMARY_BAR));
+       if (mmio_base == NULL) {
+               rc = -ENOMEM;
+               goto err_out_free_ent;
+       }
+
+       hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
+       if (!hpriv) {
+               rc = -ENOMEM;
+               goto err_out_iounmap;
+       }
+       memset(hpriv, 0, sizeof(*hpriv));
+
+       probe_ent->sht = mv_port_info[board_idx].sht;
+       probe_ent->host_flags = mv_port_info[board_idx].host_flags;
+       probe_ent->pio_mask = mv_port_info[board_idx].pio_mask;
+       probe_ent->udma_mask = mv_port_info[board_idx].udma_mask;
+       probe_ent->port_ops = mv_port_info[board_idx].port_ops;
+
+       probe_ent->irq = pdev->irq;
+       probe_ent->irq_flags = SA_SHIRQ;
+       probe_ent->mmio_base = mmio_base;
+       probe_ent->private_data = hpriv;
+
+       /* initialize adapter */
+       rc = mv_host_init(probe_ent);
+       if (rc) {
+               goto err_out_hpriv;
+       }
+/*     mv_print_info(probe_ent); */
+
+       {
+               int b, w;
+               u32 dw[4];      /* hold a line of 16b */
+               VPRINTK("PCI config space:\n");
+               for (b = 0; b < 0x40; ) {
+                       for (w = 0; w < 4; w++) {
+                               (void) pci_read_config_dword(pdev,b,&dw[w]);
+                               b += sizeof(*dw);
+                       }
+                       VPRINTK("%08x %08x %08x %08x\n",
+                               dw[0],dw[1],dw[2],dw[3]);
+               }
+       }
+
+       /* FIXME: check ata_device_add return value */
+       ata_device_add(probe_ent);
+       kfree(probe_ent);
+
+       return 0;
+
+ err_out_hpriv:
+       kfree(hpriv);
+ err_out_iounmap:
+       iounmap(mmio_base);
+ err_out_free_ent:
+       kfree(probe_ent);
+ err_out_regions:
+       pci_release_regions(pdev);
+ err_out:
+       if (!pci_dev_busy) {
+               pci_disable_device(pdev);
+       }
+
+       return rc;
+}
+
+static int __init mv_init(void)
+{
+       return pci_module_init(&mv_pci_driver);
+}
+
+static void __exit mv_exit(void)
+{
+       pci_unregister_driver(&mv_pci_driver);
+}
+
+MODULE_AUTHOR("Brett Russ");
+MODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, mv_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(mv_init);
+module_exit(mv_exit);
index b0403ccd8a25d97aec9e220d175844dd45448076..a1d62dee3be640d43b2315146a73b6401705cb3b 100644 (file)
@@ -4,21 +4,37 @@
  *  Copyright 2004 NVIDIA Corp.  All rights reserved.
  *  Copyright 2004 Andrew Chew
  *
- *  The contents of this file are subject to the Open
- *  Software License version 1.1 that can be found at
- *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
- *  by reference.
  *
- *  Alternatively, the contents of this file may be used under the terms
- *  of the GNU General Public License version 2 (the "GPL") as distributed
- *  in the kernel source COPYING file, in which case the provisions of
- *  the GPL are applicable instead of the above.  If you wish to allow
- *  the use of your version of this file only under the terms of the
- *  GPL and not to allow others to use your version of this file under
- *  the OSL, indicate your decision by deleting the provisions above and
- *  replace them with the notice and other provisions required by the GPL.
- *  If you do not delete the provisions above, a recipient may use your
- *  version of this file under either the OSL or the GPL.
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
+ *  No hardware documentation available outside of NVIDIA.
+ *  This driver programs the NVIDIA SATA controller in a similar
+ *  fashion as with other PCI IDE BMDMA controllers, with a few
+ *  NV-specific details such as register offsets, SATA phy location,
+ *  hotplug info, etc.
+ *
+ *
+ *  0.08
+ *     - Added support for MCP51 and MCP55.
+ *
+ *  0.07
+ *     - Added support for RAID class code.
  *
  *  0.06
  *     - Added generic SATA support by using a pci_device_id that filters on
@@ -48,7 +64,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME                       "sata_nv"
-#define DRV_VERSION                    "0.6"
+#define DRV_VERSION                    "0.8"
 
 #define NV_PORTS                       2
 #define NV_PIO_MASK                    0x1f
@@ -116,7 +132,9 @@ enum nv_host_type
        GENERIC,
        NFORCE2,
        NFORCE3,
-       CK804
+       CK804,
+       MCP51,
+       MCP55
 };
 
 static struct pci_device_id nv_pci_tbl[] = {
@@ -134,9 +152,18 @@ static struct pci_device_id nv_pci_tbl[] = {
                PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2,
                PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+       { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP51 },
+       { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP51 },
+       { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP55 },
        { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
                PCI_ANY_ID, PCI_ANY_ID,
                PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC },
+       { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
+               PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_STORAGE_RAID<<8, 0xffff00, GENERIC },
        { 0, } /* terminate list */
 };
 
@@ -274,7 +301,8 @@ static irqreturn_t nv_interrupt (int irq, void *dev_instance,
                struct ata_port *ap;
 
                ap = host_set->ports[i];
-               if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+               if (ap &&
+                   !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
                        struct ata_queued_cmd *qc;
 
                        qc = ata_qc_from_tag(ap, ap->active_tag);
@@ -323,6 +351,7 @@ static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
 static void nv_host_stop (struct ata_host_set *host_set)
 {
        struct nv_host *host = host_set->private_data;
+       struct pci_dev *pdev = to_pci_dev(host_set->dev);
 
        // Disable hotplug event interrupts.
        if (host->host_desc->disable_hotplug)
@@ -330,7 +359,8 @@ static void nv_host_stop (struct ata_host_set *host_set)
 
        kfree(host);
 
-       ata_host_stop(host_set);
+       if (host_set->mmio_base)
+               pci_iounmap(pdev, host_set->mmio_base);
 }
 
 static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -392,8 +422,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO) {
                unsigned long base;
 
-               probe_ent->mmio_base = ioremap(pci_resource_start(pdev, 5),
-                               pci_resource_len(pdev, 5));
+               probe_ent->mmio_base = pci_iomap(pdev, 5, 0);
                if (probe_ent->mmio_base == NULL) {
                        rc = -EIO;
                        goto err_out_free_host;
@@ -429,7 +458,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 
 err_out_iounmap:
        if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO)
-               iounmap(probe_ent->mmio_base);
+               pci_iounmap(pdev, probe_ent->mmio_base);
 err_out_free_host:
        kfree(host);
 err_out_free_ent:
index 919fb314ad10c226ebaccdd1c8ace32980fc55d0..538ad727bd2eb897c32cad017dcad8e11701d6bf 100644 (file)
@@ -7,21 +7,26 @@
  *
  *  Copyright 2003-2004 Red Hat, Inc.
  *
- *  The contents of this file are subject to the Open
- *  Software License version 1.1 that can be found at
- *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
- *  by reference.
  *
- *  Alternatively, the contents of this file may be used under the terms
- *  of the GNU General Public License version 2 (the "GPL") as distributed
- *  in the kernel source COPYING file, in which case the provisions of
- *  the GPL are applicable instead of the above.  If you wish to allow
- *  the use of your version of this file only under the terms of the
- *  GPL and not to allow others to use your version of this file under
- *  the OSL, indicate your decision by deleting the provisions above and
- *  replace them with the notice and other provisions required by the GPL.
- *  If you do not delete the provisions above, a recipient may use your
- *  version of this file under either the OSL or the GPL.
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
+ *  Hardware information only available under NDA.
  *
  */
 
@@ -79,13 +84,15 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r
 static void pdc_eng_timeout(struct ata_port *ap);
 static int pdc_port_start(struct ata_port *ap);
 static void pdc_port_stop(struct ata_port *ap);
-static void pdc_phy_reset(struct ata_port *ap);
+static void pdc_pata_phy_reset(struct ata_port *ap);
+static void pdc_sata_phy_reset(struct ata_port *ap);
 static void pdc_qc_prep(struct ata_queued_cmd *qc);
 static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf);
 static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf);
 static void pdc_irq_clear(struct ata_port *ap);
 static int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
 
+
 static Scsi_Host_Template pdc_ata_sht = {
        .module                 = THIS_MODULE,
        .name                   = DRV_NAME,
@@ -106,24 +113,48 @@ static Scsi_Host_Template pdc_ata_sht = {
        .ordered_flush          = 1,
 };
 
-static struct ata_port_operations pdc_ata_ops = {
+static struct ata_port_operations pdc_sata_ops = {
        .port_disable           = ata_port_disable,
        .tf_load                = pdc_tf_load_mmio,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
        .exec_command           = pdc_exec_command_mmio,
        .dev_select             = ata_std_dev_select,
-       .phy_reset              = pdc_phy_reset,
+
+       .phy_reset              = pdc_sata_phy_reset,
+
        .qc_prep                = pdc_qc_prep,
        .qc_issue               = pdc_qc_issue_prot,
        .eng_timeout            = pdc_eng_timeout,
        .irq_handler            = pdc_interrupt,
        .irq_clear              = pdc_irq_clear,
+
        .scr_read               = pdc_sata_scr_read,
        .scr_write              = pdc_sata_scr_write,
        .port_start             = pdc_port_start,
        .port_stop              = pdc_port_stop,
-       .host_stop              = ata_host_stop,
+       .host_stop              = ata_pci_host_stop,
+};
+
+static struct ata_port_operations pdc_pata_ops = {
+       .port_disable           = ata_port_disable,
+       .tf_load                = pdc_tf_load_mmio,
+       .tf_read                = ata_tf_read,
+       .check_status           = ata_check_status,
+       .exec_command           = pdc_exec_command_mmio,
+       .dev_select             = ata_std_dev_select,
+
+       .phy_reset              = pdc_pata_phy_reset,
+
+       .qc_prep                = pdc_qc_prep,
+       .qc_issue               = pdc_qc_issue_prot,
+       .eng_timeout            = pdc_eng_timeout,
+       .irq_handler            = pdc_interrupt,
+       .irq_clear              = pdc_irq_clear,
+
+       .port_start             = pdc_port_start,
+       .port_stop              = pdc_port_stop,
+       .host_stop              = ata_pci_host_stop,
 };
 
 static struct ata_port_info pdc_port_info[] = {
@@ -135,7 +166,7 @@ static struct ata_port_info pdc_port_info[] = {
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
-               .port_ops       = &pdc_ata_ops,
+               .port_ops       = &pdc_sata_ops,
        },
 
        /* board_20319 */
@@ -146,7 +177,7 @@ static struct ata_port_info pdc_port_info[] = {
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
-               .port_ops       = &pdc_ata_ops,
+               .port_ops       = &pdc_sata_ops,
        },
 
        /* board_20619 */
@@ -157,7 +188,7 @@ static struct ata_port_info pdc_port_info[] = {
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
-               .port_ops       = &pdc_ata_ops,
+               .port_ops       = &pdc_pata_ops,
        },
 };
 
@@ -181,6 +212,10 @@ static struct pci_device_id pdc_ata_pci_tbl[] = {
          board_20319 },
        { PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
          board_20319 },
+       { PCI_VENDOR_ID_PROMISE, 0x3519, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_20319 },
+       { PCI_VENDOR_ID_PROMISE, 0x3d17, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_20319 },
        { PCI_VENDOR_ID_PROMISE, 0x3d18, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
          board_20319 },
 
@@ -248,7 +283,7 @@ static void pdc_port_stop(struct ata_port *ap)
 
 static void pdc_reset_port(struct ata_port *ap)
 {
-       void *mmio = (void *) ap->ioaddr.cmd_addr + PDC_CTLSTAT;
+       void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT;
        unsigned int i;
        u32 tmp;
 
@@ -268,12 +303,23 @@ static void pdc_reset_port(struct ata_port *ap)
        readl(mmio);    /* flush */
 }
 
-static void pdc_phy_reset(struct ata_port *ap)
+static void pdc_sata_phy_reset(struct ata_port *ap)
 {
        pdc_reset_port(ap);
        sata_phy_reset(ap);
 }
 
+static void pdc_pata_phy_reset(struct ata_port *ap)
+{
+       /* FIXME: add cable detect.  Don't assume 40-pin cable */
+       ap->cbl = ATA_CBL_PATA40;
+       ap->udma_mask &= ATA_UDMA_MASK_40C;
+
+       pdc_reset_port(ap);
+       ata_port_probe(ap);
+       ata_bus_reset(ap);
+}
+
 static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
 {
        if (sc_reg > SCR_CONTROL)
@@ -321,11 +367,15 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc)
 
 static void pdc_eng_timeout(struct ata_port *ap)
 {
+       struct ata_host_set *host_set = ap->host_set;
        u8 drv_stat;
        struct ata_queued_cmd *qc;
+       unsigned long flags;
 
        DPRINTK("ENTER\n");
 
+       spin_lock_irqsave(&host_set->lock, flags);
+
        qc = ata_qc_from_tag(ap, ap->active_tag);
        if (!qc) {
                printk(KERN_ERR "ata%u: BUG: timeout without command\n",
@@ -359,6 +409,7 @@ static void pdc_eng_timeout(struct ata_port *ap)
        }
 
 out:
+       spin_unlock_irqrestore(&host_set->lock, flags);
        DPRINTK("EXIT\n");
 }
 
@@ -368,7 +419,7 @@ static inline unsigned int pdc_host_intr( struct ata_port *ap,
        u8 status;
        unsigned int handled = 0, have_err = 0;
        u32 tmp;
-       void *mmio = (void *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;
+       void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;
 
        tmp = readl(mmio);
        if (tmp & PDC_ERR_MASK) {
@@ -397,7 +448,7 @@ static inline unsigned int pdc_host_intr( struct ata_port *ap,
 static void pdc_irq_clear(struct ata_port *ap)
 {
        struct ata_host_set *host_set = ap->host_set;
-       void *mmio = host_set->mmio_base;
+       void __iomem *mmio = host_set->mmio_base;
 
        readl(mmio + PDC_INT_SEQMASK);
 }
@@ -409,7 +460,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r
        u32 mask = 0;
        unsigned int i, tmp;
        unsigned int handled = 0;
-       void *mmio_base;
+       void __iomem *mmio_base;
 
        VPRINTK("ENTER\n");
 
@@ -441,7 +492,8 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r
                VPRINTK("port %u\n", i);
                ap = host_set->ports[i];
                tmp = mask & (1 << (i + 1));
-               if (tmp && ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+               if (tmp && ap &&
+                   !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
                        struct ata_queued_cmd *qc;
 
                        qc = ata_qc_from_tag(ap, ap->active_tag);
@@ -530,7 +582,7 @@ static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base)
 
 static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
 {
-       void *mmio = pe->mmio_base;
+       void __iomem *mmio = pe->mmio_base;
        u32 tmp;
 
        /*
@@ -573,7 +625,7 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        static int printed_version;
        struct ata_probe_ent *probe_ent = NULL;
        unsigned long base;
-       void *mmio_base;
+       void __iomem *mmio_base;
        unsigned int board_idx = (unsigned int) ent->driver_data;
        int pci_dev_busy = 0;
        int rc;
@@ -612,8 +664,7 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        probe_ent->dev = pci_dev_to_dev(pdev);
        INIT_LIST_HEAD(&probe_ent->node);
 
-       mmio_base = ioremap(pci_resource_start(pdev, 3),
-                           pci_resource_len(pdev, 3));
+       mmio_base = pci_iomap(pdev, 3, 0);
        if (mmio_base == NULL) {
                rc = -ENOMEM;
                goto err_out_free_ent;
index 6e7e96b9ee137d621370c40d9b139eab84f4b355..6ee5e190262de8d55f9689450e8fb08aea67eb77 100644 (file)
@@ -3,21 +3,24 @@
  *
  *  Copyright 2003-2004 Red Hat, Inc.
  *
- *  The contents of this file are subject to the Open
- *  Software License version 1.1 that can be found at
- *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
- *  by reference.
  *
- *  Alternatively, the contents of this file may be used under the terms
- *  of the GNU General Public License version 2 (the "GPL") as distributed
- *  in the kernel source COPYING file, in which case the provisions of
- *  the GPL are applicable instead of the above.  If you wish to allow
- *  the use of your version of this file only under the terms of the
- *  GPL and not to allow others to use your version of this file under
- *  the OSL, indicate your decision by deleting the provisions above and
- *  replace them with the notice and other provisions required by the GPL.
- *  If you do not delete the provisions above, a recipient may use your
- *  version of this file under either the OSL or the GPL.
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
  *
  */
 
index 1383e8a28d728b34e936c0b9c7e04ffbf9a5818c..ffcdeb68641cf5a2493abf7be5b68b1da32f329c 100644 (file)
@@ -6,21 +6,24 @@
  *  Copyright 2005 Pacific Digital Corporation.
  *  (OSL/GPL code release authorized by Jalil Fadavi).
  *
- *  The contents of this file are subject to the Open
- *  Software License version 1.1 that can be found at
- *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
- *  by reference.
  *
- *  Alternatively, the contents of this file may be used under the terms
- *  of the GNU General Public License version 2 (the "GPL") as distributed
- *  in the kernel source COPYING file, in which case the provisions of
- *  the GPL are applicable instead of the above.  If you wish to allow
- *  the use of your version of this file only under the terms of the
- *  GPL and not to allow others to use your version of this file under
- *  the OSL, indicate your decision by deleting the provisions above and
- *  replace them with the notice and other provisions required by the GPL.
- *  If you do not delete the provisions above, a recipient may use your
- *  version of this file under either the OSL or the GPL.
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
  *
  */
 
@@ -117,7 +120,7 @@ static void qs_phy_reset(struct ata_port *ap);
 static void qs_qc_prep(struct ata_queued_cmd *qc);
 static int qs_qc_issue(struct ata_queued_cmd *qc);
 static int qs_check_atapi_dma(struct ata_queued_cmd *qc);
-static void qs_bmdma_stop(struct ata_port *ap);
+static void qs_bmdma_stop(struct ata_queued_cmd *qc);
 static u8 qs_bmdma_status(struct ata_port *ap);
 static void qs_irq_clear(struct ata_port *ap);
 static void qs_eng_timeout(struct ata_port *ap);
@@ -198,7 +201,7 @@ static int qs_check_atapi_dma(struct ata_queued_cmd *qc)
        return 1;       /* ATAPI DMA not supported */
 }
 
-static void qs_bmdma_stop(struct ata_port *ap)
+static void qs_bmdma_stop(struct ata_queued_cmd *qc)
 {
        /* nothing */
 }
@@ -386,7 +389,8 @@ static inline unsigned int qs_intr_pkt(struct ata_host_set *host_set)
                        DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n",
                                        sff1, sff0, port_no, sHST, sDST);
                        handled = 1;
-                       if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+                       if (ap && !(ap->flags &
+                                   (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) {
                                struct ata_queued_cmd *qc;
                                struct qs_port_priv *pp = ap->private_data;
                                if (!pp || pp->state != qs_state_pkt)
@@ -417,7 +421,8 @@ static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set)
        for (port_no = 0; port_no < host_set->n_ports; ++port_no) {
                struct ata_port *ap;
                ap = host_set->ports[port_no];
-               if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+               if (ap &&
+                   !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
                        struct ata_queued_cmd *qc;
                        struct qs_port_priv *pp = ap->private_data;
                        if (!pp || pp->state != qs_state_mmio)
@@ -431,7 +436,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set)
                                        continue;
                                DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
                                        ap->id, qc->tf.protocol, status);
-               
+
                                /* complete taskfile transaction */
                                pp->state = qs_state_idle;
                                ata_qc_complete(qc, status);
@@ -489,7 +494,7 @@ static int qs_port_start(struct ata_port *ap)
        if (rc)
                return rc;
        qs_enter_reg_mode(ap);
-       pp = kcalloc(1, sizeof(*pp), GFP_KERNEL);
+       pp = kzalloc(sizeof(*pp), GFP_KERNEL);
        if (!pp) {
                rc = -ENOMEM;
                goto err_out;
@@ -533,11 +538,12 @@ static void qs_port_stop(struct ata_port *ap)
 static void qs_host_stop(struct ata_host_set *host_set)
 {
        void __iomem *mmio_base = host_set->mmio_base;
+       struct pci_dev *pdev = to_pci_dev(host_set->dev);
 
        writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
        writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
 
-       ata_host_stop(host_set);
+       pci_iounmap(pdev, mmio_base);
 }
 
 static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
@@ -641,8 +647,7 @@ static int qs_ata_init_one(struct pci_dev *pdev,
                goto err_out_regions;
        }
 
-       mmio_base = ioremap(pci_resource_start(pdev, 4),
-                           pci_resource_len(pdev, 4));
+       mmio_base = pci_iomap(pdev, 4, 0);
        if (mmio_base == NULL) {
                rc = -ENOMEM;
                goto err_out_regions;
@@ -692,7 +697,7 @@ static int qs_ata_init_one(struct pci_dev *pdev,
        return 0;
 
 err_out_iounmap:
-       iounmap(mmio_base);
+       pci_iounmap(pdev, mmio_base);
 err_out_regions:
        pci_release_regions(pdev);
 err_out:
index 49ed557a4b661e4cfa9569b0d2af72f4375573d8..ba98a175ee3a8f9e227917689b9678285df586c3 100644 (file)
@@ -5,24 +5,32 @@
  *                 Please ALWAYS copy linux-ide@vger.kernel.org
  *                 on emails.
  *
- *  Copyright 2003 Red Hat, Inc.
+ *  Copyright 2003-2005 Red Hat, Inc.
  *  Copyright 2003 Benjamin Herrenschmidt
  *
- *  The contents of this file are subject to the Open
- *  Software License version 1.1 that can be found at
- *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
- *  by reference.
  *
- *  Alternatively, the contents of this file may be used under the terms
- *  of the GNU General Public License version 2 (the "GPL") as distributed
- *  in the kernel source COPYING file, in which case the provisions of
- *  the GPL are applicable instead of the above.  If you wish to allow
- *  the use of your version of this file only under the terms of the
- *  GPL and not to allow others to use your version of this file under
- *  the OSL, indicate your decision by deleting the provisions above and
- *  replace them with the notice and other provisions required by the GPL.
- *  If you do not delete the provisions above, a recipient may use your
- *  version of this file under either the OSL or the GPL.
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
+ *  Documentation for SiI 3112:
+ *  http://gkernel.sourceforge.net/specs/sii/3112A_SiI-DS-0095-B2.pdf.bz2
+ *
+ *  Other errata and documentation available under NDA.
  *
  */
 
 #define DRV_VERSION    "0.9"
 
 enum {
+       SIL_FLAG_MOD15WRITE     = (1 << 30),
+
        sil_3112                = 0,
-       sil_3114                = 1,
+       sil_3112_m15w           = 1,
+       sil_3114                = 2,
 
        SIL_FIFO_R0             = 0x40,
        SIL_FIFO_W0             = 0x41,
@@ -75,14 +86,15 @@ static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static void sil_post_set_mode (struct ata_port *ap);
 
+
 static struct pci_device_id sil_pci_tbl[] = {
-       { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
-       { 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+       { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
+       { 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
        { 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
        { 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, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
+       { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
+       { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
        { }     /* terminate list */
 };
 
@@ -161,7 +173,7 @@ static struct ata_port_operations sil_ops = {
        .scr_write              = sil_scr_write,
        .port_start             = ata_port_start,
        .port_stop              = ata_port_stop,
-       .host_stop              = ata_host_stop,
+       .host_stop              = ata_pci_host_stop,
 };
 
 static struct ata_port_info sil_port_info[] = {
@@ -174,6 +186,16 @@ static struct ata_port_info sil_port_info[] = {
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
                .udma_mask      = 0x3f,                 /* udma0-5 */
                .port_ops       = &sil_ops,
+       }, /* sil_3112_15w - keep it sync'd w/ sil_3112 */
+       {
+               .sht            = &sil_sht,
+               .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+                                 ATA_FLAG_SRST | ATA_FLAG_MMIO |
+                                 SIL_FLAG_MOD15WRITE,
+               .pio_mask       = 0x1f,                 /* pio0-4 */
+               .mwdma_mask     = 0x07,                 /* mwdma0-2 */
+               .udma_mask      = 0x3f,                 /* udma0-5 */
+               .port_ops       = &sil_ops,
        }, /* sil_3114 */
        {
                .sht            = &sil_sht,
@@ -210,6 +232,7 @@ MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, sil_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
+
 static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
 {
        u8 cache_line = 0;
@@ -221,7 +244,8 @@ static void sil_post_set_mode (struct ata_port *ap)
 {
        struct ata_host_set *host_set = ap->host_set;
        struct ata_device *dev;
-       void *addr = host_set->mmio_base + sil_port[ap->port_no].xfer_mode;
+       void __iomem *addr =
+               host_set->mmio_base + sil_port[ap->port_no].xfer_mode;
        u32 tmp, dev_mode[2];
        unsigned int i;
 
@@ -323,15 +347,15 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
        while ((len > 0) && (s[len - 1] == ' '))
                len--;
 
-       for (n = 0; sil_blacklist[n].product; n++) 
+       for (n = 0; sil_blacklist[n].product; n++)
                if (!memcmp(sil_blacklist[n].product, s,
                            strlen(sil_blacklist[n].product))) {
                        quirks = sil_blacklist[n].quirk;
                        break;
                }
-       
+
        /* limit requests to 15 sectors */
-       if (quirks & SIL_QUIRK_MOD15WRITE) {
+       if ((ap->flags & SIL_FLAG_MOD15WRITE) && (quirks & SIL_QUIRK_MOD15WRITE)) {
                printk(KERN_INFO "ata%u(%u): applying Seagate errata fix\n",
                       ap->id, dev->devno);
                ap->host->max_sectors = 15;
@@ -354,7 +378,7 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        static int printed_version;
        struct ata_probe_ent *probe_ent = NULL;
        unsigned long base;
-       void *mmio_base;
+       void __iomem *mmio_base;
        int rc;
        unsigned int i;
        int pci_dev_busy = 0;
@@ -404,8 +428,7 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                probe_ent->irq_flags = SA_SHIRQ;
        probe_ent->host_flags = sil_port_info[ent->driver_data].host_flags;
 
-       mmio_base = ioremap(pci_resource_start(pdev, 5),
-                           pci_resource_len(pdev, 5));
+       mmio_base = pci_iomap(pdev, 5, 0);
        if (mmio_base == NULL) {
                rc = -ENOMEM;
                goto err_out_free_ent;
index e418b89c6b9d8cf67c57a1b03431b91a19b585f2..43af445b3ad2eeafe74f37dbad64f18300f8be12 100644 (file)
@@ -7,21 +7,26 @@
  *
  *  Copyright 2004 Uwe Koziolek
  *
- *  The contents of this file are subject to the Open
- *  Software License version 1.1 that can be found at
- *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
- *  by reference.
  *
- *  Alternatively, the contents of this file may be used under the terms
- *  of the GNU General Public License version 2 (the "GPL") as distributed
- *  in the kernel source COPYING file, in which case the provisions of
- *  the GPL are applicable instead of the above.  If you wish to allow
- *  the use of your version of this file only under the terms of the
- *  GPL and not to allow others to use your version of this file under
- *  the OSL, indicate your decision by deleting the provisions above and
- *  replace them with the notice and other provisions required by the GPL.
- *  If you do not delete the provisions above, a recipient may use your
- *  version of this file under either the OSL or the GPL.
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
+ *  Hardware documentation available under NDA.
  *
  */
 
@@ -234,7 +239,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        pci_read_config_dword(pdev, SIS_GENCTL, &genctl);
        if ((genctl & GENCTL_IOMAPPED_SCR) == 0)
                probe_ent->host_flags |= SIS_FLAG_CFGSCR;
-       
+
        /* if hardware thinks SCRs are in IO space, but there are
         * no IO resources assigned, change to PCI cfg space.
         */
index 858e07185dbdf2589042924708baa297a16a3b8d..d89d968bedace68ad91771a168455b0164b12bb0 100644 (file)
  *  This driver probably works with non-Apple versions of the
  *  Broadcom chipset...
  *
- *  The contents of this file are subject to the Open
- *  Software License version 1.1 that can be found at
- *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
- *  by reference.
  *
- *  Alternatively, the contents of this file may be used under the terms
- *  of the GNU General Public License version 2 (the "GPL") as distributed
- *  in the kernel source COPYING file, in which case the provisions of
- *  the GPL are applicable instead of the above.  If you wish to allow
- *  the use of your version of this file only under the terms of the
- *  GPL and not to allow others to use your version of this file under
- *  the OSL, indicate your decision by deleting the provisions above and
- *  replace them with the notice and other provisions required by the GPL.
- *  If you do not delete the provisions above, a recipient may use your
- *  version of this file under either the OSL or the GPL.
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
+ *  Hardware documentation available under NDA.
  *
  */
 
@@ -195,18 +200,18 @@ static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
        /* start host DMA transaction */
        dmactl = readb(mmio + ATA_DMA_CMD);
        writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
-       /* There is a race condition in certain SATA controllers that can 
-          be seen when the r/w command is given to the controller before the 
+       /* There is a race condition in certain SATA controllers that can
+          be seen when the r/w command is given to the controller before the
           host DMA is started. On a Read command, the controller would initiate
           the command to the drive even before it sees the DMA start. When there
-          are very fast drives connected to the controller, or when the data request 
+          are very fast drives connected to the controller, or when the data request
           hits in the drive cache, there is the possibility that the drive returns a part
           or all of the requested data to the controller before the DMA start is issued.
           In this case, the controller would become confused as to what to do with the data.
           In the worst case when all the data is returned back to the controller, the
           controller could hang. In other cases it could return partial data returning
           in data corruption. This problem has been seen in PPC systems and can also appear
-          on an system with very fast disks, where the SATA controller is sitting behind a 
+          on an system with very fast disks, where the SATA controller is sitting behind a
           number of bridges, and hence there is significant latency between the r/w command
           and the start command. */
        /* issue r/w command if the access is to ATA*/
@@ -214,7 +219,7 @@ static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
                ap->ops->exec_command(ap, &qc->tf);
 }
 
-                                                                             
+
 static u8 k2_stat_check_status(struct ata_port *ap)
 {
                return readl((void *) ap->ioaddr.status_addr);
@@ -313,7 +318,7 @@ static struct ata_port_operations k2_sata_ops = {
        .scr_write              = k2_sata_scr_write,
        .port_start             = ata_port_start,
        .port_stop              = ata_port_stop,
-       .host_stop              = ata_host_stop,
+       .host_stop              = ata_pci_host_stop,
 };
 
 static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base)
@@ -341,7 +346,7 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        static int printed_version;
        struct ata_probe_ent *probe_ent = NULL;
        unsigned long base;
-       void *mmio_base;
+       void __iomem *mmio_base;
        int pci_dev_busy = 0;
        int rc;
        int i;
@@ -387,8 +392,7 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        probe_ent->dev = pci_dev_to_dev(pdev);
        INIT_LIST_HEAD(&probe_ent->node);
 
-       mmio_base = ioremap(pci_resource_start(pdev, 5),
-                           pci_resource_len(pdev, 5));
+       mmio_base = pci_iomap(pdev, 5, 0);
        if (mmio_base == NULL) {
                rc = -ENOMEM;
                goto err_out_free_ent;
index efd7d7a61135f01b41337fdf80111ae207a745e3..540a851911723b5329e67f6f63981acba6975339 100644 (file)
@@ -7,21 +7,26 @@
  *
  *  Copyright 2003-2004 Red Hat, Inc.
  *
- *  The contents of this file are subject to the Open
- *  Software License version 1.1 that can be found at
- *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
- *  by reference.
  *
- *  Alternatively, the contents of this file may be used under the terms
- *  of the GNU General Public License version 2 (the "GPL") as distributed
- *  in the kernel source COPYING file, in which case the provisions of
- *  the GPL are applicable instead of the above.  If you wish to allow
- *  the use of your version of this file only under the terms of the
- *  GPL and not to allow others to use your version of this file under
- *  the OSL, indicate your decision by deleting the provisions above and
- *  replace them with the notice and other provisions required by the GPL.
- *  If you do not delete the provisions above, a recipient may use your
- *  version of this file under either the OSL or the GPL.
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
+ *  Hardware documentation available under NDA.
  *
  */
 
@@ -94,7 +99,7 @@ enum {
        PDC_DIMM1_CONTROL_OFFSET      = 0x84,
        PDC_SDRAM_CONTROL_OFFSET      = 0x88,
        PDC_I2C_WRITE                 = 0x00000000,
-       PDC_I2C_READ                  = 0x00000040,     
+       PDC_I2C_READ                  = 0x00000040,
        PDC_I2C_START                 = 0x00000080,
        PDC_I2C_MASK_INT              = 0x00000020,
        PDC_I2C_COMPLETE              = 0x00010000,
@@ -105,16 +110,16 @@ enum {
        PDC_DIMM_SPD_COLUMN_NUM       = 4,
        PDC_DIMM_SPD_MODULE_ROW       = 5,
        PDC_DIMM_SPD_TYPE             = 11,
-       PDC_DIMM_SPD_FRESH_RATE       = 12,         
-       PDC_DIMM_SPD_BANK_NUM         = 17,     
+       PDC_DIMM_SPD_FRESH_RATE       = 12,
+       PDC_DIMM_SPD_BANK_NUM         = 17,
        PDC_DIMM_SPD_CAS_LATENCY      = 18,
-       PDC_DIMM_SPD_ATTRIBUTE        = 21,    
+       PDC_DIMM_SPD_ATTRIBUTE        = 21,
        PDC_DIMM_SPD_ROW_PRE_CHARGE   = 27,
-       PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28,      
+       PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28,
        PDC_DIMM_SPD_RAS_CAS_DELAY    = 29,
        PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30,
        PDC_DIMM_SPD_SYSTEM_FREQ      = 126,
-       PDC_CTL_STATUS                = 0x08,   
+       PDC_CTL_STATUS                = 0x08,
        PDC_DIMM_WINDOW_CTLR          = 0x0C,
        PDC_TIME_CONTROL              = 0x3C,
        PDC_TIME_PERIOD               = 0x40,
@@ -157,15 +162,15 @@ static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf);
 static void pdc20621_host_stop(struct ata_host_set *host_set);
 static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
 static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
-static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, 
+static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe,
                                      u32 device, u32 subaddr, u32 *pdata);
 static int pdc20621_prog_dimm0(struct ata_probe_ent *pe);
 static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe);
 #ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, 
+static void pdc20621_get_from_dimm(struct ata_probe_ent *pe,
                                   void *psource, u32 offset, u32 size);
 #endif
-static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, 
+static void pdc20621_put_to_dimm(struct ata_probe_ent *pe,
                                 void *psource, u32 offset, u32 size);
 static void pdc20621_irq_clear(struct ata_port *ap);
 static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
@@ -240,13 +245,14 @@ static struct pci_driver pdc_sata_pci_driver = {
 
 static void pdc20621_host_stop(struct ata_host_set *host_set)
 {
+       struct pci_dev *pdev = to_pci_dev(host_set->dev);
        struct pdc_host_priv *hpriv = host_set->private_data;
        void *dimm_mmio = hpriv->dimm_mmio;
 
-       iounmap(dimm_mmio);
+       pci_iounmap(pdev, dimm_mmio);
        kfree(hpriv);
 
-       ata_host_stop(host_set);
+       pci_iounmap(pdev, host_set->mmio_base);
 }
 
 static int pdc_port_start(struct ata_port *ap)
@@ -446,9 +452,9 @@ static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
        struct scatterlist *sg = qc->sg;
        struct ata_port *ap = qc->ap;
        struct pdc_port_priv *pp = ap->private_data;
-       void *mmio = ap->host_set->mmio_base;
+       void __iomem *mmio = ap->host_set->mmio_base;
        struct pdc_host_priv *hpriv = ap->host_set->private_data;
-       void *dimm_mmio = hpriv->dimm_mmio;
+       void __iomem *dimm_mmio = hpriv->dimm_mmio;
        unsigned int portno = ap->port_no;
        unsigned int i, last, idx, total_len = 0, sgt_len;
        u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
@@ -508,9 +514,9 @@ static void pdc20621_nodata_prep(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        struct pdc_port_priv *pp = ap->private_data;
-       void *mmio = ap->host_set->mmio_base;
+       void __iomem *mmio = ap->host_set->mmio_base;
        struct pdc_host_priv *hpriv = ap->host_set->private_data;
-       void *dimm_mmio = hpriv->dimm_mmio;
+       void __iomem *dimm_mmio = hpriv->dimm_mmio;
        unsigned int portno = ap->port_no;
        unsigned int i;
 
@@ -560,7 +566,7 @@ static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
 {
        struct ata_port *ap = qc->ap;
        struct ata_host_set *host_set = ap->host_set;
-       void *mmio = host_set->mmio_base;
+       void __iomem *mmio = host_set->mmio_base;
 
        /* hard-code chip #0 */
        mmio += PDC_CHIP0_OFS;
@@ -634,7 +640,7 @@ static void pdc20621_packet_start(struct ata_queued_cmd *qc)
        struct ata_port *ap = qc->ap;
        struct ata_host_set *host_set = ap->host_set;
        unsigned int port_no = ap->port_no;
-       void *mmio = host_set->mmio_base;
+       void __iomem *mmio = host_set->mmio_base;
        unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
        u8 seq = (u8) (port_no + 1);
        unsigned int port_ofs;
@@ -694,7 +700,7 @@ static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc)
 static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
                                           struct ata_queued_cmd *qc,
                                          unsigned int doing_hdma,
-                                         void *mmio)
+                                         void __iomem *mmio)
 {
        unsigned int port_no = ap->port_no;
        unsigned int port_ofs =
@@ -773,7 +779,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
 static void pdc20621_irq_clear(struct ata_port *ap)
 {
        struct ata_host_set *host_set = ap->host_set;
-       void *mmio = host_set->mmio_base;
+       void __iomem *mmio = host_set->mmio_base;
 
        mmio += PDC_CHIP0_OFS;
 
@@ -787,7 +793,7 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re
        u32 mask = 0;
        unsigned int i, tmp, port_no;
        unsigned int handled = 0;
-       void *mmio_base;
+       void __iomem *mmio_base;
 
        VPRINTK("ENTER\n");
 
@@ -825,7 +831,8 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re
                        ap = host_set->ports[port_no];
                tmp = mask & (1 << i);
                VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
-               if (tmp && ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+               if (tmp && ap &&
+                   !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
                        struct ata_queued_cmd *qc;
 
                        qc = ata_qc_from_tag(ap, ap->active_tag);
@@ -847,10 +854,14 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re
 static void pdc_eng_timeout(struct ata_port *ap)
 {
        u8 drv_stat;
+       struct ata_host_set *host_set = ap->host_set;
        struct ata_queued_cmd *qc;
+       unsigned long flags;
 
        DPRINTK("ENTER\n");
 
+       spin_lock_irqsave(&host_set->lock, flags);
+
        qc = ata_qc_from_tag(ap, ap->active_tag);
        if (!qc) {
                printk(KERN_ERR "ata%u: BUG: timeout without command\n",
@@ -884,6 +895,7 @@ static void pdc_eng_timeout(struct ata_port *ap)
        }
 
 out:
+       spin_unlock_irqrestore(&host_set->lock, flags);
        DPRINTK("EXIT\n");
 }
 
@@ -922,23 +934,23 @@ static void pdc_sata_setup_port(struct ata_ioports *port, unsigned long base)
 
 
 #ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource, 
+static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
                                   u32 offset, u32 size)
 {
        u32 window_size;
        u16 idx;
        u8 page_mask;
        long dist;
-       void *mmio = pe->mmio_base;
+       void __iomem *mmio = pe->mmio_base;
        struct pdc_host_priv *hpriv = pe->private_data;
-       void *dimm_mmio = hpriv->dimm_mmio;
+       void __iomem *dimm_mmio = hpriv->dimm_mmio;
 
        /* hard-code chip #0 */
        mmio += PDC_CHIP0_OFS;
 
-       page_mask = 0x00;       
-       window_size = 0x2000 * 4; /* 32K byte uchar size */  
-       idx = (u16) (offset / window_size); 
+       page_mask = 0x00;
+       window_size = 0x2000 * 4; /* 32K byte uchar size */
+       idx = (u16) (offset / window_size);
 
        writel(0x01, mmio + PDC_GENERAL_CTLR);
        readl(mmio + PDC_GENERAL_CTLR);
@@ -947,19 +959,19 @@ static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
 
        offset -= (idx * window_size);
        idx++;
-       dist = ((long) (window_size - (offset + size))) >= 0 ? size : 
+       dist = ((long) (window_size - (offset + size))) >= 0 ? size :
                (long) (window_size - offset);
-       memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4), 
+       memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4),
                      dist);
 
-       psource += dist;    
+       psource += dist;
        size -= dist;
        for (; (long) size >= (long) window_size ;) {
                writel(0x01, mmio + PDC_GENERAL_CTLR);
                readl(mmio + PDC_GENERAL_CTLR);
                writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
                readl(mmio + PDC_DIMM_WINDOW_CTLR);
-               memcpy_fromio((char *) psource, (char *) (dimm_mmio), 
+               memcpy_fromio((char *) psource, (char *) (dimm_mmio),
                              window_size / 4);
                psource += window_size;
                size -= window_size;
@@ -971,34 +983,34 @@ static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
                readl(mmio + PDC_GENERAL_CTLR);
                writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
                readl(mmio + PDC_DIMM_WINDOW_CTLR);
-               memcpy_fromio((char *) psource, (char *) (dimm_mmio), 
+               memcpy_fromio((char *) psource, (char *) (dimm_mmio),
                              size / 4);
        }
 }
 #endif
 
 
-static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, 
+static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
                                 u32 offset, u32 size)
 {
        u32 window_size;
        u16 idx;
        u8 page_mask;
        long dist;
-       void *mmio = pe->mmio_base;
+       void __iomem *mmio = pe->mmio_base;
        struct pdc_host_priv *hpriv = pe->private_data;
-       void *dimm_mmio = hpriv->dimm_mmio;
+       void __iomem *dimm_mmio = hpriv->dimm_mmio;
 
-       /* hard-code chip #0 */   
+       /* hard-code chip #0 */
        mmio += PDC_CHIP0_OFS;
 
-       page_mask = 0x00;       
-       window_size = 0x2000 * 4;       /* 32K byte uchar size */  
+       page_mask = 0x00;
+       window_size = 0x2000 * 4;       /* 32K byte uchar size */
        idx = (u16) (offset / window_size);
 
        writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
        readl(mmio + PDC_DIMM_WINDOW_CTLR);
-       offset -= (idx * window_size); 
+       offset -= (idx * window_size);
        idx++;
        dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size :
                (long) (window_size - offset);
@@ -1006,12 +1018,12 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
        writel(0x01, mmio + PDC_GENERAL_CTLR);
        readl(mmio + PDC_GENERAL_CTLR);
 
-       psource += dist;    
+       psource += dist;
        size -= dist;
        for (; (long) size >= (long) window_size ;) {
                writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
                readl(mmio + PDC_DIMM_WINDOW_CTLR);
-               memcpy_toio((char *) (dimm_mmio), (char *) psource, 
+               memcpy_toio((char *) (dimm_mmio), (char *) psource,
                            window_size / 4);
                writel(0x01, mmio + PDC_GENERAL_CTLR);
                readl(mmio + PDC_GENERAL_CTLR);
@@ -1019,7 +1031,7 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
                size -= window_size;
                idx ++;
        }
-    
+
        if (size) {
                writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
                readl(mmio + PDC_DIMM_WINDOW_CTLR);
@@ -1030,12 +1042,12 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
 }
 
 
-static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, 
+static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
                                      u32 subaddr, u32 *pdata)
 {
-       void *mmio = pe->mmio_base;
+       void __iomem *mmio = pe->mmio_base;
        u32 i2creg  = 0;
-       u32 status;     
+       u32 status;
        u32 count =0;
 
        /* hard-code chip #0 */
@@ -1049,7 +1061,7 @@ static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
        readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
 
        /* Write Control to perform read operation, mask int */
-       writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT, 
+       writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT,
               mmio + PDC_I2C_CONTROL_OFFSET);
 
        for (count = 0; count <= 1000; count ++) {
@@ -1062,26 +1074,26 @@ static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
        }
 
        *pdata = (status >> 8) & 0x000000ff;
-       return 1;           
+       return 1;
 }
 
 
 static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
 {
        u32 data=0 ;
-       if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 
+       if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
                             PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {
                if (data == 100)
                        return 100;
        } else
                return 0;
-       
+
        if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
-               if(data <= 0x75) 
+               if(data <= 0x75)
                        return 133;
        } else
                return 0;
-       
+
        return 0;
 }
 
@@ -1091,15 +1103,15 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
        u32 spd0[50];
        u32 data = 0;
        int size, i;
-       u8 bdimmsize; 
-       void *mmio = pe->mmio_base;
+       u8 bdimmsize;
+       void __iomem *mmio = pe->mmio_base;
        static const struct {
                unsigned int reg;
                unsigned int ofs;
        } pdc_i2c_read_data [] = {
-               { PDC_DIMM_SPD_TYPE, 11 },              
+               { PDC_DIMM_SPD_TYPE, 11 },
                { PDC_DIMM_SPD_FRESH_RATE, 12 },
-               { PDC_DIMM_SPD_COLUMN_NUM, 4 }, 
+               { PDC_DIMM_SPD_COLUMN_NUM, 4 },
                { PDC_DIMM_SPD_ATTRIBUTE, 21 },
                { PDC_DIMM_SPD_ROW_NUM, 3 },
                { PDC_DIMM_SPD_BANK_NUM, 17 },
@@ -1108,7 +1120,7 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
                { PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 },
                { PDC_DIMM_SPD_RAS_CAS_DELAY, 29 },
                { PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 },
-               { PDC_DIMM_SPD_CAS_LATENCY, 18 },       
+               { PDC_DIMM_SPD_CAS_LATENCY, 18 },
        };
 
        /* hard-code chip #0 */
@@ -1116,17 +1128,17 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
 
        for(i=0; i<ARRAY_SIZE(pdc_i2c_read_data); i++)
                pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
-                                 pdc_i2c_read_data[i].reg, 
+                                 pdc_i2c_read_data[i].reg,
                                  &spd0[pdc_i2c_read_data[i].ofs]);
-  
+
        data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4);
-       data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) | 
+       data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) |
                ((((spd0[27] + 9) / 10) - 1) << 8) ;
-       data |= (((((spd0[29] > spd0[28]) 
-                   ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10; 
+       data |= (((((spd0[29] > spd0[28])
+                   ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10;
        data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12;
-   
-       if (spd0[18] & 0x08) 
+
+       if (spd0[18] & 0x08)
                data |= ((0x03) << 14);
        else if (spd0[18] & 0x04)
                data |= ((0x02) << 14);
@@ -1135,7 +1147,7 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
        else
                data |= (0 << 14);
 
-       /* 
+       /*
           Calculate the size of bDIMMSize (power of 2) and
           merge the DIMM size by program start/end address.
        */
@@ -1145,9 +1157,9 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
        data |= (((size / 16) - 1) << 16);
        data |= (0 << 23);
        data |= 8;
-       writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET); 
+       writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET);
        readl(mmio + PDC_DIMM0_CONTROL_OFFSET);
-       return size;                          
+       return size;
 }
 
 
@@ -1155,7 +1167,7 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
 {
        u32 data, spd0;
        int error, i;
-       void *mmio = pe->mmio_base;
+       void __iomem *mmio = pe->mmio_base;
 
        /* hard-code chip #0 */
        mmio += PDC_CHIP0_OFS;
@@ -1167,12 +1179,12 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
          Refresh Enable (bit 17)
        */
 
-       data = 0x022259F1;   
+       data = 0x022259F1;
        writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
        readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
 
        /* Turn on for ECC */
-       pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 
+       pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
                          PDC_DIMM_SPD_TYPE, &spd0);
        if (spd0 == 0x02) {
                data |= (0x01 << 16);
@@ -1186,22 +1198,22 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
        data |= (1<<19);
        writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
 
-       error = 1;                     
+       error = 1;
        for (i = 1; i <= 10; i++) {   /* polling ~5 secs */
                data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
                if (!(data & (1<<19))) {
                        error = 0;
-                       break;     
+                       break;
                }
                msleep(i*100);
        }
        return error;
 }
-       
+
 
 static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
 {
-       int speed, size, length; 
+       int speed, size, length;
        u32 addr,spd0,pci_status;
        u32 tmp=0;
        u32 time_period=0;
@@ -1209,7 +1221,7 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
        u32 ticks=0;
        u32 clock=0;
        u32 fparam=0;
-       void *mmio = pe->mmio_base;
+       void __iomem *mmio = pe->mmio_base;
 
        /* hard-code chip #0 */
        mmio += PDC_CHIP0_OFS;
@@ -1228,7 +1240,7 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
        /* Wait 3 seconds */
        msleep(3000);
 
-       /* 
+       /*
           When timer is enabled, counter is decreased every internal
           clock cycle.
        */
@@ -1236,24 +1248,24 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
        tcount = readl(mmio + PDC_TIME_COUNTER);
        VPRINTK("Time Counter Register (0x44): 0x%x\n", tcount);
 
-       /* 
+       /*
           If SX4 is on PCI-X bus, after 3 seconds, the timer counter
           register should be >= (0xffffffff - 3x10^8).
        */
        if(tcount >= PCI_X_TCOUNT) {
                ticks = (time_period - tcount);
                VPRINTK("Num counters 0x%x (%d)\n", ticks, ticks);
-       
+
                clock = (ticks / 300000);
                VPRINTK("10 * Internal clk = 0x%x (%d)\n", clock, clock);
-               
+
                clock = (clock * 33);
                VPRINTK("10 * Internal clk * 33 = 0x%x (%d)\n", clock, clock);
 
                /* PLL F Param (bit 22:16) */
                fparam = (1400000 / clock) - 2;
                VPRINTK("PLL F Param: 0x%x (%d)\n", fparam, fparam);
-               
+
                /* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */
                pci_status = (0x8a001824 | (fparam << 16));
        } else
@@ -1264,21 +1276,21 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
        writel(pci_status, mmio + PDC_CTL_STATUS);
        readl(mmio + PDC_CTL_STATUS);
 
-       /* 
+       /*
           Read SPD of DIMM by I2C interface,
           and program the DIMM Module Controller.
        */
        if (!(speed = pdc20621_detect_dimm(pe))) {
-               printk(KERN_ERR "Detect Local DIMM Fail\n");  
+               printk(KERN_ERR "Detect Local DIMM Fail\n");
                return 1;       /* DIMM error */
        }
        VPRINTK("Local DIMM Speed = %d\n", speed);
 
-       /* Programming DIMM0 Module Control Register (index_CID0:80h) */ 
+       /* Programming DIMM0 Module Control Register (index_CID0:80h) */
        size = pdc20621_prog_dimm0(pe);
        VPRINTK("Local DIMM Size = %dMB\n",size);
 
-       /* Programming DIMM Module Global Control Register (index_CID0:88h) */ 
+       /* Programming DIMM Module Global Control Register (index_CID0:88h) */
        if (pdc20621_prog_dimm_global(pe)) {
                printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");
                return 1;
@@ -1297,30 +1309,30 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
 
                pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40);
                pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
-               printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], 
+               printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
                       test_parttern2[1], &(test_parttern2[2]));
-               pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040, 
+               pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040,
                                       40);
-               printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], 
+               printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
                       test_parttern2[1], &(test_parttern2[2]));
 
                pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40);
                pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
-               printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], 
+               printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
                       test_parttern2[1], &(test_parttern2[2]));
        }
 #endif
 
        /* ECC initiliazation. */
 
-       pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 
+       pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
                          PDC_DIMM_SPD_TYPE, &spd0);
        if (spd0 == 0x02) {
                VPRINTK("Start ECC initialization\n");
                addr = 0;
                length = size * 1024 * 1024;
                while (addr < length) {
-                       pdc20621_put_to_dimm(pe, (void *) &tmp, addr, 
+                       pdc20621_put_to_dimm(pe, (void *) &tmp, addr,
                                             sizeof(u32));
                        addr += sizeof(u32);
                }
@@ -1333,7 +1345,7 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
 static void pdc_20621_init(struct ata_probe_ent *pe)
 {
        u32 tmp;
-       void *mmio = pe->mmio_base;
+       void __iomem *mmio = pe->mmio_base;
 
        /* hard-code chip #0 */
        mmio += PDC_CHIP0_OFS;
@@ -1366,7 +1378,8 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
        static int printed_version;
        struct ata_probe_ent *probe_ent = NULL;
        unsigned long base;
-       void *mmio_base, *dimm_mmio = NULL;
+       void __iomem *mmio_base;
+       void __iomem *dimm_mmio = NULL;
        struct pdc_host_priv *hpriv = NULL;
        unsigned int board_idx = (unsigned int) ent->driver_data;
        int pci_dev_busy = 0;
@@ -1406,8 +1419,7 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
        probe_ent->dev = pci_dev_to_dev(pdev);
        INIT_LIST_HEAD(&probe_ent->node);
 
-       mmio_base = ioremap(pci_resource_start(pdev, 3),
-                           pci_resource_len(pdev, 3));
+       mmio_base = pci_iomap(pdev, 3, 0);
        if (mmio_base == NULL) {
                rc = -ENOMEM;
                goto err_out_free_ent;
@@ -1421,8 +1433,7 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
        }
        memset(hpriv, 0, sizeof(*hpriv));
 
-       dimm_mmio = ioremap(pci_resource_start(pdev, 4),
-                           pci_resource_len(pdev, 4));
+       dimm_mmio = pci_iomap(pdev, 4, 0);
        if (!dimm_mmio) {
                kfree(hpriv);
                rc = -ENOMEM;
@@ -1469,9 +1480,9 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
 
 err_out_iounmap_dimm:          /* only get to this label if 20621 */
        kfree(hpriv);
-       iounmap(dimm_mmio);
+       pci_iounmap(pdev, dimm_mmio);
 err_out_iounmap:
-       iounmap(mmio_base);
+       pci_iounmap(pdev, mmio_base);
 err_out_free_ent:
        kfree(probe_ent);
 err_out_regions:
index a71fb54eebd301e07240310964a323b240db670d..42e13ed8eb5b55a9f9a473b19408bae775328e85 100644 (file)
@@ -1,21 +1,26 @@
 /*
  *  sata_uli.c - ULi Electronics SATA
  *
- *  The contents of this file are subject to the Open
- *  Software License version 1.1 that can be found at
- *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
- *  by reference.
  *
- *  Alternatively, the contents of this file may be used under the terms
- *  of the GNU General Public License version 2 (the "GPL") as distributed
- *  in the kernel source COPYING file, in which case the provisions of
- *  the GPL are applicable instead of the above.  If you wish to allow
- *  the use of your version of this file only under the terms of the
- *  GPL and not to allow others to use your version of this file under
- *  the OSL, indicate your decision by deleting the provisions above and
- *  replace them with the notice and other provisions required by the GPL.
- *  If you do not delete the provisions above, a recipient may use your
- *  version of this file under either the OSL or the GPL.
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
+ *  Hardware documentation available under NDA.
  *
  */
 
@@ -120,8 +125,8 @@ static struct ata_port_info uli_port_info = {
        .sht            = &uli_sht,
        .host_flags     = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
                          ATA_FLAG_NO_LEGACY,
-       .pio_mask       = 0x03,         //support pio mode 4 (FIXME)
-       .udma_mask      = 0x7f,         //support udma mode 6
+       .pio_mask       = 0x1f,         /* pio0-4 */
+       .udma_mask      = 0x7f,         /* udma0-6 */
        .port_ops       = &uli_ops,
 };
 
@@ -214,7 +219,7 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                rc = -ENOMEM;
                goto err_out_regions;
        }
-       
+
        switch (board_idx) {
        case uli_5287:
                probe_ent->port[0].scr_addr = ULI5287_BASE;
index f43183c19a12184ebd6902eadf154bc836a7e249..128b996b07b70167e3c928a62c035249cbc2e34f 100644 (file)
@@ -1,34 +1,38 @@
 /*
-   sata_via.c - VIA Serial ATA controllers
-
-   Maintained by:  Jeff Garzik <jgarzik@pobox.com>
                 Please ALWAYS copy linux-ide@vger.kernel.org
*  sata_via.c - VIA Serial ATA controllers
+ *
*  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
*                Please ALWAYS copy linux-ide@vger.kernel.org
                   on emails.
-
-   Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
-   Copyright 2003-2004 Jeff Garzik
-
-   The contents of this file are subject to the Open
-   Software License version 1.1 that can be found at
-   http://www.opensource.org/licenses/osl-1.1.txt and is included herein
-   by reference.
-
-   Alternatively, the contents of this file may be used under the terms
-   of the GNU General Public License version 2 (the "GPL") as distributed
-   in the kernel source COPYING file, in which case the provisions of
-   the GPL are applicable instead of the above.  If you wish to allow
-   the use of your version of this file only under the terms of the
-   GPL and not to allow others to use your version of this file under
-   the OSL, indicate your decision by deleting the provisions above and
-   replace them with the notice and other provisions required by the GPL.
-   If you do not delete the provisions above, a recipient may use your
-   version of this file under either the OSL or the GPL.
-
-   ----------------------------------------------------------------------
-
-   To-do list:
-   * VT6421 PATA support
-
+ *
+ *  Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+ *  Copyright 2003-2004 Jeff Garzik
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
+ *  Hardware documentation available under NDA.
+ *
+ *
+ *  To-do list:
+ *  - VT6421 PATA support
+ *
  */
 
 #include <linux/kernel.h>
@@ -347,7 +351,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                probe_ent = vt6420_init_probe_ent(pdev);
        else
                probe_ent = vt6421_init_probe_ent(pdev);
-       
+
        if (!probe_ent) {
                printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
                       pci_name(pdev));
index c5e09dc6f3de67b3250250d7f064ff873d679bb6..cf94e0158a8df5820a28214c92bcf35842fdb33f 100644 (file)
@@ -9,9 +9,29 @@
  *
  *  Bits from Jeff Garzik, Copyright RedHat, Inc.
  *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file "COPYING" in the main directory of this archive
- *  for more details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
+ *  Vitesse hardware documentation presumably available under NDA.
+ *  Intel 31244 (same hardware interface) documentation presumably
+ *  available from http://developer.intel.com/
+ *
  */
 
 #include <linux/kernel.h>
@@ -173,7 +193,8 @@ static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance,
                        struct ata_port *ap;
 
                        ap = host_set->ports[i];
-                       if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+                       if (ap && !(ap->flags &
+                                   (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) {
                                struct ata_queued_cmd *qc;
 
                                qc = ata_qc_from_tag(ap, ap->active_tag);
@@ -231,7 +252,7 @@ static struct ata_port_operations vsc_sata_ops = {
        .scr_write              = vsc_sata_scr_write,
        .port_start             = ata_port_start,
        .port_stop              = ata_port_stop,
-       .host_stop              = ata_host_stop,
+       .host_stop              = ata_pci_host_stop,
 };
 
 static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base)
@@ -305,8 +326,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
        probe_ent->dev = pci_dev_to_dev(pdev);
        INIT_LIST_HEAD(&probe_ent->node);
 
-       mmio_base = ioremap(pci_resource_start(pdev, 0),
-                           pci_resource_len(pdev, 0));
+       mmio_base = pci_iomap(pdev, 0, 0);
        if (mmio_base == NULL) {
                rc = -ENOMEM;
                goto err_out_free_ent;
@@ -342,7 +362,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
 
        pci_set_master(pdev);
 
-       /* 
+       /*
         * Config offset 0x98 is "Extended Control and Status Register 0"
         * Default value is (1 << 28).  All bits except bit 28 are reserved in
         * DPA mode.  If bit 28 is set, LED 0 reflects all ports' activity.
index 0b10169961ebfe2898efecb192a00c5a47c4b1df..aec39fb261cae9c6b14ada4e5608d67c8b4b672f 100644 (file)
@@ -58,8 +58,7 @@ static const char serial21285_name[] = "Footbridge UART";
  *  int((BAUD_BASE - (baud >> 1)) / baud)
  */
 
-static void
-serial21285_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void serial21285_stop_tx(struct uart_port *port)
 {
        if (tx_enabled(port)) {
                disable_irq(IRQ_CONTX);
@@ -67,8 +66,7 @@ serial21285_stop_tx(struct uart_port *port, unsigned int tty_stop)
        }
 }
 
-static void
-serial21285_start_tx(struct uart_port *port, unsigned int tty_start)
+static void serial21285_start_tx(struct uart_port *port)
 {
        if (!tx_enabled(port)) {
                enable_irq(IRQ_CONTX);
@@ -148,7 +146,7 @@ static irqreturn_t serial21285_tx_chars(int irq, void *dev_id, struct pt_regs *r
                goto out;
        }
        if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               serial21285_stop_tx(port, 0);
+               serial21285_stop_tx(port);
                goto out;
        }
 
@@ -164,7 +162,7 @@ static irqreturn_t serial21285_tx_chars(int irq, void *dev_id, struct pt_regs *r
                uart_write_wakeup(port);
 
        if (uart_circ_empty(xmit))
-               serial21285_stop_tx(port, 0);
+               serial21285_stop_tx(port);
 
  out:
        return IRQ_HANDLED;
index 9097f2f7b12a6bb5a1dbfb88a79c6a40ed14051b..2efb317153ce19a8ca7d974c3b18b03bddb62c60 100644 (file)
@@ -40,7 +40,6 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <asm/delay.h>
 #include <asm/uaccess.h>
 
index b116122e569ab3592b5e3abaa23f24d83c39e9d5..170c9d2a749cc1ce8f2c3820dd603435bbcbf7ad 100644 (file)
@@ -2474,8 +2474,7 @@ static struct tty_operations rs_360_ops = {
        .tiocmset = rs_360_tiocmset,
 };
 
-/* int __init rs_360_init(void) */
-int rs_360_init(void)
+static int __init rs_360_init(void)
 {
        struct serial_state * state;
        ser_info_t      *info;
@@ -2827,10 +2826,7 @@ int rs_360_init(void)
 
        return 0;
 }
-
-
-
-
+module_init(rs_360_init);
 
 /* This must always be called before the rs_360_init() function, otherwise
  * it blows away the port control information.
index 7e8fc7c1d4cc79768b3eb53da4f338ba09d80dc4..30a0a3d1014527b991025958b7a2d36ab98cdac7 100644 (file)
@@ -1001,7 +1001,7 @@ static inline void __stop_tx(struct uart_8250_port *p)
        }
 }
 
-static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void serial8250_stop_tx(struct uart_port *port)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)port;
 
@@ -1018,7 +1018,7 @@ static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop)
 
 static void transmit_chars(struct uart_8250_port *up);
 
-static void serial8250_start_tx(struct uart_port *port, unsigned int tty_start)
+static void serial8250_start_tx(struct uart_port *port)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)port;
 
@@ -1158,7 +1158,11 @@ static _INLINE_ void transmit_chars(struct uart_8250_port *up)
                up->port.x_char = 0;
                return;
        }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+       if (uart_tx_stopped(&up->port)) {
+               serial8250_stop_tx(&up->port);
+               return;
+       }
+       if (uart_circ_empty(xmit)) {
                __stop_tx(up);
                return;
        }
@@ -2586,82 +2590,3 @@ module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444);
 MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
 #endif
 MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
-
-/**
- *     register_serial - configure a 16x50 serial port at runtime
- *     @req: request structure
- *
- *     Configure the serial port specified by the request. If the
- *     port exists and is in use an error is returned. If the port
- *     is not currently in the table it is added.
- *
- *     The port is then probed and if necessary the IRQ is autodetected
- *     If this fails an error is returned.
- *
- *     On success the port is ready to use and the line number is returned.
- *
- *     Note: this function is deprecated - use serial8250_register_port
- *     instead.
- */
-int register_serial(struct serial_struct *req)
-{
-       struct uart_port port;
-
-       port.iobase   = req->port;
-       port.membase  = req->iomem_base;
-       port.irq      = req->irq;
-       port.uartclk  = req->baud_base * 16;
-       port.fifosize = req->xmit_fifo_size;
-       port.regshift = req->iomem_reg_shift;
-       port.iotype   = req->io_type;
-       port.flags    = req->flags | UPF_BOOT_AUTOCONF;
-       port.mapbase  = req->iomap_base;
-       port.dev      = NULL;
-
-       if (share_irqs)
-               port.flags |= UPF_SHARE_IRQ;
-
-       if (HIGH_BITS_OFFSET)
-               port.iobase |= (long) req->port_high << HIGH_BITS_OFFSET;
-
-       /*
-        * If a clock rate wasn't specified by the low level driver, then
-        * default to the standard clock rate.  This should be 115200 (*16)
-        * and should not depend on the architecture's BASE_BAUD definition.
-        * However, since this API will be deprecated, it's probably a
-        * better idea to convert the drivers to use the new API
-        * (serial8250_register_port and serial8250_unregister_port).
-        */
-       if (port.uartclk == 0) {
-               printk(KERN_WARNING
-                      "Serial: registering port at [%08x,%08lx,%p] irq %d with zero baud_base\n",
-                      port.iobase, port.mapbase, port.membase, port.irq);
-               printk(KERN_WARNING "Serial: see %s:%d for more information\n",
-                      __FILE__, __LINE__);
-               dump_stack();
-
-               /*
-                * Fix it up for now, but this is only a temporary measure.
-                */
-               port.uartclk = BASE_BAUD * 16;
-       }
-
-       return serial8250_register_port(&port);
-}
-EXPORT_SYMBOL(register_serial);
-
-/**
- *     unregister_serial - remove a 16x50 serial port at runtime
- *     @line: serial line number
- *
- *     Remove one serial port.  This may not be called from interrupt
- *     context.  We hand the port back to our local PM control.
- *
- *     Note: this function is deprecated - use serial8250_unregister_port
- *     instead.
- */
-void unregister_serial(int line)
-{
-       serial8250_unregister_port(line);
-}
-EXPORT_SYMBOL(unregister_serial);
index 9225c82faeb8e13b7b88b8a7b5e81a409c72aca3..b1b459efda524fa27f2743b848497d48c3bf953a 100644 (file)
  */
 
 #include <linux/config.h>
-
-int serial8250_register_port(struct uart_port *);
-void serial8250_unregister_port(int line);
-void serial8250_suspend_port(int line);
-void serial8250_resume_port(int line);
+#include <linux/serial_8250.h>
 
 struct old_serial_port {
        unsigned int uart;
index 07f05e9d0955eb12ae58705a09ffa4d20b05531d..0e21f583690ebdeffa57f316bd8fba2c67da8e71 100644 (file)
 
 #undef SERIAL_DEBUG_PCI
 
-/*
- * Definitions for PCI support.
- */
-#define FL_BASE_MASK           0x0007
-#define FL_BASE0               0x0000
-#define FL_BASE1               0x0001
-#define FL_BASE2               0x0002
-#define FL_BASE3               0x0003
-#define FL_BASE4               0x0004
-#define FL_GET_BASE(x)         (x & FL_BASE_MASK)
-
-/* Use successive BARs (PCI base address registers),
-   else use offset into some specified BAR */
-#define FL_BASE_BARS           0x0008
-
-/* do not assign an irq */
-#define FL_NOIRQ               0x0080
-
-/* Use the Base address register size to cap number of ports */
-#define FL_REGION_SZ_CAP       0x0100
-
-struct pci_board {
-       unsigned int flags;
-       unsigned int num_ports;
-       unsigned int base_baud;
-       unsigned int uart_offset;
-       unsigned int reg_shift;
-       unsigned int first_offset;
-};
-
 /*
  * init function returns:
  *  > 0 - number of ports
@@ -75,14 +45,15 @@ struct pci_serial_quirk {
        u32     subvendor;
        u32     subdevice;
        int     (*init)(struct pci_dev *dev);
-       int     (*setup)(struct pci_dev *dev, struct pci_board *board,
-                        struct uart_port *port, int idx);
+       int     (*setup)(struct serial_private *, struct pciserial_board *,
+                        struct uart_port *, int);
        void    (*exit)(struct pci_dev *dev);
 };
 
 #define PCI_NUM_BAR_RESOURCES  6
 
 struct serial_private {
+       struct pci_dev          *dev;
        unsigned int            nr;
        void __iomem            *remapped_bar[PCI_NUM_BAR_RESOURCES];
        struct pci_serial_quirk *quirk;
@@ -101,17 +72,18 @@ static void moan_device(const char *str, struct pci_dev *dev)
 }
 
 static int
-setup_port(struct pci_dev *dev, struct uart_port *port,
+setup_port(struct serial_private *priv, struct uart_port *port,
           int bar, int offset, int regshift)
 {
-       struct serial_private *priv = pci_get_drvdata(dev);
+       struct pci_dev *dev = priv->dev;
        unsigned long base, len;
 
        if (bar >= PCI_NUM_BAR_RESOURCES)
                return -EINVAL;
 
+       base = pci_resource_start(dev, bar);
+
        if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
-               base = pci_resource_start(dev, bar);
                len =  pci_resource_len(dev, bar);
 
                if (!priv->remapped_bar[bar])
@@ -120,13 +92,16 @@ setup_port(struct pci_dev *dev, struct uart_port *port,
                        return -ENOMEM;
 
                port->iotype = UPIO_MEM;
+               port->iobase = 0;
                port->mapbase = base + offset;
                port->membase = priv->remapped_bar[bar] + offset;
                port->regshift = regshift;
        } else {
-               base = pci_resource_start(dev, bar) + offset;
                port->iotype = UPIO_PORT;
-               port->iobase = base;
+               port->iobase = base + offset;
+               port->mapbase = 0;
+               port->membase = NULL;
+               port->regshift = 0;
        }
        return 0;
 }
@@ -136,7 +111,7 @@ setup_port(struct pci_dev *dev, struct uart_port *port,
  * Not that ugly ;) -- HW
  */
 static int
-afavlab_setup(struct pci_dev *dev, struct pci_board *board,
+afavlab_setup(struct serial_private *priv, struct pciserial_board *board,
              struct uart_port *port, int idx)
 {
        unsigned int bar, offset = board->first_offset;
@@ -149,7 +124,7 @@ afavlab_setup(struct pci_dev *dev, struct pci_board *board,
                offset += (idx - 4) * board->uart_offset;
        }
 
-       return setup_port(dev, port, bar, offset, board->reg_shift);
+       return setup_port(priv, port, bar, offset, board->reg_shift);
 }
 
 /*
@@ -189,13 +164,13 @@ static int __devinit pci_hp_diva_init(struct pci_dev *dev)
  * some serial ports are supposed to be hidden on certain models.
  */
 static int
-pci_hp_diva_setup(struct pci_dev *dev, struct pci_board *board,
+pci_hp_diva_setup(struct serial_private *priv, struct pciserial_board *board,
              struct uart_port *port, int idx)
 {
        unsigned int offset = board->first_offset;
        unsigned int bar = FL_GET_BASE(board->flags);
 
-       switch (dev->subsystem_device) {
+       switch (priv->dev->subsystem_device) {
        case PCI_DEVICE_ID_HP_DIVA_MAESTRO:
                if (idx == 3)
                        idx++;
@@ -212,7 +187,7 @@ pci_hp_diva_setup(struct pci_dev *dev, struct pci_board *board,
 
        offset += idx * board->uart_offset;
 
-       return setup_port(dev, port, bar, offset, board->reg_shift);
+       return setup_port(priv, port, bar, offset, board->reg_shift);
 }
 
 /*
@@ -307,7 +282,7 @@ static void __devexit pci_plx9050_exit(struct pci_dev *dev)
 
 /* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */
 static int
-sbs_setup(struct pci_dev *dev, struct pci_board *board,
+sbs_setup(struct serial_private *priv, struct pciserial_board *board,
                struct uart_port *port, int idx)
 {
        unsigned int bar, offset = board->first_offset;
@@ -323,7 +298,7 @@ sbs_setup(struct pci_dev *dev, struct pci_board *board,
        } else /* we have only 8 ports on PMC-OCTALPRO */
                return 1;
 
-       return setup_port(dev, port, bar, offset, board->reg_shift);
+       return setup_port(priv, port, bar, offset, board->reg_shift);
 }
 
 /*
@@ -389,6 +364,9 @@ static void __devexit sbs_exit(struct pci_dev *dev)
  *     - 10x cards have control registers in IO and/or memory space;
  *     - 20x cards have control registers in standard PCI configuration space.
  *
+ * Note: all 10x cards have PCI device ids 0x10..
+ *       all 20x cards have PCI device ids 0x20..
+ *
  * There are also Quartet Serial cards which use Oxford Semiconductor
  * 16954 quad UART PCI chip clocked by 18.432 MHz quartz.
  *
@@ -445,24 +423,18 @@ static int pci_siig20x_init(struct pci_dev *dev)
        return 0;
 }
 
-int pci_siig10x_fn(struct pci_dev *dev, int enable)
+static int pci_siig_init(struct pci_dev *dev)
 {
-       int ret = 0;
-       if (enable)
-               ret = pci_siig10x_init(dev);
-       return ret;
-}
+       unsigned int type = dev->device & 0xff00;
 
-int pci_siig20x_fn(struct pci_dev *dev, int enable)
-{
-       int ret = 0;
-       if (enable)
-               ret = pci_siig20x_init(dev);
-       return ret;
-}
+       if (type == 0x1000)
+               return pci_siig10x_init(dev);
+       else if (type == 0x2000)
+               return pci_siig20x_init(dev);
 
-EXPORT_SYMBOL(pci_siig10x_fn);
-EXPORT_SYMBOL(pci_siig20x_fn);
+       moan_device("Unknown SIIG card", dev);
+       return -ENODEV;
+}
 
 /*
  * Timedia has an explosion of boards, and to avoid the PCI table from
@@ -523,7 +495,7 @@ static int __devinit pci_timedia_init(struct pci_dev *dev)
  * Ugh, this is ugly as all hell --- TYT
  */
 static int
-pci_timedia_setup(struct pci_dev *dev, struct pci_board *board,
+pci_timedia_setup(struct serial_private *priv, struct pciserial_board *board,
                  struct uart_port *port, int idx)
 {
        unsigned int bar = 0, offset = board->first_offset;
@@ -549,14 +521,15 @@ pci_timedia_setup(struct pci_dev *dev, struct pci_board *board,
                bar = idx - 2;
        }
 
-       return setup_port(dev, port, bar, offset, board->reg_shift);
+       return setup_port(priv, port, bar, offset, board->reg_shift);
 }
 
 /*
  * Some Titan cards are also a little weird
  */
 static int
-titan_400l_800l_setup(struct pci_dev *dev, struct pci_board *board,
+titan_400l_800l_setup(struct serial_private *priv,
+                     struct pciserial_board *board,
                      struct uart_port *port, int idx)
 {
        unsigned int bar, offset = board->first_offset;
@@ -573,7 +546,7 @@ titan_400l_800l_setup(struct pci_dev *dev, struct pci_board *board,
                offset = (idx - 2) * board->uart_offset;
        }
 
-       return setup_port(dev, port, bar, offset, board->reg_shift);
+       return setup_port(priv, port, bar, offset, board->reg_shift);
 }
 
 static int __devinit pci_xircom_init(struct pci_dev *dev)
@@ -593,7 +566,7 @@ static int __devinit pci_netmos_init(struct pci_dev *dev)
 }
 
 static int
-pci_default_setup(struct pci_dev *dev, struct pci_board *board,
+pci_default_setup(struct serial_private *priv, struct pciserial_board *board,
                  struct uart_port *port, int idx)
 {
        unsigned int bar, offset = board->first_offset, maxnr;
@@ -604,13 +577,13 @@ pci_default_setup(struct pci_dev *dev, struct pci_board *board,
        else
                offset += idx * board->uart_offset;
 
-       maxnr = (pci_resource_len(dev, bar) - board->first_offset) /
+       maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) /
                (8 << board->reg_shift);
 
        if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
                return 1;
                        
-       return setup_port(dev, port, bar, offset, board->reg_shift);
+       return setup_port(priv, port, bar, offset, board->reg_shift);
 }
 
 /* This should be in linux/pci_ids.h */
@@ -754,152 +727,15 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
                .setup          = sbs_setup,
                .exit           = __devexit_p(sbs_exit),
        },
-
        /*
         * SIIG cards.
-        *  It is not clear whether these could be collapsed.
         */
        {
                .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_DEVICE_ID_SIIG_1S_10x_550,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig10x_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_DEVICE_ID_SIIG_1S_10x_650,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig10x_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_DEVICE_ID_SIIG_1S_10x_850,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig10x_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_DEVICE_ID_SIIG_2S_10x_550,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig10x_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_DEVICE_ID_SIIG_2S_10x_650,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig10x_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_DEVICE_ID_SIIG_2S_10x_850,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig10x_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_DEVICE_ID_SIIG_4S_10x_550,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig10x_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_DEVICE_ID_SIIG_4S_10x_650,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig10x_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_DEVICE_ID_SIIG_4S_10x_850,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig10x_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_DEVICE_ID_SIIG_1S_20x_550,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig20x_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_DEVICE_ID_SIIG_1S_20x_650,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig20x_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_DEVICE_ID_SIIG_1S_20x_850,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig20x_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_DEVICE_ID_SIIG_2S_20x_550,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig20x_init,
-               .setup          = pci_default_setup,
-       },
-       {       .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_DEVICE_ID_SIIG_2S_20x_650,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig20x_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_DEVICE_ID_SIIG_2S_20x_850,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig20x_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_DEVICE_ID_SIIG_4S_20x_550,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig20x_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_DEVICE_ID_SIIG_4S_20x_650,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig20x_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_DEVICE_ID_SIIG_4S_20x_850,
+               .device         = PCI_ANY_ID,
                .subvendor      = PCI_ANY_ID,
                .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig20x_init,
+               .init           = pci_siig_init,
                .setup          = pci_default_setup,
        },
        /*
@@ -990,7 +826,7 @@ static struct pci_serial_quirk *find_quirk(struct pci_dev *dev)
 }
 
 static _INLINE_ int
-get_pci_irq(struct pci_dev *dev, struct pci_board *board, int idx)
+get_pci_irq(struct pci_dev *dev, struct pciserial_board *board)
 {
        if (board->flags & FL_NOIRQ)
                return 0;
@@ -1115,7 +951,7 @@ enum pci_board_num_t {
  * see first lines of serial_in() and serial_out() in 8250.c
 */
 
-static struct pci_board pci_boards[] __devinitdata = {
+static struct pciserial_board pci_boards[] __devinitdata = {
        [pbn_default] = {
                .flags          = FL_BASE0,
                .num_ports      = 1,
@@ -1575,7 +1411,7 @@ static struct pci_board pci_boards[] __devinitdata = {
  * serial specs.  Returns 0 on success, 1 on failure.
  */
 static int __devinit
-serial_pci_guess_board(struct pci_dev *dev, struct pci_board *board)
+serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
 {
        int num_iomem, num_port, first_port = -1, i;
        
@@ -1640,7 +1476,8 @@ serial_pci_guess_board(struct pci_dev *dev, struct pci_board *board)
 }
 
 static inline int
-serial_pci_matches(struct pci_board *board, struct pci_board *guessed)
+serial_pci_matches(struct pciserial_board *board,
+                  struct pciserial_board *guessed)
 {
        return
            board->num_ports == guessed->num_ports &&
@@ -1650,58 +1487,14 @@ serial_pci_matches(struct pci_board *board, struct pci_board *guessed)
            board->first_offset == guessed->first_offset;
 }
 
-/*
- * Probe one serial board.  Unfortunately, there is no rhyme nor reason
- * to the arrangement of serial ports on a PCI card.
- */
-static int __devinit
-pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
+struct serial_private *
+pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board)
 {
+       struct uart_port serial_port;
        struct serial_private *priv;
-       struct pci_board *board, tmp;
        struct pci_serial_quirk *quirk;
        int rc, nr_ports, i;
 
-       if (ent->driver_data >= ARRAY_SIZE(pci_boards)) {
-               printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n",
-                       ent->driver_data);
-               return -EINVAL;
-       }
-
-       board = &pci_boards[ent->driver_data];
-
-       rc = pci_enable_device(dev);
-       if (rc)
-               return rc;
-
-       if (ent->driver_data == pbn_default) {
-               /*
-                * Use a copy of the pci_board entry for this;
-                * avoid changing entries in the table.
-                */
-               memcpy(&tmp, board, sizeof(struct pci_board));
-               board = &tmp;
-
-               /*
-                * We matched one of our class entries.  Try to
-                * determine the parameters of this board.
-                */
-               rc = serial_pci_guess_board(dev, board);
-               if (rc)
-                       goto disable;
-       } else {
-               /*
-                * We matched an explicit entry.  If we are able to
-                * detect this boards settings with our heuristic,
-                * then we no longer need this entry.
-                */
-               memcpy(&tmp, &pci_boards[pbn_default], sizeof(struct pci_board));
-               rc = serial_pci_guess_board(dev, &tmp);
-               if (rc == 0 && serial_pci_matches(board, &tmp))
-                       moan_device("Redundant entry in serial pci_table.",
-                                   dev);
-       }
-
        nr_ports = board->num_ports;
 
        /*
@@ -1718,8 +1511,10 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
         */
        if (quirk->init) {
                rc = quirk->init(dev);
-               if (rc < 0)
-                       goto disable;
+               if (rc < 0) {
+                       priv = ERR_PTR(rc);
+                       goto err_out;
+               }
                if (rc)
                        nr_ports = rc;
        }
@@ -1728,27 +1523,26 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
                       sizeof(unsigned int) * nr_ports,
                       GFP_KERNEL);
        if (!priv) {
-               rc = -ENOMEM;
-               goto deinit;
+               priv = ERR_PTR(-ENOMEM);
+               goto err_deinit;
        }
 
        memset(priv, 0, sizeof(struct serial_private) +
                        sizeof(unsigned int) * nr_ports);
 
+       priv->dev = dev;
        priv->quirk = quirk;
-       pci_set_drvdata(dev, priv);
+
+       memset(&serial_port, 0, sizeof(struct uart_port));
+       serial_port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+       serial_port.uartclk = board->base_baud * 16;
+       serial_port.irq = get_pci_irq(dev, board);
+       serial_port.dev = &dev->dev;
 
        for (i = 0; i < nr_ports; i++) {
-               struct uart_port serial_port;
-               memset(&serial_port, 0, sizeof(struct uart_port));
-
-               serial_port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF |
-                                   UPF_SHARE_IRQ;
-               serial_port.uartclk = board->base_baud * 16;
-               serial_port.irq = get_pci_irq(dev, board, i);
-               serial_port.dev = &dev->dev;
-               if (quirk->setup(dev, board, &serial_port, i))
+               if (quirk->setup(priv, board, &serial_port, i))
                        break;
+
 #ifdef SERIAL_DEBUG_PCI
                printk("Setup PCI port: port %x, irq %d, type %d\n",
                       serial_port.iobase, serial_port.irq, serial_port.iotype);
@@ -1763,24 +1557,21 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
 
        priv->nr = i;
 
-       return 0;
+       return priv;
 
- deinit:
err_deinit:
        if (quirk->exit)
                quirk->exit(dev);
- disable:
-       pci_disable_device(dev);
-       return rc;
+ err_out:
+       return priv;
 }
+EXPORT_SYMBOL_GPL(pciserial_init_ports);
 
-static void __devexit pciserial_remove_one(struct pci_dev *dev)
+void pciserial_remove_ports(struct serial_private *priv)
 {
-       struct serial_private *priv = pci_get_drvdata(dev);
        struct pci_serial_quirk *quirk;
        int i;
 
-       pci_set_drvdata(dev, NULL);
-
        for (i = 0; i < priv->nr; i++)
                serial8250_unregister_port(priv->line[i]);
 
@@ -1793,25 +1584,123 @@ static void __devexit pciserial_remove_one(struct pci_dev *dev)
        /*
         * Find the exit quirks.
         */
-       quirk = find_quirk(dev);
+       quirk = find_quirk(priv->dev);
        if (quirk->exit)
-               quirk->exit(dev);
+               quirk->exit(priv->dev);
+
+       kfree(priv);
+}
+EXPORT_SYMBOL_GPL(pciserial_remove_ports);
+
+void pciserial_suspend_ports(struct serial_private *priv)
+{
+       int i;
+
+       for (i = 0; i < priv->nr; i++)
+               if (priv->line[i] >= 0)
+                       serial8250_suspend_port(priv->line[i]);
+}
+EXPORT_SYMBOL_GPL(pciserial_suspend_ports);
+
+void pciserial_resume_ports(struct serial_private *priv)
+{
+       int i;
+
+       /*
+        * Ensure that the board is correctly configured.
+        */
+       if (priv->quirk->init)
+               priv->quirk->init(priv->dev);
+
+       for (i = 0; i < priv->nr; i++)
+               if (priv->line[i] >= 0)
+                       serial8250_resume_port(priv->line[i]);
+}
+EXPORT_SYMBOL_GPL(pciserial_resume_ports);
+
+/*
+ * Probe one serial board.  Unfortunately, there is no rhyme nor reason
+ * to the arrangement of serial ports on a PCI card.
+ */
+static int __devinit
+pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
+{
+       struct serial_private *priv;
+       struct pciserial_board *board, tmp;
+       int rc;
+
+       if (ent->driver_data >= ARRAY_SIZE(pci_boards)) {
+               printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n",
+                       ent->driver_data);
+               return -EINVAL;
+       }
+
+       board = &pci_boards[ent->driver_data];
+
+       rc = pci_enable_device(dev);
+       if (rc)
+               return rc;
+
+       if (ent->driver_data == pbn_default) {
+               /*
+                * Use a copy of the pci_board entry for this;
+                * avoid changing entries in the table.
+                */
+               memcpy(&tmp, board, sizeof(struct pciserial_board));
+               board = &tmp;
+
+               /*
+                * We matched one of our class entries.  Try to
+                * determine the parameters of this board.
+                */
+               rc = serial_pci_guess_board(dev, board);
+               if (rc)
+                       goto disable;
+       } else {
+               /*
+                * We matched an explicit entry.  If we are able to
+                * detect this boards settings with our heuristic,
+                * then we no longer need this entry.
+                */
+               memcpy(&tmp, &pci_boards[pbn_default],
+                      sizeof(struct pciserial_board));
+               rc = serial_pci_guess_board(dev, &tmp);
+               if (rc == 0 && serial_pci_matches(board, &tmp))
+                       moan_device("Redundant entry in serial pci_table.",
+                                   dev);
+       }
 
+       priv = pciserial_init_ports(dev, board);
+       if (!IS_ERR(priv)) {
+               pci_set_drvdata(dev, priv);
+               return 0;
+       }
+
+       rc = PTR_ERR(priv);
+
+ disable:
        pci_disable_device(dev);
+       return rc;
+}
 
-       kfree(priv);
+static void __devexit pciserial_remove_one(struct pci_dev *dev)
+{
+       struct serial_private *priv = pci_get_drvdata(dev);
+
+       pci_set_drvdata(dev, NULL);
+
+       pciserial_remove_ports(priv);
+
+       pci_disable_device(dev);
 }
 
 static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state)
 {
        struct serial_private *priv = pci_get_drvdata(dev);
 
-       if (priv) {
-               int i;
+       if (priv)
+               pciserial_suspend_ports(priv);
 
-               for (i = 0; i < priv->nr; i++)
-                       serial8250_suspend_port(priv->line[i]);
-       }
        pci_save_state(dev);
        pci_set_power_state(dev, pci_choose_state(dev, state));
        return 0;
@@ -1825,21 +1714,12 @@ static int pciserial_resume_one(struct pci_dev *dev)
        pci_restore_state(dev);
 
        if (priv) {
-               int i;
-
                /*
                 * The device may have been disabled.  Re-enable it.
                 */
                pci_enable_device(dev);
 
-               /*
-                * Ensure that the board is correctly configured.
-                */
-               if (priv->quirk->init)
-                       priv->quirk->init(dev);
-
-               for (i = 0; i < priv->nr; i++)
-                       serial8250_resume_port(priv->line[i]);
+               pciserial_resume_ports(priv);
        }
        return 0;
 }
index d5797618a3b918cc41e89187780d8d641fe49207..e39818a34a0754a824df7bb2e3e46878704e18cd 100644 (file)
@@ -308,7 +308,7 @@ config SERIAL_S3C2410_CONSOLE
 
 config SERIAL_DZ
        bool "DECstation DZ serial driver"
-       depends on MACH_DECSTATION && MIPS32
+       depends on MACH_DECSTATION && 32BIT
        select SERIAL_CORE
        help
          DZ11-family serial controllers for VAXstations, including the
@@ -830,7 +830,7 @@ config SERIAL_M32R_PLDSIO
 
 config SERIAL_TXX9
        bool "TMPTX39XX/49XX SIO support"
-       depends HAS_TXX9_SERIAL
+       depends HAS_TXX9_SERIAL && BROKEN
        select SERIAL_CORE
        default y
 
index 2884b310e54d2d01f50d012d4394343b08b5717a..978e12437e617df488ccd32352e41a457516961b 100644 (file)
@@ -105,7 +105,7 @@ struct uart_amba_port {
        unsigned int            old_status;
 };
 
-static void pl010_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void pl010_stop_tx(struct uart_port *port)
 {
        unsigned int cr;
 
@@ -114,7 +114,7 @@ static void pl010_stop_tx(struct uart_port *port, unsigned int tty_stop)
        UART_PUT_CR(port, cr);
 }
 
-static void pl010_start_tx(struct uart_port *port, unsigned int tty_start)
+static void pl010_start_tx(struct uart_port *port)
 {
        unsigned int cr;
 
@@ -219,7 +219,7 @@ static void pl010_tx_chars(struct uart_port *port)
                return;
        }
        if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               pl010_stop_tx(port, 0);
+               pl010_stop_tx(port);
                return;
        }
 
@@ -236,7 +236,7 @@ static void pl010_tx_chars(struct uart_port *port)
                uart_write_wakeup(port);
 
        if (uart_circ_empty(xmit))
-               pl010_stop_tx(port, 0);
+               pl010_stop_tx(port);
 }
 
 static void pl010_modem_status(struct uart_port *port)
index 7db88ee18f75fb1f138f71921c05d833aa935a51..56071309744c526322bc404f52159e8eae95738d 100644 (file)
@@ -74,7 +74,7 @@ struct uart_amba_port {
        unsigned int            old_status;
 };
 
-static void pl011_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void pl011_stop_tx(struct uart_port *port)
 {
        struct uart_amba_port *uap = (struct uart_amba_port *)port;
 
@@ -82,7 +82,7 @@ static void pl011_stop_tx(struct uart_port *port, unsigned int tty_stop)
        writew(uap->im, uap->port.membase + UART011_IMSC);
 }
 
-static void pl011_start_tx(struct uart_port *port, unsigned int tty_start)
+static void pl011_start_tx(struct uart_port *port)
 {
        struct uart_amba_port *uap = (struct uart_amba_port *)port;
 
@@ -184,7 +184,7 @@ static void pl011_tx_chars(struct uart_amba_port *uap)
                return;
        }
        if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
-               pl011_stop_tx(&uap->port, 0);
+               pl011_stop_tx(&uap->port);
                return;
        }
 
@@ -201,7 +201,7 @@ static void pl011_tx_chars(struct uart_amba_port *uap)
                uart_write_wakeup(&uap->port);
 
        if (uart_circ_empty(xmit))
-               pl011_stop_tx(&uap->port, 0);
+               pl011_stop_tx(&uap->port);
 }
 
 static void pl011_modem_status(struct uart_amba_port *uap)
index 6104aeef12439e156928a16f77267d2215b19d6f..a274ebf256a190fb6de6e94883a8807bbf31f752 100644 (file)
@@ -200,7 +200,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
        DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name);
 }
 
-static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void serial8250_stop_tx(struct uart_port *port)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)port;
 
@@ -210,7 +210,7 @@ static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop)
        }
 }
 
-static void serial8250_start_tx(struct uart_port *port, unsigned int tty_start)
+static void serial8250_start_tx(struct uart_port *port)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)port;
 
@@ -337,7 +337,7 @@ static _INLINE_ void transmit_chars(struct uart_8250_port *up)
                return;
        }
        if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               serial8250_stop_tx(&up->port, 0);
+               serial8250_stop_tx(&up->port);
                return;
        }
 
@@ -356,7 +356,7 @@ static _INLINE_ void transmit_chars(struct uart_8250_port *up)
        DEBUG_INTR("THRE...");
 
        if (uart_circ_empty(xmit))
-               serial8250_stop_tx(&up->port, 0);
+               serial8250_stop_tx(&up->port);
 }
 
 static _INLINE_ void check_modem_status(struct uart_8250_port *up)
index e92522b33c48e9e4e283b8fbd498d4e8b7e45c12..d822896b488c80c45f68738f237a000e5af76b50 100644 (file)
@@ -69,8 +69,7 @@
 
 #define tx_enabled(port)       ((port)->unused[0])
 
-static void
-clps711xuart_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void clps711xuart_stop_tx(struct uart_port *port)
 {
        if (tx_enabled(port)) {
                disable_irq(TX_IRQ(port));
@@ -78,8 +77,7 @@ clps711xuart_stop_tx(struct uart_port *port, unsigned int tty_stop)
        }
 }
 
-static void
-clps711xuart_start_tx(struct uart_port *port, unsigned int tty_start)
+static void clps711xuart_start_tx(struct uart_port *port)
 {
        if (!tx_enabled(port)) {
                enable_irq(TX_IRQ(port));
@@ -165,7 +163,7 @@ static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id, struct pt_regs *re
                return IRQ_HANDLED;
        }
        if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               clps711xuart_stop_tx(port, 0);
+               clps711xuart_stop_tx(port);
                return IRQ_HANDLED;
        }
 
@@ -182,7 +180,7 @@ static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id, struct pt_regs *re
                uart_write_wakeup(port);
 
        if (uart_circ_empty(xmit))
-               clps711xuart_stop_tx(port, 0);
+               clps711xuart_stop_tx(port);
 
        return IRQ_HANDLED;
 }
index d639ac92a117c73eec982310534d7b2b4d908df8..25825f2aba2279abc005ab49c11cfd59c9ab5390 100644 (file)
@@ -124,7 +124,7 @@ static unsigned int cpm_uart_get_mctrl(struct uart_port *port)
 /*
  * Stop transmitter
  */
-static void cpm_uart_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void cpm_uart_stop_tx(struct uart_port *port)
 {
        struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
        volatile smc_t *smcp = pinfo->smcp;
@@ -141,7 +141,7 @@ static void cpm_uart_stop_tx(struct uart_port *port, unsigned int tty_stop)
 /*
  * Start transmitter
  */
-static void cpm_uart_start_tx(struct uart_port *port, unsigned int tty_start)
+static void cpm_uart_start_tx(struct uart_port *port)
 {
        struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
        volatile smc_t *smcp = pinfo->smcp;
@@ -403,10 +403,8 @@ static int cpm_uart_startup(struct uart_port *port)
 
 inline void cpm_uart_wait_until_send(struct uart_cpm_port *pinfo)
 {
-       unsigned long target_jiffies = jiffies + pinfo->wait_closing;
-
-       while (!time_after(jiffies, target_jiffies))
-               schedule();
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout(pinfo->wait_closing);
 }
 
 /*
@@ -425,9 +423,12 @@ static void cpm_uart_shutdown(struct uart_port *port)
        /* If the port is not the console, disable Rx and Tx. */
        if (!(pinfo->flags & FLAG_CONSOLE)) {
                /* Wait for all the BDs marked sent */
-               while(!cpm_uart_tx_empty(port))
+               while(!cpm_uart_tx_empty(port)) {
+                       set_current_state(TASK_UNINTERRUPTIBLE);
                        schedule_timeout(2);
-               if(pinfo->wait_closing)
+               }
+
+               if (pinfo->wait_closing)
                        cpm_uart_wait_until_send(pinfo);
 
                /* Stop uarts */
@@ -623,7 +624,7 @@ static int cpm_uart_tx_pump(struct uart_port *port)
        }
 
        if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               cpm_uart_stop_tx(port, 0);
+               cpm_uart_stop_tx(port);
                return 0;
        }
 
@@ -656,7 +657,7 @@ static int cpm_uart_tx_pump(struct uart_port *port)
                uart_write_wakeup(port);
 
        if (uart_circ_empty(xmit)) {
-               cpm_uart_stop_tx(port, 0);
+               cpm_uart_stop_tx(port);
                return 0;
        }
 
index c4c8f4b44f53820a8a4ae3d3431f7c3da984b1ee..15ad58d94889f431bfc4899dea71a65b1d2f7e86 100644 (file)
@@ -142,12 +142,21 @@ void scc2_lineif(struct uart_cpm_port *pinfo)
         * be supported in a sane fashion.
         */
 #ifndef CONFIG_STX_GP3
+#ifdef CONFIG_MPC8560_ADS
+       volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
+       io->iop_ppard |= 0x00000018;
+       io->iop_psord &= ~0x00000008;   /* Rx */
+       io->iop_psord &= ~0x00000010;   /* Tx */
+       io->iop_pdird &= ~0x00000008;   /* Rx */
+       io->iop_pdird |= 0x00000010;    /* Tx */
+#else
        volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
        io->iop_pparb |= 0x008b0000;
        io->iop_pdirb |= 0x00880000;
        io->iop_psorb |= 0x00880000;
        io->iop_pdirb &= ~0x00030000;
        io->iop_psorb &= ~0x00030000;
+#endif
 #endif
        cpm2_immr->im_cpmux.cmx_scr &= 0xff00ffff;
        cpm2_immr->im_cpmux.cmx_scr |= 0x00090000;
@@ -257,6 +266,7 @@ int cpm_uart_init_portdesc(void)
        cpm_uart_ports[UART_SMC1].smcp = (smc_t *) & cpm2_immr->im_smc[0];
        cpm_uart_ports[UART_SMC1].smcup =
            (smc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SMC1];
+       *(u16 *)(&cpm2_immr->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1;
        cpm_uart_ports[UART_SMC1].port.mapbase =
            (unsigned long)&cpm2_immr->im_smc[0];
        cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
@@ -269,6 +279,7 @@ int cpm_uart_init_portdesc(void)
        cpm_uart_ports[UART_SMC2].smcp = (smc_t *) & cpm2_immr->im_smc[1];
        cpm_uart_ports[UART_SMC2].smcup =
            (smc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SMC2];
+       *(u16 *)(&cpm2_immr->im_dprambase[PROFF_SMC2_BASE]) = PROFF_SMC2;
        cpm_uart_ports[UART_SMC2].port.mapbase =
            (unsigned long)&cpm2_immr->im_smc[1];
        cpm_uart_ports[UART_SMC2].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
index 23b8871e74cc1cdee8869d3a6043d7eff92a23f5..40d3e7139cfea2518fff6c2a758e0bdc4c5cd53d 100644 (file)
@@ -446,7 +446,6 @@ static char *serial_version = "$Revision: 1.25 $";
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <asm/bitops.h>
 #include <linux/delay.h>
 
@@ -5041,17 +5040,3 @@ rs_init(void)
 /* this makes sure that rs_init is called during kernel boot */
 
 module_init(rs_init);
-
-/*
- * register_serial and unregister_serial allows for serial ports to be
- * configured at run-time, to support PCMCIA modems.
- */
-int
-register_serial(struct serial_struct *req)
-{
-       return -1;
-}
-
-void unregister_serial(int line)
-{
-}
index 97824eeeafae51bdeb93cda017b21e223b7c8c9e..e63b9dffc8d7304ecd6fcfaa2b363ffd07838131 100644 (file)
@@ -112,7 +112,7 @@ static inline void dz_out(struct dz_port *dport, unsigned offset,
  * ------------------------------------------------------------
  */
 
-static void dz_stop_tx(struct uart_port *uport, unsigned int tty_stop)
+static void dz_stop_tx(struct uart_port *uport)
 {
        struct dz_port *dport = (struct dz_port *)uport;
        unsigned short tmp, mask = 1 << dport->port.line;
@@ -125,7 +125,7 @@ static void dz_stop_tx(struct uart_port *uport, unsigned int tty_stop)
        spin_unlock_irqrestore(&dport->port.lock, flags);
 }
 
-static void dz_start_tx(struct uart_port *uport, unsigned int tty_start)
+static void dz_start_tx(struct uart_port *uport)
 {
        struct dz_port *dport = (struct dz_port *)uport;
        unsigned short tmp, mask = 1 << dport->port.line;
@@ -290,7 +290,7 @@ static inline void dz_transmit_chars(struct dz_port *dport)
        }
        /* if nothing to do or stopped or hardware stopped */
        if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) {
-               dz_stop_tx(&dport->port, 0);
+               dz_stop_tx(&dport->port);
                return;
        }
 
@@ -308,7 +308,7 @@ static inline void dz_transmit_chars(struct dz_port *dport)
 
        /* Are we done */
        if (uart_circ_empty(xmit))
-               dz_stop_tx(&dport->port, 0);
+               dz_stop_tx(&dport->port);
 }
 
 /*
@@ -440,7 +440,7 @@ static int dz_startup(struct uart_port *uport)
  */
 static void dz_shutdown(struct uart_port *uport)
 {
-       dz_stop_tx(uport, 0);
+       dz_stop_tx(uport);
 }
 
 /*
index c112b32764e8ceb3045ebcbe7933d25eb7d3aa22..eb31125c6a30f84de2416f80c939bc1eae412fc8 100644 (file)
@@ -56,7 +56,6 @@
 #include <linux/bitops.h>
 
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
@@ -989,18 +988,16 @@ static unsigned int icom_get_mctrl(struct uart_port *port)
        return result;
 }
 
-static void icom_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void icom_stop_tx(struct uart_port *port)
 {
        unsigned char cmdReg;
 
-       if (tty_stop) {
-               trace(ICOM_PORT, "STOP", 0);
-               cmdReg = readb(&ICOM_PORT->dram->CmdReg);
-               writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg);
-       }
+       trace(ICOM_PORT, "STOP", 0);
+       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+       writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg);
 }
 
-static void icom_start_tx(struct uart_port *port, unsigned int tty_start)
+static void icom_start_tx(struct uart_port *port)
 {
        unsigned char cmdReg;
 
index 01a8726a3f97289b9a85e21eeab51c1703aaac8d..4c985e6b3784b0b611413c74deba61a98c086997 100644 (file)
@@ -124,7 +124,7 @@ static void imx_timeout(unsigned long data)
 /*
  * interrupts disabled on entry
  */
-static void imx_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void imx_stop_tx(struct uart_port *port)
 {
        struct imx_port *sport = (struct imx_port *)port;
        UCR1((u32)sport->port.membase) &= ~UCR1_TXMPTYEN;
@@ -165,13 +165,13 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
        } while (!(UTS((u32)sport->port.membase) & UTS_TXFULL));
 
        if (uart_circ_empty(xmit))
-               imx_stop_tx(&sport->port, 0);
+               imx_stop_tx(&sport->port);
 }
 
 /*
  * interrupts disabled on entry
  */
-static void imx_start_tx(struct uart_port *port, unsigned int tty_start)
+static void imx_start_tx(struct uart_port *port)
 {
        struct imx_port *sport = (struct imx_port *)port;
 
@@ -196,7 +196,7 @@ static irqreturn_t imx_txint(int irq, void *dev_id, struct pt_regs *regs)
        }
 
        if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
-               imx_stop_tx(&sport->port, 0);
+               imx_stop_tx(&sport->port);
                goto out;
        }
 
@@ -291,13 +291,31 @@ static unsigned int imx_tx_empty(struct uart_port *port)
        return USR2((u32)sport->port.membase) & USR2_TXDC ?  TIOCSER_TEMT : 0;
 }
 
+/*
+ * We have a modem side uart, so the meanings of RTS and CTS are inverted.
+ */
 static unsigned int imx_get_mctrl(struct uart_port *port)
 {
-       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+        struct imx_port *sport = (struct imx_port *)port;
+        unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
+
+        if (USR1((u32)sport->port.membase) & USR1_RTSS)
+                tmp |= TIOCM_CTS;
+
+        if (UCR2((u32)sport->port.membase) & UCR2_CTS)
+                tmp |= TIOCM_RTS;
+
+        return tmp;
 }
 
 static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
+        struct imx_port *sport = (struct imx_port *)port;
+
+        if (mctrl & TIOCM_RTS)
+                UCR2((u32)sport->port.membase) |= UCR2_CTS;
+        else
+                UCR2((u32)sport->port.membase) &= ~UCR2_CTS;
 }
 
 /*
index 793c3a7cbe477c868f65d1ddf224cd64b629e889..0c5c96a582b340cec9ea60f12c71262e2ddea2cc 100644 (file)
@@ -2373,10 +2373,9 @@ static unsigned int ic4_tx_empty(struct uart_port *the_port)
 /**
  * ic4_stop_tx - stop the transmitter
  * @port: Port to operate on
- * @tty_stop: Set to 1 if called via uart_stop
  *
  */
-static void ic4_stop_tx(struct uart_port *the_port, unsigned int tty_stop)
+static void ic4_stop_tx(struct uart_port *the_port)
 {
 }
 
@@ -2471,10 +2470,9 @@ static unsigned int ic4_get_mctrl(struct uart_port *the_port)
 /**
  * ic4_start_tx - Start transmitter, flush any output
  * @port: Port to operate on
- * @tty_stop: Set to 1 if called via uart_start
  *
  */
-static void ic4_start_tx(struct uart_port *the_port, unsigned int tty_stop)
+static void ic4_start_tx(struct uart_port *the_port)
 {
        struct ioc4_port *port = get_ioc4_port(the_port);
        unsigned long flags;
index ea5bf4d4daa3016db79933b268ae5240fa63e952..ef132349f310d8325122458bea12b52b039d696e 100644 (file)
@@ -592,7 +592,7 @@ static void ip22zilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
 }
 
 /* The port lock is held and interrupts are disabled.  */
-static void ip22zilog_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void ip22zilog_stop_tx(struct uart_port *port)
 {
        struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
 
@@ -600,7 +600,7 @@ static void ip22zilog_stop_tx(struct uart_port *port, unsigned int tty_stop)
 }
 
 /* The port lock is held and interrupts are disabled.  */
-static void ip22zilog_start_tx(struct uart_port *port, unsigned int tty_start)
+static void ip22zilog_start_tx(struct uart_port *port)
 {
        struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
        struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
index 98de2258fd06e731a88fc0e9a7e2277ca1ffaa18..6fa0d62d6f686269eadf52abacf56e516f7be3f8 100644 (file)
@@ -113,7 +113,7 @@ static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl)
        udelay(10);
 }
 
-static void jsm_tty_start_tx(struct uart_port *port, unsigned int tty_start)
+static void jsm_tty_start_tx(struct uart_port *port)
 {
        struct jsm_channel *channel = (struct jsm_channel *)port;
 
@@ -125,7 +125,7 @@ static void jsm_tty_start_tx(struct uart_port *port, unsigned int tty_start)
        jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
 }
 
-static void jsm_tty_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void jsm_tty_stop_tx(struct uart_port *port)
 {
        struct jsm_channel *channel = (struct jsm_channel *)port;
 
index 9b50560b9d1625d36658f3015424e7099b438ea5..b0ecc7537ce5de9bbd3328a8cd44dc53453690e7 100644 (file)
@@ -275,7 +275,7 @@ serial_out(struct uart_sio_port *up, int offset, int value)
        __sio_out(value, offset);
 }
 
-static void m32r_sio_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void m32r_sio_stop_tx(struct uart_port *port)
 {
        struct uart_sio_port *up = (struct uart_sio_port *)port;
 
@@ -285,7 +285,7 @@ static void m32r_sio_stop_tx(struct uart_port *port, unsigned int tty_stop)
        }
 }
 
-static void m32r_sio_start_tx(struct uart_port *port, unsigned int tty_start)
+static void m32r_sio_start_tx(struct uart_port *port)
 {
 #ifdef CONFIG_SERIAL_M32R_PLDSIO
        struct uart_sio_port *up = (struct uart_sio_port *)port;
@@ -425,7 +425,7 @@ static _INLINE_ void transmit_chars(struct uart_sio_port *up)
                return;
        }
        if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               m32r_sio_stop_tx(&up->port, 0);
+               m32r_sio_stop_tx(&up->port);
                return;
        }
 
@@ -446,7 +446,7 @@ static _INLINE_ void transmit_chars(struct uart_sio_port *up)
        DEBUG_INTR("THRE...");
 
        if (uart_circ_empty(xmit))
-               m32r_sio_stop_tx(&up->port, 0);
+               m32r_sio_stop_tx(&up->port);
 }
 
 /*
index 8c40167778dea949e077954a10445736f9f6ea21..43b03c55f453859a2902c7dc50d72f741b508e20 100644 (file)
@@ -40,7 +40,6 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <asm/semaphore.h>
 #include <asm/delay.h>
 #include <asm/coldfire.h>
index 2a5cf174ca30d949a6888273d70081913b6ffab0..a3cd0ee8486d42fb9a6d757841b9b140059182a5 100644 (file)
@@ -119,7 +119,7 @@ mpc52xx_uart_get_mctrl(struct uart_port *port)
 }
 
 static void 
-mpc52xx_uart_stop_tx(struct uart_port *port, unsigned int tty_stop)
+mpc52xx_uart_stop_tx(struct uart_port *port)
 {
        /* port->lock taken by caller */
        port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY;
@@ -127,7 +127,7 @@ mpc52xx_uart_stop_tx(struct uart_port *port, unsigned int tty_stop)
 }
 
 static void 
-mpc52xx_uart_start_tx(struct uart_port *port, unsigned int tty_start)
+mpc52xx_uart_start_tx(struct uart_port *port)
 {
        /* port->lock taken by caller */
        port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
@@ -485,7 +485,7 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port)
 
        /* Nothing to do ? */
        if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               mpc52xx_uart_stop_tx(port,0);
+               mpc52xx_uart_stop_tx(port);
                return 0;
        }
 
@@ -504,7 +504,7 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port)
 
        /* Maybe we're done after all */
        if (uart_circ_empty(xmit)) {
-               mpc52xx_uart_stop_tx(port,0);
+               mpc52xx_uart_stop_tx(port);
                return 0;
        }
 
index e43276c6a954d611021745375b5e2344bc85d266..efe79b1fd431b8f13c98cdf5150f4aef49759f0b 100644 (file)
@@ -1072,18 +1072,18 @@ mpsc_get_mctrl(struct uart_port *port)
 }
 
 static void
-mpsc_stop_tx(struct uart_port *port, uint tty_start)
+mpsc_stop_tx(struct uart_port *port)
 {
        struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
 
-       pr_debug("mpsc_stop_tx[%d]: tty_start: %d\n", port->line, tty_start);
+       pr_debug("mpsc_stop_tx[%d]\n", port->line);
 
        mpsc_freeze(pi);
        return;
 }
 
 static void
-mpsc_start_tx(struct uart_port *port, uint tty_start)
+mpsc_start_tx(struct uart_port *port)
 {
        struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
 
@@ -1091,7 +1091,7 @@ mpsc_start_tx(struct uart_port *port, uint tty_start)
        mpsc_copy_tx_data(pi);
        mpsc_sdma_start_tx(pi);
 
-       pr_debug("mpsc_start_tx[%d]: tty_start: %d\n", port->line, tty_start);
+       pr_debug("mpsc_start_tx[%d]\n", port->line);
        return;
 }
 
index dadd7e19714e1c91cc20a704fd87049c65f8898c..189064607709d9ae717cdb70646062b768ba2c0d 100644 (file)
@@ -111,22 +111,20 @@ static unsigned int mux_get_mctrl(struct uart_port *port)
 /**
  * mux_stop_tx - Stop transmitting characters.
  * @port: Ptr to the uart_port.
- * @tty_stop: tty layer issue this command?
  *
  * The Serial MUX does not support this function.
  */
-static void mux_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void mux_stop_tx(struct uart_port *port)
 {
 }
 
 /**
  * mux_start_tx - Start transmitting characters.
  * @port: Ptr to the uart_port.
- * @tty_start: tty layer issue this command?
  *
  * The Serial Mux does not support this function.
  */
-static void mux_start_tx(struct uart_port *port, unsigned int tty_start)
+static void mux_start_tx(struct uart_port *port)
 {
 }
 
@@ -181,7 +179,7 @@ static void mux_write(struct uart_port *port)
        }
 
        if(uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               mux_stop_tx(port, 0);
+               mux_stop_tx(port);
                return;
        }
 
@@ -202,7 +200,7 @@ static void mux_write(struct uart_port *port)
                uart_write_wakeup(port);
 
        if (uart_circ_empty(xmit))
-               mux_stop_tx(port, 0);
+               mux_stop_tx(port);
 }
 
 /**
index 7db2f37532cf368e7d1ce1d1a11d7af34f31b445..5ddd8ab1f108afb3af7b3acd0e38bc142c026c5f 100644 (file)
@@ -630,11 +630,10 @@ static unsigned int pmz_get_mctrl(struct uart_port *port)
 
 /* 
  * Stop TX side. Dealt like sunzilog at next Tx interrupt,
- * though for DMA, we will have to do a bit more. What is
- * the meaning of the tty_stop bit ? XXX
+ * though for DMA, we will have to do a bit more.
  * The port lock is held and interrupts are disabled.
  */
-static void pmz_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void pmz_stop_tx(struct uart_port *port)
 {
        to_pmz(port)->flags |= PMACZILOG_FLAG_TX_STOPPED;
 }
@@ -643,7 +642,7 @@ static void pmz_stop_tx(struct uart_port *port, unsigned int tty_stop)
  * Kick the Tx side.
  * The port lock is held and interrupts are disabled.
  */
-static void pmz_start_tx(struct uart_port *port, unsigned int tty_start)
+static void pmz_start_tx(struct uart_port *port)
 {
        struct uart_pmac_port *uap = to_pmz(port);
        unsigned char status;
@@ -1601,7 +1600,7 @@ static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
                return 0;
        }
 
-       if (pm_state == mdev->ofdev.dev.power.power_state || pm_state < 2)
+       if (pm_state.event == mdev->ofdev.dev.power.power_state.event)
                return 0;
 
        pmz_debug("suspend, switching to state %d\n", pm_state);
@@ -1661,7 +1660,7 @@ static int pmz_resume(struct macio_dev *mdev)
        if (uap == NULL)
                return 0;
 
-       if (mdev->ofdev.dev.power.power_state == 0)
+       if (mdev->ofdev.dev.power.power_state.event == PM_EVENT_ON)
                return 0;
        
        pmz_debug("resume, switching to state 0\n");
@@ -1714,7 +1713,7 @@ static int pmz_resume(struct macio_dev *mdev)
 
        pmz_debug("resume, switching complete\n");
 
-       mdev->ofdev.dev.power.power_state = 0;
+       mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON;
 
        return 0;
 }
index 461c81c93207809381c0f2bc9afe5ecfa23d8d9e..eaa0af8352907da7f6ea4f18a8d9df7f7c096edb 100644 (file)
@@ -80,7 +80,7 @@ static void serial_pxa_enable_ms(struct uart_port *port)
        serial_out(up, UART_IER, up->ier);
 }
 
-static void serial_pxa_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void serial_pxa_stop_tx(struct uart_port *port)
 {
        struct uart_pxa_port *up = (struct uart_pxa_port *)port;
 
@@ -185,7 +185,7 @@ static void transmit_chars(struct uart_pxa_port *up)
                return;
        }
        if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               serial_pxa_stop_tx(&up->port, 0);
+               serial_pxa_stop_tx(&up->port);
                return;
        }
 
@@ -203,10 +203,10 @@ static void transmit_chars(struct uart_pxa_port *up)
 
 
        if (uart_circ_empty(xmit))
-               serial_pxa_stop_tx(&up->port, 0);
+               serial_pxa_stop_tx(&up->port);
 }
 
-static void serial_pxa_start_tx(struct uart_port *port, unsigned int tty_start)
+static void serial_pxa_start_tx(struct uart_port *port)
 {
        struct uart_pxa_port *up = (struct uart_pxa_port *)port;
 
index 7365d4b50b954d2729ce1051acb461cc4ac35cc9..c361c6fb08092135171a7165876bb52c27313f19 100644 (file)
@@ -246,8 +246,7 @@ static void s3c24xx_serial_rx_disable(struct uart_port *port)
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
-static void
-s3c24xx_serial_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void s3c24xx_serial_stop_tx(struct uart_port *port)
 {
        if (tx_enabled(port)) {
                disable_irq(TX_IRQ(port));
@@ -257,8 +256,7 @@ s3c24xx_serial_stop_tx(struct uart_port *port, unsigned int tty_stop)
        }
 }
 
-static void
-s3c24xx_serial_start_tx(struct uart_port *port, unsigned int tty_start)
+static void s3c24xx_serial_start_tx(struct uart_port *port)
 {
        if (!tx_enabled(port)) {
                if (port->flags & UPF_CONS_FLOW)
@@ -424,7 +422,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id, struct pt_regs *re
        */
 
        if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               s3c24xx_serial_stop_tx(port, 0);
+               s3c24xx_serial_stop_tx(port);
                goto out;
        }
 
@@ -443,7 +441,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id, struct pt_regs *re
                uart_write_wakeup(port);
 
        if (uart_circ_empty(xmit))
-               s3c24xx_serial_stop_tx(port, 0);
+               s3c24xx_serial_stop_tx(port);
 
  out:
        return IRQ_HANDLED;
index 98641c3f5ab9dedb9de0dd1be2eb1806469fb692..1225b14f6e9d4bb7469bb1f6019bf877936f1b54 100644 (file)
@@ -145,7 +145,7 @@ static void sa1100_timeout(unsigned long data)
 /*
  * interrupts disabled on entry
  */
-static void sa1100_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void sa1100_stop_tx(struct uart_port *port)
 {
        struct sa1100_port *sport = (struct sa1100_port *)port;
        u32 utcr3;
@@ -158,7 +158,7 @@ static void sa1100_stop_tx(struct uart_port *port, unsigned int tty_stop)
 /*
  * interrupts may not be disabled on entry
  */
-static void sa1100_start_tx(struct uart_port *port, unsigned int tty_start)
+static void sa1100_start_tx(struct uart_port *port)
 {
        struct sa1100_port *sport = (struct sa1100_port *)port;
        unsigned long flags;
@@ -264,7 +264,7 @@ static void sa1100_tx_chars(struct sa1100_port *sport)
        sa1100_mctrl_check(sport);
 
        if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
-               sa1100_stop_tx(&sport->port, 0);
+               sa1100_stop_tx(&sport->port);
                return;
        }
 
@@ -284,7 +284,7 @@ static void sa1100_tx_chars(struct sa1100_port *sport)
                uart_write_wakeup(&sport->port);
 
        if (uart_circ_empty(xmit))
-               sa1100_stop_tx(&sport->port, 0);
+               sa1100_stop_tx(&sport->port);
 }
 
 static irqreturn_t sa1100_int(int irq, void *dev_id, struct pt_regs *regs)
index 54699c3a00ab4e48c1b6c6b196b24ddd80626bc2..2d8622eef7019caffee46cfe2949898e8d7174b0 100644 (file)
@@ -80,7 +80,7 @@ static void uart_stop(struct tty_struct *tty)
        unsigned long flags;
 
        spin_lock_irqsave(&port->lock, flags);
-       port->ops->stop_tx(port, 1);
+       port->ops->stop_tx(port);
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
@@ -91,7 +91,7 @@ static void __uart_start(struct tty_struct *tty)
 
        if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf &&
            !tty->stopped && !tty->hw_stopped)
-               port->ops->start_tx(port, 1);
+               port->ops->start_tx(port);
 }
 
 static void uart_start(struct tty_struct *tty)
@@ -542,7 +542,7 @@ static void uart_send_xchar(struct tty_struct *tty, char ch)
                port->x_char = ch;
                if (ch) {
                        spin_lock_irqsave(&port->lock, flags);
-                       port->ops->start_tx(port, 0);
+                       port->ops->start_tx(port);
                        spin_unlock_irqrestore(&port->lock, flags);
                }
        }
@@ -1146,7 +1146,7 @@ static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios
                spin_lock_irqsave(&state->port->lock, flags);
                if (!(state->port->ops->get_mctrl(state->port) & TIOCM_CTS)) {
                        tty->hw_stopped = 1;
-                       state->port->ops->stop_tx(state->port, 0);
+                       state->port->ops->stop_tx(state->port);
                }
                spin_unlock_irqrestore(&state->port->lock, flags);
        }
@@ -1869,7 +1869,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
                struct uart_ops *ops = port->ops;
 
                spin_lock_irq(&port->lock);
-               ops->stop_tx(port, 0);
+               ops->stop_tx(port);
                ops->set_mctrl(port, 0);
                ops->stop_rx(port);
                spin_unlock_irq(&port->lock);
@@ -1935,7 +1935,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
                uart_change_speed(state, NULL);
                spin_lock_irq(&port->lock);
                ops->set_mctrl(port, port->mctrl);
-               ops->start_tx(port, 0);
+               ops->start_tx(port);
                spin_unlock_irq(&port->lock);
        }
 
@@ -1947,21 +1947,29 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
 static inline void
 uart_report_port(struct uart_driver *drv, struct uart_port *port)
 {
-       printk("%s%d", drv->dev_name, port->line);
-       printk(" at ");
+       char address[64];
+
        switch (port->iotype) {
        case UPIO_PORT:
-               printk("I/O 0x%x", port->iobase);
+               snprintf(address, sizeof(address),
+                        "I/O 0x%x", port->iobase);
                break;
        case UPIO_HUB6:
-               printk("I/O 0x%x offset 0x%x", port->iobase, port->hub6);
+               snprintf(address, sizeof(address),
+                        "I/O 0x%x offset 0x%x", port->iobase, port->hub6);
                break;
        case UPIO_MEM:
        case UPIO_MEM32:
-               printk("MMIO 0x%lx", port->mapbase);
+               snprintf(address, sizeof(address),
+                        "MMIO 0x%lx", port->mapbase);
+               break;
+       default:
+               strlcpy(address, "*unknown*", sizeof(address));
                break;
        }
-       printk(" (irq = %d) is a %s\n", port->irq, uart_type(port));
+
+       printk(KERN_INFO "%s%d at %s (irq = %d) is a %s\n",
+              drv->dev_name, port->line, address, port->irq, uart_type(port));
 }
 
 static void
@@ -2289,143 +2297,11 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2)
 }
 EXPORT_SYMBOL(uart_match_port);
 
-/*
- *     Try to find an unused uart_state slot for a port.
- */
-static struct uart_state *
-uart_find_match_or_unused(struct uart_driver *drv, struct uart_port *port)
-{
-       int i;
-
-       /*
-        * First, find a port entry which matches.  Note: if we do
-        * find a matching entry, and it has a non-zero use count,
-        * then we can't register the port.
-        */
-       for (i = 0; i < drv->nr; i++)
-               if (uart_match_port(drv->state[i].port, port))
-                       return &drv->state[i];
-
-       /*
-        * We didn't find a matching entry, so look for the first
-        * free entry.  We look for one which hasn't been previously
-        * used (indicated by zero iobase).
-        */
-       for (i = 0; i < drv->nr; i++)
-               if (drv->state[i].port->type == PORT_UNKNOWN &&
-                   drv->state[i].port->iobase == 0 &&
-                   drv->state[i].count == 0)
-                       return &drv->state[i];
-
-       /*
-        * That also failed.  Last resort is to find any currently
-        * entry which doesn't have a real port associated with it.
-        */
-       for (i = 0; i < drv->nr; i++)
-               if (drv->state[i].port->type == PORT_UNKNOWN &&
-                   drv->state[i].count == 0)
-                       return &drv->state[i];
-
-       return NULL;
-}
-
-/**
- *     uart_register_port: register uart settings with a port
- *     @drv: pointer to the uart low level driver structure for this port
- *     @port: uart port structure describing the port
- *
- *     Register UART settings with the specified low level driver.  Detect
- *     the type of the port if UPF_BOOT_AUTOCONF is set, and detect the
- *     IRQ if UPF_AUTO_IRQ is set.
- *
- *     We try to pick the same port for the same IO base address, so that
- *     when a modem is plugged in, unplugged and plugged back in, it gets
- *     allocated the same port.
- *
- *     Returns negative error, or positive line number.
- */
-int uart_register_port(struct uart_driver *drv, struct uart_port *port)
-{
-       struct uart_state *state;
-       int ret;
-
-       down(&port_sem);
-
-       state = uart_find_match_or_unused(drv, port);
-
-       if (state) {
-               /*
-                * Ok, we've found a line that we can use.
-                *
-                * If we find a port that matches this one, and it appears
-                * to be in-use (even if it doesn't have a type) we shouldn't
-                * alter it underneath itself - the port may be open and
-                * trying to do useful work.
-                */
-               if (uart_users(state) != 0) {
-                       ret = -EBUSY;
-                       goto out;
-               }
-
-               /*
-                * If the port is already initialised, don't touch it.
-                */
-               if (state->port->type == PORT_UNKNOWN) {
-                       state->port->iobase   = port->iobase;
-                       state->port->membase  = port->membase;
-                       state->port->irq      = port->irq;
-                       state->port->uartclk  = port->uartclk;
-                       state->port->fifosize = port->fifosize;
-                       state->port->regshift = port->regshift;
-                       state->port->iotype   = port->iotype;
-                       state->port->flags    = port->flags;
-                       state->port->line     = state - drv->state;
-                       state->port->mapbase  = port->mapbase;
-
-                       uart_configure_port(drv, state, state->port);
-               }
-
-               ret = state->port->line;
-       } else
-               ret = -ENOSPC;
- out:
-       up(&port_sem);
-       return ret;
-}
-
-/**
- *     uart_unregister_port - de-allocate a port
- *     @drv: pointer to the uart low level driver structure for this port
- *     @line: line index previously returned from uart_register_port()
- *
- *     Hang up the specified line associated with the low level driver,
- *     and mark the port as unused.
- */
-void uart_unregister_port(struct uart_driver *drv, int line)
-{
-       struct uart_state *state;
-
-       if (line < 0 || line >= drv->nr) {
-               printk(KERN_ERR "Attempt to unregister ");
-               printk("%s%d", drv->dev_name, line);
-               printk("\n");
-               return;
-       }
-
-       state = drv->state + line;
-
-       down(&port_sem);
-       uart_unconfigure_port(drv, state);
-       up(&port_sem);
-}
-
 EXPORT_SYMBOL(uart_write_wakeup);
 EXPORT_SYMBOL(uart_register_driver);
 EXPORT_SYMBOL(uart_unregister_driver);
 EXPORT_SYMBOL(uart_suspend_port);
 EXPORT_SYMBOL(uart_resume_port);
-EXPORT_SYMBOL(uart_register_port);
-EXPORT_SYMBOL(uart_unregister_port);
 EXPORT_SYMBOL(uart_add_one_port);
 EXPORT_SYMBOL(uart_remove_one_port);
 
index 56f269b6bfb12c53fb323c66dcab126010888bee..8302376800c07da15b3c905a0b50baa3a8f9407b 100644 (file)
@@ -112,13 +112,12 @@ struct uart_port_lh7a40x {
        unsigned int statusPrev; /* Most recently read modem status */
 };
 
-static void lh7a40xuart_stop_tx (struct uart_port* port, unsigned int tty_stop)
+static void lh7a40xuart_stop_tx (struct uart_port* port)
 {
        BIT_CLR (port, UART_R_INTEN, TxInt);
 }
 
-static void lh7a40xuart_start_tx (struct uart_port* port,
-                                 unsigned int tty_start)
+static void lh7a40xuart_start_tx (struct uart_port* port)
 {
        BIT_SET (port, UART_R_INTEN, TxInt);
 
@@ -208,7 +207,7 @@ static void lh7a40xuart_tx_chars (struct uart_port* port)
                return;
        }
        if (uart_circ_empty (xmit) || uart_tx_stopped (port)) {
-               lh7a40xuart_stop_tx (port, 0);
+               lh7a40xuart_stop_tx (port);
                return;
        }
 
@@ -230,7 +229,7 @@ static void lh7a40xuart_tx_chars (struct uart_port* port)
                uart_write_wakeup (port);
 
        if (uart_circ_empty (xmit))
-               lh7a40xuart_stop_tx (port, 0);
+               lh7a40xuart_stop_tx (port);
 }
 
 static void lh7a40xuart_modem_status (struct uart_port* port)
index d085030df70ba5bd321a0fd5716df8ab31af39e1..49afadbe461b2875ad5b6f0c913cf9906551b5f0 100644 (file)
@@ -253,7 +253,7 @@ sio_quot_set(struct uart_txx9_port *up, int quot)
                sio_out(up, TXX9_SIBGR, 0xff | TXX9_SIBGR_BCLK_T6);
 }
 
-static void serial_txx9_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void serial_txx9_stop_tx(struct uart_port *port)
 {
        struct uart_txx9_port *up = (struct uart_txx9_port *)port;
        unsigned long flags;
@@ -263,7 +263,7 @@ static void serial_txx9_stop_tx(struct uart_port *port, unsigned int tty_stop)
        spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
-static void serial_txx9_start_tx(struct uart_port *port, unsigned int tty_start)
+static void serial_txx9_start_tx(struct uart_port *port)
 {
        struct uart_txx9_port *up = (struct uart_txx9_port *)port;
        unsigned long flags;
@@ -372,7 +372,7 @@ static inline void transmit_chars(struct uart_txx9_port *up)
                return;
        }
        if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               serial_txx9_stop_tx(&up->port, 0);
+               serial_txx9_stop_tx(&up->port);
                return;
        }
 
@@ -389,7 +389,7 @@ static inline void transmit_chars(struct uart_txx9_port *up)
                uart_write_wakeup(&up->port);
 
        if (uart_circ_empty(xmit))
-               serial_txx9_stop_tx(&up->port, 0);
+               serial_txx9_stop_tx(&up->port);
 }
 
 static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id, struct pt_regs *regs)
index ad5b776d779b3ca56a8db712ddd89defefe2dbce..512266307866d5c99784499b7d025eab47294b49 100644 (file)
@@ -79,8 +79,8 @@ static struct sci_port *serial_console_port = 0;
 #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
 
 /* Function prototypes */
-static void sci_stop_tx(struct uart_port *port, unsigned int tty_stop);
-static void sci_start_tx(struct uart_port *port, unsigned int tty_start);
+static void sci_stop_tx(struct uart_port *port);
+static void sci_start_tx(struct uart_port *port);
 static void sci_start_rx(struct uart_port *port, unsigned int tty_start);
 static void sci_stop_rx(struct uart_port *port);
 static int sci_request_irq(struct sci_port *port);
@@ -455,7 +455,7 @@ static void sci_transmit_chars(struct uart_port *port)
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
                uart_write_wakeup(port);
        if (uart_circ_empty(xmit)) {
-               sci_stop_tx(port, 0);
+               sci_stop_tx(port);
        } else {
                local_irq_save(flags);
                ctrl = sci_in(port, SCSCR);
@@ -900,7 +900,7 @@ static unsigned int sci_get_mctrl(struct uart_port *port)
        return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR;
 }
 
-static void sci_start_tx(struct uart_port *port, unsigned int tty_start)
+static void sci_start_tx(struct uart_port *port)
 {
        struct sci_port *s = &sci_ports[port->line];
 
@@ -909,7 +909,7 @@ static void sci_start_tx(struct uart_port *port, unsigned int tty_start)
        enable_irq(s->irqs[SCIx_TXI_IRQ]);
 }
 
-static void sci_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void sci_stop_tx(struct uart_port *port)
 {
        unsigned long flags;
        unsigned short ctrl;
@@ -978,7 +978,7 @@ static void sci_shutdown(struct uart_port *port)
        struct sci_port *s = &sci_ports[port->line];
 
        sci_stop_rx(port);
-       sci_stop_tx(port, 1);
+       sci_stop_tx(port);
        sci_free_irq(s);
 
 #if defined(__H8300S__)
index 12d1f14e78ce3a036da34e508fc513b28ce2af1f..313f9df24a2de97426df92de3c439af9d07dda91 100644 (file)
@@ -259,10 +259,9 @@ static unsigned int snp_tx_empty(struct uart_port *port)
 /**
  * snp_stop_tx - stop the transmitter - no-op for us
  * @port: Port to operat eon - we ignore - no-op function
- * @tty_stop: Set to 1 if called via uart_stop
  *
  */
-static void snp_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void snp_stop_tx(struct uart_port *port)
 {
 }
 
@@ -325,10 +324,9 @@ static void snp_stop_rx(struct uart_port *port)
 /**
  * snp_start_tx - Start transmitter
  * @port: Port to operate on
- * @tty_stop: Set to 1 if called via uart_start
  *
  */
-static void snp_start_tx(struct uart_port *port, unsigned int tty_stop)
+static void snp_start_tx(struct uart_port *port)
 {
        if (sal_console_port.sc_ops->sal_wakeup_transmit)
                sal_console_port.sc_ops->sal_wakeup_transmit(&sal_console_port,
@@ -615,7 +613,7 @@ static void sn_transmit_chars(struct sn_cons_port *port, int raw)
                uart_write_wakeup(&port->sc_port);
 
        if (uart_circ_empty(xmit))
-               snp_stop_tx(&port->sc_port, 0); /* no-op for us */
+               snp_stop_tx(&port->sc_port);    /* no-op for us */
 }
 
 /**
index 8d198880756a6a3aef034eb55ca6ca7ea5a212e5..e971156daa60c49e94fcf26ae1ddc3a3b3e387ad 100644 (file)
@@ -245,7 +245,7 @@ receive_chars(struct uart_sunsab_port *up,
        return tty;
 }
 
-static void sunsab_stop_tx(struct uart_port *, unsigned int);
+static void sunsab_stop_tx(struct uart_port *);
 static void sunsab_tx_idle(struct uart_sunsab_port *);
 
 static void transmit_chars(struct uart_sunsab_port *up,
@@ -301,7 +301,7 @@ static void transmit_chars(struct uart_sunsab_port *up,
                uart_write_wakeup(&up->port);
 
        if (uart_circ_empty(xmit))
-               sunsab_stop_tx(&up->port, 0);
+               sunsab_stop_tx(&up->port);
 }
 
 static void check_status(struct uart_sunsab_port *up,
@@ -448,7 +448,7 @@ static unsigned int sunsab_get_mctrl(struct uart_port *port)
 }
 
 /* port->lock held by caller.  */
-static void sunsab_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void sunsab_stop_tx(struct uart_port *port)
 {
        struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
 
@@ -476,7 +476,7 @@ static void sunsab_tx_idle(struct uart_sunsab_port *up)
 }
 
 /* port->lock held by caller.  */
-static void sunsab_start_tx(struct uart_port *port, unsigned int tty_start)
+static void sunsab_start_tx(struct uart_port *port)
 {
        struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
        struct circ_buf *xmit = &up->port.info->xmit;
index d57a3553aea359ac7a3123ae62261f2ed9abbb0d..5959e6755a8149d4fd440592b2d6ae57fe25b929 100644 (file)
@@ -255,21 +255,30 @@ static void disable_rsa(struct uart_sunsu_port *up)
 }
 #endif /* CONFIG_SERIAL_8250_RSA */
 
-static void sunsu_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static inline void __stop_tx(struct uart_sunsu_port *p)
+{
+       if (p->ier & UART_IER_THRI) {
+               p->ier &= ~UART_IER_THRI;
+               serial_out(p, UART_IER, p->ier);
+       }
+}
+
+static void sunsu_stop_tx(struct uart_port *port)
 {
        struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
 
-       if (up->ier & UART_IER_THRI) {
-               up->ier &= ~UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-       if (up->port.type == PORT_16C950 && tty_stop) {
+       __stop_tx(up);
+
+       /*
+        * We really want to stop the transmitter from sending.
+        */
+       if (up->port.type == PORT_16C950) {
                up->acr |= UART_ACR_TXDIS;
                serial_icr_write(up, UART_ACR, up->acr);
        }
 }
 
-static void sunsu_start_tx(struct uart_port *port, unsigned int tty_start)
+static void sunsu_start_tx(struct uart_port *port)
 {
        struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
 
@@ -277,10 +286,11 @@ static void sunsu_start_tx(struct uart_port *port, unsigned int tty_start)
                up->ier |= UART_IER_THRI;
                serial_out(up, UART_IER, up->ier);
        }
+
        /*
-        * We only do this from uart_start
+        * Re-enable the transmitter if we disabled it.
         */
-       if (tty_start && up->port.type == PORT_16C950) {
+       if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) {
                up->acr &= ~UART_ACR_TXDIS;
                serial_icr_write(up, UART_ACR, up->acr);
        }
@@ -413,8 +423,12 @@ static _INLINE_ void transmit_chars(struct uart_sunsu_port *up)
                up->port.x_char = 0;
                return;
        }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               sunsu_stop_tx(&up->port, 0);
+       if (uart_tx_stopped(&up->port)) {
+               sunsu_stop_tx(&up->port);
+               return;
+       }
+       if (uart_circ_empty(xmit)) {
+               __stop_tx(up);
                return;
        }
 
@@ -431,7 +445,7 @@ static _INLINE_ void transmit_chars(struct uart_sunsu_port *up)
                uart_write_wakeup(&up->port);
 
        if (uart_circ_empty(xmit))
-               sunsu_stop_tx(&up->port, 0);
+               __stop_tx(up);
 }
 
 static _INLINE_ void check_modem_status(struct uart_sunsu_port *up)
index bff42a7b89d0ec6e02862fcd656a12500ccc144b..d75445738c881d4ef442455e5b0b9e3a335be5bd 100644 (file)
@@ -684,7 +684,7 @@ static void sunzilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
 }
 
 /* The port lock is held and interrupts are disabled.  */
-static void sunzilog_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void sunzilog_stop_tx(struct uart_port *port)
 {
        struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
 
@@ -692,7 +692,7 @@ static void sunzilog_stop_tx(struct uart_port *port, unsigned int tty_stop)
 }
 
 /* The port lock is held and interrupts are disabled.  */
-static void sunzilog_start_tx(struct uart_port *port, unsigned int tty_start)
+static void sunzilog_start_tx(struct uart_port *port)
 {
        struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
        struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
index 186f1300cead9524a54e54bf7823c42492bd2dc3..47b504ff38b2e00b565deeba6698ff70b114d31b 100644 (file)
@@ -87,7 +87,7 @@
 #define UART_TX_READY(s)       (((s) & UART_TSR_TX_LEVEL_MSK) < 15)
 //#define UART_TX_EMPTY(p)     ((UART_GET_FR(p) & UART00_UARTFR_TMSK) == 0)
 
-static void uart00_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void uart00_stop_tx(struct uart_port *port)
 {
        UART_PUT_IEC(port, UART_IEC_TIE_MSK);
 }
@@ -199,7 +199,7 @@ static void uart00_tx_chars(struct uart_port *port)
                return;
        }
        if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               uart00_stop_tx(port, 0);
+               uart00_stop_tx(port);
                return;
        }
 
@@ -218,10 +218,10 @@ static void uart00_tx_chars(struct uart_port *port)
                uart_write_wakeup(port);
 
        if (uart_circ_empty(xmit))
-               uart00_stop_tx(port, 0);
+               uart00_stop_tx(port);
 }
 
-static void uart00_start_tx(struct uart_port *port, unsigned int tty_start)
+static void uart00_start_tx(struct uart_port *port)
 {
        UART_PUT_IES(port, UART_IES_TIE_MSK);
        uart00_tx_chars(port);
index bb482780a41d97c8452705825bdd4a31790fb208..9378895a8d56e9506a8e3569173087138089b832 100644 (file)
@@ -240,7 +240,7 @@ console_initcall(v850e_uart_console_init);
 \f
 /* TX/RX interrupt handlers.  */
 
-static void v850e_uart_stop_tx (struct uart_port *port, unsigned tty_stop);
+static void v850e_uart_stop_tx (struct uart_port *port);
 
 void v850e_uart_tx (struct uart_port *port)
 {
@@ -339,14 +339,14 @@ static unsigned v850e_uart_get_mctrl (struct uart_port *port)
        return mctrl;
 }
 
-static void v850e_uart_start_tx (struct uart_port *port, unsigned tty_start)
+static void v850e_uart_start_tx (struct uart_port *port)
 {
        v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line));
        v850e_uart_tx (port);
        v850e_intc_enable_irq (V850E_UART_TX_IRQ (port->line));
 }
 
-static void v850e_uart_stop_tx (struct uart_port *port, unsigned tty_stop)
+static void v850e_uart_stop_tx (struct uart_port *port)
 {
        v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line));
 }
index 1f985327b0d485ec8b4648073ef39a80d25d28f1..0c5d65a08f6e01e4d84e33d8adc042a85ed58b6e 100644 (file)
@@ -284,7 +284,7 @@ static unsigned int siu_get_mctrl(struct uart_port *port)
        return mctrl;
 }
 
-static void siu_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void siu_stop_tx(struct uart_port *port)
 {
        unsigned long flags;
        uint8_t ier;
@@ -298,7 +298,7 @@ static void siu_stop_tx(struct uart_port *port, unsigned int tty_stop)
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
-static void siu_start_tx(struct uart_port *port, unsigned int tty_start)
+static void siu_start_tx(struct uart_port *port)
 {
        unsigned long flags;
        uint8_t ier;
@@ -458,7 +458,7 @@ static inline void transmit_chars(struct uart_port *port)
        }
 
        if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               siu_stop_tx(port, 0);
+               siu_stop_tx(port);
                return;
        }
 
@@ -474,7 +474,7 @@ static inline void transmit_chars(struct uart_port *port)
                uart_write_wakeup(port);
 
        if (uart_circ_empty(xmit))
-               siu_stop_tx(port, 0);
+               siu_stop_tx(port);
 }
 
 static irqreturn_t siu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
index bb1db19598549ee10322f9d7ff0562f4f11cad2c..c466739428b2c501eb99c809f02226f55c7c9a76 100644 (file)
@@ -960,7 +960,7 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
                        intf->altsetting->desc.bInterfaceNumber);
 
        /* instance init */
-       instance = kcalloc(1, sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL);
+       instance = kzalloc(sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL);
        if (!instance) {
                dev_dbg(dev, "%s: no memory for instance data!\n", __func__);
                return -ENOMEM;
index 79422a3b07bc4bce769e6cc8ac7f08c6b3d17f95..12ecdb03ee5f20afd3bcef220e8aded0bb30857c 100644 (file)
@@ -782,7 +782,7 @@ static int usb_register_bus(struct usb_bus *bus)
                return -E2BIG;
        }
 
-       bus->class_dev = class_device_create(usb_host_class, MKDEV(0,0), bus->controller, "usb%d", busnum);
+       bus->class_dev = class_device_create(usb_host_class, MKDEV(0,0), bus->controller, "usb_host%d", busnum);
        if (IS_ERR(bus->class_dev)) {
                clear_bit(busnum, busmap.busmap);
                up(&usb_bus_list_lock);
@@ -1669,7 +1669,7 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
 {
        struct usb_hcd *hcd;
 
-       hcd = kcalloc(1, sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
+       hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
        if (!hcd) {
                dev_dbg (dev, "hcd alloc failed\n");
                return NULL;
index c3e46d24a37ed0a93c8f1c2d39c27c30617b4435..c9412daff682431a820d11c3595cde972929377d 100644 (file)
@@ -1570,7 +1570,7 @@ static int __usb_suspend_device (struct usb_device *udev, int port1,
                        struct usb_driver       *driver;
 
                        intf = udev->actconfig->interface[i];
-                       if (state <= intf->dev.power.power_state)
+                       if (state.event <= intf->dev.power.power_state.event)
                                continue;
                        if (!intf->dev.driver)
                                continue;
@@ -1578,11 +1578,11 @@ static int __usb_suspend_device (struct usb_device *udev, int port1,
 
                        if (driver->suspend) {
                                status = driver->suspend(intf, state);
-                               if (intf->dev.power.power_state != state
+                               if (intf->dev.power.power_state.event != state.event
                                                || status)
                                        dev_err(&intf->dev,
                                                "suspend %d fail, code %d\n",
-                                               state, status);
+                                               state.event, status);
                        }
 
                        /* only drivers with suspend() can ever resume();
@@ -1595,7 +1595,7 @@ static int __usb_suspend_device (struct usb_device *udev, int port1,
                         * since we know every driver's probe/disconnect works
                         * even for drivers that can't suspend.
                         */
-                       if (!driver->suspend || state > PM_SUSPEND_MEM) {
+                       if (!driver->suspend || state.event > PM_EVENT_FREEZE) {
 #if 1
                                dev_warn(&intf->dev, "resume is unsafe!\n");
 #else
@@ -1616,7 +1616,7 @@ static int __usb_suspend_device (struct usb_device *udev, int port1,
         * policies (when HNP doesn't apply) once we have mechanisms to
         * turn power back on!  (Likely not before 2.7...)
         */
-       if (state > PM_SUSPEND_MEM) {
+       if (state.event > PM_EVENT_FREEZE) {
                dev_warn(&udev->dev, "no poweroff yet, suspending instead\n");
        }
 
@@ -1733,7 +1733,7 @@ static int finish_port_resume(struct usb_device *udev)
                        struct usb_driver       *driver;
 
                        intf = udev->actconfig->interface[i];
-                       if (intf->dev.power.power_state == PMSG_ON)
+                       if (intf->dev.power.power_state.event == PM_EVENT_ON)
                                continue;
                        if (!intf->dev.driver) {
                                /* FIXME maybe force to alt 0 */
@@ -1747,11 +1747,11 @@ static int finish_port_resume(struct usb_device *udev)
 
                        /* can we do better than just logging errors? */
                        status = driver->resume(intf);
-                       if (intf->dev.power.power_state != PMSG_ON
+                       if (intf->dev.power.power_state.event != PM_EVENT_ON
                                        || status)
                                dev_dbg(&intf->dev,
                                        "resume fail, state %d code %d\n",
-                                       intf->dev.power.power_state, status);
+                                       intf->dev.power.power_state.event, status);
                }
                status = 0;
 
@@ -1934,7 +1934,7 @@ static int hub_resume(struct usb_interface *intf)
        unsigned                port1;
        int                     status;
 
-       if (intf->dev.power.power_state == PM_SUSPEND_ON)
+       if (intf->dev.power.power_state.event == PM_EVENT_ON)
                return 0;
 
        for (port1 = 1; port1 <= hdev->maxchild; port1++) {
index 99c85d2f92daaf115df6cbe902a8f7a266fa3f66..2cddd8a00437b8bede3f9814a66dc73a2190886a 100644 (file)
@@ -1400,7 +1400,7 @@ static int usb_generic_suspend(struct device *dev, pm_message_t message)
        driver = to_usb_driver(dev->driver);
 
        /* there's only one USB suspend state */
-       if (intf->dev.power.power_state)
+       if (intf->dev.power.power_state.event)
                return 0;
 
        if (driver->suspend)
index b01efb6b36f6767e7e492af441421a7d27ce631e..65ac9fef3a7c1dfc382ef2c8aaf5a089fdb7a7ad 100644 (file)
@@ -641,7 +641,7 @@ show_registers (struct class_device *class_dev, char *buf)
 
        spin_lock_irqsave (&ehci->lock, flags);
 
-       if (bus->controller->power.power_state) {
+       if (bus->controller->power.power_state.event) {
                size = scnprintf (next, size,
                        "bus %s, device %s (driver " DRIVER_VERSION ")\n"
                        "%s\n"
index b56f25864ed60084028e174e035c552bedc6a331..4c972b57c7c3a5ac1fd026269698f83375f4de1a 100644 (file)
@@ -638,7 +638,7 @@ iso_stream_alloc (unsigned mem_flags)
 {
        struct ehci_iso_stream *stream;
 
-       stream = kcalloc(1, sizeof *stream, mem_flags);
+       stream = kzalloc(sizeof *stream, mem_flags);
        if (likely (stream != NULL)) {
                INIT_LIST_HEAD(&stream->td_list);
                INIT_LIST_HEAD(&stream->free_list);
index 76cb496c5836ca3f222cbe688bf67fe2d6a2f1f7..75128c3718008a698cb0695c3eba0a0589bb2928 100644 (file)
@@ -717,7 +717,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
        }
        /* avoid all allocations within spinlocks: request or endpoint */
        if (!hep->hcpriv) {
-               ep = kcalloc(1, sizeof *ep, mem_flags);
+               ep = kzalloc(sizeof *ep, mem_flags);
                if (!ep)
                        return -ENOMEM;
        }
index c58408c95c3d26666fb86482b03274dd0b2b241b..447f488f5d937f85de1e7c75348e04bf8400a040 100644 (file)
@@ -631,7 +631,7 @@ show_registers (struct class_device *class_dev, char *buf)
                hcd->product_desc,
                hcd_name);
 
-       if (bus->controller->power.power_state) {
+       if (bus->controller->power.power_state.event) {
                size -= scnprintf (next, size,
                        "SUSPENDED (no register access)\n");
                goto done;
index 7a890a65f55dc53664b8dd130ee3b4a6b048ffa7..d2a1fd40dfcb846e148faef3e9102142c2ba7cc6 100644 (file)
@@ -835,7 +835,7 @@ static int sl811h_urb_enqueue(
 
        /* avoid all allocations within spinlocks */
        if (!hep->hcpriv)
-               ep = kcalloc(1, sizeof *ep, mem_flags);
+               ep = kzalloc(sizeof *ep, mem_flags);
 
        spin_lock_irqsave(&sl811->lock, flags);
 
@@ -1781,9 +1781,9 @@ sl811h_suspend(struct device *dev, pm_message_t state, u32 phase)
        if (phase != SUSPEND_POWER_DOWN)
                return retval;
 
-       if (state <= PM_SUSPEND_MEM)
+       if (state.event == PM_EVENT_FREEZE)
                retval = sl811h_hub_suspend(hcd);
-       else
+       else if (state.event == PM_EVENT_SUSPEND)
                port_power(sl811, 0);
        if (retval == 0)
                dev->power.power_state = state;
@@ -1802,7 +1802,7 @@ sl811h_resume(struct device *dev, u32 phase)
        /* with no "check to see if VBUS is still powered" board hook,
         * let's assume it'd only be powered to enable remote wakeup.
         */
-       if (dev->power.power_state > PM_SUSPEND_MEM
+       if (dev->power.power_state.event == PM_EVENT_SUSPEND
                        || !hcd->can_wakeup) {
                sl811->port1 = 0;
                port_power(sl811, 1);
index 13532f3e3efc4325ea1c4b516d2045fad3cfd0d4..74f8760d7c07c0c689c7fa6fe5e0b50665b670c3 100644 (file)
@@ -152,7 +152,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
        pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
        maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
 
-       acecad = kcalloc(1, sizeof(struct usb_acecad), GFP_KERNEL);
+       acecad = kzalloc(sizeof(struct usb_acecad), GFP_KERNEL);
        if (!acecad)
                return -ENOMEM;
 
index 0dc439f10823a90f1d13bbe4d7658f4c441cf3f3..becb87efb869f6800b8c7829a5dcc71d0fbd8968 100644 (file)
@@ -166,7 +166,7 @@ static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id
        interface = intf->cur_altsetting;
        endpoint = &interface->endpoint[0].desc;
 
-       if (!(itmtouch = kcalloc(1, sizeof(struct itmtouch_dev), GFP_KERNEL))) {
+       if (!(itmtouch = kzalloc(sizeof(struct itmtouch_dev), GFP_KERNEL))) {
                err("%s - Out of memory.", __FUNCTION__);
                return -ENOMEM;
        }
index 25696386347812769419a5f2a870845c0f836b8d..acc71ec560e9578dec1f34dd88dc6d90b523b8f3 100644 (file)
@@ -263,7 +263,7 @@ int hid_pid_init(struct hid_device *hid)
        struct hid_ff_pid *private;
        struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list);
 
-       private = hid->ff_private = kcalloc(1, sizeof(struct hid_ff_pid), GFP_KERNEL);
+       private = hid->ff_private = kzalloc(sizeof(struct hid_ff_pid), GFP_KERNEL);
        if (!private)
                return -ENOMEM;
 
index ca9f3a30634fef6eb3f9fb2aed8d319b33aa660b..f36c0b6c6e36cd3db2665863f001c93606f9f1c0 100644 (file)
@@ -1523,7 +1523,6 @@ static u32 w9968cf_i2c_func(struct i2c_adapter* adap)
 static int w9968cf_i2c_attach_inform(struct i2c_client* client)
 {
        struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
-       const char* clientname = i2c_clientname(client);
        int id = client->driver->id, err = 0;
 
        if (id == I2C_DRIVERID_OVCAMCHIP) {
@@ -1535,12 +1534,12 @@ static int w9968cf_i2c_attach_inform(struct i2c_client* client)
                }
        } else {
                DBG(4, "Rejected client [%s] with driver [%s]", 
-                   clientname, client->driver->name)
+                   client->name, client->driver->name)
                return -EINVAL;
        }
 
        DBG(5, "I2C attach client [%s] with driver [%s]",
-           clientname, client->driver->name)
+           client->name, client->driver->name)
 
        return 0;
 }
@@ -1549,12 +1548,11 @@ static int w9968cf_i2c_attach_inform(struct i2c_client* client)
 static int w9968cf_i2c_detach_inform(struct i2c_client* client)
 {
        struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
-       const char* clientname = i2c_clientname(client);
 
        if (cam->sensor_client == client)
                cam->sensor_client = NULL;
 
-       DBG(5, "I2C detach client [%s]", clientname)
+       DBG(5, "I2C detach client [%s]", client->name)
 
        return 0;
 }
@@ -1573,15 +1571,13 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam)
        int err = 0;
 
        static struct i2c_algorithm algo = {
-               .name =          "W996[87]CF algorithm",
-               .id =            I2C_ALGO_SMBUS,
                .smbus_xfer =    w9968cf_i2c_smbus_xfer,
                .algo_control =  w9968cf_i2c_control,
                .functionality = w9968cf_i2c_func,
        };
 
        static struct i2c_adapter adap = {
-               .id =                I2C_ALGO_SMBUS | I2C_HW_SMBUS_W9968CF,
+               .id =                I2C_HW_SMBUS_W9968CF,
                .class =             I2C_CLASS_CAM_DIGITAL,
                .owner =             THIS_MODULE,
                .client_register =   w9968cf_i2c_attach_inform,
index cda7249a90b285225df15bb99b2d3af6e5b91589..fd7fb98e4b2029c752fa94d86f8b8d26e775779e 100644 (file)
@@ -1533,7 +1533,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
        if (down_interruptible (&dev->sem))
                return -ERESTARTSYS;
 
-       if (intf->dev.power.power_state != PMSG_ON) {
+       if (intf->dev.power.power_state.event != PM_EVENT_ON) {
                up (&dev->sem);
                return -EHOSTUNREACH;
        }
index 16f352195512e1d972be935e81b9e9cbf160f37d..fe3fd4115e1e31608745a070aded61063eaba818 100644 (file)
@@ -8,5 +8,3 @@ obj-$(CONFIG_USB_PEGASUS)       += pegasus.o
 obj-$(CONFIG_USB_RTL8150)      += rtl8150.o
 obj-$(CONFIG_USB_USBNET)       += usbnet.o
 obj-$(CONFIG_USB_ZD1201)       += zd1201.o
-
-CFLAGS_zd1201.o = -Idrivers/net/wireless/
index 4528a00c45b010f8ad6ef103e5eaae6ba8ae83a1..a2f67245f6da37adac5a5bb93e68aea202c3aafb 100644 (file)
@@ -2903,19 +2903,18 @@ static struct net_device_stats *usbnet_get_stats (struct net_device *net)
  * completion callbacks.  2.5 should have fixed those bugs...
  */
 
-static void defer_bh (struct usbnet *dev, struct sk_buff *skb)
+static void defer_bh(struct usbnet *dev, struct sk_buff *skb, struct sk_buff_head *list)
 {
-       struct sk_buff_head     *list = skb->list;
        unsigned long           flags;
 
-       spin_lock_irqsave (&list->lock, flags);
-       __skb_unlink (skb, list);
-       spin_unlock (&list->lock);
-       spin_lock (&dev->done.lock);
-       __skb_queue_tail (&dev->done, skb);
+       spin_lock_irqsave(&list->lock, flags);
+       __skb_unlink(skb, list);
+       spin_unlock(&list->lock);
+       spin_lock(&dev->done.lock);
+       __skb_queue_tail(&dev->done, skb);
        if (dev->done.qlen == 1)
-               tasklet_schedule (&dev->bh);
-       spin_unlock_irqrestore (&dev->done.lock, flags);
+               tasklet_schedule(&dev->bh);
+       spin_unlock_irqrestore(&dev->done.lock, flags);
 }
 
 /* some work can't be done in tasklets, so we use keventd
@@ -3120,7 +3119,7 @@ block:
                break;
        }
 
-       defer_bh (dev, skb);
+       defer_bh(dev, skb, &dev->rxq);
 
        if (urb) {
                if (netif_running (dev->net)
@@ -3490,7 +3489,7 @@ static void tx_complete (struct urb *urb, struct pt_regs *regs)
 
        urb->dev = NULL;
        entry->state = tx_done;
-       defer_bh (dev, skb);
+       defer_bh(dev, skb, &dev->txq);
 }
 
 /*-------------------------------------------------------------------------*/
index e32a80b39182b5dbbc06d15b2f96abf1897f9e7f..fc013978837e21fd756a594d53b6d52326b2646f 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/string.h>
 #include <linux/if_arp.h>
 #include <linux/firmware.h>
-#include <ieee802_11.h>
+#include <net/ieee80211.h>
 #include "zd1201.h"
 
 static struct usb_device_id zd1201_table[] = {
@@ -338,24 +338,24 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs)
                        goto resubmit;
                }
                        
-               if ((seq & IEEE802_11_SCTL_FRAG) ||
-                   (fc & IEEE802_11_FCTL_MOREFRAGS)) {
+               if ((seq & IEEE80211_SCTL_FRAG) ||
+                   (fc & IEEE80211_FCTL_MOREFRAGS)) {
                        struct zd1201_frag *frag = NULL;
                        char *ptr;
 
                        if (datalen<14)
                                goto resubmit;
-                       if ((seq & IEEE802_11_SCTL_FRAG) == 0) {
+                       if ((seq & IEEE80211_SCTL_FRAG) == 0) {
                                frag = kmalloc(sizeof(*frag), GFP_ATOMIC);
                                if (!frag)
                                        goto resubmit;
-                               skb = dev_alloc_skb(IEEE802_11_DATA_LEN +14+2);
+                               skb = dev_alloc_skb(IEEE80211_DATA_LEN +14+2);
                                if (!skb) {
                                        kfree(frag);
                                        goto resubmit;
                                }
                                frag->skb = skb;
-                               frag->seq = seq & IEEE802_11_SCTL_SEQ;
+                               frag->seq = seq & IEEE80211_SCTL_SEQ;
                                skb_reserve(skb, 2);
                                memcpy(skb_put(skb, 12), &data[datalen-14], 12);
                                memcpy(skb_put(skb, 2), &data[6], 2);
@@ -364,7 +364,7 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs)
                                goto resubmit;
                        }
                        hlist_for_each_entry(frag, node, &zd->fraglist, fnode)
-                               if(frag->seq == (seq&IEEE802_11_SCTL_SEQ))
+                               if(frag->seq == (seq&IEEE80211_SCTL_SEQ))
                                        break;
                        if (!frag)
                                goto resubmit;
@@ -372,7 +372,7 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs)
                        ptr = skb_put(skb, len);
                        if (ptr)
                                memcpy(ptr, data+8, len);
-                       if (fc & IEEE802_11_FCTL_MOREFRAGS)
+                       if (fc & IEEE80211_FCTL_MOREFRAGS)
                                goto resubmit;
                        hlist_del_init(&frag->fnode);
                        kfree(frag);
index 7bc1d44d88147d5368e2301a78254dba1f25f4bd..b0eba3ac6420f61e692118075fa5baf8bce2be4f 100644 (file)
@@ -2323,17 +2323,16 @@ static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state)
         * can properly take care of D3 ? Also, with swsusp, we
         * know we'll be rebooted, ...
         */
-#ifdef CONFIG_PPC_PMAC
+#ifndef CONFIG_PPC_PMAC
        /* HACK ALERT ! Once I find a proper way to say to each driver
         * individually what will happen with it's PCI slot, I'll change
         * that. On laptops, the AGP slot is just unclocked, so D2 is
         * expected, while on desktops, the card is powered off
         */
-       if (state >= 3)
-               state = 2;
+       return 0;
 #endif /* CONFIG_PPC_PMAC */
         
-       if (state != 2 || state == pdev->dev.power.power_state)
+       if (state.event == pdev->dev.power.power_state.event)
                return 0;
 
        printk(KERN_DEBUG "aty128fb: suspending...\n");
@@ -2367,7 +2366,7 @@ static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state)
         * used dummy fb ops, 2.5 need proper support for this at the
         * fbdev level
         */
-       if (state == 2)
+       if (state.event != PM_EVENT_ON)
                aty128_set_suspend(par, 1);
 
        release_console_sem();
@@ -2382,12 +2381,11 @@ static int aty128_do_resume(struct pci_dev *pdev)
        struct fb_info *info = pci_get_drvdata(pdev);
        struct aty128fb_par *par = info->par;
 
-       if (pdev->dev.power.power_state == 0)
+       if (pdev->dev.power.power_state.event == PM_EVENT_ON)
                return 0;
 
        /* Wakeup chip */
-       if (pdev->dev.power.power_state == 2)
-               aty128_set_suspend(par, 0);
+       aty128_set_suspend(par, 0);
        par->asleep = 0;
 
        /* Restore display & engine */
index 8c42538dc8c12db3ff65be3721bf6f3935e0533e..3e10bd837d9e8382a9f5bf5b0ac7073bb85bdd92 100644 (file)
@@ -2022,17 +2022,16 @@ static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        struct fb_info *info = pci_get_drvdata(pdev);
        struct atyfb_par *par = (struct atyfb_par *) info->par;
 
-#ifdef CONFIG_PPC_PMAC
+#ifndef CONFIG_PPC_PMAC
        /* HACK ALERT ! Once I find a proper way to say to each driver
         * individually what will happen with it's PCI slot, I'll change
         * that. On laptops, the AGP slot is just unclocked, so D2 is
         * expected, while on desktops, the card is powered off
         */
-       if (state >= 3)
-               state = 2;
+       return 0;
 #endif /* CONFIG_PPC_PMAC */
 
-       if (state != 2 || state == pdev->dev.power.power_state)
+       if (state.event == pdev->dev.power.power_state.event)
                return 0;
 
        acquire_console_sem();
@@ -2071,12 +2070,12 @@ static int atyfb_pci_resume(struct pci_dev *pdev)
        struct fb_info *info = pci_get_drvdata(pdev);
        struct atyfb_par *par = (struct atyfb_par *) info->par;
 
-       if (pdev->dev.power.power_state == 0)
+       if (pdev->dev.power.power_state.event == PM_EVENT_ON)
                return 0;
 
        acquire_console_sem();
 
-       if (pdev->dev.power.power_state == 2)
+       if (pdev->dev.power.power_state.event == 2)
                aty_power_mgmt(0, par);
        par->asleep = 0;
 
index 762244164c81a95f00f9d9728f1b9a47858e01fe..a9d0414e4655a0ad2885cbaa807494ef0f757fc3 100644 (file)
@@ -75,7 +75,7 @@ static int radeon_setup_i2c_bus(struct radeon_i2c_chan *chan, const char *name)
 
        strcpy(chan->adapter.name, name);
        chan->adapter.owner             = THIS_MODULE;
-       chan->adapter.id                = I2C_ALGO_ATI;
+       chan->adapter.id                = I2C_HW_B_RADEON;
        chan->adapter.algo_data         = &chan->algo;
        chan->adapter.dev.parent        = &chan->rinfo->pdev->dev;
        chan->algo.setsda               = radeon_gpio_setsda;
index 98352af393255d44907ad92270b4f236cc3210ac..59a1b6f85067863a87749913911b2386827ff898 100644 (file)
@@ -2526,18 +2526,18 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
         struct radeonfb_info *rinfo = info->par;
        int i;
 
-       if (state == pdev->dev.power.power_state)
+       if (state.event == pdev->dev.power.power_state.event)
                return 0;
 
        printk(KERN_DEBUG "radeonfb (%s): suspending to state: %d...\n",
-              pci_name(pdev), state);
+              pci_name(pdev), state.event);
 
        /* For suspend-to-disk, we cheat here. We don't suspend anything and
         * let fbcon continue drawing until we are all set. That shouldn't
         * really cause any problem at this point, provided that the wakeup
         * code knows that any state in memory may not match the HW
         */
-       if (state != PM_SUSPEND_MEM)
+       if (state.event == PM_EVENT_FREEZE)
                goto done;
 
        acquire_console_sem();
@@ -2616,7 +2616,7 @@ int radeonfb_pci_resume(struct pci_dev *pdev)
         struct radeonfb_info *rinfo = info->par;
        int rc = 0;
 
-       if (pdev->dev.power.power_state == 0)
+       if (pdev->dev.power.power_state.event == PM_EVENT_ON)
                return 0;
 
        if (rinfo->no_schedule) {
@@ -2626,7 +2626,7 @@ int radeonfb_pci_resume(struct pci_dev *pdev)
                acquire_console_sem();
 
        printk(KERN_DEBUG "radeonfb (%s): resuming from state: %d...\n",
-              pci_name(pdev), pdev->dev.power.power_state);
+              pci_name(pdev), pdev->dev.power.power_state.event);
 
 
        if (pci_enable_device(pdev)) {
@@ -2637,7 +2637,7 @@ int radeonfb_pci_resume(struct pci_dev *pdev)
        }
        pci_set_master(pdev);
 
-       if (pdev->dev.power.power_state == PM_SUSPEND_MEM) {
+       if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
                /* Wakeup chip. Check from config space if we were powered off
                 * (todo: additionally, check CLK_PIN_CNTL too)
                 */
index 9aae884475beab045f67487866e085ad13539224..4af321fae3901a42c0e9b1473fb138d5ebfb696f 100644 (file)
@@ -3,3 +3,4 @@
 obj-$(CONFIG_LCD_CLASS_DEVICE)     += lcd.o
 obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
 obj-$(CONFIG_BACKLIGHT_CORGI)  += corgi_bl.o
+obj-$(CONFIG_SHARP_LOCOMO)     += locomolcd.o
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c
new file mode 100644 (file)
index 0000000..ada6e75
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Backlight control code for Sharp Zaurus SL-5500
+ *
+ * Copyright 2005 John Lenz <lenz@cs.wisc.edu>
+ * Maintainer: Pavel Machek <pavel@suse.cz> (unless John wants to :-)
+ * GPL v2
+ *
+ * This driver assumes single CPU. That's okay, because collie is
+ * slightly old hardware, and noone is going to retrofit second CPU to
+ * old PDA.
+ */
+
+/* LCD power functions */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+
+#include <asm/hardware/locomo.h>
+#include <asm/irq.h>
+
+#ifdef CONFIG_SA1100_COLLIE
+#include <asm/arch/collie.h>
+#else
+#include <asm/arch/poodle.h>
+#endif
+
+extern void (*sa1100fb_lcd_power)(int on);
+
+static struct locomo_dev *locomolcd_dev;
+
+static void locomolcd_on(int comadj)
+{
+       locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 0);
+       locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 1);
+       mdelay(2);
+
+       locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 0);
+       locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 1);
+       mdelay(2);
+
+       locomo_m62332_senddata(locomolcd_dev, comadj, 0);
+       mdelay(5);
+
+       locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 0);
+       locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 1);
+       mdelay(10);
+
+       /* TFTCRST | CPSOUT=0 | CPSEN */
+       locomo_writel(0x01, locomolcd_dev->mapbase + LOCOMO_TC);
+
+       /* Set CPSD */
+       locomo_writel(6, locomolcd_dev->mapbase + LOCOMO_CPSD);
+
+       /* TFTCRST | CPSOUT=0 | CPSEN */
+       locomo_writel((0x04 | 0x01), locomolcd_dev->mapbase + LOCOMO_TC);
+       mdelay(10);
+
+       locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 0);
+       locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 1);
+}
+
+static void locomolcd_off(int comadj)
+{
+       /* TFTCRST=1 | CPSOUT=1 | CPSEN = 0 */
+       locomo_writel(0x06, locomolcd_dev->mapbase + LOCOMO_TC);
+       mdelay(1);
+
+       locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 0);
+       mdelay(110);
+
+       locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 0);
+       mdelay(700);
+
+       /* TFTCRST=0 | CPSOUT=0 | CPSEN = 0 */
+       locomo_writel(0, locomolcd_dev->mapbase + LOCOMO_TC);
+       locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 0);
+       locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 0);
+}
+
+void locomolcd_power(int on)
+{
+       int comadj = 118;
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       if (!locomolcd_dev) {
+               local_irq_restore(flags);
+               return;
+       }
+
+       /* read comadj */
+#ifdef CONFIG_MACH_POODLE
+       comadj = 118;
+#else
+       comadj = 128;
+#endif
+
+       if (on)
+               locomolcd_on(comadj);
+       else
+               locomolcd_off(comadj);
+
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL(locomolcd_power);
+
+static int poodle_lcd_probe(struct locomo_dev *dev)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       locomolcd_dev = dev;
+
+       /* the poodle_lcd_power function is called for the first time
+        * from fs_initcall, which is before locomo is activated.
+        * We need to recall poodle_lcd_power here*/
+#ifdef CONFIG_MACH_POODLE
+       locomolcd_power(1);
+#endif
+       local_irq_restore(flags);
+       return 0;
+}
+
+static int poodle_lcd_remove(struct locomo_dev *dev)
+{
+       unsigned long flags;
+       local_irq_save(flags);
+       locomolcd_dev = NULL;
+       local_irq_restore(flags);
+       return 0;
+}
+
+static struct locomo_driver poodle_lcd_driver = {
+       .drv = {
+               .name = "locomo-backlight",
+       },
+       .devid  = LOCOMO_DEVID_BACKLIGHT,
+       .probe  = poodle_lcd_probe,
+       .remove = poodle_lcd_remove,
+};
+
+static int __init poodle_lcd_init(void)
+{
+       int ret = locomo_driver_register(&poodle_lcd_driver);
+       if (ret) return ret;
+
+#ifdef CONFIG_SA1100_COLLIE
+       sa1100fb_lcd_power = locomolcd_power;
+#endif
+       return 0;
+}
+device_initcall(poodle_lcd_init);
+
index e75a965ec760324ff3ebe5705ebdeb4fb4c97ac6..4131243cfdf85e621263f547b7ebe6baf01985ca 100644 (file)
@@ -462,9 +462,9 @@ static int chipsfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
         struct fb_info *p = pci_get_drvdata(pdev);
 
-       if (state == pdev->dev.power.power_state)
+       if (state.event == pdev->dev.power.power_state.event)
                return 0;
-       if (state != PM_SUSPEND_MEM)
+       if (state.event != PM_SUSPEND_MEM)
                goto done;
 
        acquire_console_sem();
index 7513fb9b19cf739cc41afaf888efb0edae722587..6db183462b9200ff642b364492bb39c971ad1d4d 100644 (file)
@@ -1506,12 +1506,12 @@ static int i810fb_suspend(struct pci_dev *dev, pm_message_t state)
        struct i810fb_par *par = (struct i810fb_par *) info->par;
        int blank = 0, prev_state = par->cur_state;
 
-       if (state == prev_state)
+       if (state.event == prev_state)
                return 0;
 
-       par->cur_state = state;
+       par->cur_state = state.event;
 
-       switch (state) {
+       switch (state.event) {
        case 1:
                blank = VESA_VSYNC_SUSPEND;
                break;
index 67f85344f0cc3d3e70edd617e76080788ddfef04..ad60bbb16cdf0dedd14d69333c025dd19718f2a3 100644 (file)
@@ -1271,7 +1271,7 @@ ERROR0:;
 }
 
 static int maven_attach_adapter(struct i2c_adapter* adapter) {
-       if (adapter->id == (I2C_ALGO_BIT | I2C_HW_B_G400))
+       if (adapter->id == I2C_HW_B_G400)
                return i2c_probe(adapter, &addr_data, &maven_detect_client);
        return 0;
 }
index 3757c1407c190144a1dd2190fc92c3b2d0bc7362..1a91bffdda26b78b6cbc38256c856b6f1b0264a9 100644 (file)
@@ -90,14 +90,13 @@ static int nvidia_gpio_getsda(void *data)
        return val;
 }
 
-#define I2C_ALGO_NVIDIA   0x0e0000
 static int nvidia_setup_i2c_bus(struct nvidia_i2c_chan *chan, const char *name)
 {
        int rc;
 
        strcpy(chan->adapter.name, name);
        chan->adapter.owner = THIS_MODULE;
-       chan->adapter.id = I2C_ALGO_NVIDIA;
+       chan->adapter.id = I2C_HW_B_NVIDIA;
        chan->adapter.algo_data = &chan->algo;
        chan->adapter.dev.parent = &chan->par->pci_dev->dev;
        chan->algo.setsda = nvidia_gpio_setsda;
index 3e00ad7f2e3179496086053639fc8ace2716fdf5..28d1fe5fe34007fcdf9996cb0216154732e74f1e 100644 (file)
@@ -413,7 +413,7 @@ static struct fb_ops aafb_ops = {
 
 static int __init init_one(int slot)
 {
-       unsigned long base_addr = get_tc_base_addr(slot);
+       unsigned long base_addr = CKSEG1ADDR(get_tc_base_addr(slot));
        struct aafb_info *ip = &my_fb_info[slot];
 
        memset(ip, 0, sizeof(struct aafb_info));
index f8095588e99d075b88e6056750833a3ccb9f7478..c98f1c8d7dc27b6127fc430ceea517772b1de11d 100644 (file)
@@ -1,57 +1,55 @@
 /*
- *      linux/drivers/video/pmag-ba-fb.c
+ *     linux/drivers/video/pmag-ba-fb.c
  *
- *     PMAG-BA TurboChannel framebuffer card support ... derived from:
+ *     PMAG-BA TURBOchannel Color Frame Buffer (CFB) card support,
+ *     derived from:
  *     "HP300 Topcat framebuffer support (derived from macfb of all things)
  *     Phil Blundell <philb@gnu.org> 1998", the original code can be
- *      found in the file hpfb.c in the same directory.
+ *     found in the file hpfb.c in the same directory.
  *
  *     Based on digital document:
  *     "PMAG-BA TURBOchannel Color Frame Buffer
  *      Functional Specification", Revision 1.2, August 27, 1990
  *
- *      DECstation related code Copyright (C) 1999, 2000, 2001 by
- *      Michael Engel <engel@unix-ag.org>, 
- *      Karsten Merker <merker@linuxtag.org> and
+ *     DECstation related code Copyright (C) 1999, 2000, 2001 by
+ *     Michael Engel <engel@unix-ag.org>,
+ *     Karsten Merker <merker@linuxtag.org> and
  *     Harald Koerfgen.
- *      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 (c) 2005  Maciej W. Rozycki
  *
+ *     This file is subject to the terms and conditions of the GNU General
+ *     Public License.  See the file COPYING in the main directory of this
+ *     archive for more details.
  */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
+
+#include <linux/compiler.h>
 #include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/fb.h>
-#include <asm/bootinfo.h>
-#include <asm/dec/machtype.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include <asm/bug.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
 #include <asm/dec/tc.h>
+
 #include <video/pmag-ba-fb.h>
 
-struct pmag_ba_ramdac_regs {
-       unsigned char addr_low;
-       unsigned char pad0[3];
-       unsigned char addr_hi;
-       unsigned char pad1[3];
-       unsigned char data;
-       unsigned char pad2[3];
-       unsigned char cmap;
+
+struct pmagbafb_par {
+       struct fb_info *next;
+       volatile void __iomem *mmio;
+       volatile u32 __iomem *dac;
+       int slot;
 };
 
-/*
- * Max 3 TURBOchannel slots -> max 3 PMAG-BA :)
- */
-static struct fb_info pmagba_fb_info[3];
 
-static struct fb_var_screeninfo pmagbafb_defined = {
+static struct fb_info *root_pmagbafb_dev;
+
+static struct fb_var_screeninfo pmagbafb_defined __initdata = {
        .xres           = 1024,
        .yres           = 864,
        .xres_virtual   = 1024,
@@ -61,58 +59,71 @@ static struct fb_var_screeninfo pmagbafb_defined = {
        .green.length   = 8,
        .blue.length    = 8,
        .activate       = FB_ACTIVATE_NOW,
-       .height         = 274,
-       .width          = 195,
-       .accel          = FB_ACCEL_NONE,
+       .height         = -1,
+       .width          = -1,
+       .accel_flags    = FB_ACCEL_NONE,
+       .pixclock       = 14452,
+       .left_margin    = 116,
+       .right_margin   = 12,
+       .upper_margin   = 34,
+       .lower_margin   = 12,
+       .hsync_len      = 128,
+       .vsync_len      = 3,
+       .sync           = FB_SYNC_ON_GREEN,
        .vmode          = FB_VMODE_NONINTERLACED,
 };
 
-static struct fb_fix_screeninfo pmagbafb_fix = {
+static struct fb_fix_screeninfo pmagbafb_fix __initdata = {
        .id             = "PMAG-BA",
-       .smem_len       = (1024 * 864),
+       .smem_len       = (1024 * 1024),
        .type           = FB_TYPE_PACKED_PIXELS,
        .visual         = FB_VISUAL_PSEUDOCOLOR,
        .line_length    = 1024,
+       .mmio_len       = PMAG_BA_SIZE - PMAG_BA_BT459,
 };
 
-/*
- * Turn hardware cursor off
- */
-void pmagbafb_erase_cursor(struct pmag_ba_ramdac_regs *bt459_regs)
+
+static inline void dac_write(struct pmagbafb_par *par, unsigned int reg, u8 v)
 {
-       bt459_regs->addr_low = 0;
-       bt459_regs->addr_hi = 3;
-       bt459_regs->data = 0;
+       writeb(v, par->dac + reg / 4);
 }
 
+static inline u8 dac_read(struct pmagbafb_par *par, unsigned int reg)
+{
+       return readb(par->dac + reg / 4);
+}
+
+
 /*
- * Set the palette. 
+ * Set the palette.
  */
-static int pmagbafb_setcolreg(unsigned regno, unsigned red, unsigned green,
-                             unsigned blue, unsigned transp,
-                             struct fb_info *info)
+static int pmagbafb_setcolreg(unsigned int regno, unsigned int red,
+                             unsigned int green, unsigned int blue,
+                             unsigned int transp, struct fb_info *info)
 {
-       struct pmag_ba_ramdac_regs *bt459_regs = (struct pmag_ba_ramdac_regs *) info->par;
+       struct pmagbafb_par *par = info->par;
 
-       if (regno >= info->cmap.len)
-               return 1;
+       BUG_ON(regno >= info->cmap.len);
 
        red   >>= 8;    /* The cmap fields are 16 bits    */
-       green >>= 8;    /* wide, but the harware colormap */
+       green >>= 8;    /* wide, but the hardware colormap */
        blue  >>= 8;    /* registers are only 8 bits wide */
 
-       bt459_regs->addr_low = (__u8) regno;
-       bt459_regs->addr_hi = 0;
-       bt459_regs->cmap = red;
-       bt459_regs->cmap = green;
-       bt459_regs->cmap = blue;
+       mb();
+       dac_write(par, BT459_ADDR_LO, regno);
+       dac_write(par, BT459_ADDR_HI, 0x00);
+       wmb();
+       dac_write(par, BT459_CMAP, red);
+       wmb();
+       dac_write(par, BT459_CMAP, green);
+       wmb();
+       dac_write(par, BT459_CMAP, blue);
+
        return 0;
 }
 
 static struct fb_ops pmagbafb_ops = {
        .owner          = THIS_MODULE,
-       .fb_get_fix     = gen_get_fix,
-       .fb_get_var     = gen_get_var,
        .fb_setcolreg   = pmagbafb_setcolreg,
        .fb_fillrect    = cfb_fillrect,
        .fb_copyarea    = cfb_copyarea,
@@ -120,63 +131,133 @@ static struct fb_ops pmagbafb_ops = {
        .fb_cursor      = soft_cursor,
 };
 
-int __init pmagbafb_init_one(int slot)
+
+/*
+ * Turn the hardware cursor off.
+ */
+static void __init pmagbafb_erase_cursor(struct fb_info *info)
+{
+       struct pmagbafb_par *par = info->par;
+
+       mb();
+       dac_write(par, BT459_ADDR_LO, 0x00);
+       dac_write(par, BT459_ADDR_HI, 0x03);
+       wmb();
+       dac_write(par, BT459_DATA, 0x00);
+}
+
+
+static int __init pmagbafb_init_one(int slot)
 {
-       unsigned long base_addr = get_tc_base_addr(slot);
-       struct fb_info *info = &pmagba_fb_info[slot]; 
-       struct display *disp = &pmagba_disp[slot];
-
-       printk("PMAG-BA framebuffer in slot %d\n", slot);
-       /*
-        * Framebuffer display memory base address and friends
-        */
-       pmagbafb_fix.smem_start = base_addr + PMAG_BA_ONBOARD_FBMEM_OFFSET;
-       info->par = (base_addr + PMAG_BA_BT459_OFFSET);
-
-       /*
-        * Configure the Bt459 RAM DAC
-        */
-       pmagbafb_erase_cursor((struct pmag_ba_ramdac_regs *) info->par);
-
-       /*
-        *      Let there be consoles..
-        */
+       struct fb_info *info;
+       struct pmagbafb_par *par;
+       unsigned long base_addr;
+
+       info = framebuffer_alloc(sizeof(struct pmagbafb_par), NULL);
+       if (!info)
+               return -ENOMEM;
+
+       par = info->par;
+       par->slot = slot;
+       claim_tc_card(par->slot);
+
+       base_addr = get_tc_base_addr(par->slot);
+
+       par->next = root_pmagbafb_dev;
+       root_pmagbafb_dev = info;
+
+       if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
+               goto err_alloc;
+
        info->fbops = &pmagbafb_ops;
+       info->fix = pmagbafb_fix;
        info->var = pmagbafb_defined;
-       info->fix = pmagbafb_fix; 
-       info->screen_base = pmagbafb_fix.smem_start;
        info->flags = FBINFO_DEFAULT;
 
-       fb_alloc_cmap(&fb_info.cmap, 256, 0);
+       /* MMIO mapping setup.  */
+       info->fix.mmio_start = base_addr;
+       par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
+       if (!par->mmio)
+               goto err_cmap;
+       par->dac = par->mmio + PMAG_BA_BT459;
+
+       /* Frame buffer mapping setup.  */
+       info->fix.smem_start = base_addr + PMAG_BA_FBMEM;
+       info->screen_base = ioremap_nocache(info->fix.smem_start,
+                                           info->fix.smem_len);
+       if (!info->screen_base)
+               goto err_mmio_map;
+       info->screen_size = info->fix.smem_len;
+
+       pmagbafb_erase_cursor(info);
 
        if (register_framebuffer(info) < 0)
-               return 1;
+               goto err_smem_map;
+
+       pr_info("fb%d: %s frame buffer device in slot %d\n",
+               info->node, info->fix.id, par->slot);
+
        return 0;
+
+
+err_smem_map:
+       iounmap(info->screen_base);
+
+err_mmio_map:
+       iounmap(par->mmio);
+
+err_cmap:
+       fb_dealloc_cmap(&info->cmap);
+
+err_alloc:
+       root_pmagbafb_dev = par->next;
+       release_tc_card(par->slot);
+       framebuffer_release(info);
+       return -ENXIO;
 }
 
-/* 
- * Initialise the framebuffer
- */
+static void __exit pmagbafb_exit_one(void)
+{
+       struct fb_info *info = root_pmagbafb_dev;
+       struct pmagbafb_par *par = info->par;
 
-int __init pmagbafb_init(void)
+       unregister_framebuffer(info);
+       iounmap(info->screen_base);
+       iounmap(par->mmio);
+       fb_dealloc_cmap(&info->cmap);
+       root_pmagbafb_dev = par->next;
+       release_tc_card(par->slot);
+       framebuffer_release(info);
+}
+
+
+/*
+ * Initialise the framebuffer.
+ */
+static int __init pmagbafb_init(void)
 {
-       int sid;
-       int found = 0;
+       int count = 0;
+       int slot;
 
        if (fb_get_options("pmagbafb", NULL))
-               return -ENODEV;
-
-       if (TURBOCHANNEL) {
-               while ((sid = search_tc_card("PMAG-BA")) >= 0) {
-                       found = 1;
-                       claim_tc_card(sid);
-                       pmagbafb_init_one(sid);
-               }
-               return found ? 0 : -ENODEV;
-       } else {
-               return -ENODEV;
+               return -ENXIO;
+
+       while ((slot = search_tc_card("PMAG-BA")) >= 0) {
+               if (pmagbafb_init_one(slot) < 0)
+                       break;
+               count++;
        }
+       return (count > 0) ? 0 : -ENXIO;
 }
 
+static void __exit pmagbafb_exit(void)
+{
+       while (root_pmagbafb_dev)
+               pmagbafb_exit_one();
+}
+
+
 module_init(pmagbafb_init);
+module_exit(pmagbafb_exit);
+
 MODULE_LICENSE("GPL");
index d14eaee91cfffd63d9ddd171e4f466a4a4d5640e..a483b13e117b71f93eab7b0e042075b481adf547 100644 (file)
 /*
- *      linux/drivers/video/pmagb-b-fb.c
+ *     linux/drivers/video/pmagb-b-fb.c
  *
- *     PMAGB-B TurboChannel framebuffer card support ... derived from:
+ *     PMAGB-B TURBOchannel Smart Frame Buffer (SFB) card support,
+ *     derived from:
  *     "HP300 Topcat framebuffer support (derived from macfb of all things)
  *     Phil Blundell <philb@gnu.org> 1998", the original code can be
- *      found in the file hpfb.c in the same directory.
+ *     found in the file hpfb.c in the same directory.
  *
- *      DECstation related code Copyright (C) 1999, 2000, 2001 by
- *      Michael Engel <engel@unix-ag.org>,
- *      Karsten Merker <merker@linuxtag.org> and 
+ *     DECstation related code Copyright (C) 1999, 2000, 2001 by
+ *     Michael Engel <engel@unix-ag.org>,
+ *     Karsten Merker <merker@linuxtag.org> and
  *     Harald Koerfgen.
- *      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 (c) 2005  Maciej W. Rozycki
  *
+ *     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.
  */
 
-/*
- *      We currently only support the PMAGB-B in high resolution mode
- *      as I know of no way to detect low resolution mode set via jumper.
- *      KM, 2001/01/07
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
+#include <linux/compiler.h>
 #include <linux/delay.h>
-#include <linux/init.h>
+#include <linux/errno.h>
 #include <linux/fb.h>
-#include <asm/bootinfo.h>
-#include <asm/dec/machtype.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include <asm/bug.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
 #include <asm/dec/tc.h>
+
 #include <video/pmagb-b-fb.h>
 
-struct pmagb_b_ramdac_regs {
-       unsigned char addr_low;
-       unsigned char pad0[3];
-       unsigned char addr_hi;
-       unsigned char pad1[3];
-       unsigned char data;
-       unsigned char pad2[3];
-       unsigned char cmap;
+
+struct pmagbbfb_par {
+       struct fb_info *next;
+       volatile void __iomem *mmio;
+       volatile void __iomem *smem;
+       volatile u32 __iomem *sfb;
+       volatile u32 __iomem *dac;
+       unsigned int osc0;
+       unsigned int osc1;
+       int slot;
 };
 
-/*
- * Max 3 TURBOchannel slots -> max 3 PMAGB-B :)
- */
-static struct fb_info pmagbb_fb_info[3];
 
-static struct fb_var_screeninfo pmagbbfb_defined = {
-       .xres           = 1280,
-       .yres           = 1024,
-       .xres_virtual   = 1280,
-       .yres_virtual   = 1024,
+static struct fb_info *root_pmagbbfb_dev;
+
+static struct fb_var_screeninfo pmagbbfb_defined __initdata = {
        .bits_per_pixel = 8,
        .red.length     = 8,
        .green.length   = 8,
        .blue.length    = 8,
        .activate       = FB_ACTIVATE_NOW,
-       .height         = 274,
-       .width          = 195,
+       .height         = -1,
+       .width          = -1,
        .accel_flags    = FB_ACCEL_NONE,
+       .sync           = FB_SYNC_ON_GREEN,
        .vmode          = FB_VMODE_NONINTERLACED,
 };
 
-static struct fb_fix_screeninfo pmagbafb_fix = {
+static struct fb_fix_screeninfo pmagbbfb_fix __initdata = {
        .id             = "PMAGB-BA",
-       .smem_len       = (1280 * 1024),
+       .smem_len       = (2048 * 1024),
        .type           = FB_TYPE_PACKED_PIXELS,
        .visual         = FB_VISUAL_PSEUDOCOLOR,
-       .line_length    = 1280,
+       .mmio_len       = PMAGB_B_FBMEM,
+};
+
+
+static inline void sfb_write(struct pmagbbfb_par *par, unsigned int reg, u32 v)
+{
+       writel(v, par->sfb + reg / 4);
 }
 
-/*
- * Turn hardware cursor off
- */
-void pmagbbfb_erase_cursor(struct pmagb_b_ramdac_regs *bt459_regs)
+static inline u32 sfb_read(struct pmagbbfb_par *par, unsigned int reg)
+{
+       return readl(par->sfb + reg / 4);
+}
+
+static inline void dac_write(struct pmagbbfb_par *par, unsigned int reg, u8 v)
 {
-       bt459_regs->addr_low = 0;
-       bt459_regs->addr_hi = 3;
-       bt459_regs->data = 0;
+       writeb(v, par->dac + reg / 4);
 }
 
+static inline u8 dac_read(struct pmagbbfb_par *par, unsigned int reg)
+{
+       return readb(par->dac + reg / 4);
+}
+
+static inline void gp0_write(struct pmagbbfb_par *par, u32 v)
+{
+       writel(v, par->mmio + PMAGB_B_GP0);
+}
+
+
 /*
- * Set the palette. 
+ * Set the palette.
  */
-static int pmagbbfb_setcolreg(unsigned regno, unsigned red, unsigned green,
-                              unsigned blue, unsigned transp,
-                              struct fb_info *info)
+static int pmagbbfb_setcolreg(unsigned int regno, unsigned int red,
+                             unsigned int green, unsigned int blue,
+                             unsigned int transp, struct fb_info *info)
 {
-       struct pmagb_b_ramdac_regs *bt459_regs = (struct pmagb_b_ramdac_regs *) info->par;
-       
-       if (regno >= info->cmap.len)
-               return 1;
+       struct pmagbbfb_par *par = info->par;
+
+       BUG_ON(regno >= info->cmap.len);
 
        red   >>= 8;    /* The cmap fields are 16 bits    */
-       green >>= 8;    /* wide, but the harware colormap */
+       green >>= 8;    /* wide, but the hardware colormap */
        blue  >>= 8;    /* registers are only 8 bits wide */
 
-       bt459_regs->addr_low = (__u8) regno;
-       bt459_regs->addr_hi = 0;
-       bt459_regs->cmap = red;
-       bt459_regs->cmap = green;
-       bt459_regs->cmap = blue;
+       mb();
+       dac_write(par, BT459_ADDR_LO, regno);
+       dac_write(par, BT459_ADDR_HI, 0x00);
+       wmb();
+       dac_write(par, BT459_CMAP, red);
+       wmb();
+       dac_write(par, BT459_CMAP, green);
+       wmb();
+       dac_write(par, BT459_CMAP, blue);
+
        return 0;
 }
 
@@ -121,62 +135,247 @@ static struct fb_ops pmagbbfb_ops = {
        .fb_cursor      = soft_cursor,
 };
 
-int __init pmagbbfb_init_one(int slot)
+
+/*
+ * Turn the hardware cursor off.
+ */
+static void __init pmagbbfb_erase_cursor(struct fb_info *info)
+{
+       struct pmagbbfb_par *par = info->par;
+
+       mb();
+       dac_write(par, BT459_ADDR_LO, 0x00);
+       dac_write(par, BT459_ADDR_HI, 0x03);
+       wmb();
+       dac_write(par, BT459_DATA, 0x00);
+}
+
+/*
+ * Set up screen parameters.
+ */
+static void __init pmagbbfb_screen_setup(struct fb_info *info)
+{
+       struct pmagbbfb_par *par = info->par;
+
+       info->var.xres = ((sfb_read(par, SFB_REG_VID_HOR) >>
+                          SFB_VID_HOR_PIX_SHIFT) & SFB_VID_HOR_PIX_MASK) * 4;
+       info->var.xres_virtual = info->var.xres;
+       info->var.yres = (sfb_read(par, SFB_REG_VID_VER) >>
+                         SFB_VID_VER_SL_SHIFT) & SFB_VID_VER_SL_MASK;
+       info->var.yres_virtual = info->var.yres;
+       info->var.left_margin = ((sfb_read(par, SFB_REG_VID_HOR) >>
+                                 SFB_VID_HOR_BP_SHIFT) &
+                                SFB_VID_HOR_BP_MASK) * 4;
+       info->var.right_margin = ((sfb_read(par, SFB_REG_VID_HOR) >>
+                                  SFB_VID_HOR_FP_SHIFT) &
+                                 SFB_VID_HOR_FP_MASK) * 4;
+       info->var.upper_margin = (sfb_read(par, SFB_REG_VID_VER) >>
+                                 SFB_VID_VER_BP_SHIFT) & SFB_VID_VER_BP_MASK;
+       info->var.lower_margin = (sfb_read(par, SFB_REG_VID_VER) >>
+                                 SFB_VID_VER_FP_SHIFT) & SFB_VID_VER_FP_MASK;
+       info->var.hsync_len = ((sfb_read(par, SFB_REG_VID_HOR) >>
+                               SFB_VID_HOR_SYN_SHIFT) &
+                              SFB_VID_HOR_SYN_MASK) * 4;
+       info->var.vsync_len = (sfb_read(par, SFB_REG_VID_VER) >>
+                              SFB_VID_VER_SYN_SHIFT) & SFB_VID_VER_SYN_MASK;
+
+       info->fix.line_length = info->var.xres;
+};
+
+/*
+ * Determine oscillator configuration.
+ */
+static void __init pmagbbfb_osc_setup(struct fb_info *info)
 {
-       unsigned long base_addr = get_tc_base_addr(slot);
-       struct fb_info *info = &pmagbb_fb_info[slot];
-
-       printk("PMAGB-BA framebuffer in slot %d\n", slot);
-       /*
-        * Framebuffer display memory base address and friends
-        */
-       pmagbbfb_fix.smem_start = base_addr + PMAGB_B_ONBOARD_FBMEM_OFFSET;
-       info->par = (base_addr + PMAGB_B_BT459_OFFSET); 
-       
-       /*
-        * Configure the Bt459 RAM DAC
-        */
-       pmagbbfb_erase_cursor((struct pmagb_b_ramdac_regs *) info->par);
-
-       /*
-        *      Let there be consoles..
-        */
+       static unsigned int pmagbbfb_freqs[] __initdata = {
+               130808, 119843, 104000, 92980, 74367, 72800,
+               69197, 66000, 65000, 50350, 36000, 32000, 25175
+       };
+       struct pmagbbfb_par *par = info->par;
+       u32 count0 = 8, count1 = 8, counttc = 16 * 256 + 8;
+       u32 freq0, freq1, freqtc = get_tc_speed() / 250;
+       int i, j;
+
+       gp0_write(par, 0);                              /* select Osc0 */
+       for (j = 0; j < 16; j++) {
+               mb();
+               sfb_write(par, SFB_REG_TCCLK_COUNT, 0);
+               mb();
+               for (i = 0; i < 100; i++) {     /* nominally max. 20.5us */
+                       if (sfb_read(par, SFB_REG_TCCLK_COUNT) == 0)
+                               break;
+                       udelay(1);
+               }
+               count0 += sfb_read(par, SFB_REG_VIDCLK_COUNT);
+       }
+
+       gp0_write(par, 1);                              /* select Osc1 */
+       for (j = 0; j < 16; j++) {
+               mb();
+               sfb_write(par, SFB_REG_TCCLK_COUNT, 0);
+
+               for (i = 0; i < 100; i++) {     /* nominally max. 20.5us */
+                       if (sfb_read(par, SFB_REG_TCCLK_COUNT) == 0)
+                               break;
+                       udelay(1);
+               }
+               count1 += sfb_read(par, SFB_REG_VIDCLK_COUNT);
+       }
+
+       freq0 = (freqtc * count0 + counttc / 2) / counttc;
+       par->osc0 = freq0;
+       if (freq0 >= pmagbbfb_freqs[0] - (pmagbbfb_freqs[0] + 32) / 64 &&
+           freq0 <= pmagbbfb_freqs[0] + (pmagbbfb_freqs[0] + 32) / 64)
+               par->osc0 = pmagbbfb_freqs[0];
+
+       freq1 = (par->osc0 * count1 + count0 / 2) / count0;
+       par->osc1 = freq1;
+       for (i = 0; i < sizeof(pmagbbfb_freqs) / sizeof(*pmagbbfb_freqs); i++)
+               if (freq1 >= pmagbbfb_freqs[i] -
+                            (pmagbbfb_freqs[i] + 128) / 256 &&
+                   freq1 <= pmagbbfb_freqs[i] +
+                            (pmagbbfb_freqs[i] + 128) / 256) {
+                       par->osc1 = pmagbbfb_freqs[i];
+                       break;
+               }
+
+       if (par->osc0 - par->osc1 <= (par->osc0 + par->osc1 + 256) / 512 ||
+           par->osc1 - par->osc0 <= (par->osc0 + par->osc1 + 256) / 512)
+               par->osc1 = 0;
+
+       gp0_write(par, par->osc1 != 0);                 /* reselect OscX */
+
+       info->var.pixclock = par->osc1 ?
+                            (1000000000 + par->osc1 / 2) / par->osc1 :
+                            (1000000000 + par->osc0 / 2) / par->osc0;
+};
+
+
+static int __init pmagbbfb_init_one(int slot)
+{
+       char freq0[12], freq1[12];
+       struct fb_info *info;
+       struct pmagbbfb_par *par;
+       unsigned long base_addr;
+       u32 vid_base;
+
+       info = framebuffer_alloc(sizeof(struct pmagbbfb_par), NULL);
+       if (!info)
+               return -ENOMEM;
+
+       par = info->par;
+       par->slot = slot;
+       claim_tc_card(par->slot);
+
+       base_addr = get_tc_base_addr(par->slot);
+
+       par->next = root_pmagbbfb_dev;
+       root_pmagbbfb_dev = info;
+
+       if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
+               goto err_alloc;
+
        info->fbops = &pmagbbfb_ops;
-       info->var = pmagbbfb_defined;
        info->fix = pmagbbfb_fix;
-       info->screen_base = pmagbbfb_fix.smem_start; 
+       info->var = pmagbbfb_defined;
        info->flags = FBINFO_DEFAULT;
 
-       fb_alloc_cmap(&fb_info.cmap, 256, 0);
+       /* MMIO mapping setup.  */
+       info->fix.mmio_start = base_addr;
+       par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
+       if (!par->mmio)
+               goto err_cmap;
+       par->sfb = par->mmio + PMAGB_B_SFB;
+       par->dac = par->mmio + PMAGB_B_BT459;
+
+       /* Frame buffer mapping setup.  */
+       info->fix.smem_start = base_addr + PMAGB_B_FBMEM;
+       par->smem = ioremap_nocache(info->fix.smem_start, info->fix.smem_len);
+       if (!par->smem)
+               goto err_mmio_map;
+       vid_base = sfb_read(par, SFB_REG_VID_BASE);
+       info->screen_base = (void __iomem *)par->smem + vid_base * 0x1000;
+       info->screen_size = info->fix.smem_len - 2 * vid_base * 0x1000;
+
+       pmagbbfb_erase_cursor(info);
+       pmagbbfb_screen_setup(info);
+       pmagbbfb_osc_setup(info);
 
        if (register_framebuffer(info) < 0)
-               return 1;
+               goto err_smem_map;
+
+       snprintf(freq0, sizeof(freq0), "%u.%03uMHz",
+                par->osc0 / 1000, par->osc0 % 1000);
+       snprintf(freq1, sizeof(freq1), "%u.%03uMHz",
+                par->osc1 / 1000, par->osc1 % 1000);
+
+       pr_info("fb%d: %s frame buffer device in slot %d\n",
+               info->node, info->fix.id, par->slot);
+       pr_info("fb%d: Osc0: %s, Osc1: %s, Osc%u selected\n",
+               info->node, freq0, par->osc1 ? freq1 : "disabled",
+               par->osc1 != 0);
+
        return 0;
+
+
+err_smem_map:
+       iounmap(par->smem);
+
+err_mmio_map:
+       iounmap(par->mmio);
+
+err_cmap:
+       fb_dealloc_cmap(&info->cmap);
+
+err_alloc:
+       root_pmagbbfb_dev = par->next;
+       release_tc_card(par->slot);
+       framebuffer_release(info);
+       return -ENXIO;
 }
 
-/* 
- * Initialise the framebuffer
- */
+static void __exit pmagbbfb_exit_one(void)
+{
+       struct fb_info *info = root_pmagbbfb_dev;
+       struct pmagbbfb_par *par = info->par;
+
+       unregister_framebuffer(info);
+       iounmap(par->smem);
+       iounmap(par->mmio);
+       fb_dealloc_cmap(&info->cmap);
+       root_pmagbbfb_dev = par->next;
+       release_tc_card(par->slot);
+       framebuffer_release(info);
+}
 
-int __init pmagbbfb_init(void)
+
+/*
+ * Initialise the framebuffer.
+ */
+static int __init pmagbbfb_init(void)
 {
-       int sid;
-       int found = 0;
+       int count = 0;
+       int slot;
 
        if (fb_get_options("pmagbbfb", NULL))
-               return -ENODEV;
+               return -ENXIO;
 
-       if (TURBOCHANNEL) {
-               while ((sid = search_tc_card("PMAGB-BA")) >= 0) {
-                       found = 1;
-                       claim_tc_card(sid);
-                       pmagbbfb_init_one(sid);
-               }
-               return found ? 0 : -ENODEV;
-       } else {
-               return -ENODEV;
+       while ((slot = search_tc_card("PMAGB-BA")) >= 0) {
+               if (pmagbbfb_init_one(slot) < 0)
+                       break;
+               count++;
        }
+       return (count > 0) ? 0 : -ENXIO;
+}
+
+static void __exit pmagbbfb_exit(void)
+{
+       while (root_pmagbbfb_dev)
+               pmagbbfb_exit_one();
 }
 
+
 module_init(pmagbbfb_init);
+module_exit(pmagbbfb_exit);
+
 MODULE_LICENSE("GPL");
index 71b69da0c40d761b36f1891f02b2448a1caac7de..162012bb9264edd2bb58af8b4d9b609e4b940697 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/setup.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/q40_master.h>
 #include <linux/fb.h>
index da1334dfd51d3e4ceb493055846b4aca92e4b700..77151d8e076661d4a44fd92cd9d8737190725987 100644 (file)
@@ -92,14 +92,13 @@ static int riva_gpio_getsda(void* data)
        return val;
 }
 
-#define I2C_ALGO_RIVA   0x0e0000
 static int riva_setup_i2c_bus(struct riva_i2c_chan *chan, const char *name)
 {
        int rc;
 
        strcpy(chan->adapter.name, name);
        chan->adapter.owner             = THIS_MODULE;
-       chan->adapter.id                = I2C_ALGO_RIVA;
+       chan->adapter.id                = I2C_HW_B_RIVA;
        chan->adapter.algo_data         = &chan->algo;
        chan->adapter.dev.parent        = &chan->par->pdev->dev;
        chan->algo.setsda               = riva_gpio_setsda;
index 3848be2b9d2d6e9a30194dd693f368c70d1d1dfa..fa98d91c42eb2cd858b516fdcc384833094672b1 100644 (file)
@@ -655,7 +655,7 @@ bail:
 }
 
 #ifdef CONFIG_PM
-static int s1d13xxxfb_suspend(struct device *dev, u32 state, u32 level)
+static int s1d13xxxfb_suspend(struct device *dev, pm_message_t state, u32 level)
 {
        struct fb_info *info = dev_get_drvdata(dev);
        struct s1d13xxxfb_par *s1dfb = info->par;
index 024a0cecff1563770c8be6b6709cfa5c15ec41d5..847698b5cfe7d3b2c1e518eedc5f910d451db452 100644 (file)
@@ -137,7 +137,6 @@ static int prosavage_gpio_getsda(void* data)
        return (0 != (GET_CR_DATA(chan->ioaddr) & PROSAVAGE_I2C_SDA_IN));
 }
 
-#define I2C_ALGO_SAVAGE   0x0f0000
 static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan,
                                const char *name)
 {
@@ -147,7 +146,7 @@ static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan,
        if (add_bus && chan->par) {
                strcpy(chan->adapter.name, name);
                chan->adapter.owner             = THIS_MODULE;
-               chan->adapter.id                = I2C_ALGO_SAVAGE;
+               chan->adapter.id                = I2C_HW_B_SAVAGE;
                chan->adapter.algo_data         = &chan->algo;
                chan->adapter.dev.parent        = &chan->par->pcidev->dev;
                chan->algo.udelay               = 40;
index f4633d1891f121070b68ae5c4cb4f53cf0d76ddc..117ad42f120d9c867599a36bcd0a804045732246 100644 (file)
@@ -2110,7 +2110,6 @@ static int savagefb_suspend (struct pci_dev* dev, pm_message_t state)
        struct savagefb_par *par = (struct savagefb_par *)info->par;
 
        DBG("savagefb_suspend");
-       printk(KERN_DEBUG "state: %u\n", state);
 
        acquire_console_sem();
        fb_set_suspend(info, pci_choose_state(dev, state));
index adcda697ea60d537accf3c9f9fa5e93f6695b856..0030c071da8fd5409ebb1e3276ccb09fec4bbcd3 100644 (file)
@@ -5,9 +5,15 @@
  *
  * Copyright (C) 2002, ATI Corp.
  * Copyright (C) 2004-2005 Richard Purdie
+ * Copyright (c) 2005 Ian Molton
  *
  * Rewritten for 2.6 by Richard Purdie <rpurdie@rpsys.net>
  *
+ * Generic platform support by Ian Molton <spyro@f2s.com>
+ * and Richard Purdie <rpurdie@rpsys.net>
+ *
+ * w32xx support by Ian Molton
+ *
  * 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.
@@ -21,7 +27,7 @@
 #include <linux/mm.h>
 #include <linux/device.h>
 #include <linux/string.h>
-#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <video/w100fb.h>
 /*
  * Prototypes
  */
-static void w100fb_save_buffer(void);
-static void w100fb_clear_buffer(void);
-static void w100fb_restore_buffer(void);
-static void w100fb_clear_screen(u32 mode, long int offset);
-static void w100_resume(void);
 static void w100_suspend(u32 mode);
-static void w100_init_qvga_rotation(u16 deg);
-static void w100_init_vga_rotation(u16 deg);
 static void w100_vsync(void);
-static void w100_init_sharp_lcd(u32 mode);
-static void w100_pwm_setup(void);
-static void w100_InitExtMem(u32 mode);
-static void w100_hw_init(void);
-static u16 w100_set_fastsysclk(u16 Freq);
-
-static void lcdtg_hw_init(u32 mode);
-static void lcdtg_lcd_change(u32 mode);
-static void lcdtg_resume(void);
-static void lcdtg_suspend(void);
-
-
-/* Register offsets & lengths */
-#define REMAPPED_FB_LEN   0x15ffff
-
-#define BITS_PER_PIXEL    16
+static void w100_hw_init(struct w100fb_par*);
+static void w100_pwm_setup(struct w100fb_par*);
+static void w100_init_clocks(struct w100fb_par*);
+static void w100_setup_memory(struct w100fb_par*);
+static void w100_init_lcd(struct w100fb_par*);
+static void w100_set_dispregs(struct w100fb_par*);
+static void w100_update_enable(void);
+static void w100_update_disable(void);
+static void calc_hsync(struct w100fb_par *par);
+struct w100_pll_info *w100_get_xtal_table(unsigned int freq);
 
 /* Pseudo palette size */
 #define MAX_PALETTES      16
 
-/* for resolution change */
-#define LCD_MODE_INIT (-1)
-#define LCD_MODE_480    0
-#define LCD_MODE_320    1
-#define LCD_MODE_240    2
-#define LCD_MODE_640    3
-
-#define LCD_SHARP_QVGA 0
-#define LCD_SHARP_VGA  1
-
-#define LCD_MODE_PORTRAIT      0
-#define LCD_MODE_LANDSCAPE     1
-
 #define W100_SUSPEND_EXTMEM 0
 #define W100_SUSPEND_ALL    1
 
-/* General frame buffer data structures */
-struct w100fb_par {
-       u32 xres;
-       u32 yres;
-       int fastsysclk_mode;
-       int lcdMode;
-       int rotation_flag;
-       int blanking_flag;
-       int comadj;
-       int phadadj;
-};
-
-static struct w100fb_par *current_par;
+#define BITS_PER_PIXEL    16
 
 /* Remapped addresses for base cfg, memmapped regs and the frame buffer itself */
 static void *remapped_base;
 static void *remapped_regs;
 static void *remapped_fbuf;
 
-/* External Function */
-static void(*w100fb_ssp_send)(u8 adrs, u8 data);
+#define REMAPPED_FB_LEN   0x15ffff
+
+/* This is the offset in the w100's address space we map the current
+   framebuffer memory to. We use the position of external memory as
+   we can remap internal memory to there if external isn't present. */
+#define W100_FB_BASE MEM_EXT_BASE_VALUE
+
 
 /*
  * Sysfs functions
  */
-
-static ssize_t rotation_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t flip_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct fb_info *info = dev_get_drvdata(dev);
        struct w100fb_par *par=info->par;
 
-       return sprintf(buf, "%d\n",par->rotation_flag);
+       return sprintf(buf, "%d\n",par->flip);
 }
 
-static ssize_t rotation_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t flip_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-       unsigned int rotate;
+       unsigned int flip;
        struct fb_info *info = dev_get_drvdata(dev);
        struct w100fb_par *par=info->par;
 
-       rotate = simple_strtoul(buf, NULL, 10);
+       flip = simple_strtoul(buf, NULL, 10);
+
+       if (flip > 0)
+               par->flip = 1;
+       else
+               par->flip = 0;
 
-       if (rotate > 0) par->rotation_flag = 1;
-       else par->rotation_flag = 0;
+       w100_update_disable();
+       w100_set_dispregs(par);
+       w100_update_enable();
 
-       if (par->lcdMode == LCD_MODE_320)
-               w100_init_qvga_rotation(par->rotation_flag ? 270 : 90);
-       else if (par->lcdMode == LCD_MODE_240)
-               w100_init_qvga_rotation(par->rotation_flag ? 180 : 0);
-       else if (par->lcdMode == LCD_MODE_640)
-               w100_init_vga_rotation(par->rotation_flag ? 270 : 90);
-       else if (par->lcdMode == LCD_MODE_480)
-               w100_init_vga_rotation(par->rotation_flag ? 180 : 0);
+       calc_hsync(par);
 
        return count;
 }
 
-static DEVICE_ATTR(rotation, 0644, rotation_show, rotation_store);
+static DEVICE_ATTR(flip, 0644, flip_show, flip_store);
 
 static ssize_t w100fb_reg_read(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-       unsigned long param;
-       unsigned long regs;
+       unsigned long regs, param;
        regs = simple_strtoul(buf, NULL, 16);
        param = readl(remapped_regs + regs);
        printk("Read Register 0x%08lX: 0x%08lX\n", regs, param);
@@ -148,8 +118,7 @@ static DEVICE_ATTR(reg_read, 0200, NULL, w100fb_reg_read);
 
 static ssize_t w100fb_reg_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-       unsigned long regs;
-       unsigned long param;
+       unsigned long regs, param;
        sscanf(buf, "%lx %lx", &regs, &param);
 
        if (regs <= 0x2000) {
@@ -163,54 +132,56 @@ static ssize_t w100fb_reg_write(struct device *dev, struct device_attribute *att
 static DEVICE_ATTR(reg_write, 0200, NULL, w100fb_reg_write);
 
 
-static ssize_t fastsysclk_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t fastpllclk_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct fb_info *info = dev_get_drvdata(dev);
        struct w100fb_par *par=info->par;
 
-       return sprintf(buf, "%d\n",par->fastsysclk_mode);
+       return sprintf(buf, "%d\n",par->fastpll_mode);
 }
 
-static ssize_t fastsysclk_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t fastpllclk_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-       int param;
        struct fb_info *info = dev_get_drvdata(dev);
        struct w100fb_par *par=info->par;
 
-       param = simple_strtoul(buf, NULL, 10);
-
-       if (param == 75) {
-               printk("Set fastsysclk %d\n", param);
-               par->fastsysclk_mode = param;
-               w100_set_fastsysclk(par->fastsysclk_mode);
-       } else if (param == 100) {
-               printk("Set fastsysclk %d\n", param);
-               par->fastsysclk_mode = param;
-               w100_set_fastsysclk(par->fastsysclk_mode);
+       if (simple_strtoul(buf, NULL, 10) > 0) {
+               par->fastpll_mode=1;
+               printk("w100fb: Using fast system clock (if possible)\n");
+       } else {
+               par->fastpll_mode=0;
+               printk("w100fb: Using normal system clock\n");
        }
+
+       w100_init_clocks(par);
+       calc_hsync(par);
+
        return count;
 }
 
-static DEVICE_ATTR(fastsysclk, 0644, fastsysclk_show, fastsysclk_store);
+static DEVICE_ATTR(fastpllclk, 0644, fastpllclk_show, fastpllclk_store);
 
 /*
- * The touchscreen on this device needs certain information
- * from the video driver to function correctly. We export it here.
+ * Some touchscreens need hsync information from the video driver to
+ * function correctly. We export it here.
  */
-int w100fb_get_xres(void) {
-       return current_par->xres;
-}
+unsigned long w100fb_get_hsynclen(struct device *dev)
+{
+       struct fb_info *info = dev_get_drvdata(dev);
+       struct w100fb_par *par=info->par;
 
-int w100fb_get_blanking(void) {
-       return current_par->blanking_flag;
+       /* If display is blanked/suspended, hsync isn't active */
+       if (par->blanked)
+               return 0;
+       else
+               return par->hsync_len;
 }
+EXPORT_SYMBOL(w100fb_get_hsynclen);
 
-int w100fb_get_fastsysclk(void) {
-       return current_par->fastsysclk_mode;
+static void w100fb_clear_screen(struct w100fb_par *par)
+{
+       memset_io(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), 0, (par->xres * par->yres * BITS_PER_PIXEL/8));
 }
-EXPORT_SYMBOL(w100fb_get_xres);
-EXPORT_SYMBOL(w100fb_get_blanking);
-EXPORT_SYMBOL(w100fb_get_fastsysclk);
 
 
 /*
@@ -234,7 +205,6 @@ static int w100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
         * according to the RGB bitfield information.
         */
        if (regno < MAX_PALETTES) {
-
                u32 *pal = info->pseudo_palette;
 
                val = (red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
@@ -250,115 +220,90 @@ static int w100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  */
 static int w100fb_blank(int blank_mode, struct fb_info *info)
 {
-       struct w100fb_par *par;
-       par=info->par;
+       struct w100fb_par *par = info->par;
+       struct w100_tg_info *tg = par->mach->tg;
 
        switch(blank_mode) {
 
-       case FB_BLANK_NORMAL: /* Normal blanking */
-       case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
-       case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
-       case FB_BLANK_POWERDOWN: /* Poweroff */
-               if (par->blanking_flag == 0) {
-                       w100fb_save_buffer();
-                       lcdtg_suspend();
-                       par->blanking_flag = 1;
+       case FB_BLANK_NORMAL:         /* Normal blanking */
+       case FB_BLANK_VSYNC_SUSPEND:  /* VESA blank (vsync off) */
+       case FB_BLANK_HSYNC_SUSPEND:  /* VESA blank (hsync off) */
+       case FB_BLANK_POWERDOWN:      /* Poweroff */
+               if (par->blanked == 0) {
+                       if(tg && tg->suspend)
+                               tg->suspend(par);
+                       par->blanked = 1;
                }
                break;
 
        case FB_BLANK_UNBLANK: /* Unblanking */
-               if (par->blanking_flag != 0) {
-                       w100fb_restore_buffer();
-                       lcdtg_resume();
-                       par->blanking_flag = 0;
+               if (par->blanked != 0) {
+                       if(tg && tg->resume)
+                               tg->resume(par);
+                       par->blanked = 0;
                }
                break;
        }
        return 0;
 }
 
+
 /*
  *  Change the resolution by calling the appropriate hardware functions
  */
-static void w100fb_changeres(int rotate_mode, u32 mode)
+static void w100fb_activate_var(struct w100fb_par *par)
 {
-       u16 rotation=0;
-
-       switch(rotate_mode) {
-       case LCD_MODE_LANDSCAPE:
-               rotation=(current_par->rotation_flag ? 270 : 90);
-               break;
-       case LCD_MODE_PORTRAIT:
-               rotation=(current_par->rotation_flag ? 180 : 0);
-               break;
-       }
+       struct w100_tg_info *tg = par->mach->tg;
 
-       w100_pwm_setup();
-       switch(mode) {
-       case LCD_SHARP_QVGA:
-               w100_vsync();
-               w100_suspend(W100_SUSPEND_EXTMEM);
-               w100_init_sharp_lcd(LCD_SHARP_QVGA);
-               w100_init_qvga_rotation(rotation);
-               w100_InitExtMem(LCD_SHARP_QVGA);
-               w100fb_clear_screen(LCD_SHARP_QVGA, 0);
-               lcdtg_lcd_change(LCD_SHARP_QVGA);
-               break;
-       case LCD_SHARP_VGA:
-               w100fb_clear_screen(LCD_SHARP_QVGA, 0);
-               writel(0xBFFFA000, remapped_regs + mmMC_EXT_MEM_LOCATION);
-               w100_InitExtMem(LCD_SHARP_VGA);
-               w100fb_clear_screen(LCD_SHARP_VGA, 0x200000);
-               w100_vsync();
-               w100_init_sharp_lcd(LCD_SHARP_VGA);
-               if (rotation != 0)
-                       w100_init_vga_rotation(rotation);
-               lcdtg_lcd_change(LCD_SHARP_VGA);
-               break;
-       }
+       w100_pwm_setup(par);
+       w100_setup_memory(par);
+       w100_init_clocks(par);
+       w100fb_clear_screen(par);
+       w100_vsync();
+
+       w100_update_disable();
+       w100_init_lcd(par);
+       w100_set_dispregs(par);
+       w100_update_enable();
+
+       calc_hsync(par);
+
+       if (!par->blanked && tg && tg->change)
+               tg->change(par);
 }
 
-/*
- * Set up the display for the fb subsystem
+
+/* Select the smallest mode that allows the desired resolution to be
+ * displayed. If desired, the x and y parameters can be rounded up to
+ * match the selected mode.
  */
-static void w100fb_activate_var(struct fb_info *info)
+static struct w100_mode *w100fb_get_mode(struct w100fb_par *par, unsigned int *x, unsigned int *y, int saveval)
 {
-       u32 temp32;
-       struct w100fb_par *par=info->par;
-       struct fb_var_screeninfo *var = &info->var;
+       struct w100_mode *mode = NULL;
+       struct w100_mode *modelist = par->mach->modelist;
+       unsigned int best_x = 0xffffffff, best_y = 0xffffffff;
+       unsigned int i;
+
+       for (i = 0 ; i < par->mach->num_modes ; i++) {
+               if (modelist[i].xres >= *x && modelist[i].yres >= *y &&
+                               modelist[i].xres < best_x && modelist[i].yres < best_y) {
+                       best_x = modelist[i].xres;
+                       best_y = modelist[i].yres;
+                       mode = &modelist[i];
+               } else if(modelist[i].xres >= *y && modelist[i].yres >= *x &&
+                       modelist[i].xres < best_y && modelist[i].yres < best_x) {
+                       best_x = modelist[i].yres;
+                       best_y = modelist[i].xres;
+                       mode = &modelist[i];
+               }
+       }
 
-       /* Set the hardware to 565 */
-       temp32 = readl(remapped_regs + mmDISP_DEBUG2);
-       temp32 &= 0xff7fffff;
-       temp32 |= 0x00800000;
-       writel(temp32, remapped_regs + mmDISP_DEBUG2);
+       if (mode && saveval) {
+               *x = best_x;
+               *y = best_y;
+       }
 
-       if (par->lcdMode == LCD_MODE_INIT) {
-               w100_init_sharp_lcd(LCD_SHARP_VGA);
-               w100_init_vga_rotation(par->rotation_flag ? 270 : 90);
-               par->lcdMode = LCD_MODE_640;
-               lcdtg_hw_init(LCD_SHARP_VGA);
-       } else if (var->xres == 320 && var->yres == 240) {
-               if (par->lcdMode != LCD_MODE_320) {
-                       w100fb_changeres(LCD_MODE_LANDSCAPE, LCD_SHARP_QVGA);
-                       par->lcdMode = LCD_MODE_320;
-               }
-       } else if (var->xres == 240 && var->yres == 320) {
-               if (par->lcdMode != LCD_MODE_240) {
-                       w100fb_changeres(LCD_MODE_PORTRAIT, LCD_SHARP_QVGA);
-                       par->lcdMode = LCD_MODE_240;
-               }
-       } else if (var->xres == 640 && var->yres == 480) {
-               if (par->lcdMode != LCD_MODE_640) {
-                       w100fb_changeres(LCD_MODE_LANDSCAPE, LCD_SHARP_VGA);
-                       par->lcdMode = LCD_MODE_640;
-               }
-       } else if (var->xres == 480 && var->yres == 640) {
-               if (par->lcdMode != LCD_MODE_480) {
-                       w100fb_changeres(LCD_MODE_PORTRAIT, LCD_SHARP_VGA);
-                       par->lcdMode = LCD_MODE_480;
-               }
-       } else printk(KERN_ERR "W100FB: Resolution error!\n");
+       return mode;
 }
 
 
@@ -366,31 +311,19 @@ static void w100fb_activate_var(struct fb_info *info)
  *  w100fb_check_var():
  *  Get the video params out of 'var'. If a value doesn't fit, round it up,
  *  if it's too big, return -EINVAL.
- *
  */
 static int w100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
-       if (var->xres < var->yres) { /* Portrait mode */
-               if ((var->xres > 480) || (var->yres > 640)) {
-                       return -EINVAL;
-               } else if ((var->xres > 240) || (var->yres > 320)) {
-                       var->xres = 480;
-                       var->yres = 640;
-               } else {
-                       var->xres = 240;
-                       var->yres = 320;
-               }
-       } else { /* Landscape mode */
-               if ((var->xres > 640) || (var->yres > 480)) {
-                       return -EINVAL;
-               } else if ((var->xres > 320) || (var->yres > 240)) {
-                       var->xres = 640;
-                       var->yres = 480;
-               } else {
-                       var->xres = 320;
-                       var->yres = 240;
-               }
-       }
+       struct w100fb_par *par=info->par;
+
+       if(!w100fb_get_mode(par, &var->xres, &var->yres, 1))
+               return -EINVAL;
+
+       if (par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (par->mach->mem->size+1)))
+               return -EINVAL;
+
+       if (!par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)))
+               return -EINVAL;
 
        var->xres_virtual = max(var->xres_virtual, var->xres);
        var->yres_virtual = max(var->yres_virtual, var->yres);
@@ -409,13 +342,11 @@ static int w100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        var->transp.offset = var->transp.length = 0;
 
        var->nonstd = 0;
-
        var->height = -1;
        var->width = -1;
        var->vmode = FB_VMODE_NONINTERLACED;
-
        var->sync = 0;
-       var->pixclock = 0x04;   /* 171521; */
+       var->pixclock = 0x04;  /* 171521; */
 
        return 0;
 }
@@ -430,274 +361,286 @@ static int w100fb_set_par(struct fb_info *info)
 {
        struct w100fb_par *par=info->par;
 
-       par->xres = info->var.xres;
-       par->yres = info->var.yres;
-
-       info->fix.visual = FB_VISUAL_TRUECOLOR;
-
-       info->fix.ypanstep = 0;
-       info->fix.ywrapstep = 0;
+       if (par->xres != info->var.xres || par->yres != info->var.yres) {
+               par->xres = info->var.xres;
+               par->yres = info->var.yres;
+               par->mode = w100fb_get_mode(par, &par->xres, &par->yres, 0);
 
-       if (par->blanking_flag)
-               w100fb_clear_buffer();
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+               info->fix.ypanstep = 0;
+               info->fix.ywrapstep = 0;
+               info->fix.line_length = par->xres * BITS_PER_PIXEL / 8;
 
-       w100fb_activate_var(info);
+               if ((par->xres*par->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)) {
+                       par->extmem_active = 1;
+                       info->fix.smem_len = par->mach->mem->size+1;
+               } else {
+                       par->extmem_active = 0;
+                       info->fix.smem_len = MEM_INT_SIZE+1;
+               }
 
-       if (par->lcdMode == LCD_MODE_480) {
-               info->fix.line_length = (480 * BITS_PER_PIXEL) / 8;
-               info->fix.smem_len = 0x200000;
-       } else if (par->lcdMode == LCD_MODE_320) {
-               info->fix.line_length = (320 * BITS_PER_PIXEL) / 8;
-               info->fix.smem_len = 0x60000;
-       } else if (par->lcdMode == LCD_MODE_240) {
-               info->fix.line_length = (240 * BITS_PER_PIXEL) / 8;
-               info->fix.smem_len = 0x60000;
-       } else if (par->lcdMode == LCD_MODE_INIT || par->lcdMode == LCD_MODE_640) {
-               info->fix.line_length = (640 * BITS_PER_PIXEL) / 8;
-               info->fix.smem_len = 0x200000;
+               w100fb_activate_var(par);
        }
-
        return 0;
 }
 
 
 /*
- *      Frame buffer operations
+ *  Frame buffer operations
  */
 static struct fb_ops w100fb_ops = {
-       .owner = THIS_MODULE,
+       .owner        = THIS_MODULE,
        .fb_check_var = w100fb_check_var,
-       .fb_set_par = w100fb_set_par,
+       .fb_set_par   = w100fb_set_par,
        .fb_setcolreg = w100fb_setcolreg,
-       .fb_blank = w100fb_blank,
-       .fb_fillrect = cfb_fillrect,
-       .fb_copyarea = cfb_copyarea,
+       .fb_blank     = w100fb_blank,
+       .fb_fillrect  = cfb_fillrect,
+       .fb_copyarea  = cfb_copyarea,
        .fb_imageblit = cfb_imageblit,
-       .fb_cursor = soft_cursor,
+       .fb_cursor    = soft_cursor,
 };
 
-
-static void w100fb_clear_screen(u32 mode, long int offset)
+#ifdef CONFIG_PM
+static void w100fb_save_vidmem(struct w100fb_par *par)
 {
-       int i, numPix = 0;
-
-       if (mode == LCD_SHARP_VGA)
-               numPix = 640 * 480;
-       else if (mode == LCD_SHARP_QVGA)
-               numPix = 320 * 240;
+       int memsize;
 
-       for (i = 0; i < numPix; i++)
-               writew(0xffff, remapped_fbuf + offset + (2*i));
-}
-
-
-/* Need to split up the buffers to stay within the limits of kmalloc */
-#define W100_BUF_NUM   6
-static uint32_t *gSaveImagePtr[W100_BUF_NUM] = { NULL };
-
-static void w100fb_save_buffer(void)
-{
-       int i, j, bufsize;
-
-       bufsize=(current_par->xres * current_par->yres * BITS_PER_PIXEL / 8) / W100_BUF_NUM;
-       for (i = 0; i < W100_BUF_NUM; i++) {
-               if (gSaveImagePtr[i] == NULL)
-                       gSaveImagePtr[i] = kmalloc(bufsize, GFP_KERNEL);
-               if (gSaveImagePtr[i] == NULL) {
-                       w100fb_clear_buffer();
-                       printk(KERN_WARNING "can't alloc pre-off image buffer %d\n", i);
-                       break;
-               }
-               for (j = 0; j < bufsize/4; j++)
-                       *(gSaveImagePtr[i] + j) = readl(remapped_fbuf + (bufsize*i) + j*4);
+       if (par->extmem_active) {
+               memsize=par->mach->mem->size;
+               par->saved_extmem = vmalloc(memsize);
+               if (par->saved_extmem)
+                       memcpy_fromio(par->saved_extmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize);
        }
+       memsize=MEM_INT_SIZE;
+       par->saved_intmem = vmalloc(memsize);
+       if (par->saved_intmem && par->extmem_active)
+               memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), memsize);
+       else if (par->saved_intmem)
+               memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize);
 }
 
-
-static void w100fb_restore_buffer(void)
+static void w100fb_restore_vidmem(struct w100fb_par *par)
 {
-       int i, j, bufsize;
+       int memsize;
 
-       bufsize=(current_par->xres * current_par->yres * BITS_PER_PIXEL / 8) / W100_BUF_NUM;
-       for (i = 0; i < W100_BUF_NUM; i++) {
-               if (gSaveImagePtr[i] == NULL) {
-                       printk(KERN_WARNING "can't find pre-off image buffer %d\n", i);
-                       w100fb_clear_buffer();
-                       break;
-               }
-               for (j = 0; j < (bufsize/4); j++)
-                       writel(*(gSaveImagePtr[i] + j),remapped_fbuf + (bufsize*i) + (j*4));
-               kfree(gSaveImagePtr[i]);
-               gSaveImagePtr[i] = NULL;
+       if (par->extmem_active && par->saved_extmem) {
+               memsize=par->mach->mem->size;
+               memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_extmem, memsize);
+               vfree(par->saved_extmem);
        }
-}
-
-
-static void w100fb_clear_buffer(void)
-{
-       int i;
-       for (i = 0; i < W100_BUF_NUM; i++) {
-               kfree(gSaveImagePtr[i]);
-               gSaveImagePtr[i] = NULL;
+       if (par->saved_intmem) {
+               memsize=MEM_INT_SIZE;
+               if (par->extmem_active)
+                       memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), par->saved_intmem, memsize);
+               else
+                       memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_intmem, memsize);
+               vfree(par->saved_intmem);
        }
 }
 
-
-#ifdef CONFIG_PM
-static int w100fb_suspend(struct device *dev, pm_message_t state, u32 level)
+static int w100fb_suspend(struct device *dev, pm_message_t state, uint32_t level)
 {
        if (level == SUSPEND_POWER_DOWN) {
                struct fb_info *info = dev_get_drvdata(dev);
                struct w100fb_par *par=info->par;
+               struct w100_tg_info *tg = par->mach->tg;
 
-               w100fb_save_buffer();
-               lcdtg_suspend();
+               w100fb_save_vidmem(par);
+               if(tg && tg->suspend)
+                       tg->suspend(par);
                w100_suspend(W100_SUSPEND_ALL);
-               par->blanking_flag = 1;
+               par->blanked = 1;
        }
        return 0;
 }
 
-static int w100fb_resume(struct device *dev, u32 level)
+static int w100fb_resume(struct device *dev, uint32_t level)
 {
        if (level == RESUME_POWER_ON) {
                struct fb_info *info = dev_get_drvdata(dev);
                struct w100fb_par *par=info->par;
-
-               w100_resume();
-               w100fb_restore_buffer();
-               lcdtg_resume();
-               par->blanking_flag = 0;
+               struct w100_tg_info *tg = par->mach->tg;
+
+               w100_hw_init(par);
+               w100fb_activate_var(par);
+               w100fb_restore_vidmem(par);
+               if(tg && tg->resume)
+                       tg->resume(par);
+               par->blanked = 0;
        }
        return 0;
 }
 #else
-#define w100fb_suspend NULL
-#define w100fb_resume  NULL
+#define w100fb_suspend  NULL
+#define w100fb_resume   NULL
 #endif
 
 
 int __init w100fb_probe(struct device *dev)
 {
+       int err = -EIO;
        struct w100fb_mach_info *inf;
-       struct fb_info *info;
+       struct fb_info *info = NULL;
        struct w100fb_par *par;
        struct platform_device *pdev = to_platform_device(dev);
        struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       unsigned int chip_id;
 
        if (!mem)
                return -EINVAL;
 
-       /* remap the areas we're going to use */
+       /* Remap the chip base address */
        remapped_base = ioremap_nocache(mem->start+W100_CFG_BASE, W100_CFG_LEN);
        if (remapped_base == NULL)
-               return -EIO;
+               goto out;
 
+       /* Map the register space */
        remapped_regs = ioremap_nocache(mem->start+W100_REG_BASE, W100_REG_LEN);
-       if (remapped_regs == NULL) {
-               iounmap(remapped_base);
-               return -EIO;
+       if (remapped_regs == NULL)
+               goto out;
+
+       /* Identify the chip */
+       printk("Found ");
+       chip_id = readl(remapped_regs + mmCHIP_ID);
+       switch(chip_id) {
+               case CHIP_ID_W100:  printk("w100");  break;
+               case CHIP_ID_W3200: printk("w3200"); break;
+               case CHIP_ID_W3220: printk("w3220"); break;
+               default:
+                       printk("Unknown imageon chip ID\n");
+                       err = -ENODEV;
+                       goto out;
        }
+       printk(" at 0x%08lx.\n", mem->start+W100_CFG_BASE);
 
-       remapped_fbuf = ioremap_nocache(mem->start+MEM_EXT_BASE_VALUE, REMAPPED_FB_LEN);
-       if (remapped_fbuf == NULL) {
-               iounmap(remapped_base);
-               iounmap(remapped_regs);
-               return -EIO;
-       }
+       /* Remap the framebuffer */
+       remapped_fbuf = ioremap_nocache(mem->start+MEM_WINDOW_BASE, MEM_WINDOW_SIZE);
+       if (remapped_fbuf == NULL)
+               goto out;
 
        info=framebuffer_alloc(sizeof(struct w100fb_par), dev);
        if (!info) {
-               iounmap(remapped_base);
-               iounmap(remapped_regs);
-               iounmap(remapped_fbuf);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto out;
        }
 
-       info->device=dev;
        par = info->par;
-       current_par=info->par;
        dev_set_drvdata(dev, info);
 
        inf = dev->platform_data;
-       par->phadadj = inf->phadadj;
-       par->comadj = inf->comadj;
-       par->fastsysclk_mode = 75;
-       par->lcdMode = LCD_MODE_INIT;
-       par->rotation_flag=0;
-       par->blanking_flag=0;
-       w100fb_ssp_send = inf->w100fb_ssp_send;
-
-       w100_hw_init();
-       w100_pwm_setup();
+       par->chip_id = chip_id;
+       par->mach = inf;
+       par->fastpll_mode = 0;
+       par->blanked = 0;
+
+       par->pll_table=w100_get_xtal_table(inf->xtal_freq);
+       if (!par->pll_table) {
+               printk(KERN_ERR "No matching Xtal definition found\n");
+               err = -EINVAL;
+               goto out;
+       }
 
        info->pseudo_palette = kmalloc(sizeof (u32) * MAX_PALETTES, GFP_KERNEL);
        if (!info->pseudo_palette) {
-               iounmap(remapped_base);
-               iounmap(remapped_regs);
-               iounmap(remapped_fbuf);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto out;
        }
 
        info->fbops = &w100fb_ops;
        info->flags = FBINFO_DEFAULT;
        info->node = -1;
-       info->screen_base = remapped_fbuf;
+       info->screen_base = remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE);
        info->screen_size = REMAPPED_FB_LEN;
 
-       info->var.xres = 640;
+       strcpy(info->fix.id, "w100fb");
+       info->fix.type = FB_TYPE_PACKED_PIXELS;
+       info->fix.type_aux = 0;
+       info->fix.accel = FB_ACCEL_NONE;
+       info->fix.smem_start = mem->start+W100_FB_BASE;
+       info->fix.mmio_start = mem->start+W100_REG_BASE;
+       info->fix.mmio_len = W100_REG_LEN;
+
+       if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       par->mode = &inf->modelist[0];
+       if(inf->init_mode & INIT_MODE_ROTATED) {
+               info->var.xres = par->mode->yres;
+               info->var.yres = par->mode->xres;
+       }
+       else {
+               info->var.xres = par->mode->xres;
+               info->var.yres = par->mode->yres;
+       }
+
+       if(inf->init_mode &= INIT_MODE_FLIPPED)
+               par->flip = 1;
+       else
+               par->flip = 0;
+
        info->var.xres_virtual = info->var.xres;
-       info->var.yres = 480;
        info->var.yres_virtual = info->var.yres;
-       info->var.pixclock = 0x04;      /* 171521; */
+       info->var.pixclock = 0x04;  /* 171521; */
        info->var.sync = 0;
        info->var.grayscale = 0;
        info->var.xoffset = info->var.yoffset = 0;
        info->var.accel_flags = 0;
        info->var.activate = FB_ACTIVATE_NOW;
 
-       strcpy(info->fix.id, "w100fb");
-       info->fix.type = FB_TYPE_PACKED_PIXELS;
-       info->fix.type_aux = 0;
-       info->fix.accel = FB_ACCEL_NONE;
-       info->fix.smem_start = mem->start+MEM_EXT_BASE_VALUE;
-       info->fix.mmio_start = mem->start+W100_REG_BASE;
-       info->fix.mmio_len = W100_REG_LEN;
+       w100_hw_init(par);
+
+       if (w100fb_check_var(&info->var, info) < 0) {
+               err = -EINVAL;
+               goto out;
+       }
 
-       w100fb_check_var(&info->var, info);
        w100fb_set_par(info);
 
        if (register_framebuffer(info) < 0) {
-               kfree(info->pseudo_palette);
-               iounmap(remapped_base);
-               iounmap(remapped_regs);
-               iounmap(remapped_fbuf);
-               return -EINVAL;
+               err = -EINVAL;
+               goto out;
        }
 
-       device_create_file(dev, &dev_attr_fastsysclk);
+       device_create_file(dev, &dev_attr_fastpllclk);
        device_create_file(dev, &dev_attr_reg_read);
        device_create_file(dev, &dev_attr_reg_write);
-       device_create_file(dev, &dev_attr_rotation);
+       device_create_file(dev, &dev_attr_flip);
 
        printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id);
        return 0;
+out:
+       fb_dealloc_cmap(&info->cmap);
+       kfree(info->pseudo_palette);
+       if (remapped_fbuf != NULL)
+               iounmap(remapped_fbuf);
+       if (remapped_regs != NULL)
+               iounmap(remapped_regs);
+       if (remapped_base != NULL)
+               iounmap(remapped_base);
+       if (info)
+               framebuffer_release(info);
+       return err;
 }
 
 
 static int w100fb_remove(struct device *dev)
 {
        struct fb_info *info = dev_get_drvdata(dev);
+       struct w100fb_par *par=info->par;
 
-       device_remove_file(dev, &dev_attr_fastsysclk);
+       device_remove_file(dev, &dev_attr_fastpllclk);
        device_remove_file(dev, &dev_attr_reg_read);
        device_remove_file(dev, &dev_attr_reg_write);
-       device_remove_file(dev, &dev_attr_rotation);
+       device_remove_file(dev, &dev_attr_flip);
 
        unregister_framebuffer(info);
 
-       w100fb_clear_buffer();
+       vfree(par->saved_intmem);
+       vfree(par->saved_extmem);
        kfree(info->pseudo_palette);
+       fb_dealloc_cmap(&info->cmap);
 
        iounmap(remapped_base);
        iounmap(remapped_regs);
@@ -721,10 +664,54 @@ static void w100_soft_reset(void)
        udelay(100);
 }
 
+static void w100_update_disable(void)
+{
+       union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
+
+       /* Prevent display updates */
+       disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
+       disp_db_buf_wr_cntl.f.update_db_buf = 0;
+       disp_db_buf_wr_cntl.f.en_db_buf = 0;
+       writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
+}
+
+static void w100_update_enable(void)
+{
+       union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
+
+       /* Enable display updates */
+       disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
+       disp_db_buf_wr_cntl.f.update_db_buf = 1;
+       disp_db_buf_wr_cntl.f.en_db_buf = 1;
+       writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
+}
+
+unsigned long w100fb_gpio_read(int port)
+{
+       unsigned long value;
+
+       if (port==W100_GPIO_PORT_A)
+               value = readl(remapped_regs + mmGPIO_DATA);
+       else
+               value = readl(remapped_regs + mmGPIO_DATA2);
+
+       return value;
+}
+
+void w100fb_gpio_write(int port, unsigned long value)
+{
+       if (port==W100_GPIO_PORT_A)
+               value = writel(value, remapped_regs + mmGPIO_DATA);
+       else
+               value = writel(value, remapped_regs + mmGPIO_DATA2);
+}
+EXPORT_SYMBOL(w100fb_gpio_read);
+EXPORT_SYMBOL(w100fb_gpio_write);
+
 /*
  * Initialization of critical w100 hardware
  */
-static void w100_hw_init(void)
+static void w100_hw_init(struct w100fb_par *par)
 {
        u32 temp32;
        union cif_cntl_u cif_cntl;
@@ -735,8 +722,8 @@ static void w100_hw_init(void)
        union cpu_defaults_u cpu_default;
        union cif_write_dbg_u cif_write_dbg;
        union wrap_start_dir_u wrap_start_dir;
-       union mc_ext_mem_location_u mc_ext_mem_loc;
        union cif_io_u cif_io;
+       struct w100_gpio_regs *gpio = par->mach->gpio;
 
        w100_soft_reset();
 
@@ -791,19 +778,6 @@ static void w100_hw_init(void)
        cfgreg_base.f.cfgreg_base = W100_CFG_BASE;
        writel((u32) (cfgreg_base.val), remapped_regs + mmCFGREG_BASE);
 
-       /* This location is relative to internal w100 addresses */
-       writel(0x15FF1000, remapped_regs + mmMC_FB_LOCATION);
-
-       mc_ext_mem_loc.val = defMC_EXT_MEM_LOCATION;
-       mc_ext_mem_loc.f.mc_ext_mem_start = MEM_EXT_BASE_VALUE >> 8;
-       mc_ext_mem_loc.f.mc_ext_mem_top = MEM_EXT_TOP_VALUE >> 8;
-       writel((u32) (mc_ext_mem_loc.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
-
-       if ((current_par->lcdMode == LCD_MODE_240) || (current_par->lcdMode == LCD_MODE_320))
-               w100_InitExtMem(LCD_SHARP_QVGA);
-       else
-               w100_InitExtMem(LCD_SHARP_VGA);
-
        wrap_start_dir.val = defWRAP_START_DIR;
        wrap_start_dir.f.start_addr = WRAP_BUF_BASE_VALUE >> 1;
        writel((u32) (wrap_start_dir.val), remapped_regs + mmWRAP_START_DIR);
@@ -813,21 +787,24 @@ static void w100_hw_init(void)
        writel((u32) (wrap_top_dir.val), remapped_regs + mmWRAP_TOP_DIR);
 
        writel((u32) 0x2440, remapped_regs + mmRBBM_CNTL);
-}
 
+       /* Set the hardware to 565 colour */
+       temp32 = readl(remapped_regs + mmDISP_DEBUG2);
+       temp32 &= 0xff7fffff;
+       temp32 |= 0x00800000;
+       writel(temp32, remapped_regs + mmDISP_DEBUG2);
 
-/*
- * Types
- */
+       /* Initialise the GPIO lines */
+       if (gpio) {
+               writel(gpio->init_data1, remapped_regs + mmGPIO_DATA);
+               writel(gpio->init_data2, remapped_regs + mmGPIO_DATA2);
+               writel(gpio->gpio_dir1,  remapped_regs + mmGPIO_CNTL1);
+               writel(gpio->gpio_oe1,   remapped_regs + mmGPIO_CNTL2);
+               writel(gpio->gpio_dir2,  remapped_regs + mmGPIO_CNTL3);
+               writel(gpio->gpio_oe2,   remapped_regs + mmGPIO_CNTL4);
+       }
+}
 
-struct pll_parm {
-       u16 freq;               /* desired Fout for PLL */
-       u8 M;
-       u8 N_int;
-       u8 N_fac;
-       u8 tfgoal;
-       u8 lock_time;
-};
 
 struct power_state {
        union clk_pin_cntl_u clk_pin_cntl;
@@ -835,317 +812,275 @@ struct power_state {
        union pll_cntl_u pll_cntl;
        union sclk_cntl_u sclk_cntl;
        union pclk_cntl_u pclk_cntl;
-       union clk_test_cntl_u clk_test_cntl;
        union pwrmgt_cntl_u pwrmgt_cntl;
-       u32 freq;               /* Fout for PLL calibration */
-       u8 tf100;               /* for pll calibration */
-       u8 tf80;                /* for pll calibration */
-       u8 tf20;                /* for pll calibration */
-       u8 M;                   /* for pll calibration */
-       u8 N_int;               /* for pll calibration */
-       u8 N_fac;               /* for pll calibration */
-       u8 lock_time;   /* for pll calibration */
-       u8 tfgoal;              /* for pll calibration */
-       u8 auto_mode;   /* hardware auto switch? */
-       u8 pwm_mode;            /* 0 fast, 1 normal/slow */
-       u16 fast_sclk;  /* fast clk freq */
-       u16 norm_sclk;  /* slow clk freq */
+       int auto_mode;  /* system clock auto changing? */
 };
 
 
-/*
- * Global state variables
- */
-
 static struct power_state w100_pwr_state;
 
-/* This table is specific for 12.5MHz ref crystal.  */
-static struct pll_parm gPLLTable[] = {
-    /*freq     M   N_int    N_fac  tfgoal  lock_time */
-    { 50,      0,   1,       0,     0xE0,        56}, /*  50.00 MHz */
-    { 75,      0,   5,       0,     0xDE,           37}, /*  75.00 MHz */
-    {100,      0,   7,       0,     0xE0,        28}, /* 100.00 MHz */
-    {125,      0,   9,       0,     0xE0,        22}, /* 125.00 MHz */
-    {150,      0,   11,      0,     0xE0,        17}, /* 150.00 MHz */
-    {  0,      0,   0,       0,        0,         0}  /* Terminator */
+/* The PLL Fout is determined by (XtalFreq/(M+1)) * ((N_int+1) + (N_fac/8)) */
+
+/* 12.5MHz Crystal PLL Table */
+static struct w100_pll_info xtal_12500000[] = {
+       /*freq     M   N_int    N_fac  tfgoal  lock_time */
+       { 50,      0,   1,       0,     0xe0,        56},  /*  50.00 MHz */
+       { 75,      0,   5,       0,     0xde,        37},  /*  75.00 MHz */
+       {100,      0,   7,       0,     0xe0,        28},  /* 100.00 MHz */
+       {125,      0,   9,       0,     0xe0,        22},  /* 125.00 MHz */
+       {150,      0,   11,      0,     0xe0,        17},  /* 150.00 MHz */
+       {  0,      0,   0,       0,        0,         0},  /* Terminator */
 };
 
+/* 14.318MHz Crystal PLL Table */
+static struct w100_pll_info xtal_14318000[] = {
+       /*freq     M   N_int    N_fac  tfgoal  lock_time */
+       { 40,      4,   13,      0,     0xe0,        80}, /* tfgoal guessed */
+       { 50,      1,   6,       0,     0xe0,        64}, /*  50.05 MHz */
+       { 57,      2,   11,      0,     0xe0,        53}, /* tfgoal guessed */
+       { 75,      0,   4,       3,     0xe0,        43}, /*  75.08 MHz */
+       {100,      0,   6,       0,     0xe0,        32}, /* 100.10 MHz */
+       {  0,      0,   0,       0,        0,         0},
+};
 
-static u8 w100_pll_get_testcount(u8 testclk_sel)
+/* 16MHz Crystal PLL Table */
+static struct w100_pll_info xtal_16000000[] = {
+       /*freq     M   N_int    N_fac  tfgoal  lock_time */
+       { 72,      1,   8,       0,     0xe0,        48}, /* tfgoal guessed */
+       { 95,      1,   10,      7,     0xe0,        38}, /* tfgoal guessed */
+       { 96,      1,   11,      0,     0xe0,        36}, /* tfgoal guessed */
+       {  0,      0,   0,       0,        0,         0},
+};
+
+static struct pll_entries {
+       int xtal_freq;
+       struct w100_pll_info *pll_table;
+} w100_pll_tables[] = {
+       { 12500000, &xtal_12500000[0] },
+       { 14318000, &xtal_14318000[0] },
+       { 16000000, &xtal_16000000[0] },
+       { 0 },
+};
+
+struct w100_pll_info *w100_get_xtal_table(unsigned int freq)
 {
+       struct pll_entries *pll_entry = w100_pll_tables;
+
+       do {
+               if (freq == pll_entry->xtal_freq)
+                       return pll_entry->pll_table;
+               pll_entry++;
+       } while (pll_entry->xtal_freq);
+       return 0;
+}
+
+
+static unsigned int w100_get_testcount(unsigned int testclk_sel)
+{
+       union clk_test_cntl_u clk_test_cntl;
+
        udelay(5);
 
-       w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x0;
-       w100_pwr_state.clk_test_cntl.f.testclk_sel = testclk_sel;
-       w100_pwr_state.clk_test_cntl.f.tstcount_rst = 0x1;      /*reset test count */
-       writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
-       w100_pwr_state.clk_test_cntl.f.tstcount_rst = 0x0;
-       writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
+       /* Select the test clock source and reset */
+       clk_test_cntl.f.start_check_freq = 0x0;
+       clk_test_cntl.f.testclk_sel = testclk_sel;
+       clk_test_cntl.f.tstcount_rst = 0x1; /* set reset */
+       writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
 
-       w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x1;
-       writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
+       clk_test_cntl.f.tstcount_rst = 0x0; /* clear reset */
+       writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
 
+       /* Run clock test */
+       clk_test_cntl.f.start_check_freq = 0x1;
+       writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
+
+       /* Give the test time to complete */
        udelay(20);
 
-       w100_pwr_state.clk_test_cntl.val = readl(remapped_regs + mmCLK_TEST_CNTL);
-       w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x0;
-       writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
+       /* Return the result */
+       clk_test_cntl.val = readl(remapped_regs + mmCLK_TEST_CNTL);
+       clk_test_cntl.f.start_check_freq = 0x0;
+       writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
 
-       return w100_pwr_state.clk_test_cntl.f.test_count;
+       return clk_test_cntl.f.test_count;
 }
 
 
-static u8 w100_pll_adjust(void)
+static int w100_pll_adjust(struct w100_pll_info *pll)
 {
+       unsigned int tf80;
+       unsigned int tf20;
+
+       /* Initial Settings */
+       w100_pwr_state.pll_cntl.f.pll_pwdn = 0x0;     /* power down */
+       w100_pwr_state.pll_cntl.f.pll_reset = 0x0;    /* not reset */
+       w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x1;   /* Hi-Z */
+       w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;      /* VCO gain = 0 */
+       w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0;    /* VCO frequency range control = off */
+       w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;  /* current offset inside VCO = 0 */
+       w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
+
+       /* Wai Ming 80 percent of VDD 1.3V gives 1.04V, minimum operating voltage is 1.08V
+        * therefore, commented out the following lines
+        * tf80 meant tf100
+        */
        do {
-               /* Wai Ming 80 percent of VDD 1.3V gives 1.04V, minimum operating voltage is 1.08V
-                * therefore, commented out the following lines
-                * tf80 meant tf100
-                * set VCO input = 0.8 * VDD
-                */
+               /* set VCO input = 0.8 * VDD */
                w100_pwr_state.pll_cntl.f.pll_dactal = 0xd;
                writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
 
-               w100_pwr_state.tf80 = w100_pll_get_testcount(0x1);      /* PLLCLK */
-               if (w100_pwr_state.tf80 >= (w100_pwr_state.tfgoal)) {
+               tf80 = w100_get_testcount(TESTCLK_SRC_PLL);
+               if (tf80 >= (pll->tfgoal)) {
                        /* set VCO input = 0.2 * VDD */
                        w100_pwr_state.pll_cntl.f.pll_dactal = 0x7;
                        writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
 
-                       w100_pwr_state.tf20 = w100_pll_get_testcount(0x1);      /* PLLCLK */
-                       if (w100_pwr_state.tf20 <= (w100_pwr_state.tfgoal))
-                               return 1; // Success
+                       tf20 = w100_get_testcount(TESTCLK_SRC_PLL);
+                       if (tf20 <= (pll->tfgoal))
+                               return 1;  /* Success */
 
                        if ((w100_pwr_state.pll_cntl.f.pll_vcofr == 0x0) &&
-                           ((w100_pwr_state.pll_cntl.f.pll_pvg == 0x7) ||
-                            (w100_pwr_state.pll_cntl.f.pll_ioffset == 0x0))) {
+                               ((w100_pwr_state.pll_cntl.f.pll_pvg == 0x7) ||
+                               (w100_pwr_state.pll_cntl.f.pll_ioffset == 0x0))) {
                                /* slow VCO config */
                                w100_pwr_state.pll_cntl.f.pll_vcofr = 0x1;
                                w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;
                                w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
-                               writel((u32) (w100_pwr_state.pll_cntl.val),
-                                       remapped_regs + mmPLL_CNTL);
                                continue;
                        }
                }
                if ((w100_pwr_state.pll_cntl.f.pll_ioffset) < 0x3) {
                        w100_pwr_state.pll_cntl.f.pll_ioffset += 0x1;
-                       writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
-                       continue;
-               }
-               if ((w100_pwr_state.pll_cntl.f.pll_pvg) < 0x7) {
+               } else if ((w100_pwr_state.pll_cntl.f.pll_pvg) < 0x7) {
                        w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
                        w100_pwr_state.pll_cntl.f.pll_pvg += 0x1;
-                       writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
-                       continue;
+               } else {
+                       return 0;  /* Error */
                }
-               return 0; // error
        } while(1);
 }
 
 
 /*
  * w100_pll_calibration
- *                freq = target frequency of the PLL
- *                (note: crystal = 14.3MHz)
  */
-static u8 w100_pll_calibration(u32 freq)
+static int w100_pll_calibration(struct w100_pll_info *pll)
 {
-       u8 status;
-
-       /* initial setting */
-       w100_pwr_state.pll_cntl.f.pll_pwdn = 0x0;               /* power down */
-       w100_pwr_state.pll_cntl.f.pll_reset = 0x0;              /* not reset */
-       w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x1;     /* Hi-Z */
-       w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;                /* VCO gain = 0 */
-       w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0;              /* VCO frequency range control = off */
-       w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;    /* current offset inside VCO = 0 */
-       w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
-       writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
+       int status;
 
-       /* check for (tf80 >= tfgoal) && (tf20 =< tfgoal) */
-       if ((w100_pwr_state.tf80 < w100_pwr_state.tfgoal) || (w100_pwr_state.tf20 > w100_pwr_state.tfgoal)) {
-               status=w100_pll_adjust();
-       }
-       /* PLL Reset And Lock */
+       status = w100_pll_adjust(pll);
 
+       /* PLL Reset And Lock */
        /* set VCO input = 0.5 * VDD */
        w100_pwr_state.pll_cntl.f.pll_dactal = 0xa;
        writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
 
-       /* reset time */
-       udelay(1);
+       udelay(1);  /* reset time */
 
        /* enable charge pump */
-       w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0;     /* normal */
+       w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0;  /* normal */
        writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
 
-       /* set VCO input = Hi-Z */
-       /* disable DAC */
+       /* set VCO input = Hi-Z, disable DAC */
        w100_pwr_state.pll_cntl.f.pll_dactal = 0x0;
        writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
 
-       /* lock time */
-       udelay(400);    /* delay 400 us */
+       udelay(400);  /* lock time */
 
        /* PLL locked */
 
-       w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x1;  /* PLL clock */
-       writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
-
-       w100_pwr_state.tf100 = w100_pll_get_testcount(0x1);     /* PLLCLK */
-
        return status;
 }
 
 
-static u8 w100_pll_set_clk(void)
+static int w100_pll_set_clk(struct w100_pll_info *pll)
 {
-       u8 status;
+       int status;
 
-       if (w100_pwr_state.auto_mode == 1)      /* auto mode */
+       if (w100_pwr_state.auto_mode == 1)  /* auto mode */
        {
-               w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0; /* disable fast to normal */
-               w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0; /* disable normal to fast */
+               w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0;  /* disable fast to normal */
+               w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0;  /* disable normal to fast */
                writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
        }
 
-       w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x0;  /* crystal clock */
+       /* Set system clock source to XTAL whilst adjusting the PLL! */
+       w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL;
        writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
 
-       w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = w100_pwr_state.M;
-       w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = w100_pwr_state.N_int;
-       w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = w100_pwr_state.N_fac;
-       w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = w100_pwr_state.lock_time;
+       w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = pll->M;
+       w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = pll->N_int;
+       w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = pll->N_fac;
+       w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = pll->lock_time;
        writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV);
 
        w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0;
        writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
 
-       status = w100_pll_calibration (w100_pwr_state.freq);
+       status = w100_pll_calibration(pll);
 
-       if (w100_pwr_state.auto_mode == 1)      /* auto mode */
+       if (w100_pwr_state.auto_mode == 1)  /* auto mode */
        {
-               w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x1; /* reenable fast to normal */
-               w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x1; /* reenable normal to fast  */
+               w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x1;  /* reenable fast to normal */
+               w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x1;  /* reenable normal to fast  */
                writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
        }
        return status;
 }
 
-
-/* assume reference crystal clk is 12.5MHz,
- * and that doubling is not enabled.
- *
- * Freq = 12 == 12.5MHz.
- */
-static u16 w100_set_slowsysclk(u16 freq)
-{
-       if (w100_pwr_state.norm_sclk == freq)
-               return freq;
-
-       if (w100_pwr_state.auto_mode == 1)      /* auto mode */
-               return 0;
-
-       if (freq == 12) {
-               w100_pwr_state.norm_sclk = freq;
-               w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0;    /* Pslow = 1 */
-               w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x0;  /* crystal src */
-
-               writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
-
-               w100_pwr_state.clk_pin_cntl.f.xtalin_pm_en = 0x1;
-               writel((u32) (w100_pwr_state.clk_pin_cntl.val), remapped_regs + mmCLK_PIN_CNTL);
-
-               w100_pwr_state.pwrmgt_cntl.f.pwm_enable = 0x1;
-               w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1;
-               writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
-               w100_pwr_state.pwm_mode = 1;    /* normal mode */
-               return freq;
-       } else
-               return 0;
-}
-
-
-static u16 w100_set_fastsysclk(u16 freq)
+/* freq = target frequency of the PLL */
+static int w100_set_pll_freq(struct w100fb_par *par, unsigned int freq)
 {
-       u16 pll_freq;
-       int i;
-
-       while(1) {
-               pll_freq = (u16) (freq * (w100_pwr_state.sclk_cntl.f.sclk_post_div_fast + 1));
-               i = 0;
-               do {
-                       if (pll_freq == gPLLTable[i].freq) {
-                               w100_pwr_state.freq = gPLLTable[i].freq * 1000000;
-                               w100_pwr_state.M = gPLLTable[i].M;
-                               w100_pwr_state.N_int = gPLLTable[i].N_int;
-                               w100_pwr_state.N_fac = gPLLTable[i].N_fac;
-                               w100_pwr_state.tfgoal = gPLLTable[i].tfgoal;
-                               w100_pwr_state.lock_time = gPLLTable[i].lock_time;
-                               w100_pwr_state.tf20 = 0xff;     /* set highest */
-                               w100_pwr_state.tf80 = 0x00;     /* set lowest */
-
-                               w100_pll_set_clk();
-                               w100_pwr_state.pwm_mode = 0;    /* fast mode */
-                               w100_pwr_state.fast_sclk = freq;
-                               return freq;
-                       }
-                       i++;
-               } while(gPLLTable[i].freq);
+       struct w100_pll_info *pll = par->pll_table;
 
-               if (w100_pwr_state.auto_mode == 1)
-                       break;
-
-               if (w100_pwr_state.sclk_cntl.f.sclk_post_div_fast == 0)
-                       break;
-
-               w100_pwr_state.sclk_cntl.f.sclk_post_div_fast -= 1;
-               writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
-       }
+       do {
+               if (freq == pll->freq) {
+                       return w100_pll_set_clk(pll);
+               }
+               pll++;
+       } while(pll->freq);
        return 0;
 }
 
-
 /* Set up an initial state.  Some values/fields set
    here will be overwritten. */
-static void w100_pwm_setup(void)
+static void w100_pwm_setup(struct w100fb_par *par)
 {
        w100_pwr_state.clk_pin_cntl.f.osc_en = 0x1;
        w100_pwr_state.clk_pin_cntl.f.osc_gain = 0x1f;
        w100_pwr_state.clk_pin_cntl.f.dont_use_xtalin = 0x0;
        w100_pwr_state.clk_pin_cntl.f.xtalin_pm_en = 0x0;
-       w100_pwr_state.clk_pin_cntl.f.xtalin_dbl_en = 0x0;      /* no freq doubling */
+       w100_pwr_state.clk_pin_cntl.f.xtalin_dbl_en = par->mach->xtal_dbl ? 1 : 0;
        w100_pwr_state.clk_pin_cntl.f.cg_debug = 0x0;
        writel((u32) (w100_pwr_state.clk_pin_cntl.val), remapped_regs + mmCLK_PIN_CNTL);
 
-       w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x0;  /* Crystal Clk */
-       w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = 0x0;    /* Pfast = 1 */
+       w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL;
+       w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = 0x0;  /* Pfast = 1 */
        w100_pwr_state.sclk_cntl.f.sclk_clkon_hys = 0x3;
-       w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0;    /* Pslow = 1 */
+       w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0;  /* Pslow = 1 */
        w100_pwr_state.sclk_cntl.f.disp_cg_ok2switch_en = 0x0;
-       w100_pwr_state.sclk_cntl.f.sclk_force_reg = 0x0;        /* Dynamic */
-       w100_pwr_state.sclk_cntl.f.sclk_force_disp = 0x0;       /* Dynamic */
-       w100_pwr_state.sclk_cntl.f.sclk_force_mc = 0x0; /* Dynamic */
-       w100_pwr_state.sclk_cntl.f.sclk_force_extmc = 0x0;      /* Dynamic */
-       w100_pwr_state.sclk_cntl.f.sclk_force_cp = 0x0; /* Dynamic */
-       w100_pwr_state.sclk_cntl.f.sclk_force_e2 = 0x0; /* Dynamic */
-       w100_pwr_state.sclk_cntl.f.sclk_force_e3 = 0x0; /* Dynamic */
-       w100_pwr_state.sclk_cntl.f.sclk_force_idct = 0x0;       /* Dynamic */
-       w100_pwr_state.sclk_cntl.f.sclk_force_bist = 0x0;       /* Dynamic */
+       w100_pwr_state.sclk_cntl.f.sclk_force_reg = 0x0;    /* Dynamic */
+       w100_pwr_state.sclk_cntl.f.sclk_force_disp = 0x0;   /* Dynamic */
+       w100_pwr_state.sclk_cntl.f.sclk_force_mc = 0x0;     /* Dynamic */
+       w100_pwr_state.sclk_cntl.f.sclk_force_extmc = 0x0;  /* Dynamic */
+       w100_pwr_state.sclk_cntl.f.sclk_force_cp = 0x0;     /* Dynamic */
+       w100_pwr_state.sclk_cntl.f.sclk_force_e2 = 0x0;     /* Dynamic */
+       w100_pwr_state.sclk_cntl.f.sclk_force_e3 = 0x0;     /* Dynamic */
+       w100_pwr_state.sclk_cntl.f.sclk_force_idct = 0x0;   /* Dynamic */
+       w100_pwr_state.sclk_cntl.f.sclk_force_bist = 0x0;   /* Dynamic */
        w100_pwr_state.sclk_cntl.f.busy_extend_cp = 0x0;
        w100_pwr_state.sclk_cntl.f.busy_extend_e2 = 0x0;
        w100_pwr_state.sclk_cntl.f.busy_extend_e3 = 0x0;
        w100_pwr_state.sclk_cntl.f.busy_extend_idct = 0x0;
        writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
 
-       w100_pwr_state.pclk_cntl.f.pclk_src_sel = 0x0;  /* Crystal Clk */
-       w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x1; /* P = 2 */
-       w100_pwr_state.pclk_cntl.f.pclk_force_disp = 0x0;       /* Dynamic */
+       w100_pwr_state.pclk_cntl.f.pclk_src_sel = CLK_SRC_XTAL;
+       w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x1;    /* P = 2 */
+       w100_pwr_state.pclk_cntl.f.pclk_force_disp = 0x0;  /* Dynamic */
        writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
 
-       w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = 0x0;      /* M = 1 */
-       w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = 0x0;   /* N = 1.0 */
+       w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = 0x0;     /* M = 1 */
+       w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = 0x0;  /* N = 1.0 */
        w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = 0x0;
        w100_pwr_state.pll_ref_fb_div.f.pll_reset_time = 0x5;
        w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = 0xff;
@@ -1154,7 +1089,7 @@ static void w100_pwm_setup(void)
        w100_pwr_state.pll_cntl.f.pll_pwdn = 0x1;
        w100_pwr_state.pll_cntl.f.pll_reset = 0x1;
        w100_pwr_state.pll_cntl.f.pll_pm_en = 0x0;
-       w100_pwr_state.pll_cntl.f.pll_mode = 0x0;       /* uses VCO clock */
+       w100_pwr_state.pll_cntl.f.pll_mode = 0x0;  /* uses VCO clock */
        w100_pwr_state.pll_cntl.f.pll_refclk_sel = 0x0;
        w100_pwr_state.pll_cntl.f.pll_fbclk_sel = 0x0;
        w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0;
@@ -1164,220 +1099,275 @@ static void w100_pwm_setup(void)
        w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
        w100_pwr_state.pll_cntl.f.pll_pecc_mode = 0x0;
        w100_pwr_state.pll_cntl.f.pll_pecc_scon = 0x0;
-       w100_pwr_state.pll_cntl.f.pll_dactal = 0x0;     /* Hi-Z */
+       w100_pwr_state.pll_cntl.f.pll_dactal = 0x0;  /* Hi-Z */
        w100_pwr_state.pll_cntl.f.pll_cp_clip = 0x3;
        w100_pwr_state.pll_cntl.f.pll_conf = 0x2;
        w100_pwr_state.pll_cntl.f.pll_mbctrl = 0x2;
        w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
        writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
 
-       w100_pwr_state.clk_test_cntl.f.testclk_sel = 0x1;       /* PLLCLK (for testing) */
-       w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x0;
-       w100_pwr_state.clk_test_cntl.f.tstcount_rst = 0x0;
-       writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
-
        w100_pwr_state.pwrmgt_cntl.f.pwm_enable = 0x0;
-       w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1;        /* normal mode (0, 1, 3) */
+       w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1;  /* normal mode (0, 1, 3) */
        w100_pwr_state.pwrmgt_cntl.f.pwm_wakeup_cond = 0x0;
        w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0;
        w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0;
-       w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_cond = 0x1;  /* PM4,ENG */
-       w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_cond = 0x1;  /* PM4,ENG */
+       w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_cond = 0x1;  /* PM4,ENG */
+       w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_cond = 0x1;  /* PM4,ENG */
        w100_pwr_state.pwrmgt_cntl.f.pwm_idle_timer = 0xFF;
        w100_pwr_state.pwrmgt_cntl.f.pwm_busy_timer = 0xFF;
        writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
 
-       w100_pwr_state.auto_mode = 0;   /* manual mode */
-       w100_pwr_state.pwm_mode = 1;    /* normal mode (0, 1, 2) */
-       w100_pwr_state.freq = 50000000; /* 50 MHz */
-       w100_pwr_state.M = 3;   /* M = 4 */
-       w100_pwr_state.N_int = 6;       /* N = 7.0 */
-       w100_pwr_state.N_fac = 0;
-       w100_pwr_state.tfgoal = 0xE0;
-       w100_pwr_state.lock_time = 56;
-       w100_pwr_state.tf20 = 0xff;     /* set highest */
-       w100_pwr_state.tf80 = 0x00;     /* set lowest */
-       w100_pwr_state.tf100 = 0x00;    /* set lowest */
-       w100_pwr_state.fast_sclk = 50;  /* 50.0 MHz */
-       w100_pwr_state.norm_sclk = 12;  /* 12.5 MHz */
+       w100_pwr_state.auto_mode = 0;  /* manual mode */
 }
 
 
-static void w100_init_sharp_lcd(u32 mode)
+/*
+ * Setup the w100 clocks for the specified mode
+ */
+static void w100_init_clocks(struct w100fb_par *par)
 {
-       u32 temp32;
-       union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
+       struct w100_mode *mode = par->mode;
 
-       /* Prevent display updates */
-       disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
-       disp_db_buf_wr_cntl.f.update_db_buf = 0;
-       disp_db_buf_wr_cntl.f.en_db_buf = 0;
-       writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
+       if (mode->pixclk_src == CLK_SRC_PLL || mode->sysclk_src == CLK_SRC_PLL)
+               w100_set_pll_freq(par, (par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq);
 
-       switch(mode) {
-       case LCD_SHARP_QVGA:
-               w100_set_slowsysclk(12);        /* use crystal -- 12.5MHz */
-               /* not use PLL */
-
-               writel(0x7FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION);
-               writel(0x85FF8000, remapped_regs + mmMC_FB_LOCATION);
-               writel(0x00000003, remapped_regs + mmLCD_FORMAT);
-               writel(0x00CF1C06, remapped_regs + mmGRAPHIC_CTRL);
-               writel(0x01410145, remapped_regs + mmCRTC_TOTAL);
-               writel(0x01170027, remapped_regs + mmACTIVE_H_DISP);
-               writel(0x01410001, remapped_regs + mmACTIVE_V_DISP);
-               writel(0x01170027, remapped_regs + mmGRAPHIC_H_DISP);
-               writel(0x01410001, remapped_regs + mmGRAPHIC_V_DISP);
-               writel(0x81170027, remapped_regs + mmCRTC_SS);
-               writel(0xA0140000, remapped_regs + mmCRTC_LS);
-               writel(0x00400008, remapped_regs + mmCRTC_REV);
-               writel(0xA0000000, remapped_regs + mmCRTC_DCLK);
-               writel(0xC0140014, remapped_regs + mmCRTC_GS);
-               writel(0x00010141, remapped_regs + mmCRTC_VPOS_GS);
-               writel(0x8015010F, remapped_regs + mmCRTC_GCLK);
-               writel(0x80100110, remapped_regs + mmCRTC_GOE);
-               writel(0x00000000, remapped_regs + mmCRTC_FRAME);
-               writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS);
-               writel(0x01CC0000, remapped_regs + mmLCDD_CNTL1);
-               writel(0x0003FFFF, remapped_regs + mmLCDD_CNTL2);
-               writel(0x00FFFF0D, remapped_regs + mmGENLCD_CNTL1);
-               writel(0x003F3003, remapped_regs + mmGENLCD_CNTL2);
-               writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT);
-               writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR);
-               writel(0x000102aa, remapped_regs + mmGENLCD_CNTL3);
-               writel(0x00800000, remapped_regs + mmGRAPHIC_OFFSET);
-               writel(0x000001e0, remapped_regs + mmGRAPHIC_PITCH);
-               writel(0x000000bf, remapped_regs + mmGPIO_DATA);
-               writel(0x03c0feff, remapped_regs + mmGPIO_CNTL2);
-               writel(0x00000000, remapped_regs + mmGPIO_CNTL1);
-               writel(0x41060010, remapped_regs + mmCRTC_PS1_ACTIVE);
-               break;
-       case LCD_SHARP_VGA:
-               w100_set_slowsysclk(12);        /* use crystal -- 12.5MHz */
-               w100_set_fastsysclk(current_par->fastsysclk_mode);      /* use PLL -- 75.0MHz */
-               w100_pwr_state.pclk_cntl.f.pclk_src_sel = 0x1;
-               w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x2;
-               writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
-               writel(0x15FF1000, remapped_regs + mmMC_FB_LOCATION);
-               writel(0x9FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION);
-               writel(0x00000003, remapped_regs + mmLCD_FORMAT);
-               writel(0x00DE1D66, remapped_regs + mmGRAPHIC_CTRL);
-
-               writel(0x0283028B, remapped_regs + mmCRTC_TOTAL);
-               writel(0x02360056, remapped_regs + mmACTIVE_H_DISP);
-               writel(0x02830003, remapped_regs + mmACTIVE_V_DISP);
-               writel(0x02360056, remapped_regs + mmGRAPHIC_H_DISP);
-               writel(0x02830003, remapped_regs + mmGRAPHIC_V_DISP);
-               writel(0x82360056, remapped_regs + mmCRTC_SS);
-               writel(0xA0280000, remapped_regs + mmCRTC_LS);
-               writel(0x00400008, remapped_regs + mmCRTC_REV);
-               writel(0xA0000000, remapped_regs + mmCRTC_DCLK);
-               writel(0x80280028, remapped_regs + mmCRTC_GS);
-               writel(0x02830002, remapped_regs + mmCRTC_VPOS_GS);
-               writel(0x8015010F, remapped_regs + mmCRTC_GCLK);
-               writel(0x80100110, remapped_regs + mmCRTC_GOE);
-               writel(0x00000000, remapped_regs + mmCRTC_FRAME);
-               writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS);
-               writel(0x01CC0000, remapped_regs + mmLCDD_CNTL1);
-               writel(0x0003FFFF, remapped_regs + mmLCDD_CNTL2);
-               writel(0x00FFFF0D, remapped_regs + mmGENLCD_CNTL1);
-               writel(0x003F3003, remapped_regs + mmGENLCD_CNTL2);
-               writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT);
-               writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR);
-               writel(0x000102aa, remapped_regs + mmGENLCD_CNTL3);
-               writel(0x00800000, remapped_regs + mmGRAPHIC_OFFSET);
-               writel(0x000003C0, remapped_regs + mmGRAPHIC_PITCH);
-               writel(0x000000bf, remapped_regs + mmGPIO_DATA);
-               writel(0x03c0feff, remapped_regs + mmGPIO_CNTL2);
-               writel(0x00000000, remapped_regs + mmGPIO_CNTL1);
-               writel(0x41060010, remapped_regs + mmCRTC_PS1_ACTIVE);
-               break;
-       default:
-               break;
-       }
+       w100_pwr_state.sclk_cntl.f.sclk_src_sel = mode->sysclk_src;
+       w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = mode->sysclk_divider;
+       w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = mode->sysclk_divider;
+       writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
+}
+
+static void w100_init_lcd(struct w100fb_par *par)
+{
+       u32 temp32;
+       struct w100_mode *mode = par->mode;
+       struct w100_gen_regs *regs = par->mach->regs;
+       union active_h_disp_u active_h_disp;
+       union active_v_disp_u active_v_disp;
+       union graphic_h_disp_u graphic_h_disp;
+       union graphic_v_disp_u graphic_v_disp;
+       union crtc_total_u crtc_total;
+
+       /* w3200 doesnt like undefined bits being set so zero register values first */
+
+       active_h_disp.val = 0;
+       active_h_disp.f.active_h_start=mode->left_margin;
+       active_h_disp.f.active_h_end=mode->left_margin + mode->xres;
+       writel(active_h_disp.val, remapped_regs + mmACTIVE_H_DISP);
+
+       active_v_disp.val = 0;
+       active_v_disp.f.active_v_start=mode->upper_margin;
+       active_v_disp.f.active_v_end=mode->upper_margin + mode->yres;
+       writel(active_v_disp.val, remapped_regs + mmACTIVE_V_DISP);
+
+       graphic_h_disp.val = 0;
+       graphic_h_disp.f.graphic_h_start=mode->left_margin;
+       graphic_h_disp.f.graphic_h_end=mode->left_margin + mode->xres;
+       writel(graphic_h_disp.val, remapped_regs + mmGRAPHIC_H_DISP);
+
+       graphic_v_disp.val = 0;
+       graphic_v_disp.f.graphic_v_start=mode->upper_margin;
+       graphic_v_disp.f.graphic_v_end=mode->upper_margin + mode->yres;
+       writel(graphic_v_disp.val, remapped_regs + mmGRAPHIC_V_DISP);
+
+       crtc_total.val = 0;
+       crtc_total.f.crtc_h_total=mode->left_margin  + mode->xres + mode->right_margin;
+       crtc_total.f.crtc_v_total=mode->upper_margin + mode->yres + mode->lower_margin;
+       writel(crtc_total.val, remapped_regs + mmCRTC_TOTAL);
+
+       writel(mode->crtc_ss, remapped_regs + mmCRTC_SS);
+       writel(mode->crtc_ls, remapped_regs + mmCRTC_LS);
+       writel(mode->crtc_gs, remapped_regs + mmCRTC_GS);
+       writel(mode->crtc_vpos_gs, remapped_regs + mmCRTC_VPOS_GS);
+       writel(mode->crtc_rev, remapped_regs + mmCRTC_REV);
+       writel(mode->crtc_dclk, remapped_regs + mmCRTC_DCLK);
+       writel(mode->crtc_gclk, remapped_regs + mmCRTC_GCLK);
+       writel(mode->crtc_goe, remapped_regs + mmCRTC_GOE);
+       writel(mode->crtc_ps1_active, remapped_regs + mmCRTC_PS1_ACTIVE);
+
+       writel(regs->lcd_format, remapped_regs + mmLCD_FORMAT);
+       writel(regs->lcdd_cntl1, remapped_regs + mmLCDD_CNTL1);
+       writel(regs->lcdd_cntl2, remapped_regs + mmLCDD_CNTL2);
+       writel(regs->genlcd_cntl1, remapped_regs + mmGENLCD_CNTL1);
+       writel(regs->genlcd_cntl2, remapped_regs + mmGENLCD_CNTL2);
+       writel(regs->genlcd_cntl3, remapped_regs + mmGENLCD_CNTL3);
+
+       writel(0x00000000, remapped_regs + mmCRTC_FRAME);
+       writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS);
+       writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT);
+       writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR);
 
        /* Hack for overlay in ext memory */
        temp32 = readl(remapped_regs + mmDISP_DEBUG2);
        temp32 |= 0xc0000000;
        writel(temp32, remapped_regs + mmDISP_DEBUG2);
-
-       /* Re-enable display updates */
-       disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
-       disp_db_buf_wr_cntl.f.update_db_buf = 1;
-       disp_db_buf_wr_cntl.f.en_db_buf = 1;
-       writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
 }
 
 
-static void w100_set_vga_rotation_regs(u16 divider, unsigned long ctrl, unsigned long offset, unsigned long pitch)
+static void w100_setup_memory(struct w100fb_par *par)
 {
-       w100_pwr_state.pclk_cntl.f.pclk_src_sel = 0x1;
-       w100_pwr_state.pclk_cntl.f.pclk_post_div = divider;
-       writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
+       union mc_ext_mem_location_u extmem_location;
+       union mc_fb_location_u intmem_location;
+       struct w100_mem_info *mem = par->mach->mem;
+       struct w100_bm_mem_info *bm_mem = par->mach->bm_mem;
 
-       writel(ctrl, remapped_regs + mmGRAPHIC_CTRL);
-       writel(offset, remapped_regs + mmGRAPHIC_OFFSET);
-       writel(pitch, remapped_regs + mmGRAPHIC_PITCH);
+       if (!par->extmem_active) {
+               w100_suspend(W100_SUSPEND_EXTMEM);
 
-       /* Re-enable display updates */
-       writel(0x0000007b, remapped_regs + mmDISP_DB_BUF_CNTL);
-}
+               /* Map Internal Memory at FB Base */
+               intmem_location.f.mc_fb_start = W100_FB_BASE >> 8;
+               intmem_location.f.mc_fb_top = (W100_FB_BASE+MEM_INT_SIZE) >> 8;
+               writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION);
 
+               /* Unmap External Memory - value is *probably* irrelevant but may have meaning
+                  to acceleration libraries */
+               extmem_location.f.mc_ext_mem_start = MEM_EXT_BASE_VALUE >> 8;
+               extmem_location.f.mc_ext_mem_top = (MEM_EXT_BASE_VALUE-1) >> 8;
+               writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
+       } else {
+               /* Map Internal Memory to its default location */
+               intmem_location.f.mc_fb_start = MEM_INT_BASE_VALUE >> 8;
+               intmem_location.f.mc_fb_top = (MEM_INT_BASE_VALUE+MEM_INT_SIZE) >> 8;
+               writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION);
 
-static void w100_init_vga_rotation(u16 deg)
-{
-       switch(deg) {
-       case 0:
-               w100_set_vga_rotation_regs(0x02, 0x00DE1D66, 0x00800000, 0x000003c0);
-               break;
-       case 90:
-               w100_set_vga_rotation_regs(0x06, 0x00DE1D0e, 0x00895b00, 0x00000500);
-               break;
-       case 180:
-               w100_set_vga_rotation_regs(0x02, 0x00DE1D7e, 0x00895ffc, 0x000003c0);
-               break;
-       case 270:
-               w100_set_vga_rotation_regs(0x06, 0x00DE1D16, 0x008004fc, 0x00000500);
-               break;
-       default:
-               /* not-support */
-               break;
+               /* Map External Memory at FB Base */
+               extmem_location.f.mc_ext_mem_start = W100_FB_BASE >> 8;
+               extmem_location.f.mc_ext_mem_top = (W100_FB_BASE+par->mach->mem->size) >> 8;
+               writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
+
+               writel(0x00007800, remapped_regs + mmMC_BIST_CTRL);
+               writel(mem->ext_cntl, remapped_regs + mmMEM_EXT_CNTL);
+               writel(0x00200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
+               udelay(100);
+               writel(0x80200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
+               udelay(100);
+               writel(mem->sdram_mode_reg, remapped_regs + mmMEM_SDRAM_MODE_REG);
+               udelay(100);
+               writel(mem->ext_timing_cntl, remapped_regs + mmMEM_EXT_TIMING_CNTL);
+               writel(mem->io_cntl, remapped_regs + mmMEM_IO_CNTL);
+               if (bm_mem) {
+                       writel(bm_mem->ext_mem_bw, remapped_regs + mmBM_EXT_MEM_BANDWIDTH);
+                       writel(bm_mem->offset, remapped_regs + mmBM_OFFSET);
+                       writel(bm_mem->ext_timing_ctl, remapped_regs + mmBM_MEM_EXT_TIMING_CNTL);
+                       writel(bm_mem->ext_cntl, remapped_regs + mmBM_MEM_EXT_CNTL);
+                       writel(bm_mem->mode_reg, remapped_regs + mmBM_MEM_MODE_REG);
+                       writel(bm_mem->io_cntl, remapped_regs + mmBM_MEM_IO_CNTL);
+                       writel(bm_mem->config, remapped_regs + mmBM_CONFIG);
+               }
        }
 }
 
-
-static void w100_set_qvga_rotation_regs(unsigned long ctrl, unsigned long offset, unsigned long pitch)
+static void w100_set_dispregs(struct w100fb_par *par)
 {
-       writel(ctrl, remapped_regs + mmGRAPHIC_CTRL);
-       writel(offset, remapped_regs + mmGRAPHIC_OFFSET);
-       writel(pitch, remapped_regs + mmGRAPHIC_PITCH);
+       unsigned long rot=0, divider, offset=0;
+       union graphic_ctrl_u graphic_ctrl;
+
+       /* See if the mode has been rotated */
+       if (par->xres == par->mode->xres) {
+               if (par->flip) {
+                       rot=3; /* 180 degree */
+                       offset=(par->xres * par->yres) - 1;
+               } /* else 0 degree */
+               divider = par->mode->pixclk_divider;
+       } else {
+               if (par->flip) {
+                       rot=2; /* 270 degree */
+                       offset=par->xres - 1;
+               } else {
+                       rot=1; /* 90 degree */
+                       offset=par->xres * (par->yres - 1);
+               }
+               divider = par->mode->pixclk_divider_rotated;
+       }
 
-       /* Re-enable display updates */
-       writel(0x0000007b, remapped_regs + mmDISP_DB_BUF_CNTL);
+       graphic_ctrl.val = 0; /* w32xx doesn't like undefined bits */
+       switch (par->chip_id) {
+               case CHIP_ID_W100:
+                       graphic_ctrl.f_w100.color_depth=6;
+                       graphic_ctrl.f_w100.en_crtc=1;
+                       graphic_ctrl.f_w100.en_graphic_req=1;
+                       graphic_ctrl.f_w100.en_graphic_crtc=1;
+                       graphic_ctrl.f_w100.lcd_pclk_on=1;
+                       graphic_ctrl.f_w100.lcd_sclk_on=1;
+                       graphic_ctrl.f_w100.low_power_on=0;
+                       graphic_ctrl.f_w100.req_freq=0;
+                       graphic_ctrl.f_w100.portrait_mode=rot;
+
+                       /* Zaurus needs this */
+                       switch(par->xres) {
+                               case 240:
+                               case 320:
+                               default:
+                                       graphic_ctrl.f_w100.total_req_graphic=0xa0;
+                                       break;
+                               case 480:
+                               case 640:
+                                       switch(rot) {
+                                               case 0:  /* 0 */
+                                               case 3:  /* 180 */
+                                                       graphic_ctrl.f_w100.low_power_on=1;
+                                                       graphic_ctrl.f_w100.req_freq=5;
+                                               break;
+                                               case 1:  /* 90 */
+                                               case 2:  /* 270 */
+                                                       graphic_ctrl.f_w100.req_freq=4;
+                                                       break;
+                                               default:
+                                                       break;
+                                       }
+                                       graphic_ctrl.f_w100.total_req_graphic=0xf0;
+                                       break;
+                       }
+                       break;
+               case CHIP_ID_W3200:
+               case CHIP_ID_W3220:
+                       graphic_ctrl.f_w32xx.color_depth=6;
+                       graphic_ctrl.f_w32xx.en_crtc=1;
+                       graphic_ctrl.f_w32xx.en_graphic_req=1;
+                       graphic_ctrl.f_w32xx.en_graphic_crtc=1;
+                       graphic_ctrl.f_w32xx.lcd_pclk_on=1;
+                       graphic_ctrl.f_w32xx.lcd_sclk_on=1;
+                       graphic_ctrl.f_w32xx.low_power_on=0;
+                       graphic_ctrl.f_w32xx.req_freq=0;
+                       graphic_ctrl.f_w32xx.total_req_graphic=par->mode->xres >> 1; /* panel xres, not mode */
+                       graphic_ctrl.f_w32xx.portrait_mode=rot;
+                       break;
+       }
+
+       /* Set the pixel clock source and divider */
+       w100_pwr_state.pclk_cntl.f.pclk_src_sel = par->mode->pixclk_src;
+       w100_pwr_state.pclk_cntl.f.pclk_post_div = divider;
+       writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
+
+       writel(graphic_ctrl.val, remapped_regs + mmGRAPHIC_CTRL);
+       writel(W100_FB_BASE + ((offset * BITS_PER_PIXEL/8)&~0x03UL), remapped_regs + mmGRAPHIC_OFFSET);
+       writel((par->xres*BITS_PER_PIXEL/8), remapped_regs + mmGRAPHIC_PITCH);
 }
 
 
-static void w100_init_qvga_rotation(u16 deg)
+/*
+ * Work out how long the sync pulse lasts
+ * Value is 1/(time in seconds)
+ */
+static void calc_hsync(struct w100fb_par *par)
 {
-       switch(deg) {
-       case 0:
-               w100_set_qvga_rotation_regs(0x00d41c06, 0x00800000, 0x000001e0);
-               break;
-       case 90:
-               w100_set_qvga_rotation_regs(0x00d41c0E, 0x00825580, 0x00000280);
-               break;
-       case 180:
-               w100_set_qvga_rotation_regs(0x00d41c1e, 0x008257fc, 0x000001e0);
-               break;
-       case 270:
-               w100_set_qvga_rotation_regs(0x00d41c16, 0x0080027c, 0x00000280);
-               break;
-       default:
-               /* not-support */
-               break;
-       }
-}
+       unsigned long hsync;
+       struct w100_mode *mode = par->mode;
+       union crtc_ss_u crtc_ss;
+
+       if (mode->pixclk_src == CLK_SRC_XTAL)
+               hsync=par->mach->xtal_freq;
+       else
+               hsync=((par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq)*100000;
 
+       hsync /= (w100_pwr_state.pclk_cntl.f.pclk_post_div + 1);
+
+       crtc_ss.val = readl(remapped_regs + mmCRTC_SS);
+       if (crtc_ss.val)
+               par->hsync_len = hsync / (crtc_ss.f.ss_end-crtc_ss.f.ss_start);
+       else
+               par->hsync_len = 0;
+}
 
 static void w100_suspend(u32 mode)
 {
@@ -1387,30 +1377,28 @@ static void w100_suspend(u32 mode)
        writel(0x00FF0000, remapped_regs + mmMC_PERF_MON_CNTL);
 
        val = readl(remapped_regs + mmMEM_EXT_TIMING_CNTL);
-       val &= ~(0x00100000);   /* bit20=0 */
-       val |= 0xFF000000;      /* bit31:24=0xff */
+       val &= ~(0x00100000);  /* bit20=0 */
+       val |= 0xFF000000;     /* bit31:24=0xff */
        writel(val, remapped_regs + mmMEM_EXT_TIMING_CNTL);
 
        val = readl(remapped_regs + mmMEM_EXT_CNTL);
-       val &= ~(0x00040000);   /* bit18=0 */
-       val |= 0x00080000;      /* bit19=1 */
+       val &= ~(0x00040000);  /* bit18=0 */
+       val |= 0x00080000;     /* bit19=1 */
        writel(val, remapped_regs + mmMEM_EXT_CNTL);
 
-       udelay(1);              /* wait 1us */
+       udelay(1);  /* wait 1us */
 
        if (mode == W100_SUSPEND_EXTMEM) {
-
                /* CKE: Tri-State */
                val = readl(remapped_regs + mmMEM_EXT_CNTL);
-               val |= 0x40000000;      /* bit30=1 */
+               val |= 0x40000000;  /* bit30=1 */
                writel(val, remapped_regs + mmMEM_EXT_CNTL);
 
                /* CLK: Stop */
                val = readl(remapped_regs + mmMEM_EXT_CNTL);
-               val &= ~(0x00000001);   /* bit0=0 */
+               val &= ~(0x00000001);  /* bit0=0 */
                writel(val, remapped_regs + mmMEM_EXT_CNTL);
        } else {
-
                writel(0x00000000, remapped_regs + mmSCLK_CNTL);
                writel(0x000000BF, remapped_regs + mmCLK_PIN_CNTL);
                writel(0x00000015, remapped_regs + mmPWRMGT_CNTL);
@@ -1418,43 +1406,16 @@ static void w100_suspend(u32 mode)
                udelay(5);
 
                val = readl(remapped_regs + mmPLL_CNTL);
-               val |= 0x00000004;      /* bit2=1 */
+               val |= 0x00000004;  /* bit2=1 */
                writel(val, remapped_regs + mmPLL_CNTL);
                writel(0x0000001d, remapped_regs + mmPWRMGT_CNTL);
        }
 }
 
-
-static void w100_resume(void)
-{
-       u32 temp32;
-
-       w100_hw_init();
-       w100_pwm_setup();
-
-       temp32 = readl(remapped_regs + mmDISP_DEBUG2);
-       temp32 &= 0xff7fffff;
-       temp32 |= 0x00800000;
-       writel(temp32, remapped_regs + mmDISP_DEBUG2);
-
-       if (current_par->lcdMode == LCD_MODE_480 || current_par->lcdMode == LCD_MODE_640) {
-               w100_init_sharp_lcd(LCD_SHARP_VGA);
-               if (current_par->lcdMode == LCD_MODE_640) {
-                       w100_init_vga_rotation(current_par->rotation_flag ? 270 : 90);
-               }
-       } else {
-               w100_init_sharp_lcd(LCD_SHARP_QVGA);
-               if (current_par->lcdMode == LCD_MODE_320) {
-                       w100_init_qvga_rotation(current_par->rotation_flag ? 270 : 90);
-               }
-       }
-}
-
-
 static void w100_vsync(void)
 {
        u32 tmp;
-       int timeout = 30000; /* VSync timeout = 30[ms] > 16.8[ms] */
+       int timeout = 30000;  /* VSync timeout = 30[ms] > 16.8[ms] */
 
        tmp = readl(remapped_regs + mmACTIVE_V_DISP);
 
@@ -1490,363 +1451,6 @@ static void w100_vsync(void)
        writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
 }
 
-
-static void w100_InitExtMem(u32 mode)
-{
-       switch(mode) {
-       case LCD_SHARP_QVGA:
-               /* QVGA doesn't use external memory
-                  nothing to do, really. */
-               break;
-       case LCD_SHARP_VGA:
-               writel(0x00007800, remapped_regs + mmMC_BIST_CTRL);
-               writel(0x00040003, remapped_regs + mmMEM_EXT_CNTL);
-               writel(0x00200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
-               udelay(100);
-               writel(0x80200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
-               udelay(100);
-               writel(0x00650021, remapped_regs + mmMEM_SDRAM_MODE_REG);
-               udelay(100);
-               writel(0x10002a4a, remapped_regs + mmMEM_EXT_TIMING_CNTL);
-               writel(0x7ff87012, remapped_regs + mmMEM_IO_CNTL);
-               break;
-       default:
-               break;
-       }
-}
-
-
-#define RESCTL_ADRS     0x00
-#define PHACTRL_ADRS   0x01
-#define DUTYCTRL_ADRS  0x02
-#define POWERREG0_ADRS 0x03
-#define POWERREG1_ADRS 0x04
-#define GPOR3_ADRS             0x05
-#define PICTRL_ADRS     0x06
-#define POLCTRL_ADRS    0x07
-
-#define RESCTL_QVGA     0x01
-#define RESCTL_VGA      0x00
-
-#define POWER1_VW_ON   0x01    /* VW Supply FET ON */
-#define POWER1_GVSS_ON 0x02    /* GVSS(-8V) Power Supply ON */
-#define POWER1_VDD_ON  0x04    /* VDD(8V),SVSS(-4V) Power Supply ON */
-
-#define POWER1_VW_OFF  0x00    /* VW Supply FET OFF */
-#define POWER1_GVSS_OFF        0x00    /* GVSS(-8V) Power Supply OFF */
-#define POWER1_VDD_OFF 0x00    /* VDD(8V),SVSS(-4V) Power Supply OFF */
-
-#define POWER0_COM_DCLK        0x01    /* COM Voltage DC Bias DAC Serial Data Clock */
-#define POWER0_COM_DOUT        0x02    /* COM Voltage DC Bias DAC Serial Data Out */
-#define POWER0_DAC_ON  0x04    /* DAC Power Supply ON */
-#define POWER0_COM_ON  0x08    /* COM Powewr Supply ON */
-#define POWER0_VCC5_ON 0x10    /* VCC5 Power Supply ON */
-
-#define POWER0_DAC_OFF 0x00    /* DAC Power Supply OFF */
-#define POWER0_COM_OFF 0x00    /* COM Powewr Supply OFF */
-#define POWER0_VCC5_OFF        0x00    /* VCC5 Power Supply OFF */
-
-#define PICTRL_INIT_STATE      0x01
-#define PICTRL_INIOFF          0x02
-#define PICTRL_POWER_DOWN      0x04
-#define PICTRL_COM_SIGNAL_OFF  0x08
-#define PICTRL_DAC_SIGNAL_OFF  0x10
-
-#define PICTRL_POWER_ACTIVE    (0)
-
-#define POLCTRL_SYNC_POL_FALL  0x01
-#define POLCTRL_EN_POL_FALL    0x02
-#define POLCTRL_DATA_POL_FALL  0x04
-#define POLCTRL_SYNC_ACT_H     0x08
-#define POLCTRL_EN_ACT_L       0x10
-
-#define POLCTRL_SYNC_POL_RISE  0x00
-#define POLCTRL_EN_POL_RISE    0x00
-#define POLCTRL_DATA_POL_RISE  0x00
-#define POLCTRL_SYNC_ACT_L     0x00
-#define POLCTRL_EN_ACT_H       0x00
-
-#define PHACTRL_PHASE_MANUAL   0x01
-
-#define PHAD_QVGA_DEFAULT_VAL (9)
-#define COMADJ_DEFAULT        (125)
-
-static void lcdtg_ssp_send(u8 adrs, u8 data)
-{
-       w100fb_ssp_send(adrs,data);
-}
-
-/*
- * This is only a psuedo I2C interface. We can't use the standard kernel
- * routines as the interface is write only. We just assume the data is acked...
- */
-static void lcdtg_ssp_i2c_send(u8 data)
-{
-       lcdtg_ssp_send(POWERREG0_ADRS, data);
-       udelay(10);
-}
-
-static void lcdtg_i2c_send_bit(u8 data)
-{
-       lcdtg_ssp_i2c_send(data);
-       lcdtg_ssp_i2c_send(data | POWER0_COM_DCLK);
-       lcdtg_ssp_i2c_send(data);
-}
-
-static void lcdtg_i2c_send_start(u8 base)
-{
-       lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK | POWER0_COM_DOUT);
-       lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK);
-       lcdtg_ssp_i2c_send(base);
-}
-
-static void lcdtg_i2c_send_stop(u8 base)
-{
-       lcdtg_ssp_i2c_send(base);
-       lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK);
-       lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK | POWER0_COM_DOUT);
-}
-
-static void lcdtg_i2c_send_byte(u8 base, u8 data)
-{
-       int i;
-       for (i = 0; i < 8; i++) {
-               if (data & 0x80)
-                       lcdtg_i2c_send_bit(base | POWER0_COM_DOUT);
-               else
-                       lcdtg_i2c_send_bit(base);
-               data <<= 1;
-       }
-}
-
-static void lcdtg_i2c_wait_ack(u8 base)
-{
-       lcdtg_i2c_send_bit(base);
-}
-
-static void lcdtg_set_common_voltage(u8 base_data, u8 data)
-{
-       /* Set Common Voltage to M62332FP via I2C */
-       lcdtg_i2c_send_start(base_data);
-       lcdtg_i2c_send_byte(base_data, 0x9c);
-       lcdtg_i2c_wait_ack(base_data);
-       lcdtg_i2c_send_byte(base_data, 0x00);
-       lcdtg_i2c_wait_ack(base_data);
-       lcdtg_i2c_send_byte(base_data, data);
-       lcdtg_i2c_wait_ack(base_data);
-       lcdtg_i2c_send_stop(base_data);
-}
-
-static struct lcdtg_register_setting {
-       u8 adrs;
-       u8 data;
-       u32 wait;
-} lcdtg_power_on_table[] = {
-
-    /* Initialize Internal Logic & Port */
-    { PICTRL_ADRS,
-      PICTRL_POWER_DOWN | PICTRL_INIOFF | PICTRL_INIT_STATE |
-      PICTRL_COM_SIGNAL_OFF | PICTRL_DAC_SIGNAL_OFF,
-      0 },
-
-    { POWERREG0_ADRS,
-      POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_OFF | POWER0_COM_OFF |
-      POWER0_VCC5_OFF,
-      0 },
-
-    { POWERREG1_ADRS,
-      POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF,
-      0 },
-
-    /* VDD(+8V),SVSS(-4V) ON */
-    { POWERREG1_ADRS,
-      POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON /* VDD ON */,
-      3000 },
-
-    /* DAC ON */
-    { POWERREG0_ADRS,
-      POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON /* DAC ON */ |
-      POWER0_COM_OFF | POWER0_VCC5_OFF,
-      0 },
-
-    /* INIB = H, INI = L  */
-    { PICTRL_ADRS,
-      /* PICTL[0] = H , PICTL[1] = PICTL[2] = PICTL[4] = L */
-      PICTRL_INIT_STATE | PICTRL_COM_SIGNAL_OFF,
-      0 },
-
-    /* Set Common Voltage */
-    { 0xfe, 0, 0 },
-
-    /* VCC5 ON */
-    { POWERREG0_ADRS,
-      POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON /* DAC ON */ |
-      POWER0_COM_OFF | POWER0_VCC5_ON /* VCC5 ON */,
-      0 },
-
-    /* GVSS(-8V) ON */
-    { POWERREG1_ADRS,
-      POWER1_VW_OFF | POWER1_GVSS_ON /* GVSS ON */ |
-      POWER1_VDD_ON /* VDD ON */,
-      2000 },
-
-    /* COM SIGNAL ON (PICTL[3] = L) */
-    { PICTRL_ADRS,
-      PICTRL_INIT_STATE,
-      0 },
-
-    /* COM ON */
-    { POWERREG0_ADRS,
-      POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON /* DAC ON */ |
-      POWER0_COM_ON /* COM ON */ | POWER0_VCC5_ON /* VCC5_ON */,
-      0 },
-
-    /* VW ON */
-    { POWERREG1_ADRS,
-      POWER1_VW_ON /* VW ON */ | POWER1_GVSS_ON /* GVSS ON */ |
-      POWER1_VDD_ON /* VDD ON */,
-      0 /* Wait 100ms */ },
-
-    /* Signals output enable */
-    { PICTRL_ADRS,
-      0 /* Signals output enable */,
-      0 },
-
-    { PHACTRL_ADRS,
-      PHACTRL_PHASE_MANUAL,
-      0 },
-
-    /* Initialize for Input Signals from ATI */
-    { POLCTRL_ADRS,
-      POLCTRL_SYNC_POL_RISE | POLCTRL_EN_POL_RISE | POLCTRL_DATA_POL_RISE |
-      POLCTRL_SYNC_ACT_L | POLCTRL_EN_ACT_H,
-      1000 /*100000*/ /* Wait 100ms */ },
-
-    /* end mark */
-    { 0xff, 0, 0 }
-};
-
-static void lcdtg_resume(void)
-{
-       if (current_par->lcdMode == LCD_MODE_480 || current_par->lcdMode == LCD_MODE_640) {
-               lcdtg_hw_init(LCD_SHARP_VGA);
-       } else {
-               lcdtg_hw_init(LCD_SHARP_QVGA);
-       }
-}
-
-static void lcdtg_suspend(void)
-{
-       int i;
-
-       for (i = 0; i < (current_par->xres * current_par->yres); i++) {
-               writew(0xffff, remapped_fbuf + (2*i));
-       }
-
-       /* 60Hz x 2 frame = 16.7msec x 2 = 33.4 msec */
-       mdelay(34);
-
-       /* (1)VW OFF */
-       lcdtg_ssp_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON);
-
-       /* (2)COM OFF */
-       lcdtg_ssp_send(PICTRL_ADRS, PICTRL_COM_SIGNAL_OFF);
-       lcdtg_ssp_send(POWERREG0_ADRS, POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON);
-
-       /* (3)Set Common Voltage Bias 0V */
-       lcdtg_set_common_voltage(POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON, 0);
-
-       /* (4)GVSS OFF */
-       lcdtg_ssp_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON);
-
-       /* (5)VCC5 OFF */
-       lcdtg_ssp_send(POWERREG0_ADRS, POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF);
-
-       /* (6)Set PDWN, INIOFF, DACOFF */
-       lcdtg_ssp_send(PICTRL_ADRS, PICTRL_INIOFF | PICTRL_DAC_SIGNAL_OFF |
-                       PICTRL_POWER_DOWN | PICTRL_COM_SIGNAL_OFF);
-
-       /* (7)DAC OFF */
-       lcdtg_ssp_send(POWERREG0_ADRS, POWER0_DAC_OFF | POWER0_COM_OFF | POWER0_VCC5_OFF);
-
-       /* (8)VDD OFF */
-       lcdtg_ssp_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF);
-
-}
-
-static void lcdtg_set_phadadj(u32 mode)
-{
-       int adj;
-
-       if (mode == LCD_SHARP_VGA) {
-               /* Setting for VGA */
-               adj = current_par->phadadj;
-               if (adj < 0) {
-                       adj = PHACTRL_PHASE_MANUAL;
-               } else {
-                       adj = ((adj & 0x0f) << 1) | PHACTRL_PHASE_MANUAL;
-               }
-       } else {
-               /* Setting for QVGA */
-               adj = (PHAD_QVGA_DEFAULT_VAL << 1) | PHACTRL_PHASE_MANUAL;
-       }
-       lcdtg_ssp_send(PHACTRL_ADRS, adj);
-}
-
-static void lcdtg_hw_init(u32 mode)
-{
-       int i;
-       int comadj;
-
-       i = 0;
-       while(lcdtg_power_on_table[i].adrs != 0xff) {
-               if (lcdtg_power_on_table[i].adrs == 0xfe) {
-                       /* Set Common Voltage */
-                       comadj = current_par->comadj;
-                       if (comadj < 0) {
-                               comadj = COMADJ_DEFAULT;
-                       }
-                       lcdtg_set_common_voltage((POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF), comadj);
-               } else if (lcdtg_power_on_table[i].adrs == PHACTRL_ADRS) {
-                       /* Set Phase Adjuct */
-                       lcdtg_set_phadadj(mode);
-               } else {
-                       /* Other */
-                       lcdtg_ssp_send(lcdtg_power_on_table[i].adrs, lcdtg_power_on_table[i].data);
-               }
-               if (lcdtg_power_on_table[i].wait != 0)
-                       udelay(lcdtg_power_on_table[i].wait);
-               i++;
-       }
-
-       switch(mode) {
-       case LCD_SHARP_QVGA:
-               /* Set Lcd Resolution (QVGA) */
-               lcdtg_ssp_send(RESCTL_ADRS, RESCTL_QVGA);
-               break;
-       case LCD_SHARP_VGA:
-               /* Set Lcd Resolution (VGA) */
-               lcdtg_ssp_send(RESCTL_ADRS, RESCTL_VGA);
-               break;
-       default:
-               break;
-       }
-}
-
-static void lcdtg_lcd_change(u32 mode)
-{
-       /* Set Phase Adjuct */
-       lcdtg_set_phadadj(mode);
-
-       if (mode == LCD_SHARP_VGA)
-               /* Set Lcd Resolution (VGA) */
-               lcdtg_ssp_send(RESCTL_ADRS, RESCTL_VGA);
-       else if (mode == LCD_SHARP_QVGA)
-               /* Set Lcd Resolution (QVGA) */
-               lcdtg_ssp_send(RESCTL_ADRS, RESCTL_QVGA);
-}
-
-
 static struct device_driver w100fb_driver = {
        .name           = "w100fb",
        .bus            = &platform_bus_type,
@@ -1870,4 +1474,4 @@ module_init(w100fb_init);
 module_exit(w100fb_cleanup);
 
 MODULE_DESCRIPTION("ATI Imageon w100 framebuffer driver");
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL");
index 41624f961237cdcee3b34ada2d785085dc0f5d82..7a58a1e3e427c81d7e6c95a7e4164d3296540d29 100644 (file)
@@ -5,9 +5,12 @@
  *
  * Copyright (C) 2002, ATI Corp.
  * Copyright (C) 2004-2005 Richard Purdie
+ * Copyright (c) 2005 Ian Molton <spyro@f2s.com>
  *
  * Modified to work with 2.6 by Richard Purdie <rpurdie@rpsys.net>
  *
+ * w32xx support by Ian Molton
+ *
  * 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.
@@ -19,7 +22,7 @@
 
 /* Block CIF Start: */
 #define mmCHIP_ID           0x0000
-#define mmREVISION_ID          0x0004
+#define mmREVISION_ID       0x0004
 #define mmWRAP_BUF_A        0x0008
 #define mmWRAP_BUF_B        0x000C
 #define mmWRAP_TOP_DIR      0x0010
@@ -88,7 +91,7 @@
 #define mmDISP_DEBUG        0x04D4
 #define mmDISP_DB_BUF_CNTL  0x04D8
 #define mmDISP_CRC_SIG      0x04DC
-#define mmCRTC_DEFAULT_COUNT   0x04E0
+#define mmCRTC_DEFAULT_COUNT    0x04E0
 #define mmLCD_BACKGROUND_COLOR  0x04E4
 #define mmCRTC_PS2          0x04E8
 #define mmCRTC_PS2_VPOS     0x04EC
 /* Block DISPLAY End: */
 
 /* Block GFX Start: */
-#define mmBRUSH_OFFSET      0x108C
-#define mmBRUSH_Y_X         0x1074
-#define mmDEFAULT_PITCH_OFFSET         0x10A0
-#define mmDEFAULT_SC_BOTTOM_RIGHT      0x10A8
-#define mmDEFAULT2_SC_BOTTOM_RIGHT     0x10AC
-#define mmGLOBAL_ALPHA      0x1210
-#define mmFILTER_COEF       0x1214
-#define mmMVC_CNTL_START    0x11E0
-#define mmE2_ARITHMETIC_CNTL   0x1220
-#define mmENG_CNTL          0x13E8
-#define mmENG_PERF_CNT      0x13F0
+#define mmBRUSH_OFFSET        0x108C
+#define mmBRUSH_Y_X           0x1074
+#define mmDEFAULT_PITCH_OFFSET      0x10A0
+#define mmDEFAULT_SC_BOTTOM_RIGHT   0x10A8
+#define mmDEFAULT2_SC_BOTTOM_RIGHT  0x10AC
+#define mmGLOBAL_ALPHA        0x1210
+#define mmFILTER_COEF         0x1214
+#define mmMVC_CNTL_START      0x11E0
+#define mmE2_ARITHMETIC_CNTL  0x1220
+#define mmENG_CNTL            0x13E8
+#define mmENG_PERF_CNT        0x13F0
 /* Block GFX End: */
 
 /* Block IDCT Start: */
 /* Block IDCT End: */
 
 /* Block MC Start: */
-#define mmMEM_CNTL          0x0180
-#define mmMEM_ARB           0x0184
-#define mmMC_FB_LOCATION    0x0188
-#define mmMEM_EXT_CNTL      0x018C
-#define mmMC_EXT_MEM_LOCATION   0x0190
-#define mmMEM_EXT_TIMING_CNTL   0x0194
-#define mmMEM_SDRAM_MODE_REG   0x0198
-#define mmMEM_IO_CNTL       0x019C
-#define mmMC_DEBUG          0x01A0
-#define mmMC_BIST_CTRL      0x01A4
-#define mmMC_BIST_COLLAR_READ          0x01A8
-#define mmTC_MISMATCH       0x01AC
-#define mmMC_PERF_MON_CNTL  0x01B0
-#define mmMC_PERF_COUNTERS  0x01B4
+#define mmMEM_CNTL             0x0180
+#define mmMEM_ARB              0x0184
+#define mmMC_FB_LOCATION       0x0188
+#define mmMEM_EXT_CNTL         0x018C
+#define mmMC_EXT_MEM_LOCATION  0x0190
+#define mmMEM_EXT_TIMING_CNTL  0x0194
+#define mmMEM_SDRAM_MODE_REG   0x0198
+#define mmMEM_IO_CNTL          0x019C
+#define mmMC_DEBUG             0x01A0
+#define mmMC_BIST_CTRL         0x01A4
+#define mmMC_BIST_COLLAR_READ  0x01A8
+#define mmTC_MISMATCH          0x01AC
+#define mmMC_PERF_MON_CNTL     0x01B0
+#define mmMC_PERF_COUNTERS     0x01B4
 /* Block MC End: */
 
+/* Block BM Start: */
+#define mmBM_EXT_MEM_BANDWIDTH    0x0A00
+#define mmBM_OFFSET               0x0A04
+#define mmBM_MEM_EXT_TIMING_CNTL  0x0A08
+#define mmBM_MEM_EXT_CNTL         0x0A0C
+#define mmBM_MEM_MODE_REG         0x0A10
+#define mmBM_MEM_IO_CNTL          0x0A18
+#define mmBM_CONFIG               0x0A1C
+#define mmBM_STATUS               0x0A20
+#define mmBM_DEBUG                0x0A24
+#define mmBM_PERF_MON_CNTL        0x0A28
+#define mmBM_PERF_COUNTERS        0x0A2C
+#define mmBM_PERF2_MON_CNTL       0x0A30
+#define mmBM_PERF2_COUNTERS       0x0A34
+/* Block BM End: */
+
 /* Block RBBM Start: */
 #define mmWAIT_UNTIL        0x1400
 #define mmISYNC_CNTL        0x1404
 /* Block CG End: */
 
 /* default value definitions */
-#define defWRAP_TOP_DIR     0x00000000
-#define defWRAP_START_DIR      0x00000000
-#define defCFGREG_BASE      0x00000000
-#define defCIF_IO           0x000C0902
-#define defINTF_CNTL        0x00000011
-#define defCPU_DEFAULTS     0x00000006
-#define defHW_INT           0x00000000
-#define defMC_EXT_MEM_LOCATION            0x07ff0000
-#define defTC_MISMATCH      0x00000000
+#define defWRAP_TOP_DIR        0x00000000
+#define defWRAP_START_DIR      0x00000000
+#define defCFGREG_BASE         0x00000000
+#define defCIF_IO              0x000C0902
+#define defINTF_CNTL           0x00000011
+#define defCPU_DEFAULTS        0x00000006
+#define defHW_INT              0x00000000
+#define defMC_EXT_MEM_LOCATION 0x07ff0000
+#define defTC_MISMATCH         0x00000000
 
 #define W100_CFG_BASE          0x0
 #define W100_CFG_LEN           0x10
 #define W100_REG_BASE          0x10000
 #define W100_REG_LEN           0x2000
 #define MEM_INT_BASE_VALUE     0x100000
-#define MEM_INT_TOP_VALUE_W100 0x15ffff
 #define MEM_EXT_BASE_VALUE     0x800000
-#define MEM_EXT_TOP_VALUE      0x9fffff
+#define MEM_INT_SIZE           0x05ffff
+#define MEM_WINDOW_BASE        0x100000
+#define MEM_WINDOW_SIZE        0xf00000
+
 #define WRAP_BUF_BASE_VALUE    0x80000
 #define WRAP_BUF_TOP_VALUE     0xbffff
 
+#define CHIP_ID_W100           0x57411002
+#define CHIP_ID_W3200          0x56441002
+#define CHIP_ID_W3220          0x57441002
 
-/* data structure definitions */
+/* Register structure definitions */
 
 struct wrap_top_dir_t {
-     unsigned long top_addr         : 23;
-     unsigned long                             : 9;
+       unsigned long top_addr  : 23;
+       unsigned long           : 9;
 } __attribute__((packed));
 
 union wrap_top_dir_u {
-     unsigned long val : 32;
-     struct wrap_top_dir_t f;
+       unsigned long val : 32;
+       struct wrap_top_dir_t f;
 } __attribute__((packed));
 
 struct wrap_start_dir_t {
-     unsigned long start_addr       : 23;
-     unsigned long                             : 9;
+       unsigned long start_addr : 23;
+       unsigned long            : 9;
 } __attribute__((packed));
 
 union wrap_start_dir_u {
-     unsigned long val : 32;
-     struct wrap_start_dir_t f;
+       unsigned long val : 32;
+       struct wrap_start_dir_t f;
 } __attribute__((packed));
 
 struct cif_cntl_t {
-     unsigned long swap_reg                    : 2;
-     unsigned long swap_fbuf_1                 : 2;
-     unsigned long swap_fbuf_2                 : 2;
-     unsigned long swap_fbuf_3                 : 2;
-     unsigned long pmi_int_disable             : 1;
-     unsigned long pmi_schmen_disable       : 1;
-     unsigned long intb_oe                     : 1;
-     unsigned long en_wait_to_compensate_dq_prop_dly : 1;
-     unsigned long compensate_wait_rd_size  : 2;
-     unsigned long wait_asserted_timeout_val      : 2;
-     unsigned long wait_masked_val             : 2;
-     unsigned long en_wait_timeout             : 1;
-     unsigned long en_one_clk_setup_before_wait   : 1;
-     unsigned long interrupt_active_high    : 1;
-     unsigned long en_overwrite_straps      : 1;
-     unsigned long strap_wait_active_hi     : 1;
-     unsigned long lat_busy_count              : 2;
-     unsigned long lat_rd_pm4_sclk_busy     : 1;
-     unsigned long dis_system_bits             : 1;
-     unsigned long dis_mr                      : 1;
-     unsigned long cif_spare_1                 : 4;
+       unsigned long swap_reg                 : 2;
+       unsigned long swap_fbuf_1              : 2;
+       unsigned long swap_fbuf_2              : 2;
+       unsigned long swap_fbuf_3              : 2;
+       unsigned long pmi_int_disable          : 1;
+       unsigned long pmi_schmen_disable       : 1;
+       unsigned long intb_oe                  : 1;
+       unsigned long en_wait_to_compensate_dq_prop_dly  : 1;
+       unsigned long compensate_wait_rd_size  : 2;
+       unsigned long wait_asserted_timeout_val  : 2;
+       unsigned long wait_masked_val          : 2;
+       unsigned long en_wait_timeout          : 1;
+       unsigned long en_one_clk_setup_before_wait  : 1;
+       unsigned long interrupt_active_high    : 1;
+       unsigned long en_overwrite_straps      : 1;
+       unsigned long strap_wait_active_hi     : 1;
+       unsigned long lat_busy_count           : 2;
+       unsigned long lat_rd_pm4_sclk_busy     : 1;
+       unsigned long dis_system_bits          : 1;
+       unsigned long dis_mr                   : 1;
+       unsigned long cif_spare_1              : 4;
 } __attribute__((packed));
 
 union cif_cntl_u {
-     unsigned long val : 32;
-     struct cif_cntl_t f;
+       unsigned long val : 32;
+       struct cif_cntl_t f;
 } __attribute__((packed));
 
 struct cfgreg_base_t {
-     unsigned long cfgreg_base      : 24;
-     unsigned long                             : 8;
+       unsigned long cfgreg_base  : 24;
+       unsigned long              : 8;
 } __attribute__((packed));
 
 union cfgreg_base_u {
-     unsigned long val : 32;
-     struct cfgreg_base_t f;
+       unsigned long val : 32;
+       struct cfgreg_base_t f;
 } __attribute__((packed));
 
 struct cif_io_t {
-     unsigned long dq_srp           : 1;
-     unsigned long dq_srn           : 1;
-     unsigned long dq_sp            : 4;
-     unsigned long dq_sn            : 4;
-     unsigned long waitb_srp        : 1;
-     unsigned long waitb_srn        : 1;
-     unsigned long waitb_sp         : 4;
-     unsigned long waitb_sn         : 4;
-     unsigned long intb_srp         : 1;
-     unsigned long intb_srn         : 1;
-     unsigned long intb_sp          : 4;
-     unsigned long intb_sn          : 4;
-     unsigned long                             : 2;
+       unsigned long dq_srp     : 1;
+       unsigned long dq_srn     : 1;
+       unsigned long dq_sp      : 4;
+       unsigned long dq_sn      : 4;
+       unsigned long waitb_srp  : 1;
+       unsigned long waitb_srn  : 1;
+       unsigned long waitb_sp   : 4;
+       unsigned long waitb_sn   : 4;
+       unsigned long intb_srp   : 1;
+       unsigned long intb_srn   : 1;
+       unsigned long intb_sp    : 4;
+       unsigned long intb_sn    : 4;
+       unsigned long            : 2;
 } __attribute__((packed));
 
 union cif_io_u {
-     unsigned long val : 32;
-     struct cif_io_t f;
+       unsigned long val : 32;
+       struct cif_io_t f;
 } __attribute__((packed));
 
 struct cif_read_dbg_t {
-     unsigned long unpacker_pre_fetch_trig_gen  : 2;
-     unsigned long dly_second_rd_fetch_trig     : 1;
-     unsigned long rst_rd_burst_id                     : 1;
-     unsigned long dis_rd_burst_id                     : 1;
-     unsigned long en_block_rd_when_packer_is_not_emp : 1;
-     unsigned long dis_pre_fetch_cntl_sm        : 1;
-     unsigned long rbbm_chrncy_dis                     : 1;
-     unsigned long rbbm_rd_after_wr_lat         : 2;
-     unsigned long dis_be_during_rd                    : 1;
-     unsigned long one_clk_invalidate_pulse     : 1;
-     unsigned long dis_chnl_priority                   : 1;
-     unsigned long rst_read_path_a_pls          : 1;
-     unsigned long rst_read_path_b_pls          : 1;
-     unsigned long dis_reg_rd_fetch_trig        : 1;
-     unsigned long dis_rd_fetch_trig_from_ind_addr : 1;
-     unsigned long dis_rd_same_byte_to_trig_fetch : 1;
-     unsigned long dis_dir_wrap                        : 1;
-     unsigned long dis_ring_buf_to_force_dec    : 1;
-     unsigned long dis_addr_comp_in_16bit       : 1;
-     unsigned long clr_w                               : 1;
-     unsigned long err_rd_tag_is_3                     : 1;
-     unsigned long err_load_when_ful_a          : 1;
-     unsigned long err_load_when_ful_b          : 1;
-     unsigned long                                                     : 7;
+       unsigned long unpacker_pre_fetch_trig_gen  : 2;
+       unsigned long dly_second_rd_fetch_trig     : 1;
+       unsigned long rst_rd_burst_id              : 1;
+       unsigned long dis_rd_burst_id              : 1;
+       unsigned long en_block_rd_when_packer_is_not_emp : 1;
+       unsigned long dis_pre_fetch_cntl_sm        : 1;
+       unsigned long rbbm_chrncy_dis              : 1;
+       unsigned long rbbm_rd_after_wr_lat         : 2;
+       unsigned long dis_be_during_rd             : 1;
+       unsigned long one_clk_invalidate_pulse     : 1;
+       unsigned long dis_chnl_priority            : 1;
+       unsigned long rst_read_path_a_pls          : 1;
+       unsigned long rst_read_path_b_pls          : 1;
+       unsigned long dis_reg_rd_fetch_trig        : 1;
+       unsigned long dis_rd_fetch_trig_from_ind_addr : 1;
+       unsigned long dis_rd_same_byte_to_trig_fetch : 1;
+       unsigned long dis_dir_wrap                 : 1;
+       unsigned long dis_ring_buf_to_force_dec    : 1;
+       unsigned long dis_addr_comp_in_16bit       : 1;
+       unsigned long clr_w                        : 1;
+       unsigned long err_rd_tag_is_3              : 1;
+       unsigned long err_load_when_ful_a          : 1;
+       unsigned long err_load_when_ful_b          : 1;
+       unsigned long                              : 7;
 } __attribute__((packed));
 
 union cif_read_dbg_u {
-     unsigned long val : 32;
-     struct cif_read_dbg_t f;
+       unsigned long val : 32;
+       struct cif_read_dbg_t f;
 } __attribute__((packed));
 
 struct cif_write_dbg_t {
-     unsigned long packer_timeout_count           : 2;
-     unsigned long en_upper_load_cond             : 1;
-     unsigned long en_chnl_change_cond            : 1;
-     unsigned long dis_addr_comp_cond             : 1;
-     unsigned long dis_load_same_byte_addr_cond   : 1;
-     unsigned long dis_timeout_cond                      : 1;
-     unsigned long dis_timeout_during_rbbm        : 1;
-     unsigned long dis_packer_ful_during_rbbm_timeout : 1;
-     unsigned long en_dword_split_to_rbbm         : 1;
-     unsigned long en_dummy_val                          : 1;
-     unsigned long dummy_val_sel                         : 1;
-     unsigned long mask_pm4_wrptr_dec             : 1;
-     unsigned long dis_mc_clean_cond                     : 1;
-     unsigned long err_two_reqi_during_ful        : 1;
-     unsigned long err_reqi_during_idle_clk       : 1;
-     unsigned long err_global                            : 1;
-     unsigned long en_wr_buf_dbg_load             : 1;
-     unsigned long en_wr_buf_dbg_path             : 1;
-     unsigned long sel_wr_buf_byte                       : 3;
-     unsigned long dis_rd_flush_wr                       : 1;
-     unsigned long dis_packer_ful_cond            : 1;
-     unsigned long dis_invalidate_by_ops_chnl     : 1;
-     unsigned long en_halt_when_reqi_err          : 1;
-     unsigned long cif_spare_2                           : 5;
-     unsigned long                                                       : 1;
+       unsigned long packer_timeout_count          : 2;
+       unsigned long en_upper_load_cond            : 1;
+       unsigned long en_chnl_change_cond           : 1;
+       unsigned long dis_addr_comp_cond            : 1;
+       unsigned long dis_load_same_byte_addr_cond  : 1;
+       unsigned long dis_timeout_cond              : 1;
+       unsigned long dis_timeout_during_rbbm       : 1;
+       unsigned long dis_packer_ful_during_rbbm_timeout : 1;
+       unsigned long en_dword_split_to_rbbm        : 1;
+       unsigned long en_dummy_val                  : 1;
+       unsigned long dummy_val_sel                 : 1;
+       unsigned long mask_pm4_wrptr_dec            : 1;
+       unsigned long dis_mc_clean_cond             : 1;
+       unsigned long err_two_reqi_during_ful       : 1;
+       unsigned long err_reqi_during_idle_clk      : 1;
+       unsigned long err_global                    : 1;
+       unsigned long en_wr_buf_dbg_load            : 1;
+       unsigned long en_wr_buf_dbg_path            : 1;
+       unsigned long sel_wr_buf_byte               : 3;
+       unsigned long dis_rd_flush_wr               : 1;
+       unsigned long dis_packer_ful_cond           : 1;
+       unsigned long dis_invalidate_by_ops_chnl    : 1;
+       unsigned long en_halt_when_reqi_err         : 1;
+       unsigned long cif_spare_2                   : 5;
+       unsigned long                               : 1;
 } __attribute__((packed));
 
 union cif_write_dbg_u {
-     unsigned long val : 32;
-     struct cif_write_dbg_t f;
+       unsigned long val : 32;
+       struct cif_write_dbg_t f;
 } __attribute__((packed));
 
 
 struct intf_cntl_t {
-     unsigned char ad_inc_a            : 1;
-     unsigned char ring_buf_a          : 1;
-     unsigned char rd_fetch_trigger_a  : 1;
-     unsigned char rd_data_rdy_a       : 1;
-     unsigned char ad_inc_b            : 1;
-     unsigned char ring_buf_b          : 1;
-     unsigned char rd_fetch_trigger_b  : 1;
-     unsigned char rd_data_rdy_b       : 1;
+       unsigned char ad_inc_a            : 1;
+       unsigned char ring_buf_a          : 1;
+       unsigned char rd_fetch_trigger_a  : 1;
+       unsigned char rd_data_rdy_a       : 1;
+       unsigned char ad_inc_b            : 1;
+       unsigned char ring_buf_b          : 1;
+       unsigned char rd_fetch_trigger_b  : 1;
+       unsigned char rd_data_rdy_b       : 1;
 } __attribute__((packed));
 
 union intf_cntl_u {
-     unsigned char val : 8;
-     struct intf_cntl_t f;
+       unsigned char val : 8;
+       struct intf_cntl_t f;
 } __attribute__((packed));
 
 struct cpu_defaults_t {
-     unsigned char unpack_rd_data   : 1;
-     unsigned char access_ind_addr_a: 1;
-     unsigned char access_ind_addr_b: 1;
-     unsigned char access_scratch_reg             : 1;
-     unsigned char pack_wr_data     : 1;
-     unsigned char transition_size  : 1;
-     unsigned char en_read_buf_mode : 1;
-     unsigned char rd_fetch_scratch : 1;
+       unsigned char unpack_rd_data     : 1;
+       unsigned char access_ind_addr_a  : 1;
+       unsigned char access_ind_addr_b  : 1;
+       unsigned char access_scratch_reg : 1;
+       unsigned char pack_wr_data       : 1;
+       unsigned char transition_size    : 1;
+       unsigned char en_read_buf_mode   : 1;
+       unsigned char rd_fetch_scratch   : 1;
 } __attribute__((packed));
 
 union cpu_defaults_u {
-     unsigned char val : 8;
-     struct cpu_defaults_t f;
+       unsigned char val : 8;
+       struct cpu_defaults_t f;
+} __attribute__((packed));
+
+struct crtc_total_t {
+       unsigned long crtc_h_total : 10;
+       unsigned long              : 6;
+       unsigned long crtc_v_total : 10;
+       unsigned long              : 6;
+} __attribute__((packed));
+
+union crtc_total_u {
+       unsigned long val : 32;
+       struct crtc_total_t f;
+} __attribute__((packed));
+
+struct crtc_ss_t {
+       unsigned long ss_start    : 10;
+       unsigned long             : 6;
+       unsigned long ss_end      : 10;
+       unsigned long             : 2;
+       unsigned long ss_align    : 1;
+       unsigned long ss_pol      : 1;
+       unsigned long ss_run_mode : 1;
+       unsigned long ss_en       : 1;
+} __attribute__((packed));
+
+union crtc_ss_u {
+       unsigned long val : 32;
+       struct crtc_ss_t f;
+} __attribute__((packed));
+
+struct active_h_disp_t {
+       unsigned long active_h_start  : 10;
+       unsigned long                 : 6;
+       unsigned long active_h_end    : 10;
+       unsigned long                 : 6;
+} __attribute__((packed));
+
+union active_h_disp_u {
+       unsigned long val : 32;
+       struct active_h_disp_t f;
+} __attribute__((packed));
+
+struct active_v_disp_t {
+       unsigned long active_v_start  : 10;
+       unsigned long                 : 6;
+       unsigned long active_v_end    : 10;
+       unsigned long                 : 6;
+} __attribute__((packed));
+
+union active_v_disp_u {
+       unsigned long val : 32;
+       struct active_v_disp_t f;
+} __attribute__((packed));
+
+struct graphic_h_disp_t {
+       unsigned long graphic_h_start : 10;
+       unsigned long                 : 6;
+       unsigned long graphic_h_end   : 10;
+       unsigned long                 : 6;
+} __attribute__((packed));
+
+union graphic_h_disp_u {
+       unsigned long val : 32;
+       struct graphic_h_disp_t f;
+} __attribute__((packed));
+
+struct graphic_v_disp_t {
+       unsigned long graphic_v_start : 10;
+       unsigned long                 : 6;
+       unsigned long graphic_v_end   : 10;
+       unsigned long                 : 6;
+} __attribute__((packed));
+
+union graphic_v_disp_u{
+       unsigned long val : 32;
+       struct graphic_v_disp_t f;
+} __attribute__((packed));
+
+struct graphic_ctrl_t_w100 {
+       unsigned long color_depth       : 3;
+       unsigned long portrait_mode     : 2;
+       unsigned long low_power_on      : 1;
+       unsigned long req_freq          : 4;
+       unsigned long en_crtc           : 1;
+       unsigned long en_graphic_req    : 1;
+       unsigned long en_graphic_crtc   : 1;
+       unsigned long total_req_graphic : 9;
+       unsigned long lcd_pclk_on       : 1;
+       unsigned long lcd_sclk_on       : 1;
+       unsigned long pclk_running      : 1;
+       unsigned long sclk_running      : 1;
+       unsigned long                   : 6;
+} __attribute__((packed));
+
+struct graphic_ctrl_t_w32xx {
+       unsigned long color_depth       : 3;
+       unsigned long portrait_mode     : 2;
+       unsigned long low_power_on      : 1;
+       unsigned long req_freq          : 4;
+       unsigned long en_crtc           : 1;
+       unsigned long en_graphic_req    : 1;
+       unsigned long en_graphic_crtc   : 1;
+       unsigned long total_req_graphic : 10;
+       unsigned long lcd_pclk_on       : 1;
+       unsigned long lcd_sclk_on       : 1;
+       unsigned long pclk_running      : 1;
+       unsigned long sclk_running      : 1;
+       unsigned long                   : 5;
+} __attribute__((packed));
+
+union graphic_ctrl_u {
+       unsigned long val : 32;
+       struct graphic_ctrl_t_w100 f_w100;
+       struct graphic_ctrl_t_w32xx f_w32xx;
 } __attribute__((packed));
 
 struct video_ctrl_t {
-     unsigned long video_mode       : 1;
-     unsigned long keyer_en         : 1;
-     unsigned long en_video_req     : 1;
-     unsigned long en_graphic_req_video           : 1;
-     unsigned long en_video_crtc    : 1;
-     unsigned long video_hor_exp    : 2;
-     unsigned long video_ver_exp    : 2;
-     unsigned long uv_combine       : 1;
-     unsigned long total_req_video  : 9;
-     unsigned long video_ch_sel     : 1;
-     unsigned long video_portrait   : 2;
-     unsigned long yuv2rgb_en       : 1;
-     unsigned long yuv2rgb_option   : 1;
-     unsigned long video_inv_hor    : 1;
-     unsigned long video_inv_ver    : 1;
-     unsigned long gamma_sel        : 2;
-     unsigned long dis_limit        : 1;
-     unsigned long en_uv_hblend     : 1;
-     unsigned long rgb_gamma_sel    : 2;
+       unsigned long video_mode       : 1;
+       unsigned long keyer_en         : 1;
+       unsigned long en_video_req     : 1;
+       unsigned long en_graphic_req_video  : 1;
+       unsigned long en_video_crtc    : 1;
+       unsigned long video_hor_exp    : 2;
+       unsigned long video_ver_exp    : 2;
+       unsigned long uv_combine       : 1;
+       unsigned long total_req_video  : 9;
+       unsigned long video_ch_sel     : 1;
+       unsigned long video_portrait   : 2;
+       unsigned long yuv2rgb_en       : 1;
+       unsigned long yuv2rgb_option   : 1;
+       unsigned long video_inv_hor    : 1;
+       unsigned long video_inv_ver    : 1;
+       unsigned long gamma_sel        : 2;
+       unsigned long dis_limit        : 1;
+       unsigned long en_uv_hblend     : 1;
+       unsigned long rgb_gamma_sel    : 2;
 } __attribute__((packed));
 
 union video_ctrl_u {
-     unsigned long val : 32;
-     struct video_ctrl_t f;
+       unsigned long val : 32;
+       struct video_ctrl_t f;
 } __attribute__((packed));
 
 struct disp_db_buf_cntl_rd_t {
-     unsigned long en_db_buf           : 1;
-     unsigned long update_db_buf_done   : 1;
-     unsigned long db_buf_cntl         : 6;
-     unsigned long                                     : 24;
+       unsigned long en_db_buf           : 1;
+       unsigned long update_db_buf_done  : 1;
+       unsigned long db_buf_cntl         : 6;
+       unsigned long                     : 24;
 } __attribute__((packed));
 
 union disp_db_buf_cntl_rd_u {
-     unsigned long val : 32;
-     struct disp_db_buf_cntl_rd_t f;
+       unsigned long val : 32;
+       struct disp_db_buf_cntl_rd_t f;
 } __attribute__((packed));
 
 struct disp_db_buf_cntl_wr_t {
-     unsigned long en_db_buf        : 1;
-     unsigned long update_db_buf    : 1;
-     unsigned long db_buf_cntl      : 6;
-     unsigned long    : 24;
+       unsigned long en_db_buf      : 1;
+       unsigned long update_db_buf  : 1;
+       unsigned long db_buf_cntl    : 6;
+       unsigned long                : 24;
 } __attribute__((packed));
 
 union disp_db_buf_cntl_wr_u {
-     unsigned long val : 32;
-     struct disp_db_buf_cntl_wr_t f;
+       unsigned long val : 32;
+       struct disp_db_buf_cntl_wr_t f;
 } __attribute__((packed));
 
 struct gamma_value1_t {
-     unsigned long gamma1           : 8;
-     unsigned long gamma2           : 8;
-     unsigned long gamma3           : 8;
-     unsigned long gamma4           : 8;
+       unsigned long gamma1   : 8;
+       unsigned long gamma2   : 8;
+       unsigned long gamma3   : 8;
+       unsigned long gamma4   : 8;
 } __attribute__((packed));
 
 union gamma_value1_u {
-     unsigned long val : 32;
-     struct gamma_value1_t f;
+       unsigned long val : 32;
+       struct gamma_value1_t f;
 } __attribute__((packed));
 
 struct gamma_value2_t {
-     unsigned long gamma5           : 8;
-     unsigned long gamma6           : 8;
-     unsigned long gamma7           : 8;
-     unsigned long gamma8           : 8;
+       unsigned long gamma5   : 8;
+       unsigned long gamma6   : 8;
+       unsigned long gamma7   : 8;
+       unsigned long gamma8   : 8;
 } __attribute__((packed));
 
 union gamma_value2_u {
-     unsigned long val : 32;
-     struct gamma_value2_t f;
+       unsigned long val : 32;
+       struct gamma_value2_t f;
 } __attribute__((packed));
 
 struct gamma_slope_t {
-     unsigned long slope1           : 3;
-     unsigned long slope2           : 3;
-     unsigned long slope3           : 3;
-     unsigned long slope4           : 3;
-     unsigned long slope5           : 3;
-     unsigned long slope6           : 3;
-     unsigned long slope7           : 3;
-     unsigned long slope8           : 3;
-     unsigned long                             : 8;
+       unsigned long slope1   : 3;
+       unsigned long slope2   : 3;
+       unsigned long slope3   : 3;
+       unsigned long slope4   : 3;
+       unsigned long slope5   : 3;
+       unsigned long slope6   : 3;
+       unsigned long slope7   : 3;
+       unsigned long slope8   : 3;
+       unsigned long          : 8;
 } __attribute__((packed));
 
 union gamma_slope_u {
-     unsigned long val : 32;
-     struct gamma_slope_t f;
+       unsigned long val : 32;
+       struct gamma_slope_t f;
 } __attribute__((packed));
 
 struct mc_ext_mem_location_t {
-     unsigned long mc_ext_mem_start : 16;
-     unsigned long mc_ext_mem_top   : 16;
+       unsigned long mc_ext_mem_start : 16;
+       unsigned long mc_ext_mem_top   : 16;
 } __attribute__((packed));
 
 union mc_ext_mem_location_u {
-     unsigned long val : 32;
-     struct mc_ext_mem_location_t f;
+       unsigned long val : 32;
+       struct mc_ext_mem_location_t f;
+} __attribute__((packed));
+
+struct mc_fb_location_t {
+       unsigned long mc_fb_start      : 16;
+       unsigned long mc_fb_top        : 16;
+} __attribute__((packed));
+
+union mc_fb_location_u {
+       unsigned long val : 32;
+       struct mc_fb_location_t f;
 } __attribute__((packed));
 
 struct clk_pin_cntl_t {
-     unsigned long osc_en           : 1;
-     unsigned long osc_gain         : 5;
-     unsigned long dont_use_xtalin  : 1;
-     unsigned long xtalin_pm_en     : 1;
-     unsigned long xtalin_dbl_en    : 1;
-     unsigned long                             : 7;
-     unsigned long cg_debug         : 16;
+       unsigned long osc_en           : 1;
+       unsigned long osc_gain         : 5;
+       unsigned long dont_use_xtalin  : 1;
+       unsigned long xtalin_pm_en     : 1;
+       unsigned long xtalin_dbl_en    : 1;
+       unsigned long                  : 7;
+       unsigned long cg_debug         : 16;
 } __attribute__((packed));
 
 union clk_pin_cntl_u {
-     unsigned long val : 32;
-     struct clk_pin_cntl_t f;
+       unsigned long val : 32;
+       struct clk_pin_cntl_t f;
 } __attribute__((packed));
 
 struct pll_ref_fb_div_t {
-     unsigned long pll_ref_div      : 4;
-     unsigned long                             : 4;
-     unsigned long pll_fb_div_int   : 6;
-     unsigned long                             : 2;
-     unsigned long pll_fb_div_frac  : 3;
-     unsigned long                             : 1;
-     unsigned long pll_reset_time   : 4;
-     unsigned long pll_lock_time    : 8;
+       unsigned long pll_ref_div      : 4;
+       unsigned long                  : 4;
+       unsigned long pll_fb_div_int   : 6;
+       unsigned long                  : 2;
+       unsigned long pll_fb_div_frac  : 3;
+       unsigned long                  : 1;
+       unsigned long pll_reset_time   : 4;
+       unsigned long pll_lock_time    : 8;
 } __attribute__((packed));
 
 union pll_ref_fb_div_u {
-     unsigned long val : 32;
-     struct pll_ref_fb_div_t f;
+       unsigned long val : 32;
+       struct pll_ref_fb_div_t f;
 } __attribute__((packed));
 
 struct pll_cntl_t {
-     unsigned long pll_pwdn         : 1;
-     unsigned long pll_reset        : 1;
-     unsigned long pll_pm_en        : 1;
-     unsigned long pll_mode         : 1;
-     unsigned long pll_refclk_sel   : 1;
-     unsigned long pll_fbclk_sel    : 1;
-     unsigned long pll_tcpoff       : 1;
-     unsigned long pll_pcp          : 3;
-     unsigned long pll_pvg          : 3;
-     unsigned long pll_vcofr        : 1;
-     unsigned long pll_ioffset      : 2;
-     unsigned long pll_pecc_mode    : 2;
-     unsigned long pll_pecc_scon    : 2;
-     unsigned long pll_dactal       : 4;
-     unsigned long pll_cp_clip      : 2;
-     unsigned long pll_conf         : 3;
-     unsigned long pll_mbctrl       : 2;
-     unsigned long pll_ring_off     : 1;
+       unsigned long pll_pwdn        : 1;
+       unsigned long pll_reset       : 1;
+       unsigned long pll_pm_en       : 1;
+       unsigned long pll_mode        : 1;
+       unsigned long pll_refclk_sel  : 1;
+       unsigned long pll_fbclk_sel   : 1;
+       unsigned long pll_tcpoff      : 1;
+       unsigned long pll_pcp         : 3;
+       unsigned long pll_pvg         : 3;
+       unsigned long pll_vcofr       : 1;
+       unsigned long pll_ioffset     : 2;
+       unsigned long pll_pecc_mode   : 2;
+       unsigned long pll_pecc_scon   : 2;
+       unsigned long pll_dactal      : 4;
+       unsigned long pll_cp_clip     : 2;
+       unsigned long pll_conf        : 3;
+       unsigned long pll_mbctrl      : 2;
+       unsigned long pll_ring_off    : 1;
 } __attribute__((packed));
 
 union pll_cntl_u {
-     unsigned long val : 32;
-     struct pll_cntl_t f;
+       unsigned long val : 32;
+       struct pll_cntl_t f;
 } __attribute__((packed));
 
 struct sclk_cntl_t {
-     unsigned long sclk_src_sel        : 2;
-     unsigned long                                     : 2;
-     unsigned long sclk_post_div_fast   : 4;
-     unsigned long sclk_clkon_hys      : 3;
-     unsigned long sclk_post_div_slow   : 4;
-     unsigned long disp_cg_ok2switch_en : 1;
-     unsigned long sclk_force_reg      : 1;
-     unsigned long sclk_force_disp     : 1;
-     unsigned long sclk_force_mc       : 1;
-     unsigned long sclk_force_extmc    : 1;
-     unsigned long sclk_force_cp       : 1;
-     unsigned long sclk_force_e2       : 1;
-     unsigned long sclk_force_e3       : 1;
-     unsigned long sclk_force_idct     : 1;
-     unsigned long sclk_force_bist     : 1;
-     unsigned long busy_extend_cp      : 1;
-     unsigned long busy_extend_e2      : 1;
-     unsigned long busy_extend_e3      : 1;
-     unsigned long busy_extend_idct    : 1;
-     unsigned long                                     : 3;
+       unsigned long sclk_src_sel         : 2;
+       unsigned long                      : 2;
+       unsigned long sclk_post_div_fast   : 4;
+       unsigned long sclk_clkon_hys       : 3;
+       unsigned long sclk_post_div_slow   : 4;
+       unsigned long disp_cg_ok2switch_en : 1;
+       unsigned long sclk_force_reg       : 1;
+       unsigned long sclk_force_disp      : 1;
+       unsigned long sclk_force_mc        : 1;
+       unsigned long sclk_force_extmc     : 1;
+       unsigned long sclk_force_cp        : 1;
+       unsigned long sclk_force_e2        : 1;
+       unsigned long sclk_force_e3        : 1;
+       unsigned long sclk_force_idct      : 1;
+       unsigned long sclk_force_bist      : 1;
+       unsigned long busy_extend_cp       : 1;
+       unsigned long busy_extend_e2       : 1;
+       unsigned long busy_extend_e3       : 1;
+       unsigned long busy_extend_idct     : 1;
+       unsigned long                      : 3;
 } __attribute__((packed));
 
 union sclk_cntl_u {
-     unsigned long val : 32;
-     struct sclk_cntl_t f;
+       unsigned long val : 32;
+       struct sclk_cntl_t f;
 } __attribute__((packed));
 
 struct pclk_cntl_t {
-     unsigned long pclk_src_sel     : 2;
-     unsigned long                             : 2;
-     unsigned long pclk_post_div    : 4;
-     unsigned long                             : 8;
-     unsigned long pclk_force_disp  : 1;
-     unsigned long                             : 15;
+       unsigned long pclk_src_sel     : 2;
+       unsigned long                  : 2;
+       unsigned long pclk_post_div    : 4;
+       unsigned long                  : 8;
+       unsigned long pclk_force_disp  : 1;
+       unsigned long                  : 15;
 } __attribute__((packed));
 
 union pclk_cntl_u {
-     unsigned long val : 32;
-     struct pclk_cntl_t f;
+       unsigned long val : 32;
+       struct pclk_cntl_t f;
 } __attribute__((packed));
 
+
+#define TESTCLK_SRC_PLL   0x01
+#define TESTCLK_SRC_SCLK  0x02
+#define TESTCLK_SRC_PCLK  0x03
+/* 4 and 5 seem to by XTAL/M */
+#define TESTCLK_SRC_XTAL  0x06
+
 struct clk_test_cntl_t {
-     unsigned long testclk_sel      : 4;
-     unsigned long                             : 3;
-     unsigned long start_check_freq : 1;
-     unsigned long tstcount_rst     : 1;
-     unsigned long                             : 15;
-     unsigned long test_count       : 8;
+       unsigned long testclk_sel      : 4;
+       unsigned long                  : 3;
+       unsigned long start_check_freq : 1;
+       unsigned long tstcount_rst     : 1;
+       unsigned long                  : 15;
+       unsigned long test_count       : 8;
 } __attribute__((packed));
 
 union clk_test_cntl_u {
-     unsigned long val : 32;
-     struct clk_test_cntl_t f;
+       unsigned long val : 32;
+       struct clk_test_cntl_t f;
 } __attribute__((packed));
 
 struct pwrmgt_cntl_t {
-     unsigned long pwm_enable          : 1;
-     unsigned long                                     : 1;
-     unsigned long pwm_mode_req         : 2;
-     unsigned long pwm_wakeup_cond      : 2;
-     unsigned long pwm_fast_noml_hw_en  : 1;
-     unsigned long pwm_noml_fast_hw_en  : 1;
-     unsigned long pwm_fast_noml_cond   : 4;
-     unsigned long pwm_noml_fast_cond   : 4;
-     unsigned long pwm_idle_timer      : 8;
-     unsigned long pwm_busy_timer      : 8;
+       unsigned long pwm_enable           : 1;
+       unsigned long                      : 1;
+       unsigned long pwm_mode_req         : 2;
+       unsigned long pwm_wakeup_cond      : 2;
+       unsigned long pwm_fast_noml_hw_en  : 1;
+       unsigned long pwm_noml_fast_hw_en  : 1;
+       unsigned long pwm_fast_noml_cond   : 4;
+       unsigned long pwm_noml_fast_cond   : 4;
+       unsigned long pwm_idle_timer       : 8;
+       unsigned long pwm_busy_timer       : 8;
 } __attribute__((packed));
 
 union pwrmgt_cntl_u {
-     unsigned long val : 32;
-     struct pwrmgt_cntl_t f;
+       unsigned long val : 32;
+       struct pwrmgt_cntl_t f;
 } __attribute__((packed));
 
 #endif
index b5a5e04b6d37fb172256595c3e905a22f3378d6c..498ad505fa5f94360309063f7a72ec715ef75dd2 100644 (file)
@@ -86,9 +86,9 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
 
        dev->driver = driver;
 
-       dev->groups = 23;
+       dev->groups = 1;
        dev->seq = 1;
-       dev->nls = netlink_kernel_create(NETLINK_W1, NULL);
+       dev->nls = netlink_kernel_create(NETLINK_W1, 1, NULL, THIS_MODULE);
        if (!dev->nls) {
                printk(KERN_ERR "Failed to create new netlink socket(%u) for w1 master %s.\n",
                        NETLINK_NFLOG, dev->dev.bus_id);
@@ -225,3 +225,5 @@ void w1_remove_master_device(struct w1_bus_master *bm)
 
 EXPORT_SYMBOL(w1_add_master_device);
 EXPORT_SYMBOL(w1_remove_master_device);
+
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_W1);
index 2a82fb055c70bfb2ef4a25dff024da1c681bbd13..e7b774423dd65c56fce07dc13ca0017e713fb6f3 100644 (file)
@@ -51,7 +51,7 @@ void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
 
        memcpy(data, msg, sizeof(struct w1_netlink_msg));
 
-       NETLINK_CB(skb).dst_groups = dev->groups;
+       NETLINK_CB(skb).dst_group = dev->groups;
        netlink_broadcast(dev->nls, skb, 0, dev->groups, GFP_ATOMIC);
 
 nlmsg_failure:
index e54be7058359e0beee537f4f5d21d7544148c687..5e817902cb3b408db8c02467a47b856d64eb8b09 100644 (file)
@@ -382,10 +382,8 @@ config QUOTA
          usage (also called disk quotas). Currently, it works for the
          ext2, ext3, and reiserfs file system. ext3 also supports journalled
          quotas for which you don't need to run quotacheck(8) after an unclean
-         shutdown. You need additional software in order to use quota support
-         (you can download sources from
-         <http://www.sf.net/projects/linuxquota/>). For further details, read
-         the Quota mini-HOWTO, available from
+         shutdown.
+         For further details, read the Quota mini-HOWTO, available from
          <http://www.tldp.org/docs.html#howto>, or the documentation provided
          with the quota tools. Probably the quota support is only useful for
          multi user systems. If unsure, say N.
@@ -403,8 +401,7 @@ config QFMT_V2
        depends on QUOTA
        help
          This quota format allows using quotas with 32-bit UIDs/GIDs. If you
-         need this functionality say Y here. Note that you will need recent
-         quota utilities (>= 3.01) for new quota format with this kernel.
+         need this functionality say Y here.
 
 config QUOTACTL
        bool
@@ -783,28 +780,6 @@ config SYSFS
 
        Designers of embedded systems may wish to say N here to conserve space.
 
-config DEVPTS_FS_XATTR
-       bool "/dev/pts Extended Attributes"
-       depends on UNIX98_PTYS
-       help
-         Extended attributes are name:value pairs associated with inodes by
-         the kernel or by users (see the attr(5) manual page, or visit
-         <http://acl.bestbits.at/> for details).
-
-         If unsure, say N.
-
-config DEVPTS_FS_SECURITY
-       bool "/dev/pts Security Labels"
-       depends on DEVPTS_FS_XATTR
-       help
-         Security labels support alternative access control models
-         implemented by security modules like SELinux.  This option
-         enables an extended attribute handler for file security
-         labels in the /dev/pts filesystem.
-
-         If you are not using a security module that requires using
-         extended attributes for file security labels, say N.
-
 config TMPFS
        bool "Virtual memory file system support (former shm fs)"
        help
@@ -817,27 +792,6 @@ config TMPFS
 
          See <file:Documentation/filesystems/tmpfs.txt> for details.
 
-config TMPFS_XATTR
-       bool "tmpfs Extended Attributes"
-       depends on TMPFS
-       help
-         Extended attributes are name:value pairs associated with inodes by
-         the kernel or by users (see the attr(5) manual page, or visit
-         <http://acl.bestbits.at/> for details).
-
-         If unsure, say N.
-
-config TMPFS_SECURITY
-       bool "tmpfs Security Labels"
-       depends on TMPFS_XATTR
-       help
-         Security labels support alternative access control models
-         implemented by security modules like SELinux.  This option
-         enables an extended attribute handler for file security
-         labels in the tmpfs filesystem.
-         If you are not using a security module that requires using
-         extended attributes for file security labels, say N.
-
 config HUGETLBFS
        bool "HugeTLB file system support"
        depends X86 || IA64 || PPC64 || SPARC64 || SUPERH || X86_64 || BROKEN
@@ -859,6 +813,18 @@ config RAMFS
          To compile this as a module, choose M here: the module will be called
          ramfs.
 
+config RELAYFS_FS
+       tristate "Relayfs file system support"
+       ---help---
+         Relayfs is a high-speed data relay filesystem designed to provide
+         an efficient mechanism for tools and facilities to relay large
+         amounts of data from kernel space to user space.
+
+         To compile this code as a module, choose M here: the module will be
+         called relayfs.
+
+         If unsure, say N.
+
 endmenu
 
 menu "Miscellaneous filesystems"
index cf95eb894fd53776b3429354834aac373f0e8170..15158309dee4ae42d2caf7429c274e20945efcbf 100644 (file)
@@ -90,6 +90,7 @@ obj-$(CONFIG_AUTOFS_FS)               += autofs/
 obj-$(CONFIG_AUTOFS4_FS)       += autofs4/
 obj-$(CONFIG_ADFS_FS)          += adfs/
 obj-$(CONFIG_UDF_FS)           += udf/
+obj-$(CONFIG_RELAYFS_FS)       += relayfs/
 obj-$(CONFIG_SUN_OPENPROMFS)   += openpromfs/
 obj-$(CONFIG_JFS_FS)           += jfs/
 obj-$(CONFIG_XFS_FS)           += xfs/
index 63f5df9afb71f96c5e649fbb0f2c6cf3275513b6..fd528433de43d1faeff397551081ac4ea48320b5 100644 (file)
@@ -97,7 +97,7 @@ extern int adfs_dir_update(struct super_block *sb, struct object_info *obj);
 extern struct inode_operations adfs_file_inode_operations;
 extern struct file_operations adfs_file_operations;
 
-extern inline __u32 signed_asl(__u32 val, signed int shift)
+static inline __u32 signed_asl(__u32 val, signed int shift)
 {
        if (shift >= 0)
                val <<= shift;
@@ -112,7 +112,7 @@ extern inline __u32 signed_asl(__u32 val, signed int shift)
  *
  * The root directory ID should always be looked up in the map [3.4]
  */
-extern inline int
+static inline int
 __adfs_block_map(struct super_block *sb, unsigned int object_id,
                 unsigned int block)
 {
index 06d7d4390fe7dd8562e8433ce3a29b2b9ee4e241..4f641abac3c0927f2036f81f3f70106a57a09e22 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -567,6 +567,10 @@ static void use_mm(struct mm_struct *mm)
        atomic_inc(&mm->mm_count);
        tsk->mm = mm;
        tsk->active_mm = mm;
+       /*
+        * Note that on UML this *requires* PF_BORROWED_MM to be set, otherwise
+        * it won't work. Update it accordingly if you change it here
+        */
        activate_mm(active_mm, mm);
        task_unlock(tsk);
 
index c8998dc668824df41ef382e65af0b76124d41536..7974efa107bce19795f0889da79955416db41adb 100644 (file)
@@ -520,7 +520,7 @@ static int load_flat_file(struct linux_binprm * bprm,
                DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n");
 
                down_write(&current->mm->mmap_sem);
-               textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, MAP_SHARED, 0);
+               textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, MAP_PRIVATE, 0);
                up_write(&current->mm->mmap_sem);
                if (!textpos  || textpos >= (unsigned long) -4096) {
                        if (!textpos)
index e49cf7dd2e92ab4dc6deb8c13d20f161ede6d452..a7d4fd3a329954e18c787673ccf4a15e4369b92f 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -105,18 +105,22 @@ static inline struct bio_vec *bvec_alloc_bs(unsigned int __nocast gfp_mask, int
        return bvl;
 }
 
-/*
- * default destructor for a bio allocated with bio_alloc_bioset()
- */
-static void bio_destructor(struct bio *bio)
+void bio_free(struct bio *bio, struct bio_set *bio_set)
 {
        const int pool_idx = BIO_POOL_IDX(bio);
-       struct bio_set *bs = bio->bi_set;
 
        BIO_BUG_ON(pool_idx >= BIOVEC_NR_POOLS);
 
-       mempool_free(bio->bi_io_vec, bs->bvec_pools[pool_idx]);
-       mempool_free(bio, bs->bio_pool);
+       mempool_free(bio->bi_io_vec, bio_set->bvec_pools[pool_idx]);
+       mempool_free(bio, bio_set->bio_pool);
+}
+
+/*
+ * default destructor for a bio allocated with bio_alloc_bioset()
+ */
+static void bio_fs_destructor(struct bio *bio)
+{
+       bio_free(bio, fs_bio_set);
 }
 
 inline void bio_init(struct bio *bio)
@@ -172,8 +176,6 @@ struct bio *bio_alloc_bioset(unsigned int __nocast gfp_mask, int nr_iovecs, stru
                        bio->bi_max_vecs = bvec_slabs[idx].nr_vecs;
                }
                bio->bi_io_vec = bvl;
-               bio->bi_destructor = bio_destructor;
-               bio->bi_set = bs;
        }
 out:
        return bio;
@@ -181,7 +183,12 @@ out:
 
 struct bio *bio_alloc(unsigned int __nocast gfp_mask, int nr_iovecs)
 {
-       return bio_alloc_bioset(gfp_mask, nr_iovecs, fs_bio_set);
+       struct bio *bio = bio_alloc_bioset(gfp_mask, nr_iovecs, fs_bio_set);
+
+       if (bio)
+               bio->bi_destructor = bio_fs_destructor;
+
+       return bio;
 }
 
 void zero_fill_bio(struct bio *bio)
@@ -274,8 +281,10 @@ struct bio *bio_clone(struct bio *bio, unsigned int __nocast gfp_mask)
 {
        struct bio *b = bio_alloc_bioset(gfp_mask, bio->bi_max_vecs, fs_bio_set);
 
-       if (b)
+       if (b) {
+               b->bi_destructor = bio_fs_destructor;
                __bio_clone(b, bio);
+       }
 
        return b;
 }
@@ -1211,6 +1220,7 @@ subsys_initcall(init_bio);
 
 EXPORT_SYMBOL(bio_alloc);
 EXPORT_SYMBOL(bio_put);
+EXPORT_SYMBOL(bio_free);
 EXPORT_SYMBOL(bio_endio);
 EXPORT_SYMBOL(bio_init);
 EXPORT_SYMBOL(__bio_clone);
index 6a25d7df89b176db6bb7163517538476398a9af4..1c62203a4906ec1c7ba2ca9ede00e2a2c498aeda 100644 (file)
@@ -917,8 +917,7 @@ static int fsync_buffers_list(spinlock_t *lock, struct list_head *list)
                                 * contents - it is a noop if I/O is still in
                                 * flight on potentially older contents.
                                 */
-                               wait_on_buffer(bh);
-                               ll_rw_block(WRITE, 1, &bh);
+                               ll_rw_block(SWRITE, 1, &bh);
                                brelse(bh);
                                spin_lock(lock);
                        }
@@ -2793,21 +2792,22 @@ int submit_bh(int rw, struct buffer_head * bh)
 
 /**
  * ll_rw_block: low-level access to block devices (DEPRECATED)
- * @rw: whether to %READ or %WRITE or maybe %READA (readahead)
+ * @rw: whether to %READ or %WRITE or %SWRITE or maybe %READA (readahead)
  * @nr: number of &struct buffer_heads in the array
  * @bhs: array of pointers to &struct buffer_head
  *
- * ll_rw_block() takes an array of pointers to &struct buffer_heads,
- * and requests an I/O operation on them, either a %READ or a %WRITE.
- * The third %READA option is described in the documentation for
- * generic_make_request() which ll_rw_block() calls.
+ * ll_rw_block() takes an array of pointers to &struct buffer_heads, and
+ * requests an I/O operation on them, either a %READ or a %WRITE.  The third
+ * %SWRITE is like %WRITE only we make sure that the *current* data in buffers
+ * are sent to disk. The fourth %READA option is described in the documentation
+ * for generic_make_request() which ll_rw_block() calls.
  *
  * This function drops any buffer that it cannot get a lock on (with the
- * BH_Lock state bit), any buffer that appears to be clean when doing a
- * write request, and any buffer that appears to be up-to-date when doing
- * read request.  Further it marks as clean buffers that are processed for
- * writing (the buffer cache won't assume that they are actually clean until
- * the buffer gets unlocked).
+ * BH_Lock state bit) unless SWRITE is required, any buffer that appears to be
+ * clean when doing a write request, and any buffer that appears to be
+ * up-to-date when doing read request.  Further it marks as clean buffers that
+ * are processed for writing (the buffer cache won't assume that they are
+ * actually clean until the buffer gets unlocked).
  *
  * ll_rw_block sets b_end_io to simple completion handler that marks
  * the buffer up-to-date (if approriate), unlocks the buffer and wakes
@@ -2823,11 +2823,13 @@ void ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
        for (i = 0; i < nr; i++) {
                struct buffer_head *bh = bhs[i];
 
-               if (test_set_buffer_locked(bh))
+               if (rw == SWRITE)
+                       lock_buffer(bh);
+               else if (test_set_buffer_locked(bh))
                        continue;
 
                get_bh(bh);
-               if (rw == WRITE) {
+               if (rw == WRITE || rw == SWRITE) {
                        if (test_clear_buffer_dirty(bh)) {
                                bh->b_end_io = end_buffer_write_sync;
                                submit_bh(WRITE, bh);
@@ -3046,10 +3048,9 @@ struct buffer_head *alloc_buffer_head(unsigned int __nocast gfp_flags)
 {
        struct buffer_head *ret = kmem_cache_alloc(bh_cachep, gfp_flags);
        if (ret) {
-               preempt_disable();
-               __get_cpu_var(bh_accounting).nr++;
+               get_cpu_var(bh_accounting).nr++;
                recalc_bh_state();
-               preempt_enable();
+               put_cpu_var(bh_accounting);
        }
        return ret;
 }
@@ -3059,10 +3060,9 @@ void free_buffer_head(struct buffer_head *bh)
 {
        BUG_ON(!list_empty(&bh->b_assoc_buffers));
        kmem_cache_free(bh_cachep, bh);
-       preempt_disable();
-       __get_cpu_var(bh_accounting).nr--;
+       get_cpu_var(bh_accounting).nr--;
        recalc_bh_state();
-       preempt_enable();
+       put_cpu_var(bh_accounting);
 }
 EXPORT_SYMBOL(free_buffer_head);
 
index e568cc47a7f93005518d1470696f89ee1444a1ae..3217ac5f6bd7aa03277307aa66a5f64573681c49 100644 (file)
@@ -836,7 +836,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                                /* go from value to value + temp_len condensing 
                                double commas to singles. Note that this ends up
                                allocating a few bytes too many, which is ok */
-                               vol->password = kcalloc(1, temp_len, GFP_KERNEL);
+                               vol->password = kzalloc(temp_len, GFP_KERNEL);
                                if(vol->password == NULL) {
                                        printk("CIFS: no memory for pass\n");
                                        return 1;
@@ -851,7 +851,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                                }
                                vol->password[j] = 0;
                        } else {
-                               vol->password = kcalloc(1, temp_len+1, GFP_KERNEL);
+                               vol->password = kzalloc(temp_len+1, GFP_KERNEL);
                                if(vol->password == NULL) {
                                        printk("CIFS: no memory for pass\n");
                                        return 1;
@@ -1317,7 +1317,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
                sessinit is sent but no second negprot */
                struct rfc1002_session_packet * ses_init_buf;
                struct smb_hdr * smb_buf;
-               ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
+               ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
                if(ses_init_buf) {
                        ses_init_buf->trailer.session_req.called_len = 32;
                        rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
@@ -1964,7 +1964,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 /* We look for obvious messed up bcc or strings in response so we do not go off
    the end since (at least) WIN2K and Windows XP have a major bug in not null
    terminating last Unicode string in response  */
-                               ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
+                               ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
                                if(ses->serverOS == NULL)
                                        goto sesssetup_nomem;
                                cifs_strfromUCS_le(ses->serverOS,
@@ -1976,7 +1976,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                if (remaining_words > 0) {
                                        len = UniStrnlen((wchar_t *)bcc_ptr,
                                                         remaining_words-1);
-                                       ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
+                                       ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
                                        if(ses->serverNOS == NULL)
                                                goto sesssetup_nomem;
                                        cifs_strfromUCS_le(ses->serverNOS,
@@ -1994,7 +1994,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
           /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
                                                ses->serverDomain =
-                                                   kcalloc(1, 2*(len+1),GFP_KERNEL);
+                                                   kzalloc(2*(len+1),GFP_KERNEL);
                                                if(ses->serverDomain == NULL)
                                                        goto sesssetup_nomem;
                                                cifs_strfromUCS_le(ses->serverDomain,
@@ -2005,22 +2005,22 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        } /* else no more room so create dummy domain string */
                                        else
                                                ses->serverDomain = 
-                                                       kcalloc(1, 2, GFP_KERNEL);
+                                                       kzalloc(2, GFP_KERNEL);
                                } else {        /* no room so create dummy domain and NOS string */
                                        /* if these kcallocs fail not much we
                                           can do, but better to not fail the
                                           sesssetup itself */
                                        ses->serverDomain =
-                                           kcalloc(1, 2, GFP_KERNEL);
+                                           kzalloc(2, GFP_KERNEL);
                                        ses->serverNOS =
-                                           kcalloc(1, 2, GFP_KERNEL);
+                                           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)) {
-                                       ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
+                                       ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
                                        if(ses->serverOS == NULL)
                                                goto sesssetup_nomem;
                                        strncpy(ses->serverOS,bcc_ptr, len);
@@ -2030,7 +2030,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        bcc_ptr++;
 
                                        len = strnlen(bcc_ptr, 1024);
-                                       ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
+                                       ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
                                        if(ses->serverNOS == NULL)
                                                goto sesssetup_nomem;
                                        strncpy(ses->serverNOS, bcc_ptr, len);
@@ -2039,7 +2039,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        bcc_ptr++;
 
                                        len = strnlen(bcc_ptr, 1024);
-                                       ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
+                                       ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
                                        if(ses->serverDomain == NULL)
                                                goto sesssetup_nomem;
                                        strncpy(ses->serverDomain, bcc_ptr, len);
@@ -2240,7 +2240,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
    the end since (at least) WIN2K and Windows XP have a major bug in not null
    terminating last Unicode string in response  */
                                        ses->serverOS =
-                                           kcalloc(1, 2 * (len + 1), GFP_KERNEL);
+                                           kzalloc(2 * (len + 1), GFP_KERNEL);
                                        cifs_strfromUCS_le(ses->serverOS,
                                                           (wchar_t *)
                                                           bcc_ptr, len,
@@ -2254,7 +2254,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                                 remaining_words
                                                                 - 1);
                                                ses->serverNOS =
-                                                   kcalloc(1, 2 * (len + 1),
+                                                   kzalloc(2 * (len + 1),
                                                            GFP_KERNEL);
                                                cifs_strfromUCS_le(ses->serverNOS,
                                                                   (wchar_t *)bcc_ptr,
@@ -2267,7 +2267,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                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) */
-                                                       ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
+                                                       ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL);
                                                        cifs_strfromUCS_le(ses->serverDomain,
                                                             (wchar_t *)bcc_ptr, 
                                  len,
@@ -2278,10 +2278,10 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                } /* else no more room so create dummy domain string */
                                                else
                                                        ses->serverDomain =
-                                                           kcalloc(1, 2,GFP_KERNEL);
+                                                           kzalloc(2,GFP_KERNEL);
                                        } else {        /* no room so create dummy domain and NOS string */
-                                               ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
-                                               ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
+                                               ses->serverDomain = kzalloc(2, GFP_KERNEL);
+                                               ses->serverNOS = kzalloc(2, GFP_KERNEL);
                                        }
                                } else {        /* ASCII */
 
@@ -2289,7 +2289,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        if (((long) bcc_ptr + len) - (long)
                                            pByteArea(smb_buffer_response)
                                            <= BCC(smb_buffer_response)) {
-                                               ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
+                                               ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
                                                strncpy(ses->serverOS, bcc_ptr, len);
 
                                                bcc_ptr += len;
@@ -2297,14 +2297,14 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
+                                               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);
-                                               ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
+                                               ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
                                                strncpy(ses->serverDomain, bcc_ptr, len);
                                                bcc_ptr += len;
                                                bcc_ptr[0] = 0;
@@ -2554,7 +2554,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
    the end since (at least) WIN2K and Windows XP have a major bug in not null
    terminating last Unicode string in response  */
                                        ses->serverOS =
-                                           kcalloc(1, 2 * (len + 1), GFP_KERNEL);
+                                           kzalloc(2 * (len + 1), GFP_KERNEL);
                                        cifs_strfromUCS_le(ses->serverOS,
                                                           (wchar_t *)
                                                           bcc_ptr, len,
@@ -2569,7 +2569,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                                 remaining_words
                                                                 - 1);
                                                ses->serverNOS =
-                                                   kcalloc(1, 2 * (len + 1),
+                                                   kzalloc(2 * (len + 1),
                                                            GFP_KERNEL);
                                                cifs_strfromUCS_le(ses->
                                                                   serverNOS,
@@ -2586,7 +2586,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                        len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
            /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
                                                        ses->serverDomain =
-                                                           kcalloc(1, 2 *
+                                                           kzalloc(2 *
                                                                    (len +
                                                                     1),
                                                                    GFP_KERNEL);
@@ -2612,13 +2612,13 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                } /* else no more room so create dummy domain string */
                                                else
                                                        ses->serverDomain =
-                                                           kcalloc(1, 2,
+                                                           kzalloc(2,
                                                                    GFP_KERNEL);
                                        } else {        /* no room so create dummy domain and NOS string */
                                                ses->serverDomain =
-                                                   kcalloc(1, 2, GFP_KERNEL);
+                                                   kzalloc(2, GFP_KERNEL);
                                                ses->serverNOS =
-                                                   kcalloc(1, 2, GFP_KERNEL);
+                                                   kzalloc(2, GFP_KERNEL);
                                        }
                                } else {        /* ASCII */
                                        len = strnlen(bcc_ptr, 1024);
@@ -2626,7 +2626,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                            pByteArea(smb_buffer_response)
                                            <= BCC(smb_buffer_response)) {
                                                ses->serverOS =
-                                                   kcalloc(1, len + 1,
+                                                   kzalloc(len + 1,
                                                            GFP_KERNEL);
                                                strncpy(ses->serverOS,
                                                        bcc_ptr, len);
@@ -2637,7 +2637,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
 
                                                len = strnlen(bcc_ptr, 1024);
                                                ses->serverNOS =
-                                                   kcalloc(1, len + 1,
+                                                   kzalloc(len + 1,
                                                            GFP_KERNEL);
                                                strncpy(ses->serverNOS, bcc_ptr, len);
                                                bcc_ptr += len;
@@ -2646,7 +2646,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
 
                                                len = strnlen(bcc_ptr, 1024);
                                                ses->serverDomain =
-                                                   kcalloc(1, len + 1,
+                                                   kzalloc(len + 1,
                                                            GFP_KERNEL);
                                                strncpy(ses->serverDomain, bcc_ptr, len);       
                                                bcc_ptr += len;
@@ -2948,7 +2948,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
   the end since (at least) WIN2K and Windows XP have a major bug in not null
   terminating last Unicode string in response  */
                                        ses->serverOS =
-                                           kcalloc(1, 2 * (len + 1), GFP_KERNEL);
+                                           kzalloc(2 * (len + 1), GFP_KERNEL);
                                        cifs_strfromUCS_le(ses->serverOS,
                                                           (wchar_t *)
                                                           bcc_ptr, len,
@@ -2963,7 +2963,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                                 remaining_words
                                                                 - 1);
                                                ses->serverNOS =
-                                                   kcalloc(1, 2 * (len + 1),
+                                                   kzalloc(2 * (len + 1),
                                                            GFP_KERNEL);
                                                cifs_strfromUCS_le(ses->
                                                                   serverNOS,
@@ -2979,7 +2979,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                        len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
      /* last string not always null terminated (e.g. for Windows XP & 2000) */
                                                        ses->serverDomain =
-                                                           kcalloc(1, 2 *
+                                                           kzalloc(2 *
                                                                    (len +
                                                                     1),
                                                                    GFP_KERNEL);
@@ -3004,17 +3004,17 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                            = 0;
                                                } /* else no more room so create dummy domain string */
                                                else
-                                                       ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
+                                                       ses->serverDomain = kzalloc(2,GFP_KERNEL);
                                        } else {  /* no room so create dummy domain and NOS string */
-                                               ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
-                                               ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
+                                               ses->serverDomain = kzalloc(2, GFP_KERNEL);
+                                               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)) {
-                                               ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
+                                               ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
                                                strncpy(ses->serverOS,bcc_ptr, len);
 
                                                bcc_ptr += len;
@@ -3022,14 +3022,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
+                                               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);
-                                               ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
+                                               ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
                                                strncpy(ses->serverDomain, bcc_ptr, len);
                                                bcc_ptr += len;
                                                bcc_ptr[0] = 0;
@@ -3141,7 +3141,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                                if(tcon->nativeFileSystem)
                                        kfree(tcon->nativeFileSystem);
                                tcon->nativeFileSystem =
-                                   kcalloc(1, length + 2, GFP_KERNEL);
+                                   kzalloc(length + 2, GFP_KERNEL);
                                cifs_strfromUCS_le(tcon->nativeFileSystem,
                                                   (wchar_t *) bcc_ptr,
                                                   length, nls_codepage);
@@ -3159,7 +3159,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                                if(tcon->nativeFileSystem)
                                        kfree(tcon->nativeFileSystem);
                                tcon->nativeFileSystem =
-                                   kcalloc(1, length + 1, GFP_KERNEL);
+                                   kzalloc(length + 1, GFP_KERNEL);
                                strncpy(tcon->nativeFileSystem, bcc_ptr,
                                        length);
                        }
index 3f3538d4a1fad105c0a776ef5f6d6e18fef0ff6c..d335269bd91cfe5b626aba8a45eae25136b450dc 100644 (file)
@@ -145,24 +145,23 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                return -ENOMEM;
        }
 
-       if(nd) {
-               if ((nd->intent.open.flags & O_ACCMODE) == O_RDONLY)
-                       desiredAccess = GENERIC_READ;
-               else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY) {
-                       desiredAccess = GENERIC_WRITE;
-                       write_only = TRUE;
-               } else if ((nd->intent.open.flags & O_ACCMODE) == O_RDWR) {
-                       /* GENERIC_ALL is too much permission to request */
-                       /* can cause unnecessary access denied on create */
-                       /* desiredAccess = GENERIC_ALL; */
-                       desiredAccess = GENERIC_READ | GENERIC_WRITE;
+       if(nd && (nd->flags & LOOKUP_OPEN)) {
+               int oflags = nd->intent.open.flags;
+
+               desiredAccess = 0;
+               if (oflags & FMODE_READ)
+                       desiredAccess |= GENERIC_READ;
+               if (oflags & FMODE_WRITE) {
+                       desiredAccess |= GENERIC_WRITE;
+                       if (!(oflags & FMODE_READ))
+                               write_only = TRUE;
                }
 
-               if((nd->intent.open.flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+               if((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
                        disposition = FILE_CREATE;
-               else if((nd->intent.open.flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
+               else if((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
                        disposition = FILE_OVERWRITE_IF;
-               else if((nd->intent.open.flags & O_CREAT) == O_CREAT)
+               else if((oflags & O_CREAT) == O_CREAT)
                        disposition = FILE_OPEN_IF;
                else {
                        cFYI(1,("Create flag not set in create function"));
index 6b06b6bae35e52cd078efaaabe19198007a4b36d..8c665705c6a07beea9a4ead55a2184524f7ed41f 100644 (file)
@@ -310,96 +310,6 @@ static int __init init_sys32_ioctl(void)
 
 __initcall(init_sys32_ioctl);
 
-int register_ioctl32_conversion(unsigned int cmd,
-                               ioctl_trans_handler_t handler)
-{
-       struct ioctl_trans *t;
-       struct ioctl_trans *new_t;
-       unsigned long hash = ioctl32_hash(cmd);
-
-       new_t = kmalloc(sizeof(*new_t), GFP_KERNEL);
-       if (!new_t)
-               return -ENOMEM;
-
-       down_write(&ioctl32_sem);
-       for (t = ioctl32_hash_table[hash]; t; t = t->next) {
-               if (t->cmd == cmd) {
-                       printk(KERN_ERR "Trying to register duplicated ioctl32 "
-                                       "handler %x\n", cmd);
-                       up_write(&ioctl32_sem);
-                       kfree(new_t);
-                       return -EINVAL; 
-               }
-       }
-       new_t->next = NULL;
-       new_t->cmd = cmd;
-       new_t->handler = handler;
-       ioctl32_insert_translation(new_t);
-
-       up_write(&ioctl32_sem);
-       return 0;
-}
-EXPORT_SYMBOL(register_ioctl32_conversion);
-
-static inline int builtin_ioctl(struct ioctl_trans *t)
-{ 
-       return t >= ioctl_start && t < (ioctl_start + ioctl_table_size);
-} 
-
-/* Problem: 
-   This function cannot unregister duplicate ioctls, because they are not
-   unique.
-   When they happen we need to extend the prototype to pass the handler too. */
-
-int unregister_ioctl32_conversion(unsigned int cmd)
-{
-       unsigned long hash = ioctl32_hash(cmd);
-       struct ioctl_trans *t, *t1;
-
-       down_write(&ioctl32_sem);
-
-       t = ioctl32_hash_table[hash];
-       if (!t) { 
-               up_write(&ioctl32_sem);
-               return -EINVAL;
-       } 
-
-       if (t->cmd == cmd) { 
-               if (builtin_ioctl(t)) {
-                       printk("%p tried to unregister builtin ioctl %x\n",
-                              __builtin_return_address(0), cmd);
-               } else { 
-                       ioctl32_hash_table[hash] = t->next;
-                       up_write(&ioctl32_sem);
-                       kfree(t);
-                       return 0;
-               }
-       } 
-       while (t->next) {
-               t1 = t->next;
-               if (t1->cmd == cmd) { 
-                       if (builtin_ioctl(t1)) {
-                               printk("%p tried to unregister builtin "
-                                       "ioctl %x\n",
-                                       __builtin_return_address(0), cmd);
-                               goto out;
-                       } else { 
-                               t->next = t1->next;
-                               up_write(&ioctl32_sem);
-                               kfree(t1);
-                               return 0;
-                       }
-               }
-               t = t1;
-       }
-       printk(KERN_ERR "Trying to free unknown 32bit ioctl handler %x\n",
-                               cmd);
-out:
-       up_write(&ioctl32_sem);
-       return -EINVAL;
-}
-EXPORT_SYMBOL(unregister_ioctl32_conversion); 
-
 static void compat_ioctl_error(struct file *filp, unsigned int fd,
                unsigned int cmd, unsigned long arg)
 {
@@ -720,14 +630,14 @@ compat_sys_io_submit(aio_context_t ctx_id, int nr, u32 __user *iocb)
 struct compat_ncp_mount_data {
        compat_int_t version;
        compat_uint_t ncp_fd;
-       compat_uid_t mounted_uid;
+       __compat_uid_t mounted_uid;
        compat_pid_t wdog_pid;
        unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
        compat_uint_t time_out;
        compat_uint_t retry_count;
        compat_uint_t flags;
-       compat_uid_t uid;
-       compat_gid_t gid;
+       __compat_uid_t uid;
+       __compat_gid_t gid;
        compat_mode_t file_mode;
        compat_mode_t dir_mode;
 };
@@ -784,9 +694,9 @@ static void *do_ncp_super_data_conv(void *raw_data)
 
 struct compat_smb_mount_data {
        compat_int_t version;
-       compat_uid_t mounted_uid;
-       compat_uid_t uid;
-       compat_gid_t gid;
+       __compat_uid_t mounted_uid;
+       __compat_uid_t uid;
+       __compat_gid_t gid;
        compat_mode_t file_mode;
        compat_mode_t dir_mode;
 };
@@ -1364,6 +1274,16 @@ out:
        return ret;
 }
 
+/*
+ * Exactly like fs/open.c:sys_open(), except that it doesn't set the
+ * O_LARGEFILE flag.
+ */
+asmlinkage long
+compat_sys_open(const char __user *filename, int flags, int mode)
+{
+       return do_sys_open(filename, flags, mode);
+}
+
 /*
  * compat_count() counts the number of arguments/envelopes. It is basically
  * a copy of count() from fs/exec.c, except that it works with 32 bit argv
@@ -1808,8 +1728,8 @@ struct compat_nfsctl_export {
        compat_dev_t    ex32_dev;
        compat_ino_t    ex32_ino;
        compat_int_t    ex32_flags;
-       compat_uid_t    ex32_anon_uid;
-       compat_gid_t    ex32_anon_gid;
+       __compat_uid_t  ex32_anon_uid;
+       __compat_gid_t  ex32_anon_gid;
 };
 
 struct compat_nfsctl_fdparm {
index 6c285efa20043cb8dbb4692d7a53f5ff9455bac0..7fe85415ae7c2d7aa7788bb91f5ccb4d412b0612 100644 (file)
@@ -39,12 +39,47 @@ static DECLARE_MUTEX(read_mutex);
 #define CRAMINO(x)     ((x)->offset?(x)->offset<<2:1)
 #define OFFSET(x)      ((x)->i_ino)
 
-static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inode * cramfs_inode)
+
+static int cramfs_iget5_test(struct inode *inode, void *opaque)
+{
+       struct cramfs_inode *cramfs_inode = opaque;
+
+       if (inode->i_ino != CRAMINO(cramfs_inode))
+               return 0; /* does not match */
+
+       if (inode->i_ino != 1)
+               return 1;
+
+       /* all empty directories, char, block, pipe, and sock, share inode #1 */
+
+       if ((inode->i_mode != cramfs_inode->mode) ||
+           (inode->i_gid != cramfs_inode->gid) ||
+           (inode->i_uid != cramfs_inode->uid))
+               return 0; /* does not match */
+
+       if ((S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) &&
+           (inode->i_rdev != old_decode_dev(cramfs_inode->size)))
+               return 0; /* does not match */
+
+       return 1; /* matches */
+}
+
+static int cramfs_iget5_set(struct inode *inode, void *opaque)
+{
+       struct cramfs_inode *cramfs_inode = opaque;
+       inode->i_ino = CRAMINO(cramfs_inode);
+       return 0;
+}
+
+static struct inode *get_cramfs_inode(struct super_block *sb,
+                               struct cramfs_inode * cramfs_inode)
 {
-       struct inode * inode = new_inode(sb);
+       struct inode *inode = iget5_locked(sb, CRAMINO(cramfs_inode),
+                                           cramfs_iget5_test, cramfs_iget5_set,
+                                           cramfs_inode);
        static struct timespec zerotime;
 
-       if (inode) {
+       if (inode && (inode->i_state & I_NEW)) {
                inode->i_mode = cramfs_inode->mode;
                inode->i_uid = cramfs_inode->uid;
                inode->i_size = cramfs_inode->size;
@@ -58,7 +93,6 @@ static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inod
                   but it's the best we can do without reading the directory
                   contents.  1 yields the right result in GNU find, even
                   without -noleaf option. */
-               insert_inode_hash(inode);
                if (S_ISREG(inode->i_mode)) {
                        inode->i_fop = &generic_ro_fops;
                        inode->i_data.a_ops = &cramfs_aops;
@@ -74,6 +108,7 @@ static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inod
                        init_special_inode(inode, inode->i_mode,
                                old_decode_dev(cramfs_inode->size));
                }
+               unlock_new_inode(inode);
        }
        return inode;
 }
index 5800df2e50c8e6b922a7ee7c326dc83b7e209b7b..236696efcbac7b9564ce4d8c9557f6c86226ca3a 100644 (file)
@@ -5,4 +5,3 @@
 obj-$(CONFIG_UNIX98_PTYS)              += devpts.o
 
 devpts-$(CONFIG_UNIX98_PTYS)           := inode.o
-devpts-$(CONFIG_DEVPTS_FS_SECURITY)    += xattr_security.o
index 1571c8d6c2322368ef0a8d57e753a3944c2390cf..f2be44d4491ffcf978e2e12e09484735360e9ebd 100644 (file)
 #include <linux/mount.h>
 #include <linux/tty.h>
 #include <linux/devpts_fs.h>
-#include <linux/xattr.h>
 
 #define DEVPTS_SUPER_MAGIC 0x1cd1
 
-extern struct xattr_handler devpts_xattr_security_handler;
-
-static struct xattr_handler *devpts_xattr_handlers[] = {
-#ifdef CONFIG_DEVPTS_FS_SECURITY
-       &devpts_xattr_security_handler,
-#endif
-       NULL
-};
-
-static struct inode_operations devpts_file_inode_operations = {
-#ifdef CONFIG_DEVPTS_FS_XATTR
-       .setxattr       = generic_setxattr,
-       .getxattr       = generic_getxattr,
-       .listxattr      = generic_listxattr,
-       .removexattr    = generic_removexattr,
-#endif
-};
-
 static struct vfsmount *devpts_mnt;
 static struct dentry *devpts_root;
 
@@ -102,7 +83,6 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
        s->s_blocksize_bits = 10;
        s->s_magic = DEVPTS_SUPER_MAGIC;
        s->s_op = &devpts_sops;
-       s->s_xattr = devpts_xattr_handlers;
        s->s_time_gran = 1;
 
        inode = new_inode(s);
@@ -175,7 +155,6 @@ int devpts_pty_new(struct tty_struct *tty)
        inode->i_gid = config.setgid ? config.gid : current->fsgid;
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        init_special_inode(inode, S_IFCHR|config.mode, device);
-       inode->i_op = &devpts_file_inode_operations;
        inode->u.generic_ip = tty;
 
        dentry = get_node(number);
diff --git a/fs/devpts/xattr_security.c b/fs/devpts/xattr_security.c
deleted file mode 100644 (file)
index 864cb5c..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Security xattr support for devpts.
- *
- * Author: Stephen Smalley <sds@epoch.ncsc.mil>
- * Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- */
-#include <linux/string.h>
-#include <linux/fs.h>
-#include <linux/security.h>
-#include <linux/xattr.h>
-
-static size_t
-devpts_xattr_security_list(struct inode *inode, char *list, size_t list_len,
-                          const char *name, size_t name_len)
-{
-       return security_inode_listsecurity(inode, list, list_len);
-}
-
-static int
-devpts_xattr_security_get(struct inode *inode, const char *name,
-                         void *buffer, size_t size)
-{
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
-       return security_inode_getsecurity(inode, name, buffer, size);
-}
-
-static int
-devpts_xattr_security_set(struct inode *inode, const char *name,
-                         const void *value, size_t size, int flags)
-{
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
-       return security_inode_setsecurity(inode, name, value, size, flags);
-}
-
-struct xattr_handler devpts_xattr_security_handler = {
-       .prefix = XATTR_SECURITY_PREFIX,
-       .list   = devpts_xattr_security_list,
-       .get    = devpts_xattr_security_get,
-       .set    = devpts_xattr_security_set,
-};
index dcfe331dc4c4816d8a208ecccf625439c94cc8cc..3c0c7c6a5b44004cd02de7dae02343b6674ed672 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
@@ -27,6 +28,8 @@
 #include <linux/buffer_head.h>
 #include <linux/smp_lock.h>
 #include <linux/vfs.h>
+#include <linux/seq_file.h>
+#include <linux/mount.h>
 #include <asm/uaccess.h>
 #include "ext2.h"
 #include "xattr.h"
@@ -201,6 +204,26 @@ static void ext2_clear_inode(struct inode *inode)
 #endif
 }
 
+static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs)
+{
+       struct ext2_sb_info *sbi = EXT2_SB(vfs->mnt_sb);
+
+       if (sbi->s_mount_opt & EXT2_MOUNT_GRPID)
+               seq_puts(seq, ",grpid");
+       else
+               seq_puts(seq, ",nogrpid");
+
+#if defined(CONFIG_QUOTA)
+       if (sbi->s_mount_opt & EXT2_MOUNT_USRQUOTA)
+               seq_puts(seq, ",usrquota");
+
+       if (sbi->s_mount_opt & EXT2_MOUNT_GRPQUOTA)
+               seq_puts(seq, ",grpquota");
+#endif
+
+       return 0;
+}
+
 #ifdef CONFIG_QUOTA
 static ssize_t ext2_quota_read(struct super_block *sb, int type, char *data, size_t len, loff_t off);
 static ssize_t ext2_quota_write(struct super_block *sb, int type, const char *data, size_t len, loff_t off);
@@ -218,6 +241,7 @@ static struct super_operations ext2_sops = {
        .statfs         = ext2_statfs,
        .remount_fs     = ext2_remount,
        .clear_inode    = ext2_clear_inode,
+       .show_options   = ext2_show_options,
 #ifdef CONFIG_QUOTA
        .quota_read     = ext2_quota_read,
        .quota_write    = ext2_quota_write,
@@ -256,10 +280,11 @@ static unsigned long get_sb_block(void **data)
 
 enum {
        Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
-       Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
-       Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh,
-       Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_xip,
-       Opt_ignore, Opt_err,
+       Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic,
+       Opt_err_ro, Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug,
+       Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr,
+       Opt_acl, Opt_noacl, Opt_xip, Opt_ignore, Opt_err, Opt_quota,
+       Opt_usrquota, Opt_grpquota
 };
 
 static match_table_t tokens = {
@@ -288,10 +313,10 @@ static match_table_t tokens = {
        {Opt_acl, "acl"},
        {Opt_noacl, "noacl"},
        {Opt_xip, "xip"},
-       {Opt_ignore, "grpquota"},
+       {Opt_grpquota, "grpquota"},
        {Opt_ignore, "noquota"},
-       {Opt_ignore, "quota"},
-       {Opt_ignore, "usrquota"},
+       {Opt_quota, "quota"},
+       {Opt_usrquota, "usrquota"},
        {Opt_err, NULL}
 };
 
@@ -406,6 +431,26 @@ static int parse_options (char * options,
                        printk("EXT2 xip option not supported\n");
 #endif
                        break;
+
+#if defined(CONFIG_QUOTA)
+               case Opt_quota:
+               case Opt_usrquota:
+                       set_opt(sbi->s_mount_opt, USRQUOTA);
+                       break;
+
+               case Opt_grpquota:
+                       set_opt(sbi->s_mount_opt, GRPQUOTA);
+                       break;
+#else
+               case Opt_quota:
+               case Opt_usrquota:
+               case Opt_grpquota:
+                       printk(KERN_ERR
+                               "EXT2-fs: quota operations not supported.\n");
+
+                       break;
+#endif
+
                case Opt_ignore:
                        break;
                default:
index 3c3c6e399fb3df167e7d45936df8e290227d0262..a93c3609025de91984e1673610c0dcc74adfaad0 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/mount.h>
 #include <linux/namei.h>
 #include <linux/quotaops.h>
+#include <linux/seq_file.h>
 #include <asm/uaccess.h>
 #include "xattr.h"
 #include "acl.h"
@@ -509,8 +510,41 @@ static void ext3_clear_inode(struct inode *inode)
        kfree(rsv);
 }
 
-#ifdef CONFIG_QUOTA
+static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs)
+{
+       struct ext3_sb_info *sbi = EXT3_SB(vfs->mnt_sb);
+
+       if (sbi->s_mount_opt & EXT3_MOUNT_JOURNAL_DATA)
+               seq_puts(seq, ",data=journal");
+
+       if (sbi->s_mount_opt & EXT3_MOUNT_ORDERED_DATA)
+               seq_puts(seq, ",data=ordered");
+
+       if (sbi->s_mount_opt & EXT3_MOUNT_WRITEBACK_DATA)
+               seq_puts(seq, ",data=writeback");
+
+#if defined(CONFIG_QUOTA)
+       if (sbi->s_jquota_fmt)
+               seq_printf(seq, ",jqfmt=%s",
+               (sbi->s_jquota_fmt == QFMT_VFS_OLD) ? "vfsold": "vfsv0");
+
+       if (sbi->s_qf_names[USRQUOTA])
+               seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]);
+
+       if (sbi->s_qf_names[GRPQUOTA])
+               seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]);
 
+       if (sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA)
+               seq_puts(seq, ",usrquota");
+
+       if (sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA)
+               seq_puts(seq, ",grpquota");
+#endif
+
+       return 0;
+}
+
+#ifdef CONFIG_QUOTA
 #define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group")
 #define QTYPE2MOPT(on, t) ((t)==USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA))
 
@@ -569,6 +603,7 @@ static struct super_operations ext3_sops = {
        .statfs         = ext3_statfs,
        .remount_fs     = ext3_remount,
        .clear_inode    = ext3_clear_inode,
+       .show_options   = ext3_show_options,
 #ifdef CONFIG_QUOTA
        .quota_read     = ext3_quota_read,
        .quota_write    = ext3_quota_write,
@@ -590,7 +625,8 @@ enum {
        Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
        Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
        Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
-       Opt_ignore, Opt_barrier, Opt_err, Opt_resize,
+       Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
+       Opt_grpquota
 };
 
 static match_table_t tokens = {
@@ -634,10 +670,10 @@ static match_table_t tokens = {
        {Opt_grpjquota, "grpjquota=%s"},
        {Opt_jqfmt_vfsold, "jqfmt=vfsold"},
        {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
-       {Opt_quota, "grpquota"},
+       {Opt_grpquota, "grpquota"},
        {Opt_noquota, "noquota"},
        {Opt_quota, "quota"},
-       {Opt_quota, "usrquota"},
+       {Opt_usrquota, "usrquota"},
        {Opt_barrier, "barrier=%u"},
        {Opt_err, NULL},
        {Opt_resize, "resize"},
@@ -903,7 +939,13 @@ clear_qf_name:
                        sbi->s_jquota_fmt = QFMT_VFS_V0;
                        break;
                case Opt_quota:
+               case Opt_usrquota:
                        set_opt(sbi->s_mount_opt, QUOTA);
+                       set_opt(sbi->s_mount_opt, USRQUOTA);
+                       break;
+               case Opt_grpquota:
+                       set_opt(sbi->s_mount_opt, QUOTA);
+                       set_opt(sbi->s_mount_opt, GRPQUOTA);
                        break;
                case Opt_noquota:
                        if (sb_any_quota_enabled(sb)) {
@@ -912,8 +954,13 @@ clear_qf_name:
                                return 0;
                        }
                        clear_opt(sbi->s_mount_opt, QUOTA);
+                       clear_opt(sbi->s_mount_opt, USRQUOTA);
+                       clear_opt(sbi->s_mount_opt, GRPQUOTA);
                        break;
 #else
+               case Opt_quota:
+               case Opt_usrquota:
+               case Opt_grpquota:
                case Opt_usrjquota:
                case Opt_grpjquota:
                case Opt_offusrjquota:
@@ -924,7 +971,6 @@ clear_qf_name:
                                "EXT3-fs: journalled quota options not "
                                "supported.\n");
                        break;
-               case Opt_quota:
                case Opt_noquota:
                        break;
 #endif
@@ -962,14 +1008,38 @@ clear_qf_name:
                }
        }
 #ifdef CONFIG_QUOTA
-       if (!sbi->s_jquota_fmt && (sbi->s_qf_names[USRQUOTA] ||
-           sbi->s_qf_names[GRPQUOTA])) {
-               printk(KERN_ERR
-                       "EXT3-fs: journalled quota format not specified.\n");
-               return 0;
+       if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
+               if ((sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA) &&
+                    sbi->s_qf_names[USRQUOTA])
+                       clear_opt(sbi->s_mount_opt, USRQUOTA);
+
+               if ((sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA) &&
+                    sbi->s_qf_names[GRPQUOTA])
+                       clear_opt(sbi->s_mount_opt, GRPQUOTA);
+
+               if ((sbi->s_qf_names[USRQUOTA] &&
+                               (sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA)) ||
+                   (sbi->s_qf_names[GRPQUOTA] &&
+                               (sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA))) {
+                       printk(KERN_ERR "EXT3-fs: old and new quota "
+                                       "format mixing.\n");
+                       return 0;
+               }
+
+               if (!sbi->s_jquota_fmt) {
+                       printk(KERN_ERR "EXT3-fs: journalled quota format "
+                                       "not specified.\n");
+                       return 0;
+               }
+       } else {
+               if (sbi->s_jquota_fmt) {
+                       printk(KERN_ERR "EXT3-fs: journalled quota format "
+                                       "specified with no journalling "
+                                       "enabled.\n");
+                       return 0;
+               }
        }
 #endif
-
        return 1;
 }
 
index e5ae1b720dde8b42321235bbb2b3369e017e9d27..895049b2ac9cb65fd58af857e719bc7d8d03115e 100644 (file)
@@ -30,6 +30,29 @@ static inline loff_t fat_make_i_pos(struct super_block *sb,
                | (de - (struct msdos_dir_entry *)bh->b_data);
 }
 
+static inline void fat_dir_readahead(struct inode *dir, sector_t iblock,
+                                    sector_t phys)
+{
+       struct super_block *sb = dir->i_sb;
+       struct msdos_sb_info *sbi = MSDOS_SB(sb);
+       struct buffer_head *bh;
+       int sec;
+
+       /* This is not a first sector of cluster, or sec_per_clus == 1 */
+       if ((iblock & (sbi->sec_per_clus - 1)) || sbi->sec_per_clus == 1)
+               return;
+       /* root dir of FAT12/FAT16 */
+       if ((sbi->fat_bits != 32) && (dir->i_ino == MSDOS_ROOT_INO))
+               return;
+
+       bh = sb_getblk(sb, phys);
+       if (bh && !buffer_uptodate(bh)) {
+               for (sec = 0; sec < sbi->sec_per_clus; sec++)
+                       sb_breadahead(sb, phys + sec);
+       }
+       brelse(bh);
+}
+
 /* Returns the inode number of the directory entry at offset pos. If bh is
    non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
    returned in bh.
@@ -58,6 +81,8 @@ next:
        if (err || !phys)
                return -1;      /* beyond EOF or error */
 
+       fat_dir_readahead(dir, iblock, phys);
+
        *bh = sb_bread(sb, phys);
        if (*bh == NULL) {
                printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n",
@@ -635,8 +660,7 @@ RecEnd:
 EODir:
        filp->f_pos = cpos;
 FillFailed:
-       if (bh)
-               brelse(bh);
+       brelse(bh);
        if (unicode)
                free_page((unsigned long)unicode);
 out:
index 1d3de78e6bc960ddeb2b4b42eed7815c64aca298..43e9e1737de2cb365c954afeddfb64ae0433779b 100644 (file)
@@ -89,7 +89,6 @@ struct file *get_empty_filp(void)
        rwlock_init(&f->f_owner.lock);
        /* f->f_version: 0 */
        INIT_LIST_HEAD(&f->f_list);
-       f->f_maxcount = INT_MAX;
        return f;
 
 over:
index 27f66d3e8a0413091ab58b3f0b85fae788a224fe..6aa6fbe4f8ee9a5397408d59938140e38fa4c084 100644 (file)
@@ -155,7 +155,7 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
 
        sbp->s_flags |= MS_RDONLY;
 
-       infp = kcalloc(1, sizeof(*infp), GFP_KERNEL);
+       infp = kzalloc(sizeof(*infp), GFP_KERNEL);
        if (!infp) {
                printk(KERN_WARNING "vxfs: unable to allocate incore superblock\n");
                return -ENOMEM;
index a096c5a5666442530eeb208baa4069122511c11d..3d5cdc6847c06f4200b93804710804541a909f67 100644 (file)
@@ -13,8 +13,6 @@
 
 #include "btree.h"
 
-#define REF_PAGES      0
-
 void hfs_bnode_read(struct hfs_bnode *node, void *buf,
                int off, int len)
 {
@@ -289,9 +287,7 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
                        page_cache_release(page);
                        goto fail;
                }
-#if !REF_PAGES
                page_cache_release(page);
-#endif
                node->page[i] = page;
        }
 
@@ -449,13 +445,6 @@ void hfs_bnode_get(struct hfs_bnode *node)
 {
        if (node) {
                atomic_inc(&node->refcnt);
-#if REF_PAGES
-               {
-               int i;
-               for (i = 0; i < node->tree->pages_per_bnode; i++)
-                       get_page(node->page[i]);
-               }
-#endif
                dprint(DBG_BNODE_REFS, "get_node(%d:%d): %d\n",
                       node->tree->cnid, node->this, atomic_read(&node->refcnt));
        }
@@ -472,20 +461,12 @@ void hfs_bnode_put(struct hfs_bnode *node)
                       node->tree->cnid, node->this, atomic_read(&node->refcnt));
                if (!atomic_read(&node->refcnt))
                        BUG();
-               if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock)) {
-#if REF_PAGES
-                       for (i = 0; i < tree->pages_per_bnode; i++)
-                               put_page(node->page[i]);
-#endif
+               if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock))
                        return;
-               }
                for (i = 0; i < tree->pages_per_bnode; i++) {
                        if (!node->page[i])
                                continue;
                        mark_page_accessed(node->page[i]);
-#if REF_PAGES
-                       put_page(node->page[i]);
-#endif
                }
 
                if (test_bit(HFS_BNODE_DELETED, &node->flags)) {
index 65dedefcabfc5fd5fb00d129f7569ec40fe1a819..2fcd679f02383366b7f8774ef2ed00d9fe924727 100644 (file)
  *
  * Given the ID of the parent and the name build a search key.
  */
-void hfs_cat_build_key(btree_key *key, u32 parent, struct qstr *name)
+void hfs_cat_build_key(struct super_block *sb, btree_key *key, u32 parent, struct qstr *name)
 {
        key->cat.reserved = 0;
        key->cat.ParID = cpu_to_be32(parent);
        if (name) {
-               hfs_triv2mac(&key->cat.CName, name);
+               hfs_asc2mac(sb, &key->cat.CName, name);
                key->key_len = 6 + key->cat.CName.len;
        } else {
                memset(&key->cat.CName, 0, sizeof(struct hfs_name));
@@ -62,13 +62,14 @@ static int hfs_cat_build_record(hfs_cat_rec *rec, u32 cnid, struct inode *inode)
        }
 }
 
-static int hfs_cat_build_thread(hfs_cat_rec *rec, int type,
+static int hfs_cat_build_thread(struct super_block *sb,
+                               hfs_cat_rec *rec, int type,
                                u32 parentid, struct qstr *name)
 {
        rec->type = type;
        memset(rec->thread.reserved, 0, sizeof(rec->thread.reserved));
        rec->thread.ParID = cpu_to_be32(parentid);
-       hfs_triv2mac(&rec->thread.CName, name);
+       hfs_asc2mac(sb, &rec->thread.CName, name);
        return sizeof(struct hfs_cat_thread);
 }
 
@@ -93,8 +94,8 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode *
        sb = dir->i_sb;
        hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
 
-       hfs_cat_build_key(fd.search_key, cnid, NULL);
-       entry_size = hfs_cat_build_thread(&entry, S_ISDIR(inode->i_mode) ?
+       hfs_cat_build_key(sb, fd.search_key, cnid, NULL);
+       entry_size = hfs_cat_build_thread(sb, &entry, S_ISDIR(inode->i_mode) ?
                        HFS_CDR_THD : HFS_CDR_FTH,
                        dir->i_ino, str);
        err = hfs_brec_find(&fd);
@@ -107,7 +108,7 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode *
        if (err)
                goto err2;
 
-       hfs_cat_build_key(fd.search_key, dir->i_ino, str);
+       hfs_cat_build_key(sb, fd.search_key, dir->i_ino, str);
        entry_size = hfs_cat_build_record(&entry, cnid, inode);
        err = hfs_brec_find(&fd);
        if (err != -ENOENT) {
@@ -127,7 +128,7 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode *
        return 0;
 
 err1:
-       hfs_cat_build_key(fd.search_key, cnid, NULL);
+       hfs_cat_build_key(sb, fd.search_key, cnid, NULL);
        if (!hfs_brec_find(&fd))
                hfs_brec_remove(&fd);
 err2:
@@ -176,7 +177,7 @@ int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
        hfs_cat_rec rec;
        int res, len, type;
 
-       hfs_cat_build_key(fd->search_key, cnid, NULL);
+       hfs_cat_build_key(sb, fd->search_key, cnid, NULL);
        res = hfs_brec_read(fd, &rec, sizeof(rec));
        if (res)
                return res;
@@ -211,7 +212,7 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str)
        sb = dir->i_sb;
        hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
 
-       hfs_cat_build_key(fd.search_key, dir->i_ino, str);
+       hfs_cat_build_key(sb, fd.search_key, dir->i_ino, str);
        res = hfs_brec_find(&fd);
        if (res)
                goto out;
@@ -239,7 +240,7 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str)
        if (res)
                goto out;
 
-       hfs_cat_build_key(fd.search_key, cnid, NULL);
+       hfs_cat_build_key(sb, fd.search_key, cnid, NULL);
        res = hfs_brec_find(&fd);
        if (!res) {
                res = hfs_brec_remove(&fd);
@@ -280,7 +281,7 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name,
        dst_fd = src_fd;
 
        /* find the old dir entry and read the data */
-       hfs_cat_build_key(src_fd.search_key, src_dir->i_ino, src_name);
+       hfs_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
        err = hfs_brec_find(&src_fd);
        if (err)
                goto out;
@@ -289,7 +290,7 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name,
                            src_fd.entrylength);
 
        /* create new dir entry with the data from the old entry */
-       hfs_cat_build_key(dst_fd.search_key, dst_dir->i_ino, dst_name);
+       hfs_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name);
        err = hfs_brec_find(&dst_fd);
        if (err != -ENOENT) {
                if (!err)
@@ -305,7 +306,7 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name,
        mark_inode_dirty(dst_dir);
 
        /* finally remove the old entry */
-       hfs_cat_build_key(src_fd.search_key, src_dir->i_ino, src_name);
+       hfs_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
        err = hfs_brec_find(&src_fd);
        if (err)
                goto out;
@@ -321,7 +322,7 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name,
                goto out;
 
        /* remove old thread entry */
-       hfs_cat_build_key(src_fd.search_key, cnid, NULL);
+       hfs_cat_build_key(sb, src_fd.search_key, cnid, NULL);
        err = hfs_brec_find(&src_fd);
        if (err)
                goto out;
@@ -330,8 +331,8 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name,
                goto out;
 
        /* create new thread entry */
-       hfs_cat_build_key(dst_fd.search_key, cnid, NULL);
-       entry_size = hfs_cat_build_thread(&entry, type == HFS_CDR_FIL ? HFS_CDR_FTH : HFS_CDR_THD,
+       hfs_cat_build_key(sb, dst_fd.search_key, cnid, NULL);
+       entry_size = hfs_cat_build_thread(sb, &entry, type == HFS_CDR_FIL ? HFS_CDR_FTH : HFS_CDR_THD,
                                        dst_dir->i_ino, dst_name);
        err = hfs_brec_find(&dst_fd);
        if (err != -ENOENT) {
index c55998262aed51632eefa6b6a347a5bd511fdd70..e1f24befba58b282b9f2aa7af6a5b4628cf6533d 100644 (file)
@@ -28,7 +28,7 @@ static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry,
        dentry->d_op = &hfs_dentry_operations;
 
        hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd);
-       hfs_cat_build_key(fd.search_key, dir->i_ino, &dentry->d_name);
+       hfs_cat_build_key(dir->i_sb, fd.search_key, dir->i_ino, &dentry->d_name);
        res = hfs_brec_read(&fd, &rec, sizeof(rec));
        if (res) {
                hfs_find_exit(&fd);
@@ -56,7 +56,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        struct inode *inode = filp->f_dentry->d_inode;
        struct super_block *sb = inode->i_sb;
        int len, err;
-       char strbuf[HFS_NAMELEN + 1];
+       char strbuf[HFS_MAX_NAMELEN];
        union hfs_cat_rec entry;
        struct hfs_find_data fd;
        struct hfs_readdir_data *rd;
@@ -66,7 +66,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                return 0;
 
        hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
-       hfs_cat_build_key(fd.search_key, inode->i_ino, NULL);
+       hfs_cat_build_key(sb, fd.search_key, inode->i_ino, NULL);
        err = hfs_brec_find(&fd);
        if (err)
                goto out;
@@ -111,7 +111,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                }
                hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
                type = entry.type;
-               len = hfs_mac2triv(strbuf, &fd.key->cat.CName);
+               len = hfs_mac2asc(sb, strbuf, &fd.key->cat.CName);
                if (type == HFS_CDR_DIR) {
                        if (fd.entrylength < sizeof(struct hfs_cat_dir)) {
                                printk("HFS: small dir entry\n");
@@ -307,7 +307,8 @@ static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                           old_dir, &old_dentry->d_name,
                           new_dir, &new_dentry->d_name);
        if (!res)
-               hfs_cat_build_key((btree_key *)&HFS_I(old_dentry->d_inode)->cat_key,
+               hfs_cat_build_key(old_dir->i_sb,
+                                 (btree_key *)&HFS_I(old_dentry->d_inode)->cat_key,
                                  new_dir->i_ino, &new_dentry->d_name);
        return res;
 }
index df6b33adee3bbd143d0a2873d9e378d44a7419d1..88099ab1a180121449cfc04d7ca3a0d26b9366ef 100644 (file)
@@ -25,6 +25,7 @@
 #define HFS_SECTOR_SIZE                512    /* size of an HFS sector */
 #define HFS_SECTOR_SIZE_BITS   9      /* log_2(HFS_SECTOR_SIZE) */
 #define HFS_NAMELEN            31     /* maximum length of an HFS filename */
+#define HFS_MAX_NAMELEN                128
 #define HFS_MAX_VALENCE                32767U
 
 /* Meanings of the drAtrb field of the MDB,
index 0dc8ef8e14de67e0fc2cd4dd9bf379ceaf26f8ea..aae019aadf8865728c2039deb5b2aba09b4a3517 100644 (file)
@@ -141,6 +141,8 @@ struct hfs_sb_info {
 
        int session, part;
 
+       struct nls_table *nls_io, *nls_disk;
+
        struct semaphore bitmap_lock;
 
        unsigned long flags;
@@ -168,7 +170,7 @@ extern int hfs_cat_create(u32, struct inode *, struct qstr *, struct inode *);
 extern int hfs_cat_delete(u32, struct inode *, struct qstr *);
 extern int hfs_cat_move(u32, struct inode *, struct qstr *,
                        struct inode *, struct qstr *);
-extern void hfs_cat_build_key(btree_key *, u32, struct qstr *);
+extern void hfs_cat_build_key(struct super_block *, btree_key *, u32, struct qstr *);
 
 /* dir.c */
 extern struct file_operations hfs_dir_operations;
@@ -222,8 +224,8 @@ extern int hfs_strcmp(const unsigned char *, unsigned int,
 extern int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
 
 /* trans.c */
-extern void hfs_triv2mac(struct hfs_name *, struct qstr *);
-extern int hfs_mac2triv(char *, const struct hfs_name *);
+extern void hfs_asc2mac(struct super_block *, struct hfs_name *, struct qstr *);
+extern int hfs_mac2asc(struct super_block *, char *, const struct hfs_name *);
 
 extern struct timezone sys_tz;
 
index 75191232609454d67e0e126314c15ef782bdd398..f1570b9f9de30427f133670f02893a67726ed6ed 100644 (file)
@@ -160,7 +160,7 @@ struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, int mode)
 
        init_MUTEX(&HFS_I(inode)->extents_lock);
        INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list);
-       hfs_cat_build_key((btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name);
+       hfs_cat_build_key(sb, (btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name);
        inode->i_ino = HFS_SB(sb)->next_id++;
        inode->i_mode = mode;
        inode->i_uid = current->fsuid;
index 217e32f37e0be7bce323a9962c0cf95adb394b9e..0a473f79c89feb192b71dba3f66a7951536c86f8 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/cdrom.h>
 #include <linux/genhd.h>
+#include <linux/nls.h>
 
 #include "hfs_fs.h"
 #include "btree.h"
@@ -343,6 +344,11 @@ void hfs_mdb_put(struct super_block *sb)
        brelse(HFS_SB(sb)->mdb_bh);
        brelse(HFS_SB(sb)->alt_mdb_bh);
 
+       if (HFS_SB(sb)->nls_io)
+               unload_nls(HFS_SB(sb)->nls_io);
+       if (HFS_SB(sb)->nls_disk)
+               unload_nls(HFS_SB(sb)->nls_disk);
+
        kfree(HFS_SB(sb));
        sb->s_fs_info = NULL;
 }
index ab783f6afa3b08d00c18c564b598f353af07084f..c5074aeafcae7e8bebaf55780e1548692cdad78b 100644 (file)
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/blkdev.h>
+#include <linux/mount.h>
 #include <linux/init.h>
+#include <linux/nls.h>
 #include <linux/parser.h>
+#include <linux/seq_file.h>
 #include <linux/vfs.h>
 
 #include "hfs_fs.h"
@@ -111,6 +114,32 @@ static int hfs_remount(struct super_block *sb, int *flags, char *data)
        return 0;
 }
 
+static int hfs_show_options(struct seq_file *seq, struct vfsmount *mnt)
+{
+       struct hfs_sb_info *sbi = HFS_SB(mnt->mnt_sb);
+
+       if (sbi->s_creator != cpu_to_be32(0x3f3f3f3f))
+               seq_printf(seq, ",creator=%.4s", (char *)&sbi->s_creator);
+       if (sbi->s_type != cpu_to_be32(0x3f3f3f3f))
+               seq_printf(seq, ",type=%.4s", (char *)&sbi->s_type);
+       seq_printf(seq, ",uid=%u,gid=%u", sbi->s_uid, sbi->s_gid);
+       if (sbi->s_file_umask != 0133)
+               seq_printf(seq, ",file_umask=%o", sbi->s_file_umask);
+       if (sbi->s_dir_umask != 0022)
+               seq_printf(seq, ",dir_umask=%o", sbi->s_dir_umask);
+       if (sbi->part >= 0)
+               seq_printf(seq, ",part=%u", sbi->part);
+       if (sbi->session >= 0)
+               seq_printf(seq, ",session=%u", sbi->session);
+       if (sbi->nls_disk)
+               seq_printf(seq, ",codepage=%s", sbi->nls_disk->charset);
+       if (sbi->nls_io)
+               seq_printf(seq, ",iocharset=%s", sbi->nls_io->charset);
+       if (sbi->s_quiet)
+               seq_printf(seq, ",quiet");
+       return 0;
+}
+
 static struct inode *hfs_alloc_inode(struct super_block *sb)
 {
        struct hfs_inode_info *i;
@@ -133,11 +162,13 @@ static struct super_operations hfs_super_operations = {
        .write_super    = hfs_write_super,
        .statfs         = hfs_statfs,
        .remount_fs     = hfs_remount,
+       .show_options   = hfs_show_options,
 };
 
 enum {
        opt_uid, opt_gid, opt_umask, opt_file_umask, opt_dir_umask,
        opt_part, opt_session, opt_type, opt_creator, opt_quiet,
+       opt_codepage, opt_iocharset,
        opt_err
 };
 
@@ -152,6 +183,8 @@ static match_table_t tokens = {
        { opt_type, "type=%s" },
        { opt_creator, "creator=%s" },
        { opt_quiet, "quiet" },
+       { opt_codepage, "codepage=%s" },
+       { opt_iocharset, "iocharset=%s" },
        { opt_err, NULL }
 };
 
@@ -257,11 +290,46 @@ static int parse_options(char *options, struct hfs_sb_info *hsb)
                case opt_quiet:
                        hsb->s_quiet = 1;
                        break;
+               case opt_codepage:
+                       if (hsb->nls_disk) {
+                               printk("HFS+-fs: unable to change codepage\n");
+                               return 0;
+                       }
+                       p = match_strdup(&args[0]);
+                       hsb->nls_disk = load_nls(p);
+                       if (!hsb->nls_disk) {
+                               printk("HFS+-fs: unable to load codepage \"%s\"\n", p);
+                               kfree(p);
+                               return 0;
+                       }
+                       kfree(p);
+                       break;
+               case opt_iocharset:
+                       if (hsb->nls_io) {
+                               printk("HFS: unable to change iocharset\n");
+                               return 0;
+                       }
+                       p = match_strdup(&args[0]);
+                       hsb->nls_io = load_nls(p);
+                       if (!hsb->nls_io) {
+                               printk("HFS: unable to load iocharset \"%s\"\n", p);
+                               kfree(p);
+                               return 0;
+                       }
+                       kfree(p);
+                       break;
                default:
                        return 0;
                }
        }
 
+       if (hsb->nls_disk && !hsb->nls_io) {
+               hsb->nls_io = load_nls_default();
+               if (!hsb->nls_io) {
+                       printk("HFS: unable to load default iocharset\n");
+                       return 0;
+               }
+       }
        hsb->s_dir_umask &= 0777;
        hsb->s_file_umask &= 0577;
 
index fb9720abbadd64ff572f58b4533302247347e50c..e673a88b8ae7560b14796b611aa57b267193411f 100644 (file)
@@ -9,12 +9,15 @@
  * with ':' vs. '/' as the path-element separator.
  */
 
+#include <linux/types.h>
+#include <linux/nls.h>
+
 #include "hfs_fs.h"
 
 /*================ Global functions ================*/
 
 /*
- * hfs_mac2triv()
+ * hfs_mac2asc()
  *
  * Given a 'Pascal String' (a string preceded by a length byte) in
  * the Macintosh character set produce the corresponding filename using
  * by ':' which never appears in HFS filenames.         All other characters
  * are passed unchanged from input to output.
  */
-int hfs_mac2triv(char *out, const struct hfs_name *in)
+int hfs_mac2asc(struct super_block *sb, char *out, const struct hfs_name *in)
 {
-       const char *p;
-       char c;
-       int i, len;
+       struct nls_table *nls_disk = HFS_SB(sb)->nls_disk;
+       struct nls_table *nls_io = HFS_SB(sb)->nls_io;
+       const char *src;
+       char *dst;
+       int srclen, dstlen, size;
+
+       src = in->name;
+       srclen = in->len;
+       dst = out;
+       dstlen = HFS_MAX_NAMELEN;
+       if (nls_io) {
+               wchar_t ch;
 
-       len = in->len;
-       p = in->name;
-       for (i = 0; i < len; i++) {
-               c = *p++;
-               *out++ = c == '/' ? ':' : c;
+               while (srclen > 0) {
+                       if (nls_disk) {
+                               size = nls_disk->char2uni(src, srclen, &ch);
+                               if (size <= 0) {
+                                       ch = '?';
+                                       size = 1;
+                               }
+                               src += size;
+                               srclen -= size;
+                       } else {
+                               ch = *src++;
+                               srclen--;
+                       }
+                       if (ch == '/')
+                               ch = ':';
+                       size = nls_io->uni2char(ch, dst, dstlen);
+                       if (size < 0) {
+                               if (size == -ENAMETOOLONG)
+                                       goto out;
+                               *dst = '?';
+                               size = 1;
+                       }
+                       dst += size;
+                       dstlen -= size;
+               }
+       } else {
+               char ch;
+
+               while (--srclen >= 0)
+                       *dst++ = (ch = *src++) == '/' ? ':' : ch;
        }
-       return i;
+out:
+       return dst - out;
 }
 
 /*
- * hfs_triv2mac()
+ * hfs_asc2mac()
  *
  * Given an ASCII string (not null-terminated) and its length,
  * generate the corresponding filename in the Macintosh character set
@@ -54,19 +92,57 @@ int hfs_mac2triv(char *out, const struct hfs_name *in)
  * This routine is a inverse to hfs_mac2triv().
  * A ':' is replaced by a '/'.
  */
-void hfs_triv2mac(struct hfs_name *out, struct qstr *in)
+void hfs_asc2mac(struct super_block *sb, struct hfs_name *out, struct qstr *in)
 {
+       struct nls_table *nls_disk = HFS_SB(sb)->nls_disk;
+       struct nls_table *nls_io = HFS_SB(sb)->nls_io;
        const char *src;
-       char *dst, c;
-       int i, len;
+       char *dst;
+       int srclen, dstlen, size;
 
-       out->len = len = min((unsigned int)HFS_NAMELEN, in->len);
        src = in->name;
+       srclen = in->len;
        dst = out->name;
-       for (i = 0; i < len; i++) {
-               c = *src++;
-               *dst++ = c == ':' ? '/' : c;
+       dstlen = HFS_NAMELEN;
+       if (nls_io) {
+               wchar_t ch;
+
+               while (srclen > 0) {
+                       size = nls_io->char2uni(src, srclen, &ch);
+                       if (size < 0) {
+                               ch = '?';
+                               size = 1;
+                       }
+                       src += size;
+                       srclen -= size;
+                       if (ch == ':')
+                               ch = '/';
+                       if (nls_disk) {
+                               size = nls_disk->uni2char(ch, dst, dstlen);
+                               if (size < 0) {
+                                       if (size == -ENAMETOOLONG)
+                                               goto out;
+                                       *dst = '?';
+                                       size = 1;
+                               }
+                               dst += size;
+                               dstlen -= size;
+                       } else {
+                               *dst++ = ch > 0xff ? '?' : ch;
+                               dstlen--;
+                       }
+               }
+       } else {
+               char ch;
+
+               if (dstlen > srclen)
+                       dstlen = srclen;
+               while (--dstlen >= 0)
+                       *dst++ = (ch = *src++) == ':' ? '/' : ch;
        }
-       for (; i < HFS_NAMELEN; i++)
+out:
+       out->len = dst - (char *)out->name;
+       dstlen = HFS_NAMELEN - out->len;
+       while (--dstlen >= 0)
                *dst++ = 0;
 }
index 8868d3b766fd46e1c263dfdde6d1688cc1f5cd09..b85abc6e6f83b3c3344ac102521521f7655d5134 100644 (file)
@@ -18,8 +18,6 @@
 #include "hfsplus_fs.h"
 #include "hfsplus_raw.h"
 
-#define REF_PAGES      0
-
 /* Copy a specified range of bytes from the raw data of a node */
 void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len)
 {
@@ -450,9 +448,7 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
                        page_cache_release(page);
                        goto fail;
                }
-#if !REF_PAGES
                page_cache_release(page);
-#endif
                node->page[i] = page;
        }
 
@@ -612,13 +608,6 @@ void hfs_bnode_get(struct hfs_bnode *node)
 {
        if (node) {
                atomic_inc(&node->refcnt);
-#if REF_PAGES
-               {
-               int i;
-               for (i = 0; i < node->tree->pages_per_bnode; i++)
-                       get_page(node->page[i]);
-               }
-#endif
                dprint(DBG_BNODE_REFS, "get_node(%d:%d): %d\n",
                       node->tree->cnid, node->this, atomic_read(&node->refcnt));
        }
@@ -635,20 +624,12 @@ void hfs_bnode_put(struct hfs_bnode *node)
                       node->tree->cnid, node->this, atomic_read(&node->refcnt));
                if (!atomic_read(&node->refcnt))
                        BUG();
-               if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock)) {
-#if REF_PAGES
-                       for (i = 0; i < tree->pages_per_bnode; i++)
-                               put_page(node->page[i]);
-#endif
+               if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock))
                        return;
-               }
                for (i = 0; i < tree->pages_per_bnode; i++) {
                        if (!node->page[i])
                                continue;
                        mark_page_accessed(node->page[i]);
-#if REF_PAGES
-                       put_page(node->page[i]);
-#endif
                }
 
                if (test_bit(HFS_BNODE_DELETED, &node->flags)) {
index 533094a570df3011f032822974669195fd19cd16..2bc0cdd30e5656f3325be27d84b6369f345e6a40 100644 (file)
@@ -343,8 +343,9 @@ ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
 ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size);
 
 /* options.c */
-int parse_options(char *, struct hfsplus_sb_info *);
-void fill_defaults(struct hfsplus_sb_info *);
+int hfsplus_parse_options(char *, struct hfsplus_sb_info *);
+void hfsplus_fill_defaults(struct hfsplus_sb_info *);
+int hfsplus_show_options(struct seq_file *, struct vfsmount *);
 
 /* tables.c */
 extern u16 hfsplus_case_fold_table[];
index 1cca0102c98d30e4c57a3f8097669959e64c9d45..cca0818aa4ca3dbd18fe842e802e38b558fa4d90 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/sched.h>
 #include <linux/parser.h>
 #include <linux/nls.h>
+#include <linux/mount.h>
+#include <linux/seq_file.h>
 #include "hfsplus_fs.h"
 
 enum {
@@ -38,7 +40,7 @@ static match_table_t tokens = {
 };
 
 /* Initialize an options object to reasonable defaults */
-void fill_defaults(struct hfsplus_sb_info *opts)
+void hfsplus_fill_defaults(struct hfsplus_sb_info *opts)
 {
        if (!opts)
                return;
@@ -63,7 +65,7 @@ static inline int match_fourchar(substring_t *arg, u32 *result)
 
 /* Parse options from mount. Returns 0 on failure */
 /* input is the options passed to mount() as a string */
-int parse_options(char *input, struct hfsplus_sb_info *sbi)
+int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
 {
        char *p;
        substring_t args[MAX_OPT_ARGS];
@@ -160,3 +162,23 @@ done:
 
        return 1;
 }
+
+int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt)
+{
+       struct hfsplus_sb_info *sbi = &HFSPLUS_SB(mnt->mnt_sb);
+
+       if (sbi->creator != HFSPLUS_DEF_CR_TYPE)
+               seq_printf(seq, ",creator=%.4s", (char *)&sbi->creator);
+       if (sbi->type != HFSPLUS_DEF_CR_TYPE)
+               seq_printf(seq, ",type=%.4s", (char *)&sbi->type);
+       seq_printf(seq, ",umask=%o,uid=%u,gid=%u", sbi->umask, sbi->uid, sbi->gid);
+       if (sbi->part >= 0)
+               seq_printf(seq, ",part=%u", sbi->part);
+       if (sbi->session >= 0)
+               seq_printf(seq, ",session=%u", sbi->session);
+       if (sbi->nls)
+               seq_printf(seq, ",nls=%s", sbi->nls->charset);
+       if (sbi->flags & HFSPLUS_SB_NODECOMPOSE)
+               seq_printf(seq, ",nodecompose");
+       return 0;
+}
index d55ad67b8e4238e3625f2139b78b353858337657..fd0f0f050e1d5f3643f7b6e7273af4d7ade0448e 100644 (file)
@@ -217,8 +217,7 @@ static void hfsplus_put_super(struct super_block *sb)
                vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_UNMNT);
                vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_INCNSTNT);
                mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh);
-               ll_rw_block(WRITE, 1, &HFSPLUS_SB(sb).s_vhbh);
-               wait_on_buffer(HFSPLUS_SB(sb).s_vhbh);
+               sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh);
        }
 
        hfs_btree_close(HFSPLUS_SB(sb).cat_tree);
@@ -277,6 +276,7 @@ static struct super_operations hfsplus_sops = {
        .write_super    = hfsplus_write_super,
        .statfs         = hfsplus_statfs,
        .remount_fs     = hfsplus_remount,
+       .show_options   = hfsplus_show_options,
 };
 
 static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
@@ -297,8 +297,8 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        memset(sbi, 0, sizeof(HFSPLUS_SB(sb)));
        sb->s_fs_info = sbi;
        INIT_HLIST_HEAD(&sbi->rsrc_inodes);
-       fill_defaults(sbi);
-       if (!parse_options(data, sbi)) {
+       hfsplus_fill_defaults(sbi);
+       if (!hfsplus_parse_options(data, sbi)) {
                if (!silent)
                        printk("HFS+-fs: unable to parse mount options\n");
                err = -EINVAL;
@@ -415,8 +415,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT);
        vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT);
        mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh);
-       ll_rw_block(WRITE, 1, &HFSPLUS_SB(sb).s_vhbh);
-       wait_on_buffer(HFSPLUS_SB(sb).s_vhbh);
+       sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh);
 
        if (!HFSPLUS_SB(sb).hidden_dir) {
                printk("HFS+: create hidden dir...\n");
index 67bca0d4a33ba5977a94c6a3d71b636010ac67a7..cca3fb693f9905e52ab1e6f486091d89ee2650e5 100644 (file)
@@ -49,7 +49,6 @@ struct hostfs_iattr {
        struct timespec ia_atime;
        struct timespec ia_mtime;
        struct timespec ia_ctime;
-       unsigned int    ia_attr_flags;
 };
 
 extern int stat_file(const char *path, unsigned long long *inode_out,
index e57f1724db3e89242afb362dfcda99178a2c4015..71df1b1e8f75a87910357025048b38ba7d382df6 100644 (file)
@@ -1195,9 +1195,6 @@ void update_atime(struct inode *inode)
        if (!timespec_equal(&inode->i_atime, &now)) {
                inode->i_atime = now;
                mark_inode_dirty_sync(inode);
-       } else {
-               if (!timespec_equal(&inode->i_atime, &now))
-                       inode->i_atime = now;
        }
 }
 
index 2e4e2a57708cf95dcdf348235376ef901f4dc295..a37e9fb1da589fa1457929e2079e176220ad34c0 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/ioctls.h>
 
 static atomic_t inotify_cookie;
+static atomic_t inotify_watches;
 
 static kmem_cache_t *watch_cachep;
 static kmem_cache_t *event_cachep;
@@ -422,6 +423,7 @@ static struct inotify_watch *create_watch(struct inotify_device *dev,
        get_inotify_watch(watch);
 
        atomic_inc(&dev->user->inotify_watches);
+       atomic_inc(&inotify_watches);
 
        return watch;
 }
@@ -454,6 +456,7 @@ static void remove_watch_no_event(struct inotify_watch *watch,
        list_del(&watch->d_list);
 
        atomic_dec(&dev->user->inotify_watches);
+       atomic_dec(&inotify_watches);
        idr_remove(&dev->idr, watch->wd);
        put_inotify_watch(watch);
 }
@@ -532,6 +535,9 @@ void inotify_dentry_parent_queue_event(struct dentry *dentry, u32 mask,
        struct dentry *parent;
        struct inode *inode;
 
+       if (!atomic_read (&inotify_watches))
+               return;
+
        spin_lock(&dentry->d_lock);
        parent = dentry->d_parent;
        inode = parent->d_inode;
@@ -925,6 +931,7 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask)
        struct nameidata nd;
        struct file *filp;
        int ret, fput_needed;
+       int mask_add = 0;
 
        filp = fget_light(fd, &fput_needed);
        if (unlikely(!filp))
@@ -947,6 +954,9 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask)
        down(&inode->inotify_sem);
        down(&dev->sem);
 
+       if (mask & IN_MASK_ADD)
+               mask_add = 1;
+
        /* don't let user-space set invalid bits: we don't want flags set */
        mask &= IN_ALL_EVENTS;
        if (unlikely(!mask)) {
@@ -960,7 +970,10 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask)
         */
        old = inode_find_dev(inode, dev);
        if (unlikely(old)) {
-               old->mask = mask;
+               if (mask_add)
+                       old->mask |= mask;
+               else
+                       old->mask = mask;
                ret = old->wd;
                goto out;
        }
@@ -1043,6 +1056,7 @@ static int __init inotify_setup(void)
        inotify_max_user_watches = 8192;
 
        atomic_set(&inotify_cookie, 0);
+       atomic_set(&inotify_watches, 0);
 
        watch_cachep = kmem_cache_create("inotify_watch_cache",
                                         sizeof(struct inotify_watch),
index 5a97e346bd95a247c12f0edcc5b33d1b065d6419..014a51fd00d776d0ded21d1e3eaf6b7cf22ca1ec 100644 (file)
@@ -204,7 +204,7 @@ __flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count)
        int i;
 
        spin_unlock(&journal->j_list_lock);
-       ll_rw_block(WRITE, *batch_count, bhs);
+       ll_rw_block(SWRITE, *batch_count, bhs);
        spin_lock(&journal->j_list_lock);
        for (i = 0; i < *batch_count; i++) {
                struct buffer_head *bh = bhs[i];
index dac720c837abf0475ee41fa56708c5748daf480d..2a3e310f79efa7c3665dd037dd572ca35780677f 100644 (file)
@@ -358,7 +358,7 @@ write_out_data:
                                        jbd_debug(2, "submit %d writes\n",
                                                        bufs);
                                        spin_unlock(&journal->j_list_lock);
-                                       ll_rw_block(WRITE, bufs, wbuf);
+                                       ll_rw_block(SWRITE, bufs, wbuf);
                                        journal_brelse_array(wbuf, bufs);
                                        bufs = 0;
                                        goto write_out_data;
@@ -381,7 +381,7 @@ write_out_data:
 
        if (bufs) {
                spin_unlock(&journal->j_list_lock);
-               ll_rw_block(WRITE, bufs, wbuf);
+               ll_rw_block(SWRITE, bufs, wbuf);
                journal_brelse_array(wbuf, bufs);
                spin_lock(&journal->j_list_lock);
        }
@@ -720,11 +720,17 @@ wait_for_iobuf:
        J_ASSERT(commit_transaction->t_log_list == NULL);
 
 restart_loop:
+       /*
+        * As there are other places (journal_unmap_buffer()) adding buffers
+        * to this list we have to be careful and hold the j_list_lock.
+        */
+       spin_lock(&journal->j_list_lock);
        while (commit_transaction->t_forget) {
                transaction_t *cp_transaction;
                struct buffer_head *bh;
 
                jh = commit_transaction->t_forget;
+               spin_unlock(&journal->j_list_lock);
                bh = jh2bh(jh);
                jbd_lock_bh_state(bh);
                J_ASSERT_JH(jh, jh->b_transaction == commit_transaction ||
@@ -792,9 +798,25 @@ restart_loop:
                        journal_remove_journal_head(bh);  /* needs a brelse */
                        release_buffer_page(bh);
                }
+               cond_resched_lock(&journal->j_list_lock);
+       }
+       spin_unlock(&journal->j_list_lock);
+       /*
+        * This is a bit sleazy.  We borrow j_list_lock to protect
+        * journal->j_committing_transaction in __journal_remove_checkpoint.
+        * Really, __journal_remove_checkpoint should be using j_state_lock but
+        * it's a bit hassle to hold that across __journal_remove_checkpoint
+        */
+       spin_lock(&journal->j_state_lock);
+       spin_lock(&journal->j_list_lock);
+       /*
+        * Now recheck if some buffers did not get attached to the transaction
+        * while the lock was dropped...
+        */
+       if (commit_transaction->t_forget) {
                spin_unlock(&journal->j_list_lock);
-               if (cond_resched())
-                       goto restart_loop;
+               spin_unlock(&journal->j_state_lock);
+               goto restart_loop;
        }
 
        /* Done with this transaction! */
@@ -803,14 +825,6 @@ restart_loop:
 
        J_ASSERT(commit_transaction->t_state == T_COMMIT);
 
-       /*
-        * This is a bit sleazy.  We borrow j_list_lock to protect
-        * journal->j_committing_transaction in __journal_remove_checkpoint.
-        * Really, __jornal_remove_checkpoint should be using j_state_lock but
-        * it's a bit hassle to hold that across __journal_remove_checkpoint
-        */
-       spin_lock(&journal->j_state_lock);
-       spin_lock(&journal->j_list_lock);
        commit_transaction->t_state = T_FINISHED;
        J_ASSERT(commit_transaction == journal->j_committing_transaction);
        journal->j_commit_sequence = commit_transaction->t_tid;
index 5e7b439495171c9d0fcfa7f28b2fa51aab489823..7ae2c4fe506bb5bd7b2ac21c6bbf80795741361d 100644 (file)
@@ -65,7 +65,6 @@ EXPORT_SYMBOL(journal_set_features);
 EXPORT_SYMBOL(journal_create);
 EXPORT_SYMBOL(journal_load);
 EXPORT_SYMBOL(journal_destroy);
-EXPORT_SYMBOL(journal_recover);
 EXPORT_SYMBOL(journal_update_superblock);
 EXPORT_SYMBOL(journal_abort);
 EXPORT_SYMBOL(journal_errno);
@@ -81,6 +80,7 @@ EXPORT_SYMBOL(journal_try_to_free_buffers);
 EXPORT_SYMBOL(journal_force_commit);
 
 static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *);
+static void __journal_abort_soft (journal_t *journal, int errno);
 
 /*
  * Helper function used to manage commit timeouts
@@ -93,16 +93,6 @@ static void commit_timeout(unsigned long __data)
        wake_up_process(p);
 }
 
-/* Static check for data structure consistency.  There's no code
- * invoked --- we'll just get a linker failure if things aren't right.
- */
-void __journal_internal_check(void)
-{
-       extern void journal_bad_superblock_size(void);
-       if (sizeof(struct journal_superblock_s) != 1024)
-               journal_bad_superblock_size();
-}
-
 /*
  * kjournald: The main thread function used to manage a logging device
  * journal.
@@ -119,16 +109,12 @@ void __journal_internal_check(void)
  *    known as checkpointing, and this thread is responsible for that job.
  */
 
-journal_t *current_journal;            // AKPM: debug
-
-int kjournald(void *arg)
+static int kjournald(void *arg)
 {
        journal_t *journal = (journal_t *) arg;
        transaction_t *transaction;
        struct timer_list timer;
 
-       current_journal = journal;
-
        daemonize("kjournald");
 
        /* Set up an interval timer which can be used to trigger a
@@ -193,6 +179,8 @@ loop:
                if (transaction && time_after_eq(jiffies,
                                                transaction->t_expires))
                        should_sleep = 0;
+               if (journal->j_flags & JFS_UNMOUNT)
+                       should_sleep = 0;
                if (should_sleep) {
                        spin_unlock(&journal->j_state_lock);
                        schedule();
@@ -969,7 +957,7 @@ void journal_update_superblock(journal_t *journal, int wait)
        if (wait)
                sync_dirty_buffer(bh);
        else
-               ll_rw_block(WRITE, 1, &bh);
+               ll_rw_block(SWRITE, 1, &bh);
 
 out:
        /* If we have just flushed the log (by marking s_start==0), then
@@ -1439,7 +1427,7 @@ int journal_wipe(journal_t *journal, int write)
  * device this journal is present.
  */
 
-const char *journal_dev_name(journal_t *journal, char *buffer)
+static const char *journal_dev_name(journal_t *journal, char *buffer)
 {
        struct block_device *bdev;
 
@@ -1485,7 +1473,7 @@ void __journal_abort_hard(journal_t *journal)
 
 /* Soft abort: record the abort error status in the journal superblock,
  * but don't do any other IO. */
-void __journal_abort_soft (journal_t *journal, int errno)
+static void __journal_abort_soft (journal_t *journal, int errno)
 {
        if (journal->j_flags & JFS_ABORT)
                return;
@@ -1880,7 +1868,7 @@ EXPORT_SYMBOL(journal_enable_debug);
 
 static struct proc_dir_entry *proc_jbd_debug;
 
-int read_jbd_debug(char *page, char **start, off_t off,
+static int read_jbd_debug(char *page, char **start, off_t off,
                          int count, int *eof, void *data)
 {
        int ret;
@@ -1890,7 +1878,7 @@ int read_jbd_debug(char *page, char **start, off_t off,
        return ret;
 }
 
-int write_jbd_debug(struct file *file, const char __user *buffer,
+static int write_jbd_debug(struct file *file, const char __user *buffer,
                           unsigned long count, void *data)
 {
        char buf[32];
@@ -1979,6 +1967,14 @@ static int __init journal_init(void)
 {
        int ret;
 
+/* Static check for data structure consistency.  There's no code
+ * invoked --- we'll just get a linker failure if things aren't right.
+ */
+       extern void journal_bad_superblock_size(void);
+       if (sizeof(struct journal_superblock_s) != 1024)
+               journal_bad_superblock_size();
+
+
        ret = journal_init_caches();
        if (ret != 0)
                journal_destroy_caches();
index d327a598f8612843fddcf91be7df805e23acbc70..a56144183462e20d06ad756a5b6d062c44333838 100644 (file)
@@ -116,7 +116,8 @@ static inline int hash(journal_t *journal, unsigned long block)
                (block << (hash_shift - 12))) & (table->hash_size - 1);
 }
 
-int insert_revoke_hash(journal_t *journal, unsigned long blocknr, tid_t seq)
+static int insert_revoke_hash(journal_t *journal, unsigned long blocknr,
+                             tid_t seq)
 {
        struct list_head *hash_list;
        struct jbd_revoke_record_s *record;
@@ -613,7 +614,7 @@ static void flush_descriptor(journal_t *journal,
        set_buffer_jwrite(bh);
        BUFFER_TRACE(bh, "write");
        set_buffer_dirty(bh);
-       ll_rw_block(WRITE, 1, &bh);
+       ll_rw_block(SWRITE, 1, &bh);
 }
 #endif
 
index 77b7662b840b480f681c8cc889c5689d2b60f253..c6ec66fd876682f4846f0638c2b3682a66b49f94 100644 (file)
@@ -490,23 +490,21 @@ void journal_unlock_updates (journal_t *journal)
  */
 static void jbd_unexpected_dirty_buffer(struct journal_head *jh)
 {
-       struct buffer_head *bh = jh2bh(jh);
        int jlist;
 
-       if (buffer_dirty(bh)) {
-               /* If this buffer is one which might reasonably be dirty
-                * --- ie. data, or not part of this journal --- then
-                * we're OK to leave it alone, but otherwise we need to
-                * move the dirty bit to the journal's own internal
-                * JBDDirty bit. */
-               jlist = jh->b_jlist;
-
-               if (jlist == BJ_Metadata || jlist == BJ_Reserved || 
-                   jlist == BJ_Shadow || jlist == BJ_Forget) {
-                       if (test_clear_buffer_dirty(jh2bh(jh))) {
-                               set_bit(BH_JBDDirty, &jh2bh(jh)->b_state);
-                       }
-               }
+       /* If this buffer is one which might reasonably be dirty
+        * --- ie. data, or not part of this journal --- then
+        * we're OK to leave it alone, but otherwise we need to
+        * move the dirty bit to the journal's own internal
+        * JBDDirty bit. */
+       jlist = jh->b_jlist;
+
+       if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
+           jlist == BJ_Shadow || jlist == BJ_Forget) {
+               struct buffer_head *bh = jh2bh(jh);
+
+               if (test_clear_buffer_dirty(bh))
+                       set_buffer_jbddirty(bh);
        }
 }
 
@@ -574,9 +572,14 @@ repeat:
                        if (jh->b_next_transaction)
                                J_ASSERT_JH(jh, jh->b_next_transaction ==
                                                        transaction);
-                       JBUFFER_TRACE(jh, "Unexpected dirty buffer");
-                       jbd_unexpected_dirty_buffer(jh);
-               }
+               }
+               /*
+                * In any case we need to clean the dirty flag and we must
+                * do it under the buffer lock to be sure we don't race
+                * with running write-out.
+                */
+               JBUFFER_TRACE(jh, "Unexpected dirty buffer");
+               jbd_unexpected_dirty_buffer(jh);
        }
 
        unlock_buffer(bh);
index bfbeb4c86e03af70713b00b55e846b7dde0fc8cf..777b90057b893968a2718fb3163407811947c146 100644 (file)
@@ -1629,9 +1629,6 @@ static int jffs_fsync(struct file *f, struct dentry *d, int datasync)
 }
 
 
-extern int generic_file_open(struct inode *, struct file *) __attribute__((weak));
-extern loff_t generic_file_llseek(struct file *, loff_t, int) __attribute__((weak));
-
 static struct file_operations jffs_file_operations =
 {
        .open           = generic_file_open,
index bd9ed9b0247b1d48de85680c7bed66e04b1787a2..8279bf0133ff573549c0570b707a447042fa4cf9 100644 (file)
@@ -21,9 +21,6 @@
 #include <linux/jffs2.h>
 #include "nodelist.h"
 
-extern int generic_file_open(struct inode *, struct file *) __attribute__((weak));
-extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) __attribute__((weak));
-
 static int jffs2_commit_write (struct file *filp, struct page *pg,
                               unsigned start, unsigned end);
 static int jffs2_prepare_write (struct file *filp, struct page *pg,
index 86ccac80f0abc1cea8a4c42641dac38925f734ad..72a5588faecac5040a241448796d0cfb1e7a5b3f 100644 (file)
@@ -37,6 +37,9 @@
 #define JFS_ERR_CONTINUE   0x00000004   /* continue */
 #define JFS_ERR_PANIC      0x00000008   /* panic */
 
+#define        JFS_USRQUOTA    0x00000010
+#define        JFS_GRPQUOTA    0x00000020
+
 /* platform option (conditional compilation) */
 #define JFS_AIX                0x80000000      /* AIX support */
 /*     POSIX name/directory  support */
index 1cae14e741eb53b768d9ec2ca80d7f1b904cbad1..49ccde3937f97ec7d8bf4e28cb2955dea69b08d4 100644 (file)
@@ -1390,6 +1390,8 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc
 
        jfs_info("jfs_lookup: name = %s", name);
 
+       if (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)
+               dentry->d_op = &jfs_ci_dentry_operations;
 
        if ((name[0] == '.') && (len == 1))
                inum = dip->i_ino;
@@ -1417,9 +1419,6 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc
                return ERR_PTR(-EACCES);
        }
 
-       if (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)
-               dentry->d_op = &jfs_ci_dentry_operations;
-
        dentry = d_splice_alias(ip, dentry);
 
        if (dentry && (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2))
index 9ff89720f93bab8bfeaee75ac656e04f6a0de3ee..71bc34b96b2b89d81a0086265aacba9be8b509d6 100644 (file)
 #include <linux/parser.h>
 #include <linux/completion.h>
 #include <linux/vfs.h>
+#include <linux/mount.h>
 #include <linux/moduleparam.h>
 #include <linux/posix_acl.h>
 #include <asm/uaccess.h>
+#include <linux/seq_file.h>
 
 #include "jfs_incore.h"
 #include "jfs_filsys.h"
@@ -192,7 +194,8 @@ static void jfs_put_super(struct super_block *sb)
 
 enum {
        Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize,
-       Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err,
+       Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota,
+       Opt_usrquota, Opt_grpquota
 };
 
 static match_table_t tokens = {
@@ -204,8 +207,8 @@ static match_table_t tokens = {
        {Opt_errors, "errors=%s"},
        {Opt_ignore, "noquota"},
        {Opt_ignore, "quota"},
-       {Opt_ignore, "usrquota"},
-       {Opt_ignore, "grpquota"},
+       {Opt_usrquota, "usrquota"},
+       {Opt_grpquota, "grpquota"},
        {Opt_err, NULL}
 };
 
@@ -293,6 +296,24 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
                        }
                        break;
                }
+
+#if defined(CONFIG_QUOTA)
+               case Opt_quota:
+               case Opt_usrquota:
+                       *flag |= JFS_USRQUOTA;
+                       break;
+               case Opt_grpquota:
+                       *flag |= JFS_GRPQUOTA;
+                       break;
+#else
+               case Opt_usrquota:
+               case Opt_grpquota:
+               case Opt_quota:
+                       printk(KERN_ERR
+                              "JFS: quota operations not supported\n");
+                       break;
+#endif
+
                default:
                        printk("jfs: Unrecognized mount option \"%s\" "
                                        " or missing value\n", p);
@@ -539,6 +560,26 @@ static int jfs_sync_fs(struct super_block *sb, int wait)
        return 0;
 }
 
+static int jfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
+{
+       struct jfs_sb_info *sbi = JFS_SBI(vfs->mnt_sb);
+
+       if (sbi->flag & JFS_NOINTEGRITY)
+               seq_puts(seq, ",nointegrity");
+       else
+               seq_puts(seq, ",integrity");
+
+#if defined(CONFIG_QUOTA)
+       if (sbi->flag & JFS_USRQUOTA)
+               seq_puts(seq, ",usrquota");
+
+       if (sbi->flag & JFS_GRPQUOTA)
+               seq_puts(seq, ",grpquota");
+#endif
+
+       return 0;
+}
+
 static struct super_operations jfs_super_operations = {
        .alloc_inode    = jfs_alloc_inode,
        .destroy_inode  = jfs_destroy_inode,
@@ -552,6 +593,7 @@ static struct super_operations jfs_super_operations = {
        .unlockfs       = jfs_unlockfs,
        .statfs         = jfs_statfs,
        .remount_fs     = jfs_remount,
+       .show_options   = jfs_show_options
 };
 
 static struct export_operations jfs_export_operations = {
index 6ec1f0fefc5b017aa321738f7d3581370a91fad3..145e852c4bd02d717c3dd9e3b63caa6804870f25 100644 (file)
@@ -525,6 +525,22 @@ static inline int __do_follow_link(struct path *path, struct nameidata *nd)
        return error;
 }
 
+static inline void dput_path(struct path *path, struct nameidata *nd)
+{
+       dput(path->dentry);
+       if (path->mnt != nd->mnt)
+               mntput(path->mnt);
+}
+
+static inline void path_to_nameidata(struct path *path, struct nameidata *nd)
+{
+       dput(nd->dentry);
+       if (nd->mnt != path->mnt)
+               mntput(nd->mnt);
+       nd->mnt = path->mnt;
+       nd->dentry = path->dentry;
+}
+
 /*
  * This limits recursive symlink follows to 8, while
  * limiting consecutive symlinks to 40.
@@ -552,9 +568,7 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd)
        nd->depth--;
        return err;
 loop:
-       dput(path->dentry);
-       if (path->mnt != nd->mnt)
-               mntput(path->mnt);
+       dput_path(path, nd);
        path_release(nd);
        return err;
 }
@@ -813,13 +827,8 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
                        err = -ENOTDIR; 
                        if (!inode->i_op)
                                break;
-               } else {
-                       dput(nd->dentry);
-                       if (nd->mnt != next.mnt)
-                               mntput(nd->mnt);
-                       nd->mnt = next.mnt;
-                       nd->dentry = next.dentry;
-               }
+               } else
+                       path_to_nameidata(&next, nd);
                err = -ENOTDIR; 
                if (!inode->i_op->lookup)
                        break;
@@ -859,13 +868,8 @@ last_component:
                        if (err)
                                goto return_err;
                        inode = nd->dentry->d_inode;
-               } else {
-                       dput(nd->dentry);
-                       if (nd->mnt != next.mnt)
-                               mntput(nd->mnt);
-                       nd->mnt = next.mnt;
-                       nd->dentry = next.dentry;
-               }
+               } else
+                       path_to_nameidata(&next, nd);
                err = -ENOENT;
                if (!inode)
                        break;
@@ -901,9 +905,7 @@ return_reval:
 return_base:
                return 0;
 out_dput:
-               dput(next.dentry);
-               if (nd->mnt != next.mnt)
-                       mntput(next.mnt);
+               dput_path(&next, nd);
                break;
        }
        path_release(nd);
@@ -1507,11 +1509,7 @@ do_last:
        if (path.dentry->d_inode->i_op && path.dentry->d_inode->i_op->follow_link)
                goto do_link;
 
-       dput(nd->dentry);
-       nd->dentry = path.dentry;
-       if (nd->mnt != path.mnt)
-               mntput(nd->mnt);
-       nd->mnt = path.mnt;
+       path_to_nameidata(&path, nd);
        error = -EISDIR;
        if (path.dentry->d_inode && S_ISDIR(path.dentry->d_inode->i_mode))
                goto exit;
@@ -1522,9 +1520,7 @@ ok:
        return 0;
 
 exit_dput:
-       dput(path.dentry);
-       if (nd->mnt != path.mnt)
-               mntput(path.mnt);
+       dput_path(&path, nd);
 exit:
        path_release(nd);
        return error;
index 79bd8a46e1e7298859a85f9ed9efd20e1dfdb19c..34156260c9b6586939e932e3856cc0211e98cd97 100644 (file)
@@ -40,7 +40,7 @@ static inline int sysfs_init(void)
  __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);
 
 static struct list_head *mount_hashtable;
-static int hash_mask, hash_bits;
+static int hash_mask __read_mostly, hash_bits __read_mostly;
 static kmem_cache_t *mnt_cache; 
 
 static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
@@ -1334,8 +1334,12 @@ asmlinkage long sys_pivot_root(const char __user *new_root, const char __user *p
        error = -EINVAL;
        if (user_nd.mnt->mnt_root != user_nd.dentry)
                goto out2; /* not a mountpoint */
+       if (user_nd.mnt->mnt_parent == user_nd.mnt)
+               goto out2; /* not attached */
        if (new_nd.mnt->mnt_root != new_nd.dentry)
                goto out2; /* not a mountpoint */
+       if (new_nd.mnt->mnt_parent == new_nd.mnt)
+               goto out2; /* not attached */
        tmp = old_nd.mnt; /* make sure we can reach put_old from new_root */
        spin_lock(&vfsmount_lock);
        if (tmp != new_nd.mnt) {
index 9a11aa39e2e4e887d549f9e0f942797bc902ada1..057aff745506da64d5ca6b61d00f0eb41c597029 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/namei.h>
 #include <linux/mount.h>
 #include <linux/hash.h>
+#include <linux/module.h>
 
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
@@ -221,6 +222,7 @@ static int expkey_show(struct seq_file *m,
 }
        
 struct cache_detail svc_expkey_cache = {
+       .owner          = THIS_MODULE,
        .hash_size      = EXPKEY_HASHMAX,
        .hash_table     = expkey_table,
        .name           = "nfsd.fh",
@@ -456,6 +458,7 @@ static int svc_export_show(struct seq_file *m,
        return 0;
 }
 struct cache_detail svc_export_cache = {
+       .owner          = THIS_MODULE,
        .hash_size      = EXPORT_HASHMAX,
        .hash_table     = export_table,
        .name           = "nfsd.export",
index 5605a26efc57d9db3ca93471f437996dae91056e..13369650cdf9b8db38f2af1a456db8e7cff5a645 100644 (file)
@@ -187,6 +187,7 @@ static int         idtoname_parse(struct cache_detail *, char *, int);
 static struct ent *idtoname_lookup(struct ent *, int);
 
 static struct cache_detail idtoname_cache = {
+       .owner          = THIS_MODULE,
        .hash_size      = ENT_HASHMAX,
        .hash_table     = idtoname_table,
        .name           = "nfs4.idtoname",
@@ -320,6 +321,7 @@ static struct ent *nametoid_lookup(struct ent *, int);
 static int         nametoid_parse(struct cache_detail *, char *, int);
 
 static struct cache_detail nametoid_cache = {
+       .owner          = THIS_MODULE,
        .hash_size      = ENT_HASHMAX,
        .hash_table     = nametoid_table,
        .name           = "nfs4.nametoid",
@@ -404,8 +406,10 @@ nfsd_idmap_init(void)
 void
 nfsd_idmap_shutdown(void)
 {
-       cache_unregister(&idtoname_cache);
-       cache_unregister(&nametoid_cache);
+       if (cache_unregister(&idtoname_cache))
+               printk(KERN_ERR "nfsd: failed to unregister idtoname cache\n");
+       if (cache_unregister(&nametoid_cache))
+               printk(KERN_ERR "nfsd: failed to unregister nametoid cache\n");
 }
 
 /*
index 57ed50fe7f8568be7f4408b292ee36a3d1a8ab4e..954cf893d50c34513c8c7167173a479dc9eb026d 100644 (file)
@@ -93,7 +93,7 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
 
        dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
                        clname->len, clname->data);
-       tfm = crypto_alloc_tfm("md5", 0);
+       tfm = crypto_alloc_tfm("md5", CRYPTO_TFM_REQ_MAY_SLEEP);
        if (tfm == NULL)
                goto out;
        cksum.len = crypto_tfm_alg_digestsize(tfm);
@@ -114,8 +114,7 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
        kfree(cksum.data);
        status = nfs_ok;
 out:
-       if (tfm)
-               crypto_free_tfm(tfm);
+       crypto_free_tfm(tfm);
        return status;
 }
 
index 32bf05e2996d8054b8ced182c41471d7c3e133e6..4ee2dcc31c285dc57c6922b21e1bad80e740b6c3 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -933,16 +933,11 @@ void fastcall fd_install(unsigned int fd, struct file * file)
 
 EXPORT_SYMBOL(fd_install);
 
-asmlinkage long sys_open(const char __user * filename, int flags, int mode)
+long do_sys_open(const char __user *filename, int flags, int mode)
 {
-       char * tmp;
-       int fd;
+       char *tmp = getname(filename);
+       int fd = PTR_ERR(tmp);
 
-       if (force_o_largefile())
-               flags |= O_LARGEFILE;
-
-       tmp = getname(filename);
-       fd = PTR_ERR(tmp);
        if (!IS_ERR(tmp)) {
                fd = get_unused_fd();
                if (fd >= 0) {
@@ -959,6 +954,14 @@ asmlinkage long sys_open(const char __user * filename, int flags, int mode)
        }
        return fd;
 }
+
+asmlinkage long sys_open(const char __user *filename, int flags, int mode)
+{
+       if (force_o_largefile())
+               flags |= O_LARGEFILE;
+
+       return do_sys_open(filename, flags, mode);
+}
 EXPORT_SYMBOL_GPL(sys_open);
 
 #ifndef __alpha__
index 25aa09f9d09d08ce5c29738406bae6d5e27d8843..2c7a23dde2d83f1ae18190e5723c0eb8d8ae0548 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -415,6 +415,10 @@ pipe_poll(struct file *filp, poll_table *wait)
 
        if (filp->f_mode & FMODE_WRITE) {
                mask |= (nrbufs < PIPE_BUFFERS) ? POLLOUT | POLLWRNORM : 0;
+               /*
+                * Most Unices do not set POLLERR for FIFOs but on Linux they
+                * behave exactly like pipes for poll().
+                */
                if (!PIPE_READERS(*inode))
                        mask |= POLLERR;
        }
@@ -422,9 +426,6 @@ pipe_poll(struct file *filp, poll_table *wait)
        return mask;
 }
 
-/* FIXME: most Unices do not set POLLERR for fifos */
-#define fifo_poll pipe_poll
-
 static int
 pipe_release(struct inode *inode, int decr, int decw)
 {
@@ -568,7 +569,7 @@ struct file_operations read_fifo_fops = {
        .read           = pipe_read,
        .readv          = pipe_readv,
        .write          = bad_pipe_w,
-       .poll           = fifo_poll,
+       .poll           = pipe_poll,
        .ioctl          = pipe_ioctl,
        .open           = pipe_read_open,
        .release        = pipe_read_release,
@@ -580,7 +581,7 @@ struct file_operations write_fifo_fops = {
        .read           = bad_pipe_r,
        .write          = pipe_write,
        .writev         = pipe_writev,
-       .poll           = fifo_poll,
+       .poll           = pipe_poll,
        .ioctl          = pipe_ioctl,
        .open           = pipe_write_open,
        .release        = pipe_write_release,
@@ -593,7 +594,7 @@ struct file_operations rdwr_fifo_fops = {
        .readv          = pipe_readv,
        .write          = pipe_write,
        .writev         = pipe_writev,
-       .poll           = fifo_poll,
+       .poll           = pipe_poll,
        .ioctl          = pipe_ioctl,
        .open           = pipe_rdwr_open,
        .release        = pipe_rdwr_release,
index 491f2d9f89acd93fabb0d0067ee76f329bc14c2b..84751f3f52d530e86518247e3cace7d20646ed80 100644 (file)
  *  go into icache. We cache the reference to task_struct upon lookup too.
  *  Eventually it should become a filesystem in its own. We don't use the
  *  rest of procfs anymore.
+ *
+ *
+ *  Changelog:
+ *  17-Jan-2005
+ *  Allan Bezerra
+ *  Bruna Moreira <bruna.moreira@indt.org.br>
+ *  Edjard Mota <edjard.mota@indt.org.br>
+ *  Ilias Biris <ilias.biris@indt.org.br>
+ *  Mauricio Lin <mauricio.lin@indt.org.br>
+ *
+ *  Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT
+ *
+ *  A new process specific entry (smaps) included in /proc. It shows the
+ *  size of rss for each memory area. The maps entry lacks information
+ *  about physical memory size (rss) for each mapped file, i.e.,
+ *  rss information for executables and library files.
+ *  This additional information is useful for any tools that need to know
+ *  about physical memory consumption for a process specific library.
+ *
+ *  Changelog:
+ *  21-Feb-2005
+ *  Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT
+ *  Pud inclusion in the page table walking.
+ *
+ *  ChangeLog:
+ *  10-Mar-2005
+ *  10LE Instituto Nokia de Tecnologia - INdT:
+ *  A better way to walks through the page table as suggested by Hugh Dickins.
+ *
+ *  Simo Piiroinen <simo.piiroinen@nokia.com>:
+ *  Smaps information related to shared, private, clean and dirty pages.
+ *
+ *  Paul Mundt <paul.mundt@nokia.com>:
+ *  Overall revision about smaps.
  */
 
 #include <asm/uaccess.h>
@@ -65,8 +99,10 @@ enum pid_directory_inos {
        PROC_TGID_STAT,
        PROC_TGID_STATM,
        PROC_TGID_MAPS,
+       PROC_TGID_NUMA_MAPS,
        PROC_TGID_MOUNTS,
        PROC_TGID_WCHAN,
+       PROC_TGID_SMAPS,
 #ifdef CONFIG_SCHEDSTATS
        PROC_TGID_SCHEDSTAT,
 #endif
@@ -83,7 +119,6 @@ enum pid_directory_inos {
 #ifdef CONFIG_AUDITSYSCALL
        PROC_TGID_LOGINUID,
 #endif
-       PROC_TGID_FD_DIR,
        PROC_TGID_OOM_SCORE,
        PROC_TGID_OOM_ADJUST,
        PROC_TID_INO,
@@ -102,8 +137,10 @@ enum pid_directory_inos {
        PROC_TID_STAT,
        PROC_TID_STATM,
        PROC_TID_MAPS,
+       PROC_TID_NUMA_MAPS,
        PROC_TID_MOUNTS,
        PROC_TID_WCHAN,
+       PROC_TID_SMAPS,
 #ifdef CONFIG_SCHEDSTATS
        PROC_TID_SCHEDSTAT,
 #endif
@@ -120,9 +157,11 @@ enum pid_directory_inos {
 #ifdef CONFIG_AUDITSYSCALL
        PROC_TID_LOGINUID,
 #endif
-       PROC_TID_FD_DIR = 0x8000,       /* 0x8000-0xffff */
        PROC_TID_OOM_SCORE,
        PROC_TID_OOM_ADJUST,
+
+       /* Add new entries before this */
+       PROC_TID_FD_DIR = 0x8000,       /* 0x8000-0xffff */
 };
 
 struct pid_entry {
@@ -144,6 +183,9 @@ static struct pid_entry tgid_base_stuff[] = {
        E(PROC_TGID_STAT,      "stat",    S_IFREG|S_IRUGO),
        E(PROC_TGID_STATM,     "statm",   S_IFREG|S_IRUGO),
        E(PROC_TGID_MAPS,      "maps",    S_IFREG|S_IRUGO),
+#ifdef CONFIG_NUMA
+       E(PROC_TGID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO),
+#endif
        E(PROC_TGID_MEM,       "mem",     S_IFREG|S_IRUSR|S_IWUSR),
 #ifdef CONFIG_SECCOMP
        E(PROC_TGID_SECCOMP,   "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
@@ -152,6 +194,7 @@ static struct pid_entry tgid_base_stuff[] = {
        E(PROC_TGID_ROOT,      "root",    S_IFLNK|S_IRWXUGO),
        E(PROC_TGID_EXE,       "exe",     S_IFLNK|S_IRWXUGO),
        E(PROC_TGID_MOUNTS,    "mounts",  S_IFREG|S_IRUGO),
+       E(PROC_TGID_SMAPS,     "smaps",   S_IFREG|S_IRUGO),
 #ifdef CONFIG_SECURITY
        E(PROC_TGID_ATTR,      "attr",    S_IFDIR|S_IRUGO|S_IXUGO),
 #endif
@@ -180,6 +223,9 @@ static struct pid_entry tid_base_stuff[] = {
        E(PROC_TID_STAT,       "stat",    S_IFREG|S_IRUGO),
        E(PROC_TID_STATM,      "statm",   S_IFREG|S_IRUGO),
        E(PROC_TID_MAPS,       "maps",    S_IFREG|S_IRUGO),
+#ifdef CONFIG_NUMA
+       E(PROC_TID_NUMA_MAPS,  "numa_maps",    S_IFREG|S_IRUGO),
+#endif
        E(PROC_TID_MEM,        "mem",     S_IFREG|S_IRUSR|S_IWUSR),
 #ifdef CONFIG_SECCOMP
        E(PROC_TID_SECCOMP,    "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
@@ -188,6 +234,7 @@ static struct pid_entry tid_base_stuff[] = {
        E(PROC_TID_ROOT,       "root",    S_IFLNK|S_IRWXUGO),
        E(PROC_TID_EXE,        "exe",     S_IFLNK|S_IRWXUGO),
        E(PROC_TID_MOUNTS,     "mounts",  S_IFREG|S_IRUGO),
+       E(PROC_TID_SMAPS,      "smaps",   S_IFREG|S_IRUGO),
 #ifdef CONFIG_SECURITY
        E(PROC_TID_ATTR,       "attr",    S_IFDIR|S_IRUGO|S_IXUGO),
 #endif
@@ -251,15 +298,21 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm
        return -ENOENT;
 }
 
-static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+static struct fs_struct *get_fs_struct(struct task_struct *task)
 {
        struct fs_struct *fs;
-       int result = -ENOENT;
-       task_lock(proc_task(inode));
-       fs = proc_task(inode)->fs;
+       task_lock(task);
+       fs = task->fs;
        if(fs)
                atomic_inc(&fs->count);
-       task_unlock(proc_task(inode));
+       task_unlock(task);
+       return fs;
+}
+
+static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+{
+       struct fs_struct *fs = get_fs_struct(proc_task(inode));
+       int result = -ENOENT;
        if (fs) {
                read_lock(&fs->lock);
                *mnt = mntget(fs->pwdmnt);
@@ -273,13 +326,8 @@ static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfs
 
 static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
-       struct fs_struct *fs;
+       struct fs_struct *fs = get_fs_struct(proc_task(inode));
        int result = -ENOENT;
-       task_lock(proc_task(inode));
-       fs = proc_task(inode)->fs;
-       if(fs)
-               atomic_inc(&fs->count);
-       task_unlock(proc_task(inode));
        if (fs) {
                read_lock(&fs->lock);
                *mnt = mntget(fs->rootmnt);
@@ -298,33 +346,6 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf
         (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \
         security_ptrace(current,task) == 0))
 
-static int may_ptrace_attach(struct task_struct *task)
-{
-       int retval = 0;
-
-       task_lock(task);
-
-       if (!task->mm)
-               goto out;
-       if (((current->uid != task->euid) ||
-            (current->uid != task->suid) ||
-            (current->uid != task->uid) ||
-            (current->gid != task->egid) ||
-            (current->gid != task->sgid) ||
-            (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
-               goto out;
-       rmb();
-       if (task->mm->dumpable != 1 && !capable(CAP_SYS_PTRACE))
-               goto out;
-       if (security_ptrace(current, task))
-               goto out;
-
-       retval = 1;
-out:
-       task_unlock(task);
-       return retval;
-}
-
 static int proc_pid_environ(struct task_struct *task, char * buffer)
 {
        int res = 0;
@@ -334,7 +355,7 @@ static int proc_pid_environ(struct task_struct *task, char * buffer)
                if (len > PAGE_SIZE)
                        len = PAGE_SIZE;
                res = access_process_vm(task, mm->env_start, buffer, len, 0);
-               if (!may_ptrace_attach(task))
+               if (!ptrace_may_attach(task))
                        res = -ESRCH;
                mmput(mm);
        }
@@ -515,6 +536,46 @@ static struct file_operations proc_maps_operations = {
        .release        = seq_release,
 };
 
+#ifdef CONFIG_NUMA
+extern struct seq_operations proc_pid_numa_maps_op;
+static int numa_maps_open(struct inode *inode, struct file *file)
+{
+       struct task_struct *task = proc_task(inode);
+       int ret = seq_open(file, &proc_pid_numa_maps_op);
+       if (!ret) {
+               struct seq_file *m = file->private_data;
+               m->private = task;
+       }
+       return ret;
+}
+
+static struct file_operations proc_numa_maps_operations = {
+       .open           = numa_maps_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+#endif
+
+extern struct seq_operations proc_pid_smaps_op;
+static int smaps_open(struct inode *inode, struct file *file)
+{
+       struct task_struct *task = proc_task(inode);
+       int ret = seq_open(file, &proc_pid_smaps_op);
+       if (!ret) {
+               struct seq_file *m = file->private_data;
+               m->private = task;
+       }
+       return ret;
+}
+
+static struct file_operations proc_smaps_operations = {
+       .open           = smaps_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
 extern struct seq_operations mounts_op;
 static int mounts_open(struct inode *inode, struct file *file)
 {
@@ -597,7 +658,7 @@ static ssize_t mem_read(struct file * file, char __user * buf,
        int ret = -ESRCH;
        struct mm_struct *mm;
 
-       if (!MAY_PTRACE(task) || !may_ptrace_attach(task))
+       if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
                goto out;
 
        ret = -ENOMEM;
@@ -623,7 +684,7 @@ static ssize_t mem_read(struct file * file, char __user * buf,
 
                this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
                retval = access_process_vm(task, src, page, this_len, 0);
-               if (!retval || !MAY_PTRACE(task) || !may_ptrace_attach(task)) {
+               if (!retval || !MAY_PTRACE(task) || !ptrace_may_attach(task)) {
                        if (!ret)
                                ret = -EIO;
                        break;
@@ -661,7 +722,7 @@ static ssize_t mem_write(struct file * file, const char * buf,
        struct task_struct *task = proc_task(file->f_dentry->d_inode);
        unsigned long dst = *ppos;
 
-       if (!MAY_PTRACE(task) || !may_ptrace_attach(task))
+       if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
                return -ESRCH;
 
        page = (char *)__get_free_page(GFP_USER);
@@ -1524,6 +1585,12 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
                case PROC_TGID_MAPS:
                        inode->i_fop = &proc_maps_operations;
                        break;
+#ifdef CONFIG_NUMA
+               case PROC_TID_NUMA_MAPS:
+               case PROC_TGID_NUMA_MAPS:
+                       inode->i_fop = &proc_numa_maps_operations;
+                       break;
+#endif
                case PROC_TID_MEM:
                case PROC_TGID_MEM:
                        inode->i_op = &proc_mem_inode_operations;
@@ -1539,6 +1606,10 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
                case PROC_TGID_MOUNTS:
                        inode->i_fop = &proc_mounts_operations;
                        break;
+               case PROC_TID_SMAPS:
+               case PROC_TGID_SMAPS:
+                       inode->i_fop = &proc_smaps_operations;
+                       break;
 #ifdef CONFIG_SECURITY
                case PROC_TID_ATTR:
                        inode->i_nlink = 2;
index abe8920313fb32b84ad65b78861325727ae5ce45..8a8c34461d481c115a31d628d8e598bb68c20b26 100644 (file)
@@ -249,6 +249,18 @@ out:
        return error;
 }
 
+static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry,
+                       struct kstat *stat)
+{
+       struct inode *inode = dentry->d_inode;
+       struct proc_dir_entry *de = PROC_I(inode)->pde;
+       if (de && de->nlink)
+               inode->i_nlink = de->nlink;
+
+       generic_fillattr(inode, stat);
+       return 0;
+}
+
 static struct inode_operations proc_file_inode_operations = {
        .setattr        = proc_notify_change,
 };
@@ -475,6 +487,7 @@ static struct file_operations proc_dir_operations = {
  */
 static struct inode_operations proc_dir_inode_operations = {
        .lookup         = proc_lookup,
+       .getattr        = proc_getattr,
        .setattr        = proc_notify_change,
 };
 
index 28b4a0253a92161fff797dcfae5f79585fafd022..c7ef3e48e35bae1433c18a4736979e0949a59009 100644 (file)
@@ -2,8 +2,13 @@
 #include <linux/hugetlb.h>
 #include <linux/mount.h>
 #include <linux/seq_file.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/mempolicy.h>
+
 #include <asm/elf.h>
 #include <asm/uaccess.h>
+#include <asm/tlbflush.h>
 #include "internal.h"
 
 char *task_mem(struct mm_struct *mm, char *buffer)
@@ -87,49 +92,58 @@ static void pad_len_spaces(struct seq_file *m, int len)
        seq_printf(m, "%*c", len, ' ');
 }
 
-static int show_map(struct seq_file *m, void *v)
+struct mem_size_stats
+{
+       unsigned long resident;
+       unsigned long shared_clean;
+       unsigned long shared_dirty;
+       unsigned long private_clean;
+       unsigned long private_dirty;
+};
+
+static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats *mss)
 {
        struct task_struct *task = m->private;
-       struct vm_area_struct *map = v;
-       struct mm_struct *mm = map->vm_mm;
-       struct file *file = map->vm_file;
-       int flags = map->vm_flags;
+       struct vm_area_struct *vma = v;
+       struct mm_struct *mm = vma->vm_mm;
+       struct file *file = vma->vm_file;
+       int flags = vma->vm_flags;
        unsigned long ino = 0;
        dev_t dev = 0;
        int len;
 
        if (file) {
-               struct inode *inode = map->vm_file->f_dentry->d_inode;
+               struct inode *inode = vma->vm_file->f_dentry->d_inode;
                dev = inode->i_sb->s_dev;
                ino = inode->i_ino;
        }
 
        seq_printf(m, "%08lx-%08lx %c%c%c%c %08lx %02x:%02x %lu %n",
-                       map->vm_start,
-                       map->vm_end,
+                       vma->vm_start,
+                       vma->vm_end,
                        flags & VM_READ ? 'r' : '-',
                        flags & VM_WRITE ? 'w' : '-',
                        flags & VM_EXEC ? 'x' : '-',
                        flags & VM_MAYSHARE ? 's' : 'p',
-                       map->vm_pgoff << PAGE_SHIFT,
+                       vma->vm_pgoff << PAGE_SHIFT,
                        MAJOR(dev), MINOR(dev), ino, &len);
 
        /*
         * Print the dentry name for named mappings, and a
         * special [heap] marker for the heap:
         */
-       if (map->vm_file) {
+       if (file) {
                pad_len_spaces(m, len);
-               seq_path(m, file->f_vfsmnt, file->f_dentry, "");
+               seq_path(m, file->f_vfsmnt, file->f_dentry, "\n");
        } else {
                if (mm) {
-                       if (map->vm_start <= mm->start_brk &&
-                                               map->vm_end >= mm->brk) {
+                       if (vma->vm_start <= mm->start_brk &&
+                                               vma->vm_end >= mm->brk) {
                                pad_len_spaces(m, len);
                                seq_puts(m, "[heap]");
                        } else {
-                               if (map->vm_start <= mm->start_stack &&
-                                       map->vm_end >= mm->start_stack) {
+                               if (vma->vm_start <= mm->start_stack &&
+                                       vma->vm_end >= mm->start_stack) {
 
                                        pad_len_spaces(m, len);
                                        seq_puts(m, "[stack]");
@@ -141,24 +155,146 @@ static int show_map(struct seq_file *m, void *v)
                }
        }
        seq_putc(m, '\n');
-       if (m->count < m->size)  /* map is copied successfully */
-               m->version = (map != get_gate_vma(task))? map->vm_start: 0;
+
+       if (mss)
+               seq_printf(m,
+                          "Size:          %8lu kB\n"
+                          "Rss:           %8lu kB\n"
+                          "Shared_Clean:  %8lu kB\n"
+                          "Shared_Dirty:  %8lu kB\n"
+                          "Private_Clean: %8lu kB\n"
+                          "Private_Dirty: %8lu kB\n",
+                          (vma->vm_end - vma->vm_start) >> 10,
+                          mss->resident >> 10,
+                          mss->shared_clean  >> 10,
+                          mss->shared_dirty  >> 10,
+                          mss->private_clean >> 10,
+                          mss->private_dirty >> 10);
+
+       if (m->count < m->size)  /* vma is copied successfully */
+               m->version = (vma != get_gate_vma(task))? vma->vm_start: 0;
        return 0;
 }
 
+static int show_map(struct seq_file *m, void *v)
+{
+       return show_map_internal(m, v, 0);
+}
+
+static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
+                               unsigned long addr, unsigned long end,
+                               struct mem_size_stats *mss)
+{
+       pte_t *pte, ptent;
+       unsigned long pfn;
+       struct page *page;
+
+       pte = pte_offset_map(pmd, addr);
+       do {
+               ptent = *pte;
+               if (pte_none(ptent) || !pte_present(ptent))
+                       continue;
+
+               mss->resident += PAGE_SIZE;
+               pfn = pte_pfn(ptent);
+               if (!pfn_valid(pfn))
+                       continue;
+
+               page = pfn_to_page(pfn);
+               if (page_count(page) >= 2) {
+                       if (pte_dirty(ptent))
+                               mss->shared_dirty += PAGE_SIZE;
+                       else
+                               mss->shared_clean += PAGE_SIZE;
+               } else {
+                       if (pte_dirty(ptent))
+                               mss->private_dirty += PAGE_SIZE;
+                       else
+                               mss->private_clean += PAGE_SIZE;
+               }
+       } while (pte++, addr += PAGE_SIZE, addr != end);
+       pte_unmap(pte - 1);
+       cond_resched_lock(&vma->vm_mm->page_table_lock);
+}
+
+static inline void smaps_pmd_range(struct vm_area_struct *vma, pud_t *pud,
+                               unsigned long addr, unsigned long end,
+                               struct mem_size_stats *mss)
+{
+       pmd_t *pmd;
+       unsigned long next;
+
+       pmd = pmd_offset(pud, addr);
+       do {
+               next = pmd_addr_end(addr, end);
+               if (pmd_none_or_clear_bad(pmd))
+                       continue;
+               smaps_pte_range(vma, pmd, addr, next, mss);
+       } while (pmd++, addr = next, addr != end);
+}
+
+static inline void smaps_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
+                               unsigned long addr, unsigned long end,
+                               struct mem_size_stats *mss)
+{
+       pud_t *pud;
+       unsigned long next;
+
+       pud = pud_offset(pgd, addr);
+       do {
+               next = pud_addr_end(addr, end);
+               if (pud_none_or_clear_bad(pud))
+                       continue;
+               smaps_pmd_range(vma, pud, addr, next, mss);
+       } while (pud++, addr = next, addr != end);
+}
+
+static inline void smaps_pgd_range(struct vm_area_struct *vma,
+                               unsigned long addr, unsigned long end,
+                               struct mem_size_stats *mss)
+{
+       pgd_t *pgd;
+       unsigned long next;
+
+       pgd = pgd_offset(vma->vm_mm, addr);
+       do {
+               next = pgd_addr_end(addr, end);
+               if (pgd_none_or_clear_bad(pgd))
+                       continue;
+               smaps_pud_range(vma, pgd, addr, next, mss);
+       } while (pgd++, addr = next, addr != end);
+}
+
+static int show_smap(struct seq_file *m, void *v)
+{
+       struct vm_area_struct *vma = v;
+       struct mm_struct *mm = vma->vm_mm;
+       struct mem_size_stats mss;
+
+       memset(&mss, 0, sizeof mss);
+
+       if (mm) {
+               spin_lock(&mm->page_table_lock);
+               smaps_pgd_range(vma, vma->vm_start, vma->vm_end, &mss);
+               spin_unlock(&mm->page_table_lock);
+       }
+
+       return show_map_internal(m, v, &mss);
+}
+
 static void *m_start(struct seq_file *m, loff_t *pos)
 {
        struct task_struct *task = m->private;
        unsigned long last_addr = m->version;
        struct mm_struct *mm;
-       struct vm_area_struct *map, *tail_map;
+       struct vm_area_struct *vma, *tail_vma;
        loff_t l = *pos;
 
        /*
         * We remember last_addr rather than next_addr to hit with
         * mmap_cache most of the time. We have zero last_addr at
-        * the begining and also after lseek. We will have -1 last_addr
-        * after the end of the maps.
+        * the beginning and also after lseek. We will have -1 last_addr
+        * after the end of the vmas.
         */
 
        if (last_addr == -1UL)
@@ -168,47 +304,47 @@ static void *m_start(struct seq_file *m, loff_t *pos)
        if (!mm)
                return NULL;
 
-       tail_map = get_gate_vma(task);
+       tail_vma = get_gate_vma(task);
        down_read(&mm->mmap_sem);
 
        /* Start with last addr hint */
-       if (last_addr && (map = find_vma(mm, last_addr))) {
-               map = map->vm_next;
+       if (last_addr && (vma = find_vma(mm, last_addr))) {
+               vma = vma->vm_next;
                goto out;
        }
 
        /*
-        * Check the map index is within the range and do
+        * Check the vma index is within the range and do
         * sequential scan until m_index.
         */
-       map = NULL;
+       vma = NULL;
        if ((unsigned long)l < mm->map_count) {
-               map = mm->mmap;
-               while (l-- && map)
-                       map = map->vm_next;
+               vma = mm->mmap;
+               while (l-- && vma)
+                       vma = vma->vm_next;
                goto out;
        }
 
        if (l != mm->map_count)
-               tail_map = NULL; /* After gate map */
+               tail_vma = NULL; /* After gate vma */
 
 out:
-       if (map)
-               return map;
+       if (vma)
+               return vma;
 
-       /* End of maps has reached */
-       m->version = (tail_map != NULL)? 0: -1UL;
+       /* End of vmas has been reached */
+       m->version = (tail_vma != NULL)? 0: -1UL;
        up_read(&mm->mmap_sem);
        mmput(mm);
-       return tail_map;
+       return tail_vma;
 }
 
 static void m_stop(struct seq_file *m, void *v)
 {
        struct task_struct *task = m->private;
-       struct vm_area_struct *map = v;
-       if (map && map != get_gate_vma(task)) {
-               struct mm_struct *mm = map->vm_mm;
+       struct vm_area_struct *vma = v;
+       if (vma && vma != get_gate_vma(task)) {
+               struct mm_struct *mm = vma->vm_mm;
                up_read(&mm->mmap_sem);
                mmput(mm);
        }
@@ -217,14 +353,14 @@ static void m_stop(struct seq_file *m, void *v)
 static void *m_next(struct seq_file *m, void *v, loff_t *pos)
 {
        struct task_struct *task = m->private;
-       struct vm_area_struct *map = v;
-       struct vm_area_struct *tail_map = get_gate_vma(task);
+       struct vm_area_struct *vma = v;
+       struct vm_area_struct *tail_vma = get_gate_vma(task);
 
        (*pos)++;
-       if (map && (map != tail_map) && map->vm_next)
-               return map->vm_next;
+       if (vma && (vma != tail_vma) && vma->vm_next)
+               return vma->vm_next;
        m_stop(m, v);
-       return (map != tail_map)? tail_map: NULL;
+       return (vma != tail_vma)? tail_vma: NULL;
 }
 
 struct seq_operations proc_pid_maps_op = {
@@ -233,3 +369,140 @@ struct seq_operations proc_pid_maps_op = {
        .stop   = m_stop,
        .show   = show_map
 };
+
+struct seq_operations proc_pid_smaps_op = {
+       .start  = m_start,
+       .next   = m_next,
+       .stop   = m_stop,
+       .show   = show_smap
+};
+
+#ifdef CONFIG_NUMA
+
+struct numa_maps {
+       unsigned long pages;
+       unsigned long anon;
+       unsigned long mapped;
+       unsigned long mapcount_max;
+       unsigned long node[MAX_NUMNODES];
+};
+
+/*
+ * Calculate numa node maps for a vma
+ */
+static struct numa_maps *get_numa_maps(const struct vm_area_struct *vma)
+{
+       struct page *page;
+       unsigned long vaddr;
+       struct mm_struct *mm = vma->vm_mm;
+       int i;
+       struct numa_maps *md = kmalloc(sizeof(struct numa_maps), GFP_KERNEL);
+
+       if (!md)
+               return NULL;
+       md->pages = 0;
+       md->anon = 0;
+       md->mapped = 0;
+       md->mapcount_max = 0;
+       for_each_node(i)
+               md->node[i] =0;
+
+       spin_lock(&mm->page_table_lock);
+       for (vaddr = vma->vm_start; vaddr < vma->vm_end; vaddr += PAGE_SIZE) {
+               page = follow_page(mm, vaddr, 0);
+               if (page) {
+                       int count = page_mapcount(page);
+
+                       if (count)
+                               md->mapped++;
+                       if (count > md->mapcount_max)
+                               md->mapcount_max = count;
+                       md->pages++;
+                       if (PageAnon(page))
+                               md->anon++;
+                       md->node[page_to_nid(page)]++;
+               }
+       }
+       spin_unlock(&mm->page_table_lock);
+       return md;
+}
+
+static int show_numa_map(struct seq_file *m, void *v)
+{
+       struct task_struct *task = m->private;
+       struct vm_area_struct *vma = v;
+       struct mempolicy *pol;
+       struct numa_maps *md;
+       struct zone **z;
+       int n;
+       int first;
+
+       if (!vma->vm_mm)
+               return 0;
+
+       md = get_numa_maps(vma);
+       if (!md)
+               return 0;
+
+       seq_printf(m, "%08lx", vma->vm_start);
+       pol = get_vma_policy(task, vma, vma->vm_start);
+       /* Print policy */
+       switch (pol->policy) {
+       case MPOL_PREFERRED:
+               seq_printf(m, " prefer=%d", pol->v.preferred_node);
+               break;
+       case MPOL_BIND:
+               seq_printf(m, " bind={");
+               first = 1;
+               for (z = pol->v.zonelist->zones; *z; z++) {
+
+                       if (!first)
+                               seq_putc(m, ',');
+                       else
+                               first = 0;
+                       seq_printf(m, "%d/%s", (*z)->zone_pgdat->node_id,
+                                       (*z)->name);
+               }
+               seq_putc(m, '}');
+               break;
+       case MPOL_INTERLEAVE:
+               seq_printf(m, " interleave={");
+               first = 1;
+               for_each_node(n) {
+                       if (test_bit(n, pol->v.nodes)) {
+                               if (!first)
+                                       seq_putc(m,',');
+                               else
+                                       first = 0;
+                               seq_printf(m, "%d",n);
+                       }
+               }
+               seq_putc(m, '}');
+               break;
+       default:
+               seq_printf(m," default");
+               break;
+       }
+       seq_printf(m, " MaxRef=%lu Pages=%lu Mapped=%lu",
+                       md->mapcount_max, md->pages, md->mapped);
+       if (md->anon)
+               seq_printf(m," Anon=%lu",md->anon);
+
+       for_each_online_node(n) {
+               if (md->node[n])
+                       seq_printf(m, " N%d=%lu", n, md->node[n]);
+       }
+       seq_putc(m, '\n');
+       kfree(md);
+       if (m->count < m->size)  /* vma is copied successfully */
+               m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0;
+       return 0;
+}
+
+struct seq_operations proc_pid_numa_maps_op = {
+       .start  = m_start,
+       .next   = m_next,
+       .stop   = m_stop,
+       .show   = show_numa_map
+};
+#endif
index 563abd09b5c84b882cbe6f47e56d05e80e5db4b6..b60324aaa2b6731d9ddedd67badaa7b5c9790a60 100644 (file)
@@ -188,7 +188,7 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count
        struct inode *inode;
        loff_t pos;
 
-       if (unlikely(count > file->f_maxcount))
+       if (unlikely(count > INT_MAX))
                goto Einval;
        pos = *ppos;
        if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
index ca7989b04be3490f1e430cae7af2c1b242e521c8..a8e29e9bbbd08e336fc13a3fd9b1e81d7ec4eda0 100644 (file)
@@ -1034,7 +1034,7 @@ static int flush_commit_list(struct super_block *s,
                    SB_ONDISK_JOURNAL_SIZE(s);
                tbh = journal_find_get_block(s, bn);
                if (buffer_dirty(tbh))  /* redundant, ll_rw_block() checks */
-                       ll_rw_block(WRITE, 1, &tbh);
+                       ll_rw_block(SWRITE, 1, &tbh);
                put_bh(tbh);
        }
        atomic_dec(&journal->j_async_throttle);
@@ -2172,7 +2172,7 @@ static int journal_read_transaction(struct super_block *p_s_sb,
        /* flush out the real blocks */
        for (i = 0; i < get_desc_trans_len(desc); i++) {
                set_buffer_dirty(real_blocks[i]);
-               ll_rw_block(WRITE, 1, real_blocks + i);
+               ll_rw_block(SWRITE, 1, real_blocks + i);
        }
        for (i = 0; i < get_desc_trans_len(desc); i++) {
                wait_on_buffer(real_blocks[i]);
diff --git a/fs/relayfs/Makefile b/fs/relayfs/Makefile
new file mode 100644 (file)
index 0000000..e76e182
--- /dev/null
@@ -0,0 +1,4 @@
+obj-$(CONFIG_RELAYFS_FS) += relayfs.o
+
+relayfs-y := relay.o inode.o buffers.o
+
diff --git a/fs/relayfs/buffers.c b/fs/relayfs/buffers.c
new file mode 100644 (file)
index 0000000..2aa8e27
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * RelayFS buffer management code.
+ *
+ * Copyright (C) 2002-2005 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
+ * Copyright (C) 1999-2005 - Karim Yaghmour (karim@opersys.com)
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/relayfs_fs.h>
+#include "relay.h"
+#include "buffers.h"
+
+/*
+ * close() vm_op implementation for relayfs file mapping.
+ */
+static void relay_file_mmap_close(struct vm_area_struct *vma)
+{
+       struct rchan_buf *buf = vma->vm_private_data;
+       buf->chan->cb->buf_unmapped(buf, vma->vm_file);
+}
+
+/*
+ * nopage() vm_op implementation for relayfs file mapping.
+ */
+static struct page *relay_buf_nopage(struct vm_area_struct *vma,
+                                    unsigned long address,
+                                    int *type)
+{
+       struct page *page;
+       struct rchan_buf *buf = vma->vm_private_data;
+       unsigned long offset = address - vma->vm_start;
+
+       if (address > vma->vm_end)
+               return NOPAGE_SIGBUS; /* Disallow mremap */
+       if (!buf)
+               return NOPAGE_OOM;
+
+       page = vmalloc_to_page(buf->start + offset);
+       if (!page)
+               return NOPAGE_OOM;
+       get_page(page);
+
+       if (type)
+               *type = VM_FAULT_MINOR;
+
+       return page;
+}
+
+/*
+ * vm_ops for relay file mappings.
+ */
+static struct vm_operations_struct relay_file_mmap_ops = {
+       .nopage = relay_buf_nopage,
+       .close = relay_file_mmap_close,
+};
+
+/**
+ *     relay_mmap_buf: - mmap channel buffer to process address space
+ *     @buf: relay channel buffer
+ *     @vma: vm_area_struct describing memory to be mapped
+ *
+ *     Returns 0 if ok, negative on error
+ *
+ *     Caller should already have grabbed mmap_sem.
+ */
+int relay_mmap_buf(struct rchan_buf *buf, struct vm_area_struct *vma)
+{
+       unsigned long length = vma->vm_end - vma->vm_start;
+       struct file *filp = vma->vm_file;
+
+       if (!buf)
+               return -EBADF;
+
+       if (length != (unsigned long)buf->chan->alloc_size)
+               return -EINVAL;
+
+       vma->vm_ops = &relay_file_mmap_ops;
+       vma->vm_private_data = buf;
+       buf->chan->cb->buf_mapped(buf, filp);
+
+       return 0;
+}
+
+/**
+ *     relay_alloc_buf - allocate a channel buffer
+ *     @buf: the buffer struct
+ *     @size: total size of the buffer
+ *
+ *     Returns a pointer to the resulting buffer, NULL if unsuccessful
+ */
+static void *relay_alloc_buf(struct rchan_buf *buf, unsigned long size)
+{
+       void *mem;
+       unsigned int i, j, n_pages;
+
+       size = PAGE_ALIGN(size);
+       n_pages = size >> PAGE_SHIFT;
+
+       buf->page_array = kcalloc(n_pages, sizeof(struct page *), GFP_KERNEL);
+       if (!buf->page_array)
+               return NULL;
+
+       for (i = 0; i < n_pages; i++) {
+               buf->page_array[i] = alloc_page(GFP_KERNEL);
+               if (unlikely(!buf->page_array[i]))
+                       goto depopulate;
+       }
+       mem = vmap(buf->page_array, n_pages, GFP_KERNEL, PAGE_KERNEL);
+       if (!mem)
+               goto depopulate;
+
+       memset(mem, 0, size);
+       buf->page_count = n_pages;
+       return mem;
+
+depopulate:
+       for (j = 0; j < i; j++)
+               __free_page(buf->page_array[j]);
+       kfree(buf->page_array);
+       return NULL;
+}
+
+/**
+ *     relay_create_buf - allocate and initialize a channel buffer
+ *     @alloc_size: size of the buffer to allocate
+ *     @n_subbufs: number of sub-buffers in the channel
+ *
+ *     Returns channel buffer if successful, NULL otherwise
+ */
+struct rchan_buf *relay_create_buf(struct rchan *chan)
+{
+       struct rchan_buf *buf = kcalloc(1, sizeof(struct rchan_buf), GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       buf->padding = kmalloc(chan->n_subbufs * sizeof(size_t *), GFP_KERNEL);
+       if (!buf->padding)
+               goto free_buf;
+
+       buf->start = relay_alloc_buf(buf, chan->alloc_size);
+       if (!buf->start)
+               goto free_buf;
+
+       buf->chan = chan;
+       kref_get(&buf->chan->kref);
+       return buf;
+
+free_buf:
+       kfree(buf->padding);
+       kfree(buf);
+       return NULL;
+}
+
+/**
+ *     relay_destroy_buf - destroy an rchan_buf struct and associated buffer
+ *     @buf: the buffer struct
+ */
+void relay_destroy_buf(struct rchan_buf *buf)
+{
+       struct rchan *chan = buf->chan;
+       unsigned int i;
+
+       if (likely(buf->start)) {
+               vunmap(buf->start);
+               for (i = 0; i < buf->page_count; i++)
+                       __free_page(buf->page_array[i]);
+               kfree(buf->page_array);
+       }
+       kfree(buf->padding);
+       kfree(buf);
+       kref_put(&chan->kref, relay_destroy_channel);
+}
+
+/**
+ *     relay_remove_buf - remove a channel buffer
+ *
+ *     Removes the file from the relayfs fileystem, which also frees the
+ *     rchan_buf_struct and the channel buffer.  Should only be called from
+ *     kref_put().
+ */
+void relay_remove_buf(struct kref *kref)
+{
+       struct rchan_buf *buf = container_of(kref, struct rchan_buf, kref);
+       relayfs_remove(buf->dentry);
+}
diff --git a/fs/relayfs/buffers.h b/fs/relayfs/buffers.h
new file mode 100644 (file)
index 0000000..37a1249
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _BUFFERS_H
+#define _BUFFERS_H
+
+/* This inspired by rtai/shmem */
+#define FIX_SIZE(x) (((x) - 1) & PAGE_MASK) + PAGE_SIZE
+
+extern int relay_mmap_buf(struct rchan_buf *buf, struct vm_area_struct *vma);
+extern struct rchan_buf *relay_create_buf(struct rchan *chan);
+extern void relay_destroy_buf(struct rchan_buf *buf);
+extern void relay_remove_buf(struct kref *kref);
+
+#endif/* _BUFFERS_H */
diff --git a/fs/relayfs/inode.c b/fs/relayfs/inode.c
new file mode 100644 (file)
index 0000000..0f7f88d
--- /dev/null
@@ -0,0 +1,609 @@
+/*
+ * VFS-related code for RelayFS, a high-speed data relay filesystem.
+ *
+ * Copyright (C) 2003-2005 - Tom Zanussi <zanussi@us.ibm.com>, IBM Corp
+ * Copyright (C) 2003-2005 - Karim Yaghmour <karim@opersys.com>
+ *
+ * Based on ramfs, Copyright (C) 2002 - Linus Torvalds
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/backing-dev.h>
+#include <linux/namei.h>
+#include <linux/poll.h>
+#include <linux/relayfs_fs.h>
+#include "relay.h"
+#include "buffers.h"
+
+#define RELAYFS_MAGIC                  0xF0B4A981
+
+static struct vfsmount *               relayfs_mount;
+static int                             relayfs_mount_count;
+static kmem_cache_t *                  relayfs_inode_cachep;
+
+static struct backing_dev_info         relayfs_backing_dev_info = {
+       .ra_pages       = 0,    /* No readahead */
+       .capabilities   = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
+};
+
+static struct inode *relayfs_get_inode(struct super_block *sb, int mode,
+                                      struct rchan *chan)
+{
+       struct rchan_buf *buf = NULL;
+       struct inode *inode;
+
+       if (S_ISREG(mode)) {
+               BUG_ON(!chan);
+               buf = relay_create_buf(chan);
+               if (!buf)
+                       return NULL;
+       }
+
+       inode = new_inode(sb);
+       if (!inode) {
+               relay_destroy_buf(buf);
+               return NULL;
+       }
+
+       inode->i_mode = mode;
+       inode->i_uid = 0;
+       inode->i_gid = 0;
+       inode->i_blksize = PAGE_CACHE_SIZE;
+       inode->i_blocks = 0;
+       inode->i_mapping->backing_dev_info = &relayfs_backing_dev_info;
+       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       switch (mode & S_IFMT) {
+       case S_IFREG:
+               inode->i_fop = &relayfs_file_operations;
+               RELAYFS_I(inode)->buf = buf;
+               break;
+       case S_IFDIR:
+               inode->i_op = &simple_dir_inode_operations;
+               inode->i_fop = &simple_dir_operations;
+
+               /* directory inodes start off with i_nlink == 2 (for "." entry) */
+               inode->i_nlink++;
+               break;
+       default:
+               break;
+       }
+
+       return inode;
+}
+
+/**
+ *     relayfs_create_entry - create a relayfs directory or file
+ *     @name: the name of the file to create
+ *     @parent: parent directory
+ *     @mode: mode
+ *     @chan: relay channel associated with the file
+ *
+ *     Returns the new dentry, NULL on failure
+ *
+ *     Creates a file or directory with the specifed permissions.
+ */
+static struct dentry *relayfs_create_entry(const char *name,
+                                          struct dentry *parent,
+                                          int mode,
+                                          struct rchan *chan)
+{
+       struct dentry *d;
+       struct inode *inode;
+       int error = 0;
+
+       BUG_ON(!name || !(S_ISREG(mode) || S_ISDIR(mode)));
+
+       error = simple_pin_fs("relayfs", &relayfs_mount, &relayfs_mount_count);
+       if (error) {
+               printk(KERN_ERR "Couldn't mount relayfs: errcode %d\n", error);
+               return NULL;
+       }
+
+       if (!parent && relayfs_mount && relayfs_mount->mnt_sb)
+               parent = relayfs_mount->mnt_sb->s_root;
+
+       if (!parent) {
+               simple_release_fs(&relayfs_mount, &relayfs_mount_count);
+               return NULL;
+       }
+
+       parent = dget(parent);
+       down(&parent->d_inode->i_sem);
+       d = lookup_one_len(name, parent, strlen(name));
+       if (IS_ERR(d)) {
+               d = NULL;
+               goto release_mount;
+       }
+
+       if (d->d_inode) {
+               d = NULL;
+               goto release_mount;
+       }
+
+       inode = relayfs_get_inode(parent->d_inode->i_sb, mode, chan);
+       if (!inode) {
+               d = NULL;
+               goto release_mount;
+       }
+
+       d_instantiate(d, inode);
+       dget(d);        /* Extra count - pin the dentry in core */
+
+       if (S_ISDIR(mode))
+               parent->d_inode->i_nlink++;
+
+       goto exit;
+
+release_mount:
+       simple_release_fs(&relayfs_mount, &relayfs_mount_count);
+
+exit:
+       up(&parent->d_inode->i_sem);
+       dput(parent);
+       return d;
+}
+
+/**
+ *     relayfs_create_file - create a file in the relay filesystem
+ *     @name: the name of the file to create
+ *     @parent: parent directory
+ *     @mode: mode, if not specied the default perms are used
+ *     @chan: channel associated with the file
+ *
+ *     Returns file dentry if successful, NULL otherwise.
+ *
+ *     The file will be created user r on behalf of current user.
+ */
+struct dentry *relayfs_create_file(const char *name, struct dentry *parent,
+                                  int mode, struct rchan *chan)
+{
+       if (!mode)
+               mode = S_IRUSR;
+       mode = (mode & S_IALLUGO) | S_IFREG;
+
+       return relayfs_create_entry(name, parent, mode, chan);
+}
+
+/**
+ *     relayfs_create_dir - create a directory in the relay filesystem
+ *     @name: the name of the directory to create
+ *     @parent: parent directory, NULL if parent should be fs root
+ *
+ *     Returns directory dentry if successful, NULL otherwise.
+ *
+ *     The directory will be created world rwx on behalf of current user.
+ */
+struct dentry *relayfs_create_dir(const char *name, struct dentry *parent)
+{
+       int mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
+       return relayfs_create_entry(name, parent, mode, NULL);
+}
+
+/**
+ *     relayfs_remove - remove a file or directory in the relay filesystem
+ *     @dentry: file or directory dentry
+ *
+ *     Returns 0 if successful, negative otherwise.
+ */
+int relayfs_remove(struct dentry *dentry)
+{
+       struct dentry *parent;
+       int error = 0;
+
+       if (!dentry)
+               return -EINVAL;
+       parent = dentry->d_parent;
+       if (!parent)
+               return -EINVAL;
+
+       parent = dget(parent);
+       down(&parent->d_inode->i_sem);
+       if (dentry->d_inode) {
+               if (S_ISDIR(dentry->d_inode->i_mode))
+                       error = simple_rmdir(parent->d_inode, dentry);
+               else
+                       error = simple_unlink(parent->d_inode, dentry);
+               if (!error)
+                       d_delete(dentry);
+       }
+       if (!error)
+               dput(dentry);
+       up(&parent->d_inode->i_sem);
+       dput(parent);
+
+       if (!error)
+               simple_release_fs(&relayfs_mount, &relayfs_mount_count);
+
+       return error;
+}
+
+/**
+ *     relayfs_remove_dir - remove a directory in the relay filesystem
+ *     @dentry: directory dentry
+ *
+ *     Returns 0 if successful, negative otherwise.
+ */
+int relayfs_remove_dir(struct dentry *dentry)
+{
+       return relayfs_remove(dentry);
+}
+
+/**
+ *     relayfs_open - open file op for relayfs files
+ *     @inode: the inode
+ *     @filp: the file
+ *
+ *     Increments the channel buffer refcount.
+ */
+static int relayfs_open(struct inode *inode, struct file *filp)
+{
+       struct rchan_buf *buf = RELAYFS_I(inode)->buf;
+       kref_get(&buf->kref);
+
+       return 0;
+}
+
+/**
+ *     relayfs_mmap - mmap file op for relayfs files
+ *     @filp: the file
+ *     @vma: the vma describing what to map
+ *
+ *     Calls upon relay_mmap_buf to map the file into user space.
+ */
+static int relayfs_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct inode *inode = filp->f_dentry->d_inode;
+       return relay_mmap_buf(RELAYFS_I(inode)->buf, vma);
+}
+
+/**
+ *     relayfs_poll - poll file op for relayfs files
+ *     @filp: the file
+ *     @wait: poll table
+ *
+ *     Poll implemention.
+ */
+static unsigned int relayfs_poll(struct file *filp, poll_table *wait)
+{
+       unsigned int mask = 0;
+       struct inode *inode = filp->f_dentry->d_inode;
+       struct rchan_buf *buf = RELAYFS_I(inode)->buf;
+
+       if (buf->finalized)
+               return POLLERR;
+
+       if (filp->f_mode & FMODE_READ) {
+               poll_wait(filp, &buf->read_wait, wait);
+               if (!relay_buf_empty(buf))
+                       mask |= POLLIN | POLLRDNORM;
+       }
+
+       return mask;
+}
+
+/**
+ *     relayfs_release - release file op for relayfs files
+ *     @inode: the inode
+ *     @filp: the file
+ *
+ *     Decrements the channel refcount, as the filesystem is
+ *     no longer using it.
+ */
+static int relayfs_release(struct inode *inode, struct file *filp)
+{
+       struct rchan_buf *buf = RELAYFS_I(inode)->buf;
+       kref_put(&buf->kref, relay_remove_buf);
+
+       return 0;
+}
+
+/**
+ *     relayfs_read_consume - update the consumed count for the buffer
+ */
+static void relayfs_read_consume(struct rchan_buf *buf,
+                                size_t read_pos,
+                                size_t bytes_consumed)
+{
+       size_t subbuf_size = buf->chan->subbuf_size;
+       size_t n_subbufs = buf->chan->n_subbufs;
+       size_t read_subbuf;
+
+       if (buf->bytes_consumed + bytes_consumed > subbuf_size) {
+               relay_subbufs_consumed(buf->chan, buf->cpu, 1);
+               buf->bytes_consumed = 0;
+       }
+
+       buf->bytes_consumed += bytes_consumed;
+       read_subbuf = read_pos / buf->chan->subbuf_size;
+       if (buf->bytes_consumed + buf->padding[read_subbuf] == subbuf_size) {
+               if ((read_subbuf == buf->subbufs_produced % n_subbufs) &&
+                   (buf->offset == subbuf_size))
+                       return;
+               relay_subbufs_consumed(buf->chan, buf->cpu, 1);
+               buf->bytes_consumed = 0;
+       }
+}
+
+/**
+ *     relayfs_read_avail - boolean, are there unconsumed bytes available?
+ */
+static int relayfs_read_avail(struct rchan_buf *buf, size_t read_pos)
+{
+       size_t bytes_produced, bytes_consumed, write_offset;
+       size_t subbuf_size = buf->chan->subbuf_size;
+       size_t n_subbufs = buf->chan->n_subbufs;
+       size_t produced = buf->subbufs_produced % n_subbufs;
+       size_t consumed = buf->subbufs_consumed % n_subbufs;
+
+       write_offset = buf->offset > subbuf_size ? subbuf_size : buf->offset;
+
+       if (consumed > produced) {
+               if ((produced > n_subbufs) &&
+                   (produced + n_subbufs - consumed <= n_subbufs))
+                       produced += n_subbufs;
+       } else if (consumed == produced) {
+               if (buf->offset > subbuf_size) {
+                       produced += n_subbufs;
+                       if (buf->subbufs_produced == buf->subbufs_consumed)
+                               consumed += n_subbufs;
+               }
+       }
+
+       if (buf->offset > subbuf_size)
+               bytes_produced = (produced - 1) * subbuf_size + write_offset;
+       else
+               bytes_produced = produced * subbuf_size + write_offset;
+       bytes_consumed = consumed * subbuf_size + buf->bytes_consumed;
+
+       if (bytes_produced == bytes_consumed)
+               return 0;
+
+       relayfs_read_consume(buf, read_pos, 0);
+
+       return 1;
+}
+
+/**
+ *     relayfs_read_subbuf_avail - return bytes available in sub-buffer
+ */
+static size_t relayfs_read_subbuf_avail(size_t read_pos,
+                                       struct rchan_buf *buf)
+{
+       size_t padding, avail = 0;
+       size_t read_subbuf, read_offset, write_subbuf, write_offset;
+       size_t subbuf_size = buf->chan->subbuf_size;
+
+       write_subbuf = (buf->data - buf->start) / subbuf_size;
+       write_offset = buf->offset > subbuf_size ? subbuf_size : buf->offset;
+       read_subbuf = read_pos / subbuf_size;
+       read_offset = read_pos % subbuf_size;
+       padding = buf->padding[read_subbuf];
+
+       if (read_subbuf == write_subbuf) {
+               if (read_offset + padding < write_offset)
+                       avail = write_offset - (read_offset + padding);
+       } else
+               avail = (subbuf_size - padding) - read_offset;
+
+       return avail;
+}
+
+/**
+ *     relayfs_read_start_pos - find the first available byte to read
+ *
+ *     If the read_pos is in the middle of padding, return the
+ *     position of the first actually available byte, otherwise
+ *     return the original value.
+ */
+static size_t relayfs_read_start_pos(size_t read_pos,
+                                    struct rchan_buf *buf)
+{
+       size_t read_subbuf, padding, padding_start, padding_end;
+       size_t subbuf_size = buf->chan->subbuf_size;
+       size_t n_subbufs = buf->chan->n_subbufs;
+
+       read_subbuf = read_pos / subbuf_size;
+       padding = buf->padding[read_subbuf];
+       padding_start = (read_subbuf + 1) * subbuf_size - padding;
+       padding_end = (read_subbuf + 1) * subbuf_size;
+       if (read_pos >= padding_start && read_pos < padding_end) {
+               read_subbuf = (read_subbuf + 1) % n_subbufs;
+               read_pos = read_subbuf * subbuf_size;
+       }
+
+       return read_pos;
+}
+
+/**
+ *     relayfs_read_end_pos - return the new read position
+ */
+static size_t relayfs_read_end_pos(struct rchan_buf *buf,
+                                  size_t read_pos,
+                                  size_t count)
+{
+       size_t read_subbuf, padding, end_pos;
+       size_t subbuf_size = buf->chan->subbuf_size;
+       size_t n_subbufs = buf->chan->n_subbufs;
+
+       read_subbuf = read_pos / subbuf_size;
+       padding = buf->padding[read_subbuf];
+       if (read_pos % subbuf_size + count + padding == subbuf_size)
+               end_pos = (read_subbuf + 1) * subbuf_size;
+       else
+               end_pos = read_pos + count;
+       if (end_pos >= subbuf_size * n_subbufs)
+               end_pos = 0;
+
+       return end_pos;
+}
+
+/**
+ *     relayfs_read - read file op for relayfs files
+ *     @filp: the file
+ *     @buffer: the userspace buffer
+ *     @count: number of bytes to read
+ *     @ppos: position to read from
+ *
+ *     Reads count bytes or the number of bytes available in the
+ *     current sub-buffer being read, whichever is smaller.
+ */
+static ssize_t relayfs_read(struct file *filp,
+                           char __user *buffer,
+                           size_t count,
+                           loff_t *ppos)
+{
+       struct inode *inode = filp->f_dentry->d_inode;
+       struct rchan_buf *buf = RELAYFS_I(inode)->buf;
+       size_t read_start, avail;
+       ssize_t ret = 0;
+       void *from;
+
+       down(&inode->i_sem);
+       if(!relayfs_read_avail(buf, *ppos))
+               goto out;
+
+       read_start = relayfs_read_start_pos(*ppos, buf);
+       avail = relayfs_read_subbuf_avail(read_start, buf);
+       if (!avail)
+               goto out;
+
+       from = buf->start + read_start;
+       ret = count = min(count, avail);
+       if (copy_to_user(buffer, from, count)) {
+               ret = -EFAULT;
+               goto out;
+       }
+       relayfs_read_consume(buf, read_start, count);
+       *ppos = relayfs_read_end_pos(buf, read_start, count);
+out:
+       up(&inode->i_sem);
+       return ret;
+}
+
+/**
+ *     relayfs alloc_inode() implementation
+ */
+static struct inode *relayfs_alloc_inode(struct super_block *sb)
+{
+       struct relayfs_inode_info *p = kmem_cache_alloc(relayfs_inode_cachep, SLAB_KERNEL);
+       if (!p)
+               return NULL;
+       p->buf = NULL;
+
+       return &p->vfs_inode;
+}
+
+/**
+ *     relayfs destroy_inode() implementation
+ */
+static void relayfs_destroy_inode(struct inode *inode)
+{
+       if (RELAYFS_I(inode)->buf)
+               relay_destroy_buf(RELAYFS_I(inode)->buf);
+
+       kmem_cache_free(relayfs_inode_cachep, RELAYFS_I(inode));
+}
+
+static void init_once(void *p, kmem_cache_t *cachep, unsigned long flags)
+{
+       struct relayfs_inode_info *i = p;
+       if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR)
+               inode_init_once(&i->vfs_inode);
+}
+
+struct file_operations relayfs_file_operations = {
+       .open           = relayfs_open,
+       .poll           = relayfs_poll,
+       .mmap           = relayfs_mmap,
+       .read           = relayfs_read,
+       .llseek         = no_llseek,
+       .release        = relayfs_release,
+};
+
+static struct super_operations relayfs_ops = {
+       .statfs         = simple_statfs,
+       .drop_inode     = generic_delete_inode,
+       .alloc_inode    = relayfs_alloc_inode,
+       .destroy_inode  = relayfs_destroy_inode,
+};
+
+static int relayfs_fill_super(struct super_block * sb, void * data, int silent)
+{
+       struct inode *inode;
+       struct dentry *root;
+       int mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
+
+       sb->s_blocksize = PAGE_CACHE_SIZE;
+       sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+       sb->s_magic = RELAYFS_MAGIC;
+       sb->s_op = &relayfs_ops;
+       inode = relayfs_get_inode(sb, mode, NULL);
+
+       if (!inode)
+               return -ENOMEM;
+
+       root = d_alloc_root(inode);
+       if (!root) {
+               iput(inode);
+               return -ENOMEM;
+       }
+       sb->s_root = root;
+
+       return 0;
+}
+
+static struct super_block * relayfs_get_sb(struct file_system_type *fs_type,
+                                          int flags, const char *dev_name,
+                                          void *data)
+{
+       return get_sb_single(fs_type, flags, data, relayfs_fill_super);
+}
+
+static struct file_system_type relayfs_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "relayfs",
+       .get_sb         = relayfs_get_sb,
+       .kill_sb        = kill_litter_super,
+};
+
+static int __init init_relayfs_fs(void)
+{
+       int err;
+
+       relayfs_inode_cachep = kmem_cache_create("relayfs_inode_cache",
+                               sizeof(struct relayfs_inode_info), 0,
+                               0, init_once, NULL);
+       if (!relayfs_inode_cachep)
+               return -ENOMEM;
+
+       err = register_filesystem(&relayfs_fs_type);
+       if (err)
+               kmem_cache_destroy(relayfs_inode_cachep);
+
+       return err;
+}
+
+static void __exit exit_relayfs_fs(void)
+{
+       unregister_filesystem(&relayfs_fs_type);
+       kmem_cache_destroy(relayfs_inode_cachep);
+}
+
+module_init(init_relayfs_fs)
+module_exit(exit_relayfs_fs)
+
+EXPORT_SYMBOL_GPL(relayfs_file_operations);
+EXPORT_SYMBOL_GPL(relayfs_create_dir);
+EXPORT_SYMBOL_GPL(relayfs_remove_dir);
+
+MODULE_AUTHOR("Tom Zanussi <zanussi@us.ibm.com> and Karim Yaghmour <karim@opersys.com>");
+MODULE_DESCRIPTION("Relay Filesystem");
+MODULE_LICENSE("GPL");
+
diff --git a/fs/relayfs/relay.c b/fs/relayfs/relay.c
new file mode 100644 (file)
index 0000000..16446a1
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * Public API and common code for RelayFS.
+ *
+ * See Documentation/filesystems/relayfs.txt for an overview of relayfs.
+ *
+ * Copyright (C) 2002-2005 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
+ * Copyright (C) 1999-2005 - Karim Yaghmour (karim@opersys.com)
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/errno.h>
+#include <linux/stddef.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/relayfs_fs.h>
+#include "relay.h"
+#include "buffers.h"
+
+/**
+ *     relay_buf_empty - boolean, is the channel buffer empty?
+ *     @buf: channel buffer
+ *
+ *     Returns 1 if the buffer is empty, 0 otherwise.
+ */
+int relay_buf_empty(struct rchan_buf *buf)
+{
+       return (buf->subbufs_produced - buf->subbufs_consumed) ? 0 : 1;
+}
+
+/**
+ *     relay_buf_full - boolean, is the channel buffer full?
+ *     @buf: channel buffer
+ *
+ *     Returns 1 if the buffer is full, 0 otherwise.
+ */
+int relay_buf_full(struct rchan_buf *buf)
+{
+       size_t ready = buf->subbufs_produced - buf->subbufs_consumed;
+       return (ready >= buf->chan->n_subbufs) ? 1 : 0;
+}
+
+/*
+ * High-level relayfs kernel API and associated functions.
+ */
+
+/*
+ * rchan_callback implementations defining default channel behavior.  Used
+ * in place of corresponding NULL values in client callback struct.
+ */
+
+/*
+ * subbuf_start() default callback.  Does nothing.
+ */
+static int subbuf_start_default_callback (struct rchan_buf *buf,
+                                         void *subbuf,
+                                         void *prev_subbuf,
+                                         size_t prev_padding)
+{
+       if (relay_buf_full(buf))
+               return 0;
+
+       return 1;
+}
+
+/*
+ * buf_mapped() default callback.  Does nothing.
+ */
+static void buf_mapped_default_callback(struct rchan_buf *buf,
+                                       struct file *filp)
+{
+}
+
+/*
+ * buf_unmapped() default callback.  Does nothing.
+ */
+static void buf_unmapped_default_callback(struct rchan_buf *buf,
+                                         struct file *filp)
+{
+}
+
+/* relay channel default callbacks */
+static struct rchan_callbacks default_channel_callbacks = {
+       .subbuf_start = subbuf_start_default_callback,
+       .buf_mapped = buf_mapped_default_callback,
+       .buf_unmapped = buf_unmapped_default_callback,
+};
+
+/**
+ *     wakeup_readers - wake up readers waiting on a channel
+ *     @private: the channel buffer
+ *
+ *     This is the work function used to defer reader waking.  The
+ *     reason waking is deferred is that calling directly from write
+ *     causes problems if you're writing from say the scheduler.
+ */
+static void wakeup_readers(void *private)
+{
+       struct rchan_buf *buf = private;
+       wake_up_interruptible(&buf->read_wait);
+}
+
+/**
+ *     __relay_reset - reset a channel buffer
+ *     @buf: the channel buffer
+ *     @init: 1 if this is a first-time initialization
+ *
+ *     See relay_reset for description of effect.
+ */
+static inline void __relay_reset(struct rchan_buf *buf, unsigned int init)
+{
+       size_t i;
+
+       if (init) {
+               init_waitqueue_head(&buf->read_wait);
+               kref_init(&buf->kref);
+               INIT_WORK(&buf->wake_readers, NULL, NULL);
+       } else {
+               cancel_delayed_work(&buf->wake_readers);
+               flush_scheduled_work();
+       }
+
+       buf->subbufs_produced = 0;
+       buf->subbufs_consumed = 0;
+       buf->bytes_consumed = 0;
+       buf->finalized = 0;
+       buf->data = buf->start;
+       buf->offset = 0;
+
+       for (i = 0; i < buf->chan->n_subbufs; i++)
+               buf->padding[i] = 0;
+
+       buf->chan->cb->subbuf_start(buf, buf->data, NULL, 0);
+}
+
+/**
+ *     relay_reset - reset the channel
+ *     @chan: the channel
+ *
+ *     This has the effect of erasing all data from all channel buffers
+ *     and restarting the channel in its initial state.  The buffers
+ *     are not freed, so any mappings are still in effect.
+ *
+ *     NOTE: Care should be taken that the channel isn't actually
+ *     being used by anything when this call is made.
+ */
+void relay_reset(struct rchan *chan)
+{
+       unsigned int i;
+
+       if (!chan)
+               return;
+
+       for (i = 0; i < NR_CPUS; i++) {
+               if (!chan->buf[i])
+                       continue;
+               __relay_reset(chan->buf[i], 0);
+       }
+}
+
+/**
+ *     relay_open_buf - create a new channel buffer in relayfs
+ *
+ *     Internal - used by relay_open().
+ */
+static struct rchan_buf *relay_open_buf(struct rchan *chan,
+                                       const char *filename,
+                                       struct dentry *parent)
+{
+       struct rchan_buf *buf;
+       struct dentry *dentry;
+
+       /* Create file in fs */
+       dentry = relayfs_create_file(filename, parent, S_IRUSR, chan);
+       if (!dentry)
+               return NULL;
+
+       buf = RELAYFS_I(dentry->d_inode)->buf;
+       buf->dentry = dentry;
+       __relay_reset(buf, 1);
+
+       return buf;
+}
+
+/**
+ *     relay_close_buf - close a channel buffer
+ *     @buf: channel buffer
+ *
+ *     Marks the buffer finalized and restores the default callbacks.
+ *     The channel buffer and channel buffer data structure are then freed
+ *     automatically when the last reference is given up.
+ */
+static inline void relay_close_buf(struct rchan_buf *buf)
+{
+       buf->finalized = 1;
+       buf->chan->cb = &default_channel_callbacks;
+       cancel_delayed_work(&buf->wake_readers);
+       flush_scheduled_work();
+       kref_put(&buf->kref, relay_remove_buf);
+}
+
+static inline void setup_callbacks(struct rchan *chan,
+                                  struct rchan_callbacks *cb)
+{
+       if (!cb) {
+               chan->cb = &default_channel_callbacks;
+               return;
+       }
+
+       if (!cb->subbuf_start)
+               cb->subbuf_start = subbuf_start_default_callback;
+       if (!cb->buf_mapped)
+               cb->buf_mapped = buf_mapped_default_callback;
+       if (!cb->buf_unmapped)
+               cb->buf_unmapped = buf_unmapped_default_callback;
+       chan->cb = cb;
+}
+
+/**
+ *     relay_open - create a new relayfs channel
+ *     @base_filename: base name of files to create
+ *     @parent: dentry of parent directory, NULL for root directory
+ *     @subbuf_size: size of sub-buffers
+ *     @n_subbufs: number of sub-buffers
+ *     @cb: client callback functions
+ *
+ *     Returns channel pointer if successful, NULL otherwise.
+ *
+ *     Creates a channel buffer for each cpu using the sizes and
+ *     attributes specified.  The created channel buffer files
+ *     will be named base_filename0...base_filenameN-1.  File
+ *     permissions will be S_IRUSR.
+ */
+struct rchan *relay_open(const char *base_filename,
+                        struct dentry *parent,
+                        size_t subbuf_size,
+                        size_t n_subbufs,
+                        struct rchan_callbacks *cb)
+{
+       unsigned int i;
+       struct rchan *chan;
+       char *tmpname;
+
+       if (!base_filename)
+               return NULL;
+
+       if (!(subbuf_size && n_subbufs))
+               return NULL;
+
+       chan = kcalloc(1, sizeof(struct rchan), GFP_KERNEL);
+       if (!chan)
+               return NULL;
+
+       chan->version = RELAYFS_CHANNEL_VERSION;
+       chan->n_subbufs = n_subbufs;
+       chan->subbuf_size = subbuf_size;
+       chan->alloc_size = FIX_SIZE(subbuf_size * n_subbufs);
+       setup_callbacks(chan, cb);
+       kref_init(&chan->kref);
+
+       tmpname = kmalloc(NAME_MAX + 1, GFP_KERNEL);
+       if (!tmpname)
+               goto free_chan;
+
+       for_each_online_cpu(i) {
+               sprintf(tmpname, "%s%d", base_filename, i);
+               chan->buf[i] = relay_open_buf(chan, tmpname, parent);
+               chan->buf[i]->cpu = i;
+               if (!chan->buf[i])
+                       goto free_bufs;
+       }
+
+       kfree(tmpname);
+       return chan;
+
+free_bufs:
+       for (i = 0; i < NR_CPUS; i++) {
+               if (!chan->buf[i])
+                       break;
+               relay_close_buf(chan->buf[i]);
+       }
+       kfree(tmpname);
+
+free_chan:
+       kref_put(&chan->kref, relay_destroy_channel);
+       return NULL;
+}
+
+/**
+ *     relay_switch_subbuf - switch to a new sub-buffer
+ *     @buf: channel buffer
+ *     @length: size of current event
+ *
+ *     Returns either the length passed in or 0 if full.
+
+ *     Performs sub-buffer-switch tasks such as invoking callbacks,
+ *     updating padding counts, waking up readers, etc.
+ */
+size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length)
+{
+       void *old, *new;
+       size_t old_subbuf, new_subbuf;
+
+       if (unlikely(length > buf->chan->subbuf_size))
+               goto toobig;
+
+       if (buf->offset != buf->chan->subbuf_size + 1) {
+               buf->prev_padding = buf->chan->subbuf_size - buf->offset;
+               old_subbuf = buf->subbufs_produced % buf->chan->n_subbufs;
+               buf->padding[old_subbuf] = buf->prev_padding;
+               buf->subbufs_produced++;
+               if (waitqueue_active(&buf->read_wait)) {
+                       PREPARE_WORK(&buf->wake_readers, wakeup_readers, buf);
+                       schedule_delayed_work(&buf->wake_readers, 1);
+               }
+       }
+
+       old = buf->data;
+       new_subbuf = buf->subbufs_produced % buf->chan->n_subbufs;
+       new = buf->start + new_subbuf * buf->chan->subbuf_size;
+       buf->offset = 0;
+       if (!buf->chan->cb->subbuf_start(buf, new, old, buf->prev_padding)) {
+               buf->offset = buf->chan->subbuf_size + 1;
+               return 0;
+       }
+       buf->data = new;
+       buf->padding[new_subbuf] = 0;
+
+       if (unlikely(length + buf->offset > buf->chan->subbuf_size))
+               goto toobig;
+
+       return length;
+
+toobig:
+       printk(KERN_WARNING "relayfs: event too large (%Zd)\n", length);
+       WARN_ON(1);
+       return 0;
+}
+
+/**
+ *     relay_subbufs_consumed - update the buffer's sub-buffers-consumed count
+ *     @chan: the channel
+ *     @cpu: the cpu associated with the channel buffer to update
+ *     @subbufs_consumed: number of sub-buffers to add to current buf's count
+ *
+ *     Adds to the channel buffer's consumed sub-buffer count.
+ *     subbufs_consumed should be the number of sub-buffers newly consumed,
+ *     not the total consumed.
+ *
+ *     NOTE: kernel clients don't need to call this function if the channel
+ *     mode is 'overwrite'.
+ */
+void relay_subbufs_consumed(struct rchan *chan,
+                           unsigned int cpu,
+                           size_t subbufs_consumed)
+{
+       struct rchan_buf *buf;
+
+       if (!chan)
+               return;
+
+       if (cpu >= NR_CPUS || !chan->buf[cpu])
+               return;
+
+       buf = chan->buf[cpu];
+       buf->subbufs_consumed += subbufs_consumed;
+       if (buf->subbufs_consumed > buf->subbufs_produced)
+               buf->subbufs_consumed = buf->subbufs_produced;
+}
+
+/**
+ *     relay_destroy_channel - free the channel struct
+ *
+ *     Should only be called from kref_put().
+ */
+void relay_destroy_channel(struct kref *kref)
+{
+       struct rchan *chan = container_of(kref, struct rchan, kref);
+       kfree(chan);
+}
+
+/**
+ *     relay_close - close the channel
+ *     @chan: the channel
+ *
+ *     Closes all channel buffers and frees the channel.
+ */
+void relay_close(struct rchan *chan)
+{
+       unsigned int i;
+
+       if (!chan)
+               return;
+
+       for (i = 0; i < NR_CPUS; i++) {
+               if (!chan->buf[i])
+                       continue;
+               relay_close_buf(chan->buf[i]);
+       }
+
+       kref_put(&chan->kref, relay_destroy_channel);
+}
+
+/**
+ *     relay_flush - close the channel
+ *     @chan: the channel
+ *
+ *     Flushes all channel buffers i.e. forces buffer switch.
+ */
+void relay_flush(struct rchan *chan)
+{
+       unsigned int i;
+
+       if (!chan)
+               return;
+
+       for (i = 0; i < NR_CPUS; i++) {
+               if (!chan->buf[i])
+                       continue;
+               relay_switch_subbuf(chan->buf[i], 0);
+       }
+}
+
+EXPORT_SYMBOL_GPL(relay_open);
+EXPORT_SYMBOL_GPL(relay_close);
+EXPORT_SYMBOL_GPL(relay_flush);
+EXPORT_SYMBOL_GPL(relay_reset);
+EXPORT_SYMBOL_GPL(relay_subbufs_consumed);
+EXPORT_SYMBOL_GPL(relay_switch_subbuf);
+EXPORT_SYMBOL_GPL(relay_buf_full);
diff --git a/fs/relayfs/relay.h b/fs/relayfs/relay.h
new file mode 100644 (file)
index 0000000..703503f
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _RELAY_H
+#define _RELAY_H
+
+struct dentry *relayfs_create_file(const char *name,
+                                  struct dentry *parent,
+                                  int mode,
+                                  struct rchan *chan);
+extern int relayfs_remove(struct dentry *dentry);
+extern int relay_buf_empty(struct rchan_buf *buf);
+extern void relay_destroy_channel(struct kref *kref);
+
+#endif /* _RELAY_H */
index 93f3cd22a2e93f1885e62b6f3ab4c8cdeceb6204..6815b1b12b68853351a9af047031de63cfae7782 100644 (file)
 #include <linux/file.h>
 #include <linux/in.h>
 #include <linux/net.h>
-#include <linux/tcp.h>
 #include <linux/mm.h>
 #include <linux/netdevice.h>
 #include <linux/smp_lock.h>
 #include <linux/workqueue.h>
 #include <net/scm.h>
+#include <net/tcp_states.h>
 #include <net/ip.h>
 
 #include <linux/smb_fs.h>
index 997640c99c7d88030d2de6e980deee138a18db0e..faf1512173eb23d36cf861b651b3572ded618999 100644 (file)
@@ -114,8 +114,7 @@ void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count
        ubh_mark_buffer_dirty (USPI_UBH);
        ubh_mark_buffer_dirty (UCPI_UBH);
        if (sb->s_flags & MS_SYNCHRONOUS) {
-               ubh_wait_on_buffer (UCPI_UBH);
-               ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
+               ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
                ubh_wait_on_buffer (UCPI_UBH);
        }
        sb->s_dirt = 1;
@@ -200,8 +199,7 @@ do_more:
        ubh_mark_buffer_dirty (USPI_UBH);
        ubh_mark_buffer_dirty (UCPI_UBH);
        if (sb->s_flags & MS_SYNCHRONOUS) {
-               ubh_wait_on_buffer (UCPI_UBH);
-               ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
+               ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
                ubh_wait_on_buffer (UCPI_UBH);
        }
 
@@ -459,8 +457,7 @@ ufs_add_fragments (struct inode * inode, unsigned fragment,
        ubh_mark_buffer_dirty (USPI_UBH);
        ubh_mark_buffer_dirty (UCPI_UBH);
        if (sb->s_flags & MS_SYNCHRONOUS) {
-               ubh_wait_on_buffer (UCPI_UBH);
-               ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
+               ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
                ubh_wait_on_buffer (UCPI_UBH);
        }
        sb->s_dirt = 1;
@@ -585,8 +582,7 @@ succed:
        ubh_mark_buffer_dirty (USPI_UBH);
        ubh_mark_buffer_dirty (UCPI_UBH);
        if (sb->s_flags & MS_SYNCHRONOUS) {
-               ubh_wait_on_buffer (UCPI_UBH);
-               ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
+               ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
                ubh_wait_on_buffer (UCPI_UBH);
        }
        sb->s_dirt = 1;
index 61a6b1542fc5f01eb239cca652aaf7c2bd6d2b35..0938945b9cbc2c628750061a05f772ebeee670e5 100644 (file)
@@ -124,8 +124,7 @@ void ufs_free_inode (struct inode * inode)
        ubh_mark_buffer_dirty (USPI_UBH);
        ubh_mark_buffer_dirty (UCPI_UBH);
        if (sb->s_flags & MS_SYNCHRONOUS) {
-               ubh_wait_on_buffer (UCPI_UBH);
-               ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **) &ucpi);
+               ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **) &ucpi);
                ubh_wait_on_buffer (UCPI_UBH);
        }
        
@@ -249,8 +248,7 @@ cg_found:
        ubh_mark_buffer_dirty (USPI_UBH);
        ubh_mark_buffer_dirty (UCPI_UBH);
        if (sb->s_flags & MS_SYNCHRONOUS) {
-               ubh_wait_on_buffer (UCPI_UBH);
-               ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **) &ucpi);
+               ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **) &ucpi);
                ubh_wait_on_buffer (UCPI_UBH);
        }
        sb->s_dirt = 1;
index e312bf8bad9fd5432e44df7c9c36d31e1a63e545..61d2e35012a462e2cb6be0f9fc27bd10e20db0b1 100644 (file)
@@ -285,8 +285,7 @@ next:;
                }
        }
        if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) {
-               ubh_wait_on_buffer (ind_ubh);
-               ubh_ll_rw_block (WRITE, 1, &ind_ubh);
+               ubh_ll_rw_block (SWRITE, 1, &ind_ubh);
                ubh_wait_on_buffer (ind_ubh);
        }
        ubh_brelse (ind_ubh);
@@ -353,8 +352,7 @@ static int ufs_trunc_dindirect (struct inode *inode, unsigned offset, __fs32 *p)
                }
        }
        if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) {
-               ubh_wait_on_buffer (dind_bh);
-               ubh_ll_rw_block (WRITE, 1, &dind_bh);
+               ubh_ll_rw_block (SWRITE, 1, &dind_bh);
                ubh_wait_on_buffer (dind_bh);
        }
        ubh_brelse (dind_bh);
@@ -418,8 +416,7 @@ static int ufs_trunc_tindirect (struct inode * inode)
                }
        }
        if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) {
-               ubh_wait_on_buffer (tind_bh);
-               ubh_ll_rw_block (WRITE, 1, &tind_bh);
+               ubh_ll_rw_block (SWRITE, 1, &tind_bh);
                ubh_wait_on_buffer (tind_bh);
        }
        ubh_brelse (tind_bh);
diff --git a/fs/umsdos/notes b/fs/umsdos/notes
deleted file mode 100644 (file)
index 3c47d1f..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-This file contain idea and things I don't want to forget
-
-Possible bug in fs/read_write.c
-Function sys_readdir()
-
-       There is a call the verify_area that does not take in account
-       the count parameter. I guess it should read
-
-       error = verify_area(VERIFY_WRITE, dirent, count*sizeof (*dirent));
-
-       instead of
-
-       error = verify_area(VERIFY_WRITE, dirent, sizeof (*dirent));
-
-       Of course, now , count is always 1
-
-
index 6acd5c63da9113613132492dea834d8304554fd8..3f9c64bea151fd7c6df4297e8bfa01b626a02bd5 100644 (file)
@@ -51,20 +51,29 @@ setxattr(struct dentry *d, char __user *name, void __user *value,
                }
        }
 
+       down(&d->d_inode->i_sem);
+       error = security_inode_setxattr(d, kname, kvalue, size, flags);
+       if (error)
+               goto out;
        error = -EOPNOTSUPP;
        if (d->d_inode->i_op && d->d_inode->i_op->setxattr) {
-               down(&d->d_inode->i_sem);
-               error = security_inode_setxattr(d, kname, kvalue, size, flags);
-               if (error)
-                       goto out;
-               error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags);
+               error = d->d_inode->i_op->setxattr(d, kname, kvalue,
+                                                  size, flags);
                if (!error) {
                        fsnotify_xattr(d);
-                       security_inode_post_setxattr(d, kname, kvalue, size, flags);
+                       security_inode_post_setxattr(d, kname, kvalue,
+                                                    size, flags);
                }
-out:
-               up(&d->d_inode->i_sem);
+       } else if (!strncmp(kname, XATTR_SECURITY_PREFIX,
+                           sizeof XATTR_SECURITY_PREFIX - 1)) {
+               const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1;
+               error = security_inode_setsecurity(d->d_inode, suffix, kvalue,
+                                                  size, flags);
+               if (!error)
+                       fsnotify_xattr(d);
        }
+out:
+       up(&d->d_inode->i_sem);
        if (kvalue)
                kfree(kvalue);
        return error;
@@ -139,20 +148,25 @@ getxattr(struct dentry *d, char __user *name, void __user *value, size_t size)
                        return -ENOMEM;
        }
 
+       error = security_inode_getxattr(d, kname);
+       if (error)
+               goto out;
        error = -EOPNOTSUPP;
-       if (d->d_inode->i_op && d->d_inode->i_op->getxattr) {
-               error = security_inode_getxattr(d, kname);
-               if (error)
-                       goto out;
+       if (d->d_inode->i_op && d->d_inode->i_op->getxattr)
                error = d->d_inode->i_op->getxattr(d, kname, kvalue, size);
-               if (error > 0) {
-                       if (size && copy_to_user(value, kvalue, error))
-                               error = -EFAULT;
-               } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
-                       /* The file system tried to returned a value bigger
-                          than XATTR_SIZE_MAX bytes. Not possible. */
-                       error = -E2BIG;
-               }
+       else if (!strncmp(kname, XATTR_SECURITY_PREFIX,
+                         sizeof XATTR_SECURITY_PREFIX - 1)) {
+               const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1;
+               error = security_inode_getsecurity(d->d_inode, suffix, kvalue,
+                                                  size);
+       }
+       if (error > 0) {
+               if (size && copy_to_user(value, kvalue, error))
+                       error = -EFAULT;
+       } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
+               /* The file system tried to returned a value bigger
+                  than XATTR_SIZE_MAX bytes. Not possible. */
+               error = -E2BIG;
        }
 out:
        if (kvalue)
@@ -221,20 +235,24 @@ listxattr(struct dentry *d, char __user *list, size_t size)
                        return -ENOMEM;
        }
 
+       error = security_inode_listxattr(d);
+       if (error)
+               goto out;
        error = -EOPNOTSUPP;
        if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
-               error = security_inode_listxattr(d);
-               if (error)
-                       goto out;
                error = d->d_inode->i_op->listxattr(d, klist, size);
-               if (error > 0) {
-                       if (size && copy_to_user(list, klist, error))
-                               error = -EFAULT;
-               } else if (error == -ERANGE && size >= XATTR_LIST_MAX) {
-                       /* The file system tried to returned a list bigger
-                          than XATTR_LIST_MAX bytes. Not possible. */
-                       error = -E2BIG;
-               }
+       } else {
+               error = security_inode_listsecurity(d->d_inode, klist, size);
+               if (size && error >= size)
+                       error = -ERANGE;
+       }
+       if (error > 0) {
+               if (size && copy_to_user(list, klist, error))
+                       error = -EFAULT;
+       } else if (error == -ERANGE && size >= XATTR_LIST_MAX) {
+               /* The file system tried to returned a list bigger
+                  than XATTR_LIST_MAX bytes. Not possible. */
+               error = -E2BIG;
        }
 out:
        if (klist)
@@ -307,6 +325,8 @@ removexattr(struct dentry *d, char __user *name)
                down(&d->d_inode->i_sem);
                error = d->d_inode->i_op->removexattr(d, kname);
                up(&d->d_inode->i_sem);
+               if (!error)
+                       fsnotify_xattr(d);
        }
 out:
        return error;
index d3ff78354638d671be016821323e4a3279f47446..49e3e7e5e3dc90902ae5ffcaed0fd3256fef3e52 100644 (file)
@@ -1,150 +1 @@
-#
-# Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of version 2 of the GNU General Public License as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it would be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-#
-# Further, this software is distributed without any warranty that it is
-# free of the rightful claim of any third person regarding infringement
-# or the like.  Any license provided herein, whether implied or
-# otherwise, applies only to this software file.  Patent licenses, if
-# any, provided herein do not apply to combinations of this program with
-# other software, or any other product whatsoever.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write the Free Software Foundation, Inc., 59
-# Temple Place - Suite 330, Boston MA 02111-1307, USA.
-#
-# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
-# Mountain View, CA  94043, or:
-#
-# http://www.sgi.com
-#
-# For further information regarding this notice, see:
-#
-# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
-#
-
-EXTRA_CFLAGS +=         -Ifs/xfs -Ifs/xfs/linux-2.6 -funsigned-char
-
-ifeq ($(CONFIG_XFS_DEBUG),y)
-       EXTRA_CFLAGS += -g -DSTATIC="" -DDEBUG
-       EXTRA_CFLAGS += -DPAGEBUF_LOCK_TRACKING
-endif
-ifeq ($(CONFIG_XFS_TRACE),y)
-       EXTRA_CFLAGS += -DXFS_ALLOC_TRACE
-       EXTRA_CFLAGS += -DXFS_ATTR_TRACE
-       EXTRA_CFLAGS += -DXFS_BLI_TRACE
-       EXTRA_CFLAGS += -DXFS_BMAP_TRACE
-       EXTRA_CFLAGS += -DXFS_BMBT_TRACE
-       EXTRA_CFLAGS += -DXFS_DIR_TRACE
-       EXTRA_CFLAGS += -DXFS_DIR2_TRACE
-       EXTRA_CFLAGS += -DXFS_DQUOT_TRACE
-       EXTRA_CFLAGS += -DXFS_ILOCK_TRACE
-       EXTRA_CFLAGS += -DXFS_LOG_TRACE
-       EXTRA_CFLAGS += -DXFS_RW_TRACE
-       EXTRA_CFLAGS += -DPAGEBUF_TRACE
-       EXTRA_CFLAGS += -DXFS_VNODE_TRACE
-endif
-
-obj-$(CONFIG_XFS_FS)           += xfs.o
-
-xfs-$(CONFIG_XFS_QUOTA)                += $(addprefix quota/, \
-                                  xfs_dquot.o \
-                                  xfs_dquot_item.o \
-                                  xfs_trans_dquot.o \
-                                  xfs_qm_syscalls.o \
-                                  xfs_qm_bhv.o \
-                                  xfs_qm.o)
-ifeq ($(CONFIG_XFS_QUOTA),y)
-xfs-$(CONFIG_PROC_FS)          += quota/xfs_qm_stats.o
-endif
-
-xfs-$(CONFIG_XFS_RT)           += xfs_rtalloc.o
-xfs-$(CONFIG_XFS_POSIX_ACL)    += xfs_acl.o
-xfs-$(CONFIG_PROC_FS)          += linux-2.6/xfs_stats.o
-xfs-$(CONFIG_SYSCTL)           += linux-2.6/xfs_sysctl.o
-xfs-$(CONFIG_COMPAT)           += linux-2.6/xfs_ioctl32.o
-xfs-$(CONFIG_XFS_EXPORT)       += linux-2.6/xfs_export.o
-
-
-xfs-y                          += xfs_alloc.o \
-                                  xfs_alloc_btree.o \
-                                  xfs_attr.o \
-                                  xfs_attr_leaf.o \
-                                  xfs_behavior.o \
-                                  xfs_bit.o \
-                                  xfs_bmap.o \
-                                  xfs_bmap_btree.o \
-                                  xfs_btree.o \
-                                  xfs_buf_item.o \
-                                  xfs_da_btree.o \
-                                  xfs_dir.o \
-                                  xfs_dir2.o \
-                                  xfs_dir2_block.o \
-                                  xfs_dir2_data.o \
-                                  xfs_dir2_leaf.o \
-                                  xfs_dir2_node.o \
-                                  xfs_dir2_sf.o \
-                                  xfs_dir_leaf.o \
-                                  xfs_error.o \
-                                  xfs_extfree_item.o \
-                                  xfs_fsops.o \
-                                  xfs_ialloc.o \
-                                  xfs_ialloc_btree.o \
-                                  xfs_iget.o \
-                                  xfs_inode.o \
-                                  xfs_inode_item.o \
-                                  xfs_iocore.o \
-                                  xfs_iomap.o \
-                                  xfs_itable.o \
-                                  xfs_dfrag.o \
-                                  xfs_log.o \
-                                  xfs_log_recover.o \
-                                  xfs_macros.o \
-                                  xfs_mount.o \
-                                  xfs_rename.o \
-                                  xfs_trans.o \
-                                  xfs_trans_ail.o \
-                                  xfs_trans_buf.o \
-                                  xfs_trans_extfree.o \
-                                  xfs_trans_inode.o \
-                                  xfs_trans_item.o \
-                                  xfs_utils.o \
-                                  xfs_vfsops.o \
-                                  xfs_vnodeops.o \
-                                  xfs_rw.o \
-                                  xfs_dmops.o \
-                                  xfs_qmops.o
-
-xfs-$(CONFIG_XFS_TRACE)                += xfs_dir2_trace.o
-
-# Objects in linux-2.6/
-xfs-y                          += $(addprefix linux-2.6/, \
-                                  kmem.o \
-                                  xfs_aops.o \
-                                  xfs_buf.o \
-                                  xfs_file.o \
-                                  xfs_fs_subr.o \
-                                  xfs_globals.o \
-                                  xfs_ioctl.o \
-                                  xfs_iops.o \
-                                  xfs_lrw.o \
-                                  xfs_super.o \
-                                  xfs_vfs.o \
-                                  xfs_vnode.o)
-
-# Objects in support/
-xfs-y                          += $(addprefix support/, \
-                                  debug.o \
-                                  move.o \
-                                  qsort.o \
-                                  uuid.o)
-
-xfs-$(CONFIG_XFS_TRACE)                += support/ktrace.o
-
+include $(TOPDIR)/fs/xfs/Makefile-linux-$(VERSION).$(PATCHLEVEL)
diff --git a/fs/xfs/Makefile-linux-2.6 b/fs/xfs/Makefile-linux-2.6
new file mode 100644 (file)
index 0000000..fbfcbe5
--- /dev/null
@@ -0,0 +1,141 @@
+#
+# Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like.  Any license provided herein, whether implied or
+# otherwise, applies only to this software file.  Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+# Mountain View, CA  94043, or:
+#
+# http://www.sgi.com
+#
+# For further information regarding this notice, see:
+#
+# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+
+EXTRA_CFLAGS +=         -Ifs/xfs -Ifs/xfs/linux-2.6 -funsigned-char
+
+XFS_LINUX := linux-2.6
+
+ifeq ($(CONFIG_XFS_DEBUG),y)
+       EXTRA_CFLAGS += -g -DSTATIC="" -DDEBUG
+       EXTRA_CFLAGS += -DPAGEBUF_LOCK_TRACKING
+endif
+ifeq ($(CONFIG_XFS_TRACE),y)
+       EXTRA_CFLAGS += -DXFS_ALLOC_TRACE
+       EXTRA_CFLAGS += -DXFS_ATTR_TRACE
+       EXTRA_CFLAGS += -DXFS_BLI_TRACE
+       EXTRA_CFLAGS += -DXFS_BMAP_TRACE
+       EXTRA_CFLAGS += -DXFS_BMBT_TRACE
+       EXTRA_CFLAGS += -DXFS_DIR_TRACE
+       EXTRA_CFLAGS += -DXFS_DIR2_TRACE
+       EXTRA_CFLAGS += -DXFS_DQUOT_TRACE
+       EXTRA_CFLAGS += -DXFS_ILOCK_TRACE
+       EXTRA_CFLAGS += -DXFS_LOG_TRACE
+       EXTRA_CFLAGS += -DXFS_RW_TRACE
+       EXTRA_CFLAGS += -DPAGEBUF_TRACE
+       EXTRA_CFLAGS += -DXFS_VNODE_TRACE
+endif
+
+obj-$(CONFIG_XFS_FS)           += xfs.o
+obj-$(CONFIG_XFS_QUOTA)                += quota/
+
+xfs-$(CONFIG_XFS_RT)           += xfs_rtalloc.o
+xfs-$(CONFIG_XFS_POSIX_ACL)    += xfs_acl.o
+xfs-$(CONFIG_PROC_FS)          += $(XFS_LINUX)/xfs_stats.o
+xfs-$(CONFIG_SYSCTL)           += $(XFS_LINUX)/xfs_sysctl.o
+xfs-$(CONFIG_COMPAT)           += $(XFS_LINUX)/xfs_ioctl32.o
+xfs-$(CONFIG_XFS_EXPORT)       += $(XFS_LINUX)/xfs_export.o
+
+
+xfs-y                          += xfs_alloc.o \
+                                  xfs_alloc_btree.o \
+                                  xfs_attr.o \
+                                  xfs_attr_leaf.o \
+                                  xfs_behavior.o \
+                                  xfs_bit.o \
+                                  xfs_bmap.o \
+                                  xfs_bmap_btree.o \
+                                  xfs_btree.o \
+                                  xfs_buf_item.o \
+                                  xfs_da_btree.o \
+                                  xfs_dir.o \
+                                  xfs_dir2.o \
+                                  xfs_dir2_block.o \
+                                  xfs_dir2_data.o \
+                                  xfs_dir2_leaf.o \
+                                  xfs_dir2_node.o \
+                                  xfs_dir2_sf.o \
+                                  xfs_dir_leaf.o \
+                                  xfs_error.o \
+                                  xfs_extfree_item.o \
+                                  xfs_fsops.o \
+                                  xfs_ialloc.o \
+                                  xfs_ialloc_btree.o \
+                                  xfs_iget.o \
+                                  xfs_inode.o \
+                                  xfs_inode_item.o \
+                                  xfs_iocore.o \
+                                  xfs_iomap.o \
+                                  xfs_itable.o \
+                                  xfs_dfrag.o \
+                                  xfs_log.o \
+                                  xfs_log_recover.o \
+                                  xfs_macros.o \
+                                  xfs_mount.o \
+                                  xfs_rename.o \
+                                  xfs_trans.o \
+                                  xfs_trans_ail.o \
+                                  xfs_trans_buf.o \
+                                  xfs_trans_extfree.o \
+                                  xfs_trans_inode.o \
+                                  xfs_trans_item.o \
+                                  xfs_utils.o \
+                                  xfs_vfsops.o \
+                                  xfs_vnodeops.o \
+                                  xfs_rw.o \
+                                  xfs_dmops.o \
+                                  xfs_qmops.o
+
+xfs-$(CONFIG_XFS_TRACE)                += xfs_dir2_trace.o
+
+# Objects in linux/
+xfs-y                          += $(addprefix $(XFS_LINUX)/, \
+                                  kmem.o \
+                                  xfs_aops.o \
+                                  xfs_buf.o \
+                                  xfs_file.o \
+                                  xfs_fs_subr.o \
+                                  xfs_globals.o \
+                                  xfs_ioctl.o \
+                                  xfs_iops.o \
+                                  xfs_lrw.o \
+                                  xfs_super.o \
+                                  xfs_vfs.o \
+                                  xfs_vnode.o)
+
+# Objects in support/
+xfs-y                          += $(addprefix support/, \
+                                  debug.o \
+                                  move.o \
+                                  uuid.o)
+
+xfs-$(CONFIG_XFS_TRACE)                += support/ktrace.o
+
index 364ea8c386b1825b36ecbe1a8332bc6ff4be4b98..4b184559f23155bf4cec7d529b1561ea804b8bf3 100644 (file)
 
 
 void *
-kmem_alloc(size_t size, int flags)
+kmem_alloc(size_t size, unsigned int __nocast flags)
 {
-       int     retries = 0;
-       int     lflags = kmem_flags_convert(flags);
-       void    *ptr;
+       int             retries = 0;
+       unsigned int    lflags = kmem_flags_convert(flags);
+       void            *ptr;
 
        do {
                if (size < MAX_SLAB_SIZE || retries > MAX_VMALLOCS)
@@ -67,7 +67,7 @@ kmem_alloc(size_t size, int flags)
 }
 
 void *
-kmem_zalloc(size_t size, int flags)
+kmem_zalloc(size_t size, unsigned int __nocast flags)
 {
        void    *ptr;
 
@@ -89,7 +89,8 @@ kmem_free(void *ptr, size_t size)
 }
 
 void *
-kmem_realloc(void *ptr, size_t newsize, size_t oldsize, int flags)
+kmem_realloc(void *ptr, size_t newsize, size_t oldsize,
+            unsigned int __nocast flags)
 {
        void    *new;
 
@@ -104,11 +105,11 @@ kmem_realloc(void *ptr, size_t newsize, size_t oldsize, int flags)
 }
 
 void *
-kmem_zone_alloc(kmem_zone_t *zone, int flags)
+kmem_zone_alloc(kmem_zone_t *zone, unsigned int __nocast flags)
 {
-       int     retries = 0;
-       int     lflags = kmem_flags_convert(flags);
-       void    *ptr;
+       int             retries = 0;
+       unsigned int    lflags = kmem_flags_convert(flags);
+       void            *ptr;
 
        do {
                ptr = kmem_cache_alloc(zone, lflags);
@@ -123,7 +124,7 @@ kmem_zone_alloc(kmem_zone_t *zone, int flags)
 }
 
 void *
-kmem_zone_zalloc(kmem_zone_t *zone, int flags)
+kmem_zone_zalloc(kmem_zone_t *zone, unsigned int __nocast flags)
 {
        void    *ptr;
 
index 1397b669b059feab5002c67a1a2fb6a7817b29a3..109fcf27e256edf9ac40a02e955124d7d41126ca 100644 (file)
 /*
  * memory management routines
  */
-#define KM_SLEEP       0x0001
-#define KM_NOSLEEP     0x0002
-#define KM_NOFS                0x0004
-#define KM_MAYFAIL     0x0008
+#define KM_SLEEP       0x0001u
+#define KM_NOSLEEP     0x0002u
+#define KM_NOFS                0x0004u
+#define KM_MAYFAIL     0x0008u
 
 #define        kmem_zone       kmem_cache_s
 #define kmem_zone_t    kmem_cache_t
@@ -81,9 +81,9 @@ typedef unsigned long xfs_pflags_t;
        *(NSTATEP) = *(OSTATEP);        \
 } while (0)
 
-static __inline unsigned int kmem_flags_convert(int flags)
+static __inline unsigned int kmem_flags_convert(unsigned int __nocast flags)
 {
-       int     lflags = __GFP_NOWARN;  /* we'll report problems, if need be */
+       unsigned int    lflags = __GFP_NOWARN;  /* we'll report problems, if need be */
 
 #ifdef DEBUG
        if (unlikely(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS|KM_MAYFAIL))) {
@@ -125,12 +125,13 @@ kmem_zone_destroy(kmem_zone_t *zone)
                BUG();
 }
 
-extern void        *kmem_zone_zalloc(kmem_zone_t *, int);
-extern void        *kmem_zone_alloc(kmem_zone_t *, int);
+extern void        *kmem_zone_zalloc(kmem_zone_t *, unsigned int __nocast);
+extern void        *kmem_zone_alloc(kmem_zone_t *, unsigned int __nocast);
 
-extern void        *kmem_alloc(size_t, int);
-extern void        *kmem_realloc(void *, size_t, size_t, int);
-extern void        *kmem_zalloc(size_t, int);
+extern void        *kmem_alloc(size_t, unsigned int __nocast);
+extern void        *kmem_realloc(void *, size_t, size_t,
+                                 unsigned int __nocast);
+extern void        *kmem_zalloc(size_t, unsigned int __nocast);
 extern void         kmem_free(void *, size_t);
 
 typedef struct shrinker *kmem_shaker_t;
index bcf60a0b8df0ee71211cf35939694dacdfe3416f..0039504069a51c378de0906bf2b50262f1152d86 100644 (file)
@@ -45,6 +45,9 @@
 typedef spinlock_t lock_t;
 
 #define SPLDECL(s)                     unsigned long s
+#ifndef DEFINE_SPINLOCK
+#define DEFINE_SPINLOCK(s)             spinlock_t s = SPIN_LOCK_UNLOCKED
+#endif
 
 #define spinlock_init(lock, name)      spin_lock_init(lock)
 #define        spinlock_destroy(lock)
index a3a4b5aaf5d985020672a47e0c6858a21b190ad4..c6c077978fe38bbc662e11de0d40cf0846a5dcfc 100644 (file)
@@ -104,66 +104,114 @@ xfs_page_trace(
 #define xfs_page_trace(tag, inode, page, mask)
 #endif
 
-void
-linvfs_unwritten_done(
-       struct buffer_head      *bh,
-       int                     uptodate)
+/*
+ * Schedule IO completion handling on a xfsdatad if this was
+ * the final hold on this ioend.
+ */
+STATIC void
+xfs_finish_ioend(
+       xfs_ioend_t             *ioend)
 {
-       xfs_buf_t               *pb = (xfs_buf_t *)bh->b_private;
+       if (atomic_dec_and_test(&ioend->io_remaining))
+               queue_work(xfsdatad_workqueue, &ioend->io_work);
+}
 
-       ASSERT(buffer_unwritten(bh));
-       bh->b_end_io = NULL;
-       clear_buffer_unwritten(bh);
-       if (!uptodate)
-               pagebuf_ioerror(pb, EIO);
-       if (atomic_dec_and_test(&pb->pb_io_remaining) == 1) {
-               pagebuf_iodone(pb, 1, 1);
-       }
-       end_buffer_async_write(bh, uptodate);
+STATIC void
+xfs_destroy_ioend(
+       xfs_ioend_t             *ioend)
+{
+       vn_iowake(ioend->io_vnode);
+       mempool_free(ioend, xfs_ioend_pool);
 }
 
 /*
  * Issue transactions to convert a buffer range from unwritten
- * to written extents (buffered IO).
+ * to written extents.
  */
 STATIC void
-linvfs_unwritten_convert(
-       xfs_buf_t       *bp)
+xfs_end_bio_unwritten(
+       void                    *data)
 {
-       vnode_t         *vp = XFS_BUF_FSPRIVATE(bp, vnode_t *);
-       int             error;
+       xfs_ioend_t             *ioend = data;
+       vnode_t                 *vp = ioend->io_vnode;
+       xfs_off_t               offset = ioend->io_offset;
+       size_t                  size = ioend->io_size;
+       struct buffer_head      *bh, *next;
+       int                     error;
+
+       if (ioend->io_uptodate)
+               VOP_BMAP(vp, offset, size, BMAPI_UNWRITTEN, NULL, NULL, error);
+
+       /* ioend->io_buffer_head is only non-NULL for buffered I/O */
+       for (bh = ioend->io_buffer_head; bh; bh = next) {
+               next = bh->b_private;
+
+               bh->b_end_io = NULL;
+               clear_buffer_unwritten(bh);
+               end_buffer_async_write(bh, ioend->io_uptodate);
+       }
 
-       BUG_ON(atomic_read(&bp->pb_hold) < 1);
-       VOP_BMAP(vp, XFS_BUF_OFFSET(bp), XFS_BUF_SIZE(bp),
-                       BMAPI_UNWRITTEN, NULL, NULL, error);
-       XFS_BUF_SET_FSPRIVATE(bp, NULL);
-       XFS_BUF_CLR_IODONE_FUNC(bp);
-       XFS_BUF_UNDATAIO(bp);
-       iput(LINVFS_GET_IP(vp));
-       pagebuf_iodone(bp, 0, 0);
+       xfs_destroy_ioend(ioend);
 }
 
 /*
- * Issue transactions to convert a buffer range from unwritten
- * to written extents (direct IO).
+ * Allocate and initialise an IO completion structure.
+ * We need to track unwritten extent write completion here initially.
+ * We'll need to extend this for updating the ondisk inode size later
+ * (vs. incore size).
  */
-STATIC void
-linvfs_unwritten_convert_direct(
-       struct kiocb    *iocb,
-       loff_t          offset,
-       ssize_t         size,
-       void            *private)
+STATIC xfs_ioend_t *
+xfs_alloc_ioend(
+       struct inode            *inode)
 {
-       struct inode    *inode = iocb->ki_filp->f_dentry->d_inode;
-       ASSERT(!private || inode == (struct inode *)private);
+       xfs_ioend_t             *ioend;
 
-       /* private indicates an unwritten extent lay beneath this IO */
-       if (private && size > 0) {
-               vnode_t *vp = LINVFS_GET_VP(inode);
-               int     error;
+       ioend = mempool_alloc(xfs_ioend_pool, GFP_NOFS);
 
-               VOP_BMAP(vp, offset, size, BMAPI_UNWRITTEN, NULL, NULL, error);
-       }
+       /*
+        * Set the count to 1 initially, which will prevent an I/O
+        * completion callback from happening before we have started
+        * all the I/O from calling the completion routine too early.
+        */
+       atomic_set(&ioend->io_remaining, 1);
+       ioend->io_uptodate = 1; /* cleared if any I/O fails */
+       ioend->io_vnode = LINVFS_GET_VP(inode);
+       ioend->io_buffer_head = NULL;
+       atomic_inc(&ioend->io_vnode->v_iocount);
+       ioend->io_offset = 0;
+       ioend->io_size = 0;
+
+       INIT_WORK(&ioend->io_work, xfs_end_bio_unwritten, ioend);
+
+       return ioend;
+}
+
+void
+linvfs_unwritten_done(
+       struct buffer_head      *bh,
+       int                     uptodate)
+{
+       xfs_ioend_t             *ioend = bh->b_private;
+       static spinlock_t       unwritten_done_lock = SPIN_LOCK_UNLOCKED;
+       unsigned long           flags;
+
+       ASSERT(buffer_unwritten(bh));
+       bh->b_end_io = NULL;
+
+       if (!uptodate)
+               ioend->io_uptodate = 0;
+
+       /*
+        * Deep magic here.  We reuse b_private in the buffer_heads to build
+        * a chain for completing the I/O from user context after we've issued
+        * a transaction to convert the unwritten extent.
+        */
+       spin_lock_irqsave(&unwritten_done_lock, flags);
+       bh->b_private = ioend->io_buffer_head;
+       ioend->io_buffer_head = bh;
+       spin_unlock_irqrestore(&unwritten_done_lock, flags);
+
+       xfs_finish_ioend(ioend);
 }
 
 STATIC int
@@ -255,7 +303,7 @@ xfs_probe_unwritten_page(
        struct address_space    *mapping,
        pgoff_t                 index,
        xfs_iomap_t             *iomapp,
-       xfs_buf_t               *pb,
+       xfs_ioend_t             *ioend,
        unsigned long           max_offset,
        unsigned long           *fsbs,
        unsigned int            bbits)
@@ -283,7 +331,7 @@ xfs_probe_unwritten_page(
                                break;
                        xfs_map_at_offset(page, bh, p_offset, bbits, iomapp);
                        set_buffer_unwritten_io(bh);
-                       bh->b_private = pb;
+                       bh->b_private = ioend;
                        p_offset += bh->b_size;
                        (*fsbs)++;
                } while ((bh = bh->b_this_page) != head);
@@ -434,34 +482,15 @@ xfs_map_unwritten(
 {
        struct buffer_head      *bh = curr;
        xfs_iomap_t             *tmp;
-       xfs_buf_t               *pb;
-       loff_t                  offset, size;
+       xfs_ioend_t             *ioend;
+       loff_t                  offset;
        unsigned long           nblocks = 0;
 
        offset = start_page->index;
        offset <<= PAGE_CACHE_SHIFT;
        offset += p_offset;
 
-       /* get an "empty" pagebuf to manage IO completion
-        * Proper values will be set before returning */
-       pb = pagebuf_lookup(iomapp->iomap_target, 0, 0, 0);
-       if (!pb)
-               return -EAGAIN;
-
-       /* Take a reference to the inode to prevent it from
-        * being reclaimed while we have outstanding unwritten
-        * extent IO on it.
-        */
-       if ((igrab(inode)) != inode) {
-               pagebuf_free(pb);
-               return -EAGAIN;
-       }
-
-       /* Set the count to 1 initially, this will stop an I/O
-        * completion callout which happens before we have started
-        * all the I/O from calling pagebuf_iodone too early.
-        */
-       atomic_set(&pb->pb_io_remaining, 1);
+       ioend = xfs_alloc_ioend(inode);
 
        /* First map forwards in the page consecutive buffers
         * covering this unwritten extent
@@ -474,12 +503,12 @@ xfs_map_unwritten(
                        break;
                xfs_map_at_offset(start_page, bh, p_offset, block_bits, iomapp);
                set_buffer_unwritten_io(bh);
-               bh->b_private = pb;
+               bh->b_private = ioend;
                p_offset += bh->b_size;
                nblocks++;
        } while ((bh = bh->b_this_page) != head);
 
-       atomic_add(nblocks, &pb->pb_io_remaining);
+       atomic_add(nblocks, &ioend->io_remaining);
 
        /* If we reached the end of the page, map forwards in any
         * following pages which are also covered by this extent.
@@ -496,13 +525,13 @@ xfs_map_unwritten(
                tloff = min(tlast, tloff);
                for (tindex = start_page->index + 1; tindex < tloff; tindex++) {
                        page = xfs_probe_unwritten_page(mapping,
-                                               tindex, iomapp, pb,
+                                               tindex, iomapp, ioend,
                                                PAGE_CACHE_SIZE, &bs, bbits);
                        if (!page)
                                break;
                        nblocks += bs;
-                       atomic_add(bs, &pb->pb_io_remaining);
-                       xfs_convert_page(inode, page, iomapp, wbc, pb,
+                       atomic_add(bs, &ioend->io_remaining);
+                       xfs_convert_page(inode, page, iomapp, wbc, ioend,
                                                        startio, all_bh);
                        /* stop if converting the next page might add
                         * enough blocks that the corresponding byte
@@ -514,12 +543,12 @@ xfs_map_unwritten(
                if (tindex == tlast &&
                    (pg_offset = (i_size_read(inode) & (PAGE_CACHE_SIZE - 1)))) {
                        page = xfs_probe_unwritten_page(mapping,
-                                                       tindex, iomapp, pb,
+                                                       tindex, iomapp, ioend,
                                                        pg_offset, &bs, bbits);
                        if (page) {
                                nblocks += bs;
-                               atomic_add(bs, &pb->pb_io_remaining);
-                               xfs_convert_page(inode, page, iomapp, wbc, pb,
+                               atomic_add(bs, &ioend->io_remaining);
+                               xfs_convert_page(inode, page, iomapp, wbc, ioend,
                                                        startio, all_bh);
                                if (nblocks >= ((ULONG_MAX - PAGE_SIZE) >> block_bits))
                                        goto enough;
@@ -528,21 +557,9 @@ xfs_map_unwritten(
        }
 
 enough:
-       size = nblocks;         /* NB: using 64bit number here */
-       size <<= block_bits;    /* convert fsb's to byte range */
-
-       XFS_BUF_DATAIO(pb);
-       XFS_BUF_ASYNC(pb);
-       XFS_BUF_SET_SIZE(pb, size);
-       XFS_BUF_SET_COUNT(pb, size);
-       XFS_BUF_SET_OFFSET(pb, offset);
-       XFS_BUF_SET_FSPRIVATE(pb, LINVFS_GET_VP(inode));
-       XFS_BUF_SET_IODONE_FUNC(pb, linvfs_unwritten_convert);
-
-       if (atomic_dec_and_test(&pb->pb_io_remaining) == 1) {
-               pagebuf_iodone(pb, 1, 1);
-       }
-
+       ioend->io_size = (xfs_off_t)nblocks << block_bits;
+       ioend->io_offset = offset;
+       xfs_finish_ioend(ioend);
        return 0;
 }
 
@@ -787,7 +804,7 @@ xfs_page_state_convert(
                                continue;
                        if (!iomp) {
                                err = xfs_map_blocks(inode, offset, len, &iomap,
-                                               BMAPI_READ|BMAPI_IGNSTATE);
+                                               BMAPI_WRITE|BMAPI_IGNSTATE);
                                if (err) {
                                        goto error;
                                }
@@ -1028,6 +1045,44 @@ linvfs_get_blocks_direct(
                                        create, 1, BMAPI_WRITE|BMAPI_DIRECT);
 }
 
+STATIC void
+linvfs_end_io_direct(
+       struct kiocb    *iocb,
+       loff_t          offset,
+       ssize_t         size,
+       void            *private)
+{
+       xfs_ioend_t     *ioend = iocb->private;
+
+       /*
+        * Non-NULL private data means we need to issue a transaction to
+        * convert a range from unwritten to written extents.  This needs
+        * to happen from process contect but aio+dio I/O completion
+        * happens from irq context so we need to defer it to a workqueue.
+        * This is not nessecary for synchronous direct I/O, but we do
+        * it anyway to keep the code uniform and simpler.
+        *
+        * The core direct I/O code might be changed to always call the
+        * completion handler in the future, in which case all this can
+        * go away.
+        */
+       if (private && size > 0) {
+               ioend->io_offset = offset;
+               ioend->io_size = size;
+               xfs_finish_ioend(ioend);
+       } else {
+               ASSERT(size >= 0);
+               xfs_destroy_ioend(ioend);
+       }
+
+       /*
+        * blockdev_direct_IO can return an error even afer the I/O
+        * completion handler was called.  Thus we need to protect
+        * against double-freeing.
+        */
+       iocb->private = NULL;
+}
+
 STATIC ssize_t
 linvfs_direct_IO(
        int                     rw,
@@ -1042,16 +1097,23 @@ linvfs_direct_IO(
        xfs_iomap_t     iomap;
        int             maps = 1;
        int             error;
+       ssize_t         ret;
 
        VOP_BMAP(vp, offset, 0, BMAPI_DEVICE, &iomap, &maps, error);
        if (error)
                return -error;
 
-       return blockdev_direct_IO_own_locking(rw, iocb, inode,
+       iocb->private = xfs_alloc_ioend(inode);
+
+       ret = blockdev_direct_IO_own_locking(rw, iocb, inode,
                iomap.iomap_target->pbr_bdev,
                iov, offset, nr_segs,
                linvfs_get_blocks_direct,
-               linvfs_unwritten_convert_direct);
+               linvfs_end_io_direct);
+
+       if (unlikely(ret <= 0 && iocb->private))
+               xfs_destroy_ioend(iocb->private);
+       return ret;
 }
 
 
@@ -1202,6 +1264,16 @@ out_unlock:
        return error;
 }
 
+STATIC int
+linvfs_invalidate_page(
+       struct page             *page,
+       unsigned long           offset)
+{
+       xfs_page_trace(XFS_INVALIDPAGE_ENTER,
+                       page->mapping->host, page, offset);
+       return block_invalidatepage(page, offset);
+}
+
 /*
  * Called to move a page into cleanable state - and from there
  * to be released. Possibly the page is already clean. We always
@@ -1279,6 +1351,7 @@ struct address_space_operations linvfs_aops = {
        .writepage              = linvfs_writepage,
        .sync_page              = block_sync_page,
        .releasepage            = linvfs_release_page,
+       .invalidatepage         = linvfs_invalidate_page,
        .prepare_write          = linvfs_prepare_write,
        .commit_write           = generic_commit_write,
        .bmap                   = linvfs_bmap,
diff --git a/fs/xfs/linux-2.6/xfs_aops.h b/fs/xfs/linux-2.6/xfs_aops.h
new file mode 100644 (file)
index 0000000..2fa6297
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2005 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef __XFS_AOPS_H__
+#define __XFS_AOPS_H__
+
+extern struct workqueue_struct *xfsdatad_workqueue;
+extern mempool_t *xfs_ioend_pool;
+
+typedef void (*xfs_ioend_func_t)(void *);
+
+typedef struct xfs_ioend {
+       unsigned int            io_uptodate;    /* I/O status register */
+       atomic_t                io_remaining;   /* hold count */
+       struct vnode            *io_vnode;      /* file being written to */
+       struct buffer_head      *io_buffer_head;/* buffer linked list head */
+       size_t                  io_size;        /* size of the extent */
+       xfs_off_t               io_offset;      /* offset in the file */
+       struct work_struct      io_work;        /* xfsdatad work queue */
+} xfs_ioend_t;
+
+#endif /* __XFS_IOPS_H__ */
index df0cba239dd589b2ac7b9fbb90aa0909190a5ac3..655bf4a78afeb72a57eaf4668b2034b3c85c6aa7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -54,6 +54,7 @@
 #include <linux/percpu.h>
 #include <linux/blkdev.h>
 #include <linux/hash.h>
+#include <linux/kthread.h>
 
 #include "xfs_linux.h"
 
@@ -67,7 +68,7 @@ STATIC int xfsbufd_wakeup(int, unsigned int);
 STATIC void pagebuf_delwri_queue(xfs_buf_t *, int);
 
 STATIC struct workqueue_struct *xfslogd_workqueue;
-STATIC struct workqueue_struct *xfsdatad_workqueue;
+struct workqueue_struct *xfsdatad_workqueue;
 
 /*
  * Pagebuf debugging
@@ -590,8 +591,10 @@ found:
                PB_SET_OWNER(pb);
        }
 
-       if (pb->pb_flags & PBF_STALE)
+       if (pb->pb_flags & PBF_STALE) {
+               ASSERT((pb->pb_flags & _PBF_DELWRI_Q) == 0);
                pb->pb_flags &= PBF_MAPPED;
+       }
        PB_TRACE(pb, "got_lock", 0);
        XFS_STATS_INC(pb_get_locked);
        return (pb);
@@ -699,25 +702,6 @@ xfs_buf_read_flags(
        return NULL;
 }
 
-/*
- * Create a skeletal pagebuf (no pages associated with it).
- */
-xfs_buf_t *
-pagebuf_lookup(
-       xfs_buftarg_t           *target,
-       loff_t                  ioff,
-       size_t                  isize,
-       page_buf_flags_t        flags)
-{
-       xfs_buf_t               *pb;
-
-       pb = pagebuf_allocate(flags);
-       if (pb) {
-               _pagebuf_initialize(pb, target, ioff, isize, flags);
-       }
-       return pb;
-}
-
 /*
  * If we are not low on memory then do the readahead in a deadlock
  * safe manner.
@@ -913,22 +897,23 @@ pagebuf_rele(
                        do_free = 0;
                }
 
-               if (pb->pb_flags & PBF_DELWRI) {
-                       pb->pb_flags |= PBF_ASYNC;
-                       atomic_inc(&pb->pb_hold);
-                       pagebuf_delwri_queue(pb, 0);
-                       do_free = 0;
-               } else if (pb->pb_flags & PBF_FS_MANAGED) {
+               if (pb->pb_flags & PBF_FS_MANAGED) {
                        do_free = 0;
                }
 
                if (do_free) {
+                       ASSERT((pb->pb_flags & (PBF_DELWRI|_PBF_DELWRI_Q)) == 0);
                        list_del_init(&pb->pb_hash_list);
                        spin_unlock(&hash->bh_lock);
                        pagebuf_free(pb);
                } else {
                        spin_unlock(&hash->bh_lock);
                }
+       } else {
+               /*
+                * Catch reference count leaks
+                */
+               ASSERT(atomic_read(&pb->pb_hold) >= 0);
        }
 }
 
@@ -1006,13 +991,24 @@ pagebuf_lock(
  *     pagebuf_unlock
  *
  *     pagebuf_unlock releases the lock on the buffer object created by
- *     pagebuf_lock or pagebuf_cond_lock (not any
- *     pinning of underlying pages created by pagebuf_pin).
+ *     pagebuf_lock or pagebuf_cond_lock (not any pinning of underlying pages
+ *     created by pagebuf_pin).
+ *
+ *     If the buffer is marked delwri but is not queued, do so before we
+ *     unlock the buffer as we need to set flags correctly. We also need to
+ *     take a reference for the delwri queue because the unlocker is going to
+ *     drop their's and they don't know we just queued it.
  */
 void
 pagebuf_unlock(                                /* unlock buffer                */
        xfs_buf_t               *pb)    /* buffer to unlock             */
 {
+       if ((pb->pb_flags & (PBF_DELWRI|_PBF_DELWRI_Q)) == PBF_DELWRI) {
+               atomic_inc(&pb->pb_hold);
+               pb->pb_flags |= PBF_ASYNC;
+               pagebuf_delwri_queue(pb, 0);
+       }
+
        PB_CLEAR_OWNER(pb);
        up(&pb->pb_sema);
        PB_TRACE(pb, "unlock", 0);
@@ -1249,8 +1245,8 @@ bio_end_io_pagebuf(
        int                     error)
 {
        xfs_buf_t               *pb = (xfs_buf_t *)bio->bi_private;
-       unsigned int            i, blocksize = pb->pb_target->pbr_bsize;
-       struct bio_vec          *bvec = bio->bi_io_vec;
+       unsigned int            blocksize = pb->pb_target->pbr_bsize;
+       struct bio_vec          *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
 
        if (bio->bi_size)
                return 1;
@@ -1258,10 +1254,12 @@ bio_end_io_pagebuf(
        if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
                pb->pb_error = EIO;
 
-       for (i = 0; i < bio->bi_vcnt; i++, bvec++) {
+       do {
                struct page     *page = bvec->bv_page;
 
-               if (pb->pb_error) {
+               if (unlikely(pb->pb_error)) {
+                       if (pb->pb_flags & PBF_READ)
+                               ClearPageUptodate(page);
                        SetPageError(page);
                } else if (blocksize == PAGE_CACHE_SIZE) {
                        SetPageUptodate(page);
@@ -1270,10 +1268,13 @@ bio_end_io_pagebuf(
                        set_page_region(page, bvec->bv_offset, bvec->bv_len);
                }
 
+               if (--bvec >= bio->bi_io_vec)
+                       prefetchw(&bvec->bv_page->flags);
+
                if (_pagebuf_iolocked(pb)) {
                        unlock_page(page);
                }
-       }
+       } while (bvec >= bio->bi_io_vec);
 
        _pagebuf_iodone(pb, 1);
        bio_put(bio);
@@ -1511,6 +1512,11 @@ again:
                        ASSERT(btp == bp->pb_target);
                        if (!(bp->pb_flags & PBF_FS_MANAGED)) {
                                spin_unlock(&hash->bh_lock);
+                               /*
+                                * Catch superblock reference count leaks
+                                * immediately
+                                */
+                               BUG_ON(bp->pb_bn == 0);
                                delay(100);
                                goto again;
                        }
@@ -1686,17 +1692,20 @@ pagebuf_delwri_queue(
        int                     unlock)
 {
        PB_TRACE(pb, "delwri_q", (long)unlock);
-       ASSERT(pb->pb_flags & PBF_DELWRI);
+       ASSERT((pb->pb_flags & (PBF_DELWRI|PBF_ASYNC)) ==
+                                       (PBF_DELWRI|PBF_ASYNC));
 
        spin_lock(&pbd_delwrite_lock);
        /* If already in the queue, dequeue and place at tail */
        if (!list_empty(&pb->pb_list)) {
+               ASSERT(pb->pb_flags & _PBF_DELWRI_Q);
                if (unlock) {
                        atomic_dec(&pb->pb_hold);
                }
                list_del(&pb->pb_list);
        }
 
+       pb->pb_flags |= _PBF_DELWRI_Q;
        list_add_tail(&pb->pb_list, &pbd_delwrite_queue);
        pb->pb_queuetime = jiffies;
        spin_unlock(&pbd_delwrite_lock);
@@ -1713,10 +1722,11 @@ pagebuf_delwri_dequeue(
 
        spin_lock(&pbd_delwrite_lock);
        if ((pb->pb_flags & PBF_DELWRI) && !list_empty(&pb->pb_list)) {
+               ASSERT(pb->pb_flags & _PBF_DELWRI_Q);
                list_del_init(&pb->pb_list);
                dequeued = 1;
        }
-       pb->pb_flags &= ~PBF_DELWRI;
+       pb->pb_flags &= ~(PBF_DELWRI|_PBF_DELWRI_Q);
        spin_unlock(&pbd_delwrite_lock);
 
        if (dequeued)
@@ -1733,9 +1743,7 @@ pagebuf_runall_queues(
 }
 
 /* Defines for pagebuf daemon */
-STATIC DECLARE_COMPLETION(xfsbufd_done);
 STATIC struct task_struct *xfsbufd_task;
-STATIC int xfsbufd_active;
 STATIC int xfsbufd_force_flush;
 STATIC int xfsbufd_force_sleep;
 
@@ -1761,14 +1769,8 @@ xfsbufd(
        xfs_buftarg_t           *target;
        xfs_buf_t               *pb, *n;
 
-       /*  Set up the thread  */
-       daemonize("xfsbufd");
        current->flags |= PF_MEMALLOC;
 
-       xfsbufd_task = current;
-       xfsbufd_active = 1;
-       barrier();
-
        INIT_LIST_HEAD(&tmp);
        do {
                if (unlikely(freezing(current))) {
@@ -1795,7 +1797,7 @@ xfsbufd(
                                        break;
                                }
 
-                               pb->pb_flags &= ~PBF_DELWRI;
+                               pb->pb_flags &= ~(PBF_DELWRI|_PBF_DELWRI_Q);
                                pb->pb_flags |= PBF_WRITE;
                                list_move(&pb->pb_list, &tmp);
                        }
@@ -1816,9 +1818,9 @@ xfsbufd(
                        purge_addresses();
 
                xfsbufd_force_flush = 0;
-       } while (xfsbufd_active);
+       } while (!kthread_should_stop());
 
-       complete_and_exit(&xfsbufd_done, 0);
+       return 0;
 }
 
 /*
@@ -1845,15 +1847,13 @@ xfs_flush_buftarg(
                if (pb->pb_target != target)
                        continue;
 
-               ASSERT(pb->pb_flags & PBF_DELWRI);
+               ASSERT(pb->pb_flags & (PBF_DELWRI|_PBF_DELWRI_Q));
                PB_TRACE(pb, "walkq2", (long)pagebuf_ispin(pb));
                if (pagebuf_ispin(pb)) {
                        pincount++;
                        continue;
                }
 
-               pb->pb_flags &= ~PBF_DELWRI;
-               pb->pb_flags |= PBF_WRITE;
                list_move(&pb->pb_list, &tmp);
        }
        spin_unlock(&pbd_delwrite_lock);
@@ -1862,12 +1862,14 @@ xfs_flush_buftarg(
         * Dropped the delayed write list lock, now walk the temporary list
         */
        list_for_each_entry_safe(pb, n, &tmp, pb_list) {
+               pagebuf_lock(pb);
+               pb->pb_flags &= ~(PBF_DELWRI|_PBF_DELWRI_Q);
+               pb->pb_flags |= PBF_WRITE;
                if (wait)
                        pb->pb_flags &= ~PBF_ASYNC;
                else
                        list_del_init(&pb->pb_list);
 
-               pagebuf_lock(pb);
                pagebuf_iostrategy(pb);
        }
 
@@ -1901,9 +1903,11 @@ xfs_buf_daemons_start(void)
        if (!xfsdatad_workqueue)
                goto out_destroy_xfslogd_workqueue;
 
-       error = kernel_thread(xfsbufd, NULL, CLONE_FS|CLONE_FILES);
-       if (error < 0)
+       xfsbufd_task = kthread_run(xfsbufd, NULL, "xfsbufd");
+       if (IS_ERR(xfsbufd_task)) {
+               error = PTR_ERR(xfsbufd_task);
                goto out_destroy_xfsdatad_workqueue;
+       }
        return 0;
 
  out_destroy_xfsdatad_workqueue:
@@ -1920,10 +1924,7 @@ xfs_buf_daemons_start(void)
 STATIC void
 xfs_buf_daemons_stop(void)
 {
-       xfsbufd_active = 0;
-       barrier();
-       wait_for_completion(&xfsbufd_done);
-
+       kthread_stop(xfsbufd_task);
        destroy_workqueue(xfslogd_workqueue);
        destroy_workqueue(xfsdatad_workqueue);
 }
index 3f8f69a66aeaba714b75a03a50c63b0fc6b59097..67c19f7992325ee57d743f3f77e0123a9b39588d 100644 (file)
@@ -89,6 +89,7 @@ typedef enum page_buf_flags_e {               /* pb_flags values */
        _PBF_PAGE_CACHE = (1 << 17),/* backed by pagecache                 */
        _PBF_KMEM_ALLOC = (1 << 18),/* backed by kmem_alloc()              */
        _PBF_RUN_QUEUES = (1 << 19),/* run block device task queue         */
+       _PBF_DELWRI_Q = (1 << 21),   /* buffer on delwri queue             */
 } page_buf_flags_t;
 
 #define PBF_UPDATE (PBF_READ | PBF_WRITE)
@@ -206,13 +207,6 @@ extern xfs_buf_t *xfs_buf_read_flags(      /* allocate and read a buffer   */
 #define xfs_buf_read(target, blkno, len, flags) \
        xfs_buf_read_flags((target), (blkno), (len), PBF_LOCK | PBF_MAPPED)
 
-extern xfs_buf_t *pagebuf_lookup(
-               xfs_buftarg_t *,
-               loff_t,                 /* starting offset of range     */
-               size_t,                 /* length of range              */
-               page_buf_flags_t);      /* PBF_READ, PBF_WRITE,         */
-                                       /* PBF_FORCEIO,                 */
-
 extern xfs_buf_t *pagebuf_get_empty(   /* allocate pagebuf struct with */
                                        /*  no memory or disk address   */
                size_t len,
@@ -344,8 +338,6 @@ extern void pagebuf_trace(
 
 
 
-
-
 /* These are just for xfs_syncsub... it sets an internal variable
  * then passes it to VOP_FLUSH_PAGES or adds the flags to a newly gotten buf_t
  */
@@ -452,7 +444,7 @@ extern void pagebuf_trace(
 
 #define XFS_BUF_PTR(bp)                (xfs_caddr_t)((bp)->pb_addr)
 
-extern inline xfs_caddr_t xfs_buf_offset(xfs_buf_t *bp, size_t offset)
+static inline xfs_caddr_t xfs_buf_offset(xfs_buf_t *bp, size_t offset)
 {
        if (bp->pb_flags & PBF_MAPPED)
                return XFS_BUF_PTR(bp) + offset;
index f1ce4323f56e905c499e3889734d878d82c7b566..3881622bcf081abcf35d81dbe720f184a7720d3d 100644 (file)
@@ -311,6 +311,31 @@ linvfs_fsync(
 
 #define nextdp(dp)      ((struct xfs_dirent *)((char *)(dp) + (dp)->d_reclen))
 
+#ifdef CONFIG_XFS_DMAPI
+
+STATIC struct page *
+linvfs_filemap_nopage(
+       struct vm_area_struct   *area,
+       unsigned long           address,
+       int                     *type)
+{
+       struct inode    *inode = area->vm_file->f_dentry->d_inode;
+       vnode_t         *vp = LINVFS_GET_VP(inode);
+       xfs_mount_t     *mp = XFS_VFSTOM(vp->v_vfsp);
+       int             error;
+
+       ASSERT_ALWAYS(vp->v_vfsp->vfs_flag & VFS_DMI);
+
+       error = XFS_SEND_MMAP(mp, area, 0);
+       if (error)
+               return NULL;
+
+       return filemap_nopage(area, address, type);
+}
+
+#endif /* CONFIG_XFS_DMAPI */
+
+
 STATIC int
 linvfs_readdir(
        struct file     *filp,
@@ -390,14 +415,6 @@ done:
        return -error;
 }
 
-#ifdef CONFIG_XFS_DMAPI
-STATIC void
-linvfs_mmap_close(
-       struct vm_area_struct   *vma)
-{
-       xfs_dm_mm_put(vma);
-}
-#endif /* CONFIG_XFS_DMAPI */
 
 STATIC int
 linvfs_file_mmap(
@@ -411,16 +428,11 @@ linvfs_file_mmap(
 
        vma->vm_ops = &linvfs_file_vm_ops;
 
-       if (vp->v_vfsp->vfs_flag & VFS_DMI) {
-               xfs_mount_t     *mp = XFS_VFSTOM(vp->v_vfsp);
-
-               error = -XFS_SEND_MMAP(mp, vma, 0);
-               if (error)
-                       return error;
 #ifdef CONFIG_XFS_DMAPI
+       if (vp->v_vfsp->vfs_flag & VFS_DMI) {
                vma->vm_ops = &linvfs_dmapi_file_vm_ops;
-#endif
        }
+#endif /* CONFIG_XFS_DMAPI */
 
        VOP_SETATTR(vp, &va, XFS_AT_UPDATIME, NULL, error);
        if (!error)
@@ -474,6 +486,7 @@ linvfs_ioctl_invis(
        return error;
 }
 
+#ifdef CONFIG_XFS_DMAPI
 #ifdef HAVE_VMOP_MPROTECT
 STATIC int
 linvfs_mprotect(
@@ -494,6 +507,7 @@ linvfs_mprotect(
        return error;
 }
 #endif /* HAVE_VMOP_MPROTECT */
+#endif /* CONFIG_XFS_DMAPI */
 
 #ifdef HAVE_FOP_OPEN_EXEC
 /* If the user is attempting to execute a file that is offline then
@@ -528,49 +542,10 @@ open_exec_out:
 }
 #endif /* HAVE_FOP_OPEN_EXEC */
 
-/*
- * Temporary workaround to the AIO direct IO write problem.
- * This code can go and we can revert to do_sync_write once
- * the writepage(s) rework is merged.
- */
-STATIC ssize_t
-linvfs_write(
-       struct file     *filp,
-       const char      __user *buf,
-       size_t          len,
-       loff_t          *ppos)
-{
-       struct kiocb    kiocb;
-       ssize_t         ret;
-
-       init_sync_kiocb(&kiocb, filp);
-       kiocb.ki_pos = *ppos;
-       ret = __linvfs_write(&kiocb, buf, 0, len, kiocb.ki_pos);
-       *ppos = kiocb.ki_pos;
-       return ret;
-}
-STATIC ssize_t
-linvfs_write_invis(
-       struct file     *filp,
-       const char      __user *buf,
-       size_t          len,
-       loff_t          *ppos)
-{
-       struct kiocb    kiocb;
-       ssize_t         ret;
-
-       init_sync_kiocb(&kiocb, filp);
-       kiocb.ki_pos = *ppos;
-       ret = __linvfs_write(&kiocb, buf, IO_INVIS, len, kiocb.ki_pos);
-       *ppos = kiocb.ki_pos;
-       return ret;
-}
-
-
 struct file_operations linvfs_file_operations = {
        .llseek         = generic_file_llseek,
        .read           = do_sync_read,
-       .write          = linvfs_write,
+       .write          = do_sync_write,
        .readv          = linvfs_readv,
        .writev         = linvfs_writev,
        .aio_read       = linvfs_aio_read,
@@ -592,7 +567,7 @@ struct file_operations linvfs_file_operations = {
 struct file_operations linvfs_invis_file_operations = {
        .llseek         = generic_file_llseek,
        .read           = do_sync_read,
-       .write          = linvfs_write_invis,
+       .write          = do_sync_write,
        .readv          = linvfs_readv_invis,
        .writev         = linvfs_writev_invis,
        .aio_read       = linvfs_aio_read_invis,
@@ -626,8 +601,7 @@ static struct vm_operations_struct linvfs_file_vm_ops = {
 
 #ifdef CONFIG_XFS_DMAPI
 static struct vm_operations_struct linvfs_dmapi_file_vm_ops = {
-       .close          = linvfs_mmap_close,
-       .nopage         = filemap_nopage,
+       .nopage         = linvfs_filemap_nopage,
        .populate       = filemap_populate,
 #ifdef HAVE_VMOP_MPROTECT
        .mprotect       = linvfs_mprotect,
index 05a447e51cc023c4d19f2aa4dd275d4b59d87db6..6a3326bcd8d015f86c5a66a00263b0229a1396ef 100644 (file)
@@ -141,13 +141,19 @@ xfs_find_handle(
                return -XFS_ERROR(EINVAL);
        }
 
-       /* we need the vnode */
-       vp = LINVFS_GET_VP(inode);
-       if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) {
+       switch (inode->i_mode & S_IFMT) {
+       case S_IFREG:
+       case S_IFDIR:
+       case S_IFLNK:
+               break;
+       default:
                iput(inode);
                return -XFS_ERROR(EBADF);
        }
 
+       /* we need the vnode */
+       vp = LINVFS_GET_VP(inode);
+
        /* now we can grab the fsid */
        memcpy(&handle.ha_fsid, vp->v_vfsp->vfs_altfsid, sizeof(xfs_fsid_t));
        hsize = sizeof(xfs_fsid_t);
@@ -386,7 +392,7 @@ xfs_readlink_by_handle(
                return -error;
 
        /* Restrict this handle operation to symlinks only. */
-       if (vp->v_type != VLNK) {
+       if (!S_ISLNK(inode->i_mode)) {
                VN_RELE(vp);
                return -XFS_ERROR(EINVAL);
        }
@@ -982,10 +988,10 @@ xfs_ioc_space(
        if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
                return -XFS_ERROR(EPERM);
 
-       if (!(filp->f_flags & FMODE_WRITE))
+       if (!(filp->f_mode & FMODE_WRITE))
                return -XFS_ERROR(EBADF);
 
-       if (vp->v_type != VREG)
+       if (!VN_ISREG(vp))
                return -XFS_ERROR(EINVAL);
 
        if (copy_from_user(&bf, arg, sizeof(bf)))
index 0f8f1384eb36a88a20e0e89e34f884436b8063b2..4636b7f86f1fa204be576d8eb976c1711effa200 100644 (file)
 #include "xfs_vnode.h"
 #include "xfs_dfrag.h"
 
+#define  _NATIVE_IOC(cmd, type) \
+         _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(type))
+
 #if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
 #define BROKEN_X86_ALIGNMENT
+/* on ia32 l_start is on a 32-bit boundary */
+typedef struct xfs_flock64_32 {
+       __s16           l_type;
+       __s16           l_whence;
+       __s64           l_start __attribute__((packed));
+                       /* len == 0 means until end of file */
+       __s64           l_len __attribute__((packed));
+       __s32           l_sysid;
+       __u32           l_pid;
+       __s32           l_pad[4];       /* reserve area */
+} xfs_flock64_32_t;
+
+#define XFS_IOC_ALLOCSP_32     _IOW ('X', 10, struct xfs_flock64_32)
+#define XFS_IOC_FREESP_32      _IOW ('X', 11, struct xfs_flock64_32)
+#define XFS_IOC_ALLOCSP64_32   _IOW ('X', 36, struct xfs_flock64_32)
+#define XFS_IOC_FREESP64_32    _IOW ('X', 37, struct xfs_flock64_32)
+#define XFS_IOC_RESVSP_32      _IOW ('X', 40, struct xfs_flock64_32)
+#define XFS_IOC_UNRESVSP_32    _IOW ('X', 41, struct xfs_flock64_32)
+#define XFS_IOC_RESVSP64_32    _IOW ('X', 42, struct xfs_flock64_32)
+#define XFS_IOC_UNRESVSP64_32  _IOW ('X', 43, struct xfs_flock64_32)
+
+/* just account for different alignment */
+STATIC unsigned long
+xfs_ioctl32_flock(
+       unsigned long           arg)
+{
+       xfs_flock64_32_t        __user *p32 = (void __user *)arg;
+       xfs_flock64_t           __user *p = compat_alloc_user_space(sizeof(*p));
+
+       if (copy_in_user(&p->l_type,    &p32->l_type,   sizeof(s16)) ||
+           copy_in_user(&p->l_whence,  &p32->l_whence, sizeof(s16)) ||
+           copy_in_user(&p->l_start,   &p32->l_start,  sizeof(s64)) ||
+           copy_in_user(&p->l_len,     &p32->l_len,    sizeof(s64)) ||
+           copy_in_user(&p->l_sysid,   &p32->l_sysid,  sizeof(s32)) ||
+           copy_in_user(&p->l_pid,     &p32->l_pid,    sizeof(u32)) ||
+           copy_in_user(&p->l_pad,     &p32->l_pad,    4*sizeof(u32)))
+               return -EFAULT;
+       
+       return (unsigned long)p;
+}
+
 #else
 
 typedef struct xfs_fsop_bulkreq32 {
@@ -103,7 +147,6 @@ __linvfs_compat_ioctl(int mode, struct file *f, unsigned cmd, unsigned long arg)
 /* not handled
        case XFS_IOC_FD_TO_HANDLE:
        case XFS_IOC_PATH_TO_HANDLE:
-       case XFS_IOC_PATH_TO_HANDLE:
        case XFS_IOC_PATH_TO_FSHANDLE:
        case XFS_IOC_OPEN_BY_HANDLE:
        case XFS_IOC_FSSETDM_BY_HANDLE:
@@ -124,8 +167,21 @@ __linvfs_compat_ioctl(int mode, struct file *f, unsigned cmd, unsigned long arg)
        case XFS_IOC_ERROR_CLEARALL:
                break;
 
-#ifndef BROKEN_X86_ALIGNMENT
-       /* xfs_flock_t and xfs_bstat_t have wrong u32 vs u64 alignment */
+#ifdef BROKEN_X86_ALIGNMENT
+       /* xfs_flock_t has wrong u32 vs u64 alignment */
+       case XFS_IOC_ALLOCSP_32:
+       case XFS_IOC_FREESP_32:
+       case XFS_IOC_ALLOCSP64_32:
+       case XFS_IOC_FREESP64_32:
+       case XFS_IOC_RESVSP_32:
+       case XFS_IOC_UNRESVSP_32:
+       case XFS_IOC_RESVSP64_32:
+       case XFS_IOC_UNRESVSP64_32:
+               arg = xfs_ioctl32_flock(arg);
+               cmd = _NATIVE_IOC(cmd, struct xfs_flock64);
+               break;
+
+#else /* These are handled fine if no alignment issues */
        case XFS_IOC_ALLOCSP:
        case XFS_IOC_FREESP:
        case XFS_IOC_RESVSP:
@@ -134,6 +190,9 @@ __linvfs_compat_ioctl(int mode, struct file *f, unsigned cmd, unsigned long arg)
        case XFS_IOC_FREESP64:
        case XFS_IOC_RESVSP64:
        case XFS_IOC_UNRESVSP64:
+               break;
+
+       /* xfs_bstat_t still has wrong u32 vs u64 alignment */
        case XFS_IOC_SWAPEXT:
                break;
 
index f252605514eb1dce23393e4f904d6f5789c3d535..77708a8c9f87b78afc74125879071a2617493e88 100644 (file)
@@ -140,7 +140,6 @@ linvfs_mknod(
 
        memset(&va, 0, sizeof(va));
        va.va_mask = XFS_AT_TYPE|XFS_AT_MODE;
-       va.va_type = IFTOVT(mode);
        va.va_mode = mode;
 
        switch (mode & S_IFMT) {
@@ -308,14 +307,13 @@ linvfs_symlink(
        cvp = NULL;
 
        memset(&va, 0, sizeof(va));
-       va.va_type = VLNK;
-       va.va_mode = irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO;
+       va.va_mode = S_IFLNK |
+               (irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO);
        va.va_mask = XFS_AT_TYPE|XFS_AT_MODE;
 
        error = 0;
        VOP_SYMLINK(dvp, dentry, &va, (char *)symname, &cvp, NULL, error);
        if (!error && cvp) {
-               ASSERT(cvp->v_type == VLNK);
                ip = LINVFS_GET_IP(cvp);
                d_instantiate(dentry, ip);
                validate_fields(dir);
@@ -425,9 +423,14 @@ linvfs_follow_link(
        return NULL;
 }
 
-static void linvfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
+STATIC void
+linvfs_put_link(
+       struct dentry   *dentry,
+       struct nameidata *nd,
+       void            *p)
 {
-       char *s = nd_get_link(nd);
+       char            *s = nd_get_link(nd);
+
        if (!IS_ERR(s))
                kfree(s);
 }
index 42dc5e4662ed9f950506ba25fd7d1ead729251dc..68c5d885ed9c214e737975a3d8a37379f8dbf834 100644 (file)
@@ -64,7 +64,6 @@
 #include <sema.h>
 #include <time.h>
 
-#include <support/qsort.h>
 #include <support/ktrace.h>
 #include <support/debug.h>
 #include <support/move.h>
 #include <xfs_stats.h>
 #include <xfs_sysctl.h>
 #include <xfs_iops.h>
+#include <xfs_aops.h>
 #include <xfs_super.h>
 #include <xfs_globals.h>
 #include <xfs_fs_subr.h>
@@ -254,11 +254,18 @@ static inline void set_buffer_unwritten_io(struct buffer_head *bh)
 #define MAX(a,b)       (max(a,b))
 #define howmany(x, y)  (((x)+((y)-1))/(y))
 #define roundup(x, y)  ((((x)+((y)-1))/(y))*(y))
+#define qsort(a,n,s,fn)        sort(a,n,s,fn,NULL)
 
+/*
+ * Various platform dependent calls that don't fit anywhere else
+ */
 #define xfs_stack_trace()      dump_stack()
-
 #define xfs_itruncate_data(ip, off)    \
        (-vmtruncate(LINVFS_GET_IP(XFS_ITOV(ip)), (off)))
+#define xfs_statvfs_fsid(statp, mp)    \
+       ({ u64 id = huge_encode_dev((mp)->m_dev);       \
+          __kernel_fsid_t *fsid = &(statp)->f_fsid;    \
+       (fsid->val[0] = (u32)id, fsid->val[1] = (u32)(id >> 32)); })
 
 
 /* Move the kernel do_div definition off to one side */
@@ -371,6 +378,4 @@ static inline __uint64_t roundup_64(__uint64_t x, __uint32_t y)
        return(x * y);
 }
 
-#define qsort(a, n, s, cmp) sort(a, n, s, cmp, NULL)
-
 #endif /* __XFS_LINUX__ */
index acab58c48043bd77c471c724090fbfe0156b120b..3b5fabe8dae908474c779517ef27ecaeb3b49024 100644 (file)
@@ -660,9 +660,6 @@ xfs_write(
                        (xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
                                mp->m_rtdev_targp : mp->m_ddev_targp;
 
-               if (ioflags & IO_ISAIO)
-                       return XFS_ERROR(-ENOSYS);
-
                if ((pos & target->pbr_smask) || (count & target->pbr_smask))
                        return XFS_ERROR(-EINVAL);
 
index f197a720e394db5b1bca538a3f826882cc3b7f46..6294dcdb797cc97ae98b7e24aebed23292a6f2f4 100644 (file)
@@ -70,9 +70,10 @@ struct xfs_iomap;
 #define        XFS_SENDFILE_ENTER      21
 #define        XFS_WRITEPAGE_ENTER     22
 #define        XFS_RELEASEPAGE_ENTER   23
-#define        XFS_IOMAP_ALLOC_ENTER   24
-#define        XFS_IOMAP_ALLOC_MAP     25
-#define        XFS_IOMAP_UNWRITTEN     26
+#define        XFS_INVALIDPAGE_ENTER   24
+#define        XFS_IOMAP_ALLOC_ENTER   25
+#define        XFS_IOMAP_ALLOC_MAP     26
+#define        XFS_IOMAP_UNWRITTEN     27
 extern void xfs_rw_enter_trace(int, struct xfs_iocore *,
                                void *, size_t, loff_t, int);
 extern void xfs_inval_cached_trace(struct xfs_iocore *,
index f6dd7de2592748c95dee026e0f865ec37d5ca89b..0da87bfc999999e74a32985ffbde515c429cd111 100644 (file)
 #include <linux/namei.h>
 #include <linux/init.h>
 #include <linux/mount.h>
+#include <linux/mempool.h>
 #include <linux/writeback.h>
+#include <linux/kthread.h>
 
 STATIC struct quotactl_ops linvfs_qops;
 STATIC struct super_operations linvfs_sops;
-STATIC kmem_zone_t *linvfs_inode_zone;
+STATIC kmem_zone_t *xfs_vnode_zone;
+STATIC kmem_zone_t *xfs_ioend_zone;
+mempool_t *xfs_ioend_pool;
 
 STATIC struct xfs_mount_args *
 xfs_args_allocate(
@@ -138,24 +142,25 @@ STATIC __inline__ void
 xfs_set_inodeops(
        struct inode            *inode)
 {
-       vnode_t                 *vp = LINVFS_GET_VP(inode);
-
-       if (vp->v_type == VNON) {
-               vn_mark_bad(vp);
-       } else if (S_ISREG(inode->i_mode)) {
+       switch (inode->i_mode & S_IFMT) {
+       case S_IFREG:
                inode->i_op = &linvfs_file_inode_operations;
                inode->i_fop = &linvfs_file_operations;
                inode->i_mapping->a_ops = &linvfs_aops;
-       } else if (S_ISDIR(inode->i_mode)) {
+               break;
+       case S_IFDIR:
                inode->i_op = &linvfs_dir_inode_operations;
                inode->i_fop = &linvfs_dir_operations;
-       } else if (S_ISLNK(inode->i_mode)) {
+               break;
+       case S_IFLNK:
                inode->i_op = &linvfs_symlink_inode_operations;
                if (inode->i_blocks)
                        inode->i_mapping->a_ops = &linvfs_aops;
-       } else {
+               break;
+       default:
                inode->i_op = &linvfs_file_inode_operations;
                init_special_inode(inode, inode->i_mode, inode->i_rdev);
+               break;
        }
 }
 
@@ -167,16 +172,23 @@ xfs_revalidate_inode(
 {
        struct inode            *inode = LINVFS_GET_IP(vp);
 
-       inode->i_mode   = (ip->i_d.di_mode & MODEMASK) | VTTOIF(vp->v_type);
+       inode->i_mode   = ip->i_d.di_mode;
        inode->i_nlink  = ip->i_d.di_nlink;
        inode->i_uid    = ip->i_d.di_uid;
        inode->i_gid    = ip->i_d.di_gid;
-       if (((1 << vp->v_type) & ((1<<VBLK) | (1<<VCHR))) == 0) {
+
+       switch (inode->i_mode & S_IFMT) {
+       case S_IFBLK:
+       case S_IFCHR:
+               inode->i_rdev =
+                       MKDEV(sysv_major(ip->i_df.if_u2.if_rdev) & 0x1ff,
+                             sysv_minor(ip->i_df.if_u2.if_rdev));
+               break;
+       default:
                inode->i_rdev = 0;
-       } else {
-               xfs_dev_t dev = ip->i_df.if_u2.if_rdev;
-               inode->i_rdev = MKDEV(sysv_major(dev) & 0x1ff, sysv_minor(dev));
+               break;
        }
+
        inode->i_blksize = PAGE_CACHE_SIZE;
        inode->i_generation = ip->i_d.di_gen;
        i_size_write(inode, ip->i_d.di_size);
@@ -231,7 +243,6 @@ xfs_initialize_vnode(
         * finish our work.
         */
        if (ip->i_d.di_mode != 0 && unlock && (inode->i_state & I_NEW)) {
-               vp->v_type = IFTOVT(ip->i_d.di_mode);
                xfs_revalidate_inode(XFS_BHVTOM(bdp), vp, ip);
                xfs_set_inodeops(inode);
        
@@ -274,8 +285,7 @@ linvfs_alloc_inode(
 {
        vnode_t                 *vp;
 
-       vp = (vnode_t *)kmem_cache_alloc(linvfs_inode_zone, 
-                kmem_flags_convert(KM_SLEEP));
+       vp = kmem_cache_alloc(xfs_vnode_zone, kmem_flags_convert(KM_SLEEP));
        if (!vp)
                return NULL;
        return LINVFS_GET_IP(vp);
@@ -285,11 +295,11 @@ STATIC void
 linvfs_destroy_inode(
        struct inode            *inode)
 {
-       kmem_cache_free(linvfs_inode_zone, LINVFS_GET_VP(inode));
+       kmem_zone_free(xfs_vnode_zone, LINVFS_GET_VP(inode));
 }
 
 STATIC void
-init_once(
+linvfs_inode_init_once(
        void                    *data,
        kmem_cache_t            *cachep,
        unsigned long           flags)
@@ -302,21 +312,41 @@ init_once(
 }
 
 STATIC int
-init_inodecache( void )
+linvfs_init_zones(void)
 {
-       linvfs_inode_zone = kmem_cache_create("linvfs_icache",
+       xfs_vnode_zone = kmem_cache_create("xfs_vnode",
                                sizeof(vnode_t), 0, SLAB_RECLAIM_ACCOUNT,
-                               init_once, NULL);
-       if (linvfs_inode_zone == NULL)
-               return -ENOMEM;
+                               linvfs_inode_init_once, NULL);
+       if (!xfs_vnode_zone)
+               goto out;
+
+       xfs_ioend_zone = kmem_zone_init(sizeof(xfs_ioend_t), "xfs_ioend");
+       if (!xfs_ioend_zone)
+               goto out_destroy_vnode_zone;
+
+       xfs_ioend_pool = mempool_create(4 * MAX_BUF_PER_PAGE,
+                       mempool_alloc_slab, mempool_free_slab,
+                       xfs_ioend_zone);
+       if (!xfs_ioend_pool)
+               goto out_free_ioend_zone;
+
        return 0;
+
+
+ out_free_ioend_zone:
+       kmem_zone_destroy(xfs_ioend_zone);
+ out_destroy_vnode_zone:
+       kmem_zone_destroy(xfs_vnode_zone);
+ out:
+       return -ENOMEM;
 }
 
 STATIC void
-destroy_inodecache( void )
+linvfs_destroy_zones(void)
 {
-       if (kmem_cache_destroy(linvfs_inode_zone))
-               printk(KERN_WARNING "%s: cache still in use!\n", __FUNCTION__);
+       mempool_destroy(xfs_ioend_pool);
+       kmem_zone_destroy(xfs_vnode_zone);
+       kmem_zone_destroy(xfs_ioend_zone);
 }
 
 /*
@@ -354,17 +384,38 @@ linvfs_clear_inode(
        struct inode            *inode)
 {
        vnode_t                 *vp = LINVFS_GET_VP(inode);
+       int                     error, cache;
 
-       if (vp) {
-               vn_rele(vp);
-               vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
-               /*
-                * Do all our cleanup, and remove this vnode.
-                */
-               vn_remove(vp);
+       vn_trace_entry(vp, "clear_inode", (inst_t *)__return_address);
+
+       XFS_STATS_INC(vn_rele);
+       XFS_STATS_INC(vn_remove);
+       XFS_STATS_INC(vn_reclaim);
+       XFS_STATS_DEC(vn_active);
+
+       /*
+        * This can happen because xfs_iget_core calls xfs_idestroy if we
+        * find an inode with di_mode == 0 but without IGET_CREATE set.
+        */
+       if (vp->v_fbhv)
+               VOP_INACTIVE(vp, NULL, cache);
+
+       VN_LOCK(vp);
+       vp->v_flag &= ~VMODIFIED;
+       VN_UNLOCK(vp, 0);
+
+       if (vp->v_fbhv) {
+               VOP_RECLAIM(vp, error);
+               if (error)
+                       panic("vn_purge: cannot reclaim");
        }
-}
 
+       ASSERT(vp->v_fbhv == NULL);
+
+#ifdef XFS_VNODE_TRACE
+       ktrace_free(vp->v_trace);
+#endif
+}
 
 /*
  * Enqueue a work item to be picked up by the vfs xfssyncd thread.
@@ -466,25 +517,16 @@ xfssyncd(
 {
        long                    timeleft;
        vfs_t                   *vfsp = (vfs_t *) arg;
-       struct list_head        tmp;
        struct vfs_sync_work    *work, *n;
+       LIST_HEAD               (tmp);
 
-       daemonize("xfssyncd");
-
-       vfsp->vfs_sync_work.w_vfs = vfsp;
-       vfsp->vfs_sync_work.w_syncer = vfs_sync_worker;
-       vfsp->vfs_sync_task = current;
-       wmb();
-       wake_up(&vfsp->vfs_wait_sync_task);
-
-       INIT_LIST_HEAD(&tmp);
        timeleft = (xfs_syncd_centisecs * HZ) / 100;
        for (;;) {
                set_current_state(TASK_INTERRUPTIBLE);
                timeleft = schedule_timeout(timeleft);
                /* swsusp */
                try_to_freeze();
-               if (vfsp->vfs_flag & VFS_UMOUNT)
+               if (kthread_should_stop())
                        break;
 
                spin_lock(&vfsp->vfs_sync_lock);
@@ -513,10 +555,6 @@ xfssyncd(
                }
        }
 
-       vfsp->vfs_sync_task = NULL;
-       wmb();
-       wake_up(&vfsp->vfs_wait_sync_task);
-
        return 0;
 }
 
@@ -524,13 +562,11 @@ STATIC int
 linvfs_start_syncd(
        vfs_t                   *vfsp)
 {
-       int                     pid;
-
-       pid = kernel_thread(xfssyncd, (void *) vfsp,
-                       CLONE_VM | CLONE_FS | CLONE_FILES);
-       if (pid < 0)
-               return -pid;
-       wait_event(vfsp->vfs_wait_sync_task, vfsp->vfs_sync_task);
+       vfsp->vfs_sync_work.w_syncer = vfs_sync_worker;
+       vfsp->vfs_sync_work.w_vfs = vfsp;
+       vfsp->vfs_sync_task = kthread_run(xfssyncd, vfsp, "xfssyncd");
+       if (IS_ERR(vfsp->vfs_sync_task))
+               return -PTR_ERR(vfsp->vfs_sync_task);
        return 0;
 }
 
@@ -538,11 +574,7 @@ STATIC void
 linvfs_stop_syncd(
        vfs_t                   *vfsp)
 {
-       vfsp->vfs_flag |= VFS_UMOUNT;
-       wmb();
-
-       wake_up_process(vfsp->vfs_sync_task);
-       wait_event(vfsp->vfs_wait_sync_task, !vfsp->vfs_sync_task);
+       kthread_stop(vfsp->vfs_sync_task);
 }
 
 STATIC void
@@ -866,9 +898,9 @@ init_xfs_fs( void )
 
        ktrace_init(64);
 
-       error = init_inodecache();
+       error = linvfs_init_zones();
        if (error < 0)
-               goto undo_inodecache;
+               goto undo_zones;
 
        error = pagebuf_init();
        if (error < 0)
@@ -889,9 +921,9 @@ undo_register:
        pagebuf_terminate();
 
 undo_pagebuf:
-       destroy_inodecache();
+       linvfs_destroy_zones();
 
-undo_inodecache:
+undo_zones:
        return error;
 }
 
@@ -903,7 +935,7 @@ exit_xfs_fs( void )
        unregister_filesystem(&xfs_fs_type);
        xfs_cleanup();
        pagebuf_terminate();
-       destroy_inodecache();
+       linvfs_destroy_zones();
        ktrace_uninit();
 }
 
index 669c61644959cb9165ff52bbe919937d9299a537..34cc902ec11949c4395f35e1ee70db3038022443 100644 (file)
@@ -251,7 +251,6 @@ vfs_allocate( void )
        bhv_head_init(VFS_BHVHEAD(vfsp), "vfs");
        INIT_LIST_HEAD(&vfsp->vfs_sync_list);
        spin_lock_init(&vfsp->vfs_sync_lock);
-       init_waitqueue_head(&vfsp->vfs_wait_sync_task);
        init_waitqueue_head(&vfsp->vfs_wait_single_sync_task);
        return vfsp;
 }
index 7ee1f714e9babfcefe02864f9a785fcb4ab52973..f0ab574fb47acef1efd9f7a6b64cd374b5c41af6 100644 (file)
@@ -65,7 +65,6 @@ typedef struct vfs {
        spinlock_t              vfs_sync_lock;  /* work item list lock */
        int                     vfs_sync_seq;   /* sync thread generation no. */
        wait_queue_head_t       vfs_wait_single_sync_task;
-       wait_queue_head_t       vfs_wait_sync_task;
 } vfs_t;
 
 #define vfs_fbhv               vfs_bh.bh_first /* 1st on vfs behavior chain */
@@ -96,7 +95,6 @@ typedef enum {
 #define VFS_RDONLY             0x0001  /* read-only vfs */
 #define VFS_GRPID              0x0002  /* group-ID assigned from directory */
 #define VFS_DMI                        0x0004  /* filesystem has the DMI enabled */
-#define VFS_UMOUNT             0x0008  /* unmount in progress */
 #define VFS_END                        0x0008  /* max flag */
 
 #define SYNC_ATTR              0x0001  /* sync attributes */
index 250cad54e8920e4226f3fab93c05b4b3afb44a0d..268f45bf6a9a8b8a54234eb4f5a797738255e5d2 100644 (file)
@@ -42,93 +42,33 @@ DEFINE_SPINLOCK(vnumber_lock);
  */
 #define NVSYNC                  37
 #define vptosync(v)             (&vsync[((unsigned long)v) % NVSYNC])
-sv_t vsync[NVSYNC];
-
-/*
- * Translate stat(2) file types to vnode types and vice versa.
- * Aware of numeric order of S_IFMT and vnode type values.
- */
-enum vtype iftovt_tab[] = {
-       VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
-       VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VNON
-};
-
-u_short vttoif_tab[] = {
-       0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO, 0, S_IFSOCK
-};
+STATIC wait_queue_head_t vsync[NVSYNC];
 
 
 void
 vn_init(void)
 {
-       register sv_t *svp;
-       register int i;
+       int i;
 
-       for (svp = vsync, i = 0; i < NVSYNC; i++, svp++)
-               init_sv(svp, SV_DEFAULT, "vsy", i);
+       for (i = 0; i < NVSYNC; i++)
+               init_waitqueue_head(&vsync[i]);
 }
 
-/*
- * Clean a vnode of filesystem-specific data and prepare it for reuse.
- */
-STATIC int
-vn_reclaim(
+void
+vn_iowait(
        struct vnode    *vp)
 {
-       int             error;
+       wait_queue_head_t *wq = vptosync(vp);
 
-       XFS_STATS_INC(vn_reclaim);
-       vn_trace_entry(vp, "vn_reclaim", (inst_t *)__return_address);
-
-       /*
-        * Only make the VOP_RECLAIM call if there are behaviors
-        * to call.
-        */
-       if (vp->v_fbhv) {
-               VOP_RECLAIM(vp, error);
-               if (error)
-                       return -error;
-       }
-       ASSERT(vp->v_fbhv == NULL);
-
-       VN_LOCK(vp);
-       vp->v_flag &= (VRECLM|VWAIT);
-       VN_UNLOCK(vp, 0);
-
-       vp->v_type = VNON;
-       vp->v_fbhv = NULL;
-
-#ifdef XFS_VNODE_TRACE
-       ktrace_free(vp->v_trace);
-       vp->v_trace = NULL;
-#endif
-
-       return 0;
-}
-
-STATIC void
-vn_wakeup(
-       struct vnode    *vp)
-{
-       VN_LOCK(vp);
-       if (vp->v_flag & VWAIT)
-               sv_broadcast(vptosync(vp));
-       vp->v_flag &= ~(VRECLM|VWAIT|VMODIFIED);
-       VN_UNLOCK(vp, 0);
+       wait_event(*wq, (atomic_read(&vp->v_iocount) == 0));
 }
 
-int
-vn_wait(
+void
+vn_iowake(
        struct vnode    *vp)
 {
-       VN_LOCK(vp);
-       if (vp->v_flag & (VINACT | VRECLM)) {
-               vp->v_flag |= VWAIT;
-               sv_wait(vptosync(vp), PINOD, &vp->v_lock, 0);
-               return 1;
-       }
-       VN_UNLOCK(vp, 0);
-       return 0;
+       if (atomic_dec_and_test(&vp->v_iocount))
+               wake_up(vptosync(vp));
 }
 
 struct vnode *
@@ -154,6 +94,8 @@ vn_initialize(
        /* Initialize the first behavior and the behavior chain head. */
        vn_bhv_head_init(VN_BHV_HEAD(vp), "vnode");
 
+       atomic_set(&vp->v_iocount, 0);
+
 #ifdef XFS_VNODE_TRACE
        vp->v_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP);
 #endif /* XFS_VNODE_TRACE */
@@ -162,30 +104,6 @@ vn_initialize(
        return vp;
 }
 
-/*
- * Get a reference on a vnode.
- */
-vnode_t *
-vn_get(
-       struct vnode    *vp,
-       vmap_t          *vmap)
-{
-       struct inode    *inode;
-
-       XFS_STATS_INC(vn_get);
-       inode = LINVFS_GET_IP(vp);
-       if (inode->i_state & I_FREEING)
-               return NULL;
-
-       inode = ilookup(vmap->v_vfsp->vfs_super, vmap->v_ino);
-       if (!inode)     /* Inode not present */
-               return NULL;
-
-       vn_trace_exit(vp, "vn_get", (inst_t *)__return_address);
-
-       return vp;
-}
-
 /*
  * Revalidate the Linux inode from the vattr.
  * Note: i_size _not_ updated; we must hold the inode
@@ -198,7 +116,7 @@ vn_revalidate_core(
 {
        struct inode    *inode = LINVFS_GET_IP(vp);
 
-       inode->i_mode       = VTTOIF(vap->va_type) | vap->va_mode;
+       inode->i_mode       = vap->va_mode;
        inode->i_nlink      = vap->va_nlink;
        inode->i_uid        = vap->va_uid;
        inode->i_gid        = vap->va_gid;
@@ -246,71 +164,6 @@ vn_revalidate(
        return -error;
 }
 
-/*
- * purge a vnode from the cache
- * At this point the vnode is guaranteed to have no references (vn_count == 0)
- * The caller has to make sure that there are no ways someone could
- * get a handle (via vn_get) on the vnode (usually done via a mount/vfs lock).
- */
-void
-vn_purge(
-       struct vnode    *vp,
-       vmap_t          *vmap)
-{
-       vn_trace_entry(vp, "vn_purge", (inst_t *)__return_address);
-
-again:
-       /*
-        * Check whether vp has already been reclaimed since our caller
-        * sampled its version while holding a filesystem cache lock that
-        * its VOP_RECLAIM function acquires.
-        */
-       VN_LOCK(vp);
-       if (vp->v_number != vmap->v_number) {
-               VN_UNLOCK(vp, 0);
-               return;
-       }
-
-       /*
-        * If vp is being reclaimed or inactivated, wait until it is inert,
-        * then proceed.  Can't assume that vnode is actually reclaimed
-        * just because the reclaimed flag is asserted -- a vn_alloc
-        * reclaim can fail.
-        */
-       if (vp->v_flag & (VINACT | VRECLM)) {
-               ASSERT(vn_count(vp) == 0);
-               vp->v_flag |= VWAIT;
-               sv_wait(vptosync(vp), PINOD, &vp->v_lock, 0);
-               goto again;
-       }
-
-       /*
-        * Another process could have raced in and gotten this vnode...
-        */
-       if (vn_count(vp) > 0) {
-               VN_UNLOCK(vp, 0);
-               return;
-       }
-
-       XFS_STATS_DEC(vn_active);
-       vp->v_flag |= VRECLM;
-       VN_UNLOCK(vp, 0);
-
-       /*
-        * Call VOP_RECLAIM and clean vp. The FSYNC_INVAL flag tells
-        * vp's filesystem to flush and invalidate all cached resources.
-        * When vn_reclaim returns, vp should have no private data,
-        * either in a system cache or attached to v_data.
-        */
-       if (vn_reclaim(vp) != 0)
-               panic("vn_purge: cannot reclaim");
-
-       /*
-        * Wakeup anyone waiting for vp to be reclaimed.
-        */
-       vn_wakeup(vp);
-}
-
 /*
  * Add a reference to a referenced vnode.
  */
@@ -330,80 +183,6 @@ vn_hold(
        return vp;
 }
 
-/*
- *  Call VOP_INACTIVE on last reference.
- */
-void
-vn_rele(
-       struct vnode    *vp)
-{
-       int             vcnt;
-       int             cache;
-
-       XFS_STATS_INC(vn_rele);
-
-       VN_LOCK(vp);
-
-       vn_trace_entry(vp, "vn_rele", (inst_t *)__return_address);
-       vcnt = vn_count(vp);
-
-       /*
-        * Since we always get called from put_inode we know
-        * that i_count won't be decremented after we
-        * return.
-        */
-       if (!vcnt) {
-               /*
-                * As soon as we turn this on, noone can find us in vn_get
-                * until we turn off VINACT or VRECLM
-                */
-               vp->v_flag |= VINACT;
-               VN_UNLOCK(vp, 0);
-
-               /*
-                * Do not make the VOP_INACTIVE call if there
-                * are no behaviors attached to the vnode to call.
-                */
-               if (vp->v_fbhv)
-                       VOP_INACTIVE(vp, NULL, cache);
-
-               VN_LOCK(vp);
-               if (vp->v_flag & VWAIT)
-                       sv_broadcast(vptosync(vp));
-
-               vp->v_flag &= ~(VINACT|VWAIT|VRECLM|VMODIFIED);
-       }
-
-       VN_UNLOCK(vp, 0);
-
-       vn_trace_exit(vp, "vn_rele", (inst_t *)__return_address);
-}
-
-/*
- * Finish the removal of a vnode.
- */
-void
-vn_remove(
-       struct vnode    *vp)
-{
-       vmap_t          vmap;
-
-       /* Make sure we don't do this to the same vnode twice */
-       if (!(vp->v_fbhv))
-               return;
-
-       XFS_STATS_INC(vn_remove);
-       vn_trace_exit(vp, "vn_remove", (inst_t *)__return_address);
-
-       /*
-        * After the following purge the vnode
-        * will no longer exist.
-        */
-       VMAP(vp, vmap);
-       vn_purge(vp, &vmap);
-}
-
-
 #ifdef XFS_VNODE_TRACE
 
 #define KTRACE_ENTER(vp, vk, s, line, ra)                      \
index a6e57c647be4f3ae7a9ada8f6508e13967f94c17..35f306cebb87d2e2ac86d11bfea2906caec56d4b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -65,10 +65,6 @@ struct vattr;
 struct xfs_iomap;
 struct attrlist_cursor_kern;
 
-/*
- * Vnode types.  VNON means no type.
- */
-enum vtype     { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VFIFO, VBAD, VSOCK };
 
 typedef xfs_ino_t vnumber_t;
 typedef struct dentry vname_t;
@@ -77,15 +73,14 @@ typedef bhv_head_t vn_bhv_head_t;
 /*
  * MP locking protocols:
  *     v_flag, v_vfsp                          VN_LOCK/VN_UNLOCK
- *     v_type                                  read-only or fs-dependent
  */
 typedef struct vnode {
        __u32           v_flag;                 /* vnode flags (see below) */
-       enum vtype      v_type;                 /* vnode type */
        struct vfs      *v_vfsp;                /* ptr to containing VFS */
        vnumber_t       v_number;               /* in-core vnode number */
        vn_bhv_head_t   v_bh;                   /* behavior head */
        spinlock_t      v_lock;                 /* VN_LOCK/VN_UNLOCK */
+       atomic_t        v_iocount;              /* outstanding I/O count */
 #ifdef XFS_VNODE_TRACE
        struct ktrace   *v_trace;               /* trace header structure    */
 #endif
@@ -93,6 +88,12 @@ typedef struct vnode {
        /* inode MUST be last */
 } vnode_t;
 
+#define VN_ISLNK(vp)   S_ISLNK((vp)->v_inode.i_mode)
+#define VN_ISREG(vp)   S_ISREG((vp)->v_inode.i_mode)
+#define VN_ISDIR(vp)   S_ISDIR((vp)->v_inode.i_mode)
+#define VN_ISCHR(vp)   S_ISCHR((vp)->v_inode.i_mode)
+#define VN_ISBLK(vp)   S_ISBLK((vp)->v_inode.i_mode)
+
 #define v_fbhv                 v_bh.bh_first          /* first behavior */
 #define v_fops                 v_bh.bh_first->bd_ops  /* first behavior ops */
 
@@ -132,23 +133,9 @@ typedef enum {
 #define LINVFS_GET_VP(inode)   ((vnode_t *)list_entry(inode, vnode_t, v_inode))
 #define LINVFS_GET_IP(vp)      (&(vp)->v_inode)
 
-/*
- * Convert between vnode types and inode formats (since POSIX.1
- * defines mode word of stat structure in terms of inode formats).
- */
-extern enum vtype      iftovt_tab[];
-extern u_short         vttoif_tab[];
-#define IFTOVT(mode)   (iftovt_tab[((mode) & S_IFMT) >> 12])
-#define VTTOIF(indx)   (vttoif_tab[(int)(indx)])
-#define MAKEIMODE(indx, mode)  (int)(VTTOIF(indx) | (mode))
-
-
 /*
  * Vnode flags.
  */
-#define VINACT                0x1      /* vnode is being inactivated   */
-#define VRECLM                0x2      /* vnode is being reclaimed     */
-#define VWAIT                 0x4      /* waiting for VINACT/VRECLM to end */
 #define VMODIFIED             0x8      /* XFS inode state possibly differs */
                                        /* to the Linux inode state.    */
 
@@ -408,7 +395,6 @@ typedef struct vnodeops {
  */
 typedef struct vattr {
        int             va_mask;        /* bit-mask of attributes present */
-       enum vtype      va_type;        /* vnode type (for create) */
        mode_t          va_mode;        /* file access mode and type */
        xfs_nlink_t     va_nlink;       /* number of references to file */
        uid_t           va_uid;         /* owner user id */
@@ -498,26 +484,11 @@ typedef struct vattr {
  * Check whether mandatory file locking is enabled.
  */
 #define MANDLOCK(vp, mode)     \
-       ((vp)->v_type == VREG && ((mode) & (VSGID|(VEXEC>>3))) == VSGID)
+       (VN_ISREG(vp) && ((mode) & (VSGID|(VEXEC>>3))) == VSGID)
 
 extern void    vn_init(void);
-extern int     vn_wait(struct vnode *);
 extern vnode_t *vn_initialize(struct inode *);
 
-/*
- * Acquiring and invalidating vnodes:
- *
- *     if (vn_get(vp, version, 0))
- *             ...;
- *     vn_purge(vp, version);
- *
- * vn_get and vn_purge must be called with vmap_t arguments, sampled
- * while a lock that the vnode's VOP_RECLAIM function acquires is
- * held, to ensure that the vnode sampled with the lock held isn't
- * recycled (VOP_RECLAIMed) or deallocated between the release of the lock
- * and the subsequent vn_get or vn_purge.
- */
-
 /*
  * vnode_map structures _must_ match vn_epoch and vnode structure sizes.
  */
@@ -531,11 +502,11 @@ typedef struct vnode_map {
                         (vmap).v_number = (vp)->v_number,      \
                         (vmap).v_ino    = (vp)->v_inode.i_ino; }
 
-extern void    vn_purge(struct vnode *, vmap_t *);
-extern vnode_t *vn_get(struct vnode *, vmap_t *);
 extern int     vn_revalidate(struct vnode *);
 extern void    vn_revalidate_core(struct vnode *, vattr_t *);
-extern void    vn_remove(struct vnode *);
+
+extern void    vn_iowait(struct vnode *vp);
+extern void    vn_iowake(struct vnode *vp);
 
 static inline int vn_count(struct vnode *vp)
 {
@@ -546,7 +517,6 @@ static inline int vn_count(struct vnode *vp)
  * Vnode reference counting functions (and macros for compatibility).
  */
 extern vnode_t *vn_hold(struct vnode *);
-extern void    vn_rele(struct vnode *);
 
 #if defined(XFS_VNODE_TRACE)
 #define VN_HOLD(vp)            \
@@ -560,6 +530,12 @@ extern void        vn_rele(struct vnode *);
 #define VN_RELE(vp)            (iput(LINVFS_GET_IP(vp)))
 #endif
 
+static inline struct vnode *vn_grab(struct vnode *vp)
+{
+       struct inode *inode = igrab(LINVFS_GET_IP(vp));
+       return inode ? LINVFS_GET_VP(inode) : NULL;
+}
+
 /*
  * Vname handling macros.
  */
diff --git a/fs/xfs/quota/Makefile b/fs/xfs/quota/Makefile
new file mode 100644 (file)
index 0000000..7a4f725
--- /dev/null
@@ -0,0 +1 @@
+include $(TOPDIR)/fs/xfs/quota/Makefile-linux-$(VERSION).$(PATCHLEVEL)
diff --git a/fs/xfs/quota/Makefile-linux-2.6 b/fs/xfs/quota/Makefile-linux-2.6
new file mode 100644 (file)
index 0000000..8b7b676
--- /dev/null
@@ -0,0 +1,53 @@
+#
+# Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like. Any license provided herein, whether implied or
+# otherwise, applies only to this software file.  Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+# Mountain View, CA  94043, or:
+#
+# http://www.sgi.com
+#
+# For further information regarding this notice, see:
+#
+# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+
+EXTRA_CFLAGS += -I $(TOPDIR)/fs/xfs -I $(TOPDIR)/fs/xfs/linux-2.6
+
+ifeq ($(CONFIG_XFS_DEBUG),y)
+       EXTRA_CFLAGS += -g -DDEBUG
+       #EXTRA_CFLAGS += -DQUOTADEBUG
+endif
+ifeq ($(CONFIG_XFS_TRACE),y)
+       EXTRA_CFLAGS += -DXFS_DQUOT_TRACE
+       EXTRA_CFLAGS += -DXFS_VNODE_TRACE
+endif
+
+obj-$(CONFIG_XFS_QUOTA)                += xfs_quota.o
+
+xfs_quota-y                    += xfs_dquot.o \
+                                  xfs_dquot_item.o \
+                                  xfs_trans_dquot.o \
+                                  xfs_qm_syscalls.o \
+                                  xfs_qm_bhv.o \
+                                  xfs_qm.o
+
+xfs_quota-$(CONFIG_PROC_FS)    += xfs_qm_stats.o
index 46ce1e3ce1d6c04c90b93ec46d86d2e4f64651fc..e2e8d35fa4d0361517bdb1d76f7c08c6de512f20 100644 (file)
@@ -421,7 +421,7 @@ xfs_qm_init_dquot_blk(
  */
 STATIC int
 xfs_qm_dqalloc(
-       xfs_trans_t     *tp,
+       xfs_trans_t     **tpp,
        xfs_mount_t     *mp,
        xfs_dquot_t     *dqp,
        xfs_inode_t     *quotip,
@@ -433,6 +433,7 @@ xfs_qm_dqalloc(
        xfs_bmbt_irec_t map;
        int             nmaps, error, committed;
        xfs_buf_t       *bp;
+       xfs_trans_t     *tp = *tpp;
 
        ASSERT(tp != NULL);
        xfs_dqtrace_entry(dqp, "DQALLOC");
@@ -492,10 +493,32 @@ xfs_qm_dqalloc(
        xfs_qm_init_dquot_blk(tp, mp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT),
                              dqp->dq_flags & XFS_DQ_ALLTYPES, bp);
 
-       if ((error = xfs_bmap_finish(&tp, &flist, firstblock, &committed))) {
+       /*
+        * xfs_bmap_finish() may commit the current transaction and
+        * start a second transaction if the freelist is not empty.
+        *
+        * Since we still want to modify this buffer, we need to
+        * ensure that the buffer is not released on commit of
+        * the first transaction and ensure the buffer is added to the
+        * second transaction.
+        *
+        * If there is only one transaction then don't stop the buffer
+        * from being released when it commits later on.
+        */
+
+       xfs_trans_bhold(tp, bp);
+
+       if ((error = xfs_bmap_finish(tpp, &flist, firstblock, &committed))) {
                goto error1;
        }
 
+       if (committed) {
+               tp = *tpp;
+               xfs_trans_bjoin(tp, bp);
+       } else {
+               xfs_trans_bhold_release(tp, bp);
+       }
+
        *O_bpp = bp;
        return 0;
 
@@ -514,7 +537,7 @@ xfs_qm_dqalloc(
  */
 STATIC int
 xfs_qm_dqtobp(
-       xfs_trans_t             *tp,
+       xfs_trans_t             **tpp,
        xfs_dquot_t             *dqp,
        xfs_disk_dquot_t        **O_ddpp,
        xfs_buf_t               **O_bpp,
@@ -528,6 +551,7 @@ xfs_qm_dqtobp(
        xfs_disk_dquot_t *ddq;
        xfs_dqid_t      id;
        boolean_t       newdquot;
+       xfs_trans_t     *tp = (tpp ? *tpp : NULL);
 
        mp = dqp->q_mount;
        id = INT_GET(dqp->q_core.d_id, ARCH_CONVERT);
@@ -579,9 +603,10 @@ xfs_qm_dqtobp(
                                return (ENOENT);
 
                        ASSERT(tp);
-                       if ((error = xfs_qm_dqalloc(tp, mp, dqp, quotip,
+                       if ((error = xfs_qm_dqalloc(tpp, mp, dqp, quotip,
                                                dqp->q_fileoffset, &bp)))
                                return (error);
+                       tp = *tpp;
                        newdquot = B_TRUE;
                } else {
                        /*
@@ -645,7 +670,7 @@ xfs_qm_dqtobp(
 /* ARGSUSED */
 STATIC int
 xfs_qm_dqread(
-       xfs_trans_t     *tp,
+       xfs_trans_t     **tpp,
        xfs_dqid_t      id,
        xfs_dquot_t     *dqp,   /* dquot to get filled in */
        uint            flags)
@@ -653,15 +678,19 @@ xfs_qm_dqread(
        xfs_disk_dquot_t *ddqp;
        xfs_buf_t        *bp;
        int              error;
+       xfs_trans_t      *tp;
+
+       ASSERT(tpp);
 
        /*
         * get a pointer to the on-disk dquot and the buffer containing it
         * dqp already knows its own type (GROUP/USER).
         */
        xfs_dqtrace_entry(dqp, "DQREAD");
-       if ((error = xfs_qm_dqtobp(tp, dqp, &ddqp, &bp, flags))) {
+       if ((error = xfs_qm_dqtobp(tpp, dqp, &ddqp, &bp, flags))) {
                return (error);
        }
+       tp = *tpp;
 
        /* copy everything from disk dquot to the incore dquot */
        memcpy(&dqp->q_core, ddqp, sizeof(xfs_disk_dquot_t));
@@ -740,7 +769,7 @@ xfs_qm_idtodq(
         * Read it from disk; xfs_dqread() takes care of
         * all the necessary initialization of dquot's fields (locks, etc)
         */
-       if ((error = xfs_qm_dqread(tp, id, dqp, flags))) {
+       if ((error = xfs_qm_dqread(&tp, id, dqp, flags))) {
                /*
                 * This can happen if quotas got turned off (ESRCH),
                 * or if the dquot didn't exist on disk and we ask to
index 39175103c8e0ca5ec2c81a859d5dc846aa6dab0e..8ebc87176c78c464f32a7069def5fbe6fbca127a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -113,20 +113,6 @@ typedef struct xfs_dquot {
 
 #define XFS_DQHOLD(dqp)                ((dqp)->q_nrefs++)
 
-/*
- * Quota Accounting/Enforcement flags
- */
-#define XFS_ALL_QUOTA_ACCT     \
-               (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT | XFS_PQUOTA_ACCT)
-#define XFS_ALL_QUOTA_ENFD     (XFS_UQUOTA_ENFD | XFS_OQUOTA_ENFD)
-#define XFS_ALL_QUOTA_CHKD     (XFS_UQUOTA_CHKD | XFS_OQUOTA_CHKD)
-
-#define XFS_IS_QUOTA_RUNNING(mp)       ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT)
-#define XFS_IS_QUOTA_ENFORCED(mp)      ((mp)->m_qflags & XFS_ALL_QUOTA_ENFD)
-#define XFS_IS_UQUOTA_RUNNING(mp)      ((mp)->m_qflags & XFS_UQUOTA_ACCT)
-#define XFS_IS_PQUOTA_RUNNING(mp)      ((mp)->m_qflags & XFS_PQUOTA_ACCT)
-#define XFS_IS_GQUOTA_RUNNING(mp)      ((mp)->m_qflags & XFS_GQUOTA_ACCT)
-
 #ifdef DEBUG
 static inline int
 XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp)
index f5271b7b1e84196c2d1202cc4c630747b9f54183..e74eaa7dd1bc6914a51f1e775d919354778432ca 100644 (file)
@@ -509,6 +509,7 @@ xfs_qm_qoff_logitem_format(xfs_qoff_logitem_t       *qf,
 
        log_vector->i_addr = (xfs_caddr_t)&(qf->qql_format);
        log_vector->i_len = sizeof(xfs_qoff_logitem_t);
+       XLOG_VEC_SET_TYPE(log_vector, XLOG_REG_TYPE_QUOTAOFF);
        qf->qql_format.qf_size = 1;
 }
 
index f665ca8f9e960c93c65d0cc31c244fded5f3e73a..efde16e0a91345b182aa1731c42f8388dd8cf31e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -365,16 +365,6 @@ xfs_qm_mount_quotas(
        int             error = 0;
        uint            sbf;
 
-       /*
-        * If a file system had quotas running earlier, but decided to
-        * mount without -o uquota/pquota/gquota options, revoke the
-        * quotachecked license, and bail out.
-        */
-       if (! XFS_IS_QUOTA_ON(mp) &&
-           (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT)) {
-               mp->m_qflags = 0;
-               goto write_changes;
-       }
 
        /*
         * If quotas on realtime volumes is not supported, we disable
@@ -388,11 +378,8 @@ xfs_qm_mount_quotas(
                goto write_changes;
        }
 
-#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
-       cmn_err(CE_NOTE, "Attempting to turn on disk quotas.");
-#endif
-
        ASSERT(XFS_IS_QUOTA_RUNNING(mp));
+
        /*
         * Allocate the quotainfo structure inside the mount struct, and
         * create quotainode(s), and change/rev superblock if necessary.
@@ -410,19 +397,14 @@ xfs_qm_mount_quotas(
         */
        if (XFS_QM_NEED_QUOTACHECK(mp) &&
                !(mfsi_flags & XFS_MFSI_NO_QUOTACHECK)) {
-#ifdef DEBUG
-               cmn_err(CE_NOTE, "Doing a quotacheck. Please wait.");
-#endif
                if ((error = xfs_qm_quotacheck(mp))) {
                        /* Quotacheck has failed and quotas have
                         * been disabled.
                         */
                        return XFS_ERROR(error);
                }
-#ifdef DEBUG
-               cmn_err(CE_NOTE, "Done quotacheck.");
-#endif
        }
+
  write_changes:
        /*
         * We actually don't have to acquire the SB_LOCK at all.
@@ -2010,7 +1992,7 @@ xfs_qm_quotacheck(
                ASSERT(mp->m_quotainfo != NULL);
                ASSERT(xfs_Gqm != NULL);
                xfs_qm_destroy_quotainfo(mp);
-               xfs_mount_reset_sbqflags(mp);
+               (void)xfs_mount_reset_sbqflags(mp);
        } else {
                cmn_err(CE_NOTE, "XFS quotacheck %s: Done.", mp->m_fsname);
        }
index b03eecf3b6cb19c4dba39596ce440178ebd858fd..0b00b3c67015eede68ce28da43a5d27beb19aeee 100644 (file)
@@ -184,8 +184,6 @@ typedef struct xfs_dquot_acct {
 #define XFS_QM_HOLD(xqm)       ((xqm)->qm_nrefs++)
 #define XFS_QM_RELE(xqm)       ((xqm)->qm_nrefs--)
 
-extern void            xfs_mount_reset_sbqflags(xfs_mount_t *);
-
 extern void            xfs_qm_destroy_quotainfo(xfs_mount_t *);
 extern int             xfs_qm_mount_quotas(xfs_mount_t *, int);
 extern void            xfs_qm_mount_quotainit(xfs_mount_t *, uint);
index dc3c37a1e1585702eeb814da992b216b57f4c96d..8890a18a99d8cc98857d694fc55368eb41ede195 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -229,48 +229,6 @@ xfs_qm_syncall(
        return error;
 }
 
-/*
- * Clear the quotaflags in memory and in the superblock.
- */
-void
-xfs_mount_reset_sbqflags(
-       xfs_mount_t             *mp)
-{
-       xfs_trans_t             *tp;
-       unsigned long           s;
-
-       mp->m_qflags = 0;
-       /*
-        * It is OK to look at sb_qflags here in mount path,
-        * without SB_LOCK.
-        */
-       if (mp->m_sb.sb_qflags == 0)
-               return;
-       s = XFS_SB_LOCK(mp);
-       mp->m_sb.sb_qflags = 0;
-       XFS_SB_UNLOCK(mp, s);
-
-       /*
-        * if the fs is readonly, let the incore superblock run
-        * with quotas off but don't flush the update out to disk
-        */
-       if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY)
-               return;
-#ifdef QUOTADEBUG
-       xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes");
-#endif
-       tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
-       if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
-                                     XFS_DEFAULT_LOG_COUNT)) {
-               xfs_trans_cancel(tp, 0);
-               xfs_fs_cmn_err(CE_ALERT, mp,
-                       "xfs_mount_reset_sbqflags: Superblock update failed!");
-               return;
-       }
-       xfs_mod_sb(tp, XFS_SB_QFLAGS);
-       xfs_trans_commit(tp, 0, NULL);
-}
-
 STATIC int
 xfs_qm_newmount(
        xfs_mount_t     *mp,
index 68e98962dbefe0db3f303204c97c53b82b6da975..15e02e8a9d4fc23c2850eac3b1e936f4350a859f 100644 (file)
@@ -1053,7 +1053,6 @@ xfs_qm_dqrele_all_inodes(
        struct xfs_mount *mp,
        uint             flags)
 {
-       vmap_t          vmap;
        xfs_inode_t     *ip, *topino;
        uint            ireclaims;
        vnode_t         *vp;
@@ -1061,8 +1060,8 @@ xfs_qm_dqrele_all_inodes(
 
        ASSERT(mp->m_quotainfo);
 
-again:
        XFS_MOUNT_ILOCK(mp);
+again:
        ip = mp->m_inodes;
        if (ip == NULL) {
                XFS_MOUNT_IUNLOCK(mp);
@@ -1090,18 +1089,14 @@ again:
                }
                vnode_refd = B_FALSE;
                if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) {
-                       /*
-                        * Sample vp mapping while holding the mplock, lest
-                        * we come across a non-existent vnode.
-                        */
-                       VMAP(vp, vmap);
                        ireclaims = mp->m_ireclaims;
                        topino = mp->m_inodes;
-                       XFS_MOUNT_IUNLOCK(mp);
+                       vp = vn_grab(vp);
+                       if (!vp)
+                               goto again;
 
+                       XFS_MOUNT_IUNLOCK(mp);
                        /* XXX restart limit ? */
-                       if ( ! (vp = vn_get(vp, &vmap)))
-                               goto again;
                        xfs_ilock(ip, XFS_ILOCK_EXCL);
                        vnode_refd = B_TRUE;
                } else {
@@ -1137,7 +1132,6 @@ again:
                 */
                if (topino != mp->m_inodes || mp->m_ireclaims != ireclaims) {
                        /* XXX use a sentinel */
-                       XFS_MOUNT_IUNLOCK(mp);
                        goto again;
                }
                ip = ip->i_mnext;
index 4ed7b6928cd78c4e6a02f0e4930116174295f4f2..4e1a5ec22fa370b3c6d4056d1e64cc746dd6444c 100644 (file)
@@ -31,6 +31,7 @@
  */
 
 #include "debug.h"
+#include "spin.h"
 
 #include <asm/page.h>
 #include <linux/sched.h>
index 8d01dce8c532fd2d1fd3093128ff9e4607d08e52..92fd1d67f878f4fc0c3ed2a8b75a9ff65a3ba7a5 100644 (file)
@@ -85,7 +85,7 @@ xfs_acl_vhasacl_default(
 {
        int             error;
 
-       if (vp->v_type != VDIR)
+       if (!VN_ISDIR(vp))
                return 0;
        xfs_acl_get_attr(vp, NULL, _ACL_TYPE_DEFAULT, ATTR_KERNOVAL, &error);
        return (error == 0);
@@ -389,7 +389,7 @@ xfs_acl_allow_set(
 
        if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
                return EPERM;
-       if (kind == _ACL_TYPE_DEFAULT && vp->v_type != VDIR)
+       if (kind == _ACL_TYPE_DEFAULT && !VN_ISDIR(vp))
                return ENOTDIR;
        if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
                return EROFS;
@@ -750,7 +750,7 @@ xfs_acl_inherit(
         * If the new file is a directory, its default ACL is a copy of
         * the containing directory's default ACL.
         */
-       if (vp->v_type == VDIR)
+       if (VN_ISDIR(vp))
                xfs_acl_set_attr(vp, pdaclp, _ACL_TYPE_DEFAULT, &error);
        if (!error && !basicperms)
                xfs_acl_set_attr(vp, cacl, _ACL_TYPE_ACCESS, &error);
index 6f5d283888aa2b9ab243d93f8df1fe25c4e8cc34..3e76def1283d191c8827588b221e94b981f34845 100644 (file)
@@ -4754,10 +4754,20 @@ xfs_bmapi(
                                        error = xfs_mod_incore_sb(mp,
                                                        XFS_SBS_FDBLOCKS,
                                                        -(alen), rsvd);
-                               if (!error)
+                               if (!error) {
                                        error = xfs_mod_incore_sb(mp,
                                                        XFS_SBS_FDBLOCKS,
                                                        -(indlen), rsvd);
+                                       if (error && rt) {
+                                               xfs_mod_incore_sb(ip->i_mount,
+                                                       XFS_SBS_FREXTENTS,
+                                                       extsz, rsvd);
+                                       } else if (error) {
+                                               xfs_mod_incore_sb(ip->i_mount,
+                                                       XFS_SBS_FDBLOCKS,
+                                                       alen, rsvd);
+                                       }
+                               }
 
                                if (error) {
                                        if (XFS_IS_QUOTA_ON(ip->i_mount))
index 30b8285ad4769de7f6ee5b5007ae80dee9519b29..a264657acfd9ed069452fc59725e170ba77222ea 100644 (file)
@@ -274,6 +274,7 @@ xfs_buf_item_format(
                       ((bip->bli_format.blf_map_size - 1) * sizeof(uint)));
        vecp->i_addr = (xfs_caddr_t)&bip->bli_format;
        vecp->i_len = base_size;
+       XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BFORMAT);
        vecp++;
        nvecs = 1;
 
@@ -320,12 +321,14 @@ xfs_buf_item_format(
                        buffer_offset = first_bit * XFS_BLI_CHUNK;
                        vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
                        vecp->i_len = nbits * XFS_BLI_CHUNK;
+                       XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BCHUNK);
                        nvecs++;
                        break;
                } else if (next_bit != last_bit + 1) {
                        buffer_offset = first_bit * XFS_BLI_CHUNK;
                        vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
                        vecp->i_len = nbits * XFS_BLI_CHUNK;
+                       XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BCHUNK);
                        nvecs++;
                        vecp++;
                        first_bit = next_bit;
@@ -337,6 +340,7 @@ xfs_buf_item_format(
                        buffer_offset = first_bit * XFS_BLI_CHUNK;
                        vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
                        vecp->i_len = nbits * XFS_BLI_CHUNK;
+                       XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BCHUNK);
 /* You would think we need to bump the nvecs here too, but we do not
  * this number is used by recovery, and it gets confused by the boundary
  * split here
index 55c17adaaa37d64e3c7b22be419bbd6398a9c428..19e872856f6bdc0e32129499e5c64004c127d23d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
index db7cbd1bc8573e81d5f05699032b7731573a5bf2..cc7d1494a45d1a449151451f3a109d4abec8589d 100644 (file)
@@ -107,6 +107,7 @@ xfs_efi_item_format(xfs_efi_log_item_t      *efip,
 
        log_vector->i_addr = (xfs_caddr_t)&(efip->efi_format);
        log_vector->i_len = size;
+       XLOG_VEC_SET_TYPE(log_vector, XLOG_REG_TYPE_EFI_FORMAT);
        ASSERT(size >= sizeof(xfs_efi_log_format_t));
 }
 
@@ -426,6 +427,7 @@ xfs_efd_item_format(xfs_efd_log_item_t      *efdp,
 
        log_vector->i_addr = (xfs_caddr_t)&(efdp->efd_format);
        log_vector->i_len = size;
+       XLOG_VEC_SET_TYPE(log_vector, XLOG_REG_TYPE_EFD_FORMAT);
        ASSERT(size >= sizeof(xfs_efd_log_format_t));
 }
 
index d3da00045f260074fca466319a23bfdc34ed14c3..0d9ae8fb41386c956bc43e07d383ffac7697d7fb 100644 (file)
@@ -30,6 +30,8 @@
  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
  */
 
+#include <linux/delay.h>
+
 #include "xfs.h"
 
 #include "xfs_macros.h"
@@ -505,17 +507,15 @@ xfs_iget(
        vnode_t         *vp = NULL;
        int             error;
 
-retry:
        XFS_STATS_INC(xs_ig_attempts);
 
+retry:
        if ((inode = iget_locked(XFS_MTOVFS(mp)->vfs_super, ino))) {
                bhv_desc_t      *bdp;
                xfs_inode_t     *ip;
-               int             newnode;
 
                vp = LINVFS_GET_VP(inode);
                if (inode->i_state & I_NEW) {
-inode_allocate:
                        vn_initialize(inode);
                        error = xfs_iget_core(vp, mp, tp, ino, flags,
                                        lock_flags, ipp, bno);
@@ -526,32 +526,25 @@ inode_allocate:
                                iput(inode);
                        }
                } else {
-                       /* These are true if the inode is in inactive or
-                        * reclaim. The linux inode is about to go away,
-                        * wait for that path to finish, and try again.
+                       /*
+                        * If the inode is not fully constructed due to
+                        * filehandle mistmatches wait for the inode to go
+                        * away and try again.
+                        *
+                        * iget_locked will call __wait_on_freeing_inode
+                        * to wait for the inode to go away.
                         */
-                       if (vp->v_flag & (VINACT | VRECLM)) {
-                               vn_wait(vp);
+                       if (is_bad_inode(inode) ||
+                           ((bdp = vn_bhv_lookup(VN_BHV_HEAD(vp),
+                                                 &xfs_vnodeops)) == NULL)) {
                                iput(inode);
+                               delay(1);
                                goto retry;
                        }
 
-                       if (is_bad_inode(inode)) {
-                               iput(inode);
-                               return EIO;
-                       }
-
-                       bdp = vn_bhv_lookup(VN_BHV_HEAD(vp), &xfs_vnodeops);
-                       if (bdp == NULL) {
-                               XFS_STATS_INC(xs_ig_dup);
-                               goto inode_allocate;
-                       }
                        ip = XFS_BHVTOI(bdp);
                        if (lock_flags != 0)
                                xfs_ilock(ip, lock_flags);
-                       newnode = (ip->i_d.di_mode == 0);
-                       if (newnode)
-                               xfs_iocore_inode_reinit(ip);
                        XFS_STATS_INC(xs_ig_found);
                        *ipp = ip;
                        error = 0;
index 34bdf5909687b30d0619e3e9f6d42feee4de4098..db43308aae9329597e961bc71b8c844c8fc313cd 100644 (file)
@@ -1128,7 +1128,6 @@ xfs_ialloc(
        ASSERT(ip != NULL);
 
        vp = XFS_ITOV(ip);
-       vp->v_type = IFTOVT(mode);
        ip->i_d.di_mode = (__uint16_t)mode;
        ip->i_d.di_onlink = 0;
        ip->i_d.di_nlink = nlink;
@@ -1250,7 +1249,7 @@ xfs_ialloc(
         */
        xfs_trans_log_inode(tp, ip, flags);
 
-       /* now that we have a v_type we can set Linux inode ops (& unlock) */
+       /* now that we have an i_mode  we can set Linux inode ops (& unlock) */
        VFS_INIT_VNODE(XFS_MTOVFS(tp->t_mountp), vp, XFS_ITOBHV(ip), 1);
 
        *ipp = ip;
index 0eed30f5cb19de82e45518bb1f2b08c963f9d7d3..276ec70eb7f9ab12db2b6102a7382a13128aadd6 100644 (file)
@@ -248,6 +248,7 @@ xfs_inode_item_format(
 
        vecp->i_addr = (xfs_caddr_t)&iip->ili_format;
        vecp->i_len  = sizeof(xfs_inode_log_format_t);
+       XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IFORMAT);
        vecp++;
        nvecs        = 1;
 
@@ -292,6 +293,7 @@ xfs_inode_item_format(
 
        vecp->i_addr = (xfs_caddr_t)&ip->i_d;
        vecp->i_len  = sizeof(xfs_dinode_core_t);
+       XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_ICORE);
        vecp++;
        nvecs++;
        iip->ili_format.ilf_fields |= XFS_ILOG_CORE;
@@ -349,6 +351,7 @@ xfs_inode_item_format(
                                vecp->i_addr =
                                        (char *)(ip->i_df.if_u1.if_extents);
                                vecp->i_len = ip->i_df.if_bytes;
+                               XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IEXT);
                        } else
 #endif
                        {
@@ -367,6 +370,7 @@ xfs_inode_item_format(
                                vecp->i_addr = (xfs_caddr_t)ext_buffer;
                                vecp->i_len = xfs_iextents_copy(ip, ext_buffer,
                                                XFS_DATA_FORK);
+                               XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IEXT);
                        }
                        ASSERT(vecp->i_len <= ip->i_df.if_bytes);
                        iip->ili_format.ilf_dsize = vecp->i_len;
@@ -384,6 +388,7 @@ xfs_inode_item_format(
                        ASSERT(ip->i_df.if_broot != NULL);
                        vecp->i_addr = (xfs_caddr_t)ip->i_df.if_broot;
                        vecp->i_len = ip->i_df.if_broot_bytes;
+                       XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IBROOT);
                        vecp++;
                        nvecs++;
                        iip->ili_format.ilf_dsize = ip->i_df.if_broot_bytes;
@@ -409,6 +414,7 @@ xfs_inode_item_format(
                        ASSERT((ip->i_df.if_real_bytes == 0) ||
                               (ip->i_df.if_real_bytes == data_bytes));
                        vecp->i_len = (int)data_bytes;
+                       XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_ILOCAL);
                        vecp++;
                        nvecs++;
                        iip->ili_format.ilf_dsize = (unsigned)data_bytes;
@@ -486,6 +492,7 @@ xfs_inode_item_format(
                        vecp->i_len = xfs_iextents_copy(ip, ext_buffer,
                                        XFS_ATTR_FORK);
 #endif
+                       XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IATTR_EXT);
                        iip->ili_format.ilf_asize = vecp->i_len;
                        vecp++;
                        nvecs++;
@@ -500,6 +507,7 @@ xfs_inode_item_format(
                        ASSERT(ip->i_afp->if_broot != NULL);
                        vecp->i_addr = (xfs_caddr_t)ip->i_afp->if_broot;
                        vecp->i_len = ip->i_afp->if_broot_bytes;
+                       XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IATTR_BROOT);
                        vecp++;
                        nvecs++;
                        iip->ili_format.ilf_asize = ip->i_afp->if_broot_bytes;
@@ -523,6 +531,7 @@ xfs_inode_item_format(
                        ASSERT((ip->i_afp->if_real_bytes == 0) ||
                               (ip->i_afp->if_real_bytes == data_bytes));
                        vecp->i_len = (int)data_bytes;
+                       XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IATTR_LOCAL);
                        vecp++;
                        nvecs++;
                        iip->ili_format.ilf_asize = (unsigned)data_bytes;
index 2edd6769e5d328d18da1d854d69595ff3cb5a996..d0f5be63cddb71b0e0a647d124550c57ac5b3114 100644 (file)
@@ -226,13 +226,12 @@ xfs_iomap(
                xfs_iomap_enter_trace(XFS_IOMAP_READ_ENTER, io, offset, count);
                lockmode = XFS_LCK_MAP_SHARED(mp, io);
                bmapi_flags = XFS_BMAPI_ENTIRE;
-               if (flags & BMAPI_IGNSTATE)
-                       bmapi_flags |= XFS_BMAPI_IGSTATE;
                break;
        case BMAPI_WRITE:
                xfs_iomap_enter_trace(XFS_IOMAP_WRITE_ENTER, io, offset, count);
                lockmode = XFS_ILOCK_EXCL|XFS_EXTSIZE_WR;
-               bmapi_flags = 0;
+               if (flags & BMAPI_IGNSTATE)
+                       bmapi_flags |= XFS_BMAPI_IGSTATE|XFS_BMAPI_ENTIRE;
                XFS_ILOCK(mp, io, lockmode);
                break;
        case BMAPI_ALLOCATE:
@@ -391,9 +390,9 @@ xfs_iomap_write_direct(
        xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS], *imapp;
        xfs_bmap_free_t free_list;
        int             aeof;
-       xfs_filblks_t   datablocks, qblocks, resblks;
+       xfs_filblks_t   qblocks, resblks;
        int             committed;
-       int             numrtextents;
+       int             resrtextents;
 
        /*
         * Make sure that the dquots are there. This doesn't hold
@@ -434,14 +433,14 @@ xfs_iomap_write_direct(
 
                if (!(extsz = ip->i_d.di_extsize))
                        extsz = mp->m_sb.sb_rextsize;
-               numrtextents = qblocks = (count_fsb + extsz - 1);
-               do_div(numrtextents, mp->m_sb.sb_rextsize);
+               resrtextents = qblocks = (count_fsb + extsz - 1);
+               do_div(resrtextents, mp->m_sb.sb_rextsize);
+               resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
                quota_flag = XFS_QMOPT_RES_RTBLKS;
-               datablocks = 0;
        } else {
-               datablocks = qblocks = count_fsb;
+               resrtextents = 0;
+               resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, count_fsb);
                quota_flag = XFS_QMOPT_RES_REGBLKS;
-               numrtextents = 0;
        }
 
        /*
@@ -449,9 +448,8 @@ xfs_iomap_write_direct(
         */
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
        tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
-       resblks = XFS_DIOSTRAT_SPACE_RES(mp, datablocks);
        error = xfs_trans_reserve(tp, resblks,
-                       XFS_WRITE_LOG_RES(mp), numrtextents,
+                       XFS_WRITE_LOG_RES(mp), resrtextents,
                        XFS_TRANS_PERM_LOG_RES,
                        XFS_WRITE_LOG_COUNT);
 
index 1cd2ac1638778b3e69c67acd6a47280cdc52cd3a..54a6f114240311867fa4a55a7deaa2612584abfa 100644 (file)
@@ -159,11 +159,15 @@ xfs_buftarg_t *xlog_target;
 void
 xlog_trace_loggrant(xlog_t *log, xlog_ticket_t *tic, xfs_caddr_t string)
 {
-       if (! log->l_grant_trace) {
-               log->l_grant_trace = ktrace_alloc(1024, KM_NOSLEEP);
-               if (! log->l_grant_trace)
+       unsigned long cnts;
+
+       if (!log->l_grant_trace) {
+               log->l_grant_trace = ktrace_alloc(2048, KM_NOSLEEP);
+               if (!log->l_grant_trace)
                        return;
        }
+       /* ticket counts are 1 byte each */
+       cnts = ((unsigned long)tic->t_ocnt) | ((unsigned long)tic->t_cnt) << 8;
 
        ktrace_enter(log->l_grant_trace,
                     (void *)tic,
@@ -178,10 +182,10 @@ xlog_trace_loggrant(xlog_t *log, xlog_ticket_t *tic, xfs_caddr_t string)
                     (void *)((unsigned long)CYCLE_LSN(log->l_tail_lsn)),
                     (void *)((unsigned long)BLOCK_LSN(log->l_tail_lsn)),
                     (void *)string,
-                    (void *)((unsigned long)13),
-                    (void *)((unsigned long)14),
-                    (void *)((unsigned long)15),
-                    (void *)((unsigned long)16));
+                    (void *)((unsigned long)tic->t_trans_type),
+                    (void *)cnts,
+                    (void *)((unsigned long)tic->t_curr_res),
+                    (void *)((unsigned long)tic->t_unit_res));
 }
 
 void
@@ -274,9 +278,11 @@ xfs_log_done(xfs_mount_t   *mp,
                 * Release ticket if not permanent reservation or a specifc
                 * request has been made to release a permanent reservation.
                 */
+               xlog_trace_loggrant(log, ticket, "xfs_log_done: (non-permanent)");
                xlog_ungrant_log_space(log, ticket);
                xlog_state_put_ticket(log, ticket);
        } else {
+               xlog_trace_loggrant(log, ticket, "xfs_log_done: (permanent)");
                xlog_regrant_reserve_log_space(log, ticket);
        }
 
@@ -399,7 +405,8 @@ xfs_log_reserve(xfs_mount_t  *mp,
                int              cnt,
                xfs_log_ticket_t *ticket,
                __uint8_t        client,
-               uint             flags)
+               uint             flags,
+               uint             t_type)
 {
        xlog_t          *log = mp->m_log;
        xlog_ticket_t   *internal_ticket;
@@ -421,13 +428,19 @@ xfs_log_reserve(xfs_mount_t        *mp,
        if (*ticket != NULL) {
                ASSERT(flags & XFS_LOG_PERM_RESERV);
                internal_ticket = (xlog_ticket_t *)*ticket;
+               xlog_trace_loggrant(log, internal_ticket, "xfs_log_reserve: existing ticket (permanent trans)");
                xlog_grant_push_ail(mp, internal_ticket->t_unit_res);
                retval = xlog_regrant_write_log_space(log, internal_ticket);
        } else {
                /* may sleep if need to allocate more tickets */
                internal_ticket = xlog_ticket_get(log, unit_bytes, cnt,
                                                  client, flags);
+               internal_ticket->t_trans_type = t_type;
                *ticket = internal_ticket;
+               xlog_trace_loggrant(log, internal_ticket, 
+                       (internal_ticket->t_flags & XLOG_TIC_PERM_RESERV) ?
+                       "xfs_log_reserve: create new ticket (permanent trans)" :
+                       "xfs_log_reserve: create new ticket");
                xlog_grant_push_ail(mp,
                                    (internal_ticket->t_unit_res *
                                     internal_ticket->t_cnt));
@@ -601,8 +614,9 @@ xfs_log_unmount_write(xfs_mount_t *mp)
        if (! (XLOG_FORCED_SHUTDOWN(log))) {
                reg[0].i_addr = (void*)&magic;
                reg[0].i_len  = sizeof(magic);
+               XLOG_VEC_SET_TYPE(&reg[0], XLOG_REG_TYPE_UNMOUNT);
 
-               error = xfs_log_reserve(mp, 600, 1, &tic, XFS_LOG, 0);
+               error = xfs_log_reserve(mp, 600, 1, &tic, XFS_LOG, 0, 0);
                if (!error) {
                        /* remove inited flag */
                        ((xlog_ticket_t *)tic)->t_flags = 0;
@@ -1272,6 +1286,7 @@ xlog_commit_record(xfs_mount_t  *mp,
 
        reg[0].i_addr = NULL;
        reg[0].i_len = 0;
+       XLOG_VEC_SET_TYPE(&reg[0], XLOG_REG_TYPE_COMMIT);
 
        ASSERT_ALWAYS(iclog);
        if ((error = xlog_write(mp, reg, 1, ticket, commitlsnp,
@@ -1604,6 +1619,117 @@ xlog_state_finish_copy(xlog_t           *log,
 
 
 
+/*
+ * print out info relating to regions written which consume
+ * the reservation
+ */
+#if defined(XFS_LOG_RES_DEBUG)
+STATIC void
+xlog_print_tic_res(xfs_mount_t *mp, xlog_ticket_t *ticket)
+{
+       uint i;
+       uint ophdr_spc = ticket->t_res_num_ophdrs * (uint)sizeof(xlog_op_header_t);
+
+       /* match with XLOG_REG_TYPE_* in xfs_log.h */
+       static char *res_type_str[XLOG_REG_TYPE_MAX] = {
+           "bformat",
+           "bchunk",
+           "efi_format",
+           "efd_format",
+           "iformat",
+           "icore",
+           "iext",
+           "ibroot",
+           "ilocal",
+           "iattr_ext",
+           "iattr_broot",
+           "iattr_local",
+           "qformat",
+           "dquot",
+           "quotaoff",
+           "LR header",
+           "unmount",
+           "commit",
+           "trans header"
+       };
+       static char *trans_type_str[XFS_TRANS_TYPE_MAX] = {
+           "SETATTR_NOT_SIZE",
+           "SETATTR_SIZE",
+           "INACTIVE",
+           "CREATE",
+           "CREATE_TRUNC",
+           "TRUNCATE_FILE",
+           "REMOVE",
+           "LINK",
+           "RENAME",
+           "MKDIR",
+           "RMDIR",
+           "SYMLINK",
+           "SET_DMATTRS",
+           "GROWFS",
+           "STRAT_WRITE",
+           "DIOSTRAT",
+           "WRITE_SYNC",
+           "WRITEID",
+           "ADDAFORK",
+           "ATTRINVAL",
+           "ATRUNCATE",
+           "ATTR_SET",
+           "ATTR_RM",
+           "ATTR_FLAG",
+           "CLEAR_AGI_BUCKET",
+           "QM_SBCHANGE",
+           "DUMMY1",
+           "DUMMY2",
+           "QM_QUOTAOFF",
+           "QM_DQALLOC",
+           "QM_SETQLIM",
+           "QM_DQCLUSTER",
+           "QM_QINOCREATE",
+           "QM_QUOTAOFF_END",
+           "SB_UNIT",
+           "FSYNC_TS",
+           "GROWFSRT_ALLOC",
+           "GROWFSRT_ZERO",
+           "GROWFSRT_FREE",
+           "SWAPEXT"
+       };
+
+       xfs_fs_cmn_err(CE_WARN, mp,
+                       "xfs_log_write: reservation summary:\n"
+                       "  trans type  = %s (%u)\n"
+                       "  unit res    = %d bytes\n"
+                       "  current res = %d bytes\n"
+                       "  total reg   = %u bytes (o/flow = %u bytes)\n"
+                       "  ophdrs      = %u (ophdr space = %u bytes)\n"
+                       "  ophdr + reg = %u bytes\n"
+                       "  num regions = %u\n",
+                       ((ticket->t_trans_type <= 0 ||
+                         ticket->t_trans_type > XFS_TRANS_TYPE_MAX) ?
+                         "bad-trans-type" : trans_type_str[ticket->t_trans_type-1]),
+                       ticket->t_trans_type,
+                       ticket->t_unit_res,
+                       ticket->t_curr_res,
+                       ticket->t_res_arr_sum, ticket->t_res_o_flow,
+                       ticket->t_res_num_ophdrs, ophdr_spc,
+                       ticket->t_res_arr_sum + 
+                         ticket->t_res_o_flow + ophdr_spc,
+                       ticket->t_res_num);
+
+       for (i = 0; i < ticket->t_res_num; i++) {
+               uint r_type = ticket->t_res_arr[i].r_type; 
+               cmn_err(CE_WARN,
+                           "region[%u]: %s - %u bytes\n",
+                           i, 
+                           ((r_type <= 0 || r_type > XLOG_REG_TYPE_MAX) ?
+                           "bad-rtype" : res_type_str[r_type-1]),
+                           ticket->t_res_arr[i].r_len);
+       }
+}
+#else
+#define xlog_print_tic_res(mp, ticket)
+#endif
+
 /*
  * Write some region out to in-core log
  *
@@ -1677,16 +1803,21 @@ xlog_write(xfs_mount_t *        mp,
      * xlog_op_header_t and may need to be double word aligned.
      */
     len = 0;
-    if (ticket->t_flags & XLOG_TIC_INITED)     /* acct for start rec of xact */
+    if (ticket->t_flags & XLOG_TIC_INITED) {    /* acct for start rec of xact */
        len += sizeof(xlog_op_header_t);
+       XLOG_TIC_ADD_OPHDR(ticket);
+    }
 
     for (index = 0; index < nentries; index++) {
        len += sizeof(xlog_op_header_t);            /* each region gets >= 1 */
+       XLOG_TIC_ADD_OPHDR(ticket);
        len += reg[index].i_len;
+       XLOG_TIC_ADD_REGION(ticket, reg[index].i_len, reg[index].i_type);
     }
     contwr = *start_lsn = 0;
 
     if (ticket->t_curr_res < len) {
+       xlog_print_tic_res(mp, ticket);
 #ifdef DEBUG
        xlog_panic(
                "xfs_log_write: reservation ran out. Need to up reservation");
@@ -1790,6 +1921,7 @@ xlog_write(xfs_mount_t *  mp,
                len += sizeof(xlog_op_header_t); /* from splitting of region */
                /* account for new log op header */
                ticket->t_curr_res -= sizeof(xlog_op_header_t);
+               XLOG_TIC_ADD_OPHDR(ticket);
            }
            xlog_verify_dest_ptr(log, ptr);
 
@@ -2282,6 +2414,9 @@ restart:
         */
        if (log_offset == 0) {
                ticket->t_curr_res -= log->l_iclog_hsize;
+               XLOG_TIC_ADD_REGION(ticket,
+                                   log->l_iclog_hsize,
+                                   XLOG_REG_TYPE_LRHEADER);
                INT_SET(head->h_cycle, ARCH_CONVERT, log->l_curr_cycle);
                ASSIGN_LSN(head->h_lsn, log);
                ASSERT(log->l_curr_block >= 0);
@@ -2468,6 +2603,7 @@ xlog_regrant_write_log_space(xlog_t          *log,
 #endif
 
        tic->t_curr_res = tic->t_unit_res;
+       XLOG_TIC_RESET_RES(tic);
 
        if (tic->t_cnt > 0)
                return (0);
@@ -2608,6 +2744,7 @@ xlog_regrant_reserve_log_space(xlog_t          *log,
        XLOG_GRANT_SUB_SPACE(log, ticket->t_curr_res, 'w');
        XLOG_GRANT_SUB_SPACE(log, ticket->t_curr_res, 'r');
        ticket->t_curr_res = ticket->t_unit_res;
+       XLOG_TIC_RESET_RES(ticket);
        xlog_trace_loggrant(log, ticket,
                            "xlog_regrant_reserve_log_space: sub current res");
        xlog_verify_grant_head(log, 1);
@@ -2624,6 +2761,7 @@ xlog_regrant_reserve_log_space(xlog_t          *log,
        xlog_verify_grant_head(log, 0);
        GRANT_UNLOCK(log, s);
        ticket->t_curr_res = ticket->t_unit_res;
+       XLOG_TIC_RESET_RES(ticket);
 }      /* xlog_regrant_reserve_log_space */
 
 
@@ -3179,29 +3317,57 @@ xlog_ticket_get(xlog_t          *log,
         * and their unit amount is the total amount of space required.
         *
         * The following lines of code account for non-transaction data
-        * which occupy space in the on-disk log. 
+        * which occupy space in the on-disk log.
+        *
+        * Normal form of a transaction is:
+        * <oph><trans-hdr><start-oph><reg1-oph><reg1><reg2-oph>...<commit-oph>
+        * and then there are LR hdrs, split-recs and roundoff at end of syncs.
+        *
+        * We need to account for all the leadup data and trailer data
+        * around the transaction data.
+        * And then we need to account for the worst case in terms of using
+        * more space.
+        * The worst case will happen if:
+        * - the placement of the transaction happens to be such that the
+        *   roundoff is at its maximum
+        * - the transaction data is synced before the commit record is synced
+        *   i.e. <transaction-data><roundoff> | <commit-rec><roundoff>
+        *   Therefore the commit record is in its own Log Record.
+        *   This can happen as the commit record is called with its
+        *   own region to xlog_write().
+        *   This then means that in the worst case, roundoff can happen for
+        *   the commit-rec as well.
+        *   The commit-rec is smaller than padding in this scenario and so it is
+        *   not added separately.
         */
 
+       /* for trans header */
+       unit_bytes += sizeof(xlog_op_header_t);
+       unit_bytes += sizeof(xfs_trans_header_t);
+
        /* for start-rec */
-       unit_bytes += sizeof(xlog_op_header_t); 
+       unit_bytes += sizeof(xlog_op_header_t);
+
+       /* for LR headers */
+       num_headers = ((unit_bytes + log->l_iclog_size-1) >> log->l_iclog_size_log);
+       unit_bytes += log->l_iclog_hsize * num_headers;
+
+       /* for commit-rec LR header - note: padding will subsume the ophdr */
+       unit_bytes += log->l_iclog_hsize;
+
+       /* for split-recs - ophdrs added when data split over LRs */
+       unit_bytes += sizeof(xlog_op_header_t) * num_headers;
 
-       /* for padding */
+       /* for roundoff padding for transaction data and one for commit record */
        if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) &&
-               log->l_mp->m_sb.sb_logsunit > 1) {
+           log->l_mp->m_sb.sb_logsunit > 1) {
                /* log su roundoff */
-               unit_bytes += log->l_mp->m_sb.sb_logsunit;  
+               unit_bytes += 2*log->l_mp->m_sb.sb_logsunit;
        } else {
                /* BB roundoff */
-               unit_bytes += BBSIZE;
+               unit_bytes += 2*BBSIZE;
         }
 
-       /* for commit-rec */
-       unit_bytes += sizeof(xlog_op_header_t);
-       /* for LR headers */
-       num_headers = ((unit_bytes + log->l_iclog_size-1) >> log->l_iclog_size_log);
-       unit_bytes += log->l_iclog_hsize * num_headers;
-
        tic->t_unit_res         = unit_bytes;
        tic->t_curr_res         = unit_bytes;
        tic->t_cnt              = cnt;
@@ -3209,10 +3375,13 @@ xlog_ticket_get(xlog_t          *log,
        tic->t_tid              = (xlog_tid_t)((__psint_t)tic & 0xffffffff);
        tic->t_clientid         = client;
        tic->t_flags            = XLOG_TIC_INITED;
+       tic->t_trans_type       = 0;
        if (xflags & XFS_LOG_PERM_RESERV)
                tic->t_flags |= XLOG_TIC_PERM_RESERV;
        sv_init(&(tic->t_sema), SV_DEFAULT, "logtick");
 
+       XLOG_TIC_RESET_RES(tic);
+
        return tic;
 }      /* xlog_ticket_get */
 
index 0db122ddda3f3f1322ed27bf498c620cdaaf05cb..18961119fc65c34e89cafde638a882950c4a5732 100644 (file)
@@ -114,9 +114,44 @@ xfs_lsn_t  _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2)
 #define XFS_VOLUME             0x2
 #define XFS_LOG                        0xaa
 
+
+/* Region types for iovec's i_type */
+#if defined(XFS_LOG_RES_DEBUG)
+#define XLOG_REG_TYPE_BFORMAT          1
+#define XLOG_REG_TYPE_BCHUNK           2
+#define XLOG_REG_TYPE_EFI_FORMAT       3
+#define XLOG_REG_TYPE_EFD_FORMAT       4
+#define XLOG_REG_TYPE_IFORMAT          5
+#define XLOG_REG_TYPE_ICORE            6
+#define XLOG_REG_TYPE_IEXT             7
+#define XLOG_REG_TYPE_IBROOT           8
+#define XLOG_REG_TYPE_ILOCAL           9
+#define XLOG_REG_TYPE_IATTR_EXT                10
+#define XLOG_REG_TYPE_IATTR_BROOT      11
+#define XLOG_REG_TYPE_IATTR_LOCAL      12
+#define XLOG_REG_TYPE_QFORMAT          13
+#define XLOG_REG_TYPE_DQUOT            14
+#define XLOG_REG_TYPE_QUOTAOFF         15
+#define XLOG_REG_TYPE_LRHEADER         16
+#define XLOG_REG_TYPE_UNMOUNT          17
+#define XLOG_REG_TYPE_COMMIT           18
+#define XLOG_REG_TYPE_TRANSHDR         19
+#define XLOG_REG_TYPE_MAX              19
+#endif
+
+#if defined(XFS_LOG_RES_DEBUG)
+#define XLOG_VEC_SET_TYPE(vecp, t) ((vecp)->i_type = (t))
+#else
+#define XLOG_VEC_SET_TYPE(vecp, t)
+#endif
+
+
 typedef struct xfs_log_iovec {
        xfs_caddr_t             i_addr;         /* beginning address of region */
        int             i_len;          /* length in bytes of region */
+#if defined(XFS_LOG_RES_DEBUG)
+       uint            i_type;         /* type of region */
+#endif
 } xfs_log_iovec_t;
 
 typedef void* xfs_log_ticket_t;
@@ -159,7 +194,8 @@ int   xfs_log_reserve(struct xfs_mount *mp,
                          int              count,
                          xfs_log_ticket_t *ticket,
                          __uint8_t        clientid,
-                         uint             flags);
+                         uint             flags,
+                         uint             t_type);
 int      xfs_log_write(struct xfs_mount *mp,
                        xfs_log_iovec_t  region[],
                        int              nentries,
index 1a1d452f15f97b023f8ce0d33c9e74aad32f4ad6..eb7fdc6ebc3236853198f9770313c595c5e3147b 100644 (file)
@@ -335,18 +335,66 @@ typedef __uint32_t xlog_tid_t;
 
 #define XLOG_COVER_OPS         5
 
+
+/* Ticket reservation region accounting */ 
+#if defined(XFS_LOG_RES_DEBUG)
+#define XLOG_TIC_LEN_MAX       15
+#define XLOG_TIC_RESET_RES(t) ((t)->t_res_num = \
+                               (t)->t_res_arr_sum = (t)->t_res_num_ophdrs = 0)
+#define XLOG_TIC_ADD_OPHDR(t) ((t)->t_res_num_ophdrs++)
+#define XLOG_TIC_ADD_REGION(t, len, type)                              \
+       do {                                                            \
+               if ((t)->t_res_num == XLOG_TIC_LEN_MAX) {               \
+                       /* add to overflow and start again */           \
+                       (t)->t_res_o_flow += (t)->t_res_arr_sum;        \
+                       (t)->t_res_num = 0;                             \
+                       (t)->t_res_arr_sum = 0;                         \
+               }                                                       \
+               (t)->t_res_arr[(t)->t_res_num].r_len = (len);           \
+               (t)->t_res_arr[(t)->t_res_num].r_type = (type);         \
+               (t)->t_res_arr_sum += (len);                            \
+               (t)->t_res_num++;                                       \
+       } while (0)
+
+/*
+ * Reservation region
+ * As would be stored in xfs_log_iovec but without the i_addr which
+ * we don't care about.
+ */
+typedef struct xlog_res {
+       uint    r_len;
+       uint    r_type;
+} xlog_res_t;
+#else
+#define XLOG_TIC_RESET_RES(t)
+#define XLOG_TIC_ADD_OPHDR(t)
+#define XLOG_TIC_ADD_REGION(t, len, type)
+#endif
+
+
 typedef struct xlog_ticket {
-       sv_t               t_sema;       /* sleep on this semaphore      :20 */
-       struct xlog_ticket *t_next;      /*                              : 4 */
-       struct xlog_ticket *t_prev;      /*                              : 4 */
-       xlog_tid_t         t_tid;        /* transaction identifier       : 4 */
-       int                t_curr_res;   /* current reservation in bytes : 4 */
-       int                t_unit_res;   /* unit reservation in bytes    : 4 */
-       __uint8_t          t_ocnt;       /* original count               : 1 */
-       __uint8_t          t_cnt;        /* current count                : 1 */
-       __uint8_t          t_clientid;   /* who does this belong to;     : 1 */
-       __uint8_t          t_flags;      /* properties of reservation    : 1 */
+       sv_t               t_sema;       /* sleep on this semaphore      : 20 */
+       struct xlog_ticket *t_next;      /*                              :4|8 */
+       struct xlog_ticket *t_prev;      /*                              :4|8 */
+       xlog_tid_t         t_tid;        /* transaction identifier       : 4  */
+       int                t_curr_res;   /* current reservation in bytes : 4  */
+       int                t_unit_res;   /* unit reservation in bytes    : 4  */
+       char               t_ocnt;       /* original count               : 1  */
+       char               t_cnt;        /* current count                : 1  */
+       char               t_clientid;   /* who does this belong to;     : 1  */
+       char               t_flags;      /* properties of reservation    : 1  */
+       uint               t_trans_type; /* transaction type             : 4  */
+
+#if defined (XFS_LOG_RES_DEBUG)
+        /* reservation array fields */
+       uint               t_res_num;                    /* num in array : 4 */
+       xlog_res_t         t_res_arr[XLOG_TIC_LEN_MAX];  /* array of res : X */ 
+       uint               t_res_num_ophdrs;             /* num op hdrs  : 4 */
+       uint               t_res_arr_sum;                /* array sum    : 4 */
+       uint               t_res_o_flow;                 /* sum overflow : 4 */
+#endif
 } xlog_ticket_t;
+
 #endif
 
 
index 0aac28ddb81c6bc00d6b37ee341fa4db5258d119..14faabaabf29150c902d33a41a4252346623f464 100644 (file)
@@ -1387,7 +1387,7 @@ xlog_recover_add_to_cont_trans(
        old_ptr = item->ri_buf[item->ri_cnt-1].i_addr;
        old_len = item->ri_buf[item->ri_cnt-1].i_len;
 
-       ptr = kmem_realloc(old_ptr, len+old_len, old_len, 0);
+       ptr = kmem_realloc(old_ptr, len+old_len, old_len, 0u);
        memcpy(&ptr[old_len], dp, len); /* d, s, l */
        item->ri_buf[item->ri_cnt-1].i_len += len;
        item->ri_buf[item->ri_cnt-1].i_addr = ptr;
index 4f40c92863d51ffda17cf7d7832f0dec86a3b536..a6cd6324e946af65d2f1e949606a6e7c25be0f90 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -42,7 +42,8 @@
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
-
+#include "xfs_quota.h"
+#include "xfs_error.h"
 
 STATIC struct xfs_dquot *
 xfs_dqvopchown_default(
@@ -54,8 +55,79 @@ xfs_dqvopchown_default(
        return NULL;
 }
 
+/*
+ * Clear the quotaflags in memory and in the superblock.
+ */
+int
+xfs_mount_reset_sbqflags(xfs_mount_t *mp)
+{
+       int                     error;
+       xfs_trans_t             *tp;
+       unsigned long           s;
+
+       mp->m_qflags = 0;
+       /*
+        * It is OK to look at sb_qflags here in mount path,
+        * without SB_LOCK.
+        */
+       if (mp->m_sb.sb_qflags == 0)
+               return 0;
+       s = XFS_SB_LOCK(mp);
+       mp->m_sb.sb_qflags = 0;
+       XFS_SB_UNLOCK(mp, s);
+
+       /*
+        * if the fs is readonly, let the incore superblock run
+        * with quotas off but don't flush the update out to disk
+        */
+       if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY)
+               return 0;
+#ifdef QUOTADEBUG
+       xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes");
+#endif
+       tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
+       if ((error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
+                                     XFS_DEFAULT_LOG_COUNT))) {
+               xfs_trans_cancel(tp, 0);
+               xfs_fs_cmn_err(CE_ALERT, mp,
+                       "xfs_mount_reset_sbqflags: Superblock update failed!");
+               return error;
+       }
+       xfs_mod_sb(tp, XFS_SB_QFLAGS);
+       error = xfs_trans_commit(tp, 0, NULL);
+       return error;
+}
+
+STATIC int
+xfs_noquota_init(
+       xfs_mount_t     *mp,
+       uint            *needquotamount,
+       uint            *quotaflags)
+{
+       int             error = 0;
+
+       *quotaflags = 0;
+       *needquotamount = B_FALSE;
+
+       ASSERT(!XFS_IS_QUOTA_ON(mp));
+
+       /*
+        * If a file system had quotas running earlier, but decided to
+        * mount without -o uquota/pquota/gquota options, revoke the
+        * quotachecked license.
+        */
+       if (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT) {
+               cmn_err(CE_NOTE,
+                        "XFS resetting qflags for filesystem %s",
+                        mp->m_fsname);
+
+               error = xfs_mount_reset_sbqflags(mp);
+       }
+       return error;
+}
+
 xfs_qmops_t    xfs_qmcore_stub = {
-       .xfs_qminit             = (xfs_qminit_t) fs_noerr,
+       .xfs_qminit             = (xfs_qminit_t) xfs_noquota_init,
        .xfs_qmdone             = (xfs_qmdone_t) fs_noerr,
        .xfs_qmmount            = (xfs_qmmount_t) fs_noerr,
        .xfs_qmunmount          = (xfs_qmunmount_t) fs_noerr,
index 7134576ae7faed4f64e1dbb0661bc634a0dbd611..32cb79752d5d57a5306069269fc4acf051998cb7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -159,6 +159,20 @@ typedef struct xfs_qoff_logformat {
 #define XFS_OQUOTA_CHKD        0x0020  /* quotacheck run on other (grp/prj) quotas */
 #define XFS_GQUOTA_ACCT        0x0040  /* group quota accounting ON */
 
+/*
+ * Quota Accounting/Enforcement flags
+ */
+#define XFS_ALL_QUOTA_ACCT     \
+               (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT | XFS_PQUOTA_ACCT)
+#define XFS_ALL_QUOTA_ENFD     (XFS_UQUOTA_ENFD | XFS_OQUOTA_ENFD)
+#define XFS_ALL_QUOTA_CHKD     (XFS_UQUOTA_CHKD | XFS_OQUOTA_CHKD)
+
+#define XFS_IS_QUOTA_RUNNING(mp)       ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT)
+#define XFS_IS_QUOTA_ENFORCED(mp)      ((mp)->m_qflags & XFS_ALL_QUOTA_ENFD)
+#define XFS_IS_UQUOTA_RUNNING(mp)      ((mp)->m_qflags & XFS_UQUOTA_ACCT)
+#define XFS_IS_PQUOTA_RUNNING(mp)      ((mp)->m_qflags & XFS_PQUOTA_ACCT)
+#define XFS_IS_GQUOTA_RUNNING(mp)      ((mp)->m_qflags & XFS_GQUOTA_ACCT)
+
 /*
  * Incore only flags for quotaoff - these bits get cleared when quota(s)
  * are in the process of getting turned off. These flags are in m_qflags but
@@ -362,6 +376,7 @@ typedef struct xfs_dqtrxops {
                                f | XFS_QMOPT_RES_REGBLKS)
 
 extern int xfs_qm_dqcheck(xfs_disk_dquot_t *, xfs_dqid_t, uint, uint, char *);
+extern int xfs_mount_reset_sbqflags(struct xfs_mount *);
 
 extern struct bhv_vfsops xfs_qmops;
 
index 06dfca531f79880fc146845b6863d8dc28b6e1d4..92efe272b83d6d0ea79d1ad184a93d76da690055 100644 (file)
@@ -276,7 +276,7 @@ xfs_trans_reserve(
 
                error = xfs_log_reserve(tp->t_mountp, logspace, logcount,
                                        &tp->t_ticket,
-                                       XFS_TRANSACTION, log_flags);
+                                       XFS_TRANSACTION, log_flags, tp->t_type);
                if (error) {
                        goto undo_blocks;
                }
@@ -1032,6 +1032,7 @@ xfs_trans_fill_vecs(
        tp->t_header.th_num_items = nitems;
        log_vector->i_addr = (xfs_caddr_t)&tp->t_header;
        log_vector->i_len = sizeof(xfs_trans_header_t);
+       XLOG_VEC_SET_TYPE(log_vector, XLOG_REG_TYPE_TRANSHDR);
 }
 
 
index ec541d66fa2a47309a8ec76523435d3756edf71e..a263aec8b3a6532b8dd8b887cc6f073bf4348f42 100644 (file)
@@ -112,6 +112,7 @@ typedef struct xfs_trans_header {
 #define        XFS_TRANS_GROWFSRT_ZERO         38
 #define        XFS_TRANS_GROWFSRT_FREE         39
 #define        XFS_TRANS_SWAPEXT               40
+#define        XFS_TRANS_TYPE_MAX              40
 /* new transaction types need to be reflected in xfs_logprint(8) */
 
 
@@ -998,6 +999,7 @@ struct xfs_buf      *xfs_trans_getsb(xfs_trans_t *, struct xfs_mount *, int);
 void           xfs_trans_brelse(xfs_trans_t *, struct xfs_buf *);
 void           xfs_trans_bjoin(xfs_trans_t *, struct xfs_buf *);
 void           xfs_trans_bhold(xfs_trans_t *, struct xfs_buf *);
+void           xfs_trans_bhold_release(xfs_trans_t *, struct xfs_buf *);
 void           xfs_trans_binval(xfs_trans_t *, struct xfs_buf *);
 void           xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *);
 void           xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *);
index 7bc5eab4c2c19cb703cb09539fe627a55383f6dd..2a71b4f91bfa1bf9a50909fde4b8a0a682b75eca 100644 (file)
@@ -379,8 +379,8 @@ xfs_trans_delete_ail(
                else {
                        xfs_cmn_err(XFS_PTAG_AILDELETE, CE_ALERT, mp,
                                "xfs_trans_delete_ail: attempting to delete a log item that is not in the AIL");
-                       xfs_force_shutdown(mp, XFS_CORRUPT_INCORE);
                        AIL_UNLOCK(mp, s);
+                       xfs_force_shutdown(mp, XFS_CORRUPT_INCORE);
                }
        }
 }
index 144da7a85466c2e85fbffe66ff1f15e08c0873ec..e733293dd7f488f24a8d7bedf5dc7b3cf1428085 100644 (file)
@@ -713,6 +713,29 @@ xfs_trans_bhold(xfs_trans_t        *tp,
        xfs_buf_item_trace("BHOLD", bip);
 }
 
+/*
+ * Cancel the previous buffer hold request made on this buffer
+ * for this transaction.
+ */
+void
+xfs_trans_bhold_release(xfs_trans_t    *tp,
+                       xfs_buf_t       *bp)
+{
+       xfs_buf_log_item_t      *bip;
+
+       ASSERT(XFS_BUF_ISBUSY(bp));
+       ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp);
+       ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
+
+       bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
+       ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
+       ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL));
+       ASSERT(atomic_read(&bip->bli_refcount) > 0);
+       ASSERT(bip->bli_flags & XFS_BLI_HOLD);
+       bip->bli_flags &= ~XFS_BLI_HOLD;
+       xfs_buf_item_trace("BHOLD RELEASE", bip);
+}
+
 /*
  * This is called to mark bytes first through last inclusive of the given
  * buffer as needing to be logged when the transaction is committed.
index 42bcc0215203b16f19e71c844a395a2b3398fb72..f1a904e23adeff9d1c838f958940a0d42e13a14a 100644 (file)
@@ -795,7 +795,6 @@ xfs_statvfs(
        xfs_mount_t     *mp;
        xfs_sb_t        *sbp;
        unsigned long   s;
-       u64 id;
 
        mp = XFS_BHVTOM(bdp);
        sbp = &(mp->m_sb);
@@ -823,9 +822,7 @@ xfs_statvfs(
        statp->f_ffree = statp->f_files - (sbp->sb_icount - sbp->sb_ifree);
        XFS_SB_UNLOCK(mp, s);
 
-       id = huge_encode_dev(mp->m_dev);
-       statp->f_fsid.val[0] = (u32)id;
-       statp->f_fsid.val[1] = (u32)(id >> 32);
+       xfs_statvfs_fsid(statp, mp);
        statp->f_namelen = MAXNAMELEN - 1;
 
        return 0;
@@ -906,7 +903,6 @@ xfs_sync_inodes(
        xfs_inode_t     *ip_next;
        xfs_buf_t       *bp;
        vnode_t         *vp = NULL;
-       vmap_t          vmap;
        int             error;
        int             last_error;
        uint64_t        fflag;
@@ -1101,48 +1097,21 @@ xfs_sync_inodes(
                 * lock in xfs_ireclaim() after the inode is pulled from
                 * the mount list will sleep until we release it here.
                 * This keeps the vnode from being freed while we reference
-                * it.  It is also cheaper and simpler than actually doing
-                * a vn_get() for every inode we touch here.
+                * it.
                 */
                if (xfs_ilock_nowait(ip, lock_flags) == 0) {
-
                        if ((flags & SYNC_BDFLUSH) || (vp == NULL)) {
                                ip = ip->i_mnext;
                                continue;
                        }
 
-                       /*
-                        * We need to unlock the inode list lock in order
-                        * to lock the inode. Insert a marker record into
-                        * the inode list to remember our position, dropping
-                        * the lock is now done inside the IPOINTER_INSERT
-                        * macro.
-                        *
-                        * We also use the inode list lock to protect us
-                        * in taking a snapshot of the vnode version number
-                        * for use in calling vn_get().
-                        */
-                       VMAP(vp, vmap);
-                       IPOINTER_INSERT(ip, mp);
-
-                       vp = vn_get(vp, &vmap);
+                       vp = vn_grab(vp);
                        if (vp == NULL) {
-                               /*
-                                * The vnode was reclaimed once we let go
-                                * of the inode list lock.  Skip to the
-                                * next list entry. Remove the marker.
-                                */
-
-                               XFS_MOUNT_ILOCK(mp);
-
-                               mount_locked = B_TRUE;
-                               vnode_refed  = B_FALSE;
-
-                               IPOINTER_REMOVE(ip, mp);
-
+                               ip = ip->i_mnext;
                                continue;
                        }
 
+                       IPOINTER_INSERT(ip, mp);
                        xfs_ilock(ip, lock_flags);
 
                        ASSERT(vp == XFS_ITOV(ip));
@@ -1533,7 +1502,10 @@ xfs_syncsub(
         * eventually kicked out of the cache.
         */
        if (flags & SYNC_REFCACHE) {
-               xfs_refcache_purge_some(mp);
+               if (flags & SYNC_WAIT)
+                       xfs_refcache_purge_mp(mp);
+               else
+                       xfs_refcache_purge_some(mp);
        }
 
        /*
@@ -1649,6 +1621,10 @@ xfs_vget(
 #define MNTOPT_SWIDTH  "swidth"        /* data volume stripe width */
 #define MNTOPT_NOUUID  "nouuid"        /* ignore filesystem UUID */
 #define MNTOPT_MTPT    "mtpt"          /* filesystem mount point */
+#define MNTOPT_GRPID   "grpid"         /* group-ID from parent directory */
+#define MNTOPT_NOGRPID "nogrpid"       /* group-ID from current process */
+#define MNTOPT_BSDGROUPS    "bsdgroups"    /* group-ID from parent directory */
+#define MNTOPT_SYSVGROUPS   "sysvgroups"   /* group-ID from current process */
 #define MNTOPT_ALLOCSIZE    "allocsize"    /* preferred allocation size */
 #define MNTOPT_IHASHSIZE    "ihashsize"    /* size of inode hash table */
 #define MNTOPT_NORECOVERY   "norecovery"   /* don't run XFS recovery */
@@ -1769,6 +1745,12 @@ xfs_parseargs(
                        }
                        args->flags |= XFSMNT_IHASHSIZE;
                        args->ihashsize = simple_strtoul(value, &eov, 10);
+               } else if (!strcmp(this_char, MNTOPT_GRPID) ||
+                          !strcmp(this_char, MNTOPT_BSDGROUPS)) {
+                       vfsp->vfs_flag |= VFS_GRPID;
+               } else if (!strcmp(this_char, MNTOPT_NOGRPID) ||
+                          !strcmp(this_char, MNTOPT_SYSVGROUPS)) {
+                       vfsp->vfs_flag &= ~VFS_GRPID;
                } else if (!strcmp(this_char, MNTOPT_WSYNC)) {
                        args->flags |= XFSMNT_WSYNC;
                } else if (!strcmp(this_char, MNTOPT_OSYNCISOSYNC)) {
@@ -1890,6 +1872,7 @@ xfs_showargs(
        };
        struct proc_xfs_info    *xfs_infop;
        struct xfs_mount        *mp = XFS_BHVTOM(bhv);
+       struct vfs              *vfsp = XFS_MTOVFS(mp);
 
        for (xfs_infop = xfs_info; xfs_infop->flag; xfs_infop++) {
                if (mp->m_flags & xfs_infop->flag)
@@ -1926,7 +1909,10 @@ xfs_showargs(
 
        if (!(mp->m_flags & XFS_MOUNT_32BITINOOPT))
                seq_printf(m, "," MNTOPT_64BITINODE);
-       
+
+       if (vfsp->vfs_flag & VFS_GRPID)
+               seq_printf(m, "," MNTOPT_GRPID);
+
        return 0;
 }
 
index 1377c868f3f4929aec4106f187b01c03f480c433..58bfe629b93316168b5c2ded720b6ea9cf0b6a7a 100644 (file)
@@ -104,7 +104,7 @@ xfs_open(
         * If it's a directory with any blocks, read-ahead block 0
         * as we're almost certain to have the next operation be a read there.
         */
-       if (vp->v_type == VDIR && ip->i_d.di_nextents > 0) {
+       if (VN_ISDIR(vp) && ip->i_d.di_nextents > 0) {
                mode = xfs_ilock_map_shared(ip);
                if (ip->i_d.di_nextents > 0)
                        (void)xfs_da_reada_buf(NULL, ip, 0, XFS_DATA_FORK);
@@ -163,18 +163,21 @@ xfs_getattr(
        /*
         * Copy from in-core inode.
         */
-       vap->va_type = vp->v_type;
-       vap->va_mode = ip->i_d.di_mode & MODEMASK;
+       vap->va_mode = ip->i_d.di_mode;
        vap->va_uid = ip->i_d.di_uid;
        vap->va_gid = ip->i_d.di_gid;
        vap->va_projid = ip->i_d.di_projid;
 
        /*
         * Check vnode type block/char vs. everything else.
-        * Do it with bitmask because that's faster than looking
-        * for multiple values individually.
         */
-       if (((1 << vp->v_type) & ((1<<VBLK) | (1<<VCHR))) == 0) {
+       switch (ip->i_d.di_mode & S_IFMT) {
+       case S_IFBLK:
+       case S_IFCHR:
+               vap->va_rdev = ip->i_df.if_u2.if_rdev;
+               vap->va_blocksize = BLKDEV_IOSIZE;
+               break;
+       default:
                vap->va_rdev = 0;
 
                if (!(ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) {
@@ -224,9 +227,7 @@ xfs_getattr(
                                (ip->i_d.di_extsize << mp->m_sb.sb_blocklog) :
                                (mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog);
                }
-       } else {
-               vap->va_rdev = ip->i_df.if_u2.if_rdev;
-               vap->va_blocksize = BLKDEV_IOSIZE;
+               break;
        }
 
        vap->va_atime.tv_sec = ip->i_d.di_atime.t_sec;
@@ -468,7 +469,7 @@ xfs_setattr(
                                m |= S_ISGID;
 #if 0
                        /* Linux allows this, Irix doesn't. */
-                       if ((vap->va_mode & S_ISVTX) && vp->v_type != VDIR)
+                       if ((vap->va_mode & S_ISVTX) && !VN_ISDIR(vp))
                                m |= S_ISVTX;
 #endif
                        if (m && !capable(CAP_FSETID))
@@ -546,10 +547,10 @@ xfs_setattr(
                        goto error_return;
                }
 
-               if (vp->v_type == VDIR) {
+               if (VN_ISDIR(vp)) {
                        code = XFS_ERROR(EISDIR);
                        goto error_return;
-               } else if (vp->v_type != VREG) {
+               } else if (!VN_ISREG(vp)) {
                        code = XFS_ERROR(EINVAL);
                        goto error_return;
                }
@@ -1567,7 +1568,7 @@ xfs_release(
        vp = BHV_TO_VNODE(bdp);
        ip = XFS_BHVTOI(bdp);
 
-       if ((vp->v_type != VREG) || (ip->i_d.di_mode == 0)) {
+       if (!VN_ISREG(vp) || (ip->i_d.di_mode == 0)) {
                return 0;
        }
 
@@ -1895,7 +1896,7 @@ xfs_create(
        dp = XFS_BHVTOI(dir_bdp);
        mp = dp->i_mount;
 
-       dm_di_mode = vap->va_mode|VTTOIF(vap->va_type);
+       dm_di_mode = vap->va_mode;
        namelen = VNAMELEN(dentry);
 
        if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_CREATE)) {
@@ -1973,8 +1974,7 @@ xfs_create(
            (error = XFS_DIR_CANENTER(mp, tp, dp, name, namelen)))
                goto error_return;
        rdev = (vap->va_mask & XFS_AT_RDEV) ? vap->va_rdev : 0;
-       error = xfs_dir_ialloc(&tp, dp,
-                       MAKEIMODE(vap->va_type,vap->va_mode), 1,
+       error = xfs_dir_ialloc(&tp, dp, vap->va_mode, 1,
                        rdev, credp, prid, resblks > 0,
                        &ip, &committed);
        if (error) {
@@ -2620,7 +2620,7 @@ xfs_link(
        vn_trace_entry(src_vp, __FUNCTION__, (inst_t *)__return_address);
 
        target_namelen = VNAMELEN(dentry);
-       if (src_vp->v_type == VDIR)
+       if (VN_ISDIR(src_vp))
                return XFS_ERROR(EPERM);
 
        src_bdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(src_vp), &xfs_vnodeops);
@@ -2805,7 +2805,7 @@ xfs_mkdir(
 
        tp = NULL;
        dp_joined_to_trans = B_FALSE;
-       dm_di_mode = vap->va_mode|VTTOIF(vap->va_type);
+       dm_di_mode = vap->va_mode;
 
        if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_CREATE)) {
                error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE,
@@ -2879,8 +2879,7 @@ xfs_mkdir(
        /*
         * create the directory inode.
         */
-       error = xfs_dir_ialloc(&tp, dp,
-                       MAKEIMODE(vap->va_type,vap->va_mode), 2,
+       error = xfs_dir_ialloc(&tp, dp, vap->va_mode, 2,
                        0, credp, prid, resblks > 0,
                &cdp, NULL);
        if (error) {
@@ -3650,7 +3649,7 @@ xfs_rwlock(
        vnode_t         *vp;
 
        vp = BHV_TO_VNODE(bdp);
-       if (vp->v_type == VDIR)
+       if (VN_ISDIR(vp))
                return 1;
        ip = XFS_BHVTOI(bdp);
        if (locktype == VRWLOCK_WRITE) {
@@ -3681,7 +3680,7 @@ xfs_rwunlock(
        vnode_t         *vp;
 
        vp = BHV_TO_VNODE(bdp);
-       if (vp->v_type == VDIR)
+       if (VN_ISDIR(vp))
                return;
        ip = XFS_BHVTOI(bdp);
        if (locktype == VRWLOCK_WRITE) {
@@ -3847,51 +3846,10 @@ xfs_reclaim(
                return 0;
        }
 
-       if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {
-               if (ip->i_d.di_size > 0) {
-                       /*
-                        * Flush and invalidate any data left around that is
-                        * a part of this file.
-                        *
-                        * Get the inode's i/o lock so that buffers are pushed
-                        * out while holding the proper lock.  We can't hold
-                        * the inode lock here since flushing out buffers may
-                        * cause us to try to get the lock in xfs_strategy().
-                        *
-                        * We don't have to call remapf() here, because there
-                        * cannot be any mapped file references to this vnode
-                        * since it is being reclaimed.
-                        */
-                       xfs_ilock(ip, XFS_IOLOCK_EXCL);
-
-                       /*
-                        * If we hit an IO error, we need to make sure that the
-                        * buffer and page caches of file data for
-                        * the file are tossed away. We don't want to use
-                        * VOP_FLUSHINVAL_PAGES here because we don't want dirty
-                        * pages to stay attached to the vnode, but be
-                        * marked P_BAD. pdflush/vnode_pagebad
-                        * hates that.
-                        */
-                       if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
-                               VOP_FLUSHINVAL_PAGES(vp, 0, -1, FI_NONE);
-                       } else {
-                               VOP_TOSS_PAGES(vp, 0, -1, FI_NONE);
-                       }
+       vn_iowait(vp);
 
-                       ASSERT(VN_CACHED(vp) == 0);
-                       ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) ||
-                              ip->i_delayed_blks == 0);
-                       xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-               } else if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
-                       /*
-                        * di_size field may not be quite accurate if we're
-                        * shutting down.
-                        */
-                       VOP_TOSS_PAGES(vp, 0, -1, FI_NONE);
-                       ASSERT(VN_CACHED(vp) == 0);
-               }
-       }
+       ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0);
+       ASSERT(VN_CACHED(vp) == 0);
 
        /* If we have nothing to flush with this inode then complete the
         * teardown now, otherwise break the link between the xfs inode
@@ -4567,7 +4525,7 @@ xfs_change_file_space(
        /*
         * must be a regular file and have write permission
         */
-       if (vp->v_type != VREG)
+       if (!VN_ISREG(vp))
                return XFS_ERROR(EINVAL);
 
        xfs_ilock(ip, XFS_ILOCK_SHARED);
diff --git a/include/asm-alpha/auxvec.h b/include/asm-alpha/auxvec.h
new file mode 100644 (file)
index 0000000..e96fe88
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef __ASM_ALPHA_AUXVEC_H
+#define __ASM_ALPHA_AUXVEC_H
+
+/* Reserve these numbers for any future use of a VDSO.  */
+#if 0
+#define AT_SYSINFO             32
+#define AT_SYSINFO_EHDR                33
+#endif
+
+/* More complete cache descriptions than AT_[DIU]CACHEBSIZE.  If the
+   value is -1, then the cache doesn't exist.  Otherwise:
+
+      bit 0-3:   Cache set-associativity; 0 means fully associative.
+      bit 4-7:   Log2 of cacheline size.
+      bit 8-31:          Size of the entire cache >> 8.
+      bit 32-63:  Reserved.
+*/
+
+#define AT_L1I_CACHESHAPE      34
+#define AT_L1D_CACHESHAPE      35
+#define AT_L2_CACHESHAPE       36
+#define AT_L3_CACHESHAPE       37
+
+#endif /* __ASM_ALPHA_AUXVEC_H */
index e94a945a231429fe357451f0bacf7e84feabd0f5..6c2d78fba264ac21ce616fcf9622bf1ea9b89fc7 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __ASM_ALPHA_ELF_H
 #define __ASM_ALPHA_ELF_H
 
+#include <asm/auxvec.h>
+
 /* Special values for the st_other field in the symbol table.  */
 
 #define STO_ALPHA_NOPV         0x80
@@ -142,26 +144,6 @@ extern int dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task);
        : amask (AMASK_CIX) ? "ev6" : "ev67");  \
 })
 
-/* Reserve these numbers for any future use of a VDSO.  */
-#if 0
-#define AT_SYSINFO             32
-#define AT_SYSINFO_EHDR                33
-#endif
-
-/* More complete cache descriptions than AT_[DIU]CACHEBSIZE.  If the
-   value is -1, then the cache doesn't exist.  Otherwise:
-
-      bit 0-3:   Cache set-associativity; 0 means fully associative.
-      bit 4-7:   Log2 of cacheline size.
-      bit 8-31:          Size of the entire cache >> 8.
-      bit 32-63:  Reserved.
-*/
-
-#define AT_L1I_CACHESHAPE      34
-#define AT_L1D_CACHESHAPE      35
-#define AT_L2_CACHESHAPE       36
-#define AT_L3_CACHESHAPE       37
-
 #ifdef __KERNEL__
 
 #define SET_PERSONALITY(EX, IBCS2)                             \
index 6b7d6c1649ce9c8d30aef7586ee8abad5bfabe59..87f2cf459e266367be6f16f10c545f85d41e9bbc 100644 (file)
@@ -3,10 +3,6 @@
 
 /* open/fcntl - O_SYNC is only implemented on blocks devices and on files
    located on an ext2 file system */
-#define O_ACCMODE        0003
-#define O_RDONLY           00
-#define O_WRONLY           01
-#define O_RDWR             02
 #define O_CREAT                 01000  /* not fcntl */
 #define O_TRUNC                 02000  /* not fcntl */
 #define O_EXCL          04000  /* not fcntl */
 
 #define O_NONBLOCK      00004
 #define O_APPEND        00010
-#define O_NDELAY       O_NONBLOCK
 #define O_SYNC         040000
-#define FASYNC         020000  /* fcntl, for BSD compatibility */
 #define O_DIRECTORY    0100000 /* must be a directory */
 #define O_NOFOLLOW     0200000 /* don't follow links */
 #define O_LARGEFILE    0400000 /* will be set by the kernel on every open */
 #define O_DIRECT       02000000 /* direct disk access - should check with OSF/1 */
 #define O_NOATIME      04000000
 
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
 #define F_GETLK                7
 #define F_SETLK                8
 #define F_SETLKW       9
@@ -37,9 +26,6 @@
 #define F_SETSIG       10      /*  for sockets. */
 #define F_GETSIG       11      /*  for sockets. */
 
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
 /* for posix fcntl() and lockf() */
 #define F_RDLCK                1
 #define F_WRLCK                2
 
 #define F_INPROGRESS   64
 
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW        192     /* ... Which allows concurrent read & write ops */
-struct flock {
-       short l_type;
-       short l_whence;
-       __kernel_off_t l_start;
-       __kernel_off_t l_len;
-       __kernel_pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE  1024
+#include <asm-generic/fcntl.h>
 
 #endif
diff --git a/include/asm-alpha/futex.h b/include/asm-alpha/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-alpha/hdreg.h b/include/asm-alpha/hdreg.h
deleted file mode 100644 (file)
index 7f7fd1a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/hdreg.h>
index 0577daffc720f8b2cbf63df0bdff9845d12e495a..fa0b41b164a76f04aa52481a10ac0b83d0884026 100644 (file)
@@ -63,20 +63,6 @@ typedef unsigned long pgprot_t;
 
 #endif /* STRICT_MM_TYPECHECKS */
 
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size-1) >> (PAGE_SHIFT-1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
-
 #ifdef USE_48_BIT_KSEG
 #define PAGE_OFFSET            0xffff800000000000UL
 #else
@@ -112,4 +98,6 @@ extern __inline__ int get_order(unsigned long size)
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/page.h>
+
 #endif /* _ALPHA_PAGE_H */
index d00259d3dc7849c69b1d4e9f0c828505142395ab..b5193229132a12e5f73bfe510830aef1ab95235b 100644 (file)
@@ -25,6 +25,8 @@
 #define SO_ERROR       0x1007
 #define SO_SNDBUF      0x1001
 #define SO_RCVBUF      0x1002
+#define SO_SNDBUFFORCE 0x100a
+#define SO_RCVBUFFORCE 0x100b
 #define        SO_RCVLOWAT     0x1010
 #define        SO_SNDLOWAT     0x1011
 #define        SO_RCVTIMEO     0x1012
index 43264d21924656fdc5b623367d83c7eccf105090..f5716139ec8987216d954858dfe6229ecd542488 100644 (file)
@@ -56,8 +56,6 @@ typedef unsigned long u64;
 typedef u64 dma_addr_t;
 typedef u64 dma64_addr_t;
 
-typedef unsigned short kmem_bufctl_t;
-
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ALPHA_TYPES_H */
index 4c39ee750f388f71cff6ac5dd0de7b866f1c7066..22de3b434a22a59d7f16bce6520787efab1fc8f9 100644 (file)
        __access_ok(((unsigned long)(addr)),(size),get_fs());   \
 })
 
-/* this function will go away soon - use access_ok() instead */
-extern inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
-{
-       return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
 /*
  * These are the main single-value transfer routines.  They automatically
  * use the right size if we just have the right pointer type.
index 7495026e2c18bd5c8fd9daa5c237f39e046c2867..e350dcb544e82a2dc94034a35807f8d850347991 100644 (file)
@@ -383,39 +383,45 @@ __ixp4xx_insl(u32 io_addr, u32 *vaddr, u32 count)
                *vaddr++ = inl(io_addr);
 }
 
-#define        __is_io_address(p)      (((unsigned long)p >= 0x0) && \
-                                       ((unsigned long)p <= 0x0000ffff))
+#define PIO_OFFSET      0x10000UL
+#define PIO_MASK        0x0ffffUL
+
+#define        __is_io_address(p)      (((unsigned long)p >= PIO_OFFSET) && \
+                                       ((unsigned long)p <= (PIO_MASK + PIO_OFFSET)))
 static inline unsigned int
-__ixp4xx_ioread8(void __iomem *port)
+__ixp4xx_ioread8(void __iomem *addr)
 {
+       unsigned long port = (unsigned long __force)addr;
        if (__is_io_address(port))
-               return  (unsigned int)__ixp4xx_inb((unsigned int)port);
+               return  (unsigned int)__ixp4xx_inb(port & PIO_MASK);
        else
 #ifndef CONFIG_IXP4XX_INDIRECT_PCI
-               return (unsigned int)__raw_readb((u32)port);
+               return (unsigned int)__raw_readb(port);
 #else
-               return (unsigned int)__ixp4xx_readb((u32)port);
+               return (unsigned int)__ixp4xx_readb(port);
 #endif
 }
 
 static inline void
-__ixp4xx_ioread8_rep(u32 port, u8 *vaddr, u32 count)
+__ixp4xx_ioread8_rep(void __iomem *addr, void *vaddr, u32 count)
 {
+       unsigned long port = (unsigned long __force)addr;
        if (__is_io_address(port))
-               __ixp4xx_insb(port, vaddr, count);
+               __ixp4xx_insb(port & PIO_MASK, vaddr, count);
        else
 #ifndef        CONFIG_IXP4XX_INDIRECT_PCI
-               __raw_readsb((void __iomem *)port, vaddr, count);
+               __raw_readsb(addr, vaddr, count);
 #else
                __ixp4xx_readsb(port, vaddr, count);
 #endif
 }
 
 static inline unsigned int
-__ixp4xx_ioread16(void __iomem *port)
+__ixp4xx_ioread16(void __iomem *addr)
 {
+       unsigned long port = (unsigned long __force)addr;
        if (__is_io_address(port))
-               return  (unsigned int)__ixp4xx_inw((unsigned int)port);
+               return  (unsigned int)__ixp4xx_inw(port & PIO_MASK);
        else
 #ifndef CONFIG_IXP4XX_INDIRECT_PCI
                return le16_to_cpu(__raw_readw((u32)port));
@@ -425,23 +431,25 @@ __ixp4xx_ioread16(void __iomem *port)
 }
 
 static inline void
-__ixp4xx_ioread16_rep(u32 port, u16 *vaddr, u32 count)
+__ixp4xx_ioread16_rep(void __iomem *addr, void *vaddr, u32 count)
 {
+       unsigned long port = (unsigned long __force)addr;
        if (__is_io_address(port))
-               __ixp4xx_insw(port, vaddr, count);
+               __ixp4xx_insw(port & PIO_MASK, vaddr, count);
        else
 #ifndef        CONFIG_IXP4XX_INDIRECT_PCI
-               __raw_readsw((void __iomem *)port, vaddr, count);
+               __raw_readsw(addr, vaddr, count);
 #else
                __ixp4xx_readsw(port, vaddr, count);
 #endif
 }
 
 static inline unsigned int
-__ixp4xx_ioread32(void __iomem *port)
+__ixp4xx_ioread32(void __iomem *addr)
 {
+       unsigned long port = (unsigned long __force)addr;
        if (__is_io_address(port))
-               return  (unsigned int)__ixp4xx_inl((unsigned int)port);
+               return  (unsigned int)__ixp4xx_inl(port & PIO_MASK);
        else {
 #ifndef CONFIG_IXP4XX_INDIRECT_PCI
                return le32_to_cpu(__raw_readl((u32)port));
@@ -452,90 +460,100 @@ __ixp4xx_ioread32(void __iomem *port)
 }
 
 static inline void
-__ixp4xx_ioread32_rep(u32 port, u32 *vaddr, u32 count)
+__ixp4xx_ioread32_rep(void __iomem *addr, void *vaddr, u32 count)
 {
+       unsigned long port = (unsigned long __force)addr;
        if (__is_io_address(port))
-               __ixp4xx_insl(port, vaddr, count);
+               __ixp4xx_insl(port & PIO_MASK, vaddr, count);
        else
 #ifndef        CONFIG_IXP4XX_INDIRECT_PCI
-               __raw_readsl((void __iomem *)port, vaddr, count);
+               __raw_readsl(addr, vaddr, count);
 #else
                __ixp4xx_readsl(port, vaddr, count);
 #endif
 }
 
 static inline void
-__ixp4xx_iowrite8(u8 value, void __iomem *port)
+__ixp4xx_iowrite8(u8 value, void __iomem *addr)
 {
+       unsigned long port = (unsigned long __force)addr;
        if (__is_io_address(port))
-               __ixp4xx_outb(value, (unsigned int)port);
+               __ixp4xx_outb(value, port & PIO_MASK);
        else
 #ifndef CONFIG_IXP4XX_INDIRECT_PCI
-               __raw_writeb(value, (u32)port);
+               __raw_writeb(value, port);
 #else
-               __ixp4xx_writeb(value, (u32)port);
+               __ixp4xx_writeb(value, port);
 #endif
 }
 
 static inline void
-__ixp4xx_iowrite8_rep(u32 port, u8 *vaddr, u32 count)
+__ixp4xx_iowrite8_rep(void __iomem *addr, const void *vaddr, u32 count)
 {
+       unsigned long port = (unsigned long __force)addr;
        if (__is_io_address(port))
-               __ixp4xx_outsb(port, vaddr, count);
+               __ixp4xx_outsb(port & PIO_MASK, vaddr, count);
+       else
 #ifndef CONFIG_IXP4XX_INDIRECT_PCI
-               __raw_writesb((void __iomem *)port, vaddr, count);
+               __raw_writesb(addr, vaddr, count);
 #else
                __ixp4xx_writesb(port, vaddr, count);
 #endif
 }
 
 static inline void
-__ixp4xx_iowrite16(u16 value, void __iomem *port)
+__ixp4xx_iowrite16(u16 value, void __iomem *addr)
 {
+       unsigned long port = (unsigned long __force)addr;
        if (__is_io_address(port))
-               __ixp4xx_outw(value, (unsigned int)port);
+               __ixp4xx_outw(value, port & PIO_MASK);
        else
 #ifndef CONFIG_IXP4XX_INDIRECT_PCI
-               __raw_writew(cpu_to_le16(value), (u32)port);
+               __raw_writew(cpu_to_le16(value), addr);
 #else
-               __ixp4xx_writew(value, (u32)port);
+               __ixp4xx_writew(value, port);
 #endif
 }
 
 static inline void
-__ixp4xx_iowrite16_rep(u32 port, u16 *vaddr, u32 count)
+__ixp4xx_iowrite16_rep(void __iomem *addr, const void *vaddr, u32 count)
 {
+       unsigned long port = (unsigned long __force)addr;
        if (__is_io_address(port))
-               __ixp4xx_outsw(port, vaddr, count);
+               __ixp4xx_outsw(port & PIO_MASK, vaddr, count);
+       else
 #ifndef CONFIG_IXP4XX_INDIRECT_PCI
-               __raw_readsw((void __iomem *)port, vaddr, count);
+               __raw_writesw(addr, vaddr, count);
 #else
                __ixp4xx_writesw(port, vaddr, count);
 #endif
 }
 
 static inline void
-__ixp4xx_iowrite32(u32 value, void __iomem *port)
+__ixp4xx_iowrite32(u32 value, void __iomem *addr)
 {
+       unsigned long port = (unsigned long __force)addr;
        if (__is_io_address(port))
-               __ixp4xx_outl(value, (unsigned int)port);
+               __ixp4xx_outl(value, port & PIO_MASK);
        else
 #ifndef CONFIG_IXP4XX_INDIRECT_PCI
-               __raw_writel(cpu_to_le32(value), (u32)port);
+               __raw_writel(cpu_to_le32(value), port);
 #else
-               __ixp4xx_writel(value, (u32)port);
+               __ixp4xx_writel(value, port);
 #endif
 }
 
 static inline void
-__ixp4xx_iowrite32_rep(u32 port, u32 *vaddr, u32 count)
+__ixp4xx_iowrite32_rep(void __iomem *addr, const void *vaddr, u32 count)
 {
+       unsigned long port = (unsigned long __force)addr;
        if (__is_io_address(port))
-               __ixp4xx_outsl(port, vaddr, count);
+               __ixp4xx_outsl(port & PIO_MASK, vaddr, count);
+       else
 #ifndef CONFIG_IXP4XX_INDIRECT_PCI
-               __raw_readsl((void __iomem *)port, vaddr, count);
+               __raw_writesl(addr, vaddr, count);
 #else
-               __ixp4xx_outsl(port, vaddr, count);
+               __ixp4xx_writesl(port, vaddr, count);
 #endif
 }
 
@@ -555,7 +573,7 @@ __ixp4xx_iowrite32_rep(u32 port, u32 *vaddr, u32 count)
 #define        iowrite16_rep(p, v, c)          __ixp4xx_iowrite16_rep(p, v, c)
 #define        iowrite32_rep(p, v, c)          __ixp4xx_iowrite32_rep(p, v, c)
 
-#define        ioport_map(port, nr)            ((void __iomem*)port)
+#define        ioport_map(port, nr)            ((void __iomem*)(port + PIO_OFFSET))
 #define        ioport_unmap(addr)
 
 #endif //  __ASM_ARM_ARCH_IO_H
index 3a626c03ea2665915df82795616edc06606843ea..d13ee7f78c70a93b6528b06874971fdf4961cb49 100644 (file)
@@ -83,17 +83,6 @@ extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys);
 #define IXP4XX_GPIO_OUT                0x1
 #define IXP4XX_GPIO_IN                 0x2
 
-#define IXP4XX_GPIO_INTSTYLE_MASK      0x7C  /* Bits [6:2] define interrupt style */
-
-/* 
- * GPIO interrupt types.
- */
-#define IXP4XX_GPIO_ACTIVE_HIGH                0x4 /* Default */
-#define IXP4XX_GPIO_ACTIVE_LOW         0x8
-#define IXP4XX_GPIO_RISING_EDGE                0x10
-#define IXP4XX_GPIO_FALLING_EDGE       0x20
-#define IXP4XX_GPIO_TRANSITIONAL       0x40
-
 /* GPIO signal types */
 #define IXP4XX_GPIO_LOW                        0
 #define IXP4XX_GPIO_HIGH               1
@@ -102,7 +91,13 @@ extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys);
 #define IXP4XX_GPIO_CLK_0              14
 #define IXP4XX_GPIO_CLK_1              15
 
-extern void gpio_line_config(u8 line, u32 style);
+static inline void gpio_line_config(u8 line, u32 direction)
+{
+       if (direction == IXP4XX_GPIO_OUT)
+               *IXP4XX_GPIO_GPOER |= (1 << line);
+       else
+               *IXP4XX_GPIO_GPOER &= ~(1 << line);
+}
 
 static inline void gpio_line_get(u8 line, int *value)
 {
index 79138dcfb4accafa92a10910cdc0a70a93d42e8c..d64ee9211eeddc63fbb888421f01157f72f382a1 100644 (file)
@@ -30,6 +30,9 @@
 #define __ASM_ARCH_OMAP_H4_H
 
 /* Placeholder for H4 specific defines */
+/* GPMC CS1 */
+#define OMAP24XX_ETHR_START             0x08000300
+#define OMAP24XX_ETHR_GPIO_IRQ         92
 
 #endif /*  __ASM_ARCH_OMAP_H4_H */
 
index 0f1abaefe4decf6c81f7c5d8feefb3b8ee24c9bc..79574e0ed13d3c82d03c13cd4fbcc7df69d5f4c2 100644 (file)
 #define OMAP1510P1_EMIFS_PRI_VALUE             0x00
 #define OMAP1510P1_EMIFF_PRI_VALUE             0x00
 
-/*
- * These definitions define an area of FLASH set aside
- * for the use of MTD/JFFS2. This is the area of flash
- * that a JFFS2 filesystem will reside which is mounted
- * at boot with the "root=/dev/mtdblock/0 rw"
- * command line option. The flash address used here must
- * fall within the legal range defined by rrload for storing
- * the filesystem component. This address will be sufficiently
- * deep into the overall flash range to avoid the other
- * components also stored in flash such as the bootloader,
- * the bootloader params, and the kernel.
- * The SW2 settings for the map below are:
- * 1 off, 2 off, 3 on, 4 off.
- */
-
-/* Intel flash_0, partitioned as expected by rrload */
-#define OMAP_FLASH_0_BASE      0xD8000000
-#define OMAP_FLASH_0_START     0x00000000
-#define OMAP_FLASH_0_SIZE      SZ_16M
-
-/* Intel flash_1, used for cramfs or other flash file systems */
-#define OMAP_FLASH_1_BASE      0xD9000000
-#define OMAP_FLASH_1_START     0x01000000
-#define OMAP_FLASH_1_SIZE      SZ_16M
-
 #define NR_FPGA_IRQS           24
 #define NR_IRQS                 IH_BOARD_BASE + NR_FPGA_IRQS
 
index 0c224cc74fe4289678408a1095758723c9a18af1..691e52a52b433f4fe5cf43e9feeabefdd03e04ee 100644 (file)
 #define OMAP_SDRAM_DEVICE              D256M_1X16_4B
 #endif
 
-/*
- * These definitions define an area of FLASH set aside
- * for the use of MTD/JFFS2. This is the area of flash
- * that a JFFS2 filesystem will reside which is mounted
- * at boot with the "root=/dev/mtdblock/0 rw"
- * command line option.
- */
-
-/* Intel flash_0, partitioned as expected by rrload */
-#define OMAP_FLASH_0_BASE      0xD8000000      /* VA */
-#define OMAP_FLASH_0_START     0x00000000      /* PA */
-#define OMAP_FLASH_0_SIZE      SZ_32M
-
 #define MAXIRQNUM              IH_BOARD_BASE
 #define MAXFIQNUM              MAXIRQNUM
 #define MAXSWINUM              MAXIRQNUM
 
 #define NR_IRQS                        (MAXIRQNUM + 1)
 
+/* Samsung NAND flash at CS2B or CS3(NAND Boot) */
+#define OMAP_NAND_FLASH_START1    0x0A000000 /* CS2B */
+#define OMAP_NAND_FLASH_START2    0x0C000000 /* CS3 */
+
 #endif
index 33977b8956fbb1abcaec714b839e39be6a148305..ed6d346ee12344da8fa651956b3742360b433f09 100644 (file)
 #ifndef __ASM_ARCH_VOICEBLUE_H
 #define __ASM_ARCH_VOICEBLUE_H
 
-#if (EXTERNAL_MAX_NR_PORTS < 4)
-#undef EXTERNAL_MAX_NR_PORTS
-#define EXTERNAL_MAX_NR_PORTS  4
-#endif
-
 extern void voiceblue_wdt_enable(void);
 extern void voiceblue_wdt_disable(void);
 extern void voiceblue_wdt_ping(void);
index 95bd625480c13afd715fe45a70e0a40bb9c57cf0..a0040cd86639452426f7a715e5f9043237fdc5ed 100644 (file)
@@ -30,10 +30,23 @@ struct omap_clock_config {
        u8 system_clock_type;
 };
 
+struct omap_mmc_conf {
+       unsigned enabled:1;
+       /* nomux means "standard" muxing is wrong on this board, and that
+        * board-specific code handled it before common init logic.
+        */
+       unsigned nomux:1;
+       /* switch pin can be for card detect (default) or card cover */
+       unsigned cover:1;
+       /* 4 wire signaling is optional, and is only used for SD/SDIO */
+       unsigned wire4:1;
+       s16 power_pin;
+       s16 switch_pin;
+       s16 wp_pin;
+};
+
 struct omap_mmc_config {
-       u8 mmc_blocks;
-       s16 mmc1_power_pin, mmc2_power_pin;
-       s16 mmc1_switch_pin, mmc2_switch_pin;
+       struct omap_mmc_conf mmc[2];
 };
 
 struct omap_serial_console_config {
index e8786713ee5cc561cda61b7360c15e42008b4d60..1119e2b53e724fb9773c35dcaf793cc7b7df62e0 100644 (file)
@@ -38,146 +38,179 @@ extern unsigned int system_rev;
 /*
  * Test if multicore OMAP support is needed
  */
-#undef MULTI_OMAP
+#undef MULTI_OMAP1
+#undef MULTI_OMAP2
 #undef OMAP_NAME
 
 #ifdef CONFIG_ARCH_OMAP730
 # ifdef OMAP_NAME
-#  undef  MULTI_OMAP
-#  define MULTI_OMAP
+#  undef  MULTI_OMAP1
+#  define MULTI_OMAP1
 # else
 #  define OMAP_NAME omap730
 # endif
 #endif
 #ifdef CONFIG_ARCH_OMAP1510
 # ifdef OMAP_NAME
-#  undef  MULTI_OMAP
-#  define MULTI_OMAP
+#  undef  MULTI_OMAP1
+#  define MULTI_OMAP1
 # else
 #  define OMAP_NAME omap1510
 # endif
 #endif
 #ifdef CONFIG_ARCH_OMAP16XX
 # ifdef OMAP_NAME
-#  undef  MULTI_OMAP
-#  define MULTI_OMAP
+#  undef  MULTI_OMAP1
+#  define MULTI_OMAP1
 # else
-#  define OMAP_NAME omap1610
+#  define OMAP_NAME omap16xx
 # endif
 #endif
-#ifdef CONFIG_ARCH_OMAP16XX
-# ifdef OMAP_NAME
-#  undef  MULTI_OMAP
-#  define MULTI_OMAP
+#ifdef CONFIG_ARCH_OMAP24XX
+# if (defined(OMAP_NAME) || defined(MULTI_OMAP1))
+#  error "OMAP1 and OMAP2 can't be selected at the same time"
 # else
-#  define OMAP_NAME omap1710
+#  undef  MULTI_OMAP2
+#  define OMAP_NAME omap24xx
 # endif
 #endif
 
 /*
- * Generate various OMAP cpu specific macros, and cpu class
- * specific macros
+ * Macros to group OMAP into cpu classes.
+ * These can be used in most places.
+ * cpu_is_omap7xx():   True for OMAP730
+ * cpu_is_omap15xx():  True for OMAP1510 and OMAP5910
+ * cpu_is_omap16xx():  True for OMAP1610, OMAP5912 and OMAP1710
+ * cpu_is_omap24xx():  True for OMAP2420
  */
-#define GET_OMAP_TYPE  ((system_rev >> 24) & 0xff)
 #define GET_OMAP_CLASS (system_rev & 0xff)
 
-#define IS_OMAP_TYPE(type, id)                         \
-static inline int is_omap ##type (void)                        \
-{                                                      \
-       return (GET_OMAP_TYPE == (id)) ? 1 : 0;         \
-}
-
 #define IS_OMAP_CLASS(class, id)                       \
 static inline int is_omap ##class (void)               \
 {                                                      \
        return (GET_OMAP_CLASS == (id)) ? 1 : 0;        \
 }
 
-IS_OMAP_TYPE(730, 0x07)
-IS_OMAP_TYPE(1510, 0x15)
-IS_OMAP_TYPE(1610, 0x16)
-IS_OMAP_TYPE(5912, 0x16)
-IS_OMAP_TYPE(1710, 0x17)
-IS_OMAP_TYPE(2420, 0x24)
-
 IS_OMAP_CLASS(7xx, 0x07)
 IS_OMAP_CLASS(15xx, 0x15)
 IS_OMAP_CLASS(16xx, 0x16)
 IS_OMAP_CLASS(24xx, 0x24)
 
-/*
- * Macros to group OMAP types into cpu classes.
- * These can be used in most places.
- * cpu_is_omap15xx():  True for 1510 and 5910
- * cpu_is_omap16xx():  True for 1610, 5912 and 1710
- */
-#if defined(MULTI_OMAP)
-# define cpu_is_omap7xx()              is_omap7xx()
-# define cpu_is_omap15xx()             is_omap15xx()
-# if !(defined(CONFIG_ARCH_OMAP1510) || defined(CONFIG_ARCH_OMAP730))
-#  define cpu_is_omap16xx()            1
-# else
+#define cpu_is_omap7xx()               0
+#define cpu_is_omap15xx()              0
+#define cpu_is_omap16xx()              0
+#define cpu_is_omap24xx()              0
+
+#if defined(MULTI_OMAP1)
+# if defined(CONFIG_ARCH_OMAP730)
+#  undef  cpu_is_omap7xx
+#  define cpu_is_omap7xx()             is_omap7xx()
+# endif
+# if defined(CONFIG_ARCH_OMAP1510)
+#  undef  cpu_is_omap15xx
+#  define cpu_is_omap15xx()            is_omap15xx()
+# endif
+# if defined(CONFIG_ARCH_OMAP16XX)
+#  undef  cpu_is_omap16xx
 #  define cpu_is_omap16xx()            is_omap16xx()
 # endif
 #else
 # if defined(CONFIG_ARCH_OMAP730)
+#  undef  cpu_is_omap7xx
 #  define cpu_is_omap7xx()             1
-# else
-#  define cpu_is_omap7xx()             0
 # endif
 # if defined(CONFIG_ARCH_OMAP1510)
+#  undef  cpu_is_omap15xx
 #  define cpu_is_omap15xx()            1
-# else
-#  define cpu_is_omap15xx()            0
 # endif
 # if defined(CONFIG_ARCH_OMAP16XX)
+#  undef  cpu_is_omap16xx
 #  define cpu_is_omap16xx()            1
-# else
-#  define cpu_is_omap16xx()            0
+# endif
+# if defined(CONFIG_ARCH_OMAP24XX)
+#  undef  cpu_is_omap24xx
+#  define cpu_is_omap24xx()            1
 # endif
 #endif
 
-#if defined(MULTI_OMAP)
-# define cpu_is_omap730()              is_omap730()
-# define cpu_is_omap1510()             is_omap1510()
-# define cpu_is_omap1610()             is_omap1610()
-# define cpu_is_omap5912()             is_omap5912()
-# define cpu_is_omap1710()             is_omap1710()
+/*
+ * Macros to detect individual cpu types.
+ * These are only rarely needed.
+ * cpu_is_omap730():   True for OMAP730
+ * cpu_is_omap1510():  True for OMAP1510
+ * cpu_is_omap1610():  True for OMAP1610
+ * cpu_is_omap1611():  True for OMAP1611
+ * cpu_is_omap5912():  True for OMAP5912
+ * cpu_is_omap1621():  True for OMAP1621
+ * cpu_is_omap1710():  True for OMAP1710
+ * cpu_is_omap2420():  True for OMAP2420
+ */
+#define GET_OMAP_TYPE  ((system_rev >> 16) & 0xffff)
+
+#define IS_OMAP_TYPE(type, id)                         \
+static inline int is_omap ##type (void)                        \
+{                                                      \
+       return (GET_OMAP_TYPE == (id)) ? 1 : 0;         \
+}
+
+IS_OMAP_TYPE(730, 0x0730)
+IS_OMAP_TYPE(1510, 0x1510)
+IS_OMAP_TYPE(1610, 0x1610)
+IS_OMAP_TYPE(1611, 0x1611)
+IS_OMAP_TYPE(5912, 0x1611)
+IS_OMAP_TYPE(1621, 0x1621)
+IS_OMAP_TYPE(1710, 0x1710)
+IS_OMAP_TYPE(2420, 0x2420)
+
+#define cpu_is_omap730()               0
+#define cpu_is_omap1510()              0
+#define cpu_is_omap1610()              0
+#define cpu_is_omap5912()              0
+#define cpu_is_omap1611()              0
+#define cpu_is_omap1621()              0
+#define cpu_is_omap1710()              0
+#define cpu_is_omap2420()              0
+
+#if defined(MULTI_OMAP1)
+# if defined(CONFIG_ARCH_OMAP730)
+#  undef  cpu_is_omap730
+#  define cpu_is_omap730()             is_omap730()
+# endif
+# if defined(CONFIG_ARCH_OMAP1510)
+#  undef  cpu_is_omap1510
+#  define cpu_is_omap1510()            is_omap1510()
+# endif
 #else
 # if defined(CONFIG_ARCH_OMAP730)
+#  undef  cpu_is_omap730
 #  define cpu_is_omap730()             1
-# else
-#  define cpu_is_omap730()             0
 # endif
 # if defined(CONFIG_ARCH_OMAP1510)
+#  undef  cpu_is_omap1510
 #  define cpu_is_omap1510()            1
-# else
-#  define cpu_is_omap1510()            0
 # endif
-# if defined(CONFIG_ARCH_OMAP16XX)
-#  define cpu_is_omap1610()            1
-# else
-#  define cpu_is_omap1610()            0
-# endif
-# if defined(CONFIG_ARCH_OMAP16XX)
-#  define cpu_is_omap5912()            1
-# else
-#  define cpu_is_omap5912()            0
-# endif
-# if defined(CONFIG_ARCH_OMAP16XX)
+#endif
+
+/*
+ * Whether we have MULTI_OMAP1 or not, we still need to distinguish
+ * between 1611B/5912 and 1710.
+ */
+#if defined(CONFIG_ARCH_OMAP16XX)
+# undef  cpu_is_omap1610
+# undef  cpu_is_omap1611
+# undef  cpu_is_omap5912
+# undef  cpu_is_omap1621
+# undef  cpu_is_omap1710
 # define cpu_is_omap1610()             is_omap1610()
+# define cpu_is_omap1611()             is_omap1611()
 # define cpu_is_omap5912()             is_omap5912()
+# define cpu_is_omap1621()             is_omap1621()
 # define cpu_is_omap1710()             is_omap1710()
-# else
-# define cpu_is_omap1610()             0
-# define cpu_is_omap5912()             0
-# define cpu_is_omap1710()             0
-# endif
-# if defined(CONFIG_ARCH_OMAP2420)
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2420)
+#  undef  cpu_is_omap2420
 #  define cpu_is_omap2420()            1
-# else
-#  define cpu_is_omap2420()            0
-# endif
 #endif
 
 #endif
index 83bb458afd0ba7480289e87d0b141596a71c2b9e..ca4f577f967588396bdd07146e74d41cda84682c 100644 (file)
@@ -14,6 +14,7 @@
                .macro  addruart,rx
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
+#ifdef CONFIG_ARCH_OMAP1
                moveq   \rx, #0xff000000        @ physical base address
                movne   \rx, #0xfe000000        @ virtual base
                orr     \rx, \rx, #0x00fb0000
 #endif
 #if defined(CONFIG_OMAP_LL_DEBUG_UART2) || defined(CONFIG_OMAP_LL_DEBUG_UART3)
                orr     \rx, \rx, #0x00000800   @ UART 2 & 3
+#endif
+
+#elif  CONFIG_ARCH_OMAP2
+               moveq   \rx, #0x48000000        @ physical base address
+               movne   \rx, #0xd8000000        @ virtual base
+               orr     \rx, \rx, #0x0006a000
+#ifdef CONFIG_OMAP_LL_DEBUG_UART2
+               add     \rx, \rx, #0x00002000   @ UART 2
+#endif
+#ifdef CONFIG_OMAP_LL_DEBUG_UART3
+               add     \rx, \rx, #0x00004000   @ UART 3
+#endif
 #endif
                .endm
 
index ce114ce5af5d6af63d3d44af7e49c35eb9f3b701..04ebef5c6e95d180142d3e25e938630705b4341c 100644 (file)
@@ -240,6 +240,7 @@ extern void omap_dma_unlink_lch (int lch_head, int lch_queue);
 
 extern dma_addr_t omap_get_dma_src_pos(int lch);
 extern dma_addr_t omap_get_dma_dst_pos(int lch);
+extern int omap_get_dma_src_addr_counter(int lch);
 extern void omap_clear_dma(int lch);
 extern int omap_dma_running(void);
 
diff --git a/include/asm-arm/arch-omap/dmtimer.h b/include/asm-arm/arch-omap/dmtimer.h
new file mode 100644 (file)
index 0000000..11772c7
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * linux/include/asm-arm/arm/arch-omap/dmtimer.h
+ *
+ * OMAP Dual-Mode Timers
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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 __ASM_ARCH_TIMER_H
+#define __ASM_ARCH_TIMER_H
+
+#include <linux/list.h>
+
+#define OMAP_TIMER_SRC_ARMXOR          0x00
+#define OMAP_TIMER_SRC_32_KHZ          0x01
+#define OMAP_TIMER_SRC_EXT_CLK         0x02
+
+/* timer control reg bits */
+#define OMAP_TIMER_CTRL_CAPTMODE       (1 << 13)
+#define OMAP_TIMER_CTRL_PT             (1 << 12)
+#define OMAP_TIMER_CTRL_TRG_OVERFLOW   (0x1 << 10)
+#define OMAP_TIMER_CTRL_TRG_OFANDMATCH (0x2 << 10)
+#define OMAP_TIMER_CTRL_TCM_LOWTOHIGH  (0x1 << 8)
+#define OMAP_TIMER_CTRL_TCM_HIGHTOLOW  (0x2 << 8)
+#define OMAP_TIMER_CTRL_TCM_BOTHEDGES  (0x3 << 8)
+#define OMAP_TIMER_CTRL_SCPWM          (1 << 7)
+#define OMAP_TIMER_CTRL_CE             (1 << 6)        /* compare enable */
+#define OMAP_TIMER_CTRL_PRE            (1 << 5)        /* prescaler enable */
+#define OMAP_TIMER_CTRL_PTV_SHIFT      2               /* how much to shift the prescaler value */
+#define OMAP_TIMER_CTRL_AR             (1 << 1)        /* auto-reload enable */
+#define OMAP_TIMER_CTRL_ST             (1 << 0)        /* start timer */
+
+/* timer interrupt enable bits */
+#define OMAP_TIMER_INT_CAPTURE         (1 << 2)
+#define OMAP_TIMER_INT_OVERFLOW                (1 << 1)
+#define OMAP_TIMER_INT_MATCH           (1 << 0)
+
+
+struct omap_dm_timer {
+       struct list_head timer_list;
+
+       u32 base;
+       unsigned int irq;
+};
+
+u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg);
+void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value);
+
+struct omap_dm_timer * omap_dm_timer_request(void);
+void omap_dm_timer_free(struct omap_dm_timer *timer);
+void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source);
+
+void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value);
+void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value);
+void omap_dm_timer_enable_compare(struct omap_dm_timer *timer);
+void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer);
+
+void omap_dm_timer_trigger(struct omap_dm_timer *timer);
+void omap_dm_timer_start(struct omap_dm_timer *timer);
+void omap_dm_timer_stop(struct omap_dm_timer *timer);
+
+void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load);
+void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match);
+
+unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer);
+void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value);
+
+unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer);
+void omap_dm_timer_reset_counter(struct omap_dm_timer *timer);
+
+int omap_dm_timers_active(void);
+
+#endif /* __ASM_ARCH_TIMER_H */
diff --git a/include/asm-arm/arch-omap/dsp.h b/include/asm-arm/arch-omap/dsp.h
new file mode 100644 (file)
index 0000000..57bf4f3
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * linux/include/asm-arm/arch-omap/dsp.h
+ *
+ * Header for OMAP DSP driver
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * 2005/06/01:  DSP Gateway version 3.3
+ */
+
+#ifndef ASM_ARCH_DSP_H
+#define ASM_ARCH_DSP_H
+
+
+/*
+ * for /dev/dspctl/ctl
+ */
+#define OMAP_DSP_IOCTL_RESET                   1
+#define OMAP_DSP_IOCTL_RUN                     2
+#define OMAP_DSP_IOCTL_SETRSTVECT              3
+#define OMAP_DSP_IOCTL_CPU_IDLE                        4
+#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON                5
+#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_OFF       6
+#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_ON                7
+#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_OFF       8
+#define OMAP_DSP_IOCTL_GBL_IDLE                        9
+#define OMAP_DSP_IOCTL_DSPCFG                  10
+#define OMAP_DSP_IOCTL_DSPUNCFG                        11
+#define OMAP_DSP_IOCTL_TASKCNT                 12
+#define OMAP_DSP_IOCTL_POLL                    13
+#define OMAP_DSP_IOCTL_REGMEMR                 40
+#define OMAP_DSP_IOCTL_REGMEMW                 41
+#define OMAP_DSP_IOCTL_REGIOR                  42
+#define OMAP_DSP_IOCTL_REGIOW                  43
+#define OMAP_DSP_IOCTL_GETVAR                  44
+#define OMAP_DSP_IOCTL_SETVAR                  45
+#define OMAP_DSP_IOCTL_RUNLEVEL                        50
+#define OMAP_DSP_IOCTL_SUSPEND                 51
+#define OMAP_DSP_IOCTL_RESUME                  52
+#define OMAP_DSP_IOCTL_FBEN                    53
+#define OMAP_DSP_IOCTL_FBDIS                   54
+#define OMAP_DSP_IOCTL_MBSEND                  99
+
+/*
+ * for taskdev
+ * (ioctls below should be >= 0x10000)
+ */
+#define OMAP_DSP_TASK_IOCTL_BFLSH      0x10000
+#define OMAP_DSP_TASK_IOCTL_SETBSZ     0x10001
+#define OMAP_DSP_TASK_IOCTL_LOCK       0x10002
+#define OMAP_DSP_TASK_IOCTL_UNLOCK     0x10003
+#define OMAP_DSP_TASK_IOCTL_GETNAME    0x10004
+
+/*
+ * for /dev/dspctl/mem
+ */
+#define OMAP_DSP_MEM_IOCTL_EXMAP       1
+#define OMAP_DSP_MEM_IOCTL_EXUNMAP     2
+#define OMAP_DSP_MEM_IOCTL_EXMAP_FLUSH 3
+#define OMAP_DSP_MEM_IOCTL_FBEXPORT    5
+#define OMAP_DSP_MEM_IOCTL_MMUITACK    7
+#define OMAP_DSP_MEM_IOCTL_MMUINIT     9
+#define OMAP_DSP_MEM_IOCTL_KMEM_RESERVE        11
+#define OMAP_DSP_MEM_IOCTL_KMEM_RELEASE        12
+
+struct omap_dsp_mapinfo {
+       unsigned long dspadr;
+       unsigned long size;
+};
+
+/*
+ * for /dev/dspctl/twch
+ */
+#define OMAP_DSP_TWCH_IOCTL_MKDEV      1
+#define OMAP_DSP_TWCH_IOCTL_RMDEV      2
+#define OMAP_DSP_TWCH_IOCTL_TADD       11
+#define OMAP_DSP_TWCH_IOCTL_TDEL       12
+#define OMAP_DSP_TWCH_IOCTL_TKILL      13
+
+#define OMAP_DSP_DEVSTATE_NOTASK       0x00000001
+#define OMAP_DSP_DEVSTATE_ATTACHED     0x00000002
+#define OMAP_DSP_DEVSTATE_GARBAGE      0x00000004
+#define OMAP_DSP_DEVSTATE_INVALID      0x00000008
+#define OMAP_DSP_DEVSTATE_ADDREQ       0x00000100
+#define OMAP_DSP_DEVSTATE_DELREQ       0x00000200
+#define OMAP_DSP_DEVSTATE_ADDFAIL      0x00001000
+#define OMAP_DSP_DEVSTATE_ADDING       0x00010000
+#define OMAP_DSP_DEVSTATE_DELING       0x00020000
+#define OMAP_DSP_DEVSTATE_KILLING      0x00040000
+#define OMAP_DSP_DEVSTATE_STATE_MASK   0x7fffffff
+#define OMAP_DSP_DEVSTATE_STALE                0x80000000
+
+struct omap_dsp_taddinfo {
+       unsigned char minor;
+       unsigned long taskadr;
+};
+#define OMAP_DSP_TADD_ABORTADR 0xffffffff
+
+
+/*
+ * error cause definition (for error detection device)
+ */
+#define OMAP_DSP_ERRDT_WDT     0x00000001
+#define OMAP_DSP_ERRDT_MMU     0x00000002
+
+
+/*
+ * mailbox protocol definitions
+ */
+
+struct omap_dsp_mailbox_cmd {
+       unsigned short cmd;
+       unsigned short data;
+};
+
+struct omap_dsp_reginfo {
+       unsigned short adr;
+       unsigned short val;
+};
+
+struct omap_dsp_varinfo {
+       unsigned char varid;
+       unsigned short val[0];
+};
+
+#define OMAP_DSP_MBPROT_REVISION       0x0019
+
+#define OMAP_DSP_MBCMD_WDSND   0x10
+#define OMAP_DSP_MBCMD_WDREQ   0x11
+#define OMAP_DSP_MBCMD_BKSND   0x20
+#define OMAP_DSP_MBCMD_BKREQ   0x21
+#define OMAP_DSP_MBCMD_BKYLD   0x23
+#define OMAP_DSP_MBCMD_BKSNDP  0x24
+#define OMAP_DSP_MBCMD_BKREQP  0x25
+#define OMAP_DSP_MBCMD_TCTL    0x30
+#define OMAP_DSP_MBCMD_TCTLDATA        0x31
+#define OMAP_DSP_MBCMD_POLL    0x32
+#define OMAP_DSP_MBCMD_WDT     0x50    /* v3.3: obsolete */
+#define OMAP_DSP_MBCMD_RUNLEVEL        0x51
+#define OMAP_DSP_MBCMD_PM      0x52
+#define OMAP_DSP_MBCMD_SUSPEND 0x53
+#define OMAP_DSP_MBCMD_KFUNC   0x54
+#define OMAP_DSP_MBCMD_TCFG    0x60
+#define OMAP_DSP_MBCMD_TADD    0x62
+#define OMAP_DSP_MBCMD_TDEL    0x63
+#define OMAP_DSP_MBCMD_TSTOP   0x65
+#define OMAP_DSP_MBCMD_DSPCFG  0x70
+#define OMAP_DSP_MBCMD_REGRW   0x72
+#define OMAP_DSP_MBCMD_GETVAR  0x74
+#define OMAP_DSP_MBCMD_SETVAR  0x75
+#define OMAP_DSP_MBCMD_ERR     0x78
+#define OMAP_DSP_MBCMD_DBG     0x79
+
+#define OMAP_DSP_MBCMD_TCTL_TINIT      0x0000
+#define OMAP_DSP_MBCMD_TCTL_TEN                0x0001
+#define OMAP_DSP_MBCMD_TCTL_TDIS       0x0002
+#define OMAP_DSP_MBCMD_TCTL_TCLR       0x0003
+#define OMAP_DSP_MBCMD_TCTL_TCLR_FORCE 0x0004
+
+#define OMAP_DSP_MBCMD_RUNLEVEL_USER           0x01
+#define OMAP_DSP_MBCMD_RUNLEVEL_SUPER          0x0e
+#define OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY       0x10
+
+#define OMAP_DSP_MBCMD_PM_DISABLE      0x00
+#define OMAP_DSP_MBCMD_PM_ENABLE       0x01
+
+#define OMAP_DSP_MBCMD_KFUNC_FBCTL     0x00
+
+#define OMAP_DSP_MBCMD_FBCTL_ENABLE    0x0002
+#define OMAP_DSP_MBCMD_FBCTL_DISABLE   0x0003
+
+#define OMAP_DSP_MBCMD_TDEL_SAFE       0x0000
+#define OMAP_DSP_MBCMD_TDEL_KILL       0x0001
+
+#define OMAP_DSP_MBCMD_DSPCFG_REQ      0x00
+#define OMAP_DSP_MBCMD_DSPCFG_SYSADRH  0x28
+#define OMAP_DSP_MBCMD_DSPCFG_SYSADRL  0x29
+#define OMAP_DSP_MBCMD_DSPCFG_PROTREV  0x70
+#define OMAP_DSP_MBCMD_DSPCFG_ABORT    0x78
+#define OMAP_DSP_MBCMD_DSPCFG_LAST     0x80
+
+#define OMAP_DSP_MBCMD_REGRW_MEMR      0x00
+#define OMAP_DSP_MBCMD_REGRW_MEMW      0x01
+#define OMAP_DSP_MBCMD_REGRW_IOR       0x02
+#define OMAP_DSP_MBCMD_REGRW_IOW       0x03
+#define OMAP_DSP_MBCMD_REGRW_DATA      0x04
+
+#define OMAP_DSP_MBCMD_VARID_ICRMASK   0x00
+#define OMAP_DSP_MBCMD_VARID_LOADINFO  0x01
+
+#define OMAP_DSP_TTYP_ARCV     0x0001
+#define OMAP_DSP_TTYP_ASND     0x0002
+#define OMAP_DSP_TTYP_BKMD     0x0004
+#define OMAP_DSP_TTYP_BKDM     0x0008
+#define OMAP_DSP_TTYP_PVMD     0x0010
+#define OMAP_DSP_TTYP_PVDM     0x0020
+
+#define OMAP_DSP_EID_BADTID    0x10
+#define OMAP_DSP_EID_BADTCN    0x11
+#define OMAP_DSP_EID_BADBID    0x20
+#define OMAP_DSP_EID_BADCNT    0x21
+#define OMAP_DSP_EID_NOTLOCKED 0x22
+#define OMAP_DSP_EID_STVBUF    0x23
+#define OMAP_DSP_EID_BADADR    0x24
+#define OMAP_DSP_EID_BADTCTL   0x30
+#define OMAP_DSP_EID_BADPARAM  0x50
+#define OMAP_DSP_EID_FATAL     0x58
+#define OMAP_DSP_EID_NOMEM     0xc0
+#define OMAP_DSP_EID_NORES     0xc1
+#define OMAP_DSP_EID_IPBFULL   0xc2
+#define OMAP_DSP_EID_WDT       0xd0
+#define OMAP_DSP_EID_TASKNOTRDY        0xe0
+#define OMAP_DSP_EID_TASKBSY   0xe1
+#define OMAP_DSP_EID_TASKERR   0xef
+#define OMAP_DSP_EID_BADCFGTYP 0xf0
+#define OMAP_DSP_EID_DEBUG     0xf8
+#define OMAP_DSP_EID_BADSEQ    0xfe
+#define OMAP_DSP_EID_BADCMD    0xff
+
+#define OMAP_DSP_TNM_LEN       16
+
+#define OMAP_DSP_TID_FREE      0xff
+#define OMAP_DSP_TID_ANON      0xfe
+
+#define OMAP_DSP_BID_NULL      0xffff
+#define OMAP_DSP_BID_PVT       0xfffe
+
+#endif /* ASM_ARCH_DSP_H */
diff --git a/include/asm-arm/arch-omap/dsp_common.h b/include/asm-arm/arch-omap/dsp_common.h
new file mode 100644 (file)
index 0000000..4fcce69
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * linux/include/asm-arm/arch-omap/dsp_common.h
+ *
+ * Header for OMAP DSP subsystem control
+ *
+ * Copyright (C) 2004,2005 Nokia Corporation
+ *
+ * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * 2005/06/03:  DSP Gateway version 3.3
+ */
+
+#ifndef ASM_ARCH_DSP_COMMON_H
+#define ASM_ARCH_DSP_COMMON_H
+
+void omap_dsp_pm_suspend(void);
+void omap_dsp_pm_resume(void);
+void omap_dsp_request_mpui(void);
+void omap_dsp_release_mpui(void);
+int omap_dsp_request_mem(void);
+int omap_dsp_release_mem(void);
+
+#endif /* ASM_ARCH_DSP_COMMON_H */
index 57b126889b989c3d3619222438d65919a9719209..0d29b9c56a957c9c83e76e1f5730fcbea5957da0 100644 (file)
@@ -8,6 +8,8 @@
  * warranty of any kind, whether express or implied.
  */
 
+#if defined(CONFIG_ARCH_OMAP1)
+
                .macro  disable_fiq
                .endm
 
 1510:
                .endm
 
+#elif defined(CONFIG_ARCH_OMAP24XX)
+
+#include <asm/arch/omap24xx.h>
+
+               .macro  disable_fiq
+               .endm
+
+               .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+               ldr     \base, =VA_IC_BASE
+               ldr     \irqnr, [\base, #0x98] /* IRQ pending reg 1 */
+               cmp     \irqnr, #0x0
+               bne     2222f
+               ldr     \irqnr, [\base, #0xb8] /* IRQ pending reg 2 */
+               cmp     \irqnr, #0x0
+               bne     2222f
+               ldr     \irqnr, [\base, #0xd8] /* IRQ pending reg 3 */
+               cmp     \irqnr, #0x0
+2222:
+               ldrne   \irqnr, [\base, #IRQ_SIR_IRQ]
+
+               .endm
+
+               .macro  irq_prio_table
+               .endm
+
+#endif
index fad2fc93ee7051c098ac88d00b89406da367d752..74cb2b93b70024f39bf135781e0afde230153af5 100644 (file)
@@ -3,7 +3,7 @@
  *
  * OMAP GPIO handling defines and functions
  *
- * Copyright (C) 2003 Nokia Corporation
+ * Copyright (C) 2003-2005 Nokia Corporation
  *
  * Written by Juha Yrjölä <juha.yrjola@nokia.com>
  *
 #include <asm/arch/irqs.h>
 #include <asm/io.h>
 
-#define OMAP_MPUIO_BASE                        0xfffb5000
+#define OMAP_MPUIO_BASE                        (void __iomem *)0xfffb5000
+
+#ifdef CONFIG_ARCH_OMAP730
+#define OMAP_MPUIO_INPUT_LATCH         0x00
+#define OMAP_MPUIO_OUTPUT              0x02
+#define OMAP_MPUIO_IO_CNTL             0x04
+#define OMAP_MPUIO_KBR_LATCH           0x08
+#define OMAP_MPUIO_KBC                 0x0a
+#define OMAP_MPUIO_GPIO_EVENT_MODE     0x0c
+#define OMAP_MPUIO_GPIO_INT_EDGE       0x0e
+#define OMAP_MPUIO_KBD_INT             0x10
+#define OMAP_MPUIO_GPIO_INT            0x12
+#define OMAP_MPUIO_KBD_MASKIT          0x14
+#define OMAP_MPUIO_GPIO_MASKIT         0x16
+#define OMAP_MPUIO_GPIO_DEBOUNCING     0x18
+#define OMAP_MPUIO_LATCH               0x1a
+#else
 #define OMAP_MPUIO_INPUT_LATCH         0x00
 #define OMAP_MPUIO_OUTPUT              0x04
 #define OMAP_MPUIO_IO_CNTL             0x08
@@ -44,6 +60,7 @@
 #define OMAP_MPUIO_GPIO_MASKIT         0x2c
 #define OMAP_MPUIO_GPIO_DEBOUNCING     0x30
 #define OMAP_MPUIO_LATCH               0x34
+#endif
 
 #define OMAP_MPUIO(nr)         (OMAP_MAX_GPIO_LINES + (nr))
 #define OMAP_GPIO_IS_MPUIO(nr) ((nr) >= OMAP_MAX_GPIO_LINES)
                                 IH_MPUIO_BASE + ((nr) & 0x0f) : \
                                 IH_GPIO_BASE + ((nr) & 0x3f))
 
-/* For EDGECTRL */
-#define OMAP_GPIO_NO_EDGE        0x00
-#define OMAP_GPIO_FALLING_EDGE   0x01
-#define OMAP_GPIO_RISING_EDGE    0x02
-#define OMAP_GPIO_BOTH_EDGES     0x03
-
 extern int omap_gpio_init(void);       /* Call from board init only */
 extern int omap_request_gpio(int gpio);
 extern void omap_free_gpio(int gpio);
 extern void omap_set_gpio_direction(int gpio, int is_input);
 extern void omap_set_gpio_dataout(int gpio, int enable);
 extern int omap_get_gpio_datain(int gpio);
-extern void omap_set_gpio_edge_ctrl(int gpio, int edge);
 
 #endif
index 48258c7f6541ca0c890b0df2e68b2739c6704bc2..60201e1dd6ad72b2eb05e3e81f1ae014fc10fc9b 100644 (file)
@@ -43,6 +43,7 @@
 #include <asm/arch/cpu.h>
 #endif
 #include <asm/arch/io.h>
+#include <asm/arch/serial.h>
 
 /*
  * ---------------------------------------------------------------------------
 /* DPLL control registers */
 #define DPLL_CTL               (0xfffecf00)
 
-/* DSP clock control */
+/* DSP clock control. Must use __raw_readw() and __raw_writew() with these */
 #define DSP_CONFIG_REG_BASE     (0xe1008000)
 #define DSP_CKCTL              (DSP_CONFIG_REG_BASE + 0x0)
 #define DSP_IDLECT1            (DSP_CONFIG_REG_BASE + 0x4)
 #define DSP_IDLECT2            (DSP_CONFIG_REG_BASE + 0x8)
+#define DSP_RSTCT2             (DSP_CONFIG_REG_BASE + 0x14)
 
 /*
  * ---------------------------------------------------------------------------
  * Interrupts
  * ---------------------------------------------------------------------------
  */
+#ifdef CONFIG_ARCH_OMAP1
+
+/*
+ * XXX: These probably want to be moved to arch/arm/mach-omap/omap1/irq.c
+ * or something similar.. -- PFM.
+ */
+
 #define OMAP_IH1_BASE          0xfffecb00
 #define OMAP_IH2_BASE          0xfffe0000
 
 #define IRQ_ILR0_REG_OFFSET    0x1c
 #define IRQ_GMR_REG_OFFSET     0xa0
 
+#endif
+
 /*
  * ----------------------------------------------------------------------------
  * System control registers
 
 #ifndef __ASSEMBLER__
 
-/*
- * ---------------------------------------------------------------------------
- * Serial ports
- * ---------------------------------------------------------------------------
- */
-#define OMAP_UART1_BASE                (unsigned char *)0xfffb0000
-#define OMAP_UART2_BASE                (unsigned char *)0xfffb0800
-#define OMAP_UART3_BASE                (unsigned char *)0xfffb9800
-#define OMAP_MAX_NR_PORTS      3
-#define OMAP1510_BASE_BAUD     (12000000/16)
-#define OMAP16XX_BASE_BAUD     (48000000/16)
-
-#define is_omap_port(p)        ({int __ret = 0;                        \
-                       if (p == IO_ADDRESS(OMAP_UART1_BASE) || \
-                           p == IO_ADDRESS(OMAP_UART2_BASE) || \
-                           p == IO_ADDRESS(OMAP_UART3_BASE))   \
-                               __ret = 1;                      \
-                       __ret;                                  \
-                       })
-
 /*
  * ---------------------------------------------------------------------------
  * Processor specific defines
 
 #include "omap730.h"
 #include "omap1510.h"
+
+#ifdef CONFIG_ARCH_OMAP24XX
+#include "omap24xx.h"
+#endif
+
 #include "omap16xx.h"
 
 /*
 
 #ifdef CONFIG_MACH_OMAP_H4
 #include "board-h4.h"
-#error "Support for H4 board not yet implemented."
 #endif
 
 #ifdef CONFIG_MACH_OMAP_OSK
index 1c8c9fcc766e5254c989c33e8999465e198b6f1b..11fbf629bf755410a10efee0b52f1711b584b931 100644 (file)
  * I/O mapping
  * ----------------------------------------------------------------------------
  */
-#define IO_PHYS                        0xFFFB0000
-#define IO_OFFSET              0x01000000      /* Virtual IO = 0xfefb0000 */
-#define IO_VIRT                        (IO_PHYS - IO_OFFSET)
-#define IO_SIZE                        0x40000
-#define IO_ADDRESS(x)          ((x) - IO_OFFSET)
 
-#define PCIO_BASE              0
+#if defined(CONFIG_ARCH_OMAP1)
+#define IO_PHYS                0xFFFB0000
+#define IO_OFFSET      -0x01000000     /* Virtual IO = 0xfefb0000 */
+#define IO_SIZE                0x40000
 
-#define io_p2v(x)               ((x) - IO_OFFSET)
-#define io_v2p(x)               ((x) + IO_OFFSET)
+#elif defined(CONFIG_ARCH_OMAP2)
+#define IO_PHYS                0x48000000      /* L4 peripherals; other stuff has to be mapped *
+                                        * manually. */
+#define IO_OFFSET      0x90000000      /* Virtual IO = 0xd8000000 */
+#define IO_SIZE                0x08000000
+#endif
+
+#define IO_VIRT                (IO_PHYS + IO_OFFSET)
+#define IO_ADDRESS(x)  ((x) + IO_OFFSET)
+#define PCIO_BASE      0
+#define io_p2v(x)      ((x) + IO_OFFSET)
+#define io_v2p(x)      ((x) - IO_OFFSET)
 
 #ifndef __ASSEMBLER__
 
@@ -96,6 +104,8 @@ typedef struct { volatile u32 offset[4096]; } __regbase32;
                                        ->offset[((vaddr)&4095)>>2]
 #define __REG32(paddr)         __REGV32(io_p2v(paddr))
 
+extern void omap_map_common_io(void);
+
 #else
 
 #define __REG8(paddr)          io_p2v(paddr)
index 0d05a7c957d155799e1acaf61a4dab8cf7184f42..74e108ccac168fc34444731e59611d82eca6403f 100644 (file)
 /*
  * OMAP-1510 specific IRQ numbers for interrupt handler 2
  */
-#define INT_1510_OS_32kHz_TIMER (22 + IH2_BASE)
 #define INT_1510_COM_SPI_RO    (31 + IH2_BASE)
 
 /*
 #define INT_730_DMA_CH15       (62 + IH2_BASE)
 #define INT_730_NAND           (63 + IH2_BASE)
 
+#define INT_24XX_GPIO_BANK1    29
+#define INT_24XX_GPIO_BANK2    30
+#define INT_24XX_GPIO_BANK3    31
+#define INT_24XX_GPIO_BANK4    32
+
 /* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730) and
  * 16 MPUIO lines */
 #define OMAP_MAX_GPIO_LINES    192
index f6b57dd846a318a2099981cd402fd478aacca6f9..84f81e315a25da0aa010154473dfbc272e1cfd8c 100644 (file)
 /*
  * Physical DRAM offset.
  */
+#if defined(CONFIG_ARCH_OMAP1)
 #define PHYS_OFFSET            (0x10000000UL)
-
-/*
- * OMAP-1510 Local Bus address offset
- */
-#define OMAP1510_LB_OFFSET     (0x30000000UL)
+#elif defined(CONFIG_ARCH_OMAP2)
+#define PHYS_OFFSET            (0x80000000UL)
+#endif
 
 /*
  * Conversion between SDRAM and fake PCI bus, used by USB
  */
 #ifdef CONFIG_ARCH_OMAP1510
 
+/*
+ * OMAP-1510 Local Bus address offset
+ */
+#define OMAP1510_LB_OFFSET     (0x30000000UL)
+
 #define virt_to_lbus(x)                ((x) - PAGE_OFFSET + OMAP1510_LB_OFFSET)
 #define lbus_to_virt(x)                ((x) - OMAP1510_LB_OFFSET + PAGE_OFFSET)
 #define is_lbus_device(dev)    (cpu_is_omap1510() && dev && (strncmp(dev->bus_id, "ohci", 4) == 0))
diff --git a/include/asm-arm/arch-omap/mtd-xip.h b/include/asm-arm/arch-omap/mtd-xip.h
new file mode 100644 (file)
index 0000000..a73a285
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * MTD primitives for XIP support. Architecture specific functions.
+ *
+ * Do not include this file directly. It's included from linux/mtd/xip.h
+ *
+ * Author: Vladimir Barinov <vbarinov@ru.mvista.com>
+ *
+ * (c) 2005 MontaVista Software, Inc.  This file is licensed under the
+ * terms of the GNU General Public License version 2.  This program is
+ * licensed "as is" without any warranty of any kind, whether express or
+ * implied.
+ */
+
+#ifndef __ARCH_OMAP_MTD_XIP_H__
+#define __ARCH_OMAP_MTD_XIP_H__
+
+#include <asm/hardware.h>
+#define OMAP_MPU_TIMER_BASE    (0xfffec500)
+#define OMAP_MPU_TIMER_OFFSET  0x100
+
+typedef struct {
+       u32 cntl;                       /* CNTL_TIMER, R/W */
+       u32 load_tim;                   /* LOAD_TIM,   W */
+       u32 read_tim;                   /* READ_TIM,   R */
+} xip_omap_mpu_timer_regs_t;
+
+#define xip_omap_mpu_timer_base(n)                                     \
+((volatile xip_omap_mpu_timer_regs_t*)IO_ADDRESS(OMAP_MPU_TIMER_BASE + \
+       (n)*OMAP_MPU_TIMER_OFFSET))
+
+static inline unsigned long xip_omap_mpu_timer_read(int nr)
+{
+       volatile xip_omap_mpu_timer_regs_t* timer = xip_omap_mpu_timer_base(nr);
+       return timer->read_tim;
+}
+
+#define xip_irqpending()       \
+       (omap_readl(OMAP_IH1_ITR) & ~omap_readl(OMAP_IH1_MIR))
+#define xip_currtime()         (~xip_omap_mpu_timer_read(0))
+
+/*
+ * It's permitted to do approxmation for xip_elapsed_since macro
+ * (see linux/mtd/xip.h)
+ */
+
+#ifdef CONFIG_MACH_OMAP_PERSEUS2
+#define xip_elapsed_since(x)   (signed)((~xip_omap_mpu_timer_read(0) - (x)) / 7)
+#else
+#define xip_elapsed_since(x)   (signed)((~xip_omap_mpu_timer_read(0) - (x)) / 6)
+#endif
+
+/*
+ * xip_cpu_idle() is used when waiting for a delay equal or larger than
+ * the system timer tick period.  This should put the CPU into idle mode
+ * to save power and to be woken up only when some interrupts are pending.
+ * As above, this should not rely upon standard kernel code.
+ */
+
+#define xip_cpu_idle()  asm volatile ("mcr p15, 0, %0, c7, c0, 4" :: "r" (1))
+
+#endif /* __ARCH_OMAP_MTD_XIP_H__ */
index 5bd3f0097fc6313e7f8a98623b5a26f2f8e35c62..1b1ad410534908a013515b737a7065c66d51b3bc 100644 (file)
@@ -185,6 +185,7 @@ typedef enum {
 
        /* MPUIO */
        MPUIO2,
+       N15_1610_MPUIO2,
        MPUIO4,
        MPUIO5,
        T20_1610_MPUIO5,
@@ -210,6 +211,7 @@ typedef enum {
 
        /* Misc ballouts */
        BALLOUT_V8_ARMIO3,
+       N20_HDQ,
 
        /* OMAP-1610 MMC2 */
        W8_1610_MMC2_DAT0,
@@ -235,6 +237,7 @@ typedef enum {
        P20_1610_GPIO4,
        V9_1610_GPIO7,
        W8_1610_GPIO9,
+       N20_1610_GPIO11,
        N19_1610_GPIO13,
        P10_1610_GPIO22,
        V5_1610_GPIO24,
@@ -250,7 +253,7 @@ typedef enum {
        U18_1610_UWIRE_SDI,
        W21_1610_UWIRE_SDO,
        N14_1610_UWIRE_CS0,
-       P15_1610_UWIRE_CS0,
+       P15_1610_UWIRE_CS3,
        N15_1610_UWIRE_CS1,
 
        /* OMAP-1610 Flash */
@@ -411,7 +414,8 @@ MUX_CFG("N21_1710_GPIO14",       6,    9,    0,   1,   1,   1,    1,     1,  1)
 MUX_CFG("W15_1710_GPIO40",       9,   27,    7,   2,   5,   1,    2,     1,  1)
 
 /* MPUIO */
-MUX_CFG("MPUIO2",               7,   18,    0,   1,   1,   1,   NA,     0,  1)
+MUX_CFG("MPUIO2",               7,   18,    0,   1,  14,   1,   NA,     0,  1)
+MUX_CFG("N15_1610_MPUIO2",      7,   18,    0,   1,  14,   1,    1,     0,  1)
 MUX_CFG("MPUIO4",               7,   15,    0,   1,  13,   1,   NA,     0,  1)
 MUX_CFG("MPUIO5",               7,   12,    0,   1,  12,   1,   NA,     0,  1)
 
@@ -438,6 +442,7 @@ MUX_CFG("MCBSP3_CLKX",               9,    3,    1,   1,  29,   0,   NA,     0,  1)
 
 /* Misc ballouts */
 MUX_CFG("BALLOUT_V8_ARMIO3",    B,   18,    0,   2,  25,   1,   NA,     0,  1)
+MUX_CFG("N20_HDQ",            6,   18,    1,   1,   4,   0,    1,     4,  0)
 
 /* OMAP-1610 MMC2 */
 MUX_CFG("W8_1610_MMC2_DAT0",    B,   21,    6,   2,  23,   1,    2,     1,  1)
@@ -463,6 +468,7 @@ MUX_CFG("J18_1610_ETM_D7",   5,   27,    1,   0,  19,   0,    0,     0,  1)
 MUX_CFG("P20_1610_GPIO4",       6,   27,    0,   1,   7,   0,    1,     1,  1)
 MUX_CFG("V9_1610_GPIO7",        B,   12,    1,   2,  20,   0,    2,     1,  1)
 MUX_CFG("W8_1610_GPIO9",        B,   21,    0,   2,  23,   0,    2,     1,  1)
+MUX_CFG("N20_1610_GPIO11",       6,   18,    0,   1,   4,   0,    1,     1,  1)
 MUX_CFG("N19_1610_GPIO13",      6,   12,    0,   1,   2,   0,    1,     1,  1)
 MUX_CFG("P10_1610_GPIO22",      C,    0,    7,   2,  26,   0,    2,     1,  1)
 MUX_CFG("V5_1610_GPIO24",       B,   15,    7,   2,  21,   0,    2,     1,  1)
index f491a48ef2e118904d1c36c3b9b24a96445ef360..f086a39339060c1012036f0e68cbaf0120ad0fb9 100644 (file)
 
 /* Syntax: XX_BASE = Virtual base address, XX_START = Physical base address */
 
-#define OMAP1510_SRAM_BASE     0xD0000000
-#define OMAP1510_SRAM_SIZE     (SZ_128K + SZ_64K)
-#define OMAP1510_SRAM_START    0x20000000
-
 #define OMAP1510_DSP_BASE      0xE0000000
 #define OMAP1510_DSP_SIZE      0x28000
 #define OMAP1510_DSP_START     0xE0000000
 #define OMAP1510_DSPREG_SIZE   SZ_128K
 #define OMAP1510_DSPREG_START  0xE1000000
 
-/*
- * ----------------------------------------------------------------------------
- * Memory used by power management
- * ----------------------------------------------------------------------------
- */
-
-#define OMAP1510_SRAM_IDLE_SUSPEND     (OMAP1510_SRAM_BASE + OMAP1510_SRAM_SIZE - 0x200)
-#define OMAP1510_SRAM_API_SUSPEND      (OMAP1510_SRAM_IDLE_SUSPEND + 0x100)
-
 #endif /*  __ASM_ARCH_OMAP1510_H */
 
index 38a9b95e6a336c7e12a3ebef89c629b37a22b6d9..f0c7f0fb4dc032e2a8c2303714b49504c3b7235b 100644 (file)
 
 /* Syntax: XX_BASE = Virtual base address, XX_START = Physical base address */
 
-#define OMAP16XX_SRAM_BASE     0xD0000000
-#define OMAP1610_SRAM_SIZE     (SZ_16K)
-#define OMAP5912_SRAM_SIZE     0x3E800
-#define OMAP16XX_SRAM_START    0x20000000
-
 #define OMAP16XX_DSP_BASE      0xE0000000
 #define OMAP16XX_DSP_SIZE      0x28000
 #define OMAP16XX_DSP_START     0xE0000000
 #define OMAP16XX_DSPREG_SIZE   SZ_128K
 #define OMAP16XX_DSPREG_START  0xE1000000
 
-/*
- * ----------------------------------------------------------------------------
- * Memory used by power management
- * ----------------------------------------------------------------------------
- */
-
-#define OMAP1610_SRAM_IDLE_SUSPEND     (OMAP16XX_SRAM_BASE + OMAP1610_SRAM_SIZE - 0x200)
-#define OMAP1610_SRAM_API_SUSPEND      (OMAP1610_SRAM_IDLE_SUSPEND + 0x100)
-#define OMAP5912_SRAM_IDLE_SUSPEND     (OMAP16XX_SRAM_BASE + OMAP5912_SRAM_SIZE - 0x200)
-#define OMAP5912_SRAM_API_SUSPEND      (OMAP5912_SRAM_IDLE_SUSPEND + 0x100)
-
 /*
  * ---------------------------------------------------------------------------
  * Interrupts
diff --git a/include/asm-arm/arch-omap/omap24xx.h b/include/asm-arm/arch-omap/omap24xx.h
new file mode 100644 (file)
index 0000000..a910546
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __ASM_ARCH_OMAP24XX_H
+#define __ASM_ARCH_OMAP24XX_H
+
+#define OMAP24XX_L4_IO_BASE    0x48000000
+
+/* interrupt controller */
+#define OMAP24XX_IC_BASE       (OMAP24XX_L4_IO_BASE + 0xfe000)
+#define VA_IC_BASE             IO_ADDRESS(OMAP24XX_IC_BASE)
+
+#define OMAP24XX_IVA_INTC_BASE 0x40000000
+
+#define IRQ_SIR_IRQ            0x0040
+
+#endif /* __ASM_ARCH_OMAP24XX_H */
+
index 599ab00f5488a5b0ebb14e352683cc473344703a..755b64c5e9f07342fdacf476c407226dbe66eab8 100644 (file)
 
 /* Syntax: XX_BASE = Virtual base address, XX_START = Physical base address */
 
-#define OMAP730_SRAM_BASE      0xD0000000
-#define OMAP730_SRAM_SIZE      (SZ_128K + SZ_64K + SZ_8K)
-#define OMAP730_SRAM_START     0x20000000
-
 #define OMAP730_DSP_BASE       0xE0000000
 #define OMAP730_DSP_SIZE       0x50000
 #define OMAP730_DSP_START      0xE0000000
index f209fc0953fb86559f39ffb48734ba93be13bf5d..fbd742d0c49997fc46e5ddc1299dd9d399242389 100644 (file)
 #define PER_EN                         0x1
 
 #define CPU_SUSPEND_SIZE               200
-#define ULPD_LOW_POWER_EN              0x0001
+#define ULPD_LOW_PWR_EN                        0x0001
+#define ULPD_DEEP_SLEEP_TRANSITION_EN  0x0010
+#define ULPD_SETUP_ANALOG_CELL_3_VAL   0
+#define ULPD_POWER_CTRL_REG_VAL                0x0219
 
 #define DSP_IDLE_DELAY                 10
 #define DSP_IDLE                       0x0040
 #define OMAP1510_BIG_SLEEP_REQUEST     0x0cc5
 #define OMAP1510_IDLE_LOOP_REQUEST     0x0c00
 #define OMAP1510_IDLE_CLOCK_DOMAINS    0x2
-#define OMAP1510_ULPD_LOW_POWER_REQ    0x0001
 
-#define OMAP1610_DEEP_SLEEP_REQUEST    0x17c7
-#define OMAP1610_BIG_SLEEP_REQUEST     TBD
+/* Both big sleep and deep sleep use same values. Difference is in ULPD. */
+#define OMAP1610_IDLECT1_SLEEP_VAL     0x13c7
+#define OMAP1610_IDLECT2_SLEEP_VAL     0x09c7
+#define OMAP1610_IDLECT3_VAL           0x3f
+#define OMAP1610_IDLECT3_SLEEP_ORMASK  0x2c
+#define OMAP1610_IDLECT3               0xfffece24
 #define OMAP1610_IDLE_LOOP_REQUEST     0x0400
-#define OMAP1610_IDLE_CLOCK_DOMAINS    0x09c7
-#define OMAP1610_ULPD_LOW_POWER_REQ    0x3
-
-#ifndef OMAP1510_SRAM_IDLE_SUSPEND
-#define OMAP1510_SRAM_IDLE_SUSPEND 0
-#endif
-#ifndef OMAP1610_SRAM_IDLE_SUSPEND
-#define OMAP1610_SRAM_IDLE_SUSPEND 0
-#endif
-#ifndef OMAP5912_SRAM_IDLE_SUSPEND
-#define OMAP5912_SRAM_IDLE_SUSPEND 0
-#endif
-
-#ifndef OMAP1510_SRAM_API_SUSPEND
-#define OMAP1510_SRAM_API_SUSPEND 0
-#endif
-#ifndef OMAP1610_SRAM_API_SUSPEND
-#define OMAP1610_SRAM_API_SUSPEND 0
-#endif
-#ifndef OMAP5912_SRAM_API_SUSPEND
-#define OMAP5912_SRAM_API_SUSPEND 0
-#endif
 
 #if     !defined(CONFIG_ARCH_OMAP1510) && \
-       !defined(CONFIG_ARCH_OMAP16XX)
+       !defined(CONFIG_ARCH_OMAP16XX) && \
+       !defined(CONFIG_ARCH_OMAP24XX)
 #error "Power management for this processor not implemented yet"
 #endif
 
 #ifndef __ASSEMBLER__
 extern void omap_pm_idle(void);
 extern void omap_pm_suspend(void);
-extern int omap1510_cpu_suspend(unsigned short, unsigned short);
-extern int omap1610_cpu_suspend(unsigned short, unsigned short);
-extern int omap1510_idle_loop_suspend(void);
-extern int omap1610_idle_loop_suspend(void);
+extern void omap1510_cpu_suspend(unsigned short, unsigned short);
+extern void omap1610_cpu_suspend(unsigned short, unsigned short);
+extern void omap1510_idle_loop_suspend(void);
+extern void omap1610_idle_loop_suspend(void);
+
+#ifdef CONFIG_OMAP_SERIAL_WAKE
+extern void omap_serial_wake_trigger(int enable);
+#else
+#define omap_serial_wake_trigger(x)    {}
+#endif /* CONFIG_OMAP_SERIAL_WAKE */
+
 extern unsigned int omap1510_cpu_suspend_sz;
 extern unsigned int omap1510_idle_loop_suspend_sz;
 extern unsigned int omap1610_cpu_suspend_sz;
@@ -161,6 +153,7 @@ enum arm_save_state {
        ARM_SLEEP_SAVE_ARM_CKCTL,
        ARM_SLEEP_SAVE_ARM_IDLECT1,
        ARM_SLEEP_SAVE_ARM_IDLECT2,
+       ARM_SLEEP_SAVE_ARM_IDLECT3,
        ARM_SLEEP_SAVE_ARM_EWUPCT,
        ARM_SLEEP_SAVE_ARM_RSTCT1,
        ARM_SLEEP_SAVE_ARM_RSTCT2,
diff --git a/include/asm-arm/arch-omap/serial.h b/include/asm-arm/arch-omap/serial.h
new file mode 100644 (file)
index 0000000..79a5297
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *  linux/include/asm-arm/arch-omap/serial.h
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_SERIAL_H
+#define __ASM_ARCH_SERIAL_H
+
+#if defined(CONFIG_ARCH_OMAP1)
+/* OMAP1 serial ports */
+#define OMAP_UART1_BASE                0xfffb0000
+#define OMAP_UART2_BASE                0xfffb0800
+#define OMAP_UART3_BASE                0xfffb9800
+#elif defined(CONFIG_ARCH_OMAP2)
+/* OMAP2 serial ports */
+#define OMAP_UART1_BASE                0x4806a000
+#define OMAP_UART2_BASE                0x4806c000
+#define OMAP_UART3_BASE                0x4806e000
+#endif
+
+#define OMAP_MAX_NR_PORTS      3
+#define OMAP1510_BASE_BAUD     (12000000/16)
+#define OMAP16XX_BASE_BAUD     (48000000/16)
+
+#define is_omap_port(p)        ({int __ret = 0;                        \
+                       if (p == IO_ADDRESS(OMAP_UART1_BASE) || \
+                           p == IO_ADDRESS(OMAP_UART2_BASE) || \
+                           p == IO_ADDRESS(OMAP_UART3_BASE))   \
+                               __ret = 1;                      \
+                       __ret;                                  \
+                       })
+
+#endif
index 3e640aba8c20f576410fb22b1ca72a365df431a6..3545c86859cc9a9700b02760a35fb1ba9a811ba8 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/serial_reg.h>
-#include <asm/arch/hardware.h>
+#include <asm/arch/serial.h>
 
 unsigned int system_rev;
 
@@ -34,8 +34,9 @@ static void
 putstr(const char *s)
 {
        volatile u8 * uart = 0;
-       int shift;
+       int shift = 2;
 
+#ifdef CONFIG_ARCH_OMAP
 #ifdef CONFIG_OMAP_LL_DEBUG_UART3
        uart = (volatile u8 *)(OMAP_UART3_BASE);
 #elif  CONFIG_OMAP_LL_DEBUG_UART2
@@ -44,6 +45,7 @@ putstr(const char *s)
        uart = (volatile u8 *)(OMAP_UART1_BASE);
 #endif
 
+#ifdef CONFIG_ARCH_OMAP1
        /* Determine which serial port to use */
        do {
                /* MMU is not on, so cpu_is_omapXXXX() won't work here */
@@ -51,14 +53,14 @@ putstr(const char *s)
 
                if (omap_id == OMAP_ID_730)
                        shift = 0;
-               else
-                       shift = 2;
 
                if (check_port(uart, shift))
                        break;
                /* Silent boot if no serial ports are enabled. */
                return;
        } while (0);
+#endif /* CONFIG_ARCH_OMAP1 */
+#endif
 
        /*
         * Now, xmit each character
index 324db06b5dd4b219f83316dd8a6d4aff1906e6d1..4b7aa0b8391e0741aab1fcee845ff1cc919421e1 100644 (file)
  * Shared data structures
  */
 extern struct platform_device corgiscoop_device;
+extern struct platform_device corgissp_device;
+extern struct platform_device corgifb_device;
 
 /*
  * External Functions
  */
 extern unsigned long corgi_ssp_ads7846_putget(unsigned long);
 extern unsigned long corgi_ssp_ads7846_get(void);
-extern void corgi_ssp_ads7846_put(ulong data);
+extern void corgi_ssp_ads7846_put(unsigned long data);
 extern void corgi_ssp_ads7846_lock(void);
 extern void corgi_ssp_ads7846_unlock(void);
-extern void corgi_ssp_lcdtg_send (u8 adrs, u8 data);
+extern void corgi_ssp_lcdtg_send (unsigned char adrs, unsigned char data);
 extern void corgi_ssp_blduty_set(int duty);
-extern int corgi_ssp_max1111_get(ulong data);
+extern int corgi_ssp_max1111_get(unsigned long data);
 
 #endif /* __ASM_ARCH_CORGI_H  */
 
index 7492ea7ea6141158f7bf24903541881dfa79db86..9718063a211959472bce3f7990cbdd5e8257948b 100644 (file)
@@ -10,6 +10,7 @@ struct mmc_host;
 struct pxamci_platform_data {
        unsigned int ocr_mask;                  /* available voltages */
        int (*init)(struct device *, irqreturn_t (*)(int, void *, struct pt_regs *), void *);
+       int (*get_ro)(struct device *);
        void (*setpower)(struct device *, unsigned int);
        void (*exit)(struct device *, void *);
 };
index 51f0fe0ac165bb4a6ee64f69faeaa2576994fce8..939d9e5020a0915f5c7ac7e5a50c49533187904f 100644 (file)
 #define UDCOTGICR_IEIDF        (1 << 0)        /* OTG ID Change Falling Edge
                                           Interrupt Enable */
 
+#define UP2OCR           __REG(0x40600020)  /* USB Port 2 Output Control register */
+
+#define UP2OCR_CPVEN   (1 << 0)        /* Charge Pump Vbus Enable */
+#define UP2OCR_CPVPE   (1 << 1)        /* Charge Pump Vbus Pulse Enable */
+#define UP2OCR_DPPDE   (1 << 2)        /* Host Port 2 Transceiver D+ Pull Down Enable */
+#define UP2OCR_DMPDE   (1 << 3)        /* Host Port 2 Transceiver D- Pull Down Enable */
+#define UP2OCR_DPPUE   (1 << 4)        /* Host Port 2 Transceiver D+ Pull Up Enable */
+#define UP2OCR_DMPUE   (1 << 5)        /* Host Port 2 Transceiver D- Pull Up Enable */
+#define UP2OCR_DPPUBE  (1 << 6)        /* Host Port 2 Transceiver D+ Pull Up Bypass Enable */
+#define UP2OCR_DMPUBE  (1 << 7)        /* Host Port 2 Transceiver D- Pull Up Bypass Enable */
+#define UP2OCR_EXSP            (1 << 8)        /* External Transceiver Speed Control */
+#define UP2OCR_EXSUS   (1 << 9)        /* External Transceiver Speed Enable */
+#define UP2OCR_IDON            (1 << 10)       /* OTG ID Read Enable */
+#define UP2OCR_HXS             (1 << 16)       /* Host Port 2 Transceiver Output Select */
+#define UP2OCR_HXOE            (1 << 17)       /* Host Port 2 Transceiver Output Enable */
+#define UP2OCR_SEOS            (1 << 24)       /* Single-Ended Output Select */
+
 #define UDCCSN(x)      __REG2(0x40600100, (x) << 2)
 #define UDCCSR0         __REG(0x40600100) /* UDC Control/Status register - Endpoint 0 */
 #define UDCCSR0_SA     (1 << 7)        /* Setup Active */
 #define GPIO84_NSSP_RX         (84 | GPIO_ALT_FN_2_IN)
 #define GPIO85_nPCE_1_MD       (85 | GPIO_ALT_FN_1_OUT)
 #define GPIO92_MMCDAT0_MD      (92 | GPIO_ALT_FN_1_OUT)
+#define GPIO104_pSKTSEL_MD     (104 | GPIO_ALT_FN_1_OUT)
 #define GPIO109_MMCDAT1_MD     (109 | GPIO_ALT_FN_1_OUT)
 #define GPIO110_MMCDAT2_MD     (110 | GPIO_ALT_FN_1_OUT)
 #define GPIO110_MMCCS0_MD      (110 | GPIO_ALT_FN_1_OUT)
 #define PSSR_BFS       (1 << 1)        /* Battery Fault Status */
 #define PSSR_SSS       (1 << 0)        /* Software Sleep Status */
 
+#define PSLR_SL_ROD    (1 << 20)       /* Sleep-Mode/Depp-Sleep Mode nRESET_OUT Disable */
+
 #define PCFR_RO                (1 << 15)       /* RDH Override */
 #define PCFR_PO                (1 << 14)       /* PH Override */
 #define PCFR_GPROD     (1 << 12)       /* GPIO nRESET_OUT Disable */
 #define PCFR_FVC       (1 << 10)       /* Frequency/Voltage Change */
 #define PCFR_DC_EN     (1 << 7)        /* Sleep/deep-sleep DC-DC Converter Enable */
 #define PCFR_PI2CEN    (1 << 6)        /* Enable PI2C controller */
+#define PCFR_GPR_EN    (1 << 4)        /* nRESET_GPIO Pin Enable */
 #define PCFR_DS                (1 << 3)        /* Deep Sleep Mode */
 #define PCFR_FS                (1 << 2)        /* Float Static Chip Selects */
 #define PCFR_FP                (1 << 1)        /* Float PCMCIA controls */
 #define LCCR0_PDD_S    12
 #define LCCR0_BM       (1 << 20)       /* Branch mask */
 #define LCCR0_OUM      (1 << 21)       /* Output FIFO underrun mask */
+#define LCCR0_LCDT      (1 << 22)       /* LCD panel type */
+#define LCCR0_RDSTM     (1 << 23)       /* Read status interrupt mask */
+#define LCCR0_CMDIM     (1 << 24)       /* Command interrupt mask */
+#define LCCR0_OUC       (1 << 25)       /* Overlay Underlay control bit */
+#define LCCR0_LDDALT    (1 << 26)       /* LDD alternate mapping control */
 
 #define LCCR1_PPL       Fld (10, 0)      /* Pixels Per Line - 1 */
 #define LCCR1_DisWdth(Pixel)            /* Display Width [1..800 pix.]  */ \
 #define UHCFMN         __REG(0x4C00003C) /* UHC Frame Number */
 #define UHCPERS                __REG(0x4C000040) /* UHC Periodic Start */
 #define UHCLS          __REG(0x4C000044) /* UHC Low Speed Threshold */
+
 #define UHCRHDA                __REG(0x4C000048) /* UHC Root Hub Descriptor A */
+#define UHCRHDA_NOCP   (1 << 12)       /* No over current protection */
+
 #define UHCRHDB                __REG(0x4C00004C) /* UHC Root Hub Descriptor B */
 #define UHCRHS         __REG(0x4C000050) /* UHC Root Hub Status */
 #define UHCRHPS1       __REG(0x4C000054) /* UHC Root Hub Port 1 Status */
diff --git a/include/asm-arm/arch-s3c2410/anubis-cpld.h b/include/asm-arm/arch-s3c2410/anubis-cpld.h
new file mode 100644 (file)
index 0000000..5675b17
--- /dev/null
@@ -0,0 +1,24 @@
+/* linux/include/asm-arm/arch-s3c2410/anubis-cpld.h
+ *
+ * (c) 2005 Simtec Electronics
+ *     http://www.simtec.co.uk/products/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * ANUBIS - CPLD control constants
+ *
+ * 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.
+ *
+ * Changelog:
+ *
+*/
+
+#ifndef __ASM_ARCH_ANUBISCPLD_H
+#define __ASM_ARCH_ANUBISCPLD_H
+
+/* CTRL2 - NAND WP control, IDE Reset assert/check */
+
+#define ANUBIS_CTRL1_NANDSEL           (0x3)
+
+#endif /* __ASM_ARCH_ANUBISCPLD_H */
diff --git a/include/asm-arm/arch-s3c2410/anubis-irq.h b/include/asm-arm/arch-s3c2410/anubis-irq.h
new file mode 100644 (file)
index 0000000..82f15db
--- /dev/null
@@ -0,0 +1,23 @@
+/* linux/include/asm-arm/arch-s3c2410/anubis-irq.h
+ *
+ * (c) 2005 Simtec Electronics
+ *     http://www.simtec.co.uk/products/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ *  ANUBIS - IRQ Number definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Changelog:
+ */
+
+#ifndef __ASM_ARCH_ANUBISIRQ_H
+#define __ASM_ARCH_ANUBISIRQ_H
+
+#define IRQ_IDE0       IRQ_EINT2
+#define IRQ_IDE1       IRQ_EINT3
+#define IRQ_ASIX       IRQ_EINT1
+
+#endif /* __ASM_ARCH_ANUBISIRQ_H */
diff --git a/include/asm-arm/arch-s3c2410/anubis-map.h b/include/asm-arm/arch-s3c2410/anubis-map.h
new file mode 100644 (file)
index 0000000..97741d6
--- /dev/null
@@ -0,0 +1,46 @@
+/* linux/include/asm-arm/arch-s3c2410/anubis-map.h
+ *
+ * (c) 2005 Simtec Electronics
+ *     http://www.simtec.co.uk/products/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * ANUBIS - Memory map definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Changelog:
+*/
+
+/* needs arch/map.h including with this */
+
+#ifndef __ASM_ARCH_ANUBISMAP_H
+#define __ASM_ARCH_ANUBISMAP_H
+
+/* start peripherals off after the S3C2410 */
+
+#define ANUBIS_IOADDR(x)       (S3C2410_ADDR((x) + 0x02000000))
+
+#define ANUBIS_PA_CPLD         (S3C2410_CS1 | (1<<26))
+
+/* we put the CPLD registers next, to get them out of the way */
+
+#define ANUBIS_VA_CTRL1            ANUBIS_IOADDR(0x00000000)    /* 0x01300000 */
+#define ANUBIS_PA_CTRL1            (ANUBIS_PA_CPLD)
+
+#define ANUBIS_VA_CTRL2            ANUBIS_IOADDR(0x00100000)    /* 0x01400000 */
+#define ANUBIS_PA_CTRL2            (ANUBIS_PA_CPLD)
+
+#define ANUBIS_VA_CTRL3            ANUBIS_IOADDR(0x00200000)    /* 0x01500000 */
+#define ANUBIS_PA_CTRL3            (ANUBIS_PA_CPLD)
+
+#define ANUBIS_VA_CTRL4            ANUBIS_IOADDR(0x00300000)    /* 0x01600000 */
+#define ANUBIS_PA_CTRL4            (ANUBIS_PA_CPLD)
+
+#define ANUBIS_IDEPRI      ANUBIS_IOADDR(0x01000000)
+#define ANUBIS_IDEPRIAUX    ANUBIS_IOADDR(0x01100000)
+#define ANUBIS_IDESEC      ANUBIS_IOADDR(0x01200000)
+#define ANUBIS_IDESECAUX    ANUBIS_IOADDR(0x01300000)
+
+#endif /* __ASM_ARCH_ANUBISMAP_H */
index e5e938b79accf555747e88008d86d17a50d056d9..16f4c3cc1388bd70ce8bfe9a93b16d34a5b5dabf 100644 (file)
@@ -1,7 +1,7 @@
 /* linux/include/asm/arch-s3c2410/regs-clock.h
  *
- * Copyright (c) 2003,2004 Simtec Electronics <linux@simtec.co.uk>
- *                   http://www.simtec.co.uk/products/SWLINUX/
+ * Copyright (c) 2003,2004,2005 Simtec Electronics <linux@simtec.co.uk>
+ *                   http://armlinux.simtec.co.uk/
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
  *    29-Sep-2004 Ben Dooks        Fixed usage for assembly inclusion
  *    10-Feb-2005 Ben Dooks        Fixed CAMDIVN address (Guillaume Gourat)
  *    10-Mar-2005 Lucas Villa Real  Changed S3C2410_VA to S3C24XX_VA
+ *    27-Aug-2005 Ben Dooks        Add clock-slow info
  */
 
 #ifndef __ASM_ARM_REGS_CLOCK
 #define S3C2410_CLKDIVN_PDIVN       (1<<0)
 #define S3C2410_CLKDIVN_HDIVN       (1<<1)
 
+#define S3C2410_CLKSLOW_UCLK_OFF       (1<<7)
+#define S3C2410_CLKSLOW_MPLL_OFF       (1<<5)
+#define S3C2410_CLKSLOW_SLOW           (1<<4)
+#define S3C2410_CLKSLOW_SLOWVAL(x)     (x)
+#define S3C2410_CLKSLOW_GET_SLOWVAL(x) ((x) & 7)
+
 #ifndef __ASSEMBLY__
 
 static inline unsigned int
diff --git a/include/asm-arm/arch-sa1100/mcp.h b/include/asm-arm/arch-sa1100/mcp.h
new file mode 100644 (file)
index 0000000..f58a227
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ *  linux/include/asm-arm/arch-sa1100/mcp.h
+ *
+ *  Copyright (C) 2005 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ASM_ARM_ARCH_MCP_H
+#define __ASM_ARM_ARCH_MCP_H
+
+#include <linux/types.h>
+
+struct mcp_plat_data {
+       u32 mccr0;
+       u32 mccr1;
+       unsigned int sclk_rate;
+};
+
+#endif
diff --git a/include/asm-arm/auxvec.h b/include/asm-arm/auxvec.h
new file mode 100644 (file)
index 0000000..c0536f6
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __ASMARM_AUXVEC_H
+#define __ASMARM_AUXVEC_H
+
+#endif
index 485b6bdf4d7a1fde9812d12c6b3b43da53562aa6..a80b6607b2efe35281d476d852e106cd3d6ca31b 100644 (file)
@@ -1,87 +1,11 @@
 #ifndef _ARM_FCNTL_H
 #define _ARM_FCNTL_H
 
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
-   located on an ext2 file system */
-#define O_ACCMODE         0003
-#define O_RDONLY            00
-#define O_WRONLY            01
-#define O_RDWR              02
-#define O_CREAT                   0100 /* not fcntl */
-#define O_EXCL            0200 /* not fcntl */
-#define O_NOCTTY          0400 /* not fcntl */
-#define O_TRUNC                  01000 /* not fcntl */
-#define O_APPEND         02000
-#define O_NONBLOCK       04000
-#define O_NDELAY       O_NONBLOCK
-#define O_SYNC          010000
-#define FASYNC          020000 /* fcntl, for BSD compatibility */
 #define O_DIRECTORY     040000 /* must be a directory */
 #define O_NOFOLLOW     0100000 /* don't follow links */
 #define O_DIRECT       0200000 /* direct disk access hint - currently ignored */
 #define O_LARGEFILE    0400000
-#define O_NOATIME      01000000
 
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
-#define F_GETLK                5
-#define F_SETLK                6
-#define F_SETLKW       7
+#include <asm-generic/fcntl.h>
 
-#define F_SETOWN       8       /*  for sockets. */
-#define F_GETOWN       9       /*  for sockets. */
-#define F_SETSIG       10      /*  for sockets. */
-#define F_GETSIG       11      /*  for sockets. */
-
-#define F_GETLK64      12      /*  using 'struct flock64' */
-#define F_SETLK64      13
-#define F_SETLKW64     14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK                0
-#define F_WRLCK                1
-#define F_UNLCK                2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
-
-struct flock {
-       short l_type;
-       short l_whence;
-       off_t l_start;
-       off_t l_len;
-       pid_t l_pid;
-};
-
-struct flock64 {
-       short  l_type;
-       short  l_whence;
-       loff_t l_start;
-       loff_t l_len;
-       pid_t  l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE  1024
 #endif
diff --git a/include/asm-arm/futex.h b/include/asm-arm/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-arm/hardware/gic.h b/include/asm-arm/hardware/gic.h
new file mode 100644 (file)
index 0000000..3fa5eb7
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *  linux/include/asm-arm/hardware/gic.h
+ *
+ *  Copyright (C) 2002 ARM Limited, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ASM_ARM_HARDWARE_GIC_H
+#define __ASM_ARM_HARDWARE_GIC_H
+
+#include <linux/compiler.h>
+
+#define GIC_CPU_CTRL                   0x00
+#define GIC_CPU_PRIMASK                        0x04
+#define GIC_CPU_BINPOINT               0x08
+#define GIC_CPU_INTACK                 0x0c
+#define GIC_CPU_EOI                    0x10
+#define GIC_CPU_RUNNINGPRI             0x14
+#define GIC_CPU_HIGHPRI                        0x18
+
+#define GIC_DIST_CTRL                  0x000
+#define GIC_DIST_CTR                   0x004
+#define GIC_DIST_ENABLE_SET            0x100
+#define GIC_DIST_ENABLE_CLEAR          0x180
+#define GIC_DIST_PENDING_SET           0x200
+#define GIC_DIST_PENDING_CLEAR         0x280
+#define GIC_DIST_ACTIVE_BIT            0x300
+#define GIC_DIST_PRI                   0x400
+#define GIC_DIST_TARGET                        0x800
+#define GIC_DIST_CONFIG                        0xc00
+#define GIC_DIST_SOFTINT               0xf00
+
+#ifndef __ASSEMBLY__
+void gic_dist_init(void __iomem *base);
+void gic_cpu_init(void __iomem *base);
+void gic_raise_softirq(cpumask_t cpumask, unsigned int irq);
+#endif
+
+#endif
index 7ea771ff61449457677f276baf5c5ce1bbe24521..527404b5a8df4fab7843dc0ab2c8e8372a5cf5ed 100644 (file)
@@ -40,6 +40,19 @@ struct scoop_config {
        unsigned short io_dir;
 };
 
+/* Structure for linking scoop devices to PCMCIA sockets */
+struct scoop_pcmcia_dev {
+       struct device *dev;     /* Pointer to this socket's scoop device */
+       int     irq;                /* irq for socket */
+       int cd_irq;
+       const char *cd_irq_str;
+       unsigned char keep_vs;
+       unsigned char keep_rd;
+};
+
+extern int scoop_num;
+extern struct scoop_pcmcia_dev *scoop_devs;
+
 void reset_scoop(struct device *dev);
 unsigned short set_scoop_gpio(struct device *dev, unsigned short bit);
 unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit);
diff --git a/include/asm-arm/hdreg.h b/include/asm-arm/hdreg.h
deleted file mode 100644 (file)
index 7f7fd1a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/hdreg.h>
index a43a353f6c7bd701c7e6570692ffb575e89e833f..0ce6ca588d8c0b89b43a765d35b294cf0cdad9f4 100644 (file)
@@ -42,11 +42,11 @@ struct irqchip {
        /*
         * Set the type of the IRQ.
         */
-       int (*type)(unsigned int, unsigned int);
+       int (*set_type)(unsigned int, unsigned int);
        /*
         * Set wakeup-enable on the selected IRQ
         */
-       int (*wake)(unsigned int, unsigned int);
+       int (*set_wake)(unsigned int, unsigned int);
 
 #ifdef CONFIG_SMP
        /*
@@ -91,6 +91,14 @@ struct irqdesc {
 
 extern struct irqdesc irq_desc[];
 
+/*
+ * Helpful inline function for calling irq descriptor handlers.
+ */
+static inline void desc_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+{
+       desc->handle(irq, desc, regs);
+}
+
 /*
  * This is internal.  Do not use it.
  */
index 2cf279a4401773e009cb163ecb32ea1cb477ecad..96c6db7dd0e1928e25b96e9b0e87fb64c7f113ce 100644 (file)
@@ -47,9 +47,7 @@ struct sys_timer {
 
 #ifdef CONFIG_NO_IDLE_HZ
 
-#define DYN_TICK_SKIPPING      (1 << 2)
 #define DYN_TICK_ENABLED       (1 << 1)
-#define DYN_TICK_SUITABLE      (1 << 0)
 
 struct dyn_tick_timer {
        unsigned int    state;                  /* Current state */
index 019c45d7573053a9af19088f2df4af8cb4c5e95a..4da1d532cbebd751ecba5ead32ba866ca8f9f7db 100644 (file)
@@ -163,20 +163,6 @@ typedef unsigned long pgprot_t;
 /* the upper-most page table pointer */
 extern pmd_t *top_pmd;
 
-/* Pure 2^n version of get_order */
-static inline int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size-1) >> (PAGE_SHIFT-1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
-
 #include <asm/memory.h>
 
 #endif /* !__ASSEMBLY__ */
@@ -186,4 +172,6 @@ static inline int get_order(unsigned long size)
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/page.h>
+
 #endif
index 46d20585d95143c0bf87fe8ea299fe785cf0922d..3c51da6438c95b6734e38243ebdbb21af5a6972a 100644 (file)
@@ -14,6 +14,8 @@
 #define SO_BROADCAST   6
 #define SO_SNDBUF      7
 #define SO_RCVBUF      8
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
 #define SO_KEEPALIVE   9
 #define SO_OOBINLINE   10
 #define SO_NO_CHECK    11
index f4c92e4c8c0219a31b69f8d59367c105d5767fef..22992ee0627ac3fb5c87bfa4c297184b8bfd1628 100644 (file)
@@ -52,8 +52,6 @@ typedef unsigned long long u64;
 typedef u32 dma_addr_t;
 typedef u32 dma64_addr_t;
 
-typedef unsigned int kmem_bufctl_t;
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index a7c018b8a0d4b88f7da350709a94558dd103d3aa..a2fdad0138b3e5bf2e7e2500e97a8821fe7b036e 100644 (file)
@@ -77,12 +77,6 @@ static inline void set_fs (mm_segment_t fs)
 
 #define access_ok(type,addr,size)      (__range_ok(addr,size) == 0)
 
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated verify_area(int type, const void __user *addr, unsigned long size)
-{
-       return access_ok(type, addr, size) ? 0 : -EFAULT;
-}
-
 /*
  * Single-value transfer routines.  They automatically use the right
  * size if we just have the right pointer type.  Note that the functions
index abb36e54c966b4cbed6c1b8f7fef60a60ab5e81b..278de61224d1c82ca667ebee87f62a536bc06986 100644 (file)
 #define __NR_fstatfs64                 (__NR_SYSCALL_BASE+267)
 #define __NR_tgkill                    (__NR_SYSCALL_BASE+268)
 #define __NR_utimes                    (__NR_SYSCALL_BASE+269)
-#define __NR_fadvise64_64              (__NR_SYSCALL_BASE+270)
+#define __NR_arm_fadvise64_64          (__NR_SYSCALL_BASE+270)
 #define __NR_pciconfig_iobase          (__NR_SYSCALL_BASE+271)
 #define __NR_pciconfig_read            (__NR_SYSCALL_BASE+272)
 #define __NR_pciconfig_write           (__NR_SYSCALL_BASE+273)
@@ -515,7 +515,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6
 #define __ARCH_WANT_SYS_TIME
 #define __ARCH_WANT_SYS_UTIME
 #define __ARCH_WANT_SYS_SOCKETCALL
-#define __ARCH_WANT_SYS_FADVISE64
 #define __ARCH_WANT_SYS_GETPGRP
 #define __ARCH_WANT_SYS_LLSEEK
 #define __ARCH_WANT_SYS_NICE
diff --git a/include/asm-arm26/auxvec.h b/include/asm-arm26/auxvec.h
new file mode 100644 (file)
index 0000000..c0536f6
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __ASMARM_AUXVEC_H
+#define __ASMARM_AUXVEC_H
+
+#endif
index 485b6bdf4d7a1fde9812d12c6b3b43da53562aa6..d85995e7459e4e011bcd3215c5ebe4a970721f9b 100644 (file)
@@ -3,85 +3,11 @@
 
 /* open/fcntl - O_SYNC is only implemented on blocks devices and on files
    located on an ext2 file system */
-#define O_ACCMODE         0003
-#define O_RDONLY            00
-#define O_WRONLY            01
-#define O_RDWR              02
-#define O_CREAT                   0100 /* not fcntl */
-#define O_EXCL            0200 /* not fcntl */
-#define O_NOCTTY          0400 /* not fcntl */
-#define O_TRUNC                  01000 /* not fcntl */
-#define O_APPEND         02000
-#define O_NONBLOCK       04000
-#define O_NDELAY       O_NONBLOCK
-#define O_SYNC          010000
-#define FASYNC          020000 /* fcntl, for BSD compatibility */
 #define O_DIRECTORY     040000 /* must be a directory */
 #define O_NOFOLLOW     0100000 /* don't follow links */
 #define O_DIRECT       0200000 /* direct disk access hint - currently ignored */
 #define O_LARGEFILE    0400000
-#define O_NOATIME      01000000
 
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
-#define F_GETLK                5
-#define F_SETLK                6
-#define F_SETLKW       7
+#include <asm-generic/fcntl.h>
 
-#define F_SETOWN       8       /*  for sockets. */
-#define F_GETOWN       9       /*  for sockets. */
-#define F_SETSIG       10      /*  for sockets. */
-#define F_GETSIG       11      /*  for sockets. */
-
-#define F_GETLK64      12      /*  using 'struct flock64' */
-#define F_SETLK64      13
-#define F_SETLKW64     14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK                0
-#define F_WRLCK                1
-#define F_UNLCK                2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
-
-struct flock {
-       short l_type;
-       short l_whence;
-       off_t l_start;
-       off_t l_len;
-       pid_t l_pid;
-};
-
-struct flock64 {
-       short  l_type;
-       short  l_whence;
-       loff_t l_start;
-       loff_t l_len;
-       pid_t  l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE  1024
 #endif
diff --git a/include/asm-arm26/futex.h b/include/asm-arm26/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-arm26/hdreg.h b/include/asm-arm26/hdreg.h
deleted file mode 100644 (file)
index 7f7fd1a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/hdreg.h>
index c334079b082b267e12998da8151e84f4aa1003ed..d3f23ac4d468fc748c3f366dbd383b2196ace705 100644 (file)
@@ -89,20 +89,6 @@ typedef unsigned long pgprot_t;
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
-/* Pure 2^n version of get_order */
-static inline int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size-1) >> (PAGE_SHIFT-1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
-
 #include <asm/memory.h>
 
 #endif /* !__ASSEMBLY__ */
@@ -112,4 +98,6 @@ static inline int get_order(unsigned long size)
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/page.h>
+
 #endif
index 46d20585d95143c0bf87fe8ea299fe785cf0922d..3c51da6438c95b6734e38243ebdbb21af5a6972a 100644 (file)
@@ -14,6 +14,8 @@
 #define SO_BROADCAST   6
 #define SO_SNDBUF      7
 #define SO_RCVBUF      8
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
 #define SO_KEEPALIVE   9
 #define SO_OOBINLINE   10
 #define SO_NO_CHECK    11
index 56cbe573a2349e8aac93d334def241763a9cd5cb..81bd357ada02b931a04f93c9405e139b64d4cde9 100644 (file)
@@ -52,8 +52,6 @@ typedef unsigned long long u64;
 typedef u32 dma_addr_t;
 typedef u32 dma64_addr_t;
 
-typedef unsigned int kmem_bufctl_t;
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index ab9ce38c6aec994875f9a39ce8bfa63612b8388f..3f2dd1093e58b6a233c20f223043f7efaa8afc13 100644 (file)
@@ -40,12 +40,6 @@ extern int fixup_exception(struct pt_regs *regs);
 
 #define access_ok(type,addr,size)      (__range_ok(addr,size) == 0)
 
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated verify_area(int type, const void * addr, unsigned long size)
-{
-       return access_ok(type, addr, size) ? 0 : -EFAULT;
-}
-
 /*
  * Single-value transfer routines.  They automatically use the right
  * size if we just have the right pointer type.  Note that the functions
diff --git a/include/asm-cris/auxvec.h b/include/asm-cris/auxvec.h
new file mode 100644 (file)
index 0000000..cb30b01
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __ASMCRIS_AUXVEC_H
+#define __ASMCRIS_AUXVEC_H
+
+#endif
index 61c563242b519707f9203e0720d4ce92f583ac60..46ab12db57397dfc44a7aa84f9c10ac5e97509d9 100644 (file)
@@ -1,90 +1 @@
-#ifndef _CRIS_FCNTL_H
-#define _CRIS_FCNTL_H
-
-/* verbatim copy of i386 version */
-
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
-   located on an ext2 file system */
-#define O_ACCMODE         0003
-#define O_RDONLY            00
-#define O_WRONLY            01
-#define O_RDWR              02
-#define O_CREAT                   0100 /* not fcntl */
-#define O_EXCL            0200 /* not fcntl */
-#define O_NOCTTY          0400 /* not fcntl */
-#define O_TRUNC                  01000 /* not fcntl */
-#define O_APPEND         02000
-#define O_NONBLOCK       04000
-#define O_NDELAY       O_NONBLOCK
-#define O_SYNC          010000
-#define FASYNC          020000 /* fcntl, for BSD compatibility */
-#define O_DIRECT        040000 /* direct disk access hint - currently ignored */
-#define O_LARGEFILE    0100000
-#define O_DIRECTORY    0200000 /* must be a directory */
-#define O_NOFOLLOW     0400000 /* don't follow links */
-#define O_NOATIME      01000000
-
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get f_flags */
-#define F_SETFD                2       /* set f_flags */
-#define F_GETFL                3       /* more flags (cloexec) */
-#define F_SETFL                4
-#define F_GETLK                5
-#define F_SETLK                6
-#define F_SETLKW       7
-
-#define F_SETOWN       8       /*  for sockets. */
-#define F_GETOWN       9       /*  for sockets. */
-#define F_SETSIG       10      /*  for sockets. */
-#define F_GETSIG       11      /*  for sockets. */
-
-#define F_GETLK64      12      /*  using 'struct flock64' */
-#define F_SETLK64      13
-#define F_SETLKW64     14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK                0
-#define F_WRLCK                1
-#define F_UNLCK                2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW        192     /* ... Which allows concurrent read & write ops */
-
-struct flock {
-       short l_type;
-       short l_whence;
-       off_t l_start;
-       off_t l_len;
-       pid_t l_pid;
-};
-
-struct flock64 {
-       short  l_type;
-       short  l_whence;
-       loff_t l_start;
-       loff_t l_len;
-       pid_t  l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE  1024
-
-#endif
+#include <asm-generic/fcntl.h>
diff --git a/include/asm-cris/futex.h b/include/asm-cris/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
index 8e787fdaedd41835db69807807278d953b337c34..4fab5c3b2e15ca4ee294346535d14456145c520e 100644 (file)
@@ -1,6 +1,11 @@
 #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>
 
 extern __inline__ int irq_canonicalize(int irq)
index bbf17bd3938523c81e178a5aec94cbfe424a771a..c99c478c482f77d4568206a15952435b11e0d887 100644 (file)
@@ -70,19 +70,6 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 
 #ifndef __ASSEMBLY__
 
-/* Pure 2^n version of get_order */
-static inline int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size-1) >> (PAGE_SHIFT-1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
 #endif /* __ASSEMBLY__ */
 
 #define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
@@ -90,5 +77,7 @@ static inline int get_order(unsigned long size)
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/page.h>
+
 #endif /* _CRIS_PAGE_H */
 
index f159b4f165f74f165671455f8be0cfba48ebc944..8b1da3e58c5580468f60961c498592b71c7f56c7 100644 (file)
@@ -16,6 +16,8 @@
 #define SO_BROADCAST   6
 #define SO_SNDBUF      7
 #define SO_RCVBUF      8
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
 #define SO_KEEPALIVE   9
 #define SO_OOBINLINE   10
 #define SO_NO_CHECK    11
index 8fa6d6c7afce5f19de6c0bac4abbffd0f4bdd646..84557c9bac93e4ef7993eae2c0576644a601719b 100644 (file)
@@ -52,8 +52,6 @@ typedef unsigned long long u64;
 typedef u32 dma_addr_t;
 typedef u32 dma64_addr_t;
 
-typedef unsigned short kmem_bufctl_t;
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index 6db17221fd9e5f412002cc3c9a8d8a2a9f417f8d..7d50086eb5ea08a6de01e4f4f4f7735a2ec4eee0 100644 (file)
 #define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
 #define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
 
-/* this function will go away soon - use access_ok() instead */
-extern inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
-{
-       return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
-
 #include <asm/arch/uaccess.h>
 
 /*
diff --git a/include/asm-frv/auxvec.h b/include/asm-frv/auxvec.h
new file mode 100644 (file)
index 0000000..0771077
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __FRV_AUXVEC_H
+#define __FRV_AUXVEC_H
+
+#endif
index d61b999f9973a2e4a0b4288b007ff8c1f3f64030..46ab12db57397dfc44a7aa84f9c10ac5e97509d9 100644 (file)
@@ -1,88 +1 @@
-#ifndef _ASM_FCNTL_H
-#define _ASM_FCNTL_H
-
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
-   located on an ext2 file system */
-#define O_ACCMODE         0003
-#define O_RDONLY            00
-#define O_WRONLY            01
-#define O_RDWR              02
-#define O_CREAT                   0100 /* not fcntl */
-#define O_EXCL            0200 /* not fcntl */
-#define O_NOCTTY          0400 /* not fcntl */
-#define O_TRUNC                  01000 /* not fcntl */
-#define O_APPEND         02000
-#define O_NONBLOCK       04000
-#define O_NDELAY       O_NONBLOCK
-#define O_SYNC          010000
-#define FASYNC          020000 /* fcntl, for BSD compatibility */
-#define O_DIRECT        040000 /* direct disk access hint */
-#define O_LARGEFILE    0100000
-#define O_DIRECTORY    0200000 /* must be a directory */
-#define O_NOFOLLOW     0400000 /* don't follow links */
-#define O_NOATIME      01000000
-
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
-#define F_GETLK                5
-#define F_SETLK                6
-#define F_SETLKW       7
-
-#define F_SETOWN       8       /*  for sockets. */
-#define F_GETOWN       9       /*  for sockets. */
-#define F_SETSIG       10      /*  for sockets. */
-#define F_GETSIG       11      /*  for sockets. */
-
-#define F_GETLK64      12      /*  using 'struct flock64' */
-#define F_SETLK64      13
-#define F_SETLKW64     14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK                0
-#define F_WRLCK                1
-#define F_UNLCK                2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
-
-struct flock {
-       short l_type;
-       short l_whence;
-       off_t l_start;
-       off_t l_len;
-       pid_t l_pid;
-};
-
-struct flock64 {
-       short  l_type;
-       short  l_whence;
-       loff_t l_start;
-       loff_t l_len;
-       pid_t  l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE  1024
-#endif /* _ASM_FCNTL_H */
-
+#include <asm-generic/fcntl.h>
diff --git a/include/asm-frv/futex.h b/include/asm-frv/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
index f7914f1782b0329b2d70cd6c8d172d1f2282d224..4feba567e7fd7bd47601f3199285ba15e7ed9815 100644 (file)
@@ -45,21 +45,6 @@ typedef struct { unsigned long       pgprot; } pgprot_t;
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)       (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
 
-/* Pure 2^n version of get_order */
-static inline int get_order(unsigned long size) __attribute_const__;
-static inline int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size - 1) >> (PAGE_SHIFT - 1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
-
 #define devmem_is_allowed(pfn) 1
 
 #define __pa(vaddr)            virt_to_phys((void *) vaddr)
@@ -102,4 +87,6 @@ extern unsigned long max_pfn;
 #define WANT_PAGE_VIRTUAL      1
 #endif
 
+#include <asm-generic/page.h>
+
 #endif /* _ASM_PAGE_H */
index c3be17c7de4bbf4cd60b9b2452009b98409ff124..7177f8b9817cc3586bf6c4bd4b21662ed32d2d72 100644 (file)
@@ -14,6 +14,8 @@
 #define SO_BROADCAST   6
 #define SO_SNDBUF      7
 #define SO_RCVBUF      8
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
 #define SO_KEEPALIVE   9
 #define SO_OOBINLINE   10
 #define SO_NO_CHECK    11
index 1a5b6546bb411fe404f22a0af1337e7faa7d0632..50605df6d8acbc024adcba5f4c7aabe1ac57ca14 100644 (file)
@@ -65,8 +65,6 @@ typedef u64 u_quad_t;
 
 typedef u32 dma_addr_t;
 
-typedef unsigned short kmem_bufctl_t;
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index 32dc52e883e54a31344405a48702003762688953..991b50fbba24d77b64c402389f2e93e0c48bb2a8 100644 (file)
@@ -67,12 +67,6 @@ static inline int ___range_ok(unsigned long addr, unsigned long size)
 #define access_ok(type,addr,size) (__range_ok((addr), (size)) == 0)
 #define __access_ok(addr,size) (__range_ok((addr), (size)) == 0)
 
-/* this function will go away soon - use access_ok() / __range_ok() instead */
-static inline int __deprecated verify_area(int type, const void * addr, unsigned long size)
-{
-       return __range_ok(addr, size);
-}
-
 /*
  * The exception table consists of pairs of addresses: the first is the
  * address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-generic/fcntl.h b/include/asm-generic/fcntl.h
new file mode 100644 (file)
index 0000000..b663520
--- /dev/null
@@ -0,0 +1,149 @@
+#ifndef _ASM_GENERIC_FCNTL_H
+#define _ASM_GENERIC_FCNTL_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+
+/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
+   located on an ext2 file system */
+#define O_ACCMODE      00000003
+#define O_RDONLY       00000000
+#define O_WRONLY       00000001
+#define O_RDWR         00000002
+#ifndef O_CREAT
+#define O_CREAT                00000100        /* not fcntl */
+#endif
+#ifndef O_EXCL
+#define O_EXCL         00000200        /* not fcntl */
+#endif
+#ifndef O_NOCTTY
+#define O_NOCTTY       00000400        /* not fcntl */
+#endif
+#ifndef O_TRUNC
+#define O_TRUNC                00001000        /* not fcntl */
+#endif
+#ifndef O_APPEND
+#define O_APPEND       00002000
+#endif
+#ifndef O_NONBLOCK
+#define O_NONBLOCK     00004000
+#endif
+#ifndef O_SYNC
+#define O_SYNC         00010000
+#endif
+#ifndef FASYNC
+#define FASYNC         00020000        /* fcntl, for BSD compatibility */
+#endif
+#ifndef O_DIRECT
+#define O_DIRECT       00040000        /* direct disk access hint */
+#endif
+#ifndef O_LARGEFILE
+#define O_LARGEFILE    00100000
+#endif
+#ifndef O_DIRECTORY
+#define O_DIRECTORY    00200000        /* must be a directory */
+#endif
+#ifndef O_NOFOLLOW
+#define O_NOFOLLOW     00400000        /* don't follow links */
+#endif
+#ifndef O_NOATIME
+#define O_NOATIME      01000000
+#endif
+#ifndef O_NDELAY
+#define O_NDELAY       O_NONBLOCK
+#endif
+
+#define F_DUPFD                0       /* dup */
+#define F_GETFD                1       /* get close_on_exec */
+#define F_SETFD                2       /* set/clear close_on_exec */
+#define F_GETFL                3       /* get file->f_flags */
+#define F_SETFL                4       /* set file->f_flags */
+#ifndef F_GETLK
+#define F_GETLK                5
+#define F_SETLK                6
+#define F_SETLKW       7
+#endif
+#ifndef F_SETOWN
+#define F_SETOWN       8       /* for sockets. */
+#define F_GETOWN       9       /* for sockets. */
+#endif
+#ifndef F_SETSIG
+#define F_SETSIG       10      /* for sockets. */
+#define F_GETSIG       11      /* for sockets. */
+#endif
+
+/* for F_[GET|SET]FL */
+#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
+
+/* for posix fcntl() and lockf() */
+#ifndef F_RDLCK
+#define F_RDLCK                0
+#define F_WRLCK                1
+#define F_UNLCK                2
+#endif
+
+/* for old implementation of bsd flock () */
+#ifndef F_EXLCK
+#define F_EXLCK                4       /* or 3 */
+#define F_SHLCK                8       /* or 4 */
+#endif
+
+/* for leases */
+#ifndef F_INPROGRESS
+#define F_INPROGRESS   16
+#endif
+
+/* operations for bsd flock(), also used by the kernel implementation */
+#define LOCK_SH                1       /* shared lock */
+#define LOCK_EX                2       /* exclusive lock */
+#define LOCK_NB                4       /* or'd with one of the above to prevent
+                                  blocking */
+#define LOCK_UN                8       /* remove lock */
+
+#define LOCK_MAND      32      /* This is a mandatory flock ... */
+#define LOCK_READ      64      /* which allows concurrent read operations */
+#define LOCK_WRITE     128     /* which allows concurrent write operations */
+#define LOCK_RW                192     /* which allows concurrent read & write ops */
+
+#define F_LINUX_SPECIFIC_BASE  1024
+
+#ifndef HAVE_ARCH_STRUCT_FLOCK
+#ifndef __ARCH_FLOCK_PAD
+#define __ARCH_FLOCK_PAD
+#endif
+
+struct flock {
+       short   l_type;
+       short   l_whence;
+       off_t   l_start;
+       off_t   l_len;
+       pid_t   l_pid;
+       __ARCH_FLOCK_PAD
+};
+#endif
+
+#ifndef CONFIG_64BIT
+
+#ifndef F_GETLK64
+#define F_GETLK64      12      /*  using 'struct flock64' */
+#define F_SETLK64      13
+#define F_SETLKW64     14
+#endif
+
+#ifndef HAVE_ARCH_STRUCT_FLOCK64
+#ifndef __ARCH_FLOCK64_PAD
+#define __ARCH_FLOCK64_PAD
+#endif
+
+struct flock64 {
+       short  l_type;
+       short  l_whence;
+       loff_t l_start;
+       loff_t l_len;
+       pid_t  l_pid;
+       __ARCH_FLOCK64_PAD
+};
+#endif
+#endif /* !CONFIG_64BIT */
+
+#endif /* _ASM_GENERIC_FCNTL_H */
diff --git a/include/asm-generic/hdreg.h b/include/asm-generic/hdreg.h
deleted file mode 100644 (file)
index 7051fba..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#warning <asm/hdreg.h> is obsolete, please do not use it
-
-#ifndef __ASM_GENERIC_HDREG_H
-#define __ASM_GENERIC_HDREG_H
-
-typedef unsigned long ide_ioreg_t;
-
-#endif /* __ASM_GENERIC_HDREG_H */
diff --git a/include/asm-generic/page.h b/include/asm-generic/page.h
new file mode 100644 (file)
index 0000000..a96b5d9
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef _ASM_GENERIC_PAGE_H
+#define _ASM_GENERIC_PAGE_H
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+#include <linux/compiler.h>
+
+/* Pure 2^n version of get_order */
+static __inline__ __attribute_const__ int get_order(unsigned long size)
+{
+       int order;
+
+       size = (size - 1) >> (PAGE_SHIFT - 1);
+       order = -1;
+       do {
+               size >>= 1;
+               order++;
+       } while (size);
+       return order;
+}
+
+#endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_GENERIC_PAGE_H */
index f40593565173939c5755adda6bee419d90a24635..f86c1e549466a0809c02fecc750cb5627ed08027 100644 (file)
@@ -101,6 +101,22 @@ do {                                                                         \
 })
 #endif
 
+#ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
+#define ptep_get_and_clear_full(__mm, __address, __ptep, __full)       \
+({                                                                     \
+       pte_t __pte;                                                    \
+       __pte = ptep_get_and_clear((__mm), (__address), (__ptep));      \
+       __pte;                                                          \
+})
+#endif
+
+#ifndef __HAVE_ARCH_PTE_CLEAR_FULL
+#define pte_clear_full(__mm, __address, __ptep, __full)                        \
+do {                                                                   \
+       pte_clear((__mm), (__address), (__ptep));                       \
+} while (0)
+#endif
+
 #ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH
 #define ptep_clear_flush(__vma, __address, __ptep)                     \
 ({                                                                     \
index 450eae22c39a3e2a517dea059a7e3b01bb7ce6d6..886dbd11689991396238d2cc6bdf9f09374762ff 100644 (file)
@@ -12,5 +12,6 @@ extern char _sextratext[] __attribute__((weak));
 extern char _eextratext[] __attribute__((weak));
 extern char _end[];
 extern char __per_cpu_start[], __per_cpu_end[];
+extern char __kprobes_text_start[], __kprobes_text_end[];
 
 #endif /* _ASM_GENERIC_SECTIONS_H_ */
index 6c90f0f36eec9990dc9f00f87454215c2acfe9c4..4dc8ddb401c15828797b4a7e21586e4b6d3e3418 100644 (file)
@@ -16,9 +16,9 @@
  * The main single-value unaligned transfer routines.
  */
 #define get_unaligned(ptr) \
-       ((__typeof__(*(ptr)))__get_unaligned((ptr), sizeof(*(ptr))))
+       __get_unaligned((ptr), sizeof(*(ptr)))
 #define put_unaligned(x,ptr) \
-       __put_unaligned((unsigned long)(x), (ptr), sizeof(*(ptr)))
+       __put_unaligned((__u64)(x), (ptr), sizeof(*(ptr)))
 
 /*
  * This function doesn't actually exist.  The idea is that when
@@ -36,19 +36,19 @@ struct __una_u16 { __u16 x __attribute__((packed)); };
  * Elemental unaligned loads 
  */
 
-static inline unsigned long __uldq(const __u64 *addr)
+static inline __u64 __uldq(const __u64 *addr)
 {
        const struct __una_u64 *ptr = (const struct __una_u64 *) addr;
        return ptr->x;
 }
 
-static inline unsigned long __uldl(const __u32 *addr)
+static inline __u32 __uldl(const __u32 *addr)
 {
        const struct __una_u32 *ptr = (const struct __una_u32 *) addr;
        return ptr->x;
 }
 
-static inline unsigned long __uldw(const __u16 *addr)
+static inline __u16 __uldw(const __u16 *addr)
 {
        const struct __una_u16 *ptr = (const struct __una_u16 *) addr;
        return ptr->x;
@@ -78,7 +78,7 @@ static inline void __ustw(__u16 val, __u16 *addr)
 
 #define __get_unaligned(ptr, size) ({          \
        const void *__gu_p = ptr;               \
-       unsigned long val;                      \
+       __typeof__(*(ptr)) val;                 \
        switch (size) {                         \
        case 1:                                 \
                val = *(const __u8 *)__gu_p;    \
index b3bb326ae5b618a74cc3ca79d158f6d8b92c5743..6f857be2b6447ac3f64f134ce45844ef2555b11b 100644 (file)
@@ -6,6 +6,9 @@
 #define VMLINUX_SYMBOL(_sym_) _sym_
 #endif
 
+/* Align . to a 8 byte boundary equals to maximum function alignment. */
+#define ALIGN_FUNCTION()  . = ALIGN(8)
+
 #define RODATA                                                         \
        .rodata           : AT(ADDR(.rodata) - LOAD_OFFSET) {           \
                *(.rodata) *(.rodata.*)                                 \
                VMLINUX_SYMBOL(__security_initcall_end) = .;            \
        }
 
+/* sched.text is aling to function alignment to secure we have same
+ * address even at second ld pass when generating System.map */
 #define SCHED_TEXT                                                     \
+               ALIGN_FUNCTION();                                       \
                VMLINUX_SYMBOL(__sched_text_start) = .;                 \
                *(.sched.text)                                          \
                VMLINUX_SYMBOL(__sched_text_end) = .;
 
+/* spinlock.text is aling to function alignment to secure we have same
+ * address even at second ld pass when generating System.map */
 #define LOCK_TEXT                                                      \
+               ALIGN_FUNCTION();                                       \
                VMLINUX_SYMBOL(__lock_text_start) = .;                  \
                *(.spinlock.text)                                       \
                VMLINUX_SYMBOL(__lock_text_end) = .;
+
+#define KPROBES_TEXT                                                   \
+               ALIGN_FUNCTION();                                       \
+               VMLINUX_SYMBOL(__kprobes_text_start) = .;               \
+               *(.kprobes.text)                                        \
+               VMLINUX_SYMBOL(__kprobes_text_end) = .;
diff --git a/include/asm-h8300/auxvec.h b/include/asm-h8300/auxvec.h
new file mode 100644 (file)
index 0000000..1d36fe3
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __ASMH8300_AUXVEC_H
+#define __ASMH8300_AUXVEC_H
+
+#endif
index 355350a57bf97b6ef1d054375a2b2395c6a3b973..1952cb2e3b06e406f865cba82eb64fb790628804 100644 (file)
@@ -1,87 +1,11 @@
 #ifndef _H8300_FCNTL_H
 #define _H8300_FCNTL_H
 
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
-   located on an ext2 file system */
-#define O_ACCMODE        0003
-#define O_RDONLY           00
-#define O_WRONLY           01
-#define O_RDWR             02
-#define O_CREAT                  0100  /* not fcntl */
-#define O_EXCL           0200  /* not fcntl */
-#define O_NOCTTY         0400  /* not fcntl */
-#define O_TRUNC                 01000  /* not fcntl */
-#define O_APPEND        02000
-#define O_NONBLOCK      04000
-#define O_NDELAY       O_NONBLOCK
-#define O_SYNC         010000
-#define FASYNC         020000  /* fcntl, for BSD compatibility */
 #define O_DIRECTORY    040000  /* must be a directory */
 #define O_NOFOLLOW     0100000 /* don't follow links */
 #define O_DIRECT       0200000 /* direct disk access hint - currently ignored */
 #define O_LARGEFILE    0400000
-#define O_NOATIME      01000000
 
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
-#define F_GETLK                5
-#define F_SETLK                6
-#define F_SETLKW       7
+#include <asm-generic/fcntl.h>
 
-#define F_SETOWN       8       /*  for sockets. */
-#define F_GETOWN       9       /*  for sockets. */
-#define F_SETSIG       10      /*  for sockets. */
-#define F_GETSIG       11      /*  for sockets. */
-
-#define F_GETLK64      12      /*  using 'struct flock64' */
-#define F_SETLK64      13
-#define F_SETLKW64     14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK                0
-#define F_WRLCK                1
-#define F_UNLCK                2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
-
-struct flock {
-       short l_type;
-       short l_whence;
-       off_t l_start;
-       off_t l_len;
-       pid_t l_pid;
-};
-
-struct flock64 {
-       short  l_type;
-       short  l_whence;
-       loff_t l_start;
-       loff_t l_len;
-       pid_t  l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE  1024
 #endif /* _H8300_FCNTL_H */
diff --git a/include/asm-h8300/futex.h b/include/asm-h8300/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-h8300/hdreg.h b/include/asm-h8300/hdreg.h
deleted file mode 100644 (file)
index 36d0c06..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/include/asm-h8300/hdreg.h
- *
- *  Copyright (C) 1994-1996  Linus Torvalds & authors
- */
-
-#warning this file is obsolete, please do not use it
-
-#ifndef _H8300_HDREG_H
-#define _H8300_HDREG_H
-
-typedef unsigned int   q40ide_ioreg_t;
-typedef unsigned char * ide_ioreg_t;
-
-#endif /* _H8300_HDREG_H */
index e3b7960d445bcbb02cdf5901d429d99d9bcfd25d..e8c02b8c2d99bb2d138ca200008bf5467d105fd1 100644 (file)
@@ -54,20 +54,6 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)       (((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size-1) >> (PAGE_SHIFT-1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
-
 extern unsigned long memory_start;
 extern unsigned long memory_end;
 
@@ -101,4 +87,6 @@ extern unsigned long memory_end;
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/page.h>
+
 #endif /* _H8300_PAGE_H */
index af33b8525dcf4596ce889a9e5e25519dca44c36a..d98cf85bafc1d667d9d2ebdac62752a7da267214 100644 (file)
@@ -14,6 +14,8 @@
 #define SO_BROADCAST   6
 #define SO_SNDBUF      7
 #define SO_RCVBUF      8
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
 #define SO_KEEPALIVE   9
 #define SO_OOBINLINE   10
 #define SO_NO_CHECK    11
index 21f4fc07ac0e45ae6fa9c07ce671887fdaf52eb6..bf91e0d4dde77775a46650f29f107096c2914147 100644 (file)
@@ -58,8 +58,6 @@ typedef u32 dma_addr_t;
 #define HAVE_SECTOR_T
 typedef u64 sector_t;
 
-typedef unsigned int kmem_bufctl_t;
-
 #endif /* __KERNEL__ */
 
 #endif /* __ASSEMBLY__ */
index 1480f307a4749f69e1199da2c03c1b41410084d4..ebe58c6c83878396ada351e1f142b55a159c899a 100644 (file)
@@ -24,12 +24,6 @@ static inline int __access_ok(unsigned long addr, unsigned long size)
        return(RANGE_CHECK_OK(addr, size, 0L, (unsigned long)&_ramend));
 }
 
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated verify_area(int type, const void *addr, unsigned long size)
-{
-       return access_ok(type,addr,size)?0:-EFAULT;
-}
-
 /*
  * The exception table consists of pairs of addresses: the first is the
  * address of an instruction that is allowed to fault, and the second is
index b82f5f3ab887b4307fa2e248c2122bdfe8d32bfc..9075083bab76bd2ed3cd26daaaaa63887dbf5255 100644 (file)
@@ -19,7 +19,7 @@ int unmap_page_from_agp(struct page *page);
 /* Could use CLFLUSH here if the cpu supports it. But then it would
    need to be called for each cacheline of the whole page so it may not be 
    worth it. Would need a page for it. */
-#define flush_agp_cache() asm volatile("wbinvd":::"memory")
+#define flush_agp_cache() wbinvd()
 
 /* Convert a physical address to an address suitable for the GART. */
 #define phys_to_gart(x) (x)
index a96a8f48fbfcea171f9a65a22cc0f1b2a022649d..03185cef8e0a3977de51cb2467943d59f31dabd6 100644 (file)
@@ -16,6 +16,7 @@
 #define                        GET_APIC_VERSION(x)     ((x)&0xFF)
 #define                        GET_APIC_MAXLVT(x)      (((x)>>16)&0xFF)
 #define                        APIC_INTEGRATED(x)      ((x)&0xF0)
+#define                        APIC_XAPIC(x)           ((x) >= 0x14)
 #define                APIC_TASKPRI    0x80
 #define                        APIC_TPRI_MASK          0xFF
 #define                APIC_ARBPRI     0x90
diff --git a/include/asm-i386/auxvec.h b/include/asm-i386/auxvec.h
new file mode 100644 (file)
index 0000000..395e130
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __ASMi386_AUXVEC_H
+#define __ASMi386_AUXVEC_H
+
+/*
+ * Architecture-neutral AT_ values in 0-17, leave some room
+ * for more of them, start the x86-specific ones at 32.
+ */
+#define AT_SYSINFO             32
+#define AT_SYSINFO_EHDR                33
+
+#endif
index 6789fc275da36cc3f5da7da3efc03609662f7bdb..ea54540638d211f2bb99fc4693e603a664b48dad 100644 (file)
@@ -118,7 +118,10 @@ static void __init check_hlt(void)
                printk("disabled\n");
                return;
        }
-       __asm__ __volatile__("hlt ; hlt ; hlt ; hlt");
+       halt();
+       halt();
+       halt();
+       halt();
        printk("OK.\n");
 }
 
index f949e44c2a35d290655258c83cf3f0f5731e7e20..67d3630c4e8953c74773ce17aaf1bf2c197c1930 100644 (file)
@@ -83,7 +83,7 @@ static inline unsigned short ip_fast_csum(unsigned char * iph,
            "adcl $0, %0        ;\n"
            "notl %0            ;\n"
 "2:                            ;\n"
-       /* Since the input registers which are loaded with iph and ipl
+       /* Since the input registers which are loaded with iph and ihl
           are modified, we must also specify them as outputs, or gcc
           will assume they contain their original values. */
        : "=r" (sum), "=r" (iph), "=r" (ihl)
index 11e67811a9901b5c6b31ef361dfb6d03667c3ca3..6df1a53c190e48716c46e1c4deabdd5020930950 100644 (file)
@@ -27,8 +27,18 @@ struct Xgt_desc_struct {
 
 extern struct Xgt_desc_struct idt_descr, cpu_gdt_descr[NR_CPUS];
 
-#define load_TR_desc() __asm__ __volatile__("ltr %%ax"::"a" (GDT_ENTRY_TSS*8))
-#define load_LDT_desc() __asm__ __volatile__("lldt %%ax"::"a" (GDT_ENTRY_LDT*8))
+#define load_TR_desc() __asm__ __volatile__("ltr %w0"::"q" (GDT_ENTRY_TSS*8))
+#define load_LDT_desc() __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8))
+
+#define load_gdt(dtr) __asm__ __volatile("lgdt %0"::"m" (*dtr))
+#define load_idt(dtr) __asm__ __volatile("lidt %0"::"m" (*dtr))
+#define load_tr(tr) __asm__ __volatile("ltr %0"::"mr" (tr))
+#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"mr" (ldt))
+
+#define store_gdt(dtr) __asm__ ("sgdt %0":"=m" (*dtr))
+#define store_idt(dtr) __asm__ ("sidt %0":"=m" (*dtr))
+#define store_tr(tr) __asm__ ("str %0":"=mr" (tr))
+#define store_ldt(ldt) __asm__ ("sldt %0":"=mr" (ldt))
 
 /*
  * This is the ldt that every process will get unless we need
@@ -39,14 +49,14 @@ extern void set_intr_gate(unsigned int irq, void * addr);
 
 #define _set_tssldt_desc(n,addr,limit,type) \
 __asm__ __volatile__ ("movw %w3,0(%2)\n\t" \
-       "movw %%ax,2(%2)\n\t" \
-       "rorl $16,%%eax\n\t" \
-       "movb %%al,4(%2)\n\t" \
+       "movw %w1,2(%2)\n\t" \
+       "rorl $16,%1\n\t" \
+       "movb %b1,4(%2)\n\t" \
        "movb %4,5(%2)\n\t" \
        "movb $0,6(%2)\n\t" \
-       "movb %%ah,7(%2)\n\t" \
-       "rorl $16,%%eax" \
-       : "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type))
+       "movb %h1,7(%2)\n\t" \
+       "rorl $16,%1" \
+       : "=m"(*(n)) : "q" (addr), "r"(n), "ir"(limit), "i"(type))
 
 static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, void *addr)
 {
@@ -86,6 +96,13 @@ static inline void set_ldt_desc(unsigned int cpu, void *addr, unsigned int size)
        (info)->seg_not_present == 1    && \
        (info)->useable         == 0    )
 
+static inline void write_ldt_entry(void *ldt, int entry, __u32 entry_a, __u32 entry_b)
+{
+       __u32 *lp = (__u32 *)((char *)ldt + entry*8);
+       *lp = entry_a;
+       *(lp+1) = entry_b;
+}
+
 #if TLS_SIZE != 24
 # error update this code.
 #endif
index 130bdc8c68cfd381f3ed731de5d4d9e9a4b31a2e..fa11117d3cfac32de2b2e6b3694c8d65f56b5ac5 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm/user.h>
 #include <asm/processor.h>
 #include <asm/system.h>                /* for savesegment */
+#include <asm/auxvec.h>
 
 #include <linux/utsname.h>
 
@@ -109,13 +110,6 @@ typedef struct user_fxsr_struct elf_fpxregset_t;
 
 #define ELF_PLATFORM  (system_utsname.machine)
 
-/*
- * Architecture-neutral AT_ values in 0-17, leave some room
- * for more of them, start the x86-specific ones at 32.
- */
-#define AT_SYSINFO             32
-#define AT_SYSINFO_EHDR                33
-
 #ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2) do { } while (0)
 
index 511cde94a3ed0fe230cd71d8214617113130121b..46ab12db57397dfc44a7aa84f9c10ac5e97509d9 100644 (file)
@@ -1,88 +1 @@
-#ifndef _I386_FCNTL_H
-#define _I386_FCNTL_H
-
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
-   located on an ext2 file system */
-#define O_ACCMODE         0003
-#define O_RDONLY            00
-#define O_WRONLY            01
-#define O_RDWR              02
-#define O_CREAT                   0100 /* not fcntl */
-#define O_EXCL            0200 /* not fcntl */
-#define O_NOCTTY          0400 /* not fcntl */
-#define O_TRUNC                  01000 /* not fcntl */
-#define O_APPEND         02000
-#define O_NONBLOCK       04000
-#define O_NDELAY       O_NONBLOCK
-#define O_SYNC          010000
-#define FASYNC          020000 /* fcntl, for BSD compatibility */
-#define O_DIRECT        040000 /* direct disk access hint */
-#define O_LARGEFILE    0100000
-#define O_DIRECTORY    0200000 /* must be a directory */
-#define O_NOFOLLOW     0400000 /* don't follow links */
-#define O_NOATIME      01000000
-
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
-#define F_GETLK                5
-#define F_SETLK                6
-#define F_SETLKW       7
-
-#define F_SETOWN       8       /*  for sockets. */
-#define F_GETOWN       9       /*  for sockets. */
-#define F_SETSIG       10      /*  for sockets. */
-#define F_GETSIG       11      /*  for sockets. */
-
-#define F_GETLK64      12      /*  using 'struct flock64' */
-#define F_SETLK64      13
-#define F_SETLKW64     14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK                0
-#define F_WRLCK                1
-#define F_UNLCK                2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
-
-struct flock {
-       short l_type;
-       short l_whence;
-       off_t l_start;
-       off_t l_len;
-       pid_t l_pid;
-};
-
-struct flock64 {
-       short  l_type;
-       short  l_whence;
-       loff_t l_start;
-       loff_t l_len;
-       pid_t  l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE  1024
-
-#endif
+#include <asm-generic/fcntl.h>
diff --git a/include/asm-i386/futex.h b/include/asm-i386/futex.h
new file mode 100644 (file)
index 0000000..44b9db8
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+
+#define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg) \
+  __asm__ __volatile (                                         \
+"1:    " insn "\n"                                             \
+"2:    .section .fixup,\"ax\"\n\
+3:     mov     %3, %1\n\
+       jmp     2b\n\
+       .previous\n\
+       .section __ex_table,\"a\"\n\
+       .align  8\n\
+       .long   1b,3b\n\
+       .previous"                                              \
+       : "=r" (oldval), "=r" (ret), "=m" (*uaddr)              \
+       : "i" (-EFAULT), "m" (*uaddr), "0" (oparg), "1" (0))
+
+#define __futex_atomic_op2(insn, ret, oldval, uaddr, oparg) \
+  __asm__ __volatile (                                         \
+"1:    movl    %2, %0\n\
+       movl    %0, %3\n"                                       \
+       insn "\n"                                               \
+"2:    " LOCK_PREFIX "cmpxchgl %3, %2\n\
+       jnz     1b\n\
+3:     .section .fixup,\"ax\"\n\
+4:     mov     %5, %1\n\
+       jmp     3b\n\
+       .previous\n\
+       .section __ex_table,\"a\"\n\
+       .align  8\n\
+       .long   1b,4b,2b,4b\n\
+       .previous"                                              \
+       : "=&a" (oldval), "=&r" (ret), "=m" (*uaddr),           \
+         "=&r" (tem)                                           \
+       : "r" (oparg), "i" (-EFAULT), "m" (*uaddr), "1" (0))
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       if (op == FUTEX_OP_SET)
+               __futex_atomic_op1("xchgl %0, %2", ret, oldval, uaddr, oparg);
+       else {
+#ifndef CONFIG_X86_BSWAP
+               if (boot_cpu_data.x86 == 3)
+                       ret = -ENOSYS;
+               else
+#endif
+               switch (op) {
+               case FUTEX_OP_ADD:
+                       __futex_atomic_op1(LOCK_PREFIX "xaddl %0, %2", ret,
+                                          oldval, uaddr, oparg);
+                       break;
+               case FUTEX_OP_OR:
+                       __futex_atomic_op2("orl %4, %3", ret, oldval, uaddr,
+                                          oparg);
+                       break;
+               case FUTEX_OP_ANDN:
+                       __futex_atomic_op2("andl %4, %3", ret, oldval, uaddr,
+                                          ~oparg);
+                       break;
+               case FUTEX_OP_XOR:
+                       __futex_atomic_op2("xorl %4, %3", ret, oldval, uaddr,
+                                          oparg);
+                       break;
+               default:
+                       ret = -ENOSYS;
+               }
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-i386/hdreg.h b/include/asm-i386/hdreg.h
deleted file mode 100644 (file)
index 5989bbc..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#warning this file is obsolete, please do not use it
index b3f8d5f59d5d8fc02cc1c5f88bce01921c641496..316138e89910743f3a1b265ca4f04741bdffdc98 100644 (file)
@@ -41,9 +41,16 @@ enum die_val {
        DIE_PAGE_FAULT,
 };
 
-static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,long err,int trap, int sig)
+static inline int notify_die(enum die_val val, const char *str,
+                       struct pt_regs *regs, long err, int trap, int sig)
 {
-       struct die_args args = { .regs=regs, .str=str, .err=err, .trapnr=trap,.signr=sig };
+       struct die_args args = {
+               .regs = regs,
+               .str = str,
+               .err = err,
+               .trapnr = trap,
+               .signr = sig
+       };
        return notifier_call_chain(&i386die_chain, val, &args);
 }
 
index 85809e0898d7d3cf93f9ae414cd091bc5097f5e8..28a84f6185a789834bdf753dc4e17e1bba8636c8 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __ASM_MACH_MPPARSE_H
 #define __ASM_MACH_MPPARSE_H
 
+#include <linux/acpi.h>
+
 static inline void mpc_oem_bus_info(struct mpc_config_bus *m, char *name, 
                                struct mpc_config_translation *translation)
 {
@@ -12,8 +14,9 @@ static inline void mpc_oem_pci_bus(struct mpc_config_bus *m,
 {
 }
 
-extern int parse_unisys_oem (char *oemptr, int oem_entries);
-extern int find_unisys_acpi_oem_table(unsigned long *oem_addr, int *length);
+extern int parse_unisys_oem (char *oemptr);
+extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
+extern void setup_unisys();
 
 static inline int mps_oem_check(struct mp_config_table *mpc, char *oem,
                char *productid)
@@ -22,18 +25,33 @@ static inline int mps_oem_check(struct mp_config_table *mpc, char *oem,
                struct mp_config_oemtable *oem_table = 
                        (struct mp_config_oemtable *)mpc->mpc_oemptr;
                if (!strncmp(oem, "UNISYS", 6))
-                       return parse_unisys_oem((char *)oem_table, oem_table->oem_length);
+                       return parse_unisys_oem((char *)oem_table);
        }
        return 0;
 }
 
+static inline int es7000_check_dsdt()
+{
+       struct acpi_table_header *header = NULL;
+       if(!acpi_get_table_header_early(ACPI_DSDT, &header))
+               acpi_table_print(header, 0);
+       if (!strncmp(header->oem_id, "UNISYS", 6))
+               return 1;
+       return 0;
+}
+
 /* Hook from generic ACPI tables.c */
 static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 {
        unsigned long oem_addr; 
-       int oem_entries;
-       if (!find_unisys_acpi_oem_table(&oem_addr, &oem_entries))
-               return parse_unisys_oem((char *)oem_addr, oem_entries);
+       if (!find_unisys_acpi_oem_table(&oem_addr)) {
+               if (es7000_check_dsdt())
+                       return parse_unisys_oem((char *)oem_addr);
+               else {
+                       setup_unisys();
+                       return 1;
+               }
+       }
        return 0;
 }
 
index b13767a4e9345211eaa68a5c1439ee59f82e6cdc..d9dc039da94a3a12b4902d477bb48c0e6d8f205e 100644 (file)
@@ -28,4 +28,6 @@
 #define enable_apic_mode (genapic->enable_apic_mode)
 #define phys_pkg_id (genapic->phys_pkg_id)
 
+extern void generic_bigsmp_probe(void);
+
 #endif /* __ASM_MACH_APIC_H */
index d9fafba075bc41852dfeccb90d32a24182da41a5..d84a9c326c2238e70cdc3159d18dd864a481fd01 100644 (file)
@@ -11,6 +11,7 @@ extern int mp_bus_id_to_local [MAX_MP_BUSSES];
 extern int quad_local_to_mp_bus_id [NR_CPUS/4][4];
 extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
 
+extern unsigned int def_to_bigsmp;
 extern unsigned int boot_cpu_physical_apicid;
 extern int smp_found_config;
 extern void find_smp_config (void);
index c76fce8badbbb32333691d293b4c1b172b7f3e58..62b76cd96957da8ddfca0a0d1a1508b373be8ab5 100644 (file)
@@ -47,6 +47,21 @@ static inline void wrmsrl (unsigned long msr, unsigned long long val)
                     : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT));\
        ret__; })
 
+/* rdmsr with exception handling */
+#define rdmsr_safe(msr,a,b) ({ int ret__;                                              \
+       asm volatile("2: rdmsr ; xorl %0,%0\n"                                          \
+                    "1:\n\t"                                                           \
+                    ".section .fixup,\"ax\"\n\t"                                       \
+                    "3:  movl %4,%0 ; jmp 1b\n\t"                                      \
+                    ".previous\n\t"                                                    \
+                    ".section __ex_table,\"a\"\n"                                      \
+                    "   .align 4\n\t"                                                  \
+                    "   .long  2b,3b\n\t"                                              \
+                    ".previous"                                                        \
+                    : "=r" (ret__), "=a" (*(a)), "=d" (*(b))                           \
+                    : "c" (msr), "i" (-EFAULT));\
+       ret__; })
+
 #define rdtsc(low,high) \
      __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
 
index 8d93f732d72d0586dc1598542ffa354893351808..73296d9924fb36ac196937e2d9d63e32f978aa2c 100644 (file)
@@ -68,7 +68,6 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 #define HPAGE_MASK     (~(HPAGE_SIZE - 1))
 #define HUGETLB_PAGE_ORDER     (HPAGE_SHIFT - PAGE_SHIFT)
 #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
-#define ARCH_HAS_HUGETLB_CLEAN_STALE_PGTABLE
 #endif
 
 #define pgd_val(x)     ((x).pgd)
@@ -104,20 +103,6 @@ typedef struct { unsigned long pgprot; } pgprot_t;
  */
 extern unsigned int __VMALLOC_RESERVE;
 
-/* Pure 2^n version of get_order */
-static __inline__ int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size-1) >> (PAGE_SHIFT-1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
-
 extern int sysctl_legacy_va_layout;
 
 extern int page_is_ram(unsigned long pagenr);
@@ -156,4 +141,6 @@ extern int page_is_ram(unsigned long pagenr);
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/page.h>
+
 #endif /* _I386_PAGE_H */
index d609f9c2c1f0324a790df9eef00a30ce53254c79..2e3f4a344a2d61e001f82131592830c3e967d547 100644 (file)
@@ -64,7 +64,7 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
 #define set_pmd(pmdptr,pmdval) \
                set_64bit((unsigned long long *)(pmdptr),pmd_val(pmdval))
 #define set_pud(pudptr,pudval) \
-               set_64bit((unsigned long long *)(pudptr),pud_val(pudval))
+               (*(pudptr) = (pudval))
 
 /*
  * Pentium-II erratum A13: in PAE mode we explicitly have to flush
index 77c6497f416ed07905ea6d9ae847c9b907cdabfd..47bc1ffa3d4cfb42321cec3bf25d9da23ccc8486 100644 (file)
@@ -86,9 +86,7 @@ void paging_init(void);
 #endif
 
 /*
- * The 4MB page is guessing..  Detailed in the infamous "Chapter H"
- * of the Pentium details, but assuming intel did the straightforward
- * thing, this bit set in the page directory entry just means that
+ * _PAGE_PSE set in the page directory entry just means that
  * the page directory entry points directly to a 4MB-aligned block of
  * memory. 
  */
@@ -119,8 +117,10 @@ void paging_init(void);
 #define _PAGE_UNUSED2  0x400
 #define _PAGE_UNUSED3  0x800
 
-#define _PAGE_FILE     0x040   /* set:pagecache unset:swap */
-#define _PAGE_PROTNONE 0x080   /* If not present */
+/* If _PAGE_PRESENT is clear, we use these: */
+#define _PAGE_FILE     0x040   /* nonlinear file mapping, saved PTE; unset:swap */
+#define _PAGE_PROTNONE 0x080   /* if the user mapped it with PROT_NONE;
+                                  pte_present gives true */
 #ifdef CONFIG_X86_PAE
 #define _PAGE_NX       (1ULL<<_PAGE_BIT_NX)
 #else
@@ -215,11 +215,13 @@ extern unsigned long pg0[];
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
+#define __LARGE_PTE (_PAGE_PSE | _PAGE_PRESENT)
 static inline int pte_user(pte_t pte)          { return (pte).pte_low & _PAGE_USER; }
 static inline int pte_read(pte_t pte)          { return (pte).pte_low & _PAGE_USER; }
 static inline int pte_dirty(pte_t pte)         { return (pte).pte_low & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte)         { return (pte).pte_low & _PAGE_ACCESSED; }
 static inline int pte_write(pte_t pte)         { return (pte).pte_low & _PAGE_RW; }
+static inline int pte_huge(pte_t pte)          { return ((pte).pte_low & __LARGE_PTE) == __LARGE_PTE; }
 
 /*
  * The following only works if pte_present() is not true.
@@ -236,7 +238,7 @@ static inline pte_t pte_mkexec(pte_t pte)   { (pte).pte_low |= _PAGE_USER; return
 static inline pte_t pte_mkdirty(pte_t pte)     { (pte).pte_low |= _PAGE_DIRTY; return pte; }
 static inline pte_t pte_mkyoung(pte_t pte)     { (pte).pte_low |= _PAGE_ACCESSED; return pte; }
 static inline pte_t pte_mkwrite(pte_t pte)     { (pte).pte_low |= _PAGE_RW; return pte; }
-static inline pte_t pte_mkhuge(pte_t pte)      { (pte).pte_low |= _PAGE_PRESENT | _PAGE_PSE; return pte; }
+static inline pte_t pte_mkhuge(pte_t pte)      { (pte).pte_low |= __LARGE_PTE; return pte; }
 
 #ifdef CONFIG_X86_PAE
 # include <asm/pgtable-3level.h>
@@ -258,11 +260,38 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned
        return test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte_low);
 }
 
+static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long addr, pte_t *ptep, int full)
+{
+       pte_t pte;
+       if (full) {
+               pte = *ptep;
+               *ptep = __pte(0);
+       } else {
+               pte = ptep_get_and_clear(mm, addr, ptep);
+       }
+       return pte;
+}
+
 static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
        clear_bit(_PAGE_BIT_RW, &ptep->pte_low);
 }
 
+/*
+ * clone_pgd_range(pgd_t *dst, pgd_t *src, int count);
+ *
+ *  dst - pointer to pgd range anwhere on a pgd page
+ *  src - ""
+ *  count - the number of pgds to copy.
+ *
+ * dst and src can be on the same page, but the range must not overlap,
+ * and must not cross a page boundary.
+ */
+static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
+{
+       memcpy(dst, src, count * sizeof(pgd_t));
+}
+
 /*
  * Macro to mark a page protection value as "uncacheable".  On processors which do not support
  * it, this is a no-op.
@@ -415,6 +444,7 @@ extern void noexec_setup(const char *str);
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
 #define __HAVE_ARCH_PTE_SAME
 #include <asm-generic/pgtable.h>
index d0d8b0160090427328fc384baed9ab77872ecb88..37bef8ed7bed12bd33bf3670ccf7991516aa7484 100644 (file)
@@ -203,9 +203,7 @@ static inline unsigned int cpuid_edx(unsigned int op)
        return edx;
 }
 
-#define load_cr3(pgdir) \
-       asm volatile("movl %0,%%cr3": :"r" (__pa(pgdir)))
-
+#define load_cr3(pgdir) write_cr3(__pa(pgdir))
 
 /*
  * Intel CPU features in CR4
@@ -232,22 +230,20 @@ extern unsigned long mmu_cr4_features;
 
 static inline void set_in_cr4 (unsigned long mask)
 {
+       unsigned cr4;
        mmu_cr4_features |= mask;
-       __asm__("movl %%cr4,%%eax\n\t"
-               "orl %0,%%eax\n\t"
-               "movl %%eax,%%cr4\n"
-               : : "irg" (mask)
-               :"ax");
+       cr4 = read_cr4();
+       cr4 |= mask;
+       write_cr4(cr4);
 }
 
 static inline void clear_in_cr4 (unsigned long mask)
 {
+       unsigned cr4;
        mmu_cr4_features &= ~mask;
-       __asm__("movl %%cr4,%%eax\n\t"
-               "andl %0,%%eax\n\t"
-               "movl %%eax,%%cr4\n"
-               : : "irg" (~mask)
-               :"ax");
+       cr4 = read_cr4();
+       cr4 &= ~mask;
+       write_cr4(cr4);
 }
 
 /*
@@ -281,6 +277,11 @@ static inline void clear_in_cr4 (unsigned long mask)
        outb((data), 0x23); \
 } while (0)
 
+static inline void serialize_cpu(void)
+{
+        __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
+}
+
 static inline void __monitor(const void *eax, unsigned long ecx,
                unsigned long edx)
 {
@@ -454,6 +455,7 @@ struct thread_struct {
        unsigned int            saved_fs, saved_gs;
 /* IO permissions */
        unsigned long   *io_bitmap_ptr;
+       unsigned long   iopl;
 /* max allowed port in the bitmap, in bytes: */
        unsigned long   io_bitmap_max;
 };
@@ -474,7 +476,6 @@ struct thread_struct {
        .esp0           = sizeof(init_stack) + (long)&init_stack,       \
        .ss0            = __KERNEL_DS,                                  \
        .ss1            = __KERNEL_CS,                                  \
-       .ldt            = GDT_ENTRY_LDT,                                \
        .io_bitmap_base = INVALID_IO_BITMAP_OFFSET,                     \
        .io_bitmap      = { [ 0 ... IO_BITMAP_LONGS] = ~0 },            \
 }
@@ -511,6 +512,21 @@ static inline void load_esp0(struct tss_struct *tss, struct thread_struct *threa
                        : /* no output */                       \
                        :"r" (value))
 
+/*
+ * Set IOPL bits in EFLAGS from given mask
+ */
+static inline void set_iopl_mask(unsigned mask)
+{
+       unsigned int reg;
+       __asm__ __volatile__ ("pushfl;"
+                             "popl %0;"
+                             "andl %1, %0;"
+                             "orl %2, %0;"
+                             "pushl %0;"
+                             "popfl"
+                               : "=&r" (reg)
+                               : "i" (~X86_EFLAGS_IOPL), "r" (mask));
+}
 
 /* Forward declaration, a strange C thing */
 struct task_struct;
index 05532875e39e2846a7d757f242617990d039d279..7e0f2945d17d48587dadf5a6b6b5d027b9869b0a 100644 (file)
@@ -61,6 +61,13 @@ struct pt_regs {
 struct task_struct;
 extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code);
 
+/*
+ * user_mode_vm(regs) determines whether a register set came from user mode.
+ * This is true if V8086 mode was enabled OR if the register set was from
+ * protected mode with RPL-3 CS value.  This tricky test checks that with
+ * one comparison.  Many places in the kernel can bypass this full check
+ * if they have already ruled out V8086 mode, so user_mode(regs) can be used.
+ */
 static inline int user_mode(struct pt_regs *regs)
 {
        return (regs->xcs & 3) != 0;
index 7a32184d54bf414522d10976d9a7a7a0b4d47a1b..826a8ca50ac801dd6960e2396d9a55e02e1ba2a4 100644 (file)
@@ -44,7 +44,7 @@ extern unsigned char boot_params[PARAM_SIZE];
 #define EFI_SYSTAB ((efi_system_table_t *) *((unsigned long *)(PARAM+0x1c4)))
 #define EFI_MEMDESC_SIZE (*((unsigned long *) (PARAM+0x1c8)))
 #define EFI_MEMDESC_VERSION (*((unsigned long *) (PARAM+0x1cc)))
-#define EFI_MEMMAP ((efi_memory_desc_t *) *((unsigned long *)(PARAM+0x1d0)))
+#define EFI_MEMMAP ((void *) *((unsigned long *)(PARAM+0x1d0)))
 #define EFI_MEMMAP_SIZE (*((unsigned long *) (PARAM+0x1d4)))
 #define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
 #define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
index a283738b80b30bbc9defb338b16c4f70971d7ffc..13250199976d581901aeb87d216150d721492e9b 100644 (file)
@@ -59,7 +59,7 @@ extern void cpu_uninit(void);
 
 extern cpumask_t cpu_callout_map;
 extern cpumask_t cpu_callin_map;
-#define cpu_possible_map cpu_callout_map
+extern cpumask_t cpu_possible_map;
 
 /* We don't mark CPUs online until __cpu_up(), so we need another measure */
 static inline int num_booting_cpus(void)
index 07f6b38ad140d5ace68f4d44bfeb61cf351b554f..802ae76195b72a4a09e3f9c052e96968389be694 100644 (file)
@@ -14,6 +14,8 @@
 #define SO_BROADCAST   6
 #define SO_SNDBUF      7
 #define SO_RCVBUF      8
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
 #define SO_KEEPALIVE   9
 #define SO_OOBINLINE   10
 #define SO_NO_CHECK    11
index 3db717a244f0c4df75a06102c522e6cdf19f82b1..acd5c26b69ba68f9a2964b59cdf01b86daab9fda 100644 (file)
@@ -14,8 +14,7 @@ extern struct task_struct * FASTCALL(__switch_to(struct task_struct *prev, struc
 
 #define switch_to(prev,next,last) do {                                 \
        unsigned long esi,edi;                                          \
-       asm volatile("pushfl\n\t"                                       \
-                    "pushl %%ebp\n\t"                                  \
+       asm volatile("pushl %%ebp\n\t"                                  \
                     "movl %%esp,%0\n\t"        /* save ESP */          \
                     "movl %5,%%esp\n\t"        /* restore ESP */       \
                     "movl $1f,%1\n\t"          /* save EIP */          \
@@ -23,7 +22,6 @@ extern struct task_struct * FASTCALL(__switch_to(struct task_struct *prev, struc
                     "jmp __switch_to\n"                                \
                     "1:\t"                                             \
                     "popl %%ebp\n\t"                                   \
-                    "popfl"                                            \
                     :"=m" (prev->thread.esp),"=m" (prev->thread.eip),  \
                      "=a" (last),"=S" (esi),"=D" (edi)                 \
                     :"m" (next->thread.esp),"m" (next->thread.eip),    \
@@ -93,13 +91,13 @@ static inline unsigned long _get_base(char * addr)
                ".align 4\n\t"                  \
                ".long 1b,3b\n"                 \
                ".previous"                     \
-               : :"m" (value))
+               : :"rm" (value))
 
 /*
  * Save a segment register away
  */
 #define savesegment(seg, value) \
-       asm volatile("mov %%" #seg ",%0":"=m" (value))
+       asm volatile("mov %%" #seg ",%0":"=rm" (value))
 
 /*
  * Clear and set 'TS' bit respectively
@@ -107,13 +105,33 @@ static inline unsigned long _get_base(char * addr)
 #define clts() __asm__ __volatile__ ("clts")
 #define read_cr0() ({ \
        unsigned int __dummy; \
-       __asm__( \
+       __asm__ __volatile__( \
                "movl %%cr0,%0\n\t" \
                :"=r" (__dummy)); \
        __dummy; \
 })
 #define write_cr0(x) \
-       __asm__("movl %0,%%cr0": :"r" (x));
+       __asm__ __volatile__("movl %0,%%cr0": :"r" (x));
+
+#define read_cr2() ({ \
+       unsigned int __dummy; \
+       __asm__ __volatile__( \
+               "movl %%cr2,%0\n\t" \
+               :"=r" (__dummy)); \
+       __dummy; \
+})
+#define write_cr2(x) \
+       __asm__ __volatile__("movl %0,%%cr2": :"r" (x));
+
+#define read_cr3() ({ \
+       unsigned int __dummy; \
+       __asm__ ( \
+               "movl %%cr3,%0\n\t" \
+               :"=r" (__dummy)); \
+       __dummy; \
+})
+#define write_cr3(x) \
+       __asm__ __volatile__("movl %0,%%cr3": :"r" (x));
 
 #define read_cr4() ({ \
        unsigned int __dummy; \
@@ -123,7 +141,7 @@ static inline unsigned long _get_base(char * addr)
        __dummy; \
 })
 #define write_cr4(x) \
-       __asm__("movl %0,%%cr4": :"r" (x));
+       __asm__ __volatile__("movl %0,%%cr4": :"r" (x));
 #define stts() write_cr0(8 | read_cr0())
 
 #endif /* __KERNEL__ */
@@ -447,6 +465,8 @@ struct alt_instr {
 #define local_irq_enable()     __asm__ __volatile__("sti": : :"memory")
 /* used in the idle loop; sti takes one instruction cycle to complete */
 #define safe_halt()            __asm__ __volatile__("sti; hlt": : :"memory")
+/* used when interrupts are already enabled or to shutdown the processor */
+#define halt()                 __asm__ __volatile__("hlt": : :"memory")
 
 #define irqs_disabled()                        \
 ({                                     \
index 95add81237eab1342737431cd7c7134d1d2f9985..e2cb9fa6f563db415e494dae49b0173fa3e2b7c6 100644 (file)
@@ -139,6 +139,7 @@ register unsigned long current_stack_pointer asm("esp") __attribute_used__;
 #define TIF_NEED_RESCHED       3       /* rescheduling necessary */
 #define TIF_SINGLESTEP         4       /* restore singlestep on return to user mode */
 #define TIF_IRET               5       /* return with iret */
+#define TIF_SYSCALL_EMU                6       /* syscall emulation active */
 #define TIF_SYSCALL_AUDIT      7       /* syscall auditing active */
 #define TIF_SECCOMP            8       /* secure computing */
 #define TIF_POLLING_NRFLAG     16      /* true if poll_idle() is polling TIF_NEED_RESCHED */
@@ -150,13 +151,15 @@ register unsigned long current_stack_pointer asm("esp") __attribute_used__;
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP                (1<<TIF_SINGLESTEP)
 #define _TIF_IRET              (1<<TIF_IRET)
+#define _TIF_SYSCALL_EMU       (1<<TIF_SYSCALL_EMU)
 #define _TIF_SYSCALL_AUDIT     (1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP           (1<<TIF_SECCOMP)
 #define _TIF_POLLING_NRFLAG    (1<<TIF_POLLING_NRFLAG)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK \
-  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|_TIF_SECCOMP))
+  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|\
+                 _TIF_SECCOMP|_TIF_SYSCALL_EMU))
 /* work to do on any return to u-space */
 #define _TIF_ALLWORK_MASK      (0x0000FFFF & ~_TIF_SECCOMP)
 
index dcf1e07db08a7802629cfe39fb433fc4e02af68d..aed16437479d91ecf5d2a3b87be996c39573316c 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _ASMi386_TIMER_H
 #define _ASMi386_TIMER_H
 #include <linux/init.h>
+#include <linux/pm.h>
 
 /**
  * struct timer_ops - used to define a timer source
@@ -23,6 +24,8 @@ struct timer_opts {
        unsigned long long (*monotonic_clock)(void);
        void (*delay)(unsigned long);
        unsigned long (*read_timer)(void);
+       int (*suspend)(pm_message_t state);
+       int (*resume)(void);
 };
 
 struct init_timer_opts {
index 901b77c42b8a70e860c95766641904b6fb5468d5..ced00fe8fe61c0667840795158b234c58fa35ebc 100644 (file)
@@ -63,8 +63,6 @@ typedef u64 sector_t;
 #define HAVE_SECTOR_T
 #endif
 
-typedef unsigned short kmem_bufctl_t;
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index 886867aea947094185fcac17610acc67f9310caf..89ab7e2bc5aaac8a1e230fbd7772ff5340e7b3a1 100644 (file)
@@ -83,30 +83,6 @@ extern struct movsl_mask {
  */
 #define access_ok(type,addr,size) (likely(__range_ok(addr,size) == 0))
 
-/**
- * verify_area: - Obsolete/deprecated and will go away soon,
- * use access_ok() instead.
- * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE
- * @addr: User space pointer to start of block to check
- * @size: Size of block to check
- *
- * Context: User context only.  This function may sleep.
- *
- * This function has been replaced by access_ok().
- *
- * Checks if a pointer to a block of memory in user space is valid.
- *
- * Returns zero if the memory block may be valid, -EFAULT
- * if it is definitely invalid.
- *
- * See access_ok() for more details.
- */
-static inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
-{
-       return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
-
 /*
  * The exception table consists of pairs of addresses: the first is the
  * address of an instruction that is allowed to fault, and the second is
index f80e2dbe1b56a541fc1be0e37dff529ffb46a08c..23c86cef3b258a8611e765bd168e1c89054a19f6 100644 (file)
@@ -535,14 +535,14 @@ static struct xor_block_template xor_block_p5_mmx = {
 
 #define XMMS_SAVE do {                         \
        preempt_disable();                      \
+       cr0 = read_cr0();                       \
+       clts();                                 \
        __asm__ __volatile__ (                  \
-               "movl %%cr0,%0          ;\n\t"  \
-               "clts                   ;\n\t"  \
-               "movups %%xmm0,(%1)     ;\n\t"  \
-               "movups %%xmm1,0x10(%1) ;\n\t"  \
-               "movups %%xmm2,0x20(%1) ;\n\t"  \
-               "movups %%xmm3,0x30(%1) ;\n\t"  \
-               : "=&r" (cr0)                   \
+               "movups %%xmm0,(%0)     ;\n\t"  \
+               "movups %%xmm1,0x10(%0) ;\n\t"  \
+               "movups %%xmm2,0x20(%0) ;\n\t"  \
+               "movups %%xmm3,0x30(%0) ;\n\t"  \
+               :                               \
                : "r" (xmm_save)                \
                : "memory");                    \
 } while(0)
@@ -550,14 +550,14 @@ static struct xor_block_template xor_block_p5_mmx = {
 #define XMMS_RESTORE do {                      \
        __asm__ __volatile__ (                  \
                "sfence                 ;\n\t"  \
-               "movups (%1),%%xmm0     ;\n\t"  \
-               "movups 0x10(%1),%%xmm1 ;\n\t"  \
-               "movups 0x20(%1),%%xmm2 ;\n\t"  \
-               "movups 0x30(%1),%%xmm3 ;\n\t"  \
-               "movl   %0,%%cr0        ;\n\t"  \
+               "movups (%0),%%xmm0     ;\n\t"  \
+               "movups 0x10(%0),%%xmm1 ;\n\t"  \
+               "movups 0x20(%0),%%xmm2 ;\n\t"  \
+               "movups 0x30(%0),%%xmm3 ;\n\t"  \
                :                               \
-               : "r" (cr0), "r" (xmm_save)     \
+               : "r" (xmm_save)                \
                : "memory");                    \
+       write_cr0(cr0);                         \
        preempt_enable();                       \
 } while(0)
 
index 4c06d455139c776f0cc2f78838dfcbeb2e24d48c..3a544ffc500860f5f1c166e3e2b9bff57e7e11b5 100644 (file)
@@ -116,6 +116,11 @@ extern int __initdata nid_to_pxm_map[MAX_NUMNODES];
 
 extern u16 ia64_acpiid_to_sapicid[];
 
+/*
+ * Refer Intel ACPI _PDC support document for bit definitions
+ */
+#define ACPI_PDC_EST_CAPABILITY_SMP     0x8
+
 #endif /*__KERNEL__*/
 
 #endif /*_ASM_ACPI_H*/
diff --git a/include/asm-ia64/auxvec.h b/include/asm-ia64/auxvec.h
new file mode 100644 (file)
index 0000000..23cebe5
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _ASM_IA64_AUXVEC_H
+#define _ASM_IA64_AUXVEC_H
+
+/*
+ * Architecture-neutral AT_ values are in the range 0-17.  Leave some room for more of
+ * them, start the architecture-specific ones at 32.
+ */
+#define AT_SYSINFO     32
+#define AT_SYSINFO_EHDR        33
+
+#endif /* _ASM_IA64_AUXVEC_H */
index 0c05e5bad8a0fe01e4ba88abcb84d1516014d414..aaf11f4e916997643d60c7d45fb4718ac5092363 100644 (file)
@@ -13,10 +13,10 @@ typedef s32         compat_time_t;
 typedef s32            compat_clock_t;
 typedef s32            compat_key_t;
 typedef s32            compat_pid_t;
-typedef u16            compat_uid_t;
-typedef u16            compat_gid_t;
-typedef u32            compat_uid32_t;
-typedef u32            compat_gid32_t;
+typedef u16            __compat_uid_t;
+typedef u16            __compat_gid_t;
+typedef u32            __compat_uid32_t;
+typedef u32            __compat_gid32_t;
 typedef u16            compat_mode_t;
 typedef u32            compat_ino_t;
 typedef u16            compat_dev_t;
@@ -50,8 +50,8 @@ struct compat_stat {
        compat_ino_t    st_ino;
        compat_mode_t   st_mode;
        compat_nlink_t  st_nlink;
-       compat_uid_t    st_uid;
-       compat_gid_t    st_gid;
+       __compat_uid_t  st_uid;
+       __compat_gid_t  st_gid;
        compat_dev_t    st_rdev;
        u16             __pad2;
        u32             st_size;
@@ -120,10 +120,10 @@ typedef u32               compat_sigset_word;
 
 struct compat_ipc64_perm {
        compat_key_t key;
-       compat_uid32_t uid;
-       compat_gid32_t gid;
-       compat_uid32_t cuid;
-       compat_gid32_t cgid;
+       __compat_uid32_t uid;
+       __compat_gid32_t gid;
+       __compat_uid32_t cuid;
+       __compat_gid32_t cgid;
        unsigned short mode;
        unsigned short __pad1;
        unsigned short seq;
index 7d4ccc4b976e2150fb4ab909902c68cf9ea701af..446fce036fd929eedb87ffdf95917703a568a9ae 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <asm/fpu.h>
 #include <asm/page.h>
+#include <asm/auxvec.h>
 
 /*
  * This is used to ensure we don't load something for the wrong architecture.
@@ -177,13 +178,6 @@ extern void ia64_elf_core_copy_regs (struct pt_regs *src, elf_gregset_t dst);
    relevant until we have real hardware to play with... */
 #define ELF_PLATFORM   NULL
 
-/*
- * Architecture-neutral AT_ values are in the range 0-17.  Leave some room for more of
- * them, start the architecture-specific ones at 32.
- */
-#define AT_SYSINFO     32
-#define AT_SYSINFO_EHDR        33
-
 #ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2)     set_personality(PER_LINUX)
 #define elf_read_implies_exec(ex, executable_stack)                                    \
index c9f8d835d0cc0860345312eff324beebdf7becd4..1dd275dc8f653a0b6be00f469998bfa8711044a0 100644 (file)
@@ -1,86 +1,13 @@
 #ifndef _ASM_IA64_FCNTL_H
 #define _ASM_IA64_FCNTL_H
 /*
- * Based on <asm-i386/fcntl.h>.
- *
  * Modified 1998-2000
  *     David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co.
  */
 
-/*
- * open/fcntl - O_SYNC is only implemented on blocks devices and on
- * files located on an ext2 file system
- */
-#define O_ACCMODE         0003
-#define O_RDONLY            00
-#define O_WRONLY            01
-#define O_RDWR              02
-#define O_CREAT                   0100 /* not fcntl */
-#define O_EXCL            0200 /* not fcntl */
-#define O_NOCTTY          0400 /* not fcntl */
-#define O_TRUNC                  01000 /* not fcntl */
-#define O_APPEND         02000
-#define O_NONBLOCK       04000
-#define O_NDELAY       O_NONBLOCK
-#define O_SYNC          010000
-#define FASYNC          020000 /* fcntl, for BSD compatibility */
-#define O_DIRECT        040000 /* direct disk access hint - currently ignored */
-#define O_LARGEFILE    0100000
-#define O_DIRECTORY    0200000 /* must be a directory */
-#define O_NOFOLLOW     0400000 /* don't follow links */
-#define O_NOATIME      01000000
-
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
-#define F_GETLK                5
-#define F_SETLK                6
-#define F_SETLKW       7
-
-#define F_SETOWN       8       /*  for sockets. */
-#define F_GETOWN       9       /*  for sockets. */
-#define F_SETSIG       10      /*  for sockets. */
-#define F_GETSIG       11      /*  for sockets. */
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK                0
-#define F_WRLCK                1
-#define F_UNLCK                2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
-
-struct flock {
-       short l_type;
-       short l_whence;
-       off_t l_start;
-       off_t l_len;
-       pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE  1024
+#define force_o_largefile()    \
+               (personality(current->personality) != PER_LINUX32)
 
-#define force_o_largefile() ( ! (current->personality & PER_LINUX32) )
+#include <asm-generic/fcntl.h>
 
 #endif /* _ASM_IA64_FCNTL_H */
diff --git a/include/asm-ia64/futex.h b/include/asm-ia64/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-ia64/hdreg.h b/include/asm-ia64/hdreg.h
deleted file mode 100644 (file)
index 83b5161..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- *  linux/include/asm-ia64/hdreg.h
- *
- *  Copyright (C) 1994-1996  Linus Torvalds & authors
- */
-
-#warning this file is obsolete, please do not use it
-
-#ifndef __ASM_IA64_HDREG_H
-#define __ASM_IA64_HDREG_H
-
-typedef unsigned short ide_ioreg_t;
-
-#endif /* __ASM_IA64_HDREG_H */
index 041ab8c51a6409469c1e40e3652814ac666f9817..0cf119b42f7d5c4d1d25ce4eb0e55b9a849d52cb 100644 (file)
@@ -116,13 +116,6 @@ __ia64_local_vector_to_irq (ia64_vector vec)
  * and to obtain the irq descriptor for a given irq number.
  */
 
-/* Return a pointer to the irq descriptor for IRQ.  */
-static inline irq_desc_t *
-irq_descp (int irq)
-{
-       return irq_desc + irq;
-}
-
 /* Extract the IA-64 vector that corresponds to IRQ.  */
 static inline ia64_vector
 irq_to_vector (int irq)
index 54e7637a326c4e1ffb6aab9835abab5f384e3be0..cf772a67f858763719a615f03ea8b8d117501973 100644 (file)
@@ -23,7 +23,7 @@
 #define __SLOW_DOWN_IO do { } while (0)
 #define SLOW_DOWN_IO   do { } while (0)
 
-#define __IA64_UNCACHED_OFFSET 0xc000000000000000UL    /* region 6 */
+#define __IA64_UNCACHED_OFFSET RGN_BASE(RGN_UNCACHED)
 
 /*
  * The legacy I/O space defined by the ia64 architecture supports only 65536 ports, but
@@ -41,7 +41,7 @@
 #define IO_SPACE_BASE(space)           ((space) << IO_SPACE_BITS)
 #define IO_SPACE_PORT(port)            ((port) & (IO_SPACE_SIZE - 1))
 
-#define IO_SPACE_SPARSE_ENCODING(p)    ((((p) >> 2) << 12) | (p & 0xfff))
+#define IO_SPACE_SPARSE_ENCODING(p)    ((((p) >> 2) << 12) | ((p) & 0xfff))
 
 struct io_space {
        unsigned long mmio_base;        /* base in MMIO space */
index bd07d11d9f37ac81e55a51c7e8ea35b0f19ce0c3..cd984d08fd15b09f27cdc28c4698b38d7bd57ddc 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)
 {
@@ -30,12 +35,6 @@ extern void disable_irq_nosync (unsigned int);
 extern void enable_irq (unsigned int);
 extern void set_irq_affinity_info (unsigned int irq, int dest, int redir);
 
-#ifdef CONFIG_SMP
-extern void move_irq(int irq);
-#else
-#define move_irq(irq)
-#endif
-
 struct irqaction;
 struct pt_regs;
 int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
index bf36a32e37e4661dd4abaa944f55e7776c16ee65..573a3574a24fe86ebcd4ecb5be7800c3057b4df5 100644 (file)
@@ -92,6 +92,7 @@ struct arch_specific_insn {
        kprobe_opcode_t insn;
  #define INST_FLAG_FIX_RELATIVE_IP_ADDR                1
  #define INST_FLAG_FIX_BRANCH_REG              2
+ #define INST_FLAG_BREAK_INST                  4
        unsigned long inst_flag;
        unsigned short target_br_reg;
 };
index ae1525352a25fb569c3243e475aafde7e53e81c2..611432ba579c0d91f64c402c2fc115f0ef1fe487 100644 (file)
@@ -2,10 +2,12 @@
 #define __MMU_H
 
 /*
- * Type for a context number.  We declare it volatile to ensure proper ordering when it's
- * accessed outside of spinlock'd critical sections (e.g., as done in activate_mm() and
- * init_new_context()).
+ * Type for a context number.  We declare it volatile to ensure proper
+ * ordering when it's accessed outside of spinlock'd critical sections
+ * (e.g., as done in activate_mm() and init_new_context()).
  */
 typedef volatile unsigned long mm_context_t;
 
+typedef unsigned long nv_mm_context_t;
+
 #endif
index e3e5fededb04c4c63301afd1e309c1f022d749b0..8d6e72f7b08efce6251952c7e69241ce243f8e28 100644 (file)
@@ -19,6 +19,7 @@
 
 #define ia64_rid(ctx,addr)     (((ctx) << 3) | (addr >> 61))
 
+# include <asm/page.h>
 # ifndef __ASSEMBLY__
 
 #include <linux/compiler.h>
@@ -55,34 +56,46 @@ static inline void
 delayed_tlb_flush (void)
 {
        extern void local_flush_tlb_all (void);
+       unsigned long flags;
 
        if (unlikely(__ia64_per_cpu_var(ia64_need_tlb_flush))) {
-               local_flush_tlb_all();
-               __ia64_per_cpu_var(ia64_need_tlb_flush) = 0;
+               spin_lock_irqsave(&ia64_ctx.lock, flags);
+               {
+                       if (__ia64_per_cpu_var(ia64_need_tlb_flush)) {
+                               local_flush_tlb_all();
+                               __ia64_per_cpu_var(ia64_need_tlb_flush) = 0;
+                       }
+               }
+               spin_unlock_irqrestore(&ia64_ctx.lock, flags);
        }
 }
 
-static inline mm_context_t
+static inline nv_mm_context_t
 get_mmu_context (struct mm_struct *mm)
 {
        unsigned long flags;
-       mm_context_t context = mm->context;
-
-       if (context)
-               return context;
-
-       spin_lock_irqsave(&ia64_ctx.lock, flags);
-       {
-               /* re-check, now that we've got the lock: */
-               context = mm->context;
-               if (context == 0) {
-                       cpus_clear(mm->cpu_vm_mask);
-                       if (ia64_ctx.next >= ia64_ctx.limit)
-                               wrap_mmu_context(mm);
-                       mm->context = context = ia64_ctx.next++;
+       nv_mm_context_t context = mm->context;
+
+       if (unlikely(!context)) {
+               spin_lock_irqsave(&ia64_ctx.lock, flags);
+               {
+                       /* re-check, now that we've got the lock: */
+                       context = mm->context;
+                       if (context == 0) {
+                               cpus_clear(mm->cpu_vm_mask);
+                               if (ia64_ctx.next >= ia64_ctx.limit)
+                                       wrap_mmu_context(mm);
+                               mm->context = context = ia64_ctx.next++;
+                       }
                }
+               spin_unlock_irqrestore(&ia64_ctx.lock, flags);
        }
-       spin_unlock_irqrestore(&ia64_ctx.lock, flags);
+       /*
+        * Ensure we're not starting to use "context" before any old
+        * uses of it are gone from our TLB.
+        */
+       delayed_tlb_flush();
+
        return context;
 }
 
@@ -104,13 +117,13 @@ destroy_context (struct mm_struct *mm)
 }
 
 static inline void
-reload_context (mm_context_t context)
+reload_context (nv_mm_context_t context)
 {
        unsigned long rid;
        unsigned long rid_incr = 0;
        unsigned long rr0, rr1, rr2, rr3, rr4, old_rr4;
 
-       old_rr4 = ia64_get_rr(0x8000000000000000UL);
+       old_rr4 = ia64_get_rr(RGN_BASE(RGN_HPAGE));
        rid = context << 3;     /* make space for encoding the region number */
        rid_incr = 1 << 8;
 
@@ -122,6 +135,10 @@ reload_context (mm_context_t context)
        rr4 = rr0 + 4*rid_incr;
 #ifdef  CONFIG_HUGETLB_PAGE
        rr4 = (rr4 & (~(0xfcUL))) | (old_rr4 & 0xfc);
+
+#  if RGN_HPAGE != 4
+#    error "reload_context assumes RGN_HPAGE is 4"
+#  endif
 #endif
 
        ia64_set_rr(0x0000000000000000UL, rr0);
@@ -138,7 +155,7 @@ reload_context (mm_context_t context)
 static inline void
 activate_context (struct mm_struct *mm)
 {
-       mm_context_t context;
+       nv_mm_context_t context;
 
        do {
                context = get_mmu_context(mm);
@@ -157,8 +174,6 @@ activate_context (struct mm_struct *mm)
 static inline void
 activate_mm (struct mm_struct *prev, struct mm_struct *next)
 {
-       delayed_tlb_flush();
-
        /*
         * We may get interrupts here, but that's OK because interrupt handlers cannot
         * touch user-space.
index 08894f73abf0384df70d33888228ee389be33bcb..9edffad8c28b730b301a9725d2af79463be57bde 100644 (file)
 #include <asm/intrinsics.h>
 #include <asm/types.h>
 
+/*
+ * The top three bits of an IA64 address are its Region Number.
+ * Different regions are assigned to different purposes.
+ */
+#define RGN_SHIFT      (61)
+#define RGN_BASE(r)    (__IA64_UL_CONST(r)<<RGN_SHIFT)
+#define RGN_BITS       (RGN_BASE(-1))
+
+#define RGN_KERNEL     7       /* Identity mapped region */
+#define RGN_UNCACHED    6      /* Identity mapped I/O region */
+#define RGN_GATE       5       /* Gate page, Kernel text, etc */
+#define RGN_HPAGE      4       /* For Huge TLB pages */
+
 /*
  * PAGE_SHIFT determines the actual kernel page size.
  */
 
 #define RGN_MAP_LIMIT  ((1UL << (4*PAGE_SHIFT - 12)) - PAGE_SIZE)      /* per region addr limit */
 
+
 #ifdef CONFIG_HUGETLB_PAGE
-# define REGION_HPAGE          (4UL)   /* note: this is hardcoded in reload_context()!*/
-# define REGION_SHIFT          61
-# define HPAGE_REGION_BASE     (REGION_HPAGE << REGION_SHIFT)
+# define HPAGE_REGION_BASE     RGN_BASE(RGN_HPAGE)
 # define HPAGE_SHIFT           hpage_shift
 # define HPAGE_SHIFT_DEFAULT   28      /* check ia64 SDM for architecture supported size */
 # define HPAGE_SIZE            (__IA64_UL_CONST(1) << HPAGE_SHIFT)
@@ -130,16 +142,13 @@ typedef union ia64_va {
 #define REGION_NUMBER(x)       ({ia64_va _v; _v.l = (long) (x); _v.f.reg;})
 #define REGION_OFFSET(x)       ({ia64_va _v; _v.l = (long) (x); _v.f.off;})
 
-#define REGION_SIZE            REGION_NUMBER(1)
-#define REGION_KERNEL          7
-
 #ifdef CONFIG_HUGETLB_PAGE
 # define htlbpage_to_page(x)   (((unsigned long) REGION_NUMBER(x) << 61)                       \
                                 | (REGION_OFFSET(x) >> (HPAGE_SHIFT-PAGE_SHIFT)))
 # define HUGETLB_PAGE_ORDER    (HPAGE_SHIFT - PAGE_SHIFT)
 # define is_hugepage_only_range(mm, addr, len)         \
-        (REGION_NUMBER(addr) == REGION_HPAGE &&        \
-         REGION_NUMBER((addr)+(len)-1) == REGION_HPAGE)
+        (REGION_NUMBER(addr) == RGN_HPAGE &&   \
+         REGION_NUMBER((addr)+(len)-1) == RGN_HPAGE)
 extern unsigned int hpage_shift;
 #endif
 
@@ -197,7 +206,7 @@ get_order (unsigned long size)
 # define __pgprot(x)   (x)
 #endif /* !STRICT_MM_TYPECHECKS */
 
-#define PAGE_OFFSET                    __IA64_UL_CONST(0xe000000000000000)
+#define PAGE_OFFSET                    RGN_BASE(RGN_KERNEL)
 
 #define VM_DATA_DEFAULT_FLAGS          (VM_READ | VM_WRITE |                                   \
                                         VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC |                \
index 2303a10ee595405455d4f4520d3a334fd2fdfe56..e828377ad295cec5d77dd3a06b1bbdf06f014737 100644 (file)
@@ -75,6 +75,8 @@
 #define PAL_CACHE_READ         259     /* read tag & data of cacheline for diagnostic testing */
 #define PAL_CACHE_WRITE                260     /* write tag & data of cacheline for diagnostic testing */
 #define PAL_VM_TR_READ         261     /* read contents of translation register */
+#define PAL_GET_PSTATE         262     /* get the current P-state */
+#define PAL_SET_PSTATE         263     /* set the P-state */
 
 #ifndef __ASSEMBLY__
 
@@ -1111,6 +1113,25 @@ ia64_pal_halt_info (pal_power_mgmt_info_u_t *power_buf)
        return iprv.status;
 }
 
+/* Get the current P-state information */
+static inline s64
+ia64_pal_get_pstate (u64 *pstate_index)
+{
+       struct ia64_pal_retval iprv;
+       PAL_CALL_STK(iprv, PAL_GET_PSTATE, 0, 0, 0);
+       *pstate_index = iprv.v0;
+       return iprv.status;
+}
+
+/* Set the P-state */
+static inline s64
+ia64_pal_set_pstate (u64 pstate_index)
+{
+       struct ia64_pal_retval iprv;
+       PAL_CALL_STK(iprv, PAL_SET_PSTATE, pstate_index, 0, 0);
+       return iprv.status;
+}
+
 /* Cause the processor to enter LIGHT HALT state, where prefetching and execution are
  * suspended, but cache and TLB coherency is maintained.
  */
index 48586e08f432b5cc2793d0d4952869497e11d7bf..2e34c06e677795268249609786ceb012e81e4f84 100644 (file)
@@ -204,21 +204,18 @@ ia64_phys_addr_valid (unsigned long addr)
 #define set_pte(ptep, pteval)  (*(ptep) = (pteval))
 #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
-#define RGN_SIZE       (1UL << 61)
-#define RGN_KERNEL     7
-
-#define VMALLOC_START          0xa000000200000000UL
+#define VMALLOC_START          (RGN_BASE(RGN_GATE) + 0x200000000UL)
 #ifdef CONFIG_VIRTUAL_MEM_MAP
-# define VMALLOC_END_INIT      (0xa000000000000000UL + (1UL << (4*PAGE_SHIFT - 9)))
+# define VMALLOC_END_INIT      (RGN_BASE(RGN_GATE) + (1UL << (4*PAGE_SHIFT - 9)))
 # define VMALLOC_END           vmalloc_end
   extern unsigned long vmalloc_end;
 #else
-# define VMALLOC_END           (0xa000000000000000UL + (1UL << (4*PAGE_SHIFT - 9)))
+# define VMALLOC_END           (RGN_BASE(RGN_GATE) + (1UL << (4*PAGE_SHIFT - 9)))
 #endif
 
 /* fs/proc/kcore.c */
-#define        kc_vaddr_to_offset(v) ((v) - 0xa000000000000000UL)
-#define        kc_offset_to_vaddr(o) ((o) + 0xa000000000000000UL)
+#define        kc_vaddr_to_offset(v) ((v) - RGN_BASE(RGN_GATE))
+#define        kc_offset_to_vaddr(o) ((o) + RGN_BASE(RGN_GATE))
 
 /*
  * Conversion functions: convert page frame number (pfn) and a protection value to a page
index 91bbd1f2246140121bbaec497101790c6dc278cf..94e07e7273955b1174537b9f0093612c057c1ee0 100644 (file)
@@ -20,9 +20,6 @@
 #include <asm/ptrace.h>
 #include <asm/ustack.h>
 
-/* Our arch specific arch_init_sched_domain is in arch/ia64/kernel/domain.c */
-#define ARCH_HAS_SCHED_DOMAIN
-
 #define IA64_NUM_DBG_REGS      8
 /*
  * Limits for PMC and PMD are set to less than maximum architected values
index 6ece5061dc1904256c13f062bb1de4679b4e8511..e18b5ab0cb75c0cd6ee7014260cf23bdd79a59a6 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2003 Ken Chen <kenneth.w.chen@intel.com>
  * Copyright (C) 2003 Asit Mallick <asit.k.mallick@intel.com>
+ * Copyright (C) 2005 Christoph Lameter <clameter@sgi.com>
  *
  * Based on asm-i386/rwsem.h and other architecture implementation.
  *
@@ -11,9 +12,9 @@
  *
  * The lock count is initialized to 0 (no active and no waiting lockers).
  *
- * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case
- * of an uncontended lock. Readers increment by 1 and see a positive value
- * when uncontended, negative if there are writers (and maybe) readers
+ * When a writer subtracts WRITE_BIAS, it'll get 0xffffffff00000001 for
+ * the case of an uncontended lock. Readers increment by 1 and see a positive
+ * value when uncontended, negative if there are writers (and maybe) readers
  * waiting (in which case it goes to sleep).
  */
 
@@ -29,7 +30,7 @@
  * the semaphore definition
  */
 struct rw_semaphore {
-       signed int              count;
+       signed long             count;
        spinlock_t              wait_lock;
        struct list_head        wait_list;
 #if RWSEM_DEBUG
@@ -37,10 +38,10 @@ struct rw_semaphore {
 #endif
 };
 
-#define RWSEM_UNLOCKED_VALUE           0x00000000
-#define RWSEM_ACTIVE_BIAS              0x00000001
-#define RWSEM_ACTIVE_MASK              0x0000ffff
-#define RWSEM_WAITING_BIAS             (-0x00010000)
+#define RWSEM_UNLOCKED_VALUE           __IA64_UL_CONST(0x0000000000000000)
+#define RWSEM_ACTIVE_BIAS              __IA64_UL_CONST(0x0000000000000001)
+#define RWSEM_ACTIVE_MASK              __IA64_UL_CONST(0x00000000ffffffff)
+#define RWSEM_WAITING_BIAS             -__IA64_UL_CONST(0x0000000100000000)
 #define RWSEM_ACTIVE_READ_BIAS         RWSEM_ACTIVE_BIAS
 #define RWSEM_ACTIVE_WRITE_BIAS                (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
 
@@ -83,7 +84,7 @@ init_rwsem (struct rw_semaphore *sem)
 static inline void
 __down_read (struct rw_semaphore *sem)
 {
-       int result = ia64_fetchadd4_acq((unsigned int *)&sem->count, 1);
+       long result = ia64_fetchadd8_acq((unsigned long *)&sem->count, 1);
 
        if (result < 0)
                rwsem_down_read_failed(sem);
@@ -95,7 +96,7 @@ __down_read (struct rw_semaphore *sem)
 static inline void
 __down_write (struct rw_semaphore *sem)
 {
-       int old, new;
+       long old, new;
 
        do {
                old = sem->count;
@@ -112,7 +113,7 @@ __down_write (struct rw_semaphore *sem)
 static inline void
 __up_read (struct rw_semaphore *sem)
 {
-       int result = ia64_fetchadd4_rel((unsigned int *)&sem->count, -1);
+       long result = ia64_fetchadd8_rel((unsigned long *)&sem->count, -1);
 
        if (result < 0 && (--result & RWSEM_ACTIVE_MASK) == 0)
                rwsem_wake(sem);
@@ -124,7 +125,7 @@ __up_read (struct rw_semaphore *sem)
 static inline void
 __up_write (struct rw_semaphore *sem)
 {
-       int old, new;
+       long old, new;
 
        do {
                old = sem->count;
@@ -141,7 +142,7 @@ __up_write (struct rw_semaphore *sem)
 static inline int
 __down_read_trylock (struct rw_semaphore *sem)
 {
-       int tmp;
+       long tmp;
        while ((tmp = sem->count) >= 0) {
                if (tmp == cmpxchg_acq(&sem->count, tmp, tmp+1)) {
                        return 1;
@@ -156,7 +157,7 @@ __down_read_trylock (struct rw_semaphore *sem)
 static inline int
 __down_write_trylock (struct rw_semaphore *sem)
 {
-       int tmp = cmpxchg_acq(&sem->count, RWSEM_UNLOCKED_VALUE,
+       long tmp = cmpxchg_acq(&sem->count, RWSEM_UNLOCKED_VALUE,
                              RWSEM_ACTIVE_WRITE_BIAS);
        return tmp == RWSEM_UNLOCKED_VALUE;
 }
@@ -167,7 +168,7 @@ __down_write_trylock (struct rw_semaphore *sem)
 static inline void
 __downgrade_write (struct rw_semaphore *sem)
 {
-       int old, new;
+       long old, new;
 
        do {
                old = sem->count;
@@ -182,7 +183,7 @@ __downgrade_write (struct rw_semaphore *sem)
  * Implement atomic add functionality.  These used to be "inline" functions, but GCC v3.1
  * doesn't quite optimize this stuff right and ends up with bad calls to fetchandadd.
  */
-#define rwsem_atomic_add(delta, sem)   atomic_add(delta, (atomic_t *)(&(sem)->count))
-#define rwsem_atomic_update(delta, sem)        atomic_add_return(delta, (atomic_t *)(&(sem)->count))
+#define rwsem_atomic_add(delta, sem)   atomic64_add(delta, (atomic64_t *)(&(sem)->count))
+#define rwsem_atomic_update(delta, sem)        atomic64_add_return(delta, (atomic64_t *)(&(sem)->count))
 
 #endif /* _ASM_IA64_RWSEM_H */
index 103d745dc5f2f9fc8eda359854310424cd63545c..2c32e4b77b54051e1237fb99a55825555c8b71cf 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 1992-1999,2001-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (c) 1992-1999,2001-2005 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_IA64_SN_ADDRS_H
@@ -65,7 +65,6 @@
 
 #define NASID_MASK              ((u64)NASID_BITMASK << NASID_SHIFT)
 #define AS_MASK                        ((u64)AS_BITMASK << AS_SHIFT)
-#define REGION_BITS            0xe000000000000000UL
 
 
 /*
 #define AS_CAC_SPACE           (AS_CAC_VAL << AS_SHIFT)
 
 
-/*
- * Base addresses for various address ranges.
- */
-#define CACHED                 0xe000000000000000UL
-#define UNCACHED                0xc000000000000000UL
-#define UNCACHED_PHYS           0x8000000000000000UL
-
-
 /* 
  * Virtual Mode Local & Global MMR space.  
  */
 #define SH1_LOCAL_MMR_OFFSET   0x8000000000UL
 #define SH2_LOCAL_MMR_OFFSET   0x0200000000UL
 #define LOCAL_MMR_OFFSET       (is_shub2() ? SH2_LOCAL_MMR_OFFSET : SH1_LOCAL_MMR_OFFSET)
-#define LOCAL_MMR_SPACE                (UNCACHED | LOCAL_MMR_OFFSET)
-#define LOCAL_PHYS_MMR_SPACE   (UNCACHED_PHYS | LOCAL_MMR_OFFSET)
+#define LOCAL_MMR_SPACE                (__IA64_UNCACHED_OFFSET | LOCAL_MMR_OFFSET)
+#define LOCAL_PHYS_MMR_SPACE   (RGN_BASE(RGN_HPAGE) | LOCAL_MMR_OFFSET)
 
 #define SH1_GLOBAL_MMR_OFFSET  0x0800000000UL
 #define SH2_GLOBAL_MMR_OFFSET  0x0300000000UL
 #define GLOBAL_MMR_OFFSET      (is_shub2() ? SH2_GLOBAL_MMR_OFFSET : SH1_GLOBAL_MMR_OFFSET)
-#define GLOBAL_MMR_SPACE       (UNCACHED | GLOBAL_MMR_OFFSET)
+#define GLOBAL_MMR_SPACE       (__IA64_UNCACHED_OFFSET | GLOBAL_MMR_OFFSET)
 
 /*
  * Physical mode addresses
  */
-#define GLOBAL_PHYS_MMR_SPACE  (UNCACHED_PHYS | GLOBAL_MMR_OFFSET)
+#define GLOBAL_PHYS_MMR_SPACE  (RGN_BASE(RGN_HPAGE) | GLOBAL_MMR_OFFSET)
 
 
 /*
  * Clear region & AS bits.
  */
-#define TO_PHYS_MASK           (~(REGION_BITS | AS_MASK))
+#define TO_PHYS_MASK           (~(RGN_BITS | AS_MASK))
 
 
 /*
 #define GLOBAL_MMR_PHYS_ADDR(n,a) (GLOBAL_PHYS_MMR_SPACE | REMOTE_ADDR(n,a))
 #define GLOBAL_CAC_ADDR(n,a)   (CAC_BASE | REMOTE_ADDR(n,a))
 #define CHANGE_NASID(n,x)      ((void *)(((u64)(x) & ~NASID_MASK) | NASID_SPACE(n)))
+#define IS_TIO_NASID(n)                ((n) & 1)
 
 
 /* non-II mmr's start at top of big window space (4G) */
 /*
  * general address defines
  */
-#define CAC_BASE               (CACHED   | AS_CAC_SPACE)
-#define AMO_BASE               (UNCACHED | AS_AMO_SPACE)
-#define AMO_PHYS_BASE          (UNCACHED_PHYS | AS_AMO_SPACE)
-#define GET_BASE               (CACHED   | AS_GET_SPACE)
+#define CAC_BASE               (PAGE_OFFSET | AS_CAC_SPACE)
+#define AMO_BASE               (__IA64_UNCACHED_OFFSET | AS_AMO_SPACE)
+#define AMO_PHYS_BASE          (RGN_BASE(RGN_HPAGE) | AS_AMO_SPACE)
+#define GET_BASE               (PAGE_OFFSET | AS_GET_SPACE)
 
 /*
  * Convert Memory addresses between various addressing modes.
  *           the chiplet id is zero.  If we implement TIO-TIO dma, we might need
  *           to insert a chiplet id into this macro.  However, it is our belief
  *           right now that this chiplet id will be ICE, which is also zero.
- *           Nasid starts on bit 40.
  */
-#define PHYS_TO_TIODMA(x)      ( (((u64)(NASID_GET(x))) << 40) | NODE_OFFSET(x))
-#define PHYS_TO_DMA(x)          ( (((u64)(x) & NASID_MASK) >> 2) | NODE_OFFSET(x))
+#define SH1_TIO_PHYS_TO_DMA(x)                                                 \
+       ((((u64)(NASID_GET(x))) << 40) | NODE_OFFSET(x))
+
+#define SH2_NETWORK_BANK_OFFSET(x)                                     \
+        ((u64)(x) & ((1UL << (sn_hub_info->nasid_shift - 4)) -1))
+
+#define SH2_NETWORK_BANK_SELECT(x)                                     \
+        ((((u64)(x) & (0x3UL << (sn_hub_info->nasid_shift - 4)))       \
+               >> (sn_hub_info->nasid_shift - 4)) << 36)
+
+#define SH2_NETWORK_ADDRESS(x)                                                 \
+       (SH2_NETWORK_BANK_OFFSET(x) | SH2_NETWORK_BANK_SELECT(x))
+
+#define SH2_TIO_PHYS_TO_DMA(x)                                                 \
+        (((u64)(NASID_GET(x)) << 40) |         SH2_NETWORK_ADDRESS(x))
+
+#define PHYS_TO_TIODMA(x)                                              \
+       (is_shub1() ? SH1_TIO_PHYS_TO_DMA(x) : SH2_TIO_PHYS_TO_DMA(x))
+
+#define PHYS_TO_DMA(x)                                                 \
+       ((((u64)(x) & NASID_MASK) >> 2) | NODE_OFFSET(x))
 
 
 /*
  * Macros to test for address type.
  */
-#define IS_AMO_ADDRESS(x)      (((u64)(x) & (REGION_BITS | AS_MASK)) == AMO_BASE)
-#define IS_AMO_PHYS_ADDRESS(x) (((u64)(x) & (REGION_BITS | AS_MASK)) == AMO_PHYS_BASE)
+#define IS_AMO_ADDRESS(x)      (((u64)(x) & (RGN_BITS | AS_MASK)) == AMO_BASE)
+#define IS_AMO_PHYS_ADDRESS(x) (((u64)(x) & (RGN_BITS | AS_MASK)) == AMO_PHYS_BASE)
 
 
 /*
 #define TIO_SWIN_BASE(n, w)            (TIO_IO_BASE(n) + \
                                            ((u64) (w) << TIO_SWIN_SIZE_BITS))
 #define NODE_IO_BASE(n)                        (GLOBAL_MMR_SPACE | NASID_SPACE(n))
-#define TIO_IO_BASE(n)                  (UNCACHED | NASID_SPACE(n))
+#define TIO_IO_BASE(n)                  (__IA64_UNCACHED_OFFSET | NASID_SPACE(n))
 #define BWIN_SIZE                      (1UL << BWIN_SIZE_BITS)
 #define NODE_BWIN_BASE0(n)             (NODE_IO_BASE(n) + BWIN_SIZE)
 #define NODE_BWIN_BASE(n, w)           (NODE_BWIN_BASE0(n) + ((u64) (w) << BWIN_SIZE_BITS))
 #define RAW_NODE_SWIN_BASE(n, w)       (NODE_IO_BASE(n) + ((u64) (w) << SWIN_SIZE_BITS))
 #define BWIN_WIDGET_MASK               0x7
 #define BWIN_WINDOWNUM(x)              (((x) >> BWIN_SIZE_BITS) & BWIN_WIDGET_MASK)
+#define SH1_IS_BIG_WINDOW_ADDR(x)      ((x) & BWIN_TOP)
 
 #define TIO_BWIN_WINDOW_SELECT_MASK    0x7
 #define TIO_BWIN_WINDOWNUM(x)          (((x) >> TIO_BWIN_SIZE_BITS) & TIO_BWIN_WINDOW_SELECT_MASK)
 
-
+#define TIO_HWIN_SHIFT_BITS            33
+#define TIO_HWIN(x)                    (NODE_OFFSET(x) >> TIO_HWIN_SHIFT_BITS)
 
 /*
  * The following definitions pertain to the IO special address
 #define TIO_SWIN_WIDGETNUM(x)          (((x)  >> TIO_SWIN_SIZE_BITS) & TIO_SWIN_WIDGET_MASK)
 
 
-#define TIO_IOSPACE_ADDR(n,x)                                  \
-       /* Move in the Chiplet ID for TIO Local Block MMR */    \
-       (REMOTE_ADDR(n,x) | 1UL << (NASID_SHIFT - 2))
-
 /*
  * The following macros produce the correct base virtual address for
  * the hub registers. The REMOTE_HUB_* macro produce
  *     Otherwise, the recommended approach is to use *_HUB_L() and *_HUB_S().
  *     They're always safe.
  */
+/* Shub1 TIO & MMR addressing macros */
+#define SH1_TIO_IOSPACE_ADDR(n,x)                                      \
+       GLOBAL_MMR_ADDR(n,x)
+
+#define SH1_REMOTE_BWIN_MMR(n,x)                                       \
+       GLOBAL_MMR_ADDR(n,x)
+
+#define SH1_REMOTE_SWIN_MMR(n,x)                                       \
+       (NODE_SWIN_BASE(n,1) + 0x800000UL + (x))
+
+#define SH1_REMOTE_MMR(n,x)                                            \
+       (SH1_IS_BIG_WINDOW_ADDR(x) ? SH1_REMOTE_BWIN_MMR(n,x) :         \
+               SH1_REMOTE_SWIN_MMR(n,x))
+
+/* Shub1 TIO & MMR addressing macros */
+#define SH2_TIO_IOSPACE_ADDR(n,x)                                      \
+       ((__IA64_UNCACHED_OFFSET | REMOTE_ADDR(n,x) | 1UL << (NASID_SHIFT - 2)))
+
+#define SH2_REMOTE_MMR(n,x)                                            \
+       GLOBAL_MMR_ADDR(n,x)
+
+
+/* TIO & MMR addressing macros that work on both shub1 & shub2 */
+#define TIO_IOSPACE_ADDR(n,x)                                          \
+       ((u64 *)(is_shub1() ? SH1_TIO_IOSPACE_ADDR(n,x) :               \
+                SH2_TIO_IOSPACE_ADDR(n,x)))
+
+#define SH_REMOTE_MMR(n,x)                                             \
+       (is_shub1() ? SH1_REMOTE_MMR(n,x) : SH2_REMOTE_MMR(n,x))
+
 #define REMOTE_HUB_ADDR(n,x)                                           \
-       ((n & 1) ?                                                      \
-       /* TIO: */                                                      \
-       (is_shub2() ?                                                   \
-       /* TIO on Shub2 */                                              \
-       (volatile u64 *)(TIO_IOSPACE_ADDR(n,x))                         \
-       : /* TIO on shub1 */                                            \
-       (volatile u64 *)(GLOBAL_MMR_ADDR(n,x)))                         \
-                                                                       \
-       : /* SHUB1 and SHUB2 MMRs: */                                   \
-       (((x) & BWIN_TOP) ? ((volatile u64 *)(GLOBAL_MMR_ADDR(n,x)))    \
-       : ((volatile u64 *)(NODE_SWIN_BASE(n,1) + 0x800000 + (x)))))
+       (IS_TIO_NASID(n) ?  ((volatile u64*)TIO_IOSPACE_ADDR(n,x)) :    \
+        ((volatile u64*)SH_REMOTE_MMR(n,x)))
+
 
 #define HUB_L(x)                       (*((volatile typeof(*x) *)x))
 #define        HUB_S(x,d)                      (*((volatile typeof(*x) *)x) = (d))
index 84b254603b8d18ed2a046c98f083873ab9e8ce54..f083c94340663319cda9ccccdcfbcc8a8409875d 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_IA64_SN_GEO_H
@@ -108,7 +108,6 @@ typedef union geoid_u {
 #define INVALID_SLAB            (slabid_t)-1
 #define INVALID_SLOT            (slotid_t)-1
 #define INVALID_MODULE          ((moduleid_t)-1)
-#define INVALID_PARTID          ((partid_t)-1)
 
 static inline slabid_t geo_slab(geoid_t g)
 {
index e190dd4213d56233938104e66cd1b93958abd99e..e35074f526d9fb8c146dcc6f97be49ca094d7d25 100644 (file)
 #include <linux/rcupdate.h>
 
 #define SGI_UART_VECTOR                (0xe9)
-#define SGI_PCIBR_ERROR                (0x33)
 
 /* Reserved IRQs : Note, not to exceed IA64_SN2_FIRST_DEVICE_VECTOR */
 #define SGI_XPC_ACTIVATE                (0x30)
 #define SGI_II_ERROR                    (0x31)
 #define SGI_XBOW_ERROR                  (0x32)
-#define SGI_PCIBR_ERROR                 (0x33)
+#define SGI_PCIASIC_ERROR               (0x33)
 #define SGI_ACPI_SCI_INT                (0x34)
 #define SGI_TIOCA_ERROR                 (0x35)
 #define SGI_TIO_ERROR                   (0x36)
index 7138b1eafd6b46d48a5f83f10fc7606eb1885ef7..47bb8100fd00e93a972511f7612a6999e92badfb 100644 (file)
@@ -37,7 +37,6 @@ struct phys_cpuid {
 
 struct nodepda_s {
        void            *pdinfo;        /* Platform-dependent per-node info */
-       spinlock_t              bist_lock;
 
        /*
         * The BTEs on this node are shared by the local cpus
@@ -55,6 +54,8 @@ struct nodepda_s {
         * Array of physical cpu identifiers. Indexed by cpuid.
         */
        struct phys_cpuid       phys_cpuid[NR_CPUS];
+       spinlock_t              ptc_lock ____cacheline_aligned_in_smp;
+       spinlock_t              bist_lock;
 };
 
 typedef struct nodepda_s nodepda_t;
index 976f5eff0539ff283809c53ae304efbf37a156a3..ad0e8e8ae53fef47a2a6abaa3a5efaebf2090cce 100644 (file)
@@ -18,8 +18,9 @@
 #define PCIIO_ASIC_TYPE_PIC    2
 #define PCIIO_ASIC_TYPE_TIOCP  3
 #define PCIIO_ASIC_TYPE_TIOCA  4
+#define PCIIO_ASIC_TYPE_TIOCE  5
 
-#define PCIIO_ASIC_MAX_TYPES   5
+#define PCIIO_ASIC_MAX_TYPES   6
 
 /*
  * Common pciio bus provider data.  There should be one of these as the
@@ -30,7 +31,8 @@
 struct pcibus_bussoft {
        uint32_t                bs_asic_type;   /* chipset type */
        uint32_t                bs_xid;         /* xwidget id */
-       uint64_t                bs_persist_busnum; /* Persistent Bus Number */
+       uint32_t                bs_persist_busnum; /* Persistent Bus Number */
+       uint32_t                bs_persist_segment; /* Segment Number */
        uint64_t                bs_legacy_io;   /* legacy io pio addr */
        uint64_t                bs_legacy_mem;  /* legacy mem pio addr */
        uint64_t                bs_base;        /* widget base */
@@ -47,6 +49,8 @@ struct sn_pcibus_provider {
        dma_addr_t      (*dma_map_consistent)(struct pci_dev *, unsigned long, size_t);
        void            (*dma_unmap)(struct pci_dev *, dma_addr_t, int);
        void *          (*bus_fixup)(struct pcibus_bussoft *, struct pci_controller *);
+       void            (*force_interrupt)(struct sn_irq_info *);
+       void            (*target_interrupt)(struct sn_irq_info *);
 };
 
 extern struct sn_pcibus_provider *sn_pci_provider[];
index ea5590c76ca48eafc3505ced25ef048d1d8d1b0e..1c5108d44d8bf9f4ced5a99577546e650dfc95d2 100644 (file)
@@ -39,7 +39,6 @@ typedef struct pda_s {
        unsigned long pio_write_status_val;
        volatile unsigned long *pio_shub_war_cam_addr;
 
-       unsigned long   sn_soft_irr[4];
        unsigned long   sn_in_service_ivecs[4];
        int             sn_lb_int_war_ticks;
        int             sn_last_irq;
index df75f4c4aec3bfce3385f8f5cefe1eaafc3dd1d3..291ef3d69da225983ebf85dfd2c81523e77e5396 100644 (file)
@@ -43,6 +43,7 @@ struct sn_hwperf_object_info {
 
 /* macros for object classification */
 #define SN_HWPERF_IS_NODE(x)           ((x) && strstr((x)->name, "SHub"))
+#define SN_HWPERF_IS_NODE_SHUB2(x)     ((x) && strstr((x)->name, "SHub 2."))
 #define SN_HWPERF_IS_IONODE(x)         ((x) && strstr((x)->name, "TIO"))
 #define SN_HWPERF_IS_ROUTER(x)         ((x) && strstr((x)->name, "Router"))
 #define SN_HWPERF_IS_NL3ROUTER(x)      ((x) && strstr((x)->name, "NL3Router"))
@@ -214,6 +215,15 @@ struct sn_hwperf_ioctl_args {
  */
 #define SN_HWPERF_GET_NODE_NASID       (102|SN_HWPERF_OP_MEM_COPYOUT)
 
+/*
+ * Given a node id, determine the id of the nearest node with CPUs
+ * and the id of the nearest node that has memory. The argument
+ * node would normally be a "headless" node, e.g. an "IO node".
+ * Return 0 on success.
+ */
+extern int sn_hwperf_get_nearest_node(cnodeid_t node,
+       cnodeid_t *near_mem, cnodeid_t *near_cpu);
+
 /* return codes */
 #define SN_HWPERF_OP_OK                        0
 #define SN_HWPERF_OP_NOMEM             1
index 27976d22318657e56fcdc48833cf993a887309b1..e67825ad1930cee26dca3971b5c674f1e21c79e1 100644 (file)
@@ -55,7 +55,6 @@
 #define  SN_SAL_BUS_CONFIG                        0x02000037
 #define  SN_SAL_SYS_SERIAL_GET                    0x02000038
 #define  SN_SAL_PARTITION_SERIAL_GET              0x02000039
-#define  SN_SAL_SYSCTL_PARTITION_GET              0x0200003a
 #define  SN_SAL_SYSTEM_POWER_DOWN                 0x0200003b
 #define  SN_SAL_GET_MASTER_BASEIO_NASID                   0x0200003c
 #define  SN_SAL_COHERENCE                          0x0200003d
@@ -78,7 +77,8 @@
 
 #define SN_SAL_HUB_ERROR_INTERRUPT                0x02000060
 #define SN_SAL_BTE_RECOVER                        0x02000061
-#define SN_SAL_IOIF_GET_PCI_TOPOLOGY              0x02000062
+#define SN_SAL_RESERVED_DO_NOT_USE                0x02000062
+#define SN_SAL_IOIF_GET_PCI_TOPOLOGY              0x02000064
 
 /*
  * Service-specific constants
@@ -585,35 +585,6 @@ sn_partition_serial_number_val(void) {
        return sn_partition_serial_number;
 }
 
-/*
- * Returns the partition id of the nasid passed in as an argument,
- * or INVALID_PARTID if the partition id cannot be retrieved.
- */
-static inline partid_t
-ia64_sn_sysctl_partition_get(nasid_t nasid)
-{
-       struct ia64_sal_retval ret_stuff;
-       ia64_sal_oemcall_nolock(&ret_stuff, SN_SAL_SYSCTL_PARTITION_GET, nasid,
-                               0, 0, 0, 0, 0, 0);
-       if (ret_stuff.status != 0)
-           return INVALID_PARTID;
-       return ((partid_t)ret_stuff.v0);
-}
-
-/*
- * Returns the partition id of the current processor.
- */
-
-extern partid_t sn_partid;
-
-static inline partid_t
-sn_local_partid(void) {
-       if (unlikely(sn_partid < 0)) {
-               sn_partid = ia64_sn_sysctl_partition_get(cpuid_to_nasid(smp_processor_id()));
-       }
-       return sn_partid;
-}
-
 /*
  * Returns the physical address of the partition's reserved page through
  * an iterative number of calls.
@@ -749,7 +720,8 @@ ia64_sn_power_down(void)
 {
        struct ia64_sal_retval ret_stuff;
        SAL_CALL(ret_stuff, SN_SAL_SYSTEM_POWER_DOWN, 0, 0, 0, 0, 0, 0, 0);
-       while(1);
+       while(1)
+               cpu_relax();
        /* never returns */
 }
 
@@ -1018,24 +990,6 @@ ia64_sn_get_sn_info(int fc, u8 *shubtype, u16 *nasid_bitmask, u8 *nasid_shift,
        ret_stuff.v2 = 0;
        SAL_CALL_NOLOCK(ret_stuff, SN_SAL_GET_SN_INFO, fc, 0, 0, 0, 0, 0, 0);
 
-/***** BEGIN HACK - temp til old proms no longer supported ********/
-       if (ret_stuff.status == SALRET_NOT_IMPLEMENTED) {
-               int nasid = get_sapicid() & 0xfff;;
-#define SH_SHUB_ID_NODES_PER_BIT_MASK 0x001f000000000000UL                                               
-#define SH_SHUB_ID_NODES_PER_BIT_SHFT 48                                                               
-               if (shubtype) *shubtype = 0;
-               if (nasid_bitmask) *nasid_bitmask = 0x7ff;
-               if (nasid_shift) *nasid_shift = 38;
-               if (systemsize) *systemsize = 11;
-               if (sharing_domain_size) *sharing_domain_size = 9;
-               if (partid) *partid = ia64_sn_sysctl_partition_get(nasid);
-               if (coher) *coher = nasid >> 9;
-               if (reg) *reg = (HUB_L((u64 *) LOCAL_MMR_ADDR(SH1_SHUB_ID)) & SH_SHUB_ID_NODES_PER_BIT_MASK) >>
-                       SH_SHUB_ID_NODES_PER_BIT_SHFT;
-               return 0;
-       }
-/***** END HACK *******/
-
        if (ret_stuff.status < 0)
                return ret_stuff.status;
 
@@ -1068,12 +1022,10 @@ ia64_sn_hwperf_op(nasid_t nasid, u64 opcode, u64 a0, u64 a1, u64 a2,
 }
 
 static inline int
-ia64_sn_ioif_get_pci_topology(u64 rack, u64 bay, u64 slot, u64 slab,
-                             u64 buf, u64 len)
+ia64_sn_ioif_get_pci_topology(u64 buf, u64 len)
 {
        struct ia64_sal_retval rv;
-       SAL_CALL_NOLOCK(rv, SN_SAL_IOIF_GET_PCI_TOPOLOGY,
-               rack, bay, slot, slab, buf, len, 0);
+       SAL_CALL_NOLOCK(rv, SN_SAL_IOIF_GET_PCI_TOPOLOGY, buf, len, 0, 0, 0, 0, 0);
        return (int) rv.status;
 }
 
diff --git a/include/asm-ia64/sn/tioce.h b/include/asm-ia64/sn/tioce.h
new file mode 100644 (file)
index 0000000..2287985
--- /dev/null
@@ -0,0 +1,740 @@
+/**************************************************************************
+ *                                                                        *
+ *  Unpublished copyright (c) 2005, Silicon Graphics, Inc.                *
+ *  THIS IS UNPUBLISHED CONFIDENTIAL AND PROPRIETARY SOURCE CODE OF SGI.  *
+ *                                                                        *
+ *  The copyright notice above does  not evidence any actual or intended  *
+ *  publication  or  disclosure  of  this source  code,  which  includes  *
+ *  information that is confidential  and/or proprietary, and is a trade  *
+ *  secret, of  Silicon Graphics, Inc.   ANY REPRODUCTION, MODIFICATION,  *
+ *  DISTRIBUTION, PUBLIC  PERFORMANCE, OR  PUBLIC DISPLAY OF  OR THROUGH  *
+ *  USE  OF THIS  SOURCE CODE  WITHOUT  THE EXPRESS  WRITTEN CONSENT  OF  *
+ *  SILICON GRAPHICS, INC.  IS  STRICTLY PROHIBITED, AND IN VIOLATION OF  *
+ *  APPLICABLE  LAWS   AND  INTERNATIONAL  TREATIES.    THE  RECEIPT  OR  *
+ *  POSSESSION OF  THIS SOURCE CODE AND/OR RELATED  INFORMATION DOES NOT  *
+ *  CONVEY OR IMPLY ANY RIGHTS  TO REPRODUCE, DISCLOSE OR DISTRIBUTE ITS  *
+ *  CONTENTS,  OR TO  MANUFACTURE, USE,  OR  SELL ANYTHING  THAT IT  MAY  *
+ *  DESCRIBE, IN WHOLE OR IN PART.                                        *
+ *                                                                        *
+ **************************************************************************/
+
+#ifndef __ASM_IA64_SN_TIOCE_H__
+#define __ASM_IA64_SN_TIOCE_H__
+
+/* CE ASIC part & mfgr information  */
+#define TIOCE_PART_NUM                 0xCE00
+#define TIOCE_MFGR_NUM                 0x36
+#define TIOCE_REV_A                    0x1
+
+/* CE Virtual PPB Vendor/Device IDs */
+#define CE_VIRT_PPB_VENDOR_ID          0x10a9
+#define CE_VIRT_PPB_DEVICE_ID          0x4002
+
+/* CE Host Bridge Vendor/Device IDs */
+#define CE_HOST_BRIDGE_VENDOR_ID       0x10a9
+#define CE_HOST_BRIDGE_DEVICE_ID       0x4003
+
+
+#define TIOCE_NUM_M40_ATES             4096
+#define TIOCE_NUM_M3240_ATES           2048
+#define TIOCE_NUM_PORTS                        2
+
+/*
+ * Register layout for TIOCE.  MMR offsets are shown at the far right of the
+ * structure definition.
+ */
+typedef volatile struct tioce {
+       /*
+        * ADMIN : Administration Registers
+        */
+       uint64_t        ce_adm_id;                              /* 0x000000 */
+       uint64_t        ce_pad_000008;                          /* 0x000008 */
+       uint64_t        ce_adm_dyn_credit_status;               /* 0x000010 */
+       uint64_t        ce_adm_last_credit_status;              /* 0x000018 */
+       uint64_t        ce_adm_credit_limit;                    /* 0x000020 */
+       uint64_t        ce_adm_force_credit;                    /* 0x000028 */
+       uint64_t        ce_adm_control;                         /* 0x000030 */
+       uint64_t        ce_adm_mmr_chn_timeout;                 /* 0x000038 */
+       uint64_t        ce_adm_ssp_ure_timeout;                 /* 0x000040 */
+       uint64_t        ce_adm_ssp_dre_timeout;                 /* 0x000048 */
+       uint64_t        ce_adm_ssp_debug_sel;                   /* 0x000050 */
+       uint64_t        ce_adm_int_status;                      /* 0x000058 */
+       uint64_t        ce_adm_int_status_alias;                /* 0x000060 */
+       uint64_t        ce_adm_int_mask;                        /* 0x000068 */
+       uint64_t        ce_adm_int_pending;                     /* 0x000070 */
+       uint64_t        ce_adm_force_int;                       /* 0x000078 */
+       uint64_t        ce_adm_ure_ups_buf_barrier_flush;       /* 0x000080 */
+       uint64_t        ce_adm_int_dest[15];        /* 0x000088 -- 0x0000F8 */
+       uint64_t        ce_adm_error_summary;                   /* 0x000100 */
+       uint64_t        ce_adm_error_summary_alias;             /* 0x000108 */
+       uint64_t        ce_adm_error_mask;                      /* 0x000110 */
+       uint64_t        ce_adm_first_error;                     /* 0x000118 */
+       uint64_t        ce_adm_error_overflow;                  /* 0x000120 */
+       uint64_t        ce_adm_error_overflow_alias;            /* 0x000128 */
+       uint64_t        ce_pad_000130[2];           /* 0x000130 -- 0x000138 */
+       uint64_t        ce_adm_tnum_error;                      /* 0x000140 */
+       uint64_t        ce_adm_mmr_err_detail;                  /* 0x000148 */
+       uint64_t        ce_adm_msg_sram_perr_detail;            /* 0x000150 */
+       uint64_t        ce_adm_bap_sram_perr_detail;            /* 0x000158 */
+       uint64_t        ce_adm_ce_sram_perr_detail;             /* 0x000160 */
+       uint64_t        ce_adm_ce_credit_oflow_detail;          /* 0x000168 */
+       uint64_t        ce_adm_tx_link_idle_max_timer;          /* 0x000170 */
+       uint64_t        ce_adm_pcie_debug_sel;                  /* 0x000178 */
+       uint64_t        ce_pad_000180[16];          /* 0x000180 -- 0x0001F8 */
+
+       uint64_t        ce_adm_pcie_debug_sel_top;              /* 0x000200 */
+       uint64_t        ce_adm_pcie_debug_lat_sel_lo_top;       /* 0x000208 */
+       uint64_t        ce_adm_pcie_debug_lat_sel_hi_top;       /* 0x000210 */
+       uint64_t        ce_adm_pcie_debug_trig_sel_top;         /* 0x000218 */
+       uint64_t        ce_adm_pcie_debug_trig_lat_sel_lo_top;  /* 0x000220 */
+       uint64_t        ce_adm_pcie_debug_trig_lat_sel_hi_top;  /* 0x000228 */
+       uint64_t        ce_adm_pcie_trig_compare_top;           /* 0x000230 */
+       uint64_t        ce_adm_pcie_trig_compare_en_top;        /* 0x000238 */
+       uint64_t        ce_adm_ssp_debug_sel_top;               /* 0x000240 */
+       uint64_t        ce_adm_ssp_debug_lat_sel_lo_top;        /* 0x000248 */
+       uint64_t        ce_adm_ssp_debug_lat_sel_hi_top;        /* 0x000250 */
+       uint64_t        ce_adm_ssp_debug_trig_sel_top;          /* 0x000258 */
+       uint64_t        ce_adm_ssp_debug_trig_lat_sel_lo_top;   /* 0x000260 */
+       uint64_t        ce_adm_ssp_debug_trig_lat_sel_hi_top;   /* 0x000268 */
+       uint64_t        ce_adm_ssp_trig_compare_top;            /* 0x000270 */
+       uint64_t        ce_adm_ssp_trig_compare_en_top;         /* 0x000278 */
+       uint64_t        ce_pad_000280[48];          /* 0x000280 -- 0x0003F8 */
+
+       uint64_t        ce_adm_bap_ctrl;                        /* 0x000400 */
+       uint64_t        ce_pad_000408[127];         /* 0x000408 -- 0x0007F8 */
+
+       uint64_t        ce_msg_buf_data63_0[35];    /* 0x000800 -- 0x000918 */
+       uint64_t        ce_pad_000920[29];          /* 0x000920 -- 0x0009F8 */
+
+       uint64_t        ce_msg_buf_data127_64[35];  /* 0x000A00 -- 0x000B18 */
+       uint64_t        ce_pad_000B20[29];          /* 0x000B20 -- 0x000BF8 */
+
+       uint64_t        ce_msg_buf_parity[35];      /* 0x000C00 -- 0x000D18 */
+       uint64_t        ce_pad_000D20[29];          /* 0x000D20 -- 0x000DF8 */
+
+       uint64_t        ce_pad_000E00[576];         /* 0x000E00 -- 0x001FF8 */
+
+       /*
+        * LSI : LSI's PCI Express Link Registers (Link#1 and Link#2)
+        * Link#1 MMRs at start at 0x002000, Link#2 MMRs at 0x003000
+        * NOTE: the comment offsets at far right: let 'z' = {2 or 3}
+        */
+       #define ce_lsi(link_num)        ce_lsi[link_num-1]
+       struct ce_lsi_reg {
+               uint64_t        ce_lsi_lpu_id;                  /* 0x00z000 */
+               uint64_t        ce_lsi_rst;                     /* 0x00z008 */
+               uint64_t        ce_lsi_dbg_stat;                /* 0x00z010 */
+               uint64_t        ce_lsi_dbg_cfg;                 /* 0x00z018 */
+               uint64_t        ce_lsi_ltssm_ctrl;              /* 0x00z020 */
+               uint64_t        ce_lsi_lk_stat;                 /* 0x00z028 */
+               uint64_t        ce_pad_00z030[2];   /* 0x00z030 -- 0x00z038 */
+               uint64_t        ce_lsi_int_and_stat;            /* 0x00z040 */
+               uint64_t        ce_lsi_int_mask;                /* 0x00z048 */
+               uint64_t        ce_pad_00z050[22];  /* 0x00z050 -- 0x00z0F8 */
+               uint64_t        ce_lsi_lk_perf_cnt_sel;         /* 0x00z100 */
+               uint64_t        ce_pad_00z108;                  /* 0x00z108 */
+               uint64_t        ce_lsi_lk_perf_cnt_ctrl;        /* 0x00z110 */
+               uint64_t        ce_pad_00z118;                  /* 0x00z118 */
+               uint64_t        ce_lsi_lk_perf_cnt1;            /* 0x00z120 */
+               uint64_t        ce_lsi_lk_perf_cnt1_test;       /* 0x00z128 */
+               uint64_t        ce_lsi_lk_perf_cnt2;            /* 0x00z130 */
+               uint64_t        ce_lsi_lk_perf_cnt2_test;       /* 0x00z138 */
+               uint64_t        ce_pad_00z140[24];  /* 0x00z140 -- 0x00z1F8 */
+               uint64_t        ce_lsi_lk_lyr_cfg;              /* 0x00z200 */
+               uint64_t        ce_lsi_lk_lyr_status;           /* 0x00z208 */
+               uint64_t        ce_lsi_lk_lyr_int_stat;         /* 0x00z210 */
+               uint64_t        ce_lsi_lk_ly_int_stat_test;     /* 0x00z218 */
+               uint64_t        ce_lsi_lk_ly_int_stat_mask;     /* 0x00z220 */
+               uint64_t        ce_pad_00z228[3];   /* 0x00z228 -- 0x00z238 */
+               uint64_t        ce_lsi_fc_upd_ctl;              /* 0x00z240 */
+               uint64_t        ce_pad_00z248[3];   /* 0x00z248 -- 0x00z258 */
+               uint64_t        ce_lsi_flw_ctl_upd_to_timer;    /* 0x00z260 */
+               uint64_t        ce_lsi_flw_ctl_upd_timer0;      /* 0x00z268 */
+               uint64_t        ce_lsi_flw_ctl_upd_timer1;      /* 0x00z270 */
+               uint64_t        ce_pad_00z278[49];  /* 0x00z278 -- 0x00z3F8 */
+               uint64_t        ce_lsi_freq_nak_lat_thrsh;      /* 0x00z400 */
+               uint64_t        ce_lsi_ack_nak_lat_tmr;         /* 0x00z408 */
+               uint64_t        ce_lsi_rply_tmr_thr;            /* 0x00z410 */
+               uint64_t        ce_lsi_rply_tmr;                /* 0x00z418 */
+               uint64_t        ce_lsi_rply_num_stat;           /* 0x00z420 */
+               uint64_t        ce_lsi_rty_buf_max_addr;        /* 0x00z428 */
+               uint64_t        ce_lsi_rty_fifo_ptr;            /* 0x00z430 */
+               uint64_t        ce_lsi_rty_fifo_rd_wr_ptr;      /* 0x00z438 */
+               uint64_t        ce_lsi_rty_fifo_cred;           /* 0x00z440 */
+               uint64_t        ce_lsi_seq_cnt;                 /* 0x00z448 */
+               uint64_t        ce_lsi_ack_sent_seq_num;        /* 0x00z450 */
+               uint64_t        ce_lsi_seq_cnt_fifo_max_addr;   /* 0x00z458 */
+               uint64_t        ce_lsi_seq_cnt_fifo_ptr;        /* 0x00z460 */
+               uint64_t        ce_lsi_seq_cnt_rd_wr_ptr;       /* 0x00z468 */
+               uint64_t        ce_lsi_tx_lk_ts_ctl;            /* 0x00z470 */
+               uint64_t        ce_pad_00z478;                  /* 0x00z478 */
+               uint64_t        ce_lsi_mem_addr_ctl;            /* 0x00z480 */
+               uint64_t        ce_lsi_mem_d_ld0;               /* 0x00z488 */
+               uint64_t        ce_lsi_mem_d_ld1;               /* 0x00z490 */
+               uint64_t        ce_lsi_mem_d_ld2;               /* 0x00z498 */
+               uint64_t        ce_lsi_mem_d_ld3;               /* 0x00z4A0 */
+               uint64_t        ce_lsi_mem_d_ld4;               /* 0x00z4A8 */
+               uint64_t        ce_pad_00z4B0[2];   /* 0x00z4B0 -- 0x00z4B8 */
+               uint64_t        ce_lsi_rty_d_cnt;               /* 0x00z4C0 */
+               uint64_t        ce_lsi_seq_buf_cnt;             /* 0x00z4C8 */
+               uint64_t        ce_lsi_seq_buf_bt_d;            /* 0x00z4D0 */
+               uint64_t        ce_pad_00z4D8;                  /* 0x00z4D8 */
+               uint64_t        ce_lsi_ack_lat_thr;             /* 0x00z4E0 */
+               uint64_t        ce_pad_00z4E8[3];   /* 0x00z4E8 -- 0x00z4F8 */
+               uint64_t        ce_lsi_nxt_rcv_seq_1_cntr;      /* 0x00z500 */
+               uint64_t        ce_lsi_unsp_dllp_rcvd;          /* 0x00z508 */
+               uint64_t        ce_lsi_rcv_lk_ts_ctl;           /* 0x00z510 */
+               uint64_t        ce_pad_00z518[29];  /* 0x00z518 -- 0x00z5F8 */
+               uint64_t        ce_lsi_phy_lyr_cfg;             /* 0x00z600 */
+               uint64_t        ce_pad_00z608;                  /* 0x00z608 */
+               uint64_t        ce_lsi_phy_lyr_int_stat;        /* 0x00z610 */
+               uint64_t        ce_lsi_phy_lyr_int_stat_test;   /* 0x00z618 */
+               uint64_t        ce_lsi_phy_lyr_int_mask;        /* 0x00z620 */
+               uint64_t        ce_pad_00z628[11];  /* 0x00z628 -- 0x00z678 */
+               uint64_t        ce_lsi_rcv_phy_cfg;             /* 0x00z680 */
+               uint64_t        ce_lsi_rcv_phy_stat1;           /* 0x00z688 */
+               uint64_t        ce_lsi_rcv_phy_stat2;           /* 0x00z690 */
+               uint64_t        ce_lsi_rcv_phy_stat3;           /* 0x00z698 */
+               uint64_t        ce_lsi_rcv_phy_int_stat;        /* 0x00z6A0 */
+               uint64_t        ce_lsi_rcv_phy_int_stat_test;   /* 0x00z6A8 */
+               uint64_t        ce_lsi_rcv_phy_int_mask;        /* 0x00z6B0 */
+               uint64_t        ce_pad_00z6B8[9];   /* 0x00z6B8 -- 0x00z6F8 */
+               uint64_t        ce_lsi_tx_phy_cfg;              /* 0x00z700 */
+               uint64_t        ce_lsi_tx_phy_stat;             /* 0x00z708 */
+               uint64_t        ce_lsi_tx_phy_int_stat;         /* 0x00z710 */
+               uint64_t        ce_lsi_tx_phy_int_stat_test;    /* 0x00z718 */
+               uint64_t        ce_lsi_tx_phy_int_mask;         /* 0x00z720 */
+               uint64_t        ce_lsi_tx_phy_stat2;            /* 0x00z728 */
+               uint64_t        ce_pad_00z730[10];  /* 0x00z730 -- 0x00z77F */
+               uint64_t        ce_lsi_ltssm_cfg1;              /* 0x00z780 */
+               uint64_t        ce_lsi_ltssm_cfg2;              /* 0x00z788 */
+               uint64_t        ce_lsi_ltssm_cfg3;              /* 0x00z790 */
+               uint64_t        ce_lsi_ltssm_cfg4;              /* 0x00z798 */
+               uint64_t        ce_lsi_ltssm_cfg5;              /* 0x00z7A0 */
+               uint64_t        ce_lsi_ltssm_stat1;             /* 0x00z7A8 */
+               uint64_t        ce_lsi_ltssm_stat2;             /* 0x00z7B0 */
+               uint64_t        ce_lsi_ltssm_int_stat;          /* 0x00z7B8 */
+               uint64_t        ce_lsi_ltssm_int_stat_test;     /* 0x00z7C0 */
+               uint64_t        ce_lsi_ltssm_int_mask;          /* 0x00z7C8 */
+               uint64_t        ce_lsi_ltssm_stat_wr_en;        /* 0x00z7D0 */
+               uint64_t        ce_pad_00z7D8[5];   /* 0x00z7D8 -- 0x00z7F8 */
+               uint64_t        ce_lsi_gb_cfg1;                 /* 0x00z800 */
+               uint64_t        ce_lsi_gb_cfg2;                 /* 0x00z808 */
+               uint64_t        ce_lsi_gb_cfg3;                 /* 0x00z810 */
+               uint64_t        ce_lsi_gb_cfg4;                 /* 0x00z818 */
+               uint64_t        ce_lsi_gb_stat;                 /* 0x00z820 */
+               uint64_t        ce_lsi_gb_int_stat;             /* 0x00z828 */
+               uint64_t        ce_lsi_gb_int_stat_test;        /* 0x00z830 */
+               uint64_t        ce_lsi_gb_int_mask;             /* 0x00z838 */
+               uint64_t        ce_lsi_gb_pwr_dn1;              /* 0x00z840 */
+               uint64_t        ce_lsi_gb_pwr_dn2;              /* 0x00z848 */
+               uint64_t        ce_pad_00z850[246]; /* 0x00z850 -- 0x00zFF8 */
+       } ce_lsi[2];
+
+       uint64_t        ce_pad_004000[10];          /* 0x004000 -- 0x004048 */
+
+       /*
+        * CRM: Coretalk Receive Module Registers
+        */
+       uint64_t        ce_crm_debug_mux;                       /* 0x004050 */
+       uint64_t        ce_pad_004058;                          /* 0x004058 */
+       uint64_t        ce_crm_ssp_err_cmd_wrd;                 /* 0x004060 */
+       uint64_t        ce_crm_ssp_err_addr;                    /* 0x004068 */
+       uint64_t        ce_crm_ssp_err_syn;                     /* 0x004070 */
+
+       uint64_t        ce_pad_004078[499];         /* 0x004078 -- 0x005008 */
+
+       /*
+         * CXM: Coretalk Xmit Module Registers
+         */
+       uint64_t        ce_cxm_dyn_credit_status;               /* 0x005010 */
+       uint64_t        ce_cxm_last_credit_status;              /* 0x005018 */
+       uint64_t        ce_cxm_credit_limit;                    /* 0x005020 */
+       uint64_t        ce_cxm_force_credit;                    /* 0x005028 */
+       uint64_t        ce_cxm_disable_bypass;                  /* 0x005030 */
+       uint64_t        ce_pad_005038[3];           /* 0x005038 -- 0x005048 */
+       uint64_t        ce_cxm_debug_mux;                       /* 0x005050 */
+
+        uint64_t        ce_pad_005058[501];         /* 0x005058 -- 0x005FF8 */
+
+       /*
+        * DTL: Downstream Transaction Layer Regs (Link#1 and Link#2)
+        * DTL: Link#1 MMRs at start at 0x006000, Link#2 MMRs at 0x008000
+        * DTL: the comment offsets at far right: let 'y' = {6 or 8}
+        *
+        * UTL: Downstream Transaction Layer Regs (Link#1 and Link#2)
+        * UTL: Link#1 MMRs at start at 0x007000, Link#2 MMRs at 0x009000
+        * UTL: the comment offsets at far right: let 'z' = {7 or 9}
+        */
+       #define ce_dtl(link_num)        ce_dtl_utl[link_num-1]
+       #define ce_utl(link_num)        ce_dtl_utl[link_num-1]
+       struct ce_dtl_utl_reg {
+               /* DTL */
+               uint64_t        ce_dtl_dtdr_credit_limit;       /* 0x00y000 */
+               uint64_t        ce_dtl_dtdr_credit_force;       /* 0x00y008 */
+               uint64_t        ce_dtl_dyn_credit_status;       /* 0x00y010 */
+               uint64_t        ce_dtl_dtl_last_credit_stat;    /* 0x00y018 */
+               uint64_t        ce_dtl_dtl_ctrl;                /* 0x00y020 */
+               uint64_t        ce_pad_00y028[5];   /* 0x00y028 -- 0x00y048 */
+               uint64_t        ce_dtl_debug_sel;               /* 0x00y050 */
+               uint64_t        ce_pad_00y058[501]; /* 0x00y058 -- 0x00yFF8 */
+
+               /* UTL */
+               uint64_t        ce_utl_utl_ctrl;                /* 0x00z000 */
+               uint64_t        ce_utl_debug_sel;               /* 0x00z008 */
+               uint64_t        ce_pad_00z010[510]; /* 0x00z010 -- 0x00zFF8 */
+       } ce_dtl_utl[2];
+
+       uint64_t        ce_pad_00A000[514];         /* 0x00A000 -- 0x00B008 */
+
+       /*
+        * URE: Upstream Request Engine
+         */
+       uint64_t        ce_ure_dyn_credit_status;               /* 0x00B010 */
+       uint64_t        ce_ure_last_credit_status;              /* 0x00B018 */
+       uint64_t        ce_ure_credit_limit;                    /* 0x00B020 */
+       uint64_t        ce_pad_00B028;                          /* 0x00B028 */
+       uint64_t        ce_ure_control;                         /* 0x00B030 */
+       uint64_t        ce_ure_status;                          /* 0x00B038 */
+       uint64_t        ce_pad_00B040[2];           /* 0x00B040 -- 0x00B048 */
+       uint64_t        ce_ure_debug_sel;                       /* 0x00B050 */
+       uint64_t        ce_ure_pcie_debug_sel;                  /* 0x00B058 */
+       uint64_t        ce_ure_ssp_err_cmd_wrd;                 /* 0x00B060 */
+       uint64_t        ce_ure_ssp_err_addr;                    /* 0x00B068 */
+       uint64_t        ce_ure_page_map;                        /* 0x00B070 */
+       uint64_t        ce_ure_dir_map[TIOCE_NUM_PORTS];        /* 0x00B078 */
+       uint64_t        ce_ure_pipe_sel1;                       /* 0x00B088 */
+       uint64_t        ce_ure_pipe_mask1;                      /* 0x00B090 */
+       uint64_t        ce_ure_pipe_sel2;                       /* 0x00B098 */
+       uint64_t        ce_ure_pipe_mask2;                      /* 0x00B0A0 */
+       uint64_t        ce_ure_pcie1_credits_sent;              /* 0x00B0A8 */
+       uint64_t        ce_ure_pcie1_credits_used;              /* 0x00B0B0 */
+       uint64_t        ce_ure_pcie1_credit_limit;              /* 0x00B0B8 */
+       uint64_t        ce_ure_pcie2_credits_sent;              /* 0x00B0C0 */
+       uint64_t        ce_ure_pcie2_credits_used;              /* 0x00B0C8 */
+       uint64_t        ce_ure_pcie2_credit_limit;              /* 0x00B0D0 */
+       uint64_t        ce_ure_pcie_force_credit;               /* 0x00B0D8 */
+       uint64_t        ce_ure_rd_tnum_val;                     /* 0x00B0E0 */
+       uint64_t        ce_ure_rd_tnum_rsp_rcvd;                /* 0x00B0E8 */
+       uint64_t        ce_ure_rd_tnum_esent_timer;             /* 0x00B0F0 */
+       uint64_t        ce_ure_rd_tnum_error;                   /* 0x00B0F8 */
+       uint64_t        ce_ure_rd_tnum_first_cl;                /* 0x00B100 */
+       uint64_t        ce_ure_rd_tnum_link_buf;                /* 0x00B108 */
+       uint64_t        ce_ure_wr_tnum_val;                     /* 0x00B110 */
+       uint64_t        ce_ure_sram_err_addr0;                  /* 0x00B118 */
+       uint64_t        ce_ure_sram_err_addr1;                  /* 0x00B120 */
+       uint64_t        ce_ure_sram_err_addr2;                  /* 0x00B128 */
+       uint64_t        ce_ure_sram_rd_addr0;                   /* 0x00B130 */
+       uint64_t        ce_ure_sram_rd_addr1;                   /* 0x00B138 */
+       uint64_t        ce_ure_sram_rd_addr2;                   /* 0x00B140 */
+       uint64_t        ce_ure_sram_wr_addr0;                   /* 0x00B148 */
+       uint64_t        ce_ure_sram_wr_addr1;                   /* 0x00B150 */
+       uint64_t        ce_ure_sram_wr_addr2;                   /* 0x00B158 */
+       uint64_t        ce_ure_buf_flush10;                     /* 0x00B160 */
+       uint64_t        ce_ure_buf_flush11;                     /* 0x00B168 */
+       uint64_t        ce_ure_buf_flush12;                     /* 0x00B170 */
+       uint64_t        ce_ure_buf_flush13;                     /* 0x00B178 */
+       uint64_t        ce_ure_buf_flush20;                     /* 0x00B180 */
+       uint64_t        ce_ure_buf_flush21;                     /* 0x00B188 */
+       uint64_t        ce_ure_buf_flush22;                     /* 0x00B190 */
+       uint64_t        ce_ure_buf_flush23;                     /* 0x00B198 */
+       uint64_t        ce_ure_pcie_control1;                   /* 0x00B1A0 */
+       uint64_t        ce_ure_pcie_control2;                   /* 0x00B1A8 */
+
+       uint64_t        ce_pad_00B1B0[458];         /* 0x00B1B0 -- 0x00BFF8 */
+
+       /* Upstream Data Buffer, Port1 */
+       struct ce_ure_maint_ups_dat1_data {
+               uint64_t        data63_0[512];      /* 0x00C000 -- 0x00CFF8 */
+               uint64_t        data127_64[512];    /* 0x00D000 -- 0x00DFF8 */
+               uint64_t        parity[512];        /* 0x00E000 -- 0x00EFF8 */
+       } ce_ure_maint_ups_dat1;
+
+       /* Upstream Header Buffer, Port1 */
+       struct ce_ure_maint_ups_hdr1_data {
+               uint64_t        data63_0[512];      /* 0x00F000 -- 0x00FFF8 */
+               uint64_t        data127_64[512];    /* 0x010000 -- 0x010FF8 */
+               uint64_t        parity[512];        /* 0x011000 -- 0x011FF8 */
+       } ce_ure_maint_ups_hdr1;
+
+       /* Upstream Data Buffer, Port2 */
+       struct ce_ure_maint_ups_dat2_data {
+               uint64_t        data63_0[512];      /* 0x012000 -- 0x012FF8 */
+               uint64_t        data127_64[512];    /* 0x013000 -- 0x013FF8 */
+               uint64_t        parity[512];        /* 0x014000 -- 0x014FF8 */
+       } ce_ure_maint_ups_dat2;
+
+       /* Upstream Header Buffer, Port2 */
+       struct ce_ure_maint_ups_hdr2_data {
+               uint64_t        data63_0[512];      /* 0x015000 -- 0x015FF8 */
+               uint64_t        data127_64[512];    /* 0x016000 -- 0x016FF8 */
+               uint64_t        parity[512];        /* 0x017000 -- 0x017FF8 */
+       } ce_ure_maint_ups_hdr2;
+
+       /* Downstream Data Buffer */
+       struct ce_ure_maint_dns_dat_data {
+               uint64_t        data63_0[512];      /* 0x018000 -- 0x018FF8 */
+               uint64_t        data127_64[512];    /* 0x019000 -- 0x019FF8 */
+               uint64_t        parity[512];        /* 0x01A000 -- 0x01AFF8 */
+       } ce_ure_maint_dns_dat;
+
+       /* Downstream Header Buffer */
+       struct  ce_ure_maint_dns_hdr_data {
+               uint64_t        data31_0[64];       /* 0x01B000 -- 0x01B1F8 */
+               uint64_t        data95_32[64];      /* 0x01B200 -- 0x01B3F8 */
+               uint64_t        parity[64];         /* 0x01B400 -- 0x01B5F8 */
+       } ce_ure_maint_dns_hdr;
+
+       /* RCI Buffer Data */
+       struct  ce_ure_maint_rci_data {
+               uint64_t        data41_0[64];       /* 0x01B600 -- 0x01B7F8 */
+               uint64_t        data69_42[64];      /* 0x01B800 -- 0x01B9F8 */
+       } ce_ure_maint_rci;
+
+       /* Response Queue */
+       uint64_t        ce_ure_maint_rspq[64];      /* 0x01BA00 -- 0x01BBF8 */
+
+       uint64_t        ce_pad_01C000[4224];        /* 0x01BC00 -- 0x023FF8 */
+
+       /* Admin Build-a-Packet Buffer */
+       struct  ce_adm_maint_bap_buf_data {
+               uint64_t        data63_0[258];      /* 0x024000 -- 0x024808 */
+               uint64_t        data127_64[258];    /* 0x024810 -- 0x025018 */
+               uint64_t        parity[258];        /* 0x025020 -- 0x025828 */
+       } ce_adm_maint_bap_buf;
+
+       uint64_t        ce_pad_025830[5370];        /* 0x025830 -- 0x02FFF8 */
+
+       /* URE: 40bit PMU ATE Buffer */             /* 0x030000 -- 0x037FF8 */
+       uint64_t        ce_ure_ate40[TIOCE_NUM_M40_ATES];
+
+       /* URE: 32/40bit PMU ATE Buffer */          /* 0x038000 -- 0x03BFF8 */
+       uint64_t        ce_ure_ate3240[TIOCE_NUM_M3240_ATES];
+
+       uint64_t        ce_pad_03C000[2050];        /* 0x03C000 -- 0x040008 */
+
+       /*
+        * DRE: Down Stream Request Engine
+         */
+       uint64_t        ce_dre_dyn_credit_status1;              /* 0x040010 */
+       uint64_t        ce_dre_dyn_credit_status2;              /* 0x040018 */
+       uint64_t        ce_dre_last_credit_status1;             /* 0x040020 */
+       uint64_t        ce_dre_last_credit_status2;             /* 0x040028 */
+       uint64_t        ce_dre_credit_limit1;                   /* 0x040030 */
+       uint64_t        ce_dre_credit_limit2;                   /* 0x040038 */
+       uint64_t        ce_dre_force_credit1;                   /* 0x040040 */
+       uint64_t        ce_dre_force_credit2;                   /* 0x040048 */
+       uint64_t        ce_dre_debug_mux1;                      /* 0x040050 */
+       uint64_t        ce_dre_debug_mux2;                      /* 0x040058 */
+       uint64_t        ce_dre_ssp_err_cmd_wrd;                 /* 0x040060 */
+       uint64_t        ce_dre_ssp_err_addr;                    /* 0x040068 */
+       uint64_t        ce_dre_comp_err_cmd_wrd;                /* 0x040070 */
+       uint64_t        ce_dre_comp_err_addr;                   /* 0x040078 */
+       uint64_t        ce_dre_req_status;                      /* 0x040080 */
+       uint64_t        ce_dre_config1;                         /* 0x040088 */
+       uint64_t        ce_dre_config2;                         /* 0x040090 */
+       uint64_t        ce_dre_config_req_status;               /* 0x040098 */
+       uint64_t        ce_pad_0400A0[12];          /* 0x0400A0 -- 0x0400F8 */
+       uint64_t        ce_dre_dyn_fifo;                        /* 0x040100 */
+       uint64_t        ce_pad_040108[3];           /* 0x040108 -- 0x040118 */
+       uint64_t        ce_dre_last_fifo;                       /* 0x040120 */
+
+       uint64_t        ce_pad_040128[27];          /* 0x040128 -- 0x0401F8 */
+
+       /* DRE Downstream Head Queue */
+       struct  ce_dre_maint_ds_head_queue {
+               uint64_t        data63_0[32];       /* 0x040200 -- 0x0402F8 */
+               uint64_t        data127_64[32];     /* 0x040300 -- 0x0403F8 */
+               uint64_t        parity[32];         /* 0x040400 -- 0x0404F8 */
+       } ce_dre_maint_ds_head_q;
+
+       uint64_t        ce_pad_040500[352];         /* 0x040500 -- 0x040FF8 */
+
+       /* DRE Downstream Data Queue */
+       struct  ce_dre_maint_ds_data_queue {
+               uint64_t        data63_0[256];      /* 0x041000 -- 0x0417F8 */
+               uint64_t        ce_pad_041800[256]; /* 0x041800 -- 0x041FF8 */
+               uint64_t        data127_64[256];    /* 0x042000 -- 0x0427F8 */
+               uint64_t        ce_pad_042800[256]; /* 0x042800 -- 0x042FF8 */
+               uint64_t        parity[256];        /* 0x043000 -- 0x0437F8 */
+               uint64_t        ce_pad_043800[256]; /* 0x043800 -- 0x043FF8 */
+       } ce_dre_maint_ds_data_q;
+
+       /* DRE URE Upstream Response Queue */
+       struct  ce_dre_maint_ure_us_rsp_queue {
+               uint64_t        data63_0[8];        /* 0x044000 -- 0x044038 */
+               uint64_t        ce_pad_044040[24];  /* 0x044040 -- 0x0440F8 */
+               uint64_t        data127_64[8];      /* 0x044100 -- 0x044138 */
+               uint64_t        ce_pad_044140[24];  /* 0x044140 -- 0x0441F8 */
+               uint64_t        parity[8];          /* 0x044200 -- 0x044238 */
+               uint64_t        ce_pad_044240[24];  /* 0x044240 -- 0x0442F8 */
+       } ce_dre_maint_ure_us_rsp_q;
+
+       uint64_t        ce_dre_maint_us_wrt_rsp[32];/* 0x044300 -- 0x0443F8 */
+
+       uint64_t        ce_end_of_struct;                       /* 0x044400 */
+} tioce_t;
+
+
+/* ce_adm_int_mask/ce_adm_int_status register bit defines */
+#define CE_ADM_INT_CE_ERROR_SHFT               0
+#define CE_ADM_INT_LSI1_IP_ERROR_SHFT          1
+#define CE_ADM_INT_LSI2_IP_ERROR_SHFT          2
+#define CE_ADM_INT_PCIE_ERROR_SHFT             3
+#define CE_ADM_INT_PORT1_HOTPLUG_EVENT_SHFT    4
+#define CE_ADM_INT_PORT2_HOTPLUG_EVENT_SHFT    5
+#define CE_ADM_INT_PCIE_PORT1_DEV_A_SHFT       6
+#define CE_ADM_INT_PCIE_PORT1_DEV_B_SHFT       7
+#define CE_ADM_INT_PCIE_PORT1_DEV_C_SHFT       8
+#define CE_ADM_INT_PCIE_PORT1_DEV_D_SHFT       9
+#define CE_ADM_INT_PCIE_PORT2_DEV_A_SHFT       10
+#define CE_ADM_INT_PCIE_PORT2_DEV_B_SHFT       11
+#define CE_ADM_INT_PCIE_PORT2_DEV_C_SHFT       12
+#define CE_ADM_INT_PCIE_PORT2_DEV_D_SHFT       13
+#define CE_ADM_INT_PCIE_MSG_SHFT               14 /*see int_dest_14*/
+#define CE_ADM_INT_PCIE_MSG_SLOT_0_SHFT                14
+#define CE_ADM_INT_PCIE_MSG_SLOT_1_SHFT                15
+#define CE_ADM_INT_PCIE_MSG_SLOT_2_SHFT                16
+#define CE_ADM_INT_PCIE_MSG_SLOT_3_SHFT                17
+#define CE_ADM_INT_PORT1_PM_PME_MSG_SHFT       22
+#define CE_ADM_INT_PORT2_PM_PME_MSG_SHFT       23
+
+/* ce_adm_force_int register bit defines */
+#define CE_ADM_FORCE_INT_PCIE_PORT1_DEV_A_SHFT 0
+#define CE_ADM_FORCE_INT_PCIE_PORT1_DEV_B_SHFT 1
+#define CE_ADM_FORCE_INT_PCIE_PORT1_DEV_C_SHFT 2
+#define CE_ADM_FORCE_INT_PCIE_PORT1_DEV_D_SHFT 3
+#define CE_ADM_FORCE_INT_PCIE_PORT2_DEV_A_SHFT 4
+#define CE_ADM_FORCE_INT_PCIE_PORT2_DEV_B_SHFT 5
+#define CE_ADM_FORCE_INT_PCIE_PORT2_DEV_C_SHFT 6
+#define CE_ADM_FORCE_INT_PCIE_PORT2_DEV_D_SHFT 7
+#define CE_ADM_FORCE_INT_ALWAYS_SHFT           8
+
+/* ce_adm_int_dest register bit masks & shifts */
+#define INTR_VECTOR_SHFT                       56
+
+/* ce_adm_error_mask and ce_adm_error_summary register bit masks */
+#define CE_ADM_ERR_CRM_SSP_REQ_INVALID                 (0x1ULL <<  0)
+#define CE_ADM_ERR_SSP_REQ_HEADER                      (0x1ULL <<  1)
+#define CE_ADM_ERR_SSP_RSP_HEADER                      (0x1ULL <<  2)
+#define CE_ADM_ERR_SSP_PROTOCOL_ERROR                  (0x1ULL <<  3)
+#define CE_ADM_ERR_SSP_SBE                             (0x1ULL <<  4)
+#define CE_ADM_ERR_SSP_MBE                             (0x1ULL <<  5)
+#define CE_ADM_ERR_CXM_CREDIT_OFLOW                    (0x1ULL <<  6)
+#define CE_ADM_ERR_DRE_SSP_REQ_INVAL                   (0x1ULL <<  7)
+#define CE_ADM_ERR_SSP_REQ_LONG                                (0x1ULL <<  8)
+#define CE_ADM_ERR_SSP_REQ_OFLOW                       (0x1ULL <<  9)
+#define CE_ADM_ERR_SSP_REQ_SHORT                       (0x1ULL << 10)
+#define CE_ADM_ERR_SSP_REQ_SIDEBAND                    (0x1ULL << 11)
+#define CE_ADM_ERR_SSP_REQ_ADDR_ERR                    (0x1ULL << 12)
+#define CE_ADM_ERR_SSP_REQ_BAD_BE                      (0x1ULL << 13)
+#define CE_ADM_ERR_PCIE_COMPL_TIMEOUT                  (0x1ULL << 14)
+#define CE_ADM_ERR_PCIE_UNEXP_COMPL                    (0x1ULL << 15)
+#define CE_ADM_ERR_PCIE_ERR_COMPL                      (0x1ULL << 16)
+#define CE_ADM_ERR_DRE_CREDIT_OFLOW                    (0x1ULL << 17)
+#define CE_ADM_ERR_DRE_SRAM_PE                         (0x1ULL << 18)
+#define CE_ADM_ERR_SSP_RSP_INVALID                     (0x1ULL << 19)
+#define CE_ADM_ERR_SSP_RSP_LONG                                (0x1ULL << 20)
+#define CE_ADM_ERR_SSP_RSP_SHORT                       (0x1ULL << 21)
+#define CE_ADM_ERR_SSP_RSP_SIDEBAND                    (0x1ULL << 22)
+#define CE_ADM_ERR_URE_SSP_RSP_UNEXP                   (0x1ULL << 23)
+#define CE_ADM_ERR_URE_SSP_WR_REQ_TIMEOUT              (0x1ULL << 24)
+#define CE_ADM_ERR_URE_SSP_RD_REQ_TIMEOUT              (0x1ULL << 25)
+#define CE_ADM_ERR_URE_ATE3240_PAGE_FAULT              (0x1ULL << 26)
+#define CE_ADM_ERR_URE_ATE40_PAGE_FAULT                        (0x1ULL << 27)
+#define CE_ADM_ERR_URE_CREDIT_OFLOW                    (0x1ULL << 28)
+#define CE_ADM_ERR_URE_SRAM_PE                         (0x1ULL << 29)
+#define CE_ADM_ERR_ADM_SSP_RSP_UNEXP                   (0x1ULL << 30)
+#define CE_ADM_ERR_ADM_SSP_REQ_TIMEOUT                 (0x1ULL << 31)
+#define CE_ADM_ERR_MMR_ACCESS_ERROR                    (0x1ULL << 32)
+#define CE_ADM_ERR_MMR_ADDR_ERROR                      (0x1ULL << 33)
+#define CE_ADM_ERR_ADM_CREDIT_OFLOW                    (0x1ULL << 34)
+#define CE_ADM_ERR_ADM_SRAM_PE                         (0x1ULL << 35)
+#define CE_ADM_ERR_DTL1_MIN_PDATA_CREDIT_ERR           (0x1ULL << 36)
+#define CE_ADM_ERR_DTL1_INF_COMPL_CRED_UPDT_ERR                (0x1ULL << 37)
+#define CE_ADM_ERR_DTL1_INF_POSTED_CRED_UPDT_ERR       (0x1ULL << 38)
+#define CE_ADM_ERR_DTL1_INF_NPOSTED_CRED_UPDT_ERR      (0x1ULL << 39)
+#define CE_ADM_ERR_DTL1_COMP_HD_CRED_MAX_ERR           (0x1ULL << 40)
+#define CE_ADM_ERR_DTL1_COMP_D_CRED_MAX_ERR            (0x1ULL << 41)
+#define CE_ADM_ERR_DTL1_NPOSTED_HD_CRED_MAX_ERR                (0x1ULL << 42)
+#define CE_ADM_ERR_DTL1_NPOSTED_D_CRED_MAX_ERR         (0x1ULL << 43)
+#define CE_ADM_ERR_DTL1_POSTED_HD_CRED_MAX_ERR         (0x1ULL << 44)
+#define CE_ADM_ERR_DTL1_POSTED_D_CRED_MAX_ERR          (0x1ULL << 45)
+#define CE_ADM_ERR_DTL2_MIN_PDATA_CREDIT_ERR           (0x1ULL << 46)
+#define CE_ADM_ERR_DTL2_INF_COMPL_CRED_UPDT_ERR                (0x1ULL << 47)
+#define CE_ADM_ERR_DTL2_INF_POSTED_CRED_UPDT_ERR       (0x1ULL << 48)
+#define CE_ADM_ERR_DTL2_INF_NPOSTED_CRED_UPDT_ERR      (0x1ULL << 49)
+#define CE_ADM_ERR_DTL2_COMP_HD_CRED_MAX_ERR           (0x1ULL << 50)
+#define CE_ADM_ERR_DTL2_COMP_D_CRED_MAX_ERR            (0x1ULL << 51)
+#define CE_ADM_ERR_DTL2_NPOSTED_HD_CRED_MAX_ERR                (0x1ULL << 52)
+#define CE_ADM_ERR_DTL2_NPOSTED_D_CRED_MAX_ERR         (0x1ULL << 53)
+#define CE_ADM_ERR_DTL2_POSTED_HD_CRED_MAX_ERR         (0x1ULL << 54)
+#define CE_ADM_ERR_DTL2_POSTED_D_CRED_MAX_ERR          (0x1ULL << 55)
+#define CE_ADM_ERR_PORT1_PCIE_COR_ERR                  (0x1ULL << 56)
+#define CE_ADM_ERR_PORT1_PCIE_NFAT_ERR                 (0x1ULL << 57)
+#define CE_ADM_ERR_PORT1_PCIE_FAT_ERR                  (0x1ULL << 58)
+#define CE_ADM_ERR_PORT2_PCIE_COR_ERR                  (0x1ULL << 59)
+#define CE_ADM_ERR_PORT2_PCIE_NFAT_ERR                 (0x1ULL << 60)
+#define CE_ADM_ERR_PORT2_PCIE_FAT_ERR                  (0x1ULL << 61)
+
+/* ce_adm_ure_ups_buf_barrier_flush register bit masks and shifts */
+#define FLUSH_SEL_PORT1_PIPE0_SHFT     0
+#define FLUSH_SEL_PORT1_PIPE1_SHFT     4
+#define FLUSH_SEL_PORT1_PIPE2_SHFT     8
+#define FLUSH_SEL_PORT1_PIPE3_SHFT     12
+#define FLUSH_SEL_PORT2_PIPE0_SHFT     16
+#define FLUSH_SEL_PORT2_PIPE1_SHFT     20
+#define FLUSH_SEL_PORT2_PIPE2_SHFT     24
+#define FLUSH_SEL_PORT2_PIPE3_SHFT     28
+
+/* ce_dre_config1 register bit masks and shifts */
+#define CE_DRE_RO_ENABLE               (0x1ULL << 0)
+#define CE_DRE_DYN_RO_ENABLE           (0x1ULL << 1)
+#define CE_DRE_SUP_CONFIG_COMP_ERROR   (0x1ULL << 2)
+#define CE_DRE_SUP_IO_COMP_ERROR       (0x1ULL << 3)
+#define CE_DRE_ADDR_MODE_SHFT          4
+
+/* ce_dre_config_req_status register bit masks */
+#define CE_DRE_LAST_CONFIG_COMPLETION  (0x7ULL << 0)
+#define CE_DRE_DOWNSTREAM_CONFIG_ERROR (0x1ULL << 3)
+#define CE_DRE_CONFIG_COMPLETION_VALID (0x1ULL << 4)
+#define CE_DRE_CONFIG_REQUEST_ACTIVE   (0x1ULL << 5)
+
+/* ce_ure_control register bit masks & shifts */
+#define CE_URE_RD_MRG_ENABLE           (0x1ULL << 0)
+#define CE_URE_WRT_MRG_ENABLE1         (0x1ULL << 4)
+#define CE_URE_WRT_MRG_ENABLE2         (0x1ULL << 5)
+#define CE_URE_RSPQ_BYPASS_DISABLE     (0x1ULL << 24)
+#define CE_URE_UPS_DAT1_PAR_DISABLE    (0x1ULL << 32)
+#define CE_URE_UPS_HDR1_PAR_DISABLE    (0x1ULL << 33)
+#define CE_URE_UPS_DAT2_PAR_DISABLE    (0x1ULL << 34)
+#define CE_URE_UPS_HDR2_PAR_DISABLE    (0x1ULL << 35)
+#define CE_URE_ATE_PAR_DISABLE         (0x1ULL << 36)
+#define CE_URE_RCI_PAR_DISABLE         (0x1ULL << 37)
+#define CE_URE_RSPQ_PAR_DISABLE                (0x1ULL << 38)
+#define CE_URE_DNS_DAT_PAR_DISABLE     (0x1ULL << 39)
+#define CE_URE_DNS_HDR_PAR_DISABLE     (0x1ULL << 40)
+#define CE_URE_MALFORM_DISABLE         (0x1ULL << 44)
+#define CE_URE_UNSUP_DISABLE           (0x1ULL << 45)
+
+/* ce_ure_page_map register bit masks & shifts */
+#define CE_URE_ATE3240_ENABLE          (0x1ULL << 0)
+#define CE_URE_ATE40_ENABLE            (0x1ULL << 1)
+#define CE_URE_PAGESIZE_SHFT           4
+#define CE_URE_PAGESIZE_MASK           (0x7ULL << CE_URE_PAGESIZE_SHFT)
+#define CE_URE_4K_PAGESIZE             (0x0ULL << CE_URE_PAGESIZE_SHFT)
+#define CE_URE_16K_PAGESIZE            (0x1ULL << CE_URE_PAGESIZE_SHFT)
+#define CE_URE_64K_PAGESIZE            (0x2ULL << CE_URE_PAGESIZE_SHFT)
+#define CE_URE_128K_PAGESIZE           (0x3ULL << CE_URE_PAGESIZE_SHFT)
+#define CE_URE_256K_PAGESIZE           (0x4ULL << CE_URE_PAGESIZE_SHFT)
+
+/* ce_ure_pipe_sel register bit masks & shifts */
+#define PKT_TRAFIC_SHRT                        16
+#define BUS_SRC_ID_SHFT                        8
+#define DEV_SRC_ID_SHFT                        3
+#define FNC_SRC_ID_SHFT                        0
+#define CE_URE_TC_MASK                 (0x07ULL << PKT_TRAFIC_SHRT)
+#define CE_URE_BUS_MASK                        (0xFFULL << BUS_SRC_ID_SHFT)
+#define CE_URE_DEV_MASK                        (0x1FULL << DEV_SRC_ID_SHFT)
+#define CE_URE_FNC_MASK                        (0x07ULL << FNC_SRC_ID_SHFT)
+#define CE_URE_PIPE_BUS(b)             (((uint64_t)(b) << BUS_SRC_ID_SHFT) & \
+                                        CE_URE_BUS_MASK)
+#define CE_URE_PIPE_DEV(d)             (((uint64_t)(d) << DEV_SRC_ID_SHFT) & \
+                                        CE_URE_DEV_MASK)
+#define CE_URE_PIPE_FNC(f)             (((uint64_t)(f) << FNC_SRC_ID_SHFT) & \
+                                        CE_URE_FNC_MASK)
+
+#define CE_URE_SEL1_SHFT               0
+#define CE_URE_SEL2_SHFT               20
+#define CE_URE_SEL3_SHFT               40
+#define CE_URE_SEL1_MASK               (0x7FFFFULL << CE_URE_SEL1_SHFT)
+#define CE_URE_SEL2_MASK               (0x7FFFFULL << CE_URE_SEL2_SHFT)
+#define CE_URE_SEL3_MASK               (0x7FFFFULL << CE_URE_SEL3_SHFT)
+
+
+/* ce_ure_pipe_mask register bit masks & shifts */
+#define CE_URE_MASK1_SHFT              0
+#define CE_URE_MASK2_SHFT              20
+#define CE_URE_MASK3_SHFT              40
+#define CE_URE_MASK1_MASK              (0x7FFFFULL << CE_URE_MASK1_SHFT)
+#define CE_URE_MASK2_MASK              (0x7FFFFULL << CE_URE_MASK2_SHFT)
+#define CE_URE_MASK3_MASK              (0x7FFFFULL << CE_URE_MASK3_SHFT)
+
+
+/* ce_ure_pcie_control1 register bit masks & shifts */
+#define CE_URE_SI                      (0x1ULL << 0)
+#define CE_URE_ELAL_SHFT               4
+#define CE_URE_ELAL_MASK               (0x7ULL << CE_URE_ELAL_SHFT)
+#define CE_URE_ELAL1_SHFT              8
+#define CE_URE_ELAL1_MASK              (0x7ULL << CE_URE_ELAL1_SHFT)
+#define CE_URE_SCC                     (0x1ULL << 12)
+#define CE_URE_PN1_SHFT                        16
+#define CE_URE_PN1_MASK                        (0xFFULL << CE_URE_PN1_SHFT)
+#define CE_URE_PN2_SHFT                        24
+#define CE_URE_PN2_MASK                        (0xFFULL << CE_URE_PN2_SHFT)
+#define CE_URE_PN1_SET(n)              (((uint64_t)(n) << CE_URE_PN1_SHFT) & \
+                                        CE_URE_PN1_MASK)
+#define CE_URE_PN2_SET(n)              (((uint64_t)(n) << CE_URE_PN2_SHFT) & \
+                                        CE_URE_PN2_MASK)
+
+/* ce_ure_pcie_control2 register bit masks & shifts */
+#define CE_URE_ABP                     (0x1ULL << 0)
+#define CE_URE_PCP                     (0x1ULL << 1)
+#define CE_URE_MSP                     (0x1ULL << 2)
+#define CE_URE_AIP                     (0x1ULL << 3)
+#define CE_URE_PIP                     (0x1ULL << 4)
+#define CE_URE_HPS                     (0x1ULL << 5)
+#define CE_URE_HPC                     (0x1ULL << 6)
+#define CE_URE_SPLV_SHFT               7
+#define CE_URE_SPLV_MASK               (0xFFULL << CE_URE_SPLV_SHFT)
+#define CE_URE_SPLS_SHFT               15
+#define CE_URE_SPLS_MASK               (0x3ULL << CE_URE_SPLS_SHFT)
+#define CE_URE_PSN1_SHFT               19
+#define CE_URE_PSN1_MASK               (0x1FFFULL << CE_URE_PSN1_SHFT)
+#define CE_URE_PSN2_SHFT               32
+#define CE_URE_PSN2_MASK               (0x1FFFULL << CE_URE_PSN2_SHFT)
+#define CE_URE_PSN1_SET(n)             (((uint64_t)(n) << CE_URE_PSN1_SHFT) & \
+                                        CE_URE_PSN1_MASK)
+#define CE_URE_PSN2_SET(n)             (((uint64_t)(n) << CE_URE_PSN2_SHFT) & \
+                                        CE_URE_PSN2_MASK)
+
+/*
+ * PIO address space ranges for CE
+ */
+
+/* Local CE Registers Space */
+#define CE_PIO_MMR                     0x00000000
+#define CE_PIO_MMR_LEN                 0x04000000
+
+/* PCI Compatible Config Space */
+#define CE_PIO_CONFIG_SPACE            0x04000000
+#define CE_PIO_CONFIG_SPACE_LEN                0x04000000
+
+/* PCI I/O Space Alias */
+#define CE_PIO_IO_SPACE_ALIAS          0x08000000
+#define CE_PIO_IO_SPACE_ALIAS_LEN      0x08000000
+
+/* PCI Enhanced Config Space */
+#define CE_PIO_E_CONFIG_SPACE          0x10000000
+#define CE_PIO_E_CONFIG_SPACE_LEN      0x10000000
+
+/* PCI I/O Space */
+#define CE_PIO_IO_SPACE                        0x100000000
+#define CE_PIO_IO_SPACE_LEN            0x100000000
+
+/* PCI MEM Space */
+#define CE_PIO_MEM_SPACE               0x200000000
+#define CE_PIO_MEM_SPACE_LEN           TIO_HWIN_SIZE
+
+
+/*
+ * CE PCI Enhanced Config Space shifts & masks
+ */
+#define CE_E_CONFIG_BUS_SHFT           20
+#define CE_E_CONFIG_BUS_MASK           (0xFF << CE_E_CONFIG_BUS_SHFT)
+#define CE_E_CONFIG_DEVICE_SHFT                15
+#define CE_E_CONFIG_DEVICE_MASK                (0x1F << CE_E_CONFIG_DEVICE_SHFT)
+#define CE_E_CONFIG_FUNC_SHFT          12
+#define CE_E_CONFIG_FUNC_MASK          (0x7  << CE_E_CONFIG_FUNC_SHFT)
+
+#endif /* __ASM_IA64_SN_TIOCE_H__ */
diff --git a/include/asm-ia64/sn/tioce_provider.h b/include/asm-ia64/sn/tioce_provider.h
new file mode 100644 (file)
index 0000000..7f63dec
--- /dev/null
@@ -0,0 +1,66 @@
+/**************************************************************************
+ *             Copyright (C) 2005, Silicon Graphics, Inc.                 *
+ *                                                                       *
+ *  These coded instructions, statements, and computer programs         contain  *
+ *  unpublished         proprietary  information of Silicon Graphics, Inc., and  *
+ *  are protected by Federal copyright law.  They  may not be disclosed  *
+ *  to third  parties  or copied or duplicated in any form, in whole or  *
+ *  in part, without the prior written consent of Silicon Graphics, Inc.  *
+ *                                                                       *
+ **************************************************************************/
+
+#ifndef _ASM_IA64_SN_CE_PROVIDER_H
+#define _ASM_IA64_SN_CE_PROVIDER_H
+
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/tioce.h>
+
+/*
+ * Common TIOCE structure shared between the prom and kernel
+ *
+ * DO NOT CHANGE THIS STRUCT WITHOUT MAKING CORRESPONDING CHANGES TO THE
+ * PROM VERSION.
+ */
+struct tioce_common {
+       struct pcibus_bussoft   ce_pcibus;      /* common pciio header */
+
+       uint32_t                ce_rev;
+       uint64_t                ce_kernel_private;
+       uint64_t                ce_prom_private;
+};
+
+struct tioce_kernel {
+       struct tioce_common     *ce_common;
+       spinlock_t              ce_lock;
+       struct list_head        ce_dmamap_list;
+
+       uint64_t                ce_ate40_shadow[TIOCE_NUM_M40_ATES];
+       uint64_t                ce_ate3240_shadow[TIOCE_NUM_M3240_ATES];
+       uint32_t                ce_ate3240_pagesize;
+
+       uint8_t                 ce_port1_secondary;
+
+       /* per-port resources */
+       struct {
+               int             dirmap_refcnt;
+               uint64_t        dirmap_shadow;
+       } ce_port[TIOCE_NUM_PORTS];
+};
+
+struct tioce_dmamap {
+       struct list_head        ce_dmamap_list; /* headed by tioce_kernel */
+       uint32_t                refcnt;
+
+       uint64_t                nbytes;         /* # bytes mapped */
+
+       uint64_t                ct_start;       /* coretalk start address */
+       uint64_t                pci_start;      /* bus start address */
+
+       uint64_t                *ate_hw;        /* hw ptr of first ate in map */
+       uint64_t                *ate_shadow;    /* shadow ptr of firat ate */
+       uint16_t                ate_count;      /* # ate's in the map */
+};
+
+extern int tioce_init_provider(void);
+
+#endif  /* __ASM_IA64_SN_CE_PROVIDER_H */
index 21a9f10d6baafd033e96a83d7c9e1e0568b823ea..a255006fb7b51f0db085e82f547f25938ee7c84c 100644 (file)
@@ -23,6 +23,8 @@
 #define SO_BROADCAST   6
 #define SO_SNDBUF      7
 #define SO_RCVBUF      8
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
 #define SO_KEEPALIVE   9
 #define SO_OOBINLINE   10
 #define SO_NO_CHECK    11
index 909936f25512e8ebbc3967d0eb775a12c989dd03..d2430aa0d49db76db4b6c771bc1eb9a9bc402d36 100644 (file)
@@ -93,7 +93,15 @@ _raw_spin_lock_flags (spinlock_t *lock, unsigned long flags)
 # endif /* CONFIG_MCKINLEY */
 #endif
 }
+
 #define _raw_spin_lock(lock) _raw_spin_lock_flags(lock, 0)
+
+/* Unlock by doing an ordered store and releasing the cacheline with nta */
+static inline void _raw_spin_unlock(spinlock_t *x) {
+       barrier();
+       asm volatile ("st4.rel.nta [%0] = r0\n\t" :: "r"(x));
+}
+
 #else /* !ASM_SUPPORTED */
 #define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock)
 # define _raw_spin_lock(x)                                                             \
@@ -109,16 +117,16 @@ do {                                                                                      \
                } while (ia64_spinlock_val);                                            \
        }                                                                               \
 } while (0)
+#define _raw_spin_unlock(x)    do { barrier(); ((spinlock_t *) x)->lock = 0; } while (0)
 #endif /* !ASM_SUPPORTED */
 
 #define spin_is_locked(x)      ((x)->lock != 0)
-#define _raw_spin_unlock(x)    do { barrier(); ((spinlock_t *) x)->lock = 0; } while (0)
 #define _raw_spin_trylock(x)   (cmpxchg_acq(&(x)->lock, 0, 1) == 0)
 #define spin_unlock_wait(x)    do { barrier(); } while ((x)->lock)
 
 typedef struct {
-       volatile unsigned int read_counter      : 31;
-       volatile unsigned int write_lock        :  1;
+       volatile unsigned int read_counter      : 24;
+       volatile unsigned int write_lock        :  8;
 #ifdef CONFIG_PREEMPT
        unsigned int break_lock;
 #endif
@@ -174,6 +182,13 @@ do {                                                                               \
        (result == 0);                                                          \
 })
 
+static inline void _raw_write_unlock(rwlock_t *x)
+{
+       u8 *y = (u8 *)x;
+       barrier();
+       asm volatile ("st1.rel.nta [%0] = r0\n\t" :: "r"(y+3) : "memory" );
+}
+
 #else /* !ASM_SUPPORTED */
 
 #define _raw_write_lock(l)                                                             \
@@ -195,14 +210,14 @@ do {                                                                              \
        (ia64_val == 0);                                                \
 })
 
+static inline void _raw_write_unlock(rwlock_t *x)
+{
+       barrier();
+       x->write_lock = 0;
+}
+
 #endif /* !ASM_SUPPORTED */
 
 #define _raw_read_trylock(lock) generic_raw_read_trylock(lock)
 
-#define _raw_write_unlock(x)                                                           \
-({                                                                                     \
-       smp_mb__before_clear_bit();     /* need barrier before releasing lock... */     \
-       clear_bit(31, (x));                                                             \
-})
-
 #endif /*  _ASM_IA64_SPINLOCK_H */
index cd2cf76b2db1d77cb22a69f928f96c4a74d1c59c..33256db4a7cf1b0ad4f82cdcf935b0bd421a42ed 100644 (file)
 #include <asm/pal.h>
 #include <asm/percpu.h>
 
-#define GATE_ADDR              __IA64_UL_CONST(0xa000000000000000)
+#define GATE_ADDR              RGN_BASE(RGN_GATE)
+
 /*
  * 0xa000000000000000+2*PERCPU_PAGE_SIZE
  * - 0xa000000000000000+3*PERCPU_PAGE_SIZE remain unmapped (guard page)
  */
-#define KERNEL_START            __IA64_UL_CONST(0xa000000100000000)
+#define KERNEL_START            (GATE_ADDR+0x100000000)
 #define PERCPU_ADDR            (-PERCPU_PAGE_SIZE)
 
 #ifndef __ASSEMBLY__
index 399bc29729fd2c532b20d472fcb208b83be35fa2..a9f738bf18a7e739325a4221269128fa0857ba2b 100644 (file)
@@ -98,29 +98,6 @@ void build_cpu_to_node_map(void);
        .nr_balance_failed      = 0,                    \
 }
 
-/* sched_domains SD_ALLNODES_INIT for IA64 NUMA machines */
-#define SD_ALLNODES_INIT (struct sched_domain) {       \
-       .span                   = CPU_MASK_NONE,        \
-       .parent                 = NULL,                 \
-       .groups                 = NULL,                 \
-       .min_interval           = 64,                   \
-       .max_interval           = 64*num_online_cpus(), \
-       .busy_factor            = 128,                  \
-       .imbalance_pct          = 133,                  \
-       .cache_hot_time         = (10*1000000),         \
-       .cache_nice_tries       = 1,                    \
-       .busy_idx               = 3,                    \
-       .idle_idx               = 3,                    \
-       .newidle_idx            = 0, /* unused */       \
-       .wake_idx               = 0, /* unused */       \
-       .forkexec_idx           = 0, /* unused */       \
-       .per_cpu_gain           = 100,                  \
-       .flags                  = SD_LOAD_BALANCE,      \
-       .last_balance           = jiffies,              \
-       .balance_interval       = 64,                   \
-       .nr_balance_failed      = 0,                    \
-}
-
 #endif /* CONFIG_NUMA */
 
 #include <asm-generic/topology.h>
index a677565aa95451f13191db59cfb935e9f0808aab..902850d12424daa1a492f569adc701b4596e96cf 100644 (file)
@@ -67,8 +67,6 @@ typedef __u64 u64;
 
 typedef u64 dma_addr_t;
 
-typedef unsigned short kmem_bufctl_t;
-
 # endif /* __KERNEL__ */
 #endif /* !__ASSEMBLY__ */
 
index 8edd9a90949cf9fa94134f9ebb3b71a889d71322..3a7829bb5954030cfb3a2eee73620de5a3f37403 100644 (file)
 })
 #define access_ok(type, addr, size)    __access_ok((addr), (size), get_fs())
 
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated
-verify_area (int type, const void __user *addr, unsigned long size)
-{
-       return access_ok(type, addr, size) ? 0 : -EFAULT;
-}
-
 /*
  * These are the main single-value transfer routines.  They automatically
  * use the right size if we just have the right pointer type.
diff --git a/include/asm-m32r/auxvec.h b/include/asm-m32r/auxvec.h
new file mode 100644 (file)
index 0000000..f76dcc8
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef _ASM_M32R__AUXVEC_H
+#define _ASM_M32R__AUXVEC_H
+
+#endif  /* _ASM_M32R__AUXVEC_H */
index 99f37dbf2558f033df58c5fd45ac9cf0fab92833..877ebf46e9ff540299283645f986f91c8e6f7454 100644 (file)
@@ -105,7 +105,7 @@ static inline unsigned short ip_fast_csum(unsigned char * iph,
                "       addx    %0, %3 \n"
                "       .fillinsn\n"
                "2: \n"
-       /* Since the input registers which are loaded with iph and ipl
+       /* Since the input registers which are loaded with iph and ihl
           are modified, we must also specify them as outputs, or gcc
           will assume they contain their original values. */
        : "=&r" (sum), "=r" (iph), "=r" (ihl), "=&r" (tmpreg0), "=&r" (tmpreg1)
index 3e3089572028f85e05b314536914fc08ac25f6c6..46ab12db57397dfc44a7aa84f9c10ac5e97509d9 100644 (file)
@@ -1,92 +1 @@
-#ifndef _ASM_M32R_FCNTL_H
-#define _ASM_M32R_FCNTL_H
-
-/* $Id$ */
-
-/* orig : i386 2.4.18 */
-
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
-   located on an ext2 file system */
-#define O_ACCMODE         0003
-#define O_RDONLY            00
-#define O_WRONLY            01
-#define O_RDWR              02
-#define O_CREAT                   0100 /* not fcntl */
-#define O_EXCL            0200 /* not fcntl */
-#define O_NOCTTY          0400 /* not fcntl */
-#define O_TRUNC                  01000 /* not fcntl */
-#define O_APPEND         02000
-#define O_NONBLOCK       04000
-#define O_NDELAY       O_NONBLOCK
-#define O_SYNC          010000
-#define FASYNC          020000 /* fcntl, for BSD compatibility */
-#define O_DIRECT        040000 /* direct disk access hint */
-#define O_LARGEFILE    0100000
-#define O_DIRECTORY    0200000 /* must be a directory */
-#define O_NOFOLLOW     0400000 /* don't follow links */
-#define O_NOATIME      01000000
-
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
-#define F_GETLK                5
-#define F_SETLK                6
-#define F_SETLKW       7
-
-#define F_SETOWN       8       /*  for sockets. */
-#define F_GETOWN       9       /*  for sockets. */
-#define F_SETSIG       10      /*  for sockets. */
-#define F_GETSIG       11      /*  for sockets. */
-
-#define F_GETLK64      12      /*  using 'struct flock64' */
-#define F_SETLK64      13
-#define F_SETLKW64     14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK                0
-#define F_WRLCK                1
-#define F_UNLCK                2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
-
-struct flock {
-       short l_type;
-       short l_whence;
-       off_t l_start;
-       off_t l_len;
-       pid_t l_pid;
-};
-
-struct flock64 {
-       short  l_type;
-       short  l_whence;
-       loff_t l_start;
-       loff_t l_len;
-       pid_t  l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE  1024
-
-#endif  /* _ASM_M32R_FCNTL_H */
+#include <asm-generic/fcntl.h>
diff --git a/include/asm-m32r/futex.h b/include/asm-m32r/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-m32r/hdreg.h b/include/asm-m32r/hdreg.h
deleted file mode 100644 (file)
index 7f7fd1a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/hdreg.h>
index 1c6abb9f3f1f7475a41ca8c04f6c680260d7fd91..4ab5788763616c2f2b667b08c46dd4562d30a8c5 100644 (file)
@@ -61,25 +61,6 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 
 /* This handles the memory map.. */
 
-#ifndef __ASSEMBLY__
-
-/* Pure 2^n version of get_order */
-static __inline__ int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size - 1) >> (PAGE_SHIFT - 1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-
-       return order;
-}
-
-#endif /* __ASSEMBLY__ */
-
 #define __MEMORY_START  CONFIG_MEMORY_START
 #define __MEMORY_SIZE   CONFIG_MEMORY_SIZE
 
@@ -111,5 +92,7 @@ static __inline__ int get_order(unsigned long size)
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/page.h>
+
 #endif /* _ASM_M32R_PAGE_H */
 
index 159519d99042176a1ec577b64243d7ebb5674a6d..8b6680f223c0b4a5f18781f36129cc1d541b68f8 100644 (file)
@@ -14,6 +14,8 @@
 #define SO_BROADCAST   6
 #define SO_SNDBUF      7
 #define SO_RCVBUF      8
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
 #define SO_KEEPALIVE   9
 #define SO_OOBINLINE   10
 #define SO_NO_CHECK    11
index ca0a887d2237167e313a6aa59643a59e2ade6287..fcf24c64c3ba4650d001dbf9dfa770583df51bed 100644 (file)
@@ -55,8 +55,6 @@ typedef unsigned long long u64;
 typedef u32 dma_addr_t;
 typedef u64 dma64_addr_t;
 
-typedef unsigned short kmem_bufctl_t;
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index bbb8ac4018a070d615d9df5d6fa356da3ed91ded..93d863c455a19ff302af1e231a578616bc1d9270 100644 (file)
@@ -120,31 +120,6 @@ static inline int access_ok(int type, const void *addr, unsigned long size)
 }
 #endif /* CONFIG_MMU */
 
-/**
- * verify_area: - Obsolete/deprecated and will go away soon,
- * use access_ok() instead.
- * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE
- * @addr: User space pointer to start of block to check
- * @size: Size of block to check
- *
- * Context: User context only.  This function may sleep.
- *
- * This function has been replaced by access_ok().
- *
- * Checks if a pointer to a block of memory in user space is valid.
- *
- * Returns zero if the memory block may be valid, -EFAULT
- * if it is definitely invalid.
- *
- * See access_ok() for more details.
- */
-static inline int __deprecated verify_area(int type, const void __user *addr,
-                             unsigned long size)
-{
-       return access_ok(type, addr, size) ? 0 : -EFAULT;
-}
-
-
 /*
  * The exception table consists of pairs of addresses: the first is the
  * address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-m68k/auxvec.h b/include/asm-m68k/auxvec.h
new file mode 100644 (file)
index 0000000..844d6d5
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __ASMm68k_AUXVEC_H
+#define __ASMm68k_AUXVEC_H
+
+#endif
index e4773946f10dccfb857f5717481c144f9ced12fe..8aba971b13684e8ff0d9c26867a4d12b2af59170 100644 (file)
@@ -130,20 +130,25 @@ static inline void __flush_page_to_ram(void *vaddr)
 #define flush_dcache_mmap_lock(mapping)                do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)      do { } while (0)
 #define flush_icache_page(vma, page)   __flush_page_to_ram(page_address(page))
-#define flush_icache_user_range(vma,pg,adr,len)        do { } while (0)
-
-#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
-       do {                                                    \
-               flush_cache_page(vma, vaddr, page_to_pfn(page));\
-               memcpy(dst, src, len);                          \
-       } while (0)
-
-#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
-       do {                                                    \
-               flush_cache_page(vma, vaddr, page_to_pfn(page));\
-               memcpy(dst, src, len);                          \
-       } while (0)
 
+extern void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
+                                   unsigned long addr, int len);
 extern void flush_icache_range(unsigned long address, unsigned long endaddr);
 
+static inline void copy_to_user_page(struct vm_area_struct *vma,
+                                    struct page *page, unsigned long vaddr,
+                                    void *dst, void *src, int len)
+{
+       flush_cache_page(vma, vaddr, page_to_pfn(page));
+       memcpy(dst, src, len);
+       flush_icache_user_range(vma, page, vaddr, len);
+}
+static inline void copy_from_user_page(struct vm_area_struct *vma,
+                                      struct page *page, unsigned long vaddr,
+                                      void *dst, void *src, int len)
+{
+       flush_cache_page(vma, vaddr, page_to_pfn(page));
+       memcpy(dst, src, len);
+}
+
 #endif /* _M68K_CACHEFLUSH_H */
index 0d4212983a3313221c5cf31bea0f0fc8e16c2863..1c369b20dc45b7587ad0993cb272dd57390b50d1 100644 (file)
@@ -1,87 +1,11 @@
 #ifndef _M68K_FCNTL_H
 #define _M68K_FCNTL_H
 
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
-   located on an ext2 file system */
-#define O_ACCMODE        0003
-#define O_RDONLY           00
-#define O_WRONLY           01
-#define O_RDWR             02
-#define O_CREAT                  0100  /* not fcntl */
-#define O_EXCL           0200  /* not fcntl */
-#define O_NOCTTY         0400  /* not fcntl */
-#define O_TRUNC                 01000  /* not fcntl */
-#define O_APPEND        02000
-#define O_NONBLOCK      04000
-#define O_NDELAY       O_NONBLOCK
-#define O_SYNC         010000
-#define FASYNC         020000  /* fcntl, for BSD compatibility */
 #define O_DIRECTORY    040000  /* must be a directory */
 #define O_NOFOLLOW     0100000 /* don't follow links */
 #define O_DIRECT       0200000 /* direct disk access hint - currently ignored */
 #define O_LARGEFILE    0400000
-#define O_NOATIME      01000000
 
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
-#define F_GETLK                5
-#define F_SETLK                6
-#define F_SETLKW       7
+#include <asm-generic/fcntl.h>
 
-#define F_SETOWN       8       /*  for sockets. */
-#define F_GETOWN       9       /*  for sockets. */
-#define F_SETSIG       10      /*  for sockets. */
-#define F_GETSIG       11      /*  for sockets. */
-
-#define F_GETLK64      12      /*  using 'struct flock64' */
-#define F_SETLK64      13
-#define F_SETLKW64     14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK                0
-#define F_WRLCK                1
-#define F_UNLCK                2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
-
-struct flock {
-       short l_type;
-       short l_whence;
-       off_t l_start;
-       off_t l_len;
-       pid_t l_pid;
-};
-
-struct flock64 {
-       short  l_type;
-       short  l_whence;
-       loff_t l_start;
-       loff_t l_len;
-       pid_t  l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE  1024
 #endif /* _M68K_FCNTL_H */
diff --git a/include/asm-m68k/futex.h b/include/asm-m68k/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-m68k/hdreg.h b/include/asm-m68k/hdreg.h
deleted file mode 100644 (file)
index 5989bbc..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#warning this file is obsolete, please do not use it
index 206313e2a817798a3e6eb8d77f52230d19fa59b7..f206dfbc1d486268aff67915433f5f2bf7d54f04 100644 (file)
@@ -107,20 +107,6 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)       (((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
-/* Pure 2^n version of get_order */
-static inline int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size-1) >> (PAGE_SHIFT-1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
-
 #endif /* !__ASSEMBLY__ */
 
 #include <asm/page_offset.h>
@@ -192,4 +178,6 @@ static inline void *__va(unsigned long x)
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/page.h>
+
 #endif /* _M68K_PAGE_H */
index 8d0b9fc2d07e4ea82a64504591201ad83ccd8ea8..f578ca4b776a3bfcb45b1e60781ebeb74eac785c 100644 (file)
@@ -14,6 +14,8 @@
 #define SO_BROADCAST   6
 #define SO_SNDBUF      7
 #define SO_RCVBUF      8
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
 #define SO_KEEPALIVE   9
 #define SO_OOBINLINE   10
 #define SO_NO_CHECK    11
index 44def078132a756ec2790e7073d0f33eedf7407a..6c59215b285e0b9ab1d57c69bc582767edb9e483 100644 (file)
@@ -80,43 +80,6 @@ static inline char * strchr(const char * s, int c)
   return( (char *) s);
 }
 
-#if 0
-#define __HAVE_ARCH_STRPBRK
-static inline char *strpbrk(const char *cs,const char *ct)
-{
-  const char *sc1,*sc2;
-
-  for( sc1 = cs; *sc1 != '\0'; ++sc1)
-    for( sc2 = ct; *sc2 != '\0'; ++sc2)
-      if (*sc1 == *sc2)
-       return((char *) sc1);
-  return( NULL );
-}
-#endif
-
-#if 0
-#define __HAVE_ARCH_STRSPN
-static inline size_t strspn(const char *s, const char *accept)
-{
-  const char *p;
-  const char *a;
-  size_t count = 0;
-
-  for (p = s; *p != '\0'; ++p)
-    {
-      for (a = accept; *a != '\0'; ++a)
-        if (*p == *a)
-          break;
-      if (*a == '\0')
-        return count;
-      else
-        ++count;
-    }
-
-  return count;
-}
-#endif
-
 /* strstr !! */
 
 #define __HAVE_ARCH_STRLEN
@@ -173,370 +136,18 @@ static inline int strncmp(const char * cs,const char * ct,size_t count)
 }
 
 #define __HAVE_ARCH_MEMSET
-/*
- * This is really ugly, but its highly optimizatiable by the
- * compiler and is meant as compensation for gcc's missing
- * __builtin_memset(). For the 680[23]0        it might be worth considering
- * the optimal number of misaligned writes compared to the number of
- * tests'n'branches needed to align the destination address. The
- * 680[46]0 doesn't really care due to their copy-back caches.
- *                                             10/09/96 - Jes Sorensen
- */
-static inline void * __memset_g(void * s, int c, size_t count)
-{
-  void *xs = s;
-  size_t temp;
-
-  if (!count)
-    return xs;
-
-  c &= 0xff;
-  c |= c << 8;
-  c |= c << 16;
-
-  if (count < 36){
-         long *ls = s;
-
-         switch(count){
-         case 32: case 33: case 34: case 35:
-                 *ls++ = c;
-         case 28: case 29: case 30: case 31:
-                 *ls++ = c;
-         case 24: case 25: case 26: case 27:
-                 *ls++ = c;
-         case 20: case 21: case 22: case 23:
-                 *ls++ = c;
-         case 16: case 17: case 18: case 19:
-                 *ls++ = c;
-         case 12: case 13: case 14: case 15:
-                 *ls++ = c;
-         case 8: case 9: case 10: case 11:
-                 *ls++ = c;
-         case 4: case 5: case 6: case 7:
-                 *ls++ = c;
-                 break;
-         default:
-                 break;
-         }
-         s = ls;
-         if (count & 0x02){
-                 short *ss = s;
-                 *ss++ = c;
-                 s = ss;
-         }
-         if (count & 0x01){
-                 char *cs = s;
-                 *cs++ = c;
-                 s = cs;
-         }
-         return xs;
-  }
-
-  if ((long) s & 1)
-    {
-      char *cs = s;
-      *cs++ = c;
-      s = cs;
-      count--;
-    }
-  if (count > 2 && (long) s & 2)
-    {
-      short *ss = s;
-      *ss++ = c;
-      s = ss;
-      count -= 2;
-    }
-  temp = count >> 2;
-  if (temp)
-    {
-      long *ls = s;
-      temp--;
-      do
-       *ls++ = c;
-      while (temp--);
-      s = ls;
-    }
-  if (count & 2)
-    {
-      short *ss = s;
-      *ss++ = c;
-      s = ss;
-    }
-  if (count & 1)
-    {
-      char *cs = s;
-      *cs = c;
-    }
-  return xs;
-}
-
-/*
- * __memset_page assumes that data is longword aligned. Most, if not
- * all, of these page sized memsets are performed on page aligned
- * areas, thus we do not need to check if the destination is longword
- * aligned. Of course we suffer a serious performance loss if this is
- * not the case but I think the risk of this ever happening is
- * extremely small. We spend a lot of time clearing pages in
- * get_empty_page() so I think it is worth it anyway. Besides, the
- * 680[46]0 do not really care about misaligned writes due to their
- * copy-back cache.
- *
- * The optimized case for the 680[46]0 is implemented using the move16
- * instruction. My tests showed that this implementation is 35-45%
- * faster than the original implementation using movel, the only
- * caveat is that the destination address must be 16-byte aligned.
- *                                            01/09/96 - Jes Sorensen
- */
-static inline void * __memset_page(void * s,int c,size_t count)
-{
-  unsigned long data, tmp;
-  void *xs = s;
-
-  c = c & 255;
-  data = c | (c << 8);
-  data |= data << 16;
-
-#ifdef CPU_M68040_OR_M68060_ONLY
-
-  if (((unsigned long) s) & 0x0f)
-         __memset_g(s, c, count);
-  else{
-         unsigned long *sp = s;
-         *sp++ = data;
-         *sp++ = data;
-         *sp++ = data;
-         *sp++ = data;
-
-         __asm__ __volatile__("1:\t"
-                              ".chip 68040\n\t"
-                              "move16 %2@+,%0@+\n\t"
-                              ".chip 68k\n\t"
-                              "subqw  #8,%2\n\t"
-                              "subqw  #8,%2\n\t"
-                              "dbra   %1,1b\n\t"
-                              : "=a" (sp), "=d" (tmp)
-                              : "a" (s), "0" (sp), "1" ((count - 16) / 16 - 1)
-                              );
-  }
-
-#else
-  __asm__ __volatile__("1:\t"
-                      "movel %2,%0@+\n\t"
-                      "movel %2,%0@+\n\t"
-                      "movel %2,%0@+\n\t"
-                      "movel %2,%0@+\n\t"
-                      "movel %2,%0@+\n\t"
-                      "movel %2,%0@+\n\t"
-                      "movel %2,%0@+\n\t"
-                      "movel %2,%0@+\n\t"
-                      "dbra  %1,1b\n\t"
-                      : "=a" (s), "=d" (tmp)
-                      : "d" (data), "0" (s), "1" (count / 32 - 1)
-                      );
-#endif
-
-  return xs;
-}
-
-extern void *memset(void *,int,__kernel_size_t);
-
-#define __memset_const(s,c,count) \
-((count==PAGE_SIZE) ? \
-  __memset_page((s),(c),(count)) : \
-  __memset_g((s),(c),(count)))
-
-#define memset(s, c, count) \
-(__builtin_constant_p(count) ? \
- __memset_const((s),(c),(count)) : \
- __memset_g((s),(c),(count)))
+extern void *memset(void *, int, __kernel_size_t);
+#define memset(d, c, n) __builtin_memset(d, c, n)
 
 #define __HAVE_ARCH_MEMCPY
-extern void * memcpy(void *, const void *, size_t );
-/*
- * __builtin_memcpy() does not handle page-sized memcpys very well,
- * thus following the same assumptions as for page-sized memsets, this
- * function copies page-sized areas using an unrolled loop, without
- * considering alignment.
- *
- * For the 680[46]0 only kernels we use the move16 instruction instead
- * as it writes through the data-cache, invalidating the cache-lines
- * touched. In this way we do not use up the entire data-cache (well,
- * half of it on the 68060) by copying a page. An unrolled loop of two
- * move16 instructions seem to the fastest. The only caveat is that
- * both source and destination must be 16-byte aligned, if not we fall
- * back to the generic memcpy function.  - Jes
- */
-static inline void * __memcpy_page(void * to, const void * from, size_t count)
-{
-  unsigned long tmp;
-  void *xto = to;
-
-#ifdef CPU_M68040_OR_M68060_ONLY
-
-  if (((unsigned long) to | (unsigned long) from) & 0x0f)
-         return memcpy(to, from, count);
-
-  __asm__ __volatile__("1:\t"
-                      ".chip 68040\n\t"
-                      "move16 %1@+,%0@+\n\t"
-                      "move16 %1@+,%0@+\n\t"
-                      ".chip 68k\n\t"
-                      "dbra  %2,1b\n\t"
-                      : "=a" (to), "=a" (from), "=d" (tmp)
-                      : "0" (to), "1" (from) , "2" (count / 32 - 1)
-                      );
-#else
-  __asm__ __volatile__("1:\t"
-                      "movel %1@+,%0@+\n\t"
-                      "movel %1@+,%0@+\n\t"
-                      "movel %1@+,%0@+\n\t"
-                      "movel %1@+,%0@+\n\t"
-                      "movel %1@+,%0@+\n\t"
-                      "movel %1@+,%0@+\n\t"
-                      "movel %1@+,%0@+\n\t"
-                      "movel %1@+,%0@+\n\t"
-                      "dbra  %2,1b\n\t"
-                      : "=a" (to), "=a" (from), "=d" (tmp)
-                      : "0" (to), "1" (from) , "2" (count / 32 - 1)
-                      );
-#endif
-  return xto;
-}
-
-#define __memcpy_const(to, from, n) \
-((n==PAGE_SIZE) ? \
-  __memcpy_page((to),(from),(n)) : \
-  __builtin_memcpy((to),(from),(n)))
-
-#define memcpy(to, from, n) \
-(__builtin_constant_p(n) ? \
- __memcpy_const((to),(from),(n)) : \
- memcpy((to),(from),(n)))
+extern void *memcpy(void *, const void *, __kernel_size_t);
+#define memcpy(d, s, n) __builtin_memcpy(d, s, n)
 
 #define __HAVE_ARCH_MEMMOVE
-static inline void * memmove(void * dest,const void * src, size_t n)
-{
-  void *xdest = dest;
-  size_t temp;
-
-  if (!n)
-    return xdest;
-
-  if (dest < src)
-    {
-      if ((long) dest & 1)
-       {
-         char *cdest = dest;
-         const char *csrc = src;
-         *cdest++ = *csrc++;
-         dest = cdest;
-         src = csrc;
-         n--;
-       }
-      if (n > 2 && (long) dest & 2)
-       {
-         short *sdest = dest;
-         const short *ssrc = src;
-         *sdest++ = *ssrc++;
-         dest = sdest;
-         src = ssrc;
-         n -= 2;
-       }
-      temp = n >> 2;
-      if (temp)
-       {
-         long *ldest = dest;
-         const long *lsrc = src;
-         temp--;
-         do
-           *ldest++ = *lsrc++;
-         while (temp--);
-         dest = ldest;
-         src = lsrc;
-       }
-      if (n & 2)
-       {
-         short *sdest = dest;
-         const short *ssrc = src;
-         *sdest++ = *ssrc++;
-         dest = sdest;
-         src = ssrc;
-       }
-      if (n & 1)
-       {
-         char *cdest = dest;
-         const char *csrc = src;
-         *cdest = *csrc;
-       }
-    }
-  else
-    {
-      dest = (char *) dest + n;
-      src = (const char *) src + n;
-      if ((long) dest & 1)
-       {
-         char *cdest = dest;
-         const char *csrc = src;
-         *--cdest = *--csrc;
-         dest = cdest;
-         src = csrc;
-         n--;
-       }
-      if (n > 2 && (long) dest & 2)
-       {
-         short *sdest = dest;
-         const short *ssrc = src;
-         *--sdest = *--ssrc;
-         dest = sdest;
-         src = ssrc;
-         n -= 2;
-       }
-      temp = n >> 2;
-      if (temp)
-       {
-         long *ldest = dest;
-         const long *lsrc = src;
-         temp--;
-         do
-           *--ldest = *--lsrc;
-         while (temp--);
-         dest = ldest;
-         src = lsrc;
-       }
-      if (n & 2)
-       {
-         short *sdest = dest;
-         const short *ssrc = src;
-         *--sdest = *--ssrc;
-         dest = sdest;
-         src = ssrc;
-       }
-      if (n & 1)
-       {
-         char *cdest = dest;
-         const char *csrc = src;
-         *--cdest = *--csrc;
-       }
-    }
-  return xdest;
-}
+extern void *memmove(void *, const void *, __kernel_size_t);
 
 #define __HAVE_ARCH_MEMCMP
-extern int memcmp(const void * ,const void * ,size_t );
-#define memcmp(cs, ct, n) \
-(__builtin_constant_p(n) ? \
- __builtin_memcmp((cs),(ct),(n)) : \
- memcmp((cs),(ct),(n)))
-
-#define __HAVE_ARCH_MEMCHR
-static inline void *memchr(const void *cs, int c, size_t count)
-{
-       /* Someone else can optimize this, I don't care - tonym@mac.linux-m68k.org */
-       unsigned char *ret = (unsigned char *)cs;
-       for(;count>0;count--,ret++)
-               if(*ret == c) return ret;
-
-       return NULL;
-}
+extern int memcmp(const void *, const void *, __kernel_size_t);
+#define memcmp(d, s, n) __builtin_memcmp(d, s, n)
 
 #endif /* _M68K_STRING_H_ */
index f391cbe39b965c68c9fcfdc1301ccc31c21ba897..b5a1febc97d41d2658d6d25552d788ed3f1ce6ca 100644 (file)
@@ -60,8 +60,6 @@ typedef unsigned long long u64;
 typedef u32 dma_addr_t;
 typedef u32 dma64_addr_t;
 
-typedef unsigned short kmem_bufctl_t;
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index 605e6cb811f80847fc6646ace670d2312da7339e..f5cedf19cf682c51349cd4b0856162ad0d6a1bf0 100644 (file)
 /* We let the MMU do all checking */
 #define access_ok(type,addr,size) 1
 
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated verify_area(int type, const void *addr, unsigned long size)
-{
-       return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
 /*
  * The exception table consists of pairs of addresses: the first is the
  * address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-m68knommu/auxvec.h b/include/asm-m68knommu/auxvec.h
new file mode 100644 (file)
index 0000000..844d6d5
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __ASMm68k_AUXVEC_H
+#define __ASMm68k_AUXVEC_H
+
+#endif
diff --git a/include/asm-m68knommu/futex.h b/include/asm-m68knommu/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-m68knommu/hdreg.h b/include/asm-m68knommu/hdreg.h
deleted file mode 100644 (file)
index 5cdd9b0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-m68k/hdreg.h>
index 05e03df0ec290691d5913fd08fe26933b5dac34d..942dfbead27fa8f80a403b03420aa0543c294da4 100644 (file)
@@ -48,20 +48,6 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)       (((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size-1) >> (PAGE_SHIFT-1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
-
 extern unsigned long memory_start;
 extern unsigned long memory_end;
 
@@ -73,8 +59,8 @@ extern unsigned long memory_end;
 
 #ifndef __ASSEMBLY__
 
-#define __pa(vaddr)            virt_to_phys((void *)vaddr)
-#define __va(paddr)            phys_to_virt((unsigned long)paddr)
+#define __pa(vaddr)            virt_to_phys((void *)(vaddr))
+#define __va(paddr)            phys_to_virt((unsigned long)(paddr))
 
 #define virt_to_pfn(kaddr)     (__pa(kaddr) >> PAGE_SHIFT)
 #define pfn_to_virt(pfn)       __va((pfn) << PAGE_SHIFT)
@@ -84,6 +70,7 @@ extern unsigned long memory_end;
 
 #define pfn_to_page(pfn)       virt_to_page(pfn_to_virt(pfn))
 #define page_to_pfn(page)      virt_to_pfn(page_to_virt(page))
+#define pfn_valid(pfn)         ((pfn) < max_mapnr)
 
 #define        virt_addr_valid(kaddr)  (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \
                                ((void *)(kaddr) < (void *)memory_end))
@@ -92,4 +79,6 @@ extern unsigned long memory_end;
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/page.h>
+
 #endif /* _M68KNOMMU_PAGE_H */
index f0be74bb353c634d04ea2400e30b2a1d180e7ac1..05be9515a2d2e8509cdac90753c3903435b24b70 100644 (file)
@@ -23,12 +23,6 @@ static inline int _access_ok(unsigned long addr, unsigned long size)
                (is_in_rom(addr) && is_in_rom(addr+size)));
 }
 
-/* this function will go away soon - use access_ok() instead */
-extern inline int __deprecated verify_area(int type, const void * addr, unsigned long size)
-{
-       return access_ok(type,addr,size)?0:-EFAULT;
-}
-
 /*
  * The exception table consists of pairs of addresses: the first is the
  * address of an instruction that is allowed to fault, and the second is
index e42b3093e9038ae7980bf46ae26758334c40abe5..2b3dc3bed4dac632a85114034722d00f9aa51d3b 100644 (file)
@@ -35,10 +35,10 @@ struct exec
 
 #ifdef __KERNEL__
 
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 #define STACK_TOP      TASK_SIZE
 #endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 #define STACK_TOP      (current->thread.mflags & MF_32BIT_ADDR ? TASK_SIZE32 : TASK_SIZE)
 #endif
 
index 2caa8c427204721274a90a2c00c661b2e4d662f2..7dc2619f50067be595b725e9b1c0a32eef72fa32 100644 (file)
@@ -48,7 +48,7 @@
 #define CPHYSADDR(a)           ((_ACAST32_ (a)) & 0x1fffffff)
 #define XPHYSADDR(a)            ((_ACAST64_ (a)) & 0x000000ffffffffff)
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 
 /*
  * Memory segments (64bit kernel mode addresses)
index 37a460aa0378e5474d7718934ddf589de2c83ab1..30b18ea6cb1116fd12e86094788c5917fe9f7e99 100644 (file)
@@ -7,14 +7,14 @@
  */
 #ifndef _ASM_ASMMACRO_H
 #define _ASM_ASMMACRO_H
+
 #include <linux/config.h>
 #include <asm/hazards.h>
-#ifdef CONFIG_MIPS32
+
+#ifdef CONFIG_32BIT
 #include <asm/asmmacro-32.h>
 #endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 #include <asm/asmmacro-64.h>
 #endif
 
index 7d89e87bc8c6fd9544ef3b247f57421248741396..c0bd8d014e14740a6e49a66d85f60a115a42e951 100644 (file)
@@ -334,7 +334,7 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
  */
 #define atomic_add_negative(i,v) (atomic_add_return(i, (v)) < 0)
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 
 typedef struct { volatile __s64 counter; } atomic64_t;
 
@@ -639,7 +639,7 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
  */
 #define atomic64_add_negative(i,v) (atomic64_add_return(i, (v)) < 0)
 
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
 
 /*
  * atomic*_return operations are serializing but not the non-*_return
diff --git a/include/asm-mips/auxvec.h b/include/asm-mips/auxvec.h
new file mode 100644 (file)
index 0000000..7cf7f2d
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef _ASM_AUXVEC_H
+#define _ASM_AUXVEC_H
+
+#endif /* _ASM_AUXVEC_H */
index 779d2187a6a4448fdf7db89cb58f630fc06d7b3e..eb8d79dba11ca104710662bf7fd8a2b941729187 100644 (file)
 #define SZLONG_MASK 31UL
 #define __LL   "ll     "
 #define __SC   "sc     "
-#define cpu_to_lelongp(x) cpu_to_le32p((__u32 *) (x)) 
+#define cpu_to_lelongp(x) cpu_to_le32p((__u32 *) (x))
 #elif (_MIPS_SZLONG == 64)
 #define SZLONG_LOG 6
 #define SZLONG_MASK 63UL
 #define __LL   "lld    "
 #define __SC   "scd    "
-#define cpu_to_lelongp(x) cpu_to_le64p((__u64 *) (x)) 
+#define cpu_to_lelongp(x) cpu_to_le64p((__u64 *) (x))
 #endif
 
 #ifdef __KERNEL__
@@ -533,14 +533,14 @@ static inline unsigned long ffz(unsigned long word)
        int b = 0, s;
 
        word = ~word;
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
        s = 16; if (word << 16 != 0) s = 0; b += s; word >>= s;
        s =  8; if (word << 24 != 0) s = 0; b += s; word >>= s;
        s =  4; if (word << 28 != 0) s = 0; b += s; word >>= s;
        s =  2; if (word << 30 != 0) s = 0; b += s; word >>= s;
        s =  1; if (word << 31 != 0) s = 0; b += s;
 #endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        s = 32; if (word << 32 != 0) s = 0; b += s; word >>= s;
        s = 16; if (word << 48 != 0) s = 0; b += s; word >>= s;
        s =  8; if (word << 56 != 0) s = 0; b += s; word >>= s;
@@ -683,7 +683,7 @@ found_middle:
  */
 static inline int sched_find_first_bit(const unsigned long *b)
 {
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
        if (unlikely(b[0]))
                return __ffs(b[0]);
        if (unlikely(b[1]))
@@ -694,7 +694,7 @@ static inline int sched_find_first_bit(const unsigned long *b)
                return __ffs(b[3]) + 96;
        return __ffs(b[4]) + 128;
 #endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        if (unlikely(b[0]))
                return __ffs(b[0]);
        if (unlikely(b[1]))
index 18cced19cca430ed6a5c666ffe5008089fe847a2..b14b961c2100c4394305023f0621c50caf3fef31 100644 (file)
@@ -15,7 +15,7 @@ extern void check_bugs64(void);
 static inline void check_bugs(void)
 {
        check_bugs32();
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        check_bugs64();
 #endif
 }
index c25cc92b99508b4886aa4e021beafda484926d09..c1ea5a8714f346ef729ed92e0b6b9cfeae592ea6 100644 (file)
@@ -128,7 +128,7 @@ static inline unsigned int csum_tcpudp_nofold(unsigned long saddr,
 {
        __asm__(
        ".set\tnoat\t\t\t# csum_tcpudp_nofold\n\t"
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
        "addu\t%0, %2\n\t"
        "sltu\t$1, %0, %2\n\t"
        "addu\t%0, $1\n\t"
@@ -141,7 +141,7 @@ static inline unsigned int csum_tcpudp_nofold(unsigned long saddr,
        "sltu\t$1, %0, %4\n\t"
        "addu\t%0, $1\n\t"
 #endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
        "daddu\t%0, %2\n\t"
        "daddu\t%0, %3\n\t"
        "daddu\t%0, %4\n\t"
index d78002afb1e12927f080b13f930da9006d698ed1..2c084cd4bc0af81a2b3e3ad686022cfa18e3f3d9 100644 (file)
@@ -15,8 +15,10 @@ typedef s32          compat_clock_t;
 typedef s32            compat_suseconds_t;
 
 typedef s32            compat_pid_t;
-typedef s32            compat_uid_t;
-typedef s32            compat_gid_t;
+typedef u32            __compat_uid_t;
+typedef u32            __compat_gid_t;
+typedef u32            __compat_uid32_t;
+typedef u32            __compat_gid32_t;
 typedef u32            compat_mode_t;
 typedef u32            compat_ino_t;
 typedef u32            compat_dev_t;
@@ -52,8 +54,8 @@ struct compat_stat {
        compat_ino_t    st_ino;
        compat_mode_t   st_mode;
        compat_nlink_t  st_nlink;
-       compat_uid_t    st_uid;
-       compat_gid_t    st_gid;
+       __compat_uid32_t        st_uid;
+       __compat_gid32_t        st_gid;
        compat_dev_t    st_rdev;
        s32             st_pad2[2];
        compat_off_t    st_size;
index 1df2c299de825089ebf449fbb97e20b58c66fb31..9a2de642eee6376ae239fe7ced039d1d62c54242 100644 (file)
 #define PLAT_TRAMPOLINE_STUFF_LINE     0UL
 #endif
 
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 # ifndef cpu_has_nofpuex
 # define cpu_has_nofpuex       (cpu_data[0].options & MIPS_CPU_NOFPUEX)
 # endif
 # endif
 #endif
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 # ifndef cpu_has_nofpuex
 # define cpu_has_nofpuex               0
 # endif
index ae3e2a38fd5fad5daf620362916e73c9a5511a61..a438548e6ef3b6c9930f7bf52640ba65a23b5e2d 100644 (file)
@@ -247,7 +247,7 @@ extern void ll_vrc5477_irq_disable(int vrc5477_irq);
  *  All PCI irq but INTC are active low.
  */
 
-/* 
+/*
  * irq number block assignment
  */
 
@@ -285,7 +285,7 @@ extern void ll_vrc5477_irq_disable(int vrc5477_irq);
 #define VRC5477_IRQ_IOPCI_INTB (17 + VRC5477_IRQ_BASE)      /* USB-P */
 #define VRC5477_IRQ_IOPCI_INTC (18 + VRC5477_IRQ_BASE)      /* AC97 */
 #define VRC5477_IRQ_IOPCI_INTD (19 + VRC5477_IRQ_BASE)      /* Reserved */
-#define VRC5477_IRQ_UART1      (20 + VRC5477_IRQ_BASE)     
+#define VRC5477_IRQ_UART1      (20 + VRC5477_IRQ_BASE)
 #define VRC5477_IRQ_SPT0       (21 + VRC5477_IRQ_BASE)      /* special purpose timer 0 */
 #define VRC5477_IRQ_GPT0       (22 + VRC5477_IRQ_BASE)      /* general purpose timer 0 */
 #define VRC5477_IRQ_GPT1       (23 + VRC5477_IRQ_BASE)      /* general purpose timer 1 */
@@ -301,7 +301,7 @@ extern void ll_vrc5477_irq_disable(int vrc5477_irq);
 /*
  * i2859 irq assignment
  */
-#define I8259_IRQ_RESERVED_0   (0 + I8259_IRQ_BASE)    
+#define I8259_IRQ_RESERVED_0   (0 + I8259_IRQ_BASE)
 #define I8259_IRQ_KEYBOARD     (1 + I8259_IRQ_BASE)    /* M1543 default */
 #define I8259_IRQ_CASCADE      (2 + I8259_IRQ_BASE)
 #define I8259_IRQ_UART_B       (3 + I8259_IRQ_BASE)    /* M1543 default, may conflict with RTC according to schematic diagram  */
index b63e2f2317d15cf31dd27a9ed17590d8cee2c0a9..a05d6d3395fe49ef8628043eaafb03583fcd5671 100644 (file)
  */
 #define REX_PROM_MAGIC         0x30464354
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 
 #define prom_is_rex(magic)     1       /* KN04 and KN05 are REX PROMs.  */
 
-#else /* !CONFIG_MIPS64 */
+#else /* !CONFIG_64BIT */
 
 #define prom_is_rex(magic)     ((magic) == REX_PROM_MAGIC)
 
-#endif /* !CONFIG_MIPS64 */
+#endif /* !CONFIG_64BIT */
 
 
 /*
@@ -105,7 +105,7 @@ extern int (*__pmax_read)(int, void *, int);
 extern int (*__pmax_close)(int);
 
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 
 /*
  * On MIPS64 we have to call PROM functions via a helper
@@ -138,7 +138,7 @@ int _prom_printf(int (*)(char *, ...), char *, ...) __DEC_PROM_O32;
 #define prom_getenv(x)         _prom_getenv(__prom_getenv, x)
 #define prom_printf(x...)      _prom_printf(__prom_printf, x)
 
-#else /* !CONFIG_MIPS64 */
+#else /* !CONFIG_64BIT */
 
 /*
  * On plain MIPS we just call PROM functions directly.
@@ -160,7 +160,7 @@ int _prom_printf(int (*)(char *, ...), char *, ...) __DEC_PROM_O32;
 #define pmax_read              __pmax_read
 #define pmax_close             __pmax_close
 
-#endif /* !CONFIG_MIPS64 */
+#endif /* !CONFIG_64BIT */
 
 
 extern void prom_meminit(u32);
index d0f68447e5a713ba53fa185e2e44d5c9a009afdf..a606dbee0412a4be05efc66b370a3b1987b10323 100644 (file)
@@ -57,11 +57,11 @@ static inline void __udelay(unsigned long usecs, unsigned long lpj)
         * The common rates of 1000 and 128 are rounded wrongly by the
         * catchall case for 64-bit.  Excessive precission?  Probably ...
         */
-#if defined(CONFIG_MIPS64) && (HZ == 128)
+#if defined(CONFIG_64BIT) && (HZ == 128)
        usecs *= 0x0008637bd05af6c7UL;          /* 2**64 / (1000000 / HZ) */
-#elif defined(CONFIG_MIPS64) && (HZ == 1000)
+#elif defined(CONFIG_64BIT) && (HZ == 1000)
        usecs *= 0x004189374BC6A7f0UL;          /* 2**64 / (1000000 / HZ) */
-#elif defined(CONFIG_MIPS64)
+#elif defined(CONFIG_64BIT)
        usecs *= (0x8000000000000000UL / (500000 / HZ));
 #else /* 32-bit junk follows here */
        usecs *= (unsigned long) (((0x8000000000000000ULL / (500000 / HZ)) +
index 7b92c8045cc24593c513445498466a85e5d00382..e4881144001578c7b9adde069f068d1d746f0dde 100644 (file)
@@ -125,7 +125,7 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 typedef double elf_fpreg_t;
 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 
 /*
  * This is used to ensure we don't load something for the wrong architecture.
@@ -153,9 +153,9 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
  */
 #define ELF_CLASS      ELFCLASS32
 
-#endif /* CONFIG_MIPS32 */
+#endif /* CONFIG_32BIT */
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 /*
  * This is used to ensure we don't load something for the wrong architecture.
  */
@@ -177,7 +177,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
  */
 #define ELF_CLASS      ELFCLASS64
 
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
 
 /*
  * These are used to set parameters in the core dumps.
@@ -193,7 +193,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
 #ifdef __KERNEL__
 
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 
 #define SET_PERSONALITY(ex, ibcs2)                     \
 do {                                                   \
@@ -202,9 +202,9 @@ do {                                                        \
        set_personality(PER_LINUX);                     \
 } while (0)
 
-#endif /* CONFIG_MIPS32 */
+#endif /* CONFIG_32BIT */
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 
 #define SET_PERSONALITY(ex, ibcs2)                             \
 do {   current->thread.mflags &= ~MF_ABI_MASK;                 \
@@ -222,7 +222,7 @@ do {        current->thread.mflags &= ~MF_ABI_MASK;                 \
                set_personality(PER_LINUX);                     \
 } while (0)
 
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
 
 extern void dump_regs(elf_greg_t *, struct pt_regs *regs);
 extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *);
index 2436392e7990d1fec80312ccfcea02e9e3eeb28d..06c5d13faf6629f933c22c7f70cb9ceea14495dd 100644 (file)
@@ -8,33 +8,16 @@
 #ifndef _ASM_FCNTL_H
 #define _ASM_FCNTL_H
 
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
-   located on an ext2 file system */
-#define O_ACCMODE      0x0003
-#define O_RDONLY       0x0000
-#define O_WRONLY       0x0001
-#define O_RDWR         0x0002
 #define O_APPEND       0x0008
 #define O_SYNC         0x0010
 #define O_NONBLOCK     0x0080
 #define O_CREAT         0x0100 /* not fcntl */
-#define O_TRUNC                0x0200  /* not fcntl */
 #define O_EXCL         0x0400  /* not fcntl */
 #define O_NOCTTY       0x0800  /* not fcntl */
 #define FASYNC         0x1000  /* fcntl, for BSD compatibility */
 #define O_LARGEFILE    0x2000  /* allow large file opens */
 #define O_DIRECT       0x8000  /* direct disk access hint */
-#define O_DIRECTORY    0x10000 /* must be a directory */
-#define O_NOFOLLOW     0x20000 /* don't follow links */
-#define O_NOATIME      0x40000
 
-#define O_NDELAY       O_NONBLOCK
-
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
 #define F_GETLK                14
 #define F_SETLK                6
 #define F_SETLKW       7
 #define F_SETLKW64     35
 #endif
 
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK                0
-#define F_WRLCK                1
-#define F_UNLCK                2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
-
 /*
  * The flavours of struct flock.  "struct flock" is the ABI compliant
  * variant.  Finally struct flock64 is the LFS variant of struct flock.  As
@@ -86,7 +42,7 @@
 
 #ifndef __mips64
 
-typedef struct flock {
+struct flock {
        short   l_type;
        short   l_whence;
        __kernel_off_t l_start;
@@ -94,32 +50,17 @@ typedef struct flock {
        long    l_sysid;
        __kernel_pid_t l_pid;
        long    pad[4];
-} flock_t;
-
-typedef struct flock64 {
-       short   l_type;
-       short   l_whence;
-       loff_t  l_start;
-       loff_t  l_len;
-       pid_t   l_pid;
-} flock64_t;
+};
 
-#else /* 64-bit definitions */
+#define HAVE_ARCH_STRUCT_FLOCK
 
-typedef struct flock {
-       short   l_type;
-       short   l_whence;
-       __kernel_off_t l_start;
-       __kernel_off_t l_len;
-       __kernel_pid_t l_pid;
-} flock_t;
-
-#ifdef __KERNEL__
-#define flock64                flock
 #endif
 
-#endif
+#include <asm-generic/fcntl.h>
 
-#define F_LINUX_SPECIFIC_BASE  1024
+typedef struct flock flock_t;
+#ifndef __mips64
+typedef struct flock64 flock64_t;
+#endif
 
 #endif /* _ASM_FCNTL_H */
index 1d9aa097918110c97bb5e79d0f7a1237ba6b70d0..2b5fddc8f487c82c13bb0d53dc6c36c23eb02694 100644 (file)
@@ -13,7 +13,7 @@
 #define _ASM_FPREGDEF_H
 
 #include <asm/sgidefs.h>
-                                                                                
+
 #if _MIPS_SIM == _MIPS_SIM_ABI32
 
 /*
@@ -56,7 +56,7 @@
 #define fcr31  $31      /* FPU status register */
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
-                                                                                
+
 #if _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32
 
 #define fv0    $f0     /* return value */
index 6cb38d5c0407d0c13e1a0e50da60e04201bebea6..ea24e733b1bcf84a74e952258c5527dc9ad8b714 100644 (file)
@@ -82,7 +82,7 @@ do {                                                                  \
 
 static inline int is_fpu_owner(void)
 {
-       return cpu_has_fpu && test_thread_flag(TIF_USEDFPU); 
+       return cpu_has_fpu && test_thread_flag(TIF_USEDFPU);
 }
 
 static inline void own_fpu(void)
@@ -90,7 +90,7 @@ static inline void own_fpu(void)
        if (cpu_has_fpu) {
                __enable_fpu();
                KSTK_STATUS(current) |= ST0_CU1;
-               set_thread_flag(TIF_USEDFPU); 
+               set_thread_flag(TIF_USEDFPU);
        }
 }
 
@@ -98,7 +98,7 @@ static inline void lose_fpu(void)
 {
        if (cpu_has_fpu) {
                KSTK_STATUS(current) &= ~ST0_CU1;
-               clear_thread_flag(TIF_USEDFPU); 
+               clear_thread_flag(TIF_USEDFPU);
                __disable_fpu();
        }
 }
@@ -127,7 +127,7 @@ static inline void restore_fp(struct task_struct *tsk)
 static inline fpureg_t *get_fpu_regs(struct task_struct *tsk)
 {
        if (cpu_has_fpu) {
-               if ((tsk == current) && is_fpu_owner()) 
+               if ((tsk == current) && is_fpu_owner())
                        _save_fp(current);
                return tsk->thread.fpu.hard.fpr;
        }
diff --git a/include/asm-mips/futex.h b/include/asm-mips/futex.h
new file mode 100644 (file)
index 0000000..9feff4c
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-mips/hdreg.h b/include/asm-mips/hdreg.h
deleted file mode 100644 (file)
index 5989bbc..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#warning this file is obsolete, please do not use it
diff --git a/include/asm-mips/hp-lj/asic.h b/include/asm-mips/hp-lj/asic.h
deleted file mode 100644 (file)
index fc2ca65..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-
-typedef enum { IllegalAsic, UnknownAsic, AndrosAsic, HarmonyAsic } AsicId;
-
-AsicId GetAsicId(void);
-
-const char* const GetAsicName(void);
-
index 2b7b0fdeac194129060a2bc47bfc81dc57f5984a..432011b16c2671eb51af1a5493af229b13cf1e02 100644 (file)
@@ -94,7 +94,7 @@ struct mace_video {
        unsigned long xxx;      /* later... */
 };
 
-/* 
+/*
  * Ethernet interface
  */
 struct mace_ethernet {
@@ -129,7 +129,7 @@ struct mace_ethernet {
        volatile unsigned long rx_fifo;
 };
 
-/* 
+/*
  * Peripherals
  */
 
@@ -251,7 +251,7 @@ struct mace_timers {
        timer_reg audio_out2;
        timer_reg video_in1;
        timer_reg video_in2;
-       timer_reg video_out;    
+       timer_reg video_out;
 };
 
 struct mace_perif {
@@ -272,7 +272,7 @@ struct mace_perif {
 };
 
 
-/* 
+/*
  * ISA peripherals
  */
 
index 21d0fb7cee6435581e786f57a77993279db2408f..9e88c7669c7a5b68da73bcb8c8f1673b85d726c2 100644 (file)
@@ -1,13 +1,13 @@
 #include <asm/lasat/lasat.h>
 
 /* Lasat 100 boards serial configuration */
-#define LASAT_BASE_BAUD_100            ( 7372800 / 16 ) 
+#define LASAT_BASE_BAUD_100            ( 7372800 / 16 )
 #define LASAT_UART_REGS_BASE_100       0x1c8b0000
 #define LASAT_UART_REGS_SHIFT_100      2
 #define LASATINT_UART_100              8
 
 /* * LASAT 200 boards serial configuration */
-#define LASAT_BASE_BAUD_200            (100000000 / 16 / 12) 
+#define LASAT_BASE_BAUD_200            (100000000 / 16 / 12)
 #define LASAT_UART_REGS_BASE_200       (Vrc5074_PHYS_BASE + 0x0300)
 #define LASAT_UART_REGS_SHIFT_200      3
 #define LASATINT_UART_200              13
index 7eb6bf661b8037083e08210780279aad588f1460..c38844f615fc790896faef323b487dbd83c40249 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/percpu.h>
 #include <asm/atomic.h>
 
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 
 typedef atomic_t local_t;
 
@@ -20,7 +20,7 @@ typedef atomic_t local_t;
 
 #endif
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 
 typedef atomic64_t local_t;
 
index 2b36ea346910d9e3bd36cc6cfeae742bac379a1d..148bae2fa7d32cea726004a915cc074b61b01093 100644 (file)
@@ -1383,7 +1383,7 @@ extern au1xxx_irq_map_t au1xxx_irq_map[];
 #define PCI_IO_START    0
 #define PCI_IO_END      0
 #define PCI_MEM_START   0
-#define PCI_MEM_END     0 
+#define PCI_MEM_END     0
 #define PCI_FIRST_DEVFN 0
 #define PCI_LAST_DEVFN  0
 #endif
index 4691398a414fe40560431957a884edc8744f8c40..efafe65258b6eb664b766e8844b2766a07eb41ae 100644 (file)
@@ -23,7 +23,7 @@
  *
  * ########################################################################
  *
- * 
+ *
  */
 #ifndef __ASM_DB1X00_H
 #define __ASM_DB1X00_H
index 63c0a81c78329ca8728a2d2bc7d5661f51458bd9..5a2c1efb4eb7bf47a3c2212263f69c7bb7337616 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 
 #define CAC_BASE               0x80000000
 #define IO_BASE                        0xa0000000
@@ -32,9 +32,9 @@
 #define HIGHMEM_START          0x20000000UL
 #endif
 
-#endif /* CONFIG_MIPS32 */
+#endif /* CONFIG_32BIT */
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 
 /*
  * This handles the memory map.
@@ -67,6 +67,6 @@
 #define TO_CAC(x)              (CAC_BASE   | ((x) & TO_PHYS_MASK))
 #define TO_UNCAC(x)            (UNCAC_BASE | ((x) & TO_PHYS_MASK))
 
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
 
 #endif /* __ASM_MACH_GENERIC_SPACES_H */
index 30d42fcafe3d8d03b60576d2532704faf2764e91..e96166f27c49282dc557fb2d06d423e6f76b2caf 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 
 #define CAC_BASE               0x80000000
 #define IO_BASE                        0xa0000000
@@ -32,9 +32,9 @@
 #define HIGHMEM_START          0x20000000UL
 #endif
 
-#endif /* CONFIG_MIPS32 */
+#endif /* CONFIG_32BIT */
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 #define PAGE_OFFSET            0xffffffff80000000UL
 
 #ifndef HIGHMEM_START
@@ -50,6 +50,6 @@
 #define TO_CAC(x)              (CAC_BASE   | ((x) & TO_PHYS_MASK))
 #define TO_UNCAC(x)            (UNCAC_BASE | ((x) & TO_PHYS_MASK))
 
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
 
 #endif /* __ASM_MACH_IP22_SPACES_H */
index b932237f2193ffbc874fdb33d261c0cdd9e47ce5..04713973c6c39f6f38ee0f5735719a7fe52e3c7f 100644 (file)
@@ -18,7 +18,7 @@
  * so, for 64bit IP32 kernel we just don't use ll/sc.
  * This does not affect luserland.
  */
-#if defined(CONFIG_CPU_R5000) && defined(CONFIG_MIPS64)
+#if defined(CONFIG_CPU_R5000) && defined(CONFIG_64BIT)
 #define cpu_has_llsc           0
 #else
 #define cpu_has_llsc           1
index 8cf0d042c864f6d8913fa6084535398eeee399b9..c9dad99b12324aaaffa8a55c62367b865740266d 100644 (file)
@@ -92,7 +92,7 @@ static inline int fd_request_irq(void)
        return request_irq(FLOPPY_IRQ, floppy_interrupt,
                           SA_INTERRUPT | SA_SAMPLE_RANDOM, "floppy", NULL);
 }
-                                                                                
+
 static inline void fd_free_irq(void)
 {
        free_irq(FLOPPY_IRQ, NULL);
index d6c779747b3cdd4128e324a18b17f84dd56544b0..ff6d40c87a25b0859e8782d35ca99e089faa25da 100644 (file)
 #define PCI_BOARD_REG             0xAE000010
 #define PCMCIA_BOARD_REG          0xAE000010
   #define PC_DEASSERT_RST               0x80
-  #define PC_DRV_EN                     0x10 
+  #define PC_DRV_EN                     0x10
 #define PB1500_G_CONTROL          0xAE000014
 #define PB1500_RST_VDDI           0xAE00001C
 #define PB1500_LEDS               0xAE000018
-  
+
 #define PB1500_HEX_LED            0xAF000004
 #define PB1500_HEX_LED_BLANK      0xAF000008
 
diff --git a/include/asm-mips/mach-qemu/cpu-feature-overrides.h b/include/asm-mips/mach-qemu/cpu-feature-overrides.h
new file mode 100644 (file)
index 0000000..f4e370e
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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 (C) 2003 Ralf Baechle
+ */
+#ifndef __ASM_MACH_QEMU_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_QEMU_CPU_FEATURE_OVERRIDES_H
+
+/*
+ * QEMU only comes with a hazard-free MIPS32 processor, so things are easy.
+ */
+#define cpu_has_mips16         0
+#define cpu_has_divec          0
+#define cpu_has_cache_cdex_p   0
+#define cpu_has_prefetch       0
+#define cpu_has_mcheck         0
+#define cpu_has_ejtag          0
+
+#define cpu_has_llsc           1
+#define cpu_has_vtag_icache    0
+#define cpu_has_dc_aliases     (PAGE_SIZE < 0x4000)
+#define cpu_has_ic_fills_f_dc  0
+
+#define cpu_has_dsp            0
+
+#define cpu_has_nofpuex                0
+#define cpu_has_64bits         0
+
+#endif /* __ASM_MACH_QEMU_CPU_FEATURE_OVERRIDES_H */
diff --git a/include/asm-mips/mach-qemu/param.h b/include/asm-mips/mach-qemu/param.h
new file mode 100644 (file)
index 0000000..cb30ee4
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * 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 (C) 2005 by Ralf Baechle
+ */
+#ifndef __ASM_MACH_QEMU_PARAM_H
+#define __ASM_MACH_QEMU_PARAM_H
+
+#define HZ             100             /* Internal kernel timer frequency */
+
+#endif /* __ASM_MACH_QEMU_PARAM_H */
diff --git a/include/asm-mips/mach-vr41xx/timex.h b/include/asm-mips/mach-vr41xx/timex.h
deleted file mode 100644 (file)
index 8d71485..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2003 by Ralf Baechle
- */
-/*
- * Changes:
- *  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
- *  - CLOCK_TICK_RATE is changed into 32768 from 6144000.
- */
-#ifndef __ASM_MACH_VR41XX_TIMEX_H
-#define __ASM_MACH_VR41XX_TIMEX_H
-
-#define CLOCK_TICK_RATE                32768
-
-#endif /* __ASM_MACH_VR41XX_TIMEX_H */
index 48b77c9fb4f2f8642342f7479a0ca0ab4ef4e7d7..45cd72d172e8caa52a2c23cc3adbc1e7af4b94a8 100644 (file)
@@ -28,17 +28,17 @@ extern unsigned long pgd_current[];
 #define TLBMISS_HANDLER_SETUP_PGD(pgd) \
        pgd_current[smp_processor_id()] = (unsigned long)(pgd)
 
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 #define TLBMISS_HANDLER_SETUP()                                                \
        write_c0_context((unsigned long) smp_processor_id() << 23);     \
        TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
 #endif
-#if defined(CONFIG_MIPS64) && !defined(CONFIG_BUILD_ELF64)
+#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
 #define TLBMISS_HANDLER_SETUP()                                                \
        write_c0_context((unsigned long) &pgd_current[smp_processor_id()] << 23); \
        TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
 #endif
-#if defined(CONFIG_MIPS64) && defined(CONFIG_BUILD_ELF64)
+#if defined(CONFIG_64BIT) && defined(CONFIG_BUILD_ELF64)
 #define TLBMISS_HANDLER_SETUP()                                                \
        write_c0_context((unsigned long) smp_processor_id() << 23);     \
        TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
index 90ee24aad955efbeebb29c45f67f9e7ac3c438d9..0be58b2aeb9ffab857d2a739c19c00f990c70b0b 100644 (file)
@@ -25,7 +25,7 @@ typedef struct
   Elf64_Sxword r_addend;               /* Addend.  */
 } Elf64_Mips_Rela;
 
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 
 #define Elf_Shdr       Elf32_Shdr
 #define Elf_Sym                Elf32_Sym
@@ -33,7 +33,7 @@ typedef struct
 
 #endif
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 
 #define Elf_Shdr       Elf64_Shdr
 #define Elf_Sym                Elf64_Sym
index 513b2824838b314c6025283b247d8ce5f70fb9e2..a1533959742e4693f69f1f6b2311db956cc5cd01 100644 (file)
 
 struct msqid64_ds {
        struct ipc64_perm msg_perm;
-#if defined(CONFIG_MIPS32) && !defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if defined(CONFIG_32BIT) && !defined(CONFIG_CPU_LITTLE_ENDIAN)
        unsigned long   __unused1;
 #endif
        __kernel_time_t msg_stime;      /* last msgsnd time */
-#if defined(CONFIG_MIPS32) && defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if defined(CONFIG_32BIT) && defined(CONFIG_CPU_LITTLE_ENDIAN)
        unsigned long   __unused1;
 #endif
-#if defined(CONFIG_MIPS32) && !defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if defined(CONFIG_32BIT) && !defined(CONFIG_CPU_LITTLE_ENDIAN)
        unsigned long   __unused2;
 #endif
        __kernel_time_t msg_rtime;      /* last msgrcv time */
-#if defined(CONFIG_MIPS32) && defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if defined(CONFIG_32BIT) && defined(CONFIG_CPU_LITTLE_ENDIAN)
        unsigned long   __unused2;
 #endif
-#if defined(CONFIG_MIPS32) && !defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if defined(CONFIG_32BIT) && !defined(CONFIG_CPU_LITTLE_ENDIAN)
        unsigned long   __unused3;
 #endif
        __kernel_time_t msg_ctime;      /* last change time */
-#if defined(CONFIG_MIPS32) && defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if defined(CONFIG_32BIT) && defined(CONFIG_CPU_LITTLE_ENDIAN)
        unsigned long   __unused3;
 #endif
        unsigned long  msg_cbytes;      /* current number of bytes on queue */
index 36cec9e31696ecdc12191eec39c1625e51e715ed..309bc3099f68d9904e374168a0b923257333e6c6 100644 (file)
 #include <linux/config.h>
 #include <linux/errno.h>
 
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 #define __PA_ADDR      ".word"
 #endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 #define __PA_ADDR      ".dword"
 #endif
 
index 5cae35cd9ba923f76e49754d5a81757fdd2f83ad..652b6d67a57189b8792a8388e94c71e547aad302 100644 (file)
@@ -103,20 +103,6 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 #define __pgd(x)       ((pgd_t) { (x) } )
 #define __pgprot(x)    ((pgprot_t) { (x) } )
 
-/* Pure 2^n version of get_order */
-static __inline__ int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size-1) >> (PAGE_SHIFT-1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
-
 #endif /* !__ASSEMBLY__ */
 
 /* to align the pointer to the (next) page boundary */
@@ -148,4 +134,6 @@ static __inline__ int get_order(unsigned long size)
 #define WANT_PAGE_VIRTUAL
 #endif
 
+#include <asm-generic/page.h>
+
 #endif /* _ASM_PAGE_H */
index d70dc355c1f320bf6bdd5a2fb4542a93ff82a481..c9a00ca1c012098931854e96bfe17d9f47c78eeb 100644 (file)
@@ -94,7 +94,7 @@ struct pci_dev;
  */
 extern unsigned int PCI_DMA_BUS_IS_PHYS;
 
-#ifdef CONFIG_MAPPED_DMA_IO
+#ifdef CONFIG_DMA_NEED_PCI_MAP_STATE
 
 /* pci_unmap_{single,page} is not a nop, thus... */
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      dma_addr_t ADDR_NAME;
@@ -104,7 +104,7 @@ extern unsigned int PCI_DMA_BUS_IS_PHYS;
 #define pci_unmap_len(PTR, LEN_NAME)           ((PTR)->LEN_NAME)
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)  (((PTR)->LEN_NAME) = (VAL))
 
-#else /* CONFIG_MAPPED_DMA_IO  */
+#else /* CONFIG_DMA_NEED_PCI_MAP_STATE  */
 
 /* pci_unmap_{page,single} is a nop so... */
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
@@ -114,7 +114,7 @@ extern unsigned int PCI_DMA_BUS_IS_PHYS;
 #define pci_unmap_len(PTR, LEN_NAME)           (0)
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
 
-#endif /* CONFIG_MAPPED_DMA_IO  */
+#endif /* CONFIG_DMA_NEED_PCI_MAP_STATE  */
 
 /* This is always fine. */
 #define pci_dac_dma_supported(pci_dev, mask)   (1)
@@ -142,6 +142,8 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
 
 extern void pcibios_resource_to_bus(struct pci_dev *dev,
        struct pci_bus_region *region, struct resource *res);
+extern void pcibios_bus_to_resource(struct pci_dev *dev,
+       struct resource *res, struct pci_bus_region *region);
 
 #ifdef CONFIG_PCI_DOMAINS
 
@@ -167,4 +169,17 @@ static inline void pcibios_add_platform_entries(struct pci_dev *dev)
 /* Do platform specific device initialization at pci_enable_device() time */
 extern int pcibios_plat_dev_init(struct pci_dev *dev);
 
+static inline struct resource *
+pcibios_select_root(struct pci_dev *pdev, struct resource *res)
+{
+       struct resource *root = NULL;
+
+       if (res->flags & IORESOURCE_IO)
+               root = &ioport_resource;
+       if (res->flags & IORESOURCE_MEM)
+               root = &iomem_resource;
+
+       return root;
+}
+
 #endif /* _ASM_PCI_H */
index 2d63f5ba403fe24b6568ff73a21b856a50ed62d8..ce57288d43bd5cdbea3d7ea0bc5d18de9d091e9d 100644 (file)
@@ -85,7 +85,7 @@ static inline void pte_free(struct page *pte)
 
 #define __pte_free_tlb(tlb,pte)                tlb_remove_page((tlb),(pte))
 
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 #define pgd_populate(mm, pmd, pte)     BUG()
 
 /*
@@ -97,7 +97,7 @@ static inline void pte_free(struct page *pte)
 #define __pmd_free_tlb(tlb,x)          do { } while (0)
 #endif
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 
 #define pgd_populate(mm, pgd, pmd)     set_pgd(pgd, __pgd(pmd))
 
index e76ccd6e3a5dcc8ef9760d7a48bc62b2414af3d8..dbe13da0bdadbe55affd38c3999ed4e0eb04593b 100644 (file)
 #include <asm-generic/4level-fixup.h>
 
 #include <linux/config.h>
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 #include <asm/pgtable-32.h>
 #endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 #include <asm/pgtable-64.h>
 #endif
 
index 13c54d5b3b48a3f258f8dbcdcb227009626e207f..d6466aa09fb7a181a1dd07a52ac646b3c8755c06 100644 (file)
@@ -33,7 +33,7 @@ extern void (*cpu_wait)(void);
 
 extern unsigned int vced_count, vcei_count;
 
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 /*
  * User space process size: 2GB. This is hardcoded into a few places,
  * so don't change it unless you know what you are doing.
@@ -47,7 +47,7 @@ extern unsigned int vced_count, vcei_count;
 #define TASK_UNMAPPED_BASE     (PAGE_ALIGN(TASK_SIZE / 3))
 #endif
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 /*
  * User space process size: 1TB. This is hardcoded into a few places,
  * so don't change it unless you know what you are doing.  TASK_SIZE
index d3c46d6338266f7c29300d54fce0ad9e4c2c1ab6..2b5c624c3d4fe790ec638d94ca2492b31560f0ed 100644 (file)
@@ -28,7 +28,7 @@
  * system call/exception. As usual the registers k0/k1 aren't being saved.
  */
 struct pt_regs {
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
        /* Pad bytes for argument save space on the stack. */
        unsigned long pad0[6];
 #endif
diff --git a/include/asm-mips/qemu.h b/include/asm-mips/qemu.h
new file mode 100644 (file)
index 0000000..905c395
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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 (C) 2005 by Ralf Baechle (ralf@linux-mips.org)
+ */
+#ifndef __ASM_QEMU_H
+#define __ASM_QEMU_H
+
+/*
+ * Interrupt numbers
+ */
+#define Q_PIC_IRQ_BASE         0
+#define Q_COUNT_COMPARE_IRQ    16
+
+/*
+ * Qemu clock rate.  Unlike on real MIPS this has no relation to the
+ * instruction issue rate, so the choosen value is pure fiction, just needs
+ * to match the value in Qemu itself.
+ */
+#define QEMU_C0_COUNTER_CLOCK  100000000
+
+#endif /* __ASM_QEMU_H */
index da03a32c1ca785ed8b1b10d3811f8da8fb41153b..5bea49feec66c85dc32395804e4c6157eaef6607 100644 (file)
@@ -171,11 +171,11 @@ static inline void blast_dcache16(void)
        unsigned long start = INDEX_BASE;
        unsigned long end = start + current_cpu_data.dcache.waysize;
        unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit;
-       unsigned long ws_end = current_cpu_data.dcache.ways << 
+       unsigned long ws_end = current_cpu_data.dcache.ways <<
                               current_cpu_data.dcache.waybit;
        unsigned long ws, addr;
 
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
                for (addr = start; addr < end; addr += 0x200)
                        cache16_unroll32(addr|ws,Index_Writeback_Inv_D);
 }
@@ -200,8 +200,8 @@ static inline void blast_dcache16_page_indexed(unsigned long page)
                               current_cpu_data.dcache.waybit;
        unsigned long ws, addr;
 
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
-               for (addr = start; addr < end; addr += 0x200) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
+               for (addr = start; addr < end; addr += 0x200)
                        cache16_unroll32(addr|ws,Index_Writeback_Inv_D);
 }
 
@@ -214,8 +214,8 @@ static inline void blast_icache16(void)
                               current_cpu_data.icache.waybit;
        unsigned long ws, addr;
 
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
-               for (addr = start; addr < end; addr += 0x200) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
+               for (addr = start; addr < end; addr += 0x200)
                        cache16_unroll32(addr|ws,Index_Invalidate_I);
 }
 
@@ -239,8 +239,8 @@ static inline void blast_icache16_page_indexed(unsigned long page)
                               current_cpu_data.icache.waybit;
        unsigned long ws, addr;
 
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
-               for (addr = start; addr < end; addr += 0x200) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
+               for (addr = start; addr < end; addr += 0x200)
                        cache16_unroll32(addr|ws,Index_Invalidate_I);
 }
 
@@ -249,11 +249,11 @@ static inline void blast_scache16(void)
        unsigned long start = INDEX_BASE;
        unsigned long end = start + current_cpu_data.scache.waysize;
        unsigned long ws_inc = 1UL << current_cpu_data.scache.waybit;
-       unsigned long ws_end = current_cpu_data.scache.ways << 
+       unsigned long ws_end = current_cpu_data.scache.ways <<
                               current_cpu_data.scache.waybit;
        unsigned long ws, addr;
 
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
                for (addr = start; addr < end; addr += 0x200)
                        cache16_unroll32(addr|ws,Index_Writeback_Inv_SD);
 }
@@ -278,8 +278,8 @@ static inline void blast_scache16_page_indexed(unsigned long page)
                               current_cpu_data.scache.waybit;
        unsigned long ws, addr;
 
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
-               for (addr = start; addr < end; addr += 0x200) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
+               for (addr = start; addr < end; addr += 0x200)
                        cache16_unroll32(addr|ws,Index_Writeback_Inv_SD);
 }
 
@@ -318,8 +318,8 @@ static inline void blast_dcache32(void)
                               current_cpu_data.dcache.waybit;
        unsigned long ws, addr;
 
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
-               for (addr = start; addr < end; addr += 0x400) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
+               for (addr = start; addr < end; addr += 0x400)
                        cache32_unroll32(addr|ws,Index_Writeback_Inv_D);
 }
 
@@ -343,8 +343,8 @@ static inline void blast_dcache32_page_indexed(unsigned long page)
                               current_cpu_data.dcache.waybit;
        unsigned long ws, addr;
 
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
-               for (addr = start; addr < end; addr += 0x400) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
+               for (addr = start; addr < end; addr += 0x400)
                        cache32_unroll32(addr|ws,Index_Writeback_Inv_D);
 }
 
@@ -357,8 +357,8 @@ static inline void blast_icache32(void)
                               current_cpu_data.icache.waybit;
        unsigned long ws, addr;
 
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
-               for (addr = start; addr < end; addr += 0x400) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
+               for (addr = start; addr < end; addr += 0x400)
                        cache32_unroll32(addr|ws,Index_Invalidate_I);
 }
 
@@ -383,7 +383,7 @@ static inline void blast_icache32_page_indexed(unsigned long page)
        unsigned long ws, addr;
 
        for (ws = 0; ws < ws_end; ws += ws_inc)
-               for (addr = start; addr < end; addr += 0x400) 
+               for (addr = start; addr < end; addr += 0x400)
                        cache32_unroll32(addr|ws,Index_Invalidate_I);
 }
 
@@ -392,11 +392,11 @@ static inline void blast_scache32(void)
        unsigned long start = INDEX_BASE;
        unsigned long end = start + current_cpu_data.scache.waysize;
        unsigned long ws_inc = 1UL << current_cpu_data.scache.waybit;
-       unsigned long ws_end = current_cpu_data.scache.ways << 
+       unsigned long ws_end = current_cpu_data.scache.ways <<
                               current_cpu_data.scache.waybit;
        unsigned long ws, addr;
 
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
                for (addr = start; addr < end; addr += 0x400)
                        cache32_unroll32(addr|ws,Index_Writeback_Inv_SD);
 }
@@ -421,8 +421,8 @@ static inline void blast_scache32_page_indexed(unsigned long page)
                               current_cpu_data.scache.waybit;
        unsigned long ws, addr;
 
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
-               for (addr = start; addr < end; addr += 0x400) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
+               for (addr = start; addr < end; addr += 0x400)
                        cache32_unroll32(addr|ws,Index_Writeback_Inv_SD);
 }
 
@@ -461,8 +461,8 @@ static inline void blast_icache64(void)
                               current_cpu_data.icache.waybit;
        unsigned long ws, addr;
 
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
-               for (addr = start; addr < end; addr += 0x800) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
+               for (addr = start; addr < end; addr += 0x800)
                        cache64_unroll32(addr|ws,Index_Invalidate_I);
 }
 
@@ -487,7 +487,7 @@ static inline void blast_icache64_page_indexed(unsigned long page)
        unsigned long ws, addr;
 
        for (ws = 0; ws < ws_end; ws += ws_inc)
-               for (addr = start; addr < end; addr += 0x800) 
+               for (addr = start; addr < end; addr += 0x800)
                        cache64_unroll32(addr|ws,Index_Invalidate_I);
 }
 
@@ -496,11 +496,11 @@ static inline void blast_scache64(void)
        unsigned long start = INDEX_BASE;
        unsigned long end = start + current_cpu_data.scache.waysize;
        unsigned long ws_inc = 1UL << current_cpu_data.scache.waybit;
-       unsigned long ws_end = current_cpu_data.scache.ways << 
+       unsigned long ws_end = current_cpu_data.scache.ways <<
                               current_cpu_data.scache.waybit;
        unsigned long ws, addr;
 
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
                for (addr = start; addr < end; addr += 0x800)
                        cache64_unroll32(addr|ws,Index_Writeback_Inv_SD);
 }
@@ -525,8 +525,8 @@ static inline void blast_scache64_page_indexed(unsigned long page)
                               current_cpu_data.scache.waybit;
        unsigned long ws, addr;
 
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
-               for (addr = start; addr < end; addr += 0x800) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
+               for (addr = start; addr < end; addr += 0x800)
                        cache64_unroll32(addr|ws,Index_Writeback_Inv_SD);
 }
 
@@ -561,11 +561,11 @@ static inline void blast_scache128(void)
        unsigned long start = INDEX_BASE;
        unsigned long end = start + current_cpu_data.scache.waysize;
        unsigned long ws_inc = 1UL << current_cpu_data.scache.waybit;
-       unsigned long ws_end = current_cpu_data.scache.ways << 
+       unsigned long ws_end = current_cpu_data.scache.ways <<
                               current_cpu_data.scache.waybit;
        unsigned long ws, addr;
 
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
                for (addr = start; addr < end; addr += 0x1000)
                        cache128_unroll32(addr|ws,Index_Writeback_Inv_SD);
 }
@@ -590,8 +590,8 @@ static inline void blast_scache128_page_indexed(unsigned long page)
                               current_cpu_data.scache.waybit;
        unsigned long ws, addr;
 
-       for (ws = 0; ws < ws_end; ws += ws_inc) 
-               for (addr = start; addr < end; addr += 0x1000) 
+       for (ws = 0; ws < ws_end; ws += ws_inc)
+               for (addr = start; addr < end; addr += 0x1000)
                        cache128_unroll32(addr|ws,Index_Writeback_Inv_SD);
 }
 
index 7b33bbca95857f8f7fdcbcb7670d3ebb74ac0dea..6173004cc88ec72f443f617fdbf17b3a7ad3a32a 100644 (file)
@@ -14,7 +14,7 @@
 
 #include <linux/config.h>
 
-#if defined(CONFIG_MIPS32) || defined(WANT_COMPAT_REG_H)
+#if defined(CONFIG_32BIT) || defined(WANT_COMPAT_REG_H)
 
 #define EF_R0                  6
 #define EF_R1                  7
@@ -70,7 +70,7 @@
 
 #endif
 
-#if CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 
 #define EF_R0                   0
 #define EF_R1                   1
 
 #define EF_SIZE                        304     /* size in bytes */
 
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
 
 #endif /* __ASM_MIPS_REG_H */
index fd3c6d17a5f63e89aedd39e27c3dd4086c65e795..1fba00c2207714bc83c3911ca393954ec3afb1b1 100644 (file)
@@ -27,7 +27,7 @@
  * but we keep the old value on MIPS32,
  * for compatibility:
  */
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 # define RLIM_INFINITY         0x7fffffffUL
 #endif
 
index 31c0c2347f4f82ead18ab5979d917ea1abf828d6..3c4b637fd925894da65134e0ec82c33d84053f11 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * include/asm-mips/rtc.h 
+ * include/asm-mips/rtc.h
  *
  * (Really an interface for drivers/char/genrtc.c)
  *
index a38d66f9987240058bb263bd69e63d481e9fbe12..889cf028c95d4b2e3e4c39918c01a19bcb2462a3 100644 (file)
@@ -16,7 +16,7 @@
  *
  * The Indigo and Indy have two GIO bus connectors. Indigo2 (all models) have
  * three physical connectors, but only two slots, GFX and EXP0.
- * 
+ *
  * There is 10MB of GIO address space for GIO64 slot devices
  * slot#   slot type address range            size
  * -----   --------- ----------------------- -----
index a5b988d7327ab1a3c765921bf91e7f3ae7cae78a..ac3dfc7af5b0e9b78a4d663e8d8855fe2096eb9c 100644 (file)
@@ -221,7 +221,7 @@ struct hpc3_regs {
 #define HPC3_BESTAT_PIDMASK    0x3f700 /* DMA channel parity identifier */
 
        u32 _unused1[0x14000/4 - 5];    /* padding */
-       
+
        /* Now direct PIO per-HPC3 peripheral access to external regs. */
        volatile u32 scsi0_ext[256];    /* SCSI channel 0 external regs */
        u32 _unused2[0x7c00/4];
@@ -304,7 +304,7 @@ struct hpc3_regs {
        volatile u32 bbram[8192-50-14]; /* Battery backed ram */
 };
 
-/* 
+/*
  * It is possible to have two HPC3's within the address space on
  * one machine, though only having one is more likely on an Indy.
  */
index 169187f53fbc8df39e72de48a14fc1e6de2685bc..f3e3dc9bb73239341d280f0f9eab70d20c2b756e 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/types.h>
 #include <asm/sgi/pi1.h>
 
-/* 
+/*
  * All registers are 8-bit wide alligned on 32-bit boundary. Bad things
  * happen if you try word access them. You have been warned.
  */
@@ -138,7 +138,7 @@ struct sgioc_regs {
        u8 _sysid[3];
        volatile u8 sysid;
 #define SGIOC_SYSID_FULLHOUSE  0x01
-#define SGIOC_SYSID_BOARDREV(x)        ((x & 0xe0) > 5) 
+#define SGIOC_SYSID_BOARDREV(x)        ((x & 0xe0) > 5)
 #define SGIOC_SYSID_CHIPREV(x) ((x & 0x1e) > 1)
        u32 _unused2;
        u8 _read[3];
index 97d73adb4e40b67b89d268b29de7a444e8fcd8e9..bbfc05c3cab93c26137930b7e5b1fece233f0036 100644 (file)
@@ -12,7 +12,7 @@
 #ifndef _SGI_IP22_H
 #define _SGI_IP22_H
 
-/* 
+/*
  * These are the virtual IRQ numbers, we divide all IRQ's into
  * 'spaces', the 'space' determines where and how to enable/disable
  * that particular IRQ on an SGI machine. HPC DMA and MC DMA interrups
index fd98f930607c12db13e355b2b53516f0b903da2c..c52f7834c7c87e9252d260eaa716d7dd82b761d4 100644 (file)
@@ -182,14 +182,14 @@ struct sgimc_regs {
        volatile u32 dtlb_hi3;
        u32 _unused33;
        volatile u32 dtlb_lo3;
-       
+
        u32 _unused34[0x0392];
-       
+
        u32 _unused35;
        volatile u32 rpsscounter;       /* Chirps at 100ns */
 
        u32 _unused36[0x1000/4-2*4];
-       
+
        u32 _unused37;
        volatile u32 maddronly;         /* Address DMA goes at */
        u32 _unused38;
index 59450335f04982f1000b8b4f818d0b82a73d61a1..722b77a8c5e5a010fe693374ac37644c7a6cd43f 100644 (file)
@@ -367,7 +367,7 @@ struct linux_smonblock {
  * Macros for calling a 32-bit ARC implementation from 64-bit code
  */
 
-#if defined(CONFIG_MIPS64) && defined(CONFIG_ARC32)
+#if defined(CONFIG_64BIT) && defined(CONFIG_ARC32)
 
 #define __arc_clobbers                                                 \
        "$2","$3" /* ... */, "$8","$9","$10","$11",                     \
@@ -476,10 +476,10 @@ struct linux_smonblock {
        __res;                                                          \
 })
 
-#endif /* defined(CONFIG_MIPS64) && defined(CONFIG_ARC32) */
+#endif /* defined(CONFIG_64BIT) && defined(CONFIG_ARC32) */
 
-#if (defined(CONFIG_MIPS32) && defined(CONFIG_ARC32)) ||               \
-    (defined(CONFIG_MIPS64) && defined(CONFIG_ARC64))
+#if (defined(CONFIG_32BIT) && defined(CONFIG_ARC32)) ||                \
+    (defined(CONFIG_64BIT) && defined(CONFIG_ARC64))
 
 #define ARC_CALL0(dest)                                                        \
 ({     long __res;                                                     \
index 7ac5da13ce8a15a7b9ebdd7d4dbd49320bf64471..b5e7dae19f0fc7842d5a10fdc4379af41254dde3 100644 (file)
 
 #define SIBYTE_BOARD_NAME "Carmel"
 
-#define GPIO_PHY_INTERRUPT      2 
-#define GPIO_NONMASKABLE_INT    3 
-#define GPIO_CF_INSERTED        6 
-#define GPIO_MONTEREY_RESET     7 
-#define GPIO_QUADUART_INT       8 
-#define GPIO_CF_INT             9 
+#define GPIO_PHY_INTERRUPT      2
+#define GPIO_NONMASKABLE_INT    3
+#define GPIO_CF_INSERTED        6
+#define GPIO_MONTEREY_RESET     7
+#define GPIO_QUADUART_INT       8
+#define GPIO_CF_INT             9
 #define GPIO_FPGA_CCLK          10
 #define GPIO_FPGA_DOUT          11
 #define GPIO_FPGA_DIN           12
index 96088fb074a4e8103f5090917610fcf53b517623..40ef97c76c8b531f4c523765d7fc710b593ce981 100644 (file)
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
-    *  Global constants and macros             File: sb1250_defs.h     
-    *  
+    *
+    *  Global constants and macros             File: sb1250_defs.h
+    *
     *  This file contains macros and definitions used by the other
     *  include files.
     *
     *  SB1250 specification level:  User's manual 1/02/02
-    *  
+    *
     *  Author:  Mitch Lichtenberg
-    *  
-    *********************************************************************  
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001,2002,2003
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  This program is free software; you can redistribute it and/or 
-    *  modify it under the terms of the GNU General Public License as 
-    *  published by the Free Software Foundation; either version 2 of 
+    *
+    *  This program is free software; you can redistribute it and/or
+    *  modify it under the terms of the GNU General Public License as
+    *  published by the Free Software Foundation; either version 2 of
     *  the License, or (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
 #define        SIBYTE_HDR_FMASK_112x_ALL               0x0000f00
 #define        SIBYTE_HDR_FMASK_112x_PASS1             0x0000100
 
-/* Bit mask for chip/revision.  (use _ALL for all revisions of a chip).  */ 
+/* Bit mask for chip/revision.  (use _ALL for all revisions of a chip).  */
 #define        SIBYTE_HDR_FMASK(chip, pass)                                    \
     (SIBYTE_HDR_FMASK_ ## chip ## _ ## pass)
 #define        SIBYTE_HDR_FMASK_ALLREVS(chip)                                  \
 
 /*  *********************************************************************
     *  Naming schemes for constants in these files:
-    *  
-    *  M_xxx           MASK constant (identifies bits in a register). 
+    *
+    *  M_xxx           MASK constant (identifies bits in a register).
     *                  For multi-bit fields, all bits in the field will
     *                  be set.
     *
     *  K_xxx           "Code" constant (value for data in a multi-bit
     *                  field).  The value is right justified.
     *
-    *  V_xxx           "Value" constant.  This is the same as the 
+    *  V_xxx           "Value" constant.  This is the same as the
     *                  corresponding "K_xxx" constant, except it is
     *                  shifted to the correct position in the register.
     *
     *  S_xxx           SHIFT constant.  This is the number of bits that
-    *                  a field value (code) needs to be shifted 
+    *                  a field value (code) needs to be shifted
     *                  (towards the left) to put the value in the right
     *                  position for the register.
     *
-    *  A_xxx           ADDRESS constant.  This will be a physical 
+    *  A_xxx           ADDRESS constant.  This will be a physical
     *                  address.  Use the PHYS_TO_K1 macro to generate
     *                  a K1SEG address.
     *
     *  R_xxx           RELATIVE offset constant.  This is an offset from
     *                  an A_xxx constant (usually the first register in
     *                  a group).
-    *  
+    *
     *  G_xxx(X)        GET value.  This macro obtains a multi-bit field
     *                  from a register, masks it, and shifts it to
     *                  the bottom of the register (retrieving a K_xxx
 
 
 /*
- * Cast to 64-bit number.  Presumably the syntax is different in 
+ * Cast to 64-bit number.  Presumably the syntax is different in
  * assembly language.
  *
  * Note: you'll need to define uint32_t and uint64_t in your headers.
index f1b08d32338db002e4794f848d9670dbf135571a..3cdb48f50ed02f594272c6b3ea8c868f17ac68fd 100644 (file)
@@ -1,24 +1,24 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  DMA definitions                         File: sb1250_dma.h
-    *  
+    *
     *  This module contains constants and macros useful for
     *  programming the SB1250's DMA controllers, both the data mover
     *  and the Ethernet DMA.
-    *  
+    *
     *  SB1250 specification level:  User's manual 1/02/02
-    *  
+    *
     *  Author:  Mitch Lichtenberg
-    *  
-    *********************************************************************  
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001,2002,2003
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  This program is free software; you can redistribute it and/or 
-    *  modify it under the terms of the GNU General Public License as 
-    *  published by the Free Software Foundation; either version 2 of 
+    *
+    *  This program is free software; you can redistribute it and/or
+    *  modify it under the terms of the GNU General Public License as
+    *  published by the Free Software Foundation; either version 2 of
     *  the License, or (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
@@ -28,7 +28,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -43,9 +43,9 @@
     *  DMA Registers
     ********************************************************************* */
 
-/* 
+/*
  * Ethernet and Serial DMA Configuration Register 0  (Table 7-4)
- * Registers: DMA_CONFIG0_MAC_x_RX_CH_0 
+ * Registers: DMA_CONFIG0_MAC_x_RX_CH_0
  * Registers: DMA_CONFIG0_MAC_x_TX_CH_0
  * Registers: DMA_CONFIG0_SER_x_RX
  * Registers: DMA_CONFIG0_SER_x_TX
@@ -98,7 +98,7 @@
 
 /*
  * Ethernet and Serial DMA Configuration Register 1 (Table 7-5)
- * Registers: DMA_CONFIG1_MAC_x_RX_CH_0 
+ * Registers: DMA_CONFIG1_MAC_x_RX_CH_0
  * Registers: DMA_CONFIG1_DMA_x_TX_CH_0
  * Registers: DMA_CONFIG1_SER_x_RX
  * Registers: DMA_CONFIG1_SER_x_TX
 /*
  * DMA Descriptor Count Registers (Table 7-8)
  */
+
 /* No bitfields */
 
 
-/* 
+/*
  * Current Descriptor Address Register (Table 7-11)
  */
 
 #define V_DMA_DSCRB_STATUS(x)       _SB_MAKEVALUE(x,S_DMA_DSCRB_STATUS)
 #define G_DMA_DSCRB_STATUS(x)       _SB_GETVALUE(x,S_DMA_DSCRB_STATUS,M_DMA_DSCRB_STATUS)
 
-/* 
+/*
  * Ethernet Descriptor Status Bits (Table 7-15)
  */
 
 #define M_DMA_ETHRX_BADIP4CS        _SB_MAKEMASK1(51)
 #define M_DMA_ETHRX_DSCRERR        _SB_MAKEMASK1(52)
 
-#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) 
+#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1)
 /* Note: BADTCPCS is actually in DSCR_B options field */
 #define M_DMA_ETHRX_BADTCPCS   _SB_MAKEMASK1(0)
 #endif /* 1250 PASS2 || 112x PASS1 */
 
 #define M_DMA_ETHTX_SOP                    _SB_MAKEMASK1(63)
 
-/* 
+/*
  * Ethernet Transmit Options (Table 7-17)
  */
 
     *  Data Mover Registers
     ********************************************************************* */
 
-/* 
+/*
  * Data Mover Descriptor Base Address Register (Table 7-22)
  * Register: DM_DSCR_BASE_0
  * Register: DM_DSCR_BASE_1
 #define M_DM_DSCR_BASE_ABORT        _SB_MAKEMASK1(62)
 #define M_DM_DSCR_BASE_ENABL        _SB_MAKEMASK1(63)
 
-/* 
+/*
  * Data Mover Descriptor Count Register (Table 7-25)
  */
 
index 0d9dfac3d7db737dc7ee19d7f97d997adde49466..f1f509f295c4dfe66aa8c65667211b6c4878ec32 100644 (file)
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  Generic Bus Constants                     File: sb1250_genbus.h
-    *  
-    *  This module contains constants and macros useful for 
+    *
+    *  This module contains constants and macros useful for
     *  manipulating the SB1250's Generic Bus interface
-    *  
+    *
     *  SB1250 specification level:  User's manual 1/02/02
-    *  
+    *
     *  Author:  Mitch Lichtenberg
-    *  
-    *********************************************************************  
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001,2002,2003
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  This program is free software; you can redistribute it and/or 
-    *  modify it under the terms of the GNU General Public License as 
-    *  published by the Free Software Foundation; either version 2 of 
+    *
+    *  This program is free software; you can redistribute it and/or
+    *  modify it under the terms of the GNU General Public License as
+    *  published by the Free Software Foundation; either version 2 of
     *  the License, or (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
index c3f74df211f4bdc67fa7931cd6345071b11afa34..e173e2ea4c981c60630b8e78dcc789344776142a 100644 (file)
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  Interrupt Mapper definitions            File: sb1250_int.h
-    *  
+    *
     *  This module contains constants for manipulating the SB1250's
     *  interrupt mapper and definitions for the interrupt sources.
-    *  
+    *
     *  SB1250 specification level:  User's manual 1/02/02
-    *  
+    *
     *  Author:  Mitch Lichtenberg
-    *  
-    *********************************************************************  
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001,2002,2003
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  This program is free software; you can redistribute it and/or 
-    *  modify it under the terms of the GNU General Public License as 
-    *  published by the Free Software Foundation; either version 2 of 
+    *
+    *  This program is free software; you can redistribute it and/or
+    *  modify it under the terms of the GNU General Public License as
+    *  published by the Free Software Foundation; either version 2 of
     *  the License, or (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -43,7 +43,7 @@
 
 /*
  * Interrupt sources (Table 4-8, UM 0.2)
- * 
+ *
  * First, the interrupt numbers.
  */
 
index 799db828d9632a48c643e44583c0ebc4c636e802..8afe8e01581b3cac16d133ad28208f0a319cd113 100644 (file)
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  L2 Cache constants and macros           File: sb1250_l2c.h
-    *  
+    *
     *  This module contains constants useful for manipulating the
     *  level 2 cache.
-    *  
+    *
     *  SB1250 specification level:  User's manual 1/02/02
-    *  
+    *
     *  Author:  Mitch Lichtenberg
-    *  
-    *********************************************************************  
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001,2002,2003
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  This program is free software; you can redistribute it and/or 
-    *  modify it under the terms of the GNU General Public License as 
-    *  published by the Free Software Foundation; either version 2 of 
+    *
+    *  This program is free software; you can redistribute it and/or
+    *  modify it under the terms of the GNU General Public License as
+    *  published by the Free Software Foundation; either version 2 of
     *  the License, or (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
index d8753885df1727ca5f5ae753b72413aeadc2d064..f2617ded0a8f0f80a56fd10bdbbe5297beff6df4 100644 (file)
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  LDT constants                           File: sb1250_ldt.h
-    *  
-    *  This module contains constants and macros to describe 
-    *  the LDT interface on the SB1250.  
-    *  
+    *
+    *  This module contains constants and macros to describe
+    *  the LDT interface on the SB1250.
+    *
     *  SB1250 specification level:  User's manual 1/02/02
-    *  
+    *
     *  Author:  Mitch Lichtenberg
-    *  
-    *********************************************************************  
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001,2002,2003
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  This program is free software; you can redistribute it and/or 
-    *  modify it under the terms of the GNU General Public License as 
-    *  published by the Free Software Foundation; either version 2 of 
+    *
+    *  This program is free software; you can redistribute it and/or
+    *  modify it under the terms of the GNU General Public License as
+    *  published by the Free Software Foundation; either version 2 of
     *  the License, or (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
 
 /*
  * LDT Status Register (Table 8-14).  Note that these constants
- * assume you've read the command and status register 
+ * assume you've read the command and status register
  * together (32-bit read at offset 0x04)
  *
  * These bits also apply to the secondary status
 #define M_LDT_STATUS_DETPARERR         _SB_MAKEMASK1_32(31)
 
 /*
- * Bridge Control Register (Table 8-16).  Note that these 
- * constants assume you've read the register as a 32-bit 
+ * Bridge Control Register (Table 8-16).  Note that these
+ * constants assume you've read the register as a 32-bit
  * read (offset 0x3C)
  */
 
index 81f603f03a98ff11dfc8b08f3972d5cfbf6f2142..18e74e43f4a2b7fd34333c03512ebc982d912610 100644 (file)
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  MAC constants and macros                        File: sb1250_mac.h
-    *  
+    *
     *  This module contains constants and macros for the SB1250's
     *  ethernet controllers.
-    *  
+    *
     *  SB1250 specification level:  User's manual 1/02/02
-    *  
+    *
     *  Author:  Mitch Lichtenberg
-    *  
-    *********************************************************************  
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001,2002,2003
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  This program is free software; you can redistribute it and/or 
-    *  modify it under the terms of the GNU General Public License as 
-    *  published by the Free Software Foundation; either version 2 of 
+    *
+    *  This program is free software; you can redistribute it and/or
+    *  modify it under the terms of the GNU General Public License as
+    *  published by the Free Software Foundation; either version 2 of
     *  the License, or (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
 
 /*
  * These constants are used to configure the fields within the Frame
- * Configuration Register.  
+ * Configuration Register.
  */
 
 #define K_MAC_IFG_RX_10             _SB_MAKE64(0)      /* See table 176, not used */
  * Register: MAC_INT_MASK_2
  */
 
-/* 
+/*
  * Use these constants to shift the appropriate channel
  * into the CH0 position so the same tests can be used
  * on each channel.
index 93a48334b874cbabb65f2b589ab164849b49f0d1..1dd41c9279965c476bc5ea3d846e7e295488d977 100644 (file)
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
-    *  Memory Controller constants              File: sb1250_mc.h       
-    *  
+    *
+    *  Memory Controller constants              File: sb1250_mc.h
+    *
     *  This module contains constants and macros useful for
     *  programming the memory controller.
-    *  
+    *
     *  SB1250 specification level:  User's manual 1/02/02
-    *  
+    *
     *  Author:  Mitch Lichtenberg
-    *  
-    *********************************************************************  
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001,2002,2003
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  This program is free software; you can redistribute it and/or 
-    *  modify it under the terms of the GNU General Public License as 
-    *  published by the Free Software Foundation; either version 2 of 
+    *
+    *  This program is free software; you can redistribute it and/or
+    *  modify it under the terms of the GNU General Public License as
+    *  published by the Free Software Foundation; either version 2 of
     *  the License, or (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
 
 #define K_MC_REF_RATE_100MHz         0x62
 #define K_MC_REF_RATE_133MHz         0x81
-#define K_MC_REF_RATE_200MHz         0xC4 
+#define K_MC_REF_RATE_200MHz         0xC4
 
 #define V_MC_REF_RATE_100MHz         V_MC_REF_RATE(K_MC_REF_RATE_100MHz)
 #define V_MC_REF_RATE_133MHz         V_MC_REF_RATE(K_MC_REF_RATE_133MHz)
                                      V_MC_ADDR_DRIVE_DEFAULT | \
                                      V_MC_DATA_DRIVE_DEFAULT | \
                                      V_MC_CLOCK_DRIVE_DEFAULT | \
-                                     V_MC_REF_RATE_DEFAULT 
+                                     V_MC_REF_RATE_DEFAULT
 
 
 
index 5d496c6faba61931e182a2f32a3794c9ad9cee1f..9db80cd13a79f7025d02eee7be4e067d9d45fa3a 100644 (file)
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  Register Definitions                     File: sb1250_regs.h
-    *  
+    *
     *  This module contains the addresses of the on-chip peripherals
     *  on the SB1250.
-    *  
+    *
     *  SB1250 specification level:  01/02/2002
-    *  
+    *
     *  Author:  Mitch Lichtenberg
-    *  
-    *********************************************************************  
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001,2002,2003
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  This program is free software; you can redistribute it and/or 
-    *  modify it under the terms of the GNU General Public License as 
-    *  published by the Free Software Foundation; either version 2 of 
+    *
+    *  This program is free software; you can redistribute it and/or
+    *  modify it under the terms of the GNU General Public License as
+    *  published by the Free Software Foundation; either version 2 of
     *  the License, or (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
 
 /*  *********************************************************************
     *  Some general notes:
-    *  
+    *
     *  For the most part, when there is more than one peripheral
     *  of the same type on the SOC, the constants below will be
     *  offsets from the base of each peripheral.  For example,
     *  the MAC registers are described as offsets from the first
     *  MAC register, and there will be a MAC_REGISTER() macro
-    *  to calculate the base address of a given MAC.  
-    *  
+    *  to calculate the base address of a given MAC.
+    *
     *  The information in this file is based on the SB1250 SOC
     *  manual version 0.2, July 2000.
     ********************************************************************* */
 
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * Memory Controller Registers
     ********************************************************************* */
 
 #define R_MC_TEST_ECC               0x0000000420
 #define R_MC_MCLK_CFG               0x0000000500
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * L2 Cache Control Registers
     ********************************************************************* */
 
 #define A_L2_EEC_ADDRESS            A_L2_ECC_TAG
 
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * PCI Interface Registers
     ********************************************************************* */
 
 #define A_PCI_TYPE01_HEADER         0x00DE000800
 
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * Ethernet DMA and MACs
     ********************************************************************* */
 
             (R_MAC_DMA_CHANNEL_BASE(txrx,chan) +    \
             (reg))
 
-/* 
+/*
  * DMA channel registers, relative to A_MAC_DMA_CHANNEL_BASE
  */
 
 #define MAC_CHMAP_COUNT                        4
 
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * DUART Registers
     ********************************************************************* */
 
 #endif /* 1250 PASS2 || 112x PASS1 */
 
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * Synchronous Serial Registers
     ********************************************************************* */
 
             (reg))
 
 
-/* 
+/*
  * DMA channel registers, relative to A_SER_DMA_CHANNEL_BASE
  */
 
 #define R_SER_RMON_RX_ERRORS        0x000001F0
 #define R_SER_RMON_RX_BADADDR       0x000001F8
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * Generic Bus Registers
     ********************************************************************* */
 
 #define R_IO_PCMCIA_CFG             0x0A60
 #define R_IO_PCMCIA_STATUS          0x0A70
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * GPIO Registers
     ********************************************************************* */
 
 #define R_GPIO_PIN_CLR              0x30
 #define R_GPIO_PIN_SET              0x38
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * SMBus Registers
     ********************************************************************* */
 
 #define R_SMB_CONTROL               0x0000000060
 #define R_SMB_PEC                   0x0000000070
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * Timer Registers
     ********************************************************************* */
 
 #endif /* 1250 PASS2 || 112x PASS1 */
 
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Control Registers
     ********************************************************************* */
 
 #define A_SCD_SYSTEM_CFG            0x0010020008
 #define A_SCD_SYSTEM_MANUF          0x0010038000
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Address Trap Registers
     ********************************************************************* */
 
 #endif /* 1250 PASS2 || 112x PASS1 */
 
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Interrupt Mapper Registers
     ********************************************************************* */
 
 #define R_IMR_INTERRUPT_MAP_BASE        0x0200
 #define R_IMR_INTERRUPT_MAP_COUNT       64
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Performance Counter Registers
     ********************************************************************* */
 
 #define A_SCD_PERF_CNT_2            0x00100204E0
 #define A_SCD_PERF_CNT_3            0x00100204E8
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Bus Watcher Registers
     ********************************************************************* */
 
 #define A_BUS_L2_ERRORS             0x00100208C0
 #define A_BUS_MEM_IO_ERRORS         0x00100208C8
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Debug Controller Registers
     ********************************************************************* */
 
 #define A_SCD_JTAG_BASE             0x0010000000
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Trace Buffer Registers
     ********************************************************************* */
 
 #define A_SCD_TRACE_SEQUENCE_6      0x0010020A90
 #define A_SCD_TRACE_SEQUENCE_7      0x0010020A98
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Generic DMA Registers
     ********************************************************************* */
 
index 22e8041959e26d211fdb4904a92d2028c6fbcd5d..dbbd682fb47e6955a905608ee30f79efaacc5733 100644 (file)
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  SCD Constants and Macros                        File: sb1250_scd.h
-    *  
+    *
     *  This module contains constants and macros useful for
     *  manipulating the System Control and Debug module on the 1250.
-    *  
+    *
     *  SB1250 specification level:  User's manual 1/02/02
-    *  
+    *
     *  Author:  Mitch Lichtenberg
-    *  
-    *********************************************************************  
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001,2002,2003
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  This program is free software; you can redistribute it and/or 
-    *  modify it under the terms of the GNU General Public License as 
-    *  published by the Free Software Foundation; either version 2 of 
+    *
+    *  This program is free software; you can redistribute it and/or
+    *  modify it under the terms of the GNU General Public License as
+    *  published by the Free Software Foundation; either version 2 of
     *  the License, or (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
 /* System Manufacturing Register
 * Register: SCD_SYSTEM_MANUF
 */
+
 /* Wafer ID: bits 31:0 */
 #define S_SYS_WAFERID1_200        _SB_MAKE64(0)
 #define M_SYS_WAFERID1_200        _SB_MAKEMASK(32,S_SYS_WAFERID1_200)
 #define V_SYS_WAFERID1_200(x)     _SB_MAKEVALUE(x,S_SYS_WAFERID1_200)
 #define G_SYS_WAFERID1_200(x)     _SB_GETVALUE(x,S_SYS_WAFERID1_200,M_SYS_WAFERID1_200)
+
 #define S_SYS_BIN                 _SB_MAKE64(32)
 #define M_SYS_BIN                 _SB_MAKEMASK(4,S_SYS_BIN)
 #define V_SYS_BIN                 _SB_MAKEVALUE(x,S_SYS_BIN)
 #define G_SYS_BIN                 _SB_GETVALUE(x,S_SYS_BIN,M_SYS_BIN)
+
 /* Wafer ID: bits 39:36 */
 #define S_SYS_WAFERID2_200        _SB_MAKE64(36)
 #define M_SYS_WAFERID2_200        _SB_MAKEMASK(4,S_SYS_WAFERID2_200)
 #define V_SYS_WAFERID2_200(x)     _SB_MAKEVALUE(x,S_SYS_WAFERID2_200)
 #define G_SYS_WAFERID2_200(x)     _SB_GETVALUE(x,S_SYS_WAFERID2_200,M_SYS_WAFERID2_200)
+
 /* Wafer ID: bits 39:0 */
 #define S_SYS_WAFERID_300         _SB_MAKE64(0)
 #define M_SYS_WAFERID_300         _SB_MAKEMASK(40,S_SYS_WAFERID_300)
 #define V_SYS_WAFERID_300(x)      _SB_MAKEVALUE(x,S_SYS_WAFERID_300)
 #define G_SYS_WAFERID_300(x)      _SB_GETVALUE(x,S_SYS_WAFERID_300,M_SYS_WAFERID_300)
+
 #define S_SYS_XPOS                _SB_MAKE64(40)
 #define M_SYS_XPOS                _SB_MAKEMASK(6,S_SYS_XPOS)
 #define V_SYS_XPOS(x)             _SB_MAKEVALUE(x,S_SYS_XPOS)
 #define G_SYS_XPOS(x)             _SB_GETVALUE(x,S_SYS_XPOS,M_SYS_XPOS)
+
 #define S_SYS_YPOS                _SB_MAKE64(46)
 #define M_SYS_YPOS                _SB_MAKEMASK(6,S_SYS_YPOS)
 #define V_SYS_YPOS(x)             _SB_MAKEVALUE(x,S_SYS_YPOS)
 #define G_SYS_YPOS(x)             _SB_GETVALUE(x,S_SYS_YPOS,M_SYS_YPOS)
+
 /*
  * System Config Register (Table 4-2)
  * Register: SCD_SYSTEM_CFG
index 287cbfe9efa2ce48c2034ee6485c024fd91fb0bd..335c53e9293648afe9d132a2e52bb853f2cf0042 100644 (file)
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  SMBUS Constants                          File: sb1250_smbus.h
-    *  
-    *  This module contains constants and macros useful for 
+    *
+    *  This module contains constants and macros useful for
     *  manipulating the SB1250's SMbus devices.
-    *  
+    *
     *  SB1250 specification level:  01/02/2002
-    *  
+    *
     *  Author:  Mitch Lichtenberg
-    *  
-    *********************************************************************  
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001,2002,2003
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  This program is free software; you can redistribute it and/or 
-    *  modify it under the terms of the GNU General Public License as 
-    *  published by the Free Software Foundation; either version 2 of 
+    *
+    *  This program is free software; you can redistribute it and/or
+    *  modify it under the terms of the GNU General Public License as
+    *  published by the Free Software Foundation; either version 2 of
     *  the License, or (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
index 8d5e8edd3c4b9f34ac0abc94cceb9cb9d3b9a8d8..fa2760d38b8b1efd34dd51b7d44231f52dce7f12 100644 (file)
@@ -7,17 +7,17 @@
     *  manipulating the SB1250's Synchronous Serial
     *
     *  SB1250 specification level:  User's manual 1/02/02
-    *  
+    *
     *  Author:  Mitch Lichtenberg
     *
     *********************************************************************
     *
     *  Copyright 2000,2001,2002,2003
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  This program is free software; you can redistribute it and/or 
-    *  modify it under the terms of the GNU General Public License as 
-    *  published by the Free Software Foundation; either version 2 of 
+    *
+    *  This program is free software; you can redistribute it and/or
+    *  modify it under the terms of the GNU General Public License as
+    *  published by the Free Software Foundation; either version 2 of
     *  the License, or (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
index 7655d6945cca2bd167deece5e9e02e1ccdfe12f4..923ea4f44e0f785df2b5b50d4c9d08ced1214a5d 100644 (file)
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  UART Constants                          File: sb1250_uart.h
-    *  
-    *  This module contains constants and macros useful for 
+    *
+    *  This module contains constants and macros useful for
     *  manipulating the SB1250's UARTs
     *
     *  SB1250 specification level:  User's manual 1/02/02
-    *  
+    *
     *  Author:  Mitch Lichtenberg
-    *  
-    *********************************************************************  
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001,2002,2003
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  This program is free software; you can redistribute it and/or 
-    *  modify it under the terms of the GNU General Public License as 
-    *  published by the Free Software Foundation; either version 2 of 
+    *
+    *  This program is free software; you can redistribute it and/or
+    *  modify it under the terms of the GNU General Public License as
+    *  published by the Free Software Foundation; either version 2 of
     *  the License, or (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -37,7 +37,7 @@
 
 #include "sb1250_defs.h"
 
-/* ********************************************************************** 
+/* **********************************************************************
    * DUART Registers
    ********************************************************************** */
 
 #define V_DUART_MISC_CMD_START_BREAK     V_DUART_MISC_CMD(K_DUART_MISC_CMD_START_BREAK)
 #define V_DUART_MISC_CMD_STOP_BREAK      V_DUART_MISC_CMD(K_DUART_MISC_CMD_STOP_BREAK)
 
-#define M_DUART_CMD_RESERVED             _SB_MAKEMASK1(7) 
+#define M_DUART_CMD_RESERVED             _SB_MAKEMASK1(7)
 
 /*
  * DUART Status Register (Table 10-6)
 
 /*
  * DUART Baud Rate Register (Table 10-7)
- * Register: DUART_CLK_SEL_A 
+ * Register: DUART_CLK_SEL_A
  * Register: DUART_CLK_SEL_B
  */
 
     (chan == 0 ? M_DUART_OUT_PIN_CLR0 : M_DUART_OUT_PIN_CLR1)
 
 #if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1)
-/* 
+/*
  * Full Interrupt Control Register
  */
 
index 18939e84b6f2b13c6149f81ddba80aac0d2940bc..f7fbebaa074483af0d19c2e93d8a18811d82ea1c 100644 (file)
@@ -10,7 +10,7 @@
 #define _ASM_SIGCONTEXT_H
 
 #include <asm/sgidefs.h>
-                                                                                
+
 #if _MIPS_SIM == _MIPS_SIM_ABI32
 
 /*
@@ -38,7 +38,7 @@ struct sigcontext {
 };
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
-                                                                                
+
 #if _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32
 
 /*
index a0e26e6c994dbd4ec260cbd7007507beb8b062f4..698becab5a9e2fc1cb4bd58f124ef8006bd9b81f 100644 (file)
@@ -25,10 +25,10 @@ struct siginfo;
 /*
  * Careful to keep union _sifields from shifting ...
  */
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 #define __ARCH_SI_PREAMBLE_SIZE (3 * sizeof(int))
 #endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
 #endif
 
index 6333169be329e65e385e368d8aa34b3749941578..3ccfe09fa744c0bdc702ac0c9a8e7cbc4d0d9856 100644 (file)
@@ -16,7 +16,7 @@
 #define __str2(x) #x
 #define __str(x) __str2(x)
 
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 
 #define save_static_function(symbol)                                   \
 __asm__ (                                                              \
@@ -42,9 +42,9 @@ __asm__ (                                                             \
 
 #define nabi_no_regargs
 
-#endif /* CONFIG_MIPS32 */
+#endif /* CONFIG_32BIT */
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 
 #define save_static_function(symbol)                                   \
 __asm__ (                                                              \
@@ -78,6 +78,6 @@ __asm__ (                                                             \
        unsigned long __dummy6,                                         \
        unsigned long __dummy7,
 
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
 
 #endif /* _ASM_SIM_H */
index 020b4db70ee57f04844e6300a1e3e88c31b0f4cd..753b6620e6fa3df5cd91a7ad6d3a23113ce23d26 100644 (file)
@@ -37,6 +37,8 @@ To add: #define SO_REUSEPORT 0x0200   /* Allow local address and port reuse.  */
 #define SO_ERROR       0x1007  /* get error status and clear */
 #define SO_SNDBUF      0x1001  /* Send buffer size. */
 #define SO_RCVBUF      0x1002  /* Receive buffer. */
+#define SO_SNDBUFFORCE 0x100a
+#define SO_RCVBUFFORCE 0x100b
 #define SO_SNDLOWAT    0x1003  /* send low-water mark */
 #define SO_RCVLOWAT    0x1004  /* receive low-water mark */
 #define SO_SNDTIMEO    0x1005  /* send timeout */
@@ -80,7 +82,7 @@ To add: #define SO_REUSEPORT 0x0200   /* Allow local address and port reuse.  */
  * @SOCK_STREAM - stream (connection) socket
  * @SOCK_RAW - raw socket
  * @SOCK_RDM - reliably-delivered message
- * @SOCK_SEQPACKET - sequential packet socket 
+ * @SOCK_SEQPACKET - sequential packet socket
  * @SOCK_PACKET - linux specific way of getting packets at the dev level.
  *               For writing rarp and other similar things on the user level.
  */
index 86283c25fd5bb34718d43a201b7733289b3cd953..fb42f99f85278adffcf6c41aa5f94f1378e7750b 100644 (file)
@@ -26,7 +26,7 @@
 
                .macro  SAVE_TEMP
                mfhi    v1
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
                LONG_S  $8, PT_R8(sp)
                LONG_S  $9, PT_R9(sp)
 #endif
@@ -56,7 +56,7 @@
 
 #ifdef CONFIG_SMP
                .macro  get_saved_sp    /* SMP variation */
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
                mfc0    k0, CP0_CONTEXT
                lui     k1, %hi(kernelsp)
                srl     k0, k0, 23
@@ -64,7 +64,7 @@
                addu    k1, k0
                LONG_L  k1, %lo(kernelsp)(k1)
 #endif
-#if defined(CONFIG_MIPS64) && !defined(CONFIG_BUILD_ELF64)
+#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
                MFC0    k1, CP0_CONTEXT
                dsra    k1, 23
                lui     k0, %hi(pgd_current)
@@ -74,7 +74,7 @@
                daddu   k1, k0
                LONG_L  k1, %lo(kernelsp)(k1)
 #endif
-#if defined(CONFIG_MIPS64) && defined(CONFIG_BUILD_ELF64)
+#if defined(CONFIG_64BIT) && defined(CONFIG_BUILD_ELF64)
                MFC0    k1, CP0_CONTEXT
                dsrl    k1, 23
                dsll    k1, k1, 3
                .endm
 
                .macro  set_saved_sp stackp temp temp2
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
                mfc0    \temp, CP0_CONTEXT
                srl     \temp, 23
                sll     \temp, 2
                LONG_S  \stackp, kernelsp(\temp)
 #endif
-#if defined(CONFIG_MIPS64) && !defined(CONFIG_BUILD_ELF64)
+#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
                lw      \temp, TI_CPU(gp)
                dsll    \temp, 3
                lui     \temp2, %hi(kernelsp)
                daddu   \temp, \temp2
                LONG_S  \stackp, %lo(kernelsp)(\temp)
 #endif
-#if defined(CONFIG_MIPS64) && defined(CONFIG_BUILD_ELF64)
+#if defined(CONFIG_64BIT) && defined(CONFIG_BUILD_ELF64)
                lw      \temp, TI_CPU(gp)
                dsll    \temp, 3
                LONG_S  \stackp, kernelsp(\temp)
                LONG_S  $6, PT_R6(sp)
                MFC0    v1, CP0_EPC
                LONG_S  $7, PT_R7(sp)
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
                LONG_S  $8, PT_R8(sp)
                LONG_S  $9, PT_R9(sp)
 #endif
 
                .macro  RESTORE_TEMP
                LONG_L  $24, PT_LO(sp)
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
                LONG_L  $8, PT_R8(sp)
                LONG_L  $9, PT_R9(sp)
 #endif
                LONG_L  $31, PT_R31(sp)
                LONG_L  $28, PT_R28(sp)
                LONG_L  $25, PT_R25(sp)
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
                LONG_L  $8, PT_R8(sp)
                LONG_L  $9, PT_R9(sp)
 #endif
                LONG_L  $31, PT_R31(sp)
                LONG_L  $28, PT_R28(sp)
                LONG_L  $25, PT_R25(sp)
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
                LONG_L  $8, PT_R8(sp)
                LONG_L  $9, PT_R9(sp)
 #endif
index 5076fec65780ff39c6f3852f1423c389fedfe5a2..c3ddf973c1c075e805e985f2f9f57ea5329c60e6 100644 (file)
@@ -57,7 +57,7 @@ struct statfs64 {
 };
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
+
 #if _MIPS_SIM == _MIPS_SIM_ABI64
 
 struct statfs64 {                      /* Same as struct statfs */
index b18345504f8a870f24677a2c6f02708d770072b1..5a06f6d1389981d3bb8a9c66bf384d15846e98ec 100644 (file)
@@ -16,7 +16,7 @@
  * Most of the inline functions are rather naive implementations so I just
  * didn't bother updating them for 64-bit ...
  */
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 
 #ifndef IN_STRING_C
 
@@ -130,7 +130,7 @@ strncmp(__const__ char *__cs, __const__ char *__ct, size_t __count)
 
        return __res;
 }
-#endif /* CONFIG_MIPS32 */
+#endif /* CONFIG_32BIT */
 
 #define __HAVE_ARCH_MEMSET
 extern void *memset(void *__s, int __c, size_t __count);
@@ -141,7 +141,7 @@ extern void *memcpy(void *__to, __const__ void *__from, size_t __n);
 #define __HAVE_ARCH_MEMMOVE
 extern void *memmove(void *__dest, __const__ void *__src, size_t __n);
 
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 #define __HAVE_ARCH_MEMSCAN
 static __inline__ void *memscan(void *__addr, int __c, size_t __size)
 {
@@ -161,6 +161,6 @@ static __inline__ void *memscan(void *__addr, int __c, size_t __size)
 
        return __addr;
 }
-#endif /* CONFIG_MIPS32 */
+#endif /* CONFIG_32BIT */
 
 #endif /* _ASM_STRING_H */
index 169f3d4265b14fdeec80c30982572938bab81fc1..6663efd49b27a4d5aaa698c82ce7969bc0287c10 100644 (file)
@@ -208,7 +208,7 @@ static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
        return retval;
 }
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val)
 {
        __u64 retval;
@@ -330,7 +330,7 @@ static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old,
        return retval;
 }
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old,
        unsigned long new)
 {
index 42fcd6f2c206ac42843361a278def47344d3a4ec..a70cb0854c8aff15c59e76d2e20200f92263a67f 100644 (file)
@@ -62,10 +62,10 @@ register struct thread_info *__current_thread_info __asm__("$28");
 #define current_thread_info()  __current_thread_info
 
 /* thread information allocation */
-#if defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_MIPS32)
+#if defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_32BIT)
 #define THREAD_SIZE_ORDER (1)
 #endif
-#if defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_MIPS64)
+#if defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_64BIT)
 #define THREAD_SIZE_ORDER (2)
 #endif
 #ifdef CONFIG_PAGE_SIZE_8KB
index fd9599e40a0ae4e80da1cb023db5b9a46e896503..fee1908c65d286e2a611314f0bfa9545051d81e9 100644 (file)
@@ -228,4 +228,4 @@ extern unsigned long ocd_base;
 #define RM9K_READ_8(ofs, val)   *(val) = *(volatile u8 *)(RM9000x2_BASE_ADDR+ofs)
 #define RM9K_READ_16(ofs, val)  *(val) = *(volatile u16 *)(RM9000x2_BASE_ADDR+ofs)
 
-#endif 
+#endif
index 5d939db6e220f2fc52ce6accb1d3556a4edfc360..3bb7f0087d68111af56b6086e279c3b586df9227 100644 (file)
 
 
 /* TX4927 SDRAM controller (64-bit registers) */
-#define TX4927_SDRAMC_BASE              0x8000 
-#define TX4927_SDRAMC_SDCCR0            0x8000 
+#define TX4927_SDRAMC_BASE              0x8000
+#define TX4927_SDRAMC_SDCCR0            0x8000
 #define TX4927_SDRAMC_SDCCR1            0x8008
 #define TX4927_SDRAMC_SDCCR2            0x8010
 #define TX4927_SDRAMC_SDCCR3            0x8018
 #define TX4927_SDRAMC_SDCTR             0x8040
 #define TX4927_SDRAMC_SDCMD             0x8058
-#define TX4927_SDRAMC_LIMIT             0x8fff 
+#define TX4927_SDRAMC_LIMIT             0x8fff
 
 
 /* TX4927 external bus controller (64-bit registers) */
 
 
 /* TX4927 serial port 0 (32-bit registers) */
-#define TX4927_SIO0_BASE                         0xf300 
-#define TX4927_SIO0_SILCR0                       0xf300 
+#define TX4927_SIO0_BASE                         0xf300
+#define TX4927_SIO0_SILCR0                       0xf300
 #define TX4927_SIO0_SILCR0_RESERVED_16_31                BM_16_31
 #define TX4927_SIO0_SILCR0_RWUB                          BM_15_15
 #define TX4927_SIO0_SILCR0_TWUB                          BM_14_14
 #define TX4927_SIO0_SILCR0_UMODE_DATA_7_BIT            (~BM_00_01)
 #define TX4927_SIO0_SILCR0_UMODE_DATA_8_BIT_MC           BM_01_01
 #define TX4927_SIO0_SILCR0_UMODE_DATA_7_BIT_MC           BM_00_01
-#define TX4927_SIO0_SIDICR0                      0xf304 
+#define TX4927_SIO0_SIDICR0                      0xf304
 #define TX4927_SIO0_SIDICR0_RESERVED_16_31               BM_16_31
 #define TX4927_SIO0_SIDICR0_TDE                          BM_15_15
 #define TX4927_SIO0_SIDICR0_RDE                          BM_14_14
 #define TX4927_SIO0_SIDICR0_STIE_TRDY                    BM_02_02
 #define TX4927_SIO0_SIDICR0_STIE_TXALS                   BM_01_01
 #define TX4927_SIO0_SIDICR0_STIE_UBRKD                   BM_00_00
-#define TX4927_SIO0_SIDISR0                      0xf308 
+#define TX4927_SIO0_SIDISR0                      0xf308
 #define TX4927_SIO0_SIDISR0_RESERVED_16_31               BM_16_31
 #define TX4927_SIO0_SIDISR0_UBRK                         BM_15_15
 #define TX4927_SIO0_SIDISR0_UVALID                       BM_14_14
 #define TX4927_SIO0_SIDISR0_STIS                         BM_06_06
 #define TX4927_SIO0_SIDISR0_RESERVED_05_05               BM_05_05
 #define TX4927_SIO0_SIDISR0_RFDN                         BM_00_04
-#define TX4927_SIO0_SISCISR0                     0xf30c 
+#define TX4927_SIO0_SISCISR0                     0xf30c
 #define TX4927_SIO0_SISCISR0_RESERVED_06_31              BM_06_31
 #define TX4927_SIO0_SISCISR0_OERS                        BM_05_05
 #define TX4927_SIO0_SISCISR0_CTSS                        BM_04_04
 #define TX4927_SIO0_SISCISR0_TRDY                        BM_02_02
 #define TX4927_SIO0_SISCISR0_TXALS                       BM_01_01
 #define TX4927_SIO0_SISCISR0_UBRKD                       BM_00_00
-#define TX4927_SIO0_SIFCR0                       0xf310 
+#define TX4927_SIO0_SIFCR0                       0xf310
 #define TX4927_SIO0_SIFCR0_RESERVED_16_31                BM_16_31
 #define TX4927_SIO0_SIFCR0_SWRST                         BM_16_31
 #define TX4927_SIO0_SIFCR0_RESERVED_09_14                BM_09_14
 #define TX4927_SIO0_SIFCR0_TFRST                         BM_02_02
 #define TX4927_SIO0_SIFCR0_RFRST                         BM_01_01
 #define TX4927_SIO0_SIFCR0_FRSTE                         BM_00_00
-#define TX4927_SIO0_SIFLCR0                      0xf314 
+#define TX4927_SIO0_SIFLCR0                      0xf314
 #define TX4927_SIO0_SIFLCR0_RESERVED_13_31               BM_13_31
 #define TX4927_SIO0_SIFLCR0_RCS                          BM_12_12
 #define TX4927_SIO0_SIFLCR0_TES                          BM_11_11
 #define TX4927_SIO0_SIFLCR0_RESERVED_05_06               BM_05_06
 #define TX4927_SIO0_SIFLCR0_RTSTL                        BM_01_04
 #define TX4927_SIO0_SIFLCR0_TBRK                         BM_00_00
-#define TX4927_SIO0_SIBGR0                       0xf318 
+#define TX4927_SIO0_SIBGR0                       0xf318
 #define TX4927_SIO0_SIBGR0_RESERVED_10_31                BM_10_31
 #define TX4927_SIO0_SIBGR0_BCLK                          BM_08_09
 #define TX4927_SIO0_SIBGR0_BCLK_T0                     (~BM_08_09)
 #define TX4927_SIO0_SIBGR0_BCLK_T4                       BM_09_09
 #define TX4927_SIO0_SIBGR0_BCLK_T6                       BM_08_09
 #define TX4927_SIO0_SIBGR0_BRD                           BM_00_07
-#define TX4927_SIO0_SITFIF00                     0xf31c 
+#define TX4927_SIO0_SITFIF00                     0xf31c
 #define TX4927_SIO0_SITFIF00_RESERVED_08_31              BM_08_31
 #define TX4927_SIO0_SITFIF00_TXD                         BM_00_07
-#define TX4927_SIO0_SIRFIFO0                     0xf320          
+#define TX4927_SIO0_SIRFIFO0                     0xf320
 #define TX4927_SIO0_SIRFIFO0_RESERVED_08_31              BM_08_31
 #define TX4927_SIO0_SIRFIFO0_RXD                         BM_00_07
-#define TX4927_SIO0_SIRFIFO0                     0xf320          
-#define TX4927_SIO0_LIMIT                        0xf3ff 
+#define TX4927_SIO0_SIRFIFO0                     0xf320
+#define TX4927_SIO0_LIMIT                        0xf3ff
 
 
 /* TX4927 serial port 1 (32-bit registers) */
-#define TX4927_SIO1_BASE                0xf400 
-#define TX4927_SIO1_SILCR1              0xf400 
-#define TX4927_SIO1_SIDICR1             0xf404 
-#define TX4927_SIO1_SIDISR1             0xf408 
-#define TX4927_SIO1_SISCISR1            0xf40c 
-#define TX4927_SIO1_SIFCR1              0xf410 
-#define TX4927_SIO1_SIFLCR1             0xf414 
-#define TX4927_SIO1_SIBGR1              0xf418 
-#define TX4927_SIO1_SITFIF01            0xf41c 
-#define TX4927_SIO1_SIRFIFO1            0xf420 
-#define TX4927_SIO1_LIMIT               0xf4ff 
+#define TX4927_SIO1_BASE                0xf400
+#define TX4927_SIO1_SILCR1              0xf400
+#define TX4927_SIO1_SIDICR1             0xf404
+#define TX4927_SIO1_SIDISR1             0xf408
+#define TX4927_SIO1_SISCISR1            0xf40c
+#define TX4927_SIO1_SIFCR1              0xf410
+#define TX4927_SIO1_SIFLCR1             0xf414
+#define TX4927_SIO1_SIBGR1              0xf418
+#define TX4927_SIO1_SITFIF01            0xf41c
+#define TX4927_SIO1_SIRFIFO1            0xf420
+#define TX4927_SIO1_LIMIT               0xf4ff
 
 
 /* TX4927 parallel port (32-bit registers) */
index 170433492246357fdec8839a3676c8c8867b3b7a..165f6b8b217fe6254e40c76515fb6469af5f3aca 100644 (file)
@@ -5,8 +5,8 @@
  *
  * Copyright (C) 2000-2001 Toshiba Corporation
  */
-#ifndef __ASM_TX4927_TX4927_PCI_H 
-#define __ASM_TX4927_TX4927_PCI_H 
+#ifndef __ASM_TX4927_TX4927_PCI_H
+#define __ASM_TX4927_TX4927_PCI_H
 
 #define TX4927_CCFG_TOE 0x00004000
 
index d2f0c76b00a9f85a817e3e1436243e8eb93d9bfe..421b3aea14cc9425ac30064fa427c068f89f158f 100644 (file)
@@ -78,7 +78,7 @@ typedef unsigned long long u64;
 #endif
 
 #if (defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) \
-    || defined(CONFIG_MIPS64)
+    || defined(CONFIG_64BIT)
 typedef u64 dma_addr_t;
 #else
 typedef u32 dma_addr_t;
@@ -99,8 +99,6 @@ typedef u64 sector_t;
 #define HAVE_SECTOR_T
 #endif
 
-typedef unsigned short kmem_bufctl_t;
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index 07114898e0652fd9a5a7d5df836934f9ef41c5c9..5c2c9832901204ade583cf5314f629a1b5624178 100644 (file)
@@ -22,7 +22,7 @@
  *
  * For historical reasons, these macros are grossly misnamed.
  */
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
 
 #define __UA_LIMIT     0x80000000UL
 
@@ -32,9 +32,9 @@
 #define __UA_t0                "$8"
 #define __UA_t1                "$9"
 
-#endif /* CONFIG_MIPS32 */
+#endif /* CONFIG_32BIT */
 
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
 
 #define __UA_LIMIT     (- TASK_SIZE)
 
@@ -44,7 +44,7 @@
 #define __UA_t0                "$12"
 #define __UA_t1                "$13"
 
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
 
 /*
  * USER_DS is a bitmask that has the bits set that may not be set in a valid
 #define access_ok(type, addr, size)                                    \
        likely(__access_ok((unsigned long)(addr), (size),__access_mask))
 
-/*
- * verify_area: - Obsolete/deprecated and will go away soon,
- * use access_ok() instead.
- * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE
- * @addr: User space pointer to start of block to check
- * @size: Size of block to check
- *
- * Context: User context only.  This function may sleep.
- *
- * This function has been replaced by access_ok().
- *
- * Checks if a pointer to a block of memory in user space is valid.
- *
- * Returns zero if the memory block may be valid, -EFAULT
- * if it is definitely invalid.
- *
- * See access_ok() for more details.
- */
-static inline int __deprecated verify_area(int type, const void * addr, unsigned long size)
-{
-       return access_ok(type, addr, size) ? 0 : -EFAULT;
-}
-
 /*
  * put_user: - Write a simple value into user space.
  * @x:   Value to copy to user space.
index 6d21cc964f76c8667bffd788b31dc220f3f4cd40..ad4d48056307ea704f13b2ec0f44053816c7cdb0 100644 (file)
@@ -1124,7 +1124,7 @@ type name (atype a,btype b,ctype c,dtype d,etype e,ftype f) \
 # ifndef __mips64
 #  define __ARCH_WANT_STAT64
 # endif
-# ifdef CONFIG_MIPS32
+# ifdef CONFIG_32BIT
 #  define __ARCH_WANT_SYS_TIME
 # endif
 # ifdef CONFIG_MIPS32_O32
diff --git a/include/asm-mips/vr4181/irq.h b/include/asm-mips/vr4181/irq.h
deleted file mode 100644 (file)
index 4bf0ea9..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Macros for vr4181 IRQ numbers.
- *
- * Copyright (C) 2001 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- */
-
-/*
- * Strategy:
- *
- * Vr4181 has conceptually three levels of interrupt controllers:
- *  1. the CPU itself with 8 intr level.
- *  2. system interrupt controller, cascaded from int0 pin in CPU, 32 intrs
- *  3. GPIO interrupts : forwarding external interrupts to sys intr controller
- */
-
-/* decide the irq block assignment */
-#define        VR4181_NUM_CPU_IRQ      8
-#define        VR4181_NUM_SYS_IRQ      32
-#define        VR4181_NUM_GPIO_IRQ     16
-
-#define        VR4181_IRQ_BASE         0
-
-#define        VR4181_CPU_IRQ_BASE     VR4181_IRQ_BASE
-#define        VR4181_SYS_IRQ_BASE     (VR4181_CPU_IRQ_BASE + VR4181_NUM_CPU_IRQ)
-#define        VR4181_GPIO_IRQ_BASE    (VR4181_SYS_IRQ_BASE + VR4181_NUM_SYS_IRQ)
-
-/* CPU interrupts */
-
-/*
-   IP0 - Software interrupt
-   IP1 - Software interrupt
-   IP2 - All but battery, high speed modem, and real time clock
-   IP3 - RTC Long1 (system timer)
-   IP4 - RTC Long2
-   IP5 - High Speed Modem (unused on VR4181)
-   IP6 - Unused
-   IP7 - Timer interrupt from CPO_COMPARE
-*/
-
-#define VR4181_IRQ_SW1       (VR4181_CPU_IRQ_BASE + 0)
-#define VR4181_IRQ_SW2       (VR4181_CPU_IRQ_BASE + 1)
-#define VR4181_IRQ_INT0      (VR4181_CPU_IRQ_BASE + 2)
-#define VR4181_IRQ_INT1      (VR4181_CPU_IRQ_BASE + 3)
-#define VR4181_IRQ_INT2      (VR4181_CPU_IRQ_BASE + 4)
-#define VR4181_IRQ_INT3      (VR4181_CPU_IRQ_BASE + 5)
-#define VR4181_IRQ_INT4      (VR4181_CPU_IRQ_BASE + 6)
-#define VR4181_IRQ_TIMER     (VR4181_CPU_IRQ_BASE + 7)
-
-
-/* Cascaded from VR4181_IRQ_INT0 (ICU mapped interrupts) */
-
-/*
-   IP2 - same as VR4181_IRQ_INT1
-   IP8 - This is a cascade to GPIO IRQ's. Do not use.
-   IP16 - same as VR4181_IRQ_INT2
-   IP18 - CompactFlash
-*/
-
-#define VR4181_IRQ_BATTERY   (VR4181_SYS_IRQ_BASE + 0)
-#define VR4181_IRQ_POWER     (VR4181_SYS_IRQ_BASE + 1)
-#define VR4181_IRQ_RTCL1     (VR4181_SYS_IRQ_BASE + 2)
-#define VR4181_IRQ_ETIMER    (VR4181_SYS_IRQ_BASE + 3)
-#define VR4181_IRQ_RFU12     (VR4181_SYS_IRQ_BASE + 4)
-#define VR4181_IRQ_PIU       (VR4181_SYS_IRQ_BASE + 5)
-#define VR4181_IRQ_AIU       (VR4181_SYS_IRQ_BASE + 6)
-#define VR4181_IRQ_KIU       (VR4181_SYS_IRQ_BASE + 7)
-#define VR4181_IRQ_GIU       (VR4181_SYS_IRQ_BASE + 8)
-#define VR4181_IRQ_SIU       (VR4181_SYS_IRQ_BASE + 9)
-#define VR4181_IRQ_RFU18     (VR4181_SYS_IRQ_BASE + 10)
-#define VR4181_IRQ_SOFT      (VR4181_SYS_IRQ_BASE + 11)
-#define VR4181_IRQ_RFU20     (VR4181_SYS_IRQ_BASE + 12)
-#define VR4181_IRQ_DOZEPIU   (VR4181_SYS_IRQ_BASE + 13)
-#define VR4181_IRQ_RFU22     (VR4181_SYS_IRQ_BASE + 14)
-#define VR4181_IRQ_RFU23     (VR4181_SYS_IRQ_BASE + 15)
-#define VR4181_IRQ_RTCL2     (VR4181_SYS_IRQ_BASE + 16)
-#define VR4181_IRQ_LED       (VR4181_SYS_IRQ_BASE + 17)
-#define VR4181_IRQ_ECU       (VR4181_SYS_IRQ_BASE + 18)
-#define VR4181_IRQ_CSU       (VR4181_SYS_IRQ_BASE + 19)
-#define VR4181_IRQ_USB       (VR4181_SYS_IRQ_BASE + 20)
-#define VR4181_IRQ_DMA       (VR4181_SYS_IRQ_BASE + 21)
-#define VR4181_IRQ_LCD       (VR4181_SYS_IRQ_BASE + 22)
-#define VR4181_IRQ_RFU31     (VR4181_SYS_IRQ_BASE + 23)
-#define VR4181_IRQ_RFU32     (VR4181_SYS_IRQ_BASE + 24)
-#define VR4181_IRQ_RFU33     (VR4181_SYS_IRQ_BASE + 25)
-#define VR4181_IRQ_RFU34     (VR4181_SYS_IRQ_BASE + 26)
-#define VR4181_IRQ_RFU35     (VR4181_SYS_IRQ_BASE + 27)
-#define VR4181_IRQ_RFU36     (VR4181_SYS_IRQ_BASE + 28)
-#define VR4181_IRQ_RFU37     (VR4181_SYS_IRQ_BASE + 29)
-#define VR4181_IRQ_RFU38     (VR4181_SYS_IRQ_BASE + 30)
-#define VR4181_IRQ_RFU39     (VR4181_SYS_IRQ_BASE + 31)
-
-/* Cascaded from VR4181_IRQ_GIU */
-#define VR4181_IRQ_GPIO0     (VR4181_GPIO_IRQ_BASE + 0)
-#define VR4181_IRQ_GPIO1     (VR4181_GPIO_IRQ_BASE + 1)
-#define VR4181_IRQ_GPIO2     (VR4181_GPIO_IRQ_BASE + 2)
-#define VR4181_IRQ_GPIO3     (VR4181_GPIO_IRQ_BASE + 3)
-#define VR4181_IRQ_GPIO4     (VR4181_GPIO_IRQ_BASE + 4)
-#define VR4181_IRQ_GPIO5     (VR4181_GPIO_IRQ_BASE + 5)
-#define VR4181_IRQ_GPIO6     (VR4181_GPIO_IRQ_BASE + 6)
-#define VR4181_IRQ_GPIO7     (VR4181_GPIO_IRQ_BASE + 7)
-#define VR4181_IRQ_GPIO8     (VR4181_GPIO_IRQ_BASE + 8)
-#define VR4181_IRQ_GPIO9     (VR4181_GPIO_IRQ_BASE + 9)
-#define VR4181_IRQ_GPIO10    (VR4181_GPIO_IRQ_BASE + 10)
-#define VR4181_IRQ_GPIO11    (VR4181_GPIO_IRQ_BASE + 11)
-#define VR4181_IRQ_GPIO12    (VR4181_GPIO_IRQ_BASE + 12)
-#define VR4181_IRQ_GPIO13    (VR4181_GPIO_IRQ_BASE + 13)
-#define VR4181_IRQ_GPIO14    (VR4181_GPIO_IRQ_BASE + 14)
-#define VR4181_IRQ_GPIO15    (VR4181_GPIO_IRQ_BASE + 15)
-
-
-// Alternative to above GPIO IRQ defines
-#define VR4181_IRQ_GPIO(pin) ((VR4181_IRQ_GPIO0) + (pin))
-
-#define VR4181_IRQ_MAX       (VR4181_IRQ_BASE + VR4181_NUM_CPU_IRQ + \
-                              VR4181_NUM_SYS_IRQ + VR4181_NUM_GPIO_IRQ)
diff --git a/include/asm-mips/vr4181/vr4181.h b/include/asm-mips/vr4181/vr4181.h
deleted file mode 100644 (file)
index 5c5d607..0000000
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1999 by Michael Klar
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- *
- */
-#ifndef __ASM_VR4181_VR4181_H
-#define __ASM_VR4181_VR4181_H
-
-#include <asm/addrspace.h>
-
-#include <asm/vr4181/irq.h>
-
-#ifndef __ASSEMBLY__
-#define __preg8                (volatile unsigned char*)
-#define __preg16       (volatile unsigned short*)
-#define __preg32       (volatile unsigned int*)
-#else
-#define __preg8
-#define __preg16
-#define __preg32
-#endif
-
-// Embedded CPU peripheral registers
-// Note that many of the registers have different physical address for VR4181
-
-// Bus Control Unit (BCU)
-#define VR4181_BCUCNTREG1      __preg16(KSEG1 + 0x0A000000)    /* BCU control register 1 (R/W) */
-#define VR4181_CMUCLKMSK       __preg16(KSEG1 + 0x0A000004)    /* Clock mask register (R/W) */
-#define VR4181_CMUCLKMSK_MSKCSUPCLK  0x0040
-#define VR4181_CMUCLKMSK_MSKAIUPCLK  0x0020
-#define VR4181_CMUCLKMSK_MSKPIUPCLK  0x0010
-#define VR4181_CMUCLKMSK_MSKADUPCLK  0x0008
-#define VR4181_CMUCLKMSK_MSKSIU18M   0x0004
-#define VR4181_CMUCLKMSK_MSKADU18M   0x0002
-#define VR4181_CMUCLKMSK_MSKUSB      0x0001
-#define VR4181_CMUCLKMSK_MSKSIU      VR4181_CMUCLKMSK_MSKSIU18M
-#define VR4181_BCUSPEEDREG     __preg16(KSEG1 + 0x0A00000C)    /* BCU access time parameter (R/W) */
-#define VR4181_BCURFCNTREG     __preg16(KSEG1 + 0x0A000010)    /* BCU refresh control register (R/W) */
-#define VR4181_REVIDREG                __preg16(KSEG1 + 0x0A000014)    /* Revision ID register (R) */
-#define VR4181_CLKSPEEDREG     __preg16(KSEG1 + 0x0A000018)    /* Clock speed register (R) */
-#define VR4181_EDOMCYTREG      __preg16(KSEG1 + 0x0A000300)    /* Memory cycle timing register (R/W) */
-#define VR4181_MEMCFG_REG      __preg16(KSEG1 + 0x0A000304)    /* Memory configuration register (R/W) */
-#define VR4181_MODE_REG                __preg16(KSEG1 + 0x0A000308)    /* SDRAM mode register (R/W) */
-#define VR4181_SDTIMINGREG     __preg16(KSEG1 + 0x0A00030C)    /* SDRAM timing register (R/W) */
-
-// DMA Control Unit (DCU)
-#define VR4181_MICDEST1REG1    __preg16(KSEG1 + 0x0A000020)    /* Microphone destination 1 address register 1 (R/W) */
-#define VR4181_MICDEST1REG2    __preg16(KSEG1 + 0x0A000022)    /* Microphone destination 1 address register 2 (R/W) */
-#define VR4181_MICDEST2REG1    __preg16(KSEG1 + 0x0A000024)    /* Microphone destination 2 address register 1 (R/W) */
-#define VR4181_MICDEST2REG2    __preg16(KSEG1 + 0x0A000026)    /* Microphone destination 2 address register 2 (R/W) */
-#define VR4181_SPKRRC1REG1     __preg16(KSEG1 + 0x0A000028)    /* Speaker Source 1 address register 1 (R/W) */
-#define VR4181_SPKRRC1REG2     __preg16(KSEG1 + 0x0A00002A)    /* Speaker Source 1 address register 2 (R/W) */
-#define VR4181_SPKRRC2REG1     __preg16(KSEG1 + 0x0A00002C)    /* Speaker Source 2 address register 1 (R/W) */
-#define VR4181_SPKRRC2REG2     __preg16(KSEG1 + 0x0A00002E)    /* Speaker Source 2 address register 2 (R/W) */
-#define VR4181_DMARSTREG       __preg16(KSEG1 + 0x0A000040)    /* DMA Reset register (R/W) */
-#define VR4181_AIUDMAMSKREG    __preg16(KSEG1 + 0x0A000046)    /* Audio DMA mask register (R/W) */
-#define VR4181_USBDMAMSKREG    __preg16(KSEG1 + 0x0A000600)    /* USB DMA Mask register (R/W) */
-#define VR4181_USBRXS1AREG1    __preg16(KSEG1 + 0x0A000602)    /* USB Rx source 1 address register 1 (R/W) */
-#define VR4181_USBRXS1AREG2    __preg16(KSEG1 + 0x0A000604)    /* USB Rx source 1 address register 2 (R/W) */
-#define VR4181_USBRXS2AREG1    __preg16(KSEG1 + 0x0A000606)    /* USB Rx source 2 address register 1 (R/W) */
-#define VR4181_USBRXS2AREG2    __preg16(KSEG1 + 0x0A000608)    /* USB Rx source 2 address register 2 (R/W) */
-#define VR4181_USBTXS1AREG1    __preg16(KSEG1 + 0x0A00060A)    /* USB Tx source 1 address register 1 (R/W) */
-#define VR4181_USBTXS1AREG2    __preg16(KSEG1 + 0x0A00060C)    /* USB Tx source 1 address register 2 (R/W) */
-#define VR4181_USBTXS2AREG1    __preg16(KSEG1 + 0x0A00060E)    /* USB Tx source 2 address register 1 (R/W) */
-#define VR4181_USBTXS2AREG2    __preg16(KSEG1 + 0x0A000610)    /* USB Tx source 2 address register 2 (R/W) */
-#define VR4181_USBRXD1AREG1    __preg16(KSEG1 + 0x0A00062A)    /* USB Rx destination 1 address register 1 (R/W) */
-#define VR4181_USBRXD1AREG2    __preg16(KSEG1 + 0x0A00062C)    /* USB Rx destination 1 address register 2 (R/W) */
-#define VR4181_USBRXD2AREG1    __preg16(KSEG1 + 0x0A00062E)    /* USB Rx destination 2 address register 1 (R/W) */
-#define VR4181_USBRXD2AREG2    __preg16(KSEG1 + 0x0A000630)    /* USB Rx destination 2 address register 2 (R/W) */
-#define VR4181_USBTXD1AREG1    __preg16(KSEG1 + 0x0A000632)    /* USB Tx destination 1 address register 1 (R/W) */
-#define VR4181_USBTXD1AREG2    __preg16(KSEG1 + 0x0A000634)    /* USB Tx destination 1 address register 2 (R/W) */
-#define VR4181_USBTXD2AREG1    __preg16(KSEG1 + 0x0A000636)    /* USB Tx destination 2 address register 1 (R/W) */
-#define VR4181_USBTXD2AREG2    __preg16(KSEG1 + 0x0A000638)    /* USB Tx destination 2 address register 2 (R/W) */
-#define VR4181_RxRCLENREG      __preg16(KSEG1 + 0x0A000652)    /* USB Rx record length register (R/W) */
-#define VR4181_TxRCLENREG      __preg16(KSEG1 + 0x0A000654)    /* USB Tx record length register (R/W) */
-#define VR4181_MICRCLENREG     __preg16(KSEG1 + 0x0A000658)    /* Microphone record length register (R/W) */
-#define VR4181_SPKRCLENREG     __preg16(KSEG1 + 0x0A00065A)    /* Speaker record length register (R/W) */
-#define VR4181_USBCFGREG       __preg16(KSEG1 + 0x0A00065C)    /* USB configuration register (R/W) */
-#define VR4181_MICDMACFGREG    __preg16(KSEG1 + 0x0A00065E)    /* Microphone DMA configuration register (R/W) */
-#define VR4181_SPKDMACFGREG    __preg16(KSEG1 + 0x0A000660)    /* Speaker DMA configuration register (R/W) */
-#define VR4181_DMAITRQREG      __preg16(KSEG1 + 0x0A000662)    /* DMA interrupt request register (R/W) */
-#define VR4181_DMACLTREG       __preg16(KSEG1 + 0x0A000664)    /* DMA control register (R/W) */
-#define VR4181_DMAITMKREG      __preg16(KSEG1 + 0x0A000666)    /* DMA interrupt mask register (R/W) */
-
-// ISA Bridge
-#define VR4181_ISABRGCTL       __preg16(KSEG1 + 0x0B0002C0)    /* ISA Bridge Control Register (R/W) */
-#define VR4181_ISABRGSTS       __preg16(KSEG1 + 0x0B0002C2)    /* ISA Bridge Status Register (R/W) */
-#define VR4181_XISACTL         __preg16(KSEG1 + 0x0B0002C4)    /* External ISA Control Register (R/W) */
-
-// Clocked Serial Interface (CSI)
-#define VR4181_CSIMODE         __preg16(KSEG1 + 0x0B000900)    /* CSI Mode Register (R/W) */
-#define VR4181_CSIRXDATA       __preg16(KSEG1 + 0x0B000902)    /* CSI Receive Data Register (R) */
-#define VR4181_CSITXDATA       __preg16(KSEG1 + 0x0B000904)    /* CSI Transmit Data Register (R/W) */
-#define VR4181_CSILSTAT                __preg16(KSEG1 + 0x0B000906)    /* CSI Line Status Register (R/W) */
-#define VR4181_CSIINTMSK       __preg16(KSEG1 + 0x0B000908)    /* CSI Interrupt Mask Register (R/W) */
-#define VR4181_CSIINTSTAT      __preg16(KSEG1 + 0x0B00090a)    /* CSI Interrupt Status Register (R/W) */
-#define VR4181_CSITXBLEN       __preg16(KSEG1 + 0x0B00090c)    /* CSI Transmit Burst Length Register (R/W) */
-#define VR4181_CSIRXBLEN       __preg16(KSEG1 + 0x0B00090e)    /* CSI Receive Burst Length Register (R/W) */
-
-// Interrupt Control Unit (ICU)
-#define VR4181_SYSINT1REG      __preg16(KSEG1 + 0x0A000080)    /* Level 1 System interrupt register 1 (R) */
-#define VR4181_MSYSINT1REG     __preg16(KSEG1 + 0x0A00008C)    /* Level 1 mask system interrupt register 1 (R/W) */
-#define VR4181_NMIREG          __preg16(KSEG1 + 0x0A000098)    /* NMI register (R/W) */
-#define VR4181_SOFTINTREG      __preg16(KSEG1 + 0x0A00009A)    /* Software interrupt register (R/W) */
-#define VR4181_SYSINT2REG      __preg16(KSEG1 + 0x0A000200)    /* Level 1 System interrupt register 2 (R) */
-#define VR4181_MSYSINT2REG     __preg16(KSEG1 + 0x0A000206)    /* Level 1 mask system interrupt register 2 (R/W) */
-#define VR4181_PIUINTREGro     __preg16(KSEG1 + 0x0B000082)    /* Level 2 PIU interrupt register (R) */
-#define VR4181_AIUINTREG       __preg16(KSEG1 + 0x0B000084)    /* Level 2 AIU interrupt register (R) */
-#define VR4181_MPIUINTREG      __preg16(KSEG1 + 0x0B00008E)    /* Level 2 mask PIU interrupt register (R/W) */
-#define VR4181_MAIUINTREG      __preg16(KSEG1 + 0x0B000090)    /* Level 2 mask AIU interrupt register (R/W) */
-#define VR4181_MKIUINTREG      __preg16(KSEG1 + 0x0B000092)    /* Level 2 mask KIU interrupt register (R/W) */
-#define VR4181_KIUINTREG       __preg16(KSEG1 + 0x0B000198)    /* Level 2 KIU interrupt register (R) */
-
-// Power Management Unit (PMU)
-#define VR4181_PMUINTREG       __preg16(KSEG1 + 0x0B0000A0)    /* PMU Status Register (R/W) */
-#define VR4181_PMUINT_POWERSW  0x1     /* Power switch */
-#define VR4181_PMUINT_BATT     0x2     /* Low batt during normal operation */
-#define VR4181_PMUINT_DEADMAN  0x4     /* Deadman's switch */
-#define VR4181_PMUINT_RESET    0x8     /* Reset switch */
-#define VR4181_PMUINT_RTCRESET 0x10    /* RTC Reset */
-#define VR4181_PMUINT_TIMEOUT  0x20    /* HAL Timer Reset */
-#define VR4181_PMUINT_BATTLOW  0x100   /* Battery low */
-#define VR4181_PMUINT_RTC      0x200   /* RTC Alarm */
-#define VR4181_PMUINT_DCD      0x400   /* DCD# */
-#define VR4181_PMUINT_GPIO0    0x1000  /* GPIO0 */
-#define VR4181_PMUINT_GPIO1    0x2000  /* GPIO1 */
-#define VR4181_PMUINT_GPIO2    0x4000  /* GPIO2 */
-#define VR4181_PMUINT_GPIO3    0x8000  /* GPIO3 */
-
-#define VR4181_PMUCNTREG       __preg16(KSEG1 + 0x0B0000A2)    /* PMU Control Register (R/W) */
-#define VR4181_PMUWAITREG      __preg16(KSEG1 + 0x0B0000A8)    /* PMU Wait Counter Register (R/W) */
-#define VR4181_PMUDIVREG       __preg16(KSEG1 + 0x0B0000AC)    /* PMU Divide Mode Register (R/W) */
-#define VR4181_DRAMHIBCTL      __preg16(KSEG1 + 0x0B0000B2)    /* DRAM Hibernate Control Register (R/W) */
-
-// Real Time Clock Unit (RTC)
-#define VR4181_ETIMELREG       __preg16(KSEG1 + 0x0B0000C0)    /* Elapsed Time L Register (R/W) */
-#define VR4181_ETIMEMREG       __preg16(KSEG1 + 0x0B0000C2)    /* Elapsed Time M Register (R/W) */
-#define VR4181_ETIMEHREG       __preg16(KSEG1 + 0x0B0000C4)    /* Elapsed Time H Register (R/W) */
-#define VR4181_ECMPLREG                __preg16(KSEG1 + 0x0B0000C8)    /* Elapsed Compare L Register (R/W) */
-#define VR4181_ECMPMREG                __preg16(KSEG1 + 0x0B0000CA)    /* Elapsed Compare M Register (R/W) */
-#define VR4181_ECMPHREG                __preg16(KSEG1 + 0x0B0000CC)    /* Elapsed Compare H Register (R/W) */
-#define VR4181_RTCL1LREG       __preg16(KSEG1 + 0x0B0000D0)    /* RTC Long 1 L Register (R/W) */
-#define VR4181_RTCL1HREG       __preg16(KSEG1 + 0x0B0000D2)    /* RTC Long 1 H Register (R/W) */
-#define VR4181_RTCL1CNTLREG    __preg16(KSEG1 + 0x0B0000D4)    /* RTC Long 1 Count L Register (R) */
-#define VR4181_RTCL1CNTHREG    __preg16(KSEG1 + 0x0B0000D6)    /* RTC Long 1 Count H Register (R) */
-#define VR4181_RTCL2LREG       __preg16(KSEG1 + 0x0B0000D8)    /* RTC Long 2 L Register (R/W) */
-#define VR4181_RTCL2HREG       __preg16(KSEG1 + 0x0B0000DA)    /* RTC Long 2 H Register (R/W) */
-#define VR4181_RTCL2CNTLREG    __preg16(KSEG1 + 0x0B0000DC)    /* RTC Long 2 Count L Register (R) */
-#define VR4181_RTCL2CNTHREG    __preg16(KSEG1 + 0x0B0000DE)    /* RTC Long 2 Count H Register (R) */
-#define VR4181_RTCINTREG       __preg16(KSEG1 + 0x0B0001DE)    /* RTC Interrupt Register (R/W) */
-
-// Deadman's Switch Unit (DSU)
-#define VR4181_DSUCNTREG       __preg16(KSEG1 + 0x0B0000E0)    /* DSU Control Register (R/W) */
-#define VR4181_DSUSETREG       __preg16(KSEG1 + 0x0B0000E2)    /* DSU Dead Time Set Register (R/W) */
-#define VR4181_DSUCLRREG       __preg16(KSEG1 + 0x0B0000E4)    /* DSU Clear Register (W) */
-#define VR4181_DSUTIMREG       __preg16(KSEG1 + 0x0B0000E6)    /* DSU Elapsed Time Register (R/W) */
-
-// General Purpose I/O Unit (GIU)
-#define VR4181_GPMD0REG                __preg16(KSEG1 + 0x0B000300)    /* GPIO Mode 0 Register (R/W) */
-#define VR4181_GPMD1REG                __preg16(KSEG1 + 0x0B000302)    /* GPIO Mode 1 Register (R/W) */
-#define VR4181_GPMD2REG                __preg16(KSEG1 + 0x0B000304)    /* GPIO Mode 2 Register (R/W) */
-#define VR4181_GPMD3REG                __preg16(KSEG1 + 0x0B000306)    /* GPIO Mode 3 Register (R/W) */
-#define VR4181_GPDATHREG       __preg16(KSEG1 + 0x0B000308)    /* GPIO Data High Register (R/W) */
-#define VR4181_GPDATHREG_GPIO16  0x0001
-#define VR4181_GPDATHREG_GPIO17  0x0002
-#define VR4181_GPDATHREG_GPIO18  0x0004
-#define VR4181_GPDATHREG_GPIO19  0x0008
-#define VR4181_GPDATHREG_GPIO20  0x0010
-#define VR4181_GPDATHREG_GPIO21  0x0020
-#define VR4181_GPDATHREG_GPIO22  0x0040
-#define VR4181_GPDATHREG_GPIO23  0x0080
-#define VR4181_GPDATHREG_GPIO24  0x0100
-#define VR4181_GPDATHREG_GPIO25  0x0200
-#define VR4181_GPDATHREG_GPIO26  0x0400
-#define VR4181_GPDATHREG_GPIO27  0x0800
-#define VR4181_GPDATHREG_GPIO28  0x1000
-#define VR4181_GPDATHREG_GPIO29  0x2000
-#define VR4181_GPDATHREG_GPIO30  0x4000
-#define VR4181_GPDATHREG_GPIO31  0x8000
-#define VR4181_GPDATLREG       __preg16(KSEG1 + 0x0B00030A)    /* GPIO Data Low Register (R/W) */
-#define VR4181_GPDATLREG_GPIO0   0x0001
-#define VR4181_GPDATLREG_GPIO1   0x0002
-#define VR4181_GPDATLREG_GPIO2   0x0004
-#define VR4181_GPDATLREG_GPIO3   0x0008
-#define VR4181_GPDATLREG_GPIO4   0x0010
-#define VR4181_GPDATLREG_GPIO5   0x0020
-#define VR4181_GPDATLREG_GPIO6   0x0040
-#define VR4181_GPDATLREG_GPIO7   0x0080
-#define VR4181_GPDATLREG_GPIO8   0x0100
-#define VR4181_GPDATLREG_GPIO9   0x0200
-#define VR4181_GPDATLREG_GPIO10  0x0400
-#define VR4181_GPDATLREG_GPIO11  0x0800
-#define VR4181_GPDATLREG_GPIO12  0x1000
-#define VR4181_GPDATLREG_GPIO13  0x2000
-#define VR4181_GPDATLREG_GPIO14  0x4000
-#define VR4181_GPDATLREG_GPIO15  0x8000
-#define VR4181_GPINTEN         __preg16(KSEG1 + 0x0B00030C)    /* GPIO Interrupt Enable Register (R/W) */
-#define VR4181_GPINTMSK                __preg16(KSEG1 + 0x0B00030E)    /* GPIO Interrupt Mask Register (R/W) */
-#define VR4181_GPINTTYPH       __preg16(KSEG1 + 0x0B000310)    /* GPIO Interrupt Type High Register (R/W) */
-#define VR4181_GPINTTYPL       __preg16(KSEG1 + 0x0B000312)    /* GPIO Interrupt Type Low Register (R/W) */
-#define VR4181_GPINTSTAT       __preg16(KSEG1 + 0x0B000314)    /* GPIO Interrupt Status Register (R/W) */
-#define VR4181_GPHIBSTH                __preg16(KSEG1 + 0x0B000316)    /* GPIO Hibernate Pin State High Register (R/W) */
-#define VR4181_GPHIBSTL                __preg16(KSEG1 + 0x0B000318)    /* GPIO Hibernate Pin State Low Register (R/W) */
-#define VR4181_GPSICTL         __preg16(KSEG1 + 0x0B00031A)    /* GPIO Serial Interface Control Register (R/W) */
-#define VR4181_KEYEN           __preg16(KSEG1 + 0x0B00031C)    /* Keyboard Scan Pin Enable Register (R/W) */
-#define VR4181_PCS0STRA                __preg16(KSEG1 + 0x0B000320)    /* Programmable Chip Select [0] Start Address Register (R/W) */
-#define VR4181_PCS0STPA                __preg16(KSEG1 + 0x0B000322)    /* Programmable Chip Select [0] Stop Address Register (R/W) */
-#define VR4181_PCS0HIA         __preg16(KSEG1 + 0x0B000324)    /* Programmable Chip Select [0] High Address Register (R/W) */
-#define VR4181_PCS1STRA                __preg16(KSEG1 + 0x0B000326)    /* Programmable Chip Select [1] Start Address Register (R/W) */
-#define VR4181_PCS1STPA                __preg16(KSEG1 + 0x0B000328)    /* Programmable Chip Select [1] Stop Address Register (R/W) */
-#define VR4181_PCS1HIA         __preg16(KSEG1 + 0x0B00032A)    /* Programmable Chip Select [1] High Address Register (R/W) */
-#define VR4181_PCSMODE         __preg16(KSEG1 + 0x0B00032C)    /* Programmable Chip Select Mode Register (R/W) */
-#define VR4181_LCDGPMODE       __preg16(KSEG1 + 0x0B00032E)    /* LCD General Purpose Mode Register (R/W) */
-#define VR4181_MISCREG0                __preg16(KSEG1 + 0x0B000330)    /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG1                __preg16(KSEG1 + 0x0B000332)    /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG2                __preg16(KSEG1 + 0x0B000334)    /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG3                __preg16(KSEG1 + 0x0B000336)    /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG4                __preg16(KSEG1 + 0x0B000338)    /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG5                __preg16(KSEG1 + 0x0B00033A)    /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG6                __preg16(KSEG1 + 0x0B00033C)    /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG7                __preg16(KSEG1 + 0x0B00033D)    /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG8                __preg16(KSEG1 + 0x0B000340)    /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG9                __preg16(KSEG1 + 0x0B000342)    /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG10       __preg16(KSEG1 + 0x0B000344)    /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG11       __preg16(KSEG1 + 0x0B000346)    /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG12       __preg16(KSEG1 + 0x0B000348)    /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG13       __preg16(KSEG1 + 0x0B00034A)    /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG14       __preg16(KSEG1 + 0x0B00034C)    /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG15       __preg16(KSEG1 + 0x0B00034E)    /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_SECIRQMASKL     VR4181_GPINTEN
-// No SECIRQMASKH for VR4181
-
-// Touch Panel Interface Unit (PIU)
-#define VR4181_PIUCNTREG       __preg16(KSEG1 + 0x0B000122)    /* PIU Control register (R/W) */
-#define VR4181_PIUCNTREG_PIUSEQEN      0x0004
-#define VR4181_PIUCNTREG_PIUPWR                0x0002
-#define VR4181_PIUCNTREG_PADRST                0x0001
-
-#define VR4181_PIUINTREG       __preg16(KSEG1 + 0x0B000124)    /* PIU Interrupt cause register (R/W) */
-#define VR4181_PIUINTREG_OVP           0x8000
-#define VR4181_PIUINTREG_PADCMD                0x0040
-#define VR4181_PIUINTREG_PADADP                0x0020
-#define VR4181_PIUINTREG_PADPAGE1      0x0010
-#define VR4181_PIUINTREG_PADPAGE0      0x0008
-#define VR4181_PIUINTREG_PADDLOST      0x0004
-#define VR4181_PIUINTREG_PENCHG                0x0001
-
-#define VR4181_PIUSIVLREG      __preg16(KSEG1 + 0x0B000126)    /* PIU Data sampling interval register (R/W) */
-#define VR4181_PIUSTBLREG      __preg16(KSEG1 + 0x0B000128)    /* PIU A/D converter start delay register (R/W) */
-#define VR4181_PIUCMDREG       __preg16(KSEG1 + 0x0B00012A)    /* PIU A/D command register (R/W) */
-#define VR4181_PIUASCNREG      __preg16(KSEG1 + 0x0B000130)    /* PIU A/D port scan register (R/W) */
-#define VR4181_PIUAMSKREG      __preg16(KSEG1 + 0x0B000132)    /* PIU A/D scan mask register (R/W) */
-#define VR4181_PIUCIVLREG      __preg16(KSEG1 + 0x0B00013E)    /* PIU Check interval register (R) */
-#define VR4181_PIUPB00REG      __preg16(KSEG1 + 0x0B0002A0)    /* PIU Page 0 Buffer 0 register (R/W) */
-#define VR4181_PIUPB01REG      __preg16(KSEG1 + 0x0B0002A2)    /* PIU Page 0 Buffer 1 register (R/W) */
-#define VR4181_PIUPB02REG      __preg16(KSEG1 + 0x0B0002A4)    /* PIU Page 0 Buffer 2 register (R/W) */
-#define VR4181_PIUPB03REG      __preg16(KSEG1 + 0x0B0002A6)    /* PIU Page 0 Buffer 3 register (R/W) */
-#define VR4181_PIUPB10REG      __preg16(KSEG1 + 0x0B0002A8)    /* PIU Page 1 Buffer 0 register (R/W) */
-#define VR4181_PIUPB11REG      __preg16(KSEG1 + 0x0B0002AA)    /* PIU Page 1 Buffer 1 register (R/W) */
-#define VR4181_PIUPB12REG      __preg16(KSEG1 + 0x0B0002AC)    /* PIU Page 1 Buffer 2 register (R/W) */
-#define VR4181_PIUPB13REG      __preg16(KSEG1 + 0x0B0002AE)    /* PIU Page 1 Buffer 3 register (R/W) */
-#define VR4181_PIUAB0REG       __preg16(KSEG1 + 0x0B0002B0)    /* PIU A/D scan Buffer 0 register (R/W) */
-#define VR4181_PIUAB1REG       __preg16(KSEG1 + 0x0B0002B2)    /* PIU A/D scan Buffer 1 register (R/W) */
-#define VR4181_PIUAB2REG       __preg16(KSEG1 + 0x0B0002B4)    /* PIU A/D scan Buffer 2 register (R/W) */
-#define VR4181_PIUAB3REG       __preg16(KSEG1 + 0x0B0002B6)    /* PIU A/D scan Buffer 3 register (R/W) */
-#define VR4181_PIUPB04REG      __preg16(KSEG1 + 0x0B0002BC)    /* PIU Page 0 Buffer 4 register (R/W) */
-#define VR4181_PIUPB14REG      __preg16(KSEG1 + 0x0B0002BE)    /* PIU Page 1 Buffer 4 register (R/W) */
-
-// Audio Interface Unit (AIU)
-#define VR4181_SODATREG                __preg16(KSEG1 + 0x0B000166)    /* Speaker Output Data Register (R/W) */
-#define VR4181_SCNTREG         __preg16(KSEG1 + 0x0B000168)    /* Speaker Output Control Register (R/W) */
-#define VR4181_MIDATREG                __preg16(KSEG1 + 0x0B000170)    /* Mike Input Data Register (R/W) */
-#define VR4181_MCNTREG         __preg16(KSEG1 + 0x0B000172)    /* Mike Input Control Register (R/W) */
-#define VR4181_DVALIDREG       __preg16(KSEG1 + 0x0B000178)    /* Data Valid Register (R/W) */
-#define VR4181_SEQREG          __preg16(KSEG1 + 0x0B00017A)    /* Sequential Register (R/W) */
-#define VR4181_INTREG          __preg16(KSEG1 + 0x0B00017C)    /* Interrupt Register (R/W) */
-#define VR4181_SDMADATREG      __preg16(KSEG1 + 0x0B000160)    /* Speaker DMA Data Register (R/W) */
-#define VR4181_MDMADATREG      __preg16(KSEG1 + 0x0B000162)    /* Microphone DMA Data Register (R/W) */
-#define VR4181_DAVREF_SETUP    __preg16(KSEG1 + 0x0B000164)    /* DAC Vref setup register (R/W) */
-#define VR4181_SCNVC_END       __preg16(KSEG1 + 0x0B00016E)    /* Speaker sample rate control (R/W) */
-#define VR4181_MIDATREG                __preg16(KSEG1 + 0x0B000170)    /* Microphone Input Data Register (R/W) */
-#define VR4181_MCNTREG         __preg16(KSEG1 + 0x0B000172)    /* Microphone Input Control Register (R/W) */
-#define VR4181_MCNVC_END       __preg16(KSEG1 + 0x0B00017E)    /* Microphone sample rate control (R/W) */
-
-// Keyboard Interface Unit (KIU)
-#define VR4181_KIUDAT0         __preg16(KSEG1 + 0x0B000180)    /* KIU Data0 Register (R/W) */
-#define VR4181_KIUDAT1         __preg16(KSEG1 + 0x0B000182)    /* KIU Data1 Register (R/W) */
-#define VR4181_KIUDAT2         __preg16(KSEG1 + 0x0B000184)    /* KIU Data2 Register (R/W) */
-#define VR4181_KIUDAT3         __preg16(KSEG1 + 0x0B000186)    /* KIU Data3 Register (R/W) */
-#define VR4181_KIUDAT4         __preg16(KSEG1 + 0x0B000188)    /* KIU Data4 Register (R/W) */
-#define VR4181_KIUDAT5         __preg16(KSEG1 + 0x0B00018A)    /* KIU Data5 Register (R/W) */
-#define VR4181_KIUSCANREP      __preg16(KSEG1 + 0x0B000190)    /* KIU Scan/Repeat Register (R/W) */
-#define VR4181_KIUSCANREP_KEYEN      0x8000
-#define VR4181_KIUSCANREP_SCANSTP    0x0008
-#define VR4181_KIUSCANREP_SCANSTART  0x0004
-#define VR4181_KIUSCANREP_ATSTP      0x0002
-#define VR4181_KIUSCANREP_ATSCAN     0x0001
-#define VR4181_KIUSCANS                __preg16(KSEG1 + 0x0B000192)    /* KIU Scan Status Register (R) */
-#define VR4181_KIUWKS          __preg16(KSEG1 + 0x0B000194)    /* KIU Wait Keyscan Stable Register (R/W) */
-#define VR4181_KIUWKI          __preg16(KSEG1 + 0x0B000196)    /* KIU Wait Keyscan Interval Register (R/W) */
-#define VR4181_KIUINT          __preg16(KSEG1 + 0x0B000198)    /* KIU Interrupt Register (R/W) */
-#define VR4181_KIUINT_KDATLOST       0x0004
-#define VR4181_KIUINT_KDATRDY        0x0002
-#define VR4181_KIUINT_SCANINT        0x0001
-#define VR4181_KIUDAT6         __preg16(KSEG1 + 0x0B00018C)    /* Scan Line 6 Key Data Register (R) */
-#define VR4181_KIUDAT7         __preg16(KSEG1 + 0x0B00018E)    /* Scan Line 7 Key Data Register (R) */
-
-// CompactFlash Controller
-#define VR4181_PCCARDINDEX     __preg8(KSEG1 + 0x0B0008E0)     /* PC Card Controller Index Register */
-#define VR4181_PCCARDDATA      __preg8(KSEG1 + 0x0B0008E1)     /* PC Card Controller Data Register */
-#define VR4181_INTSTATREG      __preg16(KSEG1 + 0x0B0008F8)    /* Interrupt Status Register (R/W) */
-#define VR4181_INTMSKREG       __preg16(KSEG1 + 0x0B0008FA)    /* Interrupt Mask Register (R/W) */
-#define VR4181_CFG_REG_1       __preg16(KSEG1 + 0x0B0008FE)    /* Configuration Register 1 */
-
-// LED Control Unit (LED)
-#define VR4181_LEDHTSREG       __preg16(KSEG1 + 0x0B000240)    /* LED H Time Set register (R/W) */
-#define VR4181_LEDLTSREG       __preg16(KSEG1 + 0x0B000242)    /* LED L Time Set register (R/W) */
-#define VR4181_LEDCNTREG       __preg16(KSEG1 + 0x0B000248)    /* LED Control register (R/W) */
-#define VR4181_LEDASTCREG      __preg16(KSEG1 + 0x0B00024A)    /* LED Auto Stop Time Count register (R/W) */
-#define VR4181_LEDINTREG       __preg16(KSEG1 + 0x0B00024C)    /* LED Interrupt register (R/W) */
-
-// Serial Interface Unit (SIU / SIU1 and SIU2)
-#define VR4181_SIURB           __preg8(KSEG1 + 0x0C000010)     /* Receiver Buffer Register (Read) DLAB = 0 (R) */
-#define VR4181_SIUTH           __preg8(KSEG1 + 0x0C000010)     /* Transmitter Holding Register (Write) DLAB = 0 (W) */
-#define VR4181_SIUDLL          __preg8(KSEG1 + 0x0C000010)     /* Divisor Latch (Least Significant Byte) DLAB = 1 (R/W) */
-#define VR4181_SIUIE           __preg8(KSEG1 + 0x0C000011)     /* Interrupt Enable DLAB = 0 (R/W) */
-#define VR4181_SIUDLM          __preg8(KSEG1 + 0x0C000011)     /* Divisor Latch (Most Significant Byte) DLAB = 1 (R/W) */
-#define VR4181_SIUIID          __preg8(KSEG1 + 0x0C000012)     /* Interrupt Identification Register (Read) (R) */
-#define VR4181_SIUFC           __preg8(KSEG1 + 0x0C000012)     /* FIFO Control Register (Write) (W) */
-#define VR4181_SIULC           __preg8(KSEG1 + 0x0C000013)     /* Line Control Register (R/W) */
-#define VR4181_SIUMC           __preg8(KSEG1 + 0x0C000014)     /* MODEM Control Register (R/W) */
-#define VR4181_SIULS           __preg8(KSEG1 + 0x0C000015)     /* Line Status Register (R/W) */
-#define VR4181_SIUMS           __preg8(KSEG1 + 0x0C000016)     /* MODEM Status Register (R/W) */
-#define VR4181_SIUSC           __preg8(KSEG1 + 0x0C000017)     /* Scratch Register (R/W) */
-#define VR4181_SIURESET                __preg8(KSEG1 + 0x0C000019)     /* SIU Reset Register (R/W) */
-#define VR4181_SIUACTMSK       __preg8(KSEG1 + 0x0C00001C)     /* SIU Activity Mask (R/W) */
-#define VR4181_SIUACTTMR       __preg8(KSEG1 + 0x0C00001E)     /* SIU Activity Timer (R/W) */
-#define VR4181_SIURB_2         __preg8(KSEG1 + 0x0C000000)     /* Receive Buffer Register (Read) (R) */
-#define VR4181_SIUTH_2         __preg8(KSEG1 + 0x0C000000)     /* Transmitter Holding Register (Write) (W) */
-#define VR4181_SIUDLL_2                __preg8(KSEG1 + 0x0C000000)     /* Divisor Latch (Least Significant Byte) (R/W) */
-#define VR4181_SIUIE_2         __preg8(KSEG1 + 0x0C000001)     /* Interrupt Enable (DLAB = 0) (R/W) */
-#define VR4181_SIUDLM_2                __preg8(KSEG1 + 0x0C000001)     /* Divisor Latch (Most Significant Byte) (DLAB = 1) (R/W) */
-#define VR4181_SIUIID_2                __preg8(KSEG1 + 0x0C000002)     /* Interrupt Identification Register (Read) (R) */
-#define VR4181_SIUFC_2         __preg8(KSEG1 + 0x0C000002)     /* FIFO Control Register (Write) (W) */
-#define VR4181_SIULC_2         __preg8(KSEG1 + 0x0C000003)     /* Line Control Register (R/W) */
-#define VR4181_SIUMC_2         __preg8(KSEG1 + 0x0C000004)     /* Modem Control Register (R/W) */
-#define VR4181_SIULS_2         __preg8(KSEG1 + 0x0C000005)     /* Line Status Register (R/W) */
-#define VR4181_SIUMS_2         __preg8(KSEG1 + 0x0C000006)     /* Modem Status Register (R/W) */
-#define VR4181_SIUSC_2         __preg8(KSEG1 + 0x0C000007)     /* Scratch Register (R/W) */
-#define VR4181_SIUIRSEL_2      __preg8(KSEG1 + 0x0C000008)     /* SIU IrDA Selectot (R/W) */
-#define VR4181_SIURESET_2      __preg8(KSEG1 + 0x0C000009)     /* SIU Reset Register (R/W) */
-#define VR4181_SIUCSEL_2       __preg8(KSEG1 + 0x0C00000A)     /* IrDA Echo-back Control (R/W) */
-#define VR4181_SIUACTMSK_2     __preg8(KSEG1 + 0x0C00000C)     /* SIU Activity Mask Register (R/W) */
-#define VR4181_SIUACTTMR_2     __preg8(KSEG1 + 0x0C00000E)     /* SIU Activity Timer Register (R/W) */
-
-
-// USB Module
-#define VR4181_USBINFIFO       __preg16(KSEG1 + 0x0B000780)    /* USB Bulk Input FIFO (Bulk In End Point) (W) */
-#define VR4181_USBOUTFIFO      __preg16(KSEG1 + 0x0B000782)    /* USB Bulk Output FIFO (Bulk Out End Point) (R) */
-#define VR4181_USBCTLFIFO      __preg16(KSEG1 + 0x0B000784)    /* USB Control FIFO (Control End Point) (W) */
-#define VR4181_USBSTAT         __preg16(KSEG1 + 0x0B000786)    /* Interrupt Status Register (R/W) */
-#define VR4181_USBINTMSK       __preg16(KSEG1 + 0x0B000788)    /* Interrupt Mask Register (R/W) */
-#define VR4181_USBCTLREG       __preg16(KSEG1 + 0x0B00078A)    /* Control Register (R/W) */
-#define VR4181_USBSTPREG       __preg16(KSEG1 + 0x0B00078C)    /* USB Transfer Stop Register (R/W) */
-
-// LCD Controller
-#define VR4181_HRTOTALREG      __preg16(KSEG1 + 0x0A000400)    /* Horizontal total Register (R/W) */
-#define VR4181_HRVISIBREG      __preg16(KSEG1 + 0x0A000402)    /* Horizontal Visible Register (R/W) */
-#define VR4181_LDCLKSTREG      __preg16(KSEG1 + 0x0A000404)    /* Load clock start Register (R/W) */
-#define VR4181_LDCLKNDREG      __preg16(KSEG1 + 0x0A000406)    /* Load clock end Register (R/W) */
-#define VR4181_VRTOTALREG      __preg16(KSEG1 + 0x0A000408)    /* Vertical Total Register (R/W) */
-#define VR4181_VRVISIBREG      __preg16(KSEG1 + 0x0A00040A)    /* Vertical Visible Register (R/W) */
-#define VR4181_FVSTARTREG      __preg16(KSEG1 + 0x0A00040C)    /* FLM vertical start Register (R/W) */
-#define VR4181_FVENDREG                __preg16(KSEG1 + 0x0A00040E)    /* FLM vertical end Register (R/W) */
-#define VR4181_LCDCTRLREG      __preg16(KSEG1 + 0x0A000410)    /* LCD control Register (R/W) */
-#define VR4181_LCDINRQREG      __preg16(KSEG1 + 0x0A000412)    /* LCD Interrupt request Register (R/W) */
-#define VR4181_LCDCFGREG0      __preg16(KSEG1 + 0x0A000414)    /* LCD Configuration Register 0 (R/W) */
-#define VR4181_LCDCFGREG1      __preg16(KSEG1 + 0x0A000416)    /* LCD Configuration Register 1 (R/W) */
-#define VR4181_FBSTAD1REG      __preg16(KSEG1 + 0x0A000418)    /* Frame Buffer Start Address 1 Register (R/W) */
-#define VR4181_FBSTAD2REG      __preg16(KSEG1 + 0x0A00041A)    /* Frame Buffer Start Address 2 Register (R/W) */
-#define VR4181_FBNDAD1REG      __preg16(KSEG1 + 0x0A000420)    /* Frame Buffer End Address 1 Register (R/W) */
-#define VR4181_FBNDAD2REG      __preg16(KSEG1 + 0x0A000422)    /* Frame Buffer End Address 2 register (R/W) */
-#define VR4181_FHSTARTREG      __preg16(KSEG1 + 0x0A000424)    /* FLM horizontal Start Register (R/W) */
-#define VR4181_FHENDREG                __preg16(KSEG1 + 0x0A000426)    /* FLM horizontal End Register (R/W) */
-#define VR4181_PWRCONREG1      __preg16(KSEG1 + 0x0A000430)    /* Power Control register 1 (R/W) */
-#define VR4181_PWRCONREG2      __preg16(KSEG1 + 0x0A000432)    /* Power Control register 2 (R/W) */
-#define VR4181_LCDIMSKREG      __preg16(KSEG1 + 0x0A000434)    /* LCD Interrupt Mask register (R/W) */
-#define VR4181_CPINDCTREG      __preg16(KSEG1 + 0x0A00047E)    /* Color palette Index and control Register (R/W) */
-#define VR4181_CPALDATREG      __preg32(KSEG1 + 0x0A000480)    /* Color palette data register (32bits Register) (R/W) */
-
-// physical address spaces
-#define VR4181_LCD             0x0a000000
-#define VR4181_INTERNAL_IO_2   0x0b000000
-#define VR4181_INTERNAL_IO_1   0x0c000000
-#define VR4181_ISA_MEM         0x10000000
-#define VR4181_ISA_IO          0x14000000
-#define VR4181_ROM             0x18000000
-
-// This is the base address for IO port decoding to which the 16 bit IO port address
-// is added.  Defining it to 0 will usually cause a kernel oops any time port IO is
-// attempted, which can be handy for turning up parts of the kernel that make
-// incorrect architecture assumptions (by assuming that everything acts like a PC),
-// but we need it correctly defined to use the PCMCIA/CF controller:
-#define VR4181_PORT_BASE       (KSEG1 + VR4181_ISA_IO)
-#define VR4181_ISAMEM_BASE     (KSEG1 + VR4181_ISA_MEM)
-
-#endif /* __ASM_VR4181_VR4181_H */
index 7d41e44463f954ee6edcbf93a88efe8d33684d7d..bd2723c309011461e27196f18746114be264dcce 100644 (file)
@@ -7,7 +7,7 @@
  * Copyright (C) 2001, 2002 Paul Mundt
  * Copyright (C) 2002 MontaVista Software, Inc.
  * Copyright (C) 2002 TimeSys Corp.
- * Copyright (C) 2003-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ * Copyright (C) 2003-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
  *
  * 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
@@ -79,11 +79,11 @@ extern void vr41xx_mask_clock(vr41xx_clock_t clock);
 #define MIPS_CPU_IRQ(x)                (MIPS_CPU_IRQ_BASE + (x))
 #define MIPS_SOFTINT0_IRQ      MIPS_CPU_IRQ(0)
 #define MIPS_SOFTINT1_IRQ      MIPS_CPU_IRQ(1)
-#define INT0_CASCADE_IRQ       MIPS_CPU_IRQ(2)
-#define INT1_CASCADE_IRQ       MIPS_CPU_IRQ(3)
-#define INT2_CASCADE_IRQ       MIPS_CPU_IRQ(4)
-#define INT3_CASCADE_IRQ       MIPS_CPU_IRQ(5)
-#define INT4_CASCADE_IRQ       MIPS_CPU_IRQ(6)
+#define INT0_IRQ               MIPS_CPU_IRQ(2)
+#define INT1_IRQ               MIPS_CPU_IRQ(3)
+#define INT2_IRQ               MIPS_CPU_IRQ(4)
+#define INT3_IRQ               MIPS_CPU_IRQ(5)
+#define INT4_IRQ               MIPS_CPU_IRQ(6)
 #define TIMER_IRQ              MIPS_CPU_IRQ(7)
 
 /* SYINT1 Interrupt Numbers */
@@ -97,7 +97,7 @@ extern void vr41xx_mask_clock(vr41xx_clock_t clock);
 #define PIU_IRQ                        SYSINT1_IRQ(5)
 #define AIU_IRQ                        SYSINT1_IRQ(6)
 #define KIU_IRQ                        SYSINT1_IRQ(7)
-#define GIUINT_CASCADE_IRQ     SYSINT1_IRQ(8)
+#define GIUINT_IRQ             SYSINT1_IRQ(8)
 #define SIU_IRQ                        SYSINT1_IRQ(9)
 #define BUSERR_IRQ             SYSINT1_IRQ(10)
 #define SOFTINT_IRQ            SYSINT1_IRQ(11)
@@ -128,7 +128,7 @@ extern void vr41xx_mask_clock(vr41xx_clock_t clock);
 #define GIU_IRQ_LAST           GIU_IRQ(31)
 
 extern int vr41xx_set_intassign(unsigned int irq, unsigned char intassign);
-extern int vr41xx_cascade_irq(unsigned int irq, int (*get_irq_number)(int irq));
+extern int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int, struct pt_regs *));
 
 #define PIUINT_COMMAND         0x0040
 #define PIUINT_DATA            0x0020
index 58e193c51b45ac370f7fbb9f88c2dc513c5c0fa0..bb7a85c186e4c7d663c7798b6f25d453f2c4a6a3 100644 (file)
@@ -21,8 +21,8 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#ifndef __NEC_VRC4173_H 
-#define __NEC_VRC4173_H 
+#ifndef __NEC_VRC4173_H
+#define __NEC_VRC4173_H
 
 #include <linux/config.h>
 #include <asm/io.h>
index c4a70412134327a586b46acc7f00b385b14d8f0f..04ee53b34c2e76a70a45d14ed8c5da9df6a7084b 100644 (file)
  */
 #define BCM1250_M3_WAR 1
 
-/* 
+/*
  * This is a DUART workaround related to glitches around register accesses
  */
 #define SIBYTE_1956_WAR 1
 
 /*
  * Fill buffers not flushed on CACHE instructions
- * 
+ *
  * Hit_Invalidate_I cacheops invalidate an icache line but the refill
  * for that line can get stale data from the fill buffer instead of
  * accessing memory if the previous icache miss was also to that line.
index 75c0ddfeca13e21cce645ff7c168f254f1a4cf3b..4d84a90b0f200c53c268a8f363063a4dac9deae0 100644 (file)
@@ -22,7 +22,7 @@
  *
  * ########################################################################
  *
- * 
+ *
  */
 #ifndef __ASM_XXS1500_H
 #define __ASM_XXS1500_H
diff --git a/include/asm-parisc/auxvec.h b/include/asm-parisc/auxvec.h
new file mode 100644 (file)
index 0000000..9c3ac4b
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __ASMPARISC_AUXVEC_H
+#define __ASMPARISC_AUXVEC_H
+
+#endif
index 7630d1ad2391ada9799226cb13eadaf5fc3edf63..38b918feead90ee9e2218d052346cef8046975a8 100644 (file)
@@ -13,8 +13,10 @@ typedef s32  compat_ssize_t;
 typedef s32    compat_time_t;
 typedef s32    compat_clock_t;
 typedef s32    compat_pid_t;
-typedef u32    compat_uid_t;
-typedef u32    compat_gid_t;
+typedef u32    __compat_uid_t;
+typedef u32    __compat_gid_t;
+typedef u32    __compat_uid32_t;
+typedef u32    __compat_gid32_t;
 typedef u16    compat_mode_t;
 typedef u32    compat_ino_t;
 typedef u32    compat_dev_t;
@@ -67,8 +69,8 @@ struct compat_stat {
        compat_dev_t            st_realdev;
        u16                     st_basemode;
        u16                     st_spareshort;
-       compat_uid_t            st_uid;
-       compat_gid_t            st_gid;
+       __compat_uid32_t        st_uid;
+       __compat_gid32_t        st_gid;
        u32                     st_spare4[3];
 };
 
index def35230716afc55a1e14f81fede288b96de35ad..317851fa78f3f99b702ba30fff49dea37da728ef 100644 (file)
@@ -3,38 +3,22 @@
 
 /* open/fcntl - O_SYNC is only implemented on blocks devices and on files
    located on an ext2 file system */
-#define O_ACCMODE      00000003
-#define O_RDONLY       00000000
-#define O_WRONLY       00000001
-#define O_RDWR         00000002
 #define O_APPEND       00000010
 #define O_BLKSEEK      00000100 /* HPUX only */
 #define O_CREAT                00000400 /* not fcntl */
-#define O_TRUNC                00001000 /* not fcntl */
 #define O_EXCL         00002000 /* not fcntl */
 #define O_LARGEFILE    00004000
 #define O_SYNC         00100000
 #define O_NONBLOCK     00200004 /* HPUX has separate NDELAY & NONBLOCK */
-#define O_NDELAY       O_NONBLOCK
 #define O_NOCTTY       00400000 /* not fcntl */
 #define O_DSYNC                01000000 /* HPUX only */
 #define O_RSYNC                02000000 /* HPUX only */
 #define O_NOATIME      04000000
 
-#define FASYNC         00020000 /* fcntl, for BSD compatibility */
-#define O_DIRECT       00040000 /* direct disk access hint - currently ignored */
 #define O_DIRECTORY    00010000 /* must be a directory */
 #define O_NOFOLLOW     00000200 /* don't follow links */
 #define O_INVISIBLE    04000000 /* invisible I/O, for DMAPI/XDSM */
 
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get f_flags */
-#define F_SETFD                2       /* set f_flags */
-#define F_GETFL                3       /* more flags (cloexec) */
-#define F_SETFL                4
-#define F_GETLK                5
-#define F_SETLK                6
-#define F_SETLKW       7
 #define F_GETLK64      8
 #define F_SETLK64      9
 #define F_SETLKW64     10
 #define F_SETSIG       13      /*  for sockets. */
 #define F_GETSIG       14      /*  for sockets. */
 
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
 /* for posix fcntl() and lockf() */
 #define F_RDLCK                01
 #define F_WRLCK                02
 #define F_UNLCK                03
 
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
-
-struct flock {
-       short l_type;
-       short l_whence;
-       off_t l_start;
-       off_t l_len;
-       pid_t l_pid;
-};
-
-struct flock64 {
-       short l_type;
-       short l_whence;
-       loff_t l_start;
-       loff_t l_len;
-       pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE  1024
+#include <asm-generic/fcntl.h>
 
 #endif
diff --git a/include/asm-parisc/futex.h b/include/asm-parisc/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-parisc/hdreg.h b/include/asm-parisc/hdreg.h
deleted file mode 100644 (file)
index 7f7fd1a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/hdreg.h>
index 75654ba9335359b71c61bd2f0369b757e188c196..f876bdf220569f0f90eaec0436665a8bf95d1464 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 4a12692f94b4659c5d10769416cddebb34421f88..44eae9f8274d8029786a81aa1fcad4ff9e022b95 100644 (file)
@@ -74,20 +74,6 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 #define __pgd(x)       ((pgd_t) { (x) } )
 #define __pgprot(x)    ((pgprot_t) { (x) } )
 
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size-1) >> (PAGE_SHIFT-1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
-
 typedef struct __physmem_range {
        unsigned long start_pfn;
        unsigned long pages;       /* PAGE_SIZE pages */
@@ -159,4 +145,6 @@ extern int npmem_ranges;
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/page.h>
+
 #endif /* _PARISC_PAGE_H */
index 4a77996c1862c53c773d334f8c27646ad4f9cbdc..1bf54dc53c101337200deeaafa7adcf27daf97ff 100644 (file)
@@ -16,6 +16,8 @@
 /* To add :#define SO_REUSEPORT 0x0200 */
 #define SO_SNDBUF      0x1001
 #define SO_RCVBUF      0x1002
+#define SO_SNDBUFFORCE 0x100a
+#define SO_RCVBUFFORCE 0x100b
 #define SO_SNDLOWAT    0x1003
 #define SO_RCVLOWAT    0x1004
 #define SO_SNDTIMEO    0x1005
index 8fe7a44ea205d4a3059b61c089ed0c4a747ee31b..d21b9d0d63eabc37485671c951a7fc2dee470775 100644 (file)
@@ -56,8 +56,6 @@ typedef unsigned long long u64;
 typedef u32 dma_addr_t;
 typedef u64 dma64_addr_t;
 
-typedef unsigned int kmem_bufctl_t;
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index c1b5bdea53ee078773584f3842393b8640740ed0..f6c417c8c484a8965eee6ac6cfd175d45a82c8d4 100644 (file)
@@ -40,10 +40,6 @@ static inline long access_ok(int type, const void __user * addr,
        return 1;
 }
 
-#define verify_area(type,addr,size) (0)        /* FIXME: all users should go away soon,
-                                         * and use access_ok instead, then this
-                                         * should be removed. */
-
 #define put_user __put_user
 #define get_user __get_user
 
similarity index 74%
rename from include/asm-ppc/8253pit.h
rename to include/asm-powerpc/8253pit.h
index 285f78488ccb76f988a020e1730fbbefc251cefb..862708a749b0fb1383c1d83551fc09ae26e5a2cd 100644 (file)
@@ -5,6 +5,6 @@
 #ifndef _8253PIT_H
 #define _8253PIT_H
 
-#define PIT_TICK_RATE  1193182UL
+#define PIT_TICK_RATE  1193182UL
 
 #endif
similarity index 56%
rename from include/asm-ppc64/shmparam.h
rename to include/asm-powerpc/bugs.h
index b2825ceff05eb17ed767d43e826157d5c78ba03c..310187d0e33ac21303e629b74917dec3d3ddcbeb 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _PPC64_SHMPARAM_H
-#define _PPC64_SHMPARAM_H
+#ifndef _POWERPC_BUGS_H
+#define _POWERPC_BUGS_H
 
 /*
  * This program is free software; you can redistribute it and/or
@@ -8,6 +8,11 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#define        SHMLBA PAGE_SIZE                 /* attach addr a multiple of this */
+/*
+ * This file is included by 'init/main.c' to check for
+ * architecture-dependent bugs.
+ */
+
+extern void check_bugs(void);
 
-#endif /* _PPC64_SHMPARAM_H */
+#endif /* _POWERPC_BUGS_H */
diff --git a/include/asm-powerpc/cputime.h b/include/asm-powerpc/cputime.h
new file mode 100644 (file)
index 0000000..6d68ad7
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/cputime.h>
diff --git a/include/asm-powerpc/emergency-restart.h b/include/asm-powerpc/emergency-restart.h
new file mode 100644 (file)
index 0000000..3711bd9
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/emergency-restart.h>
diff --git a/include/asm-powerpc/fcntl.h b/include/asm-powerpc/fcntl.h
new file mode 100644 (file)
index 0000000..ce5c451
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _ASM_FCNTL_H
+#define _ASM_FCNTL_H
+
+#define O_DIRECTORY      040000        /* must be a directory */
+#define O_NOFOLLOW      0100000        /* don't follow links */
+#define O_LARGEFILE     0200000
+#define O_DIRECT       0400000 /* direct disk access hint */
+
+#include <asm-generic/fcntl.h>
+
+#endif /* _ASM_FCNTL_H */
similarity index 84%
rename from include/asm-ppc64/mc146818rtc.h
rename to include/asm-powerpc/mc146818rtc.h
index f713e1bbb533fb80d844ef8d7e125a8a4b55dc53..a5619a2a1393b3c532f2f4b4199eb5556523b33f 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef _POWERPC_MC146818RTC_H
+#define _POWERPC_MC146818RTC_H
+
 /*
  * Machine dependent access functions for RTC registers.
  *
@@ -6,8 +9,8 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-#ifndef __ASM_PPC64_MC146818RTC_H
-#define __ASM_PPC64_MC146818RTC_H
+
+#ifdef __KERNEL__
 
 #include <asm/io.h>
 
@@ -29,4 +32,5 @@ outb_p((addr),RTC_PORT(0)); \
 outb_p((val),RTC_PORT(1)); \
 })
 
-#endif /* __ASM_PPC64_MC146818RTC_H */
+#endif /* __KERNEL__ */
+#endif /* _POWERPC_MC146818RTC_H */
similarity index 96%
rename from include/asm-ppc64/mman.h
rename to include/asm-powerpc/mman.h
index d4f93446a52c75e8278c8b7faf7920493f693801..f2d55988d749db110f974266f624d6b89bf447e3 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef __PPC64_MMAN_H__
-#define __PPC64_MMAN_H__
+#ifndef _POWERPC_MMAN_H
+#define _POWERPC_MMAN_H
 
 /*
  * This program is free software; you can redistribute it and/or
@@ -49,4 +49,4 @@
 #define MAP_ANON       MAP_ANONYMOUS
 #define MAP_FILE       0
 
-#endif /* __PPC64_MMAN_H__ */
+#endif /* _POWERPC_MMAN_H */
diff --git a/include/asm-powerpc/module.h b/include/asm-powerpc/module.h
new file mode 100644 (file)
index 0000000..4438f4f
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef _POWERPC_MODULE_H
+#define _POWERPC_MODULE_H
+
+/*
+ * 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/list.h>
+#include <asm/bug.h>
+
+
+#ifndef __powerpc64__
+/*
+ * Thanks to Paul M for explaining this.
+ *
+ * PPC can only do rel jumps += 32MB, and often the kernel and other
+ * modules are furthur away than this.  So, we jump to a table of
+ * trampolines attached to the module (the Procedure Linkage Table)
+ * whenever that happens.
+ */
+
+struct ppc_plt_entry {
+       /* 16 byte jump instruction sequence (4 instructions) */
+       unsigned int jump[4];
+};
+#endif /* __powerpc64__ */
+
+
+struct mod_arch_specific {
+#ifdef __powerpc64__
+       unsigned int stubs_section;     /* Index of stubs section in module */
+       unsigned int toc_section;       /* What section is the TOC? */
+#else
+       /* Indices of PLT sections within module. */
+       unsigned int core_plt_section;
+       unsigned int init_plt_section;
+#endif
+
+       /* List of BUG addresses, source line numbers and filenames */
+       struct list_head bug_list;
+       struct bug_entry *bug_table;
+       unsigned int num_bugs;
+};
+
+extern struct bug_entry *module_find_bug(unsigned long bugaddr);
+
+/*
+ * Select ELF headers.
+ * Make empty section for module_frob_arch_sections to expand.
+ */
+
+#ifdef __powerpc64__
+#    define Elf_Shdr   Elf64_Shdr
+#    define Elf_Sym    Elf64_Sym
+#    define Elf_Ehdr   Elf64_Ehdr
+#    ifdef MODULE
+       asm(".section .stubs,\"ax\",@nobits; .align 3; .previous");
+#    endif
+#else
+#    define Elf_Shdr   Elf32_Shdr
+#    define Elf_Sym    Elf32_Sym
+#    define Elf_Ehdr   Elf32_Ehdr
+#    ifdef MODULE
+       asm(".section .plt,\"ax\",@nobits; .align 3; .previous");
+       asm(".section .init.plt,\"ax\",@nobits; .align 3; .previous");
+#    endif     /* MODULE */
+#endif
+
+
+struct exception_table_entry;
+void sort_ex_table(struct exception_table_entry *start,
+                  struct exception_table_entry *finish);
+
+#endif /* _POWERPC_MODULE_H */
diff --git a/include/asm-powerpc/percpu.h b/include/asm-powerpc/percpu.h
new file mode 100644 (file)
index 0000000..06a959d
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/percpu.h>
diff --git a/include/asm-powerpc/resource.h b/include/asm-powerpc/resource.h
new file mode 100644 (file)
index 0000000..04bc4db
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/resource.h>
similarity index 62%
rename from include/asm-ppc64/sembuf.h
rename to include/asm-powerpc/sembuf.h
index 172e590007675b63d8c8d3ec8657f99125100eda..c98fc18fe805f491c14808df0baba1fe2954bcf8 100644 (file)
@@ -1,27 +1,36 @@
-#ifndef _PPC64_SEMBUF_H
-#define _PPC64_SEMBUF_H
+#ifndef _POWERPC_SEMBUF_H
+#define _POWERPC_SEMBUF_H
 
-/* 
- * The semid64_ds structure for PPC architecture.
- *
- *
+/*
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * The semid64_ds structure for PPC architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
  *
  * Pad space is left for:
- * - 2 miscellaneous 64-bit values
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
  */
 
 struct semid64_ds {
        struct ipc64_perm sem_perm;     /* permissions .. see ipc.h */
+#ifndef __powerpc64__
+       unsigned long   __unused1;
+#endif
        __kernel_time_t sem_otime;      /* last semop time */
+#ifndef __powerpc64__
+       unsigned long   __unused2;
+#endif
        __kernel_time_t sem_ctime;      /* last change time */
        unsigned long   sem_nsems;      /* no. of semaphores in array */
-
-       unsigned long   __unused1;
-       unsigned long   __unused2;
+       unsigned long   __unused3;
+       unsigned long   __unused4;
 };
 
-#endif /* _PPC64_SEMBUF_H */
+#endif /* _POWERPC_SEMBUF_H */
similarity index 72%
rename from include/asm-ppc64/shmbuf.h
rename to include/asm-powerpc/shmbuf.h
index 02e99d6ec925eb03ba003b00b5284cd1d4ad8c0b..29632db3b1788634528fee93eacf06234671a067 100644 (file)
@@ -1,31 +1,47 @@
-#ifndef _PPC64_SHMBUF_H
-#define _PPC64_SHMBUF_H
+#ifndef _POWERPC_SHMBUF_H
+#define _POWERPC_SHMBUF_H
 
-/* 
- * The shmid64_ds structure for PPC64 architecture.
- * Note extra padding because this structure is passed back and forth
- * between kernel and user space.
- *
- * Pad space is left for:
- * - 2 miscellaneous 64-bit values
- *
+/*
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
 
+/*
+ * The shmid64_ds structure for PPC architecture.
+ *
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
 struct shmid64_ds {
        struct ipc64_perm       shm_perm;       /* operation perms */
+#ifndef __power64__
+       unsigned long           __unused1;
+#endif
        __kernel_time_t         shm_atime;      /* last attach time */
+#ifndef __power64__
+       unsigned long           __unused2;
+#endif
        __kernel_time_t         shm_dtime;      /* last detach time */
+#ifndef __power64__
+       unsigned long           __unused3;
+#endif
        __kernel_time_t         shm_ctime;      /* last change time */
+#ifndef __power64__
+       unsigned long           __unused4;
+#endif
        size_t                  shm_segsz;      /* size of segment (bytes) */
        __kernel_pid_t          shm_cpid;       /* pid of creator */
        __kernel_pid_t          shm_lpid;       /* pid of last operator */
        unsigned long           shm_nattch;     /* no. of current attaches */
-       unsigned long           __unused1;
-       unsigned long           __unused2;
+       unsigned long           __unused5;
+       unsigned long           __unused6;
 };
 
 struct shminfo64 {
@@ -40,4 +56,4 @@ struct shminfo64 {
        unsigned long   __unused4;
 };
 
-#endif /* _PPC64_SHMBUF_H */
+#endif /* _POWERPC_SHMBUF_H */
similarity index 56%
rename from include/asm-ppc64/siginfo.h
rename to include/asm-powerpc/siginfo.h
index 3a7c23dcb5aaa557cc29fbe949692d2bc3c3c8be..ae70b8010b199da3ea9cabde0ad0e1283343ff28 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _PPC64_SIGINFO_H
-#define _PPC64_SIGINFO_H
+#ifndef _POWERPC_SIGINFO_H
+#define _POWERPC_SIGINFO_H
 
 /*
  * This program is free software; you can redistribute it and/or
@@ -8,9 +8,11 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#define __ARCH_SI_PREAMBLE_SIZE        (4 * sizeof(int))
-#define SI_PAD_SIZE32          ((SI_MAX_SIZE/sizeof(int)) - 3)
+#ifdef __powerpc64__
+#    define __ARCH_SI_PREAMBLE_SIZE    (4 * sizeof(int))
+#    define SI_PAD_SIZE32              ((SI_MAX_SIZE/sizeof(int)) - 3)
+#endif
 
 #include <asm-generic/siginfo.h>
 
-#endif /* _PPC64_SIGINFO_H */
+#endif /* _POWERPC_SIGINFO_H */
similarity index 85%
rename from include/asm-ppc64/socket.h
rename to include/asm-powerpc/socket.h
index 59e00dfc8b8ec48d4e566bd4d20bfd0347740251..51a0cf5ee9f0e054b02b5f7dc36fda5c26ae16a2 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _ASM_SOCKET_H
-#define _ASM_SOCKET_H
+#ifndef _POWERPC_SOCKET_H
+#define _POWERPC_SOCKET_H
 
 /*
  * This program is free software; you can redistribute it and/or
@@ -10,7 +10,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET     1
 
 #define SO_DEBUG       1
@@ -21,6 +21,8 @@
 #define SO_BROADCAST   6
 #define SO_SNDBUF      7
 #define SO_RCVBUF      8
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
 #define SO_KEEPALIVE   9
 #define SO_OOBINLINE   10
 #define SO_NO_CHECK    11
@@ -50,8 +52,8 @@
 #define SO_TIMESTAMP           29
 #define SCM_TIMESTAMP          SO_TIMESTAMP
 
-#define SO_ACCEPTCONN           30
+#define SO_ACCEPTCONN          30
 
-#define SO_PEERSEC             31
+#define SO_PEERSEC             31
 
-#endif /* _ASM_SOCKET_H */
+#endif /* _POWERPC_SOCKET_H */
similarity index 83%
rename from include/asm-ppc64/sockios.h
rename to include/asm-powerpc/sockios.h
index 6bd1a22af4f68df096471be107a090990c38fd1d..ef7ff664167e894e8a8851c4f5e383fc44ca7189 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _ASM_PPC64_SOCKIOS_H
-#define _ASM_PPC64_SOCKIOS_H
+#ifndef _POWERPC_SOCKIOS_H
+#define _POWERPC_SOCKIOS_H
 
 /*
  * This program is free software; you can redistribute it and/or
@@ -16,4 +16,4 @@
 #define SIOCATMARK     0x8905
 #define SIOCGSTAMP     0x8906          /* Get stamp */
 
-#endif /* _ASM_PPC64_SOCKIOS_H */
+#endif /* _POWERPC_SOCKIOS_H */
similarity index 97%
rename from include/asm-ppc64/termbits.h
rename to include/asm-powerpc/termbits.h
index d1a2bee10cefa5270e0a863cf9899919a1695447..2c5bf85a8c3c2c30a8a36ea8b0ccba15e0b26d03 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _PPC64_TERMBITS_H
-#define _PPC64_TERMBITS_H
+#ifndef _POWERPC_TERMBITS_H
+#define _POWERPC_TERMBITS_H
 
 /*
  * This program is free software; you can redistribute it and/or
@@ -8,8 +8,6 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#include <linux/posix_types.h>
-
 typedef unsigned char  cc_t;
 typedef unsigned int   speed_t;
 typedef unsigned int   tcflag_t;
@@ -190,4 +188,4 @@ struct termios {
 #define        TCSADRAIN       1
 #define        TCSAFLUSH       2
 
-#endif /* _PPC64_TERMBITS_H */
+#endif /* _POWERPC_TERMBITS_H */
similarity index 98%
rename from include/asm-ppc64/termios.h
rename to include/asm-powerpc/termios.h
index 02c3d283aa62bc1b4d7c5d1b22ce03ee4b8771eb..237533bb0e9f1a3e640c4906d8b350deafd315b9 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _PPC64_TERMIOS_H
-#define _PPC64_TERMIOS_H
+#ifndef _POWERPC_TERMIOS_H
+#define _POWERPC_TERMIOS_H
 
 /*
  * Liberally adapted from alpha/termios.h.  In particular, the c_cc[]
@@ -87,6 +87,7 @@ struct termio {
 #define N_SMSBLOCK     12      /* SMS block mode - for talking to GSM data cards about SMS messages */
 #define N_HDLC         13      /* synchronous HDLC */
 #define N_SYNC_PPP     14
+#define N_HCI          15  /* Bluetooth HCI UART */
 
 #ifdef __KERNEL__
 /*                   ^C  ^\ del  ^U  ^D   1   0   0   0   0  ^W  ^R  ^Z  ^Q  ^S  ^V  ^U  */
@@ -232,4 +233,4 @@ struct termio {
 
 #endif /* __KERNEL__ */
 
-#endif /* _PPC64_TERMIOS_H */
+#endif /* _POWERPC_TERMIOS_H */
diff --git a/include/asm-ppc/auxvec.h b/include/asm-ppc/auxvec.h
new file mode 100644 (file)
index 0000000..172358d
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __PPC_AUXVEC_H
+#define __PPC_AUXVEC_H
+
+/*
+ * We need to put in some extra aux table entries to tell glibc what
+ * the cache block size is, so it can use the dcbz instruction safely.
+ */
+#define AT_DCACHEBSIZE         19
+#define AT_ICACHEBSIZE         20
+#define AT_UCACHEBSIZE         21
+/* A special ignored type value for PPC, for glibc compatibility.  */
+#define AT_IGNOREPPC           22
+
+#endif
diff --git a/include/asm-ppc/bugs.h b/include/asm-ppc/bugs.h
deleted file mode 100644 (file)
index 8dce1e2..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-/*
- * This file is included by 'init/main.c'
- */
-
-extern void
-check_bugs(void);
diff --git a/include/asm-ppc/cputime.h b/include/asm-ppc/cputime.h
deleted file mode 100644 (file)
index 8e9faf5..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __PPC_CPUTIME_H
-#define __PPC_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __PPC_CPUTIME_H */
index 6f74f59938d4970d72ac74943f223baacf362669..92b8ee78dcc21b6a959219ec9ef8da7872fb26a7 100644 (file)
@@ -60,7 +60,8 @@ static inline int dma_set_mask(struct device *dev, u64 dma_mask)
 }
 
 static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-                                      dma_addr_t * dma_handle, int gfp)
+                                      dma_addr_t * dma_handle,
+                                      unsigned int __nocast gfp)
 {
 #ifdef CONFIG_NOT_COHERENT_CACHE
        return __dma_alloc_coherent(size, dma_handle, gfp);
index 2c056966efd34650ee5dfeb6f0d79c0516659bc2..c25cc35e6ab5818702dbca5241c92a93bbad2a97 100644 (file)
@@ -7,6 +7,7 @@
 #include <asm/types.h>
 #include <asm/ptrace.h>
 #include <asm/cputable.h>
+#include <asm/auxvec.h>
 
 /* PowerPC relocations defined by the ABIs */
 #define R_PPC_NONE             0
@@ -122,16 +123,6 @@ extern int dump_task_fpu(struct task_struct *t, elf_fpregset_t *fpu);
 
 #define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
 
-/*
- * We need to put in some extra aux table entries to tell glibc what
- * the cache block size is, so it can use the dcbz instruction safely.
- */
-#define AT_DCACHEBSIZE         19
-#define AT_ICACHEBSIZE         20
-#define AT_UCACHEBSIZE         21
-/* A special ignored type value for PPC, for glibc compatibility.  */
-#define AT_IGNOREPPC           22
-
 extern int dcache_bsize;
 extern int icache_bsize;
 extern int ucache_bsize;
diff --git a/include/asm-ppc/emergency-restart.h b/include/asm-ppc/emergency-restart.h
deleted file mode 100644 (file)
index 108d8c4..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_EMERGENCY_RESTART_H
-#define _ASM_EMERGENCY_RESTART_H
-
-#include <asm-generic/emergency-restart.h>
-
-#endif /* _ASM_EMERGENCY_RESTART_H */
diff --git a/include/asm-ppc/fcntl.h b/include/asm-ppc/fcntl.h
deleted file mode 100644 (file)
index 5e28e41..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-#ifndef _PPC_FCNTL_H
-#define _PPC_FCNTL_H
-
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
-   located on an ext2 file system */
-#define O_ACCMODE         0003
-#define O_RDONLY            00
-#define O_WRONLY            01
-#define O_RDWR              02
-#define O_CREAT                   0100 /* not fcntl */
-#define O_EXCL            0200 /* not fcntl */
-#define O_NOCTTY          0400 /* not fcntl */
-#define O_TRUNC                  01000 /* not fcntl */
-#define O_APPEND         02000
-#define O_NONBLOCK       04000
-#define O_NDELAY       O_NONBLOCK
-#define O_SYNC          010000
-#define FASYNC          020000 /* fcntl, for BSD compatibility */
-#define O_DIRECTORY      040000        /* must be a directory */
-#define O_NOFOLLOW      0100000        /* don't follow links */
-#define O_LARGEFILE     0200000
-#define O_DIRECT       0400000 /* direct disk access hint */
-#define O_NOATIME      01000000
-
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
-#define F_GETLK                5
-#define F_SETLK                6
-#define F_SETLKW       7
-
-#define F_SETOWN       8       /*  for sockets. */
-#define F_GETOWN       9       /*  for sockets. */
-#define F_SETSIG       10      /*  for sockets. */
-#define F_GETSIG       11      /*  for sockets. */
-
-#define F_GETLK64      12      /*  using 'struct flock64' */
-#define F_SETLK64      13
-#define F_SETLKW64     14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK                0
-#define F_WRLCK                1
-#define F_UNLCK                2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
-
-#ifdef __KERNEL__
-#define F_POSIX                1
-#define F_FLOCK                2
-#define F_BROKEN       4       /* broken flock() emulation */
-#endif /* __KERNEL__ */
-
-struct flock {
-       short l_type;
-       short l_whence;
-       off_t l_start;
-       off_t l_len;
-       pid_t l_pid;
-};
-
-struct flock64 {
-       short  l_type;
-       short  l_whence;
-       loff_t l_start;
-       loff_t l_len;
-       pid_t  l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE  1024
-#endif
diff --git a/include/asm-ppc/futex.h b/include/asm-ppc/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-ppc/hdreg.h b/include/asm-ppc/hdreg.h
deleted file mode 100644 (file)
index 7f7fd1a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/hdreg.h>
index e807be96e9814761b9033d55da6332320c287e31..e992369cb8e9b476fd64306bbc92a846a5bb074f 100644 (file)
 
 #ifdef CONFIG_40x
 
-#if defined(CONFIG_ASH)
-#include <platforms/4xx/ash.h>
-#endif
-
 #if defined(CONFIG_BUBINGA)
 #include <platforms/4xx/bubinga.h>
 #endif
 #include <platforms/4xx/ep405.h>
 #endif
 
-#if defined(CONFIG_OAK)
-#include <platforms/4xx/oak.h>
-#endif
-
-#if defined(CONFIG_REDWOOD_4)
-#include <platforms/4xx/redwood.h>
-#endif
-
 #if defined(CONFIG_REDWOOD_5)
 #include <platforms/4xx/redwood5.h>
 #endif
index 3f7b5669e6d52c852727e4c7791dd78d89a16abf..6f10a25bd628c18cc2f4bd1462d79c9f61936a86 100644 (file)
@@ -67,6 +67,7 @@ struct ocp_func_emac_data {
        int     phy_mode;       /* PHY type or configurable mode */
        u8      mac_addr[6];    /* EMAC mac address */
        u32     phy_map;        /* EMAC phy map */
+       u32     phy_feat_exc;   /* Excluded PHY features */
 };
 
 /* Sysfs support */
@@ -83,6 +84,7 @@ OCP_SYSFS_ADDTL(struct ocp_func_emac_data, "%d\n", emac, mdio_idx)    \
 OCP_SYSFS_ADDTL(struct ocp_func_emac_data, "%d\n", emac, tah_idx)      \
 OCP_SYSFS_ADDTL(struct ocp_func_emac_data, "%d\n", emac, phy_mode)     \
 OCP_SYSFS_ADDTL(struct ocp_func_emac_data, "0x%08x\n", emac, phy_map)  \
+OCP_SYSFS_ADDTL(struct ocp_func_emac_data, "0x%08x\n", emac, phy_feat_exc)\
                                                                        \
 void ocp_show_emac_data(struct device *dev)                            \
 {                                                                      \
@@ -98,8 +100,22 @@ void ocp_show_emac_data(struct device *dev)                         \
        device_create_file(dev, &dev_attr_emac_tah_idx);                \
        device_create_file(dev, &dev_attr_emac_phy_mode);               \
        device_create_file(dev, &dev_attr_emac_phy_map);                \
+       device_create_file(dev, &dev_attr_emac_phy_feat_exc);           \
 }
 
+/*
+ * PHY mode settings (EMAC <-> ZMII/RGMII bridge <-> PHY)
+ */
+#define PHY_MODE_NA    0
+#define PHY_MODE_MII   1
+#define PHY_MODE_RMII  2
+#define PHY_MODE_SMII  3
+#define PHY_MODE_RGMII 4
+#define PHY_MODE_TBI   5
+#define PHY_MODE_GMII  6
+#define PHY_MODE_RTBI  7
+#define PHY_MODE_SGMII 8
+
 #ifdef CONFIG_40x
 /*
  * Helper function to copy MAC addresses from the bd_t to OCP EMAC
@@ -133,6 +149,7 @@ struct ocp_func_mal_data {
        int     txde_irq;       /* TX Descriptor Error IRQ */
        int     rxde_irq;       /* RX Descriptor Error IRQ */
        int     serr_irq;       /* MAL System Error IRQ    */
+       int     dcr_base;       /* MALx_CFG DCR number   */
 };
 
 #define OCP_SYSFS_MAL_DATA()                                           \
@@ -143,6 +160,7 @@ OCP_SYSFS_ADDTL(struct ocp_func_mal_data, "%d\n", mal, rxeob_irq)   \
 OCP_SYSFS_ADDTL(struct ocp_func_mal_data, "%d\n", mal, txde_irq)       \
 OCP_SYSFS_ADDTL(struct ocp_func_mal_data, "%d\n", mal, rxde_irq)       \
 OCP_SYSFS_ADDTL(struct ocp_func_mal_data, "%d\n", mal, serr_irq)       \
+OCP_SYSFS_ADDTL(struct ocp_func_mal_data, "%d\n", mal, dcr_base)       \
                                                                        \
 void ocp_show_mal_data(struct device *dev)                             \
 {                                                                      \
@@ -153,6 +171,7 @@ void ocp_show_mal_data(struct device *dev)                          \
        device_create_file(dev, &dev_attr_mal_txde_irq);                \
        device_create_file(dev, &dev_attr_mal_rxde_irq);                \
        device_create_file(dev, &dev_attr_mal_serr_irq);                \
+       device_create_file(dev, &dev_attr_mal_dcr_base);                \
 }
 
 /*
index a9b33324f56299dfb49704ec5789e2cfd29df686..b4b270457eddce51eac0e30a6e604fb82630740e 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
+
 #if defined(CONFIG_40x)
 #include <asm/ibm4xx.h>
 
@@ -337,6 +342,7 @@ static __inline__ int irq_canonicalize(int irq)
 #define        SIU_INT_IDMA3           ((uint)0x08 + CPM_IRQ_OFFSET)
 #define        SIU_INT_IDMA4           ((uint)0x09 + CPM_IRQ_OFFSET)
 #define        SIU_INT_SDMA            ((uint)0x0a + CPM_IRQ_OFFSET)
+#define        SIU_INT_USB             ((uint)0x0b + CPM_IRQ_OFFSET)
 #define        SIU_INT_TIMER1          ((uint)0x0c + CPM_IRQ_OFFSET)
 #define        SIU_INT_TIMER2          ((uint)0x0d + CPM_IRQ_OFFSET)
 #define        SIU_INT_TIMER3          ((uint)0x0e + CPM_IRQ_OFFSET)
index 2589f182a6addff090f648c89e603a93c7c32be5..6d6fc78731e54627235cee4e4a846bd4bc80a3b0 100644 (file)
@@ -17,6 +17,7 @@ enum km_type {
        KM_SOFTIRQ0,
        KM_SOFTIRQ1,
        KM_PPC_SYNC_PAGE,
+       KM_PPC_SYNC_ICACHE,
        KM_TYPE_NR
 };
 
diff --git a/include/asm-ppc/local.h b/include/asm-ppc/local.h
deleted file mode 100644 (file)
index b08e3ec..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __PPC_LOCAL_H
-#define __PPC_LOCAL_H
-
-#include <asm-generic/local.h>
-
-#endif /* __PPC_LOCAL_H */
diff --git a/include/asm-ppc/mc146818rtc.h b/include/asm-ppc/mc146818rtc.h
deleted file mode 100644 (file)
index 227018b..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Machine dependent access functions for RTC registers.
- */
-#ifdef __KERNEL__
-#ifndef __ASM_PPC_MC146818RTC_H
-#define __ASM_PPC_MC146818RTC_H
-
-#include <asm/io.h>
-
-#ifndef RTC_PORT
-#define RTC_PORT(x)    (0x70 + (x))
-#define RTC_ALWAYS_BCD 1       /* RTC operates in binary mode */
-#endif
-
-/*
- * The yet supported machines all access the RTC index register via
- * an ISA port access but the way to access the date register differs ...
- */
-#define CMOS_READ(addr) ({ \
-outb_p((addr),RTC_PORT(0)); \
-inb_p(RTC_PORT(1)); \
-})
-#define CMOS_WRITE(val, addr) ({ \
-outb_p((addr),RTC_PORT(0)); \
-outb_p((val),RTC_PORT(1)); \
-})
-
-#define RTC_IRQ 8
-
-#endif /* __ASM_PPC_MC146818RTC_H */
-#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/mman.h b/include/asm-ppc/mman.h
deleted file mode 100644 (file)
index 5fd19fd..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef __PPC_MMAN_H__
-#define __PPC_MMAN_H__
-
-#define PROT_READ      0x1             /* page can be read */
-#define PROT_WRITE     0x2             /* page can be written */
-#define PROT_EXEC      0x4             /* page can be executed */
-#define PROT_SEM       0x8             /* page may be used for atomic ops */
-#define PROT_NONE      0x0             /* page can not be accessed */
-#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
-#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
-
-#define MAP_SHARED     0x01            /* Share changes */
-#define MAP_PRIVATE    0x02            /* Changes are private */
-#define MAP_TYPE       0x0f            /* Mask for type of mapping */
-#define MAP_FIXED      0x10            /* Interpret addr exactly */
-#define MAP_ANONYMOUS  0x20            /* don't use a file */
-#define MAP_RENAME      MAP_ANONYMOUS   /* In SunOS terminology */
-#define MAP_NORESERVE   0x40            /* don't reserve swap pages */
-#define MAP_LOCKED     0x80
-
-#define MAP_GROWSDOWN  0x0100          /* stack-like segment */
-#define MAP_DENYWRITE  0x0800          /* ETXTBSY */
-#define MAP_EXECUTABLE 0x1000          /* mark it as an executable */
-#define MAP_POPULATE   0x8000          /* populate (prefault) pagetables */
-#define MAP_NONBLOCK   0x10000         /* do not block on IO */
-
-#define MS_ASYNC       1               /* sync memory asynchronously */
-#define MS_INVALIDATE  2               /* invalidate the caches */
-#define MS_SYNC                4               /* synchronous memory sync */
-
-#define MCL_CURRENT     0x2000          /* lock all currently mapped pages */
-#define MCL_FUTURE      0x4000          /* lock all additions to address space */
-
-#define MADV_NORMAL    0x0             /* default page-in behavior */
-#define MADV_RANDOM    0x1             /* page-in minimum required */
-#define MADV_SEQUENTIAL        0x2             /* read-ahead aggressively */
-#define MADV_WILLNEED  0x3             /* pre-fault pages */
-#define MADV_DONTNEED  0x4             /* discard these pages */
-
-/* compatibility flags */
-#define MAP_ANON       MAP_ANONYMOUS
-#define MAP_FILE       0
-
-#endif /* __PPC_MMAN_H__ */
diff --git a/include/asm-ppc/module.h b/include/asm-ppc/module.h
deleted file mode 100644 (file)
index fb63492..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _ASM_PPC_MODULE_H
-#define _ASM_PPC_MODULE_H
-/* Module stuff for PPC.  (C) 2001 Rusty Russell */
-
-#include <linux/list.h>
-#include <asm/bug.h>
-
-/* Thanks to Paul M for explaining this.
-
-   PPC can only do rel jumps += 32MB, and often the kernel and other
-   modules are furthur away than this.  So, we jump to a table of
-   trampolines attached to the module (the Procedure Linkage Table)
-   whenever that happens.
-*/
-
-struct ppc_plt_entry
-{
-       /* 16 byte jump instruction sequence (4 instructions) */
-       unsigned int jump[4];
-};
-
-struct mod_arch_specific
-{
-       /* Indices of PLT sections within module. */
-       unsigned int core_plt_section, init_plt_section;
-
-       /* List of BUG addresses, source line numbers and filenames */
-       struct list_head bug_list;
-       struct bug_entry *bug_table;
-       unsigned int num_bugs;
-};
-
-extern struct bug_entry *module_find_bug(unsigned long bugaddr);
-
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
-
-/* Make empty sections for module_frob_arch_sections to expand. */
-#ifdef MODULE
-asm(".section .plt,\"ax\",@nobits; .align 3; .previous");
-asm(".section .init.plt,\"ax\",@nobits; .align 3; .previous");
-#endif
-#endif /* _ASM_PPC_MODULE_H */
index 89eb8a2ac6934552eeaf74d5ed222690ed504732..9694eca16e92a89ba86391e6a708f2e636dbd9e7 100644 (file)
 #define IO_VIRT_ADDR   IO_PHYS_ADDR
 #endif
 
+enum ppc_sys_devices {
+       MPC82xx_CPM_FCC1,
+       MPC82xx_CPM_FCC2,
+       MPC82xx_CPM_FCC3,
+       MPC82xx_CPM_I2C,
+       MPC82xx_CPM_SCC1,
+       MPC82xx_CPM_SCC2,
+       MPC82xx_CPM_SCC3,
+       MPC82xx_CPM_SCC4,
+       MPC82xx_CPM_SPI,
+       MPC82xx_CPM_MCC1,
+       MPC82xx_CPM_MCC2,
+       MPC82xx_CPM_SMC1,
+       MPC82xx_CPM_SMC2,
+       MPC82xx_CPM_USB,
+       MPC82xx_SEC1,
+};
+
 #ifndef __ASSEMBLY__
 /* The "residual" data board information structure the boot loader
  * hands to us.
index 7c31f2d564a16bb4dd961ff93e4881711719fa51..dc8e59896050150b7b488708517aca0209ec7dd4 100644 (file)
 #include <platforms/tqm8xx.h>
 #endif
 
-#if defined(CONFIG_SPD823TS)
-#include <platforms/spd8xx.h>
-#endif
-
 #if defined(CONFIG_IVMS8) || defined(CONFIG_IVML24)
 #include <platforms/ivms8.h>
 #endif
index cc25b921ad4fa643ccf62c7e88a4e2ab36342a3a..835930d6faa1bf54c2a4c71d5138a03730610183 100644 (file)
@@ -278,6 +278,13 @@ mv64x60_modify(struct mv64x60_handle *bh, u32 offs, u32 data, u32 mask)
 #define        mv64x60_set_bits(bh, offs, bits) mv64x60_modify(bh, offs, ~0, bits)
 #define        mv64x60_clr_bits(bh, offs, bits) mv64x60_modify(bh, offs, 0, bits)
 
+#if defined(CONFIG_SYSFS) && !defined(CONFIG_GT64260)
+#define        MV64XXX_DEV_NAME        "mv64xxx"
+
+struct mv64xxx_pdata {
+       u32     hs_reg_valid;
+};
+#endif
 
 /* Externally visible function prototypes */
 int mv64x60_init(struct mv64x60_handle *bh, struct mv64x60_setup_info *si);
index 2f428746c02ba1cf07964a870d72935753ace5e3..f8f7f16b9b5359293e9c6c7a8152070cd998ffae 100644 (file)
 /*
  *****************************************************************************
  *
- *     SRAM Cotnroller Registers
+ *     SRAM Controller Registers
  *
  *****************************************************************************
  */
 /*
  *****************************************************************************
  *
- *     SDRAM/MEM Cotnroller Registers
+ *     SDRAM/MEM Controller Registers
  *
  *****************************************************************************
  */
 /* SDRAM Control Registers */
 #define MV64360_D_UNIT_CONTROL_LOW             0x1404
 #define MV64360_D_UNIT_CONTROL_HIGH            0x1424
+#define MV64460_D_UNIT_MMASK                   0x14b0
 
 /* SDRAM Error Report Registers (64360) */
 #define        MV64360_SDRAM_ERR_DATA_LO               0x1444
 /*
  *****************************************************************************
  *
- *     Device/BOOT Cotnroller Registers
+ *     Device/BOOT Controller Registers
  *
  *****************************************************************************
  */
 #define        MV64x60_PCI1_SLAVE_P2P_IO_REMAP         0x0dec
 #define        MV64x60_PCI1_SLAVE_CPU_REMAP            0x0df0
 
+#define        MV64360_PCICFG_CPCI_HOTSWAP             0x68
+
 /*
  *****************************************************************************
  *
index b24a4e37196a7d8242bb086061295ce1f7771bc1..6198b1657a455fd30b4ebfe31b6b3382db77953b 100644 (file)
@@ -1,8 +1,10 @@
 #ifndef _ASM_PPC_PARAM_H
 #define _ASM_PPC_PARAM_H
 
+#include <linux/config.h>
+
 #ifdef __KERNEL__
-#define HZ             1000            /* internal timer frequency */
+#define HZ             CONFIG_HZ       /* internal timer frequency */
 #define USER_HZ                100             /* for user interfaces in "ticks" */
 #define CLOCKS_PER_SEC (USER_HZ)       /* frequency at which times() counts */
 #endif /* __KERNEL__ */
diff --git a/include/asm-ppc/percpu.h b/include/asm-ppc/percpu.h
deleted file mode 100644 (file)
index d66667c..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ARCH_PPC_PERCPU__
-#define __ARCH_PPC_PERCPU__
-
-#include <asm-generic/percpu.h>
-
-#endif /* __ARCH_PPC_PERCPU__ */
index 8beb162873f4d07fc331b0319baf649f5c685a36..e9683bcff19bcec68c3b5ab16d9ee50f18299bd4 100644 (file)
@@ -32,6 +32,7 @@
 #define __PPC_ASM_PMAC_FEATURE_H
 
 #include <asm/macio.h>
+#include <asm/machdep.h>
 
 /*
  * Known Mac motherboard models
index 8ea6245662312f644aef30cf26c204e99e4512a2..048f7c8596eefb3e5042db3bfc9449dbac3009f5 100644 (file)
@@ -21,7 +21,9 @@
 #include <linux/device.h>
 #include <linux/types.h>
 
-#if defined(CONFIG_83xx)
+#if defined(CONFIG_8260)
+#include <asm/mpc8260.h>
+#elif defined(CONFIG_83xx)
 #include <asm/mpc83xx.h>
 #elif defined(CONFIG_85xx)
 #include <asm/mpc85xx.h>
@@ -50,6 +52,7 @@ extern struct ppc_sys_spec *cur_ppc_sys_spec;
 /* determine which specific SOC we are */
 extern void identify_ppc_sys_by_id(u32 id) __init;
 extern void identify_ppc_sys_by_name(char *name) __init;
+extern void identify_ppc_sys_by_name_and_id(char *name, u32 id) __init;
 
 /* describes all devices that may exist in a given family of processors */
 extern struct platform_device ppc_sys_platform_devices[];
diff --git a/include/asm-ppc/resource.h b/include/asm-ppc/resource.h
deleted file mode 100644 (file)
index 86a1ea2..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _PPC_RESOURCE_H
-#define _PPC_RESOURCE_H
-
-#include <asm-generic/resource.h>
-
-#endif
diff --git a/include/asm-ppc/sembuf.h b/include/asm-ppc/sembuf.h
deleted file mode 100644 (file)
index 883f682..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _PPC_SEMBUF_H
-#define _PPC_SEMBUF_H
-
-/*
- * The semid64_ds structure for PPC architecture.
- */
-
-struct semid64_ds {
-       struct ipc64_perm sem_perm;             /* permissions .. see ipc.h */
-       unsigned int    __unused1;
-       __kernel_time_t sem_otime;              /* last semop time */
-       unsigned int    __unused2;
-       __kernel_time_t sem_ctime;              /* last change time */
-       unsigned long   sem_nsems;              /* no. of semaphores in array */
-       unsigned long   __unused3;
-       unsigned long   __unused4;
-};
-
-#endif /* _PPC_SEMBUF_H */
index 6d47438be58c25735e7c570bdd525d109efedf6b..485a924e4d06b83b97d97d85c61c80dedc8b1184 100644 (file)
@@ -18,8 +18,6 @@
 #include <platforms/powerpmc250.h>
 #elif defined(CONFIG_LOPEC)
 #include <platforms/lopec.h>
-#elif defined(CONFIG_MCPN765)
-#include <platforms/mcpn765.h>
 #elif defined(CONFIG_MVME5100)
 #include <platforms/mvme5100.h>
 #elif defined(CONFIG_PAL4)
diff --git a/include/asm-ppc/shmbuf.h b/include/asm-ppc/shmbuf.h
deleted file mode 100644 (file)
index 7ac0bd3..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef _PPC_SHMBUF_H
-#define _PPC_SHMBUF_H
-
-/*
- * The shmid64_ds structure for PPC architecture.
- */
-
-struct shmid64_ds {
-       struct ipc64_perm       shm_perm;       /* operation perms */
-       unsigned int            __unused1;
-       __kernel_time_t         shm_atime;      /* last attach time */
-       unsigned int            __unused2;
-       __kernel_time_t         shm_dtime;      /* last detach time */
-       unsigned int            __unused3;
-       __kernel_time_t         shm_ctime;      /* last change time */
-       unsigned int            __unused4;
-       size_t                  shm_segsz;      /* size of segment (bytes) */
-       __kernel_pid_t          shm_cpid;       /* pid of creator */
-       __kernel_pid_t          shm_lpid;       /* pid of last operator */
-       unsigned long           shm_nattch;     /* no. of current attaches */
-       unsigned long           __unused5;
-       unsigned long           __unused6;
-};
-
-struct shminfo64 {
-       unsigned long   shmmax;
-       unsigned long   shmmin;
-       unsigned long   shmmni;
-       unsigned long   shmseg;
-       unsigned long   shmall;
-       unsigned long   __unused1;
-       unsigned long   __unused2;
-       unsigned long   __unused3;
-       unsigned long   __unused4;
-};
-
-#endif /* _PPC_SHMBUF_H */
diff --git a/include/asm-ppc/siginfo.h b/include/asm-ppc/siginfo.h
deleted file mode 100644 (file)
index 4b9435b..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _PPC_SIGINFO_H
-#define _PPC_SIGINFO_H
-
-#include <asm-generic/siginfo.h>
-
-#endif
diff --git a/include/asm-ppc/socket.h b/include/asm-ppc/socket.h
deleted file mode 100644 (file)
index 4134376..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef _ASM_SOCKET_H
-#define _ASM_SOCKET_H
-
-/* Socket-level I/O control calls. */
-#define FIOSETOWN      0x8901
-#define SIOCSPGRP      0x8902
-#define FIOGETOWN      0x8903
-#define SIOCGPGRP      0x8904
-#define SIOCATMARK     0x8905
-#define SIOCGSTAMP     0x8906          /* Get stamp */
-
-/* For setsockopt(2) */
-#define SOL_SOCKET     1
-
-#define SO_DEBUG       1
-#define SO_REUSEADDR   2
-#define SO_TYPE                3
-#define SO_ERROR       4
-#define SO_DONTROUTE   5
-#define SO_BROADCAST   6
-#define SO_SNDBUF      7
-#define SO_RCVBUF      8
-#define SO_KEEPALIVE   9
-#define SO_OOBINLINE   10
-#define SO_NO_CHECK    11
-#define SO_PRIORITY    12
-#define SO_LINGER      13
-#define SO_BSDCOMPAT   14
-/* To add :#define SO_REUSEPORT 15 */
-#define SO_RCVLOWAT    16
-#define SO_SNDLOWAT    17
-#define SO_RCVTIMEO    18
-#define SO_SNDTIMEO    19
-#define SO_PASSCRED    20
-#define SO_PEERCRED    21
-
-/* Security levels - as per NRL IPv6 - don't actually do anything */
-#define SO_SECURITY_AUTHENTICATION             22
-#define SO_SECURITY_ENCRYPTION_TRANSPORT       23
-#define SO_SECURITY_ENCRYPTION_NETWORK         24
-
-#define SO_BINDTODEVICE        25
-
-/* Socket filtering */
-#define SO_ATTACH_FILTER       26
-#define SO_DETACH_FILTER       27
-
-#define SO_PEERNAME            28
-#define SO_TIMESTAMP           29
-#define SCM_TIMESTAMP          SO_TIMESTAMP
-
-#define SO_ACCEPTCONN          30
-
-#define SO_PEERSEC             31
-
-#endif /* _ASM_SOCKET_H */
diff --git a/include/asm-ppc/sockios.h b/include/asm-ppc/sockios.h
deleted file mode 100644 (file)
index 385aedc..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _ASM_PPC_SOCKIOS_H
-#define _ASM_PPC_SOCKIOS_H
-
-#if 0 /* These are defined this way on Alpha - maybe later. */
-/* Socket-level I/O control calls. */
-
-#define FIOGETOWN      _IOR('f', 123, int)
-#define FIOSETOWN      _IOW('f', 124, int)
-
-#define SIOCATMARK     _IOR('s', 7, int)
-#define SIOCSPGRP      _IOW('s', 8, pid_t)
-#define SIOCGPGRP      _IOR('s', 9, pid_t)
-
-#define SIOCGSTAMP     0x8906          /* Get stamp - linux-specific */
-#endif
-
-#endif /* _ASM_PPC_SOCKIOS_H */
index 82395f30004b7ba30cdec4d4e82c05c8ab9272a9..513a334c581032ec21ddc33819d7e25dad5b4bd0 100644 (file)
@@ -84,9 +84,14 @@ extern void cvt_fd(float *from, double *to, unsigned long *fpscr);
 extern void cvt_df(double *from, float *to, unsigned long *fpscr);
 extern int call_rtas(const char *, int, int, unsigned long *, ...);
 extern void cacheable_memzero(void *p, unsigned int nb);
+extern void *cacheable_memcpy(void *, const void *, unsigned int);
 extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long);
 extern void bad_page_fault(struct pt_regs *, unsigned long, int);
 extern void die(const char *, struct pt_regs *, long);
+#ifdef CONFIG_BOOKE_WDT
+extern u32 booke_wdt_enabled;
+extern u32 booke_wdt_period;
+#endif /* CONFIG_BOOKE_WDT */
 
 struct device_node;
 extern void note_scsi_host(struct device_node *, void *);
diff --git a/include/asm-ppc/termbits.h b/include/asm-ppc/termbits.h
deleted file mode 100644 (file)
index c343fb7..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-#ifndef _PPC_TERMBITS_H
-#define _PPC_TERMBITS_H
-
-typedef unsigned char  cc_t;
-typedef unsigned int   speed_t;
-typedef unsigned int   tcflag_t;
-
-/*
- * termios type and macro definitions.  Be careful about adding stuff
- * to this file since it's used in GNU libc and there are strict rules
- * concerning namespace pollution.
- */
-
-#define NCCS 19
-struct termios {
-       tcflag_t c_iflag;               /* input mode flags */
-       tcflag_t c_oflag;               /* output mode flags */
-       tcflag_t c_cflag;               /* control mode flags */
-       tcflag_t c_lflag;               /* local mode flags */
-       cc_t c_cc[NCCS];                /* control characters */
-       cc_t c_line;                    /* line discipline (== c_cc[19]) */
-       speed_t c_ispeed;               /* input speed */
-       speed_t c_ospeed;               /* output speed */
-};
-
-/* c_cc characters */
-#define VINTR  0
-#define VQUIT  1
-#define VERASE         2
-#define VKILL  3
-#define VEOF   4
-#define VMIN   5
-#define VEOL   6
-#define VTIME  7
-#define VEOL2  8
-#define VSWTC  9
-
-#define VWERASE        10
-#define VREPRINT       11
-#define VSUSP          12
-#define VSTART         13
-#define VSTOP          14
-#define VLNEXT         15
-#define VDISCARD       16
-
-/* c_iflag bits */
-#define IGNBRK 0000001
-#define BRKINT 0000002
-#define IGNPAR 0000004
-#define PARMRK 0000010
-#define INPCK  0000020
-#define ISTRIP 0000040
-#define INLCR  0000100
-#define IGNCR  0000200
-#define ICRNL  0000400
-#define IXON   0001000
-#define IXOFF  0002000
-#define IXANY          0004000
-#define IUCLC          0010000
-#define IMAXBEL        0020000
-#define IUTF8  0040000
-
-/* c_oflag bits */
-#define OPOST  0000001
-#define ONLCR  0000002
-#define OLCUC  0000004
-
-#define OCRNL  0000010
-#define ONOCR  0000020
-#define ONLRET 0000040
-
-#define OFILL  00000100
-#define OFDEL  00000200
-#define NLDLY  00001400
-#define   NL0  00000000
-#define   NL1  00000400
-#define   NL2  00001000
-#define   NL3  00001400
-#define TABDLY 00006000
-#define   TAB0 00000000
-#define   TAB1 00002000
-#define   TAB2 00004000
-#define   TAB3 00006000
-#define   XTABS        00006000        /* required by POSIX to == TAB3 */
-#define CRDLY  00030000
-#define   CR0  00000000
-#define   CR1  00010000
-#define   CR2  00020000
-#define   CR3  00030000
-#define FFDLY  00040000
-#define   FF0  00000000
-#define   FF1  00040000
-#define BSDLY  00100000
-#define   BS0  00000000
-#define   BS1  00100000
-#define VTDLY  00200000
-#define   VT0  00000000
-#define   VT1  00200000
-
-/* c_cflag bit meaning */
-#define CBAUD  0000377
-#define  B0    0000000         /* hang up */
-#define  B50   0000001
-#define  B75   0000002
-#define  B110  0000003
-#define  B134  0000004
-#define  B150  0000005
-#define  B200  0000006
-#define  B300  0000007
-#define  B600  0000010
-#define  B1200 0000011
-#define  B1800 0000012
-#define  B2400 0000013
-#define  B4800 0000014
-#define  B9600 0000015
-#define  B19200        0000016
-#define  B38400        0000017
-#define EXTA B19200
-#define EXTB B38400
-#define CBAUDEX 0000000
-#define  B57600   00020
-#define  B115200  00021
-#define  B230400  00022
-#define  B460800  00023
-#define  B500000  00024
-#define  B576000  00025
-#define  B921600  00026
-#define B1000000  00027
-#define B1152000  00030
-#define B1500000  00031
-#define B2000000  00032
-#define B2500000  00033
-#define B3000000  00034
-#define B3500000  00035
-#define B4000000  00036
-
-#define CSIZE  00001400
-#define   CS5  00000000
-#define   CS6  00000400
-#define   CS7  00001000
-#define   CS8  00001400
-
-#define CSTOPB 00002000
-#define CREAD  00004000
-#define PARENB 00010000
-#define PARODD 00020000
-#define HUPCL  00040000
-
-#define CLOCAL 00100000
-#define CRTSCTS          020000000000          /* flow control */
-
-/* c_lflag bits */
-#define ISIG   0x00000080
-#define ICANON 0x00000100
-#define XCASE  0x00004000
-#define ECHO   0x00000008
-#define ECHOE  0x00000002
-#define ECHOK  0x00000004
-#define ECHONL 0x00000010
-#define NOFLSH 0x80000000
-#define TOSTOP 0x00400000
-#define ECHOCTL        0x00000040
-#define ECHOPRT        0x00000020
-#define ECHOKE 0x00000001
-#define FLUSHO 0x00800000
-#define PENDIN 0x20000000
-#define IEXTEN 0x00000400
-
-/* Values for the ACTION argument to `tcflow'.  */
-#define        TCOOFF          0
-#define        TCOON           1
-#define        TCIOFF          2
-#define        TCION           3
-
-/* Values for the QUEUE_SELECTOR argument to `tcflush'.  */
-#define        TCIFLUSH        0
-#define        TCOFLUSH        1
-#define        TCIOFLUSH       2
-
-/* Values for the OPTIONAL_ACTIONS argument to `tcsetattr'.  */
-#define        TCSANOW         0
-#define        TCSADRAIN       1
-#define        TCSAFLUSH       2
-
-#endif /* _PPC_TERMBITS_H */
diff --git a/include/asm-ppc/termios.h b/include/asm-ppc/termios.h
deleted file mode 100644 (file)
index 97c6287..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-#ifndef _PPC_TERMIOS_H
-#define _PPC_TERMIOS_H
-
-/*
- * Liberally adapted from alpha/termios.h.  In particular, the c_cc[]
- * fields have been reordered so that termio & termios share the
- * common subset in the same order (for brain dead programs that don't
- * know or care about the differences).
- */
-
-#include <asm/ioctls.h>
-#include <asm/termbits.h>
-
-struct sgttyb {
-       char    sg_ispeed;
-       char    sg_ospeed;
-       char    sg_erase;
-       char    sg_kill;
-       short   sg_flags;
-};
-
-struct tchars {
-       char    t_intrc;
-       char    t_quitc;
-       char    t_startc;
-       char    t_stopc;
-       char    t_eofc;
-       char    t_brkc;
-};
-
-struct ltchars {
-       char    t_suspc;
-       char    t_dsuspc;
-       char    t_rprntc;
-       char    t_flushc;
-       char    t_werasc;
-       char    t_lnextc;
-};
-
-#define FIOCLEX                _IO('f', 1)
-#define FIONCLEX       _IO('f', 2)
-#define FIOASYNC       _IOW('f', 125, int)
-#define FIONBIO                _IOW('f', 126, int)
-#define FIONREAD       _IOR('f', 127, int)
-#define TIOCINQ                FIONREAD
-#define FIOQSIZE       _IOR('f', 128, loff_t)
-
-#define TIOCGETP       _IOR('t', 8, struct sgttyb)
-#define TIOCSETP       _IOW('t', 9, struct sgttyb)
-#define TIOCSETN       _IOW('t', 10, struct sgttyb)    /* TIOCSETP wo flush */
-
-#define TIOCSETC       _IOW('t', 17, struct tchars)
-#define TIOCGETC       _IOR('t', 18, struct tchars)
-#define TCGETS         _IOR('t', 19, struct termios)
-#define TCSETS         _IOW('t', 20, struct termios)
-#define TCSETSW                _IOW('t', 21, struct termios)
-#define TCSETSF                _IOW('t', 22, struct termios)
-
-#define TCGETA         _IOR('t', 23, struct termio)
-#define TCSETA         _IOW('t', 24, struct termio)
-#define TCSETAW                _IOW('t', 25, struct termio)
-#define TCSETAF                _IOW('t', 28, struct termio)
-
-#define TCSBRK         _IO('t', 29)
-#define TCXONC         _IO('t', 30)
-#define TCFLSH         _IO('t', 31)
-
-#define TIOCSWINSZ     _IOW('t', 103, struct winsize)
-#define TIOCGWINSZ     _IOR('t', 104, struct winsize)
-#define        TIOCSTART       _IO('t', 110)           /* start output, like ^Q */
-#define        TIOCSTOP        _IO('t', 111)           /* stop output, like ^S */
-#define TIOCOUTQ        _IOR('t', 115, int)     /* output queue size */
-
-#define TIOCGLTC       _IOR('t', 116, struct ltchars)
-#define TIOCSLTC       _IOW('t', 117, struct ltchars)
-#define TIOCSPGRP      _IOW('t', 118, int)
-#define TIOCGPGRP      _IOR('t', 119, int)
-
-#define TIOCEXCL       0x540C
-#define TIOCNXCL       0x540D
-#define TIOCSCTTY      0x540E
-
-#define TIOCSTI                0x5412
-#define TIOCMGET       0x5415
-#define TIOCMBIS       0x5416
-#define TIOCMBIC       0x5417
-#define TIOCMSET       0x5418
-#define TIOCGSOFTCAR   0x5419
-#define TIOCSSOFTCAR   0x541A
-#define TIOCLINUX      0x541C
-#define TIOCCONS       0x541D
-#define TIOCGSERIAL    0x541E
-#define TIOCSSERIAL    0x541F
-#define TIOCPKT                0x5420
-
-#define TIOCNOTTY      0x5422
-#define TIOCSETD       0x5423
-#define TIOCGETD       0x5424
-#define TCSBRKP                0x5425  /* Needed for POSIX tcsendbreak() */
-
-#define TIOCSERCONFIG  0x5453
-#define TIOCSERGWILD   0x5454
-#define TIOCSERSWILD   0x5455
-#define TIOCGLCKTRMIOS 0x5456
-#define TIOCSLCKTRMIOS 0x5457
-#define TIOCSERGSTRUCT 0x5458 /* For debugging only */
-#define TIOCSERGETLSR   0x5459 /* Get line status register */
-#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
-#define TIOCSERSETMULTI 0x545B /* Set multiport config */
-
-#define TIOCMIWAIT     0x545C  /* wait for a change on serial input line(s) */
-#define TIOCGICOUNT    0x545D  /* read serial port inline interrupt counts */
-
-/* Used for packet mode */
-#define TIOCPKT_DATA            0
-#define TIOCPKT_FLUSHREAD       1
-#define TIOCPKT_FLUSHWRITE      2
-#define TIOCPKT_STOP            4
-#define TIOCPKT_START           8
-#define TIOCPKT_NOSTOP         16
-#define TIOCPKT_DOSTOP         32
-
-struct winsize {
-       unsigned short ws_row;
-       unsigned short ws_col;
-       unsigned short ws_xpixel;
-       unsigned short ws_ypixel;
-};
-
-#define NCC 10
-struct termio {
-       unsigned short c_iflag;         /* input mode flags */
-       unsigned short c_oflag;         /* output mode flags */
-       unsigned short c_cflag;         /* control mode flags */
-       unsigned short c_lflag;         /* local mode flags */
-       unsigned char c_line;           /* line discipline */
-       unsigned char c_cc[NCC];        /* control characters */
-};
-
-/* c_cc characters */
-#define _VINTR 0
-#define _VQUIT 1
-#define _VERASE        2
-#define _VKILL 3
-#define _VEOF  4
-#define _VMIN  5
-#define _VEOL  6
-#define _VTIME 7
-#define _VEOL2 8
-#define _VSWTC 9
-
-#ifdef __KERNEL__
-/*                   ^C  ^\ del  ^U  ^D   1   0   0   0   0  ^W  ^R  ^Z  ^Q  ^S  ^V  ^U  */
-#define INIT_C_CC "\003\034\177\025\004\001\000\000\000\000\027\022\032\021\023\026\025"
-#endif /* __KERNEL__ */
-
-/* modem lines */
-#define TIOCM_LE       0x001
-#define TIOCM_DTR      0x002
-#define TIOCM_RTS      0x004
-#define TIOCM_ST       0x008
-#define TIOCM_SR       0x010
-#define TIOCM_CTS      0x020
-#define TIOCM_CAR      0x040
-#define TIOCM_RNG      0x080
-#define TIOCM_DSR      0x100
-#define TIOCM_CD       TIOCM_CAR
-#define TIOCM_RI       TIOCM_RNG
-#define TIOCM_OUT1     0x2000
-#define TIOCM_OUT2     0x4000
-#define TIOCM_LOOP     0x8000
-
-/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
-#define TIOCSER_TEMT    0x01   /* Transmitter physically empty */
-
-/* line disciplines */
-#define N_TTY          0
-#define N_SLIP         1
-#define N_MOUSE                2
-#define N_PPP          3
-#define N_STRIP                4
-#define N_AX25         5
-#define N_X25          6       /* X.25 async */
-#define N_6PACK                7
-#define N_MASC         8       /* Reserved for Mobitex module <kaz@cafe.net> */
-#define N_R3964                9       /* Reserved for Simatic R3964 module */
-#define N_PROFIBUS_FDL 10      /* Reserved for Profibus <Dave@mvhi.com> */
-#define N_IRDA         11      /* Linux IrDa - http://irda.sourceforge.net/ */
-#define N_SMSBLOCK     12      /* SMS block mode - for talking to GSM data cards about SMS messages */
-#define N_HDLC         13      /* synchronous HDLC */
-#define N_SYNC_PPP     14
-#define N_HCI          15  /* Bluetooth HCI UART */
-
-#ifdef __KERNEL__
-
-/*
- * Translate a "termio" structure into a "termios". Ugh.
- */
-#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \
-       unsigned short __tmp; \
-       get_user(__tmp,&(termio)->x); \
-       (termios)->x = (0xffff0000 & (termios)->x) | __tmp; \
-}
-
-#define user_termio_to_kernel_termios(termios, termio) \
-({ \
-       SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \
-       SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \
-       SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \
-       SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \
-       copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
-})
-
-/*
- * Translate a "termios" structure into a "termio". Ugh.
- */
-#define kernel_termios_to_user_termio(termio, termios) \
-({ \
-       put_user((termios)->c_iflag, &(termio)->c_iflag); \
-       put_user((termios)->c_oflag, &(termio)->c_oflag); \
-       put_user((termios)->c_cflag, &(termio)->c_cflag); \
-       put_user((termios)->c_lflag, &(termio)->c_lflag); \
-       put_user((termios)->c_line,  &(termio)->c_line); \
-       copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
-})
-
-#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
-#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
-
-#endif /* __KERNEL__ */
-
-#endif /* _PPC_TERMIOS_H */
index a787bc0325879dbc6e1bf649fbb6ec8b4867aeea..77dc24d7d2ad1910151cb23d48279e7ef3a6abd0 100644 (file)
@@ -62,8 +62,6 @@ typedef u64 sector_t;
 #define HAVE_SECTOR_T
 #endif
 
-typedef unsigned int kmem_bufctl_t;
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index b044ae03ac5638b01dff66e5bd150b404effe07e..63f56224da8ca3b69361b9f6801a81a80d12c6e3 100644 (file)
 #define access_ok(type, addr, size) \
        (__chk_user_ptr(addr),__access_ok((unsigned long)(addr),(size)))
 
-/* this function will go away soon - use access_ok() instead */
-extern inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
-{
-       return access_ok(type, addr, size) ? 0 : -EFAULT;
-}
-
-
 /*
  * The exception table consists of pairs of addresses: the first is the
  * address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-ppc64/8253pit.h b/include/asm-ppc64/8253pit.h
deleted file mode 100644 (file)
index 285f784..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * 8253/8254 Programmable Interval Timer
- */
-
-#ifndef _8253PIT_H
-#define _8253PIT_H
-
-#define PIT_TICK_RATE  1193182UL
-
-#endif
index 6d4e8e787058e8253a66ee5265270abcd5b92740..84c24d4cdb71a1e5234a3abec11308468b96528f 100644 (file)
 #include <asm/page.h>
 #include <asm/prom.h>
 #include <asm/lmb.h>
+#include <asm/firmware.h>
 
-typedef u32 msChunks_entry;
-struct msChunks {
+struct mschunks_map {
         unsigned long num_chunks;
         unsigned long chunk_size;
         unsigned long chunk_shift;
         unsigned long chunk_mask;
-        msChunks_entry *abs;
+        u32 *mapping;
 };
 
-extern struct msChunks msChunks;
+extern struct mschunks_map mschunks_map;
 
-extern unsigned long msChunks_alloc(unsigned long, unsigned long, unsigned long);
-extern unsigned long reloc_offset(void);
+/* Chunks are 256 KB */
+#define MSCHUNKS_CHUNK_SHIFT   (18)
+#define MSCHUNKS_CHUNK_SIZE    (1UL << MSCHUNKS_CHUNK_SHIFT)
+#define MSCHUNKS_OFFSET_MASK   (MSCHUNKS_CHUNK_SIZE - 1)
 
-#ifdef CONFIG_MSCHUNKS
-
-static inline unsigned long
-chunk_to_addr(unsigned long chunk)
+static inline unsigned long chunk_to_addr(unsigned long chunk)
 {
-       unsigned long offset = reloc_offset();
-       struct msChunks *_msChunks = PTRRELOC(&msChunks);
-
-       return chunk << _msChunks->chunk_shift;
+       return chunk << MSCHUNKS_CHUNK_SHIFT;
 }
 
-static inline unsigned long
-addr_to_chunk(unsigned long addr)
+static inline unsigned long addr_to_chunk(unsigned long addr)
 {
-       unsigned long offset = reloc_offset();
-       struct msChunks *_msChunks = PTRRELOC(&msChunks);
-
-       return addr >> _msChunks->chunk_shift;
+       return addr >> MSCHUNKS_CHUNK_SHIFT;
 }
 
-static inline unsigned long
-chunk_offset(unsigned long addr)
+static inline unsigned long phys_to_abs(unsigned long pa)
 {
-       unsigned long offset = reloc_offset();
-       struct msChunks *_msChunks = PTRRELOC(&msChunks);
+       unsigned long chunk;
 
-       return addr & _msChunks->chunk_mask;
-}
+       /* This is a no-op on non-iSeries */
+       if (!firmware_has_feature(FW_FEATURE_ISERIES))
+               return pa;
 
-static inline unsigned long
-abs_chunk(unsigned long pchunk)
-{
-       unsigned long offset = reloc_offset();
-       struct msChunks *_msChunks = PTRRELOC(&msChunks);
-       if ( pchunk >= _msChunks->num_chunks ) {
-               return pchunk;
-       }
-       return PTRRELOC(_msChunks->abs)[pchunk];
-}
+       chunk = addr_to_chunk(pa);
 
-/* A macro so it can take pointers or unsigned long. */
-#define phys_to_abs(pa)                                                     \
-       ({ unsigned long _pa = (unsigned long)(pa);                          \
-          chunk_to_addr(abs_chunk(addr_to_chunk(_pa))) + chunk_offset(_pa); \
-       })
+       if (chunk < mschunks_map.num_chunks)
+               chunk = mschunks_map.mapping[chunk];
 
-static inline unsigned long
-physRpn_to_absRpn(unsigned long rpn)
-{
-       unsigned long pa = rpn << PAGE_SHIFT;
-       unsigned long aa = phys_to_abs(pa);
-       return (aa >> PAGE_SHIFT);
+       return chunk_to_addr(chunk) + (pa & MSCHUNKS_OFFSET_MASK);
 }
 
-/* A macro so it can take pointers or unsigned long. */
-#define abs_to_phys(aa) lmb_abs_to_phys((unsigned long)(aa))
-
-#else  /* !CONFIG_MSCHUNKS */
-
-#define chunk_to_addr(chunk) ((unsigned long)(chunk))
-#define addr_to_chunk(addr) (addr)
-#define chunk_offset(addr) (0)
-#define abs_chunk(pchunk) (pchunk)
-
-#define phys_to_abs(pa) (pa)
-#define physRpn_to_absRpn(rpn) (rpn)
-#define abs_to_phys(aa) (aa)
-
-#endif /* !CONFIG_MSCHUNKS */
-
 /* Convenience macros */
 #define virt_to_abs(va) phys_to_abs(__pa(va))
-#define abs_to_virt(aa) __va(abs_to_phys(aa))
+#define abs_to_virt(aa) __va(aa)
 
 #endif /* _ABS_ADDR_H */
diff --git a/include/asm-ppc64/agp.h b/include/asm-ppc64/agp.h
deleted file mode 100644 (file)
index ca9e423..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef AGP_H
-#define AGP_H 1
-
-#include <asm/io.h>
-
-/* nothing much needed here */
-
-#define map_page_into_agp(page)
-#define unmap_page_from_agp(page)
-#define flush_agp_mappings()
-#define flush_agp_cache() mb()
-
-/* Convert a physical address to an address suitable for the GART. */
-#define phys_to_gart(x) (x)
-#define gart_to_phys(x) (x)
-
-/* GATT allocation. Returns/accepts GATT kernel virtual address. */
-#define alloc_gatt_pages(order)                \
-       ((char *)__get_free_pages(GFP_KERNEL, (order)))
-#define free_gatt_pages(table, order)  \
-       free_pages((unsigned long)(table), (order))
-
-#endif
diff --git a/include/asm-ppc64/auxvec.h b/include/asm-ppc64/auxvec.h
new file mode 100644 (file)
index 0000000..ac6381a
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __PPC64_AUXVEC_H
+#define __PPC64_AUXVEC_H
+
+/*
+ * We need to put in some extra aux table entries to tell glibc what
+ * the cache block size is, so it can use the dcbz instruction safely.
+ */
+#define AT_DCACHEBSIZE         19
+#define AT_ICACHEBSIZE         20
+#define AT_UCACHEBSIZE         21
+/* A special ignored type value for PPC, for glibc compatibility.  */
+#define AT_IGNOREPPC           22
+
+/* The vDSO location. We have to use the same value as x86 for glibc's
+ * sake :-)
+ */
+#define AT_SYSINFO_EHDR                33
+
+#endif /* __PPC64_AUXVEC_H */
diff --git a/include/asm-ppc64/bugs.h b/include/asm-ppc64/bugs.h
deleted file mode 100644 (file)
index 861074b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * This file is included by 'init/main.c' to check for architecture-dependent
- * bugs.
- *
- */
-#ifndef _ASM_PPC64_BUGS_H
-#define _ASM_PPC64_BUGS_H
-
-static void check_bugs(void) {
-}
-
-#endif /* _ASM_PPC64_BUGS_H */
index 12414f5fc666b00a13c433aa42326127e93c168b..6ec62cd2d1d1e24f8559b8cf65316d929a45474d 100644 (file)
@@ -13,8 +13,10 @@ typedef s32          compat_ssize_t;
 typedef s32            compat_time_t;
 typedef s32            compat_clock_t;
 typedef s32            compat_pid_t;
-typedef u32            compat_uid_t;
-typedef u32            compat_gid_t;
+typedef u32            __compat_uid_t;
+typedef u32            __compat_gid_t;
+typedef u32            __compat_uid32_t;
+typedef u32            __compat_gid32_t;
 typedef u32            compat_mode_t;
 typedef u32            compat_ino_t;
 typedef u32            compat_dev_t;
@@ -48,8 +50,8 @@ struct compat_stat {
        compat_ino_t    st_ino;
        compat_mode_t   st_mode;
        compat_nlink_t  st_nlink;       
-       compat_uid_t    st_uid;
-       compat_gid_t    st_gid;
+       __compat_uid32_t        st_uid;
+       __compat_gid32_t        st_gid;
        compat_dev_t    st_rdev;
        compat_off_t    st_size;
        compat_off_t    st_blksize;
@@ -144,10 +146,10 @@ static inline void __user *compat_alloc_user_space(long len)
  */
 struct compat_ipc64_perm {
        compat_key_t key;
-       compat_uid_t uid;
-       compat_gid_t gid;
-       compat_uid_t cuid;
-       compat_gid_t cgid;
+       __compat_uid_t uid;
+       __compat_gid_t gid;
+       __compat_uid_t cuid;
+       __compat_gid_t cgid;
        compat_mode_t mode;
        unsigned int seq;
        unsigned int __pad2;
index d67fa9e2607908477b8517df6a5ffe8bb9934337..acc9b4d6c16846a46d7f0f8120d36819c911e60e 100644 (file)
@@ -36,6 +36,7 @@
  * via the mkdefs mechanism.
  */
 struct cpu_spec;
+struct op_ppc64_model;
 
 typedef        void (*cpu_setup_t)(unsigned long offset, struct cpu_spec* spec);
 
@@ -52,15 +53,19 @@ struct cpu_spec {
        unsigned int    icache_bsize;
        unsigned int    dcache_bsize;
 
+       /* number of performance monitor counters */
+       unsigned int    num_pmcs;
+
        /* this is called to initialize various CPU bits like L1 cache,
         * BHT, SPD, etc... from head.S before branching to identify_machine
         */
        cpu_setup_t     cpu_setup;
 
-       /* This is used to identify firmware features which are available
-        * to the kernel.
-        */
-       unsigned long   firmware_features;
+       /* Used by oprofile userspace to select the right counters */
+       char            *oprofile_cpu_type;
+
+       /* Processor specific oprofile operations */
+       struct op_ppc64_model *oprofile_model;
 };
 
 extern struct cpu_spec         cpu_specs[];
@@ -71,39 +76,6 @@ static inline unsigned long cpu_has_feature(unsigned long feature)
        return cur_cpu_spec->cpu_features & feature;
 }
 
-
-/* firmware feature bitmask values */
-#define FIRMWARE_MAX_FEATURES 63
-
-#define FW_FEATURE_PFT         (1UL<<0)
-#define FW_FEATURE_TCE         (1UL<<1)        
-#define FW_FEATURE_SPRG0       (1UL<<2)        
-#define FW_FEATURE_DABR                (1UL<<3)        
-#define FW_FEATURE_COPY                (1UL<<4)        
-#define FW_FEATURE_ASR         (1UL<<5)        
-#define FW_FEATURE_DEBUG       (1UL<<6)        
-#define FW_FEATURE_TERM                (1UL<<7)        
-#define FW_FEATURE_PERF                (1UL<<8)        
-#define FW_FEATURE_DUMP                (1UL<<9)        
-#define FW_FEATURE_INTERRUPT   (1UL<<10)       
-#define FW_FEATURE_MIGRATE     (1UL<<11)       
-#define FW_FEATURE_PERFMON     (1UL<<12)       
-#define FW_FEATURE_CRQ         (1UL<<13)       
-#define FW_FEATURE_VIO         (1UL<<14)       
-#define FW_FEATURE_RDMA        (1UL<<15)       
-#define FW_FEATURE_LLAN        (1UL<<16)       
-#define FW_FEATURE_BULK        (1UL<<17)       
-#define FW_FEATURE_XDABR       (1UL<<18)       
-#define FW_FEATURE_MULTITCE    (1UL<<19)       
-#define FW_FEATURE_SPLPAR      (1UL<<20)       
-
-typedef struct {
-    unsigned long val;
-    char * name;
-} firmware_feature_t;
-
-extern firmware_feature_t firmware_features_table[];
-
 #endif /* __ASSEMBLY__ */
 
 /* CPU kernel features */
@@ -133,17 +105,15 @@ extern firmware_feature_t firmware_features_table[];
 #define CPU_FTR_NODSISRALIGN           ASM_CONST(0x0000001000000000)
 #define CPU_FTR_IABR                   ASM_CONST(0x0000002000000000)
 #define CPU_FTR_MMCRA                          ASM_CONST(0x0000004000000000)
-#define CPU_FTR_PMC8                   ASM_CONST(0x0000008000000000)
+/* unused                              ASM_CONST(0x0000008000000000) */
 #define CPU_FTR_SMT                    ASM_CONST(0x0000010000000000)
 #define CPU_FTR_COHERENT_ICACHE        ASM_CONST(0x0000020000000000)
 #define CPU_FTR_LOCKLESS_TLBIE         ASM_CONST(0x0000040000000000)
 #define CPU_FTR_MMCRA_SIHV             ASM_CONST(0x0000080000000000)
 #define CPU_FTR_CTRL                   ASM_CONST(0x0000100000000000)
 
-/* Platform firmware features */
-#define FW_FTR_                                ASM_CONST(0x0000000000000001)
-
 #ifndef __ASSEMBLY__
+
 #define COMMON_USER_PPC64      (PPC_FEATURE_32 | PPC_FEATURE_64 | \
                                 PPC_FEATURE_HAS_FPU | PPC_FEATURE_HAS_MMU)
 
@@ -156,10 +126,9 @@ extern firmware_feature_t firmware_features_table[];
 #define CPU_FTR_PPCAS_ARCH_V2  (CPU_FTR_PPCAS_ARCH_V2_BASE)
 #else
 #define CPU_FTR_PPCAS_ARCH_V2  (CPU_FTR_PPCAS_ARCH_V2_BASE | CPU_FTR_16M_PAGE)
-#endif
+#endif /* CONFIG_PPC_ISERIES */
 
-#define COMMON_PPC64_FW        (0)
-#endif
+#endif /* __ASSEMBLY */
 
 #ifdef __ASSEMBLY__
 
diff --git a/include/asm-ppc64/cputime.h b/include/asm-ppc64/cputime.h
deleted file mode 100644 (file)
index 8e9faf5..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __PPC_CPUTIME_H
-#define __PPC_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __PPC_CPUTIME_H */
diff --git a/include/asm-ppc64/div64.h b/include/asm-ppc64/div64.h
deleted file mode 100644 (file)
index 6cd978c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/div64.h>
index 085eedb956fe02f7a0f34c1cbea0895e476b00ee..c919a89343db0a3b0efb583b63fbf3ebad30ac8b 100644 (file)
@@ -4,6 +4,7 @@
 #include <asm/types.h>
 #include <asm/ptrace.h>
 #include <asm/cputable.h>
+#include <asm/auxvec.h>
 
 /* PowerPC relocations defined by the ABIs */
 #define R_PPC_NONE             0
@@ -237,21 +238,6 @@ do {                                                               \
 
 #endif
 
-/*
- * We need to put in some extra aux table entries to tell glibc what
- * the cache block size is, so it can use the dcbz instruction safely.
- */
-#define AT_DCACHEBSIZE         19
-#define AT_ICACHEBSIZE         20
-#define AT_UCACHEBSIZE         21
-/* A special ignored type value for PPC, for glibc compatibility.  */
-#define AT_IGNOREPPC           22
-
-/* The vDSO location. We have to use the same value as x86 for glibc's
- * sake :-)
- */
-#define AT_SYSINFO_EHDR                33
-
 extern int dcache_bsize;
 extern int icache_bsize;
 extern int ucache_bsize;
diff --git a/include/asm-ppc64/emergency-restart.h b/include/asm-ppc64/emergency-restart.h
deleted file mode 100644 (file)
index 108d8c4..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_EMERGENCY_RESTART_H
-#define _ASM_EMERGENCY_RESTART_H
-
-#include <asm-generic/emergency-restart.h>
-
-#endif /* _ASM_EMERGENCY_RESTART_H */
diff --git a/include/asm-ppc64/errno.h b/include/asm-ppc64/errno.h
deleted file mode 100644 (file)
index 69bc3b0..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef _PPC64_ERRNO_H
-#define _PPC64_ERRNO_H
-
-/* 
- * 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 <asm-generic/errno.h>
-
-#undef EDEADLOCK
-#define        EDEADLOCK       58      /* File locking deadlock error */
-
-#define _LAST_ERRNO    516
-
-#endif
diff --git a/include/asm-ppc64/fcntl.h b/include/asm-ppc64/fcntl.h
deleted file mode 100644 (file)
index 842560d..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef _PPC64_FCNTL_H
-#define _PPC64_FCNTL_H
-
-/*
- * 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.
- */
-
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
-   located on an ext2 file system */
-#define O_ACCMODE         0003
-#define O_RDONLY            00
-#define O_WRONLY            01
-#define O_RDWR              02
-#define O_CREAT                   0100 /* not fcntl */
-#define O_EXCL            0200 /* not fcntl */
-#define O_NOCTTY          0400 /* not fcntl */
-#define O_TRUNC                  01000 /* not fcntl */
-#define O_APPEND         02000
-#define O_NONBLOCK       04000
-#define O_NDELAY       O_NONBLOCK
-#define O_SYNC          010000
-#define FASYNC          020000 /* fcntl, for BSD compatibility */
-#define O_DIRECTORY      040000        /* must be a directory */
-#define O_NOFOLLOW      0100000        /* don't follow links */
-#define O_LARGEFILE     0200000
-#define O_DIRECT       0400000 /* direct disk access hint */
-#define O_NOATIME      01000000
-
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
-#define F_GETLK                5
-#define F_SETLK                6
-#define F_SETLKW       7
-
-#define F_SETOWN       8       /*  for sockets. */
-#define F_GETOWN       9       /*  for sockets. */
-#define F_SETSIG       10      /*  for sockets. */
-#define F_GETSIG       11      /*  for sockets. */
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK                0
-#define F_WRLCK                1
-#define F_UNLCK                2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
-
-#ifdef __KERNEL__
-#define F_POSIX                1
-#define F_FLOCK                2
-#define F_BROKEN       4       /* broken flock() emulation */
-#endif /* __KERNEL__ */
-
-struct flock {
-       short l_type;
-       short l_whence;
-       off_t l_start;
-       off_t l_len;
-       pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE  1024
-
-#endif /* _PPC64_FCNTL_H */
diff --git a/include/asm-ppc64/firmware.h b/include/asm-ppc64/firmware.h
new file mode 100644 (file)
index 0000000..22bb85c
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ *  include/asm-ppc64/firmware.h
+ *
+ *  Extracted from include/asm-ppc64/cputable.h
+ *
+ *  Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
+ *
+ *  Modifications for ppc64:
+ *      Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ */
+#ifndef __ASM_PPC_FIRMWARE_H
+#define __ASM_PPC_FIRMWARE_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+
+/* firmware feature bitmask values */
+#define FIRMWARE_MAX_FEATURES 63
+
+#define FW_FEATURE_PFT         (1UL<<0)
+#define FW_FEATURE_TCE         (1UL<<1)
+#define FW_FEATURE_SPRG0       (1UL<<2)
+#define FW_FEATURE_DABR                (1UL<<3)
+#define FW_FEATURE_COPY                (1UL<<4)
+#define FW_FEATURE_ASR         (1UL<<5)
+#define FW_FEATURE_DEBUG       (1UL<<6)
+#define FW_FEATURE_TERM                (1UL<<7)
+#define FW_FEATURE_PERF                (1UL<<8)
+#define FW_FEATURE_DUMP                (1UL<<9)
+#define FW_FEATURE_INTERRUPT   (1UL<<10)
+#define FW_FEATURE_MIGRATE     (1UL<<11)
+#define FW_FEATURE_PERFMON     (1UL<<12)
+#define FW_FEATURE_CRQ         (1UL<<13)
+#define FW_FEATURE_VIO         (1UL<<14)
+#define FW_FEATURE_RDMA                (1UL<<15)
+#define FW_FEATURE_LLAN                (1UL<<16)
+#define FW_FEATURE_BULK                (1UL<<17)
+#define FW_FEATURE_XDABR       (1UL<<18)
+#define FW_FEATURE_MULTITCE    (1UL<<19)
+#define FW_FEATURE_SPLPAR      (1UL<<20)
+#define FW_FEATURE_ISERIES     (1UL<<21)
+
+enum {
+       FW_FEATURE_PSERIES_POSSIBLE = FW_FEATURE_PFT | FW_FEATURE_TCE |
+               FW_FEATURE_SPRG0 | FW_FEATURE_DABR | FW_FEATURE_COPY |
+               FW_FEATURE_ASR | FW_FEATURE_DEBUG | FW_FEATURE_TERM |
+               FW_FEATURE_PERF | FW_FEATURE_DUMP | FW_FEATURE_INTERRUPT |
+               FW_FEATURE_MIGRATE | FW_FEATURE_PERFMON | FW_FEATURE_CRQ |
+               FW_FEATURE_VIO | FW_FEATURE_RDMA | FW_FEATURE_LLAN |
+               FW_FEATURE_BULK | FW_FEATURE_XDABR | FW_FEATURE_MULTITCE |
+               FW_FEATURE_SPLPAR,
+       FW_FEATURE_PSERIES_ALWAYS = 0,
+       FW_FEATURE_ISERIES_POSSIBLE = FW_FEATURE_ISERIES,
+       FW_FEATURE_ISERIES_ALWAYS = FW_FEATURE_ISERIES,
+       FW_FEATURE_POSSIBLE =
+#ifdef CONFIG_PPC_PSERIES
+               FW_FEATURE_PSERIES_POSSIBLE |
+#endif
+#ifdef CONFIG_PPC_ISERIES
+               FW_FEATURE_ISERIES_POSSIBLE |
+#endif
+               0,
+       FW_FEATURE_ALWAYS =
+#ifdef CONFIG_PPC_PSERIES
+               FW_FEATURE_PSERIES_ALWAYS &
+#endif
+#ifdef CONFIG_PPC_ISERIES
+               FW_FEATURE_ISERIES_ALWAYS &
+#endif
+               FW_FEATURE_POSSIBLE,
+};
+
+/* This is used to identify firmware features which are available
+ * to the kernel.
+ */
+extern unsigned long   ppc64_firmware_features;
+
+static inline unsigned long firmware_has_feature(unsigned long feature)
+{
+       return (FW_FEATURE_ALWAYS & feature) ||
+               (FW_FEATURE_POSSIBLE & ppc64_firmware_features & feature);
+}
+
+#ifdef CONFIG_PPC_PSERIES
+typedef struct {
+    unsigned long val;
+    char * name;
+} firmware_feature_t;
+
+extern firmware_feature_t firmware_features_table[];
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
+#endif /* __ASM_PPC_FIRMWARE_H */
diff --git a/include/asm-ppc64/futex.h b/include/asm-ppc64/futex.h
new file mode 100644 (file)
index 0000000..cb2640b
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/memory.h>
+#include <asm/uaccess.h>
+
+#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
+  __asm__ __volatile (SYNC_ON_SMP                              \
+"1:    lwarx   %0,0,%2\n"                                      \
+       insn                                                    \
+"2:    stwcx.  %1,0,%2\n\
+       bne-    1b\n\
+       li      %1,0\n\
+3:     .section .fixup,\"ax\"\n\
+4:     li      %1,%3\n\
+       b       3b\n\
+       .previous\n\
+       .section __ex_table,\"a\"\n\
+       .align 3\n\
+       .llong  1b,4b,2b,4b\n\
+       .previous"                                              \
+       : "=&r" (oldval), "=&r" (ret)                           \
+       : "b" (uaddr), "i" (-EFAULT), "1" (oparg)               \
+       : "cr0", "memory")
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+               __futex_atomic_op("", ret, oldval, uaddr, oparg);
+               break;
+       case FUTEX_OP_ADD:
+               __futex_atomic_op("add %1,%0,%1\n", ret, oldval, uaddr, oparg);
+               break;
+       case FUTEX_OP_OR:
+               __futex_atomic_op("or %1,%0,%1\n", ret, oldval, uaddr, oparg);
+               break;
+       case FUTEX_OP_ANDN:
+               __futex_atomic_op("andc %1,%0,%1\n", ret, oldval, uaddr, oparg);
+               break;
+       case FUTEX_OP_XOR:
+               __futex_atomic_op("xor %1,%0,%1\n", ret, oldval, uaddr, oparg);
+               break;
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-ppc64/hdreg.h b/include/asm-ppc64/hdreg.h
deleted file mode 100644 (file)
index 7f7fd1a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/hdreg.h>
index e46ff68a6e4184923547153af0853d91bef2264e..42adf7033a8106219f74c8678431a1d9037736cd 100644 (file)
@@ -6,7 +6,7 @@
  */
 #define PHBS_IO_BASE     VMALLOC_END
 #define IMALLOC_BASE      (PHBS_IO_BASE + 0x80000000ul)        /* Reserve 2 gigs for PHBs */
-#define IMALLOC_END       (VMALLOC_START + EADDR_MASK)
+#define IMALLOC_END       (VMALLOC_START + PGTABLE_RANGE)
 
 
 /* imalloc region types */
diff --git a/include/asm-ppc64/ioctl.h b/include/asm-ppc64/ioctl.h
deleted file mode 100644 (file)
index 42b8c5d..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef _PPC64_IOCTL_H
-#define _PPC64_IOCTL_H
-
-
-/*
- * This was copied from the alpha as it's a bit cleaner there.
- *                         -- Cort
- *
- * 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.
- */
-
-#define _IOC_NRBITS    8
-#define _IOC_TYPEBITS  8
-#define _IOC_SIZEBITS  13
-#define _IOC_DIRBITS   3
-
-#define _IOC_NRMASK    ((1 << _IOC_NRBITS)-1)
-#define _IOC_TYPEMASK  ((1 << _IOC_TYPEBITS)-1)
-#define _IOC_SIZEMASK  ((1 << _IOC_SIZEBITS)-1)
-#define _IOC_DIRMASK   ((1 << _IOC_DIRBITS)-1)
-
-#define _IOC_NRSHIFT   0
-#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS)
-#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS)
-#define _IOC_DIRSHIFT  (_IOC_SIZESHIFT+_IOC_SIZEBITS)
-
-/*
- * Direction bits _IOC_NONE could be 0, but OSF/1 gives it a bit.
- * And this turns out useful to catch old ioctl numbers in header
- * files for us.
- */
-#define _IOC_NONE      1U
-#define _IOC_READ      2U
-#define _IOC_WRITE     4U
-
-#define _IOC(dir,type,nr,size) \
-       (((dir)  << _IOC_DIRSHIFT) | \
-        ((type) << _IOC_TYPESHIFT) | \
-        ((nr)   << _IOC_NRSHIFT) | \
-        ((size) << _IOC_SIZESHIFT))
-
-/* provoke compile error for invalid uses of size argument */
-extern unsigned int __invalid_size_argument_for_IOC;
-#define _IOC_TYPECHECK(t) \
-       ((sizeof(t) == sizeof(t[1]) && \
-         sizeof(t) < (1 << _IOC_SIZEBITS)) ? \
-         sizeof(t) : __invalid_size_argument_for_IOC)
-
-/* used to create numbers */
-#define _IO(type,nr)           _IOC(_IOC_NONE,(type),(nr),0)
-#define _IOR(type,nr,size)     _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
-#define _IOW(type,nr,size)     _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
-#define _IOWR(type,nr,size)    _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
-#define _IOR_BAD(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
-#define _IOW_BAD(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
-#define _IOWR_BAD(type,nr,size)        _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
-
-/* used to decode them.. */
-#define _IOC_DIR(nr)           (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
-#define _IOC_TYPE(nr)          (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
-#define _IOC_NR(nr)            (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
-#define _IOC_SIZE(nr)          (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
-
-/* various drivers, such as the pcmcia stuff, need these... */
-#define IOC_IN         (_IOC_WRITE << _IOC_DIRSHIFT)
-#define IOC_OUT                (_IOC_READ << _IOC_DIRSHIFT)
-#define IOC_INOUT      ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
-#define IOCSIZE_MASK   (_IOC_SIZEMASK << _IOC_SIZESHIFT)
-#define IOCSIZE_SHIFT  (_IOC_SIZESHIFT)
-
-#endif /* _PPC64_IOCTL_H */
diff --git a/include/asm-ppc64/ioctls.h b/include/asm-ppc64/ioctls.h
deleted file mode 100644 (file)
index 48796bf..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-#ifndef _ASM_PPC64_IOCTLS_H
-#define _ASM_PPC64_IOCTLS_H
-
-/*
- * 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 <asm/ioctl.h>
-
-#define FIOCLEX                _IO('f', 1)
-#define FIONCLEX       _IO('f', 2)
-#define FIOASYNC       _IOW('f', 125, int)
-#define FIONBIO                _IOW('f', 126, int)
-#define FIONREAD       _IOR('f', 127, int)
-#define TIOCINQ                FIONREAD
-#define FIOQSIZE        _IOR('f', 128, loff_t)
-
-#define TIOCGETP       _IOR('t', 8, struct sgttyb)
-#define TIOCSETP       _IOW('t', 9, struct sgttyb)
-#define TIOCSETN       _IOW('t', 10, struct sgttyb)    /* TIOCSETP wo flush */
-
-#define TIOCSETC       _IOW('t', 17, struct tchars)
-#define TIOCGETC       _IOR('t', 18, struct tchars)
-#define TCGETS         _IOR('t', 19, struct termios)
-#define TCSETS         _IOW('t', 20, struct termios)
-#define TCSETSW                _IOW('t', 21, struct termios)
-#define TCSETSF                _IOW('t', 22, struct termios)
-
-#define TCGETA         _IOR('t', 23, struct termio)
-#define TCSETA         _IOW('t', 24, struct termio)
-#define TCSETAW                _IOW('t', 25, struct termio)
-#define TCSETAF                _IOW('t', 28, struct termio)
-
-#define TCSBRK         _IO('t', 29)
-#define TCXONC         _IO('t', 30)
-#define TCFLSH         _IO('t', 31)
-
-#define TIOCSWINSZ     _IOW('t', 103, struct winsize)
-#define TIOCGWINSZ     _IOR('t', 104, struct winsize)
-#define        TIOCSTART       _IO('t', 110)           /* start output, like ^Q */
-#define        TIOCSTOP        _IO('t', 111)           /* stop output, like ^S */
-#define TIOCOUTQ        _IOR('t', 115, int)     /* output queue size */
-
-#define TIOCGLTC       _IOR('t', 116, struct ltchars)
-#define TIOCSLTC       _IOW('t', 117, struct ltchars)
-#define TIOCSPGRP      _IOW('t', 118, int)
-#define TIOCGPGRP      _IOR('t', 119, int)
-
-#define TIOCEXCL       0x540C
-#define TIOCNXCL       0x540D
-#define TIOCSCTTY      0x540E
-
-#define TIOCSTI                0x5412
-#define TIOCMGET       0x5415
-#define TIOCMBIS       0x5416
-#define TIOCMBIC       0x5417
-#define TIOCMSET       0x5418
-# define TIOCM_LE      0x001
-# define TIOCM_DTR     0x002
-# define TIOCM_RTS     0x004
-# define TIOCM_ST      0x008
-# define TIOCM_SR      0x010
-# define TIOCM_CTS     0x020
-# define TIOCM_CAR     0x040
-# define TIOCM_RNG     0x080
-# define TIOCM_DSR     0x100
-# define TIOCM_CD      TIOCM_CAR
-# define TIOCM_RI      TIOCM_RNG
-
-#define TIOCGSOFTCAR   0x5419
-#define TIOCSSOFTCAR   0x541A
-#define TIOCLINUX      0x541C
-#define TIOCCONS       0x541D
-#define TIOCGSERIAL    0x541E
-#define TIOCSSERIAL    0x541F
-#define TIOCPKT                0x5420
-# define TIOCPKT_DATA           0
-# define TIOCPKT_FLUSHREAD      1
-# define TIOCPKT_FLUSHWRITE     2
-# define TIOCPKT_STOP           4
-# define TIOCPKT_START          8
-# define TIOCPKT_NOSTOP                16
-# define TIOCPKT_DOSTOP                32
-
-
-#define TIOCNOTTY      0x5422
-#define TIOCSETD       0x5423
-#define TIOCGETD       0x5424
-#define TCSBRKP                0x5425  /* Needed for POSIX tcsendbreak() */
-#define TIOCSBRK       0x5427  /* BSD compatibility */
-#define TIOCCBRK       0x5428  /* BSD compatibility */
-#define TIOCGSID       0x5429  /* Return the session ID of FD */
-#define TIOCGPTN       _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
-#define TIOCSPTLCK     _IOW('T',0x31, int)  /* Lock/unlock Pty */
-
-#define TIOCSERCONFIG  0x5453
-#define TIOCSERGWILD   0x5454
-#define TIOCSERSWILD   0x5455
-#define TIOCGLCKTRMIOS 0x5456
-#define TIOCSLCKTRMIOS 0x5457
-#define TIOCSERGSTRUCT 0x5458 /* For debugging only */
-#define TIOCSERGETLSR   0x5459 /* Get line status register */
-  /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
-# define TIOCSER_TEMT    0x01  /* Transmitter physically empty */
-#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
-#define TIOCSERSETMULTI 0x545B /* Set multiport config */
-
-#define TIOCMIWAIT     0x545C  /* wait for a change on serial input line(s) */
-#define TIOCGICOUNT    0x545D  /* read serial port inline interrupt counts */
-
-#endif /* _ASM_PPC64_IOCTLS_H */
index 729de5cc21d984206b33bf8e142cc9cb8a27668b..72dcf8116b04390446c7e1e4c2110f46e5df5962 100644 (file)
@@ -104,9 +104,6 @@ extern void iommu_devnode_init_pSeries(struct device_node *dn);
 
 #ifdef CONFIG_PPC_ISERIES
 
-/* Initializes tables for bio buses */
-extern void __init iommu_vio_init(void);
-
 struct iSeries_Device_Node;
 /* Creates table for an individual device node */
 extern void iommu_devnode_init_iSeries(struct iSeries_Device_Node *dn);
diff --git a/include/asm-ppc64/ipc.h b/include/asm-ppc64/ipc.h
deleted file mode 100644 (file)
index a46e3d9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/ipc.h>
index 570678b1da950335f1821485745381f470af62ee..99782afb4cdede53a3e1edfc41050f9c2a9ad990 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 0802919c3235c1b5cc2debe8a0930558525e6615..d9129d2b038ee7d09f87bd22aa6b10b95e1e3329 100644 (file)
@@ -42,6 +42,9 @@ typedef unsigned int kprobe_opcode_t;
 
 #define JPROBE_ENTRY(pentry)   (kprobe_opcode_t *)((func_descr_t *)pentry)
 
+#define is_trap(instr) (IS_TW(instr) || IS_TD(instr) || \
+                       IS_TWI(instr) || IS_TDI(instr))
+
 #define ARCH_SUPPORTS_KRETPROBES
 void kretprobe_trampoline(void);
 
diff --git a/include/asm-ppc64/linkage.h b/include/asm-ppc64/linkage.h
deleted file mode 100644 (file)
index 291c2d0..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_LINKAGE_H
-#define __ASM_LINKAGE_H
-
-/* Nothing to see here... */
-
-#endif
index a6cbca21ac1d7082147fa8800d3851d7c5bbe2b1..de91e034bd986e8d7da853aa28ca752a41b878b8 100644 (file)
@@ -22,7 +22,6 @@
 
 struct lmb_property {
        unsigned long base;
-       unsigned long physbase;
        unsigned long size;
 };
 
@@ -57,4 +56,26 @@ extern void lmb_dump_all(void);
 
 extern unsigned long io_hole_start;
 
+static inline unsigned long
+lmb_size_bytes(struct lmb_region *type, unsigned long region_nr)
+{
+       return type->region[region_nr].size;
+}
+static inline unsigned long
+lmb_size_pages(struct lmb_region *type, unsigned long region_nr)
+{
+       return lmb_size_bytes(type, region_nr) >> PAGE_SHIFT;
+}
+static inline unsigned long
+lmb_start_pfn(struct lmb_region *type, unsigned long region_nr)
+{
+       return type->region[region_nr].base >> PAGE_SHIFT;
+}
+static inline unsigned long
+lmb_end_pfn(struct lmb_region *type, unsigned long region_nr)
+{
+       return lmb_start_pfn(type, region_nr) +
+              lmb_size_pages(type, region_nr);
+}
+
 #endif /* _PPC64_LMB_H */
index 70766b5f26c1a91db3ae19bf60c5f0f4028a2c6a..9e2a6c0649a025467dc8c139e6a07ccb8154be1a 100644 (file)
@@ -108,7 +108,7 @@ struct lppaca
        volatile u32 virtual_decr;      // Virtual DECR for shared procsx78-x7B
        u16     slb_count;              // # of SLBs to maintain        x7C-x7D
        u8      idle;                   // Indicate OS is idle          x7E
-       u8      reserved5;              // Reserved                     x7F
+       u8      vmxregs_in_use;         // VMX registers in use         x7F
 
 
 //=============================================================================
index f0ef06375947bbb86b634338a215575a3fb143c9..9a1ef4427ed2dfa0b2923f99ef2f8c4098cf4011 100644 (file)
@@ -103,11 +103,6 @@ struct machdep_calls {
 
        void            (*progress)(char *, unsigned short);
 
-       /* Debug interface.  Low level I/O to some terminal device */
-       void            (*udbg_putc)(unsigned char c);
-       unsigned char   (*udbg_getc)(void);
-       int             (*udbg_getc_poll)(void);
-
        /* Interface for platform error logging */
        void            (*log_error)(char *buf, unsigned int err_type, int fatal);
 
@@ -140,6 +135,9 @@ struct machdep_calls {
 
        /* Idle loop for this platform, leave empty for default idle loop */
        int             (*idle_loop)(void);
+
+       /* Function to enable pmcs for this platform, called once per cpu. */
+       void            (*enable_pmcs)(void);
 };
 
 extern int default_idle(void);
index 56e09face9a8409e03230d7618b0fd8038eebc1e..af53ffb5572640e2246b9963a2b582d514d98d6d 100644 (file)
 #ifdef CONFIG_SMP
 #define EIEIO_ON_SMP   "eieio\n"
 #define ISYNC_ON_SMP   "\n\tisync"
+#define SYNC_ON_SMP    "lwsync\n\t"
 #else
 #define EIEIO_ON_SMP
 #define ISYNC_ON_SMP
+#define SYNC_ON_SMP
 #endif
 
 static inline void eieio(void)
index 70348a85131396773e8b1a115325246211f53e7d..7bc42eb087adb777df01b69350ada386055c97a7 100644 (file)
 #define STE_VSID_SHIFT 12
 
 /* Location of cpu0's segment table */
-#define STAB0_PAGE     0x9
+#define STAB0_PAGE     0x6
 #define STAB0_PHYS_ADDR        (STAB0_PAGE<<PAGE_SHIFT)
-#define STAB0_VIRT_ADDR        (KERNELBASE+STAB0_PHYS_ADDR)
+
+#ifndef __ASSEMBLY__
+extern char initial_stab[];
+#endif /* ! __ASSEMBLY */
 
 /*
  * SLB
 #define SLB_VSID_C             ASM_CONST(0x0000000000000080) /* class */
 #define SLB_VSID_LS            ASM_CONST(0x0000000000000070) /* size of largepage */
  
-#define SLB_VSID_KERNEL                (SLB_VSID_KP|SLB_VSID_C)
-#define SLB_VSID_USER          (SLB_VSID_KP|SLB_VSID_KS)
+#define SLB_VSID_KERNEL                (SLB_VSID_KP)
+#define SLB_VSID_USER          (SLB_VSID_KP|SLB_VSID_KS|SLB_VSID_C)
+
+#define SLBIE_C                        (0x08000000)
 
 /*
  * Hash table
@@ -259,8 +264,10 @@ extern void stabs_alloc(void);
 #define VSID_BITS      36
 #define VSID_MODULUS   ((1UL<<VSID_BITS)-1)
 
-#define CONTEXT_BITS   20
-#define USER_ESID_BITS 15
+#define CONTEXT_BITS   19
+#define USER_ESID_BITS 16
+
+#define USER_VSID_RANGE        (1UL << (USER_ESID_BITS + SID_SHIFT))
 
 /*
  * This macro generates asm code to compute the VSID scramble
@@ -302,8 +309,7 @@ typedef unsigned long mm_context_id_t;
 typedef struct {
        mm_context_id_t id;
 #ifdef CONFIG_HUGETLB_PAGE
-       pgd_t *huge_pgdir;
-       u16 htlb_segs; /* bitmask */
+       u16 low_htlb_areas, high_htlb_areas;
 #endif
 } mm_context_t;
 
diff --git a/include/asm-ppc64/module.h b/include/asm-ppc64/module.h
deleted file mode 100644 (file)
index 0581607..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef _ASM_PPC64_MODULE_H
-#define _ASM_PPC64_MODULE_H
-
-#include <linux/list.h>
-#include <asm/bug.h>
-
-struct mod_arch_specific
-{
-       /* Index of stubs section within module. */
-       unsigned int stubs_section;
-
-       /* What section is the TOC? */
-       unsigned int toc_section;
-
-       /* List of BUG addresses, source line numbers and filenames */
-       struct list_head bug_list;
-       struct bug_entry *bug_table;
-       unsigned int num_bugs;
-};
-
-extern struct bug_entry *module_find_bug(unsigned long bugaddr);
-
-#define Elf_Shdr Elf64_Shdr
-#define Elf_Sym Elf64_Sym
-#define Elf_Ehdr Elf64_Ehdr
-
-/* Make empty section for module_frob_arch_sections to expand. */
-#ifdef MODULE
-asm(".section .stubs,\"ax\",@nobits; .align 3; .previous");
-#endif
-
-struct exception_table_entry;
-void sort_ex_table(struct exception_table_entry *start,
-                       struct exception_table_entry *finish);
-
-#endif /* _ASM_PPC64_MODULE_H */
index bfb7caa32eaf74ecb599a21ce0435ca23d93e326..d2afe64475975768bd513d732c7b0c3da8813bd4 100644 (file)
@@ -12,8 +12,6 @@
 
 #include <asm/types.h>
 
-#ifndef __ASSEMBLY__
-
 struct naca_struct {
        /* Kernel only data - undefined for user space */
        void *xItVpdAreas;              /* VPD Data                  0x00 */
@@ -23,9 +21,4 @@ struct naca_struct {
 
 extern struct naca_struct naca;
 
-#endif /* __ASSEMBLY__ */
-
-#define NACA_PAGE      0x4
-#define NACA_PHYS_ADDR (NACA_PAGE<<PAGE_SHIFT)
-
 #endif /* _NACA_H */
diff --git a/include/asm-ppc64/namei.h b/include/asm-ppc64/namei.h
deleted file mode 100644 (file)
index a1412a2..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/* 
- * linux/include/asm-ppc/namei.h
- * Adapted from linux/include/asm-alpha/namei.h
- *
- * Included from linux/fs/namei.c
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef __PPC64_NAMEI_H
-#define __PPC64_NAMEI_H
-
-/* This dummy routine maybe changed to something useful
- * for /usr/gnemul/ emulation stuff.
- * Look at asm-sparc/namei.h for details.
- */
-
-#define __emul_prefix() NULL
-
-#endif /* __PPC64_NAMEI_H */
similarity index 95%
rename from arch/ppc64/oprofile/op_impl.h
rename to include/asm-ppc64/oprofile_impl.h
index 7fa7eaabc035113452be4e1efcf08bd9b2558cda..b04f1dfb14219a9ac96a392db582bd22eecf9b69 100644 (file)
@@ -49,6 +49,9 @@ struct op_ppc64_model {
        int num_counters;
 };
 
+extern struct op_ppc64_model op_model_rs64;
+extern struct op_ppc64_model op_model_power4;
+
 static inline unsigned int ctr_read(unsigned int i)
 {
        switch(i) {
index a5893a305a09bdb27a2b12b15980507b25a14d3e..a15422bcf30d2c054b3cc915feb9d025d0b592cc 100644 (file)
 
 #define HUGETLB_PAGE_ORDER     (HPAGE_SHIFT - PAGE_SHIFT)
 
-/* For 64-bit processes the hugepage range is 1T-1.5T */
-#define TASK_HPAGE_BASE ASM_CONST(0x0000010000000000)
-#define TASK_HPAGE_END         ASM_CONST(0x0000018000000000)
+#define HTLB_AREA_SHIFT                40
+#define HTLB_AREA_SIZE         (1UL << HTLB_AREA_SHIFT)
+#define GET_HTLB_AREA(x)       ((x) >> HTLB_AREA_SHIFT)
 
 #define LOW_ESID_MASK(addr, len)       (((1U << (GET_ESID(addr+len-1)+1)) \
                                        - (1U << GET_ESID(addr))) & 0xffff)
+#define HTLB_AREA_MASK(addr, len)      (((1U << (GET_HTLB_AREA(addr+len-1)+1)) \
+                                       - (1U << GET_HTLB_AREA(addr))) & 0xffff)
 
 #define ARCH_HAS_HUGEPAGE_ONLY_RANGE
 #define ARCH_HAS_PREPARE_HUGEPAGE_RANGE
+#define ARCH_HAS_SETCLEAR_HUGE_PTE
 
 #define touches_hugepage_low_range(mm, addr, len) \
-       (LOW_ESID_MASK((addr), (len)) & mm->context.htlb_segs)
-#define touches_hugepage_high_range(addr, len) \
-       (((addr) > (TASK_HPAGE_BASE-(len))) && ((addr) < TASK_HPAGE_END))
+       (LOW_ESID_MASK((addr), (len)) & (mm)->context.low_htlb_areas)
+#define touches_hugepage_high_range(mm, addr, len) \
+       (HTLB_AREA_MASK((addr), (len)) & (mm)->context.high_htlb_areas)
 
 #define __within_hugepage_low_range(addr, len, segmask) \
        ((LOW_ESID_MASK((addr), (len)) | (segmask)) == (segmask))
 #define within_hugepage_low_range(addr, len) \
        __within_hugepage_low_range((addr), (len), \
-                                   current->mm->context.htlb_segs)
-#define within_hugepage_high_range(addr, len) (((addr) >= TASK_HPAGE_BASE) \
-         && ((addr)+(len) <= TASK_HPAGE_END) && ((addr)+(len) >= (addr)))
+                                   current->mm->context.low_htlb_areas)
+#define __within_hugepage_high_range(addr, len, zonemask) \
+       ((HTLB_AREA_MASK((addr), (len)) | (zonemask)) == (zonemask))
+#define within_hugepage_high_range(addr, len) \
+       __within_hugepage_high_range((addr), (len), \
+                                   current->mm->context.high_htlb_areas)
 
 #define is_hugepage_only_range(mm, addr, len) \
-       (touches_hugepage_high_range((addr), (len)) || \
+       (touches_hugepage_high_range((mm), (addr), (len)) || \
          touches_hugepage_low_range((mm), (addr), (len)))
 #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
 
 #define in_hugepage_area(context, addr) \
        (cpu_has_feature(CPU_FTR_16M_PAGE) && \
-        ( (((addr) >= TASK_HPAGE_BASE) && ((addr) < TASK_HPAGE_END)) || \
+        ( ((1 << GET_HTLB_AREA(addr)) & (context).high_htlb_areas) || \
           ( ((addr) < 0x100000000L) && \
-            ((1 << GET_ESID(addr)) & (context).htlb_segs) ) ) )
+            ((1 << GET_ESID(addr)) & (context).low_htlb_areas) ) ) )
 
 #else /* !CONFIG_HUGETLB_PAGE */
 
@@ -125,55 +131,47 @@ extern void copy_user_page(void *to, void *from, unsigned long vaddr, struct pag
  * Entries in the pte table are 64b, while entries in the pgd & pmd are 32b.
  */
 typedef struct { unsigned long pte; } pte_t;
-typedef struct { unsigned int  pmd; } pmd_t;
-typedef struct { unsigned int  pgd; } pgd_t;
+typedef struct { unsigned long pmd; } pmd_t;
+typedef struct { unsigned long pud; } pud_t;
+typedef struct { unsigned long pgd; } pgd_t;
 typedef struct { unsigned long pgprot; } pgprot_t;
 
 #define pte_val(x)     ((x).pte)
 #define pmd_val(x)     ((x).pmd)
+#define pud_val(x)     ((x).pud)
 #define pgd_val(x)     ((x).pgd)
 #define pgprot_val(x)  ((x).pgprot)
 
-#define __pte(x)       ((pte_t) { (x) } )
-#define __pmd(x)       ((pmd_t) { (x) } )
-#define __pgd(x)       ((pgd_t) { (x) } )
-#define __pgprot(x)    ((pgprot_t) { (x) } )
+#define __pte(x)       ((pte_t) { (x) })
+#define __pmd(x)       ((pmd_t) { (x) })
+#define __pud(x)       ((pud_t) { (x) })
+#define __pgd(x)       ((pgd_t) { (x) })
+#define __pgprot(x)    ((pgprot_t) { (x) })
 
 #else
 /*
  * .. while these make it easier on the compiler
  */
 typedef unsigned long pte_t;
-typedef unsigned int  pmd_t;
-typedef unsigned int  pgd_t;
+typedef unsigned long pmd_t;
+typedef unsigned long pud_t;
+typedef unsigned long pgd_t;
 typedef unsigned long pgprot_t;
 
 #define pte_val(x)     (x)
 #define pmd_val(x)     (x)
+#define pud_val(x)     (x)
 #define pgd_val(x)     (x)
 #define pgprot_val(x)  (x)
 
 #define __pte(x)       (x)
 #define __pmd(x)       (x)
+#define __pud(x)       (x)
 #define __pgd(x)       (x)
 #define __pgprot(x)    (x)
 
 #endif
 
-/* Pure 2^n version of get_order */
-static inline int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size-1) >> (PAGE_SHIFT-1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
-
 #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
 
 extern int page_is_ram(unsigned long pfn);
@@ -208,9 +206,6 @@ extern u64 ppc64_pft_size;          /* Log 2 of page table size */
 #define USER_REGION_ID     (0UL)
 #define REGION_ID(ea)     (((unsigned long)(ea)) >> REGION_SHIFT)
 
-#define __bpn_to_ba(x) ((((unsigned long)(x)) << PAGE_SHIFT) + KERNELBASE)
-#define __ba_to_bpn(x) ((((unsigned long)(x)) & ~REGION_MASK) >> PAGE_SHIFT)
-
 #define __va(x) ((void *)((unsigned long)(x) + KERNELBASE))
 
 #ifdef CONFIG_DISCONTIGMEM
@@ -261,4 +256,7 @@ extern u64 ppc64_pft_size;          /* Log 2 of page table size */
         VM_STACK_DEFAULT_FLAGS32 : VM_STACK_DEFAULT_FLAGS64)
 
 #endif /* __KERNEL__ */
+
+#include <asm-generic/page.h>
+
 #endif /* _PPC64_PAGE_H */
index 1fad38dcf7074b08212e11dd64fefd9eab1a792f..76c212d475b35a0d37c8fd12e4e2ae1e1d4ba181 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _ASM_PPC64_PARAM_H
 #define _ASM_PPC64_PARAM_H
 
+#include <linux/config.h>
+
 /*
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -9,7 +11,7 @@
  */
 
 #ifdef __KERNEL__
-# define HZ            1000            /* Internal kernel timer frequency */
+# define HZ            CONFIG_HZ       /* Internal kernel timer frequency */
 # define USER_HZ       100             /* .. some user interfaces are in "ticks" */
 # define CLOCKS_PER_SEC        (USER_HZ)       /* like times() */
 #endif
diff --git a/include/asm-ppc64/percpu.h b/include/asm-ppc64/percpu.h
deleted file mode 100644 (file)
index 60a659a..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ARCH_PPC64_PERCPU__
-#define __ARCH_PPC64_PERCPU__
-
-#include <asm-generic/percpu.h>
-
-#endif /* __ARCH_PPC64_PERCPU__ */
index 4fc4b739b380e383f8c9936bc727ce4df4249f5d..26bc49c1108dfcd09cc30c6feb455e00e833e15f 100644 (file)
@@ -6,7 +6,12 @@
 #include <linux/cpumask.h>
 #include <linux/percpu.h>
 
-extern kmem_cache_t *zero_cache;
+extern kmem_cache_t *pgtable_cache[];
+
+#define PTE_CACHE_NUM  0
+#define PMD_CACHE_NUM  1
+#define PUD_CACHE_NUM  1
+#define PGD_CACHE_NUM  0
 
 /*
  * This program is free software; you can redistribute it and/or
@@ -15,30 +20,40 @@ extern kmem_cache_t *zero_cache;
  * 2 of the License, or (at your option) any later version.
  */
 
-static inline pgd_t *
-pgd_alloc(struct mm_struct *mm)
+static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
-       return kmem_cache_alloc(zero_cache, GFP_KERNEL);
+       return kmem_cache_alloc(pgtable_cache[PGD_CACHE_NUM], GFP_KERNEL);
 }
 
-static inline void
-pgd_free(pgd_t *pgd)
+static inline void pgd_free(pgd_t *pgd)
 {
-       kmem_cache_free(zero_cache, pgd);
+       kmem_cache_free(pgtable_cache[PGD_CACHE_NUM], pgd);
+}
+
+#define pgd_populate(MM, PGD, PUD)     pgd_set(PGD, PUD)
+
+static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
+{
+       return kmem_cache_alloc(pgtable_cache[PUD_CACHE_NUM],
+                               GFP_KERNEL|__GFP_REPEAT);
+}
+
+static inline void pud_free(pud_t *pud)
+{
+       kmem_cache_free(pgtable_cache[PUD_CACHE_NUM], pud);
 }
 
 #define pud_populate(MM, PUD, PMD)     pud_set(PUD, PMD)
 
-static inline pmd_t *
-pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
+static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
-       return kmem_cache_alloc(zero_cache, GFP_KERNEL|__GFP_REPEAT);
+       return kmem_cache_alloc(pgtable_cache[PMD_CACHE_NUM],
+                               GFP_KERNEL|__GFP_REPEAT);
 }
 
-static inline void
-pmd_free(pmd_t *pmd)
+static inline void pmd_free(pmd_t *pmd)
 {
-       kmem_cache_free(zero_cache, pmd);
+       kmem_cache_free(pgtable_cache[PMD_CACHE_NUM], pmd);
 }
 
 #define pmd_populate_kernel(mm, pmd, pte) pmd_set(pmd, pte)
@@ -47,44 +62,58 @@ pmd_free(pmd_t *pmd)
 
 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
 {
-       return kmem_cache_alloc(zero_cache, GFP_KERNEL|__GFP_REPEAT);
+       return kmem_cache_alloc(pgtable_cache[PTE_CACHE_NUM],
+                               GFP_KERNEL|__GFP_REPEAT);
 }
 
 static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
 {
-       pte_t *pte = kmem_cache_alloc(zero_cache, GFP_KERNEL|__GFP_REPEAT);
-       if (pte)
-               return virt_to_page(pte);
-       return NULL;
+       return virt_to_page(pte_alloc_one_kernel(mm, address));
 }
                
 static inline void pte_free_kernel(pte_t *pte)
 {
-       kmem_cache_free(zero_cache, pte);
+       kmem_cache_free(pgtable_cache[PTE_CACHE_NUM], pte);
 }
 
 static inline void pte_free(struct page *ptepage)
 {
-       kmem_cache_free(zero_cache, page_address(ptepage));
+       pte_free_kernel(page_address(ptepage));
 }
 
-struct pte_freelist_batch
+#define PGF_CACHENUM_MASK      0xf
+
+typedef struct pgtable_free {
+       unsigned long val;
+} pgtable_free_t;
+
+static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum,
+                                               unsigned long mask)
 {
-       struct rcu_head rcu;
-       unsigned int    index;
-       struct page *   pages[0];
-};
+       BUG_ON(cachenum > PGF_CACHENUM_MASK);
 
-#define PTE_FREELIST_SIZE      ((PAGE_SIZE - sizeof(struct pte_freelist_batch)) / \
-                                 sizeof(struct page *))
+       return (pgtable_free_t){.val = ((unsigned long) p & ~mask) | cachenum};
+}
 
-extern void pte_free_now(struct page *ptepage);
-extern void pte_free_submit(struct pte_freelist_batch *batch);
+static inline void pgtable_free(pgtable_free_t pgf)
+{
+       void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK);
+       int cachenum = pgf.val & PGF_CACHENUM_MASK;
 
-DECLARE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
+       kmem_cache_free(pgtable_cache[cachenum], p);
+}
 
-void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage);
-#define __pmd_free_tlb(tlb, pmd)       __pte_free_tlb(tlb, virt_to_page(pmd))
+void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);
+
+#define __pte_free_tlb(tlb, ptepage)   \
+       pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \
+               PTE_CACHE_NUM, PTE_TABLE_SIZE-1))
+#define __pmd_free_tlb(tlb, pmd)       \
+       pgtable_free_tlb(tlb, pgtable_free_cache(pmd, \
+               PMD_CACHE_NUM, PMD_TABLE_SIZE-1))
+#define __pud_free_tlb(tlb, pmd)       \
+       pgtable_free_tlb(tlb, pgtable_free_cache(pud, \
+               PUD_CACHE_NUM, PUD_TABLE_SIZE-1))
 
 #define check_pgt_cache()      do { } while (0)
 
index 46cf61c2ff69a3b920231122402b1405ca0d4fca..c83679c9d2b0f49d07ade70a6255c5af32d38074 100644 (file)
 #include <asm/tlbflush.h>
 #endif /* __ASSEMBLY__ */
 
-#include <asm-generic/pgtable-nopud.h>
-
 /*
  * Entries per page directory level.  The PTE level must use a 64b record
  * for each page table entry.  The PMD and PGD level use a 32b record for 
  * each entry by assuming that each entry is page aligned.
  */
 #define PTE_INDEX_SIZE  9
-#define PMD_INDEX_SIZE  10
-#define PGD_INDEX_SIZE  10
+#define PMD_INDEX_SIZE  7
+#define PUD_INDEX_SIZE  7
+#define PGD_INDEX_SIZE  9
+
+#define PTE_TABLE_SIZE (sizeof(pte_t) << PTE_INDEX_SIZE)
+#define PMD_TABLE_SIZE (sizeof(pmd_t) << PMD_INDEX_SIZE)
+#define PUD_TABLE_SIZE (sizeof(pud_t) << PUD_INDEX_SIZE)
+#define PGD_TABLE_SIZE (sizeof(pgd_t) << PGD_INDEX_SIZE)
 
 #define PTRS_PER_PTE   (1 << PTE_INDEX_SIZE)
 #define PTRS_PER_PMD   (1 << PMD_INDEX_SIZE)
+#define PTRS_PER_PUD   (1 << PMD_INDEX_SIZE)
 #define PTRS_PER_PGD   (1 << PGD_INDEX_SIZE)
 
 /* PMD_SHIFT determines what a second-level page table entry can map */
 #define PMD_SIZE       (1UL << PMD_SHIFT)
 #define PMD_MASK       (~(PMD_SIZE-1))
 
-/* PGDIR_SHIFT determines what a third-level page table entry can map */
-#define PGDIR_SHIFT    (PMD_SHIFT + PMD_INDEX_SIZE)
+/* PUD_SHIFT determines what a third-level page table entry can map */
+#define PUD_SHIFT      (PMD_SHIFT + PMD_INDEX_SIZE)
+#define PUD_SIZE       (1UL << PUD_SHIFT)
+#define PUD_MASK       (~(PUD_SIZE-1))
+
+/* PGDIR_SHIFT determines what a fourth-level page table entry can map */
+#define PGDIR_SHIFT    (PUD_SHIFT + PUD_INDEX_SIZE)
 #define PGDIR_SIZE     (1UL << PGDIR_SHIFT)
 #define PGDIR_MASK     (~(PGDIR_SIZE-1))
 
 /*
  * Size of EA range mapped by our pagetables.
  */
-#define EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
-                    PGD_INDEX_SIZE + PAGE_SHIFT)
-#define EADDR_MASK ((1UL << EADDR_SIZE) - 1)
+#define PGTABLE_EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
+                           PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT)
+#define PGTABLE_RANGE (1UL << PGTABLE_EADDR_SIZE)
+
+#if TASK_SIZE_USER64 > PGTABLE_RANGE
+#error TASK_SIZE_USER64 exceeds pagetable range
+#endif
+
+#if TASK_SIZE_USER64 > (1UL << (USER_ESID_BITS + SID_SHIFT))
+#error TASK_SIZE_USER64 exceeds user VSID range
+#endif
 
 /*
  * Define the address range of the vmalloc VM area.
  */
 #define VMALLOC_START (0xD000000000000000ul)
-#define VMALLOC_SIZE  (0x10000000000UL)
+#define VMALLOC_SIZE  (0x80000000000UL)
 #define VMALLOC_END   (VMALLOC_START + VMALLOC_SIZE)
 
 /*
@@ -154,8 +172,6 @@ extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)];
 #ifndef __ASSEMBLY__
 int hash_huge_page(struct mm_struct *mm, unsigned long access,
                   unsigned long ea, unsigned long vsid, int local);
-
-void hugetlb_mm_free_pgd(struct mm_struct *mm);
 #endif /* __ASSEMBLY__ */
 
 #define HAVE_ARCH_UNMAPPED_AREA
@@ -163,7 +179,6 @@ void hugetlb_mm_free_pgd(struct mm_struct *mm);
 #else
 
 #define hash_huge_page(mm,a,ea,vsid,local)     -1
-#define hugetlb_mm_free_pgd(mm)                        do {} while (0)
 
 #endif
 
@@ -197,39 +212,45 @@ static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot)
 #define pte_pfn(x)             ((unsigned long)((pte_val(x) >> PTE_SHIFT)))
 #define pte_page(x)            pfn_to_page(pte_pfn(x))
 
-#define pmd_set(pmdp, ptep)    \
-       (pmd_val(*(pmdp)) = __ba_to_bpn(ptep))
+#define pmd_set(pmdp, ptep)    ({BUG_ON((u64)ptep < KERNELBASE); pmd_val(*(pmdp)) = (unsigned long)(ptep);})
 #define pmd_none(pmd)          (!pmd_val(pmd))
 #define        pmd_bad(pmd)            (pmd_val(pmd) == 0)
 #define        pmd_present(pmd)        (pmd_val(pmd) != 0)
 #define        pmd_clear(pmdp)         (pmd_val(*(pmdp)) = 0)
-#define pmd_page_kernel(pmd)   (__bpn_to_ba(pmd_val(pmd)))
+#define pmd_page_kernel(pmd)   (pmd_val(pmd))
 #define pmd_page(pmd)          virt_to_page(pmd_page_kernel(pmd))
 
-#define pud_set(pudp, pmdp)    (pud_val(*(pudp)) = (__ba_to_bpn(pmdp)))
+#define pud_set(pudp, pmdp)    (pud_val(*(pudp)) = (unsigned long)(pmdp))
 #define pud_none(pud)          (!pud_val(pud))
-#define pud_bad(pud)           ((pud_val(pud)) == 0UL)
-#define pud_present(pud)       (pud_val(pud) != 0UL)
-#define pud_clear(pudp)                (pud_val(*(pudp)) = 0UL)
-#define pud_page(pud)          (__bpn_to_ba(pud_val(pud)))
+#define pud_bad(pud)           ((pud_val(pud)) == 0)
+#define pud_present(pud)       (pud_val(pud) != 0)
+#define pud_clear(pudp)                (pud_val(*(pudp)) = 0)
+#define pud_page(pud)          (pud_val(pud))
+
+#define pgd_set(pgdp, pudp)    ({pgd_val(*(pgdp)) = (unsigned long)(pudp);})
+#define pgd_none(pgd)          (!pgd_val(pgd))
+#define pgd_bad(pgd)           (pgd_val(pgd) == 0)
+#define pgd_present(pgd)       (pgd_val(pgd) != 0)
+#define pgd_clear(pgdp)                (pgd_val(*(pgdp)) = 0)
+#define pgd_page(pgd)          (pgd_val(pgd))
 
 /* 
  * Find an entry in a page-table-directory.  We combine the address region 
  * (the high order N bits) and the pgd portion of the address.
  */
 /* to avoid overflow in free_pgtables we don't use PTRS_PER_PGD here */
-#define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & 0x7ff)
+#define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & 0x1ff)
 
 #define pgd_offset(mm, address)         ((mm)->pgd + pgd_index(address))
 
-/* Find an entry in the second-level page table.. */
+#define pud_offset(pgdp, addr) \
+  (((pud_t *) pgd_page(*(pgdp))) + (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)))
+
 #define pmd_offset(pudp,addr) \
-  ((pmd_t *) pud_page(*(pudp)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
+  (((pmd_t *) pud_page(*(pudp))) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
 
-/* Find an entry in the third-level page table.. */
 #define pte_offset_kernel(dir,addr) \
-  ((pte_t *) pmd_page_kernel(*(dir)) \
- + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
+  (((pte_t *) pmd_page_kernel(*(dir))) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
 
 #define pte_offset_map(dir,addr)       pte_offset_kernel((dir), (addr))
 #define pte_offset_map_nested(dir,addr)        pte_offset_kernel((dir), (addr))
@@ -458,23 +479,20 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
 #define pte_same(A,B)  (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0)
 
 #define pmd_ERROR(e) \
-       printk("%s:%d: bad pmd %08x.\n", __FILE__, __LINE__, pmd_val(e))
+       printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
+#define pud_ERROR(e) \
+       printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pud_val(e))
 #define pgd_ERROR(e) \
-       printk("%s:%d: bad pgd %08x.\n", __FILE__, __LINE__, pgd_val(e))
+       printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
 
 extern pgd_t swapper_pg_dir[];
 
 extern void paging_init(void);
 
-/*
- * Because the huge pgtables are only 2 level, they can take
- * at most around 4M, much less than one hugepage which the
- * process is presumably entitled to use.  So we don't bother
- * freeing up the pagetables on unmap, and wait until
- * destroy_context() to clean up the lot.
- */
+#ifdef CONFIG_HUGETLB_PAGE
 #define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) \
-                                               do { } while (0)
+       free_pgd_range(tlb, addr, end, floor, ceiling)
+#endif
 
 /*
  * This gets called at the end of handling a page fault, when
index c924748c0beaa36e9ed4502f31a6f8772766e529..d1d297dbccfec062fde2ae8011ebc32fc4617d33 100644 (file)
@@ -26,4 +26,6 @@ typedef void (*perf_irq_t)(struct pt_regs *);
 int reserve_pmc_hardware(perf_irq_t new_perf_irq);
 void release_pmc_hardware(void);
 
+void power4_enable_pmcs(void);
+
 #endif /* _PPC64_PMC_H */
diff --git a/include/asm-ppc64/poll.h b/include/asm-ppc64/poll.h
deleted file mode 100644 (file)
index 370fa3b..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef __PPC64_POLL_H
-#define __PPC64_POLL_H
-
-/*
- * Copyright (C) 2001 PPC64 Team, IBM Corp
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#define POLLIN         0x0001
-#define POLLPRI                0x0002
-#define POLLOUT                0x0004
-#define POLLERR                0x0008
-#define POLLHUP                0x0010
-#define POLLNVAL       0x0020
-#define POLLRDNORM     0x0040
-#define POLLRDBAND     0x0080
-#define POLLWRNORM     0x0100
-#define POLLWRBAND     0x0200
-#define POLLMSG                0x0400
-#define POLLREMOVE     0x1000
-
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
-
-#endif /* __PPC64_POLL_H */
index 352306cfb579909177da4fec25492fd8b53adb2b..8bd7aa959385d01d33c530526609e7302cf97921 100644 (file)
 #define PV_970FX       0x003C
 #define        PV_630          0x0040
 #define        PV_630p         0x0041
+#define        PV_970MP        0x0044
 #define        PV_BE           0x0070
 
 /* Platforms supported by PPC64 */
@@ -310,6 +311,20 @@ name: \
        .type GLUE(.,name),@function; \
 GLUE(.,name):
 
+#define _KPROBE(name) \
+       .section ".kprobes.text","a"; \
+       .align 2 ; \
+       .globl name; \
+       .globl GLUE(.,name); \
+       .section ".opd","aw"; \
+name: \
+       .quad GLUE(.,name); \
+       .quad .TOC.@tocbase; \
+       .quad 0; \
+       .previous; \
+       .type GLUE(.,name),@function; \
+GLUE(.,name):
+
 #define _STATIC(name) \
        .section ".text"; \
        .align 2 ; \
@@ -382,8 +397,8 @@ extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 extern struct task_struct *last_task_used_math;
 extern struct task_struct *last_task_used_altivec;
 
-/* 64-bit user address space is 41-bits (2TBs user VM) */
-#define TASK_SIZE_USER64 (0x0000020000000000UL)
+/* 64-bit user address space is 44-bits (16TB user VM) */
+#define TASK_SIZE_USER64 (0x0000100000000000UL)
 
 /* 
  * 32-bit user address space is 4GB - 1 page 
index 04b1a84f7ca390c5f6c3ad6f5ea9bb22f44f2d40..dc5330b3950963266887091034cb82b53b7e1135 100644 (file)
 #define RELOC(x)        (*PTRRELOC(&(x)))
 
 /* Definitions used by the flattened device tree */
-#define OF_DT_HEADER           0xd00dfeed      /* 4: version, 4: total size */
-#define OF_DT_BEGIN_NODE       0x1             /* Start node: full name */
+#define OF_DT_HEADER           0xd00dfeed      /* marker */
+#define OF_DT_BEGIN_NODE       0x1             /* Start of node, full name */
 #define OF_DT_END_NODE         0x2             /* End node */
-#define OF_DT_PROP             0x3             /* Property: name off, size, content */
+#define OF_DT_PROP             0x3             /* Property: name off, size,
+                                                * content */
+#define OF_DT_NOP              0x4             /* nop */
 #define OF_DT_END              0x9
 
-#define OF_DT_VERSION          1
+#define OF_DT_VERSION          0x10
 
 /*
  * This is what gets passed to the kernel by prom_init or kexec
@@ -54,7 +56,9 @@ struct boot_param_header
        u32     version;                /* format version */
        u32     last_comp_version;      /* last compatible version */
        /* version 2 fields below */
-       u32     boot_cpuid_phys;        /* Which physical CPU id we're booting on */
+       u32     boot_cpuid_phys;        /* Physical CPU id we're booting on */
+       /* version 3 fields below */
+       u32     dt_strings_size;        /* size of the DT strings block */
 };
 
 
diff --git a/include/asm-ppc64/resource.h b/include/asm-ppc64/resource.h
deleted file mode 100644 (file)
index add031b..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _PPC64_RESOURCE_H
-#define _PPC64_RESOURCE_H
-
-#include <asm-generic/resource.h>
-
-#endif /* _PPC64_RESOURCE_H */
diff --git a/include/asm-ppc64/string.h b/include/asm-ppc64/string.h
deleted file mode 100644 (file)
index eeca68e..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef _PPC64_STRING_H_
-#define _PPC64_STRING_H_
-
-/*
- * 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.
- */
-
-#define __HAVE_ARCH_STRCPY
-#define __HAVE_ARCH_STRNCPY
-#define __HAVE_ARCH_STRLEN
-#define __HAVE_ARCH_STRCMP
-#define __HAVE_ARCH_STRCAT
-#define __HAVE_ARCH_MEMSET
-#define __HAVE_ARCH_MEMCPY
-#define __HAVE_ARCH_MEMMOVE
-#define __HAVE_ARCH_MEMCMP
-#define __HAVE_ARCH_MEMCHR
-
-extern int strcasecmp(const char *, const char *);
-extern int strncasecmp(const char *, const char *, int);
-extern char * strcpy(char *,const char *);
-extern char * strncpy(char *,const char *, __kernel_size_t);
-extern __kernel_size_t strlen(const char *);
-extern int strcmp(const char *,const char *);
-extern char * strcat(char *, const char *);
-extern void * memset(void *,int,__kernel_size_t);
-extern void * memcpy(void *,const void *,__kernel_size_t);
-extern void * memmove(void *,const void *,__kernel_size_t);
-extern int memcmp(const void *,const void *,__kernel_size_t);
-extern void * memchr(const void *,int,__kernel_size_t);
-
-#endif /* _PPC64_STRING_H_ */
index 98d120ca8a91dc0be5043d2eedc7f8be082bd826..c0396428cc3c0c908bb723c111adff2a1d44ebac 100644 (file)
@@ -88,7 +88,7 @@ DEBUGGER_BOILERPLATE(debugger_dabr_match)
 DEBUGGER_BOILERPLATE(debugger_fault_handler)
 
 #ifdef CONFIG_XMON
-extern void xmon_init(void);
+extern void xmon_init(int enable);
 #endif
 
 #else
@@ -158,7 +158,7 @@ static inline int __is_processor(unsigned long pv)
  * is more like most of the other architectures.
  */
 static __inline__ unsigned long
-__xchg_u32(volatile int *m, unsigned long val)
+__xchg_u32(volatile unsigned int *m, unsigned long val)
 {
        unsigned long dummy;
 
@@ -200,7 +200,7 @@ __xchg_u64(volatile long *m, unsigned long val)
 extern void __xchg_called_with_bad_pointer(void);
 
 static __inline__ unsigned long
-__xchg(volatile void *ptr, unsigned long x, int size)
+__xchg(volatile void *ptr, unsigned long x, unsigned int size)
 {
        switch (size) {
        case 4:
@@ -223,7 +223,7 @@ __xchg(volatile void *ptr, unsigned long x, int size)
 #define __HAVE_ARCH_CMPXCHG    1
 
 static __inline__ unsigned long
-__cmpxchg_u32(volatile int *p, int old, int new)
+__cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
 {
        unsigned int prev;
 
@@ -271,7 +271,8 @@ __cmpxchg_u64(volatile long *p, unsigned long old, unsigned long new)
 extern void __cmpxchg_called_with_bad_pointer(void);
 
 static __inline__ unsigned long
-__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
+         unsigned int size)
 {
        switch (size) {
        case 4:
@@ -283,13 +284,9 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
        return old;
 }
 
-#define cmpxchg(ptr,o,n)                                                \
-  ({                                                                    \
-     __typeof__(*(ptr)) _o_ = (o);                                      \
-     __typeof__(*(ptr)) _n_ = (n);                                      \
-     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,          \
-                                   (unsigned long)_n_, sizeof(*(ptr))); \
-  })
+#define cmpxchg(ptr,o,n)\
+       ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+       (unsigned long)(n),sizeof(*(ptr))))
 
 /*
  * We handle most unaligned accesses in hardware. On the other hand 
@@ -302,5 +299,7 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
 
 #define arch_align_stack(x) (x)
 
+extern unsigned long reloc_offset(void);
+
 #endif /* __KERNEL__ */
 #endif
index 5b8c2cfa11382248105b00937eec2d245411ac3c..bf294c1761b235817eeaad8a97c75311ac11b371 100644 (file)
@@ -72,7 +72,6 @@ typedef struct {
        unsigned long env;
 } func_descr_t;
 
-typedef unsigned int kmem_bufctl_t;
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index 05b5943ab1ee5ade4a88fdd32b3622c4089ece63..c181a60d868c7ee82e79db9ce1d57f9817a8d8d4 100644 (file)
 #define access_ok(type,addr,size) \
        __access_ok(((__force unsigned long)(addr)),(size),get_fs())
 
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated verify_area(int type, const void __user *addr, unsigned long size)
-{
-       return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
-
 /*
  * The exception table consists of pairs of addresses: the first is the
  * address of an instruction that is allowed to fault, and the second is
index a6e04d014b2b6bf9cdac8d7fd7e34dfc302b637f..c786604aef02efcc28319c71f1ffe9fc7ab00ce7 100644 (file)
@@ -2,6 +2,7 @@
 #define __UDBG_HDR
 
 #include <linux/compiler.h>
+#include <linux/init.h>
 
 /*
  * c 2001 PPC 64 Team, IBM Corp
  * 2 of the License, or (at your option) any later version.
  */
 
-void udbg_init_uart(void __iomem *comport, unsigned int speed);
-void udbg_putc(unsigned char c);
-unsigned char udbg_getc(void);
-int udbg_getc_poll(void);
-void udbg_puts(const char *s);
-int udbg_write(const char *s, int n);
-int udbg_read(char *buf, int buflen);
-struct console;
-void udbg_console_write(struct console *con, const char *s, unsigned int n);
-void udbg_printf(const char *fmt, ...);
-void udbg_ppcdbg(unsigned long flags, const char *fmt, ...);
-unsigned long udbg_ifdebug(unsigned long flags);
+extern void (*udbg_putc)(unsigned char c);
+extern unsigned char (*udbg_getc)(void);
+extern int (*udbg_getc_poll)(void);
 
+extern void udbg_puts(const char *s);
+extern int udbg_write(const char *s, int n);
+extern int udbg_read(char *buf, int buflen);
+
+extern void register_early_udbg_console(void);
+extern void udbg_printf(const char *fmt, ...);
+extern void udbg_ppcdbg(unsigned long flags, const char *fmt, ...);
+extern unsigned long udbg_ifdebug(unsigned long flags);
+extern void __init ppcdbg_initialize(void);
+
+extern void udbg_init_uart(void __iomem *comport, unsigned int speed);
 #endif
diff --git a/include/asm-ppc64/unaligned.h b/include/asm-ppc64/unaligned.h
deleted file mode 100644 (file)
index 636e93c..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef __PPC64_UNALIGNED_H
-#define __PPC64_UNALIGNED_H
-
-/*
- * The PowerPC can do unaligned accesses itself in big endian mode. 
- *
- * The strange macros are there to make sure these can't
- * be misused in a way that makes them not work on other
- * architectures where unaligned accesses aren't as simple.
- *
- * 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.
- */
-
-#define get_unaligned(ptr) (*(ptr))
-
-#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
-
-#endif /* __PPC64_UNALIGNED_H */
index 20cd98ee63378c20944c37bceb917ab429d767b6..03f1b95f433bbc7e2e1eda27f00538f7c4ee826a 100644 (file)
 #include <linux/errno.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
+#include <linux/mod_devicetable.h>
+
 #include <asm/hvcall.h>
-#include <asm/prom.h>
 #include <asm/scatterlist.h>
-/* 
+
+/*
  * Architecture-specific constants for drivers to
  * extract attributes of the device using vio_get_attribute()
-*/
+ */
 #define VETH_MAC_ADDR "local-mac-address"
 #define VETH_MCAST_FILTER_SIZE "ibm,mac-address-filters"
 
 #define VIO_IRQ_DISABLE                0UL
 #define VIO_IRQ_ENABLE         1UL
 
-struct vio_dev;
-struct vio_driver;
-struct vio_device_id;
 struct iommu_table;
 
-int vio_register_driver(struct vio_driver *drv);
-void vio_unregister_driver(struct vio_driver *drv);
-
-#ifdef CONFIG_PPC_PSERIES
-struct vio_dev * __devinit vio_register_device_node(
-               struct device_node *node_vdev);
-#endif
-void __devinit vio_unregister_device(struct vio_dev *dev);
-struct vio_dev *vio_find_node(struct device_node *vnode);
-
-const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length);
-int vio_get_irq(struct vio_dev *dev);
-int vio_enable_interrupts(struct vio_dev *dev);
-int vio_disable_interrupts(struct vio_dev *dev);
-
-extern struct dma_mapping_ops vio_dma_ops;
-
-extern struct bus_type vio_bus_type;
-
-struct vio_device_id {
+/*
+ * The vio_dev structure is used to describe virtual I/O devices.
+ */
+struct vio_dev {
+       struct iommu_table *iommu_table;     /* vio_map_* uses this */
+       char *name;
        char *type;
-       char *compat;
+       uint32_t unit_address;
+       unsigned int irq;
+       struct device dev;
 };
 
 struct vio_driver {
        struct list_head node;
        char *name;
-       const struct vio_device_id *id_table;   /* NULL if wants all devices */
-       int  (*probe)  (struct vio_dev *dev, const struct vio_device_id *id);   /* New device inserted */
-       int (*remove) (struct vio_dev *dev);    /* Device removed (NULL if not a hot-plug capable driver) */
+       const struct vio_device_id *id_table;
+       int (*probe)(struct vio_dev *dev, const struct vio_device_id *id);
+       int (*remove)(struct vio_dev *dev);
        unsigned long driver_data;
-
        struct device_driver driver;
 };
 
+struct vio_bus_ops {
+       int (*match)(const struct vio_device_id *id, const struct vio_dev *dev);
+       void (*unregister_device)(struct vio_dev *);
+       void (*release_device)(struct device *);
+};
+
+extern struct dma_mapping_ops vio_dma_ops;
+extern struct bus_type vio_bus_type;
+extern struct vio_dev vio_bus_device;
+
+extern int vio_register_driver(struct vio_driver *drv);
+extern void vio_unregister_driver(struct vio_driver *drv);
+
+extern struct vio_dev * __devinit vio_register_device(struct vio_dev *viodev);
+extern void __devinit vio_unregister_device(struct vio_dev *dev);
+
+extern int vio_bus_init(struct vio_bus_ops *);
+
+#ifdef CONFIG_PPC_PSERIES
+struct device_node;
+
+extern struct vio_dev * __devinit vio_register_device_node(
+               struct device_node *node_vdev);
+extern struct vio_dev *vio_find_node(struct device_node *vnode);
+extern const void *vio_get_attribute(struct vio_dev *vdev, void *which,
+               int *length);
+extern int vio_enable_interrupts(struct vio_dev *dev);
+extern int vio_disable_interrupts(struct vio_dev *dev);
+#endif
+
 static inline struct vio_driver *to_vio_driver(struct device_driver *drv)
 {
        return container_of(drv, struct vio_driver, driver);
 }
 
-/*
- * The vio_dev structure is used to describe virtual I/O devices.
- */
-struct vio_dev {
-       struct iommu_table *iommu_table;     /* vio_map_* uses this */
-       char *name;
-       char *type;
-       uint32_t unit_address;  
-       unsigned int irq;
-
-       struct device dev;
-};
-
 static inline struct vio_dev *to_vio_dev(struct device *dev)
 {
        return container_of(dev, struct vio_dev, dev);
diff --git a/include/asm-ppc64/xor.h b/include/asm-ppc64/xor.h
deleted file mode 100644 (file)
index c82eb12..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/xor.h>
diff --git a/include/asm-s390/auxvec.h b/include/asm-s390/auxvec.h
new file mode 100644 (file)
index 0000000..0d34072
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __ASMS390_AUXVEC_H
+#define __ASMS390_AUXVEC_H
+
+#endif
index 7f8f544eb262f8edb58a97090559ad280eea2918..a007715f4aea8150577e00b9777baee9dc04c7b9 100644 (file)
@@ -13,10 +13,10 @@ typedef s32         compat_ssize_t;
 typedef s32            compat_time_t;
 typedef s32            compat_clock_t;
 typedef s32            compat_pid_t;
-typedef u16            compat_uid_t;
-typedef u16            compat_gid_t;
-typedef u32            compat_uid32_t;
-typedef u32            compat_gid32_t;
+typedef u16            __compat_uid_t;
+typedef u16            __compat_gid_t;
+typedef u32            __compat_uid32_t;
+typedef u32            __compat_gid32_t;
 typedef u16            compat_mode_t;
 typedef u32            compat_ino_t;
 typedef u16            compat_dev_t;
@@ -51,8 +51,8 @@ struct compat_stat {
        compat_ino_t    st_ino;
        compat_mode_t   st_mode;
        compat_nlink_t  st_nlink;
-       compat_uid_t    st_uid;
-       compat_gid_t    st_gid;
+       __compat_uid_t  st_uid;
+       __compat_gid_t  st_gid;
        compat_dev_t    st_rdev;
        u16             __pad2;
        u32             st_size;
@@ -140,10 +140,10 @@ static inline void __user *compat_alloc_user_space(long len)
 
 struct compat_ipc64_perm {
        compat_key_t key;
-       compat_uid32_t uid;
-       compat_gid32_t gid;
-       compat_uid32_t cuid;
-       compat_gid32_t cgid;
+       __compat_uid32_t uid;
+       __compat_gid32_t gid;
+       __compat_uid32_t cuid;
+       __compat_gid32_t cgid;
        compat_mode_t mode;
        unsigned short __pad1;
        unsigned short seq;
index 92360d90144bc698618f1dbf09da1dae22a202d7..7127030ae162c1253380fe01b114ea3ccf595d47 100644 (file)
@@ -52,8 +52,6 @@ struct __debug_entry{
 #define DEBUG_DATA(entry) (char*)(entry + 1) /* data is stored behind */
                                              /* the entry information */
 
-#define STCK(x)        asm volatile ("STCK 0(%1)" : "=m" (x) : "a" (&(x)) : "cc")
-
 typedef struct __debug_entry debug_entry_t;
 
 struct debug_view;
index 48f692b45732494165dd7f38028731214ed1f1a0..46ab12db57397dfc44a7aa84f9c10ac5e97509d9 100644 (file)
@@ -1,97 +1 @@
-/*
- *  include/asm-s390/fcntl.h
- *
- *  S390 version
- *
- *  Derived from "include/asm-i386/fcntl.h"
- */
-#ifndef _S390_FCNTL_H
-#define _S390_FCNTL_H
-
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
-   located on an ext2 file system */
-#define O_ACCMODE         0003
-#define O_RDONLY            00
-#define O_WRONLY            01
-#define O_RDWR              02
-#define O_CREAT                   0100 /* not fcntl */
-#define O_EXCL            0200 /* not fcntl */
-#define O_NOCTTY          0400 /* not fcntl */
-#define O_TRUNC                  01000 /* not fcntl */
-#define O_APPEND         02000
-#define O_NONBLOCK       04000
-#define O_NDELAY       O_NONBLOCK
-#define O_SYNC          010000
-#define FASYNC          020000 /* fcntl, for BSD compatibility */
-#define O_DIRECT        040000 /* direct disk access hint */
-#define O_LARGEFILE    0100000
-#define O_DIRECTORY    0200000 /* must be a directory */
-#define O_NOFOLLOW     0400000 /* don't follow links */
-#define O_NOATIME      01000000
-
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
-#define F_GETLK                5
-#define F_SETLK                6
-#define F_SETLKW       7
-
-#define F_SETOWN       8       /*  for sockets. */
-#define F_GETOWN       9       /*  for sockets. */
-#define F_SETSIG       10      /*  for sockets. */
-#define F_GETSIG       11      /*  for sockets. */
-
-#ifndef __s390x__
-#define F_GETLK64      12      /*  using 'struct flock64' */
-#define F_SETLK64      13
-#define F_SETLKW64     14
-#endif /* ! __s390x__ */
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK                0
-#define F_WRLCK                1
-#define F_UNLCK                2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
-
-struct flock {
-       short l_type;
-       short l_whence;
-       off_t l_start;
-       off_t l_len;
-       pid_t l_pid;
-};
-
-#ifndef __s390x__
-struct flock64 {
-       short  l_type;
-       short  l_whence;
-       loff_t l_start;
-       loff_t l_len;
-       pid_t  l_pid;
-};
-#endif
-#define F_LINUX_SPECIFIC_BASE  1024
-#endif
+#include <asm-generic/fcntl.h>
diff --git a/include/asm-s390/futex.h b/include/asm-s390/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
index afe6a9f9b0aed53f454ca8f5c65e278cfe40d4f9..c6f51c9ce3ffb89daa43903f0a6f00b9a23574d5 100644 (file)
@@ -68,6 +68,7 @@
 #define __LC_SYSTEM_TIMER              0x270
 #define __LC_LAST_UPDATE_CLOCK         0x278
 #define __LC_STEAL_CLOCK               0x280
+#define __LC_RETURN_MCCK_PSW            0x288
 #define __LC_KERNEL_STACK               0xC40
 #define __LC_THREAD_INFO               0xC44
 #define __LC_ASYNC_STACK                0xC48
@@ -90,6 +91,7 @@
 #define __LC_SYSTEM_TIMER              0x278
 #define __LC_LAST_UPDATE_CLOCK         0x280
 #define __LC_STEAL_CLOCK               0x288
+#define __LC_RETURN_MCCK_PSW            0x290
 #define __LC_KERNEL_STACK               0xD40
 #define __LC_THREAD_INFO               0xD48
 #define __LC_ASYNC_STACK                0xD50
@@ -196,7 +198,8 @@ struct _lowcore
        __u64        system_timer;             /* 0x270 */
        __u64        last_update_clock;        /* 0x278 */
        __u64        steal_clock;              /* 0x280 */
-       __u8         pad8[0xc00-0x288];        /* 0x288 */
+        psw_t        return_mcck_psw;          /* 0x288 */
+       __u8         pad8[0xc00-0x290];        /* 0x290 */
 
         /* System info area */
        __u32        save_area[16];            /* 0xc00 */
@@ -285,7 +288,8 @@ struct _lowcore
        __u64        system_timer;             /* 0x278 */
        __u64        last_update_clock;        /* 0x280 */
        __u64        steal_clock;              /* 0x288 */
-        __u8         pad8[0xc00-0x290];        /* 0x290 */
+        psw_t        return_mcck_psw;          /* 0x290 */
+        __u8         pad8[0xc00-0x2a0];        /* 0x2a0 */
         /* System info area */
        __u64        save_area[16];            /* 0xc00 */
         __u8         pad9[0xd40-0xc80];        /* 0xc80 */
index 2be287b9df8822a0ca072e188c74fd9d84390f65..2430c561e021fe781951b5e51ea548a34567fff9 100644 (file)
@@ -111,20 +111,6 @@ static inline void copy_page(void *to, void *from)
 #define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
 #define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
 
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
-{
-        int order;
-
-        size = (size-1) >> (PAGE_SHIFT-1);
-        order = -1;
-        do {
-                size >>= 1;
-                order++;
-        } while (size);
-        return order;
-}
-
 /*
  * These are used to make use of C type-checking..
  */
@@ -207,4 +193,6 @@ page_get_storage_key(unsigned long addr)
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/page.h>
+
 #endif /* _S390_PAGE_H */
index 0e96eeca4e6b748233d9ca842e254e466bef0075..15a5298c8744bf1401be8b0cb736b406b410d55d 100644 (file)
@@ -22,6 +22,8 @@
 #define SO_BROADCAST   6
 #define SO_SNDBUF      7
 #define SO_RCVBUF      8
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
 #define SO_KEEPALIVE   9
 #define SO_OOBINLINE   10
 #define SO_NO_CHECK    11
index 8ff10300f7ee7afbf69f2ada83d387846aa60187..321b23bba1ecf16987b724e45f79319f55972159 100644 (file)
@@ -47,7 +47,7 @@ extern int _raw_spin_trylock_retry(spinlock_t *lp, unsigned int pc);
 
 static inline void _raw_spin_lock(spinlock_t *lp)
 {
-       unsigned long pc = (unsigned long) __builtin_return_address(0);
+       unsigned long pc = 1 | (unsigned long) __builtin_return_address(0);
 
        if (unlikely(_raw_compare_and_swap(&lp->lock, 0, pc) != 0))
                _raw_spin_lock_wait(lp, pc);
@@ -55,7 +55,7 @@ static inline void _raw_spin_lock(spinlock_t *lp)
 
 static inline int _raw_spin_trylock(spinlock_t *lp)
 {
-       unsigned long pc = (unsigned long) __builtin_return_address(0);
+       unsigned long pc = 1 | (unsigned long) __builtin_return_address(0);
 
        if (likely(_raw_compare_and_swap(&lp->lock, 0, pc) == 0))
                return 1;
index 3fefd61416a515e2459cd3b39edf2079cf682137..d0be3e477013de865a513c84096753eb9b1e6bfb 100644 (file)
@@ -79,8 +79,6 @@ typedef unsigned  long u64;
 
 typedef u32 dma_addr_t;
 
-typedef unsigned int kmem_bufctl_t;
-
 #ifndef __s390x__
 typedef union {
        unsigned long long pair;
index 3e3bfe6a8fa84188f86f1acef2d17e84814771c3..38a5cf8ab9e3e5cc69f162f1b8af363f886b7046 100644 (file)
 
 #define access_ok(type,addr,size) __access_ok(addr,size)
 
-/* this function will go away soon - use access_ok() instead */
-extern inline int __deprecated verify_area(int type, const void __user *addr,
-                                               unsigned long size)
-{
-       return access_ok(type, addr, size) ? 0 : -EFAULT;
-}
-
 /*
  * The exception table consists of pairs of addresses: the first is the
  * address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-sh/auxvec.h b/include/asm-sh/auxvec.h
new file mode 100644 (file)
index 0000000..fc21e4d
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __ASM_SH_AUXVEC_H
+#define __ASM_SH_AUXVEC_H
+
+#endif /* __ASM_SH_AUXVEC_H */
index 0b3ae524e34cca05d8cf77cc617ccb72fca7fb27..46ab12db57397dfc44a7aa84f9c10ac5e97509d9 100644 (file)
@@ -1,88 +1 @@
-#ifndef __ASM_SH_FCNTL_H
-#define __ASM_SH_FCNTL_H
-
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
-   located on an ext2 file system */
-#define O_ACCMODE         0003
-#define O_RDONLY            00
-#define O_WRONLY            01
-#define O_RDWR              02
-#define O_CREAT                   0100 /* not fcntl */
-#define O_EXCL            0200 /* not fcntl */
-#define O_NOCTTY          0400 /* not fcntl */
-#define O_TRUNC                  01000 /* not fcntl */
-#define O_APPEND         02000
-#define O_NONBLOCK       04000
-#define O_NDELAY       O_NONBLOCK
-#define O_SYNC          010000
-#define FASYNC          020000 /* fcntl, for BSD compatibility */
-#define O_DIRECT        040000 /* direct disk access hint - currently ignored */
-#define O_LARGEFILE    0100000
-#define O_DIRECTORY    0200000 /* must be a directory */
-#define O_NOFOLLOW     0400000 /* don't follow links */
-#define O_NOATIME      01000000
-
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
-#define F_GETLK                5
-#define F_SETLK                6
-#define F_SETLKW       7
-
-#define F_SETOWN       8       /*  for sockets. */
-#define F_GETOWN       9       /*  for sockets. */
-#define F_SETSIG       10      /*  for sockets. */
-#define F_GETSIG       11      /*  for sockets. */
-
-#define F_GETLK64      12      /*  using 'struct flock64' */
-#define F_SETLK64      13
-#define F_SETLKW64     14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK                0
-#define F_WRLCK                1
-#define F_UNLCK                2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
-
-struct flock {
-       short l_type;
-       short l_whence;
-       off_t l_start;
-       off_t l_len;
-       pid_t l_pid;
-};
-
-struct flock64 {
-       short  l_type;
-       short  l_whence;
-       loff_t l_start;
-       loff_t l_len;
-       pid_t  l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE  1024
-#endif /* __ASM_SH_FCNTL_H */
-
+#include <asm-generic/fcntl.h>
diff --git a/include/asm-sh/futex.h b/include/asm-sh/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-sh/hdreg.h b/include/asm-sh/hdreg.h
deleted file mode 100644 (file)
index 7f7fd1a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/hdreg.h>
index 180467be8e7bb84c7f4f41397697bfc503b2ef98..324e6cc5ecf71c90d66fa90fe459e944791f6c86 100644 (file)
@@ -122,24 +122,8 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 #define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
                                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
-#ifndef __ASSEMBLY__
-
-/* Pure 2^n version of get_order */
-static __inline__ int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size-1) >> (PAGE_SHIFT-1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
-
-#endif
-
 #endif /* __KERNEL__ */
 
+#include <asm-generic/page.h>
+
 #endif /* __ASM_SH_PAGE_H */
index dde696c3b4c7660d59f5e6a3809a003968f5c07b..553904ff9336c2e26304810e0f0db20e0f4a4220 100644 (file)
@@ -14,6 +14,8 @@
 #define SO_BROADCAST   6
 #define SO_SNDBUF      7
 #define SO_RCVBUF      8
+#define SO_RCVBUFFORCE 32
+#define SO_SNDBUFFORCE 33
 #define SO_KEEPALIVE   9
 #define SO_OOBINLINE   10
 #define SO_NO_CHECK    11
index c4dc126c56211cac02e2b92c06b4151cc555bf73..cb7e183a0a6beabbec8b1b0dd14d3fd53886caaa 100644 (file)
@@ -58,8 +58,6 @@ typedef u64 sector_t;
 #define HAVE_SECTOR_T
 #endif
 
-typedef unsigned int kmem_bufctl_t;
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index fb9e334afa2be050acd666412a4e5c8264a1d7f2..2cb01861e7c550babe2e44409aa0be3942d2415a 100644 (file)
@@ -146,12 +146,6 @@ static inline int access_ok(int type, const void __user *p, unsigned long size)
        return __access_ok(addr, size);
 }
 
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
-{
-       return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
 /*
  * Uh, these should become the main single-value transfer routines ...
  * They automatically use the right size if we just have the right
diff --git a/include/asm-sh64/auxvec.h b/include/asm-sh64/auxvec.h
new file mode 100644 (file)
index 0000000..1ad5a44
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __ASM_SH64_AUXVEC_H
+#define __ASM_SH64_AUXVEC_H
+
+#endif /* __ASM_SH64_AUXVEC_H */
index ffcc36c64fa5a3dc01996514010d176bc495b443..744dd79b9d5d4ee40c5a63e1542c5cf26109fc13 100644 (file)
@@ -1,7 +1 @@
-#ifndef __ASM_SH64_FCNTL_H
-#define __ASM_SH64_FCNTL_H
-
 #include <asm-sh/fcntl.h>
-
-#endif /* __ASM_SH64_FCNTL_H */
-
diff --git a/include/asm-sh64/futex.h b/include/asm-sh64/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-sh64/hdreg.h b/include/asm-sh64/hdreg.h
deleted file mode 100644 (file)
index 52d9836..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_SH64_HDREG_H
-#define __ASM_SH64_HDREG_H
-
-#include <asm-generic/hdreg.h>
-
-#endif /* __ASM_SH64_HDREG_H */
index d6167f1c0e99ef10f86877259441bfb7c5e4e908..c86df90f7cbd879b0f5d63c5831b40a789a898a4 100644 (file)
@@ -115,24 +115,8 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 #define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
                                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
-#ifndef __ASSEMBLY__
-
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size-1) >> (PAGE_SHIFT-1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
-
-#endif
-
 #endif /* __KERNEL__ */
 
+#include <asm-generic/page.h>
+
 #endif /* __ASM_SH64_PAGE_H */
index 41d4d2f82aa99dbf51f8af1438f1009964f2ba90..8d41db2153b599bcd618a47bff5726bd9d7828bd 100644 (file)
@@ -65,8 +65,6 @@ typedef u32 dma_addr_t;
 #endif
 typedef u64 dma64_addr_t;
 
-typedef unsigned int kmem_bufctl_t;
-
 #endif /* __ASSEMBLY__ */
 
 #define BITS_PER_LONG 32
index a33654d576a1a05dd2328a605217298dbbd18381..56aa3cf0f2734da96dda1ce66469dd4d5b4fcb13 100644 (file)
 #define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
 #define __access_ok(addr,size) (__range_ok(addr,size) == 0)
 
-/* this function will go away soon - use access_ok() instead */
-extern inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
-{
-       return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
 /*
  * Uh, these should become the main single-value transfer routines ...
  * They automatically use the right size if we just have the right
diff --git a/include/asm-sparc/auxvec.h b/include/asm-sparc/auxvec.h
new file mode 100644 (file)
index 0000000..ad6f360
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __ASMSPARC_AUXVEC_H
+#define __ASMSPARC_AUXVEC_H
+
+#endif /* !(__ASMSPARC_AUXVEC_H) */
index df9c75d41d6802527e72b912635b85777ddb40f0..5db60b5ae7b09d26812f7dfb1d735183e721aced 100644 (file)
@@ -4,10 +4,6 @@
 
 /* open/fcntl - O_SYNC is only implemented on blocks devices and on files
    located on an ext2 file system */
-#define O_RDONLY       0x0000
-#define O_WRONLY       0x0001
-#define O_RDWR         0x0002
-#define O_ACCMODE      0x0003
 #define O_APPEND       0x0008
 #define FASYNC         0x0040  /* fcntl, for BSD compatibility */
 #define O_CREAT                0x0200  /* not fcntl */
 #define O_NONBLOCK     0x4000
 #define O_NDELAY       (0x0004 | O_NONBLOCK)
 #define O_NOCTTY       0x8000  /* not fcntl */
-#define O_DIRECTORY    0x10000 /* must be a directory */
-#define O_NOFOLLOW     0x20000 /* don't follow links */
 #define O_LARGEFILE    0x40000
 #define O_DIRECT        0x100000 /* direct disk access hint */
 #define O_NOATIME      0x200000
 
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
 #define F_GETOWN       5       /*  for sockets. */
 #define F_SETOWN       6       /*  for sockets. */
 #define F_GETLK                7
 #define F_SETLK                8
 #define F_SETLKW       9
-#define F_SETSIG       10      /*  for sockets. */
-#define F_GETSIG       11      /*  for sockets. */
-
-#define F_GETLK64      12      /*  using 'struct flock64' */
-#define F_SETLK64      13
-#define F_SETLKW64     14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
 
 /* for posix fcntl() and lockf() */
 #define F_RDLCK                1
 #define F_WRLCK                2
 #define F_UNLCK                3
 
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
-
-struct flock {
-       short l_type;
-       short l_whence;
-       off_t l_start;
-       off_t l_len;
-       pid_t l_pid;
-       short __unused;
-};
+#define __ARCH_FLOCK_PAD       short __unused;
+#define __ARCH_FLOCK64_PAD     short __unused;
 
-struct flock64 {
-       short l_type;
-       short l_whence;
-       loff_t l_start;
-       loff_t l_len;
-       pid_t l_pid;
-       short __unused;
-};
+#include <asm-generic/fcntl.h>
 
-#define F_LINUX_SPECIFIC_BASE  1024
 #endif
diff --git a/include/asm-sparc/futex.h b/include/asm-sparc/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-sparc/hdreg.h b/include/asm-sparc/hdreg.h
deleted file mode 100644 (file)
index 7f7fd1a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/hdreg.h>
index 383060e90d947793eefb85af52c442e3b3025410..9122684f6c1eb172e7abe440df50b2b2cae054a1 100644 (file)
@@ -132,20 +132,6 @@ BTFIXUPDEF_SETHI(sparc_unmapped_base)
 
 #define TASK_UNMAPPED_BASE     BTFIXUP_SETHI(sparc_unmapped_base)
 
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size-1) >> (PAGE_SHIFT-1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
-
 #else /* !(__ASSEMBLY__) */
 
 #define __pgprot(x)    (x)
@@ -178,4 +164,6 @@ extern unsigned long pfn_base;
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/page.h>
+
 #endif /* _SPARC_PAGE_H */
index 40ed30a2b7c6f9f876d4c9a5de094bfdf6bef093..8f4f6a95965130820e03f46e22cfe795721bbfcb 100644 (file)
@@ -435,9 +435,6 @@ extern unsigned long *sparc_valid_addr_bitmap;
 #define kern_addr_valid(addr) \
        (test_bit(__pa((unsigned long)(addr))>>20, sparc_valid_addr_bitmap))
 
-extern int io_remap_page_range(struct vm_area_struct *vma,
-                              unsigned long from, unsigned long to,
-                              unsigned long size, pgprot_t prot, int space);
 extern int io_remap_pfn_range(struct vm_area_struct *vma,
                              unsigned long from, unsigned long pfn,
                              unsigned long size, pgprot_t prot);
index 32c9699367cf527c27348055d0f841879afc350a..5a7a1a8d29ac9ccbf09ea9fc5df220c4744432cb 100644 (file)
@@ -19,7 +19,6 @@
 #include <asm/ptrace.h>
 #include <asm/head.h>
 #include <asm/signal.h>
-#include <asm/segment.h>
 #include <asm/btfixup.h>
 #include <asm/page.h>
 
diff --git a/include/asm-sparc/segment.h b/include/asm-sparc/segment.h
deleted file mode 100644 (file)
index a1b7ffc..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __SPARC_SEGMENT_H
-#define __SPARC_SEGMENT_H
-
-/* Only here because we have some old header files that expect it.. */
-
-#endif
index c1154e3ecfdf53b3cbccffa88c032194e10316bc..09575b608adbb584b644adc3183eadacafe738bd 100644 (file)
@@ -29,6 +29,8 @@
 
 #define SO_SNDBUF      0x1001
 #define SO_RCVBUF      0x1002
+#define SO_SNDBUFFORCE 0x100a
+#define SO_RCVBUFFORCE 0x100b
 #define SO_ERROR       0x1007
 #define SO_TYPE                0x1008
 
index 898562ebe94c6d8e7abfbc75d8d9f22e0ffd8dc1..3557781a4bfd7082bb8bbe8dd1e3a5c8d2bc1f1d 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/threads.h>     /* NR_CPUS */
 #include <linux/thread_info.h>
 
-#include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/psr.h>
 #include <asm/ptrace.h>
index 9eabf6e61ccca66753b3ab213735f6cee7900402..42fc6ed9815690e563fceb6ca1590df9e86f5df4 100644 (file)
@@ -54,8 +54,6 @@ typedef unsigned long long u64;
 typedef u32 dma_addr_t;
 typedef u32 dma64_addr_t;
 
-typedef unsigned short kmem_bufctl_t;
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index 0a780e84a12b749fd6f1e4381407f34affcb895b..f8f1ec1f06e6ce840dc9cc5a7edc76ad03c63ebf 100644 (file)
 #define access_ok(type, addr, size)                                    \
        ({ (void)(type); __access_ok((unsigned long)(addr), size); })
 
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
-{
-       return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
 /*
  * The exception table consists of pairs of addresses: the first is the
  * address of an instruction that is allowed to fault, and the second is
index d80f3379669b4625e1be10b21c7498d9cbfb6080..e175afcf2cdeb852d712a40f51b87678dbb26521 100644 (file)
@@ -72,10 +72,10 @@ extern int atomic64_sub_ret(int, atomic64_t *);
 
 /* Atomic operations are already serializing */
 #ifdef CONFIG_SMP
-#define smp_mb__before_atomic_dec()    membar("#StoreLoad | #LoadLoad")
-#define smp_mb__after_atomic_dec()     membar("#StoreLoad | #StoreStore")
-#define smp_mb__before_atomic_inc()    membar("#StoreLoad | #LoadLoad")
-#define smp_mb__after_atomic_inc()     membar("#StoreLoad | #StoreStore")
+#define smp_mb__before_atomic_dec()    membar_storeload_loadload();
+#define smp_mb__after_atomic_dec()     membar_storeload_storestore();
+#define smp_mb__before_atomic_inc()    membar_storeload_loadload();
+#define smp_mb__after_atomic_inc()     membar_storeload_storestore();
 #else
 #define smp_mb__before_atomic_dec()    barrier()
 #define smp_mb__after_atomic_dec()     barrier()
diff --git a/include/asm-sparc64/auxvec.h b/include/asm-sparc64/auxvec.h
new file mode 100644 (file)
index 0000000..436a291
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __ASM_SPARC64_AUXVEC_H
+#define __ASM_SPARC64_AUXVEC_H
+
+#endif /* !(__ASM_SPARC64_AUXVEC_H) */
index 9c5e71970287fbaebb37297315be05dcce55bcb3..6388b8376c50227bc8609d87a40e52451f74a435 100644 (file)
@@ -72,8 +72,8 @@ static inline int __test_and_change_bit(int nr, volatile unsigned long *addr)
 }
 
 #ifdef CONFIG_SMP
-#define smp_mb__before_clear_bit()     membar("#StoreLoad | #LoadLoad")
-#define smp_mb__after_clear_bit()      membar("#StoreLoad | #StoreStore")
+#define smp_mb__before_clear_bit()     membar_storeload_loadload()
+#define smp_mb__after_clear_bit()      membar_storeload_storestore()
 #else
 #define smp_mb__before_clear_bit()     barrier()
 #define smp_mb__after_clear_bit()      barrier()
index b59122dd176dd0583fd7a1a60b0cb0303927f73c..c73935dc7ba11c8e800b79596d6ae27e3431fd30 100644 (file)
@@ -12,8 +12,10 @@ typedef s32          compat_ssize_t;
 typedef s32            compat_time_t;
 typedef s32            compat_clock_t;
 typedef s32            compat_pid_t;
-typedef u16            compat_uid_t;
-typedef u16            compat_gid_t;
+typedef u16            __compat_uid_t;
+typedef u16            __compat_gid_t;
+typedef u32            __compat_uid32_t;
+typedef u32            __compat_gid32_t;
 typedef u16            compat_mode_t;
 typedef u32            compat_ino_t;
 typedef u16            compat_dev_t;
@@ -47,8 +49,8 @@ struct compat_stat {
        compat_ino_t    st_ino;
        compat_mode_t   st_mode;
        compat_nlink_t  st_nlink;
-       compat_uid_t    st_uid;
-       compat_gid_t    st_gid;
+       __compat_uid_t  st_uid;
+       __compat_gid_t  st_gid;
        compat_dev_t    st_rdev;
        compat_off_t    st_size;
        compat_time_t   st_atime;
@@ -177,10 +179,10 @@ static __inline__ void __user *compat_alloc_user_space(long len)
 
 struct compat_ipc64_perm {
        compat_key_t key;
-       __kernel_uid_t uid;
-       __kernel_gid_t gid;
-       __kernel_uid_t cuid;
-       __kernel_gid_t cgid;
+       __compat_uid32_t uid;
+       __compat_gid32_t gid;
+       __compat_uid32_t cuid;
+       __compat_gid32_t cgid;
        unsigned short __pad1;
        compat_mode_t mode;
        unsigned short __pad2;
index cc7198aaac505ee25072d5ac26da06df233aef82..9a3a81f1cc58ab7ba06c7e4290fc851a44ed570c 100644 (file)
@@ -1,6 +1,6 @@
 /* cpudata.h: Per-cpu parameters.
  *
- * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2003, 2005 David S. Miller (davem@redhat.com)
  */
 
 #ifndef _SPARC64_CPUDATA_H
@@ -10,7 +10,7 @@
 
 typedef struct {
        /* Dcache line 1 */
-       unsigned int    __pad0;         /* bh_count moved to irq_stat for consistency. KAO */
+       unsigned int    __softirq_pending; /* must be 1st, see rtrap.S */
        unsigned int    multiplier;
        unsigned int    counter;
        unsigned int    idle_volume;
index e36def0d0d809de784e850648afb0b939581ccef..b2aecf0054bd2167b990ddc2da53dec57458aca9 100644 (file)
@@ -4,10 +4,6 @@
 
 /* open/fcntl - O_SYNC is only implemented on blocks devices and on files
    located on an ext2 file system */
-#define O_RDONLY       0x0000
-#define O_WRONLY       0x0001
-#define O_RDWR         0x0002
-#define O_ACCMODE      0x0003
 #define O_NDELAY       0x0004
 #define O_APPEND       0x0008
 #define FASYNC         0x0040  /* fcntl, for BSD compatibility */
 #define O_SYNC         0x2000
 #define O_NONBLOCK     0x4000
 #define O_NOCTTY       0x8000  /* not fcntl */
-#define O_DIRECTORY    0x10000 /* must be a directory */
-#define O_NOFOLLOW     0x20000 /* don't follow links */
 #define O_LARGEFILE    0x40000
 #define O_DIRECT        0x100000 /* direct disk access hint */
 #define O_NOATIME      0x200000
 
 
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
 #define F_GETOWN       5       /*  for sockets. */
 #define F_SETOWN       6       /*  for sockets. */
 #define F_GETLK                7
 #define F_SETLK                8
 #define F_SETLKW       9
-#define F_SETSIG       10      /*  for sockets. */
-#define F_GETSIG       11      /*  for sockets. */
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
 
 /* for posix fcntl() and lockf() */
 #define F_RDLCK                1
 #define F_WRLCK                2
 #define F_UNLCK                3
 
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
-
-struct flock {
-       short l_type;
-       short l_whence;
-       off_t l_start;
-       off_t l_len;
-       pid_t l_pid;
-       short __unused;
-};
+#define __ARCH_FLOCK_PAD       short __unused;
 
-#define F_LINUX_SPECIFIC_BASE  1024
+#include <asm-generic/fcntl.h>
 
 #endif /* !(_SPARC64_FCNTL_H) */
diff --git a/include/asm-sparc64/futex.h b/include/asm-sparc64/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
index d6db1aed7645d0504b75476536d52010a8843e2f..f0cf71376ec5b11436220f73b06ae1c329cee559 100644 (file)
@@ -1,22 +1,16 @@
 /* hardirq.h: 64-bit Sparc hard IRQ support.
  *
- * Copyright (C) 1997, 1998 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 1998, 2005 David S. Miller (davem@davemloft.net)
  */
 
 #ifndef __SPARC64_HARDIRQ_H
 #define __SPARC64_HARDIRQ_H
 
-#include <linux/config.h>
-#include <linux/threads.h>
-#include <linux/spinlock.h>
-#include <linux/cache.h>
+#include <asm/cpudata.h>
 
-/* rtrap.S is sensitive to the offsets of these fields */
-typedef struct {
-       unsigned int __softirq_pending;
-} ____cacheline_aligned irq_cpustat_t;
-
-#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+#define __ARCH_IRQ_STAT
+#define local_softirq_pending() \
+       (local_cpu_data().__softirq_pending)
 
 #define HARDIRQ_BITS   8
 
diff --git a/include/asm-sparc64/hdreg.h b/include/asm-sparc64/hdreg.h
deleted file mode 100644 (file)
index 7f7fd1a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/hdreg.h>
index afdcea90707a7a54f004d8e519877e2dab77d3db..0056770e83ada176fc091dba50be956dcaf7841f 100644 (file)
@@ -100,18 +100,41 @@ static __inline__ void _outl(u32 l, unsigned long addr)
 #define inl_p(__addr)          inl(__addr)
 #define outl_p(__l, __addr)    outl(__l, __addr)
 
-extern void outsb(void __iomem *addr, const void *src, unsigned long count);
-extern void outsw(void __iomem *addr, const void *src, unsigned long count);
-extern void outsl(void __iomem *addr, const void *src, unsigned long count);
-extern void insb(void __iomem *addr, void *dst, unsigned long count);
-extern void insw(void __iomem *addr, void *dst, unsigned long count);
-extern void insl(void __iomem *addr, void *dst, unsigned long count);
-#define ioread8_rep(a,d,c)     insb(a,d,c)
-#define ioread16_rep(a,d,c)    insw(a,d,c)
-#define ioread32_rep(a,d,c)    insl(a,d,c)
-#define iowrite8_rep(a,s,c)    outsb(a,s,c)
-#define iowrite16_rep(a,s,c)   outsw(a,s,c)
-#define iowrite32_rep(a,s,c)   outsl(a,s,c)
+extern void outsb(unsigned long, const void *, unsigned long);
+extern void outsw(unsigned long, const void *, unsigned long);
+extern void outsl(unsigned long, const void *, unsigned long);
+extern void insb(unsigned long, void *, unsigned long);
+extern void insw(unsigned long, void *, unsigned long);
+extern void insl(unsigned long, void *, unsigned long);
+
+static inline void ioread8_rep(void __iomem *port, void *buf, unsigned long count)
+{
+       insb((unsigned long __force)port, buf, count);
+}
+static inline void ioread16_rep(void __iomem *port, void *buf, unsigned long count)
+{
+       insw((unsigned long __force)port, buf, count);
+}
+
+static inline void ioread32_rep(void __iomem *port, void *buf, unsigned long count)
+{
+       insl((unsigned long __force)port, buf, count);
+}
+
+static inline void iowrite8_rep(void __iomem *port, const void *buf, unsigned long count)
+{
+       outsb((unsigned long __force)port, buf, count);
+}
+
+static inline void iowrite16_rep(void __iomem *port, const void *buf, unsigned long count)
+{
+       outsw((unsigned long __force)port, buf, count);
+}
+
+static inline void iowrite32_rep(void __iomem *port, const void *buf, unsigned long count)
+{
+       outsl((unsigned long __force)port, buf, count);
+}
 
 /* Memory functions, same as I/O accesses on Ultra. */
 static inline u8 _readb(const volatile void __iomem *addr)
index b87dbbd64bc9ca723e3077521cb5cd87af63906e..c9f8ef208ea52529aea888637e7bc8014df6f975 100644 (file)
@@ -150,20 +150,6 @@ struct sparc_phys_banks {
 
 extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
 
-/* Pure 2^n version of get_order */
-static __inline__ int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size-1) >> (PAGE_SHIFT-1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
-
 #endif /* !(__ASSEMBLY__) */
 
 #define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
@@ -171,4 +157,6 @@ static __inline__ int get_order(unsigned long size)
 
 #endif /* !(__KERNEL__) */
 
+#include <asm-generic/page.h>
+
 #endif /* !(_SPARC64_PAGE_H) */
index 1ae00c5087f10d6eb3a0c2ea8c6ade9ff304774b..a2b4f5ed46256c69ffd6597e7bc37b9c1ceb603a 100644 (file)
@@ -410,9 +410,6 @@ extern unsigned long *sparc64_valid_addr_bitmap;
 #define kern_addr_valid(addr)  \
        (test_bit(__pa((unsigned long)(addr))>>22, sparc64_valid_addr_bitmap))
 
-extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from,
-                              unsigned long offset,
-                              unsigned long size, pgprot_t prot, int space);
 extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
                               unsigned long pfn,
                               unsigned long size, pgprot_t prot);
index d0bee2413560147a62b4f7f1af7ea7f781e0b847..3169f3e2237efb91769521f0b66a9b898d7df060 100644 (file)
@@ -18,7 +18,6 @@
 #include <asm/a.out.h>
 #include <asm/pstate.h>
 #include <asm/ptrace.h>
-#include <asm/segment.h>
 #include <asm/page.h>
 
 /* The sparc has no problems with write protection */
diff --git a/include/asm-sparc64/segment.h b/include/asm-sparc64/segment.h
deleted file mode 100644 (file)
index b03e709..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __SPARC64_SEGMENT_H
-#define __SPARC64_SEGMENT_H
-
-/* Only here because we have some old header files that expect it.. */
-
-#endif
diff --git a/include/asm-sparc64/sfafsr.h b/include/asm-sparc64/sfafsr.h
new file mode 100644 (file)
index 0000000..2f792c2
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef _SPARC64_SFAFSR_H
+#define _SPARC64_SFAFSR_H
+
+#include <asm/const.h>
+
+/* Spitfire Asynchronous Fault Status register, ASI=0x4C VA<63:0>=0x0 */
+
+#define SFAFSR_ME              (_AC(1,UL) << SFAFSR_ME_SHIFT)
+#define SFAFSR_ME_SHIFT                32
+#define SFAFSR_PRIV            (_AC(1,UL) << SFAFSR_PRIV_SHIFT)
+#define SFAFSR_PRIV_SHIFT      31
+#define SFAFSR_ISAP            (_AC(1,UL) << SFAFSR_ISAP_SHIFT)
+#define SFAFSR_ISAP_SHIFT      30
+#define SFAFSR_ETP             (_AC(1,UL) << SFAFSR_ETP_SHIFT)
+#define SFAFSR_ETP_SHIFT       29
+#define SFAFSR_IVUE            (_AC(1,UL) << SFAFSR_IVUE_SHIFT)
+#define SFAFSR_IVUE_SHIFT      28
+#define SFAFSR_TO              (_AC(1,UL) << SFAFSR_TO_SHIFT)
+#define SFAFSR_TO_SHIFT                27
+#define SFAFSR_BERR            (_AC(1,UL) << SFAFSR_BERR_SHIFT)
+#define SFAFSR_BERR_SHIFT      26
+#define SFAFSR_LDP             (_AC(1,UL) << SFAFSR_LDP_SHIFT)
+#define SFAFSR_LDP_SHIFT       25
+#define SFAFSR_CP              (_AC(1,UL) << SFAFSR_CP_SHIFT)
+#define SFAFSR_CP_SHIFT                24
+#define SFAFSR_WP              (_AC(1,UL) << SFAFSR_WP_SHIFT)
+#define SFAFSR_WP_SHIFT                23
+#define SFAFSR_EDP             (_AC(1,UL) << SFAFSR_EDP_SHIFT)
+#define SFAFSR_EDP_SHIFT       22
+#define SFAFSR_UE              (_AC(1,UL) << SFAFSR_UE_SHIFT)
+#define SFAFSR_UE_SHIFT                21
+#define SFAFSR_CE              (_AC(1,UL) << SFAFSR_CE_SHIFT)
+#define SFAFSR_CE_SHIFT                20
+#define SFAFSR_ETS             (_AC(0xf,UL) << SFAFSR_ETS_SHIFT)
+#define SFAFSR_ETS_SHIFT       16
+#define SFAFSR_PSYND           (_AC(0xffff,UL) << SFAFSR_PSYND_SHIFT)
+#define SFAFSR_PSYND_SHIFT     0
+
+/* UDB Error Register, ASI=0x7f VA<63:0>=0x0(High),0x18(Low) for read
+ *                     ASI=0x77 VA<63:0>=0x0(High),0x18(Low) for write
+ */
+
+#define UDBE_UE                        (_AC(1,UL) << 9)
+#define UDBE_CE                        (_AC(1,UL) << 8)
+#define UDBE_E_SYNDR           (_AC(0xff,UL) << 0)
+
+/* The trap handlers for asynchronous errors encode the AFSR and
+ * other pieces of information into a 64-bit argument for C code
+ * encoded as follows:
+ *
+ * -----------------------------------------------
+ * |  UDB_H  |  UDB_L  | TL>1  |  TT  |   AFSR   |
+ * -----------------------------------------------
+ *  63     54 53     44    42   41  33 32       0
+ *
+ * The AFAR is passed in unchanged.
+ */
+#define SFSTAT_UDBH_MASK       (_AC(0x3ff,UL) << SFSTAT_UDBH_SHIFT)
+#define SFSTAT_UDBH_SHIFT      54
+#define SFSTAT_UDBL_MASK       (_AC(0x3ff,UL) << SFSTAT_UDBH_SHIFT)
+#define SFSTAT_UDBL_SHIFT      44
+#define SFSTAT_TL_GT_ONE       (_AC(1,UL) << SFSTAT_TL_GT_ONE_SHIFT)
+#define SFSTAT_TL_GT_ONE_SHIFT 42
+#define SFSTAT_TRAP_TYPE       (_AC(0x1FF,UL) << SFSTAT_TRAP_TYPE_SHIFT)
+#define SFSTAT_TRAP_TYPE_SHIFT 33
+#define SFSTAT_AFSR_MASK       (_AC(0x1ffffffff,UL) << SFSTAT_AFSR_SHIFT)
+#define SFSTAT_AFSR_SHIFT      0
+
+/* ESTATE Error Enable Register, ASI=0x4b VA<63:0>=0x0 */
+#define ESTATE_ERR_CE          0x1 /* Correctable errors                    */
+#define ESTATE_ERR_NCE         0x2 /* TO, BERR, LDP, ETP, EDP, WP, UE, IVUE */
+#define ESTATE_ERR_ISAP                0x4 /* System address parity error           */
+#define ESTATE_ERR_ALL         (ESTATE_ERR_CE | \
+                                ESTATE_ERR_NCE | \
+                                ESTATE_ERR_ISAP)
+
+/* The various trap types that report using the above state. */
+#define TRAP_TYPE_IAE          0x09 /* Instruction Access Error             */
+#define TRAP_TYPE_DAE          0x32 /* Data Access Error                    */
+#define TRAP_TYPE_CEE          0x63 /* Correctable ECC Error                */
+
+#endif /* _SPARC64_SFAFSR_H */
index 865547a23908120b7e8c8eda37a08b78c1d047a9..59987dad3359912059a37039512dafc807c5d2df 100644 (file)
@@ -29,6 +29,8 @@
 
 #define SO_SNDBUF      0x1001
 #define SO_RCVBUF      0x1002
+#define SO_SNDBUFFORCE 0x100a
+#define SO_RCVBUFFORCE 0x100b
 #define SO_ERROR       0x1007
 #define SO_TYPE                0x1008
 
index 9cb93a5c2b4feac61ab2245c9ca17cb74997ded0..a02c4370eb42e0d1c8f6043a25f900e0ea03ff2c 100644 (file)
@@ -43,7 +43,7 @@ typedef struct {
 #define spin_is_locked(lp)  ((lp)->lock != 0)
 
 #define spin_unlock_wait(lp)   \
-do {   membar("#LoadLoad");    \
+do {   rmb();                  \
 } while((lp)->lock)
 
 static inline void _raw_spin_lock(spinlock_t *lock)
@@ -129,15 +129,18 @@ typedef struct {
 #define spin_is_locked(__lock) ((__lock)->lock != 0)
 #define spin_unlock_wait(__lock)       \
 do { \
-       membar("#LoadLoad"); \
+       rmb(); \
 } while((__lock)->lock)
 
-extern void _do_spin_lock (spinlock_t *lock, char *str);
-extern void _do_spin_unlock (spinlock_t *lock);
-extern int _do_spin_trylock (spinlock_t *lock);
+extern void _do_spin_lock(spinlock_t *lock, char *str, unsigned long caller);
+extern void _do_spin_unlock(spinlock_t *lock);
+extern int _do_spin_trylock(spinlock_t *lock, unsigned long caller);
 
-#define _raw_spin_trylock(lp)  _do_spin_trylock(lp)
-#define _raw_spin_lock(lock)   _do_spin_lock(lock, "spin_lock")
+#define _raw_spin_trylock(lp)  \
+       _do_spin_trylock(lp, (unsigned long) __builtin_return_address(0))
+#define _raw_spin_lock(lock)   \
+       _do_spin_lock(lock, "spin_lock", \
+                     (unsigned long) __builtin_return_address(0))
 #define _raw_spin_unlock(lock) _do_spin_unlock(lock)
 #define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock)
 
@@ -279,37 +282,41 @@ typedef struct {
 #define RW_LOCK_UNLOCKED       (rwlock_t) { 0, 0, 0xff, { } }
 #define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
 
-extern void _do_read_lock(rwlock_t *rw, char *str);
-extern void _do_read_unlock(rwlock_t *rw, char *str);
-extern void _do_write_lock(rwlock_t *rw, char *str);
-extern void _do_write_unlock(rwlock_t *rw);
-extern int _do_write_trylock(rwlock_t *rw, char *str);
+extern void _do_read_lock(rwlock_t *rw, char *str, unsigned long caller);
+extern void _do_read_unlock(rwlock_t *rw, char *str, unsigned long caller);
+extern void _do_write_lock(rwlock_t *rw, char *str, unsigned long caller);
+extern void _do_write_unlock(rwlock_t *rw, unsigned long caller);
+extern int _do_write_trylock(rwlock_t *rw, char *str, unsigned long caller);
 
 #define _raw_read_lock(lock) \
 do {   unsigned long flags; \
        local_irq_save(flags); \
-       _do_read_lock(lock, "read_lock"); \
+       _do_read_lock(lock, "read_lock", \
+                     (unsigned long) __builtin_return_address(0)); \
        local_irq_restore(flags); \
 } while(0)
 
 #define _raw_read_unlock(lock) \
 do {   unsigned long flags; \
        local_irq_save(flags); \
-       _do_read_unlock(lock, "read_unlock"); \
+       _do_read_unlock(lock, "read_unlock", \
+                     (unsigned long) __builtin_return_address(0)); \
        local_irq_restore(flags); \
 } while(0)
 
 #define _raw_write_lock(lock) \
 do {   unsigned long flags; \
        local_irq_save(flags); \
-       _do_write_lock(lock, "write_lock"); \
+       _do_write_lock(lock, "write_lock", \
+                     (unsigned long) __builtin_return_address(0)); \
        local_irq_restore(flags); \
 } while(0)
 
 #define _raw_write_unlock(lock) \
 do {   unsigned long flags; \
        local_irq_save(flags); \
-       _do_write_unlock(lock); \
+       _do_write_unlock(lock, \
+                     (unsigned long) __builtin_return_address(0)); \
        local_irq_restore(flags); \
 } while(0)
 
@@ -317,7 +324,8 @@ do {        unsigned long flags; \
 ({     unsigned long flags; \
        int val; \
        local_irq_save(flags); \
-       val = _do_write_trylock(lock, "write_trylock"); \
+       val = _do_write_trylock(lock, "write_trylock", \
+                               (unsigned long) __builtin_return_address(0)); \
        local_irq_restore(flags); \
        val; \
 })
index ee4bdfc6b88f3a7b047da2361bb117bfbe312581..5e94c05dc2fccf08d6d6fd4440adbb017fd41edf 100644 (file)
@@ -28,6 +28,14 @@ enum sparc_cpu {
 #define ARCH_SUN4C_SUN4 0
 #define ARCH_SUN4 0
 
+extern void mb(void);
+extern void rmb(void);
+extern void wmb(void);
+extern void membar_storeload(void);
+extern void membar_storeload_storestore(void);
+extern void membar_storeload_loadload(void);
+extern void membar_storestore_loadstore(void);
+
 #endif
 
 #define setipl(__new_ipl) \
@@ -78,16 +86,11 @@ enum sparc_cpu {
 
 #define nop()          __asm__ __volatile__ ("nop")
 
-#define membar(type)   __asm__ __volatile__ ("membar " type : : : "memory")
-#define mb()           \
-       membar("#LoadLoad | #LoadStore | #StoreStore | #StoreLoad")
-#define rmb()          membar("#LoadLoad")
-#define wmb()          membar("#StoreStore")
 #define read_barrier_depends()         do { } while(0)
 #define set_mb(__var, __value) \
-       do { __var = __value; membar("#StoreLoad | #StoreStore"); } while(0)
+       do { __var = __value; membar_storeload_storestore(); } while(0)
 #define set_wmb(__var, __value) \
-       do { __var = __value; membar("#StoreStore"); } while(0)
+       do { __var = __value; wmb(); } while(0)
 
 #ifdef CONFIG_SMP
 #define smp_mb()       mb()
index 6248ed1a9a7a7be2f5822e58d9dce7c75b41a152..d0ee7f105838abadfb8b47504a6d0033d49347b8 100644 (file)
@@ -56,8 +56,6 @@ typedef unsigned long u64;
 typedef u32 dma_addr_t;
 typedef u64 dma64_addr_t;
 
-typedef unsigned short kmem_bufctl_t;
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index 5690142f82de3774d56faceee2539229ee0e382a..80a65d7e3dbff92308d2b4e1bf5e394e45c97551 100644 (file)
@@ -59,12 +59,6 @@ static inline int access_ok(int type, const void __user * addr, unsigned long si
        return 1;
 }
 
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
-{
-       return 0;
-}
-
 /*
  * The exception table consists of pairs of addresses: the first is the
  * address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-um/auxvec.h b/include/asm-um/auxvec.h
new file mode 100644 (file)
index 0000000..1e5e1c2
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __UM_AUXVEC_H
+#define __UM_AUXVEC_H
+
+#endif
diff --git a/include/asm-um/futex.h b/include/asm-um/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-um/hdreg.h b/include/asm-um/hdreg.h
deleted file mode 100644 (file)
index cf6363a..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __UM_HDREG_H
-#define __UM_HDREG_H
-
-#include "asm/arch/hdreg.h"
-
-#endif
index 095bb627b96a1d52be4cc1291f48c308449f65a1..2edb4f1f789cdb96e0208da409622db6f1eaa70b 100644 (file)
@@ -20,7 +20,15 @@ extern void force_flush_all(void);
 
 static inline void activate_mm(struct mm_struct *old, struct mm_struct *new)
 {
-       if (old != new)
+       /*
+        * This is called by fs/exec.c and fs/aio.c. In the first case, for an
+        * exec, we don't need to do anything as we're called from userspace
+        * and thus going to use a new host PID. In the second, we're called
+        * from a kernel thread, and thus need to go doing the mmap's on the
+        * host. Since they're very expensive, we want to avoid that as far as
+        * possible.
+        */
+       if (old != new && (current->flags & PF_BORROWED_MM))
                force_flush_all();
 }
 
index f58aedadeb4e3d88e222dcfeccfc7745a3cba5d4..bd850a249183d21399465a5b4a612c1f4b56d715 100644 (file)
@@ -116,24 +116,12 @@ extern void *to_virt(unsigned long phys);
 #define pfn_valid(pfn) ((pfn) < max_mapnr)
 #define virt_addr_valid(v) pfn_valid(phys_to_pfn(__pa(v)))
 
-/* Pure 2^n version of get_order */
-static __inline__ int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size-1) >> (PAGE_SHIFT-1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
-
 extern struct page *arch_validate(struct page *page, int mask, int order);
 #define HAVE_ARCH_VALIDATE
 
 extern void arch_free_page(struct page *page, int order);
 #define HAVE_ARCH_FREE_PAGE
 
+#include <asm-generic/page.h>
+
 #endif
index 8fcb2fc0a8920ddd54ea2cd90135b1f3ca0994a0..ea49411236dcf71334dc4dafbb152d33e720e6cc 100644 (file)
@@ -42,11 +42,13 @@ static inline void pte_free(struct page *pte)
 #define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
 
 #ifdef CONFIG_3_LEVEL_PGTABLES
-/*
- * In the 3-level case we free the pmds as part of the pgd.
- */
-#define pmd_free(x)                    do { } while (0)
-#define __pmd_free_tlb(tlb,x)          do { } while (0)
+
+extern __inline__ void pmd_free(pmd_t *pmd)
+{
+       free_page((unsigned long)pmd);
+}
+
+#define __pmd_free_tlb(tlb,x)   tlb_remove_page((tlb),virt_to_page(x))
 #endif
 
 #define check_pgt_cache()      do { } while (0)
index 9b3abc01d60e108e1304453f6c2205e90ec16d1d..ffe017f6b64b587f3863e3f3b5c70aec3e714744 100644 (file)
 static inline int pgd_newpage(pgd_t pgd)       { return 0; }
 static inline void pgd_mkuptodate(pgd_t pgd)   { }
 
-#define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
-
-static inline pte_t pte_mknewprot(pte_t pte)
-{
-       pte_val(pte) |= _PAGE_NEWPROT;
-       return(pte);
-}
-
-static inline pte_t pte_mknewpage(pte_t pte)
-{
-       pte_val(pte) |= _PAGE_NEWPAGE;
-       return(pte);
-}
-
-static inline void set_pte(pte_t *pteptr, pte_t pteval)
-{
-       /* If it's a swap entry, it needs to be marked _PAGE_NEWPAGE so
-        * fix_range knows to unmap it.  _PAGE_NEWPROT is specific to
-        * mapped pages.
-        */
-       *pteptr = pte_mknewpage(pteval);
-       if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr);
-}
-#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
-
 #define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval))
 
-#define pte_page(x) pfn_to_page(pte_pfn(x))
-#define pte_none(x) !(pte_val(x) & ~_PAGE_NEWPAGE)
 #define pte_pfn(x) phys_to_pfn(pte_val(x))
 #define pfn_pte(pfn, prot) __pte(pfn_to_phys(pfn) | pgprot_val(prot))
 #define pfn_pmd(pfn, prot) __pmd(pfn_to_phys(pfn) | pgprot_val(prot))
index 65e8bfc55fc415440e8021650b2b8fd39ecc87b1..786c2572728996879e7795fdf49d09bab7584802 100644 (file)
@@ -57,35 +57,6 @@ static inline int pgd_newpage(pgd_t pgd)
 
 static inline void pgd_mkuptodate(pgd_t pgd) { pgd_val(pgd) &= ~_PAGE_NEWPAGE; }
 
-
-#define pte_present(x) pte_get_bits(x, (_PAGE_PRESENT | _PAGE_PROTNONE))
-
-static inline pte_t pte_mknewprot(pte_t pte)
-{
-        pte_set_bits(pte, _PAGE_NEWPROT);
-       return(pte);
-}
-
-static inline pte_t pte_mknewpage(pte_t pte)
-{
-       pte_set_bits(pte, _PAGE_NEWPAGE);
-       return(pte);
-}
-
-static inline void set_pte(pte_t *pteptr, pte_t pteval)
-{
-       pte_copy(*pteptr, pteval);
-
-       /* If it's a swap entry, it needs to be marked _PAGE_NEWPAGE so
-        * fix_range knows to unmap it.  _PAGE_NEWPROT is specific to
-        * mapped pages.
-        */
-
-       *pteptr = pte_mknewpage(*pteptr);
-       if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr);
-}
-#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
-
 #define set_pmd(pmdptr, pmdval) set_64bit((phys_t *) (pmdptr), pmd_val(pmdval))
 
 static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
@@ -98,14 +69,11 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
         return pmd;
 }
 
-static inline void pmd_free(pmd_t *pmd){
-       free_page((unsigned long) pmd);
+extern inline void pud_clear (pud_t *pud)
+{
+        set_pud(pud, __pud(0));
 }
 
-#define __pmd_free_tlb(tlb,x)   do { } while (0)
-
-static inline void pud_clear (pud_t * pud) { }
-
 #define pud_page(pud) \
        ((struct page *) __va(pud_val(pud) & PAGE_MASK))
 
@@ -113,13 +81,6 @@ static inline void pud_clear (pud_t * pud) { }
 #define pmd_offset(pud, address) ((pmd_t *) pud_page(*(pud)) + \
                        pmd_index(address))
 
-#define pte_page(x) pfn_to_page(pte_pfn(x))
-
-static inline int pte_none(pte_t pte)
-{
-       return pte_is_zero(pte);
-}
-
 static inline unsigned long pte_pfn(pte_t pte)
 {
        return phys_to_pfn(pte_val(pte));
index a88040920311e7e7333d65e3610fe574b8ce4259..b48e0966ecd7b8b936a4be2a3e8cf06d9645edec 100644 (file)
 
 #define _PAGE_PRESENT  0x001
 #define _PAGE_NEWPAGE  0x002
-#define _PAGE_NEWPROT   0x004
-#define _PAGE_FILE     0x008   /* set:pagecache unset:swap */
-#define _PAGE_PROTNONE 0x010   /* If not present */
+#define _PAGE_NEWPROT  0x004
 #define _PAGE_RW       0x020
 #define _PAGE_USER     0x040
 #define _PAGE_ACCESSED 0x080
 #define _PAGE_DIRTY    0x100
+/* If _PAGE_PRESENT is clear, we use these: */
+#define _PAGE_FILE     0x008   /* nonlinear file mapping, saved PTE; unset:swap */
+#define _PAGE_PROTNONE 0x010   /* if the user mapped it with PROT_NONE;
+                                  pte_present gives true */
 
 #ifdef CONFIG_3_LEVEL_PGTABLES
 #include "asm/pgtable-3level.h"
@@ -151,10 +153,24 @@ extern unsigned long pg0[1024];
 
 #define pmd_page(pmd) phys_to_page(pmd_val(pmd) & PAGE_MASK)
 
+#define pte_page(x) pfn_to_page(pte_pfn(x))
 #define pte_address(x) (__va(pte_val(x) & PAGE_MASK))
 #define mk_phys(a, r) ((a) + (((unsigned long) r) << REGION_SHIFT))
 #define phys_addr(p) ((p) & ~REGION_MASK)
 
+#define pte_present(x) pte_get_bits(x, (_PAGE_PRESENT | _PAGE_PROTNONE))
+
+/*
+ * =================================
+ * Flags checking section.
+ * =================================
+ */
+
+static inline int pte_none(pte_t pte)
+{
+       return pte_is_zero(pte);
+}
+
 /*
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
@@ -210,6 +226,18 @@ static inline int pte_newprot(pte_t pte)
        return(pte_present(pte) && (pte_get_bits(pte, _PAGE_NEWPROT)));
 }
 
+/*
+ * =================================
+ * Flags setting section.
+ * =================================
+ */
+
+static inline pte_t pte_mknewprot(pte_t pte)
+{
+       pte_set_bits(pte, _PAGE_NEWPROT);
+       return(pte);
+}
+
 static inline pte_t pte_rdprotect(pte_t pte)
 { 
        pte_clear_bits(pte, _PAGE_USER);
@@ -278,6 +306,26 @@ static inline pte_t pte_mkuptodate(pte_t pte)
        return(pte); 
 }
 
+static inline pte_t pte_mknewpage(pte_t pte)
+{
+       pte_set_bits(pte, _PAGE_NEWPAGE);
+       return(pte);
+}
+
+static inline void set_pte(pte_t *pteptr, pte_t pteval)
+{
+       pte_copy(*pteptr, pteval);
+
+       /* If it's a swap entry, it needs to be marked _PAGE_NEWPAGE so
+        * fix_range knows to unmap it.  _PAGE_NEWPROT is specific to
+        * mapped pages.
+        */
+
+       *pteptr = pte_mknewpage(*pteptr);
+       if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr);
+}
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+
 extern phys_t page_to_phys(struct page *page);
 
 /*
diff --git a/include/asm-v850/auxvec.h b/include/asm-v850/auxvec.h
new file mode 100644 (file)
index 0000000..f493232
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __V850_AUXVEC_H__
+#define __V850_AUXVEC_H__
+
+#endif /* __V850_AUXVEC_H__ */
index 31d4b59612211fa3a33b912b19f3c5a74160aeae..3af4d56776ddfafe217e81fd5da095d83e29f19e 100644 (file)
@@ -1,87 +1,11 @@
 #ifndef __V850_FCNTL_H__
 #define __V850_FCNTL_H__
 
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
-   located on an ext2 file system */
-#define O_ACCMODE        0003
-#define O_RDONLY           00
-#define O_WRONLY           01
-#define O_RDWR             02
-#define O_CREAT                  0100  /* not fcntl */
-#define O_EXCL           0200  /* not fcntl */
-#define O_NOCTTY         0400  /* not fcntl */
-#define O_TRUNC                 01000  /* not fcntl */
-#define O_APPEND        02000
-#define O_NONBLOCK      04000
-#define O_NDELAY       O_NONBLOCK
-#define O_SYNC         010000
-#define FASYNC         020000  /* fcntl, for BSD compatibility */
 #define O_DIRECTORY    040000  /* must be a directory */
 #define O_NOFOLLOW     0100000 /* don't follow links */
 #define O_DIRECT       0200000 /* direct disk access hint - currently ignored */
 #define O_LARGEFILE    0400000
-#define O_NOATIME      01000000
 
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
-#define F_GETLK                5
-#define F_SETLK                6
-#define F_SETLKW       7
+#include <asm-generic/fcntl.h>
 
-#define F_SETOWN       8       /*  for sockets. */
-#define F_GETOWN       9       /*  for sockets. */
-#define F_SETSIG       10      /*  for sockets. */
-#define F_GETSIG       11      /*  for sockets. */
-
-#define F_GETLK64      12      /*  using 'struct flock64' */
-#define F_SETLK64      13
-#define F_SETLKW64     14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK                0
-#define F_WRLCK                1
-#define F_UNLCK                2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
-
-struct flock {
-       short l_type;
-       short l_whence;
-       off_t l_start;
-       off_t l_len;
-       pid_t l_pid;
-};
-
-struct flock64 {
-       short  l_type;
-       short  l_whence;
-       loff_t l_start;
-       loff_t l_len;
-       pid_t  l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE  1024
 #endif /* __V850_FCNTL_H__ */
diff --git a/include/asm-v850/futex.h b/include/asm-v850/futex.h
new file mode 100644 (file)
index 0000000..2cac5ec
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
index d6091622935d101df33649bbde47b6a28f7b40da..b4bc85e7b91a1440b0aafe6fc40d055a94498b8a 100644 (file)
@@ -98,25 +98,6 @@ typedef unsigned long pgprot_t;
 #define PAGE_ALIGN(addr)       (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
 
 
-#ifndef __ASSEMBLY__
-
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order (unsigned long size)
-{
-       int order;
-
-       size = (size-1) >> (PAGE_SHIFT-1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
-
-#endif /* !__ASSEMBLY__ */
-
-
 /* No current v850 processor has virtual memory.  */
 #define __virt_to_phys(addr)   (addr)
 #define __phys_to_virt(addr)   (addr)
@@ -144,4 +125,6 @@ extern __inline__ int get_order (unsigned long size)
 
 #endif /* KERNEL */
 
+#include <asm-generic/page.h>
+
 #endif /* __V850_PAGE_H__ */
index 213b852af53e83c77f151137d5ab483fca27f8c8..0240d366a0a4db32672c6e20c734efe21e32aa17 100644 (file)
@@ -14,6 +14,8 @@
 #define SO_BROADCAST   6
 #define SO_SNDBUF      7
 #define SO_RCVBUF      8
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
 #define SO_KEEPALIVE   9
 #define SO_OOBINLINE   10
 #define SO_NO_CHECK    11
index e7cfe5b33a103252e4f641eb2b9a80813a6bcae8..dcef5719687501bc39ceabff1c95e0d978996243 100644 (file)
@@ -59,8 +59,6 @@ typedef unsigned long long u64;
 
 typedef u32 dma_addr_t;
 
-typedef unsigned int kmem_bufctl_t;
-
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index 4386cfc6a8dda338cf7ed677f998e4834095221f..188b28597cf1f680a96f271fa7e3244ffdc74831 100644 (file)
@@ -27,12 +27,6 @@ extern inline int access_ok (int type, const void *addr, unsigned long size)
        return val >= (0x80 + NUM_CPU_IRQS*16) && val < 0xFFFFF000;
 }
 
-/* this function will go away soon - use access_ok() instead */
-extern inline int __deprecated verify_area (int type, const void *addr, unsigned long size)
-{
-       return access_ok (type, addr, size) ? 0 : -EFAULT;
-}
-
 /*
  * The exception table consists of pairs of addresses: the first is the
  * address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-x86_64/auxvec.h b/include/asm-x86_64/auxvec.h
new file mode 100644 (file)
index 0000000..2403c4c
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __ASM_X86_64_AUXVEC_H
+#define __ASM_X86_64_AUXVEC_H
+
+#endif
index d01356f01448188f4f8322c371b0899c2d47ae16..989469e8e0b7d756ce2d3a0e17d76c83d2763d3a 100644 (file)
@@ -64,7 +64,7 @@ static inline unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl)
                "  adcl $0, %0\n"
                "  notl %0\n"
                "2:"
-       /* Since the input registers which are loaded with iph and ipl
+       /* Since the input registers which are loaded with iph and ihl
           are modified, we must also specify them as outputs, or gcc
           will assume they contain their original values. */
        : "=r" (sum), "=r" (iph), "=r" (ihl)
index d0f453c5adfc6dd04edc3353ddd61750d5cc322e..f0155c38f639056f6c4f812fb8ad5ab345e090d0 100644 (file)
@@ -14,10 +14,10 @@ typedef s32         compat_ssize_t;
 typedef s32            compat_time_t;
 typedef s32            compat_clock_t;
 typedef s32            compat_pid_t;
-typedef u16            compat_uid_t;
-typedef u16            compat_gid_t;
-typedef u32            compat_uid32_t;
-typedef u32            compat_gid32_t;
+typedef u16            __compat_uid_t;
+typedef u16            __compat_gid_t;
+typedef u32            __compat_uid32_t;
+typedef u32            __compat_gid32_t;
 typedef u16            compat_mode_t;
 typedef u32            compat_ino_t;
 typedef u16            compat_dev_t;
@@ -52,8 +52,8 @@ struct compat_stat {
        compat_ino_t    st_ino;
        compat_mode_t   st_mode;
        compat_nlink_t  st_nlink;
-       compat_uid_t    st_uid;
-       compat_gid_t    st_gid;
+       __compat_uid_t  st_uid;
+       __compat_gid_t  st_gid;
        compat_dev_t    st_rdev;
        u16             __pad2;
        u32             st_size;
@@ -122,10 +122,10 @@ typedef u32               compat_sigset_word;
 
 struct compat_ipc64_perm {
        compat_key_t key;
-       compat_uid32_t uid;
-       compat_gid32_t gid;
-       compat_uid32_t cuid;
-       compat_gid32_t cgid;
+       __compat_uid32_t uid;
+       __compat_gid32_t gid;
+       __compat_uid32_t cuid;
+       __compat_gid32_t cgid;
        unsigned short mode;
        unsigned short __pad1;
        unsigned short seq;
index 4411f221c03789976a6b3f367cfeec7d06c7c2a4..46ab12db57397dfc44a7aa84f9c10ac5e97509d9 100644 (file)
@@ -1,76 +1 @@
-#ifndef _X86_64_FCNTL_H
-#define _X86_64_FCNTL_H
-
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
-   located on an ext2 file system */
-#define O_ACCMODE         0003
-#define O_RDONLY            00
-#define O_WRONLY            01
-#define O_RDWR              02
-#define O_CREAT                   0100 /* not fcntl */
-#define O_EXCL            0200 /* not fcntl */
-#define O_NOCTTY          0400 /* not fcntl */
-#define O_TRUNC                  01000 /* not fcntl */
-#define O_APPEND         02000
-#define O_NONBLOCK       04000
-#define O_NDELAY       O_NONBLOCK
-#define O_SYNC          010000
-#define FASYNC          020000 /* fcntl, for BSD compatibility */
-#define O_DIRECT        040000 /* direct disk access hint */
-#define O_LARGEFILE    0100000
-#define O_DIRECTORY    0200000 /* must be a directory */
-#define O_NOFOLLOW     0400000 /* don't follow links */
-#define O_NOATIME      01000000
-
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
-#define F_GETLK                5
-#define F_SETLK                6
-#define F_SETLKW       7
-
-#define F_SETOWN       8       /*  for sockets. */
-#define F_GETOWN       9       /*  for sockets. */
-#define F_SETSIG       10      /*  for sockets. */
-#define F_GETSIG       11      /*  for sockets. */
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK                0
-#define F_WRLCK                1
-#define F_UNLCK                2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock */
-#define LOCK_READ      64      /* ... Which allows concurrent read operations */
-#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
-#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
-
-struct flock {
-       short  l_type;
-       short  l_whence;
-       off_t l_start;
-       off_t l_len;
-       pid_t  l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE  1024
-
-#endif /* !_X86_64_FCNTL_H */
+#include <asm-generic/fcntl.h>
diff --git a/include/asm-x86_64/futex.h b/include/asm-x86_64/futex.h
new file mode 100644 (file)
index 0000000..8602c09
--- /dev/null
@@ -0,0 +1,98 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg) \
+  __asm__ __volatile (                                         \
+"1:    " insn "\n"                                             \
+"2:    .section .fixup,\"ax\"\n\
+3:     mov     %3, %1\n\
+       jmp     2b\n\
+       .previous\n\
+       .section __ex_table,\"a\"\n\
+       .align  8\n\
+       .quad   1b,3b\n\
+       .previous"                                              \
+       : "=r" (oldval), "=r" (ret), "=m" (*uaddr)              \
+       : "i" (-EFAULT), "m" (*uaddr), "0" (oparg), "1" (0))
+
+#define __futex_atomic_op2(insn, ret, oldval, uaddr, oparg) \
+  __asm__ __volatile (                                         \
+"1:    movl    %2, %0\n\
+       movl    %0, %3\n"                                       \
+       insn "\n"                                               \
+"2:    " LOCK_PREFIX "cmpxchgl %3, %2\n\
+       jnz     1b\n\
+3:     .section .fixup,\"ax\"\n\
+4:     mov     %5, %1\n\
+       jmp     3b\n\
+       .previous\n\
+       .section __ex_table,\"a\"\n\
+       .align  8\n\
+       .quad   1b,4b,2b,4b\n\
+       .previous"                                              \
+       : "=&a" (oldval), "=&r" (ret), "=m" (*uaddr),           \
+         "=&r" (tem)                                           \
+       : "r" (oparg), "i" (-EFAULT), "m" (*uaddr), "1" (0))
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret, tem;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+               __futex_atomic_op1("xchgl %0, %2", ret, oldval, uaddr, oparg);
+               break;
+       case FUTEX_OP_ADD:
+               __futex_atomic_op1(LOCK_PREFIX "xaddl %0, %2", ret, oldval,
+                                  uaddr, oparg);
+               break;
+       case FUTEX_OP_OR:
+               __futex_atomic_op2("orl %4, %3", ret, oldval, uaddr, oparg);
+               break;
+       case FUTEX_OP_ANDN:
+               __futex_atomic_op2("andl %4, %3", ret, oldval, uaddr, ~oparg);
+               break;
+       case FUTEX_OP_XOR:
+               __futex_atomic_op2("xorl %4, %3", ret, oldval, uaddr, oparg);
+               break;
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-x86_64/hdreg.h b/include/asm-x86_64/hdreg.h
deleted file mode 100644 (file)
index 5989bbc..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#warning this file is obsolete, please do not use it
index 431318764af60da58dae27c150deed7379676198..135ffaa0393b4d8aa5559241d0f512fb61251742 100644 (file)
@@ -28,7 +28,6 @@
 #define HPAGE_SIZE     ((1UL) << HPAGE_SHIFT)
 #define HPAGE_MASK     (~(HPAGE_SIZE - 1))
 #define HUGETLB_PAGE_ORDER     (HPAGE_SHIFT - PAGE_SHIFT)
-#define ARCH_HAS_HUGETLB_CLEAN_STALE_PGTABLE
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
@@ -92,20 +91,6 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 
 #include <asm/bug.h>
 
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
-{
-       int order;
-
-       size = (size-1) >> (PAGE_SHIFT-1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
-
 #endif /* __ASSEMBLY__ */
 
 #define PAGE_OFFSET            ((unsigned long)__PAGE_OFFSET)
@@ -141,4 +126,6 @@ extern __inline__ int get_order(unsigned long size)
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/page.h>
+
 #endif /* _X86_64_PAGE_H */
index 4e167b5ea8f31e3d4594c0fc56e5465441553264..5e0f2fdab0d35885f75f1177d54d18b4117808ec 100644 (file)
@@ -104,6 +104,19 @@ extern inline void pgd_clear (pgd_t * pgd)
 ((unsigned long) __va(pud_val(pud) & PHYSICAL_PAGE_MASK))
 
 #define ptep_get_and_clear(mm,addr,xp) __pte(xchg(&(xp)->pte, 0))
+
+static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long addr, pte_t *ptep, int full)
+{
+       pte_t pte;
+       if (full) {
+               pte = *ptep;
+               *ptep = __pte(0);
+       } else {
+               pte = ptep_get_and_clear(mm, addr, ptep);
+       }
+       return pte;
+}
+
 #define pte_same(a, b)         ((a).pte == (b).pte)
 
 #define PMD_SIZE       (1UL << PMD_SHIFT)
@@ -143,7 +156,7 @@ extern inline void pgd_clear (pgd_t * pgd)
 #define _PAGE_ACCESSED 0x020
 #define _PAGE_DIRTY    0x040
 #define _PAGE_PSE      0x080   /* 2MB page */
-#define _PAGE_FILE     0x040   /* set:pagecache, unset:swap */
+#define _PAGE_FILE     0x040   /* nonlinear file mapping, saved PTE; unset:swap */
 #define _PAGE_GLOBAL   0x100   /* Global TLB entry */
 
 #define _PAGE_PROTNONE 0x080   /* If not present */
@@ -247,6 +260,7 @@ static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
+#define __LARGE_PTE (_PAGE_PSE|_PAGE_PRESENT)
 static inline int pte_user(pte_t pte)          { return pte_val(pte) & _PAGE_USER; }
 extern inline int pte_read(pte_t pte)          { return pte_val(pte) & _PAGE_USER; }
 extern inline int pte_exec(pte_t pte)          { return pte_val(pte) & _PAGE_USER; }
@@ -254,8 +268,8 @@ extern inline int pte_dirty(pte_t pte)              { return pte_val(pte) & _PAGE_DIRTY; }
 extern inline int pte_young(pte_t pte)         { return pte_val(pte) & _PAGE_ACCESSED; }
 extern inline int pte_write(pte_t pte)         { return pte_val(pte) & _PAGE_RW; }
 static inline int pte_file(pte_t pte)          { return pte_val(pte) & _PAGE_FILE; }
+static inline int pte_huge(pte_t pte)          { return (pte_val(pte) & __LARGE_PTE) == __LARGE_PTE; }
 
-#define __LARGE_PTE (_PAGE_PSE|_PAGE_PRESENT)
 extern inline pte_t pte_rdprotect(pte_t pte)   { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; }
 extern inline pte_t pte_exprotect(pte_t pte)   { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; }
 extern inline pte_t pte_mkclean(pte_t pte)     { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; }
@@ -433,6 +447,7 @@ extern int kern_addr_valid(unsigned long addr);
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
 #define __HAVE_ARCH_PTE_SAME
 #include <asm-generic/pgtable.h>
index 85549e656eeb26aad35a50c973f8ea8b9a441bd2..a8321999448f840e256d142a3cf2a62cd62db120 100644 (file)
@@ -398,7 +398,7 @@ static inline void prefetch(void *x)
 #define ARCH_HAS_PREFETCHW 1
 static inline void prefetchw(void *x) 
 { 
-       alternative_input(ASM_NOP5,
+       alternative_input("prefetcht0 (%1)",
                          "prefetchw (%1)",
                          X86_FEATURE_3DNOW,
                          "r" (x));
@@ -437,6 +437,11 @@ static inline void prefetchw(void *x)
        outb((data), 0x23); \
 } while (0)
 
+static inline void serialize_cpu(void)
+{
+       __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
+}
+
 static inline void __monitor(const void *eax, unsigned long ecx,
                unsigned long edx)
 {
index d9a252ea8210d2677809339fd725fd948b3deeb8..f2cdbeae5d5ba17e453f24aa172f6076f9441f9b 100644 (file)
@@ -14,6 +14,8 @@
 #define SO_BROADCAST   6
 #define SO_SNDBUF      7
 #define SO_RCVBUF      8
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
 #define SO_KEEPALIVE   9
 #define SO_OOBINLINE   10
 #define SO_NO_CHECK    11
index 32bd1426b523dec2d2e251a9902295f6f628f023..c86c2e6793e2a87b55224a7d17f9dfa077ae75e3 100644 (file)
@@ -51,8 +51,6 @@ typedef u64 dma_addr_t;
 typedef u64 sector_t;
 #define HAVE_SECTOR_T
 
-typedef unsigned short kmem_bufctl_t;
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index 48f292752c96bac97900682b98e947651b701d6b..1bb8b8a24436b2387a348b8d0ae880e14d61c6c6 100644 (file)
 
 #define access_ok(type, addr, size) (__range_not_ok(addr,size) == 0)
 
-/* this function will go away soon - use access_ok() instead */
-extern inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
-{
-       return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
-
 /*
  * The exception table consists of pairs of addresses: the first is the
  * address of an instruction that is allowed to fault, and the second is
index d72bcb32ba4f74ce3d3863559f14170d8937d050..24f86f0e43cfd64c918fbe39b5b8cdb629ea9175 100644 (file)
@@ -66,7 +66,7 @@ typedef struct { volatile int counter; } atomic_t;
  *
  * Atomically adds @i to @v.
  */
-extern __inline__ void atomic_add(int i, atomic_t * v)
+static inline void atomic_add(int i, atomic_t * v)
 {
     unsigned int vval;
 
@@ -90,7 +90,7 @@ extern __inline__ void atomic_add(int i, atomic_t * v)
  *
  * Atomically subtracts @i from @v.
  */
-extern __inline__ void atomic_sub(int i, atomic_t *v)
+static inline void atomic_sub(int i, atomic_t *v)
 {
     unsigned int vval;
 
@@ -111,7 +111,7 @@ extern __inline__ void atomic_sub(int i, atomic_t *v)
  * We use atomic_{add|sub}_return to define other functions.
  */
 
-extern __inline__ int atomic_add_return(int i, atomic_t * v)
+static inline int atomic_add_return(int i, atomic_t * v)
 {
      unsigned int vval;
 
@@ -130,7 +130,7 @@ extern __inline__ int atomic_add_return(int i, atomic_t * v)
     return vval;
 }
 
-extern __inline__ int atomic_sub_return(int i, atomic_t * v)
+static inline int atomic_sub_return(int i, atomic_t * v)
 {
     unsigned int vval;
 
@@ -224,7 +224,7 @@ extern __inline__ int atomic_sub_return(int i, atomic_t * v)
 #define atomic_add_negative(i,v) (atomic_add_return((i),(v)) < 0)
 
 
-extern __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v)
+static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
 {
     unsigned int all_f = -1;
     unsigned int vval;
@@ -243,7 +243,7 @@ extern __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v)
        );
 }
 
-extern __inline__ void atomic_set_mask(unsigned int mask, atomic_t *v)
+static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
 {
     unsigned int vval;
 
diff --git a/include/asm-xtensa/auxvec.h b/include/asm-xtensa/auxvec.h
new file mode 100644 (file)
index 0000000..257dec7
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __XTENSA_AUXVEC_H
+#define __XTENSA_AUXVEC_H
+
+#endif
index 1a00fad19929fa0814457f11a1e3c6daef9fa045..81a797ae3abe1a8a3d4212a6ddb9645b27af3d01 100644 (file)
@@ -47,14 +47,14 @@ asmlinkage unsigned int csum_partial_copy_generic( const char *src, char *dst, i
  *     If you use these functions directly please don't forget the
  *     verify_area().
  */
-extern __inline__
+static inline
 unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
                                        int len, int sum)
 {
        return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
 }
 
-extern __inline__
+static inline
 unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
                                                int len, int sum, int *err_ptr)
 {
index 0a123d53a636722009633c4908d74925004f8223..1bc601ec3621a0bca23226ab8758f4a94e04cc84 100644 (file)
@@ -18,7 +18,7 @@
 
 extern unsigned long loops_per_jiffy;
 
-extern __inline__ void __delay(unsigned long loops)
+static inline void __delay(unsigned long loops)
 {
   /* 2 cycles per loop. */
   __asm__ __volatile__ ("1: addi %0, %0, -2; bgeui %0, 2, 1b"
index 48876bb727d213bc14a1df93f9bcac0d36b85a5e..ec066ae96caf166c09433442f2ac516d2c501c8c 100644 (file)
 
 /* open/fcntl - O_SYNC is only implemented on blocks devices and on files
    located on an ext2 file system */
-#define O_ACCMODE      0x0003
-#define O_RDONLY       0x0000
-#define O_WRONLY       0x0001
-#define O_RDWR         0x0002
 #define O_APPEND       0x0008
 #define O_SYNC         0x0010
 #define O_NONBLOCK     0x0080
 #define O_CREAT         0x0100 /* not fcntl */
-#define O_TRUNC                0x0200  /* not fcntl */
 #define O_EXCL         0x0400  /* not fcntl */
 #define O_NOCTTY       0x0800  /* not fcntl */
 #define FASYNC         0x1000  /* fcntl, for BSD compatibility */
 #define O_LARGEFILE    0x2000  /* allow large file opens - currently ignored */
 #define O_DIRECT       0x8000  /* direct disk access hint - currently ignored*/
-#define O_DIRECTORY    0x10000 /* must be a directory */
-#define O_NOFOLLOW     0x20000 /* don't follow links */
 #define O_NOATIME      0x100000
 
-#define O_NDELAY       O_NONBLOCK
-
-#define F_DUPFD                0       /* dup */
-#define F_GETFD                1       /* get close_on_exec */
-#define F_SETFD                2       /* set/clear close_on_exec */
-#define F_GETFL                3       /* get file->f_flags */
-#define F_SETFL                4       /* set file->f_flags */
 #define F_GETLK                14
 #define F_GETLK64       15
 #define F_SETLK                6
 
 #define F_SETOWN       24      /*  for sockets. */
 #define F_GETOWN       23      /*  for sockets. */
-#define F_SETSIG       10      /*  for sockets. */
-#define F_GETSIG       11      /*  for sockets. */
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK                0
-#define F_WRLCK                1
-#define F_UNLCK                2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK                4       /* or 3 */
-#define F_SHLCK                8       /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS   16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH                1       /* shared lock */
-#define LOCK_EX                2       /* exclusive lock */
-#define LOCK_NB                4       /* or'd with one of the above to prevent
-                                  blocking */
-#define LOCK_UN                8       /* remove lock */
-
-#define LOCK_MAND      32      /* This is a mandatory flock ... */
-#define LOCK_READ      64      /*  which allows concurrent read operations */
-#define LOCK_WRITE     128     /*  which allows concurrent write operations */
-#define LOCK_RW                192     /*  which allows concurrent read & write ops */
 
 typedef struct flock {
        short l_type;
@@ -96,6 +53,9 @@ struct flock64 {
        pid_t  l_pid;
 };
 
-#define F_LINUX_SPECIFIC_BASE  1024
+#define HAVE_ARCH_STRUCT_FLOCK
+#define HAVE_ARCH_STRUCT_FLOCK64
+
+#include <asm-generic/fcntl.h>
 
 #endif /* _XTENSA_FCNTL_H */
diff --git a/include/asm-xtensa/hdreg.h b/include/asm-xtensa/hdreg.h
deleted file mode 100644 (file)
index 64b8060..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * include/asm-xtensa/hdreg.h
- *
- * 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 (C) 2002 - 2005 Tensilica Inc.
- * Copyright (C) 1994-1996  Linus Torvalds & authors
- */
-
-#ifndef _XTENSA_HDREG_H
-#define _XTENSA_HDREG_H
-
-typedef unsigned int ide_ioreg_t;
-
-#endif
index 2c471c42ecfc40030a2185bca07db89695c35a86..c5c13985bbe1f013577fa2d371a086517bab8a7c 100644 (file)
@@ -41,12 +41,12 @@ static inline unsigned int _swapl (unsigned int v)
  * These are trivial on the 1:1 Linux/Xtensa mapping
  */
 
-extern inline unsigned long virt_to_phys(volatile void * address)
+static inline unsigned long virt_to_phys(volatile void * address)
 {
        return PHYSADDR((unsigned long)address);
 }
 
-extern inline void * phys_to_virt(unsigned long address)
+static inline void * phys_to_virt(unsigned long address)
 {
        return (void*) CACHED_ADDR(address);
 }
@@ -55,12 +55,12 @@ extern inline void * phys_to_virt(unsigned long address)
  * IO bus memory addresses are also 1:1 with the physical address
  */
 
-extern inline unsigned long virt_to_bus(volatile void * address)
+static inline unsigned long virt_to_bus(volatile void * address)
 {
        return PHYSADDR((unsigned long)address);
 }
 
-extern inline void * bus_to_virt (unsigned long address)
+static inline void * bus_to_virt (unsigned long address)
 {
        return (void *) CACHED_ADDR(address);
 }
@@ -69,17 +69,17 @@ extern inline void * bus_to_virt (unsigned long address)
  * Change "struct page" to physical address.
  */
 
-extern inline void *ioremap(unsigned long offset, unsigned long size)
+static inline void *ioremap(unsigned long offset, unsigned long size)
 {
         return (void *) CACHED_ADDR_IO(offset);
 }
 
-extern inline void *ioremap_nocache(unsigned long offset, unsigned long size)
+static inline void *ioremap_nocache(unsigned long offset, unsigned long size)
 {
         return (void *) BYPASS_ADDR_IO(offset);
 }
 
-extern inline void iounmap(void *addr)
+static inline void iounmap(void *addr)
 {
 }
 
index 1b0801548cd90ca5e30437b0d764f465bcd49d6e..364a7b057bfaa60b2e2336e7573e29193e4c451b 100644 (file)
@@ -199,13 +199,13 @@ extern pgd_t *current_pgd;
 #define ASID_FIRST_VERSION                                             \
        ((unsigned long)(~ASID_VERSION_MASK) + 1 + ASID_FIRST_NONRESERVED)
 
-extern inline void set_rasid_register (unsigned long val)
+static inline void set_rasid_register (unsigned long val)
 {
        __asm__ __volatile__ (" wsr %0, "__stringify(RASID)"\n\t"
                              " isync\n" : : "a" (val));
 }
 
-extern inline unsigned long get_rasid_register (void)
+static inline unsigned long get_rasid_register (void)
 {
        unsigned long tmp;
        __asm__ __volatile__ (" rsr %0, "__stringify(RASID)"\n\t" : "=a" (tmp));
@@ -215,7 +215,7 @@ extern inline unsigned long get_rasid_register (void)
 
 #if ((XCHAL_MMU_ASID_INVALID == 0) && (XCHAL_MMU_ASID_KERNEL == 1))
 
-extern inline void
+static inline void
 get_new_mmu_context(struct mm_struct *mm, unsigned long asid)
 {
        extern void flush_tlb_all(void);
@@ -234,7 +234,7 @@ get_new_mmu_context(struct mm_struct *mm, unsigned long asid)
 /* XCHAL_MMU_ASID_INVALID == 0 and XCHAL_MMU_ASID_KERNEL ==1 are
    really the best, but if you insist... */
 
-extern inline int validate_asid (unsigned long asid)
+static inline int validate_asid (unsigned long asid)
 {
        switch (asid) {
        case XCHAL_MMU_ASID_INVALID:
@@ -247,7 +247,7 @@ extern inline int validate_asid (unsigned long asid)
        return 1; /* valid */
 }
 
-extern inline void
+static inline void
 get_new_mmu_context(struct mm_struct *mm, unsigned long asid)
 {
        extern void flush_tlb_all(void);
@@ -274,14 +274,14 @@ get_new_mmu_context(struct mm_struct *mm, unsigned long asid)
  * instance.
  */
 
-extern inline int
+static inline int
 init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
        mm->context = NO_CONTEXT;
        return 0;
 }
 
-extern inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
                              struct task_struct *tsk)
 {
        unsigned long asid = asid_cache;
@@ -301,7 +301,7 @@ extern inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
  * Destroy context related info for an mm_struct that is about
  * to be put to rest.
  */
-extern inline void destroy_context(struct mm_struct *mm)
+static inline void destroy_context(struct mm_struct *mm)
 {
        /* Nothing to do. */
 }
@@ -310,7 +310,7 @@ extern inline void destroy_context(struct mm_struct *mm)
  * After we have set current->mm to a new value, this activates
  * the context for the new mm so we see the new mappings.
  */
-extern inline void
+static inline void
 activate_mm(struct mm_struct *prev, struct mm_struct *next)
 {
        /* Unconditionally get a new ASID.  */
index b495e5b5a9427bddae499243a634d6583711b9ae..8ded36f255a2847a12f629e38db3c3ab2dab0921 100644 (file)
@@ -55,7 +55,7 @@ typedef struct { unsigned long pgprot; } pgprot_t;
  * Pure 2^n version of get_order
  */
 
-extern __inline__ int get_order(unsigned long size)
+static inline int get_order(unsigned long size)
 {
        int order;
 #ifndef XCHAL_HAVE_NSU
diff --git a/include/asm-xtensa/page.h.n b/include/asm-xtensa/page.h.n
deleted file mode 100644 (file)
index 546cc66..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * linux/include/asm-xtensa/page.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version2 as
- * published by the Free Software Foundation.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- */
-
-#ifndef _XTENSA_PAGE_H
-#define _XTENSA_PAGE_H
-
-#ifdef __KERNEL__
-
-#include <asm/processor.h>
-#include <linux/config.h>
-
-/*
- * PAGE_SHIFT determines the page size
- * PAGE_ALIGN(x) aligns the pointer to the (next) page boundary
- */
-#define PAGE_SHIFT             XCHAL_MMU_MIN_PTE_PAGE_SIZE
-#define PAGE_SIZE              (1 << PAGE_SHIFT)
-#define PAGE_MASK              (~(PAGE_SIZE-1))
-#define PAGE_ALIGN(addr)       (((addr)+PAGE_SIZE - 1) & PAGE_MASK)
-
-#define DCACHE_WAY_SIZE                (XCHAL_DCACHE_SIZE / XCHAL_DCACHE_WAYS)
-#define PAGE_OFFSET            XCHAL_KSEG_CACHED_VADDR
-
-#ifdef __ASSEMBLY__
-
-#define __pgprot(x)    (x)
-
-#else
-
-
-/*
- * These are used to make use of C type-checking..
- */
-typedef struct { unsigned long pte; } pte_t;           /* page table entry */
-typedef struct { unsigned long pmd; } pmd_t;           /* PMD table entry */
-typedef struct { unsigned long pgd; } pgd_t;           /* PGD table entry */
-typedef struct { unsigned long pgprot; } pgprot_t;
-
-#define pte_val(x)     ((x).pte)
-#define pmd_val(x)     ((x).pmd)
-#define pgd_val(x)     ((x).pgd)
-#define pgprot_val(x)  ((x).pgprot)
-
-#define __pte(x)       ((pte_t) { (x) } )
-#define __pmd(x)       ((pmd_t) { (x) } )
-#define __pgd(x)       ((pgd_t) { (x) } )
-#define __pgprot(x)    ((pgprot_t) { (x) } )
-
-/*
- * Pure 2^n version of get_order
- */
-extern __inline__ int get_order(unsigned long size)
-{
-       int order;
-#ifndef XCHAL_HAVE_NSU
-       unsigned long x1, x2, x4, x8, x16;
-
-       size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       x1  = size & 0xAAAAAAAA;
-       x2  = size & 0xCCCCCCCC;
-       x4  = size & 0xF0F0F0F0;
-       x8  = size & 0xFF00FF00;
-       x16 = size & 0xFFFF0000;
-       order = x2 ? 2 : 0;
-       order += (x16 != 0) * 16;
-       order += (x8 != 0) * 8;
-       order += (x4 != 0) * 4;
-       order += (x1 != 0);
-
-       return order;
-#else
-       size = (size - 1) >> PAGE_SHIFT;
-       asm ("nsau %0, %1" : "=r" (order) : "r" (size));
-       return 32 - order;
-#endif
-}
-
-
-struct page;
-extern void clear_page(void *page);
-extern void copy_page(void *to, void *from);
-
-/*
- * If we have cache aliasing and writeback caches, we might have to do
- * some extra work
- */
-
-#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
-void clear_user_page(void *addr, unsigned long vaddr, struct page* page);
-void copy_user_page(void *to, void* from, unsigned long vaddr, struct page* page);
-#else
-# define clear_user_page(page,vaddr,pg)                clear_page(page)
-# define copy_user_page(to, from, vaddr, pg)   copy_page(to, from)
-#endif
-
-
-/*
- * This handles the memory map.  We handle pages at
- * XCHAL_KSEG_CACHED_VADDR for kernels with 32 bit address space.
- * These macros are for conversion of kernel address, not user
- * addresses.
- */
-
-#define __pa(x)                        ((unsigned long) (x) - PAGE_OFFSET)
-#define __va(x)                        ((void *)((unsigned long) (x) + PAGE_OFFSET))
-#define pfn_valid(pfn)         ((unsigned long)pfn < max_mapnr)
-#ifndef CONFIG_DISCONTIGMEM
-# define pfn_to_page(pfn)      (mem_map + (pfn))
-# define page_to_pfn(page)     ((unsigned long)((page) - mem_map))
-#else
-# error CONFIG_DISCONTIGMEM not supported
-#endif
-
-#define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
-#define page_to_virt(page)     __va(page_to_pfn(page) << PAGE_SHIFT)
-#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
-#define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
-
-#define WANT_PAGE_VIRTUAL
-
-
-#endif /* __ASSEMBLY__ */
-
-#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
-#endif /* __KERNEL__ */
-#endif /* _XTENSA_PAGE_H */
index 6817742301c22fa73697c6ffe837609a062f28ab..24eb7fc25da830c8fc4f74ac1b0c11efe1a677b8 100644 (file)
 
 extern struct pci_controller* pcibios_alloc_controller(void);
 
-extern inline void pcibios_set_master(struct pci_dev *dev)
+static inline void pcibios_set_master(struct pci_dev *dev)
 {
        /* No special bus mastering setup handling */
 }
 
-extern inline void pcibios_penalize_isa_irq(int irq)
+static inline void pcibios_penalize_isa_irq(int irq)
 {
        /* We don't do dynamic PCI IRQ allocation */
 }
index 0bb6416ae2660bcaafd39d92fe9cf90b19e799ab..883ebc2d75d69090f0c044e2556b7df9b324d965 100644 (file)
@@ -260,7 +260,7 @@ static inline pte_t pte_mkwrite(pte_t pte)  { pte_val(pte) |= _PAGE_RW; return pt
 #define pfn_pte(pfn, prot)     __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
 #define mk_pte(page, prot)     pfn_pte(page_to_pfn(page), prot)
 
-extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
        return __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot));
 }
@@ -278,14 +278,14 @@ static inline void update_pte(pte_t *ptep, pte_t pteval)
 #endif
 }
 
-extern inline void
+static inline void
 set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pteval)
 {
        update_pte(ptep, pteval);
 }
 
 
-extern inline void
+static inline void
 set_pmd(pmd_t *pmdp, pmd_t pmdval)
 {
        *pmdp = pmdval;
index c8a7574a9a57bc00e570e3910b325f21d06ef33b..db740b8bc6f058d006e09c96316a15ca4f8aa53b 100644 (file)
@@ -47,7 +47,7 @@ struct semaphore {
 #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
 #define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
 
-extern inline void sema_init (struct semaphore *sem, int val)
+static inline void sema_init (struct semaphore *sem, int val)
 {
 /*
  *     *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
@@ -79,7 +79,7 @@ asmlinkage void __up(struct semaphore * sem);
 
 extern spinlock_t semaphore_wake_lock;
 
-extern __inline__ void down(struct semaphore * sem)
+static inline void down(struct semaphore * sem)
 {
 #if WAITQUEUE_DEBUG
        CHECK_MAGIC(sem->__magic);
@@ -89,7 +89,7 @@ extern __inline__ void down(struct semaphore * sem)
                __down(sem);
 }
 
-extern __inline__ int down_interruptible(struct semaphore * sem)
+static inline int down_interruptible(struct semaphore * sem)
 {
        int ret = 0;
 #if WAITQUEUE_DEBUG
@@ -101,7 +101,7 @@ extern __inline__ int down_interruptible(struct semaphore * sem)
        return ret;
 }
 
-extern __inline__ int down_trylock(struct semaphore * sem)
+static inline int down_trylock(struct semaphore * sem)
 {
        int ret = 0;
 #if WAITQUEUE_DEBUG
@@ -117,7 +117,7 @@ extern __inline__ int down_trylock(struct semaphore * sem)
  * Note! This is subtle. We jump to wake people up only if
  * the semaphore was negative (== somebody was waiting on it).
  */
-extern __inline__ void up(struct semaphore * sem)
+static inline void up(struct semaphore * sem)
 {
 #if WAITQUEUE_DEBUG
        CHECK_MAGIC(sem->__magic);
index daccd05a14cdfdb7cee689951f3b22e3b7926c59..00f83f3a6d72194ad0b0f3059897cecde2d61e0f 100644 (file)
@@ -24,6 +24,8 @@
 #define SO_BROADCAST   6
 #define SO_SNDBUF      7
 #define SO_RCVBUF      8
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
 #define SO_KEEPALIVE   9
 #define SO_OOBINLINE   10
 #define SO_NO_CHECK    11
index 3f81b27d98091e1e94eacf1f098fa2b670d61c75..5fb8c27cbef58dd98cb3847e2bc1b286fdad1cd3 100644 (file)
@@ -16,7 +16,7 @@
 #define _XTENSA_STRING_H
 
 #define __HAVE_ARCH_STRCPY
-extern __inline__ char *strcpy(char *__dest, const char *__src)
+static inline char *strcpy(char *__dest, const char *__src)
 {
        register char *__xdest = __dest;
        unsigned long __dummy;
@@ -35,7 +35,7 @@ extern __inline__ char *strcpy(char *__dest, const char *__src)
 }
 
 #define __HAVE_ARCH_STRNCPY
-extern __inline__ char *strncpy(char *__dest, const char *__src, size_t __n)
+static inline char *strncpy(char *__dest, const char *__src, size_t __n)
 {
        register char *__xdest = __dest;
        unsigned long __dummy;
@@ -60,7 +60,7 @@ extern __inline__ char *strncpy(char *__dest, const char *__src, size_t __n)
 }
 
 #define __HAVE_ARCH_STRCMP
-extern __inline__ int strcmp(const char *__cs, const char *__ct)
+static inline int strcmp(const char *__cs, const char *__ct)
 {
        register int __res;
        unsigned long __dummy;
@@ -82,7 +82,7 @@ extern __inline__ int strcmp(const char *__cs, const char *__ct)
 }
 
 #define __HAVE_ARCH_STRNCMP
-extern __inline__ int strncmp(const char *__cs, const char *__ct, size_t __n)
+static inline int strncmp(const char *__cs, const char *__ct, size_t __n)
 {
        register int __res;
        unsigned long __dummy;
index 690fe325e67116861518bc059fe4ccd43ade27ef..f09393232e5e9c58dad7c84258f076b1d3414933 100644 (file)
@@ -56,7 +56,7 @@ static inline int irqs_disabled(void)
 
 #define clear_cpenable() __clear_cpenable()
 
-extern __inline__ void __clear_cpenable(void)
+static inline void __clear_cpenable(void)
 {
 #if XCHAL_HAVE_CP
        unsigned long i = 0;
@@ -64,7 +64,7 @@ extern __inline__ void __clear_cpenable(void)
 #endif
 }
 
-extern __inline__ void enable_coprocessor(int i)
+static inline void enable_coprocessor(int i)
 {
 #if XCHAL_HAVE_CP
        int cp;
@@ -74,7 +74,7 @@ extern __inline__ void enable_coprocessor(int i)
 #endif
 }
 
-extern __inline__ void disable_coprocessor(int i)
+static inline void disable_coprocessor(int i)
 {
 #if XCHAL_HAVE_CP
        int cp;
@@ -123,7 +123,7 @@ do {                                                \
  * cmpxchg
  */
 
-extern __inline__ unsigned long
+static inline unsigned long
 __cmpxchg_u32(volatile int *p, int old, int new)
 {
   __asm__ __volatile__("rsil    a15, "__stringify(LOCKLEVEL)"\n\t"
@@ -173,7 +173,7 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
  * where no register reference will cause an overflow.
  */
 
-extern __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val)
+static inline unsigned long xchg_u32(volatile int * m, unsigned long val)
 {
   unsigned long tmp;
   __asm__ __volatile__("rsil    a15, "__stringify(LOCKLEVEL)"\n\t"
index 23bfe9db45f5de0dd4e664566b98d4ab91a06214..43f6ec859af92fccd699bcc918f01a3467fa63d4 100644 (file)
@@ -39,7 +39,7 @@ extern void flush_tlb_range(struct vm_area_struct*,unsigned long,unsigned long);
  * page-table pages.
  */
 
-extern inline void flush_tlb_pgtables(struct mm_struct *mm,
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
                                       unsigned long start, unsigned long end)
 {
 }
@@ -51,26 +51,26 @@ extern inline void flush_tlb_pgtables(struct mm_struct *mm,
 #define ITLB_PROBE_SUCCESS  (1 << ITLB_WAYS_LOG2)
 #define DTLB_PROBE_SUCCESS  (1 << DTLB_WAYS_LOG2)
 
-extern inline unsigned long itlb_probe(unsigned long addr)
+static inline unsigned long itlb_probe(unsigned long addr)
 {
        unsigned long tmp;
        __asm__ __volatile__("pitlb  %0, %1\n\t" : "=a" (tmp) : "a" (addr));
        return tmp;
 }
 
-extern inline unsigned long dtlb_probe(unsigned long addr)
+static inline unsigned long dtlb_probe(unsigned long addr)
 {
        unsigned long tmp;
        __asm__ __volatile__("pdtlb  %0, %1\n\t" : "=a" (tmp) : "a" (addr));
        return tmp;
 }
 
-extern inline void invalidate_itlb_entry (unsigned long probe)
+static inline void invalidate_itlb_entry (unsigned long probe)
 {
        __asm__ __volatile__("iitlb  %0; isync\n\t" : : "a" (probe));
 }
 
-extern inline void invalidate_dtlb_entry (unsigned long probe)
+static inline void invalidate_dtlb_entry (unsigned long probe)
 {
        __asm__ __volatile__("idtlb  %0; dsync\n\t" : : "a" (probe));
 }
@@ -80,68 +80,68 @@ extern inline void invalidate_dtlb_entry (unsigned long probe)
  * caller must follow up with an 'isync', which can be relatively
  * expensive on some Xtensa implementations.
  */
-extern inline void invalidate_itlb_entry_no_isync (unsigned entry)
+static inline void invalidate_itlb_entry_no_isync (unsigned entry)
 {
        /* Caller must follow up with 'isync'. */
        __asm__ __volatile__ ("iitlb  %0\n" : : "a" (entry) );
 }
 
-extern inline void invalidate_dtlb_entry_no_isync (unsigned entry)
+static inline void invalidate_dtlb_entry_no_isync (unsigned entry)
 {
        /* Caller must follow up with 'isync'. */
        __asm__ __volatile__ ("idtlb  %0\n" : : "a" (entry) );
 }
 
-extern inline void set_itlbcfg_register (unsigned long val)
+static inline void set_itlbcfg_register (unsigned long val)
 {
        __asm__ __volatile__("wsr  %0, "__stringify(ITLBCFG)"\n\t" "isync\n\t"
                             : : "a" (val));
 }
 
-extern inline void set_dtlbcfg_register (unsigned long val)
+static inline void set_dtlbcfg_register (unsigned long val)
 {
        __asm__ __volatile__("wsr  %0, "__stringify(DTLBCFG)"; dsync\n\t"
                             : : "a" (val));
 }
 
-extern inline void set_ptevaddr_register (unsigned long val)
+static inline void set_ptevaddr_register (unsigned long val)
 {
        __asm__ __volatile__(" wsr  %0, "__stringify(PTEVADDR)"; isync\n"
                             : : "a" (val));
 }
 
-extern inline unsigned long read_ptevaddr_register (void)
+static inline unsigned long read_ptevaddr_register (void)
 {
        unsigned long tmp;
        __asm__ __volatile__("rsr  %0, "__stringify(PTEVADDR)"\n\t" : "=a" (tmp));
        return tmp;
 }
 
-extern inline void write_dtlb_entry (pte_t entry, int way)
+static inline void write_dtlb_entry (pte_t entry, int way)
 {
        __asm__ __volatile__("wdtlb  %1, %0; dsync\n\t"
                             : : "r" (way), "r" (entry) );
 }
 
-extern inline void write_itlb_entry (pte_t entry, int way)
+static inline void write_itlb_entry (pte_t entry, int way)
 {
        __asm__ __volatile__("witlb  %1, %0; isync\n\t"
                             : : "r" (way), "r" (entry) );
 }
 
-extern inline void invalidate_page_directory (void)
+static inline void invalidate_page_directory (void)
 {
        invalidate_dtlb_entry (DTLB_WAY_PGTABLE);
 }
 
-extern inline void invalidate_itlb_mapping (unsigned address)
+static inline void invalidate_itlb_mapping (unsigned address)
 {
        unsigned long tlb_entry;
        while ((tlb_entry = itlb_probe (address)) & ITLB_PROBE_SUCCESS)
                invalidate_itlb_entry (tlb_entry);
 }
 
-extern inline void invalidate_dtlb_mapping (unsigned address)
+static inline void invalidate_dtlb_mapping (unsigned address)
 {
        unsigned long tlb_entry;
        while ((tlb_entry = dtlb_probe (address)) & DTLB_PROBE_SUCCESS)
@@ -165,28 +165,28 @@ extern inline void invalidate_dtlb_mapping (unsigned address)
  *      as[07..00] contain the asid
  */
 
-extern inline unsigned long read_dtlb_virtual (int way)
+static inline unsigned long read_dtlb_virtual (int way)
 {
        unsigned long tmp;
        __asm__ __volatile__("rdtlb0  %0, %1\n\t" : "=a" (tmp), "+a" (way));
        return tmp;
 }
 
-extern inline unsigned long read_dtlb_translation (int way)
+static inline unsigned long read_dtlb_translation (int way)
 {
        unsigned long tmp;
        __asm__ __volatile__("rdtlb1  %0, %1\n\t" : "=a" (tmp), "+a" (way));
        return tmp;
 }
 
-extern inline unsigned long read_itlb_virtual (int way)
+static inline unsigned long read_itlb_virtual (int way)
 {
        unsigned long tmp;
        __asm__ __volatile__("ritlb0  %0, %1\n\t" : "=a" (tmp), "+a" (way));
        return tmp;
 }
 
-extern inline unsigned long read_itlb_translation (int way)
+static inline unsigned long read_itlb_translation (int way)
 {
        unsigned long tmp;
        __asm__ __volatile__("ritlb1  %0, %1\n\t" : "=a" (tmp), "+a" (way));
index ebac004698520fab778f8a9c2298208a606395e6..9d99a8e9e337101af6fc2bb6881cabc85103915d 100644 (file)
@@ -58,8 +58,6 @@ typedef unsigned long long u64;
 
 typedef u32 dma_addr_t;
 
-typedef unsigned int kmem_bufctl_t;
-
 #endif /* __KERNEL__ */
 #endif
 
index 35576b25c7b2fe31ec6d1ef92c9cb9eea64b0034..fc268ac923c0b9a22200515fcb54e49329a09002 100644 (file)
 #define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
 #define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
 
-extern inline int verify_area(int type, const void * addr, unsigned long size)
+static inline int verify_area(int type, const void * addr, unsigned long size)
 {
        return access_ok(type,addr,size) ? 0 : -EFAULT;
 }
@@ -464,7 +464,7 @@ __generic_copy_from_user(void *to, const void *from, unsigned long n)
  * success.
  */
 
-extern inline unsigned long
+static inline unsigned long
 __xtensa_clear_user(void *addr, unsigned long size)
 {
        if ( ! memset(addr, 0, size) )
@@ -472,7 +472,7 @@ __xtensa_clear_user(void *addr, unsigned long size)
        return 0;
 }
 
-extern inline unsigned long
+static inline unsigned long
 clear_user(void *addr, unsigned long size)
 {
        if (access_ok(VERIFY_WRITE, addr, size))
@@ -486,7 +486,7 @@ clear_user(void *addr, unsigned long size)
 extern long __strncpy_user(char *, const char *, long);
 #define __strncpy_from_user __strncpy_user
 
-extern inline long
+static inline long
 strncpy_from_user(char *dst, const char *src, long count)
 {
        if (access_ok(VERIFY_READ, src, 1))
@@ -502,7 +502,7 @@ strncpy_from_user(char *dst, const char *src, long count)
  */
 extern long __strnlen_user(const char *, long);
 
-extern inline long strnlen_user(const char *str, long len)
+static inline long strnlen_user(const char *str, long len)
 {
        unsigned long top = __kernel_ok ? ~0UL : TASK_SIZE - 1;
 
index 5f3ab21b339b7abb32e6f06917c8b6e0eac58d06..3209dd46ea7d98ce0f846d07aad0222e39764606 100644 (file)
@@ -1,2 +1,37 @@
-int pci_siig10x_fn(struct pci_dev *dev, int enable);
-int pci_siig20x_fn(struct pci_dev *dev, int enable);
+/*
+ * Definitions for PCI support.
+ */
+#define FL_BASE_MASK           0x0007
+#define FL_BASE0               0x0000
+#define FL_BASE1               0x0001
+#define FL_BASE2               0x0002
+#define FL_BASE3               0x0003
+#define FL_BASE4               0x0004
+#define FL_GET_BASE(x)         (x & FL_BASE_MASK)
+
+/* Use successive BARs (PCI base address registers),
+   else use offset into some specified BAR */
+#define FL_BASE_BARS           0x0008
+
+/* do not assign an irq */
+#define FL_NOIRQ               0x0080
+
+/* Use the Base address register size to cap number of ports */
+#define FL_REGION_SZ_CAP       0x0100
+
+struct pciserial_board {
+       unsigned int flags;
+       unsigned int num_ports;
+       unsigned int base_baud;
+       unsigned int uart_offset;
+       unsigned int reg_shift;
+       unsigned int first_offset;
+};
+
+struct serial_private;
+
+struct serial_private *
+pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board);
+void pciserial_remove_ports(struct serial_private *priv);
+void pciserial_suspend_ports(struct serial_private *priv);
+void pciserial_resume_ports(struct serial_private *priv);
index ca5fcadf998194cd663ff0414bc7435896749e84..a5b74efab0679ae2a1f17dd6329596bf89c531ea 100644 (file)
@@ -1,24 +1,29 @@
 
 /*
-   Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
-   Copyright 2003-2004 Jeff Garzik
-
-   The contents of this file are subject to the Open
-   Software License version 1.1 that can be found at
-   http://www.opensource.org/licenses/osl-1.1.txt and is included herein
-   by reference.
-
-   Alternatively, the contents of this file may be used under the terms
-   of the GNU General Public License version 2 (the "GPL") as distributed
-   in the kernel source COPYING file, in which case the provisions of
-   the GPL are applicable instead of the above.  If you wish to allow
-   the use of your version of this file only under the terms of the
-   GPL and not to allow others to use your version of this file under
-   the OSL, indicate your decision by deleting the provisions above and
-   replace them with the notice and other provisions required by the GPL.
-   If you do not delete the provisions above, a recipient may use your
-   version of this file under either the OSL or the GPL.
-
+ *  Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+ *  Copyright 2003-2004 Jeff Garzik
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
+ *  Hardware documentation available from http://www.t13.org/
+ *
  */
 
 #ifndef __LINUX_ATA_H__
@@ -108,6 +113,8 @@ enum {
 
        /* ATA device commands */
        ATA_CMD_CHK_POWER       = 0xE5, /* check power mode */
+       ATA_CMD_STANDBY         = 0xE2, /* place in standby power mode */
+       ATA_CMD_IDLE            = 0xE3, /* place in idle power mode */
        ATA_CMD_EDD             = 0x90, /* execute device diagnostic */
        ATA_CMD_FLUSH           = 0xE7,
        ATA_CMD_FLUSH_EXT       = 0xEA,
diff --git a/include/linux/auxvec.h b/include/linux/auxvec.h
new file mode 100644 (file)
index 0000000..9a7b374
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _LINUX_AUXVEC_H
+#define _LINUX_AUXVEC_H
+
+#include <asm/auxvec.h>
+
+/* Symbolic values for the entries in the auxiliary table
+   put on the initial stack */
+#define AT_NULL   0    /* end of vector */
+#define AT_IGNORE 1    /* entry should be ignored */
+#define AT_EXECFD 2    /* file descriptor of program */
+#define AT_PHDR   3    /* program headers for program */
+#define AT_PHENT  4    /* size of program header entry */
+#define AT_PHNUM  5    /* number of program headers */
+#define AT_PAGESZ 6    /* system page size */
+#define AT_BASE   7    /* base address of interpreter */
+#define AT_FLAGS  8    /* flags */
+#define AT_ENTRY  9    /* entry point of program */
+#define AT_NOTELF 10   /* program is not ELF */
+#define AT_UID    11   /* real uid */
+#define AT_EUID   12   /* effective uid */
+#define AT_GID    13   /* real gid */
+#define AT_EGID   14   /* effective gid */
+#define AT_PLATFORM 15  /* string identifying CPU for optimizations */
+#define AT_HWCAP  16    /* arch dependent hints at CPU capabilities */
+#define AT_CLKTCK 17   /* frequency at which times() increments */
+
+#define AT_SECURE 23   /* secure mode boolean */
+
+#define AT_VECTOR_SIZE  42 /* Size of auxiliary table.  */
+
+#endif /* _LINUX_AUXVEC_H */
index 4fda06da56c1c9fc5eeeb1f340cf3b00b2fdbe47..cdaf03a14a5115333ea424944ba320b1f687bedb 100644 (file)
@@ -111,7 +111,6 @@ struct bio {
        void                    *bi_private;
 
        bio_destructor_t        *bi_destructor; /* destructor */
-       struct bio_set          *bi_set;        /* memory pools set */
 };
 
 /*
@@ -280,6 +279,7 @@ extern void bioset_free(struct bio_set *);
 extern struct bio *bio_alloc(unsigned int __nocast, int);
 extern struct bio *bio_alloc_bioset(unsigned int __nocast, int, struct bio_set *);
 extern void bio_put(struct bio *);
+extern void bio_free(struct bio *, struct bio_set *);
 
 extern void bio_endio(struct bio *, unsigned int, int);
 struct request_queue;
index 8d139f4acf23beb9f7d92274f4b96f14d3f09f37..6b4618902d3dd3f9fcb6298326a757dac415fb87 100644 (file)
@@ -233,6 +233,7 @@ typedef __u32 kernel_cap_t;
 /* Allow enabling/disabling tagged queuing on SCSI controllers and sending
    arbitrary SCSI commands */
 /* Allow setting encryption key on loopback filesystem */
+/* Allow setting zone reclaim policy */
 
 #define CAP_SYS_ADMIN        21
 
index b58b7d6f2fdb9168b2dc48d58849ef8f7c5d7c22..f9ca534787e24c1075a965843e87bddd9632e3a9 100644 (file)
@@ -18,6 +18,9 @@
 #define compat_jiffies_to_clock_t(x)   \
                (((unsigned long)(x) * COMPAT_USER_HZ) / HZ)
 
+typedef __compat_uid32_t       compat_uid_t;
+typedef __compat_gid32_t       compat_gid_t;
+
 struct rusage;
 
 struct compat_itimerspec { 
index e8904c0da686e0f347c5fe35a8603fa6e581de31..86980c68234aad549fd7d7252da7df5a72139403 100644 (file)
@@ -8,7 +8,7 @@
  * Basic handling of the devices is done in drivers/base/cpu.c
  * and system devices are handled in drivers/base/sys.c. 
  *
- * CPUs are exported via driverfs in the class/cpu/devices/
+ * CPUs are exported via sysfs in the class/cpu/devices/
  * directory. 
  *
  * Per-cpu interfaces can be implemented using a struct device_interface. 
index 3438233305a3aecb1674d527744117f22bd55d95..24062a1dbf61e2674719eb24e36b0d1b062fa396 100644 (file)
@@ -23,7 +23,8 @@ void cpuset_init_current_mems_allowed(void);
 void cpuset_update_current_mems_allowed(void);
 void cpuset_restrict_to_mems_allowed(unsigned long *nodes);
 int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl);
-int cpuset_zone_allowed(struct zone *z);
+extern int cpuset_zone_allowed(struct zone *z, unsigned int __nocast gfp_mask);
+extern int cpuset_excl_nodes_overlap(const struct task_struct *p);
 extern struct file_operations proc_cpuset_operations;
 extern char *cpuset_task_status_allowed(struct task_struct *task, char *buffer);
 
@@ -48,7 +49,13 @@ static inline int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl)
        return 1;
 }
 
-static inline int cpuset_zone_allowed(struct zone *z)
+static inline int cpuset_zone_allowed(struct zone *z,
+                                       unsigned int __nocast gfp_mask)
+{
+       return 1;
+}
+
+static inline int cpuset_excl_nodes_overlap(const struct task_struct *p)
 {
        return 1;
 }
index 5e2bcc636a02fd4d7a383e661b7661d6ac916169..3c89df6e7768451acf625236790753f2ab7f5139 100644 (file)
@@ -45,6 +45,7 @@
 #define CRYPTO_TFM_MODE_CTR            0x00000008
 
 #define CRYPTO_TFM_REQ_WEAK_KEY                0x00000100
+#define CRYPTO_TFM_REQ_MAY_SLEEP       0x00000200
 #define CRYPTO_TFM_RES_WEAK_KEY                0x00100000
 #define CRYPTO_TFM_RES_BAD_KEY_LEN     0x00200000
 #define CRYPTO_TFM_RES_BAD_KEY_SCHED   0x00400000
index 50be290d24d2705e92c17cdf4f6173e9702e581e..ab04b4f9b0db0e822dc08bc5a2abccdab32cadd3 100644 (file)
@@ -88,8 +88,9 @@ struct dentry {
                                         * negative */
        /*
         * The next three fields are touched by __d_lookup.  Place them here
-        * so they all fit in a 16-byte range, with 16-byte alignment.
+        * so they all fit in a cache line.
         */
+       struct hlist_node d_hash;       /* lookup hash list */
        struct dentry *d_parent;        /* parent directory */
        struct qstr d_name;
 
@@ -103,7 +104,6 @@ struct dentry {
        void *d_fsdata;                 /* fs-specific data */
        struct rcu_head d_rcu;
        struct dcookie_struct *d_cookie; /* cookie, if any */
-       struct hlist_node d_hash;       /* lookup hash list */  
        int d_mounted;
        unsigned char d_iname[DNAME_INLINE_LEN_MIN];    /* small names */
 };
diff --git a/include/linux/dccp.h b/include/linux/dccp.h
new file mode 100644 (file)
index 0000000..007c290
--- /dev/null
@@ -0,0 +1,456 @@
+#ifndef _LINUX_DCCP_H
+#define _LINUX_DCCP_H
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+/* Structure describing an Internet (DCCP) socket address. */
+struct sockaddr_dccp {
+       __u16   sdccp_family;   /* Address family   */
+       __u16   sdccp_port;     /* Port number      */
+       __u32   sdccp_addr;     /* Internet address */
+       __u32   sdccp_service;  /* Service          */
+       /* Pad to size of `struct sockaddr': 16 bytes . */
+       __u32   sdccp_pad;
+};
+
+/**
+ * struct dccp_hdr - generic part of DCCP packet header
+ *
+ * @dccph_sport - Relevant port on the endpoint that sent this packet
+ * @dccph_dport - Relevant port on the other endpoint
+ * @dccph_doff - Data Offset from the start of the DCCP header, in 32-bit words
+ * @dccph_ccval - Used by the HC-Sender CCID
+ * @dccph_cscov - Parts of the packet that are covered by the Checksum field
+ * @dccph_checksum - Internet checksum, depends on dccph_cscov
+ * @dccph_x - 0 = 24 bit sequence number, 1 = 48
+ * @dccph_type - packet type, see DCCP_PKT_ prefixed macros
+ * @dccph_seq - sequence number high or low order 24 bits, depends on dccph_x
+ */
+struct dccp_hdr {
+       __u16   dccph_sport,
+               dccph_dport;
+       __u8    dccph_doff;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u8    dccph_cscov:4,
+               dccph_ccval:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+       __u8    dccph_ccval:4,
+               dccph_cscov:4;
+#else
+#error  "Adjust your <asm/byteorder.h> defines"
+#endif
+       __u16   dccph_checksum;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u32   dccph_x:1,
+               dccph_type:4,
+               dccph_reserved:3,
+               dccph_seq:24;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+       __u32   dccph_reserved:3,
+               dccph_type:4,
+               dccph_x:1,
+               dccph_seq:24;
+#else
+#error  "Adjust your <asm/byteorder.h> defines"
+#endif
+};
+
+/**
+ * struct dccp_hdr_ext - the low bits of a 48 bit seq packet
+ *
+ * @dccph_seq_low - low 24 bits of a 48 bit seq packet
+ */
+struct dccp_hdr_ext {
+       __u32   dccph_seq_low;
+};
+
+/**
+ * struct dccp_hdr_request - Conection initiation request header
+ *
+ * @dccph_req_service - Service to which the client app wants to connect
+ * @dccph_req_options - list of options (must be a multiple of 32 bits
+ */
+struct dccp_hdr_request {
+       __u32   dccph_req_service;
+};
+/**
+ * struct dccp_hdr_ack_bits - acknowledgment bits common to most packets
+ *
+ * @dccph_resp_ack_nr_high - 48 bit ack number high order bits, contains GSR
+ * @dccph_resp_ack_nr_low - 48 bit ack number low order bits, contains GSR
+ */
+struct dccp_hdr_ack_bits {
+       __u32   dccph_reserved1:8,
+               dccph_ack_nr_high:24;
+       __u32   dccph_ack_nr_low;
+};
+/**
+ * struct dccp_hdr_response - Conection initiation response header
+ *
+ * @dccph_resp_ack_nr_high - 48 bit ack number high order bits, contains GSR
+ * @dccph_resp_ack_nr_low - 48 bit ack number low order bits, contains GSR
+ * @dccph_resp_service - Echoes the Service Code on a received DCCP-Request
+ * @dccph_resp_options - list of options (must be a multiple of 32 bits
+ */
+struct dccp_hdr_response {
+       struct dccp_hdr_ack_bits        dccph_resp_ack;
+       __u32                           dccph_resp_service;
+};
+
+/**
+ * struct dccp_hdr_reset - Unconditionally shut down a connection
+ *
+ * @dccph_reset_service - Echoes the Service Code on a received DCCP-Request
+ * @dccph_reset_options - list of options (must be a multiple of 32 bits
+ */
+struct dccp_hdr_reset {
+       struct dccp_hdr_ack_bits        dccph_reset_ack;
+       __u8                            dccph_reset_code,
+                                       dccph_reset_data[3];
+};
+
+enum dccp_pkt_type {
+       DCCP_PKT_REQUEST = 0,
+       DCCP_PKT_RESPONSE,
+       DCCP_PKT_DATA,
+       DCCP_PKT_ACK,
+       DCCP_PKT_DATAACK,
+       DCCP_PKT_CLOSEREQ,
+       DCCP_PKT_CLOSE,
+       DCCP_PKT_RESET,
+       DCCP_PKT_SYNC,
+       DCCP_PKT_SYNCACK,
+       DCCP_PKT_INVALID,
+};
+
+#define DCCP_NR_PKT_TYPES DCCP_PKT_INVALID
+
+static inline unsigned int dccp_packet_hdr_len(const __u8 type)
+{
+       if (type == DCCP_PKT_DATA)
+               return 0;
+       if (type == DCCP_PKT_DATAACK    ||
+           type == DCCP_PKT_ACK        ||
+           type == DCCP_PKT_SYNC       ||
+           type == DCCP_PKT_SYNCACK    ||
+           type == DCCP_PKT_CLOSE      ||
+           type == DCCP_PKT_CLOSEREQ)
+               return sizeof(struct dccp_hdr_ack_bits);
+       if (type == DCCP_PKT_REQUEST)
+               return sizeof(struct dccp_hdr_request);
+       if (type == DCCP_PKT_RESPONSE)
+               return sizeof(struct dccp_hdr_response);
+       return sizeof(struct dccp_hdr_reset);
+}
+enum dccp_reset_codes {
+       DCCP_RESET_CODE_UNSPECIFIED = 0,
+       DCCP_RESET_CODE_CLOSED,
+       DCCP_RESET_CODE_ABORTED,
+       DCCP_RESET_CODE_NO_CONNECTION,
+       DCCP_RESET_CODE_PACKET_ERROR,
+       DCCP_RESET_CODE_OPTION_ERROR,
+       DCCP_RESET_CODE_MANDATORY_ERROR,
+       DCCP_RESET_CODE_CONNECTION_REFUSED,
+       DCCP_RESET_CODE_BAD_SERVICE_CODE,
+       DCCP_RESET_CODE_TOO_BUSY,
+       DCCP_RESET_CODE_BAD_INIT_COOKIE,
+       DCCP_RESET_CODE_AGGRESSION_PENALTY,
+};
+
+/* DCCP options */
+enum {
+       DCCPO_PADDING = 0,
+       DCCPO_MANDATORY = 1,
+       DCCPO_MIN_RESERVED = 3,
+       DCCPO_MAX_RESERVED = 31,
+       DCCPO_NDP_COUNT = 37,
+       DCCPO_ACK_VECTOR_0 = 38,
+       DCCPO_ACK_VECTOR_1 = 39,
+       DCCPO_TIMESTAMP = 41,
+       DCCPO_TIMESTAMP_ECHO = 42,
+       DCCPO_ELAPSED_TIME = 43,
+       DCCPO_MAX = 45,
+       DCCPO_MIN_CCID_SPECIFIC = 128,
+       DCCPO_MAX_CCID_SPECIFIC = 255,
+};
+
+/* DCCP features */
+enum {
+       DCCPF_RESERVED = 0,
+       DCCPF_SEQUENCE_WINDOW = 3,
+       DCCPF_SEND_ACK_VECTOR = 6,
+       DCCPF_SEND_NDP_COUNT = 7,
+       /* 10-127 reserved */
+       DCCPF_MIN_CCID_SPECIFIC = 128,
+       DCCPF_MAX_CCID_SPECIFIC = 255,
+};
+
+/* DCCP socket options */
+#define DCCP_SOCKOPT_PACKET_SIZE       1
+
+#ifdef __KERNEL__
+
+#include <linux/in.h>
+#include <linux/list.h>
+#include <linux/uio.h>
+#include <linux/workqueue.h>
+
+#include <net/inet_connection_sock.h>
+#include <net/inet_timewait_sock.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+#include <net/tcp.h>
+
+enum dccp_state {
+       DCCP_OPEN       = TCP_ESTABLISHED,
+       DCCP_REQUESTING = TCP_SYN_SENT,
+       DCCP_PARTOPEN   = TCP_FIN_WAIT1, /* FIXME:
+                                           This mapping is horrible, but TCP has
+                                           no matching state for DCCP_PARTOPEN,
+                                           as TCP_SYN_RECV is already used by
+                                           DCCP_RESPOND, why don't stop using TCP
+                                           mapping of states? OK, now we don't use
+                                           sk_stream_sendmsg anymore, so doesn't
+                                           seem to exist any reason for us to
+                                           do the TCP mapping here */
+       DCCP_LISTEN     = TCP_LISTEN,
+       DCCP_RESPOND    = TCP_SYN_RECV,
+       DCCP_CLOSING    = TCP_CLOSING,
+       DCCP_TIME_WAIT  = TCP_TIME_WAIT,
+       DCCP_CLOSED     = TCP_CLOSE,
+       DCCP_MAX_STATES = TCP_MAX_STATES,
+};
+
+#define DCCP_STATE_MASK 0xf
+#define DCCP_ACTION_FIN (1<<7)
+
+enum {
+       DCCPF_OPEN       = TCPF_ESTABLISHED,
+       DCCPF_REQUESTING = TCPF_SYN_SENT,
+       DCCPF_PARTOPEN   = TCPF_FIN_WAIT1,
+       DCCPF_LISTEN     = TCPF_LISTEN,
+       DCCPF_RESPOND    = TCPF_SYN_RECV,
+       DCCPF_CLOSING    = TCPF_CLOSING,
+       DCCPF_TIME_WAIT  = TCPF_TIME_WAIT,
+       DCCPF_CLOSED     = TCPF_CLOSE,
+};
+
+static inline struct dccp_hdr *dccp_hdr(const struct sk_buff *skb)
+{
+       return (struct dccp_hdr *)skb->h.raw;
+}
+
+static inline struct dccp_hdr_ext *dccp_hdrx(const struct sk_buff *skb)
+{
+       return (struct dccp_hdr_ext *)(skb->h.raw + sizeof(struct dccp_hdr));
+}
+
+static inline unsigned int __dccp_basic_hdr_len(const struct dccp_hdr *dh)
+{
+       return sizeof(*dh) + (dh->dccph_x ? sizeof(struct dccp_hdr_ext) : 0);
+}
+
+static inline unsigned int dccp_basic_hdr_len(const struct sk_buff *skb)
+{
+       const struct dccp_hdr *dh = dccp_hdr(skb);
+       return __dccp_basic_hdr_len(dh);
+}
+
+static inline __u64 dccp_hdr_seq(const struct sk_buff *skb)
+{
+       const struct dccp_hdr *dh = dccp_hdr(skb);
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u64 seq_nr = ntohl(dh->dccph_seq << 8);
+#elif defined(__BIG_ENDIAN_BITFIELD)
+       __u64 seq_nr = ntohl(dh->dccph_seq);
+#else
+#error  "Adjust your <asm/byteorder.h> defines"
+#endif
+
+       if (dh->dccph_x != 0)
+               seq_nr = (seq_nr << 32) + ntohl(dccp_hdrx(skb)->dccph_seq_low);
+
+       return seq_nr;
+}
+
+static inline struct dccp_hdr_request *dccp_hdr_request(struct sk_buff *skb)
+{
+       return (struct dccp_hdr_request *)(skb->h.raw + dccp_basic_hdr_len(skb));
+}
+
+static inline struct dccp_hdr_ack_bits *dccp_hdr_ack_bits(const struct sk_buff *skb)
+{
+       return (struct dccp_hdr_ack_bits *)(skb->h.raw + dccp_basic_hdr_len(skb));
+}
+
+static inline u64 dccp_hdr_ack_seq(const struct sk_buff *skb)
+{
+       const struct dccp_hdr_ack_bits *dhack = dccp_hdr_ack_bits(skb);
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       return (((u64)ntohl(dhack->dccph_ack_nr_high << 8)) << 32) + ntohl(dhack->dccph_ack_nr_low);
+#elif defined(__BIG_ENDIAN_BITFIELD)
+       return (((u64)ntohl(dhack->dccph_ack_nr_high)) << 32) + ntohl(dhack->dccph_ack_nr_low);
+#else
+#error  "Adjust your <asm/byteorder.h> defines"
+#endif
+}
+
+static inline struct dccp_hdr_response *dccp_hdr_response(struct sk_buff *skb)
+{
+       return (struct dccp_hdr_response *)(skb->h.raw + dccp_basic_hdr_len(skb));
+}
+
+static inline struct dccp_hdr_reset *dccp_hdr_reset(struct sk_buff *skb)
+{
+       return (struct dccp_hdr_reset *)(skb->h.raw + dccp_basic_hdr_len(skb));
+}
+
+static inline unsigned int __dccp_hdr_len(const struct dccp_hdr *dh)
+{
+       return __dccp_basic_hdr_len(dh) +
+              dccp_packet_hdr_len(dh->dccph_type);
+}
+
+static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
+{
+       return __dccp_hdr_len(dccp_hdr(skb));
+}
+
+
+/* initial values for each feature */
+#define DCCPF_INITIAL_SEQUENCE_WINDOW          100
+/* FIXME: for now we're using CCID 3 (TFRC) */
+#define DCCPF_INITIAL_CCID                     3
+#define DCCPF_INITIAL_SEND_ACK_VECTOR          0
+/* FIXME: for now we're default to 1 but it should really be 0 */
+#define DCCPF_INITIAL_SEND_NDP_COUNT           1
+
+#define DCCP_NDP_LIMIT 0xFFFFFF
+
+/**
+  * struct dccp_options - option values for a DCCP connection
+  *    @dccpo_sequence_window - Sequence Window Feature (section 7.5.2)
+  *    @dccpo_ccid - Congestion Control Id (CCID) (section 10)
+  *    @dccpo_send_ack_vector - Send Ack Vector Feature (section 11.5)
+  *    @dccpo_send_ndp_count - Send NDP Count Feature (7.7.2)
+  */
+struct dccp_options {
+       __u64   dccpo_sequence_window;
+       __u8    dccpo_ccid;
+       __u8    dccpo_send_ack_vector;
+       __u8    dccpo_send_ndp_count;
+};
+
+extern void __dccp_options_init(struct dccp_options *dccpo);
+extern void dccp_options_init(struct dccp_options *dccpo);
+extern int dccp_parse_options(struct sock *sk, struct sk_buff *skb);
+
+struct dccp_request_sock {
+       struct inet_request_sock dreq_inet_rsk;
+       __u64                    dreq_iss;
+       __u64                    dreq_isr;
+       __u32                    dreq_service;
+};
+
+static inline struct dccp_request_sock *dccp_rsk(const struct request_sock *req)
+{
+       return (struct dccp_request_sock *)req;
+}
+
+extern struct inet_timewait_death_row dccp_death_row;
+
+/* Read about the ECN nonce to see why it is 253 */
+#define DCCP_MAX_ACK_VECTOR_LEN 253
+
+struct dccp_options_received {
+       u32     dccpor_ndp:24,
+               dccpor_ack_vector_len:8;
+       u32     dccpor_ack_vector_idx:10;
+       /* 22 bits hole, try to pack */
+       u32     dccpor_timestamp;
+       u32     dccpor_timestamp_echo;
+       u32     dccpor_elapsed_time;
+};
+
+struct ccid;
+
+enum dccp_role {
+       DCCP_ROLE_UNDEFINED,
+       DCCP_ROLE_LISTEN,
+       DCCP_ROLE_CLIENT,
+       DCCP_ROLE_SERVER,
+};
+
+/**
+ * struct dccp_sock - DCCP socket state
+ *
+ * @dccps_swl - sequence number window low
+ * @dccps_swh - sequence number window high
+ * @dccps_awl - acknowledgement number window low
+ * @dccps_awh - acknowledgement number window high
+ * @dccps_iss - initial sequence number sent
+ * @dccps_isr - initial sequence number received
+ * @dccps_osr - first OPEN sequence number received
+ * @dccps_gss - greatest sequence number sent
+ * @dccps_gsr - greatest valid sequence number received
+ * @dccps_gar - greatest valid ack number received on a non-Sync; initialized to %dccps_iss
+ * @dccps_timestamp_time - time of latest TIMESTAMP option
+ * @dccps_timestamp_echo - latest timestamp received on a TIMESTAMP option
+ * @dccps_ext_header_len - network protocol overhead (IP/IPv6 options)
+ * @dccps_pmtu_cookie - Last pmtu seen by socket
+ * @dccps_packet_size - Set thru setsockopt
+ * @dccps_role - Role of this sock, one of %dccp_role
+ * @dccps_ndp_count - number of Non Data Packets since last data packet
+ * @dccps_hc_rx_ackpkts - receiver half connection acked packets
+ */
+struct dccp_sock {
+       /* inet_connection_sock has to be the first member of dccp_sock */
+       struct inet_connection_sock     dccps_inet_connection;
+       __u64                           dccps_swl;
+       __u64                           dccps_swh;
+       __u64                           dccps_awl;
+       __u64                           dccps_awh;
+       __u64                           dccps_iss;
+       __u64                           dccps_isr;
+       __u64                           dccps_osr;
+       __u64                           dccps_gss;
+       __u64                           dccps_gsr;
+       __u64                           dccps_gar;
+       unsigned long                   dccps_service;
+       struct timeval                  dccps_timestamp_time;
+       __u32                           dccps_timestamp_echo;
+       __u32                           dccps_packet_size;
+       unsigned long                   dccps_ndp_count;
+       __u16                           dccps_ext_header_len;
+       __u32                           dccps_pmtu_cookie;
+       __u32                           dccps_mss_cache;
+       struct dccp_options             dccps_options;
+       struct dccp_ackpkts             *dccps_hc_rx_ackpkts;
+       void                            *dccps_hc_rx_ccid_private;
+       void                            *dccps_hc_tx_ccid_private;
+       struct ccid                     *dccps_hc_rx_ccid;
+       struct ccid                     *dccps_hc_tx_ccid;
+       struct dccp_options_received    dccps_options_received;
+       enum dccp_role                  dccps_role:2;
+};
+static inline struct dccp_sock *dccp_sk(const struct sock *sk)
+{
+       return (struct dccp_sock *)sk;
+}
+
+static inline const char *dccp_role(const struct sock *sk)
+{
+       switch (dccp_sk(sk)->dccps_role) {
+       case DCCP_ROLE_UNDEFINED: return "undefined";
+       case DCCP_ROLE_LISTEN:    return "listen";
+       case DCCP_ROLE_SERVER:    return "server";
+       case DCCP_ROLE_CLIENT:    return "client";
+       }
+       return NULL;
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_DCCP_H */
index 5e93e6dce9a4751b7107d24e4e241a1eb1989651..c30175e8dec67fa39f7a7fb1bf753f4fa40d0dda 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __DMI_H__
 #define __DMI_H__
 
+#include <linux/list.h>
+
 enum dmi_field {
        DMI_NONE,
        DMI_BIOS_VENDOR,
@@ -16,6 +18,24 @@ enum dmi_field {
        DMI_STRING_MAX,
 };
 
+enum dmi_device_type {
+       DMI_DEV_TYPE_ANY = 0,
+       DMI_DEV_TYPE_OTHER,
+       DMI_DEV_TYPE_UNKNOWN,
+       DMI_DEV_TYPE_VIDEO,
+       DMI_DEV_TYPE_SCSI,
+       DMI_DEV_TYPE_ETHERNET,
+       DMI_DEV_TYPE_TOKENRING,
+       DMI_DEV_TYPE_SOUND,
+       DMI_DEV_TYPE_IPMI = -1
+};
+
+struct dmi_header {
+       u8 type;
+       u8 length;
+       u16 handle;
+};
+
 /*
  *     DMI callbacks for problem boards
  */
@@ -26,22 +46,32 @@ struct dmi_strmatch {
 
 struct dmi_system_id {
        int (*callback)(struct dmi_system_id *);
-       char *ident;
+       const char *ident;
        struct dmi_strmatch matches[4];
        void *driver_data;
 };
 
-#define DMI_MATCH(a,b) { a, b }
+#define DMI_MATCH(a, b)        { a, b }
+
+struct dmi_device {
+       struct list_head list;
+       int type;
+       const char *name;
+       void *device_data;      /* Type specific data */
+};
 
 #if defined(CONFIG_X86) && !defined(CONFIG_X86_64)
 
 extern int dmi_check_system(struct dmi_system_id *list);
 extern char * dmi_get_system_info(int field);
-
+extern struct dmi_device * dmi_find_device(int type, const char *name,
+       struct dmi_device *from);
 #else
 
 static inline int dmi_check_system(struct dmi_system_id *list) { return 0; }
 static inline char * dmi_get_system_info(int field) { return NULL; }
+static struct dmi_device * dmi_find_device(int type, const char *name,
+       struct dmi_device *from) { return NULL; }
 
 #endif
 
index 73781ec165b40a96e92f98c6701daa27393ea3f3..c7c5dd3161820caca202022ca92acdf2b397cd9c 100644 (file)
@@ -91,11 +91,6 @@ typedef      struct {
 
 #define EFI_PAGE_SHIFT         12
 
-/*
- * For current x86 implementations of EFI, there is
- * additional padding in the mem descriptors.  This is not
- * the case in ia64.  Need to have this fixed in the f/w.
- */
 typedef struct {
        u32 type;
        u32 pad;
@@ -103,9 +98,6 @@ typedef struct {
        u64 virt_addr;
        u64 num_pages;
        u64 attribute;
-#if defined (__i386__)
-       u64 pad1;
-#endif
 } efi_memory_desc_t;
 
 typedef int (*efi_freemem_callback_t) (unsigned long start, unsigned long end, void *arg);
@@ -240,10 +232,12 @@ typedef struct {
 } efi_system_table_t;
 
 struct efi_memory_map {
-       efi_memory_desc_t *phys_map;
-       efi_memory_desc_t *map;
+       void *phys_map;
+       void *map;
+       void *map_end;
        int nr_map;
        unsigned long desc_version;
+       unsigned long desc_size;
 };
 
 /*
index f5b3ba5a317df0c90af0a7513678fb9fd5a003cc..ff955dbf510d918503b2f634e85e55ed8bd150c5 100644 (file)
@@ -2,6 +2,7 @@
 #define _LINUX_ELF_H
 
 #include <linux/types.h>
+#include <linux/auxvec.h>
 #include <asm/elf.h>
 
 #ifndef elf_read_implies_exec
@@ -158,29 +159,6 @@ typedef __s64      Elf64_Sxword;
 #define ELF64_ST_BIND(x)       ELF_ST_BIND(x)
 #define ELF64_ST_TYPE(x)       ELF_ST_TYPE(x)
 
-/* Symbolic values for the entries in the auxiliary table
-   put on the initial stack */
-#define AT_NULL   0    /* end of vector */
-#define AT_IGNORE 1    /* entry should be ignored */
-#define AT_EXECFD 2    /* file descriptor of program */
-#define AT_PHDR   3    /* program headers for program */
-#define AT_PHENT  4    /* size of program header entry */
-#define AT_PHNUM  5    /* number of program headers */
-#define AT_PAGESZ 6    /* system page size */
-#define AT_BASE   7    /* base address of interpreter */
-#define AT_FLAGS  8    /* flags */
-#define AT_ENTRY  9    /* entry point of program */
-#define AT_NOTELF 10   /* program is not ELF */
-#define AT_UID    11   /* real uid */
-#define AT_EUID   12   /* effective uid */
-#define AT_GID    13   /* real gid */
-#define AT_EGID   14   /* effective gid */
-#define AT_PLATFORM 15  /* string identifying CPU for optimizations */
-#define AT_HWCAP  16    /* arch dependent hints at CPU capabilities */
-#define AT_CLKTCK 17   /* frequency at which times() increments */
-
-#define AT_SECURE 23   /* secure mode boolean */
-
 typedef struct dynamic{
   Elf32_Sword d_tag;
   union{
index ce8518e658b6a0c2219071ed0fbfb0e462fb9115..4522c7186bf378de1c4162b042ad8a3b78fc09ac 100644 (file)
@@ -69,6 +69,12 @@ static inline int is_multicast_ether_addr(const u8 *addr)
        return ((addr[0] != 0xff) && (0x01 & addr[0]));
 }
 
+static inline int is_broadcast_ether_addr(const u8 *addr)
+{
+        return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) &&  
+               (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff));
+}
+
 /**
  * is_valid_ether_addr - Determine if the given Ethernet address is valid
  * @addr: Pointer to a six-byte array containing the Ethernet address
index a0ab26aab450db653ab44d45296bc2809b42b13a..ed1440ea4c91ebec8d76e295e0b074ffe629c113 100644 (file)
@@ -250,6 +250,12 @@ struct ethtool_stats {
        u64     data[0];
 };
 
+struct ethtool_perm_addr {
+       u32     cmd;            /* ETHTOOL_GPERMADDR */
+       u32     size;
+       u8      data[0];
+};
+
 struct net_device;
 
 /* Some generic methods drivers may use in their ethtool_ops */
@@ -261,6 +267,8 @@ u32 ethtool_op_get_sg(struct net_device *dev);
 int ethtool_op_set_sg(struct net_device *dev, u32 data);
 u32 ethtool_op_get_tso(struct net_device *dev);
 int ethtool_op_set_tso(struct net_device *dev, u32 data);
+int ethtool_op_get_perm_addr(struct net_device *dev, 
+                            struct ethtool_perm_addr *addr, u8 *data);
 
 /**
  * &ethtool_ops - Alter and report network device settings
@@ -294,7 +302,8 @@ int ethtool_op_set_tso(struct net_device *dev, u32 data);
  * get_strings: Return a set of strings that describe the requested objects 
  * phys_id: Identify the device
  * get_stats: Return statistics about the device
- *
+ * get_perm_addr: Gets the permanent hardware address
+ * 
  * Description:
  *
  * get_settings:
@@ -352,6 +361,7 @@ struct ethtool_ops {
        int     (*phys_id)(struct net_device *, u32);
        int     (*get_stats_count)(struct net_device *);
        void    (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *);
+       int     (*get_perm_addr)(struct net_device *, struct ethtool_perm_addr *, u8 *);
        int     (*begin)(struct net_device *);
        void    (*complete)(struct net_device *);
 };
@@ -389,6 +399,7 @@ struct ethtool_ops {
 #define ETHTOOL_GSTATS         0x0000001d /* get NIC-specific statistics */
 #define ETHTOOL_GTSO           0x0000001e /* Get TSO enable (ethtool_value) */
 #define ETHTOOL_STSO           0x0000001f /* Set TSO enable (ethtool_value) */
+#define ETHTOOL_GPERMADDR      0x00000020 /* Get permanent hardware address */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET         ETHTOOL_GSET
@@ -408,6 +419,8 @@ struct ethtool_ops {
 #define SUPPORTED_FIBRE                        (1 << 10)
 #define SUPPORTED_BNC                  (1 << 11)
 #define SUPPORTED_10000baseT_Full      (1 << 12)
+#define SUPPORTED_Pause                        (1 << 13)
+#define SUPPORTED_Asym_Pause           (1 << 14)
 
 /* Indicates what features are advertised by the interface. */
 #define ADVERTISED_10baseT_Half                (1 << 0)
@@ -423,6 +436,8 @@ struct ethtool_ops {
 #define ADVERTISED_FIBRE               (1 << 10)
 #define ADVERTISED_BNC                 (1 << 11)
 #define ADVERTISED_10000baseT_Full     (1 << 12)
+#define ADVERTISED_Pause               (1 << 13)
+#define ADVERTISED_Asym_Pause          (1 << 14)
 
 /* The following are all involved in forcing a particular link
  * mode for the device for setting things.  When getting the
index a657130ba03ae576df96b8e6ec4539d64dc6df3f..f7bd1c7ebefbd2a116c4970608b6cfb3c341bf90 100644 (file)
@@ -313,6 +313,9 @@ struct ext2_inode {
 #define EXT2_MOUNT_XATTR_USER          0x004000  /* Extended user attributes */
 #define EXT2_MOUNT_POSIX_ACL           0x008000  /* POSIX Access Control Lists */
 #define EXT2_MOUNT_XIP                 0x010000  /* Execute in place */
+#define EXT2_MOUNT_USRQUOTA            0x020000 /* user quota */
+#define EXT2_MOUNT_GRPQUOTA            0x040000 /* group quota */
+
 
 #define clear_opt(o, opt)              o &= ~EXT2_MOUNT_##opt
 #define set_opt(o, opt)                        o |= EXT2_MOUNT_##opt
index c16662836c582230111f7237f916c96e0aeb6da7..c0272d73ab20a576dfc96c2291e7ab7c74076c48 100644 (file)
@@ -373,6 +373,8 @@ struct ext3_inode {
 #define EXT3_MOUNT_BARRIER             0x20000 /* Use block barriers */
 #define EXT3_MOUNT_NOBH                        0x40000 /* No bufferheads */
 #define EXT3_MOUNT_QUOTA               0x80000 /* Some quota option set */
+#define EXT3_MOUNT_USRQUOTA            0x100000 /* "old" user quota */
+#define EXT3_MOUNT_GRPQUOTA            0x200000 /* "old" group quota */
 
 /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
 #ifndef _LINUX_EXT2_FS_H
index 886255b69bb9ada407534b9621398e2543006e2e..2063c0839d4fc3e0da2022d4303b4cce327e7d0e 100644 (file)
@@ -3,6 +3,9 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #define FIRMWARE_NAME_MAX 30 
+#define FW_ACTION_NOHOTPLUG 0
+#define FW_ACTION_HOTPLUG 1
+
 struct firmware {
        size_t size;
        u8 *data;
@@ -11,7 +14,7 @@ struct device;
 int request_firmware(const struct firmware **fw, const char *name,
                     struct device *device);
 int request_firmware_nowait(
-       struct module *module,
+       struct module *module, int hotplug,
        const char *name, struct device *device, void *context,
        void (*cont)(const struct firmware *fw, void *context));
 
index 67e6732d4fdc736ec39f4c57324e4d64064e063e..fd93ab7da905041938a7e59473d086d4657a152b 100644 (file)
@@ -69,6 +69,7 @@ extern int dir_notify_enable;
 #define READ 0
 #define WRITE 1
 #define READA 2                /* read-ahead  - don't block if no resources */
+#define SWRITE 3       /* for ll_rw_block() - wait for buffer lock */
 #define SPECIAL 4      /* For non-blockdevice requests in request queue */
 #define READ_SYNC      (READ | (1 << BIO_RW_SYNC))
 #define WRITE_SYNC     (WRITE | (1 << BIO_RW_SYNC))
@@ -281,18 +282,8 @@ struct iattr {
        struct timespec ia_atime;
        struct timespec ia_mtime;
        struct timespec ia_ctime;
-       unsigned int    ia_attr_flags;
 };
 
-/*
- * This is the inode attributes flag definitions
- */
-#define ATTR_FLAG_SYNCRONOUS   1       /* Syncronous write */
-#define ATTR_FLAG_NOATIME      2       /* Don't update atime */
-#define ATTR_FLAG_APPEND       4       /* Append-only file */
-#define ATTR_FLAG_IMMUTABLE    8       /* Immutable file */
-#define ATTR_FLAG_NODIRATIME   16      /* Don't update atime for directory */
-
 /*
  * Includes for diskquotas.
  */
@@ -594,7 +585,6 @@ struct file {
        unsigned int            f_uid, f_gid;
        struct file_ra_state    f_ra;
 
-       size_t                  f_maxcount;
        unsigned long           f_version;
        void                    *f_security;
 
@@ -1291,6 +1281,7 @@ static inline int break_lease(struct inode *inode, unsigned int mode)
 /* fs/open.c */
 
 extern int do_truncate(struct dentry *, loff_t start);
+extern long do_sys_open(const char __user *filename, int flags, int mode);
 extern struct file *filp_open(const char *, int, int);
 extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
 extern int filp_close(struct file *, fl_owner_t id);
index 65d6cfdb6d39c11098008268c6e97df7a3b5b462..10f96c31971ea30daf38c9226d656c0e993af3c0 100644 (file)
@@ -4,14 +4,40 @@
 /* Second argument to futex syscall */
 
 
-#define FUTEX_WAIT (0)
-#define FUTEX_WAKE (1)
-#define FUTEX_FD (2)
-#define FUTEX_REQUEUE (3)
-#define FUTEX_CMP_REQUEUE (4)
+#define FUTEX_WAIT             0
+#define FUTEX_WAKE             1
+#define FUTEX_FD               2
+#define FUTEX_REQUEUE          3
+#define FUTEX_CMP_REQUEUE      4
+#define FUTEX_WAKE_OP          5
 
 long do_futex(unsigned long uaddr, int op, int val,
                unsigned long timeout, unsigned long uaddr2, int val2,
                int val3);
 
+#define FUTEX_OP_SET           0       /* *(int *)UADDR2 = OPARG; */
+#define FUTEX_OP_ADD           1       /* *(int *)UADDR2 += OPARG; */
+#define FUTEX_OP_OR            2       /* *(int *)UADDR2 |= OPARG; */
+#define FUTEX_OP_ANDN          3       /* *(int *)UADDR2 &= ~OPARG; */
+#define FUTEX_OP_XOR           4       /* *(int *)UADDR2 ^= OPARG; */
+
+#define FUTEX_OP_OPARG_SHIFT   8       /* Use (1 << OPARG) instead of OPARG.  */
+
+#define FUTEX_OP_CMP_EQ                0       /* if (oldval == CMPARG) wake */
+#define FUTEX_OP_CMP_NE                1       /* if (oldval != CMPARG) wake */
+#define FUTEX_OP_CMP_LT                2       /* if (oldval < CMPARG) wake */
+#define FUTEX_OP_CMP_LE                3       /* if (oldval <= CMPARG) wake */
+#define FUTEX_OP_CMP_GT                4       /* if (oldval > CMPARG) wake */
+#define FUTEX_OP_CMP_GE                5       /* if (oldval >= CMPARG) wake */
+
+/* FUTEX_WAKE_OP will perform atomically
+   int oldval = *(int *)UADDR2;
+   *(int *)UADDR2 = oldval OP OPARG;
+   if (oldval CMP CMPARG)
+     wake UADDR2;  */
+
+#define FUTEX_OP(op, oparg, cmp, cmparg) \
+  (((op & 0xf) << 28) | ((cmp & 0xf) << 24)            \
+   | ((oparg & 0xfff) << 12) | (cmparg & 0xfff))
+
 #endif
index 7c7400137e97f11dffd425004321d1e675b802a0..4dc990f3b5ccea27bf5854d1e0f96e4367b4cb7c 100644 (file)
@@ -40,6 +40,7 @@ struct vm_area_struct;
 #define __GFP_ZERO     0x8000u /* Return zeroed page on success */
 #define __GFP_NOMEMALLOC 0x10000u /* Don't use emergency reserves */
 #define __GFP_NORECLAIM  0x20000u /* No realy zone reclaim during allocation */
+#define __GFP_HARDWALL   0x40000u /* Enforce hardwall cpuset memory allocs */
 
 #define __GFP_BITS_SHIFT 20    /* Room for 20 __GFP_FOO bits */
 #define __GFP_BITS_MASK ((1 << __GFP_BITS_SHIFT) - 1)
@@ -48,14 +49,15 @@ struct vm_area_struct;
 #define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| \
                        __GFP_COLD|__GFP_NOWARN|__GFP_REPEAT| \
                        __GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP| \
-                       __GFP_NOMEMALLOC|__GFP_NORECLAIM)
+                       __GFP_NOMEMALLOC|__GFP_NORECLAIM|__GFP_HARDWALL)
 
 #define GFP_ATOMIC     (__GFP_HIGH)
 #define GFP_NOIO       (__GFP_WAIT)
 #define GFP_NOFS       (__GFP_WAIT | __GFP_IO)
 #define GFP_KERNEL     (__GFP_WAIT | __GFP_IO | __GFP_FS)
-#define GFP_USER       (__GFP_WAIT | __GFP_IO | __GFP_FS)
-#define GFP_HIGHUSER   (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HIGHMEM)
+#define GFP_USER       (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL)
+#define GFP_HIGHUSER   (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL | \
+                        __GFP_HIGHMEM)
 
 /* Flag - indicates that the buffer will be suitable for DMA.  Ignored on some
    platforms, used as appropriate on others */
index 9debe6bbe5f0265cf4ab5dd81248d2b9d4d4f04b..bab303dafd6e1e4005d3d021ae7239788a3c2c63 100644 (file)
 #include <linux/if_hippi.h>
 
 #ifdef __KERNEL__
-extern unsigned short hippi_type_trans(struct sk_buff *skb,
-                                      struct net_device *dev);
+
+struct hippi_cb {
+       __u32   ifield;
+};
+
+extern __be16 hippi_type_trans(struct sk_buff *skb, struct net_device *dev);
 
 extern struct net_device *alloc_hippi_dev(int sizeof_priv);
 #endif
index f529d144281521552491058d1b5ed66d47bc8d71..e670b0d13fe02af741f0f881058bcfb0d43639df 100644 (file)
@@ -70,12 +70,6 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
 void hugetlb_prefault_arch_hook(struct mm_struct *mm);
 #endif
 
-#ifndef ARCH_HAS_HUGETLB_CLEAN_STALE_PGTABLE
-#define hugetlb_clean_stale_pgtable(pte)       BUG()
-#else
-void hugetlb_clean_stale_pgtable(pte_t *pte);
-#endif
-
 #else /* !CONFIG_HUGETLB_PAGE */
 
 static inline int is_vm_hugetlb_page(struct vm_area_struct *vma)
index 1b5018a965f58bdb98b909b70583836fe9008e94..7eb4004b36011b2188835751053195d0e1f7b047 100644 (file)
@@ -33,4 +33,19 @@ struct sensor_device_attribute sensor_dev_attr_##_name = {   \
        .index =        _index,                                 \
 }
 
+struct sensor_device_attribute_2 {
+       struct device_attribute dev_attr;
+       u8 index;
+       u8 nr;
+};
+#define to_sensor_dev_attr_2(_dev_attr) \
+       container_of(_dev_attr, struct sensor_device_attribute_2, dev_attr)
+
+#define SENSOR_DEVICE_ATTR_2(_name,_mode,_show,_store,_nr,_index)      \
+struct sensor_device_attribute_2 sensor_dev_attr_##_name = {   \
+       .dev_attr =     __ATTR(_name,_mode,_show,_store),       \
+       .index =        _index,                                 \
+       .nr =           _nr,                                    \
+}
+
 #endif /* _LINUX_HWMON_SYSFS_H */
diff --git a/include/linux/hwmon-vid.h b/include/linux/hwmon-vid.h
new file mode 100644 (file)
index 0000000..cd4b7a0
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+    hwmon-vid.h - VID/VRM/VRD voltage conversions
+
+    Originally part of lm_sensors
+    Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
+    With assistance from Trent Piepho <xyzzy@speakeasy.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _LINUX_HWMON_VID_H
+#define _LINUX_HWMON_VID_H
+
+int vid_from_reg(int val, int vrm);
+int vid_which_vrm(void);
+
+/* vrm is the VRM/VRD document version multiplied by 10.
+   val is in mV to avoid floating point in the kernel.
+   Returned value is the 4-, 5- or 6-bit VID code.
+   Note that only VRM 9.x is supported for now. */
+static inline int vid_to_reg(int val, int vrm)
+{
+       switch (vrm) {
+       case 91:                /* VRM 9.1 */
+       case 90:                /* VRM 9.0 */
+               return ((val >= 1100) && (val <= 1850) ?
+                       ((18499 - val * 10) / 25 + 5) / 10 : -1);
+       default:
+               return -1;
+       }
+}
+
+#endif /* _LINUX_HWMON_VID_H */
diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h
new file mode 100644 (file)
index 0000000..0efd994
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+    hwmon.h - part of lm_sensors, Linux kernel modules for hardware monitoring
+
+    This file declares helper functions for the sysfs class "hwmon",
+    for use by sensors drivers.
+
+    Copyright (C) 2005 Mark M. Hoffman <mhoffman@lightlink.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; version 2 of the License.
+*/
+
+#ifndef _HWMON_H_
+#define _HWMON_H_
+
+#include <linux/device.h>
+
+struct class_device *hwmon_device_register(struct device *dev);
+
+void hwmon_device_unregister(struct class_device *cdev);
+
+/* Scale user input to sensible values */
+static inline int SENSORS_LIMIT(long value, long low, long high)
+{
+       if (value < low)
+               return low;
+       else if (value > high)
+               return high;
+       else
+               return value;
+}
+
+#endif
+
index 33f08258f22b4077e4c247e5196b59fa01c14c2c..44f30876a1c9b194287f22226a24ed63d2e0fa69 100644 (file)
@@ -1,6 +1,6 @@
 /* ------------------------------------------------------------------------- */
 /*                                                                          */
-/* i2c.h - definitions for the i2c-bus interface                            */
+/* i2c-id.h - identifier values for i2c drivers and adapters                */
 /*                                                                          */
 /* ------------------------------------------------------------------------- */
 /*   Copyright (C) 1995-1999 Simon G. Vogl
 #ifndef LINUX_I2C_ID_H
 #define LINUX_I2C_ID_H
 
-/*
- * This file is part of the i2c-bus package and contains the identifier
- * values for drivers, adapters and other folk populating these serial
- * worlds. 
- *
- * These will change often (i.e. additions) , therefore this has been 
- * separated from the functional interface definitions of the i2c api.
- *
- */
-
 /*
  * ---- Driver types -----------------------------------------------------
  *       device id name + number        function description, i2c address(es)
 
 /*
  * ---- Adapter types ----------------------------------------------------
- *
- * First, we distinguish between several algorithms to access the hardware
- * interface types, as a PCF 8584 needs other care than a bit adapter.
- */
-
-#define I2C_ALGO_NONE  0x000000
-#define I2C_ALGO_BIT   0x010000        /* bit style adapters           */
-#define I2C_ALGO_PCF   0x020000        /* PCF 8584 style adapters      */
-#define I2C_ALGO_ATI   0x030000        /* ATI video card               */
-#define I2C_ALGO_SMBUS 0x040000
-#define I2C_ALGO_ISA   0x050000        /* lm_sensors ISA pseudo-adapter */
-#define I2C_ALGO_SAA7146 0x060000      /* SAA 7146 video decoder bus   */
-#define I2C_ALGO_ACB   0x070000        /* ACCESS.bus algorithm         */
-#define I2C_ALGO_IIC    0x080000       /* ITE IIC bus */
-#define I2C_ALGO_SAA7134 0x090000
-#define I2C_ALGO_MPC824X 0x0a0000      /* Motorola 8240 / 8245         */
-#define I2C_ALGO_IPMI  0x0b0000        /* IPMI dummy adapter */
-#define I2C_ALGO_IPMB  0x0c0000        /* IPMB adapter */
-#define I2C_ALGO_MPC107 0x0d0000
-#define I2C_ALGO_EC     0x100000        /* ACPI embedded controller     */
-
-#define I2C_ALGO_MPC8XX 0x110000       /* MPC8xx PowerPC I2C algorithm */
-#define I2C_ALGO_OCP    0x120000       /* IBM or otherwise On-chip I2C algorithm */
-#define I2C_ALGO_BITHS 0x130000        /* enhanced bit style adapters  */
-#define I2C_ALGO_IOP3XX        0x140000        /* XSCALE IOP3XX On-chip I2C alg */
-#define I2C_ALGO_SIBYTE 0x150000       /* Broadcom SiByte SOCs         */
-#define I2C_ALGO_SGI   0x160000        /* SGI algorithm                */
-
-#define I2C_ALGO_USB   0x170000        /* USB algorithm                */
-#define I2C_ALGO_VIRT  0x180000        /* Virtual bus adapter          */
-
-#define I2C_ALGO_MV64XXX 0x190000      /* Marvell mv64xxx i2c ctlr     */
-#define I2C_ALGO_PCA   0x1a0000        /* PCA 9564 style adapters      */
-#define I2C_ALGO_AU1550        0x1b0000        /* Au1550 PSC algorithm         */
-
-#define I2C_ALGO_EXP   0x800000        /* experimental                 */
-
-#define I2C_ALGO_MASK  0xff0000        /* Mask for algorithms          */
-#define I2C_ALGO_SHIFT 0x10    /* right shift to get index values      */
-
-#define I2C_HW_ADAPS   0x10000         /* # adapter types              */
-#define I2C_HW_MASK    0xffff          
-
-
-/* hw specific modules that are defined per algorithm layer
  */
 
 /* --- Bit algorithm adapters                                          */
-#define I2C_HW_B_LP    0x00    /* Parallel port Philips style adapter  */
-#define I2C_HW_B_LPC   0x01    /* Parallel port, over control reg.     */
-#define I2C_HW_B_SER   0x02    /* Serial line interface                */
-#define I2C_HW_B_ELV   0x03    /* ELV Card                             */
-#define I2C_HW_B_VELLE 0x04    /* Vellemann K8000                      */
-#define I2C_HW_B_BT848 0x05    /* BT848 video boards                   */
-#define I2C_HW_B_WNV   0x06    /* Winnov Videums                       */
-#define I2C_HW_B_VIA   0x07    /* Via vt82c586b                        */
-#define I2C_HW_B_HYDRA 0x08    /* Apple Hydra Mac I/O                  */
-#define I2C_HW_B_G400  0x09    /* Matrox G400                          */
-#define I2C_HW_B_I810  0x0a    /* Intel I810                           */
-#define I2C_HW_B_VOO   0x0b    /* 3dfx Voodoo 3 / Banshee              */
-#define I2C_HW_B_PPORT  0x0c   /* Primitive parallel port adapter      */
-#define I2C_HW_B_SAVG  0x0d    /* Savage 4                             */
-#define I2C_HW_B_SCX200        0x0e    /* Nat'l Semi SCx200 I2C                */
-#define I2C_HW_B_RIVA  0x10    /* Riva based graphics cards            */
-#define I2C_HW_B_IOC   0x11    /* IOC bit-wiggling                     */
-#define I2C_HW_B_TSUNA  0x12   /* DEC Tsunami chipset                  */
-#define I2C_HW_B_FRODO  0x13    /* 2d3D, Inc. SA-1110 Development Board */
-#define I2C_HW_B_OMAHA  0x14    /* Omaha I2C interface (ARM)           */
-#define I2C_HW_B_GUIDE  0x15    /* Guide bit-basher                    */
-#define I2C_HW_B_IXP2000 0x16  /* GPIO on IXP2000 systems              */
-#define I2C_HW_B_IXP4XX 0x17   /* GPIO on IXP4XX systems               */
-#define I2C_HW_B_S3VIA 0x18    /* S3Via ProSavage adapter              */
-#define I2C_HW_B_ZR36067 0x19  /* Zoran-36057/36067 based boards       */
-#define I2C_HW_B_PCILYNX 0x1a  /* TI PCILynx I2C adapter               */
-#define I2C_HW_B_CX2388x 0x1b  /* connexant 2388x based tv cards       */
+#define I2C_HW_B_LP            0x010000 /* Parallel port Philips style */
+#define I2C_HW_B_LPC           0x010001 /* Parallel port control reg. */
+#define I2C_HW_B_SER           0x010002 /* Serial line interface */
+#define I2C_HW_B_ELV           0x010003 /* ELV Card */
+#define I2C_HW_B_VELLE         0x010004 /* Vellemann K8000 */
+#define I2C_HW_B_BT848         0x010005 /* BT848 video boards */
+#define I2C_HW_B_WNV           0x010006 /* Winnov Videums */
+#define I2C_HW_B_VIA           0x010007 /* Via vt82c586b */
+#define I2C_HW_B_HYDRA         0x010008 /* Apple Hydra Mac I/O */
+#define I2C_HW_B_G400          0x010009 /* Matrox G400 */
+#define I2C_HW_B_I810          0x01000a /* Intel I810 */
+#define I2C_HW_B_VOO           0x01000b /* 3dfx Voodoo 3 / Banshee */
+#define I2C_HW_B_PPORT         0x01000c /* Primitive parallel port adapter */
+#define I2C_HW_B_SAVG          0x01000d /* Savage 4 */
+#define I2C_HW_B_SCX200                0x01000e /* Nat'l Semi SCx200 I2C */
+#define I2C_HW_B_RIVA          0x010010 /* Riva based graphics cards */
+#define I2C_HW_B_IOC           0x010011 /* IOC bit-wiggling */
+#define I2C_HW_B_TSUNA         0x010012 /* DEC Tsunami chipset */
+#define I2C_HW_B_FRODO         0x010013 /* 2d3D SA-1110 Development Board */
+#define I2C_HW_B_OMAHA         0x010014 /* Omaha I2C interface (ARM) */
+#define I2C_HW_B_GUIDE         0x010015 /* Guide bit-basher */
+#define I2C_HW_B_IXP2000       0x010016 /* GPIO on IXP2000 systems */
+#define I2C_HW_B_IXP4XX                0x010017 /* GPIO on IXP4XX systems */
+#define I2C_HW_B_S3VIA         0x010018 /* S3Via ProSavage adapter */
+#define I2C_HW_B_ZR36067       0x010019 /* Zoran-36057/36067 based boards */
+#define I2C_HW_B_PCILYNX       0x01001a /* TI PCILynx I2C adapter */
+#define I2C_HW_B_CX2388x       0x01001b /* connexant 2388x based tv cards */
+#define I2C_HW_B_NVIDIA                0x01001c /* nvidia framebuffer driver */
+#define I2C_HW_B_SAVAGE                0x01001d /* savage framebuffer driver */
+#define I2C_HW_B_RADEON                0x01001e /* radeon framebuffer driver */
 
 /* --- PCF 8584 based algorithms                                       */
-#define I2C_HW_P_LP    0x00    /* Parallel port interface              */
-#define I2C_HW_P_ISA   0x01    /* generic ISA Bus inteface card        */
-#define I2C_HW_P_ELEK  0x02    /* Elektor ISA Bus inteface card        */
+#define I2C_HW_P_LP            0x020000 /* Parallel port interface */
+#define I2C_HW_P_ISA           0x020001 /* generic ISA Bus inteface card */
+#define I2C_HW_P_ELEK          0x020002 /* Elektor ISA Bus inteface card */
 
 /* --- PCA 9564 based algorithms */
-#define I2C_HW_A_ISA   0x00    /* generic ISA Bus interface card       */
+#define I2C_HW_A_ISA           0x1a0000 /* generic ISA Bus interface card */
 
 /* --- ACPI Embedded controller algorithms                              */
-#define I2C_HW_ACPI_EC          0x00
+#define I2C_HW_ACPI_EC          0x1f0000
 
 /* --- MPC824x PowerPC adapters                                                */
-#define I2C_HW_MPC824X 0x00    /* Motorola 8240 / 8245                 */
+#define I2C_HW_MPC824X         0x100001 /* Motorola 8240 / 8245 */
 
 /* --- MPC8xx PowerPC adapters                                         */
-#define I2C_HW_MPC8XX_EPON 0x00        /* Eponymous MPC8xx I2C adapter         */
+#define I2C_HW_MPC8XX_EPON     0x110000 /* Eponymous MPC8xx I2C adapter */
 
 /* --- ITE based algorithms                                            */
-#define I2C_HW_I_IIC   0x00    /* controller on the ITE */
+#define I2C_HW_I_IIC           0x080000 /* controller on the ITE */
 
 /* --- PowerPC on-chip adapters                                                */
-#define I2C_HW_OCP 0x00        /* IBM on-chip I2C adapter      */
+#define I2C_HW_OCP             0x120000 /* IBM on-chip I2C adapter */
 
 /* --- Broadcom SiByte adapters                                                */
-#define I2C_HW_SIBYTE  0x00
+#define I2C_HW_SIBYTE          0x150000
 
 /* --- SGI adapters                                                    */
-#define I2C_HW_SGI_VINO        0x00
-#define I2C_HW_SGI_MACE        0x01
+#define I2C_HW_SGI_VINO                0x160000
+#define I2C_HW_SGI_MACE                0x160001
 
 /* --- XSCALE on-chip adapters                          */
-#define I2C_HW_IOP3XX 0x00
+#define I2C_HW_IOP3XX          0x140000
 
 /* --- Au1550 PSC adapters adapters                                    */
-#define I2C_HW_AU1550_PSC      0x00
+#define I2C_HW_AU1550_PSC      0x1b0000
 
 /* --- SMBus only adapters                                             */
-#define I2C_HW_SMBUS_PIIX4     0x00
-#define I2C_HW_SMBUS_ALI15X3   0x01
-#define I2C_HW_SMBUS_VIA2      0x02
-#define I2C_HW_SMBUS_VOODOO3   0x03
-#define I2C_HW_SMBUS_I801      0x04
-#define I2C_HW_SMBUS_AMD756    0x05
-#define I2C_HW_SMBUS_SIS5595   0x06
-#define I2C_HW_SMBUS_ALI1535   0x07
-#define I2C_HW_SMBUS_SIS630    0x08
-#define I2C_HW_SMBUS_SIS96X    0x09
-#define I2C_HW_SMBUS_AMD8111   0x0a
-#define I2C_HW_SMBUS_SCX200    0x0b
-#define I2C_HW_SMBUS_NFORCE2   0x0c
-#define I2C_HW_SMBUS_W9968CF   0x0d
-#define I2C_HW_SMBUS_OV511     0x0e    /* OV511(+) USB 1.1 webcam ICs  */
-#define I2C_HW_SMBUS_OV518     0x0f    /* OV518(+) USB 1.1 webcam ICs  */
-#define I2C_HW_SMBUS_OV519     0x10    /* OV519 USB 1.1 webcam IC      */
-#define I2C_HW_SMBUS_OVFX2     0x11    /* Cypress/OmniVision FX2 webcam */
+#define I2C_HW_SMBUS_PIIX4     0x040000
+#define I2C_HW_SMBUS_ALI15X3   0x040001
+#define I2C_HW_SMBUS_VIA2      0x040002
+#define I2C_HW_SMBUS_VOODOO3   0x040003
+#define I2C_HW_SMBUS_I801      0x040004
+#define I2C_HW_SMBUS_AMD756    0x040005
+#define I2C_HW_SMBUS_SIS5595   0x040006
+#define I2C_HW_SMBUS_ALI1535   0x040007
+#define I2C_HW_SMBUS_SIS630    0x040008
+#define I2C_HW_SMBUS_SIS96X    0x040009
+#define I2C_HW_SMBUS_AMD8111   0x04000a
+#define I2C_HW_SMBUS_SCX200    0x04000b
+#define I2C_HW_SMBUS_NFORCE2   0x04000c
+#define I2C_HW_SMBUS_W9968CF   0x04000d
+#define I2C_HW_SMBUS_OV511     0x04000e /* OV511(+) USB 1.1 webcam ICs */
+#define I2C_HW_SMBUS_OV518     0x04000f /* OV518(+) USB 1.1 webcam ICs */
+#define I2C_HW_SMBUS_OV519     0x040010 /* OV519 USB 1.1 webcam IC */
+#define I2C_HW_SMBUS_OVFX2     0x040011 /* Cypress/OmniVision FX2 webcam */
 
 /* --- ISA pseudo-adapter                                              */
-#define I2C_HW_ISA 0x00
+#define I2C_HW_ISA             0x050000
 
 /* --- IPMI pseudo-adapter                                             */
-#define I2C_HW_IPMI 0x00
+#define I2C_HW_IPMI            0x0b0000
 
 /* --- IPMB adapter                                            */
-#define I2C_HW_IPMB 0x00
+#define I2C_HW_IPMB            0x0c0000
 
 /* --- MCP107 adapter */
-#define I2C_HW_MPC107 0x00
+#define I2C_HW_MPC107          0x0d0000
 
 /* --- Marvell mv64xxx i2c adapter */
-#define I2C_HW_MV64XXX 0x00
+#define I2C_HW_MV64XXX         0x190000
+
+/* --- Miscellaneous adapters */
+#define I2C_HW_SAA7146         0x060000 /* SAA7146 video decoder bus */
+#define I2C_HW_SAA7134         0x090000 /* SAA7134 video decoder bus */
 
 #endif /* LINUX_I2C_ID_H */
diff --git a/include/linux/i2c-isa.h b/include/linux/i2c-isa.h
new file mode 100644 (file)
index 0000000..67e3598
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * i2c-isa.h - definitions for the i2c-isa pseudo-i2c-adapter interface
+ *
+ * Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _LINUX_I2C_ISA_H
+#define _LINUX_I2C_ISA_H
+
+#include <linux/i2c.h>
+
+extern int i2c_isa_add_driver(struct i2c_driver *driver);
+extern int i2c_isa_del_driver(struct i2c_driver *driver);
+
+/* Detect whether we are on the isa bus. This is only useful to hybrid
+   (i2c+isa) drivers. */
+#define i2c_is_isa_adapter(adapptr) \
+        ((adapptr)->id == I2C_HW_ISA)
+#define i2c_is_isa_client(clientptr) \
+        i2c_is_isa_adapter((clientptr)->adapter)
+
+#endif /* _LINUX_I2C_ISA_H */
diff --git a/include/linux/i2c-sensor.h b/include/linux/i2c-sensor.h
deleted file mode 100644 (file)
index 21b6252..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
-    i2c-sensor.h - Part of the i2c package
-    was originally sensors.h - Part of lm_sensors, Linux kernel modules
-                               for hardware monitoring
-    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef _LINUX_I2C_SENSOR_H
-#define _LINUX_I2C_SENSOR_H
-
-/* A structure containing detect information.
-   Force variables overrule all other variables; they force a detection on
-   that place. If a specific chip is given, the module blindly assumes this
-   chip type is present; if a general force (kind == 0) is given, the module
-   will still try to figure out what type of chip is present. This is useful
-   if for some reasons the detect for SMBus or ISA address space filled
-   fails.
-   probe: insmod parameter. Initialize this list with I2C_CLIENT_ISA_END values.
-     A list of pairs. The first value is a bus number (ANY_I2C_ISA_BUS for
-     the ISA bus, -1 for any I2C bus), the second is the address. 
-   kind: The kind of chip. 0 equals any chip.
-*/
-struct i2c_force_data {
-       unsigned short *force;
-       unsigned short kind;
-};
-
-/* A structure containing the detect information.
-   normal_i2c: filled in by the module writer. Terminated by I2C_CLIENT_ISA_END.
-     A list of I2C addresses which should normally be examined.
-   normal_isa: filled in by the module writer. Terminated by SENSORS_ISA_END.
-     A list of ISA addresses which should normally be examined.
-   probe: insmod parameter. Initialize this list with I2C_CLIENT_ISA_END values.
-     A list of pairs. The first value is a bus number (ANY_I2C_ISA_BUS for
-     the ISA bus, -1 for any I2C bus), the second is the address. These
-     addresses are also probed, as if they were in the 'normal' list.
-   ignore: insmod parameter. Initialize this list with I2C_CLIENT_ISA_END values.
-     A list of pairs. The first value is a bus number (ANY_I2C_ISA_BUS for
-     the ISA bus, -1 for any I2C bus), the second is the I2C address. These
-     addresses are never probed. This parameter overrules 'normal' and 
-     'probe', but not the 'force' lists.
-   force_data: insmod parameters. A list, ending with an element of which
-     the force field is NULL.
-*/
-struct i2c_address_data {
-       unsigned short *normal_i2c;
-       unsigned int *normal_isa;
-       unsigned short *probe;
-       unsigned short *ignore;
-       struct i2c_force_data *forces;
-};
-
-#define SENSORS_MODULE_PARM_FORCE(name) \
-  I2C_CLIENT_MODULE_PARM(force_ ## name, \
-                      "List of adapter,address pairs which are unquestionably" \
-                      " assumed to contain a `" # name "' chip")
-
-
-/* This defines several insmod variables, and the addr_data structure */
-#define SENSORS_INSMOD \
-  I2C_CLIENT_MODULE_PARM(probe, \
-                      "List of adapter,address pairs to scan additionally"); \
-  I2C_CLIENT_MODULE_PARM(ignore, \
-                      "List of adapter,address pairs not to scan"); \
-       static struct i2c_address_data addr_data = {                    \
-                       .normal_i2c =           normal_i2c,             \
-                       .normal_isa =           normal_isa,             \
-                       .probe =                probe,                  \
-                       .ignore =               ignore,                 \
-                       .forces =               forces,                 \
-               }
-
-/* The following functions create an enum with the chip names as elements. 
-   The first element of the enum is any_chip. These are the only macros
-   a module will want to use. */
-
-#define SENSORS_INSMOD_0 \
-  enum chips { any_chip }; \
-  I2C_CLIENT_MODULE_PARM(force, \
-                      "List of adapter,address pairs to boldly assume " \
-                      "to be present"); \
-  static struct i2c_force_data forces[] = {{force,any_chip},{NULL}}; \
-  SENSORS_INSMOD
-
-#define SENSORS_INSMOD_1(chip1) \
-  enum chips { any_chip, chip1 }; \
-  I2C_CLIENT_MODULE_PARM(force, \
-                      "List of adapter,address pairs to boldly assume " \
-                      "to be present"); \
-  SENSORS_MODULE_PARM_FORCE(chip1); \
-  static struct i2c_force_data forces[] = {{force,any_chip},\
-                                                 {force_ ## chip1,chip1}, \
-                                                 {NULL}}; \
-  SENSORS_INSMOD
-
-#define SENSORS_INSMOD_2(chip1,chip2) \
-  enum chips { any_chip, chip1, chip2 }; \
-  I2C_CLIENT_MODULE_PARM(force, \
-                      "List of adapter,address pairs to boldly assume " \
-                      "to be present"); \
-  SENSORS_MODULE_PARM_FORCE(chip1); \
-  SENSORS_MODULE_PARM_FORCE(chip2); \
-  static struct i2c_force_data forces[] = {{force,any_chip}, \
-                                                 {force_ ## chip1,chip1}, \
-                                                 {force_ ## chip2,chip2}, \
-                                                 {NULL}}; \
-  SENSORS_INSMOD
-
-#define SENSORS_INSMOD_3(chip1,chip2,chip3) \
-  enum chips { any_chip, chip1, chip2, chip3 }; \
-  I2C_CLIENT_MODULE_PARM(force, \
-                      "List of adapter,address pairs to boldly assume " \
-                      "to be present"); \
-  SENSORS_MODULE_PARM_FORCE(chip1); \
-  SENSORS_MODULE_PARM_FORCE(chip2); \
-  SENSORS_MODULE_PARM_FORCE(chip3); \
-  static struct i2c_force_data forces[] = {{force,any_chip}, \
-                                                 {force_ ## chip1,chip1}, \
-                                                 {force_ ## chip2,chip2}, \
-                                                 {force_ ## chip3,chip3}, \
-                                                 {NULL}}; \
-  SENSORS_INSMOD
-
-#define SENSORS_INSMOD_4(chip1,chip2,chip3,chip4) \
-  enum chips { any_chip, chip1, chip2, chip3, chip4 }; \
-  I2C_CLIENT_MODULE_PARM(force, \
-                      "List of adapter,address pairs to boldly assume " \
-                      "to be present"); \
-  SENSORS_MODULE_PARM_FORCE(chip1); \
-  SENSORS_MODULE_PARM_FORCE(chip2); \
-  SENSORS_MODULE_PARM_FORCE(chip3); \
-  SENSORS_MODULE_PARM_FORCE(chip4); \
-  static struct i2c_force_data forces[] = {{force,any_chip}, \
-                                                 {force_ ## chip1,chip1}, \
-                                                 {force_ ## chip2,chip2}, \
-                                                 {force_ ## chip3,chip3}, \
-                                                 {force_ ## chip4,chip4}, \
-                                                 {NULL}}; \
-  SENSORS_INSMOD
-
-#define SENSORS_INSMOD_5(chip1,chip2,chip3,chip4,chip5) \
-  enum chips { any_chip, chip1, chip2, chip3, chip4, chip5 }; \
-  I2C_CLIENT_MODULE_PARM(force, \
-                      "List of adapter,address pairs to boldly assume " \
-                      "to be present"); \
-  SENSORS_MODULE_PARM_FORCE(chip1); \
-  SENSORS_MODULE_PARM_FORCE(chip2); \
-  SENSORS_MODULE_PARM_FORCE(chip3); \
-  SENSORS_MODULE_PARM_FORCE(chip4); \
-  SENSORS_MODULE_PARM_FORCE(chip5); \
-  static struct i2c_force_data forces[] = {{force,any_chip}, \
-                                                 {force_ ## chip1,chip1}, \
-                                                 {force_ ## chip2,chip2}, \
-                                                 {force_ ## chip3,chip3}, \
-                                                 {force_ ## chip4,chip4}, \
-                                                 {force_ ## chip5,chip5}, \
-                                                 {NULL}}; \
-  SENSORS_INSMOD
-
-#define SENSORS_INSMOD_6(chip1,chip2,chip3,chip4,chip5,chip6) \
-  enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6 }; \
-  I2C_CLIENT_MODULE_PARM(force, \
-                      "List of adapter,address pairs to boldly assume " \
-                      "to be present"); \
-  SENSORS_MODULE_PARM_FORCE(chip1); \
-  SENSORS_MODULE_PARM_FORCE(chip2); \
-  SENSORS_MODULE_PARM_FORCE(chip3); \
-  SENSORS_MODULE_PARM_FORCE(chip4); \
-  SENSORS_MODULE_PARM_FORCE(chip5); \
-  SENSORS_MODULE_PARM_FORCE(chip6); \
-  static struct i2c_force_data forces[] = {{force,any_chip}, \
-                                                 {force_ ## chip1,chip1}, \
-                                                 {force_ ## chip2,chip2}, \
-                                                 {force_ ## chip3,chip3}, \
-                                                 {force_ ## chip4,chip4}, \
-                                                 {force_ ## chip5,chip5}, \
-                                                 {force_ ## chip6,chip6}, \
-                                                 {NULL}}; \
-  SENSORS_INSMOD
-
-#define SENSORS_INSMOD_7(chip1,chip2,chip3,chip4,chip5,chip6,chip7) \
-  enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6, chip7 }; \
-  I2C_CLIENT_MODULE_PARM(force, \
-                      "List of adapter,address pairs to boldly assume " \
-                      "to be present"); \
-  SENSORS_MODULE_PARM_FORCE(chip1); \
-  SENSORS_MODULE_PARM_FORCE(chip2); \
-  SENSORS_MODULE_PARM_FORCE(chip3); \
-  SENSORS_MODULE_PARM_FORCE(chip4); \
-  SENSORS_MODULE_PARM_FORCE(chip5); \
-  SENSORS_MODULE_PARM_FORCE(chip6); \
-  SENSORS_MODULE_PARM_FORCE(chip7); \
-  static struct i2c_force_data forces[] = {{force,any_chip}, \
-                                                 {force_ ## chip1,chip1}, \
-                                                 {force_ ## chip2,chip2}, \
-                                                 {force_ ## chip3,chip3}, \
-                                                 {force_ ## chip4,chip4}, \
-                                                 {force_ ## chip5,chip5}, \
-                                                 {force_ ## chip6,chip6}, \
-                                                 {force_ ## chip7,chip7}, \
-                                                 {NULL}}; \
-  SENSORS_INSMOD
-
-#define SENSORS_INSMOD_8(chip1,chip2,chip3,chip4,chip5,chip6,chip7,chip8) \
-  enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6, chip7, chip8 }; \
-  I2C_CLIENT_MODULE_PARM(force, \
-                      "List of adapter,address pairs to boldly assume " \
-                      "to be present"); \
-  SENSORS_MODULE_PARM_FORCE(chip1); \
-  SENSORS_MODULE_PARM_FORCE(chip2); \
-  SENSORS_MODULE_PARM_FORCE(chip3); \
-  SENSORS_MODULE_PARM_FORCE(chip4); \
-  SENSORS_MODULE_PARM_FORCE(chip5); \
-  SENSORS_MODULE_PARM_FORCE(chip6); \
-  SENSORS_MODULE_PARM_FORCE(chip7); \
-  SENSORS_MODULE_PARM_FORCE(chip8); \
-  static struct i2c_force_data forces[] = {{force,any_chip}, \
-                                                 {force_ ## chip1,chip1}, \
-                                                 {force_ ## chip2,chip2}, \
-                                                 {force_ ## chip3,chip3}, \
-                                                 {force_ ## chip4,chip4}, \
-                                                 {force_ ## chip5,chip5}, \
-                                                 {force_ ## chip6,chip6}, \
-                                                 {force_ ## chip7,chip7}, \
-                                                 {force_ ## chip8,chip8}, \
-                                                 {NULL}}; \
-  SENSORS_INSMOD
-
-/* Detect function. It iterates over all possible addresses itself. For
-   SMBus addresses, it will only call found_proc if some client is connected
-   to the SMBus (unless a 'force' matched); for ISA detections, this is not
-   done. */
-extern int i2c_detect(struct i2c_adapter *adapter,
-                     struct i2c_address_data *address_data,
-                     int (*found_proc) (struct i2c_adapter *, int, int));
-
-
-/* This macro is used to scale user-input to sensible values in almost all
-   chip drivers. */
-static inline int SENSORS_LIMIT(long value, long low, long high)
-{
-       if (value < low)
-               return low;
-       else if (value > high)
-               return high;
-       else
-               return value;
-}
-#endif                         /* def _LINUX_I2C_SENSOR_H */
diff --git a/include/linux/i2c-vid.h b/include/linux/i2c-vid.h
deleted file mode 100644 (file)
index 41d0635..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
-    i2c-vid.h - Part of lm_sensors, Linux kernel modules for hardware
-                monitoring
-    Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
-    With assistance from Trent Piepho <xyzzy@speakeasy.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/*
-    This file contains common code for decoding VID pins.
-    This file is #included in various chip drivers in this directory.
-    As the user is unlikely to load more than one driver which
-    includes this code we don't worry about the wasted space.
-    Reference: VRM x.y DC-DC Converter Design Guidelines,
-    available at http://developer.intel.com
-*/
-
-/*
-    AMD Opteron processors don't follow the Intel VRM spec.
-    I'm going to "make up" 2.4 as the VRM spec for the Opterons.
-    No good reason just a mnemonic for the 24x Opteron processor
-    series
-
-    Opteron VID encoding is:
-
-       00000  =  1.550 V
-       00001  =  1.525 V
-        . . . .
-       11110  =  0.800 V
-       11111  =  0.000 V (off)
- */
-
-/*
-    Legal val values 0x00 - 0x1f; except for VRD 10.0, 0x00 - 0x3f.
-    vrm is the Intel VRM document version.
-    Note: vrm version is scaled by 10 and the return value is scaled by 1000
-    to avoid floating point in the kernel.
-*/
-
-int i2c_which_vrm(void);
-
-#define DEFAULT_VRM    82
-
-static inline int vid_from_reg(int val, int vrm)
-{
-       int vid;
-
-       switch(vrm) {
-
-       case  0:
-               return 0;
-
-       case 100:               /* VRD 10.0 */
-               if((val & 0x1f) == 0x1f)
-                       return 0;
-               if((val & 0x1f) <= 0x09 || val == 0x0a)
-                       vid = 10875 - (val & 0x1f) * 250;
-               else
-                       vid = 18625 - (val & 0x1f) * 250;
-               if(val & 0x20)
-                       vid -= 125;
-               vid /= 10;      /* only return 3 dec. places for now */
-               return vid;
-
-       case 24:                /* Opteron processor */
-               return(val == 0x1f ? 0 : 1550 - val * 25);
-
-       case 91:                /* VRM 9.1 */
-       case 90:                /* VRM 9.0 */
-               return(val == 0x1f ? 0 :
-                                      1850 - val * 25);
-
-       case 85:                /* VRM 8.5 */
-               return((val & 0x10  ? 25 : 0) +
-                      ((val & 0x0f) > 0x04 ? 2050 : 1250) -
-                      ((val & 0x0f) * 50));
-
-       case 84:                /* VRM 8.4 */
-               val &= 0x0f;
-                               /* fall through */
-       default:                /* VRM 8.2 */
-               return(val == 0x1f ? 0 :
-                      val & 0x10  ? 5100 - (val) * 100 :
-                                    2050 - (val) * 50);
-       }
-}
-
-static inline int vid_to_reg(int val, int vrm)
-{
-       switch (vrm) {
-       case 91:                /* VRM 9.1 */
-       case 90:                /* VRM 9.0 */
-               return ((val >= 1100) && (val <= 1850) ?
-                       ((18499 - val * 10) / 25 + 5) / 10 : -1);
-       default:
-               return -1;
-       }
-}
index be837b13f2978d027156ee7459c8453da6cdee15..be35332b67e64689f89094400d25fb0bce346b3a 100644 (file)
 #include <linux/device.h>      /* for struct device */
 #include <asm/semaphore.h>
 
+/* --- For i2c-isa ---------------------------------------------------- */
+
+extern void i2c_adapter_dev_release(struct device *dev);
+extern struct device_driver i2c_adapter_driver;
+extern struct class i2c_adapter_class;
+extern struct bus_type i2c_bus_type;
+
 /* --- General options ------------------------------------------------        */
 
 struct i2c_msg;
@@ -41,7 +48,6 @@ struct i2c_algorithm;
 struct i2c_adapter;
 struct i2c_client;
 struct i2c_driver;
-struct i2c_client_address_data;
 union i2c_smbus_data;
 
 /*
@@ -143,12 +149,9 @@ struct i2c_driver {
  */
 struct i2c_client {
        unsigned int flags;             /* div., see below              */
-       unsigned int addr;              /* chip address - NOTE: 7bit    */
+       unsigned short addr;            /* chip address - NOTE: 7bit    */
                                        /* addresses are stored in the  */
-                                       /* _LOWER_ 7 bits of this char  */
-       /* addr: unsigned int to make lm_sensors i2c-isa adapter work
-         more cleanly. It does not take any more memory space, due to
-         alignment considerations */
+                                       /* _LOWER_ 7 bits               */
        struct i2c_adapter *adapter;    /* the adapter we sit on        */
        struct i2c_driver *driver;      /* and our access routines      */
        int usage_count;                /* How many accesses currently  */
@@ -160,6 +163,11 @@ struct i2c_client {
 };
 #define to_i2c_client(d) container_of(d, struct i2c_client, dev)
 
+static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj)
+{
+       return to_i2c_client(container_of(kobj, struct device, kobj));
+}
+
 static inline void *i2c_get_clientdata (struct i2c_client *dev)
 {
        return dev_get_drvdata (&dev->dev);
@@ -170,13 +178,6 @@ static inline void i2c_set_clientdata (struct i2c_client *dev, void *data)
        dev_set_drvdata (&dev->dev, data);
 }
 
-#define I2C_DEVNAME(str)       .name = str
-
-static inline char *i2c_clientname(struct i2c_client *c)
-{
-       return &c->name[0];
-}
-
 /*
  * The following structs are for those who like to implement new bus drivers:
  * i2c_algorithm is the interface to a class of hardware solutions which can
@@ -184,9 +185,6 @@ static inline char *i2c_clientname(struct i2c_client *c)
  * to name two of the most common.
  */
 struct i2c_algorithm {
-       char name[32];                          /* textual description  */
-       unsigned int id;
-
        /* If an adapter algorithm can't do I2C-level access, set master_xfer
           to NULL. If an adapter algorithm can do SMBus access, set 
           smbus_xfer. If set to NULL, the SMBus protocol is simulated
@@ -214,8 +212,7 @@ struct i2c_algorithm {
  */
 struct i2c_adapter {
        struct module *owner;
-       unsigned int id;/* == is algo->id | hwdep.struct->id,           */
-                       /* for registered values see below              */
+       unsigned int id;
        unsigned int class;
        struct i2c_algorithm *algo;/* the algorithm to access the bus   */
        void *algo_data;
@@ -292,12 +289,11 @@ struct i2c_client_address_data {
        unsigned short *normal_i2c;
        unsigned short *probe;
        unsigned short *ignore;
-       unsigned short *force;
+       unsigned short **forces;
 };
 
 /* Internal numbers to terminate lists */
 #define I2C_CLIENT_END         0xfffeU
-#define I2C_CLIENT_ISA_END     0xfffefffeU
 
 /* The numbers to use to set I2C bus address */
 #define ANY_I2C_BUS            0xffff
@@ -356,10 +352,6 @@ extern int i2c_probe(struct i2c_adapter *adapter,
  */
 extern int i2c_control(struct i2c_client *,unsigned int, unsigned long);
 
-/* This call returns a unique low identifier for each registered adapter,
- * or -1 if the adapter was not registered. 
- */
-extern int i2c_adapter_id(struct i2c_adapter *adap);
 extern struct i2c_adapter* i2c_get_adapter(int id);
 extern void i2c_put_adapter(struct i2c_adapter *adap);
 
@@ -376,6 +368,12 @@ static inline int i2c_check_functionality(struct i2c_adapter *adap, u32 func)
        return (func & i2c_get_functionality(adap)) == func;
 }
 
+/* Return id number for a specific adapter */
+static inline int i2c_adapter_id(struct i2c_adapter *adap)
+{
+       return adap->nr;
+}
+
 /*
  * I2C Message - used for pure i2c transaction, also from /dev interface
  */
@@ -510,9 +508,6 @@ union i2c_smbus_data {
 #define I2C_FUNCS      0x0705  /* Get the adapter functionality */
 #define I2C_RDWR       0x0707  /* Combined R/W transfer (one stop only)*/
 #define I2C_PEC                0x0708  /* != 0 for SMBus PEC                   */
-#if 0
-#define I2C_ACK_TEST   0x0710  /* See if a slave is at a specific address */
-#endif
 
 #define I2C_SMBUS      0x0720  /* SMBus-level access */
 
@@ -556,27 +551,148 @@ union i2c_smbus_data {
   module_param_array(var, short, &var##_num, 0); \
   MODULE_PARM_DESC(var,desc)
 
-/* This is the one you want to use in your own modules */
+#define I2C_CLIENT_MODULE_PARM_FORCE(name)                             \
+I2C_CLIENT_MODULE_PARM(force_##name,                                   \
+                      "List of adapter,address pairs which are "       \
+                      "unquestionably assumed to contain a `"          \
+                      # name "' chip")
+
+
+#define I2C_CLIENT_INSMOD_COMMON                                       \
+I2C_CLIENT_MODULE_PARM(probe, "List of adapter,address pairs to scan " \
+                      "additionally");                                 \
+I2C_CLIENT_MODULE_PARM(ignore, "List of adapter,address pairs not to " \
+                      "scan");                                         \
+static struct i2c_client_address_data addr_data = {                    \
+       .normal_i2c     = normal_i2c,                                   \
+       .probe          = probe,                                        \
+       .ignore         = ignore,                                       \
+       .forces         = forces,                                       \
+}
+
+/* These are the ones you want to use in your own drivers. Pick the one
+   which matches the number of devices the driver differenciates between. */
 #define I2C_CLIENT_INSMOD \
-  I2C_CLIENT_MODULE_PARM(probe, \
-                      "List of adapter,address pairs to scan additionally"); \
-  I2C_CLIENT_MODULE_PARM(ignore, \
-                      "List of adapter,address pairs not to scan"); \
   I2C_CLIENT_MODULE_PARM(force, \
                       "List of adapter,address pairs to boldly assume " \
                       "to be present"); \
-       static struct i2c_client_address_data addr_data = {             \
-                       .normal_i2c =           normal_i2c,             \
-                       .probe =                probe,                  \
-                       .ignore =               ignore,                 \
-                       .force =                force,                  \
-               }
-
-/* Detect whether we are on the isa bus. If this returns true, all i2c
-   access will fail! */
-#define i2c_is_isa_client(clientptr) \
-        ((clientptr)->adapter->algo->id == I2C_ALGO_ISA)
-#define i2c_is_isa_adapter(adapptr) \
-        ((adapptr)->algo->id == I2C_ALGO_ISA)
+       static unsigned short *forces[] = {                             \
+                       force,                                          \
+                       NULL                                            \
+               };                                                      \
+I2C_CLIENT_INSMOD_COMMON
+
+#define I2C_CLIENT_INSMOD_1(chip1)                                     \
+enum chips { any_chip, chip1 };                                                \
+I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to "      \
+                      "boldly assume to be present");                  \
+I2C_CLIENT_MODULE_PARM_FORCE(chip1);                                   \
+static unsigned short *forces[] = { force, force_##chip1, NULL };      \
+I2C_CLIENT_INSMOD_COMMON
+
+#define I2C_CLIENT_INSMOD_2(chip1, chip2)                              \
+enum chips { any_chip, chip1, chip2 };                                 \
+I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to "      \
+                      "boldly assume to be present");                  \
+I2C_CLIENT_MODULE_PARM_FORCE(chip1);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip2);                                   \
+static unsigned short *forces[] = { force, force_##chip1,              \
+                                   force_##chip2, NULL };              \
+I2C_CLIENT_INSMOD_COMMON
+
+#define I2C_CLIENT_INSMOD_3(chip1, chip2, chip3)                       \
+enum chips { any_chip, chip1, chip2, chip3 };                          \
+I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to "      \
+                      "boldly assume to be present");                  \
+I2C_CLIENT_MODULE_PARM_FORCE(chip1);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip2);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip3);                                   \
+static unsigned short *forces[] = { force, force_##chip1,              \
+                                   force_##chip2, force_##chip3,       \
+                                   NULL };                             \
+I2C_CLIENT_INSMOD_COMMON
+
+#define I2C_CLIENT_INSMOD_4(chip1, chip2, chip3, chip4)                        \
+enum chips { any_chip, chip1, chip2, chip3, chip4 };                   \
+I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to "      \
+                      "boldly assume to be present");                  \
+I2C_CLIENT_MODULE_PARM_FORCE(chip1);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip2);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip3);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip4);                                   \
+static unsigned short *forces[] = { force, force_##chip1,              \
+                                   force_##chip2, force_##chip3,       \
+                                   force_##chip4, NULL};               \
+I2C_CLIENT_INSMOD_COMMON
+
+#define I2C_CLIENT_INSMOD_5(chip1, chip2, chip3, chip4, chip5)         \
+enum chips { any_chip, chip1, chip2, chip3, chip4, chip5 };            \
+I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to "      \
+                      "boldly assume to be present");                  \
+I2C_CLIENT_MODULE_PARM_FORCE(chip1);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip2);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip3);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip4);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip5);                                   \
+static unsigned short *forces[] = { force, force_##chip1,              \
+                                   force_##chip2, force_##chip3,       \
+                                   force_##chip4, force_##chip5,       \
+                                   NULL };                             \
+I2C_CLIENT_INSMOD_COMMON
+
+#define I2C_CLIENT_INSMOD_6(chip1, chip2, chip3, chip4, chip5, chip6)  \
+enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6 };     \
+I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to "      \
+                      "boldly assume to be present");                  \
+I2C_CLIENT_MODULE_PARM_FORCE(chip1);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip2);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip3);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip4);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip5);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip6);                                   \
+static unsigned short *forces[] = { force, force_##chip1,              \
+                                   force_##chip2, force_##chip3,       \
+                                   force_##chip4, force_##chip5,       \
+                                   force_##chip6, NULL };              \
+I2C_CLIENT_INSMOD_COMMON
+
+#define I2C_CLIENT_INSMOD_7(chip1, chip2, chip3, chip4, chip5, chip6, chip7) \
+enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6,       \
+            chip7 };                                                   \
+I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to "      \
+                      "boldly assume to be present");                  \
+I2C_CLIENT_MODULE_PARM_FORCE(chip1);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip2);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip3);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip4);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip5);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip6);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip7);                                   \
+static unsigned short *forces[] = { force, force_##chip1,              \
+                                   force_##chip2, force_##chip3,       \
+                                   force_##chip4, force_##chip5,       \
+                                   force_##chip6, force_##chip7,       \
+                                   NULL };                             \
+I2C_CLIENT_INSMOD_COMMON
+
+#define I2C_CLIENT_INSMOD_8(chip1, chip2, chip3, chip4, chip5, chip6, chip7, chip8) \
+enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6,       \
+            chip7, chip8 };                                            \
+I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to "      \
+                      "boldly assume to be present");                  \
+I2C_CLIENT_MODULE_PARM_FORCE(chip1);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip2);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip3);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip4);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip5);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip6);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip7);                                   \
+I2C_CLIENT_MODULE_PARM_FORCE(chip8);                                   \
+static unsigned short *forces[] = { force, force_##chip1,              \
+                                   force_##chip2, force_##chip3,       \
+                                   force_##chip4, force_##chip5,       \
+                                   force_##chip6, force_##chip7,       \
+                                   force_##chip8, NULL };              \
+I2C_CLIENT_INSMOD_COMMON
 
 #endif /* _LINUX_I2C_H */
index b5b58e9c054c3901f2b5721ea3440f97e4f2c3db..fc2d4c8225aa80d0429572594d26c87a8a5f9425 100644 (file)
@@ -110,6 +110,8 @@ static inline struct ethhdr *eth_hdr(const struct sk_buff *skb)
 {
        return (struct ethhdr *)skb->mac.raw;
 }
+
+extern struct ctl_table ether_table[];
 #endif
 
 #endif /* _LINUX_IF_ETHER_H */
index 33330b458b9568d5a4303322d8011856c2ab6a66..376a34ea47231282bc883e05fcb2dcd487b52bd3 100644 (file)
@@ -44,7 +44,7 @@ struct fcllc {
        __u8  ssap;                     /* source SAP */
        __u8  llc;                      /* LLC control field */
        __u8  protid[3];                /* protocol id */
-       __u16 ethertype;                /* ether type field */
+       __be16 ethertype;               /* ether type field */
 };
 
 #endif /* _LINUX_IF_FC_H */
index a912818e63618f0df8a54200869d5d3289cc25bd..1288a161bc0baf1b64583d668a24069e0f03a44b 100644 (file)
@@ -85,7 +85,7 @@ struct fddi_snap_hdr
        __u8    ssap;                                   /* always 0xAA */
        __u8    ctrl;                                   /* always 0x03 */
        __u8    oui[FDDI_K_OUI_LEN];    /* organizational universal id */
-       __u16   ethertype;                              /* packet type ID field */
+       __be16  ethertype;                              /* packet type ID field */
        } __attribute__ ((packed));
 
 /* Define FDDI LLC frame header */
index 3c94b1736570157b0e81d87c6ec86640305e1633..511999c7eedaa96149d2e44f06e0059e94c93141 100644 (file)
@@ -191,10 +191,12 @@ struct frad_local
    int               buffer;           /* current buffer for S508 firmware */
 };
 
-extern void dlci_ioctl_set(int (*hook)(unsigned int, void __user *));
-
 #endif /* __KERNEL__ */
 
 #endif /* CONFIG_DLCI || CONFIG_DLCI_MODULE */
 
+#ifdef __KERNEL__
+extern void dlci_ioctl_set(int (*hook)(unsigned int, void __user *));
+#endif
+
 #endif
index c8ca72c46f76e76ebdadae0df70747782c1359fc..94d31ca7d71a0936c19e066f3c899184b64eaa66 100644 (file)
@@ -102,9 +102,9 @@ struct hippi_fp_hdr
 #error "Please fix <asm/byteorder.h>"
 #endif
 #else
-       __u32           fixed;
+       __be32          fixed;
 #endif
-       __u32           d2_size;
+       __be32          d2_size;
 } __attribute__ ((packed));
 
 struct hippi_le_hdr
@@ -144,7 +144,7 @@ struct hippi_snap_hdr
        __u8    ssap;                   /* always 0xAA */
        __u8    ctrl;                   /* always 0x03 */
        __u8    oui[HIPPI_OUI_LEN];     /* organizational universal id (zero)*/
-       __u16   ethertype;              /* packet type ID field */
+       __be16  ethertype;              /* packet type ID field */
 } __attribute__ ((packed));
 
 struct hippi_hdr
index 3fba9e2f5427d633a9260854112647e9294b07a3..5502f597cf0e8808b582c6bb8d7cc52412bd2d11 100644 (file)
@@ -43,12 +43,16 @@ struct trh_hdr {
 };
 
 #ifdef __KERNEL__
+#include <linux/config.h>
 #include <linux/skbuff.h>
 
 static inline struct trh_hdr *tr_hdr(const struct sk_buff *skb)
 {
        return (struct trh_hdr *)skb->mac.raw;
 }
+#ifdef CONFIG_SYSCTL
+extern struct ctl_table tr_table[];
+#endif
 #endif
 
 /* This is an Token-Ring LLC structure */
index 096a85a58ae5e4919e8379c8763d2c0f50e5887c..88aef7b86ef43be6b5b2408aa233f559fa88c115 100644 (file)
@@ -77,6 +77,7 @@ struct tun_struct {
 #define TUNSETIFF     _IOW('T', 202, int) 
 #define TUNSETPERSIST _IOW('T', 203, int) 
 #define TUNSETOWNER   _IOW('T', 204, int)
+#define TUNSETLINK    _IOW('T', 205, int)
 
 /* TUNSETIFF ifr flags */
 #define IFF_TUN                0x0001
index 62a9d89dfbe2fcbb78edf0175446e6f2de8b2c32..17d0c0d40b0e376b80e0fa95768dc022961ee671 100644 (file)
@@ -155,7 +155,6 @@ static inline int __vlan_hwaccel_rx(struct sk_buff *skb,
 {
        struct net_device_stats *stats;
 
-       skb->real_dev = skb->dev;
        skb->dev = grp->vlan_devices[vlan_tag & VLAN_VID_MASK];
        if (skb->dev == NULL) {
                dev_kfree_skb_any(skb);
index 0c31ef0b5badc3d9dffb39a7414459d2101ae5dd..28f4f3b36950593a5eec787ce7193cb207bf9be8 100644 (file)
@@ -129,6 +129,9 @@ struct igmpv3_query {
 #include <linux/skbuff.h>
 #include <linux/in.h>
 
+extern int sysctl_igmp_max_memberships;
+extern int sysctl_igmp_max_msf;
+
 struct ip_sf_socklist
 {
        unsigned int            sl_max;
index fb88c66d748dcad89a08a2f18d9176adb67a2539..ba355384016afa440a492b25c3fd6149f0603a3b 100644 (file)
@@ -32,6 +32,7 @@ enum {
   IPPROTO_PUP = 12,            /* PUP protocol                         */
   IPPROTO_UDP = 17,            /* User Datagram Protocol               */
   IPPROTO_IDP = 22,            /* XNS IDP protocol                     */
+  IPPROTO_DCCP = 33,           /* Datagram Congestion Control Protocol */
   IPPROTO_RSVP = 46,           /* RSVP protocol                        */
   IPPROTO_GRE = 47,            /* Cisco GRE tunnels (rfc 1701,1702)    */
 
diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h
new file mode 100644 (file)
index 0000000..a4606e5
--- /dev/null
@@ -0,0 +1,138 @@
+#ifndef _INET_DIAG_H_
+#define _INET_DIAG_H_ 1
+
+/* Just some random number */
+#define TCPDIAG_GETSOCK 18
+#define DCCPDIAG_GETSOCK 19
+
+#define INET_DIAG_GETSOCK_MAX 24
+
+/* Socket identity */
+struct inet_diag_sockid {
+       __u16   idiag_sport;
+       __u16   idiag_dport;
+       __u32   idiag_src[4];
+       __u32   idiag_dst[4];
+       __u32   idiag_if;
+       __u32   idiag_cookie[2];
+#define INET_DIAG_NOCOOKIE (~0U)
+};
+
+/* Request structure */
+
+struct inet_diag_req {
+       __u8    idiag_family;           /* Family of addresses. */
+       __u8    idiag_src_len;
+       __u8    idiag_dst_len;
+       __u8    idiag_ext;              /* Query extended information */
+
+       struct inet_diag_sockid id;
+
+       __u32   idiag_states;           /* States to dump */
+       __u32   idiag_dbs;              /* Tables to dump (NI) */
+};
+
+enum {
+       INET_DIAG_REQ_NONE,
+       INET_DIAG_REQ_BYTECODE,
+};
+
+#define INET_DIAG_REQ_MAX INET_DIAG_REQ_BYTECODE
+
+/* Bytecode is sequence of 4 byte commands followed by variable arguments.
+ * All the commands identified by "code" are conditional jumps forward:
+ * to offset cc+"yes" or to offset cc+"no". "yes" is supposed to be
+ * length of the command and its arguments.
+ */
+struct inet_diag_bc_op {
+       unsigned char   code;
+       unsigned char   yes;
+       unsigned short  no;
+};
+
+enum {
+       INET_DIAG_BC_NOP,
+       INET_DIAG_BC_JMP,
+       INET_DIAG_BC_S_GE,
+       INET_DIAG_BC_S_LE,
+       INET_DIAG_BC_D_GE,
+       INET_DIAG_BC_D_LE,
+       INET_DIAG_BC_AUTO,
+       INET_DIAG_BC_S_COND,
+       INET_DIAG_BC_D_COND,
+};
+
+struct inet_diag_hostcond {
+       __u8    family;
+       __u8    prefix_len;
+       int     port;
+       __u32   addr[0];
+};
+
+/* Base info structure. It contains socket identity (addrs/ports/cookie)
+ * and, alas, the information shown by netstat. */
+struct inet_diag_msg {
+       __u8    idiag_family;
+       __u8    idiag_state;
+       __u8    idiag_timer;
+       __u8    idiag_retrans;
+
+       struct inet_diag_sockid id;
+
+       __u32   idiag_expires;
+       __u32   idiag_rqueue;
+       __u32   idiag_wqueue;
+       __u32   idiag_uid;
+       __u32   idiag_inode;
+};
+
+/* Extensions */
+
+enum {
+       INET_DIAG_NONE,
+       INET_DIAG_MEMINFO,
+       INET_DIAG_INFO,
+       INET_DIAG_VEGASINFO,
+       INET_DIAG_CONG,
+};
+
+#define INET_DIAG_MAX INET_DIAG_CONG
+
+
+/* INET_DIAG_MEM */
+
+struct inet_diag_meminfo {
+       __u32   idiag_rmem;
+       __u32   idiag_wmem;
+       __u32   idiag_fmem;
+       __u32   idiag_tmem;
+};
+
+/* INET_DIAG_VEGASINFO */
+
+struct tcpvegas_info {
+       __u32   tcpv_enabled;
+       __u32   tcpv_rttcnt;
+       __u32   tcpv_rtt;
+       __u32   tcpv_minrtt;
+};
+
+#ifdef __KERNEL__
+struct sock;
+struct inet_hashinfo;
+
+struct inet_diag_handler {
+       struct inet_hashinfo    *idiag_hashinfo;
+       void                    (*idiag_get_info)(struct sock *sk,
+                                                 struct inet_diag_msg *r,
+                                                 void *info);
+       __u16                   idiag_info_size;
+       __u16                   idiag_type;
+};
+
+extern int  inet_diag_register(const struct inet_diag_handler *handler);
+extern void inet_diag_unregister(const struct inet_diag_handler *handler);
+#endif /* __KERNEL__ */
+
+#endif /* _INET_DIAG_H_ */
index 93bb3afe646bc315d1ce17849acdad149e9b8684..ee5b239092edbb03dee1765dd7919246bf4a2400 100644 (file)
@@ -47,6 +47,7 @@ struct inotify_event {
 #define IN_MOVE                        (IN_MOVED_FROM | IN_MOVED_TO) /* moves */
 
 /* special flags */
+#define IN_MASK_ADD            0x20000000      /* add to the mask of an already existing watch */
 #define IN_ISDIR               0x40000000      /* event occurred against dir */
 #define IN_ONESHOT             0x80000000      /* only send event once */
 
index bdc53c6cc962ad78989fbbb0cfbac2a68cb57aa2..4767e5429534dff11c004923b5a3ee9827bcac50 100644 (file)
@@ -66,6 +66,7 @@ struct input_absinfo {
 #define EVIOCGKEY(len)         _IOC(_IOC_READ, 'E', 0x18, len)         /* get global keystate */
 #define EVIOCGLED(len)         _IOC(_IOC_READ, 'E', 0x19, len)         /* get all LEDs */
 #define EVIOCGSND(len)         _IOC(_IOC_READ, 'E', 0x1a, len)         /* get all sounds status */
+#define EVIOCGSW(len)          _IOC(_IOC_READ, 'E', 0x1b, len)         /* get all switch states */
 
 #define EVIOCGBIT(ev,len)      _IOC(_IOC_READ, 'E', 0x20 + ev, len)    /* get event bits */
 #define EVIOCGABS(abs)         _IOR('E', 0x40 + abs, struct input_absinfo)             /* get abs value/limits */
@@ -86,6 +87,7 @@ struct input_absinfo {
 #define EV_REL                 0x02
 #define EV_ABS                 0x03
 #define EV_MSC                 0x04
+#define EV_SW                  0x05
 #define EV_LED                 0x11
 #define EV_SND                 0x12
 #define EV_REP                 0x14
@@ -550,6 +552,20 @@ struct input_absinfo {
 #define ABS_MISC               0x28
 #define ABS_MAX                        0x3f
 
+/*
+ * Switch events
+ */
+
+#define SW_0           0x00
+#define SW_1           0x01
+#define SW_2           0x02
+#define SW_3           0x03
+#define SW_4           0x04
+#define SW_5           0x05
+#define SW_6           0x06
+#define SW_7           0x07
+#define SW_MAX         0x0f
+
 /*
  * Misc events
  */
@@ -824,6 +840,7 @@ struct input_dev {
        unsigned long ledbit[NBITS(LED_MAX)];
        unsigned long sndbit[NBITS(SND_MAX)];
        unsigned long ffbit[NBITS(FF_MAX)];
+       unsigned long swbit[NBITS(SW_MAX)];
        int ff_effects_max;
 
        unsigned int keycodemax;
@@ -844,6 +861,7 @@ struct input_dev {
        unsigned long key[NBITS(KEY_MAX)];
        unsigned long led[NBITS(LED_MAX)];
        unsigned long snd[NBITS(SND_MAX)];
+       unsigned long sw[NBITS(SW_MAX)];
 
        int absmax[ABS_MAX + 1];
        int absmin[ABS_MAX + 1];
@@ -886,6 +904,7 @@ struct input_dev {
 #define INPUT_DEVICE_ID_MATCH_LEDBIT   0x200
 #define INPUT_DEVICE_ID_MATCH_SNDBIT   0x400
 #define INPUT_DEVICE_ID_MATCH_FFBIT    0x800
+#define INPUT_DEVICE_ID_MATCH_SWBIT    0x1000
 
 #define INPUT_DEVICE_ID_MATCH_DEVICE\
        (INPUT_DEVICE_ID_MATCH_BUS | INPUT_DEVICE_ID_MATCH_VENDOR | INPUT_DEVICE_ID_MATCH_PRODUCT)
@@ -906,6 +925,7 @@ struct input_device_id {
        unsigned long ledbit[NBITS(LED_MAX)];
        unsigned long sndbit[NBITS(SND_MAX)];
        unsigned long ffbit[NBITS(FF_MAX)];
+       unsigned long swbit[NBITS(SW_MAX)];
 
        unsigned long driver_info;
 };
@@ -998,6 +1018,11 @@ static inline void input_report_ff_status(struct input_dev *dev, unsigned int co
        input_event(dev, EV_FF_STATUS, code, value);
 }
 
+static inline void input_report_switch(struct input_dev *dev, unsigned int code, int value)
+{
+       input_event(dev, EV_SW, code, !!value);
+}
+
 static inline void input_regs(struct input_dev *dev, struct pt_regs *regs)
 {
        dev->regs = regs;
index e8c4af32b3bb6ddcbd2005aa57a776d79216aef5..948809d999177867fb0820236f32e59a3d7ce52a 100644 (file)
@@ -14,26 +14,4 @@ struct ioctl_trans {
        struct ioctl_trans *next;
 };
 
-/* 
- * Register an 32bit ioctl translation handler for ioctl cmd.
- *
- * handler == NULL: use 64bit ioctl handler.
- * arguments to handler:  fd: file descriptor
- *                        cmd: ioctl command.
- *                        arg: ioctl argument
- *                        struct file *file: file descriptor pointer.
- */ 
-
-#ifdef CONFIG_COMPAT
-extern int __deprecated register_ioctl32_conversion(unsigned int cmd,
-                               ioctl_trans_handler_t handler);
-extern int __deprecated unregister_ioctl32_conversion(unsigned int cmd);
-
-#else
-
-#define register_ioctl32_conversion(cmd, handler)      ({ 0; })
-#define unregister_ioctl32_conversion(cmd)             ({ 0; })
-
-#endif
-
 #endif
index 31e7cedd9f844b3e6d28dffe271da3b724e0f644..33e8a19a1a0fbaec33122f4f931c3d577fc975c9 100644 (file)
@@ -196,6 +196,8 @@ static inline void inet_sk_copy_descendant(struct sock *sk_to,
 #endif
 #endif
 
+extern int inet_sk_rebuild_header(struct sock *sk);
+
 struct iphdr {
 #if defined(__LITTLE_ENDIAN_BITFIELD)
        __u8    ihl:4,
index 596ca6130159f749036cf15860ba275c2122a6d3..938d55b813a5f600050fcc557331195b036fa12c 100644 (file)
@@ -35,6 +35,7 @@
 #define __LINUX_IPMI_H
 
 #include <linux/ipmi_msgdefs.h>
+#include <linux/compiler.h>
 
 /*
  * This file describes an interface to an IPMI driver.  You have to
@@ -241,7 +242,8 @@ struct ipmi_recv_msg
        /* The user_msg_data is the data supplied when a message was
           sent, if this is a response to a sent message.  If this is
           not a response to a sent message, then user_msg_data will
-          be NULL. */
+          be NULL.  If the user above is NULL, then this will be the
+          intf. */
        void             *user_msg_data;
 
        /* Call this when done with the message.  It will presumably free
@@ -298,13 +300,19 @@ void ipmi_get_version(ipmi_user_t   user,
    this user, so it will affect all users of this interface.  This is
    so some initialization code can come in and do the OEM-specific
    things it takes to determine your address (if not the BMC) and set
-   it for everyone else. */
-void ipmi_set_my_address(ipmi_user_t   user,
-                        unsigned char address);
-unsigned char ipmi_get_my_address(ipmi_user_t user);
-void ipmi_set_my_LUN(ipmi_user_t   user,
-                    unsigned char LUN);
-unsigned char ipmi_get_my_LUN(ipmi_user_t user);
+   it for everyone else.  Note that each channel can have its own address. */
+int ipmi_set_my_address(ipmi_user_t   user,
+                       unsigned int  channel,
+                       unsigned char address);
+int ipmi_get_my_address(ipmi_user_t   user,
+                       unsigned int  channel,
+                       unsigned char *address);
+int ipmi_set_my_LUN(ipmi_user_t   user,
+                   unsigned int  channel,
+                   unsigned char LUN);
+int ipmi_get_my_LUN(ipmi_user_t   user,
+                   unsigned int  channel,
+                   unsigned char *LUN);
 
 /*
  * Like ipmi_request, but lets you specify the number of retries and
@@ -585,6 +593,16 @@ struct ipmi_cmdspec
  * things it takes to determine your address (if not the BMC) and set
  * it for everyone else.  You should probably leave the LUN alone.
  */
+struct ipmi_channel_lun_address_set
+{
+       unsigned short channel;
+       unsigned char  value;
+};
+#define IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 24, struct ipmi_channel_lun_address_set)
+#define IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 25, struct ipmi_channel_lun_address_set)
+#define IPMICTL_SET_MY_CHANNEL_LUN_CMD    _IOR(IPMI_IOC_MAGIC, 26, struct ipmi_channel_lun_address_set)
+#define IPMICTL_GET_MY_CHANNEL_LUN_CMD    _IOR(IPMI_IOC_MAGIC, 27, struct ipmi_channel_lun_address_set)
+/* Legacy interfaces, these only set IPMB 0. */
 #define IPMICTL_SET_MY_ADDRESS_CMD     _IOR(IPMI_IOC_MAGIC, 17, unsigned int)
 #define IPMICTL_GET_MY_ADDRESS_CMD     _IOR(IPMI_IOC_MAGIC, 18, unsigned int)
 #define IPMICTL_SET_MY_LUN_CMD         _IOR(IPMI_IOC_MAGIC, 19, unsigned int)
index 6fcd6a0ade24860807917b746abc5179c6338f6a..3c7dbc6a0a707510ae0171c20dc5e9918ca673e0 100644 (file)
@@ -193,6 +193,11 @@ struct inet6_skb_parm {
 
 #define IP6CB(skb)     ((struct inet6_skb_parm*)((skb)->cb))
 
+static inline int inet6_iif(const struct sk_buff *skb)
+{
+       return IP6CB(skb)->iif;
+}
+
 struct tcp6_request_sock {
        struct tcp_request_sock req;
        struct in6_addr         loc_addr;
@@ -308,6 +313,36 @@ static inline void inet_sk_copy_descendant(struct sock *sk_to,
 
 #define __ipv6_only_sock(sk)   (inet6_sk(sk)->ipv6only)
 #define ipv6_only_sock(sk)     ((sk)->sk_family == PF_INET6 && __ipv6_only_sock(sk))
+
+#include <linux/tcp.h>
+
+struct tcp6_timewait_sock {
+       struct tcp_timewait_sock tw_v6_sk;
+       struct in6_addr          tw_v6_daddr;
+       struct in6_addr          tw_v6_rcv_saddr;
+};
+
+static inline struct tcp6_timewait_sock *tcp6_twsk(const struct sock *sk)
+{
+       return (struct tcp6_timewait_sock *)sk;
+}
+
+static inline struct in6_addr *__tcp_v6_rcv_saddr(const struct sock *sk)
+{
+       return likely(sk->sk_state != TCP_TIME_WAIT) ?
+               &inet6_sk(sk)->rcv_saddr : &tcp6_twsk(sk)->tw_v6_rcv_saddr;
+}
+
+static inline struct in6_addr *tcp_v6_rcv_saddr(const struct sock *sk)
+{
+       return sk->sk_family == AF_INET6 ? __tcp_v6_rcv_saddr(sk) : NULL;
+}
+
+static inline int inet_v6_ipv6only(const struct sock *sk)
+{
+       return likely(sk->sk_state != TCP_TIME_WAIT) ?
+               ipv6_only_sock(sk) : inet_twsk(sk)->tw_ipv6only;
+}
 #else
 #define __ipv6_only_sock(sk)   0
 #define ipv6_only_sock(sk)     0
@@ -322,8 +357,19 @@ static inline struct raw6_sock *raw6_sk(const struct sock *sk)
        return NULL;
 }
 
-#endif
+#define __tcp_v6_rcv_saddr(__sk)       NULL
+#define tcp_v6_rcv_saddr(__sk)         NULL
+#define tcp_twsk_ipv6only(__sk)                0
+#define inet_v6_ipv6only(__sk)         0
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
 
-#endif
+#define INET6_MATCH(__sk, __saddr, __daddr, __ports, __dif)       \
+       (((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports))   && \
+        ((__sk)->sk_family             == AF_INET6)            && \
+        ipv6_addr_equal(&inet6_sk(__sk)->daddr, (__saddr))     && \
+        ipv6_addr_equal(&inet6_sk(__sk)->rcv_saddr, (__daddr)) && \
+        (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
 
-#endif
+#endif /* __KERNEL__ */
+
+#endif /* _IPV6_H */
index 069d3b84d311b442ffbbe2074733b78f5e894b7b..69681c3b1f05f8fac09efb8ad5334c60b65686c0 100644 (file)
 #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 */
-#define IRQ_PER_CPU    256     /* IRQ is per CPU */
+#if defined(ARCH_HAS_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
 
 /*
  * Interrupt controller descriptor. This is all we need
@@ -71,16 +76,139 @@ typedef struct irq_desc {
        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*/
+#endif
 } ____cacheline_aligned irq_desc_t;
 
 extern irq_desc_t 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;
+}
+
 #include <asm/hw_irq.h> /* the arch dependent stuff */
 
 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;
+}
+#else
+static inline void set_native_irq_info(int irq, cpumask_t mask)
+{
+}
+#endif
+
+#ifdef CONFIG_SMP
+
+#if defined (CONFIG_GENERIC_PENDING_IRQ) || defined (CONFIG_IRQBALANCE)
+extern cpumask_t pending_irq_cpumask[NR_IRQS];
+
+static inline void set_pending_irq(unsigned int irq, cpumask_t mask)
+{
+       irq_desc_t *desc = irq_desc + irq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&desc->lock, flags);
+       desc->move_irq = 1;
+       pending_irq_cpumask[irq] = mask;
+       spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+static inline void
+move_native_irq(int irq)
+{
+       cpumask_t tmp;
+       irq_desc_t *desc = irq_descp(irq);
+
+       if (likely (!desc->move_irq))
+               return;
+
+       desc->move_irq = 0;
+
+       if (likely(cpus_empty(pending_irq_cpumask[irq])))
+               return;
+
+       if (!desc->handler->set_affinity)
+               return;
+
+       /* note - we hold the desc->lock */
+       cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map);
+
+       /*
+        * If there was a valid mask to work with, please
+        * do the disable, re-program, enable sequence.
+        * This is *not* particularly important for level triggered
+        * but in a edge trigger case, we might be setting rte
+        * when an active trigger is comming in. This could
+        * cause some ioapics to mal-function.
+        * Being paranoid i guess!
+        */
+       if (unlikely(!cpus_empty(tmp))) {
+               desc->handler->disable(irq);
+               desc->handler->set_affinity(irq,tmp);
+               desc->handler->enable(irq);
+       }
+       cpus_clear(pending_irq_cpumask[irq]);
+}
+
+#ifdef CONFIG_PCI_MSI
+/*
+ * Wonder why these are dummies?
+ * For e.g the set_ioapic_affinity_vector() calls the set_ioapic_affinity_irq()
+ * counter part after translating the vector to irq info. We need to perform
+ * this operation on the real irq, when we dont use vector, i.e when
+ * pci_use_vector() is false.
+ */
+static inline void move_irq(int irq)
+{
+}
+
+static inline void set_irq_info(int irq, cpumask_t mask)
+{
+}
+
+#else // CONFIG_PCI_MSI
+
+static inline void move_irq(int irq)
+{
+       move_native_irq(irq);
+}
+
+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
+
+#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
+
+#else // CONFIG_SMP
+
+#define move_irq(x)
+#define move_native_irq(x)
+
+#endif // CONFIG_SMP
+
 extern int no_irq_affinity;
 extern int noirqdebug_setup(char *str);
 
index 862083eb58ab2d6650b876576d2ddd9e81e162b2..53eaee96065bc0512370b866511c7b3ed4f11737 100644 (file)
@@ -150,7 +150,6 @@ typedef struct {
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/major.h>
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
index 593407e865b1b0ce543f3bee6059b71452b32ede..84321a4cac93a1e942a4df994f28dbf44aeeec86 100644 (file)
@@ -914,7 +914,6 @@ extern int     journal_wipe       (journal_t *, int);
 extern int        journal_skip_recovery        (journal_t *);
 extern void       journal_update_superblock    (journal_t *, int);
 extern void       __journal_abort_hard (journal_t *);
-extern void       __journal_abort_soft (journal_t *, int);
 extern void       journal_abort      (journal_t *, int);
 extern int        journal_errno      (journal_t *);
 extern void       journal_ack_err    (journal_t *);
index eebf5e5696ec3b31323303a354026507b54ded52..c4d1fae4dd89a5a74ba95b1f8b8d6cd21a9edb1f 100644 (file)
@@ -9,6 +9,9 @@
  *     This file is rleased under the GPL v2.
  */
 
+#ifndef _LINUX_KLIST_H
+#define _LINUX_KLIST_H
+
 #include <linux/spinlock.h>
 #include <linux/completion.h>
 #include <linux/kref.h>
@@ -31,8 +34,8 @@ struct klist_node {
        struct completion       n_removed;
 };
 
-extern void klist_add_tail(struct klist * k, struct klist_node * n);
-extern void klist_add_head(struct klist * k, struct klist_node * n);
+extern void klist_add_tail(struct klist_node * n, struct klist * k);
+extern void klist_add_head(struct klist_node * n, struct klist * k);
 
 extern void klist_del(struct klist_node * n);
 extern void klist_remove(struct klist_node * n);
@@ -53,3 +56,4 @@ extern void klist_iter_init_node(struct klist * k, struct klist_iter * i,
 extern void klist_iter_exit(struct klist_iter * i);
 extern struct klist_node * klist_next(struct klist_iter * i);
 
+#endif
index e050fc2d4c26146fac9d289de9b2cfda5663e400..e30afdca79174f9a01b0b538dca138f62bf697f2 100644 (file)
@@ -42,6 +42,9 @@
 #define KPROBE_REENTER         0x00000004
 #define KPROBE_HIT_SSDONE      0x00000008
 
+/* Attach to insert probes on any functions which should be ignored*/
+#define __kprobes      __attribute__((__section__(".kprobes.text")))
+
 struct kprobe;
 struct pt_regs;
 struct kretprobe;
index 6cd9ba63563b4db61b0977a88db84894d313735c..022105c745fcca5cf9de0322f7dc9b69fe3940a4 100644 (file)
@@ -1,23 +1,26 @@
 /*
-   Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
-   Copyright 2003-2004 Jeff Garzik
-
-   The contents of this file are subject to the Open
-   Software License version 1.1 that can be found at
-   http://www.opensource.org/licenses/osl-1.1.txt and is included herein
-   by reference.
-
-   Alternatively, the contents of this file may be used under the terms
-   of the GNU General Public License version 2 (the "GPL") as distributed
-   in the kernel source COPYING file, in which case the provisions of
-   the GPL are applicable instead of the above.  If you wish to allow
-   the use of your version of this file only under the terms of the
-   GPL and not to allow others to use your version of this file under
-   the OSL, indicate your decision by deleting the provisions above and
-   replace them with the notice and other provisions required by the GPL.
-   If you do not delete the provisions above, a recipient may use your
-   version of this file under either the OSL or the GPL.
-
+ *  Copyright 2003-2005 Red Hat, Inc.  All rights reserved.
+ *  Copyright 2003-2005 Jeff Garzik
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
  */
 
 #ifndef __LINUX_LIBATA_H__
@@ -37,7 +40,6 @@
 #undef ATA_VERBOSE_DEBUG       /* yet more debugging output */
 #undef ATA_IRQ_TRAP            /* define to ack screaming irqs */
 #undef ATA_NDEBUG              /* define to disable quick runtime checks */
-#undef ATA_ENABLE_ATAPI                /* define to enable ATAPI support */
 #undef ATA_ENABLE_PATA         /* define to enable PATA support in some
                                 * low-level drivers */
 #undef ATAPI_ENABLE_DMADIR     /* enables ATAPI DMADIR bridge support */
@@ -113,6 +115,8 @@ enum {
        ATA_FLAG_MMIO           = (1 << 6), /* use MMIO, not PIO */
        ATA_FLAG_SATA_RESET     = (1 << 7), /* use COMRESET */
        ATA_FLAG_PIO_DMA        = (1 << 8), /* PIO cmds via DMA */
+       ATA_FLAG_NOINTR         = (1 << 9), /* FIXME: Remove this once
+                                            * proper HSM is in place. */
 
        ATA_QCFLAG_ACTIVE       = (1 << 1), /* cmd not yet ack'd to scsi lyer */
        ATA_QCFLAG_SG           = (1 << 3), /* have s/g table? */
@@ -363,7 +367,7 @@ struct ata_port_operations {
 
        void (*host_stop) (struct ata_host_set *host_set);
 
-       void (*bmdma_stop) (struct ata_port *ap);
+       void (*bmdma_stop) (struct ata_queued_cmd *qc);
        u8   (*bmdma_status) (struct ata_port *ap);
 };
 
@@ -424,7 +428,7 @@ extern void ata_dev_id_string(u16 *id, unsigned char *s,
 extern void ata_dev_config(struct ata_port *ap, unsigned int i);
 extern void ata_bmdma_setup (struct ata_queued_cmd *qc);
 extern void ata_bmdma_start (struct ata_queued_cmd *qc);
-extern void ata_bmdma_stop(struct ata_port *ap);
+extern void ata_bmdma_stop(struct ata_queued_cmd *qc);
 extern u8   ata_bmdma_status(struct ata_port *ap);
 extern void ata_bmdma_irq_clear(struct ata_port *ap);
 extern void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat);
@@ -445,6 +449,7 @@ struct pci_bits {
        unsigned long           val;
 };
 
+extern void ata_pci_host_stop (struct ata_host_set *host_set);
 extern struct ata_probe_ent *
 ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port);
 extern int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits);
@@ -644,7 +649,7 @@ static inline void scr_write(struct ata_port *ap, unsigned int reg, u32 val)
        ap->ops->scr_write(ap, reg, val);
 }
 
-static inline void scr_write_flush(struct ata_port *ap, unsigned int reg, 
+static inline void scr_write_flush(struct ata_port *ap, unsigned int reg,
                                   u32 val)
 {
        ap->ops->scr_write(ap, reg, val);
index 338f7795d8a071d63b05969505b6fe9894eafc46..147eb01e0d4bbe536da8bef077fac4ed8d9cdd37 100644 (file)
   ALIGN; \
   name:
 
+#define KPROBE_ENTRY(name) \
+  .section .kprobes.text, "ax"; \
+  .globl name; \
+  ALIGN; \
+  name:
+
+
 #endif
 
 #define NORET_TYPE    /**/
index aab2db21b013e438c672dbfe4fcceb065bf578d3..e6ec596822740ea70a2e6b4b865b704ba8bef4f7 100644 (file)
@@ -418,6 +418,20 @@ static inline void list_splice_init(struct list_head *list,
             &pos->member != (head);                                    \
             pos = n, n = list_entry(n->member.next, typeof(*n), member))
 
+/**
+ * list_for_each_entry_safe_continue - iterate over list of given type
+ *                     continuing after existing point 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.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member)                \
+       for (pos = list_entry(pos->member.next, typeof(*pos), member),          \
+               n = list_entry(pos->member.next, typeof(*pos), member);         \
+            &pos->member != (head);                                            \
+            pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
 /**
  * list_for_each_rcu   -       iterate over an rcu-protected list
  * @pos:       the &struct list_head to use as a loop counter.
@@ -620,6 +634,57 @@ static inline void hlist_add_after(struct hlist_node *n,
                next->next->pprev  = &next->next;
 }
 
+/**
+ * hlist_add_before_rcu - adds the specified element to the specified hlist
+ * before the specified node while permitting racing traversals.
+ * @n: the new element to add to the hash list.
+ * @next: the existing element to add the new element before.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_rcu(), used to prevent memory-consistency
+ * problems on Alpha CPUs.
+ */
+static inline void hlist_add_before_rcu(struct hlist_node *n,
+                                       struct hlist_node *next)
+{
+       n->pprev = next->pprev;
+       n->next = next;
+       smp_wmb();
+       next->pprev = &n->next;
+       *(n->pprev) = n;
+}
+
+/**
+ * hlist_add_after_rcu - adds the specified element to the specified hlist
+ * after the specified node while permitting racing traversals.
+ * @prev: the existing element to add the new element after.
+ * @n: the new element to add to the hash list.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_rcu(), used to prevent memory-consistency
+ * problems on Alpha CPUs.
+ */
+static inline void hlist_add_after_rcu(struct hlist_node *prev,
+                                      struct hlist_node *n)
+{
+       n->next = prev->next;
+       n->pprev = &prev->next;
+       smp_wmb();
+       prev->next = n;
+       if (n->next)
+               n->next->pprev = &n->next;
+}
+
 #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
 
 #define hlist_for_each(pos, head) \
index 8480aef10e62fa41d986751a651ffd090db4ceb7..94a46f38c5326f8a337c256e7ba6d209951e7a6b 100644 (file)
@@ -150,6 +150,9 @@ void mpol_free_shared_policy(struct shared_policy *p);
 struct mempolicy *mpol_shared_policy_lookup(struct shared_policy *sp,
                                            unsigned long idx);
 
+struct mempolicy *get_vma_policy(struct task_struct *task,
+                       struct vm_area_struct *vma, unsigned long addr);
+
 extern void numa_default_policy(void);
 extern void numa_policy_init(void);
 
index 374b615ea9ea95ec130aeb10dfffc31f0f29a6f1..9b8d0476988ad3bb1aa9bfeeae74b9d8b1a6f57f 100644 (file)
@@ -22,6 +22,7 @@
 #define MII_EXPANSION       0x06        /* Expansion register          */
 #define MII_CTRL1000        0x09        /* 1000BASE-T control          */
 #define MII_STAT1000        0x0a        /* 1000BASE-T status           */
+#define MII_ESTATUS        0x0f        /* Extended Status */
 #define MII_DCOUNTER        0x12        /* Disconnect counter          */
 #define MII_FCSCOUNTER      0x13        /* False carrier counter       */
 #define MII_NWAYTEST        0x14        /* N-way auto-neg test reg     */
 #define BMSR_ANEGCAPABLE        0x0008  /* Able to do auto-negotiation */
 #define BMSR_RFAULT             0x0010  /* Remote fault detected       */
 #define BMSR_ANEGCOMPLETE       0x0020  /* Auto-negotiation complete   */
-#define BMSR_RESV               0x07c0  /* Unused...                   */
+#define BMSR_RESV               0x00c0  /* Unused...                   */
+#define BMSR_ESTATEN           0x0100  /* Extended Status in R15 */
+#define BMSR_100FULL2          0x0200  /* Can do 100BASE-T2 HDX */
+#define BMSR_100HALF2          0x0400  /* Can do 100BASE-T2 FDX */
 #define BMSR_10HALF             0x0800  /* Can do 10mbps, half-duplex  */
 #define BMSR_10FULL             0x1000  /* Can do 10mbps, full-duplex  */
 #define BMSR_100HALF            0x2000  /* Can do 100mbps, half-duplex */
 #define EXPANSION_MFAULTS       0x0010  /* Multiple faults detected    */
 #define EXPANSION_RESV          0xffe0  /* Unused...                   */
 
+#define ESTATUS_1000_TFULL     0x2000  /* Can do 1000BT Full */
+#define ESTATUS_1000_THALF     0x1000  /* Can do 1000BT Half */
+
 /* N-way test register. */
 #define NWAYTEST_RESV1          0x00ff  /* Unused...                   */
 #define NWAYTEST_LOOPBACK       0x0100  /* Enable loopback for N-way   */
index aefedf04b9bb24384ed423b8876ee3a4d6219331..18fc77f682de8dcf629c83945c4595fd3cc0b82c 100644 (file)
@@ -33,6 +33,13 @@ struct mmc_csd {
        unsigned int            capacity;
 };
 
+struct sd_scr {
+       unsigned char           sda_vsn;
+       unsigned char           bus_widths;
+#define SD_SCR_BUS_WIDTH_1     (1<<0)
+#define SD_SCR_BUS_WIDTH_4     (1<<2)
+};
+
 struct mmc_host;
 
 /*
@@ -47,19 +54,27 @@ struct mmc_card {
 #define MMC_STATE_PRESENT      (1<<0)          /* present in sysfs */
 #define MMC_STATE_DEAD         (1<<1)          /* device no longer in stack */
 #define MMC_STATE_BAD          (1<<2)          /* unrecognised device */
+#define MMC_STATE_SDCARD       (1<<3)          /* is an SD card */
+#define MMC_STATE_READONLY     (1<<4)          /* card is read-only */
        u32                     raw_cid[4];     /* raw card CID */
        u32                     raw_csd[4];     /* raw card CSD */
+       u32                     raw_scr[2];     /* raw card SCR */
        struct mmc_cid          cid;            /* card identification */
        struct mmc_csd          csd;            /* card specific */
+       struct sd_scr           scr;            /* extra SD information */
 };
 
 #define mmc_card_present(c)    ((c)->state & MMC_STATE_PRESENT)
 #define mmc_card_dead(c)       ((c)->state & MMC_STATE_DEAD)
 #define mmc_card_bad(c)                ((c)->state & MMC_STATE_BAD)
+#define mmc_card_sd(c)         ((c)->state & MMC_STATE_SDCARD)
+#define mmc_card_readonly(c)   ((c)->state & MMC_STATE_READONLY)
 
 #define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_dead(c)   ((c)->state |= MMC_STATE_DEAD)
 #define mmc_card_set_bad(c)    ((c)->state |= MMC_STATE_BAD)
+#define mmc_card_set_sd(c)     ((c)->state |= MMC_STATE_SDCARD)
+#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 
 #define mmc_card_name(c)       ((c)->cid.prod_name)
 #define mmc_card_id(c)         ((c)->dev.bus_id)
index f90f674eb3b0ee48b6701941da6457a898530f5b..6014160d9c0665acc497ade8b1236f93f1f4637a 100644 (file)
@@ -46,16 +46,28 @@ struct mmc_ios {
 #define MMC_BUSMODE_OPENDRAIN  1
 #define MMC_BUSMODE_PUSHPULL   2
 
+       unsigned char   chip_select;            /* SPI chip select */
+
+#define MMC_CS_DONTCARE                0
+#define MMC_CS_HIGH            1
+#define MMC_CS_LOW             2
+
        unsigned char   power_mode;             /* power supply mode */
 
 #define MMC_POWER_OFF          0
 #define MMC_POWER_UP           1
 #define MMC_POWER_ON           2
+
+       unsigned char   bus_width;              /* data bus width */
+
+#define MMC_BUS_WIDTH_1                0
+#define MMC_BUS_WIDTH_4                2
 };
 
 struct mmc_host_ops {
        void    (*request)(struct mmc_host *host, struct mmc_request *req);
        void    (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
+       int     (*get_ro)(struct mmc_host *host);
 };
 
 struct mmc_card;
@@ -63,11 +75,16 @@ struct device;
 
 struct mmc_host {
        struct device           *dev;
+       struct class_device     class_dev;
+       int                     index;
        struct mmc_host_ops     *ops;
        unsigned int            f_min;
        unsigned int            f_max;
        u32                     ocr_avail;
-       char                    host_name[8];
+
+       unsigned long           caps;           /* Host capabilities */
+
+#define MMC_CAP_4_BIT_DATA     (1 << 0)        /* Can the host do 4 bit transfers */
 
        /* host specific block data */
        unsigned int            max_seg_size;   /* see blk_queue_max_segment_size */
@@ -80,6 +97,10 @@ struct mmc_host {
        struct mmc_ios          ios;            /* current io bus settings */
        u32                     ocr;            /* the current OCR setting */
 
+       unsigned int            mode;           /* current card mode of host */
+#define MMC_MODE_MMC           0
+#define MMC_MODE_SD            1
+
        struct list_head        cards;          /* devices attached to this host */
 
        wait_queue_head_t       wq;
@@ -97,6 +118,7 @@ extern void mmc_free_host(struct mmc_host *);
 
 #define mmc_priv(x)    ((void *)((x) + 1))
 #define mmc_dev(x)     ((x)->dev)
+#define mmc_hostname(x)        ((x)->class_dev.class_id)
 
 extern int mmc_suspend_host(struct mmc_host *, pm_message_t);
 extern int mmc_resume_host(struct mmc_host *);
index 0d35d4ffb360d8def93506fa05fe99be852d1dc2..1ab78e8d6c530ac36c69c12038aea7112063a2d7 100644 (file)
@@ -88,6 +88,8 @@ struct mmc_card;
 
 extern int mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
+extern int mmc_wait_for_app_cmd(struct mmc_host *, unsigned int,
+       struct mmc_command *, int);
 
 extern int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card);
 
index 896342817b97bab2a7b20bb247115317224583fe..f819cae92266aa2fdd889d7bbe9b6480828d9680 100644 (file)
@@ -236,5 +236,12 @@ struct _mmc_csd {
 #define CSD_SPEC_VER_2      2           /* Implements system specification 2.0 - 2.2 */
 #define CSD_SPEC_VER_3      3           /* Implements system specification 3.1 */
 
+
+/*
+ * SD bus widths
+ */
+#define SD_BUS_WIDTH_1      0
+#define SD_BUS_WIDTH_4      2
+
 #endif  /* MMC_MMC_PROTOCOL_H */
 
index 6c90461ed99fd5707c178d3b4fbf922b367b55b0..5ed471b58f4f0c83904101ee6cb734bb104a47ad 100644 (file)
@@ -487,11 +487,27 @@ struct mem_section {
        unsigned long section_mem_map;
 };
 
-extern struct mem_section mem_section[NR_MEM_SECTIONS];
+#ifdef CONFIG_SPARSEMEM_EXTREME
+#define SECTIONS_PER_ROOT       (PAGE_SIZE / sizeof (struct mem_section))
+#else
+#define SECTIONS_PER_ROOT      1
+#endif
+
+#define SECTION_NR_TO_ROOT(sec)        ((sec) / SECTIONS_PER_ROOT)
+#define NR_SECTION_ROOTS       (NR_MEM_SECTIONS / SECTIONS_PER_ROOT)
+#define SECTION_ROOT_MASK      (SECTIONS_PER_ROOT - 1)
+
+#ifdef CONFIG_SPARSEMEM_EXTREME
+extern struct mem_section *mem_section[NR_SECTION_ROOTS];
+#else
+extern struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT];
+#endif
 
 static inline struct mem_section *__nr_to_section(unsigned long nr)
 {
-       return &mem_section[nr];
+       if (!mem_section[SECTION_NR_TO_ROOT(nr)])
+               return NULL;
+       return &mem_section[SECTION_NR_TO_ROOT(nr)][nr & SECTION_ROOT_MASK];
 }
 
 /*
@@ -513,12 +529,12 @@ static inline struct page *__section_mem_map_addr(struct mem_section *section)
 
 static inline int valid_section(struct mem_section *section)
 {
-       return (section->section_mem_map & SECTION_MARKED_PRESENT);
+       return (section && (section->section_mem_map & SECTION_MARKED_PRESENT));
 }
 
 static inline int section_has_mem_map(struct mem_section *section)
 {
-       return (section->section_mem_map & SECTION_HAS_MEM_MAP);
+       return (section && (section->section_mem_map & SECTION_HAS_MEM_MAP));
 }
 
 static inline int valid_section_nr(unsigned long nr)
@@ -572,6 +588,7 @@ static inline int pfn_valid(unsigned long pfn)
 void sparse_init(void);
 #else
 #define sparse_init()  do {} while (0)
+#define sparse_index_init(_sec, _nid)  do {} while (0)
 #endif /* CONFIG_SPARSEMEM */
 
 #ifdef CONFIG_NODES_SPAN_OTHER_NODES
index dce53ac1625d8cea5c78b1940aedc6441dc52d63..47da39ba3f0377f378556150daed3d5530a49849 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Device tables which are exported to userspace via
- * scripts/table2alias.c.  You must keep that file in sync with this
+ * scripts/mod/file2alias.c.  You must keep that file in sync with this
  * header.
  */
 
@@ -33,7 +33,8 @@ struct ieee1394_device_id {
        __u32 model_id;
        __u32 specifier_id;
        __u32 version;
-       kernel_ulong_t driver_data;
+       kernel_ulong_t driver_data
+               __attribute__((aligned(sizeof(kernel_ulong_t))));
 };
 
 
@@ -182,9 +183,18 @@ struct of_device_id
        char    name[32];
        char    type[32];
        char    compatible[128];
+#if __KERNEL__
        void    *data;
+#else
+       kernel_ulong_t data;
+#endif
 };
 
+/* VIO */
+struct vio_device_id {
+       char type[32];
+       char compat[32];
+};
 
 /* PCMCIA */
 
@@ -208,7 +218,8 @@ struct pcmcia_device_id {
 #ifdef __KERNEL__
        const char *    prod_id[4];
 #else
-       kernel_ulong_t  prod_id[4];
+       kernel_ulong_t  prod_id[4]
+               __attribute__((aligned(sizeof(kernel_ulong_t))));
 #endif
 
        /* not matched against */
index 2c4c6aa643ff42f20217f88205ef55349b0c707f..903e0ab8101fad230721c7ecd27653b413a5d058 100644 (file)
@@ -77,6 +77,7 @@ struct msg_msg {
 /* one msq_queue structure for each present queue on the system */
 struct msg_queue {
        struct kern_ipc_perm q_perm;
+       int q_id;
        time_t q_stime;                 /* last msgsnd time */
        time_t q_rtime;                 /* last msgrcv time */
        time_t q_ctime;                 /* last change time */
index 5773ea42f6e445b406e44abe9197370be24dc132..0b08cd6922012589a938209b240a27f7bb898580 100644 (file)
 /* I2C Registers                        */
 /****************************************/
 
-#define MV64XXX_I2C_CTLR_NAME                                  "mv64xxx i2c"
+#define MV64XXX_I2C_CTLR_NAME                                  "mv64xxx_i2c"
 #define MV64XXX_I2C_OFFSET                                          0xc000
 #define MV64XXX_I2C_REG_BLOCK_SIZE                                  0x0020
 
index 20cb226b22685fcd55428104c84b64ba14c4443c..4e981585a89a349f9444ffdbfe9588cbf66d1671 100644 (file)
@@ -84,6 +84,7 @@ enum sock_type {
        SOCK_RAW        = 3,
        SOCK_RDM        = 4,
        SOCK_SEQPACKET  = 5,
+       SOCK_DCCP       = 6,
        SOCK_PACKET     = 10,
 };
 
@@ -282,5 +283,15 @@ static struct proto_ops name##_ops = {                     \
 #define MODULE_ALIAS_NETPROTO(proto) \
        MODULE_ALIAS("net-pf-" __stringify(proto))
 
+#define MODULE_ALIAS_NET_PF_PROTO(pf, proto) \
+       MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto))
+
+#ifdef CONFIG_SYSCTL
+#include <linux/sysctl.h>
+extern ctl_table net_table[];
+extern int net_msg_cost;
+extern int net_msg_burst;
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_NET_H */
index 3a0ed7f9e8015bb3165fb1e55eaf44493d9521e2..7c717907896d1d5de04ac4028f70a0ff83b8bb13 100644 (file)
@@ -244,6 +244,7 @@ struct netdev_boot_setup {
 };
 #define NETDEV_BOOT_SETUP_MAX 8
 
+extern int __init netdev_boot_setup(char *str);
 
 /*
  *     The DEVICE structure.
@@ -336,6 +337,7 @@ struct net_device
        /* Interface address info. */
        unsigned char           broadcast[MAX_ADDR_LEN];        /* hw bcast add */
        unsigned char           dev_addr[MAX_ADDR_LEN]; /* hw address   */
+       unsigned char           perm_addr[MAX_ADDR_LEN]; /* permanent hw address */
        unsigned char           addr_len;       /* hardware address length      */
        unsigned short          dev_id;         /* for shared network cards */
 
@@ -497,10 +499,12 @@ static inline void *netdev_priv(struct net_device *dev)
 #define SET_NETDEV_DEV(net, pdev)      ((net)->class_dev.dev = (pdev))
 
 struct packet_type {
-       __be16                  type;   /* This is really htons(ether_type).    */
-       struct net_device               *dev;   /* NULL is wildcarded here              */
-       int                     (*func) (struct sk_buff *, struct net_device *,
-                                        struct packet_type *);
+       __be16                  type;   /* This is really htons(ether_type). */
+       struct net_device       *dev;   /* NULL is wildcarded here           */
+       int                     (*func) (struct sk_buff *,
+                                        struct net_device *,
+                                        struct packet_type *,
+                                        struct net_device *);
        void                    *af_packet_priv;
        struct list_head        list;
 };
@@ -671,6 +675,7 @@ extern void         dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev);
 extern void            dev_init(void);
 
 extern int             netdev_nit;
+extern int             netdev_budget;
 
 /* Called by rtnetlink.c:rtnl_unlock() */
 extern void netdev_run_todo(void);
@@ -697,19 +702,9 @@ static inline int netif_carrier_ok(const struct net_device *dev)
 
 extern void __netdev_watchdog_up(struct net_device *dev);
 
-static inline void netif_carrier_on(struct net_device *dev)
-{
-       if (test_and_clear_bit(__LINK_STATE_NOCARRIER, &dev->state))
-               linkwatch_fire_event(dev);
-       if (netif_running(dev))
-               __netdev_watchdog_up(dev);
-}
+extern void netif_carrier_on(struct net_device *dev);
 
-static inline void netif_carrier_off(struct net_device *dev)
-{
-       if (!test_and_set_bit(__LINK_STATE_NOCARRIER, &dev->state))
-               linkwatch_fire_event(dev);
-}
+extern void netif_carrier_off(struct net_device *dev);
 
 /* Hot-plugging. */
 static inline int netif_device_present(struct net_device *dev)
@@ -916,6 +911,14 @@ extern int skb_checksum_help(struct sk_buff *skb, int inward);
 extern void            net_enable_timestamp(void);
 extern void            net_disable_timestamp(void);
 
+#ifdef CONFIG_PROC_FS
+extern void *dev_seq_start(struct seq_file *seq, loff_t *pos);
+extern void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos);
+extern void dev_seq_stop(struct seq_file *seq, void *v);
+#endif
+
+extern void linkwatch_run_queue(void);
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_DEV_H */
index 2e2045482cb134d6bf8f9631e2c32a391052d6a1..be365e70ee998a25865e4504fd853aa9b2bde2a3 100644 (file)
 #define NF_STOP 5
 #define NF_MAX_VERDICT NF_STOP
 
+/* we overload the higher bits for encoding auxiliary data such as the queue
+ * number. Not nice, but better than additional function arguments. */
+#define NF_VERDICT_MASK 0x0000ffff
+#define NF_VERDICT_BITS 16
+
+#define NF_VERDICT_QMASK 0xffff0000
+#define NF_VERDICT_QBITS 16
+
+#define NF_QUEUE_NR(x) (((x << NF_VERDICT_QBITS) & NF_VERDICT_QMASK) | NF_QUEUE)
+
+/* only for userspace compatibility */
+#ifndef __KERNEL__
 /* Generic cache responses from hook functions.
    <= 0x2000 is used for protocol-flags. */
 #define NFC_UNKNOWN 0x4000
 #define NFC_ALTERED 0x8000
+#endif
 
 #ifdef __KERNEL__
 #include <linux/config.h>
@@ -101,15 +114,51 @@ void nf_unregister_sockopt(struct nf_sockopt_ops *reg);
 
 extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
 
-typedef void nf_logfn(unsigned int hooknum,
+/* those NF_LOG_* defines and struct nf_loginfo are legacy definitios that will
+ * disappear once iptables is replaced with pkttables.  Please DO NOT use them
+ * for any new code! */
+#define NF_LOG_TCPSEQ          0x01    /* Log TCP sequence numbers */
+#define NF_LOG_TCPOPT          0x02    /* Log TCP options */
+#define NF_LOG_IPOPT           0x04    /* Log IP options */
+#define NF_LOG_UID             0x08    /* Log UID owning local socket */
+#define NF_LOG_MASK            0x0f
+
+#define NF_LOG_TYPE_LOG                0x01
+#define NF_LOG_TYPE_ULOG       0x02
+
+struct nf_loginfo {
+       u_int8_t type;
+       union {
+               struct {
+                       u_int32_t copy_len;
+                       u_int16_t group;
+                       u_int16_t qthreshold;
+               } ulog;
+               struct {
+                       u_int8_t level;
+                       u_int8_t logflags;
+               } log;
+       } u;
+};
+
+typedef void nf_logfn(unsigned int pf,
+                     unsigned int hooknum,
                      const struct sk_buff *skb,
                      const struct net_device *in,
                      const struct net_device *out,
+                     const struct nf_loginfo *li,
                      const char *prefix);
 
+struct nf_logger {
+       struct module   *me;
+       nf_logfn        *logfn;
+       char            *name;
+};
+
 /* Function to register/unregister log function. */
-int nf_log_register(int pf, nf_logfn *logfn);
-void nf_log_unregister(int pf, nf_logfn *logfn);
+int nf_log_register(int pf, struct nf_logger *logger);
+int nf_log_unregister_pf(int pf);
+void nf_log_unregister_logger(struct nf_logger *logger);
 
 /* Calls the registered backend logging function */
 void nf_log_packet(int pf,
@@ -117,6 +166,7 @@ void nf_log_packet(int pf,
                   const struct sk_buff *skb,
                   const struct net_device *in,
                   const struct net_device *out,
+                  struct nf_loginfo *li,
                   const char *fmt, ...);
                    
 /* Activate hook; either okfn or kfree_skb called, unless a hook
@@ -175,11 +225,16 @@ int nf_getsockopt(struct sock *sk, int pf, int optval, char __user *opt,
                  int *len);
 
 /* Packet queuing */
-typedef int (*nf_queue_outfn_t)(struct sk_buff *skb, 
-                                struct nf_info *info, void *data);
+struct nf_queue_handler {
+       int (*outfn)(struct sk_buff *skb, struct nf_info *info,
+                    unsigned int queuenum, void *data);
+       void *data;
+       char *name;
+};
 extern int nf_register_queue_handler(int pf, 
-                                     nf_queue_outfn_t outfn, void *data);
+                                     struct nf_queue_handler *qh);
 extern int nf_unregister_queue_handler(int pf);
+extern void nf_unregister_queue_handlers(struct nf_queue_handler *qh);
 extern void nf_reinject(struct sk_buff *skb,
                        struct nf_info *info,
                        unsigned int verdict);
@@ -190,6 +245,27 @@ extern void nf_ct_attach(struct sk_buff *, struct sk_buff *);
 /* FIXME: Before cache is ever used, this must be implemented for real. */
 extern void nf_invalidate_cache(int pf);
 
+/* Call this before modifying an existing packet: ensures it is
+   modifiable and linear to the point you care about (writable_len).
+   Returns true or false. */
+extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len);
+
+struct nf_queue_rerouter {
+       void (*save)(const struct sk_buff *skb, struct nf_info *info);
+       int (*reroute)(struct sk_buff **skb, const struct nf_info *info);
+       int rer_size;
+};
+
+#define nf_info_reroute(x) ((void *)x + sizeof(struct nf_info))
+
+extern int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer);
+extern int nf_unregister_queue_rerouter(int pf);
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+extern struct proc_dir_entry *proc_net_netfilter;
+#endif
+
 #else /* !CONFIG_NETFILTER */
 #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
 static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
new file mode 100644 (file)
index 0000000..1d5b10a
--- /dev/null
@@ -0,0 +1,169 @@
+#ifndef _NFNETLINK_H
+#define _NFNETLINK_H
+#include <linux/types.h>
+
+#ifndef __KERNEL__
+/* nfnetlink groups: Up to 32 maximum - backwards compatibility for userspace */
+#define NF_NETLINK_CONNTRACK_NEW               0x00000001
+#define NF_NETLINK_CONNTRACK_UPDATE            0x00000002
+#define NF_NETLINK_CONNTRACK_DESTROY           0x00000004
+#define NF_NETLINK_CONNTRACK_EXP_NEW           0x00000008
+#define NF_NETLINK_CONNTRACK_EXP_UPDATE                0x00000010
+#define NF_NETLINK_CONNTRACK_EXP_DESTROY       0x00000020
+#endif
+
+enum nfnetlink_groups {
+       NFNLGRP_NONE,
+#define NFNLGRP_NONE                   NFNLGRP_NONE
+       NFNLGRP_CONNTRACK_NEW,
+#define NFNLGRP_CONNTRACK_NEW          NFNLGRP_CONNTRACK_NEW
+       NFNLGRP_CONNTRACK_UPDATE,
+#define NFNLGRP_CONNTRACK_UPDATE       NFNLGRP_CONNTRACK_UPDATE
+       NFNLGRP_CONNTRACK_DESTROY,
+#define NFNLGRP_CONNTRACK_DESTROY      NFNLGRP_CONNTRACK_DESTROY
+       NFNLGRP_CONNTRACK_EXP_NEW,
+#define        NFNLGRP_CONNTRACK_EXP_NEW       NFNLGRP_CONNTRACK_EXP_NEW
+       NFNLGRP_CONNTRACK_EXP_UPDATE,
+#define NFNLGRP_CONNTRACK_EXP_UPDATE   NFNLGRP_CONNTRACK_EXP_UPDATE
+       NFNLGRP_CONNTRACK_EXP_DESTROY,
+#define NFNLGRP_CONNTRACK_EXP_DESTROY  NFNLGRP_CONNTRACK_EXP_DESTROY
+       __NFNLGRP_MAX,
+};
+#define NFNLGRP_MAX    (__NFNLGRP_MAX - 1)
+
+/* Generic structure for encapsulation optional netfilter information.
+ * It is reminiscent of sockaddr, but with sa_family replaced
+ * with attribute type. 
+ * ! This should someday be put somewhere generic as now rtnetlink and
+ * ! nfnetlink use the same attributes methods. - J. Schulist.
+ */
+
+struct nfattr
+{
+       u_int16_t nfa_len;
+       u_int16_t nfa_type;
+} __attribute__ ((packed));
+
+/* FIXME: Shamelessly copy and pasted from rtnetlink.h, it's time
+ *       to put this in a generic file */
+
+#define NFA_ALIGNTO     4
+#define NFA_ALIGN(len) (((len) + NFA_ALIGNTO - 1) & ~(NFA_ALIGNTO - 1))
+#define NFA_OK(nfa,len)        ((len) > 0 && (nfa)->nfa_len >= sizeof(struct nfattr) \
+       && (nfa)->nfa_len <= (len))
+#define NFA_NEXT(nfa,attrlen)  ((attrlen) -= NFA_ALIGN((nfa)->nfa_len), \
+       (struct nfattr *)(((char *)(nfa)) + NFA_ALIGN((nfa)->nfa_len)))
+#define NFA_LENGTH(len)        (NFA_ALIGN(sizeof(struct nfattr)) + (len))
+#define NFA_SPACE(len) NFA_ALIGN(NFA_LENGTH(len))
+#define NFA_DATA(nfa)   ((void *)(((char *)(nfa)) + NFA_LENGTH(0)))
+#define NFA_PAYLOAD(nfa) ((int)((nfa)->nfa_len) - NFA_LENGTH(0))
+#define NFA_NEST(skb, type) \
+({     struct nfattr *__start = (struct nfattr *) (skb)->tail; \
+       NFA_PUT(skb, type, 0, NULL); \
+       __start;  })
+#define NFA_NEST_END(skb, start) \
+({      (start)->nfa_len = ((skb)->tail - (unsigned char *) (start)); \
+        (skb)->len; })
+#define NFA_NEST_CANCEL(skb, start) \
+({      if (start) \
+                skb_trim(skb, (unsigned char *) (start) - (skb)->data); \
+        -1; })
+
+/* General form of address family dependent message.
+ */
+struct nfgenmsg {
+       u_int8_t  nfgen_family;         /* AF_xxx */
+       u_int8_t  version;              /* nfnetlink version */
+       u_int16_t res_id;               /* resource id */
+} __attribute__ ((packed));
+
+#define NFNETLINK_V0   0
+
+#define NFM_NFA(n)      ((struct nfattr *)(((char *)(n)) \
+        + NLMSG_ALIGN(sizeof(struct nfgenmsg))))
+#define NFM_PAYLOAD(n)  NLMSG_PAYLOAD(n, sizeof(struct nfgenmsg))
+
+/* netfilter netlink message types are split in two pieces:
+ * 8 bit subsystem, 8bit operation.
+ */
+
+#define NFNL_SUBSYS_ID(x)      ((x & 0xff00) >> 8)
+#define NFNL_MSG_TYPE(x)       (x & 0x00ff)
+
+/* No enum here, otherwise __stringify() trick of MODULE_ALIAS_NFNL_SUBSYS()
+ * won't work anymore */
+#define NFNL_SUBSYS_NONE               0
+#define NFNL_SUBSYS_CTNETLINK          1
+#define NFNL_SUBSYS_CTNETLINK_EXP      2
+#define NFNL_SUBSYS_QUEUE              3
+#define NFNL_SUBSYS_ULOG               4
+#define NFNL_SUBSYS_COUNT              5
+
+#ifdef __KERNEL__
+
+#include <linux/netlink.h>
+#include <linux/capability.h>
+
+struct nfnl_callback
+{
+       int (*call)(struct sock *nl, struct sk_buff *skb, 
+               struct nlmsghdr *nlh, struct nfattr *cda[], int *errp);
+       kernel_cap_t cap_required; /* capabilities required for this msg */
+       u_int16_t attr_count;   /* number of nfattr's */
+};
+
+struct nfnetlink_subsystem
+{
+       const char *name;
+       __u8 subsys_id;         /* nfnetlink subsystem ID */
+       __u8 cb_count;          /* number of callbacks */
+       struct nfnl_callback *cb; /* callback for individual types */
+};
+
+extern void __nfa_fill(struct sk_buff *skb, int attrtype,
+        int attrlen, const void *data);
+#define NFA_PUT(skb, attrtype, attrlen, data) \
+({ if (skb_tailroom(skb) < (int)NFA_SPACE(attrlen)) goto nfattr_failure; \
+   __nfa_fill(skb, attrtype, attrlen, data); })
+
+extern struct semaphore nfnl_sem;
+
+#define nfnl_shlock()          down(&nfnl_sem)
+#define nfnl_shlock_nowait()   down_trylock(&nfnl_sem)
+
+#define nfnl_shunlock()                do { up(&nfnl_sem); \
+                                    if(nfnl && nfnl->sk_receive_queue.qlen) \
+                                           nfnl->sk_data_ready(nfnl, 0); \
+                               } while(0)
+
+extern void nfnl_lock(void);
+extern void nfnl_unlock(void);
+
+extern int nfnetlink_subsys_register(struct nfnetlink_subsystem *n);
+extern int nfnetlink_subsys_unregister(struct nfnetlink_subsystem *n);
+
+extern int nfattr_parse(struct nfattr *tb[], int maxattr, 
+                       struct nfattr *nfa, int len);
+
+#define nfattr_parse_nested(tb, max, nfa) \
+       nfattr_parse((tb), (max), NFA_DATA((nfa)), NFA_PAYLOAD((nfa)))
+
+#define nfattr_bad_size(tb, max, cta_min)                              \
+({     int __i, __res = 0;                                             \
+       for (__i=0; __i<max; __i++)                                     \
+               if (tb[__i] && NFA_PAYLOAD(tb[__i]) < cta_min[__i]){    \
+                       __res = 1;                                      \
+                       break;                                          \
+               }                                                       \
+       __res;                                                          \
+})
+
+extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, 
+                         int echo);
+extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags);
+
+#define MODULE_ALIAS_NFNL_SUBSYS(subsys) \
+       MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys))
+
+#endif /* __KERNEL__ */
+#endif /* _NFNETLINK_H */
diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h
new file mode 100644 (file)
index 0000000..5c55751
--- /dev/null
@@ -0,0 +1,124 @@
+#ifndef _IPCONNTRACK_NETLINK_H
+#define _IPCONNTRACK_NETLINK_H
+#include <linux/netfilter/nfnetlink.h>
+
+enum cntl_msg_types {
+       IPCTNL_MSG_CT_NEW,
+       IPCTNL_MSG_CT_GET,
+       IPCTNL_MSG_CT_DELETE,
+       IPCTNL_MSG_CT_GET_CTRZERO,
+
+       IPCTNL_MSG_MAX
+};
+
+enum ctnl_exp_msg_types {
+       IPCTNL_MSG_EXP_NEW,
+       IPCTNL_MSG_EXP_GET,
+       IPCTNL_MSG_EXP_DELETE,
+
+       IPCTNL_MSG_EXP_MAX
+};
+
+
+enum ctattr_type {
+       CTA_UNSPEC,
+       CTA_TUPLE_ORIG,
+       CTA_TUPLE_REPLY,
+       CTA_STATUS,
+       CTA_PROTOINFO,
+       CTA_HELP,
+       CTA_NAT,
+       CTA_TIMEOUT,
+       CTA_MARK,
+       CTA_COUNTERS_ORIG,
+       CTA_COUNTERS_REPLY,
+       CTA_USE,
+       CTA_ID,
+       __CTA_MAX
+};
+#define CTA_MAX (__CTA_MAX - 1)
+
+enum ctattr_tuple {
+       CTA_TUPLE_UNSPEC,
+       CTA_TUPLE_IP,
+       CTA_TUPLE_PROTO,
+       __CTA_TUPLE_MAX
+};
+#define CTA_TUPLE_MAX (__CTA_TUPLE_MAX - 1)
+
+enum ctattr_ip {
+       CTA_IP_UNSPEC,
+       CTA_IP_V4_SRC,
+       CTA_IP_V4_DST,
+       CTA_IP_V6_SRC,
+       CTA_IP_V6_DST,
+       __CTA_IP_MAX
+};
+#define CTA_IP_MAX (__CTA_IP_MAX - 1)
+
+enum ctattr_l4proto {
+       CTA_PROTO_UNSPEC,
+       CTA_PROTO_NUM,
+       CTA_PROTO_SRC_PORT,
+       CTA_PROTO_DST_PORT,
+       CTA_PROTO_ICMP_ID,
+       CTA_PROTO_ICMP_TYPE,
+       CTA_PROTO_ICMP_CODE,
+       __CTA_PROTO_MAX
+};
+#define CTA_PROTO_MAX (__CTA_PROTO_MAX - 1)
+
+enum ctattr_protoinfo {
+       CTA_PROTOINFO_UNSPEC,
+       CTA_PROTOINFO_TCP_STATE,
+       __CTA_PROTOINFO_MAX
+};
+#define CTA_PROTOINFO_MAX (__CTA_PROTOINFO_MAX - 1)
+
+enum ctattr_counters {
+       CTA_COUNTERS_UNSPEC,
+       CTA_COUNTERS_PACKETS,
+       CTA_COUNTERS_BYTES,
+       __CTA_COUNTERS_MAX
+};
+#define CTA_COUNTERS_MAX (__CTA_COUNTERS_MAX - 1)
+
+enum ctattr_nat {
+       CTA_NAT_UNSPEC,
+       CTA_NAT_MINIP,
+       CTA_NAT_MAXIP,
+       CTA_NAT_PROTO,
+       __CTA_NAT_MAX
+};
+#define CTA_NAT_MAX (__CTA_NAT_MAX - 1)
+
+enum ctattr_protonat {
+       CTA_PROTONAT_UNSPEC,
+       CTA_PROTONAT_PORT_MIN,
+       CTA_PROTONAT_PORT_MAX,
+       __CTA_PROTONAT_MAX
+};
+#define CTA_PROTONAT_MAX (__CTA_PROTONAT_MAX - 1)
+
+enum ctattr_expect {
+       CTA_EXPECT_UNSPEC,
+       CTA_EXPECT_MASTER,
+       CTA_EXPECT_TUPLE,
+       CTA_EXPECT_MASK,
+       CTA_EXPECT_TIMEOUT,
+       CTA_EXPECT_ID,
+       CTA_EXPECT_HELP_NAME,
+       __CTA_EXPECT_MAX
+};
+#define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1)
+
+enum ctattr_help {
+       CTA_HELP_UNSPEC,
+       CTA_HELP_NAME,
+       __CTA_HELP_MAX
+};
+#define CTA_HELP_MAX (__CTA_HELP_MAX - 1)
+
+#define CTA_HELP_MAXNAMESIZE   32
+
+#endif /* _IPCONNTRACK_NETLINK_H */
diff --git a/include/linux/netfilter/nfnetlink_log.h b/include/linux/netfilter/nfnetlink_log.h
new file mode 100644 (file)
index 0000000..b04b038
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef _NFNETLINK_LOG_H
+#define _NFNETLINK_LOG_H
+
+/* This file describes the netlink messages (i.e. 'protocol packets'),
+ * and not any kind of function definitions.  It is shared between kernel and
+ * userspace.  Don't put kernel specific stuff in here */
+
+#include <linux/types.h>
+#include <linux/netfilter/nfnetlink.h>
+
+enum nfulnl_msg_types {
+       NFULNL_MSG_PACKET,              /* packet from kernel to userspace */
+       NFULNL_MSG_CONFIG,              /* connect to a particular queue */
+
+       NFULNL_MSG_MAX
+};
+
+struct nfulnl_msg_packet_hdr {
+       u_int16_t       hw_protocol;    /* hw protocol (network order) */
+       u_int8_t        hook;           /* netfilter hook */
+       u_int8_t        _pad;
+} __attribute__ ((packed));
+
+struct nfulnl_msg_packet_hw {
+       u_int16_t       hw_addrlen;
+       u_int16_t       _pad;
+       u_int8_t        hw_addr[8];
+} __attribute__ ((packed));
+
+struct nfulnl_msg_packet_timestamp {
+       aligned_u64     sec;
+       aligned_u64     usec;
+} __attribute__ ((packed));
+
+#define NFULNL_PREFIXLEN       30      /* just like old log target */
+
+enum nfulnl_attr_type {
+       NFULA_UNSPEC,
+       NFULA_PACKET_HDR,
+       NFULA_MARK,                     /* u_int32_t nfmark */
+       NFULA_TIMESTAMP,                /* nfulnl_msg_packet_timestamp */
+       NFULA_IFINDEX_INDEV,            /* u_int32_t ifindex */
+       NFULA_IFINDEX_OUTDEV,           /* u_int32_t ifindex */
+       NFULA_IFINDEX_PHYSINDEV,        /* u_int32_t ifindex */
+       NFULA_IFINDEX_PHYSOUTDEV,       /* u_int32_t ifindex */
+       NFULA_HWADDR,                   /* nfulnl_msg_packet_hw */
+       NFULA_PAYLOAD,                  /* opaque data payload */
+       NFULA_PREFIX,                   /* string prefix */
+       NFULA_UID,                      /* user id of socket */
+
+       __NFULA_MAX
+};
+#define NFULA_MAX (__NFULA_MAX - 1)
+
+enum nfulnl_msg_config_cmds {
+       NFULNL_CFG_CMD_NONE,
+       NFULNL_CFG_CMD_BIND,
+       NFULNL_CFG_CMD_UNBIND,
+       NFULNL_CFG_CMD_PF_BIND,
+       NFULNL_CFG_CMD_PF_UNBIND,
+};
+
+struct nfulnl_msg_config_cmd {
+       u_int8_t        command;        /* nfulnl_msg_config_cmds */
+} __attribute__ ((packed));
+
+struct nfulnl_msg_config_mode {
+       u_int32_t       copy_range;
+       u_int8_t        copy_mode;
+       u_int8_t        _pad;
+} __attribute__ ((packed));
+
+enum nfulnl_attr_config {
+       NFULA_CFG_UNSPEC,
+       NFULA_CFG_CMD,                  /* nfulnl_msg_config_cmd */
+       NFULA_CFG_MODE,                 /* nfulnl_msg_config_mode */
+       NFULA_CFG_NLBUFSIZ,             /* u_int32_t buffer size */
+       NFULA_CFG_TIMEOUT,              /* u_int32_t in 1/100 s */
+       NFULA_CFG_QTHRESH,              /* u_int32_t */
+       __NFULA_CFG_MAX
+};
+#define NFULA_CFG_MAX (__NFULA_CFG_MAX -1)
+
+#define NFULNL_COPY_NONE       0x00
+#define NFULNL_COPY_META       0x01
+#define NFULNL_COPY_PACKET     0x02
+
+#endif /* _NFNETLINK_LOG_H */
diff --git a/include/linux/netfilter/nfnetlink_queue.h b/include/linux/netfilter/nfnetlink_queue.h
new file mode 100644 (file)
index 0000000..9e77437
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef _NFNETLINK_QUEUE_H
+#define _NFNETLINK_QUEUE_H
+
+#include <linux/types.h>
+#include <linux/netfilter/nfnetlink.h>
+
+enum nfqnl_msg_types {
+       NFQNL_MSG_PACKET,               /* packet from kernel to userspace */
+       NFQNL_MSG_VERDICT,              /* verdict from userspace to kernel */
+       NFQNL_MSG_CONFIG,               /* connect to a particular queue */
+
+       NFQNL_MSG_MAX
+};
+
+struct nfqnl_msg_packet_hdr {
+       u_int32_t       packet_id;      /* unique ID of packet in queue */
+       u_int16_t       hw_protocol;    /* hw protocol (network order) */
+       u_int8_t        hook;           /* netfilter hook */
+} __attribute__ ((packed));
+
+struct nfqnl_msg_packet_hw {
+       u_int16_t       hw_addrlen;
+       u_int16_t       _pad;
+       u_int8_t        hw_addr[8];
+} __attribute__ ((packed));
+
+struct nfqnl_msg_packet_timestamp {
+       aligned_u64     sec;
+       aligned_u64     usec;
+} __attribute__ ((packed));
+
+enum nfqnl_attr_type {
+       NFQA_UNSPEC,
+       NFQA_PACKET_HDR,
+       NFQA_VERDICT_HDR,               /* nfqnl_msg_verdict_hrd */
+       NFQA_MARK,                      /* u_int32_t nfmark */
+       NFQA_TIMESTAMP,                 /* nfqnl_msg_packet_timestamp */
+       NFQA_IFINDEX_INDEV,             /* u_int32_t ifindex */
+       NFQA_IFINDEX_OUTDEV,            /* u_int32_t ifindex */
+       NFQA_IFINDEX_PHYSINDEV,         /* u_int32_t ifindex */
+       NFQA_IFINDEX_PHYSOUTDEV,        /* u_int32_t ifindex */
+       NFQA_HWADDR,                    /* nfqnl_msg_packet_hw */
+       NFQA_PAYLOAD,                   /* opaque data payload */
+
+       __NFQA_MAX
+};
+#define NFQA_MAX (__NFQA_MAX - 1)
+
+struct nfqnl_msg_verdict_hdr {
+       u_int32_t verdict;
+       u_int32_t id;
+} __attribute__ ((packed));
+
+
+enum nfqnl_msg_config_cmds {
+       NFQNL_CFG_CMD_NONE,
+       NFQNL_CFG_CMD_BIND,
+       NFQNL_CFG_CMD_UNBIND,
+       NFQNL_CFG_CMD_PF_BIND,
+       NFQNL_CFG_CMD_PF_UNBIND,
+};
+
+struct nfqnl_msg_config_cmd {
+       u_int8_t        command;        /* nfqnl_msg_config_cmds */
+       u_int8_t        _pad;
+       u_int16_t       pf;             /* AF_xxx for PF_[UN]BIND */
+} __attribute__ ((packed));
+
+enum nfqnl_config_mode {
+       NFQNL_COPY_NONE,
+       NFQNL_COPY_META,
+       NFQNL_COPY_PACKET,
+};
+
+struct nfqnl_msg_config_params {
+       u_int32_t       copy_range;
+       u_int8_t        copy_mode;      /* enum nfqnl_config_mode */
+} __attribute__ ((packed));
+
+
+enum nfqnl_attr_config {
+       NFQA_CFG_UNSPEC,
+       NFQA_CFG_CMD,                   /* nfqnl_msg_config_cmd */
+       NFQA_CFG_PARAMS,                /* nfqnl_msg_config_params */
+       __NFQA_CFG_MAX
+};
+#define NFQA_CFG_MAX (__NFQA_CFG_MAX-1)
+
+#endif /* _NFNETLINK_QUEUE_H */
index 3064eec9cb8e2691d3849bd3592c87c452c3bf7d..6f425369ee29b09a395652f6557ddecfe3f7ee4e 100644 (file)
@@ -9,6 +9,8 @@
 
 #include <linux/netfilter.h>
 
+/* only for userspace compatibility */
+#ifndef __KERNEL__
 /* IP Cache bits. */
 /* Src IP address. */
 #define NFC_DN_SRC             0x0001
@@ -18,6 +20,7 @@
 #define NFC_DN_IF_IN           0x0004
 /* Output device. */
 #define NFC_DN_IF_OUT          0x0008
+#endif /* ! __KERNEL__ */
 
 /* DECnet Hooks */
 /* After promisc drops, checksum checks. */
@@ -53,7 +56,21 @@ struct nf_dn_rtmsg {
 
 #define NFDN_RTMSG(r) ((unsigned char *)(r) + NLMSG_ALIGN(sizeof(struct nf_dn_rtmsg)))
 
+#ifndef __KERNEL__
+/* backwards compatibility for userspace */
 #define DNRMG_L1_GROUP 0x01
 #define DNRMG_L2_GROUP 0x02
+#endif
+
+enum {
+       DNRNG_NLGRP_NONE,
+#define DNRNG_NLGRP_NONE       DNRNG_NLGRP_NONE
+       DNRNG_NLGRP_L1,
+#define DNRNG_NLGRP_L1         DNRNG_NLGRP_L1
+       DNRNG_NLGRP_L2,
+#define DNRNG_NLGRP_L2         DNRNG_NLGRP_L2
+       __DNRNG_NLGRP_MAX
+};
+#define DNRNG_NLGRP_MAX        (__DNRNG_NLGRP_MAX - 1)
 
 #endif /*__LINUX_DECNET_NETFILTER_H*/
index 3ebc36afae1a4746be0994d709b0f4e4f6f96ba7..fdc4a95273439edd826eb928e0207420db4ea373 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/config.h>
 #include <linux/netfilter.h>
 
+/* only for userspace compatibility */
+#ifndef __KERNEL__
 /* IP Cache bits. */
 /* Src IP address. */
 #define NFC_IP_SRC             0x0001
@@ -35,6 +37,7 @@
 #define NFC_IP_DST_PT          0x0400
 /* Something else about the proto */
 #define NFC_IP_PROTO_UNKNOWN   0x2000
+#endif /* ! __KERNEL__ */
 
 /* IP Hooks */
 /* After promisc drops, checksum checks. */
@@ -77,11 +80,6 @@ enum nf_ip_hook_priorities {
 #ifdef __KERNEL__
 extern int ip_route_me_harder(struct sk_buff **pskb);
 
-/* Call this before modifying an existing IP packet: ensures it is
-   modifiable and linear to the point you care about (writable_len).
-   Returns true or false. */
-extern int skb_ip_make_writable(struct sk_buff **pskb,
-                               unsigned int writable_len);
 #endif /*__KERNEL__*/
 
 #endif /*__LINUX_IP_NETFILTER_H*/
index 08fe5f7d14a0b2e7801cf10de6ba948c5520f25b..7e033e9271a88efbb2b214e4834176147d33d28f 100644 (file)
@@ -65,6 +65,63 @@ enum ip_conntrack_status {
 
        /* Both together */
        IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE),
+
+       /* Connection is dying (removed from lists), can not be unset. */
+       IPS_DYING_BIT = 9,
+       IPS_DYING = (1 << IPS_DYING_BIT),
+};
+
+/* Connection tracking event bits */
+enum ip_conntrack_events
+{
+       /* New conntrack */
+       IPCT_NEW_BIT = 0,
+       IPCT_NEW = (1 << IPCT_NEW_BIT),
+
+       /* Expected connection */
+       IPCT_RELATED_BIT = 1,
+       IPCT_RELATED = (1 << IPCT_RELATED_BIT),
+
+       /* Destroyed conntrack */
+       IPCT_DESTROY_BIT = 2,
+       IPCT_DESTROY = (1 << IPCT_DESTROY_BIT),
+
+       /* Timer has been refreshed */
+       IPCT_REFRESH_BIT = 3,
+       IPCT_REFRESH = (1 << IPCT_REFRESH_BIT),
+
+       /* Status has changed */
+       IPCT_STATUS_BIT = 4,
+       IPCT_STATUS = (1 << IPCT_STATUS_BIT),
+
+       /* Update of protocol info */
+       IPCT_PROTOINFO_BIT = 5,
+       IPCT_PROTOINFO = (1 << IPCT_PROTOINFO_BIT),
+
+       /* Volatile protocol info */
+       IPCT_PROTOINFO_VOLATILE_BIT = 6,
+       IPCT_PROTOINFO_VOLATILE = (1 << IPCT_PROTOINFO_VOLATILE_BIT),
+
+       /* New helper for conntrack */
+       IPCT_HELPER_BIT = 7,
+       IPCT_HELPER = (1 << IPCT_HELPER_BIT),
+
+       /* Update of helper info */
+       IPCT_HELPINFO_BIT = 8,
+       IPCT_HELPINFO = (1 << IPCT_HELPINFO_BIT),
+
+       /* Volatile helper info */
+       IPCT_HELPINFO_VOLATILE_BIT = 9,
+       IPCT_HELPINFO_VOLATILE = (1 << IPCT_HELPINFO_VOLATILE_BIT),
+
+       /* NAT info */
+       IPCT_NATINFO_BIT = 10,
+       IPCT_NATINFO = (1 << IPCT_NATINFO_BIT),
+};
+
+enum ip_conntrack_expect_events {
+       IPEXP_NEW_BIT = 0,
+       IPEXP_NEW = (1 << IPEXP_NEW_BIT),
 };
 
 #ifdef __KERNEL__
@@ -152,6 +209,9 @@ struct ip_conntrack
        /* Current number of expected connections */
        unsigned int expecting;
 
+       /* Unique ID that identifies this conntrack*/
+       unsigned int id;
+
        /* Helper, if any. */
        struct ip_conntrack_helper *helper;
 
@@ -171,7 +231,7 @@ struct ip_conntrack
 #endif /* CONFIG_IP_NF_NAT_NEEDED */
 
 #if defined(CONFIG_IP_NF_CONNTRACK_MARK)
-       unsigned long mark;
+       u_int32_t mark;
 #endif
 
        /* Traversed often, so hopefully in different cacheline to top */
@@ -200,6 +260,12 @@ struct ip_conntrack_expect
        /* Usage count. */
        atomic_t use;
 
+       /* Unique ID */
+       unsigned int id;
+
+       /* Flags */
+       unsigned int flags;
+
 #ifdef CONFIG_IP_NF_NAT_NEEDED
        /* This is the original per-proto part, used to map the
         * expected connection the way the recipient expects. */
@@ -209,6 +275,8 @@ struct ip_conntrack_expect
 #endif
 };
 
+#define IP_CT_EXPECT_PERMANENT 0x1
+
 static inline struct ip_conntrack *
 tuplehash_to_ctrack(const struct ip_conntrack_tuple_hash *hash)
 {
@@ -239,7 +307,12 @@ ip_conntrack_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
 }
 
 /* decrement reference count on a conntrack */
-extern void ip_conntrack_put(struct ip_conntrack *ct);
+static inline void
+ip_conntrack_put(struct ip_conntrack *ct)
+{
+       IP_NF_ASSERT(ct);
+       nf_conntrack_put(&ct->ct_general);
+}
 
 /* call to create an explicit dependency on ip_conntrack. */
 extern void need_ip_conntrack(void);
@@ -274,12 +347,50 @@ extern void
 ip_ct_iterate_cleanup(int (*iter)(struct ip_conntrack *i, void *data),
                      void *data);
 
+extern struct ip_conntrack_helper *
+__ip_conntrack_helper_find_byname(const char *);
+extern struct ip_conntrack_helper *
+ip_conntrack_helper_find_get(const struct ip_conntrack_tuple *tuple);
+extern void ip_conntrack_helper_put(struct ip_conntrack_helper *helper);
+
+extern struct ip_conntrack_protocol *
+__ip_conntrack_proto_find(u_int8_t protocol);
+extern struct ip_conntrack_protocol *
+ip_conntrack_proto_find_get(u_int8_t protocol);
+extern void ip_conntrack_proto_put(struct ip_conntrack_protocol *proto);
+
+extern void ip_ct_remove_expectations(struct ip_conntrack *ct);
+
+extern struct ip_conntrack *ip_conntrack_alloc(struct ip_conntrack_tuple *,
+                                              struct ip_conntrack_tuple *);
+
+extern void ip_conntrack_free(struct ip_conntrack *ct);
+
+extern void ip_conntrack_hash_insert(struct ip_conntrack *ct);
+
+extern struct ip_conntrack_expect *
+__ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple);
+
+extern struct ip_conntrack_expect *
+ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple);
+
+extern struct ip_conntrack_tuple_hash *
+__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
+                    const struct ip_conntrack *ignored_conntrack);
+
+extern void ip_conntrack_flush(void);
+
 /* It's confirmed if it is, or has been in the hash table. */
 static inline int is_confirmed(struct ip_conntrack *ct)
 {
        return test_bit(IPS_CONFIRMED_BIT, &ct->status);
 }
 
+static inline int is_dying(struct ip_conntrack *ct)
+{
+       return test_bit(IPS_DYING_BIT, &ct->status);
+}
+
 extern unsigned int ip_conntrack_htable_size;
  
 struct ip_conntrack_stat
@@ -303,6 +414,85 @@ struct ip_conntrack_stat
 
 #define CONNTRACK_STAT_INC(count) (__get_cpu_var(ip_conntrack_stat).count++)
 
+#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
+#include <linux/notifier.h>
+#include <linux/interrupt.h>
+
+struct ip_conntrack_ecache {
+       struct ip_conntrack *ct;
+       unsigned int events;
+};
+DECLARE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache);
+
+#define CONNTRACK_ECACHE(x)    (__get_cpu_var(ip_conntrack_ecache).x)
+extern struct notifier_block *ip_conntrack_chain;
+extern struct notifier_block *ip_conntrack_expect_chain;
+
+static inline int ip_conntrack_register_notifier(struct notifier_block *nb)
+{
+       return notifier_chain_register(&ip_conntrack_chain, nb);
+}
+
+static inline int ip_conntrack_unregister_notifier(struct notifier_block *nb)
+{
+       return notifier_chain_unregister(&ip_conntrack_chain, nb);
+}
+
+static inline int 
+ip_conntrack_expect_register_notifier(struct notifier_block *nb)
+{
+       return notifier_chain_register(&ip_conntrack_expect_chain, nb);
+}
+
+static inline int
+ip_conntrack_expect_unregister_notifier(struct notifier_block *nb)
+{
+       return notifier_chain_unregister(&ip_conntrack_expect_chain, nb);
+}
+
+extern void ip_ct_deliver_cached_events(const struct ip_conntrack *ct);
+extern void __ip_ct_event_cache_init(struct ip_conntrack *ct);
+
+static inline void 
+ip_conntrack_event_cache(enum ip_conntrack_events event,
+                        const struct sk_buff *skb)
+{
+       struct ip_conntrack *ct = (struct ip_conntrack *)skb->nfct;
+       struct ip_conntrack_ecache *ecache;
+       
+       local_bh_disable();
+       ecache = &__get_cpu_var(ip_conntrack_ecache);
+       if (ct != ecache->ct)
+               __ip_ct_event_cache_init(ct);
+       ecache->events |= event;
+       local_bh_enable();
+}
+
+static inline void ip_conntrack_event(enum ip_conntrack_events event,
+                                     struct ip_conntrack *ct)
+{
+       if (is_confirmed(ct) && !is_dying(ct))
+               notifier_call_chain(&ip_conntrack_chain, event, ct);
+}
+
+static inline void 
+ip_conntrack_expect_event(enum ip_conntrack_expect_events event,
+                         struct ip_conntrack_expect *exp)
+{
+       notifier_call_chain(&ip_conntrack_expect_chain, event, exp);
+}
+#else /* CONFIG_IP_NF_CONNTRACK_EVENTS */
+static inline void ip_conntrack_event_cache(enum ip_conntrack_events event, 
+                                           const struct sk_buff *skb) {}
+static inline void ip_conntrack_event(enum ip_conntrack_events event, 
+                                     struct ip_conntrack *ct) {}
+static inline void ip_ct_deliver_cached_events(const struct ip_conntrack *ct) {}
+static inline void 
+ip_conntrack_expect_event(enum ip_conntrack_expect_events event, 
+                         struct ip_conntrack_expect *exp) {}
+#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
+
 #ifdef CONFIG_IP_NF_NAT_NEEDED
 static inline int ip_nat_initialized(struct ip_conntrack *conntrack,
                                     enum ip_nat_manip_type manip)
index 694aec9b478469dafd09d061bd48d4280d0f9f75..907d4f5ca5dc50f2384ad69730f8c5686e085cf1 100644 (file)
@@ -2,6 +2,9 @@
 #define _IP_CONNTRACK_CORE_H
 #include <linux/netfilter.h>
 
+#define MAX_IP_CT_PROTO 256
+extern struct ip_conntrack_protocol *ip_ct_protos[MAX_IP_CT_PROTO];
+
 /* This header is used to share core functionality between the
    standalone connection tracking module, and the compatibility layer's use
    of connection tracking. */
@@ -38,12 +41,19 @@ extern int __ip_conntrack_confirm(struct sk_buff **pskb);
 /* Confirm a connection: returns NF_DROP if packet must be dropped. */
 static inline int ip_conntrack_confirm(struct sk_buff **pskb)
 {
-       if ((*pskb)->nfct
-           && !is_confirmed((struct ip_conntrack *)(*pskb)->nfct))
-               return __ip_conntrack_confirm(pskb);
-       return NF_ACCEPT;
+       struct ip_conntrack *ct = (struct ip_conntrack *)(*pskb)->nfct;
+       int ret = NF_ACCEPT;
+
+       if (ct) {
+               if (!is_confirmed(ct))
+                       ret = __ip_conntrack_confirm(pskb);
+               ip_ct_deliver_cached_events(ct);
+       }
+       return ret;
 }
 
+extern void ip_ct_unlink_expect(struct ip_conntrack_expect *exp);
+
 extern struct list_head *ip_conntrack_hash;
 extern struct list_head ip_conntrack_expect_list;
 extern rwlock_t ip_conntrack_lock;
index 3692daa93decf3455368fc3bec5dec91fa1c40f0..8d69279ccfe46961d1356b822ba53f326bcc2f1f 100644 (file)
@@ -24,6 +24,8 @@ struct ip_conntrack_helper
        int (*help)(struct sk_buff **pskb,
                    struct ip_conntrack *ct,
                    enum ip_conntrack_info conntrackinfo);
+
+       int (*to_nfattr)(struct sk_buff *skb, const struct ip_conntrack *ct);
 };
 
 extern int ip_conntrack_helper_register(struct ip_conntrack_helper *);
index e20b57c5e1b7685053be9a0ff5a814d65dab1580..b6b99be8632a8709687e7b003858e1ee2f2de586 100644 (file)
@@ -2,6 +2,7 @@
 #ifndef _IP_CONNTRACK_PROTOCOL_H
 #define _IP_CONNTRACK_PROTOCOL_H
 #include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter/nfnetlink_conntrack.h>
 
 struct seq_file;
 
@@ -47,22 +48,22 @@ struct ip_conntrack_protocol
        int (*error)(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
                     unsigned int hooknum);
 
+       /* convert protoinfo to nfnetink attributes */
+       int (*to_nfattr)(struct sk_buff *skb, struct nfattr *nfa,
+                        const struct ip_conntrack *ct);
+
+       int (*tuple_to_nfattr)(struct sk_buff *skb,
+                              const struct ip_conntrack_tuple *t);
+       int (*nfattr_to_tuple)(struct nfattr *tb[],
+                              struct ip_conntrack_tuple *t);
+
        /* Module (if any) which this is connected to. */
        struct module *me;
 };
 
-#define MAX_IP_CT_PROTO 256
-extern struct ip_conntrack_protocol *ip_ct_protos[MAX_IP_CT_PROTO];
-
 /* Protocol registration. */
 extern int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto);
 extern void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto);
-
-static inline struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
-{
-       return ip_ct_protos[protocol];
-}
-
 /* Existing built-in protocols */
 extern struct ip_conntrack_protocol ip_conntrack_protocol_tcp;
 extern struct ip_conntrack_protocol ip_conntrack_protocol_udp;
@@ -73,6 +74,11 @@ extern int ip_conntrack_protocol_tcp_init(void);
 /* Log invalid packets */
 extern unsigned int ip_ct_log_invalid;
 
+extern int ip_ct_port_tuple_to_nfattr(struct sk_buff *,
+                                     const struct ip_conntrack_tuple *);
+extern int ip_ct_port_nfattr_to_tuple(struct nfattr *tb[],
+                                     struct ip_conntrack_tuple *);
+
 #ifdef CONFIG_SYSCTL
 #ifdef DEBUG_INVALID_PACKETS
 #define LOG_INVALID(proto) \
diff --git a/include/linux/netfilter_ipv4/ip_logging.h b/include/linux/netfilter_ipv4/ip_logging.h
deleted file mode 100644 (file)
index 0c5c52c..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* IPv4 macros for the internal logging interface. */
-#ifndef __IP_LOGGING_H
-#define __IP_LOGGING_H
-
-#ifdef __KERNEL__
-#include <linux/socket.h>
-#include <linux/netfilter_logging.h>
-
-#define nf_log_ip_packet(pskb,hooknum,in,out,fmt,args...) \
-       nf_log_packet(AF_INET,pskb,hooknum,in,out,fmt,##args)
-
-#define nf_log_ip(pfh,len,fmt,args...) \
-       nf_log(AF_INET,pfh,len,fmt,##args)
-
-#define nf_ip_log_register(logging) nf_log_register(AF_INET,logging)
-#define nf_ip_log_unregister(logging) nf_log_unregister(AF_INET,logging)
-       
-#endif /*__KERNEL__*/
-
-#endif /*__IP_LOGGING_H*/
index 129708c22386f5beb2d1276e818186dbb100b68f..ef63aa991a0669ffd02843ca332dc267b81c427c 100644 (file)
@@ -4,6 +4,9 @@
 #include <linux/init.h>
 #include <linux/list.h>
 
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter/nfnetlink_conntrack.h>
+
 struct iphdr;
 struct ip_nat_range;
 
@@ -15,6 +18,8 @@ struct ip_nat_protocol
        /* Protocol number. */
        unsigned int protonum;
 
+       struct module *me;
+
        /* Translate a packet to the target according to manip type.
           Return true if succeeded. */
        int (*manip_pkt)(struct sk_buff **pskb,
@@ -43,19 +48,20 @@ struct ip_nat_protocol
 
        unsigned int (*print_range)(char *buffer,
                                    const struct ip_nat_range *range);
-};
 
-#define MAX_IP_NAT_PROTO 256
-extern struct ip_nat_protocol *ip_nat_protos[MAX_IP_NAT_PROTO];
+       int (*range_to_nfattr)(struct sk_buff *skb,
+                              const struct ip_nat_range *range);
+
+       int (*nfattr_to_range)(struct nfattr *tb[],
+                              struct ip_nat_range *range);
+};
 
 /* Protocol registration. */
 extern int ip_nat_protocol_register(struct ip_nat_protocol *proto);
 extern void ip_nat_protocol_unregister(struct ip_nat_protocol *proto);
 
-static inline struct ip_nat_protocol *ip_nat_find_proto(u_int8_t protocol)
-{
-       return ip_nat_protos[protocol];
-}
+extern struct ip_nat_protocol *ip_nat_proto_find_get(u_int8_t protocol);
+extern void ip_nat_proto_put(struct ip_nat_protocol *proto);
 
 /* Built-in protocols. */
 extern struct ip_nat_protocol ip_nat_protocol_tcp;
@@ -67,4 +73,9 @@ extern int init_protocols(void) __init;
 extern void cleanup_protocols(void);
 extern struct ip_nat_protocol *find_nat_proto(u_int16_t protonum);
 
+extern int ip_nat_port_range_to_nfattr(struct sk_buff *skb,
+                                      const struct ip_nat_range *range);
+extern int ip_nat_port_nfattr_to_range(struct nfattr *tb[],
+                                      struct ip_nat_range *range);
+
 #endif /*_IP_NAT_PROTO_H*/
index fecd2a06dcd81166c8fd2037e57bd4d5c3d22ccd..73b9552e6a8941eea8c3c30ba74c9bb96ad69c2e 100644 (file)
@@ -19,5 +19,10 @@ extern unsigned int
 alloc_null_binding(struct ip_conntrack *conntrack,
                   struct ip_nat_info *info,
                   unsigned int hooknum);
+
+extern unsigned int
+alloc_null_binding_confirmed(struct ip_conntrack *conntrack,
+                            struct ip_nat_info *info,
+                            unsigned int hooknum);
 #endif
 #endif /* _IP_NAT_RULE_H */
index 12ce47808e7d24c3d734e3619d40d9994ee38c71..d19d65cf453046ba28724c80f7cea09d2fda4dc0 100644 (file)
@@ -109,7 +109,8 @@ struct ipt_counters
 
 /* Values for "flag" field in struct ipt_ip (general ip structure). */
 #define IPT_F_FRAG             0x01    /* Set if rule is a fragment rule */
-#define IPT_F_MASK             0x01    /* All possible flag bits mask. */
+#define IPT_F_GOTO             0x02    /* Set if jump is a goto */
+#define IPT_F_MASK             0x03    /* All possible flag bits mask. */
 
 /* Values for "inv" field in struct ipt_ip. */
 #define IPT_INV_VIA_IN         0x01    /* Invert the sense of IN IFACE. */
index d25f782e57d17acff2a6912777264236dd72b3be..22d16177319b9d46a335d11ede61f86c9fb28b8d 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _IPT_LOG_H
 #define _IPT_LOG_H
 
+/* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */
 #define IPT_LOG_TCPSEQ         0x01    /* Log TCP sequence numbers */
 #define IPT_LOG_TCPOPT         0x02    /* Log TCP options */
 #define IPT_LOG_IPOPT          0x04    /* Log IP options */
diff --git a/include/linux/netfilter_ipv4/ipt_NFQUEUE.h b/include/linux/netfilter_ipv4/ipt_NFQUEUE.h
new file mode 100644 (file)
index 0000000..b5b2943
--- /dev/null
@@ -0,0 +1,16 @@
+/* iptables module for using NFQUEUE mechanism
+ *
+ * (C) 2005 Harald Welte <laforge@netfilter.org>
+ *
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+*/
+#ifndef _IPT_NFQ_TARGET_H
+#define _IPT_NFQ_TARGET_H
+
+/* target info */
+struct ipt_NFQ_info {
+       u_int16_t queuenum;
+};
+
+#endif /* _IPT_DSCP_TARGET_H */
diff --git a/include/linux/netfilter_ipv4/ipt_TTL.h b/include/linux/netfilter_ipv4/ipt_TTL.h
new file mode 100644 (file)
index 0000000..ee6611e
--- /dev/null
@@ -0,0 +1,21 @@
+/* TTL modification module for IP tables
+ * (C) 2000 by Harald Welte <laforge@netfilter.org> */
+
+#ifndef _IPT_TTL_H
+#define _IPT_TTL_H
+
+enum {
+       IPT_TTL_SET = 0,
+       IPT_TTL_INC,
+       IPT_TTL_DEC
+};
+
+#define IPT_TTL_MAXMODE        IPT_TTL_DEC
+
+struct ipt_TTL_info {
+       u_int8_t        mode;
+       u_int8_t        ttl;
+};
+
+
+#endif
diff --git a/include/linux/netfilter_ipv4/ipt_connbytes.h b/include/linux/netfilter_ipv4/ipt_connbytes.h
new file mode 100644 (file)
index 0000000..9e5532f
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _IPT_CONNBYTES_H
+#define _IPT_CONNBYTES_H
+
+enum ipt_connbytes_what {
+       IPT_CONNBYTES_PKTS,
+       IPT_CONNBYTES_BYTES,
+       IPT_CONNBYTES_AVGPKT,
+};
+
+enum ipt_connbytes_direction {
+       IPT_CONNBYTES_DIR_ORIGINAL,
+       IPT_CONNBYTES_DIR_REPLY,
+       IPT_CONNBYTES_DIR_BOTH,
+};
+
+struct ipt_connbytes_info
+{
+       struct {
+               aligned_u64 from;       /* count to be matched */
+               aligned_u64 to;         /* count to be matched */
+       } count;
+       u_int8_t what;          /* ipt_connbytes_what */
+       u_int8_t direction;     /* ipt_connbytes_direction */
+};
+#endif
diff --git a/include/linux/netfilter_ipv4/ipt_dccp.h b/include/linux/netfilter_ipv4/ipt_dccp.h
new file mode 100644 (file)
index 0000000..3cb3a52
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _IPT_DCCP_H_
+#define _IPT_DCCP_H_
+
+#define IPT_DCCP_SRC_PORTS             0x01
+#define IPT_DCCP_DEST_PORTS            0x02
+#define IPT_DCCP_TYPE                  0x04
+#define IPT_DCCP_OPTION                        0x08
+
+#define IPT_DCCP_VALID_FLAGS           0x0f
+
+struct ipt_dccp_info {
+       u_int16_t dpts[2];  /* Min, Max */
+       u_int16_t spts[2];  /* Min, Max */
+
+       u_int16_t flags;
+       u_int16_t invflags;
+
+       u_int16_t typemask;
+       u_int8_t option;
+};
+
+#endif /* _IPT_DCCP_H_ */
+
diff --git a/include/linux/netfilter_ipv4/ipt_string.h b/include/linux/netfilter_ipv4/ipt_string.h
new file mode 100644 (file)
index 0000000..a265f6e
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _IPT_STRING_H
+#define _IPT_STRING_H
+
+#define IPT_STRING_MAX_PATTERN_SIZE 128
+#define IPT_STRING_MAX_ALGO_NAME_SIZE 16
+
+struct ipt_string_info
+{
+       u_int16_t from_offset;
+       u_int16_t to_offset;
+       char      algo[IPT_STRING_MAX_ALGO_NAME_SIZE];
+       char      pattern[IPT_STRING_MAX_PATTERN_SIZE];
+       u_int8_t  patlen;
+       u_int8_t  invert;
+       struct ts_config __attribute__((aligned(8))) *config;
+};
+
+#endif /*_IPT_STRING_H*/
index bee7a5ec7c663414579e9e4e522c8bbbdbdfaee0..edcc2c6eb5c702ce8f39c156b685023fbbe34025 100644 (file)
@@ -10,6 +10,8 @@
 
 #include <linux/netfilter.h>
 
+/* only for userspace compatibility */
+#ifndef __KERNEL__
 /* IP Cache bits. */
 /* Src IP address. */
 #define NFC_IP6_SRC              0x0001
@@ -38,6 +40,7 @@
 #define NFC_IP6_DST_PT           0x0400
 /* Something else about the proto */
 #define NFC_IP6_PROTO_UNKNOWN    0x2000
+#endif /* ! __KERNEL__ */
 
 
 /* IP6 Hooks */
@@ -68,4 +71,7 @@ enum nf_ip6_hook_priorities {
        NF_IP6_PRI_LAST = INT_MAX,
 };
 
+extern int ipv6_netfilter_init(void);
+extern void ipv6_netfilter_fini(void);
+
 #endif /*__LINUX_IP6_NETFILTER_H*/
diff --git a/include/linux/netfilter_ipv6/ip6_logging.h b/include/linux/netfilter_ipv6/ip6_logging.h
deleted file mode 100644 (file)
index a0b2ee3..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* IPv6 macros for the nternal logging interface. */
-#ifndef __IP6_LOGGING_H
-#define __IP6_LOGGING_H
-
-#ifdef __KERNEL__
-#include <linux/socket.h>
-#include <linux/netfilter_logging.h>
-
-#define nf_log_ip6_packet(pskb,hooknum,in,out,fmt,args...) \
-       nf_log_packet(AF_INET6,pskb,hooknum,in,out,fmt,##args)
-
-#define nf_log_ip6(pfh,len,fmt,args...) \
-       nf_log(AF_INET6,pfh,len,fmt,##args)
-
-#define nf_ip6_log_register(logging) nf_log_register(AF_INET6,logging)
-#define nf_ip6_log_unregister(logging) nf_log_unregister(AF_INET6,logging)
-       
-#endif /*__KERNEL__*/
-
-#endif /*__IP6_LOGGING_H*/
index f1ce3b009853b0fe8d87b2c2a563d31d9d3e6e15..58c72a52dc657ea3028f6abded8b2acdbbff924d 100644 (file)
@@ -111,7 +111,8 @@ struct ip6t_counters
 #define IP6T_F_PROTO           0x01    /* Set if rule cares about upper 
                                           protocols */
 #define IP6T_F_TOS             0x02    /* Match the TOS. */
-#define IP6T_F_MASK            0x03    /* All possible flag bits mask. */
+#define IP6T_F_GOTO            0x04    /* Set if jump is a goto */
+#define IP6T_F_MASK            0x07    /* All possible flag bits mask. */
 
 /* Values for "inv" field in struct ip6t_ip6. */
 #define IP6T_INV_VIA_IN                0x01    /* Invert the sense of IN IFACE. */
diff --git a/include/linux/netfilter_ipv6/ip6t_HL.h b/include/linux/netfilter_ipv6/ip6t_HL.h
new file mode 100644 (file)
index 0000000..afb7813
--- /dev/null
@@ -0,0 +1,22 @@
+/* Hop Limit modification module for ip6tables
+ * Maciej Soltysiak <solt@dns.toxicfilms.tv>
+ * Based on HW's TTL module */
+
+#ifndef _IP6T_HL_H
+#define _IP6T_HL_H
+
+enum {
+       IP6T_HL_SET = 0,
+       IP6T_HL_INC,
+       IP6T_HL_DEC
+};
+
+#define IP6T_HL_MAXMODE        IP6T_HL_DEC
+
+struct ip6t_HL_info {
+       u_int8_t        mode;
+       u_int8_t        hop_limit;
+};
+
+
+#endif
index 42996a43bb39c43ce8b33f7d910492a043f066ac..9008ff5c40aec70e209f8f9efd036e34db1621ab 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _IP6T_LOG_H
 #define _IP6T_LOG_H
 
+/* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */
 #define IP6T_LOG_TCPSEQ                0x01    /* Log TCP sequence numbers */
 #define IP6T_LOG_TCPOPT                0x02    /* Log TCP options */
 #define IP6T_LOG_IPOPT         0x04    /* Log IP options */
diff --git a/include/linux/netfilter_ipv6/ip6t_REJECT.h b/include/linux/netfilter_ipv6/ip6t_REJECT.h
new file mode 100644 (file)
index 0000000..6be6504
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _IP6T_REJECT_H
+#define _IP6T_REJECT_H
+
+enum ip6t_reject_with {
+       IP6T_ICMP6_NO_ROUTE,
+       IP6T_ICMP6_ADM_PROHIBITED,
+       IP6T_ICMP6_NOT_NEIGHBOUR,
+       IP6T_ICMP6_ADDR_UNREACH,
+       IP6T_ICMP6_PORT_UNREACH,
+       IP6T_ICMP6_ECHOREPLY,
+       IP6T_TCP_RESET
+};
+
+struct ip6t_reject_info {
+       u_int32_t       with;   /* reject type */
+};
+
+#endif /*_IP6T_REJECT_H*/
index 6552b71bfa73cdc69ade8d12b8cb2fbb1f1f0955..1675186689361370861897bd7b12a1003c9e5af3 100644 (file)
@@ -8,7 +8,7 @@
 #define NETLINK_W1             1       /* 1-wire subsystem                             */
 #define NETLINK_USERSOCK       2       /* Reserved for user mode socket protocols      */
 #define NETLINK_FIREWALL       3       /* Firewalling hook                             */
-#define NETLINK_TCPDIAG                4       /* TCP socket monitoring                        */
+#define NETLINK_INET_DIAG      4       /* INET socket monitoring                       */
 #define NETLINK_NFLOG          5       /* netfilter/iptables ULOG */
 #define NETLINK_XFRM           6       /* ipsec */
 #define NETLINK_SELINUX                7       /* SELinux event notifications */
@@ -90,6 +90,15 @@ struct nlmsgerr
        struct nlmsghdr msg;
 };
 
+#define NETLINK_ADD_MEMBERSHIP 1
+#define NETLINK_DROP_MEMBERSHIP        2
+#define NETLINK_PKTINFO                3
+
+struct nl_pktinfo
+{
+       __u32   group;
+};
+
 #define NET_MAJOR 36           /* Major 36 is reserved for networking                                          */
 
 enum {
@@ -106,9 +115,8 @@ struct netlink_skb_parms
 {
        struct ucred            creds;          /* Skb credentials      */
        __u32                   pid;
-       __u32                   groups;
        __u32                   dst_pid;
-       __u32                   dst_groups;
+       __u32                   dst_group;
        kernel_cap_t            eff_cap;
        __u32                   loginuid;       /* Login (audit) uid */
 };
@@ -117,11 +125,11 @@ struct netlink_skb_parms
 #define NETLINK_CREDS(skb)     (&NETLINK_CB((skb)).creds)
 
 
-extern struct sock *netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len));
+extern struct sock *netlink_kernel_create(int unit, unsigned int groups, void (*input)(struct sock *sk, int len), struct module *module);
 extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
 extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);
 extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
-                            __u32 group, int allocation);
+                            __u32 group, unsigned int __nocast allocation);
 extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code);
 extern int netlink_register_notifier(struct notifier_block *nb);
 extern int netlink_unregister_notifier(struct notifier_block *nb);
index f5a6695d4d21335dddf2aa0da868c31fad454270..f34767c5fc79e7a5ecee1676e72b4ebf84296aa2 100644 (file)
@@ -134,6 +134,7 @@ struct page_state {
 };
 
 extern void get_page_state(struct page_state *ret);
+extern void get_page_state_node(struct page_state *ret, int node);
 extern void get_full_page_state(struct page_state *ret);
 extern unsigned long __read_page_state(unsigned long offset);
 extern void __mod_page_state(unsigned long offset, unsigned long delta);
@@ -194,6 +195,7 @@ extern void __mod_page_state(unsigned long offset, unsigned long delta);
 #define SetPageDirty(page)     set_bit(PG_dirty, &(page)->flags)
 #define TestSetPageDirty(page) test_and_set_bit(PG_dirty, &(page)->flags)
 #define ClearPageDirty(page)   clear_bit(PG_dirty, &(page)->flags)
+#define __ClearPageDirty(page) __clear_bit(PG_dirty, &(page)->flags)
 #define TestClearPageDirty(page) test_and_clear_bit(PG_dirty, &(page)->flags)
 
 #define SetPageLRU(page)       set_bit(PG_lru, &(page)->flags)
index 927ed487630de4cf06ee698a63b7d88742942790..ee0ab7a5f91bbca1389cc46f1b678f4717373ece 100644 (file)
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA 0x0266
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2        0x0267
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE  0x036E
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA 0x036F
 #define PCI_DEVICE_ID_NVIDIA_NVENET_12         0x0268
 #define PCI_DEVICE_ID_NVIDIA_NVENET_13         0x0269
 #define PCI_DEVICE_ID_NVIDIA_MCP51_AUDIO       0x026B
 #define PCI_DEVICE_ID_TOSHIBA_TC35815CF        0x0030
 #define PCI_DEVICE_ID_TOSHIBA_TX4927   0x0180
 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC    0x0108
+#define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3
 
 #define PCI_VENDOR_ID_RICOH            0x1180
 #define PCI_DEVICE_ID_RICOH_RL5C465    0x0465
 #define PCI_DEVICE_ID_ENE_1225         0x1225
 #define PCI_DEVICE_ID_ENE_1410         0x1410
 #define PCI_DEVICE_ID_ENE_1420         0x1420
+#define PCI_VENDOR_ID_CHELSIO          0x1425
+
+#define PCI_VENDOR_ID_MIPS             0x153f
+#define PCI_DEVICE_ID_SOC_IT           0x0001
 
 #define PCI_VENDOR_ID_SYBA             0x1592
 #define PCI_DEVICE_ID_SYBA_2P_EPP      0x0782
diff --git a/include/linux/phy.h b/include/linux/phy.h
new file mode 100644 (file)
index 0000000..72cb67b
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * include/linux/phy.h
+ *
+ * Framework and drivers for configuring and reading different PHYs
+ * Based on code in sungem_phy.c and gianfar_phy.c
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef __PHY_H
+#define __PHY_H
+
+#include <linux/spinlock.h>
+#include <linux/device.h>
+
+#define PHY_BASIC_FEATURES     (SUPPORTED_10baseT_Half | \
+                                SUPPORTED_10baseT_Full | \
+                                SUPPORTED_100baseT_Half | \
+                                SUPPORTED_100baseT_Full | \
+                                SUPPORTED_Autoneg | \
+                                SUPPORTED_TP | \
+                                SUPPORTED_MII)
+
+#define PHY_GBIT_FEATURES      (PHY_BASIC_FEATURES | \
+                                SUPPORTED_1000baseT_Half | \
+                                SUPPORTED_1000baseT_Full)
+
+/* Set phydev->irq to PHY_POLL if interrupts are not supported,
+ * or not desired for this PHY.  Set to PHY_IGNORE_INTERRUPT if
+ * the attached driver handles the interrupt
+ */
+#define PHY_POLL               -1
+#define PHY_IGNORE_INTERRUPT   -2
+
+#define PHY_HAS_INTERRUPT      0x00000001
+#define PHY_HAS_MAGICANEG      0x00000002
+
+#define MII_BUS_MAX 4
+
+
+#define PHY_INIT_TIMEOUT 100000
+#define PHY_STATE_TIME         1
+#define PHY_FORCE_TIMEOUT      10
+#define PHY_AN_TIMEOUT         10
+
+#define PHY_MAX_ADDR 32
+
+/* The Bus class for PHYs.  Devices which provide access to
+ * PHYs should register using this structure */
+struct mii_bus {
+       const char *name;
+       int id;
+       void *priv;
+       int (*read)(struct mii_bus *bus, int phy_id, int regnum);
+       int (*write)(struct mii_bus *bus, int phy_id, int regnum, u16 val);
+       int (*reset)(struct mii_bus *bus);
+
+       /* A lock to ensure that only one thing can read/write
+        * the MDIO bus at a time */
+       spinlock_t mdio_lock;
+
+       struct device *dev;
+
+       /* list of all PHYs on bus */
+       struct phy_device *phy_map[PHY_MAX_ADDR];
+
+       /* Pointer to an array of interrupts, each PHY's
+        * interrupt at the index matching its address */
+       int *irq;
+};
+
+#define PHY_INTERRUPT_DISABLED 0x0
+#define PHY_INTERRUPT_ENABLED 0x80000000
+
+/* PHY state machine states:
+ *
+ * DOWN: PHY device and driver are not ready for anything.  probe
+ * should be called if and only if the PHY is in this state,
+ * given that the PHY device exists.
+ * - PHY driver probe function will, depending on the PHY, set
+ * the state to STARTING or READY
+ *
+ * STARTING:  PHY device is coming up, and the ethernet driver is
+ * not ready.  PHY drivers may set this in the probe function.
+ * If they do, they are responsible for making sure the state is
+ * eventually set to indicate whether the PHY is UP or READY,
+ * depending on the state when the PHY is done starting up.
+ * - PHY driver will set the state to READY
+ * - start will set the state to PENDING
+ *
+ * READY: PHY is ready to send and receive packets, but the
+ * controller is not.  By default, PHYs which do not implement
+ * probe will be set to this state by phy_probe().  If the PHY
+ * driver knows the PHY is ready, and the PHY state is STARTING,
+ * then it sets this STATE.
+ * - start will set the state to UP
+ *
+ * PENDING: PHY device is coming up, but the ethernet driver is
+ * ready.  phy_start will set this state if the PHY state is
+ * STARTING.
+ * - PHY driver will set the state to UP when the PHY is ready
+ *
+ * UP: The PHY and attached device are ready to do work.
+ * Interrupts should be started here.
+ * - timer moves to AN
+ *
+ * AN: The PHY is currently negotiating the link state.  Link is
+ * therefore down for now.  phy_timer will set this state when it
+ * detects the state is UP.  config_aneg will set this state
+ * whenever called with phydev->autoneg set to AUTONEG_ENABLE.
+ * - If autonegotiation finishes, but there's no link, it sets
+ *   the state to NOLINK.
+ * - If aneg finishes with link, it sets the state to RUNNING,
+ *   and calls adjust_link
+ * - If autonegotiation did not finish after an arbitrary amount
+ *   of time, autonegotiation should be tried again if the PHY
+ *   supports "magic" autonegotiation (back to AN)
+ * - If it didn't finish, and no magic_aneg, move to FORCING.
+ *
+ * NOLINK: PHY is up, but not currently plugged in.
+ * - If the timer notes that the link comes back, we move to RUNNING
+ * - config_aneg moves to AN
+ * - phy_stop moves to HALTED
+ *
+ * FORCING: PHY is being configured with forced settings
+ * - if link is up, move to RUNNING
+ * - If link is down, we drop to the next highest setting, and
+ *   retry (FORCING) after a timeout
+ * - phy_stop moves to HALTED
+ *
+ * RUNNING: PHY is currently up, running, and possibly sending
+ * and/or receiving packets
+ * - timer will set CHANGELINK if we're polling (this ensures the
+ *   link state is polled every other cycle of this state machine,
+ *   which makes it every other second)
+ * - irq will set CHANGELINK
+ * - config_aneg will set AN
+ * - phy_stop moves to HALTED
+ *
+ * CHANGELINK: PHY experienced a change in link state
+ * - timer moves to RUNNING if link
+ * - timer moves to NOLINK if the link is down
+ * - phy_stop moves to HALTED
+ *
+ * HALTED: PHY is up, but no polling or interrupts are done. Or
+ * PHY is in an error state.
+ *
+ * - phy_start moves to RESUMING
+ *
+ * RESUMING: PHY was halted, but now wants to run again.
+ * - If we are forcing, or aneg is done, timer moves to RUNNING
+ * - If aneg is not done, timer moves to AN
+ * - phy_stop moves to HALTED
+ */
+enum phy_state {
+       PHY_DOWN=0,
+       PHY_STARTING,
+       PHY_READY,
+       PHY_PENDING,
+       PHY_UP,
+       PHY_AN,
+       PHY_RUNNING,
+       PHY_NOLINK,
+       PHY_FORCING,
+       PHY_CHANGELINK,
+       PHY_HALTED,
+       PHY_RESUMING
+};
+
+/* phy_device: An instance of a PHY
+ *
+ * drv: Pointer to the driver for this PHY instance
+ * bus: Pointer to the bus this PHY is on
+ * dev: driver model device structure for this PHY
+ * phy_id: UID for this device found during discovery
+ * state: state of the PHY for management purposes
+ * dev_flags: Device-specific flags used by the PHY driver.
+ * addr: Bus address of PHY
+ * link_timeout: The number of timer firings to wait before the
+ * giving up on the current attempt at acquiring a link
+ * irq: IRQ number of the PHY's interrupt (-1 if none)
+ * phy_timer: The timer for handling the state machine
+ * phy_queue: A work_queue for the interrupt
+ * attached_dev: The attached enet driver's device instance ptr
+ * adjust_link: Callback for the enet controller to respond to
+ * changes in the link state.
+ * adjust_state: Callback for the enet driver to respond to
+ * changes in the state machine.
+ *
+ * speed, duplex, pause, supported, advertising, and
+ * autoneg are used like in mii_if_info
+ *
+ * interrupts currently only supports enabled or disabled,
+ * but could be changed in the future to support enabling
+ * and disabling specific interrupts
+ *
+ * Contains some infrastructure for polling and interrupt
+ * handling, as well as handling shifts in PHY hardware state
+ */
+struct phy_device {
+       /* Information about the PHY type */
+       /* And management functions */
+       struct phy_driver *drv;
+
+       struct mii_bus *bus;
+
+       struct device dev;
+
+       u32 phy_id;
+
+       enum phy_state state;
+
+       u32 dev_flags;
+
+       /* Bus address of the PHY (0-32) */
+       int addr;
+
+       /* forced speed & duplex (no autoneg)
+        * partner speed & duplex & pause (autoneg)
+        */
+       int speed;
+       int duplex;
+       int pause;
+       int asym_pause;
+
+       /* The most recently read link state */
+       int link;
+
+       /* Enabled Interrupts */
+       u32 interrupts;
+
+       /* Union of PHY and Attached devices' supported modes */
+       /* See mii.h for more info */
+       u32 supported;
+       u32 advertising;
+
+       int autoneg;
+
+       int link_timeout;
+
+       /* Interrupt number for this PHY
+        * -1 means no interrupt */
+       int irq;
+
+       /* private data pointer */
+       /* For use by PHYs to maintain extra state */
+       void *priv;
+
+       /* Interrupt and Polling infrastructure */
+       struct work_struct phy_queue;
+       struct timer_list phy_timer;
+
+       spinlock_t lock;
+
+       struct net_device *attached_dev;
+
+       void (*adjust_link)(struct net_device *dev);
+
+       void (*adjust_state)(struct net_device *dev);
+};
+#define to_phy_device(d) container_of(d, struct phy_device, dev)
+
+/* struct phy_driver: Driver structure for a particular PHY type
+ *
+ * phy_id: The result of reading the UID registers of this PHY
+ *   type, and ANDing them with the phy_id_mask.  This driver
+ *   only works for PHYs with IDs which match this field
+ * name: The friendly name of this PHY type
+ * phy_id_mask: Defines the important bits of the phy_id
+ * features: A list of features (speed, duplex, etc) supported
+ *   by this PHY
+ * flags: A bitfield defining certain other features this PHY
+ *   supports (like interrupts)
+ *
+ * The drivers must implement config_aneg and read_status.  All
+ * other functions are optional. Note that none of these
+ * functions should be called from interrupt time.  The goal is
+ * for the bus read/write functions to be able to block when the
+ * bus transaction is happening, and be freed up by an interrupt
+ * (The MPC85xx has this ability, though it is not currently
+ * supported in the driver).
+ */
+struct phy_driver {
+       u32 phy_id;
+       char *name;
+       unsigned int phy_id_mask;
+       u32 features;
+       u32 flags;
+
+       /* Called to initialize the PHY,
+        * including after a reset */
+       int (*config_init)(struct phy_device *phydev);
+
+       /* Called during discovery.  Used to set
+        * up device-specific structures, if any */
+       int (*probe)(struct phy_device *phydev);
+
+       /* PHY Power Management */
+       int (*suspend)(struct phy_device *phydev);
+       int (*resume)(struct phy_device *phydev);
+
+       /* Configures the advertisement and resets
+        * autonegotiation if phydev->autoneg is on,
+        * forces the speed to the current settings in phydev
+        * if phydev->autoneg is off */
+       int (*config_aneg)(struct phy_device *phydev);
+
+       /* Determines the negotiated speed and duplex */
+       int (*read_status)(struct phy_device *phydev);
+
+       /* Clears any pending interrupts */
+       int (*ack_interrupt)(struct phy_device *phydev);
+
+       /* Enables or disables interrupts */
+       int (*config_intr)(struct phy_device *phydev);
+
+       /* Clears up any memory if needed */
+       void (*remove)(struct phy_device *phydev);
+
+       struct device_driver driver;
+};
+#define to_phy_driver(d) container_of(d, struct phy_driver, driver)
+
+int phy_read(struct phy_device *phydev, u16 regnum);
+int phy_write(struct phy_device *phydev, u16 regnum, u16 val);
+struct phy_device* get_phy_device(struct mii_bus *bus, int addr);
+int phy_clear_interrupt(struct phy_device *phydev);
+int phy_config_interrupt(struct phy_device *phydev, u32 interrupts);
+struct phy_device * phy_attach(struct net_device *dev,
+               const char *phy_id, u32 flags);
+struct phy_device * phy_connect(struct net_device *dev, const char *phy_id,
+               void (*handler)(struct net_device *), u32 flags);
+void phy_disconnect(struct phy_device *phydev);
+void phy_detach(struct phy_device *phydev);
+void phy_start(struct phy_device *phydev);
+void phy_stop(struct phy_device *phydev);
+int phy_start_aneg(struct phy_device *phydev);
+
+int mdiobus_register(struct mii_bus *bus);
+void mdiobus_unregister(struct mii_bus *bus);
+void phy_sanitize_settings(struct phy_device *phydev);
+int phy_stop_interrupts(struct phy_device *phydev);
+
+static inline int phy_read_status(struct phy_device *phydev) {
+       return phydev->drv->read_status(phydev);
+}
+
+int genphy_config_advert(struct phy_device *phydev);
+int genphy_setup_forced(struct phy_device *phydev);
+int genphy_restart_aneg(struct phy_device *phydev);
+int genphy_config_aneg(struct phy_device *phydev);
+int genphy_update_link(struct phy_device *phydev);
+int genphy_read_status(struct phy_device *phydev);
+void phy_driver_unregister(struct phy_driver *drv);
+int phy_driver_register(struct phy_driver *new_driver);
+void phy_prepare_link(struct phy_device *phydev,
+               void (*adjust_link)(struct net_device *));
+void phy_start_machine(struct phy_device *phydev,
+               void (*handler)(struct net_device *));
+void phy_stop_machine(struct phy_device *phydev);
+int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
+int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
+int phy_mii_ioctl(struct phy_device *phydev,
+               struct mii_ioctl_data *mii_data, int cmd);
+int phy_start_interrupts(struct phy_device *phydev);
+void phy_print_status(struct phy_device *phydev);
+
+extern struct bus_type mdio_bus_type;
+#endif /* __PHY_H */
index 36725e7c02c69494222719d1aa334dc5da258c94..1767073df26fe03720176c080d13908ade41f291 100644 (file)
@@ -39,9 +39,6 @@ struct pipe_inode_info {
 
 #define PIPE_SEM(inode)                (&(inode).i_sem)
 #define PIPE_WAIT(inode)       (&(inode).i_pipe->wait)
-#define PIPE_BASE(inode)       ((inode).i_pipe->base)
-#define PIPE_START(inode)      ((inode).i_pipe->start)
-#define PIPE_LEN(inode)                ((inode).i_pipe->len)
 #define PIPE_READERS(inode)    ((inode).i_pipe->readers)
 #define PIPE_WRITERS(inode)    ((inode).i_pipe->writers)
 #define PIPE_WAITING_WRITERS(inode)    ((inode).i_pipe->waiting_writers)
index 7aeb208ed71357ad3a15891ea536021545fba48d..5cfb07648eca1c999403bc17e2f15ea14e125286 100644 (file)
@@ -186,7 +186,9 @@ extern int pm_suspend(suspend_state_t state);
 
 struct device;
 
-typedef u32 __bitwise pm_message_t;
+typedef struct pm_message {
+       int event;
+} pm_message_t;
 
 /*
  * There are 4 important states driver can be in:
@@ -207,9 +209,13 @@ typedef u32 __bitwise pm_message_t;
  * or something similar soon.
  */
 
-#define PMSG_FREEZE    ((__force pm_message_t) 3)
-#define PMSG_SUSPEND   ((__force pm_message_t) 3)
-#define PMSG_ON                ((__force pm_message_t) 0)
+#define PM_EVENT_ON 0
+#define PM_EVENT_FREEZE 1
+#define PM_EVENT_SUSPEND 2
+
+#define PMSG_FREEZE    ((struct pm_message){ .event = PM_EVENT_FREEZE, })
+#define PMSG_SUSPEND   ((struct pm_message){ .event = PM_EVENT_SUSPEND, })
+#define PMSG_ON                ((struct pm_message){ .event = PM_EVENT_ON, })
 
 struct dev_pm_info {
        pm_message_t            power_state;
index 5ec2bd0c28483c0011de79920011fe3aaa4bc2d1..aadbac29103cfc7601291e8fc0415f46d6cafc85 100644 (file)
@@ -443,7 +443,7 @@ static inline void pnp_unregister_driver(struct pnp_driver *drv) { ; }
 #define pnp_info(format, arg...) printk(KERN_INFO "pnp: " format "\n" , ## arg)
 #define pnp_warn(format, arg...) printk(KERN_WARNING "pnp: " format "\n" , ## arg)
 
-#ifdef DEBUG
+#ifdef CONFIG_PNP_DEBUG
 #define pnp_dbg(format, arg...) printk(KERN_DEBUG "pnp: " format "\n" , ## arg)
 #else
 #define pnp_dbg(format, arg...) do {} while (0)
index a373fc254df29431c52c2a879a67e766d9e3133c..dc6f3647bfbc01cfcfca8192d631b12d4c9bdd80 100644 (file)
@@ -20,6 +20,8 @@
 #define PTRACE_DETACH          0x11
 
 #define PTRACE_SYSCALL           24
+#define PTRACE_SYSEMU            31
+#define PTRACE_SYSEMU_SINGLESTEP  32
 
 /* 0x4200-0x4300 are reserved for architecture-independent additions.  */
 #define PTRACE_SETOPTIONS      0x4200
@@ -88,6 +90,7 @@ extern void __ptrace_link(struct task_struct *child,
                          struct task_struct *new_parent);
 extern void __ptrace_unlink(struct task_struct *child);
 extern void ptrace_untrace(struct task_struct *child);
+extern int ptrace_may_attach(struct task_struct *task);
 
 static inline void ptrace_link(struct task_struct *child,
                               struct task_struct *new_parent)
index cc670344991606d5d23f94c8f23068528b951f51..7b2adb3322d5a6052504058e152cc0f94828c06e 100644 (file)
@@ -59,6 +59,8 @@ extern __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
                                        __u16 sport, __u16 dport);
 extern __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr,
                                          __u16 sport, __u16 dport);
+extern u64 secure_dccp_sequence_number(__u32 saddr, __u32 daddr,
+                                      __u16 sport, __u16 dport);
 
 #ifndef MODULE
 extern struct file_operations random_fops, urandom_fops;
diff --git a/include/linux/relayfs_fs.h b/include/linux/relayfs_fs.h
new file mode 100644 (file)
index 0000000..cfafc3e
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * linux/include/linux/relayfs_fs.h
+ *
+ * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
+ * Copyright (C) 1999, 2000, 2001, 2002 - Karim Yaghmour (karim@opersys.com)
+ *
+ * RelayFS definitions and declarations
+ */
+
+#ifndef _LINUX_RELAYFS_FS_H
+#define _LINUX_RELAYFS_FS_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/kref.h>
+
+/*
+ * Tracks changes to rchan_buf struct
+ */
+#define RELAYFS_CHANNEL_VERSION                5
+
+/*
+ * Per-cpu relay channel buffer
+ */
+struct rchan_buf
+{
+       void *start;                    /* start of channel buffer */
+       void *data;                     /* start of current sub-buffer */
+       size_t offset;                  /* current offset into sub-buffer */
+       size_t subbufs_produced;        /* count of sub-buffers produced */
+       size_t subbufs_consumed;        /* count of sub-buffers consumed */
+       struct rchan *chan;             /* associated channel */
+       wait_queue_head_t read_wait;    /* reader wait queue */
+       struct work_struct wake_readers; /* reader wake-up work struct */
+       struct dentry *dentry;          /* channel file dentry */
+       struct kref kref;               /* channel buffer refcount */
+       struct page **page_array;       /* array of current buffer pages */
+       unsigned int page_count;        /* number of current buffer pages */
+       unsigned int finalized;         /* buffer has been finalized */
+       size_t *padding;                /* padding counts per sub-buffer */
+       size_t prev_padding;            /* temporary variable */
+       size_t bytes_consumed;          /* bytes consumed in cur read subbuf */
+       unsigned int cpu;               /* this buf's cpu */
+} ____cacheline_aligned;
+
+/*
+ * Relay channel data structure
+ */
+struct rchan
+{
+       u32 version;                    /* the version of this struct */
+       size_t subbuf_size;             /* sub-buffer size */
+       size_t n_subbufs;               /* number of sub-buffers per buffer */
+       size_t alloc_size;              /* total buffer size allocated */
+       struct rchan_callbacks *cb;     /* client callbacks */
+       struct kref kref;               /* channel refcount */
+       void *private_data;             /* for user-defined data */
+       struct rchan_buf *buf[NR_CPUS]; /* per-cpu channel buffers */
+};
+
+/*
+ * Relayfs inode
+ */
+struct relayfs_inode_info
+{
+       struct inode vfs_inode;
+       struct rchan_buf *buf;
+};
+
+static inline struct relayfs_inode_info *RELAYFS_I(struct inode *inode)
+{
+       return container_of(inode, struct relayfs_inode_info, vfs_inode);
+}
+
+/*
+ * Relay channel client callbacks
+ */
+struct rchan_callbacks
+{
+       /*
+        * subbuf_start - called on buffer-switch to a new sub-buffer
+        * @buf: the channel buffer containing the new sub-buffer
+        * @subbuf: the start of the new sub-buffer
+        * @prev_subbuf: the start of the previous sub-buffer
+        * @prev_padding: unused space at the end of previous sub-buffer
+        *
+        * The client should return 1 to continue logging, 0 to stop
+        * logging.
+        *
+        * NOTE: subbuf_start will also be invoked when the buffer is
+        *       created, so that the first sub-buffer can be initialized
+        *       if necessary.  In this case, prev_subbuf will be NULL.
+        *
+        * NOTE: the client can reserve bytes at the beginning of the new
+        *       sub-buffer by calling subbuf_start_reserve() in this callback.
+        */
+       int (*subbuf_start) (struct rchan_buf *buf,
+                            void *subbuf,
+                            void *prev_subbuf,
+                            size_t prev_padding);
+
+       /*
+        * buf_mapped - relayfs buffer mmap notification
+        * @buf: the channel buffer
+        * @filp: relayfs file pointer
+        *
+        * Called when a relayfs file is successfully mmapped
+        */
+        void (*buf_mapped)(struct rchan_buf *buf,
+                          struct file *filp);
+
+       /*
+        * buf_unmapped - relayfs buffer unmap notification
+        * @buf: the channel buffer
+        * @filp: relayfs file pointer
+        *
+        * Called when a relayfs file is successfully unmapped
+        */
+        void (*buf_unmapped)(struct rchan_buf *buf,
+                            struct file *filp);
+};
+
+/*
+ * relayfs kernel API, fs/relayfs/relay.c
+ */
+
+struct rchan *relay_open(const char *base_filename,
+                        struct dentry *parent,
+                        size_t subbuf_size,
+                        size_t n_subbufs,
+                        struct rchan_callbacks *cb);
+extern void relay_close(struct rchan *chan);
+extern void relay_flush(struct rchan *chan);
+extern void relay_subbufs_consumed(struct rchan *chan,
+                                  unsigned int cpu,
+                                  size_t consumed);
+extern void relay_reset(struct rchan *chan);
+extern int relay_buf_full(struct rchan_buf *buf);
+
+extern size_t relay_switch_subbuf(struct rchan_buf *buf,
+                                 size_t length);
+extern struct dentry *relayfs_create_dir(const char *name,
+                                        struct dentry *parent);
+extern int relayfs_remove_dir(struct dentry *dentry);
+
+/**
+ *     relay_write - write data into the channel
+ *     @chan: relay channel
+ *     @data: data to be written
+ *     @length: number of bytes to write
+ *
+ *     Writes data into the current cpu's channel buffer.
+ *
+ *     Protects the buffer by disabling interrupts.  Use this
+ *     if you might be logging from interrupt context.  Try
+ *     __relay_write() if you know you won't be logging from
+ *     interrupt context.
+ */
+static inline void relay_write(struct rchan *chan,
+                              const void *data,
+                              size_t length)
+{
+       unsigned long flags;
+       struct rchan_buf *buf;
+
+       local_irq_save(flags);
+       buf = chan->buf[smp_processor_id()];
+       if (unlikely(buf->offset + length > chan->subbuf_size))
+               length = relay_switch_subbuf(buf, length);
+       memcpy(buf->data + buf->offset, data, length);
+       buf->offset += length;
+       local_irq_restore(flags);
+}
+
+/**
+ *     __relay_write - write data into the channel
+ *     @chan: relay channel
+ *     @data: data to be written
+ *     @length: number of bytes to write
+ *
+ *     Writes data into the current cpu's channel buffer.
+ *
+ *     Protects the buffer by disabling preemption.  Use
+ *     relay_write() if you might be logging from interrupt
+ *     context.
+ */
+static inline void __relay_write(struct rchan *chan,
+                                const void *data,
+                                size_t length)
+{
+       struct rchan_buf *buf;
+
+       buf = chan->buf[get_cpu()];
+       if (unlikely(buf->offset + length > buf->chan->subbuf_size))
+               length = relay_switch_subbuf(buf, length);
+       memcpy(buf->data + buf->offset, data, length);
+       buf->offset += length;
+       put_cpu();
+}
+
+/**
+ *     relay_reserve - reserve slot in channel buffer
+ *     @chan: relay channel
+ *     @length: number of bytes to reserve
+ *
+ *     Returns pointer to reserved slot, NULL if full.
+ *
+ *     Reserves a slot in the current cpu's channel buffer.
+ *     Does not protect the buffer at all - caller must provide
+ *     appropriate synchronization.
+ */
+static inline void *relay_reserve(struct rchan *chan, size_t length)
+{
+       void *reserved;
+       struct rchan_buf *buf = chan->buf[smp_processor_id()];
+
+       if (unlikely(buf->offset + length > buf->chan->subbuf_size)) {
+               length = relay_switch_subbuf(buf, length);
+               if (!length)
+                       return NULL;
+       }
+       reserved = buf->data + buf->offset;
+       buf->offset += length;
+
+       return reserved;
+}
+
+/**
+ *     subbuf_start_reserve - reserve bytes at the start of a sub-buffer
+ *     @buf: relay channel buffer
+ *     @length: number of bytes to reserve
+ *
+ *     Helper function used to reserve bytes at the beginning of
+ *     a sub-buffer in the subbuf_start() callback.
+ */
+static inline void subbuf_start_reserve(struct rchan_buf *buf,
+                                       size_t length)
+{
+       BUG_ON(length >= buf->chan->subbuf_size - 1);
+       buf->offset = length;
+}
+
+/*
+ * exported relayfs file operations, fs/relayfs/inode.c
+ */
+
+extern struct file_operations relayfs_file_operations;
+
+#endif /* _LINUX_RELAYFS_FS_H */
+
index 657c05ab8f9eb79c63422d495f105e7c91bb489b..c231e9a08f0bb2b2365b7f5f568de8c459385a59 100644 (file)
@@ -826,9 +826,8 @@ enum
 #define TCA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcmsg))))
 #define TCA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcmsg))
 
-
-/* RTnetlink multicast groups */
-
+#ifndef __KERNEL__
+/* RTnetlink multicast groups - backwards compatibility for userspace */
 #define RTMGRP_LINK            1
 #define RTMGRP_NOTIFY          2
 #define RTMGRP_NEIGH           4
@@ -847,6 +846,43 @@ enum
 #define RTMGRP_DECnet_ROUTE     0x4000
 
 #define RTMGRP_IPV6_PREFIX     0x20000
+#endif
+
+/* RTnetlink multicast groups */
+enum rtnetlink_groups {
+       RTNLGRP_NONE,
+#define RTNLGRP_NONE           RTNLGRP_NONE
+       RTNLGRP_LINK,
+#define RTNLGRP_LINK           RTNLGRP_LINK
+       RTNLGRP_NOTIFY,
+#define RTNLGRP_NOTIFY         RTNLGRP_NOTIFY
+       RTNLGRP_NEIGH,
+#define RTNLGRP_NEIGH          RTNLGRP_NEIGH
+       RTNLGRP_TC,
+#define RTNLGRP_TC             RTNLGRP_TC
+       RTNLGRP_IPV4_IFADDR,
+#define RTNLGRP_IPV4_IFADDR    RTNLGRP_IPV4_IFADDR
+       RTNLGRP_IPV4_MROUTE,
+#define        RTNLGRP_IPV4_MROUTE     RTNLGRP_IPV4_MROUTE
+       RTNLGRP_IPV4_ROUTE,
+#define RTNLGRP_IPV4_ROUTE     RTNLGRP_IPV4_ROUTE
+       RTNLGRP_IPV6_IFADDR,
+#define RTNLGRP_IPV6_IFADDR    RTNLGRP_IPV6_IFADDR
+       RTNLGRP_IPV6_MROUTE,
+#define RTNLGRP_IPV6_MROUTE    RTNLGRP_IPV6_MROUTE
+       RTNLGRP_IPV6_ROUTE,
+#define RTNLGRP_IPV6_ROUTE     RTNLGRP_IPV6_ROUTE
+       RTNLGRP_IPV6_IFINFO,
+#define RTNLGRP_IPV6_IFINFO    RTNLGRP_IPV6_IFINFO
+       RTNLGRP_DECnet_IFADDR,
+#define RTNLGRP_DECnet_IFADDR  RTNLGRP_DECnet_IFADDR
+       RTNLGRP_DECnet_ROUTE,
+#define RTNLGRP_DECnet_ROUTE   RTNLGRP_DECnet_ROUTE
+       RTNLGRP_IPV6_PREFIX,
+#define RTNLGRP_IPV6_PREFIX    RTNLGRP_IPV6_PREFIX
+       __RTNLGRP_MAX
+};
+#define RTNLGRP_MAX    (__RTNLGRP_MAX - 1)
 
 /* TC action piece */
 struct tcamsg
index dec5827c77422ebbd8e7f0238cdf7f34e08cb906..ea1b5f32ec5c1952cbf254f4563d7d707a85e155 100644 (file)
@@ -35,6 +35,8 @@
 #include <linux/topology.h>
 #include <linux/seccomp.h>
 
+#include <linux/auxvec.h>      /* For AT_VECTOR_SIZE */
+
 struct exec_domain;
 
 /*
@@ -176,6 +178,23 @@ extern void trap_init(void);
 extern void update_process_times(int user);
 extern void scheduler_tick(void);
 
+#ifdef CONFIG_DETECT_SOFTLOCKUP
+extern void softlockup_tick(struct pt_regs *regs);
+extern void spawn_softlockup_task(void);
+extern void touch_softlockup_watchdog(void);
+#else
+static inline void softlockup_tick(struct pt_regs *regs)
+{
+}
+static inline void spawn_softlockup_task(void)
+{
+}
+static inline void touch_softlockup_watchdog(void)
+{
+}
+#endif
+
+
 /* Attach to any functions which should be ignored in wchan output. */
 #define __sched                __attribute__((__section__(".sched.text")))
 /* Is this address in the __sched functions? */
@@ -244,7 +263,7 @@ struct mm_struct {
        mm_counter_t _rss;
        mm_counter_t _anon_rss;
 
-       unsigned long saved_auxv[42]; /* for /proc/PID/auxv */
+       unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */
 
        unsigned dumpable:2;
        cpumask_t cpu_vm_mask;
@@ -545,13 +564,6 @@ struct sched_domain {
 
 extern void partition_sched_domains(cpumask_t *partition1,
                                    cpumask_t *partition2);
-#ifdef ARCH_HAS_SCHED_DOMAIN
-/* Useful helpers that arch setup code may use. Defined in kernel/sched.c */
-extern cpumask_t cpu_isolated_map;
-extern void init_sched_build_groups(struct sched_group groups[],
-                               cpumask_t span, int (*group_fn)(int cpu));
-extern void cpu_attach_domain(struct sched_domain *sd, int cpu);
-#endif /* ARCH_HAS_SCHED_DOMAIN */
 #endif /* CONFIG_SMP */
 
 
index b42095a68b1c44e964d65c1a13541726a717f4ff..7aab6ab7c57febdadfd4d8dedea554594b14baa6 100644 (file)
@@ -2727,7 +2727,8 @@ static inline int security_socket_getpeersec(struct socket *sock, char __user *o
        return security_ops->socket_getpeersec(sock, optval, optlen, len);
 }
 
-static inline int security_sk_alloc(struct sock *sk, int family, int priority)
+static inline int security_sk_alloc(struct sock *sk, int family,
+                                   unsigned int __nocast priority)
 {
        return security_ops->sk_alloc_security(sk, family, priority);
 }
@@ -2844,7 +2845,8 @@ static inline int security_socket_getpeersec(struct socket *sock, char __user *o
        return -ENOPROTOOPT;
 }
 
-static inline int security_sk_alloc(struct sock *sk, int family, int priority)
+static inline int security_sk_alloc(struct sock *sk, int family,
+                                   unsigned int __nocast priority)
 {
        return 0;
 }
index 957e6ebca4e6ad93275699bd77cd6892b0bbb463..bbf489decd84df3009b79dc24eea7d81d147c9ca 100644 (file)
@@ -20,10 +20,21 @@ enum {
        SELNL_MSG_MAX
 };
 
-/* Multicast groups */
+#ifndef __KERNEL__
+/* Multicast groups - backwards compatiblility for userspace */
 #define SELNL_GRP_NONE         0x00000000
 #define SELNL_GRP_AVC          0x00000001      /* AVC notifications */
 #define SELNL_GRP_ALL          0xffffffff
+#endif
+
+enum selinux_nlgroups {
+       SELNLGRP_NONE,
+#define SELNLGRP_NONE  SELNLGRP_NONE
+       SELNLGRP_AVC,
+#define SELNLGRP_AVC   SELNLGRP_AVC
+       __SELNLGRP_MAX
+};
+#define SELNLGRP_MAX   (__SELNLGRP_MAX - 1)
 
 /* Message structures */
 struct selnl_msg_setenforce {
index 2d8516be9fd7f71aac09b09076f2a04e2d37cc9f..106f9757339a54aeffc52a440129b5827040c8c1 100644 (file)
@@ -88,6 +88,7 @@ struct sem {
 /* One sem_array data structure for each set of semaphores in the system. */
 struct sem_array {
        struct kern_ipc_perm    sem_perm;       /* permissions .. see ipc.h */
+       int                     sem_id;
        time_t                  sem_otime;      /* last semop time */
        time_t                  sem_ctime;      /* last change time */
        struct sem              *sem_base;      /* ptr to first semaphore in array */
index 9f2d85284d0b78f95cba741c51d63f9545a61be1..12cd9cf65e8ffe3b6a2b58042336a8e11d5092ef 100644 (file)
@@ -176,10 +176,6 @@ struct serial_icounter_struct {
 #ifdef __KERNEL__
 #include <linux/compiler.h>
 
-/* Export to allow PCMCIA to use this - Dave Hinds */
-extern int __deprecated register_serial(struct serial_struct *req);
-extern void __deprecated unregister_serial(int line);
-
 /* Allow architectures to override entries in serial8250_ports[] at run time: */
 struct uart_port;      /* forward declaration */
 extern int early_serial_setup(struct uart_port *port);
index 2b2f35a64d7510e5436c40bd1ff5caa0b258c7f9..2b9e6b9554d577fa49130c4c4e2a4c745d7b3088 100644 (file)
@@ -140,44 +140,4 @@ struct rs_multiport_struct {
 #define ALPHA_KLUDGE_MCR 0
 #endif
 
-/*
- * Definitions for PCI support.
- */
-#define SPCI_FL_BASE_MASK      0x0007
-#define SPCI_FL_BASE0  0x0000
-#define SPCI_FL_BASE1  0x0001
-#define SPCI_FL_BASE2  0x0002
-#define SPCI_FL_BASE3  0x0003
-#define SPCI_FL_BASE4  0x0004
-#define SPCI_FL_GET_BASE(x)    (x & SPCI_FL_BASE_MASK)
-
-#define SPCI_FL_IRQ_MASK       (0x0007 << 4)
-#define SPCI_FL_IRQBASE0       (0x0000 << 4)
-#define SPCI_FL_IRQBASE1       (0x0001 << 4)
-#define SPCI_FL_IRQBASE2       (0x0002 << 4)
-#define SPCI_FL_IRQBASE3       (0x0003 << 4)
-#define SPCI_FL_IRQBASE4       (0x0004 << 4)
-#define SPCI_FL_GET_IRQBASE(x)        ((x & SPCI_FL_IRQ_MASK) >> 4)
-
-/* Use successive BARs (PCI base address registers), 
-   else use offset into some specified BAR */
-#define SPCI_FL_BASE_TABLE     0x0100
-
-/* Use successive entries in the irq resource table */
-#define SPCI_FL_IRQ_TABLE      0x0200
-
-/* Use the irq resource table instead of dev->irq */
-#define SPCI_FL_IRQRESOURCE    0x0400
-
-/* Use the Base address register size to cap number of ports */
-#define SPCI_FL_REGION_SZ_CAP  0x0800
-
-/* Do not use irq sharing for this device */
-#define SPCI_FL_NO_SHIRQ       0x1000
-
-/* This is a PNP device */
-#define SPCI_FL_ISPNP          0x2000
-
-#define SPCI_FL_PNPDEFAULT     (SPCI_FL_IRQRESOURCE|SPCI_FL_ISPNP)
-
 #endif /* _LINUX_SERIAL_H */
index 3e3c1fa35b06cc2eafa509f2cf1d2b4dcf04e7e4..d8a023d804d4606810e5f79b969cc2fad14c69e9 100644 (file)
@@ -14,6 +14,9 @@
 #include <linux/serial_core.h>
 #include <linux/device.h>
 
+/*
+ * This is the platform device platform_data structure
+ */
 struct plat_serial8250_port {
        unsigned long   iobase;         /* io base address */
        void __iomem    *membase;       /* ioremap cookie or NULL */
@@ -26,4 +29,17 @@ struct plat_serial8250_port {
        unsigned int    flags;          /* UPF_* flags */
 };
 
+/*
+ * This should be used by drivers which want to register
+ * their own 8250 ports without registering their own
+ * platform device.  Using these will make your driver
+ * dependent on the 8250 driver.
+ */
+struct uart_port;
+
+int serial8250_register_port(struct uart_port *);
+void serial8250_unregister_port(int line);
+void serial8250_suspend_port(int line);
+void serial8250_resume_port(int line);
+
 #endif
index f6fca8f2f3cac00fd24c0774ebcd8891e6c043d3..9b12fe731612dfd2ccb1665278dd5416e2e509f3 100644 (file)
@@ -142,8 +142,8 @@ struct uart_ops {
        unsigned int    (*tx_empty)(struct uart_port *);
        void            (*set_mctrl)(struct uart_port *, unsigned int mctrl);
        unsigned int    (*get_mctrl)(struct uart_port *);
-       void            (*stop_tx)(struct uart_port *, unsigned int tty_stop);
-       void            (*start_tx)(struct uart_port *, unsigned int tty_start);
+       void            (*stop_tx)(struct uart_port *);
+       void            (*start_tx)(struct uart_port *);
        void            (*send_xchar)(struct uart_port *, char ch);
        void            (*stop_rx)(struct uart_port *);
        void            (*enable_ms)(struct uart_port *);
@@ -360,8 +360,6 @@ struct tty_driver *uart_console_device(struct console *co, int *index);
  */
 int uart_register_driver(struct uart_driver *uart);
 void uart_unregister_driver(struct uart_driver *uart);
-void __deprecated uart_unregister_port(struct uart_driver *reg, int line);
-int __deprecated uart_register_port(struct uart_driver *reg, struct uart_port *port);
 int uart_add_one_port(struct uart_driver *reg, struct uart_port *port);
 int uart_remove_one_port(struct uart_driver *reg, struct uart_port *port);
 int uart_match_port(struct uart_port *port1, struct uart_port *port2);
@@ -387,11 +385,11 @@ int uart_resume_port(struct uart_driver *reg, struct uart_port *port);
 /*
  * The following are helper functions for the low level drivers.
  */
-#ifdef SUPPORT_SYSRQ
 static inline int
 uart_handle_sysrq_char(struct uart_port *port, unsigned int ch,
                       struct pt_regs *regs)
 {
+#ifdef SUPPORT_SYSRQ
        if (port->sysrq) {
                if (ch && time_before(jiffies, port->sysrq)) {
                        handle_sysrq(ch, regs, NULL);
@@ -400,11 +398,9 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch,
                }
                port->sysrq = 0;
        }
+#endif
        return 0;
 }
-#else
-#define uart_handle_sysrq_char(port,ch,regs)   (0)
-#endif
 
 /*
  * We do the SysRQ and SAK checking like this...
@@ -468,13 +464,13 @@ uart_handle_cts_change(struct uart_port *port, unsigned int status)
                if (tty->hw_stopped) {
                        if (status) {
                                tty->hw_stopped = 0;
-                               port->ops->start_tx(port, 0);
+                               port->ops->start_tx(port);
                                uart_write_wakeup(port);
                        }
                } else {
                        if (!status) {
                                tty->hw_stopped = 1;
-                               port->ops->stop_tx(port, 0);
+                               port->ops->stop_tx(port);
                        }
                }
        }
index 948527e42a60db205cdb88d458f11d4c39b22248..da7da9c0ed1b50e1f8dac7c08b919c104c287e30 100644 (file)
@@ -155,16 +155,29 @@ struct skb_shared_info {
 #define SKB_DATAREF_SHIFT 16
 #define SKB_DATAREF_MASK ((1 << SKB_DATAREF_SHIFT) - 1)
 
+extern struct timeval skb_tv_base;
+
+struct skb_timeval {
+       u32     off_sec;
+       u32     off_usec;
+};
+
+
+enum {
+       SKB_FCLONE_UNAVAILABLE,
+       SKB_FCLONE_ORIG,
+       SKB_FCLONE_CLONE,
+};
+
 /** 
  *     struct sk_buff - socket buffer
  *     @next: Next buffer in list
  *     @prev: Previous buffer in list
  *     @list: List we are on
  *     @sk: Socket we are owned by
- *     @stamp: Time we arrived
+ *     @tstamp: Time we arrived stored as offset to skb_tv_base
  *     @dev: Device we arrived on/are leaving by
  *     @input_dev: Device we arrived on
- *      @real_dev: The real device we are using
  *     @h: Transport layer header
  *     @nh: Network layer header
  *     @mac: Link layer header
@@ -190,14 +203,11 @@ struct skb_shared_info {
  *     @end: End pointer
  *     @destructor: Destruct function
  *     @nfmark: Can be used for communication between hooks
- *     @nfcache: Cache info
  *     @nfct: Associated connection, if any
  *     @nfctinfo: Relationship of this skb to the connection
  *     @nf_bridge: Saved data about a bridged frame - see br_netfilter.c
- *      @private: Data which is private to the HIPPI implementation
  *     @tc_index: Traffic control index
  *     @tc_verd: traffic control verdict
- *     @tc_classid: traffic control classid
  */
 
 struct sk_buff {
@@ -205,12 +215,10 @@ struct sk_buff {
        struct sk_buff          *next;
        struct sk_buff          *prev;
 
-       struct sk_buff_head     *list;
        struct sock             *sk;
-       struct timeval          stamp;
+       struct skb_timeval      tstamp;
        struct net_device       *dev;
        struct net_device       *input_dev;
-       struct net_device       *real_dev;
 
        union {
                struct tcphdr   *th;
@@ -252,33 +260,28 @@ struct sk_buff {
        __u8                    local_df:1,
                                cloned:1,
                                ip_summed:2,
-                               nohdr:1;
-                               /* 3 bits spare */
-       __u8                    pkt_type;
+                               nohdr:1,
+                               nfctinfo:3;
+       __u8                    pkt_type:3,
+                               fclone:2;
        __be16                  protocol;
 
        void                    (*destructor)(struct sk_buff *skb);
 #ifdef CONFIG_NETFILTER
-       unsigned long           nfmark;
-       __u32                   nfcache;
-       __u32                   nfctinfo;
+       __u32                   nfmark;
        struct nf_conntrack     *nfct;
+#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
+       __u8                    ipvs_property:1;
+#endif
 #ifdef CONFIG_BRIDGE_NETFILTER
        struct nf_bridge_info   *nf_bridge;
 #endif
 #endif /* CONFIG_NETFILTER */
-#if defined(CONFIG_HIPPI)
-       union {
-               __u32           ifield;
-       } private;
-#endif
 #ifdef CONFIG_NET_SCHED
-       __u32                   tc_index;        /* traffic control index */
+       __u16                   tc_index;       /* traffic control index */
 #ifdef CONFIG_NET_CLS_ACT
-       __u32           tc_verd;               /* traffic control verdict */
-       __u32           tc_classid;            /* traffic control classid */
+       __u16                   tc_verd;        /* traffic control verdict */
 #endif
-
 #endif
 
 
@@ -300,8 +303,20 @@ struct sk_buff {
 #include <asm/system.h>
 
 extern void           __kfree_skb(struct sk_buff *skb);
-extern struct sk_buff *alloc_skb(unsigned int size,
-                                unsigned int __nocast priority);
+extern struct sk_buff *__alloc_skb(unsigned int size,
+                                  unsigned int __nocast priority, int fclone);
+static inline struct sk_buff *alloc_skb(unsigned int size,
+                                       unsigned int __nocast priority)
+{
+       return __alloc_skb(size, priority, 0);
+}
+
+static inline struct sk_buff *alloc_skb_fclone(unsigned int size,
+                                              unsigned int __nocast priority)
+{
+       return __alloc_skb(size, priority, 1);
+}
+
 extern struct sk_buff *alloc_skb_from_cache(kmem_cache_t *cp,
                                            unsigned int size,
                                            unsigned int __nocast priority);
@@ -597,7 +612,6 @@ static inline void __skb_queue_head(struct sk_buff_head *list,
 {
        struct sk_buff *prev, *next;
 
-       newsk->list = list;
        list->qlen++;
        prev = (struct sk_buff *)list;
        next = prev->next;
@@ -622,7 +636,6 @@ static inline void __skb_queue_tail(struct sk_buff_head *list,
 {
        struct sk_buff *prev, *next;
 
-       newsk->list = list;
        list->qlen++;
        next = (struct sk_buff *)list;
        prev = next->prev;
@@ -655,7 +668,6 @@ static inline struct sk_buff *__skb_dequeue(struct sk_buff_head *list)
                next->prev   = prev;
                prev->next   = next;
                result->next = result->prev = NULL;
-               result->list = NULL;
        }
        return result;
 }
@@ -664,7 +676,7 @@ static inline struct sk_buff *__skb_dequeue(struct sk_buff_head *list)
 /*
  *     Insert a packet on a list.
  */
-extern void        skb_insert(struct sk_buff *old, struct sk_buff *newsk);
+extern void        skb_insert(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list);
 static inline void __skb_insert(struct sk_buff *newsk,
                                struct sk_buff *prev, struct sk_buff *next,
                                struct sk_buff_head *list)
@@ -672,24 +684,23 @@ static inline void __skb_insert(struct sk_buff *newsk,
        newsk->next = next;
        newsk->prev = prev;
        next->prev  = prev->next = newsk;
-       newsk->list = list;
        list->qlen++;
 }
 
 /*
  *     Place a packet after a given packet in a list.
  */
-extern void       skb_append(struct sk_buff *old, struct sk_buff *newsk);
-static inline void __skb_append(struct sk_buff *old, struct sk_buff *newsk)
+extern void       skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list);
+static inline void __skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list)
 {
-       __skb_insert(newsk, old, old->next, old->list);
+       __skb_insert(newsk, old, old->next, list);
 }
 
 /*
  * remove sk_buff from list. _Must_ be called atomically, and with
  * the list known..
  */
-extern void       skb_unlink(struct sk_buff *skb);
+extern void       skb_unlink(struct sk_buff *skb, struct sk_buff_head *list);
 static inline void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list)
 {
        struct sk_buff *next, *prev;
@@ -698,7 +709,6 @@ static inline void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list)
        next       = skb->next;
        prev       = skb->prev;
        skb->next  = skb->prev = NULL;
-       skb->list  = NULL;
        next->prev = prev;
        prev->next = next;
 }
@@ -1213,6 +1223,8 @@ extern void              skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to);
 extern void           skb_split(struct sk_buff *skb,
                                 struct sk_buff *skb1, const u32 len);
 
+extern void           skb_release_data(struct sk_buff *skb);
+
 static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
                                       int len, void *buffer)
 {
@@ -1230,6 +1242,42 @@ static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
 extern void skb_init(void);
 extern void skb_add_mtu(int mtu);
 
+/**
+ *     skb_get_timestamp - get timestamp from a skb
+ *     @skb: skb to get stamp from
+ *     @stamp: pointer to struct timeval to store stamp in
+ *
+ *     Timestamps are stored in the skb as offsets to a base timestamp.
+ *     This function converts the offset back to a struct timeval and stores
+ *     it in stamp.
+ */
+static inline void skb_get_timestamp(const struct sk_buff *skb, struct timeval *stamp)
+{
+       stamp->tv_sec  = skb->tstamp.off_sec;
+       stamp->tv_usec = skb->tstamp.off_usec;
+       if (skb->tstamp.off_sec) {
+               stamp->tv_sec  += skb_tv_base.tv_sec;
+               stamp->tv_usec += skb_tv_base.tv_usec;
+       }
+}
+
+/**
+ *     skb_set_timestamp - set timestamp of a skb
+ *     @skb: skb to set stamp of
+ *     @stamp: pointer to struct timeval to get stamp from
+ *
+ *     Timestamps are stored in the skb as offsets to a base timestamp.
+ *     This function converts a struct timeval to an offset and stores
+ *     it in the skb.
+ */
+static inline void skb_set_timestamp(struct sk_buff *skb, const struct timeval *stamp)
+{
+       skb->tstamp.off_sec  = stamp->tv_sec - skb_tv_base.tv_sec;
+       skb->tstamp.off_usec = stamp->tv_usec - skb_tv_base.tv_usec;
+}
+
+extern void __net_timestamp(struct sk_buff *skb);
+
 #ifdef CONFIG_NETFILTER
 static inline void nf_conntrack_put(struct nf_conntrack *nfct)
 {
index 80b2dfde2e8087d84ec06f945f3fa4a61ece4f55..42a6bea58af369f4408eba0cf020dbc6d74352eb 100644 (file)
@@ -99,7 +99,21 @@ found:
        return __kmalloc(size, flags);
 }
 
-extern void *kcalloc(size_t, size_t, unsigned int __nocast);
+extern void *kzalloc(size_t, unsigned int __nocast);
+
+/**
+ * kcalloc - allocate memory for an array. The memory is set to zero.
+ * @n: number of elements.
+ * @size: element size.
+ * @flags: the type of memory to allocate.
+ */
+static inline void *kcalloc(size_t n, size_t size, unsigned int __nocast flags)
+{
+       if (n != 0 && size > INT_MAX / n)
+               return NULL;
+       return kzalloc(n * size, flags);
+}
+
 extern void kfree(const void *);
 extern unsigned int ksize(const void *);
 
index a5c7d96e4d2e12172e892b3eb3a3b806e2fa2ca9..1739c2d5b95b449669b887aa86aeb324d836c1f2 100644 (file)
@@ -26,6 +26,13 @@ struct __kernel_sockaddr_storage {
 #include <linux/types.h>               /* pid_t                        */
 #include <linux/compiler.h>            /* __user                       */
 
+extern int sysctl_somaxconn;
+extern void sock_init(void);
+#ifdef CONFIG_PROC_FS
+struct seq_file;
+extern void socket_seq_show(struct seq_file *seq);
+#endif
+
 typedef unsigned short sa_family_t;
 
 /*
@@ -271,6 +278,8 @@ struct ucred {
 #define SOL_IRDA        266
 #define SOL_NETBEUI    267
 #define SOL_LLC                268
+#define SOL_DCCP       269
+#define SOL_NETLINK    270
 
 /* IPX options */
 #define IPX_TYPE       1
index 768cbba617d02533388270a1a0e1795752d15cb6..f56d2473495004a6958b95fc5a07b54f28a5aba8 100644 (file)
@@ -99,6 +99,8 @@
 #define SONYPI_EVENT_BATTERY_INSERT            57
 #define SONYPI_EVENT_BATTERY_REMOVE            58
 #define SONYPI_EVENT_FNKEY_RELEASED            59
+#define SONYPI_EVENT_WIRELESS_ON               60
+#define SONYPI_EVENT_WIRELESS_OFF              61
 
 /* get/set brightness */
 #define SONYPI_IOCGBRT         _IOR('v', 0, __u8)
index 428f59794f4877e87455d49e9de7cb1779eb4334..72b9af4c3fd48e822fb28a8d3d025115fc82ff62 100644 (file)
@@ -29,7 +29,9 @@
  *     Sound core interface functions
  */
  
+struct device;
 extern int register_sound_special(struct file_operations *fops, int unit);
+extern int register_sound_special_device(struct file_operations *fops, int unit, struct device *dev);
 extern int register_sound_mixer(struct file_operations *fops, int dev);
 extern int register_sound_midi(struct file_operations *fops, int dev);
 extern int register_sound_dsp(struct file_operations *fops, int dev);
index 6864063d1b9f0c6638a2c7fa94f525536179e522..c4e3ea7cf1545e5da79e504c8fabddbc1f4a8d87 100644 (file)
@@ -60,6 +60,7 @@ struct cache_head {
 #define        CACHE_NEW_EXPIRY 120    /* keep new things pending confirmation for 120 seconds */
 
 struct cache_detail {
+       struct module *         owner;
        int                     hash_size;
        struct cache_head **    hash_table;
        rwlock_t                hash_lock;
index bfe3e763ccf283d6bc680877aa2f11a658c04afd..3c9ff00481533a77b11561f9b11db877ac937343 100644 (file)
@@ -107,6 +107,8 @@ enum {
        SWP_USED        = (1 << 0),     /* is slot in swap_info[] used? */
        SWP_WRITEOK     = (1 << 1),     /* ok to write to this swap?    */
        SWP_ACTIVE      = (SWP_USED | SWP_WRITEOK),
+                                       /* add others here before... */
+       SWP_SCANNING    = (1 << 8),     /* refcount in scan_swap_map */
 };
 
 #define SWAP_CLUSTER_MAX 32
@@ -116,16 +118,13 @@ enum {
 
 /*
  * The in-memory structure used to track swap areas.
- * extent_list.prev points at the lowest-index extent.  That list is
- * sorted.
  */
 struct swap_info_struct {
        unsigned int flags;
-       spinlock_t sdev_lock;
+       int prio;                       /* swap priority */
        struct file *swap_file;
        struct block_device *bdev;
        struct list_head extent_list;
-       int nr_extents;
        struct swap_extent *curr_swap_extent;
        unsigned old_block_size;
        unsigned short * swap_map;
@@ -133,10 +132,9 @@ struct swap_info_struct {
        unsigned int highest_bit;
        unsigned int cluster_next;
        unsigned int cluster_nr;
-       int prio;                       /* swap priority */
-       int pages;
-       unsigned long max;
-       unsigned long inuse_pages;
+       unsigned int pages;
+       unsigned int max;
+       unsigned int inuse_pages;
        int next;                       /* next entry on swap list */
 };
 
@@ -222,13 +220,7 @@ extern int can_share_swap_page(struct page *);
 extern int remove_exclusive_swap_page(struct page *);
 struct backing_dev_info;
 
-extern struct swap_list_t swap_list;
-extern spinlock_t swaplock;
-
-#define swap_list_lock()       spin_lock(&swaplock)
-#define swap_list_unlock()     spin_unlock(&swaplock)
-#define swap_device_lock(p)    spin_lock(&p->sdev_lock)
-#define swap_device_unlock(p)  spin_unlock(&p->sdev_lock)
+extern spinlock_t swap_lock;
 
 /* linux/mm/thrash.c */
 extern struct mm_struct * swap_token_mm;
index d4c7db35e7081495cc556eb7b4dae17a6380e1b9..87b9d14c710db69217e2eac3a18c903ca772a254 100644 (file)
@@ -4,7 +4,7 @@
  * the low-order bits.
  *
  * We arrange the `type' and `offset' fields so that `type' is at the five
- * high-order bits of the smp_entry_t and `offset' is right-aligned in the
+ * high-order bits of the swp_entry_t and `offset' is right-aligned in the
  * remaining bits.
  *
  * swp_entry_t's are *never* stored anywhere in their arch-dependent format.
index e82be96d4906654bbb91e9c8fbf0a8ab7696d713..532a6c5c24e9cc105b30accf34f4a6e792967988 100644 (file)
@@ -711,6 +711,7 @@ enum {
        DEV_RAID=4,
        DEV_MAC_HID=5,
        DEV_SCSI=6,
+       DEV_IPMI=7,
 };
 
 /* /proc/sys/dev/cdrom */
@@ -776,6 +777,11 @@ enum {
        DEV_SCSI_LOGGING_LEVEL=1,
 };
 
+/* /proc/sys/dev/ipmi */
+enum {
+       DEV_IPMI_POWEROFF_POWERCYCLE=1,
+};
+
 /* /proc/sys/abi */
 enum
 {
index e4fd82e4210428458754a263c7e09930c2cb7e8a..ac4ca44c75caec326729575ba9293aab0ca457f1 100644 (file)
@@ -55,24 +55,6 @@ struct tcphdr {
        __u16   urg_ptr;
 };
 
-
-enum {
-  TCP_ESTABLISHED = 1,
-  TCP_SYN_SENT,
-  TCP_SYN_RECV,
-  TCP_FIN_WAIT1,
-  TCP_FIN_WAIT2,
-  TCP_TIME_WAIT,
-  TCP_CLOSE,
-  TCP_CLOSE_WAIT,
-  TCP_LAST_ACK,
-  TCP_LISTEN,
-  TCP_CLOSING,  /* now a valid state */
-
-  TCP_MAX_STATES /* Leave at the end! */
-};
-
-#define TCP_STATE_MASK 0xF
 #define TCP_ACTION_FIN (1 << 7)
 
 enum {
@@ -195,8 +177,9 @@ struct tcp_info
 
 #include <linux/config.h>
 #include <linux/skbuff.h>
-#include <linux/ip.h>
 #include <net/sock.h>
+#include <net/inet_connection_sock.h>
+#include <net/inet_timewait_sock.h>
 
 /* This defines a selective acknowledgement block. */
 struct tcp_sack_block {
@@ -236,8 +219,8 @@ static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req)
 }
 
 struct tcp_sock {
-       /* inet_sock has to be the first member of tcp_sock */
-       struct inet_sock        inet;
+       /* inet_connection_sock has to be the first member of tcp_sock */
+       struct inet_connection_sock     inet_conn;
        int     tcp_header_len; /* Bytes of tcp header to send          */
 
 /*
@@ -258,19 +241,6 @@ struct tcp_sock {
        __u32   snd_sml;        /* Last byte of the most recently transmitted small packet */
        __u32   rcv_tstamp;     /* timestamp of last received ACK (for keepalives) */
        __u32   lsndtime;       /* timestamp of last sent data packet (for restart window) */
-       struct tcp_bind_bucket *bind_hash;
-       /* Delayed ACK control data */
-       struct {
-               __u8    pending;        /* ACK is pending */
-               __u8    quick;          /* Scheduled number of quick acks       */
-               __u8    pingpong;       /* The session is interactive           */
-               __u8    blocked;        /* Delayed ACK was blocked by socket lock*/
-               __u32   ato;            /* Predicted tick of soft clock         */
-               unsigned long timeout;  /* Currently scheduled timeout          */
-               __u32   lrcvtime;       /* timestamp of last received data packet*/
-               __u16   last_seg_size;  /* Size of last incoming segment        */
-               __u16   rcv_mss;        /* MSS used for delayed ACK decisions   */ 
-       } ack;
 
        /* Data for direct copy to user */
        struct {
@@ -288,19 +258,15 @@ struct tcp_sock {
        __u32   mss_cache;      /* Cached effective mss, not including SACKS */
        __u16   xmit_size_goal; /* Goal for segmenting output packets   */
        __u16   ext_header_len; /* Network protocol overhead (IP/IPv6 options) */
-       __u8    ca_state;       /* State of fast-retransmit machine     */
-       __u8    retransmits;    /* Number of unrecovered RTO timeouts.  */
 
-       __u16   advmss;         /* Advertised MSS                       */
        __u32   window_clamp;   /* Maximal window to advertise          */
        __u32   rcv_ssthresh;   /* Current window clamp                 */
 
        __u32   frto_highmark;  /* snd_nxt when RTO occurred */
        __u8    reordering;     /* Packet reordering metric.            */
        __u8    frto_counter;   /* Number of new acks after RTO */
-
-       __u8    unused;
-       __u8    defer_accept;   /* User waits for some data after accept() */
+       __u8    nonagle;        /* Disable Nagle algorithm?             */
+       __u8    keepalive_probes; /* num of allowed keep alive probes   */
 
 /* RTT measurement */
        __u32   srtt;           /* smoothed round trip time << 3        */
@@ -308,19 +274,13 @@ struct tcp_sock {
        __u32   mdev_max;       /* maximal mdev for the last rtt period */
        __u32   rttvar;         /* smoothed mdev_max                    */
        __u32   rtt_seq;        /* sequence number to update rttvar     */
-       __u32   rto;            /* retransmit timeout                   */
 
        __u32   packets_out;    /* Packets which are "in flight"        */
        __u32   left_out;       /* Packets which leaved network */
        __u32   retrans_out;    /* Retransmitted packets out            */
-       __u8    backoff;        /* backoff                              */
 /*
  *      Options received (usually on last packet, some only on SYN packets).
  */
-       __u8    nonagle;        /* Disable Nagle algorithm?             */
-       __u8    keepalive_probes; /* num of allowed keep alive probes   */
-
-       __u8    probes_out;     /* unanswered 0 window probes           */
        struct tcp_options_received rx_opt;
 
 /*
@@ -333,11 +293,6 @@ struct tcp_sock {
        __u32   snd_cwnd_used;
        __u32   snd_cwnd_stamp;
 
-       /* Two commonly used timers in both sender and receiver paths. */
-       unsigned long           timeout;
-       struct timer_list       retransmit_timer;       /* Resend (no ack)      */
-       struct timer_list       delack_timer;           /* Ack delay            */
-
        struct sk_buff_head     out_of_order_queue; /* Out of order segments go here */
 
        struct tcp_func         *af_specific;   /* Operations which are AF_INET{4,6} specific   */
@@ -352,8 +307,7 @@ struct tcp_sock {
        struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */
        struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/
 
-       __u8    syn_retries;    /* num of allowed syn retries */
-       __u8    ecn_flags;      /* ECN status bits.                     */
+       __u16   advmss;         /* Advertised MSS                       */
        __u16   prior_ssthresh; /* ssthresh saved at recovery start     */
        __u32   lost_out;       /* Lost packets                 */
        __u32   sacked_out;     /* SACK'd packets                       */
@@ -367,14 +321,12 @@ struct tcp_sock {
        int     undo_retrans;   /* number of undoable retransmissions. */
        __u32   urg_seq;        /* Seq of received urgent pointer */
        __u16   urg_data;       /* Saved octet of OOB data and control flags */
-       __u8    pending;        /* Scheduled timer event        */
        __u8    urg_mode;       /* In urgent mode               */
+       __u8    ecn_flags;      /* ECN status bits.                     */
        __u32   snd_up;         /* Urgent pointer               */
 
        __u32   total_retrans;  /* Total retransmits for entire connection */
 
-       struct request_sock_queue accept_queue; /* FIFO of established children */
-
        unsigned int            keepalive_time;   /* time before keep alive takes place */
        unsigned int            keepalive_intvl;  /* time interval between keep alive probes */
        int                     linger2;
@@ -394,11 +346,6 @@ struct tcp_sock {
                __u32   seq;
                __u32   time;
        } rcvq_space;
-
-       /* Pluggable TCP congestion control hook */
-       struct tcp_congestion_ops *ca_ops;
-       u32     ca_priv[16];
-#define TCP_CA_PRIV_SIZE       (16*sizeof(u32))
 };
 
 static inline struct tcp_sock *tcp_sk(const struct sock *sk)
@@ -406,9 +353,18 @@ static inline struct tcp_sock *tcp_sk(const struct sock *sk)
        return (struct tcp_sock *)sk;
 }
 
-static inline void *tcp_ca(const struct tcp_sock *tp)
+struct tcp_timewait_sock {
+       struct inet_timewait_sock tw_sk;
+       __u32                     tw_rcv_nxt;
+       __u32                     tw_snd_nxt;
+       __u32                     tw_rcv_wnd;
+       __u32                     tw_ts_recent;
+       long                      tw_ts_recent_stamp;
+};
+
+static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk)
 {
-       return (void *) tp->ca_priv;
+       return (struct tcp_timewait_sock *)sk;
 }
 
 #endif
diff --git a/include/linux/tcp_diag.h b/include/linux/tcp_diag.h
deleted file mode 100644 (file)
index 7a59967..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-#ifndef _TCP_DIAG_H_
-#define _TCP_DIAG_H_ 1
-
-/* Just some random number */
-#define TCPDIAG_GETSOCK 18
-
-/* Socket identity */
-struct tcpdiag_sockid
-{
-       __u16   tcpdiag_sport;
-       __u16   tcpdiag_dport;
-       __u32   tcpdiag_src[4];
-       __u32   tcpdiag_dst[4];
-       __u32   tcpdiag_if;
-       __u32   tcpdiag_cookie[2];
-#define TCPDIAG_NOCOOKIE (~0U)
-};
-
-/* Request structure */
-
-struct tcpdiagreq
-{
-       __u8    tcpdiag_family;         /* Family of addresses. */
-       __u8    tcpdiag_src_len;
-       __u8    tcpdiag_dst_len;
-       __u8    tcpdiag_ext;            /* Query extended information */
-
-       struct tcpdiag_sockid id;
-
-       __u32   tcpdiag_states;         /* States to dump */
-       __u32   tcpdiag_dbs;            /* Tables to dump (NI) */
-};
-
-enum
-{
-       TCPDIAG_REQ_NONE,
-       TCPDIAG_REQ_BYTECODE,
-};
-
-#define TCPDIAG_REQ_MAX TCPDIAG_REQ_BYTECODE
-
-/* Bytecode is sequence of 4 byte commands followed by variable arguments.
- * All the commands identified by "code" are conditional jumps forward:
- * to offset cc+"yes" or to offset cc+"no". "yes" is supposed to be
- * length of the command and its arguments.
- */
-struct tcpdiag_bc_op
-{
-       unsigned char   code;
-       unsigned char   yes;
-       unsigned short  no;
-};
-
-enum
-{
-       TCPDIAG_BC_NOP,
-       TCPDIAG_BC_JMP,
-       TCPDIAG_BC_S_GE,
-       TCPDIAG_BC_S_LE,
-       TCPDIAG_BC_D_GE,
-       TCPDIAG_BC_D_LE,
-       TCPDIAG_BC_AUTO,
-       TCPDIAG_BC_S_COND,
-       TCPDIAG_BC_D_COND,
-};
-
-struct tcpdiag_hostcond
-{
-       __u8    family;
-       __u8    prefix_len;
-       int     port;
-       __u32   addr[0];
-};
-
-/* Base info structure. It contains socket identity (addrs/ports/cookie)
- * and, alas, the information shown by netstat. */
-struct tcpdiagmsg
-{
-       __u8    tcpdiag_family;
-       __u8    tcpdiag_state;
-       __u8    tcpdiag_timer;
-       __u8    tcpdiag_retrans;
-
-       struct tcpdiag_sockid id;
-
-       __u32   tcpdiag_expires;
-       __u32   tcpdiag_rqueue;
-       __u32   tcpdiag_wqueue;
-       __u32   tcpdiag_uid;
-       __u32   tcpdiag_inode;
-};
-
-/* Extensions */
-
-enum
-{
-       TCPDIAG_NONE,
-       TCPDIAG_MEMINFO,
-       TCPDIAG_INFO,
-       TCPDIAG_VEGASINFO,
-       TCPDIAG_CONG,
-};
-
-#define TCPDIAG_MAX TCPDIAG_CONG
-
-
-/* TCPDIAG_MEM */
-
-struct tcpdiag_meminfo
-{
-       __u32   tcpdiag_rmem;
-       __u32   tcpdiag_wmem;
-       __u32   tcpdiag_fmem;
-       __u32   tcpdiag_tmem;
-};
-
-/* TCPDIAG_VEGASINFO */
-
-struct tcpvegas_info {
-       __u32   tcpv_enabled;
-       __u32   tcpv_rttcnt;
-       __u32   tcpv_rtt;
-       __u32   tcpv_minrtt;
-};
-
-#endif /* _TCP_DIAG_H_ */
index 5634497ff5dfd62a7e5327dd7a8fbd95cb467698..c10d4c21c18397cd3bfe66ea83d173d89a5d85b2 100644 (file)
@@ -97,7 +97,6 @@ extern int do_settimeofday(struct timespec *tv);
 extern int do_sys_settimeofday(struct timespec *tv, struct timezone *tz);
 extern void clock_was_set(void); // call when ever the clock is set
 extern int do_posix_clock_monotonic_gettime(struct timespec *tp);
-extern long do_nanosleep(struct timespec *t);
 extern long do_utimes(char __user * filename, struct timeval * times);
 struct itimerval;
 extern int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue);
index 74fdd07d3792a55cf970c9a1ad4942511976adf7..7e050a2cc35be69f2685309ff9c445adbba8ae68 100644 (file)
@@ -260,6 +260,29 @@ extern long pps_calcnt;            /* calibration intervals */
 extern long pps_errcnt;                /* calibration errors */
 extern long pps_stbcnt;                /* stability limit exceeded */
 
+/**
+ * ntp_clear - Clears the NTP state variables
+ *
+ * Must be called while holding a write on the xtime_lock
+ */
+static inline void ntp_clear(void)
+{
+       time_adjust = 0;                /* stop active adjtime() */
+       time_status |= STA_UNSYNC;
+       time_maxerror = NTP_PHASE_LIMIT;
+       time_esterror = NTP_PHASE_LIMIT;
+}
+
+/**
+ * ntp_synced - Returns 1 if the NTP status is not UNSYNC
+ *
+ */
+static inline int ntp_synced(void)
+{
+       return !(time_status & STA_UNSYNC);
+}
+
+
 #ifdef CONFIG_TIME_INTERPOLATION
 
 #define TIME_SOURCE_CPU 0
index 0320225e96da5b6b24bc5e3d5107fc55527e6aab..3df1d474e5c56dcd4ce2ca4d371ad86fc945368b 100644 (file)
 }
 #endif
 
+/* sched_domains SD_ALLNODES_INIT for NUMA machines */
+#define SD_ALLNODES_INIT (struct sched_domain) {       \
+       .span                   = CPU_MASK_NONE,        \
+       .parent                 = NULL,                 \
+       .groups                 = NULL,                 \
+       .min_interval           = 64,                   \
+       .max_interval           = 64*num_online_cpus(), \
+       .busy_factor            = 128,                  \
+       .imbalance_pct          = 133,                  \
+       .cache_hot_time         = (10*1000000),         \
+       .cache_nice_tries       = 1,                    \
+       .busy_idx               = 3,                    \
+       .idle_idx               = 3,                    \
+       .newidle_idx            = 0, /* unused */       \
+       .wake_idx               = 0, /* unused */       \
+       .forkexec_idx           = 0, /* unused */       \
+       .per_cpu_gain           = 100,                  \
+       .flags                  = SD_LOAD_BALANCE,      \
+       .last_balance           = jiffies,              \
+       .balance_interval       = 64,                   \
+       .nr_balance_failed      = 0,                    \
+}
+
 #ifdef CONFIG_NUMA
 #ifndef SD_NODE_INIT
 #error Please define an appropriate SD_NODE_INIT in include/asm/topology.h!!!
index dcb13f865df97ccee9a7764fa247fec754f0609a..2b678c22ca4a0dead6fac2672f76d365ed8945f6 100644 (file)
@@ -123,6 +123,9 @@ typedef             __u64           u_int64_t;
 typedef                __s64           int64_t;
 #endif
 
+/* this is a special 64bit data type that is 8-byte aligned */
+#define aligned_u64 unsigned long long __attribute__((aligned(8)))
+
 /*
  * The type used for indexing onto a disc or disc partition.
  * If required, asm/types.h can override it and define
index 6409d9cf59659d8377d140e205a4a6099e8b4277..b244f69ef682e2d4f8bd4d768584990bc64dff34 100644 (file)
 #define VM_MAP         0x00000004      /* vmap()ed pages */
 /* bits [20..32] reserved for arch specific ioremap internals */
 
+/*
+ * Maximum alignment for ioremap() regions.
+ * Can be overriden by arch-specific value.
+ */
+#ifndef IOREMAP_MAX_ORDER
+#define IOREMAP_MAX_ORDER      (7 + PAGE_SHIFT)        /* 128 pages */
+#endif
+
 struct vm_struct {
        void                    *addr;
        unsigned long           size;
index ae485f9c916edb224e4cc2c869ab6347bb7f7bfe..a555a0f7a7b4ec6d42015c60c4117c862c4d99e3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :   18      12.3.05
+ * Version :   19      18.3.05
  *
  * Authors :   Jean Tourrilhes - HPL - <jt@hpl.hp.com>
  * Copyright (c) 1997-2005 Jean Tourrilhes, All Rights Reserved.
@@ -69,8 +69,6 @@
 
 /***************************** INCLUDES *****************************/
 
-/* To minimise problems in user space, I might remove those headers
- * at some point. Jean II */
 #include <linux/types.h>               /* for "caddr_t" et al          */
 #include <linux/socket.h>              /* for "struct sockaddr" et al  */
 #include <linux/if.h>                  /* for IFNAMSIZ and co... */
@@ -82,7 +80,7 @@
  * (there is some stuff that will be added in the future...)
  * I just plan to increment with each new version.
  */
-#define WIRELESS_EXT   18
+#define WIRELESS_EXT   19
 
 /*
  * Changes :
  *       related parameters (extensible up to 4096 parameter values)
  *     - Add wireless events: IWEVGENIE, IWEVMICHAELMICFAILURE,
  *       IWEVASSOCREQIE, IWEVASSOCRESPIE, IWEVPMKIDCAND
+ *
+ * V18 to V19
+ * ----------
+ *     - Remove (struct iw_point *)->pointer from events and streams
+ *     - Remove header includes to help user space
+ *     - Increase IW_ENCODING_TOKEN_MAX from 32 to 64
+ *     - Add IW_QUAL_ALL_UPDATED and IW_QUAL_ALL_INVALID macros
+ *     - Add explicit flag to tell stats are in dBm : IW_QUAL_DBM
+ *     - Add IW_IOCTL_IDX() and IW_EVENT_IDX() macros
  */
 
 /**************************** CONSTANTS ****************************/
 /* The first and the last (range) */
 #define SIOCIWFIRST    0x8B00
 #define SIOCIWLAST     SIOCIWLASTPRIV          /* 0x8BFF */
+#define IW_IOCTL_IDX(cmd)      ((cmd) - SIOCIWFIRST)
 
 /* Even : get (world access), odd : set (root access) */
 #define IW_IS_SET(cmd) (!((cmd) & 0x1))
                                         * (struct iw_pmkid_cand) */
 
 #define IWEVFIRST      0x8C00
+#define IW_EVENT_IDX(cmd)      ((cmd) - IWEVFIRST)
 
 /* ------------------------- PRIVATE INFO ------------------------- */
 /*
 #define IW_MODE_MONITOR        6       /* Passive monitor (listen only) */
 
 /* Statistics flags (bitmask in updated) */
-#define IW_QUAL_QUAL_UPDATED   0x1     /* Value was updated since last read */
-#define IW_QUAL_LEVEL_UPDATED  0x2
-#define IW_QUAL_NOISE_UPDATED  0x4
+#define IW_QUAL_QUAL_UPDATED   0x01    /* Value was updated since last read */
+#define IW_QUAL_LEVEL_UPDATED  0x02
+#define IW_QUAL_NOISE_UPDATED  0x04
+#define IW_QUAL_ALL_UPDATED    0x07
+#define IW_QUAL_DBM            0x08    /* Level + Noise are dBm */
 #define IW_QUAL_QUAL_INVALID   0x10    /* Driver doesn't provide value */
 #define IW_QUAL_LEVEL_INVALID  0x20
 #define IW_QUAL_NOISE_INVALID  0x40
+#define IW_QUAL_ALL_INVALID    0x70
 
 /* Frequency flags */
 #define IW_FREQ_AUTO           0x00    /* Let the driver decides */
 #define IW_MAX_ENCODING_SIZES  8
 
 /* Maximum size of the encoding token in bytes */
-#define IW_ENCODING_TOKEN_MAX  32      /* 256 bits (for now) */
+#define IW_ENCODING_TOKEN_MAX  64      /* 512 bits (for now) */
 
 /* Flags for encoding (along with the token) */
 #define IW_ENCODE_INDEX                0x00FF  /* Token index (if needed) */
@@ -1039,12 +1051,16 @@ struct iw_event
 #define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ)
 #define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32))
 #define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq))
-#define IW_EV_POINT_LEN        (IW_EV_LCP_LEN + sizeof(struct iw_point))
 #define IW_EV_PARAM_LEN        (IW_EV_LCP_LEN + sizeof(struct iw_param))
 #define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr))
 #define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality))
 
-/* Note : in the case of iw_point, the extra data will come at the
- * end of the event */
+/* iw_point events are special. First, the payload (extra data) come at
+ * the end of the event, so they are bigger than IW_EV_POINT_LEN. Second,
+ * we omit the pointer, so start at an offset. */
+#define IW_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \
+                         (char *) NULL)
+#define IW_EV_POINT_LEN        (IW_EV_LCP_LEN + sizeof(struct iw_point) - \
+                        IW_EV_POINT_OFF)
 
 #endif /* _LINUX_WIRELESS_H */
index f0d423300d84aead0467e222d4d3d3961627abef..0fb077d68441f864281d8473dd9744c37d9d80df 100644 (file)
@@ -258,9 +258,27 @@ struct xfrm_usersa_flush {
        __u8                            proto;
 };
 
+#ifndef __KERNEL__
+/* backwards compatibility for userspace */
 #define XFRMGRP_ACQUIRE                1
 #define XFRMGRP_EXPIRE         2
 #define XFRMGRP_SA             4
 #define XFRMGRP_POLICY         8
+#endif
+
+enum xfrm_nlgroups {
+       XFRMNLGRP_NONE,
+#define XFRMNLGRP_NONE         XFRMNLGRP_NONE
+       XFRMNLGRP_ACQUIRE,
+#define XFRMNLGRP_ACQUIRE      XFRMNLGRP_ACQUIRE
+       XFRMNLGRP_EXPIRE,
+#define XFRMNLGRP_EXPIRE       XFRMNLGRP_EXPIRE
+       XFRMNLGRP_SA,
+#define XFRMNLGRP_SA           XFRMNLGRP_SA
+       XFRMNLGRP_POLICY,
+#define XFRMNLGRP_POLICY       XFRMNLGRP_POLICY
+       __XFRMNLGRP_MAX
+};
+#define XFRMNLGRP_MAX  (__XFRMNLGRP_MAX - 1)
 
 #endif /* _LINUX_XFRM_H */
index a39a6423914bc553f8b79e9139ba7221c0710380..801ddef301aa374e16008b29ab139f165fd3def3 100644 (file)
@@ -34,8 +34,3 @@
 #ifndef  I2C_DRIVERID_SAA6752HS
 # define I2C_DRIVERID_SAA6752HS I2C_DRIVERID_EXP0+8
 #endif
-
-/* algorithms */
-#ifndef I2C_ALGO_SAA7134
-# define I2C_ALGO_SAA7134 0x090000
-#endif
index ed00a995f576f1d612b526d75b0cb0cd1cb1dbf7..b55eb7c7f0339ce2893334da2ab674e994296d4d 100644 (file)
@@ -63,7 +63,7 @@ struct tc_action_ops
        __u32   type; /* TBD to match kind */
        __u32   capab;  /* capabilities includes 4 bit version */
        struct module           *owner;
-       int     (*act)(struct sk_buff **, struct tc_action *);
+       int     (*act)(struct sk_buff **, struct tc_action *, struct tcf_result *);
        int     (*get_stats)(struct sk_buff *, struct tc_action *);
        int     (*dump)(struct sk_buff *, struct tc_action *,int , int);
        int     (*cleanup)(struct tc_action *, int bind);
index a0ed9367217601cd1e1dbcb6266bf2e8d25f68cf..750e2508dd90627084e9757363f1d25832047d30 100644 (file)
@@ -45,6 +45,7 @@ struct prefix_info {
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
 #include <linux/netdevice.h>
 #include <net/if_inet6.h>
 #include <net/ipv6.h>
@@ -238,5 +239,10 @@ static inline int ipv6_addr_is_ll_all_routers(const struct in6_addr *addr)
                addr->s6_addr32[3] == htonl(0x00000002));
 }
 
+#ifdef CONFIG_PROC_FS
+extern int if6_proc_init(void);
+extern void if6_proc_exit(void);
+#endif
+
 #endif
 #endif
index b60b3846b9d165280d012f48d9d83e4017237ec6..b5d785ab4a0ea3cd41fe6ac2c82edcaf68274c0a 100644 (file)
@@ -1,5 +1,11 @@
 #ifndef __LINUX_NET_AFUNIX_H
 #define __LINUX_NET_AFUNIX_H
+
+#include <linux/config.h>
+#include <linux/socket.h>
+#include <linux/un.h>
+#include <net/sock.h>
+
 extern void unix_inflight(struct file *fp);
 extern void unix_notinflight(struct file *fp);
 extern void unix_gc(void);
@@ -74,5 +80,14 @@ struct unix_sock {
         wait_queue_head_t       peer_wait;
 };
 #define unix_sk(__sk) ((struct unix_sock *)__sk)
+
+#ifdef CONFIG_SYSCTL
+extern int sysctl_unix_max_dgram_qlen;
+extern void unix_sysctl_register(void);
+extern void unix_sysctl_unregister(void);
+#else
+static inline void unix_sysctl_register(void) {}
+static inline void unix_sysctl_unregister(void) {}
+#endif
 #endif
 #endif
index a1f09fad6a52e57070d6a27ade661339bfc449c6..a13e30c35f4259e7ba835e7eda73b38995246437 100644 (file)
@@ -11,7 +11,7 @@ extern struct neigh_table arp_tbl;
 
 extern void    arp_init(void);
 extern int     arp_rcv(struct sk_buff *skb, struct net_device *dev,
-                       struct packet_type *pt);
+                       struct packet_type *pt, struct net_device *orig_dev);
 extern int     arp_find(unsigned char *haddr, struct sk_buff *skb);
 extern int     arp_ioctl(unsigned int cmd, void __user *arg);
 extern void     arp_send(int type, int ptype, u32 dest_ip, 
index 3696f988a9f109710f8f947880eda11283fe449d..364b046e9f478b545316236d592bf29039c3fad2 100644 (file)
@@ -257,7 +257,7 @@ extern struct sock *ax25_make_new(struct sock *, struct ax25_dev *);
 
 /* ax25_addr.c */
 extern ax25_address null_ax25_address;
-extern char *ax2asc(ax25_address *);
+extern char *ax2asc(char *buf, ax25_address *);
 extern ax25_address *asc2ax(char *);
 extern int  ax25cmp(ax25_address *, ax25_address *);
 extern int  ax25digicmp(ax25_digi *, ax25_digi *);
@@ -316,7 +316,7 @@ extern int  ax25_protocol_is_registered(unsigned int);
 
 /* ax25_in.c */
 extern int  ax25_rx_iframe(ax25_cb *, struct sk_buff *);
-extern int  ax25_kiss_rcv(struct sk_buff *, struct net_device *, struct packet_type *);
+extern int  ax25_kiss_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
 
 /* ax25_ip.c */
 extern int  ax25_encapsulate(struct sk_buff *, struct net_device *, unsigned short, void *, void *, unsigned int);
index 06b24f637026c0ded9964d5cce77a2d1c7651001..6dfa4a61ffd04cbb59ff572bc001c0072fd8e5c6 100644 (file)
@@ -131,11 +131,12 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
 
 /* Skb helpers */
 struct bt_skb_cb {
-       int incoming;
+       __u8 pkt_type;
+       __u8 incoming;
 };
 #define bt_cb(skb) ((struct bt_skb_cb *)(skb->cb)) 
 
-static inline struct sk_buff *bt_skb_alloc(unsigned int len, int how)
+static inline struct sk_buff *bt_skb_alloc(unsigned int len, unsigned int __nocast how)
 {
        struct sk_buff *skb;
 
index 6f0706f4af68178db7852aa15c728822aefa4a80..371e7d3f2e6fe9574b5ef3418685f156fd879061 100644 (file)
@@ -453,6 +453,15 @@ struct inquiry_info_with_rssi {
        __u16    clock_offset;
        __s8     rssi;
 } __attribute__ ((packed));
+struct inquiry_info_with_rssi_and_pscan_mode {
+       bdaddr_t bdaddr;
+       __u8     pscan_rep_mode;
+       __u8     pscan_period_mode;
+       __u8     pscan_mode;
+       __u8     dev_class[3];
+       __u16    clock_offset;
+       __s8     rssi;
+} __attribute__ ((packed));
 
 #define HCI_EV_CONN_COMPLETE   0x03
 struct hci_ev_conn_complete {
@@ -584,6 +593,12 @@ struct hci_ev_clock_offset {
        __u16    clock_offset;
 } __attribute__ ((packed));
 
+#define HCI_EV_PSCAN_REP_MODE  0x20
+struct hci_ev_pscan_rep_mode {
+       bdaddr_t bdaddr;
+       __u8     pscan_rep_mode;
+} __attribute__ ((packed));
+
 /* Internal events generated by Bluetooth stack */
 #define HCI_EV_STACK_INTERNAL  0xFD
 struct hci_ev_stack_internal {
index 6d63a47c731bc5bec4ed1f444ebe3b59fc5eda73..7f933f30207830333996a9d872acbbef536e636d 100644 (file)
@@ -404,7 +404,7 @@ static inline int hci_recv_frame(struct sk_buff *skb)
        bt_cb(skb)->incoming = 1;
 
        /* Time stamp */
-       do_gettimeofday(&skb->stamp);
+       __net_timestamp(skb);
 
        /* Queue frame for rx task */
        skb_queue_tail(&hdev->rx_q, skb);
index 13669bad00b3737cf260f6a65c872894af3adb27..ffea9d54071f7eb65a4cb4ae089799ed4ceeedb4 100644 (file)
@@ -80,9 +80,9 @@
 #define RFCOMM_RPN_STOP_15     1
 
 #define RFCOMM_RPN_PARITY_NONE 0x0
-#define RFCOMM_RPN_PARITY_ODD  0x4
-#define RFCOMM_RPN_PARITY_EVEN 0x5
-#define RFCOMM_RPN_PARITY_MARK 0x6
+#define RFCOMM_RPN_PARITY_ODD  0x1
+#define RFCOMM_RPN_PARITY_EVEN 0x3
+#define RFCOMM_RPN_PARITY_MARK 0x5
 #define RFCOMM_RPN_PARITY_SPACE        0x7
 
 #define RFCOMM_RPN_FLOW_NONE   0x00
@@ -223,8 +223,14 @@ struct rfcomm_dlc {
 #define RFCOMM_CFC_DISABLED 0
 #define RFCOMM_CFC_ENABLED  RFCOMM_MAX_CREDITS
 
+/* ---- RFCOMM SEND RPN ---- */
+int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
+                       u8 bit_rate, u8 data_bits, u8 stop_bits,
+                       u8 parity, u8 flow_ctrl_settings, 
+                       u8 xon_char, u8 xoff_char, u16 param_mask);
+
 /* ---- RFCOMM DLCs (channels) ---- */
-struct rfcomm_dlc *rfcomm_dlc_alloc(int prio);
+struct rfcomm_dlc *rfcomm_dlc_alloc(unsigned int __nocast prio);
 void rfcomm_dlc_free(struct rfcomm_dlc *d);
 int  rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel);
 int  rfcomm_dlc_close(struct rfcomm_dlc *d, int reason);
index 5797ba3d2eb5dbf0b5b8559282669dd57912e84e..deb7ca75db488f94b0c697cbdfa1946c3263b63b 100644 (file)
@@ -9,7 +9,7 @@ struct datalink_proto {
         unsigned short  header_length;
 
         int     (*rcvfunc)(struct sk_buff *, struct net_device *,
-                                struct packet_type *);
+                                struct packet_type *, struct net_device *);
        int     (*request)(struct datalink_proto *, struct sk_buff *,
                                         unsigned char *);
        struct list_head node;
index 5551c46db397ecd9eef41d2954db60de42fd7239..c1dbbd22279394863d3d7cb7d8b7ed948e8bcfa7 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/dn.h>
 #include <net/sock.h>
+#include <net/tcp.h>
 #include <asm/byteorder.h>
 
 typedef unsigned short dn_address;
index e5ef0d15fb45e8e7130c53ecdeb5c0f3279a7492..6cdebeee5f961318bc5c8e942b1a2f92e4b276ce 100644 (file)
@@ -57,4 +57,11 @@ static inline struct raw_sock *raw_sk(const struct sock *sk)
        return (struct raw_sock *)sk;
 }
 
+extern int sysctl_icmp_echo_ignore_all;
+extern int sysctl_icmp_echo_ignore_broadcasts;
+extern int sysctl_icmp_ignore_bogus_error_responses;
+extern int sysctl_icmp_errors_use_inbound_ifaddr;
+extern int sysctl_icmp_ratelimit;
+extern int sysctl_icmp_ratemask;
+
 #endif /* _ICMP_H */
index db09580ad14b8031ee17cce1e38272453817b877..dc36b1be6745ac7c8b2e8e28810b9b99bc49de66 100644 (file)
  */
 #ifndef IEEE80211_H
 #define IEEE80211_H
-
 #include <linux/if_ether.h> /* ETH_ALEN */
 #include <linux/kernel.h>   /* ARRAY_SIZE */
-
-#if WIRELESS_EXT < 17
-#define IW_QUAL_QUAL_INVALID   0x10
-#define IW_QUAL_LEVEL_INVALID  0x20
-#define IW_QUAL_NOISE_INVALID  0x40
-#define IW_QUAL_QUAL_UPDATED   0x1
-#define IW_QUAL_LEVEL_UPDATED  0x2
-#define IW_QUAL_NOISE_UPDATED  0x4
-#endif
+#include <linux/wireless.h>
 
 #define IEEE80211_DATA_LEN             2304
 /* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
 #define IEEE80211_FRAME_LEN            (IEEE80211_DATA_LEN + IEEE80211_HLEN)
 
 struct ieee80211_hdr {
-       u16 frame_ctl;
-       u16 duration_id;
+       __le16 frame_ctl;
+       __le16 duration_id;
        u8 addr1[ETH_ALEN];
        u8 addr2[ETH_ALEN];
        u8 addr3[ETH_ALEN];
-       u16 seq_ctl;
+       __le16 seq_ctl;
        u8 addr4[ETH_ALEN];
 } __attribute__ ((packed));
 
 struct ieee80211_hdr_3addr {
-       u16 frame_ctl;
-       u16 duration_id;
+       __le16 frame_ctl;
+       __le16 duration_id;
        u8 addr1[ETH_ALEN];
        u8 addr2[ETH_ALEN];
        u8 addr3[ETH_ALEN];
-       u16 seq_ctl;
-} __attribute__ ((packed));
-
-enum eap_type {
-       EAP_PACKET = 0,
-       EAPOL_START,
-       EAPOL_LOGOFF,
-       EAPOL_KEY,
-       EAPOL_ENCAP_ASF_ALERT
-};
-
-static const char *eap_types[] = {
-       [EAP_PACKET]            = "EAP-Packet",
-       [EAPOL_START]           = "EAPOL-Start",
-       [EAPOL_LOGOFF]          = "EAPOL-Logoff",
-       [EAPOL_KEY]             = "EAPOL-Key",
-       [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert"
-};
-
-static inline const char *eap_get_type(int type)
-{
-       return (type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type];
-}
-
-struct eapol {
-       u8 snap[6];
-       u16 ethertype;
-       u8 version;
-       u8 type;
-       u16 length;
+       __le16 seq_ctl;
 } __attribute__ ((packed));
 
 #define IEEE80211_1ADDR_LEN 10
@@ -104,7 +66,7 @@ struct eapol {
 #define        MAX_FRAG_THRESHOLD     2346U
 
 /* Frame control field constants */
-#define IEEE80211_FCTL_VERS            0x0002
+#define IEEE80211_FCTL_VERS            0x0003
 #define IEEE80211_FCTL_FTYPE           0x000c
 #define IEEE80211_FCTL_STYPE           0x00f0
 #define IEEE80211_FCTL_TODS            0x0100
@@ -112,8 +74,8 @@ struct eapol {
 #define IEEE80211_FCTL_MOREFRAGS       0x0400
 #define IEEE80211_FCTL_RETRY           0x0800
 #define IEEE80211_FCTL_PM              0x1000
-#define IEEE80211_FCTL_MOREDATA        0x2000
-#define IEEE80211_FCTL_WEP             0x4000
+#define IEEE80211_FCTL_MOREDATA                0x2000
+#define IEEE80211_FCTL_PROTECTED       0x4000
 #define IEEE80211_FCTL_ORDER           0x8000
 
 #define IEEE80211_FTYPE_MGMT           0x0000
@@ -132,6 +94,7 @@ struct eapol {
 #define IEEE80211_STYPE_DISASSOC       0x00A0
 #define IEEE80211_STYPE_AUTH           0x00B0
 #define IEEE80211_STYPE_DEAUTH         0x00C0
+#define IEEE80211_STYPE_ACTION         0x00D0
 
 /* control */
 #define IEEE80211_STYPE_PSPOLL         0x00A0
@@ -167,8 +130,19 @@ do { if (ieee80211_debug_level & (level)) \
 #define IEEE80211_DEBUG(level, fmt, args...) do {} while (0)
 #endif /* CONFIG_IEEE80211_DEBUG */
 
+
+/* debug macros not dependent on CONFIG_IEEE80211_DEBUG */
+
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
+
+/* escape_essid() is intended to be used in debug (and possibly error)
+ * messages. It should never be used for passing essid to user space. */
+const char *escape_essid(const char *essid, u8 essid_len);
+
+
 /*
- * To use the debug system;
+ * To use the debug system:
  *
  * If you are defining a new debug classification, simply add it to the #define
  * list here in the form of:
@@ -184,11 +158,11 @@ do { if (ieee80211_debug_level & (level)) \
  *
  * To add your debug level to the list of levels seen when you perform
  *
- * % cat /proc/net/ipw/debug_level
+ * % cat /proc/net/ieee80211/debug_level
  *
- * you simply need to add your entry to the ipw_debug_levels array.
+ * you simply need to add your entry to the ieee80211_debug_level array.
  *
- * If you do not see debug_level in /proc/net/ipw then you do not have
+ * If you do not see debug_level in /proc/net/ieee80211 then you do not have
  * CONFIG_IEEE80211_DEBUG defined in your kernel configuration
  *
  */
@@ -199,7 +173,6 @@ do { if (ieee80211_debug_level & (level)) \
 #define IEEE80211_DL_STATE         (1<<3)
 #define IEEE80211_DL_MGMT          (1<<4)
 #define IEEE80211_DL_FRAG          (1<<5)
-#define IEEE80211_DL_EAP           (1<<6)
 #define IEEE80211_DL_DROP          (1<<7)
 
 #define IEEE80211_DL_TX            (1<<8)
@@ -214,7 +187,6 @@ do { if (ieee80211_debug_level & (level)) \
 #define IEEE80211_DEBUG_STATE(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a)
 #define IEEE80211_DEBUG_MGMT(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a)
 #define IEEE80211_DEBUG_FRAG(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a)
-#define IEEE80211_DEBUG_EAP(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a)
 #define IEEE80211_DEBUG_DROP(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a)
 #define IEEE80211_DEBUG_TX(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a)
 #define IEEE80211_DEBUG_RX(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a)
@@ -223,9 +195,9 @@ do { if (ieee80211_debug_level & (level)) \
 #include <linux/if_arp.h> /* ARPHRD_ETHER */
 
 #ifndef WIRELESS_SPY
-#define WIRELESS_SPY           // enable iwspy support
+#define WIRELESS_SPY           /* enable iwspy support */
 #endif
-#include <net/iw_handler.h>    // new driver API
+#include <net/iw_handler.h>    /* new driver API */
 
 #ifndef ETH_P_PAE
 #define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
@@ -252,6 +224,7 @@ struct ieee80211_snap_hdr {
 
 #define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
 
+#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS)
 #define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
 #define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
 
@@ -264,7 +237,7 @@ struct ieee80211_snap_hdr {
 
 #define WLAN_AUTH_CHALLENGE_LEN 128
 
-#define WLAN_CAPABILITY_BSS (1<<0)
+#define WLAN_CAPABILITY_ESS (1<<0)
 #define WLAN_CAPABILITY_IBSS (1<<1)
 #define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
 #define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
@@ -272,34 +245,72 @@ struct ieee80211_snap_hdr {
 #define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
 #define WLAN_CAPABILITY_PBCC (1<<6)
 #define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
+#define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8)
+#define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
+#define WLAN_CAPABILITY_OSSS_OFDM (1<<13)
 
 /* Status codes */
-#define WLAN_STATUS_SUCCESS 0
-#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
-#define WLAN_STATUS_CAPS_UNSUPPORTED 10
-#define WLAN_STATUS_REASSOC_NO_ASSOC 11
-#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
-#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
-#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
-#define WLAN_STATUS_CHALLENGE_FAIL 15
-#define WLAN_STATUS_AUTH_TIMEOUT 16
-#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
-#define WLAN_STATUS_ASSOC_DENIED_RATES 18
-/* 802.11b */
-#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
-#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
-#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
+enum ieee80211_statuscode {
+       WLAN_STATUS_SUCCESS = 0,
+       WLAN_STATUS_UNSPECIFIED_FAILURE = 1,
+       WLAN_STATUS_CAPS_UNSUPPORTED = 10,
+       WLAN_STATUS_REASSOC_NO_ASSOC = 11,
+       WLAN_STATUS_ASSOC_DENIED_UNSPEC = 12,
+       WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG = 13,
+       WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION = 14,
+       WLAN_STATUS_CHALLENGE_FAIL = 15,
+       WLAN_STATUS_AUTH_TIMEOUT = 16,
+       WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17,
+       WLAN_STATUS_ASSOC_DENIED_RATES = 18,
+       /* 802.11b */
+       WLAN_STATUS_ASSOC_DENIED_NOSHORTPREAMBLE = 19,
+       WLAN_STATUS_ASSOC_DENIED_NOPBCC = 20,
+       WLAN_STATUS_ASSOC_DENIED_NOAGILITY = 21,
+       /* 802.11h */
+       WLAN_STATUS_ASSOC_DENIED_NOSPECTRUM = 22,
+       WLAN_STATUS_ASSOC_REJECTED_BAD_POWER = 23,
+       WLAN_STATUS_ASSOC_REJECTED_BAD_SUPP_CHAN = 24,
+       /* 802.11g */
+       WLAN_STATUS_ASSOC_DENIED_NOSHORTTIME = 25,
+       WLAN_STATUS_ASSOC_DENIED_NODSSSOFDM = 26,
+       /* 802.11i */
+       WLAN_STATUS_INVALID_IE = 40,
+       WLAN_STATUS_INVALID_GROUP_CIPHER = 41,
+       WLAN_STATUS_INVALID_PAIRWISE_CIPHER = 42,
+       WLAN_STATUS_INVALID_AKMP = 43,
+       WLAN_STATUS_UNSUPP_RSN_VERSION = 44,
+       WLAN_STATUS_INVALID_RSN_IE_CAP = 45,
+       WLAN_STATUS_CIPHER_SUITE_REJECTED = 46,
+};
 
 /* Reason codes */
-#define WLAN_REASON_UNSPECIFIED 1
-#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
-#define WLAN_REASON_DEAUTH_LEAVING 3
-#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
-#define WLAN_REASON_DISASSOC_AP_BUSY 5
-#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
-#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
-#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
-#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
+enum ieee80211_reasoncode {
+       WLAN_REASON_UNSPECIFIED = 1,
+       WLAN_REASON_PREV_AUTH_NOT_VALID = 2,
+       WLAN_REASON_DEAUTH_LEAVING = 3,
+       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY = 4,
+       WLAN_REASON_DISASSOC_AP_BUSY = 5,
+       WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA = 6,
+       WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA = 7,
+       WLAN_REASON_DISASSOC_STA_HAS_LEFT = 8,
+       WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH = 9,
+       /* 802.11h */
+       WLAN_REASON_DISASSOC_BAD_POWER = 10,
+       WLAN_REASON_DISASSOC_BAD_SUPP_CHAN = 11,
+       /* 802.11i */
+       WLAN_REASON_INVALID_IE = 13,
+       WLAN_REASON_MIC_FAILURE = 14,
+       WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT = 15,
+       WLAN_REASON_GROUP_KEY_HANDSHAKE_TIMEOUT = 16,
+       WLAN_REASON_IE_DIFFERENT = 17,
+       WLAN_REASON_INVALID_GROUP_CIPHER = 18,
+       WLAN_REASON_INVALID_PAIRWISE_CIPHER = 19,
+       WLAN_REASON_INVALID_AKMP = 20,
+       WLAN_REASON_UNSUPP_RSN_VERSION = 21,
+       WLAN_REASON_INVALID_RSN_IE_CAP = 22,
+       WLAN_REASON_IEEE8021X_FAILED = 23,
+       WLAN_REASON_CIPHER_SUITE_REJECTED = 24,
+};
 
 
 #define IEEE80211_STATMASK_SIGNAL (1<<0)
@@ -426,9 +437,7 @@ struct ieee80211_stats {
 
 struct ieee80211_device;
 
-#if 0 /* for later */
 #include "ieee80211_crypt.h"
-#endif
 
 #define SEC_KEY_1         (1<<0)
 #define SEC_KEY_2         (1<<1)
@@ -480,17 +489,34 @@ Total: 28-2340 bytes
 #define BEACON_PROBE_SSID_ID_POSITION 12
 
 /* Management Frame Information Element Types */
-#define MFIE_TYPE_SSID       0
-#define MFIE_TYPE_RATES      1
-#define MFIE_TYPE_FH_SET     2
-#define MFIE_TYPE_DS_SET     3
-#define MFIE_TYPE_CF_SET     4
-#define MFIE_TYPE_TIM        5
-#define MFIE_TYPE_IBSS_SET   6
-#define MFIE_TYPE_CHALLENGE  16
-#define MFIE_TYPE_RSN       48
-#define MFIE_TYPE_RATES_EX   50
-#define MFIE_TYPE_GENERIC    221
+enum ieee80211_mfie {
+       MFIE_TYPE_SSID = 0,
+       MFIE_TYPE_RATES = 1,
+       MFIE_TYPE_FH_SET = 2,
+       MFIE_TYPE_DS_SET = 3,
+       MFIE_TYPE_CF_SET =  4,
+       MFIE_TYPE_TIM = 5,
+       MFIE_TYPE_IBSS_SET = 6,
+       MFIE_TYPE_COUNTRY = 7,
+       MFIE_TYPE_HOP_PARAMS = 8,
+       MFIE_TYPE_HOP_TABLE = 9,
+       MFIE_TYPE_REQUEST = 10,
+       MFIE_TYPE_CHALLENGE = 16,
+       MFIE_TYPE_POWER_CONSTRAINT = 32,
+       MFIE_TYPE_POWER_CAPABILITY = 33,
+       MFIE_TYPE_TPC_REQUEST = 34,
+       MFIE_TYPE_TPC_REPORT = 35,
+       MFIE_TYPE_SUPP_CHANNELS = 36,
+       MFIE_TYPE_CSA = 37,
+       MFIE_TYPE_MEASURE_REQUEST = 38,
+       MFIE_TYPE_MEASURE_REPORT = 39,
+       MFIE_TYPE_QUIET = 40,
+       MFIE_TYPE_IBSS_DFS = 41,
+       MFIE_TYPE_ERP_INFO = 42,
+       MFIE_TYPE_RSN = 48,
+       MFIE_TYPE_RATES_EX = 50,
+       MFIE_TYPE_GENERIC = 221,
+};
 
 struct ieee80211_info_element_hdr {
        u8 id;
@@ -522,9 +548,9 @@ struct ieee80211_info_element {
 
 struct ieee80211_authentication {
        struct ieee80211_hdr_3addr header;
-       u16 algorithm;
-       u16 transaction;
-       u16 status;
+       __le16 algorithm;
+       __le16 transaction;
+       __le16 status;
        struct ieee80211_info_element info_element;
 } __attribute__ ((packed));
 
@@ -532,23 +558,23 @@ struct ieee80211_authentication {
 struct ieee80211_probe_response {
        struct ieee80211_hdr_3addr header;
        u32 time_stamp[2];
-       u16 beacon_interval;
-       u16 capability;
+       __le16 beacon_interval;
+       __le16 capability;
        struct ieee80211_info_element info_element;
 } __attribute__ ((packed));
 
 struct ieee80211_assoc_request_frame {
-       u16 capability;
-       u16 listen_interval;
+       __le16 capability;
+       __le16 listen_interval;
        u8 current_ap[ETH_ALEN];
        struct ieee80211_info_element info_element;
 } __attribute__ ((packed));
 
 struct ieee80211_assoc_response_frame {
        struct ieee80211_hdr_3addr header;
-       u16 capability;
-       u16 status;
-       u16 aid;
+       __le16 capability;
+       __le16 status;
+       __le16 aid;
        struct ieee80211_info_element info_element; /* supported rates */
 } __attribute__ ((packed));
 
@@ -563,7 +589,7 @@ struct ieee80211_txb {
 };
 
 
-/* SWEEP TABLE ENTRIES NUMBER*/
+/* SWEEP TABLE ENTRIES NUMBER */
 #define MAX_SWEEP_TAB_ENTRIES            42
 #define MAX_SWEEP_TAB_ENTRIES_PER_PACKET  7
 /* MAX_RATES_LENGTH needs to be 12.  The spec says 8, and many APs
@@ -624,8 +650,6 @@ enum ieee80211_state {
 
 #define DEFAULT_MAX_SCAN_AGE (15 * HZ)
 #define DEFAULT_FTS 2346
-#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
-#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
 
 
 #define CFG_IEEE80211_RESERVE_FCS (1<<0)
@@ -793,8 +817,6 @@ extern struct net_device *alloc_ieee80211(int sizeof_priv);
 extern int ieee80211_set_encryption(struct ieee80211_device *ieee);
 
 /* ieee80211_tx.c */
-
-
 extern int ieee80211_xmit(struct sk_buff *skb,
                          struct net_device *dev);
 extern void ieee80211_txb_free(struct ieee80211_txb *);
@@ -807,7 +829,7 @@ extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
                             struct ieee80211_hdr *header,
                             struct ieee80211_rx_stats *stats);
 
-/* iee80211_wx.c */
+/* ieee80211_wx.c */
 extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
                                 struct iw_request_info *info,
                                 union iwreq_data *wrqu, char *key);
@@ -829,28 +851,5 @@ extern inline int ieee80211_get_scans(struct ieee80211_device *ieee)
        return ieee->scans;
 }
 
-static inline const char *escape_essid(const char *essid, u8 essid_len) {
-       static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
-       const char *s = essid;
-       char *d = escaped;
-
-       if (ieee80211_is_empty_essid(essid, essid_len)) {
-               memcpy(escaped, "<hidden>", sizeof("<hidden>"));
-               return escaped;
-       }
-
-       essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE);
-       while (essid_len--) {
-               if (*s == '\0') {
-                       *d++ = '\\';
-                       *d++ = '0';
-                       s++;
-               } else {
-                       *d++ = *s++;
-               }
-       }
-       *d = '\0';
-       return escaped;
-}
 
 #endif /* IEEE80211_H */
diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h
new file mode 100644 (file)
index 0000000..b58a3bc
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Original code based on Host AP (software wireless LAN access point) driver
+ * for Intersil Prism2/2.5/3.
+ *
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * Adaption to a generic IEEE 802.11 stack by James Ketrenos
+ * <jketreno@linux.intel.com>
+ *
+ * Copyright (c) 2004, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. See README and COPYING for
+ * more details.
+ */
+
+/*
+ * This file defines the interface to the ieee80211 crypto module.
+ */
+#ifndef IEEE80211_CRYPT_H
+#define IEEE80211_CRYPT_H
+
+#include <linux/skbuff.h>
+
+struct ieee80211_crypto_ops {
+       const char *name;
+
+       /* init new crypto context (e.g., allocate private data space,
+        * select IV, etc.); returns NULL on failure or pointer to allocated
+        * private data on success */
+       void * (*init)(int keyidx);
+
+       /* deinitialize crypto context and free allocated private data */
+       void (*deinit)(void *priv);
+
+       /* encrypt/decrypt return < 0 on error or >= 0 on success. The return
+        * value from decrypt_mpdu is passed as the keyidx value for
+        * decrypt_msdu. skb must have enough head and tail room for the
+        * encryption; if not, error will be returned; these functions are
+        * called for all MPDUs (i.e., fragments).
+        */
+       int (*encrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv);
+       int (*decrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv);
+
+       /* These functions are called for full MSDUs, i.e. full frames.
+        * These can be NULL if full MSDU operations are not needed. */
+       int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv);
+       int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len,
+                           void *priv);
+
+       int (*set_key)(void *key, int len, u8 *seq, void *priv);
+       int (*get_key)(void *key, int len, u8 *seq, void *priv);
+
+       /* procfs handler for printing out key information and possible
+        * statistics */
+       char * (*print_stats)(char *p, void *priv);
+
+       /* maximum number of bytes added by encryption; encrypt buf is
+        * allocated with extra_prefix_len bytes, copy of in_buf, and
+        * extra_postfix_len; encrypt need not use all this space, but
+        * the result must start at the beginning of the buffer and correct
+        * length must be returned */
+       int extra_prefix_len, extra_postfix_len;
+
+       struct module *owner;
+};
+
+struct ieee80211_crypt_data {
+       struct list_head list; /* delayed deletion list */
+       struct ieee80211_crypto_ops *ops;
+       void *priv;
+       atomic_t refcnt;
+};
+
+int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops);
+int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops);
+struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name);
+void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int);
+void ieee80211_crypt_deinit_handler(unsigned long);
+void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
+                                   struct ieee80211_crypt_data **crypt);
+
+#endif
diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h
new file mode 100644 (file)
index 0000000..03df3b1
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ * Authors:    Lotsa people, from code originally in tcp
+ *
+ *     This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _INET6_HASHTABLES_H
+#define _INET6_HASHTABLES_H
+
+#include <linux/config.h>
+
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+#include <linux/in6.h>
+#include <linux/ipv6.h>
+#include <linux/types.h>
+
+#include <net/ipv6.h>
+
+struct inet_hashinfo;
+
+/* I have no idea if this is a good hash for v6 or not. -DaveM */
+static inline int inet6_ehashfn(const struct in6_addr *laddr, const u16 lport,
+                               const struct in6_addr *faddr, const u16 fport,
+                               const int ehash_size)
+{
+       int hashent = (lport ^ fport);
+
+       hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]);
+       hashent ^= hashent >> 16;
+       hashent ^= hashent >> 8;
+       return (hashent & (ehash_size - 1));
+}
+
+static inline int inet6_sk_ehashfn(const struct sock *sk, const int ehash_size)
+{
+       const struct inet_sock *inet = inet_sk(sk);
+       const struct ipv6_pinfo *np = inet6_sk(sk);
+       const struct in6_addr *laddr = &np->rcv_saddr;
+       const struct in6_addr *faddr = &np->daddr;
+       const __u16 lport = inet->num;
+       const __u16 fport = inet->dport;
+       return inet6_ehashfn(laddr, lport, faddr, fport, ehash_size);
+}
+
+/*
+ * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
+ * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
+ *
+ * The sockhash lock must be held as a reader here.
+ */
+static inline struct sock *
+               __inet6_lookup_established(struct inet_hashinfo *hashinfo,
+                                          const struct in6_addr *saddr,
+                                          const u16 sport,
+                                          const struct in6_addr *daddr,
+                                          const u16 hnum,
+                                          const int dif)
+{
+       struct sock *sk;
+       const struct hlist_node *node;
+       const __u32 ports = INET_COMBINED_PORTS(sport, hnum);
+       /* Optimize here for direct hit, only listening connections can
+        * have wildcards anyways.
+        */
+       const int hash = inet6_ehashfn(daddr, hnum, saddr, sport,
+                                      hashinfo->ehash_size);
+       struct inet_ehash_bucket *head = &hashinfo->ehash[hash];
+
+       read_lock(&head->lock);
+       sk_for_each(sk, node, &head->chain) {
+               /* For IPV6 do the cheaper port and family tests first. */
+               if (INET6_MATCH(sk, saddr, daddr, ports, dif))
+                       goto hit; /* You sunk my battleship! */
+       }
+       /* Must check for a TIME_WAIT'er before going to listener hash. */
+       sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) {
+               const struct inet_timewait_sock *tw = inet_twsk(sk);
+
+               if(*((__u32 *)&(tw->tw_dport))  == ports        &&
+                  sk->sk_family                == PF_INET6) {
+                       const struct tcp6_timewait_sock *tcp6tw = tcp6_twsk(sk);
+
+                       if (ipv6_addr_equal(&tcp6tw->tw_v6_daddr, saddr)        &&
+                           ipv6_addr_equal(&tcp6tw->tw_v6_rcv_saddr, daddr)    &&
+                           (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dif))
+                               goto hit;
+               }
+       }
+       read_unlock(&head->lock);
+       return NULL;
+
+hit:
+       sock_hold(sk);
+       read_unlock(&head->lock);
+       return sk;
+}
+
+extern struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
+                                         const struct in6_addr *daddr,
+                                         const unsigned short hnum,
+                                         const int dif);
+
+static inline struct sock *__inet6_lookup(struct inet_hashinfo *hashinfo,
+                                         const struct in6_addr *saddr,
+                                         const u16 sport,
+                                         const struct in6_addr *daddr,
+                                         const u16 hnum,
+                                         const int dif)
+{
+       struct sock *sk = __inet6_lookup_established(hashinfo, saddr, sport,
+                                                    daddr, hnum, dif);
+       if (sk)
+               return sk;
+
+       return inet6_lookup_listener(hashinfo, daddr, hnum, dif);
+}
+
+extern struct sock *inet6_lookup(struct inet_hashinfo *hashinfo,
+                                const struct in6_addr *saddr, const u16 sport,
+                                const struct in6_addr *daddr, const u16 dport,
+                                const int dif);
+#endif /* defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) */
+#endif /* _INET6_HASHTABLES_H */
index fbc1f4d140d82c1d7fe05092a8e12296ccff7284..f943306ce5ff3104092f604ed4d23c5c93de9855 100644 (file)
@@ -8,6 +8,11 @@ extern struct proto_ops                inet_dgram_ops;
  *     INET4 prototypes used by INET6
  */
 
+struct msghdr;
+struct sock;
+struct sockaddr;
+struct socket;
+
 extern void                    inet_remove_sock(struct sock *sk1);
 extern void                    inet_put_sock(unsigned short num, 
                                              struct sock *sk);
@@ -29,7 +34,6 @@ extern unsigned int           inet_poll(struct file * file, struct socket *sock, struct p
 extern int                     inet_listen(struct socket *sock, int backlog);
 
 extern void                    inet_sock_destruct(struct sock *sk);
-extern atomic_t                        inet_sock_nr;
 
 extern int                     inet_bind(struct socket *sock, 
                                          struct sockaddr *uaddr, int addr_len);
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
new file mode 100644 (file)
index 0000000..651f824
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * NET         Generic infrastructure for INET connection oriented protocols.
+ *
+ *             Definitions for inet_connection_sock 
+ *
+ * Authors:    Many people, see the TCP sources
+ *
+ *             From code originally in TCP
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ */
+#ifndef _INET_CONNECTION_SOCK_H
+#define _INET_CONNECTION_SOCK_H
+
+#include <linux/ip.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <net/request_sock.h>
+
+#define INET_CSK_DEBUG 1
+
+/* Cancel timers, when they are not required. */
+#undef INET_CSK_CLEAR_TIMERS
+
+struct inet_bind_bucket;
+struct inet_hashinfo;
+struct tcp_congestion_ops;
+
+/** inet_connection_sock - INET connection oriented sock
+ *
+ * @icsk_accept_queue:    FIFO of established children 
+ * @icsk_bind_hash:       Bind node
+ * @icsk_timeout:         Timeout
+ * @icsk_retransmit_timer: Resend (no ack)
+ * @icsk_rto:             Retransmit timeout
+ * @icsk_ca_ops                   Pluggable congestion control hook
+ * @icsk_ca_state:        Congestion control state
+ * @icsk_retransmits:     Number of unrecovered [RTO] timeouts
+ * @icsk_pending:         Scheduled timer event
+ * @icsk_backoff:         Backoff
+ * @icsk_syn_retries:      Number of allowed SYN (or equivalent) retries
+ * @icsk_probes_out:      unanswered 0 window probes
+ * @icsk_ack:             Delayed ACK control data
+ */
+struct inet_connection_sock {
+       /* inet_sock has to be the first member! */
+       struct inet_sock          icsk_inet;
+       struct request_sock_queue icsk_accept_queue;
+       struct inet_bind_bucket   *icsk_bind_hash;
+       unsigned long             icsk_timeout;
+       struct timer_list         icsk_retransmit_timer;
+       struct timer_list         icsk_delack_timer;
+       __u32                     icsk_rto;
+       struct tcp_congestion_ops *icsk_ca_ops;
+       __u8                      icsk_ca_state;
+       __u8                      icsk_retransmits;
+       __u8                      icsk_pending;
+       __u8                      icsk_backoff;
+       __u8                      icsk_syn_retries;
+       __u8                      icsk_probes_out;
+       /* 2 BYTES HOLE, TRY TO PACK! */
+       struct {
+               __u8              pending;       /* ACK is pending                         */
+               __u8              quick;         /* Scheduled number of quick acks         */
+               __u8              pingpong;      /* The session is interactive             */
+               __u8              blocked;       /* Delayed ACK was blocked by socket lock */
+               __u32             ato;           /* Predicted tick of soft clock           */
+               unsigned long     timeout;       /* Currently scheduled timeout            */
+               __u32             lrcvtime;      /* timestamp of last received data packet */
+               __u16             last_seg_size; /* Size of last incoming segment          */
+               __u16             rcv_mss;       /* MSS used for delayed ACK decisions     */ 
+       } icsk_ack;
+       u32                       icsk_ca_priv[16];
+#define ICSK_CA_PRIV_SIZE      (16 * sizeof(u32))
+};
+
+#define ICSK_TIME_RETRANS      1       /* Retransmit timer */
+#define ICSK_TIME_DACK         2       /* Delayed ack timer */
+#define ICSK_TIME_PROBE0       3       /* Zero window probe timer */
+#define ICSK_TIME_KEEPOPEN     4       /* Keepalive timer */
+
+static inline struct inet_connection_sock *inet_csk(const struct sock *sk)
+{
+       return (struct inet_connection_sock *)sk;
+}
+
+static inline void *inet_csk_ca(const struct sock *sk)
+{
+       return (void *)inet_csk(sk)->icsk_ca_priv;
+}
+
+extern struct sock *inet_csk_clone(struct sock *sk,
+                                  const struct request_sock *req,
+                                  const unsigned int __nocast priority);
+
+enum inet_csk_ack_state_t {
+       ICSK_ACK_SCHED  = 1,
+       ICSK_ACK_TIMER  = 2,
+       ICSK_ACK_PUSHED = 4
+};
+
+extern void inet_csk_init_xmit_timers(struct sock *sk,
+                                     void (*retransmit_handler)(unsigned long),
+                                     void (*delack_handler)(unsigned long),
+                                     void (*keepalive_handler)(unsigned long));
+extern void inet_csk_clear_xmit_timers(struct sock *sk);
+
+static inline void inet_csk_schedule_ack(struct sock *sk)
+{
+       inet_csk(sk)->icsk_ack.pending |= ICSK_ACK_SCHED;
+}
+
+static inline int inet_csk_ack_scheduled(const struct sock *sk)
+{
+       return inet_csk(sk)->icsk_ack.pending & ICSK_ACK_SCHED;
+}
+
+static inline void inet_csk_delack_init(struct sock *sk)
+{
+       memset(&inet_csk(sk)->icsk_ack, 0, sizeof(inet_csk(sk)->icsk_ack));
+}
+
+extern void inet_csk_delete_keepalive_timer(struct sock *sk);
+extern void inet_csk_reset_keepalive_timer(struct sock *sk, unsigned long timeout);
+
+#ifdef INET_CSK_DEBUG
+extern const char inet_csk_timer_bug_msg[];
+#endif
+
+static inline void inet_csk_clear_xmit_timer(struct sock *sk, const int what)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       
+       if (what == ICSK_TIME_RETRANS || what == ICSK_TIME_PROBE0) {
+               icsk->icsk_pending = 0;
+#ifdef INET_CSK_CLEAR_TIMERS
+               sk_stop_timer(sk, &icsk->icsk_retransmit_timer);
+#endif
+       } else if (what == ICSK_TIME_DACK) {
+               icsk->icsk_ack.blocked = icsk->icsk_ack.pending = 0;
+#ifdef INET_CSK_CLEAR_TIMERS
+               sk_stop_timer(sk, &icsk->icsk_delack_timer);
+#endif
+       }
+#ifdef INET_CSK_DEBUG
+       else {
+               pr_debug("%s", inet_csk_timer_bug_msg);
+       }
+#endif
+}
+
+/*
+ *     Reset the retransmission timer
+ */
+static inline void inet_csk_reset_xmit_timer(struct sock *sk, const int what,
+                                            unsigned long when,
+                                            const unsigned long max_when)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       if (when > max_when) {
+#ifdef INET_CSK_DEBUG
+               pr_debug("reset_xmit_timer: sk=%p %d when=0x%lx, caller=%p\n",
+                        sk, what, when, current_text_addr());
+#endif
+               when = max_when;
+       }
+
+       if (what == ICSK_TIME_RETRANS || what == ICSK_TIME_PROBE0) {
+               icsk->icsk_pending = what;
+               icsk->icsk_timeout = jiffies + when;
+               sk_reset_timer(sk, &icsk->icsk_retransmit_timer, icsk->icsk_timeout);
+       } else if (what == ICSK_TIME_DACK) {
+               icsk->icsk_ack.pending |= ICSK_ACK_TIMER;
+               icsk->icsk_ack.timeout = jiffies + when;
+               sk_reset_timer(sk, &icsk->icsk_delack_timer, icsk->icsk_ack.timeout);
+       }
+#ifdef INET_CSK_DEBUG
+       else {
+               pr_debug("%s", inet_csk_timer_bug_msg);
+       }
+#endif
+}
+
+extern struct sock *inet_csk_accept(struct sock *sk, int flags, int *err);
+
+extern struct request_sock *inet_csk_search_req(const struct sock *sk,
+                                               struct request_sock ***prevp,
+                                               const __u16 rport,
+                                               const __u32 raddr,
+                                               const __u32 laddr);
+extern int inet_csk_get_port(struct inet_hashinfo *hashinfo,
+                            struct sock *sk, unsigned short snum);
+
+extern struct dst_entry* inet_csk_route_req(struct sock *sk,
+                                           const struct request_sock *req);
+
+static inline void inet_csk_reqsk_queue_add(struct sock *sk,
+                                           struct request_sock *req,
+                                           struct sock *child)
+{
+       reqsk_queue_add(&inet_csk(sk)->icsk_accept_queue, req, sk, child);
+}
+
+extern void inet_csk_reqsk_queue_hash_add(struct sock *sk,
+                                         struct request_sock *req,
+                                         const unsigned timeout);
+
+static inline void inet_csk_reqsk_queue_removed(struct sock *sk,
+                                               struct request_sock *req)
+{
+       if (reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req) == 0)
+               inet_csk_delete_keepalive_timer(sk);
+}
+
+static inline void inet_csk_reqsk_queue_added(struct sock *sk,
+                                             const unsigned long timeout)
+{
+       if (reqsk_queue_added(&inet_csk(sk)->icsk_accept_queue) == 0)
+               inet_csk_reset_keepalive_timer(sk, timeout);
+}
+
+static inline int inet_csk_reqsk_queue_len(const struct sock *sk)
+{
+       return reqsk_queue_len(&inet_csk(sk)->icsk_accept_queue);
+}
+
+static inline int inet_csk_reqsk_queue_young(const struct sock *sk)
+{
+       return reqsk_queue_len_young(&inet_csk(sk)->icsk_accept_queue);
+}
+
+static inline int inet_csk_reqsk_queue_is_full(const struct sock *sk)
+{
+       return reqsk_queue_is_full(&inet_csk(sk)->icsk_accept_queue);
+}
+
+static inline void inet_csk_reqsk_queue_unlink(struct sock *sk,
+                                              struct request_sock *req,
+                                              struct request_sock **prev)
+{
+       reqsk_queue_unlink(&inet_csk(sk)->icsk_accept_queue, req, prev);
+}
+
+static inline void inet_csk_reqsk_queue_drop(struct sock *sk,
+                                            struct request_sock *req,
+                                            struct request_sock **prev)
+{
+       inet_csk_reqsk_queue_unlink(sk, req, prev);
+       inet_csk_reqsk_queue_removed(sk, req);
+       reqsk_free(req);
+}
+
+extern void inet_csk_reqsk_queue_prune(struct sock *parent,
+                                      const unsigned long interval,
+                                      const unsigned long timeout,
+                                      const unsigned long max_rto);
+
+extern void inet_csk_destroy_sock(struct sock *sk);
+
+/*
+ * LISTEN is a special case for poll..
+ */
+static inline unsigned int inet_csk_listen_poll(const struct sock *sk)
+{
+       return !reqsk_queue_empty(&inet_csk(sk)->icsk_accept_queue) ?
+                       (POLLIN | POLLRDNORM) : 0;
+}
+
+extern int  inet_csk_listen_start(struct sock *sk, const int nr_table_entries);
+extern void inet_csk_listen_stop(struct sock *sk);
+
+#endif /* _INET_CONNECTION_SOCK_H */
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
new file mode 100644 (file)
index 0000000..646b6ea
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ * Authors:    Lotsa people, from code originally in tcp
+ *
+ *     This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _INET_HASHTABLES_H
+#define _INET_HASHTABLES_H
+
+#include <linux/config.h>
+
+#include <linux/interrupt.h>
+#include <linux/ipv6.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/socket.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+
+#include <net/inet_connection_sock.h>
+#include <net/route.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+
+#include <asm/atomic.h>
+#include <asm/byteorder.h>
+
+/* This is for all connections with a full identity, no wildcards.
+ * New scheme, half the table is for TIME_WAIT, the other half is
+ * for the rest.  I'll experiment with dynamic table growth later.
+ */
+struct inet_ehash_bucket {
+       rwlock_t          lock;
+       struct hlist_head chain;
+} __attribute__((__aligned__(8)));
+
+/* There are a few simple rules, which allow for local port reuse by
+ * an application.  In essence:
+ *
+ *     1) Sockets bound to different interfaces may share a local port.
+ *        Failing that, goto test 2.
+ *     2) If all sockets have sk->sk_reuse set, and none of them are in
+ *        TCP_LISTEN state, the port may be shared.
+ *        Failing that, goto test 3.
+ *     3) If all sockets are bound to a specific inet_sk(sk)->rcv_saddr local
+ *        address, and none of them are the same, the port may be
+ *        shared.
+ *        Failing this, the port cannot be shared.
+ *
+ * The interesting point, is test #2.  This is what an FTP server does
+ * all day.  To optimize this case we use a specific flag bit defined
+ * below.  As we add sockets to a bind bucket list, we perform a
+ * check of: (newsk->sk_reuse && (newsk->sk_state != TCP_LISTEN))
+ * As long as all sockets added to a bind bucket pass this test,
+ * the flag bit will be set.
+ * The resulting situation is that tcp_v[46]_verify_bind() can just check
+ * for this flag bit, if it is set and the socket trying to bind has
+ * sk->sk_reuse set, we don't even have to walk the owners list at all,
+ * we return that it is ok to bind this socket to the requested local port.
+ *
+ * Sounds like a lot of work, but it is worth it.  In a more naive
+ * implementation (ie. current FreeBSD etc.) the entire list of ports
+ * must be walked for each data port opened by an ftp server.  Needless
+ * to say, this does not scale at all.  With a couple thousand FTP
+ * users logged onto your box, isn't it nice to know that new data
+ * ports are created in O(1) time?  I thought so. ;-)  -DaveM
+ */
+struct inet_bind_bucket {
+       unsigned short          port;
+       signed short            fastreuse;
+       struct hlist_node       node;
+       struct hlist_head       owners;
+};
+
+#define inet_bind_bucket_for_each(tb, node, head) \
+       hlist_for_each_entry(tb, node, head, node)
+
+struct inet_bind_hashbucket {
+       spinlock_t              lock;
+       struct hlist_head       chain;
+};
+
+/* This is for listening sockets, thus all sockets which possess wildcards. */
+#define INET_LHTABLE_SIZE      32      /* Yes, really, this is all you need. */
+
+struct inet_hashinfo {
+       /* This is for sockets with full identity only.  Sockets here will
+        * always be without wildcards and will have the following invariant:
+        *
+        *          TCP_ESTABLISHED <= sk->sk_state < TCP_CLOSE
+        *
+        * First half of the table is for sockets not in TIME_WAIT, second half
+        * is for TIME_WAIT sockets only.
+        */
+       struct inet_ehash_bucket        *ehash;
+
+       /* Ok, let's try this, I give up, we do need a local binding
+        * TCP hash as well as the others for fast bind/connect.
+        */
+       struct inet_bind_hashbucket     *bhash;
+
+       int                             bhash_size;
+       int                             ehash_size;
+
+       /* All sockets in TCP_LISTEN state will be in here.  This is the only
+        * table where wildcard'd TCP sockets can exist.  Hash function here
+        * is just local port number.
+        */
+       struct hlist_head               listening_hash[INET_LHTABLE_SIZE];
+
+       /* All the above members are written once at bootup and
+        * never written again _or_ are predominantly read-access.
+        *
+        * Now align to a new cache line as all the following members
+        * are often dirty.
+        */
+       rwlock_t                        lhash_lock ____cacheline_aligned;
+       atomic_t                        lhash_users;
+       wait_queue_head_t               lhash_wait;
+       spinlock_t                      portalloc_lock;
+       kmem_cache_t                    *bind_bucket_cachep;
+       int                             port_rover;
+};
+
+static inline int inet_ehashfn(const __u32 laddr, const __u16 lport,
+                              const __u32 faddr, const __u16 fport,
+                              const int ehash_size)
+{
+       int h = (laddr ^ lport) ^ (faddr ^ fport);
+       h ^= h >> 16;
+       h ^= h >> 8;
+       return h & (ehash_size - 1);
+}
+
+static inline int inet_sk_ehashfn(const struct sock *sk, const int ehash_size)
+{
+       const struct inet_sock *inet = inet_sk(sk);
+       const __u32 laddr = inet->rcv_saddr;
+       const __u16 lport = inet->num;
+       const __u32 faddr = inet->daddr;
+       const __u16 fport = inet->dport;
+
+       return inet_ehashfn(laddr, lport, faddr, fport, ehash_size);
+}
+
+extern struct inet_bind_bucket *
+                   inet_bind_bucket_create(kmem_cache_t *cachep,
+                                           struct inet_bind_hashbucket *head,
+                                           const unsigned short snum);
+extern void inet_bind_bucket_destroy(kmem_cache_t *cachep,
+                                    struct inet_bind_bucket *tb);
+
+static inline int inet_bhashfn(const __u16 lport, const int bhash_size)
+{
+       return lport & (bhash_size - 1);
+}
+
+extern void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb,
+                          const unsigned short snum);
+
+/* These can have wildcards, don't try too hard. */
+static inline int inet_lhashfn(const unsigned short num)
+{
+       return num & (INET_LHTABLE_SIZE - 1);
+}
+
+static inline int inet_sk_listen_hashfn(const struct sock *sk)
+{
+       return inet_lhashfn(inet_sk(sk)->num);
+}
+
+/* Caller must disable local BH processing. */
+static inline void __inet_inherit_port(struct inet_hashinfo *table,
+                                      struct sock *sk, struct sock *child)
+{
+       const int bhash = inet_bhashfn(inet_sk(child)->num, table->bhash_size);
+       struct inet_bind_hashbucket *head = &table->bhash[bhash];
+       struct inet_bind_bucket *tb;
+
+       spin_lock(&head->lock);
+       tb = inet_csk(sk)->icsk_bind_hash;
+       sk_add_bind_node(child, &tb->owners);
+       inet_csk(child)->icsk_bind_hash = tb;
+       spin_unlock(&head->lock);
+}
+
+static inline void inet_inherit_port(struct inet_hashinfo *table,
+                                    struct sock *sk, struct sock *child)
+{
+       local_bh_disable();
+       __inet_inherit_port(table, sk, child);
+       local_bh_enable();
+}
+
+extern void inet_put_port(struct inet_hashinfo *table, struct sock *sk);
+
+extern void inet_listen_wlock(struct inet_hashinfo *hashinfo);
+
+/*
+ * - We may sleep inside this lock.
+ * - If sleeping is not required (or called from BH),
+ *   use plain read_(un)lock(&inet_hashinfo.lhash_lock).
+ */
+static inline void inet_listen_lock(struct inet_hashinfo *hashinfo)
+{
+       /* read_lock synchronizes to candidates to writers */
+       read_lock(&hashinfo->lhash_lock);
+       atomic_inc(&hashinfo->lhash_users);
+       read_unlock(&hashinfo->lhash_lock);
+}
+
+static inline void inet_listen_unlock(struct inet_hashinfo *hashinfo)
+{
+       if (atomic_dec_and_test(&hashinfo->lhash_users))
+               wake_up(&hashinfo->lhash_wait);
+}
+
+static inline void __inet_hash(struct inet_hashinfo *hashinfo,
+                              struct sock *sk, const int listen_possible)
+{
+       struct hlist_head *list;
+       rwlock_t *lock;
+
+       BUG_TRAP(sk_unhashed(sk));
+       if (listen_possible && sk->sk_state == TCP_LISTEN) {
+               list = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];
+               lock = &hashinfo->lhash_lock;
+               inet_listen_wlock(hashinfo);
+       } else {
+               sk->sk_hashent = inet_sk_ehashfn(sk, hashinfo->ehash_size);
+               list = &hashinfo->ehash[sk->sk_hashent].chain;
+               lock = &hashinfo->ehash[sk->sk_hashent].lock;
+               write_lock(lock);
+       }
+       __sk_add_node(sk, list);
+       sock_prot_inc_use(sk->sk_prot);
+       write_unlock(lock);
+       if (listen_possible && sk->sk_state == TCP_LISTEN)
+               wake_up(&hashinfo->lhash_wait);
+}
+
+static inline void inet_hash(struct inet_hashinfo *hashinfo, struct sock *sk)
+{
+       if (sk->sk_state != TCP_CLOSE) {
+               local_bh_disable();
+               __inet_hash(hashinfo, sk, 1);
+               local_bh_enable();
+       }
+}
+
+static inline void inet_unhash(struct inet_hashinfo *hashinfo, struct sock *sk)
+{
+       rwlock_t *lock;
+
+       if (sk_unhashed(sk))
+               goto out;
+
+       if (sk->sk_state == TCP_LISTEN) {
+               local_bh_disable();
+               inet_listen_wlock(hashinfo);
+               lock = &hashinfo->lhash_lock;
+       } else {
+               struct inet_ehash_bucket *head = &hashinfo->ehash[sk->sk_hashent];
+               lock = &head->lock;
+               write_lock_bh(&head->lock);
+       }
+
+       if (__sk_del_node_init(sk))
+               sock_prot_dec_use(sk->sk_prot);
+       write_unlock_bh(lock);
+out:
+       if (sk->sk_state == TCP_LISTEN)
+               wake_up(&hashinfo->lhash_wait);
+}
+
+static inline int inet_iif(const struct sk_buff *skb)
+{
+       return ((struct rtable *)skb->dst)->rt_iif;
+}
+
+extern struct sock *__inet_lookup_listener(const struct hlist_head *head,
+                                          const u32 daddr,
+                                          const unsigned short hnum,
+                                          const int dif);
+
+/* Optimize the common listener case. */
+static inline struct sock *
+               inet_lookup_listener(struct inet_hashinfo *hashinfo,
+                                    const u32 daddr,
+                                    const unsigned short hnum, const int dif)
+{
+       struct sock *sk = NULL;
+       const struct hlist_head *head;
+
+       read_lock(&hashinfo->lhash_lock);
+       head = &hashinfo->listening_hash[inet_lhashfn(hnum)];
+       if (!hlist_empty(head)) {
+               const struct inet_sock *inet = inet_sk((sk = __sk_head(head)));
+
+               if (inet->num == hnum && !sk->sk_node.next &&
+                   (!inet->rcv_saddr || inet->rcv_saddr == daddr) &&
+                   (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) &&
+                   !sk->sk_bound_dev_if)
+                       goto sherry_cache;
+               sk = __inet_lookup_listener(head, daddr, hnum, dif);
+       }
+       if (sk) {
+sherry_cache:
+               sock_hold(sk);
+       }
+       read_unlock(&hashinfo->lhash_lock);
+       return sk;
+}
+
+/* Socket demux engine toys. */
+#ifdef __BIG_ENDIAN
+#define INET_COMBINED_PORTS(__sport, __dport) \
+       (((__u32)(__sport) << 16) | (__u32)(__dport))
+#else /* __LITTLE_ENDIAN */
+#define INET_COMBINED_PORTS(__sport, __dport) \
+       (((__u32)(__dport) << 16) | (__u32)(__sport))
+#endif
+
+#if (BITS_PER_LONG == 64)
+#ifdef __BIG_ENDIAN
+#define INET_ADDR_COOKIE(__name, __saddr, __daddr) \
+       const __u64 __name = (((__u64)(__saddr)) << 32) | ((__u64)(__daddr));
+#else /* __LITTLE_ENDIAN */
+#define INET_ADDR_COOKIE(__name, __saddr, __daddr) \
+       const __u64 __name = (((__u64)(__daddr)) << 32) | ((__u64)(__saddr));
+#endif /* __BIG_ENDIAN */
+#define INET_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\
+       (((*((__u64 *)&(inet_sk(__sk)->daddr))) == (__cookie))  &&      \
+        ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports))   &&      \
+        (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
+#define INET_TW_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\
+       (((*((__u64 *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) &&  \
+        ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) &&   \
+        (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
+#else /* 32-bit arch */
+#define INET_ADDR_COOKIE(__name, __saddr, __daddr)
+#define INET_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)   \
+       ((inet_sk(__sk)->daddr          == (__saddr))           &&      \
+        (inet_sk(__sk)->rcv_saddr      == (__daddr))           &&      \
+        ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports))   &&      \
+        (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
+#define INET_TW_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)        \
+       ((inet_twsk(__sk)->tw_daddr     == (__saddr))           &&      \
+        (inet_twsk(__sk)->tw_rcv_saddr == (__daddr))           &&      \
+        ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) &&   \
+        (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
+#endif /* 64-bit arch */
+
+/*
+ * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so we need
+ * not check it for lookups anymore, thanks Alexey. -DaveM
+ *
+ * Local BH must be disabled here.
+ */
+static inline struct sock *
+       __inet_lookup_established(struct inet_hashinfo *hashinfo,
+                                 const u32 saddr, const u16 sport,
+                                 const u32 daddr, const u16 hnum,
+                                 const int dif)
+{
+       INET_ADDR_COOKIE(acookie, saddr, daddr)
+       const __u32 ports = INET_COMBINED_PORTS(sport, hnum);
+       struct sock *sk;
+       const struct hlist_node *node;
+       /* Optimize here for direct hit, only listening connections can
+        * have wildcards anyways.
+        */
+       const int hash = inet_ehashfn(daddr, hnum, saddr, sport, hashinfo->ehash_size);
+       struct inet_ehash_bucket *head = &hashinfo->ehash[hash];
+
+       read_lock(&head->lock);
+       sk_for_each(sk, node, &head->chain) {
+               if (INET_MATCH(sk, acookie, saddr, daddr, ports, dif))
+                       goto hit; /* You sunk my battleship! */
+       }
+
+       /* Must check for a TIME_WAIT'er before going to listener hash. */
+       sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) {
+               if (INET_TW_MATCH(sk, acookie, saddr, daddr, ports, dif))
+                       goto hit;
+       }
+       sk = NULL;
+out:
+       read_unlock(&head->lock);
+       return sk;
+hit:
+       sock_hold(sk);
+       goto out;
+}
+
+static inline struct sock *__inet_lookup(struct inet_hashinfo *hashinfo,
+                                        const u32 saddr, const u16 sport,
+                                        const u32 daddr, const u16 hnum,
+                                        const int dif)
+{
+       struct sock *sk = __inet_lookup_established(hashinfo, saddr, sport, daddr,
+                                                   hnum, dif);
+       return sk ? : inet_lookup_listener(hashinfo, daddr, hnum, dif);
+}
+
+static inline struct sock *inet_lookup(struct inet_hashinfo *hashinfo,
+                                      const u32 saddr, const u16 sport,
+                                      const u32 daddr, const u16 dport,
+                                      const int dif)
+{
+       struct sock *sk;
+
+       local_bh_disable();
+       sk = __inet_lookup(hashinfo, saddr, sport, daddr, ntohs(dport), dif);
+       local_bh_enable();
+
+       return sk;
+}
+#endif /* _INET_HASHTABLES_H */
diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
new file mode 100644 (file)
index 0000000..3b07035
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the  BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             Definitions for a generic INET TIMEWAIT sock
+ *
+ *             From code originally in net/tcp.h
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ */
+#ifndef _INET_TIMEWAIT_SOCK_
+#define _INET_TIMEWAIT_SOCK_
+
+#include <linux/config.h>
+
+#include <linux/ip.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
+#include <net/sock.h>
+#include <net/tcp_states.h>
+
+#include <asm/atomic.h>
+
+struct inet_hashinfo;
+
+#define INET_TWDR_RECYCLE_SLOTS_LOG    5
+#define INET_TWDR_RECYCLE_SLOTS                (1 << INET_TWDR_RECYCLE_SLOTS_LOG)
+
+/*
+ * If time > 4sec, it is "slow" path, no recycling is required,
+ * so that we select tick to get range about 4 seconds.
+ */
+#if HZ <= 16 || HZ > 4096
+# error Unsupported: HZ <= 16 or HZ > 4096
+#elif HZ <= 32
+# define INET_TWDR_RECYCLE_TICK (5 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG)
+#elif HZ <= 64
+# define INET_TWDR_RECYCLE_TICK (6 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG)
+#elif HZ <= 128
+# define INET_TWDR_RECYCLE_TICK (7 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG)
+#elif HZ <= 256
+# define INET_TWDR_RECYCLE_TICK (8 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG)
+#elif HZ <= 512
+# define INET_TWDR_RECYCLE_TICK (9 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG)
+#elif HZ <= 1024
+# define INET_TWDR_RECYCLE_TICK (10 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG)
+#elif HZ <= 2048
+# define INET_TWDR_RECYCLE_TICK (11 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG)
+#else
+# define INET_TWDR_RECYCLE_TICK (12 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG)
+#endif
+
+/* TIME_WAIT reaping mechanism. */
+#define INET_TWDR_TWKILL_SLOTS 8 /* Please keep this a power of 2. */
+
+#define INET_TWDR_TWKILL_QUOTA 100
+
+struct inet_timewait_death_row {
+       /* Short-time timewait calendar */
+       int                     twcal_hand;
+       int                     twcal_jiffie;
+       struct timer_list       twcal_timer;
+       struct hlist_head       twcal_row[INET_TWDR_RECYCLE_SLOTS];
+
+       spinlock_t              death_lock;
+       int                     tw_count;
+       int                     period;
+       u32                     thread_slots;
+       struct work_struct      twkill_work;
+       struct timer_list       tw_timer;
+       int                     slot;
+       struct hlist_head       cells[INET_TWDR_TWKILL_SLOTS];
+       struct inet_hashinfo    *hashinfo;
+       int                     sysctl_tw_recycle;
+       int                     sysctl_max_tw_buckets;
+};
+
+extern void inet_twdr_hangman(unsigned long data);
+extern void inet_twdr_twkill_work(void *data);
+extern void inet_twdr_twcal_tick(unsigned long data);
+
+#if (BITS_PER_LONG == 64)
+#define INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES 8
+#else
+#define INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES 4
+#endif
+
+struct inet_bind_bucket;
+
+/*
+ * This is a TIME_WAIT sock. It works around the memory consumption
+ * problems of sockets in such a state on heavily loaded servers, but
+ * without violating the protocol specification.
+ */
+struct inet_timewait_sock {
+       /*
+        * Now struct sock also uses sock_common, so please just
+        * don't add nothing before this first member (__tw_common) --acme
+        */
+       struct sock_common      __tw_common;
+#define tw_family              __tw_common.skc_family
+#define tw_state               __tw_common.skc_state
+#define tw_reuse               __tw_common.skc_reuse
+#define tw_bound_dev_if                __tw_common.skc_bound_dev_if
+#define tw_node                        __tw_common.skc_node
+#define tw_bind_node           __tw_common.skc_bind_node
+#define tw_refcnt              __tw_common.skc_refcnt
+#define tw_prot                        __tw_common.skc_prot
+       volatile unsigned char  tw_substate;
+       /* 3 bits hole, try to pack */
+       unsigned char           tw_rcv_wscale;
+       /* Socket demultiplex comparisons on incoming packets. */
+       /* these five are in inet_sock */
+       __u16                   tw_sport;
+       __u32                   tw_daddr __attribute__((aligned(INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES)));
+       __u32                   tw_rcv_saddr;
+       __u16                   tw_dport;
+       __u16                   tw_num;
+       /* And these are ours. */
+       __u8                    tw_ipv6only:1;
+       /* 31 bits hole, try to pack */
+       int                     tw_hashent;
+       int                     tw_timeout;
+       unsigned long           tw_ttd;
+       struct inet_bind_bucket *tw_tb;
+       struct hlist_node       tw_death_node;
+};
+
+static inline void inet_twsk_add_node(struct inet_timewait_sock *tw,
+                                     struct hlist_head *list)
+{
+       hlist_add_head(&tw->tw_node, list);
+}
+
+static inline void inet_twsk_add_bind_node(struct inet_timewait_sock *tw,
+                                          struct hlist_head *list)
+{
+       hlist_add_head(&tw->tw_bind_node, list);
+}
+
+static inline int inet_twsk_dead_hashed(const struct inet_timewait_sock *tw)
+{
+       return tw->tw_death_node.pprev != NULL;
+}
+
+static inline void inet_twsk_dead_node_init(struct inet_timewait_sock *tw)
+{
+       tw->tw_death_node.pprev = NULL;
+}
+
+static inline void __inet_twsk_del_dead_node(struct inet_timewait_sock *tw)
+{
+       __hlist_del(&tw->tw_death_node);
+       inet_twsk_dead_node_init(tw);
+}
+
+static inline int inet_twsk_del_dead_node(struct inet_timewait_sock *tw)
+{
+       if (inet_twsk_dead_hashed(tw)) {
+               __inet_twsk_del_dead_node(tw);
+               return 1;
+       }
+       return 0;
+}
+
+#define inet_twsk_for_each(tw, node, head) \
+       hlist_for_each_entry(tw, node, head, tw_node)
+
+#define inet_twsk_for_each_inmate(tw, node, jail) \
+       hlist_for_each_entry(tw, node, jail, tw_death_node)
+
+#define inet_twsk_for_each_inmate_safe(tw, node, safe, jail) \
+       hlist_for_each_entry_safe(tw, node, safe, jail, tw_death_node)
+
+static inline struct inet_timewait_sock *inet_twsk(const struct sock *sk)
+{
+       return (struct inet_timewait_sock *)sk;
+}
+
+static inline u32 inet_rcv_saddr(const struct sock *sk)
+{
+       return likely(sk->sk_state != TCP_TIME_WAIT) ?
+               inet_sk(sk)->rcv_saddr : inet_twsk(sk)->tw_rcv_saddr;
+}
+
+static inline void inet_twsk_put(struct inet_timewait_sock *tw)
+{
+       if (atomic_dec_and_test(&tw->tw_refcnt)) {
+#ifdef SOCK_REFCNT_DEBUG
+               printk(KERN_DEBUG "%s timewait_sock %p released\n",
+                      tw->tw_prot->name, tw);
+#endif
+               kmem_cache_free(tw->tw_prot->twsk_slab, tw);
+       }
+}
+
+extern struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk,
+                                                 const int state);
+
+extern void __inet_twsk_kill(struct inet_timewait_sock *tw,
+                            struct inet_hashinfo *hashinfo);
+
+extern void __inet_twsk_hashdance(struct inet_timewait_sock *tw,
+                                 struct sock *sk,
+                                 struct inet_hashinfo *hashinfo);
+
+extern void inet_twsk_schedule(struct inet_timewait_sock *tw,
+                              struct inet_timewait_death_row *twdr,
+                              const int timeo, const int timewait_len);
+extern void inet_twsk_deschedule(struct inet_timewait_sock *tw,
+                                struct inet_timewait_death_row *twdr);
+#endif /* _INET_TIMEWAIT_SOCK_ */
index 32360bbe143faebcefe80eb9ae7a43d19585680c..e4563bbee6ea2baab2d6e61571dc2bd78cc1502e 100644 (file)
@@ -86,7 +86,7 @@ extern int            ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
                                              u32 saddr, u32 daddr,
                                              struct ip_options *opt);
 extern int             ip_rcv(struct sk_buff *skb, struct net_device *dev,
-                              struct packet_type *pt);
+                              struct packet_type *pt, struct net_device *orig_dev);
 extern int             ip_local_deliver(struct sk_buff *skb);
 extern int             ip_mr_input(struct sk_buff *skb);
 extern int             ip_output(struct sk_buff *skb);
@@ -140,8 +140,6 @@ struct ip_reply_arg {
 void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *arg,
                   unsigned int len); 
 
-extern int ip_finish_output(struct sk_buff *skb);
-
 struct ipv4_config
 {
        int     log_martians;
@@ -165,6 +163,24 @@ extern int sysctl_local_port_range[2];
 extern int sysctl_ip_default_ttl;
 extern int sysctl_ip_nonlocal_bind;
 
+/* From ip_fragment.c */
+extern int sysctl_ipfrag_high_thresh; 
+extern int sysctl_ipfrag_low_thresh;
+extern int sysctl_ipfrag_time;
+extern int sysctl_ipfrag_secret_interval;
+
+/* From inetpeer.c */
+extern int inet_peer_threshold;
+extern int inet_peer_minttl;
+extern int inet_peer_maxttl;
+extern int inet_peer_gc_mintime;
+extern int inet_peer_gc_maxtime;
+
+/* From ip_output.c */
+extern int sysctl_ip_dynaddr;
+
+extern void ipfrag_init(void);
+
 #ifdef CONFIG_INET
 /* The function in 2.2 was invalid, producing wrong result for
  * check=0xFEFF. It was noticed by Arthur Skawina _year_ ago. --ANK(000625) */
@@ -319,7 +335,10 @@ extern void ip_options_build(struct sk_buff *skb, struct ip_options *opt, u32 da
 extern int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb);
 extern void ip_options_fragment(struct sk_buff *skb);
 extern int ip_options_compile(struct ip_options *opt, struct sk_buff *skb);
-extern int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen, int user);
+extern int ip_options_get(struct ip_options **optp,
+                         unsigned char *data, int optlen);
+extern int ip_options_get_from_user(struct ip_options **optp,
+                                   unsigned char __user *data, int optlen);
 extern void ip_options_undo(struct ip_options * opt);
 extern void ip_forward_options(struct sk_buff *skb);
 extern int ip_options_rcv_srr(struct sk_buff *skb);
@@ -350,5 +369,10 @@ int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
                                  void __user *oldval, size_t __user *oldlenp,
                                  void __user *newval, size_t newlen, 
                                  void **context);
+#ifdef CONFIG_PROC_FS
+extern int ip_misc_proc_init(void);
+#endif
+
+extern struct ctl_table ipv4_table[];
 
 #endif /* _IP_H */
index f920706d526b4397288240e9e11bf6bcaa07db54..1f2e428ca364d0dcbcf3031d68892b1a75fb09b7 100644 (file)
@@ -12,7 +12,6 @@
 #include <net/flow.h>
 #include <net/ip6_fib.h>
 #include <net/sock.h>
-#include <linux/tcp.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 
index a4208a336ac09e58061af807e28a417f9ad1dd69..14de4ebd12113f4b31b05991159428d842cd78cf 100644 (file)
@@ -295,4 +295,9 @@ static inline void fib_res_put(struct fib_result *res)
 #endif
 }
 
+#ifdef CONFIG_PROC_FS
+extern int  fib_proc_init(void);
+extern void fib_proc_exit(void);
+#endif
+
 #endif  /* _NET_FIB_H */
index 52da5d26617a2989f4c0c7a0c017b22388582b77..e426641c519f4e4fcf4dd70a9bda3090cd612037 100644 (file)
@@ -255,7 +255,6 @@ struct ip_vs_daemon_user {
 #include <asm/atomic.h>                 /* for struct atomic_t */
 #include <linux/netdevice.h>           /* for struct neighbour */
 #include <net/dst.h>                   /* for struct dst_entry */
-#include <net/tcp.h>
 #include <net/udp.h>
 #include <linux/compiler.h>
 
@@ -959,7 +958,7 @@ static __inline__ int ip_vs_todrop(void)
  */
 #define IP_VS_FWD_METHOD(cp)  (cp->flags & IP_VS_CONN_F_FWD_MASK)
 
-extern __inline__ char ip_vs_fwd_tag(struct ip_vs_conn *cp)
+static inline char ip_vs_fwd_tag(struct ip_vs_conn *cp)
 {
        char fwd;
 
index 69324465e8b357fd1d10e90eac83630319f6dac8..3203eaff4bd4b71dcdbd82fe5242c8cf22d8161c 100644 (file)
@@ -104,6 +104,7 @@ struct frag_hdr {
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
 #include <net/sock.h>
 
 /* sysctls */
@@ -145,7 +146,6 @@ DECLARE_SNMP_STAT(struct udp_mib, udp_stats_in6);
 #define UDP6_INC_STATS(field)          SNMP_INC_STATS(udp_stats_in6, field)
 #define UDP6_INC_STATS_BH(field)       SNMP_INC_STATS_BH(udp_stats_in6, field)
 #define UDP6_INC_STATS_USER(field)     SNMP_INC_STATS_USER(udp_stats_in6, field)
-extern atomic_t                        inet6_sock_nr;
 
 int snmp6_register_dev(struct inet6_dev *idev);
 int snmp6_unregister_dev(struct inet6_dev *idev);
@@ -346,7 +346,8 @@ static inline int ipv6_addr_any(const struct in6_addr *a)
 
 extern int                     ipv6_rcv(struct sk_buff *skb, 
                                         struct net_device *dev, 
-                                        struct packet_type *pt);
+                                        struct packet_type *pt,
+                                        struct net_device *orig_dev);
 
 /*
  *     upper-layer output functions
@@ -464,8 +465,38 @@ extern int sysctl_ip6frag_low_thresh;
 extern int sysctl_ip6frag_time;
 extern int sysctl_ip6frag_secret_interval;
 
-#endif /* __KERNEL__ */
-#endif /* _NET_IPV6_H */
+extern struct proto_ops inet6_stream_ops;
+extern struct proto_ops inet6_dgram_ops;
+
+extern int ip6_mc_source(int add, int omode, struct sock *sk,
+                        struct group_source_req *pgsr);
+extern int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf);
+extern int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
+                        struct group_filter __user *optval,
+                        int __user *optlen);
+
+#ifdef CONFIG_PROC_FS
+extern int  ac6_proc_init(void);
+extern void ac6_proc_exit(void);
+extern int  raw6_proc_init(void);
+extern void raw6_proc_exit(void);
+extern int  tcp6_proc_init(void);
+extern void tcp6_proc_exit(void);
+extern int  udp6_proc_init(void);
+extern void udp6_proc_exit(void);
+extern int  ipv6_misc_proc_init(void);
+extern void ipv6_misc_proc_exit(void);
+
+extern struct rt6_statistics rt6_stats;
+#endif
 
+#ifdef CONFIG_SYSCTL
+extern ctl_table ipv6_route_table[];
+extern ctl_table ipv6_icmp_table[];
 
+extern void ipv6_sysctl_register(void);
+extern void ipv6_sysctl_unregister(void);
+#endif
 
+#endif /* __KERNEL__ */
+#endif /* _NET_IPV6_H */
index 3afeb6c94ea4b31337f14275133105aaa83c4177..492dedaa8ac16dacd4cbab84484293a61e636f72 100644 (file)
@@ -28,6 +28,6 @@
 void irlan_check_command_param(struct irlan_cb *self, char *param, 
                               char *value);
 void irlan_filter_request(struct irlan_cb *self, struct sk_buff *skb);
-int irlan_print_filter(struct seq_file *seq, int filter_type);
+void irlan_print_filter(struct seq_file *seq, int filter_type);
 
 #endif /* IRLAN_FILTER_H */
index 44edd48f123410d524ad21c79de8b2e86da73988..d67c8393a343711ad367108e595a48136995c9f8 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * This file define the new driver API for Wireless Extensions
  *
- * Version :   6       21.6.04
+ * Version :   7       18.3.05
  *
  * Authors :   Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 2001-2004 Jean Tourrilhes, All Rights Reserved.
+ * Copyright (c) 2001-2005 Jean Tourrilhes, All Rights Reserved.
  */
 
 #ifndef _IW_HANDLER_H
  * will be needed...
  * I just plan to increment with each new version.
  */
-#define IW_HANDLER_VERSION     6
+#define IW_HANDLER_VERSION     7
 
 /*
  * Changes :
  *     - Remove spy #ifdef, they are always on -> cleaner code
  *     - Add IW_DESCR_FLAG_NOMAX flag for very large requests
  *     - Start migrating get_wireless_stats to struct iw_handler_def
+ *
+ * V6 to V7
+ * --------
+ *     - Add struct ieee80211_device pointer in struct iw_public_data
+ *     - Remove (struct iw_point *)->pointer from events and streams
+ *     - Remove spy_offset from struct iw_handler_def
+ *     - Add "check" version of event macros for ieee802.11 stack
  */
 
 /**************************** CONSTANTS ****************************/
@@ -334,9 +341,6 @@ struct iw_handler_def
         * We will automatically export that to user space... */
        const struct iw_priv_args *     private_args;
 
-       /* This field will be *removed* in the next version of WE */
-       long                    spy_offset;     /* DO NOT USE */
-
        /* New location of get_wireless_stats, to de-bloat struct net_device.
         * The old pointer in struct net_device will be gradually phased
         * out, and drivers are encouraged to use this one... */
@@ -400,16 +404,21 @@ struct iw_spy_data
 /* --------------------- DEVICE WIRELESS DATA --------------------- */
 /*
  * This is all the wireless data specific to a device instance that
- * is managed by the core of Wireless Extensions.
+ * is managed by the core of Wireless Extensions or the 802.11 layer.
  * We only keep pointer to those structures, so that a driver is free
  * to share them between instances.
  * This structure should be initialised before registering the device.
  * Access to this data follow the same rules as any other struct net_device
  * data (i.e. valid as long as struct net_device exist, same locking rules).
  */
+/* Forward declaration */
+struct ieee80211_device;
+/* The struct */
 struct iw_public_data {
        /* Driver enhanced spy support */
-       struct iw_spy_data *    spy_data;
+       struct iw_spy_data *            spy_data;
+       /* Structure managed by the in-kernel IEEE 802.11 layer */
+       struct ieee80211_device *       ieee80211;
 };
 
 /**************************** PROTOTYPES ****************************/
@@ -424,7 +433,7 @@ struct iw_public_data {
 extern int dev_get_wireless_info(char * buffer, char **start, off_t offset,
                                 int length);
 
-/* Handle IOCTLs, called in net/code/dev.c */
+/* Handle IOCTLs, called in net/core/dev.c */
 extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
 
 /* Second : functions that may be called by driver modules */
@@ -479,7 +488,7 @@ iwe_stream_add_event(char * stream,         /* Stream of events */
                     int        event_len)      /* Real size of payload */
 {
        /* Check if it's possible */
-       if((stream + event_len) < ends) {
+       if(likely((stream + event_len) < ends)) {
                iwe->len = event_len;
                memcpy(stream, (char *) iwe, event_len);
                stream += event_len;
@@ -495,14 +504,17 @@ iwe_stream_add_event(char *       stream,         /* Stream of events */
 static inline char *
 iwe_stream_add_point(char *    stream,         /* Stream of events */
                     char *     ends,           /* End of stream */
-                    struct iw_event *iwe,      /* Payload */
-                    char *     extra)
+                    struct iw_event *iwe,      /* Payload length + flags */
+                    char *     extra)          /* More payload */
 {
        int     event_len = IW_EV_POINT_LEN + iwe->u.data.length;
        /* Check if it's possible */
-       if((stream + event_len) < ends) {
+       if(likely((stream + event_len) < ends)) {
                iwe->len = event_len;
-               memcpy(stream, (char *) iwe, IW_EV_POINT_LEN);
+               memcpy(stream, (char *) iwe, IW_EV_LCP_LEN);
+               memcpy(stream + IW_EV_LCP_LEN,
+                      ((char *) iwe) + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
+                      IW_EV_POINT_LEN - IW_EV_LCP_LEN);
                memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length);
                stream += event_len;
        }
@@ -526,7 +538,7 @@ iwe_stream_add_value(char * event,          /* Event in the stream */
        event_len -= IW_EV_LCP_LEN;
 
        /* Check if it's possible */
-       if((value + event_len) < ends) {
+       if(likely((value + event_len) < ends)) {
                /* Add new value */
                memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len);
                value += event_len;
@@ -537,4 +549,85 @@ iwe_stream_add_value(char *        event,          /* Event in the stream */
        return value;
 }
 
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper to add an Wireless Event to a stream of events.
+ * Same as above, with explicit error check...
+ */
+static inline char *
+iwe_stream_check_add_event(char *      stream,         /* Stream of events */
+                          char *       ends,           /* End of stream */
+                          struct iw_event *iwe,        /* Payload */
+                          int          event_len,      /* Size of payload */
+                          int *        perr)           /* Error report */
+{
+       /* Check if it's possible, set error if not */
+       if(likely((stream + event_len) < ends)) {
+               iwe->len = event_len;
+               memcpy(stream, (char *) iwe, event_len);
+               stream += event_len;
+       } else
+               *perr = -E2BIG;
+       return stream;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper to add an short Wireless Event containing a pointer to a
+ * stream of events.
+ * Same as above, with explicit error check...
+ */
+static inline char *
+iwe_stream_check_add_point(char *      stream,         /* Stream of events */
+                          char *       ends,           /* End of stream */
+                          struct iw_event *iwe,        /* Payload length + flags */
+                          char *       extra,          /* More payload */
+                          int *        perr)           /* Error report */
+{
+       int     event_len = IW_EV_POINT_LEN + iwe->u.data.length;
+       /* Check if it's possible */
+       if(likely((stream + event_len) < ends)) {
+               iwe->len = event_len;
+               memcpy(stream, (char *) iwe, IW_EV_LCP_LEN);
+               memcpy(stream + IW_EV_LCP_LEN,
+                      ((char *) iwe) + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
+                      IW_EV_POINT_LEN - IW_EV_LCP_LEN);
+               memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length);
+               stream += event_len;
+       } else
+               *perr = -E2BIG;
+       return stream;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper to add a value to a Wireless Event in a stream of events.
+ * Be careful, this one is tricky to use properly :
+ * At the first run, you need to have (value = event + IW_EV_LCP_LEN).
+ * Same as above, with explicit error check...
+ */
+static inline char *
+iwe_stream_check_add_value(char *      event,          /* Event in the stream */
+                          char *       value,          /* Value in event */
+                          char *       ends,           /* End of stream */
+                          struct iw_event *iwe,        /* Payload */
+                          int          event_len,      /* Size of payload */
+                          int *        perr)           /* Error report */
+{
+       /* Don't duplicate LCP */
+       event_len -= IW_EV_LCP_LEN;
+
+       /* Check if it's possible */
+       if(likely((value + event_len) < ends)) {
+               /* Add new value */
+               memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len);
+               value += event_len;
+               /* Patch LCP */
+               iwe->len = value - event;
+               memcpy(event, (char *) iwe, IW_EV_LCP_LEN);
+       } else
+               *perr = -E2BIG;
+       return value;
+}
+
 #endif /* _IW_HANDLER_H */
index c9aed2a8b4e20590d5f882e1150e4c714b8e0afa..71769a5aeef3b929afd6b8dd0aa9fdab6f3c7f13 100644 (file)
@@ -46,7 +46,8 @@ struct llc_sap {
        unsigned char    f_bit;
        int              (*rcv_func)(struct sk_buff *skb,
                                     struct net_device *dev,
-                                    struct packet_type *pt);
+                                    struct packet_type *pt,
+                                    struct net_device *orig_dev);
        struct llc_addr  laddr;
        struct list_head node;
        struct {
@@ -64,7 +65,7 @@ extern rwlock_t llc_sap_list_lock;
 extern unsigned char llc_station_mac_sa[ETH_ALEN];
 
 extern int llc_rcv(struct sk_buff *skb, struct net_device *dev,
-                  struct packet_type *pt);
+                  struct packet_type *pt, struct net_device *orig_dev);
 
 extern int llc_mac_hdr_init(struct sk_buff *skb,
                            unsigned char *sa, unsigned char *da);
@@ -78,7 +79,8 @@ extern void llc_set_station_handler(void (*handler)(struct sk_buff *skb));
 extern struct llc_sap *llc_sap_open(unsigned char lsap,
                                    int (*rcv)(struct sk_buff *skb,
                                               struct net_device *dev,
-                                              struct packet_type *pt));
+                                              struct packet_type *pt,
+                                              struct net_device *orig_dev));
 extern void llc_sap_close(struct llc_sap *sap);
 
 extern struct llc_sap *llc_sap_find(unsigned char sap_value);
index 89809891e5ab2e8e9430ccac31255d22ee364231..34c07731933db95b38cbb05a4db4ccefde2d6d7e 100644 (file)
@@ -363,7 +363,14 @@ __neigh_lookup_errno(struct neigh_table *tbl, const void *pkey,
        return neigh_create(tbl, pkey, dev);
 }
 
-#define LOCALLY_ENQUEUED -2
+struct neighbour_cb {
+       unsigned long sched_next;
+       unsigned int flags;
+};
+
+#define LOCALLY_ENQUEUED 0x1
+
+#define NEIGH_CB(skb)  ((struct neighbour_cb *)(skb)->cb)
 
 #endif
 #endif
index 3c99a86c35812da1da1dc34c9cf424386a784f29..42e9fac51b3115f86d0a766d8d19c90cc812ac0e 100644 (file)
@@ -4,7 +4,10 @@ extern struct datalink_proto *
        register_8022_client(unsigned char type,
                             int (*func)(struct sk_buff *skb,
                                         struct net_device *dev,
-                                        struct packet_type *pt));
+                                        struct packet_type *pt,
+                                        struct net_device *orig_dev));
 extern void unregister_8022_client(struct datalink_proto *proto);
 
+extern struct datalink_proto *make_8023_client(void);
+extern void destroy_8023_client(struct datalink_proto *dl);
 #endif
index 4abda6aec05a8cc4ca2cde35d6115427d71044fc..b902d24a32563f424d0934a6fb04d504a0b1e3ca 100644 (file)
@@ -352,10 +352,10 @@ tcf_change_indev(struct tcf_proto *tp, char *indev, struct rtattr *indev_tlv)
 static inline int
 tcf_match_indev(struct sk_buff *skb, char *indev)
 {
-       if (0 != indev[0]) {
-               if  (NULL == skb->input_dev)
+       if (indev[0]) {
+               if  (!skb->input_dev)
                        return 0;
-               else if (0 != strcmp(indev, skb->input_dev->name))
+               if (strcmp(indev, skb->input_dev->name))
                        return 0;
        }
 
index 9c94e8f98b36631a92477697defe5690d06b8f1b..b2e01cc3fc8a1c892bad42efc008d0c2ba80aa87 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _NET_PSNAP_H
 #define _NET_PSNAP_H
 
-extern struct datalink_proto *register_snap_client(unsigned char *desc, int (*rcvfunc)(struct sk_buff *, struct net_device *, struct packet_type *));
+extern struct datalink_proto *register_snap_client(unsigned char *desc, int (*rcvfunc)(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *orig_dev));
 extern void unregister_snap_client(struct datalink_proto *proto);
 
 #endif
index 1c411c45587a6a11862a6394fd8e6fa04c8391b4..f47917469b12121c9b3d770514f474ae5bf7a9d7 100644 (file)
 #ifndef _RAW_H
 #define _RAW_H
 
+#include <linux/config.h>
 
 extern struct proto raw_prot;
 
-
 extern void    raw_err(struct sock *, struct sk_buff *, u32 info);
 extern int     raw_rcv(struct sock *, struct sk_buff *);
 
@@ -37,6 +37,11 @@ extern struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num,
                                    unsigned long raddr, unsigned long laddr,
                                    int dif);
 
-extern void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash);
+extern int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash);
+
+#ifdef CONFIG_PROC_FS
+extern int  raw_proc_init(void);
+extern void raw_proc_exit(void);
+#endif
 
 #endif /* _RAW_H */
index 23fd9a6a221a2094546fe66c7a17b619a906d0c3..14476a71725e56467fe934611d3ec2f7e659abb6 100644 (file)
@@ -7,10 +7,11 @@
 extern struct hlist_head raw_v6_htable[RAWV6_HTABLE_SIZE];
 extern rwlock_t raw_v6_lock;
 
-extern void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr);
+extern int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr);
 
 extern struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num,
-                                   struct in6_addr *loc_addr, struct in6_addr *rmt_addr);
+                                   struct in6_addr *loc_addr, struct in6_addr *rmt_addr,
+                                   int dif);
 
 extern int                     rawv6_rcv(struct sock *sk,
                                          struct sk_buff *skb);
index 72fd6f5e86b19bbb1fc2444620d4764456469403..b52cc52ffe39f1475488c0d904753519a6df531f 100644 (file)
@@ -89,6 +89,7 @@ struct listen_sock {
        int                     qlen_young;
        int                     clock_hand;
        u32                     hash_rnd;
+       u32                     nr_table_entries;
        struct request_sock     *syn_table[0];
 };
 
@@ -96,6 +97,7 @@ struct listen_sock {
  *
  * @rskq_accept_head - FIFO head of established children
  * @rskq_accept_tail - FIFO tail of established children
+ * @rskq_defer_accept - User waits for some data after accept()
  * @syn_wait_lock - serializer
  *
  * %syn_wait_lock is necessary only to avoid proc interface having to grab the main
@@ -111,6 +113,8 @@ struct request_sock_queue {
        struct request_sock     *rskq_accept_head;
        struct request_sock     *rskq_accept_tail;
        rwlock_t                syn_wait_lock;
+       u8                      rskq_defer_accept;
+       /* 3 bytes hole, try to pack */
        struct listen_sock      *listen_opt;
 };
 
@@ -129,11 +133,13 @@ static inline struct listen_sock *reqsk_queue_yank_listen_sk(struct request_sock
        return lopt;
 }
 
-static inline void reqsk_queue_destroy(struct request_sock_queue *queue)
+static inline void __reqsk_queue_destroy(struct request_sock_queue *queue)
 {
        kfree(reqsk_queue_yank_listen_sk(queue));
 }
 
+extern void reqsk_queue_destroy(struct request_sock_queue *queue);
+
 static inline struct request_sock *
        reqsk_queue_yank_acceptq(struct request_sock_queue *queue)
 {
@@ -221,17 +227,17 @@ static inline int reqsk_queue_added(struct request_sock_queue *queue)
        return prev_qlen;
 }
 
-static inline int reqsk_queue_len(struct request_sock_queue *queue)
+static inline int reqsk_queue_len(const struct request_sock_queue *queue)
 {
        return queue->listen_opt != NULL ? queue->listen_opt->qlen : 0;
 }
 
-static inline int reqsk_queue_len_young(struct request_sock_queue *queue)
+static inline int reqsk_queue_len_young(const struct request_sock_queue *queue)
 {
        return queue->listen_opt->qlen_young;
 }
 
-static inline int reqsk_queue_is_full(struct request_sock_queue *queue)
+static inline int reqsk_queue_is_full(const struct request_sock_queue *queue)
 {
        return queue->listen_opt->qlen >> queue->listen_opt->max_qlen_log;
 }
index c3cd069a9aca5f17c0c09b6b6a0f2f7a53be6fa9..dbe79ca67d317cc1410b879e0898ae6ac52a3b03 100644 (file)
@@ -105,10 +105,6 @@ struct rt_cache_stat
         unsigned int out_hlist_search;
 };
 
-extern struct rt_cache_stat *rt_cache_stat;
-#define RT_CACHE_STAT_INC(field)                                         \
-               (per_cpu_ptr(rt_cache_stat, raw_smp_processor_id())->field++)
-
 extern struct ip_rt_acct *ip_rt_acct;
 
 struct in_device;
@@ -199,4 +195,6 @@ static inline struct inet_peer *rt_get_peer(struct rtable *rt)
        return rt->peer;
 }
 
+extern ctl_table ipv4_route_table[];
+
 #endif /* _ROUTE_H */
index 5999e5684bbfc5136f36964fb3ebe2c0e669f9b1..c51541ee0247cea21202369d8827be0b86db3132 100644 (file)
 #ifndef __sctp_constants_h__
 #define __sctp_constants_h__
 
-#include <linux/tcp.h>  /* For TCP states used in sctp_sock_state_t */
 #include <linux/sctp.h>
 #include <linux/ipv6.h> /* For ipv6hdr. */
 #include <net/sctp/user.h>
+#include <net/tcp_states.h>  /* For TCP states used in sctp_sock_state_t */
 
 /* Value used for stream negotiation. */
 enum { SCTP_MAX_STREAM = 0xffff };
index e9b1dbab90d007fec58e666d98205c1b8ca6a114..8c48fbecb7cf8fc9e4828a81fdd9a3ca8bd35457 100644 (file)
@@ -88,6 +88,7 @@ do {  spin_lock_init(&((__sk)->sk_lock.slock)); \
 } while(0)
 
 struct sock;
+struct proto;
 
 /**
  *     struct sock_common - minimal network layer representation of sockets
@@ -98,10 +99,11 @@ struct sock;
  *     @skc_node: main hash linkage for various protocol lookup tables
  *     @skc_bind_node: bind hash linkage for various protocol lookup tables
  *     @skc_refcnt: reference count
+ *     @skc_prot: protocol handlers inside a network family
  *
  *     This is the minimal network layer representation of sockets, the header
- *     for struct sock and struct tcp_tw_bucket.
 */
+ *     for struct sock and struct inet_timewait_sock.
+ */
 struct sock_common {
        unsigned short          skc_family;
        volatile unsigned char  skc_state;
@@ -110,11 +112,12 @@ struct sock_common {
        struct hlist_node       skc_node;
        struct hlist_node       skc_bind_node;
        atomic_t                skc_refcnt;
+       struct proto            *skc_prot;
 };
 
 /**
   *    struct sock - network layer representation of sockets
-  *    @__sk_common: shared layout with tcp_tw_bucket
+  *    @__sk_common: shared layout with inet_timewait_sock
   *    @sk_shutdown: mask of %SEND_SHUTDOWN and/or %RCV_SHUTDOWN
   *    @sk_userlocks: %SO_SNDBUF and %SO_RCVBUF settings
   *    @sk_lock:       synchronizer
@@ -136,11 +139,10 @@ struct sock_common {
   *    @sk_no_check: %SO_NO_CHECK setting, wether or not checkup packets
   *    @sk_route_caps: route capabilities (e.g. %NETIF_F_TSO)
   *    @sk_lingertime: %SO_LINGER l_linger setting
-  *    @sk_hashent: hash entry in several tables (e.g. tcp_ehash)
+  *    @sk_hashent: hash entry in several tables (e.g. inet_hashinfo.ehash)
   *    @sk_backlog: always used with the per-socket spinlock held
   *    @sk_callback_lock: used with the callbacks in the end of this struct
   *    @sk_error_queue: rarely used
-  *    @sk_prot: protocol handlers inside a network family
   *    @sk_prot_creator: sk_prot of original sock creator (see ipv6_setsockopt, IPV6_ADDRFORM for instance)
   *    @sk_err: last error
   *    @sk_err_soft: errors that don't cause failure but are the cause of a persistent failure not just 'timed out'
@@ -173,7 +175,7 @@ struct sock_common {
  */
 struct sock {
        /*
-        * Now struct tcp_tw_bucket also uses sock_common, so please just
+        * Now struct inet_timewait_sock also uses sock_common, so please just
         * don't add nothing before this first member (__sk_common) --acme
         */
        struct sock_common      __sk_common;
@@ -184,6 +186,7 @@ struct sock {
 #define sk_node                        __sk_common.skc_node
 #define sk_bind_node           __sk_common.skc_bind_node
 #define sk_refcnt              __sk_common.skc_refcnt
+#define sk_prot                        __sk_common.skc_prot
        unsigned char           sk_shutdown : 2,
                                sk_no_check : 2,
                                sk_userlocks : 4;
@@ -218,7 +221,6 @@ struct sock {
                struct sk_buff *tail;
        } sk_backlog;
        struct sk_buff_head     sk_error_queue;
-       struct proto            *sk_prot;
        struct proto            *sk_prot_creator;
        rwlock_t                sk_callback_lock;
        int                     sk_err,
@@ -253,28 +255,28 @@ struct sock {
 /*
  * Hashed lists helper routines
  */
-static inline struct sock *__sk_head(struct hlist_head *head)
+static inline struct sock *__sk_head(const struct hlist_head *head)
 {
        return hlist_entry(head->first, struct sock, sk_node);
 }
 
-static inline struct sock *sk_head(struct hlist_head *head)
+static inline struct sock *sk_head(const struct hlist_head *head)
 {
        return hlist_empty(head) ? NULL : __sk_head(head);
 }
 
-static inline struct sock *sk_next(struct sock *sk)
+static inline struct sock *sk_next(const struct sock *sk)
 {
        return sk->sk_node.next ?
                hlist_entry(sk->sk_node.next, struct sock, sk_node) : NULL;
 }
 
-static inline int sk_unhashed(struct sock *sk)
+static inline int sk_unhashed(const struct sock *sk)
 {
        return hlist_unhashed(&sk->sk_node);
 }
 
-static inline int sk_hashed(struct sock *sk)
+static inline int sk_hashed(const struct sock *sk)
 {
        return sk->sk_node.pprev != NULL;
 }
@@ -554,6 +556,10 @@ struct proto {
        kmem_cache_t            *slab;
        unsigned int            obj_size;
 
+       kmem_cache_t            *twsk_slab;
+       unsigned int            twsk_obj_size;
+       atomic_t                *orphan_count;
+
        struct request_sock_ops *rsk_prot;
 
        struct module           *owner;
@@ -561,7 +567,9 @@ struct proto {
        char                    name[32];
 
        struct list_head        node;
-
+#ifdef SOCK_REFCNT_DEBUG
+       atomic_t                socks;
+#endif
        struct {
                int inuse;
                u8  __pad[SMP_CACHE_BYTES - sizeof(int)];
@@ -571,6 +579,31 @@ struct proto {
 extern int proto_register(struct proto *prot, int alloc_slab);
 extern void proto_unregister(struct proto *prot);
 
+#ifdef SOCK_REFCNT_DEBUG
+static inline void sk_refcnt_debug_inc(struct sock *sk)
+{
+       atomic_inc(&sk->sk_prot->socks);
+}
+
+static inline void sk_refcnt_debug_dec(struct sock *sk)
+{
+       atomic_dec(&sk->sk_prot->socks);
+       printk(KERN_DEBUG "%s socket %p released, %d are still alive\n",
+              sk->sk_prot->name, sk, atomic_read(&sk->sk_prot->socks));
+}
+
+static inline void sk_refcnt_debug_release(const struct sock *sk)
+{
+       if (atomic_read(&sk->sk_refcnt) != 1)
+               printk(KERN_DEBUG "Destruction of the %s socket %p delayed, refcnt=%d\n",
+                      sk->sk_prot->name, sk, atomic_read(&sk->sk_refcnt));
+}
+#else /* SOCK_REFCNT_DEBUG */
+#define sk_refcnt_debug_inc(sk) do { } while (0)
+#define sk_refcnt_debug_dec(sk) do { } while (0)
+#define sk_refcnt_debug_release(sk) do { } while (0)
+#endif /* SOCK_REFCNT_DEBUG */
+
 /* Called with local bh disabled */
 static __inline__ void sock_prot_inc_use(struct proto *prot)
 {
@@ -582,6 +615,15 @@ static __inline__ void sock_prot_dec_use(struct proto *prot)
        prot->stats[smp_processor_id()].inuse--;
 }
 
+/* With per-bucket locks this operation is not-atomic, so that
+ * this version is not worse.
+ */
+static inline void __sk_prot_rehash(struct sock *sk)
+{
+       sk->sk_prot->unhash(sk);
+       sk->sk_prot->hash(sk);
+}
+
 /* About 10 seconds */
 #define SOCK_DESTROY_TIME (10*HZ)
 
@@ -667,6 +709,12 @@ static inline int sk_stream_rmem_schedule(struct sock *sk, struct sk_buff *skb)
                sk_stream_mem_schedule(sk, skb->truesize, 1);
 }
 
+static inline int sk_stream_wmem_schedule(struct sock *sk, int size)
+{
+       return size <= sk->sk_forward_alloc ||
+              sk_stream_mem_schedule(sk, size, 0);
+}
+
 /* Used by processes to "lock" a socket state, so that
  * interrupts and bottom half handlers won't change it
  * from under us. It essentially blocks any incoming
@@ -693,6 +741,8 @@ extern struct sock          *sk_alloc(int family,
                                          unsigned int __nocast priority,
                                          struct proto *prot, int zero_it);
 extern void                    sk_free(struct sock *sk);
+extern struct sock             *sk_clone(const struct sock *sk,
+                                         const unsigned int __nocast priority);
 
 extern struct sk_buff          *sock_wmalloc(struct sock *sk,
                                              unsigned long size, int force,
@@ -986,6 +1036,16 @@ sk_dst_check(struct sock *sk, u32 cookie)
        return dst;
 }
 
+static inline void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
+{
+       __sk_dst_set(sk, dst);
+       sk->sk_route_caps = dst->dev->features;
+       if (sk->sk_route_caps & NETIF_F_TSO) {
+               if (sock_flag(sk, SOCK_NO_LARGESEND) || dst->header_len)
+                       sk->sk_route_caps &= ~NETIF_F_TSO;
+       }
+}
+
 static inline void sk_charge_skb(struct sock *sk, struct sk_buff *skb)
 {
        sk->sk_wmem_queued   += skb->truesize;
@@ -1146,11 +1206,10 @@ static inline struct sk_buff *sk_stream_alloc_pskb(struct sock *sk,
        int hdr_len;
 
        hdr_len = SKB_DATA_ALIGN(sk->sk_prot->max_header);
-       skb = alloc_skb(size + hdr_len, gfp);
+       skb = alloc_skb_fclone(size + hdr_len, gfp);
        if (skb) {
                skb->truesize += mem;
-               if (sk->sk_forward_alloc >= (int)skb->truesize ||
-                   sk_stream_mem_schedule(sk, skb->truesize, 0)) {
+               if (sk_stream_wmem_schedule(sk, skb->truesize)) {
                        skb_reserve(skb, hdr_len);
                        return skb;
                }
@@ -1173,10 +1232,8 @@ static inline struct page *sk_stream_alloc_page(struct sock *sk)
 {
        struct page *page = NULL;
 
-       if (sk->sk_forward_alloc >= (int)PAGE_SIZE ||
-           sk_stream_mem_schedule(sk, PAGE_SIZE, 0))
-               page = alloc_pages(sk->sk_allocation, 0);
-       else {
+       page = alloc_pages(sk->sk_allocation, 0);
+       if (!page) {
                sk->sk_prot->enter_memory_pressure();
                sk_stream_moderate_sndbuf(sk);
        }
@@ -1228,16 +1285,19 @@ static inline int sock_intr_errno(long timeo)
 static __inline__ void
 sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
 {
-       struct timeval *stamp = &skb->stamp;
+       struct timeval stamp;
+
+       skb_get_timestamp(skb, &stamp);
        if (sock_flag(sk, SOCK_RCVTSTAMP)) {
                /* Race occurred between timestamp enabling and packet
                   receiving.  Fill in the current time for now. */
-               if (stamp->tv_sec == 0)
-                       do_gettimeofday(stamp);
+               if (stamp.tv_sec == 0)
+                       do_gettimeofday(&stamp);
+               skb_set_timestamp(skb, &stamp);
                put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP, sizeof(struct timeval),
-                        stamp);
+                        &stamp);
        } else
-               sk->sk_stamp = *stamp;
+               sk->sk_stamp = stamp;
 }
 
 /**
@@ -1262,11 +1322,11 @@ extern int sock_get_timestamp(struct sock *, struct timeval __user *);
  */
 
 #if 0
-#define NETDEBUG(x)    do { } while (0)
-#define LIMIT_NETDEBUG(x) do {} while(0)
+#define NETDEBUG(fmt, args...) do { } while (0)
+#define LIMIT_NETDEBUG(fmt, args...) do { } while(0)
 #else
-#define NETDEBUG(x)    do { x; } while (0)
-#define LIMIT_NETDEBUG(x) do { if (net_ratelimit()) { x; } } while(0)
+#define NETDEBUG(fmt, args...) printk(fmt,##args)
+#define LIMIT_NETDEBUG(fmt, args...) do { if (net_ratelimit()) printk(fmt,##args); } while(0)
 #endif
 
 /*
@@ -1313,4 +1373,15 @@ static inline int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsign
 }
 #endif
 
+extern void sk_init(void);
+
+#ifdef CONFIG_SYSCTL
+extern struct ctl_table core_table[];
+#endif
+
+extern int sysctl_optmem_max;
+
+extern __u32 sysctl_wmem_default;
+extern __u32 sysctl_rmem_default;
+
 #endif /* _SOCK_H */
index 5010f0c5a56e32c8492723d8342b99bde0df7d67..97af77c4d0961c5866534f0e40c069905fa4d225 100644 (file)
 #define TCP_DEBUG 1
 #define FASTRETRANS_DEBUG 1
 
-/* Cancel timers, when they are not required. */
-#undef TCP_CLEAR_TIMERS
-
 #include <linux/config.h>
 #include <linux/list.h>
 #include <linux/tcp.h>
 #include <linux/slab.h>
 #include <linux/cache.h>
 #include <linux/percpu.h>
+
+#include <net/inet_connection_sock.h>
+#include <net/inet_timewait_sock.h>
+#include <net/inet_hashtables.h>
 #include <net/checksum.h>
 #include <net/request_sock.h>
 #include <net/sock.h>
 #include <net/snmp.h>
 #include <net/ip.h>
-#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
-#include <linux/ipv6.h>
-#endif
-#include <linux/seq_file.h>
-
-/* This is for all connections with a full identity, no wildcards.
- * New scheme, half the table is for TIME_WAIT, the other half is
- * for the rest.  I'll experiment with dynamic table growth later.
- */
-struct tcp_ehash_bucket {
-       rwlock_t          lock;
-       struct hlist_head chain;
-} __attribute__((__aligned__(8)));
-
-/* This is for listening sockets, thus all sockets which possess wildcards. */
-#define TCP_LHTABLE_SIZE       32      /* Yes, really, this is all you need. */
-
-/* There are a few simple rules, which allow for local port reuse by
- * an application.  In essence:
- *
- *     1) Sockets bound to different interfaces may share a local port.
- *        Failing that, goto test 2.
- *     2) If all sockets have sk->sk_reuse set, and none of them are in
- *        TCP_LISTEN state, the port may be shared.
- *        Failing that, goto test 3.
- *     3) If all sockets are bound to a specific inet_sk(sk)->rcv_saddr local
- *        address, and none of them are the same, the port may be
- *        shared.
- *        Failing this, the port cannot be shared.
- *
- * The interesting point, is test #2.  This is what an FTP server does
- * all day.  To optimize this case we use a specific flag bit defined
- * below.  As we add sockets to a bind bucket list, we perform a
- * check of: (newsk->sk_reuse && (newsk->sk_state != TCP_LISTEN))
- * As long as all sockets added to a bind bucket pass this test,
- * the flag bit will be set.
- * The resulting situation is that tcp_v[46]_verify_bind() can just check
- * for this flag bit, if it is set and the socket trying to bind has
- * sk->sk_reuse set, we don't even have to walk the owners list at all,
- * we return that it is ok to bind this socket to the requested local port.
- *
- * Sounds like a lot of work, but it is worth it.  In a more naive
- * implementation (ie. current FreeBSD etc.) the entire list of ports
- * must be walked for each data port opened by an ftp server.  Needless
- * to say, this does not scale at all.  With a couple thousand FTP
- * users logged onto your box, isn't it nice to know that new data
- * ports are created in O(1) time?  I thought so. ;-)  -DaveM
- */
-struct tcp_bind_bucket {
-       unsigned short          port;
-       signed short            fastreuse;
-       struct hlist_node       node;
-       struct hlist_head       owners;
-};
-
-#define tb_for_each(tb, node, head) hlist_for_each_entry(tb, node, head, node)
-
-struct tcp_bind_hashbucket {
-       spinlock_t              lock;
-       struct hlist_head       chain;
-};
-
-static inline struct tcp_bind_bucket *__tb_head(struct tcp_bind_hashbucket *head)
-{
-       return hlist_entry(head->chain.first, struct tcp_bind_bucket, node);
-}
-
-static inline struct tcp_bind_bucket *tb_head(struct tcp_bind_hashbucket *head)
-{
-       return hlist_empty(&head->chain) ? NULL : __tb_head(head);
-}
-
-extern struct tcp_hashinfo {
-       /* This is for sockets with full identity only.  Sockets here will
-        * always be without wildcards and will have the following invariant:
-        *
-        *          TCP_ESTABLISHED <= sk->sk_state < TCP_CLOSE
-        *
-        * First half of the table is for sockets not in TIME_WAIT, second half
-        * is for TIME_WAIT sockets only.
-        */
-       struct tcp_ehash_bucket *__tcp_ehash;
-
-       /* Ok, let's try this, I give up, we do need a local binding
-        * TCP hash as well as the others for fast bind/connect.
-        */
-       struct tcp_bind_hashbucket *__tcp_bhash;
+#include <net/tcp_states.h>
 
-       int __tcp_bhash_size;
-       int __tcp_ehash_size;
-
-       /* All sockets in TCP_LISTEN state will be in here.  This is the only
-        * table where wildcard'd TCP sockets can exist.  Hash function here
-        * is just local port number.
-        */
-       struct hlist_head __tcp_listening_hash[TCP_LHTABLE_SIZE];
-
-       /* All the above members are written once at bootup and
-        * never written again _or_ are predominantly read-access.
-        *
-        * Now align to a new cache line as all the following members
-        * are often dirty.
-        */
-       rwlock_t __tcp_lhash_lock ____cacheline_aligned;
-       atomic_t __tcp_lhash_users;
-       wait_queue_head_t __tcp_lhash_wait;
-       spinlock_t __tcp_portalloc_lock;
-} tcp_hashinfo;
-
-#define tcp_ehash      (tcp_hashinfo.__tcp_ehash)
-#define tcp_bhash      (tcp_hashinfo.__tcp_bhash)
-#define tcp_ehash_size (tcp_hashinfo.__tcp_ehash_size)
-#define tcp_bhash_size (tcp_hashinfo.__tcp_bhash_size)
-#define tcp_listening_hash (tcp_hashinfo.__tcp_listening_hash)
-#define tcp_lhash_lock (tcp_hashinfo.__tcp_lhash_lock)
-#define tcp_lhash_users        (tcp_hashinfo.__tcp_lhash_users)
-#define tcp_lhash_wait (tcp_hashinfo.__tcp_lhash_wait)
-#define tcp_portalloc_lock (tcp_hashinfo.__tcp_portalloc_lock)
-
-extern kmem_cache_t *tcp_bucket_cachep;
-extern struct tcp_bind_bucket *tcp_bucket_create(struct tcp_bind_hashbucket *head,
-                                                unsigned short snum);
-extern void tcp_bucket_destroy(struct tcp_bind_bucket *tb);
-extern void tcp_bucket_unlock(struct sock *sk);
-extern int tcp_port_rover;
-
-/* These are AF independent. */
-static __inline__ int tcp_bhashfn(__u16 lport)
-{
-       return (lport & (tcp_bhash_size - 1));
-}
-
-extern void tcp_bind_hash(struct sock *sk, struct tcp_bind_bucket *tb,
-                         unsigned short snum);
-
-#if (BITS_PER_LONG == 64)
-#define TCP_ADDRCMP_ALIGN_BYTES 8
-#else
-#define TCP_ADDRCMP_ALIGN_BYTES 4
-#endif
-
-/* This is a TIME_WAIT bucket.  It works around the memory consumption
- * problems of sockets in such a state on heavily loaded servers, but
- * without violating the protocol specification.
- */
-struct tcp_tw_bucket {
-       /*
-        * Now struct sock also uses sock_common, so please just
-        * don't add nothing before this first member (__tw_common) --acme
-        */
-       struct sock_common      __tw_common;
-#define tw_family              __tw_common.skc_family
-#define tw_state               __tw_common.skc_state
-#define tw_reuse               __tw_common.skc_reuse
-#define tw_bound_dev_if                __tw_common.skc_bound_dev_if
-#define tw_node                        __tw_common.skc_node
-#define tw_bind_node           __tw_common.skc_bind_node
-#define tw_refcnt              __tw_common.skc_refcnt
-       volatile unsigned char  tw_substate;
-       unsigned char           tw_rcv_wscale;
-       __u16                   tw_sport;
-       /* Socket demultiplex comparisons on incoming packets. */
-       /* these five are in inet_sock */
-       __u32                   tw_daddr
-               __attribute__((aligned(TCP_ADDRCMP_ALIGN_BYTES)));
-       __u32                   tw_rcv_saddr;
-       __u16                   tw_dport;
-       __u16                   tw_num;
-       /* And these are ours. */
-       int                     tw_hashent;
-       int                     tw_timeout;
-       __u32                   tw_rcv_nxt;
-       __u32                   tw_snd_nxt;
-       __u32                   tw_rcv_wnd;
-       __u32                   tw_ts_recent;
-       long                    tw_ts_recent_stamp;
-       unsigned long           tw_ttd;
-       struct tcp_bind_bucket  *tw_tb;
-       struct hlist_node       tw_death_node;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-       struct in6_addr         tw_v6_daddr;
-       struct in6_addr         tw_v6_rcv_saddr;
-       int                     tw_v6_ipv6only;
-#endif
-};
-
-static __inline__ void tw_add_node(struct tcp_tw_bucket *tw,
-                                  struct hlist_head *list)
-{
-       hlist_add_head(&tw->tw_node, list);
-}
-
-static __inline__ void tw_add_bind_node(struct tcp_tw_bucket *tw,
-                                       struct hlist_head *list)
-{
-       hlist_add_head(&tw->tw_bind_node, list);
-}
-
-static inline int tw_dead_hashed(struct tcp_tw_bucket *tw)
-{
-       return tw->tw_death_node.pprev != NULL;
-}
-
-static __inline__ void tw_dead_node_init(struct tcp_tw_bucket *tw)
-{
-       tw->tw_death_node.pprev = NULL;
-}
-
-static __inline__ void __tw_del_dead_node(struct tcp_tw_bucket *tw)
-{
-       __hlist_del(&tw->tw_death_node);
-       tw_dead_node_init(tw);
-}
-
-static __inline__ int tw_del_dead_node(struct tcp_tw_bucket *tw)
-{
-       if (tw_dead_hashed(tw)) {
-               __tw_del_dead_node(tw);
-               return 1;
-       }
-       return 0;
-}
-
-#define tw_for_each(tw, node, head) \
-       hlist_for_each_entry(tw, node, head, tw_node)
-
-#define tw_for_each_inmate(tw, node, jail) \
-       hlist_for_each_entry(tw, node, jail, tw_death_node)
-
-#define tw_for_each_inmate_safe(tw, node, safe, jail) \
-       hlist_for_each_entry_safe(tw, node, safe, jail, tw_death_node)
-
-#define tcptw_sk(__sk) ((struct tcp_tw_bucket *)(__sk))
-
-static inline u32 tcp_v4_rcv_saddr(const struct sock *sk)
-{
-       return likely(sk->sk_state != TCP_TIME_WAIT) ?
-               inet_sk(sk)->rcv_saddr : tcptw_sk(sk)->tw_rcv_saddr;
-}
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-static inline struct in6_addr *__tcp_v6_rcv_saddr(const struct sock *sk)
-{
-       return likely(sk->sk_state != TCP_TIME_WAIT) ?
-               &inet6_sk(sk)->rcv_saddr : &tcptw_sk(sk)->tw_v6_rcv_saddr;
-}
-
-static inline struct in6_addr *tcp_v6_rcv_saddr(const struct sock *sk)
-{
-       return sk->sk_family == AF_INET6 ? __tcp_v6_rcv_saddr(sk) : NULL;
-}
-
-#define tcptw_sk_ipv6only(__sk)        (tcptw_sk(__sk)->tw_v6_ipv6only)
-
-static inline int tcp_v6_ipv6only(const struct sock *sk)
-{
-       return likely(sk->sk_state != TCP_TIME_WAIT) ?
-               ipv6_only_sock(sk) : tcptw_sk_ipv6only(sk);
-}
-#else
-# define __tcp_v6_rcv_saddr(__sk)      NULL
-# define tcp_v6_rcv_saddr(__sk)                NULL
-# define tcptw_sk_ipv6only(__sk)       0
-# define tcp_v6_ipv6only(__sk)         0
-#endif
+#include <linux/seq_file.h>
 
-extern kmem_cache_t *tcp_timewait_cachep;
-
-static inline void tcp_tw_put(struct tcp_tw_bucket *tw)
-{
-       if (atomic_dec_and_test(&tw->tw_refcnt)) {
-#ifdef INET_REFCNT_DEBUG
-               printk(KERN_DEBUG "tw_bucket %p released\n", tw);
-#endif
-               kmem_cache_free(tcp_timewait_cachep, tw);
-       }
-}
+extern struct inet_hashinfo tcp_hashinfo;
 
 extern atomic_t tcp_orphan_count;
-extern int tcp_tw_count;
 extern void tcp_time_wait(struct sock *sk, int state, int timeo);
-extern void tcp_tw_deschedule(struct tcp_tw_bucket *tw);
-
-
-/* Socket demux engine toys. */
-#ifdef __BIG_ENDIAN
-#define TCP_COMBINED_PORTS(__sport, __dport) \
-       (((__u32)(__sport)<<16) | (__u32)(__dport))
-#else /* __LITTLE_ENDIAN */
-#define TCP_COMBINED_PORTS(__sport, __dport) \
-       (((__u32)(__dport)<<16) | (__u32)(__sport))
-#endif
-
-#if (BITS_PER_LONG == 64)
-#ifdef __BIG_ENDIAN
-#define TCP_V4_ADDR_COOKIE(__name, __saddr, __daddr) \
-       __u64 __name = (((__u64)(__saddr))<<32)|((__u64)(__daddr));
-#else /* __LITTLE_ENDIAN */
-#define TCP_V4_ADDR_COOKIE(__name, __saddr, __daddr) \
-       __u64 __name = (((__u64)(__daddr))<<32)|((__u64)(__saddr));
-#endif /* __BIG_ENDIAN */
-#define TCP_IPV4_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\
-       (((*((__u64 *)&(inet_sk(__sk)->daddr)))== (__cookie))   &&      \
-        ((*((__u32 *)&(inet_sk(__sk)->dport)))== (__ports))    &&      \
-        (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
-#define TCP_IPV4_TW_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\
-       (((*((__u64 *)&(tcptw_sk(__sk)->tw_daddr))) == (__cookie)) &&   \
-        ((*((__u32 *)&(tcptw_sk(__sk)->tw_dport))) == (__ports)) &&    \
-        (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
-#else /* 32-bit arch */
-#define TCP_V4_ADDR_COOKIE(__name, __saddr, __daddr)
-#define TCP_IPV4_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\
-       ((inet_sk(__sk)->daddr                  == (__saddr))   &&      \
-        (inet_sk(__sk)->rcv_saddr              == (__daddr))   &&      \
-        ((*((__u32 *)&(inet_sk(__sk)->dport)))== (__ports))    &&      \
-        (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
-#define TCP_IPV4_TW_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\
-       ((tcptw_sk(__sk)->tw_daddr              == (__saddr))   &&      \
-        (tcptw_sk(__sk)->tw_rcv_saddr          == (__daddr))   &&      \
-        ((*((__u32 *)&(tcptw_sk(__sk)->tw_dport))) == (__ports)) &&    \
-        (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
-#endif /* 64-bit arch */
-
-#define TCP_IPV6_MATCH(__sk, __saddr, __daddr, __ports, __dif)    \
-       (((*((__u32 *)&(inet_sk(__sk)->dport)))== (__ports))    && \
-        ((__sk)->sk_family             == AF_INET6)            && \
-        ipv6_addr_equal(&inet6_sk(__sk)->daddr, (__saddr))     && \
-        ipv6_addr_equal(&inet6_sk(__sk)->rcv_saddr, (__daddr)) && \
-        (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
-
-/* These can have wildcards, don't try too hard. */
-static __inline__ int tcp_lhashfn(unsigned short num)
-{
-       return num & (TCP_LHTABLE_SIZE - 1);
-}
-
-static __inline__ int tcp_sk_listen_hashfn(struct sock *sk)
-{
-       return tcp_lhashfn(inet_sk(sk)->num);
-}
 
 #define MAX_TCP_HEADER (128 + MAX_HEADER)
 
@@ -478,33 +147,6 @@ static __inline__ int tcp_sk_listen_hashfn(struct sock *sk)
                                         * timestamps. It must be less than
                                         * minimal timewait lifetime.
                                         */
-
-#define TCP_TW_RECYCLE_SLOTS_LOG       5
-#define TCP_TW_RECYCLE_SLOTS           (1<<TCP_TW_RECYCLE_SLOTS_LOG)
-
-/* If time > 4sec, it is "slow" path, no recycling is required,
-   so that we select tick to get range about 4 seconds.
- */
-
-#if HZ <= 16 || HZ > 4096
-# error Unsupported: HZ <= 16 or HZ > 4096
-#elif HZ <= 32
-# define TCP_TW_RECYCLE_TICK (5+2-TCP_TW_RECYCLE_SLOTS_LOG)
-#elif HZ <= 64
-# define TCP_TW_RECYCLE_TICK (6+2-TCP_TW_RECYCLE_SLOTS_LOG)
-#elif HZ <= 128
-# define TCP_TW_RECYCLE_TICK (7+2-TCP_TW_RECYCLE_SLOTS_LOG)
-#elif HZ <= 256
-# define TCP_TW_RECYCLE_TICK (8+2-TCP_TW_RECYCLE_SLOTS_LOG)
-#elif HZ <= 512
-# define TCP_TW_RECYCLE_TICK (9+2-TCP_TW_RECYCLE_SLOTS_LOG)
-#elif HZ <= 1024
-# define TCP_TW_RECYCLE_TICK (10+2-TCP_TW_RECYCLE_SLOTS_LOG)
-#elif HZ <= 2048
-# define TCP_TW_RECYCLE_TICK (11+2-TCP_TW_RECYCLE_SLOTS_LOG)
-#else
-# define TCP_TW_RECYCLE_TICK (12+2-TCP_TW_RECYCLE_SLOTS_LOG)
-#endif
 /*
  *     TCP option
  */
@@ -534,22 +176,18 @@ static __inline__ int tcp_sk_listen_hashfn(struct sock *sk)
 #define TCPOLEN_SACK_BASE_ALIGNED      4
 #define TCPOLEN_SACK_PERBLOCK          8
 
-#define TCP_TIME_RETRANS       1       /* Retransmit timer */
-#define TCP_TIME_DACK          2       /* Delayed ack timer */
-#define TCP_TIME_PROBE0                3       /* Zero window probe timer */
-#define TCP_TIME_KEEPOPEN      4       /* Keepalive timer */
-
 /* Flags in tp->nonagle */
 #define TCP_NAGLE_OFF          1       /* Nagle's algo is disabled */
 #define TCP_NAGLE_CORK         2       /* Socket is corked         */
 #define TCP_NAGLE_PUSH         4       /* Cork is overriden for already queued data */
 
+extern struct inet_timewait_death_row tcp_death_row;
+
 /* sysctl variables for tcp */
 extern int sysctl_tcp_timestamps;
 extern int sysctl_tcp_window_scaling;
 extern int sysctl_tcp_sack;
 extern int sysctl_tcp_fin_timeout;
-extern int sysctl_tcp_tw_recycle;
 extern int sysctl_tcp_keepalive_time;
 extern int sysctl_tcp_keepalive_probes;
 extern int sysctl_tcp_keepalive_intvl;
@@ -564,7 +202,6 @@ extern int sysctl_tcp_stdurg;
 extern int sysctl_tcp_rfc1337;
 extern int sysctl_tcp_abort_on_overflow;
 extern int sysctl_tcp_max_orphans;
-extern int sysctl_tcp_max_tw_buckets;
 extern int sysctl_tcp_fack;
 extern int sysctl_tcp_reordering;
 extern int sysctl_tcp_ecn;
@@ -585,12 +222,6 @@ extern atomic_t tcp_memory_allocated;
 extern atomic_t tcp_sockets_allocated;
 extern int tcp_memory_pressure;
 
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-#define TCP_INET_FAMILY(fam) ((fam) == AF_INET)
-#else
-#define TCP_INET_FAMILY(fam) 1
-#endif
-
 /*
  *     Pointers to address related TCP functions
  *     (i.e. things that depend on the address family)
@@ -671,9 +302,6 @@ DECLARE_SNMP_STAT(struct tcp_mib, tcp_statistics);
 #define TCP_ADD_STATS_BH(field, val)   SNMP_ADD_STATS_BH(tcp_statistics, field, val)
 #define TCP_ADD_STATS_USER(field, val) SNMP_ADD_STATS_USER(tcp_statistics, field, val)
 
-extern void                    tcp_put_port(struct sock *sk);
-extern void                    tcp_inherit_port(struct sock *sk, struct sock *child);
-
 extern void                    tcp_v4_err(struct sk_buff *skb, u32);
 
 extern void                    tcp_shutdown (struct sock *sk, int how);
@@ -682,7 +310,7 @@ extern int                  tcp_v4_rcv(struct sk_buff *skb);
 
 extern int                     tcp_v4_remember_stamp(struct sock *sk);
 
-extern int                     tcp_v4_tw_remember_stamp(struct tcp_tw_bucket *tw);
+extern int                     tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);
 
 extern int                     tcp_sendmsg(struct kiocb *iocb, struct sock *sk,
                                            struct msghdr *msg, size_t size);
@@ -704,42 +332,22 @@ extern int                        tcp_rcv_established(struct sock *sk,
 
 extern void                    tcp_rcv_space_adjust(struct sock *sk);
 
-enum tcp_ack_state_t
-{
-       TCP_ACK_SCHED = 1,
-       TCP_ACK_TIMER = 2,
-       TCP_ACK_PUSHED= 4
-};
-
-static inline void tcp_schedule_ack(struct tcp_sock *tp)
+static inline void tcp_dec_quickack_mode(struct sock *sk,
+                                        const unsigned int pkts)
 {
-       tp->ack.pending |= TCP_ACK_SCHED;
-}
-
-static inline int tcp_ack_scheduled(struct tcp_sock *tp)
-{
-       return tp->ack.pending&TCP_ACK_SCHED;
-}
-
-static __inline__ void tcp_dec_quickack_mode(struct tcp_sock *tp, unsigned int pkts)
-{
-       if (tp->ack.quick) {
-               if (pkts >= tp->ack.quick) {
-                       tp->ack.quick = 0;
+       struct inet_connection_sock *icsk = inet_csk(sk);
 
+       if (icsk->icsk_ack.quick) {
+               if (pkts >= icsk->icsk_ack.quick) {
+                       icsk->icsk_ack.quick = 0;
                        /* Leaving quickack mode we deflate ATO. */
-                       tp->ack.ato = TCP_ATO_MIN;
+                       icsk->icsk_ack.ato   = TCP_ATO_MIN;
                } else
-                       tp->ack.quick -= pkts;
+                       icsk->icsk_ack.quick -= pkts;
        }
 }
 
-extern void tcp_enter_quickack_mode(struct tcp_sock *tp);
-
-static __inline__ void tcp_delack_init(struct tcp_sock *tp)
-{
-       memset(&tp->ack, 0, sizeof(tp->ack));
-}
+extern void tcp_enter_quickack_mode(struct sock *sk);
 
 static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
 {
@@ -755,10 +363,9 @@ enum tcp_tw_status
 };
 
 
-extern enum tcp_tw_status      tcp_timewait_state_process(struct tcp_tw_bucket *tw,
+extern enum tcp_tw_status      tcp_timewait_state_process(struct inet_timewait_sock *tw,
                                                           struct sk_buff *skb,
-                                                          struct tcphdr *th,
-                                                          unsigned len);
+                                                          const struct tcphdr *th);
 
 extern struct sock *           tcp_check_req(struct sock *sk,struct sk_buff *skb,
                                              struct request_sock *req,
@@ -773,7 +380,6 @@ extern void                 tcp_update_metrics(struct sock *sk);
 
 extern void                    tcp_close(struct sock *sk, 
                                          long timeout);
-extern struct sock *           tcp_accept(struct sock *sk, int flags, int *err);
 extern unsigned int            tcp_poll(struct file * file, struct socket *sock, struct poll_table_struct *wait);
 
 extern int                     tcp_getsockopt(struct sock *sk, int level, 
@@ -789,8 +395,6 @@ extern int                  tcp_recvmsg(struct kiocb *iocb, struct sock *sk,
                                            size_t len, int nonblock, 
                                            int flags, int *addr_len);
 
-extern int                     tcp_listen_start(struct sock *sk);
-
 extern void                    tcp_parse_options(struct sk_buff *skb,
                                                  struct tcp_options_received *opt_rx,
                                                  int estab);
@@ -799,11 +403,6 @@ extern void                        tcp_parse_options(struct sk_buff *skb,
  *     TCP v4 functions exported for the inet6 API
  */
 
-extern int                     tcp_v4_rebuild_header(struct sock *sk);
-
-extern int                     tcp_v4_build_header(struct sock *sk, 
-                                                   struct sk_buff *skb);
-
 extern void                    tcp_v4_send_check(struct sock *sk, 
                                                  struct tcphdr *th, int len, 
                                                  struct sk_buff *skb);
@@ -855,6 +454,7 @@ extern int tcp_retransmit_skb(struct sock *, struct sk_buff *);
 extern void tcp_xmit_retransmit_queue(struct sock *);
 extern void tcp_simple_retransmit(struct sock *);
 extern int tcp_trim_head(struct sock *, struct sk_buff *, u32);
+extern int tcp_fragment(struct sock *, struct sk_buff *, u32, unsigned int);
 
 extern void tcp_send_probe0(struct sock *);
 extern void tcp_send_partial(struct sock *);
@@ -872,18 +472,15 @@ extern void tcp_cwnd_application_limited(struct sock *sk);
 
 /* tcp_timer.c */
 extern void tcp_init_xmit_timers(struct sock *);
-extern void tcp_clear_xmit_timers(struct sock *);
+static inline void tcp_clear_xmit_timers(struct sock *sk)
+{
+       inet_csk_clear_xmit_timers(sk);
+}
 
-extern void tcp_delete_keepalive_timer(struct sock *);
-extern void tcp_reset_keepalive_timer(struct sock *, unsigned long);
 extern unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu);
 extern unsigned int tcp_current_mss(struct sock *sk, int large);
 
-#ifdef TCP_DEBUG
-extern const char tcp_timer_bug_msg[];
-#endif
-
-/* tcp_diag.c */
+/* tcp.c */
 extern void tcp_get_info(struct sock *, struct tcp_info *);
 
 /* Read 'sendfile()'-style from a TCP socket */
@@ -892,72 +489,6 @@ typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *,
 extern int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
                         sk_read_actor_t recv_actor);
 
-static inline void tcp_clear_xmit_timer(struct sock *sk, int what)
-{
-       struct tcp_sock *tp = tcp_sk(sk);
-       
-       switch (what) {
-       case TCP_TIME_RETRANS:
-       case TCP_TIME_PROBE0:
-               tp->pending = 0;
-
-#ifdef TCP_CLEAR_TIMERS
-               sk_stop_timer(sk, &tp->retransmit_timer);
-#endif
-               break;
-       case TCP_TIME_DACK:
-               tp->ack.blocked = 0;
-               tp->ack.pending = 0;
-
-#ifdef TCP_CLEAR_TIMERS
-               sk_stop_timer(sk, &tp->delack_timer);
-#endif
-               break;
-       default:
-#ifdef TCP_DEBUG
-               printk(tcp_timer_bug_msg);
-#endif
-               return;
-       };
-
-}
-
-/*
- *     Reset the retransmission timer
- */
-static inline void tcp_reset_xmit_timer(struct sock *sk, int what, unsigned long when)
-{
-       struct tcp_sock *tp = tcp_sk(sk);
-
-       if (when > TCP_RTO_MAX) {
-#ifdef TCP_DEBUG
-               printk(KERN_DEBUG "reset_xmit_timer sk=%p %d when=0x%lx, caller=%p\n", sk, what, when, current_text_addr());
-#endif
-               when = TCP_RTO_MAX;
-       }
-
-       switch (what) {
-       case TCP_TIME_RETRANS:
-       case TCP_TIME_PROBE0:
-               tp->pending = what;
-               tp->timeout = jiffies+when;
-               sk_reset_timer(sk, &tp->retransmit_timer, tp->timeout);
-               break;
-
-       case TCP_TIME_DACK:
-               tp->ack.pending |= TCP_ACK_TIMER;
-               tp->ack.timeout = jiffies+when;
-               sk_reset_timer(sk, &tp->delack_timer, tp->ack.timeout);
-               break;
-
-       default:
-#ifdef TCP_DEBUG
-               printk(tcp_timer_bug_msg);
-#endif
-               return;
-       };
-}
-
 /* Initialize RCV_MSS value.
  * RCV_MSS is an our guess about MSS used by the peer.
  * We haven't any direct information about the MSS.
@@ -975,7 +506,7 @@ static inline void tcp_initialize_rcv_mss(struct sock *sk)
        hint = min(hint, TCP_MIN_RCVMSS);
        hint = max(hint, TCP_MIN_MSS);
 
-       tp->ack.rcv_mss = hint;
+       inet_csk(sk)->icsk_ack.rcv_mss = hint;
 }
 
 static __inline__ void __tcp_fast_path_on(struct tcp_sock *tp, u32 snd_wnd)
@@ -1110,7 +641,8 @@ static inline void tcp_packets_out_inc(struct sock *sk,
 
        tp->packets_out += tcp_skb_pcount(skb);
        if (!orig)
-               tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
+               inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
+                                         inet_csk(sk)->icsk_rto, TCP_RTO_MAX);
 }
 
 static inline void tcp_packets_out_dec(struct tcp_sock *tp, 
@@ -1138,29 +670,29 @@ struct tcp_congestion_ops {
        struct list_head        list;
 
        /* initialize private data (optional) */
-       void (*init)(struct tcp_sock *tp);
+       void (*init)(struct sock *sk);
        /* cleanup private data  (optional) */
-       void (*release)(struct tcp_sock *tp);
+       void (*release)(struct sock *sk);
 
        /* return slow start threshold (required) */
-       u32 (*ssthresh)(struct tcp_sock *tp);
+       u32 (*ssthresh)(struct sock *sk);
        /* lower bound for congestion window (optional) */
-       u32 (*min_cwnd)(struct tcp_sock *tp);
+       u32 (*min_cwnd)(struct sock *sk);
        /* do new cwnd calculation (required) */
-       void (*cong_avoid)(struct tcp_sock *tp, u32 ack,
+       void (*cong_avoid)(struct sock *sk, u32 ack,
                           u32 rtt, u32 in_flight, int good_ack);
        /* round trip time sample per acked packet (optional) */
-       void (*rtt_sample)(struct tcp_sock *tp, u32 usrtt);
+       void (*rtt_sample)(struct sock *sk, u32 usrtt);
        /* call before changing ca_state (optional) */
-       void (*set_state)(struct tcp_sock *tp, u8 new_state);
+       void (*set_state)(struct sock *sk, u8 new_state);
        /* call when cwnd event occurs (optional) */
-       void (*cwnd_event)(struct tcp_sock *tp, enum tcp_ca_event ev);
+       void (*cwnd_event)(struct sock *sk, enum tcp_ca_event ev);
        /* new value of cwnd after loss (optional) */
-       u32  (*undo_cwnd)(struct tcp_sock *tp);
+       u32  (*undo_cwnd)(struct sock *sk);
        /* hook for packet ack accounting (optional) */
-       void (*pkts_acked)(struct tcp_sock *tp, u32 num_acked);
-       /* get info for tcp_diag (optional) */
-       void (*get_info)(struct tcp_sock *tp, u32 ext, struct sk_buff *skb);
+       void (*pkts_acked)(struct sock *sk, u32 num_acked);
+       /* get info for inet_diag (optional) */
+       void (*get_info)(struct sock *sk, u32 ext, struct sk_buff *skb);
 
        char            name[TCP_CA_NAME_MAX];
        struct module   *owner;
@@ -1169,30 +701,34 @@ struct tcp_congestion_ops {
 extern int tcp_register_congestion_control(struct tcp_congestion_ops *type);
 extern void tcp_unregister_congestion_control(struct tcp_congestion_ops *type);
 
-extern void tcp_init_congestion_control(struct tcp_sock *tp);
-extern void tcp_cleanup_congestion_control(struct tcp_sock *tp);
+extern void tcp_init_congestion_control(struct sock *sk);
+extern void tcp_cleanup_congestion_control(struct sock *sk);
 extern int tcp_set_default_congestion_control(const char *name);
 extern void tcp_get_default_congestion_control(char *name);
-extern int tcp_set_congestion_control(struct tcp_sock *tp, const char *name);
+extern int tcp_set_congestion_control(struct sock *sk, const char *name);
 
 extern struct tcp_congestion_ops tcp_init_congestion_ops;
-extern u32 tcp_reno_ssthresh(struct tcp_sock *tp);
-extern void tcp_reno_cong_avoid(struct tcp_sock *tp, u32 ack,
+extern u32 tcp_reno_ssthresh(struct sock *sk);
+extern void tcp_reno_cong_avoid(struct sock *sk, u32 ack,
                                u32 rtt, u32 in_flight, int flag);
-extern u32 tcp_reno_min_cwnd(struct tcp_sock *tp);
+extern u32 tcp_reno_min_cwnd(struct sock *sk);
 extern struct tcp_congestion_ops tcp_reno;
 
-static inline void tcp_set_ca_state(struct tcp_sock *tp, u8 ca_state)
+static inline void tcp_set_ca_state(struct sock *sk, const u8 ca_state)
 {
-       if (tp->ca_ops->set_state)
-               tp->ca_ops->set_state(tp, ca_state);
-       tp->ca_state = ca_state;
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       if (icsk->icsk_ca_ops->set_state)
+               icsk->icsk_ca_ops->set_state(sk, ca_state);
+       icsk->icsk_ca_state = ca_state;
 }
 
-static inline void tcp_ca_event(struct tcp_sock *tp, enum tcp_ca_event event)
+static inline void tcp_ca_event(struct sock *sk, const enum tcp_ca_event event)
 {
-       if (tp->ca_ops->cwnd_event)
-               tp->ca_ops->cwnd_event(tp, event);
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+
+       if (icsk->icsk_ca_ops->cwnd_event)
+               icsk->icsk_ca_ops->cwnd_event(sk, event);
 }
 
 /* This determines how many packets are "in the network" to the best
@@ -1218,9 +754,10 @@ static __inline__ unsigned int tcp_packets_in_flight(const struct tcp_sock *tp)
  * The exception is rate halving phase, when cwnd is decreasing towards
  * ssthresh.
  */
-static inline __u32 tcp_current_ssthresh(struct tcp_sock *tp)
+static inline __u32 tcp_current_ssthresh(const struct sock *sk)
 {
-       if ((1<<tp->ca_state)&(TCPF_CA_CWR|TCPF_CA_Recovery))
+       const struct tcp_sock *tp = tcp_sk(sk);
+       if ((1 << inet_csk(sk)->icsk_ca_state) & (TCPF_CA_CWR | TCPF_CA_Recovery))
                return tp->snd_ssthresh;
        else
                return max(tp->snd_ssthresh,
@@ -1237,10 +774,13 @@ static inline void tcp_sync_left_out(struct tcp_sock *tp)
 }
 
 /* Set slow start threshold and cwnd not falling to slow start */
-static inline void __tcp_enter_cwr(struct tcp_sock *tp)
+static inline void __tcp_enter_cwr(struct sock *sk)
 {
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+       struct tcp_sock *tp = tcp_sk(sk);
+
        tp->undo_marker = 0;
-       tp->snd_ssthresh = tp->ca_ops->ssthresh(tp);
+       tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk);
        tp->snd_cwnd = min(tp->snd_cwnd,
                           tcp_packets_in_flight(tp) + 1U);
        tp->snd_cwnd_cnt = 0;
@@ -1249,12 +789,14 @@ static inline void __tcp_enter_cwr(struct tcp_sock *tp)
        TCP_ECN_queue_cwr(tp);
 }
 
-static inline void tcp_enter_cwr(struct tcp_sock *tp)
+static inline void tcp_enter_cwr(struct sock *sk)
 {
+       struct tcp_sock *tp = tcp_sk(sk);
+
        tp->prior_ssthresh = 0;
-       if (tp->ca_state < TCP_CA_CWR) {
-               __tcp_enter_cwr(tp);
-               tcp_set_ca_state(tp, TCP_CA_CWR);
+       if (inet_csk(sk)->icsk_ca_state < TCP_CA_CWR) {
+               __tcp_enter_cwr(sk);
+               tcp_set_ca_state(sk, TCP_CA_CWR);
        }
 }
 
@@ -1277,8 +819,10 @@ static __inline__ void tcp_minshall_update(struct tcp_sock *tp, int mss,
 
 static __inline__ void tcp_check_probe_timer(struct sock *sk, struct tcp_sock *tp)
 {
-       if (!tp->packets_out && !tp->pending)
-               tcp_reset_xmit_timer(sk, TCP_TIME_PROBE0, tp->rto);
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+       if (!tp->packets_out && !icsk->icsk_pending)
+               inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0,
+                                         icsk->icsk_rto, TCP_RTO_MAX);
 }
 
 static __inline__ void tcp_push_pending_frames(struct sock *sk,
@@ -1297,9 +841,6 @@ static __inline__ void tcp_update_wl(struct tcp_sock *tp, u32 ack, u32 seq)
        tp->snd_wl1 = seq;
 }
 
-extern void tcp_destroy_sock(struct sock *sk);
-
-
 /*
  * Calculate(/check) TCP checksum
  */
@@ -1359,8 +900,10 @@ static __inline__ int tcp_prequeue(struct sock *sk, struct sk_buff *skb)
                        tp->ucopy.memory = 0;
                } else if (skb_queue_len(&tp->ucopy.prequeue) == 1) {
                        wake_up_interruptible(sk->sk_sleep);
-                       if (!tcp_ack_scheduled(tp))
-                               tcp_reset_xmit_timer(sk, TCP_TIME_DACK, (3*TCP_RTO_MIN)/4);
+                       if (!inet_csk_ack_scheduled(sk))
+                               inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
+                                                         (3 * TCP_RTO_MIN) / 4,
+                                                         TCP_RTO_MAX);
                }
                return 1;
        }
@@ -1393,9 +936,9 @@ static __inline__ void tcp_set_state(struct sock *sk, int state)
                        TCP_INC_STATS(TCP_MIB_ESTABRESETS);
 
                sk->sk_prot->unhash(sk);
-               if (tcp_sk(sk)->bind_hash &&
+               if (inet_csk(sk)->icsk_bind_hash &&
                    !(sk->sk_userlocks & SOCK_BINDPORT_LOCK))
-                       tcp_put_port(sk);
+                       inet_put_port(&tcp_hashinfo, sk);
                /* fall through */
        default:
                if (oldstate==TCP_ESTABLISHED)
@@ -1422,7 +965,7 @@ static __inline__ void tcp_done(struct sock *sk)
        if (!sock_flag(sk, SOCK_DEAD))
                sk->sk_state_change(sk);
        else
-               tcp_destroy_sock(sk);
+               inet_csk_destroy_sock(sk);
 }
 
 static __inline__ void tcp_sack_reset(struct tcp_options_received *rx_opt)
@@ -1524,54 +1067,6 @@ static inline int tcp_full_space(const struct sock *sk)
        return tcp_win_from_space(sk->sk_rcvbuf); 
 }
 
-static inline void tcp_acceptq_queue(struct sock *sk, struct request_sock *req,
-                                        struct sock *child)
-{
-       reqsk_queue_add(&tcp_sk(sk)->accept_queue, req, sk, child);
-}
-
-static inline void
-tcp_synq_removed(struct sock *sk, struct request_sock *req)
-{
-       if (reqsk_queue_removed(&tcp_sk(sk)->accept_queue, req) == 0)
-               tcp_delete_keepalive_timer(sk);
-}
-
-static inline void tcp_synq_added(struct sock *sk)
-{
-       if (reqsk_queue_added(&tcp_sk(sk)->accept_queue) == 0)
-               tcp_reset_keepalive_timer(sk, TCP_TIMEOUT_INIT);
-}
-
-static inline int tcp_synq_len(struct sock *sk)
-{
-       return reqsk_queue_len(&tcp_sk(sk)->accept_queue);
-}
-
-static inline int tcp_synq_young(struct sock *sk)
-{
-       return reqsk_queue_len_young(&tcp_sk(sk)->accept_queue);
-}
-
-static inline int tcp_synq_is_full(struct sock *sk)
-{
-       return reqsk_queue_is_full(&tcp_sk(sk)->accept_queue);
-}
-
-static inline void tcp_synq_unlink(struct tcp_sock *tp, struct request_sock *req,
-                                  struct request_sock **prev)
-{
-       reqsk_queue_unlink(&tp->accept_queue, req, prev);
-}
-
-static inline void tcp_synq_drop(struct sock *sk, struct request_sock *req,
-                                    struct request_sock **prev)
-{
-       tcp_synq_unlink(tcp_sk(sk), req, prev);
-       tcp_synq_removed(sk, req);
-       reqsk_free(req);
-}
-
 static __inline__ void tcp_openreq_init(struct request_sock *req,
                                        struct tcp_options_received *rx_opt,
                                        struct sk_buff *skb)
@@ -1593,27 +1088,6 @@ static __inline__ void tcp_openreq_init(struct request_sock *req,
 
 extern void tcp_enter_memory_pressure(void);
 
-extern void tcp_listen_wlock(void);
-
-/* - We may sleep inside this lock.
- * - If sleeping is not required (or called from BH),
- *   use plain read_(un)lock(&tcp_lhash_lock).
- */
-
-static inline void tcp_listen_lock(void)
-{
-       /* read_lock synchronizes to candidates to writers */
-       read_lock(&tcp_lhash_lock);
-       atomic_inc(&tcp_lhash_users);
-       read_unlock(&tcp_lhash_lock);
-}
-
-static inline void tcp_listen_unlock(void)
-{
-       if (atomic_dec_and_test(&tcp_lhash_users))
-               wake_up(&tcp_lhash_wait);
-}
-
 static inline int keepalive_intvl_when(const struct tcp_sock *tp)
 {
        return tp->keepalive_intvl ? : sysctl_tcp_keepalive_intvl;
@@ -1624,12 +1098,13 @@ static inline int keepalive_time_when(const struct tcp_sock *tp)
        return tp->keepalive_time ? : sysctl_tcp_keepalive_time;
 }
 
-static inline int tcp_fin_time(const struct tcp_sock *tp)
+static inline int tcp_fin_time(const struct sock *sk)
 {
-       int fin_timeout = tp->linger2 ? : sysctl_tcp_fin_timeout;
+       int fin_timeout = tcp_sk(sk)->linger2 ? : sysctl_tcp_fin_timeout;
+       const int rto = inet_csk(sk)->icsk_rto;
 
-       if (fin_timeout < (tp->rto<<2) - (tp->rto>>1))
-               fin_timeout = (tp->rto<<2) - (tp->rto>>1);
+       if (fin_timeout < (rto << 2) - (rto >> 1))
+               fin_timeout = (rto << 2) - (rto >> 1);
 
        return fin_timeout;
 }
@@ -1658,15 +1133,6 @@ static inline int tcp_paws_check(const struct tcp_options_received *rx_opt, int
        return 1;
 }
 
-static inline void tcp_v4_setup_caps(struct sock *sk, struct dst_entry *dst)
-{
-       sk->sk_route_caps = dst->dev->features;
-       if (sk->sk_route_caps & NETIF_F_TSO) {
-               if (sock_flag(sk, SOCK_NO_LARGESEND) || dst->header_len)
-                       sk->sk_route_caps &= ~NETIF_F_TSO;
-       }
-}
-
 #define TCP_CHECK_TIMER(sk) do { } while (0)
 
 static inline int tcp_use_frto(const struct sock *sk)
@@ -1718,4 +1184,16 @@ struct tcp_iter_state {
 extern int tcp_proc_register(struct tcp_seq_afinfo *afinfo);
 extern void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo);
 
+extern struct request_sock_ops tcp_request_sock_ops;
+
+extern int tcp_v4_destroy_sock(struct sock *sk);
+
+#ifdef CONFIG_PROC_FS
+extern int  tcp4_proc_init(void);
+extern void tcp4_proc_exit(void);
+#endif
+
+extern void tcp_v4_init(struct net_proto_family *ops);
+extern void tcp_init(void);
+
 #endif /* _TCP_H */
index 64980ee8c92a9ee77d6c57b1806f7acd290883cf..c6b84397448dac0b810079c96fe1c642773b16fd 100644 (file)
@@ -88,7 +88,7 @@ static inline void TCP_ECN_check_ce(struct tcp_sock *tp, struct sk_buff *skb)
                 * it is surely retransmit. It is not in ECN RFC,
                 * but Linux follows this rule. */
                else if (INET_ECN_is_not_ect((TCP_SKB_CB(skb)->flags)))
-                       tcp_enter_quickack_mode(tp);
+                       tcp_enter_quickack_mode((struct sock *)tp);
        }
 }
 
diff --git a/include/net/tcp_states.h b/include/net/tcp_states.h
new file mode 100644 (file)
index 0000000..b9d4176
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the  BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             Definitions for the TCP protocol sk_state field.
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_TCP_STATES_H
+#define _LINUX_TCP_STATES_H
+
+enum {
+       TCP_ESTABLISHED = 1,
+       TCP_SYN_SENT,
+       TCP_SYN_RECV,
+       TCP_FIN_WAIT1,
+       TCP_FIN_WAIT2,
+       TCP_TIME_WAIT,
+       TCP_CLOSE,
+       TCP_CLOSE_WAIT,
+       TCP_LAST_ACK,
+       TCP_LISTEN,
+       TCP_CLOSING,    /* Now a valid state */
+
+       TCP_MAX_STATES  /* Leave at the end! */
+};
+
+#define TCP_STATE_MASK 0xF
+
+#endif /* _LINUX_TCP_STATES_H */
index ac229b761dbc488b24fb031b1acf51192c6bb927..107b9d791a1f1d31fc478bc31b7fedbe25c2ba22 100644 (file)
@@ -94,6 +94,11 @@ struct udp_iter_state {
        struct seq_operations   seq_ops;
 };
 
+#ifdef CONFIG_PROC_FS
 extern int udp_proc_register(struct udp_seq_afinfo *afinfo);
 extern void udp_proc_unregister(struct udp_seq_afinfo *afinfo);
+
+extern int  udp4_proc_init(void);
+extern void udp4_proc_exit(void);
+#endif
 #endif /* _UDP_H */
index 8b39b98876e89bc4dd2fdf89be43c5d608d5bcee..fee62ff8c1946c78744f7ab880fa67315ad6cd5e 100644 (file)
@@ -175,7 +175,7 @@ extern void x25_kill_by_neigh(struct x25_neigh *);
 
 /* x25_dev.c */
 extern void x25_send_frame(struct sk_buff *, struct x25_neigh *);
-extern int  x25_lapb_receive_frame(struct sk_buff *, struct net_device *, struct packet_type *);
+extern int  x25_lapb_receive_frame(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
 extern void x25_establish_link(struct x25_neigh *);
 extern void x25_terminate_link(struct x25_neigh *);
 
index d45ae883bd1dabebf1e304bf29e6e5c382267a5f..1a318374faefc42e853ab4692b9aeb046aebda46 100644 (file)
@@ -8,7 +8,6 @@
 static inline __be16 x25_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
        skb->mac.raw = skb->data;
-       skb->input_dev = skb->dev = dev;
        skb->pkt_type = PACKET_HOST;
        
        return htons(ETH_P_X25);
index 868ef88ef9711c0fd3065deb9780537a301283ed..a9d0d8c5dfbffa04c1ca67ccb35e464940301833 100644 (file)
@@ -818,7 +818,6 @@ extern void xfrm6_init(void);
 extern void xfrm6_fini(void);
 extern void xfrm_state_init(void);
 extern void xfrm4_state_init(void);
-extern void xfrm4_state_fini(void);
 extern void xfrm6_state_init(void);
 extern void xfrm6_state_fini(void);
 
similarity index 96%
rename from drivers/infiniband/include/ib_cache.h
rename to include/rdma/ib_cache.h
index 44ef6bb9b9df49ec95cc9c0a73eb4429fb975983..5bf9834f7dcae588f126a8800f6685654e1bb881 100644 (file)
@@ -1,5 +1,7 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Intel Corporation. All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -35,7 +37,7 @@
 #ifndef _IB_CACHE_H
 #define _IB_CACHE_H
 
-#include <ib_verbs.h>
+#include <rdma/ib_verbs.h>
 
 /**
  * ib_get_cached_gid - Returns a cached GID table entry
similarity index 88%
rename from drivers/infiniband/include/ib_cm.h
rename to include/rdma/ib_cm.h
index da650115e79adcec3caedb94a4dbc2eb8da6167d..77fe9039209b1612590fcf7923fc1faaf8b1c8a7 100644 (file)
@@ -37,8 +37,8 @@
 #if !defined(IB_CM_H)
 #define IB_CM_H
 
-#include <ib_mad.h>
-#include <ib_sa.h>
+#include <rdma/ib_mad.h>
+#include <rdma/ib_sa.h>
 
 enum ib_cm_state {
        IB_CM_IDLE,
@@ -115,7 +115,7 @@ struct ib_cm_req_event_param {
        struct ib_sa_path_rec   *primary_path;
        struct ib_sa_path_rec   *alternate_path;
 
-       u64                     remote_ca_guid;
+       __be64                  remote_ca_guid;
        u32                     remote_qkey;
        u32                     remote_qpn;
        enum ib_qp_type         qp_type;
@@ -132,7 +132,7 @@ struct ib_cm_req_event_param {
 };
 
 struct ib_cm_rep_event_param {
-       u64                     remote_ca_guid;
+       __be64                  remote_ca_guid;
        u32                     remote_qkey;
        u32                     remote_qpn;
        u32                     starting_psn;
@@ -146,39 +146,39 @@ struct ib_cm_rep_event_param {
 };
 
 enum ib_cm_rej_reason {
-       IB_CM_REJ_NO_QP                         = __constant_htons(1),
-       IB_CM_REJ_NO_EEC                        = __constant_htons(2),
-       IB_CM_REJ_NO_RESOURCES                  = __constant_htons(3),
-       IB_CM_REJ_TIMEOUT                       = __constant_htons(4),
-       IB_CM_REJ_UNSUPPORTED                   = __constant_htons(5),
-       IB_CM_REJ_INVALID_COMM_ID               = __constant_htons(6),
-       IB_CM_REJ_INVALID_COMM_INSTANCE         = __constant_htons(7),
-       IB_CM_REJ_INVALID_SERVICE_ID            = __constant_htons(8),
-       IB_CM_REJ_INVALID_TRANSPORT_TYPE        = __constant_htons(9),
-       IB_CM_REJ_STALE_CONN                    = __constant_htons(10),
-       IB_CM_REJ_RDC_NOT_EXIST                 = __constant_htons(11),
-       IB_CM_REJ_INVALID_GID                   = __constant_htons(12),
-       IB_CM_REJ_INVALID_LID                   = __constant_htons(13),
-       IB_CM_REJ_INVALID_SL                    = __constant_htons(14),
-       IB_CM_REJ_INVALID_TRAFFIC_CLASS         = __constant_htons(15),
-       IB_CM_REJ_INVALID_HOP_LIMIT             = __constant_htons(16),
-       IB_CM_REJ_INVALID_PACKET_RATE           = __constant_htons(17),
-       IB_CM_REJ_INVALID_ALT_GID               = __constant_htons(18),
-       IB_CM_REJ_INVALID_ALT_LID               = __constant_htons(19),
-       IB_CM_REJ_INVALID_ALT_SL                = __constant_htons(20),
-       IB_CM_REJ_INVALID_ALT_TRAFFIC_CLASS     = __constant_htons(21),
-       IB_CM_REJ_INVALID_ALT_HOP_LIMIT         = __constant_htons(22),
-       IB_CM_REJ_INVALID_ALT_PACKET_RATE       = __constant_htons(23),
-       IB_CM_REJ_PORT_CM_REDIRECT              = __constant_htons(24),
-       IB_CM_REJ_PORT_REDIRECT                 = __constant_htons(25),
-       IB_CM_REJ_INVALID_MTU                   = __constant_htons(26),
-       IB_CM_REJ_INSUFFICIENT_RESP_RESOURCES   = __constant_htons(27),
-       IB_CM_REJ_CONSUMER_DEFINED              = __constant_htons(28),
-       IB_CM_REJ_INVALID_RNR_RETRY             = __constant_htons(29),
-       IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID       = __constant_htons(30),
-       IB_CM_REJ_INVALID_CLASS_VERSION         = __constant_htons(31),
-       IB_CM_REJ_INVALID_FLOW_LABEL            = __constant_htons(32),
-       IB_CM_REJ_INVALID_ALT_FLOW_LABEL        = __constant_htons(33)
+       IB_CM_REJ_NO_QP                         = 1,
+       IB_CM_REJ_NO_EEC                        = 2,
+       IB_CM_REJ_NO_RESOURCES                  = 3,
+       IB_CM_REJ_TIMEOUT                       = 4,
+       IB_CM_REJ_UNSUPPORTED                   = 5,
+       IB_CM_REJ_INVALID_COMM_ID               = 6,
+       IB_CM_REJ_INVALID_COMM_INSTANCE         = 7,
+       IB_CM_REJ_INVALID_SERVICE_ID            = 8,
+       IB_CM_REJ_INVALID_TRANSPORT_TYPE        = 9,
+       IB_CM_REJ_STALE_CONN                    = 10,
+       IB_CM_REJ_RDC_NOT_EXIST                 = 11,
+       IB_CM_REJ_INVALID_GID                   = 12,
+       IB_CM_REJ_INVALID_LID                   = 13,
+       IB_CM_REJ_INVALID_SL                    = 14,
+       IB_CM_REJ_INVALID_TRAFFIC_CLASS         = 15,
+       IB_CM_REJ_INVALID_HOP_LIMIT             = 16,
+       IB_CM_REJ_INVALID_PACKET_RATE           = 17,
+       IB_CM_REJ_INVALID_ALT_GID               = 18,
+       IB_CM_REJ_INVALID_ALT_LID               = 19,
+       IB_CM_REJ_INVALID_ALT_SL                = 20,
+       IB_CM_REJ_INVALID_ALT_TRAFFIC_CLASS     = 21,
+       IB_CM_REJ_INVALID_ALT_HOP_LIMIT         = 22,
+       IB_CM_REJ_INVALID_ALT_PACKET_RATE       = 23,
+       IB_CM_REJ_PORT_CM_REDIRECT              = 24,
+       IB_CM_REJ_PORT_REDIRECT                 = 25,
+       IB_CM_REJ_INVALID_MTU                   = 26,
+       IB_CM_REJ_INSUFFICIENT_RESP_RESOURCES   = 27,
+       IB_CM_REJ_CONSUMER_DEFINED              = 28,
+       IB_CM_REJ_INVALID_RNR_RETRY             = 29,
+       IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID       = 30,
+       IB_CM_REJ_INVALID_CLASS_VERSION         = 31,
+       IB_CM_REJ_INVALID_FLOW_LABEL            = 32,
+       IB_CM_REJ_INVALID_ALT_FLOW_LABEL        = 33
 };
 
 struct ib_cm_rej_event_param {
@@ -222,8 +222,7 @@ struct ib_cm_sidr_req_event_param {
        struct ib_cm_id         *listen_id;
        struct ib_device        *device;
        u8                      port;
-
-       u16     pkey;
+       u16                     pkey;
 };
 
 enum ib_cm_sidr_status {
@@ -285,12 +284,12 @@ typedef int (*ib_cm_handler)(struct ib_cm_id *cm_id,
 struct ib_cm_id {
        ib_cm_handler           cm_handler;
        void                    *context;
-       u64                     service_id;
-       u64                     service_mask;
+       __be64                  service_id;
+       __be64                  service_mask;
        enum ib_cm_state        state;          /* internal CM/debug use */
        enum ib_cm_lap_state    lap_state;      /* internal CM/debug use */
-       u32                     local_id;
-       u32                     remote_id;
+       __be32                  local_id;
+       __be32                  remote_id;
 };
 
 /**
@@ -330,13 +329,13 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id);
  *   IB_CM_ASSIGN_SERVICE_ID.
  */
 int ib_cm_listen(struct ib_cm_id *cm_id,
-                u64 service_id,
-                u64 service_mask);
+                __be64 service_id,
+                __be64 service_mask);
 
 struct ib_cm_req_param {
        struct ib_sa_path_rec   *primary_path;
        struct ib_sa_path_rec   *alternate_path;
-       u64                     service_id;
+       __be64                  service_id;
        u32                     qp_num;
        enum ib_qp_type         qp_type;
        u32                     starting_psn;
@@ -528,7 +527,7 @@ int ib_send_cm_apr(struct ib_cm_id *cm_id,
 
 struct ib_cm_sidr_req_param {
        struct ib_sa_path_rec   *path;
-       u64                     service_id;
+       __be64                  service_id;
        int                     timeout_ms;
        const void              *private_data;
        u8                      private_data_len;
similarity index 99%
rename from drivers/infiniband/include/ib_fmr_pool.h
rename to include/rdma/ib_fmr_pool.h
index 6c9e24d6e1448968e583577ede6972f982a2f46e..86b7e93f198b429959c70dbf20d5782bb24a351a 100644 (file)
@@ -36,7 +36,7 @@
 #if !defined(IB_FMR_POOL_H)
 #define IB_FMR_POOL_H
 
-#include <ib_verbs.h>
+#include <rdma/ib_verbs.h>
 
 struct ib_fmr_pool;
 
similarity index 98%
rename from drivers/infiniband/include/ib_mad.h
rename to include/rdma/ib_mad.h
index 491b6f25b3b854afa6ac796d6f1042e4d7778b03..fc6b1c18ffc698fae47992646c2abed213a9ac3a 100644 (file)
@@ -41,7 +41,7 @@
 
 #include <linux/pci.h>
 
-#include <ib_verbs.h>
+#include <rdma/ib_verbs.h>
 
 /* Management base version */
 #define IB_MGMT_BASE_VERSION                   1
@@ -90,6 +90,7 @@
 
 #define        IB_MGMT_RMPP_STATUS_SUCCESS             0
 #define        IB_MGMT_RMPP_STATUS_RESX                1
+#define        IB_MGMT_RMPP_STATUS_ABORT_MIN           118
 #define        IB_MGMT_RMPP_STATUS_T2L                 118
 #define        IB_MGMT_RMPP_STATUS_BAD_LEN             119
 #define        IB_MGMT_RMPP_STATUS_BAD_SEG             120
 #define        IB_MGMT_RMPP_STATUS_UNV                 125
 #define        IB_MGMT_RMPP_STATUS_TMR                 126
 #define        IB_MGMT_RMPP_STATUS_UNSPEC              127
+#define        IB_MGMT_RMPP_STATUS_ABORT_MAX           127
 
 #define IB_QP0         0
 #define IB_QP1         __constant_htonl(1)
@@ -111,12 +113,12 @@ struct ib_mad_hdr {
        u8      mgmt_class;
        u8      class_version;
        u8      method;
-       u16     status;
-       u16     class_specific;
-       u64     tid;
-       u16     attr_id;
-       u16     resv;
-       u32     attr_mod;
+       __be16  status;
+       __be16  class_specific;
+       __be64  tid;
+       __be16  attr_id;
+       __be16  resv;
+       __be32  attr_mod;
 };
 
 struct ib_rmpp_hdr {
@@ -124,8 +126,8 @@ struct ib_rmpp_hdr {
        u8      rmpp_type;
        u8      rmpp_rtime_flags;
        u8      rmpp_status;
-       u32     seg_num;
-       u32     paylen_newwin;
+       __be32  seg_num;
+       __be32  paylen_newwin;
 };
 
 typedef u64 __bitwise ib_sa_comp_mask;
@@ -139,9 +141,9 @@ typedef u64 __bitwise ib_sa_comp_mask;
  * the wire so we can't change the layout)
  */
 struct ib_sa_hdr {
-       u64                     sm_key;
-       u16                     attr_offset;
-       u16                     reserved;
+       __be64                  sm_key;
+       __be16                  attr_offset;
+       __be16                  reserved;
        ib_sa_comp_mask         comp_mask;
 } __attribute__ ((packed));
 
similarity index 99%
rename from drivers/infiniband/include/ib_pack.h
rename to include/rdma/ib_pack.h
index fe480f3e8654d8afb1fee3d5a158e9860fc60f1b..f926020d63314dc2a5a43fd047ea4ef95d43bc36 100644 (file)
@@ -35,7 +35,7 @@
 #ifndef IB_PACK_H
 #define IB_PACK_H
 
-#include <ib_verbs.h>
+#include <rdma/ib_verbs.h>
 
 enum {
        IB_LRH_BYTES  = 8,
similarity index 98%
rename from drivers/infiniband/include/ib_sa.h
rename to include/rdma/ib_sa.h
index 6d999f7b5d93fd5146ceb02b4988f0cc00433e5e..c022edfc49da013844509e4b4ff22368449cae9c 100644 (file)
@@ -38,8 +38,8 @@
 
 #include <linux/compiler.h>
 
-#include <ib_verbs.h>
-#include <ib_mad.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_mad.h>
 
 enum {
        IB_SA_CLASS_VERSION             = 2,    /* IB spec version 1.1/1.2 */
@@ -133,16 +133,16 @@ struct ib_sa_path_rec {
        /* reserved */
        union ib_gid dgid;
        union ib_gid sgid;
-       u16          dlid;
-       u16          slid;
+       __be16       dlid;
+       __be16       slid;
        int          raw_traffic;
        /* reserved */
-       u32          flow_label;
+       __be32       flow_label;
        u8           hop_limit;
        u8           traffic_class;
        int          reversible;
        u8           numb_path;
-       u16          pkey;
+       __be16       pkey;
        /* reserved */
        u8           sl;
        u8           mtu_selector;
@@ -176,18 +176,18 @@ struct ib_sa_path_rec {
 struct ib_sa_mcmember_rec {
        union ib_gid mgid;
        union ib_gid port_gid;
-       u32          qkey;
-       u16          mlid;
+       __be32       qkey;
+       __be16       mlid;
        u8           mtu_selector;
        u8           mtu;
        u8           traffic_class;
-       u16          pkey;
+       __be16       pkey;
        u8           rate_selector;
        u8           rate;
        u8           packet_life_time_selector;
        u8           packet_life_time;
        u8           sl;
-       u32          flow_label;
+       __be32       flow_label;
        u8           hop_limit;
        u8           scope;
        u8           join_state;
@@ -238,7 +238,7 @@ struct ib_sa_mcmember_rec {
 struct ib_sa_service_rec {
        u64             id;
        union ib_gid    gid;
-       u16             pkey;
+       __be16          pkey;
        /* reserved */
        u32             lease;
        u8              key[16];
similarity index 95%
rename from drivers/infiniband/include/ib_smi.h
rename to include/rdma/ib_smi.h
index ca82165149639e1d4cba6591f63a2d33e90dcfb0..87f60737f69575e2b86426f3cbaa592638dca151 100644 (file)
@@ -39,9 +39,7 @@
 #if !defined( IB_SMI_H )
 #define IB_SMI_H
 
-#include <ib_mad.h>
-
-#define IB_LID_PERMISSIVE                      0xFFFF
+#include <rdma/ib_mad.h>
 
 #define IB_SMP_DATA_SIZE                       64
 #define IB_SMP_MAX_PATH_HOPS                   64
@@ -51,16 +49,16 @@ struct ib_smp {
        u8      mgmt_class;
        u8      class_version;
        u8      method;
-       u16     status;
+       __be16  status;
        u8      hop_ptr;
        u8      hop_cnt;
-       u64     tid;
-       u16     attr_id;
-       u16     resv;
-       u32     attr_mod;
-       u64     mkey;
-       u16     dr_slid;
-       u16     dr_dlid;
+       __be64  tid;
+       __be16  attr_id;
+       __be16  resv;
+       __be32  attr_mod;
+       __be64  mkey;
+       __be16  dr_slid;
+       __be16  dr_dlid;
        u8      reserved[28];
        u8      data[IB_SMP_DATA_SIZE];
        u8      initial_path[IB_SMP_MAX_PATH_HOPS];
similarity index 95%
rename from drivers/infiniband/include/ib_user_cm.h
rename to include/rdma/ib_user_cm.h
index 500b1af6ff773e00b78f7c3f765f8b94084d7fee..72182d16778b5dabd3a64157b17e8eb9cb0d267f 100644 (file)
@@ -88,15 +88,15 @@ struct ib_ucm_attr_id {
 };
 
 struct ib_ucm_attr_id_resp {
-       __u64 service_id;
-       __u64 service_mask;
-       __u32 local_id;
-       __u32 remote_id;
+       __be64 service_id;
+       __be64 service_mask;
+       __be32 local_id;
+       __be32 remote_id;
 };
 
 struct ib_ucm_listen {
-       __u64 service_id;
-       __u64 service_mask;
+       __be64 service_id;
+       __be64 service_mask;
        __u32 id;
 };
 
@@ -114,13 +114,13 @@ struct ib_ucm_private_data {
 struct ib_ucm_path_rec {
        __u8  dgid[16];
        __u8  sgid[16];
-       __u16 dlid;
-       __u16 slid;
+       __be16 dlid;
+       __be16 slid;
        __u32 raw_traffic;
-       __u32 flow_label;
+       __be32 flow_label;
        __u32 reversible;
        __u32 mtu;
-       __u16 pkey;
+       __be16 pkey;
        __u8  hop_limit;
        __u8  traffic_class;
        __u8  numb_path;
@@ -138,7 +138,7 @@ struct ib_ucm_req {
        __u32 qpn;
        __u32 qp_type;
        __u32 psn;
-       __u64 sid;
+       __be64 sid;
        __u64 data;
        __u64 primary_path;
        __u64 alternate_path;
@@ -200,7 +200,7 @@ struct ib_ucm_lap {
 struct ib_ucm_sidr_req {
        __u32 id;
        __u32 timeout;
-       __u64 sid;
+       __be64 sid;
        __u64 data;
        __u64 path;
        __u16 pkey;
@@ -237,7 +237,7 @@ struct ib_ucm_req_event_resp {
        /* port */
        struct ib_ucm_path_rec primary_path;
        struct ib_ucm_path_rec alternate_path;
-       __u64                  remote_ca_guid;
+       __be64                 remote_ca_guid;
        __u32                  remote_qkey;
        __u32                  remote_qpn;
        __u32                  qp_type;
@@ -253,7 +253,7 @@ struct ib_ucm_req_event_resp {
 };
 
 struct ib_ucm_rep_event_resp {
-       __u64 remote_ca_guid;
+       __be64 remote_ca_guid;
        __u32 remote_qkey;
        __u32 remote_qpn;
        __u32 starting_psn;
similarity index 97%
rename from drivers/infiniband/include/ib_user_mad.h
rename to include/rdma/ib_user_mad.h
index a9a56b50aacc229d3529274769e0fa17ec4e75d4..44537aa32e62319072c104058dfe020682576894 100644 (file)
@@ -70,8 +70,6 @@
  * @traffic_class - Traffic class in GRH
  * @gid - Remote GID in GRH
  * @flow_label - Flow label in GRH
- *
- * All multi-byte quantities are stored in network (big endian) byte order.
  */
 struct ib_user_mad_hdr {
        __u32   id;
@@ -79,9 +77,9 @@ struct ib_user_mad_hdr {
        __u32   timeout_ms;
        __u32   retries;
        __u32   length;
-       __u32   qpn;
-       __u32   qkey;
-       __u16   lid;
+       __be32  qpn;
+       __be32  qkey;
+       __be16  lid;
        __u8    sl;
        __u8    path_bits;
        __u8    grh_present;
@@ -89,7 +87,7 @@ struct ib_user_mad_hdr {
        __u8    hop_limit;
        __u8    traffic_class;
        __u8    gid[16];
-       __u32   flow_label;
+       __be32  flow_label;
 };
 
 /**
similarity index 92%
rename from drivers/infiniband/include/ib_user_verbs.h
rename to include/rdma/ib_user_verbs.h
index 7c613706af725f76c08c24903ec7aa1b6ebb7761..7ebb01c8f99638597123d4f4185ebd14be9ab1fa 100644 (file)
@@ -78,7 +78,12 @@ enum {
        IB_USER_VERBS_CMD_POST_SEND,
        IB_USER_VERBS_CMD_POST_RECV,
        IB_USER_VERBS_CMD_ATTACH_MCAST,
-       IB_USER_VERBS_CMD_DETACH_MCAST
+       IB_USER_VERBS_CMD_DETACH_MCAST,
+       IB_USER_VERBS_CMD_CREATE_SRQ,
+       IB_USER_VERBS_CMD_MODIFY_SRQ,
+       IB_USER_VERBS_CMD_QUERY_SRQ,
+       IB_USER_VERBS_CMD_DESTROY_SRQ,
+       IB_USER_VERBS_CMD_POST_SRQ_RECV
 };
 
 /*
@@ -143,8 +148,8 @@ struct ib_uverbs_query_device {
 
 struct ib_uverbs_query_device_resp {
        __u64 fw_ver;
-       __u64 node_guid;
-       __u64 sys_image_guid;
+       __be64 node_guid;
+       __be64 sys_image_guid;
        __u64 max_mr_size;
        __u64 page_size_cap;
        __u32 vendor_id;
@@ -386,4 +391,32 @@ struct ib_uverbs_detach_mcast {
        __u64 driver_data[0];
 };
 
+struct ib_uverbs_create_srq {
+       __u64 response;
+       __u64 user_handle;
+       __u32 pd_handle;
+       __u32 max_wr;
+       __u32 max_sge;
+       __u32 srq_limit;
+       __u64 driver_data[0];
+};
+
+struct ib_uverbs_create_srq_resp {
+       __u32 srq_handle;
+};
+
+struct ib_uverbs_modify_srq {
+       __u32 srq_handle;
+       __u32 attr_mask;
+       __u32 max_wr;
+       __u32 max_sge;
+       __u32 srq_limit;
+       __u32 reserved;
+       __u64 driver_data[0];
+};
+
+struct ib_uverbs_destroy_srq {
+       __u32 srq_handle;
+};
+
 #endif /* IB_USER_VERBS_H */
similarity index 91%
rename from drivers/infiniband/include/ib_verbs.h
rename to include/rdma/ib_verbs.h
index 5d24edaa66e6381b29b32ee4f53995be5f58bdd0..e16cf94870f263936fdcbef502739791a709f11d 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (c) 2004 Intel Corporation.  All rights reserved.
  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
  * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  * Copyright (c) 2005 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -50,8 +51,8 @@
 union ib_gid {
        u8      raw[16];
        struct {
-               u64     subnet_prefix;
-               u64     interface_id;
+               __be64  subnet_prefix;
+               __be64  interface_id;
        } global;
 };
 
@@ -87,8 +88,8 @@ enum ib_atomic_cap {
 
 struct ib_device_attr {
        u64                     fw_ver;
-       u64                     node_guid;
-       u64                     sys_image_guid;
+       __be64                  node_guid;
+       __be64                  sys_image_guid;
        u64                     max_mr_size;
        u64                     page_size_cap;
        u32                     vendor_id;
@@ -255,7 +256,10 @@ enum ib_event_type {
        IB_EVENT_PORT_ERR,
        IB_EVENT_LID_CHANGE,
        IB_EVENT_PKEY_CHANGE,
-       IB_EVENT_SM_CHANGE
+       IB_EVENT_SM_CHANGE,
+       IB_EVENT_SRQ_ERR,
+       IB_EVENT_SRQ_LIMIT_REACHED,
+       IB_EVENT_QP_LAST_WQE_REACHED
 };
 
 struct ib_event {
@@ -263,6 +267,7 @@ struct ib_event {
        union {
                struct ib_cq    *cq;
                struct ib_qp    *qp;
+               struct ib_srq   *srq;
                u8              port_num;
        } element;
        enum ib_event_type      event;
@@ -290,8 +295,8 @@ struct ib_global_route {
 };
 
 struct ib_grh {
-       u32             version_tclass_flow;
-       u16             paylen;
+       __be32          version_tclass_flow;
+       __be16          paylen;
        u8              next_hdr;
        u8              hop_limit;
        union ib_gid    sgid;
@@ -302,6 +307,8 @@ enum {
        IB_MULTICAST_QPN = 0xffffff
 };
 
+#define IB_LID_PERMISSIVE      __constant_htons(0xFFFF)
+
 enum ib_ah_flags {
        IB_AH_GRH       = 1
 };
@@ -383,6 +390,23 @@ enum ib_cq_notify {
        IB_CQ_NEXT_COMP
 };
 
+enum ib_srq_attr_mask {
+       IB_SRQ_MAX_WR   = 1 << 0,
+       IB_SRQ_LIMIT    = 1 << 1,
+};
+
+struct ib_srq_attr {
+       u32     max_wr;
+       u32     max_sge;
+       u32     srq_limit;
+};
+
+struct ib_srq_init_attr {
+       void                  (*event_handler)(struct ib_event *, void *);
+       void                   *srq_context;
+       struct ib_srq_attr      attr;
+};
+
 struct ib_qp_cap {
        u32     max_send_wr;
        u32     max_recv_wr;
@@ -710,10 +734,11 @@ struct ib_cq {
 };
 
 struct ib_srq {
-       struct ib_device        *device;
-       struct ib_uobject       *uobject;
-       struct ib_pd            *pd;
-       void                    *srq_context;
+       struct ib_device       *device;
+       struct ib_pd           *pd;
+       struct ib_uobject      *uobject;
+       void                  (*event_handler)(struct ib_event *, void *);
+       void                   *srq_context;
        atomic_t                usecnt;
 };
 
@@ -827,6 +852,18 @@ struct ib_device {
        int                        (*query_ah)(struct ib_ah *ah,
                                               struct ib_ah_attr *ah_attr);
        int                        (*destroy_ah)(struct ib_ah *ah);
+       struct ib_srq *            (*create_srq)(struct ib_pd *pd,
+                                                struct ib_srq_init_attr *srq_init_attr,
+                                                struct ib_udata *udata);
+       int                        (*modify_srq)(struct ib_srq *srq,
+                                                struct ib_srq_attr *srq_attr,
+                                                enum ib_srq_attr_mask srq_attr_mask);
+       int                        (*query_srq)(struct ib_srq *srq,
+                                               struct ib_srq_attr *srq_attr);
+       int                        (*destroy_srq)(struct ib_srq *srq);
+       int                        (*post_srq_recv)(struct ib_srq *srq,
+                                                   struct ib_recv_wr *recv_wr,
+                                                   struct ib_recv_wr **bad_recv_wr);
        struct ib_qp *             (*create_qp)(struct ib_pd *pd,
                                                struct ib_qp_init_attr *qp_init_attr,
                                                struct ib_udata *udata);
@@ -1038,6 +1075,65 @@ int ib_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr);
  */
 int ib_destroy_ah(struct ib_ah *ah);
 
+/**
+ * ib_create_srq - Creates a SRQ associated with the specified protection
+ *   domain.
+ * @pd: The protection domain associated with the SRQ.
+ * @srq_init_attr: A list of initial attributes required to create the SRQ.
+ *
+ * srq_attr->max_wr and srq_attr->max_sge are read the determine the
+ * requested size of the SRQ, and set to the actual values allocated
+ * on return.  If ib_create_srq() succeeds, then max_wr and max_sge
+ * will always be at least as large as the requested values.
+ */
+struct ib_srq *ib_create_srq(struct ib_pd *pd,
+                            struct ib_srq_init_attr *srq_init_attr);
+
+/**
+ * ib_modify_srq - Modifies the attributes for the specified SRQ.
+ * @srq: The SRQ to modify.
+ * @srq_attr: On input, specifies the SRQ attributes to modify.  On output,
+ *   the current values of selected SRQ attributes are returned.
+ * @srq_attr_mask: A bit-mask used to specify which attributes of the SRQ
+ *   are being modified.
+ *
+ * The mask may contain IB_SRQ_MAX_WR to resize the SRQ and/or
+ * IB_SRQ_LIMIT to set the SRQ's limit and request notification when
+ * the number of receives queued drops below the limit.
+ */
+int ib_modify_srq(struct ib_srq *srq,
+                 struct ib_srq_attr *srq_attr,
+                 enum ib_srq_attr_mask srq_attr_mask);
+
+/**
+ * ib_query_srq - Returns the attribute list and current values for the
+ *   specified SRQ.
+ * @srq: The SRQ to query.
+ * @srq_attr: The attributes of the specified SRQ.
+ */
+int ib_query_srq(struct ib_srq *srq,
+                struct ib_srq_attr *srq_attr);
+
+/**
+ * ib_destroy_srq - Destroys the specified SRQ.
+ * @srq: The SRQ to destroy.
+ */
+int ib_destroy_srq(struct ib_srq *srq);
+
+/**
+ * ib_post_srq_recv - Posts a list of work requests to the specified SRQ.
+ * @srq: The SRQ to post the work request on.
+ * @recv_wr: A list of work requests to post on the receive queue.
+ * @bad_recv_wr: On an immediate failure, this parameter will reference
+ *   the work request that failed to be posted on the QP.
+ */
+static inline int ib_post_srq_recv(struct ib_srq *srq,
+                                  struct ib_recv_wr *recv_wr,
+                                  struct ib_recv_wr **bad_recv_wr)
+{
+       return srq->device->post_srq_recv(srq, recv_wr, bad_recv_wr);
+}
+
 /**
  * ib_create_qp - Creates a QP associated with the specified protection
  *   domain.
index 1309c12b8f71274faf024a944a8244abf17ed5e3..2857cf0472df02116ff7e1c82ddc4a8906752752 100644 (file)
@@ -26,6 +26,7 @@
  */
 
 #include <linux/bitops.h>
+#include <linux/device.h>
 #include "pcm.h"
 #include "control.h"
 #include "info.h"
 #define AC97_HAS_NO_PC_BEEP    (1<<12) /* no PC Beep volume */
 #define AC97_HAS_NO_VIDEO      (1<<13) /* no Video volume */
 #define AC97_HAS_NO_CD         (1<<14) /* no CD volume */
+#define AC97_HAS_NO_MIC        (1<<15) /* no MIC volume */
+#define AC97_HAS_NO_TONE       (1<<16) /* no Tone volume */
+#define AC97_HAS_NO_STD_PCM    (1<<17) /* no standard AC97 PCM volume and mute */
 
 /* rates indexes */
 #define AC97_RATES_FRONT_DAC   0
@@ -520,6 +524,7 @@ struct _snd_ac97 {
        /* jack-sharing info */
        unsigned char indep_surround;
        unsigned char channel_mode;
+       struct device dev;
 };
 
 /* conditions */
@@ -599,4 +604,8 @@ struct ac97_enum {
        unsigned short mask;
        const char **texts;
 };
+
+/* ad hoc AC97 device driver access */
+extern struct bus_type ac97_bus_type;
+
 #endif /* __SOUND_AC97_CODEC_H */
index 395978e375cf7caa870b106b9a0b53287a7002a2..ca2e0e4fa9375d866f3fb4866c515aa0481a173d 100644 (file)
@@ -138,6 +138,7 @@ struct _snd_ad1816a {
        spinlock_t lock;
 
        unsigned short mode;
+       unsigned int clock_freq;
 
        snd_card_t *card;
        snd_pcm_t *pcm;
index 9974f83cca440a88e6e9af4f30e0b7cc2bad767b..8e552d627fa58629dce85cf3408e077f99f132b2 100644 (file)
@@ -560,7 +560,7 @@ enum {
  *  Timer section - /dev/snd/timer
  */
 
-#define SNDRV_TIMER_VERSION            SNDRV_PROTOCOL_VERSION(2, 0, 4)
+#define SNDRV_TIMER_VERSION            SNDRV_PROTOCOL_VERSION(2, 0, 5)
 
 enum sndrv_timer_class {
        SNDRV_TIMER_CLASS_NONE = -1,
@@ -693,11 +693,15 @@ enum sndrv_timer_event {
        SNDRV_TIMER_EVENT_CONTINUE,             /* val = resolution in ns */
        SNDRV_TIMER_EVENT_PAUSE,                /* val = 0 */
        SNDRV_TIMER_EVENT_EARLY,                /* val = 0, early event */
+       SNDRV_TIMER_EVENT_SUSPEND,              /* val = 0 */
+       SNDRV_TIMER_EVENT_RESUME,               /* val = resolution in ns */
        /* master timer events for slave timer instances */
        SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10,
        SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10,
        SNDRV_TIMER_EVENT_MCONTINUE = SNDRV_TIMER_EVENT_CONTINUE + 10,
        SNDRV_TIMER_EVENT_MPAUSE = SNDRV_TIMER_EVENT_PAUSE + 10,
+       SNDRV_TIMER_EVENT_MSUSPEND = SNDRV_TIMER_EVENT_SUSPEND + 10,
+       SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10,
 };
 
 struct sndrv_timer_tread {
index f72b3ef515e25e7d8ca1ee64f7f063a7b8d84f9f..3dc41fd5c54d46730d39c01967c93d05e5b48b32 100644 (file)
@@ -291,12 +291,14 @@ void snd_memory_done(void);
 int snd_memory_info_init(void);
 int snd_memory_info_done(void);
 void *snd_hidden_kmalloc(size_t size, unsigned int __nocast flags);
+void *snd_hidden_kzalloc(size_t size, unsigned int __nocast flags);
 void *snd_hidden_kcalloc(size_t n, size_t size, unsigned int __nocast flags);
 void snd_hidden_kfree(const void *obj);
 void *snd_hidden_vmalloc(unsigned long size);
 void snd_hidden_vfree(void *obj);
 char *snd_hidden_kstrdup(const char *s, unsigned int __nocast flags);
 #define kmalloc(size, flags) snd_hidden_kmalloc(size, flags)
+#define kzalloc(size, flags) snd_hidden_kzalloc(size, flags)
 #define kcalloc(n, size, flags) snd_hidden_kcalloc(n, size, flags)
 #define kfree(obj) snd_hidden_kfree(obj)
 #define vmalloc(size) snd_hidden_vmalloc(size)
index 182dd276ee74552f499de0fdaa08e165407658a3..9b94510eda60224f67d513e27ca1f1b4bd0596d6 100644 (file)
@@ -1748,7 +1748,7 @@ int snd_cs46xx_pcm(cs46xx_t *chip, int device, snd_pcm_t **rpcm);
 int snd_cs46xx_pcm_rear(cs46xx_t *chip, int device, snd_pcm_t **rpcm);
 int snd_cs46xx_pcm_iec958(cs46xx_t *chip, int device, snd_pcm_t **rpcm);
 int snd_cs46xx_pcm_center_lfe(cs46xx_t *chip, int device, snd_pcm_t **rpcm);
-int snd_cs46xx_mixer(cs46xx_t *chip);
+int snd_cs46xx_mixer(cs46xx_t *chip, int spdif_device);
 int snd_cs46xx_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rmidi);
 int snd_cs46xx_start_dsp(cs46xx_t *chip);
 int snd_cs46xx_gameport(cs46xx_t *chip);
index c2ef3f02368793ffaddda2133b907653ab502320..4e3993dfcefef1a9301e0eee798c6554b42cc4cb 100644 (file)
@@ -1178,7 +1178,7 @@ int snd_p16v_free(emu10k1_t * emu);
 int snd_p16v_mixer(emu10k1_t * emu);
 int snd_emu10k1_pcm_multi(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
 int snd_emu10k1_fx8010_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
-int snd_emu10k1_mixer(emu10k1_t * emu);
+int snd_emu10k1_mixer(emu10k1_t * emu, int pcm_device, int multi_device);
 int snd_emu10k1_timer(emu10k1_t * emu, int device);
 int snd_emu10k1_fx8010_new(emu10k1_t *emu, int device, snd_hwdep_t ** rhwdep);
 
index b4b461ca173d6eb72a58ce7a1079b1c1e9417aaf..7000d9d9199d4575dab94b9726c711272122652c 100644 (file)
@@ -512,13 +512,13 @@ extern void snd_gf1_ctrl_stop(snd_gus_card_t * gus, unsigned char reg);
 
 extern void snd_gf1_write8(snd_gus_card_t * gus, unsigned char reg, unsigned char data);
 extern unsigned char snd_gf1_look8(snd_gus_card_t * gus, unsigned char reg);
-extern inline unsigned char snd_gf1_read8(snd_gus_card_t * gus, unsigned char reg)
+static inline unsigned char snd_gf1_read8(snd_gus_card_t * gus, unsigned char reg)
 {
        return snd_gf1_look8(gus, reg | 0x80);
 }
 extern void snd_gf1_write16(snd_gus_card_t * gus, unsigned char reg, unsigned int data);
 extern unsigned short snd_gf1_look16(snd_gus_card_t * gus, unsigned char reg);
-extern inline unsigned short snd_gf1_read16(snd_gus_card_t * gus, unsigned char reg)
+static inline unsigned short snd_gf1_read16(snd_gus_card_t * gus, unsigned char reg)
 {
        return snd_gf1_look16(gus, reg | 0x80);
 }
@@ -532,12 +532,12 @@ extern void snd_gf1_i_ctrl_stop(snd_gus_card_t * gus, unsigned char reg);
 extern void snd_gf1_i_write8(snd_gus_card_t * gus, unsigned char reg, unsigned char data);
 extern unsigned char snd_gf1_i_look8(snd_gus_card_t * gus, unsigned char reg);
 extern void snd_gf1_i_write16(snd_gus_card_t * gus, unsigned char reg, unsigned int data);
-extern inline unsigned char snd_gf1_i_read8(snd_gus_card_t * gus, unsigned char reg)
+static inline unsigned char snd_gf1_i_read8(snd_gus_card_t * gus, unsigned char reg)
 {
        return snd_gf1_i_look8(gus, reg | 0x80);
 }
 extern unsigned short snd_gf1_i_look16(snd_gus_card_t * gus, unsigned char reg);
-extern inline unsigned short snd_gf1_i_read16(snd_gus_card_t * gus, unsigned char reg)
+static inline unsigned short snd_gf1_i_read16(snd_gus_card_t * gus, unsigned char reg)
 {
        return snd_gf1_i_look16(gus, reg | 0x80);
 }
index d935417575b542bd94cc9ba1cff1dcc9c6fd4445..389e8ebe9c191cf550fe824905c5f8f465f4832c 100644 (file)
@@ -379,7 +379,6 @@ struct _snd_pcm_substream {
        unsigned int dma_buf_id;
        size_t dma_max;
        /* -- hardware operations -- */
-       unsigned int open_flag: 1;      /* lowlevel device has been opened */
        snd_pcm_ops_t *ops;
        /* -- runtime information -- */
        snd_pcm_runtime_t *runtime;
@@ -904,7 +903,7 @@ int snd_pcm_format_unsigned(snd_pcm_format_t format);
 int snd_pcm_format_linear(snd_pcm_format_t format);
 int snd_pcm_format_little_endian(snd_pcm_format_t format);
 int snd_pcm_format_big_endian(snd_pcm_format_t format);
-/**
+/*
  * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian
  * @format: the format to check
  *
index c085136f391f3be148c585ba150c9b927e7d2b19..8d19bfabb7e0812caf0963dfb763e92329fb1d82 100644 (file)
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by configure.  */
-#define CONFIG_SND_VERSION "1.0.9b"
-#define CONFIG_SND_DATE " (Thu Jul 28 12:20:13 2005 UTC)"
+#define CONFIG_SND_VERSION "1.0.10rc1"
+#define CONFIG_SND_DATE " (Tue Aug 30 05:31:08 2005 UTC)"
index 4b570684a6aaeee45b75fd974d88f44a52e30bc4..9a3c1e6c820a2d28ddec0cffdaa83cfe7ba81d1f 100644 (file)
@@ -295,6 +295,7 @@ struct _snd_ymfpci_pcm {
        unsigned int running: 1;
        unsigned int output_front: 1;
        unsigned int output_rear: 1;
+       unsigned int update_pcm_vol;
        u32 period_size;                /* cached from runtime->period_size */
        u32 buffer_size;                /* cached from runtime->buffer_size */
        u32 period_pos;
@@ -367,6 +368,11 @@ struct _snd_ymfpci {
        int mode_dup4ch;
        int rear_opened;
        int spdif_opened;
+       struct {
+               u16 left;
+               u16 right;
+               snd_kcontrol_t *ctl;
+       } pcm_mixer[32];
 
        spinlock_t reg_lock;
        spinlock_t voice_lock;
index cebef073b9a3789948e45a50504568d704774679..fceb6c0f65835eec78b1e61a4c348028120d1d42 100644 (file)
@@ -1,24 +1,27 @@
 /*
- *      linux/drivers/video/pmag-ba-fb.h
+ *     linux/include/video/pmag-ba-fb.h
  *
- *      TurboChannel PMAG-BA framebuffer card support,
- *      Copyright (C) 1999,2000,2001 by
- *      Michael Engel <engel@unix-ag.org>,
- *      Karsten Merker <merker@linuxtag.org>
- *      This file is subject to the terms and conditions of the GNU General
- *      Public License.  See the file COPYING in the main directory of this
- *      archive for more details.
- */
-
-/*
- * Bt459 RAM DAC register base offset (rel. to TC slot base address)
+ *     TURBOchannel PMAG-BA Color Frame Buffer (CFB) card support,
+ *     Copyright (C) 1999, 2000, 2001 by
+ *     Michael Engel <engel@unix-ag.org>,
+ *     Karsten Merker <merker@linuxtag.org>
+ *     Copyright (c) 2005  Maciej W. Rozycki
+ *
+ *     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.
  */
 
-#define PMAG_BA_BT459_OFFSET                    0x00200000
-
-/*
- * Begin of PMAG-BA framebuffer memory relative to TC slot address,
- * resolution is 1024x864x8
- */
+/* IOmem resource offsets.  */
+#define PMAG_BA_FBMEM          0x000000        /* frame buffer */
+#define PMAG_BA_BT459          0x200000        /* Bt459 RAMDAC */
+#define PMAG_BA_IRQ            0x300000        /* IRQ acknowledge */
+#define PMAG_BA_ROM            0x380000        /* REX option ROM */
+#define PMAG_BA_BT438          0x380000        /* Bt438 clock chip reset */
+#define PMAG_BA_SIZE           0x400000        /* address space size */
 
-#define PMAG_BA_ONBOARD_FBMEM_OFFSET    0x00000000
+/* Bt459 register offsets, byte-wide registers.  */
+#define BT459_ADDR_LO          0x0             /* address low */
+#define BT459_ADDR_HI          0x4             /* address high */
+#define BT459_DATA             0x8             /* data window register */
+#define BT459_CMAP             0xc             /* color map window register */
index 87b81a555139b2c21181f3db9121cc3168f8d768..7539b9087a80ba2b96887b590c106ea3b4fdd6cf 100644 (file)
@@ -1,32 +1,58 @@
 /*
- *      linux/drivers/video/pmagb-b-fb.h
+ *     linux/include/video/pmagb-b-fb.h
  *
- *      TurboChannel PMAGB-B framebuffer card support,
- *      Copyright (C) 1999, 2000, 2001 by
- *      Michael Engel <engel@unix-ag.org> and 
- *      Karsten Merker <merker@linuxtag.org>
- *      This file is subject to the terms and conditions of the GNU General
- *      Public License.  See the file COPYING in the main directory of this
- *      archive for more details.
+ *     TURBOchannel PMAGB-B Smart Frame Buffer (SFB) card support,
+ *     Copyright (C) 1999, 2000, 2001 by
+ *     Michael Engel <engel@unix-ag.org> and
+ *     Karsten Merker <merker@linuxtag.org>
+ *     Copyright (c) 2005  Maciej W. Rozycki
+ *
+ *     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.
  */
 
+/* IOmem resource offsets.  */
+#define PMAGB_B_ROM            0x000000        /* REX option ROM */
+#define PMAGB_B_SFB            0x100000        /* SFB ASIC */
+#define PMAGB_B_GP0            0x140000        /* general purpose output 0 */
+#define PMAGB_B_GP1            0x180000        /* general purpose output 1 */
+#define PMAGB_B_BT459          0x1c0000        /* Bt459 RAMDAC */
+#define PMAGB_B_FBMEM          0x200000        /* frame buffer */
+#define PMAGB_B_SIZE           0x400000        /* address space size */
 
-/*
- * Bt459 RAM DAC register base offset (rel. to TC slot base address)
- */
-#define PMAGB_B_BT459_OFFSET                   0x001C0000
+/* IOmem register offsets.  */
+#define SFB_REG_VID_HOR                0x64            /* video horizontal setup */
+#define SFB_REG_VID_VER                0x68            /* video vertical setup */
+#define SFB_REG_VID_BASE       0x6c            /* video base address */
+#define SFB_REG_TCCLK_COUNT    0x78            /* TURBOchannel clock count */
+#define SFB_REG_VIDCLK_COUNT   0x7c            /* video clock count */
 
-/*
- * Begin of PMAGB-B framebuffer memory, resolution is configurable:
- * 1024x864x8 or 1280x1024x8, settable by jumper on the card
- */
-#define PMAGB_B_ONBOARD_FBMEM_OFFSET   0x00201000
+/* Video horizontal setup register constants.  All bits are r/w.  */
+#define SFB_VID_HOR_BP_SHIFT   0x15            /* back porch */
+#define SFB_VID_HOR_BP_MASK    0x7f
+#define SFB_VID_HOR_SYN_SHIFT  0x0e            /* sync pulse */
+#define SFB_VID_HOR_SYN_MASK   0x7f
+#define SFB_VID_HOR_FP_SHIFT   0x09            /* front porch */
+#define SFB_VID_HOR_FP_MASK    0x1f
+#define SFB_VID_HOR_PIX_SHIFT  0x00            /* active video */
+#define SFB_VID_HOR_PIX_MASK   0x1ff
 
-/*
- * Bt459 register offsets, byte-wide registers
- */
+/* Video vertical setup register constants.  All bits are r/w.  */
+#define SFB_VID_VER_BP_SHIFT   0x16            /* back porch */
+#define SFB_VID_VER_BP_MASK    0x3f
+#define SFB_VID_VER_SYN_SHIFT  0x10            /* sync pulse */
+#define SFB_VID_VER_SYN_MASK   0x3f
+#define SFB_VID_VER_FP_SHIFT   0x0b            /* front porch */
+#define SFB_VID_VER_FP_MASK    0x1f
+#define SFB_VID_VER_SL_SHIFT   0x00            /* active scan lines */
+#define SFB_VID_VER_SL_MASK    0x7ff
+
+/* Video base address register constants.  All bits are r/w.  */
+#define SFB_VID_BASE_MASK      0x1ff           /* video base row address */
 
-#define BT459_ADR_LOW                  BT459_OFFSET + 0x00     /* addr. low */
-#define BT459_ADR_HIGH                 BT459_OFFSET + 0x04     /* addr. high */
-#define BT459_DATA                     BT459_OFFSET + 0x08     /* r/w data */
-#define BT459_CMAP                     BT459_OFFSET + 0x0C     /* color map */
+/* Bt459 register offsets, byte-wide registers.  */
+#define BT459_ADDR_LO          0x0             /* address low */
+#define BT459_ADDR_HI          0x4             /* address high */
+#define BT459_DATA             0x8             /* data window register */
+#define BT459_CMAP             0xc             /* color map window register */
index bd548c2b47c4f0376960b3fabc41634354d29b0d..e6da2d7ded8cfa7a0a5c1d16ae1e732b98af996a 100644 (file)
 /*
  *  Support for the w100 frame buffer.
  *
- *  Copyright (c) 2004 Richard Purdie
+ *  Copyright (c) 2004-2005 Richard Purdie
+ *  Copyright (c) 2005 Ian Molton
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  */
 
+#define W100_GPIO_PORT_A       0
+#define W100_GPIO_PORT_B       1
+
+#define CLK_SRC_XTAL  0
+#define CLK_SRC_PLL   1
+
+struct w100fb_par;
+
+unsigned long w100fb_gpio_read(int port);
+void w100fb_gpio_write(int port, unsigned long value);
+
+/* LCD Specific Routines and Config */
+struct w100_tg_info {
+       void (*change)(struct w100fb_par*);
+       void (*suspend)(struct w100fb_par*);
+       void (*resume)(struct w100fb_par*);
+};
+
+/* General Platform Specific w100 Register Values */
+struct w100_gen_regs {
+       unsigned long lcd_format;
+       unsigned long lcdd_cntl1;
+       unsigned long lcdd_cntl2;
+       unsigned long genlcd_cntl1;
+       unsigned long genlcd_cntl2;
+       unsigned long genlcd_cntl3;
+};
+
+struct w100_gpio_regs {
+       unsigned long init_data1;
+       unsigned long init_data2;
+       unsigned long gpio_dir1;
+       unsigned long gpio_oe1;
+       unsigned long gpio_dir2;
+       unsigned long gpio_oe2;
+};
+
+/* Optional External Memory Configuration */
+struct w100_mem_info {
+       unsigned long ext_cntl;
+       unsigned long sdram_mode_reg;
+       unsigned long ext_timing_cntl;
+       unsigned long io_cntl;
+       unsigned int size;
+};
+
+struct w100_bm_mem_info {
+       unsigned long ext_mem_bw;
+       unsigned long offset;
+       unsigned long ext_timing_ctl;
+       unsigned long ext_cntl;
+       unsigned long mode_reg;
+       unsigned long io_cntl;
+       unsigned long config;
+};
+
+/* LCD Mode definition */
+struct w100_mode {
+       unsigned int xres;
+       unsigned int yres;
+       unsigned short left_margin;
+       unsigned short right_margin;
+       unsigned short upper_margin;
+       unsigned short lower_margin;
+       unsigned long crtc_ss;
+       unsigned long crtc_ls;
+       unsigned long crtc_gs;
+       unsigned long crtc_vpos_gs;
+       unsigned long crtc_rev;
+       unsigned long crtc_dclk;
+       unsigned long crtc_gclk;
+       unsigned long crtc_goe;
+       unsigned long crtc_ps1_active;
+       char pll_freq;
+       char fast_pll_freq;
+       int sysclk_src;
+       int sysclk_divider;
+       int pixclk_src;
+       int pixclk_divider;
+       int pixclk_divider_rotated;
+};
+
+struct w100_pll_info {
+       uint16_t freq;  /* desired Fout for PLL (Mhz) */
+       uint8_t M;      /* input divider */
+       uint8_t N_int;  /* VCO multiplier */
+       uint8_t N_fac;  /* VCO multiplier fractional part */
+       uint8_t tfgoal;
+       uint8_t lock_time;
+};
+
+/* Initial Video mode orientation flags */
+#define INIT_MODE_ROTATED  0x1
+#define INIT_MODE_FLIPPED  0x2
+
 /*
  * This structure describes the machine which we are running on.
  * It is set by machine specific code and used in the probe routine
  * of drivers/video/w100fb.c
  */
-
 struct w100fb_mach_info {
-       void (*w100fb_ssp_send)(u8 adrs, u8 data);
-       int comadj;
-       int phadadj;
+       /* General Platform Specific Registers */
+       struct w100_gen_regs *regs;
+       /* Table of modes the LCD is capable of */
+       struct w100_mode *modelist;
+       unsigned int num_modes;
+       /* Hooks for any platform specific tg/lcd code (optional) */
+       struct w100_tg_info *tg;
+       /* External memory definition (if present) */
+       struct w100_mem_info *mem;
+       /* Additional External memory definition (if present) */
+       struct w100_bm_mem_info *bm_mem;
+       /* GPIO definitions (optional) */
+       struct w100_gpio_regs *gpio;
+       /* Initial Mode flags */
+       unsigned int init_mode;
+       /* Xtal Frequency */
+       unsigned int xtal_freq;
+       /* Enable Xtal input doubler (1 == enable) */
+       unsigned int xtal_dbl;
+};
+
+/* General frame buffer data structure */
+struct w100fb_par {
+       unsigned int chip_id;
+       unsigned int xres;
+       unsigned int yres;
+       unsigned int extmem_active;
+       unsigned int flip;
+       unsigned int blanked;
+       unsigned int fastpll_mode;
+       unsigned long hsync_len;
+       struct w100_mode *mode;
+       struct w100_pll_info *pll_table;
+       struct w100fb_mach_info *mach;
+       uint32_t *saved_intmem;
+       uint32_t *saved_extmem;
 };
index 05a75c4f5ce2a230f9193233dd4e05737878b5bf..d5a1a1228fab05632107e53152c954c0033d10f9 100644 (file)
@@ -77,6 +77,22 @@ config LOCALVERSION
          object and source tree, in that order.  Your total string can
          be a maximum of 64 characters.
 
+config LOCALVERSION_AUTO
+       bool "Automatically append version information to the version string"
+       default y
+       help
+         This will try to automatically determine if the current tree is a
+         release tree by looking for git tags that
+         belong to the current top of tree revision.
+
+         A string of the format -gxxxxxxxx will be added to the localversion
+         if a git based tree is found.  The string generated by this will be
+         appended after any matching localversion* files, and after the value
+         set in CONFIG_LOCALVERSION
+
+         Note: This requires Perl, and a git repository, but not necessarily
+         the git or cogito tools to be installed.
+
 config SWAP
        bool "Support for paging of anonymous memory (swap)"
        depends on MMU
@@ -238,6 +254,8 @@ config CPUSETS
 
          Say N if unsure.
 
+source "usr/Kconfig"
+
 menuconfig EMBEDDED
        bool "Configure standard kernel features (for small systems)"
        help
@@ -260,8 +278,8 @@ config KALLSYMS_ALL
        help
           Normally kallsyms only contains the symbols of functions, for nicer
           OOPS messages.  Some debuggers can use kallsyms for other
-          symbols too: say Y here to include all symbols, and you
-          don't care about adding 300k to the size of your kernel.
+          symbols too: say Y here to include all symbols, if you need them 
+          and you don't care about adding 300k to the size of your kernel.
 
           Say N.
 
index 93a53fbdbe79637b4111b73cc54a9d6bec44409e..a2300078f2b7d98f97a603678e40a39d034bdea5 100644 (file)
@@ -25,4 +25,5 @@ $(obj)/version.o: include/linux/compile.h
 
 include/linux/compile.h: FORCE
        @echo '  CHK     $@'
-       @$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CC) $(CFLAGS)"
+       $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ \
+       "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT)" "$(CC) $(CFLAGS)"
index 4e11a9aaf14ab82288e136937de1ec62559c7ac7..b27c11064409a35812d9d35ba359e06f6d8c0ffb 100644 (file)
@@ -127,10 +127,10 @@ fail:
  *        used when disk name of partitioned disk ends on a digit.
  *
  *     If name doesn't have fall into the categories above, we return 0.
- *     Driverfs is used to check if something is a disk name - it has
+ *     Sysfs is used to check if something is a disk name - it has
  *     all known disks under bus/block/devices.  If the disk name
- *     contains slashes, name of driverfs node has them replaced with
- *     bangs.  try_name() does the actual checks, assuming that driverfs
+ *     contains slashes, name of sysfs node has them replaced with
+ *     bangs.  try_name() does the actual checks, assuming that sysfs
  *     is mounted on rootfs /sys.
  */
 
index c9c311cf1771362a349c177e5662140640370e36..f142d403534190f4588b3d7eda585112077e0607 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/rmap.h>
 #include <linux/mempolicy.h>
 #include <linux/key.h>
+#include <net/sock.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -80,7 +81,6 @@
 static int init(void *);
 
 extern void init_IRQ(void);
-extern void sock_init(void);
 extern void fork_init(unsigned long);
 extern void mca_init(void);
 extern void sbus_init(void);
@@ -123,6 +123,7 @@ extern void softirq_init(void);
 char saved_command_line[COMMAND_LINE_SIZE];
 
 static char *execute_command;
+static char *ramdisk_execute_command;
 
 /* Setup configured maximum number of CPUs to activate */
 static unsigned int max_cpus = NR_CPUS;
@@ -297,6 +298,18 @@ static int __init init_setup(char *str)
 }
 __setup("init=", init_setup);
 
+static int __init rdinit_setup(char *str)
+{
+       unsigned int i;
+
+       ramdisk_execute_command = str;
+       /* See "auto" comment in init_setup */
+       for (i = 1; i < MAX_INIT_ARGS; i++)
+               argv_init[i] = NULL;
+       return 1;
+}
+__setup("rdinit=", rdinit_setup);
+
 extern void setup_arch(char **);
 
 #ifndef CONFIG_SMP
@@ -614,6 +627,7 @@ static void do_pre_smp_initcalls(void)
        migration_init();
 #endif
        spawn_ksoftirqd();
+       spawn_softlockup_task();
 }
 
 static void run_init_process(char *init_filename)
@@ -680,10 +694,14 @@ static int init(void * unused)
         * check if there is an early userspace init.  If yes, let it do all
         * the work
         */
-       if (sys_access((const char __user *) "/init", 0) == 0)
-               execute_command = "/init";
-       else
+
+       if (!ramdisk_execute_command)
+               ramdisk_execute_command = "/init";
+
+       if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
+               ramdisk_execute_command = NULL;
                prepare_namespace();
+       }
 
        /*
         * Ok, we have completed the initial bootup, and
@@ -700,17 +718,24 @@ static int init(void * unused)
 
        (void) sys_dup(0);
        (void) sys_dup(0);
-       
+
+       if (ramdisk_execute_command) {
+               run_init_process(ramdisk_execute_command);
+               printk(KERN_WARNING "Failed to execute %s\n",
+                               ramdisk_execute_command);
+       }
+
        /*
         * We try each of these until one succeeds.
         *
         * The Bourne shell can be used instead of init if we are 
         * trying to recover a really broken machine.
         */
-
-       if (execute_command)
+       if (execute_command) {
                run_init_process(execute_command);
-
+               printk(KERN_WARNING "Failed to execute %s.  Attempting "
+                                       "defaults...\n", execute_command);
+       }
        run_init_process("/sbin/init");
        run_init_process("/etc/init");
        run_init_process("/bin/init");
index 3881d564c66837ad6a925ae7a43e429cf30cd482..1fe95f6659dd2b25cc28920051658f288a935f82 100644 (file)
@@ -42,10 +42,10 @@ struct compat_msgbuf {
 
 struct compat_ipc_perm {
        key_t key;
-       compat_uid_t uid;
-       compat_gid_t gid;
-       compat_uid_t cuid;
-       compat_gid_t cgid;
+       __compat_uid_t uid;
+       __compat_gid_t gid;
+       __compat_uid_t cuid;
+       __compat_gid_t cgid;
        compat_mode_t mode;
        unsigned short seq;
 };
@@ -174,8 +174,8 @@ static inline int __put_compat_ipc_perm(struct ipc64_perm *p,
                                        struct compat_ipc_perm __user *up)
 {
        int err;
-       compat_uid_t u;
-       compat_gid_t g;
+       __compat_uid_t u;
+       __compat_gid_t g;
 
        err  = __put_user(p->key, &up->key);
        SET_UID(u, p->uid);
index 27e516f96cdc7c3907b7b25243ff1e4cd786a8e0..d035bd2aba9671cc56fdd6f10b81182ac628b011 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -26,6 +26,7 @@
 #include <linux/sched.h>
 #include <linux/syscalls.h>
 #include <linux/audit.h>
+#include <linux/seq_file.h>
 #include <asm/current.h>
 #include <asm/uaccess.h>
 #include "util.h"
@@ -74,16 +75,16 @@ static struct ipc_ids msg_ids;
 static void freeque (struct msg_queue *msq, int id);
 static int newque (key_t key, int msgflg);
 #ifdef CONFIG_PROC_FS
-static int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
+static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
 #endif
 
 void __init msg_init (void)
 {
        ipc_init_ids(&msg_ids,msg_ctlmni);
-
-#ifdef CONFIG_PROC_FS
-       create_proc_read_entry("sysvipc/msg", 0, NULL, sysvipc_msg_read_proc, NULL);
-#endif
+       ipc_init_proc_interface("sysvipc/msg",
+                               "       key      msqid perms      cbytes       qnum lspid lrpid   uid   gid  cuid  cgid      stime      rtime      ctime\n",
+                               &msg_ids,
+                               sysvipc_msg_proc_show);
 }
 
 static int newque (key_t key, int msgflg)
@@ -113,6 +114,7 @@ static int newque (key_t key, int msgflg)
                return -ENOSPC;
        }
 
+       msq->q_id = msg_buildid(id,msq->q_perm.seq);
        msq->q_stime = msq->q_rtime = 0;
        msq->q_ctime = get_seconds();
        msq->q_cbytes = msq->q_qnum = 0;
@@ -123,7 +125,7 @@ static int newque (key_t key, int msgflg)
        INIT_LIST_HEAD(&msq->q_senders);
        msg_unlock(msq);
 
-       return msg_buildid(id,msq->q_perm.seq);
+       return msq->q_id;
 }
 
 static inline void ss_add(struct msg_queue* msq, struct msg_sender* mss)
@@ -808,55 +810,25 @@ out_unlock:
 }
 
 #ifdef CONFIG_PROC_FS
-static int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
 {
-       off_t pos = 0;
-       off_t begin = 0;
-       int i, len = 0;
-
-       down(&msg_ids.sem);
-       len += sprintf(buffer, "       key      msqid perms      cbytes       qnum lspid lrpid   uid   gid  cuid  cgid      stime      rtime      ctime\n");
-
-       for(i = 0; i <= msg_ids.max_id; i++) {
-               struct msg_queue * msq;
-               msq = msg_lock(i);
-               if(msq != NULL) {
-                       len += sprintf(buffer + len, "%10d %10d  %4o  %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n",
-                               msq->q_perm.key,
-                               msg_buildid(i,msq->q_perm.seq),
-                               msq->q_perm.mode,
-                               msq->q_cbytes,
-                               msq->q_qnum,
-                               msq->q_lspid,
-                               msq->q_lrpid,
-                               msq->q_perm.uid,
-                               msq->q_perm.gid,
-                               msq->q_perm.cuid,
-                               msq->q_perm.cgid,
-                               msq->q_stime,
-                               msq->q_rtime,
-                               msq->q_ctime);
-                       msg_unlock(msq);
-
-                       pos += len;
-                       if(pos < offset) {
-                               len = 0;
-                               begin = pos;
-                       }
-                       if(pos > offset + length)
-                               goto done;
-               }
-
-       }
-       *eof = 1;
-done:
-       up(&msg_ids.sem);
-       *start = buffer + (offset - begin);
-       len -= (offset - begin);
-       if(len > length)
-               len = length;
-       if(len < 0)
-               len = 0;
-       return len;
+       struct msg_queue *msq = it;
+
+       return seq_printf(s,
+                         "%10d %10d  %4o  %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n",
+                         msq->q_perm.key,
+                         msq->q_id,
+                         msq->q_perm.mode,
+                         msq->q_cbytes,
+                         msq->q_qnum,
+                         msq->q_lspid,
+                         msq->q_lrpid,
+                         msq->q_perm.uid,
+                         msq->q_perm.gid,
+                         msq->q_perm.cuid,
+                         msq->q_perm.cgid,
+                         msq->q_stime,
+                         msq->q_rtime,
+                         msq->q_ctime);
 }
 #endif
index 70975ce0784a9082207659c31e4e1cd946f32c7b..19af028a3e380d251d31e4b8ec4cd96ee679a1cb 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -73,6 +73,7 @@
 #include <linux/security.h>
 #include <linux/syscalls.h>
 #include <linux/audit.h>
+#include <linux/seq_file.h>
 #include <asm/uaccess.h>
 #include "util.h"
 
@@ -89,7 +90,7 @@ static struct ipc_ids sem_ids;
 static int newary (key_t, int, int);
 static void freeary (struct sem_array *sma, int id);
 #ifdef CONFIG_PROC_FS
-static int sysvipc_sem_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
+static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
 #endif
 
 #define SEMMSL_FAST    256 /* 512 bytes on stack */
@@ -116,10 +117,10 @@ void __init sem_init (void)
 {
        used_sems = 0;
        ipc_init_ids(&sem_ids,sc_semmni);
-
-#ifdef CONFIG_PROC_FS
-       create_proc_read_entry("sysvipc/sem", 0, NULL, sysvipc_sem_read_proc, NULL);
-#endif
+       ipc_init_proc_interface("sysvipc/sem",
+                               "       key      semid perms      nsems   uid   gid  cuid  cgid      otime      ctime\n",
+                               &sem_ids,
+                               sysvipc_sem_proc_show);
 }
 
 /*
@@ -193,6 +194,7 @@ static int newary (key_t key, int nsems, int semflg)
        }
        used_sems += nsems;
 
+       sma->sem_id = sem_buildid(id, sma->sem_perm.seq);
        sma->sem_base = (struct sem *) &sma[1];
        /* sma->sem_pending = NULL; */
        sma->sem_pending_last = &sma->sem_pending;
@@ -201,7 +203,7 @@ static int newary (key_t key, int nsems, int semflg)
        sma->sem_ctime = get_seconds();
        sem_unlock(sma);
 
-       return sem_buildid(id, sma->sem_perm.seq);
+       return sma->sem_id;
 }
 
 asmlinkage long sys_semget (key_t key, int nsems, int semflg)
@@ -1328,50 +1330,21 @@ next_entry:
 }
 
 #ifdef CONFIG_PROC_FS
-static int sysvipc_sem_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
 {
-       off_t pos = 0;
-       off_t begin = 0;
-       int i, len = 0;
-
-       len += sprintf(buffer, "       key      semid perms      nsems   uid   gid  cuid  cgid      otime      ctime\n");
-       down(&sem_ids.sem);
-
-       for(i = 0; i <= sem_ids.max_id; i++) {
-               struct sem_array *sma;
-               sma = sem_lock(i);
-               if(sma) {
-                       len += sprintf(buffer + len, "%10d %10d  %4o %10lu %5u %5u %5u %5u %10lu %10lu\n",
-                               sma->sem_perm.key,
-                               sem_buildid(i,sma->sem_perm.seq),
-                               sma->sem_perm.mode,
-                               sma->sem_nsems,
-                               sma->sem_perm.uid,
-                               sma->sem_perm.gid,
-                               sma->sem_perm.cuid,
-                               sma->sem_perm.cgid,
-                               sma->sem_otime,
-                               sma->sem_ctime);
-                       sem_unlock(sma);
-
-                       pos += len;
-                       if(pos < offset) {
-                               len = 0;
-                               begin = pos;
-                       }
-                       if(pos > offset + length)
-                               goto done;
-               }
-       }
-       *eof = 1;
-done:
-       up(&sem_ids.sem);
-       *start = buffer + (offset - begin);
-       len -= (offset - begin);
-       if(len > length)
-               len = length;
-       if(len < 0)
-               len = 0;
-       return len;
+       struct sem_array *sma = it;
+
+       return seq_printf(s,
+                         "%10d %10d  %4o %10lu %5u %5u %5u %5u %10lu %10lu\n",
+                         sma->sem_perm.key,
+                         sma->sem_id,
+                         sma->sem_perm.mode,
+                         sma->sem_nsems,
+                         sma->sem_perm.uid,
+                         sma->sem_perm.gid,
+                         sma->sem_perm.cuid,
+                         sma->sem_perm.cgid,
+                         sma->sem_otime,
+                         sma->sem_ctime);
 }
 #endif
index 1d6cf08d950b93c9f5223c7ead161b6f08ed9877..dca90489e3b0f7b9cfd189b593eeee1d3c0f197e 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
 #include <linux/init.h>
 #include <linux/file.h>
 #include <linux/mman.h>
-#include <linux/proc_fs.h>
 #include <linux/shmem_fs.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
 #include <linux/audit.h>
 #include <linux/ptrace.h>
+#include <linux/seq_file.h>
 
 #include <asm/uaccess.h>
 
@@ -51,7 +51,7 @@ static int newseg (key_t key, int shmflg, size_t size);
 static void shm_open (struct vm_area_struct *shmd);
 static void shm_close (struct vm_area_struct *shmd);
 #ifdef CONFIG_PROC_FS
-static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
+static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
 #endif
 
 size_t shm_ctlmax = SHMMAX;
@@ -63,9 +63,10 @@ static int shm_tot; /* total number of shared memory pages */
 void __init shm_init (void)
 {
        ipc_init_ids(&shm_ids, 1);
-#ifdef CONFIG_PROC_FS
-       create_proc_read_entry("sysvipc/shm", 0, NULL, sysvipc_shm_read_proc, NULL);
-#endif
+       ipc_init_proc_interface("sysvipc/shm",
+                               "       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime\n",
+                               &shm_ids,
+                               sysvipc_shm_proc_show);
 }
 
 static inline int shm_checkid(struct shmid_kernel *s, int id)
@@ -869,63 +870,32 @@ asmlinkage long sys_shmdt(char __user *shmaddr)
 }
 
 #ifdef CONFIG_PROC_FS
-static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
 {
-       off_t pos = 0;
-       off_t begin = 0;
-       int i, len = 0;
-
-       down(&shm_ids.sem);
-       len += sprintf(buffer, "       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime\n");
+       struct shmid_kernel *shp = it;
+       char *format;
 
-       for(i = 0; i <= shm_ids.max_id; i++) {
-               struct shmid_kernel* shp;
-
-               shp = shm_lock(i);
-               if(shp!=NULL) {
 #define SMALL_STRING "%10d %10d  %4o %10u %5u %5u  %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
 #define BIG_STRING   "%10d %10d  %4o %21u %5u %5u  %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
-                       char *format;
 
-                       if (sizeof(size_t) <= sizeof(int))
-                               format = SMALL_STRING;
-                       else
-                               format = BIG_STRING;
-                       len += sprintf(buffer + len, format,
-                               shp->shm_perm.key,
-                               shm_buildid(i, shp->shm_perm.seq),
-                               shp->shm_flags,
-                               shp->shm_segsz,
-                               shp->shm_cprid,
-                               shp->shm_lprid,
-                               is_file_hugepages(shp->shm_file) ? (file_count(shp->shm_file) - 1) : shp->shm_nattch,
-                               shp->shm_perm.uid,
-                               shp->shm_perm.gid,
-                               shp->shm_perm.cuid,
-                               shp->shm_perm.cgid,
-                               shp->shm_atim,
-                               shp->shm_dtim,
-                               shp->shm_ctim);
-                       shm_unlock(shp);
-
-                       pos += len;
-                       if(pos < offset) {
-                               len = 0;
-                               begin = pos;
-                       }
-                       if(pos > offset + length)
-                               goto done;
-               }
-       }
-       *eof = 1;
-done:
-       up(&shm_ids.sem);
-       *start = buffer + (offset - begin);
-       len -= (offset - begin);
-       if(len > length)
-               len = length;
-       if(len < 0)
-               len = 0;
-       return len;
+       if (sizeof(size_t) <= sizeof(int))
+               format = SMALL_STRING;
+       else
+               format = BIG_STRING;
+       return seq_printf(s, format,
+                         shp->shm_perm.key,
+                         shp->id,
+                         shp->shm_flags,
+                         shp->shm_segsz,
+                         shp->shm_cprid,
+                         shp->shm_lprid,
+                         is_file_hugepages(shp->shm_file) ? (file_count(shp->shm_file) - 1) : shp->shm_nattch,
+                         shp->shm_perm.uid,
+                         shp->shm_perm.gid,
+                         shp->shm_perm.cuid,
+                         shp->shm_perm.cgid,
+                         shp->shm_atim,
+                         shp->shm_dtim,
+                         shp->shm_ctim);
 }
 #endif
index e00c35f7b2b8055ffc9d516b69343eb6c3158836..10e836d0d89e86fb36de703364a0afdeb0f21c7e 100644 (file)
 #include <linux/security.h>
 #include <linux/rcupdate.h>
 #include <linux/workqueue.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
 
 #include <asm/unistd.h>
 
 #include "util.h"
 
+struct ipc_proc_iface {
+       const char *path;
+       const char *header;
+       struct ipc_ids *ids;
+       int (*show)(struct seq_file *, void *);
+};
+
 /**
  *     ipc_init        -       initialise IPC subsystem
  *
@@ -86,6 +95,43 @@ void __init ipc_init_ids(struct ipc_ids* ids, int size)
                ids->entries->p[i] = NULL;
 }
 
+#ifdef CONFIG_PROC_FS
+static struct file_operations sysvipc_proc_fops;
+/**
+ *     ipc_init_proc_interface -  Create a proc interface for sysipc types
+ *                                using a seq_file interface.
+ *     @path: Path in procfs
+ *     @header: Banner to be printed at the beginning of the file.
+ *     @ids: ipc id table to iterate.
+ *     @show: show routine.
+ */
+void __init ipc_init_proc_interface(const char *path, const char *header,
+                                   struct ipc_ids *ids,
+                                   int (*show)(struct seq_file *, void *))
+{
+       struct proc_dir_entry *pde;
+       struct ipc_proc_iface *iface;
+
+       iface = kmalloc(sizeof(*iface), GFP_KERNEL);
+       if (!iface)
+               return;
+       iface->path     = path;
+       iface->header   = header;
+       iface->ids      = ids;
+       iface->show     = show;
+
+       pde = create_proc_entry(path,
+                               S_IRUGO,        /* world readable */
+                               NULL            /* parent dir */);
+       if (pde) {
+               pde->data = iface;
+               pde->proc_fops = &sysvipc_proc_fops;
+       } else {
+               kfree(iface);
+       }
+}
+#endif
+
 /**
  *     ipc_findkey     -       find a key in an ipc identifier set     
  *     @ids: Identifier set
@@ -578,3 +624,113 @@ int ipc_parse_version (int *cmd)
 }
 
 #endif /* __ARCH_WANT_IPC_PARSE_VERSION */
+
+#ifdef CONFIG_PROC_FS
+static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)
+{
+       struct ipc_proc_iface *iface = s->private;
+       struct kern_ipc_perm *ipc = it;
+       loff_t p;
+
+       /* If we had an ipc id locked before, unlock it */
+       if (ipc && ipc != SEQ_START_TOKEN)
+               ipc_unlock(ipc);
+
+       /*
+        * p = *pos - 1 (because id 0 starts at position 1)
+        *          + 1 (because we increment the position by one)
+        */
+       for (p = *pos; p <= iface->ids->max_id; p++) {
+               if ((ipc = ipc_lock(iface->ids, p)) != NULL) {
+                       *pos = p + 1;
+                       return ipc;
+               }
+       }
+
+       /* Out of range - return NULL to terminate iteration */
+       return NULL;
+}
+
+/*
+ * File positions: pos 0 -> header, pos n -> ipc id + 1.
+ * SeqFile iterator: iterator value locked shp or SEQ_TOKEN_START.
+ */
+static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)
+{
+       struct ipc_proc_iface *iface = s->private;
+       struct kern_ipc_perm *ipc;
+       loff_t p;
+
+       /*
+        * Take the lock - this will be released by the corresponding
+        * call to stop().
+        */
+       down(&iface->ids->sem);
+
+       /* pos < 0 is invalid */
+       if (*pos < 0)
+               return NULL;
+
+       /* pos == 0 means header */
+       if (*pos == 0)
+               return SEQ_START_TOKEN;
+
+       /* Find the (pos-1)th ipc */
+       for (p = *pos - 1; p <= iface->ids->max_id; p++) {
+               if ((ipc = ipc_lock(iface->ids, p)) != NULL) {
+                       *pos = p + 1;
+                       return ipc;
+               }
+       }
+       return NULL;
+}
+
+static void sysvipc_proc_stop(struct seq_file *s, void *it)
+{
+       struct kern_ipc_perm *ipc = it;
+       struct ipc_proc_iface *iface = s->private;
+
+       /* If we had a locked segment, release it */
+       if (ipc && ipc != SEQ_START_TOKEN)
+               ipc_unlock(ipc);
+
+       /* Release the lock we took in start() */
+       up(&iface->ids->sem);
+}
+
+static int sysvipc_proc_show(struct seq_file *s, void *it)
+{
+       struct ipc_proc_iface *iface = s->private;
+
+       if (it == SEQ_START_TOKEN)
+               return seq_puts(s, iface->header);
+
+       return iface->show(s, it);
+}
+
+static struct seq_operations sysvipc_proc_seqops = {
+       .start = sysvipc_proc_start,
+       .stop  = sysvipc_proc_stop,
+       .next  = sysvipc_proc_next,
+       .show  = sysvipc_proc_show,
+};
+
+static int sysvipc_proc_open(struct inode *inode, struct file *file) {
+       int ret;
+       struct seq_file *seq;
+
+       ret = seq_open(file, &sysvipc_proc_seqops);
+       if (!ret) {
+               seq = file->private_data;
+               seq->private = PDE(inode)->data;
+       }
+       return ret;
+}
+
+static struct file_operations sysvipc_proc_fops = {
+       .open    = sysvipc_proc_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release,
+};
+#endif /* CONFIG_PROC_FS */
index 44348ca5a70738ab4033b68d66c97bdcaa626495..fc9a28be0797b3a27ac7f99f8572eeff99ffe99c 100644 (file)
@@ -30,7 +30,15 @@ struct ipc_ids {
        struct ipc_id_ary* entries;
 };
 
+struct seq_file;
 void __init ipc_init_ids(struct ipc_ids* ids, int size);
+#ifdef CONFIG_PROC_FS
+void __init ipc_init_proc_interface(const char *path, const char *header,
+                                   struct ipc_ids *ids,
+                                   int (*show)(struct seq_file *, void *));
+#else
+#define ipc_init_proc_interface(path, header, ids, show) do {} while (0)
+#endif
 
 /* must be called with ids->sem acquired.*/
 int ipc_findkey(struct ipc_ids* ids, key_t key);
index cb05cd05d2374b1ae316adb437ec14da370bd8a5..8d57a2f1226baa8034e8d93b7e4806d5a3f5fce1 100644 (file)
@@ -27,6 +27,7 @@ obj-$(CONFIG_AUDIT) += audit.o
 obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
 obj-$(CONFIG_KPROBES) += kprobes.o
 obj-$(CONFIG_SYSFS) += ksysfs.o
+obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
 obj-$(CONFIG_SECCOMP) += seccomp.o
index 4168f631868e15bb5e9a50c457c9b5f539a6838c..f70e6027cca9758c7ca35f3dc4bd89b7d97d5b14 100644 (file)
@@ -220,7 +220,7 @@ asmlinkage long sys_acct(const char __user *name)
                        return (PTR_ERR(tmp));
                }
                /* Difference from BSD - they don't do O_APPEND */
-               file = filp_open(tmp, O_WRONLY|O_APPEND, 0);
+               file = filp_open(tmp, O_WRONLY|O_APPEND|O_LARGEFILE, 0);
                putname(tmp);
                if (IS_ERR(file)) {
                        return (PTR_ERR(file));
index ef35166fdc29b459e0beb24505df6766972b261b..7f0699790d469ce218ff4ec91967608275871fb7 100644 (file)
@@ -514,7 +514,8 @@ static int __init audit_init(void)
 {
        printk(KERN_INFO "audit: initializing netlink socket (%s)\n",
               audit_default ? "enabled" : "disabled");
-       audit_sock = netlink_kernel_create(NETLINK_AUDIT, audit_receive);
+       audit_sock = netlink_kernel_create(NETLINK_AUDIT, 0, audit_receive,
+                                          THIS_MODULE);
        if (!audit_sock)
                audit_panic("cannot initialize netlink socket");
 
index 8ab1b4e518b8909a867595534957dbf3c12cf3d8..1f06e76901067ffa1c08d586d0128f64ad6d6c65 100644 (file)
@@ -628,13 +628,6 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
  * lock_cpu_hotplug()/unlock_cpu_hotplug() pair.
  */
 
-/*
- * Hack to avoid 2.6.13 partial node dynamic sched domain bug.
- * Disable letting 'cpu_exclusive' cpusets define dynamic sched
- * domains, until the sched domain can handle partial nodes.
- * Remove this #if hackery when sched domains fixed.
- */
-#if 0
 static void update_cpu_domains(struct cpuset *cur)
 {
        struct cpuset *c, *par = cur->parent;
@@ -675,11 +668,6 @@ static void update_cpu_domains(struct cpuset *cur)
        partition_sched_domains(&pspan, &cspan);
        unlock_cpu_hotplug();
 }
-#else
-static void update_cpu_domains(struct cpuset *cur)
-{
-}
-#endif
 
 static int update_cpumask(struct cpuset *cs, char *buf)
 {
@@ -1611,17 +1599,114 @@ int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl)
        return 0;
 }
 
+/*
+ * nearest_exclusive_ancestor() - Returns the nearest mem_exclusive
+ * ancestor to the specified cpuset.  Call while holding cpuset_sem.
+ * If no ancestor is mem_exclusive (an unusual configuration), then
+ * returns the root cpuset.
+ */
+static const struct cpuset *nearest_exclusive_ancestor(const struct cpuset *cs)
+{
+       while (!is_mem_exclusive(cs) && cs->parent)
+               cs = cs->parent;
+       return cs;
+}
+
 /**
- * cpuset_zone_allowed - is zone z allowed in current->mems_allowed
- * @z: zone in question
+ * cpuset_zone_allowed - Can we allocate memory on zone z's memory node?
+ * @z: is this zone on an allowed node?
+ * @gfp_mask: memory allocation flags (we use __GFP_HARDWALL)
  *
- * Is zone z allowed in current->mems_allowed, or is
- * the CPU in interrupt context? (zone is always allowed in this case)
- */
-int cpuset_zone_allowed(struct zone *z)
+ * If we're in interrupt, yes, we can always allocate.  If zone
+ * z's node is in our tasks mems_allowed, yes.  If it's not a
+ * __GFP_HARDWALL request and this zone's nodes is in the nearest
+ * mem_exclusive cpuset ancestor to this tasks cpuset, yes.
+ * Otherwise, no.
+ *
+ * GFP_USER allocations are marked with the __GFP_HARDWALL bit,
+ * and do not allow allocations outside the current tasks cpuset.
+ * GFP_KERNEL allocations are not so marked, so can escape to the
+ * nearest mem_exclusive ancestor cpuset.
+ *
+ * Scanning up parent cpusets requires cpuset_sem.  The __alloc_pages()
+ * routine only calls here with __GFP_HARDWALL bit _not_ set if
+ * it's a GFP_KERNEL allocation, and all nodes in the current tasks
+ * mems_allowed came up empty on the first pass over the zonelist.
+ * So only GFP_KERNEL allocations, if all nodes in the cpuset are
+ * short of memory, might require taking the cpuset_sem semaphore.
+ *
+ * The first loop over the zonelist in mm/page_alloc.c:__alloc_pages()
+ * calls here with __GFP_HARDWALL always set in gfp_mask, enforcing
+ * hardwall cpusets - no allocation on a node outside the cpuset is
+ * allowed (unless in interrupt, of course).
+ *
+ * The second loop doesn't even call here for GFP_ATOMIC requests
+ * (if the __alloc_pages() local variable 'wait' is set).  That check
+ * and the checks below have the combined affect in the second loop of
+ * the __alloc_pages() routine that:
+ *     in_interrupt - any node ok (current task context irrelevant)
+ *     GFP_ATOMIC   - any node ok
+ *     GFP_KERNEL   - any node in enclosing mem_exclusive cpuset ok
+ *     GFP_USER     - only nodes in current tasks mems allowed ok.
+ **/
+
+int cpuset_zone_allowed(struct zone *z, unsigned int __nocast gfp_mask)
 {
-       return in_interrupt() ||
-               node_isset(z->zone_pgdat->node_id, current->mems_allowed);
+       int node;                       /* node that zone z is on */
+       const struct cpuset *cs;        /* current cpuset ancestors */
+       int allowed = 1;                /* is allocation in zone z allowed? */
+
+       if (in_interrupt())
+               return 1;
+       node = z->zone_pgdat->node_id;
+       if (node_isset(node, current->mems_allowed))
+               return 1;
+       if (gfp_mask & __GFP_HARDWALL)  /* If hardwall request, stop here */
+               return 0;
+
+       /* Not hardwall and node outside mems_allowed: scan up cpusets */
+       down(&cpuset_sem);
+       cs = current->cpuset;
+       if (!cs)
+               goto done;              /* current task exiting */
+       cs = nearest_exclusive_ancestor(cs);
+       allowed = node_isset(node, cs->mems_allowed);
+done:
+       up(&cpuset_sem);
+       return allowed;
+}
+
+/**
+ * cpuset_excl_nodes_overlap - Do we overlap @p's mem_exclusive ancestors?
+ * @p: pointer to task_struct of some other task.
+ *
+ * Description: Return true if the nearest mem_exclusive ancestor
+ * cpusets of tasks @p and current overlap.  Used by oom killer to
+ * determine if task @p's memory usage might impact the memory
+ * available to the current task.
+ *
+ * Acquires cpuset_sem - not suitable for calling from a fast path.
+ **/
+
+int cpuset_excl_nodes_overlap(const struct task_struct *p)
+{
+       const struct cpuset *cs1, *cs2; /* my and p's cpuset ancestors */
+       int overlap = 0;                /* do cpusets overlap? */
+
+       down(&cpuset_sem);
+       cs1 = current->cpuset;
+       if (!cs1)
+               goto done;              /* current task exiting */
+       cs2 = p->cpuset;
+       if (!cs2)
+               goto done;              /* task p is exiting */
+       cs1 = nearest_exclusive_ancestor(cs1);
+       cs2 = nearest_exclusive_ancestor(cs2);
+       overlap = nodes_intersects(cs1->mems_allowed, cs2->mems_allowed);
+done:
+       up(&cpuset_sem);
+
+       return overlap;
 }
 
 /*
index b65187f0c74e720281ff6f08b98e3bef19e638c4..7e1ead9a6ba453bbfafab739df3690e69684e769 100644 (file)
@@ -994,6 +994,9 @@ static task_t *copy_process(unsigned long clone_flags,
         * of CLONE_PTRACE.
         */
        clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
+#ifdef TIF_SYSCALL_EMU
+       clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
+#endif
 
        /* Our parent execution domain becomes current domain
           These must match for thread signalling to apply */
index c7130f86106c30a8c9970b425dad032d3885318e..ca05fe6a70b24a2921901505c99dd7eb105b3df7 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/pagemap.h>
 #include <linux/syscalls.h>
 #include <linux/signal.h>
+#include <asm/futex.h>
 
 #define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8)
 
@@ -326,6 +327,118 @@ out:
        return ret;
 }
 
+/*
+ * 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)
+{
+       union futex_key key1, key2;
+       struct futex_hash_bucket *bh1, *bh2;
+       struct list_head *head;
+       struct futex_q *this, *next;
+       int ret, op_ret, attempt = 0;
+
+retryfull:
+       down_read(&current->mm->mmap_sem);
+
+       ret = get_futex_key(uaddr1, &key1);
+       if (unlikely(ret != 0))
+               goto out;
+       ret = get_futex_key(uaddr2, &key2);
+       if (unlikely(ret != 0))
+               goto out;
+
+       bh1 = hash_futex(&key1);
+       bh2 = hash_futex(&key2);
+
+retry:
+       if (bh1 < bh2)
+               spin_lock(&bh1->lock);
+       spin_lock(&bh2->lock);
+       if (bh1 > bh2)
+               spin_lock(&bh1->lock);
+
+       op_ret = futex_atomic_op_inuser(op, (int __user *)uaddr2);
+       if (unlikely(op_ret < 0)) {
+               int dummy;
+
+               spin_unlock(&bh1->lock);
+               if (bh1 != bh2)
+                       spin_unlock(&bh2->lock);
+
+               /* 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.  */
+               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:
+                               goto out;
+                       }
+                       goto retry;
+               }
+
+               /* 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);
+               if (ret)
+                       return ret;
+
+               goto retryfull;
+       }
+
+       head = &bh1->chain;
+
+       list_for_each_entry_safe(this, next, head, list) {
+               if (match_futex (&this->key, &key1)) {
+                       wake_futex(this);
+                       if (++ret >= nr_wake)
+                               break;
+               }
+       }
+
+       if (op_ret > 0) {
+               head = &bh2->chain;
+
+               op_ret = 0;
+               list_for_each_entry_safe(this, next, head, list) {
+                       if (match_futex (&this->key, &key2)) {
+                               wake_futex(this);
+                               if (++op_ret >= nr_wake2)
+                                       break;
+                       }
+               }
+               ret += op_ret;
+       }
+
+       spin_unlock(&bh1->lock);
+       if (bh1 != bh2)
+               spin_unlock(&bh2->lock);
+out:
+       up_read(&current->mm->mmap_sem);
+       return ret;
+}
+
 /*
  * Requeue all waiters hashed on one physical page to another
  * physical page.
@@ -673,23 +786,17 @@ static int futex_fd(unsigned long uaddr, int signal)
        filp->f_mapping = filp->f_dentry->d_inode->i_mapping;
 
        if (signal) {
-               int err;
                err = f_setown(filp, current->pid, 1);
                if (err < 0) {
-                       put_unused_fd(ret);
-                       put_filp(filp);
-                       ret = err;
-                       goto out;
+                       goto error;
                }
                filp->f_owner.signum = signal;
        }
 
        q = kmalloc(sizeof(*q), GFP_KERNEL);
        if (!q) {
-               put_unused_fd(ret);
-               put_filp(filp);
-               ret = -ENOMEM;
-               goto out;
+               err = -ENOMEM;
+               goto error;
        }
 
        down_read(&current->mm->mmap_sem);
@@ -697,10 +804,8 @@ static int futex_fd(unsigned long uaddr, int signal)
 
        if (unlikely(err != 0)) {
                up_read(&current->mm->mmap_sem);
-               put_unused_fd(ret);
-               put_filp(filp);
                kfree(q);
-               return err;
+               goto error;
        }
 
        /*
@@ -716,6 +821,11 @@ static int futex_fd(unsigned long uaddr, int signal)
        fd_install(ret, filp);
 out:
        return ret;
+error:
+       put_unused_fd(ret);
+       put_filp(filp);
+       ret = err;
+       goto out;
 }
 
 long do_futex(unsigned long uaddr, int op, int val, unsigned long timeout,
@@ -740,6 +850,9 @@ long do_futex(unsigned long uaddr, int op, int val, unsigned long timeout,
        case FUTEX_CMP_REQUEUE:
                ret = futex_requeue(uaddr, uaddr2, val, val2, &val3);
                break;
+       case FUTEX_WAKE_OP:
+               ret = futex_wake_op(uaddr, uaddr2, val, val2, val3);
+               break;
        default:
                ret = -ENOSYS;
        }
index 388977f3e9b7d7a826e57d60a3227da0d4f3c1ac..0cbe633420fb9b6d46376debb0c68d201a5966d5 100644 (file)
@@ -39,7 +39,7 @@ void inter_module_register(const char *im_name, struct module *owner, const void
        struct list_head *tmp;
        struct inter_module_entry *ime, *ime_new;
 
-       if (!(ime_new = kmalloc(sizeof(*ime), GFP_KERNEL))) {
+       if (!(ime_new = kzalloc(sizeof(*ime), GFP_KERNEL))) {
                /* Overloaded kernel, not fatal */
                printk(KERN_ERR
                        "Aiee, inter_module_register: cannot kmalloc entry for '%s'\n",
@@ -47,7 +47,6 @@ void inter_module_register(const char *im_name, struct module *owner, const void
                kmalloc_failed = 1;
                return;
        }
-       memset(ime_new, 0, sizeof(*ime_new));
        ime_new->im_name = im_name;
        ime_new->owner = owner;
        ime_new->userdata = userdata;
index c29f83c16497cff719b118bf1a8fabfb78076cd2..3ff7b925c38773f1c0df8eb4dcda1ea5926f1ea3 100644 (file)
@@ -111,7 +111,7 @@ fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs)
        unsigned int status;
 
        kstat_this_cpu.irqs[irq]++;
-       if (desc->status & IRQ_PER_CPU) {
+       if (CHECK_IRQ_PER_CPU(desc->status)) {
                irqreturn_t action_ret;
 
                /*
index ac670098570579e980e6b7bba35a235f7be885a9..1cfdb08ddf2054f6f219d28c78b97828e2f8b447 100644 (file)
 
 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)
  *
index 85d08daa6600ee826e1810010500ddca76133e86..f26e534c6585dacf089be5fb602f70b08ee6db60 100644 (file)
@@ -19,12 +19,22 @@ static struct proc_dir_entry *root_irq_dir, *irq_dir[NR_IRQS];
  */
 static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];
 
-void __attribute__((weak))
-proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
+#ifdef CONFIG_GENERIC_PENDING_IRQ
+void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
+{
+       /*
+        * Save these away for later use. Re-progam when the
+        * interrupt is pending
+        */
+       set_pending_irq(irq, mask_val);
+}
+#else
+void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
 {
        irq_affinity[irq] = mask_val;
        irq_desc[irq].handler->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)
index b0237122b24e14667631716a8a6c3e23a495a7e9..f3ea492ab44dfcfc05e2fad4027e303f9b69d9dd 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleloader.h>
+#include <asm-generic/sections.h>
 #include <asm/cacheflush.h>
 #include <asm/errno.h>
 #include <asm/kdebug.h>
@@ -72,7 +73,7 @@ static struct hlist_head kprobe_insn_pages;
  * get_insn_slot() - Find a slot on an executable page for an instruction.
  * We allocate an executable page if there's no room on existing ones.
  */
-kprobe_opcode_t *get_insn_slot(void)
+kprobe_opcode_t __kprobes *get_insn_slot(void)
 {
        struct kprobe_insn_page *kip;
        struct hlist_node *pos;
@@ -117,7 +118,7 @@ kprobe_opcode_t *get_insn_slot(void)
        return kip->insns;
 }
 
-void free_insn_slot(kprobe_opcode_t *slot)
+void __kprobes free_insn_slot(kprobe_opcode_t *slot)
 {
        struct kprobe_insn_page *kip;
        struct hlist_node *pos;
@@ -152,20 +153,42 @@ void free_insn_slot(kprobe_opcode_t *slot)
 }
 
 /* Locks kprobe: irqs must be disabled */
-void lock_kprobes(void)
+void __kprobes lock_kprobes(void)
 {
+       unsigned long flags = 0;
+
+       /* Avoiding local interrupts to happen right after we take the kprobe_lock
+        * and before we get a chance to update kprobe_cpu, this to prevent
+        * deadlock when we have a kprobe on ISR routine and a kprobe on task
+        * routine
+        */
+       local_irq_save(flags);
+
        spin_lock(&kprobe_lock);
        kprobe_cpu = smp_processor_id();
+
+       local_irq_restore(flags);
 }
 
-void unlock_kprobes(void)
+void __kprobes unlock_kprobes(void)
 {
+       unsigned long flags = 0;
+
+       /* Avoiding local interrupts to happen right after we update
+        * kprobe_cpu and before we get a a chance to release kprobe_lock,
+        * this to prevent deadlock when we have a kprobe on ISR routine and
+        * a kprobe on task routine
+        */
+       local_irq_save(flags);
+
        kprobe_cpu = NR_CPUS;
        spin_unlock(&kprobe_lock);
+
+       local_irq_restore(flags);
 }
 
 /* You have to be holding the kprobe_lock */
-struct kprobe *get_kprobe(void *addr)
+struct kprobe __kprobes *get_kprobe(void *addr)
 {
        struct hlist_head *head;
        struct hlist_node *node;
@@ -183,7 +206,7 @@ struct kprobe *get_kprobe(void *addr)
  * Aggregate handlers for multiple kprobes support - these handlers
  * take care of invoking the individual kprobe handlers on p->list
  */
-static int aggr_pre_handler(struct kprobe *p, struct pt_regs *regs)
+static int __kprobes aggr_pre_handler(struct kprobe *p, struct pt_regs *regs)
 {
        struct kprobe *kp;
 
@@ -198,8 +221,8 @@ static int aggr_pre_handler(struct kprobe *p, struct pt_regs *regs)
        return 0;
 }
 
-static void aggr_post_handler(struct kprobe *p, struct pt_regs *regs,
-                             unsigned long flags)
+static void __kprobes aggr_post_handler(struct kprobe *p, struct pt_regs *regs,
+                                       unsigned long flags)
 {
        struct kprobe *kp;
 
@@ -213,8 +236,8 @@ static void aggr_post_handler(struct kprobe *p, struct pt_regs *regs,
        return;
 }
 
-static int aggr_fault_handler(struct kprobe *p, struct pt_regs *regs,
-                             int trapnr)
+static int __kprobes aggr_fault_handler(struct kprobe *p, struct pt_regs *regs,
+                                       int trapnr)
 {
        /*
         * if we faulted "during" the execution of a user specified
@@ -227,7 +250,7 @@ static int aggr_fault_handler(struct kprobe *p, struct pt_regs *regs,
        return 0;
 }
 
-static int aggr_break_handler(struct kprobe *p, struct pt_regs *regs)
+static int __kprobes aggr_break_handler(struct kprobe *p, struct pt_regs *regs)
 {
        struct kprobe *kp = curr_kprobe;
        if (curr_kprobe && kp->break_handler) {
@@ -240,7 +263,7 @@ static int aggr_break_handler(struct kprobe *p, struct pt_regs *regs)
        return 0;
 }
 
-struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp)
+struct kretprobe_instance __kprobes *get_free_rp_inst(struct kretprobe *rp)
 {
        struct hlist_node *node;
        struct kretprobe_instance *ri;
@@ -249,7 +272,8 @@ struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp)
        return NULL;
 }
 
-static struct kretprobe_instance *get_used_rp_inst(struct kretprobe *rp)
+static struct kretprobe_instance __kprobes *get_used_rp_inst(struct kretprobe
+                                                             *rp)
 {
        struct hlist_node *node;
        struct kretprobe_instance *ri;
@@ -258,7 +282,7 @@ static struct kretprobe_instance *get_used_rp_inst(struct kretprobe *rp)
        return NULL;
 }
 
-void add_rp_inst(struct kretprobe_instance *ri)
+void __kprobes add_rp_inst(struct kretprobe_instance *ri)
 {
        /*
         * Remove rp inst off the free list -
@@ -276,7 +300,7 @@ void add_rp_inst(struct kretprobe_instance *ri)
        hlist_add_head(&ri->uflist, &ri->rp->used_instances);
 }
 
-void recycle_rp_inst(struct kretprobe_instance *ri)
+void __kprobes recycle_rp_inst(struct kretprobe_instance *ri)
 {
        /* remove rp inst off the rprobe_inst_table */
        hlist_del(&ri->hlist);
@@ -291,7 +315,7 @@ void recycle_rp_inst(struct kretprobe_instance *ri)
                kfree(ri);
 }
 
-struct hlist_head kretprobe_inst_table_head(struct task_struct *tsk)
+struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk)
 {
        return &kretprobe_inst_table[hash_ptr(tsk, KPROBE_HASH_BITS)];
 }
@@ -302,7 +326,7 @@ struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk)
  * instances associated with this task. These left over instances represent
  * probed functions that have been called but will never return.
  */
-void kprobe_flush_task(struct task_struct *tk)
+void __kprobes kprobe_flush_task(struct task_struct *tk)
 {
         struct kretprobe_instance *ri;
         struct hlist_head *head;
@@ -322,7 +346,8 @@ void kprobe_flush_task(struct task_struct *tk)
  * This kprobe pre_handler is registered with every kretprobe. When probe
  * hits it will set up the return probe.
  */
-static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
+static int __kprobes pre_handler_kretprobe(struct kprobe *p,
+                                          struct pt_regs *regs)
 {
        struct kretprobe *rp = container_of(p, struct kretprobe, kp);
 
@@ -353,7 +378,7 @@ static inline void copy_kprobe(struct kprobe *old_p, struct kprobe *p)
 * Add the new probe to old_p->list. Fail if this is the
 * second jprobe at the address - two jprobes can't coexist
 */
-static int add_new_kprobe(struct kprobe *old_p, struct kprobe *p)
+static int __kprobes add_new_kprobe(struct kprobe *old_p, struct kprobe *p)
 {
         struct kprobe *kp;
 
@@ -395,7 +420,8 @@ static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p)
  * the intricacies
  * TODO: Move kcalloc outside the spinlock
  */
-static int register_aggr_kprobe(struct kprobe *old_p, struct kprobe *p)
+static int __kprobes register_aggr_kprobe(struct kprobe *old_p,
+                                         struct kprobe *p)
 {
        int ret = 0;
        struct kprobe *ap;
@@ -434,15 +460,25 @@ static inline void cleanup_aggr_kprobe(struct kprobe *old_p,
                spin_unlock_irqrestore(&kprobe_lock, flags);
 }
 
-int register_kprobe(struct kprobe *p)
+static int __kprobes in_kprobes_functions(unsigned long addr)
+{
+       if (addr >= (unsigned long)__kprobes_text_start
+               && addr < (unsigned long)__kprobes_text_end)
+               return -EINVAL;
+       return 0;
+}
+
+int __kprobes register_kprobe(struct kprobe *p)
 {
        int ret = 0;
        unsigned long flags = 0;
        struct kprobe *old_p;
 
-       if ((ret = arch_prepare_kprobe(p)) != 0) {
+       if ((ret = in_kprobes_functions((unsigned long) p->addr)) != 0)
+               return ret;
+       if ((ret = arch_prepare_kprobe(p)) != 0)
                goto rm_kprobe;
-       }
+
        spin_lock_irqsave(&kprobe_lock, flags);
        old_p = get_kprobe(p->addr);
        p->nmissed = 0;
@@ -466,7 +502,7 @@ rm_kprobe:
        return ret;
 }
 
-void unregister_kprobe(struct kprobe *p)
+void __kprobes unregister_kprobe(struct kprobe *p)
 {
        unsigned long flags;
        struct kprobe *old_p;
@@ -487,7 +523,7 @@ static struct notifier_block kprobe_exceptions_nb = {
        .priority = 0x7fffffff /* we need to notified first */
 };
 
-int register_jprobe(struct jprobe *jp)
+int __kprobes register_jprobe(struct jprobe *jp)
 {
        /* Todo: Verify probepoint is a function entry point */
        jp->kp.pre_handler = setjmp_pre_handler;
@@ -496,14 +532,14 @@ int register_jprobe(struct jprobe *jp)
        return register_kprobe(&jp->kp);
 }
 
-void unregister_jprobe(struct jprobe *jp)
+void __kprobes unregister_jprobe(struct jprobe *jp)
 {
        unregister_kprobe(&jp->kp);
 }
 
 #ifdef ARCH_SUPPORTS_KRETPROBES
 
-int register_kretprobe(struct kretprobe *rp)
+int __kprobes register_kretprobe(struct kretprobe *rp)
 {
        int ret = 0;
        struct kretprobe_instance *inst;
@@ -540,14 +576,14 @@ int register_kretprobe(struct kretprobe *rp)
 
 #else /* ARCH_SUPPORTS_KRETPROBES */
 
-int register_kretprobe(struct kretprobe *rp)
+int __kprobes register_kretprobe(struct kretprobe *rp)
 {
        return -ENOSYS;
 }
 
 #endif /* ARCH_SUPPORTS_KRETPROBES */
 
-void unregister_kretprobe(struct kretprobe *rp)
+void __kprobes unregister_kretprobe(struct kretprobe *rp)
 {
        unsigned long flags;
        struct kretprobe_instance *ri;
index c32995fbd8fd14b608bb49e5b0f5899e41ffd979..4b39d3793c720673452b6d8be18ade674360131a 100644 (file)
@@ -1509,6 +1509,7 @@ static struct module *load_module(void __user *umod,
        long err = 0;
        void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
        struct exception_table_entry *extable;
+       mm_segment_t old_fs;
 
        DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
               umod, len, uargs);
@@ -1779,6 +1780,24 @@ static struct module *load_module(void __user *umod,
        if (err < 0)
                goto cleanup;
 
+       /* flush the icache in correct context */
+       old_fs = get_fs();
+       set_fs(KERNEL_DS);
+
+       /*
+        * Flush the instruction cache, since we've played with text.
+        * Do it before processing of module parameters, so the module
+        * can provide parameter accessor functions of its own.
+        */
+       if (mod->module_init)
+               flush_icache_range((unsigned long)mod->module_init,
+                                  (unsigned long)mod->module_init
+                                  + mod->init_size);
+       flush_icache_range((unsigned long)mod->module_core,
+                          (unsigned long)mod->module_core + mod->core_size);
+
+       set_fs(old_fs);
+
        mod->args = args;
        if (obsparmindex) {
                err = obsolete_params(mod->name, mod->args,
@@ -1860,7 +1879,6 @@ sys_init_module(void __user *umod,
                const char __user *uargs)
 {
        struct module *mod;
-       mm_segment_t old_fs = get_fs();
        int ret = 0;
 
        /* Must have permission */
@@ -1878,19 +1896,6 @@ sys_init_module(void __user *umod,
                return PTR_ERR(mod);
        }
 
-       /* flush the icache in correct context */
-       set_fs(KERNEL_DS);
-
-       /* Flush the instruction cache, since we've played with text */
-       if (mod->module_init)
-               flush_icache_range((unsigned long)mod->module_init,
-                                  (unsigned long)mod->module_init
-                                  + mod->init_size);
-       flush_icache_range((unsigned long)mod->module_core,
-                          (unsigned long)mod->module_core + mod->core_size);
-
-       set_fs(old_fs);
-
        /* Now sew it into the lists.  They won't access us, since
            strong_try_module_get() will fail. */
        stop_machine_run(__link_module, mod, NR_CPUS);
index d586c35ef8fca8f4540031c5ad071b90c1071df4..fbf173215fd217bed3db643ba0676916f7085daf 100644 (file)
@@ -542,8 +542,8 @@ static void __init kernel_param_sysfs_setup(const char *name,
 {
        struct module_kobject *mk;
 
-       mk = kmalloc(sizeof(struct module_kobject), GFP_KERNEL);
-       memset(mk, 0, sizeof(struct module_kobject));
+       mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL);
+       BUG_ON(!mk);
 
        mk->mod = THIS_MODULE;
        kobj_set_kset_s(mk, module_subsys);
index 38798a2ff994e96c017010b8c2c62db578fe2002..b7b532acd9fc419050f03de66b12acb14d5c4077 100644 (file)
@@ -427,21 +427,23 @@ int posix_timer_event(struct k_itimer *timr,int si_private)
        timr->sigq->info.si_code = SI_TIMER;
        timr->sigq->info.si_tid = timr->it_id;
        timr->sigq->info.si_value = timr->it_sigev_value;
+
        if (timr->it_sigev_notify & SIGEV_THREAD_ID) {
-               if (unlikely(timr->it_process->flags & PF_EXITING)) {
-                       timr->it_sigev_notify = SIGEV_SIGNAL;
-                       put_task_struct(timr->it_process);
-                       timr->it_process = timr->it_process->group_leader;
-                       goto group;
-               }
-               return send_sigqueue(timr->it_sigev_signo, timr->sigq,
-                       timr->it_process);
-       }
-       else {
-       group:
-               return send_group_sigqueue(timr->it_sigev_signo, timr->sigq,
-                       timr->it_process);
+               struct task_struct *leader;
+               int ret = send_sigqueue(timr->it_sigev_signo, timr->sigq,
+                                       timr->it_process);
+
+               if (likely(ret >= 0))
+                       return ret;
+
+               timr->it_sigev_notify = SIGEV_SIGNAL;
+               leader = timr->it_process->group_leader;
+               put_task_struct(timr->it_process);
+               timr->it_process = leader;
        }
+
+       return send_group_sigqueue(timr->it_sigev_signo, timr->sigq,
+                                  timr->it_process);
 }
 EXPORT_SYMBOL_GPL(posix_timer_event);
 
index 2c7121d9bff11aff162a578bd68d7934c1030104..c14cd99911818c893294c52afff301b58e729554 100644 (file)
@@ -28,7 +28,7 @@ config PM_DEBUG
 
 config SOFTWARE_SUSPEND
        bool "Software Suspend"
-       depends on EXPERIMENTAL && PM && SWAP && ((X86 && SMP) || ((FVR || PPC32 || X86) && !SMP))
+       depends on PM && SWAP && (X86 || ((FVR || PPC32) && !SMP))
        ---help---
          Enable the possibility of suspending the machine.
          It doesn't need APM.
@@ -72,6 +72,18 @@ config PM_STD_PARTITION
          suspended image to. It will simply pick the first available swap 
          device.
 
+config SWSUSP_ENCRYPT
+       bool "Encrypt suspend image"
+       depends on SOFTWARE_SUSPEND && CRYPTO=y && (CRYPTO_AES=y || CRYPTO_AES_586=y || CRYPTO_AES_X86_64=y)
+       default ""
+       ---help---
+         To prevent data gathering from swap after resume you can encrypt
+         the suspend image with a temporary key that is deleted on
+         resume.
+
+         Note that the temporary key is stored unencrypted on disk while the
+         system is suspended.
+
 config SUSPEND_SMP
        bool
        depends on HOTPLUG_CPU && X86 && PM
index 664eb0469b6e18230f3daf84fcf78ed09e8f0bcf..2d8bf054d036810766352d66b2fb84ec16361717 100644 (file)
@@ -112,24 +112,12 @@ static inline void platform_finish(void)
        }
 }
 
-static void finish(void)
-{
-       device_resume();
-       platform_finish();
-       thaw_processes();
-       enable_nonboot_cpus();
-       pm_restore_console();
-}
-
-
 static int prepare_processes(void)
 {
        int error;
 
        pm_prepare_console();
-
        sys_sync();
-
        disable_nonboot_cpus();
 
        if (freeze_processes()) {
@@ -162,15 +150,6 @@ static void unprepare_processes(void)
        pm_restore_console();
 }
 
-static int prepare_devices(void)
-{
-       int error;
-
-       if ((error = device_suspend(PMSG_FREEZE)))
-               printk("Some devices failed to suspend\n");
-       return error;
-}
-
 /**
  *     pm_suspend_disk - The granpappy of power management.
  *
@@ -187,17 +166,14 @@ int pm_suspend_disk(void)
        error = prepare_processes();
        if (error)
                return error;
-       error = prepare_devices();
 
+       error = device_suspend(PMSG_FREEZE);
        if (error) {
+               printk("Some devices failed to suspend\n");
                unprepare_processes();
                return error;
        }
 
-       pr_debug("PM: Attempting to suspend to disk.\n");
-       if (pm_disk_mode == PM_DISK_FIRMWARE)
-               return pm_ops->enter(PM_SUSPEND_DISK);
-
        pr_debug("PM: snapshotting memory.\n");
        in_suspend = 1;
        if ((error = swsusp_suspend()))
@@ -208,11 +184,20 @@ int pm_suspend_disk(void)
                error = swsusp_write();
                if (!error)
                        power_down(pm_disk_mode);
+               else {
+               /* swsusp_write can not fail in device_resume,
+                  no need to do second device_resume */
+                       swsusp_free();
+                       unprepare_processes();
+                       return error;
+               }
        } else
                pr_debug("PM: Image restored successfully.\n");
+
        swsusp_free();
  Done:
-       finish();
+       device_resume();
+       unprepare_processes();
        return error;
 }
 
@@ -233,9 +218,12 @@ static int software_resume(void)
 {
        int error;
 
+       down(&pm_sem);
        if (!swsusp_resume_device) {
-               if (!strlen(resume_file))
+               if (!strlen(resume_file)) {
+                       up(&pm_sem);
                        return -ENOENT;
+               }
                swsusp_resume_device = name_to_dev_t(resume_file);
                pr_debug("swsusp: Resume From Partition %s\n", resume_file);
        } else {
@@ -248,6 +236,7 @@ static int software_resume(void)
                 * FIXME: If noresume is specified, we need to find the partition
                 * and reset it back to normal swap space.
                 */
+               up(&pm_sem);
                return 0;
        }
 
@@ -270,20 +259,24 @@ static int software_resume(void)
 
        pr_debug("PM: Preparing devices for restore.\n");
 
-       if ((error = prepare_devices()))
+       if ((error = device_suspend(PMSG_FREEZE))) {
+               printk("Some devices failed to suspend\n");
                goto Free;
+       }
 
        mb();
 
        pr_debug("PM: Restoring saved image.\n");
        swsusp_resume();
        pr_debug("PM: Restore failed, recovering.n");
-       finish();
+       device_resume();
  Free:
        swsusp_free();
  Cleanup:
        unprepare_processes();
  Done:
+       /* For success case, the suspend path will release the lock */
+       up(&pm_sem);
        pr_debug("PM: Resume from disk failed.\n");
        return 0;
 }
@@ -390,7 +383,9 @@ static ssize_t resume_store(struct subsystem * subsys, const char * buf, size_t
        if (sscanf(buf, "%u:%u", &maj, &min) == 2) {
                res = MKDEV(maj,min);
                if (maj == MAJOR(res) && min == MINOR(res)) {
+                       down(&pm_sem);
                        swsusp_resume_device = res;
+                       up(&pm_sem);
                        printk("Attempting manual resume\n");
                        noresume = 0;
                        software_resume();
index 71aa0fd22007d8c5c188a4ce62c516726fd228d2..22bdc93cc03885096a5e29755e5f3f5aeadee68a 100644 (file)
@@ -143,11 +143,12 @@ static void suspend_finish(suspend_state_t state)
 
 
 
-static char * pm_states[] = {
+static char *pm_states[PM_SUSPEND_MAX] = {
        [PM_SUSPEND_STANDBY]    = "standby",
        [PM_SUSPEND_MEM]        = "mem",
+#ifdef CONFIG_SOFTWARE_SUSPEND
        [PM_SUSPEND_DISK]       = "disk",
-       NULL,
+#endif
 };
 
 
index 61deda04e39e2af3d7c31298665e02213afdafdd..159149321b3c2adb4dcf20372ada8edb2a098c7a 100644 (file)
@@ -60,9 +60,8 @@ struct pm_dev *pm_register(pm_dev_t type,
                           unsigned long id,
                           pm_callback callback)
 {
-       struct pm_dev *dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL);
+       struct pm_dev *dev = kzalloc(sizeof(struct pm_dev), GFP_KERNEL);
        if (dev) {
-               memset(dev, 0, sizeof(*dev));
                dev->type = type;
                dev->id = id;
                dev->callback = callback;
index 3bd0d261818f5d7769af8b265544dbe8abf5d519..28de118f7a0b047c6c507a8adbf2113ce52bb21d 100644 (file)
@@ -38,7 +38,6 @@ void refrigerator(void)
           processes around? */
        long save;
        save = current->state;
-       current->state = TASK_UNINTERRUPTIBLE;
        pr_debug("%s entered refrigerator\n", current->comm);
        printk("=");
 
@@ -47,8 +46,10 @@ void refrigerator(void)
        recalc_sigpending(); /* We sent fake signal, clean it up */
        spin_unlock_irq(&current->sighand->siglock);
 
-       while (frozen(current))
+       while (frozen(current)) {
+               current->state = TASK_UNINTERRUPTIBLE;
                schedule();
+       }
        pr_debug("%s left refrigerator\n", current->comm);
        current->state = save;
 }
@@ -80,13 +81,33 @@ int freeze_processes(void)
                } while_each_thread(g, p);
                read_unlock(&tasklist_lock);
                yield();                        /* Yield is okay here */
-               if (time_after(jiffies, start_time + TIMEOUT)) {
+               if (todo && time_after(jiffies, start_time + TIMEOUT)) {
                        printk( "\n" );
                        printk(KERN_ERR " stopping tasks failed (%d tasks remaining)\n", todo );
-                       return todo;
+                       break;
                }
        } while(todo);
 
+       /* This does not unfreeze processes that are already frozen
+        * (we have slightly ugly calling convention in that respect,
+        * and caller must call thaw_processes() if something fails),
+        * but it cleans up leftover PF_FREEZE requests.
+        */
+       if (todo) {
+               read_lock(&tasklist_lock);
+               do_each_thread(g, p)
+                       if (freezing(p)) {
+                               pr_debug("  clean up: %s\n", p->comm);
+                               p->flags &= ~PF_FREEZE;
+                               spin_lock_irqsave(&p->sighand->siglock, flags);
+                               recalc_sigpending_tsk(p);
+                               spin_unlock_irqrestore(&p->sighand->siglock, flags);
+                       }
+               while_each_thread(g, p);
+               read_unlock(&tasklist_lock);
+               return todo;
+       }
+
        printk( "|\n" );
        BUG_ON(in_atomic());
        return 0;
index f2bc71b9fe8be2dd226addc38ea7a7e48783317e..d967e875ee82f974d9f4e8e365aa59270a6f5c61 100644 (file)
@@ -31,6 +31,9 @@
  * Alex Badea <vampire@go.ro>:
  * Fixed runaway init
  *
+ * Andreas Steinmetz <ast@domdv.de>:
+ * Added encrypted suspend option
+ *
  * More state savers are welcome. Especially for the scsi layer...
  *
  * For TODOs,FIXMEs also look in Documentation/power/swsusp.txt
 #include <asm/tlbflush.h>
 #include <asm/io.h>
 
+#include <linux/random.h>
+#include <linux/crypto.h>
+#include <asm/scatterlist.h>
+
 #include "power.h"
 
+#define CIPHER "aes"
+#define MAXKEY 32
+#define MAXIV  32
+
 /* References to section boundaries */
 extern const void __nosave_begin, __nosave_end;
 
@@ -103,7 +114,8 @@ static suspend_pagedir_t *pagedir_save;
 #define SWSUSP_SIG     "S1SUSPEND"
 
 static struct swsusp_header {
-       char reserved[PAGE_SIZE - 20 - sizeof(swp_entry_t)];
+       char reserved[PAGE_SIZE - 20 - MAXKEY - MAXIV - sizeof(swp_entry_t)];
+       u8 key_iv[MAXKEY+MAXIV];
        swp_entry_t swsusp_info;
        char    orig_sig[10];
        char    sig[10];
@@ -129,6 +141,131 @@ static struct swsusp_info swsusp_info;
 static unsigned short swapfile_used[MAX_SWAPFILES];
 static unsigned short root_swap;
 
+static int write_page(unsigned long addr, swp_entry_t * loc);
+static int bio_read_page(pgoff_t page_off, void * page);
+
+static u8 key_iv[MAXKEY+MAXIV];
+
+#ifdef CONFIG_SWSUSP_ENCRYPT
+
+static int crypto_init(int mode, void **mem)
+{
+       int error = 0;
+       int len;
+       char *modemsg;
+       struct crypto_tfm *tfm;
+
+       modemsg = mode ? "suspend not possible" : "resume not possible";
+
+       tfm = crypto_alloc_tfm(CIPHER, CRYPTO_TFM_MODE_CBC);
+       if(!tfm) {
+               printk(KERN_ERR "swsusp: no tfm, %s\n", modemsg);
+               error = -EINVAL;
+               goto out;
+       }
+
+       if(MAXKEY < crypto_tfm_alg_min_keysize(tfm)) {
+               printk(KERN_ERR "swsusp: key buffer too small, %s\n", modemsg);
+               error = -ENOKEY;
+               goto fail;
+       }
+
+       if (mode)
+               get_random_bytes(key_iv, MAXKEY+MAXIV);
+
+       len = crypto_tfm_alg_max_keysize(tfm);
+       if (len > MAXKEY)
+               len = MAXKEY;
+
+       if (crypto_cipher_setkey(tfm, key_iv, len)) {
+               printk(KERN_ERR "swsusp: key setup failure, %s\n", modemsg);
+               error = -EKEYREJECTED;
+               goto fail;
+       }
+
+       len = crypto_tfm_alg_ivsize(tfm);
+
+       if (MAXIV < len) {
+               printk(KERN_ERR "swsusp: iv buffer too small, %s\n", modemsg);
+               error = -EOVERFLOW;
+               goto fail;
+       }
+
+       crypto_cipher_set_iv(tfm, key_iv+MAXKEY, len);
+
+       *mem=(void *)tfm;
+
+       goto out;
+
+fail:  crypto_free_tfm(tfm);
+out:   return error;
+}
+
+static __inline__ void crypto_exit(void *mem)
+{
+       crypto_free_tfm((struct crypto_tfm *)mem);
+}
+
+static __inline__ int crypto_write(struct pbe *p, void *mem)
+{
+       int error = 0;
+       struct scatterlist src, dst;
+
+       src.page   = virt_to_page(p->address);
+       src.offset = 0;
+       src.length = PAGE_SIZE;
+       dst.page   = virt_to_page((void *)&swsusp_header);
+       dst.offset = 0;
+       dst.length = PAGE_SIZE;
+
+       error = crypto_cipher_encrypt((struct crypto_tfm *)mem, &dst, &src,
+                                       PAGE_SIZE);
+
+       if (!error)
+               error = write_page((unsigned long)&swsusp_header,
+                               &(p->swap_address));
+       return error;
+}
+
+static __inline__ int crypto_read(struct pbe *p, void *mem)
+{
+       int error = 0;
+       struct scatterlist src, dst;
+
+       error = bio_read_page(swp_offset(p->swap_address), (void *)p->address);
+       if (!error) {
+               src.offset = 0;
+               src.length = PAGE_SIZE;
+               dst.offset = 0;
+               dst.length = PAGE_SIZE;
+               src.page = dst.page = virt_to_page((void *)p->address);
+
+               error = crypto_cipher_decrypt((struct crypto_tfm *)mem, &dst,
+                                               &src, PAGE_SIZE);
+       }
+       return error;
+}
+#else
+static __inline__ int crypto_init(int mode, void *mem)
+{
+       return 0;
+}
+
+static __inline__ void crypto_exit(void *mem)
+{
+}
+
+static __inline__ int crypto_write(struct pbe *p, void *mem)
+{
+       return write_page(p->address, &(p->swap_address));
+}
+
+static __inline__ int crypto_read(struct pbe *p, void *mem)
+{
+       return bio_read_page(swp_offset(p->swap_address), (void *)p->address);
+}
+#endif
+
 static int mark_swapfiles(swp_entry_t prev)
 {
        int error;
@@ -140,6 +277,7 @@ static int mark_swapfiles(swp_entry_t prev)
            !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) {
                memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
                memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
+               memcpy(swsusp_header.key_iv, key_iv, MAXKEY+MAXIV);
                swsusp_header.swsusp_info = prev;
                error = rw_swap_page_sync(WRITE,
                                          swp_entry(root_swap, 0),
@@ -179,9 +317,9 @@ static int swsusp_swap_check(void) /* This is called before saving image */
        len=strlen(resume_file);
        root_swap = 0xFFFF;
 
-       swap_list_lock();
+       spin_lock(&swap_lock);
        for (i=0; i<MAX_SWAPFILES; i++) {
-               if (swap_info[i].flags == 0) {
+               if (!(swap_info[i].flags & SWP_WRITEOK)) {
                        swapfile_used[i]=SWAPFILE_UNUSED;
                } else {
                        if (!len) {
@@ -202,7 +340,7 @@ static int swsusp_swap_check(void) /* This is called before saving image */
                        }
                }
        }
-       swap_list_unlock();
+       spin_unlock(&swap_lock);
        return (root_swap != 0xffff) ? 0 : -ENODEV;
 }
 
@@ -216,12 +354,12 @@ static void lock_swapdevices(void)
 {
        int i;
 
-       swap_list_lock();
+       spin_lock(&swap_lock);
        for (i = 0; i< MAX_SWAPFILES; i++)
                if (swapfile_used[i] == SWAPFILE_IGNORED) {
-                       swap_info[i].flags ^= 0xFF;
+                       swap_info[i].flags ^= SWP_WRITEOK;
                }
-       swap_list_unlock();
+       spin_unlock(&swap_lock);
 }
 
 /**
@@ -286,6 +424,10 @@ static int data_write(void)
        int error = 0, i = 0;
        unsigned int mod = nr_copy_pages / 100;
        struct pbe *p;
+       void *tfm;
+
+       if ((error = crypto_init(1, &tfm)))
+               return error;
 
        if (!mod)
                mod = 1;
@@ -294,11 +436,14 @@ static int data_write(void)
        for_each_pbe (p, pagedir_nosave) {
                if (!(i%mod))
                        printk( "\b\b\b\b%3d%%", i / mod );
-               if ((error = write_page(p->address, &(p->swap_address))))
+               if ((error = crypto_write(p, tfm))) {
+                       crypto_exit(tfm);
                        return error;
+               }
                i++;
        }
        printk("\b\b\b\bdone\n");
+       crypto_exit(tfm);
        return error;
 }
 
@@ -385,7 +530,6 @@ static int write_pagedir(void)
  *     write_suspend_image - Write entire image and metadata.
  *
  */
-
 static int write_suspend_image(void)
 {
        int error;
@@ -400,6 +544,7 @@ static int write_suspend_image(void)
        if ((error = close_swap()))
                goto FreePagedir;
  Done:
+       memset(key_iv, 0, MAXKEY+MAXIV);
        return error;
  FreePagedir:
        free_pagedir_entries();
@@ -591,18 +736,7 @@ static void copy_data_pages(void)
 
 static int calc_nr(int nr_copy)
 {
-       int extra = 0;
-       int mod = !!(nr_copy % PBES_PER_PAGE);
-       int diff = (nr_copy / PBES_PER_PAGE) + mod;
-
-       do {
-               extra += diff;
-               nr_copy += diff;
-               mod = !!(nr_copy % PBES_PER_PAGE);
-               diff = (nr_copy / PBES_PER_PAGE) + mod - extra;
-       } while (diff > 0);
-
-       return nr_copy;
+       return nr_copy + (nr_copy+PBES_PER_PAGE-2)/(PBES_PER_PAGE-1);
 }
 
 /**
@@ -886,20 +1020,21 @@ int swsusp_suspend(void)
         * at resume time, and evil weirdness ensues.
         */
        if ((error = device_power_down(PMSG_FREEZE))) {
+               printk(KERN_ERR "Some devices failed to power down, aborting suspend\n");
                local_irq_enable();
                return error;
        }
 
        if ((error = swsusp_swap_check())) {
-               printk(KERN_ERR "swsusp: FATAL: cannot find swap device, try "
-                               "swapon -a!\n");
+               printk(KERN_ERR "swsusp: cannot find swap device, try swapon -a.\n");
+               device_power_up();
                local_irq_enable();
                return error;
        }
 
        save_processor_state();
        if ((error = swsusp_arch_suspend()))
-               printk("Error %d suspending\n", error);
+               printk(KERN_ERR "Error %d suspending\n", error);
        /* Restore control flow magically appears here */
        restore_processor_state();
        BUG_ON (nr_copy_pages_check != nr_copy_pages);
@@ -924,6 +1059,7 @@ int swsusp_resume(void)
        BUG_ON(!error);
        restore_processor_state();
        restore_highmem();
+       touch_softlockup_watchdog();
        device_power_up();
        local_irq_enable();
        return error;
@@ -1179,7 +1315,8 @@ static const char * sanity_check(void)
        if (strcmp(swsusp_info.uts.machine,system_utsname.machine))
                return "machine";
 #if 0
-       if(swsusp_info.cpus != num_online_cpus())
+       /* We can't use number of online CPUs when we use hotplug to remove them ;-))) */
+       if (swsusp_info.cpus != num_possible_cpus())
                return "number of cpus";
 #endif
        return NULL;
@@ -1212,13 +1349,14 @@ static int check_sig(void)
                return error;
        if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
                memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
+               memcpy(key_iv, swsusp_header.key_iv, MAXKEY+MAXIV);
+               memset(swsusp_header.key_iv, 0, MAXKEY+MAXIV);
 
                /*
                 * Reset swap signature now.
                 */
                error = bio_write_page(0, &swsusp_header);
        } else { 
-               printk(KERN_ERR "swsusp: Suspend partition has wrong signature?\n");
                return -EINVAL;
        }
        if (!error)
@@ -1239,6 +1377,10 @@ static int data_read(struct pbe *pblist)
        int error = 0;
        int i = 0;
        int mod = swsusp_info.image_pages / 100;
+       void *tfm;
+
+       if ((error = crypto_init(0, &tfm)))
+               return error;
 
        if (!mod)
                mod = 1;
@@ -1250,14 +1392,15 @@ static int data_read(struct pbe *pblist)
                if (!(i % mod))
                        printk("\b\b\b\b%3d%%", i / mod);
 
-               error = bio_read_page(swp_offset(p->swap_address),
-                                 (void *)p->address);
-               if (error)
+               if ((error = crypto_read(p, tfm))) {
+                       crypto_exit(tfm);
                        return error;
+               }
 
                i++;
        }
        printk("\b\b\b\bdone\n");
+       crypto_exit(tfm);
        return error;
 }
 
@@ -1385,6 +1528,7 @@ int swsusp_read(void)
 
        error = read_suspend_image();
        blkdev_put(resume_bdev);
+       memset(key_iv, 0, MAXKEY+MAXIV);
 
        if (!error)
                pr_debug("swsusp: Reading resume file was successful\n");
index 5092397fac29926bfab6da75fc273882b14e905d..a967605bc2e358cbcf95dd7fe60f7870fe9dd14b 100644 (file)
@@ -514,6 +514,9 @@ asmlinkage int printk(const char *fmt, ...)
        return r;
 }
 
+/* cpu currently holding logbuf_lock */
+static volatile unsigned int printk_cpu = UINT_MAX;
+
 asmlinkage int vprintk(const char *fmt, va_list args)
 {
        unsigned long flags;
@@ -522,11 +525,15 @@ asmlinkage int vprintk(const char *fmt, va_list args)
        static char printk_buf[1024];
        static int log_level_unknown = 1;
 
-       if (unlikely(oops_in_progress))
+       preempt_disable();
+       if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id())
+               /* If a crash is occurring during printk() on this CPU,
+                * make sure we can't deadlock */
                zap_locks();
 
        /* This stops the holder of console_sem just where we want him */
        spin_lock_irqsave(&logbuf_lock, flags);
+       printk_cpu = smp_processor_id();
 
        /* Emit the output into the temporary buffer */
        printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
@@ -595,6 +602,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
                 * CPU until it is officially up.  We shouldn't be calling into
                 * random console drivers on a CPU which doesn't exist yet..
                 */
+               printk_cpu = UINT_MAX;
                spin_unlock_irqrestore(&logbuf_lock, flags);
                goto out;
        }
@@ -604,6 +612,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
                 * We own the drivers.  We can drop the spinlock and let
                 * release_console_sem() print the text
                 */
+               printk_cpu = UINT_MAX;
                spin_unlock_irqrestore(&logbuf_lock, flags);
                console_may_schedule = 0;
                release_console_sem();
@@ -613,9 +622,11 @@ asmlinkage int vprintk(const char *fmt, va_list args)
                 * allows the semaphore holder to proceed and to call the
                 * console drivers with the output which we just produced.
                 */
+               printk_cpu = UINT_MAX;
                spin_unlock_irqrestore(&logbuf_lock, flags);
        }
 out:
+       preempt_enable();
        return printed_len;
 }
 EXPORT_SYMBOL(printk);
index 8dcb8f6288bcecf1f436a2904c0ded883f9d3862..019e04ec065a55d8f28157d3a1f7ba06cafd347f 100644 (file)
@@ -118,6 +118,33 @@ int ptrace_check_attach(struct task_struct *child, int kill)
        return ret;
 }
 
+static int may_attach(struct task_struct *task)
+{
+       if (!task->mm)
+               return -EPERM;
+       if (((current->uid != task->euid) ||
+            (current->uid != task->suid) ||
+            (current->uid != task->uid) ||
+            (current->gid != task->egid) ||
+            (current->gid != task->sgid) ||
+            (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
+               return -EPERM;
+       smp_rmb();
+       if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE))
+               return -EPERM;
+
+       return security_ptrace(current, task);
+}
+
+int ptrace_may_attach(struct task_struct *task)
+{
+       int err;
+       task_lock(task);
+       err = may_attach(task);
+       task_unlock(task);
+       return !err;
+}
+
 int ptrace_attach(struct task_struct *task)
 {
        int retval;
@@ -127,22 +154,10 @@ int ptrace_attach(struct task_struct *task)
                goto bad;
        if (task == current)
                goto bad;
-       if (!task->mm)
-               goto bad;
-       if(((current->uid != task->euid) ||
-           (current->uid != task->suid) ||
-           (current->uid != task->uid) ||
-           (current->gid != task->egid) ||
-           (current->gid != task->sgid) ||
-           (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
-               goto bad;
-       smp_rmb();
-       if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE))
-               goto bad;
        /* the same process cannot be attached many times */
        if (task->ptrace & PT_PTRACED)
                goto bad;
-       retval = security_ptrace(current, task);
+       retval = may_attach(task);
        if (retval)
                goto bad;
 
index 26967e0422014a5957f4b01bbed9a4cea40098bf..92285d822de6c9ce3a75825b7b876b8379d522d6 100644 (file)
@@ -430,10 +430,9 @@ EXPORT_SYMBOL(adjust_resource);
  */
 struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
 {
-       struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
+       struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
 
        if (res) {
-               memset(res, 0, sizeof(*res));
                res->name = name;
                res->start = start;
                res->end = start + n - 1;
index 5f889d0cbfcc2e614aef87963ec0bea5ea6a5f21..18b95520a2e29bdfa181aecb913f0ea50995f609 100644 (file)
@@ -1478,6 +1478,7 @@ static inline void prepare_task_switch(runqueue_t *rq, task_t *next)
 
 /**
  * finish_task_switch - clean up after a task-switch
+ * @rq: runqueue associated with task-switch
  * @prev: the thread we just switched away from.
  *
  * finish_task_switch must be called after the context switch, paired
@@ -4779,7 +4780,7 @@ static int sd_parent_degenerate(struct sched_domain *sd,
  * Attach the domain 'sd' to 'cpu' as its base domain.  Callers must
  * hold the hotplug lock.
  */
-void cpu_attach_domain(struct sched_domain *sd, int cpu)
+static void cpu_attach_domain(struct sched_domain *sd, int cpu)
 {
        runqueue_t *rq = cpu_rq(cpu);
        struct sched_domain *tmp;
@@ -4802,7 +4803,7 @@ void cpu_attach_domain(struct sched_domain *sd, int cpu)
 }
 
 /* cpus with isolated domains */
-cpumask_t __devinitdata cpu_isolated_map = CPU_MASK_NONE;
+static cpumask_t __devinitdata cpu_isolated_map = CPU_MASK_NONE;
 
 /* Setup the mask of cpus configured for isolated domains */
 static int __init isolated_cpu_setup(char *str)
@@ -4830,8 +4831,8 @@ __setup ("isolcpus=", isolated_cpu_setup);
  * covered by the given span, and will set each group's ->cpumask correctly,
  * and ->cpu_power to 0.
  */
-void init_sched_build_groups(struct sched_group groups[],
-                       cpumask_t span, int (*group_fn)(int cpu))
+static void init_sched_build_groups(struct sched_group groups[], cpumask_t span,
+                                   int (*group_fn)(int cpu))
 {
        struct sched_group *first = NULL, *last = NULL;
        cpumask_t covered = CPU_MASK_NONE;
@@ -4864,12 +4865,85 @@ void init_sched_build_groups(struct sched_group groups[],
        last->next = first;
 }
 
+#define SD_NODES_PER_DOMAIN 16
 
-#ifdef ARCH_HAS_SCHED_DOMAIN
-extern void build_sched_domains(const cpumask_t *cpu_map);
-extern void arch_init_sched_domains(const cpumask_t *cpu_map);
-extern void arch_destroy_sched_domains(const cpumask_t *cpu_map);
-#else
+#ifdef CONFIG_NUMA
+/**
+ * find_next_best_node - find the next node to include in a sched_domain
+ * @node: node whose sched_domain we're building
+ * @used_nodes: nodes already in the sched_domain
+ *
+ * Find the next node to include in a given scheduling domain.  Simply
+ * finds the closest node not already in the @used_nodes map.
+ *
+ * Should use nodemask_t.
+ */
+static int find_next_best_node(int node, unsigned long *used_nodes)
+{
+       int i, n, val, min_val, best_node = 0;
+
+       min_val = INT_MAX;
+
+       for (i = 0; i < MAX_NUMNODES; i++) {
+               /* Start at @node */
+               n = (node + i) % MAX_NUMNODES;
+
+               if (!nr_cpus_node(n))
+                       continue;
+
+               /* Skip already used nodes */
+               if (test_bit(n, used_nodes))
+                       continue;
+
+               /* Simple min distance search */
+               val = node_distance(node, n);
+
+               if (val < min_val) {
+                       min_val = val;
+                       best_node = n;
+               }
+       }
+
+       set_bit(best_node, used_nodes);
+       return best_node;
+}
+
+/**
+ * sched_domain_node_span - get a cpumask for a node's sched_domain
+ * @node: node whose cpumask we're constructing
+ * @size: number of nodes to include in this span
+ *
+ * Given a node, construct a good cpumask for its sched_domain to span.  It
+ * should be one that prevents unnecessary balancing, but also spreads tasks
+ * out optimally.
+ */
+static cpumask_t sched_domain_node_span(int node)
+{
+       int i;
+       cpumask_t span, nodemask;
+       DECLARE_BITMAP(used_nodes, MAX_NUMNODES);
+
+       cpus_clear(span);
+       bitmap_zero(used_nodes, MAX_NUMNODES);
+
+       nodemask = node_to_cpumask(node);
+       cpus_or(span, span, nodemask);
+       set_bit(node, used_nodes);
+
+       for (i = 1; i < SD_NODES_PER_DOMAIN; i++) {
+               int next_node = find_next_best_node(node, used_nodes);
+               nodemask = node_to_cpumask(next_node);
+               cpus_or(span, span, nodemask);
+       }
+
+       return span;
+}
+#endif
+
+/*
+ * At the moment, CONFIG_SCHED_SMT is never defined, but leave it in so we
+ * can switch it on easily if needed.
+ */
 #ifdef CONFIG_SCHED_SMT
 static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
 static struct sched_group sched_group_cpus[NR_CPUS];
@@ -4891,36 +4965,20 @@ static int cpu_to_phys_group(int cpu)
 }
 
 #ifdef CONFIG_NUMA
-
-static DEFINE_PER_CPU(struct sched_domain, node_domains);
-static struct sched_group sched_group_nodes[MAX_NUMNODES];
-static int cpu_to_node_group(int cpu)
-{
-       return cpu_to_node(cpu);
-}
-#endif
-
-#if defined(CONFIG_SCHED_SMT) && defined(CONFIG_NUMA)
 /*
- * The domains setup code relies on siblings not spanning
- * multiple nodes. Make sure the architecture has a proper
- * siblings map:
+ * The init_sched_build_groups can't handle what we want to do with node
+ * groups, so roll our own. Now each node has its own list of groups which
+ * gets dynamically allocated.
  */
-static void check_sibling_maps(void)
-{
-       int i, j;
+static DEFINE_PER_CPU(struct sched_domain, node_domains);
+static struct sched_group **sched_group_nodes_bycpu[NR_CPUS];
 
-       for_each_online_cpu(i) {
-               for_each_cpu_mask(j, cpu_sibling_map[i]) {
-                       if (cpu_to_node(i) != cpu_to_node(j)) {
-                               printk(KERN_INFO "warning: CPU %d siblings map "
-                                       "to different node - isolating "
-                                       "them.\n", i);
-                               cpu_sibling_map[i] = cpumask_of_cpu(i);
-                               break;
-                       }
-               }
-       }
+static DEFINE_PER_CPU(struct sched_domain, allnodes_domains);
+static struct sched_group *sched_group_allnodes_bycpu[NR_CPUS];
+
+static int cpu_to_allnodes_group(int cpu)
+{
+       return cpu_to_node(cpu);
 }
 #endif
 
@@ -4928,9 +4986,24 @@ static void check_sibling_maps(void)
  * Build sched domains for a given set of cpus and attach the sched domains
  * to the individual cpus
  */
-static void build_sched_domains(const cpumask_t *cpu_map)
+void build_sched_domains(const cpumask_t *cpu_map)
 {
        int i;
+#ifdef CONFIG_NUMA
+       struct sched_group **sched_group_nodes = NULL;
+       struct sched_group *sched_group_allnodes = NULL;
+
+       /*
+        * Allocate the per-node list of sched groups
+        */
+       sched_group_nodes = kmalloc(sizeof(struct sched_group*)*MAX_NUMNODES,
+                                          GFP_ATOMIC);
+       if (!sched_group_nodes) {
+               printk(KERN_WARNING "Can not alloc sched group node list\n");
+               return;
+       }
+       sched_group_nodes_bycpu[first_cpu(*cpu_map)] = sched_group_nodes;
+#endif
 
        /*
         * Set up domains for cpus specified by the cpu_map.
@@ -4943,11 +5016,35 @@ static void build_sched_domains(const cpumask_t *cpu_map)
                cpus_and(nodemask, nodemask, *cpu_map);
 
 #ifdef CONFIG_NUMA
+               if (cpus_weight(*cpu_map)
+                               > SD_NODES_PER_DOMAIN*cpus_weight(nodemask)) {
+                       if (!sched_group_allnodes) {
+                               sched_group_allnodes
+                                       = kmalloc(sizeof(struct sched_group)
+                                                       * MAX_NUMNODES,
+                                                 GFP_KERNEL);
+                               if (!sched_group_allnodes) {
+                                       printk(KERN_WARNING
+                                       "Can not alloc allnodes sched group\n");
+                                       break;
+                               }
+                               sched_group_allnodes_bycpu[i]
+                                               = sched_group_allnodes;
+                       }
+                       sd = &per_cpu(allnodes_domains, i);
+                       *sd = SD_ALLNODES_INIT;
+                       sd->span = *cpu_map;
+                       group = cpu_to_allnodes_group(i);
+                       sd->groups = &sched_group_allnodes[group];
+                       p = sd;
+               } else
+                       p = NULL;
+
                sd = &per_cpu(node_domains, i);
-               group = cpu_to_node_group(i);
                *sd = SD_NODE_INIT;
-               sd->span = *cpu_map;
-               sd->groups = &sched_group_nodes[group];
+               sd->span = sched_domain_node_span(cpu_to_node(i));
+               sd->parent = p;
+               cpus_and(sd->span, sd->span, *cpu_map);
 #endif
 
                p = sd;
@@ -4972,7 +5069,7 @@ static void build_sched_domains(const cpumask_t *cpu_map)
 
 #ifdef CONFIG_SCHED_SMT
        /* Set up CPU (sibling) groups */
-       for_each_online_cpu(i) {
+       for_each_cpu_mask(i, *cpu_map) {
                cpumask_t this_sibling_map = cpu_sibling_map[i];
                cpus_and(this_sibling_map, this_sibling_map, *cpu_map);
                if (i != first_cpu(this_sibling_map))
@@ -4997,8 +5094,77 @@ static void build_sched_domains(const cpumask_t *cpu_map)
 
 #ifdef CONFIG_NUMA
        /* Set up node groups */
-       init_sched_build_groups(sched_group_nodes, *cpu_map,
-                                       &cpu_to_node_group);
+       if (sched_group_allnodes)
+               init_sched_build_groups(sched_group_allnodes, *cpu_map,
+                                       &cpu_to_allnodes_group);
+
+       for (i = 0; i < MAX_NUMNODES; i++) {
+               /* Set up node groups */
+               struct sched_group *sg, *prev;
+               cpumask_t nodemask = node_to_cpumask(i);
+               cpumask_t domainspan;
+               cpumask_t covered = CPU_MASK_NONE;
+               int j;
+
+               cpus_and(nodemask, nodemask, *cpu_map);
+               if (cpus_empty(nodemask)) {
+                       sched_group_nodes[i] = NULL;
+                       continue;
+               }
+
+               domainspan = sched_domain_node_span(i);
+               cpus_and(domainspan, domainspan, *cpu_map);
+
+               sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL);
+               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;
+               cpus_or(covered, covered, nodemask);
+               prev = sg;
+
+               for (j = 0; j < MAX_NUMNODES; j++) {
+                       cpumask_t tmp, notcovered;
+                       int n = (i + j) % MAX_NUMNODES;
+
+                       cpus_complement(notcovered, covered);
+                       cpus_and(tmp, notcovered, *cpu_map);
+                       cpus_and(tmp, tmp, domainspan);
+                       if (cpus_empty(tmp))
+                               break;
+
+                       nodemask = node_to_cpumask(n);
+                       cpus_and(tmp, tmp, nodemask);
+                       if (cpus_empty(tmp))
+                               continue;
+
+                       sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL);
+                       if (!sg) {
+                               printk(KERN_WARNING
+                               "Can not alloc domain group for node %d\n", j);
+                               break;
+                       }
+                       sg->cpu_power = 0;
+                       sg->cpumask = tmp;
+                       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 */
@@ -5017,14 +5183,46 @@ static void build_sched_domains(const cpumask_t *cpu_map)
                sd->groups->cpu_power = power;
 
 #ifdef CONFIG_NUMA
-               if (i == first_cpu(sd->groups->cpumask)) {
-                       /* Only add "power" once for each physical package. */
-                       sd = &per_cpu(node_domains, i);
-                       sd->groups->cpu_power += power;
+               sd = &per_cpu(allnodes_domains, i);
+               if (sd->groups) {
+                       power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
+                               (cpus_weight(sd->groups->cpumask)-1) / 10;
+                       sd->groups->cpu_power = power;
                }
 #endif
        }
 
+#ifdef CONFIG_NUMA
+       for (i = 0; i < MAX_NUMNODES; i++) {
+               struct sched_group *sg = sched_group_nodes[i];
+               int j;
+
+               if (sg == NULL)
+                       continue;
+next_sg:
+               for_each_cpu_mask(j, sg->cpumask) {
+                       struct sched_domain *sd;
+                       int power;
+
+                       sd = &per_cpu(phys_domains, j);
+                       if (j != first_cpu(sd->groups->cpumask)) {
+                               /*
+                                * Only add "power" once for each
+                                * physical package.
+                                */
+                               continue;
+                       }
+                       power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
+                               (cpus_weight(sd->groups->cpumask)-1) / 10;
+
+                       sg->cpu_power += power;
+               }
+               sg = sg->next;
+               if (sg != sched_group_nodes[i])
+                       goto next_sg;
+       }
+#endif
+
        /* Attach the domains */
        for_each_cpu_mask(i, *cpu_map) {
                struct sched_domain *sd;
@@ -5039,13 +5237,10 @@ static void build_sched_domains(const cpumask_t *cpu_map)
 /*
  * Set up scheduler domains and groups.  Callers must hold the hotplug lock.
  */
-static void arch_init_sched_domains(cpumask_t *cpu_map)
+static void arch_init_sched_domains(const cpumask_t *cpu_map)
 {
        cpumask_t cpu_default_map;
 
-#if defined(CONFIG_SCHED_SMT) && defined(CONFIG_NUMA)
-       check_sibling_maps();
-#endif
        /*
         * Setup mask for cpus without special case scheduling requirements.
         * For now this just excludes isolated cpus, but could be used to
@@ -5058,10 +5253,47 @@ static void arch_init_sched_domains(cpumask_t *cpu_map)
 
 static void arch_destroy_sched_domains(const cpumask_t *cpu_map)
 {
-       /* Do nothing: everything is statically allocated. */
-}
+#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];
 
-#endif /* ARCH_HAS_SCHED_DOMAIN */
+                       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
+}
 
 /*
  * Detach sched domains from a group of cpus specified in cpu_map
index d282fea8113815c441417f91c8c0a5374879a4a3..4980a073237ff45ed28c39b38225c40923da0848 100644 (file)
@@ -678,7 +678,7 @@ static int check_kill_permission(int sig, struct siginfo *info,
 
 /* forward decl */
 static void do_notify_parent_cldstop(struct task_struct *tsk,
-                                    struct task_struct *parent,
+                                    int to_self,
                                     int why);
 
 /*
@@ -729,14 +729,7 @@ static void handle_stop_signal(int sig, struct task_struct *p)
                        p->signal->group_stop_count = 0;
                        p->signal->flags = SIGNAL_STOP_CONTINUED;
                        spin_unlock(&p->sighand->siglock);
-                       if (p->ptrace & PT_PTRACED)
-                               do_notify_parent_cldstop(p, p->parent,
-                                                        CLD_STOPPED);
-                       else
-                               do_notify_parent_cldstop(
-                                       p->group_leader,
-                                       p->group_leader->real_parent,
-                                                        CLD_STOPPED);
+                       do_notify_parent_cldstop(p, (p->ptrace & PT_PTRACED), CLD_STOPPED);
                        spin_lock(&p->sighand->siglock);
                }
                rm_from_queue(SIG_KERNEL_STOP_MASK, &p->signal->shared_pending);
@@ -777,14 +770,7 @@ static void handle_stop_signal(int sig, struct task_struct *p)
                        p->signal->flags = SIGNAL_STOP_CONTINUED;
                        p->signal->group_exit_code = 0;
                        spin_unlock(&p->sighand->siglock);
-                       if (p->ptrace & PT_PTRACED)
-                               do_notify_parent_cldstop(p, p->parent,
-                                                        CLD_CONTINUED);
-                       else
-                               do_notify_parent_cldstop(
-                                       p->group_leader,
-                                       p->group_leader->real_parent,
-                                                        CLD_CONTINUED);
+                       do_notify_parent_cldstop(p, (p->ptrace & PT_PTRACED), CLD_CONTINUED);
                        spin_lock(&p->sighand->siglock);
                } else {
                        /*
@@ -1380,16 +1366,16 @@ send_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
        unsigned long flags;
        int ret = 0;
 
-       /*
-        * We need the tasklist lock even for the specific
-        * thread case (when we don't need to follow the group
-        * lists) in order to avoid races with "p->sighand"
-        * going away or changing from under us.
-        */
        BUG_ON(!(q->flags & SIGQUEUE_PREALLOC));
-       read_lock(&tasklist_lock);  
+       read_lock(&tasklist_lock);
+
+       if (unlikely(p->flags & PF_EXITING)) {
+               ret = -1;
+               goto out_err;
+       }
+
        spin_lock_irqsave(&p->sighand->siglock, flags);
-       
+
        if (unlikely(!list_empty(&q->list))) {
                /*
                 * If an SI_TIMER entry is already queue just increment
@@ -1399,7 +1385,7 @@ send_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
                        BUG();
                q->info.si_overrun++;
                goto out;
-       } 
+       }
        /* Short-circuit ignored signals.  */
        if (sig_ignored(p, sig)) {
                ret = 1;
@@ -1414,8 +1400,10 @@ send_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
 
 out:
        spin_unlock_irqrestore(&p->sighand->siglock, flags);
+out_err:
        read_unlock(&tasklist_lock);
-       return(ret);
+
+       return ret;
 }
 
 int
@@ -1542,14 +1530,20 @@ void do_notify_parent(struct task_struct *tsk, int sig)
        spin_unlock_irqrestore(&psig->siglock, flags);
 }
 
-static void
-do_notify_parent_cldstop(struct task_struct *tsk, struct task_struct *parent,
-                        int why)
+static void do_notify_parent_cldstop(struct task_struct *tsk, int to_self, int why)
 {
        struct siginfo info;
        unsigned long flags;
+       struct task_struct *parent;
        struct sighand_struct *sighand;
 
+       if (to_self)
+               parent = tsk->parent;
+       else {
+               tsk = tsk->group_leader;
+               parent = tsk->real_parent;
+       }
+
        info.si_signo = SIGCHLD;
        info.si_errno = 0;
        info.si_pid = tsk->pid;
@@ -1618,8 +1612,7 @@ static void ptrace_stop(int exit_code, int nostop_code, siginfo_t *info)
                   !(current->ptrace & PT_ATTACHED)) &&
            (likely(current->parent->signal != current->signal) ||
             !unlikely(current->signal->flags & SIGNAL_GROUP_EXIT))) {
-               do_notify_parent_cldstop(current, current->parent,
-                                        CLD_TRAPPED);
+               do_notify_parent_cldstop(current, 1, CLD_TRAPPED);
                read_unlock(&tasklist_lock);
                schedule();
        } else {
@@ -1668,25 +1661,25 @@ void ptrace_notify(int exit_code)
 static void
 finish_stop(int stop_count)
 {
+       int to_self;
+
        /*
         * If there are no other threads in the group, or if there is
         * a group stop in progress and we are the last to stop,
         * report to the parent.  When ptraced, every thread reports itself.
         */
-       if (stop_count < 0 || (current->ptrace & PT_PTRACED)) {
-               read_lock(&tasklist_lock);
-               do_notify_parent_cldstop(current, current->parent,
-                                        CLD_STOPPED);
-               read_unlock(&tasklist_lock);
-       }
-       else if (stop_count == 0) {
-               read_lock(&tasklist_lock);
-               do_notify_parent_cldstop(current->group_leader,
-                                        current->group_leader->real_parent,
-                                        CLD_STOPPED);
-               read_unlock(&tasklist_lock);
-       }
+       if (stop_count < 0 || (current->ptrace & PT_PTRACED))
+               to_self = 1;
+       else if (stop_count == 0)
+               to_self = 0;
+       else
+               goto out;
 
+       read_lock(&tasklist_lock);
+       do_notify_parent_cldstop(current, to_self, CLD_STOPPED);
+       read_unlock(&tasklist_lock);
+
+out:
        schedule();
        /*
         * Now we don't run again until continued.
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
new file mode 100644 (file)
index 0000000..7597620
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Detect Soft Lockups
+ *
+ * started by Ingo Molnar, (C) 2005, Red Hat
+ *
+ * this code detects soft lockups: incidents in where on a CPU
+ * the kernel does not reschedule for 10 seconds or more.
+ */
+
+#include <linux/mm.h>
+#include <linux/cpu.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/notifier.h>
+#include <linux/module.h>
+
+static DEFINE_SPINLOCK(print_lock);
+
+static DEFINE_PER_CPU(unsigned long, timestamp) = 0;
+static DEFINE_PER_CPU(unsigned long, print_timestamp) = 0;
+static DEFINE_PER_CPU(struct task_struct *, watchdog_task);
+
+static int did_panic = 0;
+static int softlock_panic(struct notifier_block *this, unsigned long event,
+                               void *ptr)
+{
+       did_panic = 1;
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_block = {
+       .notifier_call = softlock_panic,
+};
+
+void touch_softlockup_watchdog(void)
+{
+       per_cpu(timestamp, raw_smp_processor_id()) = jiffies;
+}
+EXPORT_SYMBOL(touch_softlockup_watchdog);
+
+/*
+ * This callback runs from the timer interrupt, and checks
+ * whether the watchdog thread has hung or not:
+ */
+void softlockup_tick(struct pt_regs *regs)
+{
+       int this_cpu = smp_processor_id();
+       unsigned long timestamp = per_cpu(timestamp, this_cpu);
+
+       if (per_cpu(print_timestamp, this_cpu) == timestamp)
+               return;
+
+       /* Do not cause a second panic when there already was one */
+       if (did_panic)
+               return;
+
+       if (time_after(jiffies, timestamp + 10*HZ)) {
+               per_cpu(print_timestamp, this_cpu) = timestamp;
+
+               spin_lock(&print_lock);
+               printk(KERN_ERR "BUG: soft lockup detected on CPU#%d!\n",
+                       this_cpu);
+               show_regs(regs);
+               spin_unlock(&print_lock);
+       }
+}
+
+/*
+ * The watchdog thread - runs every second and touches the timestamp.
+ */
+static int watchdog(void * __bind_cpu)
+{
+       struct sched_param param = { .sched_priority = 99 };
+       int this_cpu = (long) __bind_cpu;
+
+       printk("softlockup thread %d started up.\n", this_cpu);
+
+       sched_setscheduler(current, SCHED_FIFO, &param);
+       current->flags |= PF_NOFREEZE;
+
+       set_current_state(TASK_INTERRUPTIBLE);
+
+       /*
+        * Run briefly once per second - if this gets delayed for
+        * more than 10 seconds then the debug-printout triggers
+        * in softlockup_tick():
+        */
+       while (!kthread_should_stop()) {
+               msleep_interruptible(1000);
+               touch_softlockup_watchdog();
+       }
+       __set_current_state(TASK_RUNNING);
+
+       return 0;
+}
+
+/*
+ * Create/destroy watchdog threads as CPUs come and go:
+ */
+static int __devinit
+cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
+{
+       int hotcpu = (unsigned long)hcpu;
+       struct task_struct *p;
+
+       switch (action) {
+       case CPU_UP_PREPARE:
+               BUG_ON(per_cpu(watchdog_task, hotcpu));
+               p = kthread_create(watchdog, hcpu, "watchdog/%d", hotcpu);
+               if (IS_ERR(p)) {
+                       printk("watchdog for %i failed\n", hotcpu);
+                       return NOTIFY_BAD;
+               }
+               per_cpu(watchdog_task, hotcpu) = p;
+               kthread_bind(p, hotcpu);
+               break;
+       case CPU_ONLINE:
+
+               wake_up_process(per_cpu(watchdog_task, hotcpu));
+               break;
+#ifdef CONFIG_HOTPLUG_CPU
+       case CPU_UP_CANCELED:
+               /* Unbind so it can run.  Fall thru. */
+               kthread_bind(per_cpu(watchdog_task, hotcpu), smp_processor_id());
+       case CPU_DEAD:
+               p = per_cpu(watchdog_task, hotcpu);
+               per_cpu(watchdog_task, hotcpu) = NULL;
+               kthread_stop(p);
+               break;
+#endif /* CONFIG_HOTPLUG_CPU */
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block __devinitdata cpu_nfb = {
+       .notifier_call = cpu_callback
+};
+
+__init void spawn_softlockup_task(void)
+{
+       void *cpu = (void *)(long)smp_processor_id();
+
+       cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
+       cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
+       register_cpu_notifier(&cpu_nfb);
+
+       notifier_chain_register(&panic_notifier_list, &panic_block);
+}
+
index 0bcaed6560ac19f72ab308b2fe92839238e9ba70..c80412be2302c6321898b57ef3a99d10a1c21a68 100644 (file)
@@ -1711,7 +1711,6 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
                          unsigned long arg4, unsigned long arg5)
 {
        long error;
-       int sig;
 
        error = security_task_prctl(option, arg2, arg3, arg4, arg5);
        if (error)
@@ -1719,12 +1718,11 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
 
        switch (option) {
                case PR_SET_PDEATHSIG:
-                       sig = arg2;
-                       if (!valid_signal(sig)) {
+                       if (!valid_signal(arg2)) {
                                error = -EINVAL;
                                break;
                        }
-                       current->pdeath_signal = sig;
+                       current->pdeath_signal = arg2;
                        break;
                case PR_GET_PDEATHSIG:
                        error = put_user(current->pdeath_signal, (int __user *)arg2);
index 3e0bbee549ea32270b523e58e76c1a5fb80cf70b..8e56e2495542be41fa688aa7a15604cb2e3e6897 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/net.h>
 #include <linux/sysrq.h>
 #include <linux/highuid.h>
 #include <linux/writeback.h>
@@ -136,9 +137,6 @@ static struct ctl_table_header root_table_header =
 
 static ctl_table kern_table[];
 static ctl_table vm_table[];
-#ifdef CONFIG_NET
-extern ctl_table net_table[];
-#endif
 static ctl_table proc_table[];
 static ctl_table fs_table[];
 static ctl_table debug_table[];
index 5377f40723ff0dc37f13897847ea040f8c317292..13e2b513be019bf0b8b6b9218e4f268fff95f58a 100644 (file)
@@ -950,6 +950,7 @@ void do_timer(struct pt_regs *regs)
 {
        jiffies_64++;
        update_times();
+       softlockup_tick(regs);
 }
 
 #ifdef __ARCH_WANT_SYS_ALARM
@@ -1428,7 +1429,7 @@ static inline u64 time_interpolator_get_cycles(unsigned int src)
        }
 }
 
-static inline u64 time_interpolator_get_counter(void)
+static inline u64 time_interpolator_get_counter(int writelock)
 {
        unsigned int src = time_interpolator->source;
 
@@ -1442,6 +1443,15 @@ static inline u64 time_interpolator_get_counter(void)
                        now = time_interpolator_get_cycles(src);
                        if (lcycle && time_after(lcycle, now))
                                return lcycle;
+
+                       /* When holding the xtime write lock, there's no need
+                        * to add the overhead of the cmpxchg.  Readers are
+                        * force to retry until the write lock is released.
+                        */
+                       if (writelock) {
+                               time_interpolator->last_cycle = now;
+                               return now;
+                       }
                        /* Keep track of the last timer value returned. The use of cmpxchg here
                         * will cause contention in an SMP environment.
                         */
@@ -1455,7 +1465,7 @@ static inline u64 time_interpolator_get_counter(void)
 void time_interpolator_reset(void)
 {
        time_interpolator->offset = 0;
-       time_interpolator->last_counter = time_interpolator_get_counter();
+       time_interpolator->last_counter = time_interpolator_get_counter(1);
 }
 
 #define GET_TI_NSECS(count,i) (((((count) - i->last_counter) & (i)->mask) * (i)->nsec_per_cyc) >> (i)->shift)
@@ -1467,7 +1477,7 @@ unsigned long time_interpolator_get_offset(void)
                return 0;
 
        return time_interpolator->offset +
-               GET_TI_NSECS(time_interpolator_get_counter(), time_interpolator);
+               GET_TI_NSECS(time_interpolator_get_counter(0), time_interpolator);
 }
 
 #define INTERPOLATOR_ADJUST 65536
@@ -1490,7 +1500,7 @@ static void time_interpolator_update(long delta_nsec)
         * and the tuning logic insures that.
          */
 
-       counter = time_interpolator_get_counter();
+       counter = time_interpolator_get_counter(1);
        offset = time_interpolator->offset + GET_TI_NSECS(counter, time_interpolator);
 
        if (delta_nsec < 0 || (unsigned long) delta_nsec < offset)
index c7e36d4a70cabdb9711640575e68ac86d68a7da1..91bacb13a7e2fec56f5067f12e0b97c1043c30b7 100644 (file)
@@ -308,10 +308,9 @@ struct workqueue_struct *__create_workqueue(const char *name,
        struct workqueue_struct *wq;
        struct task_struct *p;
 
-       wq = kmalloc(sizeof(*wq), GFP_KERNEL);
+       wq = kzalloc(sizeof(*wq), GFP_KERNEL);
        if (!wq)
                return NULL;
-       memset(wq, 0, sizeof(*wq));
 
        wq->name = name;
        /* We don't need the distraction of CPUs appearing and vanishing. */
@@ -499,7 +498,7 @@ static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
        case CPU_UP_PREPARE:
                /* Create a new workqueue thread for it. */
                list_for_each_entry(wq, &workqueues, list) {
-                       if (create_workqueue_thread(wq, hotcpu) < 0) {
+                       if (!create_workqueue_thread(wq, hotcpu)) {
                                printk("workqueue for %i failed\n", hotcpu);
                                return NOTIFY_BAD;
                        }
index eeb429a52152bf51e34c5f67f96d8404d66ddf2e..e43197efeb9c559a459cf199a9908a876eb3a976 100644 (file)
@@ -72,6 +72,9 @@ config TEXTSEARCH
 config TEXTSEARCH_KMP
        tristate
 
+config TEXTSEARCH_BM
+       tristate
+
 config TEXTSEARCH_FSM
        tristate
 
index 299f7f3b5b0871fdd332a647f83ea54d2ddf059b..3754c9a8f5c8e1e3fccebf2d0f282fd5eda6bcb4 100644 (file)
@@ -46,6 +46,25 @@ config LOG_BUF_SHIFT
                     13 =>  8 KB
                     12 =>  4 KB
 
+config DETECT_SOFTLOCKUP
+       bool "Detect Soft Lockups"
+       depends on DEBUG_KERNEL
+       default y
+       help
+         Say Y here to enable the kernel to detect "soft lockups",
+         which are bugs that cause the kernel to loop in kernel
+         mode for more than 10 seconds, without giving other tasks a
+         chance to run.
+
+         When a soft-lockup is detected, the kernel will print the
+         current stack trace (which you should report), but the
+         system will stay locked up. This feature has negligible
+         overhead.
+
+         (Note that "hard lockups" are separate type of bugs that
+          can be detected via the NMI-watchdog, on platforms that
+          support it.)
+
 config SCHEDSTATS
        bool "Collect scheduler statistics"
        depends on DEBUG_KERNEL && PROC_FS
index f28d9031303c2cfebb2eb260ab48d6008951fd9e..3e2bd0df23bb4c76d745bdee5b71b97a57dd4c8f 100644 (file)
@@ -18,6 +18,7 @@ endif
 
 lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
 lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
+lib-$(CONFIG_SEMAPHORE_SLEEPERS) += semaphore-sleepers.o
 lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
 obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
 obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
@@ -38,6 +39,7 @@ obj-$(CONFIG_REED_SOLOMON) += reed_solomon/
 
 obj-$(CONFIG_TEXTSEARCH) += textsearch.o
 obj-$(CONFIG_TEXTSEARCH_KMP) += ts_kmp.o
+obj-$(CONFIG_TEXTSEARCH_BM) += ts_bm.o
 obj-$(CONFIG_TEXTSEARCH_FSM) += ts_fsm.o
 
 hostprogs-y    := gen_crc32table
index 738ab810160a85b1c437da82e0389d354c76cf20..a70c836c5c4c2617f6929407034a8706b57c4886 100644 (file)
@@ -79,11 +79,11 @@ static void klist_node_init(struct klist * k, struct klist_node * n)
 
 /**
  *     klist_add_head - Initialize a klist_node and add it to front.
- *     @k:     klist it's going on.
  *     @n:     node we're adding.
+ *     @k:     klist it's going on.
  */
 
-void klist_add_head(struct klist * k, struct klist_node * n)
+void klist_add_head(struct klist_node * n, struct klist * k)
 {
        klist_node_init(k, n);
        add_head(k, n);
@@ -94,11 +94,11 @@ EXPORT_SYMBOL_GPL(klist_add_head);
 
 /**
  *     klist_add_tail - Initialize a klist_node and add it to back.
- *     @k:     klist it's going on.
  *     @n:     node we're adding.
+ *     @k:     klist it's going on.
  */
 
-void klist_add_tail(struct klist * k, struct klist_node * n)
+void klist_add_tail(struct klist_node * n, struct klist * k)
 {
        klist_node_init(k, n);
        add_tail(k, n);
index 8e49d21057e48f1294786a2acbc7f9d4c930c744..04ca4429ddfaf4a077f48c45bb2b718d647b4e42 100644 (file)
@@ -93,6 +93,7 @@ static int send_uevent(const char *signal, const char *obj,
                }
        }
 
+       NETLINK_CB(skb).dst_group = 1;
        return netlink_broadcast(uevent_sock, skb, 0, 1, gfp_mask);
 }
 
@@ -153,7 +154,8 @@ EXPORT_SYMBOL_GPL(kobject_uevent_atomic);
 
 static int __init kobject_uevent_init(void)
 {
-       uevent_sock = netlink_kernel_create(NETLINK_KOBJECT_UEVENT, NULL);
+       uevent_sock = netlink_kernel_create(NETLINK_KOBJECT_UEVENT, 1, NULL,
+                                           THIS_MODULE);
 
        if (!uevent_sock) {
                printk(KERN_ERR
index 10bed1c8c3c3012b861a055eaaf095af7906e8e5..b972dd29289d6669fd353dcd2b3118cd93ab87cb 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2001 Momchil Velikov
  * Portions Copyright (C) 2001 Christoph Hellwig
+ * Copyright (C) 2005 SGI, Christoph Lameter <clameter@sgi.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -51,7 +52,7 @@ struct radix_tree_node {
 };
 
 struct radix_tree_path {
-       struct radix_tree_node *node, **slot;
+       struct radix_tree_node *node;
        int offset;
 };
 
@@ -227,7 +228,7 @@ out:
 int radix_tree_insert(struct radix_tree_root *root,
                        unsigned long index, void *item)
 {
-       struct radix_tree_node *node = NULL, *tmp, **slot;
+       struct radix_tree_node *node = NULL, *slot;
        unsigned int height, shift;
        int offset;
        int error;
@@ -240,38 +241,42 @@ int radix_tree_insert(struct radix_tree_root *root,
                        return error;
        }
 
-       slot = &root->rnode;
+       slot = root->rnode;
        height = root->height;
        shift = (height-1) * RADIX_TREE_MAP_SHIFT;
 
        offset = 0;                     /* uninitialised var warning */
        while (height > 0) {
-               if (*slot == NULL) {
+               if (slot == NULL) {
                        /* Have to add a child node.  */
-                       if (!(tmp = radix_tree_node_alloc(root)))
+                       if (!(slot = radix_tree_node_alloc(root)))
                                return -ENOMEM;
-                       *slot = tmp;
-                       if (node)
+                       if (node) {
+                               node->slots[offset] = slot;
                                node->count++;
+                       } else
+                               root->rnode = slot;
                }
 
                /* Go a level down */
                offset = (index >> shift) & RADIX_TREE_MAP_MASK;
-               node = *slot;
-               slot = (struct radix_tree_node **)(node->slots + offset);
+               node = slot;
+               slot = node->slots[offset];
                shift -= RADIX_TREE_MAP_SHIFT;
                height--;
        }
 
-       if (*slot != NULL)
+       if (slot != NULL)
                return -EEXIST;
+
        if (node) {
                node->count++;
+               node->slots[offset] = item;
                BUG_ON(tag_get(node, 0, offset));
                BUG_ON(tag_get(node, 1, offset));
-       }
+       } else
+               root->rnode = item;
 
-       *slot = item;
        return 0;
 }
 EXPORT_SYMBOL(radix_tree_insert);
@@ -286,27 +291,25 @@ EXPORT_SYMBOL(radix_tree_insert);
 void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index)
 {
        unsigned int height, shift;
-       struct radix_tree_node **slot;
+       struct radix_tree_node *slot;
 
        height = root->height;
        if (index > radix_tree_maxindex(height))
                return NULL;
 
        shift = (height-1) * RADIX_TREE_MAP_SHIFT;
-       slot = &root->rnode;
+       slot = root->rnode;
 
        while (height > 0) {
-               if (*slot == NULL)
+               if (slot == NULL)
                        return NULL;
 
-               slot = (struct radix_tree_node **)
-                       ((*slot)->slots +
-                               ((index >> shift) & RADIX_TREE_MAP_MASK));
+               slot = slot->slots[(index >> shift) & RADIX_TREE_MAP_MASK];
                shift -= RADIX_TREE_MAP_SHIFT;
                height--;
        }
 
-       return *slot;
+       return slot;
 }
 EXPORT_SYMBOL(radix_tree_lookup);
 
@@ -326,27 +329,27 @@ void *radix_tree_tag_set(struct radix_tree_root *root,
                        unsigned long index, int tag)
 {
        unsigned int height, shift;
-       struct radix_tree_node **slot;
+       struct radix_tree_node *slot;
 
        height = root->height;
        if (index > radix_tree_maxindex(height))
                return NULL;
 
        shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
-       slot = &root->rnode;
+       slot = root->rnode;
 
        while (height > 0) {
                int offset;
 
                offset = (index >> shift) & RADIX_TREE_MAP_MASK;
-               tag_set(*slot, tag, offset);
-               slot = (struct radix_tree_node **)((*slot)->slots + offset);
-               BUG_ON(*slot == NULL);
+               tag_set(slot, tag, offset);
+               slot = slot->slots[offset];
+               BUG_ON(slot == NULL);
                shift -= RADIX_TREE_MAP_SHIFT;
                height--;
        }
 
-       return *slot;
+       return slot;
 }
 EXPORT_SYMBOL(radix_tree_tag_set);
 
@@ -367,6 +370,7 @@ void *radix_tree_tag_clear(struct radix_tree_root *root,
                        unsigned long index, int tag)
 {
        struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
+       struct radix_tree_node *slot;
        unsigned int height, shift;
        void *ret = NULL;
 
@@ -376,38 +380,37 @@ void *radix_tree_tag_clear(struct radix_tree_root *root,
 
        shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
        pathp->node = NULL;
-       pathp->slot = &root->rnode;
+       slot = root->rnode;
 
        while (height > 0) {
                int offset;
 
-               if (*pathp->slot == NULL)
+               if (slot == NULL)
                        goto out;
 
                offset = (index >> shift) & RADIX_TREE_MAP_MASK;
                pathp[1].offset = offset;
-               pathp[1].node = *pathp[0].slot;
-               pathp[1].slot = (struct radix_tree_node **)
-                               (pathp[1].node->slots + offset);
+               pathp[1].node = slot;
+               slot = slot->slots[offset];
                pathp++;
                shift -= RADIX_TREE_MAP_SHIFT;
                height--;
        }
 
-       ret = *pathp[0].slot;
+       ret = slot;
        if (ret == NULL)
                goto out;
 
        do {
                int idx;
 
-               tag_clear(pathp[0].node, tag, pathp[0].offset);
+               tag_clear(pathp->node, tag, pathp->offset);
                for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
-                       if (pathp[0].node->tags[tag][idx])
+                       if (pathp->node->tags[tag][idx])
                                goto out;
                }
                pathp--;
-       } while (pathp[0].node);
+       } while (pathp->node);
 out:
        return ret;
 }
@@ -415,21 +418,22 @@ EXPORT_SYMBOL(radix_tree_tag_clear);
 
 #ifndef __KERNEL__     /* Only the test harness uses this at present */
 /**
- *     radix_tree_tag_get - get a tag on a radix tree node
- *     @root:          radix tree root
- *     @index:         index key
- *     @tag:           tag index
+ * radix_tree_tag_get - get a tag on a radix tree node
+ * @root:              radix tree root
+ * @index:             index key
+ * @tag:               tag index
  *
- *     Return the search tag corresponging to @index in the radix tree.
+ * Return values:
  *
- *     Returns zero if the tag is unset, or if there is no corresponding item
- *     in the tree.
+ *  0: tag not present
+ *  1: tag present, set
+ * -1: tag present, unset
  */
 int radix_tree_tag_get(struct radix_tree_root *root,
                        unsigned long index, int tag)
 {
        unsigned int height, shift;
-       struct radix_tree_node **slot;
+       struct radix_tree_node *slot;
        int saw_unset_tag = 0;
 
        height = root->height;
@@ -437,12 +441,12 @@ int radix_tree_tag_get(struct radix_tree_root *root,
                return 0;
 
        shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
-       slot = &root->rnode;
+       slot = root->rnode;
 
        for ( ; ; ) {
                int offset;
 
-               if (*slot == NULL)
+               if (slot == NULL)
                        return 0;
 
                offset = (index >> shift) & RADIX_TREE_MAP_MASK;
@@ -451,15 +455,15 @@ int radix_tree_tag_get(struct radix_tree_root *root,
                 * This is just a debug check.  Later, we can bale as soon as
                 * we see an unset tag.
                 */
-               if (!tag_get(*slot, tag, offset))
+               if (!tag_get(slot, tag, offset))
                        saw_unset_tag = 1;
                if (height == 1) {
-                       int ret = tag_get(*slot, tag, offset);
+                       int ret = tag_get(slot, tag, offset);
 
                        BUG_ON(ret && saw_unset_tag);
-                       return ret;
+                       return ret ? 1 : -1;
                }
-               slot = (struct radix_tree_node **)((*slot)->slots + offset);
+               slot = slot->slots[offset];
                shift -= RADIX_TREE_MAP_SHIFT;
                height--;
        }
@@ -472,17 +476,21 @@ __lookup(struct radix_tree_root *root, void **results, unsigned long index,
        unsigned int max_items, unsigned long *next_index)
 {
        unsigned int nr_found = 0;
-       unsigned int shift;
-       unsigned int height = root->height;
+       unsigned int shift, height;
        struct radix_tree_node *slot;
+       unsigned long i;
+
+       height = root->height;
+       if (height == 0)
+               goto out;
 
        shift = (height-1) * RADIX_TREE_MAP_SHIFT;
        slot = root->rnode;
 
-       while (height > 0) {
-               unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK;
+       for ( ; height > 1; height--) {
 
-               for ( ; i < RADIX_TREE_MAP_SIZE; i++) {
+               for (i = (index >> shift) & RADIX_TREE_MAP_MASK ;
+                               i < RADIX_TREE_MAP_SIZE; i++) {
                        if (slot->slots[i] != NULL)
                                break;
                        index &= ~((1UL << shift) - 1);
@@ -492,22 +500,20 @@ __lookup(struct radix_tree_root *root, void **results, unsigned long index,
                }
                if (i == RADIX_TREE_MAP_SIZE)
                        goto out;
-               height--;
-               if (height == 0) {      /* Bottom level: grab some items */
-                       unsigned long j = index & RADIX_TREE_MAP_MASK;
 
-                       for ( ; j < RADIX_TREE_MAP_SIZE; j++) {
-                               index++;
-                               if (slot->slots[j]) {
-                                       results[nr_found++] = slot->slots[j];
-                                       if (nr_found == max_items)
-                                               goto out;
-                               }
-                       }
-               }
                shift -= RADIX_TREE_MAP_SHIFT;
                slot = slot->slots[i];
        }
+
+       /* Bottom level: grab some items */
+       for (i = index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) {
+               index++;
+               if (slot->slots[i]) {
+                       results[nr_found++] = slot->slots[i];
+                       if (nr_found == max_items)
+                               goto out;
+               }
+       }
 out:
        *next_index = index;
        return nr_found;
@@ -655,6 +661,7 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
 {
        struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
        struct radix_tree_path *orig_pathp;
+       struct radix_tree_node *slot;
        unsigned int height, shift;
        void *ret = NULL;
        char tags[RADIX_TREE_TAGS];
@@ -666,25 +673,23 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
 
        shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
        pathp->node = NULL;
-       pathp->slot = &root->rnode;
+       slot = root->rnode;
 
-       while (height > 0) {
+       for ( ; height > 0; height--) {
                int offset;
 
-               if (*pathp->slot == NULL)
+               if (slot == NULL)
                        goto out;
 
                offset = (index >> shift) & RADIX_TREE_MAP_MASK;
                pathp[1].offset = offset;
-               pathp[1].node = *pathp[0].slot;
-               pathp[1].slot = (struct radix_tree_node **)
-                               (pathp[1].node->slots + offset);
+               pathp[1].node = slot;
+               slot = slot->slots[offset];
                pathp++;
                shift -= RADIX_TREE_MAP_SHIFT;
-               height--;
        }
 
-       ret = *pathp[0].slot;
+       ret = slot;
        if (ret == NULL)
                goto out;
 
@@ -704,10 +709,10 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
                        if (tags[tag])
                                continue;
 
-                       tag_clear(pathp[0].node, tag, pathp[0].offset);
+                       tag_clear(pathp->node, tag, pathp->offset);
 
                        for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
-                               if (pathp[0].node->tags[tag][idx]) {
+                               if (pathp->node->tags[tag][idx]) {
                                        tags[tag] = 1;
                                        nr_cleared_tags--;
                                        break;
@@ -715,18 +720,19 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
                        }
                }
                pathp--;
-       } while (pathp[0].node && nr_cleared_tags);
+       } while (pathp->node && nr_cleared_tags);
 
-       pathp = orig_pathp;
-       *pathp[0].slot = NULL;
-       while (pathp[0].node && --pathp[0].node->count == 0) {
-               pathp--;
-               BUG_ON(*pathp[0].slot == NULL);
-               *pathp[0].slot = NULL;
-               radix_tree_node_free(pathp[1].node);
+       /* Now free the nodes we do not need anymore */
+       for (pathp = orig_pathp; pathp->node; pathp--) {
+               pathp->node->slots[pathp->offset] = NULL;
+               if (--pathp->node->count)
+                       goto out;
+
+               /* Node with zero slots in use so free it */
+               radix_tree_node_free(pathp->node);
        }
-       if (root->rnode == NULL)
-               root->height = 0;
+       root->rnode = NULL;
+       root->height = 0;
 out:
        return ret;
 }
similarity index 94%
rename from arch/x86_64/kernel/semaphore.c
rename to lib/semaphore-sleepers.c
index 48f7c18172b9990d17c6c00fac7940835a8afe0f..4d5f18889fa54c7535dcf8fced756d4344a88afc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * x86_64 semaphore implementation.
+ * i386 and x86-64 semaphore implementation.
  *
  * (C) Copyright 1999 Linus Torvalds
  *
@@ -14,9 +14,8 @@
  */
 #include <linux/config.h>
 #include <linux/sched.h>
+#include <linux/err.h>
 #include <linux/init.h>
-#include <asm/errno.h>
-
 #include <asm/semaphore.h>
 
 /*
  *    we cannot lose wakeup events.
  */
 
-void __up(struct semaphore *sem)
+fastcall void __up(struct semaphore *sem)
 {
        wake_up(&sem->wait);
 }
 
-void __sched __down(struct semaphore * sem)
+fastcall void __sched __down(struct semaphore * sem)
 {
        struct task_struct *tsk = current;
        DECLARE_WAITQUEUE(wait, tsk);
@@ -92,7 +91,7 @@ void __sched __down(struct semaphore * sem)
        tsk->state = TASK_RUNNING;
 }
 
-int __sched __down_interruptible(struct semaphore * sem)
+fastcall int __sched __down_interruptible(struct semaphore * sem)
 {
        int retval = 0;
        struct task_struct *tsk = current;
@@ -155,7 +154,7 @@ int __sched __down_interruptible(struct semaphore * sem)
  * single "cmpxchg" without failure cases,
  * but then it wouldn't work on a 386.
  */
-int __down_trylock(struct semaphore * sem)
+fastcall int __down_trylock(struct semaphore * sem)
 {
        int sleepers;
        unsigned long flags;
@@ -176,5 +175,3 @@ int __down_trylock(struct semaphore * sem)
        spin_unlock_irqrestore(&sem->wait.lock, flags);
        return 1;
 }
-
-
diff --git a/lib/ts_bm.c b/lib/ts_bm.c
new file mode 100644 (file)
index 0000000..2cc7911
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * lib/ts_bm.c         Boyer-Moore text search implementation
+ *
+ *             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.
+ *
+ * Authors:    Pablo Neira Ayuso <pablo@eurodev.net>
+ *
+ * ==========================================================================
+ * 
+ *   Implements Boyer-Moore string matching algorithm:
+ *
+ *   [1] A Fast String Searching Algorithm, R.S. Boyer and Moore.
+ *       Communications of the Association for Computing Machinery, 
+ *       20(10), 1977, pp. 762-772.
+ *       http://www.cs.utexas.edu/users/moore/publications/fstrpos.pdf
+ *
+ *   [2] Handbook of Exact String Matching Algorithms, Thierry Lecroq, 2004
+ *       http://www-igm.univ-mlv.fr/~lecroq/string/string.pdf
+ *
+ *   Note: Since Boyer-Moore (BM) performs searches for matchings from right 
+ *   to left, it's still possible that a matching could be spread over 
+ *   multiple blocks, in that case this algorithm won't find any coincidence.
+ *   
+ *   If you're willing to ensure that such thing won't ever happen, use the
+ *   Knuth-Pratt-Morris (KMP) implementation instead. In conclusion, choose 
+ *   the proper string search algorithm depending on your setting. 
+ *
+ *   Say you're using the textsearch infrastructure for filtering, NIDS or 
+ *   any similar security focused purpose, then go KMP. Otherwise, if you 
+ *   really care about performance, say you're classifying packets to apply
+ *   Quality of Service (QoS) policies, and you don't mind about possible
+ *   matchings spread over multiple fragments, then go BM.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/textsearch.h>
+
+/* Alphabet size, use ASCII */
+#define ASIZE 256
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(args, format...)
+#endif
+
+struct ts_bm
+{
+       u8 *            pattern;
+       unsigned int    patlen;
+       unsigned int    bad_shift[ASIZE];
+       unsigned int    good_shift[0];
+};
+
+static unsigned int bm_find(struct ts_config *conf, struct ts_state *state)
+{
+       struct ts_bm *bm = ts_config_priv(conf);
+       unsigned int i, text_len, consumed = state->offset;
+       const u8 *text;
+       int shift = bm->patlen, bs;
+
+       for (;;) {
+               text_len = conf->get_next_block(consumed, &text, conf, state);
+
+               if (unlikely(text_len == 0))
+                       break;
+
+               while (shift < text_len) {
+                       DEBUGP("Searching in position %d (%c)\n", 
+                               shift, text[shift]);
+                       for (i = 0; i < bm->patlen; i++) 
+                            if (text[shift-i] != bm->pattern[bm->patlen-1-i])
+                                    goto next;
+
+                       /* London calling... */
+                       DEBUGP("found!\n");
+                       return consumed += (shift-(bm->patlen-1));
+
+next:                  bs = bm->bad_shift[text[shift-i]];
+
+                       /* Now jumping to... */
+                       shift = max_t(int, shift-i+bs, shift+bm->good_shift[i]);
+               }
+               consumed += text_len;
+       }
+
+       return UINT_MAX;
+}
+
+static void compute_prefix_tbl(struct ts_bm *bm, const u8 *pattern,
+                              unsigned int len)
+{
+       int i, j, ended, l[ASIZE];
+
+       for (i = 0; i < ASIZE; i++)
+               bm->bad_shift[i] = len;
+       for (i = 0; i < len - 1; i++)
+               bm->bad_shift[pattern[i]] = len - 1 - i;
+
+       /* Compute the good shift array, used to match reocurrences 
+        * of a subpattern */
+       for (i = 1; i < bm->patlen; i++) {
+               for (j = 0; j < bm->patlen && bm->pattern[bm->patlen - 1 - j]
+                               == bm->pattern[bm->patlen - 1 - i - j]; j++);
+               l[i] = j;
+       }  
+
+       bm->good_shift[0] = 1;
+       for (i = 1; i < bm->patlen; i++)
+               bm->good_shift[i] = bm->patlen;
+       for (i = bm->patlen - 1; i > 0; i--)
+               bm->good_shift[l[i]] = i;
+       ended = 0;
+       for (i = 0; i < bm->patlen; i++) {
+               if (l[i] == bm->patlen - 1 - i)
+                       ended = i;
+               if (ended)
+                       bm->good_shift[i] = ended;
+       }
+}
+
+static struct ts_config *bm_init(const void *pattern, unsigned int len,
+                                int gfp_mask)
+{
+       struct ts_config *conf;
+       struct ts_bm *bm;
+       unsigned int prefix_tbl_len = len * sizeof(unsigned int);
+       size_t priv_size = sizeof(*bm) + len + prefix_tbl_len;
+
+       conf = alloc_ts_config(priv_size, gfp_mask);
+       if (IS_ERR(conf))
+               return conf;
+
+       bm = ts_config_priv(conf);
+       bm->patlen = len;
+       bm->pattern = (u8 *) bm->good_shift + prefix_tbl_len;
+       compute_prefix_tbl(bm, pattern, len);
+       memcpy(bm->pattern, pattern, len);
+
+       return conf;
+}
+
+static void *bm_get_pattern(struct ts_config *conf)
+{
+       struct ts_bm *bm = ts_config_priv(conf);
+       return bm->pattern;
+}
+
+static unsigned int bm_get_pattern_len(struct ts_config *conf)
+{
+       struct ts_bm *bm = ts_config_priv(conf);
+       return bm->patlen;
+}
+
+static struct ts_ops bm_ops = {
+       .name             = "bm",
+       .find             = bm_find,
+       .init             = bm_init,
+       .get_pattern      = bm_get_pattern,
+       .get_pattern_len  = bm_get_pattern_len,
+       .owner            = THIS_MODULE,
+       .list             = LIST_HEAD_INIT(bm_ops.list)
+};
+
+static int __init init_bm(void)
+{
+       return textsearch_register(&bm_ops);
+}
+
+static void __exit exit_bm(void)
+{
+       textsearch_unregister(&bm_ops);
+}
+
+MODULE_LICENSE("GPL");
+
+module_init(init_bm);
+module_exit(exit_bm);
index cd379936cac663eb1c4f1a730460ceda4216c477..4e9937ac3529ae391762f5071e938f8ac5497077 100644 (file)
@@ -89,3 +89,25 @@ config NEED_MULTIPLE_NODES
 config HAVE_MEMORY_PRESENT
        def_bool y
        depends on ARCH_HAVE_MEMORY_PRESENT || SPARSEMEM
+
+#
+# SPARSEMEM_EXTREME (which is the default) does some bootmem
+# allocations when memory_present() is called.  If this can not
+# be done on your architecture, select this option.  However,
+# statically allocating the mem_section[] array can potentially
+# consume vast quantities of .bss, so be careful.
+#
+# This option will also potentially produce smaller runtime code
+# with gcc 3.4 and later.
+#
+config SPARSEMEM_STATIC
+       def_bool n
+
+#
+# Architectecture platforms which require a two level mem_section in SPARSEMEM
+# must select this option. This is usually for architecture platforms with
+# an extremely sparse physical address space.
+#
+config SPARSEMEM_EXTREME
+       def_bool y
+       depends on SPARSEMEM && !SPARSEMEM_STATIC
index c11418dd94e810f4c8d9c4aa7ed2fae6d8aba290..88611928e71fc928a89b5b319044d759ea5f612d 100644 (file)
@@ -54,9 +54,8 @@
  *
  *  ->i_mmap_lock              (vmtruncate)
  *    ->private_lock           (__free_pte->__set_page_dirty_buffers)
- *      ->swap_list_lock
- *        ->swap_device_lock   (exclusive_swap_page, others)
- *          ->mapping->tree_lock
+ *      ->swap_lock            (exclusive_swap_page, others)
+ *        ->mapping->tree_lock
  *
  *  ->i_sem
  *    ->i_mmap_lock            (truncate->unmap_mapping_range)
@@ -86,7 +85,7 @@
  *    ->page_table_lock                (anon_vma_prepare and various)
  *
  *  ->page_table_lock
- *    ->swap_device_lock       (try_to_unmap_one)
+ *    ->swap_lock              (try_to_unmap_one)
  *    ->private_lock           (try_to_unmap_one)
  *    ->tree_lock              (try_to_unmap_one)
  *    ->zone.lru_lock          (follow_page->mark_page_accessed)
@@ -1505,8 +1504,12 @@ repeat:
                return -EINVAL;
 
        page = filemap_getpage(file, pgoff, nonblock);
+
+       /* XXX: This is wrong, a filesystem I/O error may have happened. Fix that as
+        * done in shmem_populate calling shmem_getpage */
        if (!page && !nonblock)
                return -ENOMEM;
+
        if (page) {
                err = install_page(mm, vma, addr, page, prot);
                if (err) {
@@ -1514,6 +1517,9 @@ repeat:
                        return err;
                }
        } else {
+               /* No page was found just because we can't read it in now (being
+                * here implies nonblock != 0), but the page may exist, so set
+                * the PTE to fault it in later. */
                err = install_file_pte(mm, vma, addr, pgoff, prot);
                if (err)
                        return err;
index 6bf720bc662c41983c1208e2aef409d4e0a276ac..901ac523a1c39fc17cc15d626ffb9cc8aa7f083d 100644 (file)
@@ -360,8 +360,6 @@ int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma)
                        ret = -ENOMEM;
                        goto out;
                }
-               if (! pte_none(*pte))
-                       hugetlb_clean_stale_pgtable(pte);
 
                idx = ((addr - vma->vm_start) >> HPAGE_SHIFT)
                        + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT));
index c8c01a12fea43719b034e6f394d8d72faa1aea16..4454936f87d1b6fb2fde25e1570a2748ea4a16b0 100644 (file)
@@ -37,7 +37,7 @@ static long madvise_behavior(struct vm_area_struct * vma,
 
        if (new_flags == vma->vm_flags) {
                *prev = vma;
-               goto success;
+               goto out;
        }
 
        pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
@@ -62,6 +62,7 @@ static long madvise_behavior(struct vm_area_struct * vma,
                        goto out;
        }
 
+success:
        /*
         * vm_flags is protected by the mmap_sem held in write mode.
         */
@@ -70,7 +71,6 @@ static long madvise_behavior(struct vm_area_struct * vma,
 out:
        if (error == -ENOMEM)
                error = -EAGAIN;
-success:
        return error;
 }
 
@@ -237,8 +237,9 @@ asmlinkage long sys_madvise(unsigned long start, size_t len_in, int behavior)
         * - different from the way of handling in mlock etc.
         */
        vma = find_vma_prev(current->mm, start, &prev);
-       if (!vma && prev)
-               vma = prev->vm_next;
+       if (vma && start > vma->vm_start)
+               prev = vma;
+
        for (;;) {
                /* Still start < end. */
                error = -ENOMEM;
index e046b7e4b53092bb879f8d183d24de36b3389d83..788a628103405e955a7d28f9935be690eb6d021a 100644 (file)
@@ -498,6 +498,17 @@ int copy_page_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
        unsigned long addr = vma->vm_start;
        unsigned long end = vma->vm_end;
 
+       /*
+        * Don't copy ptes where a page fault will fill them correctly.
+        * Fork becomes much lighter when there are big shared or private
+        * readonly mappings. The tradeoff is that copy_page_range is more
+        * efficient than faulting.
+        */
+       if (!(vma->vm_flags & (VM_HUGETLB|VM_NONLINEAR|VM_RESERVED))) {
+               if (!vma->anon_vma)
+                       return 0;
+       }
+
        if (is_vm_hugetlb_page(vma))
                return copy_hugetlb_page_range(dst_mm, src_mm, vma);
 
@@ -551,7 +562,8 @@ static void zap_pte_range(struct mmu_gather *tlb, pmd_t *pmd,
                                     page->index > details->last_index))
                                        continue;
                        }
-                       ptent = ptep_get_and_clear(tlb->mm, addr, pte);
+                       ptent = ptep_get_and_clear_full(tlb->mm, addr, pte,
+                                                       tlb->fullmm);
                        tlb_remove_tlb_entry(tlb, pte, addr);
                        if (unlikely(!page))
                                continue;
@@ -579,7 +591,7 @@ static void zap_pte_range(struct mmu_gather *tlb, pmd_t *pmd,
                        continue;
                if (!pte_file(ptent))
                        free_swap_and_cache(pte_to_swp_entry(ptent));
-               pte_clear(tlb->mm, addr, pte);
+               pte_clear_full(tlb->mm, addr, pte, tlb->fullmm);
        } while (pte++, addr += PAGE_SIZE, addr != end);
        pte_unmap(pte - 1);
 }
@@ -1944,7 +1956,7 @@ static int do_file_page(struct mm_struct * mm, struct vm_area_struct * vma,
         * Fall back to the linear mapping if the fs does not support
         * ->populate:
         */
-       if (!vma->vm_ops || !vma->vm_ops->populate || 
+       if (!vma->vm_ops->populate ||
                        (write_access && !(vma->vm_flags & VM_SHARED))) {
                pte_clear(mm, address, pte);
                return do_no_page(mm, vma, address, write_access, pte, pmd);
index b4eababc8198790961ead62cf421b2ac2c21aaf5..13492d66b7c809ff603f6c996f5ea1aafbe51a34 100644 (file)
@@ -664,10 +664,10 @@ asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len,
 #endif
 
 /* Return effective policy for a VMA */
-static struct mempolicy *
-get_vma_policy(struct vm_area_struct *vma, unsigned long addr)
+struct mempolicy *
+get_vma_policy(struct task_struct *task, struct vm_area_struct *vma, unsigned long addr)
 {
-       struct mempolicy *pol = current->mempolicy;
+       struct mempolicy *pol = task->mempolicy;
 
        if (vma) {
                if (vma->vm_ops && vma->vm_ops->get_policy)
@@ -786,7 +786,7 @@ static struct page *alloc_page_interleave(unsigned int __nocast gfp, unsigned or
 struct page *
 alloc_page_vma(unsigned int __nocast gfp, struct vm_area_struct *vma, unsigned long addr)
 {
-       struct mempolicy *pol = get_vma_policy(vma, addr);
+       struct mempolicy *pol = get_vma_policy(current, vma, addr);
 
        cpuset_update_current_mems_allowed();
 
@@ -908,7 +908,7 @@ void __mpol_free(struct mempolicy *p)
 /* Find first node suitable for an allocation */
 int mpol_first_node(struct vm_area_struct *vma, unsigned long addr)
 {
-       struct mempolicy *pol = get_vma_policy(vma, addr);
+       struct mempolicy *pol = get_vma_policy(current, vma, addr);
 
        switch (pol->policy) {
        case MPOL_DEFAULT:
@@ -928,7 +928,7 @@ int mpol_first_node(struct vm_area_struct *vma, unsigned long addr)
 /* Find secondary valid nodes for an allocation */
 int mpol_node_valid(int nid, struct vm_area_struct *vma, unsigned long addr)
 {
-       struct mempolicy *pol = get_vma_policy(vma, addr);
+       struct mempolicy *pol = get_vma_policy(current, vma, addr);
 
        switch (pol->policy) {
        case MPOL_PREFERRED:
index 404319477e71d61679166bc954ed246719affe89..12334aecf8ad3d74b62f93da8db6f529e981d51d 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -61,7 +61,7 @@ pgprot_t protection_map[16] = {
 
 int sysctl_overcommit_memory = OVERCOMMIT_GUESS;  /* heuristic overcommit */
 int sysctl_overcommit_ratio = 50;      /* default is 50% */
-int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT;
+int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT;
 atomic_t vm_committed_space = ATOMIC_INIT(0);
 
 /*
@@ -203,13 +203,6 @@ static void remove_vm_struct(struct vm_area_struct *vma)
        kmem_cache_free(vm_area_cachep, vma);
 }
 
-/*
- *  sys_brk() for the most part doesn't need the global kernel
- *  lock, except when an application is doing something nasty
- *  like trying to un-brk an area that has already been mapped
- *  to a regular file.  in this case, the unmapping will need
- *  to invoke file system routines that need the global lock.
- */
 asmlinkage unsigned long sys_brk(unsigned long brk)
 {
        unsigned long rlim, retval;
index fc45dc9a617b013f4db5aea5fe7898bf6cd677b6..a32fed454bd7c60e15da0c720b1631b55a3f8835 100644 (file)
@@ -141,6 +141,10 @@ move_one_page(struct vm_area_struct *vma, unsigned long old_addr,
                        if (dst) {
                                pte_t pte;
                                pte = ptep_clear_flush(vma, old_addr, src);
+                               /* ZERO_PAGE can be dependant on virtual addr */
+                               if (pfn_valid(pte_pfn(pte)) &&
+                                       pte_page(pte) == ZERO_PAGE(old_addr))
+                                       pte = pte_wrprotect(mk_pte(ZERO_PAGE(new_addr), new_vma->vm_page_prot));
                                set_pte_at(mm, new_addr, dst, pte);
                        } else
                                error = -ENOMEM;
index 1e56076672f5870e9766753270d77442e5743ac9..5ec8da12cfd986523bb1968ffa9f2ea0be064868 100644 (file)
@@ -6,8 +6,8 @@
  *     for goading me into coding this file...
  *
  *  The routines in this file are used to kill a process when
- *  we're seriously out of memory. This gets called from kswapd()
- *  in linux/mm/vmscan.c when we really run out of memory.
+ *  we're seriously out of memory. This gets called from __alloc_pages()
+ *  in mm/page_alloc.c when we really run out of memory.
  *
  *  Since we won't call these routines often (on a well-configured
  *  machine) this file will double as a 'coding guide' and a signpost
 #include <linux/swap.h>
 #include <linux/timex.h>
 #include <linux/jiffies.h>
+#include <linux/cpuset.h>
 
 /* #define DEBUG */
 
 /**
  * oom_badness - calculate a numeric value for how bad this task has been
  * @p: task struct of which task we should calculate
- * @p: current uptime in seconds
+ * @uptime: current uptime in seconds
  *
  * The formula used is relatively simple and documented inline in the
  * function. The main rationale is that we want to select a good task
@@ -57,9 +58,9 @@ unsigned long badness(struct task_struct *p, unsigned long uptime)
 
        /*
         * Processes which fork a lot of child processes are likely
-        * a good choice. We add the vmsize of the childs if they
+        * a good choice. We add the vmsize of the children if they
         * have an own mm. This prevents forking servers to flood the
-        * machine with an endless amount of childs
+        * machine with an endless amount of children
         */
        list_for_each(tsk, &p->children) {
                struct task_struct *chld;
@@ -143,28 +144,36 @@ static struct task_struct * select_bad_process(void)
        struct timespec uptime;
 
        do_posix_clock_monotonic_gettime(&uptime);
-       do_each_thread(g, p)
+       do_each_thread(g, p) {
+               unsigned long points;
+               int releasing;
+
                /* skip the init task with pid == 1 */
-               if (p->pid > 1 && p->oomkilladj != OOM_DISABLE) {
-                       unsigned long points;
-
-                       /*
-                        * This is in the process of releasing memory so wait it
-                        * to finish before killing some other task by mistake.
-                        */
-                       if ((unlikely(test_tsk_thread_flag(p, TIF_MEMDIE)) || (p->flags & PF_EXITING)) &&
-                           !(p->flags & PF_DEAD))
-                               return ERR_PTR(-1UL);
-                       if (p->flags & PF_SWAPOFF)
-                               return p;
-
-                       points = badness(p, uptime.tv_sec);
-                       if (points > maxpoints || !chosen) {
-                               chosen = p;
-                               maxpoints = points;
-                       }
+               if (p->pid == 1)
+                       continue;
+               if (p->oomkilladj == OOM_DISABLE)
+                       continue;
+               /* If p's nodes don't overlap ours, it won't help to kill p. */
+               if (!cpuset_excl_nodes_overlap(p))
+                       continue;
+
+               /*
+                * This is in the process of releasing memory so for wait it
+                * to finish before killing some other task by mistake.
+                */
+               releasing = test_tsk_thread_flag(p, TIF_MEMDIE) ||
+                                               p->flags & PF_EXITING;
+               if (releasing && !(p->flags & PF_DEAD))
+                       return ERR_PTR(-1UL);
+               if (p->flags & PF_SWAPOFF)
+                       return p;
+
+               points = badness(p, uptime.tv_sec);
+               if (points > maxpoints || !chosen) {
+                       chosen = p;
+                       maxpoints = points;
                }
-       while_each_thread(g, p);
+       while_each_thread(g, p);
        return chosen;
 }
 
@@ -189,7 +198,8 @@ static void __oom_kill_task(task_t *p)
                return;
        }
        task_unlock(p);
-       printk(KERN_ERR "Out of Memory: Killed process %d (%s).\n", p->pid, p->comm);
+       printk(KERN_ERR "Out of Memory: Killed process %d (%s).\n",
+                                                       p->pid, p->comm);
 
        /*
         * We give our sacrificial lamb high priority and access to
index 8d088371196a559b5baa5a8dc02e2d07253fd50c..3974fd81d27c0de38a12a299e6f6b6dd2645cbf7 100644 (file)
  * MCD - HACK: Find somewhere to initialize this EARLY, or make this
  * initializer cleaner
  */
-nodemask_t node_online_map = { { [0] = 1UL } };
+nodemask_t node_online_map __read_mostly = { { [0] = 1UL } };
 EXPORT_SYMBOL(node_online_map);
-nodemask_t node_possible_map = NODE_MASK_ALL;
+nodemask_t node_possible_map __read_mostly = NODE_MASK_ALL;
 EXPORT_SYMBOL(node_possible_map);
-struct pglist_data *pgdat_list;
-unsigned long totalram_pages;
-unsigned long totalhigh_pages;
+struct pglist_data *pgdat_list __read_mostly;
+unsigned long totalram_pages __read_mostly;
+unsigned long totalhigh_pages __read_mostly;
 long nr_swap_pages;
 
 /*
@@ -68,7 +68,7 @@ EXPORT_SYMBOL(nr_swap_pages);
  * Used by page_zone() to look up the address of the struct zone whose
  * id is encoded in the upper bits of page->flags
  */
-struct zone *zone_table[1 << ZONETABLE_SHIFT];
+struct zone *zone_table[1 << ZONETABLE_SHIFT] __read_mostly;
 EXPORT_SYMBOL(zone_table);
 
 static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" };
@@ -329,7 +329,7 @@ static inline void free_pages_check(const char *function, struct page *page)
                        1 << PG_writeback )))
                bad_page(function, page);
        if (PageDirty(page))
-               ClearPageDirty(page);
+               __ClearPageDirty(page);
 }
 
 /*
@@ -806,11 +806,14 @@ __alloc_pages(unsigned int __nocast gfp_mask, unsigned int order,
        classzone_idx = zone_idx(zones[0]);
 
 restart:
-       /* Go through the zonelist once, looking for a zone with enough free */
+       /*
+        * Go through the zonelist once, looking for a zone with enough free.
+        * See also cpuset_zone_allowed() comment in kernel/cpuset.c.
+        */
        for (i = 0; (z = zones[i]) != NULL; i++) {
                int do_reclaim = should_reclaim_zone(z, gfp_mask);
 
-               if (!cpuset_zone_allowed(z))
+               if (!cpuset_zone_allowed(z, __GFP_HARDWALL))
                        continue;
 
                /*
@@ -845,6 +848,7 @@ zone_reclaim_retry:
         *
         * This is the last chance, in general, before the goto nopage.
         * Ignore cpuset if GFP_ATOMIC (!wait) rather than fail alloc.
+        * See also cpuset_zone_allowed() comment in kernel/cpuset.c.
         */
        for (i = 0; (z = zones[i]) != NULL; i++) {
                if (!zone_watermark_ok(z, order, z->pages_min,
@@ -852,7 +856,7 @@ zone_reclaim_retry:
                                       gfp_mask & __GFP_HIGH))
                        continue;
 
-               if (wait && !cpuset_zone_allowed(z))
+               if (wait && !cpuset_zone_allowed(z, gfp_mask))
                        continue;
 
                page = buffered_rmqueue(z, order, gfp_mask);
@@ -867,7 +871,7 @@ zone_reclaim_retry:
                if (!(gfp_mask & __GFP_NOMEMALLOC)) {
                        /* go through the zonelist yet again, ignoring mins */
                        for (i = 0; (z = zones[i]) != NULL; i++) {
-                               if (!cpuset_zone_allowed(z))
+                               if (!cpuset_zone_allowed(z, gfp_mask))
                                        continue;
                                page = buffered_rmqueue(z, order, gfp_mask);
                                if (page)
@@ -903,7 +907,7 @@ rebalance:
                                               gfp_mask & __GFP_HIGH))
                                continue;
 
-                       if (!cpuset_zone_allowed(z))
+                       if (!cpuset_zone_allowed(z, gfp_mask))
                                continue;
 
                        page = buffered_rmqueue(z, order, gfp_mask);
@@ -922,7 +926,7 @@ rebalance:
                                               classzone_idx, 0, 0))
                                continue;
 
-                       if (!cpuset_zone_allowed(z))
+                       if (!cpuset_zone_allowed(z, __GFP_HARDWALL))
                                continue;
 
                        page = buffered_rmqueue(z, order, gfp_mask);
@@ -1130,19 +1134,20 @@ EXPORT_SYMBOL(nr_pagecache);
 DEFINE_PER_CPU(long, nr_pagecache_local) = 0;
 #endif
 
-void __get_page_state(struct page_state *ret, int nr)
+void __get_page_state(struct page_state *ret, int nr, cpumask_t *cpumask)
 {
        int cpu = 0;
 
        memset(ret, 0, sizeof(*ret));
+       cpus_and(*cpumask, *cpumask, cpu_online_map);
 
-       cpu = first_cpu(cpu_online_map);
+       cpu = first_cpu(*cpumask);
        while (cpu < NR_CPUS) {
                unsigned long *in, *out, off;
 
                in = (unsigned long *)&per_cpu(page_states, cpu);
 
-               cpu = next_cpu(cpu, cpu_online_map);
+               cpu = next_cpu(cpu, *cpumask);
 
                if (cpu < NR_CPUS)
                        prefetch(&per_cpu(page_states, cpu));
@@ -1153,19 +1158,33 @@ void __get_page_state(struct page_state *ret, int nr)
        }
 }
 
+void get_page_state_node(struct page_state *ret, int node)
+{
+       int nr;
+       cpumask_t mask = node_to_cpumask(node);
+
+       nr = offsetof(struct page_state, GET_PAGE_STATE_LAST);
+       nr /= sizeof(unsigned long);
+
+       __get_page_state(ret, nr+1, &mask);
+}
+
 void get_page_state(struct page_state *ret)
 {
        int nr;
+       cpumask_t mask = CPU_MASK_ALL;
 
        nr = offsetof(struct page_state, GET_PAGE_STATE_LAST);
        nr /= sizeof(unsigned long);
 
-       __get_page_state(ret, nr + 1);
+       __get_page_state(ret, nr + 1, &mask);
 }
 
 void get_full_page_state(struct page_state *ret)
 {
-       __get_page_state(ret, sizeof(*ret) / sizeof(unsigned long));
+       cpumask_t mask = CPU_MASK_ALL;
+
+       __get_page_state(ret, sizeof(*ret) / sizeof(unsigned long), &mask);
 }
 
 unsigned long __read_page_state(unsigned long offset)
@@ -1909,7 +1928,7 @@ static void __init free_area_init_core(struct pglist_data *pgdat,
                zone->nr_scan_inactive = 0;
                zone->nr_active = 0;
                zone->nr_inactive = 0;
-               atomic_set(&zone->reclaim_in_progress, -1);
+               atomic_set(&zone->reclaim_in_progress, 0);
                if (!size)
                        continue;
 
index b840e7c6ea740433d1851c379705efe191259e1d..d0b50034e245a0095c7d359388b59676af0bdb59 100644 (file)
@@ -540,6 +540,7 @@ void handle_ra_miss(struct address_space *mapping,
 {
        ra->flags |= RA_FLAG_MISS;
        ra->flags &= ~RA_FLAG_INCACHE;
+       ra->cache_hit = 0;
 }
 
 /*
index 08ac5c7fa91fa02b42c03515749fb43ff057554e..450f5241b5a525282ae7eb150fe322423b01e570 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -34,9 +34,8 @@
  *       anon_vma->lock
  *         mm->page_table_lock
  *           zone->lru_lock (in mark_page_accessed)
- *           swap_list_lock (in swap_free etc's swap_info_get)
+ *           swap_lock (in swap_duplicate, swap_info_get)
  *             mmlist_lock (in mmput, drain_mmlist and others)
- *             swap_device_lock (in swap_duplicate, swap_info_get)
  *             mapping->private_lock (in __set_page_dirty_buffers)
  *             inode_lock (in set_page_dirty's __mark_inode_dirty)
  *               sb_lock (within inode_lock in fs/fs-writeback.c)
@@ -290,8 +289,6 @@ static int page_referenced_one(struct page *page,
        pte_t *pte;
        int referenced = 0;
 
-       if (!get_mm_counter(mm, rss))
-               goto out;
        address = vma_address(page, vma);
        if (address == -EFAULT)
                goto out;
@@ -442,22 +439,19 @@ int page_referenced(struct page *page, int is_locked, int ignore_token)
 void page_add_anon_rmap(struct page *page,
        struct vm_area_struct *vma, unsigned long address)
 {
-       struct anon_vma *anon_vma = vma->anon_vma;
-       pgoff_t index;
-
        BUG_ON(PageReserved(page));
-       BUG_ON(!anon_vma);
 
        inc_mm_counter(vma->vm_mm, anon_rss);
 
-       anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
-       index = (address - vma->vm_start) >> PAGE_SHIFT;
-       index += vma->vm_pgoff;
-       index >>= PAGE_CACHE_SHIFT - PAGE_SHIFT;
-
        if (atomic_inc_and_test(&page->_mapcount)) {
-               page->index = index;
+               struct anon_vma *anon_vma = vma->anon_vma;
+
+               BUG_ON(!anon_vma);
+               anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
                page->mapping = (struct address_space *) anon_vma;
+
+               page->index = linear_page_index(vma, address);
+
                inc_page_state(nr_mapped);
        }
        /* else checking page index and mapping is racy */
@@ -518,8 +512,6 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma)
        pte_t pteval;
        int ret = SWAP_AGAIN;
 
-       if (!get_mm_counter(mm, rss))
-               goto out;
        address = vma_address(page, vma);
        if (address == -EFAULT)
                goto out;
@@ -532,6 +524,8 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma)
         * If the page is mlock()d, we cannot swap it out.
         * If it's recently referenced (perhaps page_referenced
         * skipped over this mm) then we should reactivate it.
+        *
+        * Pages belonging to VM_RESERVED regions should not happen here.
         */
        if ((vma->vm_flags & (VM_LOCKED|VM_RESERVED)) ||
                        ptep_clear_flush_young(vma, address, pte)) {
@@ -767,8 +761,7 @@ static int try_to_unmap_file(struct page *page)
                        if (vma->vm_flags & (VM_LOCKED|VM_RESERVED))
                                continue;
                        cursor = (unsigned long) vma->vm_private_data;
-                       while (get_mm_counter(vma->vm_mm, rss) &&
-                               cursor < max_nl_cursor &&
+                       while ( cursor < max_nl_cursor &&
                                cursor < vma->vm_end - vma->vm_start) {
                                try_to_unmap_cluster(cursor, &mapcount, vma);
                                cursor += CLUSTER_SIZE;
index 5a81b1ee4f7a43fc972d7ec762f2d51d7ac8aa42..db2c9e8d99095ace5bae8324f2387b9ebdbaf7c6 100644 (file)
@@ -45,7 +45,6 @@
 #include <linux/swapops.h>
 #include <linux/mempolicy.h>
 #include <linux/namei.h>
-#include <linux/xattr.h>
 #include <asm/uaccess.h>
 #include <asm/div64.h>
 #include <asm/pgtable.h>
@@ -179,10 +178,9 @@ static 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;
-static struct inode_operations shmem_special_inode_operations;
 static struct vm_operations_struct shmem_vm_ops;
 
-static struct backing_dev_info shmem_backing_dev_info = {
+static struct backing_dev_info shmem_backing_dev_info  __read_mostly = {
        .ra_pages       = 0,    /* No readahead */
        .capabilities   = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
        .unplug_io_fn   = default_unplug_io_fn,
@@ -1195,6 +1193,7 @@ static int shmem_populate(struct vm_area_struct *vma,
                err = shmem_getpage(inode, pgoff, &page, sgp, NULL);
                if (err)
                        return err;
+               /* Page may still be null, but only if nonblock was set. */
                if (page) {
                        mark_page_accessed(page);
                        err = install_page(mm, vma, addr, page, prot);
@@ -1202,7 +1201,10 @@ static int shmem_populate(struct vm_area_struct *vma,
                                page_cache_release(page);
                                return err;
                        }
-               } else if (nonblock) {
+               } else {
+                       /* No page was found just because we can't read it in
+                        * now (being here implies nonblock != 0), but the page
+                        * may exist, so set the PTE to fault it in later. */
                        err = install_file_pte(mm, vma, addr, pgoff, prot);
                        if (err)
                                return err;
@@ -1296,7 +1298,6 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
 
                switch (mode & S_IFMT) {
                default:
-                       inode->i_op = &shmem_special_inode_operations;
                        init_special_inode(inode, mode, dev);
                        break;
                case S_IFREG:
@@ -1800,12 +1801,6 @@ static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *co
 static struct inode_operations shmem_symlink_inline_operations = {
        .readlink       = generic_readlink,
        .follow_link    = shmem_follow_link_inline,
-#ifdef CONFIG_TMPFS_XATTR
-       .setxattr       = generic_setxattr,
-       .getxattr       = generic_getxattr,
-       .listxattr      = generic_listxattr,
-       .removexattr    = generic_removexattr,
-#endif
 };
 
 static struct inode_operations shmem_symlink_inode_operations = {
@@ -1813,12 +1808,6 @@ static struct inode_operations shmem_symlink_inode_operations = {
        .readlink       = generic_readlink,
        .follow_link    = shmem_follow_link,
        .put_link       = shmem_put_link,
-#ifdef CONFIG_TMPFS_XATTR
-       .setxattr       = generic_setxattr,
-       .getxattr       = generic_getxattr,
-       .listxattr      = generic_listxattr,
-       .removexattr    = generic_removexattr,
-#endif
 };
 
 static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid, unsigned long *blocks, unsigned long *inodes)
@@ -1938,12 +1927,6 @@ static void shmem_put_super(struct super_block *sb)
        sb->s_fs_info = NULL;
 }
 
-#ifdef CONFIG_TMPFS_XATTR
-static struct xattr_handler *shmem_xattr_handlers[];
-#else
-#define shmem_xattr_handlers NULL
-#endif
-
 static int shmem_fill_super(struct super_block *sb,
                            void *data, int silent)
 {
@@ -1994,7 +1977,6 @@ static int shmem_fill_super(struct super_block *sb,
        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
        sb->s_magic = TMPFS_MAGIC;
        sb->s_op = &shmem_ops;
-       sb->s_xattr = shmem_xattr_handlers;
 
        inode = shmem_get_inode(sb, S_IFDIR | mode, 0);
        if (!inode)
@@ -2083,12 +2065,6 @@ static struct file_operations shmem_file_operations = {
 static struct inode_operations shmem_inode_operations = {
        .truncate       = shmem_truncate,
        .setattr        = shmem_notify_change,
-#ifdef CONFIG_TMPFS_XATTR
-       .setxattr       = generic_setxattr,
-       .getxattr       = generic_getxattr,
-       .listxattr      = generic_listxattr,
-       .removexattr    = generic_removexattr,
-#endif
 };
 
 static struct inode_operations shmem_dir_inode_operations = {
@@ -2102,21 +2078,6 @@ static struct inode_operations shmem_dir_inode_operations = {
        .rmdir          = shmem_rmdir,
        .mknod          = shmem_mknod,
        .rename         = shmem_rename,
-#ifdef CONFIG_TMPFS_XATTR
-       .setxattr       = generic_setxattr,
-       .getxattr       = generic_getxattr,
-       .listxattr      = generic_listxattr,
-       .removexattr    = generic_removexattr,
-#endif
-#endif
-};
-
-static struct inode_operations shmem_special_inode_operations = {
-#ifdef CONFIG_TMPFS_XATTR
-       .setxattr       = generic_setxattr,
-       .getxattr       = generic_getxattr,
-       .listxattr      = generic_listxattr,
-       .removexattr    = generic_removexattr,
 #endif
 };
 
@@ -2142,48 +2103,6 @@ static struct vm_operations_struct shmem_vm_ops = {
 };
 
 
-#ifdef CONFIG_TMPFS_SECURITY
-
-static size_t shmem_xattr_security_list(struct inode *inode, char *list, size_t list_len,
-                                       const char *name, size_t name_len)
-{
-       return security_inode_listsecurity(inode, list, list_len);
-}
-
-static int shmem_xattr_security_get(struct inode *inode, const char *name, void *buffer, size_t size)
-{
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
-       return security_inode_getsecurity(inode, name, buffer, size);
-}
-
-static int shmem_xattr_security_set(struct inode *inode, const char *name, const void *value, size_t size, int flags)
-{
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
-       return security_inode_setsecurity(inode, name, value, size, flags);
-}
-
-static struct xattr_handler shmem_xattr_security_handler = {
-       .prefix = XATTR_SECURITY_PREFIX,
-       .list   = shmem_xattr_security_list,
-       .get    = shmem_xattr_security_get,
-       .set    = shmem_xattr_security_set,
-};
-
-#endif /* CONFIG_TMPFS_SECURITY */
-
-#ifdef CONFIG_TMPFS_XATTR
-
-static struct xattr_handler *shmem_xattr_handlers[] = {
-#ifdef CONFIG_TMPFS_SECURITY
-       &shmem_xattr_security_handler,
-#endif
-       NULL
-};
-
-#endif /* CONFIG_TMPFS_XATTR */
-
 static struct super_block *shmem_get_sb(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data)
 {
index c9e706db46340f81f723e899d45510cdfe78d50c..d7c4443991fe8e29e16dfaffa30a1711c6844c30 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
  * is less than 512 (PAGE_SIZE<<3), but greater than 256.
  */
 
+typedef unsigned int kmem_bufctl_t;
 #define BUFCTL_END     (((kmem_bufctl_t)(~0U))-0)
 #define BUFCTL_FREE    (((kmem_bufctl_t)(~0U))-1)
 #define        SLAB_LIMIT      (((kmem_bufctl_t)(~0U))-2)
@@ -600,7 +601,7 @@ static inline kmem_cache_t *__find_general_cachep(size_t size,
                csizep++;
 
        /*
-        * Really subtile: The last entry with cs->cs_size==ULONG_MAX
+        * Really subtle: The last entry with cs->cs_size==ULONG_MAX
         * has cs_{dma,}cachep==NULL. Thus no special case
         * for large kmalloc calls required.
         */
@@ -2165,7 +2166,9 @@ static inline void *__cache_alloc(kmem_cache_t *cachep, unsigned int __nocast fl
                objp = cache_alloc_refill(cachep, flags);
        }
        local_irq_restore(save_flags);
-       objp = cache_alloc_debugcheck_after(cachep, flags, objp, __builtin_return_address(0));
+       objp = cache_alloc_debugcheck_after(cachep, flags, objp,
+                                       __builtin_return_address(0));
+       prefetchw(objp);
        return objp;
 }
 
@@ -2555,24 +2558,18 @@ void kmem_cache_free(kmem_cache_t *cachep, void *objp)
 EXPORT_SYMBOL(kmem_cache_free);
 
 /**
- * kcalloc - allocate memory for an array. The memory is set to zero.
- * @n: number of elements.
- * @size: element size.
+ * kzalloc - allocate memory. The memory is set to zero.
+ * @size: how many bytes of memory are required.
  * @flags: the type of memory to allocate.
  */
-void *kcalloc(size_t n, size_t size, unsigned int __nocast flags)
+void *kzalloc(size_t size, unsigned int __nocast flags)
 {
-       void *ret = NULL;
-
-       if (n != 0 && size > INT_MAX / n)
-               return ret;
-
-       ret = kmalloc(n * size, flags);
+       void *ret = kmalloc(size, flags);
        if (ret)
-               memset(ret, 0, n * size);
+               memset(ret, 0, size);
        return ret;
 }
-EXPORT_SYMBOL(kcalloc);
+EXPORT_SYMBOL(kzalloc);
 
 /**
  * kfree - free previously allocated memory
@@ -3073,20 +3070,24 @@ ssize_t slabinfo_write(struct file *file, const char __user *buffer,
 }
 #endif
 
+/**
+ * ksize - get the actual amount of memory allocated for a given object
+ * @objp: Pointer to the object
+ *
+ * kmalloc may internally round up allocations and return more memory
+ * than requested. ksize() can be used to determine the actual amount of
+ * memory allocated. The caller may use this additional memory, even though
+ * a smaller amount of memory was initially specified with the kmalloc call.
+ * The caller must guarantee that objp points to a valid object previously
+ * allocated with either kmalloc() or kmem_cache_alloc(). The object
+ * must not be freed during the duration of the call.
+ */
 unsigned int ksize(const void *objp)
 {
-       kmem_cache_t *c;
-       unsigned long flags;
-       unsigned int size = 0;
-
-       if (likely(objp != NULL)) {
-               local_irq_save(flags);
-               c = GET_PAGE_CACHE(virt_to_page(objp));
-               size = kmem_cache_size(c);
-               local_irq_restore(flags);
-       }
+       if (unlikely(objp == NULL))
+               return 0;
 
-       return size;
+       return obj_reallen(GET_PAGE_CACHE(virt_to_page(objp)));
 }
 
 
index b54e304df4a70c7232dcc9464f69582d68339993..347249a4917afa922f4c8ae5d38fbfe81c189a5a 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/mmzone.h>
 #include <linux/bootmem.h>
 #include <linux/module.h>
+#include <linux/spinlock.h>
 #include <asm/dma.h>
 
 /*
  *
  * 1) mem_section      - memory sections, mem_map's for valid memory
  */
-struct mem_section mem_section[NR_MEM_SECTIONS];
+#ifdef CONFIG_SPARSEMEM_EXTREME
+struct mem_section *mem_section[NR_SECTION_ROOTS]
+       ____cacheline_maxaligned_in_smp;
+#else
+struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT]
+       ____cacheline_maxaligned_in_smp;
+#endif
 EXPORT_SYMBOL(mem_section);
 
+#ifdef CONFIG_SPARSEMEM_EXTREME
+static struct mem_section *sparse_index_alloc(int nid)
+{
+       struct mem_section *section = NULL;
+       unsigned long array_size = SECTIONS_PER_ROOT *
+                                  sizeof(struct mem_section);
+
+       section = alloc_bootmem_node(NODE_DATA(nid), array_size);
+
+       if (section)
+               memset(section, 0, array_size);
+
+       return section;
+}
+
+static int sparse_index_init(unsigned long section_nr, int nid)
+{
+       static spinlock_t index_init_lock = SPIN_LOCK_UNLOCKED;
+       unsigned long root = SECTION_NR_TO_ROOT(section_nr);
+       struct mem_section *section;
+       int ret = 0;
+
+       if (mem_section[root])
+               return -EEXIST;
+
+       section = sparse_index_alloc(nid);
+       /*
+        * This lock keeps two different sections from
+        * reallocating for the same index
+        */
+       spin_lock(&index_init_lock);
+
+       if (mem_section[root]) {
+               ret = -EEXIST;
+               goto out;
+       }
+
+       mem_section[root] = section;
+out:
+       spin_unlock(&index_init_lock);
+       return ret;
+}
+#else /* !SPARSEMEM_EXTREME */
+static inline int sparse_index_init(unsigned long section_nr, int nid)
+{
+       return 0;
+}
+#endif
+
 /* Record a memory area against a node. */
 void memory_present(int nid, unsigned long start, unsigned long end)
 {
@@ -24,8 +80,13 @@ void memory_present(int nid, unsigned long start, unsigned long end)
        start &= PAGE_SECTION_MASK;
        for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) {
                unsigned long section = pfn_to_section_nr(pfn);
-               if (!mem_section[section].section_mem_map)
-                       mem_section[section].section_mem_map = SECTION_MARKED_PRESENT;
+               struct mem_section *ms;
+
+               sparse_index_init(section, nid);
+
+               ms = __nr_to_section(section);
+               if (!ms->section_mem_map)
+                       ms->section_mem_map = SECTION_MARKED_PRESENT;
        }
 }
 
@@ -85,6 +146,7 @@ static struct page *sparse_early_mem_map_alloc(unsigned long pnum)
 {
        struct page *map;
        int nid = early_pfn_to_nid(section_nr_to_pfn(pnum));
+       struct mem_section *ms = __nr_to_section(pnum);
 
        map = alloc_remap(nid, sizeof(struct page) * PAGES_PER_SECTION);
        if (map)
@@ -96,7 +158,7 @@ static struct page *sparse_early_mem_map_alloc(unsigned long pnum)
                return map;
 
        printk(KERN_WARNING "%s: allocation failed\n", __FUNCTION__);
-       mem_section[pnum].section_mem_map = 0;
+       ms->section_mem_map = 0;
        return NULL;
 }
 
@@ -114,8 +176,9 @@ void sparse_init(void)
                        continue;
 
                map = sparse_early_mem_map_alloc(pnum);
-               if (map)
-                       sparse_init_one_section(&mem_section[pnum], pnum, map);
+               if (!map)
+                       continue;
+               sparse_init_one_section(__nr_to_section(pnum), pnum, map);
        }
 }
 
index 4f251775ef902f3b83c5d680a9caa536773b3a60..029e56eb5e77c342559954e7c18c710a5c51092e 100644 (file)
@@ -124,6 +124,7 @@ void __delete_from_swap_cache(struct page *page)
        BUG_ON(!PageLocked(page));
        BUG_ON(!PageSwapCache(page));
        BUG_ON(PageWriteback(page));
+       BUG_ON(PagePrivate(page));
 
        radix_tree_delete(&swapper_space.page_tree, page->private);
        page->private = 0;
@@ -196,11 +197,6 @@ void delete_from_swap_cache(struct page *page)
 {
        swp_entry_t entry;
 
-       BUG_ON(!PageSwapCache(page));
-       BUG_ON(!PageLocked(page));
-       BUG_ON(PageWriteback(page));
-       BUG_ON(PagePrivate(page));
-  
        entry.val = page->private;
 
        write_lock_irq(&swapper_space.tree_lock);
index 60cd24a55204efc5c84956443d02f9806bd66a9d..4b6e8bf986bcad3080c23b9ad2424d24479d2f35 100644 (file)
@@ -31,7 +31,7 @@
 #include <asm/tlbflush.h>
 #include <linux/swapops.h>
 
-DEFINE_SPINLOCK(swaplock);
+DEFINE_SPINLOCK(swap_lock);
 unsigned int nr_swapfiles;
 long total_swap_pages;
 static int swap_overflow;
@@ -51,13 +51,11 @@ static DECLARE_MUTEX(swapon_sem);
 
 /*
  * We need this because the bdev->unplug_fn can sleep and we cannot
- * hold swap_list_lock while calling the unplug_fn. And swap_list_lock
+ * hold swap_lock while calling the unplug_fn. And swap_lock
  * cannot be turned into a semaphore.
  */
 static DECLARE_RWSEM(swap_unplug_sem);
 
-#define SWAPFILE_CLUSTER 256
-
 void swap_unplug_io_fn(struct backing_dev_info *unused_bdi, struct page *page)
 {
        swp_entry_t entry;
@@ -84,116 +82,135 @@ void swap_unplug_io_fn(struct backing_dev_info *unused_bdi, struct page *page)
        up_read(&swap_unplug_sem);
 }
 
-static inline int scan_swap_map(struct swap_info_struct *si)
+#define SWAPFILE_CLUSTER       256
+#define LATENCY_LIMIT          256
+
+static inline unsigned long scan_swap_map(struct swap_info_struct *si)
 {
-       unsigned long offset;
+       unsigned long offset, last_in_cluster;
+       int latency_ration = LATENCY_LIMIT;
+
        /* 
-        * We try to cluster swap pages by allocating them
-        * sequentially in swap.  Once we've allocated
-        * SWAPFILE_CLUSTER pages this way, however, we resort to
-        * first-free allocation, starting a new cluster.  This
-        * prevents us from scattering swap pages all over the entire
-        * swap partition, so that we reduce overall disk seek times
-        * between swap pages.  -- sct */
-       if (si->cluster_nr) {
-               while (si->cluster_next <= si->highest_bit) {
-                       offset = si->cluster_next++;
+        * We try to cluster swap pages by allocating them sequentially
+        * in swap.  Once we've allocated SWAPFILE_CLUSTER pages this
+        * way, however, we resort to first-free allocation, starting
+        * a new cluster.  This prevents us from scattering swap pages
+        * all over the entire swap partition, so that we reduce
+        * overall disk seek times between swap pages.  -- sct
+        * But we do now try to find an empty cluster.  -Andrea
+        */
+
+       si->flags += SWP_SCANNING;
+       if (unlikely(!si->cluster_nr)) {
+               si->cluster_nr = SWAPFILE_CLUSTER - 1;
+               if (si->pages - si->inuse_pages < SWAPFILE_CLUSTER)
+                       goto lowest;
+               spin_unlock(&swap_lock);
+
+               offset = si->lowest_bit;
+               last_in_cluster = offset + SWAPFILE_CLUSTER - 1;
+
+               /* Locate the first empty (unaligned) cluster */
+               for (; last_in_cluster <= si->highest_bit; offset++) {
                        if (si->swap_map[offset])
-                               continue;
-                       si->cluster_nr--;
-                       goto got_page;
-               }
-       }
-       si->cluster_nr = SWAPFILE_CLUSTER;
-
-       /* try to find an empty (even not aligned) cluster. */
-       offset = si->lowest_bit;
- check_next_cluster:
-       if (offset+SWAPFILE_CLUSTER-1 <= si->highest_bit)
-       {
-               unsigned long nr;
-               for (nr = offset; nr < offset+SWAPFILE_CLUSTER; nr++)
-                       if (si->swap_map[nr])
-                       {
-                               offset = nr+1;
-                               goto check_next_cluster;
+                               last_in_cluster = offset + SWAPFILE_CLUSTER;
+                       else if (offset == last_in_cluster) {
+                               spin_lock(&swap_lock);
+                               si->cluster_next = offset-SWAPFILE_CLUSTER-1;
+                               goto cluster;
                        }
-               /* We found a completly empty cluster, so start
-                * using it.
-                */
-               goto got_page;
+                       if (unlikely(--latency_ration < 0)) {
+                               cond_resched();
+                               latency_ration = LATENCY_LIMIT;
+                       }
+               }
+               spin_lock(&swap_lock);
+               goto lowest;
        }
-       /* No luck, so now go finegrined as usual. -Andrea */
-       for (offset = si->lowest_bit; offset <= si->highest_bit ; offset++) {
-               if (si->swap_map[offset])
-                       continue;
-               si->lowest_bit = offset+1;
-       got_page:
+
+       si->cluster_nr--;
+cluster:
+       offset = si->cluster_next;
+       if (offset > si->highest_bit)
+lowest:                offset = si->lowest_bit;
+checks:        if (!(si->flags & SWP_WRITEOK))
+               goto no_page;
+       if (!si->highest_bit)
+               goto no_page;
+       if (!si->swap_map[offset]) {
                if (offset == si->lowest_bit)
                        si->lowest_bit++;
                if (offset == si->highest_bit)
                        si->highest_bit--;
-               if (si->lowest_bit > si->highest_bit) {
+               si->inuse_pages++;
+               if (si->inuse_pages == si->pages) {
                        si->lowest_bit = si->max;
                        si->highest_bit = 0;
                }
                si->swap_map[offset] = 1;
-               si->inuse_pages++;
-               nr_swap_pages--;
-               si->cluster_next = offset+1;
+               si->cluster_next = offset + 1;
+               si->flags -= SWP_SCANNING;
                return offset;
        }
-       si->lowest_bit = si->max;
-       si->highest_bit = 0;
+
+       spin_unlock(&swap_lock);
+       while (++offset <= si->highest_bit) {
+               if (!si->swap_map[offset]) {
+                       spin_lock(&swap_lock);
+                       goto checks;
+               }
+               if (unlikely(--latency_ration < 0)) {
+                       cond_resched();
+                       latency_ration = LATENCY_LIMIT;
+               }
+       }
+       spin_lock(&swap_lock);
+       goto lowest;
+
+no_page:
+       si->flags -= SWP_SCANNING;
        return 0;
 }
 
 swp_entry_t get_swap_page(void)
 {
-       struct swap_info_struct * p;
-       unsigned long offset;
-       swp_entry_t entry;
-       int type, wrapped = 0;
+       struct swap_info_struct *si;
+       pgoff_t offset;
+       int type, next;
+       int wrapped = 0;
 
-       entry.val = 0;  /* Out of memory */
-       swap_list_lock();
-       type = swap_list.next;
-       if (type < 0)
-               goto out;
+       spin_lock(&swap_lock);
        if (nr_swap_pages <= 0)
-               goto out;
+               goto noswap;
+       nr_swap_pages--;
+
+       for (type = swap_list.next; type >= 0 && wrapped < 2; type = next) {
+               si = swap_info + type;
+               next = si->next;
+               if (next < 0 ||
+                   (!wrapped && si->prio != swap_info[next].prio)) {
+                       next = swap_list.head;
+                       wrapped++;
+               }
 
-       while (1) {
-               p = &swap_info[type];
-               if ((p->flags & SWP_ACTIVE) == SWP_ACTIVE) {
-                       swap_device_lock(p);
-                       offset = scan_swap_map(p);
-                       swap_device_unlock(p);
-                       if (offset) {
-                               entry = swp_entry(type,offset);
-                               type = swap_info[type].next;
-                               if (type < 0 ||
-                                       p->prio != swap_info[type].prio) {
-                                               swap_list.next = swap_list.head;
-                               } else {
-                                       swap_list.next = type;
-                               }
-                               goto out;
-                       }
+               if (!si->highest_bit)
+                       continue;
+               if (!(si->flags & SWP_WRITEOK))
+                       continue;
+
+               swap_list.next = next;
+               offset = scan_swap_map(si);
+               if (offset) {
+                       spin_unlock(&swap_lock);
+                       return swp_entry(type, offset);
                }
-               type = p->next;
-               if (!wrapped) {
-                       if (type < 0 || p->prio != swap_info[type].prio) {
-                               type = swap_list.head;
-                               wrapped = 1;
-                       }
-               } else
-                       if (type < 0)
-                               goto out;       /* out of swap space */
+               next = swap_list.next;
        }
-out:
-       swap_list_unlock();
-       return entry;
+
+       nr_swap_pages++;
+noswap:
+       spin_unlock(&swap_lock);
+       return (swp_entry_t) {0};
 }
 
 static struct swap_info_struct * swap_info_get(swp_entry_t entry)
@@ -214,10 +231,7 @@ static struct swap_info_struct * swap_info_get(swp_entry_t entry)
                goto bad_offset;
        if (!p->swap_map[offset])
                goto bad_free;
-       swap_list_lock();
-       if (p->prio > swap_info[swap_list.next].prio)
-               swap_list.next = type;
-       swap_device_lock(p);
+       spin_lock(&swap_lock);
        return p;
 
 bad_free:
@@ -235,12 +249,6 @@ out:
        return NULL;
 }      
 
-static void swap_info_put(struct swap_info_struct * p)
-{
-       swap_device_unlock(p);
-       swap_list_unlock();
-}
-
 static int swap_entry_free(struct swap_info_struct *p, unsigned long offset)
 {
        int count = p->swap_map[offset];
@@ -253,6 +261,8 @@ static int swap_entry_free(struct swap_info_struct *p, unsigned long offset)
                                p->lowest_bit = offset;
                        if (offset > p->highest_bit)
                                p->highest_bit = offset;
+                       if (p->prio > swap_info[swap_list.next].prio)
+                               swap_list.next = p - swap_info;
                        nr_swap_pages++;
                        p->inuse_pages--;
                }
@@ -271,7 +281,7 @@ void swap_free(swp_entry_t entry)
        p = swap_info_get(entry);
        if (p) {
                swap_entry_free(p, swp_offset(entry));
-               swap_info_put(p);
+               spin_unlock(&swap_lock);
        }
 }
 
@@ -289,7 +299,7 @@ static inline int page_swapcount(struct page *page)
        if (p) {
                /* Subtract the 1 for the swap cache itself */
                count = p->swap_map[swp_offset(entry)] - 1;
-               swap_info_put(p);
+               spin_unlock(&swap_lock);
        }
        return count;
 }
@@ -346,7 +356,7 @@ int remove_exclusive_swap_page(struct page *page)
                }
                write_unlock_irq(&swapper_space.tree_lock);
        }
-       swap_info_put(p);
+       spin_unlock(&swap_lock);
 
        if (retval) {
                swap_free(entry);
@@ -369,7 +379,7 @@ void free_swap_and_cache(swp_entry_t entry)
        if (p) {
                if (swap_entry_free(p, swp_offset(entry)) == 1)
                        page = find_trylock_page(&swapper_space, entry.val);
-               swap_info_put(p);
+               spin_unlock(&swap_lock);
        }
        if (page) {
                int one_user;
@@ -531,17 +541,18 @@ static int unuse_mm(struct mm_struct *mm,
  * Scan swap_map from current position to next entry still in use.
  * Recycle to start on reaching the end, returning 0 when empty.
  */
-static int find_next_to_unuse(struct swap_info_struct *si, int prev)
+static unsigned int find_next_to_unuse(struct swap_info_struct *si,
+                                       unsigned int prev)
 {
-       int max = si->max;
-       int i = prev;
+       unsigned int max = si->max;
+       unsigned int i = prev;
        int count;
 
        /*
-        * No need for swap_device_lock(si) here: we're just looking
+        * No need for swap_lock here: we're just looking
         * for whether an entry is in use, not modifying it; false
         * hits are okay, and sys_swapoff() has already prevented new
-        * allocations from this area (while holding swap_list_lock()).
+        * allocations from this area (while holding swap_lock).
         */
        for (;;) {
                if (++i >= max) {
@@ -577,7 +588,7 @@ static int try_to_unuse(unsigned int type)
        unsigned short swcount;
        struct page *page;
        swp_entry_t entry;
-       int i = 0;
+       unsigned int i = 0;
        int retval = 0;
        int reset_overflow = 0;
        int shmem;
@@ -731,9 +742,9 @@ static int try_to_unuse(unsigned int type)
                 * report them; but do report if we reset SWAP_MAP_MAX.
                 */
                if (*swap_map == SWAP_MAP_MAX) {
-                       swap_device_lock(si);
+                       spin_lock(&swap_lock);
                        *swap_map = 1;
-                       swap_device_unlock(si);
+                       spin_unlock(&swap_lock);
                        reset_overflow = 1;
                }
 
@@ -797,9 +808,9 @@ static int try_to_unuse(unsigned int type)
 }
 
 /*
- * After a successful try_to_unuse, if no swap is now in use, we know we
- * can empty the mmlist.  swap_list_lock must be held on entry and exit.
- * Note that mmlist_lock nests inside swap_list_lock, and an mm must be
+ * After a successful try_to_unuse, if no swap is now in use, we know
+ * we can empty the mmlist.  swap_lock must be held on entry and exit.
+ * Note that mmlist_lock nests inside swap_lock, and an mm must be
  * added to the mmlist just after page_duplicate - before would be racy.
  */
 static void drain_mmlist(void)
@@ -832,9 +843,9 @@ sector_t map_swap_page(struct swap_info_struct *sis, pgoff_t offset)
                                offset < (se->start_page + se->nr_pages)) {
                        return se->start_block + (offset - se->start_page);
                }
-               lh = se->list.prev;
+               lh = se->list.next;
                if (lh == &sis->extent_list)
-                       lh = lh->prev;
+                       lh = lh->next;
                se = list_entry(lh, struct swap_extent, list);
                sis->curr_swap_extent = se;
                BUG_ON(se == start_se);         /* It *must* be present */
@@ -854,15 +865,13 @@ static void destroy_swap_extents(struct swap_info_struct *sis)
                list_del(&se->list);
                kfree(se);
        }
-       sis->nr_extents = 0;
 }
 
 /*
  * Add a block range (and the corresponding page range) into this swapdev's
- * extent list.  The extent list is kept sorted in block order.
+ * extent list.  The extent list is kept sorted in page order.
  *
- * This function rather assumes that it is called in ascending sector_t order.
- * It doesn't look for extent coalescing opportunities.
+ * This function rather assumes that it is called in ascending page order.
  */
 static int
 add_swap_extent(struct swap_info_struct *sis, unsigned long start_page,
@@ -872,16 +881,15 @@ add_swap_extent(struct swap_info_struct *sis, unsigned long start_page,
        struct swap_extent *new_se;
        struct list_head *lh;
 
-       lh = sis->extent_list.next;     /* The highest-addressed block */
-       while (lh != &sis->extent_list) {
+       lh = sis->extent_list.prev;     /* The highest page extent */
+       if (lh != &sis->extent_list) {
                se = list_entry(lh, struct swap_extent, list);
-               if (se->start_block + se->nr_pages == start_block &&
-                   se->start_page  + se->nr_pages == start_page) {
+               BUG_ON(se->start_page + se->nr_pages != start_page);
+               if (se->start_block + se->nr_pages == start_block) {
                        /* Merge it */
                        se->nr_pages += nr_pages;
                        return 0;
                }
-               lh = lh->next;
        }
 
        /*
@@ -894,16 +902,8 @@ add_swap_extent(struct swap_info_struct *sis, unsigned long start_page,
        new_se->nr_pages = nr_pages;
        new_se->start_block = start_block;
 
-       lh = sis->extent_list.prev;     /* The lowest block */
-       while (lh != &sis->extent_list) {
-               se = list_entry(lh, struct swap_extent, list);
-               if (se->start_block > start_block)
-                       break;
-               lh = lh->prev;
-       }
-       list_add_tail(&new_se->list, lh);
-       sis->nr_extents++;
-       return 0;
+       list_add_tail(&new_se->list, &sis->extent_list);
+       return 1;
 }
 
 /*
@@ -926,7 +926,7 @@ add_swap_extent(struct swap_info_struct *sis, unsigned long start_page,
  * requirements, they are simply tossed out - we will never use those blocks
  * for swapping.
  *
- * For S_ISREG swapfiles we hold i_sem across the life of the swapon.  This
+ * For S_ISREG swapfiles we set S_SWAPFILE across the life of the swapon.  This
  * prevents root from shooting her foot off by ftruncating an in-use swapfile,
  * which will scribble on the fs.
  *
@@ -937,7 +937,7 @@ add_swap_extent(struct swap_info_struct *sis, unsigned long start_page,
  * This is extremely effective.  The average number of iterations in
  * map_swap_page() has been measured at about 0.3 per page.  - akpm.
  */
-static int setup_swap_extents(struct swap_info_struct *sis)
+static int setup_swap_extents(struct swap_info_struct *sis, sector_t *span)
 {
        struct inode *inode;
        unsigned blocks_per_page;
@@ -945,11 +945,15 @@ static int setup_swap_extents(struct swap_info_struct *sis)
        unsigned blkbits;
        sector_t probe_block;
        sector_t last_block;
+       sector_t lowest_block = -1;
+       sector_t highest_block = 0;
+       int nr_extents = 0;
        int ret;
 
        inode = sis->swap_file->f_mapping->host;
        if (S_ISBLK(inode->i_mode)) {
                ret = add_swap_extent(sis, 0, sis->max, 0);
+               *span = sis->pages;
                goto done;
        }
 
@@ -994,22 +998,32 @@ static int setup_swap_extents(struct swap_info_struct *sis)
                        }
                }
 
+               first_block >>= (PAGE_SHIFT - blkbits);
+               if (page_no) {  /* exclude the header page */
+                       if (first_block < lowest_block)
+                               lowest_block = first_block;
+                       if (first_block > highest_block)
+                               highest_block = first_block;
+               }
+
                /*
                 * We found a PAGE_SIZE-length, PAGE_SIZE-aligned run of blocks
                 */
-               ret = add_swap_extent(sis, page_no, 1,
-                               first_block >> (PAGE_SHIFT - blkbits));
-               if (ret)
+               ret = add_swap_extent(sis, page_no, 1, first_block);
+               if (ret < 0)
                        goto out;
+               nr_extents += ret;
                page_no++;
                probe_block += blocks_per_page;
 reprobe:
                continue;
        }
-       ret = 0;
+       ret = nr_extents;
+       *span = 1 + highest_block - lowest_block;
        if (page_no == 0)
-               ret = -EINVAL;
+               page_no = 1;    /* force Empty message */
        sis->max = page_no;
+       sis->pages = page_no - 1;
        sis->highest_bit = page_no - 1;
 done:
        sis->curr_swap_extent = list_entry(sis->extent_list.prev,
@@ -1069,7 +1083,7 @@ asmlinkage long sys_swapoff(const char __user * specialfile)
 
        mapping = victim->f_mapping;
        prev = -1;
-       swap_list_lock();
+       spin_lock(&swap_lock);
        for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
                p = swap_info + type;
                if ((p->flags & SWP_ACTIVE) == SWP_ACTIVE) {
@@ -1080,14 +1094,14 @@ asmlinkage long sys_swapoff(const char __user * specialfile)
        }
        if (type < 0) {
                err = -EINVAL;
-               swap_list_unlock();
+               spin_unlock(&swap_lock);
                goto out_dput;
        }
        if (!security_vm_enough_memory(p->pages))
                vm_unacct_memory(p->pages);
        else {
                err = -ENOMEM;
-               swap_list_unlock();
+               spin_unlock(&swap_lock);
                goto out_dput;
        }
        if (prev < 0) {
@@ -1102,18 +1116,15 @@ asmlinkage long sys_swapoff(const char __user * specialfile)
        nr_swap_pages -= p->pages;
        total_swap_pages -= p->pages;
        p->flags &= ~SWP_WRITEOK;
-       swap_list_unlock();
+       spin_unlock(&swap_lock);
+
        current->flags |= PF_SWAPOFF;
        err = try_to_unuse(type);
        current->flags &= ~PF_SWAPOFF;
 
-       /* wait for any unplug function to finish */
-       down_write(&swap_unplug_sem);
-       up_write(&swap_unplug_sem);
-
        if (err) {
                /* re-insert swap space back into swap_list */
-               swap_list_lock();
+               spin_lock(&swap_lock);
                for (prev = -1, i = swap_list.head; i >= 0; prev = i, i = swap_info[i].next)
                        if (p->prio >= swap_info[i].prio)
                                break;
@@ -1125,22 +1136,35 @@ asmlinkage long sys_swapoff(const char __user * specialfile)
                nr_swap_pages += p->pages;
                total_swap_pages += p->pages;
                p->flags |= SWP_WRITEOK;
-               swap_list_unlock();
+               spin_unlock(&swap_lock);
                goto out_dput;
        }
+
+       /* wait for any unplug function to finish */
+       down_write(&swap_unplug_sem);
+       up_write(&swap_unplug_sem);
+
+       destroy_swap_extents(p);
        down(&swapon_sem);
-       swap_list_lock();
+       spin_lock(&swap_lock);
        drain_mmlist();
-       swap_device_lock(p);
+
+       /* wait for anyone still in scan_swap_map */
+       p->highest_bit = 0;             /* cuts scans short */
+       while (p->flags >= SWP_SCANNING) {
+               spin_unlock(&swap_lock);
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(1);
+               spin_lock(&swap_lock);
+       }
+
        swap_file = p->swap_file;
        p->swap_file = NULL;
        p->max = 0;
        swap_map = p->swap_map;
        p->swap_map = NULL;
        p->flags = 0;
-       destroy_swap_extents(p);
-       swap_device_unlock(p);
-       swap_list_unlock();
+       spin_unlock(&swap_lock);
        up(&swapon_sem);
        vfree(swap_map);
        inode = mapping->host;
@@ -1213,7 +1237,7 @@ static int swap_show(struct seq_file *swap, void *v)
 
        file = ptr->swap_file;
        len = seq_path(swap, file->f_vfsmnt, file->f_dentry, " \t\n\\");
-       seq_printf(swap, "%*s%s\t%d\t%ld\t%d\n",
+       seq_printf(swap, "%*s%s\t%u\t%u\t%d\n",
                       len < 40 ? 40 - len : 1, " ",
                       S_ISBLK(file->f_dentry->d_inode->i_mode) ?
                                "partition" : "file\t",
@@ -1272,7 +1296,9 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
        static int least_priority;
        union swap_header *swap_header = NULL;
        int swap_header_version;
-       int nr_good_pages = 0;
+       unsigned int nr_good_pages = 0;
+       int nr_extents = 0;
+       sector_t span;
        unsigned long maxpages = 1;
        int swapfilesize;
        unsigned short *swap_map;
@@ -1282,7 +1308,7 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
-       swap_list_lock();
+       spin_lock(&swap_lock);
        p = swap_info;
        for (type = 0 ; type < nr_swapfiles ; type++,p++)
                if (!(p->flags & SWP_USED))
@@ -1301,14 +1327,13 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
         * swp_entry_t or the architecture definition of a swap pte.
         */
        if (type > swp_type(pte_to_swp_entry(swp_entry_to_pte(swp_entry(~0UL,0))))) {
-               swap_list_unlock();
+               spin_unlock(&swap_lock);
                goto out;
        }
        if (type >= nr_swapfiles)
                nr_swapfiles = type+1;
        INIT_LIST_HEAD(&p->extent_list);
        p->flags = SWP_USED;
-       p->nr_extents = 0;
        p->swap_file = NULL;
        p->old_block_size = 0;
        p->swap_map = NULL;
@@ -1316,7 +1341,6 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
        p->highest_bit = 0;
        p->cluster_nr = 0;
        p->inuse_pages = 0;
-       spin_lock_init(&p->sdev_lock);
        p->next = -1;
        if (swap_flags & SWAP_FLAG_PREFER) {
                p->prio =
@@ -1324,7 +1348,7 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
        } else {
                p->prio = --least_priority;
        }
-       swap_list_unlock();
+       spin_unlock(&swap_lock);
        name = getname(specialfile);
        error = PTR_ERR(name);
        if (IS_ERR(name)) {
@@ -1426,6 +1450,8 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
                }
 
                p->lowest_bit  = 1;
+               p->cluster_next = 1;
+
                /*
                 * Find out how many pages are allowed for a single swap
                 * device. There are two limiting factors: 1) the number of
@@ -1446,6 +1472,10 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
                p->highest_bit = maxpages - 1;
 
                error = -EINVAL;
+               if (!maxpages)
+                       goto bad_swap;
+               if (swap_header->info.nr_badpages && S_ISREG(inode->i_mode))
+                       goto bad_swap;
                if (swap_header->info.nr_badpages > MAX_SWAP_BADPAGES)
                        goto bad_swap;
                
@@ -1470,35 +1500,40 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
                if (error) 
                        goto bad_swap;
        }
-       
+
        if (swapfilesize && maxpages > swapfilesize) {
                printk(KERN_WARNING
                       "Swap area shorter than signature indicates\n");
                error = -EINVAL;
                goto bad_swap;
        }
+       if (nr_good_pages) {
+               p->swap_map[0] = SWAP_MAP_BAD;
+               p->max = maxpages;
+               p->pages = nr_good_pages;
+               nr_extents = setup_swap_extents(p, &span);
+               if (nr_extents < 0) {
+                       error = nr_extents;
+                       goto bad_swap;
+               }
+               nr_good_pages = p->pages;
+       }
        if (!nr_good_pages) {
                printk(KERN_WARNING "Empty swap-file\n");
                error = -EINVAL;
                goto bad_swap;
        }
-       p->swap_map[0] = SWAP_MAP_BAD;
-       p->max = maxpages;
-       p->pages = nr_good_pages;
-
-       error = setup_swap_extents(p);
-       if (error)
-               goto bad_swap;
 
        down(&swapon_sem);
-       swap_list_lock();
-       swap_device_lock(p);
+       spin_lock(&swap_lock);
        p->flags = SWP_ACTIVE;
        nr_swap_pages += nr_good_pages;
        total_swap_pages += nr_good_pages;
-       printk(KERN_INFO "Adding %dk swap on %s.  Priority:%d extents:%d\n",
-               nr_good_pages<<(PAGE_SHIFT-10), name,
-               p->prio, p->nr_extents);
+
+       printk(KERN_INFO "Adding %uk swap on %s.  "
+                       "Priority:%d extents:%d across:%lluk\n",
+               nr_good_pages<<(PAGE_SHIFT-10), name, p->prio,
+               nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10));
 
        /* insert swap space into swap_list: */
        prev = -1;
@@ -1514,8 +1549,7 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
        } else {
                swap_info[prev].next = p - swap_info;
        }
-       swap_device_unlock(p);
-       swap_list_unlock();
+       spin_unlock(&swap_lock);
        up(&swapon_sem);
        error = 0;
        goto out;
@@ -1524,16 +1558,16 @@ bad_swap:
                set_blocksize(bdev, p->old_block_size);
                bd_release(bdev);
        }
+       destroy_swap_extents(p);
 bad_swap_2:
-       swap_list_lock();
+       spin_lock(&swap_lock);
        swap_map = p->swap_map;
        p->swap_file = NULL;
        p->swap_map = NULL;
        p->flags = 0;
        if (!(swap_flags & SWAP_FLAG_PREFER))
                ++least_priority;
-       swap_list_unlock();
-       destroy_swap_extents(p);
+       spin_unlock(&swap_lock);
        vfree(swap_map);
        if (swap_file)
                filp_close(swap_file, NULL);
@@ -1557,7 +1591,7 @@ void si_swapinfo(struct sysinfo *val)
        unsigned int i;
        unsigned long nr_to_be_unused = 0;
 
-       swap_list_lock();
+       spin_lock(&swap_lock);
        for (i = 0; i < nr_swapfiles; i++) {
                if (!(swap_info[i].flags & SWP_USED) ||
                     (swap_info[i].flags & SWP_WRITEOK))
@@ -1566,7 +1600,7 @@ void si_swapinfo(struct sysinfo *val)
        }
        val->freeswap = nr_swap_pages + nr_to_be_unused;
        val->totalswap = total_swap_pages + nr_to_be_unused;
-       swap_list_unlock();
+       spin_unlock(&swap_lock);
 }
 
 /*
@@ -1587,7 +1621,7 @@ int swap_duplicate(swp_entry_t entry)
        p = type + swap_info;
        offset = swp_offset(entry);
 
-       swap_device_lock(p);
+       spin_lock(&swap_lock);
        if (offset < p->max && p->swap_map[offset]) {
                if (p->swap_map[offset] < SWAP_MAP_MAX - 1) {
                        p->swap_map[offset]++;
@@ -1599,7 +1633,7 @@ int swap_duplicate(swp_entry_t entry)
                        result = 1;
                }
        }
-       swap_device_unlock(p);
+       spin_unlock(&swap_lock);
 out:
        return result;
 
@@ -1615,7 +1649,7 @@ get_swap_info_struct(unsigned type)
 }
 
 /*
- * swap_device_lock prevents swap_map being freed. Don't grab an extra
+ * swap_lock prevents swap_map being freed. Don't grab an extra
  * reference on the swaphandle, it doesn't matter if it becomes unused.
  */
 int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
@@ -1631,7 +1665,7 @@ int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
                toff++, i--;
        *offset = toff;
 
-       swap_device_lock(swapdev);
+       spin_lock(&swap_lock);
        do {
                /* Don't read-ahead past the end of the swap area */
                if (toff >= swapdev->max)
@@ -1644,6 +1678,6 @@ int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
                toff++;
                ret++;
        } while (--i);
-       swap_device_unlock(swapdev);
+       spin_unlock(&swap_lock);
        return ret;
 }
index 8ff16a1eee6ad43e5a7bec93a207ee94392c2233..67b358e57ef67af05279196408c6c0bc430180c3 100644 (file)
@@ -158,8 +158,6 @@ int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages)
        return err;
 }
 
-#define IOREMAP_MAX_ORDER      (7 + PAGE_SHIFT)        /* 128 pages */
-
 struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
                                unsigned long start, unsigned long end)
 {
index cfffe5098d538e6d54d1954c523d455924cbf7fc..a740778f688da277d35eb0d15a60168257dbe42e 100644 (file)
@@ -822,6 +822,8 @@ shrink_zone(struct zone *zone, struct scan_control *sc)
        unsigned long nr_active;
        unsigned long nr_inactive;
 
+       atomic_inc(&zone->reclaim_in_progress);
+
        /*
         * Add one to `nr_to_scan' just to make sure that the kernel will
         * slowly sift through the active list.
@@ -861,6 +863,8 @@ shrink_zone(struct zone *zone, struct scan_control *sc)
        }
 
        throttle_vm_writeout();
+
+       atomic_dec(&zone->reclaim_in_progress);
 }
 
 /*
@@ -890,7 +894,7 @@ shrink_caches(struct zone **zones, struct scan_control *sc)
                if (zone->present_pages == 0)
                        continue;
 
-               if (!cpuset_zone_allowed(zone))
+               if (!cpuset_zone_allowed(zone, __GFP_HARDWALL))
                        continue;
 
                zone->temp_priority = sc->priority;
@@ -900,9 +904,7 @@ shrink_caches(struct zone **zones, struct scan_control *sc)
                if (zone->all_unreclaimable && sc->priority != DEF_PRIORITY)
                        continue;       /* Let kswapd poll it */
 
-               atomic_inc(&zone->reclaim_in_progress);
                shrink_zone(zone, sc);
-               atomic_dec(&zone->reclaim_in_progress);
        }
 }
  
@@ -938,7 +940,7 @@ int try_to_free_pages(struct zone **zones, unsigned int gfp_mask)
        for (i = 0; zones[i] != NULL; i++) {
                struct zone *zone = zones[i];
 
-               if (!cpuset_zone_allowed(zone))
+               if (!cpuset_zone_allowed(zone, __GFP_HARDWALL))
                        continue;
 
                zone->temp_priority = DEF_PRIORITY;
@@ -984,7 +986,7 @@ out:
        for (i = 0; zones[i] != 0; i++) {
                struct zone *zone = zones[i];
 
-               if (!cpuset_zone_allowed(zone))
+               if (!cpuset_zone_allowed(zone, __GFP_HARDWALL))
                        continue;
 
                zone->prev_priority = zone->temp_priority;
@@ -1254,7 +1256,7 @@ void wakeup_kswapd(struct zone *zone, int order)
                return;
        if (pgdat->kswapd_max_order < order)
                pgdat->kswapd_max_order = order;
-       if (!cpuset_zone_allowed(zone))
+       if (!cpuset_zone_allowed(zone, __GFP_HARDWALL))
                return;
        if (!waitqueue_active(&zone->zone_pgdat->kswapd_wait))
                return;
@@ -1358,14 +1360,13 @@ int zone_reclaim(struct zone *zone, unsigned int gfp_mask, unsigned int order)
                sc.swap_cluster_max = SWAP_CLUSTER_MAX;
 
        /* Don't reclaim the zone if there are other reclaimers active */
-       if (!atomic_inc_and_test(&zone->reclaim_in_progress))
+       if (atomic_read(&zone->reclaim_in_progress) > 0)
                goto out;
 
        shrink_zone(zone, &sc);
        total_reclaimed = sc.nr_reclaimed;
 
  out:
-       atomic_dec(&zone->reclaim_in_progress);
        return total_reclaimed;
 }
 
@@ -1375,6 +1376,9 @@ asmlinkage long sys_set_zone_reclaim(unsigned int node, unsigned int zone,
        struct zone *z;
        int i;
 
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+
        if (node >= MAX_NUMNODES || !node_online(node))
                return -EINVAL;
 
index 640d34e026c2e819623543f48aae3ef8dea126d9..282c4ab1abe60836c79cccb39173cf2cbc918f92 100644 (file)
@@ -87,7 +87,7 @@ static int fc_rebuild_header(struct sk_buff *skb)
        struct fch_hdr *fch=(struct fch_hdr *)skb->data;
        struct fcllc *fcllc=(struct fcllc *)(skb->data+sizeof(struct fch_hdr));
        if(fcllc->ethertype != htons(ETH_P_IP)) {
-               printk("fc_rebuild_header: Don't know how to resolve type %04X addresses ?\n",(unsigned int)htons(fcllc->ethertype));
+               printk("fc_rebuild_header: Don't know how to resolve type %04X addresses ?\n", ntohs(fcllc->ethertype));
                return 0;
        }
 #ifdef CONFIG_INET
index 5ce24c4bb840c7171b5948d797cb98b5267a9307..ac242a4bc346b541a09fe63456b17dcb64335ca5 100644 (file)
@@ -108,8 +108,8 @@ static int fddi_rebuild_header(struct sk_buff       *skb)
        else
 #endif 
        {
-               printk("%s: Don't know how to resolve type %02X addresses.\n",
-                      skb->dev->name, htons(fddi->hdr.llc_snap.ethertype));
+               printk("%s: Don't know how to resolve type %04X addresses.\n",
+                      skb->dev->name, ntohs(fddi->hdr.llc_snap.ethertype));
                return(0);
        }
 }
index 051e8af56a7785f371b24e8ba9b4a3ae28c8f58e..6d7fed3dd99ac0bd635ab7256ab0fc210fbafe76 100644 (file)
@@ -51,6 +51,7 @@ static int hippi_header(struct sk_buff *skb, struct net_device *dev,
                        unsigned len)
 {
        struct hippi_hdr *hip = (struct hippi_hdr *)skb_push(skb, HIPPI_HLEN);
+       struct hippi_cb *hcb = (struct hippi_cb *) skb->cb;
 
        if (!len){
                len = skb->len - HIPPI_HLEN;
@@ -84,9 +85,10 @@ static int hippi_header(struct sk_buff *skb, struct net_device *dev,
        if (daddr)
        {
                memcpy(hip->le.dest_switch_addr, daddr + 3, 3);
-               memcpy(&skb->private.ifield, daddr + 2, 4);
+               memcpy(&hcb->ifield, daddr + 2, 4);
                return HIPPI_HLEN;
        }
+       hcb->ifield = 0;
        return -((int)HIPPI_HLEN);
 }
 
@@ -122,7 +124,7 @@ static int hippi_rebuild_header(struct sk_buff *skb)
  *     Determine the packet's protocol ID.
  */
  
-unsigned short hippi_type_trans(struct sk_buff *skb, struct net_device *dev)
+__be16 hippi_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
        struct hippi_hdr *hip;
        
index 5ae63416df6dfc1bcdd58c10004a3d4b49487df9..b24817c63ca8e31459a7b2c87b43bb2b05726ec8 100644 (file)
@@ -35,7 +35,8 @@ static int p8022_request(struct datalink_proto *dl, struct sk_buff *skb,
 struct datalink_proto *register_8022_client(unsigned char type,
                                            int (*func)(struct sk_buff *skb,
                                                        struct net_device *dev,
-                                                       struct packet_type *pt))
+                                                       struct packet_type *pt,
+                                                       struct net_device *orig_dev))
 {
        struct datalink_proto *proto;
 
index a0b61b40225f40fe994e644c99e4ad6e0c17d356..6368d3dce444489ea41e654067aa92c012c0b924 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/skbuff.h>
 
 #include <net/datalink.h>
+#include <net/p8022.h>
 
 /*
  *     Place an 802.3 header on a packet. The driver will do the mac
index 1053821ddf933c922f01e5e8a9733046b0e64676..ab80b1fab53c877eb312e35bea9b98f7bc3b233b 100644 (file)
@@ -47,7 +47,7 @@ static struct datalink_proto *find_snap_client(unsigned char *desc)
  *     A SNAP packet has arrived
  */
 static int snap_rcv(struct sk_buff *skb, struct net_device *dev,
-                   struct packet_type *pt)
+                   struct packet_type *pt, struct net_device *orig_dev)
 {
        int rc = 1;
        struct datalink_proto *proto;
@@ -61,7 +61,7 @@ static int snap_rcv(struct sk_buff *skb, struct net_device *dev,
                /* Pass the frame on. */
                skb->h.raw  += 5;
                skb_pull(skb, 5);
-               rc = proto->rcvfunc(skb, dev, &snap_packet_type);
+               rc = proto->rcvfunc(skb, dev, &snap_packet_type, orig_dev);
        } else {
                skb->sk = NULL;
                kfree_skb(skb);
@@ -118,7 +118,8 @@ module_exit(snap_exit);
 struct datalink_proto *register_snap_client(unsigned char *desc,
                                            int (*rcvfunc)(struct sk_buff *,
                                                           struct net_device *,
-                                                          struct packet_type *))
+                                                          struct packet_type *,
+                                                          struct net_device *))
 {
        struct datalink_proto *proto = NULL;
 
index 36079630c49f1fbcfb7b9a29d8c84d46618e2501..700129556c13145b16355d2400d33b6b207843d7 100644 (file)
  *             2 of the License, or (at your option) any later version.
  */
 
+#include <linux/config.h>
 #include <linux/mm.h>
+#include <linux/if_tr.h>
 #include <linux/sysctl.h>
-#include <linux/config.h>
 
 #ifdef CONFIG_TR
 extern int sysctl_tr_rif_timeout;
index 508b1fa14546803c1c1f8300ba60e791f0e4dd71..9ae3a14dd016d3ed9da0c2fb603c6a8da900e182 100644 (file)
@@ -51,7 +51,7 @@ struct net_device *__find_vlan_dev(struct net_device* real_dev,
 /* found in vlan_dev.c */
 int vlan_dev_rebuild_header(struct sk_buff *skb);
 int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
-                  struct packet_type* ptype);
+                  struct packet_type *ptype, struct net_device *orig_dev);
 int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
                          unsigned short type, void *daddr, void *saddr,
                          unsigned len);
index 49c487413518c632204cbc0e409297949e8a49c3..145f5cde96cf7a0ece22d77da07e0c4fc0311e53 100644 (file)
@@ -113,7 +113,7 @@ static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb)
  *
  */
 int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
-                  struct packet_type* ptype)
+                  struct packet_type* ptype, struct net_device *orig_dev)
 {
        unsigned char *rawp = NULL;
        struct vlan_hdr *vhdr = (struct vlan_hdr *)(skb->data);
index 40a31ba86d2c9b689d4e59152539e4e4f10930db..2bdd5623fdd50889327bd4889e137f82bea6279c 100644 (file)
@@ -147,6 +147,7 @@ source "net/bridge/netfilter/Kconfig"
 
 endif
 
+source "net/dccp/Kconfig"
 source "net/sctp/Kconfig"
 source "net/atm/Kconfig"
 source "net/bridge/Kconfig"
@@ -205,6 +206,8 @@ config NET_PKTGEN
          To compile this code as a module, choose M here: the
          module will be called pktgen.
 
+source "net/netfilter/Kconfig"
+
 endmenu
 
 endmenu
@@ -212,6 +215,7 @@ endmenu
 source "net/ax25/Kconfig"
 source "net/irda/Kconfig"
 source "net/bluetooth/Kconfig"
+source "net/ieee80211/Kconfig"
 
 endif   # if NET
 endmenu # Networking
index 8e2bdc025ab852fccaf8b66c80175864c806b36a..4aa2f46d2a561f5ccc514a6f19312487cabba807 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_NET)             += $(tmp-y)
 obj-$(CONFIG_LLC)              += llc/
 obj-$(CONFIG_NET)              += ethernet/ 802/ sched/ netlink/
 obj-$(CONFIG_INET)             += ipv4/
+obj-$(CONFIG_NETFILTER)                += netfilter/
 obj-$(CONFIG_XFRM)             += xfrm/
 obj-$(CONFIG_UNIX)             += unix/
 ifneq ($(CONFIG_IPV6),)
@@ -41,7 +42,9 @@ obj-$(CONFIG_ATM)             += atm/
 obj-$(CONFIG_DECNET)           += decnet/
 obj-$(CONFIG_ECONET)           += econet/
 obj-$(CONFIG_VLAN_8021Q)       += 8021q/
+obj-$(CONFIG_IP_DCCP)          += dccp/
 obj-$(CONFIG_IP_SCTP)          += sctp/
+obj-$(CONFIG_IEEE80211)                += ieee80211/
 
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_SYSCTL)           += sysctl_net.o
index c34614ea5fcedcdc898c75c014a6c36ecfe65d4d..7076097debc29e454e02856d232015ad44607f8c 100644 (file)
@@ -698,7 +698,7 @@ static void __aarp_resolved(struct aarp_entry **list, struct aarp_entry *a,
  *     frame. We currently only support Ethernet.
  */
 static int aarp_rcv(struct sk_buff *skb, struct net_device *dev,
-                   struct packet_type *pt)
+                   struct packet_type *pt, struct net_device *orig_dev)
 {
        struct elapaarp *ea = aarp_hdr(skb);
        int hash, ret = 0;
index 192b529f86a456e62864867d9a219b5eabb7f796..1d31b3a3f1e598c2da003d9dd4e5c50551719e39 100644 (file)
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/tcp.h>
 #include <linux/if_arp.h>
 #include <linux/termios.h>     /* For TIOCOUTQ/INQ */
 #include <net/datalink.h>
 #include <net/psnap.h>
 #include <net/sock.h>
+#include <net/tcp_states.h>
 #include <net/route.h>
 #include <linux/atalk.h>
 
@@ -1390,7 +1390,7 @@ free_it:
  *     [ie ARPHRD_ETHERTALK]
  */
 static int atalk_rcv(struct sk_buff *skb, struct net_device *dev,
-                    struct packet_type *pt)
+                    struct packet_type *pt, struct net_device *orig_dev)
 {
        struct ddpehdr *ddp;
        struct sock *sock;
@@ -1482,7 +1482,7 @@ freeit:
  * header and append a long one.
  */
 static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev,
-                       struct packet_type *pt)
+                    struct packet_type *pt, struct net_device *orig_dev)
 {
        /* Expand any short form frames */
        if (skb->mac.raw[2] == 1) {
@@ -1528,7 +1528,7 @@ static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev,
        }
        skb->h.raw = skb->data;
 
-       return atalk_rcv(skb, dev, pt);
+       return atalk_rcv(skb, dev, pt, orig_dev);
 freeit:
        kfree_skb(skb);
        return 0;
index 4dbb5af34a5ed6bb67fae64501d96cbe04147593..d89056ec44d4ff11a842b045a8403253151cdae4 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "resources.h"
 #include "signaling.h"         /* for WAITING and sigd_attach */
+#include "common.h"
 
 
 static DECLARE_MUTEX(ioctl_mutex);
index 181a3002d8adc5eebfc117e609ba4427ccf8ff2f..4b1faca5013ff8d573ef784253c77e867be1fcbc 100644 (file)
@@ -34,7 +34,6 @@
 
 void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to)
 {
-       struct sk_buff *skb;
        unsigned long flags;
        struct sk_buff *skb_from = (struct sk_buff *) from;
        struct sk_buff *skb_to = (struct sk_buff *) to;
@@ -47,8 +46,6 @@ void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to)
        prev->next = skb_to;
        to->prev->next = from->next;
        to->prev = from->prev;
-       for (skb = from->next; skb != skb_to; skb = skb->next)
-               skb->list = to;
        to->qlen += from->qlen;
        spin_unlock(&to->lock);
        from->prev = skb_from;
index a5c94f11547c8e5319086f64a894f76f98994cbd..ed705ddad56be0e9bb6b69580b681b1e5c91f6d0 100644 (file)
@@ -45,7 +45,7 @@
 #include <linux/sysctl.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <net/ip.h>
 #include <net/arp.h>
 
@@ -1874,6 +1874,7 @@ static void ax25_info_stop(struct seq_file *seq, void *v)
 static int ax25_info_show(struct seq_file *seq, void *v)
 {
        ax25_cb *ax25 = v;
+       char buf[11];
        int k;
 
 
@@ -1885,13 +1886,13 @@ static int ax25_info_show(struct seq_file *seq, void *v)
        seq_printf(seq, "%8.8lx %s %s%s ",
                   (long) ax25,
                   ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name,
-                  ax2asc(&ax25->source_addr),
+                  ax2asc(buf, &ax25->source_addr),
                   ax25->iamdigi? "*":"");
-       seq_printf(seq, "%s", ax2asc(&ax25->dest_addr));
+       seq_printf(seq, "%s", ax2asc(buf, &ax25->dest_addr));
 
        for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) {
                seq_printf(seq, ",%s%s",
-                          ax2asc(&ax25->digipeat->calls[k]),
+                          ax2asc(buf, &ax25->digipeat->calls[k]),
                           ax25->digipeat->repeated[k]? "*":"");
        }
 
index f4fa6dfb846e6aa4cf2359584e4efed452dc8f58..dca179daf4150d3202e290709e611e13505dbd7d 100644 (file)
@@ -36,9 +36,8 @@ ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}};
 /*
  *     ax25 -> ascii conversion
  */
-char *ax2asc(ax25_address *a)
+char *ax2asc(char *buf, ax25_address *a)
 {
-       static char buf[11];
        char c, *s;
        int n;
 
index 8adc0022cf580fe60adc82fb5f58bed34dc089d9..edcaa897027cc031861b6d6bc66c5720a2c25b55 100644 (file)
@@ -22,8 +22,7 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/ip.h>                    /* For ip_rcv */
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
index 3a8b67316fc388d31360d999f0ebb35367328cff..061083efc1dcddc70cf900fbc43e77b69bfafa41 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/string.h>
 #include <linux/sockios.h>
 #include <linux/net.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <net/ax25.h>
 #include <linux/inet.h>
 #include <linux/netdevice.h>
index 3dc808fde33ffad4f70fc87ef8a9df08c66ad94a..810c9c76c2e022b08d171e255a0bf1340159f97f 100644 (file)
@@ -9,7 +9,6 @@
  * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
  * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
  */
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -26,9 +25,7 @@
 #include <linux/skbuff.h>
 #include <linux/netfilter.h>
 #include <net/sock.h>
-#include <net/ip.h>                    /* For ip_rcv */
-#include <net/tcp.h>
-#include <net/arp.h>                   /* For arp_rcv */
+#include <net/tcp_states.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
@@ -114,7 +111,6 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
 
        pid = *skb->data;
 
-#ifdef CONFIG_INET
        if (pid == AX25_P_IP) {
                /* working around a TCP bug to keep additional listeners
                 * happy. TCP re-uses the buffer and destroys the original
@@ -132,10 +128,9 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
                skb->dev      = ax25->ax25_dev->dev;
                skb->pkt_type = PACKET_HOST;
                skb->protocol = htons(ETH_P_IP);
-               ip_rcv(skb, skb->dev, NULL);    /* Wrong ptype */
+               netif_rx(skb);
                return 1;
        }
-#endif
        if (pid == AX25_P_SEGMENT) {
                skb_pull(skb, 1);       /* Remove PID */
                return ax25_rx_fragment(ax25, skb);
@@ -250,7 +245,6 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
 
                /* Now we are pointing at the pid byte */
                switch (skb->data[1]) {
-#ifdef CONFIG_INET
                case AX25_P_IP:
                        skb_pull(skb,2);                /* drop PID/CTRL */
                        skb->h.raw    = skb->data;
@@ -258,7 +252,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
                        skb->dev      = dev;
                        skb->pkt_type = PACKET_HOST;
                        skb->protocol = htons(ETH_P_IP);
-                       ip_rcv(skb, dev, ptype);        /* Note ptype here is the wrong one, fix me later */
+                       netif_rx(skb);
                        break;
 
                case AX25_P_ARP:
@@ -268,9 +262,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
                        skb->dev      = dev;
                        skb->pkt_type = PACKET_HOST;
                        skb->protocol = htons(ETH_P_ARP);
-                       arp_rcv(skb, dev, ptype);       /* Note ptype here is wrong... */
+                       netif_rx(skb);
                        break;
-#endif
                case AX25_P_TEXT:
                        /* Now find a suitable dgram socket */
                        sk = ax25_get_socket(&dest, &src, SOCK_DGRAM);
@@ -454,7 +447,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
  *     Receive an AX.25 frame via a SLIP interface.
  */
 int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev,
-                 struct packet_type *ptype)
+                 struct packet_type *ptype, struct net_device *orig_dev)
 {
        skb->sk = NULL;         /* Initially we don't know who it's for */
        skb->destructor = NULL; /* Who initializes this, dammit?! */
index c288526da4ce194c65f49878f40cd686cedd1216..26b77d9722201232d7adfcb2bb27dcc3fb90e246 100644 (file)
@@ -298,6 +298,8 @@ static void ax25_rt_seq_stop(struct seq_file *seq, void *v)
 
 static int ax25_rt_seq_show(struct seq_file *seq, void *v)
 {
+       char buf[11];
+
        if (v == SEQ_START_TOKEN)
                seq_puts(seq, "callsign  dev  mode digipeaters\n");
        else {
@@ -308,7 +310,7 @@ static int ax25_rt_seq_show(struct seq_file *seq, void *v)
                if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0)
                        callsign = "default";
                else
-                       callsign = ax2asc(&ax25_rt->callsign);
+                       callsign = ax2asc(buf, &ax25_rt->callsign);
 
                seq_printf(seq, "%-9s %-4s",
                        callsign,
@@ -328,7 +330,8 @@ static int ax25_rt_seq_show(struct seq_file *seq, void *v)
 
                if (ax25_rt->digipeat != NULL)
                        for (i = 0; i < ax25_rt->digipeat->ndigi; i++)
-                               seq_printf(seq, " %s", ax2asc(&ax25_rt->digipeat->calls[i]));
+                               seq_printf(seq, " %s",
+                                    ax2asc(buf, &ax25_rt->digipeat->calls[i]));
 
                seq_puts(seq, "\n");
        }
index 7131873322c4cec98554e5334b1899211aca835d..f6ed283e9de82fb2baee56e73580f5bc117fb5f4 100644 (file)
@@ -29,8 +29,7 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/ip.h>                    /* For ip_rcv */
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
index 066897bc074901965b83487c30e850ee27adc105..a29c480a4dc1f992f7f339c44f4b3d0ca9184526 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
index 99694b57f6f565d36f6787f58c8faa43cced25d2..c41dbe5fadee53867d98e24967ce96f942a32c18 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
@@ -76,7 +76,7 @@ void ax25_requeue_frames(ax25_cb *ax25)
                if (skb_prev == NULL)
                        skb_queue_head(&ax25->write_queue, skb);
                else
-                       skb_append(skb_prev, skb);
+                       skb_append(skb_prev, skb, &ax25->write_queue);
                skb_prev = skb;
        }
 }
index a8b3822f3ee42155032c914c31e80e1354b1fbfb..d53cc8615865f4b2e9ea7cc82452b57ddbbcef99 100644 (file)
@@ -168,12 +168,14 @@ static void ax25_uid_seq_stop(struct seq_file *seq, void *v)
 
 static int ax25_uid_seq_show(struct seq_file *seq, void *v)
 {
+       char buf[11];
+
        if (v == SEQ_START_TOKEN)
                seq_printf(seq, "Policy: %d\n", ax25_uid_policy);
        else {
                struct ax25_uid_assoc *pt = v;
 
-               seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(&pt->call));
+               seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(buf, &pt->call));
        }
        return 0;
 }
index ffa26c10bfe82d48c425d2ebf8b45bfb1e4fe82a..55dc42eac92c090cee03ac1adb11946b9880c062 100644 (file)
@@ -191,7 +191,7 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
 
        /* Special commands */
        while ((skb = skb_dequeue(&hdev->driver_init))) {
-               skb->pkt_type = HCI_COMMAND_PKT;
+               bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
                skb->dev = (void *) hdev;
                skb_queue_tail(&hdev->cmd_q, skb);
                hci_sched_cmd(hdev);
@@ -995,11 +995,11 @@ static int hci_send_frame(struct sk_buff *skb)
                return -ENODEV;
        }
 
-       BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
+       BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
 
        if (atomic_read(&hdev->promisc)) {
                /* Time stamp */
-               do_gettimeofday(&skb->stamp);
+               __net_timestamp(skb);
 
                hci_send_to_sock(hdev, skb);
        }
@@ -1034,7 +1034,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *p
 
        BT_DBG("skb len %d", skb->len);
 
-       skb->pkt_type = HCI_COMMAND_PKT;
+       bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
        skb->dev = (void *) hdev;
        skb_queue_tail(&hdev->cmd_q, skb);
        hci_sched_cmd(hdev);
@@ -1081,7 +1081,7 @@ int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
        BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
 
        skb->dev = (void *) hdev;
-       skb->pkt_type = HCI_ACLDATA_PKT;
+       bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
        hci_add_acl_hdr(skb, conn->handle, flags | ACL_START);
 
        if (!(list = skb_shinfo(skb)->frag_list)) {
@@ -1103,7 +1103,7 @@ int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
                        skb = list; list = list->next;
                        
                        skb->dev = (void *) hdev;
-                       skb->pkt_type = HCI_ACLDATA_PKT;
+                       bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
                        hci_add_acl_hdr(skb, conn->handle, flags | ACL_CONT);
 
                        BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
@@ -1139,7 +1139,7 @@ int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
        memcpy(skb->h.raw, &hdr, HCI_SCO_HDR_SIZE);
 
        skb->dev = (void *) hdev;
-       skb->pkt_type = HCI_SCODATA_PKT;
+       bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
        skb_queue_tail(&conn->data_q, skb);
        hci_sched_tx(hdev);
        return 0;
@@ -1369,7 +1369,7 @@ void hci_rx_task(unsigned long arg)
 
                if (test_bit(HCI_INIT, &hdev->flags)) {
                        /* Don't process data packets in this states. */
-                       switch (skb->pkt_type) {
+                       switch (bt_cb(skb)->pkt_type) {
                        case HCI_ACLDATA_PKT:
                        case HCI_SCODATA_PKT:
                                kfree_skb(skb);
@@ -1378,7 +1378,7 @@ void hci_rx_task(unsigned long arg)
                }
 
                /* Process frame */
-               switch (skb->pkt_type) {
+               switch (bt_cb(skb)->pkt_type) {
                case HCI_EVENT_PKT:
                        hci_event_packet(hdev, skb);
                        break;
index 46367bd129c34d14df31b23437b5af0d2bc3089d..d6da0939216d292baf0088a179d92672a647a54d 100644 (file)
@@ -484,14 +484,18 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
 /* Inquiry Result */
 static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
+       struct inquiry_data data;
        struct inquiry_info *info = (struct inquiry_info *) (skb->data + 1);
        int num_rsp = *((__u8 *) skb->data);
 
        BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
 
+       if (!num_rsp)
+               return;
+
        hci_dev_lock(hdev);
+
        for (; num_rsp; num_rsp--) {
-               struct inquiry_data data;
                bacpy(&data.bdaddr, &info->bdaddr);
                data.pscan_rep_mode     = info->pscan_rep_mode;
                data.pscan_period_mode  = info->pscan_period_mode;
@@ -502,30 +506,55 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
                info++;
                hci_inquiry_cache_update(hdev, &data);
        }
+
        hci_dev_unlock(hdev);
 }
 
 /* Inquiry Result With RSSI */
 static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct inquiry_info_with_rssi *info = (struct inquiry_info_with_rssi *) (skb->data + 1);
+       struct inquiry_data data;
        int num_rsp = *((__u8 *) skb->data);
 
        BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
 
+       if (!num_rsp)
+               return;
+
        hci_dev_lock(hdev);
-       for (; num_rsp; num_rsp--) {
-               struct inquiry_data data;
-               bacpy(&data.bdaddr, &info->bdaddr);
-               data.pscan_rep_mode     = info->pscan_rep_mode;
-               data.pscan_period_mode  = info->pscan_period_mode;
-               data.pscan_mode         = 0x00;
-               memcpy(data.dev_class, info->dev_class, 3);
-               data.clock_offset       = info->clock_offset;
-               data.rssi               = info->rssi;
-               info++;
-               hci_inquiry_cache_update(hdev, &data);
+
+       if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
+               struct inquiry_info_with_rssi_and_pscan_mode *info =
+                       (struct inquiry_info_with_rssi_and_pscan_mode *) (skb->data + 1);
+
+               for (; num_rsp; num_rsp--) {
+                       bacpy(&data.bdaddr, &info->bdaddr);
+                       data.pscan_rep_mode     = info->pscan_rep_mode;
+                       data.pscan_period_mode  = info->pscan_period_mode;
+                       data.pscan_mode         = info->pscan_mode;
+                       memcpy(data.dev_class, info->dev_class, 3);
+                       data.clock_offset       = info->clock_offset;
+                       data.rssi               = info->rssi;
+                       info++;
+                       hci_inquiry_cache_update(hdev, &data);
+               }
+       } else {
+               struct inquiry_info_with_rssi *info =
+                       (struct inquiry_info_with_rssi *) (skb->data + 1);
+
+               for (; num_rsp; num_rsp--) {
+                       bacpy(&data.bdaddr, &info->bdaddr);
+                       data.pscan_rep_mode     = info->pscan_rep_mode;
+                       data.pscan_period_mode  = info->pscan_period_mode;
+                       data.pscan_mode         = 0x00;
+                       memcpy(data.dev_class, info->dev_class, 3);
+                       data.clock_offset       = info->clock_offset;
+                       data.rssi               = info->rssi;
+                       info++;
+                       hci_inquiry_cache_update(hdev, &data);
+               }
        }
+
        hci_dev_unlock(hdev);
 }
 
@@ -865,6 +894,24 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk
        hci_dev_unlock(hdev);
 }
 
+/* Page Scan Repetition Mode */
+static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_pscan_rep_mode *ev = (struct hci_ev_pscan_rep_mode *) skb->data;
+       struct inquiry_entry *ie;
+
+       BT_DBG("%s", hdev->name);
+
+       hci_dev_lock(hdev);
+
+       if ((ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr))) {
+               ie->data.pscan_rep_mode = ev->pscan_rep_mode;
+               ie->timestamp = jiffies;
+       }
+
+       hci_dev_unlock(hdev);
+}
+
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_event_hdr *hdr = (struct hci_event_hdr *) skb->data;
@@ -937,6 +984,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_clock_offset_evt(hdev, skb);
                break;
 
+       case HCI_EV_PSCAN_REP_MODE:
+               hci_pscan_rep_mode_evt(hdev, skb);
+               break;
+
        case HCI_EV_CMD_STATUS:
                cs = (struct hci_ev_cmd_status *) skb->data;
                skb_pull(skb, sizeof(cs));
@@ -1036,9 +1087,9 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
        memcpy(ev->data, data, dlen);
 
        bt_cb(skb)->incoming = 1;
-       do_gettimeofday(&skb->stamp);
+       __net_timestamp(skb);
 
-       skb->pkt_type = HCI_EVENT_PKT;
+       bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
        skb->dev = (void *) hdev;
        hci_send_to_sock(hdev, skb);
        kfree_skb(skb);
index ebdcce5e7ca0b6d67e8974a52ede4f934e2c1936..32ef7975a139149a31481711a34de2c27040ce17 100644 (file)
@@ -110,11 +110,11 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
                /* Apply filter */
                flt = &hci_pi(sk)->filter;
 
-               if (!test_bit((skb->pkt_type == HCI_VENDOR_PKT) ?
-                               0 : (skb->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
+               if (!test_bit((bt_cb(skb)->pkt_type == HCI_VENDOR_PKT) ?
+                               0 : (bt_cb(skb)->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
                        continue;
 
-               if (skb->pkt_type == HCI_EVENT_PKT) {
+               if (bt_cb(skb)->pkt_type == HCI_EVENT_PKT) {
                        register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
 
                        if (!hci_test_bit(evt, &flt->event_mask))
@@ -131,7 +131,7 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
                        continue;
 
                /* Put type byte before the data */
-               memcpy(skb_push(nskb, 1), &nskb->pkt_type, 1);
+               memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1);
 
                if (sock_queue_rcv_skb(sk, nskb))
                        kfree_skb(nskb);
@@ -327,11 +327,17 @@ static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_
 {
        __u32 mask = hci_pi(sk)->cmsg_mask;
 
-       if (mask & HCI_CMSG_DIR)
-               put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(int), &bt_cb(skb)->incoming);
+       if (mask & HCI_CMSG_DIR) {
+               int incoming = bt_cb(skb)->incoming;
+               put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(incoming), &incoming);
+       }
+
+       if (mask & HCI_CMSG_TSTAMP) {
+               struct timeval tv;
 
-       if (mask & HCI_CMSG_TSTAMP)
-               put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, sizeof(skb->stamp), &skb->stamp);
+               skb_get_timestamp(skb, &tv);
+               put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, sizeof(tv), &tv);
+       }
 }
  
 static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, 
@@ -405,11 +411,11 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                goto drop;
        }
 
-       skb->pkt_type = *((unsigned char *) skb->data);
+       bt_cb(skb)->pkt_type = *((unsigned char *) skb->data);
        skb_pull(skb, 1);
        skb->dev = (void *) hdev;
 
-       if (skb->pkt_type == HCI_COMMAND_PKT) {
+       if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) {
                u16 opcode = __le16_to_cpu(get_unaligned((u16 *)skb->data));
                u16 ogf = hci_opcode_ogf(opcode);
                u16 ocf = hci_opcode_ocf(opcode);
index 32fccfb5bfa5de1b8c701fe0bb107792e2653534..d3d6bc547212f7d289928cdf393abce3a167eb08 100644 (file)
@@ -372,7 +372,7 @@ static struct proto l2cap_proto = {
        .obj_size       = sizeof(struct l2cap_pinfo)
 };
 
-static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio)
+static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, unsigned int __nocast prio)
 {
        struct sock *sk;
 
index 27bf5047cd3335967c90e8232ac8d9231ce94259..173f46e8cdaedbaffaf2a75852bd3522c7523421 100644 (file)
    SOFTWARE IS DISCLAIMED.
 */
 
-/* 
-   RPN support    -    Dirk Husemann <hud@zurich.ibm.com>
-*/
-
 /*
  * Bluetooth RFCOMM core.
  *
@@ -115,10 +111,10 @@ static void rfcomm_session_del(struct rfcomm_session *s);
 #define __get_mcc_len(b)  ((b & 0xfe) >> 1)
 
 /* RPN macros */
-#define __rpn_line_settings(data, stop, parity)  ((data & 0x3) | ((stop & 0x1) << 2) | ((parity & 0x3) << 3))
+#define __rpn_line_settings(data, stop, parity)  ((data & 0x3) | ((stop & 0x1) << 2) | ((parity & 0x7) << 3))
 #define __get_rpn_data_bits(line) ((line) & 0x3)
 #define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
-#define __get_rpn_parity(line)    (((line) >> 3) & 0x3)
+#define __get_rpn_parity(line)    (((line) >> 3) & 0x7)
 
 static inline void rfcomm_schedule(uint event)
 {
@@ -233,7 +229,7 @@ static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d)
        d->rx_credits = RFCOMM_DEFAULT_CREDITS;
 }
 
-struct rfcomm_dlc *rfcomm_dlc_alloc(int prio)
+struct rfcomm_dlc *rfcomm_dlc_alloc(unsigned int __nocast prio)
 {
        struct rfcomm_dlc *d = kmalloc(sizeof(*d), prio);
        if (!d)
@@ -780,10 +776,10 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d
        return rfcomm_send_frame(s, buf, ptr - buf);
 }
 
-static int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
-                          u8 bit_rate, u8 data_bits, u8 stop_bits,
-                          u8 parity, u8 flow_ctrl_settings, 
-                          u8 xon_char, u8 xoff_char, u16 param_mask)
+int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
+                       u8 bit_rate, u8 data_bits, u8 stop_bits,
+                       u8 parity, u8 flow_ctrl_settings, 
+                       u8 xon_char, u8 xoff_char, u16 param_mask)
 {
        struct rfcomm_hdr *hdr;
        struct rfcomm_mcc *mcc;
@@ -791,9 +787,9 @@ static int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
        u8 buf[16], *ptr = buf;
 
        BT_DBG("%p cr %d dlci %d bit_r 0x%x data_b 0x%x stop_b 0x%x parity 0x%x"
-              "flwc_s 0x%x xon_c 0x%x xoff_c 0x%x p_mask 0x%x", 
-                       s, cr, dlci, bit_rate, data_bits, stop_bits, parity, 
-                       flow_ctrl_settings, xon_char, xoff_char, param_mask);
+                       " flwc_s 0x%x xon_c 0x%x xoff_c 0x%x p_mask 0x%x", 
+               s, cr, dlci, bit_rate, data_bits, stop_bits, parity, 
+               flow_ctrl_settings, xon_char, xoff_char, param_mask);
 
        hdr = (void *) ptr; ptr += sizeof(*hdr);
        hdr->addr = __addr(s->initiator, 0);
@@ -1265,16 +1261,16 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
        u8 xon_char  = 0;
        u8 xoff_char = 0;
        u16 rpn_mask = RFCOMM_RPN_PM_ALL;
-       
-       BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", 
-              dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl,
-              rpn->xon_char, rpn->xoff_char, rpn->param_mask);
-       
-       if (!cr) 
+
+       BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x",
+               dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl,
+               rpn->xon_char, rpn->xoff_char, rpn->param_mask);
+
+       if (!cr)
                return 0;
-       
+
        if (len == 1) {
-               /* request: return default setting */
+               /* This is a request, return default settings */
                bit_rate  = RFCOMM_RPN_BR_115200;
                data_bits = RFCOMM_RPN_DATA_8;
                stop_bits = RFCOMM_RPN_STOP_1;
@@ -1282,11 +1278,12 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
                flow_ctrl = RFCOMM_RPN_FLOW_NONE;
                xon_char  = RFCOMM_RPN_XON_CHAR;
                xoff_char = RFCOMM_RPN_XOFF_CHAR;
-
                goto rpn_out;
        }
-       /* check for sane values: ignore/accept bit_rate, 8 bits, 1 stop bit, no parity,
-                                 no flow control lines, normal XON/XOFF chars */
+
+       /* Check for sane values, ignore/accept bit_rate, 8 bits, 1 stop bit,
+        * no parity, no flow control lines, normal XON/XOFF chars */
+
        if (rpn->param_mask & RFCOMM_RPN_PM_BITRATE) {
                bit_rate = rpn->bit_rate;
                if (bit_rate != RFCOMM_RPN_BR_115200) {
@@ -1295,6 +1292,7 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
                        rpn_mask ^= RFCOMM_RPN_PM_BITRATE;
                }
        }
+
        if (rpn->param_mask & RFCOMM_RPN_PM_DATA) {
                data_bits = __get_rpn_data_bits(rpn->line_settings);
                if (data_bits != RFCOMM_RPN_DATA_8) {
@@ -1303,6 +1301,7 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
                        rpn_mask ^= RFCOMM_RPN_PM_DATA;
                }
        }
+
        if (rpn->param_mask & RFCOMM_RPN_PM_STOP) {
                stop_bits = __get_rpn_stop_bits(rpn->line_settings);
                if (stop_bits != RFCOMM_RPN_STOP_1) {
@@ -1311,6 +1310,7 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
                        rpn_mask ^= RFCOMM_RPN_PM_STOP;
                }
        }
+
        if (rpn->param_mask & RFCOMM_RPN_PM_PARITY) {
                parity = __get_rpn_parity(rpn->line_settings);
                if (parity != RFCOMM_RPN_PARITY_NONE) {
@@ -1319,6 +1319,7 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
                        rpn_mask ^= RFCOMM_RPN_PM_PARITY;
                }
        }
+
        if (rpn->param_mask & RFCOMM_RPN_PM_FLOW) {
                flow_ctrl = rpn->flow_ctrl;
                if (flow_ctrl != RFCOMM_RPN_FLOW_NONE) {
@@ -1327,6 +1328,7 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
                        rpn_mask ^= RFCOMM_RPN_PM_FLOW;
                }
        }
+
        if (rpn->param_mask & RFCOMM_RPN_PM_XON) {
                xon_char = rpn->xon_char;
                if (xon_char != RFCOMM_RPN_XON_CHAR) {
@@ -1335,6 +1337,7 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
                        rpn_mask ^= RFCOMM_RPN_PM_XON;
                }
        }
+
        if (rpn->param_mask & RFCOMM_RPN_PM_XOFF) {
                xoff_char = rpn->xoff_char;
                if (xoff_char != RFCOMM_RPN_XOFF_CHAR) {
@@ -1345,9 +1348,8 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
        }
 
 rpn_out:
-       rfcomm_send_rpn(s, 0, dlci, 
-                       bit_rate, data_bits, stop_bits, parity, flow_ctrl,
-                       xon_char, xoff_char, rpn_mask);
+       rfcomm_send_rpn(s, 0, dlci, bit_rate, data_bits, stop_bits,
+                       parity, flow_ctrl, xon_char, xoff_char, rpn_mask);
 
        return 0;
 }
@@ -1358,14 +1360,13 @@ static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb
        u8 dlci = __get_dlci(rls->dlci);
 
        BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status);
-       
+
        if (!cr)
                return 0;
 
-       /* FIXME: We should probably do something with this
-          information here. But for now it's sufficient just
-          to reply -- Bluetooth 1.1 says it's mandatory to 
-          recognise and respond to RLS */
+       /* We should probably do something with this information here. But
+        * for now it's sufficient just to reply -- Bluetooth 1.1 says it's
+        * mandatory to recognise and respond to RLS */
 
        rfcomm_send_rls(s, 0, dlci, rls->status);
 
@@ -1381,7 +1382,7 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb
        BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig);
 
        d = rfcomm_dlc_get(s, dlci);
-       if (!d) 
+       if (!d)
                return 0;
 
        if (cr) {
@@ -1389,7 +1390,7 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb
                        set_bit(RFCOMM_TX_THROTTLED, &d->flags);
                else
                        clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
-               
+
                rfcomm_dlc_lock(d);
                if (d->modem_status)
                        d->modem_status(d, msc->v24_sig);
@@ -1398,7 +1399,7 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb
                rfcomm_send_msc(s, 0, dlci, msc->v24_sig);
 
                d->mscex |= RFCOMM_MSCEX_RX;
-       } else 
+       } else
                d->mscex |= RFCOMM_MSCEX_TX;
 
        return 0;
index 63a123c5c41b38dedef853b56c44ac4f55d55d16..90e19eb6d3cce0de84bb9a48796f9c260aacc71e 100644 (file)
@@ -284,7 +284,7 @@ static struct proto rfcomm_proto = {
        .obj_size       = sizeof(struct rfcomm_pinfo)
 };
 
-static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio)
+static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, unsigned int __nocast prio)
 {
        struct rfcomm_dlc *d;
        struct sock *sk;
index 6304590fd36a5f6d132f8a6262d5acdb616c0ebf..1bca860a6109fefc7e31216534996476826470ce 100644 (file)
@@ -286,7 +286,7 @@ static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *de
        skb->destructor = rfcomm_wfree;
 }
 
-static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int priority)
+static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, unsigned int __nocast priority)
 {
        if (atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) {
                struct sk_buff *skb = alloc_skb(size, priority);
@@ -528,9 +528,14 @@ static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
        struct rfcomm_dev *dev = dlc->owner;
        if (!dev)
                return;
-       
+
        BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig);
 
+       if ((dev->modem_status & TIOCM_CD) && !(v24_sig & RFCOMM_V24_DV)) {
+               if (dev->tty && !C_CLOCAL(dev->tty))
+                       tty_hangup(dev->tty);
+       }
+
        dev->modem_status = 
                ((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) |
                ((v24_sig & RFCOMM_V24_RTR) ? (TIOCM_RTS | TIOCM_CTS) : 0) |
@@ -740,20 +745,143 @@ static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned
        return -ENOIOCTLCMD;
 }
 
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
 static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old)
 {
-       BT_DBG("tty %p", tty);
+       struct termios *new = (struct termios *) tty->termios;
+       int old_baud_rate = tty_termios_baud_rate(old);
+       int new_baud_rate = tty_termios_baud_rate(new);
 
-       if ((tty->termios->c_cflag == old->c_cflag) &&
-               (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old->c_iflag)))
-               return;
+       u8 baud, data_bits, stop_bits, parity, x_on, x_off;
+       u16 changes = 0;
+
+       struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+
+       BT_DBG("tty %p termios %p", tty, old);
+
+       /* Handle turning off CRTSCTS */
+       if ((old->c_cflag & CRTSCTS) && !(new->c_cflag & CRTSCTS)) 
+               BT_DBG("Turning off CRTSCTS unsupported");
+
+       /* Parity on/off and when on, odd/even */
+       if (((old->c_cflag & PARENB) != (new->c_cflag & PARENB)) ||
+                       ((old->c_cflag & PARODD) != (new->c_cflag & PARODD)) ) {
+               changes |= RFCOMM_RPN_PM_PARITY;
+               BT_DBG("Parity change detected.");
+       }
+
+       /* Mark and space parity are not supported! */
+       if (new->c_cflag & PARENB) {
+               if (new->c_cflag & PARODD) {
+                       BT_DBG("Parity is ODD");
+                       parity = RFCOMM_RPN_PARITY_ODD;
+               } else {
+                       BT_DBG("Parity is EVEN");
+                       parity = RFCOMM_RPN_PARITY_EVEN;
+               }
+       } else {
+               BT_DBG("Parity is OFF");
+               parity = RFCOMM_RPN_PARITY_NONE;
+       }
+
+       /* Setting the x_on / x_off characters */
+       if (old->c_cc[VSTOP] != new->c_cc[VSTOP]) {
+               BT_DBG("XOFF custom");
+               x_on = new->c_cc[VSTOP];
+               changes |= RFCOMM_RPN_PM_XON;
+       } else {
+               BT_DBG("XOFF default");
+               x_on = RFCOMM_RPN_XON_CHAR;
+       }
+
+       if (old->c_cc[VSTART] != new->c_cc[VSTART]) {
+               BT_DBG("XON custom");
+               x_off = new->c_cc[VSTART];
+               changes |= RFCOMM_RPN_PM_XOFF;
+       } else {
+               BT_DBG("XON default");
+               x_off = RFCOMM_RPN_XOFF_CHAR;
+       }
+
+       /* Handle setting of stop bits */
+       if ((old->c_cflag & CSTOPB) != (new->c_cflag & CSTOPB))
+               changes |= RFCOMM_RPN_PM_STOP;
+
+       /* POSIX does not support 1.5 stop bits and RFCOMM does not
+        * support 2 stop bits. So a request for 2 stop bits gets
+        * translated to 1.5 stop bits */
+       if (new->c_cflag & CSTOPB) {
+               stop_bits = RFCOMM_RPN_STOP_15;
+       } else {
+               stop_bits = RFCOMM_RPN_STOP_1;
+       }
+
+       /* Handle number of data bits [5-8] */
+       if ((old->c_cflag & CSIZE) != (new->c_cflag & CSIZE)) 
+               changes |= RFCOMM_RPN_PM_DATA;
+
+       switch (new->c_cflag & CSIZE) {
+       case CS5:
+               data_bits = RFCOMM_RPN_DATA_5;
+               break;
+       case CS6:
+               data_bits = RFCOMM_RPN_DATA_6;
+               break;
+       case CS7:
+               data_bits = RFCOMM_RPN_DATA_7;
+               break;
+       case CS8:
+               data_bits = RFCOMM_RPN_DATA_8;
+               break;
+       default:
+               data_bits = RFCOMM_RPN_DATA_8;
+               break;
+       }
+
+       /* Handle baudrate settings */
+       if (old_baud_rate != new_baud_rate)
+               changes |= RFCOMM_RPN_PM_BITRATE;
 
-       /* handle turning off CRTSCTS */
-       if ((old->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
-               BT_DBG("turning off CRTSCTS");
+       switch (new_baud_rate) {
+       case 2400:
+               baud = RFCOMM_RPN_BR_2400;
+               break;
+       case 4800:
+               baud = RFCOMM_RPN_BR_4800;
+               break;
+       case 7200:
+               baud = RFCOMM_RPN_BR_7200;
+               break;
+       case 9600:
+               baud = RFCOMM_RPN_BR_9600;
+               break;
+       case 19200: 
+               baud = RFCOMM_RPN_BR_19200;
+               break;
+       case 38400:
+               baud = RFCOMM_RPN_BR_38400;
+               break;
+       case 57600:
+               baud = RFCOMM_RPN_BR_57600;
+               break;
+       case 115200:
+               baud = RFCOMM_RPN_BR_115200;
+               break;
+       case 230400:
+               baud = RFCOMM_RPN_BR_230400;
+               break;
+       default:
+               /* 9600 is standard accordinag to the RFCOMM specification */
+               baud = RFCOMM_RPN_BR_9600;
+               break;
+       
        }
+
+       if (changes)
+               rfcomm_send_rpn(dev->dlc->session, 1, dev->dlc->dlci, baud,
+                               data_bits, stop_bits, parity,
+                               RFCOMM_RPN_FLOW_NONE, x_on, x_off, changes);
+
+       return;
 }
 
 static void rfcomm_tty_throttle(struct tty_struct *tty)
@@ -761,7 +889,7 @@ static void rfcomm_tty_throttle(struct tty_struct *tty)
        struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
 
        BT_DBG("tty %p dev %p", tty, dev);
-       
+
        rfcomm_dlc_throttle(dev->dlc);
 }
 
@@ -770,7 +898,7 @@ static void rfcomm_tty_unthrottle(struct tty_struct *tty)
        struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
 
        BT_DBG("tty %p dev %p", tty, dev);
-       
+
        rfcomm_dlc_unthrottle(dev->dlc);
 }
 
@@ -841,35 +969,35 @@ static int rfcomm_tty_tiocmget(struct tty_struct *tty, struct file *filp)
 
 static int rfcomm_tty_tiocmset(struct tty_struct *tty, struct file *filp, unsigned int set, unsigned int clear)
 {
-       struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-       struct rfcomm_dlc *dlc = dev->dlc;
-       u8 v24_sig;
+       struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+       struct rfcomm_dlc *dlc = dev->dlc;
+       u8 v24_sig;
 
        BT_DBG("tty %p dev %p set 0x%02x clear 0x%02x", tty, dev, set, clear);
 
-       rfcomm_dlc_get_modem_status(dlc, &v24_sig);
-
-       if (set & TIOCM_DSR || set & TIOCM_DTR)
-               v24_sig |= RFCOMM_V24_RTC;
-       if (set & TIOCM_RTS || set & TIOCM_CTS)
-               v24_sig |= RFCOMM_V24_RTR;
-       if (set & TIOCM_RI)
-               v24_sig |= RFCOMM_V24_IC;
-       if (set & TIOCM_CD)
-               v24_sig |= RFCOMM_V24_DV;
-
-       if (clear & TIOCM_DSR || clear & TIOCM_DTR)
-               v24_sig &= ~RFCOMM_V24_RTC;
-       if (clear & TIOCM_RTS || clear & TIOCM_CTS)
-               v24_sig &= ~RFCOMM_V24_RTR;
-       if (clear & TIOCM_RI)
-               v24_sig &= ~RFCOMM_V24_IC;
-       if (clear & TIOCM_CD)
-               v24_sig &= ~RFCOMM_V24_DV;
-
-       rfcomm_dlc_set_modem_status(dlc, v24_sig);
-
-       return 0;
+       rfcomm_dlc_get_modem_status(dlc, &v24_sig);
+
+       if (set & TIOCM_DSR || set & TIOCM_DTR)
+               v24_sig |= RFCOMM_V24_RTC;
+       if (set & TIOCM_RTS || set & TIOCM_CTS)
+               v24_sig |= RFCOMM_V24_RTR;
+       if (set & TIOCM_RI)
+               v24_sig |= RFCOMM_V24_IC;
+       if (set & TIOCM_CD)
+               v24_sig |= RFCOMM_V24_DV;
+
+       if (clear & TIOCM_DSR || clear & TIOCM_DTR)
+               v24_sig &= ~RFCOMM_V24_RTC;
+       if (clear & TIOCM_RTS || clear & TIOCM_CTS)
+               v24_sig &= ~RFCOMM_V24_RTR;
+       if (clear & TIOCM_RI)
+               v24_sig &= ~RFCOMM_V24_IC;
+       if (clear & TIOCM_CD)
+               v24_sig &= ~RFCOMM_V24_DV;
+
+       rfcomm_dlc_set_modem_status(dlc, v24_sig);
+
+       return 0;
 }
 
 /* ---- TTY structure ---- */
index 746c11fc017e9b8e73320ac126e68a607d02e76a..ce7ab7dfa0b206f7ecfa3e76f15cbc0e71666f2d 100644 (file)
@@ -418,7 +418,7 @@ static struct proto sco_proto = {
        .obj_size       = sizeof(struct sco_pinfo)
 };
 
-static struct sock *sco_sock_alloc(struct socket *sock, int proto, int prio)
+static struct sock *sco_sock_alloc(struct socket *sock, int proto, unsigned int __nocast prio)
 {
        struct sock *sk;
 
index e6c2200b7ca3f75824f029810221fbcb86d39d5b..24396b914d11634f6e3fe26d9c3c06a9d94ded5c 100644 (file)
@@ -23,7 +23,7 @@
 #include <asm/atomic.h>
 #include "br_private.h"
 
-static kmem_cache_t *br_fdb_cache;
+static kmem_cache_t *br_fdb_cache __read_mostly;
 static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
                      const unsigned char *addr);
 
index 02c632b4d3259a97b91a972d97e882dc46959e09..c93d35ab95c02ac50bb7edfe139e2766a3bf6d2b 100644 (file)
@@ -23,10 +23,9 @@ static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr,
 {
        struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
 
-       if ((*pskb)->nfmark != info->mark) {
+       if ((*pskb)->nfmark != info->mark)
                (*pskb)->nfmark = info->mark;
-               (*pskb)->nfcache |= NFC_ALTERED;
-       }
+
        return info->target;
 }
 
index 01af4fcef26d0b6926604b2ba92a9d3f41e38bf5..aae26ae2e61f5ec990c0a7f5d23caeaa1e642e68 100644 (file)
@@ -78,8 +78,8 @@ static void ulog_send(unsigned int nlgroup)
        if (ub->qlen > 1)
                ub->lastnlh->nlmsg_type = NLMSG_DONE;
 
-       NETLINK_CB(ub->skb).dst_groups = 1 << nlgroup;
-       netlink_broadcast(ebtulognl, ub->skb, 0, 1 << nlgroup, GFP_ATOMIC);
+       NETLINK_CB(ub->skb).dst_group = nlgroup + 1;
+       netlink_broadcast(ebtulognl, ub->skb, 0, nlgroup + 1, GFP_ATOMIC);
 
        ub->qlen = 0;
        ub->skb = NULL;
@@ -162,7 +162,7 @@ static void ebt_ulog(const struct sk_buff *skb, unsigned int hooknr,
        pm->version = EBT_ULOG_VERSION;
        do_gettimeofday(&pm->stamp);
        if (ub->qlen == 1)
-               ub->skb->stamp = pm->stamp;
+               skb_set_timestamp(ub->skb, &pm->stamp);
        pm->data_len = copy_len;
        pm->mark = skb->nfmark;
        pm->hook = hooknr;
@@ -258,7 +258,8 @@ static int __init init(void)
                spin_lock_init(&ulog_buffers[i].lock);
        }
 
-       ebtulognl = netlink_kernel_create(NETLINK_NFLOG, NULL);
+       ebtulognl = netlink_kernel_create(NETLINK_NFLOG, EBT_ULOG_MAXNLGROUPS,
+                                         NULL, THIS_MODULE);
        if (!ebtulognl)
                ret = -ENOMEM;
        else if ((ret = ebt_register_watcher(&ulog)))
index f5f5e58943e862e0dde31729cb2a370060c3dd76..630da0f0579e5c3bf26cc5391ee49f7551f00882 100644 (file)
@@ -12,7 +12,6 @@ obj-y              += dev.o ethtool.o dev_mcast.o dst.o \
 
 obj-$(CONFIG_XFRM) += flow.o
 obj-$(CONFIG_SYSFS) += net-sysfs.o
-obj-$(CONFIG_NETFILTER) += netfilter.o
 obj-$(CONFIG_NET_DIVERT) += dv.o
 obj-$(CONFIG_NET_PKTGEN) += pktgen.o
 obj-$(CONFIG_NET_RADIO) += wireless.o
index fcee054b6f750a98063ec164f667e16d4043731e..da9bf71421a7ef98e6ade66ea8902d7cfaadb37f 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/inet.h>
-#include <linux/tcp.h>
 #include <linux/netdevice.h>
 #include <linux/rtnetlink.h>
 #include <linux/poll.h>
 
 #include <net/protocol.h>
 #include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/checksum.h>
 
+#include <net/checksum.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
 
 /*
  *     Is a socket 'connection oriented' ?
index faf59b02c4bf082179ff67477ab47719e885cafa..c01511e3d0c14a417f4ac025749405c061446e19 100644 (file)
@@ -267,10 +267,6 @@ void dev_add_pack(struct packet_type *pt)
        spin_unlock_bh(&ptype_lock);
 }
 
-extern void linkwatch_run_queue(void);
-
-
-
 /**
  *     __dev_remove_pack        - remove packet handler
  *     @pt: packet type declaration
@@ -1009,13 +1005,22 @@ void net_disable_timestamp(void)
        atomic_dec(&netstamp_needed);
 }
 
-static inline void net_timestamp(struct timeval *stamp)
+void __net_timestamp(struct sk_buff *skb)
+{
+       struct timeval tv;
+
+       do_gettimeofday(&tv);
+       skb_set_timestamp(skb, &tv);
+}
+EXPORT_SYMBOL(__net_timestamp);
+
+static inline void net_timestamp(struct sk_buff *skb)
 {
        if (atomic_read(&netstamp_needed))
-               do_gettimeofday(stamp);
+               __net_timestamp(skb);
        else {
-               stamp->tv_sec = 0;
-               stamp->tv_usec = 0;
+               skb->tstamp.off_sec = 0;
+               skb->tstamp.off_usec = 0;
        }
 }
 
@@ -1027,7 +1032,8 @@ static inline void net_timestamp(struct timeval *stamp)
 void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
 {
        struct packet_type *ptype;
-       net_timestamp(&skb->stamp);
+
+       net_timestamp(skb);
 
        rcu_read_lock();
        list_for_each_entry_rcu(ptype, &ptype_all, list) {
@@ -1058,7 +1064,7 @@ void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
 
                        skb2->h.raw = skb2->nh.raw;
                        skb2->pkt_type = PACKET_OUTGOING;
-                       ptype->func(skb2, skb->dev, ptype);
+                       ptype->func(skb2, skb->dev, ptype, skb->dev);
                }
        }
        rcu_read_unlock();
@@ -1123,8 +1129,6 @@ static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
 #define illegal_highdma(dev, skb)      (0)
 #endif
 
-extern void skb_release_data(struct sk_buff *);
-
 /* Keep head the same: replace data */
 int __skb_linearize(struct sk_buff *skb, unsigned int __nocast gfp_mask)
 {
@@ -1379,8 +1383,8 @@ int netif_rx(struct sk_buff *skb)
        if (netpoll_rx(skb))
                return NET_RX_DROP;
 
-       if (!skb->stamp.tv_sec)
-               net_timestamp(&skb->stamp);
+       if (!skb->tstamp.off_sec)
+               net_timestamp(skb);
 
        /*
         * The code is rearranged so that the path is the most
@@ -1425,14 +1429,14 @@ int netif_rx_ni(struct sk_buff *skb)
 
 EXPORT_SYMBOL(netif_rx_ni);
 
-static __inline__ void skb_bond(struct sk_buff *skb)
+static inline struct net_device *skb_bond(struct sk_buff *skb)
 {
        struct net_device *dev = skb->dev;
 
-       if (dev->master) {
-               skb->real_dev = skb->dev;
+       if (dev->master)
                skb->dev = dev->master;
-       }
+
+       return dev;
 }
 
 static void net_tx_action(struct softirq_action *h)
@@ -1482,10 +1486,11 @@ static void net_tx_action(struct softirq_action *h)
 }
 
 static __inline__ int deliver_skb(struct sk_buff *skb,
-                                 struct packet_type *pt_prev)
+                                 struct packet_type *pt_prev,
+                                 struct net_device *orig_dev)
 {
        atomic_inc(&skb->users);
-       return pt_prev->func(skb, skb->dev, pt_prev);
+       return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
 }
 
 #if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE)
@@ -1496,7 +1501,8 @@ struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
 void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
 
 static __inline__ int handle_bridge(struct sk_buff **pskb,
-                                   struct packet_type **pt_prev, int *ret)
+                                   struct packet_type **pt_prev, int *ret,
+                                   struct net_device *orig_dev)
 {
        struct net_bridge_port *port;
 
@@ -1505,14 +1511,14 @@ static __inline__ int handle_bridge(struct sk_buff **pskb,
                return 0;
 
        if (*pt_prev) {
-               *ret = deliver_skb(*pskb, *pt_prev);
+               *ret = deliver_skb(*pskb, *pt_prev, orig_dev);
                *pt_prev = NULL;
        } 
        
        return br_handle_frame_hook(port, pskb);
 }
 #else
-#define handle_bridge(skb, pt_prev, ret)       (0)
+#define handle_bridge(skb, pt_prev, ret, orig_dev)     (0)
 #endif
 
 #ifdef CONFIG_NET_CLS_ACT
@@ -1534,17 +1540,14 @@ static int ing_filter(struct sk_buff *skb)
                __u32 ttl = (__u32) G_TC_RTTL(skb->tc_verd);
                if (MAX_RED_LOOP < ttl++) {
                        printk("Redir loop detected Dropping packet (%s->%s)\n",
-                               skb->input_dev?skb->input_dev->name:"??",skb->dev->name);
+                               skb->input_dev->name, skb->dev->name);
                        return TC_ACT_SHOT;
                }
 
                skb->tc_verd = SET_TC_RTTL(skb->tc_verd,ttl);
 
                skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_INGRESS);
-               if (NULL == skb->input_dev) {
-                       skb->input_dev = skb->dev;
-                       printk("ing_filter:  fixed  %s out %s\n",skb->input_dev->name,skb->dev->name);
-               }
+
                spin_lock(&dev->ingress_lock);
                if ((q = dev->qdisc_ingress) != NULL)
                        result = q->enqueue(skb, q);
@@ -1559,6 +1562,7 @@ static int ing_filter(struct sk_buff *skb)
 int netif_receive_skb(struct sk_buff *skb)
 {
        struct packet_type *ptype, *pt_prev;
+       struct net_device *orig_dev;
        int ret = NET_RX_DROP;
        unsigned short type;
 
@@ -1566,10 +1570,13 @@ int netif_receive_skb(struct sk_buff *skb)
        if (skb->dev->poll && netpoll_rx(skb))
                return NET_RX_DROP;
 
-       if (!skb->stamp.tv_sec)
-               net_timestamp(&skb->stamp);
+       if (!skb->tstamp.off_sec)
+               net_timestamp(skb);
+
+       if (!skb->input_dev)
+               skb->input_dev = skb->dev;
 
-       skb_bond(skb);
+       orig_dev = skb_bond(skb);
 
        __get_cpu_var(netdev_rx_stat).total++;
 
@@ -1590,14 +1597,14 @@ int netif_receive_skb(struct sk_buff *skb)
        list_for_each_entry_rcu(ptype, &ptype_all, list) {
                if (!ptype->dev || ptype->dev == skb->dev) {
                        if (pt_prev) 
-                               ret = deliver_skb(skb, pt_prev);
+                               ret = deliver_skb(skb, pt_prev, orig_dev);
                        pt_prev = ptype;
                }
        }
 
 #ifdef CONFIG_NET_CLS_ACT
        if (pt_prev) {
-               ret = deliver_skb(skb, pt_prev);
+               ret = deliver_skb(skb, pt_prev, orig_dev);
                pt_prev = NULL; /* noone else should process this after*/
        } else {
                skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);
@@ -1616,7 +1623,7 @@ ncls:
 
        handle_diverter(skb);
 
-       if (handle_bridge(&skb, &pt_prev, &ret))
+       if (handle_bridge(&skb, &pt_prev, &ret, orig_dev))
                goto out;
 
        type = skb->protocol;
@@ -1624,13 +1631,13 @@ ncls:
                if (ptype->type == type &&
                    (!ptype->dev || ptype->dev == skb->dev)) {
                        if (pt_prev) 
-                               ret = deliver_skb(skb, pt_prev);
+                               ret = deliver_skb(skb, pt_prev, orig_dev);
                        pt_prev = ptype;
                }
        }
 
        if (pt_prev) {
-               ret = pt_prev->func(skb, skb->dev, pt_prev);
+               ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
        } else {
                kfree_skb(skb);
                /* Jamal, now you will not able to escape explaining
index a3eeb88e1c81fabe1eea26499958723955b08615..404b761e82ce8d712412717b58fb139478ed4b37 100644 (file)
@@ -81,6 +81,18 @@ int ethtool_op_set_tso(struct net_device *dev, u32 data)
        return 0;
 }
 
+int ethtool_op_get_perm_addr(struct net_device *dev, struct ethtool_perm_addr *addr, u8 *data)
+{
+       unsigned char len = dev->addr_len;
+       if ( addr->size < len )
+               return -ETOOSMALL;
+       
+       addr->size = len;
+       memcpy(data, dev->perm_addr, len);
+       return 0;
+}
+
 /* Handlers for each ethtool command */
 
 static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
@@ -683,6 +695,39 @@ static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
        return ret;
 }
 
+static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr)
+{
+       struct ethtool_perm_addr epaddr;
+       u8 *data;
+       int ret;
+
+       if (!dev->ethtool_ops->get_perm_addr)
+               return -EOPNOTSUPP;
+
+       if (copy_from_user(&epaddr,useraddr,sizeof(epaddr)))
+               return -EFAULT;
+
+       data = kmalloc(epaddr.size, GFP_USER);
+       if (!data)
+               return -ENOMEM;
+
+       ret = dev->ethtool_ops->get_perm_addr(dev,&epaddr,data);
+       if (ret)
+               return ret;
+
+       ret = -EFAULT;
+       if (copy_to_user(useraddr, &epaddr, sizeof(epaddr)))
+               goto out;
+       useraddr += sizeof(epaddr);
+       if (copy_to_user(useraddr, data, epaddr.size))
+               goto out;
+       ret = 0;
+
+ out:
+       kfree(data);
+       return ret;
+}
+
 /* The main entry point in this file.  Called from net/core/dev.c */
 
 int dev_ethtool(struct ifreq *ifr)
@@ -806,6 +851,9 @@ int dev_ethtool(struct ifreq *ifr)
        case ETHTOOL_GSTATS:
                rc = ethtool_get_stats(dev, useraddr);
                break;
+       case ETHTOOL_GPERMADDR:
+               rc = ethtool_get_perm_addr(dev, useraddr);
+               break;
        default:
                rc =  -EOPNOTSUPP;
        }
@@ -826,6 +874,7 @@ int dev_ethtool(struct ifreq *ifr)
 
 EXPORT_SYMBOL(dev_ethtool);
 EXPORT_SYMBOL(ethtool_op_get_link);
+EXPORT_SYMBOL_GPL(ethtool_op_get_perm_addr);
 EXPORT_SYMBOL(ethtool_op_get_sg);
 EXPORT_SYMBOL(ethtool_op_get_tso);
 EXPORT_SYMBOL(ethtool_op_get_tx_csum);
index cd91a24f97202f08944aea961153074d02b91449..079c2edff789e95ccc9fbcec96184c2eb2772e84 100644 (file)
@@ -182,7 +182,7 @@ int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen)
                                A = ntohl(*(u32 *)ptr);
                                continue;
                        }
-                       return 0;
+                       break;
                case BPF_LD|BPF_H|BPF_ABS:
                        k = fentry->k;
  load_h:
@@ -191,7 +191,7 @@ int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen)
                                A = ntohs(*(u16 *)ptr);
                                continue;
                        }
-                       return 0;
+                       break;
                case BPF_LD|BPF_B|BPF_ABS:
                        k = fentry->k;
 load_b:
@@ -200,7 +200,7 @@ load_b:
                                A = *(u8 *)ptr;
                                continue;
                        }
-                       return 0;
+                       break;
                case BPF_LD|BPF_W|BPF_LEN:
                        A = skb->len;
                        continue;
index f289570b15a3b3e3ba442d14ca6e133a8dff575e..7e95b39de9fdd369d0ae0011a42c993c554f37f2 100644 (file)
@@ -42,7 +42,7 @@ static DEFINE_PER_CPU(struct flow_cache_entry **, flow_tables) = { NULL };
 
 #define flow_table(cpu) (per_cpu(flow_tables, cpu))
 
-static kmem_cache_t *flow_cachep;
+static kmem_cache_t *flow_cachep __read_mostly;
 
 static int flow_lwm, flow_hwm;
 
index 1beb782ac41b6fe91eb91ddab02ef738ab7ee1d4..39fc55edf691aab986eb1cb53f134f65839c33a4 100644 (file)
@@ -1217,7 +1217,7 @@ static void neigh_proxy_process(unsigned long arg)
 
        while (skb != (struct sk_buff *)&tbl->proxy_queue) {
                struct sk_buff *back = skb;
-               long tdif = back->stamp.tv_usec - now;
+               long tdif = NEIGH_CB(back)->sched_next - now;
 
                skb = skb->next;
                if (tdif <= 0) {
@@ -1248,8 +1248,9 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
                kfree_skb(skb);
                return;
        }
-       skb->stamp.tv_sec  = LOCALLY_ENQUEUED;
-       skb->stamp.tv_usec = sched_next;
+
+       NEIGH_CB(skb)->sched_next = sched_next;
+       NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
 
        spin_lock(&tbl->proxy_queue.lock);
        if (del_timer(&tbl->proxy_timer)) {
@@ -2342,8 +2343,8 @@ void neigh_app_ns(struct neighbour *n)
        }
        nlh                        = (struct nlmsghdr *)skb->data;
        nlh->nlmsg_flags           = NLM_F_REQUEST;
-       NETLINK_CB(skb).dst_groups = RTMGRP_NEIGH;
-       netlink_broadcast(rtnl, skb, 0, RTMGRP_NEIGH, GFP_ATOMIC);
+       NETLINK_CB(skb).dst_group  = RTNLGRP_NEIGH;
+       netlink_broadcast(rtnl, skb, 0, RTNLGRP_NEIGH, GFP_ATOMIC);
 }
 
 static void neigh_app_notify(struct neighbour *n)
@@ -2360,8 +2361,8 @@ static void neigh_app_notify(struct neighbour *n)
                return;
        }
        nlh                        = (struct nlmsghdr *)skb->data;
-       NETLINK_CB(skb).dst_groups = RTMGRP_NEIGH;
-       netlink_broadcast(rtnl, skb, 0, RTMGRP_NEIGH, GFP_ATOMIC);
+       NETLINK_CB(skb).dst_group  = RTNLGRP_NEIGH;
+       netlink_broadcast(rtnl, skb, 0, RTNLGRP_NEIGH, GFP_ATOMIC);
 }
 
 #endif /* CONFIG_ARPD */
diff --git a/net/core/netfilter.c b/net/core/netfilter.c
deleted file mode 100644 (file)
index 076c156..0000000
+++ /dev/null
@@ -1,648 +0,0 @@
-/* netfilter.c: look after the filters for various protocols. 
- * Heavily influenced by the old firewall.c by David Bonn and Alan Cox.
- *
- * Thanks to Rob `CmdrTaco' Malda for not influencing this code in any
- * way.
- *
- * Rusty Russell (C)2000 -- This code is GPL.
- *
- * February 2000: Modified by James Morris to have 1 queue per protocol.
- * 15-Mar-2000:   Added NF_REPEAT --RR.
- * 08-May-2003:          Internal logging interface added by Jozsef Kadlecsik.
- */
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/netfilter.h>
-#include <net/protocol.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/wait.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/if.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
-#include <linux/icmp.h>
-#include <net/sock.h>
-#include <net/route.h>
-#include <linux/ip.h>
-
-/* In this code, we can be waiting indefinitely for userspace to
- * service a packet if a hook returns NF_QUEUE.  We could keep a count
- * of skbuffs queued for userspace, and not deregister a hook unless
- * this is zero, but that sucks.  Now, we simply check when the
- * packets come back: if the hook is gone, the packet is discarded. */
-#ifdef CONFIG_NETFILTER_DEBUG
-#define NFDEBUG(format, args...)  printk(format , ## args)
-#else
-#define NFDEBUG(format, args...)
-#endif
-
-/* Sockopts only registered and called from user context, so
-   net locking would be overkill.  Also, [gs]etsockopt calls may
-   sleep. */
-static DECLARE_MUTEX(nf_sockopt_mutex);
-
-struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
-static LIST_HEAD(nf_sockopts);
-static DEFINE_SPINLOCK(nf_hook_lock);
-
-/* 
- * A queue handler may be registered for each protocol.  Each is protected by
- * long term mutex.  The handler must provide an an outfn() to accept packets
- * for queueing and must reinject all packets it receives, no matter what.
- */
-static struct nf_queue_handler_t {
-       nf_queue_outfn_t outfn;
-       void *data;
-} queue_handler[NPROTO];
-static DEFINE_RWLOCK(queue_handler_lock);
-
-int nf_register_hook(struct nf_hook_ops *reg)
-{
-       struct list_head *i;
-
-       spin_lock_bh(&nf_hook_lock);
-       list_for_each(i, &nf_hooks[reg->pf][reg->hooknum]) {
-               if (reg->priority < ((struct nf_hook_ops *)i)->priority)
-                       break;
-       }
-       list_add_rcu(&reg->list, i->prev);
-       spin_unlock_bh(&nf_hook_lock);
-
-       synchronize_net();
-       return 0;
-}
-
-void nf_unregister_hook(struct nf_hook_ops *reg)
-{
-       spin_lock_bh(&nf_hook_lock);
-       list_del_rcu(&reg->list);
-       spin_unlock_bh(&nf_hook_lock);
-
-       synchronize_net();
-}
-
-/* Do exclusive ranges overlap? */
-static inline int overlap(int min1, int max1, int min2, int max2)
-{
-       return max1 > min2 && min1 < max2;
-}
-
-/* Functions to register sockopt ranges (exclusive). */
-int nf_register_sockopt(struct nf_sockopt_ops *reg)
-{
-       struct list_head *i;
-       int ret = 0;
-
-       if (down_interruptible(&nf_sockopt_mutex) != 0)
-               return -EINTR;
-
-       list_for_each(i, &nf_sockopts) {
-               struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i;
-               if (ops->pf == reg->pf
-                   && (overlap(ops->set_optmin, ops->set_optmax, 
-                               reg->set_optmin, reg->set_optmax)
-                       || overlap(ops->get_optmin, ops->get_optmax, 
-                                  reg->get_optmin, reg->get_optmax))) {
-                       NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n",
-                               ops->set_optmin, ops->set_optmax, 
-                               ops->get_optmin, ops->get_optmax, 
-                               reg->set_optmin, reg->set_optmax,
-                               reg->get_optmin, reg->get_optmax);
-                       ret = -EBUSY;
-                       goto out;
-               }
-       }
-
-       list_add(&reg->list, &nf_sockopts);
-out:
-       up(&nf_sockopt_mutex);
-       return ret;
-}
-
-void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
-{
-       /* No point being interruptible: we're probably in cleanup_module() */
- restart:
-       down(&nf_sockopt_mutex);
-       if (reg->use != 0) {
-               /* To be woken by nf_sockopt call... */
-               /* FIXME: Stuart Young's name appears gratuitously. */
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               reg->cleanup_task = current;
-               up(&nf_sockopt_mutex);
-               schedule();
-               goto restart;
-       }
-       list_del(&reg->list);
-       up(&nf_sockopt_mutex);
-}
-
-/* Call get/setsockopt() */
-static int nf_sockopt(struct sock *sk, int pf, int val, 
-                     char __user *opt, int *len, int get)
-{
-       struct list_head *i;
-       struct nf_sockopt_ops *ops;
-       int ret;
-
-       if (down_interruptible(&nf_sockopt_mutex) != 0)
-               return -EINTR;
-
-       list_for_each(i, &nf_sockopts) {
-               ops = (struct nf_sockopt_ops *)i;
-               if (ops->pf == pf) {
-                       if (get) {
-                               if (val >= ops->get_optmin
-                                   && val < ops->get_optmax) {
-                                       ops->use++;
-                                       up(&nf_sockopt_mutex);
-                                       ret = ops->get(sk, val, opt, len);
-                                       goto out;
-                               }
-                       } else {
-                               if (val >= ops->set_optmin
-                                   && val < ops->set_optmax) {
-                                       ops->use++;
-                                       up(&nf_sockopt_mutex);
-                                       ret = ops->set(sk, val, opt, *len);
-                                       goto out;
-                               }
-                       }
-               }
-       }
-       up(&nf_sockopt_mutex);
-       return -ENOPROTOOPT;
-       
- out:
-       down(&nf_sockopt_mutex);
-       ops->use--;
-       if (ops->cleanup_task)
-               wake_up_process(ops->cleanup_task);
-       up(&nf_sockopt_mutex);
-       return ret;
-}
-
-int nf_setsockopt(struct sock *sk, int pf, int val, char __user *opt,
-                 int len)
-{
-       return nf_sockopt(sk, pf, val, opt, &len, 0);
-}
-
-int nf_getsockopt(struct sock *sk, int pf, int val, char __user *opt, int *len)
-{
-       return nf_sockopt(sk, pf, val, opt, len, 1);
-}
-
-static unsigned int nf_iterate(struct list_head *head,
-                              struct sk_buff **skb,
-                              int hook,
-                              const struct net_device *indev,
-                              const struct net_device *outdev,
-                              struct list_head **i,
-                              int (*okfn)(struct sk_buff *),
-                              int hook_thresh)
-{
-       unsigned int verdict;
-
-       /*
-        * The caller must not block between calls to this
-        * function because of risk of continuing from deleted element.
-        */
-       list_for_each_continue_rcu(*i, head) {
-               struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;
-
-               if (hook_thresh > elem->priority)
-                       continue;
-
-               /* Optimization: we don't need to hold module
-                   reference here, since function can't sleep. --RR */
-               verdict = elem->hook(hook, skb, indev, outdev, okfn);
-               if (verdict != NF_ACCEPT) {
-#ifdef CONFIG_NETFILTER_DEBUG
-                       if (unlikely(verdict > NF_MAX_VERDICT)) {
-                               NFDEBUG("Evil return from %p(%u).\n",
-                                       elem->hook, hook);
-                               continue;
-                       }
-#endif
-                       if (verdict != NF_REPEAT)
-                               return verdict;
-                       *i = (*i)->prev;
-               }
-       }
-       return NF_ACCEPT;
-}
-
-int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
-{      
-       int ret;
-
-       write_lock_bh(&queue_handler_lock);
-       if (queue_handler[pf].outfn)
-               ret = -EBUSY;
-       else {
-               queue_handler[pf].outfn = outfn;
-               queue_handler[pf].data = data;
-               ret = 0;
-       }
-       write_unlock_bh(&queue_handler_lock);
-
-       return ret;
-}
-
-/* The caller must flush their queue before this */
-int nf_unregister_queue_handler(int pf)
-{
-       write_lock_bh(&queue_handler_lock);
-       queue_handler[pf].outfn = NULL;
-       queue_handler[pf].data = NULL;
-       write_unlock_bh(&queue_handler_lock);
-       
-       return 0;
-}
-
-/* 
- * Any packet that leaves via this function must come back 
- * through nf_reinject().
- */
-static int nf_queue(struct sk_buff *skb, 
-                   struct list_head *elem, 
-                   int pf, unsigned int hook,
-                   struct net_device *indev,
-                   struct net_device *outdev,
-                   int (*okfn)(struct sk_buff *))
-{
-       int status;
-       struct nf_info *info;
-#ifdef CONFIG_BRIDGE_NETFILTER
-       struct net_device *physindev = NULL;
-       struct net_device *physoutdev = NULL;
-#endif
-
-       /* QUEUE == DROP if noone is waiting, to be safe. */
-       read_lock(&queue_handler_lock);
-       if (!queue_handler[pf].outfn) {
-               read_unlock(&queue_handler_lock);
-               kfree_skb(skb);
-               return 1;
-       }
-
-       info = kmalloc(sizeof(*info), GFP_ATOMIC);
-       if (!info) {
-               if (net_ratelimit())
-                       printk(KERN_ERR "OOM queueing packet %p\n",
-                              skb);
-               read_unlock(&queue_handler_lock);
-               kfree_skb(skb);
-               return 1;
-       }
-
-       *info = (struct nf_info) { 
-               (struct nf_hook_ops *)elem, pf, hook, indev, outdev, okfn };
-
-       /* If it's going away, ignore hook. */
-       if (!try_module_get(info->elem->owner)) {
-               read_unlock(&queue_handler_lock);
-               kfree(info);
-               return 0;
-       }
-
-       /* Bump dev refs so they don't vanish while packet is out */
-       if (indev) dev_hold(indev);
-       if (outdev) dev_hold(outdev);
-
-#ifdef CONFIG_BRIDGE_NETFILTER
-       if (skb->nf_bridge) {
-               physindev = skb->nf_bridge->physindev;
-               if (physindev) dev_hold(physindev);
-               physoutdev = skb->nf_bridge->physoutdev;
-               if (physoutdev) dev_hold(physoutdev);
-       }
-#endif
-
-       status = queue_handler[pf].outfn(skb, info, queue_handler[pf].data);
-       read_unlock(&queue_handler_lock);
-
-       if (status < 0) {
-               /* James M doesn't say fuck enough. */
-               if (indev) dev_put(indev);
-               if (outdev) dev_put(outdev);
-#ifdef CONFIG_BRIDGE_NETFILTER
-               if (physindev) dev_put(physindev);
-               if (physoutdev) dev_put(physoutdev);
-#endif
-               module_put(info->elem->owner);
-               kfree(info);
-               kfree_skb(skb);
-               return 1;
-       }
-       return 1;
-}
-
-/* Returns 1 if okfn() needs to be executed by the caller,
- * -EPERM for NF_DROP, 0 otherwise. */
-int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
-                struct net_device *indev,
-                struct net_device *outdev,
-                int (*okfn)(struct sk_buff *),
-                int hook_thresh)
-{
-       struct list_head *elem;
-       unsigned int verdict;
-       int ret = 0;
-
-       /* We may already have this, but read-locks nest anyway */
-       rcu_read_lock();
-
-       elem = &nf_hooks[pf][hook];
-next_hook:
-       verdict = nf_iterate(&nf_hooks[pf][hook], pskb, hook, indev,
-                            outdev, &elem, okfn, hook_thresh);
-       if (verdict == NF_ACCEPT || verdict == NF_STOP) {
-               ret = 1;
-               goto unlock;
-       } else if (verdict == NF_DROP) {
-               kfree_skb(*pskb);
-               ret = -EPERM;
-       } else if (verdict == NF_QUEUE) {
-               NFDEBUG("nf_hook: Verdict = QUEUE.\n");
-               if (!nf_queue(*pskb, elem, pf, hook, indev, outdev, okfn))
-                       goto next_hook;
-       }
-unlock:
-       rcu_read_unlock();
-       return ret;
-}
-
-void nf_reinject(struct sk_buff *skb, struct nf_info *info,
-                unsigned int verdict)
-{
-       struct list_head *elem = &info->elem->list;
-       struct list_head *i;
-
-       rcu_read_lock();
-
-       /* Release those devices we held, or Alexey will kill me. */
-       if (info->indev) dev_put(info->indev);
-       if (info->outdev) dev_put(info->outdev);
-#ifdef CONFIG_BRIDGE_NETFILTER
-       if (skb->nf_bridge) {
-               if (skb->nf_bridge->physindev)
-                       dev_put(skb->nf_bridge->physindev);
-               if (skb->nf_bridge->physoutdev)
-                       dev_put(skb->nf_bridge->physoutdev);
-       }
-#endif
-
-       /* Drop reference to owner of hook which queued us. */
-       module_put(info->elem->owner);
-
-       list_for_each_rcu(i, &nf_hooks[info->pf][info->hook]) {
-               if (i == elem) 
-                       break;
-       }
-  
-       if (elem == &nf_hooks[info->pf][info->hook]) {
-               /* The module which sent it to userspace is gone. */
-               NFDEBUG("%s: module disappeared, dropping packet.\n",
-                       __FUNCTION__);
-               verdict = NF_DROP;
-       }
-
-       /* Continue traversal iff userspace said ok... */
-       if (verdict == NF_REPEAT) {
-               elem = elem->prev;
-               verdict = NF_ACCEPT;
-       }
-
-       if (verdict == NF_ACCEPT) {
-       next_hook:
-               verdict = nf_iterate(&nf_hooks[info->pf][info->hook],
-                                    &skb, info->hook, 
-                                    info->indev, info->outdev, &elem,
-                                    info->okfn, INT_MIN);
-       }
-
-       switch (verdict) {
-       case NF_ACCEPT:
-               info->okfn(skb);
-               break;
-
-       case NF_QUEUE:
-               if (!nf_queue(skb, elem, info->pf, info->hook, 
-                             info->indev, info->outdev, info->okfn))
-                       goto next_hook;
-               break;
-       }
-       rcu_read_unlock();
-
-       if (verdict == NF_DROP)
-               kfree_skb(skb);
-
-       kfree(info);
-       return;
-}
-
-#ifdef CONFIG_INET
-/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
-int ip_route_me_harder(struct sk_buff **pskb)
-{
-       struct iphdr *iph = (*pskb)->nh.iph;
-       struct rtable *rt;
-       struct flowi fl = {};
-       struct dst_entry *odst;
-       unsigned int hh_len;
-
-       /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
-        * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook.
-        */
-       if (inet_addr_type(iph->saddr) == RTN_LOCAL) {
-               fl.nl_u.ip4_u.daddr = iph->daddr;
-               fl.nl_u.ip4_u.saddr = iph->saddr;
-               fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
-               fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0;
-#ifdef CONFIG_IP_ROUTE_FWMARK
-               fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark;
-#endif
-               fl.proto = iph->protocol;
-               if (ip_route_output_key(&rt, &fl) != 0)
-                       return -1;
-
-               /* Drop old route. */
-               dst_release((*pskb)->dst);
-               (*pskb)->dst = &rt->u.dst;
-       } else {
-               /* non-local src, find valid iif to satisfy
-                * rp-filter when calling ip_route_input. */
-               fl.nl_u.ip4_u.daddr = iph->saddr;
-               if (ip_route_output_key(&rt, &fl) != 0)
-                       return -1;
-
-               odst = (*pskb)->dst;
-               if (ip_route_input(*pskb, iph->daddr, iph->saddr,
-                                  RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
-                       dst_release(&rt->u.dst);
-                       return -1;
-               }
-               dst_release(&rt->u.dst);
-               dst_release(odst);
-       }
-       
-       if ((*pskb)->dst->error)
-               return -1;
-
-       /* Change in oif may mean change in hh_len. */
-       hh_len = (*pskb)->dst->dev->hard_header_len;
-       if (skb_headroom(*pskb) < hh_len) {
-               struct sk_buff *nskb;
-
-               nskb = skb_realloc_headroom(*pskb, hh_len);
-               if (!nskb) 
-                       return -1;
-               if ((*pskb)->sk)
-                       skb_set_owner_w(nskb, (*pskb)->sk);
-               kfree_skb(*pskb);
-               *pskb = nskb;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL(ip_route_me_harder);
-
-int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
-{
-       struct sk_buff *nskb;
-
-       if (writable_len > (*pskb)->len)
-               return 0;
-
-       /* Not exclusive use of packet?  Must copy. */
-       if (skb_shared(*pskb) || skb_cloned(*pskb))
-               goto copy_skb;
-
-       return pskb_may_pull(*pskb, writable_len);
-
-copy_skb:
-       nskb = skb_copy(*pskb, GFP_ATOMIC);
-       if (!nskb)
-               return 0;
-       BUG_ON(skb_is_nonlinear(nskb));
-
-       /* Rest of kernel will get very unhappy if we pass it a
-          suddenly-orphaned skbuff */
-       if ((*pskb)->sk)
-               skb_set_owner_w(nskb, (*pskb)->sk);
-       kfree_skb(*pskb);
-       *pskb = nskb;
-       return 1;
-}
-EXPORT_SYMBOL(skb_ip_make_writable);
-#endif /*CONFIG_INET*/
-
-/* Internal logging interface, which relies on the real 
-   LOG target modules */
-
-#define NF_LOG_PREFIXLEN               128
-
-static nf_logfn *nf_logging[NPROTO]; /* = NULL */
-static int reported = 0;
-static DEFINE_SPINLOCK(nf_log_lock);
-
-int nf_log_register(int pf, nf_logfn *logfn)
-{
-       int ret = -EBUSY;
-
-       /* Any setup of logging members must be done before
-        * substituting pointer. */
-       spin_lock(&nf_log_lock);
-       if (!nf_logging[pf]) {
-               rcu_assign_pointer(nf_logging[pf], logfn);
-               ret = 0;
-       }
-       spin_unlock(&nf_log_lock);
-       return ret;
-}              
-
-void nf_log_unregister(int pf, nf_logfn *logfn)
-{
-       spin_lock(&nf_log_lock);
-       if (nf_logging[pf] == logfn)
-               nf_logging[pf] = NULL;
-       spin_unlock(&nf_log_lock);
-
-       /* Give time to concurrent readers. */
-       synchronize_net();
-}              
-
-void nf_log_packet(int pf,
-                  unsigned int hooknum,
-                  const struct sk_buff *skb,
-                  const struct net_device *in,
-                  const struct net_device *out,
-                  const char *fmt, ...)
-{
-       va_list args;
-       char prefix[NF_LOG_PREFIXLEN];
-       nf_logfn *logfn;
-       
-       rcu_read_lock();
-       logfn = rcu_dereference(nf_logging[pf]);
-       if (logfn) {
-               va_start(args, fmt);
-               vsnprintf(prefix, sizeof(prefix), fmt, args);
-               va_end(args);
-               /* We must read logging before nf_logfn[pf] */
-               logfn(hooknum, skb, in, out, prefix);
-       } else if (!reported) {
-               printk(KERN_WARNING "nf_log_packet: can\'t log yet, "
-                      "no backend logging module loaded in!\n");
-               reported++;
-       }
-       rcu_read_unlock();
-}
-EXPORT_SYMBOL(nf_log_register);
-EXPORT_SYMBOL(nf_log_unregister);
-EXPORT_SYMBOL(nf_log_packet);
-
-/* This does not belong here, but locally generated errors need it if connection
-   tracking in use: without this, connection may not be in hash table, and hence
-   manufactured ICMP or RST packets will not be associated with it. */
-void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *);
-
-void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb)
-{
-       void (*attach)(struct sk_buff *, struct sk_buff *);
-
-       if (skb->nfct && (attach = ip_ct_attach) != NULL) {
-               mb(); /* Just to be sure: must be read before executing this */
-               attach(new, skb);
-       }
-}
-
-void __init netfilter_init(void)
-{
-       int i, h;
-
-       for (i = 0; i < NPROTO; i++) {
-               for (h = 0; h < NF_MAX_HOOKS; h++)
-                       INIT_LIST_HEAD(&nf_hooks[i][h]);
-       }
-}
-
-EXPORT_SYMBOL(ip_ct_attach);
-EXPORT_SYMBOL(nf_ct_attach);
-EXPORT_SYMBOL(nf_getsockopt);
-EXPORT_SYMBOL(nf_hook_slow);
-EXPORT_SYMBOL(nf_hooks);
-EXPORT_SYMBOL(nf_register_hook);
-EXPORT_SYMBOL(nf_register_queue_handler);
-EXPORT_SYMBOL(nf_register_sockopt);
-EXPORT_SYMBOL(nf_reinject);
-EXPORT_SYMBOL(nf_setsockopt);
-EXPORT_SYMBOL(nf_unregister_hook);
-EXPORT_SYMBOL(nf_unregister_queue_handler);
-EXPORT_SYMBOL(nf_unregister_sockopt);
index bb55675f0685e1a52accb47c734d1b2f8eb6368d..b8203de5ff073c4e3bda5166ef1542b793141a0c 100644 (file)
@@ -32,7 +32,6 @@
  * Further increasing requires to change hash table size.
  */
 int sysctl_max_syn_backlog = 256;
-EXPORT_SYMBOL(sysctl_max_syn_backlog);
 
 int reqsk_queue_alloc(struct request_sock_queue *queue,
                      const int nr_table_entries)
@@ -53,6 +52,8 @@ int reqsk_queue_alloc(struct request_sock_queue *queue,
        get_random_bytes(&lopt->hash_rnd, sizeof(lopt->hash_rnd));
        rwlock_init(&queue->syn_wait_lock);
        queue->rskq_accept_head = queue->rskq_accept_head = NULL;
+       queue->rskq_defer_accept = 0;
+       lopt->nr_table_entries = nr_table_entries;
 
        write_lock_bh(&queue->syn_wait_lock);
        queue->listen_opt = lopt;
@@ -62,3 +63,28 @@ int reqsk_queue_alloc(struct request_sock_queue *queue,
 }
 
 EXPORT_SYMBOL(reqsk_queue_alloc);
+
+void reqsk_queue_destroy(struct request_sock_queue *queue)
+{
+       /* make all the listen_opt local to us */
+       struct listen_sock *lopt = reqsk_queue_yank_listen_sk(queue);
+
+       if (lopt->qlen != 0) {
+               int i;
+
+               for (i = 0; i < lopt->nr_table_entries; i++) {
+                       struct request_sock *req;
+
+                       while ((req = lopt->syn_table[i]) != NULL) {
+                               lopt->syn_table[i] = req->dl_next;
+                               lopt->qlen--;
+                               reqsk_free(req);
+                       }
+               }
+       }
+
+       BUG_TRAP(lopt->qlen == 0);
+       kfree(lopt);
+}
+
+EXPORT_SYMBOL(reqsk_queue_destroy);
index 4b1bb30e6381fb9abf82b596852ec89b3c36827c..9bed7569ce3f30b7f13f522f973aa45e73a2840f 100644 (file)
@@ -148,7 +148,7 @@ int rtnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo)
 {
        int err = 0;
 
-       NETLINK_CB(skb).dst_groups = group;
+       NETLINK_CB(skb).dst_group = group;
        if (echo)
                atomic_inc(&skb->users);
        netlink_broadcast(rtnl, skb, pid, group, GFP_KERNEL);
@@ -458,8 +458,8 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
                kfree_skb(skb);
                return;
        }
-       NETLINK_CB(skb).dst_groups = RTMGRP_LINK;
-       netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_KERNEL);
+       NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
+       netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_KERNEL);
 }
 
 static int rtnetlink_done(struct netlink_callback *cb)
@@ -708,7 +708,8 @@ void __init rtnetlink_init(void)
        if (!rta_buf)
                panic("rtnetlink_init: cannot allocate rta_buf\n");
 
-       rtnl = netlink_kernel_create(NETLINK_ROUTE, rtnetlink_rcv);
+       rtnl = netlink_kernel_create(NETLINK_ROUTE, RTNLGRP_MAX, rtnetlink_rcv,
+                                    THIS_MODULE);
        if (rtnl == NULL)
                panic("rtnetlink_init: cannot initialize rtnetlink\n");
        netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV);
index 7eab867ede5938a4fb698df683876937ce106364..f80a28785610d62c180313310a47d2ad0fa11736 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-static kmem_cache_t *skbuff_head_cache;
+static kmem_cache_t *skbuff_head_cache __read_mostly;
+static kmem_cache_t *skbuff_fclone_cache __read_mostly;
+
+struct timeval __read_mostly skb_tv_base;
 
 /*
  *     Keep out-of-line to prevent kernel bloat.
@@ -118,7 +121,7 @@ void skb_under_panic(struct sk_buff *skb, int sz, void *here)
  */
 
 /**
- *     alloc_skb       -       allocate a network buffer
+ *     __alloc_skb     -       allocate a network buffer
  *     @size: size to allocate
  *     @gfp_mask: allocation mask
  *
@@ -129,14 +132,20 @@ void skb_under_panic(struct sk_buff *skb, int sz, void *here)
  *     Buffers may only be allocated from interrupts using a @gfp_mask of
  *     %GFP_ATOMIC.
  */
-struct sk_buff *alloc_skb(unsigned int size, unsigned int __nocast gfp_mask)
+struct sk_buff *__alloc_skb(unsigned int size, unsigned int __nocast gfp_mask,
+                           int fclone)
 {
        struct sk_buff *skb;
        u8 *data;
 
        /* Get the HEAD */
-       skb = kmem_cache_alloc(skbuff_head_cache,
-                              gfp_mask & ~__GFP_DMA);
+       if (fclone)
+               skb = kmem_cache_alloc(skbuff_fclone_cache,
+                                      gfp_mask & ~__GFP_DMA);
+       else
+               skb = kmem_cache_alloc(skbuff_head_cache,
+                                      gfp_mask & ~__GFP_DMA);
+
        if (!skb)
                goto out;
 
@@ -153,7 +162,15 @@ struct sk_buff *alloc_skb(unsigned int size, unsigned int __nocast gfp_mask)
        skb->data = data;
        skb->tail = data;
        skb->end  = data + size;
+       if (fclone) {
+               struct sk_buff *child = skb + 1;
+               atomic_t *fclone_ref = (atomic_t *) (child + 1);
 
+               skb->fclone = SKB_FCLONE_ORIG;
+               atomic_set(fclone_ref, 1);
+
+               child->fclone = SKB_FCLONE_UNAVAILABLE;
+       }
        atomic_set(&(skb_shinfo(skb)->dataref), 1);
        skb_shinfo(skb)->nr_frags  = 0;
        skb_shinfo(skb)->tso_size = 0;
@@ -266,8 +283,34 @@ void skb_release_data(struct sk_buff *skb)
  */
 void kfree_skbmem(struct sk_buff *skb)
 {
+       struct sk_buff *other;
+       atomic_t *fclone_ref;
+
        skb_release_data(skb);
-       kmem_cache_free(skbuff_head_cache, skb);
+       switch (skb->fclone) {
+       case SKB_FCLONE_UNAVAILABLE:
+               kmem_cache_free(skbuff_head_cache, skb);
+               break;
+
+       case SKB_FCLONE_ORIG:
+               fclone_ref = (atomic_t *) (skb + 2);
+               if (atomic_dec_and_test(fclone_ref))
+                       kmem_cache_free(skbuff_fclone_cache, skb);
+               break;
+
+       case SKB_FCLONE_CLONE:
+               fclone_ref = (atomic_t *) (skb + 1);
+               other = skb - 1;
+
+               /* The clone portion is available for
+                * fast-cloning again.
+                */
+               skb->fclone = SKB_FCLONE_UNAVAILABLE;
+
+               if (atomic_dec_and_test(fclone_ref))
+                       kmem_cache_free(skbuff_fclone_cache, other);
+               break;
+       };
 }
 
 /**
@@ -281,8 +324,6 @@ void kfree_skbmem(struct sk_buff *skb)
 
 void __kfree_skb(struct sk_buff *skb)
 {
-       BUG_ON(skb->list != NULL);
-
        dst_release(skb->dst);
 #ifdef CONFIG_XFRM
        secpath_put(skb->sp);
@@ -302,7 +343,6 @@ void __kfree_skb(struct sk_buff *skb)
        skb->tc_index = 0;
 #ifdef CONFIG_NET_CLS_ACT
        skb->tc_verd = 0;
-       skb->tc_classid = 0;
 #endif
 #endif
 
@@ -325,19 +365,27 @@ void __kfree_skb(struct sk_buff *skb)
 
 struct sk_buff *skb_clone(struct sk_buff *skb, unsigned int __nocast gfp_mask)
 {
-       struct sk_buff *n = kmem_cache_alloc(skbuff_head_cache, gfp_mask);
-
-       if (!n) 
-               return NULL;
+       struct sk_buff *n;
+
+       n = skb + 1;
+       if (skb->fclone == SKB_FCLONE_ORIG &&
+           n->fclone == SKB_FCLONE_UNAVAILABLE) {
+               atomic_t *fclone_ref = (atomic_t *) (n + 1);
+               n->fclone = SKB_FCLONE_CLONE;
+               atomic_inc(fclone_ref);
+       } else {
+               n = kmem_cache_alloc(skbuff_head_cache, gfp_mask);
+               if (!n)
+                       return NULL;
+               n->fclone = SKB_FCLONE_UNAVAILABLE;
+       }
 
 #define C(x) n->x = skb->x
 
        n->next = n->prev = NULL;
-       n->list = NULL;
        n->sk = NULL;
-       C(stamp);
+       C(tstamp);
        C(dev);
-       C(real_dev);
        C(h);
        C(nh);
        C(mac);
@@ -361,7 +409,6 @@ struct sk_buff *skb_clone(struct sk_buff *skb, unsigned int __nocast gfp_mask)
        n->destructor = NULL;
 #ifdef CONFIG_NETFILTER
        C(nfmark);
-       C(nfcache);
        C(nfct);
        nf_conntrack_get(skb->nfct);
        C(nfctinfo);
@@ -370,9 +417,6 @@ struct sk_buff *skb_clone(struct sk_buff *skb, unsigned int __nocast gfp_mask)
        nf_bridge_get(skb->nf_bridge);
 #endif
 #endif /*CONFIG_NETFILTER*/
-#if defined(CONFIG_HIPPI)
-       C(private);
-#endif
 #ifdef CONFIG_NET_SCHED
        C(tc_index);
 #ifdef CONFIG_NET_CLS_ACT
@@ -380,7 +424,6 @@ struct sk_buff *skb_clone(struct sk_buff *skb, unsigned int __nocast gfp_mask)
        n->tc_verd = CLR_TC_OK2MUNGE(n->tc_verd);
        n->tc_verd = CLR_TC_MUNGED(n->tc_verd);
        C(input_dev);
-       C(tc_classid);
 #endif
 
 #endif
@@ -404,10 +447,8 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
         */
        unsigned long offset = new->data - old->data;
 
-       new->list       = NULL;
        new->sk         = NULL;
        new->dev        = old->dev;
-       new->real_dev   = old->real_dev;
        new->priority   = old->priority;
        new->protocol   = old->protocol;
        new->dst        = dst_clone(old->dst);
@@ -419,12 +460,12 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
        new->mac.raw    = old->mac.raw + offset;
        memcpy(new->cb, old->cb, sizeof(old->cb));
        new->local_df   = old->local_df;
+       new->fclone     = SKB_FCLONE_UNAVAILABLE;
        new->pkt_type   = old->pkt_type;
-       new->stamp      = old->stamp;
+       new->tstamp     = old->tstamp;
        new->destructor = NULL;
 #ifdef CONFIG_NETFILTER
        new->nfmark     = old->nfmark;
-       new->nfcache    = old->nfcache;
        new->nfct       = old->nfct;
        nf_conntrack_get(old->nfct);
        new->nfctinfo   = old->nfctinfo;
@@ -1344,50 +1385,43 @@ void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)
        __skb_queue_tail(list, newsk);
        spin_unlock_irqrestore(&list->lock, flags);
 }
+
 /**
  *     skb_unlink      -       remove a buffer from a list
  *     @skb: buffer to remove
+ *     @list: list to use
  *
- *     Place a packet after a given packet in a list. The list locks are taken
- *     and this function is atomic with respect to other list locked calls
+ *     Remove a packet from a list. The list locks are taken and this
+ *     function is atomic with respect to other list locked calls
  *
- *     Works even without knowing the list it is sitting on, which can be
- *     handy at times. It also means that THE LIST MUST EXIST when you
- *     unlink. Thus a list must have its contents unlinked before it is
- *     destroyed.
+ *     You must know what list the SKB is on.
  */
-void skb_unlink(struct sk_buff *skb)
+void skb_unlink(struct sk_buff *skb, struct sk_buff_head *list)
 {
-       struct sk_buff_head *list = skb->list;
-
-       if (list) {
-               unsigned long flags;
+       unsigned long flags;
 
-               spin_lock_irqsave(&list->lock, flags);
-               if (skb->list == list)
-                       __skb_unlink(skb, skb->list);
-               spin_unlock_irqrestore(&list->lock, flags);
-       }
+       spin_lock_irqsave(&list->lock, flags);
+       __skb_unlink(skb, list);
+       spin_unlock_irqrestore(&list->lock, flags);
 }
 
-
 /**
  *     skb_append      -       append a buffer
  *     @old: buffer to insert after
  *     @newsk: buffer to insert
+ *     @list: list to use
  *
  *     Place a packet after a given packet in a list. The list locks are taken
  *     and this function is atomic with respect to other list locked calls.
  *     A buffer cannot be placed on two lists at the same time.
  */
-
-void skb_append(struct sk_buff *old, struct sk_buff *newsk)
+void skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&old->list->lock, flags);
-       __skb_append(old, newsk);
-       spin_unlock_irqrestore(&old->list->lock, flags);
+       spin_lock_irqsave(&list->lock, flags);
+       __skb_append(old, newsk, list);
+       spin_unlock_irqrestore(&list->lock, flags);
 }
 
 
@@ -1395,19 +1429,21 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
  *     skb_insert      -       insert a buffer
  *     @old: buffer to insert before
  *     @newsk: buffer to insert
+ *     @list: list to use
+ *
+ *     Place a packet before a given packet in a list. The list locks are
+ *     taken and this function is atomic with respect to other list locked
+ *     calls.
  *
- *     Place a packet before a given packet in a list. The list locks are taken
- *     and this function is atomic with respect to other list locked calls
  *     A buffer cannot be placed on two lists at the same time.
  */
-
-void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
+void skb_insert(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&old->list->lock, flags);
-       __skb_insert(newsk, old->prev, old, old->list);
-       spin_unlock_irqrestore(&old->list->lock, flags);
+       spin_lock_irqsave(&list->lock, flags);
+       __skb_insert(newsk, old->prev, old, list);
+       spin_unlock_irqrestore(&list->lock, flags);
 }
 
 #if 0
@@ -1663,12 +1699,23 @@ void __init skb_init(void)
                                              NULL, NULL);
        if (!skbuff_head_cache)
                panic("cannot create skbuff cache");
+
+       skbuff_fclone_cache = kmem_cache_create("skbuff_fclone_cache",
+                                               (2*sizeof(struct sk_buff)) +
+                                               sizeof(atomic_t),
+                                               0,
+                                               SLAB_HWCACHE_ALIGN,
+                                               NULL, NULL);
+       if (!skbuff_fclone_cache)
+               panic("cannot create skbuff cache");
+
+       do_gettimeofday(&skb_tv_base);
 }
 
 EXPORT_SYMBOL(___pskb_trim);
 EXPORT_SYMBOL(__kfree_skb);
 EXPORT_SYMBOL(__pskb_pull_tail);
-EXPORT_SYMBOL(alloc_skb);
+EXPORT_SYMBOL(__alloc_skb);
 EXPORT_SYMBOL(pskb_copy);
 EXPORT_SYMBOL(pskb_expand_head);
 EXPORT_SYMBOL(skb_checksum);
@@ -1696,3 +1743,4 @@ EXPORT_SYMBOL(skb_prepare_seq_read);
 EXPORT_SYMBOL(skb_seq_read);
 EXPORT_SYMBOL(skb_abort_seq_read);
 EXPORT_SYMBOL(skb_find_text);
+EXPORT_SYMBOL(skb_tv_base);
index 12f6d9a2a522c730ef1fbc268bcd50b6b28f6b9b..ac63b56e23b29c45113df81fa226bc2c9568d758 100644 (file)
@@ -260,7 +260,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                           
                        if (val > sysctl_wmem_max)
                                val = sysctl_wmem_max;
-
+set_sndbuf:
                        sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
                        if ((val * 2) < SOCK_MIN_SNDBUF)
                                sk->sk_sndbuf = SOCK_MIN_SNDBUF;
@@ -274,6 +274,13 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                        sk->sk_write_space(sk);
                        break;
 
+               case SO_SNDBUFFORCE:
+                       if (!capable(CAP_NET_ADMIN)) {
+                               ret = -EPERM;
+                               break;
+                       }
+                       goto set_sndbuf;
+
                case SO_RCVBUF:
                        /* Don't error on this BSD doesn't and if you think
                           about it this is right. Otherwise apps have to
@@ -282,7 +289,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                          
                        if (val > sysctl_rmem_max)
                                val = sysctl_rmem_max;
-
+set_rcvbuf:
                        sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
                        /* FIXME: is this lower bound the right one? */
                        if ((val * 2) < SOCK_MIN_RCVBUF)
@@ -291,6 +298,13 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                                sk->sk_rcvbuf = val * 2;
                        break;
 
+               case SO_RCVBUFFORCE:
+                       if (!capable(CAP_NET_ADMIN)) {
+                               ret = -EPERM;
+                               break;
+                       }
+                       goto set_rcvbuf;
+
                case SO_KEEPALIVE:
 #ifdef CONFIG_INET
                        if (sk->sk_protocol == IPPROTO_TCP)
@@ -327,11 +341,11 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                                sock_reset_flag(sk, SOCK_LINGER);
                        else {
 #if (BITS_PER_LONG == 32)
-                               if (ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ)
+                               if ((unsigned int)ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ)
                                        sk->sk_lingertime = MAX_SCHEDULE_TIMEOUT;
                                else
 #endif
-                                       sk->sk_lingertime = ling.l_linger * HZ;
+                                       sk->sk_lingertime = (unsigned int)ling.l_linger * HZ;
                                sock_set_flag(sk, SOCK_LINGER);
                        }
                        break;
@@ -686,6 +700,80 @@ void sk_free(struct sock *sk)
        module_put(owner);
 }
 
+struct sock *sk_clone(const struct sock *sk, const unsigned int __nocast priority)
+{
+       struct sock *newsk = sk_alloc(sk->sk_family, priority, sk->sk_prot, 0);
+
+       if (newsk != NULL) {
+               struct sk_filter *filter;
+
+               memcpy(newsk, sk, sk->sk_prot->obj_size);
+
+               /* SANITY */
+               sk_node_init(&newsk->sk_node);
+               sock_lock_init(newsk);
+               bh_lock_sock(newsk);
+
+               atomic_set(&newsk->sk_rmem_alloc, 0);
+               atomic_set(&newsk->sk_wmem_alloc, 0);
+               atomic_set(&newsk->sk_omem_alloc, 0);
+               skb_queue_head_init(&newsk->sk_receive_queue);
+               skb_queue_head_init(&newsk->sk_write_queue);
+
+               rwlock_init(&newsk->sk_dst_lock);
+               rwlock_init(&newsk->sk_callback_lock);
+
+               newsk->sk_dst_cache     = NULL;
+               newsk->sk_wmem_queued   = 0;
+               newsk->sk_forward_alloc = 0;
+               newsk->sk_send_head     = NULL;
+               newsk->sk_backlog.head  = newsk->sk_backlog.tail = NULL;
+               newsk->sk_userlocks     = sk->sk_userlocks & ~SOCK_BINDPORT_LOCK;
+
+               sock_reset_flag(newsk, SOCK_DONE);
+               skb_queue_head_init(&newsk->sk_error_queue);
+
+               filter = newsk->sk_filter;
+               if (filter != NULL)
+                       sk_filter_charge(newsk, filter);
+
+               if (unlikely(xfrm_sk_clone_policy(newsk))) {
+                       /* It is still raw copy of parent, so invalidate
+                        * destructor and make plain sk_free() */
+                       newsk->sk_destruct = NULL;
+                       sk_free(newsk);
+                       newsk = NULL;
+                       goto out;
+               }
+
+               newsk->sk_err      = 0;
+               newsk->sk_priority = 0;
+               atomic_set(&newsk->sk_refcnt, 2);
+
+               /*
+                * Increment the counter in the same struct proto as the master
+                * sock (sk_refcnt_debug_inc uses newsk->sk_prot->socks, that
+                * is the same as sk->sk_prot->socks, as this field was copied
+                * with memcpy).
+                *
+                * This _changes_ the previous behaviour, where
+                * tcp_create_openreq_child always was incrementing the
+                * equivalent to tcp_prot->socks (inet_sock_nr), so this have
+                * to be taken into account in all callers. -acme
+                */
+               sk_refcnt_debug_inc(newsk);
+               newsk->sk_socket = NULL;
+               newsk->sk_sleep  = NULL;
+
+               if (newsk->sk_prot->sockets_allocated)
+                       atomic_inc(newsk->sk_prot->sockets_allocated);
+       }
+out:
+       return newsk;
+}
+
+EXPORT_SYMBOL_GPL(sk_clone);
+
 void __init sk_init(void)
 {
        if (num_physpages <= 4096) {
@@ -1353,11 +1441,7 @@ void sk_common_release(struct sock *sk)
 
        xfrm_sk_free_policy(sk);
 
-#ifdef INET_REFCNT_DEBUG
-       if (atomic_read(&sk->sk_refcnt) != 1)
-               printk(KERN_DEBUG "Destruction of the socket %p delayed, c=%d\n",
-                      sk, atomic_read(&sk->sk_refcnt));
-#endif
+       sk_refcnt_debug_release(sk);
        sock_put(sk);
 }
 
@@ -1368,7 +1452,8 @@ static LIST_HEAD(proto_list);
 
 int proto_register(struct proto *prot, int alloc_slab)
 {
-       char *request_sock_slab_name;
+       char *request_sock_slab_name = NULL;
+       char *timewait_sock_slab_name;
        int rc = -ENOBUFS;
 
        if (alloc_slab) {
@@ -1399,6 +1484,23 @@ int proto_register(struct proto *prot, int alloc_slab)
                                goto out_free_request_sock_slab_name;
                        }
                }
+
+               if (prot->twsk_obj_size) {
+                       static const char mask[] = "tw_sock_%s";
+
+                       timewait_sock_slab_name = kmalloc(strlen(prot->name) + sizeof(mask) - 1, GFP_KERNEL);
+
+                       if (timewait_sock_slab_name == NULL)
+                               goto out_free_request_sock_slab;
+
+                       sprintf(timewait_sock_slab_name, mask, prot->name);
+                       prot->twsk_slab = kmem_cache_create(timewait_sock_slab_name,
+                                                           prot->twsk_obj_size,
+                                                           0, SLAB_HWCACHE_ALIGN,
+                                                           NULL, NULL);
+                       if (prot->twsk_slab == NULL)
+                               goto out_free_timewait_sock_slab_name;
+               }
        }
 
        write_lock(&proto_list_lock);
@@ -1407,6 +1509,13 @@ int proto_register(struct proto *prot, int alloc_slab)
        rc = 0;
 out:
        return rc;
+out_free_timewait_sock_slab_name:
+       kfree(timewait_sock_slab_name);
+out_free_request_sock_slab:
+       if (prot->rsk_prot && prot->rsk_prot->slab) {
+               kmem_cache_destroy(prot->rsk_prot->slab);
+               prot->rsk_prot->slab = NULL;
+       }
 out_free_request_sock_slab_name:
        kfree(request_sock_slab_name);
 out_free_sock_slab:
@@ -1420,6 +1529,8 @@ EXPORT_SYMBOL(proto_register);
 void proto_unregister(struct proto *prot)
 {
        write_lock(&proto_list_lock);
+       list_del(&prot->node);
+       write_unlock(&proto_list_lock);
 
        if (prot->slab != NULL) {
                kmem_cache_destroy(prot->slab);
@@ -1434,8 +1545,13 @@ void proto_unregister(struct proto *prot)
                prot->rsk_prot->slab = NULL;
        }
 
-       list_del(&prot->node);
-       write_unlock(&proto_list_lock);
+       if (prot->twsk_slab != NULL) {
+               const char *name = kmem_cache_name(prot->twsk_slab);
+
+               kmem_cache_destroy(prot->twsk_slab);
+               kfree(name);
+               prot->twsk_slab = NULL;
+       }
 }
 
 EXPORT_SYMBOL(proto_unregister);
@@ -1602,8 +1718,8 @@ EXPORT_SYMBOL(sock_wfree);
 EXPORT_SYMBOL(sock_wmalloc);
 EXPORT_SYMBOL(sock_i_uid);
 EXPORT_SYMBOL(sock_i_ino);
-#ifdef CONFIG_SYSCTL
 EXPORT_SYMBOL(sysctl_optmem_max);
+#ifdef CONFIG_SYSCTL
 EXPORT_SYMBOL(sysctl_rmem_max);
 EXPORT_SYMBOL(sysctl_wmem_max);
 #endif
index 8f817ad9f54629f61dcd5dc54115a04bf527d0f7..2f278c8e474370e422bdcc5b66b8c3fa16a42ca3 100644 (file)
@@ -9,23 +9,18 @@
 #include <linux/sysctl.h>
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/socket.h>
+#include <net/sock.h>
 
 #ifdef CONFIG_SYSCTL
 
 extern int netdev_max_backlog;
-extern int netdev_budget;
 extern int weight_p;
-extern int net_msg_cost;
-extern int net_msg_burst;
 
 extern __u32 sysctl_wmem_max;
 extern __u32 sysctl_rmem_max;
-extern __u32 sysctl_wmem_default;
-extern __u32 sysctl_rmem_default;
 
 extern int sysctl_core_destroy_delay;
-extern int sysctl_optmem_max;
-extern int sysctl_somaxconn;
 
 #ifdef CONFIG_NET_DIVERT
 extern char sysctl_divert_version[];
index 88eb8b68e26b2c21b18a6e5f1256f24d6104d36c..7b5970fc9e407f7886332cba4d95b8ee3cf2c011 100644 (file)
@@ -16,7 +16,9 @@
 #include <linux/module.h>
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
+#include <linux/inet.h>
 #include <linux/mm.h>
+#include <linux/net.h>
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/random.h>
index 3ff5639c0b7886f77a92e42047733d6822db5e5c..d17f1583ea3e00150424839b4254b709cf48ac8f 100644 (file)
  *     o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus
  * Based on patch from Pavel Roskin <proski@gnu.org> :
  *     o Fix kernel data leak to user space in private handler handling
+ *
+ * v7 - 18.3.05 - Jean II
+ *     o Remove (struct iw_point *)->pointer from events and streams
+ *     o Remove spy_offset from struct iw_handler_def
+ *     o Start deprecating dev->get_wireless_stats, output a warning
+ *     o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless
+ *     o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats)
  */
 
 /***************************** INCLUDES *****************************/
@@ -446,10 +453,14 @@ static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
           (dev->wireless_handlers->get_wireless_stats != NULL))
                return dev->wireless_handlers->get_wireless_stats(dev);
 
-       /* Old location, will be phased out in next WE */
-       return (dev->get_wireless_stats ?
-               dev->get_wireless_stats(dev) :
-               (struct iw_statistics *) NULL);
+       /* Old location, field to be removed in next WE */
+       if(dev->get_wireless_stats) {
+               printk(KERN_DEBUG "%s (WE) : Driver using old /proc/net/wireless support, please fix driver !\n",
+                      dev->name);
+               return dev->get_wireless_stats(dev);
+       }
+       /* Not found */
+       return (struct iw_statistics *) NULL;
 }
 
 /* ---------------------------------------------------------------- */
@@ -541,16 +552,18 @@ static __inline__ void wireless_seq_printf_stats(struct seq_file *seq,
                           dev->name, stats->status, stats->qual.qual,
                           stats->qual.updated & IW_QUAL_QUAL_UPDATED
                           ? '.' : ' ',
-                          ((__u8) stats->qual.level),
+                          ((__s32) stats->qual.level) - 
+                          ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
                           stats->qual.updated & IW_QUAL_LEVEL_UPDATED
                           ? '.' : ' ',
-                          ((__u8) stats->qual.noise),
+                          ((__s32) stats->qual.noise) - 
+                          ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
                           stats->qual.updated & IW_QUAL_NOISE_UPDATED
                           ? '.' : ' ',
                           stats->discard.nwid, stats->discard.code,
                           stats->discard.fragment, stats->discard.retries,
                           stats->discard.misc, stats->miss.beacon);
-               stats->qual.updated = 0;
+               stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
        }
 }
 
@@ -571,10 +584,6 @@ static int wireless_seq_show(struct seq_file *seq, void *v)
        return 0;
 }
 
-extern void *dev_seq_start(struct seq_file *seq, loff_t *pos);
-extern void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos);
-extern void dev_seq_stop(struct seq_file *seq, void *v);
-
 static struct seq_operations wireless_seq_ops = {
        .start = dev_seq_start,
        .next  = dev_seq_next,
@@ -597,6 +606,7 @@ static struct file_operations wireless_seq_fops = {
 
 int __init wireless_proc_init(void)
 {
+       /* Create /proc/net/wireless entry */
        if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops))
                return -ENOMEM;
 
@@ -631,9 +641,9 @@ static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
                                sizeof(struct iw_statistics)))
                        return -EFAULT;
 
-               /* Check if we need to clear the update flag */
+               /* Check if we need to clear the updated flag */
                if(wrq->u.data.flags != 0)
-                       stats->qual.updated = 0;
+                       stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
                return 0;
        } else
                return -EOPNOTSUPP;
@@ -1144,8 +1154,8 @@ static inline void rtmsg_iwinfo(struct net_device *       dev,
                kfree_skb(skb);
                return;
        }
-       NETLINK_CB(skb).dst_groups = RTMGRP_LINK;
-       netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC);
+       NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
+       netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_ATOMIC);
 }
 #endif /* WE_EVENT_NETLINK */
 
@@ -1165,10 +1175,11 @@ void wireless_send_event(struct net_device *    dev,
        struct iw_event  *event;                /* Mallocated whole event */
        int event_len;                          /* Its size */
        int hdr_len;                            /* Size of the event header */
+       int wrqu_off = 0;                       /* Offset in wrqu */
        /* Don't "optimise" the following variable, it will crash */
        unsigned        cmd_index;              /* *MUST* be unsigned */
 
-       /* Get the description of the IOCTL */
+       /* Get the description of the Event */
        if(cmd <= SIOCIWLAST) {
                cmd_index = cmd - SIOCIWFIRST;
                if(cmd_index < standard_ioctl_num)
@@ -1211,6 +1222,8 @@ void wireless_send_event(struct net_device *      dev,
                /* Calculate extra_len - extra is NULL for restricted events */
                if(extra != NULL)
                        extra_len = wrqu->data.length * descr->token_size;
+               /* Always at an offset in wrqu */
+               wrqu_off = IW_EV_POINT_OFF;
 #ifdef WE_EVENT_DEBUG
                printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len);
 #endif /* WE_EVENT_DEBUG */
@@ -1221,7 +1234,7 @@ void wireless_send_event(struct net_device *      dev,
        event_len = hdr_len + extra_len;
 
 #ifdef WE_EVENT_DEBUG
-       printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len);
+       printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, wrqu_off %d, event_len %d\n", dev->name, cmd, hdr_len, wrqu_off, event_len);
 #endif /* WE_EVENT_DEBUG */
 
        /* Create temporary buffer to hold the event */
@@ -1232,7 +1245,7 @@ void wireless_send_event(struct net_device *      dev,
        /* Fill event */
        event->len = event_len;
        event->cmd = cmd;
-       memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN);
+       memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
        if(extra != NULL)
                memcpy(((char *) event) + hdr_len, extra, extra_len);
 
@@ -1253,7 +1266,7 @@ void wireless_send_event(struct net_device *      dev,
  * Now, the driver can delegate this task to Wireless Extensions.
  * It needs to use those standard spy iw_handler in struct iw_handler_def,
  * push data to us via wireless_spy_update() and include struct iw_spy_data
- * in its private part (and advertise it in iw_handler_def->spy_offset).
+ * in its private part (and export it in net_device->wireless_data->spy_data).
  * One of the main advantage of centralising spy support here is that
  * it becomes much easier to improve and extend it without having to touch
  * the drivers. One example is the addition of the Spy-Threshold events.
@@ -1270,10 +1283,7 @@ static inline struct iw_spy_data * get_spydata(struct net_device *dev)
        /* This is the new way */
        if(dev->wireless_data)
                return(dev->wireless_data->spy_data);
-
-       /* This is the old way. Doesn't work for multi-headed drivers.
-        * It will be removed in the next version of WE. */
-       return (dev->priv + dev->wireless_handlers->spy_offset);
+       return NULL;
 }
 
 /*------------------------------------------------------------------*/
@@ -1288,10 +1298,6 @@ int iw_handler_set_spy(struct net_device *       dev,
        struct iw_spy_data *    spydata = get_spydata(dev);
        struct sockaddr *       address = (struct sockaddr *) extra;
 
-       if(!dev->wireless_data)
-               /* Help user know that driver needs updating */
-               printk(KERN_DEBUG "%s (WE) : Driver using old/buggy spy support, please fix driver !\n",
-                      dev->name);
        /* Make sure driver is not buggy or using the old API */
        if(!spydata)
                return -EOPNOTSUPP;
@@ -1322,7 +1328,7 @@ int iw_handler_set_spy(struct net_device *        dev,
                       sizeof(struct iw_quality) * IW_MAX_SPY);
 
 #ifdef WE_SPY_DEBUG
-               printk(KERN_DEBUG "iw_handler_set_spy() :  offset %ld, spydata %p, num %d\n", dev->wireless_handlers->spy_offset, spydata, wrqu->data.length);
+               printk(KERN_DEBUG "iw_handler_set_spy() :  wireless_data %p, spydata %p, num %d\n", dev->wireless_data, spydata, wrqu->data.length);
                for (i = 0; i < wrqu->data.length; i++)
                        printk(KERN_DEBUG
                               "%02X:%02X:%02X:%02X:%02X:%02X \n",
@@ -1375,7 +1381,7 @@ int iw_handler_get_spy(struct net_device *        dev,
                       sizeof(struct iw_quality) * spydata->spy_number);
        /* Reset updated flags. */
        for(i = 0; i < spydata->spy_number; i++)
-               spydata->spy_stat[i].updated = 0;
+               spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
        return 0;
 }
 
@@ -1490,7 +1496,7 @@ void wireless_spy_update(struct net_device *      dev,
                return;
 
 #ifdef WE_SPY_DEBUG
-       printk(KERN_DEBUG "wireless_spy_update() :  offset %ld, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_handlers->spy_offset, spydata, address[0], address[1], address[2], address[3], address[4], address[5]);
+       printk(KERN_DEBUG "wireless_spy_update() :  wireless_data %p, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_data, spydata, address[0], address[1], address[2], address[3], address[4], address[5]);
 #endif /* WE_SPY_DEBUG */
 
        /* Update all records that match */
diff --git a/net/dccp/Kconfig b/net/dccp/Kconfig
new file mode 100644 (file)
index 0000000..187ac18
--- /dev/null
@@ -0,0 +1,50 @@
+menu "DCCP Configuration (EXPERIMENTAL)"
+       depends on INET && EXPERIMENTAL
+
+config IP_DCCP
+       tristate "The DCCP Protocol (EXPERIMENTAL)"
+       ---help---
+         Datagram Congestion Control Protocol
+
+         From draft-ietf-dccp-spec-11 <http://www.icir.org/kohler/dcp/draft-ietf-dccp-spec-11.txt>.
+
+         The Datagram Congestion Control Protocol (DCCP) is a transport
+         protocol that implements bidirectional, unicast connections of
+         congestion-controlled, unreliable datagrams. It should be suitable
+         for use by applications such as streaming media, Internet telephony,
+         and on-line games
+
+         To compile this protocol support as a module, choose M here: the
+         module will be called dccp.
+
+         If in doubt, say N.
+
+config INET_DCCP_DIAG
+       depends on IP_DCCP && INET_DIAG
+       def_tristate y if (IP_DCCP = y && INET_DIAG = y)
+       def_tristate m
+
+source "net/dccp/ccids/Kconfig"
+
+menu "DCCP Kernel Hacking"
+       depends on IP_DCCP && DEBUG_KERNEL=y
+
+config IP_DCCP_DEBUG
+       bool "DCCP debug messages"
+       ---help---
+         Only use this if you're hacking DCCP.
+
+         Just say N.
+
+config IP_DCCP_UNLOAD_HACK
+       depends on IP_DCCP=m && IP_DCCP_CCID3=m
+       bool "DCCP control sock unload hack"
+       ---help---
+         Enable this to be able to unload the dccp module when the it
+         has only one refcount held, the control sock one. Just execute
+         "rmmod dccp_ccid3 dccp"
+
+         Just say N.
+endmenu
+
+endmenu
diff --git a/net/dccp/Makefile b/net/dccp/Makefile
new file mode 100644 (file)
index 0000000..fb97bb0
--- /dev/null
@@ -0,0 +1,10 @@
+obj-$(CONFIG_IP_DCCP) += dccp.o
+
+dccp-y := ccid.o input.o ipv4.o minisocks.o options.o output.o proto.o \
+         timer.o
+
+obj-$(CONFIG_INET_DCCP_DIAG) += dccp_diag.o
+
+dccp_diag-y := diag.o
+
+obj-y += ccids/
diff --git a/net/dccp/ccid.c b/net/dccp/ccid.c
new file mode 100644 (file)
index 0000000..9d8fc0e
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ *  net/dccp/ccid.c
+ *
+ *  An implementation of the DCCP protocol
+ *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *  CCID infrastructure
+ *
+ *     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 "ccid.h"
+
+static struct ccid *ccids[CCID_MAX];
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
+static atomic_t ccids_lockct = ATOMIC_INIT(0);
+static DEFINE_SPINLOCK(ccids_lock);
+
+/*
+ * The strategy is: modifications ccids vector are short, do not sleep and
+ * veeery rare, but read access should be free of any exclusive locks.
+ */
+static void ccids_write_lock(void)
+{
+       spin_lock(&ccids_lock);
+       while (atomic_read(&ccids_lockct) != 0) {
+               spin_unlock(&ccids_lock);
+               yield();
+               spin_lock(&ccids_lock);
+       }
+}
+
+static inline void ccids_write_unlock(void)
+{
+       spin_unlock(&ccids_lock);
+}
+
+static inline void ccids_read_lock(void)
+{
+       atomic_inc(&ccids_lockct);
+       spin_unlock_wait(&ccids_lock);
+}
+
+static inline void ccids_read_unlock(void)
+{
+       atomic_dec(&ccids_lockct);
+}
+
+#else
+#define ccids_write_lock() do { } while(0)
+#define ccids_write_unlock() do { } while(0)
+#define ccids_read_lock() do { } while(0)
+#define ccids_read_unlock() do { } while(0)
+#endif
+
+int ccid_register(struct ccid *ccid)
+{
+       int err;
+
+       if (ccid->ccid_init == NULL)
+               return -1;
+
+       ccids_write_lock();
+       err = -EEXIST;
+       if (ccids[ccid->ccid_id] == NULL) {
+               ccids[ccid->ccid_id] = ccid;
+               err = 0;
+       }
+       ccids_write_unlock();
+       if (err == 0)
+               pr_info("CCID: Registered CCID %d (%s)\n",
+                       ccid->ccid_id, ccid->ccid_name);
+       return err;
+}
+
+EXPORT_SYMBOL_GPL(ccid_register);
+
+int ccid_unregister(struct ccid *ccid)
+{
+       ccids_write_lock();
+       ccids[ccid->ccid_id] = NULL;
+       ccids_write_unlock();
+       pr_info("CCID: Unregistered CCID %d (%s)\n",
+               ccid->ccid_id, ccid->ccid_name);
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(ccid_unregister);
+
+struct ccid *ccid_init(unsigned char id, struct sock *sk)
+{
+       struct ccid *ccid;
+
+#ifdef CONFIG_KMOD
+       if (ccids[id] == NULL)
+               request_module("net-dccp-ccid-%d", id);
+#endif
+       ccids_read_lock();
+
+       ccid = ccids[id];
+       if (ccid == NULL)
+               goto out;
+
+       if (!try_module_get(ccid->ccid_owner))
+               goto out_err;
+
+       if (ccid->ccid_init(sk) != 0)
+               goto out_module_put;
+out:
+       ccids_read_unlock();
+       return ccid;
+out_module_put:
+       module_put(ccid->ccid_owner);
+out_err:
+       ccid = NULL;
+       goto out;
+}
+
+EXPORT_SYMBOL_GPL(ccid_init);
+
+void ccid_exit(struct ccid *ccid, struct sock *sk)
+{
+       if (ccid == NULL)
+               return;
+
+       ccids_read_lock();
+
+       if (ccids[ccid->ccid_id] != NULL) {
+               if (ccid->ccid_exit != NULL)
+                       ccid->ccid_exit(sk);
+               module_put(ccid->ccid_owner);
+       }
+
+       ccids_read_unlock();
+}
+
+EXPORT_SYMBOL_GPL(ccid_exit);
diff --git a/net/dccp/ccid.h b/net/dccp/ccid.h
new file mode 100644 (file)
index 0000000..962f1e9
--- /dev/null
@@ -0,0 +1,180 @@
+#ifndef _CCID_H
+#define _CCID_H
+/*
+ *  net/dccp/ccid.h
+ *
+ *  An implementation of the DCCP protocol
+ *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *  CCID infrastructure
+ *
+ *     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 <net/sock.h>
+#include <linux/dccp.h>
+#include <linux/list.h>
+#include <linux/module.h>
+
+#define CCID_MAX 255
+
+struct ccid {
+       unsigned char   ccid_id;
+       const char      *ccid_name;
+       struct module   *ccid_owner;
+       int             (*ccid_init)(struct sock *sk);
+       void            (*ccid_exit)(struct sock *sk);
+       int             (*ccid_hc_rx_init)(struct sock *sk);
+       int             (*ccid_hc_tx_init)(struct sock *sk);
+       void            (*ccid_hc_rx_exit)(struct sock *sk);
+       void            (*ccid_hc_tx_exit)(struct sock *sk);
+       void            (*ccid_hc_rx_packet_recv)(struct sock *sk,
+                                                 struct sk_buff *skb);
+       int             (*ccid_hc_rx_parse_options)(struct sock *sk,
+                                                   unsigned char option,
+                                                   unsigned char len, u16 idx,
+                                                   unsigned char* value);
+       void            (*ccid_hc_rx_insert_options)(struct sock *sk,
+                                                    struct sk_buff *skb);
+       void            (*ccid_hc_tx_insert_options)(struct sock *sk,
+                                                    struct sk_buff *skb);
+       void            (*ccid_hc_tx_packet_recv)(struct sock *sk,
+                                                 struct sk_buff *skb);
+       int             (*ccid_hc_tx_parse_options)(struct sock *sk,
+                                                   unsigned char option,
+                                                   unsigned char len, u16 idx,
+                                                   unsigned char* value);
+       int             (*ccid_hc_tx_send_packet)(struct sock *sk,
+                                                 struct sk_buff *skb, int len);
+       void            (*ccid_hc_tx_packet_sent)(struct sock *sk, int more,
+                                                 int len);
+       void            (*ccid_hc_rx_get_info)(struct sock *sk,
+                                              struct tcp_info *info);
+       void            (*ccid_hc_tx_get_info)(struct sock *sk,
+                                              struct tcp_info *info);
+};
+
+extern int        ccid_register(struct ccid *ccid);
+extern int        ccid_unregister(struct ccid *ccid);
+
+extern struct ccid *ccid_init(unsigned char id, struct sock *sk);
+extern void       ccid_exit(struct ccid *ccid, struct sock *sk);
+
+static inline void __ccid_get(struct ccid *ccid)
+{
+       __module_get(ccid->ccid_owner);
+}
+
+static inline int ccid_hc_tx_send_packet(struct ccid *ccid, struct sock *sk,
+                                        struct sk_buff *skb, int len)
+{
+       int rc = 0;
+       if (ccid->ccid_hc_tx_send_packet != NULL)
+               rc = ccid->ccid_hc_tx_send_packet(sk, skb, len);
+       return rc;
+}
+
+static inline void ccid_hc_tx_packet_sent(struct ccid *ccid, struct sock *sk,
+                                         int more, int len)
+{
+       if (ccid->ccid_hc_tx_packet_sent != NULL)
+               ccid->ccid_hc_tx_packet_sent(sk, more, len);
+}
+
+static inline int ccid_hc_rx_init(struct ccid *ccid, struct sock *sk)
+{
+       int rc = 0;
+       if (ccid->ccid_hc_rx_init != NULL)
+               rc = ccid->ccid_hc_rx_init(sk);
+       return rc;
+}
+
+static inline int ccid_hc_tx_init(struct ccid *ccid, struct sock *sk)
+{
+       int rc = 0;
+       if (ccid->ccid_hc_tx_init != NULL)
+               rc = ccid->ccid_hc_tx_init(sk);
+       return rc;
+}
+
+static inline void ccid_hc_rx_exit(struct ccid *ccid, struct sock *sk)
+{
+       if (ccid->ccid_hc_rx_exit != NULL &&
+           dccp_sk(sk)->dccps_hc_rx_ccid_private != NULL)
+               ccid->ccid_hc_rx_exit(sk);
+}
+
+static inline void ccid_hc_tx_exit(struct ccid *ccid, struct sock *sk)
+{
+       if (ccid->ccid_hc_tx_exit != NULL &&
+           dccp_sk(sk)->dccps_hc_tx_ccid_private != NULL)
+               ccid->ccid_hc_tx_exit(sk);
+}
+
+static inline void ccid_hc_rx_packet_recv(struct ccid *ccid, struct sock *sk,
+                                         struct sk_buff *skb)
+{
+       if (ccid->ccid_hc_rx_packet_recv != NULL)
+               ccid->ccid_hc_rx_packet_recv(sk, skb);
+}
+
+static inline void ccid_hc_tx_packet_recv(struct ccid *ccid, struct sock *sk,
+                                         struct sk_buff *skb)
+{
+       if (ccid->ccid_hc_tx_packet_recv != NULL)
+               ccid->ccid_hc_tx_packet_recv(sk, skb);
+}
+
+static inline int ccid_hc_tx_parse_options(struct ccid *ccid, struct sock *sk,
+                                          unsigned char option,
+                                          unsigned char len, u16 idx,
+                                          unsigned char* value)
+{
+       int rc = 0;
+       if (ccid->ccid_hc_tx_parse_options != NULL)
+               rc = ccid->ccid_hc_tx_parse_options(sk, option, len, idx,
+                                                   value);
+       return rc;
+}
+
+static inline int ccid_hc_rx_parse_options(struct ccid *ccid, struct sock *sk,
+                                          unsigned char option,
+                                          unsigned char len, u16 idx,
+                                          unsigned char* value)
+{
+       int rc = 0;
+       if (ccid->ccid_hc_rx_parse_options != NULL)
+               rc = ccid->ccid_hc_rx_parse_options(sk, option, len, idx, value);
+       return rc;
+}
+
+static inline void ccid_hc_tx_insert_options(struct ccid *ccid, struct sock *sk,
+                                            struct sk_buff *skb)
+{
+       if (ccid->ccid_hc_tx_insert_options != NULL)
+               ccid->ccid_hc_tx_insert_options(sk, skb);
+}
+
+static inline void ccid_hc_rx_insert_options(struct ccid *ccid, struct sock *sk,
+                                            struct sk_buff *skb)
+{
+       if (ccid->ccid_hc_rx_insert_options != NULL)
+               ccid->ccid_hc_rx_insert_options(sk, skb);
+}
+
+static inline void ccid_hc_rx_get_info(struct ccid *ccid, struct sock *sk,
+                                      struct tcp_info *info)
+{
+       if (ccid->ccid_hc_rx_get_info != NULL)
+               ccid->ccid_hc_rx_get_info(sk, info);
+}
+
+static inline void ccid_hc_tx_get_info(struct ccid *ccid, struct sock *sk,
+                                      struct tcp_info *info)
+{
+       if (ccid->ccid_hc_tx_get_info != NULL)
+               ccid->ccid_hc_tx_get_info(sk, info);
+}
+#endif /* _CCID_H */
diff --git a/net/dccp/ccids/Kconfig b/net/dccp/ccids/Kconfig
new file mode 100644 (file)
index 0000000..7684d83
--- /dev/null
@@ -0,0 +1,29 @@
+menu "DCCP CCIDs Configuration (EXPERIMENTAL)"
+       depends on IP_DCCP && EXPERIMENTAL
+
+config IP_DCCP_CCID3
+       tristate "CCID3 (TFRC) (EXPERIMENTAL)"
+       depends on IP_DCCP
+       ---help---
+         CCID 3 denotes TCP-Friendly Rate Control (TFRC), an equation-based
+         rate-controlled congestion control mechanism.  TFRC is designed to
+         be reasonably fair when competing for bandwidth with TCP-like flows,
+         where a flow is "reasonably fair" if its sending rate is generally
+         within a factor of two of the sending rate of a TCP flow under the
+         same conditions.  However, TFRC has a much lower variation of
+         throughput over time compared with TCP, which makes CCID 3 more
+         suitable than CCID 2 for applications such streaming media where a
+         relatively smooth sending rate is of importance.
+
+         CCID 3 is further described in [CCID 3 PROFILE]. The TFRC
+         congestion control algorithms were initially described in RFC 3448.
+
+         This text was extracted from draft-ietf-dccp-spec-11.txt.
+         
+         If in doubt, say M.
+
+config IP_DCCP_TFRC_LIB
+       depends on IP_DCCP_CCID3
+       def_tristate IP_DCCP_CCID3
+
+endmenu
diff --git a/net/dccp/ccids/Makefile b/net/dccp/ccids/Makefile
new file mode 100644 (file)
index 0000000..956f79f
--- /dev/null
@@ -0,0 +1,5 @@
+obj-$(CONFIG_IP_DCCP_CCID3) += dccp_ccid3.o
+
+dccp_ccid3-y := ccid3.o
+
+obj-y += lib/
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
new file mode 100644 (file)
index 0000000..7bf3b3a
--- /dev/null
@@ -0,0 +1,1221 @@
+/*
+ *  net/dccp/ccids/ccid3.c
+ *
+ *  Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand.
+ *  Copyright (c) 2005 Ian McDonald <iam4@cs.waikato.ac.nz>
+ *
+ *  An implementation of the DCCP protocol
+ *
+ *  This code has been developed by the University of Waikato WAND
+ *  research group. For further information please see http://www.wand.net.nz/
+ *
+ *  This code also uses code from Lulea University, rereleased as GPL by its
+ *  authors:
+ *  Copyright (c) 2003 Nils-Erik Mattsson, Joacim Haggmark, Magnus Erixzon
+ *
+ *  Changes to meet Linux coding standards, to make it meet latest ccid3 draft
+ *  and to make it work as a loadable module in the DCCP stack written by
+ *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>.
+ *
+ *  Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include "../ccid.h"
+#include "../dccp.h"
+#include "lib/packet_history.h"
+#include "lib/loss_interval.h"
+#include "lib/tfrc.h"
+#include "ccid3.h"
+
+/*
+ * Reason for maths with 10 here is to avoid 32 bit overflow when a is big.
+ */
+static inline u32 usecs_div(const u32 a, const u32 b)
+{
+       const u32 tmp = a * (USEC_PER_SEC / 10);
+       return b > 20 ? tmp / (b / 10) : tmp;
+}
+
+static int ccid3_debug;
+
+#ifdef CCID3_DEBUG
+#define ccid3_pr_debug(format, a...) \
+       do { if (ccid3_debug) \
+               printk(KERN_DEBUG "%s: " format, __FUNCTION__, ##a); \
+       } while (0)
+#else
+#define ccid3_pr_debug(format, a...)
+#endif
+
+static struct dccp_tx_hist *ccid3_tx_hist;
+static struct dccp_rx_hist *ccid3_rx_hist;
+static struct dccp_li_hist *ccid3_li_hist;
+
+static int ccid3_init(struct sock *sk)
+{
+       ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
+       return 0;
+}
+
+static void ccid3_exit(struct sock *sk)
+{
+       ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
+}
+
+/* TFRC sender states */
+enum ccid3_hc_tx_states {
+               TFRC_SSTATE_NO_SENT = 1,
+       TFRC_SSTATE_NO_FBACK,
+       TFRC_SSTATE_FBACK,
+       TFRC_SSTATE_TERM,
+};
+
+#ifdef CCID3_DEBUG
+static const char *ccid3_tx_state_name(enum ccid3_hc_tx_states state)
+{
+       static char *ccid3_state_names[] = {
+       [TFRC_SSTATE_NO_SENT]  = "NO_SENT",
+       [TFRC_SSTATE_NO_FBACK] = "NO_FBACK",
+       [TFRC_SSTATE_FBACK]    = "FBACK",
+       [TFRC_SSTATE_TERM]     = "TERM",
+       };
+
+       return ccid3_state_names[state];
+}
+#endif
+
+static inline void ccid3_hc_tx_set_state(struct sock *sk,
+                                        enum ccid3_hc_tx_states state)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+       enum ccid3_hc_tx_states oldstate = hctx->ccid3hctx_state;
+
+       ccid3_pr_debug("%s(%p) %-8.8s -> %s\n",
+                      dccp_role(sk), sk, ccid3_tx_state_name(oldstate),
+                      ccid3_tx_state_name(state));
+       WARN_ON(state == oldstate);
+       hctx->ccid3hctx_state = state;
+}
+
+/* Calculate new t_ipi (inter packet interval) by t_ipi = s / X_inst */
+static inline void ccid3_calc_new_t_ipi(struct ccid3_hc_tx_sock *hctx)
+{
+       /*
+        * If no feedback spec says t_ipi is 1 second (set elsewhere and then
+        * doubles after every no feedback timer (separate function)
+        */
+       if (hctx->ccid3hctx_state != TFRC_SSTATE_NO_FBACK)
+               hctx->ccid3hctx_t_ipi = usecs_div(hctx->ccid3hctx_s,
+                                                 hctx->ccid3hctx_x);
+}
+
+/* Calculate new delta by delta = min(t_ipi / 2, t_gran / 2) */
+static inline void ccid3_calc_new_delta(struct ccid3_hc_tx_sock *hctx)
+{
+       hctx->ccid3hctx_delta = min_t(u32, hctx->ccid3hctx_t_ipi / 2,
+                                          TFRC_OPSYS_HALF_TIME_GRAN);
+}
+
+/*
+ * Update X by
+ *    If (p > 0)
+ *       x_calc = calcX(s, R, p);
+ *       X = max(min(X_calc, 2 * X_recv), s / t_mbi);
+ *    Else
+ *       If (now - tld >= R)
+ *          X = max(min(2 * X, 2 * X_recv), s / R);
+ *          tld = now;
+ */ 
+static void ccid3_hc_tx_update_x(struct sock *sk)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+
+       /* To avoid large error in calcX */
+       if (hctx->ccid3hctx_p >= TFRC_SMALLEST_P) {
+               hctx->ccid3hctx_x_calc = tfrc_calc_x(hctx->ccid3hctx_s,
+                                                    hctx->ccid3hctx_rtt,
+                                                    hctx->ccid3hctx_p);
+               hctx->ccid3hctx_x = max_t(u32, min_t(u32, hctx->ccid3hctx_x_calc,
+                                                         2 * hctx->ccid3hctx_x_recv),
+                                              (hctx->ccid3hctx_s /
+                                               TFRC_MAX_BACK_OFF_TIME));
+       } else {
+               struct timeval now;
+
+               do_gettimeofday(&now);
+               if (timeval_delta(&now, &hctx->ccid3hctx_t_ld) >=
+                   hctx->ccid3hctx_rtt) {
+                       hctx->ccid3hctx_x = max_t(u32, min_t(u32, hctx->ccid3hctx_x_recv,
+                                                                 hctx->ccid3hctx_x) * 2,
+                                                      usecs_div(hctx->ccid3hctx_s,
+                                                                hctx->ccid3hctx_rtt));
+                       hctx->ccid3hctx_t_ld = now;
+               }
+       }
+}
+
+static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
+{
+       struct sock *sk = (struct sock *)data;
+       struct dccp_sock *dp = dccp_sk(sk);
+       unsigned long next_tmout = 0;
+       struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+
+       bh_lock_sock(sk);
+       if (sock_owned_by_user(sk)) {
+               /* Try again later. */
+               /* XXX: set some sensible MIB */
+               sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
+                              jiffies + HZ / 5);
+               goto out;
+       }
+
+       ccid3_pr_debug("%s, sk=%p, state=%s\n", dccp_role(sk), sk,
+                      ccid3_tx_state_name(hctx->ccid3hctx_state));
+       
+       switch (hctx->ccid3hctx_state) {
+       case TFRC_SSTATE_TERM:
+               goto out;
+       case TFRC_SSTATE_NO_FBACK:
+               /* Halve send rate */
+               hctx->ccid3hctx_x /= 2;
+               if (hctx->ccid3hctx_x < (hctx->ccid3hctx_s /
+                                        TFRC_MAX_BACK_OFF_TIME))
+                       hctx->ccid3hctx_x = (hctx->ccid3hctx_s /
+                                            TFRC_MAX_BACK_OFF_TIME);
+
+               ccid3_pr_debug("%s, sk=%p, state=%s, updated tx rate to %d "
+                              "bytes/s\n",
+                              dccp_role(sk), sk,
+                              ccid3_tx_state_name(hctx->ccid3hctx_state),
+                              hctx->ccid3hctx_x);
+               next_tmout = max_t(u32, 2 * usecs_div(hctx->ccid3hctx_s,
+                                                     hctx->ccid3hctx_x),
+                                       TFRC_INITIAL_TIMEOUT);
+               /*
+                * FIXME - not sure above calculation is correct. See section
+                * 5 of CCID3 11 should adjust tx_t_ipi and double that to
+                * achieve it really
+                */
+               break;
+       case TFRC_SSTATE_FBACK:
+               /*
+                * Check if IDLE since last timeout and recv rate is less than
+                * 4 packets per RTT
+                */
+               if (!hctx->ccid3hctx_idle ||
+                   (hctx->ccid3hctx_x_recv >=
+                    4 * usecs_div(hctx->ccid3hctx_s, hctx->ccid3hctx_rtt))) {
+                       ccid3_pr_debug("%s, sk=%p, state=%s, not idle\n",
+                                      dccp_role(sk), sk,
+                                      ccid3_tx_state_name(hctx->ccid3hctx_state));
+                       /* Halve sending rate */
+
+                       /*  If (X_calc > 2 * X_recv)
+                        *    X_recv = max(X_recv / 2, s / (2 * t_mbi));
+                        *  Else
+                        *    X_recv = X_calc / 4;
+                        */
+                       BUG_ON(hctx->ccid3hctx_p >= TFRC_SMALLEST_P &&
+                              hctx->ccid3hctx_x_calc == 0);
+
+                       /* check also if p is zero -> x_calc is infinity? */
+                       if (hctx->ccid3hctx_p < TFRC_SMALLEST_P ||
+                           hctx->ccid3hctx_x_calc > 2 * hctx->ccid3hctx_x_recv)
+                               hctx->ccid3hctx_x_recv = max_t(u32, hctx->ccid3hctx_x_recv / 2,
+                                                                   hctx->ccid3hctx_s / (2 * TFRC_MAX_BACK_OFF_TIME));
+                       else
+                               hctx->ccid3hctx_x_recv = hctx->ccid3hctx_x_calc / 4;
+
+                       /* Update sending rate */
+                       ccid3_hc_tx_update_x(sk);
+               }
+               /*
+                * Schedule no feedback timer to expire in
+                * max(4 * R, 2 * s / X)
+                */
+               next_tmout = max_t(u32, hctx->ccid3hctx_t_rto, 
+                                       2 * usecs_div(hctx->ccid3hctx_s,
+                                                     hctx->ccid3hctx_x));
+               break;
+       default:
+               printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n",
+                      __FUNCTION__, dccp_role(sk), sk, hctx->ccid3hctx_state);
+               dump_stack();
+               goto out;
+       }
+
+       sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer, 
+                     jiffies + max_t(u32, 1, usecs_to_jiffies(next_tmout)));
+       hctx->ccid3hctx_idle = 1;
+out:
+       bh_unlock_sock(sk);
+       sock_put(sk);
+}
+
+static int ccid3_hc_tx_send_packet(struct sock *sk,
+                                  struct sk_buff *skb, int len)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+       struct dccp_tx_hist_entry *new_packet;
+       struct timeval now;
+       long delay;
+       int rc = -ENOTCONN;
+
+       /* Check if pure ACK or Terminating*/
+
+       /*
+        * XXX: We only call this function for DATA and DATAACK, on, these
+        * packets can have zero length, but why the comment about "pure ACK"?
+        */
+       if (hctx == NULL || len == 0 ||
+           hctx->ccid3hctx_state == TFRC_SSTATE_TERM)
+               goto out;
+
+       /* See if last packet allocated was not sent */
+       new_packet = dccp_tx_hist_head(&hctx->ccid3hctx_hist);
+       if (new_packet == NULL || new_packet->dccphtx_sent) {
+               new_packet = dccp_tx_hist_entry_new(ccid3_tx_hist,
+                                                   SLAB_ATOMIC);
+
+               rc = -ENOBUFS;
+               if (new_packet == NULL) {
+                       ccid3_pr_debug("%s, sk=%p, not enough mem to add "
+                                      "to history, send refused\n",
+                                      dccp_role(sk), sk);
+                       goto out;
+               }
+
+               dccp_tx_hist_add_entry(&hctx->ccid3hctx_hist, new_packet);
+       }
+
+       do_gettimeofday(&now);
+
+       switch (hctx->ccid3hctx_state) {
+       case TFRC_SSTATE_NO_SENT:
+               ccid3_pr_debug("%s, sk=%p, first packet(%llu)\n",
+                              dccp_role(sk), sk, dp->dccps_gss);
+
+               hctx->ccid3hctx_no_feedback_timer.function = ccid3_hc_tx_no_feedback_timer;
+               hctx->ccid3hctx_no_feedback_timer.data     = (unsigned long)sk;
+               sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
+                              jiffies + usecs_to_jiffies(TFRC_INITIAL_TIMEOUT));
+               hctx->ccid3hctx_last_win_count   = 0;
+               hctx->ccid3hctx_t_last_win_count = now;
+               ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK);
+               hctx->ccid3hctx_t_ipi = TFRC_INITIAL_TIMEOUT;
+
+               /* Set nominal send time for initial packet */
+               hctx->ccid3hctx_t_nom = now;
+               timeval_add_usecs(&hctx->ccid3hctx_t_nom,
+                                 hctx->ccid3hctx_t_ipi);
+               ccid3_calc_new_delta(hctx);
+               rc = 0;
+               break;
+       case TFRC_SSTATE_NO_FBACK:
+       case TFRC_SSTATE_FBACK:
+               delay = (timeval_delta(&now, &hctx->ccid3hctx_t_nom) -
+                        hctx->ccid3hctx_delta);
+               ccid3_pr_debug("send_packet delay=%ld\n", delay);
+               delay /= -1000;
+               /* divide by -1000 is to convert to ms and get sign right */
+               rc = delay > 0 ? delay : 0;
+               break;
+       default:
+               printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n",
+                      __FUNCTION__, dccp_role(sk), sk, hctx->ccid3hctx_state);
+               dump_stack();
+               rc = -EINVAL;
+               break;
+       }
+
+       /* Can we send? if so add options and add to packet history */
+       if (rc == 0)
+               new_packet->dccphtx_ccval =
+                       DCCP_SKB_CB(skb)->dccpd_ccval =
+                               hctx->ccid3hctx_last_win_count;
+out:
+       return rc;
+}
+
+static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, int len)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+       struct timeval now;
+
+       BUG_ON(hctx == NULL);
+
+       if (hctx->ccid3hctx_state == TFRC_SSTATE_TERM) {
+               ccid3_pr_debug("%s, sk=%p, while state is TFRC_SSTATE_TERM!\n",
+                              dccp_role(sk), sk);
+               return;
+       }
+
+       do_gettimeofday(&now);
+
+       /* check if we have sent a data packet */
+       if (len > 0) {
+               unsigned long quarter_rtt;
+               struct dccp_tx_hist_entry *packet;
+
+               packet = dccp_tx_hist_head(&hctx->ccid3hctx_hist);
+               if (packet == NULL) {
+                       printk(KERN_CRIT "%s: packet doesn't exists in "
+                                        "history!\n", __FUNCTION__);
+                       return;
+               }
+               if (packet->dccphtx_sent) {
+                       printk(KERN_CRIT "%s: no unsent packet in history!\n",
+                              __FUNCTION__);
+                       return;
+               }
+               packet->dccphtx_tstamp = now;
+               packet->dccphtx_seqno  = dp->dccps_gss;
+               /*
+                * Check if win_count have changed
+                * Algorithm in "8.1. Window Counter Valuer" in
+                * draft-ietf-dccp-ccid3-11.txt
+                */
+               quarter_rtt = timeval_delta(&now, &hctx->ccid3hctx_t_last_win_count);
+               if (likely(hctx->ccid3hctx_rtt > 8))
+                       quarter_rtt /= hctx->ccid3hctx_rtt / 4;
+
+               if (quarter_rtt > 0) {
+                       hctx->ccid3hctx_t_last_win_count = now;
+                       hctx->ccid3hctx_last_win_count   = (hctx->ccid3hctx_last_win_count +
+                                                           min_t(unsigned long, quarter_rtt, 5)) % 16;
+                       ccid3_pr_debug("%s, sk=%p, window changed from "
+                                      "%u to %u!\n",
+                                      dccp_role(sk), sk,
+                                      packet->dccphtx_ccval,
+                                      hctx->ccid3hctx_last_win_count);
+               }
+
+               hctx->ccid3hctx_idle = 0;
+               packet->dccphtx_rtt  = hctx->ccid3hctx_rtt;
+               packet->dccphtx_sent = 1;
+       } else
+               ccid3_pr_debug("%s, sk=%p, seqno=%llu NOT inserted!\n",
+                              dccp_role(sk), sk, dp->dccps_gss);
+
+       switch (hctx->ccid3hctx_state) {
+       case TFRC_SSTATE_NO_SENT:
+               /* if first wasn't pure ack */
+               if (len != 0)
+                       printk(KERN_CRIT "%s: %s, First packet sent is noted "
+                                        "as a data packet\n",
+                              __FUNCTION__, dccp_role(sk));
+               return;
+       case TFRC_SSTATE_NO_FBACK:
+       case TFRC_SSTATE_FBACK:
+               if (len > 0) {
+                       hctx->ccid3hctx_t_nom = now;
+                       ccid3_calc_new_t_ipi(hctx);
+                       ccid3_calc_new_delta(hctx);
+                       timeval_add_usecs(&hctx->ccid3hctx_t_nom,
+                                         hctx->ccid3hctx_t_ipi);
+               }
+               break;
+       default:
+               printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n",
+                      __FUNCTION__, dccp_role(sk), sk, hctx->ccid3hctx_state);
+               dump_stack();
+               break;
+       }
+}
+
+static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+       struct ccid3_options_received *opt_recv;
+       struct dccp_tx_hist_entry *packet;
+       unsigned long next_tmout; 
+       u32 t_elapsed;
+       u32 pinv;
+       u32 x_recv;
+       u32 r_sample;
+
+       if (hctx == NULL)
+               return;
+
+       if (hctx->ccid3hctx_state == TFRC_SSTATE_TERM) {
+               ccid3_pr_debug("%s, sk=%p, received a packet when "
+                              "terminating!\n", dccp_role(sk), sk);
+               return;
+       }
+
+       /* we are only interested in ACKs */
+       if (!(DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_ACK ||
+             DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_DATAACK))
+               return;
+
+       opt_recv = &hctx->ccid3hctx_options_received;
+
+       t_elapsed = dp->dccps_options_received.dccpor_elapsed_time;
+       x_recv = opt_recv->ccid3or_receive_rate;
+       pinv = opt_recv->ccid3or_loss_event_rate;
+
+       switch (hctx->ccid3hctx_state) {
+       case TFRC_SSTATE_NO_SENT:
+               /* FIXME: what to do here? */
+               return;
+       case TFRC_SSTATE_NO_FBACK:
+       case TFRC_SSTATE_FBACK:
+               /* Calculate new round trip sample by
+                * R_sample = (now - t_recvdata) - t_delay */
+               /* get t_recvdata from history */
+               packet = dccp_tx_hist_find_entry(&hctx->ccid3hctx_hist,
+                                                DCCP_SKB_CB(skb)->dccpd_ack_seq);
+               if (packet == NULL) {
+                       ccid3_pr_debug("%s, sk=%p, seqno %llu(%s) does't "
+                                      "exist in history!\n",
+                                      dccp_role(sk), sk,
+                                      DCCP_SKB_CB(skb)->dccpd_ack_seq,
+                                      dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type));
+                       return;
+               }
+
+               /* Update RTT */
+               r_sample = timeval_now_delta(&packet->dccphtx_tstamp);
+               /* FIXME: */
+               // r_sample -= usecs_to_jiffies(t_elapsed * 10);
+
+               /* Update RTT estimate by 
+                * If (No feedback recv)
+                *    R = R_sample;
+                * Else
+                *    R = q * R + (1 - q) * R_sample;
+                *
+                * q is a constant, RFC 3448 recomments 0.9
+                */
+               if (hctx->ccid3hctx_state == TFRC_SSTATE_NO_FBACK) {
+                       ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK);
+                       hctx->ccid3hctx_rtt = r_sample;
+               } else
+                       hctx->ccid3hctx_rtt = (hctx->ccid3hctx_rtt * 9) / 10 +
+                                             r_sample / 10;
+
+               ccid3_pr_debug("%s, sk=%p, New RTT estimate=%uus, "
+                              "r_sample=%us\n", dccp_role(sk), sk,
+                              hctx->ccid3hctx_rtt, r_sample);
+
+               /* Update timeout interval */
+               hctx->ccid3hctx_t_rto = max_t(u32, 4 * hctx->ccid3hctx_rtt,
+                                             USEC_PER_SEC);
+
+               /* Update receive rate */
+               hctx->ccid3hctx_x_recv = x_recv;/* X_recv in bytes per sec */
+
+               /* Update loss event rate */
+               if (pinv == ~0 || pinv == 0)
+                       hctx->ccid3hctx_p = 0;
+               else {
+                       hctx->ccid3hctx_p = 1000000 / pinv;
+
+                       if (hctx->ccid3hctx_p < TFRC_SMALLEST_P) {
+                               hctx->ccid3hctx_p = TFRC_SMALLEST_P;
+                               ccid3_pr_debug("%s, sk=%p, Smallest p used!\n",
+                                              dccp_role(sk), sk);
+                       }
+               }
+
+               /* unschedule no feedback timer */
+               sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer);
+
+               /* Update sending rate */
+               ccid3_hc_tx_update_x(sk);
+
+               /* Update next send time */
+               timeval_sub_usecs(&hctx->ccid3hctx_t_nom,
+                                 hctx->ccid3hctx_t_ipi);
+               ccid3_calc_new_t_ipi(hctx);
+               timeval_add_usecs(&hctx->ccid3hctx_t_nom,
+                                 hctx->ccid3hctx_t_ipi);
+               ccid3_calc_new_delta(hctx);
+
+               /* remove all packets older than the one acked from history */
+               dccp_tx_hist_purge_older(ccid3_tx_hist,
+                                        &hctx->ccid3hctx_hist, packet);
+               /*
+                * As we have calculated new ipi, delta, t_nom it is possible that
+                * we now can send a packet, so wake up dccp_wait_for_ccids.
+                */
+               sk->sk_write_space(sk);
+
+               /*
+                * Schedule no feedback timer to expire in
+                * max(4 * R, 2 * s / X)
+                */
+               next_tmout = max(hctx->ccid3hctx_t_rto,
+                                2 * usecs_div(hctx->ccid3hctx_s,
+                                              hctx->ccid3hctx_x));
+                       
+               ccid3_pr_debug("%s, sk=%p, Scheduled no feedback timer to "
+                              "expire in %lu jiffies (%luus)\n",
+                              dccp_role(sk), sk,
+                              usecs_to_jiffies(next_tmout), next_tmout); 
+
+               sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer, 
+                              jiffies + max_t(u32, 1, usecs_to_jiffies(next_tmout)));
+
+               /* set idle flag */
+               hctx->ccid3hctx_idle = 1;   
+               break;
+       default:
+               printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n",
+                      __FUNCTION__, dccp_role(sk), sk, hctx->ccid3hctx_state);
+               dump_stack();
+               break;
+       }
+}
+
+static void ccid3_hc_tx_insert_options(struct sock *sk, struct sk_buff *skb)
+{
+       const struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+
+       if (hctx == NULL || !(sk->sk_state == DCCP_OPEN ||
+                             sk->sk_state == DCCP_PARTOPEN))
+               return;
+
+        DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count;
+}
+
+static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
+                                    unsigned char len, u16 idx,
+                                    unsigned char *value)
+{
+       int rc = 0;
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+       struct ccid3_options_received *opt_recv;
+
+       if (hctx == NULL)
+               return 0;
+
+       opt_recv = &hctx->ccid3hctx_options_received;
+
+       if (opt_recv->ccid3or_seqno != dp->dccps_gsr) {
+               opt_recv->ccid3or_seqno              = dp->dccps_gsr;
+               opt_recv->ccid3or_loss_event_rate    = ~0;
+               opt_recv->ccid3or_loss_intervals_idx = 0;
+               opt_recv->ccid3or_loss_intervals_len = 0;
+               opt_recv->ccid3or_receive_rate       = 0;
+       }
+
+       switch (option) {
+       case TFRC_OPT_LOSS_EVENT_RATE:
+               if (len != 4) {
+                       ccid3_pr_debug("%s, sk=%p, invalid len for "
+                                      "TFRC_OPT_LOSS_EVENT_RATE\n",
+                                      dccp_role(sk), sk);
+                       rc = -EINVAL;
+               } else {
+                       opt_recv->ccid3or_loss_event_rate = ntohl(*(u32 *)value);
+                       ccid3_pr_debug("%s, sk=%p, LOSS_EVENT_RATE=%u\n",
+                                      dccp_role(sk), sk,
+                                      opt_recv->ccid3or_loss_event_rate);
+               }
+               break;
+       case TFRC_OPT_LOSS_INTERVALS:
+               opt_recv->ccid3or_loss_intervals_idx = idx;
+               opt_recv->ccid3or_loss_intervals_len = len;
+               ccid3_pr_debug("%s, sk=%p, LOSS_INTERVALS=(%u, %u)\n",
+                              dccp_role(sk), sk,
+                              opt_recv->ccid3or_loss_intervals_idx,
+                              opt_recv->ccid3or_loss_intervals_len);
+               break;
+       case TFRC_OPT_RECEIVE_RATE:
+               if (len != 4) {
+                       ccid3_pr_debug("%s, sk=%p, invalid len for "
+                                      "TFRC_OPT_RECEIVE_RATE\n",
+                                      dccp_role(sk), sk);
+                       rc = -EINVAL;
+               } else {
+                       opt_recv->ccid3or_receive_rate = ntohl(*(u32 *)value);
+                       ccid3_pr_debug("%s, sk=%p, RECEIVE_RATE=%u\n",
+                                      dccp_role(sk), sk,
+                                      opt_recv->ccid3or_receive_rate);
+               }
+               break;
+       }
+
+       return rc;
+}
+
+static int ccid3_hc_tx_init(struct sock *sk)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_tx_sock *hctx;
+
+       ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
+
+       hctx = dp->dccps_hc_tx_ccid_private = kmalloc(sizeof(*hctx),
+                                                     gfp_any());
+       if (hctx == NULL)
+               return -ENOMEM;
+
+       memset(hctx, 0, sizeof(*hctx));
+
+       if (dp->dccps_packet_size >= TFRC_MIN_PACKET_SIZE &&
+           dp->dccps_packet_size <= TFRC_MAX_PACKET_SIZE)
+               hctx->ccid3hctx_s = dp->dccps_packet_size;
+       else
+               hctx->ccid3hctx_s = TFRC_STD_PACKET_SIZE;
+
+       /* Set transmission rate to 1 packet per second */
+       hctx->ccid3hctx_x     = hctx->ccid3hctx_s;
+       hctx->ccid3hctx_t_rto = USEC_PER_SEC;
+       hctx->ccid3hctx_state = TFRC_SSTATE_NO_SENT;
+       INIT_LIST_HEAD(&hctx->ccid3hctx_hist);
+       init_timer(&hctx->ccid3hctx_no_feedback_timer);
+
+       return 0;
+}
+
+static void ccid3_hc_tx_exit(struct sock *sk)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+
+       ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
+       BUG_ON(hctx == NULL);
+
+       ccid3_hc_tx_set_state(sk, TFRC_SSTATE_TERM);
+       sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer);
+
+       /* Empty packet history */
+       dccp_tx_hist_purge(ccid3_tx_hist, &hctx->ccid3hctx_hist);
+
+       kfree(dp->dccps_hc_tx_ccid_private);
+       dp->dccps_hc_tx_ccid_private = NULL;
+}
+
+/*
+ * RX Half Connection methods
+ */
+
+/* TFRC receiver states */
+enum ccid3_hc_rx_states {
+               TFRC_RSTATE_NO_DATA = 1,
+       TFRC_RSTATE_DATA,
+       TFRC_RSTATE_TERM    = 127,
+};
+
+#ifdef CCID3_DEBUG
+static const char *ccid3_rx_state_name(enum ccid3_hc_rx_states state)
+{
+       static char *ccid3_rx_state_names[] = {
+       [TFRC_RSTATE_NO_DATA] = "NO_DATA",
+       [TFRC_RSTATE_DATA]    = "DATA",
+       [TFRC_RSTATE_TERM]    = "TERM",
+       };
+
+       return ccid3_rx_state_names[state];
+}
+#endif
+
+static inline void ccid3_hc_rx_set_state(struct sock *sk,
+                                        enum ccid3_hc_rx_states state)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
+       enum ccid3_hc_rx_states oldstate = hcrx->ccid3hcrx_state;
+
+       ccid3_pr_debug("%s(%p) %-8.8s -> %s\n",
+                      dccp_role(sk), sk, ccid3_rx_state_name(oldstate),
+                      ccid3_rx_state_name(state));
+       WARN_ON(state == oldstate);
+       hcrx->ccid3hcrx_state = state;
+}
+
+static void ccid3_hc_rx_send_feedback(struct sock *sk)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
+       struct dccp_rx_hist_entry *packet;
+       struct timeval now;
+
+       ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
+
+       do_gettimeofday(&now);
+
+       switch (hcrx->ccid3hcrx_state) {
+       case TFRC_RSTATE_NO_DATA:
+               hcrx->ccid3hcrx_x_recv = 0;
+               break;
+       case TFRC_RSTATE_DATA: {
+               const u32 delta = timeval_delta(&now,
+                                       &hcrx->ccid3hcrx_tstamp_last_feedback);
+
+               hcrx->ccid3hcrx_x_recv = (hcrx->ccid3hcrx_bytes_recv *
+                                         USEC_PER_SEC);
+               if (likely(delta > 1))
+                       hcrx->ccid3hcrx_x_recv /= delta;
+       }
+               break;
+       default:
+               printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n",
+                      __FUNCTION__, dccp_role(sk), sk, hcrx->ccid3hcrx_state);
+               dump_stack();
+               return;
+       }
+
+       packet = dccp_rx_hist_find_data_packet(&hcrx->ccid3hcrx_hist);
+       if (packet == NULL) {
+               printk(KERN_CRIT "%s: %s, sk=%p, no data packet in history!\n",
+                      __FUNCTION__, dccp_role(sk), sk);
+               dump_stack();
+               return;
+       }
+
+       hcrx->ccid3hcrx_tstamp_last_feedback = now;
+       hcrx->ccid3hcrx_last_counter         = packet->dccphrx_ccval;
+       hcrx->ccid3hcrx_seqno_last_counter   = packet->dccphrx_seqno;
+       hcrx->ccid3hcrx_bytes_recv           = 0;
+
+       /* Convert to multiples of 10us */
+       hcrx->ccid3hcrx_elapsed_time =
+                       timeval_delta(&now, &packet->dccphrx_tstamp) / 10;
+       if (hcrx->ccid3hcrx_p == 0)
+               hcrx->ccid3hcrx_pinv = ~0;
+       else
+               hcrx->ccid3hcrx_pinv = 1000000 / hcrx->ccid3hcrx_p;
+       dccp_send_ack(sk);
+}
+
+static void ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
+{
+       const struct dccp_sock *dp = dccp_sk(sk);
+       u32 x_recv, pinv;
+       struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
+
+       if (hcrx == NULL || !(sk->sk_state == DCCP_OPEN ||
+                             sk->sk_state == DCCP_PARTOPEN))
+               return;
+
+       DCCP_SKB_CB(skb)->dccpd_ccval = hcrx->ccid3hcrx_last_counter;
+
+       if (dccp_packet_without_ack(skb))
+               return;
+               
+       if (hcrx->ccid3hcrx_elapsed_time != 0)
+               dccp_insert_option_elapsed_time(sk, skb,
+                                               hcrx->ccid3hcrx_elapsed_time);
+       dccp_insert_option_timestamp(sk, skb);
+       x_recv = htonl(hcrx->ccid3hcrx_x_recv);
+       pinv   = htonl(hcrx->ccid3hcrx_pinv);
+       dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE,
+                          &pinv, sizeof(pinv));
+       dccp_insert_option(sk, skb, TFRC_OPT_RECEIVE_RATE,
+                          &x_recv, sizeof(x_recv));
+}
+
+/* calculate first loss interval
+ *
+ * returns estimated loss interval in usecs */
+
+static u32 ccid3_hc_rx_calc_first_li(struct sock *sk)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
+       struct dccp_rx_hist_entry *entry, *next, *tail = NULL;
+       u32 rtt, delta, x_recv, fval, p, tmp2;
+       struct timeval tstamp = { 0, };
+       int interval = 0;
+       int win_count = 0;
+       int step = 0;
+       u64 tmp1;
+
+       list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist,
+                                dccphrx_node) {
+               if (dccp_rx_hist_entry_data_packet(entry)) {
+                       tail = entry;
+
+                       switch (step) {
+                       case 0:
+                               tstamp    = entry->dccphrx_tstamp;
+                               win_count = entry->dccphrx_ccval;
+                               step = 1;
+                               break;
+                       case 1:
+                               interval = win_count - entry->dccphrx_ccval;
+                               if (interval < 0)
+                                       interval += TFRC_WIN_COUNT_LIMIT;
+                               if (interval > 4)
+                                       goto found;
+                               break;
+                       }
+               }
+       }
+
+       if (step == 0) {
+               printk(KERN_CRIT "%s: %s, sk=%p, packet history contains no "
+                                "data packets!\n",
+                      __FUNCTION__, dccp_role(sk), sk);
+               return ~0;
+       }
+
+       if (interval == 0) {
+               ccid3_pr_debug("%s, sk=%p, Could not find a win_count "
+                              "interval > 0. Defaulting to 1\n",
+                              dccp_role(sk), sk);
+               interval = 1;
+       }
+found:
+       rtt = timeval_delta(&tstamp, &tail->dccphrx_tstamp) * 4 / interval;
+       ccid3_pr_debug("%s, sk=%p, approximated RTT to %uus\n",
+                      dccp_role(sk), sk, rtt);
+       if (rtt == 0)
+               rtt = 1;
+
+       delta = timeval_now_delta(&hcrx->ccid3hcrx_tstamp_last_feedback);
+       x_recv = hcrx->ccid3hcrx_bytes_recv * USEC_PER_SEC;
+       if (likely(delta > 1))
+               x_recv /= delta;
+
+       tmp1 = (u64)x_recv * (u64)rtt;
+       do_div(tmp1,10000000);
+       tmp2 = (u32)tmp1;
+       fval = (hcrx->ccid3hcrx_s * 100000) / tmp2;
+       /* do not alter order above or you will get overflow on 32 bit */
+       p = tfrc_calc_x_reverse_lookup(fval);
+       ccid3_pr_debug("%s, sk=%p, receive rate=%u bytes/s, implied "
+                      "loss rate=%u\n", dccp_role(sk), sk, x_recv, p);
+
+       if (p == 0)
+               return ~0;
+       else
+               return 1000000 / p; 
+}
+
+static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
+
+       if (seq_loss != DCCP_MAX_SEQNO + 1 &&
+           list_empty(&hcrx->ccid3hcrx_li_hist)) {
+               struct dccp_li_hist_entry *li_tail;
+
+               li_tail = dccp_li_hist_interval_new(ccid3_li_hist,
+                                                   &hcrx->ccid3hcrx_li_hist,
+                                                   seq_loss, win_loss);
+               if (li_tail == NULL)
+                       return;
+               li_tail->dccplih_interval = ccid3_hc_rx_calc_first_li(sk);
+       }
+       /* FIXME: find end of interval */
+}
+
+static void ccid3_hc_rx_detect_loss(struct sock *sk)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
+       u8 win_loss;
+       const u64 seq_loss = dccp_rx_hist_detect_loss(&hcrx->ccid3hcrx_hist,
+                                                     &hcrx->ccid3hcrx_li_hist,
+                                                     &win_loss);
+
+       ccid3_hc_rx_update_li(sk, seq_loss, win_loss);
+}
+
+static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
+       const struct dccp_options_received *opt_recv;
+       struct dccp_rx_hist_entry *packet;
+       struct timeval now;
+       u8 win_count;
+       u32 p_prev;
+       int ins;
+
+       if (hcrx == NULL)
+               return;
+
+       BUG_ON(!(hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA ||
+                hcrx->ccid3hcrx_state == TFRC_RSTATE_DATA));
+
+       opt_recv = &dp->dccps_options_received;
+
+       switch (DCCP_SKB_CB(skb)->dccpd_type) {
+       case DCCP_PKT_ACK:
+               if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA)
+                       return;
+       case DCCP_PKT_DATAACK:
+               if (opt_recv->dccpor_timestamp_echo == 0)
+                       break;
+               p_prev = hcrx->ccid3hcrx_rtt;
+               do_gettimeofday(&now);
+               hcrx->ccid3hcrx_rtt = timeval_usecs(&now) -
+                                    (opt_recv->dccpor_timestamp_echo -
+                                     opt_recv->dccpor_elapsed_time) * 10;
+               if (p_prev != hcrx->ccid3hcrx_rtt)
+                       ccid3_pr_debug("%s, New RTT=%luus, elapsed time=%u\n",
+                                      dccp_role(sk), hcrx->ccid3hcrx_rtt,
+                                      opt_recv->dccpor_elapsed_time);
+               break;
+       case DCCP_PKT_DATA:
+               break;
+       default:
+               ccid3_pr_debug("%s, sk=%p, not DATA/DATAACK/ACK packet(%s)\n",
+                              dccp_role(sk), sk,
+                              dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type));
+               return;
+       }
+
+       packet = dccp_rx_hist_entry_new(ccid3_rx_hist, opt_recv->dccpor_ndp,
+                                       skb, SLAB_ATOMIC);
+       if (packet == NULL) {
+               ccid3_pr_debug("%s, sk=%p, Not enough mem to add rx packet "
+                              "to history (consider it lost)!",
+                              dccp_role(sk), sk);
+               return;
+       }
+
+       win_count = packet->dccphrx_ccval;
+
+       ins = dccp_rx_hist_add_packet(ccid3_rx_hist, &hcrx->ccid3hcrx_hist,
+                                     &hcrx->ccid3hcrx_li_hist, packet);
+
+       if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_ACK)
+               return;
+
+       switch (hcrx->ccid3hcrx_state) {
+       case TFRC_RSTATE_NO_DATA:
+               ccid3_pr_debug("%s, sk=%p(%s), skb=%p, sending initial "
+                              "feedback\n",
+                              dccp_role(sk), sk,
+                              dccp_state_name(sk->sk_state), skb);
+               ccid3_hc_rx_send_feedback(sk);
+               ccid3_hc_rx_set_state(sk, TFRC_RSTATE_DATA);
+               return;
+       case TFRC_RSTATE_DATA:
+               hcrx->ccid3hcrx_bytes_recv += skb->len -
+                                             dccp_hdr(skb)->dccph_doff * 4;
+               if (ins != 0)
+                       break;
+
+               do_gettimeofday(&now);
+               if (timeval_delta(&now, &hcrx->ccid3hcrx_tstamp_last_ack) >=
+                   hcrx->ccid3hcrx_rtt) {
+                       hcrx->ccid3hcrx_tstamp_last_ack = now;
+                       ccid3_hc_rx_send_feedback(sk);
+               }
+               return;
+       default:
+               printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n",
+                      __FUNCTION__, dccp_role(sk), sk, hcrx->ccid3hcrx_state);
+               dump_stack();
+               return;
+       }
+
+       /* Dealing with packet loss */
+       ccid3_pr_debug("%s, sk=%p(%s), data loss! Reacting...\n",
+                      dccp_role(sk), sk, dccp_state_name(sk->sk_state));
+
+       ccid3_hc_rx_detect_loss(sk);
+       p_prev = hcrx->ccid3hcrx_p;
+       
+       /* Calculate loss event rate */
+       if (!list_empty(&hcrx->ccid3hcrx_li_hist))
+               /* Scaling up by 1000000 as fixed decimal */
+               hcrx->ccid3hcrx_p = 1000000 / dccp_li_hist_calc_i_mean(&hcrx->ccid3hcrx_li_hist);
+
+       if (hcrx->ccid3hcrx_p > p_prev) {
+               ccid3_hc_rx_send_feedback(sk);
+               return;
+       }
+}
+
+static int ccid3_hc_rx_init(struct sock *sk)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_rx_sock *hcrx;
+
+       ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
+
+       hcrx = dp->dccps_hc_rx_ccid_private = kmalloc(sizeof(*hcrx),
+                                                     gfp_any());
+       if (hcrx == NULL)
+               return -ENOMEM;
+
+       memset(hcrx, 0, sizeof(*hcrx));
+
+       if (dp->dccps_packet_size >= TFRC_MIN_PACKET_SIZE &&
+           dp->dccps_packet_size <= TFRC_MAX_PACKET_SIZE)
+               hcrx->ccid3hcrx_s = dp->dccps_packet_size;
+       else
+               hcrx->ccid3hcrx_s = TFRC_STD_PACKET_SIZE;
+
+       hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA;
+       INIT_LIST_HEAD(&hcrx->ccid3hcrx_hist);
+       INIT_LIST_HEAD(&hcrx->ccid3hcrx_li_hist);
+       /*
+        * XXX this seems to be paranoid, need to think more about this, for
+        * now start with something different than zero. -acme
+        */
+       hcrx->ccid3hcrx_rtt = USEC_PER_SEC / 5;
+       return 0;
+}
+
+static void ccid3_hc_rx_exit(struct sock *sk)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
+
+       ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
+
+       if (hcrx == NULL)
+               return;
+
+       ccid3_hc_rx_set_state(sk, TFRC_RSTATE_TERM);
+
+       /* Empty packet history */
+       dccp_rx_hist_purge(ccid3_rx_hist, &hcrx->ccid3hcrx_hist);
+
+       /* Empty loss interval history */
+       dccp_li_hist_purge(ccid3_li_hist, &hcrx->ccid3hcrx_li_hist);
+
+       kfree(dp->dccps_hc_rx_ccid_private);
+       dp->dccps_hc_rx_ccid_private = NULL;
+}
+
+static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info)
+{
+       const struct dccp_sock *dp = dccp_sk(sk);
+       const struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
+
+       if (hcrx == NULL)
+               return;
+
+       info->tcpi_ca_state     = hcrx->ccid3hcrx_state;
+       info->tcpi_options      |= TCPI_OPT_TIMESTAMPS;
+       info->tcpi_rcv_rtt      = hcrx->ccid3hcrx_rtt;
+}
+
+static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info)
+{
+       const struct dccp_sock *dp = dccp_sk(sk);
+       const struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+
+       if (hctx == NULL)
+               return;
+
+       info->tcpi_rto = hctx->ccid3hctx_t_rto;
+       info->tcpi_rtt = hctx->ccid3hctx_rtt;
+}
+
+static struct ccid ccid3 = {
+       .ccid_id                   = 3,
+       .ccid_name                 = "ccid3",
+       .ccid_owner                = THIS_MODULE,
+       .ccid_init                 = ccid3_init,
+       .ccid_exit                 = ccid3_exit,
+       .ccid_hc_tx_init           = ccid3_hc_tx_init,
+       .ccid_hc_tx_exit           = ccid3_hc_tx_exit,
+       .ccid_hc_tx_send_packet    = ccid3_hc_tx_send_packet,
+       .ccid_hc_tx_packet_sent    = ccid3_hc_tx_packet_sent,
+       .ccid_hc_tx_packet_recv    = ccid3_hc_tx_packet_recv,
+       .ccid_hc_tx_insert_options = ccid3_hc_tx_insert_options,
+       .ccid_hc_tx_parse_options  = ccid3_hc_tx_parse_options,
+       .ccid_hc_rx_init           = ccid3_hc_rx_init,
+       .ccid_hc_rx_exit           = ccid3_hc_rx_exit,
+       .ccid_hc_rx_insert_options = ccid3_hc_rx_insert_options,
+       .ccid_hc_rx_packet_recv    = ccid3_hc_rx_packet_recv,
+       .ccid_hc_rx_get_info       = ccid3_hc_rx_get_info,
+       .ccid_hc_tx_get_info       = ccid3_hc_tx_get_info,
+};
+module_param(ccid3_debug, int, 0444);
+MODULE_PARM_DESC(ccid3_debug, "Enable debug messages");
+
+static __init int ccid3_module_init(void)
+{
+       int rc = -ENOBUFS;
+
+       ccid3_rx_hist = dccp_rx_hist_new("ccid3");
+       if (ccid3_rx_hist == NULL)
+               goto out;
+
+       ccid3_tx_hist = dccp_tx_hist_new("ccid3");
+       if (ccid3_tx_hist == NULL)
+               goto out_free_rx;
+
+       ccid3_li_hist = dccp_li_hist_new("ccid3");
+       if (ccid3_li_hist == NULL)
+               goto out_free_tx;
+
+       rc = ccid_register(&ccid3);
+       if (rc != 0) 
+               goto out_free_loss_interval_history;
+out:
+       return rc;
+
+out_free_loss_interval_history:
+       dccp_li_hist_delete(ccid3_li_hist);
+       ccid3_li_hist = NULL;
+out_free_tx:
+       dccp_tx_hist_delete(ccid3_tx_hist);
+       ccid3_tx_hist = NULL;
+out_free_rx:
+       dccp_rx_hist_delete(ccid3_rx_hist);
+       ccid3_rx_hist = NULL;
+       goto out;
+}
+module_init(ccid3_module_init);
+
+static __exit void ccid3_module_exit(void)
+{
+#ifdef CONFIG_IP_DCCP_UNLOAD_HACK
+       /*
+        * Hack to use while developing, so that we get rid of the control
+        * sock, that is what keeps a refcount on dccp.ko -acme
+        */
+       extern void dccp_ctl_sock_exit(void);
+
+       dccp_ctl_sock_exit();
+#endif
+       ccid_unregister(&ccid3);
+
+       if (ccid3_tx_hist != NULL) {
+               dccp_tx_hist_delete(ccid3_tx_hist);
+               ccid3_tx_hist = NULL;
+       }
+       if (ccid3_rx_hist != NULL) {
+               dccp_rx_hist_delete(ccid3_rx_hist);
+               ccid3_rx_hist = NULL;
+       }
+       if (ccid3_li_hist != NULL) {
+               dccp_li_hist_delete(ccid3_li_hist);
+               ccid3_li_hist = NULL;
+       }
+}
+module_exit(ccid3_module_exit);
+
+MODULE_AUTHOR("Ian McDonald <iam4@cs.waikato.ac.nz>, "
+             "Arnaldo Carvalho de Melo <acme@ghostprotocols.net>");
+MODULE_DESCRIPTION("DCCP TFRC CCID3 CCID");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("net-dccp-ccid-3");
diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h
new file mode 100644 (file)
index 0000000..ee8cbac
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ *  net/dccp/ccids/ccid3.h
+ *
+ *  Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand.
+ *
+ *  An implementation of the DCCP protocol
+ *
+ *  This code has been developed by the University of Waikato WAND
+ *  research group. For further information please see http://www.wand.net.nz/
+ *  or e-mail Ian McDonald - iam4@cs.waikato.ac.nz
+ *
+ *  This code also uses code from Lulea University, rereleased as GPL by its
+ *  authors:
+ *  Copyright (c) 2003 Nils-Erik Mattsson, Joacim Haggmark, Magnus Erixzon
+ *
+ *  Changes to meet Linux coding standards, to make it meet latest ccid3 draft
+ *  and to make it work as a loadable module in the DCCP stack written by
+ *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>.
+ *
+ *  Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _DCCP_CCID3_H_
+#define _DCCP_CCID3_H_
+
+#include <linux/config.h>
+#include <linux/list.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+#define TFRC_MIN_PACKET_SIZE      16
+#define TFRC_STD_PACKET_SIZE     256
+#define TFRC_MAX_PACKET_SIZE   65535
+
+/* Two seconds as per CCID3 spec */
+#define TFRC_INITIAL_TIMEOUT      (2 * USEC_PER_SEC)
+
+/* In usecs - half the scheduling granularity as per RFC3448 4.6 */
+#define TFRC_OPSYS_HALF_TIME_GRAN  (USEC_PER_SEC / (2 * HZ))
+
+/* In seconds */
+#define TFRC_MAX_BACK_OFF_TIME    64
+
+#define TFRC_SMALLEST_P                   40
+
+enum ccid3_options {
+       TFRC_OPT_LOSS_EVENT_RATE = 192,
+       TFRC_OPT_LOSS_INTERVALS  = 193,
+       TFRC_OPT_RECEIVE_RATE    = 194,
+};
+
+struct ccid3_options_received {
+       u64 ccid3or_seqno:48,
+           ccid3or_loss_intervals_idx:16;
+       u16 ccid3or_loss_intervals_len;
+       u32 ccid3or_loss_event_rate;
+       u32 ccid3or_receive_rate;
+};
+
+/** struct ccid3_hc_tx_sock - CCID3 sender half connection sock
+ *
+  * @ccid3hctx_state - Sender state
+  * @ccid3hctx_x - Current sending rate
+  * @ccid3hctx_x_recv - Receive rate
+  * @ccid3hctx_x_calc - Calculated send (?) rate
+  * @ccid3hctx_s - Packet size
+  * @ccid3hctx_rtt - Estimate of current round trip time in usecs
+  * @@ccid3hctx_p - Current loss event rate (0-1) scaled by 1000000
+  * @ccid3hctx_last_win_count - Last window counter sent
+  * @ccid3hctx_t_last_win_count - Timestamp of earliest packet
+  *                              with last_win_count value sent
+  * @ccid3hctx_no_feedback_timer - Handle to no feedback timer
+  * @ccid3hctx_idle - FIXME
+  * @ccid3hctx_t_ld - Time last doubled during slow start
+  * @ccid3hctx_t_nom - Nominal send time of next packet
+  * @ccid3hctx_t_ipi - Interpacket (send) interval
+  * @ccid3hctx_delta - Send timer delta
+  * @ccid3hctx_hist - Packet history
+  */
+struct ccid3_hc_tx_sock {
+       u32                             ccid3hctx_x;
+       u32                             ccid3hctx_x_recv;
+       u32                             ccid3hctx_x_calc;
+       u16                             ccid3hctx_s;
+       u32                             ccid3hctx_rtt;
+       u32                             ccid3hctx_p;
+       u8                              ccid3hctx_state;
+       u8                              ccid3hctx_last_win_count;
+       u8                              ccid3hctx_idle;
+       struct timeval                  ccid3hctx_t_last_win_count;
+       struct timer_list               ccid3hctx_no_feedback_timer;
+       struct timeval                  ccid3hctx_t_ld;
+       struct timeval                  ccid3hctx_t_nom;
+       u32                             ccid3hctx_t_rto;
+       u32                             ccid3hctx_t_ipi;
+       u32                             ccid3hctx_delta;
+       struct list_head                ccid3hctx_hist;
+       struct ccid3_options_received   ccid3hctx_options_received;
+};
+
+struct ccid3_hc_rx_sock {
+       u64                     ccid3hcrx_seqno_last_counter:48,
+                               ccid3hcrx_state:8,
+                               ccid3hcrx_last_counter:4;
+       unsigned long           ccid3hcrx_rtt;
+       u32                     ccid3hcrx_p;
+       u32                     ccid3hcrx_bytes_recv;
+       struct timeval          ccid3hcrx_tstamp_last_feedback;
+       struct timeval          ccid3hcrx_tstamp_last_ack;
+       struct list_head        ccid3hcrx_hist;
+       struct list_head        ccid3hcrx_li_hist;
+       u16                     ccid3hcrx_s;
+       u32                     ccid3hcrx_pinv;
+       u32                     ccid3hcrx_elapsed_time;
+       u32                     ccid3hcrx_x_recv;
+};
+
+#define ccid3_hc_tx_field(s,field) (s->dccps_hc_tx_ccid_private == NULL ? 0 : \
+    ((struct ccid3_hc_tx_sock *)s->dccps_hc_tx_ccid_private)->ccid3hctx_##field)
+
+#define ccid3_hc_rx_field(s,field) (s->dccps_hc_rx_ccid_private == NULL ? 0 : \
+    ((struct ccid3_hc_rx_sock *)s->dccps_hc_rx_ccid_private)->ccid3hcrx_##field)
+
+#endif /* _DCCP_CCID3_H_ */
diff --git a/net/dccp/ccids/lib/Makefile b/net/dccp/ccids/lib/Makefile
new file mode 100644 (file)
index 0000000..5f940a6
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_IP_DCCP_TFRC_LIB) += dccp_tfrc_lib.o
+
+dccp_tfrc_lib-y := loss_interval.o packet_history.o tfrc_equation.o
diff --git a/net/dccp/ccids/lib/loss_interval.c b/net/dccp/ccids/lib/loss_interval.c
new file mode 100644 (file)
index 0000000..4c01a54
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ *  net/dccp/ccids/lib/loss_interval.c
+ *
+ *  Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand.
+ *  Copyright (c) 2005 Ian McDonald <iam4@cs.waikato.ac.nz>
+ *  Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *  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/module.h>
+
+#include "loss_interval.h"
+
+struct dccp_li_hist *dccp_li_hist_new(const char *name)
+{
+       struct dccp_li_hist *hist = kmalloc(sizeof(*hist), GFP_ATOMIC);
+       static const char dccp_li_hist_mask[] = "li_hist_%s";
+       char *slab_name;
+
+       if (hist == NULL)
+               goto out;
+
+       slab_name = kmalloc(strlen(name) + sizeof(dccp_li_hist_mask) - 1,
+                           GFP_ATOMIC);
+       if (slab_name == NULL)
+               goto out_free_hist;
+
+       sprintf(slab_name, dccp_li_hist_mask, name);
+       hist->dccplih_slab = kmem_cache_create(slab_name,
+                                            sizeof(struct dccp_li_hist_entry),
+                                              0, SLAB_HWCACHE_ALIGN,
+                                              NULL, NULL);
+       if (hist->dccplih_slab == NULL)
+               goto out_free_slab_name;
+out:
+       return hist;
+out_free_slab_name:
+       kfree(slab_name);
+out_free_hist:
+       kfree(hist);
+       hist = NULL;
+       goto out;
+}
+
+EXPORT_SYMBOL_GPL(dccp_li_hist_new);
+
+void dccp_li_hist_delete(struct dccp_li_hist *hist)
+{
+       const char* name = kmem_cache_name(hist->dccplih_slab);
+
+       kmem_cache_destroy(hist->dccplih_slab);
+       kfree(name);
+       kfree(hist);
+}
+
+EXPORT_SYMBOL_GPL(dccp_li_hist_delete);
+
+void dccp_li_hist_purge(struct dccp_li_hist *hist, struct list_head *list)
+{
+       struct dccp_li_hist_entry *entry, *next;
+
+       list_for_each_entry_safe(entry, next, list, dccplih_node) {
+               list_del_init(&entry->dccplih_node);
+               kmem_cache_free(hist->dccplih_slab, entry);
+       }
+}
+
+EXPORT_SYMBOL_GPL(dccp_li_hist_purge);
+
+/* Weights used to calculate loss event rate */
+/*
+ * These are integers as per section 8 of RFC3448. We can then divide by 4 *
+ * when we use it.
+ */
+static const int dccp_li_hist_w[DCCP_LI_HIST_IVAL_F_LENGTH] = {
+       4, 4, 4, 4, 3, 2, 1, 1,
+};
+
+u32 dccp_li_hist_calc_i_mean(struct list_head *list)
+{
+       struct dccp_li_hist_entry *li_entry, *li_next;
+       int i = 0;
+       u32 i_tot;
+       u32 i_tot0 = 0;
+       u32 i_tot1 = 0;
+       u32 w_tot  = 0;
+
+       list_for_each_entry_safe(li_entry, li_next, list, dccplih_node) {
+               if (i < DCCP_LI_HIST_IVAL_F_LENGTH) {
+                       i_tot0 += li_entry->dccplih_interval * dccp_li_hist_w[i];
+                       w_tot  += dccp_li_hist_w[i];
+               }
+
+               if (i != 0)
+                       i_tot1 += li_entry->dccplih_interval * dccp_li_hist_w[i - 1];
+
+               if (++i > DCCP_LI_HIST_IVAL_F_LENGTH)
+                       break;
+       }
+
+       if (i != DCCP_LI_HIST_IVAL_F_LENGTH)
+               return 0;
+
+       i_tot = max(i_tot0, i_tot1);
+
+       /* FIXME: Why do we do this? -Ian McDonald */
+       if (i_tot * 4 < w_tot)
+               i_tot = w_tot * 4;
+
+       return i_tot * 4 / w_tot;
+}
+
+EXPORT_SYMBOL_GPL(dccp_li_hist_calc_i_mean);
+
+struct dccp_li_hist_entry *dccp_li_hist_interval_new(struct dccp_li_hist *hist,
+                                                    struct list_head *list,
+                                                    const u64 seq_loss,
+                                                    const u8 win_loss)
+{
+       struct dccp_li_hist_entry *tail = NULL, *entry;
+       int i;
+
+       for (i = 0; i <= DCCP_LI_HIST_IVAL_F_LENGTH; ++i) {
+               entry = dccp_li_hist_entry_new(hist, SLAB_ATOMIC);
+               if (entry == NULL) {
+                       dccp_li_hist_purge(hist, list);
+                       return NULL;
+               }
+               if (tail == NULL)
+                       tail = entry;
+               list_add(&entry->dccplih_node, list);
+       }
+
+       entry->dccplih_seqno     = seq_loss;
+       entry->dccplih_win_count = win_loss;
+       return tail;
+}
+
+EXPORT_SYMBOL_GPL(dccp_li_hist_interval_new);
diff --git a/net/dccp/ccids/lib/loss_interval.h b/net/dccp/ccids/lib/loss_interval.h
new file mode 100644 (file)
index 0000000..13ad47b
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef _DCCP_LI_HIST_
+#define _DCCP_LI_HIST_
+/*
+ *  net/dccp/ccids/lib/loss_interval.h
+ *
+ *  Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand.
+ *  Copyright (c) 2005 Ian McDonald <iam4@cs.waikato.ac.nz>
+ *  Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *  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/list.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+
+#define DCCP_LI_HIST_IVAL_F_LENGTH  8
+
+struct dccp_li_hist {
+       kmem_cache_t *dccplih_slab;
+};
+
+extern struct dccp_li_hist *dccp_li_hist_new(const char *name);
+extern void dccp_li_hist_delete(struct dccp_li_hist *hist);
+
+struct dccp_li_hist_entry {
+       struct list_head dccplih_node;
+       u64              dccplih_seqno:48,
+                        dccplih_win_count:4;
+       u32              dccplih_interval;
+};
+
+static inline struct dccp_li_hist_entry *
+               dccp_li_hist_entry_new(struct dccp_li_hist *hist,
+                                      const unsigned int __nocast prio)
+{
+       return kmem_cache_alloc(hist->dccplih_slab, prio);
+}
+
+static inline void dccp_li_hist_entry_delete(struct dccp_li_hist *hist,
+                                            struct dccp_li_hist_entry *entry)
+{
+       if (entry != NULL)
+               kmem_cache_free(hist->dccplih_slab, entry);
+}
+
+extern void dccp_li_hist_purge(struct dccp_li_hist *hist,
+                              struct list_head *list);
+
+extern u32 dccp_li_hist_calc_i_mean(struct list_head *list);
+
+extern struct dccp_li_hist_entry *
+                       dccp_li_hist_interval_new(struct dccp_li_hist *hist,
+                                                 struct list_head *list,
+                                                 const u64 seq_loss,
+                                                 const u8 win_loss);
+#endif /* _DCCP_LI_HIST_ */
diff --git a/net/dccp/ccids/lib/packet_history.c b/net/dccp/ccids/lib/packet_history.c
new file mode 100644 (file)
index 0000000..d3f9d20
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ *  net/dccp/packet_history.h
+ *
+ *  Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand.
+ *
+ *  An implementation of the DCCP protocol
+ *
+ *  This code has been developed by the University of Waikato WAND
+ *  research group. For further information please see http://www.wand.net.nz/
+ *  or e-mail Ian McDonald - iam4@cs.waikato.ac.nz
+ *
+ *  This code also uses code from Lulea University, rereleased as GPL by its
+ *  authors:
+ *  Copyright (c) 2003 Nils-Erik Mattsson, Joacim Haggmark, Magnus Erixzon
+ *
+ *  Changes to meet Linux coding standards, to make it meet latest ccid3 draft
+ *  and to make it work as a loadable module in the DCCP stack written by
+ *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>.
+ *
+ *  Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include "packet_history.h"
+
+struct dccp_rx_hist *dccp_rx_hist_new(const char *name)
+{
+       struct dccp_rx_hist *hist = kmalloc(sizeof(*hist), GFP_ATOMIC);
+       static const char dccp_rx_hist_mask[] = "rx_hist_%s";
+       char *slab_name;
+
+       if (hist == NULL)
+               goto out;
+
+       slab_name = kmalloc(strlen(name) + sizeof(dccp_rx_hist_mask) - 1,
+                           GFP_ATOMIC);
+       if (slab_name == NULL)
+               goto out_free_hist;
+
+       sprintf(slab_name, dccp_rx_hist_mask, name);
+       hist->dccprxh_slab = kmem_cache_create(slab_name,
+                                            sizeof(struct dccp_rx_hist_entry),
+                                              0, SLAB_HWCACHE_ALIGN,
+                                              NULL, NULL);
+       if (hist->dccprxh_slab == NULL)
+               goto out_free_slab_name;
+out:
+       return hist;
+out_free_slab_name:
+       kfree(slab_name);
+out_free_hist:
+       kfree(hist);
+       hist = NULL;
+       goto out;
+}
+
+EXPORT_SYMBOL_GPL(dccp_rx_hist_new);
+
+void dccp_rx_hist_delete(struct dccp_rx_hist *hist)
+{
+       const char* name = kmem_cache_name(hist->dccprxh_slab);
+
+       kmem_cache_destroy(hist->dccprxh_slab);
+       kfree(name);
+       kfree(hist);
+}
+
+EXPORT_SYMBOL_GPL(dccp_rx_hist_delete);
+
+void dccp_rx_hist_purge(struct dccp_rx_hist *hist, struct list_head *list)
+{
+       struct dccp_rx_hist_entry *entry, *next;
+
+       list_for_each_entry_safe(entry, next, list, dccphrx_node) {
+               list_del_init(&entry->dccphrx_node);
+               kmem_cache_free(hist->dccprxh_slab, entry);
+       }
+}
+
+EXPORT_SYMBOL_GPL(dccp_rx_hist_purge);
+
+struct dccp_rx_hist_entry *
+               dccp_rx_hist_find_data_packet(const struct list_head *list)
+{
+       struct dccp_rx_hist_entry *entry, *packet = NULL;
+
+       list_for_each_entry(entry, list, dccphrx_node)
+               if (entry->dccphrx_type == DCCP_PKT_DATA ||
+                   entry->dccphrx_type == DCCP_PKT_DATAACK) {
+                       packet = entry;
+                       break;
+               }
+
+       return packet;
+}
+
+EXPORT_SYMBOL_GPL(dccp_rx_hist_find_data_packet);
+
+int dccp_rx_hist_add_packet(struct dccp_rx_hist *hist,
+                           struct list_head *rx_list,
+                           struct list_head *li_list,
+                           struct dccp_rx_hist_entry *packet)
+{
+       struct dccp_rx_hist_entry *entry, *next, *iter;
+       u8 num_later = 0;
+
+       iter = dccp_rx_hist_head(rx_list);
+       if (iter == NULL)
+               dccp_rx_hist_add_entry(rx_list, packet);
+       else {
+               const u64 seqno = packet->dccphrx_seqno;
+
+               if (after48(seqno, iter->dccphrx_seqno))
+                       dccp_rx_hist_add_entry(rx_list, packet);
+               else {
+                       if (dccp_rx_hist_entry_data_packet(iter))
+                               num_later = 1;
+
+                       list_for_each_entry_continue(iter, rx_list,
+                                                    dccphrx_node) {
+                               if (after48(seqno, iter->dccphrx_seqno)) {
+                                       dccp_rx_hist_add_entry(&iter->dccphrx_node,
+                                                              packet);
+                                       goto trim_history;
+                               }
+
+                               if (dccp_rx_hist_entry_data_packet(iter))
+                                       num_later++;
+
+                               if (num_later == TFRC_RECV_NUM_LATE_LOSS) {
+                                       dccp_rx_hist_entry_delete(hist, packet);
+                                       return 1;
+                               }
+                       }
+
+                       if (num_later < TFRC_RECV_NUM_LATE_LOSS)
+                               dccp_rx_hist_add_entry(rx_list, packet);
+                       /*
+                        * FIXME: else what? should we destroy the packet
+                        * like above?
+                        */
+               }
+       }
+
+trim_history:
+       /*
+        * Trim history (remove all packets after the NUM_LATE_LOSS + 1
+        * data packets)
+        */
+       num_later = TFRC_RECV_NUM_LATE_LOSS + 1;
+
+       if (!list_empty(li_list)) {
+               list_for_each_entry_safe(entry, next, rx_list, dccphrx_node) {
+                       if (num_later == 0) {
+                               list_del_init(&entry->dccphrx_node);
+                               dccp_rx_hist_entry_delete(hist, entry);
+                       } else if (dccp_rx_hist_entry_data_packet(entry))
+                               --num_later;
+               }
+       } else {
+               int step = 0;
+               u8 win_count = 0; /* Not needed, but lets shut up gcc */
+               int tmp;
+               /*
+                * We have no loss interval history so we need at least one
+                * rtt:s of data packets to approximate rtt.
+                */
+               list_for_each_entry_safe(entry, next, rx_list, dccphrx_node) {
+                       if (num_later == 0) {
+                               switch (step) {
+                               case 0:
+                                       step = 1;
+                                       /* OK, find next data packet */
+                                       num_later = 1;
+                                       break;
+                               case 1:
+                                       step = 2;
+                                       /* OK, find next data packet */
+                                       num_later = 1;
+                                       win_count = entry->dccphrx_ccval;
+                                       break;
+                               case 2:
+                                       tmp = win_count - entry->dccphrx_ccval;
+                                       if (tmp < 0)
+                                               tmp += TFRC_WIN_COUNT_LIMIT;
+                                       if (tmp > TFRC_WIN_COUNT_PER_RTT + 1) {
+                                               /*
+                                                * We have found a packet older
+                                                * than one rtt remove the rest
+                                                */
+                                               step = 3;
+                                       } else /* OK, find next data packet */
+                                               num_later = 1;
+                                       break;
+                               case 3:
+                                       list_del_init(&entry->dccphrx_node);
+                                       dccp_rx_hist_entry_delete(hist, entry);
+                                       break;
+                               }
+                       } else if (dccp_rx_hist_entry_data_packet(entry))
+                               --num_later;
+               }
+       }
+
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(dccp_rx_hist_add_packet);
+
+u64 dccp_rx_hist_detect_loss(struct list_head *rx_list,
+                            struct list_head *li_list, u8 *win_loss)
+{
+       struct dccp_rx_hist_entry *entry, *next, *packet;
+       struct dccp_rx_hist_entry *a_loss = NULL;
+       struct dccp_rx_hist_entry *b_loss = NULL;
+       u64 seq_loss = DCCP_MAX_SEQNO + 1;
+       u8 num_later = TFRC_RECV_NUM_LATE_LOSS;
+
+       list_for_each_entry_safe(entry, next, rx_list, dccphrx_node) {
+               if (num_later == 0) {
+                       b_loss = entry;
+                       break;
+               } else if (dccp_rx_hist_entry_data_packet(entry))
+                       --num_later;
+       }
+
+       if (b_loss == NULL)
+               goto out;
+
+       num_later = 1;
+       list_for_each_entry_safe_continue(entry, next, rx_list, dccphrx_node) {
+               if (num_later == 0) {
+                       a_loss = entry;
+                       break;
+               } else if (dccp_rx_hist_entry_data_packet(entry))
+                       --num_later;
+       }
+
+       if (a_loss == NULL) {
+               if (list_empty(li_list)) {
+                       /* no loss event have occured yet */
+                       LIMIT_NETDEBUG("%s: TODO: find a lost data packet by "
+                                      "comparing to initial seqno\n",
+                                      __FUNCTION__);
+                       goto out;
+               } else {
+                       LIMIT_NETDEBUG("%s: Less than 4 data pkts in history!",
+                                      __FUNCTION__);
+                       goto out;
+               }
+       }
+
+       /* Locate a lost data packet */
+       entry = packet = b_loss;
+       list_for_each_entry_safe_continue(entry, next, rx_list, dccphrx_node) {
+               u64 delta = dccp_delta_seqno(entry->dccphrx_seqno,
+                                            packet->dccphrx_seqno);
+
+               if (delta != 0) {
+                       if (dccp_rx_hist_entry_data_packet(packet))
+                               --delta;
+                       /*
+                        * FIXME: check this, probably this % usage is because
+                        * in earlier drafts the ndp count was just 8 bits
+                        * long, but now it cam be up to 24 bits long.
+                        */
+#if 0
+                       if (delta % DCCP_NDP_LIMIT !=
+                           (packet->dccphrx_ndp -
+                            entry->dccphrx_ndp) % DCCP_NDP_LIMIT)
+#endif
+                       if (delta != packet->dccphrx_ndp - entry->dccphrx_ndp) {
+                               seq_loss = entry->dccphrx_seqno;
+                               dccp_inc_seqno(&seq_loss);
+                       }
+               }
+               packet = entry;
+               if (packet == a_loss)
+                       break;
+       }
+out:
+       if (seq_loss != DCCP_MAX_SEQNO + 1)
+               *win_loss = a_loss->dccphrx_ccval;
+       else
+               *win_loss = 0; /* Paranoia */
+
+       return seq_loss;
+}
+
+EXPORT_SYMBOL_GPL(dccp_rx_hist_detect_loss);
+
+struct dccp_tx_hist *dccp_tx_hist_new(const char *name)
+{
+       struct dccp_tx_hist *hist = kmalloc(sizeof(*hist), GFP_ATOMIC);
+       static const char dccp_tx_hist_mask[] = "tx_hist_%s";
+       char *slab_name;
+
+       if (hist == NULL)
+               goto out;
+
+       slab_name = kmalloc(strlen(name) + sizeof(dccp_tx_hist_mask) - 1,
+                           GFP_ATOMIC);
+       if (slab_name == NULL)
+               goto out_free_hist;
+
+       sprintf(slab_name, dccp_tx_hist_mask, name);
+       hist->dccptxh_slab = kmem_cache_create(slab_name,
+                                            sizeof(struct dccp_tx_hist_entry),
+                                              0, SLAB_HWCACHE_ALIGN,
+                                              NULL, NULL);
+       if (hist->dccptxh_slab == NULL)
+               goto out_free_slab_name;
+out:
+       return hist;
+out_free_slab_name:
+       kfree(slab_name);
+out_free_hist:
+       kfree(hist);
+       hist = NULL;
+       goto out;
+}
+
+EXPORT_SYMBOL_GPL(dccp_tx_hist_new);
+
+void dccp_tx_hist_delete(struct dccp_tx_hist *hist)
+{
+       const char* name = kmem_cache_name(hist->dccptxh_slab);
+
+       kmem_cache_destroy(hist->dccptxh_slab);
+       kfree(name);
+       kfree(hist);
+}
+
+EXPORT_SYMBOL_GPL(dccp_tx_hist_delete);
+
+struct dccp_tx_hist_entry *
+       dccp_tx_hist_find_entry(const struct list_head *list, const u64 seq)
+{
+       struct dccp_tx_hist_entry *packet = NULL, *entry;
+
+       list_for_each_entry(entry, list, dccphtx_node)
+               if (entry->dccphtx_seqno == seq) {
+                       packet = entry;
+                       break;
+               }
+
+       return packet;
+}
+
+EXPORT_SYMBOL_GPL(dccp_tx_hist_find_entry);
+
+void dccp_tx_hist_purge_older(struct dccp_tx_hist *hist,
+                             struct list_head *list,
+                             struct dccp_tx_hist_entry *packet)
+{
+       struct dccp_tx_hist_entry *next;
+
+       list_for_each_entry_safe_continue(packet, next, list, dccphtx_node) {
+               list_del_init(&packet->dccphtx_node);
+               dccp_tx_hist_entry_delete(hist, packet);
+       }
+}
+
+EXPORT_SYMBOL_GPL(dccp_tx_hist_purge_older);
+
+void dccp_tx_hist_purge(struct dccp_tx_hist *hist, struct list_head *list)
+{
+       struct dccp_tx_hist_entry *entry, *next;
+
+       list_for_each_entry_safe(entry, next, list, dccphtx_node) {
+               list_del_init(&entry->dccphtx_node);
+               dccp_tx_hist_entry_delete(hist, entry);
+       }
+}
+
+EXPORT_SYMBOL_GPL(dccp_tx_hist_purge);
+
+MODULE_AUTHOR("Ian McDonald <iam4@cs.waikato.ac.nz>, "
+             "Arnaldo Carvalho de Melo <acme@ghostprotocols.net>");
+MODULE_DESCRIPTION("DCCP TFRC library");
+MODULE_LICENSE("GPL");
diff --git a/net/dccp/ccids/lib/packet_history.h b/net/dccp/ccids/lib/packet_history.h
new file mode 100644 (file)
index 0000000..fb90a91
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ *  net/dccp/packet_history.h
+ *
+ *  Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand.
+ *
+ *  An implementation of the DCCP protocol
+ *
+ *  This code has been developed by the University of Waikato WAND
+ *  research group. For further information please see http://www.wand.net.nz/
+ *  or e-mail Ian McDonald - iam4@cs.waikato.ac.nz
+ *
+ *  This code also uses code from Lulea University, rereleased as GPL by its
+ *  authors:
+ *  Copyright (c) 2003 Nils-Erik Mattsson, Joacim Haggmark, Magnus Erixzon
+ *
+ *  Changes to meet Linux coding standards, to make it meet latest ccid3 draft
+ *  and to make it work as a loadable module in the DCCP stack written by
+ *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>.
+ *
+ *  Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _DCCP_PKT_HIST_
+#define _DCCP_PKT_HIST_
+
+#include <linux/config.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+
+#include "../../dccp.h"
+
+/* Number of later packets received before one is considered lost */
+#define TFRC_RECV_NUM_LATE_LOSS         3
+
+#define TFRC_WIN_COUNT_PER_RTT  4
+#define TFRC_WIN_COUNT_LIMIT   16
+
+struct dccp_tx_hist_entry {
+       struct list_head dccphtx_node;
+       u64              dccphtx_seqno:48,
+                        dccphtx_ccval:4,
+                        dccphtx_sent:1;
+       u32              dccphtx_rtt;
+       struct timeval   dccphtx_tstamp;
+};
+
+struct dccp_rx_hist_entry {
+       struct list_head dccphrx_node;
+       u64              dccphrx_seqno:48,
+                        dccphrx_ccval:4,
+                        dccphrx_type:4;
+       u32              dccphrx_ndp; /* In fact it is from 8 to 24 bits */
+       struct timeval   dccphrx_tstamp;
+};
+
+struct dccp_tx_hist {
+       kmem_cache_t *dccptxh_slab;
+};
+
+extern struct dccp_tx_hist *dccp_tx_hist_new(const char *name);
+extern void dccp_tx_hist_delete(struct dccp_tx_hist *hist);
+
+struct dccp_rx_hist {
+       kmem_cache_t *dccprxh_slab;
+};
+
+extern struct dccp_rx_hist *dccp_rx_hist_new(const char *name);
+extern void dccp_rx_hist_delete(struct dccp_rx_hist *hist);
+extern struct dccp_rx_hist_entry *
+               dccp_rx_hist_find_data_packet(const struct list_head *list);
+
+static inline struct dccp_tx_hist_entry *
+               dccp_tx_hist_entry_new(struct dccp_tx_hist *hist,
+                                      const unsigned int __nocast prio)
+{
+       struct dccp_tx_hist_entry *entry = kmem_cache_alloc(hist->dccptxh_slab,
+                                                           prio);
+
+       if (entry != NULL)
+               entry->dccphtx_sent = 0;
+
+       return entry;
+}
+
+static inline void dccp_tx_hist_entry_delete(struct dccp_tx_hist *hist,
+                                            struct dccp_tx_hist_entry *entry)
+{
+       if (entry != NULL)
+               kmem_cache_free(hist->dccptxh_slab, entry);
+}
+
+extern struct dccp_tx_hist_entry *
+                       dccp_tx_hist_find_entry(const struct list_head *list,
+                                               const u64 seq);
+
+static inline void dccp_tx_hist_add_entry(struct list_head *list,
+                                         struct dccp_tx_hist_entry *entry)
+{
+       list_add(&entry->dccphtx_node, list);
+}
+
+extern void dccp_tx_hist_purge_older(struct dccp_tx_hist *hist,
+                                    struct list_head *list,
+                                    struct dccp_tx_hist_entry *next);
+
+extern void dccp_tx_hist_purge(struct dccp_tx_hist *hist,
+                              struct list_head *list);
+
+static inline struct dccp_tx_hist_entry *
+               dccp_tx_hist_head(struct list_head *list)
+{
+       struct dccp_tx_hist_entry *head = NULL;
+
+       if (!list_empty(list))
+               head = list_entry(list->next, struct dccp_tx_hist_entry,
+                                 dccphtx_node);
+       return head;
+}
+
+static inline struct dccp_rx_hist_entry *
+                    dccp_rx_hist_entry_new(struct dccp_rx_hist *hist,
+                                           const u32 ndp, 
+                                           const struct sk_buff *skb,
+                                           const unsigned int __nocast prio)
+{
+       struct dccp_rx_hist_entry *entry = kmem_cache_alloc(hist->dccprxh_slab,
+                                                           prio);
+
+       if (entry != NULL) {
+               const struct dccp_hdr *dh = dccp_hdr(skb);
+
+               entry->dccphrx_seqno = DCCP_SKB_CB(skb)->dccpd_seq;
+               entry->dccphrx_ccval = dh->dccph_ccval;
+               entry->dccphrx_type  = dh->dccph_type;
+               entry->dccphrx_ndp   = ndp;
+               do_gettimeofday(&(entry->dccphrx_tstamp));
+       }
+
+       return entry;
+}
+
+static inline void dccp_rx_hist_entry_delete(struct dccp_rx_hist *hist,
+                                            struct dccp_rx_hist_entry *entry)
+{
+       if (entry != NULL)
+               kmem_cache_free(hist->dccprxh_slab, entry);
+}
+
+extern void dccp_rx_hist_purge(struct dccp_rx_hist *hist,
+                              struct list_head *list);
+
+static inline void dccp_rx_hist_add_entry(struct list_head *list,
+                                         struct dccp_rx_hist_entry *entry)
+{
+       list_add(&entry->dccphrx_node, list);
+}
+
+static inline struct dccp_rx_hist_entry *
+               dccp_rx_hist_head(struct list_head *list)
+{
+       struct dccp_rx_hist_entry *head = NULL;
+
+       if (!list_empty(list))
+               head = list_entry(list->next, struct dccp_rx_hist_entry,
+                                 dccphrx_node);
+       return head;
+}
+
+static inline int
+       dccp_rx_hist_entry_data_packet(const struct dccp_rx_hist_entry *entry)
+{
+       return entry->dccphrx_type == DCCP_PKT_DATA ||
+              entry->dccphrx_type == DCCP_PKT_DATAACK;
+}
+
+extern int dccp_rx_hist_add_packet(struct dccp_rx_hist *hist,
+                                  struct list_head *rx_list,
+                                  struct list_head *li_list,
+                                  struct dccp_rx_hist_entry *packet);
+
+extern u64 dccp_rx_hist_detect_loss(struct list_head *rx_list,
+                                   struct list_head *li_list, u8 *win_loss);
+
+#endif /* _DCCP_PKT_HIST_ */
diff --git a/net/dccp/ccids/lib/tfrc.h b/net/dccp/ccids/lib/tfrc.h
new file mode 100644 (file)
index 0000000..130c4c4
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _TFRC_H_
+#define _TFRC_H_
+/*
+ *  net/dccp/ccids/lib/tfrc.h
+ *
+ *  Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand.
+ *  Copyright (c) 2005 Ian McDonald <iam4@cs.waikato.ac.nz>
+ *  Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *  Copyright (c) 2003 Nils-Erik Mattsson, Joacim Haggmark, Magnus Erixzon
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ */
+
+#include <linux/types.h>
+
+extern u32 tfrc_calc_x(u16 s, u32 R, u32 p);
+extern u32 tfrc_calc_x_reverse_lookup(u32 fvalue);
+
+#endif /* _TFRC_H_ */
diff --git a/net/dccp/ccids/lib/tfrc_equation.c b/net/dccp/ccids/lib/tfrc_equation.c
new file mode 100644 (file)
index 0000000..d2b5933
--- /dev/null
@@ -0,0 +1,644 @@
+/*
+ *  net/dccp/ccids/lib/tfrc_equation.c
+ *
+ *  Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand.
+ *  Copyright (c) 2005 Ian McDonald <iam4@cs.waikato.ac.nz>
+ *  Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *  Copyright (c) 2003 Nils-Erik Mattsson, Joacim Haggmark, Magnus Erixzon
+ *
+ *  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/module.h>
+
+#include <asm/bug.h>
+#include <asm/div64.h>
+
+#include "tfrc.h"
+
+#define TFRC_CALC_X_ARRSIZE 500
+
+#define TFRC_CALC_X_SPLIT 50000
+/* equivalent to 0.05 */
+
+static const u32 tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE][2] = {
+       {     37172,   8172 },
+       {     53499,  11567 },
+       {     66664,  14180 },
+       {     78298,  16388 },
+       {     89021,  18339 },
+       {     99147,  20108 },
+       {    108858,  21738 },
+       {    118273,  23260 },
+       {    127474,  24693 },
+       {    136520,  26052 },
+       {    145456,  27348 },
+       {    154316,  28589 },
+       {    163130,  29783 },
+       {    171919,  30935 },
+       {    180704,  32049 },
+       {    189502,  33130 },
+       {    198328,  34180 },
+       {    207194,  35202 },
+       {    216114,  36198 },
+       {    225097,  37172 },
+       {    234153,  38123 },
+       {    243294,  39055 },
+       {    252527,  39968 },
+       {    261861,  40864 },
+       {    271305,  41743 },
+       {    280866,  42607 },
+       {    290553,  43457 },
+       {    300372,  44293 },
+       {    310333,  45117 },
+       {    320441,  45929 },
+       {    330705,  46729 },
+       {    341131,  47518 },
+       {    351728,  48297 },
+       {    362501,  49066 },
+       {    373460,  49826 },
+       {    384609,  50577 },
+       {    395958,  51320 },
+       {    407513,  52054 },
+       {    419281,  52780 },
+       {    431270,  53499 },
+       {    443487,  54211 },
+       {    455940,  54916 },
+       {    468635,  55614 },
+       {    481581,  56306 },
+       {    494785,  56991 },
+       {    508254,  57671 },
+       {    521996,  58345 },
+       {    536019,  59014 },
+       {    550331,  59677 },
+       {    564939,  60335 },
+       {    579851,  60988 },
+       {    595075,  61636 },
+       {    610619,  62279 },
+       {    626491,  62918 },
+       {    642700,  63553 },
+       {    659253,  64183 },
+       {    676158,  64809 },
+       {    693424,  65431 },
+       {    711060,  66050 },
+       {    729073,  66664 },
+       {    747472,  67275 },
+       {    766266,  67882 },
+       {    785464,  68486 },
+       {    805073,  69087 },
+       {    825103,  69684 },
+       {    845562,  70278 },
+       {    866460,  70868 },
+       {    887805,  71456 },
+       {    909606,  72041 },
+       {    931873,  72623 },
+       {    954614,  73202 },
+       {    977839,  73778 },
+       {   1001557,  74352 },
+       {   1025777,  74923 },
+       {   1050508,  75492 },
+       {   1075761,  76058 },
+       {   1101544,  76621 },
+       {   1127867,  77183 },
+       {   1154739,  77741 },
+       {   1182172,  78298 },
+       {   1210173,  78852 },
+       {   1238753,  79405 },
+       {   1267922,  79955 },
+       {   1297689,  80503 },
+       {   1328066,  81049 },
+       {   1359060,  81593 },
+       {   1390684,  82135 },
+       {   1422947,  82675 },
+       {   1455859,  83213 },
+       {   1489430,  83750 },
+       {   1523671,  84284 },
+       {   1558593,  84817 },
+       {   1594205,  85348 },
+       {   1630518,  85878 },
+       {   1667543,  86406 },
+       {   1705290,  86932 },
+       {   1743770,  87457 },
+       {   1782994,  87980 },
+       {   1822973,  88501 },
+       {   1863717,  89021 },
+       {   1905237,  89540 },
+       {   1947545,  90057 },
+       {   1990650,  90573 },
+       {   2034566,  91087 },
+       {   2079301,  91600 },
+       {   2124869,  92111 },
+       {   2171279,  92622 },
+       {   2218543,  93131 },
+       {   2266673,  93639 },
+       {   2315680,  94145 },
+       {   2365575,  94650 },
+       {   2416371,  95154 },
+       {   2468077,  95657 },
+       {   2520707,  96159 },
+       {   2574271,  96660 },
+       {   2628782,  97159 },
+       {   2684250,  97658 },
+       {   2740689,  98155 },
+       {   2798110,  98651 },
+       {   2856524,  99147 },
+       {   2915944,  99641 },
+       {   2976382, 100134 },
+       {   3037850, 100626 },
+       {   3100360, 101117 },
+       {   3163924, 101608 },
+       {   3228554, 102097 },
+       {   3294263, 102586 },
+       {   3361063, 103073 },
+       {   3428966, 103560 },
+       {   3497984, 104045 },
+       {   3568131, 104530 },
+       {   3639419, 105014 },
+       {   3711860, 105498 },
+       {   3785467, 105980 },
+       {   3860253, 106462 },
+       {   3936229, 106942 },
+       {   4013410, 107422 },
+       {   4091808, 107902 },
+       {   4171435, 108380 },
+       {   4252306, 108858 },
+       {   4334431, 109335 },
+       {   4417825, 109811 },
+       {   4502501, 110287 },
+       {   4588472, 110762 },
+       {   4675750, 111236 },
+       {   4764349, 111709 },
+       {   4854283, 112182 },
+       {   4945564, 112654 },
+       {   5038206, 113126 },
+       {   5132223, 113597 },
+       {   5227627, 114067 },
+       {   5324432, 114537 },
+       {   5422652, 115006 },
+       {   5522299, 115474 },
+       {   5623389, 115942 },
+       {   5725934, 116409 },
+       {   5829948, 116876 },
+       {   5935446, 117342 },
+       {   6042439, 117808 },
+       {   6150943, 118273 },
+       {   6260972, 118738 },
+       {   6372538, 119202 },
+       {   6485657, 119665 },
+       {   6600342, 120128 },
+       {   6716607, 120591 },
+       {   6834467, 121053 },
+       {   6953935, 121514 },
+       {   7075025, 121976 },
+       {   7197752, 122436 },
+       {   7322131, 122896 },
+       {   7448175, 123356 },
+       {   7575898, 123815 },
+       {   7705316, 124274 },
+       {   7836442, 124733 },
+       {   7969291, 125191 },
+       {   8103877, 125648 },
+       {   8240216, 126105 },
+       {   8378321, 126562 },
+       {   8518208, 127018 },
+       {   8659890, 127474 },
+       {   8803384, 127930 },
+       {   8948702, 128385 },
+       {   9095861, 128840 },
+       {   9244875, 129294 },
+       {   9395760, 129748 },
+       {   9548529, 130202 },
+       {   9703198, 130655 },
+       {   9859782, 131108 },
+       {  10018296, 131561 },
+       {  10178755, 132014 },
+       {  10341174, 132466 },
+       {  10505569, 132917 },
+       {  10671954, 133369 },
+       {  10840345, 133820 },
+       {  11010757, 134271 },
+       {  11183206, 134721 },
+       {  11357706, 135171 },
+       {  11534274, 135621 },
+       {  11712924, 136071 },
+       {  11893673, 136520 },
+       {  12076536, 136969 },
+       {  12261527, 137418 },
+       {  12448664, 137867 },
+       {  12637961, 138315 },
+       {  12829435, 138763 },
+       {  13023101, 139211 },
+       {  13218974, 139658 },
+       {  13417071, 140106 },
+       {  13617407, 140553 },
+       {  13819999, 140999 },
+       {  14024862, 141446 },
+       {  14232012, 141892 },
+       {  14441465, 142339 },
+       {  14653238, 142785 },
+       {  14867346, 143230 },
+       {  15083805, 143676 },
+       {  15302632, 144121 },
+       {  15523842, 144566 },
+       {  15747453, 145011 },
+       {  15973479, 145456 },
+       {  16201939, 145900 },
+       {  16432847, 146345 },
+       {  16666221, 146789 },
+       {  16902076, 147233 },
+       {  17140429, 147677 },
+       {  17381297, 148121 },
+       {  17624696, 148564 },
+       {  17870643, 149007 },
+       {  18119154, 149451 },
+       {  18370247, 149894 },
+       {  18623936, 150336 },
+       {  18880241, 150779 },
+       {  19139176, 151222 },
+       {  19400759, 151664 },
+       {  19665007, 152107 },
+       {  19931936, 152549 },
+       {  20201564, 152991 },
+       {  20473907, 153433 },
+       {  20748982, 153875 },
+       {  21026807, 154316 },
+       {  21307399, 154758 },
+       {  21590773, 155199 },
+       {  21876949, 155641 },
+       {  22165941, 156082 },
+       {  22457769, 156523 },
+       {  22752449, 156964 },
+       {  23049999, 157405 },
+       {  23350435, 157846 },
+       {  23653774, 158287 },
+       {  23960036, 158727 },
+       {  24269236, 159168 },
+       {  24581392, 159608 },
+       {  24896521, 160049 },
+       {  25214642, 160489 },
+       {  25535772, 160929 },
+       {  25859927, 161370 },
+       {  26187127, 161810 },
+       {  26517388, 162250 },
+       {  26850728, 162690 },
+       {  27187165, 163130 },
+       {  27526716, 163569 },
+       {  27869400, 164009 },
+       {  28215234, 164449 },
+       {  28564236, 164889 },
+       {  28916423, 165328 },
+       {  29271815, 165768 },
+       {  29630428, 166208 },
+       {  29992281, 166647 },
+       {  30357392, 167087 },
+       {  30725779, 167526 },
+       {  31097459, 167965 },
+       {  31472452, 168405 },
+       {  31850774, 168844 },
+       {  32232445, 169283 },
+       {  32617482, 169723 },
+       {  33005904, 170162 },
+       {  33397730, 170601 },
+       {  33792976, 171041 },
+       {  34191663, 171480 },
+       {  34593807, 171919 },
+       {  34999428, 172358 },
+       {  35408544, 172797 },
+       {  35821174, 173237 },
+       {  36237335, 173676 },
+       {  36657047, 174115 },
+       {  37080329, 174554 },
+       {  37507197, 174993 },
+       {  37937673, 175433 },
+       {  38371773, 175872 },
+       {  38809517, 176311 },
+       {  39250924, 176750 },
+       {  39696012, 177190 },
+       {  40144800, 177629 },
+       {  40597308, 178068 },
+       {  41053553, 178507 },
+       {  41513554, 178947 },
+       {  41977332, 179386 },
+       {  42444904, 179825 },
+       {  42916290, 180265 },
+       {  43391509, 180704 },
+       {  43870579, 181144 },
+       {  44353520, 181583 },
+       {  44840352, 182023 },
+       {  45331092, 182462 },
+       {  45825761, 182902 },
+       {  46324378, 183342 },
+       {  46826961, 183781 },
+       {  47333531, 184221 },
+       {  47844106, 184661 },
+       {  48358706, 185101 },
+       {  48877350, 185541 },
+       {  49400058, 185981 },
+       {  49926849, 186421 },
+       {  50457743, 186861 },
+       {  50992759, 187301 },
+       {  51531916, 187741 },
+       {  52075235, 188181 },
+       {  52622735, 188622 },
+       {  53174435, 189062 },
+       {  53730355, 189502 },
+       {  54290515, 189943 },
+       {  54854935, 190383 },
+       {  55423634, 190824 },
+       {  55996633, 191265 },
+       {  56573950, 191706 },
+       {  57155606, 192146 },
+       {  57741621, 192587 },
+       {  58332014, 193028 },
+       {  58926806, 193470 },
+       {  59526017, 193911 },
+       {  60129666, 194352 },
+       {  60737774, 194793 },
+       {  61350361, 195235 },
+       {  61967446, 195677 },
+       {  62589050, 196118 },
+       {  63215194, 196560 },
+       {  63845897, 197002 },
+       {  64481179, 197444 },
+       {  65121061, 197886 },
+       {  65765563, 198328 },
+       {  66414705, 198770 },
+       {  67068508, 199213 },
+       {  67726992, 199655 },
+       {  68390177, 200098 },
+       {  69058085, 200540 },
+       {  69730735, 200983 },
+       {  70408147, 201426 },
+       {  71090343, 201869 },
+       {  71777343, 202312 },
+       {  72469168, 202755 },
+       {  73165837, 203199 },
+       {  73867373, 203642 },
+       {  74573795, 204086 },
+       {  75285124, 204529 },
+       {  76001380, 204973 },
+       {  76722586, 205417 },
+       {  77448761, 205861 },
+       {  78179926, 206306 },
+       {  78916102, 206750 },
+       {  79657310, 207194 },
+       {  80403571, 207639 },
+       {  81154906, 208084 },
+       {  81911335, 208529 },
+       {  82672880, 208974 },
+       {  83439562, 209419 },
+       {  84211402, 209864 },
+       {  84988421, 210309 },
+       {  85770640, 210755 },
+       {  86558080, 211201 },
+       {  87350762, 211647 },
+       {  88148708, 212093 },
+       {  88951938, 212539 },
+       {  89760475, 212985 },
+       {  90574339, 213432 },
+       {  91393551, 213878 },
+       {  92218133, 214325 },
+       {  93048107, 214772 },
+       {  93883493, 215219 },
+       {  94724314, 215666 },
+       {  95570590, 216114 },
+       {  96422343, 216561 },
+       {  97279594, 217009 },
+       {  98142366, 217457 },
+       {  99010679, 217905 },
+       {  99884556, 218353 },
+       { 100764018, 218801 },
+       { 101649086, 219250 },
+       { 102539782, 219698 },
+       { 103436128, 220147 },
+       { 104338146, 220596 },
+       { 105245857, 221046 },
+       { 106159284, 221495 },
+       { 107078448, 221945 },
+       { 108003370, 222394 },
+       { 108934074, 222844 },
+       { 109870580, 223294 },
+       { 110812910, 223745 },
+       { 111761087, 224195 },
+       { 112715133, 224646 },
+       { 113675069, 225097 },
+       { 114640918, 225548 },
+       { 115612702, 225999 },
+       { 116590442, 226450 },
+       { 117574162, 226902 },
+       { 118563882, 227353 },
+       { 119559626, 227805 },
+       { 120561415, 228258 },
+       { 121569272, 228710 },
+       { 122583219, 229162 },
+       { 123603278, 229615 },
+       { 124629471, 230068 },
+       { 125661822, 230521 },
+       { 126700352, 230974 },
+       { 127745083, 231428 },
+       { 128796039, 231882 },
+       { 129853241, 232336 },
+       { 130916713, 232790 },
+       { 131986475, 233244 },
+       { 133062553, 233699 },
+       { 134144966, 234153 },
+       { 135233739, 234608 },
+       { 136328894, 235064 },
+       { 137430453, 235519 },
+       { 138538440, 235975 },
+       { 139652876, 236430 },
+       { 140773786, 236886 },
+       { 141901190, 237343 },
+       { 143035113, 237799 },
+       { 144175576, 238256 },
+       { 145322604, 238713 },
+       { 146476218, 239170 },
+       { 147636442, 239627 },
+       { 148803298, 240085 },
+       { 149976809, 240542 },
+       { 151156999, 241000 },
+       { 152343890, 241459 },
+       { 153537506, 241917 },
+       { 154737869, 242376 },
+       { 155945002, 242835 },
+       { 157158929, 243294 },
+       { 158379673, 243753 },
+       { 159607257, 244213 },
+       { 160841704, 244673 },
+       { 162083037, 245133 },
+       { 163331279, 245593 },
+       { 164586455, 246054 },
+       { 165848586, 246514 },
+       { 167117696, 246975 },
+       { 168393810, 247437 },
+       { 169676949, 247898 },
+       { 170967138, 248360 },
+       { 172264399, 248822 },
+       { 173568757, 249284 },
+       { 174880235, 249747 },
+       { 176198856, 250209 },
+       { 177524643, 250672 },
+       { 178857621, 251136 },
+       { 180197813, 251599 },
+       { 181545242, 252063 },
+       { 182899933, 252527 },
+       { 184261908, 252991 },
+       { 185631191, 253456 },
+       { 187007807, 253920 },
+       { 188391778, 254385 },
+       { 189783129, 254851 },
+       { 191181884, 255316 },
+       { 192588065, 255782 },
+       { 194001698, 256248 },
+       { 195422805, 256714 },
+       { 196851411, 257181 },
+       { 198287540, 257648 },
+       { 199731215, 258115 },
+       { 201182461, 258582 },
+       { 202641302, 259050 },
+       { 204107760, 259518 },
+       { 205581862, 259986 },
+       { 207063630, 260454 },
+       { 208553088, 260923 },
+       { 210050262, 261392 },
+       { 211555174, 261861 },
+       { 213067849, 262331 },
+       { 214588312, 262800 },
+       { 216116586, 263270 },
+       { 217652696, 263741 },
+       { 219196666, 264211 },
+       { 220748520, 264682 },
+       { 222308282, 265153 },
+       { 223875978, 265625 },
+       { 225451630, 266097 },
+       { 227035265, 266569 },
+       { 228626905, 267041 },
+       { 230226576, 267514 },
+       { 231834302, 267986 },
+       { 233450107, 268460 },
+       { 235074016, 268933 },
+       { 236706054, 269407 },
+       { 238346244, 269881 },
+       { 239994613, 270355 },
+       { 241651183, 270830 },
+       { 243315981, 271305 }
+};
+
+/* Calculate the send rate as per section 3.1 of RFC3448
+Returns send rate in bytes per second
+
+Integer maths and lookups are used as not allowed floating point in kernel
+
+The function for Xcalc as per section 3.1 of RFC3448 is:
+
+X =                            s
+     -------------------------------------------------------------
+     R*sqrt(2*b*p/3) + (t_RTO * (3*sqrt(3*b*p/8) * p * (1+32*p^2)))
+
+where 
+X is the trasmit rate in bytes/second
+s is the packet size in bytes
+R is the round trip time in seconds
+p is the loss event rate, between 0 and 1.0, of the number of loss events 
+  as a fraction of the number of packets transmitted
+t_RTO is the TCP retransmission timeout value in seconds
+b is the number of packets acknowledged by a single TCP acknowledgement
+
+we can assume that b = 1 and t_RTO is 4 * R. With this the equation becomes:
+
+X =                            s
+     -----------------------------------------------------------------------
+     R * sqrt(2 * p / 3) + (12 * R * (sqrt(3 * p / 8) * p * (1 + 32 * p^2)))
+
+
+which we can break down into:
+
+X =     s
+     --------
+     R * f(p)
+
+where f(p) = sqrt(2 * p / 3) + (12 * sqrt(3 * p / 8) * p * (1 + 32 * p * p))
+
+Function parameters:
+s - bytes
+R - RTT in usecs
+p - loss rate (decimal fraction multiplied by 1,000,000)
+
+Returns Xcalc in bytes per second
+
+DON'T alter this code unless you run test cases against it as the code
+has been manipulated to stop underflow/overlow.
+
+*/
+u32 tfrc_calc_x(u16 s, u32 R, u32 p)
+{
+       int index;
+       u32 f;
+       u64 tmp1, tmp2;
+
+       if (p < TFRC_CALC_X_SPLIT)
+               index = (p / (TFRC_CALC_X_SPLIT / TFRC_CALC_X_ARRSIZE)) - 1;
+       else
+               index = (p / (1000000 / TFRC_CALC_X_ARRSIZE)) - 1;
+
+       if (index < 0)
+               /* p should be 0 unless there is a bug in my code */
+               index = 0;
+
+       if (R == 0)
+               R = 1; /* RTT can't be zero or else divide by zero */
+
+       BUG_ON(index >= TFRC_CALC_X_ARRSIZE);
+
+       if (p >= TFRC_CALC_X_SPLIT)
+               f = tfrc_calc_x_lookup[index][0];
+       else
+               f = tfrc_calc_x_lookup[index][1];
+
+       tmp1 = ((u64)s * 100000000);
+       tmp2 = ((u64)R * (u64)f);
+       do_div(tmp2, 10000);
+       do_div(tmp1, tmp2); 
+       /* Don't alter above math unless you test due to overflow on 32 bit */
+
+       return (u32)tmp1; 
+}
+
+EXPORT_SYMBOL_GPL(tfrc_calc_x);
+
+/*
+ * args: fvalue - function value to match
+ * returns: p closest to that value
+ *
+ * both fvalue and p are multiplied by 1,000,000 to use ints
+ */
+u32 tfrc_calc_x_reverse_lookup(u32 fvalue)
+{
+       int ctr = 0;
+       int small;
+
+       if (fvalue < tfrc_calc_x_lookup[0][1])
+               return 0;
+
+       if (fvalue <= tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][1])
+               small = 1;
+       else if (fvalue > tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][0])
+               return 1000000;
+       else
+               small = 0;
+
+       while (fvalue > tfrc_calc_x_lookup[ctr][small])
+               ctr++;
+
+       if (small)
+               return TFRC_CALC_X_SPLIT * ctr / TFRC_CALC_X_ARRSIZE;
+       else
+               return 1000000 * ctr / TFRC_CALC_X_ARRSIZE;
+}
+
+EXPORT_SYMBOL_GPL(tfrc_calc_x_reverse_lookup);
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
new file mode 100644 (file)
index 0000000..33456c0
--- /dev/null
@@ -0,0 +1,493 @@
+#ifndef _DCCP_H
+#define _DCCP_H
+/*
+ *  net/dccp/dccp.h
+ *
+ *  An implementation of the DCCP protocol
+ *  Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *  Copyright (c) 2005 Ian McDonald <iam4@cs.waikato.ac.nz>
+ *
+ *     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/config.h>
+#include <linux/dccp.h>
+#include <net/snmp.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+
+#ifdef CONFIG_IP_DCCP_DEBUG
+extern int dccp_debug;
+
+#define dccp_pr_debug(format, a...) \
+       do { if (dccp_debug) \
+               printk(KERN_DEBUG "%s: " format, __FUNCTION__ , ##a); \
+       } while (0)
+#define dccp_pr_debug_cat(format, a...) do { if (dccp_debug) \
+                                            printk(format, ##a); } while (0)
+#else
+#define dccp_pr_debug(format, a...)
+#define dccp_pr_debug_cat(format, a...)
+#endif
+
+extern struct inet_hashinfo dccp_hashinfo;
+
+extern atomic_t dccp_orphan_count;
+extern int dccp_tw_count;
+extern void dccp_tw_deschedule(struct inet_timewait_sock *tw);
+
+extern void dccp_time_wait(struct sock *sk, int state, int timeo);
+
+/* FIXME: Right size this */
+#define DCCP_MAX_OPT_LEN 128
+
+#define DCCP_MAX_PACKET_HDR 32
+
+#define MAX_DCCP_HEADER  (DCCP_MAX_PACKET_HDR + DCCP_MAX_OPT_LEN + MAX_HEADER)
+
+#define DCCP_TIMEWAIT_LEN (60 * HZ) /* how long to wait to destroy TIME-WAIT
+                                    * state, about 60 seconds */
+
+/* draft-ietf-dccp-spec-11.txt initial RTO value */
+#define DCCP_TIMEOUT_INIT ((unsigned)(3 * HZ))
+
+/* Maximal interval between probes for local resources.  */
+#define DCCP_RESOURCE_PROBE_INTERVAL ((unsigned)(HZ / 2U))
+
+#define DCCP_RTO_MAX ((unsigned)(120 * HZ)) /* FIXME: using TCP value */
+
+extern struct proto dccp_v4_prot;
+
+/* is seq1 < seq2 ? */
+static inline int before48(const u64 seq1, const u64 seq2)
+{
+       return (s64)((seq1 << 16) - (seq2 << 16)) < 0;
+}
+
+/* is seq1 > seq2 ? */
+static inline int after48(const u64 seq1, const u64 seq2)
+{
+       return (s64)((seq2 << 16) - (seq1 << 16)) < 0;
+}
+
+/* is seq2 <= seq1 <= seq3 ? */
+static inline int between48(const u64 seq1, const u64 seq2, const u64 seq3)
+{
+       return (seq3 << 16) - (seq2 << 16) >= (seq1 << 16) - (seq2 << 16);
+}
+
+static inline u64 max48(const u64 seq1, const u64 seq2)
+{
+       return after48(seq1, seq2) ? seq1 : seq2;
+}
+
+enum {
+       DCCP_MIB_NUM = 0,
+       DCCP_MIB_ACTIVEOPENS,                   /* ActiveOpens */
+       DCCP_MIB_ESTABRESETS,                   /* EstabResets */
+       DCCP_MIB_CURRESTAB,                     /* CurrEstab */
+       DCCP_MIB_OUTSEGS,                       /* OutSegs */ 
+       DCCP_MIB_OUTRSTS,
+       DCCP_MIB_ABORTONTIMEOUT,
+       DCCP_MIB_TIMEOUTS,
+       DCCP_MIB_ABORTFAILED,
+       DCCP_MIB_PASSIVEOPENS,
+       DCCP_MIB_ATTEMPTFAILS,
+       DCCP_MIB_OUTDATAGRAMS,
+       DCCP_MIB_INERRS,
+       DCCP_MIB_OPTMANDATORYERROR,
+       DCCP_MIB_INVALIDOPT,
+       __DCCP_MIB_MAX
+};
+
+#define DCCP_MIB_MAX   __DCCP_MIB_MAX
+struct dccp_mib {
+       unsigned long   mibs[DCCP_MIB_MAX];
+} __SNMP_MIB_ALIGN__;
+
+DECLARE_SNMP_STAT(struct dccp_mib, dccp_statistics);
+#define DCCP_INC_STATS(field)      SNMP_INC_STATS(dccp_statistics, field)
+#define DCCP_INC_STATS_BH(field)    SNMP_INC_STATS_BH(dccp_statistics, field)
+#define DCCP_INC_STATS_USER(field)  SNMP_INC_STATS_USER(dccp_statistics, field)
+#define DCCP_DEC_STATS(field)      SNMP_DEC_STATS(dccp_statistics, field)
+#define DCCP_ADD_STATS_BH(field, val) \
+                       SNMP_ADD_STATS_BH(dccp_statistics, field, val)
+#define DCCP_ADD_STATS_USER(field, val)        \
+                       SNMP_ADD_STATS_USER(dccp_statistics, field, val)
+
+extern int  dccp_transmit_skb(struct sock *sk, struct sk_buff *skb);
+extern int  dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb);
+
+extern int dccp_send_response(struct sock *sk);
+extern void dccp_send_ack(struct sock *sk);
+extern void dccp_send_delayed_ack(struct sock *sk);
+extern void dccp_send_sync(struct sock *sk, const u64 seq,
+                          const enum dccp_pkt_type pkt_type);
+
+extern int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo);
+extern void dccp_write_space(struct sock *sk);
+
+extern void dccp_init_xmit_timers(struct sock *sk);
+static inline void dccp_clear_xmit_timers(struct sock *sk)
+{
+       inet_csk_clear_xmit_timers(sk);
+}
+
+extern unsigned int dccp_sync_mss(struct sock *sk, u32 pmtu);
+
+extern const char *dccp_packet_name(const int type);
+extern const char *dccp_state_name(const int state);
+
+static inline void dccp_set_state(struct sock *sk, const int state)
+{
+       const int oldstate = sk->sk_state;
+
+       dccp_pr_debug("%s(%p) %-10.10s -> %s\n",
+                     dccp_role(sk), sk,
+                     dccp_state_name(oldstate), dccp_state_name(state));
+       WARN_ON(state == oldstate);
+
+       switch (state) {
+       case DCCP_OPEN:
+               if (oldstate != DCCP_OPEN)
+                       DCCP_INC_STATS(DCCP_MIB_CURRESTAB);
+               break;
+
+       case DCCP_CLOSED:
+               if (oldstate == DCCP_CLOSING || oldstate == DCCP_OPEN)
+                       DCCP_INC_STATS(DCCP_MIB_ESTABRESETS);
+
+               sk->sk_prot->unhash(sk);
+               if (inet_csk(sk)->icsk_bind_hash != NULL &&
+                   !(sk->sk_userlocks & SOCK_BINDPORT_LOCK))
+                       inet_put_port(&dccp_hashinfo, sk);
+               /* fall through */
+       default:
+               if (oldstate == DCCP_OPEN)
+                       DCCP_DEC_STATS(DCCP_MIB_CURRESTAB);
+       }
+
+       /* Change state AFTER socket is unhashed to avoid closed
+        * socket sitting in hash tables.
+        */
+       sk->sk_state = state;
+}
+
+static inline void dccp_done(struct sock *sk)
+{
+       dccp_set_state(sk, DCCP_CLOSED);
+       dccp_clear_xmit_timers(sk);
+
+       sk->sk_shutdown = SHUTDOWN_MASK;
+
+       if (!sock_flag(sk, SOCK_DEAD))
+               sk->sk_state_change(sk);
+       else
+               inet_csk_destroy_sock(sk);
+}
+
+static inline void dccp_openreq_init(struct request_sock *req,
+                                    struct dccp_sock *dp,
+                                    struct sk_buff *skb)
+{
+       /*
+        * FIXME: fill in the other req fields from the DCCP options
+        * received
+        */
+       inet_rsk(req)->rmt_port = dccp_hdr(skb)->dccph_sport;
+       inet_rsk(req)->acked    = 0;
+       req->rcv_wnd = 0;
+}
+
+extern int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
+
+extern struct sock *dccp_create_openreq_child(struct sock *sk,
+                                             const struct request_sock *req,
+                                             const struct sk_buff *skb);
+
+extern int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb);
+
+extern void dccp_v4_err(struct sk_buff *skb, u32);
+
+extern int dccp_v4_rcv(struct sk_buff *skb);
+
+extern struct sock *dccp_v4_request_recv_sock(struct sock *sk,
+                                             struct sk_buff *skb,
+                                             struct request_sock *req,
+                                             struct dst_entry *dst);
+extern struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
+                                  struct request_sock *req,
+                                  struct request_sock **prev);
+
+extern int dccp_child_process(struct sock *parent, struct sock *child,
+                             struct sk_buff *skb);
+extern int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
+                                 struct dccp_hdr *dh, unsigned len);
+extern int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
+                               const struct dccp_hdr *dh, const unsigned len);
+
+extern void            dccp_close(struct sock *sk, long timeout);
+extern struct sk_buff  *dccp_make_response(struct sock *sk,
+                                           struct dst_entry *dst,
+                                           struct request_sock *req);
+extern struct sk_buff  *dccp_make_reset(struct sock *sk,
+                                        struct dst_entry *dst,
+                                        enum dccp_reset_codes code);
+
+extern int        dccp_connect(struct sock *sk);
+extern int        dccp_disconnect(struct sock *sk, int flags);
+extern int        dccp_getsockopt(struct sock *sk, int level, int optname,
+                                  char __user *optval, int __user *optlen);
+extern int        dccp_setsockopt(struct sock *sk, int level, int optname,
+                                  char __user *optval, int optlen);
+extern int        dccp_ioctl(struct sock *sk, int cmd, unsigned long arg);
+extern int        dccp_sendmsg(struct kiocb *iocb, struct sock *sk,
+                               struct msghdr *msg, size_t size);
+extern int        dccp_recvmsg(struct kiocb *iocb, struct sock *sk,
+                               struct msghdr *msg, size_t len, int nonblock,
+                               int flags, int *addr_len);
+extern void       dccp_shutdown(struct sock *sk, int how);
+
+extern int        dccp_v4_checksum(const struct sk_buff *skb,
+                                   const u32 saddr, const u32 daddr);
+
+extern int        dccp_v4_send_reset(struct sock *sk,
+                                     enum dccp_reset_codes code);
+extern void       dccp_send_close(struct sock *sk, const int active);
+
+struct dccp_skb_cb {
+       __u8 dccpd_type;
+       __u8 dccpd_reset_code;
+       __u8 dccpd_service;
+       __u8 dccpd_ccval;
+       __u64 dccpd_seq;
+       __u64 dccpd_ack_seq;
+       int  dccpd_opt_len;
+};
+
+#define DCCP_SKB_CB(__skb) ((struct dccp_skb_cb *)&((__skb)->cb[0]))
+
+static inline int dccp_non_data_packet(const struct sk_buff *skb)
+{
+       const __u8 type = DCCP_SKB_CB(skb)->dccpd_type;
+
+       return type == DCCP_PKT_ACK      ||
+              type == DCCP_PKT_CLOSE    ||
+              type == DCCP_PKT_CLOSEREQ ||
+              type == DCCP_PKT_RESET    ||
+              type == DCCP_PKT_SYNC     ||
+              type == DCCP_PKT_SYNCACK;
+}
+
+static inline int dccp_packet_without_ack(const struct sk_buff *skb)
+{
+       const __u8 type = DCCP_SKB_CB(skb)->dccpd_type;
+
+       return type == DCCP_PKT_DATA || type == DCCP_PKT_REQUEST;
+}
+
+#define DCCP_MAX_SEQNO ((((u64)1) << 48) - 1)
+#define DCCP_PKT_WITHOUT_ACK_SEQ (DCCP_MAX_SEQNO << 2)
+
+static inline void dccp_set_seqno(u64 *seqno, u64 value)
+{
+       if (value > DCCP_MAX_SEQNO)
+               value -= DCCP_MAX_SEQNO + 1;
+       *seqno = value;
+}
+
+static inline u64 dccp_delta_seqno(u64 seqno1, u64 seqno2)
+{
+       return ((seqno2 << 16) - (seqno1 << 16)) >> 16;
+}
+
+static inline void dccp_inc_seqno(u64 *seqno)
+{
+       if (++*seqno > DCCP_MAX_SEQNO)
+               *seqno = 0;
+}
+
+static inline void dccp_hdr_set_seq(struct dccp_hdr *dh, const u64 gss)
+{
+       struct dccp_hdr_ext *dhx = (struct dccp_hdr_ext *)((void *)dh +
+                                                          sizeof(*dh));
+
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       dh->dccph_seq      = htonl((gss >> 32)) >> 8;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+       dh->dccph_seq      = htonl((gss >> 32));
+#else
+#error  "Adjust your <asm/byteorder.h> defines"
+#endif
+       dhx->dccph_seq_low = htonl(gss & 0xffffffff);
+}
+
+static inline void dccp_hdr_set_ack(struct dccp_hdr_ack_bits *dhack,
+                                   const u64 gsr)
+{
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       dhack->dccph_ack_nr_high = htonl((gsr >> 32)) >> 8;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+       dhack->dccph_ack_nr_high = htonl((gsr >> 32));
+#else
+#error  "Adjust your <asm/byteorder.h> defines"
+#endif
+       dhack->dccph_ack_nr_low  = htonl(gsr & 0xffffffff);
+}
+
+static inline void dccp_update_gsr(struct sock *sk, u64 seq)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+
+       dp->dccps_gsr = seq;
+       dccp_set_seqno(&dp->dccps_swl,
+                      (dp->dccps_gsr + 1 -
+                       (dp->dccps_options.dccpo_sequence_window / 4)));
+       dccp_set_seqno(&dp->dccps_swh,
+                      (dp->dccps_gsr +
+                       (3 * dp->dccps_options.dccpo_sequence_window) / 4));
+}
+
+static inline void dccp_update_gss(struct sock *sk, u64 seq)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+
+       dp->dccps_awh = dp->dccps_gss = seq;
+       dccp_set_seqno(&dp->dccps_awl,
+                      (dp->dccps_gss -
+                       dp->dccps_options.dccpo_sequence_window + 1));
+}
+
+extern void dccp_insert_options(struct sock *sk, struct sk_buff *skb);
+extern void dccp_insert_option_elapsed_time(struct sock *sk,
+                                           struct sk_buff *skb,
+                                           u32 elapsed_time);
+extern void dccp_insert_option_timestamp(struct sock *sk,
+                                        struct sk_buff *skb);
+extern void dccp_insert_option(struct sock *sk, struct sk_buff *skb,
+                              unsigned char option,
+                              const void *value, unsigned char len);
+
+extern struct socket *dccp_ctl_socket;
+
+#define DCCP_ACKPKTS_STATE_RECEIVED    0
+#define DCCP_ACKPKTS_STATE_ECN_MARKED  (1 << 6)
+#define DCCP_ACKPKTS_STATE_NOT_RECEIVED        (3 << 6)
+
+#define DCCP_ACKPKTS_STATE_MASK                0xC0 /* 11000000 */
+#define DCCP_ACKPKTS_LEN_MASK          0x3F /* 00111111 */
+
+/** struct dccp_ackpkts - acknowledgeable packets
+ *
+ * This data structure is the one defined in the DCCP draft
+ * Appendix A.
+ *
+ * @dccpap_buf_head - circular buffer head
+ * @dccpap_buf_tail - circular buffer tail
+ * @dccpap_buf_ackno - ack # of the most recent packet acknowledgeable in the
+ *                    buffer (i.e. %dccpap_buf_head)
+ * @dccpap_buf_nonce - the one-bit sum of the ECN Nonces on all packets acked
+ *                    by the buffer with State 0
+ *
+ * Additionally, the HC-Receiver must keep some information about the
+ * Ack Vectors it has recently sent. For each packet sent carrying an
+ * Ack Vector, it remembers four variables:
+ *
+ * @dccpap_ack_seqno - the Sequence Number used for the packet
+ *                    (HC-Receiver seqno)
+ * @dccpap_ack_ptr - the value of buf_head at the time of acknowledgement.
+ * @dccpap_ack_ackno - the Acknowledgement Number used for the packet
+ *                    (HC-Sender seqno)
+ * @dccpap_ack_nonce - the one-bit sum of the ECN Nonces for all State 0.
+ *
+ * @dccpap_buf_len - circular buffer length
+ * @dccpap_time                - the time in usecs
+ * @dccpap_buf - circular buffer of acknowledgeable packets
+ */
+struct dccp_ackpkts {
+       unsigned int            dccpap_buf_head;
+       unsigned int            dccpap_buf_tail;
+       u64                     dccpap_buf_ackno;
+       u64                     dccpap_ack_seqno;
+       u64                     dccpap_ack_ackno;
+       unsigned int            dccpap_ack_ptr;
+       unsigned int            dccpap_buf_vector_len;
+       unsigned int            dccpap_ack_vector_len;
+       unsigned int            dccpap_buf_len;
+       struct timeval          dccpap_time;
+       u8                      dccpap_buf_nonce;
+       u8                      dccpap_ack_nonce;
+       u8                      dccpap_buf[0];
+};
+
+extern struct dccp_ackpkts *
+               dccp_ackpkts_alloc(unsigned int len,
+                                 const unsigned int __nocast priority);
+extern void dccp_ackpkts_free(struct dccp_ackpkts *ap);
+extern int dccp_ackpkts_add(struct dccp_ackpkts *ap, u64 ackno, u8 state);
+extern void dccp_ackpkts_check_rcv_ackno(struct dccp_ackpkts *ap,
+                                        struct sock *sk, u64 ackno);
+
+static inline suseconds_t timeval_usecs(const struct timeval *tv)
+{
+       return tv->tv_sec * USEC_PER_SEC + tv->tv_usec;
+}
+
+static inline suseconds_t timeval_delta(const struct timeval *large,
+                                       const struct timeval *small)
+{
+       time_t      secs  = large->tv_sec  - small->tv_sec;
+       suseconds_t usecs = large->tv_usec - small->tv_usec;
+
+       if (usecs < 0) {
+               secs--;
+               usecs += USEC_PER_SEC;
+       }
+       return secs * USEC_PER_SEC + usecs;
+}
+
+static inline void timeval_add_usecs(struct timeval *tv,
+                                    const suseconds_t usecs)
+{
+       tv->tv_usec += usecs;
+       while (tv->tv_usec >= USEC_PER_SEC) {
+               tv->tv_sec++;
+               tv->tv_usec -= USEC_PER_SEC;
+       }
+}
+
+static inline void timeval_sub_usecs(struct timeval *tv,
+                                    const suseconds_t usecs)
+{
+       tv->tv_usec -= usecs;
+       while (tv->tv_usec < 0) {
+               tv->tv_sec--;
+               tv->tv_usec += USEC_PER_SEC;
+       }
+}
+
+/*
+ * Returns the difference in usecs between timeval
+ * passed in and current time
+ */
+static inline suseconds_t timeval_now_delta(const struct timeval *tv)
+{
+       struct timeval now;
+       do_gettimeofday(&now);
+       return timeval_delta(&now, tv);
+}
+
+#ifdef CONFIG_IP_DCCP_DEBUG
+extern void dccp_ackvector_print(const u64 ackno,
+                                const unsigned char *vector, int len);
+extern void dccp_ackpkts_print(const struct dccp_ackpkts *ap);
+#else
+static inline void dccp_ackvector_print(const u64 ackno,
+                                       const unsigned char *vector,
+                                       int len) { }
+static inline void dccp_ackpkts_print(const struct dccp_ackpkts *ap) { }
+#endif
+
+#endif /* _DCCP_H */
diff --git a/net/dccp/diag.c b/net/dccp/diag.c
new file mode 100644 (file)
index 0000000..f675d8e
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *  net/dccp/diag.c
+ *
+ *  An implementation of the DCCP protocol
+ *  Arnaldo Carvalho de Melo <acme@mandriva.com>
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+
+#include <linux/module.h>
+#include <linux/inet_diag.h>
+
+#include "ccid.h"
+#include "dccp.h"
+
+static void dccp_get_info(struct sock *sk, struct tcp_info *info)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+
+       memset(info, 0, sizeof(*info));
+
+       info->tcpi_state        = sk->sk_state;
+       info->tcpi_retransmits  = icsk->icsk_retransmits;
+       info->tcpi_probes       = icsk->icsk_probes_out;
+       info->tcpi_backoff      = icsk->icsk_backoff;
+       info->tcpi_pmtu         = dp->dccps_pmtu_cookie;
+
+       if (dp->dccps_options.dccpo_send_ack_vector)
+               info->tcpi_options |= TCPI_OPT_SACK;
+
+       ccid_hc_rx_get_info(dp->dccps_hc_rx_ccid, sk, info);
+       ccid_hc_tx_get_info(dp->dccps_hc_tx_ccid, sk, info);
+}
+
+static void dccp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
+                              void *_info)
+{
+       r->idiag_rqueue = r->idiag_wqueue = 0;
+
+       if (_info != NULL)
+               dccp_get_info(sk, _info);
+}
+
+static struct inet_diag_handler dccp_diag_handler = {
+       .idiag_hashinfo  = &dccp_hashinfo,
+       .idiag_get_info  = dccp_diag_get_info,
+       .idiag_type      = DCCPDIAG_GETSOCK,
+       .idiag_info_size = sizeof(struct tcp_info),
+};
+
+static int __init dccp_diag_init(void)
+{
+       return inet_diag_register(&dccp_diag_handler);
+}
+
+static void __exit dccp_diag_fini(void)
+{
+       inet_diag_unregister(&dccp_diag_handler);
+}
+
+module_init(dccp_diag_init);
+module_exit(dccp_diag_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
+MODULE_DESCRIPTION("DCCP inet_diag handler");
diff --git a/net/dccp/input.c b/net/dccp/input.c
new file mode 100644 (file)
index 0000000..ef29cef
--- /dev/null
@@ -0,0 +1,600 @@
+/*
+ *  net/dccp/input.c
+ * 
+ *  An implementation of the DCCP protocol
+ *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *     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/dccp.h>
+#include <linux/skbuff.h>
+
+#include <net/sock.h>
+
+#include "ccid.h"
+#include "dccp.h"
+
+static void dccp_fin(struct sock *sk, struct sk_buff *skb)
+{
+       sk->sk_shutdown |= RCV_SHUTDOWN;
+       sock_set_flag(sk, SOCK_DONE);
+       __skb_pull(skb, dccp_hdr(skb)->dccph_doff * 4);
+       __skb_queue_tail(&sk->sk_receive_queue, skb);
+       skb_set_owner_r(skb, sk);
+       sk->sk_data_ready(sk, 0);
+}
+
+static void dccp_rcv_close(struct sock *sk, struct sk_buff *skb)
+{
+       dccp_v4_send_reset(sk, DCCP_RESET_CODE_CLOSED);
+       dccp_fin(sk, skb);
+       dccp_set_state(sk, DCCP_CLOSED);
+       sk_wake_async(sk, 1, POLL_HUP);
+}
+
+static void dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb)
+{
+       /*
+        *   Step 7: Check for unexpected packet types
+        *      If (S.is_server and P.type == CloseReq)
+        *        Send Sync packet acknowledging P.seqno
+        *        Drop packet and return
+        */
+       if (dccp_sk(sk)->dccps_role != DCCP_ROLE_CLIENT) {
+               dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq, DCCP_PKT_SYNC);
+               return;
+       }
+
+       dccp_set_state(sk, DCCP_CLOSING);
+       dccp_send_close(sk, 0);
+}
+
+static inline void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+
+       if (dp->dccps_options.dccpo_send_ack_vector)
+               dccp_ackpkts_check_rcv_ackno(dp->dccps_hc_rx_ackpkts, sk,
+                                            DCCP_SKB_CB(skb)->dccpd_ack_seq);
+}
+
+static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb)
+{
+       const struct dccp_hdr *dh = dccp_hdr(skb);
+       struct dccp_sock *dp = dccp_sk(sk);
+       u64 lswl, lawl;
+
+       /*
+        *   Step 5: Prepare sequence numbers for Sync
+        *     If P.type == Sync or P.type == SyncAck,
+        *        If S.AWL <= P.ackno <= S.AWH and P.seqno >= S.SWL,
+        *           / * P is valid, so update sequence number variables
+        *               accordingly.  After this update, P will pass the tests
+        *               in Step 6.  A SyncAck is generated if necessary in
+        *               Step 15 * /
+        *           Update S.GSR, S.SWL, S.SWH
+        *        Otherwise,
+        *           Drop packet and return
+        */
+       if (dh->dccph_type == DCCP_PKT_SYNC || 
+           dh->dccph_type == DCCP_PKT_SYNCACK) {
+               if (between48(DCCP_SKB_CB(skb)->dccpd_ack_seq,
+                             dp->dccps_awl, dp->dccps_awh) &&
+                   !before48(DCCP_SKB_CB(skb)->dccpd_seq, dp->dccps_swl))
+                       dccp_update_gsr(sk, DCCP_SKB_CB(skb)->dccpd_seq);
+               else
+                       return -1;
+       }
+       
+       /*
+        *   Step 6: Check sequence numbers
+        *      Let LSWL = S.SWL and LAWL = S.AWL
+        *      If P.type == CloseReq or P.type == Close or P.type == Reset,
+        *        LSWL := S.GSR + 1, LAWL := S.GAR
+        *      If LSWL <= P.seqno <= S.SWH
+        *           and (P.ackno does not exist or LAWL <= P.ackno <= S.AWH),
+        *        Update S.GSR, S.SWL, S.SWH
+        *        If P.type != Sync,
+        *           Update S.GAR
+        *      Otherwise,
+        *        Send Sync packet acknowledging P.seqno
+        *        Drop packet and return
+        */
+       lswl = dp->dccps_swl;
+       lawl = dp->dccps_awl;
+
+       if (dh->dccph_type == DCCP_PKT_CLOSEREQ ||
+           dh->dccph_type == DCCP_PKT_CLOSE ||
+           dh->dccph_type == DCCP_PKT_RESET) {
+               lswl = dp->dccps_gsr;
+               dccp_inc_seqno(&lswl);
+               lawl = dp->dccps_gar;
+       }
+
+       if (between48(DCCP_SKB_CB(skb)->dccpd_seq, lswl, dp->dccps_swh) &&
+           (DCCP_SKB_CB(skb)->dccpd_ack_seq == DCCP_PKT_WITHOUT_ACK_SEQ ||
+            between48(DCCP_SKB_CB(skb)->dccpd_ack_seq,
+                      lawl, dp->dccps_awh))) {
+               dccp_update_gsr(sk, DCCP_SKB_CB(skb)->dccpd_seq);
+
+               if (dh->dccph_type != DCCP_PKT_SYNC &&
+                   (DCCP_SKB_CB(skb)->dccpd_ack_seq !=
+                    DCCP_PKT_WITHOUT_ACK_SEQ))
+                       dp->dccps_gar = DCCP_SKB_CB(skb)->dccpd_ack_seq;
+       } else {
+               LIMIT_NETDEBUG(KERN_WARNING "DCCP: Step 6 failed for %s packet, "
+                                           "(LSWL(%llu) <= P.seqno(%llu) <= S.SWH(%llu)) and "
+                                           "(P.ackno %s or LAWL(%llu) <= P.ackno(%llu) <= S.AWH(%llu), "
+                                           "sending SYNC...\n",
+                              dccp_packet_name(dh->dccph_type),
+                              (unsigned long long) lswl,
+                              (unsigned long long)
+                              DCCP_SKB_CB(skb)->dccpd_seq,
+                              (unsigned long long) dp->dccps_swh,
+                              (DCCP_SKB_CB(skb)->dccpd_ack_seq ==
+                               DCCP_PKT_WITHOUT_ACK_SEQ) ? "doesn't exist" : "exists",
+                              (unsigned long long) lawl,
+                              (unsigned long long)
+                              DCCP_SKB_CB(skb)->dccpd_ack_seq,
+                              (unsigned long long) dp->dccps_awh);
+               dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq, DCCP_PKT_SYNC);
+               return -1;
+       }
+
+       return 0;
+}
+
+int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
+                        const struct dccp_hdr *dh, const unsigned len)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+
+       if (dccp_check_seqno(sk, skb))
+               goto discard;
+
+       if (dccp_parse_options(sk, skb))
+               goto discard;
+
+       if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
+               dccp_event_ack_recv(sk, skb);
+
+       /*
+        * FIXME: check ECN to see if we should use
+        * DCCP_ACKPKTS_STATE_ECN_MARKED
+        */
+       if (dp->dccps_options.dccpo_send_ack_vector) {
+               struct dccp_ackpkts *ap = dp->dccps_hc_rx_ackpkts;
+
+               if (dccp_ackpkts_add(dp->dccps_hc_rx_ackpkts,
+                                    DCCP_SKB_CB(skb)->dccpd_seq,
+                                    DCCP_ACKPKTS_STATE_RECEIVED)) {
+                       LIMIT_NETDEBUG(KERN_WARNING "DCCP: acknowledgeable "
+                                                   "packets buffer full!\n");
+                       ap->dccpap_ack_seqno = DCCP_MAX_SEQNO + 1;
+                       inet_csk_schedule_ack(sk);
+                       inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
+                                                 TCP_DELACK_MIN,
+                                                 DCCP_RTO_MAX);
+                       goto discard;
+               }
+
+               /*
+                * FIXME: this activation is probably wrong, have to study more
+                * TCP delack machinery and how it fits into DCCP draft, but
+                * for now it kinda "works" 8)
+                */
+               if (!inet_csk_ack_scheduled(sk)) {
+                       inet_csk_schedule_ack(sk);
+                       inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, 5 * HZ,
+                                                 DCCP_RTO_MAX);
+               }
+       }
+
+       ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
+       ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
+
+       switch (dccp_hdr(skb)->dccph_type) {
+       case DCCP_PKT_DATAACK:
+       case DCCP_PKT_DATA:
+               /*
+                * FIXME: check if sk_receive_queue is full, schedule DATA_DROPPED
+                * option if it is.
+                */
+               __skb_pull(skb, dh->dccph_doff * 4);
+               __skb_queue_tail(&sk->sk_receive_queue, skb);
+               skb_set_owner_r(skb, sk);
+               sk->sk_data_ready(sk, 0);
+               return 0;
+       case DCCP_PKT_ACK:
+               goto discard;
+       case DCCP_PKT_RESET:
+               /*
+                *  Step 9: Process Reset
+                *      If P.type == Reset,
+                *              Tear down connection
+                *              S.state := TIMEWAIT
+                *              Set TIMEWAIT timer
+                *              Drop packet and return
+               */
+               dccp_fin(sk, skb);
+               dccp_time_wait(sk, DCCP_TIME_WAIT, 0);
+               return 0;
+       case DCCP_PKT_CLOSEREQ:
+               dccp_rcv_closereq(sk, skb);
+               goto discard;
+       case DCCP_PKT_CLOSE:
+               dccp_rcv_close(sk, skb);
+               return 0;
+       case DCCP_PKT_REQUEST:
+               /* Step 7 
+                *   or (S.is_server and P.type == Response)
+                *   or (S.is_client and P.type == Request)
+                *   or (S.state >= OPEN and P.type == Request
+                *      and P.seqno >= S.OSR)
+                *    or (S.state >= OPEN and P.type == Response
+                *      and P.seqno >= S.OSR)
+                *    or (S.state == RESPOND and P.type == Data),
+                *  Send Sync packet acknowledging P.seqno
+                *  Drop packet and return
+                */
+               if (dp->dccps_role != DCCP_ROLE_LISTEN)
+                       goto send_sync;
+               goto check_seq;
+       case DCCP_PKT_RESPONSE:
+               if (dp->dccps_role != DCCP_ROLE_CLIENT)
+                       goto send_sync;
+check_seq:
+               if (!before48(DCCP_SKB_CB(skb)->dccpd_seq, dp->dccps_osr)) {
+send_sync:
+                       dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq,
+                                      DCCP_PKT_SYNC);
+               }
+               break;
+       case DCCP_PKT_SYNC:
+               dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq,
+                              DCCP_PKT_SYNCACK);
+               /*
+                * From the draft:
+                *
+                * As with DCCP-Ack packets, DCCP-Sync and DCCP-SyncAck packets
+                * MAY have non-zero-length application data areas, whose
+                * contents * receivers MUST ignore.
+                */
+               goto discard;
+       }
+
+       DCCP_INC_STATS_BH(DCCP_MIB_INERRS);
+discard:
+       __kfree_skb(skb);
+       return 0;
+}
+
+static int dccp_rcv_request_sent_state_process(struct sock *sk,
+                                              struct sk_buff *skb,
+                                              const struct dccp_hdr *dh,
+                                              const unsigned len)
+{
+       /* 
+        *  Step 4: Prepare sequence numbers in REQUEST
+        *     If S.state == REQUEST,
+        *        If (P.type == Response or P.type == Reset)
+        *              and S.AWL <= P.ackno <= S.AWH,
+        *           / * Set sequence number variables corresponding to the
+        *              other endpoint, so P will pass the tests in Step 6 * /
+        *           Set S.GSR, S.ISR, S.SWL, S.SWH
+        *           / * Response processing continues in Step 10; Reset
+        *              processing continues in Step 9 * /
+       */
+       if (dh->dccph_type == DCCP_PKT_RESPONSE) {
+               const struct inet_connection_sock *icsk = inet_csk(sk);
+               struct dccp_sock *dp = dccp_sk(sk);
+
+               /* Stop the REQUEST timer */
+               inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
+               BUG_TRAP(sk->sk_send_head != NULL);
+               __kfree_skb(sk->sk_send_head);
+               sk->sk_send_head = NULL;
+
+               if (!between48(DCCP_SKB_CB(skb)->dccpd_ack_seq,
+                              dp->dccps_awl, dp->dccps_awh)) {
+                       dccp_pr_debug("invalid ackno: S.AWL=%llu, "
+                                     "P.ackno=%llu, S.AWH=%llu \n",
+                                     (unsigned long long)dp->dccps_awl,
+                          (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq,
+                                     (unsigned long long)dp->dccps_awh);
+                       goto out_invalid_packet;
+               }
+
+               dp->dccps_isr = DCCP_SKB_CB(skb)->dccpd_seq;
+               dccp_update_gsr(sk, dp->dccps_isr);
+               /*
+                * SWL and AWL are initially adjusted so that they are not less than
+                * the initial Sequence Numbers received and sent, respectively:
+                *      SWL := max(GSR + 1 - floor(W/4), ISR),
+                *      AWL := max(GSS - W' + 1, ISS).
+                * These adjustments MUST be applied only at the beginning of the
+                * connection.
+                *
+                * AWL was adjusted in dccp_v4_connect -acme
+                */
+               dccp_set_seqno(&dp->dccps_swl,
+                              max48(dp->dccps_swl, dp->dccps_isr));
+
+               if (ccid_hc_rx_init(dp->dccps_hc_rx_ccid, sk) != 0 ||
+                   ccid_hc_tx_init(dp->dccps_hc_tx_ccid, sk) != 0) {
+                       ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk);
+                       ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk);
+                       /* FIXME: send appropriate RESET code */
+                       goto out_invalid_packet;
+               }
+
+               dccp_sync_mss(sk, dp->dccps_pmtu_cookie);
+
+               /*
+                *    Step 10: Process REQUEST state (second part)
+                *       If S.state == REQUEST,
+                *        / * If we get here, P is a valid Response from the
+                *            server (see Step 4), and we should move to
+                *            PARTOPEN state. PARTOPEN means send an Ack,
+                *            don't send Data packets, retransmit Acks
+                *            periodically, and always include any Init Cookie
+                *            from the Response * /
+                *        S.state := PARTOPEN
+                *        Set PARTOPEN timer
+                *        Continue with S.state == PARTOPEN
+                *        / * Step 12 will send the Ack completing the
+                *            three-way handshake * /
+                */
+               dccp_set_state(sk, DCCP_PARTOPEN);
+
+               /* Make sure socket is routed, for correct metrics. */
+               inet_sk_rebuild_header(sk);
+
+               if (!sock_flag(sk, SOCK_DEAD)) {
+                       sk->sk_state_change(sk);
+                       sk_wake_async(sk, 0, POLL_OUT);
+               }
+
+               if (sk->sk_write_pending || icsk->icsk_ack.pingpong ||
+                   icsk->icsk_accept_queue.rskq_defer_accept) {
+                       /* Save one ACK. Data will be ready after
+                        * several ticks, if write_pending is set.
+                        *
+                        * It may be deleted, but with this feature tcpdumps
+                        * look so _wonderfully_ clever, that I was not able
+                        * to stand against the temptation 8)     --ANK
+                        */
+                       /*
+                        * OK, in DCCP we can as well do a similar trick, its
+                        * even in the draft, but there is no need for us to
+                        * schedule an ack here, as dccp_sendmsg does this for
+                        * us, also stated in the draft. -acme
+                        */
+                       __kfree_skb(skb);
+                       return 0;
+               } 
+               dccp_send_ack(sk);
+               return -1;
+       }
+
+out_invalid_packet:
+       return 1; /* dccp_v4_do_rcv will send a reset, but...
+                    FIXME: the reset code should be
+                           DCCP_RESET_CODE_PACKET_ERROR */
+}
+
+static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
+                                                  struct sk_buff *skb,
+                                                  const struct dccp_hdr *dh,
+                                                  const unsigned len)
+{
+       int queued = 0;
+
+       switch (dh->dccph_type) {
+       case DCCP_PKT_RESET:
+               inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK);
+               break;
+       case DCCP_PKT_DATAACK:
+       case DCCP_PKT_ACK:
+               /*
+                * FIXME: we should be reseting the PARTOPEN (DELACK) timer
+                * here but only if we haven't used the DELACK timer for
+                * something else, like sending a delayed ack for a TIMESTAMP
+                * echo, etc, for now were not clearing it, sending an extra
+                * ACK when there is nothing else to do in DELACK is not a big
+                * deal after all.
+                */
+
+               /* Stop the PARTOPEN timer */
+               if (sk->sk_state == DCCP_PARTOPEN)
+                       inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK);
+
+               dccp_sk(sk)->dccps_osr = DCCP_SKB_CB(skb)->dccpd_seq;
+               dccp_set_state(sk, DCCP_OPEN);
+
+               if (dh->dccph_type == DCCP_PKT_DATAACK) {
+                       dccp_rcv_established(sk, skb, dh, len);
+                       queued = 1; /* packet was queued
+                                      (by dccp_rcv_established) */
+               }
+               break;
+       }
+
+       return queued;
+}
+
+int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
+                          struct dccp_hdr *dh, unsigned len)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       const int old_state = sk->sk_state;
+       int queued = 0;
+
+       /*
+        *  Step 3: Process LISTEN state
+        *      (Continuing from dccp_v4_do_rcv and dccp_v6_do_rcv)
+        *
+        *     If S.state == LISTEN,
+        *        If P.type == Request or P contains a valid Init Cookie
+        *              option,
+        *           * Must scan the packet's options to check for an Init
+        *              Cookie.  Only the Init Cookie is processed here,
+        *              however; other options are processed in Step 8.  This
+        *              scan need only be performed if the endpoint uses Init
+        *              Cookies *
+        *           * Generate a new socket and switch to that socket *
+        *           Set S := new socket for this port pair
+        *           S.state = RESPOND
+        *           Choose S.ISS (initial seqno) or set from Init Cookie
+        *           Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
+        *           Continue with S.state == RESPOND
+        *           * A Response packet will be generated in Step 11 *
+        *        Otherwise,
+        *           Generate Reset(No Connection) unless P.type == Reset
+        *           Drop packet and return
+        *
+        * NOTE: the check for the packet types is done in
+        *       dccp_rcv_state_process
+        */
+       if (sk->sk_state == DCCP_LISTEN) {
+               if (dh->dccph_type == DCCP_PKT_REQUEST) {
+                       if (dccp_v4_conn_request(sk, skb) < 0)
+                               return 1;
+
+                       /* FIXME: do congestion control initialization */
+                       goto discard;
+               }
+               if (dh->dccph_type == DCCP_PKT_RESET)
+                       goto discard;
+
+               /* Caller (dccp_v4_do_rcv) will send Reset(No Connection)*/
+               return 1;
+       }
+
+       if (sk->sk_state != DCCP_REQUESTING) {
+               if (dccp_check_seqno(sk, skb))
+                       goto discard;
+
+               /*
+                * Step 8: Process options and mark acknowledgeable
+                */
+               if (dccp_parse_options(sk, skb))
+                       goto discard;
+
+               if (DCCP_SKB_CB(skb)->dccpd_ack_seq !=
+                   DCCP_PKT_WITHOUT_ACK_SEQ)
+                       dccp_event_ack_recv(sk, skb);
+
+               ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
+               ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
+
+               /*
+                * FIXME: check ECN to see if we should use
+                * DCCP_ACKPKTS_STATE_ECN_MARKED
+                */
+               if (dp->dccps_options.dccpo_send_ack_vector) {
+                       if (dccp_ackpkts_add(dp->dccps_hc_rx_ackpkts,
+                                            DCCP_SKB_CB(skb)->dccpd_seq,
+                                            DCCP_ACKPKTS_STATE_RECEIVED))
+                               goto discard;
+                       /*
+                        * FIXME: this activation is probably wrong, have to
+                        * study more TCP delack machinery and how it fits into
+                        * DCCP draft, but for now it kinda "works" 8)
+                        */
+                       if ((dp->dccps_hc_rx_ackpkts->dccpap_ack_seqno ==
+                            DCCP_MAX_SEQNO + 1) &&
+                           !inet_csk_ack_scheduled(sk)) {
+                               inet_csk_schedule_ack(sk);
+                               inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
+                                                         TCP_DELACK_MIN,
+                                                         DCCP_RTO_MAX);
+                       }
+               }
+       }
+
+       /*
+        *  Step 9: Process Reset
+        *      If P.type == Reset,
+        *              Tear down connection
+        *              S.state := TIMEWAIT
+        *              Set TIMEWAIT timer
+        *              Drop packet and return
+       */
+       if (dh->dccph_type == DCCP_PKT_RESET) {
+               /*
+                * Queue the equivalent of TCP fin so that dccp_recvmsg
+                * exits the loop
+                */
+               dccp_fin(sk, skb);
+               dccp_time_wait(sk, DCCP_TIME_WAIT, 0);
+               return 0;
+               /*
+                *   Step 7: Check for unexpected packet types
+                *      If (S.is_server and P.type == CloseReq)
+                *          or (S.is_server and P.type == Response)
+                *          or (S.is_client and P.type == Request)
+                *          or (S.state == RESPOND and P.type == Data),
+                *        Send Sync packet acknowledging P.seqno
+                *        Drop packet and return
+                */
+       } else if ((dp->dccps_role != DCCP_ROLE_CLIENT &&
+                   (dh->dccph_type == DCCP_PKT_RESPONSE ||
+                    dh->dccph_type == DCCP_PKT_CLOSEREQ)) ||
+                   (dp->dccps_role == DCCP_ROLE_CLIENT &&
+                    dh->dccph_type == DCCP_PKT_REQUEST) ||
+                   (sk->sk_state == DCCP_RESPOND &&
+                    dh->dccph_type == DCCP_PKT_DATA)) {
+               dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq,
+                              DCCP_PKT_SYNC);
+               goto discard;
+       } else if (dh->dccph_type == DCCP_PKT_CLOSEREQ) {
+               dccp_rcv_closereq(sk, skb);
+               goto discard;
+       } else if (dh->dccph_type == DCCP_PKT_CLOSE) {
+               dccp_rcv_close(sk, skb);
+               return 0;
+       }
+
+       switch (sk->sk_state) {
+       case DCCP_CLOSED:
+               return 1;
+
+       case DCCP_REQUESTING:
+               /* FIXME: do congestion control initialization */
+
+               queued = dccp_rcv_request_sent_state_process(sk, skb, dh, len);
+               if (queued >= 0)
+                       return queued;
+
+               __kfree_skb(skb);
+               return 0;
+
+       case DCCP_RESPOND:
+       case DCCP_PARTOPEN:
+               queued = dccp_rcv_respond_partopen_state_process(sk, skb,
+                                                                dh, len);
+               break;
+       }
+
+       if (dh->dccph_type == DCCP_PKT_ACK ||
+           dh->dccph_type == DCCP_PKT_DATAACK) {
+               switch (old_state) {
+               case DCCP_PARTOPEN:
+                       sk->sk_state_change(sk);
+                       sk_wake_async(sk, 0, POLL_OUT);
+                       break;
+               }
+       }
+
+       if (!queued) { 
+discard:
+               __kfree_skb(skb);
+       }
+       return 0;
+}
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
new file mode 100644 (file)
index 0000000..3fc75db
--- /dev/null
@@ -0,0 +1,1356 @@
+/*
+ *  net/dccp/ipv4.c
+ *
+ *  An implementation of the DCCP protocol
+ *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *     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/dccp.h>
+#include <linux/icmp.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/random.h>
+
+#include <net/icmp.h>
+#include <net/inet_hashtables.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+#include <net/xfrm.h>
+
+#include "ccid.h"
+#include "dccp.h"
+
+struct inet_hashinfo __cacheline_aligned dccp_hashinfo = {
+       .lhash_lock     = RW_LOCK_UNLOCKED,
+       .lhash_users    = ATOMIC_INIT(0),
+       .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait),
+       .portalloc_lock = SPIN_LOCK_UNLOCKED,
+       .port_rover     = 1024 - 1,
+};
+
+EXPORT_SYMBOL_GPL(dccp_hashinfo);
+
+static int dccp_v4_get_port(struct sock *sk, const unsigned short snum)
+{
+       return inet_csk_get_port(&dccp_hashinfo, sk, snum);
+}
+
+static void dccp_v4_hash(struct sock *sk)
+{
+       inet_hash(&dccp_hashinfo, sk);
+}
+
+static void dccp_v4_unhash(struct sock *sk)
+{
+       inet_unhash(&dccp_hashinfo, sk);
+}
+
+/* called with local bh disabled */
+static int __dccp_v4_check_established(struct sock *sk, const __u16 lport,
+                                     struct inet_timewait_sock **twp)
+{
+       struct inet_sock *inet = inet_sk(sk);
+       const u32 daddr = inet->rcv_saddr;
+       const u32 saddr = inet->daddr;
+       const int dif = sk->sk_bound_dev_if;
+       INET_ADDR_COOKIE(acookie, saddr, daddr)
+       const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
+       const int hash = inet_ehashfn(daddr, lport, saddr, inet->dport,
+                                     dccp_hashinfo.ehash_size);
+       struct inet_ehash_bucket *head = &dccp_hashinfo.ehash[hash];
+       const struct sock *sk2;
+       const struct hlist_node *node;
+       struct inet_timewait_sock *tw;
+
+       write_lock(&head->lock);
+
+       /* Check TIME-WAIT sockets first. */
+       sk_for_each(sk2, node, &(head + dccp_hashinfo.ehash_size)->chain) {
+               tw = inet_twsk(sk2);
+
+               if (INET_TW_MATCH(sk2, acookie, saddr, daddr, ports, dif))
+                       goto not_unique;
+       }
+       tw = NULL;
+
+       /* And established part... */
+       sk_for_each(sk2, node, &head->chain) {
+               if (INET_MATCH(sk2, acookie, saddr, daddr, ports, dif))
+                       goto not_unique;
+       }
+
+       /* Must record num and sport now. Otherwise we will see
+        * in hash table socket with a funny identity. */
+       inet->num = lport;
+       inet->sport = htons(lport);
+       sk->sk_hashent = hash;
+       BUG_TRAP(sk_unhashed(sk));
+       __sk_add_node(sk, &head->chain);
+       sock_prot_inc_use(sk->sk_prot);
+       write_unlock(&head->lock);
+
+       if (twp != NULL) {
+               *twp = tw;
+               NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
+       } else if (tw != NULL) {
+               /* Silly. Should hash-dance instead... */
+               inet_twsk_deschedule(tw, &dccp_death_row);
+               NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
+
+               inet_twsk_put(tw);
+       }
+
+       return 0;
+
+not_unique:
+       write_unlock(&head->lock);
+       return -EADDRNOTAVAIL;
+}
+
+/*
+ * Bind a port for a connect operation and hash it.
+ */
+static int dccp_v4_hash_connect(struct sock *sk)
+{
+       const unsigned short snum = inet_sk(sk)->num;
+       struct inet_bind_hashbucket *head;
+       struct inet_bind_bucket *tb;
+       int ret;
+
+       if (snum == 0) {
+               int rover;
+               int low = sysctl_local_port_range[0];
+               int high = sysctl_local_port_range[1];
+               int remaining = (high - low) + 1;
+               struct hlist_node *node;
+               struct inet_timewait_sock *tw = NULL;
+
+               local_bh_disable();
+
+               /* TODO. Actually it is not so bad idea to remove
+                * dccp_hashinfo.portalloc_lock before next submission to
+                * Linus.
+                * As soon as we touch this place at all it is time to think.
+                *
+                * Now it protects single _advisory_ variable
+                * dccp_hashinfo.port_rover, hence it is mostly useless.
+                * Code will work nicely if we just delete it, but
+                * I am afraid in contented case it will work not better or
+                * even worse: another cpu just will hit the same bucket
+                * and spin there.
+                * So some cpu salt could remove both contention and
+                * memory pingpong. Any ideas how to do this in a nice way?
+                */
+               spin_lock(&dccp_hashinfo.portalloc_lock);
+               rover = dccp_hashinfo.port_rover;
+
+               do {
+                       rover++;
+                       if ((rover < low) || (rover > high))
+                               rover = low;
+                       head = &dccp_hashinfo.bhash[inet_bhashfn(rover,
+                                                   dccp_hashinfo.bhash_size)];
+                       spin_lock(&head->lock);
+
+                       /* Does not bother with rcv_saddr checks,
+                        * because the established check is already
+                        * unique enough.
+                        */
+                       inet_bind_bucket_for_each(tb, node, &head->chain) {
+                               if (tb->port == rover) {
+                                       BUG_TRAP(!hlist_empty(&tb->owners));
+                                       if (tb->fastreuse >= 0)
+                                               goto next_port;
+                                       if (!__dccp_v4_check_established(sk,
+                                                                        rover,
+                                                                        &tw))
+                                               goto ok;
+                                       goto next_port;
+                               }
+                       }
+
+                       tb = inet_bind_bucket_create(dccp_hashinfo.bind_bucket_cachep,
+                                                    head, rover);
+                       if (tb == NULL) {
+                               spin_unlock(&head->lock);
+                               break;
+                       }
+                       tb->fastreuse = -1;
+                       goto ok;
+
+               next_port:
+                       spin_unlock(&head->lock);
+               } while (--remaining > 0);
+               dccp_hashinfo.port_rover = rover;
+               spin_unlock(&dccp_hashinfo.portalloc_lock);
+
+               local_bh_enable();
+
+               return -EADDRNOTAVAIL;
+
+ok:
+               /* All locks still held and bhs disabled */
+               dccp_hashinfo.port_rover = rover;
+               spin_unlock(&dccp_hashinfo.portalloc_lock);
+
+               inet_bind_hash(sk, tb, rover);
+               if (sk_unhashed(sk)) {
+                       inet_sk(sk)->sport = htons(rover);
+                       __inet_hash(&dccp_hashinfo, sk, 0);
+               }
+               spin_unlock(&head->lock);
+
+               if (tw != NULL) {
+                       inet_twsk_deschedule(tw, &dccp_death_row);
+                       inet_twsk_put(tw);
+               }
+
+               ret = 0;
+               goto out;
+       }
+
+       head = &dccp_hashinfo.bhash[inet_bhashfn(snum,
+                                                dccp_hashinfo.bhash_size)];
+       tb   = inet_csk(sk)->icsk_bind_hash;
+       spin_lock_bh(&head->lock);
+       if (sk_head(&tb->owners) == sk && sk->sk_bind_node.next == NULL) {
+               __inet_hash(&dccp_hashinfo, sk, 0);
+               spin_unlock_bh(&head->lock);
+               return 0;
+       } else {
+               spin_unlock(&head->lock);
+               /* No definite answer... Walk to established hash table */
+               ret = __dccp_v4_check_established(sk, snum, NULL);
+out:
+               local_bh_enable();
+               return ret;
+       }
+}
+
+static int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr,
+                          int addr_len)
+{
+       struct inet_sock *inet = inet_sk(sk);
+       struct dccp_sock *dp = dccp_sk(sk);
+       const struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
+       struct rtable *rt;
+       u32 daddr, nexthop;
+       int tmp;
+       int err;
+
+       dp->dccps_role = DCCP_ROLE_CLIENT;
+
+       if (addr_len < sizeof(struct sockaddr_in))
+               return -EINVAL;
+
+       if (usin->sin_family != AF_INET)
+               return -EAFNOSUPPORT;
+
+       nexthop = daddr = usin->sin_addr.s_addr;
+       if (inet->opt != NULL && inet->opt->srr) {
+               if (daddr == 0)
+                       return -EINVAL;
+               nexthop = inet->opt->faddr;
+       }
+
+       tmp = ip_route_connect(&rt, nexthop, inet->saddr,
+                              RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
+                              IPPROTO_DCCP,
+                              inet->sport, usin->sin_port, sk);
+       if (tmp < 0)
+               return tmp;
+
+       if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
+               ip_rt_put(rt);
+               return -ENETUNREACH;
+       }
+
+       if (inet->opt == NULL || !inet->opt->srr)
+               daddr = rt->rt_dst;
+
+       if (inet->saddr == 0)
+               inet->saddr = rt->rt_src;
+       inet->rcv_saddr = inet->saddr;
+
+       inet->dport = usin->sin_port;
+       inet->daddr = daddr;
+
+       dp->dccps_ext_header_len = 0;
+       if (inet->opt != NULL)
+               dp->dccps_ext_header_len = inet->opt->optlen;
+       /*
+        * Socket identity is still unknown (sport may be zero).
+        * However we set state to DCCP_REQUESTING and not releasing socket
+        * lock select source port, enter ourselves into the hash tables and
+        * complete initialization after this.
+        */
+       dccp_set_state(sk, DCCP_REQUESTING);
+       err = dccp_v4_hash_connect(sk);
+       if (err != 0)
+               goto failure;
+
+       err = ip_route_newports(&rt, inet->sport, inet->dport, sk);
+       if (err != 0)
+               goto failure;
+
+       /* OK, now commit destination to socket.  */
+       sk_setup_caps(sk, &rt->u.dst);
+
+       dp->dccps_gar =
+               dp->dccps_iss = secure_dccp_sequence_number(inet->saddr,
+                                                           inet->daddr,
+                                                           inet->sport,
+                                                           usin->sin_port);
+       dccp_update_gss(sk, dp->dccps_iss);
+
+       /*
+        * SWL and AWL are initially adjusted so that they are not less than
+        * the initial Sequence Numbers received and sent, respectively:
+        *      SWL := max(GSR + 1 - floor(W/4), ISR),
+        *      AWL := max(GSS - W' + 1, ISS).
+        * These adjustments MUST be applied only at the beginning of the
+        * connection.
+        */
+       dccp_set_seqno(&dp->dccps_awl, max48(dp->dccps_awl, dp->dccps_iss));
+
+       inet->id = dp->dccps_iss ^ jiffies;
+
+       err = dccp_connect(sk);
+       rt = NULL;
+       if (err != 0)
+               goto failure;
+out:
+       return err;
+failure:
+       /*
+        * This unhashes the socket and releases the local port, if necessary.
+        */
+       dccp_set_state(sk, DCCP_CLOSED);
+       ip_rt_put(rt);
+       sk->sk_route_caps = 0;
+       inet->dport = 0;
+       goto out;
+}
+
+/*
+ * This routine does path mtu discovery as defined in RFC1191.
+ */
+static inline void dccp_do_pmtu_discovery(struct sock *sk,
+                                         const struct iphdr *iph,
+                                         u32 mtu)
+{
+       struct dst_entry *dst;
+       const struct inet_sock *inet = inet_sk(sk);
+       const struct dccp_sock *dp = dccp_sk(sk);
+
+       /* We are not interested in DCCP_LISTEN and request_socks (RESPONSEs
+        * send out by Linux are always < 576bytes so they should go through
+        * unfragmented).
+        */
+       if (sk->sk_state == DCCP_LISTEN)
+               return;
+
+       /* We don't check in the destentry if pmtu discovery is forbidden
+        * on this route. We just assume that no packet_to_big packets
+        * are send back when pmtu discovery is not active.
+        * There is a small race when the user changes this flag in the
+        * route, but I think that's acceptable.
+        */
+       if ((dst = __sk_dst_check(sk, 0)) == NULL)
+               return;
+
+       dst->ops->update_pmtu(dst, mtu);
+
+       /* Something is about to be wrong... Remember soft error
+        * for the case, if this connection will not able to recover.
+        */
+       if (mtu < dst_mtu(dst) && ip_dont_fragment(sk, dst))
+               sk->sk_err_soft = EMSGSIZE;
+
+       mtu = dst_mtu(dst);
+
+       if (inet->pmtudisc != IP_PMTUDISC_DONT &&
+           dp->dccps_pmtu_cookie > mtu) {
+               dccp_sync_mss(sk, mtu);
+
+               /*
+                * From: draft-ietf-dccp-spec-11.txt
+                *
+                *      DCCP-Sync packets are the best choice for upward
+                *      probing, since DCCP-Sync probes do not risk application
+                *      data loss.
+                */
+               dccp_send_sync(sk, dp->dccps_gsr, DCCP_PKT_SYNC);
+       } /* else let the usual retransmit timer handle it */
+}
+
+static void dccp_v4_ctl_send_ack(struct sk_buff *rxskb)
+{
+       int err;
+       struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
+       const int dccp_hdr_ack_len = sizeof(struct dccp_hdr) +
+                                    sizeof(struct dccp_hdr_ext) +
+                                    sizeof(struct dccp_hdr_ack_bits);
+       struct sk_buff *skb;
+
+       if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL)
+               return;
+
+       skb = alloc_skb(MAX_DCCP_HEADER + 15, GFP_ATOMIC);
+       if (skb == NULL)
+               return;
+
+       /* Reserve space for headers. */
+       skb_reserve(skb, MAX_DCCP_HEADER);
+
+       skb->dst = dst_clone(rxskb->dst);
+
+       skb->h.raw = skb_push(skb, dccp_hdr_ack_len);
+       dh = dccp_hdr(skb);
+       memset(dh, 0, dccp_hdr_ack_len);
+
+       /* Build DCCP header and checksum it. */
+       dh->dccph_type     = DCCP_PKT_ACK;
+       dh->dccph_sport    = rxdh->dccph_dport;
+       dh->dccph_dport    = rxdh->dccph_sport;
+       dh->dccph_doff     = dccp_hdr_ack_len / 4;
+       dh->dccph_x        = 1;
+
+       dccp_hdr_set_seq(dh, DCCP_SKB_CB(rxskb)->dccpd_ack_seq);
+       dccp_hdr_set_ack(dccp_hdr_ack_bits(skb),
+                        DCCP_SKB_CB(rxskb)->dccpd_seq);
+
+       bh_lock_sock(dccp_ctl_socket->sk);
+       err = ip_build_and_send_pkt(skb, dccp_ctl_socket->sk,
+                                   rxskb->nh.iph->daddr,
+                                   rxskb->nh.iph->saddr, NULL);
+       bh_unlock_sock(dccp_ctl_socket->sk);
+
+       if (err == NET_XMIT_CN || err == 0) {
+               DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
+               DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
+       }
+}
+
+static void dccp_v4_reqsk_send_ack(struct sk_buff *skb,
+                                  struct request_sock *req)
+{
+       dccp_v4_ctl_send_ack(skb);
+}
+
+static int dccp_v4_send_response(struct sock *sk, struct request_sock *req,
+                                struct dst_entry *dst)
+{
+       int err = -1;
+       struct sk_buff *skb;
+
+       /* First, grab a route. */
+       
+       if (dst == NULL && (dst = inet_csk_route_req(sk, req)) == NULL)
+               goto out;
+
+       skb = dccp_make_response(sk, dst, req);
+       if (skb != NULL) {
+               const struct inet_request_sock *ireq = inet_rsk(req);
+
+               err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr,
+                                           ireq->rmt_addr,
+                                           ireq->opt);
+               if (err == NET_XMIT_CN)
+                       err = 0;
+       }
+
+out:
+       dst_release(dst);
+       return err;
+}
+
+/*
+ * This routine is called by the ICMP module when it gets some sort of error
+ * condition. If err < 0 then the socket should be closed and the error
+ * returned to the user. If err > 0 it's just the icmp type << 8 | icmp code.
+ * After adjustment header points to the first 8 bytes of the tcp header. We
+ * need to find the appropriate port.
+ *
+ * The locking strategy used here is very "optimistic". When someone else
+ * accesses the socket the ICMP is just dropped and for some paths there is no
+ * check at all. A more general error queue to queue errors for later handling
+ * is probably better.
+ */
+void dccp_v4_err(struct sk_buff *skb, u32 info)
+{
+       const struct iphdr *iph = (struct iphdr *)skb->data;
+       const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data +
+                                                       (iph->ihl << 2));
+       struct dccp_sock *dp;
+       struct inet_sock *inet;
+       const int type = skb->h.icmph->type;
+       const int code = skb->h.icmph->code;
+       struct sock *sk;
+       __u64 seq;
+       int err;
+
+       if (skb->len < (iph->ihl << 2) + 8) {
+               ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
+               return;
+       }
+
+       sk = inet_lookup(&dccp_hashinfo, iph->daddr, dh->dccph_dport,
+                        iph->saddr, dh->dccph_sport, inet_iif(skb));
+       if (sk == NULL) {
+               ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
+               return;
+       }
+
+       if (sk->sk_state == DCCP_TIME_WAIT) {
+               inet_twsk_put((struct inet_timewait_sock *)sk);
+               return;
+       }
+
+       bh_lock_sock(sk);
+       /* If too many ICMPs get dropped on busy
+        * servers this needs to be solved differently.
+        */
+       if (sock_owned_by_user(sk))
+               NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS);
+
+       if (sk->sk_state == DCCP_CLOSED)
+               goto out;
+
+       dp = dccp_sk(sk);
+       seq = dccp_hdr_seq(skb);
+       if (sk->sk_state != DCCP_LISTEN &&
+           !between48(seq, dp->dccps_swl, dp->dccps_swh)) {
+               NET_INC_STATS(LINUX_MIB_OUTOFWINDOWICMPS);
+               goto out;
+       }
+
+       switch (type) {
+       case ICMP_SOURCE_QUENCH:
+               /* Just silently ignore these. */
+               goto out;
+       case ICMP_PARAMETERPROB:
+               err = EPROTO;
+               break;
+       case ICMP_DEST_UNREACH:
+               if (code > NR_ICMP_UNREACH)
+                       goto out;
+
+               if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */
+                       if (!sock_owned_by_user(sk))
+                               dccp_do_pmtu_discovery(sk, iph, info);
+                       goto out;
+               }
+
+               err = icmp_err_convert[code].errno;
+               break;
+       case ICMP_TIME_EXCEEDED:
+               err = EHOSTUNREACH;
+               break;
+       default:
+               goto out;
+       }
+
+       switch (sk->sk_state) {
+               struct request_sock *req , **prev;
+       case DCCP_LISTEN:
+               if (sock_owned_by_user(sk))
+                       goto out;
+               req = inet_csk_search_req(sk, &prev, dh->dccph_dport,
+                                         iph->daddr, iph->saddr);
+               if (!req)
+                       goto out;
+
+               /*
+                * ICMPs are not backlogged, hence we cannot get an established
+                * socket here.
+                */
+               BUG_TRAP(!req->sk);
+
+               if (seq != dccp_rsk(req)->dreq_iss) {
+                       NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
+                       goto out;
+               }
+               /*
+                * Still in RESPOND, just remove it silently.
+                * There is no good way to pass the error to the newly
+                * created socket, and POSIX does not want network
+                * errors returned from accept().
+                */
+               inet_csk_reqsk_queue_drop(sk, req, prev);
+               goto out;
+
+       case DCCP_REQUESTING:
+       case DCCP_RESPOND:
+               if (!sock_owned_by_user(sk)) {
+                       DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
+                       sk->sk_err = err;
+
+                       sk->sk_error_report(sk);
+
+                       dccp_done(sk);
+               } else
+                       sk->sk_err_soft = err;
+               goto out;
+       }
+
+       /* If we've already connected we will keep trying
+        * until we time out, or the user gives up.
+        *
+        * rfc1122 4.2.3.9 allows to consider as hard errors
+        * only PROTO_UNREACH and PORT_UNREACH (well, FRAG_FAILED too,
+        * but it is obsoleted by pmtu discovery).
+        *
+        * Note, that in modern internet, where routing is unreliable
+        * and in each dark corner broken firewalls sit, sending random
+        * errors ordered by their masters even this two messages finally lose
+        * their original sense (even Linux sends invalid PORT_UNREACHs)
+        *
+        * Now we are in compliance with RFCs.
+        *                                                      --ANK (980905)
+        */
+
+       inet = inet_sk(sk);
+       if (!sock_owned_by_user(sk) && inet->recverr) {
+               sk->sk_err = err;
+               sk->sk_error_report(sk);
+       } else /* Only an error on timeout */
+               sk->sk_err_soft = err;
+out:
+       bh_unlock_sock(sk);
+       sock_put(sk);
+}
+
+int dccp_v4_send_reset(struct sock *sk, enum dccp_reset_codes code)
+{
+       struct sk_buff *skb;
+       /*
+        * FIXME: what if rebuild_header fails?
+        * Should we be doing a rebuild_header here?
+        */
+       int err = inet_sk_rebuild_header(sk);
+
+       if (err != 0)
+               return err;
+
+       skb = dccp_make_reset(sk, sk->sk_dst_cache, code);
+       if (skb != NULL) {
+               const struct dccp_sock *dp = dccp_sk(sk);
+               const struct inet_sock *inet = inet_sk(sk);
+
+               err = ip_build_and_send_pkt(skb, sk,
+                                           inet->saddr, inet->daddr, NULL);
+               if (err == NET_XMIT_CN)
+                       err = 0;
+
+               ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk);
+               ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk);
+       }
+
+       return err;
+}
+
+static inline u64 dccp_v4_init_sequence(const struct sock *sk,
+                                       const struct sk_buff *skb)
+{
+       return secure_dccp_sequence_number(skb->nh.iph->daddr,
+                                          skb->nh.iph->saddr,
+                                          dccp_hdr(skb)->dccph_dport,
+                                          dccp_hdr(skb)->dccph_sport);
+}
+
+int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
+{
+       struct inet_request_sock *ireq;
+       struct dccp_sock dp;
+       struct request_sock *req;
+       struct dccp_request_sock *dreq;
+       const __u32 saddr = skb->nh.iph->saddr;
+       const __u32 daddr = skb->nh.iph->daddr;
+       struct dst_entry *dst = NULL;
+
+       /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */
+       if (((struct rtable *)skb->dst)->rt_flags &
+           (RTCF_BROADCAST | RTCF_MULTICAST))
+               goto drop;
+
+       /*
+        * TW buckets are converted to open requests without
+        * limitations, they conserve resources and peer is
+        * evidently real one.
+        */
+       if (inet_csk_reqsk_queue_is_full(sk))
+               goto drop;
+
+       /*
+        * Accept backlog is full. If we have already queued enough
+        * of warm entries in syn queue, drop request. It is better than
+        * clogging syn queue with openreqs with exponentially increasing
+        * timeout.
+        */
+       if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
+               goto drop;
+
+       req = reqsk_alloc(sk->sk_prot->rsk_prot);
+       if (req == NULL)
+               goto drop;
+
+       /* FIXME: process options */
+
+       dccp_openreq_init(req, &dp, skb);
+
+       ireq = inet_rsk(req);
+       ireq->loc_addr = daddr;
+       ireq->rmt_addr = saddr;
+       /* FIXME: Merge Aristeu's option parsing code when ready */
+       req->rcv_wnd    = 100; /* Fake, option parsing will get the
+                                 right value */
+       ireq->opt       = NULL;
+
+       /* 
+        * Step 3: Process LISTEN state
+        *
+        * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
+        *
+        * In fact we defer setting S.GSR, S.SWL, S.SWH to
+        * dccp_create_openreq_child.
+        */
+       dreq = dccp_rsk(req);
+       dreq->dreq_isr = DCCP_SKB_CB(skb)->dccpd_seq;
+       dreq->dreq_iss = dccp_v4_init_sequence(sk, skb);
+       dreq->dreq_service = dccp_hdr_request(skb)->dccph_req_service;
+
+       if (dccp_v4_send_response(sk, req, dst))
+               goto drop_and_free;
+
+       inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
+       return 0;
+
+drop_and_free:
+       /*
+        * FIXME: should be reqsk_free after implementing req->rsk_ops
+        */
+       __reqsk_free(req);
+drop:
+       DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
+       return -1;
+}
+
+/*
+ * The three way handshake has completed - we got a valid ACK or DATAACK -
+ * now create the new socket.
+ *
+ * This is the equivalent of TCP's tcp_v4_syn_recv_sock
+ */
+struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb,
+                                      struct request_sock *req,
+                                      struct dst_entry *dst)
+{
+       struct inet_request_sock *ireq;
+       struct inet_sock *newinet;
+       struct dccp_sock *newdp;
+       struct sock *newsk;
+
+       if (sk_acceptq_is_full(sk))
+               goto exit_overflow;
+
+       if (dst == NULL && (dst = inet_csk_route_req(sk, req)) == NULL)
+               goto exit;
+
+       newsk = dccp_create_openreq_child(sk, req, skb);
+       if (newsk == NULL)
+               goto exit;
+
+       sk_setup_caps(newsk, dst);
+
+       newdp              = dccp_sk(newsk);
+       newinet            = inet_sk(newsk);
+       ireq               = inet_rsk(req);
+       newinet->daddr     = ireq->rmt_addr;
+       newinet->rcv_saddr = ireq->loc_addr;
+       newinet->saddr     = ireq->loc_addr;
+       newinet->opt       = ireq->opt;
+       ireq->opt          = NULL;
+       newinet->mc_index  = inet_iif(skb);
+       newinet->mc_ttl    = skb->nh.iph->ttl;
+       newinet->id        = jiffies;
+
+       dccp_sync_mss(newsk, dst_mtu(dst));
+
+       __inet_hash(&dccp_hashinfo, newsk, 0);
+       __inet_inherit_port(&dccp_hashinfo, sk, newsk);
+
+       return newsk;
+
+exit_overflow:
+       NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS);
+exit:
+       NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS);
+       dst_release(dst);
+       return NULL;
+}
+
+static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
+{
+       const struct dccp_hdr *dh = dccp_hdr(skb);
+       const struct iphdr *iph = skb->nh.iph;
+       struct sock *nsk;
+       struct request_sock **prev;
+       /* Find possible connection requests. */
+       struct request_sock *req = inet_csk_search_req(sk, &prev,
+                                                      dh->dccph_sport,
+                                                      iph->saddr, iph->daddr);
+       if (req != NULL)
+               return dccp_check_req(sk, skb, req, prev);
+
+       nsk = __inet_lookup_established(&dccp_hashinfo,
+                                       iph->saddr, dh->dccph_sport,
+                                       iph->daddr, ntohs(dh->dccph_dport),
+                                       inet_iif(skb));
+       if (nsk != NULL) {
+               if (nsk->sk_state != DCCP_TIME_WAIT) {
+                       bh_lock_sock(nsk);
+                       return nsk;
+               }
+               inet_twsk_put((struct inet_timewait_sock *)nsk);
+               return NULL;
+       }
+
+       return sk;
+}
+
+int dccp_v4_checksum(const struct sk_buff *skb, const u32 saddr,
+                    const u32 daddr)
+{
+       const struct dccp_hdr* dh = dccp_hdr(skb);
+       int checksum_len;
+       u32 tmp;
+
+       if (dh->dccph_cscov == 0)
+               checksum_len = skb->len;
+       else {
+               checksum_len = (dh->dccph_cscov + dh->dccph_x) * sizeof(u32);
+               checksum_len = checksum_len < skb->len ? checksum_len :
+                                                        skb->len;
+       }
+
+       tmp = csum_partial((unsigned char *)dh, checksum_len, 0);
+       return csum_tcpudp_magic(saddr, daddr, checksum_len,
+                                IPPROTO_DCCP, tmp);
+}
+
+static int dccp_v4_verify_checksum(struct sk_buff *skb,
+                                  const u32 saddr, const u32 daddr)
+{
+       struct dccp_hdr *dh = dccp_hdr(skb);
+       int checksum_len;
+       u32 tmp;
+
+       if (dh->dccph_cscov == 0)
+               checksum_len = skb->len;
+       else {
+               checksum_len = (dh->dccph_cscov + dh->dccph_x) * sizeof(u32);
+               checksum_len = checksum_len < skb->len ? checksum_len :
+                                                        skb->len;
+       }
+       tmp = csum_partial((unsigned char *)dh, checksum_len, 0);
+       return csum_tcpudp_magic(saddr, daddr, checksum_len,
+                                IPPROTO_DCCP, tmp) == 0 ? 0 : -1;
+}
+
+static struct dst_entry* dccp_v4_route_skb(struct sock *sk,
+                                          struct sk_buff *skb)
+{
+       struct rtable *rt;
+       struct flowi fl = { .oif = ((struct rtable *)skb->dst)->rt_iif,
+                           .nl_u = { .ip4_u =
+                                     { .daddr = skb->nh.iph->saddr,
+                                       .saddr = skb->nh.iph->daddr,
+                                       .tos = RT_CONN_FLAGS(sk) } },
+                           .proto = sk->sk_protocol,
+                           .uli_u = { .ports =
+                                      { .sport = dccp_hdr(skb)->dccph_dport,
+                                        .dport = dccp_hdr(skb)->dccph_sport }
+                                    }
+                         };
+
+       if (ip_route_output_flow(&rt, &fl, sk, 0)) {
+               IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
+               return NULL;
+       }
+
+       return &rt->u.dst;
+}
+
+static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb)
+{
+       int err;
+       struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
+       const int dccp_hdr_reset_len = sizeof(struct dccp_hdr) +
+                                      sizeof(struct dccp_hdr_ext) +
+                                      sizeof(struct dccp_hdr_reset);
+       struct sk_buff *skb;
+       struct dst_entry *dst;
+       u64 seqno;
+
+       /* Never send a reset in response to a reset. */
+       if (rxdh->dccph_type == DCCP_PKT_RESET)
+               return;
+
+       if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL)
+               return;
+
+       dst = dccp_v4_route_skb(dccp_ctl_socket->sk, rxskb);
+       if (dst == NULL)
+               return;
+
+       skb = alloc_skb(MAX_DCCP_HEADER + 15, GFP_ATOMIC);
+       if (skb == NULL)
+               goto out;
+
+       /* Reserve space for headers. */
+       skb_reserve(skb, MAX_DCCP_HEADER);
+       skb->dst = dst_clone(dst);
+
+       skb->h.raw = skb_push(skb, dccp_hdr_reset_len);
+       dh = dccp_hdr(skb);
+       memset(dh, 0, dccp_hdr_reset_len);
+
+       /* Build DCCP header and checksum it. */
+       dh->dccph_type     = DCCP_PKT_RESET;
+       dh->dccph_sport    = rxdh->dccph_dport;
+       dh->dccph_dport    = rxdh->dccph_sport;
+       dh->dccph_doff     = dccp_hdr_reset_len / 4;
+       dh->dccph_x        = 1;
+       dccp_hdr_reset(skb)->dccph_reset_code =
+                               DCCP_SKB_CB(rxskb)->dccpd_reset_code;
+
+       /* See "8.3.1. Abnormal Termination" in draft-ietf-dccp-spec-11 */
+       seqno = 0;
+       if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
+               dccp_set_seqno(&seqno, DCCP_SKB_CB(rxskb)->dccpd_ack_seq + 1);
+
+       dccp_hdr_set_seq(dh, seqno);
+       dccp_hdr_set_ack(dccp_hdr_ack_bits(skb),
+                        DCCP_SKB_CB(rxskb)->dccpd_seq);
+
+       dh->dccph_checksum = dccp_v4_checksum(skb, rxskb->nh.iph->saddr,
+                                             rxskb->nh.iph->daddr);
+
+       bh_lock_sock(dccp_ctl_socket->sk);
+       err = ip_build_and_send_pkt(skb, dccp_ctl_socket->sk,
+                                   rxskb->nh.iph->daddr,
+                                   rxskb->nh.iph->saddr, NULL);
+       bh_unlock_sock(dccp_ctl_socket->sk);
+
+       if (err == NET_XMIT_CN || err == 0) {
+               DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
+               DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
+       }
+out:
+        dst_release(dst);
+}
+
+int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
+{
+       struct dccp_hdr *dh = dccp_hdr(skb);
+
+       if (sk->sk_state == DCCP_OPEN) { /* Fast path */
+               if (dccp_rcv_established(sk, skb, dh, skb->len))
+                       goto reset;
+               return 0;
+       }
+
+       /*
+        *  Step 3: Process LISTEN state
+        *     If S.state == LISTEN,
+        *        If P.type == Request or P contains a valid Init Cookie
+        *              option,
+        *           * Must scan the packet's options to check for an Init
+        *              Cookie.  Only the Init Cookie is processed here,
+        *              however; other options are processed in Step 8.  This
+        *              scan need only be performed if the endpoint uses Init
+        *              Cookies *
+        *           * Generate a new socket and switch to that socket *
+        *           Set S := new socket for this port pair
+        *           S.state = RESPOND
+        *           Choose S.ISS (initial seqno) or set from Init Cookie
+        *           Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
+        *           Continue with S.state == RESPOND
+        *           * A Response packet will be generated in Step 11 *
+        *        Otherwise,
+        *           Generate Reset(No Connection) unless P.type == Reset
+        *           Drop packet and return
+        *
+        * NOTE: the check for the packet types is done in
+        *       dccp_rcv_state_process
+        */
+       if (sk->sk_state == DCCP_LISTEN) {
+               struct sock *nsk = dccp_v4_hnd_req(sk, skb);
+
+               if (nsk == NULL)
+                       goto discard;
+
+               if (nsk != sk) {
+                       if (dccp_child_process(sk, nsk, skb))
+                               goto reset;
+                       return 0;
+               }
+       }
+
+       if (dccp_rcv_state_process(sk, skb, dh, skb->len))
+               goto reset;
+       return 0;
+
+reset:
+       DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION;
+       dccp_v4_ctl_send_reset(skb);
+discard:
+       kfree_skb(skb);
+       return 0;
+}
+
+static inline int dccp_invalid_packet(struct sk_buff *skb)
+{
+       const struct dccp_hdr *dh;
+
+       if (skb->pkt_type != PACKET_HOST)
+               return 1;
+
+       if (!pskb_may_pull(skb, sizeof(struct dccp_hdr))) {
+               LIMIT_NETDEBUG(KERN_WARNING "DCCP: pskb_may_pull failed\n");
+               return 1;
+       }
+
+       dh = dccp_hdr(skb);
+
+       /* If the packet type is not understood, drop packet and return */
+       if (dh->dccph_type >= DCCP_PKT_INVALID) {
+               LIMIT_NETDEBUG(KERN_WARNING "DCCP: invalid packet type\n");
+               return 1;
+       }
+
+       /*
+        * If P.Data Offset is too small for packet type, or too large for
+        * packet, drop packet and return
+        */
+       if (dh->dccph_doff < dccp_hdr_len(skb) / sizeof(u32)) {
+               LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.Data Offset(%u) "
+                                           "too small 1\n",
+                              dh->dccph_doff);
+               return 1;
+       }
+
+       if (!pskb_may_pull(skb, dh->dccph_doff * sizeof(u32))) {
+               LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.Data Offset(%u) "
+                                           "too small 2\n",
+                              dh->dccph_doff);
+               return 1;
+       }
+
+       dh = dccp_hdr(skb);
+
+       /*
+        * If P.type is not Data, Ack, or DataAck and P.X == 0 (the packet
+        * has short sequence numbers), drop packet and return
+        */
+       if (dh->dccph_x == 0 &&
+           dh->dccph_type != DCCP_PKT_DATA &&
+           dh->dccph_type != DCCP_PKT_ACK &&
+           dh->dccph_type != DCCP_PKT_DATAACK) {
+               LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.type (%s) not Data, Ack "
+                                           "nor DataAck and P.X == 0\n",
+                              dccp_packet_name(dh->dccph_type));
+               return 1;
+       }
+
+       /* If the header checksum is incorrect, drop packet and return */
+       if (dccp_v4_verify_checksum(skb, skb->nh.iph->saddr,
+                                   skb->nh.iph->daddr) < 0) {
+               LIMIT_NETDEBUG(KERN_WARNING "DCCP: header checksum is "
+                                           "incorrect\n");
+               return 1;
+       }
+
+       return 0;
+}
+
+/* this is called when real data arrives */
+int dccp_v4_rcv(struct sk_buff *skb)
+{
+       const struct dccp_hdr *dh;
+       struct sock *sk;
+       int rc;
+
+       /* Step 1: Check header basics: */
+
+       if (dccp_invalid_packet(skb))
+               goto discard_it;
+
+       dh = dccp_hdr(skb);
+#if 0
+       /*
+        * Use something like this to simulate some DATA/DATAACK loss to test
+        * dccp_ackpkts_add, you'll get something like this on a session that
+        * sends 10 DATA/DATAACK packets:
+        *
+        * ackpkts_print: 281473596467422 |0,0|3,0|0,0|3,0|0,0|3,0|0,0|3,0|0,1|
+        *
+        * 0, 0 means: DCCP_ACKPKTS_STATE_RECEIVED, RLE == just this packet
+        * 0, 1 means: DCCP_ACKPKTS_STATE_RECEIVED, RLE == two adjacent packets
+        *                                                 with the same state
+        * 3, 0 means: DCCP_ACKPKTS_STATE_NOT_RECEIVED, RLE == just this packet
+        *
+        * So...
+        *
+        * 281473596467422 was received
+        * 281473596467421 was not received
+        * 281473596467420 was received
+        * 281473596467419 was not received
+        * 281473596467418 was received
+        * 281473596467417 was not received
+        * 281473596467416 was received
+        * 281473596467415 was not received
+        * 281473596467414 was received
+        * 281473596467413 was received (this one was the 3way handshake
+        *                               RESPONSE)
+        *
+        */
+       if (dh->dccph_type == DCCP_PKT_DATA ||
+           dh->dccph_type == DCCP_PKT_DATAACK) {
+               static int discard = 0;
+
+               if (discard) {
+                       discard = 0;
+                       goto discard_it;
+               }
+               discard = 1;
+       }
+#endif
+       DCCP_SKB_CB(skb)->dccpd_seq  = dccp_hdr_seq(skb);
+       DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
+
+       dccp_pr_debug("%8.8s "
+                     "src=%u.%u.%u.%u@%-5d "
+                     "dst=%u.%u.%u.%u@%-5d seq=%llu",
+                     dccp_packet_name(dh->dccph_type),
+                     NIPQUAD(skb->nh.iph->saddr), ntohs(dh->dccph_sport),
+                     NIPQUAD(skb->nh.iph->daddr), ntohs(dh->dccph_dport),
+                     (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq);
+
+       if (dccp_packet_without_ack(skb)) {
+               DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
+               dccp_pr_debug_cat("\n");
+       } else {
+               DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
+               dccp_pr_debug_cat(", ack=%llu\n",
+                                 (unsigned long long)
+                                 DCCP_SKB_CB(skb)->dccpd_ack_seq);
+       }
+
+       /* Step 2:
+        *      Look up flow ID in table and get corresponding socket */
+       sk = __inet_lookup(&dccp_hashinfo,
+                          skb->nh.iph->saddr, dh->dccph_sport,
+                          skb->nh.iph->daddr, ntohs(dh->dccph_dport),
+                          inet_iif(skb));
+
+       /* 
+        * Step 2:
+        *      If no socket ...
+        *              Generate Reset(No Connection) unless P.type == Reset
+        *              Drop packet and return
+        */
+       if (sk == NULL) {
+               dccp_pr_debug("failed to look up flow ID in table and "
+                             "get corresponding socket\n");
+               goto no_dccp_socket;
+       }
+
+       /* 
+        * Step 2:
+        *      ... or S.state == TIMEWAIT,
+        *              Generate Reset(No Connection) unless P.type == Reset
+        *              Drop packet and return
+        */
+              
+       if (sk->sk_state == DCCP_TIME_WAIT) {
+               dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: "
+                             "do_time_wait\n");
+                goto do_time_wait;
+       }
+
+       if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) {
+               dccp_pr_debug("xfrm4_policy_check failed\n");
+               goto discard_and_relse;
+       }
+
+        if (sk_filter(sk, skb, 0)) {
+               dccp_pr_debug("sk_filter failed\n");
+                goto discard_and_relse;
+       }
+
+       skb->dev = NULL;
+
+       bh_lock_sock(sk);
+       rc = 0;
+       if (!sock_owned_by_user(sk))
+               rc = dccp_v4_do_rcv(sk, skb);
+       else
+               sk_add_backlog(sk, skb);
+       bh_unlock_sock(sk);
+
+       sock_put(sk);
+       return rc;
+
+no_dccp_socket:
+       if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
+               goto discard_it;
+       /*
+        * Step 2:
+        *              Generate Reset(No Connection) unless P.type == Reset
+        *              Drop packet and return
+        */
+       if (dh->dccph_type != DCCP_PKT_RESET) {
+               DCCP_SKB_CB(skb)->dccpd_reset_code =
+                                       DCCP_RESET_CODE_NO_CONNECTION;
+               dccp_v4_ctl_send_reset(skb);
+       }
+
+discard_it:
+       /* Discard frame. */
+       kfree_skb(skb);
+       return 0;
+
+discard_and_relse:
+       sock_put(sk);
+       goto discard_it;
+
+do_time_wait:
+       inet_twsk_put((struct inet_timewait_sock *)sk);
+       goto no_dccp_socket;
+}
+
+static int dccp_v4_init_sock(struct sock *sk)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       static int dccp_ctl_socket_init = 1;
+
+       dccp_options_init(&dp->dccps_options);
+
+       if (dp->dccps_options.dccpo_send_ack_vector) {
+               dp->dccps_hc_rx_ackpkts =
+                       dccp_ackpkts_alloc(DCCP_MAX_ACK_VECTOR_LEN,
+                                          GFP_KERNEL);
+
+               if (dp->dccps_hc_rx_ackpkts == NULL)
+                       return -ENOMEM;
+       }
+
+       /*
+        * FIXME: We're hardcoding the CCID, and doing this at this point makes
+        * the listening (master) sock get CCID control blocks, which is not
+        * necessary, but for now, to not mess with the test userspace apps,
+        * lets leave it here, later the real solution is to do this in a
+        * setsockopt(CCIDs-I-want/accept). -acme
+        */
+       if (likely(!dccp_ctl_socket_init)) {
+               dp->dccps_hc_rx_ccid = ccid_init(dp->dccps_options.dccpo_ccid,
+                                                sk);
+               dp->dccps_hc_tx_ccid = ccid_init(dp->dccps_options.dccpo_ccid,
+                                                sk);
+               if (dp->dccps_hc_rx_ccid == NULL ||
+                   dp->dccps_hc_tx_ccid == NULL) {
+                       ccid_exit(dp->dccps_hc_rx_ccid, sk);
+                       ccid_exit(dp->dccps_hc_tx_ccid, sk);
+                       dccp_ackpkts_free(dp->dccps_hc_rx_ackpkts);
+                       dp->dccps_hc_rx_ackpkts = NULL;
+                       dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
+                       return -ENOMEM;
+               }
+       } else
+               dccp_ctl_socket_init = 0;
+
+       dccp_init_xmit_timers(sk);
+       inet_csk(sk)->icsk_rto = DCCP_TIMEOUT_INIT;
+       sk->sk_state = DCCP_CLOSED;
+       sk->sk_write_space = dccp_write_space;
+       dp->dccps_mss_cache = 536;
+       dp->dccps_role = DCCP_ROLE_UNDEFINED;
+
+       return 0;
+}
+
+static int dccp_v4_destroy_sock(struct sock *sk)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+
+       /*
+        * DCCP doesn't use sk_qrite_queue, just sk_send_head
+        * for retransmissions
+        */
+       if (sk->sk_send_head != NULL) {
+               kfree_skb(sk->sk_send_head);
+               sk->sk_send_head = NULL;
+       }
+
+       /* Clean up a referenced DCCP bind bucket. */
+       if (inet_csk(sk)->icsk_bind_hash != NULL)
+               inet_put_port(&dccp_hashinfo, sk);
+
+       ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk);
+       ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk);
+       dccp_ackpkts_free(dp->dccps_hc_rx_ackpkts);
+       dp->dccps_hc_rx_ackpkts = NULL;
+       ccid_exit(dp->dccps_hc_rx_ccid, sk);
+       ccid_exit(dp->dccps_hc_tx_ccid, sk);
+       dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
+
+       return 0;
+}
+
+static void dccp_v4_reqsk_destructor(struct request_sock *req)
+{
+       kfree(inet_rsk(req)->opt);
+}
+
+static struct request_sock_ops dccp_request_sock_ops = {
+       .family         = PF_INET,
+       .obj_size       = sizeof(struct dccp_request_sock),
+       .rtx_syn_ack    = dccp_v4_send_response,
+       .send_ack       = dccp_v4_reqsk_send_ack,
+       .destructor     = dccp_v4_reqsk_destructor,
+       .send_reset     = dccp_v4_ctl_send_reset,
+};
+
+struct proto dccp_v4_prot = {
+       .name                   = "DCCP",
+       .owner                  = THIS_MODULE,
+       .close                  = dccp_close,
+       .connect                = dccp_v4_connect,
+       .disconnect             = dccp_disconnect,
+       .ioctl                  = dccp_ioctl,
+       .init                   = dccp_v4_init_sock,
+       .setsockopt             = dccp_setsockopt,
+       .getsockopt             = dccp_getsockopt,
+       .sendmsg                = dccp_sendmsg,
+       .recvmsg                = dccp_recvmsg,
+       .backlog_rcv            = dccp_v4_do_rcv,
+       .hash                   = dccp_v4_hash,
+       .unhash                 = dccp_v4_unhash,
+       .accept                 = inet_csk_accept,
+       .get_port               = dccp_v4_get_port,
+       .shutdown               = dccp_shutdown,
+       .destroy                = dccp_v4_destroy_sock,
+       .orphan_count           = &dccp_orphan_count,
+       .max_header             = MAX_DCCP_HEADER,
+       .obj_size               = sizeof(struct dccp_sock),
+       .rsk_prot               = &dccp_request_sock_ops,
+       .twsk_obj_size          = sizeof(struct inet_timewait_sock),
+};
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c
new file mode 100644 (file)
index 0000000..ce5dff4
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ *  net/dccp/minisocks.c
+ *
+ *  An implementation of the DCCP protocol
+ *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *     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/dccp.h>
+#include <linux/skbuff.h>
+#include <linux/timer.h>
+
+#include <net/sock.h>
+#include <net/xfrm.h>
+#include <net/inet_timewait_sock.h>
+
+#include "ccid.h"
+#include "dccp.h"
+
+struct inet_timewait_death_row dccp_death_row = {
+       .sysctl_max_tw_buckets = NR_FILE * 2,
+       .period         = DCCP_TIMEWAIT_LEN / INET_TWDR_TWKILL_SLOTS,
+       .death_lock     = SPIN_LOCK_UNLOCKED,
+       .hashinfo       = &dccp_hashinfo,
+       .tw_timer       = TIMER_INITIALIZER(inet_twdr_hangman, 0,
+                                           (unsigned long)&dccp_death_row),
+       .twkill_work    = __WORK_INITIALIZER(dccp_death_row.twkill_work,
+                                            inet_twdr_twkill_work,
+                                            &dccp_death_row),
+/* Short-time timewait calendar */
+
+       .twcal_hand     = -1,
+       .twcal_timer    = TIMER_INITIALIZER(inet_twdr_twcal_tick, 0,
+                                           (unsigned long)&dccp_death_row),
+};
+
+void dccp_time_wait(struct sock *sk, int state, int timeo)
+{
+       struct inet_timewait_sock *tw = NULL;
+
+       if (dccp_death_row.tw_count < dccp_death_row.sysctl_max_tw_buckets)
+               tw = inet_twsk_alloc(sk, state);
+
+       if (tw != NULL) {
+               const struct inet_connection_sock *icsk = inet_csk(sk);
+               const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1);
+
+               /* Linkage updates. */
+               __inet_twsk_hashdance(tw, sk, &dccp_hashinfo);
+
+               /* Get the TIME_WAIT timeout firing. */
+               if (timeo < rto)
+                       timeo = rto;
+
+               tw->tw_timeout = DCCP_TIMEWAIT_LEN;
+               if (state == DCCP_TIME_WAIT)
+                       timeo = DCCP_TIMEWAIT_LEN;
+
+               inet_twsk_schedule(tw, &dccp_death_row, timeo,
+                                  DCCP_TIMEWAIT_LEN);
+               inet_twsk_put(tw);
+       } else {
+               /* Sorry, if we're out of memory, just CLOSE this
+                * socket up.  We've got bigger problems than
+                * non-graceful socket closings.
+                */
+               LIMIT_NETDEBUG(KERN_INFO "DCCP: time wait bucket "
+                                        "table overflow\n");
+       }
+
+       dccp_done(sk);
+}
+
+struct sock *dccp_create_openreq_child(struct sock *sk,
+                                      const struct request_sock *req,
+                                      const struct sk_buff *skb)
+{
+       /*
+        * Step 3: Process LISTEN state
+        *
+        * // Generate a new socket and switch to that socket
+        * Set S := new socket for this port pair
+        */
+       struct sock *newsk = inet_csk_clone(sk, req, GFP_ATOMIC);
+
+       if (newsk != NULL) {
+               const struct dccp_request_sock *dreq = dccp_rsk(req);
+               struct inet_connection_sock *newicsk = inet_csk(sk);
+               struct dccp_sock *newdp = dccp_sk(newsk);
+
+               newdp->dccps_hc_rx_ackpkts = NULL;
+               newdp->dccps_role = DCCP_ROLE_SERVER;
+               newicsk->icsk_rto = DCCP_TIMEOUT_INIT;
+
+               if (newdp->dccps_options.dccpo_send_ack_vector) {
+                       newdp->dccps_hc_rx_ackpkts =
+                               dccp_ackpkts_alloc(DCCP_MAX_ACK_VECTOR_LEN,
+                                                  GFP_ATOMIC);
+                       /*
+                        * XXX: We're using the same CCIDs set on the parent,
+                        * i.e. sk_clone copied the master sock and left the
+                        * CCID pointers for this child, that is why we do the
+                        * __ccid_get calls.
+                        */
+                       if (unlikely(newdp->dccps_hc_rx_ackpkts == NULL))
+                               goto out_free;
+               }
+
+               if (unlikely(ccid_hc_rx_init(newdp->dccps_hc_rx_ccid,
+                                            newsk) != 0 ||
+                            ccid_hc_tx_init(newdp->dccps_hc_tx_ccid,
+                                            newsk) != 0)) {
+                       dccp_ackpkts_free(newdp->dccps_hc_rx_ackpkts);
+                       ccid_hc_rx_exit(newdp->dccps_hc_rx_ccid, newsk);
+                       ccid_hc_tx_exit(newdp->dccps_hc_tx_ccid, newsk);
+out_free:
+                       /* It is still raw copy of parent, so invalidate
+                        * destructor and make plain sk_free() */
+                       newsk->sk_destruct = NULL;
+                       sk_free(newsk);
+                       return NULL;
+               }
+
+               __ccid_get(newdp->dccps_hc_rx_ccid);
+               __ccid_get(newdp->dccps_hc_tx_ccid);
+
+               /*
+                * Step 3: Process LISTEN state
+                *
+                *      Choose S.ISS (initial seqno) or set from Init Cookie
+                *      Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init
+                *      Cookie
+                */
+
+               /* See dccp_v4_conn_request */
+               newdp->dccps_options.dccpo_sequence_window = req->rcv_wnd;
+
+               newdp->dccps_gar = newdp->dccps_isr = dreq->dreq_isr;
+               dccp_update_gsr(newsk, dreq->dreq_isr);
+
+               newdp->dccps_iss = dreq->dreq_iss;
+               dccp_update_gss(newsk, dreq->dreq_iss);
+
+               /*
+                * SWL and AWL are initially adjusted so that they are not less than
+                * the initial Sequence Numbers received and sent, respectively:
+                *      SWL := max(GSR + 1 - floor(W/4), ISR),
+                *      AWL := max(GSS - W' + 1, ISS).
+                * These adjustments MUST be applied only at the beginning of the
+                * connection.
+                */
+               dccp_set_seqno(&newdp->dccps_swl,
+                              max48(newdp->dccps_swl, newdp->dccps_isr));
+               dccp_set_seqno(&newdp->dccps_awl,
+                              max48(newdp->dccps_awl, newdp->dccps_iss));
+
+               dccp_init_xmit_timers(newsk);
+
+               DCCP_INC_STATS_BH(DCCP_MIB_PASSIVEOPENS);
+       }
+       return newsk;
+}
+
+/* 
+ * Process an incoming packet for RESPOND sockets represented
+ * as an request_sock.
+ */
+struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
+                           struct request_sock *req,
+                           struct request_sock **prev)
+{
+       struct sock *child = NULL;
+
+       /* Check for retransmitted REQUEST */
+       if (dccp_hdr(skb)->dccph_type == DCCP_PKT_REQUEST) {
+               if (after48(DCCP_SKB_CB(skb)->dccpd_seq,
+                           dccp_rsk(req)->dreq_isr)) {
+                       struct dccp_request_sock *dreq = dccp_rsk(req);
+
+                       dccp_pr_debug("Retransmitted REQUEST\n");
+                       /* Send another RESPONSE packet */
+                       dccp_set_seqno(&dreq->dreq_iss, dreq->dreq_iss + 1);
+                       dccp_set_seqno(&dreq->dreq_isr,
+                                      DCCP_SKB_CB(skb)->dccpd_seq);
+                       req->rsk_ops->rtx_syn_ack(sk, req, NULL);
+               }
+               /* Network Duplicate, discard packet */
+               return NULL;
+       }
+
+       DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR;
+
+       if (dccp_hdr(skb)->dccph_type != DCCP_PKT_ACK &&
+           dccp_hdr(skb)->dccph_type != DCCP_PKT_DATAACK)
+               goto drop;
+
+       /* Invalid ACK */
+       if (DCCP_SKB_CB(skb)->dccpd_ack_seq != dccp_rsk(req)->dreq_iss) {
+               dccp_pr_debug("Invalid ACK number: ack_seq=%llu, "
+                             "dreq_iss=%llu\n",
+                             (unsigned long long)
+                             DCCP_SKB_CB(skb)->dccpd_ack_seq,
+                             (unsigned long long)
+                             dccp_rsk(req)->dreq_iss);
+               goto drop;
+       }
+
+       child = dccp_v4_request_recv_sock(sk, skb, req, NULL);
+       if (child == NULL)
+               goto listen_overflow;
+
+       /* FIXME: deal with options */
+
+       inet_csk_reqsk_queue_unlink(sk, req, prev);
+       inet_csk_reqsk_queue_removed(sk, req);
+       inet_csk_reqsk_queue_add(sk, req, child);
+out:
+       return child;
+listen_overflow:
+       dccp_pr_debug("listen_overflow!\n");
+       DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
+drop:
+       if (dccp_hdr(skb)->dccph_type != DCCP_PKT_RESET)
+               req->rsk_ops->send_reset(skb);
+
+       inet_csk_reqsk_queue_drop(sk, req, prev);
+       goto out;
+}
+
+/*
+ *  Queue segment on the new socket if the new socket is active,
+ *  otherwise we just shortcircuit this and continue with
+ *  the new socket.
+ */
+int dccp_child_process(struct sock *parent, struct sock *child,
+                      struct sk_buff *skb)
+{
+       int ret = 0;
+       const int state = child->sk_state;
+
+       if (!sock_owned_by_user(child)) {
+               ret = dccp_rcv_state_process(child, skb, dccp_hdr(skb),
+                                            skb->len);
+
+               /* Wakeup parent, send SIGIO */
+               if (state == DCCP_RESPOND && child->sk_state != state)
+                       parent->sk_data_ready(parent, 0);
+       } else {
+               /* Alas, it is possible again, because we do lookup
+                * in main socket hash table and lock on listening
+                * socket does not protect us more.
+                */
+               sk_add_backlog(child, skb);
+       }
+
+       bh_unlock_sock(child);
+       sock_put(child);
+       return ret;
+}
diff --git a/net/dccp/options.c b/net/dccp/options.c
new file mode 100644 (file)
index 0000000..382c589
--- /dev/null
@@ -0,0 +1,855 @@
+/*
+ *  net/dccp/options.c
+ *
+ *  An implementation of the DCCP protocol
+ *  Copyright (c) 2005 Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
+ *  Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
+ *  Copyright (c) 2005 Ian McDonald <iam4@cs.waikato.ac.nz>
+ *
+ *      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/dccp.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+
+#include "ccid.h"
+#include "dccp.h"
+
+static void dccp_ackpkts_check_rcv_ackvector(struct dccp_ackpkts *ap,
+                                            struct sock *sk,
+                                            const u64 ackno,
+                                            const unsigned char len,
+                                            const unsigned char *vector);
+
+/* stores the default values for new connection. may be changed with sysctl */
+static const struct dccp_options dccpo_default_values = {
+       .dccpo_sequence_window    = DCCPF_INITIAL_SEQUENCE_WINDOW,
+       .dccpo_ccid               = DCCPF_INITIAL_CCID,
+       .dccpo_send_ack_vector    = DCCPF_INITIAL_SEND_ACK_VECTOR,
+       .dccpo_send_ndp_count     = DCCPF_INITIAL_SEND_NDP_COUNT,
+};
+
+void dccp_options_init(struct dccp_options *dccpo)
+{
+       memcpy(dccpo, &dccpo_default_values, sizeof(*dccpo));
+}
+
+static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len)
+{
+       u32 value = 0;
+
+       if (len > 3)
+               value += *bf++ << 24;
+       if (len > 2)
+               value += *bf++ << 16;
+       if (len > 1)
+               value += *bf++ << 8;
+       if (len > 0)
+               value += *bf;
+
+       return value;
+}
+
+int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+#ifdef CONFIG_IP_DCCP_DEBUG
+       const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
+                                       "CLIENT rx opt: " : "server rx opt: ";
+#endif
+       const struct dccp_hdr *dh = dccp_hdr(skb);
+       const u8 pkt_type = DCCP_SKB_CB(skb)->dccpd_type;
+       unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb);
+       unsigned char *opt_ptr = options;
+       const unsigned char *opt_end = (unsigned char *)dh +
+                                       (dh->dccph_doff * 4);
+       struct dccp_options_received *opt_recv = &dp->dccps_options_received;
+       unsigned char opt, len;
+       unsigned char *value;
+
+       memset(opt_recv, 0, sizeof(*opt_recv));
+
+       while (opt_ptr != opt_end) {
+               opt   = *opt_ptr++;
+               len   = 0;
+               value = NULL;
+
+               /* Check if this isn't a single byte option */
+               if (opt > DCCPO_MAX_RESERVED) {
+                       if (opt_ptr == opt_end)
+                               goto out_invalid_option;
+
+                       len = *opt_ptr++;
+                       if (len < 3)
+                               goto out_invalid_option;
+                       /*
+                        * Remove the type and len fields, leaving
+                        * just the value size
+                        */
+                       len     -= 2;
+                       value   = opt_ptr;
+                       opt_ptr += len;
+
+                       if (opt_ptr > opt_end)
+                               goto out_invalid_option;
+               }
+
+               switch (opt) {
+               case DCCPO_PADDING:
+                       break;
+               case DCCPO_NDP_COUNT:
+                       if (len > 3)
+                               goto out_invalid_option;
+
+                       opt_recv->dccpor_ndp = dccp_decode_value_var(value, len);
+                       dccp_pr_debug("%sNDP count=%d\n", debug_prefix,
+                                     opt_recv->dccpor_ndp);
+                       break;
+               case DCCPO_ACK_VECTOR_0:
+                       if (len > DCCP_MAX_ACK_VECTOR_LEN)
+                               goto out_invalid_option;
+
+                       if (pkt_type == DCCP_PKT_DATA)
+                               continue;
+
+                       opt_recv->dccpor_ack_vector_len = len;
+                       opt_recv->dccpor_ack_vector_idx = value - options;
+
+                       dccp_pr_debug("%sACK vector 0, len=%d, ack_ackno=%llu\n",
+                                     debug_prefix, len,
+                                     (unsigned long long)
+                                     DCCP_SKB_CB(skb)->dccpd_ack_seq);
+                       dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq,
+                                            value, len);
+                       dccp_ackpkts_check_rcv_ackvector(dp->dccps_hc_rx_ackpkts,
+                                                        sk,
+                                                DCCP_SKB_CB(skb)->dccpd_ack_seq,
+                                                        len, value);
+                       break;
+               case DCCPO_TIMESTAMP:
+                       if (len != 4)
+                               goto out_invalid_option;
+
+                       opt_recv->dccpor_timestamp = ntohl(*(u32 *)value);
+
+                       dp->dccps_timestamp_echo = opt_recv->dccpor_timestamp;
+                       do_gettimeofday(&dp->dccps_timestamp_time);
+
+                       dccp_pr_debug("%sTIMESTAMP=%u, ackno=%llu\n",
+                                     debug_prefix, opt_recv->dccpor_timestamp,
+                                     (unsigned long long)
+                                     DCCP_SKB_CB(skb)->dccpd_ack_seq);
+                       break;
+               case DCCPO_TIMESTAMP_ECHO:
+                       if (len != 4 && len != 6 && len != 8)
+                               goto out_invalid_option;
+
+                       opt_recv->dccpor_timestamp_echo = ntohl(*(u32 *)value);
+
+                       dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, ackno=%llu, ",
+                                     debug_prefix,
+                                     opt_recv->dccpor_timestamp_echo,
+                                     len + 2,
+                                     (unsigned long long)
+                                     DCCP_SKB_CB(skb)->dccpd_ack_seq);
+
+                       if (len > 4) {
+                               if (len == 6)
+                                       opt_recv->dccpor_elapsed_time =
+                                                ntohs(*(u16 *)(value + 4));
+                               else
+                                       opt_recv->dccpor_elapsed_time =
+                                                ntohl(*(u32 *)(value + 4));
+
+                               dccp_pr_debug("%sTIMESTAMP_ECHO ELAPSED_TIME=%d\n",
+                                     debug_prefix,
+                                     opt_recv->dccpor_elapsed_time);
+                       }
+                       break;
+               case DCCPO_ELAPSED_TIME:
+                       if (len != 2 && len != 4)
+                               goto out_invalid_option;
+
+                       if (pkt_type == DCCP_PKT_DATA)
+                               continue;
+
+                       if (len == 2)
+                               opt_recv->dccpor_elapsed_time =
+                                                       ntohs(*(u16 *)value);
+                       else
+                               opt_recv->dccpor_elapsed_time =
+                                                       ntohl(*(u32 *)value);
+
+                       dccp_pr_debug("%sELAPSED_TIME=%d\n", debug_prefix,
+                                     opt_recv->dccpor_elapsed_time);
+                       break;
+                       /*
+                        * From draft-ietf-dccp-spec-11.txt:
+                        *
+                        *      Option numbers 128 through 191 are for
+                        *      options sent from the HC-Sender to the
+                        *      HC-Receiver; option numbers 192 through 255
+                        *      are for options sent from the HC-Receiver to
+                        *      the HC-Sender.
+                        */
+               case 128 ... 191: {
+                       const u16 idx = value - options;
+
+                       if (ccid_hc_rx_parse_options(dp->dccps_hc_rx_ccid, sk,
+                                                    opt, len, idx,
+                                                    value) != 0)
+                               goto out_invalid_option;
+               }
+                       break;
+               case 192 ... 255: {
+                       const u16 idx = value - options;
+
+                       if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk,
+                                                    opt, len, idx,
+                                                    value) != 0)
+                               goto out_invalid_option;
+               }
+                       break;
+               default:
+                       pr_info("DCCP(%p): option %d(len=%d) not "
+                               "implemented, ignoring\n",
+                               sk, opt, len);
+                       break;
+               }
+       }
+
+       return 0;
+
+out_invalid_option:
+       DCCP_INC_STATS_BH(DCCP_MIB_INVALIDOPT);
+       DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_OPTION_ERROR;
+       pr_info("DCCP(%p): invalid option %d, len=%d\n", sk, opt, len);
+       return -1;
+}
+
+static void dccp_encode_value_var(const u32 value, unsigned char *to,
+                                 const unsigned int len)
+{
+       if (len > 3)
+               *to++ = (value & 0xFF000000) >> 24;
+       if (len > 2)
+               *to++ = (value & 0xFF0000) >> 16;
+       if (len > 1)
+               *to++ = (value & 0xFF00) >> 8;
+       if (len > 0)
+               *to++ = (value & 0xFF);
+}
+
+static inline int dccp_ndp_len(const int ndp)
+{
+       return likely(ndp <= 0xFF) ? 1 : ndp <= 0xFFFF ? 2 : 3;
+}
+
+void dccp_insert_option(struct sock *sk, struct sk_buff *skb,
+                       const unsigned char option,
+                       const void *value, const unsigned char len)
+{
+       unsigned char *to;
+
+       if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN) {
+               LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert "
+                              "%d option!\n", option);
+               return;
+       }
+
+       DCCP_SKB_CB(skb)->dccpd_opt_len += len + 2;
+
+       to    = skb_push(skb, len + 2);
+       *to++ = option;
+       *to++ = len + 2;
+
+       memcpy(to, value, len);
+}
+
+EXPORT_SYMBOL_GPL(dccp_insert_option);
+
+static void dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       int ndp = dp->dccps_ndp_count;
+
+       if (dccp_non_data_packet(skb))
+               ++dp->dccps_ndp_count;
+       else
+               dp->dccps_ndp_count = 0;
+
+       if (ndp > 0) {
+               unsigned char *ptr;
+               const int ndp_len = dccp_ndp_len(ndp);
+               const int len = ndp_len + 2;
+
+               if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
+                       return;
+
+               DCCP_SKB_CB(skb)->dccpd_opt_len += len;
+
+               ptr = skb_push(skb, len);
+               *ptr++ = DCCPO_NDP_COUNT;
+               *ptr++ = len;
+               dccp_encode_value_var(ndp, ptr, ndp_len);
+       }
+}
+
+static inline int dccp_elapsed_time_len(const u32 elapsed_time)
+{
+       return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4;
+}
+
+void dccp_insert_option_elapsed_time(struct sock *sk,
+                                    struct sk_buff *skb,
+                                    u32 elapsed_time)
+{
+#ifdef CONFIG_IP_DCCP_DEBUG
+       struct dccp_sock *dp = dccp_sk(sk);
+       const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
+                                       "CLIENT TX opt: " : "server TX opt: ";
+#endif
+       const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time);
+       const int len = 2 + elapsed_time_len;
+       unsigned char *to;
+
+       if (elapsed_time_len == 0)
+               return;
+
+       if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) {
+               LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to "
+                                        "insert elapsed time!\n");
+               return;
+       }
+
+       DCCP_SKB_CB(skb)->dccpd_opt_len += len;
+
+       to    = skb_push(skb, len);
+       *to++ = DCCPO_ELAPSED_TIME;
+       *to++ = len;
+
+       if (elapsed_time_len == 2) {
+               const u16 var16 = htons((u16)elapsed_time);
+               memcpy(to, &var16, 2);
+       } else {
+               const u32 var32 = htonl(elapsed_time);
+               memcpy(to, &var32, 4);
+       }
+
+       dccp_pr_debug("%sELAPSED_TIME=%u, len=%d, seqno=%llu\n",
+                     debug_prefix, elapsed_time,
+                     len,
+                     (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq);
+}
+
+EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time);
+
+static void dccp_insert_option_ack_vector(struct sock *sk, struct sk_buff *skb)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+#ifdef CONFIG_IP_DCCP_DEBUG
+       const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
+                                       "CLIENT TX opt: " : "server TX opt: ";
+#endif
+       struct dccp_ackpkts *ap = dp->dccps_hc_rx_ackpkts;
+       int len = ap->dccpap_buf_vector_len + 2;
+       const u32 elapsed_time = timeval_now_delta(&ap->dccpap_time) / 10;
+       unsigned char *to, *from;
+
+       if (elapsed_time != 0)
+               dccp_insert_option_elapsed_time(sk, skb, elapsed_time);
+
+       if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) {
+               LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to "
+                                        "insert ACK Vector!\n");
+               return;
+       }
+
+       /*
+        * XXX: now we have just one ack vector sent record, so
+        * we have to wait for it to be cleared.
+        *
+        * Of course this is not acceptable, but this is just for
+        * basic testing now.
+        */
+       if (ap->dccpap_ack_seqno != DCCP_MAX_SEQNO + 1)
+               return;
+
+       DCCP_SKB_CB(skb)->dccpd_opt_len += len;
+
+       to    = skb_push(skb, len);
+       *to++ = DCCPO_ACK_VECTOR_0;
+       *to++ = len;
+
+       len  = ap->dccpap_buf_vector_len;
+       from = ap->dccpap_buf + ap->dccpap_buf_head;
+
+       /* Check if buf_head wraps */
+       if (ap->dccpap_buf_head + len > ap->dccpap_buf_len) {
+               const unsigned int tailsize = (ap->dccpap_buf_len -
+                                              ap->dccpap_buf_head);
+
+               memcpy(to, from, tailsize);
+               to   += tailsize;
+               len  -= tailsize;
+               from = ap->dccpap_buf;
+       }
+
+       memcpy(to, from, len);
+       /*
+        *      From draft-ietf-dccp-spec-11.txt:
+        *
+        *      For each acknowledgement it sends, the HC-Receiver will add an
+        *      acknowledgement record.  ack_seqno will equal the HC-Receiver
+        *      sequence number it used for the ack packet; ack_ptr will equal
+        *      buf_head; ack_ackno will equal buf_ackno; and ack_nonce will
+        *      equal buf_nonce.
+        *
+        * This implemention uses just one ack record for now.
+        */
+       ap->dccpap_ack_seqno      = DCCP_SKB_CB(skb)->dccpd_seq;
+       ap->dccpap_ack_ptr        = ap->dccpap_buf_head;
+       ap->dccpap_ack_ackno      = ap->dccpap_buf_ackno;
+       ap->dccpap_ack_nonce      = ap->dccpap_buf_nonce;
+       ap->dccpap_ack_vector_len = ap->dccpap_buf_vector_len;
+
+       dccp_pr_debug("%sACK Vector 0, len=%d, ack_seqno=%llu, "
+                     "ack_ackno=%llu\n",
+                     debug_prefix, ap->dccpap_ack_vector_len,
+                     (unsigned long long) ap->dccpap_ack_seqno,
+                     (unsigned long long) ap->dccpap_ack_ackno);
+}
+
+void dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb)
+{
+       struct timeval tv;
+       u32 now;
+       
+       do_gettimeofday(&tv);
+       now = (tv.tv_sec * USEC_PER_SEC + tv.tv_usec) / 10;
+       /* yes this will overflow but that is the point as we want a
+        * 10 usec 32 bit timer which mean it wraps every 11.9 hours */
+
+       now = htonl(now);
+       dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now));
+}
+
+EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp);
+
+static void dccp_insert_option_timestamp_echo(struct sock *sk,
+                                             struct sk_buff *skb)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+#ifdef CONFIG_IP_DCCP_DEBUG
+       const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
+                                       "CLIENT TX opt: " : "server TX opt: ";
+#endif
+       u32 tstamp_echo;
+       const u32 elapsed_time =
+                       timeval_now_delta(&dp->dccps_timestamp_time) / 10;
+       const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time);
+       const int len = 6 + elapsed_time_len;
+       unsigned char *to;
+
+       if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) {
+               LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert "
+                                        "timestamp echo!\n");
+               return;
+       }
+
+       DCCP_SKB_CB(skb)->dccpd_opt_len += len;
+
+       to    = skb_push(skb, len);
+       *to++ = DCCPO_TIMESTAMP_ECHO;
+       *to++ = len;
+
+       tstamp_echo = htonl(dp->dccps_timestamp_echo);
+       memcpy(to, &tstamp_echo, 4);
+       to += 4;
+       
+       if (elapsed_time_len == 2) {
+               const u16 var16 = htons((u16)elapsed_time);
+               memcpy(to, &var16, 2);
+       } else if (elapsed_time_len == 4) {
+               const u32 var32 = htonl(elapsed_time);
+               memcpy(to, &var32, 4);
+       }
+
+       dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, seqno=%llu\n",
+                     debug_prefix, dp->dccps_timestamp_echo,
+                     len,
+                     (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq);
+
+       dp->dccps_timestamp_echo = 0;
+       dp->dccps_timestamp_time.tv_sec = 0;
+       dp->dccps_timestamp_time.tv_usec = 0;
+}
+
+void dccp_insert_options(struct sock *sk, struct sk_buff *skb)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+
+       DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
+
+       if (dp->dccps_options.dccpo_send_ndp_count)
+               dccp_insert_option_ndp(sk, skb);
+
+       if (!dccp_packet_without_ack(skb)) {
+               if (dp->dccps_options.dccpo_send_ack_vector &&
+                   (dp->dccps_hc_rx_ackpkts->dccpap_buf_ackno !=
+                    DCCP_MAX_SEQNO + 1))
+                       dccp_insert_option_ack_vector(sk, skb);
+
+               if (dp->dccps_timestamp_echo != 0)
+                       dccp_insert_option_timestamp_echo(sk, skb);
+       }
+
+       ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb);
+       ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb);
+
+       /* XXX: insert other options when appropriate */
+
+       if (DCCP_SKB_CB(skb)->dccpd_opt_len != 0) {
+               /* The length of all options has to be a multiple of 4 */
+               int padding = DCCP_SKB_CB(skb)->dccpd_opt_len % 4;
+
+               if (padding != 0) {
+                       padding = 4 - padding;
+                       memset(skb_push(skb, padding), 0, padding);
+                       DCCP_SKB_CB(skb)->dccpd_opt_len += padding;
+               }
+       }
+}
+
+struct dccp_ackpkts *dccp_ackpkts_alloc(const unsigned int len,
+                                       const unsigned int __nocast priority)
+{
+       struct dccp_ackpkts *ap = kmalloc(sizeof(*ap) + len, priority);
+
+       if (ap != NULL) {
+#ifdef CONFIG_IP_DCCP_DEBUG
+               memset(ap->dccpap_buf, 0xFF, len);
+#endif
+               ap->dccpap_buf_len   = len;
+               ap->dccpap_buf_head  =
+                       ap->dccpap_buf_tail =
+                               ap->dccpap_buf_len - 1;
+               ap->dccpap_buf_ackno =
+                       ap->dccpap_ack_ackno =
+                               ap->dccpap_ack_seqno = DCCP_MAX_SEQNO + 1;
+               ap->dccpap_buf_nonce = ap->dccpap_buf_nonce = 0;
+               ap->dccpap_ack_ptr   = 0;
+               ap->dccpap_time.tv_sec = 0;
+               ap->dccpap_time.tv_usec = 0;
+               ap->dccpap_buf_vector_len = ap->dccpap_ack_vector_len = 0;
+       }
+
+       return ap;
+}
+
+void dccp_ackpkts_free(struct dccp_ackpkts *ap)
+{
+       if (ap != NULL) {
+#ifdef CONFIG_IP_DCCP_DEBUG
+               memset(ap, 0xFF, sizeof(*ap) + ap->dccpap_buf_len);
+#endif
+               kfree(ap);
+       }
+}
+
+static inline u8 dccp_ackpkts_state(const struct dccp_ackpkts *ap,
+                                   const unsigned int index)
+{
+       return ap->dccpap_buf[index] & DCCP_ACKPKTS_STATE_MASK;
+}
+
+static inline u8 dccp_ackpkts_len(const struct dccp_ackpkts *ap,
+                                 const unsigned int index)
+{
+       return ap->dccpap_buf[index] & DCCP_ACKPKTS_LEN_MASK;
+}
+
+/*
+ * If several packets are missing, the HC-Receiver may prefer to enter multiple
+ * bytes with run length 0, rather than a single byte with a larger run length;
+ * this simplifies table updates if one of the missing packets arrives.
+ */
+static inline int dccp_ackpkts_set_buf_head_state(struct dccp_ackpkts *ap,
+                                                 const unsigned int packets,
+                                                 const unsigned char state)
+{
+       unsigned int gap;
+       signed long new_head;
+
+       if (ap->dccpap_buf_vector_len + packets > ap->dccpap_buf_len)
+               return -ENOBUFS;
+
+       gap      = packets - 1;
+       new_head = ap->dccpap_buf_head - packets;
+
+       if (new_head < 0) {
+               if (gap > 0) {
+                       memset(ap->dccpap_buf, DCCP_ACKPKTS_STATE_NOT_RECEIVED,
+                              gap + new_head + 1);
+                       gap = -new_head;
+               }
+               new_head += ap->dccpap_buf_len;
+       } 
+
+       ap->dccpap_buf_head = new_head;
+
+       if (gap > 0)
+               memset(ap->dccpap_buf + ap->dccpap_buf_head + 1,
+                      DCCP_ACKPKTS_STATE_NOT_RECEIVED, gap);
+
+       ap->dccpap_buf[ap->dccpap_buf_head] = state;
+       ap->dccpap_buf_vector_len += packets;
+       return 0;
+}
+
+/*
+ * Implements the draft-ietf-dccp-spec-11.txt Appendix A
+ */
+int dccp_ackpkts_add(struct dccp_ackpkts *ap, u64 ackno, u8 state)
+{
+       /*
+        * Check at the right places if the buffer is full, if it is, tell the
+        * caller to start dropping packets till the HC-Sender acks our ACK
+        * vectors, when we will free up space in dccpap_buf.
+        *
+        * We may well decide to do buffer compression, etc, but for now lets
+        * just drop.
+        *
+        * From Appendix A:
+        *
+        *      Of course, the circular buffer may overflow, either when the
+        *      HC-Sender is sending data at a very high rate, when the
+        *      HC-Receiver's acknowledgements are not reaching the HC-Sender,
+        *      or when the HC-Sender is forgetting to acknowledge those acks
+        *      (so the HC-Receiver is unable to clean up old state). In this
+        *      case, the HC-Receiver should either compress the buffer (by
+        *      increasing run lengths when possible), transfer its state to
+        *      a larger buffer, or, as a last resort, drop all received
+        *      packets, without processing them whatsoever, until its buffer
+        *      shrinks again.
+        */
+
+       /* See if this is the first ackno being inserted */
+       if (ap->dccpap_buf_vector_len == 0) {
+               ap->dccpap_buf[ap->dccpap_buf_head] = state;
+               ap->dccpap_buf_vector_len = 1;
+       } else if (after48(ackno, ap->dccpap_buf_ackno)) {
+               const u64 delta = dccp_delta_seqno(ap->dccpap_buf_ackno,
+                                                  ackno);
+
+               /*
+                * Look if the state of this packet is the same as the
+                * previous ackno and if so if we can bump the head len.
+                */
+               if (delta == 1 &&
+                   dccp_ackpkts_state(ap, ap->dccpap_buf_head) == state &&
+                   (dccp_ackpkts_len(ap, ap->dccpap_buf_head) <
+                    DCCP_ACKPKTS_LEN_MASK))
+                       ap->dccpap_buf[ap->dccpap_buf_head]++;
+               else if (dccp_ackpkts_set_buf_head_state(ap, delta, state))
+                       return -ENOBUFS;
+       } else {
+               /*
+                * A.1.2.  Old Packets
+                *
+                *      When a packet with Sequence Number S arrives, and
+                *      S <= buf_ackno, the HC-Receiver will scan the table
+                *      for the byte corresponding to S. (Indexing structures
+                *      could reduce the complexity of this scan.)
+                */
+               u64 delta = dccp_delta_seqno(ackno, ap->dccpap_buf_ackno);
+               unsigned int index = ap->dccpap_buf_head;
+
+               while (1) {
+                       const u8 len = dccp_ackpkts_len(ap, index);
+                       const u8 state = dccp_ackpkts_state(ap, index);
+                       /*
+                        * valid packets not yet in dccpap_buf have a reserved
+                        * entry, with a len equal to 0.
+                        */
+                       if (state == DCCP_ACKPKTS_STATE_NOT_RECEIVED &&
+                           len == 0 && delta == 0) { /* Found our
+                                                        reserved seat! */
+                               dccp_pr_debug("Found %llu reserved seat!\n",
+                                             (unsigned long long) ackno);
+                               ap->dccpap_buf[index] = state;
+                               goto out;
+                       }
+                       /* len == 0 means one packet */
+                       if (delta < len + 1)
+                               goto out_duplicate;
+
+                       delta -= len + 1;
+                       if (++index == ap->dccpap_buf_len)
+                               index = 0;
+               }
+       }
+
+       ap->dccpap_buf_ackno = ackno;
+       do_gettimeofday(&ap->dccpap_time);
+out:
+       dccp_pr_debug("");
+       dccp_ackpkts_print(ap);
+       return 0;
+
+out_duplicate:
+       /* Duplicate packet */
+       dccp_pr_debug("Received a dup or already considered lost "
+                     "packet: %llu\n", (unsigned long long) ackno);
+       return -EILSEQ;
+}
+
+#ifdef CONFIG_IP_DCCP_DEBUG
+void dccp_ackvector_print(const u64 ackno, const unsigned char *vector,
+                         int len)
+{
+       if (!dccp_debug)
+               return;
+
+       printk("ACK vector len=%d, ackno=%llu |", len,
+              (unsigned long long) ackno);
+
+       while (len--) {
+               const u8 state = (*vector & DCCP_ACKPKTS_STATE_MASK) >> 6;
+               const u8 rl = (*vector & DCCP_ACKPKTS_LEN_MASK);
+
+               printk("%d,%d|", state, rl);
+               ++vector;
+       }
+
+       printk("\n");
+}
+
+void dccp_ackpkts_print(const struct dccp_ackpkts *ap)
+{
+       dccp_ackvector_print(ap->dccpap_buf_ackno,
+                            ap->dccpap_buf + ap->dccpap_buf_head,
+                            ap->dccpap_buf_vector_len);
+}
+#endif
+
+static void dccp_ackpkts_trow_away_ack_record(struct dccp_ackpkts *ap)
+{
+       /*
+        * As we're keeping track of the ack vector size
+        * (dccpap_buf_vector_len) and the sent ack vector size
+        * (dccpap_ack_vector_len) we don't need dccpap_buf_tail at all, but
+        * keep this code here as in the future we'll implement a vector of
+        * ack records, as suggested in draft-ietf-dccp-spec-11.txt
+        * Appendix A. -acme
+        */
+#if 0
+       ap->dccpap_buf_tail = ap->dccpap_ack_ptr + 1;
+       if (ap->dccpap_buf_tail >= ap->dccpap_buf_len)
+               ap->dccpap_buf_tail -= ap->dccpap_buf_len;
+#endif
+       ap->dccpap_buf_vector_len -= ap->dccpap_ack_vector_len;
+}
+
+void dccp_ackpkts_check_rcv_ackno(struct dccp_ackpkts *ap, struct sock *sk,
+                                u64 ackno)
+{
+       /* Check if we actually sent an ACK vector */
+       if (ap->dccpap_ack_seqno == DCCP_MAX_SEQNO + 1)
+               return;
+
+       if (ackno == ap->dccpap_ack_seqno) {
+#ifdef CONFIG_IP_DCCP_DEBUG
+               struct dccp_sock *dp = dccp_sk(sk);
+               const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
+                                       "CLIENT rx ack: " : "server rx ack: ";
+#endif
+               dccp_pr_debug("%sACK packet 0, len=%d, ack_seqno=%llu, "
+                             "ack_ackno=%llu, ACKED!\n",
+                             debug_prefix, 1,
+                             (unsigned long long) ap->dccpap_ack_seqno,
+                             (unsigned long long) ap->dccpap_ack_ackno);
+               dccp_ackpkts_trow_away_ack_record(ap);
+               ap->dccpap_ack_seqno = DCCP_MAX_SEQNO + 1;
+       }
+}
+
+static void dccp_ackpkts_check_rcv_ackvector(struct dccp_ackpkts *ap,
+                                            struct sock *sk, u64 ackno,
+                                            const unsigned char len,
+                                            const unsigned char *vector)
+{
+       unsigned char i;
+
+       /* Check if we actually sent an ACK vector */
+       if (ap->dccpap_ack_seqno == DCCP_MAX_SEQNO + 1)
+               return;
+       /*
+        * We're in the receiver half connection, so if the received an ACK
+        * vector ackno (e.g. 50) before dccpap_ack_seqno (e.g. 52), we're
+        * not interested.
+        *
+        * Extra explanation with example:
+        * 
+        * if we received an ACK vector with ackno 50, it can only be acking
+        * 50, 49, 48, etc, not 52 (the seqno for the ACK vector we sent).
+        */
+       /* dccp_pr_debug("is %llu < %llu? ", ackno, ap->dccpap_ack_seqno); */
+       if (before48(ackno, ap->dccpap_ack_seqno)) {
+               /* dccp_pr_debug_cat("yes\n"); */
+               return;
+       }
+       /* dccp_pr_debug_cat("no\n"); */
+
+       i = len;
+       while (i--) {
+               const u8 rl = (*vector & DCCP_ACKPKTS_LEN_MASK);
+               u64 ackno_end_rl;
+
+               dccp_set_seqno(&ackno_end_rl, ackno - rl);
+
+               /*
+                * dccp_pr_debug("is %llu <= %llu <= %llu? ", ackno_end_rl,
+                * ap->dccpap_ack_seqno, ackno);
+                */
+               if (between48(ap->dccpap_ack_seqno, ackno_end_rl, ackno)) {
+                       const u8 state = (*vector &
+                                         DCCP_ACKPKTS_STATE_MASK) >> 6;
+                       /* dccp_pr_debug_cat("yes\n"); */
+
+                       if (state != DCCP_ACKPKTS_STATE_NOT_RECEIVED) {
+#ifdef CONFIG_IP_DCCP_DEBUG
+                               struct dccp_sock *dp = dccp_sk(sk);
+                               const char *debug_prefix =
+                                       dp->dccps_role == DCCP_ROLE_CLIENT ?
+                                       "CLIENT rx ack: " : "server rx ack: ";
+#endif
+                               dccp_pr_debug("%sACK vector 0, len=%d, "
+                                             "ack_seqno=%llu, ack_ackno=%llu, "
+                                             "ACKED!\n",
+                                             debug_prefix, len,
+                                             (unsigned long long)
+                                             ap->dccpap_ack_seqno,
+                                             (unsigned long long)
+                                             ap->dccpap_ack_ackno);
+                               dccp_ackpkts_trow_away_ack_record(ap);
+                       }
+                       /*
+                        * If dccpap_ack_seqno was not received, no problem
+                        * we'll send another ACK vector.
+                        */
+                       ap->dccpap_ack_seqno = DCCP_MAX_SEQNO + 1;
+                       break;
+               }
+               /* dccp_pr_debug_cat("no\n"); */
+
+               dccp_set_seqno(&ackno, ackno_end_rl - 1);
+               ++vector;
+       }
+}
diff --git a/net/dccp/output.c b/net/dccp/output.c
new file mode 100644 (file)
index 0000000..28de157
--- /dev/null
@@ -0,0 +1,528 @@
+/*
+ *  net/dccp/output.c
+ * 
+ *  An implementation of the DCCP protocol
+ *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *     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/dccp.h>
+#include <linux/skbuff.h>
+
+#include <net/sock.h>
+
+#include "ccid.h"
+#include "dccp.h"
+
+static inline void dccp_event_ack_sent(struct sock *sk)
+{
+       inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK);
+}
+
+/*
+ * All SKB's seen here are completely headerless. It is our
+ * job to build the DCCP header, and pass the packet down to
+ * IP so it can do the same plus pass the packet off to the
+ * device.
+ */
+int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
+{
+       if (likely(skb != NULL)) {
+               const struct inet_sock *inet = inet_sk(sk);
+               struct dccp_sock *dp = dccp_sk(sk);
+               struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
+               struct dccp_hdr *dh;
+               /* XXX For now we're using only 48 bits sequence numbers */
+               const int dccp_header_size = sizeof(*dh) +
+                                            sizeof(struct dccp_hdr_ext) +
+                                         dccp_packet_hdr_len(dcb->dccpd_type);
+               int err, set_ack = 1;
+               u64 ackno = dp->dccps_gsr;
+
+               dccp_inc_seqno(&dp->dccps_gss);
+
+               switch (dcb->dccpd_type) {
+               case DCCP_PKT_DATA:
+                       set_ack = 0;
+                       break;
+               case DCCP_PKT_SYNC:
+               case DCCP_PKT_SYNCACK:
+                       ackno = dcb->dccpd_seq;
+                       break;
+               }
+
+               dcb->dccpd_seq = dp->dccps_gss;
+               dccp_insert_options(sk, skb);
+               
+               skb->h.raw = skb_push(skb, dccp_header_size);
+               dh = dccp_hdr(skb);
+               /*
+                * Data packets are not cloned as they are never retransmitted
+                */
+               if (skb_cloned(skb))
+                       skb_set_owner_w(skb, sk);
+
+               /* Build DCCP header and checksum it. */
+               memset(dh, 0, dccp_header_size);
+               dh->dccph_type  = dcb->dccpd_type;
+               dh->dccph_sport = inet->sport;
+               dh->dccph_dport = inet->dport;
+               dh->dccph_doff  = (dccp_header_size + dcb->dccpd_opt_len) / 4;
+               dh->dccph_ccval = dcb->dccpd_ccval;
+               /* XXX For now we're using only 48 bits sequence numbers */
+               dh->dccph_x     = 1;
+
+               dp->dccps_awh = dp->dccps_gss;
+               dccp_hdr_set_seq(dh, dp->dccps_gss);
+               if (set_ack)
+                       dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), ackno);
+
+               switch (dcb->dccpd_type) {
+               case DCCP_PKT_REQUEST:
+                       dccp_hdr_request(skb)->dccph_req_service =
+                                                       dcb->dccpd_service;
+                       break;
+               case DCCP_PKT_RESET:
+                       dccp_hdr_reset(skb)->dccph_reset_code =
+                                                       dcb->dccpd_reset_code;
+                       break;
+               }
+
+               dh->dccph_checksum = dccp_v4_checksum(skb, inet->saddr,
+                                                     inet->daddr);
+
+               if (set_ack)
+                       dccp_event_ack_sent(sk);
+
+               DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
+
+               err = ip_queue_xmit(skb, 0);
+               if (err <= 0)
+                       return err;
+
+               /* NET_XMIT_CN is special. It does not guarantee,
+                * that this packet is lost. It tells that device
+                * is about to start to drop packets or already
+                * drops some packets of the same priority and
+                * invokes us to send less aggressively.
+                */
+               return err == NET_XMIT_CN ? 0 : err;
+       }
+       return -ENOBUFS;
+}
+
+unsigned int dccp_sync_mss(struct sock *sk, u32 pmtu)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       int mss_now;
+
+       /*
+        * FIXME: we really should be using the af_specific thing to support
+        *        IPv6.
+        * mss_now = pmtu - tp->af_specific->net_header_len -
+        *           sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext);
+        */
+       mss_now = pmtu - sizeof(struct iphdr) - sizeof(struct dccp_hdr) -
+                 sizeof(struct dccp_hdr_ext);
+
+       /* Now subtract optional transport overhead */
+       mss_now -= dp->dccps_ext_header_len;
+
+       /*
+        * FIXME: this should come from the CCID infrastructure, where, say,
+        * TFRC will say it wants TIMESTAMPS, ELAPSED time, etc, for now lets
+        * put a rough estimate for NDP + TIMESTAMP + TIMESTAMP_ECHO + ELAPSED
+        * TIME + TFRC_OPT_LOSS_EVENT_RATE + TFRC_OPT_RECEIVE_RATE + padding to
+        * make it a multiple of 4
+        */
+
+       mss_now -= ((5 + 6 + 10 + 6 + 6 + 6 + 3) / 4) * 4;
+
+       /* And store cached results */
+       dp->dccps_pmtu_cookie = pmtu;
+       dp->dccps_mss_cache = mss_now;
+
+       return mss_now;
+}
+
+void dccp_write_space(struct sock *sk)
+{
+       read_lock(&sk->sk_callback_lock);
+
+       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+               wake_up_interruptible(sk->sk_sleep);
+       /* Should agree with poll, otherwise some programs break */
+       if (sock_writeable(sk))
+               sk_wake_async(sk, 2, POLL_OUT);
+
+       read_unlock(&sk->sk_callback_lock);
+}
+
+/**
+ * dccp_wait_for_ccid - Wait for ccid to tell us we can send a packet
+ * @sk: socket to wait for
+ * @timeo: for how long
+ */
+static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb,
+                             long *timeo)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       DEFINE_WAIT(wait);
+       long delay;
+       int rc;
+
+       while (1) {
+               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+
+               if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
+                       goto do_error;
+               if (!*timeo)
+                       goto do_nonblock;
+               if (signal_pending(current))
+                       goto do_interrupted;
+
+               rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb,
+                                           skb->len);
+               if (rc <= 0)
+                       break;
+               delay = msecs_to_jiffies(rc);
+               if (delay > *timeo || delay < 0)
+                       goto do_nonblock;
+
+               sk->sk_write_pending++;
+               release_sock(sk);
+               *timeo -= schedule_timeout(delay);
+               lock_sock(sk);
+               sk->sk_write_pending--;
+       }
+out:
+       finish_wait(sk->sk_sleep, &wait);
+       return rc;
+
+do_error:
+       rc = -EPIPE;
+       goto out;
+do_nonblock:
+       rc = -EAGAIN;
+       goto out;
+do_interrupted:
+       rc = sock_intr_errno(*timeo);
+       goto out;
+}
+
+int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo)
+{
+       const struct dccp_sock *dp = dccp_sk(sk);
+       int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb,
+                                        skb->len);
+
+       if (err > 0)
+               err = dccp_wait_for_ccid(sk, skb, timeo);
+
+       if (err == 0) {
+               const struct dccp_ackpkts *ap = dp->dccps_hc_rx_ackpkts;
+               struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
+               const int len = skb->len;
+
+               if (sk->sk_state == DCCP_PARTOPEN) {
+                       /* See 8.1.5.  Handshake Completion */
+                       inet_csk_schedule_ack(sk);
+                       inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
+                                                 inet_csk(sk)->icsk_rto,
+                                                 DCCP_RTO_MAX);
+                       dcb->dccpd_type = DCCP_PKT_DATAACK;
+                       /*
+                        * FIXME: we really should have a
+                        * dccps_ack_pending or use icsk.
+                        */
+               } else if (inet_csk_ack_scheduled(sk) ||
+                          dp->dccps_timestamp_echo != 0 ||
+                          (dp->dccps_options.dccpo_send_ack_vector &&
+                           ap->dccpap_buf_ackno != DCCP_MAX_SEQNO + 1 &&
+                           ap->dccpap_ack_seqno == DCCP_MAX_SEQNO + 1))
+                       dcb->dccpd_type = DCCP_PKT_DATAACK;
+               else
+                       dcb->dccpd_type = DCCP_PKT_DATA;
+
+               err = dccp_transmit_skb(sk, skb);
+               ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len);
+       }
+
+       return err;
+}
+
+int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
+{
+       if (inet_sk_rebuild_header(sk) != 0)
+               return -EHOSTUNREACH; /* Routing failure or similar. */
+
+       return dccp_transmit_skb(sk, (skb_cloned(skb) ?
+                                     pskb_copy(skb, GFP_ATOMIC):
+                                     skb_clone(skb, GFP_ATOMIC)));
+}
+
+struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
+                                  struct request_sock *req)
+{
+       struct dccp_hdr *dh;
+       const int dccp_header_size = sizeof(struct dccp_hdr) +
+                                    sizeof(struct dccp_hdr_ext) +
+                                    sizeof(struct dccp_hdr_response);
+       struct sk_buff *skb = sock_wmalloc(sk, MAX_HEADER + DCCP_MAX_OPT_LEN +
+                                              dccp_header_size, 1,
+                                          GFP_ATOMIC);
+       if (skb == NULL)
+               return NULL;
+
+       /* Reserve space for headers. */
+       skb_reserve(skb, MAX_HEADER + DCCP_MAX_OPT_LEN + dccp_header_size);
+
+       skb->dst = dst_clone(dst);
+       skb->csum = 0;
+
+       DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE;
+       DCCP_SKB_CB(skb)->dccpd_seq  = dccp_rsk(req)->dreq_iss;
+       dccp_insert_options(sk, skb);
+
+       skb->h.raw = skb_push(skb, dccp_header_size);
+
+       dh = dccp_hdr(skb);
+       memset(dh, 0, dccp_header_size);
+
+       dh->dccph_sport = inet_sk(sk)->sport;
+       dh->dccph_dport = inet_rsk(req)->rmt_port;
+       dh->dccph_doff  = (dccp_header_size +
+                          DCCP_SKB_CB(skb)->dccpd_opt_len) / 4;
+       dh->dccph_type  = DCCP_PKT_RESPONSE;
+       dh->dccph_x     = 1;
+       dccp_hdr_set_seq(dh, dccp_rsk(req)->dreq_iss);
+       dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dccp_rsk(req)->dreq_isr);
+
+       dh->dccph_checksum = dccp_v4_checksum(skb, inet_rsk(req)->loc_addr,
+                                             inet_rsk(req)->rmt_addr);
+
+       DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
+       return skb;
+}
+
+struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst,
+                               const enum dccp_reset_codes code)
+                                  
+{
+       struct dccp_hdr *dh;
+       struct dccp_sock *dp = dccp_sk(sk);
+       const int dccp_header_size = sizeof(struct dccp_hdr) +
+                                    sizeof(struct dccp_hdr_ext) +
+                                    sizeof(struct dccp_hdr_reset);
+       struct sk_buff *skb = sock_wmalloc(sk, MAX_HEADER + DCCP_MAX_OPT_LEN +
+                                              dccp_header_size, 1,
+                                          GFP_ATOMIC);
+       if (skb == NULL)
+               return NULL;
+
+       /* Reserve space for headers. */
+       skb_reserve(skb, MAX_HEADER + DCCP_MAX_OPT_LEN + dccp_header_size);
+
+       skb->dst = dst_clone(dst);
+       skb->csum = 0;
+
+       dccp_inc_seqno(&dp->dccps_gss);
+
+       DCCP_SKB_CB(skb)->dccpd_reset_code = code;
+       DCCP_SKB_CB(skb)->dccpd_type       = DCCP_PKT_RESET;
+       DCCP_SKB_CB(skb)->dccpd_seq        = dp->dccps_gss;
+       dccp_insert_options(sk, skb);
+
+       skb->h.raw = skb_push(skb, dccp_header_size);
+
+       dh = dccp_hdr(skb);
+       memset(dh, 0, dccp_header_size);
+
+       dh->dccph_sport = inet_sk(sk)->sport;
+       dh->dccph_dport = inet_sk(sk)->dport;
+       dh->dccph_doff  = (dccp_header_size +
+                          DCCP_SKB_CB(skb)->dccpd_opt_len) / 4;
+       dh->dccph_type  = DCCP_PKT_RESET;
+       dh->dccph_x     = 1;
+       dccp_hdr_set_seq(dh, dp->dccps_gss);
+       dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dp->dccps_gsr);
+
+       dccp_hdr_reset(skb)->dccph_reset_code = code;
+
+       dh->dccph_checksum = dccp_v4_checksum(skb, inet_sk(sk)->saddr,
+                                             inet_sk(sk)->daddr);
+
+       DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
+       return skb;
+}
+
+/*
+ * Do all connect socket setups that can be done AF independent.
+ */
+static inline void dccp_connect_init(struct sock *sk)
+{
+       struct dst_entry *dst = __sk_dst_get(sk);
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       sk->sk_err = 0;
+       sock_reset_flag(sk, SOCK_DONE);
+       
+       dccp_sync_mss(sk, dst_mtu(dst));
+
+       /*
+        * FIXME: set dp->{dccps_swh,dccps_swl}, with
+        * something like dccp_inc_seq
+        */
+
+       icsk->icsk_retransmits = 0;
+}
+
+int dccp_connect(struct sock *sk)
+{
+       struct sk_buff *skb;
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       dccp_connect_init(sk);
+
+       skb = alloc_skb(MAX_DCCP_HEADER + 15, sk->sk_allocation);
+       if (unlikely(skb == NULL))
+               return -ENOBUFS;
+
+       /* Reserve space for headers. */
+       skb_reserve(skb, MAX_DCCP_HEADER);
+
+       DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST;
+       /* FIXME: set service to something meaningful, coming
+        * from userspace*/
+       DCCP_SKB_CB(skb)->dccpd_service = 0;
+       skb->csum = 0;
+       skb_set_owner_w(skb, sk);
+
+       BUG_TRAP(sk->sk_send_head == NULL);
+       sk->sk_send_head = skb;
+       dccp_transmit_skb(sk, skb_clone(skb, GFP_KERNEL));
+       DCCP_INC_STATS(DCCP_MIB_ACTIVEOPENS);
+
+       /* Timer for repeating the REQUEST until an answer. */
+       inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
+                                 icsk->icsk_rto, DCCP_RTO_MAX);
+       return 0;
+}
+
+void dccp_send_ack(struct sock *sk)
+{
+       /* If we have been reset, we may not send again. */
+       if (sk->sk_state != DCCP_CLOSED) {
+               struct sk_buff *skb = alloc_skb(MAX_DCCP_HEADER, GFP_ATOMIC);
+
+               if (skb == NULL) {
+                       inet_csk_schedule_ack(sk);
+                       inet_csk(sk)->icsk_ack.ato = TCP_ATO_MIN;
+                       inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
+                                                 TCP_DELACK_MAX,
+                                                 DCCP_RTO_MAX);
+                       return;
+               }
+
+               /* Reserve space for headers */
+               skb_reserve(skb, MAX_DCCP_HEADER);
+               skb->csum = 0;
+               DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_ACK;
+               skb_set_owner_w(skb, sk);
+               dccp_transmit_skb(sk, skb);
+       }
+}
+
+EXPORT_SYMBOL_GPL(dccp_send_ack);
+
+void dccp_send_delayed_ack(struct sock *sk)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       /*
+        * FIXME: tune this timer. elapsed time fixes the skew, so no problem
+        * with using 2s, and active senders also piggyback the ACK into a
+        * DATAACK packet, so this is really for quiescent senders.
+        */
+       unsigned long timeout = jiffies + 2 * HZ;
+
+       /* Use new timeout only if there wasn't a older one earlier. */
+       if (icsk->icsk_ack.pending & ICSK_ACK_TIMER) {
+               /* If delack timer was blocked or is about to expire,
+                * send ACK now.
+                *
+                * FIXME: check the "about to expire" part
+                */
+               if (icsk->icsk_ack.blocked) {
+                       dccp_send_ack(sk);
+                       return;
+               }
+
+               if (!time_before(timeout, icsk->icsk_ack.timeout))
+                       timeout = icsk->icsk_ack.timeout;
+       }
+       icsk->icsk_ack.pending |= ICSK_ACK_SCHED | ICSK_ACK_TIMER;
+       icsk->icsk_ack.timeout = timeout;
+       sk_reset_timer(sk, &icsk->icsk_delack_timer, timeout);
+}
+
+void dccp_send_sync(struct sock *sk, const u64 seq,
+                   const enum dccp_pkt_type pkt_type)
+{
+       /*
+        * We are not putting this on the write queue, so
+        * dccp_transmit_skb() will set the ownership to this
+        * sock.
+        */
+       struct sk_buff *skb = alloc_skb(MAX_DCCP_HEADER, GFP_ATOMIC);
+
+       if (skb == NULL)
+               /* FIXME: how to make sure the sync is sent? */
+               return;
+
+       /* Reserve space for headers and prepare control bits. */
+       skb_reserve(skb, MAX_DCCP_HEADER);
+       skb->csum = 0;
+       DCCP_SKB_CB(skb)->dccpd_type = pkt_type;
+       DCCP_SKB_CB(skb)->dccpd_seq = seq;
+
+       skb_set_owner_w(skb, sk);
+       dccp_transmit_skb(sk, skb);
+}
+
+/*
+ * Send a DCCP_PKT_CLOSE/CLOSEREQ. The caller locks the socket for us. This
+ * cannot be allowed to fail queueing a DCCP_PKT_CLOSE/CLOSEREQ frame under
+ * any circumstances.
+ */
+void dccp_send_close(struct sock *sk, const int active)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct sk_buff *skb;
+       const unsigned int prio = active ? GFP_KERNEL : GFP_ATOMIC;
+
+       skb = alloc_skb(sk->sk_prot->max_header, prio);
+       if (skb == NULL)
+               return;
+
+       /* Reserve space for headers and prepare control bits. */
+       skb_reserve(skb, sk->sk_prot->max_header);
+       skb->csum = 0;
+       DCCP_SKB_CB(skb)->dccpd_type = dp->dccps_role == DCCP_ROLE_CLIENT ?
+                                       DCCP_PKT_CLOSE : DCCP_PKT_CLOSEREQ;
+
+       skb_set_owner_w(skb, sk);
+       if (active) {
+               BUG_TRAP(sk->sk_send_head == NULL);
+               sk->sk_send_head = skb;
+               dccp_transmit_skb(sk, skb_clone(skb, prio));
+       } else
+               dccp_transmit_skb(sk, skb);
+
+       ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk);
+       ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk);
+}
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
new file mode 100644 (file)
index 0000000..18a0e69
--- /dev/null
@@ -0,0 +1,826 @@
+/*
+ *  net/dccp/proto.c
+ *
+ *  An implementation of the DCCP protocol
+ *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *     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/config.h>
+#include <linux/dccp.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/in.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <net/checksum.h>
+
+#include <net/inet_common.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/sock.h>
+#include <net/xfrm.h>
+
+#include <asm/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/dccp.h>
+
+#include "ccid.h"
+#include "dccp.h"
+
+DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly;
+
+atomic_t dccp_orphan_count = ATOMIC_INIT(0);
+
+static struct net_protocol dccp_protocol = {
+       .handler        = dccp_v4_rcv,
+       .err_handler    = dccp_v4_err,
+};
+
+const char *dccp_packet_name(const int type)
+{
+       static const char *dccp_packet_names[] = {
+               [DCCP_PKT_REQUEST]  = "REQUEST",
+               [DCCP_PKT_RESPONSE] = "RESPONSE",
+               [DCCP_PKT_DATA]     = "DATA",
+               [DCCP_PKT_ACK]      = "ACK",
+               [DCCP_PKT_DATAACK]  = "DATAACK",
+               [DCCP_PKT_CLOSEREQ] = "CLOSEREQ",
+               [DCCP_PKT_CLOSE]    = "CLOSE",
+               [DCCP_PKT_RESET]    = "RESET",
+               [DCCP_PKT_SYNC]     = "SYNC",
+               [DCCP_PKT_SYNCACK]  = "SYNCACK",
+       };
+
+       if (type >= DCCP_NR_PKT_TYPES)
+               return "INVALID";
+       else
+               return dccp_packet_names[type];
+}
+
+EXPORT_SYMBOL_GPL(dccp_packet_name);
+
+const char *dccp_state_name(const int state)
+{
+       static char *dccp_state_names[] = {
+       [DCCP_OPEN]       = "OPEN",
+       [DCCP_REQUESTING] = "REQUESTING",
+       [DCCP_PARTOPEN]   = "PARTOPEN",
+       [DCCP_LISTEN]     = "LISTEN",
+       [DCCP_RESPOND]    = "RESPOND",
+       [DCCP_CLOSING]    = "CLOSING",
+       [DCCP_TIME_WAIT]  = "TIME_WAIT",
+       [DCCP_CLOSED]     = "CLOSED",
+       };
+
+       if (state >= DCCP_MAX_STATES)
+               return "INVALID STATE!";
+       else
+               return dccp_state_names[state];
+}
+
+EXPORT_SYMBOL_GPL(dccp_state_name);
+
+static inline int dccp_listen_start(struct sock *sk)
+{
+       dccp_sk(sk)->dccps_role = DCCP_ROLE_LISTEN;
+       return inet_csk_listen_start(sk, TCP_SYNQ_HSIZE);
+}
+
+int dccp_disconnect(struct sock *sk, int flags)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       struct inet_sock *inet = inet_sk(sk);
+       int err = 0;
+       const int old_state = sk->sk_state;
+
+       if (old_state != DCCP_CLOSED)
+               dccp_set_state(sk, DCCP_CLOSED);
+
+       /* ABORT function of RFC793 */
+       if (old_state == DCCP_LISTEN) {
+               inet_csk_listen_stop(sk);
+       /* FIXME: do the active reset thing */
+       } else if (old_state == DCCP_REQUESTING)
+               sk->sk_err = ECONNRESET;
+
+       dccp_clear_xmit_timers(sk);
+       __skb_queue_purge(&sk->sk_receive_queue);
+       if (sk->sk_send_head != NULL) {
+               __kfree_skb(sk->sk_send_head);
+               sk->sk_send_head = NULL;
+       }
+
+       inet->dport = 0;
+
+       if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
+               inet_reset_saddr(sk);
+
+       sk->sk_shutdown = 0;
+       sock_reset_flag(sk, SOCK_DONE);
+
+       icsk->icsk_backoff = 0;
+       inet_csk_delack_init(sk);
+       __sk_dst_reset(sk);
+
+       BUG_TRAP(!inet->num || icsk->icsk_bind_hash);
+
+       sk->sk_error_report(sk);
+       return err;
+}
+
+/*
+ *     Wait for a DCCP event.
+ *
+ *     Note that we don't need to lock the socket, as the upper poll layers
+ *     take care of normal races (between the test and the event) and we don't
+ *     go look at any of the socket buffers directly.
+ */
+static unsigned int dccp_poll(struct file *file, struct socket *sock,
+                             poll_table *wait)
+{
+       unsigned int mask;
+       struct sock *sk = sock->sk;
+
+       poll_wait(file, sk->sk_sleep, wait);
+       if (sk->sk_state == DCCP_LISTEN)
+               return inet_csk_listen_poll(sk);
+
+       /* Socket is not locked. We are protected from async events
+          by poll logic and correct handling of state changes
+          made by another threads is impossible in any case.
+        */
+
+       mask = 0;
+       if (sk->sk_err)
+               mask = POLLERR;
+
+       if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == DCCP_CLOSED)
+               mask |= POLLHUP;
+       if (sk->sk_shutdown & RCV_SHUTDOWN)
+               mask |= POLLIN | POLLRDNORM;
+
+       /* Connected? */
+       if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_RESPOND)) {
+               if (atomic_read(&sk->sk_rmem_alloc) > 0)
+                       mask |= POLLIN | POLLRDNORM;
+
+               if (!(sk->sk_shutdown & SEND_SHUTDOWN)) {
+                       if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) {
+                               mask |= POLLOUT | POLLWRNORM;
+                       } else {  /* send SIGIO later */
+                               set_bit(SOCK_ASYNC_NOSPACE,
+                                       &sk->sk_socket->flags);
+                               set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
+
+                               /* Race breaker. If space is freed after
+                                * wspace test but before the flags are set,
+                                * IO signal will be lost.
+                                */
+                               if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk))
+                                       mask |= POLLOUT | POLLWRNORM;
+                       }
+               }
+       }
+       return mask;
+}
+
+int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg)
+{
+       dccp_pr_debug("entry\n");
+       return -ENOIOCTLCMD;
+}
+
+int dccp_setsockopt(struct sock *sk, int level, int optname,
+                   char __user *optval, int optlen)
+{
+       struct dccp_sock *dp;
+       int err;
+       int val;
+
+       if (level != SOL_DCCP)
+               return ip_setsockopt(sk, level, optname, optval, optlen);
+
+       if (optlen < sizeof(int))
+               return -EINVAL;
+
+       if (get_user(val, (int __user *)optval))
+               return -EFAULT;
+
+       lock_sock(sk);
+
+       dp = dccp_sk(sk);
+       err = 0;
+
+       switch (optname) {
+       case DCCP_SOCKOPT_PACKET_SIZE:
+               dp->dccps_packet_size = val;
+               break;
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+       
+       release_sock(sk);
+       return err;
+}
+
+int dccp_getsockopt(struct sock *sk, int level, int optname,
+                   char __user *optval, int __user *optlen)
+{
+       struct dccp_sock *dp;
+       int val, len;
+
+       if (level != SOL_DCCP)
+               return ip_getsockopt(sk, level, optname, optval, optlen);
+
+       if (get_user(len, optlen))
+               return -EFAULT;
+
+       len = min_t(unsigned int, len, sizeof(int));
+       if (len < 0)
+               return -EINVAL;
+
+       dp = dccp_sk(sk);
+
+       switch (optname) {
+       case DCCP_SOCKOPT_PACKET_SIZE:
+               val = dp->dccps_packet_size;
+               break;
+       default:
+               return -ENOPROTOOPT;
+       }
+
+       if (put_user(len, optlen) || copy_to_user(optval, &val, len))
+               return -EFAULT;
+
+       return 0;
+}
+
+int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+                size_t len)
+{
+       const struct dccp_sock *dp = dccp_sk(sk);
+       const int flags = msg->msg_flags;
+       const int noblock = flags & MSG_DONTWAIT;
+       struct sk_buff *skb;
+       int rc, size;
+       long timeo;
+
+       if (len > dp->dccps_mss_cache)
+               return -EMSGSIZE;
+
+       lock_sock(sk);
+       timeo = sock_sndtimeo(sk, noblock);
+
+       /*
+        * We have to use sk_stream_wait_connect here to set sk_write_pending,
+        * so that the trick in dccp_rcv_request_sent_state_process.
+        */
+       /* Wait for a connection to finish. */
+       if ((1 << sk->sk_state) & ~(DCCPF_OPEN | DCCPF_PARTOPEN | DCCPF_CLOSING))
+               if ((rc = sk_stream_wait_connect(sk, &timeo)) != 0)
+                       goto out_release;
+
+       size = sk->sk_prot->max_header + len;
+       release_sock(sk);
+       skb = sock_alloc_send_skb(sk, size, noblock, &rc);
+       lock_sock(sk);
+       if (skb == NULL)
+               goto out_release;
+
+       skb_reserve(skb, sk->sk_prot->max_header);
+       rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
+       if (rc != 0)
+               goto out_discard;
+
+       rc = dccp_write_xmit(sk, skb, &timeo);
+       /*
+        * XXX we don't use sk_write_queue, so just discard the packet.
+        *     Current plan however is to _use_ sk_write_queue with
+        *     an algorith similar to tcp_sendmsg, where the main difference
+        *     is that in DCCP we have to respect packet boundaries, so
+        *     no coalescing of skbs.
+        *
+        *     This bug was _quickly_ found & fixed by just looking at an OSTRA
+        *     generated callgraph 8) -acme
+        */
+       if (rc != 0)
+               goto out_discard;
+out_release:
+       release_sock(sk);
+       return rc ? : len;
+out_discard:
+       kfree_skb(skb);
+       goto out_release;
+}
+
+int dccp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+                size_t len, int nonblock, int flags, int *addr_len)
+{
+       const struct dccp_hdr *dh;
+       long timeo;
+
+       lock_sock(sk);
+
+       if (sk->sk_state == DCCP_LISTEN) {
+               len = -ENOTCONN;
+               goto out;
+       }
+
+       timeo = sock_rcvtimeo(sk, nonblock);
+
+       do {
+               struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
+
+               if (skb == NULL)
+                       goto verify_sock_status;
+
+               dh = dccp_hdr(skb);
+
+               if (dh->dccph_type == DCCP_PKT_DATA ||
+                   dh->dccph_type == DCCP_PKT_DATAACK)
+                       goto found_ok_skb;
+
+               if (dh->dccph_type == DCCP_PKT_RESET ||
+                   dh->dccph_type == DCCP_PKT_CLOSE) {
+                       dccp_pr_debug("found fin ok!\n");
+                       len = 0;
+                       goto found_fin_ok;
+               }
+               dccp_pr_debug("packet_type=%s\n",
+                             dccp_packet_name(dh->dccph_type));
+               sk_eat_skb(sk, skb);
+verify_sock_status:
+               if (sock_flag(sk, SOCK_DONE)) {
+                       len = 0;
+                       break;
+               }
+
+               if (sk->sk_err) {
+                       len = sock_error(sk);
+                       break;
+               }
+
+               if (sk->sk_shutdown & RCV_SHUTDOWN) {
+                       len = 0;
+                       break;
+               }
+
+               if (sk->sk_state == DCCP_CLOSED) {
+                       if (!sock_flag(sk, SOCK_DONE)) {
+                               /* This occurs when user tries to read
+                                * from never connected socket.
+                                */
+                               len = -ENOTCONN;
+                               break;
+                       }
+                       len = 0;
+                       break;
+               }
+
+               if (!timeo) {
+                       len = -EAGAIN;
+                       break;
+               }
+
+               if (signal_pending(current)) {
+                       len = sock_intr_errno(timeo);
+                       break;
+               }
+
+               sk_wait_data(sk, &timeo);
+               continue;
+       found_ok_skb:
+               if (len > skb->len)
+                       len = skb->len;
+               else if (len < skb->len)
+                       msg->msg_flags |= MSG_TRUNC;
+
+               if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len)) {
+                       /* Exception. Bailout! */
+                       len = -EFAULT;
+                       break;
+               }
+       found_fin_ok:
+               if (!(flags & MSG_PEEK))
+                       sk_eat_skb(sk, skb);
+               break;
+       } while (1);
+out:
+       release_sock(sk);
+       return len;
+}
+
+static int inet_dccp_listen(struct socket *sock, int backlog)
+{
+       struct sock *sk = sock->sk;
+       unsigned char old_state;
+       int err;
+
+       lock_sock(sk);
+
+       err = -EINVAL;
+       if (sock->state != SS_UNCONNECTED || sock->type != SOCK_DCCP)
+               goto out;
+
+       old_state = sk->sk_state;
+       if (!((1 << old_state) & (DCCPF_CLOSED | DCCPF_LISTEN)))
+               goto out;
+
+       /* Really, if the socket is already in listen state
+        * we can only allow the backlog to be adjusted.
+        */
+       if (old_state != DCCP_LISTEN) {
+               /*
+                * FIXME: here it probably should be sk->sk_prot->listen_start
+                * see tcp_listen_start
+                */
+               err = dccp_listen_start(sk);
+               if (err)
+                       goto out;
+       }
+       sk->sk_max_ack_backlog = backlog;
+       err = 0;
+
+out:
+       release_sock(sk);
+       return err;
+}
+
+static const unsigned char dccp_new_state[] = {
+       /* current state:   new state:      action:     */
+       [0]               = DCCP_CLOSED,
+       [DCCP_OPEN]       = DCCP_CLOSING | DCCP_ACTION_FIN,
+       [DCCP_REQUESTING] = DCCP_CLOSED,
+       [DCCP_PARTOPEN]   = DCCP_CLOSING | DCCP_ACTION_FIN,
+       [DCCP_LISTEN]     = DCCP_CLOSED,
+       [DCCP_RESPOND]    = DCCP_CLOSED,
+       [DCCP_CLOSING]    = DCCP_CLOSED,
+       [DCCP_TIME_WAIT]  = DCCP_CLOSED,
+       [DCCP_CLOSED]     = DCCP_CLOSED,
+};
+
+static int dccp_close_state(struct sock *sk)
+{
+       const int next = dccp_new_state[sk->sk_state];
+       const int ns = next & DCCP_STATE_MASK;
+
+       if (ns != sk->sk_state)
+               dccp_set_state(sk, ns);
+
+       return next & DCCP_ACTION_FIN;
+}
+
+void dccp_close(struct sock *sk, long timeout)
+{
+       struct sk_buff *skb;
+
+       lock_sock(sk);
+
+       sk->sk_shutdown = SHUTDOWN_MASK;
+
+       if (sk->sk_state == DCCP_LISTEN) {
+               dccp_set_state(sk, DCCP_CLOSED);
+
+               /* Special case. */
+               inet_csk_listen_stop(sk);
+
+               goto adjudge_to_death;
+       }
+
+       /*
+        * We need to flush the recv. buffs.  We do this only on the
+        * descriptor close, not protocol-sourced closes, because the
+         *reader process may not have drained the data yet!
+        */
+       /* FIXME: check for unread data */
+       while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) {
+               __kfree_skb(skb);
+       }
+
+       if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) {
+               /* Check zero linger _after_ checking for unread data. */
+               sk->sk_prot->disconnect(sk, 0);
+       } else if (dccp_close_state(sk)) {
+               dccp_send_close(sk, 1);
+       }
+
+       sk_stream_wait_close(sk, timeout);
+
+adjudge_to_death:
+       /*
+        * It is the last release_sock in its life. It will remove backlog.
+        */
+       release_sock(sk);
+       /*
+        * Now socket is owned by kernel and we acquire BH lock
+        * to finish close. No need to check for user refs.
+        */
+       local_bh_disable();
+       bh_lock_sock(sk);
+       BUG_TRAP(!sock_owned_by_user(sk));
+
+       sock_hold(sk);
+       sock_orphan(sk);
+
+       /*
+        * The last release_sock may have processed the CLOSE or RESET
+        * packet moving sock to CLOSED state, if not we have to fire
+        * the CLOSE/CLOSEREQ retransmission timer, see "8.3. Termination"
+        * in draft-ietf-dccp-spec-11. -acme
+        */
+       if (sk->sk_state == DCCP_CLOSING) {
+               /* FIXME: should start at 2 * RTT */
+               /* Timer for repeating the CLOSE/CLOSEREQ until an answer. */
+               inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
+                                         inet_csk(sk)->icsk_rto,
+                                         DCCP_RTO_MAX);
+#if 0
+               /* Yeah, we should use sk->sk_prot->orphan_count, etc */
+               dccp_set_state(sk, DCCP_CLOSED);
+#endif
+       }
+
+       atomic_inc(sk->sk_prot->orphan_count);
+       if (sk->sk_state == DCCP_CLOSED)
+               inet_csk_destroy_sock(sk);
+
+       /* Otherwise, socket is reprieved until protocol close. */
+
+       bh_unlock_sock(sk);
+       local_bh_enable();
+       sock_put(sk);
+}
+
+void dccp_shutdown(struct sock *sk, int how)
+{
+       dccp_pr_debug("entry\n");
+}
+
+static struct proto_ops inet_dccp_ops = {
+       .family         = PF_INET,
+       .owner          = THIS_MODULE,
+       .release        = inet_release,
+       .bind           = inet_bind,
+       .connect        = inet_stream_connect,
+       .socketpair     = sock_no_socketpair,
+       .accept         = inet_accept,
+       .getname        = inet_getname,
+       /* FIXME: work on tcp_poll to rename it to inet_csk_poll */
+       .poll           = dccp_poll,
+       .ioctl          = inet_ioctl,
+       /* FIXME: work on inet_listen to rename it to sock_common_listen */
+       .listen         = inet_dccp_listen,
+       .shutdown       = inet_shutdown,
+       .setsockopt     = sock_common_setsockopt,
+       .getsockopt     = sock_common_getsockopt,
+       .sendmsg        = inet_sendmsg,
+       .recvmsg        = sock_common_recvmsg,
+       .mmap           = sock_no_mmap,
+       .sendpage       = sock_no_sendpage,
+};
+
+extern struct net_proto_family inet_family_ops;
+
+static struct inet_protosw dccp_v4_protosw = {
+       .type           = SOCK_DCCP,
+       .protocol       = IPPROTO_DCCP,
+       .prot           = &dccp_v4_prot,
+       .ops            = &inet_dccp_ops,
+       .capability     = -1,
+       .no_check       = 0,
+       .flags          = 0,
+};
+
+/*
+ * This is the global socket data structure used for responding to
+ * the Out-of-the-blue (OOTB) packets. A control sock will be created
+ * for this socket at the initialization time.
+ */
+struct socket *dccp_ctl_socket;
+
+static char dccp_ctl_socket_err_msg[] __initdata =
+       KERN_ERR "DCCP: Failed to create the control socket.\n";
+
+static int __init dccp_ctl_sock_init(void)
+{
+       int rc = sock_create_kern(PF_INET, SOCK_DCCP, IPPROTO_DCCP,
+                                 &dccp_ctl_socket);
+       if (rc < 0)
+               printk(dccp_ctl_socket_err_msg);
+       else {
+               dccp_ctl_socket->sk->sk_allocation = GFP_ATOMIC;
+               inet_sk(dccp_ctl_socket->sk)->uc_ttl = -1;
+
+               /* Unhash it so that IP input processing does not even
+                * see it, we do not wish this socket to see incoming
+                * packets.
+                */
+               dccp_ctl_socket->sk->sk_prot->unhash(dccp_ctl_socket->sk);
+       }
+
+       return rc;
+}
+
+#ifdef CONFIG_IP_DCCP_UNLOAD_HACK
+void dccp_ctl_sock_exit(void)
+{
+       if (dccp_ctl_socket != NULL) {
+               sock_release(dccp_ctl_socket);
+               dccp_ctl_socket = NULL;
+       }
+}
+
+EXPORT_SYMBOL_GPL(dccp_ctl_sock_exit);
+#endif
+
+static int __init init_dccp_v4_mibs(void)
+{
+       int rc = -ENOMEM;
+
+       dccp_statistics[0] = alloc_percpu(struct dccp_mib);
+       if (dccp_statistics[0] == NULL)
+               goto out;
+
+       dccp_statistics[1] = alloc_percpu(struct dccp_mib);
+       if (dccp_statistics[1] == NULL)
+               goto out_free_one;
+
+       rc = 0;
+out:
+       return rc;
+out_free_one:
+       free_percpu(dccp_statistics[0]);
+       dccp_statistics[0] = NULL;
+       goto out;
+
+}
+
+static int thash_entries;
+module_param(thash_entries, int, 0444);
+MODULE_PARM_DESC(thash_entries, "Number of ehash buckets");
+
+#ifdef CONFIG_IP_DCCP_DEBUG
+int dccp_debug;
+module_param(dccp_debug, int, 0444);
+MODULE_PARM_DESC(dccp_debug, "Enable debug messages");
+#endif
+
+static int __init dccp_init(void)
+{
+       unsigned long goal;
+       int ehash_order, bhash_order, i;
+       int rc = proto_register(&dccp_v4_prot, 1);
+
+       if (rc)
+               goto out;
+
+       dccp_hashinfo.bind_bucket_cachep =
+               kmem_cache_create("dccp_bind_bucket",
+                                 sizeof(struct inet_bind_bucket), 0,
+                                 SLAB_HWCACHE_ALIGN, NULL, NULL);
+       if (!dccp_hashinfo.bind_bucket_cachep)
+               goto out_proto_unregister;
+
+       /*
+        * Size and allocate the main established and bind bucket
+        * hash tables.
+        *
+        * The methodology is similar to that of the buffer cache.
+        */
+       if (num_physpages >= (128 * 1024))
+               goal = num_physpages >> (21 - PAGE_SHIFT);
+       else
+               goal = num_physpages >> (23 - PAGE_SHIFT);
+
+       if (thash_entries)
+               goal = (thash_entries *
+                       sizeof(struct inet_ehash_bucket)) >> PAGE_SHIFT;
+       for (ehash_order = 0; (1UL << ehash_order) < goal; ehash_order++)
+               ;
+       do {
+               dccp_hashinfo.ehash_size = (1UL << ehash_order) * PAGE_SIZE /
+                                       sizeof(struct inet_ehash_bucket);
+               dccp_hashinfo.ehash_size >>= 1;
+               while (dccp_hashinfo.ehash_size &
+                      (dccp_hashinfo.ehash_size - 1))
+                       dccp_hashinfo.ehash_size--;
+               dccp_hashinfo.ehash = (struct inet_ehash_bucket *)
+                       __get_free_pages(GFP_ATOMIC, ehash_order);
+       } while (!dccp_hashinfo.ehash && --ehash_order > 0);
+
+       if (!dccp_hashinfo.ehash) {
+               printk(KERN_CRIT "Failed to allocate DCCP "
+                                "established hash table\n");
+               goto out_free_bind_bucket_cachep;
+       }
+
+       for (i = 0; i < (dccp_hashinfo.ehash_size << 1); i++) {
+               rwlock_init(&dccp_hashinfo.ehash[i].lock);
+               INIT_HLIST_HEAD(&dccp_hashinfo.ehash[i].chain);
+       }
+
+       bhash_order = ehash_order;
+
+       do {
+               dccp_hashinfo.bhash_size = (1UL << bhash_order) * PAGE_SIZE /
+                                       sizeof(struct inet_bind_hashbucket);
+               if ((dccp_hashinfo.bhash_size > (64 * 1024)) &&
+                   bhash_order > 0)
+                       continue;
+               dccp_hashinfo.bhash = (struct inet_bind_hashbucket *)
+                       __get_free_pages(GFP_ATOMIC, bhash_order);
+       } while (!dccp_hashinfo.bhash && --bhash_order >= 0);
+
+       if (!dccp_hashinfo.bhash) {
+               printk(KERN_CRIT "Failed to allocate DCCP bind hash table\n");
+               goto out_free_dccp_ehash;
+       }
+
+       for (i = 0; i < dccp_hashinfo.bhash_size; i++) {
+               spin_lock_init(&dccp_hashinfo.bhash[i].lock);
+               INIT_HLIST_HEAD(&dccp_hashinfo.bhash[i].chain);
+       }
+
+       if (init_dccp_v4_mibs())
+               goto out_free_dccp_bhash;
+
+       rc = -EAGAIN;
+       if (inet_add_protocol(&dccp_protocol, IPPROTO_DCCP))
+               goto out_free_dccp_v4_mibs;
+
+       inet_register_protosw(&dccp_v4_protosw);
+
+       rc = dccp_ctl_sock_init();
+       if (rc)
+               goto out_unregister_protosw;
+out:
+       return rc;
+out_unregister_protosw:
+       inet_unregister_protosw(&dccp_v4_protosw);
+       inet_del_protocol(&dccp_protocol, IPPROTO_DCCP);
+out_free_dccp_v4_mibs:
+       free_percpu(dccp_statistics[0]);
+       free_percpu(dccp_statistics[1]);
+       dccp_statistics[0] = dccp_statistics[1] = NULL;
+out_free_dccp_bhash:
+       free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order);
+       dccp_hashinfo.bhash = NULL;
+out_free_dccp_ehash:
+       free_pages((unsigned long)dccp_hashinfo.ehash, ehash_order);
+       dccp_hashinfo.ehash = NULL;
+out_free_bind_bucket_cachep:
+       kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
+       dccp_hashinfo.bind_bucket_cachep = NULL;
+out_proto_unregister:
+       proto_unregister(&dccp_v4_prot);
+       goto out;
+}
+
+static const char dccp_del_proto_err_msg[] __exitdata =
+       KERN_ERR "can't remove dccp net_protocol\n";
+
+static void __exit dccp_fini(void)
+{
+       inet_unregister_protosw(&dccp_v4_protosw);
+
+       if (inet_del_protocol(&dccp_protocol, IPPROTO_DCCP) < 0)
+               printk(dccp_del_proto_err_msg);
+
+       free_percpu(dccp_statistics[0]);
+       free_percpu(dccp_statistics[1]);
+       free_pages((unsigned long)dccp_hashinfo.bhash,
+                  get_order(dccp_hashinfo.bhash_size *
+                            sizeof(struct inet_bind_hashbucket)));
+       free_pages((unsigned long)dccp_hashinfo.ehash,
+                  get_order(dccp_hashinfo.ehash_size *
+                            sizeof(struct inet_ehash_bucket)));
+       kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
+       proto_unregister(&dccp_v4_prot);
+}
+
+module_init(dccp_init);
+module_exit(dccp_fini);
+
+/*
+ * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
+ * values directly, Also cover the case where the protocol is not specified,
+ * i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP
+ */
+MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-33-type-6");
+MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-0-type-6");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@conectiva.com.br>");
+MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol");
diff --git a/net/dccp/timer.c b/net/dccp/timer.c
new file mode 100644 (file)
index 0000000..aa34b57
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ *  net/dccp/timer.c
+ * 
+ *  An implementation of the DCCP protocol
+ *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *     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/dccp.h>
+#include <linux/skbuff.h>
+
+#include "dccp.h"
+
+static void dccp_write_timer(unsigned long data);
+static void dccp_keepalive_timer(unsigned long data);
+static void dccp_delack_timer(unsigned long data);
+
+void dccp_init_xmit_timers(struct sock *sk)
+{
+       inet_csk_init_xmit_timers(sk, &dccp_write_timer, &dccp_delack_timer,
+                                 &dccp_keepalive_timer);
+}
+
+static void dccp_write_err(struct sock *sk)
+{
+       sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT;
+       sk->sk_error_report(sk);
+
+       dccp_v4_send_reset(sk, DCCP_RESET_CODE_ABORTED);
+       dccp_done(sk);
+       DCCP_INC_STATS_BH(DCCP_MIB_ABORTONTIMEOUT);
+}
+
+/* A write timeout has occurred. Process the after effects. */
+static int dccp_write_timeout(struct sock *sk)
+{
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+       int retry_until;
+
+       if (sk->sk_state == DCCP_REQUESTING || sk->sk_state == DCCP_PARTOPEN) {
+               if (icsk->icsk_retransmits != 0)
+                       dst_negative_advice(&sk->sk_dst_cache);
+               retry_until = icsk->icsk_syn_retries ? :
+                           /* FIXME! */ 3 /* FIXME! sysctl_tcp_syn_retries */;
+       } else {
+               if (icsk->icsk_retransmits >=
+                    /* FIXME! sysctl_tcp_retries1 */ 5 /* FIXME! */) {
+                       /* NOTE. draft-ietf-tcpimpl-pmtud-01.txt requires pmtu
+                          black hole detection. :-(
+
+                          It is place to make it. It is not made. I do not want
+                          to make it. It is disguisting. It does not work in any
+                          case. Let me to cite the same draft, which requires for
+                          us to implement this:
+
+   "The one security concern raised by this memo is that ICMP black holes
+   are often caused by over-zealous security administrators who block
+   all ICMP messages.  It is vitally important that those who design and
+   deploy security systems understand the impact of strict filtering on
+   upper-layer protocols.  The safest web site in the world is worthless
+   if most TCP implementations cannot transfer data from it.  It would
+   be far nicer to have all of the black holes fixed rather than fixing
+   all of the TCP implementations."
+
+                           Golden words :-).
+                  */
+
+                       dst_negative_advice(&sk->sk_dst_cache);
+               }
+
+               retry_until = /* FIXME! */ 15 /* FIXME! sysctl_tcp_retries2 */;
+               /*
+                * FIXME: see tcp_write_timout and tcp_out_of_resources
+                */
+       }
+
+       if (icsk->icsk_retransmits >= retry_until) {
+               /* Has it gone just too far? */
+               dccp_write_err(sk);
+               return 1;
+       }
+       return 0;
+}
+
+/* This is the same as tcp_delack_timer, sans prequeue & mem_reclaim stuff */
+static void dccp_delack_timer(unsigned long data)
+{
+       struct sock *sk = (struct sock *)data;
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       bh_lock_sock(sk);
+       if (sock_owned_by_user(sk)) {
+               /* Try again later. */
+               icsk->icsk_ack.blocked = 1;
+               NET_INC_STATS_BH(LINUX_MIB_DELAYEDACKLOCKED);
+               sk_reset_timer(sk, &icsk->icsk_delack_timer,
+                              jiffies + TCP_DELACK_MIN);
+               goto out;
+       }
+
+       if (sk->sk_state == DCCP_CLOSED ||
+           !(icsk->icsk_ack.pending & ICSK_ACK_TIMER))
+               goto out;
+       if (time_after(icsk->icsk_ack.timeout, jiffies)) {
+               sk_reset_timer(sk, &icsk->icsk_delack_timer,
+                              icsk->icsk_ack.timeout);
+               goto out;
+       }
+
+       icsk->icsk_ack.pending &= ~ICSK_ACK_TIMER;
+
+       if (inet_csk_ack_scheduled(sk)) {
+               if (!icsk->icsk_ack.pingpong) {
+                       /* Delayed ACK missed: inflate ATO. */
+                       icsk->icsk_ack.ato = min(icsk->icsk_ack.ato << 1,
+                                                icsk->icsk_rto);
+               } else {
+                       /* Delayed ACK missed: leave pingpong mode and
+                        * deflate ATO.
+                        */
+                       icsk->icsk_ack.pingpong = 0;
+                       icsk->icsk_ack.ato = TCP_ATO_MIN;
+               }
+               dccp_send_ack(sk);
+               NET_INC_STATS_BH(LINUX_MIB_DELAYEDACKS);
+       }
+out:
+       bh_unlock_sock(sk);
+       sock_put(sk);
+}
+
+/*
+ *     The DCCP retransmit timer.
+ */
+static void dccp_retransmit_timer(struct sock *sk)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       /*
+        * sk->sk_send_head has to have one skb with
+        * DCCP_SKB_CB(skb)->dccpd_type set to one of the retransmittable DCCP
+        * packet types (REQUEST, RESPONSE, the ACK in the 3way handshake
+        * (PARTOPEN timer), etc).
+        */
+       BUG_TRAP(sk->sk_send_head != NULL);
+
+       /* 
+        * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was
+        * sent, no need to retransmit, this sock is dead.
+        */
+       if (dccp_write_timeout(sk))
+               goto out;
+
+       /*
+        * We want to know the number of packets retransmitted, not the
+        * total number of retransmissions of clones of original packets.
+        */
+       if (icsk->icsk_retransmits == 0)
+               DCCP_INC_STATS_BH(DCCP_MIB_TIMEOUTS);
+
+       if (dccp_retransmit_skb(sk, sk->sk_send_head) < 0) {
+               /*
+                * Retransmission failed because of local congestion,
+                * do not backoff.
+                */
+               if (icsk->icsk_retransmits == 0)
+                       icsk->icsk_retransmits = 1;
+               inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
+                                         min(icsk->icsk_rto,
+                                             TCP_RESOURCE_PROBE_INTERVAL),
+                                         DCCP_RTO_MAX);
+               goto out;
+       }
+
+       icsk->icsk_backoff++;
+       icsk->icsk_retransmits++;
+
+       icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX);
+       inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto,
+                                 DCCP_RTO_MAX);
+       if (icsk->icsk_retransmits > 3 /* FIXME: sysctl_dccp_retries1 */)
+               __sk_dst_reset(sk);
+out:;
+}
+
+static void dccp_write_timer(unsigned long data)
+{
+       struct sock *sk = (struct sock *)data;
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       int event = 0;
+
+       bh_lock_sock(sk);
+       if (sock_owned_by_user(sk)) {
+               /* Try again later */
+               sk_reset_timer(sk, &icsk->icsk_retransmit_timer,
+                              jiffies + (HZ / 20));
+               goto out;
+       }
+
+       if (sk->sk_state == DCCP_CLOSED || !icsk->icsk_pending)
+               goto out;
+
+       if (time_after(icsk->icsk_timeout, jiffies)) {
+               sk_reset_timer(sk, &icsk->icsk_retransmit_timer,
+                              icsk->icsk_timeout);
+               goto out;
+       }
+
+       event = icsk->icsk_pending;
+       icsk->icsk_pending = 0;
+
+       switch (event) {
+       case ICSK_TIME_RETRANS:
+               dccp_retransmit_timer(sk);
+               break;
+       }
+out:
+       bh_unlock_sock(sk);
+       sock_put(sk);
+}
+
+/*
+ *     Timer for listening sockets
+ */
+static void dccp_response_timer(struct sock *sk)
+{
+       inet_csk_reqsk_queue_prune(sk, TCP_SYNQ_INTERVAL, DCCP_TIMEOUT_INIT,
+                                  DCCP_RTO_MAX);
+}
+
+static void dccp_keepalive_timer(unsigned long data)
+{
+       struct sock *sk = (struct sock *)data;
+
+       /* Only process if socket is not in use. */
+       bh_lock_sock(sk);
+       if (sock_owned_by_user(sk)) {
+               /* Try again later. */ 
+               inet_csk_reset_keepalive_timer(sk, HZ / 20);
+               goto out;
+       }
+
+       if (sk->sk_state == DCCP_LISTEN) {
+               dccp_response_timer(sk);
+               goto out;
+       }
+out:
+       bh_unlock_sock(sk);
+       sock_put(sk);
+}
index acdd18e6adb2172903a2e6519e331c5489646330..348f36b529f741e2f82005f69e86a1d353a63761 100644 (file)
@@ -118,7 +118,7 @@ Version 0.0.6    2.1.110   07-aug-98   Eduardo Marcelo Serrat
 #include <linux/netfilter.h>
 #include <linux/seq_file.h>
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <net/flow.h>
 #include <asm/system.h>
 #include <asm/ioctls.h>
@@ -1763,7 +1763,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
                nskb = skb->next;
 
                if (skb->len == 0) {
-                       skb_unlink(skb);
+                       skb_unlink(skb, queue);
                        kfree_skb(skb);
                        /* 
                         * N.B. Don't refer to skb or cb after this point
@@ -1876,8 +1876,27 @@ static inline unsigned int dn_current_mss(struct sock *sk, int flags)
        return mss_now;
 }
 
+/* 
+ * N.B. We get the timeout wrong here, but then we always did get it
+ * wrong before and this is another step along the road to correcting
+ * it. It ought to get updated each time we pass through the routine,
+ * but in practise it probably doesn't matter too much for now.
+ */
+static inline struct sk_buff *dn_alloc_send_pskb(struct sock *sk,
+                             unsigned long datalen, int noblock,
+                             int *errcode)
+{
+       struct sk_buff *skb = sock_alloc_send_skb(sk, datalen,
+                                                  noblock, errcode);
+       if (skb) {
+               skb->protocol = __constant_htons(ETH_P_DNA_RT);
+               skb->pkt_type = PACKET_OUTGOING;
+       }
+       return skb;
+}
+
 static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
-          struct msghdr *msg, size_t size)
+                     struct msghdr *msg, size_t size)
 {
        struct sock *sk = sock->sk;
        struct dn_scp *scp = DN_SK(sk);
@@ -1892,7 +1911,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
        struct dn_skb_cb *cb;
        size_t len;
        unsigned char fctype;
-       long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
+       long timeo;
 
        if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|MSG_MORE|MSG_CMSG_COMPAT))
                return -EOPNOTSUPP;
@@ -1900,18 +1919,21 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
        if (addr_len && (addr_len != sizeof(struct sockaddr_dn)))
                return -EINVAL;
 
+       lock_sock(sk);
+       timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
        /*
         * The only difference between stream sockets and sequenced packet
         * sockets is that the stream sockets always behave as if MSG_EOR
         * has been set.
         */
        if (sock->type == SOCK_STREAM) {
-               if (flags & MSG_EOR)
-                       return -EINVAL;
+               if (flags & MSG_EOR) {
+                       err = -EINVAL;
+                       goto out;
+               }
                flags |= MSG_EOR;
        }
 
-       lock_sock(sk);
 
        err = dn_check_state(sk, addr, addr_len, &timeo, flags);
        if (err)
@@ -1980,8 +2002,12 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
 
                /*
                 * Get a suitably sized skb.
+                * 64 is a bit of a hack really, but its larger than any
+                * link-layer headers and has served us well as a good
+                * guess as to their real length.
                 */
-               skb = dn_alloc_send_skb(sk, &len, flags & MSG_DONTWAIT, timeo, &err);
+               skb = dn_alloc_send_pskb(sk, len + 64 + DN_MAX_NSP_DATA_HEADER,
+                                        flags & MSG_DONTWAIT, &err);
 
                if (err)
                        break;
@@ -1991,7 +2017,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
 
                cb = DN_SKB_CB(skb);
 
-               skb_reserve(skb, DN_MAX_NSP_DATA_HEADER);
+               skb_reserve(skb, 64 + DN_MAX_NSP_DATA_HEADER);
 
                if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
                        err = -EFAULT;
@@ -2064,7 +2090,7 @@ static struct notifier_block dn_dev_notifier = {
        .notifier_call = dn_device_event,
 };
 
-extern int dn_route_rcv(struct sk_buff *, struct net_device *, struct packet_type *);
+extern int dn_route_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
 
 static struct packet_type dn_dix_packet_type = {
        .type =         __constant_htons(ETH_P_DNA_RT),
index 00233ecbc9cba98022396af66bafaf1b09fb21b4..5610bb16dbf941db2307076b31f9a8e8914c70bf 100644 (file)
@@ -752,16 +752,16 @@ static void rtmsg_ifa(int event, struct dn_ifaddr *ifa)
 
        skb = alloc_skb(size, GFP_KERNEL);
        if (!skb) {
-               netlink_set_err(rtnl, 0, RTMGRP_DECnet_IFADDR, ENOBUFS);
+               netlink_set_err(rtnl, 0, RTNLGRP_DECnet_IFADDR, ENOBUFS);
                return;
        }
        if (dn_dev_fill_ifaddr(skb, ifa, 0, 0, event, 0) < 0) {
                kfree_skb(skb);
-               netlink_set_err(rtnl, 0, RTMGRP_DECnet_IFADDR, EINVAL);
+               netlink_set_err(rtnl, 0, RTNLGRP_DECnet_IFADDR, EINVAL);
                return;
        }
-       NETLINK_CB(skb).dst_groups = RTMGRP_DECnet_IFADDR;
-       netlink_broadcast(rtnl, skb, 0, RTMGRP_DECnet_IFADDR, GFP_KERNEL);
+       NETLINK_CB(skb).dst_group = RTNLGRP_DECnet_IFADDR;
+       netlink_broadcast(rtnl, skb, 0, RTNLGRP_DECnet_IFADDR, GFP_KERNEL);
 }
 
 static int dn_dev_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
index 202dbde9850d4dfee2eee86ed05ff9f39c14048f..369f25b60f3f3a3966ccfb2ba93982cece27dd21 100644 (file)
@@ -60,7 +60,7 @@
 #include <linux/inet.h>
 #include <linux/route.h>
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
index 8cce1fdbda907ac29dc29c2ea530102cc8f36d86..53633d352868766f699298754b0c6b192595f7bb 100644 (file)
@@ -136,69 +136,6 @@ struct sk_buff *dn_alloc_skb(struct sock *sk, int size, int pri)
        return skb;
 }
 
-/*
- * Wrapper for the above, for allocs of data skbs. We try and get the
- * whole size thats been asked for (plus 11 bytes of header). If this
- * fails, then we try for any size over 16 bytes for SOCK_STREAMS.
- */
-struct sk_buff *dn_alloc_send_skb(struct sock *sk, size_t *size, int noblock, long timeo, int *err)
-{
-       int space;
-       int len;
-       struct sk_buff *skb = NULL;
-
-       *err = 0;
-
-       while(skb == NULL) {
-               if (signal_pending(current)) {
-                       *err = sock_intr_errno(timeo);
-                       break;
-               }
-
-               if (sk->sk_shutdown & SEND_SHUTDOWN) {
-                       *err = EINVAL;
-                       break;
-               }
-
-               if (sk->sk_err)
-                       break;
-
-               len = *size + 11;
-               space = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
-
-               if (space < len) {
-                       if ((sk->sk_socket->type == SOCK_STREAM) &&
-                           (space >= (16 + 11)))
-                               len = space;
-               }
-
-               if (space < len) {
-                       set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
-                       if (noblock) {
-                               *err = EWOULDBLOCK;
-                               break;
-                       }
-
-                       clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
-                       SOCK_SLEEP_PRE(sk)
-
-                       if ((sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc)) <
-                           len)
-                               schedule();
-
-                       SOCK_SLEEP_POST(sk)
-                       continue;
-               }
-
-               if ((skb = dn_alloc_skb(sk, len, sk->sk_allocation)) == NULL)
-                       continue;
-
-               *size = len - 11;
-       }
-
-       return skb;
-}
-
 /*
  * Calculate persist timer based upon the smoothed round
  * trip time and the variance. Backoff according to the
@@ -479,7 +416,7 @@ int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff
                xmit_count = cb2->xmit_count;
                segnum = cb2->segnum;
                /* Remove and drop ack'ed packet */
-               skb_unlink(ack);
+               skb_unlink(ack, q);
                kfree_skb(ack);
                ack = NULL;
 
index 2399fa8a3f86e8db94dc753acd5c7240bf1f500f..2c915f305be37ffef87997ae5fbab5a166103c3b 100644 (file)
@@ -572,7 +572,7 @@ static int dn_route_ptp_hello(struct sk_buff *skb)
        return NET_RX_SUCCESS;
 }
 
-int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
+int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
 {
        struct dn_skb_cb *cb;
        unsigned char flags = 0;
index 28ba5777a25ac58ff21e4c7ba9ecae08c96c251f..eeba56f99323b0cf82131b0fa3f6c9614dc2927e 100644 (file)
@@ -79,7 +79,7 @@ for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_n
 static DEFINE_RWLOCK(dn_fib_tables_lock);
 struct dn_fib_table *dn_fib_tables[RT_TABLE_MAX + 1];
 
-static kmem_cache_t *dn_hash_kmem;
+static kmem_cache_t *dn_hash_kmem __read_mostly;
 static int dn_fib_hash_zombies;
 
 static inline dn_fib_idx_t dn_hash(dn_fib_key_t key, struct dn_zone *dz)
@@ -349,10 +349,10 @@ static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, int tb_id,
                 kfree_skb(skb);
                 return;
         }
-        NETLINK_CB(skb).dst_groups = RTMGRP_DECnet_ROUTE;
+        NETLINK_CB(skb).dst_group = RTNLGRP_DECnet_ROUTE;
         if (nlh->nlmsg_flags & NLM_F_ECHO)
                 atomic_inc(&skb->users);
-        netlink_broadcast(rtnl, skb, pid, RTMGRP_DECnet_ROUTE, GFP_KERNEL);
+        netlink_broadcast(rtnl, skb, pid, RTNLGRP_DECnet_ROUTE, GFP_KERNEL);
         if (nlh->nlmsg_flags & NLM_F_ECHO)
                 netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT);
 }
index 284a9998e53d756f02fe84a3cfd16ef2276cf617..1ab94c6e22ed504bba14c81c42470371870bc99b 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/netfilter.h>
 #include <linux/spinlock.h>
 #include <linux/netlink.h>
+#include <linux/netfilter_decnet.h>
 
 #include <net/sock.h>
 #include <net/flow.h>
@@ -71,10 +72,10 @@ static void dnrmg_send_peer(struct sk_buff *skb)
 
        switch(flags & DN_RT_CNTL_MSK) {
                case DN_RT_PKT_L1RT:
-                       group = DNRMG_L1_GROUP;
+                       group = DNRNG_NLGRP_L1;
                        break;
                case DN_RT_PKT_L2RT:
-                       group = DNRMG_L2_GROUP;
+                       group = DNRNG_NLGRP_L2;
                        break;
                default:
                        return;
@@ -83,7 +84,7 @@ static void dnrmg_send_peer(struct sk_buff *skb)
        skb2 = dnrmg_build_message(skb, &status);
        if (skb2 == NULL)
                return;
-       NETLINK_CB(skb2).dst_groups = group;
+       NETLINK_CB(skb2).dst_group = group;
        netlink_broadcast(dnrmg, skb2, 0, group, GFP_ATOMIC);
 }
 
@@ -138,7 +139,8 @@ static int __init init(void)
 {
        int rv = 0;
 
-       dnrmg = netlink_kernel_create(NETLINK_DNRTMSG, dnrmg_receive_user_sk);
+       dnrmg = netlink_kernel_create(NETLINK_DNRTMSG, DNRNG_NLGRP_MAX,
+                                     dnrmg_receive_user_sk, THIS_MODULE);
        if (dnrmg == NULL) {
                printk(KERN_ERR "dn_rtmsg: Cannot create netlink socket");
                return -ENOMEM;
@@ -162,6 +164,7 @@ static void __exit fini(void)
 MODULE_DESCRIPTION("DECnet Routing Message Grabulator");
 MODULE_AUTHOR("Steven Whitehouse <steve@chygwyn.com>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_DNRTMSG);
 
 module_init(init);
 module_exit(fini);
index de691e119e173fab412e8e90be336f9d3312e25f..4a62093eb343afae44042592e75271c40f0fc2fd 100644 (file)
@@ -159,7 +159,7 @@ static int econet_recvmsg(struct kiocb *iocb, struct socket *sock,
        err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
        if (err)
                goto out_free;
-       sk->sk_stamp = skb->stamp;
+       skb_get_timestamp(skb, &sk->sk_stamp);
 
        if (msg->msg_name)
                memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
@@ -869,7 +869,7 @@ static void aun_tx_ack(unsigned long seq, int result)
 
 foundit:
        tx_result(skb->sk, eb->cookie, result);
-       skb_unlink(skb);
+       skb_unlink(skb, &aun_queue);
        spin_unlock_irqrestore(&aun_queue_lock, flags);
        kfree_skb(skb);
 }
@@ -947,7 +947,7 @@ static void ab_cleanup(unsigned long h)
                {
                        tx_result(skb->sk, eb->cookie, 
                                  ECTYPE_TRANSMIT_NOT_PRESENT);
-                       skb_unlink(skb);
+                       skb_unlink(skb, &aun_queue);
                        kfree_skb(skb);
                }
                skb = newskb;
@@ -1009,7 +1009,7 @@ release:
  *     Receive an Econet frame from a device.
  */
 
-static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
+static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
 {
        struct ec_framehdr *hdr;
        struct sock *sk;
index f6dbfb99b14ddf76db0d26eae2d904fda3ccb5c0..87a052a9a84f9b4025ebf430f0c6197afd3a759c 100644 (file)
@@ -62,8 +62,6 @@
 #include <asm/system.h>
 #include <asm/checksum.h>
 
-extern int __init netdev_boot_setup(char *str);
-
 __setup("ether=", netdev_boot_setup);
 
 /*
@@ -163,7 +161,6 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
        skb->mac.raw=skb->data;
        skb_pull(skb,ETH_HLEN);
        eth = eth_hdr(skb);
-       skb->input_dev = dev;
        
        if(*eth->h_dest&1)
        {
index b81a6d532342a3bbb610670174918e02935bcaf2..66b39fc342d20e8a8088857d8ee4d06244f0d8e7 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/mm.h>
 #include <linux/sysctl.h>
+#include <linux/if_ether.h>
 
 ctl_table ether_table[] = {
        {0}
diff --git a/net/ieee80211/Kconfig b/net/ieee80211/Kconfig
new file mode 100644 (file)
index 0000000..58ed431
--- /dev/null
@@ -0,0 +1,69 @@
+config IEEE80211
+       tristate "Generic IEEE 802.11 Networking Stack"
+       select NET_RADIO
+       ---help---
+       This option enables the hardware independent IEEE 802.11
+       networking stack.
+
+config IEEE80211_DEBUG
+       bool "Enable full debugging output"
+       depends on IEEE80211
+       ---help---
+         This option will enable debug tracing output for the
+         ieee80211 network stack.
+
+         This will result in the kernel module being ~70k larger.  You
+         can control which debug output is sent to the kernel log by
+         setting the value in
+
+         /proc/net/ieee80211/debug_level
+
+         For example:
+
+         % echo 0x00000FFO > /proc/net/ieee80211/debug_level
+
+         For a list of values you can assign to debug_level, you
+         can look at the bit mask values in <net/ieee80211.h>
+
+         If you are not trying to debug or develop the ieee80211
+         subsystem, you most likely want to say N here.
+
+config IEEE80211_CRYPT_WEP
+       tristate "IEEE 802.11 WEP encryption (802.1x)"
+       depends on IEEE80211
+       select CRYPTO
+       select CRYPTO_ARC4
+       select CRC32
+       ---help---
+       Include software based cipher suites in support of IEEE
+       802.11's WEP.  This is needed for WEP as well as 802.1x.
+
+       This can be compiled as a modules and it will be called
+       "ieee80211_crypt_wep".
+
+config IEEE80211_CRYPT_CCMP
+       tristate "IEEE 802.11i CCMP support"
+       depends on IEEE80211
+       select CRYPTO
+       select CRYPTO_AES
+       ---help---
+       Include software based cipher suites in support of IEEE 802.11i
+       (aka TGi, WPA, WPA2, WPA-PSK, etc.) for use with CCMP enabled
+       networks.
+
+       This can be compiled as a modules and it will be called
+       "ieee80211_crypt_ccmp".
+
+config IEEE80211_CRYPT_TKIP
+       tristate "IEEE 802.11i TKIP encryption"
+       depends on IEEE80211
+       select CRYPTO
+       select CRYPTO_MICHAEL_MIC
+       ---help---
+       Include software based cipher suites in support of IEEE 802.11i
+       (aka TGi, WPA, WPA2, WPA-PSK, etc.) for use with TKIP enabled
+       networks.
+
+       This can be compiled as a modules and it will be called
+       "ieee80211_crypt_tkip".
+
diff --git a/net/ieee80211/Makefile b/net/ieee80211/Makefile
new file mode 100644 (file)
index 0000000..a6ccac5
--- /dev/null
@@ -0,0 +1,11 @@
+obj-$(CONFIG_IEEE80211) += ieee80211.o
+obj-$(CONFIG_IEEE80211) += ieee80211_crypt.o
+obj-$(CONFIG_IEEE80211_CRYPT_WEP) += ieee80211_crypt_wep.o
+obj-$(CONFIG_IEEE80211_CRYPT_CCMP) += ieee80211_crypt_ccmp.o
+obj-$(CONFIG_IEEE80211_CRYPT_TKIP) += ieee80211_crypt_tkip.o
+ieee80211-objs := \
+       ieee80211_module.o \
+       ieee80211_tx.o \
+       ieee80211_rx.o \
+       ieee80211_wx.o
+
diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c
new file mode 100644 (file)
index 0000000..61a9d92
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Host AP crypto routines
+ *
+ * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. See README and COPYING for
+ * more details.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/string.h>
+#include <asm/errno.h>
+
+#include <net/ieee80211.h>
+
+MODULE_AUTHOR("Jouni Malinen");
+MODULE_DESCRIPTION("HostAP crypto");
+MODULE_LICENSE("GPL");
+
+struct ieee80211_crypto_alg {
+       struct list_head list;
+       struct ieee80211_crypto_ops *ops;
+};
+
+struct ieee80211_crypto {
+       struct list_head algs;
+       spinlock_t lock;
+};
+
+static struct ieee80211_crypto *hcrypt;
+
+void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force)
+{
+       struct list_head *ptr, *n;
+       struct ieee80211_crypt_data *entry;
+
+       for (ptr = ieee->crypt_deinit_list.next, n = ptr->next;
+            ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) {
+               entry = list_entry(ptr, struct ieee80211_crypt_data, list);
+
+               if (atomic_read(&entry->refcnt) != 0 && !force)
+                       continue;
+
+               list_del(ptr);
+
+               if (entry->ops) {
+                       entry->ops->deinit(entry->priv);
+                       module_put(entry->ops->owner);
+               }
+               kfree(entry);
+       }
+}
+
+void ieee80211_crypt_deinit_handler(unsigned long data)
+{
+       struct ieee80211_device *ieee = (struct ieee80211_device *)data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ieee->lock, flags);
+       ieee80211_crypt_deinit_entries(ieee, 0);
+       if (!list_empty(&ieee->crypt_deinit_list)) {
+               printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
+                      "deletion list\n", ieee->dev->name);
+               ieee->crypt_deinit_timer.expires = jiffies + HZ;
+               add_timer(&ieee->crypt_deinit_timer);
+       }
+       spin_unlock_irqrestore(&ieee->lock, flags);
+
+}
+
+void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
+                                   struct ieee80211_crypt_data **crypt)
+{
+       struct ieee80211_crypt_data *tmp;
+       unsigned long flags;
+
+       if (*crypt == NULL)
+               return;
+
+       tmp = *crypt;
+       *crypt = NULL;
+
+       /* must not run ops->deinit() while there may be pending encrypt or
+        * decrypt operations. Use a list of delayed deinits to avoid needing
+        * locking. */
+
+       spin_lock_irqsave(&ieee->lock, flags);
+       list_add(&tmp->list, &ieee->crypt_deinit_list);
+       if (!timer_pending(&ieee->crypt_deinit_timer)) {
+               ieee->crypt_deinit_timer.expires = jiffies + HZ;
+               add_timer(&ieee->crypt_deinit_timer);
+       }
+       spin_unlock_irqrestore(&ieee->lock, flags);
+}
+
+int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops)
+{
+       unsigned long flags;
+       struct ieee80211_crypto_alg *alg;
+
+       if (hcrypt == NULL)
+               return -1;
+
+       alg = kmalloc(sizeof(*alg), GFP_KERNEL);
+       if (alg == NULL)
+               return -ENOMEM;
+
+       memset(alg, 0, sizeof(*alg));
+       alg->ops = ops;
+
+       spin_lock_irqsave(&hcrypt->lock, flags);
+       list_add(&alg->list, &hcrypt->algs);
+       spin_unlock_irqrestore(&hcrypt->lock, flags);
+
+       printk(KERN_DEBUG "ieee80211_crypt: registered algorithm '%s'\n",
+              ops->name);
+
+       return 0;
+}
+
+int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops)
+{
+       unsigned long flags;
+       struct list_head *ptr;
+       struct ieee80211_crypto_alg *del_alg = NULL;
+
+       if (hcrypt == NULL)
+               return -1;
+
+       spin_lock_irqsave(&hcrypt->lock, flags);
+       for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) {
+               struct ieee80211_crypto_alg *alg =
+                   (struct ieee80211_crypto_alg *)ptr;
+               if (alg->ops == ops) {
+                       list_del(&alg->list);
+                       del_alg = alg;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&hcrypt->lock, flags);
+
+       if (del_alg) {
+               printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm "
+                      "'%s'\n", ops->name);
+               kfree(del_alg);
+       }
+
+       return del_alg ? 0 : -1;
+}
+
+struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name)
+{
+       unsigned long flags;
+       struct list_head *ptr;
+       struct ieee80211_crypto_alg *found_alg = NULL;
+
+       if (hcrypt == NULL)
+               return NULL;
+
+       spin_lock_irqsave(&hcrypt->lock, flags);
+       for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) {
+               struct ieee80211_crypto_alg *alg =
+                   (struct ieee80211_crypto_alg *)ptr;
+               if (strcmp(alg->ops->name, name) == 0) {
+                       found_alg = alg;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&hcrypt->lock, flags);
+
+       if (found_alg)
+               return found_alg->ops;
+       else
+               return NULL;
+}
+
+static void *ieee80211_crypt_null_init(int keyidx)
+{
+       return (void *)1;
+}
+static void ieee80211_crypt_null_deinit(void *priv)
+{
+}
+
+static struct ieee80211_crypto_ops ieee80211_crypt_null = {
+       .name                   = "NULL",
+       .init                   = ieee80211_crypt_null_init,
+       .deinit                 = ieee80211_crypt_null_deinit,
+       .encrypt_mpdu           = NULL,
+       .decrypt_mpdu           = NULL,
+       .encrypt_msdu           = NULL,
+       .decrypt_msdu           = NULL,
+       .set_key                = NULL,
+       .get_key                = NULL,
+       .extra_prefix_len       = 0,
+       .extra_postfix_len      = 0,
+       .owner                  = THIS_MODULE,
+};
+
+static int __init ieee80211_crypto_init(void)
+{
+       int ret = -ENOMEM;
+
+       hcrypt = kmalloc(sizeof(*hcrypt), GFP_KERNEL);
+       if (!hcrypt)
+               goto out;
+
+       memset(hcrypt, 0, sizeof(*hcrypt));
+       INIT_LIST_HEAD(&hcrypt->algs);
+       spin_lock_init(&hcrypt->lock);
+
+       ret = ieee80211_register_crypto_ops(&ieee80211_crypt_null);
+       if (ret < 0) {
+               kfree(hcrypt);
+               hcrypt = NULL;
+       }
+      out:
+       return ret;
+}
+
+static void __exit ieee80211_crypto_deinit(void)
+{
+       struct list_head *ptr, *n;
+
+       if (hcrypt == NULL)
+               return;
+
+       for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs;
+            ptr = n, n = ptr->next) {
+               struct ieee80211_crypto_alg *alg =
+                   (struct ieee80211_crypto_alg *)ptr;
+               list_del(ptr);
+               printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm "
+                      "'%s' (deinit)\n", alg->ops->name);
+               kfree(alg);
+       }
+
+       kfree(hcrypt);
+}
+
+EXPORT_SYMBOL(ieee80211_crypt_deinit_entries);
+EXPORT_SYMBOL(ieee80211_crypt_deinit_handler);
+EXPORT_SYMBOL(ieee80211_crypt_delayed_deinit);
+
+EXPORT_SYMBOL(ieee80211_register_crypto_ops);
+EXPORT_SYMBOL(ieee80211_unregister_crypto_ops);
+EXPORT_SYMBOL(ieee80211_get_crypto_ops);
+
+module_init(ieee80211_crypto_init);
+module_exit(ieee80211_crypto_deinit);
diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c
new file mode 100644 (file)
index 0000000..8fc13f4
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * Host AP crypt: host-based CCMP encryption implementation for Host AP driver
+ *
+ * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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. See README and COPYING for
+ * more details.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if_ether.h>
+#include <linux/if_arp.h>
+#include <asm/string.h>
+#include <linux/wireless.h>
+
+#include <net/ieee80211.h>
+
+#include <linux/crypto.h>
+#include <asm/scatterlist.h>
+
+MODULE_AUTHOR("Jouni Malinen");
+MODULE_DESCRIPTION("Host AP crypt: CCMP");
+MODULE_LICENSE("GPL");
+
+#define AES_BLOCK_LEN 16
+#define CCMP_HDR_LEN 8
+#define CCMP_MIC_LEN 8
+#define CCMP_TK_LEN 16
+#define CCMP_PN_LEN 6
+
+struct ieee80211_ccmp_data {
+       u8 key[CCMP_TK_LEN];
+       int key_set;
+
+       u8 tx_pn[CCMP_PN_LEN];
+       u8 rx_pn[CCMP_PN_LEN];
+
+       u32 dot11RSNAStatsCCMPFormatErrors;
+       u32 dot11RSNAStatsCCMPReplays;
+       u32 dot11RSNAStatsCCMPDecryptErrors;
+
+       int key_idx;
+
+       struct crypto_tfm *tfm;
+
+       /* scratch buffers for virt_to_page() (crypto API) */
+       u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN],
+           tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN];
+       u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN];
+};
+
+static void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm,
+                                      const u8 pt[16], u8 ct[16])
+{
+       struct scatterlist src, dst;
+
+       src.page = virt_to_page(pt);
+       src.offset = offset_in_page(pt);
+       src.length = AES_BLOCK_LEN;
+
+       dst.page = virt_to_page(ct);
+       dst.offset = offset_in_page(ct);
+       dst.length = AES_BLOCK_LEN;
+
+       crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN);
+}
+
+static void *ieee80211_ccmp_init(int key_idx)
+{
+       struct ieee80211_ccmp_data *priv;
+
+       priv = kmalloc(sizeof(*priv), GFP_ATOMIC);
+       if (priv == NULL)
+               goto fail;
+       memset(priv, 0, sizeof(*priv));
+       priv->key_idx = key_idx;
+
+       priv->tfm = crypto_alloc_tfm("aes", 0);
+       if (priv->tfm == NULL) {
+               printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate "
+                      "crypto API aes\n");
+               goto fail;
+       }
+
+       return priv;
+
+      fail:
+       if (priv) {
+               if (priv->tfm)
+                       crypto_free_tfm(priv->tfm);
+               kfree(priv);
+       }
+
+       return NULL;
+}
+
+static void ieee80211_ccmp_deinit(void *priv)
+{
+       struct ieee80211_ccmp_data *_priv = priv;
+       if (_priv && _priv->tfm)
+               crypto_free_tfm(_priv->tfm);
+       kfree(priv);
+}
+
+static inline void xor_block(u8 * b, u8 * a, size_t len)
+{
+       int i;
+       for (i = 0; i < len; i++)
+               b[i] ^= a[i];
+}
+
+static void ccmp_init_blocks(struct crypto_tfm *tfm,
+                            struct ieee80211_hdr *hdr,
+                            u8 * pn, size_t dlen, u8 * b0, u8 * auth, u8 * s0)
+{
+       u8 *pos, qc = 0;
+       size_t aad_len;
+       u16 fc;
+       int a4_included, qc_included;
+       u8 aad[2 * AES_BLOCK_LEN];
+
+       fc = le16_to_cpu(hdr->frame_ctl);
+       a4_included = ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+                      (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS));
+       qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) &&
+                      (WLAN_FC_GET_STYPE(fc) & 0x08));
+       aad_len = 22;
+       if (a4_included)
+               aad_len += 6;
+       if (qc_included) {
+               pos = (u8 *) & hdr->addr4;
+               if (a4_included)
+                       pos += 6;
+               qc = *pos & 0x0f;
+               aad_len += 2;
+       }
+
+       /* CCM Initial Block:
+        * Flag (Include authentication header, M=3 (8-octet MIC),
+        *       L=1 (2-octet Dlen))
+        * Nonce: 0x00 | A2 | PN
+        * Dlen */
+       b0[0] = 0x59;
+       b0[1] = qc;
+       memcpy(b0 + 2, hdr->addr2, ETH_ALEN);
+       memcpy(b0 + 8, pn, CCMP_PN_LEN);
+       b0[14] = (dlen >> 8) & 0xff;
+       b0[15] = dlen & 0xff;
+
+       /* AAD:
+        * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
+        * A1 | A2 | A3
+        * SC with bits 4..15 (seq#) masked to zero
+        * A4 (if present)
+        * QC (if present)
+        */
+       pos = (u8 *) hdr;
+       aad[0] = 0;             /* aad_len >> 8 */
+       aad[1] = aad_len & 0xff;
+       aad[2] = pos[0] & 0x8f;
+       aad[3] = pos[1] & 0xc7;
+       memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN);
+       pos = (u8 *) & hdr->seq_ctl;
+       aad[22] = pos[0] & 0x0f;
+       aad[23] = 0;            /* all bits masked */
+       memset(aad + 24, 0, 8);
+       if (a4_included)
+               memcpy(aad + 24, hdr->addr4, ETH_ALEN);
+       if (qc_included) {
+               aad[a4_included ? 30 : 24] = qc;
+               /* rest of QC masked */
+       }
+
+       /* Start with the first block and AAD */
+       ieee80211_ccmp_aes_encrypt(tfm, b0, auth);
+       xor_block(auth, aad, AES_BLOCK_LEN);
+       ieee80211_ccmp_aes_encrypt(tfm, auth, auth);
+       xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN);
+       ieee80211_ccmp_aes_encrypt(tfm, auth, auth);
+       b0[0] &= 0x07;
+       b0[14] = b0[15] = 0;
+       ieee80211_ccmp_aes_encrypt(tfm, b0, s0);
+}
+
+static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+       struct ieee80211_ccmp_data *key = priv;
+       int data_len, i, blocks, last, len;
+       u8 *pos, *mic;
+       struct ieee80211_hdr *hdr;
+       u8 *b0 = key->tx_b0;
+       u8 *b = key->tx_b;
+       u8 *e = key->tx_e;
+       u8 *s0 = key->tx_s0;
+
+       if (skb_headroom(skb) < CCMP_HDR_LEN ||
+           skb_tailroom(skb) < CCMP_MIC_LEN || skb->len < hdr_len)
+               return -1;
+
+       data_len = skb->len - hdr_len;
+       pos = skb_push(skb, CCMP_HDR_LEN);
+       memmove(pos, pos + CCMP_HDR_LEN, hdr_len);
+       pos += hdr_len;
+       mic = skb_put(skb, CCMP_MIC_LEN);
+
+       i = CCMP_PN_LEN - 1;
+       while (i >= 0) {
+               key->tx_pn[i]++;
+               if (key->tx_pn[i] != 0)
+                       break;
+               i--;
+       }
+
+       *pos++ = key->tx_pn[5];
+       *pos++ = key->tx_pn[4];
+       *pos++ = 0;
+       *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
+       *pos++ = key->tx_pn[3];
+       *pos++ = key->tx_pn[2];
+       *pos++ = key->tx_pn[1];
+       *pos++ = key->tx_pn[0];
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+       ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0);
+
+       blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
+       last = data_len % AES_BLOCK_LEN;
+
+       for (i = 1; i <= blocks; i++) {
+               len = (i == blocks && last) ? last : AES_BLOCK_LEN;
+               /* Authentication */
+               xor_block(b, pos, len);
+               ieee80211_ccmp_aes_encrypt(key->tfm, b, b);
+               /* Encryption, with counter */
+               b0[14] = (i >> 8) & 0xff;
+               b0[15] = i & 0xff;
+               ieee80211_ccmp_aes_encrypt(key->tfm, b0, e);
+               xor_block(pos, e, len);
+               pos += len;
+       }
+
+       for (i = 0; i < CCMP_MIC_LEN; i++)
+               mic[i] = b[i] ^ s0[i];
+
+       return 0;
+}
+
+static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+       struct ieee80211_ccmp_data *key = priv;
+       u8 keyidx, *pos;
+       struct ieee80211_hdr *hdr;
+       u8 *b0 = key->rx_b0;
+       u8 *b = key->rx_b;
+       u8 *a = key->rx_a;
+       u8 pn[6];
+       int i, blocks, last, len;
+       size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN;
+       u8 *mic = skb->data + skb->len - CCMP_MIC_LEN;
+
+       if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) {
+               key->dot11RSNAStatsCCMPFormatErrors++;
+               return -1;
+       }
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+       pos = skb->data + hdr_len;
+       keyidx = pos[3];
+       if (!(keyidx & (1 << 5))) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "CCMP: received packet without ExtIV"
+                              " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
+               }
+               key->dot11RSNAStatsCCMPFormatErrors++;
+               return -2;
+       }
+       keyidx >>= 6;
+       if (key->key_idx != keyidx) {
+               printk(KERN_DEBUG "CCMP: RX tkey->key_idx=%d frame "
+                      "keyidx=%d priv=%p\n", key->key_idx, keyidx, priv);
+               return -6;
+       }
+       if (!key->key_set) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "CCMP: received packet from " MAC_FMT
+                              " with keyid=%d that does not have a configured"
+                              " key\n", MAC_ARG(hdr->addr2), keyidx);
+               }
+               return -3;
+       }
+
+       pn[0] = pos[7];
+       pn[1] = pos[6];
+       pn[2] = pos[5];
+       pn[3] = pos[4];
+       pn[4] = pos[1];
+       pn[5] = pos[0];
+       pos += 8;
+
+       if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT
+                              " previous PN %02x%02x%02x%02x%02x%02x "
+                              "received PN %02x%02x%02x%02x%02x%02x\n",
+                              MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn),
+                              MAC_ARG(pn));
+               }
+               key->dot11RSNAStatsCCMPReplays++;
+               return -4;
+       }
+
+       ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b);
+       xor_block(mic, b, CCMP_MIC_LEN);
+
+       blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
+       last = data_len % AES_BLOCK_LEN;
+
+       for (i = 1; i <= blocks; i++) {
+               len = (i == blocks && last) ? last : AES_BLOCK_LEN;
+               /* Decrypt, with counter */
+               b0[14] = (i >> 8) & 0xff;
+               b0[15] = i & 0xff;
+               ieee80211_ccmp_aes_encrypt(key->tfm, b0, b);
+               xor_block(pos, b, len);
+               /* Authentication */
+               xor_block(a, pos, len);
+               ieee80211_ccmp_aes_encrypt(key->tfm, a, a);
+               pos += len;
+       }
+
+       if (memcmp(mic, a, CCMP_MIC_LEN) != 0) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "CCMP: decrypt failed: STA="
+                              MAC_FMT "\n", MAC_ARG(hdr->addr2));
+               }
+               key->dot11RSNAStatsCCMPDecryptErrors++;
+               return -5;
+       }
+
+       memcpy(key->rx_pn, pn, CCMP_PN_LEN);
+
+       /* Remove hdr and MIC */
+       memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len);
+       skb_pull(skb, CCMP_HDR_LEN);
+       skb_trim(skb, skb->len - CCMP_MIC_LEN);
+
+       return keyidx;
+}
+
+static int ieee80211_ccmp_set_key(void *key, int len, u8 * seq, void *priv)
+{
+       struct ieee80211_ccmp_data *data = priv;
+       int keyidx;
+       struct crypto_tfm *tfm = data->tfm;
+
+       keyidx = data->key_idx;
+       memset(data, 0, sizeof(*data));
+       data->key_idx = keyidx;
+       data->tfm = tfm;
+       if (len == CCMP_TK_LEN) {
+               memcpy(data->key, key, CCMP_TK_LEN);
+               data->key_set = 1;
+               if (seq) {
+                       data->rx_pn[0] = seq[5];
+                       data->rx_pn[1] = seq[4];
+                       data->rx_pn[2] = seq[3];
+                       data->rx_pn[3] = seq[2];
+                       data->rx_pn[4] = seq[1];
+                       data->rx_pn[5] = seq[0];
+               }
+               crypto_cipher_setkey(data->tfm, data->key, CCMP_TK_LEN);
+       } else if (len == 0)
+               data->key_set = 0;
+       else
+               return -1;
+
+       return 0;
+}
+
+static int ieee80211_ccmp_get_key(void *key, int len, u8 * seq, void *priv)
+{
+       struct ieee80211_ccmp_data *data = priv;
+
+       if (len < CCMP_TK_LEN)
+               return -1;
+
+       if (!data->key_set)
+               return 0;
+       memcpy(key, data->key, CCMP_TK_LEN);
+
+       if (seq) {
+               seq[0] = data->tx_pn[5];
+               seq[1] = data->tx_pn[4];
+               seq[2] = data->tx_pn[3];
+               seq[3] = data->tx_pn[2];
+               seq[4] = data->tx_pn[1];
+               seq[5] = data->tx_pn[0];
+       }
+
+       return CCMP_TK_LEN;
+}
+
+static char *ieee80211_ccmp_print_stats(char *p, void *priv)
+{
+       struct ieee80211_ccmp_data *ccmp = priv;
+       p += sprintf(p, "key[%d] alg=CCMP key_set=%d "
+                    "tx_pn=%02x%02x%02x%02x%02x%02x "
+                    "rx_pn=%02x%02x%02x%02x%02x%02x "
+                    "format_errors=%d replays=%d decrypt_errors=%d\n",
+                    ccmp->key_idx, ccmp->key_set,
+                    MAC_ARG(ccmp->tx_pn), MAC_ARG(ccmp->rx_pn),
+                    ccmp->dot11RSNAStatsCCMPFormatErrors,
+                    ccmp->dot11RSNAStatsCCMPReplays,
+                    ccmp->dot11RSNAStatsCCMPDecryptErrors);
+
+       return p;
+}
+
+static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = {
+       .name                   = "CCMP",
+       .init                   = ieee80211_ccmp_init,
+       .deinit                 = ieee80211_ccmp_deinit,
+       .encrypt_mpdu           = ieee80211_ccmp_encrypt,
+       .decrypt_mpdu           = ieee80211_ccmp_decrypt,
+       .encrypt_msdu           = NULL,
+       .decrypt_msdu           = NULL,
+       .set_key                = ieee80211_ccmp_set_key,
+       .get_key                = ieee80211_ccmp_get_key,
+       .print_stats            = ieee80211_ccmp_print_stats,
+       .extra_prefix_len       = CCMP_HDR_LEN,
+       .extra_postfix_len      = CCMP_MIC_LEN,
+       .owner                  = THIS_MODULE,
+};
+
+static int __init ieee80211_crypto_ccmp_init(void)
+{
+       return ieee80211_register_crypto_ops(&ieee80211_crypt_ccmp);
+}
+
+static void __exit ieee80211_crypto_ccmp_exit(void)
+{
+       ieee80211_unregister_crypto_ops(&ieee80211_crypt_ccmp);
+}
+
+module_init(ieee80211_crypto_ccmp_init);
+module_exit(ieee80211_crypto_ccmp_exit);
diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c
new file mode 100644 (file)
index 0000000..d4f9164
--- /dev/null
@@ -0,0 +1,683 @@
+/*
+ * Host AP crypt: host-based TKIP encryption implementation for Host AP driver
+ *
+ * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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. See README and COPYING for
+ * more details.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if_ether.h>
+#include <linux/if_arp.h>
+#include <asm/string.h>
+
+#include <net/ieee80211.h>
+
+#include <linux/crypto.h>
+#include <asm/scatterlist.h>
+#include <linux/crc32.h>
+
+MODULE_AUTHOR("Jouni Malinen");
+MODULE_DESCRIPTION("Host AP crypt: TKIP");
+MODULE_LICENSE("GPL");
+
+struct ieee80211_tkip_data {
+#define TKIP_KEY_LEN 32
+       u8 key[TKIP_KEY_LEN];
+       int key_set;
+
+       u32 tx_iv32;
+       u16 tx_iv16;
+       u16 tx_ttak[5];
+       int tx_phase1_done;
+
+       u32 rx_iv32;
+       u16 rx_iv16;
+       u16 rx_ttak[5];
+       int rx_phase1_done;
+       u32 rx_iv32_new;
+       u16 rx_iv16_new;
+
+       u32 dot11RSNAStatsTKIPReplays;
+       u32 dot11RSNAStatsTKIPICVErrors;
+       u32 dot11RSNAStatsTKIPLocalMICFailures;
+
+       int key_idx;
+
+       struct crypto_tfm *tfm_arc4;
+       struct crypto_tfm *tfm_michael;
+
+       /* scratch buffers for virt_to_page() (crypto API) */
+       u8 rx_hdr[16], tx_hdr[16];
+};
+
+static void *ieee80211_tkip_init(int key_idx)
+{
+       struct ieee80211_tkip_data *priv;
+
+       priv = kmalloc(sizeof(*priv), GFP_ATOMIC);
+       if (priv == NULL)
+               goto fail;
+       memset(priv, 0, sizeof(*priv));
+       priv->key_idx = key_idx;
+
+       priv->tfm_arc4 = crypto_alloc_tfm("arc4", 0);
+       if (priv->tfm_arc4 == NULL) {
+               printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
+                      "crypto API arc4\n");
+               goto fail;
+       }
+
+       priv->tfm_michael = crypto_alloc_tfm("michael_mic", 0);
+       if (priv->tfm_michael == NULL) {
+               printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
+                      "crypto API michael_mic\n");
+               goto fail;
+       }
+
+       return priv;
+
+      fail:
+       if (priv) {
+               if (priv->tfm_michael)
+                       crypto_free_tfm(priv->tfm_michael);
+               if (priv->tfm_arc4)
+                       crypto_free_tfm(priv->tfm_arc4);
+               kfree(priv);
+       }
+
+       return NULL;
+}
+
+static void ieee80211_tkip_deinit(void *priv)
+{
+       struct ieee80211_tkip_data *_priv = priv;
+       if (_priv && _priv->tfm_michael)
+               crypto_free_tfm(_priv->tfm_michael);
+       if (_priv && _priv->tfm_arc4)
+               crypto_free_tfm(_priv->tfm_arc4);
+       kfree(priv);
+}
+
+static inline u16 RotR1(u16 val)
+{
+       return (val >> 1) | (val << 15);
+}
+
+static inline u8 Lo8(u16 val)
+{
+       return val & 0xff;
+}
+
+static inline u8 Hi8(u16 val)
+{
+       return val >> 8;
+}
+
+static inline u16 Lo16(u32 val)
+{
+       return val & 0xffff;
+}
+
+static inline u16 Hi16(u32 val)
+{
+       return val >> 16;
+}
+
+static inline u16 Mk16(u8 hi, u8 lo)
+{
+       return lo | (((u16) hi) << 8);
+}
+
+static inline u16 Mk16_le(u16 * v)
+{
+       return le16_to_cpu(*v);
+}
+
+static const u16 Sbox[256] = {
+       0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
+       0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
+       0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
+       0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
+       0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
+       0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
+       0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
+       0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
+       0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
+       0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
+       0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
+       0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
+       0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
+       0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
+       0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
+       0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
+       0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
+       0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
+       0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
+       0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
+       0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
+       0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
+       0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
+       0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
+       0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
+       0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
+       0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
+       0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
+       0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
+       0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
+       0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
+       0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
+};
+
+static inline u16 _S_(u16 v)
+{
+       u16 t = Sbox[Hi8(v)];
+       return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
+}
+
+#define PHASE1_LOOP_COUNT 8
+
+static void tkip_mixing_phase1(u16 * TTAK, const u8 * TK, const u8 * TA,
+                              u32 IV32)
+{
+       int i, j;
+
+       /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
+       TTAK[0] = Lo16(IV32);
+       TTAK[1] = Hi16(IV32);
+       TTAK[2] = Mk16(TA[1], TA[0]);
+       TTAK[3] = Mk16(TA[3], TA[2]);
+       TTAK[4] = Mk16(TA[5], TA[4]);
+
+       for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
+               j = 2 * (i & 1);
+               TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
+               TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
+               TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
+               TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
+               TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
+       }
+}
+
+static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK,
+                              u16 IV16)
+{
+       /* Make temporary area overlap WEP seed so that the final copy can be
+        * avoided on little endian hosts. */
+       u16 *PPK = (u16 *) & WEPSeed[4];
+
+       /* Step 1 - make copy of TTAK and bring in TSC */
+       PPK[0] = TTAK[0];
+       PPK[1] = TTAK[1];
+       PPK[2] = TTAK[2];
+       PPK[3] = TTAK[3];
+       PPK[4] = TTAK[4];
+       PPK[5] = TTAK[4] + IV16;
+
+       /* Step 2 - 96-bit bijective mixing using S-box */
+       PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) & TK[0]));
+       PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) & TK[2]));
+       PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) & TK[4]));
+       PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) & TK[6]));
+       PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) & TK[8]));
+       PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) & TK[10]));
+
+       PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) & TK[12]));
+       PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) & TK[14]));
+       PPK[2] += RotR1(PPK[1]);
+       PPK[3] += RotR1(PPK[2]);
+       PPK[4] += RotR1(PPK[3]);
+       PPK[5] += RotR1(PPK[4]);
+
+       /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
+        * WEPSeed[0..2] is transmitted as WEP IV */
+       WEPSeed[0] = Hi8(IV16);
+       WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
+       WEPSeed[2] = Lo8(IV16);
+       WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) & TK[0])) >> 1);
+
+#ifdef __BIG_ENDIAN
+       {
+               int i;
+               for (i = 0; i < 6; i++)
+                       PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
+       }
+#endif
+}
+
+static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+       struct ieee80211_tkip_data *tkey = priv;
+       int len;
+       u8 rc4key[16], *pos, *icv;
+       struct ieee80211_hdr *hdr;
+       u32 crc;
+       struct scatterlist sg;
+
+       if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 ||
+           skb->len < hdr_len)
+               return -1;
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+       if (!tkey->tx_phase1_done) {
+               tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
+                                  tkey->tx_iv32);
+               tkey->tx_phase1_done = 1;
+       }
+       tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
+
+       len = skb->len - hdr_len;
+       pos = skb_push(skb, 8);
+       memmove(pos, pos + 8, hdr_len);
+       pos += hdr_len;
+       icv = skb_put(skb, 4);
+
+       *pos++ = rc4key[0];
+       *pos++ = rc4key[1];
+       *pos++ = rc4key[2];
+       *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
+       *pos++ = tkey->tx_iv32 & 0xff;
+       *pos++ = (tkey->tx_iv32 >> 8) & 0xff;
+       *pos++ = (tkey->tx_iv32 >> 16) & 0xff;
+       *pos++ = (tkey->tx_iv32 >> 24) & 0xff;
+
+       crc = ~crc32_le(~0, pos, len);
+       icv[0] = crc;
+       icv[1] = crc >> 8;
+       icv[2] = crc >> 16;
+       icv[3] = crc >> 24;
+
+       crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16);
+       sg.page = virt_to_page(pos);
+       sg.offset = offset_in_page(pos);
+       sg.length = len + 4;
+       crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4);
+
+       tkey->tx_iv16++;
+       if (tkey->tx_iv16 == 0) {
+               tkey->tx_phase1_done = 0;
+               tkey->tx_iv32++;
+       }
+
+       return 0;
+}
+
+static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+       struct ieee80211_tkip_data *tkey = priv;
+       u8 rc4key[16];
+       u8 keyidx, *pos;
+       u32 iv32;
+       u16 iv16;
+       struct ieee80211_hdr *hdr;
+       u8 icv[4];
+       u32 crc;
+       struct scatterlist sg;
+       int plen;
+
+       if (skb->len < hdr_len + 8 + 4)
+               return -1;
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+       pos = skb->data + hdr_len;
+       keyidx = pos[3];
+       if (!(keyidx & (1 << 5))) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "TKIP: received packet without ExtIV"
+                              " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
+               }
+               return -2;
+       }
+       keyidx >>= 6;
+       if (tkey->key_idx != keyidx) {
+               printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame "
+                      "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv);
+               return -6;
+       }
+       if (!tkey->key_set) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT
+                              " with keyid=%d that does not have a configured"
+                              " key\n", MAC_ARG(hdr->addr2), keyidx);
+               }
+               return -3;
+       }
+       iv16 = (pos[0] << 8) | pos[2];
+       iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
+       pos += 8;
+
+       if (iv32 < tkey->rx_iv32 ||
+           (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT
+                              " previous TSC %08x%04x received TSC "
+                              "%08x%04x\n", MAC_ARG(hdr->addr2),
+                              tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
+               }
+               tkey->dot11RSNAStatsTKIPReplays++;
+               return -4;
+       }
+
+       if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) {
+               tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32);
+               tkey->rx_phase1_done = 1;
+       }
+       tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);
+
+       plen = skb->len - hdr_len - 12;
+
+       crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16);
+       sg.page = virt_to_page(pos);
+       sg.offset = offset_in_page(pos);
+       sg.length = plen + 4;
+       crypto_cipher_decrypt(tkey->tfm_arc4, &sg, &sg, plen + 4);
+
+       crc = ~crc32_le(~0, pos, plen);
+       icv[0] = crc;
+       icv[1] = crc >> 8;
+       icv[2] = crc >> 16;
+       icv[3] = crc >> 24;
+       if (memcmp(icv, pos + plen, 4) != 0) {
+               if (iv32 != tkey->rx_iv32) {
+                       /* Previously cached Phase1 result was already lost, so
+                        * it needs to be recalculated for the next packet. */
+                       tkey->rx_phase1_done = 0;
+               }
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "TKIP: ICV error detected: STA="
+                              MAC_FMT "\n", MAC_ARG(hdr->addr2));
+               }
+               tkey->dot11RSNAStatsTKIPICVErrors++;
+               return -5;
+       }
+
+       /* Update real counters only after Michael MIC verification has
+        * completed */
+       tkey->rx_iv32_new = iv32;
+       tkey->rx_iv16_new = iv16;
+
+       /* Remove IV and ICV */
+       memmove(skb->data + 8, skb->data, hdr_len);
+       skb_pull(skb, 8);
+       skb_trim(skb, skb->len - 4);
+
+       return keyidx;
+}
+
+static int michael_mic(struct ieee80211_tkip_data *tkey, u8 * key, u8 * hdr,
+                      u8 * data, size_t data_len, u8 * mic)
+{
+       struct scatterlist sg[2];
+
+       if (tkey->tfm_michael == NULL) {
+               printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
+               return -1;
+       }
+       sg[0].page = virt_to_page(hdr);
+       sg[0].offset = offset_in_page(hdr);
+       sg[0].length = 16;
+
+       sg[1].page = virt_to_page(data);
+       sg[1].offset = offset_in_page(data);
+       sg[1].length = data_len;
+
+       crypto_digest_init(tkey->tfm_michael);
+       crypto_digest_setkey(tkey->tfm_michael, key, 8);
+       crypto_digest_update(tkey->tfm_michael, sg, 2);
+       crypto_digest_final(tkey->tfm_michael, mic);
+
+       return 0;
+}
+
+static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
+{
+       struct ieee80211_hdr *hdr11;
+
+       hdr11 = (struct ieee80211_hdr *)skb->data;
+       switch (le16_to_cpu(hdr11->frame_ctl) &
+               (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
+       case IEEE80211_FCTL_TODS:
+               memcpy(hdr, hdr11->addr3, ETH_ALEN);    /* DA */
+               memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
+               break;
+       case IEEE80211_FCTL_FROMDS:
+               memcpy(hdr, hdr11->addr1, ETH_ALEN);    /* DA */
+               memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */
+               break;
+       case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
+               memcpy(hdr, hdr11->addr3, ETH_ALEN);    /* DA */
+               memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */
+               break;
+       case 0:
+               memcpy(hdr, hdr11->addr1, ETH_ALEN);    /* DA */
+               memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
+               break;
+       }
+
+       hdr[12] = 0;            /* priority */
+       hdr[13] = hdr[14] = hdr[15] = 0;        /* reserved */
+}
+
+static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
+                                    void *priv)
+{
+       struct ieee80211_tkip_data *tkey = priv;
+       u8 *pos;
+
+       if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
+               printk(KERN_DEBUG "Invalid packet for Michael MIC add "
+                      "(tailroom=%d hdr_len=%d skb->len=%d)\n",
+                      skb_tailroom(skb), hdr_len, skb->len);
+               return -1;
+       }
+
+       michael_mic_hdr(skb, tkey->tx_hdr);
+       pos = skb_put(skb, 8);
+       if (michael_mic(tkey, &tkey->key[16], tkey->tx_hdr,
+                       skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
+               return -1;
+
+       return 0;
+}
+
+#if WIRELESS_EXT >= 18
+static void ieee80211_michael_mic_failure(struct net_device *dev,
+                                         struct ieee80211_hdr *hdr, int keyidx)
+{
+       union iwreq_data wrqu;
+       struct iw_michaelmicfailure ev;
+
+       /* TODO: needed parameters: count, keyid, key type, TSC */
+       memset(&ev, 0, sizeof(ev));
+       ev.flags = keyidx & IW_MICFAILURE_KEY_ID;
+       if (hdr->addr1[0] & 0x01)
+               ev.flags |= IW_MICFAILURE_GROUP;
+       else
+               ev.flags |= IW_MICFAILURE_PAIRWISE;
+       ev.src_addr.sa_family = ARPHRD_ETHER;
+       memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN);
+       memset(&wrqu, 0, sizeof(wrqu));
+       wrqu.data.length = sizeof(ev);
+       wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
+}
+#elif WIRELESS_EXT >= 15
+static void ieee80211_michael_mic_failure(struct net_device *dev,
+                                         struct ieee80211_hdr *hdr, int keyidx)
+{
+       union iwreq_data wrqu;
+       char buf[128];
+
+       /* TODO: needed parameters: count, keyid, key type, TSC */
+       sprintf(buf, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr="
+               MAC_FMT ")", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni",
+               MAC_ARG(hdr->addr2));
+       memset(&wrqu, 0, sizeof(wrqu));
+       wrqu.data.length = strlen(buf);
+       wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
+}
+#else                          /* WIRELESS_EXT >= 15 */
+static inline void ieee80211_michael_mic_failure(struct net_device *dev,
+                                                struct ieee80211_hdr *hdr,
+                                                int keyidx)
+{
+}
+#endif                         /* WIRELESS_EXT >= 15 */
+
+static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
+                                       int hdr_len, void *priv)
+{
+       struct ieee80211_tkip_data *tkey = priv;
+       u8 mic[8];
+
+       if (!tkey->key_set)
+               return -1;
+
+       michael_mic_hdr(skb, tkey->rx_hdr);
+       if (michael_mic(tkey, &tkey->key[24], tkey->rx_hdr,
+                       skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
+               return -1;
+       if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
+               struct ieee80211_hdr *hdr;
+               hdr = (struct ieee80211_hdr *)skb->data;
+               printk(KERN_DEBUG "%s: Michael MIC verification failed for "
+                      "MSDU from " MAC_FMT " keyidx=%d\n",
+                      skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2),
+                      keyidx);
+               if (skb->dev)
+                       ieee80211_michael_mic_failure(skb->dev, hdr, keyidx);
+               tkey->dot11RSNAStatsTKIPLocalMICFailures++;
+               return -1;
+       }
+
+       /* Update TSC counters for RX now that the packet verification has
+        * completed. */
+       tkey->rx_iv32 = tkey->rx_iv32_new;
+       tkey->rx_iv16 = tkey->rx_iv16_new;
+
+       skb_trim(skb, skb->len - 8);
+
+       return 0;
+}
+
+static int ieee80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
+{
+       struct ieee80211_tkip_data *tkey = priv;
+       int keyidx;
+       struct crypto_tfm *tfm = tkey->tfm_michael;
+       struct crypto_tfm *tfm2 = tkey->tfm_arc4;
+
+       keyidx = tkey->key_idx;
+       memset(tkey, 0, sizeof(*tkey));
+       tkey->key_idx = keyidx;
+       tkey->tfm_michael = tfm;
+       tkey->tfm_arc4 = tfm2;
+       if (len == TKIP_KEY_LEN) {
+               memcpy(tkey->key, key, TKIP_KEY_LEN);
+               tkey->key_set = 1;
+               tkey->tx_iv16 = 1;      /* TSC is initialized to 1 */
+               if (seq) {
+                       tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) |
+                           (seq[3] << 8) | seq[2];
+                       tkey->rx_iv16 = (seq[1] << 8) | seq[0];
+               }
+       } else if (len == 0)
+               tkey->key_set = 0;
+       else
+               return -1;
+
+       return 0;
+}
+
+static int ieee80211_tkip_get_key(void *key, int len, u8 * seq, void *priv)
+{
+       struct ieee80211_tkip_data *tkey = priv;
+
+       if (len < TKIP_KEY_LEN)
+               return -1;
+
+       if (!tkey->key_set)
+               return 0;
+       memcpy(key, tkey->key, TKIP_KEY_LEN);
+
+       if (seq) {
+               /* Return the sequence number of the last transmitted frame. */
+               u16 iv16 = tkey->tx_iv16;
+               u32 iv32 = tkey->tx_iv32;
+               if (iv16 == 0)
+                       iv32--;
+               iv16--;
+               seq[0] = tkey->tx_iv16;
+               seq[1] = tkey->tx_iv16 >> 8;
+               seq[2] = tkey->tx_iv32;
+               seq[3] = tkey->tx_iv32 >> 8;
+               seq[4] = tkey->tx_iv32 >> 16;
+               seq[5] = tkey->tx_iv32 >> 24;
+       }
+
+       return TKIP_KEY_LEN;
+}
+
+static char *ieee80211_tkip_print_stats(char *p, void *priv)
+{
+       struct ieee80211_tkip_data *tkip = priv;
+       p += sprintf(p, "key[%d] alg=TKIP key_set=%d "
+                    "tx_pn=%02x%02x%02x%02x%02x%02x "
+                    "rx_pn=%02x%02x%02x%02x%02x%02x "
+                    "replays=%d icv_errors=%d local_mic_failures=%d\n",
+                    tkip->key_idx, tkip->key_set,
+                    (tkip->tx_iv32 >> 24) & 0xff,
+                    (tkip->tx_iv32 >> 16) & 0xff,
+                    (tkip->tx_iv32 >> 8) & 0xff,
+                    tkip->tx_iv32 & 0xff,
+                    (tkip->tx_iv16 >> 8) & 0xff,
+                    tkip->tx_iv16 & 0xff,
+                    (tkip->rx_iv32 >> 24) & 0xff,
+                    (tkip->rx_iv32 >> 16) & 0xff,
+                    (tkip->rx_iv32 >> 8) & 0xff,
+                    tkip->rx_iv32 & 0xff,
+                    (tkip->rx_iv16 >> 8) & 0xff,
+                    tkip->rx_iv16 & 0xff,
+                    tkip->dot11RSNAStatsTKIPReplays,
+                    tkip->dot11RSNAStatsTKIPICVErrors,
+                    tkip->dot11RSNAStatsTKIPLocalMICFailures);
+       return p;
+}
+
+static struct ieee80211_crypto_ops ieee80211_crypt_tkip = {
+       .name                   = "TKIP",
+       .init                   = ieee80211_tkip_init,
+       .deinit                 = ieee80211_tkip_deinit,
+       .encrypt_mpdu           = ieee80211_tkip_encrypt,
+       .decrypt_mpdu           = ieee80211_tkip_decrypt,
+       .encrypt_msdu           = ieee80211_michael_mic_add,
+       .decrypt_msdu           = ieee80211_michael_mic_verify,
+       .set_key                = ieee80211_tkip_set_key,
+       .get_key                = ieee80211_tkip_get_key,
+       .print_stats            = ieee80211_tkip_print_stats,
+       .extra_prefix_len       = 4 + 4,        /* IV + ExtIV */
+       .extra_postfix_len      = 8 + 4,        /* MIC + ICV */
+       .owner                  = THIS_MODULE,
+};
+
+static int __init ieee80211_crypto_tkip_init(void)
+{
+       return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip);
+}
+
+static void __exit ieee80211_crypto_tkip_exit(void)
+{
+       ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip);
+}
+
+module_init(ieee80211_crypto_tkip_init);
+module_exit(ieee80211_crypto_tkip_exit);
diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c
new file mode 100644 (file)
index 0000000..b4d2514
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Host AP crypt: host-based WEP encryption implementation for Host AP driver
+ *
+ * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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. See README and COPYING for
+ * more details.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/skbuff.h>
+#include <asm/string.h>
+
+#include <net/ieee80211.h>
+
+#include <linux/crypto.h>
+#include <asm/scatterlist.h>
+#include <linux/crc32.h>
+
+MODULE_AUTHOR("Jouni Malinen");
+MODULE_DESCRIPTION("Host AP crypt: WEP");
+MODULE_LICENSE("GPL");
+
+struct prism2_wep_data {
+       u32 iv;
+#define WEP_KEY_LEN 13
+       u8 key[WEP_KEY_LEN + 1];
+       u8 key_len;
+       u8 key_idx;
+       struct crypto_tfm *tfm;
+};
+
+static void *prism2_wep_init(int keyidx)
+{
+       struct prism2_wep_data *priv;
+
+       priv = kmalloc(sizeof(*priv), GFP_ATOMIC);
+       if (priv == NULL)
+               goto fail;
+       memset(priv, 0, sizeof(*priv));
+       priv->key_idx = keyidx;
+
+       priv->tfm = crypto_alloc_tfm("arc4", 0);
+       if (priv->tfm == NULL) {
+               printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
+                      "crypto API arc4\n");
+               goto fail;
+       }
+
+       /* start WEP IV from a random value */
+       get_random_bytes(&priv->iv, 4);
+
+       return priv;
+
+      fail:
+       if (priv) {
+               if (priv->tfm)
+                       crypto_free_tfm(priv->tfm);
+               kfree(priv);
+       }
+       return NULL;
+}
+
+static void prism2_wep_deinit(void *priv)
+{
+       struct prism2_wep_data *_priv = priv;
+       if (_priv && _priv->tfm)
+               crypto_free_tfm(_priv->tfm);
+       kfree(priv);
+}
+
+/* Perform WEP encryption on given skb that has at least 4 bytes of headroom
+ * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
+ * so the payload length increases with 8 bytes.
+ *
+ * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
+ */
+static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+       struct prism2_wep_data *wep = priv;
+       u32 crc, klen, len;
+       u8 key[WEP_KEY_LEN + 3];
+       u8 *pos, *icv;
+       struct scatterlist sg;
+
+       if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
+           skb->len < hdr_len)
+               return -1;
+
+       len = skb->len - hdr_len;
+       pos = skb_push(skb, 4);
+       memmove(pos, pos + 4, hdr_len);
+       pos += hdr_len;
+
+       klen = 3 + wep->key_len;
+
+       wep->iv++;
+
+       /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key
+        * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N)
+        * can be used to speedup attacks, so avoid using them. */
+       if ((wep->iv & 0xff00) == 0xff00) {
+               u8 B = (wep->iv >> 16) & 0xff;
+               if (B >= 3 && B < klen)
+                       wep->iv += 0x0100;
+       }
+
+       /* Prepend 24-bit IV to RC4 key and TX frame */
+       *pos++ = key[0] = (wep->iv >> 16) & 0xff;
+       *pos++ = key[1] = (wep->iv >> 8) & 0xff;
+       *pos++ = key[2] = wep->iv & 0xff;
+       *pos++ = wep->key_idx << 6;
+
+       /* Copy rest of the WEP key (the secret part) */
+       memcpy(key + 3, wep->key, wep->key_len);
+
+       /* Append little-endian CRC32 and encrypt it to produce ICV */
+       crc = ~crc32_le(~0, pos, len);
+       icv = skb_put(skb, 4);
+       icv[0] = crc;
+       icv[1] = crc >> 8;
+       icv[2] = crc >> 16;
+       icv[3] = crc >> 24;
+
+       crypto_cipher_setkey(wep->tfm, key, klen);
+       sg.page = virt_to_page(pos);
+       sg.offset = offset_in_page(pos);
+       sg.length = len + 4;
+       crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4);
+
+       return 0;
+}
+
+/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of
+ * the frame: IV (4 bytes), encrypted payload (including SNAP header),
+ * ICV (4 bytes). len includes both IV and ICV.
+ *
+ * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
+ * failure. If frame is OK, IV and ICV will be removed.
+ */
+static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+       struct prism2_wep_data *wep = priv;
+       u32 crc, klen, plen;
+       u8 key[WEP_KEY_LEN + 3];
+       u8 keyidx, *pos, icv[4];
+       struct scatterlist sg;
+
+       if (skb->len < hdr_len + 8)
+               return -1;
+
+       pos = skb->data + hdr_len;
+       key[0] = *pos++;
+       key[1] = *pos++;
+       key[2] = *pos++;
+       keyidx = *pos++ >> 6;
+       if (keyidx != wep->key_idx)
+               return -1;
+
+       klen = 3 + wep->key_len;
+
+       /* Copy rest of the WEP key (the secret part) */
+       memcpy(key + 3, wep->key, wep->key_len);
+
+       /* Apply RC4 to data and compute CRC32 over decrypted data */
+       plen = skb->len - hdr_len - 8;
+
+       crypto_cipher_setkey(wep->tfm, key, klen);
+       sg.page = virt_to_page(pos);
+       sg.offset = offset_in_page(pos);
+       sg.length = plen + 4;
+       crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4);
+
+       crc = ~crc32_le(~0, pos, plen);
+       icv[0] = crc;
+       icv[1] = crc >> 8;
+       icv[2] = crc >> 16;
+       icv[3] = crc >> 24;
+       if (memcmp(icv, pos + plen, 4) != 0) {
+               /* ICV mismatch - drop frame */
+               return -2;
+       }
+
+       /* Remove IV and ICV */
+       memmove(skb->data + 4, skb->data, hdr_len);
+       skb_pull(skb, 4);
+       skb_trim(skb, skb->len - 4);
+
+       return 0;
+}
+
+static int prism2_wep_set_key(void *key, int len, u8 * seq, void *priv)
+{
+       struct prism2_wep_data *wep = priv;
+
+       if (len < 0 || len > WEP_KEY_LEN)
+               return -1;
+
+       memcpy(wep->key, key, len);
+       wep->key_len = len;
+
+       return 0;
+}
+
+static int prism2_wep_get_key(void *key, int len, u8 * seq, void *priv)
+{
+       struct prism2_wep_data *wep = priv;
+
+       if (len < wep->key_len)
+               return -1;
+
+       memcpy(key, wep->key, wep->key_len);
+
+       return wep->key_len;
+}
+
+static char *prism2_wep_print_stats(char *p, void *priv)
+{
+       struct prism2_wep_data *wep = priv;
+       p += sprintf(p, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len);
+       return p;
+}
+
+static struct ieee80211_crypto_ops ieee80211_crypt_wep = {
+       .name                   = "WEP",
+       .init                   = prism2_wep_init,
+       .deinit                 = prism2_wep_deinit,
+       .encrypt_mpdu           = prism2_wep_encrypt,
+       .decrypt_mpdu           = prism2_wep_decrypt,
+       .encrypt_msdu           = NULL,
+       .decrypt_msdu           = NULL,
+       .set_key                = prism2_wep_set_key,
+       .get_key                = prism2_wep_get_key,
+       .print_stats            = prism2_wep_print_stats,
+       .extra_prefix_len       = 4,    /* IV */
+       .extra_postfix_len      = 4,    /* ICV */
+       .owner                  = THIS_MODULE,
+};
+
+static int __init ieee80211_crypto_wep_init(void)
+{
+       return ieee80211_register_crypto_ops(&ieee80211_crypt_wep);
+}
+
+static void __exit ieee80211_crypto_wep_exit(void)
+{
+       ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep);
+}
+
+module_init(ieee80211_crypto_wep_init);
+module_exit(ieee80211_crypto_wep_exit);
diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c
new file mode 100644 (file)
index 0000000..03a4734
--- /dev/null
@@ -0,0 +1,297 @@
+/*******************************************************************************
+
+  Copyright(c) 2004 Intel Corporation. All rights reserved.
+
+  Portions of this file are based on the WEP enablement code provided by the
+  Host AP project hostap-drivers v0.1.3
+  Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+  <jkmaline@cc.hut.fi>
+  Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+
+  Contact Information:
+  James P. Ketrenos <ipw2100-admin@linux.intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/compiler.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/in6.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/wireless.h>
+#include <linux/etherdevice.h>
+#include <asm/uaccess.h>
+#include <net/arp.h>
+
+#include <net/ieee80211.h>
+
+MODULE_DESCRIPTION("802.11 data/management/control stack");
+MODULE_AUTHOR
+    ("Copyright (C) 2004 Intel Corporation <jketreno@linux.intel.com>");
+MODULE_LICENSE("GPL");
+
+#define DRV_NAME "ieee80211"
+
+static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee)
+{
+       if (ieee->networks)
+               return 0;
+
+       ieee->networks =
+           kmalloc(MAX_NETWORK_COUNT * sizeof(struct ieee80211_network),
+                   GFP_KERNEL);
+       if (!ieee->networks) {
+               printk(KERN_WARNING "%s: Out of memory allocating beacons\n",
+                      ieee->dev->name);
+               return -ENOMEM;
+       }
+
+       memset(ieee->networks, 0,
+              MAX_NETWORK_COUNT * sizeof(struct ieee80211_network));
+
+       return 0;
+}
+
+static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
+{
+       if (!ieee->networks)
+               return;
+       kfree(ieee->networks);
+       ieee->networks = NULL;
+}
+
+static inline void ieee80211_networks_initialize(struct ieee80211_device *ieee)
+{
+       int i;
+
+       INIT_LIST_HEAD(&ieee->network_free_list);
+       INIT_LIST_HEAD(&ieee->network_list);
+       for (i = 0; i < MAX_NETWORK_COUNT; i++)
+               list_add_tail(&ieee->networks[i].list,
+                             &ieee->network_free_list);
+}
+
+struct net_device *alloc_ieee80211(int sizeof_priv)
+{
+       struct ieee80211_device *ieee;
+       struct net_device *dev;
+       int err;
+
+       IEEE80211_DEBUG_INFO("Initializing...\n");
+
+       dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv);
+       if (!dev) {
+               IEEE80211_ERROR("Unable to network device.\n");
+               goto failed;
+       }
+       ieee = netdev_priv(dev);
+       dev->hard_start_xmit = ieee80211_xmit;
+
+       ieee->dev = dev;
+
+       err = ieee80211_networks_allocate(ieee);
+       if (err) {
+               IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err);
+               goto failed;
+       }
+       ieee80211_networks_initialize(ieee);
+
+       /* Default fragmentation threshold is maximum payload size */
+       ieee->fts = DEFAULT_FTS;
+       ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
+       ieee->open_wep = 1;
+
+       /* Default to enabling full open WEP with host based encrypt/decrypt */
+       ieee->host_encrypt = 1;
+       ieee->host_decrypt = 1;
+       ieee->ieee802_1x = 1;   /* Default to supporting 802.1x */
+
+       INIT_LIST_HEAD(&ieee->crypt_deinit_list);
+       init_timer(&ieee->crypt_deinit_timer);
+       ieee->crypt_deinit_timer.data = (unsigned long)ieee;
+       ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler;
+
+       spin_lock_init(&ieee->lock);
+
+       ieee->wpa_enabled = 0;
+       ieee->tkip_countermeasures = 0;
+       ieee->drop_unencrypted = 0;
+       ieee->privacy_invoked = 0;
+       ieee->ieee802_1x = 1;
+
+       return dev;
+
+      failed:
+       if (dev)
+               free_netdev(dev);
+       return NULL;
+}
+
+void free_ieee80211(struct net_device *dev)
+{
+       struct ieee80211_device *ieee = netdev_priv(dev);
+
+       int i;
+
+       del_timer_sync(&ieee->crypt_deinit_timer);
+       ieee80211_crypt_deinit_entries(ieee, 1);
+
+       for (i = 0; i < WEP_KEYS; i++) {
+               struct ieee80211_crypt_data *crypt = ieee->crypt[i];
+               if (crypt) {
+                       if (crypt->ops) {
+                               crypt->ops->deinit(crypt->priv);
+                               module_put(crypt->ops->owner);
+                       }
+                       kfree(crypt);
+                       ieee->crypt[i] = NULL;
+               }
+       }
+
+       ieee80211_networks_free(ieee);
+       free_netdev(dev);
+}
+
+#ifdef CONFIG_IEEE80211_DEBUG
+
+static int debug = 0;
+u32 ieee80211_debug_level = 0;
+struct proc_dir_entry *ieee80211_proc = NULL;
+
+static int show_debug_level(char *page, char **start, off_t offset,
+                           int count, int *eof, void *data)
+{
+       return snprintf(page, count, "0x%08X\n", ieee80211_debug_level);
+}
+
+static int store_debug_level(struct file *file, const char __user * buffer,
+                            unsigned long count, void *data)
+{
+       char buf[] = "0x00000000";
+       char *p = (char *)buf;
+       unsigned long val;
+
+       if (count > sizeof(buf) - 1)
+               count = sizeof(buf) - 1;
+
+       if (copy_from_user(buf, buffer, count))
+               return count;
+       buf[count] = 0;
+       /*
+        * what a FPOS...  What, sscanf(buf, "%i", &val) would be too
+        * scary?
+        */
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+               p++;
+               if (p[0] == 'x' || p[0] == 'X')
+                       p++;
+               val = simple_strtoul(p, &p, 16);
+       } else
+               val = simple_strtoul(p, &p, 10);
+       if (p == buf)
+               printk(KERN_INFO DRV_NAME
+                      ": %s is not in hex or decimal form.\n", buf);
+       else
+               ieee80211_debug_level = val;
+
+       return strlen(buf);
+}
+
+static int __init ieee80211_init(void)
+{
+       struct proc_dir_entry *e;
+
+       ieee80211_debug_level = debug;
+       ieee80211_proc = create_proc_entry(DRV_NAME, S_IFDIR, proc_net);
+       if (ieee80211_proc == NULL) {
+               IEEE80211_ERROR("Unable to create " DRV_NAME
+                               " proc directory\n");
+               return -EIO;
+       }
+       e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
+                             ieee80211_proc);
+       if (!e) {
+               remove_proc_entry(DRV_NAME, proc_net);
+               ieee80211_proc = NULL;
+               return -EIO;
+       }
+       e->read_proc = show_debug_level;
+       e->write_proc = store_debug_level;
+       e->data = NULL;
+
+       return 0;
+}
+
+static void __exit ieee80211_exit(void)
+{
+       if (ieee80211_proc) {
+               remove_proc_entry("debug_level", ieee80211_proc);
+               remove_proc_entry(DRV_NAME, proc_net);
+               ieee80211_proc = NULL;
+       }
+}
+
+#include <linux/moduleparam.h>
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "debug output mask");
+
+module_exit(ieee80211_exit);
+module_init(ieee80211_init);
+#endif
+
+const char *escape_essid(const char *essid, u8 essid_len)
+{
+       static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+       const char *s = essid;
+       char *d = escaped;
+
+       if (ieee80211_is_empty_essid(essid, essid_len)) {
+               memcpy(escaped, "<hidden>", sizeof("<hidden>"));
+               return escaped;
+       }
+
+       essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
+       while (essid_len--) {
+               if (*s == '\0') {
+                       *d++ = '\\';
+                       *d++ = '0';
+                       s++;
+               } else {
+                       *d++ = *s++;
+               }
+       }
+       *d = '\0';
+       return escaped;
+}
+
+EXPORT_SYMBOL(alloc_ieee80211);
+EXPORT_SYMBOL(free_ieee80211);
+EXPORT_SYMBOL(escape_essid);
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
new file mode 100644 (file)
index 0000000..f7dcd85
--- /dev/null
@@ -0,0 +1,1193 @@
+/*
+ * Original code based Host AP (software wireless LAN access point) driver
+ * for Intersil Prism2/2.5/3 - hostap.o module, common routines
+ *
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. See README and COPYING for
+ * more details.
+ */
+
+#include <linux/compiler.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/in6.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/wireless.h>
+#include <linux/etherdevice.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+
+#include <net/ieee80211.h>
+
+static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee,
+                                       struct sk_buff *skb,
+                                       struct ieee80211_rx_stats *rx_stats)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       u16 fc = le16_to_cpu(hdr->frame_ctl);
+
+       skb->dev = ieee->dev;
+       skb->mac.raw = skb->data;
+       skb_pull(skb, ieee80211_get_hdrlen(fc));
+       skb->pkt_type = PACKET_OTHERHOST;
+       skb->protocol = __constant_htons(ETH_P_80211_RAW);
+       memset(skb->cb, 0, sizeof(skb->cb));
+       netif_rx(skb);
+}
+
+/* Called only as a tasklet (software IRQ) */
+static struct ieee80211_frag_entry *ieee80211_frag_cache_find(struct
+                                                             ieee80211_device
+                                                             *ieee,
+                                                             unsigned int seq,
+                                                             unsigned int frag,
+                                                             u8 * src,
+                                                             u8 * dst)
+{
+       struct ieee80211_frag_entry *entry;
+       int i;
+
+       for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) {
+               entry = &ieee->frag_cache[i];
+               if (entry->skb != NULL &&
+                   time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
+                       IEEE80211_DEBUG_FRAG("expiring fragment cache entry "
+                                            "seq=%u last_frag=%u\n",
+                                            entry->seq, entry->last_frag);
+                       dev_kfree_skb_any(entry->skb);
+                       entry->skb = NULL;
+               }
+
+               if (entry->skb != NULL && entry->seq == seq &&
+                   (entry->last_frag + 1 == frag || frag == -1) &&
+                   memcmp(entry->src_addr, src, ETH_ALEN) == 0 &&
+                   memcmp(entry->dst_addr, dst, ETH_ALEN) == 0)
+                       return entry;
+       }
+
+       return NULL;
+}
+
+/* Called only as a tasklet (software IRQ) */
+static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee,
+                                               struct ieee80211_hdr *hdr)
+{
+       struct sk_buff *skb = NULL;
+       u16 sc;
+       unsigned int frag, seq;
+       struct ieee80211_frag_entry *entry;
+
+       sc = le16_to_cpu(hdr->seq_ctl);
+       frag = WLAN_GET_SEQ_FRAG(sc);
+       seq = WLAN_GET_SEQ_SEQ(sc);
+
+       if (frag == 0) {
+               /* Reserve enough space to fit maximum frame length */
+               skb = dev_alloc_skb(ieee->dev->mtu +
+                                   sizeof(struct ieee80211_hdr) +
+                                   8 /* LLC */  +
+                                   2 /* alignment */  +
+                                   8 /* WEP */  + ETH_ALEN /* WDS */ );
+               if (skb == NULL)
+                       return NULL;
+
+               entry = &ieee->frag_cache[ieee->frag_next_idx];
+               ieee->frag_next_idx++;
+               if (ieee->frag_next_idx >= IEEE80211_FRAG_CACHE_LEN)
+                       ieee->frag_next_idx = 0;
+
+               if (entry->skb != NULL)
+                       dev_kfree_skb_any(entry->skb);
+
+               entry->first_frag_time = jiffies;
+               entry->seq = seq;
+               entry->last_frag = frag;
+               entry->skb = skb;
+               memcpy(entry->src_addr, hdr->addr2, ETH_ALEN);
+               memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN);
+       } else {
+               /* received a fragment of a frame for which the head fragment
+                * should have already been received */
+               entry = ieee80211_frag_cache_find(ieee, seq, frag, hdr->addr2,
+                                                 hdr->addr1);
+               if (entry != NULL) {
+                       entry->last_frag = frag;
+                       skb = entry->skb;
+               }
+       }
+
+       return skb;
+}
+
+/* Called only as a tasklet (software IRQ) */
+static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee,
+                                          struct ieee80211_hdr *hdr)
+{
+       u16 sc;
+       unsigned int seq;
+       struct ieee80211_frag_entry *entry;
+
+       sc = le16_to_cpu(hdr->seq_ctl);
+       seq = WLAN_GET_SEQ_SEQ(sc);
+
+       entry = ieee80211_frag_cache_find(ieee, seq, -1, hdr->addr2,
+                                         hdr->addr1);
+
+       if (entry == NULL) {
+               IEEE80211_DEBUG_FRAG("could not invalidate fragment cache "
+                                    "entry (seq=%u)\n", seq);
+               return -1;
+       }
+
+       entry->skb = NULL;
+       return 0;
+}
+
+#ifdef NOT_YET
+/* ieee80211_rx_frame_mgtmt
+ *
+ * Responsible for handling management control frames
+ *
+ * Called by ieee80211_rx */
+static inline int
+ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb,
+                       struct ieee80211_rx_stats *rx_stats, u16 type,
+                       u16 stype)
+{
+       if (ieee->iw_mode == IW_MODE_MASTER) {
+               printk(KERN_DEBUG "%s: Master mode not yet suppported.\n",
+                      ieee->dev->name);
+               return 0;
+/*
+  hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr *)
+  skb->data);*/
+       }
+
+       if (ieee->hostapd && type == WLAN_FC_TYPE_MGMT) {
+               if (stype == WLAN_FC_STYPE_BEACON &&
+                   ieee->iw_mode == IW_MODE_MASTER) {
+                       struct sk_buff *skb2;
+                       /* Process beacon frames also in kernel driver to
+                        * update STA(AP) table statistics */
+                       skb2 = skb_clone(skb, GFP_ATOMIC);
+                       if (skb2)
+                               hostap_rx(skb2->dev, skb2, rx_stats);
+               }
+
+               /* send management frames to the user space daemon for
+                * processing */
+               ieee->apdevstats.rx_packets++;
+               ieee->apdevstats.rx_bytes += skb->len;
+               prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT);
+               return 0;
+       }
+
+       if (ieee->iw_mode == IW_MODE_MASTER) {
+               if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) {
+                       printk(KERN_DEBUG "%s: unknown management frame "
+                              "(type=0x%02x, stype=0x%02x) dropped\n",
+                              skb->dev->name, type, stype);
+                       return -1;
+               }
+
+               hostap_rx(skb->dev, skb, rx_stats);
+               return 0;
+       }
+
+       printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame "
+              "received in non-Host AP mode\n", skb->dev->name);
+       return -1;
+}
+#endif
+
+/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
+/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
+static unsigned char rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
+static unsigned char bridge_tunnel_header[] =
+    { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
+/* No encapsulation header if EtherType < 0x600 (=length) */
+
+/* Called by ieee80211_rx_frame_decrypt */
+static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee,
+                                   struct sk_buff *skb)
+{
+       struct net_device *dev = ieee->dev;
+       u16 fc, ethertype;
+       struct ieee80211_hdr *hdr;
+       u8 *pos;
+
+       if (skb->len < 24)
+               return 0;
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+       fc = le16_to_cpu(hdr->frame_ctl);
+
+       /* check that the frame is unicast frame to us */
+       if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+           IEEE80211_FCTL_TODS &&
+           memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 &&
+           memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) {
+               /* ToDS frame with own addr BSSID and DA */
+       } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+                  IEEE80211_FCTL_FROMDS &&
+                  memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) {
+               /* FromDS frame with own addr as DA */
+       } else
+               return 0;
+
+       if (skb->len < 24 + 8)
+               return 0;
+
+       /* check for port access entity Ethernet type */
+       pos = skb->data + 24;
+       ethertype = (pos[6] << 8) | pos[7];
+       if (ethertype == ETH_P_PAE)
+               return 1;
+
+       return 0;
+}
+
+/* Called only as a tasklet (software IRQ), by ieee80211_rx */
+static inline int
+ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb,
+                          struct ieee80211_crypt_data *crypt)
+{
+       struct ieee80211_hdr *hdr;
+       int res, hdrlen;
+
+       if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
+               return 0;
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+       hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+
+#ifdef CONFIG_IEEE80211_CRYPT_TKIP
+       if (ieee->tkip_countermeasures && strcmp(crypt->ops->name, "TKIP") == 0) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
+                              "received packet from " MAC_FMT "\n",
+                              ieee->dev->name, MAC_ARG(hdr->addr2));
+               }
+               return -1;
+       }
+#endif
+
+       atomic_inc(&crypt->refcnt);
+       res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
+       atomic_dec(&crypt->refcnt);
+       if (res < 0) {
+               IEEE80211_DEBUG_DROP("decryption failed (SA=" MAC_FMT
+                                    ") res=%d\n", MAC_ARG(hdr->addr2), res);
+               if (res == -2)
+                       IEEE80211_DEBUG_DROP("Decryption failed ICV "
+                                            "mismatch (key %d)\n",
+                                            skb->data[hdrlen + 3] >> 6);
+               ieee->ieee_stats.rx_discards_undecryptable++;
+               return -1;
+       }
+
+       return res;
+}
+
+/* Called only as a tasklet (software IRQ), by ieee80211_rx */
+static inline int
+ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee,
+                               struct sk_buff *skb, int keyidx,
+                               struct ieee80211_crypt_data *crypt)
+{
+       struct ieee80211_hdr *hdr;
+       int res, hdrlen;
+
+       if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
+               return 0;
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+       hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+
+       atomic_inc(&crypt->refcnt);
+       res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);
+       atomic_dec(&crypt->refcnt);
+       if (res < 0) {
+               printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
+                      " (SA=" MAC_FMT " keyidx=%d)\n",
+                      ieee->dev->name, MAC_ARG(hdr->addr2), keyidx);
+               return -1;
+       }
+
+       return 0;
+}
+
+/* All received frames are sent to this function. @skb contains the frame in
+ * IEEE 802.11 format, i.e., in the format it was sent over air.
+ * This function is called only as a tasklet (software IRQ). */
+int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
+                struct ieee80211_rx_stats *rx_stats)
+{
+       struct net_device *dev = ieee->dev;
+       struct ieee80211_hdr *hdr;
+       size_t hdrlen;
+       u16 fc, type, stype, sc;
+       struct net_device_stats *stats;
+       unsigned int frag;
+       u8 *payload;
+       u16 ethertype;
+#ifdef NOT_YET
+       struct net_device *wds = NULL;
+       struct sk_buff *skb2 = NULL;
+       struct net_device *wds = NULL;
+       int frame_authorized = 0;
+       int from_assoc_ap = 0;
+       void *sta = NULL;
+#endif
+       u8 dst[ETH_ALEN];
+       u8 src[ETH_ALEN];
+       struct ieee80211_crypt_data *crypt = NULL;
+       int keyidx = 0;
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+       stats = &ieee->stats;
+
+       if (skb->len < 10) {
+               printk(KERN_INFO "%s: SKB length < 10\n", dev->name);
+               goto rx_dropped;
+       }
+
+       fc = le16_to_cpu(hdr->frame_ctl);
+       type = WLAN_FC_GET_TYPE(fc);
+       stype = WLAN_FC_GET_STYPE(fc);
+       sc = le16_to_cpu(hdr->seq_ctl);
+       frag = WLAN_GET_SEQ_FRAG(sc);
+       hdrlen = ieee80211_get_hdrlen(fc);
+
+#ifdef NOT_YET
+#if WIRELESS_EXT > 15
+       /* Put this code here so that we avoid duplicating it in all
+        * Rx paths. - Jean II */
+#ifdef IW_WIRELESS_SPY         /* defined in iw_handler.h */
+       /* If spy monitoring on */
+       if (iface->spy_data.spy_number > 0) {
+               struct iw_quality wstats;
+               wstats.level = rx_stats->signal;
+               wstats.noise = rx_stats->noise;
+               wstats.updated = 6;     /* No qual value */
+               /* Update spy records */
+               wireless_spy_update(dev, hdr->addr2, &wstats);
+       }
+#endif                         /* IW_WIRELESS_SPY */
+#endif                         /* WIRELESS_EXT > 15 */
+       hostap_update_rx_stats(local->ap, hdr, rx_stats);
+#endif
+
+#if WIRELESS_EXT > 15
+       if (ieee->iw_mode == IW_MODE_MONITOR) {
+               ieee80211_monitor_rx(ieee, skb, rx_stats);
+               stats->rx_packets++;
+               stats->rx_bytes += skb->len;
+               return 1;
+       }
+#endif
+
+       if (ieee->host_decrypt) {
+               int idx = 0;
+               if (skb->len >= hdrlen + 3)
+                       idx = skb->data[hdrlen + 3] >> 6;
+               crypt = ieee->crypt[idx];
+#ifdef NOT_YET
+               sta = NULL;
+
+               /* Use station specific key to override default keys if the
+                * receiver address is a unicast address ("individual RA"). If
+                * bcrx_sta_key parameter is set, station specific key is used
+                * even with broad/multicast targets (this is against IEEE
+                * 802.11, but makes it easier to use different keys with
+                * stations that do not support WEP key mapping). */
+
+               if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key)
+                       (void)hostap_handle_sta_crypto(local, hdr, &crypt,
+                                                      &sta);
+#endif
+
+               /* allow NULL decrypt to indicate an station specific override
+                * for default encryption */
+               if (crypt && (crypt->ops == NULL ||
+                             crypt->ops->decrypt_mpdu == NULL))
+                       crypt = NULL;
+
+               if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) {
+                       /* This seems to be triggered by some (multicast?)
+                        * frames from other than current BSS, so just drop the
+                        * frames silently instead of filling system log with
+                        * these reports. */
+                       IEEE80211_DEBUG_DROP("Decryption failed (not set)"
+                                            " (SA=" MAC_FMT ")\n",
+                                            MAC_ARG(hdr->addr2));
+                       ieee->ieee_stats.rx_discards_undecryptable++;
+                       goto rx_dropped;
+               }
+       }
+#ifdef NOT_YET
+       if (type != WLAN_FC_TYPE_DATA) {
+               if (type == WLAN_FC_TYPE_MGMT && stype == WLAN_FC_STYPE_AUTH &&
+                   fc & IEEE80211_FCTL_PROTECTED && ieee->host_decrypt &&
+                   (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) {
+                       printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
+                              "from " MAC_FMT "\n", dev->name,
+                              MAC_ARG(hdr->addr2));
+                       /* TODO: could inform hostapd about this so that it
+                        * could send auth failure report */
+                       goto rx_dropped;
+               }
+
+               if (ieee80211_rx_frame_mgmt(ieee, skb, rx_stats, type, stype))
+                       goto rx_dropped;
+               else
+                       goto rx_exit;
+       }
+#endif
+
+       /* Data frame - extract src/dst addresses */
+       if (skb->len < IEEE80211_3ADDR_LEN)
+               goto rx_dropped;
+
+       switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
+       case IEEE80211_FCTL_FROMDS:
+               memcpy(dst, hdr->addr1, ETH_ALEN);
+               memcpy(src, hdr->addr3, ETH_ALEN);
+               break;
+       case IEEE80211_FCTL_TODS:
+               memcpy(dst, hdr->addr3, ETH_ALEN);
+               memcpy(src, hdr->addr2, ETH_ALEN);
+               break;
+       case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
+               if (skb->len < IEEE80211_4ADDR_LEN)
+                       goto rx_dropped;
+               memcpy(dst, hdr->addr3, ETH_ALEN);
+               memcpy(src, hdr->addr4, ETH_ALEN);
+               break;
+       case 0:
+               memcpy(dst, hdr->addr1, ETH_ALEN);
+               memcpy(src, hdr->addr2, ETH_ALEN);
+               break;
+       }
+
+#ifdef NOT_YET
+       if (hostap_rx_frame_wds(ieee, hdr, fc, &wds))
+               goto rx_dropped;
+       if (wds) {
+               skb->dev = dev = wds;
+               stats = hostap_get_stats(dev);
+       }
+
+       if (ieee->iw_mode == IW_MODE_MASTER && !wds &&
+           (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+           IEEE80211_FCTL_FROMDS && ieee->stadev
+           && memcmp(hdr->addr2, ieee->assoc_ap_addr, ETH_ALEN) == 0) {
+               /* Frame from BSSID of the AP for which we are a client */
+               skb->dev = dev = ieee->stadev;
+               stats = hostap_get_stats(dev);
+               from_assoc_ap = 1;
+       }
+#endif
+
+       dev->last_rx = jiffies;
+
+#ifdef NOT_YET
+       if ((ieee->iw_mode == IW_MODE_MASTER ||
+            ieee->iw_mode == IW_MODE_REPEAT) && !from_assoc_ap) {
+               switch (hostap_handle_sta_rx(ieee, dev, skb, rx_stats,
+                                            wds != NULL)) {
+               case AP_RX_CONTINUE_NOT_AUTHORIZED:
+                       frame_authorized = 0;
+                       break;
+               case AP_RX_CONTINUE:
+                       frame_authorized = 1;
+                       break;
+               case AP_RX_DROP:
+                       goto rx_dropped;
+               case AP_RX_EXIT:
+                       goto rx_exit;
+               }
+       }
+#endif
+
+       /* Nullfunc frames may have PS-bit set, so they must be passed to
+        * hostap_handle_sta_rx() before being dropped here. */
+       if (stype != IEEE80211_STYPE_DATA &&
+           stype != IEEE80211_STYPE_DATA_CFACK &&
+           stype != IEEE80211_STYPE_DATA_CFPOLL &&
+           stype != IEEE80211_STYPE_DATA_CFACKPOLL) {
+               if (stype != IEEE80211_STYPE_NULLFUNC)
+                       IEEE80211_DEBUG_DROP("RX: dropped data frame "
+                                            "with no data (type=0x%02x, "
+                                            "subtype=0x%02x, len=%d)\n",
+                                            type, stype, skb->len);
+               goto rx_dropped;
+       }
+
+       /* skb: hdr + (possibly fragmented, possibly encrypted) payload */
+
+       if (ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+           (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0)
+               goto rx_dropped;
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+
+       /* skb: hdr + (possibly fragmented) plaintext payload */
+       // PR: FIXME: hostap has additional conditions in the "if" below:
+       // ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+       if ((frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) {
+               int flen;
+               struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr);
+               IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag);
+
+               if (!frag_skb) {
+                       IEEE80211_DEBUG(IEEE80211_DL_RX | IEEE80211_DL_FRAG,
+                                       "Rx cannot get skb from fragment "
+                                       "cache (morefrag=%d seq=%u frag=%u)\n",
+                                       (fc & IEEE80211_FCTL_MOREFRAGS) != 0,
+                                       WLAN_GET_SEQ_SEQ(sc), frag);
+                       goto rx_dropped;
+               }
+
+               flen = skb->len;
+               if (frag != 0)
+                       flen -= hdrlen;
+
+               if (frag_skb->tail + flen > frag_skb->end) {
+                       printk(KERN_WARNING "%s: host decrypted and "
+                              "reassembled frame did not fit skb\n",
+                              dev->name);
+                       ieee80211_frag_cache_invalidate(ieee, hdr);
+                       goto rx_dropped;
+               }
+
+               if (frag == 0) {
+                       /* copy first fragment (including full headers) into
+                        * beginning of the fragment cache skb */
+                       memcpy(skb_put(frag_skb, flen), skb->data, flen);
+               } else {
+                       /* append frame payload to the end of the fragment
+                        * cache skb */
+                       memcpy(skb_put(frag_skb, flen), skb->data + hdrlen,
+                              flen);
+               }
+               dev_kfree_skb_any(skb);
+               skb = NULL;
+
+               if (fc & IEEE80211_FCTL_MOREFRAGS) {
+                       /* more fragments expected - leave the skb in fragment
+                        * cache for now; it will be delivered to upper layers
+                        * after all fragments have been received */
+                       goto rx_exit;
+               }
+
+               /* this was the last fragment and the frame will be
+                * delivered, so remove skb from fragment cache */
+               skb = frag_skb;
+               hdr = (struct ieee80211_hdr *)skb->data;
+               ieee80211_frag_cache_invalidate(ieee, hdr);
+       }
+
+       /* skb: hdr + (possible reassembled) full MSDU payload; possibly still
+        * encrypted/authenticated */
+       if (ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+           ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt))
+               goto rx_dropped;
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+       if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep) {
+               if (            /*ieee->ieee802_1x && */
+                          ieee80211_is_eapol_frame(ieee, skb)) {
+                       /* pass unencrypted EAPOL frames even if encryption is
+                        * configured */
+               } else {
+                       IEEE80211_DEBUG_DROP("encryption configured, but RX "
+                                            "frame not encrypted (SA=" MAC_FMT
+                                            ")\n", MAC_ARG(hdr->addr2));
+                       goto rx_dropped;
+               }
+       }
+
+       if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep &&
+           !ieee80211_is_eapol_frame(ieee, skb)) {
+               IEEE80211_DEBUG_DROP("dropped unencrypted RX data "
+                                    "frame from " MAC_FMT
+                                    " (drop_unencrypted=1)\n",
+                                    MAC_ARG(hdr->addr2));
+               goto rx_dropped;
+       }
+
+       /* skb: hdr + (possible reassembled) full plaintext payload */
+
+       payload = skb->data + hdrlen;
+       ethertype = (payload[6] << 8) | payload[7];
+
+#ifdef NOT_YET
+       /* If IEEE 802.1X is used, check whether the port is authorized to send
+        * the received frame. */
+       if (ieee->ieee802_1x && ieee->iw_mode == IW_MODE_MASTER) {
+               if (ethertype == ETH_P_PAE) {
+                       printk(KERN_DEBUG "%s: RX: IEEE 802.1X frame\n",
+                              dev->name);
+                       if (ieee->hostapd && ieee->apdev) {
+                               /* Send IEEE 802.1X frames to the user
+                                * space daemon for processing */
+                               prism2_rx_80211(ieee->apdev, skb, rx_stats,
+                                               PRISM2_RX_MGMT);
+                               ieee->apdevstats.rx_packets++;
+                               ieee->apdevstats.rx_bytes += skb->len;
+                               goto rx_exit;
+                       }
+               } else if (!frame_authorized) {
+                       printk(KERN_DEBUG "%s: dropped frame from "
+                              "unauthorized port (IEEE 802.1X): "
+                              "ethertype=0x%04x\n", dev->name, ethertype);
+                       goto rx_dropped;
+               }
+       }
+#endif
+
+       /* convert hdr + possible LLC headers into Ethernet header */
+       if (skb->len - hdrlen >= 8 &&
+           ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 &&
+             ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
+            memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) {
+               /* remove RFC1042 or Bridge-Tunnel encapsulation and
+                * replace EtherType */
+               skb_pull(skb, hdrlen + SNAP_SIZE);
+               memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
+               memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+       } else {
+               u16 len;
+               /* Leave Ethernet header part of hdr and full payload */
+               skb_pull(skb, hdrlen);
+               len = htons(skb->len);
+               memcpy(skb_push(skb, 2), &len, 2);
+               memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
+               memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+       }
+
+#ifdef NOT_YET
+       if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+                   IEEE80211_FCTL_TODS) && skb->len >= ETH_HLEN + ETH_ALEN) {
+               /* Non-standard frame: get addr4 from its bogus location after
+                * the payload */
+               memcpy(skb->data + ETH_ALEN,
+                      skb->data + skb->len - ETH_ALEN, ETH_ALEN);
+               skb_trim(skb, skb->len - ETH_ALEN);
+       }
+#endif
+
+       stats->rx_packets++;
+       stats->rx_bytes += skb->len;
+
+#ifdef NOT_YET
+       if (ieee->iw_mode == IW_MODE_MASTER && !wds && ieee->ap->bridge_packets) {
+               if (dst[0] & 0x01) {
+                       /* copy multicast frame both to the higher layers and
+                        * to the wireless media */
+                       ieee->ap->bridged_multicast++;
+                       skb2 = skb_clone(skb, GFP_ATOMIC);
+                       if (skb2 == NULL)
+                               printk(KERN_DEBUG "%s: skb_clone failed for "
+                                      "multicast frame\n", dev->name);
+               } else if (hostap_is_sta_assoc(ieee->ap, dst)) {
+                       /* send frame directly to the associated STA using
+                        * wireless media and not passing to higher layers */
+                       ieee->ap->bridged_unicast++;
+                       skb2 = skb;
+                       skb = NULL;
+               }
+       }
+
+       if (skb2 != NULL) {
+               /* send to wireless media */
+               skb2->protocol = __constant_htons(ETH_P_802_3);
+               skb2->mac.raw = skb2->nh.raw = skb2->data;
+               /* skb2->nh.raw = skb2->data + ETH_HLEN; */
+               skb2->dev = dev;
+               dev_queue_xmit(skb2);
+       }
+#endif
+
+       if (skb) {
+               skb->protocol = eth_type_trans(skb, dev);
+               memset(skb->cb, 0, sizeof(skb->cb));
+               skb->dev = dev;
+               skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */
+               netif_rx(skb);
+       }
+
+      rx_exit:
+#ifdef NOT_YET
+       if (sta)
+               hostap_handle_sta_release(sta);
+#endif
+       return 1;
+
+      rx_dropped:
+       stats->rx_dropped++;
+
+       /* Returning 0 indicates to caller that we have not handled the SKB--
+        * so it is still allocated and can be used again by underlying
+        * hardware as a DMA target */
+       return 0;
+}
+
+#define MGMT_FRAME_FIXED_PART_LENGTH           0x24
+
+static inline int ieee80211_is_ofdm_rate(u8 rate)
+{
+       switch (rate & ~IEEE80211_BASIC_RATE_MASK) {
+       case IEEE80211_OFDM_RATE_6MB:
+       case IEEE80211_OFDM_RATE_9MB:
+       case IEEE80211_OFDM_RATE_12MB:
+       case IEEE80211_OFDM_RATE_18MB:
+       case IEEE80211_OFDM_RATE_24MB:
+       case IEEE80211_OFDM_RATE_36MB:
+       case IEEE80211_OFDM_RATE_48MB:
+       case IEEE80211_OFDM_RATE_54MB:
+               return 1;
+       }
+       return 0;
+}
+
+static inline int ieee80211_network_init(struct ieee80211_device *ieee,
+                                        struct ieee80211_probe_response
+                                        *beacon,
+                                        struct ieee80211_network *network,
+                                        struct ieee80211_rx_stats *stats)
+{
+#ifdef CONFIG_IEEE80211_DEBUG
+       char rates_str[64];
+       char *p;
+#endif
+       struct ieee80211_info_element *info_element;
+       u16 left;
+       u8 i;
+
+       /* Pull out fixed field data */
+       memcpy(network->bssid, beacon->header.addr3, ETH_ALEN);
+       network->capability = beacon->capability;
+       network->last_scanned = jiffies;
+       network->time_stamp[0] = beacon->time_stamp[0];
+       network->time_stamp[1] = beacon->time_stamp[1];
+       network->beacon_interval = beacon->beacon_interval;
+       /* Where to pull this? beacon->listen_interval; */
+       network->listen_interval = 0x0A;
+       network->rates_len = network->rates_ex_len = 0;
+       network->last_associate = 0;
+       network->ssid_len = 0;
+       network->flags = 0;
+       network->atim_window = 0;
+
+       if (stats->freq == IEEE80211_52GHZ_BAND) {
+               /* for A band (No DS info) */
+               network->channel = stats->received_channel;
+       } else
+               network->flags |= NETWORK_HAS_CCK;
+
+       network->wpa_ie_len = 0;
+       network->rsn_ie_len = 0;
+
+       info_element = &beacon->info_element;
+       left = stats->len - ((void *)info_element - (void *)beacon);
+       while (left >= sizeof(struct ieee80211_info_element_hdr)) {
+               if (sizeof(struct ieee80211_info_element_hdr) +
+                   info_element->len > left) {
+                       IEEE80211_DEBUG_SCAN
+                           ("SCAN: parse failed: info_element->len + 2 > left : info_element->len+2=%Zd left=%d.\n",
+                            info_element->len +
+                            sizeof(struct ieee80211_info_element), left);
+                       return 1;
+               }
+
+               switch (info_element->id) {
+               case MFIE_TYPE_SSID:
+                       if (ieee80211_is_empty_essid(info_element->data,
+                                                    info_element->len)) {
+                               network->flags |= NETWORK_EMPTY_ESSID;
+                               break;
+                       }
+
+                       network->ssid_len = min(info_element->len,
+                                               (u8) IW_ESSID_MAX_SIZE);
+                       memcpy(network->ssid, info_element->data,
+                              network->ssid_len);
+                       if (network->ssid_len < IW_ESSID_MAX_SIZE)
+                               memset(network->ssid + network->ssid_len, 0,
+                                      IW_ESSID_MAX_SIZE - network->ssid_len);
+
+                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_SSID: '%s' len=%d.\n",
+                                            network->ssid, network->ssid_len);
+                       break;
+
+               case MFIE_TYPE_RATES:
+#ifdef CONFIG_IEEE80211_DEBUG
+                       p = rates_str;
+#endif
+                       network->rates_len =
+                           min(info_element->len, MAX_RATES_LENGTH);
+                       for (i = 0; i < network->rates_len; i++) {
+                               network->rates[i] = info_element->data[i];
+#ifdef CONFIG_IEEE80211_DEBUG
+                               p += snprintf(p,
+                                             sizeof(rates_str) - (p -
+                                                                  rates_str),
+                                             "%02X ", network->rates[i]);
+#endif
+                               if (ieee80211_is_ofdm_rate
+                                   (info_element->data[i])) {
+                                       network->flags |= NETWORK_HAS_OFDM;
+                                       if (info_element->data[i] &
+                                           IEEE80211_BASIC_RATE_MASK)
+                                               network->flags &=
+                                                   ~NETWORK_HAS_CCK;
+                               }
+                       }
+
+                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES: '%s' (%d)\n",
+                                            rates_str, network->rates_len);
+                       break;
+
+               case MFIE_TYPE_RATES_EX:
+#ifdef CONFIG_IEEE80211_DEBUG
+                       p = rates_str;
+#endif
+                       network->rates_ex_len =
+                           min(info_element->len, MAX_RATES_EX_LENGTH);
+                       for (i = 0; i < network->rates_ex_len; i++) {
+                               network->rates_ex[i] = info_element->data[i];
+#ifdef CONFIG_IEEE80211_DEBUG
+                               p += snprintf(p,
+                                             sizeof(rates_str) - (p -
+                                                                  rates_str),
+                                             "%02X ", network->rates[i]);
+#endif
+                               if (ieee80211_is_ofdm_rate
+                                   (info_element->data[i])) {
+                                       network->flags |= NETWORK_HAS_OFDM;
+                                       if (info_element->data[i] &
+                                           IEEE80211_BASIC_RATE_MASK)
+                                               network->flags &=
+                                                   ~NETWORK_HAS_CCK;
+                               }
+                       }
+
+                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES_EX: '%s' (%d)\n",
+                                            rates_str, network->rates_ex_len);
+                       break;
+
+               case MFIE_TYPE_DS_SET:
+                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_DS_SET: %d\n",
+                                            info_element->data[0]);
+                       if (stats->freq == IEEE80211_24GHZ_BAND)
+                               network->channel = info_element->data[0];
+                       break;
+
+               case MFIE_TYPE_FH_SET:
+                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_FH_SET: ignored\n");
+                       break;
+
+               case MFIE_TYPE_CF_SET:
+                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_CF_SET: ignored\n");
+                       break;
+
+               case MFIE_TYPE_TIM:
+                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_TIM: ignored\n");
+                       break;
+
+               case MFIE_TYPE_IBSS_SET:
+                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_IBSS_SET: ignored\n");
+                       break;
+
+               case MFIE_TYPE_CHALLENGE:
+                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_CHALLENGE: ignored\n");
+                       break;
+
+               case MFIE_TYPE_GENERIC:
+                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n",
+                                            info_element->len);
+                       if (info_element->len >= 4 &&
+                           info_element->data[0] == 0x00 &&
+                           info_element->data[1] == 0x50 &&
+                           info_element->data[2] == 0xf2 &&
+                           info_element->data[3] == 0x01) {
+                               network->wpa_ie_len = min(info_element->len + 2,
+                                                         MAX_WPA_IE_LEN);
+                               memcpy(network->wpa_ie, info_element,
+                                      network->wpa_ie_len);
+                       }
+                       break;
+
+               case MFIE_TYPE_RSN:
+                       IEEE80211_DEBUG_SCAN("MFIE_TYPE_RSN: %d bytes\n",
+                                            info_element->len);
+                       network->rsn_ie_len = min(info_element->len + 2,
+                                                 MAX_WPA_IE_LEN);
+                       memcpy(network->rsn_ie, info_element,
+                              network->rsn_ie_len);
+                       break;
+
+               default:
+                       IEEE80211_DEBUG_SCAN("unsupported IE %d\n",
+                                            info_element->id);
+                       break;
+               }
+
+               left -= sizeof(struct ieee80211_info_element_hdr) +
+                   info_element->len;
+               info_element = (struct ieee80211_info_element *)
+                   &info_element->data[info_element->len];
+       }
+
+       network->mode = 0;
+       if (stats->freq == IEEE80211_52GHZ_BAND)
+               network->mode = IEEE_A;
+       else {
+               if (network->flags & NETWORK_HAS_OFDM)
+                       network->mode |= IEEE_G;
+               if (network->flags & NETWORK_HAS_CCK)
+                       network->mode |= IEEE_B;
+       }
+
+       if (network->mode == 0) {
+               IEEE80211_DEBUG_SCAN("Filtered out '%s (" MAC_FMT ")' "
+                                    "network.\n",
+                                    escape_essid(network->ssid,
+                                                 network->ssid_len),
+                                    MAC_ARG(network->bssid));
+               return 1;
+       }
+
+       if (ieee80211_is_empty_essid(network->ssid, network->ssid_len))
+               network->flags |= NETWORK_EMPTY_ESSID;
+
+       memcpy(&network->stats, stats, sizeof(network->stats));
+
+       return 0;
+}
+
+static inline int is_same_network(struct ieee80211_network *src,
+                                 struct ieee80211_network *dst)
+{
+       /* A network is only a duplicate if the channel, BSSID, and ESSID
+        * all match.  We treat all <hidden> with the same BSSID and channel
+        * as one network */
+       return ((src->ssid_len == dst->ssid_len) &&
+               (src->channel == dst->channel) &&
+               !memcmp(src->bssid, dst->bssid, ETH_ALEN) &&
+               !memcmp(src->ssid, dst->ssid, src->ssid_len));
+}
+
+static inline void update_network(struct ieee80211_network *dst,
+                                 struct ieee80211_network *src)
+{
+       memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats));
+       dst->capability = src->capability;
+       memcpy(dst->rates, src->rates, src->rates_len);
+       dst->rates_len = src->rates_len;
+       memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len);
+       dst->rates_ex_len = src->rates_ex_len;
+
+       dst->mode = src->mode;
+       dst->flags = src->flags;
+       dst->time_stamp[0] = src->time_stamp[0];
+       dst->time_stamp[1] = src->time_stamp[1];
+
+       dst->beacon_interval = src->beacon_interval;
+       dst->listen_interval = src->listen_interval;
+       dst->atim_window = src->atim_window;
+
+       memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len);
+       dst->wpa_ie_len = src->wpa_ie_len;
+       memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len);
+       dst->rsn_ie_len = src->rsn_ie_len;
+
+       dst->last_scanned = jiffies;
+       /* dst->last_associate is not overwritten */
+}
+
+static inline void ieee80211_process_probe_response(struct ieee80211_device
+                                                   *ieee,
+                                                   struct
+                                                   ieee80211_probe_response
+                                                   *beacon,
+                                                   struct ieee80211_rx_stats
+                                                   *stats)
+{
+       struct ieee80211_network network;
+       struct ieee80211_network *target;
+       struct ieee80211_network *oldest = NULL;
+#ifdef CONFIG_IEEE80211_DEBUG
+       struct ieee80211_info_element *info_element = &beacon->info_element;
+#endif
+       unsigned long flags;
+
+       IEEE80211_DEBUG_SCAN("'%s' (" MAC_FMT
+                            "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
+                            escape_essid(info_element->data,
+                                         info_element->len),
+                            MAC_ARG(beacon->header.addr3),
+                            (beacon->capability & (1 << 0xf)) ? '1' : '0',
+                            (beacon->capability & (1 << 0xe)) ? '1' : '0',
+                            (beacon->capability & (1 << 0xd)) ? '1' : '0',
+                            (beacon->capability & (1 << 0xc)) ? '1' : '0',
+                            (beacon->capability & (1 << 0xb)) ? '1' : '0',
+                            (beacon->capability & (1 << 0xa)) ? '1' : '0',
+                            (beacon->capability & (1 << 0x9)) ? '1' : '0',
+                            (beacon->capability & (1 << 0x8)) ? '1' : '0',
+                            (beacon->capability & (1 << 0x7)) ? '1' : '0',
+                            (beacon->capability & (1 << 0x6)) ? '1' : '0',
+                            (beacon->capability & (1 << 0x5)) ? '1' : '0',
+                            (beacon->capability & (1 << 0x4)) ? '1' : '0',
+                            (beacon->capability & (1 << 0x3)) ? '1' : '0',
+                            (beacon->capability & (1 << 0x2)) ? '1' : '0',
+                            (beacon->capability & (1 << 0x1)) ? '1' : '0',
+                            (beacon->capability & (1 << 0x0)) ? '1' : '0');
+
+       if (ieee80211_network_init(ieee, beacon, &network, stats)) {
+               IEEE80211_DEBUG_SCAN("Dropped '%s' (" MAC_FMT ") via %s.\n",
+                                    escape_essid(info_element->data,
+                                                 info_element->len),
+                                    MAC_ARG(beacon->header.addr3),
+                                    WLAN_FC_GET_STYPE(beacon->header.
+                                                      frame_ctl) ==
+                                    IEEE80211_STYPE_PROBE_RESP ?
+                                    "PROBE RESPONSE" : "BEACON");
+               return;
+       }
+
+       /* The network parsed correctly -- so now we scan our known networks
+        * to see if we can find it in our list.
+        *
+        * NOTE:  This search is definitely not optimized.  Once its doing
+        *        the "right thing" we'll optimize it for efficiency if
+        *        necessary */
+
+       /* Search for this entry in the list and update it if it is
+        * already there. */
+
+       spin_lock_irqsave(&ieee->lock, flags);
+
+       list_for_each_entry(target, &ieee->network_list, list) {
+               if (is_same_network(target, &network))
+                       break;
+
+               if ((oldest == NULL) ||
+                   (target->last_scanned < oldest->last_scanned))
+                       oldest = target;
+       }
+
+       /* If we didn't find a match, then get a new network slot to initialize
+        * with this beacon's information */
+       if (&target->list == &ieee->network_list) {
+               if (list_empty(&ieee->network_free_list)) {
+                       /* If there are no more slots, expire the oldest */
+                       list_del(&oldest->list);
+                       target = oldest;
+                       IEEE80211_DEBUG_SCAN("Expired '%s' (" MAC_FMT ") from "
+                                            "network list.\n",
+                                            escape_essid(target->ssid,
+                                                         target->ssid_len),
+                                            MAC_ARG(target->bssid));
+               } else {
+                       /* Otherwise just pull from the free list */
+                       target = list_entry(ieee->network_free_list.next,
+                                           struct ieee80211_network, list);
+                       list_del(ieee->network_free_list.next);
+               }
+
+#ifdef CONFIG_IEEE80211_DEBUG
+               IEEE80211_DEBUG_SCAN("Adding '%s' (" MAC_FMT ") via %s.\n",
+                                    escape_essid(network.ssid,
+                                                 network.ssid_len),
+                                    MAC_ARG(network.bssid),
+                                    WLAN_FC_GET_STYPE(beacon->header.
+                                                      frame_ctl) ==
+                                    IEEE80211_STYPE_PROBE_RESP ?
+                                    "PROBE RESPONSE" : "BEACON");
+#endif
+               memcpy(target, &network, sizeof(*target));
+               list_add_tail(&target->list, &ieee->network_list);
+       } else {
+               IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n",
+                                    escape_essid(target->ssid,
+                                                 target->ssid_len),
+                                    MAC_ARG(target->bssid),
+                                    WLAN_FC_GET_STYPE(beacon->header.
+                                                      frame_ctl) ==
+                                    IEEE80211_STYPE_PROBE_RESP ?
+                                    "PROBE RESPONSE" : "BEACON");
+               update_network(target, &network);
+       }
+
+       spin_unlock_irqrestore(&ieee->lock, flags);
+}
+
+void ieee80211_rx_mgt(struct ieee80211_device *ieee,
+                     struct ieee80211_hdr *header,
+                     struct ieee80211_rx_stats *stats)
+{
+       switch (WLAN_FC_GET_STYPE(header->frame_ctl)) {
+       case IEEE80211_STYPE_ASSOC_RESP:
+               IEEE80211_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n",
+                                    WLAN_FC_GET_STYPE(header->frame_ctl));
+               break;
+
+       case IEEE80211_STYPE_REASSOC_RESP:
+               IEEE80211_DEBUG_MGMT("received REASSOCIATION RESPONSE (%d)\n",
+                                    WLAN_FC_GET_STYPE(header->frame_ctl));
+               break;
+
+       case IEEE80211_STYPE_PROBE_RESP:
+               IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n",
+                                    WLAN_FC_GET_STYPE(header->frame_ctl));
+               IEEE80211_DEBUG_SCAN("Probe response\n");
+               ieee80211_process_probe_response(ieee,
+                                                (struct
+                                                 ieee80211_probe_response *)
+                                                header, stats);
+               break;
+
+       case IEEE80211_STYPE_BEACON:
+               IEEE80211_DEBUG_MGMT("received BEACON (%d)\n",
+                                    WLAN_FC_GET_STYPE(header->frame_ctl));
+               IEEE80211_DEBUG_SCAN("Beacon\n");
+               ieee80211_process_probe_response(ieee,
+                                                (struct
+                                                 ieee80211_probe_response *)
+                                                header, stats);
+               break;
+
+       default:
+               IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n",
+                                    WLAN_FC_GET_STYPE(header->frame_ctl));
+               IEEE80211_WARNING("%s: Unknown management packet: %d\n",
+                                 ieee->dev->name,
+                                 WLAN_FC_GET_STYPE(header->frame_ctl));
+               break;
+       }
+}
+
+EXPORT_SYMBOL(ieee80211_rx_mgt);
+EXPORT_SYMBOL(ieee80211_rx);
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
new file mode 100644 (file)
index 0000000..c9aaff3
--- /dev/null
@@ -0,0 +1,428 @@
+/******************************************************************************
+
+  Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+
+  Contact Information:
+  James P. Ketrenos <ipw2100-admin@linux.intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+******************************************************************************/
+#include <linux/compiler.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/in6.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/wireless.h>
+#include <linux/etherdevice.h>
+#include <asm/uaccess.h>
+
+#include <net/ieee80211.h>
+
+/*
+
+802.11 Data Frame
+
+      ,-------------------------------------------------------------------.
+Bytes |  2   |  2   |    6    |    6    |    6    |  2   | 0..2312 |   4  |
+      |------|------|---------|---------|---------|------|---------|------|
+Desc. | ctrl | dura |  DA/RA  |   TA    |    SA   | Sequ |  Frame  |  fcs |
+      |      | tion | (BSSID) |         |         | ence |  data   |      |
+      `--------------------------------------------------|         |------'
+Total: 28 non-data bytes                                 `----.----'
+                                                              |
+       .- 'Frame data' expands to <---------------------------'
+       |
+       V
+      ,---------------------------------------------------.
+Bytes |  1   |  1   |    1    |    3     |  2   |  0-2304 |
+      |------|------|---------|----------|------|---------|
+Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP      |
+      | DSAP | SSAP |         |          |      | Packet  |
+      | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8|      |         |
+      `-----------------------------------------|         |
+Total: 8 non-data bytes                         `----.----'
+                                                     |
+       .- 'IP Packet' expands, if WEP enabled, to <--'
+       |
+       V
+      ,-----------------------.
+Bytes |  4  |   0-2296  |  4  |
+      |-----|-----------|-----|
+Desc. | IV  | Encrypted | ICV |
+      |     | IP Packet |     |
+      `-----------------------'
+Total: 8 non-data bytes
+
+802.3 Ethernet Data Frame
+
+      ,-----------------------------------------.
+Bytes |   6   |   6   |  2   |  Variable |   4  |
+      |-------|-------|------|-----------|------|
+Desc. | Dest. | Source| Type | IP Packet |  fcs |
+      |  MAC  |  MAC  |      |           |      |
+      `-----------------------------------------'
+Total: 18 non-data bytes
+
+In the event that fragmentation is required, the incoming payload is split into
+N parts of size ieee->fts.  The first fragment contains the SNAP header and the
+remaining packets are just data.
+
+If encryption is enabled, each fragment payload size is reduced by enough space
+to add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP)
+So if you have 1500 bytes of payload with ieee->fts set to 500 without
+encryption it will take 3 frames.  With WEP it will take 4 frames as the
+payload of each frame is reduced to 492 bytes.
+
+* SKB visualization
+*
+*  ,- skb->data
+* |
+* |    ETHERNET HEADER        ,-<-- PAYLOAD
+* |                           |     14 bytes from skb->data
+* |  2 bytes for Type --> ,T. |     (sizeof ethhdr)
+* |                       | | |
+* |,-Dest.--. ,--Src.---. | | |
+* |  6 bytes| | 6 bytes | | | |
+* v         | |         | | | |
+* 0         | v       1 | v | v           2
+* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+*     ^     | ^         | ^ |
+*     |     | |         | | |
+*     |     | |         | `T' <---- 2 bytes for Type
+*     |     | |         |
+*     |     | '---SNAP--' <-------- 6 bytes for SNAP
+*     |     |
+*     `-IV--' <-------------------- 4 bytes for IV (WEP)
+*
+*      SNAP HEADER
+*
+*/
+
+static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
+static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
+
+static inline int ieee80211_put_snap(u8 * data, u16 h_proto)
+{
+       struct ieee80211_snap_hdr *snap;
+       u8 *oui;
+
+       snap = (struct ieee80211_snap_hdr *)data;
+       snap->dsap = 0xaa;
+       snap->ssap = 0xaa;
+       snap->ctrl = 0x03;
+
+       if (h_proto == 0x8137 || h_proto == 0x80f3)
+               oui = P802_1H_OUI;
+       else
+               oui = RFC1042_OUI;
+       snap->oui[0] = oui[0];
+       snap->oui[1] = oui[1];
+       snap->oui[2] = oui[2];
+
+       *(u16 *) (data + SNAP_SIZE) = htons(h_proto);
+
+       return SNAP_SIZE + sizeof(u16);
+}
+
+static inline int ieee80211_encrypt_fragment(struct ieee80211_device *ieee,
+                                            struct sk_buff *frag, int hdr_len)
+{
+       struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx];
+       int res;
+
+#ifdef CONFIG_IEEE80211_CRYPT_TKIP
+       struct ieee80211_hdr *header;
+
+       if (ieee->tkip_countermeasures &&
+           crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) {
+               header = (struct ieee80211_hdr *)frag->data;
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
+                              "TX packet to " MAC_FMT "\n",
+                              ieee->dev->name, MAC_ARG(header->addr1));
+               }
+               return -1;
+       }
+#endif
+       /* To encrypt, frame format is:
+        * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */
+
+       // PR: FIXME: Copied from hostap. Check fragmentation/MSDU/MPDU encryption.
+       /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so
+        * call both MSDU and MPDU encryption functions from here. */
+       atomic_inc(&crypt->refcnt);
+       res = 0;
+       if (crypt->ops->encrypt_msdu)
+               res = crypt->ops->encrypt_msdu(frag, hdr_len, crypt->priv);
+       if (res == 0 && crypt->ops->encrypt_mpdu)
+               res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv);
+
+       atomic_dec(&crypt->refcnt);
+       if (res < 0) {
+               printk(KERN_INFO "%s: Encryption failed: len=%d.\n",
+                      ieee->dev->name, frag->len);
+               ieee->ieee_stats.tx_discards++;
+               return -1;
+       }
+
+       return 0;
+}
+
+void ieee80211_txb_free(struct ieee80211_txb *txb)
+{
+       int i;
+       if (unlikely(!txb))
+               return;
+       for (i = 0; i < txb->nr_frags; i++)
+               if (txb->fragments[i])
+                       dev_kfree_skb_any(txb->fragments[i]);
+       kfree(txb);
+}
+
+static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size,
+                                                int gfp_mask)
+{
+       struct ieee80211_txb *txb;
+       int i;
+       txb = kmalloc(sizeof(struct ieee80211_txb) + (sizeof(u8 *) * nr_frags),
+                     gfp_mask);
+       if (!txb)
+               return NULL;
+
+       memset(txb, 0, sizeof(struct ieee80211_txb));
+       txb->nr_frags = nr_frags;
+       txb->frag_size = txb_size;
+
+       for (i = 0; i < nr_frags; i++) {
+               txb->fragments[i] = dev_alloc_skb(txb_size);
+               if (unlikely(!txb->fragments[i])) {
+                       i--;
+                       break;
+               }
+       }
+       if (unlikely(i != nr_frags)) {
+               while (i >= 0)
+                       dev_kfree_skb_any(txb->fragments[i--]);
+               kfree(txb);
+               return NULL;
+       }
+       return txb;
+}
+
+/* SKBs are added to the ieee->tx_queue. */
+int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct ieee80211_device *ieee = netdev_priv(dev);
+       struct ieee80211_txb *txb = NULL;
+       struct ieee80211_hdr *frag_hdr;
+       int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size;
+       unsigned long flags;
+       struct net_device_stats *stats = &ieee->stats;
+       int ether_type, encrypt;
+       int bytes, fc, hdr_len;
+       struct sk_buff *skb_frag;
+       struct ieee80211_hdr header = { /* Ensure zero initialized */
+               .duration_id = 0,
+               .seq_ctl = 0
+       };
+       u8 dest[ETH_ALEN], src[ETH_ALEN];
+
+       struct ieee80211_crypt_data *crypt;
+
+       spin_lock_irqsave(&ieee->lock, flags);
+
+       /* If there is no driver handler to take the TXB, dont' bother
+        * creating it... */
+       if (!ieee->hard_start_xmit) {
+               printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name);
+               goto success;
+       }
+
+       if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) {
+               printk(KERN_WARNING "%s: skb too small (%d).\n",
+                      ieee->dev->name, skb->len);
+               goto success;
+       }
+
+       ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto);
+
+       crypt = ieee->crypt[ieee->tx_keyidx];
+
+       encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) &&
+           ieee->host_encrypt && crypt && crypt->ops;
+
+       if (!encrypt && ieee->ieee802_1x &&
+           ieee->drop_unencrypted && ether_type != ETH_P_PAE) {
+               stats->tx_dropped++;
+               goto success;
+       }
+
+       /* Save source and destination addresses */
+       memcpy(&dest, skb->data, ETH_ALEN);
+       memcpy(&src, skb->data + ETH_ALEN, ETH_ALEN);
+
+       /* Advance the SKB to the start of the payload */
+       skb_pull(skb, sizeof(struct ethhdr));
+
+       /* Determine total amount of storage required for TXB packets */
+       bytes = skb->len + SNAP_SIZE + sizeof(u16);
+
+       if (encrypt)
+               fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
+                   IEEE80211_FCTL_PROTECTED;
+       else
+               fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
+
+       if (ieee->iw_mode == IW_MODE_INFRA) {
+               fc |= IEEE80211_FCTL_TODS;
+               /* To DS: Addr1 = BSSID, Addr2 = SA,
+                  Addr3 = DA */
+               memcpy(&header.addr1, ieee->bssid, ETH_ALEN);
+               memcpy(&header.addr2, &src, ETH_ALEN);
+               memcpy(&header.addr3, &dest, ETH_ALEN);
+       } else if (ieee->iw_mode == IW_MODE_ADHOC) {
+               /* not From/To DS: Addr1 = DA, Addr2 = SA,
+                  Addr3 = BSSID */
+               memcpy(&header.addr1, dest, ETH_ALEN);
+               memcpy(&header.addr2, src, ETH_ALEN);
+               memcpy(&header.addr3, ieee->bssid, ETH_ALEN);
+       }
+       header.frame_ctl = cpu_to_le16(fc);
+       hdr_len = IEEE80211_3ADDR_LEN;
+
+       /* Determine fragmentation size based on destination (multicast
+        * and broadcast are not fragmented) */
+       if (is_multicast_ether_addr(dest) || is_broadcast_ether_addr(dest))
+               frag_size = MAX_FRAG_THRESHOLD;
+       else
+               frag_size = ieee->fts;
+
+       /* Determine amount of payload per fragment.  Regardless of if
+        * this stack is providing the full 802.11 header, one will
+        * eventually be affixed to this fragment -- so we must account for
+        * it when determining the amount of payload space. */
+       bytes_per_frag = frag_size - IEEE80211_3ADDR_LEN;
+       if (ieee->config &
+           (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
+               bytes_per_frag -= IEEE80211_FCS_LEN;
+
+       /* Each fragment may need to have room for encryptiong pre/postfix */
+       if (encrypt)
+               bytes_per_frag -= crypt->ops->extra_prefix_len +
+                   crypt->ops->extra_postfix_len;
+
+       /* Number of fragments is the total bytes_per_frag /
+        * payload_per_fragment */
+       nr_frags = bytes / bytes_per_frag;
+       bytes_last_frag = bytes % bytes_per_frag;
+       if (bytes_last_frag)
+               nr_frags++;
+       else
+               bytes_last_frag = bytes_per_frag;
+
+       /* When we allocate the TXB we allocate enough space for the reserve
+        * and full fragment bytes (bytes_per_frag doesn't include prefix,
+        * postfix, header, FCS, etc.) */
+       txb = ieee80211_alloc_txb(nr_frags, frag_size, GFP_ATOMIC);
+       if (unlikely(!txb)) {
+               printk(KERN_WARNING "%s: Could not allocate TXB\n",
+                      ieee->dev->name);
+               goto failed;
+       }
+       txb->encrypted = encrypt;
+       txb->payload_size = bytes;
+
+       for (i = 0; i < nr_frags; i++) {
+               skb_frag = txb->fragments[i];
+
+               if (encrypt)
+                       skb_reserve(skb_frag, crypt->ops->extra_prefix_len);
+
+               frag_hdr = (struct ieee80211_hdr *)skb_put(skb_frag, hdr_len);
+               memcpy(frag_hdr, &header, hdr_len);
+
+               /* If this is not the last fragment, then add the MOREFRAGS
+                * bit to the frame control */
+               if (i != nr_frags - 1) {
+                       frag_hdr->frame_ctl =
+                           cpu_to_le16(fc | IEEE80211_FCTL_MOREFRAGS);
+                       bytes = bytes_per_frag;
+               } else {
+                       /* The last fragment takes the remaining length */
+                       bytes = bytes_last_frag;
+               }
+
+               /* Put a SNAP header on the first fragment */
+               if (i == 0) {
+                       ieee80211_put_snap(skb_put
+                                          (skb_frag, SNAP_SIZE + sizeof(u16)),
+                                          ether_type);
+                       bytes -= SNAP_SIZE + sizeof(u16);
+               }
+
+               memcpy(skb_put(skb_frag, bytes), skb->data, bytes);
+
+               /* Advance the SKB... */
+               skb_pull(skb, bytes);
+
+               /* Encryption routine will move the header forward in order
+                * to insert the IV between the header and the payload */
+               if (encrypt)
+                       ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
+               if (ieee->config &
+                   (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
+                       skb_put(skb_frag, 4);
+       }
+
+      success:
+       spin_unlock_irqrestore(&ieee->lock, flags);
+
+       dev_kfree_skb_any(skb);
+
+       if (txb) {
+               if ((*ieee->hard_start_xmit) (txb, dev) == 0) {
+                       stats->tx_packets++;
+                       stats->tx_bytes += txb->payload_size;
+                       return 0;
+               }
+               ieee80211_txb_free(txb);
+       }
+
+       return 0;
+
+      failed:
+       spin_unlock_irqrestore(&ieee->lock, flags);
+       netif_stop_queue(dev);
+       stats->tx_errors++;
+       return 1;
+
+}
+
+EXPORT_SYMBOL(ieee80211_txb_free);
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
new file mode 100644 (file)
index 0000000..94882f3
--- /dev/null
@@ -0,0 +1,468 @@
+/******************************************************************************
+
+  Copyright(c) 2004 Intel Corporation. All rights reserved.
+
+  Portions of this file are based on the WEP enablement code provided by the
+  Host AP project hostap-drivers v0.1.3
+  Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+  <jkmaline@cc.hut.fi>
+  Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+
+  Contact Information:
+  James P. Ketrenos <ipw2100-admin@linux.intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+******************************************************************************/
+
+#include <linux/kmod.h>
+#include <linux/module.h>
+
+#include <net/ieee80211.h>
+#include <linux/wireless.h>
+
+static const char *ieee80211_modes[] = {
+       "?", "a", "b", "ab", "g", "ag", "bg", "abg"
+};
+
+#define MAX_CUSTOM_LEN 64
+static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee,
+                                          char *start, char *stop,
+                                          struct ieee80211_network *network)
+{
+       char custom[MAX_CUSTOM_LEN];
+       char *p;
+       struct iw_event iwe;
+       int i, j;
+       u8 max_rate, rate;
+
+       /* First entry *MUST* be the AP MAC address */
+       iwe.cmd = SIOCGIWAP;
+       iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+       memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
+       start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN);
+
+       /* Remaining entries will be displayed in the order we provide them */
+
+       /* Add the ESSID */
+       iwe.cmd = SIOCGIWESSID;
+       iwe.u.data.flags = 1;
+       if (network->flags & NETWORK_EMPTY_ESSID) {
+               iwe.u.data.length = sizeof("<hidden>");
+               start = iwe_stream_add_point(start, stop, &iwe, "<hidden>");
+       } else {
+               iwe.u.data.length = min(network->ssid_len, (u8) 32);
+               start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
+       }
+
+       /* Add the protocol name */
+       iwe.cmd = SIOCGIWNAME;
+       snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
+                ieee80211_modes[network->mode]);
+       start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN);
+
+       /* Add mode */
+       iwe.cmd = SIOCGIWMODE;
+       if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
+               if (network->capability & WLAN_CAPABILITY_ESS)
+                       iwe.u.mode = IW_MODE_MASTER;
+               else
+                       iwe.u.mode = IW_MODE_ADHOC;
+
+               start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
+       }
+
+       /* Add frequency/channel */
+       iwe.cmd = SIOCGIWFREQ;
+/*     iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
+       iwe.u.freq.e = 3; */
+       iwe.u.freq.m = network->channel;
+       iwe.u.freq.e = 0;
+       iwe.u.freq.i = 0;
+       start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
+
+       /* Add encryption capability */
+       iwe.cmd = SIOCGIWENCODE;
+       if (network->capability & WLAN_CAPABILITY_PRIVACY)
+               iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+       else
+               iwe.u.data.flags = IW_ENCODE_DISABLED;
+       iwe.u.data.length = 0;
+       start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
+
+       /* Add basic and extended rates */
+       max_rate = 0;
+       p = custom;
+       p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
+       for (i = 0, j = 0; i < network->rates_len;) {
+               if (j < network->rates_ex_len &&
+                   ((network->rates_ex[j] & 0x7F) <
+                    (network->rates[i] & 0x7F)))
+                       rate = network->rates_ex[j++] & 0x7F;
+               else
+                       rate = network->rates[i++] & 0x7F;
+               if (rate > max_rate)
+                       max_rate = rate;
+               p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+                             "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
+       }
+       for (; j < network->rates_ex_len; j++) {
+               rate = network->rates_ex[j] & 0x7F;
+               p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+                             "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
+               if (rate > max_rate)
+                       max_rate = rate;
+       }
+
+       iwe.cmd = SIOCGIWRATE;
+       iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+       iwe.u.bitrate.value = max_rate * 500000;
+       start = iwe_stream_add_event(start, stop, &iwe, IW_EV_PARAM_LEN);
+
+       iwe.cmd = IWEVCUSTOM;
+       iwe.u.data.length = p - custom;
+       if (iwe.u.data.length)
+               start = iwe_stream_add_point(start, stop, &iwe, custom);
+
+       /* Add quality statistics */
+       /* TODO: Fix these values... */
+       iwe.cmd = IWEVQUAL;
+       iwe.u.qual.qual = network->stats.signal;
+       iwe.u.qual.level = network->stats.rssi;
+       iwe.u.qual.noise = network->stats.noise;
+       iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK;
+       if (!(network->stats.mask & IEEE80211_STATMASK_RSSI))
+               iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
+       if (!(network->stats.mask & IEEE80211_STATMASK_NOISE))
+               iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
+       if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL))
+               iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
+
+       start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
+
+       iwe.cmd = IWEVCUSTOM;
+       p = custom;
+
+       iwe.u.data.length = p - custom;
+       if (iwe.u.data.length)
+               start = iwe_stream_add_point(start, stop, &iwe, custom);
+
+       if (ieee->wpa_enabled && network->wpa_ie_len) {
+               char buf[MAX_WPA_IE_LEN * 2 + 30];
+
+               u8 *p = buf;
+               p += sprintf(p, "wpa_ie=");
+               for (i = 0; i < network->wpa_ie_len; i++) {
+                       p += sprintf(p, "%02x", network->wpa_ie[i]);
+               }
+
+               memset(&iwe, 0, sizeof(iwe));
+               iwe.cmd = IWEVCUSTOM;
+               iwe.u.data.length = strlen(buf);
+               start = iwe_stream_add_point(start, stop, &iwe, buf);
+       }
+
+       if (ieee->wpa_enabled && network->rsn_ie_len) {
+               char buf[MAX_WPA_IE_LEN * 2 + 30];
+
+               u8 *p = buf;
+               p += sprintf(p, "rsn_ie=");
+               for (i = 0; i < network->rsn_ie_len; i++) {
+                       p += sprintf(p, "%02x", network->rsn_ie[i]);
+               }
+
+               memset(&iwe, 0, sizeof(iwe));
+               iwe.cmd = IWEVCUSTOM;
+               iwe.u.data.length = strlen(buf);
+               start = iwe_stream_add_point(start, stop, &iwe, buf);
+       }
+
+       /* Add EXTRA: Age to display seconds since last beacon/probe response
+        * for given network. */
+       iwe.cmd = IWEVCUSTOM;
+       p = custom;
+       p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+                     " Last beacon: %lums ago",
+                     (jiffies - network->last_scanned) / (HZ / 100));
+       iwe.u.data.length = p - custom;
+       if (iwe.u.data.length)
+               start = iwe_stream_add_point(start, stop, &iwe, custom);
+
+       return start;
+}
+
+int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
+                         struct iw_request_info *info,
+                         union iwreq_data *wrqu, char *extra)
+{
+       struct ieee80211_network *network;
+       unsigned long flags;
+
+       char *ev = extra;
+       char *stop = ev + IW_SCAN_MAX_DATA;
+       int i = 0;
+
+       IEEE80211_DEBUG_WX("Getting scan\n");
+
+       spin_lock_irqsave(&ieee->lock, flags);
+
+       list_for_each_entry(network, &ieee->network_list, list) {
+               i++;
+               if (ieee->scan_age == 0 ||
+                   time_after(network->last_scanned + ieee->scan_age, jiffies))
+                       ev = ipw2100_translate_scan(ieee, ev, stop, network);
+               else
+                       IEEE80211_DEBUG_SCAN("Not showing network '%s ("
+                                            MAC_FMT ")' due to age (%lums).\n",
+                                            escape_essid(network->ssid,
+                                                         network->ssid_len),
+                                            MAC_ARG(network->bssid),
+                                            (jiffies -
+                                             network->last_scanned) / (HZ /
+                                                                       100));
+       }
+
+       spin_unlock_irqrestore(&ieee->lock, flags);
+
+       wrqu->data.length = ev - extra;
+       wrqu->data.flags = 0;
+
+       IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
+
+       return 0;
+}
+
+int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
+                           struct iw_request_info *info,
+                           union iwreq_data *wrqu, char *keybuf)
+{
+       struct iw_point *erq = &(wrqu->encoding);
+       struct net_device *dev = ieee->dev;
+       struct ieee80211_security sec = {
+               .flags = 0
+       };
+       int i, key, key_provided, len;
+       struct ieee80211_crypt_data **crypt;
+
+       IEEE80211_DEBUG_WX("SET_ENCODE\n");
+
+       key = erq->flags & IW_ENCODE_INDEX;
+       if (key) {
+               if (key > WEP_KEYS)
+                       return -EINVAL;
+               key--;
+               key_provided = 1;
+       } else {
+               key_provided = 0;
+               key = ieee->tx_keyidx;
+       }
+
+       IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
+                          "provided" : "default");
+
+       crypt = &ieee->crypt[key];
+
+       if (erq->flags & IW_ENCODE_DISABLED) {
+               if (key_provided && *crypt) {
+                       IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
+                                          key);
+                       ieee80211_crypt_delayed_deinit(ieee, crypt);
+               } else
+                       IEEE80211_DEBUG_WX("Disabling encryption.\n");
+
+               /* Check all the keys to see if any are still configured,
+                * and if no key index was provided, de-init them all */
+               for (i = 0; i < WEP_KEYS; i++) {
+                       if (ieee->crypt[i] != NULL) {
+                               if (key_provided)
+                                       break;
+                               ieee80211_crypt_delayed_deinit(ieee,
+                                                              &ieee->crypt[i]);
+                       }
+               }
+
+               if (i == WEP_KEYS) {
+                       sec.enabled = 0;
+                       sec.level = SEC_LEVEL_0;
+                       sec.flags |= SEC_ENABLED | SEC_LEVEL;
+               }
+
+               goto done;
+       }
+
+       sec.enabled = 1;
+       sec.flags |= SEC_ENABLED;
+
+       if (*crypt != NULL && (*crypt)->ops != NULL &&
+           strcmp((*crypt)->ops->name, "WEP") != 0) {
+               /* changing to use WEP; deinit previously used algorithm
+                * on this key */
+               ieee80211_crypt_delayed_deinit(ieee, crypt);
+       }
+
+       if (*crypt == NULL) {
+               struct ieee80211_crypt_data *new_crypt;
+
+               /* take WEP into use */
+               new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data),
+                                   GFP_KERNEL);
+               if (new_crypt == NULL)
+                       return -ENOMEM;
+               memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
+               new_crypt->ops = ieee80211_get_crypto_ops("WEP");
+               if (!new_crypt->ops) {
+                       request_module("ieee80211_crypt_wep");
+                       new_crypt->ops = ieee80211_get_crypto_ops("WEP");
+               }
+
+               if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
+                       new_crypt->priv = new_crypt->ops->init(key);
+
+               if (!new_crypt->ops || !new_crypt->priv) {
+                       kfree(new_crypt);
+                       new_crypt = NULL;
+
+                       printk(KERN_WARNING "%s: could not initialize WEP: "
+                              "load module ieee80211_crypt_wep\n", dev->name);
+                       return -EOPNOTSUPP;
+               }
+               *crypt = new_crypt;
+       }
+
+       /* If a new key was provided, set it up */
+       if (erq->length > 0) {
+               len = erq->length <= 5 ? 5 : 13;
+               memcpy(sec.keys[key], keybuf, erq->length);
+               if (len > erq->length)
+                       memset(sec.keys[key] + erq->length, 0,
+                              len - erq->length);
+               IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
+                                  key, escape_essid(sec.keys[key], len),
+                                  erq->length, len);
+               sec.key_sizes[key] = len;
+               (*crypt)->ops->set_key(sec.keys[key], len, NULL,
+                                      (*crypt)->priv);
+               sec.flags |= (1 << key);
+               /* This ensures a key will be activated if no key is
+                * explicitely set */
+               if (key == sec.active_key)
+                       sec.flags |= SEC_ACTIVE_KEY;
+       } else {
+               len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
+                                            NULL, (*crypt)->priv);
+               if (len == 0) {
+                       /* Set a default key of all 0 */
+                       IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
+                                          key);
+                       memset(sec.keys[key], 0, 13);
+                       (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
+                                              (*crypt)->priv);
+                       sec.key_sizes[key] = 13;
+                       sec.flags |= (1 << key);
+               }
+
+               /* No key data - just set the default TX key index */
+               if (key_provided) {
+                       IEEE80211_DEBUG_WX
+                           ("Setting key %d to default Tx key.\n", key);
+                       ieee->tx_keyidx = key;
+                       sec.active_key = key;
+                       sec.flags |= SEC_ACTIVE_KEY;
+               }
+       }
+
+      done:
+       ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
+       sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
+       sec.flags |= SEC_AUTH_MODE;
+       IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
+                          "OPEN" : "SHARED KEY");
+
+       /* For now we just support WEP, so only set that security level...
+        * TODO: When WPA is added this is one place that needs to change */
+       sec.flags |= SEC_LEVEL;
+       sec.level = SEC_LEVEL_1;        /* 40 and 104 bit WEP */
+
+       if (ieee->set_security)
+               ieee->set_security(dev, &sec);
+
+       /* Do not reset port if card is in Managed mode since resetting will
+        * generate new IEEE 802.11 authentication which may end up in looping
+        * with IEEE 802.1X.  If your hardware requires a reset after WEP
+        * configuration (for example... Prism2), implement the reset_port in
+        * the callbacks structures used to initialize the 802.11 stack. */
+       if (ieee->reset_on_keychange &&
+           ieee->iw_mode != IW_MODE_INFRA &&
+           ieee->reset_port && ieee->reset_port(dev)) {
+               printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
+                           struct iw_request_info *info,
+                           union iwreq_data *wrqu, char *keybuf)
+{
+       struct iw_point *erq = &(wrqu->encoding);
+       int len, key;
+       struct ieee80211_crypt_data *crypt;
+
+       IEEE80211_DEBUG_WX("GET_ENCODE\n");
+
+       key = erq->flags & IW_ENCODE_INDEX;
+       if (key) {
+               if (key > WEP_KEYS)
+                       return -EINVAL;
+               key--;
+       } else
+               key = ieee->tx_keyidx;
+
+       crypt = ieee->crypt[key];
+       erq->flags = key + 1;
+
+       if (crypt == NULL || crypt->ops == NULL) {
+               erq->length = 0;
+               erq->flags |= IW_ENCODE_DISABLED;
+               return 0;
+       }
+
+       if (strcmp(crypt->ops->name, "WEP") != 0) {
+               /* only WEP is supported with wireless extensions, so just
+                * report that encryption is used */
+               erq->length = 0;
+               erq->flags |= IW_ENCODE_ENABLED;
+               return 0;
+       }
+
+       len = crypt->ops->get_key(keybuf, WEP_KEY_LEN, NULL, crypt->priv);
+       erq->length = (len >= 0 ? len : 0);
+
+       erq->flags |= IW_ENCODE_ENABLED;
+
+       if (ieee->open_wep)
+               erq->flags |= IW_ENCODE_OPEN;
+       else
+               erq->flags |= IW_ENCODE_RESTRICTED;
+
+       return 0;
+}
+
+EXPORT_SYMBOL(ieee80211_wx_get_scan);
+EXPORT_SYMBOL(ieee80211_wx_set_encode);
+EXPORT_SYMBOL(ieee80211_wx_get_encode);
index 0b3d9f1d806952b35f9603fcd4dc0163bcfdcc53..e55136ae09f40708bbcdd50004abe97822ba0a71 100644 (file)
@@ -413,20 +413,19 @@ config INET_TUNNEL
          
          If unsure, say Y.
 
-config IP_TCPDIAG
-       tristate "IP: TCP socket monitoring interface"
+config INET_DIAG
+       tristate "INET: socket monitoring interface"
        default y
        ---help---
-         Support for TCP socket monitoring interface used by native Linux
-         tools such as ss. ss is included in iproute2, currently downloadable
-         at <http://developer.osdl.org/dev/iproute2>. If you want IPv6 support
-         and have selected IPv6 as a module, you need to build this as a
-         module too.
+         Support for INET (TCP, DCCP, etc) socket monitoring interface used by
+         native Linux tools such as ss. ss is included in iproute2, currently
+         downloadable at <http://developer.osdl.org/dev/iproute2>. 
          
          If unsure, say Y.
 
-config IP_TCPDIAG_IPV6
-       def_bool (IP_TCPDIAG=y && IPV6=y) || (IP_TCPDIAG=m && IPV6)
+config INET_TCP_DIAG
+       depends on INET_DIAG
+       def_tristate INET_DIAG
 
 config TCP_CONG_ADVANCED
        bool "TCP: advanced congestion control"
index 55dc6cca1e7bb865b445430786740d46ba1bfce9..f0435d00db6befe152f8afaf730d6bdf1b975d6b 100644 (file)
@@ -4,11 +4,12 @@
 
 obj-y     := route.o inetpeer.o protocol.o \
             ip_input.o ip_fragment.o ip_forward.o ip_options.o \
-            ip_output.o ip_sockglue.o \
+            ip_output.o ip_sockglue.o inet_hashtables.o \
+            inet_timewait_sock.o inet_connection_sock.o \
             tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \
             tcp_minisocks.o tcp_cong.o \
             datagram.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \
-            sysctl_net_ipv4.o fib_frontend.o fib_semantics.o
+            sysctl_net_ipv4.o fib_frontend.o fib_semantics.o netfilter.o
 
 obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o
 obj-$(CONFIG_IP_FIB_TRIE) += fib_trie.o
@@ -29,8 +30,9 @@ obj-$(CONFIG_IP_ROUTE_MULTIPATH_WRANDOM) += multipath_wrandom.o
 obj-$(CONFIG_IP_ROUTE_MULTIPATH_DRR) += multipath_drr.o
 obj-$(CONFIG_NETFILTER)        += netfilter/
 obj-$(CONFIG_IP_VS) += ipvs/
-obj-$(CONFIG_IP_TCPDIAG) += tcp_diag.o 
+obj-$(CONFIG_INET_DIAG) += inet_diag.o 
 obj-$(CONFIG_IP_ROUTE_MULTIPATH_CACHED) += multipath.o
+obj-$(CONFIG_INET_TCP_DIAG) += tcp_diag.o
 obj-$(CONFIG_TCP_CONG_BIC) += tcp_bic.o
 obj-$(CONFIG_TCP_CONG_WESTWOOD) += tcp_westwood.o
 obj-$(CONFIG_TCP_CONG_HSTCP) += tcp_highspeed.o
index 163ae4068b5f3acfb70c1434bfd0e82c94478cb4..bf147f8db399489260d2292409ba5749b1ef93e8 100644 (file)
@@ -99,6 +99,7 @@
 #include <net/arp.h>
 #include <net/route.h>
 #include <net/ip_fib.h>
+#include <net/inet_connection_sock.h>
 #include <net/tcp.h>
 #include <net/udp.h>
 #include <linux/skbuff.h>
 #include <linux/mroute.h>
 #endif
 
-DEFINE_SNMP_STAT(struct linux_mib, net_statistics);
-
-#ifdef INET_REFCNT_DEBUG
-atomic_t inet_sock_nr;
-#endif
+DEFINE_SNMP_STAT(struct linux_mib, net_statistics) __read_mostly;
 
 extern void ip_mc_drop_socket(struct sock *sk);
 
@@ -153,11 +150,7 @@ void inet_sock_destruct(struct sock *sk)
        if (inet->opt)
                kfree(inet->opt);
        dst_release(sk->sk_dst_cache);
-#ifdef INET_REFCNT_DEBUG
-       atomic_dec(&inet_sock_nr);
-       printk(KERN_DEBUG "INET socket %p released, %d are still alive\n",
-              sk, atomic_read(&inet_sock_nr));
-#endif
+       sk_refcnt_debug_dec(sk);
 }
 
 /*
@@ -210,7 +203,7 @@ int inet_listen(struct socket *sock, int backlog)
         * we can only allow the backlog to be adjusted.
         */
        if (old_state != TCP_LISTEN) {
-               err = tcp_listen_start(sk);
+               err = inet_csk_listen_start(sk, TCP_SYNQ_HSIZE);
                if (err)
                        goto out;
        }
@@ -235,12 +228,14 @@ static int inet_create(struct socket *sock, int protocol)
        struct proto *answer_prot;
        unsigned char answer_flags;
        char answer_no_check;
-       int err;
+       int try_loading_module = 0;
+       int err = -ESOCKTNOSUPPORT;
 
        sock->state = SS_UNCONNECTED;
 
        /* Look for the requested type/protocol pair. */
        answer = NULL;
+lookup_protocol:
        rcu_read_lock();
        list_for_each_rcu(p, &inetsw[sock->type]) {
                answer = list_entry(p, struct inet_protosw, list);
@@ -261,9 +256,28 @@ static int inet_create(struct socket *sock, int protocol)
                answer = NULL;
        }
 
-       err = -ESOCKTNOSUPPORT;
-       if (!answer)
-               goto out_rcu_unlock;
+       if (unlikely(answer == NULL)) {
+               if (try_loading_module < 2) {
+                       rcu_read_unlock();
+                       /*
+                        * Be more specific, e.g. net-pf-2-proto-132-type-1
+                        * (net-pf-PF_INET-proto-IPPROTO_SCTP-type-SOCK_STREAM)
+                        */
+                       if (++try_loading_module == 1)
+                               request_module("net-pf-%d-proto-%d-type-%d",
+                                              PF_INET, protocol, sock->type);
+                       /*
+                        * Fall back to generic, e.g. net-pf-2-proto-132
+                        * (net-pf-PF_INET-proto-IPPROTO_SCTP)
+                        */
+                       else
+                               request_module("net-pf-%d-proto-%d",
+                                              PF_INET, protocol);
+                       goto lookup_protocol;
+               } else
+                       goto out_rcu_unlock;
+       }
+
        err = -EPERM;
        if (answer->capability > 0 && !capable(answer->capability))
                goto out_rcu_unlock;
@@ -317,9 +331,7 @@ static int inet_create(struct socket *sock, int protocol)
        inet->mc_index  = 0;
        inet->mc_list   = NULL;
 
-#ifdef INET_REFCNT_DEBUG
-       atomic_inc(&inet_sock_nr);
-#endif
+       sk_refcnt_debug_inc(sk);
 
        if (inet->num) {
                /* It assumes that any protocol which allows
@@ -847,10 +859,6 @@ static struct net_proto_family inet_family_ops = {
        .owner  = THIS_MODULE,
 };
 
-
-extern void tcp_init(void);
-extern void tcp_v4_init(struct net_proto_family *);
-
 /* Upon startup we insert all the elements in inetsw_array[] into
  * the linked list inetsw.
  */
@@ -961,6 +969,119 @@ void inet_unregister_protosw(struct inet_protosw *p)
        }
 }
 
+/*
+ *      Shall we try to damage output packets if routing dev changes?
+ */
+
+int sysctl_ip_dynaddr;
+
+static int inet_sk_reselect_saddr(struct sock *sk)
+{
+       struct inet_sock *inet = inet_sk(sk);
+       int err;
+       struct rtable *rt;
+       __u32 old_saddr = inet->saddr;
+       __u32 new_saddr;
+       __u32 daddr = inet->daddr;
+
+       if (inet->opt && inet->opt->srr)
+               daddr = inet->opt->faddr;
+
+       /* Query new route. */
+       err = ip_route_connect(&rt, daddr, 0,
+                              RT_CONN_FLAGS(sk),
+                              sk->sk_bound_dev_if,
+                              sk->sk_protocol,
+                              inet->sport, inet->dport, sk);
+       if (err)
+               return err;
+
+       sk_setup_caps(sk, &rt->u.dst);
+
+       new_saddr = rt->rt_src;
+
+       if (new_saddr == old_saddr)
+               return 0;
+
+       if (sysctl_ip_dynaddr > 1) {
+               printk(KERN_INFO "%s(): shifting inet->"
+                                "saddr from %d.%d.%d.%d to %d.%d.%d.%d\n",
+                      __FUNCTION__,
+                      NIPQUAD(old_saddr),
+                      NIPQUAD(new_saddr));
+       }
+
+       inet->saddr = inet->rcv_saddr = new_saddr;
+
+       /*
+        * XXX The only one ugly spot where we need to
+        * XXX really change the sockets identity after
+        * XXX it has entered the hashes. -DaveM
+        *
+        * Besides that, it does not check for connection
+        * uniqueness. Wait for troubles.
+        */
+       __sk_prot_rehash(sk);
+       return 0;
+}
+
+int inet_sk_rebuild_header(struct sock *sk)
+{
+       struct inet_sock *inet = inet_sk(sk);
+       struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0);
+       u32 daddr;
+       int err;
+
+       /* Route is OK, nothing to do. */
+       if (rt)
+               return 0;
+
+       /* Reroute. */
+       daddr = inet->daddr;
+       if (inet->opt && inet->opt->srr)
+               daddr = inet->opt->faddr;
+{
+       struct flowi fl = {
+               .oif = sk->sk_bound_dev_if,
+               .nl_u = {
+                       .ip4_u = {
+                               .daddr  = daddr,
+                               .saddr  = inet->saddr,
+                               .tos    = RT_CONN_FLAGS(sk),
+                       },
+               },
+               .proto = sk->sk_protocol,
+               .uli_u = {
+                       .ports = {
+                               .sport = inet->sport,
+                               .dport = inet->dport,
+                       },
+               },
+       };
+                                               
+       err = ip_route_output_flow(&rt, &fl, sk, 0);
+}
+       if (!err)
+               sk_setup_caps(sk, &rt->u.dst);
+       else {
+               /* Routing failed... */
+               sk->sk_route_caps = 0;
+               /*
+                * Other protocols have to map its equivalent state to TCP_SYN_SENT.
+                * DCCP maps its DCCP_REQUESTING state to TCP_SYN_SENT. -acme
+                */
+               if (!sysctl_ip_dynaddr ||
+                   sk->sk_state != TCP_SYN_SENT ||
+                   (sk->sk_userlocks & SOCK_BINDADDR_LOCK) ||
+                   (err = inet_sk_reselect_saddr(sk)) != 0)
+                       sk->sk_err_soft = -err;
+       }
+
+       return err;
+}
+
+EXPORT_SYMBOL(inet_sk_rebuild_header);
+
 #ifdef CONFIG_IP_MULTICAST
 static struct net_protocol igmp_protocol = {
        .handler =      igmp_rcv,
@@ -1007,7 +1128,6 @@ static int __init init_ipv4_mibs(void)
 }
 
 static int ipv4_proc_init(void);
-extern void ipfrag_init(void);
 
 /*
  *     IP protocol layer initialiser
@@ -1128,19 +1248,10 @@ module_init(inet_init);
 /* ------------------------------------------------------------------------ */
 
 #ifdef CONFIG_PROC_FS
-extern int  fib_proc_init(void);
-extern void fib_proc_exit(void);
 #ifdef CONFIG_IP_FIB_TRIE
 extern int  fib_stat_proc_init(void);
 extern void fib_stat_proc_exit(void);
 #endif
-extern int  ip_misc_proc_init(void);
-extern int  raw_proc_init(void);
-extern void raw_proc_exit(void);
-extern int  tcp4_proc_init(void);
-extern void tcp4_proc_exit(void);
-extern int  udp4_proc_init(void);
-extern void udp4_proc_exit(void);
 
 static int __init ipv4_proc_init(void)
 {
@@ -1205,7 +1316,3 @@ EXPORT_SYMBOL(inet_stream_ops);
 EXPORT_SYMBOL(inet_unregister_protosw);
 EXPORT_SYMBOL(net_statistics);
 EXPORT_SYMBOL(sysctl_ip_nonlocal_bind);
-
-#ifdef INET_REFCNT_DEBUG
-EXPORT_SYMBOL(inet_sock_nr);
-#endif
index 514c85b2631a3332187141c2afdd7ed7825314cb..035ad2c9e1bad3cdc9fd1382004bfcca2da966eb 100644 (file)
@@ -263,10 +263,8 @@ static int ah_init_state(struct xfrm_state *x)
 
 error:
        if (ahp) {
-               if (ahp->work_icv)
-                       kfree(ahp->work_icv);
-               if (ahp->tfm)
-                       crypto_free_tfm(ahp->tfm);
+               kfree(ahp->work_icv);
+               crypto_free_tfm(ahp->tfm);
                kfree(ahp);
        }
        return -EINVAL;
@@ -279,14 +277,10 @@ static void ah_destroy(struct xfrm_state *x)
        if (!ahp)
                return;
 
-       if (ahp->work_icv) {
-               kfree(ahp->work_icv);
-               ahp->work_icv = NULL;
-       }
-       if (ahp->tfm) {
-               crypto_free_tfm(ahp->tfm);
-               ahp->tfm = NULL;
-       }
+       kfree(ahp->work_icv);
+       ahp->work_icv = NULL;
+       crypto_free_tfm(ahp->tfm);
+       ahp->tfm = NULL;
        kfree(ahp);
 }
 
index a642fd6128533810e96a159723f2c337fedb6dd9..8bf312bdea13c50f48291df5481affb6cfc10f4a 100644 (file)
@@ -700,7 +700,7 @@ void arp_send(int type, int ptype, u32 dest_ip,
 static void parp_redo(struct sk_buff *skb)
 {
        nf_reset(skb);
-       arp_rcv(skb, skb->dev, NULL);
+       arp_rcv(skb, skb->dev, NULL, skb->dev);
 }
 
 /*
@@ -865,7 +865,7 @@ static int arp_process(struct sk_buff *skb)
                                if (n)
                                        neigh_release(n);
 
-                               if (skb->stamp.tv_sec == LOCALLY_ENQUEUED || 
+                               if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED || 
                                    skb->pkt_type == PACKET_HOST ||
                                    in_dev->arp_parms->proxy_delay == 0) {
                                        arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
@@ -927,7 +927,7 @@ out:
  *     Receive an arp request from the device layer.
  */
 
-int arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
+int arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
 {
        struct arphdr *arp;
 
@@ -948,6 +948,8 @@ int arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
        if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
                goto out_of_mem;
 
+       memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
+
        return NF_HOOK(NF_ARP, NF_ARP_IN, skb, dev, NULL, arp_process);
 
 freeskb:
index b1db561f25423c3575a2e03ff56699fe5bba2c0e..c1b42b5257f8455d54c0388ac1ac25e76595b659 100644 (file)
 #include <linux/module.h>
 #include <linux/ip.h>
 #include <linux/in.h>
+#include <net/ip.h>
 #include <net/sock.h>
-#include <net/tcp.h>
 #include <net/route.h>
+#include <net/tcp_states.h>
 
 int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
index d8a10e3dd77d2090d3729ef39a41633bbe8fbda9..ba2895ae81514ab1aea769339876acce7bf6a76c 100644 (file)
@@ -1111,13 +1111,12 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa)
        struct sk_buff *skb = alloc_skb(size, GFP_KERNEL);
 
        if (!skb)
-               netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, ENOBUFS);
+               netlink_set_err(rtnl, 0, RTNLGRP_IPV4_IFADDR, ENOBUFS);
        else if (inet_fill_ifaddr(skb, ifa, current->pid, 0, event, 0) < 0) {
                kfree_skb(skb);
-               netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, EINVAL);
+               netlink_set_err(rtnl, 0, RTNLGRP_IPV4_IFADDR, EINVAL);
        } else {
-               NETLINK_CB(skb).dst_groups = RTMGRP_IPV4_IFADDR;
-               netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV4_IFADDR, GFP_KERNEL);
+               netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV4_IFADDR, GFP_KERNEL);
        }
 }
 
index ba57446d5d1f4a1831f926859dca12c40369067e..1b5a09d1b90b77ca26b03210e974746f7b316218 100644 (file)
@@ -331,8 +331,8 @@ static void esp4_err(struct sk_buff *skb, u32 info)
        x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET);
        if (!x)
                return;
-       NETDEBUG(printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%08x\n",
-                       ntohl(esph->spi), ntohl(iph->daddr)));
+       NETDEBUG(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%08x\n",
+                ntohl(esph->spi), ntohl(iph->daddr));
        xfrm_state_put(x);
 }
 
@@ -343,22 +343,14 @@ static void esp_destroy(struct xfrm_state *x)
        if (!esp)
                return;
 
-       if (esp->conf.tfm) {
-               crypto_free_tfm(esp->conf.tfm);
-               esp->conf.tfm = NULL;
-       }
-       if (esp->conf.ivec) {
-               kfree(esp->conf.ivec);
-               esp->conf.ivec = NULL;
-       }
-       if (esp->auth.tfm) {
-               crypto_free_tfm(esp->auth.tfm);
-               esp->auth.tfm = NULL;
-       }
-       if (esp->auth.work_icv) {
-               kfree(esp->auth.work_icv);
-               esp->auth.work_icv = NULL;
-       }
+       crypto_free_tfm(esp->conf.tfm);
+       esp->conf.tfm = NULL;
+       kfree(esp->conf.ivec);
+       esp->conf.ivec = NULL;
+       crypto_free_tfm(esp->auth.tfm);
+       esp->auth.tfm = NULL;
+       kfree(esp->auth.work_icv);
+       esp->auth.work_icv = NULL;
        kfree(esp);
 }
 
@@ -395,10 +387,10 @@ static int esp_init_state(struct xfrm_state *x)
 
                if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
                    crypto_tfm_alg_digestsize(esp->auth.tfm)) {
-                       NETDEBUG(printk(KERN_INFO "ESP: %s digestsize %u != %hu\n",
-                              x->aalg->alg_name,
-                              crypto_tfm_alg_digestsize(esp->auth.tfm),
-                              aalg_desc->uinfo.auth.icv_fullbits/8));
+                       NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n",
+                                x->aalg->alg_name,
+                                crypto_tfm_alg_digestsize(esp->auth.tfm),
+                                aalg_desc->uinfo.auth.icv_fullbits/8);
                        goto error;
                }
 
index cd8e45ab95807116a18fe1649422766ef636da3c..4e1379f712696e82be169fd4b69dde6456cee855 100644 (file)
@@ -558,16 +558,15 @@ static void nl_fib_input(struct sock *sk, int len)
        nl_fib_lookup(frn, tb);
        
        pid = nlh->nlmsg_pid;           /*pid of sending process */
-       NETLINK_CB(skb).groups = 0;     /* not in mcast group */
        NETLINK_CB(skb).pid = 0;         /* from kernel */
        NETLINK_CB(skb).dst_pid = pid;
-       NETLINK_CB(skb).dst_groups = 0;  /* unicast */
+       NETLINK_CB(skb).dst_group = 0;  /* unicast */
        netlink_unicast(sk, skb, pid, MSG_DONTWAIT);
 }    
 
 static void nl_fib_lookup_init(void)
 {
-      netlink_kernel_create(NETLINK_FIB_LOOKUP, nl_fib_input);
+      netlink_kernel_create(NETLINK_FIB_LOOKUP, 0, nl_fib_input, THIS_MODULE);
 }
 
 static void fib_disable_ip(struct net_device *dev, int force)
@@ -662,5 +661,4 @@ void __init ip_fib_init(void)
 }
 
 EXPORT_SYMBOL(inet_addr_type);
-EXPORT_SYMBOL(ip_dev_find);
 EXPORT_SYMBOL(ip_rt_ioctl);
index b10d6bb5ef3d67f5bc125243fda1a391f57460d2..2a8c9afc3695d88a673e2f35cba900d0aa63c409 100644 (file)
@@ -45,8 +45,8 @@
 
 #include "fib_lookup.h"
 
-static kmem_cache_t *fn_hash_kmem;
-static kmem_cache_t *fn_alias_kmem;
+static kmem_cache_t *fn_hash_kmem __read_mostly;
+static kmem_cache_t *fn_alias_kmem __read_mostly;
 
 struct fib_node {
        struct hlist_node       fn_hash;
index b729d97cfa9344655e1842530aeb55b5609f308e..ef6609ea0eb757e8b3daa8117f38e7837819d197 100644 (file)
@@ -7,6 +7,7 @@
 
 struct fib_alias {
        struct list_head        fa_list;
+       struct rcu_head rcu;
        struct fib_info         *fa_info;
        u8                      fa_tos;
        u8                      fa_type;
index e278cb9d00751a97a65424a2f9e5f34d7f7157f2..d41219e8037c7a9f8a9c69dc1bd720f36d357d0b 100644 (file)
@@ -290,10 +290,10 @@ void rtmsg_fib(int event, u32 key, struct fib_alias *fa,
                kfree_skb(skb);
                return;
        }
-       NETLINK_CB(skb).dst_groups = RTMGRP_IPV4_ROUTE;
+       NETLINK_CB(skb).dst_group = RTNLGRP_IPV4_ROUTE;
        if (n->nlmsg_flags&NLM_F_ECHO)
                atomic_inc(&skb->users);
-       netlink_broadcast(rtnl, skb, pid, RTMGRP_IPV4_ROUTE, GFP_KERNEL);
+       netlink_broadcast(rtnl, skb, pid, RTNLGRP_IPV4_ROUTE, GFP_KERNEL);
        if (n->nlmsg_flags&NLM_F_ECHO)
                netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT);
 }
@@ -854,6 +854,7 @@ failure:
        return NULL;
 }
 
+/* Note! fib_semantic_match intentionally uses  RCU list functions. */
 int fib_semantic_match(struct list_head *head, const struct flowi *flp,
                       struct fib_result *res, __u32 zone, __u32 mask, 
                        int prefixlen)
@@ -861,7 +862,7 @@ int fib_semantic_match(struct list_head *head, const struct flowi *flp,
        struct fib_alias *fa;
        int nh_sel = 0;
 
-       list_for_each_entry(fa, head, fa_list) {
+       list_for_each_entry_rcu(fa, head, fa_list) {
                int err;
 
                if (fa->fa_tos &&
index 45efd5f4741b93830d5ee7021cec57bd47c14aed..b2dea4e5da77cfe2f00bf09cfaa5a0ec0e171ed5 100644 (file)
@@ -43,7 +43,7 @@
  *             2 of the License, or (at your option) any later version.
  */
 
-#define VERSION "0.325"
+#define VERSION "0.402"
 
 #include <linux/config.h>
 #include <asm/uaccess.h>
@@ -62,6 +62,7 @@
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/proc_fs.h>
+#include <linux/rcupdate.h>
 #include <linux/skbuff.h>
 #include <linux/netlink.h>
 #include <linux/init.h>
 #undef CONFIG_IP_FIB_TRIE_STATS
 #define MAX_CHILDS 16384
 
-#define EXTRACT(p, n, str) ((str)<<(p)>>(32-(n)))
 #define KEYLENGTH (8*sizeof(t_key))
 #define MASK_PFX(k, l) (((l)==0)?0:(k >> (KEYLENGTH-l)) << (KEYLENGTH-l))
 #define TKEY_GET_MASK(offset, bits) (((bits)==0)?0:((t_key)(-1) << (KEYLENGTH - bits) >> offset))
 
-static DEFINE_RWLOCK(fib_lock);
-
 typedef unsigned int t_key;
 
 #define T_TNODE 0
 #define T_LEAF  1
 #define NODE_TYPE_MASK 0x1UL
-#define NODE_PARENT(_node) \
-       ((struct tnode *)((_node)->_parent & ~NODE_TYPE_MASK))
-#define NODE_SET_PARENT(_node, _ptr) \
-       ((_node)->_parent = (((unsigned long)(_ptr)) | \
-                     ((_node)->_parent & NODE_TYPE_MASK)))
-#define NODE_INIT_PARENT(_node, _type) \
-       ((_node)->_parent = (_type))
-#define NODE_TYPE(_node) \
-       ((_node)->_parent & NODE_TYPE_MASK)
-
-#define IS_TNODE(n) (!(n->_parent & T_LEAF))
-#define IS_LEAF(n) (n->_parent & T_LEAF)
+#define NODE_PARENT(node) \
+       ((struct tnode *)rcu_dereference(((node)->parent & ~NODE_TYPE_MASK)))
+
+#define NODE_TYPE(node) ((node)->parent & NODE_TYPE_MASK)
+
+#define NODE_SET_PARENT(node, ptr)             \
+       rcu_assign_pointer((node)->parent,      \
+                          ((unsigned long)(ptr)) | NODE_TYPE(node))
+
+#define IS_TNODE(n) (!(n->parent & T_LEAF))
+#define IS_LEAF(n) (n->parent & T_LEAF)
 
 struct node {
-        t_key key;
-       unsigned long _parent;
+       t_key key;
+       unsigned long parent;
 };
 
 struct leaf {
-        t_key key;
-       unsigned long _parent;
+       t_key key;
+       unsigned long parent;
        struct hlist_head list;
+       struct rcu_head rcu;
 };
 
 struct leaf_info {
        struct hlist_node hlist;
+       struct rcu_head rcu;
        int plen;
        struct list_head falh;
 };
 
 struct tnode {
-        t_key key;
-       unsigned long _parent;
-        unsigned short pos:5;        /* 2log(KEYLENGTH) bits needed */
-        unsigned short bits:5;       /* 2log(KEYLENGTH) bits needed */
-        unsigned short full_children;  /* KEYLENGTH bits needed */
-        unsigned short empty_children; /* KEYLENGTH bits needed */
-        struct node *child[0];
+       t_key key;
+       unsigned long parent;
+       unsigned short pos:5;           /* 2log(KEYLENGTH) bits needed */
+       unsigned short bits:5;          /* 2log(KEYLENGTH) bits needed */
+       unsigned short full_children;   /* KEYLENGTH bits needed */
+       unsigned short empty_children;  /* KEYLENGTH bits needed */
+       struct rcu_head rcu;
+       struct node *child[0];
 };
 
 #ifdef CONFIG_IP_FIB_TRIE_STATS
@@ -150,77 +150,45 @@ struct trie_stat {
 };
 
 struct trie {
-        struct node *trie;
+       struct node *trie;
 #ifdef CONFIG_IP_FIB_TRIE_STATS
        struct trie_use_stats stats;
 #endif
-        int size;
+       int size;
        unsigned int revision;
 };
 
-static int trie_debug = 0;
-
-static int tnode_full(struct tnode *tn, struct node *n);
 static void put_child(struct trie *t, struct tnode *tn, int i, struct node *n);
 static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull);
-static int tnode_child_length(struct tnode *tn);
 static struct node *resize(struct trie *t, struct tnode *tn);
-static struct tnode *inflate(struct trie *t, struct tnode *tn, int *err);
-static struct tnode *halve(struct trie *t, struct tnode *tn, int *err);
+static struct tnode *inflate(struct trie *t, struct tnode *tn);
+static struct tnode *halve(struct trie *t, struct tnode *tn);
 static void tnode_free(struct tnode *tn);
 static void trie_dump_seq(struct seq_file *seq, struct trie *t);
-extern struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio);
-extern int fib_detect_death(struct fib_info *fi, int order,
-                            struct fib_info **last_resort, int *last_idx, int *dflt);
-
-extern void rtmsg_fib(int event, u32 key, struct fib_alias *fa, int z, int tb_id,
-               struct nlmsghdr *n, struct netlink_skb_parms *req);
 
-static kmem_cache_t *fn_alias_kmem;
+static kmem_cache_t *fn_alias_kmem __read_mostly;
 static struct trie *trie_local = NULL, *trie_main = NULL;
 
-static void trie_bug(char *err)
-{
-       printk("Trie Bug: %s\n", err);
-       BUG();
-}
+
+/* rcu_read_lock needs to be hold by caller from readside */
 
 static inline struct node *tnode_get_child(struct tnode *tn, int i)
 {
-        if (i >= 1<<tn->bits)
-                trie_bug("tnode_get_child");
+       BUG_ON(i >= 1 << tn->bits);
 
-        return tn->child[i];
+       return rcu_dereference(tn->child[i]);
 }
 
-static inline int tnode_child_length(struct tnode *tn)
+static inline int tnode_child_length(const struct tnode *tn)
 {
-        return 1<<tn->bits;
+       return 1 << tn->bits;
 }
 
-/*
-  _________________________________________________________________
-  | i | i | i | i | i | i | i | N | N | N | S | S | S | S | S | C |
-  ----------------------------------------------------------------
-    0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
-
-  _________________________________________________________________
-  | C | C | C | u | u | u | u | u | u | u | u | u | u | u | u | u |
-  -----------------------------------------------------------------
-   16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31
-
-  tp->pos = 7
-  tp->bits = 3
-  n->pos = 15
-  n->bits=4
-  KEYLENGTH=32
-*/
-
 static inline t_key tkey_extract_bits(t_key a, int offset, int bits)
 {
-        if (offset < KEYLENGTH)
+       if (offset < KEYLENGTH)
                return ((t_key)(a << offset)) >> (KEYLENGTH - bits);
-        else
+       else
                return 0;
 }
 
@@ -233,8 +201,8 @@ static inline int tkey_sub_equals(t_key a, int offset, int bits, t_key b)
 {
        if (bits == 0 || offset >= KEYLENGTH)
                return 1;
-        bits = bits > KEYLENGTH ? KEYLENGTH : bits;
-        return ((a ^ b) << offset) >> (KEYLENGTH - bits) == 0;
+       bits = bits > KEYLENGTH ? KEYLENGTH : bits;
+       return ((a ^ b) << offset) >> (KEYLENGTH - bits) == 0;
 }
 
 static inline int tkey_mismatch(t_key a, int offset, t_key b)
@@ -249,14 +217,6 @@ static inline int tkey_mismatch(t_key a, int offset, t_key b)
        return i;
 }
 
-/* Candiate for fib_semantics */
-
-static void fn_free_alias(struct fib_alias *fa)
-{
-       fib_release_info(fa->fa_info);
-       kmem_cache_free(fn_alias_kmem, fa);
-}
-
 /*
   To understand this stuff, an understanding of keys and all their bits is 
   necessary. Every node in the trie has a key associated with it, but not 
@@ -295,7 +255,7 @@ static void fn_free_alias(struct fib_alias *fa)
   tp->pos = 7
   tp->bits = 3
   n->pos = 15
-  n->bits=4
+  n->bits = 4
 
   First, let's just ignore the bits that come before the parent tp, that is 
   the bits from 0 to (tp->pos-1). They are *known* but at this point we do 
@@ -320,60 +280,65 @@ static void fn_free_alias(struct fib_alias *fa)
 
 */
 
-static void check_tnode(struct tnode *tn)
+static inline void check_tnode(const struct tnode *tn)
 {
-       if (tn && tn->pos+tn->bits > 32) {
-               printk("TNODE ERROR tn=%p, pos=%d, bits=%d\n", tn, tn->pos, tn->bits);
-       }
+       WARN_ON(tn && tn->pos+tn->bits > 32);
 }
 
 static int halve_threshold = 25;
 static int inflate_threshold = 50;
 
-static struct leaf *leaf_new(void)
+
+static void __alias_free_mem(struct rcu_head *head)
 {
-       struct leaf *l = kmalloc(sizeof(struct leaf),  GFP_KERNEL);
-       if (l) {
-               NODE_INIT_PARENT(l, T_LEAF);
-               INIT_HLIST_HEAD(&l->list);
-       }
-       return l;
+       struct fib_alias *fa = container_of(head, struct fib_alias, rcu);
+       kmem_cache_free(fn_alias_kmem, fa);
 }
 
-static struct leaf_info *leaf_info_new(int plen)
+static inline void alias_free_mem_rcu(struct fib_alias *fa)
 {
-       struct leaf_info *li = kmalloc(sizeof(struct leaf_info),  GFP_KERNEL);
-       if (li) {
-               li->plen = plen;
-               INIT_LIST_HEAD(&li->falh);
-       }
-       return li;
+       call_rcu(&fa->rcu, __alias_free_mem);
+}
+
+static void __leaf_free_rcu(struct rcu_head *head)
+{
+       kfree(container_of(head, struct leaf, rcu));
+}
+
+static inline void free_leaf(struct leaf *leaf)
+{
+       call_rcu(&leaf->rcu, __leaf_free_rcu);
 }
 
-static inline void free_leaf(struct leaf *l)
+static void __leaf_info_free_rcu(struct rcu_head *head)
 {
-       kfree(l);
+       kfree(container_of(head, struct leaf_info, rcu));
 }
 
-static inline void free_leaf_info(struct leaf_info *li)
+static inline void free_leaf_info(struct leaf_info *leaf)
 {
-       kfree(li);
+       call_rcu(&leaf->rcu, __leaf_info_free_rcu);
 }
 
 static struct tnode *tnode_alloc(unsigned int size)
 {
-       if (size <= PAGE_SIZE) {
-               return kmalloc(size, GFP_KERNEL);
-       } else {
-               return (struct tnode *)
-                       __get_free_pages(GFP_KERNEL, get_order(size));
-       }
+       struct page *pages;
+
+       if (size <= PAGE_SIZE)
+               return kcalloc(size, 1, GFP_KERNEL);
+
+       pages = alloc_pages(GFP_KERNEL|__GFP_ZERO, get_order(size));
+       if (!pages)
+               return NULL;
+
+       return page_address(pages);
 }
 
-static void __tnode_free(struct tnode *tn)
+static void __tnode_free_rcu(struct rcu_head *head)
 {
+       struct tnode *tn = container_of(head, struct tnode, rcu);
        unsigned int size = sizeof(struct tnode) +
-                           (1<<tn->bits) * sizeof(struct node *);
+               (1 << tn->bits) * sizeof(struct node *);
 
        if (size <= PAGE_SIZE)
                kfree(tn);
@@ -381,15 +346,40 @@ static void __tnode_free(struct tnode *tn)
                free_pages((unsigned long)tn, get_order(size));
 }
 
+static inline void tnode_free(struct tnode *tn)
+{
+       call_rcu(&tn->rcu, __tnode_free_rcu);
+}
+
+static struct leaf *leaf_new(void)
+{
+       struct leaf *l = kmalloc(sizeof(struct leaf),  GFP_KERNEL);
+       if (l) {
+               l->parent = T_LEAF;
+               INIT_HLIST_HEAD(&l->list);
+       }
+       return l;
+}
+
+static struct leaf_info *leaf_info_new(int plen)
+{
+       struct leaf_info *li = kmalloc(sizeof(struct leaf_info),  GFP_KERNEL);
+       if (li) {
+               li->plen = plen;
+               INIT_LIST_HEAD(&li->falh);
+       }
+       return li;
+}
+
 static struct tnode* tnode_new(t_key key, int pos, int bits)
 {
        int nchildren = 1<<bits;
        int sz = sizeof(struct tnode) + nchildren * sizeof(struct node *);
        struct tnode *tn = tnode_alloc(sz);
 
-       if (tn)  {
+       if (tn) {
                memset(tn, 0, sz);
-               NODE_INIT_PARENT(tn, T_TNODE);
+               tn->parent = T_TNODE;
                tn->pos = pos;
                tn->bits = bits;
                tn->key = key;
@@ -397,38 +387,17 @@ static struct tnode* tnode_new(t_key key, int pos, int bits)
                tn->empty_children = 1<<bits;
        }
 
-       if (trie_debug > 0)
-               printk("AT %p s=%u %u\n", tn, (unsigned int) sizeof(struct tnode),
-                      (unsigned int) (sizeof(struct node) * 1<<bits));
+       pr_debug("AT %p s=%u %u\n", tn, (unsigned int) sizeof(struct tnode),
+                (unsigned int) (sizeof(struct node) * 1<<bits));
        return tn;
 }
 
-static void tnode_free(struct tnode *tn)
-{
-       if (!tn) {
-               trie_bug("tnode_free\n");
-       }
-       if (IS_LEAF(tn)) {
-               free_leaf((struct leaf *)tn);
-               if (trie_debug > 0 )
-                       printk("FL %p \n", tn);
-       }
-       else if (IS_TNODE(tn)) {
-               __tnode_free(tn);
-               if (trie_debug > 0 )
-                       printk("FT %p \n", tn);
-       }
-       else {
-               trie_bug("tnode_free\n");
-       }
-}
-
 /*
  * Check whether a tnode 'n' is "full", i.e. it is an internal node
  * and no bits are skipped. See discussion in dyntree paper p. 6
  */
 
-static inline int tnode_full(struct tnode *tn, struct node *n)
+static inline int tnode_full(const struct tnode *tn, const struct node *n)
 {
        if (n == NULL || IS_LEAF(n))
                return 0;
@@ -448,15 +417,11 @@ static inline void put_child(struct trie *t, struct tnode *tn, int i, struct nod
 
 static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull)
 {
-       struct node *chi;
+       struct node *chi = tn->child[i];
        int isfull;
 
-       if (i >= 1<<tn->bits) {
-               printk("bits=%d, i=%d\n", tn->bits, i);
-               trie_bug("tnode_put_child_reorg bits");
-       }
-       write_lock_bh(&fib_lock);
-       chi = tn->child[i];
+       BUG_ON(i >= 1<<tn->bits);
+
 
        /* update emptyChildren */
        if (n == NULL && chi != NULL)
@@ -465,33 +430,32 @@ static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int w
                tn->empty_children--;
 
        /* update fullChildren */
-        if (wasfull == -1)
+       if (wasfull == -1)
                wasfull = tnode_full(tn, chi);
 
        isfull = tnode_full(tn, n);
        if (wasfull && !isfull)
                tn->full_children--;
-
        else if (!wasfull && isfull)
                tn->full_children++;
+
        if (n)
                NODE_SET_PARENT(n, tn);
 
-       tn->child[i] = n;
-       write_unlock_bh(&fib_lock);
+       rcu_assign_pointer(tn->child[i], n);
 }
 
 static struct node *resize(struct trie *t, struct tnode *tn)
 {
        int i;
        int err = 0;
+       struct tnode *old_tn;
 
        if (!tn)
                return NULL;
 
-       if (trie_debug)
-               printk("In tnode_resize %p inflate_threshold=%d threshold=%d\n",
-                     tn, inflate_threshold, halve_threshold);
+       pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n",
+                tn, inflate_threshold, halve_threshold);
 
        /* No children */
        if (tn->empty_children == tnode_child_length(tn)) {
@@ -501,20 +465,16 @@ static struct node *resize(struct trie *t, struct tnode *tn)
        /* One child */
        if (tn->empty_children == tnode_child_length(tn) - 1)
                for (i = 0; i < tnode_child_length(tn); i++) {
+                       struct node *n;
 
-                       write_lock_bh(&fib_lock);
-                       if (tn->child[i] != NULL) {
-
-                               /* compress one level */
-                               struct node *n = tn->child[i];
-                               if (n)
-                                       NODE_INIT_PARENT(n, NODE_TYPE(n));
+                       n = tn->child[i];
+                       if (!n)
+                               continue;
 
-                               write_unlock_bh(&fib_lock);
-                               tnode_free(tn);
-                               return n;
-                       }
-                       write_unlock_bh(&fib_lock);
+                       /* compress one level */
+                       NODE_SET_PARENT(n, NULL);
+                       tnode_free(tn);
+                       return n;
                }
        /*
         * Double as long as the resulting node has a number of
@@ -566,16 +526,16 @@ static struct node *resize(struct trie *t, struct tnode *tn)
         *
         * expand not_to_be_doubled and to_be_doubled, and shorten:
         * 100 * (tnode_child_length(tn) - tn->empty_children +
-        *    tn->full_children ) >= inflate_threshold * new_child_length
+        *    tn->full_children) >= inflate_threshold * new_child_length
         *
         * expand new_child_length:
         * 100 * (tnode_child_length(tn) - tn->empty_children +
-        *    tn->full_children ) >=
+        *    tn->full_children) >=
         *      inflate_threshold * tnode_child_length(tn) * 2
         *
         * shorten again:
         * 50 * (tn->full_children + tnode_child_length(tn) -
-        *    tn->empty_children ) >= inflate_threshold *
+        *    tn->empty_children) >= inflate_threshold *
         *    tnode_child_length(tn)
         *
         */
@@ -587,9 +547,10 @@ static struct node *resize(struct trie *t, struct tnode *tn)
               50 * (tn->full_children + tnode_child_length(tn) - tn->empty_children) >=
                                inflate_threshold * tnode_child_length(tn))) {
 
-               tn = inflate(t, tn, &err);
-
-               if (err) {
+               old_tn = tn;
+               tn = inflate(t, tn);
+               if (IS_ERR(tn)) {
+                       tn = old_tn;
 #ifdef CONFIG_IP_FIB_TRIE_STATS
                        t->stats.resize_node_skipped++;
 #endif
@@ -609,9 +570,10 @@ static struct node *resize(struct trie *t, struct tnode *tn)
               100 * (tnode_child_length(tn) - tn->empty_children) <
               halve_threshold * tnode_child_length(tn)) {
 
-               tn = halve(t, tn, &err);
-
-               if (err) {
+               old_tn = tn;
+               tn = halve(t, tn);
+               if (IS_ERR(tn)) {
+                       tn = old_tn;
 #ifdef CONFIG_IP_FIB_TRIE_STATS
                        t->stats.resize_node_skipped++;
 #endif
@@ -621,44 +583,37 @@ static struct node *resize(struct trie *t, struct tnode *tn)
 
 
        /* Only one child remains */
-
        if (tn->empty_children == tnode_child_length(tn) - 1)
                for (i = 0; i < tnode_child_length(tn); i++) {
-               
-                       write_lock_bh(&fib_lock);
-                       if (tn->child[i] != NULL) {
-                               /* compress one level */
-                               struct node *n = tn->child[i];
-
-                               if (n)
-                                       NODE_INIT_PARENT(n, NODE_TYPE(n));
-
-                               write_unlock_bh(&fib_lock);
-                               tnode_free(tn);
-                               return n;
-                       }
-                       write_unlock_bh(&fib_lock);
+                       struct node *n;
+
+                       n = tn->child[i];
+                       if (!n)
+                               continue;
+
+                       /* compress one level */
+
+                       NODE_SET_PARENT(n, NULL);
+                       tnode_free(tn);
+                       return n;
                }
 
        return (struct node *) tn;
 }
 
-static struct tnode *inflate(struct trie *t, struct tnode *tn, int *err)
+static struct tnode *inflate(struct trie *t, struct tnode *tn)
 {
        struct tnode *inode;
        struct tnode *oldtnode = tn;
        int olen = tnode_child_length(tn);
        int i;
 
-       if (trie_debug)
-               printk("In inflate\n");
+       pr_debug("In inflate\n");
 
        tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits + 1);
 
-       if (!tn) {
-               *err = -ENOMEM;
-               return oldtnode;
-       }
+       if (!tn)
+               return ERR_PTR(-ENOMEM);
 
        /*
         * Preallocate and store tnodes before the actual work so we
@@ -666,8 +621,8 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn, int *err)
         * fails. In case of failure we return the oldnode and  inflate
         * of tnode is ignored.
         */
-               
-       for(i = 0; i < olen; i++) {
+
+       for (i = 0; i < olen; i++) {
                struct tnode *inode = (struct tnode *) tnode_get_child(oldtnode, i);
 
                if (inode &&
@@ -675,46 +630,30 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn, int *err)
                    inode->pos == oldtnode->pos + oldtnode->bits &&
                    inode->bits > 1) {
                        struct tnode *left, *right;
-
                        t_key m = TKEY_GET_MASK(inode->pos, 1);
 
                        left = tnode_new(inode->key&(~m), inode->pos + 1,
                                         inode->bits - 1);
+                       if (!left)
+                               goto nomem;
 
-                       if (!left) {
-                               *err = -ENOMEM;
-                               break;
-                       }
-               
                        right = tnode_new(inode->key|m, inode->pos + 1,
                                          inode->bits - 1);
 
-                       if (!right) {
-                               *err = -ENOMEM;
-                               break;
-                       }
+                        if (!right) {
+                               tnode_free(left);
+                               goto nomem;
+                        }
 
                        put_child(t, tn, 2*i, (struct node *) left);
                        put_child(t, tn, 2*i+1, (struct node *) right);
                }
        }
 
-       if (*err) {
-               int size = tnode_child_length(tn);
-               int j;
-
-               for(j = 0; j < size; j++)
-                       if (tn->child[j])
-                               tnode_free((struct tnode *)tn->child[j]);
-
-               tnode_free(tn);
-       
-               *err = -ENOMEM;
-               return oldtnode;
-       }
-
-       for(i = 0; i < olen; i++) {
+       for (i = 0; i < olen; i++) {
                struct node *node = tnode_get_child(oldtnode, i);
+               struct tnode *left, *right;
+               int size, j;
 
                /* An empty child */
                if (node == NULL)
@@ -740,76 +679,82 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn, int *err)
                        put_child(t, tn, 2*i+1, inode->child[1]);
 
                        tnode_free(inode);
+                       continue;
                }
 
-                       /* An internal node with more than two children */
-               else {
-                       struct tnode *left, *right;
-                       int size, j;
-
-                       /* We will replace this node 'inode' with two new
-                        * ones, 'left' and 'right', each with half of the
-                        * original children. The two new nodes will have
-                        * a position one bit further down the key and this
-                        * means that the "significant" part of their keys
-                        * (see the discussion near the top of this file)
-                        * will differ by one bit, which will be "0" in
-                        * left's key and "1" in right's key. Since we are
-                        * moving the key position by one step, the bit that
-                        * we are moving away from - the bit at position
-                        * (inode->pos) - is the one that will differ between
-                        * left and right. So... we synthesize that bit in the
-                        * two  new keys.
-                        * The mask 'm' below will be a single "one" bit at
-                        * the position (inode->pos)
-                        */
-
-                       /* Use the old key, but set the new significant
-                        *   bit to zero.
-                        */
+               /* An internal node with more than two children */
+
+               /* We will replace this node 'inode' with two new
+                * ones, 'left' and 'right', each with half of the
+                * original children. The two new nodes will have
+                * a position one bit further down the key and this
+                * means that the "significant" part of their keys
+                * (see the discussion near the top of this file)
+                * will differ by one bit, which will be "0" in
+                * left's key and "1" in right's key. Since we are
+                * moving the key position by one step, the bit that
+                * we are moving away from - the bit at position
+                * (inode->pos) - is the one that will differ between
+                * left and right. So... we synthesize that bit in the
+                * two  new keys.
+                * The mask 'm' below will be a single "one" bit at
+                * the position (inode->pos)
+                */
 
-                       left = (struct tnode *) tnode_get_child(tn, 2*i);
-                       put_child(t, tn, 2*i, NULL);
+               /* Use the old key, but set the new significant
+                *   bit to zero.
+                */
 
-                       if (!left)
-                               BUG();
+               left = (struct tnode *) tnode_get_child(tn, 2*i);
+               put_child(t, tn, 2*i, NULL);
 
-                       right = (struct tnode *) tnode_get_child(tn, 2*i+1);
-                       put_child(t, tn, 2*i+1, NULL);
+               BUG_ON(!left);
 
-                       if (!right)
-                               BUG();
+               right = (struct tnode *) tnode_get_child(tn, 2*i+1);
+               put_child(t, tn, 2*i+1, NULL);
 
-                       size = tnode_child_length(left);
-                       for(j = 0; j < size; j++) {
-                               put_child(t, left, j, inode->child[j]);
-                               put_child(t, right, j, inode->child[j + size]);
-                       }
-                       put_child(t, tn, 2*i, resize(t, left));
-                       put_child(t, tn, 2*i+1, resize(t, right));
+               BUG_ON(!right);
 
-                       tnode_free(inode);
+               size = tnode_child_length(left);
+               for (j = 0; j < size; j++) {
+                       put_child(t, left, j, inode->child[j]);
+                       put_child(t, right, j, inode->child[j + size]);
                }
+               put_child(t, tn, 2*i, resize(t, left));
+               put_child(t, tn, 2*i+1, resize(t, right));
+
+               tnode_free(inode);
        }
        tnode_free(oldtnode);
        return tn;
+nomem:
+       {
+               int size = tnode_child_length(tn);
+               int j;
+
+               for (j = 0; j < size; j++)
+                       if (tn->child[j])
+                               tnode_free((struct tnode *)tn->child[j]);
+
+               tnode_free(tn);
+
+               return ERR_PTR(-ENOMEM);
+       }
 }
 
-static struct tnode *halve(struct trie *t, struct tnode *tn, int *err)
+static struct tnode *halve(struct trie *t, struct tnode *tn)
 {
        struct tnode *oldtnode = tn;
        struct node *left, *right;
        int i;
        int olen = tnode_child_length(tn);
 
-       if (trie_debug) printk("In halve\n");
+       pr_debug("In halve\n");
 
        tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits - 1);
 
-       if (!tn) {
-               *err = -ENOMEM;
-               return oldtnode;
-       }
+       if (!tn)
+               return ERR_PTR(-ENOMEM);
 
        /*
         * Preallocate and store tnodes before the actual work so we
@@ -818,38 +763,27 @@ static struct tnode *halve(struct trie *t, struct tnode *tn, int *err)
         * of tnode is ignored.
         */
 
-       for(i = 0; i < olen; i += 2) {
+       for (i = 0; i < olen; i += 2) {
                left = tnode_get_child(oldtnode, i);
                right = tnode_get_child(oldtnode, i+1);
 
                /* Two nonempty children */
-               if (left && right)  {
-                       struct tnode *newBinNode =
-                               tnode_new(left->key, tn->pos + tn->bits, 1);
+               if (left && right) {
+                       struct tnode *newn;
 
-                       if (!newBinNode) {
-                               *err = -ENOMEM;
-                               break;
-                       }
-                       put_child(t, tn, i/2, (struct node *)newBinNode);
-               }
-       }
+                       newn = tnode_new(left->key, tn->pos + tn->bits, 1);
 
-       if (*err) {
-               int size = tnode_child_length(tn);
-               int j;
+                       if (!newn)
+                               goto nomem;
 
-               for(j = 0; j < size; j++)
-                       if (tn->child[j])
-                               tnode_free((struct tnode *)tn->child[j]);
+                       put_child(t, tn, i/2, (struct node *)newn);
+               }
 
-               tnode_free(tn);
-       
-               *err = -ENOMEM;
-               return oldtnode;
        }
 
-       for(i = 0; i < olen; i += 2) {
+       for (i = 0; i < olen; i += 2) {
+               struct tnode *newBinNode;
+
                left = tnode_get_child(oldtnode, i);
                right = tnode_get_child(oldtnode, i+1);
 
@@ -858,88 +792,99 @@ static struct tnode *halve(struct trie *t, struct tnode *tn, int *err)
                        if (right == NULL)    /* Both are empty */
                                continue;
                        put_child(t, tn, i/2, right);
-               } else if (right == NULL)
+                       continue;
+               }
+
+               if (right == NULL) {
                        put_child(t, tn, i/2, left);
+                       continue;
+               }
 
                /* Two nonempty children */
-               else {
-                       struct tnode *newBinNode =
-                               (struct tnode *) tnode_get_child(tn, i/2);
-                       put_child(t, tn, i/2, NULL);
-
-                       if (!newBinNode)
-                               BUG();
-
-                       put_child(t, newBinNode, 0, left);
-                       put_child(t, newBinNode, 1, right);
-                       put_child(t, tn, i/2, resize(t, newBinNode));
-               }
+               newBinNode = (struct tnode *) tnode_get_child(tn, i/2);
+               put_child(t, tn, i/2, NULL);
+               put_child(t, newBinNode, 0, left);
+               put_child(t, newBinNode, 1, right);
+               put_child(t, tn, i/2, resize(t, newBinNode));
        }
        tnode_free(oldtnode);
        return tn;
+nomem:
+       {
+               int size = tnode_child_length(tn);
+               int j;
+
+               for (j = 0; j < size; j++)
+                       if (tn->child[j])
+                               tnode_free((struct tnode *)tn->child[j]);
+
+               tnode_free(tn);
+
+               return ERR_PTR(-ENOMEM);
+       }
 }
 
-static void *trie_init(struct trie *t)
+static void trie_init(struct trie *t)
 {
-       if (t) {
-               t->size = 0;
-               t->trie = NULL;
-               t->revision = 0;
+       if (!t)
+               return;
+
+       t->size = 0;
+       rcu_assign_pointer(t->trie, NULL);
+       t->revision = 0;
 #ifdef CONFIG_IP_FIB_TRIE_STATS
-                       memset(&t->stats, 0, sizeof(struct trie_use_stats));
+       memset(&t->stats, 0, sizeof(struct trie_use_stats));
 #endif
-       }
-       return t;
 }
 
+/* readside most use rcu_read_lock currently dump routines
+ via get_fa_head and dump */
+
 static struct leaf_info *find_leaf_info(struct hlist_head *head, int plen)
 {
        struct hlist_node *node;
        struct leaf_info *li;
 
-       hlist_for_each_entry(li, node, head, hlist) {
+       hlist_for_each_entry_rcu(li, node, head, hlist)
                if (li->plen == plen)
                        return li;
-       }
+
        return NULL;
 }
 
 static inline struct list_head * get_fa_head(struct leaf *l, int plen)
 {
-       struct list_head *fa_head = NULL;
        struct leaf_info *li = find_leaf_info(&l->list, plen);
 
-       if (li)
-               fa_head = &li->falh;
+       if (!li)
+               return NULL;
 
-       return fa_head;
+       return &li->falh;
 }
 
 static void insert_leaf_info(struct hlist_head *head, struct leaf_info *new)
 {
-       struct leaf_info *li = NULL, *last = NULL;
-       struct hlist_node *node, *tmp;
-
-       write_lock_bh(&fib_lock);
-
-       if (hlist_empty(head))
-               hlist_add_head(&new->hlist, head);
-       else {
-               hlist_for_each_entry_safe(li, node, tmp, head, hlist) {
-               
-                       if (new->plen > li->plen)
-                               break;
-               
-                       last = li;
-               }
-               if (last)
-                       hlist_add_after(&last->hlist, &new->hlist);
-               else
-                       hlist_add_before(&new->hlist, &li->hlist);
-       }
-       write_unlock_bh(&fib_lock);
+        struct leaf_info *li = NULL, *last = NULL;
+        struct hlist_node *node;
+
+        if (hlist_empty(head)) {
+                hlist_add_head_rcu(&new->hlist, head);
+        } else {
+                hlist_for_each_entry(li, node, head, hlist) {
+                        if (new->plen > li->plen)
+                                break;
+
+                        last = li;
+                }
+                if (last)
+                        hlist_add_after_rcu(&last->hlist, &new->hlist);
+                else
+                        hlist_add_before_rcu(&new->hlist, &li->hlist);
+        }
 }
 
+/* rcu_read_lock needs to be hold by caller from readside */
+
 static struct leaf *
 fib_find_node(struct trie *t, u32 key)
 {
@@ -948,61 +893,43 @@ fib_find_node(struct trie *t, u32 key)
        struct node *n;
 
        pos = 0;
-       n = t->trie;
+       n = rcu_dereference(t->trie);
 
        while (n != NULL &&  NODE_TYPE(n) == T_TNODE) {
                tn = (struct tnode *) n;
-               
+
                check_tnode(tn);
-               
+
                if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
-                       pos=tn->pos + tn->bits;
+                       pos = tn->pos + tn->bits;
                        n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits));
-               }
-               else
+               } else
                        break;
        }
        /* Case we have found a leaf. Compare prefixes */
 
-       if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) {
-               struct leaf *l = (struct leaf *) n;
-               return l;
-       }
+       if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key))
+               return (struct leaf *)n;
+
        return NULL;
 }
 
 static struct node *trie_rebalance(struct trie *t, struct tnode *tn)
 {
-       int i = 0;
        int wasfull;
        t_key cindex, key;
        struct tnode *tp = NULL;
 
-       if (!tn)
-               BUG();
-
        key = tn->key;
-       i = 0;
 
        while (tn != NULL && NODE_PARENT(tn) != NULL) {
 
-               if (i > 10) {
-                       printk("Rebalance tn=%p \n", tn);
-                       if (tn)                 printk("tn->parent=%p \n", NODE_PARENT(tn));
-               
-                       printk("Rebalance tp=%p \n", tp);
-                       if (tp)                 printk("tp->parent=%p \n", NODE_PARENT(tp));
-               }
-
-               if (i > 12) BUG();
-               i++;
-
                tp = NODE_PARENT(tn);
                cindex = tkey_extract_bits(key, tp->pos, tp->bits);
                wasfull = tnode_full(tp, tnode_get_child(tp, cindex));
                tn = (struct tnode *) resize (t, (struct tnode *)tn);
                tnode_put_child_reorg((struct tnode *)tp, cindex,(struct node*)tn, wasfull);
-       
+
                if (!NODE_PARENT(tn))
                        break;
 
@@ -1015,6 +942,8 @@ static struct node *trie_rebalance(struct trie *t, struct tnode *tn)
        return (struct node*) tn;
 }
 
+/* only used from updater-side */
+
 static  struct list_head *
 fib_insert_node(struct trie *t, int *err, u32 key, int plen)
 {
@@ -1050,20 +979,16 @@ fib_insert_node(struct trie *t, int *err, u32 key, int plen)
 
        while (n != NULL &&  NODE_TYPE(n) == T_TNODE) {
                tn = (struct tnode *) n;
-               
+
                check_tnode(tn);
-       
+
                if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
                        tp = tn;
-                       pos=tn->pos + tn->bits;
+                       pos = tn->pos + tn->bits;
                        n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits));
 
-                       if (n && NODE_PARENT(n) != tn) {
-                               printk("BUG tn=%p, n->parent=%p\n", tn, NODE_PARENT(n));
-                               BUG();
-                       }
-               }
-               else
+                       BUG_ON(n && NODE_PARENT(n) != tn);
+               } else
                        break;
        }
 
@@ -1073,17 +998,15 @@ fib_insert_node(struct trie *t, int *err, u32 key, int plen)
         * tp is n's (parent) ----> NULL or TNODE
         */
 
-       if (tp && IS_LEAF(tp))
-               BUG();
-
+       BUG_ON(tp && IS_LEAF(tp));
 
        /* Case 1: n is a leaf. Compare prefixes */
 
        if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) {
-               struct leaf *l = ( struct leaf *)  n;
-       
+               struct leaf *l = (struct leaf *) n;
+
                li = leaf_info_new(plen);
-       
+
                if (!li) {
                        *err = -ENOMEM;
                        goto err;
@@ -1113,35 +1036,29 @@ fib_insert_node(struct trie *t, int *err, u32 key, int plen)
        fa_head = &li->falh;
        insert_leaf_info(&l->list, li);
 
-       /* Case 2: n is NULL, and will just insert a new leaf */
        if (t->trie && n == NULL) {
+               /* Case 2: n is NULL, and will just insert a new leaf */
 
                NODE_SET_PARENT(l, tp);
-       
-               if (!tp)
-                       BUG();
 
-               else {
-                       cindex = tkey_extract_bits(key, tp->pos, tp->bits);
-                       put_child(t, (struct tnode *)tp, cindex, (struct node *)l);
-               }
-       }
-       /* Case 3: n is a LEAF or a TNODE and the key doesn't match. */
-       else {
+               cindex = tkey_extract_bits(key, tp->pos, tp->bits);
+               put_child(t, (struct tnode *)tp, cindex, (struct node *)l);
+       } else {
+               /* Case 3: n is a LEAF or a TNODE and the key doesn't match. */
                /*
                 *  Add a new tnode here
                 *  first tnode need some special handling
                 */
 
                if (tp)
-                       pos=tp->pos+tp->bits;
+                       pos = tp->pos+tp->bits;
                else
-                       pos=0;
+                       pos = 0;
+
                if (n) {
                        newpos = tkey_mismatch(key, pos, n->key);
                        tn = tnode_new(n->key, newpos, 1);
-               }
-               else {
+               } else {
                        newpos = 0;
                        tn = tnode_new(key, newpos, 1); /* First tnode */
                }
@@ -1151,32 +1068,33 @@ fib_insert_node(struct trie *t, int *err, u32 key, int plen)
                        tnode_free((struct tnode *) l);
                        *err = -ENOMEM;
                        goto err;
-               }               
-               
+               }
+
                NODE_SET_PARENT(tn, tp);
 
-               missbit=tkey_extract_bits(key, newpos, 1);
+               missbit = tkey_extract_bits(key, newpos, 1);
                put_child(t, tn, missbit, (struct node *)l);
                put_child(t, tn, 1-missbit, n);
 
                if (tp) {
                        cindex = tkey_extract_bits(key, tp->pos, tp->bits);
                        put_child(t, (struct tnode *)tp, cindex, (struct node *)tn);
-               }
-               else {
-                       t->trie = (struct node*) tn; /* First tnode */
+               } else {
+                       rcu_assign_pointer(t->trie, (struct node *)tn); /* First tnode */
                        tp = tn;
                }
        }
-       if (tp && tp->pos+tp->bits > 32) {
+
+       if (tp && tp->pos + tp->bits > 32)
                printk("ERROR tp=%p pos=%d, bits=%d, key=%0x plen=%d\n",
                       tp, tp->pos, tp->bits, key, plen);
-       }
+
        /* Rebalance the trie */
-       t->trie = trie_rebalance(t, tp);
+
+       rcu_assign_pointer(t->trie, trie_rebalance(t, tp));
 done:
        t->revision++;
-err:;
+err:
        return fa_head;
 }
 
@@ -1204,17 +1122,18 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
 
        key = ntohl(key);
 
-       if (trie_debug)
-               printk("Insert table=%d %08x/%d\n", tb->tb_id, key, plen);
+       pr_debug("Insert table=%d %08x/%d\n", tb->tb_id, key, plen);
 
-       mask = ntohl( inet_make_mask(plen) );
+       mask = ntohl(inet_make_mask(plen));
 
        if (key & ~mask)
                return -EINVAL;
 
        key = key & mask;
 
-       if  ((fi = fib_create_info(r, rta, nlhdr, &err)) == NULL)
+       fi = fib_create_info(r, rta, nlhdr, &err);
+
+       if (!fi)
                goto err;
 
        l = fib_find_node(t, key);
@@ -1236,8 +1155,7 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
         * and we need to allocate a new one of those as well.
         */
 
-       if (fa &&
-           fa->fa_info->fib_priority == fi->fib_priority) {
+       if (fa && fa->fa_info->fib_priority == fi->fib_priority) {
                struct fib_alias *fa_orig;
 
                err = -EEXIST;
@@ -1248,22 +1166,27 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
                        struct fib_info *fi_drop;
                        u8 state;
 
-                       write_lock_bh(&fib_lock);
+                       err = -ENOBUFS;
+                       new_fa = kmem_cache_alloc(fn_alias_kmem, SLAB_KERNEL);
+                       if (new_fa == NULL)
+                               goto out;
 
                        fi_drop = fa->fa_info;
-                       fa->fa_info = fi;
-                       fa->fa_type = type;
-                       fa->fa_scope = r->rtm_scope;
+                       new_fa->fa_tos = fa->fa_tos;
+                       new_fa->fa_info = fi;
+                       new_fa->fa_type = type;
+                       new_fa->fa_scope = r->rtm_scope;
                        state = fa->fa_state;
-                       fa->fa_state &= ~FA_S_ACCESSED;
+                       new_fa->fa_state &= ~FA_S_ACCESSED;
 
-                       write_unlock_bh(&fib_lock);
+                       list_replace_rcu(&fa->fa_list, &new_fa->fa_list);
+                       alias_free_mem_rcu(fa);
 
                        fib_release_info(fi_drop);
                        if (state & FA_S_ACCESSED)
-                         rt_cache_flush(-1);
+                               rt_cache_flush(-1);
 
-                           goto succeeded;
+                       goto succeeded;
                }
                /* Error if we find a perfect match which
                 * uses the same scope, type, and nexthop
@@ -1285,7 +1208,7 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
                        fa = fa_orig;
        }
        err = -ENOENT;
-       if (!(nlhdr->nlmsg_flags&NLM_F_CREATE))
+       if (!(nlhdr->nlmsg_flags & NLM_F_CREATE))
                goto out;
 
        err = -ENOBUFS;
@@ -1298,9 +1221,6 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
        new_fa->fa_type = type;
        new_fa->fa_scope = r->rtm_scope;
        new_fa->fa_state = 0;
-#if 0
-       new_fa->dst = NULL;
-#endif
        /*
         * Insert new entry to the list.
         */
@@ -1312,12 +1232,8 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
                        goto out_free_new_fa;
        }
 
-       write_lock_bh(&fib_lock);
-
-       list_add_tail(&new_fa->fa_list,
-                (fa ? &fa->fa_list : fa_head));
-
-       write_unlock_bh(&fib_lock);
+       list_add_tail_rcu(&new_fa->fa_list,
+                         (fa ? &fa->fa_list : fa_head));
 
        rt_cache_flush(-1);
        rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, nlhdr, req);
@@ -1328,11 +1244,14 @@ out_free_new_fa:
        kmem_cache_free(fn_alias_kmem, new_fa);
 out:
        fib_release_info(fi);
-err:;
+err:
        return err;
 }
 
-static inline int check_leaf(struct trie *t, struct leaf *l,  t_key key, int *plen, const struct flowi *flp,
+
+/* should be clalled with rcu_read_lock */
+static inline int check_leaf(struct trie *t, struct leaf *l,
+                            t_key key, int *plen, const struct flowi *flp,
                             struct fib_result *res)
 {
        int err, i;
@@ -1341,8 +1260,7 @@ static inline int check_leaf(struct trie *t, struct leaf *l,  t_key key, int *pl
        struct hlist_head *hhead = &l->list;
        struct hlist_node *node;
 
-       hlist_for_each_entry(li, node, hhead, hlist) {
-
+       hlist_for_each_entry_rcu(li, node, hhead, hlist) {
                i = li->plen;
                mask = ntohl(inet_make_mask(i));
                if (l->key != (key & mask))
@@ -1370,13 +1288,17 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
        struct node *n;
        struct tnode *pn;
        int pos, bits;
-       t_key key=ntohl(flp->fl4_dst);
+       t_key key = ntohl(flp->fl4_dst);
        int chopped_off;
        t_key cindex = 0;
        int current_prefix_length = KEYLENGTH;
-       n = t->trie;
+       struct tnode *cn;
+       t_key node_prefix, key_prefix, pref_mismatch;
+       int mp;
+
+       rcu_read_lock();
 
-       read_lock(&fib_lock);
+       n = rcu_dereference(t->trie);
        if (!n)
                goto failed;
 
@@ -1393,8 +1315,7 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
        pn = (struct tnode *) n;
        chopped_off = 0;
 
-        while (pn) {
-
+       while (pn) {
                pos = pn->pos;
                bits = pn->bits;
 
@@ -1410,130 +1331,129 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
                        goto backtrace;
                }
 
-               if (IS_TNODE(n)) {
+               if (IS_LEAF(n)) {
+                       if ((ret = check_leaf(t, (struct leaf *)n, key, &plen, flp, res)) <= 0)
+                               goto found;
+                       else
+                               goto backtrace;
+               }
+
 #define HL_OPTIMIZE
 #ifdef HL_OPTIMIZE
-                       struct tnode *cn = (struct tnode *)n;
-                       t_key node_prefix, key_prefix, pref_mismatch;
-                       int mp;
+               cn = (struct tnode *)n;
 
-                       /*
-                        * It's a tnode, and we can do some extra checks here if we
-                        * like, to avoid descending into a dead-end branch.
-                        * This tnode is in the parent's child array at index
-                        * key[p_pos..p_pos+p_bits] but potentially with some bits
-                        * chopped off, so in reality the index may be just a
-                        * subprefix, padded with zero at the end.
-                        * We can also take a look at any skipped bits in this
-                        * tnode - everything up to p_pos is supposed to be ok,
-                        * and the non-chopped bits of the index (se previous
-                        * paragraph) are also guaranteed ok, but the rest is
-                        * considered unknown.
-                        *
-                        * The skipped bits are key[pos+bits..cn->pos].
-                        */
-               
-                       /* If current_prefix_length < pos+bits, we are already doing
-                        * actual prefix  matching, which means everything from
-                        * pos+(bits-chopped_off) onward must be zero along some
-                        * branch of this subtree - otherwise there is *no* valid
-                        * prefix present. Here we can only check the skipped
-                        * bits. Remember, since we have already indexed into the
-                        * parent's child array, we know that the bits we chopped of
-                        * *are* zero.
-                        */
+               /*
+                * It's a tnode, and we can do some extra checks here if we
+                * like, to avoid descending into a dead-end branch.
+                * This tnode is in the parent's child array at index
+                * key[p_pos..p_pos+p_bits] but potentially with some bits
+                * chopped off, so in reality the index may be just a
+                * subprefix, padded with zero at the end.
+                * We can also take a look at any skipped bits in this
+                * tnode - everything up to p_pos is supposed to be ok,
+                * and the non-chopped bits of the index (se previous
+                * paragraph) are also guaranteed ok, but the rest is
+                * considered unknown.
+                *
+                * The skipped bits are key[pos+bits..cn->pos].
+                */
 
-                       /* NOTA BENE: CHECKING ONLY SKIPPED BITS FOR THE NEW NODE HERE */
-               
-                       if (current_prefix_length < pos+bits) {
-                               if (tkey_extract_bits(cn->key, current_prefix_length,
-                                                     cn->pos - current_prefix_length) != 0 ||
-                                   !(cn->child[0]))
-                                       goto backtrace;
-                       }
+               /* If current_prefix_length < pos+bits, we are already doing
+                * actual prefix  matching, which means everything from
+                * pos+(bits-chopped_off) onward must be zero along some
+                * branch of this subtree - otherwise there is *no* valid
+                * prefix present. Here we can only check the skipped
+                * bits. Remember, since we have already indexed into the
+                * parent's child array, we know that the bits we chopped of
+                * *are* zero.
+                */
 
-                       /*
-                        * If chopped_off=0, the index is fully validated and we
-                        * only need to look at the skipped bits for this, the new,
-                        * tnode. What we actually want to do is to find out if
-                        * these skipped bits match our key perfectly, or if we will
-                        * have to count on finding a matching prefix further down,
-                        * because if we do, we would like to have some way of
-                        * verifying the existence of such a prefix at this point.
-                        */
+               /* NOTA BENE: CHECKING ONLY SKIPPED BITS FOR THE NEW NODE HERE */
 
-                       /* The only thing we can do at this point is to verify that
-                        * any such matching prefix can indeed be a prefix to our
-                        * key, and if the bits in the node we are inspecting that
-                        * do not match our key are not ZERO, this cannot be true.
-                        * Thus, find out where there is a mismatch (before cn->pos)
-                        * and verify that all the mismatching bits are zero in the
-                        * new tnode's key.
-                        */
+               if (current_prefix_length < pos+bits) {
+                       if (tkey_extract_bits(cn->key, current_prefix_length,
+                                               cn->pos - current_prefix_length) != 0 ||
+                           !(cn->child[0]))
+                               goto backtrace;
+               }
 
-                       /* Note: We aren't very concerned about the piece of the key
-                        * that precede pn->pos+pn->bits, since these have already been
-                        * checked. The bits after cn->pos aren't checked since these are
-                        * by definition "unknown" at this point. Thus, what we want to
-                        * see is if we are about to enter the "prefix matching" state,
-                        * and in that case verify that the skipped bits that will prevail
-                        * throughout this subtree are zero, as they have to be if we are
-                        * to find a matching prefix.
-                        */
+               /*
+                * If chopped_off=0, the index is fully validated and we
+                * only need to look at the skipped bits for this, the new,
+                * tnode. What we actually want to do is to find out if
+                * these skipped bits match our key perfectly, or if we will
+                * have to count on finding a matching prefix further down,
+                * because if we do, we would like to have some way of
+                * verifying the existence of such a prefix at this point.
+                */
 
-                       node_prefix = MASK_PFX(cn->key, cn->pos);
-                       key_prefix = MASK_PFX(key, cn->pos);
-                       pref_mismatch = key_prefix^node_prefix;
-                       mp = 0;
+               /* The only thing we can do at this point is to verify that
+                * any such matching prefix can indeed be a prefix to our
+                * key, and if the bits in the node we are inspecting that
+                * do not match our key are not ZERO, this cannot be true.
+                * Thus, find out where there is a mismatch (before cn->pos)
+                * and verify that all the mismatching bits are zero in the
+                * new tnode's key.
+                */
 
-                       /* In short: If skipped bits in this node do not match the search
-                        * key, enter the "prefix matching" state.directly.
-                        */
-                       if (pref_mismatch) {
-                               while (!(pref_mismatch & (1<<(KEYLENGTH-1)))) {
-                                       mp++;
-                                       pref_mismatch = pref_mismatch <<1;
-                               }
-                               key_prefix = tkey_extract_bits(cn->key, mp, cn->pos-mp);
-                       
-                               if (key_prefix != 0)
-                                       goto backtrace;
-
-                               if (current_prefix_length >= cn->pos)
-                                       current_prefix_length=mp;
-                      }
-#endif
-                      pn = (struct tnode *)n; /* Descend */
-                      chopped_off = 0;
-                      continue;
+               /* Note: We aren't very concerned about the piece of the key
+                * that precede pn->pos+pn->bits, since these have already been
+                * checked. The bits after cn->pos aren't checked since these are
+                * by definition "unknown" at this point. Thus, what we want to
+                * see is if we are about to enter the "prefix matching" state,
+                * and in that case verify that the skipped bits that will prevail
+                * throughout this subtree are zero, as they have to be if we are
+                * to find a matching prefix.
+                */
+
+               node_prefix = MASK_PFX(cn->key, cn->pos);
+               key_prefix = MASK_PFX(key, cn->pos);
+               pref_mismatch = key_prefix^node_prefix;
+               mp = 0;
+
+               /* In short: If skipped bits in this node do not match the search
+                * key, enter the "prefix matching" state.directly.
+                */
+               if (pref_mismatch) {
+                       while (!(pref_mismatch & (1<<(KEYLENGTH-1)))) {
+                               mp++;
+                               pref_mismatch = pref_mismatch <<1;
+                       }
+                       key_prefix = tkey_extract_bits(cn->key, mp, cn->pos-mp);
+
+                       if (key_prefix != 0)
+                               goto backtrace;
+
+                       if (current_prefix_length >= cn->pos)
+                               current_prefix_length = mp;
                }
-               if (IS_LEAF(n)) {
-                       if ((ret = check_leaf(t, (struct leaf *)n, key, &plen, flp, res)) <= 0)
-                               goto found;
-              }
+#endif
+               pn = (struct tnode *)n; /* Descend */
+               chopped_off = 0;
+               continue;
+
 backtrace:
                chopped_off++;
 
                /* As zero don't change the child key (cindex) */
-               while ((chopped_off <= pn->bits) && !(cindex & (1<<(chopped_off-1)))) {
+               while ((chopped_off <= pn->bits) && !(cindex & (1<<(chopped_off-1))))
                        chopped_off++;
-               }
 
                /* Decrease current_... with bits chopped off */
                if (current_prefix_length > pn->pos + pn->bits - chopped_off)
                        current_prefix_length = pn->pos + pn->bits - chopped_off;
-       
+
                /*
                 * Either we do the actual chop off according or if we have
                 * chopped off all bits in this tnode walk up to our parent.
                 */
 
-               if (chopped_off <= pn->bits)
+               if (chopped_off <= pn->bits) {
                        cindex &= ~(1 << (chopped_off-1));
-               else {
+               else {
                        if (NODE_PARENT(pn) == NULL)
                                goto failed;
-               
+
                        /* Get Child's index */
                        cindex = tkey_extract_bits(pn->key, NODE_PARENT(pn)->pos, NODE_PARENT(pn)->bits);
                        pn = NODE_PARENT(pn);
@@ -1548,10 +1468,11 @@ backtrace:
 failed:
        ret = 1;
 found:
-       read_unlock(&fib_lock);
+       rcu_read_unlock();
        return ret;
 }
 
+/* only called from updater side */
 static int trie_leaf_remove(struct trie *t, t_key key)
 {
        t_key cindex;
@@ -1559,24 +1480,20 @@ static int trie_leaf_remove(struct trie *t, t_key key)
        struct node *n = t->trie;
        struct leaf *l;
 
-       if (trie_debug)
-               printk("entering trie_leaf_remove(%p)\n", n);
+       pr_debug("entering trie_leaf_remove(%p)\n", n);
 
        /* Note that in the case skipped bits, those bits are *not* checked!
         * When we finish this, we will have NULL or a T_LEAF, and the
         * T_LEAF may or may not match our key.
         */
 
-        while (n != NULL && IS_TNODE(n)) {
+       while (n != NULL && IS_TNODE(n)) {
                struct tnode *tn = (struct tnode *) n;
                check_tnode(tn);
                n = tnode_get_child(tn ,tkey_extract_bits(key, tn->pos, tn->bits));
 
-                       if (n && NODE_PARENT(n) != tn) {
-                               printk("BUG tn=%p, n->parent=%p\n", tn, NODE_PARENT(n));
-                               BUG();
-                       }
-        }
+               BUG_ON(n && NODE_PARENT(n) != tn);
+       }
        l = (struct leaf *) n;
 
        if (!n || !tkey_equals(l->key, key))
@@ -1590,23 +1507,24 @@ static int trie_leaf_remove(struct trie *t, t_key key)
        t->revision++;
        t->size--;
 
+       preempt_disable();
        tp = NODE_PARENT(n);
        tnode_free((struct tnode *) n);
 
        if (tp) {
                cindex = tkey_extract_bits(key, tp->pos, tp->bits);
                put_child(t, (struct tnode *)tp, cindex, NULL);
-               t->trie = trie_rebalance(t, tp);
-       }
-       else
-               t->trie = NULL;
+               rcu_assign_pointer(t->trie, trie_rebalance(t, tp));
+       } else
+               rcu_assign_pointer(t->trie, NULL);
+       preempt_enable();
 
        return 1;
 }
 
 static int
 fn_trie_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
-              struct nlmsghdr *nlhdr, struct netlink_skb_parms *req)
+               struct nlmsghdr *nlhdr, struct netlink_skb_parms *req)
 {
        struct trie *t = (struct trie *) tb->tb_data;
        u32 key, mask;
@@ -1615,6 +1533,8 @@ fn_trie_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
        struct fib_alias *fa, *fa_to_delete;
        struct list_head *fa_head;
        struct leaf *l;
+       struct leaf_info *li;
+
 
        if (plen > 32)
                return -EINVAL;
@@ -1624,7 +1544,7 @@ fn_trie_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
                memcpy(&key, rta->rta_dst, 4);
 
        key = ntohl(key);
-       mask = ntohl( inet_make_mask(plen) );
+       mask = ntohl(inet_make_mask(plen));
 
        if (key & ~mask)
                return -EINVAL;
@@ -1641,11 +1561,11 @@ fn_trie_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
        if (!fa)
                return -ESRCH;
 
-       if (trie_debug)
-               printk("Deleting %08x/%d tos=%d t=%p\n", key, plen, tos, t);
+       pr_debug("Deleting %08x/%d tos=%d t=%p\n", key, plen, tos, t);
 
        fa_to_delete = NULL;
        fa_head = fa->fa_list.prev;
+
        list_for_each_entry(fa, fa_head, fa_list) {
                struct fib_info *fi = fa->fa_info;
 
@@ -1664,39 +1584,31 @@ fn_trie_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
                }
        }
 
-       if (fa_to_delete) {
-               int kill_li = 0;
-               struct leaf_info *li;
-
-               fa = fa_to_delete;
-               rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, nlhdr, req);
+       if (!fa_to_delete)
+               return -ESRCH;
 
-               l = fib_find_node(t, key);
-               li = find_leaf_info(&l->list, plen);
+       fa = fa_to_delete;
+       rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, nlhdr, req);
 
-               write_lock_bh(&fib_lock);
+       l = fib_find_node(t, key);
+       li = find_leaf_info(&l->list, plen);
 
-               list_del(&fa->fa_list);
+       list_del_rcu(&fa->fa_list);
 
-               if (list_empty(fa_head)) {
-                       hlist_del(&li->hlist);
-                       kill_li = 1;
-               }
-               write_unlock_bh(&fib_lock);
-       
-               if (kill_li)
-                       free_leaf_info(li);
+       if (list_empty(fa_head)) {
+               hlist_del_rcu(&li->hlist);
+               free_leaf_info(li);
+       }
 
-               if (hlist_empty(&l->list))
-                       trie_leaf_remove(t, key);
+       if (hlist_empty(&l->list))
+               trie_leaf_remove(t, key);
 
-               if (fa->fa_state & FA_S_ACCESSED)
-                       rt_cache_flush(-1);
+       if (fa->fa_state & FA_S_ACCESSED)
+               rt_cache_flush(-1);
 
-               fn_free_alias(fa);
-               return 0;
-       }
-       return -ESRCH;
+       fib_release_info(fa->fa_info);
+       alias_free_mem_rcu(fa);
+       return 0;
 }
 
 static int trie_flush_list(struct trie *t, struct list_head *head)
@@ -1706,14 +1618,11 @@ static int trie_flush_list(struct trie *t, struct list_head *head)
 
        list_for_each_entry_safe(fa, fa_node, head, fa_list) {
                struct fib_info *fi = fa->fa_info;
-       
-               if (fi && (fi->fib_flags&RTNH_F_DEAD)) {
-
-                       write_lock_bh(&fib_lock);
-                       list_del(&fa->fa_list);
-                       write_unlock_bh(&fib_lock);
 
-                       fn_free_alias(fa);
+               if (fi && (fi->fib_flags & RTNH_F_DEAD)) {
+                       list_del_rcu(&fa->fa_list);
+                       fib_release_info(fa->fa_info);
+                       alias_free_mem_rcu(fa);
                        found++;
                }
        }
@@ -1728,37 +1637,34 @@ static int trie_flush_leaf(struct trie *t, struct leaf *l)
        struct leaf_info *li = NULL;
 
        hlist_for_each_entry_safe(li, node, tmp, lih, hlist) {
-               
                found += trie_flush_list(t, &li->falh);
 
                if (list_empty(&li->falh)) {
-
-                       write_lock_bh(&fib_lock);
-                       hlist_del(&li->hlist);
-                       write_unlock_bh(&fib_lock);
-
+                       hlist_del_rcu(&li->hlist);
                        free_leaf_info(li);
                }
        }
        return found;
 }
 
+/* rcu_read_lock needs to be hold by caller from readside */
+
 static struct leaf *nextleaf(struct trie *t, struct leaf *thisleaf)
 {
        struct node *c = (struct node *) thisleaf;
        struct tnode *p;
        int idx;
+       struct node *trie = rcu_dereference(t->trie);
 
        if (c == NULL) {
-               if (t->trie == NULL)
+               if (trie == NULL)
                        return NULL;
 
-               if (IS_LEAF(t->trie))          /* trie w. just a leaf */
-                       return (struct leaf *) t->trie;
+               if (IS_LEAF(trie))          /* trie w. just a leaf */
+                       return (struct leaf *) trie;
 
-               p = (struct tnode*) t->trie;  /* Start */
-       }
-       else
+               p = (struct tnode*) trie;  /* Start */
+       } else
                p = (struct tnode *) NODE_PARENT(c);
 
        while (p) {
@@ -1771,29 +1677,31 @@ static struct leaf *nextleaf(struct trie *t, struct leaf *thisleaf)
                        pos = 0;
 
                last = 1 << p->bits;
-               for(idx = pos; idx < last ; idx++) {
-                       if (p->child[idx]) {
-
-                               /* Decend if tnode */
-
-                               while (IS_TNODE(p->child[idx])) {
-                                       p = (struct tnode*) p->child[idx];
-                                       idx = 0;
-                               
-                                       /* Rightmost non-NULL branch */
-                                       if (p && IS_TNODE(p))
-                                               while (p->child[idx] == NULL && idx < (1 << p->bits)) idx++;
-
-                                       /* Done with this tnode? */
-                                       if (idx >= (1 << p->bits) || p->child[idx] == NULL )
-                                               goto up;
-                               }
-                               return (struct leaf*) p->child[idx];
+               for (idx = pos; idx < last ; idx++) {
+                       c = rcu_dereference(p->child[idx]);
+
+                       if (!c)
+                               continue;
+
+                       /* Decend if tnode */
+                       while (IS_TNODE(c)) {
+                               p = (struct tnode *) c;
+                               idx = 0;
+
+                               /* Rightmost non-NULL branch */
+                               if (p && IS_TNODE(p))
+                                       while (!(c = rcu_dereference(p->child[idx]))
+                                              && idx < (1<<p->bits)) idx++;
+
+                               /* Done with this tnode? */
+                               if (idx >= (1 << p->bits) || !c)
+                                       goto up;
                        }
+                       return (struct leaf *) c;
                }
 up:
                /* No more children go up one step  */
-               c = (struct node*) p;
+               c = (struct node *) p;
                p = (struct tnode *) NODE_PARENT(p);
        }
        return NULL; /* Ready. Root of trie */
@@ -1807,23 +1715,24 @@ static int fn_trie_flush(struct fib_table *tb)
 
        t->revision++;
 
-       for (h=0; (l = nextleaf(t, l)) != NULL; h++) {
+       rcu_read_lock();
+       for (h = 0; (l = nextleaf(t, l)) != NULL; h++) {
                found += trie_flush_leaf(t, l);
 
                if (ll && hlist_empty(&ll->list))
                        trie_leaf_remove(t, ll->key);
                ll = l;
        }
+       rcu_read_unlock();  
 
        if (ll && hlist_empty(&ll->list))
                trie_leaf_remove(t, ll->key);
 
-       if (trie_debug)
-               printk("trie_flush found=%d\n", found);
+       pr_debug("trie_flush found=%d\n", found);
        return found;
 }
 
-static int trie_last_dflt=-1;
+static int trie_last_dflt = -1;
 
 static void
 fn_trie_select_default(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
@@ -1840,7 +1749,7 @@ fn_trie_select_default(struct fib_table *tb, const struct flowi *flp, struct fib
        last_resort = NULL;
        order = -1;
 
-       read_lock(&fib_lock);
+       rcu_read_lock();
 
        l = fib_find_node(t, 0);
        if (!l)
@@ -1853,20 +1762,20 @@ fn_trie_select_default(struct fib_table *tb, const struct flowi *flp, struct fib
        if (list_empty(fa_head))
                goto out;
 
-       list_for_each_entry(fa, fa_head, fa_list) {
+       list_for_each_entry_rcu(fa, fa_head, fa_list) {
                struct fib_info *next_fi = fa->fa_info;
-       
+
                if (fa->fa_scope != res->scope ||
                    fa->fa_type != RTN_UNICAST)
                        continue;
-       
+
                if (next_fi->fib_priority > res->fi->fib_priority)
                        break;
                if (!next_fi->fib_nh[0].nh_gw ||
                    next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
                        continue;
                fa->fa_state |= FA_S_ACCESSED;
-       
+
                if (fi == NULL) {
                        if (next_fi != res->fi)
                                break;
@@ -1904,7 +1813,7 @@ fn_trie_select_default(struct fib_table *tb, const struct flowi *flp, struct fib
        }
        trie_last_dflt = last_idx;
  out:;
-       read_unlock(&fib_lock);
+       rcu_read_unlock();
 }
 
 static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fib_table *tb,
@@ -1913,12 +1822,14 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fi
        int i, s_i;
        struct fib_alias *fa;
 
-       u32 xkey=htonl(key);
+       u32 xkey = htonl(key);
 
-       s_i=cb->args[3];
+       s_i = cb->args[3];
        i = 0;
 
-       list_for_each_entry(fa, fah, fa_list) {
+       /* rcu_read_lock is hold by caller */
+
+       list_for_each_entry_rcu(fa, fah, fa_list) {
                if (i < s_i) {
                        i++;
                        continue;
@@ -1946,10 +1857,10 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fi
                                  fa->fa_info, 0) < 0) {
                        cb->args[3] = i;
                        return -1;
-                       }
+               }
                i++;
        }
-       cb->args[3]=i;
+       cb->args[3] = i;
        return skb->len;
 }
 
@@ -1959,10 +1870,10 @@ static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb, str
        int h, s_h;
        struct list_head *fa_head;
        struct leaf *l = NULL;
-       s_h=cb->args[2];
 
-       for (h=0; (l = nextleaf(t, l)) != NULL; h++) {
+       s_h = cb->args[2];
 
+       for (h = 0; (l = nextleaf(t, l)) != NULL; h++) {
                if (h < s_h)
                        continue;
                if (h > s_h)
@@ -1970,7 +1881,7 @@ static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb, str
                               sizeof(cb->args) - 3*sizeof(cb->args[0]));
 
                fa_head = get_fa_head(l, plen);
-       
+
                if (!fa_head)
                        continue;
 
@@ -1978,11 +1889,11 @@ static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb, str
                        continue;
 
                if (fn_trie_dump_fa(l->key, plen, fa_head, tb, skb, cb)<0) {
-                       cb->args[2]=h;
+                       cb->args[2] = h;
                        return -1;
                }
        }
-       cb->args[2]=h;
+       cb->args[2] = h;
        return skb->len;
 }
 
@@ -1993,25 +1904,24 @@ static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin
 
        s_m = cb->args[1];
 
-       read_lock(&fib_lock);
-       for (m=0; m<=32; m++) {
-
+       rcu_read_lock();
+       for (m = 0; m <= 32; m++) {
                if (m < s_m)
                        continue;
                if (m > s_m)
                        memset(&cb->args[2], 0,
-                              sizeof(cb->args) - 2*sizeof(cb->args[0]));
+                               sizeof(cb->args) - 2*sizeof(cb->args[0]));
 
                if (fn_trie_dump_plen(t, 32-m, tb, skb, cb)<0) {
                        cb->args[1] = m;
                        goto out;
                }
        }
-       read_unlock(&fib_lock);
+       rcu_read_unlock();
        cb->args[1] = m;
        return skb->len;
- out:
-       read_unlock(&fib_lock);
+out:
+       rcu_read_unlock();
        return -1;
 }
 
@@ -2051,9 +1961,9 @@ struct fib_table * __init fib_hash_init(int id)
        trie_init(t);
 
        if (id == RT_TABLE_LOCAL)
-                trie_local = t;
+               trie_local = t;
        else if (id == RT_TABLE_MAIN)
-                trie_main = t;
+               trie_main = t;
 
        if (id == RT_TABLE_LOCAL)
                printk("IPv4 FIB: Using LC-trie version %s\n", VERSION);
@@ -2065,7 +1975,8 @@ struct fib_table * __init fib_hash_init(int id)
 
 static void putspace_seq(struct seq_file *seq, int n)
 {
-       while (n--) seq_printf(seq, " ");
+       while (n--)
+               seq_printf(seq, " ");
 }
 
 static void printbin_seq(struct seq_file *seq, unsigned int v, int bits)
@@ -2086,29 +1997,22 @@ static void printnode_seq(struct seq_file *seq, int indent, struct node *n,
                seq_printf(seq, "%d/", cindex);
                printbin_seq(seq, cindex, bits);
                seq_printf(seq, ": ");
-       }
-       else
+       } else
                seq_printf(seq, "<root>: ");
        seq_printf(seq, "%s:%p ", IS_LEAF(n)?"Leaf":"Internal node", n);
 
-       if (IS_LEAF(n))
-               seq_printf(seq, "key=%d.%d.%d.%d\n",
-                          n->key >> 24, (n->key >> 16) % 256, (n->key >> 8) % 256, n->key % 256);
-       else {
-               int plen = ((struct tnode *)n)->pos;
-               t_key prf=MASK_PFX(n->key, plen);
-               seq_printf(seq, "key=%d.%d.%d.%d/%d\n",
-                          prf >> 24, (prf >> 16) % 256, (prf >> 8) % 256, prf % 256, plen);
-       }
        if (IS_LEAF(n)) {
-               struct leaf *l=(struct leaf *)n;
+               struct leaf *l = (struct leaf *)n;
                struct fib_alias *fa;
                int i;
-               for (i=32; i>=0; i--)
-                 if (find_leaf_info(&l->list, i)) {
-               
+
+               seq_printf(seq, "key=%d.%d.%d.%d\n",
+                          n->key >> 24, (n->key >> 16) % 256, (n->key >> 8) % 256, n->key % 256);
+
+               for (i = 32; i >= 0; i--)
+                       if (find_leaf_info(&l->list, i)) {
                                struct list_head *fa_head = get_fa_head(l, i);
-                       
+
                                if (!fa_head)
                                        continue;
 
@@ -2118,17 +2022,16 @@ static void printnode_seq(struct seq_file *seq, int indent, struct node *n,
                                putspace_seq(seq, indent+2);
                                seq_printf(seq, "{/%d...dumping}\n", i);
 
-
-                               list_for_each_entry(fa, fa_head, fa_list) {
+                               list_for_each_entry_rcu(fa, fa_head, fa_list) {
                                        putspace_seq(seq, indent+2);
-                                       if (fa->fa_info->fib_nh == NULL) {
-                                               seq_printf(seq, "Error _fib_nh=NULL\n");
-                                               continue;
-                                       }
                                        if (fa->fa_info == NULL) {
                                                seq_printf(seq, "Error fa_info=NULL\n");
                                                continue;
                                        }
+                                       if (fa->fa_info->fib_nh == NULL) {
+                                               seq_printf(seq, "Error _fib_nh=NULL\n");
+                                               continue;
+                                       }
 
                                        seq_printf(seq, "{type=%d scope=%d TOS=%d}\n",
                                              fa->fa_type,
@@ -2136,11 +2039,16 @@ static void printnode_seq(struct seq_file *seq, int indent, struct node *n,
                                              fa->fa_tos);
                                }
                        }
-       }
-       else if (IS_TNODE(n)) {
+       } else {
                struct tnode *tn = (struct tnode *)n;
+               int plen = ((struct tnode *)n)->pos;
+               t_key prf = MASK_PFX(n->key, plen);
+
+               seq_printf(seq, "key=%d.%d.%d.%d/%d\n",
+                          prf >> 24, (prf >> 16) % 256, (prf >> 8) % 256, prf % 256, plen);
+
                putspace_seq(seq, indent); seq_printf(seq, "|    ");
-               seq_printf(seq, "{key prefix=%08x/", tn->key&TKEY_GET_MASK(0, tn->pos));
+               seq_printf(seq, "{key prefix=%08x/", tn->key & TKEY_GET_MASK(0, tn->pos));
                printbin_seq(seq, tkey_extract_bits(tn->key, 0, tn->pos), tn->pos);
                seq_printf(seq, "}\n");
                putspace_seq(seq, indent); seq_printf(seq, "|    ");
@@ -2154,194 +2062,196 @@ static void printnode_seq(struct seq_file *seq, int indent, struct node *n,
 
 static void trie_dump_seq(struct seq_file *seq, struct trie *t)
 {
-       struct node *n = t->trie;
-       int cindex=0;
-       int indent=1;
-       int pend=0;
+       struct node *n;
+       int cindex = 0;
+       int indent = 1;
+       int pend = 0;
        int depth = 0;
+       struct tnode *tn;
 
-       read_lock(&fib_lock);
-
+       rcu_read_lock();
+       n = rcu_dereference(t->trie);
        seq_printf(seq, "------ trie_dump of t=%p ------\n", t);
-       if (n) {
-               printnode_seq(seq, indent, n, pend, cindex, 0);
-               if (IS_TNODE(n)) {
-                       struct tnode *tn = (struct tnode *)n;
-                       pend = tn->pos+tn->bits;
-                       putspace_seq(seq, indent); seq_printf(seq, "\\--\n");
-                       indent += 3;
-                       depth++;
-
-                       while (tn && cindex < (1 << tn->bits)) {
-                               if (tn->child[cindex]) {
-                               
-                                       /* Got a child */
-                               
-                                       printnode_seq(seq, indent, tn->child[cindex], pend, cindex, tn->bits);
-                                       if (IS_LEAF(tn->child[cindex])) {
-                                               cindex++;
-                                       
-                                       }
-                                       else {
-                                               /*
-                                                * New tnode. Decend one level
-                                                */
-                                       
-                                               depth++;
-                                               n = tn->child[cindex];
-                                               tn = (struct tnode *)n;
-                                               pend = tn->pos+tn->bits;
-                                               putspace_seq(seq, indent); seq_printf(seq, "\\--\n");
-                                               indent+=3;
-                                               cindex=0;
-                                       }
-                               }
-                               else
-                                       cindex++;
 
+       if (!n) {
+               seq_printf(seq, "------ trie is empty\n");
+
+               rcu_read_unlock();
+               return;
+       }
+
+       printnode_seq(seq, indent, n, pend, cindex, 0);
+
+       if (!IS_TNODE(n)) {
+               rcu_read_unlock();
+               return;
+       }
+
+       tn = (struct tnode *)n;
+       pend = tn->pos+tn->bits;
+       putspace_seq(seq, indent); seq_printf(seq, "\\--\n");
+       indent += 3;
+       depth++;
+
+       while (tn && cindex < (1 << tn->bits)) {
+               struct node *child = rcu_dereference(tn->child[cindex]);
+               if (!child)
+                       cindex++;
+               else {
+                       /* Got a child */
+                       printnode_seq(seq, indent, child, pend,
+                                     cindex, tn->bits);
+
+                       if (IS_LEAF(child))
+                               cindex++;
+
+                       else {
                                /*
-                                * Test if we are done
+                                * New tnode. Decend one level
                                 */
-                       
-                               while (cindex >= (1 << tn->bits)) {
 
-                                       /*
-                                        * Move upwards and test for root
-                                        * pop off all traversed  nodes
-                                        */
-                               
-                                       if (NODE_PARENT(tn) == NULL) {
-                                               tn = NULL;
-                                               n = NULL;
-                                               break;
-                                       }
-                                       else {
-                                               cindex = tkey_extract_bits(tn->key, NODE_PARENT(tn)->pos, NODE_PARENT(tn)->bits);
-                                               tn = NODE_PARENT(tn);
-                                               cindex++;
-                                               n = (struct node *)tn;
-                                               pend = tn->pos+tn->bits;
-                                               indent-=3;
-                                               depth--;
-                                       }
-                               }
+                               depth++;
+                               n = child;
+                               tn = (struct tnode *)n;
+                               pend = tn->pos+tn->bits;
+                               putspace_seq(seq, indent);
+                               seq_printf(seq, "\\--\n");
+                               indent += 3;
+                               cindex = 0;
                        }
                }
-               else n = NULL;
-       }
-       else seq_printf(seq, "------ trie is empty\n");
 
-       read_unlock(&fib_lock);
+               /*
+                * Test if we are done
+                */
+
+               while (cindex >= (1 << tn->bits)) {
+                       /*
+                        * Move upwards and test for root
+                        * pop off all traversed  nodes
+                        */
+
+                       if (NODE_PARENT(tn) == NULL) {
+                               tn = NULL;
+                               break;
+                       }
+
+                       cindex = tkey_extract_bits(tn->key, NODE_PARENT(tn)->pos, NODE_PARENT(tn)->bits);
+                       cindex++;
+                       tn = NODE_PARENT(tn);
+                       pend = tn->pos + tn->bits;
+                       indent -= 3;
+                       depth--;
+               }
+       }
+       rcu_read_unlock();
 }
 
 static struct trie_stat *trie_stat_new(void)
 {
-       struct trie_stat *s = kmalloc(sizeof(struct trie_stat), GFP_KERNEL);
+       struct trie_stat *s;
        int i;
 
-       if (s) {
-               s->totdepth = 0;
-               s->maxdepth = 0;
-               s->tnodes = 0;
-               s->leaves = 0;
-               s->nullpointers = 0;
-       
-               for(i=0; i< MAX_CHILDS; i++)
-                       s->nodesizes[i] = 0;
-       }
+       s = kmalloc(sizeof(struct trie_stat), GFP_KERNEL);
+       if (!s)
+               return NULL;
+
+       s->totdepth = 0;
+       s->maxdepth = 0;
+       s->tnodes = 0;
+       s->leaves = 0;
+       s->nullpointers = 0;
+
+       for (i = 0; i < MAX_CHILDS; i++)
+               s->nodesizes[i] = 0;
+
        return s;
 }
 
 static struct trie_stat *trie_collect_stats(struct trie *t)
 {
-       struct node *n = t->trie;
+       struct node *n;
        struct trie_stat *s = trie_stat_new();
        int cindex = 0;
-       int indent = 1;
        int pend = 0;
        int depth = 0;
 
-       read_lock(&fib_lock);   
+       if (!s)
+               return NULL;
 
-       if (s) {
-               if (n) {
-                       if (IS_TNODE(n)) {
-                               struct tnode *tn = (struct tnode *)n;
-                               pend = tn->pos+tn->bits;
-                               indent += 3;
-                               s->nodesizes[tn->bits]++;
-                               depth++;
+       rcu_read_lock();
+       n = rcu_dereference(t->trie);
 
-                               while (tn && cindex < (1 << tn->bits)) {
-                                       if (tn->child[cindex]) {
-                                               /* Got a child */
-                               
-                                               if (IS_LEAF(tn->child[cindex])) {
-                                                       cindex++;
-                                       
-                                                       /* stats */
-                                                       if (depth > s->maxdepth)
-                                                               s->maxdepth = depth;
-                                                       s->totdepth += depth;
-                                                       s->leaves++;
-                                               }
-                               
-                                               else {
-                                                       /*
-                                                        * New tnode. Decend one level
-                                                        */
-                                       
-                                                       s->tnodes++;
-                                                       s->nodesizes[tn->bits]++;
-                                                       depth++;
-                                       
-                                                       n = tn->child[cindex];
-                                                       tn = (struct tnode *)n;
-                                                       pend = tn->pos+tn->bits;
-
-                                                       indent += 3;
-                                                       cindex = 0;
-                                               }
-                                       }
-                                       else {
-                                               cindex++;
-                                               s->nullpointers++;
-                                       }
+       if (!n)
+               return s;
+
+       if (IS_TNODE(n)) {
+               struct tnode *tn = (struct tnode *)n;
+               pend = tn->pos+tn->bits;
+               s->nodesizes[tn->bits]++;
+               depth++;
+
+               while (tn && cindex < (1 << tn->bits)) {
+                       struct node *ch = rcu_dereference(tn->child[cindex]);
+                       if (ch) {
 
+                               /* Got a child */
+
+                               if (IS_LEAF(tn->child[cindex])) {
+                                       cindex++;
+
+                                       /* stats */
+                                       if (depth > s->maxdepth)
+                                               s->maxdepth = depth;
+                                       s->totdepth += depth;
+                                       s->leaves++;
+                               } else {
                                        /*
-                                        * Test if we are done
+                                        * New tnode. Decend one level
                                         */
-                       
-                                       while (cindex >= (1 << tn->bits)) {
-
-                                               /*
-                                                * Move upwards and test for root
-                                                * pop off all traversed  nodes
-                                                */
-
-                                       
-                                               if (NODE_PARENT(tn) == NULL) {
-                                                       tn = NULL;
-                                                       n = NULL;
-                                                       break;
-                                               }
-                                               else {
-                                                       cindex = tkey_extract_bits(tn->key, NODE_PARENT(tn)->pos, NODE_PARENT(tn)->bits);
-                                                       tn = NODE_PARENT(tn);
-                                                       cindex++;
-                                                       n = (struct node *)tn;
-                                                       pend = tn->pos+tn->bits;
-                                                       indent -= 3;
-                                                       depth--;
-                                               }
-                                       }
+
+                                       s->tnodes++;
+                                       s->nodesizes[tn->bits]++;
+                                       depth++;
+
+                                       n = ch;
+                                       tn = (struct tnode *)n;
+                                       pend = tn->pos+tn->bits;
+
+                                       cindex = 0;
                                }
+                       } else {
+                               cindex++;
+                               s->nullpointers++;
                        }
-                       else n = NULL;
+
+                       /*
+                        * Test if we are done
+                        */
+
+                       while (cindex >= (1 << tn->bits)) {
+                               /*
+                                * Move upwards and test for root
+                                * pop off all traversed  nodes
+                                */
+
+                               if (NODE_PARENT(tn) == NULL) {
+                                       tn = NULL;
+                                       n = NULL;
+                                       break;
+                               }
+
+                               cindex = tkey_extract_bits(tn->key, NODE_PARENT(tn)->pos, NODE_PARENT(tn)->bits);
+                               tn = NODE_PARENT(tn);
+                               cindex++;
+                               n = (struct node *)tn;
+                               pend = tn->pos+tn->bits;
+                               depth--;
+                       }
                }
        }
 
-       read_unlock(&fib_lock); 
+       rcu_read_unlock();
        return s;
 }
 
@@ -2359,17 +2269,22 @@ static struct fib_alias *fib_triestat_get_next(struct seq_file *seq)
 
 static void *fib_triestat_seq_start(struct seq_file *seq, loff_t *pos)
 {
-       void *v = NULL;
+       if (!ip_fib_main_table)
+               return NULL;
 
-       if (ip_fib_main_table)
-               v = *pos ? fib_triestat_get_next(seq) : SEQ_START_TOKEN;
-       return v;
+       if (*pos)
+               return fib_triestat_get_next(seq);
+       else
+               return SEQ_START_TOKEN;
 }
 
 static void *fib_triestat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
        ++*pos;
-       return v == SEQ_START_TOKEN ? fib_triestat_get_first(seq) : fib_triestat_get_next(seq);
+       if (v == SEQ_START_TOKEN)
+               return fib_triestat_get_first(seq);
+       else
+               return fib_triestat_get_next(seq);
 }
 
 static void fib_triestat_seq_stop(struct seq_file *seq, void *v)
@@ -2388,22 +2303,22 @@ static void collect_and_show(struct trie *t, struct seq_file *seq)
 {
        int bytes = 0; /* How many bytes are used, a ref is 4 bytes */
        int i, max, pointers;
-        struct trie_stat *stat;
+       struct trie_stat *stat;
        int avdepth;
 
        stat = trie_collect_stats(t);
 
-       bytes=0;
+       bytes = 0;
        seq_printf(seq, "trie=%p\n", t);
 
        if (stat) {
                if (stat->leaves)
-                       avdepth=stat->totdepth*100 / stat->leaves;
+                       avdepth = stat->totdepth*100 / stat->leaves;
                else
-                       avdepth=0;
-               seq_printf(seq, "Aver depth: %d.%02d\n", avdepth / 100, avdepth % 100 );
+                       avdepth = 0;
+               seq_printf(seq, "Aver depth: %d.%02d\n", avdepth / 100, avdepth % 100);
                seq_printf(seq, "Max depth: %4d\n", stat->maxdepth);
-                       
+
                seq_printf(seq, "Leaves: %d\n", stat->leaves);
                bytes += sizeof(struct leaf) * stat->leaves;
                seq_printf(seq, "Internal nodes: %d\n", stat->tnodes);
@@ -2455,11 +2370,9 @@ static int fib_triestat_seq_show(struct seq_file *seq, void *v)
 
                if (trie_main)
                        collect_and_show(trie_main, seq);
-       }
-       else {
-               snprintf(bf, sizeof(bf),
-                        "*\t%08X\t%08X", 200, 400);
-       
+       } else {
+               snprintf(bf, sizeof(bf), "*\t%08X\t%08X", 200, 400);
+
                seq_printf(seq, "%-127s\n", bf);
        }
        return 0;
@@ -2520,22 +2433,27 @@ static struct fib_alias *fib_trie_get_next(struct seq_file *seq)
 
 static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos)
 {
-       void *v = NULL;
+       if (!ip_fib_main_table)
+               return NULL;
 
-       if (ip_fib_main_table)
-               v = *pos ? fib_trie_get_next(seq) : SEQ_START_TOKEN;
-       return v;
+       if (*pos)
+               return fib_trie_get_next(seq);
+       else
+               return SEQ_START_TOKEN;
 }
 
 static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
        ++*pos;
-       return v == SEQ_START_TOKEN ? fib_trie_get_first(seq) : fib_trie_get_next(seq);
+       if (v == SEQ_START_TOKEN)
+               return fib_trie_get_first(seq);
+       else
+               return fib_trie_get_next(seq);
+
 }
 
 static void fib_trie_seq_stop(struct seq_file *seq, void *v)
 {
-
 }
 
 /*
@@ -2555,9 +2473,7 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
 
                if (trie_main)
                        trie_dump_seq(seq, trie_main);
-       }
-
-       else {
+       } else {
                snprintf(bf, sizeof(bf),
                         "*\t%08X\t%08X", 200, 400);
                seq_printf(seq, "%-127s\n", bf);
index badfc584997336ff5dc94a49c13420796de68060..24eb56ae1b5ac4e5d4f6235654a899ea676e4039 100644 (file)
@@ -114,7 +114,7 @@ struct icmp_bxm {
 /*
  *     Statistics
  */
-DEFINE_SNMP_STAT(struct icmp_mib, icmp_statistics);
+DEFINE_SNMP_STAT(struct icmp_mib, icmp_statistics) __read_mostly;
 
 /* An array of errno for error messages from dest unreach. */
 /* RFC 1122: 3.2.2.1 States that NET_UNREACH, HOST_UNREACH and SR_FAILED MUST be considered 'transient errs'. */
@@ -627,11 +627,10 @@ static void icmp_unreach(struct sk_buff *skb)
                        break;
                case ICMP_FRAG_NEEDED:
                        if (ipv4_config.no_pmtu_disc) {
-                               LIMIT_NETDEBUG(
-                                       printk(KERN_INFO "ICMP: %u.%u.%u.%u: "
+                               LIMIT_NETDEBUG(KERN_INFO "ICMP: %u.%u.%u.%u: "
                                                         "fragmentation needed "
                                                         "and DF set.\n",
-                                              NIPQUAD(iph->daddr)));
+                                              NIPQUAD(iph->daddr));
                        } else {
                                info = ip_rt_frag_needed(iph,
                                                     ntohs(icmph->un.frag.mtu));
@@ -640,10 +639,9 @@ static void icmp_unreach(struct sk_buff *skb)
                        }
                        break;
                case ICMP_SR_FAILED:
-                       LIMIT_NETDEBUG(
-                               printk(KERN_INFO "ICMP: %u.%u.%u.%u: Source "
+                       LIMIT_NETDEBUG(KERN_INFO "ICMP: %u.%u.%u.%u: Source "
                                                 "Route Failed.\n",
-                                      NIPQUAD(iph->daddr)));
+                                      NIPQUAD(iph->daddr));
                        break;
                default:
                        break;
@@ -936,7 +934,7 @@ int icmp_rcv(struct sk_buff *skb)
        case CHECKSUM_HW:
                if (!(u16)csum_fold(skb->csum))
                        break;
-               LIMIT_NETDEBUG(printk(KERN_DEBUG "icmp v4 hw csum failure\n"));
+               LIMIT_NETDEBUG(KERN_DEBUG "icmp v4 hw csum failure\n");
        case CHECKSUM_NONE:
                if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0)))
                        goto error;
index 5088f90835ae00694a31a8cdfa9b91829a4c5396..44607f4767b871820f5d33ab9dfd230e59933745 100644 (file)
@@ -904,7 +904,7 @@ int igmp_rcv(struct sk_buff *skb)
        case IGMP_MTRACE_RESP:
                break;
        default:
-               NETDEBUG(printk(KERN_DEBUG "New IGMP type=%d, why we do not know about it?\n", ih->type));
+               NETDEBUG(KERN_DEBUG "New IGMP type=%d, why we do not know about it?\n", ih->type);
        }
        in_dev_put(in_dev);
        kfree_skb(skb);
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
new file mode 100644 (file)
index 0000000..fe3c6d3
--- /dev/null
@@ -0,0 +1,641 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the  BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             Support for INET connection oriented protocols.
+ *
+ * Authors:    See the TCP sources
+ *
+ *             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/module.h>
+#include <linux/jhash.h>
+
+#include <net/inet_connection_sock.h>
+#include <net/inet_hashtables.h>
+#include <net/inet_timewait_sock.h>
+#include <net/ip.h>
+#include <net/route.h>
+#include <net/tcp_states.h>
+#include <net/xfrm.h>
+
+#ifdef INET_CSK_DEBUG
+const char inet_csk_timer_bug_msg[] = "inet_csk BUG: unknown timer value\n";
+EXPORT_SYMBOL(inet_csk_timer_bug_msg);
+#endif
+
+/*
+ * This array holds the first and last local port number.
+ * For high-usage systems, use sysctl to change this to
+ * 32768-61000
+ */
+int sysctl_local_port_range[2] = { 1024, 4999 };
+
+static inline int inet_csk_bind_conflict(struct sock *sk, struct inet_bind_bucket *tb)
+{
+       const u32 sk_rcv_saddr = inet_rcv_saddr(sk);
+       struct sock *sk2;
+       struct hlist_node *node;
+       int reuse = sk->sk_reuse;
+
+       sk_for_each_bound(sk2, node, &tb->owners) {
+               if (sk != sk2 &&
+                   !inet_v6_ipv6only(sk2) &&
+                   (!sk->sk_bound_dev_if ||
+                    !sk2->sk_bound_dev_if ||
+                    sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) {
+                       if (!reuse || !sk2->sk_reuse ||
+                           sk2->sk_state == TCP_LISTEN) {
+                               const u32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
+                               if (!sk2_rcv_saddr || !sk_rcv_saddr ||
+                                   sk2_rcv_saddr == sk_rcv_saddr)
+                                       break;
+                       }
+               }
+       }
+       return node != NULL;
+}
+
+/* Obtain a reference to a local port for the given sock,
+ * if snum is zero it means select any available local port.
+ */
+int inet_csk_get_port(struct inet_hashinfo *hashinfo,
+                     struct sock *sk, unsigned short snum)
+{
+       struct inet_bind_hashbucket *head;
+       struct hlist_node *node;
+       struct inet_bind_bucket *tb;
+       int ret;
+
+       local_bh_disable();
+       if (!snum) {
+               int low = sysctl_local_port_range[0];
+               int high = sysctl_local_port_range[1];
+               int remaining = (high - low) + 1;
+               int rover;
+
+               spin_lock(&hashinfo->portalloc_lock);
+               if (hashinfo->port_rover < low)
+                       rover = low;
+               else
+                       rover = hashinfo->port_rover;
+               do {
+                       rover++;
+                       if (rover > high)
+                               rover = low;
+                       head = &hashinfo->bhash[inet_bhashfn(rover, hashinfo->bhash_size)];
+                       spin_lock(&head->lock);
+                       inet_bind_bucket_for_each(tb, node, &head->chain)
+                               if (tb->port == rover)
+                                       goto next;
+                       break;
+               next:
+                       spin_unlock(&head->lock);
+               } while (--remaining > 0);
+               hashinfo->port_rover = rover;
+               spin_unlock(&hashinfo->portalloc_lock);
+
+               /* Exhausted local port range during search?  It is not
+                * possible for us to be holding one of the bind hash
+                * locks if this test triggers, because if 'remaining'
+                * drops to zero, we broke out of the do/while loop at
+                * the top level, not from the 'break;' statement.
+                */
+               ret = 1;
+               if (remaining <= 0)
+                       goto fail;
+
+               /* OK, here is the one we will use.  HEAD is
+                * non-NULL and we hold it's mutex.
+                */
+               snum = rover;
+       } else {
+               head = &hashinfo->bhash[inet_bhashfn(snum, hashinfo->bhash_size)];
+               spin_lock(&head->lock);
+               inet_bind_bucket_for_each(tb, node, &head->chain)
+                       if (tb->port == snum)
+                               goto tb_found;
+       }
+       tb = NULL;
+       goto tb_not_found;
+tb_found:
+       if (!hlist_empty(&tb->owners)) {
+               if (sk->sk_reuse > 1)
+                       goto success;
+               if (tb->fastreuse > 0 &&
+                   sk->sk_reuse && sk->sk_state != TCP_LISTEN) {
+                       goto success;
+               } else {
+                       ret = 1;
+                       if (inet_csk_bind_conflict(sk, tb))
+                               goto fail_unlock;
+               }
+       }
+tb_not_found:
+       ret = 1;
+       if (!tb && (tb = inet_bind_bucket_create(hashinfo->bind_bucket_cachep, head, snum)) == NULL)
+               goto fail_unlock;
+       if (hlist_empty(&tb->owners)) {
+               if (sk->sk_reuse && sk->sk_state != TCP_LISTEN)
+                       tb->fastreuse = 1;
+               else
+                       tb->fastreuse = 0;
+       } else if (tb->fastreuse &&
+                  (!sk->sk_reuse || sk->sk_state == TCP_LISTEN))
+               tb->fastreuse = 0;
+success:
+       if (!inet_csk(sk)->icsk_bind_hash)
+               inet_bind_hash(sk, tb, snum);
+       BUG_TRAP(inet_csk(sk)->icsk_bind_hash == tb);
+       ret = 0;
+
+fail_unlock:
+       spin_unlock(&head->lock);
+fail:
+       local_bh_enable();
+       return ret;
+}
+
+EXPORT_SYMBOL_GPL(inet_csk_get_port);
+
+/*
+ * Wait for an incoming connection, avoid race conditions. This must be called
+ * with the socket locked.
+ */
+static int inet_csk_wait_for_connect(struct sock *sk, long timeo)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       DEFINE_WAIT(wait);
+       int err;
+
+       /*
+        * True wake-one mechanism for incoming connections: only
+        * one process gets woken up, not the 'whole herd'.
+        * Since we do not 'race & poll' for established sockets
+        * anymore, the common case will execute the loop only once.
+        *
+        * Subtle issue: "add_wait_queue_exclusive()" will be added
+        * after any current non-exclusive waiters, and we know that
+        * it will always _stay_ after any new non-exclusive waiters
+        * because all non-exclusive waiters are added at the
+        * beginning of the wait-queue. As such, it's ok to "drop"
+        * our exclusiveness temporarily when we get woken up without
+        * having to remove and re-insert us on the wait queue.
+        */
+       for (;;) {
+               prepare_to_wait_exclusive(sk->sk_sleep, &wait,
+                                         TASK_INTERRUPTIBLE);
+               release_sock(sk);
+               if (reqsk_queue_empty(&icsk->icsk_accept_queue))
+                       timeo = schedule_timeout(timeo);
+               lock_sock(sk);
+               err = 0;
+               if (!reqsk_queue_empty(&icsk->icsk_accept_queue))
+                       break;
+               err = -EINVAL;
+               if (sk->sk_state != TCP_LISTEN)
+                       break;
+               err = sock_intr_errno(timeo);
+               if (signal_pending(current))
+                       break;
+               err = -EAGAIN;
+               if (!timeo)
+                       break;
+       }
+       finish_wait(sk->sk_sleep, &wait);
+       return err;
+}
+
+/*
+ * This will accept the next outstanding connection.
+ */
+struct sock *inet_csk_accept(struct sock *sk, int flags, int *err)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       struct sock *newsk;
+       int error;
+
+       lock_sock(sk);
+
+       /* We need to make sure that this socket is listening,
+        * and that it has something pending.
+        */
+       error = -EINVAL;
+       if (sk->sk_state != TCP_LISTEN)
+               goto out_err;
+
+       /* Find already established connection */
+       if (reqsk_queue_empty(&icsk->icsk_accept_queue)) {
+               long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
+
+               /* If this is a non blocking socket don't sleep */
+               error = -EAGAIN;
+               if (!timeo)
+                       goto out_err;
+
+               error = inet_csk_wait_for_connect(sk, timeo);
+               if (error)
+                       goto out_err;
+       }
+
+       newsk = reqsk_queue_get_child(&icsk->icsk_accept_queue, sk);
+       BUG_TRAP(newsk->sk_state != TCP_SYN_RECV);
+out:
+       release_sock(sk);
+       return newsk;
+out_err:
+       newsk = NULL;
+       *err = error;
+       goto out;
+}
+
+EXPORT_SYMBOL(inet_csk_accept);
+
+/*
+ * Using different timers for retransmit, delayed acks and probes
+ * We may wish use just one timer maintaining a list of expire jiffies 
+ * to optimize.
+ */
+void inet_csk_init_xmit_timers(struct sock *sk,
+                              void (*retransmit_handler)(unsigned long),
+                              void (*delack_handler)(unsigned long),
+                              void (*keepalive_handler)(unsigned long))
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       init_timer(&icsk->icsk_retransmit_timer);
+       init_timer(&icsk->icsk_delack_timer);
+       init_timer(&sk->sk_timer);
+
+       icsk->icsk_retransmit_timer.function = retransmit_handler;
+       icsk->icsk_delack_timer.function     = delack_handler;
+       sk->sk_timer.function                = keepalive_handler;
+
+       icsk->icsk_retransmit_timer.data = 
+               icsk->icsk_delack_timer.data =
+                       sk->sk_timer.data  = (unsigned long)sk;
+
+       icsk->icsk_pending = icsk->icsk_ack.pending = 0;
+}
+
+EXPORT_SYMBOL(inet_csk_init_xmit_timers);
+
+void inet_csk_clear_xmit_timers(struct sock *sk)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       icsk->icsk_pending = icsk->icsk_ack.pending = icsk->icsk_ack.blocked = 0;
+
+       sk_stop_timer(sk, &icsk->icsk_retransmit_timer);
+       sk_stop_timer(sk, &icsk->icsk_delack_timer);
+       sk_stop_timer(sk, &sk->sk_timer);
+}
+
+EXPORT_SYMBOL(inet_csk_clear_xmit_timers);
+
+void inet_csk_delete_keepalive_timer(struct sock *sk)
+{
+       sk_stop_timer(sk, &sk->sk_timer);
+}
+
+EXPORT_SYMBOL(inet_csk_delete_keepalive_timer);
+
+void inet_csk_reset_keepalive_timer(struct sock *sk, unsigned long len)
+{
+       sk_reset_timer(sk, &sk->sk_timer, jiffies + len);
+}
+
+EXPORT_SYMBOL(inet_csk_reset_keepalive_timer);
+
+struct dst_entry* inet_csk_route_req(struct sock *sk,
+                                    const struct request_sock *req)
+{
+       struct rtable *rt;
+       const struct inet_request_sock *ireq = inet_rsk(req);
+       struct ip_options *opt = inet_rsk(req)->opt;
+       struct flowi fl = { .oif = sk->sk_bound_dev_if,
+                           .nl_u = { .ip4_u =
+                                     { .daddr = ((opt && opt->srr) ?
+                                                 opt->faddr :
+                                                 ireq->rmt_addr),
+                                       .saddr = ireq->loc_addr,
+                                       .tos = RT_CONN_FLAGS(sk) } },
+                           .proto = sk->sk_protocol,
+                           .uli_u = { .ports =
+                                      { .sport = inet_sk(sk)->sport,
+                                        .dport = ireq->rmt_port } } };
+
+       if (ip_route_output_flow(&rt, &fl, sk, 0)) {
+               IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
+               return NULL;
+       }
+       if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) {
+               ip_rt_put(rt);
+               IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
+               return NULL;
+       }
+       return &rt->u.dst;
+}
+
+EXPORT_SYMBOL_GPL(inet_csk_route_req);
+
+static inline u32 inet_synq_hash(const u32 raddr, const u16 rport,
+                                const u32 rnd, const u16 synq_hsize)
+{
+       return jhash_2words(raddr, (u32)rport, rnd) & (synq_hsize - 1);
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#define AF_INET_FAMILY(fam) ((fam) == AF_INET)
+#else
+#define AF_INET_FAMILY(fam) 1
+#endif
+
+struct request_sock *inet_csk_search_req(const struct sock *sk,
+                                        struct request_sock ***prevp,
+                                        const __u16 rport, const __u32 raddr,
+                                        const __u32 laddr)
+{
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+       struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
+       struct request_sock *req, **prev;
+
+       for (prev = &lopt->syn_table[inet_synq_hash(raddr, rport, lopt->hash_rnd,
+                                                   lopt->nr_table_entries)];
+            (req = *prev) != NULL;
+            prev = &req->dl_next) {
+               const struct inet_request_sock *ireq = inet_rsk(req);
+
+               if (ireq->rmt_port == rport &&
+                   ireq->rmt_addr == raddr &&
+                   ireq->loc_addr == laddr &&
+                   AF_INET_FAMILY(req->rsk_ops->family)) {
+                       BUG_TRAP(!req->sk);
+                       *prevp = prev;
+                       break;
+               }
+       }
+
+       return req;
+}
+
+EXPORT_SYMBOL_GPL(inet_csk_search_req);
+
+void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req,
+                                  const unsigned timeout)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
+       const u32 h = inet_synq_hash(inet_rsk(req)->rmt_addr, inet_rsk(req)->rmt_port,
+                                    lopt->hash_rnd, lopt->nr_table_entries);
+
+       reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, timeout);
+       inet_csk_reqsk_queue_added(sk, timeout);
+}
+
+/* Only thing we need from tcp.h */
+extern int sysctl_tcp_synack_retries;
+
+EXPORT_SYMBOL_GPL(inet_csk_reqsk_queue_hash_add);
+
+void inet_csk_reqsk_queue_prune(struct sock *parent,
+                               const unsigned long interval,
+                               const unsigned long timeout,
+                               const unsigned long max_rto)
+{
+       struct inet_connection_sock *icsk = inet_csk(parent);
+       struct request_sock_queue *queue = &icsk->icsk_accept_queue;
+       struct listen_sock *lopt = queue->listen_opt;
+       int max_retries = icsk->icsk_syn_retries ? : sysctl_tcp_synack_retries;
+       int thresh = max_retries;
+       unsigned long now = jiffies;
+       struct request_sock **reqp, *req;
+       int i, budget;
+
+       if (lopt == NULL || lopt->qlen == 0)
+               return;
+
+       /* Normally all the openreqs are young and become mature
+        * (i.e. converted to established socket) for first timeout.
+        * If synack was not acknowledged for 3 seconds, it means
+        * one of the following things: synack was lost, ack was lost,
+        * rtt is high or nobody planned to ack (i.e. synflood).
+        * When server is a bit loaded, queue is populated with old
+        * open requests, reducing effective size of queue.
+        * When server is well loaded, queue size reduces to zero
+        * after several minutes of work. It is not synflood,
+        * it is normal operation. The solution is pruning
+        * too old entries overriding normal timeout, when
+        * situation becomes dangerous.
+        *
+        * Essentially, we reserve half of room for young
+        * embrions; and abort old ones without pity, if old
+        * ones are about to clog our table.
+        */
+       if (lopt->qlen>>(lopt->max_qlen_log-1)) {
+               int young = (lopt->qlen_young<<1);
+
+               while (thresh > 2) {
+                       if (lopt->qlen < young)
+                               break;
+                       thresh--;
+                       young <<= 1;
+               }
+       }
+
+       if (queue->rskq_defer_accept)
+               max_retries = queue->rskq_defer_accept;
+
+       budget = 2 * (lopt->nr_table_entries / (timeout / interval));
+       i = lopt->clock_hand;
+
+       do {
+               reqp=&lopt->syn_table[i];
+               while ((req = *reqp) != NULL) {
+                       if (time_after_eq(now, req->expires)) {
+                               if ((req->retrans < thresh ||
+                                    (inet_rsk(req)->acked && req->retrans < max_retries))
+                                   && !req->rsk_ops->rtx_syn_ack(parent, req, NULL)) {
+                                       unsigned long timeo;
+
+                                       if (req->retrans++ == 0)
+                                               lopt->qlen_young--;
+                                       timeo = min((timeout << req->retrans), max_rto);
+                                       req->expires = now + timeo;
+                                       reqp = &req->dl_next;
+                                       continue;
+                               }
+
+                               /* Drop this request */
+                               inet_csk_reqsk_queue_unlink(parent, req, reqp);
+                               reqsk_queue_removed(queue, req);
+                               reqsk_free(req);
+                               continue;
+                       }
+                       reqp = &req->dl_next;
+               }
+
+               i = (i + 1) & (lopt->nr_table_entries - 1);
+
+       } while (--budget > 0);
+
+       lopt->clock_hand = i;
+
+       if (lopt->qlen)
+               inet_csk_reset_keepalive_timer(parent, interval);
+}
+
+EXPORT_SYMBOL_GPL(inet_csk_reqsk_queue_prune);
+
+struct sock *inet_csk_clone(struct sock *sk, const struct request_sock *req,
+                           const unsigned int __nocast priority)
+{
+       struct sock *newsk = sk_clone(sk, priority);
+
+       if (newsk != NULL) {
+               struct inet_connection_sock *newicsk = inet_csk(newsk);
+
+               newsk->sk_state = TCP_SYN_RECV;
+               newicsk->icsk_bind_hash = NULL;
+
+               inet_sk(newsk)->dport = inet_rsk(req)->rmt_port;
+               newsk->sk_write_space = sk_stream_write_space;
+
+               newicsk->icsk_retransmits = 0;
+               newicsk->icsk_backoff     = 0;
+               newicsk->icsk_probes_out  = 0;
+
+               /* Deinitialize accept_queue to trap illegal accesses. */
+               memset(&newicsk->icsk_accept_queue, 0, sizeof(newicsk->icsk_accept_queue));
+       }
+       return newsk;
+}
+
+EXPORT_SYMBOL_GPL(inet_csk_clone);
+
+/*
+ * At this point, there should be no process reference to this
+ * socket, and thus no user references at all.  Therefore we
+ * can assume the socket waitqueue is inactive and nobody will
+ * try to jump onto it.
+ */
+void inet_csk_destroy_sock(struct sock *sk)
+{
+       BUG_TRAP(sk->sk_state == TCP_CLOSE);
+       BUG_TRAP(sock_flag(sk, SOCK_DEAD));
+
+       /* It cannot be in hash table! */
+       BUG_TRAP(sk_unhashed(sk));
+
+       /* If it has not 0 inet_sk(sk)->num, it must be bound */
+       BUG_TRAP(!inet_sk(sk)->num || inet_csk(sk)->icsk_bind_hash);
+
+       sk->sk_prot->destroy(sk);
+
+       sk_stream_kill_queues(sk);
+
+       xfrm_sk_free_policy(sk);
+
+       sk_refcnt_debug_release(sk);
+
+       atomic_dec(sk->sk_prot->orphan_count);
+       sock_put(sk);
+}
+
+EXPORT_SYMBOL(inet_csk_destroy_sock);
+
+int inet_csk_listen_start(struct sock *sk, const int nr_table_entries)
+{
+       struct inet_sock *inet = inet_sk(sk);
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       int rc = reqsk_queue_alloc(&icsk->icsk_accept_queue, nr_table_entries);
+
+       if (rc != 0)
+               return rc;
+
+       sk->sk_max_ack_backlog = 0;
+       sk->sk_ack_backlog = 0;
+       inet_csk_delack_init(sk);
+
+       /* There is race window here: we announce ourselves listening,
+        * but this transition is still not validated by get_port().
+        * It is OK, because this socket enters to hash table only
+        * after validation is complete.
+        */
+       sk->sk_state = TCP_LISTEN;
+       if (!sk->sk_prot->get_port(sk, inet->num)) {
+               inet->sport = htons(inet->num);
+
+               sk_dst_reset(sk);
+               sk->sk_prot->hash(sk);
+
+               return 0;
+       }
+
+       sk->sk_state = TCP_CLOSE;
+       __reqsk_queue_destroy(&icsk->icsk_accept_queue);
+       return -EADDRINUSE;
+}
+
+EXPORT_SYMBOL_GPL(inet_csk_listen_start);
+
+/*
+ *     This routine closes sockets which have been at least partially
+ *     opened, but not yet accepted.
+ */
+void inet_csk_listen_stop(struct sock *sk)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       struct request_sock *acc_req;
+       struct request_sock *req;
+
+       inet_csk_delete_keepalive_timer(sk);
+
+       /* make all the listen_opt local to us */
+       acc_req = reqsk_queue_yank_acceptq(&icsk->icsk_accept_queue);
+
+       /* Following specs, it would be better either to send FIN
+        * (and enter FIN-WAIT-1, it is normal close)
+        * or to send active reset (abort).
+        * Certainly, it is pretty dangerous while synflood, but it is
+        * bad justification for our negligence 8)
+        * To be honest, we are not able to make either
+        * of the variants now.                 --ANK
+        */
+       reqsk_queue_destroy(&icsk->icsk_accept_queue);
+
+       while ((req = acc_req) != NULL) {
+               struct sock *child = req->sk;
+
+               acc_req = req->dl_next;
+
+               local_bh_disable();
+               bh_lock_sock(child);
+               BUG_TRAP(!sock_owned_by_user(child));
+               sock_hold(child);
+
+               sk->sk_prot->disconnect(child, O_NONBLOCK);
+
+               sock_orphan(child);
+
+               atomic_inc(sk->sk_prot->orphan_count);
+
+               inet_csk_destroy_sock(child);
+
+               bh_unlock_sock(child);
+               local_bh_enable();
+               sock_put(child);
+
+               sk_acceptq_removed(sk);
+               __reqsk_free(req);
+       }
+       BUG_TRAP(!sk->sk_ack_backlog);
+}
+
+EXPORT_SYMBOL_GPL(inet_csk_listen_stop);
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
new file mode 100644 (file)
index 0000000..71f3c73
--- /dev/null
@@ -0,0 +1,868 @@
+/*
+ * inet_diag.c Module for monitoring INET transport protocols sockets.
+ *
+ * Version:    $Id: inet_diag.c,v 1.3 2002/02/01 22:01:04 davem Exp $
+ *
+ * Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ *     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/module.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/random.h>
+#include <linux/cache.h>
+#include <linux/init.h>
+#include <linux/time.h>
+
+#include <net/icmp.h>
+#include <net/tcp.h>
+#include <net/ipv6.h>
+#include <net/inet_common.h>
+#include <net/inet_connection_sock.h>
+#include <net/inet_hashtables.h>
+#include <net/inet_timewait_sock.h>
+#include <net/inet6_hashtables.h>
+
+#include <linux/inet.h>
+#include <linux/stddef.h>
+
+#include <linux/inet_diag.h>
+
+static const struct inet_diag_handler **inet_diag_table;
+
+struct inet_diag_entry {
+       u32 *saddr;
+       u32 *daddr;
+       u16 sport;
+       u16 dport;
+       u16 family;
+       u16 userlocks;
+};
+
+static struct sock *idiagnl;
+
+#define INET_DIAG_PUT(skb, attrtype, attrlen) \
+       RTA_DATA(__RTA_PUT(skb, attrtype, attrlen))
+
+static int inet_diag_fill(struct sk_buff *skb, struct sock *sk,
+                       int ext, u32 pid, u32 seq, u16 nlmsg_flags,
+                       const struct nlmsghdr *unlh)
+{
+       const struct inet_sock *inet = inet_sk(sk);
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+       struct inet_diag_msg *r;
+       struct nlmsghdr  *nlh;
+       void *info = NULL;
+       struct inet_diag_meminfo  *minfo = NULL;
+       unsigned char    *b = skb->tail;
+       const struct inet_diag_handler *handler;
+
+       handler = inet_diag_table[unlh->nlmsg_type];
+       BUG_ON(handler == NULL);
+
+       nlh = NLMSG_PUT(skb, pid, seq, unlh->nlmsg_type, sizeof(*r));
+       nlh->nlmsg_flags = nlmsg_flags;
+
+       r = NLMSG_DATA(nlh);
+       if (sk->sk_state != TCP_TIME_WAIT) {
+               if (ext & (1 << (INET_DIAG_MEMINFO - 1)))
+                       minfo = INET_DIAG_PUT(skb, INET_DIAG_MEMINFO,
+                                             sizeof(*minfo));
+               if (ext & (1 << (INET_DIAG_INFO - 1)))
+                       info = INET_DIAG_PUT(skb, INET_DIAG_INFO,
+                                          handler->idiag_info_size);
+               
+               if ((ext & (1 << (INET_DIAG_CONG - 1))) && icsk->icsk_ca_ops) {
+                       size_t len = strlen(icsk->icsk_ca_ops->name);
+                       strcpy(INET_DIAG_PUT(skb, INET_DIAG_CONG, len + 1),
+                              icsk->icsk_ca_ops->name);
+               }
+       }
+       r->idiag_family = sk->sk_family;
+       r->idiag_state = sk->sk_state;
+       r->idiag_timer = 0;
+       r->idiag_retrans = 0;
+
+       r->id.idiag_if = sk->sk_bound_dev_if;
+       r->id.idiag_cookie[0] = (u32)(unsigned long)sk;
+       r->id.idiag_cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1);
+
+       if (r->idiag_state == TCP_TIME_WAIT) {
+               const struct inet_timewait_sock *tw = inet_twsk(sk);
+               long tmo = tw->tw_ttd - jiffies;
+               if (tmo < 0)
+                       tmo = 0;
+
+               r->id.idiag_sport = tw->tw_sport;
+               r->id.idiag_dport = tw->tw_dport;
+               r->id.idiag_src[0] = tw->tw_rcv_saddr;
+               r->id.idiag_dst[0] = tw->tw_daddr;
+               r->idiag_state = tw->tw_substate;
+               r->idiag_timer = 3;
+               r->idiag_expires = (tmo * 1000 + HZ - 1) / HZ;
+               r->idiag_rqueue = 0;
+               r->idiag_wqueue = 0;
+               r->idiag_uid = 0;
+               r->idiag_inode = 0;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+               if (r->idiag_family == AF_INET6) {
+                       const struct tcp6_timewait_sock *tcp6tw = tcp6_twsk(sk);
+
+                       ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
+                                      &tcp6tw->tw_v6_rcv_saddr);
+                       ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
+                                      &tcp6tw->tw_v6_daddr);
+               }
+#endif
+               nlh->nlmsg_len = skb->tail - b;
+               return skb->len;
+       }
+
+       r->id.idiag_sport = inet->sport;
+       r->id.idiag_dport = inet->dport;
+       r->id.idiag_src[0] = inet->rcv_saddr;
+       r->id.idiag_dst[0] = inet->daddr;
+
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+       if (r->idiag_family == AF_INET6) {
+               struct ipv6_pinfo *np = inet6_sk(sk);
+
+               ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
+                              &np->rcv_saddr);
+               ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
+                              &np->daddr);
+       }
+#endif
+
+#define EXPIRES_IN_MS(tmo)  ((tmo - jiffies) * 1000 + HZ - 1) / HZ
+
+       if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
+               r->idiag_timer = 1;
+               r->idiag_retrans = icsk->icsk_retransmits;
+               r->idiag_expires = EXPIRES_IN_MS(icsk->icsk_timeout);
+       } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
+               r->idiag_timer = 4;
+               r->idiag_retrans = icsk->icsk_probes_out;
+               r->idiag_expires = EXPIRES_IN_MS(icsk->icsk_timeout);
+       } else if (timer_pending(&sk->sk_timer)) {
+               r->idiag_timer = 2;
+               r->idiag_retrans = icsk->icsk_probes_out;
+               r->idiag_expires = EXPIRES_IN_MS(sk->sk_timer.expires);
+       } else {
+               r->idiag_timer = 0;
+               r->idiag_expires = 0;
+       }
+#undef EXPIRES_IN_MS
+
+       r->idiag_uid = sock_i_uid(sk);
+       r->idiag_inode = sock_i_ino(sk);
+
+       if (minfo) {
+               minfo->idiag_rmem = atomic_read(&sk->sk_rmem_alloc);
+               minfo->idiag_wmem = sk->sk_wmem_queued;
+               minfo->idiag_fmem = sk->sk_forward_alloc;
+               minfo->idiag_tmem = atomic_read(&sk->sk_wmem_alloc);
+       }
+
+       handler->idiag_get_info(sk, r, info);
+
+       if (sk->sk_state < TCP_TIME_WAIT &&
+           icsk->icsk_ca_ops && icsk->icsk_ca_ops->get_info)
+               icsk->icsk_ca_ops->get_info(sk, ext, skb);
+
+       nlh->nlmsg_len = skb->tail - b;
+       return skb->len;
+
+rtattr_failure:
+nlmsg_failure:
+       skb_trim(skb, b - skb->data);
+       return -1;
+}
+
+static int inet_diag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh)
+{
+       int err;
+       struct sock *sk;
+       struct inet_diag_req *req = NLMSG_DATA(nlh);
+       struct sk_buff *rep;
+       struct inet_hashinfo *hashinfo;
+       const struct inet_diag_handler *handler;
+
+       handler = inet_diag_table[nlh->nlmsg_type];
+       BUG_ON(handler == NULL);
+       hashinfo = handler->idiag_hashinfo;
+
+       if (req->idiag_family == AF_INET) {
+               sk = inet_lookup(hashinfo, req->id.idiag_dst[0],
+                                req->id.idiag_dport, req->id.idiag_src[0],
+                                req->id.idiag_sport, req->id.idiag_if);
+       }
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+       else if (req->idiag_family == AF_INET6) {
+               sk = inet6_lookup(hashinfo,
+                                 (struct in6_addr *)req->id.idiag_dst,
+                                 req->id.idiag_dport,
+                                 (struct in6_addr *)req->id.idiag_src,
+                                 req->id.idiag_sport,
+                                 req->id.idiag_if);
+       }
+#endif
+       else {
+               return -EINVAL;
+       }
+
+       if (sk == NULL)
+               return -ENOENT;
+
+       err = -ESTALE;
+       if ((req->id.idiag_cookie[0] != INET_DIAG_NOCOOKIE ||
+            req->id.idiag_cookie[1] != INET_DIAG_NOCOOKIE) &&
+           ((u32)(unsigned long)sk != req->id.idiag_cookie[0] ||
+            (u32)((((unsigned long)sk) >> 31) >> 1) != req->id.idiag_cookie[1]))
+               goto out;
+
+       err = -ENOMEM;
+       rep = alloc_skb(NLMSG_SPACE((sizeof(struct inet_diag_msg) +
+                                    sizeof(struct inet_diag_meminfo) +
+                                    handler->idiag_info_size + 64)),
+                       GFP_KERNEL);
+       if (!rep)
+               goto out;
+
+       if (inet_diag_fill(rep, sk, req->idiag_ext,
+                        NETLINK_CB(in_skb).pid,
+                        nlh->nlmsg_seq, 0, nlh) <= 0)
+               BUG();
+
+       err = netlink_unicast(idiagnl, rep, NETLINK_CB(in_skb).pid,
+                             MSG_DONTWAIT);
+       if (err > 0)
+               err = 0;
+
+out:
+       if (sk) {
+               if (sk->sk_state == TCP_TIME_WAIT)
+                       inet_twsk_put((struct inet_timewait_sock *)sk);
+               else
+                       sock_put(sk);
+       }
+       return err;
+}
+
+static int bitstring_match(const u32 *a1, const u32 *a2, int bits)
+{
+       int words = bits >> 5;
+
+       bits &= 0x1f;
+
+       if (words) {
+               if (memcmp(a1, a2, words << 2))
+                       return 0;
+       }
+       if (bits) {
+               __u32 w1, w2;
+               __u32 mask;
+
+               w1 = a1[words];
+               w2 = a2[words];
+
+               mask = htonl((0xffffffff) << (32 - bits));
+
+               if ((w1 ^ w2) & mask)
+                       return 0;
+       }
+
+       return 1;
+}
+
+
+static int inet_diag_bc_run(const void *bc, int len,
+                         const struct inet_diag_entry *entry)
+{
+       while (len > 0) {
+               int yes = 1;
+               const struct inet_diag_bc_op *op = bc;
+
+               switch (op->code) {
+               case INET_DIAG_BC_NOP:
+                       break;
+               case INET_DIAG_BC_JMP:
+                       yes = 0;
+                       break;
+               case INET_DIAG_BC_S_GE:
+                       yes = entry->sport >= op[1].no;
+                       break;
+               case INET_DIAG_BC_S_LE:
+                       yes = entry->dport <= op[1].no;
+                       break;
+               case INET_DIAG_BC_D_GE:
+                       yes = entry->dport >= op[1].no;
+                       break;
+               case INET_DIAG_BC_D_LE:
+                       yes = entry->dport <= op[1].no;
+                       break;
+               case INET_DIAG_BC_AUTO:
+                       yes = !(entry->userlocks & SOCK_BINDPORT_LOCK);
+                       break;
+               case INET_DIAG_BC_S_COND:
+               case INET_DIAG_BC_D_COND: {
+                       struct inet_diag_hostcond *cond;
+                       u32 *addr;
+
+                       cond = (struct inet_diag_hostcond *)(op + 1);
+                       if (cond->port != -1 &&
+                           cond->port != (op->code == INET_DIAG_BC_S_COND ?
+                                            entry->sport : entry->dport)) {
+                               yes = 0;
+                               break;
+                       }
+                       
+                       if (cond->prefix_len == 0)
+                               break;
+
+                       if (op->code == INET_DIAG_BC_S_COND)
+                               addr = entry->saddr;
+                       else
+                               addr = entry->daddr;
+
+                       if (bitstring_match(addr, cond->addr, cond->prefix_len))
+                               break;
+                       if (entry->family == AF_INET6 &&
+                           cond->family == AF_INET) {
+                               if (addr[0] == 0 && addr[1] == 0 &&
+                                   addr[2] == htonl(0xffff) &&
+                                   bitstring_match(addr + 3, cond->addr,
+                                                   cond->prefix_len))
+                                       break;
+                       }
+                       yes = 0;
+                       break;
+               }
+               }
+
+               if (yes) { 
+                       len -= op->yes;
+                       bc += op->yes;
+               } else {
+                       len -= op->no;
+                       bc += op->no;
+               }
+       }
+       return (len == 0);
+}
+
+static int valid_cc(const void *bc, int len, int cc)
+{
+       while (len >= 0) {
+               const struct inet_diag_bc_op *op = bc;
+
+               if (cc > len)
+                       return 0;
+               if (cc == len)
+                       return 1;
+               if (op->yes < 4)
+                       return 0;
+               len -= op->yes;
+               bc  += op->yes;
+       }
+       return 0;
+}
+
+static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
+{
+       const unsigned char *bc = bytecode;
+       int  len = bytecode_len;
+
+       while (len > 0) {
+               struct inet_diag_bc_op *op = (struct inet_diag_bc_op *)bc;
+
+//printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len);
+               switch (op->code) {
+               case INET_DIAG_BC_AUTO:
+               case INET_DIAG_BC_S_COND:
+               case INET_DIAG_BC_D_COND:
+               case INET_DIAG_BC_S_GE:
+               case INET_DIAG_BC_S_LE:
+               case INET_DIAG_BC_D_GE:
+               case INET_DIAG_BC_D_LE:
+                       if (op->yes < 4 || op->yes > len + 4)
+                               return -EINVAL;
+               case INET_DIAG_BC_JMP:
+                       if (op->no < 4 || op->no > len + 4)
+                               return -EINVAL;
+                       if (op->no < len &&
+                           !valid_cc(bytecode, bytecode_len, len - op->no))
+                               return -EINVAL;
+                       break;
+               case INET_DIAG_BC_NOP:
+                       if (op->yes < 4 || op->yes > len + 4)
+                               return -EINVAL;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               bc += op->yes;
+               len -= op->yes;
+       }
+       return len == 0 ? 0 : -EINVAL;
+}
+
+static int inet_diag_dump_sock(struct sk_buff *skb, struct sock *sk,
+                            struct netlink_callback *cb)
+{
+       struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
+
+       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
+               struct inet_diag_entry entry;
+               struct rtattr *bc = (struct rtattr *)(r + 1);
+               struct inet_sock *inet = inet_sk(sk);
+
+               entry.family = sk->sk_family;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+               if (entry.family == AF_INET6) {
+                       struct ipv6_pinfo *np = inet6_sk(sk);
+
+                       entry.saddr = np->rcv_saddr.s6_addr32;
+                       entry.daddr = np->daddr.s6_addr32;
+               } else
+#endif
+               {
+                       entry.saddr = &inet->rcv_saddr;
+                       entry.daddr = &inet->daddr;
+               }
+               entry.sport = inet->num;
+               entry.dport = ntohs(inet->dport);
+               entry.userlocks = sk->sk_userlocks;
+
+               if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
+                       return 0;
+       }
+
+       return inet_diag_fill(skb, sk, r->idiag_ext, NETLINK_CB(cb->skb).pid,
+                           cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
+}
+
+static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
+                           struct request_sock *req,
+                           u32 pid, u32 seq,
+                           const struct nlmsghdr *unlh)
+{
+       const struct inet_request_sock *ireq = inet_rsk(req);
+       struct inet_sock *inet = inet_sk(sk);
+       unsigned char *b = skb->tail;
+       struct inet_diag_msg *r;
+       struct nlmsghdr *nlh;
+       long tmo;
+
+       nlh = NLMSG_PUT(skb, pid, seq, unlh->nlmsg_type, sizeof(*r));
+       nlh->nlmsg_flags = NLM_F_MULTI;
+       r = NLMSG_DATA(nlh);
+
+       r->idiag_family = sk->sk_family;
+       r->idiag_state = TCP_SYN_RECV;
+       r->idiag_timer = 1;
+       r->idiag_retrans = req->retrans;
+
+       r->id.idiag_if = sk->sk_bound_dev_if;
+       r->id.idiag_cookie[0] = (u32)(unsigned long)req;
+       r->id.idiag_cookie[1] = (u32)(((unsigned long)req >> 31) >> 1);
+
+       tmo = req->expires - jiffies;
+       if (tmo < 0)
+               tmo = 0;
+
+       r->id.idiag_sport = inet->sport;
+       r->id.idiag_dport = ireq->rmt_port;
+       r->id.idiag_src[0] = ireq->loc_addr;
+       r->id.idiag_dst[0] = ireq->rmt_addr;
+       r->idiag_expires = jiffies_to_msecs(tmo);
+       r->idiag_rqueue = 0;
+       r->idiag_wqueue = 0;
+       r->idiag_uid = sock_i_uid(sk);
+       r->idiag_inode = 0;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+       if (r->idiag_family == AF_INET6) {
+               ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
+                              &tcp6_rsk(req)->loc_addr);
+               ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
+                              &tcp6_rsk(req)->rmt_addr);
+       }
+#endif
+       nlh->nlmsg_len = skb->tail - b;
+
+       return skb->len;
+
+nlmsg_failure:
+       skb_trim(skb, b - skb->data);
+       return -1;
+}
+
+static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
+                            struct netlink_callback *cb)
+{
+       struct inet_diag_entry entry;
+       struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       struct listen_sock *lopt;
+       struct rtattr *bc = NULL;
+       struct inet_sock *inet = inet_sk(sk);
+       int j, s_j;
+       int reqnum, s_reqnum;
+       int err = 0;
+
+       s_j = cb->args[3];
+       s_reqnum = cb->args[4];
+
+       if (s_j > 0)
+               s_j--;
+
+       entry.family = sk->sk_family;
+
+       read_lock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
+
+       lopt = icsk->icsk_accept_queue.listen_opt;
+       if (!lopt || !lopt->qlen)
+               goto out;
+
+       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
+               bc = (struct rtattr *)(r + 1);
+               entry.sport = inet->num;
+               entry.userlocks = sk->sk_userlocks;
+       }
+
+       for (j = s_j; j < lopt->nr_table_entries; j++) {
+               struct request_sock *req, *head = lopt->syn_table[j];
+
+               reqnum = 0;
+               for (req = head; req; reqnum++, req = req->dl_next) {
+                       struct inet_request_sock *ireq = inet_rsk(req);
+
+                       if (reqnum < s_reqnum)
+                               continue;
+                       if (r->id.idiag_dport != ireq->rmt_port &&
+                           r->id.idiag_dport)
+                               continue;
+
+                       if (bc) {
+                               entry.saddr =
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+                                       (entry.family == AF_INET6) ?
+                                       tcp6_rsk(req)->loc_addr.s6_addr32 :
+#endif
+                                       &ireq->loc_addr;
+                               entry.daddr = 
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+                                       (entry.family == AF_INET6) ?
+                                       tcp6_rsk(req)->rmt_addr.s6_addr32 :
+#endif
+                                       &ireq->rmt_addr;
+                               entry.dport = ntohs(ireq->rmt_port);
+
+                               if (!inet_diag_bc_run(RTA_DATA(bc),
+                                                   RTA_PAYLOAD(bc), &entry))
+                                       continue;
+                       }
+
+                       err = inet_diag_fill_req(skb, sk, req,
+                                              NETLINK_CB(cb->skb).pid,
+                                              cb->nlh->nlmsg_seq, cb->nlh);
+                       if (err < 0) {
+                               cb->args[3] = j + 1;
+                               cb->args[4] = reqnum;
+                               goto out;
+                       }
+               }
+
+               s_reqnum = 0;
+       }
+
+out:
+       read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
+
+       return err;
+}
+
+static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       int i, num;
+       int s_i, s_num;
+       struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
+       const struct inet_diag_handler *handler;
+       struct inet_hashinfo *hashinfo;
+
+       handler = inet_diag_table[cb->nlh->nlmsg_type];
+       BUG_ON(handler == NULL);
+       hashinfo = handler->idiag_hashinfo;
+               
+       s_i = cb->args[1];
+       s_num = num = cb->args[2];
+
+       if (cb->args[0] == 0) {
+               if (!(r->idiag_states & (TCPF_LISTEN | TCPF_SYN_RECV)))
+                       goto skip_listen_ht;
+
+               inet_listen_lock(hashinfo);
+               for (i = s_i; i < INET_LHTABLE_SIZE; i++) {
+                       struct sock *sk;
+                       struct hlist_node *node;
+
+                       num = 0;
+                       sk_for_each(sk, node, &hashinfo->listening_hash[i]) {
+                               struct inet_sock *inet = inet_sk(sk);
+
+                               if (num < s_num) {
+                                       num++;
+                                       continue;
+                               }
+
+                               if (r->id.idiag_sport != inet->sport &&
+                                   r->id.idiag_sport)
+                                       goto next_listen;
+
+                               if (!(r->idiag_states & TCPF_LISTEN) ||
+                                   r->id.idiag_dport ||
+                                   cb->args[3] > 0)
+                                       goto syn_recv;
+
+                               if (inet_diag_dump_sock(skb, sk, cb) < 0) {
+                                       inet_listen_unlock(hashinfo);
+                                       goto done;
+                               }
+
+syn_recv:
+                               if (!(r->idiag_states & TCPF_SYN_RECV))
+                                       goto next_listen;
+
+                               if (inet_diag_dump_reqs(skb, sk, cb) < 0) {
+                                       inet_listen_unlock(hashinfo);
+                                       goto done;
+                               }
+
+next_listen:
+                               cb->args[3] = 0;
+                               cb->args[4] = 0;
+                               ++num;
+                       }
+
+                       s_num = 0;
+                       cb->args[3] = 0;
+                       cb->args[4] = 0;
+               }
+               inet_listen_unlock(hashinfo);
+skip_listen_ht:
+               cb->args[0] = 1;
+               s_i = num = s_num = 0;
+       }
+
+       if (!(r->idiag_states & ~(TCPF_LISTEN | TCPF_SYN_RECV)))
+               return skb->len;
+
+       for (i = s_i; i < hashinfo->ehash_size; i++) {
+               struct inet_ehash_bucket *head = &hashinfo->ehash[i];
+               struct sock *sk;
+               struct hlist_node *node;
+
+               if (i > s_i)
+                       s_num = 0;
+
+               read_lock_bh(&head->lock);
+
+               num = 0;
+               sk_for_each(sk, node, &head->chain) {
+                       struct inet_sock *inet = inet_sk(sk);
+
+                       if (num < s_num)
+                               goto next_normal;
+                       if (!(r->idiag_states & (1 << sk->sk_state)))
+                               goto next_normal;
+                       if (r->id.idiag_sport != inet->sport &&
+                           r->id.idiag_sport)
+                               goto next_normal;
+                       if (r->id.idiag_dport != inet->dport && r->id.idiag_dport)
+                               goto next_normal;
+                       if (inet_diag_dump_sock(skb, sk, cb) < 0) {
+                               read_unlock_bh(&head->lock);
+                               goto done;
+                       }
+next_normal:
+                       ++num;
+               }
+
+               if (r->idiag_states & TCPF_TIME_WAIT) {
+                       sk_for_each(sk, node,
+                                   &hashinfo->ehash[i + hashinfo->ehash_size].chain) {
+                               struct inet_sock *inet = inet_sk(sk);
+
+                               if (num < s_num)
+                                       goto next_dying;
+                               if (r->id.idiag_sport != inet->sport &&
+                                   r->id.idiag_sport)
+                                       goto next_dying;
+                               if (r->id.idiag_dport != inet->dport &&
+                                   r->id.idiag_dport)
+                                       goto next_dying;
+                               if (inet_diag_dump_sock(skb, sk, cb) < 0) {
+                                       read_unlock_bh(&head->lock);
+                                       goto done;
+                               }
+next_dying:
+                               ++num;
+                       }
+               }
+               read_unlock_bh(&head->lock);
+       }
+
+done:
+       cb->args[1] = i;
+       cb->args[2] = num;
+       return skb->len;
+}
+
+static int inet_diag_dump_done(struct netlink_callback *cb)
+{
+       return 0;
+}
+
+
+static __inline__ int
+inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+       if (!(nlh->nlmsg_flags&NLM_F_REQUEST))
+               return 0;
+
+       if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX)
+               goto err_inval;
+
+       if (inet_diag_table[nlh->nlmsg_type] == NULL)
+               return -ENOENT;
+
+       if (NLMSG_LENGTH(sizeof(struct inet_diag_req)) > skb->len)
+               goto err_inval;
+
+       if (nlh->nlmsg_flags&NLM_F_DUMP) {
+               if (nlh->nlmsg_len >
+                   (4 + NLMSG_SPACE(sizeof(struct inet_diag_req)))) {
+                       struct rtattr *rta = (void *)(NLMSG_DATA(nlh) +
+                                                sizeof(struct inet_diag_req));
+                       if (rta->rta_type != INET_DIAG_REQ_BYTECODE ||
+                           rta->rta_len < 8 ||
+                           rta->rta_len >
+                           (nlh->nlmsg_len -
+                            NLMSG_SPACE(sizeof(struct inet_diag_req))))
+                               goto err_inval;
+                       if (inet_diag_bc_audit(RTA_DATA(rta), RTA_PAYLOAD(rta)))
+                               goto err_inval;
+               }
+               return netlink_dump_start(idiagnl, skb, nlh,
+                                         inet_diag_dump,
+                                         inet_diag_dump_done);
+       } else {
+               return inet_diag_get_exact(skb, nlh);
+       }
+
+err_inval:
+       return -EINVAL;
+}
+
+
+static inline void inet_diag_rcv_skb(struct sk_buff *skb)
+{
+       int err;
+       struct nlmsghdr * nlh;
+
+       if (skb->len >= NLMSG_SPACE(0)) {
+               nlh = (struct nlmsghdr *)skb->data;
+               if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
+                       return;
+               err = inet_diag_rcv_msg(skb, nlh);
+               if (err || nlh->nlmsg_flags & NLM_F_ACK) 
+                       netlink_ack(skb, nlh, err);
+       }
+}
+
+static void inet_diag_rcv(struct sock *sk, int len)
+{
+       struct sk_buff *skb;
+       unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
+
+       while (qlen-- && (skb = skb_dequeue(&sk->sk_receive_queue))) {
+               inet_diag_rcv_skb(skb);
+               kfree_skb(skb);
+       }
+}
+
+static DEFINE_SPINLOCK(inet_diag_register_lock);
+
+int inet_diag_register(const struct inet_diag_handler *h)
+{
+       const __u16 type = h->idiag_type;
+       int err = -EINVAL;
+
+       if (type >= INET_DIAG_GETSOCK_MAX)
+               goto out;
+
+       spin_lock(&inet_diag_register_lock);
+       err = -EEXIST;
+       if (inet_diag_table[type] == NULL) {
+               inet_diag_table[type] = h;
+               err = 0;
+       }
+       spin_unlock(&inet_diag_register_lock);
+out:
+       return err;
+}
+EXPORT_SYMBOL_GPL(inet_diag_register);
+
+void inet_diag_unregister(const struct inet_diag_handler *h)
+{
+       const __u16 type = h->idiag_type;
+
+       if (type >= INET_DIAG_GETSOCK_MAX)
+               return;
+
+       spin_lock(&inet_diag_register_lock);
+       inet_diag_table[type] = NULL;
+       spin_unlock(&inet_diag_register_lock);
+
+       synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(inet_diag_unregister);
+
+static int __init inet_diag_init(void)
+{
+       const int inet_diag_table_size = (INET_DIAG_GETSOCK_MAX *
+                                         sizeof(struct inet_diag_handler *));
+       int err = -ENOMEM;
+
+       inet_diag_table = kmalloc(inet_diag_table_size, GFP_KERNEL);
+       if (!inet_diag_table)
+               goto out;
+
+       memset(inet_diag_table, 0, inet_diag_table_size);
+       idiagnl = netlink_kernel_create(NETLINK_INET_DIAG, 0, inet_diag_rcv,
+                                       THIS_MODULE);
+       if (idiagnl == NULL)
+               goto out_free_table;
+       err = 0;
+out:
+       return err;
+out_free_table:
+       kfree(inet_diag_table);
+       goto out;
+}
+
+static void __exit inet_diag_exit(void)
+{
+       sock_release(idiagnl->sk_socket);
+       kfree(inet_diag_table);
+}
+
+module_init(inet_diag_init);
+module_exit(inet_diag_exit);
+MODULE_LICENSE("GPL");
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
new file mode 100644 (file)
index 0000000..e8d29fe
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             Generic INET transport hashtables
+ *
+ * Authors:    Lotsa people, from code originally in tcp
+ *
+ *     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/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+#include <net/inet_connection_sock.h>
+#include <net/inet_hashtables.h>
+
+/*
+ * Allocate and initialize a new local port bind bucket.
+ * The bindhash mutex for snum's hash chain must be held here.
+ */
+struct inet_bind_bucket *inet_bind_bucket_create(kmem_cache_t *cachep,
+                                                struct inet_bind_hashbucket *head,
+                                                const unsigned short snum)
+{
+       struct inet_bind_bucket *tb = kmem_cache_alloc(cachep, SLAB_ATOMIC);
+
+       if (tb != NULL) {
+               tb->port      = snum;
+               tb->fastreuse = 0;
+               INIT_HLIST_HEAD(&tb->owners);
+               hlist_add_head(&tb->node, &head->chain);
+       }
+       return tb;
+}
+
+EXPORT_SYMBOL(inet_bind_bucket_create);
+
+/*
+ * Caller must hold hashbucket lock for this tb with local BH disabled
+ */
+void inet_bind_bucket_destroy(kmem_cache_t *cachep, struct inet_bind_bucket *tb)
+{
+       if (hlist_empty(&tb->owners)) {
+               __hlist_del(&tb->node);
+               kmem_cache_free(cachep, tb);
+       }
+}
+
+void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb,
+                   const unsigned short snum)
+{
+       inet_sk(sk)->num = snum;
+       sk_add_bind_node(sk, &tb->owners);
+       inet_csk(sk)->icsk_bind_hash = tb;
+}
+
+EXPORT_SYMBOL(inet_bind_hash);
+
+/*
+ * Get rid of any references to a local port held by the given sock.
+ */
+static void __inet_put_port(struct inet_hashinfo *hashinfo, struct sock *sk)
+{
+       const int bhash = inet_bhashfn(inet_sk(sk)->num, hashinfo->bhash_size);
+       struct inet_bind_hashbucket *head = &hashinfo->bhash[bhash];
+       struct inet_bind_bucket *tb;
+
+       spin_lock(&head->lock);
+       tb = inet_csk(sk)->icsk_bind_hash;
+       __sk_del_bind_node(sk);
+       inet_csk(sk)->icsk_bind_hash = NULL;
+       inet_sk(sk)->num = 0;
+       inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
+       spin_unlock(&head->lock);
+}
+
+void inet_put_port(struct inet_hashinfo *hashinfo, struct sock *sk)
+{
+       local_bh_disable();
+       __inet_put_port(hashinfo, sk);
+       local_bh_enable();
+}
+
+EXPORT_SYMBOL(inet_put_port);
+
+/*
+ * This lock without WQ_FLAG_EXCLUSIVE is good on UP and it can be very bad on SMP.
+ * Look, when several writers sleep and reader wakes them up, all but one
+ * immediately hit write lock and grab all the cpus. Exclusive sleep solves
+ * this, _but_ remember, it adds useless work on UP machines (wake up each
+ * exclusive lock release). It should be ifdefed really.
+ */
+void inet_listen_wlock(struct inet_hashinfo *hashinfo)
+{
+       write_lock(&hashinfo->lhash_lock);
+
+       if (atomic_read(&hashinfo->lhash_users)) {
+               DEFINE_WAIT(wait);
+
+               for (;;) {
+                       prepare_to_wait_exclusive(&hashinfo->lhash_wait,
+                                                 &wait, TASK_UNINTERRUPTIBLE);
+                       if (!atomic_read(&hashinfo->lhash_users))
+                               break;
+                       write_unlock_bh(&hashinfo->lhash_lock);
+                       schedule();
+                       write_lock_bh(&hashinfo->lhash_lock);
+               }
+
+               finish_wait(&hashinfo->lhash_wait, &wait);
+       }
+}
+
+EXPORT_SYMBOL(inet_listen_wlock);
+
+/*
+ * Don't inline this cruft. Here are some nice properties to exploit here. The
+ * BSD API does not allow a listening sock to specify the remote port nor the
+ * remote address for the connection. So always assume those are both
+ * wildcarded during the search since they can never be otherwise.
+ */
+struct sock *__inet_lookup_listener(const struct hlist_head *head, const u32 daddr,
+                                   const unsigned short hnum, const int dif)
+{
+       struct sock *result = NULL, *sk;
+       const struct hlist_node *node;
+       int hiscore = -1;
+
+       sk_for_each(sk, node, head) {
+               const struct inet_sock *inet = inet_sk(sk);
+
+               if (inet->num == hnum && !ipv6_only_sock(sk)) {
+                       const __u32 rcv_saddr = inet->rcv_saddr;
+                       int score = sk->sk_family == PF_INET ? 1 : 0;
+
+                       if (rcv_saddr) {
+                               if (rcv_saddr != daddr)
+                                       continue;
+                               score += 2;
+                       }
+                       if (sk->sk_bound_dev_if) {
+                               if (sk->sk_bound_dev_if != dif)
+                                       continue;
+                               score += 2;
+                       }
+                       if (score == 5)
+                               return sk;
+                       if (score > hiscore) {
+                               hiscore = score;
+                               result  = sk;
+                       }
+               }
+       }
+       return result;
+}
+
+EXPORT_SYMBOL_GPL(__inet_lookup_listener);
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
new file mode 100644 (file)
index 0000000..4d1502a
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the  BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             Generic TIME_WAIT sockets functions
+ *
+ *             From code orinally in TCP
+ */
+
+#include <linux/config.h>
+
+#include <net/inet_hashtables.h>
+#include <net/inet_timewait_sock.h>
+#include <net/ip.h>
+
+/* Must be called with locally disabled BHs. */
+void __inet_twsk_kill(struct inet_timewait_sock *tw, struct inet_hashinfo *hashinfo)
+{
+       struct inet_bind_hashbucket *bhead;
+       struct inet_bind_bucket *tb;
+       /* Unlink from established hashes. */
+       struct inet_ehash_bucket *ehead = &hashinfo->ehash[tw->tw_hashent];
+
+       write_lock(&ehead->lock);
+       if (hlist_unhashed(&tw->tw_node)) {
+               write_unlock(&ehead->lock);
+               return;
+       }
+       __hlist_del(&tw->tw_node);
+       sk_node_init(&tw->tw_node);
+       write_unlock(&ehead->lock);
+
+       /* Disassociate with bind bucket. */
+       bhead = &hashinfo->bhash[inet_bhashfn(tw->tw_num, hashinfo->bhash_size)];
+       spin_lock(&bhead->lock);
+       tb = tw->tw_tb;
+       __hlist_del(&tw->tw_bind_node);
+       tw->tw_tb = NULL;
+       inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
+       spin_unlock(&bhead->lock);
+#ifdef SOCK_REFCNT_DEBUG
+       if (atomic_read(&tw->tw_refcnt) != 1) {
+               printk(KERN_DEBUG "%s timewait_sock %p refcnt=%d\n",
+                      tw->tw_prot->name, tw, atomic_read(&tw->tw_refcnt));
+       }
+#endif
+       inet_twsk_put(tw);
+}
+
+EXPORT_SYMBOL_GPL(__inet_twsk_kill);
+
+/*
+ * Enter the time wait state. This is called with locally disabled BH.
+ * Essentially we whip up a timewait bucket, copy the relevant info into it
+ * from the SK, and mess with hash chains and list linkage.
+ */
+void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
+                          struct inet_hashinfo *hashinfo)
+{
+       const struct inet_sock *inet = inet_sk(sk);
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+       struct inet_ehash_bucket *ehead = &hashinfo->ehash[sk->sk_hashent];
+       struct inet_bind_hashbucket *bhead;
+       /* Step 1: Put TW into bind hash. Original socket stays there too.
+          Note, that any socket with inet->num != 0 MUST be bound in
+          binding cache, even if it is closed.
+        */
+       bhead = &hashinfo->bhash[inet_bhashfn(inet->num, hashinfo->bhash_size)];
+       spin_lock(&bhead->lock);
+       tw->tw_tb = icsk->icsk_bind_hash;
+       BUG_TRAP(icsk->icsk_bind_hash);
+       inet_twsk_add_bind_node(tw, &tw->tw_tb->owners);
+       spin_unlock(&bhead->lock);
+
+       write_lock(&ehead->lock);
+
+       /* Step 2: Remove SK from established hash. */
+       if (__sk_del_node_init(sk))
+               sock_prot_dec_use(sk->sk_prot);
+
+       /* Step 3: Hash TW into TIMEWAIT half of established hash table. */
+       inet_twsk_add_node(tw, &(ehead + hashinfo->ehash_size)->chain);
+       atomic_inc(&tw->tw_refcnt);
+
+       write_unlock(&ehead->lock);
+}
+
+EXPORT_SYMBOL_GPL(__inet_twsk_hashdance);
+
+struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int state)
+{
+       struct inet_timewait_sock *tw = kmem_cache_alloc(sk->sk_prot_creator->twsk_slab,
+                                                        SLAB_ATOMIC);
+       if (tw != NULL) {
+               const struct inet_sock *inet = inet_sk(sk);
+
+               /* Give us an identity. */
+               tw->tw_daddr        = inet->daddr;
+               tw->tw_rcv_saddr    = inet->rcv_saddr;
+               tw->tw_bound_dev_if = sk->sk_bound_dev_if;
+               tw->tw_num          = inet->num;
+               tw->tw_state        = TCP_TIME_WAIT;
+               tw->tw_substate     = state;
+               tw->tw_sport        = inet->sport;
+               tw->tw_dport        = inet->dport;
+               tw->tw_family       = sk->sk_family;
+               tw->tw_reuse        = sk->sk_reuse;
+               tw->tw_hashent      = sk->sk_hashent;
+               tw->tw_ipv6only     = 0;
+               tw->tw_prot         = sk->sk_prot_creator;
+               atomic_set(&tw->tw_refcnt, 1);
+               inet_twsk_dead_node_init(tw);
+       }
+
+       return tw;
+}
+
+EXPORT_SYMBOL_GPL(inet_twsk_alloc);
+
+/* Returns non-zero if quota exceeded.  */
+static int inet_twdr_do_twkill_work(struct inet_timewait_death_row *twdr,
+                                   const int slot)
+{
+       struct inet_timewait_sock *tw;
+       struct hlist_node *node;
+       unsigned int killed;
+       int ret;
+
+       /* NOTE: compare this to previous version where lock
+        * was released after detaching chain. It was racy,
+        * because tw buckets are scheduled in not serialized context
+        * in 2.3 (with netfilter), and with softnet it is common, because
+        * soft irqs are not sequenced.
+        */
+       killed = 0;
+       ret = 0;
+rescan:
+       inet_twsk_for_each_inmate(tw, node, &twdr->cells[slot]) {
+               __inet_twsk_del_dead_node(tw);
+               spin_unlock(&twdr->death_lock);
+               __inet_twsk_kill(tw, twdr->hashinfo);
+               inet_twsk_put(tw);
+               killed++;
+               spin_lock(&twdr->death_lock);
+               if (killed > INET_TWDR_TWKILL_QUOTA) {
+                       ret = 1;
+                       break;
+               }
+
+               /* While we dropped twdr->death_lock, another cpu may have
+                * killed off the next TW bucket in the list, therefore
+                * do a fresh re-read of the hlist head node with the
+                * lock reacquired.  We still use the hlist traversal
+                * macro in order to get the prefetches.
+                */
+               goto rescan;
+       }
+
+       twdr->tw_count -= killed;
+       NET_ADD_STATS_BH(LINUX_MIB_TIMEWAITED, killed);
+
+       return ret;
+}
+
+void inet_twdr_hangman(unsigned long data)
+{
+       struct inet_timewait_death_row *twdr;
+       int unsigned need_timer;
+
+       twdr = (struct inet_timewait_death_row *)data;
+       spin_lock(&twdr->death_lock);
+
+       if (twdr->tw_count == 0)
+               goto out;
+
+       need_timer = 0;
+       if (inet_twdr_do_twkill_work(twdr, twdr->slot)) {
+               twdr->thread_slots |= (1 << twdr->slot);
+               mb();
+               schedule_work(&twdr->twkill_work);
+               need_timer = 1;
+       } else {
+               /* We purged the entire slot, anything left?  */
+               if (twdr->tw_count)
+                       need_timer = 1;
+       }
+       twdr->slot = ((twdr->slot + 1) & (INET_TWDR_TWKILL_SLOTS - 1));
+       if (need_timer)
+               mod_timer(&twdr->tw_timer, jiffies + twdr->period);
+out:
+       spin_unlock(&twdr->death_lock);
+}
+
+EXPORT_SYMBOL_GPL(inet_twdr_hangman);
+
+extern void twkill_slots_invalid(void);
+
+void inet_twdr_twkill_work(void *data)
+{
+       struct inet_timewait_death_row *twdr = data;
+       int i;
+
+       if ((INET_TWDR_TWKILL_SLOTS - 1) > (sizeof(twdr->thread_slots) * 8))
+               twkill_slots_invalid();
+
+       while (twdr->thread_slots) {
+               spin_lock_bh(&twdr->death_lock);
+               for (i = 0; i < INET_TWDR_TWKILL_SLOTS; i++) {
+                       if (!(twdr->thread_slots & (1 << i)))
+                               continue;
+
+                       while (inet_twdr_do_twkill_work(twdr, i) != 0) {
+                               if (need_resched()) {
+                                       spin_unlock_bh(&twdr->death_lock);
+                                       schedule();
+                                       spin_lock_bh(&twdr->death_lock);
+                               }
+                       }
+
+                       twdr->thread_slots &= ~(1 << i);
+               }
+               spin_unlock_bh(&twdr->death_lock);
+       }
+}
+
+EXPORT_SYMBOL_GPL(inet_twdr_twkill_work);
+
+/* These are always called from BH context.  See callers in
+ * tcp_input.c to verify this.
+ */
+
+/* This is for handling early-kills of TIME_WAIT sockets. */
+void inet_twsk_deschedule(struct inet_timewait_sock *tw,
+                         struct inet_timewait_death_row *twdr)
+{
+       spin_lock(&twdr->death_lock);
+       if (inet_twsk_del_dead_node(tw)) {
+               inet_twsk_put(tw);
+               if (--twdr->tw_count == 0)
+                       del_timer(&twdr->tw_timer);
+       }
+       spin_unlock(&twdr->death_lock);
+       __inet_twsk_kill(tw, twdr->hashinfo);
+}
+
+EXPORT_SYMBOL(inet_twsk_deschedule);
+
+void inet_twsk_schedule(struct inet_timewait_sock *tw,
+                      struct inet_timewait_death_row *twdr,
+                      const int timeo, const int timewait_len)
+{
+       struct hlist_head *list;
+       int slot;
+
+       /* timeout := RTO * 3.5
+        *
+        * 3.5 = 1+2+0.5 to wait for two retransmits.
+        *
+        * RATIONALE: if FIN arrived and we entered TIME-WAIT state,
+        * our ACK acking that FIN can be lost. If N subsequent retransmitted
+        * FINs (or previous seqments) are lost (probability of such event
+        * is p^(N+1), where p is probability to lose single packet and
+        * time to detect the loss is about RTO*(2^N - 1) with exponential
+        * backoff). Normal timewait length is calculated so, that we
+        * waited at least for one retransmitted FIN (maximal RTO is 120sec).
+        * [ BTW Linux. following BSD, violates this requirement waiting
+        *   only for 60sec, we should wait at least for 240 secs.
+        *   Well, 240 consumes too much of resources 8)
+        * ]
+        * This interval is not reduced to catch old duplicate and
+        * responces to our wandering segments living for two MSLs.
+        * However, if we use PAWS to detect
+        * old duplicates, we can reduce the interval to bounds required
+        * by RTO, rather than MSL. So, if peer understands PAWS, we
+        * kill tw bucket after 3.5*RTO (it is important that this number
+        * is greater than TS tick!) and detect old duplicates with help
+        * of PAWS.
+        */
+       slot = (timeo + (1 << INET_TWDR_RECYCLE_TICK) - 1) >> INET_TWDR_RECYCLE_TICK;
+
+       spin_lock(&twdr->death_lock);
+
+       /* Unlink it, if it was scheduled */
+       if (inet_twsk_del_dead_node(tw))
+               twdr->tw_count--;
+       else
+               atomic_inc(&tw->tw_refcnt);
+
+       if (slot >= INET_TWDR_RECYCLE_SLOTS) {
+               /* Schedule to slow timer */
+               if (timeo >= timewait_len) {
+                       slot = INET_TWDR_TWKILL_SLOTS - 1;
+               } else {
+                       slot = (timeo + twdr->period - 1) / twdr->period;
+                       if (slot >= INET_TWDR_TWKILL_SLOTS)
+                               slot = INET_TWDR_TWKILL_SLOTS - 1;
+               }
+               tw->tw_ttd = jiffies + timeo;
+               slot = (twdr->slot + slot) & (INET_TWDR_TWKILL_SLOTS - 1);
+               list = &twdr->cells[slot];
+       } else {
+               tw->tw_ttd = jiffies + (slot << INET_TWDR_RECYCLE_TICK);
+
+               if (twdr->twcal_hand < 0) {
+                       twdr->twcal_hand = 0;
+                       twdr->twcal_jiffie = jiffies;
+                       twdr->twcal_timer.expires = twdr->twcal_jiffie +
+                                             (slot << INET_TWDR_RECYCLE_TICK);
+                       add_timer(&twdr->twcal_timer);
+               } else {
+                       if (time_after(twdr->twcal_timer.expires,
+                                      jiffies + (slot << INET_TWDR_RECYCLE_TICK)))
+                               mod_timer(&twdr->twcal_timer,
+                                         jiffies + (slot << INET_TWDR_RECYCLE_TICK));
+                       slot = (twdr->twcal_hand + slot) & (INET_TWDR_RECYCLE_SLOTS - 1);
+               }
+               list = &twdr->twcal_row[slot];
+       }
+
+       hlist_add_head(&tw->tw_death_node, list);
+
+       if (twdr->tw_count++ == 0)
+               mod_timer(&twdr->tw_timer, jiffies + twdr->period);
+       spin_unlock(&twdr->death_lock);
+}
+
+EXPORT_SYMBOL_GPL(inet_twsk_schedule);
+
+void inet_twdr_twcal_tick(unsigned long data)
+{
+       struct inet_timewait_death_row *twdr;
+       int n, slot;
+       unsigned long j;
+       unsigned long now = jiffies;
+       int killed = 0;
+       int adv = 0;
+
+       twdr = (struct inet_timewait_death_row *)data;
+
+       spin_lock(&twdr->death_lock);
+       if (twdr->twcal_hand < 0)
+               goto out;
+
+       slot = twdr->twcal_hand;
+       j = twdr->twcal_jiffie;
+
+       for (n = 0; n < INET_TWDR_RECYCLE_SLOTS; n++) {
+               if (time_before_eq(j, now)) {
+                       struct hlist_node *node, *safe;
+                       struct inet_timewait_sock *tw;
+
+                       inet_twsk_for_each_inmate_safe(tw, node, safe,
+                                                      &twdr->twcal_row[slot]) {
+                               __inet_twsk_del_dead_node(tw);
+                               __inet_twsk_kill(tw, twdr->hashinfo);
+                               inet_twsk_put(tw);
+                               killed++;
+                       }
+               } else {
+                       if (!adv) {
+                               adv = 1;
+                               twdr->twcal_jiffie = j;
+                               twdr->twcal_hand = slot;
+                       }
+
+                       if (!hlist_empty(&twdr->twcal_row[slot])) {
+                               mod_timer(&twdr->twcal_timer, j);
+                               goto out;
+                       }
+               }
+               j += 1 << INET_TWDR_RECYCLE_TICK;
+               slot = (slot + 1) & (INET_TWDR_RECYCLE_SLOTS - 1);
+       }
+       twdr->twcal_hand = -1;
+
+out:
+       if ((twdr->tw_count -= killed) == 0)
+               del_timer(&twdr->tw_timer);
+       NET_ADD_STATS_BH(LINUX_MIB_TIMEWAITKILLED, killed);
+       spin_unlock(&twdr->death_lock);
+}
+
+EXPORT_SYMBOL_GPL(inet_twdr_twcal_tick);
index ab18a853d7ce3ca5249606af7f5a1660de6e5182..f84ba9c96551e015882d9895ac197814c3b769f1 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/net.h>
+#include <net/ip.h>
 #include <net/inetpeer.h>
 
 /*
@@ -72,7 +73,7 @@
 /* Exported for inet_getid inline function.  */
 DEFINE_SPINLOCK(inet_peer_idlock);
 
-static kmem_cache_t *peer_cachep;
+static kmem_cache_t *peer_cachep __read_mostly;
 
 #define node_height(x) x->avl_height
 static struct inet_peer peer_fake_node = {
@@ -459,5 +460,3 @@ static void peer_check_expire(unsigned long dummy)
                                peer_total / inet_peer_threshold * HZ;
        add_timer(&peer_periodic_timer);
 }
-
-EXPORT_SYMBOL(inet_peer_idlock);
index 77094aac6c28c6164342066a7a72690934405f1c..0923add122b415b8000d46fbad28fcffe217e0cc 100644 (file)
@@ -76,16 +76,12 @@ int ip_forward(struct sk_buff *skb)
         *      that reaches zero, we must reply an ICMP control message telling
         *      that the packet's lifetime expired.
         */
-
-       iph = skb->nh.iph;
-
-       if (iph->ttl <= 1)
+       if (skb->nh.iph->ttl <= 1)
                 goto too_many_hops;
 
        if (!xfrm4_route_forward(skb))
                goto drop;
 
-       iph = skb->nh.iph;
        rt = (struct rtable*)skb->dst;
 
        if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
index eb377ae15305f7bff94c6c5e7967a68502464146..e7d26d9943c2d5aea36b465304b8b98db12a7abd 100644 (file)
@@ -377,7 +377,7 @@ static struct ipq *ip_frag_create(unsigned hash, struct iphdr *iph, u32 user)
        return ip_frag_intern(hash, qp);
 
 out_nomem:
-       LIMIT_NETDEBUG(printk(KERN_ERR "ip_frag_create: no memory left !\n"));
+       LIMIT_NETDEBUG(KERN_ERR "ip_frag_create: no memory left !\n");
        return NULL;
 }
 
@@ -457,7 +457,7 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
 
        if (pskb_pull(skb, ihl) == NULL)
                goto err;
-       if (pskb_trim(skb, end-offset))
+       if (pskb_trim_rcsum(skb, end-offset))
                goto err;
 
        /* Find out which fragments are in front and at the back of us
@@ -533,7 +533,7 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
        if (skb->dev)
                qp->iif = skb->dev->ifindex;
        skb->dev = NULL;
-       qp->stamp = skb->stamp;
+       skb_get_timestamp(skb, &qp->stamp);
        qp->meat += skb->len;
        atomic_add(skb->truesize, &ip_frag_mem);
        if (offset == 0)
@@ -615,7 +615,7 @@ static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev)
 
        head->next = NULL;
        head->dev = dev;
-       head->stamp = qp->stamp;
+       skb_set_timestamp(head, &qp->stamp);
 
        iph = head->nh.iph;
        iph->frag_off = 0;
@@ -625,8 +625,8 @@ static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev)
        return head;
 
 out_nomem:
-       LIMIT_NETDEBUG(printk(KERN_ERR "IP: queue_glue: no memory for gluing "
-                             "queue %p\n", qp));
+       LIMIT_NETDEBUG(KERN_ERR "IP: queue_glue: no memory for gluing "
+                             "queue %p\n", qp);
        goto out_fail;
 out_oversize:
        if (net_ratelimit())
index c703528e0bcd524751b8b4e43415e2b8e8ccadaf..473d0f2b2e0d6b5a4252f7c825ea870a2afc2c91 100644 (file)
  *     SNMP management statistics
  */
 
-DEFINE_SNMP_STAT(struct ipstats_mib, ip_statistics);
+DEFINE_SNMP_STAT(struct ipstats_mib, ip_statistics) __read_mostly;
 
 /*
  *     Process Router Attention IP option
@@ -225,8 +225,8 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb)
                /* If there maybe a raw socket we must check - if not we
                 * don't care less
                 */
-               if (raw_sk)
-                       raw_v4_input(skb, skb->nh.iph, hash);
+               if (raw_sk && !raw_v4_input(skb, skb->nh.iph, hash))
+                       raw_sk = NULL;
 
                if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) {
                        int ret;
@@ -279,18 +279,70 @@ int ip_local_deliver(struct sk_buff *skb)
                       ip_local_deliver_finish);
 }
 
-static inline int ip_rcv_finish(struct sk_buff *skb)
+static inline int ip_rcv_options(struct sk_buff *skb)
 {
+       struct ip_options *opt;
+       struct iphdr *iph;
        struct net_device *dev = skb->dev;
+
+       /* It looks as overkill, because not all
+          IP options require packet mangling.
+          But it is the easiest for now, especially taking
+          into account that combination of IP options
+          and running sniffer is extremely rare condition.
+                                             --ANK (980813)
+       */
+       if (skb_cow(skb, skb_headroom(skb))) {
+               IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
+               goto drop;
+       }
+
+       iph = skb->nh.iph;
+
+       if (ip_options_compile(NULL, skb)) {
+               IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+               goto drop;
+       }
+
+       opt = &(IPCB(skb)->opt);
+       if (unlikely(opt->srr)) {
+               struct in_device *in_dev = in_dev_get(dev);
+               if (in_dev) {
+                       if (!IN_DEV_SOURCE_ROUTE(in_dev)) {
+                               if (IN_DEV_LOG_MARTIANS(in_dev) &&
+                                   net_ratelimit())
+                                       printk(KERN_INFO "source route option "
+                                              "%u.%u.%u.%u -> %u.%u.%u.%u\n",
+                                              NIPQUAD(iph->saddr),
+                                              NIPQUAD(iph->daddr));
+                               in_dev_put(in_dev);
+                               goto drop;
+                       }
+
+                       in_dev_put(in_dev);
+               }
+
+               if (ip_options_rcv_srr(skb))
+                       goto drop;
+       }
+
+       return 0;
+drop:
+       return -1;
+}
+
+static inline int ip_rcv_finish(struct sk_buff *skb)
+{
        struct iphdr *iph = skb->nh.iph;
-       int err;
 
        /*
         *      Initialise the virtual path cache for the packet. It describes
         *      how the packet travels inside Linux networking.
         */ 
-       if (skb->dst == NULL) {
-               if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) {
+       if (likely(skb->dst == NULL)) {
+               int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
+                                        skb->dev);
+               if (unlikely(err)) {
                        if (err == -EHOSTUNREACH)
                                IP_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
                        goto drop; 
@@ -298,7 +350,7 @@ static inline int ip_rcv_finish(struct sk_buff *skb)
        }
 
 #ifdef CONFIG_NET_CLS_ROUTE
-       if (skb->dst->tclassid) {
+       if (unlikely(skb->dst->tclassid)) {
                struct ip_rt_acct *st = ip_rt_acct + 256*smp_processor_id();
                u32 idx = skb->dst->tclassid;
                st[idx&0xFF].o_packets++;
@@ -308,48 +360,11 @@ static inline int ip_rcv_finish(struct sk_buff *skb)
        }
 #endif
 
-       if (iph->ihl > 5) {
-               struct ip_options *opt;
-
-               /* It looks as overkill, because not all
-                  IP options require packet mangling.
-                  But it is the easiest for now, especially taking
-                  into account that combination of IP options
-                  and running sniffer is extremely rare condition.
-                                                     --ANK (980813)
-               */
-
-               if (skb_cow(skb, skb_headroom(skb))) {
-                       IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
-                       goto drop;
-               }
-               iph = skb->nh.iph;
-
-               if (ip_options_compile(NULL, skb))
-                       goto inhdr_error;
-
-               opt = &(IPCB(skb)->opt);
-               if (opt->srr) {
-                       struct in_device *in_dev = in_dev_get(dev);
-                       if (in_dev) {
-                               if (!IN_DEV_SOURCE_ROUTE(in_dev)) {
-                                       if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())
-                                               printk(KERN_INFO "source route option %u.%u.%u.%u -> %u.%u.%u.%u\n",
-                                                      NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
-                                       in_dev_put(in_dev);
-                                       goto drop;
-                               }
-                               in_dev_put(in_dev);
-                       }
-                       if (ip_options_rcv_srr(skb))
-                               goto drop;
-               }
-       }
+       if (iph->ihl > 5 && ip_rcv_options(skb))
+               goto drop;
 
        return dst_input(skb);
 
-inhdr_error:
-       IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
 drop:
         kfree_skb(skb);
         return NET_RX_DROP;
@@ -358,9 +373,10 @@ drop:
 /*
  *     Main IP Receive routine.
  */ 
-int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
+int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
 {
        struct iphdr *iph;
+       u32 len;
 
        /* When the interface is in promisc. mode, drop all the crap
         * that it receives, do not try to analyse it.
@@ -392,29 +408,27 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
         */
 
        if (iph->ihl < 5 || iph->version != 4)
-               goto inhdr_error; 
+               goto inhdr_error;
 
        if (!pskb_may_pull(skb, iph->ihl*4))
                goto inhdr_error;
 
        iph = skb->nh.iph;
 
-       if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
-               goto inhdr_error; 
+       if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
+               goto inhdr_error;
 
-       {
-               __u32 len = ntohs(iph->tot_len); 
-               if (skb->len < len || len < (iph->ihl<<2))
-                       goto inhdr_error;
+       len = ntohs(iph->tot_len);
+       if (skb->len < len || len < (iph->ihl*4))
+               goto inhdr_error;
 
-               /* Our transport medium may have padded the buffer out. Now we know it
-                * is IP we can trim to the true length of the frame.
-                * Note this now means skb->len holds ntohs(iph->tot_len).
-                */
-               if (pskb_trim_rcsum(skb, len)) {
-                       IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
-                       goto drop;
-               }
+       /* Our transport medium may have padded the buffer out. Now we know it
+        * is IP we can trim to the true length of the frame.
+        * Note this now means skb->len holds ntohs(iph->tot_len).
+        */
+       if (pskb_trim_rcsum(skb, len)) {
+               IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
+               goto drop;
        }
 
        return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
@@ -428,5 +442,4 @@ out:
         return NET_RX_DROP;
 }
 
-EXPORT_SYMBOL(ip_rcv);
 EXPORT_SYMBOL(ip_statistics);
index 6d89f3f3e70193042ee8873834e57875bc20abba..bce4e875193be1d596c4c607ab42e9e1f966513f 100644 (file)
@@ -489,23 +489,18 @@ void ip_options_undo(struct ip_options * opt)
        }
 }
 
-int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen, int user)
+static struct ip_options *ip_options_get_alloc(const int optlen)
 {
-       struct ip_options *opt;
+       struct ip_options *opt = kmalloc(sizeof(*opt) + ((optlen + 3) & ~3),
+                                        GFP_KERNEL);
+       if (opt)
+               memset(opt, 0, sizeof(*opt));
+       return opt;
+}
 
-       opt = kmalloc(sizeof(struct ip_options)+((optlen+3)&~3), GFP_KERNEL);
-       if (!opt)
-               return -ENOMEM;
-       memset(opt, 0, sizeof(struct ip_options));
-       if (optlen) {
-               if (user) {
-                       if (copy_from_user(opt->__data, data, optlen)) {
-                               kfree(opt);
-                               return -EFAULT;
-                       }
-               } else
-                       memcpy(opt->__data, data, optlen);
-       }
+static int ip_options_get_finish(struct ip_options **optp,
+                                struct ip_options *opt, int optlen)
+{
        while (optlen & 3)
                opt->__data[optlen++] = IPOPT_END;
        opt->optlen = optlen;
@@ -521,6 +516,30 @@ int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen, in
        return 0;
 }
 
+int ip_options_get_from_user(struct ip_options **optp, unsigned char __user *data, int optlen)
+{
+       struct ip_options *opt = ip_options_get_alloc(optlen);
+
+       if (!opt)
+               return -ENOMEM;
+       if (optlen && copy_from_user(opt->__data, data, optlen)) {
+               kfree(opt);
+               return -EFAULT;
+       }
+       return ip_options_get_finish(optp, opt, optlen);
+}
+
+int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen)
+{
+       struct ip_options *opt = ip_options_get_alloc(optlen);
+
+       if (!opt)
+               return -ENOMEM;
+       if (optlen)
+               memcpy(opt->__data, data, optlen);
+       return ip_options_get_finish(optp, opt, optlen);
+}
+
 void ip_forward_options(struct sk_buff *skb)
 {
        struct   ip_options * opt       = &(IPCB(skb)->opt);
@@ -620,6 +639,3 @@ int ip_options_rcv_srr(struct sk_buff *skb)
        }
        return 0;
 }
-
-EXPORT_SYMBOL(ip_options_compile);
-EXPORT_SYMBOL(ip_options_undo);
index 80d13103b2b018624b0b845b3c713cfe4eafcaa7..3f1a263e1249ebbaef7e3fb719252bb90d19ee6a 100644 (file)
 #include <net/ip.h>
 #include <net/protocol.h>
 #include <net/route.h>
-#include <net/tcp.h>
-#include <net/udp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <net/arp.h>
 #include <net/icmp.h>
-#include <net/raw.h>
 #include <net/checksum.h>
 #include <net/inetpeer.h>
 #include <net/checksum.h>
 #include <linux/netfilter_bridge.h>
 #include <linux/mroute.h>
 #include <linux/netlink.h>
+#include <linux/tcp.h>
 
-/*
- *      Shall we try to damage output packets if routing dev changes?
- */
-
-int sysctl_ip_dynaddr;
 int sysctl_ip_default_ttl = IPDEFTTL;
 
 /* Generate a checksum for an outgoing IP datagram. */
@@ -165,6 +158,8 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
                       dst_output);
 }
 
+EXPORT_SYMBOL_GPL(ip_build_and_send_pkt);
+
 static inline int ip_finish_output2(struct sk_buff *skb)
 {
        struct dst_entry *dst = skb->dst;
@@ -205,7 +200,7 @@ static inline int ip_finish_output2(struct sk_buff *skb)
        return -EINVAL;
 }
 
-int ip_finish_output(struct sk_buff *skb)
+static inline int ip_finish_output(struct sk_buff *skb)
 {
        struct net_device *dev = skb->dst->dev;
 
@@ -329,8 +324,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
                        if (ip_route_output_flow(&rt, &fl, sk, 0))
                                goto no_route;
                }
-               __sk_dst_set(sk, &rt->u.dst);
-               tcp_v4_setup_caps(sk, &rt->u.dst);
+               sk_setup_caps(sk, &rt->u.dst);
        }
        skb->dst = dst_clone(&rt->u.dst);
 
@@ -392,7 +386,6 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
 #endif
 #ifdef CONFIG_NETFILTER
        to->nfmark = from->nfmark;
-       to->nfcache = from->nfcache;
        /* Connection association is same as pre-frag packet */
        nf_conntrack_put(to->nfct);
        to->nfct = from->nfct;
@@ -580,7 +573,7 @@ slow_path:
                 */
 
                if ((skb2 = alloc_skb(len+hlen+ll_rs, GFP_ATOMIC)) == NULL) {
-                       NETDEBUG(printk(KERN_INFO "IP: frag: no memory for new fragment!\n"));
+                       NETDEBUG(KERN_INFO "IP: frag: no memory for new fragment!\n");
                        err = -ENOMEM;
                        goto fail;
                }
@@ -1329,12 +1322,7 @@ void __init ip_init(void)
 #endif
 }
 
-EXPORT_SYMBOL(ip_finish_output);
 EXPORT_SYMBOL(ip_fragment);
 EXPORT_SYMBOL(ip_generic_getfrag);
 EXPORT_SYMBOL(ip_queue_xmit);
 EXPORT_SYMBOL(ip_send_check);
-
-#ifdef CONFIG_SYSCTL
-EXPORT_SYMBOL(sysctl_ip_default_ttl);
-#endif
index ff4bd067b39727c50e4aafdd1cbd49ea0dfd849b..2f0b47da5b37e3b3c0c44235355e704958cba8a3 100644 (file)
@@ -153,7 +153,7 @@ int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc)
                switch (cmsg->cmsg_type) {
                case IP_RETOPTS:
                        err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr));
-                       err = ip_options_get(&ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40, 0);
+                       err = ip_options_get(&ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40);
                        if (err)
                                return err;
                        break;
@@ -425,7 +425,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
                        struct ip_options * opt = NULL;
                        if (optlen > 40 || optlen < 0)
                                goto e_inval;
-                       err = ip_options_get(&opt, optval, optlen, 1);
+                       err = ip_options_get_from_user(&opt, optval, optlen);
                        if (err)
                                break;
                        if (sk->sk_type == SOCK_STREAM) {
@@ -614,7 +614,6 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
                }
                case IP_MSFILTER:
                {
-                       extern int sysctl_optmem_max;
                        extern int sysctl_igmp_max_msf;
                        struct ip_msfilter *msf;
 
@@ -769,7 +768,6 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
                }
                case MCAST_MSFILTER:
                {
-                       extern int sysctl_optmem_max;
                        extern int sysctl_igmp_max_msf;
                        struct sockaddr_in *psin;
                        struct ip_msfilter *msf = NULL;
@@ -1090,7 +1088,5 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
 
 EXPORT_SYMBOL(ip_cmsg_recv);
 
-#ifdef CONFIG_IP_SCTP_MODULE
 EXPORT_SYMBOL(ip_getsockopt);
 EXPORT_SYMBOL(ip_setsockopt);
-#endif
index 7ded6e60f43af7902fc6ce26e3625475295cf601..fc718df17b40d9b1a0719d39798331cf30a2fca3 100644 (file)
@@ -214,8 +214,8 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
                              spi, IPPROTO_COMP, AF_INET);
        if (!x)
                return;
-       NETDEBUG(printk(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/%u.%u.%u.%u\n",
-              spi, NIPQUAD(iph->daddr)));
+       NETDEBUG(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/%u.%u.%u.%u\n",
+                spi, NIPQUAD(iph->daddr));
        xfrm_state_put(x);
 }
 
@@ -345,8 +345,7 @@ static void ipcomp_free_tfms(struct crypto_tfm **tfms)
 
        for_each_cpu(cpu) {
                struct crypto_tfm *tfm = *per_cpu_ptr(tfms, cpu);
-               if (tfm)
-                       crypto_free_tfm(tfm);
+               crypto_free_tfm(tfm);
        }
        free_percpu(tfms);
 }
index d2bf8e1930a3709a41ce0154fabc50d0ff781b7d..953129d392d21cc97f551f93c519b491cb0190cc 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/major.h>
 #include <linux/root_dev.h>
 #include <linux/delay.h>
+#include <linux/nfs_fs.h>
 #include <net/arp.h>
 #include <net/ip.h>
 #include <net/ipconfig.h>
@@ -393,7 +394,7 @@ static int __init ic_defaults(void)
 
 #ifdef IPCONFIG_RARP
 
-static int ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt);
+static int ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev);
 
 static struct packet_type rarp_packet_type __initdata = {
        .type = __constant_htons(ETH_P_RARP),
@@ -414,7 +415,7 @@ static inline void ic_rarp_cleanup(void)
  *  Process received RARP packet.
  */
 static int __init
-ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
+ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
 {
        struct arphdr *rarp;
        unsigned char *rarp_ptr;
@@ -555,7 +556,7 @@ struct bootp_pkt {          /* BOOTP packet format */
 #define DHCPRELEASE    7
 #define DHCPINFORM     8
 
-static int ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt);
+static int ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev);
 
 static struct packet_type bootp_packet_type __initdata = {
        .type = __constant_htons(ETH_P_IP),
@@ -823,7 +824,7 @@ static void __init ic_do_bootp_ext(u8 *ext)
 /*
  *  Receive BOOTP reply.
  */
-static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
+static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
 {
        struct bootp_pkt *b;
        struct iphdr *h;
index dc806b57842705ac97f6a294a8a426f4f711b5aa..9dbf5909f3a6a190fcef1961e3737100a4b12e57 100644 (file)
@@ -103,7 +103,7 @@ static DEFINE_SPINLOCK(mfc_unres_lock);
    In this case data path is free of exclusive locks at all.
  */
 
-static kmem_cache_t *mrt_cachep;
+static kmem_cache_t *mrt_cachep __read_mostly;
 
 static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local);
 static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert);
index d9212addd1933a8a47fe4ca28aaae15b05762bcc..6e092dadb3883964a33bdc657417331ebdbc2b25 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <net/protocol.h>
+#include <net/tcp.h>
 #include <asm/system.h>
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
index d0145a8b1551765b2cb31049d256e2546f1d91d1..e11952ea17afd89cfba231fee4e27754fbd9c849 100644 (file)
@@ -40,7 +40,7 @@
 static struct list_head *ip_vs_conn_tab;
 
 /*  SLAB cache for IPVS connections */
-static kmem_cache_t *ip_vs_conn_cachep;
+static kmem_cache_t *ip_vs_conn_cachep __read_mostly;
 
 /*  counter for current IPVS connections */
 static atomic_t ip_vs_conn_count = ATOMIC_INIT(0);
index 5fb257dd07cb38187e0b01158f4a75e4d4d3cd8a..3ac7eeca04ac4ca4da81bdc1f6e75cce70316b79 100644 (file)
@@ -22,6 +22,7 @@
  *
  * Changes:
  *     Paul `Rusty' Russell            properly handle non-linear skbs
+ *     Harald Welte                    don't use nfcache
  *
  */
 
@@ -529,7 +530,7 @@ static unsigned int ip_vs_post_routing(unsigned int hooknum,
                                       const struct net_device *out,
                                       int (*okfn)(struct sk_buff *))
 {
-       if (!((*pskb)->nfcache & NFC_IPVS_PROPERTY))
+       if (!((*pskb)->ipvs_property))
                return NF_ACCEPT;
 
        /* The packet was sent from IPVS, exit this chain */
@@ -701,7 +702,7 @@ static int ip_vs_out_icmp(struct sk_buff **pskb, int *related)
        /* do the statistics and put it back */
        ip_vs_out_stats(cp, skb);
 
-       skb->nfcache |= NFC_IPVS_PROPERTY;
+       skb->ipvs_property = 1;
        verdict = NF_ACCEPT;
 
   out:
@@ -739,7 +740,7 @@ ip_vs_out(unsigned int hooknum, struct sk_buff **pskb,
 
        EnterFunction(11);
 
-       if (skb->nfcache & NFC_IPVS_PROPERTY)
+       if (skb->ipvs_property)
                return NF_ACCEPT;
 
        iph = skb->nh.iph;
@@ -821,7 +822,7 @@ ip_vs_out(unsigned int hooknum, struct sk_buff **pskb,
        ip_vs_set_state(cp, IP_VS_DIR_OUTPUT, skb, pp);
        ip_vs_conn_put(cp);
 
-       skb->nfcache |= NFC_IPVS_PROPERTY;
+       skb->ipvs_property = 1;
 
        LeaveFunction(11);
        return NF_ACCEPT;
index 7d99ede2ef79316f4842e6b2b2eb7465cbcd0bcb..2d66848e7aa06bb75df50aad715d6c45837535e7 100644 (file)
@@ -1598,7 +1598,7 @@ static ctl_table vs_table[] = {
        { .ctl_name = 0 }
 };
 
-static ctl_table ipv4_table[] = {
+static ctl_table ipvs_ipv4_table[] = {
        {
                .ctl_name       = NET_IPV4,
                .procname       = "ipv4",
@@ -1613,7 +1613,7 @@ static ctl_table vs_root_table[] = {
                .ctl_name       = CTL_NET,
                .procname       = "net",
                .mode           = 0555,
-               .child          = ipv4_table,
+               .child          = ipvs_ipv4_table,
        },
        { .ctl_name = 0 }
 };
index c035838b780a0fa56b5352d83e71e9ed7d8e3f38..561cda326fa8092cf2b27da87cac78d68cded80e 100644 (file)
@@ -131,7 +131,7 @@ static ctl_table vs_table[] = {
        { .ctl_name = 0 }
 };
 
-static ctl_table ipv4_table[] = {
+static ctl_table ipvs_ipv4_table[] = {
        {
                .ctl_name       = NET_IPV4,
                .procname       = "ipv4", 
@@ -146,7 +146,7 @@ static ctl_table lblc_root_table[] = {
                .ctl_name       = CTL_NET,
                .procname       = "net", 
                .mode           = 0555, 
-               .child          = ipv4_table
+               .child          = ipvs_ipv4_table
        },
        { .ctl_name = 0 }
 };
index 22b5dd55d2710a7b697e2ce538d68b9429bc2f45..ce456dbf09a54967c4edde5d648ffd3661e400a1 100644 (file)
@@ -320,7 +320,7 @@ static ctl_table vs_table[] = {
        { .ctl_name = 0 }
 };
 
-static ctl_table ipv4_table[] = {
+static ctl_table ipvs_ipv4_table[] = {
        {
                .ctl_name       = NET_IPV4,
                .procname       = "ipv4", 
@@ -335,7 +335,7 @@ static ctl_table lblcr_root_table[] = {
                .ctl_name       = CTL_NET,
                .procname       = "net", 
                .mode           = 0555, 
-               .child          = ipv4_table
+               .child          = ipvs_ipv4_table
        },
        { .ctl_name = 0 }
 };
index e65de675da74b57e1ab01332a8daa438ea8190a7..c19408973c091d12bb5d4e850c37af7aa3b64e37 100644 (file)
@@ -604,14 +604,14 @@ void ip_vs_tcp_conn_listen(struct ip_vs_conn *cp)
 }
 
 
-static void tcp_init(struct ip_vs_protocol *pp)
+static void ip_vs_tcp_init(struct ip_vs_protocol *pp)
 {
        IP_VS_INIT_HASH_TABLE(tcp_apps);
        pp->timeout_table = tcp_timeouts;
 }
 
 
-static void tcp_exit(struct ip_vs_protocol *pp)
+static void ip_vs_tcp_exit(struct ip_vs_protocol *pp)
 {
 }
 
@@ -621,8 +621,8 @@ struct ip_vs_protocol ip_vs_protocol_tcp = {
        .protocol =             IPPROTO_TCP,
        .dont_defrag =          0,
        .appcnt =               ATOMIC_INIT(0),
-       .init =                 tcp_init,
-       .exit =                 tcp_exit,
+       .init =                 ip_vs_tcp_init,
+       .exit =                 ip_vs_tcp_exit,
        .register_app =         tcp_register_app,
        .unregister_app =       tcp_unregister_app,
        .conn_schedule =        tcp_conn_schedule,
index a8512a3fd08a02503aae30187f07f6b81ff9732c..3b87482049cf395804431a35c065ff6722bcc4ab 100644 (file)
@@ -127,7 +127,7 @@ ip_vs_dst_reset(struct ip_vs_dest *dest)
 
 #define IP_VS_XMIT(skb, rt)                            \
 do {                                                   \
-       (skb)->nfcache |= NFC_IPVS_PROPERTY;            \
+       (skb)->ipvs_property = 1;                       \
        (skb)->ip_summed = CHECKSUM_NONE;               \
        NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, (skb), NULL,  \
                (rt)->u.dst.dev, dst_output);           \
index c9cf8726051d7cae07a3d1278b0bea36b1c2eee5..db67373f9b348669de5045ba39c558105c7b1219 100644 (file)
@@ -107,7 +107,7 @@ static int drr_dev_event(struct notifier_block *this,
        return NOTIFY_DONE;
 }
 
-struct notifier_block drr_dev_notifier = {
+static struct notifier_block drr_dev_notifier = {
        .notifier_call  = drr_dev_event,
 };
 
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
new file mode 100644 (file)
index 0000000..ae0779d
--- /dev/null
@@ -0,0 +1,139 @@
+/* IPv4 specific functions of netfilter core */
+
+#include <linux/config.h>
+#ifdef CONFIG_NETFILTER
+
+#include <linux/kernel.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/icmp.h>
+#include <net/route.h>
+#include <linux/ip.h>
+
+/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
+int ip_route_me_harder(struct sk_buff **pskb)
+{
+       struct iphdr *iph = (*pskb)->nh.iph;
+       struct rtable *rt;
+       struct flowi fl = {};
+       struct dst_entry *odst;
+       unsigned int hh_len;
+
+       /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
+        * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook.
+        */
+       if (inet_addr_type(iph->saddr) == RTN_LOCAL) {
+               fl.nl_u.ip4_u.daddr = iph->daddr;
+               fl.nl_u.ip4_u.saddr = iph->saddr;
+               fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
+               fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0;
+#ifdef CONFIG_IP_ROUTE_FWMARK
+               fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark;
+#endif
+               fl.proto = iph->protocol;
+               if (ip_route_output_key(&rt, &fl) != 0)
+                       return -1;
+
+               /* Drop old route. */
+               dst_release((*pskb)->dst);
+               (*pskb)->dst = &rt->u.dst;
+       } else {
+               /* non-local src, find valid iif to satisfy
+                * rp-filter when calling ip_route_input. */
+               fl.nl_u.ip4_u.daddr = iph->saddr;
+               if (ip_route_output_key(&rt, &fl) != 0)
+                       return -1;
+
+               odst = (*pskb)->dst;
+               if (ip_route_input(*pskb, iph->daddr, iph->saddr,
+                                  RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
+                       dst_release(&rt->u.dst);
+                       return -1;
+               }
+               dst_release(&rt->u.dst);
+               dst_release(odst);
+       }
+       
+       if ((*pskb)->dst->error)
+               return -1;
+
+       /* Change in oif may mean change in hh_len. */
+       hh_len = (*pskb)->dst->dev->hard_header_len;
+       if (skb_headroom(*pskb) < hh_len) {
+               struct sk_buff *nskb;
+
+               nskb = skb_realloc_headroom(*pskb, hh_len);
+               if (!nskb) 
+                       return -1;
+               if ((*pskb)->sk)
+                       skb_set_owner_w(nskb, (*pskb)->sk);
+               kfree_skb(*pskb);
+               *pskb = nskb;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(ip_route_me_harder);
+
+/*
+ * Extra routing may needed on local out, as the QUEUE target never
+ * returns control to the table.
+ */
+
+struct ip_rt_info {
+       u_int32_t daddr;
+       u_int32_t saddr;
+       u_int8_t tos;
+};
+
+static void queue_save(const struct sk_buff *skb, struct nf_info *info)
+{
+       struct ip_rt_info *rt_info = nf_info_reroute(info);
+
+       if (info->hook == NF_IP_LOCAL_OUT) {
+               const struct iphdr *iph = skb->nh.iph;
+
+               rt_info->tos = iph->tos;
+               rt_info->daddr = iph->daddr;
+               rt_info->saddr = iph->saddr;
+       }
+}
+
+static int queue_reroute(struct sk_buff **pskb, const struct nf_info *info)
+{
+       const struct ip_rt_info *rt_info = nf_info_reroute(info);
+
+       if (info->hook == NF_IP_LOCAL_OUT) {
+               struct iphdr *iph = (*pskb)->nh.iph;
+
+               if (!(iph->tos == rt_info->tos
+                     && iph->daddr == rt_info->daddr
+                     && iph->saddr == rt_info->saddr))
+                       return ip_route_me_harder(pskb);
+       }
+       return 0;
+}
+
+static struct nf_queue_rerouter ip_reroute = {
+       .rer_size       = sizeof(struct ip_rt_info),
+       .save           = queue_save,
+       .reroute        = queue_reroute,
+};
+
+static int init(void)
+{
+       return nf_register_queue_rerouter(PF_INET, &ip_reroute);
+}
+
+static void fini(void)
+{
+       nf_unregister_queue_rerouter(PF_INET);
+}
+
+module_init(init);
+module_exit(fini);
+
+#endif /* CONFIG_NETFILTER */
index 46d4cb1c06f053b3d3e831d2649202d4282de513..30aa8e2ee214263c6b1d124f5566eb56c804bf58 100644 (file)
@@ -34,12 +34,23 @@ config IP_NF_CT_ACCT
 
 config IP_NF_CONNTRACK_MARK
        bool  'Connection mark tracking support'
+       depends on IP_NF_CONNTRACK
        help
          This option enables support for connection marks, used by the
          `CONNMARK' target and `connmark' match. Similar to the mark value
          of packets, but this mark value is kept in the conntrack session
          instead of the individual packets.
        
+config IP_NF_CONNTRACK_EVENTS
+       bool "Connection tracking events"
+       depends on IP_NF_CONNTRACK
+       help
+         If this option is enabled, the connection tracking code will
+         provide a notifier chain that can be used by other kernel code
+         to get notified about changes in the connection tracking state.
+         
+         IF unsure, say `N'.
+
 config IP_NF_CT_PROTO_SCTP
        tristate  'SCTP protocol connection tracking support (EXPERIMENTAL)'
        depends on IP_NF_CONNTRACK && EXPERIMENTAL
@@ -75,6 +86,25 @@ config IP_NF_IRC
 
          To compile it as a module, choose M here.  If unsure, say Y.
 
+config IP_NF_NETBIOS_NS
+       tristate "NetBIOS name service protocol support (EXPERIMENTAL)"
+       depends on IP_NF_CONNTRACK && EXPERIMENTAL
+       help
+         NetBIOS name service requests are sent as broadcast messages from an
+         unprivileged port and responded to with unicast messages to the
+         same port. This make them hard to firewall properly because connection
+         tracking doesn't deal with broadcasts. This helper tracks locally
+         originating NetBIOS name service requests and the corresponding
+         responses. It relies on correct IP address configuration, specifically
+         netmask and broadcast address. When properly configured, the output
+         of "ip address show" should look similar to this:
+
+         $ ip -4 address show eth0
+         4: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000
+             inet 172.16.2.252/24 brd 172.16.2.255 scope global eth0
+         
+         To compile it as a module, choose M here.  If unsure, say N.
+
 config IP_NF_TFTP
        tristate "TFTP protocol support"
        depends on IP_NF_CONNTRACK
@@ -100,11 +130,15 @@ config IP_NF_AMANDA
          To compile it as a module, choose M here.  If unsure, say Y.
 
 config IP_NF_QUEUE
-       tristate "Userspace queueing via NETLINK"
+       tristate "IP Userspace queueing via NETLINK (OBSOLETE)"
        help
          Netfilter has the ability to queue packets to user space: the
          netlink device can be used to access them using this driver.
 
+         This option enables the old IPv4-only "ip_queue" implementation
+         which has been obsoleted by the new "nfnetlink_queue" code (see
+         CONFIG_NETFILTER_NETLINK_QUEUE).
+
          To compile it as a module, choose M here.  If unsure, say N.
 
 config IP_NF_IPTABLES
@@ -340,6 +374,17 @@ config IP_NF_MATCH_SCTP
          If you want to compile it as a module, say M here and read
          <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+config IP_NF_MATCH_DCCP
+       tristate  'DCCP protocol match support'
+       depends on IP_NF_IPTABLES
+       help
+         With this option enabled, you will be able to use the iptables
+         `dccp' match in order to match on DCCP source/destination ports
+         and DCCP flags.
+
+         If you want to compile it as a module, say M here and read
+         <file:Documentation/modules.txt>.  If unsure, say `N'.
+
 config IP_NF_MATCH_COMMENT
        tristate  'comment match support'
        depends on IP_NF_IPTABLES
@@ -361,6 +406,16 @@ config IP_NF_MATCH_CONNMARK
          <file:Documentation/modules.txt>.  The module will be called
          ipt_connmark.o.  If unsure, say `N'.
 
+config IP_NF_MATCH_CONNBYTES
+       tristate  'Connection byte/packet counter match support'
+       depends on IP_NF_CT_ACCT && IP_NF_IPTABLES
+       help
+         This option adds a `connbytes' match, which allows you to match the
+         number of bytes and/or packets for each direction within a connection.
+
+         If you want to compile it as a module, say M here and read
+         <file:Documentation/modules.txt>.  If unsure, say `N'.
+
 config IP_NF_MATCH_HASHLIMIT
        tristate  'hashlimit match support'
        depends on IP_NF_IPTABLES
@@ -375,6 +430,19 @@ config IP_NF_MATCH_HASHLIMIT
          destination IP' or `500pps from any given source IP'  with a single
          IPtables rule.
 
+config IP_NF_MATCH_STRING
+       tristate  'string match support'
+       depends on IP_NF_IPTABLES 
+       select TEXTSEARCH
+       select TEXTSEARCH_KMP
+       select TEXTSEARCH_BM
+       select TEXTSEARCH_FSM
+       help
+         This option adds a `string' match, which allows you to look for
+         pattern matchings in packets.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 # `filter', generic and specific targets
 config IP_NF_FILTER
        tristate "Packet filtering"
@@ -616,6 +684,20 @@ config IP_NF_TARGET_CLASSIFY
 
          To compile it as a module, choose M here.  If unsure, say N.
 
+config IP_NF_TARGET_TTL
+       tristate  'TTL target support'
+       depends on IP_NF_MANGLE
+       help
+         This option adds a `TTL' target, which enables the user to modify
+         the TTL value of the IP header.
+
+         While it is safe to decrement/lower the TTL, this target also enables
+         functionality to increment and set the TTL value of the IP header to
+         arbitrary values.  This is EXTREMELY DANGEROUS since you can easily
+         create immortal packets that loop forever on the network.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 config IP_NF_TARGET_CONNMARK
        tristate  'CONNMARK target support'
        depends on IP_NF_CONNTRACK_MARK && IP_NF_MANGLE
@@ -692,5 +774,11 @@ config IP_NF_ARP_MANGLE
          Allows altering the ARP packet payload: source and destination
          hardware and network addresses.
 
+config IP_NF_CONNTRACK_NETLINK
+        tristate 'Connection tracking netlink interface'
+        depends on IP_NF_CONNTRACK && NETFILTER_NETLINK
+        help
+          This option enables support for a netlink-based userspace interface
+
 endmenu
 
index 45796d5924dd9c23c791ea246cffb4395c442423..1ba0db746817cf2809e80c073899c8a37ba3d50c 100644 (file)
@@ -9,6 +9,10 @@ iptable_nat-objs       := ip_nat_standalone.o ip_nat_rule.o ip_nat_core.o ip_nat_helpe
 # connection tracking
 obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
 
+# conntrack netlink interface
+obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o
+
+
 # SCTP protocol connection tracking
 obj-$(CONFIG_IP_NF_CT_PROTO_SCTP) += ip_conntrack_proto_sctp.o
 
@@ -17,6 +21,7 @@ obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o
 obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
 obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
 obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
+obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o
 
 # NAT helpers 
 obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
@@ -38,6 +43,7 @@ obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
 obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
 obj-$(CONFIG_IP_NF_MATCH_HASHLIMIT) += ipt_hashlimit.o
 obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o
+obj-$(CONFIG_IP_NF_MATCH_DCCP) += ipt_dccp.o
 obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
 obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
 obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
@@ -54,11 +60,13 @@ obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
 obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
 obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.o
 obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
+obj-$(CONFIG_IP_NF_MATCH_CONNBYTES) += ipt_connbytes.o
 obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
 obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o
 obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
 obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
 obj-$(CONFIG_IP_NF_MATCH_COMMENT) += ipt_comment.o
+obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o
 
 # targets
 obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
@@ -78,6 +86,7 @@ obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
 obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
 obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o
 obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
+obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
 
 # generic ARP tables
 obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o
@@ -87,3 +96,4 @@ obj-$(CONFIG_IP_NF_ARP_MANGLE) += arpt_mangle.o
 obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o
 
 obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o
+obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += ipt_NFQUEUE.o
index 01e1b58322a9b07cba23e4d2b678debf873c42d1..dc20881004bc57731b4ae348b8272d26622b863e 100644 (file)
@@ -40,7 +40,7 @@ MODULE_PARM_DESC(master_timeout, "timeout for the master connection");
 static char *conns[] = { "DATA ", "MESG ", "INDEX " };
 
 /* This is slow, but it's simple. --RR */
-static char amanda_buffer[65536];
+static char *amanda_buffer;
 static DEFINE_SPINLOCK(amanda_buffer_lock);
 
 unsigned int (*ip_nat_amanda_hook)(struct sk_buff **pskb,
@@ -108,6 +108,7 @@ static int help(struct sk_buff **pskb,
                }
 
                exp->expectfn = NULL;
+               exp->flags = 0;
 
                exp->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
                exp->tuple.src.u.tcp.port = 0;
@@ -153,11 +154,25 @@ static struct ip_conntrack_helper amanda_helper = {
 static void __exit fini(void)
 {
        ip_conntrack_helper_unregister(&amanda_helper);
+       kfree(amanda_buffer);
 }
 
 static int __init init(void)
 {
-       return ip_conntrack_helper_register(&amanda_helper);
+       int ret;
+
+       amanda_buffer = kmalloc(65536, GFP_KERNEL);
+       if (!amanda_buffer)
+               return -ENOMEM;
+
+       ret = ip_conntrack_helper_register(&amanda_helper);
+       if (ret < 0) {
+               kfree(amanda_buffer);
+               return ret;
+       }
+       return 0;
+
+
 }
 
 module_init(init);
index a7f0c821a9b2025483ee6636ab2e6df95147c182..19cba16e6e1e587c5281a997ac67ec7fa291da8a 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/err.h>
 #include <linux/percpu.h>
 #include <linux/moduleparam.h>
+#include <linux/notifier.h>
 
 /* ip_conntrack_lock protects the main hash table, protocol/helper/expected
    registrations, conntrack timers*/
@@ -49,7 +50,7 @@
 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
 #include <linux/netfilter_ipv4/listhelp.h>
 
-#define IP_CONNTRACK_VERSION   "2.1"
+#define IP_CONNTRACK_VERSION   "2.3"
 
 #if 0
 #define DEBUGP printk
@@ -69,22 +70,81 @@ static LIST_HEAD(helpers);
 unsigned int ip_conntrack_htable_size = 0;
 int ip_conntrack_max;
 struct list_head *ip_conntrack_hash;
-static kmem_cache_t *ip_conntrack_cachep;
-static kmem_cache_t *ip_conntrack_expect_cachep;
+static kmem_cache_t *ip_conntrack_cachep __read_mostly;
+static kmem_cache_t *ip_conntrack_expect_cachep __read_mostly;
 struct ip_conntrack ip_conntrack_untracked;
 unsigned int ip_ct_log_invalid;
 static LIST_HEAD(unconfirmed);
 static int ip_conntrack_vmalloc;
 
-DEFINE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat);
+static unsigned int ip_conntrack_next_id = 1;
+static unsigned int ip_conntrack_expect_next_id = 1;
+#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
+struct notifier_block *ip_conntrack_chain;
+struct notifier_block *ip_conntrack_expect_chain;
+
+DEFINE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache);
 
-void 
-ip_conntrack_put(struct ip_conntrack *ct)
+/* deliver cached events and clear cache entry - must be called with locally
+ * disabled softirqs */
+static inline void
+__ip_ct_deliver_cached_events(struct ip_conntrack_ecache *ecache)
 {
-       IP_NF_ASSERT(ct);
-       nf_conntrack_put(&ct->ct_general);
+       DEBUGP("ecache: delivering events for %p\n", ecache->ct);
+       if (is_confirmed(ecache->ct) && !is_dying(ecache->ct) && ecache->events)
+               notifier_call_chain(&ip_conntrack_chain, ecache->events,
+                                   ecache->ct);
+       ecache->events = 0;
+       ip_conntrack_put(ecache->ct);
+       ecache->ct = NULL;
 }
 
+/* Deliver all cached events for a particular conntrack. This is called
+ * by code prior to async packet handling or freeing the skb */
+void ip_ct_deliver_cached_events(const struct ip_conntrack *ct)
+{
+       struct ip_conntrack_ecache *ecache;
+       
+       local_bh_disable();
+       ecache = &__get_cpu_var(ip_conntrack_ecache);
+       if (ecache->ct == ct)
+               __ip_ct_deliver_cached_events(ecache);
+       local_bh_enable();
+}
+
+void __ip_ct_event_cache_init(struct ip_conntrack *ct)
+{
+       struct ip_conntrack_ecache *ecache;
+
+       /* take care of delivering potentially old events */
+       ecache = &__get_cpu_var(ip_conntrack_ecache);
+       BUG_ON(ecache->ct == ct);
+       if (ecache->ct)
+               __ip_ct_deliver_cached_events(ecache);
+       /* initialize for this conntrack/packet */
+       ecache->ct = ct;
+       nf_conntrack_get(&ct->ct_general);
+}
+
+/* flush the event cache - touches other CPU's data and must not be called while
+ * packets are still passing through the code */
+static void ip_ct_event_cache_flush(void)
+{
+       struct ip_conntrack_ecache *ecache;
+       int cpu;
+
+       for_each_cpu(cpu) {
+               ecache = &per_cpu(ip_conntrack_ecache, cpu);
+               if (ecache->ct)
+                       ip_conntrack_put(ecache->ct);
+       }
+}
+#else
+static inline void ip_ct_event_cache_flush(void) {}
+#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
+
+DEFINE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat);
+
 static int ip_conntrack_hash_rnd_initted;
 static unsigned int ip_conntrack_hash_rnd;
 
@@ -137,13 +197,14 @@ ip_ct_invert_tuple(struct ip_conntrack_tuple *inverse,
 
 
 /* ip_conntrack_expect helper functions */
-static void unlink_expect(struct ip_conntrack_expect *exp)
+void ip_ct_unlink_expect(struct ip_conntrack_expect *exp)
 {
        ASSERT_WRITE_LOCK(&ip_conntrack_lock);
        IP_NF_ASSERT(!timer_pending(&exp->timeout));
        list_del(&exp->list);
        CONNTRACK_STAT_INC(expect_delete);
        exp->master->expecting--;
+       ip_conntrack_expect_put(exp);
 }
 
 static void expectation_timed_out(unsigned long ul_expect)
@@ -151,11 +212,38 @@ static void expectation_timed_out(unsigned long ul_expect)
        struct ip_conntrack_expect *exp = (void *)ul_expect;
 
        write_lock_bh(&ip_conntrack_lock);
-       unlink_expect(exp);
+       ip_ct_unlink_expect(exp);
        write_unlock_bh(&ip_conntrack_lock);
        ip_conntrack_expect_put(exp);
 }
 
+struct ip_conntrack_expect *
+__ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple)
+{
+       struct ip_conntrack_expect *i;
+       
+       list_for_each_entry(i, &ip_conntrack_expect_list, list) {
+               if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) {
+                       atomic_inc(&i->use);
+                       return i;
+               }
+       }
+       return NULL;
+}
+
+/* Just find a expectation corresponding to a tuple. */
+struct ip_conntrack_expect *
+ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
+{
+       struct ip_conntrack_expect *i;
+       
+       read_lock_bh(&ip_conntrack_lock);
+       i = __ip_conntrack_expect_find(tuple);
+       read_unlock_bh(&ip_conntrack_lock);
+
+       return i;
+}
+
 /* If an expectation for this connection is found, it gets delete from
  * global list then returned. */
 static struct ip_conntrack_expect *
@@ -170,17 +258,21 @@ find_expectation(const struct ip_conntrack_tuple *tuple)
                   master ct never got confirmed, we'd hold a reference to it
                   and weird things would happen to future packets). */
                if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)
-                   && is_confirmed(i->master)
-                   && del_timer(&i->timeout)) {
-                       unlink_expect(i);
-                       return i;
+                   && is_confirmed(i->master)) {
+                       if (i->flags & IP_CT_EXPECT_PERMANENT) {
+                               atomic_inc(&i->use);
+                               return i;
+                       } else if (del_timer(&i->timeout)) {
+                               ip_ct_unlink_expect(i);
+                               return i;
+                       }
                }
        }
        return NULL;
 }
 
 /* delete all expectations for this conntrack */
-static void remove_expectations(struct ip_conntrack *ct)
+void ip_ct_remove_expectations(struct ip_conntrack *ct)
 {
        struct ip_conntrack_expect *i, *tmp;
 
@@ -190,7 +282,7 @@ static void remove_expectations(struct ip_conntrack *ct)
 
        list_for_each_entry_safe(i, tmp, &ip_conntrack_expect_list, list) {
                if (i->master == ct && del_timer(&i->timeout)) {
-                       unlink_expect(i);
+                       ip_ct_unlink_expect(i);
                        ip_conntrack_expect_put(i);
                }
        }
@@ -210,7 +302,7 @@ clean_from_lists(struct ip_conntrack *ct)
        LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
 
        /* Destroy all pending expectations */
-       remove_expectations(ct);
+       ip_ct_remove_expectations(ct);
 }
 
 static void
@@ -223,10 +315,13 @@ destroy_conntrack(struct nf_conntrack *nfct)
        IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
        IP_NF_ASSERT(!timer_pending(&ct->timeout));
 
+       ip_conntrack_event(IPCT_DESTROY, ct);
+       set_bit(IPS_DYING_BIT, &ct->status);
+
        /* To make sure we don't get any weird locking issues here:
         * destroy_conntrack() MUST NOT be called with a write lock
         * to ip_conntrack_lock!!! -HW */
-       proto = ip_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
+       proto = __ip_conntrack_proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
        if (proto && proto->destroy)
                proto->destroy(ct);
 
@@ -238,7 +333,7 @@ destroy_conntrack(struct nf_conntrack *nfct)
         * except TFTP can create an expectation on the first packet,
         * before connection is in the list, so we need to clean here,
         * too. */
-       remove_expectations(ct);
+       ip_ct_remove_expectations(ct);
 
        /* We overload first tuple to link into unconfirmed list. */
        if (!is_confirmed(ct)) {
@@ -253,8 +348,7 @@ destroy_conntrack(struct nf_conntrack *nfct)
                ip_conntrack_put(ct->master);
 
        DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
-       kmem_cache_free(ip_conntrack_cachep, ct);
-       atomic_dec(&ip_conntrack_count);
+       ip_conntrack_free(ct);
 }
 
 static void death_by_timeout(unsigned long ul_conntrack)
@@ -280,7 +374,7 @@ conntrack_tuple_cmp(const struct ip_conntrack_tuple_hash *i,
                && ip_ct_tuple_equal(tuple, &i->tuple);
 }
 
-static struct ip_conntrack_tuple_hash *
+struct ip_conntrack_tuple_hash *
 __ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
                    const struct ip_conntrack *ignored_conntrack)
 {
@@ -315,6 +409,29 @@ ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
        return h;
 }
 
+static void __ip_conntrack_hash_insert(struct ip_conntrack *ct,
+                                       unsigned int hash,
+                                       unsigned int repl_hash) 
+{
+       ct->id = ++ip_conntrack_next_id;
+       list_prepend(&ip_conntrack_hash[hash],
+                    &ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
+       list_prepend(&ip_conntrack_hash[repl_hash],
+                    &ct->tuplehash[IP_CT_DIR_REPLY].list);
+}
+
+void ip_conntrack_hash_insert(struct ip_conntrack *ct)
+{
+       unsigned int hash, repl_hash;
+
+       hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+       repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+
+       write_lock_bh(&ip_conntrack_lock);
+       __ip_conntrack_hash_insert(ct, hash, repl_hash);
+       write_unlock_bh(&ip_conntrack_lock);
+}
+
 /* Confirm a connection given skb; places it in hash table */
 int
 __ip_conntrack_confirm(struct sk_buff **pskb)
@@ -361,10 +478,7 @@ __ip_conntrack_confirm(struct sk_buff **pskb)
                /* Remove from unconfirmed list */
                list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
 
-               list_prepend(&ip_conntrack_hash[hash],
-                            &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
-               list_prepend(&ip_conntrack_hash[repl_hash],
-                            &ct->tuplehash[IP_CT_DIR_REPLY]);
+               __ip_conntrack_hash_insert(ct, hash, repl_hash);
                /* Timer relative to confirmation time, not original
                   setting time, otherwise we'd get timer wrap in
                   weird delay cases. */
@@ -374,6 +488,16 @@ __ip_conntrack_confirm(struct sk_buff **pskb)
                set_bit(IPS_CONFIRMED_BIT, &ct->status);
                CONNTRACK_STAT_INC(insert);
                write_unlock_bh(&ip_conntrack_lock);
+               if (ct->helper)
+                       ip_conntrack_event_cache(IPCT_HELPER, *pskb);
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+               if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) ||
+                   test_bit(IPS_DST_NAT_DONE_BIT, &ct->status))
+                       ip_conntrack_event_cache(IPCT_NATINFO, *pskb);
+#endif
+               ip_conntrack_event_cache(master_ct(ct) ?
+                                        IPCT_RELATED : IPCT_NEW, *pskb);
+
                return NF_ACCEPT;
        }
 
@@ -438,34 +562,84 @@ static inline int helper_cmp(const struct ip_conntrack_helper *i,
        return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
 }
 
-static struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
+static struct ip_conntrack_helper *
+__ip_conntrack_helper_find( const struct ip_conntrack_tuple *tuple)
 {
        return LIST_FIND(&helpers, helper_cmp,
                         struct ip_conntrack_helper *,
                         tuple);
 }
 
-/* Allocate a new conntrack: we return -ENOMEM if classification
-   failed due to stress.  Otherwise it really is unclassifiable. */
-static struct ip_conntrack_tuple_hash *
-init_conntrack(const struct ip_conntrack_tuple *tuple,
-              struct ip_conntrack_protocol *protocol,
-              struct sk_buff *skb)
+struct ip_conntrack_helper *
+ip_conntrack_helper_find_get( const struct ip_conntrack_tuple *tuple)
+{
+       struct ip_conntrack_helper *helper;
+
+       /* need ip_conntrack_lock to assure that helper exists until
+        * try_module_get() is called */
+       read_lock_bh(&ip_conntrack_lock);
+
+       helper = __ip_conntrack_helper_find(tuple);
+       if (helper) {
+               /* need to increase module usage count to assure helper will
+                * not go away while the caller is e.g. busy putting a
+                * conntrack in the hash that uses the helper */
+               if (!try_module_get(helper->me))
+                       helper = NULL;
+       }
+
+       read_unlock_bh(&ip_conntrack_lock);
+
+       return helper;
+}
+
+void ip_conntrack_helper_put(struct ip_conntrack_helper *helper)
+{
+       module_put(helper->me);
+}
+
+struct ip_conntrack_protocol *
+__ip_conntrack_proto_find(u_int8_t protocol)
+{
+       return ip_ct_protos[protocol];
+}
+
+/* this is guaranteed to always return a valid protocol helper, since
+ * it falls back to generic_protocol */
+struct ip_conntrack_protocol *
+ip_conntrack_proto_find_get(u_int8_t protocol)
+{
+       struct ip_conntrack_protocol *p;
+
+       preempt_disable();
+       p = __ip_conntrack_proto_find(protocol);
+       if (p) {
+               if (!try_module_get(p->me))
+                       p = &ip_conntrack_generic_protocol;
+       }
+       preempt_enable();
+       
+       return p;
+}
+
+void ip_conntrack_proto_put(struct ip_conntrack_protocol *p)
+{
+       module_put(p->me);
+}
+
+struct ip_conntrack *ip_conntrack_alloc(struct ip_conntrack_tuple *orig,
+                                       struct ip_conntrack_tuple *repl)
 {
        struct ip_conntrack *conntrack;
-       struct ip_conntrack_tuple repl_tuple;
-       size_t hash;
-       struct ip_conntrack_expect *exp;
 
        if (!ip_conntrack_hash_rnd_initted) {
                get_random_bytes(&ip_conntrack_hash_rnd, 4);
                ip_conntrack_hash_rnd_initted = 1;
        }
 
-       hash = hash_conntrack(tuple);
-
        if (ip_conntrack_max
            && atomic_read(&ip_conntrack_count) >= ip_conntrack_max) {
+               unsigned int hash = hash_conntrack(orig);
                /* Try dropping from this hash chain. */
                if (!early_drop(&ip_conntrack_hash[hash])) {
                        if (net_ratelimit())
@@ -476,11 +650,6 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
                }
        }
 
-       if (!ip_ct_invert_tuple(&repl_tuple, tuple, protocol)) {
-               DEBUGP("Can't invert tuple.\n");
-               return NULL;
-       }
-
        conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
        if (!conntrack) {
                DEBUGP("Can't allocate conntrack.\n");
@@ -490,17 +659,50 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
        memset(conntrack, 0, sizeof(*conntrack));
        atomic_set(&conntrack->ct_general.use, 1);
        conntrack->ct_general.destroy = destroy_conntrack;
-       conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
-       conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple;
-       if (!protocol->new(conntrack, skb)) {
-               kmem_cache_free(ip_conntrack_cachep, conntrack);
-               return NULL;
-       }
+       conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig;
+       conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *repl;
        /* Don't set timer yet: wait for confirmation */
        init_timer(&conntrack->timeout);
        conntrack->timeout.data = (unsigned long)conntrack;
        conntrack->timeout.function = death_by_timeout;
 
+       atomic_inc(&ip_conntrack_count);
+
+       return conntrack;
+}
+
+void
+ip_conntrack_free(struct ip_conntrack *conntrack)
+{
+       atomic_dec(&ip_conntrack_count);
+       kmem_cache_free(ip_conntrack_cachep, conntrack);
+}
+
+/* Allocate a new conntrack: we return -ENOMEM if classification
+ * failed due to stress.   Otherwise it really is unclassifiable */
+static struct ip_conntrack_tuple_hash *
+init_conntrack(struct ip_conntrack_tuple *tuple,
+              struct ip_conntrack_protocol *protocol,
+              struct sk_buff *skb)
+{
+       struct ip_conntrack *conntrack;
+       struct ip_conntrack_tuple repl_tuple;
+       struct ip_conntrack_expect *exp;
+
+       if (!ip_ct_invert_tuple(&repl_tuple, tuple, protocol)) {
+               DEBUGP("Can't invert tuple.\n");
+               return NULL;
+       }
+
+       conntrack = ip_conntrack_alloc(tuple, &repl_tuple);
+       if (conntrack == NULL || IS_ERR(conntrack))
+               return (struct ip_conntrack_tuple_hash *)conntrack;
+
+       if (!protocol->new(conntrack, skb)) {
+               ip_conntrack_free(conntrack);
+               return NULL;
+       }
+
        write_lock_bh(&ip_conntrack_lock);
        exp = find_expectation(tuple);
 
@@ -521,7 +723,7 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
                nf_conntrack_get(&conntrack->master->ct_general);
                CONNTRACK_STAT_INC(expect_new);
        } else {
-               conntrack->helper = ip_ct_find_helper(&repl_tuple);
+               conntrack->helper = __ip_conntrack_helper_find(&repl_tuple);
 
                CONNTRACK_STAT_INC(new);
        }
@@ -529,7 +731,6 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
        /* Overload tuple linked list to put us in unconfirmed list. */
        list_add(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list, &unconfirmed);
 
-       atomic_inc(&ip_conntrack_count);
        write_unlock_bh(&ip_conntrack_lock);
 
        if (exp) {
@@ -607,7 +808,7 @@ unsigned int ip_conntrack_in(unsigned int hooknum,
        struct ip_conntrack *ct;
        enum ip_conntrack_info ctinfo;
        struct ip_conntrack_protocol *proto;
-       int set_reply;
+       int set_reply = 0;
        int ret;
 
        /* Previously seen (loopback or untracked)?  Ignore. */
@@ -625,9 +826,6 @@ unsigned int ip_conntrack_in(unsigned int hooknum,
                return NF_DROP;
        }
 
-       /* FIXME: Do this right please. --RR */
-       (*pskb)->nfcache |= NFC_UNKNOWN;
-
 /* Doesn't cover locally-generated broadcast, so not worth it. */
 #if 0
        /* Ignore broadcast: no `connection'. */
@@ -643,7 +841,7 @@ unsigned int ip_conntrack_in(unsigned int hooknum,
        }
 #endif
 
-       proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
+       proto = __ip_conntrack_proto_find((*pskb)->nh.iph->protocol);
 
        /* It may be an special packet, error, unclean...
         * inverse of the return code tells to the netfilter
@@ -679,8 +877,8 @@ unsigned int ip_conntrack_in(unsigned int hooknum,
                return -ret;
        }
 
-       if (set_reply)
-               set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
+       if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status))
+               ip_conntrack_event_cache(IPCT_STATUS, *pskb);
 
        return ret;
 }
@@ -689,7 +887,7 @@ int invert_tuplepr(struct ip_conntrack_tuple *inverse,
                   const struct ip_conntrack_tuple *orig)
 {
        return ip_ct_invert_tuple(inverse, orig, 
-                                 ip_ct_find_proto(orig->dst.protonum));
+                                 __ip_conntrack_proto_find(orig->dst.protonum));
 }
 
 /* Would two expected things clash? */
@@ -725,7 +923,7 @@ void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp)
        /* choose the the oldest expectation to evict */
        list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) {
                if (expect_matches(i, exp) && del_timer(&i->timeout)) {
-                       unlink_expect(i);
+                       ip_ct_unlink_expect(i);
                        write_unlock_bh(&ip_conntrack_lock);
                        ip_conntrack_expect_put(i);
                        return;
@@ -734,6 +932,9 @@ void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp)
        write_unlock_bh(&ip_conntrack_lock);
 }
 
+/* We don't increase the master conntrack refcount for non-fulfilled
+ * conntracks. During the conntrack destruction, the expectations are 
+ * always killed before the conntrack itself */
 struct ip_conntrack_expect *ip_conntrack_expect_alloc(struct ip_conntrack *me)
 {
        struct ip_conntrack_expect *new;
@@ -744,17 +945,14 @@ struct ip_conntrack_expect *ip_conntrack_expect_alloc(struct ip_conntrack *me)
                return NULL;
        }
        new->master = me;
-       atomic_inc(&new->master->ct_general.use);
        atomic_set(&new->use, 1);
        return new;
 }
 
 void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
 {
-       if (atomic_dec_and_test(&exp->use)) {
-               ip_conntrack_put(exp->master);
+       if (atomic_dec_and_test(&exp->use))
                kmem_cache_free(ip_conntrack_expect_cachep, exp);
-       }
 }
 
 static void ip_conntrack_expect_insert(struct ip_conntrack_expect *exp)
@@ -769,6 +967,8 @@ static void ip_conntrack_expect_insert(struct ip_conntrack_expect *exp)
        exp->timeout.expires = jiffies + exp->master->helper->timeout * HZ;
        add_timer(&exp->timeout);
 
+       exp->id = ++ip_conntrack_expect_next_id;
+       atomic_inc(&exp->use);
        CONNTRACK_STAT_INC(expect_create);
 }
 
@@ -780,7 +980,7 @@ static void evict_oldest_expect(struct ip_conntrack *master)
        list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) {
                if (i->master == master) {
                        if (del_timer(&i->timeout)) {
-                               unlink_expect(i);
+                               ip_ct_unlink_expect(i);
                                ip_conntrack_expect_put(i);
                        }
                        break;
@@ -827,6 +1027,7 @@ int ip_conntrack_expect_related(struct ip_conntrack_expect *expect)
                evict_oldest_expect(expect->master);
 
        ip_conntrack_expect_insert(expect);
+       ip_conntrack_expect_event(IPEXP_NEW, expect);
        ret = 0;
 out:
        write_unlock_bh(&ip_conntrack_lock);
@@ -847,7 +1048,7 @@ void ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
 
        conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
        if (!conntrack->master && conntrack->expecting == 0)
-               conntrack->helper = ip_ct_find_helper(newreply);
+               conntrack->helper = __ip_conntrack_helper_find(newreply);
        write_unlock_bh(&ip_conntrack_lock);
 }
 
@@ -861,11 +1062,26 @@ int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
        return 0;
 }
 
+struct ip_conntrack_helper *
+__ip_conntrack_helper_find_byname(const char *name)
+{
+       struct ip_conntrack_helper *h;
+
+       list_for_each_entry(h, &helpers, list) {
+               if (!strcmp(h->name, name))
+                       return h;
+       }
+
+       return NULL;
+}
+
 static inline int unhelp(struct ip_conntrack_tuple_hash *i,
                         const struct ip_conntrack_helper *me)
 {
-       if (tuplehash_to_ctrack(i)->helper == me)
+       if (tuplehash_to_ctrack(i)->helper == me) {
+               ip_conntrack_event(IPCT_HELPER, tuplehash_to_ctrack(i));
                tuplehash_to_ctrack(i)->helper = NULL;
+       }
        return 0;
 }
 
@@ -881,7 +1097,7 @@ void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
        /* Get rid of expectations */
        list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, list) {
                if (exp->master->helper == me && del_timer(&exp->timeout)) {
-                       unlink_expect(exp);
+                       ip_ct_unlink_expect(exp);
                        ip_conntrack_expect_put(exp);
                }
        }
@@ -927,12 +1143,46 @@ void ip_ct_refresh_acct(struct ip_conntrack *ct,
                if (del_timer(&ct->timeout)) {
                        ct->timeout.expires = jiffies + extra_jiffies;
                        add_timer(&ct->timeout);
+                       ip_conntrack_event_cache(IPCT_REFRESH, skb);
                }
                ct_add_counters(ct, ctinfo, skb);
                write_unlock_bh(&ip_conntrack_lock);
        }
 }
 
+#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
+    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
+/* Generic function for tcp/udp/sctp/dccp and alike. This needs to be
+ * in ip_conntrack_core, since we don't want the protocols to autoload
+ * or depend on ctnetlink */
+int ip_ct_port_tuple_to_nfattr(struct sk_buff *skb,
+                              const struct ip_conntrack_tuple *tuple)
+{
+       NFA_PUT(skb, CTA_PROTO_SRC_PORT, sizeof(u_int16_t),
+               &tuple->src.u.tcp.port);
+       NFA_PUT(skb, CTA_PROTO_DST_PORT, sizeof(u_int16_t),
+               &tuple->dst.u.tcp.port);
+       return 0;
+
+nfattr_failure:
+       return -1;
+}
+
+int ip_ct_port_nfattr_to_tuple(struct nfattr *tb[],
+                              struct ip_conntrack_tuple *t)
+{
+       if (!tb[CTA_PROTO_SRC_PORT-1] || !tb[CTA_PROTO_DST_PORT-1])
+               return -EINVAL;
+
+       t->src.u.tcp.port =
+               *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]);
+       t->dst.u.tcp.port =
+               *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]);
+
+       return 0;
+}
+#endif
+
 /* Returns new sk_buff, or NULL */
 struct sk_buff *
 ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user)
@@ -943,10 +1193,8 @@ ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user)
        skb = ip_defrag(skb, user);
        local_bh_enable();
 
-       if (skb) {
+       if (skb)
                ip_send_check(skb->nh.iph);
-               skb->nfcache |= NFC_ALTERED;
-       }
        return skb;
 }
 
@@ -1096,16 +1344,14 @@ static void free_conntrack_hash(void)
                                     * ip_conntrack_htable_size));
 }
 
-/* Mishearing the voices in his head, our hero wonders how he's
-   supposed to kill the mall. */
-void ip_conntrack_cleanup(void)
+void ip_conntrack_flush()
 {
-       ip_ct_attach = NULL;
        /* This makes sure all current packets have passed through
            netfilter framework.  Roll on, two-stage module
            delete... */
        synchronize_net();
+
+       ip_ct_event_cache_flush();
  i_see_dead_people:
        ip_ct_iterate_cleanup(kill_all, NULL);
        if (atomic_read(&ip_conntrack_count) != 0) {
@@ -1115,7 +1361,14 @@ void ip_conntrack_cleanup(void)
        /* wait until all references to ip_conntrack_untracked are dropped */
        while (atomic_read(&ip_conntrack_untracked.ct_general.use) > 1)
                schedule();
+}
 
+/* Mishearing the voices in his head, our hero wonders how he's
+   supposed to kill the mall. */
+void ip_conntrack_cleanup(void)
+{
+       ip_ct_attach = NULL;
+       ip_conntrack_flush();
        kmem_cache_destroy(ip_conntrack_cachep);
        kmem_cache_destroy(ip_conntrack_expect_cachep);
        free_conntrack_hash();
index 7a3b773be3f93cf4e7a2d1d706fec6d63f3f252c..1b79ec36085ffed8896fdd9882126b24400fd57c 100644 (file)
@@ -25,8 +25,7 @@ MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
 MODULE_DESCRIPTION("ftp connection tracking helper");
 
 /* This is slow, but it's simple. --RR */
-static char ftp_buffer[65536];
-
+static char *ftp_buffer;
 static DEFINE_SPINLOCK(ip_ftp_lock);
 
 #define MAX_PORTS 8
@@ -262,7 +261,8 @@ static int find_nl_seq(u32 seq, const struct ip_ct_ftp_master *info, int dir)
 }
 
 /* We don't update if it's older than what we have. */
-static void update_nl_seq(u32 nl_seq, struct ip_ct_ftp_master *info, int dir)
+static void update_nl_seq(u32 nl_seq, struct ip_ct_ftp_master *info, int dir,
+                         struct sk_buff *skb)
 {
        unsigned int i, oldest = NUM_SEQ_TO_REMEMBER;
 
@@ -276,10 +276,13 @@ static void update_nl_seq(u32 nl_seq, struct ip_ct_ftp_master *info, int dir)
                        oldest = i;
        }
 
-       if (info->seq_aft_nl_num[dir] < NUM_SEQ_TO_REMEMBER)
+       if (info->seq_aft_nl_num[dir] < NUM_SEQ_TO_REMEMBER) {
                info->seq_aft_nl[dir][info->seq_aft_nl_num[dir]++] = nl_seq;
-       else if (oldest != NUM_SEQ_TO_REMEMBER)
+               ip_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, skb);
+       } else if (oldest != NUM_SEQ_TO_REMEMBER) {
                info->seq_aft_nl[dir][oldest] = nl_seq;
+               ip_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, skb);
+       }
 }
 
 static int help(struct sk_buff **pskb,
@@ -418,6 +421,7 @@ static int help(struct sk_buff **pskb,
                  { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }});
 
        exp->expectfn = NULL;
+       exp->flags = 0;
 
        /* Now, NAT might want to mangle the packet, and register the
         * (possibly changed) expectation itself. */
@@ -439,7 +443,7 @@ out_update_nl:
        /* Now if this ends in \n, update ftp info.  Seq may have been
         * adjusted by NAT code. */
        if (ends_in_nl)
-               update_nl_seq(seq, ct_ftp_info,dir);
+               update_nl_seq(seq, ct_ftp_info,dir, *pskb);
  out:
        spin_unlock_bh(&ip_ftp_lock);
        return ret;
@@ -457,6 +461,8 @@ static void fini(void)
                                ports[i]);
                ip_conntrack_helper_unregister(&ftp[i]);
        }
+
+       kfree(ftp_buffer);
 }
 
 static int __init init(void)
@@ -464,6 +470,10 @@ static int __init init(void)
        int i, ret;
        char *tmpname;
 
+       ftp_buffer = kmalloc(65536, GFP_KERNEL);
+       if (!ftp_buffer)
+               return -ENOMEM;
+
        if (ports_c == 0)
                ports[ports_c++] = FTP_PORT;
 
index 4a28f297d502a38d4c10b780306b5bfca127f97f..d7a8a98c05e1982a9b4b13839ac169a44d00deea 100644 (file)
@@ -39,7 +39,7 @@ static int ports_c;
 static int max_dcc_channels = 8;
 static unsigned int dcc_timeout = 300;
 /* This is slow, but it's simple. --RR */
-static char irc_buffer[65536];
+static char *irc_buffer;
 static DEFINE_SPINLOCK(irc_buffer_lock);
 
 unsigned int (*ip_nat_irc_hook)(struct sk_buff **pskb,
@@ -221,6 +221,7 @@ static int help(struct sk_buff **pskb,
                                { { 0, { 0 } },
                                  { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }});
                        exp->expectfn = NULL;
+                       exp->flags = 0;
                        if (ip_nat_irc_hook)
                                ret = ip_nat_irc_hook(pskb, ctinfo, 
                                                      addr_beg_p - ib_ptr,
@@ -257,6 +258,10 @@ static int __init init(void)
                printk("ip_conntrack_irc: dcc_timeout must be a positive integer\n");
                return -EBUSY;
        }
+
+       irc_buffer = kmalloc(65536, GFP_KERNEL);
+       if (!irc_buffer)
+               return -ENOMEM;
        
        /* If no port given, default to standard irc port */
        if (ports_c == 0)
@@ -304,6 +309,7 @@ static void fini(void)
                       ports[i]);
                ip_conntrack_helper_unregister(&irc_helpers[i]);
        }
+       kfree(irc_buffer);
 }
 
 module_init(init);
diff --git a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
new file mode 100644 (file)
index 0000000..2b5cf9c
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ *      NetBIOS name service broadcast connection tracking helper
+ *
+ *      (c) 2005 Patrick McHardy <kaber@trash.net>
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+/*
+ *      This helper tracks locally originating NetBIOS name service
+ *      requests by issuing permanent expectations (valid until
+ *      timing out) matching all reply connections from the
+ *      destination network. The only NetBIOS specific thing is
+ *      actually the port number.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <net/route.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_DESCRIPTION("NetBIOS name service broadcast connection tracking helper");
+MODULE_LICENSE("GPL");
+
+static unsigned int timeout = 3;
+module_param(timeout, int, 0600);
+MODULE_PARM_DESC(timeout, "timeout for master connection/replies in seconds");
+
+static int help(struct sk_buff **pskb,
+                struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
+{
+       struct ip_conntrack_expect *exp;
+       struct iphdr *iph = (*pskb)->nh.iph;
+       struct udphdr _uh, *uh;
+       struct rtable *rt = (struct rtable *)(*pskb)->dst;
+       struct in_device *in_dev;
+       u_int32_t mask = 0;
+
+       /* we're only interested in locally generated packets */
+       if ((*pskb)->sk == NULL)
+               goto out;
+       if (rt == NULL || !(rt->rt_flags & RTCF_BROADCAST))
+               goto out;
+       if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
+               goto out;
+
+       rcu_read_lock();
+       in_dev = __in_dev_get(rt->u.dst.dev);
+       if (in_dev != NULL) {
+               for_primary_ifa(in_dev) {
+                       if (ifa->ifa_broadcast == iph->daddr) {
+                               mask = ifa->ifa_mask;
+                               break;
+                       }
+               } endfor_ifa(in_dev);
+       }
+       rcu_read_unlock();
+
+       if (mask == 0)
+               goto out;
+
+       uh = skb_header_pointer(*pskb, iph->ihl * 4, sizeof(_uh), &_uh);
+       BUG_ON(uh == NULL);
+
+       exp = ip_conntrack_expect_alloc(ct);
+       if (exp == NULL)
+               goto out;
+       memset(&exp->tuple, 0, sizeof(exp->tuple));
+       exp->tuple.src.ip         = iph->daddr & mask;
+       exp->tuple.dst.ip         = iph->saddr;
+       exp->tuple.dst.u.udp.port = uh->source;
+       exp->tuple.dst.protonum   = IPPROTO_UDP;
+
+       memset(&exp->mask, 0, sizeof(exp->mask));
+       exp->mask.src.ip          = mask;
+       exp->mask.dst.ip          = 0xFFFFFFFF;
+       exp->mask.dst.u.udp.port  = 0xFFFF;
+       exp->mask.dst.protonum    = 0xFF;
+
+       exp->expectfn             = NULL;
+       exp->flags                = IP_CT_EXPECT_PERMANENT;
+
+       ip_conntrack_expect_related(exp);
+       ip_conntrack_expect_put(exp);
+
+       ip_ct_refresh_acct(ct, ctinfo, NULL, timeout * HZ);
+out:
+       return NF_ACCEPT;
+}
+
+static struct ip_conntrack_helper helper = {
+       .name                   = "netbios-ns",
+       .tuple = {
+               .src.u.udp.port = __constant_htons(137),
+               .dst.protonum   = IPPROTO_UDP,
+       },
+       .mask = {
+               .src.u.udp.port = 0xFFFF,
+               .dst.protonum   = 0xFF,
+       },
+       .max_expected           = 1,
+       .me                     = THIS_MODULE,
+       .help                   = help,
+};
+
+static int __init init(void)
+{
+       helper.timeout = timeout;
+       return ip_conntrack_helper_register(&helper);
+}
+
+static void __exit fini(void)
+{
+       ip_conntrack_helper_unregister(&helper);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
new file mode 100644 (file)
index 0000000..15aef35
--- /dev/null
@@ -0,0 +1,1584 @@
+/* Connection tracking via netlink socket. Allows for user space
+ * protocol helpers and general trouble making from userspace.
+ *
+ * (C) 2001 by Jay Schulist <jschlst@samba.org>
+ * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2003 by Patrick Mchardy <kaber@trash.net>
+ * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
+ *
+ * I've reworked this stuff to use attributes instead of conntrack 
+ * structures. 5.44 am. I need more tea. --pablo 05/07/11.
+ *
+ * Initial connection tracking via netlink development funded and 
+ * generally made possible by Network Robots, Inc. (www.networkrobots.com)
+ *
+ * Further development of this code funded by Astaro AG (http://www.astaro.com)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/skbuff.h>
+#include <linux/errno.h>
+#include <linux/netlink.h>
+#include <linux/spinlock.h>
+#include <linux/notifier.h>
+#include <linux/rtnetlink.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+#include <linux/netfilter_ipv4/ip_nat_protocol.h>
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_conntrack.h>
+
+MODULE_LICENSE("GPL");
+
+static char __initdata version[] = "0.90";
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+
+static inline int
+ctnetlink_dump_tuples_proto(struct sk_buff *skb, 
+                           const struct ip_conntrack_tuple *tuple)
+{
+       struct ip_conntrack_protocol *proto;
+
+       NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum);
+
+       proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
+       if (proto && proto->tuple_to_nfattr)
+               return proto->tuple_to_nfattr(skb, tuple);
+
+       return 0;
+
+nfattr_failure:
+       return -1;
+}
+
+static inline int
+ctnetlink_dump_tuples(struct sk_buff *skb, 
+                     const struct ip_conntrack_tuple *tuple)
+{
+       struct nfattr *nest_parms;
+       
+       nest_parms = NFA_NEST(skb, CTA_TUPLE_IP);
+       NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), &tuple->src.ip);
+       NFA_PUT(skb, CTA_IP_V4_DST, sizeof(u_int32_t), &tuple->dst.ip);
+       NFA_NEST_END(skb, nest_parms);
+
+       nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO);
+       ctnetlink_dump_tuples_proto(skb, tuple);
+       NFA_NEST_END(skb, nest_parms);
+
+       return 0;
+
+nfattr_failure:
+       return -1;
+}
+
+static inline int
+ctnetlink_dump_status(struct sk_buff *skb, const struct ip_conntrack *ct)
+{
+       u_int32_t status = htonl((u_int32_t) ct->status);
+       NFA_PUT(skb, CTA_STATUS, sizeof(status), &status);
+       return 0;
+
+nfattr_failure:
+       return -1;
+}
+
+static inline int
+ctnetlink_dump_timeout(struct sk_buff *skb, const struct ip_conntrack *ct)
+{
+       long timeout_l = ct->timeout.expires - jiffies;
+       u_int32_t timeout;
+
+       if (timeout_l < 0)
+               timeout = 0;
+       else
+               timeout = htonl(timeout_l / HZ);
+       
+       NFA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout);
+       return 0;
+
+nfattr_failure:
+       return -1;
+}
+
+static inline int
+ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct ip_conntrack *ct)
+{
+       struct ip_conntrack_protocol *proto = ip_conntrack_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
+
+       struct nfattr *nest_proto;
+       int ret;
+       
+       if (!proto || !proto->to_nfattr)
+               return 0;
+       
+       nest_proto = NFA_NEST(skb, CTA_PROTOINFO);
+
+       ret = proto->to_nfattr(skb, nest_proto, ct);
+
+       ip_conntrack_proto_put(proto);
+
+       NFA_NEST_END(skb, nest_proto);
+
+       return ret;
+
+nfattr_failure:
+       return -1;
+}
+
+static inline int
+ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct ip_conntrack *ct)
+{
+       struct nfattr *nest_helper;
+
+       if (!ct->helper)
+               return 0;
+               
+       nest_helper = NFA_NEST(skb, CTA_HELP);
+       NFA_PUT(skb, CTA_HELP_NAME, CTA_HELP_MAXNAMESIZE, &ct->helper->name);
+
+       if (ct->helper->to_nfattr)
+               ct->helper->to_nfattr(skb, ct);
+
+       NFA_NEST_END(skb, nest_helper);
+
+       return 0;
+
+nfattr_failure:
+       return -1;
+}
+
+#ifdef CONFIG_IP_NF_CT_ACCT
+static inline int
+ctnetlink_dump_counters(struct sk_buff *skb, const struct ip_conntrack *ct,
+                       enum ip_conntrack_dir dir)
+{
+       enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;
+       struct nfattr *nest_count = NFA_NEST(skb, type);
+       u_int64_t tmp;
+
+       tmp = cpu_to_be64(ct->counters[dir].packets);
+       NFA_PUT(skb, CTA_COUNTERS_PACKETS, sizeof(u_int64_t), &tmp);
+
+       tmp = cpu_to_be64(ct->counters[dir].bytes);
+       NFA_PUT(skb, CTA_COUNTERS_BYTES, sizeof(u_int64_t), &tmp);
+
+       NFA_NEST_END(skb, nest_count);
+
+       return 0;
+
+nfattr_failure:
+       return -1;
+}
+#else
+#define ctnetlink_dump_counters(a, b, c) (0)
+#endif
+
+#ifdef CONFIG_IP_NF_CONNTRACK_MARK
+static inline int
+ctnetlink_dump_mark(struct sk_buff *skb, const struct ip_conntrack *ct)
+{
+       u_int32_t mark = htonl(ct->mark);
+
+       NFA_PUT(skb, CTA_MARK, sizeof(u_int32_t), &mark);
+       return 0;
+
+nfattr_failure:
+       return -1;
+}
+#else
+#define ctnetlink_dump_mark(a, b) (0)
+#endif
+
+static inline int
+ctnetlink_dump_id(struct sk_buff *skb, const struct ip_conntrack *ct)
+{
+       u_int32_t id = htonl(ct->id);
+       NFA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id);
+       return 0;
+
+nfattr_failure:
+       return -1;
+}
+
+static inline int
+ctnetlink_dump_use(struct sk_buff *skb, const struct ip_conntrack *ct)
+{
+       unsigned int use = htonl(atomic_read(&ct->ct_general.use));
+       
+       NFA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use);
+       return 0;
+
+nfattr_failure:
+       return -1;
+}
+
+#define tuple(ct, dir) (&(ct)->tuplehash[dir].tuple)
+
+static int
+ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
+                   int event, int nowait, 
+                   const struct ip_conntrack *ct)
+{
+       struct nlmsghdr *nlh;
+       struct nfgenmsg *nfmsg;
+       struct nfattr *nest_parms;
+       unsigned char *b;
+
+       b = skb->tail;
+
+       event |= NFNL_SUBSYS_CTNETLINK << 8;
+       nlh    = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg));
+       nfmsg  = NLMSG_DATA(nlh);
+
+       nlh->nlmsg_flags    = (nowait && pid) ? NLM_F_MULTI : 0;
+       nfmsg->nfgen_family = AF_INET;
+       nfmsg->version      = NFNETLINK_V0;
+       nfmsg->res_id       = 0;
+
+       nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG);
+       if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)
+               goto nfattr_failure;
+       NFA_NEST_END(skb, nest_parms);
+       
+       nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY);
+       if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0)
+               goto nfattr_failure;
+       NFA_NEST_END(skb, nest_parms);
+
+       if (ctnetlink_dump_status(skb, ct) < 0 ||
+           ctnetlink_dump_timeout(skb, ct) < 0 ||
+           ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
+           ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0 ||
+           ctnetlink_dump_protoinfo(skb, ct) < 0 ||
+           ctnetlink_dump_helpinfo(skb, ct) < 0 ||
+           ctnetlink_dump_mark(skb, ct) < 0 ||
+           ctnetlink_dump_id(skb, ct) < 0 ||
+           ctnetlink_dump_use(skb, ct) < 0)
+               goto nfattr_failure;
+
+       nlh->nlmsg_len = skb->tail - b;
+       return skb->len;
+
+nlmsg_failure:
+nfattr_failure:
+       skb_trim(skb, b - skb->data);
+       return -1;
+}
+
+#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
+static int ctnetlink_conntrack_event(struct notifier_block *this,
+                                     unsigned long events, void *ptr)
+{
+       struct nlmsghdr *nlh;
+       struct nfgenmsg *nfmsg;
+       struct nfattr *nest_parms;
+       struct ip_conntrack *ct = (struct ip_conntrack *)ptr;
+       struct sk_buff *skb;
+       unsigned int type;
+       unsigned char *b;
+       unsigned int flags = 0, group;
+
+       /* ignore our fake conntrack entry */
+       if (ct == &ip_conntrack_untracked)
+               return NOTIFY_DONE;
+
+       if (events & IPCT_DESTROY) {
+               type = IPCTNL_MSG_CT_DELETE;
+               group = NFNLGRP_CONNTRACK_DESTROY;
+               goto alloc_skb;
+       }
+       if (events & (IPCT_NEW | IPCT_RELATED)) {
+               type = IPCTNL_MSG_CT_NEW;
+               flags = NLM_F_CREATE|NLM_F_EXCL;
+               /* dump everything */
+               events = ~0UL;
+               group = NFNLGRP_CONNTRACK_NEW;
+               goto alloc_skb;
+       }
+       if (events & (IPCT_STATUS |
+                     IPCT_PROTOINFO |
+                     IPCT_HELPER |
+                     IPCT_HELPINFO |
+                     IPCT_NATINFO)) {
+               type = IPCTNL_MSG_CT_NEW;
+               group = NFNLGRP_CONNTRACK_UPDATE;
+               goto alloc_skb;
+       } 
+       
+       return NOTIFY_DONE;
+
+alloc_skb:
+  /* FIXME: Check if there are any listeners before, don't hurt performance */
+       
+       skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
+       if (!skb)
+               return NOTIFY_DONE;
+
+       b = skb->tail;
+
+       type |= NFNL_SUBSYS_CTNETLINK << 8;
+       nlh   = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));
+       nfmsg = NLMSG_DATA(nlh);
+
+       nlh->nlmsg_flags    = flags;
+       nfmsg->nfgen_family = AF_INET;
+       nfmsg->version  = NFNETLINK_V0;
+       nfmsg->res_id   = 0;
+
+       nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG);
+       if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)
+               goto nfattr_failure;
+       NFA_NEST_END(skb, nest_parms);
+       
+       nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY);
+       if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0)
+               goto nfattr_failure;
+       NFA_NEST_END(skb, nest_parms);
+       
+       /* NAT stuff is now a status flag */
+       if ((events & IPCT_STATUS || events & IPCT_NATINFO)
+           && ctnetlink_dump_status(skb, ct) < 0)
+               goto nfattr_failure;
+       if (events & IPCT_REFRESH
+           && ctnetlink_dump_timeout(skb, ct) < 0)
+               goto nfattr_failure;
+       if (events & IPCT_PROTOINFO
+           && ctnetlink_dump_protoinfo(skb, ct) < 0)
+               goto nfattr_failure;
+       if (events & IPCT_HELPINFO
+           && ctnetlink_dump_helpinfo(skb, ct) < 0)
+               goto nfattr_failure;
+
+       if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
+           ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)
+               goto nfattr_failure;
+
+       nlh->nlmsg_len = skb->tail - b;
+       nfnetlink_send(skb, 0, group, 0);
+       return NOTIFY_DONE;
+
+nlmsg_failure:
+nfattr_failure:
+       kfree_skb(skb);
+       return NOTIFY_DONE;
+}
+#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
+
+static int ctnetlink_done(struct netlink_callback *cb)
+{
+       DEBUGP("entered %s\n", __FUNCTION__);
+       return 0;
+}
+
+static int
+ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       struct ip_conntrack *ct = NULL;
+       struct ip_conntrack_tuple_hash *h;
+       struct list_head *i;
+       u_int32_t *id = (u_int32_t *) &cb->args[1];
+
+       DEBUGP("entered %s, last bucket=%lu id=%u\n", __FUNCTION__, 
+                       cb->args[0], *id);
+
+       read_lock_bh(&ip_conntrack_lock);
+       for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++, *id = 0) {
+               list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) {
+                       h = (struct ip_conntrack_tuple_hash *) i;
+                       if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
+                               continue;
+                       ct = tuplehash_to_ctrack(h);
+                       if (ct->id <= *id)
+                               continue;
+                       if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
+                                               cb->nlh->nlmsg_seq,
+                                               IPCTNL_MSG_CT_NEW,
+                                               1, ct) < 0)
+                               goto out;
+                       *id = ct->id;
+               }
+       }
+out:   
+       read_unlock_bh(&ip_conntrack_lock);
+
+       DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
+
+       return skb->len;
+}
+
+#ifdef CONFIG_IP_NF_CT_ACCT
+static int
+ctnetlink_dump_table_w(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       struct ip_conntrack *ct = NULL;
+       struct ip_conntrack_tuple_hash *h;
+       struct list_head *i;
+       u_int32_t *id = (u_int32_t *) &cb->args[1];
+
+       DEBUGP("entered %s, last bucket=%u id=%u\n", __FUNCTION__, 
+                       cb->args[0], *id);
+
+       write_lock_bh(&ip_conntrack_lock);
+       for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++, *id = 0) {
+               list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) {
+                       h = (struct ip_conntrack_tuple_hash *) i;
+                       if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
+                               continue;
+                       ct = tuplehash_to_ctrack(h);
+                       if (ct->id <= *id)
+                               continue;
+                       if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
+                                               cb->nlh->nlmsg_seq,
+                                               IPCTNL_MSG_CT_NEW,
+                                               1, ct) < 0)
+                               goto out;
+                       *id = ct->id;
+
+                       memset(&ct->counters, 0, sizeof(ct->counters));
+               }
+       }
+out:   
+       write_unlock_bh(&ip_conntrack_lock);
+
+       DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
+
+       return skb->len;
+}
+#endif
+
+static const int cta_min_ip[CTA_IP_MAX] = {
+       [CTA_IP_V4_SRC-1]       = sizeof(u_int32_t),
+       [CTA_IP_V4_DST-1]       = sizeof(u_int32_t),
+};
+
+static inline int
+ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple)
+{
+       struct nfattr *tb[CTA_IP_MAX];
+
+       DEBUGP("entered %s\n", __FUNCTION__);
+
+       
+       if (nfattr_parse_nested(tb, CTA_IP_MAX, attr) < 0)
+               goto nfattr_failure;
+
+       if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip))
+               return -EINVAL;
+
+       if (!tb[CTA_IP_V4_SRC-1])
+               return -EINVAL;
+       tuple->src.ip = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]);
+
+       if (!tb[CTA_IP_V4_DST-1])
+               return -EINVAL;
+       tuple->dst.ip = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]);
+
+       DEBUGP("leaving\n");
+
+       return 0;
+
+nfattr_failure:
+       return -1;
+}
+
+static const int cta_min_proto[CTA_PROTO_MAX] = {
+       [CTA_PROTO_NUM-1]       = sizeof(u_int16_t),
+       [CTA_PROTO_SRC_PORT-1]  = sizeof(u_int16_t),
+       [CTA_PROTO_DST_PORT-1]  = sizeof(u_int16_t),
+       [CTA_PROTO_ICMP_TYPE-1] = sizeof(u_int8_t),
+       [CTA_PROTO_ICMP_CODE-1] = sizeof(u_int8_t),
+       [CTA_PROTO_ICMP_ID-1]   = sizeof(u_int16_t),
+};
+
+static inline int
+ctnetlink_parse_tuple_proto(struct nfattr *attr, 
+                           struct ip_conntrack_tuple *tuple)
+{
+       struct nfattr *tb[CTA_PROTO_MAX];
+       struct ip_conntrack_protocol *proto;
+       int ret = 0;
+
+       DEBUGP("entered %s\n", __FUNCTION__);
+
+       if (nfattr_parse_nested(tb, CTA_PROTO_MAX, attr) < 0)
+               goto nfattr_failure;
+
+       if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
+               return -EINVAL;
+
+       if (!tb[CTA_PROTO_NUM-1])
+               return -EINVAL;
+       tuple->dst.protonum = *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]);
+
+       proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
+
+       if (likely(proto && proto->nfattr_to_tuple)) {
+               ret = proto->nfattr_to_tuple(tb, tuple);
+               ip_conntrack_proto_put(proto);
+       }
+       
+       return ret;
+
+nfattr_failure:
+       return -1;
+}
+
+static inline int
+ctnetlink_parse_tuple(struct nfattr *cda[], struct ip_conntrack_tuple *tuple,
+                     enum ctattr_tuple type)
+{
+       struct nfattr *tb[CTA_TUPLE_MAX];
+       int err;
+
+       DEBUGP("entered %s\n", __FUNCTION__);
+
+       memset(tuple, 0, sizeof(*tuple));
+
+       if (nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]) < 0)
+               goto nfattr_failure;
+
+       if (!tb[CTA_TUPLE_IP-1])
+               return -EINVAL;
+
+       err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP-1], tuple);
+       if (err < 0)
+               return err;
+
+       if (!tb[CTA_TUPLE_PROTO-1])
+               return -EINVAL;
+
+       err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO-1], tuple);
+       if (err < 0)
+               return err;
+
+       /* orig and expect tuples get DIR_ORIGINAL */
+       if (type == CTA_TUPLE_REPLY)
+               tuple->dst.dir = IP_CT_DIR_REPLY;
+       else
+               tuple->dst.dir = IP_CT_DIR_ORIGINAL;
+
+       DUMP_TUPLE(tuple);
+
+       DEBUGP("leaving\n");
+
+       return 0;
+
+nfattr_failure:
+       return -1;
+}
+
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+static const int cta_min_protonat[CTA_PROTONAT_MAX] = {
+       [CTA_PROTONAT_PORT_MIN-1]       = sizeof(u_int16_t),
+       [CTA_PROTONAT_PORT_MAX-1]       = sizeof(u_int16_t),
+};
+
+static int ctnetlink_parse_nat_proto(struct nfattr *attr,
+                                    const struct ip_conntrack *ct,
+                                    struct ip_nat_range *range)
+{
+       struct nfattr *tb[CTA_PROTONAT_MAX];
+       struct ip_nat_protocol *npt;
+
+       DEBUGP("entered %s\n", __FUNCTION__);
+
+       if (nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr) < 0)
+               goto nfattr_failure;
+
+       if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat))
+               goto nfattr_failure;
+
+       npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
+       if (!npt)
+               return 0;
+
+       if (!npt->nfattr_to_range) {
+               ip_nat_proto_put(npt);
+               return 0;
+       }
+
+       /* nfattr_to_range returns 1 if it parsed, 0 if not, neg. on error */
+       if (npt->nfattr_to_range(tb, range) > 0)
+               range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+
+       ip_nat_proto_put(npt);
+
+       DEBUGP("leaving\n");
+       return 0;
+
+nfattr_failure:
+       return -1;
+}
+
+static inline int
+ctnetlink_parse_nat(struct nfattr *cda[],
+                   const struct ip_conntrack *ct, struct ip_nat_range *range)
+{
+       struct nfattr *tb[CTA_NAT_MAX];
+       int err;
+
+       DEBUGP("entered %s\n", __FUNCTION__);
+
+       memset(range, 0, sizeof(*range));
+       
+       if (nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]) < 0)
+               goto nfattr_failure;
+
+       if (tb[CTA_NAT_MINIP-1])
+               range->min_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MINIP-1]);
+
+       if (!tb[CTA_NAT_MAXIP-1])
+               range->max_ip = range->min_ip;
+       else
+               range->max_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MAXIP-1]);
+
+       if (range->min_ip)
+               range->flags |= IP_NAT_RANGE_MAP_IPS;
+
+       if (!tb[CTA_NAT_PROTO-1])
+               return 0;
+
+       err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range);
+       if (err < 0)
+               return err;
+
+       DEBUGP("leaving\n");
+       return 0;
+
+nfattr_failure:
+       return -1;
+}
+#endif
+
+static inline int
+ctnetlink_parse_help(struct nfattr *attr, char **helper_name)
+{
+       struct nfattr *tb[CTA_HELP_MAX];
+
+       DEBUGP("entered %s\n", __FUNCTION__);
+
+       if (nfattr_parse_nested(tb, CTA_HELP_MAX, attr) < 0)
+               goto nfattr_failure;
+
+       if (!tb[CTA_HELP_NAME-1])
+               return -EINVAL;
+
+       *helper_name = NFA_DATA(tb[CTA_HELP_NAME-1]);
+
+       return 0;
+
+nfattr_failure:
+       return -1;
+}
+
+static int
+ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, 
+                       struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
+{
+       struct ip_conntrack_tuple_hash *h;
+       struct ip_conntrack_tuple tuple;
+       struct ip_conntrack *ct;
+       int err = 0;
+
+       DEBUGP("entered %s\n", __FUNCTION__);
+
+       if (cda[CTA_TUPLE_ORIG-1])
+               err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG);
+       else if (cda[CTA_TUPLE_REPLY-1])
+               err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY);
+       else {
+               /* Flush the whole table */
+               ip_conntrack_flush();
+               return 0;
+       }
+
+       if (err < 0)
+               return err;
+
+       h = ip_conntrack_find_get(&tuple, NULL);
+       if (!h) {
+               DEBUGP("tuple not found in conntrack hash\n");
+               return -ENOENT;
+       }
+
+       ct = tuplehash_to_ctrack(h);
+       
+       if (cda[CTA_ID-1]) {
+               u_int32_t id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_ID-1]));
+               if (ct->id != id) {
+                       ip_conntrack_put(ct);
+                       return -ENOENT;
+               }
+       }       
+       if (del_timer(&ct->timeout)) {
+               ip_conntrack_put(ct);
+               ct->timeout.function((unsigned long)ct);
+               return 0;
+       }
+       ip_conntrack_put(ct);
+       DEBUGP("leaving\n");
+
+       return 0;
+}
+
+static int
+ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, 
+                       struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
+{
+       struct ip_conntrack_tuple_hash *h;
+       struct ip_conntrack_tuple tuple;
+       struct ip_conntrack *ct;
+       struct sk_buff *skb2 = NULL;
+       int err = 0;
+
+       DEBUGP("entered %s\n", __FUNCTION__);
+
+       if (nlh->nlmsg_flags & NLM_F_DUMP) {
+               struct nfgenmsg *msg = NLMSG_DATA(nlh);
+               u32 rlen;
+
+               if (msg->nfgen_family != AF_INET)
+                       return -EAFNOSUPPORT;
+
+               if (NFNL_MSG_TYPE(nlh->nlmsg_type) ==
+                                       IPCTNL_MSG_CT_GET_CTRZERO) {
+#ifdef CONFIG_IP_NF_CT_ACCT
+                       if ((*errp = netlink_dump_start(ctnl, skb, nlh,
+                                               ctnetlink_dump_table_w,
+                                               ctnetlink_done)) != 0)
+                               return -EINVAL;
+#else
+                       return -ENOTSUPP;
+#endif
+               } else {
+                       if ((*errp = netlink_dump_start(ctnl, skb, nlh,
+                                                       ctnetlink_dump_table,
+                                                       ctnetlink_done)) != 0)
+                       return -EINVAL;
+               }
+
+               rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+               if (rlen > skb->len)
+                       rlen = skb->len;
+               skb_pull(skb, rlen);
+               return 0;
+       }
+
+       if (cda[CTA_TUPLE_ORIG-1])
+               err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG);
+       else if (cda[CTA_TUPLE_REPLY-1])
+               err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY);
+       else
+               return -EINVAL;
+
+       if (err < 0)
+               return err;
+
+       h = ip_conntrack_find_get(&tuple, NULL);
+       if (!h) {
+               DEBUGP("tuple not found in conntrack hash");
+               return -ENOENT;
+       }
+       DEBUGP("tuple found\n");
+       ct = tuplehash_to_ctrack(h);
+
+       err = -ENOMEM;
+       skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
+       if (!skb2) {
+               ip_conntrack_put(ct);
+               return -ENOMEM;
+       }
+       NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid;
+
+       err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 
+                                 IPCTNL_MSG_CT_NEW, 1, ct);
+       ip_conntrack_put(ct);
+       if (err <= 0)
+               goto out;
+
+       err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
+       if (err < 0)
+               goto out;
+
+       DEBUGP("leaving\n");
+       return 0;
+
+out:
+       if (skb2)
+               kfree_skb(skb2);
+       return -1;
+}
+
+static inline int
+ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[])
+{
+       unsigned long d, status = *(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1]);
+       d = ct->status ^ status;
+
+       if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
+               /* unchangeable */
+               return -EINVAL;
+       
+       if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY))
+               /* SEEN_REPLY bit can only be set */
+               return -EINVAL;
+
+       
+       if (d & IPS_ASSURED && !(status & IPS_ASSURED))
+               /* ASSURED bit can only be set */
+               return -EINVAL;
+
+       if (cda[CTA_NAT-1]) {
+#ifndef CONFIG_IP_NF_NAT_NEEDED
+               return -EINVAL;
+#else
+               unsigned int hooknum;
+               struct ip_nat_range range;
+
+               if (ctnetlink_parse_nat(cda, ct, &range) < 0)
+                       return -EINVAL;
+
+               DEBUGP("NAT: %u.%u.%u.%u-%u.%u.%u.%u:%u-%u\n", 
+                      NIPQUAD(range.min_ip), NIPQUAD(range.max_ip),
+                      htons(range.min.all), htons(range.max.all));
+               
+               /* This is tricky but it works. ip_nat_setup_info needs the
+                * hook number as parameter, so let's do the correct 
+                * conversion and run away */
+               if (status & IPS_SRC_NAT_DONE)
+                       hooknum = NF_IP_POST_ROUTING; /* IP_NAT_MANIP_SRC */
+               else if (status & IPS_DST_NAT_DONE)
+                       hooknum = NF_IP_PRE_ROUTING;  /* IP_NAT_MANIP_DST */
+               else 
+                       return -EINVAL; /* Missing NAT flags */
+
+               DEBUGP("NAT status: %lu\n", 
+                      status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
+               
+               if (ip_nat_initialized(ct, hooknum))
+                       return -EEXIST;
+               ip_nat_setup_info(ct, &range, hooknum);
+
+                DEBUGP("NAT status after setup_info: %lu\n",
+                       ct->status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
+#endif
+       }
+
+       /* Be careful here, modifying NAT bits can screw up things,
+        * so don't let users modify them directly if they don't pass
+        * ip_nat_range. */
+       ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK);
+       return 0;
+}
+
+
+static inline int
+ctnetlink_change_helper(struct ip_conntrack *ct, struct nfattr *cda[])
+{
+       struct ip_conntrack_helper *helper;
+       char *helpname;
+       int err;
+
+       DEBUGP("entered %s\n", __FUNCTION__);
+
+       /* don't change helper of sibling connections */
+       if (ct->master)
+               return -EINVAL;
+
+       err = ctnetlink_parse_help(cda[CTA_HELP-1], &helpname);
+       if (err < 0)
+               return err;
+
+       helper = __ip_conntrack_helper_find_byname(helpname);
+       if (!helper) {
+               if (!strcmp(helpname, ""))
+                       helper = NULL;
+               else
+                       return -EINVAL;
+       }
+
+       if (ct->helper) {
+               if (!helper) {
+                       /* we had a helper before ... */
+                       ip_ct_remove_expectations(ct);
+                       ct->helper = NULL;
+               } else {
+                       /* need to zero data of old helper */
+                       memset(&ct->help, 0, sizeof(ct->help));
+               }
+       }
+       
+       ct->helper = helper;
+
+       return 0;
+}
+
+static inline int
+ctnetlink_change_timeout(struct ip_conntrack *ct, struct nfattr *cda[])
+{
+       u_int32_t timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
+       
+       if (!del_timer(&ct->timeout))
+               return -ETIME;
+
+       ct->timeout.expires = jiffies + timeout * HZ;
+       add_timer(&ct->timeout);
+
+       return 0;
+}
+
+static int
+ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[])
+{
+       int err;
+
+       DEBUGP("entered %s\n", __FUNCTION__);
+
+       if (cda[CTA_HELP-1]) {
+               err = ctnetlink_change_helper(ct, cda);
+               if (err < 0)
+                       return err;
+       }
+
+       if (cda[CTA_TIMEOUT-1]) {
+               err = ctnetlink_change_timeout(ct, cda);
+               if (err < 0)
+                       return err;
+       }
+
+       if (cda[CTA_STATUS-1]) {
+               err = ctnetlink_change_status(ct, cda);
+               if (err < 0)
+                       return err;
+       }
+
+       DEBUGP("all done\n");
+       return 0;
+}
+
+static int
+ctnetlink_create_conntrack(struct nfattr *cda[], 
+                          struct ip_conntrack_tuple *otuple,
+                          struct ip_conntrack_tuple *rtuple)
+{
+       struct ip_conntrack *ct;
+       int err = -EINVAL;
+
+       DEBUGP("entered %s\n", __FUNCTION__);
+
+       ct = ip_conntrack_alloc(otuple, rtuple);
+       if (ct == NULL || IS_ERR(ct))
+               return -ENOMEM; 
+
+       if (!cda[CTA_TIMEOUT-1])
+               goto err;
+       ct->timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
+
+       ct->timeout.expires = jiffies + ct->timeout.expires * HZ;
+       ct->status |= IPS_CONFIRMED;
+
+       err = ctnetlink_change_status(ct, cda);
+       if (err < 0)
+               goto err;
+
+       ct->helper = ip_conntrack_helper_find_get(rtuple);
+
+       add_timer(&ct->timeout);
+       ip_conntrack_hash_insert(ct);
+
+       if (ct->helper)
+               ip_conntrack_helper_put(ct->helper);
+
+       DEBUGP("conntrack with id %u inserted\n", ct->id);
+       return 0;
+
+err:   
+       ip_conntrack_free(ct);
+       return err;
+}
+
+static int 
+ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, 
+                       struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
+{
+       struct ip_conntrack_tuple otuple, rtuple;
+       struct ip_conntrack_tuple_hash *h = NULL;
+       int err = 0;
+
+       DEBUGP("entered %s\n", __FUNCTION__);
+
+       if (cda[CTA_TUPLE_ORIG-1]) {
+               err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG);
+               if (err < 0)
+                       return err;
+       }
+
+       if (cda[CTA_TUPLE_REPLY-1]) {
+               err = ctnetlink_parse_tuple(cda, &rtuple, CTA_TUPLE_REPLY);
+               if (err < 0)
+                       return err;
+       }
+
+       write_lock_bh(&ip_conntrack_lock);
+       if (cda[CTA_TUPLE_ORIG-1])
+               h = __ip_conntrack_find(&otuple, NULL);
+       else if (cda[CTA_TUPLE_REPLY-1])
+               h = __ip_conntrack_find(&rtuple, NULL);
+
+       if (h == NULL) {
+               write_unlock_bh(&ip_conntrack_lock);
+               DEBUGP("no such conntrack, create new\n");
+               err = -ENOENT;
+               if (nlh->nlmsg_flags & NLM_F_CREATE)
+                       err = ctnetlink_create_conntrack(cda, &otuple, &rtuple);
+               return err;
+       }
+       /* implicit 'else' */
+
+       /* we only allow nat config for new conntracks */
+       if (cda[CTA_NAT-1]) {
+               err = -EINVAL;
+               goto out_unlock;
+       }
+
+       /* We manipulate the conntrack inside the global conntrack table lock,
+        * so there's no need to increase the refcount */
+       DEBUGP("conntrack found\n");
+       err = -EEXIST;
+       if (!(nlh->nlmsg_flags & NLM_F_EXCL))
+               err = ctnetlink_change_conntrack(tuplehash_to_ctrack(h), cda);
+
+out_unlock:
+       write_unlock_bh(&ip_conntrack_lock);
+       return err;
+}
+
+/*********************************************************************** 
+ * EXPECT 
+ ***********************************************************************/ 
+
+static inline int
+ctnetlink_exp_dump_tuple(struct sk_buff *skb,
+                        const struct ip_conntrack_tuple *tuple,
+                        enum ctattr_expect type)
+{
+       struct nfattr *nest_parms = NFA_NEST(skb, type);
+       
+       if (ctnetlink_dump_tuples(skb, tuple) < 0)
+               goto nfattr_failure;
+
+       NFA_NEST_END(skb, nest_parms);
+
+       return 0;
+
+nfattr_failure:
+       return -1;
+}                      
+
+static inline int
+ctnetlink_exp_dump_expect(struct sk_buff *skb,
+                          const struct ip_conntrack_expect *exp)
+{
+       struct ip_conntrack *master = exp->master;
+       u_int32_t timeout = htonl((exp->timeout.expires - jiffies) / HZ);
+       u_int32_t id = htonl(exp->id);
+
+       if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0)
+               goto nfattr_failure;
+       if (ctnetlink_exp_dump_tuple(skb, &exp->mask, CTA_EXPECT_MASK) < 0)
+               goto nfattr_failure;
+       if (ctnetlink_exp_dump_tuple(skb,
+                                &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
+                                CTA_EXPECT_MASTER) < 0)
+               goto nfattr_failure;
+       
+       NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout);
+       NFA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id);
+
+       return 0;
+       
+nfattr_failure:
+       return -1;
+}
+
+static int
+ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
+                   int event, 
+                   int nowait, 
+                   const struct ip_conntrack_expect *exp)
+{
+       struct nlmsghdr *nlh;
+       struct nfgenmsg *nfmsg;
+       unsigned char *b;
+
+       b = skb->tail;
+
+       event |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
+       nlh    = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg));
+       nfmsg  = NLMSG_DATA(nlh);
+
+       nlh->nlmsg_flags    = (nowait && pid) ? NLM_F_MULTI : 0;
+       nfmsg->nfgen_family = AF_INET;
+       nfmsg->version      = NFNETLINK_V0;
+       nfmsg->res_id       = 0;
+
+       if (ctnetlink_exp_dump_expect(skb, exp) < 0)
+               goto nfattr_failure;
+
+       nlh->nlmsg_len = skb->tail - b;
+       return skb->len;
+
+nlmsg_failure:
+nfattr_failure:
+       skb_trim(skb, b - skb->data);
+       return -1;
+}
+
+#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
+static int ctnetlink_expect_event(struct notifier_block *this,
+                                 unsigned long events, void *ptr)
+{
+       struct nlmsghdr *nlh;
+       struct nfgenmsg *nfmsg;
+       struct ip_conntrack_expect *exp = (struct ip_conntrack_expect *)ptr;
+       struct sk_buff *skb;
+       unsigned int type;
+       unsigned char *b;
+       int flags = 0;
+       u16 proto;
+
+       if (events & IPEXP_NEW) {
+               type = IPCTNL_MSG_EXP_NEW;
+               flags = NLM_F_CREATE|NLM_F_EXCL;
+       } else
+               return NOTIFY_DONE;
+
+       skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
+       if (!skb)
+               return NOTIFY_DONE;
+
+       b = skb->tail;
+
+       type |= NFNL_SUBSYS_CTNETLINK << 8;
+       nlh   = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));
+       nfmsg = NLMSG_DATA(nlh);
+
+       nlh->nlmsg_flags    = flags;
+       nfmsg->nfgen_family = AF_INET;
+       nfmsg->version      = NFNETLINK_V0;
+       nfmsg->res_id       = 0;
+
+       if (ctnetlink_exp_dump_expect(skb, exp) < 0)
+               goto nfattr_failure;
+
+       nlh->nlmsg_len = skb->tail - b;
+       proto = exp->tuple.dst.protonum;
+       nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0);
+       return NOTIFY_DONE;
+
+nlmsg_failure:
+nfattr_failure:
+       kfree_skb(skb);
+       return NOTIFY_DONE;
+}
+#endif
+
+static int
+ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       struct ip_conntrack_expect *exp = NULL;
+       struct list_head *i;
+       u_int32_t *id = (u_int32_t *) &cb->args[0];
+
+       DEBUGP("entered %s, last id=%llu\n", __FUNCTION__, *id);
+
+       read_lock_bh(&ip_conntrack_lock);
+       list_for_each_prev(i, &ip_conntrack_expect_list) {
+               exp = (struct ip_conntrack_expect *) i;
+               if (exp->id <= *id)
+                       continue;
+               if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid,
+                                           cb->nlh->nlmsg_seq,
+                                           IPCTNL_MSG_EXP_NEW,
+                                           1, exp) < 0)
+                       goto out;
+               *id = exp->id;
+       }
+out:   
+       read_unlock_bh(&ip_conntrack_lock);
+
+       DEBUGP("leaving, last id=%llu\n", *id);
+
+       return skb->len;
+}
+
+static int
+ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, 
+                    struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
+{
+       struct ip_conntrack_tuple tuple;
+       struct ip_conntrack_expect *exp;
+       struct sk_buff *skb2;
+       int err = 0;
+
+       DEBUGP("entered %s\n", __FUNCTION__);
+
+       if (nlh->nlmsg_flags & NLM_F_DUMP) {
+               struct nfgenmsg *msg = NLMSG_DATA(nlh);
+               u32 rlen;
+
+               if (msg->nfgen_family != AF_INET)
+                       return -EAFNOSUPPORT;
+
+               if ((*errp = netlink_dump_start(ctnl, skb, nlh,
+                                               ctnetlink_exp_dump_table,
+                                               ctnetlink_done)) != 0)
+                       return -EINVAL;
+               rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+               if (rlen > skb->len)
+                       rlen = skb->len;
+               skb_pull(skb, rlen);
+               return 0;
+       }
+
+       if (cda[CTA_EXPECT_MASTER-1])
+               err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER);
+       else
+               return -EINVAL;
+
+       if (err < 0)
+               return err;
+
+       exp = ip_conntrack_expect_find_get(&tuple);
+       if (!exp)
+               return -ENOENT;
+
+       err = -ENOMEM;
+       skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!skb2)
+               goto out;
+       NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid;
+       
+       err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, 
+                                     nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW,
+                                     1, exp);
+       if (err <= 0)
+               goto out;
+
+       ip_conntrack_expect_put(exp);
+
+       err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
+       if (err < 0)
+               goto free;
+
+       return err;
+
+out:
+       ip_conntrack_expect_put(exp);
+free:
+       if (skb2)
+               kfree_skb(skb2);
+       return err;
+}
+
+static int
+ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, 
+                    struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
+{
+       struct ip_conntrack_expect *exp, *tmp;
+       struct ip_conntrack_tuple tuple;
+       struct ip_conntrack_helper *h;
+       int err;
+
+       if (cda[CTA_EXPECT_TUPLE-1]) {
+               /* delete a single expect by tuple */
+               err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
+               if (err < 0)
+                       return err;
+
+               /* bump usage count to 2 */
+               exp = ip_conntrack_expect_find_get(&tuple);
+               if (!exp)
+                       return -ENOENT;
+
+               if (cda[CTA_EXPECT_ID-1]) {
+                       u_int32_t id = 
+                               *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
+                       if (exp->id != ntohl(id)) {
+                               ip_conntrack_expect_put(exp);
+                               return -ENOENT;
+                       }
+               }
+
+               /* after list removal, usage count == 1 */
+               ip_conntrack_unexpect_related(exp);
+               /* have to put what we 'get' above. 
+                * after this line usage count == 0 */
+               ip_conntrack_expect_put(exp);
+       } else if (cda[CTA_EXPECT_HELP_NAME-1]) {
+               char *name = NFA_DATA(cda[CTA_EXPECT_HELP_NAME-1]);
+
+               /* delete all expectations for this helper */
+               write_lock_bh(&ip_conntrack_lock);
+               h = __ip_conntrack_helper_find_byname(name);
+               if (!h) {
+                       write_unlock_bh(&ip_conntrack_lock);
+                       return -EINVAL;
+               }
+               list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list,
+                                        list) {
+                       if (exp->master->helper == h 
+                           && del_timer(&exp->timeout)) {
+                               ip_ct_unlink_expect(exp);
+                               ip_conntrack_expect_put(exp);
+                       }
+               }
+               write_unlock(&ip_conntrack_lock);
+       } else {
+               /* This basically means we have to flush everything*/
+               write_lock_bh(&ip_conntrack_lock);
+               list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list,
+                                        list) {
+                       if (del_timer(&exp->timeout)) {
+                               ip_ct_unlink_expect(exp);
+                               ip_conntrack_expect_put(exp);
+                       }
+               }
+               write_unlock_bh(&ip_conntrack_lock);
+       }
+
+       return 0;
+}
+static int
+ctnetlink_change_expect(struct ip_conntrack_expect *x, struct nfattr *cda[])
+{
+       return -EOPNOTSUPP;
+}
+
+static int
+ctnetlink_create_expect(struct nfattr *cda[])
+{
+       struct ip_conntrack_tuple tuple, mask, master_tuple;
+       struct ip_conntrack_tuple_hash *h = NULL;
+       struct ip_conntrack_expect *exp;
+       struct ip_conntrack *ct;
+       int err = 0;
+
+       DEBUGP("entered %s\n", __FUNCTION__);
+
+       /* caller guarantees that those three CTA_EXPECT_* exist */
+       err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
+       if (err < 0)
+               return err;
+       err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK);
+       if (err < 0)
+               return err;
+       err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER);
+       if (err < 0)
+               return err;
+
+       /* Look for master conntrack of this expectation */
+       h = ip_conntrack_find_get(&master_tuple, NULL);
+       if (!h)
+               return -ENOENT;
+       ct = tuplehash_to_ctrack(h);
+
+       if (!ct->helper) {
+               /* such conntrack hasn't got any helper, abort */
+               err = -EINVAL;
+               goto out;
+       }
+
+       exp = ip_conntrack_expect_alloc(ct);
+       if (!exp) {
+               err = -ENOMEM;
+               goto out;
+       }
+       
+       exp->expectfn = NULL;
+       exp->flags = 0;
+       exp->master = ct;
+       memcpy(&exp->tuple, &tuple, sizeof(struct ip_conntrack_tuple));
+       memcpy(&exp->mask, &mask, sizeof(struct ip_conntrack_tuple));
+
+       err = ip_conntrack_expect_related(exp);
+       ip_conntrack_expect_put(exp);
+
+out:   
+       ip_conntrack_put(tuplehash_to_ctrack(h));
+       return err;
+}
+
+static int
+ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
+                    struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
+{
+       struct ip_conntrack_tuple tuple;
+       struct ip_conntrack_expect *exp;
+       int err = 0;
+
+       DEBUGP("entered %s\n", __FUNCTION__);   
+
+       if (!cda[CTA_EXPECT_TUPLE-1]
+           || !cda[CTA_EXPECT_MASK-1]
+           || !cda[CTA_EXPECT_MASTER-1])
+               return -EINVAL;
+
+       err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
+       if (err < 0)
+               return err;
+
+       write_lock_bh(&ip_conntrack_lock);
+       exp = __ip_conntrack_expect_find(&tuple);
+
+       if (!exp) {
+               write_unlock_bh(&ip_conntrack_lock);
+               err = -ENOENT;
+               if (nlh->nlmsg_flags & NLM_F_CREATE)
+                       err = ctnetlink_create_expect(cda);
+               return err;
+       }
+
+       err = -EEXIST;
+       if (!(nlh->nlmsg_flags & NLM_F_EXCL))
+               err = ctnetlink_change_expect(exp, cda);
+       write_unlock_bh(&ip_conntrack_lock);
+
+       DEBUGP("leaving\n");
+       
+       return err;
+}
+
+#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
+static struct notifier_block ctnl_notifier = {
+       .notifier_call  = ctnetlink_conntrack_event,
+};
+
+static struct notifier_block ctnl_notifier_exp = {
+       .notifier_call  = ctnetlink_expect_event,
+};
+#endif
+
+static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
+       [IPCTNL_MSG_CT_NEW]             = { .call = ctnetlink_new_conntrack,
+                                           .attr_count = CTA_MAX,
+                                           .cap_required = CAP_NET_ADMIN },
+       [IPCTNL_MSG_CT_GET]             = { .call = ctnetlink_get_conntrack,
+                                           .attr_count = CTA_MAX,
+                                           .cap_required = CAP_NET_ADMIN },
+       [IPCTNL_MSG_CT_DELETE]          = { .call = ctnetlink_del_conntrack,
+                                           .attr_count = CTA_MAX,
+                                           .cap_required = CAP_NET_ADMIN },
+       [IPCTNL_MSG_CT_GET_CTRZERO]     = { .call = ctnetlink_get_conntrack,
+                                           .attr_count = CTA_MAX,
+                                           .cap_required = CAP_NET_ADMIN },
+};
+
+static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {
+       [IPCTNL_MSG_EXP_GET]            = { .call = ctnetlink_get_expect,
+                                           .attr_count = CTA_EXPECT_MAX,
+                                           .cap_required = CAP_NET_ADMIN },
+       [IPCTNL_MSG_EXP_NEW]            = { .call = ctnetlink_new_expect,
+                                           .attr_count = CTA_EXPECT_MAX,
+                                           .cap_required = CAP_NET_ADMIN },
+       [IPCTNL_MSG_EXP_DELETE]         = { .call = ctnetlink_del_expect,
+                                           .attr_count = CTA_EXPECT_MAX,
+                                           .cap_required = CAP_NET_ADMIN },
+};
+
+static struct nfnetlink_subsystem ctnl_subsys = {
+       .name                           = "conntrack",
+       .subsys_id                      = NFNL_SUBSYS_CTNETLINK,
+       .cb_count                       = IPCTNL_MSG_MAX,
+       .cb                             = ctnl_cb,
+};
+
+static struct nfnetlink_subsystem ctnl_exp_subsys = {
+       .name                           = "conntrack_expect",
+       .subsys_id                      = NFNL_SUBSYS_CTNETLINK_EXP,
+       .cb_count                       = IPCTNL_MSG_EXP_MAX,
+       .cb                             = ctnl_exp_cb,
+};
+
+static int __init ctnetlink_init(void)
+{
+       int ret;
+
+       printk("ctnetlink v%s: registering with nfnetlink.\n", version);
+       ret = nfnetlink_subsys_register(&ctnl_subsys);
+       if (ret < 0) {
+               printk("ctnetlink_init: cannot register with nfnetlink.\n");
+               goto err_out;
+       }
+
+       ret = nfnetlink_subsys_register(&ctnl_exp_subsys);
+       if (ret < 0) {
+               printk("ctnetlink_init: cannot register exp with nfnetlink.\n");
+               goto err_unreg_subsys;
+       }
+
+#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
+       ret = ip_conntrack_register_notifier(&ctnl_notifier);
+       if (ret < 0) {
+               printk("ctnetlink_init: cannot register notifier.\n");
+               goto err_unreg_exp_subsys;
+       }
+
+       ret = ip_conntrack_expect_register_notifier(&ctnl_notifier_exp);
+       if (ret < 0) {
+               printk("ctnetlink_init: cannot expect register notifier.\n");
+               goto err_unreg_notifier;
+       }
+#endif
+
+       return 0;
+
+#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
+err_unreg_notifier:
+       ip_conntrack_unregister_notifier(&ctnl_notifier);
+err_unreg_exp_subsys:
+       nfnetlink_subsys_unregister(&ctnl_exp_subsys);
+#endif
+err_unreg_subsys:
+       nfnetlink_subsys_unregister(&ctnl_subsys);
+err_out:
+       return ret;
+}
+
+static void __exit ctnetlink_exit(void)
+{
+       printk("ctnetlink: unregistering from nfnetlink.\n");
+
+#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
+       ip_conntrack_unregister_notifier(&ctnl_notifier_exp);
+       ip_conntrack_unregister_notifier(&ctnl_notifier);
+#endif
+
+       nfnetlink_subsys_unregister(&ctnl_exp_subsys);
+       nfnetlink_subsys_unregister(&ctnl_subsys);
+       return;
+}
+
+module_init(ctnetlink_init);
+module_exit(ctnetlink_exit);
index 602c74db3252de8a35b37d438a222ffdfb197df5..838d1d69b36e0acd868038124c39a81d3a92722b 100644 (file)
@@ -102,22 +102,24 @@ static int icmp_packet(struct ip_conntrack *ct,
                        ct->timeout.function((unsigned long)ct);
        } else {
                atomic_inc(&ct->proto.icmp.count);
+               ip_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
                ip_ct_refresh_acct(ct, ctinfo, skb, ip_ct_icmp_timeout);
        }
 
        return NF_ACCEPT;
 }
 
+static u_int8_t valid_new[] = { 
+       [ICMP_ECHO] = 1,
+       [ICMP_TIMESTAMP] = 1,
+       [ICMP_INFO_REQUEST] = 1,
+       [ICMP_ADDRESS] = 1 
+};
+
 /* Called when a new connection for this protocol found. */
 static int icmp_new(struct ip_conntrack *conntrack,
                    const struct sk_buff *skb)
 {
-       static u_int8_t valid_new[]
-               = { [ICMP_ECHO] = 1,
-                   [ICMP_TIMESTAMP] = 1,
-                   [ICMP_INFO_REQUEST] = 1,
-                   [ICMP_ADDRESS] = 1 };
-
        if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new)
            || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) {
                /* Can't create a new ICMP `conn' with this. */
@@ -158,11 +160,12 @@ icmp_error_message(struct sk_buff *skb,
                return NF_ACCEPT;
        }
 
-       innerproto = ip_ct_find_proto(inside->ip.protocol);
+       innerproto = ip_conntrack_proto_find_get(inside->ip.protocol);
        dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp) + inside->ip.ihl*4;
        /* Are they talking about one of our connections? */
        if (!ip_ct_get_tuple(&inside->ip, skb, dataoff, &origtuple, innerproto)) {
                DEBUGP("icmp_error: ! get_tuple p=%u", inside->ip.protocol);
+               ip_conntrack_proto_put(innerproto);
                return NF_ACCEPT;
        }
 
@@ -170,8 +173,10 @@ icmp_error_message(struct sk_buff *skb,
           been preserved inside the ICMP. */
        if (!ip_ct_invert_tuple(&innertuple, &origtuple, innerproto)) {
                DEBUGP("icmp_error_track: Can't invert tuple\n");
+               ip_conntrack_proto_put(innerproto);
                return NF_ACCEPT;
        }
+       ip_conntrack_proto_put(innerproto);
 
        *ctinfo = IP_CT_RELATED;
 
@@ -212,7 +217,7 @@ icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
        icmph = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_ih), &_ih);
        if (icmph == NULL) {
                if (LOG_INVALID(IPPROTO_ICMP))
-                       nf_log_packet(PF_INET, 0, skb, NULL, NULL,
+                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
                                      "ip_ct_icmp: short packet ");
                return -NF_ACCEPT;
        }
@@ -226,13 +231,13 @@ icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
                if (!(u16)csum_fold(skb->csum)) 
                        break;
                if (LOG_INVALID(IPPROTO_ICMP))
-                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
+                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
                                      "ip_ct_icmp: bad HW ICMP checksum ");
                return -NF_ACCEPT;
        case CHECKSUM_NONE:
                if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) {
                        if (LOG_INVALID(IPPROTO_ICMP))
-                               nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
+                               nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
                                              "ip_ct_icmp: bad ICMP checksum ");
                        return -NF_ACCEPT;
                }
@@ -249,7 +254,7 @@ checksum_skipped:
         */
        if (icmph->type > NR_ICMP_TYPES) {
                if (LOG_INVALID(IPPROTO_ICMP))
-                       nf_log_packet(PF_INET, 0, skb, NULL, NULL,
+                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
                                      "ip_ct_icmp: invalid ICMP type ");
                return -NF_ACCEPT;
        }
@@ -265,6 +270,47 @@ checksum_skipped:
        return icmp_error_message(skb, ctinfo, hooknum);
 }
 
+#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
+    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
+static int icmp_tuple_to_nfattr(struct sk_buff *skb,
+                               const struct ip_conntrack_tuple *t)
+{
+       NFA_PUT(skb, CTA_PROTO_ICMP_ID, sizeof(u_int16_t),
+               &t->src.u.icmp.id);
+       NFA_PUT(skb, CTA_PROTO_ICMP_TYPE, sizeof(u_int8_t),
+               &t->dst.u.icmp.type);
+       NFA_PUT(skb, CTA_PROTO_ICMP_CODE, sizeof(u_int8_t),
+               &t->dst.u.icmp.code);
+
+       if (t->dst.u.icmp.type >= sizeof(valid_new) 
+           || !valid_new[t->dst.u.icmp.type])
+               return -EINVAL;
+
+       return 0;
+
+nfattr_failure:
+       return -1;
+}
+
+static int icmp_nfattr_to_tuple(struct nfattr *tb[],
+                               struct ip_conntrack_tuple *tuple)
+{
+       if (!tb[CTA_PROTO_ICMP_TYPE-1]
+           || !tb[CTA_PROTO_ICMP_CODE-1]
+           || !tb[CTA_PROTO_ICMP_ID-1])
+               return -1;
+
+       tuple->dst.u.icmp.type = 
+                       *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_TYPE-1]);
+       tuple->dst.u.icmp.code =
+                       *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]);
+       tuple->src.u.icmp.id =
+                       *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]);
+
+       return 0;
+}
+#endif
+
 struct ip_conntrack_protocol ip_conntrack_protocol_icmp =
 {
        .proto                  = IPPROTO_ICMP,
@@ -276,4 +322,9 @@ struct ip_conntrack_protocol ip_conntrack_protocol_icmp =
        .packet                 = icmp_packet,
        .new                    = icmp_new,
        .error                  = icmp_error,
+#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
+    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
+       .tuple_to_nfattr        = icmp_tuple_to_nfattr,
+       .nfattr_to_tuple        = icmp_nfattr_to_tuple,
+#endif
 };
index 31d75390bf12b5e648b1b4cd73f701e75764a48d..a875f35e576ddfd117a2ac4224f1a5e9feff3016 100644 (file)
@@ -404,6 +404,8 @@ static int sctp_packet(struct ip_conntrack *conntrack,
                }
 
                conntrack->proto.sctp.state = newconntrack;
+               if (oldsctpstate != newconntrack)
+                       ip_conntrack_event_cache(IPCT_PROTOINFO, skb);
                write_unlock_bh(&sctp_lock);
        }
 
@@ -503,7 +505,12 @@ static struct ip_conntrack_protocol ip_conntrack_protocol_sctp = {
        .packet          = sctp_packet, 
        .new             = sctp_new, 
        .destroy         = NULL, 
-       .me              = THIS_MODULE 
+       .me              = THIS_MODULE,
+#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
+    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
+       .tuple_to_nfattr = ip_ct_port_tuple_to_nfattr,
+       .nfattr_to_tuple = ip_ct_port_nfattr_to_tuple,
+#endif
 };
 
 #ifdef CONFIG_SYSCTL
index 809dfed766d4274962fcd949c17814a1011ccace..1985abc59d2497f13c453750277d71da0bf73946 100644 (file)
@@ -336,6 +336,24 @@ static int tcp_print_conntrack(struct seq_file *s,
        return seq_printf(s, "%s ", tcp_conntrack_names[state]);
 }
 
+#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
+    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
+static int tcp_to_nfattr(struct sk_buff *skb, struct nfattr *nfa,
+                        const struct ip_conntrack *ct)
+{
+       read_lock_bh(&tcp_lock);
+       NFA_PUT(skb, CTA_PROTOINFO_TCP_STATE, sizeof(u_int8_t),
+               &ct->proto.tcp.state);
+       read_unlock_bh(&tcp_lock);
+
+       return 0;
+
+nfattr_failure:
+       read_unlock_bh(&tcp_lock);
+       return -1;
+}
+#endif
+
 static unsigned int get_conntrack_index(const struct tcphdr *tcph)
 {
        if (tcph->rst) return TCP_RST_SET;
@@ -699,7 +717,7 @@ static int tcp_in_window(struct ip_ct_tcp *state,
                res = 1;
        } else {
                if (LOG_INVALID(IPPROTO_TCP))
-                       nf_log_packet(PF_INET, 0, skb, NULL, NULL,
+                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
                        "ip_ct_tcp: %s ",
                        before(seq, sender->td_maxend + 1) ?
                        after(end, sender->td_end - receiver->td_maxwin - 1) ?
@@ -798,7 +816,7 @@ static int tcp_error(struct sk_buff *skb,
                                sizeof(_tcph), &_tcph);
        if (th == NULL) {
                if (LOG_INVALID(IPPROTO_TCP))
-                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
+                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
                                "ip_ct_tcp: short packet ");
                return -NF_ACCEPT;
        }
@@ -806,7 +824,7 @@ static int tcp_error(struct sk_buff *skb,
        /* Not whole TCP header or malformed packet */
        if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) {
                if (LOG_INVALID(IPPROTO_TCP))
-                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
+                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
                                "ip_ct_tcp: truncated/malformed packet ");
                return -NF_ACCEPT;
        }
@@ -823,7 +841,7 @@ static int tcp_error(struct sk_buff *skb,
                                 skb->ip_summed == CHECKSUM_HW ? skb->csum
                                 : skb_checksum(skb, iph->ihl*4, tcplen, 0))) {
                if (LOG_INVALID(IPPROTO_TCP))
-                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
+                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
                                  "ip_ct_tcp: bad TCP checksum ");
                return -NF_ACCEPT;
        }
@@ -832,7 +850,7 @@ static int tcp_error(struct sk_buff *skb,
        tcpflags = (((u_int8_t *)th)[13] & ~(TH_ECE|TH_CWR));
        if (!tcp_valid_flags[tcpflags]) {
                if (LOG_INVALID(IPPROTO_TCP))
-                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
+                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
                                  "ip_ct_tcp: invalid TCP flag combination ");
                return -NF_ACCEPT;
        }
@@ -880,8 +898,9 @@ static int tcp_packet(struct ip_conntrack *conntrack,
                         */
                        write_unlock_bh(&tcp_lock);
                        if (LOG_INVALID(IPPROTO_TCP))
-                               nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
-                                         "ip_ct_tcp: killing out of sync session ");
+                               nf_log_packet(PF_INET, 0, skb, NULL, NULL,
+                                             NULL, "ip_ct_tcp: "
+                                             "killing out of sync session ");
                        if (del_timer(&conntrack->timeout))
                                conntrack->timeout.function((unsigned long)
                                                            conntrack);
@@ -895,7 +914,7 @@ static int tcp_packet(struct ip_conntrack *conntrack,
                
                write_unlock_bh(&tcp_lock);
                if (LOG_INVALID(IPPROTO_TCP))
-                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
+                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
                                  "ip_ct_tcp: invalid packet ignored ");
                return NF_ACCEPT;
        case TCP_CONNTRACK_MAX:
@@ -905,7 +924,7 @@ static int tcp_packet(struct ip_conntrack *conntrack,
                       old_state);
                write_unlock_bh(&tcp_lock);
                if (LOG_INVALID(IPPROTO_TCP))
-                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
+                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
                                  "ip_ct_tcp: invalid state ");
                return -NF_ACCEPT;
        case TCP_CONNTRACK_SYN_SENT:
@@ -926,7 +945,7 @@ static int tcp_packet(struct ip_conntrack *conntrack,
                        write_unlock_bh(&tcp_lock);
                        if (LOG_INVALID(IPPROTO_TCP))
                                nf_log_packet(PF_INET, 0, skb, NULL, NULL,
-                                             "ip_ct_tcp: invalid SYN");
+                                             NULL, "ip_ct_tcp: invalid SYN");
                        return -NF_ACCEPT;
                }
        case TCP_CONNTRACK_CLOSE:
@@ -973,6 +992,10 @@ static int tcp_packet(struct ip_conntrack *conntrack,
                  ? ip_ct_tcp_timeout_max_retrans : *tcp_timeouts[new_state];
        write_unlock_bh(&tcp_lock);
 
+       ip_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
+       if (new_state != old_state)
+               ip_conntrack_event_cache(IPCT_PROTOINFO, skb);
+
        if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
                /* If only reply is a RST, we can consider ourselves not to
                   have an established connection: this is a fairly common
@@ -1096,4 +1119,10 @@ struct ip_conntrack_protocol ip_conntrack_protocol_tcp =
        .packet                 = tcp_packet,
        .new                    = tcp_new,
        .error                  = tcp_error,
+#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
+    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
+       .to_nfattr              = tcp_to_nfattr,
+       .tuple_to_nfattr        = ip_ct_port_tuple_to_nfattr,
+       .nfattr_to_tuple        = ip_ct_port_nfattr_to_tuple,
+#endif
 };
index 8c1eaba098d4cbf6829c8bf79eb3a0ef29a01b14..f2dcac7c76607830e28c092494238b9ea548e2ae 100644 (file)
@@ -73,7 +73,8 @@ static int udp_packet(struct ip_conntrack *conntrack,
                ip_ct_refresh_acct(conntrack, ctinfo, skb, 
                                   ip_ct_udp_timeout_stream);
                /* Also, more likely to be important, and not a probe */
-               set_bit(IPS_ASSURED_BIT, &conntrack->status);
+               if (!test_and_set_bit(IPS_ASSURED_BIT, &conntrack->status))
+                       ip_conntrack_event_cache(IPCT_STATUS, skb);
        } else
                ip_ct_refresh_acct(conntrack, ctinfo, skb, ip_ct_udp_timeout);
 
@@ -97,7 +98,7 @@ static int udp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
        hdr = skb_header_pointer(skb, iph->ihl*4, sizeof(_hdr), &_hdr);
        if (hdr == NULL) {
                if (LOG_INVALID(IPPROTO_UDP))
-                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
+                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
                                  "ip_ct_udp: short packet ");
                return -NF_ACCEPT;
        }
@@ -105,7 +106,7 @@ static int udp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
        /* Truncated/malformed packets */
        if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) {
                if (LOG_INVALID(IPPROTO_UDP))
-                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
+                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
                                  "ip_ct_udp: truncated/malformed packet ");
                return -NF_ACCEPT;
        }
@@ -125,7 +126,7 @@ static int udp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
                                 skb->ip_summed == CHECKSUM_HW ? skb->csum
                                 : skb_checksum(skb, iph->ihl*4, udplen, 0))) {
                if (LOG_INVALID(IPPROTO_UDP))
-                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
+                       nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
                                  "ip_ct_udp: bad UDP checksum ");
                return -NF_ACCEPT;
        }
@@ -144,4 +145,9 @@ struct ip_conntrack_protocol ip_conntrack_protocol_udp =
        .packet                 = udp_packet,
        .new                    = udp_new,
        .error                  = udp_error,
+#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
+    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
+       .tuple_to_nfattr        = ip_ct_port_tuple_to_nfattr,
+       .nfattr_to_tuple        = ip_ct_port_nfattr_to_tuple,
+#endif
 };
index 61798c46e91d06e051947db664c301a45b5b6b74..ae3e3e655db555054c14dd34372e792abb2e25e5 100644 (file)
@@ -5,7 +5,7 @@
 */
 
 /* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ * (C) 2002-2005 Netfilter Core Team <coreteam@netfilter.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
@@ -147,8 +147,7 @@ static int ct_seq_show(struct seq_file *s, void *v)
        if (DIRECTION(hash))
                return 0;
 
-       proto = ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
-                              .tuple.dst.protonum);
+       proto = __ip_conntrack_proto_find(conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
        IP_NF_ASSERT(proto);
 
        if (seq_printf(s, "%-8s %u %ld ",
@@ -185,7 +184,7 @@ static int ct_seq_show(struct seq_file *s, void *v)
                        return -ENOSPC;
 
 #if defined(CONFIG_IP_NF_CONNTRACK_MARK)
-       if (seq_printf(s, "mark=%lu ", conntrack->mark))
+       if (seq_printf(s, "mark=%u ", conntrack->mark))
                return -ENOSPC;
 #endif
 
@@ -283,7 +282,7 @@ static int exp_seq_show(struct seq_file *s, void *v)
        seq_printf(s, "proto=%u ", expect->tuple.dst.protonum);
 
        print_tuple(s, &expect->tuple,
-                   ip_ct_find_proto(expect->tuple.dst.protonum));
+                   __ip_conntrack_proto_find(expect->tuple.dst.protonum));
        return seq_putc(s, '\n');
 }
 
@@ -889,6 +888,7 @@ static int init_or_cleanup(int init)
        return ret;
 
  cleanup:
+       synchronize_net();
 #ifdef CONFIG_SYSCTL
        unregister_sysctl_table(ip_ct_sysctl_header);
  cleanup_localinops:
@@ -971,6 +971,14 @@ void need_ip_conntrack(void)
 {
 }
 
+#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
+EXPORT_SYMBOL_GPL(ip_conntrack_chain);
+EXPORT_SYMBOL_GPL(ip_conntrack_expect_chain);
+EXPORT_SYMBOL_GPL(ip_conntrack_register_notifier);
+EXPORT_SYMBOL_GPL(ip_conntrack_unregister_notifier);
+EXPORT_SYMBOL_GPL(__ip_ct_event_cache_init);
+EXPORT_PER_CPU_SYMBOL_GPL(ip_conntrack_ecache);
+#endif
 EXPORT_SYMBOL(ip_conntrack_protocol_register);
 EXPORT_SYMBOL(ip_conntrack_protocol_unregister);
 EXPORT_SYMBOL(ip_ct_get_tuple);
@@ -982,12 +990,16 @@ EXPORT_SYMBOL(ip_conntrack_helper_register);
 EXPORT_SYMBOL(ip_conntrack_helper_unregister);
 EXPORT_SYMBOL(ip_ct_iterate_cleanup);
 EXPORT_SYMBOL(ip_ct_refresh_acct);
-EXPORT_SYMBOL(ip_ct_protos);
-EXPORT_SYMBOL(ip_ct_find_proto);
+
 EXPORT_SYMBOL(ip_conntrack_expect_alloc);
 EXPORT_SYMBOL(ip_conntrack_expect_put);
+EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get);
 EXPORT_SYMBOL(ip_conntrack_expect_related);
 EXPORT_SYMBOL(ip_conntrack_unexpect_related);
+EXPORT_SYMBOL_GPL(ip_conntrack_expect_list);
+EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find);
+EXPORT_SYMBOL_GPL(ip_ct_unlink_expect);
+
 EXPORT_SYMBOL(ip_conntrack_tuple_taken);
 EXPORT_SYMBOL(ip_ct_gather_frags);
 EXPORT_SYMBOL(ip_conntrack_htable_size);
@@ -995,7 +1007,28 @@ EXPORT_SYMBOL(ip_conntrack_lock);
 EXPORT_SYMBOL(ip_conntrack_hash);
 EXPORT_SYMBOL(ip_conntrack_untracked);
 EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
-EXPORT_SYMBOL_GPL(ip_conntrack_put);
 #ifdef CONFIG_IP_NF_NAT_NEEDED
 EXPORT_SYMBOL(ip_conntrack_tcp_update);
 #endif
+
+EXPORT_SYMBOL_GPL(ip_conntrack_flush);
+EXPORT_SYMBOL_GPL(__ip_conntrack_find);
+
+EXPORT_SYMBOL_GPL(ip_conntrack_alloc);
+EXPORT_SYMBOL_GPL(ip_conntrack_free);
+EXPORT_SYMBOL_GPL(ip_conntrack_hash_insert);
+
+EXPORT_SYMBOL_GPL(ip_ct_remove_expectations);
+
+EXPORT_SYMBOL_GPL(ip_conntrack_helper_find_get);
+EXPORT_SYMBOL_GPL(ip_conntrack_helper_put);
+EXPORT_SYMBOL_GPL(__ip_conntrack_helper_find_byname);
+
+EXPORT_SYMBOL_GPL(ip_conntrack_proto_find_get);
+EXPORT_SYMBOL_GPL(ip_conntrack_proto_put);
+EXPORT_SYMBOL_GPL(__ip_conntrack_proto_find);
+#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
+    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
+EXPORT_SYMBOL_GPL(ip_ct_port_tuple_to_nfattr);
+EXPORT_SYMBOL_GPL(ip_ct_port_nfattr_to_tuple);
+#endif
index f8ff170f390a3ad8bd8e5f0100658d7d1908008f..d2b590533452e201d48c8b1bc172a0661828b917 100644 (file)
@@ -75,6 +75,7 @@ static int tftp_help(struct sk_buff **pskb,
                exp->mask.dst.u.udp.port = 0xffff;
                exp->mask.dst.protonum = 0xff;
                exp->expectfn = NULL;
+               exp->flags = 0;
 
                DEBUGP("expect: ");
                DUMP_TUPLE(&exp->tuple);
index 739b6dde1c826e3e77ef246ba240234a3b31c3f6..1adedb743f609f8b349a545184040d54512f639d 100644 (file)
@@ -47,8 +47,39 @@ DEFINE_RWLOCK(ip_nat_lock);
 static unsigned int ip_nat_htable_size;
 
 static struct list_head *bysource;
+
+#define MAX_IP_NAT_PROTO 256
 struct ip_nat_protocol *ip_nat_protos[MAX_IP_NAT_PROTO];
 
+static inline struct ip_nat_protocol *
+__ip_nat_proto_find(u_int8_t protonum)
+{
+       return ip_nat_protos[protonum];
+}
+
+struct ip_nat_protocol *
+ip_nat_proto_find_get(u_int8_t protonum)
+{
+       struct ip_nat_protocol *p;
+
+       /* we need to disable preemption to make sure 'p' doesn't get
+        * removed until we've grabbed the reference */
+       preempt_disable();
+       p = __ip_nat_proto_find(protonum);
+       if (p) {
+               if (!try_module_get(p->me))
+                       p = &ip_nat_unknown_protocol;
+       }
+       preempt_enable();
+
+       return p;
+}
+
+void
+ip_nat_proto_put(struct ip_nat_protocol *p)
+{
+       module_put(p->me);
+}
 
 /* We keep an extra hash for each conntrack, for fast searching. */
 static inline unsigned int
@@ -103,7 +134,8 @@ static int
 in_range(const struct ip_conntrack_tuple *tuple,
         const struct ip_nat_range *range)
 {
-       struct ip_nat_protocol *proto = ip_nat_find_proto(tuple->dst.protonum);
+       struct ip_nat_protocol *proto = 
+                               __ip_nat_proto_find(tuple->dst.protonum);
 
        /* If we are supposed to map IPs, then we must be in the
           range specified, otherwise let this drag us onto a new src IP. */
@@ -216,8 +248,7 @@ get_unique_tuple(struct ip_conntrack_tuple *tuple,
                 struct ip_conntrack *conntrack,
                 enum ip_nat_manip_type maniptype)
 {
-       struct ip_nat_protocol *proto
-               = ip_nat_find_proto(orig_tuple->dst.protonum);
+       struct ip_nat_protocol *proto;
 
        /* 1) If this srcip/proto/src-proto-part is currently mapped,
           and that same mapping gives a unique tuple within the given
@@ -242,14 +273,20 @@ get_unique_tuple(struct ip_conntrack_tuple *tuple,
        /* 3) The per-protocol part of the manip is made to map into
           the range to make a unique tuple. */
 
+       proto = ip_nat_proto_find_get(orig_tuple->dst.protonum);
+
        /* Only bother mapping if it's not already in range and unique */
        if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)
             || proto->in_range(tuple, maniptype, &range->min, &range->max))
-           && !ip_nat_used_tuple(tuple, conntrack))
+           && !ip_nat_used_tuple(tuple, conntrack)) {
+               ip_nat_proto_put(proto);
                return;
+       }
 
        /* Last change: get protocol to try to obtain unique tuple. */
        proto->unique_tuple(tuple, range, maniptype, conntrack);
+
+       ip_nat_proto_put(proto);
 }
 
 unsigned int
@@ -320,17 +357,20 @@ manip_pkt(u_int16_t proto,
          enum ip_nat_manip_type maniptype)
 {
        struct iphdr *iph;
+       struct ip_nat_protocol *p;
 
-       (*pskb)->nfcache |= NFC_ALTERED;
-       if (!skb_ip_make_writable(pskb, iphdroff + sizeof(*iph)))
+       if (!skb_make_writable(pskb, iphdroff + sizeof(*iph)))
                return 0;
 
        iph = (void *)(*pskb)->data + iphdroff;
 
        /* Manipulate protcol part. */
-       if (!ip_nat_find_proto(proto)->manip_pkt(pskb, iphdroff,
-                                                target, maniptype))
+       p = ip_nat_proto_find_get(proto);
+       if (!p->manip_pkt(pskb, iphdroff, target, maniptype)) {
+               ip_nat_proto_put(p);
                return 0;
+       }
+       ip_nat_proto_put(p);
 
        iph = (void *)(*pskb)->data + iphdroff;
 
@@ -391,7 +431,7 @@ int icmp_reply_translation(struct sk_buff **pskb,
        struct ip_conntrack_tuple inner, target;
        int hdrlen = (*pskb)->nh.iph->ihl * 4;
 
-       if (!skb_ip_make_writable(pskb, hdrlen + sizeof(*inside)))
+       if (!skb_make_writable(pskb, hdrlen + sizeof(*inside)))
                return 0;
 
        inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
@@ -426,7 +466,8 @@ int icmp_reply_translation(struct sk_buff **pskb,
 
        if (!ip_ct_get_tuple(&inside->ip, *pskb, (*pskb)->nh.iph->ihl*4 +
                             sizeof(struct icmphdr) + inside->ip.ihl*4,
-                            &inner, ip_ct_find_proto(inside->ip.protocol)))
+                            &inner,
+                            __ip_conntrack_proto_find(inside->ip.protocol)))
                return 0;
 
        /* Change inner back to look like incoming packet.  We do the
@@ -496,6 +537,49 @@ void ip_nat_protocol_unregister(struct ip_nat_protocol *proto)
        synchronize_net();
 }
 
+#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
+    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
+int
+ip_nat_port_range_to_nfattr(struct sk_buff *skb, 
+                           const struct ip_nat_range *range)
+{
+       NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(u_int16_t),
+               &range->min.tcp.port);
+       NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(u_int16_t),
+               &range->max.tcp.port);
+
+       return 0;
+
+nfattr_failure:
+       return -1;
+}
+
+int
+ip_nat_port_nfattr_to_range(struct nfattr *tb[], struct ip_nat_range *range)
+{
+       int ret = 0;
+       
+       /* we have to return whether we actually parsed something or not */
+
+       if (tb[CTA_PROTONAT_PORT_MIN-1]) {
+               ret = 1;
+               range->min.tcp.port = 
+                       *(u_int16_t *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]);
+       }
+       
+       if (!tb[CTA_PROTONAT_PORT_MAX-1]) {
+               if (ret) 
+                       range->max.tcp.port = range->min.tcp.port;
+       } else {
+               ret = 1;
+               range->max.tcp.port = 
+                       *(u_int16_t *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]);
+       }
+
+       return ret;
+}
+#endif
+
 int __init ip_nat_init(void)
 {
        size_t i;
index 158f34f32c043e789bb263d74bdd1a01299c8b03..d2dd5d3135563f9e17631f6ab72e8bd42bcad387 100644 (file)
@@ -168,7 +168,7 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb,
        struct tcphdr *tcph;
        int datalen;
 
-       if (!skb_ip_make_writable(pskb, (*pskb)->len))
+       if (!skb_make_writable(pskb, (*pskb)->len))
                return 0;
 
        if (rep_len > match_len
@@ -228,7 +228,7 @@ ip_nat_mangle_udp_packet(struct sk_buff **pskb,
                               match_offset + match_len)
                return 0;
 
-       if (!skb_ip_make_writable(pskb, (*pskb)->len))
+       if (!skb_make_writable(pskb, (*pskb)->len))
                return 0;
 
        if (rep_len > match_len
@@ -315,7 +315,7 @@ ip_nat_sack_adjust(struct sk_buff **pskb,
        optoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr);
        optend = (*pskb)->nh.iph->ihl*4 + tcph->doff*4;
 
-       if (!skb_ip_make_writable(pskb, optend))
+       if (!skb_make_writable(pskb, optend))
                return 0;
 
        dir = CTINFO2DIR(ctinfo);
@@ -363,7 +363,7 @@ ip_nat_seq_adjust(struct sk_buff **pskb,
        this_way = &ct->nat.info.seq[dir];
        other_way = &ct->nat.info.seq[!dir];
 
-       if (!skb_ip_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph)))
+       if (!skb_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph)))
                return 0;
 
        tcph = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
index 6596c9ee1655914db4789691416d60aee56ea86c..93871904399916cc1cde540b1cd3baba5111d98d 100644 (file)
@@ -62,7 +62,7 @@ icmp_manip_pkt(struct sk_buff **pskb,
        struct icmphdr *hdr;
        unsigned int hdroff = iphdroff + iph->ihl*4;
 
-       if (!skb_ip_make_writable(pskb, hdroff + sizeof(*hdr)))
+       if (!skb_make_writable(pskb, hdroff + sizeof(*hdr)))
                return 0;
 
        hdr = (struct icmphdr *)((*pskb)->data + hdroff);
@@ -106,11 +106,18 @@ icmp_print_range(char *buffer, const struct ip_nat_range *range)
        else return 0;
 }
 
-struct ip_nat_protocol ip_nat_protocol_icmp
-= { "ICMP", IPPROTO_ICMP,
-    icmp_manip_pkt,
-    icmp_in_range,
-    icmp_unique_tuple,
-    icmp_print,
-    icmp_print_range
+struct ip_nat_protocol ip_nat_protocol_icmp = {
+       .name                   = "ICMP",
+       .protonum               = IPPROTO_ICMP,
+       .me                     = THIS_MODULE,
+       .manip_pkt              = icmp_manip_pkt,
+       .in_range               = icmp_in_range,
+       .unique_tuple           = icmp_unique_tuple,
+       .print                  = icmp_print,
+       .print_range            = icmp_print_range,
+#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
+    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
+       .range_to_nfattr        = ip_nat_port_range_to_nfattr,
+       .nfattr_to_range        = ip_nat_port_nfattr_to_range,
+#endif
 };
index a98e36d2b3c627d66cec58ece9d2b173c98de71d..1d381bf68574ade3451930faa7c82ee9c42020f4 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/if.h>
+#include <linux/netfilter/nfnetlink_conntrack.h>
 #include <linux/netfilter_ipv4/ip_nat.h>
 #include <linux/netfilter_ipv4/ip_nat_rule.h>
 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
@@ -102,7 +103,7 @@ tcp_manip_pkt(struct sk_buff **pskb,
        if ((*pskb)->len >= hdroff + sizeof(struct tcphdr))
                hdrsize = sizeof(struct tcphdr);
 
-       if (!skb_ip_make_writable(pskb, hdroff + hdrsize))
+       if (!skb_make_writable(pskb, hdroff + hdrsize))
                return 0;
 
        iph = (struct iphdr *)((*pskb)->data + iphdroff);
@@ -169,11 +170,18 @@ tcp_print_range(char *buffer, const struct ip_nat_range *range)
        else return 0;
 }
 
-struct ip_nat_protocol ip_nat_protocol_tcp
-= { "TCP", IPPROTO_TCP,
-    tcp_manip_pkt,
-    tcp_in_range,
-    tcp_unique_tuple,
-    tcp_print,
-    tcp_print_range
+struct ip_nat_protocol ip_nat_protocol_tcp = {
+       .name                   = "TCP",
+       .protonum               = IPPROTO_TCP,
+       .me                     = THIS_MODULE,
+       .manip_pkt              = tcp_manip_pkt,
+       .in_range               = tcp_in_range,
+       .unique_tuple           = tcp_unique_tuple,
+       .print                  = tcp_print,
+       .print_range            = tcp_print_range,
+#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
+    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
+       .range_to_nfattr        = ip_nat_port_range_to_nfattr,
+       .nfattr_to_range        = ip_nat_port_nfattr_to_range,
+#endif
 };
index 9f66e56256644e0756e82f73e70a412883de23b1..c4906e1aa24a01027db952b38bccc2bea57f202e 100644 (file)
@@ -94,7 +94,7 @@ udp_manip_pkt(struct sk_buff **pskb,
        u32 oldip, newip;
        u16 *portptr, newport;
 
-       if (!skb_ip_make_writable(pskb, hdroff + sizeof(*hdr)))
+       if (!skb_make_writable(pskb, hdroff + sizeof(*hdr)))
                return 0;
 
        iph = (struct iphdr *)((*pskb)->data + iphdroff);
@@ -156,11 +156,18 @@ udp_print_range(char *buffer, const struct ip_nat_range *range)
        else return 0;
 }
 
-struct ip_nat_protocol ip_nat_protocol_udp
-= { "UDP", IPPROTO_UDP,
-    udp_manip_pkt,
-    udp_in_range,
-    udp_unique_tuple,
-    udp_print,
-    udp_print_range
+struct ip_nat_protocol ip_nat_protocol_udp = {
+       .name                   = "UDP",
+       .protonum               = IPPROTO_UDP,
+       .me                     = THIS_MODULE,
+       .manip_pkt              = udp_manip_pkt,
+       .in_range               = udp_in_range,
+       .unique_tuple           = udp_unique_tuple,
+       .print                  = udp_print,
+       .print_range            = udp_print_range,
+#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
+    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
+       .range_to_nfattr        = ip_nat_port_range_to_nfattr,
+       .nfattr_to_range        = ip_nat_port_nfattr_to_range,
+#endif
 };
index f5525bd58d16f2e8acb6dd7c167a130ad8f57dfe..99bbef56f84e9ff346b856760e4db18319d3d78f 100644 (file)
@@ -61,10 +61,11 @@ unknown_print_range(char *buffer, const struct ip_nat_range *range)
 }
 
 struct ip_nat_protocol ip_nat_unknown_protocol = {
-       "unknown", 0,
-       unknown_manip_pkt,
-       unknown_in_range,
-       unknown_unique_tuple,
-       unknown_print,
-       unknown_print_range
+       .name                   = "unknown",
+       .me                     = THIS_MODULE,
+       .manip_pkt              = unknown_manip_pkt,
+       .in_range               = unknown_in_range,
+       .unique_tuple           = unknown_unique_tuple,
+       .print                  = unknown_print,
+       .print_range            = unknown_print_range
 };
index 60d70fa41a156a63bd4abb9a04a894297a8fa0d7..cb66b8bddeb3d63eb2ef23ee359a2491c6511c63 100644 (file)
@@ -255,6 +255,27 @@ alloc_null_binding(struct ip_conntrack *conntrack,
        return ip_nat_setup_info(conntrack, &range, hooknum);
 }
 
+unsigned int
+alloc_null_binding_confirmed(struct ip_conntrack *conntrack,
+                             struct ip_nat_info *info,
+                             unsigned int hooknum)
+{
+       u_int32_t ip
+               = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
+                  ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
+                  : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip);
+       u_int16_t all
+               = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
+                  ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all
+                  : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all);
+       struct ip_nat_range range
+               = { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } };
+
+       DEBUGP("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n",
+              conntrack, NIPQUAD(ip));
+       return ip_nat_setup_info(conntrack, &range, hooknum);
+}
+
 int ip_nat_rule_find(struct sk_buff **pskb,
                     unsigned int hooknum,
                     const struct net_device *in,
index 2a48b6e635aef35193fb3b70babe78d17c03519d..93b2c5111bb2338b15f765ed604866d4a860310b 100644 (file)
@@ -1275,7 +1275,7 @@ static int help(struct sk_buff **pskb,
                 return NF_DROP;
        }
 
-       if (!skb_ip_make_writable(pskb, (*pskb)->len))
+       if (!skb_make_writable(pskb, (*pskb)->len))
                return NF_DROP;
 
        spin_lock_bh(&snmp_lock);
index 91d5ea1dbbc921b2a891283a53f7abb69783fd98..0ff368b131f6bac3bfd27e8201b519ce700b64bd 100644 (file)
@@ -73,8 +73,6 @@ ip_nat_fn(unsigned int hooknum,
        IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
                       & htons(IP_MF|IP_OFFSET)));
 
-       (*pskb)->nfcache |= NFC_UNKNOWN;
-
        /* If we had a hardware checksum before, it's now invalid */
        if ((*pskb)->ip_summed == CHECKSUM_HW)
                if (skb_checksum_help(*pskb, (out == NULL)))
@@ -125,8 +123,12 @@ ip_nat_fn(unsigned int hooknum,
                if (!ip_nat_initialized(ct, maniptype)) {
                        unsigned int ret;
 
-                       /* LOCAL_IN hook doesn't have a chain!  */
-                       if (hooknum == NF_IP_LOCAL_IN)
+                       if (unlikely(is_confirmed(ct)))
+                               /* NAT module was loaded late */
+                               ret = alloc_null_binding_confirmed(ct, info,
+                                                                  hooknum);
+                       else if (hooknum == NF_IP_LOCAL_IN)
+                               /* LOCAL_IN hook doesn't have a chain!  */
                                ret = alloc_null_binding(ct, info, hooknum);
                        else
                                ret = ip_nat_rule_find(pskb, hooknum,
@@ -396,6 +398,8 @@ module_exit(fini);
 EXPORT_SYMBOL(ip_nat_setup_info);
 EXPORT_SYMBOL(ip_nat_protocol_register);
 EXPORT_SYMBOL(ip_nat_protocol_unregister);
+EXPORT_SYMBOL_GPL(ip_nat_proto_find_get);
+EXPORT_SYMBOL_GPL(ip_nat_proto_put);
 EXPORT_SYMBOL(ip_nat_cheat_check);
 EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
 EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
index c6baa8174389fd64d864100d3133759b797b82bd..d54f14d926f6e0caafc80a68cc8e84d60d1b86d7 100644 (file)
 #define NET_IPQ_QMAX 2088
 #define NET_IPQ_QMAX_NAME "ip_queue_maxlen"
 
-struct ipq_rt_info {
-       __u8 tos;
-       __u32 daddr;
-       __u32 saddr;
-};
-
 struct ipq_queue_entry {
        struct list_head list;
        struct nf_info *info;
        struct sk_buff *skb;
-       struct ipq_rt_info rt_info;
 };
 
 typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long);
@@ -247,8 +240,8 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
 
        pmsg->packet_id       = (unsigned long )entry;
        pmsg->data_len        = data_len;
-       pmsg->timestamp_sec   = entry->skb->stamp.tv_sec;
-       pmsg->timestamp_usec  = entry->skb->stamp.tv_usec;
+       pmsg->timestamp_sec   = skb_tv_base.tv_sec + entry->skb->tstamp.off_sec;
+       pmsg->timestamp_usec  = skb_tv_base.tv_usec + entry->skb->tstamp.off_usec;
        pmsg->mark            = entry->skb->nfmark;
        pmsg->hook            = entry->info->hook;
        pmsg->hw_protocol     = entry->skb->protocol;
@@ -287,7 +280,8 @@ nlmsg_failure:
 }
 
 static int
-ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data)
+ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info,
+                  unsigned int queuenum, void *data)
 {
        int status = -EINVAL;
        struct sk_buff *nskb;
@@ -305,14 +299,6 @@ ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data)
        entry->info = info;
        entry->skb = skb;
 
-       if (entry->info->hook == NF_IP_LOCAL_OUT) {
-               struct iphdr *iph = skb->nh.iph;
-
-               entry->rt_info.tos = iph->tos;
-               entry->rt_info.daddr = iph->daddr;
-               entry->rt_info.saddr = iph->saddr;
-       }
-
        nskb = ipq_build_packet_message(entry, &status);
        if (nskb == NULL)
                goto err_out_free;
@@ -388,24 +374,11 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
                }
                skb_put(e->skb, diff);
        }
-       if (!skb_ip_make_writable(&e->skb, v->data_len))
+       if (!skb_make_writable(&e->skb, v->data_len))
                return -ENOMEM;
        memcpy(e->skb->data, v->payload, v->data_len);
        e->skb->ip_summed = CHECKSUM_NONE;
-       e->skb->nfcache |= NFC_ALTERED;
-
-       /*
-        * Extra routing may needed on local out, as the QUEUE target never
-        * returns control to the table.
-        */
-       if (e->info->hook == NF_IP_LOCAL_OUT) {
-               struct iphdr *iph = e->skb->nh.iph;
-
-               if (!(iph->tos == e->rt_info.tos
-                     && iph->daddr == e->rt_info.daddr
-                     && iph->saddr == e->rt_info.saddr))
-                       return ip_route_me_harder(&e->skb);
-       }
+
        return 0;
 }
 
@@ -683,6 +656,11 @@ ipq_get_info(char *buffer, char **start, off_t offset, int length)
 }
 #endif /* CONFIG_PROC_FS */
 
+static struct nf_queue_handler nfqh = {
+       .name   = "ip_queue",
+       .outfn  = &ipq_enqueue_packet,
+};
+
 static int
 init_or_cleanup(int init)
 {
@@ -693,7 +671,8 @@ init_or_cleanup(int init)
                goto cleanup;
 
        netlink_register_notifier(&ipq_nl_notifier);
-       ipqnl = netlink_kernel_create(NETLINK_FIREWALL, ipq_rcv_sk);
+       ipqnl = netlink_kernel_create(NETLINK_FIREWALL, 0, ipq_rcv_sk,
+                                     THIS_MODULE);
        if (ipqnl == NULL) {
                printk(KERN_ERR "ip_queue: failed to create netlink socket\n");
                goto cleanup_netlink_notifier;
@@ -710,7 +689,7 @@ init_or_cleanup(int init)
        register_netdevice_notifier(&ipq_dev_notifier);
        ipq_sysctl_header = register_sysctl_table(ipq_root_table, 0);
        
-       status = nf_register_queue_handler(PF_INET, ipq_enqueue_packet, NULL);
+       status = nf_register_queue_handler(PF_INET, &nfqh);
        if (status < 0) {
                printk(KERN_ERR "ip_queue: failed to register queue handler\n");
                goto cleanup_sysctl;
@@ -718,7 +697,7 @@ init_or_cleanup(int init)
        return status;
 
 cleanup:
-       nf_unregister_queue_handler(PF_INET);
+       nf_unregister_queue_handlers(&nfqh);
        synchronize_net();
        ipq_flush(NF_DROP);
        
index c88dfcd38c5623792e9876810129be204e010915..eef99a1b5de6e5fd35103497e8caa13458f11820 100644 (file)
@@ -312,7 +312,6 @@ ipt_do_table(struct sk_buff **pskb,
        do {
                IP_NF_ASSERT(e);
                IP_NF_ASSERT(back);
-               (*pskb)->nfcache |= e->nfcache;
                if (ip_packet_match(ip, indev, outdev, &e->ip, offset)) {
                        struct ipt_entry_target *t;
 
@@ -341,8 +340,8 @@ ipt_do_table(struct sk_buff **pskb,
                                                         back->comefrom);
                                        continue;
                                }
-                               if (table_base + v
-                                   != (void *)e + e->next_offset) {
+                               if (table_base + v != (void *)e + e->next_offset
+                                   && !(e->ip.flags & IPT_F_GOTO)) {
                                        /* Save old back ptr in next entry */
                                        struct ipt_entry *next
                                                = (void *)e + e->next_offset;
index 9842e6e231845c7aec4e42dafe4585f03fca4def..dab78d8bd494fd3d00fd92a1126b2ea56e0d389d 100644 (file)
@@ -32,10 +32,8 @@ target(struct sk_buff **pskb,
 {
        const struct ipt_classify_target_info *clinfo = targinfo;
 
-       if((*pskb)->priority != clinfo->priority) {
+       if((*pskb)->priority != clinfo->priority) 
                (*pskb)->priority = clinfo->priority;
-               (*pskb)->nfcache |= NFC_ALTERED;
-       }
 
        return IPT_CONTINUE;
 }
index 6706d3a1bc4fbe548746412597497ddccf895dc4..7d38913754b1a5ca44771248d4f7548f19ad9921 100644 (file)
@@ -144,7 +144,7 @@ clusterip_config_init(struct ipt_clusterip_tgt_info *i, u_int32_t ip,
        memcpy(&c->clustermac, &i->clustermac, ETH_ALEN);
        c->num_total_nodes = i->num_total_nodes;
        c->num_local_nodes = i->num_local_nodes;
-       memcpy(&c->local_nodes, &i->local_nodes, sizeof(&c->local_nodes));
+       memcpy(&c->local_nodes, &i->local_nodes, sizeof(c->local_nodes));
        c->hash_mode = i->hash_mode;
        c->hash_initval = i->hash_initval;
        atomic_set(&c->refcount, 1);
@@ -367,7 +367,7 @@ target(struct sk_buff **pskb,
 #ifdef DEBUG_CLUSTERP
        DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
 #endif
-       DEBUGP("hash=%u ct_hash=%lu ", hash, ct->mark);
+       DEBUGP("hash=%u ct_hash=%u ", hash, ct->mark);
        if (!clusterip_responsible(cipinfo->config, hash)) {
                DEBUGP("not responsible\n");
                return NF_DROP;
index 30ddd3e18eb747184b80eea693778058a85c14ec..134638021339d8126885231fa7abc896ecfb2266 100644 (file)
@@ -40,9 +40,9 @@ target(struct sk_buff **pskb,
        void *userinfo)
 {
        const struct ipt_connmark_target_info *markinfo = targinfo;
-       unsigned long diff;
-       unsigned long nfmark;
-       unsigned long newmark;
+       u_int32_t diff;
+       u_int32_t nfmark;
+       u_int32_t newmark;
 
        enum ip_conntrack_info ctinfo;
        struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo);
@@ -61,10 +61,8 @@ target(struct sk_buff **pskb,
            case IPT_CONNMARK_RESTORE:
                nfmark = (*pskb)->nfmark;
                diff = (ct->mark ^ nfmark) & markinfo->mask;
-               if (diff != 0) {
+               if (diff != 0)
                    (*pskb)->nfmark = nfmark ^ diff;
-                   (*pskb)->nfcache |= NFC_ALTERED;
-               }
                break;
            }
        }
@@ -94,6 +92,11 @@ checkentry(const char *tablename,
            }
        }
 
+       if (matchinfo->mark > 0xffffffff || matchinfo->mask > 0xffffffff) {
+               printk(KERN_WARNING "CONNMARK: Only supports 32bit mark\n");
+               return 0;
+       }
+
        return 1;
 }
 
index 3ea4509099f907ec15fe0975e3dc9d8def7f78eb..6e319570a28caf01107dff4e825f6844aa52d992 100644 (file)
@@ -39,7 +39,7 @@ target(struct sk_buff **pskb,
        if (((*pskb)->nh.iph->tos & IPT_DSCP_MASK) != sh_dscp) {
                u_int16_t diffs[2];
 
-               if (!skb_ip_make_writable(pskb, sizeof(struct iphdr)))
+               if (!skb_make_writable(pskb, sizeof(struct iphdr)))
                        return NF_DROP;
 
                diffs[0] = htons((*pskb)->nh.iph->tos) ^ 0xFFFF;
@@ -51,7 +51,6 @@ target(struct sk_buff **pskb,
                                                 sizeof(diffs),
                                                 (*pskb)->nh.iph->check
                                                 ^ 0xFFFF));
-               (*pskb)->nfcache |= NFC_ALTERED;
        }
        return IPT_CONTINUE;
 }
index 94a0ce1c1c9d057e565748b8dbef8e2b76a31491..a1319693f648c2beba63fea33070c8c79fe04fef 100644 (file)
@@ -31,7 +31,7 @@ set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
            != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
                u_int16_t diffs[2];
 
-               if (!skb_ip_make_writable(pskb, sizeof(struct iphdr)))
+               if (!skb_make_writable(pskb, sizeof(struct iphdr)))
                        return 0;
 
                diffs[0] = htons((*pskb)->nh.iph->tos) ^ 0xFFFF;
@@ -43,7 +43,6 @@ set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
                                                 sizeof(diffs),
                                                 (*pskb)->nh.iph->check
                                                 ^0xFFFF));
-               (*pskb)->nfcache |= NFC_ALTERED;
        } 
        return 1;
 }
@@ -67,7 +66,7 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo, int inward)
             tcph->cwr == einfo->proto.tcp.cwr)))
                return 1;
 
-       if (!skb_ip_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph)))
+       if (!skb_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph)))
                return 0;
        tcph = (void *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl*4;
 
@@ -87,7 +86,6 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo, int inward)
                tcph->check = csum_fold(csum_partial((char *)diffs,
                                                     sizeof(diffs),
                                                     tcph->check^0xFFFF));
-       (*pskb)->nfcache |= NFC_ALTERED;
        return 1;
 }
 
index ef08733d26da277a2fc473454e4f7b6832e6e4c3..92ed050fac69bcce35424122c8a69c5d4ac5c48f 100644 (file)
@@ -27,10 +27,6 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
 MODULE_DESCRIPTION("iptables syslog logging module");
 
-static unsigned int nflog = 1;
-module_param(nflog, int, 0400);
-MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
 #if 0
 #define DEBUGP printk
 #else
@@ -41,11 +37,17 @@ MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
 static DEFINE_SPINLOCK(log_lock);
 
 /* One level of recursion won't kill us */
-static void dump_packet(const struct ipt_log_info *info,
+static void dump_packet(const struct nf_loginfo *info,
                        const struct sk_buff *skb,
                        unsigned int iphoff)
 {
        struct iphdr _iph, *ih;
+       unsigned int logflags;
+
+       if (info->type == NF_LOG_TYPE_LOG)
+               logflags = info->u.log.logflags;
+       else
+               logflags = NF_LOG_MASK;
 
        ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph);
        if (ih == NULL) {
@@ -76,7 +78,7 @@ static void dump_packet(const struct ipt_log_info *info,
        if (ntohs(ih->frag_off) & IP_OFFSET)
                printk("FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET);
 
-       if ((info->logflags & IPT_LOG_IPOPT)
+       if ((logflags & IPT_LOG_IPOPT)
            && ih->ihl * 4 > sizeof(struct iphdr)) {
                unsigned char _opt[4 * 15 - sizeof(struct iphdr)], *op;
                unsigned int i, optsize;
@@ -119,7 +121,7 @@ static void dump_packet(const struct ipt_log_info *info,
                printk("SPT=%u DPT=%u ",
                       ntohs(th->source), ntohs(th->dest));
                /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */
-               if (info->logflags & IPT_LOG_TCPSEQ)
+               if (logflags & IPT_LOG_TCPSEQ)
                        printk("SEQ=%u ACK=%u ",
                               ntohl(th->seq), ntohl(th->ack_seq));
                /* Max length: 13 "WINDOW=65535 " */
@@ -146,7 +148,7 @@ static void dump_packet(const struct ipt_log_info *info,
                /* Max length: 11 "URGP=65535 " */
                printk("URGP=%u ", ntohs(th->urg_ptr));
 
-               if ((info->logflags & IPT_LOG_TCPOPT)
+               if ((logflags & IPT_LOG_TCPOPT)
                    && th->doff * 4 > sizeof(struct tcphdr)) {
                        unsigned char _opt[4 * 15 - sizeof(struct tcphdr)];
                        unsigned char *op;
@@ -328,7 +330,7 @@ static void dump_packet(const struct ipt_log_info *info,
        }
 
        /* Max length: 15 "UID=4294967295 " */
-       if ((info->logflags & IPT_LOG_UID) && !iphoff && skb->sk) {
+       if ((logflags & IPT_LOG_UID) && !iphoff && skb->sk) {
                read_lock_bh(&skb->sk->sk_callback_lock);
                if (skb->sk->sk_socket && skb->sk->sk_socket->file)
                        printk("UID=%u ", skb->sk->sk_socket->file->f_uid);
@@ -349,19 +351,31 @@ static void dump_packet(const struct ipt_log_info *info,
        /* maxlen = 230+   91  + 230 + 252 = 803 */
 }
 
+struct nf_loginfo default_loginfo = {
+       .type   = NF_LOG_TYPE_LOG,
+       .u = {
+               .log = {
+                       .level    = 0,
+                       .logflags = NF_LOG_MASK,
+               },
+       },
+};
+
 static void
-ipt_log_packet(unsigned int hooknum,
+ipt_log_packet(unsigned int pf,
+              unsigned int hooknum,
               const struct sk_buff *skb,
               const struct net_device *in,
               const struct net_device *out,
-              const struct ipt_log_info *loginfo,
-              const char *level_string,
+              const struct nf_loginfo *loginfo,
               const char *prefix)
 {
+       if (!loginfo)
+               loginfo = &default_loginfo;
+
        spin_lock_bh(&log_lock);
-       printk(level_string);
-       printk("%sIN=%s OUT=%s ",
-              prefix == NULL ? loginfo->prefix : prefix,
+       printk("<%d>%sIN=%s OUT=%s ", loginfo->u.log.level,
+              prefix,
               in ? in->name : "",
               out ? out->name : "");
 #ifdef CONFIG_BRIDGE_NETFILTER
@@ -405,28 +419,15 @@ ipt_log_target(struct sk_buff **pskb,
               void *userinfo)
 {
        const struct ipt_log_info *loginfo = targinfo;
-       char level_string[4] = "< >";
+       struct nf_loginfo li;
 
-       level_string[1] = '0' + (loginfo->level % 8);
-       ipt_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL);
+       li.type = NF_LOG_TYPE_LOG;
+       li.u.log.level = loginfo->level;
+       li.u.log.logflags = loginfo->logflags;
 
-       return IPT_CONTINUE;
-}
+       nf_log_packet(PF_INET, hooknum, *pskb, in, out, &li, loginfo->prefix);
 
-static void
-ipt_logfn(unsigned int hooknum,
-         const struct sk_buff *skb,
-         const struct net_device *in,
-         const struct net_device *out,
-         const char *prefix)
-{
-       struct ipt_log_info loginfo = { 
-               .level = 0, 
-               .logflags = IPT_LOG_MASK, 
-               .prefix = "" 
-       };
-
-       ipt_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix);
+       return IPT_CONTINUE;
 }
 
 static int ipt_log_checkentry(const char *tablename,
@@ -464,20 +465,29 @@ static struct ipt_target ipt_log_reg = {
        .me             = THIS_MODULE,
 };
 
+static struct nf_logger ipt_log_logger ={
+       .name           = "ipt_LOG",
+       .logfn          = &ipt_log_packet,
+       .me             = THIS_MODULE,
+};
+
 static int __init init(void)
 {
        if (ipt_register_target(&ipt_log_reg))
                return -EINVAL;
-       if (nflog)
-               nf_log_register(PF_INET, &ipt_logfn);
+       if (nf_log_register(PF_INET, &ipt_log_logger) < 0) {
+               printk(KERN_WARNING "ipt_LOG: not logging via system console "
+                      "since somebody else already registered for PF_INET\n");
+               /* we cannot make module load fail here, since otherwise
+                * iptables userspace would abort */
+       }
        
        return 0;
 }
 
 static void __exit fini(void)
 {
-       if (nflog)
-               nf_log_unregister(PF_INET, &ipt_logfn);
+       nf_log_unregister_logger(&ipt_log_logger);
        ipt_unregister_target(&ipt_log_reg);
 }
 
index 33c6f9b63b8d7af0d0fa36c74158b0fc633f2e37..52b4f2c296bf81a3772c25a122c8ca7a12f49bb0 100644 (file)
@@ -29,10 +29,9 @@ target_v0(struct sk_buff **pskb,
 {
        const struct ipt_mark_target_info *markinfo = targinfo;
 
-       if((*pskb)->nfmark != markinfo->mark) {
+       if((*pskb)->nfmark != markinfo->mark)
                (*pskb)->nfmark = markinfo->mark;
-               (*pskb)->nfcache |= NFC_ALTERED;
-       }
+
        return IPT_CONTINUE;
 }
 
@@ -61,10 +60,9 @@ target_v1(struct sk_buff **pskb,
                break;
        }
 
-       if((*pskb)->nfmark != mark) {
+       if((*pskb)->nfmark != mark)
                (*pskb)->nfmark = mark;
-               (*pskb)->nfcache |= NFC_ALTERED;
-       }
+
        return IPT_CONTINUE;
 }
 
@@ -76,6 +74,8 @@ checkentry_v0(const char *tablename,
              unsigned int targinfosize,
              unsigned int hook_mask)
 {
+       struct ipt_mark_target_info *markinfo = targinfo;
+
        if (targinfosize != IPT_ALIGN(sizeof(struct ipt_mark_target_info))) {
                printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n",
                       targinfosize,
@@ -88,6 +88,11 @@ checkentry_v0(const char *tablename,
                return 0;
        }
 
+       if (markinfo->mark > 0xffffffff) {
+               printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
+               return 0;
+       }
+
        return 1;
 }
 
@@ -120,6 +125,11 @@ checkentry_v1(const char *tablename,
                return 0;
        }
 
+       if (markinfo->mark > 0xffffffff) {
+               printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
+               return 0;
+       }
+
        return 1;
 }
 
index 91e74502c3d36ae652eca8041cc8dc66690eaf44..2f3e181c8e97ad2455b0d488d8388b007c1b0a95 100644 (file)
@@ -86,11 +86,6 @@ masquerade_target(struct sk_buff **pskb,
 
        IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
 
-       /* FIXME: For the moment, don't do local packets, breaks
-          testsuite for 2.3.49 --RR */
-       if ((*pskb)->sk)
-               return NF_ACCEPT;
-
        ct = ip_conntrack_get(*pskb, &ctinfo);
        IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED
                            || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
index 06254b29d034fab98e9b16ff6444ec71a0e8640a..e6e7b6095363db60b760b93196c5d289a3796da0 100644 (file)
@@ -46,7 +46,8 @@ check(const char *tablename,
                DEBUGP(MODULENAME":check: size %u.\n", targinfosize);
                return 0;
        }
-       if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING))) {
+       if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING) |
+                         (1 << NF_IP_LOCAL_OUT))) {
                DEBUGP(MODULENAME":check: bad hooks %x.\n", hook_mask);
                return 0;
        }
@@ -76,12 +77,13 @@ target(struct sk_buff **pskb,
        struct ip_nat_range newrange;
 
        IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
-                    || hooknum == NF_IP_POST_ROUTING);
+                    || hooknum == NF_IP_POST_ROUTING
+                    || hooknum == NF_IP_LOCAL_OUT);
        ct = ip_conntrack_get(*pskb, &ctinfo);
 
        netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip);
 
-       if (hooknum == NF_IP_PRE_ROUTING)
+       if (hooknum == NF_IP_PRE_ROUTING || hooknum == NF_IP_LOCAL_OUT)
                new_ip = (*pskb)->nh.iph->daddr & ~netmask;
        else
                new_ip = (*pskb)->nh.iph->saddr & ~netmask;
diff --git a/net/ipv4/netfilter/ipt_NFQUEUE.c b/net/ipv4/netfilter/ipt_NFQUEUE.c
new file mode 100644 (file)
index 0000000..3cedc9b
--- /dev/null
@@ -0,0 +1,70 @@
+/* iptables module for using new netfilter netlink queue
+ *
+ * (C) 2005 by Harald Welte <laforge@netfilter.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/skbuff.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_NFQUEUE.h>
+
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_DESCRIPTION("iptables NFQUEUE target");
+MODULE_LICENSE("GPL");
+
+static unsigned int
+target(struct sk_buff **pskb,
+       const struct net_device *in,
+       const struct net_device *out,
+       unsigned int hooknum,
+       const void *targinfo,
+       void *userinfo)
+{
+       const struct ipt_NFQ_info *tinfo = targinfo;
+
+       return NF_QUEUE_NR(tinfo->queuenum);
+}
+
+static int
+checkentry(const char *tablename,
+          const struct ipt_entry *e,
+           void *targinfo,
+           unsigned int targinfosize,
+           unsigned int hook_mask)
+{
+       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_NFQ_info))) {
+               printk(KERN_WARNING "NFQUEUE: targinfosize %u != %Zu\n",
+                      targinfosize,
+                      IPT_ALIGN(sizeof(struct ipt_NFQ_info)));
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct ipt_target ipt_NFQ_reg = {
+       .name           = "NFQUEUE",
+       .target         = target,
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       return ipt_register_target(&ipt_NFQ_reg);
+}
+
+static void __exit fini(void)
+{
+       ipt_unregister_target(&ipt_NFQ_reg);
+}
+
+module_init(init);
+module_exit(fini);
index 91569644602008d5b6d04d943de37379c4430f20..f115a84a4ac628ba5a41883eab33c127ce797f40 100644 (file)
@@ -156,7 +156,6 @@ static void send_reset(struct sk_buff *oldskb, int hook)
 
        /* This packet will not be the same as the other: clear nf fields */
        nf_reset(nskb);
-       nskb->nfcache = 0;
        nskb->nfmark = 0;
 #ifdef CONFIG_BRIDGE_NETFILTER
        nf_bridge_put(nskb->nf_bridge);
index 7b84a254440e79db82680e29e977367a887af718..8db70d6908c33947917babc2c6cf2df11ce871a3 100644 (file)
@@ -58,7 +58,7 @@ ipt_tcpmss_target(struct sk_buff **pskb,
        unsigned int i;
        u_int8_t *opt;
 
-       if (!skb_ip_make_writable(pskb, (*pskb)->len))
+       if (!skb_make_writable(pskb, (*pskb)->len))
                return NF_DROP;
 
        if ((*pskb)->ip_summed == CHECKSUM_HW &&
@@ -190,7 +190,6 @@ ipt_tcpmss_target(struct sk_buff **pskb,
               newmss);
 
  retmodified:
-       (*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED;
        return IPT_CONTINUE;
 }
 
index 85c70d240f8bf433e6e7b59d7cc9712371a5769b..deadb36d442805aefba5d96465f5a478aa016fa3 100644 (file)
@@ -33,7 +33,7 @@ target(struct sk_buff **pskb,
        if (((*pskb)->nh.iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) {
                u_int16_t diffs[2];
 
-               if (!skb_ip_make_writable(pskb, sizeof(struct iphdr)))
+               if (!skb_make_writable(pskb, sizeof(struct iphdr)))
                        return NF_DROP;
 
                diffs[0] = htons((*pskb)->nh.iph->tos) ^ 0xFFFF;
@@ -46,7 +46,6 @@ target(struct sk_buff **pskb,
                                                 sizeof(diffs),
                                                 (*pskb)->nh.iph->check
                                                 ^0xFFFF));
-               (*pskb)->nfcache |= NFC_ALTERED;
        }
        return IPT_CONTINUE;
 }
diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c
new file mode 100644 (file)
index 0000000..b9ae6a9
--- /dev/null
@@ -0,0 +1,119 @@
+/* TTL modification target for IP tables
+ * (C) 2000,2005 by Harald Welte <laforge@netfilter.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/skbuff.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_TTL.h>
+
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_DESCRIPTION("IP tables TTL modification module");
+MODULE_LICENSE("GPL");
+
+static unsigned int 
+ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in, 
+               const struct net_device *out, unsigned int hooknum, 
+               const void *targinfo, void *userinfo)
+{
+       struct iphdr *iph;
+       const struct ipt_TTL_info *info = targinfo;
+       u_int16_t diffs[2];
+       int new_ttl;
+
+       if (!skb_make_writable(pskb, (*pskb)->len))
+               return NF_DROP;
+
+       iph = (*pskb)->nh.iph;
+
+       switch (info->mode) {
+               case IPT_TTL_SET:
+                       new_ttl = info->ttl;
+                       break;
+               case IPT_TTL_INC:
+                       new_ttl = iph->ttl + info->ttl;
+                       if (new_ttl > 255)
+                               new_ttl = 255;
+                       break;
+               case IPT_TTL_DEC:
+                       new_ttl = iph->ttl - info->ttl;
+                       if (new_ttl < 0)
+                               new_ttl = 0;
+                       break;
+               default:
+                       new_ttl = iph->ttl;
+                       break;
+       }
+
+       if (new_ttl != iph->ttl) {
+               diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF;
+               iph->ttl = new_ttl;
+               diffs[1] = htons(((unsigned)iph->ttl) << 8);
+               iph->check = csum_fold(csum_partial((char *)diffs,
+                                                   sizeof(diffs),
+                                                   iph->check^0xFFFF));
+       }
+
+       return IPT_CONTINUE;
+}
+
+static int ipt_ttl_checkentry(const char *tablename,
+               const struct ipt_entry *e,
+               void *targinfo,
+               unsigned int targinfosize,
+               unsigned int hook_mask)
+{
+       struct ipt_TTL_info *info = targinfo;
+
+       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) {
+               printk(KERN_WARNING "ipt_TTL: targinfosize %u != %Zu\n",
+                               targinfosize,
+                               IPT_ALIGN(sizeof(struct ipt_TTL_info)));
+               return 0;
+       }
+
+       if (strcmp(tablename, "mangle")) {
+               printk(KERN_WARNING "ipt_TTL: can only be called from "
+                       "\"mangle\" table, not \"%s\"\n", tablename);
+               return 0;
+       }
+
+       if (info->mode > IPT_TTL_MAXMODE) {
+               printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n", 
+                       info->mode);
+               return 0;
+       }
+
+       if ((info->mode != IPT_TTL_SET) && (info->ttl == 0))
+               return 0;
+
+       return 1;
+}
+
+static struct ipt_target ipt_TTL = { 
+       .name           = "TTL",
+       .target         = ipt_ttl_target, 
+       .checkentry     = ipt_ttl_checkentry, 
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       return ipt_register_target(&ipt_TTL);
+}
+
+static void __exit fini(void)
+{
+       ipt_unregister_target(&ipt_TTL);
+}
+
+module_init(init);
+module_exit(fini);
index 52a0076302a7668a4e627f86c4b4186f964cd9e2..e2c14f3cb2fc6a91e32d81bcdda5777cbd248c06 100644 (file)
@@ -62,6 +62,7 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
 MODULE_DESCRIPTION("iptables userspace logging module");
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NFLOG);
 
 #define ULOG_NL_EVENT          111             /* Harald's favorite number */
 #define ULOG_MAXNLGROUPS       32              /* numer of nlgroups */
@@ -115,10 +116,10 @@ static void ulog_send(unsigned int nlgroupnum)
        if (ub->qlen > 1)
                ub->lastnlh->nlmsg_type = NLMSG_DONE;
 
-       NETLINK_CB(ub->skb).dst_groups = (1 << nlgroupnum);
-       DEBUGP("ipt_ULOG: throwing %d packets to netlink mask %u\n",
-               ub->qlen, nlgroupnum);
-       netlink_broadcast(nflognl, ub->skb, 0, (1 << nlgroupnum), GFP_ATOMIC);
+       NETLINK_CB(ub->skb).dst_group = nlgroupnum + 1;
+       DEBUGP("ipt_ULOG: throwing %d packets to netlink group %u\n",
+               ub->qlen, nlgroupnum + 1);
+       netlink_broadcast(nflognl, ub->skb, 0, nlgroupnum + 1, GFP_ATOMIC);
 
        ub->qlen = 0;
        ub->skb = NULL;
@@ -219,13 +220,13 @@ static void ipt_ulog_packet(unsigned int hooknum,
        pm = NLMSG_DATA(nlh);
 
        /* We might not have a timestamp, get one */
-       if (skb->stamp.tv_sec == 0)
-               do_gettimeofday((struct timeval *)&skb->stamp);
+       if (skb->tstamp.off_sec == 0)
+               __net_timestamp((struct sk_buff *)skb);
 
        /* copy hook, prefix, timestamp, payload, etc. */
        pm->data_len = copy_len;
-       pm->timestamp_sec = skb->stamp.tv_sec;
-       pm->timestamp_usec = skb->stamp.tv_usec;
+       pm->timestamp_sec = skb_tv_base.tv_sec + skb->tstamp.off_sec;
+       pm->timestamp_usec = skb_tv_base.tv_usec + skb->tstamp.off_usec;
        pm->mark = skb->nfmark;
        pm->hook = hooknum;
        if (prefix != NULL)
@@ -303,18 +304,27 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb,
        return IPT_CONTINUE;
 }
  
-static void ipt_logfn(unsigned int hooknum,
+static void ipt_logfn(unsigned int pf,
+                     unsigned int hooknum,
                      const struct sk_buff *skb,
                      const struct net_device *in,
                      const struct net_device *out,
+                     const struct nf_loginfo *li,
                      const char *prefix)
 {
-       struct ipt_ulog_info loginfo = { 
-               .nl_group = ULOG_DEFAULT_NLGROUP,
-               .copy_range = 0,
-               .qthreshold = ULOG_DEFAULT_QTHRESHOLD,
-               .prefix = ""
-       };
+       struct ipt_ulog_info loginfo;
+
+       if (!li || li->type != NF_LOG_TYPE_ULOG) {
+               loginfo.nl_group = ULOG_DEFAULT_NLGROUP;
+               loginfo.copy_range = 0;
+               loginfo.qthreshold = ULOG_DEFAULT_QTHRESHOLD;
+               loginfo.prefix[0] = '\0';
+       } else {
+               loginfo.nl_group = li->u.ulog.group;
+               loginfo.copy_range = li->u.ulog.copy_len;
+               loginfo.qthreshold = li->u.ulog.qthreshold;
+               strlcpy(loginfo.prefix, prefix, sizeof(loginfo.prefix));
+       }
 
        ipt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix);
 }
@@ -354,6 +364,12 @@ static struct ipt_target ipt_ulog_reg = {
        .me             = THIS_MODULE,
 };
 
+static struct nf_logger ipt_ulog_logger = {
+       .name           = "ipt_ULOG",
+       .logfn          = &ipt_logfn,
+       .me             = THIS_MODULE,
+};
+
 static int __init init(void)
 {
        int i;
@@ -372,7 +388,8 @@ static int __init init(void)
                ulog_buffers[i].timer.data = i;
        }
 
-       nflognl = netlink_kernel_create(NETLINK_NFLOG, NULL);
+       nflognl = netlink_kernel_create(NETLINK_NFLOG, ULOG_MAXNLGROUPS, NULL,
+                                       THIS_MODULE);
        if (!nflognl)
                return -ENOMEM;
 
@@ -381,7 +398,7 @@ static int __init init(void)
                return -EINVAL;
        }
        if (nflog)
-               nf_log_register(PF_INET, &ipt_logfn);
+               nf_log_register(PF_INET, &ipt_ulog_logger);
        
        return 0;
 }
@@ -394,7 +411,7 @@ static void __exit fini(void)
        DEBUGP("ipt_ULOG: cleanup_module\n");
 
        if (nflog)
-               nf_log_unregister(PF_INET, &ipt_logfn);
+               nf_log_unregister_logger(&ipt_ulog_logger);
        ipt_unregister_target(&ipt_ulog_reg);
        sock_release(nflognl->sk_socket);
 
diff --git a/net/ipv4/netfilter/ipt_connbytes.c b/net/ipv4/netfilter/ipt_connbytes.c
new file mode 100644 (file)
index 0000000..df4a42c
--- /dev/null
@@ -0,0 +1,162 @@
+/* Kernel module to match connection tracking byte counter.
+ * GPL (C) 2002 Martin Devera (devik@cdi.cz).
+ *
+ * 2004-07-20 Harald Welte <laforge@netfilter.org>
+ *     - reimplemented to use per-connection accounting counters
+ *     - add functionality to match number of packets
+ *     - add functionality to match average packet size
+ *     - add support to match directions seperately
+ *
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_connbytes.h>
+
+#include <asm/div64.h>
+#include <asm/bitops.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_DESCRIPTION("iptables match for matching number of pkts/bytes per connection");
+
+/* 64bit divisor, dividend and result. dynamic precision */
+static u_int64_t div64_64(u_int64_t dividend, u_int64_t divisor)
+{
+       u_int32_t d = divisor;
+
+       if (divisor > 0xffffffffULL) {
+               unsigned int shift = fls(divisor >> 32);
+
+               d = divisor >> shift;
+               dividend >>= shift;
+       }
+
+       do_div(dividend, d);
+       return dividend;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      int *hotdrop)
+{
+       const struct ipt_connbytes_info *sinfo = matchinfo;
+       enum ip_conntrack_info ctinfo;
+       struct ip_conntrack *ct;
+       u_int64_t what = 0;     /* initialize to make gcc happy */
+
+       if (!(ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo)))
+               return 0; /* no match */
+
+       switch (sinfo->what) {
+       case IPT_CONNBYTES_PKTS:
+               switch (sinfo->direction) {
+               case IPT_CONNBYTES_DIR_ORIGINAL:
+                       what = ct->counters[IP_CT_DIR_ORIGINAL].packets;
+                       break;
+               case IPT_CONNBYTES_DIR_REPLY:
+                       what = ct->counters[IP_CT_DIR_REPLY].packets;
+                       break;
+               case IPT_CONNBYTES_DIR_BOTH:
+                       what = ct->counters[IP_CT_DIR_ORIGINAL].packets;
+                       what += ct->counters[IP_CT_DIR_REPLY].packets;
+                       break;
+               }
+               break;
+       case IPT_CONNBYTES_BYTES:
+               switch (sinfo->direction) {
+               case IPT_CONNBYTES_DIR_ORIGINAL:
+                       what = ct->counters[IP_CT_DIR_ORIGINAL].bytes;
+                       break;
+               case IPT_CONNBYTES_DIR_REPLY:
+                       what = ct->counters[IP_CT_DIR_REPLY].bytes;
+                       break;
+               case IPT_CONNBYTES_DIR_BOTH:
+                       what = ct->counters[IP_CT_DIR_ORIGINAL].bytes;
+                       what += ct->counters[IP_CT_DIR_REPLY].bytes;
+                       break;
+               }
+               break;
+       case IPT_CONNBYTES_AVGPKT:
+               switch (sinfo->direction) {
+               case IPT_CONNBYTES_DIR_ORIGINAL:
+                       what = div64_64(ct->counters[IP_CT_DIR_ORIGINAL].bytes,
+                                       ct->counters[IP_CT_DIR_ORIGINAL].packets);
+                       break;
+               case IPT_CONNBYTES_DIR_REPLY:
+                       what = div64_64(ct->counters[IP_CT_DIR_REPLY].bytes,
+                                       ct->counters[IP_CT_DIR_REPLY].packets);
+                       break;
+               case IPT_CONNBYTES_DIR_BOTH:
+                       {
+                               u_int64_t bytes;
+                               u_int64_t pkts;
+                               bytes = ct->counters[IP_CT_DIR_ORIGINAL].bytes +
+                                       ct->counters[IP_CT_DIR_REPLY].bytes;
+                               pkts = ct->counters[IP_CT_DIR_ORIGINAL].packets+
+                                       ct->counters[IP_CT_DIR_REPLY].packets;
+
+                               /* FIXME_THEORETICAL: what to do if sum
+                                * overflows ? */
+
+                               what = div64_64(bytes, pkts);
+                       }
+                       break;
+               }
+               break;
+       }
+
+       if (sinfo->count.to)
+               return (what <= sinfo->count.to && what >= sinfo->count.from);
+       else
+               return (what >= sinfo->count.from);
+}
+
+static int check(const char *tablename,
+                const struct ipt_ip *ip,
+                void *matchinfo,
+                unsigned int matchsize,
+                unsigned int hook_mask)
+{
+       const struct ipt_connbytes_info *sinfo = matchinfo;
+
+       if (matchsize != IPT_ALIGN(sizeof(struct ipt_connbytes_info)))
+               return 0;
+
+       if (sinfo->what != IPT_CONNBYTES_PKTS &&
+           sinfo->what != IPT_CONNBYTES_BYTES &&
+           sinfo->what != IPT_CONNBYTES_AVGPKT)
+               return 0;
+
+       if (sinfo->direction != IPT_CONNBYTES_DIR_ORIGINAL &&
+           sinfo->direction != IPT_CONNBYTES_DIR_REPLY &&
+           sinfo->direction != IPT_CONNBYTES_DIR_BOTH)
+               return 0;
+
+       return 1;
+}
+
+static struct ipt_match state_match = {
+       .name           = "connbytes",
+       .match          = &match,
+       .checkentry     = &check,
+       .me             = THIS_MODULE
+};
+
+static int __init init(void)
+{
+       return ipt_register_match(&state_match);
+}
+
+static void __exit fini(void)
+{
+       ipt_unregister_match(&state_match);
+}
+
+module_init(init);
+module_exit(fini);
index 2706f96cea55dba1078baeca1e788a2fa116be94..bf8de47ce0041487822543d275523541e4023dc1 100644 (file)
@@ -54,9 +54,16 @@ checkentry(const char *tablename,
           unsigned int matchsize,
           unsigned int hook_mask)
 {
+       struct ipt_connmark_info *cm = 
+                               (struct ipt_connmark_info *)matchinfo;
        if (matchsize != IPT_ALIGN(sizeof(struct ipt_connmark_info)))
                return 0;
 
+       if (cm->mark > 0xffffffff || cm->mask > 0xffffffff) {
+               printk(KERN_WARNING "connmark: only support 32bit mark\n");
+               return 0;
+       }
+
        return 1;
 }
 
diff --git a/net/ipv4/netfilter/ipt_dccp.c b/net/ipv4/netfilter/ipt_dccp.c
new file mode 100644 (file)
index 0000000..ad3278b
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * iptables module for DCCP protocol header matching
+ *
+ * (C) 2005 by Harald Welte <laforge@netfilter.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/skbuff.h>
+#include <linux/spinlock.h>
+#include <net/ip.h>
+#include <linux/dccp.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_dccp.h>
+
+#define DCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
+                                 || (!!((invflag) & (option)) ^ (cond)))
+
+static unsigned char *dccp_optbuf;
+static DEFINE_SPINLOCK(dccp_buflock);
+
+static inline int
+dccp_find_option(u_int8_t option,
+                const struct sk_buff *skb,
+                const struct dccp_hdr *dh,
+                int *hotdrop)
+{
+       /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
+       unsigned char *op;
+       unsigned int optoff = __dccp_hdr_len(dh);
+       unsigned int optlen = dh->dccph_doff*4 - __dccp_hdr_len(dh);
+       unsigned int i;
+
+       if (dh->dccph_doff * 4 < __dccp_hdr_len(dh)) {
+               *hotdrop = 1;
+               return 0;
+       }
+
+       if (!optlen)
+               return 0;
+
+       spin_lock_bh(&dccp_buflock);
+       op = skb_header_pointer(skb,
+                               skb->nh.iph->ihl*4 + optoff,
+                               optlen, dccp_optbuf);
+       if (op == NULL) {
+               /* If we don't have the whole header, drop packet. */
+               spin_unlock_bh(&dccp_buflock);
+               *hotdrop = 1;
+               return 0;
+       }
+
+       for (i = 0; i < optlen; ) {
+               if (op[i] == option) {
+                       spin_unlock_bh(&dccp_buflock);
+                       return 1;
+               }
+
+               if (op[i] < 2) 
+                       i++;
+               else 
+                       i += op[i+1]?:1;
+       }
+
+       spin_unlock_bh(&dccp_buflock);
+       return 0;
+}
+
+
+static inline int
+match_types(const struct dccp_hdr *dh, u_int16_t typemask)
+{
+       return (typemask & (1 << dh->dccph_type));
+}
+
+static inline int
+match_option(u_int8_t option, const struct sk_buff *skb,
+            const struct dccp_hdr *dh, int *hotdrop)
+{
+       return dccp_find_option(option, skb, dh, hotdrop);
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      int *hotdrop)
+{
+       const struct ipt_dccp_info *info = 
+                               (const struct ipt_dccp_info *)matchinfo;
+       struct dccp_hdr _dh, *dh;
+
+       if (offset)
+               return 0;
+       
+       dh = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_dh), &_dh);
+       if (dh == NULL) {
+               *hotdrop = 1;
+               return 0;
+               }
+
+       return  DCCHECK(((ntohs(dh->dccph_sport) >= info->spts[0]) 
+                       && (ntohs(dh->dccph_sport) <= info->spts[1])), 
+                       IPT_DCCP_SRC_PORTS, info->flags, info->invflags)
+               && DCCHECK(((ntohs(dh->dccph_dport) >= info->dpts[0]) 
+                       && (ntohs(dh->dccph_dport) <= info->dpts[1])), 
+                       IPT_DCCP_DEST_PORTS, info->flags, info->invflags)
+               && DCCHECK(match_types(dh, info->typemask),
+                          IPT_DCCP_TYPE, info->flags, info->invflags)
+               && DCCHECK(match_option(info->option, skb, dh, hotdrop),
+                          IPT_DCCP_OPTION, info->flags, info->invflags);
+}
+
+static int
+checkentry(const char *tablename,
+          const struct ipt_ip *ip,
+          void *matchinfo,
+          unsigned int matchsize,
+          unsigned int hook_mask)
+{
+       const struct ipt_dccp_info *info;
+
+       info = (const struct ipt_dccp_info *)matchinfo;
+
+       return ip->proto == IPPROTO_DCCP
+               && !(ip->invflags & IPT_INV_PROTO)
+               && matchsize == IPT_ALIGN(sizeof(struct ipt_dccp_info))
+               && !(info->flags & ~IPT_DCCP_VALID_FLAGS)
+               && !(info->invflags & ~IPT_DCCP_VALID_FLAGS)
+               && !(info->invflags & ~info->flags);
+}
+
+static struct ipt_match dccp_match = 
+{ 
+       .name           = "dccp",
+       .match          = &match,
+       .checkentry     = &checkentry,
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       int ret;
+
+       /* doff is 8 bits, so the maximum option size is (4*256).  Don't put
+        * this in BSS since DaveM is worried about locked TLB's for kernel
+        * BSS. */
+       dccp_optbuf = kmalloc(256 * 4, GFP_KERNEL);
+       if (!dccp_optbuf)
+               return -ENOMEM;
+       ret = ipt_register_match(&dccp_match);
+       if (ret)
+               kfree(dccp_optbuf);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       ipt_unregister_match(&dccp_match);
+       kfree(dccp_optbuf);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_DESCRIPTION("Match for DCCP protocol packets");
+
index 564b49bfebcf6feda673d223713d911da17145a1..2dd1cccbdab9e938f20920c9355ab1a834bdc0ff 100644 (file)
@@ -94,7 +94,7 @@ struct ipt_hashlimit_htable {
 static DEFINE_SPINLOCK(hashlimit_lock);        /* protects htables list */
 static DECLARE_MUTEX(hlimit_mutex);    /* additional checkentry protection */
 static HLIST_HEAD(hashlimit_htables);
-static kmem_cache_t *hashlimit_cachep;
+static kmem_cache_t *hashlimit_cachep __read_mostly;
 
 static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b)
 {
index 8955728127b9528e720fdba0259da1f9d216f261..00bef6cdd3f8e3c6b164bea7142b8dba81448be9 100644 (file)
@@ -37,9 +37,16 @@ checkentry(const char *tablename,
            unsigned int matchsize,
            unsigned int hook_mask)
 {
+       struct ipt_mark_info *minfo = (struct ipt_mark_info *) matchinfo;
+
        if (matchsize != IPT_ALIGN(sizeof(struct ipt_mark_info)))
                return 0;
 
+       if (minfo->mark > 0xffffffff || minfo->mask > 0xffffffff) {
+               printk(KERN_WARNING "mark: only supports 32bit mark\n");
+               return 0;
+       }
+
        return 1;
 }
 
index 3b9065e06381c1a2473f3a028299d94fe380471e..c1889f88262b4867bc844322351e4909f14ed434 100644 (file)
@@ -20,106 +20,6 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
 MODULE_DESCRIPTION("iptables owner match");
 
-static int
-match_comm(const struct sk_buff *skb, const char *comm)
-{
-       struct task_struct *g, *p;
-       struct files_struct *files;
-       int i;
-
-       read_lock(&tasklist_lock);
-       do_each_thread(g, p) {
-               if(strncmp(p->comm, comm, sizeof(p->comm)))
-                       continue;
-
-               task_lock(p);
-               files = p->files;
-               if(files) {
-                       spin_lock(&files->file_lock);
-                       for (i=0; i < files->max_fds; i++) {
-                               if (fcheck_files(files, i) ==
-                                   skb->sk->sk_socket->file) {
-                                       spin_unlock(&files->file_lock);
-                                       task_unlock(p);
-                                       read_unlock(&tasklist_lock);
-                                       return 1;
-                               }
-                       }
-                       spin_unlock(&files->file_lock);
-               }
-               task_unlock(p);
-       } while_each_thread(g, p);
-       read_unlock(&tasklist_lock);
-       return 0;
-}
-
-static int
-match_pid(const struct sk_buff *skb, pid_t pid)
-{
-       struct task_struct *p;
-       struct files_struct *files;
-       int i;
-
-       read_lock(&tasklist_lock);
-       p = find_task_by_pid(pid);
-       if (!p)
-               goto out;
-       task_lock(p);
-       files = p->files;
-       if(files) {
-               spin_lock(&files->file_lock);
-               for (i=0; i < files->max_fds; i++) {
-                       if (fcheck_files(files, i) ==
-                           skb->sk->sk_socket->file) {
-                               spin_unlock(&files->file_lock);
-                               task_unlock(p);
-                               read_unlock(&tasklist_lock);
-                               return 1;
-                       }
-               }
-               spin_unlock(&files->file_lock);
-       }
-       task_unlock(p);
-out:
-       read_unlock(&tasklist_lock);
-       return 0;
-}
-
-static int
-match_sid(const struct sk_buff *skb, pid_t sid)
-{
-       struct task_struct *g, *p;
-       struct file *file = skb->sk->sk_socket->file;
-       int i, found=0;
-
-       read_lock(&tasklist_lock);
-       do_each_thread(g, p) {
-               struct files_struct *files;
-               if (p->signal->session != sid)
-                       continue;
-
-               task_lock(p);
-               files = p->files;
-               if (files) {
-                       spin_lock(&files->file_lock);
-                       for (i=0; i < files->max_fds; i++) {
-                               if (fcheck_files(files, i) == file) {
-                                       found = 1;
-                                       break;
-                               }
-                       }
-                       spin_unlock(&files->file_lock);
-               }
-               task_unlock(p);
-               if (found)
-                       goto out;
-       } while_each_thread(g, p);
-out:
-       read_unlock(&tasklist_lock);
-
-       return found;
-}
-
 static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
@@ -145,24 +45,6 @@ match(const struct sk_buff *skb,
                        return 0;
        }
 
-       if(info->match & IPT_OWNER_PID) {
-               if (!match_pid(skb, info->pid) ^
-                   !!(info->invert & IPT_OWNER_PID))
-                       return 0;
-       }
-
-       if(info->match & IPT_OWNER_SID) {
-               if (!match_sid(skb, info->sid) ^
-                   !!(info->invert & IPT_OWNER_SID))
-                       return 0;
-       }
-
-       if(info->match & IPT_OWNER_COMM) {
-               if (!match_comm(skb, info->comm) ^
-                   !!(info->invert & IPT_OWNER_COMM))
-                       return 0;
-       }
-
        return 1;
 }
 
@@ -173,6 +55,8 @@ checkentry(const char *tablename,
            unsigned int matchsize,
            unsigned int hook_mask)
 {
+       const struct ipt_owner_info *info = matchinfo;
+
         if (hook_mask
             & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING))) {
                 printk("ipt_owner: only valid for LOCAL_OUT or POST_ROUTING.\n");
@@ -184,15 +68,13 @@ checkentry(const char *tablename,
                       IPT_ALIGN(sizeof(struct ipt_owner_info)));
                return 0;
        }
-#ifdef CONFIG_SMP
-       /* files->file_lock can not be used in a BH */
-       if (((struct ipt_owner_info *)matchinfo)->match
-           & (IPT_OWNER_PID|IPT_OWNER_SID|IPT_OWNER_COMM)) {
-               printk("ipt_owner: pid, sid and command matching is broken "
-                      "on SMP.\n");
+
+       if (info->match & (IPT_OWNER_PID|IPT_OWNER_SID|IPT_OWNER_COMM)) {
+               printk("ipt_owner: pid, sid and command matching "
+                      "not supported anymore\n");
                return 0;
        }
-#endif
+
        return 1;
 }
 
diff --git a/net/ipv4/netfilter/ipt_string.c b/net/ipv4/netfilter/ipt_string.c
new file mode 100644 (file)
index 0000000..b5def20
--- /dev/null
@@ -0,0 +1,91 @@
+/* String matching match for iptables
+ * 
+ * (C) 2005 Pablo Neira Ayuso <pablo@eurodev.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_string.h>
+#include <linux/textsearch.h>
+
+MODULE_AUTHOR("Pablo Neira Ayuso <pablo@eurodev.net>");
+MODULE_DESCRIPTION("IP tables string match module");
+MODULE_LICENSE("GPL");
+
+static int match(const struct sk_buff *skb,
+                const struct net_device *in,
+                const struct net_device *out,
+                const void *matchinfo,
+                int offset,
+                int *hotdrop)
+{
+       struct ts_state state;
+       struct ipt_string_info *conf = (struct ipt_string_info *) matchinfo;
+
+       memset(&state, 0, sizeof(struct ts_state));
+
+       return (skb_find_text((struct sk_buff *)skb, conf->from_offset, 
+                            conf->to_offset, conf->config, &state) 
+                            != UINT_MAX) && !conf->invert;
+}
+
+#define STRING_TEXT_PRIV(m) ((struct ipt_string_info *) m)
+
+static int checkentry(const char *tablename,
+                     const struct ipt_ip *ip,
+                     void *matchinfo,
+                     unsigned int matchsize,
+                     unsigned int hook_mask)
+{
+       struct ipt_string_info *conf = matchinfo;
+       struct ts_config *ts_conf;
+
+       if (matchsize != IPT_ALIGN(sizeof(struct ipt_string_info)))
+               return 0;
+
+       /* Damn, can't handle this case properly with iptables... */
+       if (conf->from_offset > conf->to_offset)
+               return 0;
+
+       ts_conf = textsearch_prepare(conf->algo, conf->pattern, conf->patlen,
+                                    GFP_KERNEL, TS_AUTOLOAD);
+       if (IS_ERR(ts_conf))
+               return 0;
+
+       conf->config = ts_conf;
+
+       return 1;
+}
+
+static void destroy(void *matchinfo, unsigned int matchsize)
+{
+       textsearch_destroy(STRING_TEXT_PRIV(matchinfo)->config);
+}
+
+static struct ipt_match string_match = {
+       .name           = "string",
+       .match          = match,
+       .checkentry     = checkentry,
+       .destroy        = destroy,
+       .me             = THIS_MODULE
+};
+
+static int __init init(void)
+{
+       return ipt_register_match(&string_match);
+}
+
+static void __exit fini(void)
+{
+       ipt_unregister_match(&string_match);
+}
+
+module_init(init);
+module_exit(fini);
index 912bbcc7f4152efb998f20328d433d0535dc0f85..f7943ba1f43c42d3d8c6546730c283ae134f53e6 100644 (file)
@@ -59,13 +59,10 @@ static int fold_prot_inuse(struct proto *proto)
  */
 static int sockstat_seq_show(struct seq_file *seq, void *v)
 {
-       /* From net/socket.c */
-       extern void socket_seq_show(struct seq_file *seq);
-
        socket_seq_show(seq);
        seq_printf(seq, "TCP: inuse %d orphan %d tw %d alloc %d mem %d\n",
                   fold_prot_inuse(&tcp_prot), atomic_read(&tcp_orphan_count),
-                  tcp_tw_count, atomic_read(&tcp_sockets_allocated),
+                  tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated),
                   atomic_read(&tcp_memory_allocated));
        seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot));
        seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot));
index 0db405a869f2524c4768884580590a0a42c07a37..291831e792aff067c46e8a3959c9a7058580ddbc 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/timer.h>
 #include <net/ip.h>
 #include <net/protocol.h>
-#include <net/tcp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <net/icmp.h>
index d1835b1bc8c469d8394e0ae1a0bb8c9b9a6f975c..304bb0a1d4f0f1b936e0500f08282bf137ae4505 100644 (file)
@@ -59,7 +59,6 @@
 #include <linux/netdevice.h>
 #include <linux/in_route.h>
 #include <linux/route.h>
-#include <linux/tcp.h>
 #include <linux/skbuff.h>
 #include <net/dst.h>
 #include <net/sock.h>
@@ -71,6 +70,7 @@
 #include <net/udp.h>
 #include <net/raw.h>
 #include <net/snmp.h>
+#include <net/tcp_states.h>
 #include <net/inet_common.h>
 #include <net/checksum.h>
 #include <net/xfrm.h>
@@ -150,10 +150,11 @@ static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb)
  * RFC 1122: SHOULD pass TOS value up to the transport layer.
  * -> It does. And not only TOS, but all IP header.
  */
-void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
+int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
 {
        struct sock *sk;
        struct hlist_head *head;
+       int delivered = 0;
 
        read_lock(&raw_v4_lock);
        head = &raw_v4_htable[hash];
@@ -164,6 +165,7 @@ void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
                             skb->dev->ifindex);
 
        while (sk) {
+               delivered = 1;
                if (iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) {
                        struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
 
@@ -177,6 +179,7 @@ void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
        }
 out:
        read_unlock(&raw_v4_lock);
+       return delivered;
 }
 
 void raw_err (struct sock *sk, struct sk_buff *skb, u32 info)
index d675ff80b04d98910d083cd9e1dea8c754d550e2..8c0b14e3beecc761e08c684cea964720fd2b2b97 100644 (file)
@@ -240,7 +240,9 @@ static unsigned                     rt_hash_mask;
 static int                     rt_hash_log;
 static unsigned int            rt_hash_rnd;
 
-struct rt_cache_stat *rt_cache_stat;
+static struct rt_cache_stat *rt_cache_stat;
+#define RT_CACHE_STAT_INC(field)                                         \
+               (per_cpu_ptr(rt_cache_stat, raw_smp_processor_id())->field++)
 
 static int rt_intern_hash(unsigned hash, struct rtable *rth,
                                struct rtable **res);
@@ -2600,6 +2602,8 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp)
        return ip_route_output_slow(rp, flp);
 }
 
+EXPORT_SYMBOL_GPL(__ip_route_output_key);
+
 int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, int flags)
 {
        int err;
@@ -2618,6 +2622,8 @@ int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk,
        return 0;
 }
 
+EXPORT_SYMBOL_GPL(ip_route_output_flow);
+
 int ip_route_output_key(struct rtable **rp, struct flowi *flp)
 {
        return ip_route_output_flow(rp, flp, NULL, 0);
index 72d014442185fcb1d29ee855b17da26a5bb82988..a34e60ea48a15f3b33a0531a4d5cc260a9e62f17 100644 (file)
@@ -169,8 +169,6 @@ static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
        return mssind < NUM_MSS ? msstab[mssind] + 1 : 0;
 }
 
-extern struct request_sock_ops tcp_request_sock_ops;
-
 static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
                                           struct request_sock *req,
                                           struct dst_entry *dst)
@@ -180,7 +178,7 @@ static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
 
        child = tp->af_specific->syn_recv_sock(sk, skb, req, dst);
        if (child)
-               tcp_acceptq_queue(sk, req, child);
+               inet_csk_reqsk_queue_add(sk, req, child);
        else
                reqsk_free(req);
 
index e32894532416ed0381368fb6b09b99318356ec3f..652685623519d74cca40682afbc7ade2785a8eab 100644 (file)
@@ -11,7 +11,9 @@
 #include <linux/module.h>
 #include <linux/sysctl.h>
 #include <linux/config.h>
+#include <linux/igmp.h>
 #include <net/snmp.h>
+#include <net/icmp.h>
 #include <net/ip.h>
 #include <net/route.h>
 #include <net/tcp.h>
 /* From af_inet.c */
 extern int sysctl_ip_nonlocal_bind;
 
-/* From icmp.c */
-extern int sysctl_icmp_echo_ignore_all;
-extern int sysctl_icmp_echo_ignore_broadcasts;
-extern int sysctl_icmp_ignore_bogus_error_responses;
-extern int sysctl_icmp_errors_use_inbound_ifaddr;
-
-/* From ip_fragment.c */
-extern int sysctl_ipfrag_low_thresh;
-extern int sysctl_ipfrag_high_thresh; 
-extern int sysctl_ipfrag_time;
-extern int sysctl_ipfrag_secret_interval;
-
-/* From ip_output.c */
-extern int sysctl_ip_dynaddr;
-
-/* From icmp.c */
-extern int sysctl_icmp_ratelimit;
-extern int sysctl_icmp_ratemask;
-
-/* From igmp.c */
-extern int sysctl_igmp_max_memberships;
-extern int sysctl_igmp_max_msf;
-
-/* From inetpeer.c */
-extern int inet_peer_threshold;
-extern int inet_peer_minttl;
-extern int inet_peer_maxttl;
-extern int inet_peer_gc_mintime;
-extern int inet_peer_gc_maxtime;
-
 #ifdef CONFIG_SYSCTL
 static int tcp_retr1_max = 255; 
 static int ip_local_port_range_min[] = { 1, 1 };
@@ -57,8 +29,6 @@ static int ip_local_port_range_max[] = { 65535, 65535 };
 
 struct ipv4_config ipv4_config;
 
-extern ctl_table ipv4_route_table[];
-
 #ifdef CONFIG_SYSCTL
 
 static
@@ -136,10 +106,11 @@ static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file *
        return ret;
 }
 
-int sysctl_tcp_congestion_control(ctl_table *table, int __user *name, int nlen,
-                                 void __user *oldval, size_t __user *oldlenp,
-                                 void __user *newval, size_t newlen,
-                                 void **context)
+static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name,
+                                        int nlen, void __user *oldval,
+                                        size_t __user *oldlenp,
+                                        void __user *newval, size_t newlen,
+                                        void **context)
 {
        char val[TCP_CA_NAME_MAX];
        ctl_table tbl = {
@@ -259,7 +230,7 @@ ctl_table ipv4_table[] = {
        {
                .ctl_name       = NET_TCP_MAX_TW_BUCKETS,
                .procname       = "tcp_max_tw_buckets",
-               .data           = &sysctl_tcp_max_tw_buckets,
+               .data           = &tcp_death_row.sysctl_max_tw_buckets,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = &proc_dointvec
@@ -363,7 +334,7 @@ ctl_table ipv4_table[] = {
        {
                .ctl_name       = NET_TCP_TW_RECYCLE,
                .procname       = "tcp_tw_recycle",
-               .data           = &sysctl_tcp_tw_recycle,
+               .data           = &tcp_death_row.sysctl_tw_recycle,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = &proc_dointvec
index 69b1fcf70077262e39737ce5f87bb8effb1e85e9..f3f0013a95804808d1522e89192b0beaefa91a30 100644 (file)
 
 int sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT;
 
-DEFINE_SNMP_STAT(struct tcp_mib, tcp_statistics);
-
-kmem_cache_t *tcp_bucket_cachep;
-kmem_cache_t *tcp_timewait_cachep;
+DEFINE_SNMP_STAT(struct tcp_mib, tcp_statistics) __read_mostly;
 
 atomic_t tcp_orphan_count = ATOMIC_INIT(0);
 
+EXPORT_SYMBOL_GPL(tcp_orphan_count);
+
 int sysctl_tcp_mem[3];
 int sysctl_tcp_wmem[3] = { 4 * 1024, 16 * 1024, 128 * 1024 };
 int sysctl_tcp_rmem[3] = { 4 * 1024, 87380, 87380 * 2 };
@@ -310,15 +309,6 @@ void tcp_enter_memory_pressure(void)
 
 EXPORT_SYMBOL(tcp_enter_memory_pressure);
 
-/*
- * LISTEN is a special case for poll..
- */
-static __inline__ unsigned int tcp_listen_poll(struct sock *sk,
-                                              poll_table *wait)
-{
-       return !reqsk_queue_empty(&tcp_sk(sk)->accept_queue) ? (POLLIN | POLLRDNORM) : 0;
-}
-
 /*
  *     Wait for a TCP event.
  *
@@ -334,7 +324,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
 
        poll_wait(file, sk->sk_sleep, wait);
        if (sk->sk_state == TCP_LISTEN)
-               return tcp_listen_poll(sk, wait);
+               return inet_csk_listen_poll(sk);
 
        /* Socket is not locked. We are protected from async events
           by poll logic and correct handling of state changes
@@ -457,109 +447,6 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
        return put_user(answ, (int __user *)arg);
 }
 
-
-int tcp_listen_start(struct sock *sk)
-{
-       struct inet_sock *inet = inet_sk(sk);
-       struct tcp_sock *tp = tcp_sk(sk);
-       int rc = reqsk_queue_alloc(&tp->accept_queue, TCP_SYNQ_HSIZE);
-
-       if (rc != 0)
-               return rc;
-
-       sk->sk_max_ack_backlog = 0;
-       sk->sk_ack_backlog = 0;
-       tcp_delack_init(tp);
-
-       /* There is race window here: we announce ourselves listening,
-        * but this transition is still not validated by get_port().
-        * It is OK, because this socket enters to hash table only
-        * after validation is complete.
-        */
-       sk->sk_state = TCP_LISTEN;
-       if (!sk->sk_prot->get_port(sk, inet->num)) {
-               inet->sport = htons(inet->num);
-
-               sk_dst_reset(sk);
-               sk->sk_prot->hash(sk);
-
-               return 0;
-       }
-
-       sk->sk_state = TCP_CLOSE;
-       reqsk_queue_destroy(&tp->accept_queue);
-       return -EADDRINUSE;
-}
-
-/*
- *     This routine closes sockets which have been at least partially
- *     opened, but not yet accepted.
- */
-
-static void tcp_listen_stop (struct sock *sk)
-{
-       struct tcp_sock *tp = tcp_sk(sk);
-       struct listen_sock *lopt;
-       struct request_sock *acc_req;
-       struct request_sock *req;
-       int i;
-
-       tcp_delete_keepalive_timer(sk);
-
-       /* make all the listen_opt local to us */
-       lopt = reqsk_queue_yank_listen_sk(&tp->accept_queue);
-       acc_req = reqsk_queue_yank_acceptq(&tp->accept_queue);
-
-       if (lopt->qlen) {
-               for (i = 0; i < TCP_SYNQ_HSIZE; i++) {
-                       while ((req = lopt->syn_table[i]) != NULL) {
-                               lopt->syn_table[i] = req->dl_next;
-                               lopt->qlen--;
-                               reqsk_free(req);
-
-               /* Following specs, it would be better either to send FIN
-                * (and enter FIN-WAIT-1, it is normal close)
-                * or to send active reset (abort).
-                * Certainly, it is pretty dangerous while synflood, but it is
-                * bad justification for our negligence 8)
-                * To be honest, we are not able to make either
-                * of the variants now.                 --ANK
-                */
-                       }
-               }
-       }
-       BUG_TRAP(!lopt->qlen);
-
-       kfree(lopt);
-
-       while ((req = acc_req) != NULL) {
-               struct sock *child = req->sk;
-
-               acc_req = req->dl_next;
-
-               local_bh_disable();
-               bh_lock_sock(child);
-               BUG_TRAP(!sock_owned_by_user(child));
-               sock_hold(child);
-
-               tcp_disconnect(child, O_NONBLOCK);
-
-               sock_orphan(child);
-
-               atomic_inc(&tcp_orphan_count);
-
-               tcp_destroy_sock(child);
-
-               bh_unlock_sock(child);
-               local_bh_enable();
-               sock_put(child);
-
-               sk_acceptq_removed(sk);
-               __reqsk_free(req);
-       }
-       BUG_TRAP(!sk->sk_ack_backlog);
-}
-
 static inline void tcp_mark_push(struct tcp_sock *tp, struct sk_buff *skb)
 {
        TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
@@ -665,8 +552,7 @@ new_segment:
                        tcp_mark_push(tp, skb);
                        goto new_segment;
                }
-               if (sk->sk_forward_alloc < copy &&
-                   !sk_stream_mem_schedule(sk, copy, 0))
+               if (!sk_stream_wmem_schedule(sk, copy))
                        goto wait_for_memory;
                
                if (can_coalesce) {
@@ -883,19 +769,23 @@ new_segment:
                                        if (off == PAGE_SIZE) {
                                                put_page(page);
                                                TCP_PAGE(sk) = page = NULL;
+                                               off = 0;
                                        }
-                               }
+                               } else
+                                       off = 0;
+
+                               if (copy > PAGE_SIZE - off)
+                                       copy = PAGE_SIZE - off;
+
+                               if (!sk_stream_wmem_schedule(sk, copy))
+                                       goto wait_for_memory;
 
                                if (!page) {
                                        /* Allocate new cache page. */
                                        if (!(page = sk_stream_alloc_page(sk)))
                                                goto wait_for_memory;
-                                       off = 0;
                                }
 
-                               if (copy > PAGE_SIZE - off)
-                                       copy = PAGE_SIZE - off;
-
                                /* Time to copy data. We are close to
                                 * the end! */
                                err = skb_copy_to_page(sk, from, skb, page,
@@ -975,7 +865,7 @@ do_fault:
        if (!skb->len) {
                if (sk->sk_send_head == skb)
                        sk->sk_send_head = NULL;
-               __skb_unlink(skb, skb->list);
+               __skb_unlink(skb, &sk->sk_write_queue);
                sk_stream_free_skb(sk, skb);
        }
 
@@ -1057,20 +947,21 @@ static void cleanup_rbuf(struct sock *sk, int copied)
        BUG_TRAP(!skb || before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq));
 #endif
 
-       if (tcp_ack_scheduled(tp)) {
+       if (inet_csk_ack_scheduled(sk)) {
+               const struct inet_connection_sock *icsk = inet_csk(sk);
                   /* Delayed ACKs frequently hit locked sockets during bulk
                    * receive. */
-               if (tp->ack.blocked ||
+               if (icsk->icsk_ack.blocked ||
                    /* Once-per-two-segments ACK was not sent by tcp_input.c */
-                   tp->rcv_nxt - tp->rcv_wup > tp->ack.rcv_mss ||
+                   tp->rcv_nxt - tp->rcv_wup > icsk->icsk_ack.rcv_mss ||
                    /*
                     * If this read emptied read buffer, we send ACK, if
                     * connection is not bidirectional, user drained
                     * receive buffer and there was a small segment
                     * in queue.
                     */
-                   (copied > 0 && (tp->ack.pending & TCP_ACK_PUSHED) &&
-                    !tp->ack.pingpong && !atomic_read(&sk->sk_rmem_alloc)))
+                   (copied > 0 && (icsk->icsk_ack.pending & ICSK_ACK_PUSHED) &&
+                    !icsk->icsk_ack.pingpong && !atomic_read(&sk->sk_rmem_alloc)))
                        time_to_ack = 1;
        }
 
@@ -1572,40 +1463,6 @@ void tcp_shutdown(struct sock *sk, int how)
        }
 }
 
-/*
- * At this point, there should be no process reference to this
- * socket, and thus no user references at all.  Therefore we
- * can assume the socket waitqueue is inactive and nobody will
- * try to jump onto it.
- */
-void tcp_destroy_sock(struct sock *sk)
-{
-       BUG_TRAP(sk->sk_state == TCP_CLOSE);
-       BUG_TRAP(sock_flag(sk, SOCK_DEAD));
-
-       /* It cannot be in hash table! */
-       BUG_TRAP(sk_unhashed(sk));
-
-       /* If it has not 0 inet_sk(sk)->num, it must be bound */
-       BUG_TRAP(!inet_sk(sk)->num || tcp_sk(sk)->bind_hash);
-
-       sk->sk_prot->destroy(sk);
-
-       sk_stream_kill_queues(sk);
-
-       xfrm_sk_free_policy(sk);
-
-#ifdef INET_REFCNT_DEBUG
-       if (atomic_read(&sk->sk_refcnt) != 1) {
-               printk(KERN_DEBUG "Destruction TCP %p delayed, c=%d\n",
-                      sk, atomic_read(&sk->sk_refcnt));
-       }
-#endif
-
-       atomic_dec(&tcp_orphan_count);
-       sock_put(sk);
-}
-
 void tcp_close(struct sock *sk, long timeout)
 {
        struct sk_buff *skb;
@@ -1618,7 +1475,7 @@ void tcp_close(struct sock *sk, long timeout)
                tcp_set_state(sk, TCP_CLOSE);
 
                /* Special case. */
-               tcp_listen_stop(sk);
+               inet_csk_listen_stop(sk);
 
                goto adjudge_to_death;
        }
@@ -1721,12 +1578,12 @@ adjudge_to_death:
                        tcp_send_active_reset(sk, GFP_ATOMIC);
                        NET_INC_STATS_BH(LINUX_MIB_TCPABORTONLINGER);
                } else {
-                       int tmo = tcp_fin_time(tp);
+                       const int tmo = tcp_fin_time(sk);
 
                        if (tmo > TCP_TIMEWAIT_LEN) {
-                               tcp_reset_keepalive_timer(sk, tcp_fin_time(tp));
+                               inet_csk_reset_keepalive_timer(sk, tcp_fin_time(sk));
                        } else {
-                               atomic_inc(&tcp_orphan_count);
+                               atomic_inc(sk->sk_prot->orphan_count);
                                tcp_time_wait(sk, TCP_FIN_WAIT2, tmo);
                                goto out;
                        }
@@ -1734,7 +1591,7 @@ adjudge_to_death:
        }
        if (sk->sk_state != TCP_CLOSE) {
                sk_stream_mem_reclaim(sk);
-               if (atomic_read(&tcp_orphan_count) > sysctl_tcp_max_orphans ||
+               if (atomic_read(sk->sk_prot->orphan_count) > sysctl_tcp_max_orphans ||
                    (sk->sk_wmem_queued > SOCK_MIN_SNDBUF &&
                     atomic_read(&tcp_memory_allocated) > sysctl_tcp_mem[2])) {
                        if (net_ratelimit())
@@ -1745,10 +1602,10 @@ adjudge_to_death:
                        NET_INC_STATS_BH(LINUX_MIB_TCPABORTONMEMORY);
                }
        }
-       atomic_inc(&tcp_orphan_count);
+       atomic_inc(sk->sk_prot->orphan_count);
 
        if (sk->sk_state == TCP_CLOSE)
-               tcp_destroy_sock(sk);
+               inet_csk_destroy_sock(sk);
        /* Otherwise, socket is reprieved until protocol close. */
 
 out:
@@ -1769,6 +1626,7 @@ static inline int tcp_need_reset(int state)
 int tcp_disconnect(struct sock *sk, int flags)
 {
        struct inet_sock *inet = inet_sk(sk);
+       struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        int err = 0;
        int old_state = sk->sk_state;
@@ -1778,7 +1636,7 @@ int tcp_disconnect(struct sock *sk, int flags)
 
        /* ABORT function of RFC793 */
        if (old_state == TCP_LISTEN) {
-               tcp_listen_stop(sk);
+               inet_csk_listen_stop(sk);
        } else if (tcp_need_reset(old_state) ||
                   (tp->snd_nxt != tp->write_seq &&
                    (1 << old_state) & (TCPF_CLOSING | TCPF_LAST_ACK))) {
@@ -1805,118 +1663,26 @@ int tcp_disconnect(struct sock *sk, int flags)
        tp->srtt = 0;
        if ((tp->write_seq += tp->max_window + 2) == 0)
                tp->write_seq = 1;
-       tp->backoff = 0;
+       icsk->icsk_backoff = 0;
        tp->snd_cwnd = 2;
-       tp->probes_out = 0;
+       icsk->icsk_probes_out = 0;
        tp->packets_out = 0;
        tp->snd_ssthresh = 0x7fffffff;
        tp->snd_cwnd_cnt = 0;
-       tcp_set_ca_state(tp, TCP_CA_Open);
+       tcp_set_ca_state(sk, TCP_CA_Open);
        tcp_clear_retrans(tp);
-       tcp_delack_init(tp);
+       inet_csk_delack_init(sk);
        sk->sk_send_head = NULL;
        tp->rx_opt.saw_tstamp = 0;
        tcp_sack_reset(&tp->rx_opt);
        __sk_dst_reset(sk);
 
-       BUG_TRAP(!inet->num || tp->bind_hash);
+       BUG_TRAP(!inet->num || icsk->icsk_bind_hash);
 
        sk->sk_error_report(sk);
        return err;
 }
 
-/*
- *     Wait for an incoming connection, avoid race
- *     conditions. This must be called with the socket locked.
- */
-static int wait_for_connect(struct sock *sk, long timeo)
-{
-       struct tcp_sock *tp = tcp_sk(sk);
-       DEFINE_WAIT(wait);
-       int err;
-
-       /*
-        * True wake-one mechanism for incoming connections: only
-        * one process gets woken up, not the 'whole herd'.
-        * Since we do not 'race & poll' for established sockets
-        * anymore, the common case will execute the loop only once.
-        *
-        * Subtle issue: "add_wait_queue_exclusive()" will be added
-        * after any current non-exclusive waiters, and we know that
-        * it will always _stay_ after any new non-exclusive waiters
-        * because all non-exclusive waiters are added at the
-        * beginning of the wait-queue. As such, it's ok to "drop"
-        * our exclusiveness temporarily when we get woken up without
-        * having to remove and re-insert us on the wait queue.
-        */
-       for (;;) {
-               prepare_to_wait_exclusive(sk->sk_sleep, &wait,
-                                         TASK_INTERRUPTIBLE);
-               release_sock(sk);
-               if (reqsk_queue_empty(&tp->accept_queue))
-                       timeo = schedule_timeout(timeo);
-               lock_sock(sk);
-               err = 0;
-               if (!reqsk_queue_empty(&tp->accept_queue))
-                       break;
-               err = -EINVAL;
-               if (sk->sk_state != TCP_LISTEN)
-                       break;
-               err = sock_intr_errno(timeo);
-               if (signal_pending(current))
-                       break;
-               err = -EAGAIN;
-               if (!timeo)
-                       break;
-       }
-       finish_wait(sk->sk_sleep, &wait);
-       return err;
-}
-
-/*
- *     This will accept the next outstanding connection.
- */
-
-struct sock *tcp_accept(struct sock *sk, int flags, int *err)
-{
-       struct tcp_sock *tp = tcp_sk(sk);
-       struct sock *newsk;
-       int error;
-
-       lock_sock(sk);
-
-       /* We need to make sure that this socket is listening,
-        * and that it has something pending.
-        */
-       error = -EINVAL;
-       if (sk->sk_state != TCP_LISTEN)
-               goto out_err;
-
-       /* Find already established connection */
-       if (reqsk_queue_empty(&tp->accept_queue)) {
-               long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
-
-               /* If this is a non blocking socket don't sleep */
-               error = -EAGAIN;
-               if (!timeo)
-                       goto out_err;
-
-               error = wait_for_connect(sk, timeo);
-               if (error)
-                       goto out_err;
-       }
-
-       newsk = reqsk_queue_get_child(&tp->accept_queue, sk);
-       BUG_TRAP(newsk->sk_state != TCP_SYN_RECV);
-out:
-       release_sock(sk);
-       return newsk;
-out_err:
-       newsk = NULL;
-       *err = error;
-       goto out;
-}
-
 /*
  *     Socket option code for TCP.
  */
@@ -1924,6 +1690,7 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
                   int optlen)
 {
        struct tcp_sock *tp = tcp_sk(sk);
+       struct inet_connection_sock *icsk = inet_csk(sk);
        int val;
        int err = 0;
 
@@ -1945,7 +1712,7 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
                name[val] = 0;
 
                lock_sock(sk);
-               err = tcp_set_congestion_control(tp, name);
+               err = tcp_set_congestion_control(sk, name);
                release_sock(sk);
                return err;
        }
@@ -2022,7 +1789,7 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
                                        elapsed = tp->keepalive_time - elapsed;
                                else
                                        elapsed = 0;
-                               tcp_reset_keepalive_timer(sk, elapsed);
+                               inet_csk_reset_keepalive_timer(sk, elapsed);
                        }
                }
                break;
@@ -2042,7 +1809,7 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
                if (val < 1 || val > MAX_TCP_SYNCNT)
                        err = -EINVAL;
                else
-                       tp->syn_retries = val;
+                       icsk->icsk_syn_retries = val;
                break;
 
        case TCP_LINGER2:
@@ -2055,15 +1822,15 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
                break;
 
        case TCP_DEFER_ACCEPT:
-               tp->defer_accept = 0;
+               icsk->icsk_accept_queue.rskq_defer_accept = 0;
                if (val > 0) {
                        /* Translate value in seconds to number of
                         * retransmits */
-                       while (tp->defer_accept < 32 &&
+                       while (icsk->icsk_accept_queue.rskq_defer_accept < 32 &&
                               val > ((TCP_TIMEOUT_INIT / HZ) <<
-                                      tp->defer_accept))
-                               tp->defer_accept++;
-                       tp->defer_accept++;
+                                      icsk->icsk_accept_queue.rskq_defer_accept))
+                               icsk->icsk_accept_queue.rskq_defer_accept++;
+                       icsk->icsk_accept_queue.rskq_defer_accept++;
                }
                break;
 
@@ -2081,16 +1848,16 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
 
        case TCP_QUICKACK:
                if (!val) {
-                       tp->ack.pingpong = 1;
+                       icsk->icsk_ack.pingpong = 1;
                } else {
-                       tp->ack.pingpong = 0;
+                       icsk->icsk_ack.pingpong = 0;
                        if ((1 << sk->sk_state) &
                            (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT) &&
-                           tcp_ack_scheduled(tp)) {
-                               tp->ack.pending |= TCP_ACK_PUSHED;
+                           inet_csk_ack_scheduled(sk)) {
+                               icsk->icsk_ack.pending |= ICSK_ACK_PUSHED;
                                cleanup_rbuf(sk, 1);
                                if (!(val & 1))
-                                       tp->ack.pingpong = 1;
+                                       icsk->icsk_ack.pingpong = 1;
                        }
                }
                break;
@@ -2107,15 +1874,16 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
 void tcp_get_info(struct sock *sk, struct tcp_info *info)
 {
        struct tcp_sock *tp = tcp_sk(sk);
+       const struct inet_connection_sock *icsk = inet_csk(sk);
        u32 now = tcp_time_stamp;
 
        memset(info, 0, sizeof(*info));
 
        info->tcpi_state = sk->sk_state;
-       info->tcpi_ca_state = tp->ca_state;
-       info->tcpi_retransmits = tp->retransmits;
-       info->tcpi_probes = tp->probes_out;
-       info->tcpi_backoff = tp->backoff;
+       info->tcpi_ca_state = icsk->icsk_ca_state;
+       info->tcpi_retransmits = icsk->icsk_retransmits;
+       info->tcpi_probes = icsk->icsk_probes_out;
+       info->tcpi_backoff = icsk->icsk_backoff;
 
        if (tp->rx_opt.tstamp_ok)
                info->tcpi_options |= TCPI_OPT_TIMESTAMPS;
@@ -2130,10 +1898,10 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
        if (tp->ecn_flags&TCP_ECN_OK)
                info->tcpi_options |= TCPI_OPT_ECN;
 
-       info->tcpi_rto = jiffies_to_usecs(tp->rto);
-       info->tcpi_ato = jiffies_to_usecs(tp->ack.ato);
+       info->tcpi_rto = jiffies_to_usecs(icsk->icsk_rto);
+       info->tcpi_ato = jiffies_to_usecs(icsk->icsk_ack.ato);
        info->tcpi_snd_mss = tp->mss_cache;
-       info->tcpi_rcv_mss = tp->ack.rcv_mss;
+       info->tcpi_rcv_mss = icsk->icsk_ack.rcv_mss;
 
        info->tcpi_unacked = tp->packets_out;
        info->tcpi_sacked = tp->sacked_out;
@@ -2142,7 +1910,7 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
        info->tcpi_fackets = tp->fackets_out;
 
        info->tcpi_last_data_sent = jiffies_to_msecs(now - tp->lsndtime);
-       info->tcpi_last_data_recv = jiffies_to_msecs(now - tp->ack.lrcvtime);
+       info->tcpi_last_data_recv = jiffies_to_msecs(now - icsk->icsk_ack.lrcvtime);
        info->tcpi_last_ack_recv = jiffies_to_msecs(now - tp->rcv_tstamp);
 
        info->tcpi_pmtu = tp->pmtu_cookie;
@@ -2165,6 +1933,7 @@ EXPORT_SYMBOL_GPL(tcp_get_info);
 int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
                   int __user *optlen)
 {
+       struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        int val, len;
 
@@ -2202,7 +1971,7 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
                val = tp->keepalive_probes ? : sysctl_tcp_keepalive_probes;
                break;
        case TCP_SYNCNT:
-               val = tp->syn_retries ? : sysctl_tcp_syn_retries;
+               val = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries;
                break;
        case TCP_LINGER2:
                val = tp->linger2;
@@ -2210,8 +1979,8 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
                        val = (val ? : sysctl_tcp_fin_timeout) / HZ;
                break;
        case TCP_DEFER_ACCEPT:
-               val = !tp->defer_accept ? 0 : ((TCP_TIMEOUT_INIT / HZ) <<
-                                              (tp->defer_accept - 1));
+               val = !icsk->icsk_accept_queue.rskq_defer_accept ? 0 :
+                       ((TCP_TIMEOUT_INIT / HZ) << (icsk->icsk_accept_queue.rskq_defer_accept - 1));
                break;
        case TCP_WINDOW_CLAMP:
                val = tp->window_clamp;
@@ -2232,7 +2001,7 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
                return 0;
        }
        case TCP_QUICKACK:
-               val = !tp->ack.pingpong;
+               val = !icsk->icsk_ack.pingpong;
                break;
 
        case TCP_CONGESTION:
@@ -2241,7 +2010,7 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
                len = min_t(unsigned int, len, TCP_CA_NAME_MAX);
                if (put_user(len, optlen))
                        return -EFAULT;
-               if (copy_to_user(optval, tp->ca_ops->name, len))
+               if (copy_to_user(optval, icsk->icsk_ca_ops->name, len))
                        return -EFAULT;
                return 0;
        default:
@@ -2278,79 +2047,72 @@ void __init tcp_init(void)
                __skb_cb_too_small_for_tcp(sizeof(struct tcp_skb_cb),
                                           sizeof(skb->cb));
 
-       tcp_bucket_cachep = kmem_cache_create("tcp_bind_bucket",
-                                             sizeof(struct tcp_bind_bucket),
-                                             0, SLAB_HWCACHE_ALIGN,
-                                             NULL, NULL);
-       if (!tcp_bucket_cachep)
+       tcp_hashinfo.bind_bucket_cachep =
+               kmem_cache_create("tcp_bind_bucket",
+                                 sizeof(struct inet_bind_bucket), 0,
+                                 SLAB_HWCACHE_ALIGN, NULL, NULL);
+       if (!tcp_hashinfo.bind_bucket_cachep)
                panic("tcp_init: Cannot alloc tcp_bind_bucket cache.");
 
-       tcp_timewait_cachep = kmem_cache_create("tcp_tw_bucket",
-                                               sizeof(struct tcp_tw_bucket),
-                                               0, SLAB_HWCACHE_ALIGN,
-                                               NULL, NULL);
-       if (!tcp_timewait_cachep)
-               panic("tcp_init: Cannot alloc tcp_tw_bucket cache.");
-
        /* Size and allocate the main established and bind bucket
         * hash tables.
         *
         * The methodology is similar to that of the buffer cache.
         */
-       tcp_ehash = (struct tcp_ehash_bucket *)
+       tcp_hashinfo.ehash =
                alloc_large_system_hash("TCP established",
-                                       sizeof(struct tcp_ehash_bucket),
+                                       sizeof(struct inet_ehash_bucket),
                                        thash_entries,
                                        (num_physpages >= 128 * 1024) ?
                                                (25 - PAGE_SHIFT) :
                                                (27 - PAGE_SHIFT),
                                        HASH_HIGHMEM,
-                                       &tcp_ehash_size,
+                                       &tcp_hashinfo.ehash_size,
                                        NULL,
                                        0);
-       tcp_ehash_size = (1 << tcp_ehash_size) >> 1;
-       for (i = 0; i < (tcp_ehash_size << 1); i++) {
-               rwlock_init(&tcp_ehash[i].lock);
-               INIT_HLIST_HEAD(&tcp_ehash[i].chain);
+       tcp_hashinfo.ehash_size = (1 << tcp_hashinfo.ehash_size) >> 1;
+       for (i = 0; i < (tcp_hashinfo.ehash_size << 1); i++) {
+               rwlock_init(&tcp_hashinfo.ehash[i].lock);
+               INIT_HLIST_HEAD(&tcp_hashinfo.ehash[i].chain);
        }
 
-       tcp_bhash = (struct tcp_bind_hashbucket *)
+       tcp_hashinfo.bhash =
                alloc_large_system_hash("TCP bind",
-                                       sizeof(struct tcp_bind_hashbucket),
-                                       tcp_ehash_size,
+                                       sizeof(struct inet_bind_hashbucket),
+                                       tcp_hashinfo.ehash_size,
                                        (num_physpages >= 128 * 1024) ?
                                                (25 - PAGE_SHIFT) :
                                                (27 - PAGE_SHIFT),
                                        HASH_HIGHMEM,
-                                       &tcp_bhash_size,
+                                       &tcp_hashinfo.bhash_size,
                                        NULL,
                                        64 * 1024);
-       tcp_bhash_size = 1 << tcp_bhash_size;
-       for (i = 0; i < tcp_bhash_size; i++) {
-               spin_lock_init(&tcp_bhash[i].lock);
-               INIT_HLIST_HEAD(&tcp_bhash[i].chain);
+       tcp_hashinfo.bhash_size = 1 << tcp_hashinfo.bhash_size;
+       for (i = 0; i < tcp_hashinfo.bhash_size; i++) {
+               spin_lock_init(&tcp_hashinfo.bhash[i].lock);
+               INIT_HLIST_HEAD(&tcp_hashinfo.bhash[i].chain);
        }
 
        /* Try to be a bit smarter and adjust defaults depending
         * on available memory.
         */
        for (order = 0; ((1 << order) << PAGE_SHIFT) <
-                       (tcp_bhash_size * sizeof(struct tcp_bind_hashbucket));
+                       (tcp_hashinfo.bhash_size * sizeof(struct inet_bind_hashbucket));
                        order++)
                ;
        if (order >= 4) {
                sysctl_local_port_range[0] = 32768;
                sysctl_local_port_range[1] = 61000;
-               sysctl_tcp_max_tw_buckets = 180000;
+               tcp_death_row.sysctl_max_tw_buckets = 180000;
                sysctl_tcp_max_orphans = 4096 << (order - 4);
                sysctl_max_syn_backlog = 1024;
        } else if (order < 3) {
                sysctl_local_port_range[0] = 1024 * (3 - order);
-               sysctl_tcp_max_tw_buckets >>= (3 - order);
+               tcp_death_row.sysctl_max_tw_buckets >>= (3 - order);
                sysctl_tcp_max_orphans >>= (3 - order);
                sysctl_max_syn_backlog = 128;
        }
-       tcp_port_rover = sysctl_local_port_range[0] - 1;
+       tcp_hashinfo.port_rover = sysctl_local_port_range[0] - 1;
 
        sysctl_tcp_mem[0] =  768 << order;
        sysctl_tcp_mem[1] = 1024 << order;
@@ -2365,14 +2127,12 @@ void __init tcp_init(void)
 
        printk(KERN_INFO "TCP: Hash tables configured "
               "(established %d bind %d)\n",
-              tcp_ehash_size << 1, tcp_bhash_size);
+              tcp_hashinfo.ehash_size << 1, tcp_hashinfo.bhash_size);
 
        tcp_register_congestion_control(&tcp_reno);
 }
 
-EXPORT_SYMBOL(tcp_accept);
 EXPORT_SYMBOL(tcp_close);
-EXPORT_SYMBOL(tcp_destroy_sock);
 EXPORT_SYMBOL(tcp_disconnect);
 EXPORT_SYMBOL(tcp_getsockopt);
 EXPORT_SYMBOL(tcp_ioctl);
@@ -2384,4 +2144,3 @@ EXPORT_SYMBOL(tcp_sendpage);
 EXPORT_SYMBOL(tcp_setsockopt);
 EXPORT_SYMBOL(tcp_shutdown);
 EXPORT_SYMBOL(tcp_statistics);
-EXPORT_SYMBOL(tcp_timewait_cachep);
index ec38d45d6649633178c8d541a34499349443c8a4..b940346de4e7cbc5bc724245992c07f6c0e41120 100644 (file)
@@ -86,11 +86,11 @@ static inline void bictcp_reset(struct bictcp *ca)
        ca->delayed_ack = 2 << ACK_RATIO_SHIFT;
 }
 
-static void bictcp_init(struct tcp_sock *tp)
+static void bictcp_init(struct sock *sk)
 {
-       bictcp_reset(tcp_ca(tp));
+       bictcp_reset(inet_csk_ca(sk));
        if (initial_ssthresh)
-               tp->snd_ssthresh = initial_ssthresh;
+               tcp_sk(sk)->snd_ssthresh = initial_ssthresh;
 }
 
 /*
@@ -156,9 +156,10 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
 
 
 /* Detect low utilization in congestion avoidance */
-static inline void bictcp_low_utilization(struct tcp_sock *tp, int flag)
+static inline void bictcp_low_utilization(struct sock *sk, int flag)
 {
-       struct bictcp *ca = tcp_ca(tp);
+       const struct tcp_sock *tp = tcp_sk(sk);
+       struct bictcp *ca = inet_csk_ca(sk);
        u32 dist, delay;
 
        /* No time stamp */
@@ -208,12 +209,13 @@ static inline void bictcp_low_utilization(struct tcp_sock *tp, int flag)
 
 }
 
-static void bictcp_cong_avoid(struct tcp_sock *tp, u32 ack,
+static void bictcp_cong_avoid(struct sock *sk, u32 ack,
                              u32 seq_rtt, u32 in_flight, int data_acked)
 {
-       struct bictcp *ca = tcp_ca(tp);
+       struct tcp_sock *tp = tcp_sk(sk);
+       struct bictcp *ca = inet_csk_ca(sk);
 
-       bictcp_low_utilization(tp, data_acked);
+       bictcp_low_utilization(sk, data_acked);
 
        if (in_flight < tp->snd_cwnd)
                return;
@@ -242,9 +244,10 @@ static void bictcp_cong_avoid(struct tcp_sock *tp, u32 ack,
  *     behave like Reno until low_window is reached,
  *     then increase congestion window slowly
  */
-static u32 bictcp_recalc_ssthresh(struct tcp_sock *tp)
+static u32 bictcp_recalc_ssthresh(struct sock *sk)
 {
-       struct bictcp *ca = tcp_ca(tp);
+       const struct tcp_sock *tp = tcp_sk(sk);
+       struct bictcp *ca = inet_csk_ca(sk);
 
        ca->epoch_start = 0;    /* end of epoch */
 
@@ -269,31 +272,34 @@ static u32 bictcp_recalc_ssthresh(struct tcp_sock *tp)
                return max((tp->snd_cwnd * beta) / BICTCP_BETA_SCALE, 2U);
 }
 
-static u32 bictcp_undo_cwnd(struct tcp_sock *tp)
+static u32 bictcp_undo_cwnd(struct sock *sk)
 {
-       struct bictcp *ca = tcp_ca(tp);
-
+       const struct tcp_sock *tp = tcp_sk(sk);
+       const struct bictcp *ca = inet_csk_ca(sk);
        return max(tp->snd_cwnd, ca->last_max_cwnd);
 }
 
-static u32 bictcp_min_cwnd(struct tcp_sock *tp)
+static u32 bictcp_min_cwnd(struct sock *sk)
 {
+       const struct tcp_sock *tp = tcp_sk(sk);
        return tp->snd_ssthresh;
 }
 
-static void bictcp_state(struct tcp_sock *tp, u8 new_state)
+static void bictcp_state(struct sock *sk, u8 new_state)
 {
        if (new_state == TCP_CA_Loss)
-               bictcp_reset(tcp_ca(tp));
+               bictcp_reset(inet_csk_ca(sk));
 }
 
 /* Track delayed acknowledgement ratio using sliding window
  * ratio = (15*ratio + sample) / 16
  */
-static void bictcp_acked(struct tcp_sock *tp, u32 cnt)
+static void bictcp_acked(struct sock *sk, u32 cnt)
 {
-       if (cnt > 0 &&  tp->ca_state == TCP_CA_Open) {
-               struct bictcp *ca = tcp_ca(tp);
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+
+       if (cnt > 0 &&  icsk->icsk_ca_state == TCP_CA_Open) {
+               struct bictcp *ca = inet_csk_ca(sk);
                cnt -= ca->delayed_ack >> ACK_RATIO_SHIFT;
                ca->delayed_ack += cnt;
        }
@@ -314,7 +320,7 @@ static struct tcp_congestion_ops bictcp = {
 
 static int __init bictcp_register(void)
 {
-       BUG_ON(sizeof(struct bictcp) > TCP_CA_PRIV_SIZE);
+       BUG_ON(sizeof(struct bictcp) > ICSK_CA_PRIV_SIZE);
        return tcp_register_congestion_control(&bictcp);
 }
 
index 4970d10a7785af03276c22a29f03e8f7c90c14e9..bbf2d6624e894b927a169d92ae2be882c851b91a 100644 (file)
@@ -73,33 +73,36 @@ void tcp_unregister_congestion_control(struct tcp_congestion_ops *ca)
 EXPORT_SYMBOL_GPL(tcp_unregister_congestion_control);
 
 /* Assign choice of congestion control. */
-void tcp_init_congestion_control(struct tcp_sock *tp)
+void tcp_init_congestion_control(struct sock *sk)
 {
+       struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_congestion_ops *ca;
 
-       if (tp->ca_ops != &tcp_init_congestion_ops)
+       if (icsk->icsk_ca_ops != &tcp_init_congestion_ops)
                return;
 
        rcu_read_lock();
        list_for_each_entry_rcu(ca, &tcp_cong_list, list) {
                if (try_module_get(ca->owner)) {
-                       tp->ca_ops = ca;
+                       icsk->icsk_ca_ops = ca;
                        break;
                }
 
        }
        rcu_read_unlock();
 
-       if (tp->ca_ops->init)
-               tp->ca_ops->init(tp);
+       if (icsk->icsk_ca_ops->init)
+               icsk->icsk_ca_ops->init(sk);
 }
 
 /* Manage refcounts on socket close. */
-void tcp_cleanup_congestion_control(struct tcp_sock *tp)
+void tcp_cleanup_congestion_control(struct sock *sk)
 {
-       if (tp->ca_ops->release)
-               tp->ca_ops->release(tp);
-       module_put(tp->ca_ops->owner);
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       if (icsk->icsk_ca_ops->release)
+               icsk->icsk_ca_ops->release(sk);
+       module_put(icsk->icsk_ca_ops->owner);
 }
 
 /* Used by sysctl to change default congestion control */
@@ -143,14 +146,15 @@ void tcp_get_default_congestion_control(char *name)
 }
 
 /* Change congestion control for socket */
-int tcp_set_congestion_control(struct tcp_sock *tp, const char *name)
+int tcp_set_congestion_control(struct sock *sk, const char *name)
 {
+       struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_congestion_ops *ca;
        int err = 0;
 
        rcu_read_lock();
        ca = tcp_ca_find(name);
-       if (ca == tp->ca_ops)
+       if (ca == icsk->icsk_ca_ops)
                goto out;
 
        if (!ca)
@@ -160,10 +164,10 @@ int tcp_set_congestion_control(struct tcp_sock *tp, const char *name)
                err = -EBUSY;
 
        else {
-               tcp_cleanup_congestion_control(tp);
-               tp->ca_ops = ca;
-               if (tp->ca_ops->init)
-                       tp->ca_ops->init(tp);
+               tcp_cleanup_congestion_control(sk);
+               icsk->icsk_ca_ops = ca;
+               if (icsk->icsk_ca_ops->init)
+                       icsk->icsk_ca_ops->init(sk);
        }
  out:
        rcu_read_unlock();
@@ -177,9 +181,11 @@ int tcp_set_congestion_control(struct tcp_sock *tp, const char *name)
 /* This is Jacobson's slow start and congestion avoidance.
  * SIGCOMM '88, p. 328.
  */
-void tcp_reno_cong_avoid(struct tcp_sock *tp, u32 ack, u32 rtt, u32 in_flight,
+void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 rtt, u32 in_flight,
                         int flag)
 {
+       struct tcp_sock *tp = tcp_sk(sk);
+
        if (in_flight < tp->snd_cwnd)
                return;
 
@@ -202,15 +208,17 @@ void tcp_reno_cong_avoid(struct tcp_sock *tp, u32 ack, u32 rtt, u32 in_flight,
 EXPORT_SYMBOL_GPL(tcp_reno_cong_avoid);
 
 /* Slow start threshold is half the congestion window (min 2) */
-u32 tcp_reno_ssthresh(struct tcp_sock *tp)
+u32 tcp_reno_ssthresh(struct sock *sk)
 {
+       const struct tcp_sock *tp = tcp_sk(sk);
        return max(tp->snd_cwnd >> 1U, 2U);
 }
 EXPORT_SYMBOL_GPL(tcp_reno_ssthresh);
 
 /* Lower bound on congestion window. */
-u32 tcp_reno_min_cwnd(struct tcp_sock *tp)
+u32 tcp_reno_min_cwnd(struct sock *sk)
 {
+       const struct tcp_sock *tp = tcp_sk(sk);
        return tp->snd_ssthresh/2;
 }
 EXPORT_SYMBOL_GPL(tcp_reno_min_cwnd);
index f66945cb158fd346c0b2f87d0dec068620b7a838..c148c1081880a03aa1a7f24a692cb439f7ee3d70 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * tcp_diag.c  Module for monitoring TCP sockets.
+ * tcp_diag.c  Module for monitoring TCP transport protocols sockets.
  *
  * Version:    $Id: tcp_diag.c,v 1.3 2002/02/01 22:01:04 davem Exp $
  *
  */
 
 #include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/random.h>
-#include <linux/cache.h>
-#include <linux/init.h>
-#include <linux/time.h>
-
-#include <net/icmp.h>
-#include <net/tcp.h>
-#include <net/ipv6.h>
-#include <net/inet_common.h>
-
-#include <linux/inet.h>
-#include <linux/stddef.h>
-
-#include <linux/tcp_diag.h>
 
-struct tcpdiag_entry
-{
-       u32 *saddr;
-       u32 *daddr;
-       u16 sport;
-       u16 dport;
-       u16 family;
-       u16 userlocks;
-};
+#include <linux/module.h>
+#include <linux/inet_diag.h>
 
-static struct sock *tcpnl;
+#include <linux/tcp.h>
 
-#define TCPDIAG_PUT(skb, attrtype, attrlen) \
-       RTA_DATA(__RTA_PUT(skb, attrtype, attrlen))
+#include <net/tcp.h>
 
-static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
-                       int ext, u32 pid, u32 seq, u16 nlmsg_flags)
+static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
+                             void *_info)
 {
-       struct inet_sock *inet = inet_sk(sk);
-       struct tcp_sock *tp = tcp_sk(sk);
-       struct tcpdiagmsg *r;
-       struct nlmsghdr  *nlh;
-       struct tcp_info  *info = NULL;
-       struct tcpdiag_meminfo  *minfo = NULL;
-       unsigned char    *b = skb->tail;
-
-       nlh = NLMSG_PUT(skb, pid, seq, TCPDIAG_GETSOCK, sizeof(*r));
-       nlh->nlmsg_flags = nlmsg_flags;
-       r = NLMSG_DATA(nlh);
-       if (sk->sk_state != TCP_TIME_WAIT) {
-               if (ext & (1<<(TCPDIAG_MEMINFO-1)))
-                       minfo = TCPDIAG_PUT(skb, TCPDIAG_MEMINFO, sizeof(*minfo));
-               if (ext & (1<<(TCPDIAG_INFO-1)))
-                       info = TCPDIAG_PUT(skb, TCPDIAG_INFO, sizeof(*info));
-               
-               if (ext & (1<<(TCPDIAG_CONG-1))) {
-                       size_t len = strlen(tp->ca_ops->name);
-                       strcpy(TCPDIAG_PUT(skb, TCPDIAG_CONG, len+1),
-                              tp->ca_ops->name);
-               }
-       }
-       r->tcpdiag_family = sk->sk_family;
-       r->tcpdiag_state = sk->sk_state;
-       r->tcpdiag_timer = 0;
-       r->tcpdiag_retrans = 0;
-
-       r->id.tcpdiag_if = sk->sk_bound_dev_if;
-       r->id.tcpdiag_cookie[0] = (u32)(unsigned long)sk;
-       r->id.tcpdiag_cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1);
-
-       if (r->tcpdiag_state == TCP_TIME_WAIT) {
-               struct tcp_tw_bucket *tw = (struct tcp_tw_bucket*)sk;
-               long tmo = tw->tw_ttd - jiffies;
-               if (tmo < 0)
-                       tmo = 0;
-
-               r->id.tcpdiag_sport = tw->tw_sport;
-               r->id.tcpdiag_dport = tw->tw_dport;
-               r->id.tcpdiag_src[0] = tw->tw_rcv_saddr;
-               r->id.tcpdiag_dst[0] = tw->tw_daddr;
-               r->tcpdiag_state = tw->tw_substate;
-               r->tcpdiag_timer = 3;
-               r->tcpdiag_expires = (tmo*1000+HZ-1)/HZ;
-               r->tcpdiag_rqueue = 0;
-               r->tcpdiag_wqueue = 0;
-               r->tcpdiag_uid = 0;
-               r->tcpdiag_inode = 0;
-#ifdef CONFIG_IP_TCPDIAG_IPV6
-               if (r->tcpdiag_family == AF_INET6) {
-                       ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_src,
-                                      &tw->tw_v6_rcv_saddr);
-                       ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_dst,
-                                      &tw->tw_v6_daddr);
-               }
-#endif
-               nlh->nlmsg_len = skb->tail - b;
-               return skb->len;
-       }
-
-       r->id.tcpdiag_sport = inet->sport;
-       r->id.tcpdiag_dport = inet->dport;
-       r->id.tcpdiag_src[0] = inet->rcv_saddr;
-       r->id.tcpdiag_dst[0] = inet->daddr;
-
-#ifdef CONFIG_IP_TCPDIAG_IPV6
-       if (r->tcpdiag_family == AF_INET6) {
-               struct ipv6_pinfo *np = inet6_sk(sk);
-
-               ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_src,
-                              &np->rcv_saddr);
-               ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_dst,
-                              &np->daddr);
-       }
-#endif
-
-#define EXPIRES_IN_MS(tmo)  ((tmo-jiffies)*1000+HZ-1)/HZ
-
-       if (tp->pending == TCP_TIME_RETRANS) {
-               r->tcpdiag_timer = 1;
-               r->tcpdiag_retrans = tp->retransmits;
-               r->tcpdiag_expires = EXPIRES_IN_MS(tp->timeout);
-       } else if (tp->pending == TCP_TIME_PROBE0) {
-               r->tcpdiag_timer = 4;
-               r->tcpdiag_retrans = tp->probes_out;
-               r->tcpdiag_expires = EXPIRES_IN_MS(tp->timeout);
-       } else if (timer_pending(&sk->sk_timer)) {
-               r->tcpdiag_timer = 2;
-               r->tcpdiag_retrans = tp->probes_out;
-               r->tcpdiag_expires = EXPIRES_IN_MS(sk->sk_timer.expires);
-       } else {
-               r->tcpdiag_timer = 0;
-               r->tcpdiag_expires = 0;
-       }
-#undef EXPIRES_IN_MS
+       const struct tcp_sock *tp = tcp_sk(sk);
+       struct tcp_info *info = _info;
 
-       r->tcpdiag_rqueue = tp->rcv_nxt - tp->copied_seq;
-       r->tcpdiag_wqueue = tp->write_seq - tp->snd_una;
-       r->tcpdiag_uid = sock_i_uid(sk);
-       r->tcpdiag_inode = sock_i_ino(sk);
-
-       if (minfo) {
-               minfo->tcpdiag_rmem = atomic_read(&sk->sk_rmem_alloc);
-               minfo->tcpdiag_wmem = sk->sk_wmem_queued;
-               minfo->tcpdiag_fmem = sk->sk_forward_alloc;
-               minfo->tcpdiag_tmem = atomic_read(&sk->sk_wmem_alloc);
-       }
-
-       if (info) 
+       r->idiag_rqueue = tp->rcv_nxt - tp->copied_seq;
+       r->idiag_wqueue = tp->write_seq - tp->snd_una;
+       if (info != NULL)
                tcp_get_info(sk, info);
-
-       if (sk->sk_state < TCP_TIME_WAIT && tp->ca_ops->get_info)
-               tp->ca_ops->get_info(tp, ext, skb);
-
-       nlh->nlmsg_len = skb->tail - b;
-       return skb->len;
-
-rtattr_failure:
-nlmsg_failure:
-       skb_trim(skb, b - skb->data);
-       return -1;
-}
-
-extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport,
-                                 int dif);
-#ifdef CONFIG_IP_TCPDIAG_IPV6
-extern struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport,
-                                 struct in6_addr *daddr, u16 dport,
-                                 int dif);
-#else
-static inline struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport,
-                                        struct in6_addr *daddr, u16 dport,
-                                        int dif)
-{
-       return NULL;
-}
-#endif
-
-static int tcpdiag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh)
-{
-       int err;
-       struct sock *sk;
-       struct tcpdiagreq *req = NLMSG_DATA(nlh);
-       struct sk_buff *rep;
-
-       if (req->tcpdiag_family == AF_INET) {
-               sk = tcp_v4_lookup(req->id.tcpdiag_dst[0], req->id.tcpdiag_dport,
-                                  req->id.tcpdiag_src[0], req->id.tcpdiag_sport,
-                                  req->id.tcpdiag_if);
-       }
-#ifdef CONFIG_IP_TCPDIAG_IPV6
-       else if (req->tcpdiag_family == AF_INET6) {
-               sk = tcp_v6_lookup((struct in6_addr*)req->id.tcpdiag_dst, req->id.tcpdiag_dport,
-                                  (struct in6_addr*)req->id.tcpdiag_src, req->id.tcpdiag_sport,
-                                  req->id.tcpdiag_if);
-       }
-#endif
-       else {
-               return -EINVAL;
-       }
-
-       if (sk == NULL)
-               return -ENOENT;
-
-       err = -ESTALE;
-       if ((req->id.tcpdiag_cookie[0] != TCPDIAG_NOCOOKIE ||
-            req->id.tcpdiag_cookie[1] != TCPDIAG_NOCOOKIE) &&
-           ((u32)(unsigned long)sk != req->id.tcpdiag_cookie[0] ||
-            (u32)((((unsigned long)sk) >> 31) >> 1) != req->id.tcpdiag_cookie[1]))
-               goto out;
-
-       err = -ENOMEM;
-       rep = alloc_skb(NLMSG_SPACE(sizeof(struct tcpdiagmsg)+
-                                   sizeof(struct tcpdiag_meminfo)+
-                                   sizeof(struct tcp_info)+64), GFP_KERNEL);
-       if (!rep)
-               goto out;
-
-       if (tcpdiag_fill(rep, sk, req->tcpdiag_ext,
-                        NETLINK_CB(in_skb).pid,
-                        nlh->nlmsg_seq, 0) <= 0)
-               BUG();
-
-       err = netlink_unicast(tcpnl, rep, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
-       if (err > 0)
-               err = 0;
-
-out:
-       if (sk) {
-               if (sk->sk_state == TCP_TIME_WAIT)
-                       tcp_tw_put((struct tcp_tw_bucket*)sk);
-               else
-                       sock_put(sk);
-       }
-       return err;
-}
-
-static int bitstring_match(const u32 *a1, const u32 *a2, int bits)
-{
-       int words = bits >> 5;
-
-       bits &= 0x1f;
-
-       if (words) {
-               if (memcmp(a1, a2, words << 2))
-                       return 0;
-       }
-       if (bits) {
-               __u32 w1, w2;
-               __u32 mask;
-
-               w1 = a1[words];
-               w2 = a2[words];
-
-               mask = htonl((0xffffffff) << (32 - bits));
-
-               if ((w1 ^ w2) & mask)
-                       return 0;
-       }
-
-       return 1;
-}
-
-
-static int tcpdiag_bc_run(const void *bc, int len,
-                         const struct tcpdiag_entry *entry)
-{
-       while (len > 0) {
-               int yes = 1;
-               const struct tcpdiag_bc_op *op = bc;
-
-               switch (op->code) {
-               case TCPDIAG_BC_NOP:
-                       break;
-               case TCPDIAG_BC_JMP:
-                       yes = 0;
-                       break;
-               case TCPDIAG_BC_S_GE:
-                       yes = entry->sport >= op[1].no;
-                       break;
-               case TCPDIAG_BC_S_LE:
-                       yes = entry->dport <= op[1].no;
-                       break;
-               case TCPDIAG_BC_D_GE:
-                       yes = entry->dport >= op[1].no;
-                       break;
-               case TCPDIAG_BC_D_LE:
-                       yes = entry->dport <= op[1].no;
-                       break;
-               case TCPDIAG_BC_AUTO:
-                       yes = !(entry->userlocks & SOCK_BINDPORT_LOCK);
-                       break;
-               case TCPDIAG_BC_S_COND:
-               case TCPDIAG_BC_D_COND:
-               {
-                       struct tcpdiag_hostcond *cond = (struct tcpdiag_hostcond*)(op+1);
-                       u32 *addr;
-
-                       if (cond->port != -1 &&
-                           cond->port != (op->code == TCPDIAG_BC_S_COND ?
-                                            entry->sport : entry->dport)) {
-                               yes = 0;
-                               break;
-                       }
-                       
-                       if (cond->prefix_len == 0)
-                               break;
-
-                       if (op->code == TCPDIAG_BC_S_COND)
-                               addr = entry->saddr;
-                       else
-                               addr = entry->daddr;
-
-                       if (bitstring_match(addr, cond->addr, cond->prefix_len))
-                               break;
-                       if (entry->family == AF_INET6 &&
-                           cond->family == AF_INET) {
-                               if (addr[0] == 0 && addr[1] == 0 &&
-                                   addr[2] == htonl(0xffff) &&
-                                   bitstring_match(addr+3, cond->addr, cond->prefix_len))
-                                       break;
-                       }
-                       yes = 0;
-                       break;
-               }
-               }
-
-               if (yes) { 
-                       len -= op->yes;
-                       bc += op->yes;
-               } else {
-                       len -= op->no;
-                       bc += op->no;
-               }
-       }
-       return (len == 0);
-}
-
-static int valid_cc(const void *bc, int len, int cc)
-{
-       while (len >= 0) {
-               const struct tcpdiag_bc_op *op = bc;
-
-               if (cc > len)
-                       return 0;
-               if (cc == len)
-                       return 1;
-               if (op->yes < 4)
-                       return 0;
-               len -= op->yes;
-               bc  += op->yes;
-       }
-       return 0;
-}
-
-static int tcpdiag_bc_audit(const void *bytecode, int bytecode_len)
-{
-       const unsigned char *bc = bytecode;
-       int  len = bytecode_len;
-
-       while (len > 0) {
-               struct tcpdiag_bc_op *op = (struct tcpdiag_bc_op*)bc;
-
-//printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len);
-               switch (op->code) {
-               case TCPDIAG_BC_AUTO:
-               case TCPDIAG_BC_S_COND:
-               case TCPDIAG_BC_D_COND:
-               case TCPDIAG_BC_S_GE:
-               case TCPDIAG_BC_S_LE:
-               case TCPDIAG_BC_D_GE:
-               case TCPDIAG_BC_D_LE:
-                       if (op->yes < 4 || op->yes > len+4)
-                               return -EINVAL;
-               case TCPDIAG_BC_JMP:
-                       if (op->no < 4 || op->no > len+4)
-                               return -EINVAL;
-                       if (op->no < len &&
-                           !valid_cc(bytecode, bytecode_len, len-op->no))
-                               return -EINVAL;
-                       break;
-               case TCPDIAG_BC_NOP:
-                       if (op->yes < 4 || op->yes > len+4)
-                               return -EINVAL;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               bc += op->yes;
-               len -= op->yes;
-       }
-       return len == 0 ? 0 : -EINVAL;
-}
-
-static int tcpdiag_dump_sock(struct sk_buff *skb, struct sock *sk,
-                            struct netlink_callback *cb)
-{
-       struct tcpdiagreq *r = NLMSG_DATA(cb->nlh);
-
-       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
-               struct tcpdiag_entry entry;
-               struct rtattr *bc = (struct rtattr *)(r + 1);
-               struct inet_sock *inet = inet_sk(sk);
-
-               entry.family = sk->sk_family;
-#ifdef CONFIG_IP_TCPDIAG_IPV6
-               if (entry.family == AF_INET6) {
-                       struct ipv6_pinfo *np = inet6_sk(sk);
-
-                       entry.saddr = np->rcv_saddr.s6_addr32;
-                       entry.daddr = np->daddr.s6_addr32;
-               } else
-#endif
-               {
-                       entry.saddr = &inet->rcv_saddr;
-                       entry.daddr = &inet->daddr;
-               }
-               entry.sport = inet->num;
-               entry.dport = ntohs(inet->dport);
-               entry.userlocks = sk->sk_userlocks;
-
-               if (!tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
-                       return 0;
-       }
-
-       return tcpdiag_fill(skb, sk, r->tcpdiag_ext, NETLINK_CB(cb->skb).pid,
-                           cb->nlh->nlmsg_seq, NLM_F_MULTI);
 }
 
-static int tcpdiag_fill_req(struct sk_buff *skb, struct sock *sk,
-                           struct request_sock *req,
-                           u32 pid, u32 seq)
-{
-       const struct inet_request_sock *ireq = inet_rsk(req);
-       struct inet_sock *inet = inet_sk(sk);
-       unsigned char *b = skb->tail;
-       struct tcpdiagmsg *r;
-       struct nlmsghdr *nlh;
-       long tmo;
-
-       nlh = NLMSG_PUT(skb, pid, seq, TCPDIAG_GETSOCK, sizeof(*r));
-       nlh->nlmsg_flags = NLM_F_MULTI;
-       r = NLMSG_DATA(nlh);
-
-       r->tcpdiag_family = sk->sk_family;
-       r->tcpdiag_state = TCP_SYN_RECV;
-       r->tcpdiag_timer = 1;
-       r->tcpdiag_retrans = req->retrans;
-
-       r->id.tcpdiag_if = sk->sk_bound_dev_if;
-       r->id.tcpdiag_cookie[0] = (u32)(unsigned long)req;
-       r->id.tcpdiag_cookie[1] = (u32)(((unsigned long)req >> 31) >> 1);
-
-       tmo = req->expires - jiffies;
-       if (tmo < 0)
-               tmo = 0;
-
-       r->id.tcpdiag_sport = inet->sport;
-       r->id.tcpdiag_dport = ireq->rmt_port;
-       r->id.tcpdiag_src[0] = ireq->loc_addr;
-       r->id.tcpdiag_dst[0] = ireq->rmt_addr;
-       r->tcpdiag_expires = jiffies_to_msecs(tmo),
-       r->tcpdiag_rqueue = 0;
-       r->tcpdiag_wqueue = 0;
-       r->tcpdiag_uid = sock_i_uid(sk);
-       r->tcpdiag_inode = 0;
-#ifdef CONFIG_IP_TCPDIAG_IPV6
-       if (r->tcpdiag_family == AF_INET6) {
-               ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_src,
-                              &tcp6_rsk(req)->loc_addr);
-               ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_dst,
-                              &tcp6_rsk(req)->rmt_addr);
-       }
-#endif
-       nlh->nlmsg_len = skb->tail - b;
-
-       return skb->len;
-
-nlmsg_failure:
-       skb_trim(skb, b - skb->data);
-       return -1;
-}
-
-static int tcpdiag_dump_reqs(struct sk_buff *skb, struct sock *sk,
-                            struct netlink_callback *cb)
-{
-       struct tcpdiag_entry entry;
-       struct tcpdiagreq *r = NLMSG_DATA(cb->nlh);
-       struct tcp_sock *tp = tcp_sk(sk);
-       struct listen_sock *lopt;
-       struct rtattr *bc = NULL;
-       struct inet_sock *inet = inet_sk(sk);
-       int j, s_j;
-       int reqnum, s_reqnum;
-       int err = 0;
-
-       s_j = cb->args[3];
-       s_reqnum = cb->args[4];
-
-       if (s_j > 0)
-               s_j--;
-
-       entry.family = sk->sk_family;
-
-       read_lock_bh(&tp->accept_queue.syn_wait_lock);
-
-       lopt = tp->accept_queue.listen_opt;
-       if (!lopt || !lopt->qlen)
-               goto out;
-
-       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
-               bc = (struct rtattr *)(r + 1);
-               entry.sport = inet->num;
-               entry.userlocks = sk->sk_userlocks;
-       }
-
-       for (j = s_j; j < TCP_SYNQ_HSIZE; j++) {
-               struct request_sock *req, *head = lopt->syn_table[j];
-
-               reqnum = 0;
-               for (req = head; req; reqnum++, req = req->dl_next) {
-                       struct inet_request_sock *ireq = inet_rsk(req);
-
-                       if (reqnum < s_reqnum)
-                               continue;
-                       if (r->id.tcpdiag_dport != ireq->rmt_port &&
-                           r->id.tcpdiag_dport)
-                               continue;
-
-                       if (bc) {
-                               entry.saddr =
-#ifdef CONFIG_IP_TCPDIAG_IPV6
-                                       (entry.family == AF_INET6) ?
-                                       tcp6_rsk(req)->loc_addr.s6_addr32 :
-#endif
-                                       &ireq->loc_addr;
-                               entry.daddr = 
-#ifdef CONFIG_IP_TCPDIAG_IPV6
-                                       (entry.family == AF_INET6) ?
-                                       tcp6_rsk(req)->rmt_addr.s6_addr32 :
-#endif
-                                       &ireq->rmt_addr;
-                               entry.dport = ntohs(ireq->rmt_port);
-
-                               if (!tcpdiag_bc_run(RTA_DATA(bc),
-                                                   RTA_PAYLOAD(bc), &entry))
-                                       continue;
-                       }
-
-                       err = tcpdiag_fill_req(skb, sk, req,
-                                              NETLINK_CB(cb->skb).pid,
-                                              cb->nlh->nlmsg_seq);
-                       if (err < 0) {
-                               cb->args[3] = j + 1;
-                               cb->args[4] = reqnum;
-                               goto out;
-                       }
-               }
-
-               s_reqnum = 0;
-       }
-
-out:
-       read_unlock_bh(&tp->accept_queue.syn_wait_lock);
-
-       return err;
-}
-
-static int tcpdiag_dump(struct sk_buff *skb, struct netlink_callback *cb)
-{
-       int i, num;
-       int s_i, s_num;
-       struct tcpdiagreq *r = NLMSG_DATA(cb->nlh);
-
-       s_i = cb->args[1];
-       s_num = num = cb->args[2];
-
-       if (cb->args[0] == 0) {
-               if (!(r->tcpdiag_states&(TCPF_LISTEN|TCPF_SYN_RECV)))
-                       goto skip_listen_ht;
-               tcp_listen_lock();
-               for (i = s_i; i < TCP_LHTABLE_SIZE; i++) {
-                       struct sock *sk;
-                       struct hlist_node *node;
-
-                       num = 0;
-                       sk_for_each(sk, node, &tcp_listening_hash[i]) {
-                               struct inet_sock *inet = inet_sk(sk);
-
-                               if (num < s_num) {
-                                       num++;
-                                       continue;
-                               }
-
-                               if (r->id.tcpdiag_sport != inet->sport &&
-                                   r->id.tcpdiag_sport)
-                                       goto next_listen;
-
-                               if (!(r->tcpdiag_states&TCPF_LISTEN) ||
-                                   r->id.tcpdiag_dport ||
-                                   cb->args[3] > 0)
-                                       goto syn_recv;
-
-                               if (tcpdiag_dump_sock(skb, sk, cb) < 0) {
-                                       tcp_listen_unlock();
-                                       goto done;
-                               }
-
-syn_recv:
-                               if (!(r->tcpdiag_states&TCPF_SYN_RECV))
-                                       goto next_listen;
-
-                               if (tcpdiag_dump_reqs(skb, sk, cb) < 0) {
-                                       tcp_listen_unlock();
-                                       goto done;
-                               }
-
-next_listen:
-                               cb->args[3] = 0;
-                               cb->args[4] = 0;
-                               ++num;
-                       }
-
-                       s_num = 0;
-                       cb->args[3] = 0;
-                       cb->args[4] = 0;
-               }
-               tcp_listen_unlock();
-skip_listen_ht:
-               cb->args[0] = 1;
-               s_i = num = s_num = 0;
-       }
-
-       if (!(r->tcpdiag_states&~(TCPF_LISTEN|TCPF_SYN_RECV)))
-               return skb->len;
-
-       for (i = s_i; i < tcp_ehash_size; i++) {
-               struct tcp_ehash_bucket *head = &tcp_ehash[i];
-               struct sock *sk;
-               struct hlist_node *node;
-
-               if (i > s_i)
-                       s_num = 0;
-
-               read_lock_bh(&head->lock);
-
-               num = 0;
-               sk_for_each(sk, node, &head->chain) {
-                       struct inet_sock *inet = inet_sk(sk);
-
-                       if (num < s_num)
-                               goto next_normal;
-                       if (!(r->tcpdiag_states & (1 << sk->sk_state)))
-                               goto next_normal;
-                       if (r->id.tcpdiag_sport != inet->sport &&
-                           r->id.tcpdiag_sport)
-                               goto next_normal;
-                       if (r->id.tcpdiag_dport != inet->dport && r->id.tcpdiag_dport)
-                               goto next_normal;
-                       if (tcpdiag_dump_sock(skb, sk, cb) < 0) {
-                               read_unlock_bh(&head->lock);
-                               goto done;
-                       }
-next_normal:
-                       ++num;
-               }
-
-               if (r->tcpdiag_states&TCPF_TIME_WAIT) {
-                       sk_for_each(sk, node,
-                                   &tcp_ehash[i + tcp_ehash_size].chain) {
-                               struct inet_sock *inet = inet_sk(sk);
-
-                               if (num < s_num)
-                                       goto next_dying;
-                               if (r->id.tcpdiag_sport != inet->sport &&
-                                   r->id.tcpdiag_sport)
-                                       goto next_dying;
-                               if (r->id.tcpdiag_dport != inet->dport &&
-                                   r->id.tcpdiag_dport)
-                                       goto next_dying;
-                               if (tcpdiag_dump_sock(skb, sk, cb) < 0) {
-                                       read_unlock_bh(&head->lock);
-                                       goto done;
-                               }
-next_dying:
-                               ++num;
-                       }
-               }
-               read_unlock_bh(&head->lock);
-       }
-
-done:
-       cb->args[1] = i;
-       cb->args[2] = num;
-       return skb->len;
-}
-
-static int tcpdiag_dump_done(struct netlink_callback *cb)
-{
-       return 0;
-}
-
-
-static __inline__ int
-tcpdiag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
-{
-       if (!(nlh->nlmsg_flags&NLM_F_REQUEST))
-               return 0;
-
-       if (nlh->nlmsg_type != TCPDIAG_GETSOCK)
-               goto err_inval;
-
-       if (NLMSG_LENGTH(sizeof(struct tcpdiagreq)) > skb->len)
-               goto err_inval;
-
-       if (nlh->nlmsg_flags&NLM_F_DUMP) {
-               if (nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(struct tcpdiagreq))) {
-                       struct rtattr *rta = (struct rtattr*)(NLMSG_DATA(nlh) + sizeof(struct tcpdiagreq));
-                       if (rta->rta_type != TCPDIAG_REQ_BYTECODE ||
-                           rta->rta_len < 8 ||
-                           rta->rta_len > nlh->nlmsg_len - NLMSG_SPACE(sizeof(struct tcpdiagreq)))
-                               goto err_inval;
-                       if (tcpdiag_bc_audit(RTA_DATA(rta), RTA_PAYLOAD(rta)))
-                               goto err_inval;
-               }
-               return netlink_dump_start(tcpnl, skb, nlh,
-                                         tcpdiag_dump,
-                                         tcpdiag_dump_done);
-       } else {
-               return tcpdiag_get_exact(skb, nlh);
-       }
-
-err_inval:
-       return -EINVAL;
-}
-
-
-static inline void tcpdiag_rcv_skb(struct sk_buff *skb)
-{
-       int err;
-       struct nlmsghdr * nlh;
-
-       if (skb->len >= NLMSG_SPACE(0)) {
-               nlh = (struct nlmsghdr *)skb->data;
-               if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
-                       return;
-               err = tcpdiag_rcv_msg(skb, nlh);
-               if (err || nlh->nlmsg_flags & NLM_F_ACK) 
-                       netlink_ack(skb, nlh, err);
-       }
-}
-
-static void tcpdiag_rcv(struct sock *sk, int len)
-{
-       struct sk_buff *skb;
-       unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
-
-       while (qlen-- && (skb = skb_dequeue(&sk->sk_receive_queue))) {
-               tcpdiag_rcv_skb(skb);
-               kfree_skb(skb);
-       }
-}
+static struct inet_diag_handler tcp_diag_handler = {
+       .idiag_hashinfo  = &tcp_hashinfo,
+       .idiag_get_info  = tcp_diag_get_info,
+       .idiag_type      = TCPDIAG_GETSOCK,
+       .idiag_info_size = sizeof(struct tcp_info),
+};
 
-static int __init tcpdiag_init(void)
+static int __init tcp_diag_init(void)
 {
-       tcpnl = netlink_kernel_create(NETLINK_TCPDIAG, tcpdiag_rcv);
-       if (tcpnl == NULL)
-               return -ENOMEM;
-       return 0;
+       return inet_diag_register(&tcp_diag_handler);
 }
 
-static void __exit tcpdiag_exit(void)
+static void __exit tcp_diag_exit(void)
 {
-       sock_release(tcpnl->sk_socket);
+       inet_diag_unregister(&tcp_diag_handler);
 }
 
-module_init(tcpdiag_init);
-module_exit(tcpdiag_exit);
+module_init(tcp_diag_init);
+module_exit(tcp_diag_exit);
 MODULE_LICENSE("GPL");
index 36c51f8136bfa6aae3bb1f3f3abf12889673c799..6acc04bde08099c598e633a21518ed51e5b75bd2 100644 (file)
@@ -98,9 +98,10 @@ struct hstcp {
        u32     ai;
 };
 
-static void hstcp_init(struct tcp_sock *tp)
+static void hstcp_init(struct sock *sk)
 {
-       struct hstcp *ca = tcp_ca(tp);
+       struct tcp_sock *tp = tcp_sk(sk);
+       struct hstcp *ca = inet_csk_ca(sk);
 
        ca->ai = 0;
 
@@ -109,10 +110,11 @@ static void hstcp_init(struct tcp_sock *tp)
        tp->snd_cwnd_clamp = min_t(u32, tp->snd_cwnd_clamp, 0xffffffff/128);
 }
 
-static void hstcp_cong_avoid(struct tcp_sock *tp, u32 adk, u32 rtt,
+static void hstcp_cong_avoid(struct sock *sk, u32 adk, u32 rtt,
                             u32 in_flight, int good)
 {
-       struct hstcp *ca = tcp_ca(tp);
+       struct tcp_sock *tp = tcp_sk(sk);
+       struct hstcp *ca = inet_csk_ca(sk);
 
        if (in_flight < tp->snd_cwnd)
                return;
@@ -143,9 +145,10 @@ static void hstcp_cong_avoid(struct tcp_sock *tp, u32 adk, u32 rtt,
        }
 }
 
-static u32 hstcp_ssthresh(struct tcp_sock *tp)
+static u32 hstcp_ssthresh(struct sock *sk)
 {
-       struct hstcp *ca = tcp_ca(tp);
+       const struct tcp_sock *tp = tcp_sk(sk);
+       const struct hstcp *ca = inet_csk_ca(sk);
 
        /* Do multiplicative decrease */
        return max(tp->snd_cwnd - ((tp->snd_cwnd * hstcp_aimd_vals[ca->ai].md) >> 8), 2U);
@@ -164,7 +167,7 @@ static struct tcp_congestion_ops tcp_highspeed = {
 
 static int __init hstcp_register(void)
 {
-       BUG_ON(sizeof(struct hstcp) > TCP_CA_PRIV_SIZE);
+       BUG_ON(sizeof(struct hstcp) > ICSK_CA_PRIV_SIZE);
        return tcp_register_congestion_control(&tcp_highspeed);
 }
 
index 40168275acf9d278c6a6bedb768a2c06640a4a41..e47b37984e951e087cc2185b97336a5e3dadc21f 100644 (file)
@@ -55,18 +55,21 @@ static inline void htcp_reset(struct htcp *ca)
        ca->snd_cwnd_cnt2 = 0;
 }
 
-static u32 htcp_cwnd_undo(struct tcp_sock *tp)
+static u32 htcp_cwnd_undo(struct sock *sk)
 {
-       struct htcp *ca = tcp_ca(tp);
+       const struct tcp_sock *tp = tcp_sk(sk);
+       struct htcp *ca = inet_csk_ca(sk);
        ca->ccount = ca->undo_ccount;
        ca->maxRTT = ca->undo_maxRTT;
        ca->old_maxB = ca->undo_old_maxB;
        return max(tp->snd_cwnd, (tp->snd_ssthresh<<7)/ca->beta);
 }
 
-static inline void measure_rtt(struct tcp_sock *tp)
+static inline void measure_rtt(struct sock *sk)
 {
-       struct htcp *ca = tcp_ca(tp);
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+       const struct tcp_sock *tp = tcp_sk(sk);
+       struct htcp *ca = inet_csk_ca(sk);
        u32 srtt = tp->srtt>>3;
 
        /* keep track of minimum RTT seen so far, minRTT is zero at first */
@@ -74,7 +77,7 @@ static inline void measure_rtt(struct tcp_sock *tp)
                ca->minRTT = srtt;
 
        /* max RTT */
-       if (tp->ca_state == TCP_CA_Open && tp->snd_ssthresh < 0xFFFF && ca->ccount > 3) {
+       if (icsk->icsk_ca_state == TCP_CA_Open && tp->snd_ssthresh < 0xFFFF && ca->ccount > 3) {
                if (ca->maxRTT < ca->minRTT)
                        ca->maxRTT = ca->minRTT;
                if (ca->maxRTT < srtt && srtt <= ca->maxRTT+HZ/50)
@@ -82,13 +85,16 @@ static inline void measure_rtt(struct tcp_sock *tp)
        }
 }
 
-static void measure_achieved_throughput(struct tcp_sock *tp, u32 pkts_acked)
+static void measure_achieved_throughput(struct sock *sk, u32 pkts_acked)
 {
-       struct htcp *ca = tcp_ca(tp);
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+       const struct tcp_sock *tp = tcp_sk(sk);
+       struct htcp *ca = inet_csk_ca(sk);
        u32 now = tcp_time_stamp;
 
        /* achieved throughput calculations */
-       if (tp->ca_state != TCP_CA_Open && tp->ca_state != TCP_CA_Disorder) {
+       if (icsk->icsk_ca_state != TCP_CA_Open &&
+           icsk->icsk_ca_state != TCP_CA_Disorder) {
                ca->packetcount = 0;
                ca->lasttime = now;
                return;
@@ -173,9 +179,9 @@ static inline void htcp_alpha_update(struct htcp *ca)
  * that point do we really have a real sense of maxRTT (the queues en route
  * were getting just too full now).
  */
-static void htcp_param_update(struct tcp_sock *tp)
+static void htcp_param_update(struct sock *sk)
 {
-       struct htcp *ca = tcp_ca(tp);
+       struct htcp *ca = inet_csk_ca(sk);
        u32 minRTT = ca->minRTT;
        u32 maxRTT = ca->maxRTT;
 
@@ -187,17 +193,19 @@ static void htcp_param_update(struct tcp_sock *tp)
                ca->maxRTT = minRTT + ((maxRTT-minRTT)*95)/100;
 }
 
-static u32 htcp_recalc_ssthresh(struct tcp_sock *tp)
+static u32 htcp_recalc_ssthresh(struct sock *sk)
 {
-       struct htcp *ca = tcp_ca(tp);
-       htcp_param_update(tp);
+       const struct tcp_sock *tp = tcp_sk(sk);
+       const struct htcp *ca = inet_csk_ca(sk);
+       htcp_param_update(sk);
        return max((tp->snd_cwnd * ca->beta) >> 7, 2U);
 }
 
-static void htcp_cong_avoid(struct tcp_sock *tp, u32 ack, u32 rtt,
+static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
                            u32 in_flight, int data_acked)
 {
-       struct htcp *ca = tcp_ca(tp);
+       struct tcp_sock *tp = tcp_sk(sk);
+       struct htcp *ca = inet_csk_ca(sk);
 
        if (in_flight < tp->snd_cwnd)
                return;
@@ -207,7 +215,7 @@ static void htcp_cong_avoid(struct tcp_sock *tp, u32 ack, u32 rtt,
                if (tp->snd_cwnd < tp->snd_cwnd_clamp)
                        tp->snd_cwnd++;
        } else {
-               measure_rtt(tp);
+               measure_rtt(sk);
 
                /* keep track of number of round-trip times since last backoff event */
                if (ca->snd_cwnd_cnt2++ > tp->snd_cwnd) {
@@ -229,28 +237,29 @@ static void htcp_cong_avoid(struct tcp_sock *tp, u32 ack, u32 rtt,
 }
 
 /* Lower bound on congestion window. */
-static u32 htcp_min_cwnd(struct tcp_sock *tp)
+static u32 htcp_min_cwnd(struct sock *sk)
 {
+       const struct tcp_sock *tp = tcp_sk(sk);
        return tp->snd_ssthresh;
 }
 
 
-static void htcp_init(struct tcp_sock *tp)
+static void htcp_init(struct sock *sk)
 {
-       struct htcp *ca = tcp_ca(tp);
+       struct htcp *ca = inet_csk_ca(sk);
 
        memset(ca, 0, sizeof(struct htcp));
        ca->alpha = ALPHA_BASE;
        ca->beta = BETA_MIN;
 }
 
-static void htcp_state(struct tcp_sock *tp, u8 new_state)
+static void htcp_state(struct sock *sk, u8 new_state)
 {
        switch (new_state) {
        case TCP_CA_CWR:
        case TCP_CA_Recovery:
        case TCP_CA_Loss:
-               htcp_reset(tcp_ca(tp));
+               htcp_reset(inet_csk_ca(sk));
                break;
        }
 }
@@ -269,7 +278,7 @@ static struct tcp_congestion_ops htcp = {
 
 static int __init htcp_register(void)
 {
-       BUG_ON(sizeof(struct htcp) > TCP_CA_PRIV_SIZE);
+       BUG_ON(sizeof(struct htcp) > ICSK_CA_PRIV_SIZE);
        BUILD_BUG_ON(BETA_MIN >= BETA_MAX);
        if (!use_bandwidth_switch)
                htcp.pkts_acked = NULL;
index 13a66342c304d57db6f2b74fa6dbf04882a8eb2f..77add63623df2a1034a21bfdb6fbaddf82385a71 100644 (file)
@@ -33,19 +33,20 @@ MODULE_PARM_DESC(rtt0, "reference rout trip time (ms)");
 
 
 /* This is called to refresh values for hybla parameters */
-static inline void hybla_recalc_param (struct tcp_sock *tp)
+static inline void hybla_recalc_param (struct sock *sk)
 {
-       struct hybla *ca = tcp_ca(tp);
+       struct hybla *ca = inet_csk_ca(sk);
 
-       ca->rho_3ls = max_t(u32, tp->srtt / msecs_to_jiffies(rtt0), 8);
+       ca->rho_3ls = max_t(u32, tcp_sk(sk)->srtt / msecs_to_jiffies(rtt0), 8);
        ca->rho = ca->rho_3ls >> 3;
        ca->rho2_7ls = (ca->rho_3ls * ca->rho_3ls) << 1;
        ca->rho2 = ca->rho2_7ls >>7;
 }
 
-static void hybla_init(struct tcp_sock *tp)
+static void hybla_init(struct sock *sk)
 {
-       struct hybla *ca = tcp_ca(tp);
+       struct tcp_sock *tp = tcp_sk(sk);
+       struct hybla *ca = inet_csk_ca(sk);
 
        ca->rho = 0;
        ca->rho2 = 0;
@@ -57,17 +58,16 @@ static void hybla_init(struct tcp_sock *tp)
        tp->snd_cwnd_clamp = 65535;
 
        /* 1st Rho measurement based on initial srtt */
-       hybla_recalc_param(tp);
+       hybla_recalc_param(sk);
 
        /* set minimum rtt as this is the 1st ever seen */
        ca->minrtt = tp->srtt;
        tp->snd_cwnd = ca->rho;
 }
 
-static void hybla_state(struct tcp_sock *tp, u8 ca_state)
+static void hybla_state(struct sock *sk, u8 ca_state)
 {
-       struct hybla *ca = tcp_ca(tp);
-
+       struct hybla *ca = inet_csk_ca(sk);
        ca->hybla_en = (ca_state == TCP_CA_Open);
 }
 
@@ -86,27 +86,28 @@ static inline u32 hybla_fraction(u32 odds)
  *     o Give cwnd a new value based on the model proposed
  *     o remember increments <1
  */
-static void hybla_cong_avoid(struct tcp_sock *tp, u32 ack, u32 rtt,
+static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
                            u32 in_flight, int flag)
 {
-       struct hybla *ca = tcp_ca(tp);
+       struct tcp_sock *tp = tcp_sk(sk);
+       struct hybla *ca = inet_csk_ca(sk);
        u32 increment, odd, rho_fractions;
        int is_slowstart = 0;
 
        /*  Recalculate rho only if this srtt is the lowest */
        if (tp->srtt < ca->minrtt){
-               hybla_recalc_param(tp);
+               hybla_recalc_param(sk);
                ca->minrtt = tp->srtt;
        }
 
        if (!ca->hybla_en)
-               return tcp_reno_cong_avoid(tp, ack, rtt, in_flight, flag);
+               return tcp_reno_cong_avoid(sk, ack, rtt, in_flight, flag);
 
        if (in_flight < tp->snd_cwnd)
                return;
 
        if (ca->rho == 0)
-               hybla_recalc_param(tp);
+               hybla_recalc_param(sk);
 
        rho_fractions = ca->rho_3ls - (ca->rho << 3);
 
@@ -170,7 +171,7 @@ static struct tcp_congestion_ops tcp_hybla = {
 
 static int __init hybla_register(void)
 {
-       BUG_ON(sizeof(struct hybla) > TCP_CA_PRIV_SIZE);
+       BUG_ON(sizeof(struct hybla) > ICSK_CA_PRIV_SIZE);
        return tcp_register_congestion_control(&tcp_hybla);
 }
 
index 53a8a5399f1e6e6de3b13a05d691612c533f433c..29222b964951ce4d2d505a3d3d9bed0ca762e025 100644 (file)
@@ -114,20 +114,21 @@ int sysctl_tcp_moderate_rcvbuf = 1;
 /* Adapt the MSS value used to make delayed ack decision to the 
  * real world.
  */ 
-static inline void tcp_measure_rcv_mss(struct tcp_sock *tp,
-                                      struct sk_buff *skb)
+static inline void tcp_measure_rcv_mss(struct sock *sk,
+                                      const struct sk_buff *skb)
 {
-       unsigned int len, lss;
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       const unsigned int lss = icsk->icsk_ack.last_seg_size; 
+       unsigned int len;
 
-       lss = tp->ack.last_seg_size; 
-       tp->ack.last_seg_size = 0; 
+       icsk->icsk_ack.last_seg_size = 0; 
 
        /* skb->len may jitter because of SACKs, even if peer
         * sends good full-sized frames.
         */
        len = skb->len;
-       if (len >= tp->ack.rcv_mss) {
-               tp->ack.rcv_mss = len;
+       if (len >= icsk->icsk_ack.rcv_mss) {
+               icsk->icsk_ack.rcv_mss = len;
        } else {
                /* Otherwise, we make more careful check taking into account,
                 * that SACKs block is variable.
@@ -147,41 +148,44 @@ static inline void tcp_measure_rcv_mss(struct tcp_sock *tp,
                         * tcp header plus fixed timestamp option length.
                         * Resulting "len" is MSS free of SACK jitter.
                         */
-                       len -= tp->tcp_header_len;
-                       tp->ack.last_seg_size = len;
+                       len -= tcp_sk(sk)->tcp_header_len;
+                       icsk->icsk_ack.last_seg_size = len;
                        if (len == lss) {
-                               tp->ack.rcv_mss = len;
+                               icsk->icsk_ack.rcv_mss = len;
                                return;
                        }
                }
-               tp->ack.pending |= TCP_ACK_PUSHED;
+               icsk->icsk_ack.pending |= ICSK_ACK_PUSHED;
        }
 }
 
-static void tcp_incr_quickack(struct tcp_sock *tp)
+static void tcp_incr_quickack(struct sock *sk)
 {
-       unsigned quickacks = tp->rcv_wnd/(2*tp->ack.rcv_mss);
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       unsigned quickacks = tcp_sk(sk)->rcv_wnd / (2 * icsk->icsk_ack.rcv_mss);
 
        if (quickacks==0)
                quickacks=2;
-       if (quickacks > tp->ack.quick)
-               tp->ack.quick = min(quickacks, TCP_MAX_QUICKACKS);
+       if (quickacks > icsk->icsk_ack.quick)
+               icsk->icsk_ack.quick = min(quickacks, TCP_MAX_QUICKACKS);
 }
 
-void tcp_enter_quickack_mode(struct tcp_sock *tp)
+void tcp_enter_quickack_mode(struct sock *sk)
 {
-       tcp_incr_quickack(tp);
-       tp->ack.pingpong = 0;
-       tp->ack.ato = TCP_ATO_MIN;
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       tcp_incr_quickack(sk);
+       icsk->icsk_ack.pingpong = 0;
+       icsk->icsk_ack.ato = TCP_ATO_MIN;
 }
 
 /* Send ACKs quickly, if "quick" count is not exhausted
  * and the session is not interactive.
  */
 
-static __inline__ int tcp_in_quickack_mode(struct tcp_sock *tp)
+static inline int tcp_in_quickack_mode(const struct sock *sk)
 {
-       return (tp->ack.quick && !tp->ack.pingpong);
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+       return icsk->icsk_ack.quick && !icsk->icsk_ack.pingpong;
 }
 
 /* Buffer size and advertised window tuning.
@@ -224,8 +228,8 @@ static void tcp_fixup_sndbuf(struct sock *sk)
  */
 
 /* Slow part of check#2. */
-static int __tcp_grow_window(struct sock *sk, struct tcp_sock *tp,
-                            struct sk_buff *skb)
+static int __tcp_grow_window(const struct sock *sk, struct tcp_sock *tp,
+                            const struct sk_buff *skb)
 {
        /* Optimize this! */
        int truesize = tcp_win_from_space(skb->truesize)/2;
@@ -233,7 +237,7 @@ static int __tcp_grow_window(struct sock *sk, struct tcp_sock *tp,
 
        while (tp->rcv_ssthresh <= window) {
                if (truesize <= skb->len)
-                       return 2*tp->ack.rcv_mss;
+                       return 2 * inet_csk(sk)->icsk_ack.rcv_mss;
 
                truesize >>= 1;
                window >>= 1;
@@ -260,7 +264,7 @@ static inline void tcp_grow_window(struct sock *sk, struct tcp_sock *tp,
 
                if (incr) {
                        tp->rcv_ssthresh = min(tp->rcv_ssthresh + incr, tp->window_clamp);
-                       tp->ack.quick |= 1;
+                       inet_csk(sk)->icsk_ack.quick |= 1;
                }
        }
 }
@@ -321,11 +325,12 @@ static void tcp_init_buffer_space(struct sock *sk)
 /* 5. Recalculate window clamp after socket hit its memory bounds. */
 static void tcp_clamp_window(struct sock *sk, struct tcp_sock *tp)
 {
+       struct inet_connection_sock *icsk = inet_csk(sk);
        struct sk_buff *skb;
        unsigned int app_win = tp->rcv_nxt - tp->copied_seq;
        int ofo_win = 0;
 
-       tp->ack.quick = 0;
+       icsk->icsk_ack.quick = 0;
 
        skb_queue_walk(&tp->out_of_order_queue, skb) {
                ofo_win += skb->len;
@@ -346,8 +351,8 @@ static void tcp_clamp_window(struct sock *sk, struct tcp_sock *tp)
                app_win += ofo_win;
                if (atomic_read(&sk->sk_rmem_alloc) >= 2 * sk->sk_rcvbuf)
                        app_win >>= 1;
-               if (app_win > tp->ack.rcv_mss)
-                       app_win -= tp->ack.rcv_mss;
+               if (app_win > icsk->icsk_ack.rcv_mss)
+                       app_win -= icsk->icsk_ack.rcv_mss;
                app_win = max(app_win, 2U*tp->advmss);
 
                if (!ofo_win)
@@ -415,11 +420,12 @@ new_measure:
        tp->rcv_rtt_est.time = tcp_time_stamp;
 }
 
-static inline void tcp_rcv_rtt_measure_ts(struct tcp_sock *tp, struct sk_buff *skb)
+static inline void tcp_rcv_rtt_measure_ts(struct sock *sk, const struct sk_buff *skb)
 {
+       struct tcp_sock *tp = tcp_sk(sk);
        if (tp->rx_opt.rcv_tsecr &&
            (TCP_SKB_CB(skb)->end_seq -
-            TCP_SKB_CB(skb)->seq >= tp->ack.rcv_mss))
+            TCP_SKB_CB(skb)->seq >= inet_csk(sk)->icsk_ack.rcv_mss))
                tcp_rcv_rtt_update(tp, tcp_time_stamp - tp->rx_opt.rcv_tsecr, 0);
 }
 
@@ -492,41 +498,42 @@ new_measure:
  */
 static void tcp_event_data_recv(struct sock *sk, struct tcp_sock *tp, struct sk_buff *skb)
 {
+       struct inet_connection_sock *icsk = inet_csk(sk);
        u32 now;
 
-       tcp_schedule_ack(tp);
+       inet_csk_schedule_ack(sk);
 
-       tcp_measure_rcv_mss(tp, skb);
+       tcp_measure_rcv_mss(sk, skb);
 
        tcp_rcv_rtt_measure(tp);
        
        now = tcp_time_stamp;
 
-       if (!tp->ack.ato) {
+       if (!icsk->icsk_ack.ato) {
                /* The _first_ data packet received, initialize
                 * delayed ACK engine.
                 */
-               tcp_incr_quickack(tp);
-               tp->ack.ato = TCP_ATO_MIN;
+               tcp_incr_quickack(sk);
+               icsk->icsk_ack.ato = TCP_ATO_MIN;
        } else {
-               int m = now - tp->ack.lrcvtime;
+               int m = now - icsk->icsk_ack.lrcvtime;
 
                if (m <= TCP_ATO_MIN/2) {
                        /* The fastest case is the first. */
-                       tp->ack.ato = (tp->ack.ato>>1) + TCP_ATO_MIN/2;
-               } else if (m < tp->ack.ato) {
-                       tp->ack.ato = (tp->ack.ato>>1) + m;
-                       if (tp->ack.ato > tp->rto)
-                               tp->ack.ato = tp->rto;
-               } else if (m > tp->rto) {
+                       icsk->icsk_ack.ato = (icsk->icsk_ack.ato >> 1) + TCP_ATO_MIN / 2;
+               } else if (m < icsk->icsk_ack.ato) {
+                       icsk->icsk_ack.ato = (icsk->icsk_ack.ato >> 1) + m;
+                       if (icsk->icsk_ack.ato > icsk->icsk_rto)
+                               icsk->icsk_ack.ato = icsk->icsk_rto;
+               } else if (m > icsk->icsk_rto) {
                        /* Too long gap. Apparently sender falled to
                         * restart window, so that we send ACKs quickly.
                         */
-                       tcp_incr_quickack(tp);
+                       tcp_incr_quickack(sk);
                        sk_stream_mem_reclaim(sk);
                }
        }
-       tp->ack.lrcvtime = now;
+       icsk->icsk_ack.lrcvtime = now;
 
        TCP_ECN_check_ce(tp, skb);
 
@@ -543,8 +550,10 @@ static void tcp_event_data_recv(struct sock *sk, struct tcp_sock *tp, struct sk_
  * To save cycles in the RFC 1323 implementation it was better to break
  * it up into three procedures. -- erics
  */
-static void tcp_rtt_estimator(struct tcp_sock *tp, __u32 mrtt, u32 *usrtt)
+static void tcp_rtt_estimator(struct sock *sk, const __u32 mrtt, u32 *usrtt)
 {
+       struct tcp_sock *tp = tcp_sk(sk);
+       const struct inet_connection_sock *icsk = inet_csk(sk);
        long m = mrtt; /* RTT */
 
        /*      The following amusing code comes from Jacobson's
@@ -604,15 +613,16 @@ static void tcp_rtt_estimator(struct tcp_sock *tp, __u32 mrtt, u32 *usrtt)
                tp->rtt_seq = tp->snd_nxt;
        }
 
-       if (tp->ca_ops->rtt_sample)
-               tp->ca_ops->rtt_sample(tp, *usrtt);
+       if (icsk->icsk_ca_ops->rtt_sample)
+               icsk->icsk_ca_ops->rtt_sample(sk, *usrtt);
 }
 
 /* Calculate rto without backoff.  This is the second half of Van Jacobson's
  * routine referred to above.
  */
-static inline void tcp_set_rto(struct tcp_sock *tp)
+static inline void tcp_set_rto(struct sock *sk)
 {
+       const struct tcp_sock *tp = tcp_sk(sk);
        /* Old crap is replaced with new one. 8)
         *
         * More seriously:
@@ -623,7 +633,7 @@ static inline void tcp_set_rto(struct tcp_sock *tp)
         *    is invisible. Actually, Linux-2.4 also generates erratic
         *    ACKs in some curcumstances.
         */
-       tp->rto = (tp->srtt >> 3) + tp->rttvar;
+       inet_csk(sk)->icsk_rto = (tp->srtt >> 3) + tp->rttvar;
 
        /* 2. Fixups made earlier cannot be right.
         *    If we do not estimate RTO correctly without them,
@@ -635,10 +645,10 @@ static inline void tcp_set_rto(struct tcp_sock *tp)
 /* NOTE: clamping at TCP_RTO_MIN is not required, current algo
  * guarantees that rto is higher.
  */
-static inline void tcp_bound_rto(struct tcp_sock *tp)
+static inline void tcp_bound_rto(struct sock *sk)
 {
-       if (tp->rto > TCP_RTO_MAX)
-               tp->rto = TCP_RTO_MAX;
+       if (inet_csk(sk)->icsk_rto > TCP_RTO_MAX)
+               inet_csk(sk)->icsk_rto = TCP_RTO_MAX;
 }
 
 /* Save metrics learned by this TCP session.
@@ -656,9 +666,10 @@ void tcp_update_metrics(struct sock *sk)
        dst_confirm(dst);
 
        if (dst && (dst->flags&DST_HOST)) {
+               const struct inet_connection_sock *icsk = inet_csk(sk);
                int m;
 
-               if (tp->backoff || !tp->srtt) {
+               if (icsk->icsk_backoff || !tp->srtt) {
                        /* This session failed to estimate rtt. Why?
                         * Probably, no packets returned in time.
                         * Reset our results.
@@ -707,7 +718,7 @@ void tcp_update_metrics(struct sock *sk)
                            tp->snd_cwnd > dst_metric(dst, RTAX_CWND))
                                dst->metrics[RTAX_CWND-1] = tp->snd_cwnd;
                } else if (tp->snd_cwnd > tp->snd_ssthresh &&
-                          tp->ca_state == TCP_CA_Open) {
+                          icsk->icsk_ca_state == TCP_CA_Open) {
                        /* Cong. avoidance phase, cwnd is reliable. */
                        if (!dst_metric_locked(dst, RTAX_SSTHRESH))
                                dst->metrics[RTAX_SSTHRESH-1] =
@@ -801,9 +812,9 @@ static void tcp_init_metrics(struct sock *sk)
                tp->mdev = dst_metric(dst, RTAX_RTTVAR);
                tp->mdev_max = tp->rttvar = max(tp->mdev, TCP_RTO_MIN);
        }
-       tcp_set_rto(tp);
-       tcp_bound_rto(tp);
-       if (tp->rto < TCP_TIMEOUT_INIT && !tp->rx_opt.saw_tstamp)
+       tcp_set_rto(sk);
+       tcp_bound_rto(sk);
+       if (inet_csk(sk)->icsk_rto < TCP_TIMEOUT_INIT && !tp->rx_opt.saw_tstamp)
                goto reset;
        tp->snd_cwnd = tcp_init_cwnd(tp, dst);
        tp->snd_cwnd_stamp = tcp_time_stamp;
@@ -817,12 +828,14 @@ reset:
        if (!tp->rx_opt.saw_tstamp && tp->srtt) {
                tp->srtt = 0;
                tp->mdev = tp->mdev_max = tp->rttvar = TCP_TIMEOUT_INIT;
-               tp->rto = TCP_TIMEOUT_INIT;
+               inet_csk(sk)->icsk_rto = TCP_TIMEOUT_INIT;
        }
 }
 
-static void tcp_update_reordering(struct tcp_sock *tp, int metric, int ts)
+static void tcp_update_reordering(struct sock *sk, const int metric,
+                                 const int ts)
 {
+       struct tcp_sock *tp = tcp_sk(sk);
        if (metric > tp->reordering) {
                tp->reordering = min(TCP_MAX_REORDERING, metric);
 
@@ -837,7 +850,7 @@ static void tcp_update_reordering(struct tcp_sock *tp, int metric, int ts)
                        NET_INC_STATS_BH(LINUX_MIB_TCPSACKREORDER);
 #if FASTRETRANS_DEBUG > 1
                printk(KERN_DEBUG "Disorder%d %d %u f%u s%u rr%d\n",
-                      tp->rx_opt.sack_ok, tp->ca_state,
+                      tp->rx_opt.sack_ok, inet_csk(sk)->icsk_ca_state,
                       tp->reordering,
                       tp->fackets_out,
                       tp->sacked_out,
@@ -899,6 +912,7 @@ static void tcp_update_reordering(struct tcp_sock *tp, int metric, int ts)
 static int
 tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_una)
 {
+       const struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        unsigned char *ptr = ack_skb->h.raw + TCP_SKB_CB(ack_skb)->sacked;
        struct tcp_sack_block *sp = (struct tcp_sack_block *)(ptr+2);
@@ -909,14 +923,6 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
        int flag = 0;
        int i;
 
-       /* So, SACKs for already sent large segments will be lost.
-        * Not good, but alternative is to resegment the queue. */
-       if (sk->sk_route_caps & NETIF_F_TSO) {
-               sk->sk_route_caps &= ~NETIF_F_TSO;
-               sock_set_flag(sk, SOCK_NO_LARGESEND);
-               tp->mss_cache = tp->mss_cache;
-       }
-
        if (!tp->sacked_out)
                tp->fackets_out = 0;
        prior_fackets = tp->fackets_out;
@@ -964,20 +970,40 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
                        flag |= FLAG_DATA_LOST;
 
                sk_stream_for_retrans_queue(skb, sk) {
-                       u8 sacked = TCP_SKB_CB(skb)->sacked;
-                       int in_sack;
+                       int in_sack, pcount;
+                       u8 sacked;
 
                        /* The retransmission queue is always in order, so
                         * we can short-circuit the walk early.
                         */
-                       if(!before(TCP_SKB_CB(skb)->seq, end_seq))
+                       if (!before(TCP_SKB_CB(skb)->seq, end_seq))
                                break;
 
-                       fack_count += tcp_skb_pcount(skb);
+                       pcount = tcp_skb_pcount(skb);
+
+                       if (pcount > 1 &&
+                           (after(start_seq, TCP_SKB_CB(skb)->seq) ||
+                            before(end_seq, TCP_SKB_CB(skb)->end_seq))) {
+                               unsigned int pkt_len;
+
+                               if (after(start_seq, TCP_SKB_CB(skb)->seq))
+                                       pkt_len = (start_seq -
+                                                  TCP_SKB_CB(skb)->seq);
+                               else
+                                       pkt_len = (end_seq -
+                                                  TCP_SKB_CB(skb)->seq);
+                               if (tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->tso_size))
+                                       break;
+                               pcount = tcp_skb_pcount(skb);
+                       }
+
+                       fack_count += pcount;
 
                        in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) &&
                                !before(end_seq, TCP_SKB_CB(skb)->end_seq);
 
+                       sacked = TCP_SKB_CB(skb)->sacked;
+
                        /* Account D-SACK for retransmitted packet. */
                        if ((dup_sack && in_sack) &&
                            (sacked & TCPCB_RETRANS) &&
@@ -1064,7 +1090,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
         * we have to account for reordering! Ugly,
         * but should help.
         */
-       if (lost_retrans && tp->ca_state == TCP_CA_Recovery) {
+       if (lost_retrans && icsk->icsk_ca_state == TCP_CA_Recovery) {
                struct sk_buff *skb;
 
                sk_stream_for_retrans_queue(skb, sk) {
@@ -1093,8 +1119,8 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
 
        tp->left_out = tp->sacked_out + tp->lost_out;
 
-       if ((reord < tp->fackets_out) && tp->ca_state != TCP_CA_Loss)
-               tcp_update_reordering(tp, ((tp->fackets_out + 1) - reord), 0);
+       if ((reord < tp->fackets_out) && icsk->icsk_ca_state != TCP_CA_Loss)
+               tcp_update_reordering(sk, ((tp->fackets_out + 1) - reord), 0);
 
 #if FASTRETRANS_DEBUG > 0
        BUG_TRAP((int)tp->sacked_out >= 0);
@@ -1111,17 +1137,18 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
  */
 void tcp_enter_frto(struct sock *sk)
 {
+       const struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *skb;
 
        tp->frto_counter = 1;
 
-       if (tp->ca_state <= TCP_CA_Disorder ||
+       if (icsk->icsk_ca_state <= TCP_CA_Disorder ||
             tp->snd_una == tp->high_seq ||
-            (tp->ca_state == TCP_CA_Loss && !tp->retransmits)) {
-               tp->prior_ssthresh = tcp_current_ssthresh(tp);
-               tp->snd_ssthresh = tp->ca_ops->ssthresh(tp);
-               tcp_ca_event(tp, CA_EVENT_FRTO);
+            (icsk->icsk_ca_state == TCP_CA_Loss && !icsk->icsk_retransmits)) {
+               tp->prior_ssthresh = tcp_current_ssthresh(sk);
+               tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk);
+               tcp_ca_event(sk, CA_EVENT_FRTO);
        }
 
        /* Have to clear retransmission markers here to keep the bookkeeping
@@ -1138,7 +1165,7 @@ void tcp_enter_frto(struct sock *sk)
        }
        tcp_sync_left_out(tp);
 
-       tcp_set_ca_state(tp, TCP_CA_Open);
+       tcp_set_ca_state(sk, TCP_CA_Open);
        tp->frto_highmark = tp->snd_nxt;
 }
 
@@ -1184,7 +1211,7 @@ static void tcp_enter_frto_loss(struct sock *sk)
 
        tp->reordering = min_t(unsigned int, tp->reordering,
                                             sysctl_tcp_reordering);
-       tcp_set_ca_state(tp, TCP_CA_Loss);
+       tcp_set_ca_state(sk, TCP_CA_Loss);
        tp->high_seq = tp->frto_highmark;
        TCP_ECN_queue_cwr(tp);
 }
@@ -1208,16 +1235,17 @@ void tcp_clear_retrans(struct tcp_sock *tp)
  */
 void tcp_enter_loss(struct sock *sk, int how)
 {
+       const struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *skb;
        int cnt = 0;
 
        /* Reduce ssthresh if it has not yet been made inside this window. */
-       if (tp->ca_state <= TCP_CA_Disorder || tp->snd_una == tp->high_seq ||
-           (tp->ca_state == TCP_CA_Loss && !tp->retransmits)) {
-               tp->prior_ssthresh = tcp_current_ssthresh(tp);
-               tp->snd_ssthresh = tp->ca_ops->ssthresh(tp);
-               tcp_ca_event(tp, CA_EVENT_LOSS);
+       if (icsk->icsk_ca_state <= TCP_CA_Disorder || tp->snd_una == tp->high_seq ||
+           (icsk->icsk_ca_state == TCP_CA_Loss && !icsk->icsk_retransmits)) {
+               tp->prior_ssthresh = tcp_current_ssthresh(sk);
+               tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk);
+               tcp_ca_event(sk, CA_EVENT_LOSS);
        }
        tp->snd_cwnd       = 1;
        tp->snd_cwnd_cnt   = 0;
@@ -1248,12 +1276,12 @@ void tcp_enter_loss(struct sock *sk, int how)
 
        tp->reordering = min_t(unsigned int, tp->reordering,
                                             sysctl_tcp_reordering);
-       tcp_set_ca_state(tp, TCP_CA_Loss);
+       tcp_set_ca_state(sk, TCP_CA_Loss);
        tp->high_seq = tp->snd_nxt;
        TCP_ECN_queue_cwr(tp);
 }
 
-static int tcp_check_sack_reneging(struct sock *sk, struct tcp_sock *tp)
+static int tcp_check_sack_reneging(struct sock *sk)
 {
        struct sk_buff *skb;
 
@@ -1265,12 +1293,14 @@ static int tcp_check_sack_reneging(struct sock *sk, struct tcp_sock *tp)
         */
        if ((skb = skb_peek(&sk->sk_write_queue)) != NULL &&
            (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) {
+               struct inet_connection_sock *icsk = inet_csk(sk);
                NET_INC_STATS_BH(LINUX_MIB_TCPSACKRENEGING);
 
                tcp_enter_loss(sk, 1);
-               tp->retransmits++;
+               icsk->icsk_retransmits++;
                tcp_retransmit_skb(sk, skb_peek(&sk->sk_write_queue));
-               tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
+               inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
+                                         icsk->icsk_rto, TCP_RTO_MAX);
                return 1;
        }
        return 0;
@@ -1281,15 +1311,15 @@ static inline int tcp_fackets_out(struct tcp_sock *tp)
        return IsReno(tp) ? tp->sacked_out+1 : tp->fackets_out;
 }
 
-static inline int tcp_skb_timedout(struct tcp_sock *tp, struct sk_buff *skb)
+static inline int tcp_skb_timedout(struct sock *sk, struct sk_buff *skb)
 {
-       return (tcp_time_stamp - TCP_SKB_CB(skb)->when > tp->rto);
+       return (tcp_time_stamp - TCP_SKB_CB(skb)->when > inet_csk(sk)->icsk_rto);
 }
 
 static inline int tcp_head_timedout(struct sock *sk, struct tcp_sock *tp)
 {
        return tp->packets_out &&
-              tcp_skb_timedout(tp, skb_peek(&sk->sk_write_queue));
+              tcp_skb_timedout(sk, skb_peek(&sk->sk_write_queue));
 }
 
 /* Linux NewReno/SACK/FACK/ECN state machine.
@@ -1423,8 +1453,9 @@ static int tcp_time_to_recover(struct sock *sk, struct tcp_sock *tp)
  * in assumption of absent reordering, interpret this as reordering.
  * The only another reason could be bug in receiver TCP.
  */
-static void tcp_check_reno_reordering(struct tcp_sock *tp, int addend)
+static void tcp_check_reno_reordering(struct sock *sk, const int addend)
 {
+       struct tcp_sock *tp = tcp_sk(sk);
        u32 holes;
 
        holes = max(tp->lost_out, 1U);
@@ -1432,16 +1463,17 @@ static void tcp_check_reno_reordering(struct tcp_sock *tp, int addend)
 
        if ((tp->sacked_out + holes) > tp->packets_out) {
                tp->sacked_out = tp->packets_out - holes;
-               tcp_update_reordering(tp, tp->packets_out+addend, 0);
+               tcp_update_reordering(sk, tp->packets_out + addend, 0);
        }
 }
 
 /* Emulate SACKs for SACKless connection: account for a new dupack. */
 
-static void tcp_add_reno_sack(struct tcp_sock *tp)
+static void tcp_add_reno_sack(struct sock *sk)
 {
+       struct tcp_sock *tp = tcp_sk(sk);
        tp->sacked_out++;
-       tcp_check_reno_reordering(tp, 0);
+       tcp_check_reno_reordering(sk, 0);
        tcp_sync_left_out(tp);
 }
 
@@ -1456,7 +1488,7 @@ static void tcp_remove_reno_sacks(struct sock *sk, struct tcp_sock *tp, int acke
                else
                        tp->sacked_out -= acked-1;
        }
-       tcp_check_reno_reordering(tp, acked);
+       tcp_check_reno_reordering(sk, acked);
        tcp_sync_left_out(tp);
 }
 
@@ -1509,7 +1541,7 @@ static void tcp_update_scoreboard(struct sock *sk, struct tcp_sock *tp)
                struct sk_buff *skb;
 
                sk_stream_for_retrans_queue(skb, sk) {
-                       if (tcp_skb_timedout(tp, skb) &&
+                       if (tcp_skb_timedout(sk, skb) &&
                            !(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) {
                                TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
                                tp->lost_out += tcp_skb_pcount(skb);
@@ -1530,14 +1562,16 @@ static inline void tcp_moderate_cwnd(struct tcp_sock *tp)
 }
 
 /* Decrease cwnd each second ack. */
-static void tcp_cwnd_down(struct tcp_sock *tp)
+static void tcp_cwnd_down(struct sock *sk)
 {
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+       struct tcp_sock *tp = tcp_sk(sk);
        int decr = tp->snd_cwnd_cnt + 1;
 
        tp->snd_cwnd_cnt = decr&1;
        decr >>= 1;
 
-       if (decr && tp->snd_cwnd > tp->ca_ops->min_cwnd(tp))
+       if (decr && tp->snd_cwnd > icsk->icsk_ca_ops->min_cwnd(sk))
                tp->snd_cwnd -= decr;
 
        tp->snd_cwnd = min(tp->snd_cwnd, tcp_packets_in_flight(tp)+1);
@@ -1571,11 +1605,15 @@ static void DBGUNDO(struct sock *sk, struct tcp_sock *tp, const char *msg)
 #define DBGUNDO(x...) do { } while (0)
 #endif
 
-static void tcp_undo_cwr(struct tcp_sock *tp, int undo)
+static void tcp_undo_cwr(struct sock *sk, const int undo)
 {
+       struct tcp_sock *tp = tcp_sk(sk);
+
        if (tp->prior_ssthresh) {
-               if (tp->ca_ops->undo_cwnd)
-                       tp->snd_cwnd = tp->ca_ops->undo_cwnd(tp);
+               const struct inet_connection_sock *icsk = inet_csk(sk);
+
+               if (icsk->icsk_ca_ops->undo_cwnd)
+                       tp->snd_cwnd = icsk->icsk_ca_ops->undo_cwnd(sk);
                else
                        tp->snd_cwnd = max(tp->snd_cwnd, tp->snd_ssthresh<<1);
 
@@ -1603,9 +1641,9 @@ static int tcp_try_undo_recovery(struct sock *sk, struct tcp_sock *tp)
                /* Happy end! We did not retransmit anything
                 * or our original transmission succeeded.
                 */
-               DBGUNDO(sk, tp, tp->ca_state == TCP_CA_Loss ? "loss" : "retrans");
-               tcp_undo_cwr(tp, 1);
-               if (tp->ca_state == TCP_CA_Loss)
+               DBGUNDO(sk, tp, inet_csk(sk)->icsk_ca_state == TCP_CA_Loss ? "loss" : "retrans");
+               tcp_undo_cwr(sk, 1);
+               if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss)
                        NET_INC_STATS_BH(LINUX_MIB_TCPLOSSUNDO);
                else
                        NET_INC_STATS_BH(LINUX_MIB_TCPFULLUNDO);
@@ -1618,7 +1656,7 @@ static int tcp_try_undo_recovery(struct sock *sk, struct tcp_sock *tp)
                tcp_moderate_cwnd(tp);
                return 1;
        }
-       tcp_set_ca_state(tp, TCP_CA_Open);
+       tcp_set_ca_state(sk, TCP_CA_Open);
        return 0;
 }
 
@@ -1627,7 +1665,7 @@ static void tcp_try_undo_dsack(struct sock *sk, struct tcp_sock *tp)
 {
        if (tp->undo_marker && !tp->undo_retrans) {
                DBGUNDO(sk, tp, "D-SACK");
-               tcp_undo_cwr(tp, 1);
+               tcp_undo_cwr(sk, 1);
                tp->undo_marker = 0;
                NET_INC_STATS_BH(LINUX_MIB_TCPDSACKUNDO);
        }
@@ -1648,10 +1686,10 @@ static int tcp_try_undo_partial(struct sock *sk, struct tcp_sock *tp,
                if (tp->retrans_out == 0)
                        tp->retrans_stamp = 0;
 
-               tcp_update_reordering(tp, tcp_fackets_out(tp)+acked, 1);
+               tcp_update_reordering(sk, tcp_fackets_out(tp) + acked, 1);
 
                DBGUNDO(sk, tp, "Hoe");
-               tcp_undo_cwr(tp, 0);
+               tcp_undo_cwr(sk, 0);
                NET_INC_STATS_BH(LINUX_MIB_TCPPARTIALUNDO);
 
                /* So... Do not make Hoe's retransmit yet.
@@ -1674,22 +1712,23 @@ static int tcp_try_undo_loss(struct sock *sk, struct tcp_sock *tp)
                DBGUNDO(sk, tp, "partial loss");
                tp->lost_out = 0;
                tp->left_out = tp->sacked_out;
-               tcp_undo_cwr(tp, 1);
+               tcp_undo_cwr(sk, 1);
                NET_INC_STATS_BH(LINUX_MIB_TCPLOSSUNDO);
-               tp->retransmits = 0;
+               inet_csk(sk)->icsk_retransmits = 0;
                tp->undo_marker = 0;
                if (!IsReno(tp))
-                       tcp_set_ca_state(tp, TCP_CA_Open);
+                       tcp_set_ca_state(sk, TCP_CA_Open);
                return 1;
        }
        return 0;
 }
 
-static inline void tcp_complete_cwr(struct tcp_sock *tp)
+static inline void tcp_complete_cwr(struct sock *sk)
 {
+       struct tcp_sock *tp = tcp_sk(sk);
        tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh);
        tp->snd_cwnd_stamp = tcp_time_stamp;
-       tcp_ca_event(tp, CA_EVENT_COMPLETE_CWR);
+       tcp_ca_event(sk, CA_EVENT_COMPLETE_CWR);
 }
 
 static void tcp_try_to_open(struct sock *sk, struct tcp_sock *tp, int flag)
@@ -1700,21 +1739,21 @@ static void tcp_try_to_open(struct sock *sk, struct tcp_sock *tp, int flag)
                tp->retrans_stamp = 0;
 
        if (flag&FLAG_ECE)
-               tcp_enter_cwr(tp);
+               tcp_enter_cwr(sk);
 
-       if (tp->ca_state != TCP_CA_CWR) {
+       if (inet_csk(sk)->icsk_ca_state != TCP_CA_CWR) {
                int state = TCP_CA_Open;
 
                if (tp->left_out || tp->retrans_out || tp->undo_marker)
                        state = TCP_CA_Disorder;
 
-               if (tp->ca_state != state) {
-                       tcp_set_ca_state(tp, state);
+               if (inet_csk(sk)->icsk_ca_state != state) {
+                       tcp_set_ca_state(sk, state);
                        tp->high_seq = tp->snd_nxt;
                }
                tcp_moderate_cwnd(tp);
        } else {
-               tcp_cwnd_down(tp);
+               tcp_cwnd_down(sk);
        }
 }
 
@@ -1733,6 +1772,7 @@ static void
 tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una,
                      int prior_packets, int flag)
 {
+       struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        int is_dupack = (tp->snd_una == prior_snd_una && !(flag&FLAG_NOT_DUP));
 
@@ -1750,13 +1790,13 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una,
                tp->prior_ssthresh = 0;
 
        /* B. In all the states check for reneging SACKs. */
-       if (tp->sacked_out && tcp_check_sack_reneging(sk, tp))
+       if (tp->sacked_out && tcp_check_sack_reneging(sk))
                return;
 
        /* C. Process data loss notification, provided it is valid. */
        if ((flag&FLAG_DATA_LOST) &&
            before(tp->snd_una, tp->high_seq) &&
-           tp->ca_state != TCP_CA_Open &&
+           icsk->icsk_ca_state != TCP_CA_Open &&
            tp->fackets_out > tp->reordering) {
                tcp_mark_head_lost(sk, tp, tp->fackets_out-tp->reordering, tp->high_seq);
                NET_INC_STATS_BH(LINUX_MIB_TCPLOSS);
@@ -1767,14 +1807,14 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una,
 
        /* E. Check state exit conditions. State can be terminated
         *    when high_seq is ACKed. */
-       if (tp->ca_state == TCP_CA_Open) {
+       if (icsk->icsk_ca_state == TCP_CA_Open) {
                if (!sysctl_tcp_frto)
                        BUG_TRAP(tp->retrans_out == 0);
                tp->retrans_stamp = 0;
        } else if (!before(tp->snd_una, tp->high_seq)) {
-               switch (tp->ca_state) {
+               switch (icsk->icsk_ca_state) {
                case TCP_CA_Loss:
-                       tp->retransmits = 0;
+                       icsk->icsk_retransmits = 0;
                        if (tcp_try_undo_recovery(sk, tp))
                                return;
                        break;
@@ -1783,8 +1823,8 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una,
                        /* CWR is to be held something *above* high_seq
                         * is ACKed for CWR bit to reach receiver. */
                        if (tp->snd_una != tp->high_seq) {
-                               tcp_complete_cwr(tp);
-                               tcp_set_ca_state(tp, TCP_CA_Open);
+                               tcp_complete_cwr(sk);
+                               tcp_set_ca_state(sk, TCP_CA_Open);
                        }
                        break;
 
@@ -1795,7 +1835,7 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una,
                             * catching for all duplicate ACKs. */
                            IsReno(tp) || tp->snd_una != tp->high_seq) {
                                tp->undo_marker = 0;
-                               tcp_set_ca_state(tp, TCP_CA_Open);
+                               tcp_set_ca_state(sk, TCP_CA_Open);
                        }
                        break;
 
@@ -1804,17 +1844,17 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una,
                                tcp_reset_reno_sack(tp);
                        if (tcp_try_undo_recovery(sk, tp))
                                return;
-                       tcp_complete_cwr(tp);
+                       tcp_complete_cwr(sk);
                        break;
                }
        }
 
        /* F. Process state. */
-       switch (tp->ca_state) {
+       switch (icsk->icsk_ca_state) {
        case TCP_CA_Recovery:
                if (prior_snd_una == tp->snd_una) {
                        if (IsReno(tp) && is_dupack)
-                               tcp_add_reno_sack(tp);
+                               tcp_add_reno_sack(sk);
                } else {
                        int acked = prior_packets - tp->packets_out;
                        if (IsReno(tp))
@@ -1824,13 +1864,13 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una,
                break;
        case TCP_CA_Loss:
                if (flag&FLAG_DATA_ACKED)
-                       tp->retransmits = 0;
+                       icsk->icsk_retransmits = 0;
                if (!tcp_try_undo_loss(sk, tp)) {
                        tcp_moderate_cwnd(tp);
                        tcp_xmit_retransmit_queue(sk);
                        return;
                }
-               if (tp->ca_state != TCP_CA_Open)
+               if (icsk->icsk_ca_state != TCP_CA_Open)
                        return;
                /* Loss is undone; fall through to processing in Open state. */
        default:
@@ -1838,10 +1878,10 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una,
                        if (tp->snd_una != prior_snd_una)
                                tcp_reset_reno_sack(tp);
                        if (is_dupack)
-                               tcp_add_reno_sack(tp);
+                               tcp_add_reno_sack(sk);
                }
 
-               if (tp->ca_state == TCP_CA_Disorder)
+               if (icsk->icsk_ca_state == TCP_CA_Disorder)
                        tcp_try_undo_dsack(sk, tp);
 
                if (!tcp_time_to_recover(sk, tp)) {
@@ -1861,30 +1901,28 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una,
                tp->undo_marker = tp->snd_una;
                tp->undo_retrans = tp->retrans_out;
 
-               if (tp->ca_state < TCP_CA_CWR) {
+               if (icsk->icsk_ca_state < TCP_CA_CWR) {
                        if (!(flag&FLAG_ECE))
-                               tp->prior_ssthresh = tcp_current_ssthresh(tp);
-                       tp->snd_ssthresh = tp->ca_ops->ssthresh(tp);
+                               tp->prior_ssthresh = tcp_current_ssthresh(sk);
+                       tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk);
                        TCP_ECN_queue_cwr(tp);
                }
 
                tp->snd_cwnd_cnt = 0;
-               tcp_set_ca_state(tp, TCP_CA_Recovery);
+               tcp_set_ca_state(sk, TCP_CA_Recovery);
        }
 
        if (is_dupack || tcp_head_timedout(sk, tp))
                tcp_update_scoreboard(sk, tp);
-       tcp_cwnd_down(tp);
+       tcp_cwnd_down(sk);
        tcp_xmit_retransmit_queue(sk);
 }
 
 /* Read draft-ietf-tcplw-high-performance before mucking
  * with this code. (Superceeds RFC1323)
  */
-static void tcp_ack_saw_tstamp(struct tcp_sock *tp, u32 *usrtt, int flag)
+static void tcp_ack_saw_tstamp(struct sock *sk, u32 *usrtt, int flag)
 {
-       __u32 seq_rtt;
-
        /* RTTM Rule: A TSecr value received in a segment is used to
         * update the averaged RTT measurement only if the segment
         * acknowledges some new data, i.e., only if it advances the
@@ -1900,14 +1938,15 @@ static void tcp_ack_saw_tstamp(struct tcp_sock *tp, u32 *usrtt, int flag)
         * answer arrives rto becomes 120 seconds! If at least one of segments
         * in window is lost... Voila.                          --ANK (010210)
         */
-       seq_rtt = tcp_time_stamp - tp->rx_opt.rcv_tsecr;
-       tcp_rtt_estimator(tp, seq_rtt, usrtt);
-       tcp_set_rto(tp);
-       tp->backoff = 0;
-       tcp_bound_rto(tp);
+       struct tcp_sock *tp = tcp_sk(sk);
+       const __u32 seq_rtt = tcp_time_stamp - tp->rx_opt.rcv_tsecr;
+       tcp_rtt_estimator(sk, seq_rtt, usrtt);
+       tcp_set_rto(sk);
+       inet_csk(sk)->icsk_backoff = 0;
+       tcp_bound_rto(sk);
 }
 
-static void tcp_ack_no_tstamp(struct tcp_sock *tp, u32 seq_rtt, u32 *usrtt, int flag)
+static void tcp_ack_no_tstamp(struct sock *sk, u32 seq_rtt, u32 *usrtt, int flag)
 {
        /* We don't have a timestamp. Can only use
         * packets that are not retransmitted to determine
@@ -1921,27 +1960,29 @@ static void tcp_ack_no_tstamp(struct tcp_sock *tp, u32 seq_rtt, u32 *usrtt, int
        if (flag & FLAG_RETRANS_DATA_ACKED)
                return;
 
-       tcp_rtt_estimator(tp, seq_rtt, usrtt);
-       tcp_set_rto(tp);
-       tp->backoff = 0;
-       tcp_bound_rto(tp);
+       tcp_rtt_estimator(sk, seq_rtt, usrtt);
+       tcp_set_rto(sk);
+       inet_csk(sk)->icsk_backoff = 0;
+       tcp_bound_rto(sk);
 }
 
-static inline void tcp_ack_update_rtt(struct tcp_sock *tp,
-                                     int flag, s32 seq_rtt, u32 *usrtt)
+static inline void tcp_ack_update_rtt(struct sock *sk, const int flag,
+                                     const s32 seq_rtt, u32 *usrtt)
 {
+       const struct tcp_sock *tp = tcp_sk(sk);
        /* Note that peer MAY send zero echo. In this case it is ignored. (rfc1323) */
        if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr)
-               tcp_ack_saw_tstamp(tp, usrtt, flag);
+               tcp_ack_saw_tstamp(sk, usrtt, flag);
        else if (seq_rtt >= 0)
-               tcp_ack_no_tstamp(tp, seq_rtt, usrtt, flag);
+               tcp_ack_no_tstamp(sk, seq_rtt, usrtt, flag);
 }
 
-static inline void tcp_cong_avoid(struct tcp_sock *tp, u32 ack, u32 rtt,
+static inline void tcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
                                  u32 in_flight, int good)
 {
-       tp->ca_ops->cong_avoid(tp, ack, rtt, in_flight, good);
-       tp->snd_cwnd_stamp = tcp_time_stamp;
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+       icsk->icsk_ca_ops->cong_avoid(sk, ack, rtt, in_flight, good);
+       tcp_sk(sk)->snd_cwnd_stamp = tcp_time_stamp;
 }
 
 /* Restart timer after forward progress on connection.
@@ -1951,9 +1992,9 @@ static inline void tcp_cong_avoid(struct tcp_sock *tp, u32 ack, u32 rtt,
 static inline void tcp_ack_packets_out(struct sock *sk, struct tcp_sock *tp)
 {
        if (!tp->packets_out) {
-               tcp_clear_xmit_timer(sk, TCP_TIME_RETRANS);
+               inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
        } else {
-               tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
+               inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, inet_csk(sk)->icsk_rto, TCP_RTO_MAX);
        }
 }
 
@@ -2068,9 +2109,13 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p, s32 *seq_usrtt
                                seq_rtt = -1;
                        } else if (seq_rtt < 0)
                                seq_rtt = now - scb->when;
-                       if (seq_usrtt)
-                               *seq_usrtt = (usnow.tv_sec - skb->stamp.tv_sec) * 1000000
-                                       + (usnow.tv_usec - skb->stamp.tv_usec);
+                       if (seq_usrtt) {
+                               struct timeval tv;
+                       
+                               skb_get_timestamp(skb, &tv);
+                               *seq_usrtt = (usnow.tv_sec - tv.tv_sec) * 1000000
+                                       + (usnow.tv_usec - tv.tv_usec);
+                       }
 
                        if (sacked & TCPCB_SACKED_ACKED)
                                tp->sacked_out -= tcp_skb_pcount(skb);
@@ -2085,16 +2130,17 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p, s32 *seq_usrtt
                        seq_rtt = now - scb->when;
                tcp_dec_pcount_approx(&tp->fackets_out, skb);
                tcp_packets_out_dec(tp, skb);
-               __skb_unlink(skb, skb->list);
+               __skb_unlink(skb, &sk->sk_write_queue);
                sk_stream_free_skb(sk, skb);
        }
 
        if (acked&FLAG_ACKED) {
-               tcp_ack_update_rtt(tp, acked, seq_rtt, seq_usrtt);
+               const struct inet_connection_sock *icsk = inet_csk(sk);
+               tcp_ack_update_rtt(sk, acked, seq_rtt, seq_usrtt);
                tcp_ack_packets_out(sk, tp);
 
-               if (tp->ca_ops->pkts_acked)
-                       tp->ca_ops->pkts_acked(tp, pkts_acked);
+               if (icsk->icsk_ca_ops->pkts_acked)
+                       icsk->icsk_ca_ops->pkts_acked(sk, pkts_acked);
        }
 
 #if FASTRETRANS_DEBUG > 0
@@ -2102,19 +2148,20 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p, s32 *seq_usrtt
        BUG_TRAP((int)tp->lost_out >= 0);
        BUG_TRAP((int)tp->retrans_out >= 0);
        if (!tp->packets_out && tp->rx_opt.sack_ok) {
+               const struct inet_connection_sock *icsk = inet_csk(sk);
                if (tp->lost_out) {
                        printk(KERN_DEBUG "Leak l=%u %d\n",
-                              tp->lost_out, tp->ca_state);
+                              tp->lost_out, icsk->icsk_ca_state);
                        tp->lost_out = 0;
                }
                if (tp->sacked_out) {
                        printk(KERN_DEBUG "Leak s=%u %d\n",
-                              tp->sacked_out, tp->ca_state);
+                              tp->sacked_out, icsk->icsk_ca_state);
                        tp->sacked_out = 0;
                }
                if (tp->retrans_out) {
                        printk(KERN_DEBUG "Leak r=%u %d\n",
-                              tp->retrans_out, tp->ca_state);
+                              tp->retrans_out, icsk->icsk_ca_state);
                        tp->retrans_out = 0;
                }
        }
@@ -2125,40 +2172,43 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p, s32 *seq_usrtt
 
 static void tcp_ack_probe(struct sock *sk)
 {
-       struct tcp_sock *tp = tcp_sk(sk);
+       const struct tcp_sock *tp = tcp_sk(sk);
+       struct inet_connection_sock *icsk = inet_csk(sk);
 
        /* Was it a usable window open? */
 
        if (!after(TCP_SKB_CB(sk->sk_send_head)->end_seq,
                   tp->snd_una + tp->snd_wnd)) {
-               tp->backoff = 0;
-               tcp_clear_xmit_timer(sk, TCP_TIME_PROBE0);
+               icsk->icsk_backoff = 0;
+               inet_csk_clear_xmit_timer(sk, ICSK_TIME_PROBE0);
                /* Socket must be waked up by subsequent tcp_data_snd_check().
                 * This function is not for random using!
                 */
        } else {
-               tcp_reset_xmit_timer(sk, TCP_TIME_PROBE0,
-                                    min(tp->rto << tp->backoff, TCP_RTO_MAX));
+               inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0,
+                                         min(icsk->icsk_rto << icsk->icsk_backoff, TCP_RTO_MAX),
+                                         TCP_RTO_MAX);
        }
 }
 
-static inline int tcp_ack_is_dubious(struct tcp_sock *tp, int flag)
+static inline int tcp_ack_is_dubious(const struct sock *sk, const int flag)
 {
        return (!(flag & FLAG_NOT_DUP) || (flag & FLAG_CA_ALERT) ||
-               tp->ca_state != TCP_CA_Open);
+               inet_csk(sk)->icsk_ca_state != TCP_CA_Open);
 }
 
-static inline int tcp_may_raise_cwnd(struct tcp_sock *tp, int flag)
+static inline int tcp_may_raise_cwnd(const struct sock *sk, const int flag)
 {
+       const struct tcp_sock *tp = tcp_sk(sk);
        return (!(flag & FLAG_ECE) || tp->snd_cwnd < tp->snd_ssthresh) &&
-               !((1<<tp->ca_state)&(TCPF_CA_Recovery|TCPF_CA_CWR));
+               !((1 << inet_csk(sk)->icsk_ca_state) & (TCPF_CA_Recovery | TCPF_CA_CWR));
 }
 
 /* Check that window update is acceptable.
  * The function assumes that snd_una<=ack<=snd_next.
  */
-static inline int tcp_may_update_window(struct tcp_sock *tp, u32 ack,
-                                       u32 ack_seq, u32 nwin)
+static inline int tcp_may_update_window(const struct tcp_sock *tp, const u32 ack,
+                                       const u32 ack_seq, const u32 nwin)
 {
        return (after(ack, tp->snd_una) ||
                after(ack_seq, tp->snd_wl1) ||
@@ -2241,6 +2291,7 @@ static void tcp_process_frto(struct sock *sk, u32 prior_snd_una)
 /* This routine deals with incoming acks, but not outgoing ones. */
 static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
 {
+       struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        u32 prior_snd_una = tp->snd_una;
        u32 ack_seq = TCP_SKB_CB(skb)->seq;
@@ -2268,7 +2319,7 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
                tp->snd_una = ack;
                flag |= FLAG_WIN_UPDATE;
 
-               tcp_ca_event(tp, CA_EVENT_FAST_ACK);
+               tcp_ca_event(sk, CA_EVENT_FAST_ACK);
 
                NET_INC_STATS_BH(LINUX_MIB_TCPHPACKS);
        } else {
@@ -2285,7 +2336,7 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
                if (TCP_ECN_rcv_ecn_echo(tp, skb->h.th))
                        flag |= FLAG_ECE;
 
-               tcp_ca_event(tp, CA_EVENT_SLOW_ACK);
+               tcp_ca_event(sk, CA_EVENT_SLOW_ACK);
        }
 
        /* We passed data and got it acked, remove any soft error
@@ -2301,19 +2352,19 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
 
        /* See if we can take anything off of the retransmit queue. */
        flag |= tcp_clean_rtx_queue(sk, &seq_rtt,
-                                   tp->ca_ops->rtt_sample ? &seq_usrtt : NULL);
+                                   icsk->icsk_ca_ops->rtt_sample ? &seq_usrtt : NULL);
 
        if (tp->frto_counter)
                tcp_process_frto(sk, prior_snd_una);
 
-       if (tcp_ack_is_dubious(tp, flag)) {
+       if (tcp_ack_is_dubious(sk, flag)) {
                /* Advanve CWND, if state allows this. */
-               if ((flag & FLAG_DATA_ACKED) && tcp_may_raise_cwnd(tp, flag))
-                       tcp_cong_avoid(tp, ack,  seq_rtt, prior_in_flight, 0);
+               if ((flag & FLAG_DATA_ACKED) && tcp_may_raise_cwnd(sk, flag))
+                       tcp_cong_avoid(sk, ack,  seq_rtt, prior_in_flight, 0);
                tcp_fastretrans_alert(sk, prior_snd_una, prior_packets, flag);
        } else {
                if ((flag & FLAG_DATA_ACKED))
-                       tcp_cong_avoid(tp, ack, seq_rtt, prior_in_flight, 1);
+                       tcp_cong_avoid(sk, ack, seq_rtt, prior_in_flight, 1);
        }
 
        if ((flag & FLAG_FORWARD_PROGRESS) || !(flag&FLAG_NOT_DUP))
@@ -2322,7 +2373,7 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
        return 1;
 
 no_queue:
-       tp->probes_out = 0;
+       icsk->icsk_probes_out = 0;
 
        /* If this ack opens up a zero window, clear backoff.  It was
         * being used to time the probes, and is probably far higher than
@@ -2500,8 +2551,9 @@ static inline void tcp_replace_ts_recent(struct tcp_sock *tp, u32 seq)
  * up to bandwidth of 18Gigabit/sec. 8) ]
  */
 
-static int tcp_disordered_ack(struct tcp_sock *tp, struct sk_buff *skb)
+static int tcp_disordered_ack(const struct sock *sk, const struct sk_buff *skb)
 {
+       struct tcp_sock *tp = tcp_sk(sk);
        struct tcphdr *th = skb->h.th;
        u32 seq = TCP_SKB_CB(skb)->seq;
        u32 ack = TCP_SKB_CB(skb)->ack_seq;
@@ -2516,14 +2568,15 @@ static int tcp_disordered_ack(struct tcp_sock *tp, struct sk_buff *skb)
                !tcp_may_update_window(tp, ack, seq, ntohs(th->window) << tp->rx_opt.snd_wscale) &&
 
                /* 4. ... and sits in replay window. */
-               (s32)(tp->rx_opt.ts_recent - tp->rx_opt.rcv_tsval) <= (tp->rto*1024)/HZ);
+               (s32)(tp->rx_opt.ts_recent - tp->rx_opt.rcv_tsval) <= (inet_csk(sk)->icsk_rto * 1024) / HZ);
 }
 
-static inline int tcp_paws_discard(struct tcp_sock *tp, struct sk_buff *skb)
+static inline int tcp_paws_discard(const struct sock *sk, const struct sk_buff *skb)
 {
+       const struct tcp_sock *tp = tcp_sk(sk);
        return ((s32)(tp->rx_opt.ts_recent - tp->rx_opt.rcv_tsval) > TCP_PAWS_WINDOW &&
                xtime.tv_sec < tp->rx_opt.ts_recent_stamp + TCP_PAWS_24DAYS &&
-               !tcp_disordered_ack(tp, skb));
+               !tcp_disordered_ack(sk, skb));
 }
 
 /* Check segment sequence number for validity.
@@ -2586,7 +2639,7 @@ static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
 {
        struct tcp_sock *tp = tcp_sk(sk);
 
-       tcp_schedule_ack(tp);
+       inet_csk_schedule_ack(sk);
 
        sk->sk_shutdown |= RCV_SHUTDOWN;
        sock_set_flag(sk, SOCK_DONE);
@@ -2596,7 +2649,7 @@ static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
                case TCP_ESTABLISHED:
                        /* Move to CLOSE_WAIT */
                        tcp_set_state(sk, TCP_CLOSE_WAIT);
-                       tp->ack.pingpong = 1;
+                       inet_csk(sk)->icsk_ack.pingpong = 1;
                        break;
 
                case TCP_CLOSE_WAIT:
@@ -2694,7 +2747,7 @@ static void tcp_send_dupack(struct sock *sk, struct sk_buff *skb)
        if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq &&
            before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
                NET_INC_STATS_BH(LINUX_MIB_DELAYEDACKLOST);
-               tcp_enter_quickack_mode(tp);
+               tcp_enter_quickack_mode(sk);
 
                if (tp->rx_opt.sack_ok && sysctl_tcp_dsack) {
                        u32 end_seq = TCP_SKB_CB(skb)->end_seq;
@@ -2853,7 +2906,7 @@ static void tcp_ofo_queue(struct sock *sk)
 
                if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) {
                        SOCK_DEBUG(sk, "ofo packet was already received \n");
-                       __skb_unlink(skb, skb->list);
+                       __skb_unlink(skb, &tp->out_of_order_queue);
                        __kfree_skb(skb);
                        continue;
                }
@@ -2861,7 +2914,7 @@ static void tcp_ofo_queue(struct sock *sk)
                           tp->rcv_nxt, TCP_SKB_CB(skb)->seq,
                           TCP_SKB_CB(skb)->end_seq);
 
-               __skb_unlink(skb, skb->list);
+               __skb_unlink(skb, &tp->out_of_order_queue);
                __skb_queue_tail(&sk->sk_receive_queue, skb);
                tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
                if(skb->h.th->fin)
@@ -2942,7 +2995,7 @@ queue_and_out:
                         * gap in queue is filled.
                         */
                        if (skb_queue_empty(&tp->out_of_order_queue))
-                               tp->ack.pingpong = 0;
+                               inet_csk(sk)->icsk_ack.pingpong = 0;
                }
 
                if (tp->rx_opt.num_sacks)
@@ -2963,8 +3016,8 @@ queue_and_out:
                tcp_dsack_set(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq);
 
 out_of_window:
-               tcp_enter_quickack_mode(tp);
-               tcp_schedule_ack(tp);
+               tcp_enter_quickack_mode(sk);
+               inet_csk_schedule_ack(sk);
 drop:
                __kfree_skb(skb);
                return;
@@ -2974,7 +3027,7 @@ drop:
        if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt + tcp_receive_window(tp)))
                goto out_of_window;
 
-       tcp_enter_quickack_mode(tp);
+       tcp_enter_quickack_mode(sk);
 
        if (before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
                /* Partial packet, seq < rcv_next < end_seq */
@@ -3003,7 +3056,7 @@ drop:
 
        /* Disable header prediction. */
        tp->pred_flags = 0;
-       tcp_schedule_ack(tp);
+       inet_csk_schedule_ack(sk);
 
        SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n",
                   tp->rcv_nxt, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq);
@@ -3027,7 +3080,7 @@ drop:
                u32 end_seq = TCP_SKB_CB(skb)->end_seq;
 
                if (seq == TCP_SKB_CB(skb1)->end_seq) {
-                       __skb_append(skb1, skb);
+                       __skb_append(skb1, skb, &tp->out_of_order_queue);
 
                        if (!tp->rx_opt.num_sacks ||
                            tp->selective_acks[0].end_seq != seq)
@@ -3071,7 +3124,7 @@ drop:
                               tcp_dsack_extend(tp, TCP_SKB_CB(skb1)->seq, end_seq);
                               break;
                       }
-                      __skb_unlink(skb1, skb1->list);
+                      __skb_unlink(skb1, &tp->out_of_order_queue);
                       tcp_dsack_extend(tp, TCP_SKB_CB(skb1)->seq, TCP_SKB_CB(skb1)->end_seq);
                       __kfree_skb(skb1);
                }
@@ -3088,8 +3141,9 @@ add_sack:
  * simplifies code)
  */
 static void
-tcp_collapse(struct sock *sk, struct sk_buff *head,
-            struct sk_buff *tail, u32 start, u32 end)
+tcp_collapse(struct sock *sk, struct sk_buff_head *list,
+            struct sk_buff *head, struct sk_buff *tail,
+            u32 start, u32 end)
 {
        struct sk_buff *skb;
 
@@ -3099,7 +3153,7 @@ tcp_collapse(struct sock *sk, struct sk_buff *head,
                /* No new bits? It is possible on ofo queue. */
                if (!before(start, TCP_SKB_CB(skb)->end_seq)) {
                        struct sk_buff *next = skb->next;
-                       __skb_unlink(skb, skb->list);
+                       __skb_unlink(skb, list);
                        __kfree_skb(skb);
                        NET_INC_STATS_BH(LINUX_MIB_TCPRCVCOLLAPSED);
                        skb = next;
@@ -3145,7 +3199,7 @@ tcp_collapse(struct sock *sk, struct sk_buff *head,
                nskb->mac.raw = nskb->head + (skb->mac.raw-skb->head);
                memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
                TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(nskb)->end_seq = start;
-               __skb_insert(nskb, skb->prev, skb, skb->list);
+               __skb_insert(nskb, skb->prev, skb, list);
                sk_stream_set_owner_r(nskb, sk);
 
                /* Copy data, releasing collapsed skbs. */
@@ -3164,7 +3218,7 @@ tcp_collapse(struct sock *sk, struct sk_buff *head,
                        }
                        if (!before(start, TCP_SKB_CB(skb)->end_seq)) {
                                struct sk_buff *next = skb->next;
-                               __skb_unlink(skb, skb->list);
+                               __skb_unlink(skb, list);
                                __kfree_skb(skb);
                                NET_INC_STATS_BH(LINUX_MIB_TCPRCVCOLLAPSED);
                                skb = next;
@@ -3200,7 +3254,8 @@ static void tcp_collapse_ofo_queue(struct sock *sk)
                if (skb == (struct sk_buff *)&tp->out_of_order_queue ||
                    after(TCP_SKB_CB(skb)->seq, end) ||
                    before(TCP_SKB_CB(skb)->end_seq, start)) {
-                       tcp_collapse(sk, head, skb, start, end);
+                       tcp_collapse(sk, &tp->out_of_order_queue,
+                                    head, skb, start, end);
                        head = skb;
                        if (skb == (struct sk_buff *)&tp->out_of_order_queue)
                                break;
@@ -3237,7 +3292,8 @@ static int tcp_prune_queue(struct sock *sk)
                tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss);
 
        tcp_collapse_ofo_queue(sk);
-       tcp_collapse(sk, sk->sk_receive_queue.next,
+       tcp_collapse(sk, &sk->sk_receive_queue,
+                    sk->sk_receive_queue.next,
                     (struct sk_buff*)&sk->sk_receive_queue,
                     tp->copied_seq, tp->rcv_nxt);
        sk_stream_mem_reclaim(sk);
@@ -3286,12 +3342,12 @@ void tcp_cwnd_application_limited(struct sock *sk)
 {
        struct tcp_sock *tp = tcp_sk(sk);
 
-       if (tp->ca_state == TCP_CA_Open &&
+       if (inet_csk(sk)->icsk_ca_state == TCP_CA_Open &&
            sk->sk_socket && !test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {
                /* Limited by application or receiver window. */
                u32 win_used = max(tp->snd_cwnd_used, 2U);
                if (win_used < tp->snd_cwnd) {
-                       tp->snd_ssthresh = tcp_current_ssthresh(tp);
+                       tp->snd_ssthresh = tcp_current_ssthresh(sk);
                        tp->snd_cwnd = (tp->snd_cwnd + win_used) >> 1;
                }
                tp->snd_cwnd_used = 0;
@@ -3370,13 +3426,13 @@ static void __tcp_ack_snd_check(struct sock *sk, int ofo_possible)
        struct tcp_sock *tp = tcp_sk(sk);
 
            /* More than one full frame received... */
-       if (((tp->rcv_nxt - tp->rcv_wup) > tp->ack.rcv_mss
+       if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss
             /* ... and right edge of window advances far enough.
              * (tcp_recvmsg() will send ACK otherwise). Or...
              */
             && __tcp_select_window(sk) >= tp->rcv_wnd) ||
            /* We ACK each frame or... */
-           tcp_in_quickack_mode(tp) ||
+           tcp_in_quickack_mode(sk) ||
            /* We have out of order data. */
            (ofo_possible &&
             skb_peek(&tp->out_of_order_queue))) {
@@ -3390,8 +3446,7 @@ static void __tcp_ack_snd_check(struct sock *sk, int ofo_possible)
 
 static __inline__ void tcp_ack_snd_check(struct sock *sk)
 {
-       struct tcp_sock *tp = tcp_sk(sk);
-       if (!tcp_ack_scheduled(tp)) {
+       if (!inet_csk_ack_scheduled(sk)) {
                /* We sent a data segment already. */
                return;
        }
@@ -3462,7 +3517,7 @@ static void tcp_check_urg(struct sock * sk, struct tcphdr * th)
                struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
                tp->copied_seq++;
                if (skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq)) {
-                       __skb_unlink(skb, skb->list);
+                       __skb_unlink(skb, &sk->sk_receive_queue);
                        __kfree_skb(skb);
                }
        }
@@ -3645,7 +3700,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                                    tp->rcv_nxt == tp->rcv_wup)
                                        tcp_store_ts_recent(tp);
 
-                               tcp_rcv_rtt_measure_ts(tp, skb);
+                               tcp_rcv_rtt_measure_ts(sk, skb);
 
                                /* We know that such packets are checksummed
                                 * on entry.
@@ -3678,7 +3733,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                                            tp->rcv_nxt == tp->rcv_wup)
                                                tcp_store_ts_recent(tp);
 
-                                       tcp_rcv_rtt_measure_ts(tp, skb);
+                                       tcp_rcv_rtt_measure_ts(sk, skb);
 
                                        __skb_pull(skb, tcp_header_len);
                                        tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
@@ -3699,7 +3754,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                                    tp->rcv_nxt == tp->rcv_wup)
                                        tcp_store_ts_recent(tp);
 
-                               tcp_rcv_rtt_measure_ts(tp, skb);
+                               tcp_rcv_rtt_measure_ts(sk, skb);
 
                                if ((int)skb->truesize > sk->sk_forward_alloc)
                                        goto step5;
@@ -3719,7 +3774,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                                /* Well, only one small jumplet in fast path... */
                                tcp_ack(sk, skb, FLAG_DATA);
                                tcp_data_snd_check(sk, tp);
-                               if (!tcp_ack_scheduled(tp))
+                               if (!inet_csk_ack_scheduled(sk))
                                        goto no_ack;
                        }
 
@@ -3741,7 +3796,7 @@ slow_path:
         * RFC1323: H1. Apply PAWS check first.
         */
        if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp &&
-           tcp_paws_discard(tp, skb)) {
+           tcp_paws_discard(sk, skb)) {
                if (!th->rst) {
                        NET_INC_STATS_BH(LINUX_MIB_PAWSESTABREJECTED);
                        tcp_send_dupack(sk, skb);
@@ -3788,7 +3843,7 @@ step5:
        if(th->ack)
                tcp_ack(sk, skb, FLAG_SLOWPATH);
 
-       tcp_rcv_rtt_measure_ts(tp, skb);
+       tcp_rcv_rtt_measure_ts(sk, skb);
 
        /* Process urgent data. */
        tcp_urg(sk, skb, th);
@@ -3817,6 +3872,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
        tcp_parse_options(skb, &tp->rx_opt, 0);
 
        if (th->ack) {
+               struct inet_connection_sock *icsk;
                /* rfc793:
                 * "If the state is SYN-SENT then
                 *    first check the ACK bit
@@ -3920,7 +3976,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
 
                tcp_init_metrics(sk);
 
-               tcp_init_congestion_control(tp);
+               tcp_init_congestion_control(sk);
 
                /* Prevent spurious tcp_cwnd_restart() on first data
                 * packet.
@@ -3930,7 +3986,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
                tcp_init_buffer_space(sk);
 
                if (sock_flag(sk, SOCK_KEEPOPEN))
-                       tcp_reset_keepalive_timer(sk, keepalive_time_when(tp));
+                       inet_csk_reset_keepalive_timer(sk, keepalive_time_when(tp));
 
                if (!tp->rx_opt.snd_wscale)
                        __tcp_fast_path_on(tp, tp->snd_wnd);
@@ -3942,7 +3998,11 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
                        sk_wake_async(sk, 0, POLL_OUT);
                }
 
-               if (sk->sk_write_pending || tp->defer_accept || tp->ack.pingpong) {
+               icsk = inet_csk(sk);
+
+               if (sk->sk_write_pending ||
+                   icsk->icsk_accept_queue.rskq_defer_accept ||
+                   icsk->icsk_ack.pingpong) {
                        /* Save one ACK. Data will be ready after
                         * several ticks, if write_pending is set.
                         *
@@ -3950,12 +4010,13 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
                         * look so _wonderfully_ clever, that I was not able
                         * to stand against the temptation 8)     --ANK
                         */
-                       tcp_schedule_ack(tp);
-                       tp->ack.lrcvtime = tcp_time_stamp;
-                       tp->ack.ato      = TCP_ATO_MIN;
-                       tcp_incr_quickack(tp);
-                       tcp_enter_quickack_mode(tp);
-                       tcp_reset_xmit_timer(sk, TCP_TIME_DACK, TCP_DELACK_MAX);
+                       inet_csk_schedule_ack(sk);
+                       icsk->icsk_ack.lrcvtime = tcp_time_stamp;
+                       icsk->icsk_ack.ato       = TCP_ATO_MIN;
+                       tcp_incr_quickack(sk);
+                       tcp_enter_quickack_mode(sk);
+                       inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
+                                                 TCP_DELACK_MAX, TCP_RTO_MAX);
 
 discard:
                        __kfree_skb(skb);
@@ -4111,7 +4172,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
        }
 
        if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp &&
-           tcp_paws_discard(tp, skb)) {
+           tcp_paws_discard(sk, skb)) {
                if (!th->rst) {
                        NET_INC_STATS_BH(LINUX_MIB_PAWSESTABREJECTED);
                        tcp_send_dupack(sk, skb);
@@ -4180,7 +4241,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                                 */
                                if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr &&
                                    !tp->srtt)
-                                       tcp_ack_saw_tstamp(tp, 0, 0);
+                                       tcp_ack_saw_tstamp(sk, NULL, 0);
 
                                if (tp->rx_opt.tstamp_ok)
                                        tp->advmss -= TCPOLEN_TSTAMP_ALIGNED;
@@ -4192,7 +4253,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 
                                tcp_init_metrics(sk);
 
-                               tcp_init_congestion_control(tp);
+                               tcp_init_congestion_control(sk);
 
                                /* Prevent spurious tcp_cwnd_restart() on
                                 * first data packet.
@@ -4227,9 +4288,9 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                                                return 1;
                                        }
 
-                                       tmo = tcp_fin_time(tp);
+                                       tmo = tcp_fin_time(sk);
                                        if (tmo > TCP_TIMEWAIT_LEN) {
-                                               tcp_reset_keepalive_timer(sk, tmo - TCP_TIMEWAIT_LEN);
+                                               inet_csk_reset_keepalive_timer(sk, tmo - TCP_TIMEWAIT_LEN);
                                        } else if (th->fin || sock_owned_by_user(sk)) {
                                                /* Bad case. We could lose such FIN otherwise.
                                                 * It is not a big problem, but it looks confusing
@@ -4237,7 +4298,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                                                 * if it spins in bh_lock_sock(), but it is really
                                                 * marginal case.
                                                 */
-                                               tcp_reset_keepalive_timer(sk, tmo);
+                                               inet_csk_reset_keepalive_timer(sk, tmo);
                                        } else {
                                                tcp_time_wait(sk, TCP_FIN_WAIT2, tmo);
                                                goto discard;
index 67c670886c1fda8f3f8beb156e4b23b36888eae1..13dfb391cdf17a376c301c9f56973db93696c1d6 100644 (file)
@@ -64,7 +64,9 @@
 #include <linux/times.h>
 
 #include <net/icmp.h>
+#include <net/inet_hashtables.h>
 #include <net/tcp.h>
+#include <net/transp_v6.h>
 #include <net/ipv6.h>
 #include <net/inet_common.h>
 #include <net/xfrm.h>
@@ -75,7 +77,6 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 
-extern int sysctl_ip_dynaddr;
 int sysctl_tcp_tw_reuse;
 int sysctl_tcp_low_latency;
 
@@ -88,463 +89,29 @@ static struct socket *tcp_socket;
 void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len,
                       struct sk_buff *skb);
 
-struct tcp_hashinfo __cacheline_aligned tcp_hashinfo = {
-       .__tcp_lhash_lock       =       RW_LOCK_UNLOCKED,
-       .__tcp_lhash_users      =       ATOMIC_INIT(0),
-       .__tcp_lhash_wait
-         = __WAIT_QUEUE_HEAD_INITIALIZER(tcp_hashinfo.__tcp_lhash_wait),
-       .__tcp_portalloc_lock   =       SPIN_LOCK_UNLOCKED
+struct inet_hashinfo __cacheline_aligned tcp_hashinfo = {
+       .lhash_lock     = RW_LOCK_UNLOCKED,
+       .lhash_users    = ATOMIC_INIT(0),
+       .lhash_wait     = __WAIT_QUEUE_HEAD_INITIALIZER(tcp_hashinfo.lhash_wait),
+       .portalloc_lock = SPIN_LOCK_UNLOCKED,
+       .port_rover     = 1024 - 1,
 };
 
-/*
- * This array holds the first and last local port number.
- * For high-usage systems, use sysctl to change this to
- * 32768-61000
- */
-int sysctl_local_port_range[2] = { 1024, 4999 };
-int tcp_port_rover = 1024 - 1;
-
-static __inline__ int tcp_hashfn(__u32 laddr, __u16 lport,
-                                __u32 faddr, __u16 fport)
-{
-       int h = (laddr ^ lport) ^ (faddr ^ fport);
-       h ^= h >> 16;
-       h ^= h >> 8;
-       return h & (tcp_ehash_size - 1);
-}
-
-static __inline__ int tcp_sk_hashfn(struct sock *sk)
-{
-       struct inet_sock *inet = inet_sk(sk);
-       __u32 laddr = inet->rcv_saddr;
-       __u16 lport = inet->num;
-       __u32 faddr = inet->daddr;
-       __u16 fport = inet->dport;
-
-       return tcp_hashfn(laddr, lport, faddr, fport);
-}
-
-/* Allocate and initialize a new TCP local port bind bucket.
- * The bindhash mutex for snum's hash chain must be held here.
- */
-struct tcp_bind_bucket *tcp_bucket_create(struct tcp_bind_hashbucket *head,
-                                         unsigned short snum)
-{
-       struct tcp_bind_bucket *tb = kmem_cache_alloc(tcp_bucket_cachep,
-                                                     SLAB_ATOMIC);
-       if (tb) {
-               tb->port = snum;
-               tb->fastreuse = 0;
-               INIT_HLIST_HEAD(&tb->owners);
-               hlist_add_head(&tb->node, &head->chain);
-       }
-       return tb;
-}
-
-/* Caller must hold hashbucket lock for this tb with local BH disabled */
-void tcp_bucket_destroy(struct tcp_bind_bucket *tb)
-{
-       if (hlist_empty(&tb->owners)) {
-               __hlist_del(&tb->node);
-               kmem_cache_free(tcp_bucket_cachep, tb);
-       }
-}
-
-/* Caller must disable local BH processing. */
-static __inline__ void __tcp_inherit_port(struct sock *sk, struct sock *child)
-{
-       struct tcp_bind_hashbucket *head =
-                               &tcp_bhash[tcp_bhashfn(inet_sk(child)->num)];
-       struct tcp_bind_bucket *tb;
-
-       spin_lock(&head->lock);
-       tb = tcp_sk(sk)->bind_hash;
-       sk_add_bind_node(child, &tb->owners);
-       tcp_sk(child)->bind_hash = tb;
-       spin_unlock(&head->lock);
-}
-
-inline void tcp_inherit_port(struct sock *sk, struct sock *child)
-{
-       local_bh_disable();
-       __tcp_inherit_port(sk, child);
-       local_bh_enable();
-}
-
-void tcp_bind_hash(struct sock *sk, struct tcp_bind_bucket *tb,
-                  unsigned short snum)
-{
-       inet_sk(sk)->num = snum;
-       sk_add_bind_node(sk, &tb->owners);
-       tcp_sk(sk)->bind_hash = tb;
-}
-
-static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb)
-{
-       const u32 sk_rcv_saddr = tcp_v4_rcv_saddr(sk);
-       struct sock *sk2;
-       struct hlist_node *node;
-       int reuse = sk->sk_reuse;
-
-       sk_for_each_bound(sk2, node, &tb->owners) {
-               if (sk != sk2 &&
-                   !tcp_v6_ipv6only(sk2) &&
-                   (!sk->sk_bound_dev_if ||
-                    !sk2->sk_bound_dev_if ||
-                    sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) {
-                       if (!reuse || !sk2->sk_reuse ||
-                           sk2->sk_state == TCP_LISTEN) {
-                               const u32 sk2_rcv_saddr = tcp_v4_rcv_saddr(sk2);
-                               if (!sk2_rcv_saddr || !sk_rcv_saddr ||
-                                   sk2_rcv_saddr == sk_rcv_saddr)
-                                       break;
-                       }
-               }
-       }
-       return node != NULL;
-}
-
-/* Obtain a reference to a local port for the given sock,
- * if snum is zero it means select any available local port.
- */
 static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
 {
-       struct tcp_bind_hashbucket *head;
-       struct hlist_node *node;
-       struct tcp_bind_bucket *tb;
-       int ret;
-
-       local_bh_disable();
-       if (!snum) {
-               int low = sysctl_local_port_range[0];
-               int high = sysctl_local_port_range[1];
-               int remaining = (high - low) + 1;
-               int rover;
-
-               spin_lock(&tcp_portalloc_lock);
-               if (tcp_port_rover < low)
-                       rover = low;
-               else
-                       rover = tcp_port_rover;
-               do {
-                       rover++;
-                       if (rover > high)
-                               rover = low;
-                       head = &tcp_bhash[tcp_bhashfn(rover)];
-                       spin_lock(&head->lock);
-                       tb_for_each(tb, node, &head->chain)
-                               if (tb->port == rover)
-                                       goto next;
-                       break;
-               next:
-                       spin_unlock(&head->lock);
-               } while (--remaining > 0);
-               tcp_port_rover = rover;
-               spin_unlock(&tcp_portalloc_lock);
-
-               /* Exhausted local port range during search?  It is not
-                * possible for us to be holding one of the bind hash
-                * locks if this test triggers, because if 'remaining'
-                * drops to zero, we broke out of the do/while loop at
-                * the top level, not from the 'break;' statement.
-                */
-               ret = 1;
-               if (unlikely(remaining <= 0))
-                       goto fail;
-
-               /* OK, here is the one we will use.  HEAD is
-                * non-NULL and we hold it's mutex.
-                */
-               snum = rover;
-       } else {
-               head = &tcp_bhash[tcp_bhashfn(snum)];
-               spin_lock(&head->lock);
-               tb_for_each(tb, node, &head->chain)
-                       if (tb->port == snum)
-                               goto tb_found;
-       }
-       tb = NULL;
-       goto tb_not_found;
-tb_found:
-       if (!hlist_empty(&tb->owners)) {
-               if (sk->sk_reuse > 1)
-                       goto success;
-               if (tb->fastreuse > 0 &&
-                   sk->sk_reuse && sk->sk_state != TCP_LISTEN) {
-                       goto success;
-               } else {
-                       ret = 1;
-                       if (tcp_bind_conflict(sk, tb))
-                               goto fail_unlock;
-               }
-       }
-tb_not_found:
-       ret = 1;
-       if (!tb && (tb = tcp_bucket_create(head, snum)) == NULL)
-               goto fail_unlock;
-       if (hlist_empty(&tb->owners)) {
-               if (sk->sk_reuse && sk->sk_state != TCP_LISTEN)
-                       tb->fastreuse = 1;
-               else
-                       tb->fastreuse = 0;
-       } else if (tb->fastreuse &&
-                  (!sk->sk_reuse || sk->sk_state == TCP_LISTEN))
-               tb->fastreuse = 0;
-success:
-       if (!tcp_sk(sk)->bind_hash)
-               tcp_bind_hash(sk, tb, snum);
-       BUG_TRAP(tcp_sk(sk)->bind_hash == tb);
-       ret = 0;
-
-fail_unlock:
-       spin_unlock(&head->lock);
-fail:
-       local_bh_enable();
-       return ret;
-}
-
-/* Get rid of any references to a local port held by the
- * given sock.
- */
-static void __tcp_put_port(struct sock *sk)
-{
-       struct inet_sock *inet = inet_sk(sk);
-       struct tcp_bind_hashbucket *head = &tcp_bhash[tcp_bhashfn(inet->num)];
-       struct tcp_bind_bucket *tb;
-
-       spin_lock(&head->lock);
-       tb = tcp_sk(sk)->bind_hash;
-       __sk_del_bind_node(sk);
-       tcp_sk(sk)->bind_hash = NULL;
-       inet->num = 0;
-       tcp_bucket_destroy(tb);
-       spin_unlock(&head->lock);
-}
-
-void tcp_put_port(struct sock *sk)
-{
-       local_bh_disable();
-       __tcp_put_port(sk);
-       local_bh_enable();
-}
-
-/* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it can be very bad on SMP.
- * Look, when several writers sleep and reader wakes them up, all but one
- * immediately hit write lock and grab all the cpus. Exclusive sleep solves
- * this, _but_ remember, it adds useless work on UP machines (wake up each
- * exclusive lock release). It should be ifdefed really.
- */
-
-void tcp_listen_wlock(void)
-{
-       write_lock(&tcp_lhash_lock);
-
-       if (atomic_read(&tcp_lhash_users)) {
-               DEFINE_WAIT(wait);
-
-               for (;;) {
-                       prepare_to_wait_exclusive(&tcp_lhash_wait,
-                                               &wait, TASK_UNINTERRUPTIBLE);
-                       if (!atomic_read(&tcp_lhash_users))
-                               break;
-                       write_unlock_bh(&tcp_lhash_lock);
-                       schedule();
-                       write_lock_bh(&tcp_lhash_lock);
-               }
-
-               finish_wait(&tcp_lhash_wait, &wait);
-       }
-}
-
-static __inline__ void __tcp_v4_hash(struct sock *sk, const int listen_possible)
-{
-       struct hlist_head *list;
-       rwlock_t *lock;
-
-       BUG_TRAP(sk_unhashed(sk));
-       if (listen_possible && sk->sk_state == TCP_LISTEN) {
-               list = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
-               lock = &tcp_lhash_lock;
-               tcp_listen_wlock();
-       } else {
-               list = &tcp_ehash[(sk->sk_hashent = tcp_sk_hashfn(sk))].chain;
-               lock = &tcp_ehash[sk->sk_hashent].lock;
-               write_lock(lock);
-       }
-       __sk_add_node(sk, list);
-       sock_prot_inc_use(sk->sk_prot);
-       write_unlock(lock);
-       if (listen_possible && sk->sk_state == TCP_LISTEN)
-               wake_up(&tcp_lhash_wait);
+       return inet_csk_get_port(&tcp_hashinfo, sk, snum);
 }
 
 static void tcp_v4_hash(struct sock *sk)
 {
-       if (sk->sk_state != TCP_CLOSE) {
-               local_bh_disable();
-               __tcp_v4_hash(sk, 1);
-               local_bh_enable();
-       }
+       inet_hash(&tcp_hashinfo, sk);
 }
 
 void tcp_unhash(struct sock *sk)
 {
-       rwlock_t *lock;
-
-       if (sk_unhashed(sk))
-               goto ende;
-
-       if (sk->sk_state == TCP_LISTEN) {
-               local_bh_disable();
-               tcp_listen_wlock();
-               lock = &tcp_lhash_lock;
-       } else {
-               struct tcp_ehash_bucket *head = &tcp_ehash[sk->sk_hashent];
-               lock = &head->lock;
-               write_lock_bh(&head->lock);
-       }
-
-       if (__sk_del_node_init(sk))
-               sock_prot_dec_use(sk->sk_prot);
-       write_unlock_bh(lock);
-
- ende:
-       if (sk->sk_state == TCP_LISTEN)
-               wake_up(&tcp_lhash_wait);
-}
-
-/* Don't inline this cruft.  Here are some nice properties to
- * exploit here.  The BSD API does not allow a listening TCP
- * to specify the remote port nor the remote address for the
- * connection.  So always assume those are both wildcarded
- * during the search since they can never be otherwise.
- */
-static struct sock *__tcp_v4_lookup_listener(struct hlist_head *head, u32 daddr,
-                                            unsigned short hnum, int dif)
-{
-       struct sock *result = NULL, *sk;
-       struct hlist_node *node;
-       int score, hiscore;
-
-       hiscore=-1;
-       sk_for_each(sk, node, head) {
-               struct inet_sock *inet = inet_sk(sk);
-
-               if (inet->num == hnum && !ipv6_only_sock(sk)) {
-                       __u32 rcv_saddr = inet->rcv_saddr;
-
-                       score = (sk->sk_family == PF_INET ? 1 : 0);
-                       if (rcv_saddr) {
-                               if (rcv_saddr != daddr)
-                                       continue;
-                               score+=2;
-                       }
-                       if (sk->sk_bound_dev_if) {
-                               if (sk->sk_bound_dev_if != dif)
-                                       continue;
-                               score+=2;
-                       }
-                       if (score == 5)
-                               return sk;
-                       if (score > hiscore) {
-                               hiscore = score;
-                               result = sk;
-                       }
-               }
-       }
-       return result;
-}
-
-/* Optimize the common listener case. */
-static inline struct sock *tcp_v4_lookup_listener(u32 daddr,
-               unsigned short hnum, int dif)
-{
-       struct sock *sk = NULL;
-       struct hlist_head *head;
-
-       read_lock(&tcp_lhash_lock);
-       head = &tcp_listening_hash[tcp_lhashfn(hnum)];
-       if (!hlist_empty(head)) {
-               struct inet_sock *inet = inet_sk((sk = __sk_head(head)));
-
-               if (inet->num == hnum && !sk->sk_node.next &&
-                   (!inet->rcv_saddr || inet->rcv_saddr == daddr) &&
-                   (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) &&
-                   !sk->sk_bound_dev_if)
-                       goto sherry_cache;
-               sk = __tcp_v4_lookup_listener(head, daddr, hnum, dif);
-       }
-       if (sk) {
-sherry_cache:
-               sock_hold(sk);
-       }
-       read_unlock(&tcp_lhash_lock);
-       return sk;
+       inet_unhash(&tcp_hashinfo, sk);
 }
 
-/* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
- * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
- *
- * Local BH must be disabled here.
- */
-
-static inline struct sock *__tcp_v4_lookup_established(u32 saddr, u16 sport,
-                                                      u32 daddr, u16 hnum,
-                                                      int dif)
-{
-       struct tcp_ehash_bucket *head;
-       TCP_V4_ADDR_COOKIE(acookie, saddr, daddr)
-       __u32 ports = TCP_COMBINED_PORTS(sport, hnum);
-       struct sock *sk;
-       struct hlist_node *node;
-       /* Optimize here for direct hit, only listening connections can
-        * have wildcards anyways.
-        */
-       int hash = tcp_hashfn(daddr, hnum, saddr, sport);
-       head = &tcp_ehash[hash];
-       read_lock(&head->lock);
-       sk_for_each(sk, node, &head->chain) {
-               if (TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
-                       goto hit; /* You sunk my battleship! */
-       }
-
-       /* Must check for a TIME_WAIT'er before going to listener hash. */
-       sk_for_each(sk, node, &(head + tcp_ehash_size)->chain) {
-               if (TCP_IPV4_TW_MATCH(sk, acookie, saddr, daddr, ports, dif))
-                       goto hit;
-       }
-       sk = NULL;
-out:
-       read_unlock(&head->lock);
-       return sk;
-hit:
-       sock_hold(sk);
-       goto out;
-}
-
-static inline struct sock *__tcp_v4_lookup(u32 saddr, u16 sport,
-                                          u32 daddr, u16 hnum, int dif)
-{
-       struct sock *sk = __tcp_v4_lookup_established(saddr, sport,
-                                                     daddr, hnum, dif);
-
-       return sk ? : tcp_v4_lookup_listener(daddr, hnum, dif);
-}
-
-inline struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr,
-                                 u16 dport, int dif)
-{
-       struct sock *sk;
-
-       local_bh_disable();
-       sk = __tcp_v4_lookup(saddr, sport, daddr, ntohs(dport), dif);
-       local_bh_enable();
-
-       return sk;
-}
-
-EXPORT_SYMBOL_GPL(tcp_v4_lookup);
-
 static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb)
 {
        return secure_tcp_sequence_number(skb->nh.iph->daddr,
@@ -555,27 +122,28 @@ static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb)
 
 /* called with local bh disabled */
 static int __tcp_v4_check_established(struct sock *sk, __u16 lport,
-                                     struct tcp_tw_bucket **twp)
+                                     struct inet_timewait_sock **twp)
 {
        struct inet_sock *inet = inet_sk(sk);
        u32 daddr = inet->rcv_saddr;
        u32 saddr = inet->daddr;
        int dif = sk->sk_bound_dev_if;
-       TCP_V4_ADDR_COOKIE(acookie, saddr, daddr)
-       __u32 ports = TCP_COMBINED_PORTS(inet->dport, lport);
-       int hash = tcp_hashfn(daddr, lport, saddr, inet->dport);
-       struct tcp_ehash_bucket *head = &tcp_ehash[hash];
+       INET_ADDR_COOKIE(acookie, saddr, daddr)
+       const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
+       const int hash = inet_ehashfn(daddr, lport, saddr, inet->dport, tcp_hashinfo.ehash_size);
+       struct inet_ehash_bucket *head = &tcp_hashinfo.ehash[hash];
        struct sock *sk2;
-       struct hlist_node *node;
-       struct tcp_tw_bucket *tw;
+       const struct hlist_node *node;
+       struct inet_timewait_sock *tw;
 
        write_lock(&head->lock);
 
        /* Check TIME-WAIT sockets first. */
-       sk_for_each(sk2, node, &(head + tcp_ehash_size)->chain) {
-               tw = (struct tcp_tw_bucket *)sk2;
+       sk_for_each(sk2, node, &(head + tcp_hashinfo.ehash_size)->chain) {
+               tw = inet_twsk(sk2);
 
-               if (TCP_IPV4_TW_MATCH(sk2, acookie, saddr, daddr, ports, dif)) {
+               if (INET_TW_MATCH(sk2, acookie, saddr, daddr, ports, dif)) {
+                       const struct tcp_timewait_sock *tcptw = tcp_twsk(sk2);
                        struct tcp_sock *tp = tcp_sk(sk);
 
                        /* With PAWS, it is safe from the viewpoint
@@ -592,15 +160,15 @@ static int __tcp_v4_check_established(struct sock *sk, __u16 lport,
                           fall back to VJ's scheme and use initial
                           timestamp retrieved from peer table.
                         */
-                       if (tw->tw_ts_recent_stamp &&
+                       if (tcptw->tw_ts_recent_stamp &&
                            (!twp || (sysctl_tcp_tw_reuse &&
                                      xtime.tv_sec -
-                                     tw->tw_ts_recent_stamp > 1))) {
-                               if ((tp->write_seq =
-                                               tw->tw_snd_nxt + 65535 + 2) == 0)
+                                     tcptw->tw_ts_recent_stamp > 1))) {
+                               tp->write_seq = tcptw->tw_snd_nxt + 65535 + 2;
+                               if (tp->write_seq == 0)
                                        tp->write_seq = 1;
-                               tp->rx_opt.ts_recent       = tw->tw_ts_recent;
-                               tp->rx_opt.ts_recent_stamp = tw->tw_ts_recent_stamp;
+                               tp->rx_opt.ts_recent       = tcptw->tw_ts_recent;
+                               tp->rx_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp;
                                sock_hold(sk2);
                                goto unique;
                        } else
@@ -611,7 +179,7 @@ static int __tcp_v4_check_established(struct sock *sk, __u16 lport,
 
        /* And established part... */
        sk_for_each(sk2, node, &head->chain) {
-               if (TCP_IPV4_MATCH(sk2, acookie, saddr, daddr, ports, dif))
+               if (INET_MATCH(sk2, acookie, saddr, daddr, ports, dif))
                        goto not_unique;
        }
 
@@ -631,10 +199,10 @@ unique:
                NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
        } else if (tw) {
                /* Silly. Should hash-dance instead... */
-               tcp_tw_deschedule(tw);
+               inet_twsk_deschedule(tw, &tcp_death_row);
                NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
 
-               tcp_tw_put(tw);
+               inet_twsk_put(tw);
        }
 
        return 0;
@@ -657,9 +225,9 @@ static inline u32 connect_port_offset(const struct sock *sk)
  */
 static inline int tcp_v4_hash_connect(struct sock *sk)
 {
-       unsigned short snum = inet_sk(sk)->num;
-       struct tcp_bind_hashbucket *head;
-       struct tcp_bind_bucket *tb;
+       const unsigned short snum = inet_sk(sk)->num;
+       struct inet_bind_hashbucket *head;
+       struct inet_bind_bucket *tb;
        int ret;
 
        if (!snum) {
@@ -671,19 +239,19 @@ static inline int tcp_v4_hash_connect(struct sock *sk)
                static u32 hint;
                u32 offset = hint + connect_port_offset(sk);
                struct hlist_node *node;
-               struct tcp_tw_bucket *tw = NULL;
+               struct inet_timewait_sock *tw = NULL;
 
                local_bh_disable();
                for (i = 1; i <= range; i++) {
                        port = low + (i + offset) % range;
-                       head = &tcp_bhash[tcp_bhashfn(port)];
+                       head = &tcp_hashinfo.bhash[inet_bhashfn(port, tcp_hashinfo.bhash_size)];
                        spin_lock(&head->lock);
 
                        /* Does not bother with rcv_saddr checks,
                         * because the established check is already
                         * unique enough.
                         */
-                       tb_for_each(tb, node, &head->chain) {
+                       inet_bind_bucket_for_each(tb, node, &head->chain) {
                                if (tb->port == port) {
                                        BUG_TRAP(!hlist_empty(&tb->owners));
                                        if (tb->fastreuse >= 0)
@@ -696,7 +264,7 @@ static inline int tcp_v4_hash_connect(struct sock *sk)
                                }
                        }
 
-                       tb = tcp_bucket_create(head, port);
+                       tb = inet_bind_bucket_create(tcp_hashinfo.bind_bucket_cachep, head, port);
                        if (!tb) {
                                spin_unlock(&head->lock);
                                break;
@@ -715,27 +283,27 @@ ok:
                hint += i;
 
                /* Head lock still held and bh's disabled */
-               tcp_bind_hash(sk, tb, port);
+               inet_bind_hash(sk, tb, port);
                if (sk_unhashed(sk)) {
                        inet_sk(sk)->sport = htons(port);
-                       __tcp_v4_hash(sk, 0);
+                       __inet_hash(&tcp_hashinfo, sk, 0);
                }
                spin_unlock(&head->lock);
 
                if (tw) {
-                       tcp_tw_deschedule(tw);
-                       tcp_tw_put(tw);
+                       inet_twsk_deschedule(tw, &tcp_death_row);;
+                       inet_twsk_put(tw);
                }
 
                ret = 0;
                goto out;
        }
 
-       head  = &tcp_bhash[tcp_bhashfn(snum)];
-       tb  = tcp_sk(sk)->bind_hash;
+       head = &tcp_hashinfo.bhash[inet_bhashfn(snum, tcp_hashinfo.bhash_size)];
+       tb  = inet_csk(sk)->icsk_bind_hash;
        spin_lock_bh(&head->lock);
        if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) {
-               __tcp_v4_hash(sk, 0);
+               __inet_hash(&tcp_hashinfo, sk, 0);
                spin_unlock_bh(&head->lock);
                return 0;
        } else {
@@ -798,7 +366,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                tp->write_seq              = 0;
        }
 
-       if (sysctl_tcp_tw_recycle &&
+       if (tcp_death_row.sysctl_tw_recycle &&
            !tp->rx_opt.ts_recent_stamp && rt->rt_dst == daddr) {
                struct inet_peer *peer = rt_get_peer(rt);
 
@@ -837,8 +405,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                goto failure;
 
        /* OK, now commit destination to socket.  */
-       __sk_dst_set(sk, &rt->u.dst);
-       tcp_v4_setup_caps(sk, &rt->u.dst);
+       sk_setup_caps(sk, &rt->u.dst);
 
        if (!tp->write_seq)
                tp->write_seq = secure_tcp_sequence_number(inet->saddr,
@@ -864,53 +431,6 @@ failure:
        return err;
 }
 
-static __inline__ int tcp_v4_iif(struct sk_buff *skb)
-{
-       return ((struct rtable *)skb->dst)->rt_iif;
-}
-
-static __inline__ u32 tcp_v4_synq_hash(u32 raddr, u16 rport, u32 rnd)
-{
-       return (jhash_2words(raddr, (u32) rport, rnd) & (TCP_SYNQ_HSIZE - 1));
-}
-
-static struct request_sock *tcp_v4_search_req(struct tcp_sock *tp,
-                                             struct request_sock ***prevp,
-                                             __u16 rport,
-                                             __u32 raddr, __u32 laddr)
-{
-       struct listen_sock *lopt = tp->accept_queue.listen_opt;
-       struct request_sock *req, **prev;
-
-       for (prev = &lopt->syn_table[tcp_v4_synq_hash(raddr, rport, lopt->hash_rnd)];
-            (req = *prev) != NULL;
-            prev = &req->dl_next) {
-               const struct inet_request_sock *ireq = inet_rsk(req);
-
-               if (ireq->rmt_port == rport &&
-                   ireq->rmt_addr == raddr &&
-                   ireq->loc_addr == laddr &&
-                   TCP_INET_FAMILY(req->rsk_ops->family)) {
-                       BUG_TRAP(!req->sk);
-                       *prevp = prev;
-                       break;
-               }
-       }
-
-       return req;
-}
-
-static void tcp_v4_synq_add(struct sock *sk, struct request_sock *req)
-{
-       struct tcp_sock *tp = tcp_sk(sk);
-       struct listen_sock *lopt = tp->accept_queue.listen_opt;
-       u32 h = tcp_v4_synq_hash(inet_rsk(req)->rmt_addr, inet_rsk(req)->rmt_port, lopt->hash_rnd);
-
-       reqsk_queue_hash_req(&tp->accept_queue, h, req, TCP_TIMEOUT_INIT);
-       tcp_synq_added(sk);
-}
-
-
 /*
  * This routine does path mtu discovery as defined in RFC1191.
  */
@@ -993,14 +513,14 @@ void tcp_v4_err(struct sk_buff *skb, u32 info)
                return;
        }
 
-       sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr,
-                          th->source, tcp_v4_iif(skb));
+       sk = inet_lookup(&tcp_hashinfo, iph->daddr, th->dest, iph->saddr,
+                        th->source, inet_iif(skb));
        if (!sk) {
                ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
                return;
        }
        if (sk->sk_state == TCP_TIME_WAIT) {
-               tcp_tw_put((struct tcp_tw_bucket *)sk);
+               inet_twsk_put((struct inet_timewait_sock *)sk);
                return;
        }
 
@@ -1054,8 +574,8 @@ void tcp_v4_err(struct sk_buff *skb, u32 info)
                if (sock_owned_by_user(sk))
                        goto out;
 
-               req = tcp_v4_search_req(tp, &prev, th->dest,
-                                       iph->daddr, iph->saddr);
+               req = inet_csk_search_req(sk, &prev, th->dest,
+                                         iph->daddr, iph->saddr);
                if (!req)
                        goto out;
 
@@ -1075,7 +595,7 @@ void tcp_v4_err(struct sk_buff *skb, u32 info)
                 * created socket, and POSIX does not want network
                 * errors returned from accept().
                 */
-               tcp_synq_drop(sk, req, prev);
+               inet_csk_reqsk_queue_drop(sk, req, prev);
                goto out;
 
        case TCP_SYN_SENT:
@@ -1245,12 +765,13 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
 
 static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb)
 {
-       struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk;
+       struct inet_timewait_sock *tw = inet_twsk(sk);
+       const struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
 
-       tcp_v4_send_ack(skb, tw->tw_snd_nxt, tw->tw_rcv_nxt,
-                       tw->tw_rcv_wnd >> tw->tw_rcv_wscale, tw->tw_ts_recent);
+       tcp_v4_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
+                       tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, tcptw->tw_ts_recent);
 
-       tcp_tw_put(tw);
+       inet_twsk_put(tw);
 }
 
 static void tcp_v4_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req)
@@ -1259,36 +780,6 @@ static void tcp_v4_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req)
                        req->ts_recent);
 }
 
-static struct dst_entry* tcp_v4_route_req(struct sock *sk,
-                                         struct request_sock *req)
-{
-       struct rtable *rt;
-       const struct inet_request_sock *ireq = inet_rsk(req);
-       struct ip_options *opt = inet_rsk(req)->opt;
-       struct flowi fl = { .oif = sk->sk_bound_dev_if,
-                           .nl_u = { .ip4_u =
-                                     { .daddr = ((opt && opt->srr) ?
-                                                 opt->faddr :
-                                                 ireq->rmt_addr),
-                                       .saddr = ireq->loc_addr,
-                                       .tos = RT_CONN_FLAGS(sk) } },
-                           .proto = IPPROTO_TCP,
-                           .uli_u = { .ports =
-                                      { .sport = inet_sk(sk)->sport,
-                                        .dport = ireq->rmt_port } } };
-
-       if (ip_route_output_flow(&rt, &fl, sk, 0)) {
-               IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
-               return NULL;
-       }
-       if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) {
-               ip_rt_put(rt);
-               IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
-               return NULL;
-       }
-       return &rt->u.dst;
-}
-
 /*
  *     Send a SYN-ACK after having received an ACK.
  *     This still operates on a request_sock only, not on a big
@@ -1302,7 +793,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
        struct sk_buff * skb;
 
        /* First, grab a route. */
-       if (!dst && (dst = tcp_v4_route_req(sk, req)) == NULL)
+       if (!dst && (dst = inet_csk_route_req(sk, req)) == NULL)
                goto out;
 
        skb = tcp_make_synack(sk, dst, req);
@@ -1404,7 +895,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
         * limitations, they conserve resources and peer is
         * evidently real one.
         */
-       if (tcp_synq_is_full(sk) && !isn) {
+       if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
 #ifdef CONFIG_SYN_COOKIES
                if (sysctl_tcp_syncookies) {
                        want_cookie = 1;
@@ -1418,7 +909,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
         * clogging syn queue with openreqs with exponentially increasing
         * timeout.
         */
-       if (sk_acceptq_is_full(sk) && tcp_synq_young(sk) > 1)
+       if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
                goto drop;
 
        req = reqsk_alloc(&tcp_request_sock_ops);
@@ -1474,8 +965,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
                 * are made in the function processing timewait state.
                 */
                if (tmp_opt.saw_tstamp &&
-                   sysctl_tcp_tw_recycle &&
-                   (dst = tcp_v4_route_req(sk, req)) != NULL &&
+                   tcp_death_row.sysctl_tw_recycle &&
+                   (dst = inet_csk_route_req(sk, req)) != NULL &&
                    (peer = rt_get_peer((struct rtable *)dst)) != NULL &&
                    peer->v4daddr == saddr) {
                        if (xtime.tv_sec < peer->tcp_ts_stamp + TCP_PAWS_MSL &&
@@ -1488,7 +979,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
                }
                /* Kill the following clause, if you dislike this way. */
                else if (!sysctl_tcp_syncookies &&
-                        (sysctl_max_syn_backlog - tcp_synq_len(sk) <
+                        (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) <
                          (sysctl_max_syn_backlog >> 2)) &&
                         (!peer || !peer->tcp_ts_stamp) &&
                         (!dst || !dst_metric(dst, RTAX_RTT))) {
@@ -1499,11 +990,10 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
                         * to destinations, already remembered
                         * to the moment of synflood.
                         */
-                       LIMIT_NETDEBUG(printk(KERN_DEBUG "TCP: drop open "
-                                             "request from %u.%u."
-                                             "%u.%u/%u\n",
-                                             NIPQUAD(saddr),
-                                             ntohs(skb->h.th->source)));
+                       LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open "
+                                      "request from %u.%u.%u.%u/%u\n",
+                                      NIPQUAD(saddr),
+                                      ntohs(skb->h.th->source));
                        dst_release(dst);
                        goto drop_and_free;
                }
@@ -1518,7 +1008,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        if (want_cookie) {
                reqsk_free(req);
        } else {
-               tcp_v4_synq_add(sk, req);
+               inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
        }
        return 0;
 
@@ -1546,15 +1036,14 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        if (sk_acceptq_is_full(sk))
                goto exit_overflow;
 
-       if (!dst && (dst = tcp_v4_route_req(sk, req)) == NULL)
+       if (!dst && (dst = inet_csk_route_req(sk, req)) == NULL)
                goto exit;
 
        newsk = tcp_create_openreq_child(sk, req, skb);
        if (!newsk)
                goto exit;
 
-       newsk->sk_dst_cache = dst;
-       tcp_v4_setup_caps(newsk, dst);
+       sk_setup_caps(newsk, dst);
 
        newtp                 = tcp_sk(newsk);
        newinet               = inet_sk(newsk);
@@ -1564,7 +1053,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        newinet->saddr        = ireq->loc_addr;
        newinet->opt          = ireq->opt;
        ireq->opt             = NULL;
-       newinet->mc_index     = tcp_v4_iif(skb);
+       newinet->mc_index     = inet_iif(skb);
        newinet->mc_ttl       = skb->nh.iph->ttl;
        newtp->ext_header_len = 0;
        if (newinet->opt)
@@ -1575,8 +1064,8 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
        tcp_initialize_rcv_mss(newsk);
 
-       __tcp_v4_hash(newsk, 0);
-       __tcp_inherit_port(sk, newsk);
+       __inet_hash(&tcp_hashinfo, newsk, 0);
+       __inet_inherit_port(&tcp_hashinfo, sk, newsk);
 
        return newsk;
 
@@ -1592,27 +1081,24 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
 {
        struct tcphdr *th = skb->h.th;
        struct iphdr *iph = skb->nh.iph;
-       struct tcp_sock *tp = tcp_sk(sk);
        struct sock *nsk;
        struct request_sock **prev;
        /* Find possible connection requests. */
-       struct request_sock *req = tcp_v4_search_req(tp, &prev, th->source,
-                                                    iph->saddr, iph->daddr);
+       struct request_sock *req = inet_csk_search_req(sk, &prev, th->source,
+                                                      iph->saddr, iph->daddr);
        if (req)
                return tcp_check_req(sk, skb, req, prev);
 
-       nsk = __tcp_v4_lookup_established(skb->nh.iph->saddr,
-                                         th->source,
-                                         skb->nh.iph->daddr,
-                                         ntohs(th->dest),
-                                         tcp_v4_iif(skb));
+       nsk = __inet_lookup_established(&tcp_hashinfo, skb->nh.iph->saddr,
+                                       th->source, skb->nh.iph->daddr,
+                                       ntohs(th->dest), inet_iif(skb));
 
        if (nsk) {
                if (nsk->sk_state != TCP_TIME_WAIT) {
                        bh_lock_sock(nsk);
                        return nsk;
                }
-               tcp_tw_put((struct tcp_tw_bucket *)nsk);
+               inet_twsk_put((struct inet_timewait_sock *)nsk);
                return NULL;
        }
 
@@ -1631,7 +1117,7 @@ static int tcp_v4_checksum_init(struct sk_buff *skb)
                                  skb->nh.iph->daddr, skb->csum))
                        return 0;
 
-               LIMIT_NETDEBUG(printk(KERN_DEBUG "hw tcp v4 csum failed\n"));
+               LIMIT_NETDEBUG(KERN_DEBUG "hw tcp v4 csum failed\n");
                skb->ip_summed = CHECKSUM_NONE;
        }
        if (skb->len <= 76) {
@@ -1747,9 +1233,9 @@ int tcp_v4_rcv(struct sk_buff *skb)
        TCP_SKB_CB(skb)->flags   = skb->nh.iph->tos;
        TCP_SKB_CB(skb)->sacked  = 0;
 
-       sk = __tcp_v4_lookup(skb->nh.iph->saddr, th->source,
-                            skb->nh.iph->daddr, ntohs(th->dest),
-                            tcp_v4_iif(skb));
+       sk = __inet_lookup(&tcp_hashinfo, skb->nh.iph->saddr, th->source,
+                          skb->nh.iph->daddr, ntohs(th->dest),
+                          inet_iif(skb));
 
        if (!sk)
                goto no_tcp_socket;
@@ -1801,24 +1287,26 @@ discard_and_relse:
 
 do_time_wait:
        if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
-               tcp_tw_put((struct tcp_tw_bucket *) sk);
+               inet_twsk_put((struct inet_timewait_sock *) sk);
                goto discard_it;
        }
 
        if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) {
                TCP_INC_STATS_BH(TCP_MIB_INERRS);
-               tcp_tw_put((struct tcp_tw_bucket *) sk);
+               inet_twsk_put((struct inet_timewait_sock *) sk);
                goto discard_it;
        }
-       switch (tcp_timewait_state_process((struct tcp_tw_bucket *)sk,
-                                          skb, th, skb->len)) {
+       switch (tcp_timewait_state_process((struct inet_timewait_sock *)sk,
+                                          skb, th)) {
        case TCP_TW_SYN: {
-               struct sock *sk2 = tcp_v4_lookup_listener(skb->nh.iph->daddr,
-                                                         ntohs(th->dest),
-                                                         tcp_v4_iif(skb));
+               struct sock *sk2 = inet_lookup_listener(&tcp_hashinfo,
+                                                       skb->nh.iph->daddr,
+                                                       ntohs(th->dest),
+                                                       inet_iif(skb));
                if (sk2) {
-                       tcp_tw_deschedule((struct tcp_tw_bucket *)sk);
-                       tcp_tw_put((struct tcp_tw_bucket *)sk);
+                       inet_twsk_deschedule((struct inet_timewait_sock *)sk,
+                                            &tcp_death_row);
+                       inet_twsk_put((struct inet_timewait_sock *)sk);
                        sk = sk2;
                        goto process;
                }
@@ -1834,112 +1322,6 @@ do_time_wait:
        goto discard_it;
 }
 
-/* With per-bucket locks this operation is not-atomic, so that
- * this version is not worse.
- */
-static void __tcp_v4_rehash(struct sock *sk)
-{
-       sk->sk_prot->unhash(sk);
-       sk->sk_prot->hash(sk);
-}
-
-static int tcp_v4_reselect_saddr(struct sock *sk)
-{
-       struct inet_sock *inet = inet_sk(sk);
-       int err;
-       struct rtable *rt;
-       __u32 old_saddr = inet->saddr;
-       __u32 new_saddr;
-       __u32 daddr = inet->daddr;
-
-       if (inet->opt && inet->opt->srr)
-               daddr = inet->opt->faddr;
-
-       /* Query new route. */
-       err = ip_route_connect(&rt, daddr, 0,
-                              RT_CONN_FLAGS(sk),
-                              sk->sk_bound_dev_if,
-                              IPPROTO_TCP,
-                              inet->sport, inet->dport, sk);
-       if (err)
-               return err;
-
-       __sk_dst_set(sk, &rt->u.dst);
-       tcp_v4_setup_caps(sk, &rt->u.dst);
-
-       new_saddr = rt->rt_src;
-
-       if (new_saddr == old_saddr)
-               return 0;
-
-       if (sysctl_ip_dynaddr > 1) {
-               printk(KERN_INFO "tcp_v4_rebuild_header(): shifting inet->"
-                                "saddr from %d.%d.%d.%d to %d.%d.%d.%d\n",
-                      NIPQUAD(old_saddr),
-                      NIPQUAD(new_saddr));
-       }
-
-       inet->saddr = new_saddr;
-       inet->rcv_saddr = new_saddr;
-
-       /* XXX The only one ugly spot where we need to
-        * XXX really change the sockets identity after
-        * XXX it has entered the hashes. -DaveM
-        *
-        * Besides that, it does not check for connection
-        * uniqueness. Wait for troubles.
-        */
-       __tcp_v4_rehash(sk);
-       return 0;
-}
-
-int tcp_v4_rebuild_header(struct sock *sk)
-{
-       struct inet_sock *inet = inet_sk(sk);
-       struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0);
-       u32 daddr;
-       int err;
-
-       /* Route is OK, nothing to do. */
-       if (rt)
-               return 0;
-
-       /* Reroute. */
-       daddr = inet->daddr;
-       if (inet->opt && inet->opt->srr)
-               daddr = inet->opt->faddr;
-
-       {
-               struct flowi fl = { .oif = sk->sk_bound_dev_if,
-                                   .nl_u = { .ip4_u =
-                                             { .daddr = daddr,
-                                               .saddr = inet->saddr,
-                                               .tos = RT_CONN_FLAGS(sk) } },
-                                   .proto = IPPROTO_TCP,
-                                   .uli_u = { .ports =
-                                              { .sport = inet->sport,
-                                                .dport = inet->dport } } };
-                                               
-               err = ip_route_output_flow(&rt, &fl, sk, 0);
-       }
-       if (!err) {
-               __sk_dst_set(sk, &rt->u.dst);
-               tcp_v4_setup_caps(sk, &rt->u.dst);
-               return 0;
-       }
-
-       /* Routing failed... */
-       sk->sk_route_caps = 0;
-
-       if (!sysctl_ip_dynaddr ||
-           sk->sk_state != TCP_SYN_SENT ||
-           (sk->sk_userlocks & SOCK_BINDADDR_LOCK) ||
-           (err = tcp_v4_reselect_saddr(sk)) != 0)
-               sk->sk_err_soft = -err;
-
-       return err;
-}
-
 static void v4_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
 {
        struct sockaddr_in *sin = (struct sockaddr_in *) uaddr;
@@ -1988,18 +1370,18 @@ int tcp_v4_remember_stamp(struct sock *sk)
        return 0;
 }
 
-int tcp_v4_tw_remember_stamp(struct tcp_tw_bucket *tw)
+int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw)
 {
-       struct inet_peer *peer = NULL;
-
-       peer = inet_getpeer(tw->tw_daddr, 1);
+       struct inet_peer *peer = inet_getpeer(tw->tw_daddr, 1);
 
        if (peer) {
-               if ((s32)(peer->tcp_ts - tw->tw_ts_recent) <= 0 ||
+               const struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
+
+               if ((s32)(peer->tcp_ts - tcptw->tw_ts_recent) <= 0 ||
                    (peer->tcp_ts_stamp + TCP_PAWS_MSL < xtime.tv_sec &&
-                    peer->tcp_ts_stamp <= tw->tw_ts_recent_stamp)) {
-                       peer->tcp_ts_stamp = tw->tw_ts_recent_stamp;
-                       peer->tcp_ts tw->tw_ts_recent;
+                    peer->tcp_ts_stamp <= tcptw->tw_ts_recent_stamp)) {
+                       peer->tcp_ts_stamp = tcptw->tw_ts_recent_stamp;
+                       peer->tcp_ts       = tcptw->tw_ts_recent;
                }
                inet_putpeer(peer);
                return 1;
@@ -2011,7 +1393,7 @@ int tcp_v4_tw_remember_stamp(struct tcp_tw_bucket *tw)
 struct tcp_func ipv4_specific = {
        .queue_xmit     =       ip_queue_xmit,
        .send_check     =       tcp_v4_send_check,
-       .rebuild_header =       tcp_v4_rebuild_header,
+       .rebuild_header =       inet_sk_rebuild_header,
        .conn_request   =       tcp_v4_conn_request,
        .syn_recv_sock  =       tcp_v4_syn_recv_sock,
        .remember_stamp =       tcp_v4_remember_stamp,
@@ -2027,13 +1409,14 @@ struct tcp_func ipv4_specific = {
  */
 static int tcp_v4_init_sock(struct sock *sk)
 {
+       struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
 
        skb_queue_head_init(&tp->out_of_order_queue);
        tcp_init_xmit_timers(sk);
        tcp_prequeue_init(tp);
 
-       tp->rto  = TCP_TIMEOUT_INIT;
+       icsk->icsk_rto = TCP_TIMEOUT_INIT;
        tp->mdev = TCP_TIMEOUT_INIT;
 
        /* So many TCP implementations out there (incorrectly) count the
@@ -2051,7 +1434,7 @@ static int tcp_v4_init_sock(struct sock *sk)
        tp->mss_cache = 536;
 
        tp->reordering = sysctl_tcp_reordering;
-       tp->ca_ops = &tcp_init_congestion_ops;
+       icsk->icsk_ca_ops = &tcp_init_congestion_ops;
 
        sk->sk_state = TCP_CLOSE;
 
@@ -2074,7 +1457,7 @@ int tcp_v4_destroy_sock(struct sock *sk)
 
        tcp_clear_xmit_timers(sk);
 
-       tcp_cleanup_congestion_control(tp);
+       tcp_cleanup_congestion_control(sk);
 
        /* Cleanup up the write buffer. */
        sk_stream_writequeue_purge(sk);
@@ -2086,8 +1469,8 @@ int tcp_v4_destroy_sock(struct sock *sk)
        __skb_queue_purge(&tp->ucopy.prequeue);
 
        /* Clean up a referenced TCP bind bucket. */
-       if (tp->bind_hash)
-               tcp_put_port(sk);
+       if (inet_csk(sk)->icsk_bind_hash)
+               inet_put_port(&tcp_hashinfo, sk);
 
        /*
         * If sendmsg cached page exists, toss it.
@@ -2107,13 +1490,13 @@ EXPORT_SYMBOL(tcp_v4_destroy_sock);
 #ifdef CONFIG_PROC_FS
 /* Proc filesystem TCP sock list dumping. */
 
-static inline struct tcp_tw_bucket *tw_head(struct hlist_head *head)
+static inline struct inet_timewait_sock *tw_head(struct hlist_head *head)
 {
        return hlist_empty(head) ? NULL :
-               list_entry(head->first, struct tcp_tw_bucket, tw_node);
+               list_entry(head->first, struct inet_timewait_sock, tw_node);
 }
 
-static inline struct tcp_tw_bucket *tw_next(struct tcp_tw_bucket *tw)
+static inline struct inet_timewait_sock *tw_next(struct inet_timewait_sock *tw)
 {
        return tw->tw_node.next ?
                hlist_entry(tw->tw_node.next, typeof(*tw), tw_node) : NULL;
@@ -2121,14 +1504,14 @@ static inline struct tcp_tw_bucket *tw_next(struct tcp_tw_bucket *tw)
 
 static void *listening_get_next(struct seq_file *seq, void *cur)
 {
-       struct tcp_sock *tp;
+       struct inet_connection_sock *icsk;
        struct hlist_node *node;
        struct sock *sk = cur;
        struct tcp_iter_state* st = seq->private;
 
        if (!sk) {
                st->bucket = 0;
-               sk = sk_head(&tcp_listening_hash[0]);
+               sk = sk_head(&tcp_hashinfo.listening_hash[0]);
                goto get_sk;
        }
 
@@ -2137,7 +1520,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
        if (st->state == TCP_SEQ_STATE_OPENREQ) {
                struct request_sock *req = cur;
 
-               tp = tcp_sk(st->syn_wait_sk);
+               icsk = inet_csk(st->syn_wait_sk);
                req = req->dl_next;
                while (1) {
                        while (req) {
@@ -2150,17 +1533,17 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
                        if (++st->sbucket >= TCP_SYNQ_HSIZE)
                                break;
 get_req:
-                       req = tp->accept_queue.listen_opt->syn_table[st->sbucket];
+                       req = icsk->icsk_accept_queue.listen_opt->syn_table[st->sbucket];
                }
                sk        = sk_next(st->syn_wait_sk);
                st->state = TCP_SEQ_STATE_LISTENING;
-               read_unlock_bh(&tp->accept_queue.syn_wait_lock);
+               read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
        } else {
-               tp = tcp_sk(sk);
-               read_lock_bh(&tp->accept_queue.syn_wait_lock);
-               if (reqsk_queue_len(&tp->accept_queue))
+               icsk = inet_csk(sk);
+               read_lock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
+               if (reqsk_queue_len(&icsk->icsk_accept_queue))
                        goto start_req;
-               read_unlock_bh(&tp->accept_queue.syn_wait_lock);
+               read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
                sk = sk_next(sk);
        }
 get_sk:
@@ -2169,9 +1552,9 @@ get_sk:
                        cur = sk;
                        goto out;
                }
-               tp = tcp_sk(sk);
-               read_lock_bh(&tp->accept_queue.syn_wait_lock);
-               if (reqsk_queue_len(&tp->accept_queue)) {
+               icsk = inet_csk(sk);
+               read_lock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
+               if (reqsk_queue_len(&icsk->icsk_accept_queue)) {
 start_req:
                        st->uid         = sock_i_uid(sk);
                        st->syn_wait_sk = sk;
@@ -2179,10 +1562,10 @@ start_req:
                        st->sbucket     = 0;
                        goto get_req;
                }
-               read_unlock_bh(&tp->accept_queue.syn_wait_lock);
+               read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
        }
-       if (++st->bucket < TCP_LHTABLE_SIZE) {
-               sk = sk_head(&tcp_listening_hash[st->bucket]);
+       if (++st->bucket < INET_LHTABLE_SIZE) {
+               sk = sk_head(&tcp_hashinfo.listening_hash[st->bucket]);
                goto get_sk;
        }
        cur = NULL;
@@ -2206,16 +1589,16 @@ static void *established_get_first(struct seq_file *seq)
        struct tcp_iter_state* st = seq->private;
        void *rc = NULL;
 
-       for (st->bucket = 0; st->bucket < tcp_ehash_size; ++st->bucket) {
+       for (st->bucket = 0; st->bucket < tcp_hashinfo.ehash_size; ++st->bucket) {
                struct sock *sk;
                struct hlist_node *node;
-               struct tcp_tw_bucket *tw;
+               struct inet_timewait_sock *tw;
 
                /* We can reschedule _before_ having picked the target: */
                cond_resched_softirq();
 
-               read_lock(&tcp_ehash[st->bucket].lock);
-               sk_for_each(sk, node, &tcp_ehash[st->bucket].chain) {
+               read_lock(&tcp_hashinfo.ehash[st->bucket].lock);
+               sk_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) {
                        if (sk->sk_family != st->family) {
                                continue;
                        }
@@ -2223,15 +1606,15 @@ static void *established_get_first(struct seq_file *seq)
                        goto out;
                }
                st->state = TCP_SEQ_STATE_TIME_WAIT;
-               tw_for_each(tw, node,
-                           &tcp_ehash[st->bucket + tcp_ehash_size].chain) {
+               inet_twsk_for_each(tw, node,
+                                  &tcp_hashinfo.ehash[st->bucket + tcp_hashinfo.ehash_size].chain) {
                        if (tw->tw_family != st->family) {
                                continue;
                        }
                        rc = tw;
                        goto out;
                }
-               read_unlock(&tcp_ehash[st->bucket].lock);
+               read_unlock(&tcp_hashinfo.ehash[st->bucket].lock);
                st->state = TCP_SEQ_STATE_ESTABLISHED;
        }
 out:
@@ -2241,7 +1624,7 @@ out:
 static void *established_get_next(struct seq_file *seq, void *cur)
 {
        struct sock *sk = cur;
-       struct tcp_tw_bucket *tw;
+       struct inet_timewait_sock *tw;
        struct hlist_node *node;
        struct tcp_iter_state* st = seq->private;
 
@@ -2258,15 +1641,15 @@ get_tw:
                        cur = tw;
                        goto out;
                }
-               read_unlock(&tcp_ehash[st->bucket].lock);
+               read_unlock(&tcp_hashinfo.ehash[st->bucket].lock);
                st->state = TCP_SEQ_STATE_ESTABLISHED;
 
                /* We can reschedule between buckets: */
                cond_resched_softirq();
 
-               if (++st->bucket < tcp_ehash_size) {
-                       read_lock(&tcp_ehash[st->bucket].lock);
-                       sk = sk_head(&tcp_ehash[st->bucket].chain);
+               if (++st->bucket < tcp_hashinfo.ehash_size) {
+                       read_lock(&tcp_hashinfo.ehash[st->bucket].lock);
+                       sk = sk_head(&tcp_hashinfo.ehash[st->bucket].chain);
                } else {
                        cur = NULL;
                        goto out;
@@ -2280,7 +1663,7 @@ get_tw:
        }
 
        st->state = TCP_SEQ_STATE_TIME_WAIT;
-       tw = tw_head(&tcp_ehash[st->bucket + tcp_ehash_size].chain);
+       tw = tw_head(&tcp_hashinfo.ehash[st->bucket + tcp_hashinfo.ehash_size].chain);
        goto get_tw;
 found:
        cur = sk;
@@ -2304,12 +1687,12 @@ static void *tcp_get_idx(struct seq_file *seq, loff_t pos)
        void *rc;
        struct tcp_iter_state* st = seq->private;
 
-       tcp_listen_lock();
+       inet_listen_lock(&tcp_hashinfo);
        st->state = TCP_SEQ_STATE_LISTENING;
        rc        = listening_get_idx(seq, &pos);
 
        if (!rc) {
-               tcp_listen_unlock();
+               inet_listen_unlock(&tcp_hashinfo);
                local_bh_disable();
                st->state = TCP_SEQ_STATE_ESTABLISHED;
                rc        = established_get_idx(seq, pos);
@@ -2342,7 +1725,7 @@ static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
        case TCP_SEQ_STATE_LISTENING:
                rc = listening_get_next(seq, v);
                if (!rc) {
-                       tcp_listen_unlock();
+                       inet_listen_unlock(&tcp_hashinfo);
                        local_bh_disable();
                        st->state = TCP_SEQ_STATE_ESTABLISHED;
                        rc        = established_get_first(seq);
@@ -2365,17 +1748,17 @@ static void tcp_seq_stop(struct seq_file *seq, void *v)
        switch (st->state) {
        case TCP_SEQ_STATE_OPENREQ:
                if (v) {
-                       struct tcp_sock *tp = tcp_sk(st->syn_wait_sk);
-                       read_unlock_bh(&tp->accept_queue.syn_wait_lock);
+                       struct inet_connection_sock *icsk = inet_csk(st->syn_wait_sk);
+                       read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
                }
        case TCP_SEQ_STATE_LISTENING:
                if (v != SEQ_START_TOKEN)
-                       tcp_listen_unlock();
+                       inet_listen_unlock(&tcp_hashinfo);
                break;
        case TCP_SEQ_STATE_TIME_WAIT:
        case TCP_SEQ_STATE_ESTABLISHED:
                if (v)
-                       read_unlock(&tcp_ehash[st->bucket].lock);
+                       read_unlock(&tcp_hashinfo.ehash[st->bucket].lock);
                local_bh_enable();
                break;
        }
@@ -2472,18 +1855,19 @@ static void get_tcp4_sock(struct sock *sp, char *tmpbuf, int i)
        int timer_active;
        unsigned long timer_expires;
        struct tcp_sock *tp = tcp_sk(sp);
+       const struct inet_connection_sock *icsk = inet_csk(sp);
        struct inet_sock *inet = inet_sk(sp);
        unsigned int dest = inet->daddr;
        unsigned int src = inet->rcv_saddr;
        __u16 destp = ntohs(inet->dport);
        __u16 srcp = ntohs(inet->sport);
 
-       if (tp->pending == TCP_TIME_RETRANS) {
+       if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
                timer_active    = 1;
-               timer_expires   = tp->timeout;
-       } else if (tp->pending == TCP_TIME_PROBE0) {
+               timer_expires   = icsk->icsk_timeout;
+       } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
                timer_active    = 4;
-               timer_expires   = tp->timeout;
+               timer_expires   = icsk->icsk_timeout;
        } else if (timer_pending(&sp->sk_timer)) {
                timer_active    = 2;
                timer_expires   = sp->sk_timer.expires;
@@ -2498,17 +1882,19 @@ static void get_tcp4_sock(struct sock *sp, char *tmpbuf, int i)
                tp->write_seq - tp->snd_una, tp->rcv_nxt - tp->copied_seq,
                timer_active,
                jiffies_to_clock_t(timer_expires - jiffies),
-               tp->retransmits,
+               icsk->icsk_retransmits,
                sock_i_uid(sp),
-               tp->probes_out,
+               icsk->icsk_probes_out,
                sock_i_ino(sp),
                atomic_read(&sp->sk_refcnt), sp,
-               tp->rto, tp->ack.ato, (tp->ack.quick << 1) | tp->ack.pingpong,
+               icsk->icsk_rto,
+               icsk->icsk_ack.ato,
+               (icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong,
                tp->snd_cwnd,
                tp->snd_ssthresh >= 0xFFFF ? -1 : tp->snd_ssthresh);
 }
 
-static void get_timewait4_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i)
+static void get_timewait4_sock(struct inet_timewait_sock *tw, char *tmpbuf, int i)
 {
        unsigned int dest, src;
        __u16 destp, srcp;
@@ -2588,7 +1974,7 @@ struct proto tcp_prot = {
        .close                  = tcp_close,
        .connect                = tcp_v4_connect,
        .disconnect             = tcp_disconnect,
-       .accept                 = tcp_accept,
+       .accept                 = inet_csk_accept,
        .ioctl                  = tcp_ioctl,
        .init                   = tcp_v4_init_sock,
        .destroy                = tcp_v4_destroy_sock,
@@ -2603,6 +1989,7 @@ struct proto tcp_prot = {
        .get_port               = tcp_v4_get_port,
        .enter_memory_pressure  = tcp_enter_memory_pressure,
        .sockets_allocated      = &tcp_sockets_allocated,
+       .orphan_count           = &tcp_orphan_count,
        .memory_allocated       = &tcp_memory_allocated,
        .memory_pressure        = &tcp_memory_pressure,
        .sysctl_mem             = sysctl_tcp_mem,
@@ -2610,6 +1997,7 @@ struct proto tcp_prot = {
        .sysctl_rmem            = sysctl_tcp_rmem,
        .max_header             = MAX_TCP_HEADER,
        .obj_size               = sizeof(struct tcp_sock),
+       .twsk_obj_size          = sizeof(struct tcp_timewait_sock),
        .rsk_prot               = &tcp_request_sock_ops,
 };
 
@@ -2631,19 +2019,13 @@ void __init tcp_v4_init(struct net_proto_family *ops)
 }
 
 EXPORT_SYMBOL(ipv4_specific);
-EXPORT_SYMBOL(tcp_bind_hash);
-EXPORT_SYMBOL(tcp_bucket_create);
+EXPORT_SYMBOL(inet_bind_bucket_create);
 EXPORT_SYMBOL(tcp_hashinfo);
-EXPORT_SYMBOL(tcp_inherit_port);
-EXPORT_SYMBOL(tcp_listen_wlock);
-EXPORT_SYMBOL(tcp_port_rover);
 EXPORT_SYMBOL(tcp_prot);
-EXPORT_SYMBOL(tcp_put_port);
 EXPORT_SYMBOL(tcp_unhash);
 EXPORT_SYMBOL(tcp_v4_conn_request);
 EXPORT_SYMBOL(tcp_v4_connect);
 EXPORT_SYMBOL(tcp_v4_do_rcv);
-EXPORT_SYMBOL(tcp_v4_rebuild_header);
 EXPORT_SYMBOL(tcp_v4_remember_stamp);
 EXPORT_SYMBOL(tcp_v4_send_check);
 EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
index f42a284164b794aefec97bb296a115bc5dbc231a..a88db28b0af7d83db35c516cabcc337169a88aa3 100644 (file)
 #define SYNC_INIT 1
 #endif
 
-int sysctl_tcp_tw_recycle;
-int sysctl_tcp_max_tw_buckets = NR_FILE*2;
-
 int sysctl_tcp_syncookies = SYNC_INIT; 
 int sysctl_tcp_abort_on_overflow;
 
-static void tcp_tw_schedule(struct tcp_tw_bucket *tw, int timeo);
+struct inet_timewait_death_row tcp_death_row = {
+       .sysctl_max_tw_buckets = NR_FILE * 2,
+       .period         = TCP_TIMEWAIT_LEN / INET_TWDR_TWKILL_SLOTS,
+       .death_lock     = SPIN_LOCK_UNLOCKED,
+       .hashinfo       = &tcp_hashinfo,
+       .tw_timer       = TIMER_INITIALIZER(inet_twdr_hangman, 0,
+                                           (unsigned long)&tcp_death_row),
+       .twkill_work    = __WORK_INITIALIZER(tcp_death_row.twkill_work,
+                                            inet_twdr_twkill_work,
+                                            &tcp_death_row),
+/* Short-time timewait calendar */
+
+       .twcal_hand     = -1,
+       .twcal_timer    = TIMER_INITIALIZER(inet_twdr_twcal_tick, 0,
+                                           (unsigned long)&tcp_death_row),
+};
+
+EXPORT_SYMBOL_GPL(tcp_death_row);
 
 static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win)
 {
@@ -52,47 +66,6 @@ static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win)
        return (seq == e_win && seq == end_seq);
 }
 
-/* New-style handling of TIME_WAIT sockets. */
-
-int tcp_tw_count;
-
-
-/* Must be called with locally disabled BHs. */
-static void tcp_timewait_kill(struct tcp_tw_bucket *tw)
-{
-       struct tcp_ehash_bucket *ehead;
-       struct tcp_bind_hashbucket *bhead;
-       struct tcp_bind_bucket *tb;
-
-       /* Unlink from established hashes. */
-       ehead = &tcp_ehash[tw->tw_hashent];
-       write_lock(&ehead->lock);
-       if (hlist_unhashed(&tw->tw_node)) {
-               write_unlock(&ehead->lock);
-               return;
-       }
-       __hlist_del(&tw->tw_node);
-       sk_node_init(&tw->tw_node);
-       write_unlock(&ehead->lock);
-
-       /* Disassociate with bind bucket. */
-       bhead = &tcp_bhash[tcp_bhashfn(tw->tw_num)];
-       spin_lock(&bhead->lock);
-       tb = tw->tw_tb;
-       __hlist_del(&tw->tw_bind_node);
-       tw->tw_tb = NULL;
-       tcp_bucket_destroy(tb);
-       spin_unlock(&bhead->lock);
-
-#ifdef INET_REFCNT_DEBUG
-       if (atomic_read(&tw->tw_refcnt) != 1) {
-               printk(KERN_DEBUG "tw_bucket %p refcnt=%d\n", tw,
-                      atomic_read(&tw->tw_refcnt));
-       }
-#endif
-       tcp_tw_put(tw);
-}
-
 /* 
  * * Main purpose of TIME-WAIT state is to close connection gracefully,
  *   when one of ends sits in LAST-ACK or CLOSING retransmitting FIN
@@ -122,19 +95,20 @@ static void tcp_timewait_kill(struct tcp_tw_bucket *tw)
  * to avoid misread sequence numbers, states etc.  --ANK
  */
 enum tcp_tw_status
-tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb,
-                          struct tcphdr *th, unsigned len)
+tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
+                          const struct tcphdr *th)
 {
+       struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
        struct tcp_options_received tmp_opt;
        int paws_reject = 0;
 
        tmp_opt.saw_tstamp = 0;
-       if (th->doff > (sizeof(struct tcphdr) >> 2) && tw->tw_ts_recent_stamp) {
+       if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) {
                tcp_parse_options(skb, &tmp_opt, 0);
 
                if (tmp_opt.saw_tstamp) {
-                       tmp_opt.ts_recent          = tw->tw_ts_recent;
-                       tmp_opt.ts_recent_stamp = tw->tw_ts_recent_stamp;
+                       tmp_opt.ts_recent       = tcptw->tw_ts_recent;
+                       tmp_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp;
                        paws_reject = tcp_paws_check(&tmp_opt, th->rst);
                }
        }
@@ -145,20 +119,20 @@ tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb,
                /* Out of window, send ACK */
                if (paws_reject ||
                    !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
-                                  tw->tw_rcv_nxt,
-                                  tw->tw_rcv_nxt + tw->tw_rcv_wnd))
+                                  tcptw->tw_rcv_nxt,
+                                  tcptw->tw_rcv_nxt + tcptw->tw_rcv_wnd))
                        return TCP_TW_ACK;
 
                if (th->rst)
                        goto kill;
 
-               if (th->syn && !before(TCP_SKB_CB(skb)->seq, tw->tw_rcv_nxt))
+               if (th->syn && !before(TCP_SKB_CB(skb)->seq, tcptw->tw_rcv_nxt))
                        goto kill_with_rst;
 
                /* Dup ACK? */
-               if (!after(TCP_SKB_CB(skb)->end_seq, tw->tw_rcv_nxt) ||
+               if (!after(TCP_SKB_CB(skb)->end_seq, tcptw->tw_rcv_nxt) ||
                    TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq) {
-                       tcp_tw_put(tw);
+                       inet_twsk_put(tw);
                        return TCP_TW_SUCCESS;
                }
 
@@ -166,19 +140,19 @@ tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb,
                 * reset.
                 */
                if (!th->fin ||
-                   TCP_SKB_CB(skb)->end_seq != tw->tw_rcv_nxt + 1) {
+                   TCP_SKB_CB(skb)->end_seq != tcptw->tw_rcv_nxt + 1) {
 kill_with_rst:
-                       tcp_tw_deschedule(tw);
-                       tcp_tw_put(tw);
+                       inet_twsk_deschedule(tw, &tcp_death_row);
+                       inet_twsk_put(tw);
                        return TCP_TW_RST;
                }
 
                /* FIN arrived, enter true time-wait state. */
-               tw->tw_substate = TCP_TIME_WAIT;
-               tw->tw_rcv_nxt  = TCP_SKB_CB(skb)->end_seq;
+               tw->tw_substate   = TCP_TIME_WAIT;
+               tcptw->tw_rcv_nxt = TCP_SKB_CB(skb)->end_seq;
                if (tmp_opt.saw_tstamp) {
-                       tw->tw_ts_recent_stamp  = xtime.tv_sec;
-                       tw->tw_ts_recent        = tmp_opt.rcv_tsval;
+                       tcptw->tw_ts_recent_stamp = xtime.tv_sec;
+                       tcptw->tw_ts_recent       = tmp_opt.rcv_tsval;
                }
 
                /* I am shamed, but failed to make it more elegant.
@@ -187,11 +161,13 @@ kill_with_rst:
                 * do not undertsnad recycling in any case, it not
                 * a big problem in practice. --ANK */
                if (tw->tw_family == AF_INET &&
-                   sysctl_tcp_tw_recycle && tw->tw_ts_recent_stamp &&
+                   tcp_death_row.sysctl_tw_recycle && tcptw->tw_ts_recent_stamp &&
                    tcp_v4_tw_remember_stamp(tw))
-                       tcp_tw_schedule(tw, tw->tw_timeout);
+                       inet_twsk_schedule(tw, &tcp_death_row, tw->tw_timeout,
+                                          TCP_TIMEWAIT_LEN);
                else
-                       tcp_tw_schedule(tw, TCP_TIMEWAIT_LEN);
+                       inet_twsk_schedule(tw, &tcp_death_row, TCP_TIMEWAIT_LEN,
+                                          TCP_TIMEWAIT_LEN);
                return TCP_TW_ACK;
        }
 
@@ -213,7 +189,7 @@ kill_with_rst:
         */
 
        if (!paws_reject &&
-           (TCP_SKB_CB(skb)->seq == tw->tw_rcv_nxt &&
+           (TCP_SKB_CB(skb)->seq == tcptw->tw_rcv_nxt &&
             (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq || th->rst))) {
                /* In window segment, it may be only reset or bare ack. */
 
@@ -224,19 +200,20 @@ kill_with_rst:
                         */
                        if (sysctl_tcp_rfc1337 == 0) {
 kill:
-                               tcp_tw_deschedule(tw);
-                               tcp_tw_put(tw);
+                               inet_twsk_deschedule(tw, &tcp_death_row);
+                               inet_twsk_put(tw);
                                return TCP_TW_SUCCESS;
                        }
                }
-               tcp_tw_schedule(tw, TCP_TIMEWAIT_LEN);
+               inet_twsk_schedule(tw, &tcp_death_row, TCP_TIMEWAIT_LEN,
+                                  TCP_TIMEWAIT_LEN);
 
                if (tmp_opt.saw_tstamp) {
-                       tw->tw_ts_recent        = tmp_opt.rcv_tsval;
-                       tw->tw_ts_recent_stamp  = xtime.tv_sec;
+                       tcptw->tw_ts_recent       = tmp_opt.rcv_tsval;
+                       tcptw->tw_ts_recent_stamp = xtime.tv_sec;
                }
 
-               tcp_tw_put(tw);
+               inet_twsk_put(tw);
                return TCP_TW_SUCCESS;
        }
 
@@ -258,9 +235,10 @@ kill:
         */
 
        if (th->syn && !th->rst && !th->ack && !paws_reject &&
-           (after(TCP_SKB_CB(skb)->seq, tw->tw_rcv_nxt) ||
-            (tmp_opt.saw_tstamp && (s32)(tw->tw_ts_recent - tmp_opt.rcv_tsval) < 0))) {
-               u32 isn = tw->tw_snd_nxt + 65535 + 2;
+           (after(TCP_SKB_CB(skb)->seq, tcptw->tw_rcv_nxt) ||
+            (tmp_opt.saw_tstamp &&
+             (s32)(tcptw->tw_ts_recent - tmp_opt.rcv_tsval) < 0))) {
+               u32 isn = tcptw->tw_snd_nxt + 65535 + 2;
                if (isn == 0)
                        isn++;
                TCP_SKB_CB(skb)->when = isn;
@@ -278,107 +256,57 @@ kill:
                 * Do not reschedule in the last case.
                 */
                if (paws_reject || th->ack)
-                       tcp_tw_schedule(tw, TCP_TIMEWAIT_LEN);
+                       inet_twsk_schedule(tw, &tcp_death_row, TCP_TIMEWAIT_LEN,
+                                          TCP_TIMEWAIT_LEN);
 
                /* Send ACK. Note, we do not put the bucket,
                 * it will be released by caller.
                 */
                return TCP_TW_ACK;
        }
-       tcp_tw_put(tw);
+       inet_twsk_put(tw);
        return TCP_TW_SUCCESS;
 }
 
-/* Enter the time wait state.  This is called with locally disabled BH.
- * Essentially we whip up a timewait bucket, copy the
- * relevant info into it from the SK, and mess with hash chains
- * and list linkage.
- */
-static void __tcp_tw_hashdance(struct sock *sk, struct tcp_tw_bucket *tw)
-{
-       struct tcp_ehash_bucket *ehead = &tcp_ehash[sk->sk_hashent];
-       struct tcp_bind_hashbucket *bhead;
-
-       /* Step 1: Put TW into bind hash. Original socket stays there too.
-          Note, that any socket with inet_sk(sk)->num != 0 MUST be bound in
-          binding cache, even if it is closed.
-        */
-       bhead = &tcp_bhash[tcp_bhashfn(inet_sk(sk)->num)];
-       spin_lock(&bhead->lock);
-       tw->tw_tb = tcp_sk(sk)->bind_hash;
-       BUG_TRAP(tcp_sk(sk)->bind_hash);
-       tw_add_bind_node(tw, &tw->tw_tb->owners);
-       spin_unlock(&bhead->lock);
-
-       write_lock(&ehead->lock);
-
-       /* Step 2: Remove SK from established hash. */
-       if (__sk_del_node_init(sk))
-               sock_prot_dec_use(sk->sk_prot);
-
-       /* Step 3: Hash TW into TIMEWAIT half of established hash table. */
-       tw_add_node(tw, &(ehead + tcp_ehash_size)->chain);
-       atomic_inc(&tw->tw_refcnt);
-
-       write_unlock(&ehead->lock);
-}
-
 /* 
  * Move a socket to time-wait or dead fin-wait-2 state.
  */ 
 void tcp_time_wait(struct sock *sk, int state, int timeo)
 {
-       struct tcp_tw_bucket *tw = NULL;
-       struct tcp_sock *tp = tcp_sk(sk);
+       struct inet_timewait_sock *tw = NULL;
+       const struct tcp_sock *tp = tcp_sk(sk);
        int recycle_ok = 0;
 
-       if (sysctl_tcp_tw_recycle && tp->rx_opt.ts_recent_stamp)
+       if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp)
                recycle_ok = tp->af_specific->remember_stamp(sk);
 
-       if (tcp_tw_count < sysctl_tcp_max_tw_buckets)
-               tw = kmem_cache_alloc(tcp_timewait_cachep, SLAB_ATOMIC);
-
-       if(tw != NULL) {
-               struct inet_sock *inet = inet_sk(sk);
-               int rto = (tp->rto<<2) - (tp->rto>>1);
-
-               /* Give us an identity. */
-               tw->tw_daddr            = inet->daddr;
-               tw->tw_rcv_saddr        = inet->rcv_saddr;
-               tw->tw_bound_dev_if     = sk->sk_bound_dev_if;
-               tw->tw_num              = inet->num;
-               tw->tw_state            = TCP_TIME_WAIT;
-               tw->tw_substate         = state;
-               tw->tw_sport            = inet->sport;
-               tw->tw_dport            = inet->dport;
-               tw->tw_family           = sk->sk_family;
-               tw->tw_reuse            = sk->sk_reuse;
-               tw->tw_rcv_wscale       = tp->rx_opt.rcv_wscale;
-               atomic_set(&tw->tw_refcnt, 1);
+       if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets)
+               tw = inet_twsk_alloc(sk, state);
 
-               tw->tw_hashent          = sk->sk_hashent;
-               tw->tw_rcv_nxt          = tp->rcv_nxt;
-               tw->tw_snd_nxt          = tp->snd_nxt;
-               tw->tw_rcv_wnd          = tcp_receive_window(tp);
-               tw->tw_ts_recent        = tp->rx_opt.ts_recent;
-               tw->tw_ts_recent_stamp  = tp->rx_opt.ts_recent_stamp;
-               tw_dead_node_init(tw);
+       if (tw != NULL) {
+               struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
+               const struct inet_connection_sock *icsk = inet_csk(sk);
+               const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1);
+
+               tw->tw_rcv_wscale       = tp->rx_opt.rcv_wscale;
+               tcptw->tw_rcv_nxt       = tp->rcv_nxt;
+               tcptw->tw_snd_nxt       = tp->snd_nxt;
+               tcptw->tw_rcv_wnd       = tcp_receive_window(tp);
+               tcptw->tw_ts_recent     = tp->rx_opt.ts_recent;
+               tcptw->tw_ts_recent_stamp = tp->rx_opt.ts_recent_stamp;
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
                if (tw->tw_family == PF_INET6) {
                        struct ipv6_pinfo *np = inet6_sk(sk);
+                       struct tcp6_timewait_sock *tcp6tw = tcp6_twsk((struct sock *)tw);
 
-                       ipv6_addr_copy(&tw->tw_v6_daddr, &np->daddr);
-                       ipv6_addr_copy(&tw->tw_v6_rcv_saddr, &np->rcv_saddr);
-                       tw->tw_v6_ipv6only = np->ipv6only;
-               } else {
-                       memset(&tw->tw_v6_daddr, 0, sizeof(tw->tw_v6_daddr));
-                       memset(&tw->tw_v6_rcv_saddr, 0, sizeof(tw->tw_v6_rcv_saddr));
-                       tw->tw_v6_ipv6only = 0;
+                       ipv6_addr_copy(&tcp6tw->tw_v6_daddr, &np->daddr);
+                       ipv6_addr_copy(&tcp6tw->tw_v6_rcv_saddr, &np->rcv_saddr);
+                       tw->tw_ipv6only = np->ipv6only;
                }
 #endif
                /* Linkage updates. */
-               __tcp_tw_hashdance(sk, tw);
+               __inet_twsk_hashdance(tw, sk, &tcp_hashinfo);
 
                /* Get the TIME_WAIT timeout firing. */
                if (timeo < rto)
@@ -392,8 +320,9 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
                                timeo = TCP_TIMEWAIT_LEN;
                }
 
-               tcp_tw_schedule(tw, timeo);
-               tcp_tw_put(tw);
+               inet_twsk_schedule(tw, &tcp_death_row, timeo,
+                                  TCP_TIMEWAIT_LEN);
+               inet_twsk_put(tw);
        } else {
                /* Sorry, if we're out of memory, just CLOSE this
                 * socket up.  We've got bigger problems than
@@ -407,277 +336,6 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
        tcp_done(sk);
 }
 
-/* Kill off TIME_WAIT sockets once their lifetime has expired. */
-static int tcp_tw_death_row_slot;
-
-static void tcp_twkill(unsigned long);
-
-/* TIME_WAIT reaping mechanism. */
-#define TCP_TWKILL_SLOTS       8       /* Please keep this a power of 2. */
-#define TCP_TWKILL_PERIOD      (TCP_TIMEWAIT_LEN/TCP_TWKILL_SLOTS)
-
-#define TCP_TWKILL_QUOTA       100
-
-static struct hlist_head tcp_tw_death_row[TCP_TWKILL_SLOTS];
-static DEFINE_SPINLOCK(tw_death_lock);
-static struct timer_list tcp_tw_timer = TIMER_INITIALIZER(tcp_twkill, 0, 0);
-static void twkill_work(void *);
-static DECLARE_WORK(tcp_twkill_work, twkill_work, NULL);
-static u32 twkill_thread_slots;
-
-/* Returns non-zero if quota exceeded.  */
-static int tcp_do_twkill_work(int slot, unsigned int quota)
-{
-       struct tcp_tw_bucket *tw;
-       struct hlist_node *node;
-       unsigned int killed;
-       int ret;
-
-       /* NOTE: compare this to previous version where lock
-        * was released after detaching chain. It was racy,
-        * because tw buckets are scheduled in not serialized context
-        * in 2.3 (with netfilter), and with softnet it is common, because
-        * soft irqs are not sequenced.
-        */
-       killed = 0;
-       ret = 0;
-rescan:
-       tw_for_each_inmate(tw, node, &tcp_tw_death_row[slot]) {
-               __tw_del_dead_node(tw);
-               spin_unlock(&tw_death_lock);
-               tcp_timewait_kill(tw);
-               tcp_tw_put(tw);
-               killed++;
-               spin_lock(&tw_death_lock);
-               if (killed > quota) {
-                       ret = 1;
-                       break;
-               }
-
-               /* While we dropped tw_death_lock, another cpu may have
-                * killed off the next TW bucket in the list, therefore
-                * do a fresh re-read of the hlist head node with the
-                * lock reacquired.  We still use the hlist traversal
-                * macro in order to get the prefetches.
-                */
-               goto rescan;
-       }
-
-       tcp_tw_count -= killed;
-       NET_ADD_STATS_BH(LINUX_MIB_TIMEWAITED, killed);
-
-       return ret;
-}
-
-static void tcp_twkill(unsigned long dummy)
-{
-       int need_timer, ret;
-
-       spin_lock(&tw_death_lock);
-
-       if (tcp_tw_count == 0)
-               goto out;
-
-       need_timer = 0;
-       ret = tcp_do_twkill_work(tcp_tw_death_row_slot, TCP_TWKILL_QUOTA);
-       if (ret) {
-               twkill_thread_slots |= (1 << tcp_tw_death_row_slot);
-               mb();
-               schedule_work(&tcp_twkill_work);
-               need_timer = 1;
-       } else {
-               /* We purged the entire slot, anything left?  */
-               if (tcp_tw_count)
-                       need_timer = 1;
-       }
-       tcp_tw_death_row_slot =
-               ((tcp_tw_death_row_slot + 1) & (TCP_TWKILL_SLOTS - 1));
-       if (need_timer)
-               mod_timer(&tcp_tw_timer, jiffies + TCP_TWKILL_PERIOD);
-out:
-       spin_unlock(&tw_death_lock);
-}
-
-extern void twkill_slots_invalid(void);
-
-static void twkill_work(void *dummy)
-{
-       int i;
-
-       if ((TCP_TWKILL_SLOTS - 1) > (sizeof(twkill_thread_slots) * 8))
-               twkill_slots_invalid();
-
-       while (twkill_thread_slots) {
-               spin_lock_bh(&tw_death_lock);
-               for (i = 0; i < TCP_TWKILL_SLOTS; i++) {
-                       if (!(twkill_thread_slots & (1 << i)))
-                               continue;
-
-                       while (tcp_do_twkill_work(i, TCP_TWKILL_QUOTA) != 0) {
-                               if (need_resched()) {
-                                       spin_unlock_bh(&tw_death_lock);
-                                       schedule();
-                                       spin_lock_bh(&tw_death_lock);
-                               }
-                       }
-
-                       twkill_thread_slots &= ~(1 << i);
-               }
-               spin_unlock_bh(&tw_death_lock);
-       }
-}
-
-/* These are always called from BH context.  See callers in
- * tcp_input.c to verify this.
- */
-
-/* This is for handling early-kills of TIME_WAIT sockets. */
-void tcp_tw_deschedule(struct tcp_tw_bucket *tw)
-{
-       spin_lock(&tw_death_lock);
-       if (tw_del_dead_node(tw)) {
-               tcp_tw_put(tw);
-               if (--tcp_tw_count == 0)
-                       del_timer(&tcp_tw_timer);
-       }
-       spin_unlock(&tw_death_lock);
-       tcp_timewait_kill(tw);
-}
-
-/* Short-time timewait calendar */
-
-static int tcp_twcal_hand = -1;
-static int tcp_twcal_jiffie;
-static void tcp_twcal_tick(unsigned long);
-static struct timer_list tcp_twcal_timer =
-               TIMER_INITIALIZER(tcp_twcal_tick, 0, 0);
-static struct hlist_head tcp_twcal_row[TCP_TW_RECYCLE_SLOTS];
-
-static void tcp_tw_schedule(struct tcp_tw_bucket *tw, int timeo)
-{
-       struct hlist_head *list;
-       int slot;
-
-       /* timeout := RTO * 3.5
-        *
-        * 3.5 = 1+2+0.5 to wait for two retransmits.
-        *
-        * RATIONALE: if FIN arrived and we entered TIME-WAIT state,
-        * our ACK acking that FIN can be lost. If N subsequent retransmitted
-        * FINs (or previous seqments) are lost (probability of such event
-        * is p^(N+1), where p is probability to lose single packet and
-        * time to detect the loss is about RTO*(2^N - 1) with exponential
-        * backoff). Normal timewait length is calculated so, that we
-        * waited at least for one retransmitted FIN (maximal RTO is 120sec).
-        * [ BTW Linux. following BSD, violates this requirement waiting
-        *   only for 60sec, we should wait at least for 240 secs.
-        *   Well, 240 consumes too much of resources 8)
-        * ]
-        * This interval is not reduced to catch old duplicate and
-        * responces to our wandering segments living for two MSLs.
-        * However, if we use PAWS to detect
-        * old duplicates, we can reduce the interval to bounds required
-        * by RTO, rather than MSL. So, if peer understands PAWS, we
-        * kill tw bucket after 3.5*RTO (it is important that this number
-        * is greater than TS tick!) and detect old duplicates with help
-        * of PAWS.
-        */
-       slot = (timeo + (1<<TCP_TW_RECYCLE_TICK) - 1) >> TCP_TW_RECYCLE_TICK;
-
-       spin_lock(&tw_death_lock);
-
-       /* Unlink it, if it was scheduled */
-       if (tw_del_dead_node(tw))
-               tcp_tw_count--;
-       else
-               atomic_inc(&tw->tw_refcnt);
-
-       if (slot >= TCP_TW_RECYCLE_SLOTS) {
-               /* Schedule to slow timer */
-               if (timeo >= TCP_TIMEWAIT_LEN) {
-                       slot = TCP_TWKILL_SLOTS-1;
-               } else {
-                       slot = (timeo + TCP_TWKILL_PERIOD-1) / TCP_TWKILL_PERIOD;
-                       if (slot >= TCP_TWKILL_SLOTS)
-                               slot = TCP_TWKILL_SLOTS-1;
-               }
-               tw->tw_ttd = jiffies + timeo;
-               slot = (tcp_tw_death_row_slot + slot) & (TCP_TWKILL_SLOTS - 1);
-               list = &tcp_tw_death_row[slot];
-       } else {
-               tw->tw_ttd = jiffies + (slot << TCP_TW_RECYCLE_TICK);
-
-               if (tcp_twcal_hand < 0) {
-                       tcp_twcal_hand = 0;
-                       tcp_twcal_jiffie = jiffies;
-                       tcp_twcal_timer.expires = tcp_twcal_jiffie + (slot<<TCP_TW_RECYCLE_TICK);
-                       add_timer(&tcp_twcal_timer);
-               } else {
-                       if (time_after(tcp_twcal_timer.expires, jiffies + (slot<<TCP_TW_RECYCLE_TICK)))
-                               mod_timer(&tcp_twcal_timer, jiffies + (slot<<TCP_TW_RECYCLE_TICK));
-                       slot = (tcp_twcal_hand + slot)&(TCP_TW_RECYCLE_SLOTS-1);
-               }
-               list = &tcp_twcal_row[slot];
-       }
-
-       hlist_add_head(&tw->tw_death_node, list);
-
-       if (tcp_tw_count++ == 0)
-               mod_timer(&tcp_tw_timer, jiffies+TCP_TWKILL_PERIOD);
-       spin_unlock(&tw_death_lock);
-}
-
-void tcp_twcal_tick(unsigned long dummy)
-{
-       int n, slot;
-       unsigned long j;
-       unsigned long now = jiffies;
-       int killed = 0;
-       int adv = 0;
-
-       spin_lock(&tw_death_lock);
-       if (tcp_twcal_hand < 0)
-               goto out;
-
-       slot = tcp_twcal_hand;
-       j = tcp_twcal_jiffie;
-
-       for (n=0; n<TCP_TW_RECYCLE_SLOTS; n++) {
-               if (time_before_eq(j, now)) {
-                       struct hlist_node *node, *safe;
-                       struct tcp_tw_bucket *tw;
-
-                       tw_for_each_inmate_safe(tw, node, safe,
-                                          &tcp_twcal_row[slot]) {
-                               __tw_del_dead_node(tw);
-                               tcp_timewait_kill(tw);
-                               tcp_tw_put(tw);
-                               killed++;
-                       }
-               } else {
-                       if (!adv) {
-                               adv = 1;
-                               tcp_twcal_jiffie = j;
-                               tcp_twcal_hand = slot;
-                       }
-
-                       if (!hlist_empty(&tcp_twcal_row[slot])) {
-                               mod_timer(&tcp_twcal_timer, j);
-                               goto out;
-                       }
-               }
-               j += (1<<TCP_TW_RECYCLE_TICK);
-               slot = (slot+1)&(TCP_TW_RECYCLE_SLOTS-1);
-       }
-       tcp_twcal_hand = -1;
-
-out:
-       if ((tcp_tw_count -= killed) == 0)
-               del_timer(&tcp_tw_timer);
-       NET_ADD_STATS_BH(LINUX_MIB_TIMEWAITKILLED, killed);
-       spin_unlock(&tw_death_lock);
-}
-
 /* This is not only more efficient than what we used to do, it eliminates
  * a lot of code duplication between IPv4/IPv6 SYN recv processing. -DaveM
  *
@@ -686,75 +344,27 @@ out:
  */
 struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, struct sk_buff *skb)
 {
-       /* allocate the newsk from the same slab of the master sock,
-        * if not, at sk_free time we'll try to free it from the wrong
-        * slabcache (i.e. is it TCPv4 or v6?), this is handled thru sk->sk_prot -acme */
-       struct sock *newsk = sk_alloc(PF_INET, GFP_ATOMIC, sk->sk_prot, 0);
+       struct sock *newsk = inet_csk_clone(sk, req, GFP_ATOMIC);
 
-       if(newsk != NULL) {
-               struct inet_request_sock *ireq = inet_rsk(req);
+       if (newsk != NULL) {
+               const struct inet_request_sock *ireq = inet_rsk(req);
                struct tcp_request_sock *treq = tcp_rsk(req);
+               struct inet_connection_sock *newicsk = inet_csk(sk);
                struct tcp_sock *newtp;
-               struct sk_filter *filter;
-
-               memcpy(newsk, sk, sizeof(struct tcp_sock));
-               newsk->sk_state = TCP_SYN_RECV;
-
-               /* SANITY */
-               sk_node_init(&newsk->sk_node);
-               tcp_sk(newsk)->bind_hash = NULL;
-
-               /* Clone the TCP header template */
-               inet_sk(newsk)->dport = ireq->rmt_port;
-
-               sock_lock_init(newsk);
-               bh_lock_sock(newsk);
-
-               rwlock_init(&newsk->sk_dst_lock);
-               atomic_set(&newsk->sk_rmem_alloc, 0);
-               skb_queue_head_init(&newsk->sk_receive_queue);
-               atomic_set(&newsk->sk_wmem_alloc, 0);
-               skb_queue_head_init(&newsk->sk_write_queue);
-               atomic_set(&newsk->sk_omem_alloc, 0);
-               newsk->sk_wmem_queued = 0;
-               newsk->sk_forward_alloc = 0;
-
-               sock_reset_flag(newsk, SOCK_DONE);
-               newsk->sk_userlocks = sk->sk_userlocks & ~SOCK_BINDPORT_LOCK;
-               newsk->sk_backlog.head = newsk->sk_backlog.tail = NULL;
-               newsk->sk_send_head = NULL;
-               rwlock_init(&newsk->sk_callback_lock);
-               skb_queue_head_init(&newsk->sk_error_queue);
-               newsk->sk_write_space = sk_stream_write_space;
-
-               if ((filter = newsk->sk_filter) != NULL)
-                       sk_filter_charge(newsk, filter);
-
-               if (unlikely(xfrm_sk_clone_policy(newsk))) {
-                       /* It is still raw copy of parent, so invalidate
-                        * destructor and make plain sk_free() */
-                       newsk->sk_destruct = NULL;
-                       sk_free(newsk);
-                       return NULL;
-               }
 
                /* Now setup tcp_sock */
                newtp = tcp_sk(newsk);
                newtp->pred_flags = 0;
                newtp->rcv_nxt = treq->rcv_isn + 1;
-               newtp->snd_nxt = treq->snt_isn + 1;
-               newtp->snd_una = treq->snt_isn + 1;
-               newtp->snd_sml = treq->snt_isn + 1;
+               newtp->snd_nxt = newtp->snd_una = newtp->snd_sml = treq->snt_isn + 1;
 
                tcp_prequeue_init(newtp);
 
                tcp_init_wl(newtp, treq->snt_isn, treq->rcv_isn);
 
-               newtp->retransmits = 0;
-               newtp->backoff = 0;
                newtp->srtt = 0;
                newtp->mdev = TCP_TIMEOUT_INIT;
-               newtp->rto = TCP_TIMEOUT_INIT;
+               newicsk->icsk_rto = TCP_TIMEOUT_INIT;
 
                newtp->packets_out = 0;
                newtp->left_out = 0;
@@ -774,9 +384,9 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
                newtp->frto_counter = 0;
                newtp->frto_highmark = 0;
 
-               newtp->ca_ops = &tcp_reno;
+               newicsk->icsk_ca_ops = &tcp_reno;
 
-               tcp_set_ca_state(newtp, TCP_CA_Open);
+               tcp_set_ca_state(newsk, TCP_CA_Open);
                tcp_init_xmit_timers(newsk);
                skb_queue_head_init(&newtp->out_of_order_queue);
                newtp->rcv_wup = treq->rcv_isn + 1;
@@ -789,26 +399,12 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
                newtp->rx_opt.dsack = 0;
                newtp->rx_opt.eff_sacks = 0;
 
-               newtp->probes_out = 0;
                newtp->rx_opt.num_sacks = 0;
                newtp->urg_data = 0;
-               /* Deinitialize accept_queue to trap illegal accesses. */
-               memset(&newtp->accept_queue, 0, sizeof(newtp->accept_queue));
-
-               /* Back to base struct sock members. */
-               newsk->sk_err = 0;
-               newsk->sk_priority = 0;
-               atomic_set(&newsk->sk_refcnt, 2);
-#ifdef INET_REFCNT_DEBUG
-               atomic_inc(&inet_sock_nr);
-#endif
-               atomic_inc(&tcp_sockets_allocated);
 
                if (sock_flag(newsk, SOCK_KEEPOPEN))
-                       tcp_reset_keepalive_timer(newsk,
-                                                 keepalive_time_when(newtp));
-               newsk->sk_socket = NULL;
-               newsk->sk_sleep = NULL;
+                       inet_csk_reset_keepalive_timer(newsk,
+                                                      keepalive_time_when(newtp));
 
                newtp->rx_opt.tstamp_ok = ireq->tstamp_ok;
                if((newtp->rx_opt.sack_ok = ireq->sack_ok) != 0) {
@@ -838,7 +434,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
                        newtp->tcp_header_len = sizeof(struct tcphdr);
                }
                if (skb->len >= TCP_MIN_RCVMSS+newtp->tcp_header_len)
-                       newtp->ack.last_seg_size = skb->len-newtp->tcp_header_len;
+                       newicsk->icsk_ack.last_seg_size = skb->len - newtp->tcp_header_len;
                newtp->rx_opt.mss_clamp = req->mss;
                TCP_ECN_openreq_child(newtp, req);
                if (newtp->ecn_flags&TCP_ECN_OK)
@@ -934,9 +530,10 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
           does sequence test, SYN is truncated, and thus we consider
           it a bare ACK.
 
-          If tp->defer_accept, we silently drop this bare ACK.  Otherwise,
-          we create an established connection.  Both ends (listening sockets)
-          accept the new incoming connection and try to talk to each other. 8-)
+          If icsk->icsk_accept_queue.rskq_defer_accept, we silently drop this
+          bare ACK.  Otherwise, we create an established connection.  Both
+          ends (listening sockets) accept the new incoming connection and try
+          to talk to each other. 8-)
 
           Note: This case is both harmless, and rare.  Possibility is about the
           same as us discovering intelligent life on another plant tomorrow.
@@ -1003,7 +600,8 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
                        return NULL;
 
                /* If TCP_DEFER_ACCEPT is set, drop bare ACK. */
-               if (tp->defer_accept && TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) {
+               if (inet_csk(sk)->icsk_accept_queue.rskq_defer_accept &&
+                   TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) {
                        inet_rsk(req)->acked = 1;
                        return NULL;
                }
@@ -1018,10 +616,10 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
                if (child == NULL)
                        goto listen_overflow;
 
-               tcp_synq_unlink(tp, req, prev);
-               tcp_synq_removed(sk, req);
+               inet_csk_reqsk_queue_unlink(sk, req, prev);
+               inet_csk_reqsk_queue_removed(sk, req);
 
-               tcp_acceptq_queue(sk, req, child);
+               inet_csk_reqsk_queue_add(sk, req, child);
                return child;
 
        listen_overflow:
@@ -1035,7 +633,7 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
                if (!(flg & TCP_FLAG_RST))
                        req->rsk_ops->send_reset(skb);
 
-               tcp_synq_drop(sk, req, prev);
+               inet_csk_reqsk_queue_drop(sk, req, prev);
                return NULL;
 }
 
@@ -1074,4 +672,3 @@ EXPORT_SYMBOL(tcp_check_req);
 EXPORT_SYMBOL(tcp_child_process);
 EXPORT_SYMBOL(tcp_create_openreq_child);
 EXPORT_SYMBOL(tcp_timewait_state_process);
-EXPORT_SYMBOL(tcp_tw_deschedule);
index dd30dd137b74dd061d74af66500f3d3294be13cf..6094db5e11be798631ff7699396f551314374ee2 100644 (file)
@@ -105,18 +105,19 @@ static __u16 tcp_advertise_mss(struct sock *sk)
 
 /* RFC2861. Reset CWND after idle period longer RTO to "restart window".
  * This is the first part of cwnd validation mechanism. */
-static void tcp_cwnd_restart(struct tcp_sock *tp, struct dst_entry *dst)
+static void tcp_cwnd_restart(struct sock *sk, struct dst_entry *dst)
 {
+       struct tcp_sock *tp = tcp_sk(sk);
        s32 delta = tcp_time_stamp - tp->lsndtime;
        u32 restart_cwnd = tcp_init_cwnd(tp, dst);
        u32 cwnd = tp->snd_cwnd;
 
-       tcp_ca_event(tp, CA_EVENT_CWND_RESTART);
+       tcp_ca_event(sk, CA_EVENT_CWND_RESTART);
 
-       tp->snd_ssthresh = tcp_current_ssthresh(tp);
+       tp->snd_ssthresh = tcp_current_ssthresh(sk);
        restart_cwnd = min(restart_cwnd, cwnd);
 
-       while ((delta -= tp->rto) > 0 && cwnd > restart_cwnd)
+       while ((delta -= inet_csk(sk)->icsk_rto) > 0 && cwnd > restart_cwnd)
                cwnd >>= 1;
        tp->snd_cwnd = max(cwnd, restart_cwnd);
        tp->snd_cwnd_stamp = tcp_time_stamp;
@@ -126,26 +127,25 @@ static void tcp_cwnd_restart(struct tcp_sock *tp, struct dst_entry *dst)
 static inline void tcp_event_data_sent(struct tcp_sock *tp,
                                       struct sk_buff *skb, struct sock *sk)
 {
-       u32 now = tcp_time_stamp;
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       const u32 now = tcp_time_stamp;
 
-       if (!tp->packets_out && (s32)(now - tp->lsndtime) > tp->rto)
-               tcp_cwnd_restart(tp, __sk_dst_get(sk));
+       if (!tp->packets_out && (s32)(now - tp->lsndtime) > icsk->icsk_rto)
+               tcp_cwnd_restart(sk, __sk_dst_get(sk));
 
        tp->lsndtime = now;
 
        /* If it is a reply for ato after last received
         * packet, enter pingpong mode.
         */
-       if ((u32)(now - tp->ack.lrcvtime) < tp->ack.ato)
-               tp->ack.pingpong = 1;
+       if ((u32)(now - icsk->icsk_ack.lrcvtime) < icsk->icsk_ack.ato)
+               icsk->icsk_ack.pingpong = 1;
 }
 
 static __inline__ void tcp_event_ack_sent(struct sock *sk, unsigned int pkts)
 {
-       struct tcp_sock *tp = tcp_sk(sk);
-
-       tcp_dec_quickack_mode(tp, pkts);
-       tcp_clear_xmit_timer(sk, TCP_TIME_DACK);
+       tcp_dec_quickack_mode(sk, pkts);
+       inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK);
 }
 
 /* Determine a window scaling and initial window to offer.
@@ -265,6 +265,7 @@ static __inline__ u16 tcp_select_window(struct sock *sk)
 static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb)
 {
        if (skb != NULL) {
+               const struct inet_connection_sock *icsk = inet_csk(sk);
                struct inet_sock *inet = inet_sk(sk);
                struct tcp_sock *tp = tcp_sk(sk);
                struct tcp_skb_cb *tcb = TCP_SKB_CB(skb);
@@ -280,8 +281,8 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb)
 #define SYSCTL_FLAG_SACK       0x4
 
                /* If congestion control is doing timestamping */
-               if (tp->ca_ops->rtt_sample)
-                       do_gettimeofday(&skb->stamp);
+               if (icsk->icsk_ca_ops->rtt_sample)
+                       __net_timestamp(skb);
 
                sysctl_flags = 0;
                if (tcb->flags & TCPCB_FLAG_SYN) {
@@ -308,7 +309,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb)
                }
                
                if (tcp_packets_in_flight(tp) == 0)
-                       tcp_ca_event(tp, CA_EVENT_TX_START);
+                       tcp_ca_event(sk, CA_EVENT_TX_START);
 
                th = (struct tcphdr *) skb_push(skb, tcp_header_size);
                skb->h.th = th;
@@ -366,7 +367,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb)
                if (err <= 0)
                        return err;
 
-               tcp_enter_cwr(tp);
+               tcp_enter_cwr(sk);
 
                /* NET_XMIT_CN is special. It does not guarantee,
                 * that this packet is lost. It tells that device
@@ -427,11 +428,11 @@ static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned
  * packet to the list.  This won't be called frequently, I hope. 
  * Remember, these are still headerless SKBs at this point.
  */
-static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss_now)
+int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss_now)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *buff;
-       int nsize;
+       int nsize, old_factor;
        u16 flags;
 
        nsize = skb_headlen(skb) - len;
@@ -482,30 +483,41 @@ static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned
         * skbs, which it never sent before. --ANK
         */
        TCP_SKB_CB(buff)->when = TCP_SKB_CB(skb)->when;
-       buff->stamp = skb->stamp;
+       buff->tstamp = skb->tstamp;
 
        if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) {
                tp->lost_out -= tcp_skb_pcount(skb);
                tp->left_out -= tcp_skb_pcount(skb);
        }
 
+       old_factor = tcp_skb_pcount(skb);
+
        /* Fix up tso_factor for both original and new SKB.  */
        tcp_set_skb_tso_segs(sk, skb, mss_now);
        tcp_set_skb_tso_segs(sk, buff, mss_now);
 
-       if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) {
-               tp->lost_out += tcp_skb_pcount(skb);
-               tp->left_out += tcp_skb_pcount(skb);
-       }
+       /* If this packet has been sent out already, we must
+        * adjust the various packet counters.
+        */
+       if (after(tp->snd_nxt, TCP_SKB_CB(buff)->end_seq)) {
+               int diff = old_factor - tcp_skb_pcount(skb) -
+                       tcp_skb_pcount(buff);
 
-       if (TCP_SKB_CB(buff)->sacked&TCPCB_LOST) {
-               tp->lost_out += tcp_skb_pcount(buff);
-               tp->left_out += tcp_skb_pcount(buff);
+               tp->packets_out -= diff;
+               if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) {
+                       tp->lost_out -= diff;
+                       tp->left_out -= diff;
+               }
+               if (diff > 0) {
+                       tp->fackets_out -= diff;
+                       if ((int)tp->fackets_out < 0)
+                               tp->fackets_out = 0;
+               }
        }
 
        /* Link BUFF into the send queue. */
        skb_header_release(buff);
-       __skb_append(skb, buff);
+       __skb_append(skb, buff, &sk->sk_write_queue);
 
        return 0;
 }
@@ -696,7 +708,7 @@ static inline void tcp_cwnd_validate(struct sock *sk, struct tcp_sock *tp)
                if (tp->packets_out > tp->snd_cwnd_used)
                        tp->snd_cwnd_used = tp->packets_out;
 
-               if ((s32)(tcp_time_stamp - tp->snd_cwnd_stamp) >= tp->rto)
+               if ((s32)(tcp_time_stamp - tp->snd_cwnd_stamp) >= inet_csk(sk)->icsk_rto)
                        tcp_cwnd_application_limited(sk);
        }
 }
@@ -893,7 +905,7 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len,
 
        /* Link BUFF into the send queue. */
        skb_header_release(buff);
-       __skb_append(skb, buff);
+       __skb_append(skb, buff, &sk->sk_write_queue);
 
        return 0;
 }
@@ -905,12 +917,13 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len,
  */
 static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_buff *skb)
 {
+       const struct inet_connection_sock *icsk = inet_csk(sk);
        u32 send_win, cong_win, limit, in_flight;
 
        if (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)
                return 0;
 
-       if (tp->ca_state != TCP_CA_Open)
+       if (icsk->icsk_ca_state != TCP_CA_Open)
                return 0;
 
        in_flight = tcp_packets_in_flight(tp);
@@ -1147,6 +1160,7 @@ void tcp_push_one(struct sock *sk, unsigned int mss_now)
  */
 u32 __tcp_select_window(struct sock *sk)
 {
+       struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        /* MSS for the peer's data.  Previous verions used mss_clamp
         * here.  I don't know if the value based on our guesses
@@ -1154,7 +1168,7 @@ u32 __tcp_select_window(struct sock *sk)
         * but may be worse for the performance because of rcv_mss
         * fluctuations.  --SAW  1998/11/1
         */
-       int mss = tp->ack.rcv_mss;
+       int mss = icsk->icsk_ack.rcv_mss;
        int free_space = tcp_space(sk);
        int full_space = min_t(int, tp->window_clamp, tcp_full_space(sk));
        int window;
@@ -1163,7 +1177,7 @@ u32 __tcp_select_window(struct sock *sk)
                mss = full_space; 
 
        if (free_space < full_space/2) {
-               tp->ack.quick = 0;
+               icsk->icsk_ack.quick = 0;
 
                if (tcp_memory_pressure)
                        tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U*tp->advmss);
@@ -1238,7 +1252,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m
                       tcp_skb_pcount(next_skb) != 1);
 
                /* Ok.  We will be able to collapse the packet. */
-               __skb_unlink(next_skb, next_skb->list);
+               __skb_unlink(next_skb, &sk->sk_write_queue);
 
                memcpy(skb_put(skb, next_skb_size), next_skb->data, next_skb_size);
 
@@ -1286,6 +1300,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m
  */ 
 void tcp_simple_retransmit(struct sock *sk)
 {
+       const struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *skb;
        unsigned int mss = tcp_current_mss(sk, 0);
@@ -1316,12 +1331,12 @@ void tcp_simple_retransmit(struct sock *sk)
         * in network, but units changed and effective
         * cwnd/ssthresh really reduced now.
         */
-       if (tp->ca_state != TCP_CA_Loss) {
+       if (icsk->icsk_ca_state != TCP_CA_Loss) {
                tp->high_seq = tp->snd_nxt;
-               tp->snd_ssthresh = tcp_current_ssthresh(tp);
+               tp->snd_ssthresh = tcp_current_ssthresh(sk);
                tp->prior_ssthresh = 0;
                tp->undo_marker = 0;
-               tcp_set_ca_state(tp, TCP_CA_Loss);
+               tcp_set_ca_state(sk, TCP_CA_Loss);
        }
        tcp_xmit_retransmit_queue(sk);
 }
@@ -1346,12 +1361,6 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
        if (before(TCP_SKB_CB(skb)->seq, tp->snd_una)) {
                if (before(TCP_SKB_CB(skb)->end_seq, tp->snd_una))
                        BUG();
-
-               if (sk->sk_route_caps & NETIF_F_TSO) {
-                       sk->sk_route_caps &= ~NETIF_F_TSO;
-                       sock_set_flag(sk, SOCK_NO_LARGESEND);
-               }
-
                if (tcp_trim_head(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq))
                        return -ENOMEM;
        }
@@ -1366,22 +1375,8 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
                return -EAGAIN;
 
        if (skb->len > cur_mss) {
-               int old_factor = tcp_skb_pcount(skb);
-               int diff;
-
                if (tcp_fragment(sk, skb, cur_mss, cur_mss))
                        return -ENOMEM; /* We'll try again later. */
-
-               /* New SKB created, account for it. */
-               diff = old_factor - tcp_skb_pcount(skb) -
-                      tcp_skb_pcount(skb->next);
-               tp->packets_out -= diff;
-
-               if (diff > 0) {
-                       tp->fackets_out -= diff;
-                       if ((int)tp->fackets_out < 0)
-                               tp->fackets_out = 0;
-               }
        }
 
        /* Collapse two adjacent packets if worthwhile and we can. */
@@ -1461,6 +1456,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
  */
 void tcp_xmit_retransmit_queue(struct sock *sk)
 {
+       const struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *skb;
        int packet_cnt = tp->lost_out;
@@ -1484,14 +1480,16 @@ void tcp_xmit_retransmit_queue(struct sock *sk)
                                if (!(sacked&(TCPCB_SACKED_ACKED|TCPCB_SACKED_RETRANS))) {
                                        if (tcp_retransmit_skb(sk, skb))
                                                return;
-                                       if (tp->ca_state != TCP_CA_Loss)
+                                       if (icsk->icsk_ca_state != TCP_CA_Loss)
                                                NET_INC_STATS_BH(LINUX_MIB_TCPFASTRETRANS);
                                        else
                                                NET_INC_STATS_BH(LINUX_MIB_TCPSLOWSTARTRETRANS);
 
                                        if (skb ==
                                            skb_peek(&sk->sk_write_queue))
-                                               tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
+                                               inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
+                                                                         inet_csk(sk)->icsk_rto,
+                                                                         TCP_RTO_MAX);
                                }
 
                                packet_cnt -= tcp_skb_pcount(skb);
@@ -1504,7 +1502,7 @@ void tcp_xmit_retransmit_queue(struct sock *sk)
        /* OK, demanded retransmission is finished. */
 
        /* Forward retransmissions are possible only during Recovery. */
-       if (tp->ca_state != TCP_CA_Recovery)
+       if (icsk->icsk_ca_state != TCP_CA_Recovery)
                return;
 
        /* No forward retransmissions in Reno are possible. */
@@ -1544,7 +1542,9 @@ void tcp_xmit_retransmit_queue(struct sock *sk)
                        break;
 
                if (skb == skb_peek(&sk->sk_write_queue))
-                       tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
+                       inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
+                                                 inet_csk(sk)->icsk_rto,
+                                                 TCP_RTO_MAX);
 
                NET_INC_STATS_BH(LINUX_MIB_TCPFORWARDRETRANS);
        }
@@ -1573,7 +1573,7 @@ void tcp_send_fin(struct sock *sk)
        } else {
                /* Socket is locked, keep trying until memory is available. */
                for (;;) {
-                       skb = alloc_skb(MAX_TCP_HEADER, GFP_KERNEL);
+                       skb = alloc_skb_fclone(MAX_TCP_HEADER, GFP_KERNEL);
                        if (skb)
                                break;
                        yield();
@@ -1780,8 +1780,8 @@ static inline void tcp_connect_init(struct sock *sk)
        tp->rcv_wup = 0;
        tp->copied_seq = 0;
 
-       tp->rto = TCP_TIMEOUT_INIT;
-       tp->retransmits = 0;
+       inet_csk(sk)->icsk_rto = TCP_TIMEOUT_INIT;
+       inet_csk(sk)->icsk_retransmits = 0;
        tcp_clear_retrans(tp);
 }
 
@@ -1795,7 +1795,7 @@ int tcp_connect(struct sock *sk)
 
        tcp_connect_init(sk);
 
-       buff = alloc_skb(MAX_TCP_HEADER + 15, sk->sk_allocation);
+       buff = alloc_skb_fclone(MAX_TCP_HEADER + 15, sk->sk_allocation);
        if (unlikely(buff == NULL))
                return -ENOBUFS;
 
@@ -1824,7 +1824,8 @@ int tcp_connect(struct sock *sk)
        TCP_INC_STATS(TCP_MIB_ACTIVEOPENS);
 
        /* Timer for repeating the SYN until an answer. */
-       tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
+       inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
+                                 inet_csk(sk)->icsk_rto, TCP_RTO_MAX);
        return 0;
 }
 
@@ -1834,20 +1835,21 @@ int tcp_connect(struct sock *sk)
  */
 void tcp_send_delayed_ack(struct sock *sk)
 {
-       struct tcp_sock *tp = tcp_sk(sk);
-       int ato = tp->ack.ato;
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       int ato = icsk->icsk_ack.ato;
        unsigned long timeout;
 
        if (ato > TCP_DELACK_MIN) {
+               const struct tcp_sock *tp = tcp_sk(sk);
                int max_ato = HZ/2;
 
-               if (tp->ack.pingpong || (tp->ack.pending&TCP_ACK_PUSHED))
+               if (icsk->icsk_ack.pingpong || (icsk->icsk_ack.pending & ICSK_ACK_PUSHED))
                        max_ato = TCP_DELACK_MAX;
 
                /* Slow path, intersegment interval is "high". */
 
                /* If some rtt estimate is known, use it to bound delayed ack.
-                * Do not use tp->rto here, use results of rtt measurements
+                * Do not use inet_csk(sk)->icsk_rto here, use results of rtt measurements
                 * directly.
                 */
                if (tp->srtt) {
@@ -1864,21 +1866,22 @@ void tcp_send_delayed_ack(struct sock *sk)
        timeout = jiffies + ato;
 
        /* Use new timeout only if there wasn't a older one earlier. */
-       if (tp->ack.pending&TCP_ACK_TIMER) {
+       if (icsk->icsk_ack.pending & ICSK_ACK_TIMER) {
                /* If delack timer was blocked or is about to expire,
                 * send ACK now.
                 */
-               if (tp->ack.blocked || time_before_eq(tp->ack.timeout, jiffies+(ato>>2))) {
+               if (icsk->icsk_ack.blocked ||
+                   time_before_eq(icsk->icsk_ack.timeout, jiffies + (ato >> 2))) {
                        tcp_send_ack(sk);
                        return;
                }
 
-               if (!time_before(timeout, tp->ack.timeout))
-                       timeout = tp->ack.timeout;
+               if (!time_before(timeout, icsk->icsk_ack.timeout))
+                       timeout = icsk->icsk_ack.timeout;
        }
-       tp->ack.pending |= TCP_ACK_SCHED|TCP_ACK_TIMER;
-       tp->ack.timeout = timeout;
-       sk_reset_timer(sk, &tp->delack_timer, timeout);
+       icsk->icsk_ack.pending |= ICSK_ACK_SCHED | ICSK_ACK_TIMER;
+       icsk->icsk_ack.timeout = timeout;
+       sk_reset_timer(sk, &icsk->icsk_delack_timer, timeout);
 }
 
 /* This routine sends an ack and also updates the window. */
@@ -1895,9 +1898,10 @@ void tcp_send_ack(struct sock *sk)
                 */
                buff = alloc_skb(MAX_TCP_HEADER, GFP_ATOMIC);
                if (buff == NULL) {
-                       tcp_schedule_ack(tp);
-                       tp->ack.ato = TCP_ATO_MIN;
-                       tcp_reset_xmit_timer(sk, TCP_TIME_DACK, TCP_DELACK_MAX);
+                       inet_csk_schedule_ack(sk);
+                       inet_csk(sk)->icsk_ack.ato = TCP_ATO_MIN;
+                       inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
+                                                 TCP_DELACK_MAX, TCP_RTO_MAX);
                        return;
                }
 
@@ -1980,12 +1984,6 @@ int tcp_write_wakeup(struct sock *sk)
                                TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
                                if (tcp_fragment(sk, skb, seg_size, mss))
                                        return -1;
-                               /* SWS override triggered forced fragmentation.
-                                * Disable TSO, the connection is too sick. */
-                               if (sk->sk_route_caps & NETIF_F_TSO) {
-                                       sock_set_flag(sk, SOCK_NO_LARGESEND);
-                                       sk->sk_route_caps &= ~NETIF_F_TSO;
-                               }
                        } else if (!tcp_skb_pcount(skb))
                                tcp_set_skb_tso_segs(sk, skb, mss);
 
@@ -2011,6 +2009,7 @@ int tcp_write_wakeup(struct sock *sk)
  */
 void tcp_send_probe0(struct sock *sk)
 {
+       struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        int err;
 
@@ -2018,28 +2017,31 @@ void tcp_send_probe0(struct sock *sk)
 
        if (tp->packets_out || !sk->sk_send_head) {
                /* Cancel probe timer, if it is not required. */
-               tp->probes_out = 0;
-               tp->backoff = 0;
+               icsk->icsk_probes_out = 0;
+               icsk->icsk_backoff = 0;
                return;
        }
 
        if (err <= 0) {
-               if (tp->backoff < sysctl_tcp_retries2)
-                       tp->backoff++;
-               tp->probes_out++;
-               tcp_reset_xmit_timer (sk, TCP_TIME_PROBE0, 
-                                     min(tp->rto << tp->backoff, TCP_RTO_MAX));
+               if (icsk->icsk_backoff < sysctl_tcp_retries2)
+                       icsk->icsk_backoff++;
+               icsk->icsk_probes_out++;
+               inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0, 
+                                         min(icsk->icsk_rto << icsk->icsk_backoff, TCP_RTO_MAX),
+                                         TCP_RTO_MAX);
        } else {
                /* If packet was not sent due to local congestion,
-                * do not backoff and do not remember probes_out.
+                * do not backoff and do not remember icsk_probes_out.
                 * Let local senders to fight for local resources.
                 *
                 * Use accumulated backoff yet.
                 */
-               if (!tp->probes_out)
-                       tp->probes_out=1;
-               tcp_reset_xmit_timer (sk, TCP_TIME_PROBE0, 
-                                     min(tp->rto << tp->backoff, TCP_RESOURCE_PROBE_INTERVAL));
+               if (!icsk->icsk_probes_out)
+                       icsk->icsk_probes_out = 1;
+               inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0, 
+                                         min(icsk->icsk_rto << icsk->icsk_backoff,
+                                             TCP_RESOURCE_PROBE_INTERVAL),
+                                         TCP_RTO_MAX);
        }
 }
 
index 70e108e15c71e42b5992f9ba01964d99ca70c490..327770bf552230211f2db5d799183fa08dd7e440 100644 (file)
 #define TCP_SCALABLE_AI_CNT    50U
 #define TCP_SCALABLE_MD_SCALE  3
 
-static void tcp_scalable_cong_avoid(struct tcp_sock *tp, u32 ack, u32 rtt,
+static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
                                    u32 in_flight, int flag)
 {
+       struct tcp_sock *tp = tcp_sk(sk);
        if (in_flight < tp->snd_cwnd)
                return;
 
@@ -35,8 +36,9 @@ static void tcp_scalable_cong_avoid(struct tcp_sock *tp, u32 ack, u32 rtt,
        tp->snd_cwnd_stamp = tcp_time_stamp;
 }
 
-static u32 tcp_scalable_ssthresh(struct tcp_sock *tp)
+static u32 tcp_scalable_ssthresh(struct sock *sk)
 {
+       const struct tcp_sock *tp = tcp_sk(sk);
        return max(tp->snd_cwnd - (tp->snd_cwnd>>TCP_SCALABLE_MD_SCALE), 2U);
 }
 
index 0084227438c28d26bc2d089b1facc4675310f741..415ee47ac1c55f24c7d58a8327b089c6925c34a3 100644 (file)
@@ -36,49 +36,13 @@ static void tcp_write_timer(unsigned long);
 static void tcp_delack_timer(unsigned long);
 static void tcp_keepalive_timer (unsigned long data);
 
-#ifdef TCP_DEBUG
-const char tcp_timer_bug_msg[] = KERN_DEBUG "tcpbug: unknown timer value\n";
-EXPORT_SYMBOL(tcp_timer_bug_msg);
-#endif
-
-/*
- * Using different timers for retransmit, delayed acks and probes
- * We may wish use just one timer maintaining a list of expire jiffies 
- * to optimize.
- */
-
 void tcp_init_xmit_timers(struct sock *sk)
 {
-       struct tcp_sock *tp = tcp_sk(sk);
-
-       init_timer(&tp->retransmit_timer);
-       tp->retransmit_timer.function=&tcp_write_timer;
-       tp->retransmit_timer.data = (unsigned long) sk;
-       tp->pending = 0;
-
-       init_timer(&tp->delack_timer);
-       tp->delack_timer.function=&tcp_delack_timer;
-       tp->delack_timer.data = (unsigned long) sk;
-       tp->ack.pending = 0;
-
-       init_timer(&sk->sk_timer);
-       sk->sk_timer.function   = &tcp_keepalive_timer;
-       sk->sk_timer.data       = (unsigned long)sk;
+       inet_csk_init_xmit_timers(sk, &tcp_write_timer, &tcp_delack_timer,
+                                 &tcp_keepalive_timer);
 }
 
-void tcp_clear_xmit_timers(struct sock *sk)
-{
-       struct tcp_sock *tp = tcp_sk(sk);
-
-       tp->pending = 0;
-       sk_stop_timer(sk, &tp->retransmit_timer);
-
-       tp->ack.pending = 0;
-       tp->ack.blocked = 0;
-       sk_stop_timer(sk, &tp->delack_timer);
-
-       sk_stop_timer(sk, &sk->sk_timer);
-}
+EXPORT_SYMBOL(tcp_init_xmit_timers);
 
 static void tcp_write_err(struct sock *sk)
 {
@@ -155,15 +119,15 @@ static int tcp_orphan_retries(struct sock *sk, int alive)
 /* A write timeout has occurred. Process the after effects. */
 static int tcp_write_timeout(struct sock *sk)
 {
-       struct tcp_sock *tp = tcp_sk(sk);
+       const struct inet_connection_sock *icsk = inet_csk(sk);
        int retry_until;
 
        if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
-               if (tp->retransmits)
+               if (icsk->icsk_retransmits)
                        dst_negative_advice(&sk->sk_dst_cache);
-               retry_until = tp->syn_retries ? : sysctl_tcp_syn_retries;
+               retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries;
        } else {
-               if (tp->retransmits >= sysctl_tcp_retries1) {
+               if (icsk->icsk_retransmits >= sysctl_tcp_retries1) {
                        /* NOTE. draft-ietf-tcpimpl-pmtud-01.txt requires pmtu black
                           hole detection. :-(
 
@@ -189,16 +153,16 @@ static int tcp_write_timeout(struct sock *sk)
 
                retry_until = sysctl_tcp_retries2;
                if (sock_flag(sk, SOCK_DEAD)) {
-                       int alive = (tp->rto < TCP_RTO_MAX);
+                       const int alive = (icsk->icsk_rto < TCP_RTO_MAX);
  
                        retry_until = tcp_orphan_retries(sk, alive);
 
-                       if (tcp_out_of_resources(sk, alive || tp->retransmits < retry_until))
+                       if (tcp_out_of_resources(sk, alive || icsk->icsk_retransmits < retry_until))
                                return 1;
                }
        }
 
-       if (tp->retransmits >= retry_until) {
+       if (icsk->icsk_retransmits >= retry_until) {
                /* Has it gone just too far? */
                tcp_write_err(sk);
                return 1;
@@ -210,26 +174,27 @@ static void tcp_delack_timer(unsigned long data)
 {
        struct sock *sk = (struct sock*)data;
        struct tcp_sock *tp = tcp_sk(sk);
+       struct inet_connection_sock *icsk = inet_csk(sk);
 
        bh_lock_sock(sk);
        if (sock_owned_by_user(sk)) {
                /* Try again later. */
-               tp->ack.blocked = 1;
+               icsk->icsk_ack.blocked = 1;
                NET_INC_STATS_BH(LINUX_MIB_DELAYEDACKLOCKED);
-               sk_reset_timer(sk, &tp->delack_timer, jiffies + TCP_DELACK_MIN);
+               sk_reset_timer(sk, &icsk->icsk_delack_timer, jiffies + TCP_DELACK_MIN);
                goto out_unlock;
        }
 
        sk_stream_mem_reclaim(sk);
 
-       if (sk->sk_state == TCP_CLOSE || !(tp->ack.pending & TCP_ACK_TIMER))
+       if (sk->sk_state == TCP_CLOSE || !(icsk->icsk_ack.pending & ICSK_ACK_TIMER))
                goto out;
 
-       if (time_after(tp->ack.timeout, jiffies)) {
-               sk_reset_timer(sk, &tp->delack_timer, tp->ack.timeout);
+       if (time_after(icsk->icsk_ack.timeout, jiffies)) {
+               sk_reset_timer(sk, &icsk->icsk_delack_timer, icsk->icsk_ack.timeout);
                goto out;
        }
-       tp->ack.pending &= ~TCP_ACK_TIMER;
+       icsk->icsk_ack.pending &= ~ICSK_ACK_TIMER;
 
        if (!skb_queue_empty(&tp->ucopy.prequeue)) {
                struct sk_buff *skb;
@@ -242,16 +207,16 @@ static void tcp_delack_timer(unsigned long data)
                tp->ucopy.memory = 0;
        }
 
-       if (tcp_ack_scheduled(tp)) {
-               if (!tp->ack.pingpong) {
+       if (inet_csk_ack_scheduled(sk)) {
+               if (!icsk->icsk_ack.pingpong) {
                        /* Delayed ACK missed: inflate ATO. */
-                       tp->ack.ato = min(tp->ack.ato << 1, tp->rto);
+                       icsk->icsk_ack.ato = min(icsk->icsk_ack.ato << 1, icsk->icsk_rto);
                } else {
                        /* Delayed ACK missed: leave pingpong mode and
                         * deflate ATO.
                         */
-                       tp->ack.pingpong = 0;
-                       tp->ack.ato = TCP_ATO_MIN;
+                       icsk->icsk_ack.pingpong = 0;
+                       icsk->icsk_ack.ato      = TCP_ATO_MIN;
                }
                tcp_send_ack(sk);
                NET_INC_STATS_BH(LINUX_MIB_DELAYEDACKS);
@@ -268,11 +233,12 @@ out_unlock:
 
 static void tcp_probe_timer(struct sock *sk)
 {
+       struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        int max_probes;
 
        if (tp->packets_out || !sk->sk_send_head) {
-               tp->probes_out = 0;
+               icsk->icsk_probes_out = 0;
                return;
        }
 
@@ -283,7 +249,7 @@ static void tcp_probe_timer(struct sock *sk)
         * FIXME: We ought not to do it, Solaris 2.5 actually has fixing
         * this behaviour in Solaris down as a bug fix. [AC]
         *
-        * Let me to explain. probes_out is zeroed by incoming ACKs
+        * Let me to explain. icsk_probes_out is zeroed by incoming ACKs
         * even if they advertise zero window. Hence, connection is killed only
         * if we received no ACKs for normal connection timeout. It is not killed
         * only because window stays zero for some time, window may be zero
@@ -294,15 +260,15 @@ static void tcp_probe_timer(struct sock *sk)
        max_probes = sysctl_tcp_retries2;
 
        if (sock_flag(sk, SOCK_DEAD)) {
-               int alive = ((tp->rto<<tp->backoff) < TCP_RTO_MAX);
+               const int alive = ((icsk->icsk_rto << icsk->icsk_backoff) < TCP_RTO_MAX);
  
                max_probes = tcp_orphan_retries(sk, alive);
 
-               if (tcp_out_of_resources(sk, alive || tp->probes_out <= max_probes))
+               if (tcp_out_of_resources(sk, alive || icsk->icsk_probes_out <= max_probes))
                        return;
        }
 
-       if (tp->probes_out > max_probes) {
+       if (icsk->icsk_probes_out > max_probes) {
                tcp_write_err(sk);
        } else {
                /* Only send another probe if we didn't close things up. */
@@ -317,6 +283,7 @@ static void tcp_probe_timer(struct sock *sk)
 static void tcp_retransmit_timer(struct sock *sk)
 {
        struct tcp_sock *tp = tcp_sk(sk);
+       struct inet_connection_sock *icsk = inet_csk(sk);
 
        if (!tp->packets_out)
                goto out;
@@ -351,20 +318,21 @@ static void tcp_retransmit_timer(struct sock *sk)
        if (tcp_write_timeout(sk))
                goto out;
 
-       if (tp->retransmits == 0) {
-               if (tp->ca_state == TCP_CA_Disorder || tp->ca_state == TCP_CA_Recovery) {
+       if (icsk->icsk_retransmits == 0) {
+               if (icsk->icsk_ca_state == TCP_CA_Disorder ||
+                   icsk->icsk_ca_state == TCP_CA_Recovery) {
                        if (tp->rx_opt.sack_ok) {
-                               if (tp->ca_state == TCP_CA_Recovery)
+                               if (icsk->icsk_ca_state == TCP_CA_Recovery)
                                        NET_INC_STATS_BH(LINUX_MIB_TCPSACKRECOVERYFAIL);
                                else
                                        NET_INC_STATS_BH(LINUX_MIB_TCPSACKFAILURES);
                        } else {
-                               if (tp->ca_state == TCP_CA_Recovery)
+                               if (icsk->icsk_ca_state == TCP_CA_Recovery)
                                        NET_INC_STATS_BH(LINUX_MIB_TCPRENORECOVERYFAIL);
                                else
                                        NET_INC_STATS_BH(LINUX_MIB_TCPRENOFAILURES);
                        }
-               } else if (tp->ca_state == TCP_CA_Loss) {
+               } else if (icsk->icsk_ca_state == TCP_CA_Loss) {
                        NET_INC_STATS_BH(LINUX_MIB_TCPLOSSFAILURES);
                } else {
                        NET_INC_STATS_BH(LINUX_MIB_TCPTIMEOUTS);
@@ -381,10 +349,11 @@ static void tcp_retransmit_timer(struct sock *sk)
                /* Retransmission failed because of local congestion,
                 * do not backoff.
                 */
-               if (!tp->retransmits)
-                       tp->retransmits=1;
-               tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS,
-                                    min(tp->rto, TCP_RESOURCE_PROBE_INTERVAL));
+               if (!icsk->icsk_retransmits)
+                       icsk->icsk_retransmits = 1;
+               inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
+                                         min(icsk->icsk_rto, TCP_RESOURCE_PROBE_INTERVAL),
+                                         TCP_RTO_MAX);
                goto out;
        }
 
@@ -403,13 +372,13 @@ static void tcp_retransmit_timer(struct sock *sk)
         * implemented ftp to mars will work nicely. We will have to fix
         * the 120 second clamps though!
         */
-       tp->backoff++;
-       tp->retransmits++;
+       icsk->icsk_backoff++;
+       icsk->icsk_retransmits++;
 
 out_reset_timer:
-       tp->rto = min(tp->rto << 1, TCP_RTO_MAX);
-       tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
-       if (tp->retransmits > sysctl_tcp_retries1)
+       icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
+       inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX);
+       if (icsk->icsk_retransmits > sysctl_tcp_retries1)
                __sk_dst_reset(sk);
 
 out:;
@@ -418,32 +387,32 @@ out:;
 static void tcp_write_timer(unsigned long data)
 {
        struct sock *sk = (struct sock*)data;
-       struct tcp_sock *tp = tcp_sk(sk);
+       struct inet_connection_sock *icsk = inet_csk(sk);
        int event;
 
        bh_lock_sock(sk);
        if (sock_owned_by_user(sk)) {
                /* Try again later */
-               sk_reset_timer(sk, &tp->retransmit_timer, jiffies + (HZ / 20));
+               sk_reset_timer(sk, &icsk->icsk_retransmit_timer, jiffies + (HZ / 20));
                goto out_unlock;
        }
 
-       if (sk->sk_state == TCP_CLOSE || !tp->pending)
+       if (sk->sk_state == TCP_CLOSE || !icsk->icsk_pending)
                goto out;
 
-       if (time_after(tp->timeout, jiffies)) {
-               sk_reset_timer(sk, &tp->retransmit_timer, tp->timeout);
+       if (time_after(icsk->icsk_timeout, jiffies)) {
+               sk_reset_timer(sk, &icsk->icsk_retransmit_timer, icsk->icsk_timeout);
                goto out;
        }
 
-       event = tp->pending;
-       tp->pending = 0;
+       event = icsk->icsk_pending;
+       icsk->icsk_pending = 0;
 
        switch (event) {
-       case TCP_TIME_RETRANS:
+       case ICSK_TIME_RETRANS:
                tcp_retransmit_timer(sk);
                break;
-       case TCP_TIME_PROBE0:
+       case ICSK_TIME_PROBE0:
                tcp_probe_timer(sk);
                break;
        }
@@ -462,96 +431,8 @@ out_unlock:
 
 static void tcp_synack_timer(struct sock *sk)
 {
-       struct tcp_sock *tp = tcp_sk(sk);
-       struct listen_sock *lopt = tp->accept_queue.listen_opt;
-       int max_retries = tp->syn_retries ? : sysctl_tcp_synack_retries;
-       int thresh = max_retries;
-       unsigned long now = jiffies;
-       struct request_sock **reqp, *req;
-       int i, budget;
-
-       if (lopt == NULL || lopt->qlen == 0)
-               return;
-
-       /* Normally all the openreqs are young and become mature
-        * (i.e. converted to established socket) for first timeout.
-        * If synack was not acknowledged for 3 seconds, it means
-        * one of the following things: synack was lost, ack was lost,
-        * rtt is high or nobody planned to ack (i.e. synflood).
-        * When server is a bit loaded, queue is populated with old
-        * open requests, reducing effective size of queue.
-        * When server is well loaded, queue size reduces to zero
-        * after several minutes of work. It is not synflood,
-        * it is normal operation. The solution is pruning
-        * too old entries overriding normal timeout, when
-        * situation becomes dangerous.
-        *
-        * Essentially, we reserve half of room for young
-        * embrions; and abort old ones without pity, if old
-        * ones are about to clog our table.
-        */
-       if (lopt->qlen>>(lopt->max_qlen_log-1)) {
-               int young = (lopt->qlen_young<<1);
-
-               while (thresh > 2) {
-                       if (lopt->qlen < young)
-                               break;
-                       thresh--;
-                       young <<= 1;
-               }
-       }
-
-       if (tp->defer_accept)
-               max_retries = tp->defer_accept;
-
-       budget = 2*(TCP_SYNQ_HSIZE/(TCP_TIMEOUT_INIT/TCP_SYNQ_INTERVAL));
-       i = lopt->clock_hand;
-
-       do {
-               reqp=&lopt->syn_table[i];
-               while ((req = *reqp) != NULL) {
-                       if (time_after_eq(now, req->expires)) {
-                               if ((req->retrans < thresh ||
-                                    (inet_rsk(req)->acked && req->retrans < max_retries))
-                                   && !req->rsk_ops->rtx_syn_ack(sk, req, NULL)) {
-                                       unsigned long timeo;
-
-                                       if (req->retrans++ == 0)
-                                               lopt->qlen_young--;
-                                       timeo = min((TCP_TIMEOUT_INIT << req->retrans),
-                                                   TCP_RTO_MAX);
-                                       req->expires = now + timeo;
-                                       reqp = &req->dl_next;
-                                       continue;
-                               }
-
-                               /* Drop this request */
-                               tcp_synq_unlink(tp, req, reqp);
-                               reqsk_queue_removed(&tp->accept_queue, req);
-                               reqsk_free(req);
-                               continue;
-                       }
-                       reqp = &req->dl_next;
-               }
-
-               i = (i+1)&(TCP_SYNQ_HSIZE-1);
-
-       } while (--budget > 0);
-
-       lopt->clock_hand = i;
-
-       if (lopt->qlen)
-               tcp_reset_keepalive_timer(sk, TCP_SYNQ_INTERVAL);
-}
-
-void tcp_delete_keepalive_timer (struct sock *sk)
-{
-       sk_stop_timer(sk, &sk->sk_timer);
-}
-
-void tcp_reset_keepalive_timer (struct sock *sk, unsigned long len)
-{
-       sk_reset_timer(sk, &sk->sk_timer, jiffies + len);
+       inet_csk_reqsk_queue_prune(sk, TCP_SYNQ_INTERVAL,
+                                  TCP_TIMEOUT_INIT, TCP_RTO_MAX);
 }
 
 void tcp_set_keepalive(struct sock *sk, int val)
@@ -560,15 +441,16 @@ void tcp_set_keepalive(struct sock *sk, int val)
                return;
 
        if (val && !sock_flag(sk, SOCK_KEEPOPEN))
-               tcp_reset_keepalive_timer(sk, keepalive_time_when(tcp_sk(sk)));
+               inet_csk_reset_keepalive_timer(sk, keepalive_time_when(tcp_sk(sk)));
        else if (!val)
-               tcp_delete_keepalive_timer(sk);
+               inet_csk_delete_keepalive_timer(sk);
 }
 
 
 static void tcp_keepalive_timer (unsigned long data)
 {
        struct sock *sk = (struct sock *) data;
+       struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        __u32 elapsed;
 
@@ -576,7 +458,7 @@ static void tcp_keepalive_timer (unsigned long data)
        bh_lock_sock(sk);
        if (sock_owned_by_user(sk)) {
                /* Try again later. */ 
-               tcp_reset_keepalive_timer (sk, HZ/20);
+               inet_csk_reset_keepalive_timer (sk, HZ/20);
                goto out;
        }
 
@@ -587,7 +469,7 @@ static void tcp_keepalive_timer (unsigned long data)
 
        if (sk->sk_state == TCP_FIN_WAIT2 && sock_flag(sk, SOCK_DEAD)) {
                if (tp->linger2 >= 0) {
-                       int tmo = tcp_fin_time(tp) - TCP_TIMEWAIT_LEN;
+                       const int tmo = tcp_fin_time(sk) - TCP_TIMEWAIT_LEN;
 
                        if (tmo > 0) {
                                tcp_time_wait(sk, TCP_FIN_WAIT2, tmo);
@@ -610,14 +492,14 @@ static void tcp_keepalive_timer (unsigned long data)
        elapsed = tcp_time_stamp - tp->rcv_tstamp;
 
        if (elapsed >= keepalive_time_when(tp)) {
-               if ((!tp->keepalive_probes && tp->probes_out >= sysctl_tcp_keepalive_probes) ||
-                    (tp->keepalive_probes && tp->probes_out >= tp->keepalive_probes)) {
+               if ((!tp->keepalive_probes && icsk->icsk_probes_out >= sysctl_tcp_keepalive_probes) ||
+                    (tp->keepalive_probes && icsk->icsk_probes_out >= tp->keepalive_probes)) {
                        tcp_send_active_reset(sk, GFP_ATOMIC);
                        tcp_write_err(sk);
                        goto out;
                }
                if (tcp_write_wakeup(sk) <= 0) {
-                       tp->probes_out++;
+                       icsk->icsk_probes_out++;
                        elapsed = keepalive_intvl_when(tp);
                } else {
                        /* If keepalive was lost due to local congestion,
@@ -634,7 +516,7 @@ static void tcp_keepalive_timer (unsigned long data)
        sk_stream_mem_reclaim(sk);
 
 resched:
-       tcp_reset_keepalive_timer (sk, elapsed);
+       inet_csk_reset_keepalive_timer (sk, elapsed);
        goto out;
 
 death: 
@@ -644,8 +526,3 @@ out:
        bh_unlock_sock(sk);
        sock_put(sk);
 }
-
-EXPORT_SYMBOL(tcp_clear_xmit_timers);
-EXPORT_SYMBOL(tcp_delete_keepalive_timer);
-EXPORT_SYMBOL(tcp_init_xmit_timers);
-EXPORT_SYMBOL(tcp_reset_keepalive_timer);
index 9bd443db5193a82c69fee4796e386106f959b705..93c5f92070f9129bfd55667f9945fbaeb7cee194 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
-#include <linux/tcp_diag.h>
+#include <linux/inet_diag.h>
 
 #include <net/tcp.h>
 
@@ -82,9 +82,10 @@ struct vegas {
  * Instead we must wait until the completion of an RTT during
  * which we actually receive ACKs.
  */
-static inline void vegas_enable(struct tcp_sock *tp)
+static inline void vegas_enable(struct sock *sk)
 {
-       struct vegas *vegas = tcp_ca(tp);
+       const struct tcp_sock *tp = tcp_sk(sk);
+       struct vegas *vegas = inet_csk_ca(sk);
 
        /* Begin taking Vegas samples next time we send something. */
        vegas->doing_vegas_now = 1;
@@ -97,19 +98,19 @@ static inline void vegas_enable(struct tcp_sock *tp)
 }
 
 /* Stop taking Vegas samples for now. */
-static inline void vegas_disable(struct tcp_sock *tp)
+static inline void vegas_disable(struct sock *sk)
 {
-       struct vegas *vegas = tcp_ca(tp);
+       struct vegas *vegas = inet_csk_ca(sk);
 
        vegas->doing_vegas_now = 0;
 }
 
-static void tcp_vegas_init(struct tcp_sock *tp)
+static void tcp_vegas_init(struct sock *sk)
 {
-       struct vegas *vegas = tcp_ca(tp);
+       struct vegas *vegas = inet_csk_ca(sk);
 
        vegas->baseRTT = 0x7fffffff;
-       vegas_enable(tp);
+       vegas_enable(sk);
 }
 
 /* Do RTT sampling needed for Vegas.
@@ -120,9 +121,9 @@ static void tcp_vegas_init(struct tcp_sock *tp)
  *   o min-filter RTT samples from a much longer window (forever for now)
  *     to find the propagation delay (baseRTT)
  */
-static void tcp_vegas_rtt_calc(struct tcp_sock *tp, u32 usrtt)
+static void tcp_vegas_rtt_calc(struct sock *sk, u32 usrtt)
 {
-       struct vegas *vegas = tcp_ca(tp);
+       struct vegas *vegas = inet_csk_ca(sk);
        u32 vrtt = usrtt + 1; /* Never allow zero rtt or baseRTT */
 
        /* Filter to find propagation delay: */
@@ -136,13 +137,13 @@ static void tcp_vegas_rtt_calc(struct tcp_sock *tp, u32 usrtt)
        vegas->cntRTT++;
 }
 
-static void tcp_vegas_state(struct tcp_sock *tp, u8 ca_state)
+static void tcp_vegas_state(struct sock *sk, u8 ca_state)
 {
 
        if (ca_state == TCP_CA_Open)
-               vegas_enable(tp);
+               vegas_enable(sk);
        else
-               vegas_disable(tp);
+               vegas_disable(sk);
 }
 
 /*
@@ -154,20 +155,21 @@ static void tcp_vegas_state(struct tcp_sock *tp, u8 ca_state)
  * packets, _then_ we can make Vegas calculations
  * again.
  */
-static void tcp_vegas_cwnd_event(struct tcp_sock *tp, enum tcp_ca_event event)
+static void tcp_vegas_cwnd_event(struct sock *sk, enum tcp_ca_event event)
 {
        if (event == CA_EVENT_CWND_RESTART ||
            event == CA_EVENT_TX_START)
-               tcp_vegas_init(tp);
+               tcp_vegas_init(sk);
 }
 
-static void tcp_vegas_cong_avoid(struct tcp_sock *tp, u32 ack,
+static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack,
                                 u32 seq_rtt, u32 in_flight, int flag)
 {
-       struct vegas *vegas = tcp_ca(tp);
+       struct tcp_sock *tp = tcp_sk(sk);
+       struct vegas *vegas = inet_csk_ca(sk);
 
        if (!vegas->doing_vegas_now)
-               return tcp_reno_cong_avoid(tp, ack, seq_rtt, in_flight, flag);
+               return tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag);
 
        /* The key players are v_beg_snd_una and v_beg_snd_nxt.
         *
@@ -219,7 +221,7 @@ static void tcp_vegas_cong_avoid(struct tcp_sock *tp, u32 ack,
                 * but that's not too awful, since we're taking the min,
                 * rather than averaging.
                 */
-               tcp_vegas_rtt_calc(tp, seq_rtt*1000);
+               tcp_vegas_rtt_calc(sk, seq_rtt * 1000);
 
                /* We do the Vegas calculations only if we got enough RTT
                 * samples that we can be reasonably sure that we got
@@ -359,14 +361,14 @@ static void tcp_vegas_cong_avoid(struct tcp_sock *tp, u32 ack,
 }
 
 /* Extract info for Tcp socket info provided via netlink. */
-static void tcp_vegas_get_info(struct tcp_sock *tp, u32 ext,
+static void tcp_vegas_get_info(struct sock *sk, u32 ext,
                               struct sk_buff *skb)
 {
-       const struct vegas *ca = tcp_ca(tp);
-       if (ext & (1<<(TCPDIAG_VEGASINFO-1))) {
+       const struct vegas *ca = inet_csk_ca(sk);
+       if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) {
                struct tcpvegas_info *info;
 
-               info = RTA_DATA(__RTA_PUT(skb, TCPDIAG_VEGASINFO,
+               info = RTA_DATA(__RTA_PUT(skb, INET_DIAG_VEGASINFO,
                                          sizeof(*info)));
 
                info->tcpv_enabled = ca->doing_vegas_now;
@@ -393,7 +395,7 @@ static struct tcp_congestion_ops tcp_vegas = {
 
 static int __init tcp_vegas_register(void)
 {
-       BUG_ON(sizeof(struct vegas) > TCP_CA_PRIV_SIZE);
+       BUG_ON(sizeof(struct vegas) > ICSK_CA_PRIV_SIZE);
        tcp_register_congestion_control(&tcp_vegas);
        return 0;
 }
index ef827242c940ec4271746111159bf8fb34441968..0c340c3756c2e06082f9cd400a53498614239fae 100644 (file)
@@ -8,7 +8,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
-#include <linux/tcp_diag.h>
+#include <linux/inet_diag.h>
 #include <net/tcp.h>
 
 /* TCP Westwood structure */
@@ -40,9 +40,9 @@ struct westwood {
  * way as soon as possible. It will reasonably happen within the first
  * RTT period of the connection lifetime.
  */
-static void tcp_westwood_init(struct tcp_sock *tp)
+static void tcp_westwood_init(struct sock *sk)
 {
-       struct westwood *w = tcp_ca(tp);
+       struct westwood *w = inet_csk_ca(sk);
 
        w->bk = 0;
         w->bw_ns_est = 0;
@@ -51,7 +51,7 @@ static void tcp_westwood_init(struct tcp_sock *tp)
         w->cumul_ack = 0;
        w->rtt_min = w->rtt = TCP_WESTWOOD_INIT_RTT;
        w->rtt_win_sx = tcp_time_stamp;
-       w->snd_una = tp->snd_una;
+       w->snd_una = tcp_sk(sk)->snd_una;
 }
 
 /*
@@ -74,11 +74,11 @@ static inline void westwood_filter(struct westwood *w, u32 delta)
  * Called after processing group of packets.
  * but all westwood needs is the last sample of srtt.
  */
-static void tcp_westwood_pkts_acked(struct tcp_sock *tp, u32 cnt)
+static void tcp_westwood_pkts_acked(struct sock *sk, u32 cnt)
 {
-       struct westwood *w = tcp_ca(tp);
+       struct westwood *w = inet_csk_ca(sk);
        if (cnt > 0)
-               w->rtt = tp->srtt >> 3;
+               w->rtt = tcp_sk(sk)->srtt >> 3;
 }
 
 /*
@@ -86,9 +86,9 @@ static void tcp_westwood_pkts_acked(struct tcp_sock *tp, u32 cnt)
  * It updates RTT evaluation window if it is the right moment to do
  * it. If so it calls filter for evaluating bandwidth.
  */
-static void westwood_update_window(struct tcp_sock *tp)
+static void westwood_update_window(struct sock *sk)
 {
-       struct westwood *w = tcp_ca(tp);
+       struct westwood *w = inet_csk_ca(sk);
        s32 delta = tcp_time_stamp - w->rtt_win_sx;
 
        /*
@@ -114,11 +114,12 @@ static void westwood_update_window(struct tcp_sock *tp)
  * header prediction is successful. In such case in fact update is
  * straight forward and doesn't need any particular care.
  */
-static inline void westwood_fast_bw(struct tcp_sock *tp)
+static inline void westwood_fast_bw(struct sock *sk)
 {
-       struct westwood *w = tcp_ca(tp);
+       const struct tcp_sock *tp = tcp_sk(sk);
+       struct westwood *w = inet_csk_ca(sk);
 
-       westwood_update_window(tp);
+       westwood_update_window(sk);
 
        w->bk += tp->snd_una - w->snd_una;
        w->snd_una = tp->snd_una;
@@ -130,9 +131,10 @@ static inline void westwood_fast_bw(struct tcp_sock *tp)
  * This function evaluates cumul_ack for evaluating bk in case of
  * delayed or partial acks.
  */
-static inline u32 westwood_acked_count(struct tcp_sock *tp)
+static inline u32 westwood_acked_count(struct sock *sk)
 {
-       struct westwood *w = tcp_ca(tp);
+       const struct tcp_sock *tp = tcp_sk(sk);
+       struct westwood *w = inet_csk_ca(sk);
 
        w->cumul_ack = tp->snd_una - w->snd_una;
 
@@ -160,9 +162,10 @@ static inline u32 westwood_acked_count(struct tcp_sock *tp)
        return w->cumul_ack;
 }
 
-static inline u32 westwood_bw_rttmin(const struct tcp_sock *tp)
+static inline u32 westwood_bw_rttmin(const struct sock *sk)
 {
-       struct westwood *w = tcp_ca(tp);
+       const struct tcp_sock *tp = tcp_sk(sk);
+       const struct westwood *w = inet_csk_ca(sk);
        return max_t(u32, (w->bw_est * w->rtt_min) / tp->mss_cache, 2);
 }
 
@@ -172,31 +175,32 @@ static inline u32 westwood_bw_rttmin(const struct tcp_sock *tp)
  * in packets we use mss_cache). Rttmin is guaranteed to be >= 2
  * so avoids ever returning 0.
  */
-static u32 tcp_westwood_cwnd_min(struct tcp_sock *tp)
+static u32 tcp_westwood_cwnd_min(struct sock *sk)
 {
-       return westwood_bw_rttmin(tp);
+       return westwood_bw_rttmin(sk);
 }
 
-static void tcp_westwood_event(struct tcp_sock *tp, enum tcp_ca_event event)
+static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event)
 {
-       struct westwood *w = tcp_ca(tp);
+       struct tcp_sock *tp = tcp_sk(sk);
+       struct westwood *w = inet_csk_ca(sk);
 
        switch(event) {
        case CA_EVENT_FAST_ACK:
-               westwood_fast_bw(tp);
+               westwood_fast_bw(sk);
                break;
 
        case CA_EVENT_COMPLETE_CWR:
-               tp->snd_cwnd = tp->snd_ssthresh = westwood_bw_rttmin(tp);
+               tp->snd_cwnd = tp->snd_ssthresh = westwood_bw_rttmin(sk);
                break;
 
        case CA_EVENT_FRTO:
-               tp->snd_ssthresh = westwood_bw_rttmin(tp);
+               tp->snd_ssthresh = westwood_bw_rttmin(sk);
                break;
 
        case CA_EVENT_SLOW_ACK:
-               westwood_update_window(tp);
-               w->bk += westwood_acked_count(tp);
+               westwood_update_window(sk);
+               w->bk += westwood_acked_count(sk);
                w->rtt_min = min(w->rtt, w->rtt_min);
                break;
 
@@ -208,15 +212,15 @@ static void tcp_westwood_event(struct tcp_sock *tp, enum tcp_ca_event event)
 
 
 /* Extract info for Tcp socket info provided via netlink. */
-static void tcp_westwood_info(struct tcp_sock *tp, u32 ext,
+static void tcp_westwood_info(struct sock *sk, u32 ext,
                              struct sk_buff *skb)
 {
-       const struct westwood *ca = tcp_ca(tp);
-       if (ext & (1<<(TCPDIAG_VEGASINFO-1))) {
+       const struct westwood *ca = inet_csk_ca(sk);
+       if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) {
                struct rtattr *rta;
                struct tcpvegas_info *info;
 
-               rta = __RTA_PUT(skb, TCPDIAG_VEGASINFO, sizeof(*info));
+               rta = __RTA_PUT(skb, INET_DIAG_VEGASINFO, sizeof(*info));
                info = RTA_DATA(rta);
                info->tcpv_enabled = 1;
                info->tcpv_rttcnt = 0;
@@ -242,7 +246,7 @@ static struct tcp_congestion_ops tcp_westwood = {
 
 static int __init tcp_westwood_register(void)
 {
-       BUG_ON(sizeof(struct westwood) > TCP_CA_PRIV_SIZE);
+       BUG_ON(sizeof(struct westwood) > ICSK_CA_PRIV_SIZE);
        return tcp_register_congestion_control(&tcp_westwood);
 }
 
index dc4d07357e3a1a315285fa645c7dee1c7e4048ac..e5beca7de86c4b67e7455172ac66f6a7ad54ad49 100644 (file)
@@ -95,7 +95,8 @@
 #include <linux/ipv6.h>
 #include <linux/netdevice.h>
 #include <net/snmp.h>
-#include <net/tcp.h>
+#include <net/ip.h>
+#include <net/tcp_states.h>
 #include <net/protocol.h>
 #include <linux/skbuff.h>
 #include <linux/proc_fs.h>
  *     Snmp MIB for the UDP layer
  */
 
-DEFINE_SNMP_STAT(struct udp_mib, udp_statistics);
+DEFINE_SNMP_STAT(struct udp_mib, udp_statistics) __read_mostly;
 
 struct hlist_head udp_hash[UDP_HTABLE_SIZE];
 DEFINE_RWLOCK(udp_hash_lock);
@@ -628,7 +629,7 @@ back_from_confirm:
                /* ... which is an evident application bug. --ANK */
                release_sock(sk);
 
-               LIMIT_NETDEBUG(printk(KERN_DEBUG "udp cork app bug 2\n"));
+               LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n");
                err = -EINVAL;
                goto out;
        }
@@ -693,7 +694,7 @@ static int udp_sendpage(struct sock *sk, struct page *page, int offset,
        if (unlikely(!up->pending)) {
                release_sock(sk);
 
-               LIMIT_NETDEBUG(printk(KERN_DEBUG "udp cork app bug 3\n"));
+               LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 3\n");
                return -EINVAL;
        }
 
@@ -1102,7 +1103,7 @@ static int udp_checksum_init(struct sk_buff *skb, struct udphdr *uh,
                skb->ip_summed = CHECKSUM_UNNECESSARY;
                if (!udp_check(uh, ulen, saddr, daddr, skb->csum))
                        return 0;
-               LIMIT_NETDEBUG(printk(KERN_DEBUG "udp v4 hw csum failure.\n"));
+               LIMIT_NETDEBUG(KERN_DEBUG "udp v4 hw csum failure.\n");
                skb->ip_summed = CHECKSUM_NONE;
        }
        if (skb->ip_summed != CHECKSUM_UNNECESSARY)
@@ -1181,13 +1182,13 @@ int udp_rcv(struct sk_buff *skb)
        return(0);
 
 short_packet:
-       LIMIT_NETDEBUG(printk(KERN_DEBUG "UDP: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n",
-                             NIPQUAD(saddr),
-                             ntohs(uh->source),
-                             ulen,
-                             len,
-                             NIPQUAD(daddr),
-                             ntohs(uh->dest)));
+       LIMIT_NETDEBUG(KERN_DEBUG "UDP: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n",
+                      NIPQUAD(saddr),
+                      ntohs(uh->source),
+                      ulen,
+                      len,
+                      NIPQUAD(daddr),
+                      ntohs(uh->dest));
 no_header:
        UDP_INC_STATS_BH(UDP_MIB_INERRORS);
        kfree_skb(skb);
@@ -1198,12 +1199,12 @@ csum_error:
         * RFC1122: OK.  Discards the bad packet silently (as far as 
         * the network is concerned, anyway) as per 4.1.3.4 (MUST). 
         */
-       LIMIT_NETDEBUG(printk(KERN_DEBUG "UDP: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n",
-                             NIPQUAD(saddr),
-                             ntohs(uh->source),
-                             NIPQUAD(daddr),
-                             ntohs(uh->dest),
-                             ulen));
+       LIMIT_NETDEBUG(KERN_DEBUG "UDP: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n",
+                      NIPQUAD(saddr),
+                      ntohs(uh->source),
+                      NIPQUAD(daddr),
+                      ntohs(uh->dest),
+                      ulen);
 drop:
        UDP_INC_STATS_BH(UDP_MIB_INERRORS);
        kfree_skb(skb);
index 050611d7a9670d178c37cc6a835fd7503f0117b9..d23e07fc81facafe1c7a34e10c9a0d5fc75a4168 100644 (file)
@@ -128,8 +128,10 @@ void __init xfrm4_state_init(void)
        xfrm_state_register_afinfo(&xfrm4_state_afinfo);
 }
 
+#if 0
 void __exit xfrm4_state_fini(void)
 {
        xfrm_state_unregister_afinfo(&xfrm4_state_afinfo);
 }
+#endif  /*  0  */
 
index b39e04940590bd07ad7f311412505ff8201834bc..6460eec834b7b9f9ca354f0b91622698fc2d4cb8 100644 (file)
@@ -8,7 +8,7 @@ ipv6-objs :=    af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o sit.o \
                route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \
                protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
                exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
-               ip6_flowlabel.o ipv6_syms.o
+               ip6_flowlabel.o ipv6_syms.o netfilter.o
 
 ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \
        xfrm6_output.o
@@ -23,3 +23,5 @@ obj-$(CONFIG_NETFILTER)       += netfilter/
 obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
 
 obj-y += exthdrs_core.o
+
+obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
index 77004b9456c049f05cadbc52de47a4880c62fdd7..6d6fb74f3b5291bc2639b250f284905c048de30a 100644 (file)
@@ -1041,9 +1041,9 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
        const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr;
        const struct in6_addr *sk2_rcv_saddr6 = tcp_v6_rcv_saddr(sk2);
        u32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr;
-       u32 sk2_rcv_saddr = tcp_v4_rcv_saddr(sk2);
+       u32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
        int sk_ipv6only = ipv6_only_sock(sk);
-       int sk2_ipv6only = tcp_v6_ipv6only(sk2);
+       int sk2_ipv6only = inet_v6_ipv6only(sk2);
        int addr_type = ipv6_addr_type(sk_rcv_saddr6);
        int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED;
 
@@ -1126,7 +1126,7 @@ void addrconf_leave_solict(struct inet6_dev *idev, struct in6_addr *addr)
        __ipv6_dev_mc_dec(idev, &maddr);
 }
 
-void addrconf_join_anycast(struct inet6_ifaddr *ifp)
+static void addrconf_join_anycast(struct inet6_ifaddr *ifp)
 {
        struct in6_addr addr;
        ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
@@ -1135,7 +1135,7 @@ void addrconf_join_anycast(struct inet6_ifaddr *ifp)
        ipv6_dev_ac_inc(ifp->idev->dev, &addr);
 }
 
-void addrconf_leave_anycast(struct inet6_ifaddr *ifp)
+static void addrconf_leave_anycast(struct inet6_ifaddr *ifp)
 {
        struct in6_addr addr;
        ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
@@ -2858,16 +2858,16 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
 
        skb = alloc_skb(size, GFP_ATOMIC);
        if (!skb) {
-               netlink_set_err(rtnl, 0, RTMGRP_IPV6_IFADDR, ENOBUFS);
+               netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFADDR, ENOBUFS);
                return;
        }
        if (inet6_fill_ifaddr(skb, ifa, current->pid, 0, event, 0) < 0) {
                kfree_skb(skb);
-               netlink_set_err(rtnl, 0, RTMGRP_IPV6_IFADDR, EINVAL);
+               netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFADDR, EINVAL);
                return;
        }
-       NETLINK_CB(skb).dst_groups = RTMGRP_IPV6_IFADDR;
-       netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV6_IFADDR, GFP_ATOMIC);
+       NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_IFADDR;
+       netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_IFADDR, GFP_ATOMIC);
 }
 
 static void inline ipv6_store_devconf(struct ipv6_devconf *cnf,
@@ -2994,16 +2994,16 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
        
        skb = alloc_skb(size, GFP_ATOMIC);
        if (!skb) {
-               netlink_set_err(rtnl, 0, RTMGRP_IPV6_IFINFO, ENOBUFS);
+               netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFINFO, ENOBUFS);
                return;
        }
        if (inet6_fill_ifinfo(skb, idev, current->pid, 0, event, 0) < 0) {
                kfree_skb(skb);
-               netlink_set_err(rtnl, 0, RTMGRP_IPV6_IFINFO, EINVAL);
+               netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFINFO, EINVAL);
                return;
        }
-       NETLINK_CB(skb).dst_groups = RTMGRP_IPV6_IFINFO;
-       netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV6_IFINFO, GFP_ATOMIC);
+       NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_IFINFO;
+       netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_IFINFO, GFP_ATOMIC);
 }
 
 static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev,
@@ -3054,16 +3054,16 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
 
        skb = alloc_skb(size, GFP_ATOMIC);
        if (!skb) {
-               netlink_set_err(rtnl, 0, RTMGRP_IPV6_PREFIX, ENOBUFS);
+               netlink_set_err(rtnl, 0, RTNLGRP_IPV6_PREFIX, ENOBUFS);
                return;
        }
        if (inet6_fill_prefix(skb, idev, pinfo, current->pid, 0, event, 0) < 0) {
                kfree_skb(skb);
-               netlink_set_err(rtnl, 0, RTMGRP_IPV6_PREFIX, EINVAL);
+               netlink_set_err(rtnl, 0, RTNLGRP_IPV6_PREFIX, EINVAL);
                return;
        }
-       NETLINK_CB(skb).dst_groups = RTMGRP_IPV6_PREFIX;
-       netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV6_PREFIX, GFP_ATOMIC);
+       NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_PREFIX;
+       netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_PREFIX, GFP_ATOMIC);
 }
 
 static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = {
@@ -3593,10 +3593,8 @@ void __exit addrconf_cleanup(void)
        rtnl_unlock();
 
 #ifdef CONFIG_IPV6_PRIVACY
-       if (likely(md5_tfm != NULL)) {
-               crypto_free_tfm(md5_tfm);
-               md5_tfm = NULL;
-       }
+       crypto_free_tfm(md5_tfm);
+       md5_tfm = NULL;
 #endif
 
 #ifdef CONFIG_PROC_FS
index 28d9bcab0970ce63fbe6a224a0488b23db6847f9..4f8795af2edb68d950d909952f583ff0e3be8005 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/netdevice.h>
 #include <linux/icmpv6.h>
 #include <linux/smp_lock.h>
+#include <linux/netfilter_ipv6.h>
 
 #include <net/ip.h>
 #include <net/ipv6.h>
@@ -66,45 +67,14 @@ MODULE_AUTHOR("Cast of dozens");
 MODULE_DESCRIPTION("IPv6 protocol stack for Linux");
 MODULE_LICENSE("GPL");
 
-/* IPv6 procfs goodies... */
-
-#ifdef CONFIG_PROC_FS
-extern int raw6_proc_init(void);
-extern void raw6_proc_exit(void);
-extern int tcp6_proc_init(void);
-extern void tcp6_proc_exit(void);
-extern int udp6_proc_init(void);
-extern void udp6_proc_exit(void);
-extern int ipv6_misc_proc_init(void);
-extern void ipv6_misc_proc_exit(void);
-extern int ac6_proc_init(void);
-extern void ac6_proc_exit(void);
-extern int if6_proc_init(void);
-extern void if6_proc_exit(void);
-#endif
-
 int sysctl_ipv6_bindv6only;
 
-#ifdef INET_REFCNT_DEBUG
-atomic_t inet6_sock_nr;
-EXPORT_SYMBOL(inet6_sock_nr);
-#endif
-
 /* The inetsw table contains everything that inet_create needs to
  * build a new socket.
  */
 static struct list_head inetsw6[SOCK_MAX];
 static DEFINE_SPINLOCK(inetsw6_lock);
 
-static void inet6_sock_destruct(struct sock *sk)
-{
-       inet_sock_destruct(sk);
-
-#ifdef INET_REFCNT_DEBUG
-       atomic_dec(&inet6_sock_nr);
-#endif
-}
-
 static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk)
 {
        const int offset = sk->sk_prot->obj_size - sizeof(struct ipv6_pinfo);
@@ -185,7 +155,7 @@ static int inet6_create(struct socket *sock, int protocol)
                        inet->hdrincl = 1;
        }
 
-       sk->sk_destruct         = inet6_sock_destruct;
+       sk->sk_destruct         = inet_sock_destruct;
        sk->sk_family           = PF_INET6;
        sk->sk_protocol         = protocol;
 
@@ -212,12 +182,17 @@ static int inet6_create(struct socket *sock, int protocol)
                inet->pmtudisc = IP_PMTUDISC_DONT;
        else
                inet->pmtudisc = IP_PMTUDISC_WANT;
+       /* 
+        * Increment only the relevant sk_prot->socks debug field, this changes
+        * the previous behaviour of incrementing both the equivalent to
+        * answer->prot->socks (inet6_sock_nr) and inet_sock_nr.
+        *
+        * This allows better debug granularity as we'll know exactly how many
+        * UDPv6, TCPv6, etc socks were allocated, not the sum of all IPv6
+        * transport protocol socks. -acme
+        */
+       sk_refcnt_debug_inc(sk);
 
-
-#ifdef INET_REFCNT_DEBUG
-       atomic_inc(&inet6_sock_nr);
-       atomic_inc(&inet_sock_nr);
-#endif
        if (inet->num) {
                /* It assumes that any protocol which allows
                 * the user to assign a number at socket
@@ -513,11 +488,6 @@ static struct net_proto_family inet6_family_ops = {
        .owner  = THIS_MODULE,
 };
 
-#ifdef CONFIG_SYSCTL
-extern void ipv6_sysctl_register(void);
-extern void ipv6_sysctl_unregister(void);
-#endif
-
 /* Same as inet6_dgram_ops, sans udp_poll.  */
 static struct proto_ops inet6_sockraw_ops = {
        .family =       PF_INET6,
@@ -684,8 +654,6 @@ static void cleanup_ipv6_mibs(void)
        snmp6_mib_free((void **)udp_stats_in6);
 }
 
-extern int ipv6_misc_proc_init(void);
-
 static int __init inet6_init(void)
 {
        struct sk_buff *dummy_skb;
@@ -757,6 +725,9 @@ static int __init inet6_init(void)
        err = igmp6_init(&inet6_family_ops);
        if (err)
                goto igmp_fail;
+       err = ipv6_netfilter_init();
+       if (err)
+               goto netfilter_fail;
        /* Create /proc/foo6 entries. */
 #ifdef CONFIG_PROC_FS
        err = -ENOMEM;
@@ -813,6 +784,8 @@ proc_tcp6_fail:
        raw6_proc_exit();
 proc_raw6_fail:
 #endif
+       ipv6_netfilter_fini();
+netfilter_fail:
        igmp6_cleanup();
 igmp_fail:
        ndisc_cleanup();
@@ -852,6 +825,7 @@ static void __exit inet6_exit(void)
        ip6_route_cleanup();
        ipv6_packet_cleanup();
        igmp6_cleanup();
+       ipv6_netfilter_fini();
        ndisc_cleanup();
        icmpv6_cleanup();
 #ifdef CONFIG_SYSCTL
index 986fdfdccbcdee96a9f2b7d014fa7575ae4bd386..f3629730eb157950c9adc0caec507d1a28379e15 100644 (file)
@@ -131,10 +131,10 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len)
                case NEXTHDR_HOP:
                case NEXTHDR_DEST:
                        if (!zero_out_mutable_opts(exthdr.opth)) {
-                               LIMIT_NETDEBUG(printk(
+                               LIMIT_NETDEBUG(
                                        KERN_WARNING "overrun %sopts\n",
                                        nexthdr == NEXTHDR_HOP ?
-                                               "hop" : "dest"));
+                                               "hop" : "dest");
                                return -EINVAL;
                        }
                        break;
@@ -293,8 +293,7 @@ static int ah6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struc
                skb_push(skb, skb->data - skb->nh.raw);
                ahp->icv(ahp, skb, ah->auth_data);
                if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) {
-                       LIMIT_NETDEBUG(
-                               printk(KERN_WARNING "ipsec ah authentication error\n"));
+                       LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n");
                        x->stats.integrity_failed++;
                        goto free_out;
                }
@@ -332,9 +331,9 @@ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        if (!x)
                return;
 
-       NETDEBUG(printk(KERN_DEBUG "pmtu discovery on SA AH/%08x/"
-                       "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
-              ntohl(ah->spi), NIP6(iph->daddr)));
+       NETDEBUG(KERN_DEBUG "pmtu discovery on SA AH/%08x/"
+                "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+                ntohl(ah->spi), NIP6(iph->daddr));
 
        xfrm_state_put(x);
 }
@@ -402,10 +401,8 @@ static int ah6_init_state(struct xfrm_state *x)
 
 error:
        if (ahp) {
-               if (ahp->work_icv)
-                       kfree(ahp->work_icv);
-               if (ahp->tfm)
-                       crypto_free_tfm(ahp->tfm);
+               kfree(ahp->work_icv);
+               crypto_free_tfm(ahp->tfm);
                kfree(ahp);
        }
        return -EINVAL;
@@ -418,14 +415,10 @@ static void ah6_destroy(struct xfrm_state *x)
        if (!ahp)
                return;
 
-       if (ahp->work_icv) {
-               kfree(ahp->work_icv);
-               ahp->work_icv = NULL;
-       }
-       if (ahp->tfm) {
-               crypto_free_tfm(ahp->tfm);
-               ahp->tfm = NULL;
-       }
+       kfree(ahp->work_icv);
+       ahp->work_icv = NULL;
+       crypto_free_tfm(ahp->tfm);
+       ahp->tfm = NULL;
        kfree(ahp);
 }
 
index 5229365cd8b4849371e498489fe0fe65427c6aa8..01468fab3d3db103388f17d960d46e2f44f4e2f6 100644 (file)
@@ -29,6 +29,7 @@
 #include <net/addrconf.h>
 #include <net/transp_v6.h>
 #include <net/ip6_route.h>
+#include <net/tcp_states.h>
 
 #include <linux/errqueue.h>
 #include <asm/uaccess.h>
@@ -588,8 +589,8 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
                        break;
 
                default:
-                       LIMIT_NETDEBUG(
-                               printk(KERN_DEBUG "invalid cmsg type: %d\n", cmsg->cmsg_type));
+                       LIMIT_NETDEBUG(KERN_DEBUG "invalid cmsg type: %d\n",
+                                      cmsg->cmsg_type);
                        err = -EINVAL;
                        break;
                };
index 324db62515a29e88c51c3fff9fe48e2960ac51da..9b27460f0cc703412e3fb71bba690553cdf799da 100644 (file)
@@ -212,8 +212,7 @@ static int esp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, stru
 
                padlen = nexthdr[0];
                if (padlen+2 >= elen) {
-                       LIMIT_NETDEBUG(
-                               printk(KERN_WARNING "ipsec esp packet is garbage padlen=%d, elen=%d\n", padlen+2, elen));
+                       LIMIT_NETDEBUG(KERN_WARNING "ipsec esp packet is garbage padlen=%d, elen=%d\n", padlen+2, elen);
                        ret = -EINVAL;
                        goto out;
                }
@@ -277,22 +276,14 @@ static void esp6_destroy(struct xfrm_state *x)
        if (!esp)
                return;
 
-       if (esp->conf.tfm) {
-               crypto_free_tfm(esp->conf.tfm);
-               esp->conf.tfm = NULL;
-       }
-       if (esp->conf.ivec) {
-               kfree(esp->conf.ivec);
-               esp->conf.ivec = NULL;
-       }
-       if (esp->auth.tfm) {
-               crypto_free_tfm(esp->auth.tfm);
-               esp->auth.tfm = NULL;
-       }
-       if (esp->auth.work_icv) {
-               kfree(esp->auth.work_icv);
-               esp->auth.work_icv = NULL;
-       }
+       crypto_free_tfm(esp->conf.tfm);
+       esp->conf.tfm = NULL;
+       kfree(esp->conf.ivec);
+       esp->conf.ivec = NULL;
+       crypto_free_tfm(esp->auth.tfm);
+       esp->auth.tfm = NULL;
+       kfree(esp->auth.work_icv);
+       esp->auth.work_icv = NULL;
        kfree(esp);
 }
 
index e0839eafc3a90e36e085ef50f895382d5d441f9a..5be6da2584eec540d38d554b068b0d6ad5ebd910 100644 (file)
@@ -424,8 +424,8 @@ static int ipv6_hop_ra(struct sk_buff *skb, int optoff)
                IP6CB(skb)->ra = optoff;
                return 1;
        }
-       LIMIT_NETDEBUG(
-                printk(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n", skb->nh.raw[optoff+1]));
+       LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n",
+                      skb->nh.raw[optoff+1]);
        kfree_skb(skb);
        return 0;
 }
@@ -437,8 +437,8 @@ static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
        u32 pkt_len;
 
        if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) {
-               LIMIT_NETDEBUG(
-                        printk(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", skb->nh.raw[optoff+1]));
+               LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
+                              skb->nh.raw[optoff+1]);
                IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
                goto drop;
        }
index ff3ec9822e36bb5e8c0100014c20bd8e3b14af50..fa8f1bb0aa52926d4fe1808cedb81a611fbf2885 100644 (file)
@@ -67,7 +67,7 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics);
+DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics) __read_mostly;
 
 /*
  *     The ICMP socket(s). This is the most convenient way to flow control
@@ -332,8 +332,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
         *      for now we don't know that.
         */
        if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
-               LIMIT_NETDEBUG(
-                       printk(KERN_DEBUG "icmpv6_send: addr_any/mcast source\n"));
+               LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: addr_any/mcast source\n");
                return;
        }
 
@@ -341,8 +340,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
         *      Never answer to a ICMP packet.
         */
        if (is_ineligible(skb)) {
-               LIMIT_NETDEBUG(
-                       printk(KERN_DEBUG "icmpv6_send: no reply to icmp error\n")); 
+               LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: no reply to icmp error\n");
                return;
        }
 
@@ -393,8 +391,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
        len = skb->len - msg.offset;
        len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) -sizeof(struct icmp6hdr));
        if (len < 0) {
-               LIMIT_NETDEBUG(
-                       printk(KERN_DEBUG "icmp: len problem\n"));
+               LIMIT_NETDEBUG(KERN_DEBUG "icmp: len problem\n");
                goto out_dst_release;
        }
 
@@ -551,7 +548,8 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info)
 
        read_lock(&raw_v6_lock);
        if ((sk = sk_head(&raw_v6_htable[hash])) != NULL) {
-               while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr))) {
+               while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr,
+                                           IP6CB(skb)->iif))) {
                        rawv6_err(sk, skb, NULL, type, code, inner_offset, info);
                        sk = sk_next(sk);
                }
@@ -583,17 +581,15 @@ static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
                skb->ip_summed = CHECKSUM_UNNECESSARY;
                if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6,
                                    skb->csum)) {
-                       LIMIT_NETDEBUG(
-                               printk(KERN_DEBUG "ICMPv6 hw checksum failed\n"));
+                       LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 hw checksum failed\n");
                        skb->ip_summed = CHECKSUM_NONE;
                }
        }
        if (skb->ip_summed == CHECKSUM_NONE) {
                if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6,
                                    skb_checksum(skb, 0, skb->len, 0))) {
-                       LIMIT_NETDEBUG(
-                               printk(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n",
-                                      NIP6(*saddr), NIP6(*daddr)));
+                       LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n",
+                                      NIP6(*saddr), NIP6(*daddr));
                        goto discard_it;
                }
        }
@@ -669,8 +665,7 @@ static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
                break;
 
        default:
-               LIMIT_NETDEBUG(
-                       printk(KERN_DEBUG "icmpv6: msg of unknown type\n"));
+               LIMIT_NETDEBUG(KERN_DEBUG "icmpv6: msg of unknown type\n");
 
                /* informational */
                if (type & ICMPV6_INFOMSG_MASK)
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
new file mode 100644 (file)
index 0000000..01d5f46
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             Generic INET6 transport hashtables
+ *
+ * Authors:    Lotsa people, from code originally in tcp
+ *
+ *     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/module.h>
+
+#include <net/inet_connection_sock.h>
+#include <net/inet_hashtables.h>
+#include <net/inet6_hashtables.h>
+
+struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
+                                  const struct in6_addr *daddr,
+                                  const unsigned short hnum, const int dif)
+{
+       struct sock *sk;
+       const struct hlist_node *node;
+       struct sock *result = NULL;
+       int score, hiscore = 0;
+
+       read_lock(&hashinfo->lhash_lock);
+       sk_for_each(sk, node, &hashinfo->listening_hash[inet_lhashfn(hnum)]) {
+               if (inet_sk(sk)->num == hnum && sk->sk_family == PF_INET6) {
+                       const struct ipv6_pinfo *np = inet6_sk(sk);
+                       
+                       score = 1;
+                       if (!ipv6_addr_any(&np->rcv_saddr)) {
+                               if (!ipv6_addr_equal(&np->rcv_saddr, daddr))
+                                       continue;
+                               score++;
+                       }
+                       if (sk->sk_bound_dev_if) {
+                               if (sk->sk_bound_dev_if != dif)
+                                       continue;
+                               score++;
+                       }
+                       if (score == 3) {
+                               result = sk;
+                               break;
+                       }
+                       if (score > hiscore) {
+                               hiscore = score;
+                               result = sk;
+                       }
+               }
+       }
+       if (result)
+               sock_hold(result);
+       read_unlock(&hashinfo->lhash_lock);
+       return result;
+}
+
+EXPORT_SYMBOL_GPL(inet6_lookup_listener);
+
+struct sock *inet6_lookup(struct inet_hashinfo *hashinfo,
+                         const struct in6_addr *saddr, const u16 sport,
+                         const struct in6_addr *daddr, const u16 dport,
+                         const int dif)
+{
+       struct sock *sk;
+
+       local_bh_disable();
+       sk = __inet6_lookup(hashinfo, saddr, sport, daddr, ntohs(dport), dif);
+       local_bh_enable();
+
+       return sk;
+}
+
+EXPORT_SYMBOL_GPL(inet6_lookup);
index 1b354aa979340f41c0bc5d413f87dbdf2ff69117..16af874c9e8f15e39242b034ae59d8e623ed3e37 100644 (file)
@@ -49,7 +49,7 @@
 
 struct rt6_statistics  rt6_stats;
 
-static kmem_cache_t * fib6_node_kmem;
+static kmem_cache_t * fib6_node_kmem __read_mostly;
 
 enum fib_walk_state_t
 {
index 10fbb50daea44d1c79b2c40b688c54750e9933e6..6e3480426939150b7c997dc01c41d7a1805951d1 100644 (file)
@@ -56,7 +56,7 @@ static inline int ip6_rcv_finish( struct sk_buff *skb)
        return dst_input(skb);
 }
 
-int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
+int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
 {
        struct ipv6hdr *hdr;
        u32             pkt_len;
@@ -166,8 +166,8 @@ resubmit:
        nexthdr = skb->nh.raw[nhoff];
 
        raw_sk = sk_head(&raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)]);
-       if (raw_sk)
-               ipv6_raw_deliver(skb, nexthdr);
+       if (raw_sk && !ipv6_raw_deliver(skb, nexthdr))
+               raw_sk = NULL;
 
        hash = nexthdr & (MAX_INET_PROTOS - 1);
        if ((ipprot = rcu_dereference(inet6_protos[hash])) != NULL) {
index ae652ca14bc9ef013431324276dc241ab2631ecc..01ef94f7c7f1ce5dfd899703d287be308376a83c 100644 (file)
@@ -153,51 +153,6 @@ int ip6_output(struct sk_buff *skb)
                return ip6_output2(skb);
 }
 
-#ifdef CONFIG_NETFILTER
-int ip6_route_me_harder(struct sk_buff *skb)
-{
-       struct ipv6hdr *iph = skb->nh.ipv6h;
-       struct dst_entry *dst;
-       struct flowi fl = {
-               .oif = skb->sk ? skb->sk->sk_bound_dev_if : 0,
-               .nl_u =
-               { .ip6_u =
-                 { .daddr = iph->daddr,
-                   .saddr = iph->saddr, } },
-               .proto = iph->nexthdr,
-       };
-
-       dst = ip6_route_output(skb->sk, &fl);
-
-       if (dst->error) {
-               IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
-               LIMIT_NETDEBUG(
-                       printk(KERN_DEBUG "ip6_route_me_harder: No more route.\n"));
-               dst_release(dst);
-               return -EINVAL;
-       }
-
-       /* Drop old route. */
-       dst_release(skb->dst);
-
-       skb->dst = dst;
-       return 0;
-}
-#endif
-
-static inline int ip6_maybe_reroute(struct sk_buff *skb)
-{
-#ifdef CONFIG_NETFILTER
-       if (skb->nfcache & NFC_ALTERED){
-               if (ip6_route_me_harder(skb) != 0){
-                       kfree_skb(skb);
-                       return -EINVAL;
-               }
-       }
-#endif /* CONFIG_NETFILTER */
-       return dst_output(skb);
-}
-
 /*
  *     xmit an sk_buff (used by TCP)
  */
@@ -266,7 +221,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
        mtu = dst_mtu(dst);
        if ((skb->len <= mtu) || ipfragok) {
                IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
-               return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
+               return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev,
+                               dst_output);
        }
 
        if (net_ratelimit())
@@ -321,7 +277,9 @@ static int ip6_call_ra_chain(struct sk_buff *skb, int sel)
        read_lock(&ip6_ra_lock);
        for (ra = ip6_ra_chain; ra; ra = ra->next) {
                struct sock *sk = ra->sk;
-               if (sk && ra->sel == sel) {
+               if (sk && ra->sel == sel &&
+                   (!sk->sk_bound_dev_if ||
+                    sk->sk_bound_dev_if == skb->dev->ifindex)) {
                        if (last) {
                                struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
                                if (skb2)
@@ -667,7 +625,7 @@ slow_path:
                 */
 
                if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) {
-                       NETDEBUG(printk(KERN_INFO "IPv6: frag: no memory for new fragment!\n"));
+                       NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n");
                        IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS);
                        err = -ENOMEM;
                        goto fail;
index 135383ef538f5a33573d745d17962237af3ae082..85bfbc69b2c3dc716618f6e528dfcb63658e96b5 100644 (file)
@@ -341,8 +341,7 @@ static void ipcomp6_free_tfms(struct crypto_tfm **tfms)
 
        for_each_cpu(cpu) {
                struct crypto_tfm *tfm = *per_cpu_ptr(tfms, cpu);
-               if (tfm)
-                       crypto_free_tfm(tfm);
+               crypto_free_tfm(tfm);
        }
        free_percpu(tfms);
 }
index 3bc144a79fa5cf454908b83bd32537139212b54b..76466af8331e8c117b12f75b0a6740a5f9a590c5 100644 (file)
@@ -55,7 +55,7 @@
 
 #include <asm/uaccess.h>
 
-DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics);
+DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly;
 
 static struct packet_type ipv6_packet_type = {
        .type = __constant_htons(ETH_P_IPV6), 
@@ -109,13 +109,6 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *))
        return 0;
 }
 
-extern int ip6_mc_source(int add, int omode, struct sock *sk,
-       struct group_source_req *pgsr);
-extern int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf);
-extern int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
-       struct group_filter __user *optval, int __user *optlen);
-
-
 int ipv6_setsockopt(struct sock *sk, int level, int optname,
                    char __user *optval, int optlen)
 {
@@ -163,6 +156,13 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
                        fl6_free_socklist(sk);
                        ipv6_sock_mc_close(sk);
 
+                       /*
+                        * Sock is moving from IPv6 to IPv4 (sk_prot), so
+                        * remove it from the refcnt debug socks count in the
+                        * original family...
+                        */
+                       sk_refcnt_debug_dec(sk);
+
                        if (sk->sk_protocol == IPPROTO_TCP) {
                                struct tcp_sock *tp = tcp_sk(sk);
 
@@ -192,9 +192,11 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
                                kfree_skb(pktopt);
 
                        sk->sk_destruct = inet_sock_destruct;
-#ifdef INET_REFCNT_DEBUG
-                       atomic_dec(&inet6_sock_nr);
-#endif
+                       /*
+                        * ... and add it to the refcnt debug socks count
+                        * in the new family. -acme
+                        */
+                       sk_refcnt_debug_inc(sk);
                        module_put(THIS_MODULE);
                        retv = 0;
                        break;
@@ -437,7 +439,6 @@ done:
        }
        case MCAST_MSFILTER:
        {
-               extern int sysctl_optmem_max;
                extern int sysctl_mld_max_msf;
                struct group_filter *gsf;
 
index 5ade5a5d199053dc20d349a8c8f313263a240260..37a4a99c9fe9e1837e5cd82f686ff3736fd94daa 100644 (file)
@@ -15,9 +15,6 @@ EXPORT_SYMBOL(ndisc_mc_map);
 EXPORT_SYMBOL(register_inet6addr_notifier);
 EXPORT_SYMBOL(unregister_inet6addr_notifier);
 EXPORT_SYMBOL(ip6_route_output);
-#ifdef CONFIG_NETFILTER
-EXPORT_SYMBOL(ip6_route_me_harder);
-#endif
 EXPORT_SYMBOL(addrconf_lock);
 EXPORT_SYMBOL(ipv6_setsockopt);
 EXPORT_SYMBOL(ipv6_getsockopt);
index 7ae72d4c9bd2cbc31cb23f8ad553109bd5fd657a..a7eae30f4554b86ed9d035f0fa1863fab073a115 100644 (file)
@@ -812,7 +812,7 @@ static void ndisc_recv_ns(struct sk_buff *skb)
                if (ipv6_chk_acast_addr(dev, &msg->target) ||
                    (idev->cnf.forwarding && 
                     pneigh_lookup(&nd_tbl, &msg->target, dev, 0))) {
-                       if (skb->stamp.tv_sec != LOCALLY_ENQUEUED &&
+                       if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
                            skb->pkt_type != PACKET_HOST &&
                            inc != 0 &&
                            idev->nd_parms->proxy_delay != 0) {
@@ -1487,6 +1487,8 @@ int ndisc_rcv(struct sk_buff *skb)
                return 0;
        }
 
+       memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
+
        switch (msg->icmph.icmp6_type) {
        case NDISC_NEIGHBOUR_SOLICITATION:
                ndisc_recv_ns(skb);
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
new file mode 100644 (file)
index 0000000..f8626eb
--- /dev/null
@@ -0,0 +1,104 @@
+#include <linux/config.h>
+#include <linux/init.h>
+
+#ifdef CONFIG_NETFILTER
+
+#include <linux/kernel.h>
+#include <linux/ipv6.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6.h>
+#include <net/dst.h>
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+
+int ip6_route_me_harder(struct sk_buff *skb)
+{
+       struct ipv6hdr *iph = skb->nh.ipv6h;
+       struct dst_entry *dst;
+       struct flowi fl = {
+               .oif = skb->sk ? skb->sk->sk_bound_dev_if : 0,
+               .nl_u =
+               { .ip6_u =
+                 { .daddr = iph->daddr,
+                   .saddr = iph->saddr, } },
+               .proto = iph->nexthdr,
+       };
+
+       dst = ip6_route_output(skb->sk, &fl);
+
+       if (dst->error) {
+               IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
+               LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n");
+               dst_release(dst);
+               return -EINVAL;
+       }
+
+       /* Drop old route. */
+       dst_release(skb->dst);
+
+       skb->dst = dst;
+       return 0;
+}
+EXPORT_SYMBOL(ip6_route_me_harder);
+
+/*
+ * Extra routing may needed on local out, as the QUEUE target never
+ * returns control to the table.
+ */
+
+struct ip6_rt_info {
+       struct in6_addr daddr;
+       struct in6_addr saddr;
+};
+
+static void save(const struct sk_buff *skb, struct nf_info *info)
+{
+       struct ip6_rt_info *rt_info = nf_info_reroute(info);
+
+       if (info->hook == NF_IP6_LOCAL_OUT) {
+               struct ipv6hdr *iph = skb->nh.ipv6h;
+
+               rt_info->daddr = iph->daddr;
+               rt_info->saddr = iph->saddr;
+       }
+}
+
+static int reroute(struct sk_buff **pskb, const struct nf_info *info)
+{
+       struct ip6_rt_info *rt_info = nf_info_reroute(info);
+
+       if (info->hook == NF_IP6_LOCAL_OUT) {
+               struct ipv6hdr *iph = (*pskb)->nh.ipv6h;
+               if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) ||
+                   !ipv6_addr_equal(&iph->saddr, &rt_info->saddr))
+                       return ip6_route_me_harder(*pskb);
+       }
+       return 0;
+}
+
+static struct nf_queue_rerouter ip6_reroute = {
+       .rer_size       = sizeof(struct ip6_rt_info),
+       .save           = &save,
+       .reroute        = &reroute,
+};
+
+int __init ipv6_netfilter_init(void)
+{
+       return nf_register_queue_rerouter(PF_INET6, &ip6_reroute);
+}
+
+void ipv6_netfilter_fini(void)
+{
+       nf_unregister_queue_rerouter(PF_INET6);
+}
+
+#else /* CONFIG_NETFILTER */
+int __init ipv6_netfilter_init(void)
+{
+       return 0;
+}
+
+void ipv6_netfilter_fini(void)
+{
+}
+#endif /* CONFIG_NETFILTER */
index 77ec704c9ee34c6315c07f917bc5b17da5e5203e..216fbe1ac65c71c86c4d7545ee2c3025049670c2 100644 (file)
@@ -10,13 +10,16 @@ menu "IPv6: Netfilter Configuration (EXPERIMENTAL)"
 #  dep_tristate '  FTP protocol support' CONFIG_IP6_NF_FTP $CONFIG_IP6_NF_CONNTRACK
 #fi
 config IP6_NF_QUEUE
-       tristate "Userspace queueing via NETLINK"
+       tristate "IP6 Userspace queueing via NETLINK (OBSOLETE)"
        ---help---
 
          This option adds a queue handler to the kernel for IPv6
-         packets which lets us to receive the filtered packets
-         with QUEUE target using libiptc as we can do with
-         the IPv4 now.
+         packets which enables users to receive the filtered packets
+         with QUEUE target using libipq.
+
+         THis option enables the old IPv6-only "ip6_queue" implementation
+         which has been obsoleted by the new "nfnetlink_queue" code (see
+         CONFIG_NETFILTER_NETLINK_QUEUE).
 
          (C) Fernando Anton 2001
          IPv64 Project - Work based in IPv64 draft by Arturo Azcorra.
@@ -196,6 +199,16 @@ config IP6_NF_TARGET_LOG
 
          To compile it as a module, choose M here.  If unsure, say N.
 
+config IP6_NF_TARGET_REJECT
+       tristate "REJECT target support"
+       depends on IP6_NF_FILTER
+       help
+         The REJECT target allows a filtering rule to specify that an ICMPv6
+         error should be issued in response to an incoming packet, rather
+         than silently being dropped.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 #  if [ "$CONFIG_IP6_NF_FILTER" != "n" ]; then
 #    dep_tristate '    REJECT target support' CONFIG_IP6_NF_TARGET_REJECT $CONFIG_IP6_NF_FILTER
 #    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
@@ -226,6 +239,22 @@ config IP6_NF_TARGET_MARK
 
          To compile it as a module, choose M here.  If unsure, say N.
 
+config IP6_NF_TARGET_HL
+       tristate  'HL (hoplimit) target support'
+       depends on IP6_NF_MANGLE
+       help
+         This option adds a `HL' target, which enables the user to decrement
+         the hoplimit value of the IPv6 header or set it to a given (lower)
+         value.
+       
+         While it is safe to decrement the hoplimit value, this option also
+         enables functionality to increment and set the hoplimit value of the
+         IPv6 header to arbitrary values.  This is EXTREMELY DANGEROUS since
+         you can easily create immortal packets that loop forever on the
+         network.  
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 #dep_tristate '  LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES
 config IP6_NF_RAW
        tristate  'raw table support (required for TRACE)'
index 2e51714953b6576d74f328dc9c7c397131692f1f..bd9a16a5cbba3b48e9d9199eb68a16cbb60c1246 100644 (file)
@@ -20,7 +20,10 @@ obj-$(CONFIG_IP6_NF_MATCH_PHYSDEV) += ip6t_physdev.o
 obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
 obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
 obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
+obj-$(CONFIG_IP6_NF_TARGET_HL) += ip6t_HL.o
 obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
 obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
 obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
 obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
+obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
+obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += ip6t_NFQUEUE.o
index a16df5b27c84e8ab93dc5dc42be41c1c5662e591..aa11cf366efab29a428434e014c08034b0eb54ee 100644 (file)
 #define NET_IPQ_QMAX 2088
 #define NET_IPQ_QMAX_NAME "ip6_queue_maxlen"
 
-struct ipq_rt_info {
-       struct in6_addr daddr;
-       struct in6_addr saddr;
-};
-
 struct ipq_queue_entry {
        struct list_head list;
        struct nf_info *info;
        struct sk_buff *skb;
-       struct ipq_rt_info rt_info;
 };
 
 typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long);
@@ -244,8 +238,8 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
 
        pmsg->packet_id       = (unsigned long )entry;
        pmsg->data_len        = data_len;
-       pmsg->timestamp_sec   = entry->skb->stamp.tv_sec;
-       pmsg->timestamp_usec  = entry->skb->stamp.tv_usec;
+       pmsg->timestamp_sec   = skb_tv_base.tv_sec + entry->skb->tstamp.off_sec;
+       pmsg->timestamp_usec  = skb_tv_base.tv_usec + entry->skb->tstamp.off_usec;
        pmsg->mark            = entry->skb->nfmark;
        pmsg->hook            = entry->info->hook;
        pmsg->hw_protocol     = entry->skb->protocol;
@@ -284,7 +278,8 @@ nlmsg_failure:
 }
 
 static int
-ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data)
+ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, 
+                  unsigned int queuenum, void *data)
 {
        int status = -EINVAL;
        struct sk_buff *nskb;
@@ -302,13 +297,6 @@ ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data)
        entry->info = info;
        entry->skb = skb;
 
-       if (entry->info->hook == NF_IP_LOCAL_OUT) {
-               struct ipv6hdr *iph = skb->nh.ipv6h;
-
-               entry->rt_info.daddr = iph->daddr;
-               entry->rt_info.saddr = iph->saddr;
-       }
-
        nskb = ipq_build_packet_message(entry, &status);
        if (nskb == NULL)
                goto err_out_free;
@@ -384,23 +372,11 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
                }
                skb_put(e->skb, diff);
        }
-       if (!skb_ip_make_writable(&e->skb, v->data_len))
+       if (!skb_make_writable(&e->skb, v->data_len))
                return -ENOMEM;
        memcpy(e->skb->data, v->payload, v->data_len);
        e->skb->ip_summed = CHECKSUM_NONE;
-       e->skb->nfcache |= NFC_ALTERED;
-
-       /*
-        * Extra routing may needed on local out, as the QUEUE target never
-        * returns control to the table.
-         * Not a nice way to cmp, but works
-        */
-       if (e->info->hook == NF_IP_LOCAL_OUT) {
-               struct ipv6hdr *iph = e->skb->nh.ipv6h;
-               if (!ipv6_addr_equal(&iph->daddr, &e->rt_info.daddr) ||
-                   !ipv6_addr_equal(&iph->saddr, &e->rt_info.saddr))
-                       return ip6_route_me_harder(e->skb);
-       }
+
        return 0;
 }
 
@@ -676,6 +652,11 @@ ipq_get_info(char *buffer, char **start, off_t offset, int length)
        return len;
 }
 
+static struct nf_queue_handler nfqh = {
+       .name   = "ip6_queue",
+       .outfn  = &ipq_enqueue_packet,
+};
+
 static int
 init_or_cleanup(int init)
 {
@@ -686,7 +667,8 @@ init_or_cleanup(int init)
                goto cleanup;
 
        netlink_register_notifier(&ipq_nl_notifier);
-       ipqnl = netlink_kernel_create(NETLINK_IP6_FW, ipq_rcv_sk);
+       ipqnl = netlink_kernel_create(NETLINK_IP6_FW, 0, ipq_rcv_sk,
+                                     THIS_MODULE);
        if (ipqnl == NULL) {
                printk(KERN_ERR "ip6_queue: failed to create netlink socket\n");
                goto cleanup_netlink_notifier;
@@ -703,7 +685,7 @@ init_or_cleanup(int init)
        register_netdevice_notifier(&ipq_dev_notifier);
        ipq_sysctl_header = register_sysctl_table(ipq_root_table, 0);
        
-       status = nf_register_queue_handler(PF_INET6, ipq_enqueue_packet, NULL);
+       status = nf_register_queue_handler(PF_INET6, &nfqh);
        if (status < 0) {
                printk(KERN_ERR "ip6_queue: failed to register queue handler\n");
                goto cleanup_sysctl;
@@ -711,7 +693,7 @@ init_or_cleanup(int init)
        return status;
 
 cleanup:
-       nf_unregister_queue_handler(PF_INET6);
+       nf_unregister_queue_handlers(&nfqh);
        synchronize_net();
        ipq_flush(NF_DROP);
        
index 73034511c8db49d8b03ec2f441899a2118523af1..1cb8adb2787fc59f44c15dbf0f06ca533955e6f3 100644 (file)
@@ -401,7 +401,6 @@ ip6t_do_table(struct sk_buff **pskb,
        do {
                IP_NF_ASSERT(e);
                IP_NF_ASSERT(back);
-               (*pskb)->nfcache |= e->nfcache;
                if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
                        &protoff, &offset)) {
                        struct ip6t_entry_target *t;
@@ -434,8 +433,8 @@ ip6t_do_table(struct sk_buff **pskb,
                                                         back->comefrom);
                                        continue;
                                }
-                               if (table_base + v
-                                   != (void *)e + e->next_offset) {
+                               if (table_base + v != (void *)e + e->next_offset
+                                   && !(e->ipv6.flags & IP6T_F_GOTO)) {
                                        /* Save old back ptr in next entry */
                                        struct ip6t_entry *next
                                                = (void *)e + e->next_offset;
diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c
new file mode 100644 (file)
index 0000000..8f5549b
--- /dev/null
@@ -0,0 +1,118 @@
+/* 
+ * Hop Limit modification target for ip6tables
+ * Maciej Soltysiak <solt@dns.toxicfilms.tv>
+ * Based on HW's TTL module
+ *
+ * This software is distributed under the terms of GNU GPL
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_HL.h>
+
+MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
+MODULE_DESCRIPTION("IP tables Hop Limit modification module");
+MODULE_LICENSE("GPL");
+
+static unsigned int ip6t_hl_target(struct sk_buff **pskb, 
+                                  const struct net_device *in,
+                                  const struct net_device *out,
+                                  unsigned int hooknum,
+                                  const void *targinfo, void *userinfo)
+{
+       struct ipv6hdr *ip6h;
+       const struct ip6t_HL_info *info = targinfo;
+       u_int16_t diffs[2];
+       int new_hl;
+
+       if (!skb_make_writable(pskb, (*pskb)->len))
+               return NF_DROP;
+
+       ip6h = (*pskb)->nh.ipv6h;
+
+       switch (info->mode) {
+               case IP6T_HL_SET:
+                       new_hl = info->hop_limit;
+                       break;
+               case IP6T_HL_INC:
+                       new_hl = ip6h->hop_limit + info->hop_limit;
+                       if (new_hl > 255)
+                               new_hl = 255;
+                       break;
+               case IP6T_HL_DEC:
+                       new_hl = ip6h->hop_limit - info->hop_limit;
+                       if (new_hl < 0)
+                               new_hl = 0;
+                       break;
+               default:
+                       new_hl = ip6h->hop_limit;
+                       break;
+       }
+
+       if (new_hl != ip6h->hop_limit) {
+               diffs[0] = htons(((unsigned)ip6h->hop_limit) << 8) ^ 0xFFFF;
+               ip6h->hop_limit = new_hl;
+               diffs[1] = htons(((unsigned)ip6h->hop_limit) << 8);
+       }
+
+       return IP6T_CONTINUE;
+}
+
+static int ip6t_hl_checkentry(const char *tablename,
+               const struct ip6t_entry *e,
+               void *targinfo,
+               unsigned int targinfosize,
+               unsigned int hook_mask)
+{
+       struct ip6t_HL_info *info = targinfo;
+
+       if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HL_info))) {
+               printk(KERN_WARNING "ip6t_HL: targinfosize %u != %Zu\n",
+                               targinfosize,
+                               IP6T_ALIGN(sizeof(struct ip6t_HL_info)));
+               return 0;       
+       }       
+
+       if (strcmp(tablename, "mangle")) {
+               printk(KERN_WARNING "ip6t_HL: can only be called from "
+                       "\"mangle\" table, not \"%s\"\n", tablename);
+               return 0;
+       }
+
+       if (info->mode > IP6T_HL_MAXMODE) {
+               printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n", 
+                       info->mode);
+               return 0;
+       }
+
+       if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) {
+               printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't "
+                       "make sense with value 0\n");
+               return 0;
+       }
+       
+       return 1;
+}
+
+static struct ip6t_target ip6t_HL = { 
+       .name           = "HL", 
+       .target         = ip6t_hl_target, 
+       .checkentry     = ip6t_hl_checkentry, 
+       .me             = THIS_MODULE
+};
+
+static int __init init(void)
+{
+       return ip6t_register_target(&ip6t_HL);
+}
+
+static void __exit fini(void)
+{
+       ip6t_unregister_target(&ip6t_HL);
+}
+
+module_init(init);
+module_exit(fini);
index a692e26a4fa37715eecdc87bbb647efcc7f796e7..0cd1d1bd9033ced7e87f26ef5193983e24951159 100644 (file)
@@ -26,10 +26,6 @@ MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>");
 MODULE_DESCRIPTION("IP6 tables LOG target module");
 MODULE_LICENSE("GPL");
 
-static unsigned int nflog = 1;
-module_param(nflog, int, 0400);
-MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
 struct in_device;
 #include <net/route.h>
 #include <linux/netfilter_ipv6/ip6t_LOG.h>
@@ -44,7 +40,7 @@ struct in_device;
 static DEFINE_SPINLOCK(log_lock);
 
 /* One level of recursion won't kill us */
-static void dump_packet(const struct ip6t_log_info *info,
+static void dump_packet(const struct nf_loginfo *info,
                        const struct sk_buff *skb, unsigned int ip6hoff,
                        int recurse)
 {
@@ -53,6 +49,12 @@ static void dump_packet(const struct ip6t_log_info *info,
        struct ipv6hdr _ip6h, *ih;
        unsigned int ptr;
        unsigned int hdrlen = 0;
+       unsigned int logflags;
+
+       if (info->type == NF_LOG_TYPE_LOG)
+               logflags = info->u.log.logflags;
+       else
+               logflags = NF_LOG_MASK;
 
        ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h);
        if (ih == NULL) {
@@ -84,7 +86,7 @@ static void dump_packet(const struct ip6t_log_info *info,
                }
 
                /* Max length: 48 "OPT (...) " */
-               if (info->logflags & IP6T_LOG_IPOPT)
+               if (logflags & IP6T_LOG_IPOPT)
                        printk("OPT ( ");
 
                switch (currenthdr) {
@@ -119,7 +121,7 @@ static void dump_packet(const struct ip6t_log_info *info,
                case IPPROTO_ROUTING:
                case IPPROTO_HOPOPTS:
                        if (fragment) {
-                               if (info->logflags & IP6T_LOG_IPOPT)
+                               if (logflags & IP6T_LOG_IPOPT)
                                        printk(")");
                                return;
                        }
@@ -127,7 +129,7 @@ static void dump_packet(const struct ip6t_log_info *info,
                        break;
                /* Max Length */
                case IPPROTO_AH:
-                       if (info->logflags & IP6T_LOG_IPOPT) {
+                       if (logflags & IP6T_LOG_IPOPT) {
                                struct ip_auth_hdr _ahdr, *ah;
 
                                /* Max length: 3 "AH " */
@@ -158,7 +160,7 @@ static void dump_packet(const struct ip6t_log_info *info,
                        hdrlen = (hp->hdrlen+2)<<2;
                        break;
                case IPPROTO_ESP:
-                       if (info->logflags & IP6T_LOG_IPOPT) {
+                       if (logflags & IP6T_LOG_IPOPT) {
                                struct ip_esp_hdr _esph, *eh;
 
                                /* Max length: 4 "ESP " */
@@ -190,7 +192,7 @@ static void dump_packet(const struct ip6t_log_info *info,
                        printk("Unknown Ext Hdr %u", currenthdr);
                        return;
                }
-               if (info->logflags & IP6T_LOG_IPOPT)
+               if (logflags & IP6T_LOG_IPOPT)
                        printk(") ");
 
                currenthdr = hp->nexthdr;
@@ -218,7 +220,7 @@ static void dump_packet(const struct ip6t_log_info *info,
                printk("SPT=%u DPT=%u ",
                       ntohs(th->source), ntohs(th->dest));
                /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */
-               if (info->logflags & IP6T_LOG_TCPSEQ)
+               if (logflags & IP6T_LOG_TCPSEQ)
                        printk("SEQ=%u ACK=%u ",
                               ntohl(th->seq), ntohl(th->ack_seq));
                /* Max length: 13 "WINDOW=65535 " */
@@ -245,7 +247,7 @@ static void dump_packet(const struct ip6t_log_info *info,
                /* Max length: 11 "URGP=65535 " */
                printk("URGP=%u ", ntohs(th->urg_ptr));
 
-               if ((info->logflags & IP6T_LOG_TCPOPT)
+               if ((logflags & IP6T_LOG_TCPOPT)
                    && th->doff * 4 > sizeof(struct tcphdr)) {
                        u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
                        unsigned int i;
@@ -349,7 +351,7 @@ static void dump_packet(const struct ip6t_log_info *info,
        }
 
        /* Max length: 15 "UID=4294967295 " */
-       if ((info->logflags & IP6T_LOG_UID) && recurse && skb->sk) {
+       if ((logflags & IP6T_LOG_UID) && recurse && skb->sk) {
                read_lock_bh(&skb->sk->sk_callback_lock);
                if (skb->sk->sk_socket && skb->sk->sk_socket->file)
                        printk("UID=%u ", skb->sk->sk_socket->file->f_uid);
@@ -357,19 +359,31 @@ static void dump_packet(const struct ip6t_log_info *info,
        }
 }
 
+static struct nf_loginfo default_loginfo = {
+       .type   = NF_LOG_TYPE_LOG,
+       .u = {
+               .log = {
+                       .level    = 0,
+                       .logflags = NF_LOG_MASK,
+               },
+       },
+};
+
 static void
-ip6t_log_packet(unsigned int hooknum,
+ip6t_log_packet(unsigned int pf,
+               unsigned int hooknum,
                const struct sk_buff *skb,
                const struct net_device *in,
                const struct net_device *out,
-               const struct ip6t_log_info *loginfo,
-               const char *level_string,
+               const struct nf_loginfo *loginfo,
                const char *prefix)
 {
+       if (!loginfo)
+               loginfo = &default_loginfo;
+
        spin_lock_bh(&log_lock);
-       printk(level_string);
-       printk("%sIN=%s OUT=%s ",
-               prefix == NULL ? loginfo->prefix : prefix,
+       printk("<%d>%sIN=%s OUT=%s ", loginfo->u.log.level, 
+               prefix,
                in ? in->name : "",
                out ? out->name : "");
        if (in && !out) {
@@ -416,29 +430,17 @@ ip6t_log_target(struct sk_buff **pskb,
                void *userinfo)
 {
        const struct ip6t_log_info *loginfo = targinfo;
-       char level_string[4] = "< >";
+       struct nf_loginfo li;
+
+       li.type = NF_LOG_TYPE_LOG;
+       li.u.log.level = loginfo->level;
+       li.u.log.logflags = loginfo->logflags;
 
-       level_string[1] = '0' + (loginfo->level % 8);
-       ip6t_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL);
+       nf_log_packet(PF_INET6, hooknum, *pskb, in, out, &li, loginfo->prefix);
 
        return IP6T_CONTINUE;
 }
 
-static void
-ip6t_logfn(unsigned int hooknum,
-          const struct sk_buff *skb,
-          const struct net_device *in,
-          const struct net_device *out,
-          const char *prefix)
-{
-       struct ip6t_log_info loginfo = {
-               .level = 0,
-               .logflags = IP6T_LOG_MASK,
-               .prefix = ""
-       };
-
-       ip6t_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix);
-}
 
 static int ip6t_log_checkentry(const char *tablename,
                               const struct ip6t_entry *e,
@@ -475,20 +477,29 @@ static struct ip6t_target ip6t_log_reg = {
        .me             = THIS_MODULE,
 };
 
+static struct nf_logger ip6t_logger = {
+       .name           = "ip6t_LOG",
+       .logfn          = &ip6t_log_packet,
+       .me             = THIS_MODULE,
+};
+
 static int __init init(void)
 {
        if (ip6t_register_target(&ip6t_log_reg))
                return -EINVAL;
-       if (nflog)
-               nf_log_register(PF_INET6, &ip6t_logfn);
+       if (nf_log_register(PF_INET6, &ip6t_logger) < 0) {
+               printk(KERN_WARNING "ip6t_LOG: not logging via system console "
+                      "since somebody else already registered for PF_INET6\n");
+               /* we cannot make module load fail here, since otherwise
+                * ip6tables userspace would abort */
+       }
 
        return 0;
 }
 
 static void __exit fini(void)
 {
-       if (nflog)
-               nf_log_unregister(PF_INET6, &ip6t_logfn);
+       nf_log_unregister_logger(&ip6t_logger);
        ip6t_unregister_target(&ip6t_log_reg);
 }
 
index d09ceb05013a90346f916a44a5c77830164a4250..81924fcc5857afd71f571cdda023448ef2d7931e 100644 (file)
@@ -28,10 +28,9 @@ target(struct sk_buff **pskb,
 {
        const struct ip6t_mark_target_info *markinfo = targinfo;
 
-       if((*pskb)->nfmark != markinfo->mark) {
+       if((*pskb)->nfmark != markinfo->mark)
                (*pskb)->nfmark = markinfo->mark;
-               (*pskb)->nfcache |= NFC_ALTERED;
-       }
+
        return IP6T_CONTINUE;
 }
 
diff --git a/net/ipv6/netfilter/ip6t_NFQUEUE.c b/net/ipv6/netfilter/ip6t_NFQUEUE.c
new file mode 100644 (file)
index 0000000..c6e3730
--- /dev/null
@@ -0,0 +1,70 @@
+/* ip6tables module for using new netfilter netlink queue
+ *
+ * (C) 2005 by Harald Welte <laforge@netfilter.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/skbuff.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv4/ipt_NFQUEUE.h>
+
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_DESCRIPTION("ip6tables NFQUEUE target");
+MODULE_LICENSE("GPL");
+
+static unsigned int
+target(struct sk_buff **pskb,
+       const struct net_device *in,
+       const struct net_device *out,
+       unsigned int hooknum,
+       const void *targinfo,
+       void *userinfo)
+{
+       const struct ipt_NFQ_info *tinfo = targinfo;
+
+       return NF_QUEUE_NR(tinfo->queuenum);
+}
+
+static int
+checkentry(const char *tablename,
+          const struct ip6t_entry *e,
+           void *targinfo,
+           unsigned int targinfosize,
+           unsigned int hook_mask)
+{
+       if (targinfosize != IP6T_ALIGN(sizeof(struct ipt_NFQ_info))) {
+               printk(KERN_WARNING "NFQUEUE: targinfosize %u != %Zu\n",
+                      targinfosize,
+                      IP6T_ALIGN(sizeof(struct ipt_NFQ_info)));
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct ip6t_target ipt_NFQ_reg = {
+       .name           = "NFQUEUE",
+       .target         = target,
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       return ip6t_register_target(&ipt_NFQ_reg);
+}
+
+static void __exit fini(void)
+{
+       ip6t_unregister_target(&ipt_NFQ_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
new file mode 100644 (file)
index 0000000..14316c3
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * IP6 tables REJECT target module
+ * Linux INET6 implementation
+ *
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ *     Yasuyuki Kozakai        <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on net/ipv4/netfilter/ipt_REJECT.c
+ *
+ * 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/module.h>
+#include <linux/skbuff.h>
+#include <linux/icmpv6.h>
+#include <linux/netdevice.h>
+#include <net/ipv6.h>
+#include <net/tcp.h>
+#include <net/icmp.h>
+#include <net/ip6_checksum.h>
+#include <net/ip6_fib.h>
+#include <net/ip6_route.h>
+#include <net/flow.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_REJECT.h>
+
+MODULE_AUTHOR("Yasuyuki KOZAKAI <yasuyuki.kozakai@toshiba.co.jp>");
+MODULE_DESCRIPTION("IP6 tables REJECT target module");
+MODULE_LICENSE("GPL");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/* Send RST reply */
+static void send_reset(struct sk_buff *oldskb)
+{
+       struct sk_buff *nskb;
+       struct tcphdr otcph, *tcph;
+       unsigned int otcplen, hh_len;
+       int tcphoff, needs_ack;
+       struct ipv6hdr *oip6h = oldskb->nh.ipv6h, *ip6h;
+       struct dst_entry *dst = NULL;
+       u8 proto;
+       struct flowi fl;
+
+       if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
+           (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) {
+               DEBUGP("ip6t_REJECT: addr is not unicast.\n");
+               return;
+       }
+
+       proto = oip6h->nexthdr;
+       tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto);
+
+       if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
+               DEBUGP("ip6t_REJECT: Can't get TCP header.\n");
+               return;
+       }
+
+       otcplen = oldskb->len - tcphoff;
+
+       /* IP header checks: fragment, too short. */
+       if ((proto != IPPROTO_TCP) || (otcplen < sizeof(struct tcphdr))) {
+               DEBUGP("ip6t_REJECT: proto(%d) != IPPROTO_TCP, or too short. otcplen = %d\n",
+                       proto, otcplen);
+               return;
+       }
+
+       if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr)))
+               BUG();
+
+       /* No RST for RST. */
+       if (otcph.rst) {
+               DEBUGP("ip6t_REJECT: RST is set\n");
+               return;
+       }
+
+       /* Check checksum. */
+       if (csum_ipv6_magic(&oip6h->saddr, &oip6h->daddr, otcplen, IPPROTO_TCP,
+                           skb_checksum(oldskb, tcphoff, otcplen, 0))) {
+               DEBUGP("ip6t_REJECT: TCP checksum is invalid\n");
+               return;
+       }
+
+       memset(&fl, 0, sizeof(fl));
+       fl.proto = IPPROTO_TCP;
+       ipv6_addr_copy(&fl.fl6_src, &oip6h->daddr);
+       ipv6_addr_copy(&fl.fl6_dst, &oip6h->saddr);
+       fl.fl_ip_sport = otcph.dest;
+       fl.fl_ip_dport = otcph.source;
+       dst = ip6_route_output(NULL, &fl);
+       if (dst == NULL)
+               return;
+       if (dst->error ||
+           xfrm_lookup(&dst, &fl, NULL, 0)) {
+               dst_release(dst);
+               return;
+       }
+
+       hh_len = (dst->dev->hard_header_len + 15)&~15;
+       nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr)
+                        + sizeof(struct tcphdr) + dst->trailer_len,
+                        GFP_ATOMIC);
+
+       if (!nskb) {
+               if (net_ratelimit())
+                       printk("ip6t_REJECT: Can't alloc skb\n");
+               dst_release(dst);
+               return;
+       }
+
+       nskb->dst = dst;
+
+       skb_reserve(nskb, hh_len + dst->header_len);
+
+       ip6h = nskb->nh.ipv6h = (struct ipv6hdr *)
+                                       skb_put(nskb, sizeof(struct ipv6hdr));
+       ip6h->version = 6;
+       ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
+       ip6h->nexthdr = IPPROTO_TCP;
+       ip6h->payload_len = htons(sizeof(struct tcphdr));
+       ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr);
+       ipv6_addr_copy(&ip6h->daddr, &oip6h->saddr);
+
+       tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
+       /* Truncate to length (no data) */
+       tcph->doff = sizeof(struct tcphdr)/4;
+       tcph->source = otcph.dest;
+       tcph->dest = otcph.source;
+
+       if (otcph.ack) {
+               needs_ack = 0;
+               tcph->seq = otcph.ack_seq;
+               tcph->ack_seq = 0;
+       } else {
+               needs_ack = 1;
+               tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin
+                                     + otcplen - (otcph.doff<<2));
+               tcph->seq = 0;
+       }
+
+       /* Reset flags */
+       ((u_int8_t *)tcph)[13] = 0;
+       tcph->rst = 1;
+       tcph->ack = needs_ack;
+       tcph->window = 0;
+       tcph->urg_ptr = 0;
+       tcph->check = 0;
+
+       /* Adjust TCP checksum */
+       tcph->check = csum_ipv6_magic(&nskb->nh.ipv6h->saddr,
+                                     &nskb->nh.ipv6h->daddr,
+                                     sizeof(struct tcphdr), IPPROTO_TCP,
+                                     csum_partial((char *)tcph,
+                                                  sizeof(struct tcphdr), 0));
+
+       NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
+               dst_output);
+}
+
+static inline void
+send_unreach(struct sk_buff *skb_in, unsigned char code, unsigned int hooknum)
+{
+       if (hooknum == NF_IP6_LOCAL_OUT && skb_in->dev == NULL)
+               skb_in->dev = &loopback_dev;
+
+       icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0, NULL);
+}
+
+static unsigned int reject6_target(struct sk_buff **pskb,
+                          const struct net_device *in,
+                          const struct net_device *out,
+                          unsigned int hooknum,
+                          const void *targinfo,
+                          void *userinfo)
+{
+       const struct ip6t_reject_info *reject = targinfo;
+
+       DEBUGP(KERN_DEBUG "%s: medium point\n", __FUNCTION__);
+       /* WARNING: This code causes reentry within ip6tables.
+          This means that the ip6tables jump stack is now crap.  We
+          must return an absolute verdict. --RR */
+       switch (reject->with) {
+       case IP6T_ICMP6_NO_ROUTE:
+               send_unreach(*pskb, ICMPV6_NOROUTE, hooknum);
+               break;
+       case IP6T_ICMP6_ADM_PROHIBITED:
+               send_unreach(*pskb, ICMPV6_ADM_PROHIBITED, hooknum);
+               break;
+       case IP6T_ICMP6_NOT_NEIGHBOUR:
+               send_unreach(*pskb, ICMPV6_NOT_NEIGHBOUR, hooknum);
+               break;
+       case IP6T_ICMP6_ADDR_UNREACH:
+               send_unreach(*pskb, ICMPV6_ADDR_UNREACH, hooknum);
+               break;
+       case IP6T_ICMP6_PORT_UNREACH:
+               send_unreach(*pskb, ICMPV6_PORT_UNREACH, hooknum);
+               break;
+       case IP6T_ICMP6_ECHOREPLY:
+               /* Do nothing */
+               break;
+       case IP6T_TCP_RESET:
+               send_reset(*pskb);
+               break;
+       default:
+               if (net_ratelimit())
+                       printk(KERN_WARNING "ip6t_REJECT: case %u not handled yet\n", reject->with);
+               break;
+       }
+
+       return NF_DROP;
+}
+
+static int check(const char *tablename,
+                const struct ip6t_entry *e,
+                void *targinfo,
+                unsigned int targinfosize,
+                unsigned int hook_mask)
+{
+       const struct ip6t_reject_info *rejinfo = targinfo;
+
+       if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
+               DEBUGP("ip6t_REJECT: targinfosize %u != 0\n", targinfosize);
+               return 0;
+       }
+
+       /* Only allow these for packet filtering. */
+       if (strcmp(tablename, "filter") != 0) {
+               DEBUGP("ip6t_REJECT: bad table `%s'.\n", tablename);
+               return 0;
+       }
+
+       if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN)
+                          | (1 << NF_IP6_FORWARD)
+                          | (1 << NF_IP6_LOCAL_OUT))) != 0) {
+               DEBUGP("ip6t_REJECT: bad hook mask %X\n", hook_mask);
+               return 0;
+       }
+
+       if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
+               printk("ip6t_REJECT: ECHOREPLY is not supported.\n");
+               return 0;
+       } else if (rejinfo->with == IP6T_TCP_RESET) {
+               /* Must specify that it's a TCP packet */
+               if (e->ipv6.proto != IPPROTO_TCP
+                   || (e->ipv6.invflags & IP6T_INV_PROTO)) {
+                       DEBUGP("ip6t_REJECT: TCP_RESET illegal for non-tcp\n");
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
+static struct ip6t_target ip6t_reject_reg = {
+       .name           = "REJECT",
+       .target         = reject6_target,
+       .checkentry     = check,
+       .me             = THIS_MODULE
+};
+
+static int __init init(void)
+{
+       if (ip6t_register_target(&ip6t_reject_reg))
+               return -EINVAL;
+       return 0;
+}
+
+static void __exit fini(void)
+{
+       ip6t_unregister_target(&ip6t_reject_reg);
+}
+
+module_init(init);
+module_exit(fini);
index ab0e32d3de462fea928017ae728374b0c1e1a200..9b91decbfddba43f44f05ab1fe104e9c4c016000 100644 (file)
@@ -20,71 +20,6 @@ MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
 MODULE_DESCRIPTION("IP6 tables owner matching module");
 MODULE_LICENSE("GPL");
 
-static int
-match_pid(const struct sk_buff *skb, pid_t pid)
-{
-       struct task_struct *p;
-       struct files_struct *files;
-       int i;
-
-       read_lock(&tasklist_lock);
-       p = find_task_by_pid(pid);
-       if (!p)
-               goto out;
-       task_lock(p);
-       files = p->files;
-       if(files) {
-               spin_lock(&files->file_lock);
-               for (i=0; i < files->max_fds; i++) {
-                       if (fcheck_files(files, i) == skb->sk->sk_socket->file) {
-                               spin_unlock(&files->file_lock);
-                               task_unlock(p);
-                               read_unlock(&tasklist_lock);
-                               return 1;
-                       }
-               }
-               spin_unlock(&files->file_lock);
-       }
-       task_unlock(p);
-out:
-       read_unlock(&tasklist_lock);
-       return 0;
-}
-
-static int
-match_sid(const struct sk_buff *skb, pid_t sid)
-{
-       struct task_struct *g, *p;
-       struct file *file = skb->sk->sk_socket->file;
-       int i, found=0;
-
-       read_lock(&tasklist_lock);
-       do_each_thread(g, p) {
-               struct files_struct *files;
-               if (p->signal->session != sid)
-                       continue;
-
-               task_lock(p);
-               files = p->files;
-               if (files) {
-                       spin_lock(&files->file_lock);
-                       for (i=0; i < files->max_fds; i++) {
-                               if (fcheck_files(files, i) == file) {
-                                       found = 1;
-                                       break;
-                               }
-                       }
-                       spin_unlock(&files->file_lock);
-               }
-               task_unlock(p);
-               if (found)
-                       goto out;
-       } while_each_thread(g, p);
-out:
-       read_unlock(&tasklist_lock);
-
-       return found;
-}
 
 static int
 match(const struct sk_buff *skb,
@@ -112,18 +47,6 @@ match(const struct sk_buff *skb,
                        return 0;
        }
 
-       if(info->match & IP6T_OWNER_PID) {
-               if (!match_pid(skb, info->pid) ^
-                   !!(info->invert & IP6T_OWNER_PID))
-                       return 0;
-       }
-
-       if(info->match & IP6T_OWNER_SID) {
-               if (!match_sid(skb, info->sid) ^
-                   !!(info->invert & IP6T_OWNER_SID))
-                       return 0;
-       }
-
        return 1;
 }
 
@@ -134,6 +57,8 @@ checkentry(const char *tablename,
            unsigned int matchsize,
            unsigned int hook_mask)
 {
+       const struct ip6t_owner_info *info = matchinfo;
+
         if (hook_mask
             & ~((1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING))) {
                 printk("ip6t_owner: only valid for LOCAL_OUT or POST_ROUTING.\n");
@@ -142,14 +67,13 @@ checkentry(const char *tablename,
 
        if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_owner_info)))
                return 0;
-#ifdef CONFIG_SMP
-       /* files->file_lock can not be used in a BH */
-       if (((struct ip6t_owner_info *)matchinfo)->match
-           & (IP6T_OWNER_PID|IP6T_OWNER_SID)) {
-               printk("ip6t_owner: pid and sid matching is broken on SMP.\n");
+
+       if (info->match & (IP6T_OWNER_PID|IP6T_OWNER_SID)) {
+               printk("ipt_owner: pid and sid matching "
+                      "not supported anymore\n");
                return 0;
        }
-#endif
+
        return 1;
 }
 
index 1d4d75b34d321c19ec892013c9f3b73bdfa3d9fe..ed3a76b30fd932db9153b0fd31ea405ff97cc15a 100644 (file)
@@ -49,6 +49,7 @@
 #include <net/transp_v6.h>
 #include <net/udp.h>
 #include <net/inet_common.h>
+#include <net/tcp_states.h>
 
 #include <net/rawv6.h>
 #include <net/xfrm.h>
@@ -81,7 +82,8 @@ static void raw_v6_unhash(struct sock *sk)
 
 /* Grumble... icmp and ip_input want to get at this... */
 struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num,
-                            struct in6_addr *loc_addr, struct in6_addr *rmt_addr)
+                            struct in6_addr *loc_addr, struct in6_addr *rmt_addr,
+                            int dif)
 {
        struct hlist_node *node;
        int is_multicast = ipv6_addr_is_multicast(loc_addr);
@@ -94,6 +96,9 @@ struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num,
                            !ipv6_addr_equal(&np->daddr, rmt_addr))
                                continue;
 
+                       if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)
+                               continue;
+
                        if (!ipv6_addr_any(&np->rcv_saddr)) {
                                if (ipv6_addr_equal(&np->rcv_saddr, loc_addr))
                                        goto found;
@@ -137,11 +142,12 @@ static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb)
  *
  *     Caller owns SKB so we must make clones.
  */
-void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
+int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
 {
        struct in6_addr *saddr;
        struct in6_addr *daddr;
        struct sock *sk;
+       int delivered = 0;
        __u8 hash;
 
        saddr = &skb->nh.ipv6h->saddr;
@@ -160,9 +166,10 @@ void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
        if (sk == NULL)
                goto out;
 
-       sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr);
+       sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, IP6CB(skb)->iif);
 
        while (sk) {
+               delivered = 1;
                if (nexthdr != IPPROTO_ICMPV6 || !icmpv6_filter(sk, skb)) {
                        struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
 
@@ -170,10 +177,12 @@ void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
                        if (clone)
                                rawv6_rcv(sk, clone);
                }
-               sk = __raw_v6_lookup(sk_next(sk), nexthdr, daddr, saddr);
+               sk = __raw_v6_lookup(sk_next(sk), nexthdr, daddr, saddr,
+                                    IP6CB(skb)->iif);
        }
 out:
        read_unlock(&raw_v6_lock);
+       return delivered;
 }
 
 /* This cleans up af_inet6 a bit. -DaveM */
@@ -334,8 +343,7 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb)
                        if (csum_ipv6_magic(&skb->nh.ipv6h->saddr,
                                            &skb->nh.ipv6h->daddr,
                                            skb->len, inet->num, skb->csum)) {
-                               LIMIT_NETDEBUG(
-                               printk(KERN_DEBUG "raw v6 hw csum failure.\n"));
+                               LIMIT_NETDEBUG(KERN_DEBUG "raw v6 hw csum failure.\n");
                                skb->ip_summed = CHECKSUM_NONE;
                        }
                }
index 59e7c631787279bef822efccb9ea4e51813bcc6e..9d9e04344c777c8bd331b7b1f5e566fae38351e4 100644 (file)
@@ -562,7 +562,7 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
        if (skb->dev)
                fq->iif = skb->dev->ifindex;
        skb->dev = NULL;
-       fq->stamp = skb->stamp;
+       skb_get_timestamp(skb, &fq->stamp);
        fq->meat += skb->len;
        atomic_add(skb->truesize, &ip6_frag_mem);
 
@@ -664,7 +664,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
 
        head->next = NULL;
        head->dev = dev;
-       head->stamp = fq->stamp;
+       skb_set_timestamp(head, &fq->stamp);
        head->nh.ipv6h->payload_len = htons(payload_len);
 
        *skb_in = head;
index 878789b3122de74a29ffe4b9cf59963d35bb7b11..5d5bbb49ec7893811743477e45ed1e6a651b2115 100644 (file)
@@ -1372,7 +1372,7 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg)
  *     Drop the packet on the floor
  */
 
-int ip6_pkt_discard(struct sk_buff *skb)
+static int ip6_pkt_discard(struct sk_buff *skb)
 {
        IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
        icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, skb->dev);
@@ -1380,7 +1380,7 @@ int ip6_pkt_discard(struct sk_buff *skb)
        return 0;
 }
 
-int ip6_pkt_discard_out(struct sk_buff *skb)
+static int ip6_pkt_discard_out(struct sk_buff *skb)
 {
        skb->dev = skb->dst->dev;
        return ip6_pkt_discard(skb);
@@ -1850,16 +1850,16 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nlmsghdr *nlh,
        
        skb = alloc_skb(size, gfp_any());
        if (!skb) {
-               netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, ENOBUFS);
+               netlink_set_err(rtnl, 0, RTNLGRP_IPV6_ROUTE, ENOBUFS);
                return;
        }
        if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, pid, seq, 0, 0) < 0) {
                kfree_skb(skb);
-               netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, EINVAL);
+               netlink_set_err(rtnl, 0, RTNLGRP_IPV6_ROUTE, EINVAL);
                return;
        }
-       NETLINK_CB(skb).dst_groups = RTMGRP_IPV6_ROUTE;
-       netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV6_ROUTE, gfp_any());
+       NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_ROUTE;
+       netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_ROUTE, gfp_any());
 }
 
 /*
@@ -1960,8 +1960,6 @@ static int rt6_proc_info(char *buffer, char **start, off_t offset, int length)
        return arg.len;
 }
 
-extern struct rt6_statistics rt6_stats;
-
 static int rt6_stats_seq_show(struct seq_file *seq, void *v)
 {
        seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
index e553e5b80d6e3ed78124073c5163ec17dc0143b6..c3123c9e1a8e9510511d14ca4ac58f5f63d09c46 100644 (file)
@@ -770,7 +770,7 @@ static int ipip6_tunnel_init(struct net_device *dev)
        return 0;
 }
 
-int __init ipip6_fb_tunnel_init(struct net_device *dev)
+static int __init ipip6_fb_tunnel_init(struct net_device *dev)
 {
        struct ip_tunnel *tunnel = dev->priv;
        struct iphdr *iph = &tunnel->parms.iph;
index 3a18e0e6ffed8793e953ed231b0e73abff972661..8eff9fa1e983312b38926e1d5e3286d7474f84b6 100644 (file)
@@ -14,9 +14,6 @@
 #include <net/ipv6.h>
 #include <net/addrconf.h>
 
-extern ctl_table ipv6_route_table[];
-extern ctl_table ipv6_icmp_table[];
-
 #ifdef CONFIG_SYSCTL
 
 static ctl_table ipv6_table[] = {
index ef29cfd936d3bed8f094f89627e8e67932529886..794734f1d230b3b5a5449eb013f4d0545bcb7871 100644 (file)
@@ -47,6 +47,7 @@
 
 #include <net/tcp.h>
 #include <net/ndisc.h>
+#include <net/inet6_hashtables.h>
 #include <net/ipv6.h>
 #include <net/transp_v6.h>
 #include <net/addrconf.h>
@@ -75,34 +76,11 @@ static int  tcp_v6_xmit(struct sk_buff *skb, int ipfragok);
 static struct tcp_func ipv6_mapped;
 static struct tcp_func ipv6_specific;
 
-/* I have no idea if this is a good hash for v6 or not. -DaveM */
-static __inline__ int tcp_v6_hashfn(struct in6_addr *laddr, u16 lport,
-                                   struct in6_addr *faddr, u16 fport)
+static inline int tcp_v6_bind_conflict(const struct sock *sk,
+                                      const struct inet_bind_bucket *tb)
 {
-       int hashent = (lport ^ fport);
-
-       hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]);
-       hashent ^= hashent>>16;
-       hashent ^= hashent>>8;
-       return (hashent & (tcp_ehash_size - 1));
-}
-
-static __inline__ int tcp_v6_sk_hashfn(struct sock *sk)
-{
-       struct inet_sock *inet = inet_sk(sk);
-       struct ipv6_pinfo *np = inet6_sk(sk);
-       struct in6_addr *laddr = &np->rcv_saddr;
-       struct in6_addr *faddr = &np->daddr;
-       __u16 lport = inet->num;
-       __u16 fport = inet->dport;
-       return tcp_v6_hashfn(laddr, lport, faddr, fport);
-}
-
-static inline int tcp_v6_bind_conflict(struct sock *sk,
-                                      struct tcp_bind_bucket *tb)
-{
-       struct sock *sk2;
-       struct hlist_node *node;
+       const struct sock *sk2;
+       const struct hlist_node *node;
 
        /* We must walk the whole port owner list in this case. -DaveM */
        sk_for_each_bound(sk2, node, &tb->owners) {
@@ -126,8 +104,8 @@ static inline int tcp_v6_bind_conflict(struct sock *sk,
  */
 static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
 {
-       struct tcp_bind_hashbucket *head;
-       struct tcp_bind_bucket *tb;
+       struct inet_bind_hashbucket *head;
+       struct inet_bind_bucket *tb;
        struct hlist_node *node;
        int ret;
 
@@ -138,25 +116,25 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
                int remaining = (high - low) + 1;
                int rover;
 
-               spin_lock(&tcp_portalloc_lock);
-               if (tcp_port_rover < low)
+               spin_lock(&tcp_hashinfo.portalloc_lock);
+               if (tcp_hashinfo.port_rover < low)
                        rover = low;
                else
-                       rover = tcp_port_rover;
+                       rover = tcp_hashinfo.port_rover;
                do {    rover++;
                        if (rover > high)
                                rover = low;
-                       head = &tcp_bhash[tcp_bhashfn(rover)];
+                       head = &tcp_hashinfo.bhash[inet_bhashfn(rover, tcp_hashinfo.bhash_size)];
                        spin_lock(&head->lock);
-                       tb_for_each(tb, node, &head->chain)
+                       inet_bind_bucket_for_each(tb, node, &head->chain)
                                if (tb->port == rover)
                                        goto next;
                        break;
                next:
                        spin_unlock(&head->lock);
                } while (--remaining > 0);
-               tcp_port_rover = rover;
-               spin_unlock(&tcp_portalloc_lock);
+               tcp_hashinfo.port_rover = rover;
+               spin_unlock(&tcp_hashinfo.portalloc_lock);
 
                /* Exhausted local port range during search?  It is not
                 * possible for us to be holding one of the bind hash
@@ -171,9 +149,9 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
                /* OK, here is the one we will use. */
                snum = rover;
        } else {
-               head = &tcp_bhash[tcp_bhashfn(snum)];
+               head = &tcp_hashinfo.bhash[inet_bhashfn(snum, tcp_hashinfo.bhash_size)];
                spin_lock(&head->lock);
-               tb_for_each(tb, node, &head->chain)
+               inet_bind_bucket_for_each(tb, node, &head->chain)
                        if (tb->port == snum)
                                goto tb_found;
        }
@@ -192,8 +170,11 @@ tb_found:
        }
 tb_not_found:
        ret = 1;
-       if (!tb && (tb = tcp_bucket_create(head, snum)) == NULL)
-               goto fail_unlock;
+       if (tb == NULL) {
+               tb = inet_bind_bucket_create(tcp_hashinfo.bind_bucket_cachep, head, snum);
+               if (tb == NULL)
+                       goto fail_unlock;
+       }
        if (hlist_empty(&tb->owners)) {
                if (sk->sk_reuse && sk->sk_state != TCP_LISTEN)
                        tb->fastreuse = 1;
@@ -204,9 +185,9 @@ tb_not_found:
                tb->fastreuse = 0;
 
 success:
-       if (!tcp_sk(sk)->bind_hash)
-               tcp_bind_hash(sk, tb, snum);
-       BUG_TRAP(tcp_sk(sk)->bind_hash == tb);
+       if (!inet_csk(sk)->icsk_bind_hash)
+               inet_bind_hash(sk, tb, snum);
+       BUG_TRAP(inet_csk(sk)->icsk_bind_hash == tb);
        ret = 0;
 
 fail_unlock:
@@ -224,13 +205,13 @@ static __inline__ void __tcp_v6_hash(struct sock *sk)
        BUG_TRAP(sk_unhashed(sk));
 
        if (sk->sk_state == TCP_LISTEN) {
-               list = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
-               lock = &tcp_lhash_lock;
-               tcp_listen_wlock();
+               list = &tcp_hashinfo.listening_hash[inet_sk_listen_hashfn(sk)];
+               lock = &tcp_hashinfo.lhash_lock;
+               inet_listen_wlock(&tcp_hashinfo);
        } else {
-               sk->sk_hashent = tcp_v6_sk_hashfn(sk);
-               list = &tcp_ehash[sk->sk_hashent].chain;
-               lock = &tcp_ehash[sk->sk_hashent].lock;
+               sk->sk_hashent = inet6_sk_ehashfn(sk, tcp_hashinfo.ehash_size);
+               list = &tcp_hashinfo.ehash[sk->sk_hashent].chain;
+               lock = &tcp_hashinfo.ehash[sk->sk_hashent].lock;
                write_lock(lock);
        }
 
@@ -255,131 +236,11 @@ static void tcp_v6_hash(struct sock *sk)
        }
 }
 
-static struct sock *tcp_v6_lookup_listener(struct in6_addr *daddr, unsigned short hnum, int dif)
-{
-       struct sock *sk;
-       struct hlist_node *node;
-       struct sock *result = NULL;
-       int score, hiscore;
-
-       hiscore=0;
-       read_lock(&tcp_lhash_lock);
-       sk_for_each(sk, node, &tcp_listening_hash[tcp_lhashfn(hnum)]) {
-               if (inet_sk(sk)->num == hnum && sk->sk_family == PF_INET6) {
-                       struct ipv6_pinfo *np = inet6_sk(sk);
-                       
-                       score = 1;
-                       if (!ipv6_addr_any(&np->rcv_saddr)) {
-                               if (!ipv6_addr_equal(&np->rcv_saddr, daddr))
-                                       continue;
-                               score++;
-                       }
-                       if (sk->sk_bound_dev_if) {
-                               if (sk->sk_bound_dev_if != dif)
-                                       continue;
-                               score++;
-                       }
-                       if (score == 3) {
-                               result = sk;
-                               break;
-                       }
-                       if (score > hiscore) {
-                               hiscore = score;
-                               result = sk;
-                       }
-               }
-       }
-       if (result)
-               sock_hold(result);
-       read_unlock(&tcp_lhash_lock);
-       return result;
-}
-
-/* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
- * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
- *
- * The sockhash lock must be held as a reader here.
- */
-
-static inline struct sock *__tcp_v6_lookup_established(struct in6_addr *saddr, u16 sport,
-                                                      struct in6_addr *daddr, u16 hnum,
-                                                      int dif)
-{
-       struct tcp_ehash_bucket *head;
-       struct sock *sk;
-       struct hlist_node *node;
-       __u32 ports = TCP_COMBINED_PORTS(sport, hnum);
-       int hash;
-
-       /* Optimize here for direct hit, only listening connections can
-        * have wildcards anyways.
-        */
-       hash = tcp_v6_hashfn(daddr, hnum, saddr, sport);
-       head = &tcp_ehash[hash];
-       read_lock(&head->lock);
-       sk_for_each(sk, node, &head->chain) {
-               /* For IPV6 do the cheaper port and family tests first. */
-               if(TCP_IPV6_MATCH(sk, saddr, daddr, ports, dif))
-                       goto hit; /* You sunk my battleship! */
-       }
-       /* Must check for a TIME_WAIT'er before going to listener hash. */
-       sk_for_each(sk, node, &(head + tcp_ehash_size)->chain) {
-               /* FIXME: acme: check this... */
-               struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk;
-
-               if(*((__u32 *)&(tw->tw_dport))  == ports        &&
-                  sk->sk_family                == PF_INET6) {
-                       if(ipv6_addr_equal(&tw->tw_v6_daddr, saddr)     &&
-                          ipv6_addr_equal(&tw->tw_v6_rcv_saddr, daddr) &&
-                          (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dif))
-                               goto hit;
-               }
-       }
-       read_unlock(&head->lock);
-       return NULL;
-
-hit:
-       sock_hold(sk);
-       read_unlock(&head->lock);
-       return sk;
-}
-
-
-static inline struct sock *__tcp_v6_lookup(struct in6_addr *saddr, u16 sport,
-                                          struct in6_addr *daddr, u16 hnum,
-                                          int dif)
-{
-       struct sock *sk;
-
-       sk = __tcp_v6_lookup_established(saddr, sport, daddr, hnum, dif);
-
-       if (sk)
-               return sk;
-
-       return tcp_v6_lookup_listener(daddr, hnum, dif);
-}
-
-inline struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport,
-                                 struct in6_addr *daddr, u16 dport,
-                                 int dif)
-{
-       struct sock *sk;
-
-       local_bh_disable();
-       sk = __tcp_v6_lookup(saddr, sport, daddr, ntohs(dport), dif);
-       local_bh_enable();
-
-       return sk;
-}
-
-EXPORT_SYMBOL_GPL(tcp_v6_lookup);
-
-
 /*
  * Open request hash tables.
  */
 
-static u32 tcp_v6_synq_hash(struct in6_addr *raddr, u16 rport, u32 rnd)
+static u32 tcp_v6_synq_hash(const struct in6_addr *raddr, const u16 rport, const u32 rnd)
 {
        u32 a, b, c;
 
@@ -399,14 +260,15 @@ static u32 tcp_v6_synq_hash(struct in6_addr *raddr, u16 rport, u32 rnd)
        return c & (TCP_SYNQ_HSIZE - 1);
 }
 
-static struct request_sock *tcp_v6_search_req(struct tcp_sock *tp,
+static struct request_sock *tcp_v6_search_req(const struct sock *sk,
                                              struct request_sock ***prevp,
                                              __u16 rport,
                                              struct in6_addr *raddr,
                                              struct in6_addr *laddr,
                                              int iif)
 {
-       struct listen_sock *lopt = tp->accept_queue.listen_opt;
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+       struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
        struct request_sock *req, **prev;  
 
        for (prev = &lopt->syn_table[tcp_v6_synq_hash(raddr, rport, lopt->hash_rnd)];
@@ -451,44 +313,48 @@ static __u32 tcp_v6_init_sequence(struct sock *sk, struct sk_buff *skb)
        }
 }
 
-static int __tcp_v6_check_established(struct sock *sk, __u16 lport,
-                                     struct tcp_tw_bucket **twp)
+static int __tcp_v6_check_established(struct sock *sk, const __u16 lport,
+                                     struct inet_timewait_sock **twp)
 {
        struct inet_sock *inet = inet_sk(sk);
-       struct ipv6_pinfo *np = inet6_sk(sk);
-       struct in6_addr *daddr = &np->rcv_saddr;
-       struct in6_addr *saddr = &np->daddr;
-       int dif = sk->sk_bound_dev_if;
-       u32 ports = TCP_COMBINED_PORTS(inet->dport, lport);
-       int hash = tcp_v6_hashfn(daddr, inet->num, saddr, inet->dport);
-       struct tcp_ehash_bucket *head = &tcp_ehash[hash];
+       const struct ipv6_pinfo *np = inet6_sk(sk);
+       const struct in6_addr *daddr = &np->rcv_saddr;
+       const struct in6_addr *saddr = &np->daddr;
+       const int dif = sk->sk_bound_dev_if;
+       const u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
+       const int hash = inet6_ehashfn(daddr, inet->num, saddr, inet->dport,
+                                      tcp_hashinfo.ehash_size);
+       struct inet_ehash_bucket *head = &tcp_hashinfo.ehash[hash];
        struct sock *sk2;
-       struct hlist_node *node;
-       struct tcp_tw_bucket *tw;
+       const struct hlist_node *node;
+       struct inet_timewait_sock *tw;
 
        write_lock(&head->lock);
 
        /* Check TIME-WAIT sockets first. */
-       sk_for_each(sk2, node, &(head + tcp_ehash_size)->chain) {
-               tw = (struct tcp_tw_bucket*)sk2;
+       sk_for_each(sk2, node, &(head + tcp_hashinfo.ehash_size)->chain) {
+               const struct tcp6_timewait_sock *tcp6tw = tcp6_twsk(sk2);
+
+               tw = inet_twsk(sk2);
 
                if(*((__u32 *)&(tw->tw_dport))  == ports        &&
                   sk2->sk_family               == PF_INET6     &&
-                  ipv6_addr_equal(&tw->tw_v6_daddr, saddr)     &&
-                  ipv6_addr_equal(&tw->tw_v6_rcv_saddr, daddr) &&
+                  ipv6_addr_equal(&tcp6tw->tw_v6_daddr, saddr) &&
+                  ipv6_addr_equal(&tcp6tw->tw_v6_rcv_saddr, daddr)     &&
                   sk2->sk_bound_dev_if == sk->sk_bound_dev_if) {
+                       const struct tcp_timewait_sock *tcptw = tcp_twsk(sk2);
                        struct tcp_sock *tp = tcp_sk(sk);
 
-                       if (tw->tw_ts_recent_stamp &&
-                           (!twp || (sysctl_tcp_tw_reuse &&
-                                     xtime.tv_sec - 
-                                     tw->tw_ts_recent_stamp > 1))) {
+                       if (tcptw->tw_ts_recent_stamp &&
+                           (!twp ||
+                            (sysctl_tcp_tw_reuse &&
+                             xtime.tv_sec - tcptw->tw_ts_recent_stamp > 1))) {
                                /* See comment in tcp_ipv4.c */
-                               tp->write_seq = tw->tw_snd_nxt + 65535 + 2;
+                               tp->write_seq = tcptw->tw_snd_nxt + 65535 + 2;
                                if (!tp->write_seq)
                                        tp->write_seq = 1;
-                               tp->rx_opt.ts_recent tw->tw_ts_recent;
-                               tp->rx_opt.ts_recent_stamp = tw->tw_ts_recent_stamp;
+                               tp->rx_opt.ts_recent       = tcptw->tw_ts_recent;
+                               tp->rx_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp;
                                sock_hold(sk2);
                                goto unique;
                        } else
@@ -499,7 +365,7 @@ static int __tcp_v6_check_established(struct sock *sk, __u16 lport,
 
        /* And established part... */
        sk_for_each(sk2, node, &head->chain) {
-               if(TCP_IPV6_MATCH(sk2, saddr, daddr, ports, dif))
+               if (INET6_MATCH(sk2, saddr, daddr, ports, dif))
                        goto not_unique;
        }
 
@@ -515,10 +381,10 @@ unique:
                NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
        } else if (tw) {
                /* Silly. Should hash-dance instead... */
-               tcp_tw_deschedule(tw);
+               inet_twsk_deschedule(tw, &tcp_death_row);
                NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
 
-               tcp_tw_put(tw);
+               inet_twsk_put(tw);
        }
        return 0;
 
@@ -540,8 +406,8 @@ static inline u32 tcpv6_port_offset(const struct sock *sk)
 static int tcp_v6_hash_connect(struct sock *sk)
 {
        unsigned short snum = inet_sk(sk)->num;
-       struct tcp_bind_hashbucket *head;
-       struct tcp_bind_bucket *tb;
+       struct inet_bind_hashbucket *head;
+       struct inet_bind_bucket *tb;
        int ret;
 
        if (!snum) {
@@ -553,19 +419,19 @@ static int tcp_v6_hash_connect(struct sock *sk)
                static u32 hint;
                u32 offset = hint + tcpv6_port_offset(sk);
                struct hlist_node *node;
-               struct tcp_tw_bucket *tw = NULL;
+               struct inet_timewait_sock *tw = NULL;
 
                local_bh_disable();
                for (i = 1; i <= range; i++) {
                        port = low + (i + offset) % range;
-                       head = &tcp_bhash[tcp_bhashfn(port)];
+                       head = &tcp_hashinfo.bhash[inet_bhashfn(port, tcp_hashinfo.bhash_size)];
                        spin_lock(&head->lock);
 
                        /* Does not bother with rcv_saddr checks,
                         * because the established check is already
                         * unique enough.
                         */
-                       tb_for_each(tb, node, &head->chain) {
+                       inet_bind_bucket_for_each(tb, node, &head->chain) {
                                if (tb->port == port) {
                                        BUG_TRAP(!hlist_empty(&tb->owners));
                                        if (tb->fastreuse >= 0)
@@ -578,7 +444,7 @@ static int tcp_v6_hash_connect(struct sock *sk)
                                }
                        }
 
-                       tb = tcp_bucket_create(head, port);
+                       tb = inet_bind_bucket_create(tcp_hashinfo.bind_bucket_cachep, head, port);
                        if (!tb) {
                                spin_unlock(&head->lock);
                                break;
@@ -597,7 +463,7 @@ ok:
                hint += i;
 
                /* Head lock still held and bh's disabled */
-               tcp_bind_hash(sk, tb, port);
+               inet_bind_hash(sk, tb, port);
                if (sk_unhashed(sk)) {
                        inet_sk(sk)->sport = htons(port);
                        __tcp_v6_hash(sk);
@@ -605,16 +471,16 @@ ok:
                spin_unlock(&head->lock);
 
                if (tw) {
-                       tcp_tw_deschedule(tw);
-                       tcp_tw_put(tw);
+                       inet_twsk_deschedule(tw, &tcp_death_row);
+                       inet_twsk_put(tw);
                }
 
                ret = 0;
                goto out;
        }
 
-       head  = &tcp_bhash[tcp_bhashfn(snum)];
-       tb  = tcp_sk(sk)->bind_hash;
+       head = &tcp_hashinfo.bhash[inet_bhashfn(snum, tcp_hashinfo.bhash_size)];
+       tb   = inet_csk(sk)->icsk_bind_hash;
        spin_lock_bh(&head->lock);
 
        if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) {
@@ -631,11 +497,6 @@ out:
        }
 }
 
-static __inline__ int tcp_v6_iif(struct sk_buff *skb)
-{
-       return IP6CB(skb)->iif;
-}
-
 static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, 
                          int addr_len)
 {
@@ -827,14 +688,15 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                int type, int code, int offset, __u32 info)
 {
        struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
-       struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
+       const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
        struct ipv6_pinfo *np;
        struct sock *sk;
        int err;
        struct tcp_sock *tp; 
        __u32 seq;
 
-       sk = tcp_v6_lookup(&hdr->daddr, th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
+       sk = inet6_lookup(&tcp_hashinfo, &hdr->daddr, th->dest, &hdr->saddr,
+                         th->source, skb->dev->ifindex);
 
        if (sk == NULL) {
                ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
@@ -842,7 +704,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        }
 
        if (sk->sk_state == TCP_TIME_WAIT) {
-               tcp_tw_put((struct tcp_tw_bucket*)sk);
+               inet_twsk_put((struct inet_timewait_sock *)sk);
                return;
        }
 
@@ -920,8 +782,8 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                if (sock_owned_by_user(sk))
                        goto out;
 
-               req = tcp_v6_search_req(tp, &prev, th->dest, &hdr->daddr,
-                                       &hdr->saddr, tcp_v6_iif(skb));
+               req = tcp_v6_search_req(sk, &prev, th->dest, &hdr->daddr,
+                                       &hdr->saddr, inet6_iif(skb));
                if (!req)
                        goto out;
 
@@ -935,7 +797,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                        goto out;
                }
 
-               tcp_synq_drop(sk, req, prev);
+               inet_csk_reqsk_queue_drop(sk, req, prev);
                goto out;
 
        case TCP_SYN_SENT:
@@ -1132,7 +994,7 @@ static void tcp_v6_send_reset(struct sk_buff *skb)
                                    buff->csum);
 
        fl.proto = IPPROTO_TCP;
-       fl.oif = tcp_v6_iif(skb);
+       fl.oif = inet6_iif(skb);
        fl.fl_ip_dport = t1->dest;
        fl.fl_ip_sport = t1->source;
 
@@ -1201,7 +1063,7 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32
                                    buff->csum);
 
        fl.proto = IPPROTO_TCP;
-       fl.oif = tcp_v6_iif(skb);
+       fl.oif = inet6_iif(skb);
        fl.fl_ip_dport = t1->dest;
        fl.fl_ip_sport = t1->source;
 
@@ -1220,12 +1082,14 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32
 
 static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
 {
-       struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk;
+       struct inet_timewait_sock *tw = inet_twsk(sk);
+       const struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
 
-       tcp_v6_send_ack(skb, tw->tw_snd_nxt, tw->tw_rcv_nxt,
-                       tw->tw_rcv_wnd >> tw->tw_rcv_wscale, tw->tw_ts_recent);
+       tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
+                       tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
+                       tcptw->tw_ts_recent);
 
-       tcp_tw_put(tw);
+       inet_twsk_put(tw);
 }
 
 static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req)
@@ -1237,28 +1101,25 @@ static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req)
 static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
 {
        struct request_sock *req, **prev;
-       struct tcphdr *th = skb->h.th;
-       struct tcp_sock *tp = tcp_sk(sk);
+       const struct tcphdr *th = skb->h.th;
        struct sock *nsk;
 
        /* Find possible connection requests. */
-       req = tcp_v6_search_req(tp, &prev, th->source, &skb->nh.ipv6h->saddr,
-                               &skb->nh.ipv6h->daddr, tcp_v6_iif(skb));
+       req = tcp_v6_search_req(sk, &prev, th->source, &skb->nh.ipv6h->saddr,
+                               &skb->nh.ipv6h->daddr, inet6_iif(skb));
        if (req)
                return tcp_check_req(sk, skb, req, prev);
 
-       nsk = __tcp_v6_lookup_established(&skb->nh.ipv6h->saddr,
-                                         th->source,
-                                         &skb->nh.ipv6h->daddr,
-                                         ntohs(th->dest),
-                                         tcp_v6_iif(skb));
+       nsk = __inet6_lookup_established(&tcp_hashinfo, &skb->nh.ipv6h->saddr,
+                                        th->source, &skb->nh.ipv6h->daddr,
+                                        ntohs(th->dest), inet6_iif(skb));
 
        if (nsk) {
                if (nsk->sk_state != TCP_TIME_WAIT) {
                        bh_lock_sock(nsk);
                        return nsk;
                }
-               tcp_tw_put((struct tcp_tw_bucket*)nsk);
+               inet_twsk_put((struct inet_timewait_sock *)nsk);
                return NULL;
        }
 
@@ -1271,12 +1132,12 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
 
 static void tcp_v6_synq_add(struct sock *sk, struct request_sock *req)
 {
-       struct tcp_sock *tp = tcp_sk(sk);
-       struct listen_sock *lopt = tp->accept_queue.listen_opt;
-       u32 h = tcp_v6_synq_hash(&tcp6_rsk(req)->rmt_addr, inet_rsk(req)->rmt_port, lopt->hash_rnd);
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
+       const u32 h = tcp_v6_synq_hash(&tcp6_rsk(req)->rmt_addr, inet_rsk(req)->rmt_port, lopt->hash_rnd);
 
-       reqsk_queue_hash_req(&tp->accept_queue, h, req, TCP_TIMEOUT_INIT);
-       tcp_synq_added(sk);
+       reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, TCP_TIMEOUT_INIT);
+       inet_csk_reqsk_queue_added(sk, TCP_TIMEOUT_INIT);
 }
 
 
@@ -1301,13 +1162,13 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
        /*
         *      There are no SYN attacks on IPv6, yet...        
         */
-       if (tcp_synq_is_full(sk) && !isn) {
+       if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
                if (net_ratelimit())
                        printk(KERN_INFO "TCPv6: dropping request, synflood is possible\n");
                goto drop;              
        }
 
-       if (sk_acceptq_is_full(sk) && tcp_synq_young(sk) > 1)
+       if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
                goto drop;
 
        req = reqsk_alloc(&tcp6_request_sock_ops);
@@ -1339,7 +1200,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
        /* So that link locals have meaning */
        if (!sk->sk_bound_dev_if &&
            ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
-               treq->iif = tcp_v6_iif(skb);
+               treq->iif = inet6_iif(skb);
 
        if (isn == 0) 
                isn = tcp_v6_init_sequence(sk,skb);
@@ -1404,15 +1265,14 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                newsk->sk_backlog_rcv = tcp_v4_do_rcv;
                newnp->pktoptions  = NULL;
                newnp->opt         = NULL;
-               newnp->mcast_oif   = tcp_v6_iif(skb);
+               newnp->mcast_oif   = inet6_iif(skb);
                newnp->mcast_hops  = skb->nh.ipv6h->hop_limit;
 
-               /* Charge newly allocated IPv6 socket. Though it is mapped,
-                * it is IPv6 yet.
+               /*
+                * No need to charge this sock to the relevant IPv6 refcnt debug socks count
+                * here, tcp_create_openreq_child now does this for us, see the comment in
+                * that function for the gory details. -acme
                 */
-#ifdef INET_REFCNT_DEBUG
-               atomic_inc(&inet6_sock_nr);
-#endif
 
                /* It is tricky place. Until this moment IPv4 tcp
                   worked with IPv6 af_tcp.af_specific.
@@ -1467,10 +1327,11 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        if (newsk == NULL)
                goto out;
 
-       /* Charge newly allocated IPv6 socket */
-#ifdef INET_REFCNT_DEBUG
-       atomic_inc(&inet6_sock_nr);
-#endif
+       /*
+        * No need to charge this sock to the relevant IPv6 refcnt debug socks
+        * count here, tcp_create_openreq_child now does this for us, see the
+        * comment in that function for the gory details. -acme
+        */
 
        ip6_dst_store(newsk, dst, NULL);
        newsk->sk_route_caps = dst->dev->features &
@@ -1509,7 +1370,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                        skb_set_owner_r(newnp->pktoptions, newsk);
        }
        newnp->opt        = NULL;
-       newnp->mcast_oif  = tcp_v6_iif(skb);
+       newnp->mcast_oif  = inet6_iif(skb);
        newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
 
        /* Clone native IPv6 options from listening socket (if any)
@@ -1536,7 +1397,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
 
        __tcp_v6_hash(newsk);
-       tcp_inherit_port(sk, newsk);
+       inet_inherit_port(&tcp_hashinfo, sk, newsk);
 
        return newsk;
 
@@ -1557,7 +1418,7 @@ static int tcp_v6_checksum_init(struct sk_buff *skb)
                if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
                                  &skb->nh.ipv6h->daddr,skb->csum))
                        return 0;
-               LIMIT_NETDEBUG(printk(KERN_DEBUG "hw tcp v6 csum failed\n"));
+               LIMIT_NETDEBUG(KERN_DEBUG "hw tcp v6 csum failed\n");
        }
        if (skb->len <= 76) {
                if (tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
@@ -1684,7 +1545,7 @@ ipv6_pktoptions:
        if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
            !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
                if (np->rxopt.bits.rxinfo)
-                       np->mcast_oif = tcp_v6_iif(opt_skb);
+                       np->mcast_oif = inet6_iif(opt_skb);
                if (np->rxopt.bits.rxhlim)
                        np->mcast_hops = opt_skb->nh.ipv6h->hop_limit;
                if (ipv6_opt_accepted(sk, opt_skb)) {
@@ -1739,8 +1600,9 @@ static int tcp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
        TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(skb->nh.ipv6h);
        TCP_SKB_CB(skb)->sacked = 0;
 
-       sk = __tcp_v6_lookup(&skb->nh.ipv6h->saddr, th->source,
-                            &skb->nh.ipv6h->daddr, ntohs(th->dest), tcp_v6_iif(skb));
+       sk = __inet6_lookup(&tcp_hashinfo, &skb->nh.ipv6h->saddr, th->source,
+                           &skb->nh.ipv6h->daddr, ntohs(th->dest),
+                           inet6_iif(skb));
 
        if (!sk)
                goto no_tcp_socket;
@@ -1795,26 +1657,29 @@ discard_and_relse:
 
 do_time_wait:
        if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
-               tcp_tw_put((struct tcp_tw_bucket *) sk);
+               inet_twsk_put((struct inet_timewait_sock *)sk);
                goto discard_it;
        }
 
        if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
                TCP_INC_STATS_BH(TCP_MIB_INERRS);
-               tcp_tw_put((struct tcp_tw_bucket *) sk);
+               inet_twsk_put((struct inet_timewait_sock *)sk);
                goto discard_it;
        }
 
-       switch(tcp_timewait_state_process((struct tcp_tw_bucket *)sk,
-                                         skb, th, skb->len)) {
+       switch (tcp_timewait_state_process((struct inet_timewait_sock *)sk,
+                                          skb, th)) {
        case TCP_TW_SYN:
        {
                struct sock *sk2;
 
-               sk2 = tcp_v6_lookup_listener(&skb->nh.ipv6h->daddr, ntohs(th->dest), tcp_v6_iif(skb));
+               sk2 = inet6_lookup_listener(&tcp_hashinfo,
+                                           &skb->nh.ipv6h->daddr,
+                                           ntohs(th->dest), inet6_iif(skb));
                if (sk2 != NULL) {
-                       tcp_tw_deschedule((struct tcp_tw_bucket *)sk);
-                       tcp_tw_put((struct tcp_tw_bucket *)sk);
+                       struct inet_timewait_sock *tw = inet_twsk(sk);
+                       inet_twsk_deschedule(tw, &tcp_death_row);
+                       inet_twsk_put(tw);
                        sk = sk2;
                        goto process;
                }
@@ -1983,7 +1848,7 @@ static struct tcp_func ipv6_specific = {
 static struct tcp_func ipv6_mapped = {
        .queue_xmit     =       ip_queue_xmit,
        .send_check     =       tcp_v4_send_check,
-       .rebuild_header =       tcp_v4_rebuild_header,
+       .rebuild_header =       inet_sk_rebuild_header,
        .conn_request   =       tcp_v6_conn_request,
        .syn_recv_sock  =       tcp_v6_syn_recv_sock,
        .remember_stamp =       tcp_v4_remember_stamp,
@@ -2002,13 +1867,14 @@ static struct tcp_func ipv6_mapped = {
  */
 static int tcp_v6_init_sock(struct sock *sk)
 {
+       struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
 
        skb_queue_head_init(&tp->out_of_order_queue);
        tcp_init_xmit_timers(sk);
        tcp_prequeue_init(tp);
 
-       tp->rto  = TCP_TIMEOUT_INIT;
+       icsk->icsk_rto = TCP_TIMEOUT_INIT;
        tp->mdev = TCP_TIMEOUT_INIT;
 
        /* So many TCP implementations out there (incorrectly) count the
@@ -2030,7 +1896,7 @@ static int tcp_v6_init_sock(struct sock *sk)
        sk->sk_state = TCP_CLOSE;
 
        tp->af_specific = &ipv6_specific;
-       tp->ca_ops = &tcp_init_congestion_ops;
+       icsk->icsk_ca_ops = &tcp_init_congestion_ops;
        sk->sk_write_space = sk_stream_write_space;
        sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
 
@@ -2044,8 +1910,6 @@ static int tcp_v6_init_sock(struct sock *sk)
 
 static int tcp_v6_destroy_sock(struct sock *sk)
 {
-       extern int tcp_v4_destroy_sock(struct sock *sk);
-
        tcp_v4_destroy_sock(sk);
        return inet6_destroy_sock(sk);
 }
@@ -2091,18 +1955,20 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
        unsigned long timer_expires;
        struct inet_sock *inet = inet_sk(sp);
        struct tcp_sock *tp = tcp_sk(sp);
+       const struct inet_connection_sock *icsk = inet_csk(sp);
        struct ipv6_pinfo *np = inet6_sk(sp);
 
        dest  = &np->daddr;
        src   = &np->rcv_saddr;
        destp = ntohs(inet->dport);
        srcp  = ntohs(inet->sport);
-       if (tp->pending == TCP_TIME_RETRANS) {
+
+       if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
                timer_active    = 1;
-               timer_expires   = tp->timeout;
-       } else if (tp->pending == TCP_TIME_PROBE0) {
+               timer_expires   = icsk->icsk_timeout;
+       } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
                timer_active    = 4;
-               timer_expires   = tp->timeout;
+               timer_expires   = icsk->icsk_timeout;
        } else if (timer_pending(&sp->sk_timer)) {
                timer_active    = 2;
                timer_expires   = sp->sk_timer.expires;
@@ -2123,28 +1989,31 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
                   tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq,
                   timer_active,
                   jiffies_to_clock_t(timer_expires - jiffies),
-                  tp->retransmits,
+                  icsk->icsk_retransmits,
                   sock_i_uid(sp),
-                  tp->probes_out,
+                  icsk->icsk_probes_out,
                   sock_i_ino(sp),
                   atomic_read(&sp->sk_refcnt), sp,
-                  tp->rto, tp->ack.ato, (tp->ack.quick<<1)|tp->ack.pingpong,
+                  icsk->icsk_rto,
+                  icsk->icsk_ack.ato,
+                  (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong,
                   tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh
                   );
 }
 
 static void get_timewait6_sock(struct seq_file *seq, 
-                              struct tcp_tw_bucket *tw, int i)
+                              struct inet_timewait_sock *tw, int i)
 {
        struct in6_addr *dest, *src;
        __u16 destp, srcp;
+       struct tcp6_timewait_sock *tcp6tw = tcp6_twsk((struct sock *)tw);
        int ttd = tw->tw_ttd - jiffies;
 
        if (ttd < 0)
                ttd = 0;
 
-       dest  = &tw->tw_v6_daddr;
-       src   = &tw->tw_v6_rcv_saddr;
+       dest = &tcp6tw->tw_v6_daddr;
+       src  = &tcp6tw->tw_v6_rcv_saddr;
        destp = ntohs(tw->tw_dport);
        srcp  = ntohs(tw->tw_sport);
 
@@ -2219,7 +2088,7 @@ struct proto tcpv6_prot = {
        .close                  = tcp_close,
        .connect                = tcp_v6_connect,
        .disconnect             = tcp_disconnect,
-       .accept                 = tcp_accept,
+       .accept                 = inet_csk_accept,
        .ioctl                  = tcp_ioctl,
        .init                   = tcp_v6_init_sock,
        .destroy                = tcp_v6_destroy_sock,
@@ -2236,11 +2105,13 @@ struct proto tcpv6_prot = {
        .sockets_allocated      = &tcp_sockets_allocated,
        .memory_allocated       = &tcp_memory_allocated,
        .memory_pressure        = &tcp_memory_pressure,
+       .orphan_count           = &tcp_orphan_count,
        .sysctl_mem             = sysctl_tcp_mem,
        .sysctl_wmem            = sysctl_tcp_wmem,
        .sysctl_rmem            = sysctl_tcp_rmem,
        .max_header             = MAX_TCP_HEADER,
        .obj_size               = sizeof(struct tcp6_sock),
+       .twsk_obj_size          = sizeof(struct tcp6_timewait_sock),
        .rsk_prot               = &tcp6_request_sock_ops,
 };
 
@@ -2250,8 +2121,6 @@ static struct inet6_protocol tcpv6_protocol = {
        .flags          =       INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
-extern struct proto_ops inet6_stream_ops;
-
 static struct inet_protosw tcpv6_protosw = {
        .type           =       SOCK_STREAM,
        .protocol       =       IPPROTO_TCP,
index eff050ac7049601e6cc040c14210ac678b16e788..390d750449ce6f801dd3ed906dd68fa7bcc20126 100644 (file)
@@ -51,6 +51,7 @@
 #include <net/udp.h>
 #include <net/raw.h>
 #include <net/inet_common.h>
+#include <net/tcp_states.h>
 
 #include <net/ip6_checksum.h>
 #include <net/xfrm.h>
@@ -58,7 +59,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 
-DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6);
+DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly;
 
 /* Grrr, addr_type already calculated by caller, but I don't want
  * to add some silly "cookie" argument to this method just for that.
@@ -477,8 +478,7 @@ static int udpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
                /* RFC 2460 section 8.1 says that we SHOULD log
                   this error. Well, it is reasonable.
                 */
-               LIMIT_NETDEBUG(
-                       printk(KERN_INFO "IPv6: udp checksum is 0\n"));
+               LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n");
                goto discard;
        }
 
@@ -493,7 +493,7 @@ static int udpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
        if (skb->ip_summed==CHECKSUM_HW) {
                skb->ip_summed = CHECKSUM_UNNECESSARY;
                if (csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) {
-                       LIMIT_NETDEBUG(printk(KERN_DEBUG "udp v6 hw csum failure.\n"));
+                       LIMIT_NETDEBUG(KERN_DEBUG "udp v6 hw csum failure.\n");
                        skb->ip_summed = CHECKSUM_NONE;
                }
        }
@@ -825,7 +825,7 @@ back_from_confirm:
                /* ... which is an evident application bug. --ANK */
                release_sock(sk);
 
-               LIMIT_NETDEBUG(printk(KERN_DEBUG "udp cork app bug 2\n"));
+               LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n");
                err = -EINVAL;
                goto out;
        }
@@ -1054,8 +1054,6 @@ struct proto udpv6_prot = {
        .obj_size =     sizeof(struct udp6_sock),
 };
 
-extern struct proto_ops inet6_dgram_ops;
-
 static struct inet_protosw udpv6_protosw = {
        .type =      SOCK_DGRAM,
        .protocol =  IPPROTO_UDP,
index 60c26c87277e7fa63a34f9b8671cbdd79efb1fd4..fbef7826a74f610556d02b11b9332f11a823b980 100644 (file)
@@ -79,7 +79,7 @@ static u32 xfrm6_tunnel_spi;
 #define XFRM6_TUNNEL_SPI_MIN   1
 #define XFRM6_TUNNEL_SPI_MAX   0xffffffff
 
-static kmem_cache_t *xfrm6_tunnel_spi_kmem;
+static kmem_cache_t *xfrm6_tunnel_spi_kmem __read_mostly;
 
 #define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256
 #define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256
index 5a27e5df5886e91e4acd3448c995c2b07c79d275..34b3bb86840912da024646f070170f9c933c650e 100644 (file)
@@ -44,7 +44,6 @@
 #include <linux/socket.h>
 #include <linux/sockios.h>
 #include <linux/string.h>
-#include <linux/tcp.h>
 #include <linux/types.h>
 #include <linux/termios.h>
 
@@ -52,6 +51,7 @@
 #include <net/p8022.h>
 #include <net/psnap.h>
 #include <net/sock.h>
+#include <net/tcp_states.h>
 
 #include <asm/uaccess.h>
 
@@ -1627,7 +1627,7 @@ out:
        return rc;
 }
 
-static int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
+static int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
 {
        /* NULL here for pt means the packet was looped back */
        struct ipx_interface *intrfc;
@@ -1796,8 +1796,8 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
                                     copied);
        if (rc)
                goto out_free;
-       if (skb->stamp.tv_sec)
-               sk->sk_stamp = skb->stamp;
+       if (skb->tstamp.off_sec)
+               skb_get_timestamp(skb, &sk->sk_stamp);
 
        msg->msg_namelen = sizeof(*sipx);
 
@@ -1940,9 +1940,7 @@ static struct notifier_block ipx_dev_notifier = {
 };
 
 extern struct datalink_proto *make_EII_client(void);
-extern struct datalink_proto *make_8023_client(void);
 extern void destroy_EII_client(struct datalink_proto *);
-extern void destroy_8023_client(struct datalink_proto *);
 
 static unsigned char ipx_8022_type = 0xE0;
 static unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 };
index b6761913445ad478026c31f749c102d3ff855529..1f73d9ea434da9938b7750725cad19f561647aa7 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/proc_fs.h>
 #include <linux/spinlock.h>
 #include <linux/seq_file.h>
-#include <linux/tcp.h>
+#include <net/tcp_states.h>
 #include <net/ipx.h>
 
 static __inline__ struct ipx_interface *ipx_get_interface_idx(loff_t pos)
index 92c6e8d4e731b196a58af56ab5803723db63f2e1..6f92f9c62990ab4854178cc67e72c2a71b2f64f7 100644 (file)
@@ -56,7 +56,7 @@
 #include <asm/uaccess.h>
 
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 
 #include <net/irda/af_irda.h>
 
index 343c5d4a1a1de4cdc09b80432b45dae6e6b01c9e..ca7d358dab523866d32f67813d6a13781adaff67 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/seq_file.h>
 
 #include <net/irda/irlan_common.h>
+#include <net/irda/irlan_filter.h>
 
 /*
  * Function irlan_filter_request (self, skb)
index 6dafbb43b5296922f62cacf8c596d9987d835c0f..3e9a06abbdd08d8e223169bb4f0155b6dd409138 100644 (file)
@@ -988,9 +988,6 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
                        IRDA_DEBUG(0, "%s(), unable to copy\n", __FUNCTION__);
                        return;
                }
-               /* Unlink tx_skb from list */
-               tx_skb->next = tx_skb->prev = NULL;
-               tx_skb->list = NULL;
 
                /* Clear old Nr field + poll bit */
                tx_skb->data[1] &= 0x0f;
@@ -1063,9 +1060,6 @@ void irlap_resend_rejected_frame(struct irlap_cb *self, int command)
                        IRDA_DEBUG(0, "%s(), unable to copy\n", __FUNCTION__);
                        return;
                }
-               /* Unlink tx_skb from list */
-               tx_skb->next = tx_skb->prev = NULL;
-               tx_skb->list = NULL;
 
                /* Clear old Nr field + poll bit */
                tx_skb->data[1] &= 0x0f;
@@ -1309,7 +1303,7 @@ static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb,
  * Jean II
  */
 int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
-                    struct packet_type *ptype)
+                    struct packet_type *ptype, struct net_device *orig_dev)
 {
        struct irlap_info info;
        struct irlap_cb *self;
index 7a4a4d7fbe66bf7774d91e9e04c1a42c2bf5b495..c19e9ce05a3a117d9a404140c735ea8a5c766d47 100644 (file)
@@ -53,7 +53,6 @@ struct irlmp_cb *irlmp = NULL;
 /* These can be altered by the sysctl interface */
 int  sysctl_discovery         = 0;
 int  sysctl_discovery_timeout = 3; /* 3 seconds by default */
-EXPORT_SYMBOL(sysctl_discovery_timeout);
 int  sysctl_discovery_slots   = 6; /* 6 slots by default */
 int  sysctl_lap_keepalive_time = LM_IDLE_TIMEOUT * 1000 / HZ;
 char sysctl_devname[65];
@@ -67,7 +66,6 @@ const char *irlmp_reasons[] = {
        "LM_INIT_DISCONNECT",
        "ERROR, NOT USED",
 };
-EXPORT_SYMBOL(irlmp_reasons);
 
 /*
  * Function irlmp_init (void)
@@ -675,7 +673,6 @@ struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance)
 
        return new;
 }
-EXPORT_SYMBOL(irlmp_dup);
 
 /*
  * Function irlmp_disconnect_request (handle, userdata)
index 6ffaed4544e963bbd010b515977b3d2586cc5cf8..634901dd156fc7b2154234f423417324032515a0 100644 (file)
@@ -54,7 +54,7 @@ extern int  irsock_init(void);
 extern void irsock_cleanup(void);
 /* irlap_frame.c */
 extern int  irlap_driver_rcv(struct sk_buff *, struct net_device *, 
-                            struct packet_type *);
+                            struct packet_type *, struct net_device *);
 
 /*
  * Module parameters
index 9004f7349a7604d9043cb6322a10f4d5c53ade51..b391cb3893d4852c57374eef08b95bd79daac3b1 100644 (file)
@@ -517,9 +517,6 @@ extern int
        irda_irnet_init(void);          /* Initialise IrDA part of IrNET */
 extern void
        irda_irnet_cleanup(void);       /* Teardown IrDA part of IrNET */
-/* ---------------------------- MODULE ---------------------------- */
-extern int
-       irnet_init(void);               /* Initialise IrNET module */
 
 /**************************** VARIABLES ****************************/
 
index f8f984bb99225631db2ca2c1edef438ec6bb4cb8..e53bf9e0053ee831d46639a4e70917c0436af585 100644 (file)
@@ -1107,7 +1107,7 @@ ppp_irnet_cleanup(void)
 /*
  * Module main entry point
  */
-int __init
+static int __init
 irnet_init(void)
 {
   int err;
index b0dd3ea35999698d2d577de56d1bef0ff35b248c..1ba8c7106639604f9ed91f8acff0afdc2ed5f170 100644 (file)
@@ -822,7 +822,6 @@ void* hashbin_find_next( hashbin_t* hashbin, long hashv, const char* name,
 
        return entry;
 }
-EXPORT_SYMBOL(hashbin_find_next);
 
 /*
  * Function hashbin_get_first (hashbin)
index df732d56cc577177b1b348b11158ea913c8c108e..ddfb5c502a90468fcc25651080708fd287bfdee5 100644 (file)
@@ -37,6 +37,7 @@
 #include <net/irda/parameters.h>
 #include <net/irda/qos.h>
 #include <net/irda/irlap.h>
+#include <net/irda/irlap_frame.h>
 
 /*
  * Maximum values of the baud rate we negociate with the other end.
index 5de05a0bc0ffe11ab5e59e2edc93302d06df866f..8b5eefd70f03c3f686f14fc84947ac5e7ce90ab3 100644 (file)
@@ -78,7 +78,7 @@ void lapb_requeue_frames(struct lapb_cb *lapb)
                if (!skb_prev)
                        skb_queue_head(&lapb->write_queue, skb);
                else
-                       skb_append(skb_prev, skb);
+                       skb_append(skb_prev, skb, &lapb->write_queue);
                skb_prev = skb;
        }
 }
index 20b4cfebd74ca543fc894b075802226d912011b3..66f55e514b568d2682f0c859e0db1e90cd252cf2 100644 (file)
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/tcp.h>
 #include <linux/rtnetlink.h>
 #include <linux/init.h>
 #include <net/llc.h>
 #include <net/llc_sap.h>
 #include <net/llc_pdu.h>
 #include <net/llc_conn.h>
+#include <net/tcp_states.h>
 
 /* remember: uninitialized global data is zeroed because its in .bss */
 static u16 llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
@@ -714,7 +714,7 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock,
        if (uaddr)
                memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr));
        msg->msg_namelen = sizeof(*uaddr);
-       if (!skb->list) {
+       if (!skb->next) {
 dgram_free:
                kfree_skb(skb);
        }
index eba812a9c69c6e0e0de271b5ec275d696da8e52d..4c644bc70eaec7b4a9f3f11d55f603afd72922b0 100644 (file)
@@ -16,7 +16,7 @@
 #include <net/llc_sap.h>
 #include <net/llc_conn.h>
 #include <net/sock.h>
-#include <linux/tcp.h>
+#include <net/tcp_states.h>
 #include <net/llc_c_ev.h>
 #include <net/llc_c_ac.h>
 #include <net/llc_c_st.h>
@@ -71,7 +71,11 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
 
        if (!ev->ind_prim && !ev->cfm_prim) {
                /* indicate or confirm not required */
-               if (!skb->list)
+               /* XXX this is not very pretty, perhaps we should store
+                * XXX indicate/confirm-needed state in the llc_conn_state_ev
+                * XXX control block of the SKB instead? -DaveM
+                */
+               if (!skb->next)
                        goto out_kfree_skb;
                goto out_skb_put;
        }
index 5ff02c080a0bfdbfee1bbacda96843c51843fc89..9727455bf0e7907d4285c42e2744bb1e4d52aed9 100644 (file)
@@ -103,7 +103,8 @@ out:
 struct llc_sap *llc_sap_open(unsigned char lsap,
                             int (*func)(struct sk_buff *skb,
                                         struct net_device *dev,
-                                        struct packet_type *pt))
+                                        struct packet_type *pt,
+                                        struct net_device *orig_dev))
 {
        struct llc_sap *sap = llc_sap_find(lsap);
 
index 0f9fc48aeaf916318a2198283ab007b08e96df27..0f84f66018e4ca2f63c09ee7b0a8ecdbfb429c19 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
-#include <linux/tcp.h>
 #include <asm/errno.h>
 #include <net/llc_if.h>
 #include <net/llc_sap.h>
@@ -25,6 +24,7 @@
 #include <net/llc_c_ev.h>
 #include <net/llc_c_ac.h>
 #include <net/llc_c_st.h>
+#include <net/tcp_states.h>
 
 u8 llc_mac_null_var[IFHWADDRLEN];
 
index 4da6976efc9c716b1460af2549a3a36f98849f71..13b46240b7a108148657aa736a03a52b7e540b41 100644 (file)
@@ -132,7 +132,7 @@ static inline int llc_fixup_skb(struct sk_buff *skb)
  *     data now), it queues this frame in the connection's backlog.
  */
 int llc_rcv(struct sk_buff *skb, struct net_device *dev,
-           struct packet_type *pt)
+           struct packet_type *pt, struct net_device *orig_dev)
 {
        struct llc_sap *sap;
        struct llc_pdu_sn *pdu;
@@ -165,7 +165,7 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
         * LLC functionality
         */
        if (sap->rcv_func) {
-               sap->rcv_func(skb, dev, pt);
+               sap->rcv_func(skb, dev, pt, orig_dev);
                goto out;
        }
        dest = llc_pdu_type(skb);
index 965c94eb4bbc7b93867f4f4bf707adef0a613552..34228ef149854175c7ecc65a6bc7d008c05421b5 100644 (file)
@@ -21,7 +21,7 @@
 #include <net/llc_s_ev.h>
 #include <net/llc_s_st.h>
 #include <net/sock.h>
-#include <linux/tcp.h>
+#include <net/tcp_states.h>
 #include <linux/llc.h>
 
 /**
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
new file mode 100644 (file)
index 0000000..8296b38
--- /dev/null
@@ -0,0 +1,24 @@
+config NETFILTER_NETLINK
+       tristate "Netfilter netlink interface"
+       help
+         If this option is enabled, the kernel will include support
+         for the new netfilter netlink interface.
+
+config NETFILTER_NETLINK_QUEUE
+       tristate "Netfilter NFQUEUE over NFNETLINK interface"
+       depends on NETFILTER_NETLINK
+       help
+         If this option isenabled, the kernel will include support
+         for queueing packets via NFNETLINK.
+         
+config NETFILTER_NETLINK_LOG
+       tristate "Netfilter LOG over NFNETLINK interface"
+       depends on NETFILTER_NETLINK
+       help
+         If this option is enabled, the kernel will include support
+         for logging packets via NFNETLINK.
+
+         This obsoletes the existing ipt_ULOG and ebg_ulog mechanisms,
+         and is also scheduled to replace the old syslog-based ipt_LOG
+         and ip6t_LOG modules.
+
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
new file mode 100644 (file)
index 0000000..b3b44f8
--- /dev/null
@@ -0,0 +1,7 @@
+netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o
+
+obj-$(CONFIG_NETFILTER) = netfilter.o
+
+obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o
+obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o
+obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
new file mode 100644 (file)
index 0000000..1ceb1a6
--- /dev/null
@@ -0,0 +1,216 @@
+/* netfilter.c: look after the filters for various protocols. 
+ * Heavily influenced by the old firewall.c by David Bonn and Alan Cox.
+ *
+ * Thanks to Rob `CmdrTaco' Malda for not influencing this code in any
+ * way.
+ *
+ * Rusty Russell (C)2000 -- This code is GPL.
+ *
+ * February 2000: Modified by James Morris to have 1 queue per protocol.
+ * 15-Mar-2000:   Added NF_REPEAT --RR.
+ * 08-May-2003:          Internal logging interface added by Jozsef Kadlecsik.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/netfilter.h>
+#include <net/protocol.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/if.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/proc_fs.h>
+#include <net/sock.h>
+
+#include "nf_internals.h"
+
+/* In this code, we can be waiting indefinitely for userspace to
+ * service a packet if a hook returns NF_QUEUE.  We could keep a count
+ * of skbuffs queued for userspace, and not deregister a hook unless
+ * this is zero, but that sucks.  Now, we simply check when the
+ * packets come back: if the hook is gone, the packet is discarded. */
+struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
+EXPORT_SYMBOL(nf_hooks);
+static DEFINE_SPINLOCK(nf_hook_lock);
+
+int nf_register_hook(struct nf_hook_ops *reg)
+{
+       struct list_head *i;
+
+       spin_lock_bh(&nf_hook_lock);
+       list_for_each(i, &nf_hooks[reg->pf][reg->hooknum]) {
+               if (reg->priority < ((struct nf_hook_ops *)i)->priority)
+                       break;
+       }
+       list_add_rcu(&reg->list, i->prev);
+       spin_unlock_bh(&nf_hook_lock);
+
+       synchronize_net();
+       return 0;
+}
+EXPORT_SYMBOL(nf_register_hook);
+
+void nf_unregister_hook(struct nf_hook_ops *reg)
+{
+       spin_lock_bh(&nf_hook_lock);
+       list_del_rcu(&reg->list);
+       spin_unlock_bh(&nf_hook_lock);
+
+       synchronize_net();
+}
+EXPORT_SYMBOL(nf_unregister_hook);
+
+unsigned int nf_iterate(struct list_head *head,
+                       struct sk_buff **skb,
+                       int hook,
+                       const struct net_device *indev,
+                       const struct net_device *outdev,
+                       struct list_head **i,
+                       int (*okfn)(struct sk_buff *),
+                       int hook_thresh)
+{
+       unsigned int verdict;
+
+       /*
+        * The caller must not block between calls to this
+        * function because of risk of continuing from deleted element.
+        */
+       list_for_each_continue_rcu(*i, head) {
+               struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;
+
+               if (hook_thresh > elem->priority)
+                       continue;
+
+               /* Optimization: we don't need to hold module
+                   reference here, since function can't sleep. --RR */
+               verdict = elem->hook(hook, skb, indev, outdev, okfn);
+               if (verdict != NF_ACCEPT) {
+#ifdef CONFIG_NETFILTER_DEBUG
+                       if (unlikely((verdict & NF_VERDICT_MASK)
+                                                       > NF_MAX_VERDICT)) {
+                               NFDEBUG("Evil return from %p(%u).\n",
+                                       elem->hook, hook);
+                               continue;
+                       }
+#endif
+                       if (verdict != NF_REPEAT)
+                               return verdict;
+                       *i = (*i)->prev;
+               }
+       }
+       return NF_ACCEPT;
+}
+
+
+/* Returns 1 if okfn() needs to be executed by the caller,
+ * -EPERM for NF_DROP, 0 otherwise. */
+int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
+                struct net_device *indev,
+                struct net_device *outdev,
+                int (*okfn)(struct sk_buff *),
+                int hook_thresh)
+{
+       struct list_head *elem;
+       unsigned int verdict;
+       int ret = 0;
+
+       /* We may already have this, but read-locks nest anyway */
+       rcu_read_lock();
+
+       elem = &nf_hooks[pf][hook];
+next_hook:
+       verdict = nf_iterate(&nf_hooks[pf][hook], pskb, hook, indev,
+                            outdev, &elem, okfn, hook_thresh);
+       if (verdict == NF_ACCEPT || verdict == NF_STOP) {
+               ret = 1;
+               goto unlock;
+       } else if (verdict == NF_DROP) {
+               kfree_skb(*pskb);
+               ret = -EPERM;
+       } else if ((verdict & NF_VERDICT_MASK)  == NF_QUEUE) {
+               NFDEBUG("nf_hook: Verdict = QUEUE.\n");
+               if (!nf_queue(pskb, elem, pf, hook, indev, outdev, okfn,
+                             verdict >> NF_VERDICT_BITS))
+                       goto next_hook;
+       }
+unlock:
+       rcu_read_unlock();
+       return ret;
+}
+EXPORT_SYMBOL(nf_hook_slow);
+
+
+int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len)
+{
+       struct sk_buff *nskb;
+
+       if (writable_len > (*pskb)->len)
+               return 0;
+
+       /* Not exclusive use of packet?  Must copy. */
+       if (skb_shared(*pskb) || skb_cloned(*pskb))
+               goto copy_skb;
+
+       return pskb_may_pull(*pskb, writable_len);
+
+copy_skb:
+       nskb = skb_copy(*pskb, GFP_ATOMIC);
+       if (!nskb)
+               return 0;
+       BUG_ON(skb_is_nonlinear(nskb));
+
+       /* Rest of kernel will get very unhappy if we pass it a
+          suddenly-orphaned skbuff */
+       if ((*pskb)->sk)
+               skb_set_owner_w(nskb, (*pskb)->sk);
+       kfree_skb(*pskb);
+       *pskb = nskb;
+       return 1;
+}
+EXPORT_SYMBOL(skb_make_writable);
+
+
+/* This does not belong here, but locally generated errors need it if connection
+   tracking in use: without this, connection may not be in hash table, and hence
+   manufactured ICMP or RST packets will not be associated with it. */
+void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *);
+EXPORT_SYMBOL(ip_ct_attach);
+
+void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb)
+{
+       void (*attach)(struct sk_buff *, struct sk_buff *);
+
+       if (skb->nfct && (attach = ip_ct_attach) != NULL) {
+               mb(); /* Just to be sure: must be read before executing this */
+               attach(new, skb);
+       }
+}
+EXPORT_SYMBOL(nf_ct_attach);
+
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry *proc_net_netfilter;
+EXPORT_SYMBOL(proc_net_netfilter);
+#endif
+
+void __init netfilter_init(void)
+{
+       int i, h;
+       for (i = 0; i < NPROTO; i++) {
+               for (h = 0; h < NF_MAX_HOOKS; h++)
+                       INIT_LIST_HEAD(&nf_hooks[i][h]);
+       }
+
+#ifdef CONFIG_PROC_FS
+       proc_net_netfilter = proc_mkdir("netfilter", proc_net);
+       if (!proc_net_netfilter)
+               panic("cannot create netfilter proc entry");
+#endif
+
+       if (netfilter_queue_init() < 0)
+               panic("cannot initialize nf_queue");
+       if (netfilter_log_init() < 0)
+               panic("cannot initialize nf_log");
+}
diff --git a/net/netfilter/nf_internals.h b/net/netfilter/nf_internals.h
new file mode 100644 (file)
index 0000000..6bdee29
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _NF_INTERNALS_H
+#define _NF_INTERNALS_H
+
+#include <linux/config.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+
+#ifdef CONFIG_NETFILTER_DEBUG
+#define NFDEBUG(format, args...)  printk(format , ## args)
+#else
+#define NFDEBUG(format, args...)
+#endif
+
+
+/* core.c */
+extern unsigned int nf_iterate(struct list_head *head,
+                               struct sk_buff **skb,
+                               int hook,
+                               const struct net_device *indev,
+                               const struct net_device *outdev,
+                               struct list_head **i,
+                               int (*okfn)(struct sk_buff *),
+                               int hook_thresh);
+
+/* nf_queue.c */
+extern int nf_queue(struct sk_buff **skb, 
+                   struct list_head *elem, 
+                   int pf, unsigned int hook,
+                   struct net_device *indev,
+                   struct net_device *outdev,
+                   int (*okfn)(struct sk_buff *),
+                   unsigned int queuenum);
+extern int __init netfilter_queue_init(void);
+
+/* nf_log.c */
+extern int __init netfilter_log_init(void);
+
+#endif
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
new file mode 100644 (file)
index 0000000..3e76bd0
--- /dev/null
@@ -0,0 +1,178 @@
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter.h>
+#include <linux/seq_file.h>
+#include <net/protocol.h>
+
+#include "nf_internals.h"
+
+/* Internal logging interface, which relies on the real 
+   LOG target modules */
+
+#define NF_LOG_PREFIXLEN               128
+
+static struct nf_logger *nf_logging[NPROTO]; /* = NULL */
+static DEFINE_SPINLOCK(nf_log_lock);
+
+/* return EBUSY if somebody else is registered, EEXIST if the same logger
+ * is registred, 0 on success. */
+int nf_log_register(int pf, struct nf_logger *logger)
+{
+       int ret = -EBUSY;
+
+       if (pf >= NPROTO)
+               return -EINVAL;
+
+       /* Any setup of logging members must be done before
+        * substituting pointer. */
+       spin_lock(&nf_log_lock);
+       if (!nf_logging[pf]) {
+               rcu_assign_pointer(nf_logging[pf], logger);
+               ret = 0;
+       } else if (nf_logging[pf] == logger)
+               ret = -EEXIST;
+
+       spin_unlock(&nf_log_lock);
+       return ret;
+}              
+EXPORT_SYMBOL(nf_log_register);
+
+int nf_log_unregister_pf(int pf)
+{
+       if (pf >= NPROTO)
+               return -EINVAL;
+
+       spin_lock(&nf_log_lock);
+       nf_logging[pf] = NULL;
+       spin_unlock(&nf_log_lock);
+
+       /* Give time to concurrent readers. */
+       synchronize_net();
+
+       return 0;
+}
+EXPORT_SYMBOL(nf_log_unregister_pf);
+
+void nf_log_unregister_logger(struct nf_logger *logger)
+{
+       int i;
+
+       spin_lock(&nf_log_lock);
+       for (i = 0; i < NPROTO; i++) {
+               if (nf_logging[i] == logger)
+                       nf_logging[i] = NULL;
+       }
+       spin_unlock(&nf_log_lock);
+
+       synchronize_net();
+}
+EXPORT_SYMBOL(nf_log_unregister_logger);
+
+void nf_log_packet(int pf,
+                  unsigned int hooknum,
+                  const struct sk_buff *skb,
+                  const struct net_device *in,
+                  const struct net_device *out,
+                  struct nf_loginfo *loginfo,
+                  const char *fmt, ...)
+{
+       va_list args;
+       char prefix[NF_LOG_PREFIXLEN];
+       struct nf_logger *logger;
+       
+       rcu_read_lock();
+       logger = rcu_dereference(nf_logging[pf]);
+       if (logger) {
+               va_start(args, fmt);
+               vsnprintf(prefix, sizeof(prefix), fmt, args);
+               va_end(args);
+               /* We must read logging before nf_logfn[pf] */
+               logger->logfn(pf, hooknum, skb, in, out, loginfo, prefix);
+       } else if (net_ratelimit()) {
+               printk(KERN_WARNING "nf_log_packet: can\'t log since "
+                      "no backend logging module loaded in! Please either "
+                      "load one, or disable logging explicitly\n");
+       }
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL(nf_log_packet);
+
+#ifdef CONFIG_PROC_FS
+static void *seq_start(struct seq_file *seq, loff_t *pos)
+{
+       rcu_read_lock();
+
+       if (*pos >= NPROTO)
+               return NULL;
+
+       return pos;
+}
+
+static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       (*pos)++;
+
+       if (*pos >= NPROTO)
+               return NULL;
+
+       return pos;
+}
+
+static void seq_stop(struct seq_file *s, void *v)
+{
+       rcu_read_unlock();
+}
+
+static int seq_show(struct seq_file *s, void *v)
+{
+       loff_t *pos = v;
+       const struct nf_logger *logger;
+
+       logger = rcu_dereference(nf_logging[*pos]);
+
+       if (!logger)
+               return seq_printf(s, "%2lld NONE\n", *pos);
+       
+       return seq_printf(s, "%2lld %s\n", *pos, logger->name);
+}
+
+static struct seq_operations nflog_seq_ops = {
+       .start  = seq_start,
+       .next   = seq_next,
+       .stop   = seq_stop,
+       .show   = seq_show,
+};
+
+static int nflog_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &nflog_seq_ops);
+}
+
+static struct file_operations nflog_file_ops = {
+       .owner   = THIS_MODULE,
+       .open    = nflog_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release,
+};
+
+#endif /* PROC_FS */
+
+
+int __init netfilter_log_init(void)
+{
+#ifdef CONFIG_PROC_FS
+       struct proc_dir_entry *pde;
+
+       pde = create_proc_entry("nf_log", S_IRUGO, proc_net_netfilter);
+       if (!pde)
+               return -1;
+
+       pde->proc_fops = &nflog_file_ops;
+#endif
+       return 0;
+}
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
new file mode 100644 (file)
index 0000000..d10d552
--- /dev/null
@@ -0,0 +1,343 @@
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter.h>
+#include <linux/seq_file.h>
+#include <net/protocol.h>
+
+#include "nf_internals.h"
+
+/* 
+ * A queue handler may be registered for each protocol.  Each is protected by
+ * long term mutex.  The handler must provide an an outfn() to accept packets
+ * for queueing and must reinject all packets it receives, no matter what.
+ */
+static struct nf_queue_handler *queue_handler[NPROTO];
+static struct nf_queue_rerouter *queue_rerouter;
+
+static DEFINE_RWLOCK(queue_handler_lock);
+
+/* return EBUSY when somebody else is registered, return EEXIST if the
+ * same handler is registered, return 0 in case of success. */
+int nf_register_queue_handler(int pf, struct nf_queue_handler *qh)
+{      
+       int ret;
+
+       if (pf >= NPROTO)
+               return -EINVAL;
+
+       write_lock_bh(&queue_handler_lock);
+       if (queue_handler[pf] == qh)
+               ret = -EEXIST;
+       else if (queue_handler[pf])
+               ret = -EBUSY;
+       else {
+               queue_handler[pf] = qh;
+               ret = 0;
+       }
+       write_unlock_bh(&queue_handler_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(nf_register_queue_handler);
+
+/* The caller must flush their queue before this */
+int nf_unregister_queue_handler(int pf)
+{
+       if (pf >= NPROTO)
+               return -EINVAL;
+
+       write_lock_bh(&queue_handler_lock);
+       queue_handler[pf] = NULL;
+       write_unlock_bh(&queue_handler_lock);
+       
+       return 0;
+}
+EXPORT_SYMBOL(nf_unregister_queue_handler);
+
+int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer)
+{
+       if (pf >= NPROTO)
+               return -EINVAL;
+
+       write_lock_bh(&queue_handler_lock);
+       memcpy(&queue_rerouter[pf], rer, sizeof(queue_rerouter[pf]));
+       write_unlock_bh(&queue_handler_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nf_register_queue_rerouter);
+
+int nf_unregister_queue_rerouter(int pf)
+{
+       if (pf >= NPROTO)
+               return -EINVAL;
+
+       write_lock_bh(&queue_handler_lock);
+       memset(&queue_rerouter[pf], 0, sizeof(queue_rerouter[pf]));
+       write_unlock_bh(&queue_handler_lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter);
+
+void nf_unregister_queue_handlers(struct nf_queue_handler *qh)
+{
+       int pf;
+
+       write_lock_bh(&queue_handler_lock);
+       for (pf = 0; pf < NPROTO; pf++)  {
+               if (queue_handler[pf] == qh)
+                       queue_handler[pf] = NULL;
+       }
+       write_unlock_bh(&queue_handler_lock);
+}
+EXPORT_SYMBOL_GPL(nf_unregister_queue_handlers);
+
+/* 
+ * Any packet that leaves via this function must come back 
+ * through nf_reinject().
+ */
+int nf_queue(struct sk_buff **skb, 
+            struct list_head *elem, 
+            int pf, unsigned int hook,
+            struct net_device *indev,
+            struct net_device *outdev,
+            int (*okfn)(struct sk_buff *),
+            unsigned int queuenum)
+{
+       int status;
+       struct nf_info *info;
+#ifdef CONFIG_BRIDGE_NETFILTER
+       struct net_device *physindev = NULL;
+       struct net_device *physoutdev = NULL;
+#endif
+
+       /* QUEUE == DROP if noone is waiting, to be safe. */
+       read_lock(&queue_handler_lock);
+       if (!queue_handler[pf]->outfn) {
+               read_unlock(&queue_handler_lock);
+               kfree_skb(*skb);
+               return 1;
+       }
+
+       info = kmalloc(sizeof(*info)+queue_rerouter[pf].rer_size, GFP_ATOMIC);
+       if (!info) {
+               if (net_ratelimit())
+                       printk(KERN_ERR "OOM queueing packet %p\n",
+                              *skb);
+               read_unlock(&queue_handler_lock);
+               kfree_skb(*skb);
+               return 1;
+       }
+
+       *info = (struct nf_info) { 
+               (struct nf_hook_ops *)elem, pf, hook, indev, outdev, okfn };
+
+       /* If it's going away, ignore hook. */
+       if (!try_module_get(info->elem->owner)) {
+               read_unlock(&queue_handler_lock);
+               kfree(info);
+               return 0;
+       }
+
+       /* Bump dev refs so they don't vanish while packet is out */
+       if (indev) dev_hold(indev);
+       if (outdev) dev_hold(outdev);
+
+#ifdef CONFIG_BRIDGE_NETFILTER
+       if ((*skb)->nf_bridge) {
+               physindev = (*skb)->nf_bridge->physindev;
+               if (physindev) dev_hold(physindev);
+               physoutdev = (*skb)->nf_bridge->physoutdev;
+               if (physoutdev) dev_hold(physoutdev);
+       }
+#endif
+       if (queue_rerouter[pf].save)
+               queue_rerouter[pf].save(*skb, info);
+
+       status = queue_handler[pf]->outfn(*skb, info, queuenum,
+                                         queue_handler[pf]->data);
+
+       if (status >= 0 && queue_rerouter[pf].reroute)
+               status = queue_rerouter[pf].reroute(skb, info);
+
+       read_unlock(&queue_handler_lock);
+
+       if (status < 0) {
+               /* James M doesn't say fuck enough. */
+               if (indev) dev_put(indev);
+               if (outdev) dev_put(outdev);
+#ifdef CONFIG_BRIDGE_NETFILTER
+               if (physindev) dev_put(physindev);
+               if (physoutdev) dev_put(physoutdev);
+#endif
+               module_put(info->elem->owner);
+               kfree(info);
+               kfree_skb(*skb);
+
+               return 1;
+       }
+
+       return 1;
+}
+
+void nf_reinject(struct sk_buff *skb, struct nf_info *info,
+                unsigned int verdict)
+{
+       struct list_head *elem = &info->elem->list;
+       struct list_head *i;
+
+       rcu_read_lock();
+
+       /* Release those devices we held, or Alexey will kill me. */
+       if (info->indev) dev_put(info->indev);
+       if (info->outdev) dev_put(info->outdev);
+#ifdef CONFIG_BRIDGE_NETFILTER
+       if (skb->nf_bridge) {
+               if (skb->nf_bridge->physindev)
+                       dev_put(skb->nf_bridge->physindev);
+               if (skb->nf_bridge->physoutdev)
+                       dev_put(skb->nf_bridge->physoutdev);
+       }
+#endif
+
+       /* Drop reference to owner of hook which queued us. */
+       module_put(info->elem->owner);
+
+       list_for_each_rcu(i, &nf_hooks[info->pf][info->hook]) {
+               if (i == elem) 
+                       break;
+       }
+  
+       if (elem == &nf_hooks[info->pf][info->hook]) {
+               /* The module which sent it to userspace is gone. */
+               NFDEBUG("%s: module disappeared, dropping packet.\n",
+                       __FUNCTION__);
+               verdict = NF_DROP;
+       }
+
+       /* Continue traversal iff userspace said ok... */
+       if (verdict == NF_REPEAT) {
+               elem = elem->prev;
+               verdict = NF_ACCEPT;
+       }
+
+       if (verdict == NF_ACCEPT) {
+       next_hook:
+               verdict = nf_iterate(&nf_hooks[info->pf][info->hook],
+                                    &skb, info->hook, 
+                                    info->indev, info->outdev, &elem,
+                                    info->okfn, INT_MIN);
+       }
+
+       switch (verdict & NF_VERDICT_MASK) {
+       case NF_ACCEPT:
+               info->okfn(skb);
+               break;
+
+       case NF_QUEUE:
+               if (!nf_queue(&skb, elem, info->pf, info->hook, 
+                             info->indev, info->outdev, info->okfn,
+                             verdict >> NF_VERDICT_BITS))
+                       goto next_hook;
+               break;
+       }
+       rcu_read_unlock();
+
+       if (verdict == NF_DROP)
+               kfree_skb(skb);
+
+       kfree(info);
+       return;
+}
+EXPORT_SYMBOL(nf_reinject);
+
+#ifdef CONFIG_PROC_FS
+static void *seq_start(struct seq_file *seq, loff_t *pos)
+{
+       if (*pos >= NPROTO)
+               return NULL;
+
+       return pos;
+}
+
+static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       (*pos)++;
+
+       if (*pos >= NPROTO)
+               return NULL;
+
+       return pos;
+}
+
+static void seq_stop(struct seq_file *s, void *v)
+{
+
+}
+
+static int seq_show(struct seq_file *s, void *v)
+{
+       int ret;
+       loff_t *pos = v;
+       struct nf_queue_handler *qh;
+
+       read_lock_bh(&queue_handler_lock);
+       qh = queue_handler[*pos];
+       if (!qh)
+               ret = seq_printf(s, "%2lld NONE\n", *pos);
+       else
+               ret = seq_printf(s, "%2lld %s\n", *pos, qh->name);
+       read_unlock_bh(&queue_handler_lock);
+
+       return ret;
+}
+
+static struct seq_operations nfqueue_seq_ops = {
+       .start  = seq_start,
+       .next   = seq_next,
+       .stop   = seq_stop,
+       .show   = seq_show,
+};
+
+static int nfqueue_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &nfqueue_seq_ops);
+}
+
+static struct file_operations nfqueue_file_ops = {
+       .owner   = THIS_MODULE,
+       .open    = nfqueue_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release,
+};
+#endif /* PROC_FS */
+
+
+int __init netfilter_queue_init(void)
+{
+#ifdef CONFIG_PROC_FS
+       struct proc_dir_entry *pde;
+#endif
+       queue_rerouter = kmalloc(NPROTO * sizeof(struct nf_queue_rerouter),
+                                GFP_KERNEL);
+       if (!queue_rerouter)
+               return -ENOMEM;
+
+#ifdef CONFIG_PROC_FS
+       pde = create_proc_entry("nf_queue", S_IRUGO, proc_net_netfilter);
+       if (!pde) {
+               kfree(queue_rerouter);
+               return -1;
+       }
+       pde->proc_fops = &nfqueue_file_ops;
+#endif
+       memset(queue_rerouter, 0, NPROTO * sizeof(struct nf_queue_rerouter));
+
+       return 0;
+}
+
diff --git a/net/netfilter/nf_sockopt.c b/net/netfilter/nf_sockopt.c
new file mode 100644 (file)
index 0000000..61a833a
--- /dev/null
@@ -0,0 +1,132 @@
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter.h>
+#include <net/sock.h>
+
+#include "nf_internals.h"
+
+/* Sockopts only registered and called from user context, so
+   net locking would be overkill.  Also, [gs]etsockopt calls may
+   sleep. */
+static DECLARE_MUTEX(nf_sockopt_mutex);
+static LIST_HEAD(nf_sockopts);
+
+/* Do exclusive ranges overlap? */
+static inline int overlap(int min1, int max1, int min2, int max2)
+{
+       return max1 > min2 && min1 < max2;
+}
+
+/* Functions to register sockopt ranges (exclusive). */
+int nf_register_sockopt(struct nf_sockopt_ops *reg)
+{
+       struct list_head *i;
+       int ret = 0;
+
+       if (down_interruptible(&nf_sockopt_mutex) != 0)
+               return -EINTR;
+
+       list_for_each(i, &nf_sockopts) {
+               struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i;
+               if (ops->pf == reg->pf
+                   && (overlap(ops->set_optmin, ops->set_optmax, 
+                               reg->set_optmin, reg->set_optmax)
+                       || overlap(ops->get_optmin, ops->get_optmax, 
+                                  reg->get_optmin, reg->get_optmax))) {
+                       NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n",
+                               ops->set_optmin, ops->set_optmax, 
+                               ops->get_optmin, ops->get_optmax, 
+                               reg->set_optmin, reg->set_optmax,
+                               reg->get_optmin, reg->get_optmax);
+                       ret = -EBUSY;
+                       goto out;
+               }
+       }
+
+       list_add(&reg->list, &nf_sockopts);
+out:
+       up(&nf_sockopt_mutex);
+       return ret;
+}
+EXPORT_SYMBOL(nf_register_sockopt);
+
+void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
+{
+       /* No point being interruptible: we're probably in cleanup_module() */
+ restart:
+       down(&nf_sockopt_mutex);
+       if (reg->use != 0) {
+               /* To be woken by nf_sockopt call... */
+               /* FIXME: Stuart Young's name appears gratuitously. */
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               reg->cleanup_task = current;
+               up(&nf_sockopt_mutex);
+               schedule();
+               goto restart;
+       }
+       list_del(&reg->list);
+       up(&nf_sockopt_mutex);
+}
+EXPORT_SYMBOL(nf_unregister_sockopt);
+
+/* Call get/setsockopt() */
+static int nf_sockopt(struct sock *sk, int pf, int val, 
+                     char __user *opt, int *len, int get)
+{
+       struct list_head *i;
+       struct nf_sockopt_ops *ops;
+       int ret;
+
+       if (down_interruptible(&nf_sockopt_mutex) != 0)
+               return -EINTR;
+
+       list_for_each(i, &nf_sockopts) {
+               ops = (struct nf_sockopt_ops *)i;
+               if (ops->pf == pf) {
+                       if (get) {
+                               if (val >= ops->get_optmin
+                                   && val < ops->get_optmax) {
+                                       ops->use++;
+                                       up(&nf_sockopt_mutex);
+                                       ret = ops->get(sk, val, opt, len);
+                                       goto out;
+                               }
+                       } else {
+                               if (val >= ops->set_optmin
+                                   && val < ops->set_optmax) {
+                                       ops->use++;
+                                       up(&nf_sockopt_mutex);
+                                       ret = ops->set(sk, val, opt, *len);
+                                       goto out;
+                               }
+                       }
+               }
+       }
+       up(&nf_sockopt_mutex);
+       return -ENOPROTOOPT;
+       
+ out:
+       down(&nf_sockopt_mutex);
+       ops->use--;
+       if (ops->cleanup_task)
+               wake_up_process(ops->cleanup_task);
+       up(&nf_sockopt_mutex);
+       return ret;
+}
+
+int nf_setsockopt(struct sock *sk, int pf, int val, char __user *opt,
+                 int len)
+{
+       return nf_sockopt(sk, pf, val, opt, &len, 0);
+}
+EXPORT_SYMBOL(nf_setsockopt);
+
+int nf_getsockopt(struct sock *sk, int pf, int val, char __user *opt, int *len)
+{
+       return nf_sockopt(sk, pf, val, opt, len, 1);
+}
+EXPORT_SYMBOL(nf_getsockopt);
+
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
new file mode 100644 (file)
index 0000000..49a3900
--- /dev/null
@@ -0,0 +1,376 @@
+/* Netfilter messages via netlink socket. Allows for user space
+ * protocol helpers and general trouble making from userspace.
+ *
+ * (C) 2001 by Jay Schulist <jschlst@samba.org>,
+ * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
+ *
+ * Initial netfilter messages via netlink development funded and
+ * generally made possible by Network Robots, Inc. (www.networkrobots.com)
+ *
+ * Further development of this code funded by Astaro AG (http://www.astaro.com)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/fcntl.h>
+#include <linux/skbuff.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <net/sock.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+
+#include <linux/netfilter.h>
+#include <linux/netlink.h>
+#include <linux/netfilter/nfnetlink.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER);
+
+static char __initdata nfversion[] = "0.30";
+
+#if 0
+#define DEBUGP(format, args...)        \
+               printk(KERN_DEBUG "%s(%d):%s(): " format, __FILE__, \
+                       __LINE__, __FUNCTION__, ## args)
+#else
+#define DEBUGP(format, args...)
+#endif
+
+static struct sock *nfnl = NULL;
+static struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT];
+DECLARE_MUTEX(nfnl_sem);
+
+void nfnl_lock(void)
+{
+       nfnl_shlock();
+}
+
+void nfnl_unlock(void)
+{
+       nfnl_shunlock();
+}
+
+int nfnetlink_subsys_register(struct nfnetlink_subsystem *n)
+{
+       DEBUGP("registering subsystem ID %u\n", n->subsys_id);
+
+       nfnl_lock();
+       if (subsys_table[n->subsys_id]) {
+               nfnl_unlock();
+               return -EBUSY;
+       }
+       subsys_table[n->subsys_id] = n;
+       nfnl_unlock();
+
+       return 0;
+}
+
+int nfnetlink_subsys_unregister(struct nfnetlink_subsystem *n)
+{
+       DEBUGP("unregistering subsystem ID %u\n", n->subsys_id);
+
+       nfnl_lock();
+       subsys_table[n->subsys_id] = NULL;
+       nfnl_unlock();
+
+       return 0;
+}
+
+static inline struct nfnetlink_subsystem *nfnetlink_get_subsys(u_int16_t type)
+{
+       u_int8_t subsys_id = NFNL_SUBSYS_ID(type);
+
+       if (subsys_id >= NFNL_SUBSYS_COUNT
+           || subsys_table[subsys_id] == NULL)
+               return NULL;
+
+       return subsys_table[subsys_id];
+}
+
+static inline struct nfnl_callback *
+nfnetlink_find_client(u_int16_t type, struct nfnetlink_subsystem *ss)
+{
+       u_int8_t cb_id = NFNL_MSG_TYPE(type);
+       
+       if (cb_id >= ss->cb_count) {
+               DEBUGP("msgtype %u >= %u, returning\n", type, ss->cb_count);
+               return NULL;
+       }
+
+       return &ss->cb[cb_id];
+}
+
+void __nfa_fill(struct sk_buff *skb, int attrtype, int attrlen,
+               const void *data)
+{
+       struct nfattr *nfa;
+       int size = NFA_LENGTH(attrlen);
+
+       nfa = (struct nfattr *)skb_put(skb, NFA_ALIGN(size));
+       nfa->nfa_type = attrtype;
+       nfa->nfa_len  = size;
+       memcpy(NFA_DATA(nfa), data, attrlen);
+       memset(NFA_DATA(nfa) + attrlen, 0, NFA_ALIGN(size) - size);
+}
+
+int nfattr_parse(struct nfattr *tb[], int maxattr, struct nfattr *nfa, int len)
+{
+       memset(tb, 0, sizeof(struct nfattr *) * maxattr);
+
+       while (NFA_OK(nfa, len)) {
+               unsigned flavor = nfa->nfa_type;
+               if (flavor && flavor <= maxattr)
+                       tb[flavor-1] = nfa;
+               nfa = NFA_NEXT(nfa, len);
+       }
+
+       return 0;
+}
+
+/**
+ * nfnetlink_check_attributes - check and parse nfnetlink attributes
+ *
+ * subsys: nfnl subsystem for which this message is to be parsed
+ * nlmsghdr: netlink message to be checked/parsed
+ * cda: array of pointers, needs to be at least subsys->attr_count big
+ *
+ */
+static int
+nfnetlink_check_attributes(struct nfnetlink_subsystem *subsys,
+                          struct nlmsghdr *nlh, struct nfattr *cda[])
+{
+       int min_len;
+       u_int16_t attr_count;
+       u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
+
+       if (unlikely(cb_id >= subsys->cb_count)) {
+               DEBUGP("msgtype %u >= %u, returning\n",
+                       cb_id, subsys->cb_count);
+               return -EINVAL;
+       }
+
+       min_len = NLMSG_ALIGN(sizeof(struct nfgenmsg));
+       if (unlikely(nlh->nlmsg_len < min_len))
+               return -EINVAL;
+
+       attr_count = subsys->cb[cb_id].attr_count;
+       memset(cda, 0, sizeof(struct nfattr *) * attr_count);
+
+       /* check attribute lengths. */
+       if (likely(nlh->nlmsg_len > min_len)) {
+               struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh));
+               int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
+
+               while (NFA_OK(attr, attrlen)) {
+                       unsigned flavor = attr->nfa_type;
+                       if (flavor) {
+                               if (flavor > attr_count)
+                                       return -EINVAL;
+                               cda[flavor - 1] = attr;
+                       }
+                       attr = NFA_NEXT(attr, attrlen);
+               }
+       }
+
+       /* implicit: if nlmsg_len == min_len, we return 0, and an empty
+        * (zeroed) cda[] array. The message is valid, but empty. */
+
+        return 0;
+}
+
+int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo)
+{
+       int allocation = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+       int err = 0;
+
+       NETLINK_CB(skb).dst_group = group;
+       if (echo)
+               atomic_inc(&skb->users);
+       netlink_broadcast(nfnl, skb, pid, group, allocation);
+       if (echo)
+               err = netlink_unicast(nfnl, skb, pid, MSG_DONTWAIT);
+
+       return err;
+}
+
+int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags)
+{
+       return netlink_unicast(nfnl, skb, pid, flags);
+}
+
+/* Process one complete nfnetlink message. */
+static inline int nfnetlink_rcv_msg(struct sk_buff *skb,
+                                   struct nlmsghdr *nlh, int *errp)
+{
+       struct nfnl_callback *nc;
+       struct nfnetlink_subsystem *ss;
+       int type, err = 0;
+
+       DEBUGP("entered; subsys=%u, msgtype=%u\n",
+                NFNL_SUBSYS_ID(nlh->nlmsg_type),
+                NFNL_MSG_TYPE(nlh->nlmsg_type));
+
+       /* Only requests are handled by kernel now. */
+       if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) {
+               DEBUGP("received non-request message\n");
+               return 0;
+       }
+
+       /* All the messages must at least contain nfgenmsg */
+       if (nlh->nlmsg_len < 
+                       NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct nfgenmsg)))) {
+               DEBUGP("received message was too short\n");
+               return 0;
+       }
+
+       type = nlh->nlmsg_type;
+       ss = nfnetlink_get_subsys(type);
+       if (!ss) {
+#ifdef CONFIG_KMOD
+               /* don't call nfnl_shunlock, since it would reenter
+                * with further packet processing */
+               up(&nfnl_sem);
+               request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type));
+               nfnl_shlock();
+               ss = nfnetlink_get_subsys(type);
+               if (!ss)
+#endif
+               goto err_inval;
+       }
+
+       nc = nfnetlink_find_client(type, ss);
+       if (!nc) {
+               DEBUGP("unable to find client for type %d\n", type);
+               goto err_inval;
+       }
+
+       if (nc->cap_required && 
+           !cap_raised(NETLINK_CB(skb).eff_cap, nc->cap_required)) {
+               DEBUGP("permission denied for type %d\n", type);
+               *errp = -EPERM;
+               return -1;
+       }
+
+       {
+               u_int16_t attr_count = 
+                       ss->cb[NFNL_MSG_TYPE(nlh->nlmsg_type)].attr_count;
+               struct nfattr *cda[attr_count];
+
+               memset(cda, 0, sizeof(struct nfattr *) * attr_count);
+               
+               err = nfnetlink_check_attributes(ss, nlh, cda);
+               if (err < 0)
+                       goto err_inval;
+
+               DEBUGP("calling handler\n");
+               err = nc->call(nfnl, skb, nlh, cda, errp);
+               *errp = err;
+               return err;
+       }
+
+err_inval:
+       DEBUGP("returning -EINVAL\n");
+       *errp = -EINVAL;
+       return -1;
+}
+
+/* Process one packet of messages. */
+static inline int nfnetlink_rcv_skb(struct sk_buff *skb)
+{
+       int err;
+       struct nlmsghdr *nlh;
+
+       while (skb->len >= NLMSG_SPACE(0)) {
+               u32 rlen;
+
+               nlh = (struct nlmsghdr *)skb->data;
+               if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
+                   || skb->len < nlh->nlmsg_len)
+                       return 0;
+               rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+               if (rlen > skb->len)
+                       rlen = skb->len;
+               if (nfnetlink_rcv_msg(skb, nlh, &err)) {
+                       if (!err)
+                               return -1;
+                       netlink_ack(skb, nlh, err);
+               } else
+                       if (nlh->nlmsg_flags & NLM_F_ACK)
+                               netlink_ack(skb, nlh, 0);
+               skb_pull(skb, rlen);
+       }
+
+       return 0;
+}
+
+static void nfnetlink_rcv(struct sock *sk, int len)
+{
+       do {
+               struct sk_buff *skb;
+
+               if (nfnl_shlock_nowait())
+                       return;
+
+               while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
+                       if (nfnetlink_rcv_skb(skb)) {
+                               if (skb->len)
+                                       skb_queue_head(&sk->sk_receive_queue,
+                                                      skb);
+                               else
+                                       kfree_skb(skb);
+                               break;
+                       }
+                       kfree_skb(skb);
+               }
+
+               /* don't call nfnl_shunlock, since it would reenter
+                * with further packet processing */
+               up(&nfnl_sem);
+       } while(nfnl && nfnl->sk_receive_queue.qlen);
+}
+
+static void __exit nfnetlink_exit(void)
+{
+       printk("Removing netfilter NETLINK layer.\n");
+       sock_release(nfnl->sk_socket);
+       return;
+}
+
+static int __init nfnetlink_init(void)
+{
+       printk("Netfilter messages via NETLINK v%s.\n", nfversion);
+
+       nfnl = netlink_kernel_create(NETLINK_NETFILTER, NFNLGRP_MAX,
+                                    nfnetlink_rcv, THIS_MODULE);
+       if (!nfnl) {
+               printk(KERN_ERR "cannot initialize nfnetlink!\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+module_init(nfnetlink_init);
+module_exit(nfnetlink_exit);
+
+EXPORT_SYMBOL_GPL(nfnetlink_subsys_register);
+EXPORT_SYMBOL_GPL(nfnetlink_subsys_unregister);
+EXPORT_SYMBOL_GPL(nfnetlink_send);
+EXPORT_SYMBOL_GPL(nfnetlink_unicast);
+EXPORT_SYMBOL_GPL(nfattr_parse);
+EXPORT_SYMBOL_GPL(__nfa_fill);
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
new file mode 100644 (file)
index 0000000..ff5601c
--- /dev/null
@@ -0,0 +1,1055 @@
+/*
+ * This is a module which is used for logging packets to userspace via
+ * nfetlink.
+ *
+ * (C) 2005 by Harald Welte <laforge@netfilter.org>
+ *
+ * Based on the old ipv4-only ipt_ULOG.c:
+ * (C) 2000-2004 by Harald Welte <laforge@netfilter.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/skbuff.h>
+#include <linux/init.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/netdevice.h>
+#include <linux/netfilter.h>
+#include <linux/netlink.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_log.h>
+#include <linux/spinlock.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/security.h>
+#include <linux/list.h>
+#include <linux/jhash.h>
+#include <linux/random.h>
+#include <net/sock.h>
+
+#include <asm/atomic.h>
+
+#ifdef CONFIG_BRIDGE_NETFILTER
+#include "../bridge/br_private.h"
+#endif
+
+#define NFULNL_NLBUFSIZ_DEFAULT        4096
+#define NFULNL_TIMEOUT_DEFAULT         100     /* every second */
+#define NFULNL_QTHRESH_DEFAULT         100     /* 100 packets */
+
+#define PRINTR(x, args...)     do { if (net_ratelimit()) \
+                                    printk(x, ## args); } while (0);
+
+#if 0
+#define UDEBUG(x, args ...)    printk(KERN_DEBUG "%s(%d):%s(): " x,       \
+                                       __FILE__, __LINE__, __FUNCTION__,  \
+                                       ## args)
+#else
+#define UDEBUG(x, ...)
+#endif
+
+struct nfulnl_instance {
+       struct hlist_node hlist;        /* global list of instances */
+       spinlock_t lock;
+       atomic_t use;                   /* use count */
+
+       unsigned int qlen;              /* number of nlmsgs in skb */
+       struct sk_buff *skb;            /* pre-allocatd skb */
+       struct nlmsghdr *lastnlh;       /* netlink header of last msg in skb */
+       struct timer_list timer;
+       int peer_pid;                   /* PID of the peer process */
+
+       /* configurable parameters */
+       unsigned int flushtimeout;      /* timeout until queue flush */
+       unsigned int nlbufsiz;          /* netlink buffer allocation size */
+       unsigned int qthreshold;        /* threshold of the queue */
+       u_int32_t copy_range;
+       u_int16_t group_num;            /* number of this queue */
+       u_int8_t copy_mode;     
+};
+
+static DEFINE_RWLOCK(instances_lock);
+
+#define INSTANCE_BUCKETS       16
+static struct hlist_head instance_table[INSTANCE_BUCKETS];
+static unsigned int hash_init;
+
+static inline u_int8_t instance_hashfn(u_int16_t group_num)
+{
+       return ((group_num & 0xff) % INSTANCE_BUCKETS);
+}
+
+static struct nfulnl_instance *
+__instance_lookup(u_int16_t group_num)
+{
+       struct hlist_head *head;
+       struct hlist_node *pos;
+       struct nfulnl_instance *inst;
+
+       UDEBUG("entering (group_num=%u)\n", group_num);
+
+       head = &instance_table[instance_hashfn(group_num)];
+       hlist_for_each_entry(inst, pos, head, hlist) {
+               if (inst->group_num == group_num)
+                       return inst;
+       }
+       return NULL;
+}
+
+static inline void
+instance_get(struct nfulnl_instance *inst)
+{
+       atomic_inc(&inst->use);
+}
+
+static struct nfulnl_instance *
+instance_lookup_get(u_int16_t group_num)
+{
+       struct nfulnl_instance *inst;
+
+       read_lock_bh(&instances_lock);
+       inst = __instance_lookup(group_num);
+       if (inst)
+               instance_get(inst);
+       read_unlock_bh(&instances_lock);
+
+       return inst;
+}
+
+static void
+instance_put(struct nfulnl_instance *inst)
+{
+       if (inst && atomic_dec_and_test(&inst->use)) {
+               UDEBUG("kfree(inst=%p)\n", inst);
+               kfree(inst);
+       }
+}
+
+static void nfulnl_timer(unsigned long data);
+
+static struct nfulnl_instance *
+instance_create(u_int16_t group_num, int pid)
+{
+       struct nfulnl_instance *inst;
+
+       UDEBUG("entering (group_num=%u, pid=%d)\n", group_num,
+               pid);
+
+       write_lock_bh(&instances_lock); 
+       if (__instance_lookup(group_num)) {
+               inst = NULL;
+               UDEBUG("aborting, instance already exists\n");
+               goto out_unlock;
+       }
+
+       inst = kmalloc(sizeof(*inst), GFP_ATOMIC);
+       if (!inst)
+               goto out_unlock;
+
+       memset(inst, 0, sizeof(*inst));
+       INIT_HLIST_NODE(&inst->hlist);
+       inst->lock = SPIN_LOCK_UNLOCKED;
+       /* needs to be two, since we _put() after creation */
+       atomic_set(&inst->use, 2);
+
+       init_timer(&inst->timer);
+       inst->timer.function = nfulnl_timer;
+       inst->timer.data = (unsigned long)inst;
+       /* don't start timer yet. (re)start it  with every packet */
+
+       inst->peer_pid = pid;
+       inst->group_num = group_num;
+
+       inst->qthreshold        = NFULNL_QTHRESH_DEFAULT;
+       inst->flushtimeout      = NFULNL_TIMEOUT_DEFAULT;
+       inst->nlbufsiz          = NFULNL_NLBUFSIZ_DEFAULT;
+       inst->copy_mode         = NFULNL_COPY_PACKET;
+       inst->copy_range        = 0xffff;
+
+       if (!try_module_get(THIS_MODULE))
+               goto out_free;
+
+       hlist_add_head(&inst->hlist, 
+                      &instance_table[instance_hashfn(group_num)]);
+
+       UDEBUG("newly added node: %p, next=%p\n", &inst->hlist, 
+               inst->hlist.next);
+
+       write_unlock_bh(&instances_lock);
+
+       return inst;
+
+out_free:
+       instance_put(inst);
+out_unlock:
+       write_unlock_bh(&instances_lock);
+       return NULL;
+}
+
+static int __nfulnl_send(struct nfulnl_instance *inst);
+
+static void
+_instance_destroy2(struct nfulnl_instance *inst, int lock)
+{
+       /* first pull it out of the global list */
+       if (lock)
+               write_lock_bh(&instances_lock);
+
+       UDEBUG("removing instance %p (queuenum=%u) from hash\n",
+               inst, inst->group_num);
+
+       hlist_del(&inst->hlist);
+
+       if (lock)
+               write_unlock_bh(&instances_lock);
+
+       /* then flush all pending packets from skb */
+
+       spin_lock_bh(&inst->lock);
+       if (inst->skb) {
+               if (inst->qlen)
+                       __nfulnl_send(inst);
+               if (inst->skb) {
+                       kfree_skb(inst->skb);
+                       inst->skb = NULL;
+               }
+       }
+       spin_unlock_bh(&inst->lock);
+
+       /* and finally put the refcount */
+       instance_put(inst);
+
+       module_put(THIS_MODULE);
+}
+
+static inline void
+__instance_destroy(struct nfulnl_instance *inst)
+{
+       _instance_destroy2(inst, 0);
+}
+
+static inline void
+instance_destroy(struct nfulnl_instance *inst)
+{
+       _instance_destroy2(inst, 1);
+}
+
+static int
+nfulnl_set_mode(struct nfulnl_instance *inst, u_int8_t mode,
+                 unsigned int range)
+{
+       int status = 0;
+
+       spin_lock_bh(&inst->lock);
+       
+       switch (mode) {
+       case NFULNL_COPY_NONE:
+       case NFULNL_COPY_META:
+               inst->copy_mode = mode;
+               inst->copy_range = 0;
+               break;
+               
+       case NFULNL_COPY_PACKET:
+               inst->copy_mode = mode;
+               /* we're using struct nfattr which has 16bit nfa_len */
+               if (range > 0xffff)
+                       inst->copy_range = 0xffff;
+               else
+                       inst->copy_range = range;
+               break;
+               
+       default:
+               status = -EINVAL;
+               break;
+       }
+
+       spin_unlock_bh(&inst->lock);
+
+       return status;
+}
+
+static int
+nfulnl_set_nlbufsiz(struct nfulnl_instance *inst, u_int32_t nlbufsiz)
+{
+       int status;
+
+       spin_lock_bh(&inst->lock);
+       if (nlbufsiz < NFULNL_NLBUFSIZ_DEFAULT)
+               status = -ERANGE;
+       else if (nlbufsiz > 131072)
+               status = -ERANGE;
+       else {
+               inst->nlbufsiz = nlbufsiz;
+               status = 0;
+       }
+       spin_unlock_bh(&inst->lock);
+
+       return status;
+}
+
+static int
+nfulnl_set_timeout(struct nfulnl_instance *inst, u_int32_t timeout)
+{
+       spin_lock_bh(&inst->lock);
+       inst->flushtimeout = timeout;
+       spin_unlock_bh(&inst->lock);
+
+       return 0;
+}
+
+static int
+nfulnl_set_qthresh(struct nfulnl_instance *inst, u_int32_t qthresh)
+{
+       spin_lock_bh(&inst->lock);
+       inst->qthreshold = qthresh;
+       spin_unlock_bh(&inst->lock);
+
+       return 0;
+}
+
+static struct sk_buff *nfulnl_alloc_skb(unsigned int inst_size, 
+                                       unsigned int pkt_size)
+{
+       struct sk_buff *skb;
+
+       UDEBUG("entered (%u, %u)\n", inst_size, pkt_size);
+
+       /* alloc skb which should be big enough for a whole multipart
+        * message.  WARNING: has to be <= 128k due to slab restrictions */
+
+       skb = alloc_skb(inst_size, GFP_ATOMIC);
+       if (!skb) {
+               PRINTR("nfnetlink_log: can't alloc whole buffer (%u bytes)\n",
+                       inst_size);
+
+               /* try to allocate only as much as we need for current
+                * packet */
+
+               skb = alloc_skb(pkt_size, GFP_ATOMIC);
+               if (!skb)
+                       PRINTR("nfnetlink_log: can't even alloc %u bytes\n",
+                               pkt_size);
+       }
+
+       return skb;
+}
+
+static int
+__nfulnl_send(struct nfulnl_instance *inst)
+{
+       int status;
+
+       if (timer_pending(&inst->timer))
+               del_timer(&inst->timer);
+
+       if (inst->qlen > 1)
+               inst->lastnlh->nlmsg_type = NLMSG_DONE;
+
+       status = nfnetlink_unicast(inst->skb, inst->peer_pid, MSG_DONTWAIT);
+       if (status < 0) {
+               UDEBUG("netlink_unicast() failed\n");
+               /* FIXME: statistics */
+       }
+
+       inst->qlen = 0;
+       inst->skb = NULL;
+       inst->lastnlh = NULL;
+
+       return status;
+}
+
+static void nfulnl_timer(unsigned long data)
+{
+       struct nfulnl_instance *inst = (struct nfulnl_instance *)data; 
+
+       UDEBUG("timer function called, flushing buffer\n");
+
+       spin_lock_bh(&inst->lock);
+       __nfulnl_send(inst);
+       instance_put(inst);
+       spin_unlock_bh(&inst->lock);
+}
+
+static inline int 
+__build_packet_message(struct nfulnl_instance *inst,
+                       const struct sk_buff *skb, 
+                       unsigned int data_len,
+                       unsigned int pf,
+                       unsigned int hooknum,
+                       const struct net_device *indev,
+                       const struct net_device *outdev,
+                       const struct nf_loginfo *li,
+                       const char *prefix)
+{
+       unsigned char *old_tail;
+       struct nfulnl_msg_packet_hdr pmsg;
+       struct nlmsghdr *nlh;
+       struct nfgenmsg *nfmsg;
+       u_int32_t tmp_uint;
+
+       UDEBUG("entered\n");
+               
+       old_tail = inst->skb->tail;
+       nlh = NLMSG_PUT(inst->skb, 0, 0, 
+                       NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET,
+                       sizeof(struct nfgenmsg));
+       nfmsg = NLMSG_DATA(nlh);
+       nfmsg->nfgen_family = pf;
+       nfmsg->version = NFNETLINK_V0;
+       nfmsg->res_id = htons(inst->group_num);
+
+       pmsg.hw_protocol        = htons(skb->protocol);
+       pmsg.hook               = hooknum;
+
+       NFA_PUT(inst->skb, NFULA_PACKET_HDR, sizeof(pmsg), &pmsg);
+
+       if (prefix) {
+               int slen = strlen(prefix);
+               if (slen > NFULNL_PREFIXLEN)
+                       slen = NFULNL_PREFIXLEN;
+               NFA_PUT(inst->skb, NFULA_PREFIX, slen, prefix);
+       }
+
+       if (indev) {
+               tmp_uint = htonl(indev->ifindex);
+#ifndef CONFIG_BRIDGE_NETFILTER
+               NFA_PUT(inst->skb, NFULA_IFINDEX_INDEV, sizeof(tmp_uint),
+                       &tmp_uint);
+#else
+               if (pf == PF_BRIDGE) {
+                       /* Case 1: outdev is physical input device, we need to
+                        * look for bridge group (when called from
+                        * netfilter_bridge) */
+                       NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV,
+                               sizeof(tmp_uint), &tmp_uint);
+                       /* this is the bridge group "brX" */
+                       tmp_uint = htonl(indev->br_port->br->dev->ifindex);
+                       NFA_PUT(inst->skb, NFULA_IFINDEX_INDEV,
+                               sizeof(tmp_uint), &tmp_uint);
+               } else {
+                       /* Case 2: indev is bridge group, we need to look for
+                        * physical device (when called from ipv4) */
+                       NFA_PUT(inst->skb, NFULA_IFINDEX_INDEV,
+                               sizeof(tmp_uint), &tmp_uint);
+                       if (skb->nf_bridge && skb->nf_bridge->physindev) {
+                               tmp_uint = 
+                                   htonl(skb->nf_bridge->physindev->ifindex);
+                               NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV,
+                                       sizeof(tmp_uint), &tmp_uint);
+                       }
+               }
+#endif
+       }
+
+       if (outdev) {
+               tmp_uint = htonl(outdev->ifindex);
+#ifndef CONFIG_BRIDGE_NETFILTER
+               NFA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV, sizeof(tmp_uint),
+                       &tmp_uint);
+#else
+               if (pf == PF_BRIDGE) {
+                       /* Case 1: outdev is physical output device, we need to
+                        * look for bridge group (when called from
+                        * netfilter_bridge) */
+                       NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
+                               sizeof(tmp_uint), &tmp_uint);
+                       /* this is the bridge group "brX" */
+                       tmp_uint = htonl(outdev->br_port->br->dev->ifindex);
+                       NFA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV,
+                               sizeof(tmp_uint), &tmp_uint);
+               } else {
+                       /* Case 2: indev is a bridge group, we need to look
+                        * for physical device (when called from ipv4) */
+                       NFA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV,
+                               sizeof(tmp_uint), &tmp_uint);
+                       if (skb->nf_bridge) {
+                               tmp_uint = 
+                                   htonl(skb->nf_bridge->physoutdev->ifindex);
+                               NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
+                                       sizeof(tmp_uint), &tmp_uint);
+                       }
+               }
+#endif
+       }
+
+       if (skb->nfmark) {
+               tmp_uint = htonl(skb->nfmark);
+               NFA_PUT(inst->skb, NFULA_MARK, sizeof(tmp_uint), &tmp_uint);
+       }
+
+       if (indev && skb->dev && skb->dev->hard_header_parse) {
+               struct nfulnl_msg_packet_hw phw;
+
+               phw.hw_addrlen = 
+                       skb->dev->hard_header_parse((struct sk_buff *)skb, 
+                                                   phw.hw_addr);
+               phw.hw_addrlen = htons(phw.hw_addrlen);
+               NFA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw);
+       }
+
+       if (skb->tstamp.off_sec) {
+               struct nfulnl_msg_packet_timestamp ts;
+
+               ts.sec = cpu_to_be64(skb_tv_base.tv_sec + skb->tstamp.off_sec);
+               ts.usec = cpu_to_be64(skb_tv_base.tv_usec + skb->tstamp.off_usec);
+
+               NFA_PUT(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts);
+       }
+
+       /* UID */
+       if (skb->sk) {
+               read_lock_bh(&skb->sk->sk_callback_lock);
+               if (skb->sk->sk_socket && skb->sk->sk_socket->file) {
+                       u_int32_t uid = htonl(skb->sk->sk_socket->file->f_uid);
+                       /* need to unlock here since NFA_PUT may goto */
+                       read_unlock_bh(&skb->sk->sk_callback_lock);
+                       NFA_PUT(inst->skb, NFULA_UID, sizeof(uid), &uid);
+               } else
+                       read_unlock_bh(&skb->sk->sk_callback_lock);
+       }
+
+       if (data_len) {
+               struct nfattr *nfa;
+               int size = NFA_LENGTH(data_len);
+
+               if (skb_tailroom(inst->skb) < (int)NFA_SPACE(data_len)) {
+                       printk(KERN_WARNING "nfnetlink_log: no tailroom!\n");
+                       goto nlmsg_failure;
+               }
+
+               nfa = (struct nfattr *)skb_put(inst->skb, NFA_ALIGN(size));
+               nfa->nfa_type = NFULA_PAYLOAD;
+               nfa->nfa_len = size;
+
+               if (skb_copy_bits(skb, 0, NFA_DATA(nfa), data_len))
+                       BUG();
+       }
+               
+       nlh->nlmsg_len = inst->skb->tail - old_tail;
+       return 0;
+
+nlmsg_failure:
+       UDEBUG("nlmsg_failure\n");
+nfattr_failure:
+       PRINTR(KERN_ERR "nfnetlink_log: error creating log nlmsg\n");
+       return -1;
+}
+
+#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
+
+static struct nf_loginfo default_loginfo = {
+       .type =         NF_LOG_TYPE_ULOG,
+       .u = {
+               .ulog = {
+                       .copy_len       = 0xffff,
+                       .group          = 0,
+                       .qthreshold     = 1,
+               },
+       },
+};
+
+/* log handler for internal netfilter logging api */
+static void
+nfulnl_log_packet(unsigned int pf,
+                 unsigned int hooknum,
+                 const struct sk_buff *skb,
+                 const struct net_device *in,
+                 const struct net_device *out,
+                 const struct nf_loginfo *li_user,
+                 const char *prefix)
+{
+       unsigned int size, data_len;
+       struct nfulnl_instance *inst;
+       const struct nf_loginfo *li;
+       unsigned int qthreshold;
+       unsigned int nlbufsiz;
+
+       if (li_user && li_user->type == NF_LOG_TYPE_ULOG) 
+               li = li_user;
+       else
+               li = &default_loginfo;
+
+       inst = instance_lookup_get(li->u.ulog.group);
+       if (!inst)
+               inst = instance_lookup_get(0);
+       if (!inst) {
+               PRINTR("nfnetlink_log: trying to log packet, "
+                       "but no instance for group %u\n", li->u.ulog.group);
+               return;
+       }
+
+       /* all macros expand to constant values at compile time */
+       /* FIXME: do we want to make the size calculation conditional based on
+        * what is actually present?  way more branches and checks, but more
+        * memory efficient... */
+       size =    NLMSG_SPACE(sizeof(struct nfgenmsg))
+               + NFA_SPACE(sizeof(struct nfulnl_msg_packet_hdr))
+               + NFA_SPACE(sizeof(u_int32_t))  /* ifindex */
+               + NFA_SPACE(sizeof(u_int32_t))  /* ifindex */
+#ifdef CONFIG_BRIDGE_NETFILTER
+               + NFA_SPACE(sizeof(u_int32_t))  /* ifindex */
+               + NFA_SPACE(sizeof(u_int32_t))  /* ifindex */
+#endif
+               + NFA_SPACE(sizeof(u_int32_t))  /* mark */
+               + NFA_SPACE(sizeof(u_int32_t))  /* uid */
+               + NFA_SPACE(NFULNL_PREFIXLEN)   /* prefix */
+               + NFA_SPACE(sizeof(struct nfulnl_msg_packet_hw))
+               + NFA_SPACE(sizeof(struct nfulnl_msg_packet_timestamp));
+
+       UDEBUG("initial size=%u\n", size);
+
+       spin_lock_bh(&inst->lock);
+
+       qthreshold = inst->qthreshold;
+       /* per-rule qthreshold overrides per-instance */
+       if (qthreshold > li->u.ulog.qthreshold)
+               qthreshold = li->u.ulog.qthreshold;
+       
+       switch (inst->copy_mode) {
+       case NFULNL_COPY_META:
+       case NFULNL_COPY_NONE:
+               data_len = 0;
+               break;
+       
+       case NFULNL_COPY_PACKET:
+               if (inst->copy_range == 0 
+                   || inst->copy_range > skb->len)
+                       data_len = skb->len;
+               else
+                       data_len = inst->copy_range;
+               
+               size += NFA_SPACE(data_len);
+               UDEBUG("copy_packet, therefore size now %u\n", size);
+               break;
+       
+       default:
+               spin_unlock_bh(&inst->lock);
+               instance_put(inst);
+               return;
+       }
+
+       if (size > inst->nlbufsiz)
+               nlbufsiz = size;
+       else
+               nlbufsiz = inst->nlbufsiz;
+
+       if (!inst->skb) {
+               if (!(inst->skb = nfulnl_alloc_skb(nlbufsiz, size))) {
+                       UDEBUG("error in nfulnl_alloc_skb(%u, %u)\n",
+                               inst->nlbufsiz, size);
+                       goto alloc_failure;
+               }
+       } else if (inst->qlen >= qthreshold ||
+                  size > skb_tailroom(inst->skb)) {
+               /* either the queue len is too high or we don't have
+                * enough room in the skb left. flush to userspace. */
+               UDEBUG("flushing old skb\n");
+
+               __nfulnl_send(inst);
+
+               if (!(inst->skb = nfulnl_alloc_skb(nlbufsiz, size))) {
+                       UDEBUG("error in nfulnl_alloc_skb(%u, %u)\n",
+                               inst->nlbufsiz, size);
+                       goto alloc_failure;
+               }
+       }
+
+       UDEBUG("qlen %d, qthreshold %d\n", inst->qlen, qthreshold);
+       inst->qlen++;
+
+       __build_packet_message(inst, skb, data_len, pf,
+                               hooknum, in, out, li, prefix);
+
+       /* timer_pending always called within inst->lock, so there
+        * is no chance of a race here */
+       if (!timer_pending(&inst->timer)) {
+               instance_get(inst);
+               inst->timer.expires = jiffies + (inst->flushtimeout*HZ/100);
+               add_timer(&inst->timer);
+       }
+       spin_unlock_bh(&inst->lock);
+
+       return;
+
+alloc_failure:
+       spin_unlock_bh(&inst->lock);
+       instance_put(inst);
+       UDEBUG("error allocating skb\n");
+       /* FIXME: statistics */
+}
+
+static int
+nfulnl_rcv_nl_event(struct notifier_block *this,
+                  unsigned long event, void *ptr)
+{
+       struct netlink_notify *n = ptr;
+
+       if (event == NETLINK_URELEASE &&
+           n->protocol == NETLINK_NETFILTER && n->pid) {
+               int i;
+
+               /* destroy all instances for this pid */
+               write_lock_bh(&instances_lock);
+               for  (i = 0; i < INSTANCE_BUCKETS; i++) {
+                       struct hlist_node *tmp, *t2;
+                       struct nfulnl_instance *inst;
+                       struct hlist_head *head = &instance_table[i];
+
+                       hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) {
+                               UDEBUG("node = %p\n", inst);
+                               if (n->pid == inst->peer_pid)
+                                       __instance_destroy(inst);
+                       }
+               }
+               write_unlock_bh(&instances_lock);
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block nfulnl_rtnl_notifier = {
+       .notifier_call  = nfulnl_rcv_nl_event,
+};
+
+static int
+nfulnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
+                 struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp)
+{
+       return -ENOTSUPP;
+}
+
+static struct nf_logger nfulnl_logger = {
+       .name   = "nfnetlink_log",
+       .logfn  = &nfulnl_log_packet,
+       .me     = THIS_MODULE,
+};
+
+static const int nfula_min[NFULA_MAX] = {
+       [NFULA_PACKET_HDR-1]    = sizeof(struct nfulnl_msg_packet_hdr),
+       [NFULA_MARK-1]          = sizeof(u_int32_t),
+       [NFULA_TIMESTAMP-1]     = sizeof(struct nfulnl_msg_packet_timestamp),
+       [NFULA_IFINDEX_INDEV-1] = sizeof(u_int32_t),
+       [NFULA_IFINDEX_OUTDEV-1]= sizeof(u_int32_t),
+       [NFULA_HWADDR-1]        = sizeof(struct nfulnl_msg_packet_hw),
+       [NFULA_PAYLOAD-1]       = 0,
+       [NFULA_PREFIX-1]        = 0,
+       [NFULA_UID-1]           = sizeof(u_int32_t),
+};
+
+static const int nfula_cfg_min[NFULA_CFG_MAX] = {
+       [NFULA_CFG_CMD-1]       = sizeof(struct nfulnl_msg_config_cmd),
+       [NFULA_CFG_MODE-1]      = sizeof(struct nfulnl_msg_config_mode),
+       [NFULA_CFG_TIMEOUT-1]   = sizeof(u_int32_t),
+       [NFULA_CFG_QTHRESH-1]   = sizeof(u_int32_t),
+       [NFULA_CFG_NLBUFSIZ-1]  = sizeof(u_int32_t),
+};
+
+static int
+nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
+                  struct nlmsghdr *nlh, struct nfattr *nfula[], int *errp)
+{
+       struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
+       u_int16_t group_num = ntohs(nfmsg->res_id);
+       struct nfulnl_instance *inst;
+       int ret = 0;
+
+       UDEBUG("entering for msg %u\n", NFNL_MSG_TYPE(nlh->nlmsg_type));
+
+       if (nfattr_bad_size(nfula, NFULA_CFG_MAX, nfula_cfg_min)) {
+               UDEBUG("bad attribute size\n");
+               return -EINVAL;
+       }
+
+       inst = instance_lookup_get(group_num);
+       if (nfula[NFULA_CFG_CMD-1]) {
+               u_int8_t pf = nfmsg->nfgen_family;
+               struct nfulnl_msg_config_cmd *cmd;
+               cmd = NFA_DATA(nfula[NFULA_CFG_CMD-1]);
+               UDEBUG("found CFG_CMD for\n");
+
+               switch (cmd->command) {
+               case NFULNL_CFG_CMD_BIND:
+                       if (inst) {
+                               ret = -EBUSY;
+                               goto out_put;
+                       }
+
+                       inst = instance_create(group_num,
+                                              NETLINK_CB(skb).pid);
+                       if (!inst) {
+                               ret = -EINVAL;
+                               goto out_put;
+                       }
+                       break;
+               case NFULNL_CFG_CMD_UNBIND:
+                       if (!inst) {
+                               ret = -ENODEV;
+                               goto out_put;
+                       }
+
+                       if (inst->peer_pid != NETLINK_CB(skb).pid) {
+                               ret = -EPERM;
+                               goto out_put;
+                       }
+
+                       instance_destroy(inst);
+                       break;
+               case NFULNL_CFG_CMD_PF_BIND:
+                       UDEBUG("registering log handler for pf=%u\n", pf);
+                       ret = nf_log_register(pf, &nfulnl_logger);
+                       break;
+               case NFULNL_CFG_CMD_PF_UNBIND:
+                       UDEBUG("unregistering log handler for pf=%u\n", pf);
+                       /* This is a bug and a feature.  We cannot unregister
+                        * other handlers, like nfnetlink_inst can */
+                       nf_log_unregister_pf(pf);
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+       } else {
+               if (!inst) {
+                       UDEBUG("no config command, and no instance for "
+                               "group=%u pid=%u =>ENOENT\n",
+                               group_num, NETLINK_CB(skb).pid);
+                       ret = -ENOENT;
+                       goto out_put;
+               }
+
+               if (inst->peer_pid != NETLINK_CB(skb).pid) {
+                       UDEBUG("no config command, and wrong pid\n");
+                       ret = -EPERM;
+                       goto out_put;
+               }
+       }
+
+       if (nfula[NFULA_CFG_MODE-1]) {
+               struct nfulnl_msg_config_mode *params;
+               params = NFA_DATA(nfula[NFULA_CFG_MODE-1]);
+
+               nfulnl_set_mode(inst, params->copy_mode,
+                               ntohs(params->copy_range));
+       }
+
+       if (nfula[NFULA_CFG_TIMEOUT-1]) {
+               u_int32_t timeout = 
+                       *(u_int32_t *)NFA_DATA(nfula[NFULA_CFG_TIMEOUT-1]);
+
+               nfulnl_set_timeout(inst, ntohl(timeout));
+       }
+
+       if (nfula[NFULA_CFG_NLBUFSIZ-1]) {
+               u_int32_t nlbufsiz = 
+                       *(u_int32_t *)NFA_DATA(nfula[NFULA_CFG_NLBUFSIZ-1]);
+
+               nfulnl_set_nlbufsiz(inst, ntohl(nlbufsiz));
+       }
+
+       if (nfula[NFULA_CFG_QTHRESH-1]) {
+               u_int32_t qthresh = 
+                       *(u_int16_t *)NFA_DATA(nfula[NFULA_CFG_QTHRESH-1]);
+
+               nfulnl_set_qthresh(inst, ntohl(qthresh));
+       }
+
+out_put:
+       instance_put(inst);
+       return ret;
+}
+
+static struct nfnl_callback nfulnl_cb[NFULNL_MSG_MAX] = {
+       [NFULNL_MSG_PACKET]     = { .call = nfulnl_recv_unsupp,
+                                   .attr_count = NFULA_MAX,
+                                   .cap_required = CAP_NET_ADMIN, },
+       [NFULNL_MSG_CONFIG]     = { .call = nfulnl_recv_config,
+                                   .attr_count = NFULA_CFG_MAX,
+                                   .cap_required = CAP_NET_ADMIN },
+};
+
+static struct nfnetlink_subsystem nfulnl_subsys = {
+       .name           = "log",
+       .subsys_id      = NFNL_SUBSYS_ULOG,
+       .cb_count       = NFULNL_MSG_MAX,
+       .cb             = nfulnl_cb,
+};
+
+#ifdef CONFIG_PROC_FS
+struct iter_state {
+       unsigned int bucket;
+};
+
+static struct hlist_node *get_first(struct seq_file *seq)
+{
+       struct iter_state *st = seq->private;
+
+       if (!st)
+               return NULL;
+
+       for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) {
+               if (!hlist_empty(&instance_table[st->bucket]))
+                       return instance_table[st->bucket].first;
+       }
+       return NULL;
+}
+
+static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h)
+{
+       struct iter_state *st = seq->private;
+
+       h = h->next;
+       while (!h) {
+               if (++st->bucket >= INSTANCE_BUCKETS)
+                       return NULL;
+
+               h = instance_table[st->bucket].first;
+       }
+       return h;
+}
+
+static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos)
+{
+       struct hlist_node *head;
+       head = get_first(seq);
+
+       if (head)
+               while (pos && (head = get_next(seq, head)))
+                       pos--;
+       return pos ? NULL : head;
+}
+
+static void *seq_start(struct seq_file *seq, loff_t *pos)
+{
+       read_lock_bh(&instances_lock);
+       return get_idx(seq, *pos);
+}
+
+static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       (*pos)++;
+       return get_next(s, v);
+}
+
+static void seq_stop(struct seq_file *s, void *v)
+{
+       read_unlock_bh(&instances_lock);
+}
+
+static int seq_show(struct seq_file *s, void *v)
+{
+       const struct nfulnl_instance *inst = v;
+
+       return seq_printf(s, "%5d %6d %5d %1d %5d %6d %2d\n", 
+                         inst->group_num,
+                         inst->peer_pid, inst->qlen, 
+                         inst->copy_mode, inst->copy_range,
+                         inst->flushtimeout, atomic_read(&inst->use));
+}
+
+static struct seq_operations nful_seq_ops = {
+       .start  = seq_start,
+       .next   = seq_next,
+       .stop   = seq_stop,
+       .show   = seq_show,
+};
+
+static int nful_open(struct inode *inode, struct file *file)
+{
+       struct seq_file *seq;
+       struct iter_state *is;
+       int ret;
+
+       is = kmalloc(sizeof(*is), GFP_KERNEL);
+       if (!is)
+               return -ENOMEM;
+       memset(is, 0, sizeof(*is));
+       ret = seq_open(file, &nful_seq_ops);
+       if (ret < 0)
+               goto out_free;
+       seq = file->private_data;
+       seq->private = is;
+       return ret;
+out_free:
+       kfree(is);
+       return ret;
+}
+
+static struct file_operations nful_file_ops = {
+       .owner   = THIS_MODULE,
+       .open    = nful_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release_private,
+};
+
+#endif /* PROC_FS */
+
+static int
+init_or_cleanup(int init)
+{
+       int i, status = -ENOMEM;
+#ifdef CONFIG_PROC_FS
+       struct proc_dir_entry *proc_nful;
+#endif
+       
+       if (!init)
+               goto cleanup;
+
+       for (i = 0; i < INSTANCE_BUCKETS; i++)
+               INIT_HLIST_HEAD(&instance_table[i]);
+       
+       /* it's not really all that important to have a random value, so
+        * we can do this from the init function, even if there hasn't
+        * been that much entropy yet */
+       get_random_bytes(&hash_init, sizeof(hash_init));
+
+       netlink_register_notifier(&nfulnl_rtnl_notifier);
+       status = nfnetlink_subsys_register(&nfulnl_subsys);
+       if (status < 0) {
+               printk(KERN_ERR "log: failed to create netlink socket\n");
+               goto cleanup_netlink_notifier;
+       }
+
+#ifdef CONFIG_PROC_FS
+       proc_nful = create_proc_entry("nfnetlink_log", 0440,
+                                     proc_net_netfilter);
+       if (!proc_nful)
+               goto cleanup_subsys;
+       proc_nful->proc_fops = &nful_file_ops;
+#endif
+
+       return status;
+
+cleanup:
+       nf_log_unregister_logger(&nfulnl_logger);
+#ifdef CONFIG_PROC_FS
+       remove_proc_entry("nfnetlink_log", proc_net_netfilter);
+cleanup_subsys:
+#endif
+       nfnetlink_subsys_unregister(&nfulnl_subsys);
+cleanup_netlink_notifier:
+       netlink_unregister_notifier(&nfulnl_rtnl_notifier);
+       return status;
+}
+
+static int __init init(void)
+{
+       
+       return init_or_cleanup(1);
+}
+
+static void __exit fini(void)
+{
+       init_or_cleanup(0);
+}
+
+MODULE_DESCRIPTION("netfilter userspace logging");
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_ULOG);
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
new file mode 100644 (file)
index 0000000..f81fe8c
--- /dev/null
@@ -0,0 +1,1127 @@
+/*
+ * This is a module which is used for queueing packets and communicating with
+ * userspace via nfetlink.
+ *
+ * (C) 2005 by Harald Welte <laforge@netfilter.org>
+ *
+ * Based on the old ipv4-only ip_queue.c:
+ * (C) 2000-2002 James Morris <jmorris@intercode.com.au>
+ * (C) 2003-2005 Netfilter Core Team <coreteam@netfilter.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/skbuff.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/notifier.h>
+#include <linux/netdevice.h>
+#include <linux/netfilter.h>
+#include <linux/proc_fs.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_queue.h>
+#include <linux/list.h>
+#include <net/sock.h>
+
+#include <asm/atomic.h>
+
+#ifdef CONFIG_BRIDGE_NETFILTER
+#include "../bridge/br_private.h"
+#endif
+
+#define NFQNL_QMAX_DEFAULT 1024
+
+#if 0
+#define QDEBUG(x, args ...)    printk(KERN_DEBUG "%s(%d):%s(): " x,       \
+                                       __FILE__, __LINE__, __FUNCTION__,  \
+                                       ## args)
+#else
+#define QDEBUG(x, ...)
+#endif
+
+struct nfqnl_queue_entry {
+       struct list_head list;
+       struct nf_info *info;
+       struct sk_buff *skb;
+       unsigned int id;
+};
+
+struct nfqnl_instance {
+       struct hlist_node hlist;                /* global list of queues */
+       atomic_t use;
+
+       int peer_pid;
+       unsigned int queue_maxlen;
+       unsigned int copy_range;
+       unsigned int queue_total;
+       unsigned int queue_dropped;
+       unsigned int queue_user_dropped;
+
+       atomic_t id_sequence;                   /* 'sequence' of pkt ids */
+
+       u_int16_t queue_num;                    /* number of this queue */
+       u_int8_t copy_mode;
+
+       spinlock_t lock;
+
+       struct list_head queue_list;            /* packets in queue */
+};
+
+typedef int (*nfqnl_cmpfn)(struct nfqnl_queue_entry *, unsigned long);
+
+static DEFINE_RWLOCK(instances_lock);
+
+#define INSTANCE_BUCKETS       16
+static struct hlist_head instance_table[INSTANCE_BUCKETS];
+
+static inline u_int8_t instance_hashfn(u_int16_t queue_num)
+{
+       return ((queue_num >> 8) | queue_num) % INSTANCE_BUCKETS;
+}
+
+static struct nfqnl_instance *
+__instance_lookup(u_int16_t queue_num)
+{
+       struct hlist_head *head;
+       struct hlist_node *pos;
+       struct nfqnl_instance *inst;
+
+       head = &instance_table[instance_hashfn(queue_num)];
+       hlist_for_each_entry(inst, pos, head, hlist) {
+               if (inst->queue_num == queue_num)
+                       return inst;
+       }
+       return NULL;
+}
+
+static struct nfqnl_instance *
+instance_lookup_get(u_int16_t queue_num)
+{
+       struct nfqnl_instance *inst;
+
+       read_lock_bh(&instances_lock);
+       inst = __instance_lookup(queue_num);
+       if (inst)
+               atomic_inc(&inst->use);
+       read_unlock_bh(&instances_lock);
+
+       return inst;
+}
+
+static void
+instance_put(struct nfqnl_instance *inst)
+{
+       if (inst && atomic_dec_and_test(&inst->use)) {
+               QDEBUG("kfree(inst=%p)\n", inst);
+               kfree(inst);
+       }
+}
+
+static struct nfqnl_instance *
+instance_create(u_int16_t queue_num, int pid)
+{
+       struct nfqnl_instance *inst;
+
+       QDEBUG("entering for queue_num=%u, pid=%d\n", queue_num, pid);
+
+       write_lock_bh(&instances_lock); 
+       if (__instance_lookup(queue_num)) {
+               inst = NULL;
+               QDEBUG("aborting, instance already exists\n");
+               goto out_unlock;
+       }
+
+       inst = kmalloc(sizeof(*inst), GFP_ATOMIC);
+       if (!inst)
+               goto out_unlock;
+
+       memset(inst, 0, sizeof(*inst));
+       inst->queue_num = queue_num;
+       inst->peer_pid = pid;
+       inst->queue_maxlen = NFQNL_QMAX_DEFAULT;
+       inst->copy_range = 0xfffff;
+       inst->copy_mode = NFQNL_COPY_NONE;
+       atomic_set(&inst->id_sequence, 0);
+       /* needs to be two, since we _put() after creation */
+       atomic_set(&inst->use, 2);
+       inst->lock = SPIN_LOCK_UNLOCKED;
+       INIT_LIST_HEAD(&inst->queue_list);
+
+       if (!try_module_get(THIS_MODULE))
+               goto out_free;
+
+       hlist_add_head(&inst->hlist, 
+                      &instance_table[instance_hashfn(queue_num)]);
+
+       write_unlock_bh(&instances_lock);
+
+       QDEBUG("successfully created new instance\n");
+
+       return inst;
+
+out_free:
+       kfree(inst);
+out_unlock:
+       write_unlock_bh(&instances_lock);
+       return NULL;
+}
+
+static void nfqnl_flush(struct nfqnl_instance *queue, int verdict);
+
+static void
+_instance_destroy2(struct nfqnl_instance *inst, int lock)
+{
+       /* first pull it out of the global list */
+       if (lock)
+               write_lock_bh(&instances_lock);
+
+       QDEBUG("removing instance %p (queuenum=%u) from hash\n",
+               inst, inst->queue_num);
+       hlist_del(&inst->hlist);
+
+       if (lock)
+               write_unlock_bh(&instances_lock);
+
+       /* then flush all pending skbs from the queue */
+       nfqnl_flush(inst, NF_DROP);
+
+       /* and finally put the refcount */
+       instance_put(inst);
+
+       module_put(THIS_MODULE);
+}
+
+static inline void
+__instance_destroy(struct nfqnl_instance *inst)
+{
+       _instance_destroy2(inst, 0);
+}
+
+static inline void
+instance_destroy(struct nfqnl_instance *inst)
+{
+       _instance_destroy2(inst, 1);
+}
+
+
+
+static void
+issue_verdict(struct nfqnl_queue_entry *entry, int verdict)
+{
+       QDEBUG("entering for entry %p, verdict %u\n", entry, verdict);
+
+       /* TCP input path (and probably other bits) assume to be called
+        * from softirq context, not from syscall, like issue_verdict is
+        * called.  TCP input path deadlocks with locks taken from timer
+        * softirq, e.g.  We therefore emulate this by local_bh_disable() */
+
+       local_bh_disable();
+       nf_reinject(entry->skb, entry->info, verdict);
+       local_bh_enable();
+
+       kfree(entry);
+}
+
+static inline void
+__enqueue_entry(struct nfqnl_instance *queue,
+                     struct nfqnl_queue_entry *entry)
+{
+       list_add(&entry->list, &queue->queue_list);
+       queue->queue_total++;
+}
+
+/*
+ * Find and return a queued entry matched by cmpfn, or return the last
+ * entry if cmpfn is NULL.
+ */
+static inline struct nfqnl_queue_entry *
+__find_entry(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, 
+                  unsigned long data)
+{
+       struct list_head *p;
+
+       list_for_each_prev(p, &queue->queue_list) {
+               struct nfqnl_queue_entry *entry = (struct nfqnl_queue_entry *)p;
+               
+               if (!cmpfn || cmpfn(entry, data))
+                       return entry;
+       }
+       return NULL;
+}
+
+static inline void
+__dequeue_entry(struct nfqnl_instance *q, struct nfqnl_queue_entry *entry)
+{
+       list_del(&entry->list);
+       q->queue_total--;
+}
+
+static inline struct nfqnl_queue_entry *
+__find_dequeue_entry(struct nfqnl_instance *queue,
+                    nfqnl_cmpfn cmpfn, unsigned long data)
+{
+       struct nfqnl_queue_entry *entry;
+
+       entry = __find_entry(queue, cmpfn, data);
+       if (entry == NULL)
+               return NULL;
+
+       __dequeue_entry(queue, entry);
+       return entry;
+}
+
+
+static inline void
+__nfqnl_flush(struct nfqnl_instance *queue, int verdict)
+{
+       struct nfqnl_queue_entry *entry;
+       
+       while ((entry = __find_dequeue_entry(queue, NULL, 0)))
+               issue_verdict(entry, verdict);
+}
+
+static inline int
+__nfqnl_set_mode(struct nfqnl_instance *queue,
+                unsigned char mode, unsigned int range)
+{
+       int status = 0;
+       
+       switch (mode) {
+       case NFQNL_COPY_NONE:
+       case NFQNL_COPY_META:
+               queue->copy_mode = mode;
+               queue->copy_range = 0;
+               break;
+               
+       case NFQNL_COPY_PACKET:
+               queue->copy_mode = mode;
+               /* we're using struct nfattr which has 16bit nfa_len */
+               if (range > 0xffff)
+                       queue->copy_range = 0xffff;
+               else
+                       queue->copy_range = range;
+               break;
+               
+       default:
+               status = -EINVAL;
+
+       }
+       return status;
+}
+
+static struct nfqnl_queue_entry *
+find_dequeue_entry(struct nfqnl_instance *queue,
+                        nfqnl_cmpfn cmpfn, unsigned long data)
+{
+       struct nfqnl_queue_entry *entry;
+       
+       spin_lock_bh(&queue->lock);
+       entry = __find_dequeue_entry(queue, cmpfn, data);
+       spin_unlock_bh(&queue->lock);
+
+       return entry;
+}
+
+static void
+nfqnl_flush(struct nfqnl_instance *queue, int verdict)
+{
+       spin_lock_bh(&queue->lock);
+       __nfqnl_flush(queue, verdict);
+       spin_unlock_bh(&queue->lock);
+}
+
+static struct sk_buff *
+nfqnl_build_packet_message(struct nfqnl_instance *queue,
+                          struct nfqnl_queue_entry *entry, int *errp)
+{
+       unsigned char *old_tail;
+       size_t size;
+       size_t data_len = 0;
+       struct sk_buff *skb;
+       struct nfqnl_msg_packet_hdr pmsg;
+       struct nlmsghdr *nlh;
+       struct nfgenmsg *nfmsg;
+       unsigned int tmp_uint;
+
+       QDEBUG("entered\n");
+
+       /* all macros expand to constant values at compile time */
+       size =    NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_hdr))
+               + NLMSG_SPACE(sizeof(u_int32_t))        /* ifindex */
+               + NLMSG_SPACE(sizeof(u_int32_t))        /* ifindex */
+#ifdef CONFIG_BRIDGE_NETFILTER
+               + NLMSG_SPACE(sizeof(u_int32_t))        /* ifindex */
+               + NLMSG_SPACE(sizeof(u_int32_t))        /* ifindex */
+#endif
+               + NLMSG_SPACE(sizeof(u_int32_t))        /* mark */
+               + NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_hw))
+               + NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_timestamp));
+
+       spin_lock_bh(&queue->lock);
+       
+       switch (queue->copy_mode) {
+       case NFQNL_COPY_META:
+       case NFQNL_COPY_NONE:
+               data_len = 0;
+               break;
+       
+       case NFQNL_COPY_PACKET:
+               if (entry->skb->ip_summed == CHECKSUM_HW &&
+                   (*errp = skb_checksum_help(entry->skb,
+                                              entry->info->outdev == NULL))) {
+                       spin_unlock_bh(&queue->lock);
+                       return NULL;
+               }
+               if (queue->copy_range == 0 
+                   || queue->copy_range > entry->skb->len)
+                       data_len = entry->skb->len;
+               else
+                       data_len = queue->copy_range;
+               
+               size += NLMSG_SPACE(data_len);
+               break;
+       
+       default:
+               *errp = -EINVAL;
+               spin_unlock_bh(&queue->lock);
+               return NULL;
+       }
+
+       spin_unlock_bh(&queue->lock);
+
+       skb = alloc_skb(size, GFP_ATOMIC);
+       if (!skb)
+               goto nlmsg_failure;
+               
+       old_tail= skb->tail;
+       nlh = NLMSG_PUT(skb, 0, 0, 
+                       NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET,
+                       sizeof(struct nfgenmsg));
+       nfmsg = NLMSG_DATA(nlh);
+       nfmsg->nfgen_family = entry->info->pf;
+       nfmsg->version = NFNETLINK_V0;
+       nfmsg->res_id = htons(queue->queue_num);
+
+       pmsg.packet_id          = htonl(entry->id);
+       pmsg.hw_protocol        = htons(entry->skb->protocol);
+       pmsg.hook               = entry->info->hook;
+
+       NFA_PUT(skb, NFQA_PACKET_HDR, sizeof(pmsg), &pmsg);
+
+       if (entry->info->indev) {
+               tmp_uint = htonl(entry->info->indev->ifindex);
+#ifndef CONFIG_BRIDGE_NETFILTER
+               NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), &tmp_uint);
+#else
+               if (entry->info->pf == PF_BRIDGE) {
+                       /* Case 1: indev is physical input device, we need to
+                        * look for bridge group (when called from 
+                        * netfilter_bridge) */
+                       NFA_PUT(skb, NFQA_IFINDEX_PHYSINDEV, sizeof(tmp_uint), 
+                               &tmp_uint);
+                       /* this is the bridge group "brX" */
+                       tmp_uint = htonl(entry->info->indev->br_port->br->dev->ifindex);
+                       NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint),
+                               &tmp_uint);
+               } else {
+                       /* Case 2: indev is bridge group, we need to look for
+                        * physical device (when called from ipv4) */
+                       NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint),
+                               &tmp_uint);
+                       if (entry->skb->nf_bridge
+                           && entry->skb->nf_bridge->physindev) {
+                               tmp_uint = htonl(entry->skb->nf_bridge->physindev->ifindex);
+                               NFA_PUT(skb, NFQA_IFINDEX_PHYSINDEV,
+                                       sizeof(tmp_uint), &tmp_uint);
+                       }
+               }
+#endif
+       }
+
+       if (entry->info->outdev) {
+               tmp_uint = htonl(entry->info->outdev->ifindex);
+#ifndef CONFIG_BRIDGE_NETFILTER
+               NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), &tmp_uint);
+#else
+               if (entry->info->pf == PF_BRIDGE) {
+                       /* Case 1: outdev is physical output device, we need to
+                        * look for bridge group (when called from 
+                        * netfilter_bridge) */
+                       NFA_PUT(skb, NFQA_IFINDEX_PHYSOUTDEV, sizeof(tmp_uint),
+                               &tmp_uint);
+                       /* this is the bridge group "brX" */
+                       tmp_uint = htonl(entry->info->outdev->br_port->br->dev->ifindex);
+                       NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint),
+                               &tmp_uint);
+               } else {
+                       /* Case 2: outdev is bridge group, we need to look for
+                        * physical output device (when called from ipv4) */
+                       NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint),
+                               &tmp_uint);
+                       if (entry->skb->nf_bridge
+                           && entry->skb->nf_bridge->physoutdev) {
+                               tmp_uint = htonl(entry->skb->nf_bridge->physoutdev->ifindex);
+                               NFA_PUT(skb, NFQA_IFINDEX_PHYSOUTDEV,
+                                       sizeof(tmp_uint), &tmp_uint);
+                       }
+               }
+#endif
+       }
+
+       if (entry->skb->nfmark) {
+               tmp_uint = htonl(entry->skb->nfmark);
+               NFA_PUT(skb, NFQA_MARK, sizeof(u_int32_t), &tmp_uint);
+       }
+
+       if (entry->info->indev && entry->skb->dev
+           && entry->skb->dev->hard_header_parse) {
+               struct nfqnl_msg_packet_hw phw;
+
+               phw.hw_addrlen =
+                       entry->skb->dev->hard_header_parse(entry->skb,
+                                                          phw.hw_addr);
+               phw.hw_addrlen = htons(phw.hw_addrlen);
+               NFA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw);
+       }
+
+       if (entry->skb->tstamp.off_sec) {
+               struct nfqnl_msg_packet_timestamp ts;
+
+               ts.sec = cpu_to_be64(skb_tv_base.tv_sec + entry->skb->tstamp.off_sec);
+               ts.usec = cpu_to_be64(skb_tv_base.tv_usec + entry->skb->tstamp.off_usec);
+
+               NFA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts);
+       }
+
+       if (data_len) {
+               struct nfattr *nfa;
+               int size = NFA_LENGTH(data_len);
+
+               if (skb_tailroom(skb) < (int)NFA_SPACE(data_len)) {
+                       printk(KERN_WARNING "nf_queue: no tailroom!\n");
+                       goto nlmsg_failure;
+               }
+
+               nfa = (struct nfattr *)skb_put(skb, NFA_ALIGN(size));
+               nfa->nfa_type = NFQA_PAYLOAD;
+               nfa->nfa_len = size;
+
+               if (skb_copy_bits(entry->skb, 0, NFA_DATA(nfa), data_len))
+                       BUG();
+       }
+               
+       nlh->nlmsg_len = skb->tail - old_tail;
+       return skb;
+
+nlmsg_failure:
+nfattr_failure:
+       if (skb)
+               kfree_skb(skb);
+       *errp = -EINVAL;
+       if (net_ratelimit())
+               printk(KERN_ERR "nf_queue: error creating packet message\n");
+       return NULL;
+}
+
+static int
+nfqnl_enqueue_packet(struct sk_buff *skb, struct nf_info *info, 
+                    unsigned int queuenum, void *data)
+{
+       int status = -EINVAL;
+       struct sk_buff *nskb;
+       struct nfqnl_instance *queue;
+       struct nfqnl_queue_entry *entry;
+
+       QDEBUG("entered\n");
+
+       queue = instance_lookup_get(queuenum);
+       if (!queue) {
+               QDEBUG("no queue instance matching\n");
+               return -EINVAL;
+       }
+
+       if (queue->copy_mode == NFQNL_COPY_NONE) {
+               QDEBUG("mode COPY_NONE, aborting\n");
+               status = -EAGAIN;
+               goto err_out_put;
+       }
+
+       entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+       if (entry == NULL) {
+               if (net_ratelimit())
+                       printk(KERN_ERR 
+                               "nf_queue: OOM in nfqnl_enqueue_packet()\n");
+               status = -ENOMEM;
+               goto err_out_put;
+       }
+
+       entry->info = info;
+       entry->skb = skb;
+       entry->id = atomic_inc_return(&queue->id_sequence);
+
+       nskb = nfqnl_build_packet_message(queue, entry, &status);
+       if (nskb == NULL)
+               goto err_out_free;
+               
+       spin_lock_bh(&queue->lock);
+       
+       if (!queue->peer_pid)
+               goto err_out_free_nskb; 
+
+       if (queue->queue_total >= queue->queue_maxlen) {
+                queue->queue_dropped++;
+               status = -ENOSPC;
+               if (net_ratelimit())
+                         printk(KERN_WARNING "ip_queue: full at %d entries, "
+                                "dropping packets(s). Dropped: %d\n", 
+                                queue->queue_total, queue->queue_dropped);
+               goto err_out_free_nskb;
+       }
+
+       /* nfnetlink_unicast will either free the nskb or add it to a socket */
+       status = nfnetlink_unicast(nskb, queue->peer_pid, MSG_DONTWAIT);
+       if (status < 0) {
+               queue->queue_user_dropped++;
+               goto err_out_unlock;
+       }
+
+       __enqueue_entry(queue, entry);
+
+       spin_unlock_bh(&queue->lock);
+       instance_put(queue);
+       return status;
+
+err_out_free_nskb:
+       kfree_skb(nskb); 
+       
+err_out_unlock:
+       spin_unlock_bh(&queue->lock);
+
+err_out_free:
+       kfree(entry);
+err_out_put:
+       instance_put(queue);
+       return status;
+}
+
+static int
+nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e)
+{
+       int diff;
+
+       diff = data_len - e->skb->len;
+       if (diff < 0)
+               skb_trim(e->skb, data_len);
+       else if (diff > 0) {
+               if (data_len > 0xFFFF)
+                       return -EINVAL;
+               if (diff > skb_tailroom(e->skb)) {
+                       struct sk_buff *newskb;
+                       
+                       newskb = skb_copy_expand(e->skb,
+                                                skb_headroom(e->skb),
+                                                diff,
+                                                GFP_ATOMIC);
+                       if (newskb == NULL) {
+                               printk(KERN_WARNING "ip_queue: OOM "
+                                     "in mangle, dropping packet\n");
+                               return -ENOMEM;
+                       }
+                       if (e->skb->sk)
+                               skb_set_owner_w(newskb, e->skb->sk);
+                       kfree_skb(e->skb);
+                       e->skb = newskb;
+               }
+               skb_put(e->skb, diff);
+       }
+       if (!skb_make_writable(&e->skb, data_len))
+               return -ENOMEM;
+       memcpy(e->skb->data, data, data_len);
+       e->skb->ip_summed = CHECKSUM_NONE;
+       return 0;
+}
+
+static inline int
+id_cmp(struct nfqnl_queue_entry *e, unsigned long id)
+{
+       return (id == e->id);
+}
+
+static int
+nfqnl_set_mode(struct nfqnl_instance *queue,
+              unsigned char mode, unsigned int range)
+{
+       int status;
+
+       spin_lock_bh(&queue->lock);
+       status = __nfqnl_set_mode(queue, mode, range);
+       spin_unlock_bh(&queue->lock);
+
+       return status;
+}
+
+static int
+dev_cmp(struct nfqnl_queue_entry *entry, unsigned long ifindex)
+{
+       if (entry->info->indev)
+               if (entry->info->indev->ifindex == ifindex)
+                       return 1;
+                       
+       if (entry->info->outdev)
+               if (entry->info->outdev->ifindex == ifindex)
+                       return 1;
+
+       return 0;
+}
+
+/* drop all packets with either indev or outdev == ifindex from all queue
+ * instances */
+static void
+nfqnl_dev_drop(int ifindex)
+{
+       int i;
+       
+       QDEBUG("entering for ifindex %u\n", ifindex);
+
+       /* this only looks like we have to hold the readlock for a way too long
+        * time, issue_verdict(),  nf_reinject(), ... - but we always only
+        * issue NF_DROP, which is processed directly in nf_reinject() */
+       read_lock_bh(&instances_lock);
+
+       for  (i = 0; i < INSTANCE_BUCKETS; i++) {
+               struct hlist_node *tmp;
+               struct nfqnl_instance *inst;
+               struct hlist_head *head = &instance_table[i];
+
+               hlist_for_each_entry(inst, tmp, head, hlist) {
+                       struct nfqnl_queue_entry *entry;
+                       while ((entry = find_dequeue_entry(inst, dev_cmp, 
+                                                          ifindex)) != NULL)
+                               issue_verdict(entry, NF_DROP);
+               }
+       }
+
+       read_unlock_bh(&instances_lock);
+}
+
+#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
+
+static int
+nfqnl_rcv_dev_event(struct notifier_block *this,
+                   unsigned long event, void *ptr)
+{
+       struct net_device *dev = ptr;
+
+       /* Drop any packets associated with the downed device */
+       if (event == NETDEV_DOWN)
+               nfqnl_dev_drop(dev->ifindex);
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block nfqnl_dev_notifier = {
+       .notifier_call  = nfqnl_rcv_dev_event,
+};
+
+static int
+nfqnl_rcv_nl_event(struct notifier_block *this,
+                  unsigned long event, void *ptr)
+{
+       struct netlink_notify *n = ptr;
+
+       if (event == NETLINK_URELEASE &&
+           n->protocol == NETLINK_NETFILTER && n->pid) {
+               int i;
+
+               /* destroy all instances for this pid */
+               write_lock_bh(&instances_lock);
+               for  (i = 0; i < INSTANCE_BUCKETS; i++) {
+                       struct hlist_node *tmp, *t2;
+                       struct nfqnl_instance *inst;
+                       struct hlist_head *head = &instance_table[i];
+
+                       hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) {
+                               if (n->pid == inst->peer_pid)
+                                       __instance_destroy(inst);
+                       }
+               }
+               write_unlock_bh(&instances_lock);
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block nfqnl_rtnl_notifier = {
+       .notifier_call  = nfqnl_rcv_nl_event,
+};
+
+static const int nfqa_verdict_min[NFQA_MAX] = {
+       [NFQA_VERDICT_HDR-1]    = sizeof(struct nfqnl_msg_verdict_hdr),
+       [NFQA_MARK-1]           = sizeof(u_int32_t),
+       [NFQA_PAYLOAD-1]        = 0,
+};
+
+static int
+nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
+                  struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp)
+{
+       struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
+       u_int16_t queue_num = ntohs(nfmsg->res_id);
+
+       struct nfqnl_msg_verdict_hdr *vhdr;
+       struct nfqnl_instance *queue;
+       unsigned int verdict;
+       struct nfqnl_queue_entry *entry;
+       int err;
+
+       if (nfattr_bad_size(nfqa, NFQA_MAX, nfqa_verdict_min)) {
+               QDEBUG("bad attribute size\n");
+               return -EINVAL;
+       }
+
+       queue = instance_lookup_get(queue_num);
+       if (!queue)
+               return -ENODEV;
+
+       if (queue->peer_pid != NETLINK_CB(skb).pid) {
+               err = -EPERM;
+               goto err_out_put;
+       }
+
+       if (!nfqa[NFQA_VERDICT_HDR-1]) {
+               err = -EINVAL;
+               goto err_out_put;
+       }
+
+       vhdr = NFA_DATA(nfqa[NFQA_VERDICT_HDR-1]);
+       verdict = ntohl(vhdr->verdict);
+
+       if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT) {
+               err = -EINVAL;
+               goto err_out_put;
+       }
+
+       entry = find_dequeue_entry(queue, id_cmp, ntohl(vhdr->id));
+       if (entry == NULL) {
+               err = -ENOENT;
+               goto err_out_put;
+       }
+
+       if (nfqa[NFQA_PAYLOAD-1]) {
+               if (nfqnl_mangle(NFA_DATA(nfqa[NFQA_PAYLOAD-1]),
+                                NFA_PAYLOAD(nfqa[NFQA_PAYLOAD-1]), entry) < 0)
+                       verdict = NF_DROP;
+       }
+
+       if (nfqa[NFQA_MARK-1])
+               skb->nfmark = ntohl(*(u_int32_t *)NFA_DATA(nfqa[NFQA_MARK-1]));
+               
+       issue_verdict(entry, verdict);
+       instance_put(queue);
+       return 0;
+
+err_out_put:
+       instance_put(queue);
+       return err;
+}
+
+static int
+nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
+                 struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp)
+{
+       return -ENOTSUPP;
+}
+
+static const int nfqa_cfg_min[NFQA_CFG_MAX] = {
+       [NFQA_CFG_CMD-1]        = sizeof(struct nfqnl_msg_config_cmd),
+       [NFQA_CFG_PARAMS-1]     = sizeof(struct nfqnl_msg_config_params),
+};
+
+static struct nf_queue_handler nfqh = {
+       .name   = "nf_queue",
+       .outfn  = &nfqnl_enqueue_packet,
+};
+
+static int
+nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
+                 struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp)
+{
+       struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
+       u_int16_t queue_num = ntohs(nfmsg->res_id);
+       struct nfqnl_instance *queue;
+       int ret = 0;
+
+       QDEBUG("entering for msg %u\n", NFNL_MSG_TYPE(nlh->nlmsg_type));
+
+       if (nfattr_bad_size(nfqa, NFQA_CFG_MAX, nfqa_cfg_min)) {
+               QDEBUG("bad attribute size\n");
+               return -EINVAL;
+       }
+
+       queue = instance_lookup_get(queue_num);
+       if (nfqa[NFQA_CFG_CMD-1]) {
+               struct nfqnl_msg_config_cmd *cmd;
+               cmd = NFA_DATA(nfqa[NFQA_CFG_CMD-1]);
+               QDEBUG("found CFG_CMD\n");
+
+               switch (cmd->command) {
+               case NFQNL_CFG_CMD_BIND:
+                       if (queue)
+                               return -EBUSY;
+
+                       queue = instance_create(queue_num, NETLINK_CB(skb).pid);
+                       if (!queue)
+                               return -EINVAL;
+                       break;
+               case NFQNL_CFG_CMD_UNBIND:
+                       if (!queue)
+                               return -ENODEV;
+
+                       if (queue->peer_pid != NETLINK_CB(skb).pid) {
+                               ret = -EPERM;
+                               goto out_put;
+                       }
+
+                       instance_destroy(queue);
+                       break;
+               case NFQNL_CFG_CMD_PF_BIND:
+                       QDEBUG("registering queue handler for pf=%u\n",
+                               ntohs(cmd->pf));
+                       ret = nf_register_queue_handler(ntohs(cmd->pf), &nfqh);
+                       break;
+               case NFQNL_CFG_CMD_PF_UNBIND:
+                       QDEBUG("unregistering queue handler for pf=%u\n",
+                               ntohs(cmd->pf));
+                       /* This is a bug and a feature.  We can unregister
+                        * other handlers(!) */
+                       ret = nf_unregister_queue_handler(ntohs(cmd->pf));
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+       } else {
+               if (!queue) {
+                       QDEBUG("no config command, and no instance ENOENT\n");
+                       ret = -ENOENT;
+                       goto out_put;
+               }
+
+               if (queue->peer_pid != NETLINK_CB(skb).pid) {
+                       QDEBUG("no config command, and wrong pid\n");
+                       ret = -EPERM;
+                       goto out_put;
+               }
+       }
+
+       if (nfqa[NFQA_CFG_PARAMS-1]) {
+               struct nfqnl_msg_config_params *params;
+               params = NFA_DATA(nfqa[NFQA_CFG_PARAMS-1]);
+
+               nfqnl_set_mode(queue, params->copy_mode,
+                               ntohl(params->copy_range));
+       }
+
+out_put:
+       instance_put(queue);
+       return ret;
+}
+
+static struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
+       [NFQNL_MSG_PACKET]      = { .call = nfqnl_recv_unsupp,
+                                   .attr_count = NFQA_MAX,
+                                   .cap_required = CAP_NET_ADMIN },
+       [NFQNL_MSG_VERDICT]     = { .call = nfqnl_recv_verdict,
+                                   .attr_count = NFQA_MAX,
+                                   .cap_required = CAP_NET_ADMIN },
+       [NFQNL_MSG_CONFIG]      = { .call = nfqnl_recv_config,
+                                   .attr_count = NFQA_CFG_MAX,
+                                   .cap_required = CAP_NET_ADMIN },
+};
+
+static struct nfnetlink_subsystem nfqnl_subsys = {
+       .name           = "nf_queue",
+       .subsys_id      = NFNL_SUBSYS_QUEUE,
+       .cb_count       = NFQNL_MSG_MAX,
+       .cb             = nfqnl_cb,
+};
+
+#ifdef CONFIG_PROC_FS
+struct iter_state {
+       unsigned int bucket;
+};
+
+static struct hlist_node *get_first(struct seq_file *seq)
+{
+       struct iter_state *st = seq->private;
+
+       if (!st)
+               return NULL;
+
+       for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) {
+               if (!hlist_empty(&instance_table[st->bucket]))
+                       return instance_table[st->bucket].first;
+       }
+       return NULL;
+}
+
+static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h)
+{
+       struct iter_state *st = seq->private;
+
+       h = h->next;
+       while (!h) {
+               if (++st->bucket >= INSTANCE_BUCKETS)
+                       return NULL;
+
+               h = instance_table[st->bucket].first;
+       }
+       return h;
+}
+
+static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos)
+{
+       struct hlist_node *head;
+       head = get_first(seq);
+
+       if (head)
+               while (pos && (head = get_next(seq, head)))
+                       pos--;
+       return pos ? NULL : head;
+}
+
+static void *seq_start(struct seq_file *seq, loff_t *pos)
+{
+       read_lock_bh(&instances_lock);
+       return get_idx(seq, *pos);
+}
+
+static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       (*pos)++;
+       return get_next(s, v);
+}
+
+static void seq_stop(struct seq_file *s, void *v)
+{
+       read_unlock_bh(&instances_lock);
+}
+
+static int seq_show(struct seq_file *s, void *v)
+{
+       const struct nfqnl_instance *inst = v;
+
+       return seq_printf(s, "%5d %6d %5d %1d %5d %5d %5d %8d %2d\n",
+                         inst->queue_num,
+                         inst->peer_pid, inst->queue_total,
+                         inst->copy_mode, inst->copy_range,
+                         inst->queue_dropped, inst->queue_user_dropped,
+                         atomic_read(&inst->id_sequence),
+                         atomic_read(&inst->use));
+}
+
+static struct seq_operations nfqnl_seq_ops = {
+       .start  = seq_start,
+       .next   = seq_next,
+       .stop   = seq_stop,
+       .show   = seq_show,
+};
+
+static int nfqnl_open(struct inode *inode, struct file *file)
+{
+       struct seq_file *seq;
+       struct iter_state *is;
+       int ret;
+
+       is = kmalloc(sizeof(*is), GFP_KERNEL);
+       if (!is)
+               return -ENOMEM;
+       memset(is, 0, sizeof(*is));
+       ret = seq_open(file, &nfqnl_seq_ops);
+       if (ret < 0)
+               goto out_free;
+       seq = file->private_data;
+       seq->private = is;
+       return ret;
+out_free:
+       kfree(is);
+       return ret;
+}
+
+static struct file_operations nfqnl_file_ops = {
+       .owner   = THIS_MODULE,
+       .open    = nfqnl_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release_private,
+};
+
+#endif /* PROC_FS */
+
+static int
+init_or_cleanup(int init)
+{
+       int i, status = -ENOMEM;
+#ifdef CONFIG_PROC_FS
+       struct proc_dir_entry *proc_nfqueue;
+#endif
+       
+       if (!init)
+               goto cleanup;
+
+       for (i = 0; i < INSTANCE_BUCKETS; i++)
+               INIT_HLIST_HEAD(&instance_table[i]);
+
+       netlink_register_notifier(&nfqnl_rtnl_notifier);
+       status = nfnetlink_subsys_register(&nfqnl_subsys);
+       if (status < 0) {
+               printk(KERN_ERR "nf_queue: failed to create netlink socket\n");
+               goto cleanup_netlink_notifier;
+       }
+
+#ifdef CONFIG_PROC_FS
+       proc_nfqueue = create_proc_entry("nfnetlink_queue", 0440,
+                                        proc_net_netfilter);
+       if (!proc_nfqueue)
+               goto cleanup_subsys;
+       proc_nfqueue->proc_fops = &nfqnl_file_ops;
+#endif
+
+       register_netdevice_notifier(&nfqnl_dev_notifier);
+
+       return status;
+
+cleanup:
+       nf_unregister_queue_handlers(&nfqh);
+       unregister_netdevice_notifier(&nfqnl_dev_notifier);
+#ifdef CONFIG_PROC_FS
+       remove_proc_entry("nfnetlink_queue", proc_net_netfilter);
+cleanup_subsys:
+#endif 
+       nfnetlink_subsys_unregister(&nfqnl_subsys);
+cleanup_netlink_notifier:
+       netlink_unregister_notifier(&nfqnl_rtnl_notifier);
+       return status;
+}
+
+static int __init init(void)
+{
+       
+       return init_or_cleanup(1);
+}
+
+static void __exit fini(void)
+{
+       init_or_cleanup(0);
+}
+
+MODULE_DESCRIPTION("netfilter packet queue handler");
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_QUEUE);
+
+module_init(init);
+module_exit(fini);
index ff774a06c89df46c2c4ce8b0a5d7e6ce07a90f71..a64e1d5ce3ca8f38ae3cb76c41d62d4bd0a8d136 100644 (file)
  *                               added netlink_proto_exit
  * Tue Jan 22 18:32:44 BRST 2002 Arnaldo C. de Melo <acme@conectiva.com.br>
  *                              use nlk_sk, as sk->protinfo is on a diet 8)
- *
+ * Fri Jul 22 19:51:12 MEST 2005 Harald Welte <laforge@gnumonks.org>
+ *                              - inc module use count of module that owns
+ *                                the kernel socket in case userspace opens
+ *                                socket of same protocol
+ *                              - remove all module support, since netlink is
+ *                                mandatory if CONFIG_NET=y these days
  */
 
 #include <linux/config.h>
 #include <net/scm.h>
 
 #define Nprintk(a...)
+#define NLGRPSZ(x)     (ALIGN(x, sizeof(unsigned long) * 8) / 8)
 
 struct netlink_sock {
        /* struct sock has to be the first member of netlink_sock */
        struct sock             sk;
        u32                     pid;
-       unsigned int            groups;
        u32                     dst_pid;
-       unsigned int            dst_groups;
+       u32                     dst_group;
+       u32                     flags;
+       u32                     subscriptions;
+       u32                     ngroups;
+       unsigned long           *groups;
        unsigned long           state;
        wait_queue_head_t       wait;
        struct netlink_callback *cb;
        spinlock_t              cb_lock;
        void                    (*data_ready)(struct sock *sk, int bytes);
+       struct module           *module;
 };
 
+#define NETLINK_KERNEL_SOCKET  0x1
+#define NETLINK_RECV_PKTINFO   0x2
+
 static inline struct netlink_sock *nlk_sk(struct sock *sk)
 {
        return (struct netlink_sock *)sk;
@@ -92,6 +105,9 @@ struct netlink_table {
        struct nl_pid_hash hash;
        struct hlist_head mc_list;
        unsigned int nl_nonroot;
+       unsigned int groups;
+       struct module *module;
+       int registered;
 };
 
 static struct netlink_table *nl_table;
@@ -106,6 +122,11 @@ static atomic_t nl_table_users = ATOMIC_INIT(0);
 
 static struct notifier_block *netlink_chain;
 
+static u32 netlink_group_mask(u32 group)
+{
+       return group ? 1 << (group - 1) : 0;
+}
+
 static struct hlist_head *nl_pid_hashfn(struct nl_pid_hash *hash, u32 pid)
 {
        return &hash->table[jhash_1word(pid, hash->rnd) & hash->mask];
@@ -122,6 +143,7 @@ static void netlink_sock_destruct(struct sock *sk)
        BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc));
        BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc));
        BUG_TRAP(!nlk_sk(sk)->cb);
+       BUG_TRAP(!nlk_sk(sk)->groups);
 }
 
 /* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on SMP.
@@ -317,7 +339,7 @@ static void netlink_remove(struct sock *sk)
        netlink_table_grab();
        if (sk_del_node_init(sk))
                nl_table[sk->sk_protocol].hash.entries--;
-       if (nlk_sk(sk)->groups)
+       if (nlk_sk(sk)->subscriptions)
                __sk_del_bind_node(sk);
        netlink_table_ungrab();
 }
@@ -328,19 +350,11 @@ static struct proto netlink_proto = {
        .obj_size = sizeof(struct netlink_sock),
 };
 
-static int netlink_create(struct socket *sock, int protocol)
+static int __netlink_create(struct socket *sock, int protocol)
 {
        struct sock *sk;
        struct netlink_sock *nlk;
 
-       sock->state = SS_UNCONNECTED;
-
-       if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM)
-               return -ESOCKTNOSUPPORT;
-
-       if (protocol<0 || protocol >= MAX_LINKS)
-               return -EPROTONOSUPPORT;
-
        sock->ops = &netlink_ops;
 
        sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1);
@@ -350,15 +364,56 @@ static int netlink_create(struct socket *sock, int protocol)
        sock_init_data(sock, sk);
 
        nlk = nlk_sk(sk);
-
        spin_lock_init(&nlk->cb_lock);
        init_waitqueue_head(&nlk->wait);
-       sk->sk_destruct = netlink_sock_destruct;
 
+       sk->sk_destruct = netlink_sock_destruct;
        sk->sk_protocol = protocol;
        return 0;
 }
 
+static int netlink_create(struct socket *sock, int protocol)
+{
+       struct module *module = NULL;
+       struct netlink_sock *nlk;
+       unsigned int groups;
+       int err = 0;
+
+       sock->state = SS_UNCONNECTED;
+
+       if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM)
+               return -ESOCKTNOSUPPORT;
+
+       if (protocol<0 || protocol >= MAX_LINKS)
+               return -EPROTONOSUPPORT;
+
+       netlink_lock_table();
+#ifdef CONFIG_KMOD
+       if (!nl_table[protocol].registered) {
+               netlink_unlock_table();
+               request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol);
+               netlink_lock_table();
+       }
+#endif
+       if (nl_table[protocol].registered &&
+           try_module_get(nl_table[protocol].module))
+               module = nl_table[protocol].module;
+       groups = nl_table[protocol].groups;
+       netlink_unlock_table();
+
+       if ((err = __netlink_create(sock, protocol) < 0))
+               goto out_module;
+
+       nlk = nlk_sk(sock->sk);
+       nlk->module = module;
+out:
+       return err;
+
+out_module:
+       module_put(module);
+       goto out;
+}
+
 static int netlink_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
@@ -387,14 +442,27 @@ static int netlink_release(struct socket *sock)
 
        skb_queue_purge(&sk->sk_write_queue);
 
-       if (nlk->pid && !nlk->groups) {
+       if (nlk->pid && !nlk->subscriptions) {
                struct netlink_notify n = {
                                                .protocol = sk->sk_protocol,
                                                .pid = nlk->pid,
                                          };
                notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n);
        }       
-       
+
+       if (nlk->module)
+               module_put(nlk->module);
+
+       if (nlk->flags & NETLINK_KERNEL_SOCKET) {
+               netlink_table_grab();
+               nl_table[sk->sk_protocol].module = NULL;
+               nl_table[sk->sk_protocol].registered = 0;
+               netlink_table_ungrab();
+       }
+
+       kfree(nlk->groups);
+       nlk->groups = NULL;
+
        sock_put(sk);
        return 0;
 }
@@ -443,6 +511,41 @@ static inline int netlink_capable(struct socket *sock, unsigned int flag)
               capable(CAP_NET_ADMIN);
 } 
 
+static void
+netlink_update_subscriptions(struct sock *sk, unsigned int subscriptions)
+{
+       struct netlink_sock *nlk = nlk_sk(sk);
+
+       if (nlk->subscriptions && !subscriptions)
+               __sk_del_bind_node(sk);
+       else if (!nlk->subscriptions && subscriptions)
+               sk_add_bind_node(sk, &nl_table[sk->sk_protocol].mc_list);
+       nlk->subscriptions = subscriptions;
+}
+
+static int netlink_alloc_groups(struct sock *sk)
+{
+       struct netlink_sock *nlk = nlk_sk(sk);
+       unsigned int groups;
+       int err = 0;
+
+       netlink_lock_table();
+       groups = nl_table[sk->sk_protocol].groups;
+       if (!nl_table[sk->sk_protocol].registered)
+               err = -ENOENT;
+       netlink_unlock_table();
+
+       if (err)
+               return err;
+
+       nlk->groups = kmalloc(NLGRPSZ(groups), GFP_KERNEL);
+       if (nlk->groups == NULL)
+               return -ENOMEM;
+       memset(nlk->groups, 0, NLGRPSZ(groups));
+       nlk->ngroups = groups;
+       return 0;
+}
+
 static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
 {
        struct sock *sk = sock->sk;
@@ -454,8 +557,15 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len
                return -EINVAL;
 
        /* Only superuser is allowed to listen multicasts */
-       if (nladdr->nl_groups && !netlink_capable(sock, NL_NONROOT_RECV))
-               return -EPERM;
+       if (nladdr->nl_groups) {
+               if (!netlink_capable(sock, NL_NONROOT_RECV))
+                       return -EPERM;
+               if (nlk->groups == NULL) {
+                       err = netlink_alloc_groups(sk);
+                       if (err)
+                               return err;
+               }
+       }
 
        if (nlk->pid) {
                if (nladdr->nl_pid != nlk->pid)
@@ -468,15 +578,14 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len
                        return err;
        }
 
-       if (!nladdr->nl_groups && !nlk->groups)
+       if (!nladdr->nl_groups && (nlk->groups == NULL || !(u32)nlk->groups[0]))
                return 0;
 
        netlink_table_grab();
-       if (nlk->groups && !nladdr->nl_groups)
-               __sk_del_bind_node(sk);
-       else if (!nlk->groups && nladdr->nl_groups)
-               sk_add_bind_node(sk, &nl_table[sk->sk_protocol].mc_list);
-       nlk->groups = nladdr->nl_groups;
+       netlink_update_subscriptions(sk, nlk->subscriptions +
+                                        hweight32(nladdr->nl_groups) -
+                                        hweight32(nlk->groups[0]));
+       nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups; 
        netlink_table_ungrab();
 
        return 0;
@@ -493,7 +602,7 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
        if (addr->sa_family == AF_UNSPEC) {
                sk->sk_state    = NETLINK_UNCONNECTED;
                nlk->dst_pid    = 0;
-               nlk->dst_groups = 0;
+               nlk->dst_group  = 0;
                return 0;
        }
        if (addr->sa_family != AF_NETLINK)
@@ -509,7 +618,7 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
        if (err == 0) {
                sk->sk_state    = NETLINK_CONNECTED;
                nlk->dst_pid    = nladdr->nl_pid;
-               nlk->dst_groups = nladdr->nl_groups;
+               nlk->dst_group  = ffs(nladdr->nl_groups);
        }
 
        return err;
@@ -527,10 +636,10 @@ static int netlink_getname(struct socket *sock, struct sockaddr *addr, int *addr
 
        if (peer) {
                nladdr->nl_pid = nlk->dst_pid;
-               nladdr->nl_groups = nlk->dst_groups;
+               nladdr->nl_groups = netlink_group_mask(nlk->dst_group);
        } else {
                nladdr->nl_pid = nlk->pid;
-               nladdr->nl_groups = nlk->groups;
+               nladdr->nl_groups = nlk->groups ? nlk->groups[0] : 0;
        }
        return 0;
 }
@@ -731,7 +840,8 @@ static inline int do_one_broadcast(struct sock *sk,
        if (p->exclude_sk == sk)
                goto out;
 
-       if (nlk->pid == p->pid || !(nlk->groups & p->group))
+       if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups ||
+           !test_bit(p->group - 1, nlk->groups))
                goto out;
 
        if (p->failure) {
@@ -770,7 +880,7 @@ out:
 }
 
 int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
-                     u32 group, int allocation)
+                     u32 group, unsigned int __nocast allocation)
 {
        struct netlink_broadcast_data info;
        struct hlist_node *node;
@@ -827,7 +937,8 @@ static inline int do_one_set_err(struct sock *sk,
        if (sk == p->exclude_sk)
                goto out;
 
-       if (nlk->pid == p->pid || !(nlk->groups & p->group))
+       if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups ||
+           !test_bit(p->group - 1, nlk->groups))
                goto out;
 
        sk->sk_err = p->code;
@@ -855,6 +966,99 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)
        read_unlock(&nl_table_lock);
 }
 
+static int netlink_setsockopt(struct socket *sock, int level, int optname,
+                              char __user *optval, int optlen)
+{
+       struct sock *sk = sock->sk;
+       struct netlink_sock *nlk = nlk_sk(sk);
+       int val = 0, err;
+
+       if (level != SOL_NETLINK)
+               return -ENOPROTOOPT;
+
+       if (optlen >= sizeof(int) &&
+           get_user(val, (int __user *)optval))
+               return -EFAULT;
+
+       switch (optname) {
+       case NETLINK_PKTINFO:
+               if (val)
+                       nlk->flags |= NETLINK_RECV_PKTINFO;
+               else
+                       nlk->flags &= ~NETLINK_RECV_PKTINFO;
+               err = 0;
+               break;
+       case NETLINK_ADD_MEMBERSHIP:
+       case NETLINK_DROP_MEMBERSHIP: {
+               unsigned int subscriptions;
+               int old, new = optname == NETLINK_ADD_MEMBERSHIP ? 1 : 0;
+
+               if (!netlink_capable(sock, NL_NONROOT_RECV))
+                       return -EPERM;
+               if (nlk->groups == NULL) {
+                       err = netlink_alloc_groups(sk);
+                       if (err)
+                               return err;
+               }
+               if (!val || val - 1 >= nlk->ngroups)
+                       return -EINVAL;
+               netlink_table_grab();
+               old = test_bit(val - 1, nlk->groups);
+               subscriptions = nlk->subscriptions - old + new;
+               if (new)
+                       __set_bit(val - 1, nlk->groups);
+               else
+                       __clear_bit(val - 1, nlk->groups);
+               netlink_update_subscriptions(sk, subscriptions);
+               netlink_table_ungrab();
+               err = 0;
+               break;
+       }
+       default:
+               err = -ENOPROTOOPT;
+       }
+       return err;
+}
+
+static int netlink_getsockopt(struct socket *sock, int level, int optname,
+                              char __user *optval, int __user *optlen)
+{
+       struct sock *sk = sock->sk;
+       struct netlink_sock *nlk = nlk_sk(sk);
+       int len, val, err;
+
+       if (level != SOL_NETLINK)
+               return -ENOPROTOOPT;
+
+       if (get_user(len, optlen))
+               return -EFAULT;
+       if (len < 0)
+               return -EINVAL;
+
+       switch (optname) {
+       case NETLINK_PKTINFO:
+               if (len < sizeof(int))
+                       return -EINVAL;
+               len = sizeof(int);
+               val = nlk->flags & NETLINK_RECV_PKTINFO ? 1 : 0;
+               put_user(len, optlen);
+               put_user(val, optval);
+               err = 0;
+               break;
+       default:
+               err = -ENOPROTOOPT;
+       }
+       return err;
+}
+
+static void netlink_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb)
+{
+       struct nl_pktinfo info;
+
+       info.group = NETLINK_CB(skb).dst_group;
+       put_cmsg(msg, SOL_NETLINK, NETLINK_PKTINFO, sizeof(info), &info);
+}
+
 static inline void netlink_rcv_wake(struct sock *sk)
 {
        struct netlink_sock *nlk = nlk_sk(sk);
@@ -873,7 +1077,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
        struct netlink_sock *nlk = nlk_sk(sk);
        struct sockaddr_nl *addr=msg->msg_name;
        u32 dst_pid;
-       u32 dst_groups;
+       u32 dst_group;
        struct sk_buff *skb;
        int err;
        struct scm_cookie scm;
@@ -891,12 +1095,12 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
                if (addr->nl_family != AF_NETLINK)
                        return -EINVAL;
                dst_pid = addr->nl_pid;
-               dst_groups = addr->nl_groups;
-               if (dst_groups && !netlink_capable(sock, NL_NONROOT_SEND))
+               dst_group = ffs(addr->nl_groups);
+               if (dst_group && !netlink_capable(sock, NL_NONROOT_SEND))
                        return -EPERM;
        } else {
                dst_pid = nlk->dst_pid;
-               dst_groups = nlk->dst_groups;
+               dst_group = nlk->dst_group;
        }
 
        if (!nlk->pid) {
@@ -914,9 +1118,8 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
                goto out;
 
        NETLINK_CB(skb).pid     = nlk->pid;
-       NETLINK_CB(skb).groups  = nlk->groups;
        NETLINK_CB(skb).dst_pid = dst_pid;
-       NETLINK_CB(skb).dst_groups = dst_groups;
+       NETLINK_CB(skb).dst_group = dst_group;
        NETLINK_CB(skb).loginuid = audit_get_loginuid(current->audit_context);
        memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
 
@@ -938,9 +1141,9 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
                goto out;
        }
 
-       if (dst_groups) {
+       if (dst_group) {
                atomic_inc(&skb->users);
-               netlink_broadcast(sk, skb, dst_pid, dst_groups, GFP_KERNEL);
+               netlink_broadcast(sk, skb, dst_pid, dst_group, GFP_KERNEL);
        }
        err = netlink_unicast(sk, skb, dst_pid, msg->msg_flags&MSG_DONTWAIT);
 
@@ -986,7 +1189,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
                addr->nl_family = AF_NETLINK;
                addr->nl_pad    = 0;
                addr->nl_pid    = NETLINK_CB(skb).pid;
-               addr->nl_groups = NETLINK_CB(skb).dst_groups;
+               addr->nl_groups = netlink_group_mask(NETLINK_CB(skb).dst_group);
                msg->msg_namelen = sizeof(*addr);
        }
 
@@ -1001,6 +1204,8 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
                netlink_dump(sk);
 
        scm_recv(sock, msg, siocb->scm, flags);
+       if (nlk->flags & NETLINK_RECV_PKTINFO)
+               netlink_cmsg_recv_pktinfo(msg, skb);
 
 out:
        netlink_rcv_wake(sk);
@@ -1023,10 +1228,13 @@ static void netlink_data_ready(struct sock *sk, int len)
  */
 
 struct sock *
-netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len))
+netlink_kernel_create(int unit, unsigned int groups,
+                      void (*input)(struct sock *sk, int len),
+                      struct module *module)
 {
        struct socket *sock;
        struct sock *sk;
+       struct netlink_sock *nlk;
 
        if (!nl_table)
                return NULL;
@@ -1037,20 +1245,31 @@ netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len))
        if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock))
                return NULL;
 
-       if (netlink_create(sock, unit) < 0) {
-               sock_release(sock);
-               return NULL;
-       }
+       if (__netlink_create(sock, unit) < 0)
+               goto out_sock_release;
+
        sk = sock->sk;
        sk->sk_data_ready = netlink_data_ready;
        if (input)
                nlk_sk(sk)->data_ready = input;
 
-       if (netlink_insert(sk, 0)) {
-               sock_release(sock);
-               return NULL;
-       }
+       if (netlink_insert(sk, 0))
+               goto out_sock_release;
+
+       nlk = nlk_sk(sk);
+       nlk->flags |= NETLINK_KERNEL_SOCKET;
+
+       netlink_table_grab();
+       nl_table[unit].groups = groups < 32 ? 32 : groups;
+       nl_table[unit].module = module;
+       nl_table[unit].registered = 1;
+       netlink_table_ungrab();
+
        return sk;
+
+out_sock_release:
+       sock_release(sock);
+       return NULL;
 }
 
 void netlink_set_nonroot(int protocol, unsigned int flags)
@@ -1288,7 +1507,7 @@ static int netlink_seq_show(struct seq_file *seq, void *v)
                           s,
                           s->sk_protocol,
                           nlk->pid,
-                          nlk->groups,
+                          nlk->groups ? (u32)nlk->groups[0] : 0,
                           atomic_read(&s->sk_rmem_alloc),
                           atomic_read(&s->sk_wmem_alloc),
                           nlk->cb,
@@ -1362,8 +1581,8 @@ static struct proto_ops netlink_ops = {
        .ioctl =        sock_no_ioctl,
        .listen =       sock_no_listen,
        .shutdown =     sock_no_shutdown,
-       .setsockopt =   sock_no_setsockopt,
-       .getsockopt =   sock_no_getsockopt,
+       .setsockopt =   netlink_setsockopt,
+       .getsockopt =   netlink_getsockopt,
        .sendmsg =      netlink_sendmsg,
        .recvmsg =      netlink_recvmsg,
        .mmap =         sock_no_mmap,
@@ -1438,21 +1657,7 @@ out:
        return err;
 }
 
-static void __exit netlink_proto_exit(void)
-{
-       sock_unregister(PF_NETLINK);
-       proc_net_remove("netlink");
-       kfree(nl_table);
-       nl_table = NULL;
-       proto_unregister(&netlink_proto);
-}
-
 core_initcall(netlink_proto_init);
-module_exit(netlink_proto_exit);
-
-MODULE_LICENSE("GPL");
-
-MODULE_ALIAS_NETPROTO(PF_NETLINK);
 
 EXPORT_SYMBOL(netlink_ack);
 EXPORT_SYMBOL(netlink_broadcast);
index 162a85fed150efd5a359da92a9524e6f3f3f4742..f4578c759ffcc3350ebbd708c7f0a2ffef52c587 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <net/ip.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <net/arp.h>
 #include <linux/init.h>
 
@@ -858,17 +858,16 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
        frametype          = skb->data[19] & 0x0F;
        flags              = skb->data[19] & 0xF0;
 
-#ifdef CONFIG_INET
        /*
         * Check for an incoming IP over NET/ROM frame.
         */
-       if (frametype == NR_PROTOEXT && circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) {
+       if (frametype == NR_PROTOEXT &&
+           circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) {
                skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
                skb->h.raw = skb->data;
 
                return nr_rx_ip(skb, dev);
        }
-#endif
 
        /*
         * Find an existing socket connection, based on circuit ID, if it's
@@ -1262,6 +1261,7 @@ static int nr_info_show(struct seq_file *seq, void *v)
        struct net_device *dev;
        struct nr_sock *nr;
        const char *devname;
+       char buf[11];
 
        if (v == SEQ_START_TOKEN)
                seq_puts(seq,
@@ -1277,11 +1277,11 @@ static int nr_info_show(struct seq_file *seq, void *v)
                else
                        devname = dev->name;
 
-               seq_printf(seq, "%-9s ", ax2asc(&nr->user_addr));
-               seq_printf(seq, "%-9s ", ax2asc(&nr->dest_addr));
+               seq_printf(seq, "%-9s ", ax2asc(buf, &nr->user_addr));
+               seq_printf(seq, "%-9s ", ax2asc(buf, &nr->dest_addr));
                seq_printf(seq, 
 "%-9s %-3s  %02X/%02X %02X/%02X %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3d %5d %5d %ld\n",
-                       ax2asc(&nr->source_addr),
+                       ax2asc(buf, &nr->source_addr),
                        devname,
                        nr->my_index,
                        nr->my_id,
index 220bf7494f71591b59be618f7bcc2fcdc669b741..263da4c26494cb2cf875d22b75ca773be770c8b8 100644 (file)
@@ -38,8 +38,6 @@
 #include <net/ax25.h>
 #include <net/netrom.h>
 
-#ifdef CONFIG_INET
-
 /*
  *     Only allow IP over NET/ROM frames through if the netrom device is up.
  */
@@ -64,11 +62,12 @@ int nr_rx_ip(struct sk_buff *skb, struct net_device *dev)
        skb->nh.raw   = skb->data;
        skb->pkt_type = PACKET_HOST;
 
-       ip_rcv(skb, skb->dev, NULL);
+       netif_rx(skb);
 
        return 1;
 }
 
+#ifdef CONFIG_INET
 
 static int nr_rebuild_header(struct sk_buff *skb)
 {
index 9c44b379412630dd7b269142b5fd557fca59139a..64b81a7969077c706353e76309a67698380f2095 100644 (file)
@@ -22,8 +22,7 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/tcp.h>
-#include <net/ip.h>                    /* For ip_rcv */
+#include <net/tcp_states.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
index 7a86b36cba505d6547a0a63620e5105858c9955d..b3b9097c87c7df5ae3c9af4a8d5b7115c34a9d10 100644 (file)
@@ -881,6 +881,7 @@ static void nr_node_stop(struct seq_file *seq, void *v)
 
 static int nr_node_show(struct seq_file *seq, void *v)
 {
+       char buf[11];
        int i;
 
        if (v == SEQ_START_TOKEN)
@@ -890,7 +891,7 @@ static int nr_node_show(struct seq_file *seq, void *v)
                struct nr_node *nr_node = v;
                nr_node_lock(nr_node);
                seq_printf(seq, "%-9s %-7s  %d %d",
-                       ax2asc(&nr_node->callsign),
+                       ax2asc(buf, &nr_node->callsign),
                        (nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic,
                        nr_node->which + 1,
                        nr_node->count);
@@ -964,6 +965,7 @@ static void nr_neigh_stop(struct seq_file *seq, void *v)
 
 static int nr_neigh_show(struct seq_file *seq, void *v)
 {
+       char buf[11];
        int i;
 
        if (v == SEQ_START_TOKEN)
@@ -973,7 +975,7 @@ static int nr_neigh_show(struct seq_file *seq, void *v)
 
                seq_printf(seq, "%05d %-9s %-4s  %3d    %d   %3d    %3d",
                        nr_neigh->number,
-                       ax2asc(&nr_neigh->callsign),
+                       ax2asc(buf, &nr_neigh->callsign),
                        nr_neigh->dev ? nr_neigh->dev->name : "???",
                        nr_neigh->quality,
                        nr_neigh->locked,
@@ -983,7 +985,7 @@ static int nr_neigh_show(struct seq_file *seq, void *v)
                if (nr_neigh->digipeat != NULL) {
                        for (i = 0; i < nr_neigh->digipeat->ndigi; i++)
                                seq_printf(seq, " %s", 
-                                          ax2asc(&nr_neigh->digipeat->calls[i]));
+                                          ax2asc(buf, &nr_neigh->digipeat->calls[i]));
                }
 
                seq_puts(seq, "\n");
index 0627347b14b88d7458b356e24aff9d051d464f75..587bed2674bfb4dcb09e40f13ae0d33b8342e053 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
@@ -77,7 +77,7 @@ void nr_requeue_frames(struct sock *sk)
                if (skb_prev == NULL)
                        skb_queue_head(&sk->sk_write_queue, skb);
                else
-                       skb_append(skb_prev, skb);
+                       skb_append(skb_prev, skb, &sk->sk_write_queue);
                skb_prev = skb;
        }
 }
index faabda8088be5cba98de33e09b3982805a52fbb2..75b72d389ba95283b4c0f1e9adfc69eb8d3ed2a5 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
index c9d5980aa4de5f16726bd646e2ebc93513fc46e1..8690f171c1ef28136e7e57e160e980955d6b742d 100644 (file)
@@ -241,7 +241,7 @@ static struct proto_ops packet_ops;
 #ifdef CONFIG_SOCK_PACKET
 static struct proto_ops packet_ops_spkt;
 
-static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,  struct packet_type *pt)
+static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,  struct packet_type *pt, struct net_device *orig_dev)
 {
        struct sock *sk;
        struct sockaddr_pkt *spkt;
@@ -441,7 +441,7 @@ static inline unsigned run_filter(struct sk_buff *skb, struct sock *sk, unsigned
    we will not harm anyone.
  */
 
-static int packet_rcv(struct sk_buff *skb, struct net_device *dev,  struct packet_type *pt)
+static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
 {
        struct sock *sk;
        struct sockaddr_ll *sll;
@@ -546,7 +546,7 @@ drop:
 }
 
 #ifdef CONFIG_PACKET_MMAP
-static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,  struct packet_type *pt)
+static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
 {
        struct sock *sk;
        struct packet_sock *po;
@@ -635,12 +635,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,  struct pack
        h->tp_snaplen = snaplen;
        h->tp_mac = macoff;
        h->tp_net = netoff;
-       if (skb->stamp.tv_sec == 0) { 
-               do_gettimeofday(&skb->stamp);
+       if (skb->tstamp.off_sec == 0) { 
+               __net_timestamp(skb);
                sock_enable_timestamp(sk);
        }
-       h->tp_sec = skb->stamp.tv_sec;
-       h->tp_usec = skb->stamp.tv_usec;
+       h->tp_sec = skb_tv_base.tv_sec + skb->tstamp.off_sec;
+       h->tp_usec = skb_tv_base.tv_usec + skb->tstamp.off_usec;
 
        sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h)));
        sll->sll_halen = 0;
@@ -1535,8 +1535,7 @@ static unsigned int packet_poll(struct file * file, struct socket *sock,
 static void packet_mm_open(struct vm_area_struct *vma)
 {
        struct file *file = vma->vm_file;
-       struct inode *inode = file->f_dentry->d_inode;
-       struct socket * sock = SOCKET_I(inode);
+       struct socket * sock = file->private_data;
        struct sock *sk = sock->sk;
        
        if (sk)
@@ -1546,8 +1545,7 @@ static void packet_mm_open(struct vm_area_struct *vma)
 static void packet_mm_close(struct vm_area_struct *vma)
 {
        struct file *file = vma->vm_file;
-       struct inode *inode = file->f_dentry->d_inode;
-       struct socket * sock = SOCKET_I(inode);
+       struct socket * sock = file->private_data;
        struct sock *sk = sock->sk;
        
        if (sk)
index 5480caf8ccc2e0dd2141c8058db5b37c05c14dcd..3077878ed4f09fdc1a9a1bcf0b1303084f098641 100644 (file)
@@ -41,7 +41,7 @@
 #include <net/rose.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <net/ip.h>
 #include <net/arp.h>
 
@@ -1363,6 +1363,8 @@ static void rose_info_stop(struct seq_file *seq, void *v)
 
 static int rose_info_show(struct seq_file *seq, void *v)
 {
+       char buf[11];
+
        if (v == SEQ_START_TOKEN)
                seq_puts(seq, 
                         "dest_addr  dest_call src_addr   src_call  dev   lci neigh st vs vr va   t  t1  t2  t3  hb    idle Snd-Q Rcv-Q inode\n");
@@ -1380,12 +1382,12 @@ static int rose_info_show(struct seq_file *seq, void *v)
                
                seq_printf(seq, "%-10s %-9s ",
                        rose2asc(&rose->dest_addr),
-                       ax2asc(&rose->dest_call));
+                       ax2asc(buf, &rose->dest_call));
 
                if (ax25cmp(&rose->source_call, &null_ax25_address) == 0)
                        callsign = "??????-?";
                else
-                       callsign = ax2asc(&rose->source_call);
+                       callsign = ax2asc(buf, &rose->source_call);
 
                seq_printf(seq,
                           "%-10s %-9s %-5s %3.3X %05d  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n",
index ef475a1bb1ba6d84d91b7db4c1c20045b80cb880..8348d33f1efefceb64472f52577067c3550931bf 100644 (file)
@@ -26,8 +26,7 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/ip.h>                    /* For ip_rcv */
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
index 25da6f699fd03c7b748cca110d42eb68eb54da27..e556d92c0bc4d2eb5883acda48b051a608a10d9f 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/fcntl.h>
@@ -851,6 +851,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
        unsigned char cause, diagnostic;
        struct net_device *dev;
        int len, res = 0;
+       char buf[11];
 
 #if 0
        if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT)
@@ -876,7 +877,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
 
        if (rose_neigh == NULL) {
                printk("rose_route : unknown neighbour or device %s\n",
-                      ax2asc(&ax25->dest_addr));
+                      ax2asc(buf, &ax25->dest_addr));
                goto out;
        }
 
@@ -1178,6 +1179,7 @@ static void rose_neigh_stop(struct seq_file *seq, void *v)
 
 static int rose_neigh_show(struct seq_file *seq, void *v)
 {
+       char buf[11];
        int i;
 
        if (v == SEQ_START_TOKEN)
@@ -1189,7 +1191,7 @@ static int rose_neigh_show(struct seq_file *seq, void *v)
                /* if (!rose_neigh->loopback) { */
                seq_printf(seq, "%05d %-9s %-4s   %3d %3d  %3s     %3s %3lu %3lu",
                           rose_neigh->number,
-                          (rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(&rose_neigh->callsign),
+                          (rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(buf, &rose_neigh->callsign),
                           rose_neigh->dev ? rose_neigh->dev->name : "???",
                           rose_neigh->count,
                           rose_neigh->use,
@@ -1200,7 +1202,7 @@ static int rose_neigh_show(struct seq_file *seq, void *v)
 
                if (rose_neigh->digipeat != NULL) {
                        for (i = 0; i < rose_neigh->digipeat->ndigi; i++)
-                               seq_printf(seq, " %s", ax2asc(&rose_neigh->digipeat->calls[i]));
+                               seq_printf(seq, " %s", ax2asc(buf, &rose_neigh->digipeat->calls[i]));
                }
 
                seq_puts(seq, "\n");
@@ -1260,6 +1262,8 @@ static void rose_route_stop(struct seq_file *seq, void *v)
 
 static int rose_route_show(struct seq_file *seq, void *v)
 {
+       char buf[11];
+
        if (v == SEQ_START_TOKEN)
                seq_puts(seq, 
                         "lci  address     callsign   neigh  <-> lci  address     callsign   neigh\n");
@@ -1271,7 +1275,7 @@ static int rose_route_show(struct seq_file *seq, void *v)
                                   "%3.3X  %-10s  %-9s  %05d      ",
                                   rose_route->lci1,
                                   rose2asc(&rose_route->src_addr),
-                                  ax2asc(&rose_route->src_call),
+                                  ax2asc(buf, &rose_route->src_call),
                                   rose_route->neigh1->number);
                else 
                        seq_puts(seq, 
@@ -1282,7 +1286,7 @@ static int rose_route_show(struct seq_file *seq, void *v)
                                   "%3.3X  %-10s  %-9s  %05d\n",
                                rose_route->lci2,
                                rose2asc(&rose_route->dest_addr),
-                               ax2asc(&rose_route->dest_call),
+                               ax2asc(buf, &rose_route->dest_call),
                                rose_route->neigh2->number);
                 else 
                         seq_puts(seq,
index 7db7e1cedc3aed3e0cb07ebb5630df776cbb16ad..02891ce2db37b3ee52c118f9fcb4ca876ccc18ff 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
@@ -74,7 +74,7 @@ void rose_requeue_frames(struct sock *sk)
                if (skb_prev == NULL)
                        skb_queue_head(&sk->sk_write_queue, skb);
                else
-                       skb_append(skb_prev, skb);
+                       skb_append(skb_prev, skb, &sk->sk_write_queue);
                skb_prev = skb;
        }
 }
@@ -400,6 +400,7 @@ static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose)
 {
        unsigned char *p = buffer + 1;
        char *callsign;
+       char buf[11];
        int len, nb;
 
        /* National Facilities */
@@ -456,7 +457,7 @@ static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose)
 
        *p++ = FAC_CCITT_DEST_NSAP;
 
-       callsign = ax2asc(&rose->dest_call);
+       callsign = ax2asc(buf, &rose->dest_call);
 
        *p++ = strlen(callsign) + 10;
        *p++ = (strlen(callsign) + 9) * 2;              /* ??? */
@@ -471,7 +472,7 @@ static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose)
 
        *p++ = FAC_CCITT_SRC_NSAP;
 
-       callsign = ax2asc(&rose->source_call);
+       callsign = ax2asc(buf, &rose->source_call);
 
        *p++ = strlen(callsign) + 10;
        *p++ = (strlen(callsign) + 9) * 2;              /* ??? */
index 84dd4403f792d3c566cb0625965e8b902bcbbdf6..50ae0371dab872e1ee0b51d11362d8f7de532f8b 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
index 9bce7794130af0e3b3bad3988cbbf350a51f642a..122c086ee2dbfc00f3cff0a0813919fb303ff03f 100644 (file)
@@ -330,7 +330,7 @@ static int rxrpc_incoming_msg(struct rxrpc_transport *trans,
 
        msg->trans = trans;
        msg->state = RXRPC_MSG_RECEIVED;
-       msg->stamp = pkt->stamp;
+       skb_get_timestamp(pkt, &msg->stamp);
        if (msg->stamp.tv_sec == 0) {
                do_gettimeofday(&msg->stamp); 
                if (pkt->sk) 
index 59d3e71f8b85296c820a0099010d50341d0135fb..45d3bc0812c8b270ea95e7a6c21799d6ec42273b 100644 (file)
@@ -491,6 +491,7 @@ config NET_EMATCH_TEXT
        depends on NET_EMATCH
        select TEXTSEARCH
        select TEXTSEARCH_KMP
+       select TEXTSEARCH_BM
        select TEXTSEARCH_FSM
        ---help---
          Say Y here if you want to be ablt to classify packets based on
index 249c61936ea0391f30bddb767117d928ff958625..8aebe8f6d271b3876e5e6730829c3b4bf1cc4c63 100644 (file)
@@ -165,7 +165,7 @@ int tcf_action_exec(struct sk_buff *skb, struct tc_action *act,
        while ((a = act) != NULL) {
 repeat:
                if (a->ops && a->ops->act) {
-                       ret = a->ops->act(&skb, a);
+                       ret = a->ops->act(&skb, a, res);
                        if (TC_MUNGED & skb->tc_verd) {
                                /* copied already, allow trampling */
                                skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);
@@ -179,11 +179,6 @@ repeat:
                act = a->next;
        }
 exec_done:
-       if (skb->tc_classid > 0) {
-               res->classid = skb->tc_classid;
-               res->class = 0;
-               skb->tc_classid = 0;
-       }
        return ret;
 }
 
@@ -598,7 +593,7 @@ static int tca_action_flush(struct rtattr *rta, struct nlmsghdr *n, u32 pid)
        nlh->nlmsg_flags |= NLM_F_ROOT;
        module_put(a->ops->owner);
        kfree(a);
-       err = rtnetlink_send(skb, pid, RTMGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
+       err = rtnetlink_send(skb, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
        if (err > 0)
                return 0;
 
@@ -661,7 +656,7 @@ tca_action_gd(struct rtattr *rta, struct nlmsghdr *n, u32 pid, int event)
 
                /* now do the delete */
                tcf_action_destroy(head, 0);
-               ret = rtnetlink_send(skb, pid, RTMGRP_TC,
+               ret = rtnetlink_send(skb, pid, RTNLGRP_TC,
                                     n->nlmsg_flags&NLM_F_ECHO);
                if (ret > 0)
                        return 0;
@@ -703,9 +698,9 @@ static int tcf_add_notify(struct tc_action *a, u32 pid, u32 seq, int event,
        x->rta_len = skb->tail - (u8*)x;
        
        nlh->nlmsg_len = skb->tail - b;
-       NETLINK_CB(skb).dst_groups = RTMGRP_TC;
+       NETLINK_CB(skb).dst_group = RTNLGRP_TC;
        
-       err = rtnetlink_send(skb, pid, RTMGRP_TC, flags&NLM_F_ECHO);
+       err = rtnetlink_send(skb, pid, RTNLGRP_TC, flags&NLM_F_ECHO);
        if (err > 0)
                err = 0;
        return err;
index 3b5714ef4d1af2463d127589d7aa8af91c166384..b4d89fbb378212966b93d9cbc25596ce8add064c 100644 (file)
@@ -367,7 +367,7 @@ static int tfilter_notify(struct sk_buff *oskb, struct nlmsghdr *n,
                return -EINVAL;
        }
 
-       return rtnetlink_send(skb, pid, RTMGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
+       return rtnetlink_send(skb, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
 }
 
 struct tcf_dump_args
index a811c89fef7fd105e98f2b2dadf1518ff3eb0847..d1c6d542912a418a89fe47c67870aed328b029a1 100644 (file)
@@ -135,7 +135,7 @@ tcf_gact_cleanup(struct tc_action *a, int bind)
 }
 
 static int
-tcf_gact(struct sk_buff **pskb, struct tc_action *a)
+tcf_gact(struct sk_buff **pskb, struct tc_action *a, struct tcf_result *res)
 {
        struct tcf_gact *p = PRIV(a, gact);
        struct sk_buff *skb = *pskb;
index b114d994d5236002c8faaacc740c89138bffe2f7..f50136eed211a3e4b4a8936525e4a17b165f6c0c 100644 (file)
@@ -201,7 +201,7 @@ tcf_ipt_cleanup(struct tc_action *a, int bind)
 }
 
 static int
-tcf_ipt(struct sk_buff **pskb, struct tc_action *a)
+tcf_ipt(struct sk_buff **pskb, struct tc_action *a, struct tcf_result *res)
 {
        int ret = 0, result = 0;
        struct tcf_ipt *p = PRIV(a, ipt);
index f309ce336803480b090e9100d7cc2978aea78b90..20d06916dc0b7a4ac576f4ef06b78dc41484963b 100644 (file)
@@ -158,7 +158,7 @@ tcf_mirred_cleanup(struct tc_action *a, int bind)
 }
 
 static int
-tcf_mirred(struct sk_buff **pskb, struct tc_action *a)
+tcf_mirred(struct sk_buff **pskb, struct tc_action *a, struct tcf_result *res)
 {
        struct tcf_mirred *p = PRIV(a, mirred);
        struct net_device *dev;
index 678be6a645fbf41548d2c120ccd278ed0e03042a..767d24f4610ec8e516ae0ec3847043e70fa2f353 100644 (file)
@@ -130,7 +130,7 @@ tcf_pedit_cleanup(struct tc_action *a, int bind)
 }
 
 static int
-tcf_pedit(struct sk_buff **pskb, struct tc_action *a)
+tcf_pedit(struct sk_buff **pskb, struct tc_action *a, struct tcf_result *res)
 {
        struct tcf_pedit *p = PRIV(a, pedit);
        struct sk_buff *skb = *pskb;
index c03545faf5233c23e2b9c0dabbd4f4c17493c9e2..eb39fb2f39b6da90c76a24698289212864dfb354 100644 (file)
@@ -284,7 +284,8 @@ static int tcf_act_police_cleanup(struct tc_action *a, int bind)
        return 0;
 }
 
-static int tcf_act_police(struct sk_buff **pskb, struct tc_action *a)
+static int tcf_act_police(struct sk_buff **pskb, struct tc_action *a,
+                          struct tcf_result *res)
 {
        psched_time_t now;
        struct sk_buff *skb = *pskb;
index b9a069af4a02f24353b31f144d574cfd8d57904d..737681cb9a928d65800a7e85661b034764683840 100644 (file)
@@ -816,7 +816,7 @@ static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n,
        }
 
        if (skb->len)
-               return rtnetlink_send(skb, pid, RTMGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
+               return rtnetlink_send(skb, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
 
 err_out:
        kfree_skb(skb);
@@ -1040,7 +1040,7 @@ static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n,
                return -EINVAL;
        }
 
-       return rtnetlink_send(skb, pid, RTMGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
+       return rtnetlink_send(skb, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
 }
 
 struct qdisc_dump_args
index 0d066c965342e5bbb93bcbe2a80cd4d39653028b..99ceb91f0150a158aa926c3c3ebeb13d1860cbd4 100644 (file)
@@ -238,6 +238,20 @@ static void dev_watchdog_down(struct net_device *dev)
        spin_unlock_bh(&dev->xmit_lock);
 }
 
+void netif_carrier_on(struct net_device *dev)
+{
+       if (test_and_clear_bit(__LINK_STATE_NOCARRIER, &dev->state))
+               linkwatch_fire_event(dev);
+       if (netif_running(dev))
+               __netdev_watchdog_up(dev);
+}
+
+void netif_carrier_off(struct net_device *dev)
+{
+       if (!test_and_set_bit(__LINK_STATE_NOCARRIER, &dev->state))
+               linkwatch_fire_event(dev);
+}
+
 /* "NOOP" scheduler: the best scheduler, recommended for all interfaces
    under all circumstances. It is difficult to invent anything faster or
    cheaper.
@@ -600,6 +614,8 @@ void dev_shutdown(struct net_device *dev)
 }
 
 EXPORT_SYMBOL(__netdev_watchdog_up);
+EXPORT_SYMBOL(netif_carrier_on);
+EXPORT_SYMBOL(netif_carrier_off);
 EXPORT_SYMBOL(noop_qdisc);
 EXPORT_SYMBOL(noop_qdisc_ops);
 EXPORT_SYMBOL(qdisc_create_dflt);
index 3ab4c675ab5dad934834cd50ffbabc5192d0ec0b..8a6ae4f491e872dd3b1f381ab29ef98b4656011c 100644 (file)
@@ -44,7 +44,7 @@ static DEFINE_RWLOCK(simp_lock);
 #include <net/pkt_act.h>
 #include <net/act_generic.h>
 
-static int tcf_simp(struct sk_buff **pskb, struct tc_action *a)
+static int tcf_simp(struct sk_buff **pskb, struct tc_action *a, struct tcf_result *res)
 {
        struct sk_buff *skb = *pskb;
        struct tcf_defact *p = PRIV(a, defact);
index e47ac0d1a6d64f679bf963113b1989d93e4d4c44..e22ccd6559658592179505b6572246ad9ee37fc1 100644 (file)
@@ -193,8 +193,7 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep)
        sctp_unhash_endpoint(ep);
 
        /* Free up the HMAC transform. */
-       if (sctp_sk(ep->base.sk)->hmac)
-               sctp_crypto_free_tfm(sctp_sk(ep->base.sk)->hmac);
+       sctp_crypto_free_tfm(sctp_sk(ep->base.sk)->hmac);
 
        /* Cleanup. */
        sctp_inq_free(&ep->base.inqueue);
index 742be9171b7df4b1741fad84852f47e6193c03b9..28f32243397f3b1b9755f42fcc70fa824d92dea0 100644 (file)
@@ -236,8 +236,8 @@ int sctp_rcv(struct sk_buff *skb)
        }
 
        /* SCTP seems to always need a timestamp right now (FIXME) */
-       if (skb->stamp.tv_sec == 0) {
-               do_gettimeofday(&skb->stamp);
+       if (skb->tstamp.off_sec == 0) {
+               __net_timestamp(skb);
                sock_enable_timestamp(sk); 
        }
 
index e9b2fd480d6153edd54d6e045140bb4e023bcefd..fa3be2b8fb5ffcaa88ac19e5919f7703461f90ef 100644 (file)
@@ -66,8 +66,8 @@
 #include <linux/seq_file.h>
 
 #include <net/protocol.h>
-#include <net/tcp.h>
 #include <net/ndisc.h>
+#include <net/ip.h>
 #include <net/ipv6.h>
 #include <net/transp_v6.h>
 #include <net/addrconf.h>
@@ -641,10 +641,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
        else
                newinet->pmtudisc = IP_PMTUDISC_WANT;
 
-#ifdef INET_REFCNT_DEBUG
-       atomic_inc(&inet6_sock_nr);
-       atomic_inc(&inet_sock_nr);
-#endif
+       sk_refcnt_debug_inc(newsk);
 
        if (newsk->sk_prot->init(newsk)) {
                sk_common_release(newsk);
index ce9245e71fca9b0694c473c4cc21b7eb8c5ba058..e7025be77691c096d23807fbc75818d00610380e 100644 (file)
@@ -62,7 +62,7 @@
 /* Global data structures. */
 struct sctp_globals sctp_globals;
 struct proc_dir_entry  *proc_net_sctp;
-DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics);
+DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics) __read_mostly;
 
 struct idr sctp_assocs_id;
 DEFINE_SPINLOCK(sctp_assocs_id_lock);
@@ -78,8 +78,8 @@ static struct sctp_pf *sctp_pf_inet_specific;
 static struct sctp_af *sctp_af_v4_specific;
 static struct sctp_af *sctp_af_v6_specific;
 
-kmem_cache_t *sctp_chunk_cachep;
-kmem_cache_t *sctp_bucket_cachep;
+kmem_cache_t *sctp_chunk_cachep __read_mostly;
+kmem_cache_t *sctp_bucket_cachep __read_mostly;
 
 extern int sctp_snmp_proc_init(void);
 extern int sctp_snmp_proc_exit(void);
@@ -593,9 +593,7 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk,
        newinet->mc_index = 0;
        newinet->mc_list = NULL;
 
-#ifdef INET_REFCNT_DEBUG
-       atomic_inc(&inet_sock_nr);
-#endif
+       sk_refcnt_debug_inc(newsk);
 
        if (newsk->sk_prot->init(newsk)) {
                sk_common_release(newsk);
@@ -1244,6 +1242,10 @@ SCTP_STATIC __exit void sctp_exit(void)
 module_init(sctp_init);
 module_exit(sctp_exit);
 
+/*
+ * __stringify doesn't likes enums, so use IPPROTO_SCTP value (132) directly.
+ */
+MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-132");
 MODULE_AUTHOR("Linux Kernel SCTP developers <lksctp-developers@lists.sourceforge.net>");
 MODULE_DESCRIPTION("Support for the SCTP protocol (RFC2960)");
 MODULE_LICENSE("GPL");
index 00d32b7c8266a055b81d1b6569dbb1c59ef6ac46..3868a8d70cc058332f8918a5bab47b6233530c68 100644 (file)
@@ -1362,6 +1362,7 @@ struct sctp_association *sctp_unpack_cookie(
        char *key;
        sctp_scope_t scope;
        struct sk_buff *skb = chunk->skb;
+       struct timeval tv;
 
        headersize = sizeof(sctp_chunkhdr_t) + SCTP_SECRET_SIZE;
        bodysize = ntohs(chunk->chunk_hdr->length) - headersize;
@@ -1434,7 +1435,8 @@ no_hmac:
         * an association, there is no need to check cookie's expiration
         * for init collision case of lost COOKIE ACK.
         */
-       if (!asoc && tv_lt(bear_cookie->expiration, skb->stamp)) {
+       skb_get_timestamp(skb, &tv);
+       if (!asoc && tv_lt(bear_cookie->expiration, tv)) {
                __u16 len;
                /*
                 * Section 3.3.10.3 Stale Cookie Error (3)
@@ -1447,10 +1449,9 @@ no_hmac:
                len = ntohs(chunk->chunk_hdr->length);
                *errp = sctp_make_op_error_space(asoc, chunk, len);
                if (*errp) {
-                       suseconds_t usecs = (skb->stamp.tv_sec -
+                       suseconds_t usecs = (tv.tv_sec -
                                bear_cookie->expiration.tv_sec) * 1000000L +
-                               skb->stamp.tv_usec -
-                               bear_cookie->expiration.tv_usec;
+                               tv.tv_usec - bear_cookie->expiration.tv_usec;
 
                        usecs = htonl(usecs);
                        sctp_init_cause(*errp, SCTP_ERROR_STALE_COOKIE,
index 091a66f06a35a7518f9f1d2ab8143d0631b6efec..91ec8c9369135ade53002ff4a5bdebc139e7a80a 100644 (file)
@@ -4194,8 +4194,7 @@ out:
        sctp_release_sock(sk);
        return err;
 cleanup:
-       if (tfm)
-               sctp_crypto_free_tfm(tfm);
+       sctp_crypto_free_tfm(tfm);
        goto out;
 }
 
@@ -4892,7 +4891,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
        sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
                event = sctp_skb2event(skb);
                if (event->asoc == assoc) {
-                       __skb_unlink(skb, skb->list);
+                       __skb_unlink(skb, &oldsk->sk_receive_queue);
                        __skb_queue_tail(&newsk->sk_receive_queue, skb);
                }
        }
@@ -4921,7 +4920,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
                sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
                        event = sctp_skb2event(skb);
                        if (event->asoc == assoc) {
-                               __skb_unlink(skb, skb->list);
+                               __skb_unlink(skb, &oldsp->pd_lobby);
                                __skb_queue_tail(queue, skb);
                        }
                }
index dc4893474f186e68b93225cdba82ba71000f9831..75b28dd634fe3e0c06b0a556716b7c4755b7c816 100644 (file)
@@ -42,6 +42,7 @@
  */
 
 #include <net/sctp/structs.h>
+#include <net/sctp/sctp.h>
 #include <linux/sysctl.h>
 
 static ctl_handler sctp_sysctl_jiffies_ms;
index 8bbc279d6c99378934a8f4d2fb3943a04bd70143..ec2c857eae7fecfd6800940975c6f91d4741d995 100644 (file)
@@ -50,9 +50,9 @@
 
 /* Forward declarations for internal helpers.  */
 static struct sctp_ulpevent * sctp_ulpq_reasm(struct sctp_ulpq *ulpq,
-                                               struct sctp_ulpevent *);
+                                             struct sctp_ulpevent *);
 static struct sctp_ulpevent * sctp_ulpq_order(struct sctp_ulpq *,
-                                               struct sctp_ulpevent *);
+                                             struct sctp_ulpevent *);
 
 /* 1st Level Abstractions */
 
@@ -125,7 +125,9 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
                event = sctp_ulpq_order(ulpq, event);
        }
 
-       /* Send event to the ULP.  */
+       /* Send event to the ULP.  'event' is the sctp_ulpevent for
+        * very first SKB on the 'temp' list.
+        */
        if (event)
                sctp_ulpq_tail_event(ulpq, event);
 
@@ -158,14 +160,18 @@ static int sctp_ulpq_clear_pd(struct sctp_ulpq *ulpq)
        return sctp_clear_pd(ulpq->asoc->base.sk);
 }
 
-
-
+/* If the SKB of 'event' is on a list, it is the first such member
+ * of that list.
+ */
 int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
 {
        struct sock *sk = ulpq->asoc->base.sk;
-       struct sk_buff_head *queue;
+       struct sk_buff_head *queue, *skb_list;
+       struct sk_buff *skb = sctp_event2skb(event);
        int clear_pd = 0;
 
+       skb_list = (struct sk_buff_head *) skb->prev;
+
        /* If the socket is just going to throw this away, do not
         * even try to deliver it.
         */
@@ -197,10 +203,10 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
        /* If we are harvesting multiple skbs they will be
         * collected on a list.
         */
-       if (sctp_event2skb(event)->list)
-               sctp_skb_list_tail(sctp_event2skb(event)->list, queue);
+       if (skb_list)
+               sctp_skb_list_tail(skb_list, queue);
        else
-               __skb_queue_tail(queue, sctp_event2skb(event));
+               __skb_queue_tail(queue, skb);
 
        /* Did we just complete partial delivery and need to get
         * rolling again?  Move pending data to the receive
@@ -214,10 +220,11 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
        return 1;
 
 out_free:
-       if (sctp_event2skb(event)->list)
-               sctp_queue_purge_ulpevents(sctp_event2skb(event)->list);
+       if (skb_list)
+               sctp_queue_purge_ulpevents(skb_list);
        else
                sctp_ulpevent_free(event);
+
        return 0;
 }
 
@@ -269,7 +276,7 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq,
  * payload was fragmented on the way and ip had to reassemble them.
  * We add the rest of skb's to the first skb's fraglist.
  */
-static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *f_frag, struct sk_buff *l_frag)
+static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *queue, struct sk_buff *f_frag, struct sk_buff *l_frag)
 {
        struct sk_buff *pos;
        struct sctp_ulpevent *event;
@@ -294,7 +301,7 @@ static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *f_frag,
                skb_shinfo(f_frag)->frag_list = pos;
 
        /* Remove the first fragment from the reassembly queue.  */
-       __skb_unlink(f_frag, f_frag->list);
+       __skb_unlink(f_frag, queue);
        while (pos) {
 
                pnext = pos->next;
@@ -304,7 +311,7 @@ static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *f_frag,
                f_frag->data_len += pos->len;
 
                /* Remove the fragment from the reassembly queue.  */
-               __skb_unlink(pos, pos->list);
+               __skb_unlink(pos, queue);
        
                /* Break if we have reached the last fragment.  */
                if (pos == l_frag)
@@ -375,7 +382,7 @@ static inline struct sctp_ulpevent *sctp_ulpq_retrieve_reassembled(struct sctp_u
 done:
        return retval;
 found:
-       retval = sctp_make_reassembled_event(first_frag, pos);
+       retval = sctp_make_reassembled_event(&ulpq->reasm, first_frag, pos);
        if (retval)
                retval->msg_flags |= MSG_EOR;
        goto done;
@@ -435,7 +442,7 @@ static inline struct sctp_ulpevent *sctp_ulpq_retrieve_partial(struct sctp_ulpq
         * further.
         */
 done:
-       retval = sctp_make_reassembled_event(first_frag, last_frag);
+       retval = sctp_make_reassembled_event(&ulpq->reasm, first_frag, last_frag);
        if (retval && is_last)
                retval->msg_flags |= MSG_EOR;
 
@@ -527,7 +534,7 @@ static inline struct sctp_ulpevent *sctp_ulpq_retrieve_first(struct sctp_ulpq *u
         * further.
         */
 done:
-       retval = sctp_make_reassembled_event(first_frag, last_frag);
+       retval = sctp_make_reassembled_event(&ulpq->reasm, first_frag, last_frag);
        return retval;
 }
 
@@ -537,6 +544,7 @@ done:
 static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
                                              struct sctp_ulpevent *event)
 {
+       struct sk_buff_head *event_list;
        struct sk_buff *pos, *tmp;
        struct sctp_ulpevent *cevent;
        struct sctp_stream *in;
@@ -547,6 +555,8 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
        ssn = event->ssn;
        in  = &ulpq->asoc->ssnmap->in;
 
+       event_list = (struct sk_buff_head *) sctp_event2skb(event)->prev;
+
        /* We are holding the chunks by stream, by SSN.  */
        sctp_skb_for_each(pos, &ulpq->lobby, tmp) {
                cevent = (struct sctp_ulpevent *) pos->cb;
@@ -567,10 +577,10 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
                /* Found it, so mark in the ssnmap. */
                sctp_ssn_next(in, sid);
 
-               __skb_unlink(pos, pos->list);
+               __skb_unlink(pos, &ulpq->lobby);
 
                /* Attach all gathered skbs to the event.  */
-               __skb_queue_tail(sctp_event2skb(event)->list, pos);
+               __skb_queue_tail(event_list, pos);
        }
 }
 
@@ -626,7 +636,7 @@ static inline void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq,
 }
 
 static struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq,
-                                               struct sctp_ulpevent *event)
+                                            struct sctp_ulpevent *event)
 {
        __u16 sid, ssn;
        struct sctp_stream *in;
@@ -667,7 +677,7 @@ static inline void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq)
 {
        struct sk_buff *pos, *tmp;
        struct sctp_ulpevent *cevent;
-       struct sctp_ulpevent *event = NULL;
+       struct sctp_ulpevent *event;
        struct sctp_stream *in;
        struct sk_buff_head temp;
        __u16 csid, cssn;
@@ -675,6 +685,8 @@ static inline void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq)
        in  = &ulpq->asoc->ssnmap->in;
 
        /* We are holding the chunks by stream, by SSN.  */
+       skb_queue_head_init(&temp);
+       event = NULL;
        sctp_skb_for_each(pos, &ulpq->lobby, tmp) {
                cevent = (struct sctp_ulpevent *) pos->cb;
                csid = cevent->stream;
@@ -686,19 +698,20 @@ static inline void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq)
                /* Found it, so mark in the ssnmap. */         
                sctp_ssn_next(in, csid);
 
-               __skb_unlink(pos, pos->list);
+               __skb_unlink(pos, &ulpq->lobby);
                if (!event) {                                           
                        /* Create a temporary list to collect chunks on.  */
                        event = sctp_skb2event(pos);
-                       skb_queue_head_init(&temp);
                        __skb_queue_tail(&temp, sctp_event2skb(event));
                } else {
                        /* Attach all gathered skbs to the event.  */
-                       __skb_queue_tail(sctp_event2skb(event)->list, pos);
+                       __skb_queue_tail(&temp, pos);
                }
        }
 
-       /* Send event to the ULP.  */
+       /* Send event to the ULP.  'event' is the sctp_ulpevent for
+        * very first SKB on the 'temp' list.
+        */
        if (event)
                sctp_ulpq_tail_event(ulpq, event);
 }
index 6f2a178819726b7b878aa22a6d79954b61c1e239..e1bd5d84d7bf11acce8a2c6b73d0f5ac41809d05 100644 (file)
@@ -70,6 +70,8 @@
 #include <linux/seq_file.h>
 #include <linux/wanrouter.h>
 #include <linux/if_bridge.h>
+#include <linux/if_frad.h>
+#include <linux/if_vlan.h>
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/cache.h>
@@ -272,7 +274,7 @@ int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, int __user *ule
 
 #define SOCKFS_MAGIC 0x534F434B
 
-static kmem_cache_t * sock_inode_cachep;
+static kmem_cache_t * sock_inode_cachep __read_mostly;
 
 static struct inode *sock_alloc_inode(struct super_block *sb)
 {
@@ -331,7 +333,7 @@ static struct super_block *sockfs_get_sb(struct file_system_type *fs_type,
        return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC);
 }
 
-static struct vfsmount *sock_mnt;
+static struct vfsmount *sock_mnt __read_mostly;
 
 static struct file_system_type sock_fs_type = {
        .name =         "sockfs",
@@ -404,6 +406,7 @@ int sock_map_fd(struct socket *sock)
                file->f_mode = FMODE_READ | FMODE_WRITE;
                file->f_flags = O_RDWR;
                file->f_pos = 0;
+               file->private_data = sock;
                fd_install(fd, file);
        }
 
@@ -436,6 +439,9 @@ struct socket *sockfd_lookup(int fd, int *err)
                return NULL;
        }
 
+       if (file->f_op == &socket_file_ops)
+               return file->private_data;      /* set in sock_map_fd */
+
        inode = file->f_dentry->d_inode;
        if (!S_ISSOCK(inode->i_mode)) {
                *err = -ENOTSOCK;
@@ -661,7 +667,7 @@ static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf,
        }
        iocb->private = x;
        x->kiocb = iocb;
-       sock = SOCKET_I(iocb->ki_filp->f_dentry->d_inode)
+       sock = iocb->ki_filp->private_data
 
        x->async_msg.msg_name = NULL;
        x->async_msg.msg_namelen = 0;
@@ -703,7 +709,7 @@ static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf,
        }
        iocb->private = x;
        x->kiocb = iocb;
-       sock = SOCKET_I(iocb->ki_filp->f_dentry->d_inode)
+       sock = iocb->ki_filp->private_data
 
        x->async_msg.msg_name = NULL;
        x->async_msg.msg_namelen = 0;
@@ -720,13 +726,13 @@ static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf,
        return __sock_sendmsg(iocb, sock, &x->async_msg, size);
 }
 
-ssize_t sock_sendpage(struct file *file, struct page *page,
-                     int offset, size_t size, loff_t *ppos, int more)
+static ssize_t sock_sendpage(struct file *file, struct page *page,
+                            int offset, size_t size, loff_t *ppos, int more)
 {
        struct socket *sock;
        int flags;
 
-       sock = SOCKET_I(file->f_dentry->d_inode);
+       sock = file->private_data;
 
        flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT;
        if (more)
@@ -735,14 +741,14 @@ ssize_t sock_sendpage(struct file *file, struct page *page,
        return sock->ops->sendpage(sock, page, offset, size, flags);
 }
 
-static int sock_readv_writev(int type, struct inode * inode,
+static int sock_readv_writev(int type,
                             struct file * file, const struct iovec * iov,
                             long count, size_t size)
 {
        struct msghdr msg;
        struct socket *sock;
 
-       sock = SOCKET_I(inode);
+       sock = file->private_data;
 
        msg.msg_name = NULL;
        msg.msg_namelen = 0;
@@ -769,7 +775,7 @@ static ssize_t sock_readv(struct file *file, const struct iovec *vector,
        int i;
         for (i = 0 ; i < count ; i++)
                 tot_len += vector[i].iov_len;
-       return sock_readv_writev(VERIFY_WRITE, file->f_dentry->d_inode,
+       return sock_readv_writev(VERIFY_WRITE,
                                 file, vector, count, tot_len);
 }
        
@@ -780,7 +786,7 @@ static ssize_t sock_writev(struct file *file, const struct iovec *vector,
        int i;
         for (i = 0 ; i < count ; i++)
                 tot_len += vector[i].iov_len;
-       return sock_readv_writev(VERIFY_READ, file->f_dentry->d_inode,
+       return sock_readv_writev(VERIFY_READ,
                                 file, vector, count, tot_len);
 }
 
@@ -834,7 +840,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
        void __user *argp = (void __user *)arg;
        int pid, err;
 
-       sock = SOCKET_I(file->f_dentry->d_inode);
+       sock = file->private_data;
        if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
                err = dev_ioctl(cmd, argp);
        } else
@@ -933,18 +939,18 @@ static unsigned int sock_poll(struct file *file, poll_table * wait)
        /*
         *      We can't return errors to poll, so it's either yes or no. 
         */
-       sock = SOCKET_I(file->f_dentry->d_inode);
+       sock = file->private_data;
        return sock->ops->poll(file, sock, wait);
 }
 
 static int sock_mmap(struct file * file, struct vm_area_struct * vma)
 {
-       struct socket *sock = SOCKET_I(file->f_dentry->d_inode);
+       struct socket *sock = file->private_data;
 
        return sock->ops->mmap(file, sock, vma);
 }
 
-int sock_close(struct inode *inode, struct file *filp)
+static int sock_close(struct inode *inode, struct file *filp)
 {
        /*
         *      It was possible the inode is NULL we were 
@@ -989,7 +995,7 @@ static int sock_fasync(int fd, struct file *filp, int on)
                        return -ENOMEM;
        }
 
-       sock = SOCKET_I(filp->f_dentry->d_inode);
+       sock = filp->private_data;
 
        if ((sk=sock->sk) == NULL) {
                kfree(fna);
@@ -2023,9 +2029,6 @@ int sock_unregister(int family)
        return 0;
 }
 
-
-extern void sk_init(void);
-
 void __init sock_init(void)
 {
        /*
index 5a7265aeaf839c160ee047d9f319b0763fdefe82..ee6ae74cd1b226b2bb7d39655f2a1862e4507c21 100644 (file)
@@ -160,7 +160,7 @@ make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body,
                                " unsupported checksum %d", cksumtype);
                        goto out;
        }
-       if (!(tfm = crypto_alloc_tfm(cksumname, 0)))
+       if (!(tfm = crypto_alloc_tfm(cksumname, CRYPTO_TFM_REQ_MAY_SLEEP)))
                goto out;
        cksum->len = crypto_tfm_alg_digestsize(tfm);
        if ((cksum->data = kmalloc(cksum->len, GFP_KERNEL)) == NULL)
@@ -199,8 +199,7 @@ make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body,
        crypto_digest_final(tfm, cksum->data);
        code = 0;
 out:
-       if (tfm)
-               crypto_free_tfm(tfm);
+       crypto_free_tfm(tfm);
        return code;
 }
 
index cf726510df8e5ad2d6075b8547245f85666d59eb..606a8a82cafbedc84545ec73def5ff2e54054b5c 100644 (file)
@@ -185,12 +185,9 @@ static void
 gss_delete_sec_context_kerberos(void *internal_ctx) {
        struct krb5_ctx *kctx = internal_ctx;
 
-       if (kctx->seq)
-               crypto_free_tfm(kctx->seq);
-       if (kctx->enc)
-               crypto_free_tfm(kctx->enc);
-       if (kctx->mech_used.data)
-               kfree(kctx->mech_used.data);
+       crypto_free_tfm(kctx->seq);
+       crypto_free_tfm(kctx->enc);
+       kfree(kctx->mech_used.data);
        kfree(kctx);
 }
 
index dad05994c3eb3f934c5446460404a92101e3b7c8..6c97d61baa9bfa3a819fa079a132eb745babd081 100644 (file)
@@ -214,14 +214,10 @@ static void
 gss_delete_sec_context_spkm3(void *internal_ctx) {
        struct spkm3_ctx *sctx = internal_ctx;
 
-       if(sctx->derived_integ_key)
-               crypto_free_tfm(sctx->derived_integ_key);
-       if(sctx->derived_conf_key)
-               crypto_free_tfm(sctx->derived_conf_key);
-       if(sctx->share_key.data)
-               kfree(sctx->share_key.data);
-       if(sctx->mech_used.data)
-               kfree(sctx->mech_used.data);
+       crypto_free_tfm(sctx->derived_integ_key);
+       crypto_free_tfm(sctx->derived_conf_key);
+       kfree(sctx->share_key.data);
+       kfree(sctx->mech_used.data);
        kfree(sctx);
 }
 
index 5c8fe3bfc49415195058c8b6c939767d619478bb..e3308195374e635b2ea617d64fc48684c24d1241 100644 (file)
@@ -250,6 +250,7 @@ out:
 }
 
 static struct cache_detail rsi_cache = {
+       .owner          = THIS_MODULE,
        .hash_size      = RSI_HASHMAX,
        .hash_table     = rsi_table,
        .name           = "auth.rpcsec.init",
@@ -436,6 +437,7 @@ out:
 }
 
 static struct cache_detail rsc_cache = {
+       .owner          = THIS_MODULE,
        .hash_size      = RSC_HASHMAX,
        .hash_table     = rsc_table,
        .name           = "auth.rpcsec.context",
@@ -1074,7 +1076,9 @@ gss_svc_init(void)
 void
 gss_svc_shutdown(void)
 {
-       cache_unregister(&rsc_cache);
-       cache_unregister(&rsi_cache);
+       if (cache_unregister(&rsc_cache))
+               printk(KERN_ERR "auth_rpcgss: failed to unregister rsc cache\n");
+       if (cache_unregister(&rsi_cache))
+               printk(KERN_ERR "auth_rpcgss: failed to unregister rsi cache\n");
        svc_auth_unregister(RPC_AUTH_GSS);
 }
index 900f5bc7e3366480426f0674ec4a2ca5c2113f7d..f509e99927675e173f251f44637f976489a0abf1 100644 (file)
@@ -177,7 +177,7 @@ void cache_register(struct cache_detail *cd)
        cd->proc_ent = proc_mkdir(cd->name, proc_net_rpc);
        if (cd->proc_ent) {
                struct proc_dir_entry *p;
-               cd->proc_ent->owner = THIS_MODULE;
+               cd->proc_ent->owner = cd->owner;
                cd->channel_ent = cd->content_ent = NULL;
                
                p = create_proc_entry("flush", S_IFREG|S_IRUSR|S_IWUSR,
@@ -185,7 +185,7 @@ void cache_register(struct cache_detail *cd)
                cd->flush_ent =  p;
                if (p) {
                        p->proc_fops = &cache_flush_operations;
-                       p->owner = THIS_MODULE;
+                       p->owner = cd->owner;
                        p->data = cd;
                }
  
@@ -195,7 +195,7 @@ void cache_register(struct cache_detail *cd)
                        cd->channel_ent = p;
                        if (p) {
                                p->proc_fops = &cache_file_operations;
-                               p->owner = THIS_MODULE;
+                               p->owner = cd->owner;
                                p->data = cd;
                        }
                }
@@ -205,7 +205,7 @@ void cache_register(struct cache_detail *cd)
                        cd->content_ent = p;
                        if (p) {
                                p->proc_fops = &content_file_operations;
-                               p->owner = THIS_MODULE;
+                               p->owner = cd->owner;
                                p->data = cd;
                        }
                }
index 554f224c0445b11e8e38377226934ca7e9c8b0e5..ded6c63f11ec968263890ebded1f65ea31f1f674 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Userland/kernel interface for rpcauth_gss.
  * Code shamelessly plagiarized from fs/nfsd/nfsctl.c
- * and fs/driverfs/inode.c
+ * and fs/sysfs/inode.c
  *
  * Copyright (c) 2002, Trond Myklebust <trond.myklebust@fys.uio.no>
  *
 #include <linux/workqueue.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
 
-static struct vfsmount *rpc_mount;
+static struct vfsmount *rpc_mount __read_mostly;
 static int rpc_mount_count;
 
 static struct file_system_type rpc_pipe_fs_type;
 
 
-static kmem_cache_t *rpc_inode_cachep;
+static kmem_cache_t *rpc_inode_cachep __read_mostly;
 
 #define RPC_UPCALL_TIMEOUT (30*HZ)
 
index 2d9eb7fbd5213323f870fa25286512e466a7e764..f3104035e35d446828a0d29b92e947dfb7dfdcc5 100644 (file)
@@ -34,10 +34,10 @@ static int                  rpc_task_id;
 #define RPC_BUFFER_MAXSIZE     (2048)
 #define RPC_BUFFER_POOLSIZE    (8)
 #define RPC_TASK_POOLSIZE      (8)
-static kmem_cache_t    *rpc_task_slabp;
-static kmem_cache_t    *rpc_buffer_slabp;
-static mempool_t       *rpc_task_mempool;
-static mempool_t       *rpc_buffer_mempool;
+static kmem_cache_t    *rpc_task_slabp __read_mostly;
+static kmem_cache_t    *rpc_buffer_slabp __read_mostly;
+static mempool_t       *rpc_task_mempool __read_mostly;
+static mempool_t       *rpc_buffer_mempool __read_mostly;
 
 static void                    __rpc_default_timer(struct rpc_task *task);
 static void                    rpciod_killall(void);
index 9b67dc19944c0d0c7d40e96852b19359fae5c181..4979f226e285f57117cc8daa71667f64549b0b7a 100644 (file)
@@ -35,13 +35,13 @@ static int rpc_proc_show(struct seq_file *seq, void *v) {
        int             i, j;
 
        seq_printf(seq,
-               "net %d %d %d %d\n",
+               "net %u %u %u %u\n",
                        statp->netcnt,
                        statp->netudpcnt,
                        statp->nettcpcnt,
                        statp->nettcpconn);
        seq_printf(seq,
-               "rpc %d %d %d\n",
+               "rpc %u %u %u\n",
                        statp->rpccnt,
                        statp->rpcretrans,
                        statp->rpcauthrefresh);
@@ -50,10 +50,10 @@ static int rpc_proc_show(struct seq_file *seq, void *v) {
                const struct rpc_version *vers = prog->version[i];
                if (!vers)
                        continue;
-               seq_printf(seq, "proc%d %d",
+               seq_printf(seq, "proc%u %u",
                                        vers->number, vers->nrprocs);
                for (j = 0; j < vers->nrprocs; j++)
-                       seq_printf(seq, " %d",
+                       seq_printf(seq, " %u",
                                        vers->procs[j].p_count);
                seq_putc(seq, '\n');
        }
@@ -83,13 +83,13 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
        int             i, j;
 
        seq_printf(seq,
-               "net %d %d %d %d\n",
+               "net %u %u %u %u\n",
                        statp->netcnt,
                        statp->netudpcnt,
                        statp->nettcpcnt,
                        statp->nettcpconn);
        seq_printf(seq,
-               "rpc %d %d %d %d %d\n",
+               "rpc %u %u %u %u %u\n",
                        statp->rpccnt,
                        statp->rpcbadfmt+statp->rpcbadauth+statp->rpcbadclnt,
                        statp->rpcbadfmt,
@@ -99,9 +99,9 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
        for (i = 0; i < prog->pg_nvers; i++) {
                if (!(vers = prog->pg_vers[i]) || !(proc = vers->vs_proc))
                        continue;
-               seq_printf(seq, "proc%d %d", i, vers->vs_nproc);
+               seq_printf(seq, "proc%d %u", i, vers->vs_nproc);
                for (j = 0; j < vers->vs_nproc; j++, proc++)
-                       seq_printf(seq, " %d", proc->pc_count);
+                       seq_printf(seq, " %u", proc->pc_count);
                seq_putc(seq, '\n');
        }
 }
index 62a0734952766b56ae48e1053dce92f91ecf278c..ed48ff022d3529055c4a508ca86db9379052107d 100644 (file)
@@ -176,8 +176,10 @@ cleanup_sunrpc(void)
 {
        unregister_rpc_pipefs();
        rpc_destroy_mempool();
-       cache_unregister(&auth_domain_cache);
-       cache_unregister(&ip_map_cache);
+       if (cache_unregister(&auth_domain_cache))
+               printk(KERN_ERR "sunrpc: failed to unregister auth_domain cache\n");
+       if (cache_unregister(&ip_map_cache))
+               printk(KERN_ERR "sunrpc: failed to unregister ip_map cache\n");
 #ifdef RPC_DEBUG
        rpc_unregister_sysctl();
 #endif
index bde8147ef2db54dc35ad8dbf77dd43994aae84fa..dda4f0c63511ca74475e9d1259bc73c0db9c47ef 100644 (file)
@@ -143,6 +143,7 @@ static void auth_domain_drop(struct cache_head *item, struct cache_detail *cd)
 
 
 struct cache_detail auth_domain_cache = {
+       .owner          = THIS_MODULE,
        .hash_size      = DN_HASHMAX,
        .hash_table     = auth_domain_table,
        .name           = "auth.domain",
index d6baf6fdf8a97d43f8569d9fef0bc762ebc616b9..cac2e774dd813669d810f464a2263f2c08354a6a 100644 (file)
@@ -242,6 +242,7 @@ static int ip_map_show(struct seq_file *m,
        
 
 struct cache_detail ip_map_cache = {
+       .owner          = THIS_MODULE,
        .hash_size      = IP_HASHMAX,
        .hash_table     = ip_table,
        .name           = "auth.unix.ip",
index d0c3120d0233a43b9089b78c71bed97e627de923..05fe2e735538e15999a5b018f19b5c8474573dc7 100644 (file)
@@ -34,7 +34,7 @@
 #include <net/sock.h>
 #include <net/checksum.h>
 #include <net/ip.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
 
@@ -584,13 +584,16 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
                /* possibly an icmp error */
                dprintk("svc: recvfrom returned error %d\n", -err);
        }
-       if (skb->stamp.tv_sec == 0) {
-               skb->stamp.tv_sec = xtime.tv_sec; 
-               skb->stamp.tv_usec = xtime.tv_nsec / NSEC_PER_USEC; 
+       if (skb->tstamp.off_sec == 0) {
+               struct timeval tv;
+
+               tv.tv_sec = xtime.tv_sec;
+               tv.tv_usec = xtime.tv_nsec * 1000;
+               skb_set_timestamp(skb, &tv);
                /* Don't enable netstamp, sunrpc doesn't 
                   need that much accuracy */
        }
-       svsk->sk_sk->sk_stamp = skb->stamp;
+       skb_get_timestamp(skb, &svsk->sk_sk->sk_stamp);
        set_bit(SK_DATA, &svsk->sk_flags); /* there may be more data... */
 
        /*
index 3f6e31069c547ebb8b7a850da018f1a3e1169234..c5241fcbb9662451918242557022da60ff003ca0 100644 (file)
 #include <linux/sysctl.h>
 
 #ifdef CONFIG_INET
-extern struct ctl_table ipv4_table[];
+#include <net/ip.h>
 #endif
 
-extern struct ctl_table core_table[];
-
 #ifdef CONFIG_NET
-extern struct ctl_table ether_table[];
+#include <linux/if_ether.h>
 #endif
 
 #ifdef CONFIG_TR
-extern struct ctl_table tr_table[];
+#include <linux/if_tr.h>
 #endif
 
 struct ctl_table net_table[] = {
index d403e34088ad75c1c12ee5fbba7bf8d90e233cfc..41feca3bef86346f3890f8c428c795ff7316abf5 100644 (file)
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <net/sock.h>
-#include <linux/tcp.h>
+#include <net/tcp_states.h>
 #include <net/af_unix.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
@@ -2026,14 +2026,6 @@ static struct net_proto_family unix_family_ops = {
        .owner  = THIS_MODULE,
 };
 
-#ifdef CONFIG_SYSCTL
-extern void unix_sysctl_register(void);
-extern void unix_sysctl_unregister(void);
-#else
-static inline void unix_sysctl_register(void) {}
-static inline void unix_sysctl_unregister(void) {}
-#endif
-
 static int __init af_unix_init(void)
 {
        int rc = -1;
index 4bd95c8f5934a5ca77d265bfdf01e046339ca634..6ffc64e1712d291f40723109db1a774e507c738c 100644 (file)
 #include <linux/netdevice.h>
 #include <linux/file.h>
 #include <linux/proc_fs.h>
-#include <linux/tcp.h>
 
 #include <net/sock.h>
 #include <net/af_unix.h>
 #include <net/scm.h>
+#include <net/tcp_states.h>
 
 /* Internal data structures and random procedures: */
 
@@ -286,16 +286,16 @@ void unix_gc(void)
                        skb = skb_peek(&s->sk_receive_queue);
                        while (skb &&
                               skb != (struct sk_buff *)&s->sk_receive_queue) {
-                               nextsk=skb->next;
+                               nextsk = skb->next;
                                /*
                                 *      Do we have file descriptors ?
                                 */
-                               if(UNIXCB(skb).fp)
-                               {
-                                       __skb_unlink(skb, skb->list);
-                                       __skb_queue_tail(&hitlist,skb);
+                               if (UNIXCB(skb).fp) {
+                                       __skb_unlink(skb,
+                                                    &s->sk_receive_queue);
+                                       __skb_queue_tail(&hitlist, skb);
                                }
-                               skb=nextsk;
+                               skb = nextsk;
                        }
                        spin_unlock(&s->sk_receive_queue.lock);
                }
index c974dac4580a6e4bc0170103af79d83a9e7c4dcb..690ffa5d5bfbf5bd5e01e0bf0fa61ca263f68b10 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/mm.h>
 #include <linux/sysctl.h>
 
-extern int sysctl_unix_max_dgram_qlen;
+#include <net/af_unix.h>
 
 static ctl_table unix_table[] = {
        {
index d93b19faaab7f9b4b1e3fee8caa0975aae9b3eaa..596cb96e5f471227c348ce214d46dce63f5cf4a7 100644 (file)
@@ -57,7 +57,7 @@
 #include <linux/wanpipe.h>
 #include <linux/if_wanpipe.h>
 #include <linux/pkt_sched.h>
-#include <linux/tcp.h>
+#include <linux/tcp_states.h>
 #include <linux/if_wanpipe_common.h>
 #include <linux/sdla_x25.h>
 
index 04bec047fa9ab5910d7ef7c134e734f178e42aa0..020d73cc8414916f6a0bf65b2fbe675ec5759ead 100644 (file)
@@ -47,7 +47,7 @@
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <asm/uaccess.h>
 #include <linux/fcntl.h>
 #include <linux/termios.h>     /* For TIOCINQ/OUTQ */
index 36fc3bf6d8827c4a47de80900ebee0a5ab54e7fa..adfe7b8df35591d29ee2d8a91de8bca57e9a3052 100644 (file)
@@ -81,7 +81,7 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
 }
 
 int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev,
-                          struct packet_type *ptype)
+                          struct packet_type *ptype, struct net_device *orig_dev)
 {
        struct sk_buff *nskb;
        struct x25_neigh *nb;
index b0197c70a9fc5fd2bd1ffb46462490f7636b8417..26146874b839eedb667327b67ed85c624834409c 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/string.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <net/x25.h>
 
 static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
index 7fd872ad0c20a2acbb709e5cb8ca9c22bae7ebac..8be9b8fbc24d143e6d3df6c9dff14f005a6b4cfe 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/string.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <net/x25.h>
 
 /*
@@ -80,7 +80,7 @@ void x25_requeue_frames(struct sock *sk)
                if (!skb_prev)
                        skb_queue_head(&sk->sk_write_queue, skb);
                else
-                       skb_append(skb_prev, skb);
+                       skb_append(skb_prev, skb, &sk->sk_write_queue);
                skb_prev = skb;
        }
 }
index d6a21a3ad80e78b2b9299b4d52817266b1cc1b9f..0a92e1da3922dc802b51cc93dd0d9f8a0a9d2f22 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/jiffies.h>
 #include <linux/timer.h>
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <net/x25.h>
 
 static void x25_heartbeat_expiry(unsigned long);
index c58a6f05a0b66366411b7725faa6422b9c645611..2407a7072327f9156ea6e5771762bb6adc0f072b 100644 (file)
@@ -12,7 +12,7 @@
 #include <net/ip.h>
 #include <net/xfrm.h>
 
-static kmem_cache_t *secpath_cachep;
+static kmem_cache_t *secpath_cachep __read_mostly;
 
 void __secpath_destroy(struct sec_path *sp)
 {
index d65ed8684fc1a340b1f470e3d3f50fc2b940a60f..83c8135e17641dd19bd5fdb204dff3096bdd2eeb 100644 (file)
@@ -37,7 +37,7 @@ EXPORT_SYMBOL(xfrm_policy_list);
 static DEFINE_RWLOCK(xfrm_policy_afinfo_lock);
 static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO];
 
-static kmem_cache_t *xfrm_dst_cache;
+static kmem_cache_t *xfrm_dst_cache __read_mostly;
 
 static struct work_struct xfrm_policy_gc_work;
 static struct list_head xfrm_policy_gc_list =
index 8da3e25b2c4c1f305fd85428d3a9eb62b543bfba..c35336a0f71b5c50cca286fc2eca45043d205807 100644 (file)
@@ -1125,9 +1125,8 @@ static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c)
        if (build_expire(skb, x, c->data.hard) < 0)
                BUG();
 
-       NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE;
-
-       return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
+       NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE;
+       return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC);
 }
 
 static int xfrm_notify_sa_flush(struct km_event *c)
@@ -1152,7 +1151,8 @@ static int xfrm_notify_sa_flush(struct km_event *c)
 
        nlh->nlmsg_len = skb->tail - b;
 
-       return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_SA, GFP_ATOMIC);
+       NETLINK_CB(skb).dst_group = XFRMNLGRP_SA;
+       return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC);
 
 nlmsg_failure:
        kfree_skb(skb);
@@ -1226,7 +1226,8 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c)
 
        nlh->nlmsg_len = skb->tail - b;
 
-       return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_SA, GFP_ATOMIC);
+       NETLINK_CB(skb).dst_group = XFRMNLGRP_SA;
+       return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC);
 
 nlmsg_failure:
 rtattr_failure:
@@ -1304,9 +1305,8 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt,
        if (build_acquire(skb, x, xt, xp, dir) < 0)
                BUG();
 
-       NETLINK_CB(skb).dst_groups = XFRMGRP_ACQUIRE;
-
-       return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_ACQUIRE, GFP_ATOMIC);
+       NETLINK_CB(skb).dst_group = XFRMNLGRP_ACQUIRE;
+       return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC);
 }
 
 /* User gives us xfrm_user_policy_info followed by an array of 0
@@ -1405,9 +1405,8 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_eve
        if (build_polexpire(skb, xp, dir, c->data.hard) < 0)
                BUG();
 
-       NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE;
-
-       return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
+       NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE;
+       return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC);
 }
 
 static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c)
@@ -1455,7 +1454,8 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *
 
        nlh->nlmsg_len = skb->tail - b;
 
-       return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_POLICY, GFP_ATOMIC);
+       NETLINK_CB(skb).dst_group = XFRMNLGRP_POLICY;
+       return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC);
 
 nlmsg_failure:
 rtattr_failure:
@@ -1480,7 +1480,8 @@ static int xfrm_notify_policy_flush(struct km_event *c)
 
        nlh->nlmsg_len = skb->tail - b;
 
-       return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_POLICY, GFP_ATOMIC);
+       NETLINK_CB(skb).dst_group = XFRMNLGRP_POLICY;
+       return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC);
 
 nlmsg_failure:
        kfree_skb(skb);
@@ -1519,7 +1520,8 @@ static int __init xfrm_user_init(void)
 {
        printk(KERN_INFO "Initializing IPsec netlink socket\n");
 
-       xfrm_nl = netlink_kernel_create(NETLINK_XFRM, xfrm_netlink_rcv);
+       xfrm_nl = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX,
+                                       xfrm_netlink_rcv, THIS_MODULE);
        if (xfrm_nl == NULL)
                return -ENOMEM;
 
@@ -1537,3 +1539,4 @@ static void __exit xfrm_user_exit(void)
 module_init(xfrm_user_init);
 module_exit(xfrm_user_exit);
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM);
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
new file mode 100644 (file)
index 0000000..9087273
--- /dev/null
@@ -0,0 +1,96 @@
+####
+# kbuild: Generic definitions
+
+# Convinient variables
+comma   := ,
+empty   :=
+space   := $(empty) $(empty)
+
+###
+# The temporary file to save gcc -MD generated dependencies must not
+# contain a comma
+depfile = $(subst $(comma),_,$(@D)/.$(@F).d)
+
+###
+# filechk is used to check if the content of a generated file is updated.
+# Sample usage:
+# define filechk_sample
+#      echo $KERNELRELEASE
+# endef
+# version.h : Makefile
+#      $(call filechk,sample)
+# The rule defined shall write to stdout the content of the new file.
+# The existing file will be compared with the new one.
+# - If no file exist it is created
+# - If the content differ the new file is used
+# - If they are equal no change, and no timestamp update
+# - stdin is piped in from the first prerequisite ($<) so one has
+#   to specify a valid file as first prerequisite (often the kbuild file)
+define filechk
+       $(Q)set -e;                             \
+       echo '  CHK     $@';                    \
+       mkdir -p $(dir $@);                     \
+       $(filechk_$(1)) < $< > $@.tmp;          \
+       if [ -r $@ ] && cmp -s $@ $@.tmp; then  \
+               rm -f $@.tmp;                   \
+       else                                    \
+               echo '  UPD     $@';            \
+               mv -f $@.tmp $@;                \
+       fi
+endef
+
+###
+# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
+# Usage:
+# $(Q)$(MAKE) $(build)=dir
+build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
+
+# If quiet is set, only print short version of command
+cmd = @$(if $($(quiet)cmd_$(1)),\
+      echo '  $(subst ','\'',$($(quiet)cmd_$(1)))' &&) $(cmd_$(1))
+
+###
+# if_changed      - execute command if any prerequisite is newer than 
+#                   target, or command line has changed
+# if_changed_dep  - as if_changed, but uses fixdep to reveal dependencies
+#                   including used config symbols
+# if_changed_rule - as if_changed but execute rule instead
+# See Documentation/kbuild/makefiles.txt for more info
+
+ifneq ($(KBUILD_NOCMDDEP),1)
+# Check if both arguments has same arguments. Result in empty string if equal
+# User may override this check using make KBUILD_NOCMDDEP=1
+arg-check = $(strip $(filter-out $(1), $(2)) $(filter-out $(2), $(1)) )
+endif
+
+# echo command. Short version is $(quiet) equals quiet, otherwise full command
+echo-cmd = $(if $($(quiet)cmd_$(1)), \
+       echo '  $(subst ','\'',$($(quiet)cmd_$(1)))';)
+
+# function to only execute the passed command if necessary
+# >'< substitution is for echo to work, >$< substitution to preserve $ when reloading .cmd file
+# note: when using inline perl scripts [perl -e '...$$t=1;...'] in $(cmd_xxx) double $$ your perl vars
+# 
+if_changed = $(if $(strip $? $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ), \
+       @set -e; \
+       $(echo-cmd) \
+       $(cmd_$(1)); \
+       echo 'cmd_$@ := $(subst $$,$$$$,$(subst ','\'',$(cmd_$(1))))' > $(@D)/.$(@F).cmd)
+
+# execute the command and also postprocess generated .d dependencies
+# file
+if_changed_dep = $(if $(strip $? $(filter-out FORCE $(wildcard $^),$^)\
+       $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ),                  \
+       @set -e; \
+       $(echo-cmd) \
+       $(cmd_$(1)); \
+       scripts/basic/fixdep $(depfile) $@ '$(subst $$,$$$$,$(subst ','\'',$(cmd_$(1))))' > $(@D)/.$(@F).tmp; \
+       rm -f $(depfile); \
+       mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd)
+
+# Usage: $(call if_changed_rule,foo)
+# will check if $(cmd_foo) changed, or any of the prequisites changed,
+# and if so will execute $(rule_foo)
+if_changed_rule = $(if $(strip $? $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ),\
+                       @set -e; \
+                       $(rule_$(1)))
index 76ba6be3dfc9cd51888b57ef54c9aea8e8d19e81..506e3f3befe3104b35d2518fd42af7fb53048f67 100644 (file)
@@ -10,8 +10,11 @@ __build:
 # Read .config if it exist, otherwise ignore
 -include .config
 
-include $(if $(wildcard $(obj)/Kbuild), $(obj)/Kbuild, $(obj)/Makefile)
+# The filename Kbuild has precedence over Makefile
+kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
+include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)
 
+include scripts/Kbuild.include
 include scripts/Makefile.lib
 
 ifdef host-progs
@@ -169,7 +172,7 @@ cmd_modversions =                                                   \
                        -T $(@D)/.tmp_$(@F:.o=.ver);                    \
                rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver);        \
        else                                                            \
-               mv $(@D)/.tmp_$(@F) $@;                                 \
+               mv -f $(@D)/.tmp_$(@F) $@;                              \
        fi;
 endif
 
index ff3e87dbf387412448f8f1d1359120a997636234..8974ea5fc878896fac077f274af8a6c60c91568d 100644 (file)
@@ -7,7 +7,14 @@ src := $(obj)
 .PHONY: __clean
 __clean:
 
-include $(if $(wildcard $(obj)/Kbuild), $(obj)/Kbuild, $(obj)/Makefile)
+# Shorthand for $(Q)$(MAKE) scripts/Makefile.clean obj=dir
+# Usage:
+# $(Q)$(MAKE) $(clean)=dir
+clean := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.clean obj
+
+# The filename Kbuild has precedence over Makefile
+kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
+include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)
 
 # Figure out what we need to build from the various variables
 # ==========================================================================
@@ -87,8 +94,3 @@ $(subdir-ymn):
 # If quiet is set, only print short version of command
 
 cmd = @$(if $($(quiet)cmd_$(1)),echo '  $($(quiet)cmd_$(1))' &&) $(cmd_$(1))
-
-# Shorthand for $(Q)$(MAKE) scripts/Makefile.clean obj=dir
-# Usage:
-# $(Q)$(MAKE) $(clean)=dir
-clean := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.clean obj
index 2821a2b83bbb3c73a8d8b1be91ade4f517e64e49..2d519704b8fd7993775bfc75cd40520631b06d39 100644 (file)
@@ -98,7 +98,8 @@ hostcxx_flags  = -Wp,-MD,$(depfile) $(__hostcxx_flags)
 # Create executable from a single .c file
 # host-csingle -> Executable
 quiet_cmd_host-csingle         = HOSTCC  $@
-      cmd_host-csingle = $(HOSTCC) $(hostc_flags) $(HOST_LOADLIBES) -o $@ $<
+      cmd_host-csingle = $(HOSTCC) $(hostc_flags) -o $@ $< \
+               $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
 $(host-csingle): %: %.c FORCE
        $(call if_changed_dep,host-csingle)
 
index 7cf75cc4f849dfe8a75a05a604809c2ec5a19bed..0f81dcfd6909aec0f873fdef797fec5fca75f44a 100644 (file)
@@ -1,13 +1,3 @@
-# ===========================================================================
-# kbuild: Generic definitions
-# ===========================================================================
-
-# Standard vars
-
-comma   := ,
-empty   :=
-space   := $(empty) $(empty)
-
 # Backward compatibility - to be removed...
 extra-y        += $(EXTRA_TARGETS)
 # Figure out what we need to build from the various variables
@@ -84,10 +74,6 @@ multi-objs-m := $(addprefix $(obj)/,$(multi-objs-m))
 subdir-ym      := $(addprefix $(obj)/,$(subdir-ym))
 obj-dirs       := $(addprefix $(obj)/,$(obj-dirs))
 
-# The temporary file to save gcc -MD generated dependencies must not
-# contain a comma
-depfile = $(subst $(comma),_,$(@D)/.$(@F).d)
-
 # These flags are needed for modversions and compiling, so we define them here
 # already
 # $(modname_flags) #defines KBUILD_MODNAME as the name of the module it will 
@@ -179,89 +165,4 @@ cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
 quiet_cmd_gzip = GZIP    $@
 cmd_gzip = gzip -f -9 < $< > $@
 
-# ===========================================================================
-# Generic stuff
-# ===========================================================================
-
-ifneq ($(KBUILD_NOCMDDEP),1)
-# Check if both arguments has same arguments. Result in empty string if equal
-# User may override this check using make KBUILD_NOCMDDEP=1
-arg-check = $(strip $(filter-out $(1), $(2)) $(filter-out $(2), $(1)) )
-
-endif
-
-# echo command. Short version is $(quiet) equals quiet, otherwise full command
-echo-cmd = $(if $($(quiet)cmd_$(1)), \
-       echo '  $(subst ','\'',$($(quiet)cmd_$(1)))';)
-
-# function to only execute the passed command if necessary
-# >'< substitution is for echo to work, >$< substitution to preserve $ when reloading .cmd file
-# note: when using inline perl scripts [perl -e '...$$t=1;...'] in $(cmd_xxx) double $$ your perl vars
-# 
-if_changed = $(if $(strip $? $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ), \
-       @set -e; \
-       $(echo-cmd) \
-       $(cmd_$(1)); \
-       echo 'cmd_$@ := $(subst $$,$$$$,$(subst ','\'',$(cmd_$(1))))' > $(@D)/.$(@F).cmd)
-
-
-# execute the command and also postprocess generated .d dependencies
-# file
-
-if_changed_dep = $(if $(strip $? $(filter-out FORCE $(wildcard $^),$^)\
-       $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ),                  \
-       @set -e; \
-       $(echo-cmd) \
-       $(cmd_$(1)); \
-       scripts/basic/fixdep $(depfile) $@ '$(subst $$,$$$$,$(subst ','\'',$(cmd_$(1))))' > $(@D)/.$(@F).tmp; \
-       rm -f $(depfile); \
-       mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd)
-
-# Usage: $(call if_changed_rule,foo)
-# will check if $(cmd_foo) changed, or any of the prequisites changed,
-# and if so will execute $(rule_foo)
-
-if_changed_rule = $(if $(strip $? $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ),\
-                       @set -e; \
-                       $(rule_$(1)))
-
-# If quiet is set, only print short version of command
-
-cmd = @$(if $($(quiet)cmd_$(1)),echo '  $(subst ','\'',$($(quiet)cmd_$(1)))' &&) $(cmd_$(1))
-
-#      $(call descend,<dir>,<target>)
-#      Recursively call a sub-make in <dir> with target <target> 
-# Usage is deprecated, because make do not see this as an invocation of make.
-descend =$(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj=$(1) $(2)
-
-# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
-# Usage:
-# $(Q)$(MAKE) $(build)=dir
-build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
-
-# filechk is used to check if the content of a generated file is updated.
-# Sample usage:
-# define filechk_sample
-#      echo $KERNELRELEASE
-# endef
-# version.h : Makefile
-#      $(call filechk,sample)
-# The rule defined shall write to stdout the content of the new file.
-# The existing file will be compared with the new one.
-# - If no file exist it is created
-# - If the content differ the new file is used
-# - If they are equal no change, and no timestamp update
-
-define filechk
-       $(Q)set -e;                             \
-       echo '  CHK     $@';                    \
-       mkdir -p $(dir $@);                     \
-       $(filechk_$(1)) $(2) > $@.tmp;          \
-       if [ -r $@ ] && cmp -s $@ $@.tmp; then  \
-               rm -f $@.tmp;                   \
-       else                                    \
-               echo '  UPD     $@';            \
-               mv -f $@.tmp $@;                \
-       fi
-endef
 
index 85d6494e3c24a3c8e3b3b603f7122e90cea3b83a..23fd1bdc25cebe7a3ddaa1a96c147f6121befc33 100644 (file)
@@ -5,7 +5,7 @@
 .PHONY: __modinst
 __modinst:
 
-include scripts/Makefile.lib
+include scripts/Kbuild.include
 
 #
 
index 94b550e21be8d8bc67a8ebf51b7c5621045aa4a3..0c4f3a9f2ea95e9d863c9063eefce6806cb11e60 100644 (file)
@@ -36,6 +36,7 @@
 _modpost: __modpost
 
 include .config
+include scripts/Kbuild.include
 include scripts/Makefile.lib
 
 symverfile := $(objtree)/Module.symvers
index 93dd23f21ec96b5736f205bdf38e6b1ad787c557..e0c6891a9ad4f5b35c7bb96b381a171f32887d99 100644 (file)
@@ -33,7 +33,7 @@ void usage(char *argv0)
 
 int getunicode(char **p0)
 {
-  unsigned char *p = *p0;
+  char *p = *p0;
 
   while (*p == ' ' || *p == '\t')
     p++;
index d3d2e5341051809b01d13b75b352ed3d41f01d5c..d591578bd3b209ab8258a814b30727366e8909d8 100644 (file)
  *
  */
 
+#define _GNU_SOURCE
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
 
-/* maximum token length used. It doesn't pay to increase it a lot, because
- * very long substrings probably don't repeat themselves too often. */
-#define MAX_TOK_SIZE           11
 #define KSYM_NAME_LEN          127
 
-/* we use only a subset of the complete symbol table to gather the token count,
- * to speed up compression, at the expense of a little compression ratio */
-#define WORKING_SET            1024
-
-/* first find the best token only on the list of tokens that would profit more
- * than GOOD_BAD_THRESHOLD. Only if this list is empty go to the "bad" list.
- * Increasing this value will put less tokens on the "good" list, so the search
- * is faster. However, if the good list runs out of tokens, we must painfully
- * search the bad list. */
-#define GOOD_BAD_THRESHOLD     10
-
-/* token hash parameters */
-#define HASH_BITS              18
-#define HASH_TABLE_SIZE                (1 << HASH_BITS)
-#define HASH_MASK              (HASH_TABLE_SIZE - 1)
-#define HASH_BASE_OFFSET       2166136261U
-#define HASH_FOLD(a)           ((a)&(HASH_MASK))
-
-/* flags to mark symbols */
-#define SYM_FLAG_VALID         1
-#define SYM_FLAG_SAMPLED       2
 
 struct sym_entry {
        unsigned long long addr;
-       char type;
-       unsigned char flags;
-       unsigned char len;
+       unsigned int len;
        unsigned char *sym;
 };
 
 
 static struct sym_entry *table;
-static int size, cnt;
+static unsigned int table_size, table_cnt;
 static unsigned long long _stext, _etext, _sinittext, _einittext, _sextratext, _eextratext;
 static int all_symbols = 0;
 static char symbol_prefix_char = '\0';
 
-struct token {
-       unsigned char data[MAX_TOK_SIZE];
-       unsigned char len;
-       /* profit: the number of bytes that could be saved by inserting this
-        * token into the table */
-       int profit;
-       struct token *next;     /* next token on the hash list */
-       struct token *right;    /* next token on the good/bad list */
-       struct token *left;    /* previous token on the good/bad list */
-       struct token *smaller; /* token that is less one letter than this one */
-       };
-
-struct token bad_head, good_head;
-struct token *hash_table[HASH_TABLE_SIZE];
+int token_profit[0x10000];
 
 /* the table that holds the result of the compression */
-unsigned char best_table[256][MAX_TOK_SIZE+1];
+unsigned char best_table[256][2];
 unsigned char best_table_len[256];
 
 
-static void
-usage(void)
+static void usage(void)
 {
        fprintf(stderr, "Usage: kallsyms [--all-symbols] [--symbol-prefix=<prefix char>] < in.map > out.S\n");
        exit(1);
@@ -102,21 +64,19 @@ usage(void)
  * This ignores the intensely annoying "mapping symbols" found
  * in ARM ELF files: $a, $t and $d.
  */
-static inline int
-is_arm_mapping_symbol(const char *str)
+static inline int is_arm_mapping_symbol(const char *str)
 {
        return str[0] == '$' && strchr("atd", str[1])
               && (str[2] == '\0' || str[2] == '.');
 }
 
-static int
-read_symbol(FILE *in, struct sym_entry *s)
+static int read_symbol(FILE *in, struct sym_entry *s)
 {
        char str[500];
-       char *sym;
+       char *sym, stype;
        int rc;
 
-       rc = fscanf(in, "%llx %c %499s\n", &s->addr, &s->type, str);
+       rc = fscanf(in, "%llx %c %499s\n", &s->addr, &stype, str);
        if (rc != 3) {
                if (rc != EOF) {
                        /* skip line */
@@ -143,7 +103,7 @@ read_symbol(FILE *in, struct sym_entry *s)
                _sextratext = s->addr;
        else if (strcmp(sym, "_eextratext") == 0)
                _eextratext = s->addr;
-       else if (toupper(s->type) == 'A')
+       else if (toupper(stype) == 'A')
        {
                /* Keep these useful absolute symbols */
                if (strcmp(sym, "__kernel_syscall_via_break") &&
@@ -153,22 +113,24 @@ read_symbol(FILE *in, struct sym_entry *s)
                        return -1;
 
        }
-       else if (toupper(s->type) == 'U' ||
+       else if (toupper(stype) == 'U' ||
                 is_arm_mapping_symbol(sym))
                return -1;
+       /* exclude also MIPS ELF local symbols ($L123 instead of .L123) */
+       else if (str[0] == '$')
+               return -1;
 
        /* include the type field in the symbol name, so that it gets
         * compressed together */
        s->len = strlen(str) + 1;
-       s->sym = (char *) malloc(s->len + 1);
-       strcpy(s->sym + 1, str);
-       s->sym[0] = s->type;
+       s->sym = malloc(s->len + 1);
+       strcpy((char *)s->sym + 1, str);
+       s->sym[0] = stype;
 
        return 0;
 }
 
-static int
-symbol_valid(struct sym_entry *s)
+static int symbol_valid(struct sym_entry *s)
 {
        /* Symbols which vary between passes.  Passes 1 and 2 must have
         * identical symbol lists.  The kallsyms_* symbols below are only added
@@ -207,37 +169,36 @@ symbol_valid(struct sym_entry *s)
                 * move then they may get dropped in pass 2, which breaks the
                 * kallsyms rules.
                 */
-               if ((s->addr == _etext && strcmp(s->sym + offset, "_etext")) ||
-                   (s->addr == _einittext && strcmp(s->sym + offset, "_einittext")) ||
-                   (s->addr == _eextratext && strcmp(s->sym + offset, "_eextratext")))
+               if ((s->addr == _etext && strcmp((char*)s->sym + offset, "_etext")) ||
+                   (s->addr == _einittext && strcmp((char*)s->sym + offset, "_einittext")) ||
+                   (s->addr == _eextratext && strcmp((char*)s->sym + offset, "_eextratext")))
                        return 0;
        }
 
        /* Exclude symbols which vary between passes. */
-       if (strstr(s->sym + offset, "_compiled."))
+       if (strstr((char *)s->sym + offset, "_compiled."))
                return 0;
 
        for (i = 0; special_symbols[i]; i++)
-               if( strcmp(s->sym + offset, special_symbols[i]) == 0 )
+               if( strcmp((char *)s->sym + offset, special_symbols[i]) == 0 )
                        return 0;
 
        return 1;
 }
 
-static void
-read_map(FILE *in)
+static void read_map(FILE *in)
 {
        while (!feof(in)) {
-               if (cnt >= size) {
-                       size += 10000;
-                       table = realloc(table, sizeof(*table) * size);
+               if (table_cnt >= table_size) {
+                       table_size += 10000;
+                       table = realloc(table, sizeof(*table) * table_size);
                        if (!table) {
                                fprintf(stderr, "out of memory\n");
                                exit (1);
                        }
                }
-               if (read_symbol(in, &table[cnt]) == 0)
-                       cnt++;
+               if (read_symbol(in, &table[table_cnt]) == 0)
+                       table_cnt++;
        }
 }
 
@@ -281,10 +242,9 @@ static int expand_symbol(unsigned char *data, int len, char *result)
        return total;
 }
 
-static void
-write_src(void)
+static void write_src(void)
 {
-       int i, k, off, valid;
+       unsigned int i, k, off;
        unsigned int best_idx[256];
        unsigned int *markers;
        char buf[KSYM_NAME_LEN+1];
@@ -301,33 +261,24 @@ write_src(void)
        printf(".data\n");
 
        output_label("kallsyms_addresses");
-       valid = 0;
-       for (i = 0; i < cnt; i++) {
-               if (table[i].flags & SYM_FLAG_VALID) {
-                       printf("\tPTR\t%#llx\n", table[i].addr);
-                       valid++;
-               }
+       for (i = 0; i < table_cnt; i++) {
+               printf("\tPTR\t%#llx\n", table[i].addr);
        }
        printf("\n");
 
        output_label("kallsyms_num_syms");
-       printf("\tPTR\t%d\n", valid);
+       printf("\tPTR\t%d\n", table_cnt);
        printf("\n");
 
        /* table of offset markers, that give the offset in the compressed stream
         * every 256 symbols */
-       markers = (unsigned int *) malloc(sizeof(unsigned int)*((valid + 255) / 256));
+       markers = (unsigned int *) malloc(sizeof(unsigned int) * ((table_cnt + 255) / 256));
 
        output_label("kallsyms_names");
-       valid = 0;
        off = 0;
-       for (i = 0; i < cnt; i++) {
-
-               if (!table[i].flags & SYM_FLAG_VALID)
-                       continue;
-
-               if ((valid & 0xFF) == 0)
-                       markers[valid >> 8] = off;
+       for (i = 0; i < table_cnt; i++) {
+               if ((i & 0xFF) == 0)
+                       markers[i >> 8] = off;
 
                printf("\t.byte 0x%02x", table[i].len);
                for (k = 0; k < table[i].len; k++)
@@ -335,12 +286,11 @@ write_src(void)
                printf("\n");
 
                off += table[i].len + 1;
-               valid++;
        }
        printf("\n");
 
        output_label("kallsyms_markers");
-       for (i = 0; i < ((valid + 255) >> 8); i++)
+       for (i = 0; i < ((table_cnt + 255) >> 8); i++)
                printf("\tPTR\t%d\n", markers[i]);
        printf("\n");
 
@@ -350,7 +300,7 @@ write_src(void)
        off = 0;
        for (i = 0; i < 256; i++) {
                best_idx[i] = off;
-               expand_symbol(best_table[i],best_table_len[i],buf);
+               expand_symbol(best_table[i], best_table_len[i], buf);
                printf("\t.asciz\t\"%s\"\n", buf);
                off += strlen(buf) + 1;
        }
@@ -365,153 +315,13 @@ write_src(void)
 
 /* table lookup compression functions */
 
-static inline unsigned int rehash_token(unsigned int hash, unsigned char data)
-{
-       return ((hash * 16777619) ^ data);
-}
-
-static unsigned int hash_token(unsigned char *data, int len)
-{
-       unsigned int hash=HASH_BASE_OFFSET;
-       int i;
-
-       for (i = 0; i < len; i++)
-               hash = rehash_token(hash, data[i]);
-
-       return HASH_FOLD(hash);
-}
-
-/* find a token given its data and hash value */
-static struct token *find_token_hash(unsigned char *data, int len, unsigned int hash)
-{
-       struct token *ptr;
-
-       ptr = hash_table[hash];
-
-       while (ptr) {
-               if ((ptr->len == len) && (memcmp(ptr->data, data, len) == 0))
-                       return ptr;
-               ptr=ptr->next;
-       }
-
-       return NULL;
-}
-
-static inline void insert_token_in_group(struct token *head, struct token *ptr)
-{
-       ptr->right = head->right;
-       ptr->right->left = ptr;
-       head->right = ptr;
-       ptr->left = head;
-}
-
-static inline void remove_token_from_group(struct token *ptr)
-{
-       ptr->left->right = ptr->right;
-       ptr->right->left = ptr->left;
-}
-
-
-/* build the counts for all the tokens that start with "data", and have lenghts
- * from 2 to "len" */
-static void learn_token(unsigned char *data, int len)
-{
-       struct token *ptr,*last_ptr;
-       int i, newprofit;
-       unsigned int hash = HASH_BASE_OFFSET;
-       unsigned int hashes[MAX_TOK_SIZE + 1];
-
-       if (len > MAX_TOK_SIZE)
-               len = MAX_TOK_SIZE;
-
-       /* calculate and store the hash values for all the sub-tokens */
-       hash = rehash_token(hash, data[0]);
-       for (i = 2; i <= len; i++) {
-               hash = rehash_token(hash, data[i-1]);
-               hashes[i] = HASH_FOLD(hash);
-       }
-
-       last_ptr = NULL;
-       ptr = NULL;
-
-       for (i = len; i >= 2; i--) {
-               hash = hashes[i];
-
-               if (!ptr) ptr = find_token_hash(data, i, hash);
-
-               if (!ptr) {
-                       /* create a new token entry */
-                       ptr = (struct token *) malloc(sizeof(*ptr));
-
-                       memcpy(ptr->data, data, i);
-                       ptr->len = i;
-
-                       /* when we create an entry, it's profit is 0 because
-                        * we also take into account the size of the token on
-                        * the compressed table. We then subtract GOOD_BAD_THRESHOLD
-                        * so that the test to see if this token belongs to
-                        * the good or bad list, is a comparison to zero */
-                       ptr->profit = -GOOD_BAD_THRESHOLD;
-
-                       ptr->next = hash_table[hash];
-                       hash_table[hash] = ptr;
-
-                       insert_token_in_group(&bad_head, ptr);
-
-                       ptr->smaller = NULL;
-               } else {
-                       newprofit = ptr->profit + (ptr->len - 1);
-                       /* check to see if this token needs to be moved to a
-                        * different list */
-                       if((ptr->profit < 0) && (newprofit >= 0)) {
-                               remove_token_from_group(ptr);
-                               insert_token_in_group(&good_head,ptr);
-                       }
-                       ptr->profit = newprofit;
-               }
-
-               if (last_ptr) last_ptr->smaller = ptr;
-               last_ptr = ptr;
-
-               ptr = ptr->smaller;
-       }
-}
-
-/* decrease the counts for all the tokens that start with "data", and have lenghts
- * from 2 to "len". This function is much simpler than learn_token because we have
- * more guarantees (tho tokens exist, the ->smaller pointer is set, etc.)
- * The two separate functions exist only because of compression performance */
-static void forget_token(unsigned char *data, int len)
-{
-       struct token *ptr;
-       int i, newprofit;
-       unsigned int hash=0;
-
-       if (len > MAX_TOK_SIZE) len = MAX_TOK_SIZE;
-
-       hash = hash_token(data, len);
-       ptr = find_token_hash(data, len, hash);
-
-       for (i = len; i >= 2; i--) {
-
-               newprofit = ptr->profit - (ptr->len - 1);
-               if ((ptr->profit >= 0) && (newprofit < 0)) {
-                       remove_token_from_group(ptr);
-                       insert_token_in_group(&bad_head, ptr);
-               }
-               ptr->profit=newprofit;
-
-               ptr=ptr->smaller;
-       }
-}
-
 /* count all the possible tokens in a symbol */
 static void learn_symbol(unsigned char *symbol, int len)
 {
        int i;
 
        for (i = 0; i < len - 1; i++)
-               learn_token(symbol + i, len - i);
+               token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++;
 }
 
 /* decrease the count for all the possible tokens in a symbol */
@@ -520,117 +330,90 @@ static void forget_symbol(unsigned char *symbol, int len)
        int i;
 
        for (i = 0; i < len - 1; i++)
-               forget_token(symbol + i, len - i);
+               token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--;
 }
 
-/* set all the symbol flags and do the initial token count */
+/* remove all the invalid symbols from the table and do the initial token count */
 static void build_initial_tok_table(void)
 {
-       int i, use_it, valid;
+       unsigned int i, pos;
 
-       valid = 0;
-       for (i = 0; i < cnt; i++) {
-               table[i].flags = 0;
+       pos = 0;
+       for (i = 0; i < table_cnt; i++) {
                if ( symbol_valid(&table[i]) ) {
-                       table[i].flags |= SYM_FLAG_VALID;
-                       valid++;
+                       if (pos != i)
+                               table[pos] = table[i];
+                       learn_symbol(table[pos].sym, table[pos].len);
+                       pos++;
                }
        }
-
-       use_it = 0;
-       for (i = 0; i < cnt; i++) {
-
-               /* subsample the available symbols. This method is almost like
-                * a Bresenham's algorithm to get uniformly distributed samples
-                * across the symbol table */
-               if (table[i].flags & SYM_FLAG_VALID) {
-
-                       use_it += WORKING_SET;
-
-                       if (use_it >= valid) {
-                               table[i].flags |= SYM_FLAG_SAMPLED;
-                               use_it -= valid;
-                       }
-               }
-               if (table[i].flags & SYM_FLAG_SAMPLED)
-                       learn_symbol(table[i].sym, table[i].len);
-       }
+       table_cnt = pos;
 }
 
 /* replace a given token in all the valid symbols. Use the sampled symbols
  * to update the counts */
-static void compress_symbols(unsigned char *str, int tlen, int idx)
+static void compress_symbols(unsigned char *str, int idx)
 {
-       int i, len, learn, size;
-       unsigned char *p;
+       unsigned int i, len, size;
+       unsigned char *p1, *p2;
 
-       for (i = 0; i < cnt; i++) {
-
-               if (!(table[i].flags & SYM_FLAG_VALID)) continue;
+       for (i = 0; i < table_cnt; i++) {
 
                len = table[i].len;
-               learn = 0;
-               p = table[i].sym;
+               p1 = table[i].sym;
+
+               /* find the token on the symbol */
+               p2 = memmem(p1, len, str, 2);
+               if (!p2) continue;
+
+               /* decrease the counts for this symbol's tokens */
+               forget_symbol(table[i].sym, len);
+
+               size = len;
 
                do {
+                       *p2 = idx;
+                       p2++;
+                       size -= (p2 - p1);
+                       memmove(p2, p2 + 1, size);
+                       p1 = p2;
+                       len--;
+
+                       if (size < 2) break;
+
                        /* find the token on the symbol */
-                       p = (unsigned char *) strstr((char *) p, (char *) str);
-                       if (!p) break;
-
-                       if (!learn) {
-                               /* if this symbol was used to count, decrease it */
-                               if (table[i].flags & SYM_FLAG_SAMPLED)
-                                       forget_symbol(table[i].sym, len);
-                               learn = 1;
-                       }
+                       p2 = memmem(p1, size, str, 2);
 
-                       *p = idx;
-                       size = (len - (p - table[i].sym)) - tlen + 1;
-                       memmove(p + 1, p + tlen, size);
-                       p++;
-                       len -= tlen - 1;
+               } while (p2);
 
-               } while (size >= tlen);
+               table[i].len = len;
 
-               if(learn) {
-                       table[i].len = len;
-                       /* if this symbol was used to count, learn it again */
-                       if(table[i].flags & SYM_FLAG_SAMPLED)
-                               learn_symbol(table[i].sym, len);
-               }
+               /* increase the counts for this symbol's new tokens */
+               learn_symbol(table[i].sym, len);
        }
 }
 
 /* search the token with the maximum profit */
-static struct token *find_best_token(void)
+static int find_best_token(void)
 {
-       struct token *ptr,*best,*head;
-       int bestprofit;
+       int i, best, bestprofit;
 
        bestprofit=-10000;
+       best = 0;
 
-       /* failsafe: if the "good" list is empty search from the "bad" list */
-       if(good_head.right == &good_head) head = &bad_head;
-       else head = &good_head;
-
-       ptr = head->right;
-       best = NULL;
-       while (ptr != head) {
-               if (ptr->profit > bestprofit) {
-                       bestprofit = ptr->profit;
-                       best = ptr;
+       for (i = 0; i < 0x10000; i++) {
+               if (token_profit[i] > bestprofit) {
+                       best = i;
+                       bestprofit = token_profit[i];
                }
-               ptr = ptr->right;
        }
-
        return best;
 }
 
 /* this is the core of the algorithm: calculate the "best" table */
 static void optimize_result(void)
 {
-       struct token *best;
-       int i;
+       int i, best;
 
        /* using the '\0' symbol last allows compress_symbols to use standard
         * fast string functions */
@@ -644,14 +427,12 @@ static void optimize_result(void)
                        best = find_best_token();
 
                        /* place it in the "best" table */
-                       best_table_len[i] = best->len;
-                       memcpy(best_table[i], best->data, best_table_len[i]);
-                       /* zero terminate the token so that we can use strstr
-                          in compress_symbols */
-                       best_table[i][best_table_len[i]]='\0';
+                       best_table_len[i] = 2;
+                       best_table[i][0] = best & 0xFF;
+                       best_table[i][1] = (best >> 8) & 0xFF;
 
                        /* replace this token in all the valid symbols */
-                       compress_symbols(best_table[i], best_table_len[i], i);
+                       compress_symbols(best_table[i], i);
                }
        }
 }
@@ -659,39 +440,28 @@ static void optimize_result(void)
 /* start by placing the symbols that are actually used on the table */
 static void insert_real_symbols_in_table(void)
 {
-       int i, j, c;
+       unsigned int i, j, c;
 
        memset(best_table, 0, sizeof(best_table));
        memset(best_table_len, 0, sizeof(best_table_len));
 
-       for (i = 0; i < cnt; i++) {
-               if (table[i].flags & SYM_FLAG_VALID) {
-                       for (j = 0; j < table[i].len; j++) {
-                               c = table[i].sym[j];
-                               best_table[c][0]=c;
-                               best_table_len[c]=1;
-                       }
+       for (i = 0; i < table_cnt; i++) {
+               for (j = 0; j < table[i].len; j++) {
+                       c = table[i].sym[j];
+                       best_table[c][0]=c;
+                       best_table_len[c]=1;
                }
        }
 }
 
 static void optimize_token_table(void)
 {
-       memset(hash_table, 0, sizeof(hash_table));
-
-       good_head.left = &good_head;
-       good_head.right = &good_head;
-
-       bad_head.left = &bad_head;
-       bad_head.right = &bad_head;
-
        build_initial_tok_table();
 
        insert_real_symbols_in_table();
 
        /* When valid symbol is not registered, exit to error */
-       if (good_head.left == good_head.right &&
-           bad_head.left == bad_head.right) {
+       if (!table_cnt) {
                fprintf(stderr, "No valid symbol.\n");
                exit(1);
        }
@@ -700,8 +470,7 @@ static void optimize_token_table(void)
 }
 
 
-int
-main(int argc, char **argv)
+int main(int argc, char **argv)
 {
        if (argc >= 2) {
                int i;
index 09abb891d11f2eb5741b41a66307a13fe2d8a203..2fcb244a9e180abe89d5783f189d3b09a18bc2a7 100644 (file)
@@ -27,8 +27,20 @@ update-po-config: $(obj)/kxgettext
        xgettext --default-domain=linux \
           --add-comments --keyword=_ --keyword=N_ \
           --files-from=scripts/kconfig/POTFILES.in \
-       -o scripts/kconfig/linux.pot
-       scripts/kconfig/kxgettext arch/$(ARCH)/Kconfig >> scripts/kconfig/linux.pot
+          --output scripts/kconfig/config.pot
+       $(Q)ln -fs Kconfig_i386 arch/um/Kconfig_arch
+       $(Q)for i in `ls arch/`; \
+       do \
+         scripts/kconfig/kxgettext arch/$$i/Kconfig \
+           | msguniq -o scripts/kconfig/linux_$${i}.pot; \
+       done
+       $(Q)msgcat scripts/kconfig/config.pot \
+         `find scripts/kconfig/ -type f -name linux_*.pot` \
+         --output scripts/kconfig/linux_raw.pot
+       $(Q)msguniq --sort-by-file scripts/kconfig/linux_raw.pot \
+           --output scripts/kconfig/linux.pot
+       $(Q)rm -f arch/um/Kconfig_arch
+       $(Q)rm -f scripts/kconfig/linux_*.pot scripts/kconfig/config.pot
 
 .PHONY: randconfig allyesconfig allnoconfig allmodconfig defconfig
 
index 1c88d7c6d5a718ca9850bab1bf410f2439c51fab..abee55ca6174ca8527476899c9ce87b5bf4a0020 100644 (file)
@@ -14,6 +14,11 @@ static char *escape(const char* text, char *bf, int len)
 {
        char *bfp = bf;
        int multiline = strchr(text, '\n') != NULL;
+       int eol = 0;
+       int textlen = strlen(text);
+
+       if ((textlen > 0) && (text[textlen-1] == '\n'))
+               eol = 1;
 
        *bfp++ = '"';
        --len;
@@ -43,7 +48,7 @@ next:
                --len;
        }
 
-       if (multiline)
+       if (multiline && eol)
                bfp -= 3;
 
        *bfp++ = '"';
@@ -179,7 +184,11 @@ static void message__print_file_lineno(struct message *self)
 {
        struct file_line *fl = self->files;
 
-       printf("\n#: %s:%d", fl->file, fl->lineno);
+       putchar('\n');
+       if (self->option != NULL)
+               printf("# %s:00000\n", self->option);
+
+       printf("#: %s:%d", fl->file, fl->lineno);
        fl = fl->next;
 
        while (fl != NULL) {
@@ -187,9 +196,6 @@ static void message__print_file_lineno(struct message *self)
                fl = fl->next;
        }
 
-       if (self->option != NULL)
-               printf(", %s:00000", self->option);
-
        putchar('\n');
 }
 
index 8b84c42b49b5bdd0e191b044434c488e5e9af064..c3d25786a64dcec385e437867682069bcf18deda 100644 (file)
@@ -59,7 +59,7 @@ void menu_add_entry(struct symbol *sym);
 void menu_end_entry(void);
 void menu_add_dep(struct expr *dep);
 struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
-void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
 void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
 void menu_finalize(struct menu *parent);
index 8c59b212722dc21bb66e695ebdef09bf339f5e72..5cfa6c405cf074f369b8ea1766ea549287560279 100644 (file)
@@ -136,9 +136,9 @@ struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *e
        return prop;
 }
 
-void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
 {
-       menu_add_prop(type, prompt, NULL, dep);
+       return menu_add_prop(type, prompt, NULL, dep);
 }
 
 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
index f163d8d2d9ef2e91bb193fce5032d7265b182e54..ff4fcc09720ecbd5303ab4c13a37efdde3eb0c98 100644 (file)
@@ -1531,7 +1531,7 @@ yyreduce:
 
     {
        menu_add_entry(NULL);
-       menu_add_prop(P_MENU, yyvsp[-1].string, NULL, NULL);
+       menu_add_prompt(P_MENU, yyvsp[-1].string, NULL);
        printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
 ;}
     break;
@@ -1586,7 +1586,7 @@ yyreduce:
 
     {
        menu_add_entry(NULL);
-       menu_add_prop(P_COMMENT, yyvsp[-1].string, NULL, NULL);
+       menu_add_prompt(P_COMMENT, yyvsp[-1].string, NULL);
        printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
 ;}
     break;
@@ -1640,7 +1640,7 @@ yyreduce:
   case 86:
 
     {
-       menu_add_prop(P_PROMPT, yyvsp[-1].string, NULL, yyvsp[0].expr);
+       menu_add_prompt(P_PROMPT, yyvsp[-1].string, yyvsp[0].expr);
 ;}
     break;
 
@@ -1925,7 +1925,7 @@ void conf_parse(const char *name)
        sym_init();
        menu_init();
        modules_sym = sym_lookup("MODULES", 0);
-       rootmenu.prompt = menu_add_prop(P_MENU, "Linux Kernel Configuration", NULL, NULL);
+       rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
 
        //zconfdebug = 1;
        zconfparse();
index 54460f8d3696b2bd9ee1895ff35d3e5a845a32de..e1a0f455d4a8decb163ff3196a0725b738279bb1 100644 (file)
@@ -342,7 +342,7 @@ if_block:
 menu: T_MENU prompt T_EOL
 {
        menu_add_entry(NULL);
-       menu_add_prop(P_MENU, $2, NULL, NULL);
+       menu_add_prompt(P_MENU, $2, NULL);
        printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
 };
 
@@ -392,7 +392,7 @@ source_stmt: source
 comment: T_COMMENT prompt T_EOL
 {
        menu_add_entry(NULL);
-       menu_add_prop(P_COMMENT, $2, NULL, NULL);
+       menu_add_prompt(P_COMMENT, $2, NULL);
        printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
 };
 
@@ -443,7 +443,7 @@ prompt_stmt_opt:
          /* empty */
        | prompt if_expr
 {
-       menu_add_prop(P_PROMPT, $1, NULL, $2);
+       menu_add_prompt(P_PROMPT, $1, $2);
 };
 
 prompt:          T_WORD
@@ -487,7 +487,7 @@ void conf_parse(const char *name)
        sym_init();
        menu_init();
        modules_sym = sym_lookup("MODULES", 0);
-       rootmenu.prompt = menu_add_prop(P_MENU, "Linux Kernel Configuration", NULL, NULL);
+       rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
 
        //zconfdebug = 1;
        zconfparse();
index 0835dc2a8aa9f4070167faa2b27905c126049616..8aaf74e64183ff46972acb0ac1d312aed4c16bfb 100755 (executable)
@@ -1665,11 +1665,17 @@ sub xml_escape($) {
 }
 
 sub process_file($) {
-    my ($file) = "$ENV{'SRCTREE'}@_";
+    my $file;
     my $identifier;
     my $func;
     my $initial_section_counter = $section_counter;
 
+    if (defined($ENV{'SRCTREE'})) {
+       $file = "$ENV{'SRCTREE'}" . "/" . "@_";
+    }
+    else {
+       $file = "@_";
+    }
     if (defined($source_map{$file})) {
        $file = $source_map{$file};
     }
index c571548daa8200add713dd605239c09c2b8f60d0..eb63e1bb63a3beb084f75eceb7fafb7b14c2217e 100644 (file)
@@ -163,7 +163,7 @@ int dialog_menu (const char *title, const char *prompt, int height, int width,
 int dialog_checklist (const char *title, const char *prompt, int height,
                int width, int list_height, int item_no,
                const char * const * items, int flag);
-extern unsigned char dialog_input_result[];
+extern char dialog_input_result[];
 int dialog_inputbox (const char *title, const char *prompt, int height,
                int width, const char *init);
 
index fa7bebc693b932d36c86cb8c6d19d3fd8a5bd999..074d2d68bd31fbcc35d5c785db79f72977d4dfb1 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "dialog.h"
 
-unsigned char dialog_input_result[MAX_LEN + 1];
+char dialog_input_result[MAX_LEN + 1];
 
 /*
  *  Print the termination buttons
@@ -48,7 +48,7 @@ dialog_inputbox (const char *title, const char *prompt, int height, int width,
 {
     int i, x, y, box_y, box_x, box_width;
     int input_x = 0, scroll = 0, key = 0, button = -1;
-    unsigned char *instr = dialog_input_result;
+    char *instr = dialog_input_result;
     WINDOW *dialog;
 
     /* center dialog box on screen */
index 8d118d1819508cf9a14d252086a89108cb8f4e0d..d7b8a384b4a7991960d33c7c01c60d6f58f92fd6 100755 (executable)
@@ -1,7 +1,8 @@
 TARGET=$1
 ARCH=$2
 SMP=$3
-CC=$4
+PREEMPT=$4
+CC=$5
 
 # If compile.h exists already and we don't own autoconf.h
 # (i.e. we're not the same user who did make *config), don't
@@ -26,8 +27,10 @@ fi
 
 
 UTS_VERSION="#$VERSION"
-if [ -n "$SMP" ] ; then UTS_VERSION="$UTS_VERSION SMP"; fi
-UTS_VERSION="$UTS_VERSION `LC_ALL=C LANG=C date`"
+CONFIG_FLAGS=""
+if [ -n "$SMP" ] ; then CONFIG_FLAGS="SMP"; fi
+if [ -n "$PREEMPT" ] ; then CONFIG_FLAGS="$CONFIG_FLAGS PREEMPT"; fi
+UTS_VERSION="$UTS_VERSION $CONFIG_FLAGS `LC_ALL=C LANG=C date`"
 
 # Truncate to maximum length
 
@@ -37,7 +40,8 @@ UTS_TRUNCATE="sed -e s/\(.\{1,$UTS_LEN\}\).*/\1/"
 # Generate a temporary compile.h
 
 ( echo /\* This file is auto generated, version $VERSION \*/
-
+  if [ -n "$CONFIG_FLAGS" ] ; then echo "/* $CONFIG_FLAGS */"; fi
+  
   echo \#define UTS_MACHINE \"$ARCH\"
 
   echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\"
index 5180405c1a844efa5a42ed8032c0059c506f5768..d8ee38aede26fee4cb8b78d8bd99467267c80da6 100644 (file)
@@ -341,6 +341,22 @@ static int do_of_entry (const char *filename, struct of_device_id *of, char *ali
     return 1;
 }
 
+static int do_vio_entry(const char *filename, struct vio_device_id *vio,
+               char *alias)
+{
+       char *tmp;
+
+       sprintf(alias, "vio:T%sS%s", vio->type[0] ? vio->type : "*",
+                       vio->compat[0] ? vio->compat : "*");
+
+       /* Replace all whitespace with underscores */
+       for (tmp = alias; tmp && *tmp; tmp++)
+               if (isspace (*tmp))
+                       *tmp = '_';
+
+       return 1;
+}
+
 /* Ignore any prefix, eg. v850 prepends _ */
 static inline int sym_is(const char *symbol, const char *name)
 {
@@ -422,6 +438,9 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
         else if (sym_is(symname, "__mod_of_device_table"))
                do_table(symval, sym->st_size, sizeof(struct of_device_id),
                         do_of_entry, mod);
+        else if (sym_is(symname, "__mod_vio_device_table"))
+               do_table(symval, sym->st_size, sizeof(struct vio_device_id),
+                        do_vio_entry, mod);
 
 }
 
index 1112347245c024f612c4ee1eea8e65dedc58a861..43271a1ca01ec82017f7f6a40fd7c6b79c9d7987 100644 (file)
@@ -252,9 +252,9 @@ static int parse_comment(const char *file, unsigned long len)
 }
 
 /* FIXME: Handle .s files differently (eg. # starts comments) --RR */
-static int parse_file(const signed char *fname, struct md4_ctx *md)
+static int parse_file(const char *fname, struct md4_ctx *md)
 {
-       signed char *file;
+       char *file;
        unsigned long i, len;
 
        file = grab_file(fname, &len);
@@ -332,7 +332,7 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md)
           Sum all files in the same dir or subdirs.
        */
        while ((line = get_next_line(&pos, file, flen)) != NULL) {
-               signed char* p = line;
+               char* p = line;
                if (strncmp(line, "deps_", sizeof("deps_")-1) == 0) {
                        check_files = 1;
                        continue;
@@ -458,7 +458,7 @@ out:
        close(fd);
 }
 
-static int strip_rcs_crap(signed char *version)
+static int strip_rcs_crap(char *version)
 {
        unsigned int len, full_len;
 
index 3b1f2eff258448c2230e6ffe94484720795aff96..f3e7e8e4a500fe8e6ae0438cd09ebd148067b3bd 100644 (file)
@@ -59,7 +59,7 @@ $(objtree)/binkernel.spec: $(MKSPEC) $(srctree)/Makefile
        $(CONFIG_SHELL) $(MKSPEC) prebuilt > $@
        
 binrpm-pkg: $(objtree)/binkernel.spec
-       $(MAKE)
+       $(MAKE) KBUILD_SRC=
        set -e; \
        $(CONFIG_SHELL) $(srctree)/scripts/mkversion > $(objtree)/.tmp_version
        set -e; \
@@ -74,16 +74,30 @@ clean-files += $(objtree)/binkernel.spec
 #
 .PHONY: deb-pkg
 deb-pkg:
-       $(MAKE)
+       $(MAKE) KBUILD_SRC=
        $(CONFIG_SHELL) $(srctree)/scripts/package/builddeb
 
 clean-dirs += $(objtree)/debian/
 
 
+# tarball targets
+# ---------------------------------------------------------------------------
+.PHONY: tar%pkg
+tar%pkg:
+       $(MAKE)
+       $(CONFIG_SHELL) $(srctree)/scripts/package/buildtar $@
+
+clean-dirs += $(objtree)/tar-install/
+
+
 # Help text displayed when executing 'make help'
 # ---------------------------------------------------------------------------
 help:
-       @echo  '  rpm-pkg         - Build the kernel as an RPM package'
-       @echo  '  binrpm-pkg      - Build an rpm package containing the compiled kernel & modules'
-       @echo  '  deb-pkg         - Build the kernel as an deb package'
+       @echo '  rpm-pkg         - Build the kernel as an RPM package'
+       @echo '  binrpm-pkg      - Build an rpm package containing the compiled kernel'
+       @echo '                    and modules'
+       @echo '  deb-pkg         - Build the kernel as an deb package'
+       @echo '  tar-pkg         - Build the kernel as an uncompressed tarball'
+       @echo '  targz-pkg       - Build the kernel as a gzip compressed tarball'
+       @echo '  tarbz2-pkg      - Build the kernel as a bzip2 compressed tarball'
 
index c279b6310f02f11bc88c0d2d0c7f10c94b690764..6edb29f2b4a6c8aa056a748168a70583897a9d3c 100644 (file)
@@ -14,18 +14,38 @@ set -e
 # Some variables and settings used throughout the script
 version=$KERNELRELEASE
 tmpdir="$objtree/debian/tmp"
+packagename=linux-$version
+
+if [ "$ARCH" == "um" ] ; then
+       packagename=user-mode-linux-$version
+fi
 
 # Setup the directory structure
 rm -rf "$tmpdir"
 mkdir -p "$tmpdir/DEBIAN" "$tmpdir/lib" "$tmpdir/boot"
+if [ "$ARCH" == "um" ] ; then
+       mkdir -p "$tmpdir/usr/lib/uml/modules/$version" "$tmpdir/usr/share/doc/$packagename" "$tmpdir/usr/bin"
+fi
 
 # Build and install the kernel
-cp System.map "$tmpdir/boot/System.map-$version"
-cp .config "$tmpdir/boot/config-$version"
-cp $KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version"
+if [ "$ARCH" == "um" ] ; then
+       $MAKE linux
+       cp System.map "$tmpdir/usr/lib/uml/modules/$version/System.map"
+       cp .config "$tmpdir/usr/share/doc/$packagename/config"
+       gzip "$tmpdir/usr/share/doc/$packagename/config"
+       cp $KBUILD_IMAGE "$tmpdir/usr/bin/linux-$version"
+else 
+       cp System.map "$tmpdir/boot/System.map-$version"
+       cp .config "$tmpdir/boot/config-$version"
+       cp $KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version"
+fi
 
 if grep -q '^CONFIG_MODULES=y' .config ; then
-       INSTALL_MOD_PATH="$tmpdir" make modules_install
+       INSTALL_MOD_PATH="$tmpdir" make KBUILD_SRC= modules_install
+       if [ "$ARCH" == "um" ] ; then
+               mv "$tmpdir/lib/modules/$version"/* "$tmpdir/usr/lib/uml/modules/$version/"
+               rmdir "$tmpdir/lib/modules/$version"
+       fi
 fi
 
 # Install the maintainer scripts
@@ -53,6 +73,8 @@ linux ($version) unstable; urgency=low
 EOF
 
 # Generate a control file
+if [ "$ARCH" == "um" ]; then
+
 cat <<EOF > debian/control
 Source: linux
 Section: base
@@ -60,12 +82,34 @@ Priority: optional
 Maintainer: $name
 Standards-Version: 3.6.1
 
-Package: linux-$version
+Package: $packagename
+Architecture: any
+Description: User Mode Linux kernel, version $version
+ User-mode Linux is a port of the Linux kernel to its own system call
+ interface.  It provides a kind of virtual machine, which runs Linux
+ as a user process under another Linux kernel.  This is useful for
+ kernel development, sandboxes, jails, experimentation, and
+ many other things.
+ .
+ This package contains the Linux kernel, modules and corresponding other
+ files version $version
+EOF
+
+else
+cat <<EOF > debian/control
+Source: linux
+Section: base
+Priority: optional
+Maintainer: $name
+Standards-Version: 3.6.1
+
+Package: $packagename
 Architecture: any
 Description: Linux kernel, version $version
  This package contains the Linux kernel, modules and corresponding other
- files version $version.
+ files version $version
 EOF
+fi
 
 # Fix some ownership and permissions
 chown -R root:root "$tmpdir"
diff --git a/scripts/package/buildtar b/scripts/package/buildtar
new file mode 100644 (file)
index 0000000..d8fffe6
--- /dev/null
@@ -0,0 +1,111 @@
+#!/bin/sh
+
+#
+# buildtar 0.0.3
+#
+# (C) 2004-2005 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
+#
+# This script is used to compile a tarball from the currently
+# prepared kernel. Based upon the builddeb script from
+# Wichert Akkerman <wichert@wiggy.net>.
+#
+
+set -e
+
+#
+# Some variables and settings used throughout the script
+#
+version="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}${EXTRANAME}"
+tmpdir="${objtree}/tar-install"
+tarball="${objtree}/linux-${version}.tar"
+
+
+#
+# Figure out how to compress, if requested at all
+#
+case "${1}" in
+       tar-pkg)
+               compress="cat"
+               file_ext=""
+               ;;
+       targz-pkg)
+               compress="gzip -c9"
+               file_ext=".gz"
+               ;;
+       tarbz2-pkg)
+               compress="bzip2 -c9"
+               file_ext=".bz2"
+               ;;
+       *)
+               echo "Unknown tarball target \"${1}\" requested, please add it to ${0}." >&2
+               exit 1
+               ;;
+esac
+
+
+#
+# Clean-up and re-create the temporary directory
+#
+rm -rf -- "${tmpdir}"
+mkdir -p -- "${tmpdir}/boot"
+
+
+#
+# Try to install modules
+#
+if ! make INSTALL_MOD_PATH="${tmpdir}" modules_install; then
+       echo "" >&2
+       echo "Ignoring error at module_install time, since that could be" >&2
+       echo "a result of missing local modutils/module-init-tools," >&2
+       echo "or you just didn't compile in module support at all..." >&2
+       echo "" >&2
+fi
+
+
+#
+# Install basic kernel files
+#
+cp -v -- System.map "${tmpdir}/boot/System.map-${version}"
+cp -v -- .config "${tmpdir}/boot/config-${version}"
+cp -v -- vmlinux "${tmpdir}/boot/vmlinux-${version}"
+
+
+#
+# Install arch-specific kernel image(s)
+#
+case "${ARCH}" in
+       i386)
+               [ -f arch/i386/boot/bzImage ] && cp -v -- arch/i386/boot/bzImage "${tmpdir}/boot/vmlinuz-${version}"
+               ;;
+       alpha)
+               [ -f arch/alpha/boot/vmlinux.gz ] && cp -v -- arch/alpha/boot/vmlinux.gz "${tmpdir}/boot/vmlinuz-${version}"
+               ;;
+       vax)
+               [ -f vmlinux.SYS ] && cp -v -- vmlinux.SYS "${tmpdir}/boot/vmlinux-${version}.SYS"
+               [ -f vmlinux.dsk ] && cp -v -- vmlinux.dsk "${tmpdir}/boot/vmlinux-${version}.dsk"
+               ;;
+       *)
+               [ -f "${KBUILD_IMAGE}" ] && cp -v -- "${KBUILD_IMAGE}" "${tmpdir}/boot/vmlinux-kbuild-${version}"
+               echo "" >&2
+               echo '** ** **  WARNING  ** ** **' >&2
+               echo "" >&2
+               echo "Your architecture did not define any architecture-dependant files" >&2
+               echo "to be placed into the tarball. Please add those to ${0} ..." >&2
+               echo "" >&2
+               sleep 5
+               ;;
+esac
+
+
+#
+# Create the tarball
+#
+(
+       cd "${tmpdir}"
+       tar cf - . | ${compress} > "${tarball}${file_ext}"
+)
+
+echo "Tarball successfully created in ${tarball}${file_ext}"
+
+exit 0
+
index 6e7a58f145adfadce753997cd40c89161944469d..0b10387375480eb70f05e4ba57a1baa5e0143275 100755 (executable)
@@ -62,10 +62,19 @@ echo ""
 fi
 
 echo "%install"
+echo "%ifarch ia64"
+echo 'mkdir -p $RPM_BUILD_ROOT/boot/efi $RPM_BUILD_ROOT/lib $RPM_BUILD_ROOT/lib/modules'
+echo "%else"
 echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib $RPM_BUILD_ROOT/lib/modules'
+echo "%endif"
 
 echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{_smp_mflags} modules_install'
+echo "%ifarch ia64"
+echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/efi/vmlinuz-$KERNELRELEASE"
+echo 'ln -s '"efi/vmlinuz-$KERNELRELEASE" '$RPM_BUILD_ROOT'"/boot/"
+echo "%else"
 echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/vmlinuz-$KERNELRELEASE"
+echo "%endif"
 
 echo 'cp System.map $RPM_BUILD_ROOT'"/boot/System.map-$KERNELRELEASE"
 
index d5cabb81bd1be5617a3afdd1cabf6c7e04f6cfde..f04f6273685161dc45c98e11f8d1065660ca0a0f 100644 (file)
@@ -96,6 +96,7 @@ foreach $object (keys(%object)) {
                     $from !~ /\.debug_ranges$/ &&
                     $from !~ /\.debug_line$/ &&
                     $from !~ /\.debug_frame$/ &&
+                    $from !~ /\.debug_loc$/ &&
                     $from !~ /\.exitcall\.exit$/ &&
                     $from !~ /\.eh_frame$/ &&
                     $from !~ /\.stab$/)) {
index 9a240845386958c574cabe4b6ca5b88a94a443ac..7f6960b175a2132f661839a807b8a9b9f3d91410 100644 (file)
@@ -98,6 +98,7 @@ foreach $object (sort(keys(%object))) {
                     $from !~ /\.pdr$/ &&
                     $from !~ /\__param$/ &&
                     $from !~ /\.altinstructions/ &&
+                    $from !~ /\.eh_frame/ &&
                     $from !~ /\.debug_/)) {
                        printf("Error: %s %s refers to %s\n", $object, $from, $line);
                }
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
new file mode 100644 (file)
index 0000000..7c805c8
--- /dev/null
@@ -0,0 +1,56 @@
+#!/usr/bin/perl
+# Copyright 2004 - Ryan Anderson <ryan@michonline.com>  GPL v2
+
+use strict;
+use warnings;
+use Digest::MD5;
+require 5.006;
+
+if (@ARGV != 1) {
+       print <<EOT;
+Usage: setlocalversion <srctree>
+EOT
+       exit(1);
+}
+
+my ($srctree) = @ARGV;
+chdir($srctree);
+
+my @LOCALVERSIONS = ();
+
+# We are going to use the following commands to try and determine if this
+# repository is at a Version boundary (i.e, 2.6.10 vs 2.6.10 + some patches) We
+# currently assume that all meaningful version boundaries are marked by a tag.
+# We don't care what the tag is, just that something exists.
+
+# Git/Cogito store the top-of-tree "commit" in .git/HEAD
+# A list of known tags sits in .git/refs/tags/
+#
+# The simple trick here is to just compare the two of these, and if we get a
+# match, return nothing, otherwise, return a subset of the SHA-1 hash in
+# .git/HEAD
+
+sub do_git_checks {
+       open(H,"<.git/HEAD") or return;
+       my $head = <H>;
+       chomp $head;
+       close(H);
+
+       opendir(D,".git/refs/tags") or return;
+       foreach my $tagfile (grep !/^\.{1,2}$/, readdir(D)) {
+               open(F,"<.git/refs/tags/" . $tagfile) or return;
+               my $tag = <F>;
+               chomp $tag;
+               close(F);
+               return if ($tag eq $head);
+       }
+       closedir(D);
+
+       push @LOCALVERSIONS, "g" . substr($head,0,8);
+}
+
+if ( -d ".git") {
+       do_git_checks();
+}
+
+printf "-%s\n", join("-",@LOCALVERSIONS) if (scalar @LOCALVERSIONS > 0);
index a28c279c49dd043b86aa976ce58bd01261d86410..beb43ef7f761fffaaa80393129e554922f92b544 100755 (executable)
@@ -25,9 +25,11 @@ ld -v | awk -F\) '{print $1}' | awk \
 '/BFD/{print "binutils              ",$NF} \
 /^GNU/{print "binutils              ",$4}'
 
-fdformat --version | awk -F\- '{print "util-linux            ", $NF}'
+echo -n "util-linux             "
+fdformat --version | awk '{print $NF}' | sed -e s/^util-linux-// -e s/\)$//
 
-mount --version | awk -F\- '{print "mount                 ", $NF}'
+echo -n "mount                  "
+mount --version | awk '{print $NF}' | sed -e s/^mount-// -e s/\)$//
 
 depmod -V  2>&1 | awk 'NR==1 {print "module-init-tools     ",$NF}'
 
index c8e87b22c9bdcca5e9d26593b383441109381ce7..96b1f2122f67bdac673a18fab792ea56e8d236ab 100644 (file)
@@ -321,7 +321,7 @@ plaintext_to_sha1(unsigned char *hash, const char *plaintext, int len)
                              "bytes.\n", len, PAGE_SIZE);
                return -ENOMEM;
        }
-       tfm = crypto_alloc_tfm("sha1", 0);
+       tfm = crypto_alloc_tfm("sha1", CRYPTO_TFM_REQ_MAY_SLEEP);
        if (tfm == NULL) {
                seclvl_printk(0, KERN_ERR,
                              "Failed to load transform for SHA1\n");
index 451502467a9b882ffda85c3626dd9a832522c880..cf6020f85403e54e23660e7c86c7e0f30e4750f4 100644 (file)
@@ -490,7 +490,7 @@ out:
 }
 
 static inline void avc_print_ipv6_addr(struct audit_buffer *ab,
-                                      struct in6_addr *addr, u16 port,
+                                      struct in6_addr *addr, __be16 port,
                                       char *name1, char *name2)
 {
        if (!ipv6_addr_any(addr))
@@ -501,7 +501,7 @@ static inline void avc_print_ipv6_addr(struct audit_buffer *ab,
 }
 
 static inline void avc_print_ipv4_addr(struct audit_buffer *ab, u32 addr,
-                                      u16 port, char *name1, char *name2)
+                                      __be16 port, char *name1, char *name2)
 {
        if (addr)
                audit_log_format(ab, " %s=%d.%d.%d.%d", name1, NIPQUAD(addr));
index 2253f388234ff7b2e031c5d30da29f5f0c1a6831..8641f8894b4c0aa458238ca8c9195a0495c9238d 100644 (file)
@@ -659,7 +659,7 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
                        return SECCLASS_NETLINK_ROUTE_SOCKET;
                case NETLINK_FIREWALL:
                        return SECCLASS_NETLINK_FIREWALL_SOCKET;
-               case NETLINK_TCPDIAG:
+               case NETLINK_INET_DIAG:
                        return SECCLASS_NETLINK_TCPDIAG_SOCKET;
                case NETLINK_NFLOG:
                        return SECCLASS_NETLINK_NFLOG_SOCKET;
index 71c0a19c97538da142962be9a458b259205c1d80..5f016c98056f53e35491c779fcb3dd2dc23c54c9 100644 (file)
 #define POLICYDB_VERSION_NLCLASS       18
 #define POLICYDB_VERSION_VALIDATETRANS 19
 #define POLICYDB_VERSION_MLS           19
+#define POLICYDB_VERSION_AVTAB         20
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN   POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_MLS
+#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_AVTAB
 
 #ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
 extern int selinux_enabled;
index 18d08acafa7827485161bee36f7a4ea16ca9587d..e203883406dd662bda61e5f9a55c5d1bcbbdbeeb 100644 (file)
@@ -80,7 +80,8 @@ static void selnl_notify(int msgtype, void *data)
        nlh = NLMSG_PUT(skb, 0, 0, msgtype, len);
        selnl_add_payload(nlh, len, msgtype, data);
        nlh->nlmsg_len = skb->tail - tmp;
-       netlink_broadcast(selnl, skb, 0, SELNL_GRP_AVC, GFP_USER);
+       NETLINK_CB(skb).dst_group = SELNLGRP_AVC;
+       netlink_broadcast(selnl, skb, 0, SELNLGRP_AVC, GFP_USER);
 out:
        return;
        
@@ -103,7 +104,8 @@ void selnl_notify_policyload(u32 seqno)
 
 static int __init selnl_init(void)
 {
-       selnl = netlink_kernel_create(NETLINK_SELINUX, NULL);
+       selnl = netlink_kernel_create(NETLINK_SELINUX, SELNLGRP_MAX, NULL,
+                                     THIS_MODULE);
        if (selnl == NULL)
                panic("SELinux:  Cannot create netlink socket.");
        netlink_set_nonroot(NETLINK_SELINUX, NL_NONROOT_RECV);  
index 92b057becb4b63abe6cb16d477998d3fcdc79fdb..69b9329b2054e1b74c0529a94991673055442305 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/if.h>
 #include <linux/netfilter_ipv4/ip_queue.h>
-#include <linux/tcp_diag.h>
+#include <linux/inet_diag.h>
 #include <linux/xfrm.h>
 #include <linux/audit.h>
 
@@ -76,6 +76,7 @@ static struct nlmsg_perm nlmsg_firewall_perms[] =
 static struct nlmsg_perm nlmsg_tcpdiag_perms[] =
 {
        { TCPDIAG_GETSOCK,      NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
+       { DCCPDIAG_GETSOCK,     NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
 };
 
 static struct nlmsg_perm nlmsg_xfrm_perms[] =
index f238c034c44e22e882dbccd71844ffb0224818dc..dde094feb20dfb5976b8e215db975b61f14df1c3 100644 (file)
@@ -58,6 +58,7 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat
 {
        int hvalue;
        struct avtab_node *prev, *cur, *newnode;
+       u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
 
        if (!h)
                return -EINVAL;
@@ -69,7 +70,7 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat
                if (key->source_type == cur->key.source_type &&
                    key->target_type == cur->key.target_type &&
                    key->target_class == cur->key.target_class &&
-                   (datum->specified & cur->datum.specified))
+                   (specified & cur->key.specified))
                        return -EEXIST;
                if (key->source_type < cur->key.source_type)
                        break;
@@ -98,6 +99,7 @@ avtab_insert_nonunique(struct avtab * h, struct avtab_key * key, struct avtab_da
 {
        int hvalue;
        struct avtab_node *prev, *cur, *newnode;
+       u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
 
        if (!h)
                return NULL;
@@ -108,7 +110,7 @@ avtab_insert_nonunique(struct avtab * h, struct avtab_key * key, struct avtab_da
                if (key->source_type == cur->key.source_type &&
                    key->target_type == cur->key.target_type &&
                    key->target_class == cur->key.target_class &&
-                   (datum->specified & cur->datum.specified))
+                   (specified & cur->key.specified))
                        break;
                if (key->source_type < cur->key.source_type)
                        break;
@@ -125,10 +127,11 @@ avtab_insert_nonunique(struct avtab * h, struct avtab_key * key, struct avtab_da
        return newnode;
 }
 
-struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key, int specified)
+struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key)
 {
        int hvalue;
        struct avtab_node *cur;
+       u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
 
        if (!h)
                return NULL;
@@ -138,7 +141,7 @@ struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key, int spe
                if (key->source_type == cur->key.source_type &&
                    key->target_type == cur->key.target_type &&
                    key->target_class == cur->key.target_class &&
-                   (specified & cur->datum.specified))
+                   (specified & cur->key.specified))
                        return &cur->datum;
 
                if (key->source_type < cur->key.source_type)
@@ -159,10 +162,11 @@ struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key, int spe
  * conjunction with avtab_search_next_node()
  */
 struct avtab_node*
-avtab_search_node(struct avtab *h, struct avtab_key *key, int specified)
+avtab_search_node(struct avtab *h, struct avtab_key *key)
 {
        int hvalue;
        struct avtab_node *cur;
+       u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
 
        if (!h)
                return NULL;
@@ -172,7 +176,7 @@ avtab_search_node(struct avtab *h, struct avtab_key *key, int specified)
                if (key->source_type == cur->key.source_type &&
                    key->target_type == cur->key.target_type &&
                    key->target_class == cur->key.target_class &&
-                   (specified & cur->datum.specified))
+                   (specified & cur->key.specified))
                        return cur;
 
                if (key->source_type < cur->key.source_type)
@@ -196,11 +200,12 @@ avtab_search_node_next(struct avtab_node *node, int specified)
        if (!node)
                return NULL;
 
+       specified &= ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
        for (cur = node->next; cur; cur = cur->next) {
                if (node->key.source_type == cur->key.source_type &&
                    node->key.target_type == cur->key.target_type &&
                    node->key.target_class == cur->key.target_class &&
-                   (specified & cur->datum.specified))
+                   (specified & cur->key.specified))
                        return cur;
 
                if (node->key.source_type < cur->key.source_type)
@@ -278,76 +283,129 @@ void avtab_hash_eval(struct avtab *h, char *tag)
               max_chain_len);
 }
 
-int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey)
+static uint16_t spec_order[] = {
+       AVTAB_ALLOWED,
+       AVTAB_AUDITDENY,
+       AVTAB_AUDITALLOW,
+       AVTAB_TRANSITION,
+       AVTAB_CHANGE,
+       AVTAB_MEMBER
+};
+
+int avtab_read_item(void *fp, u32 vers, struct avtab *a,
+                   int (*insertf)(struct avtab *a, struct avtab_key *k,
+                                  struct avtab_datum *d, void *p),
+                   void *p)
 {
-       u32 buf[7];
-       u32 items, items2;
-       int rc;
+       __le16 buf16[4];
+       u16 enabled;
+       __le32 buf32[7];
+       u32 items, items2, val;
+       struct avtab_key key;
+       struct avtab_datum datum;
+       int i, rc;
+
+       memset(&key, 0, sizeof(struct avtab_key));
+       memset(&datum, 0, sizeof(struct avtab_datum));
+
+       if (vers < POLICYDB_VERSION_AVTAB) {
+               rc = next_entry(buf32, fp, sizeof(u32));
+               if (rc < 0) {
+                       printk(KERN_ERR "security: avtab: truncated entry\n");
+                       return -1;
+               }
+               items2 = le32_to_cpu(buf32[0]);
+               if (items2 > ARRAY_SIZE(buf32)) {
+                       printk(KERN_ERR "security: avtab: entry overflow\n");
+                       return -1;
 
-       memset(avkey, 0, sizeof(struct avtab_key));
-       memset(avdatum, 0, sizeof(struct avtab_datum));
+               }
+               rc = next_entry(buf32, fp, sizeof(u32)*items2);
+               if (rc < 0) {
+                       printk(KERN_ERR "security: avtab: truncated entry\n");
+                       return -1;
+               }
+               items = 0;
 
-       rc = next_entry(buf, fp, sizeof(u32));
-       if (rc < 0) {
-               printk(KERN_ERR "security: avtab: truncated entry\n");
-               goto bad;
-       }
-       items2 = le32_to_cpu(buf[0]);
-       if (items2 > ARRAY_SIZE(buf)) {
-               printk(KERN_ERR "security: avtab: entry overflow\n");
-               goto bad;
+               val = le32_to_cpu(buf32[items++]);
+               key.source_type = (u16)val;
+               if (key.source_type != val) {
+                       printk("security: avtab: truncated source type\n");
+                       return -1;
+               }
+               val = le32_to_cpu(buf32[items++]);
+               key.target_type = (u16)val;
+               if (key.target_type != val) {
+                       printk("security: avtab: truncated target type\n");
+                       return -1;
+               }
+               val = le32_to_cpu(buf32[items++]);
+               key.target_class = (u16)val;
+               if (key.target_class != val) {
+                       printk("security: avtab: truncated target class\n");
+                       return -1;
+               }
+
+               val = le32_to_cpu(buf32[items++]);
+               enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0;
+
+               if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
+                       printk("security: avtab: null entry\n");
+                       return -1;
+               }
+               if ((val & AVTAB_AV) &&
+                   (val & AVTAB_TYPE)) {
+                       printk("security: avtab: entry has both access vectors and types\n");
+                       return -1;
+               }
+
+               for (i = 0; i < sizeof(spec_order)/sizeof(u16); i++) {
+                       if (val & spec_order[i]) {
+                               key.specified = spec_order[i] | enabled;
+                               datum.data = le32_to_cpu(buf32[items++]);
+                               rc = insertf(a, &key, &datum, p);
+                               if (rc) return rc;
+                       }
+               }
+
+               if (items != items2) {
+                       printk("security: avtab: entry only had %d items, expected %d\n", items2, items);
+                       return -1;
+               }
+               return 0;
        }
-       rc = next_entry(buf, fp, sizeof(u32)*items2);
+
+       rc = next_entry(buf16, fp, sizeof(u16)*4);
        if (rc < 0) {
-               printk(KERN_ERR "security: avtab: truncated entry\n");
-               goto bad;
+               printk("security: avtab: truncated entry\n");
+               return -1;
        }
+
        items = 0;
-       avkey->source_type = le32_to_cpu(buf[items++]);
-       avkey->target_type = le32_to_cpu(buf[items++]);
-       avkey->target_class = le32_to_cpu(buf[items++]);
-       avdatum->specified = le32_to_cpu(buf[items++]);
-       if (!(avdatum->specified & (AVTAB_AV | AVTAB_TYPE))) {
-               printk(KERN_ERR "security: avtab: null entry\n");
-               goto bad;
-       }
-       if ((avdatum->specified & AVTAB_AV) &&
-           (avdatum->specified & AVTAB_TYPE)) {
-               printk(KERN_ERR "security: avtab: entry has both access vectors and types\n");
-               goto bad;
-       }
-       if (avdatum->specified & AVTAB_AV) {
-               if (avdatum->specified & AVTAB_ALLOWED)
-                       avtab_allowed(avdatum) = le32_to_cpu(buf[items++]);
-               if (avdatum->specified & AVTAB_AUDITDENY)
-                       avtab_auditdeny(avdatum) = le32_to_cpu(buf[items++]);
-               if (avdatum->specified & AVTAB_AUDITALLOW)
-                       avtab_auditallow(avdatum) = le32_to_cpu(buf[items++]);
-       } else {
-               if (avdatum->specified & AVTAB_TRANSITION)
-                       avtab_transition(avdatum) = le32_to_cpu(buf[items++]);
-               if (avdatum->specified & AVTAB_CHANGE)
-                       avtab_change(avdatum) = le32_to_cpu(buf[items++]);
-               if (avdatum->specified & AVTAB_MEMBER)
-                       avtab_member(avdatum) = le32_to_cpu(buf[items++]);
-       }
-       if (items != items2) {
-               printk(KERN_ERR "security: avtab: entry only had %d items, expected %d\n",
-                      items2, items);
-               goto bad;
+       key.source_type = le16_to_cpu(buf16[items++]);
+       key.target_type = le16_to_cpu(buf16[items++]);
+       key.target_class = le16_to_cpu(buf16[items++]);
+       key.specified = le16_to_cpu(buf16[items++]);
+
+       rc = next_entry(buf32, fp, sizeof(u32));
+       if (rc < 0) {
+               printk("security: avtab: truncated entry\n");
+               return -1;
        }
+       datum.data = le32_to_cpu(*buf32);
+       return insertf(a, &key, &datum, p);
+}
 
-       return 0;
-bad:
-       return -1;
+static int avtab_insertf(struct avtab *a, struct avtab_key *k,
+                        struct avtab_datum *d, void *p)
+{
+       return avtab_insert(a, k, d);
 }
 
-int avtab_read(struct avtab *a, void *fp, u32 config)
+int avtab_read(struct avtab *a, void *fp, u32 vers)
 {
        int rc;
-       struct avtab_key avkey;
-       struct avtab_datum avdatum;
-       u32 buf[1];
+       __le32 buf[1];
        u32 nel, i;
 
 
@@ -363,16 +421,14 @@ int avtab_read(struct avtab *a, void *fp, u32 config)
                goto bad;
        }
        for (i = 0; i < nel; i++) {
-               if (avtab_read_item(fp, &avdatum, &avkey)) {
-                       rc = -EINVAL;
-                       goto bad;
-               }
-               rc = avtab_insert(a, &avkey, &avdatum);
+               rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL);
                if (rc) {
                        if (rc == -ENOMEM)
                                printk(KERN_ERR "security: avtab: out of memory\n");
-                       if (rc == -EEXIST)
+                       else if (rc == -EEXIST)
                                printk(KERN_ERR "security: avtab: duplicate entry\n");
+                       else
+                               rc = -EINVAL;
                        goto bad;
                }
        }
index 519d4f6dc655e0cce267a15a0f93880fabeafa11..0a90d939af93f8b17167fbef67dbab34b8f2bd04 100644 (file)
 #define _SS_AVTAB_H_
 
 struct avtab_key {
-       u32 source_type;        /* source type */
-       u32 target_type;        /* target type */
-       u32 target_class;       /* target object class */
-};
-
-struct avtab_datum {
+       u16 source_type;        /* source type */
+       u16 target_type;        /* target type */
+       u16 target_class;       /* target object class */
 #define AVTAB_ALLOWED     1
 #define AVTAB_AUDITALLOW  2
 #define AVTAB_AUDITDENY   4
@@ -35,15 +32,13 @@ struct avtab_datum {
 #define AVTAB_MEMBER     32
 #define AVTAB_CHANGE     64
 #define AVTAB_TYPE       (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
-#define AVTAB_ENABLED    0x80000000 /* reserved for used in cond_avtab */
-       u32 specified;  /* what fields are specified */
-       u32 data[3];    /* access vectors or types */
-#define avtab_allowed(x) (x)->data[0]
-#define avtab_auditdeny(x) (x)->data[1]
-#define avtab_auditallow(x) (x)->data[2]
-#define avtab_transition(x) (x)->data[0]
-#define avtab_change(x) (x)->data[1]
-#define avtab_member(x) (x)->data[2]
+#define AVTAB_ENABLED_OLD    0x80000000 /* reserved for used in cond_avtab */
+#define AVTAB_ENABLED    0x8000 /* reserved for used in cond_avtab */
+       u16 specified;  /* what field is specified */
+};
+
+struct avtab_datum {
+       u32 data; /* access vector or type value */
 };
 
 struct avtab_node {
@@ -58,17 +53,21 @@ struct avtab {
 };
 
 int avtab_init(struct avtab *);
-struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k, int specified);
+struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
 void avtab_destroy(struct avtab *h);
 void avtab_hash_eval(struct avtab *h, char *tag);
 
-int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey);
-int avtab_read(struct avtab *a, void *fp, u32 config);
+int avtab_read_item(void *fp, uint32_t vers, struct avtab *a,
+                   int (*insert)(struct avtab *a, struct avtab_key *k,
+                                 struct avtab_datum *d, void *p),
+                   void *p);
+
+int avtab_read(struct avtab *a, void *fp, u32 vers);
 
 struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key,
                                          struct avtab_datum *datum);
 
-struct avtab_node *avtab_search_node(struct avtab *h, struct avtab_key *key, int specified);
+struct avtab_node *avtab_search_node(struct avtab *h, struct avtab_key *key);
 
 struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified);
 
index e2057f5a411a470372efcf919bfa502daa5149d9..daf2880074607fd535080ed6a08bebd3a36a3082 100644 (file)
@@ -100,18 +100,18 @@ int evaluate_cond_node(struct policydb *p, struct cond_node *node)
                /* turn the rules on or off */
                for (cur = node->true_list; cur != NULL; cur = cur->next) {
                        if (new_state <= 0) {
-                               cur->node->datum.specified &= ~AVTAB_ENABLED;
+                               cur->node->key.specified &= ~AVTAB_ENABLED;
                        } else {
-                               cur->node->datum.specified |= AVTAB_ENABLED;
+                               cur->node->key.specified |= AVTAB_ENABLED;
                        }
                }
 
                for (cur = node->false_list; cur != NULL; cur = cur->next) {
                        /* -1 or 1 */
                        if (new_state) {
-                               cur->node->datum.specified &= ~AVTAB_ENABLED;
+                               cur->node->key.specified &= ~AVTAB_ENABLED;
                        } else {
-                               cur->node->datum.specified |= AVTAB_ENABLED;
+                               cur->node->key.specified |= AVTAB_ENABLED;
                        }
                }
        }
@@ -216,7 +216,8 @@ int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp)
 {
        char *key = NULL;
        struct cond_bool_datum *booldatum;
-       u32 buf[3], len;
+       __le32 buf[3];
+       u32 len;
        int rc;
 
        booldatum = kmalloc(sizeof(struct cond_bool_datum), GFP_KERNEL);
@@ -252,104 +253,127 @@ err:
        return -1;
 }
 
-static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list,
-                            struct cond_av_list *other)
+struct cond_insertf_data
 {
-       struct cond_av_list *list, *last = NULL, *cur;
-       struct avtab_key key;
-       struct avtab_datum datum;
+       struct policydb *p;
+       struct cond_av_list *other;
+       struct cond_av_list *head;
+       struct cond_av_list *tail;
+};
+
+static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum *d, void *ptr)
+{
+       struct cond_insertf_data *data = ptr;
+       struct policydb *p = data->p;
+       struct cond_av_list *other = data->other, *list, *cur;
        struct avtab_node *node_ptr;
-       int rc;
-       u32 buf[1], i, len;
        u8 found;
 
-       *ret_list = NULL;
-
-       len = 0;
-       rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0)
-               return -1;
-
-       len = le32_to_cpu(buf[0]);
-       if (len == 0) {
-               return 0;
-       }
 
-       for (i = 0; i < len; i++) {
-               if (avtab_read_item(fp, &datum, &key))
+       /*
+        * For type rules we have to make certain there aren't any
+        * conflicting rules by searching the te_avtab and the
+        * cond_te_avtab.
+        */
+       if (k->specified & AVTAB_TYPE) {
+               if (avtab_search(&p->te_avtab, k)) {
+                       printk("security: type rule already exists outside of a conditional.");
                        goto err;
-
+               }
                /*
-                * For type rules we have to make certain there aren't any
-                * conflicting rules by searching the te_avtab and the
-                * cond_te_avtab.
+                * If we are reading the false list other will be a pointer to
+                * the true list. We can have duplicate entries if there is only
+                * 1 other entry and it is in our true list.
+                *
+                * If we are reading the true list (other == NULL) there shouldn't
+                * be any other entries.
                 */
-               if (datum.specified & AVTAB_TYPE) {
-                       if (avtab_search(&p->te_avtab, &key, AVTAB_TYPE)) {
-                               printk("security: type rule already exists outside of a conditional.");
-                               goto err;
-                       }
-                       /*
-                        * If we are reading the false list other will be a pointer to
-                        * the true list. We can have duplicate entries if there is only
-                        * 1 other entry and it is in our true list.
-                        *
-                        * If we are reading the true list (other == NULL) there shouldn't
-                        * be any other entries.
-                        */
-                       if (other) {
-                               node_ptr = avtab_search_node(&p->te_cond_avtab, &key, AVTAB_TYPE);
-                               if (node_ptr) {
-                                       if (avtab_search_node_next(node_ptr, AVTAB_TYPE)) {
-                                               printk("security: too many conflicting type rules.");
-                                               goto err;
-                                       }
-                                       found = 0;
-                                       for (cur = other; cur != NULL; cur = cur->next) {
-                                               if (cur->node == node_ptr) {
-                                                       found = 1;
-                                                       break;
-                                               }
-                                       }
-                                       if (!found) {
-                                               printk("security: conflicting type rules.");
-                                               goto err;
+               if (other) {
+                       node_ptr = avtab_search_node(&p->te_cond_avtab, k);
+                       if (node_ptr) {
+                               if (avtab_search_node_next(node_ptr, k->specified)) {
+                                       printk("security: too many conflicting type rules.");
+                                       goto err;
+                               }
+                               found = 0;
+                               for (cur = other; cur != NULL; cur = cur->next) {
+                                       if (cur->node == node_ptr) {
+                                               found = 1;
+                                               break;
                                        }
                                }
-                       } else {
-                               if (avtab_search(&p->te_cond_avtab, &key, AVTAB_TYPE)) {
-                                       printk("security: conflicting type rules when adding type rule for true.");
+                               if (!found) {
+                                       printk("security: conflicting type rules.\n");
                                        goto err;
                                }
                        }
+               } else {
+                       if (avtab_search(&p->te_cond_avtab, k)) {
+                               printk("security: conflicting type rules when adding type rule for true.\n");
+                               goto err;
+                       }
                }
-               node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, &key, &datum);
-               if (!node_ptr) {
-                       printk("security: could not insert rule.");
-                       goto err;
-               }
-
-               list = kmalloc(sizeof(struct cond_av_list), GFP_KERNEL);
-               if (!list)
-                       goto err;
-               memset(list, 0, sizeof(struct cond_av_list));
-
-               list->node = node_ptr;
-               if (i == 0)
-                       *ret_list = list;
-               else
-                       last->next = list;
-               last = list;
+       }
 
+       node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
+       if (!node_ptr) {
+               printk("security: could not insert rule.");
+               goto err;
        }
 
+       list = kmalloc(sizeof(struct cond_av_list), GFP_KERNEL);
+       if (!list)
+               goto err;
+       memset(list, 0, sizeof(*list));
+
+       list->node = node_ptr;
+       if (!data->head)
+               data->head = list;
+       else
+               data->tail->next = list;
+       data->tail = list;
        return 0;
+
 err:
-       cond_av_list_destroy(*ret_list);
-       *ret_list = NULL;
+       cond_av_list_destroy(data->head);
+       data->head = NULL;
        return -1;
 }
 
+static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other)
+{
+       int i, rc;
+       __le32 buf[1];
+       u32 len;
+       struct cond_insertf_data data;
+
+       *ret_list = NULL;
+
+       len = 0;
+       rc = next_entry(buf, fp, sizeof(u32));
+       if (rc < 0)
+               return -1;
+
+       len = le32_to_cpu(buf[0]);
+       if (len == 0) {
+               return 0;
+       }
+
+       data.p = p;
+       data.other = other;
+       data.head = NULL;
+       data.tail = NULL;
+       for (i = 0; i < len; i++) {
+               rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab, cond_insertf, &data);
+               if (rc)
+                       return rc;
+
+       }
+
+       *ret_list = data.head;
+       return 0;
+}
+
 static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
 {
        if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
@@ -366,7 +390,8 @@ static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
 
 static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
 {
-       u32 buf[2], len, i;
+       __le32 buf[2];
+       u32 len, i;
        int rc;
        struct cond_expr *expr = NULL, *last = NULL;
 
@@ -424,7 +449,8 @@ err:
 int cond_read_list(struct policydb *p, void *fp)
 {
        struct cond_node *node, *last = NULL;
-       u32 buf[1], i, len;
+       __le32 buf[1];
+       u32 i, len;
        int rc;
 
        rc = next_entry(buf, fp, sizeof buf);
@@ -452,6 +478,7 @@ int cond_read_list(struct policydb *p, void *fp)
        return 0;
 err:
        cond_list_destroy(p->cond_list);
+       p->cond_list = NULL;
        return -1;
 }
 
@@ -465,22 +492,22 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decisi
        if(!ctab || !key || !avd)
                return;
 
-       for(node = avtab_search_node(ctab, key, AVTAB_AV); node != NULL;
-                               node = avtab_search_node_next(node, AVTAB_AV)) {
-               if ( (__u32) (AVTAB_ALLOWED|AVTAB_ENABLED) ==
-                    (node->datum.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
-                       avd->allowed |= avtab_allowed(&node->datum);
-               if ( (__u32) (AVTAB_AUDITDENY|AVTAB_ENABLED) ==
-                    (node->datum.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
+       for(node = avtab_search_node(ctab, key); node != NULL;
+                               node = avtab_search_node_next(node, key->specified)) {
+               if ( (u16) (AVTAB_ALLOWED|AVTAB_ENABLED) ==
+                    (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
+                       avd->allowed |= node->datum.data;
+               if ( (u16) (AVTAB_AUDITDENY|AVTAB_ENABLED) ==
+                    (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
                        /* Since a '0' in an auditdeny mask represents a
                         * permission we do NOT want to audit (dontaudit), we use
                         * the '&' operand to ensure that all '0's in the mask
                         * are retained (much unlike the allow and auditallow cases).
                         */
-                       avd->auditdeny &= avtab_auditdeny(&node->datum);
-               if ( (__u32) (AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
-                    (node->datum.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
-                       avd->auditallow |= avtab_auditallow(&node->datum);
+                       avd->auditdeny &= node->datum.data;
+               if ( (u16) (AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
+                    (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
+                       avd->auditallow |= node->datum.data;
        }
        return;
 }
index d8ce9cc0b9f15042c50bc7abf2b3bea9202031bb..d515154128cc613bcdc916191f44936a411029fc 100644 (file)
@@ -196,8 +196,9 @@ int ebitmap_read(struct ebitmap *e, void *fp)
 {
        int rc;
        struct ebitmap_node *n, *l;
-       u32 buf[3], mapsize, count, i;
-       u64 map;
+       __le32 buf[3];
+       u32 mapsize, count, i;
+       __le64 map;
 
        ebitmap_init(e);
 
index 471370233fd9e93a1467bb6b3ebaa85b9194b1da..8bf41055a6cb7303c7a781e8b77513c1ecbbe5a8 100644 (file)
@@ -32,11 +32,41 @@ struct ebitmap {
 #define ebitmap_length(e) ((e)->highbit)
 #define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
 
+static inline unsigned int ebitmap_start(struct ebitmap *e,
+                                        struct ebitmap_node **n)
+{
+       *n = e->node;
+       return ebitmap_startbit(e);
+}
+
 static inline void ebitmap_init(struct ebitmap *e)
 {
        memset(e, 0, sizeof(*e));
 }
 
+static inline unsigned int ebitmap_next(struct ebitmap_node **n,
+                                       unsigned int bit)
+{
+       if ((bit == ((*n)->startbit + MAPSIZE - 1)) &&
+           (*n)->next) {
+               *n = (*n)->next;
+               return (*n)->startbit;
+       }
+
+       return (bit+1);
+}
+
+static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
+                                      unsigned int bit)
+{
+       if (n->map & (MAPBIT << (bit - n->startbit)))
+               return 1;
+       return 0;
+}
+
+#define ebitmap_for_each_bit(e, n, bit) \
+       for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
+
 int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
 int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
 int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2);
index d4c32c39ccc9db9533eb1fb60f495edeb94fe77d..aaefac2921f1d94cedbd33f29afa631796e28503 100644 (file)
@@ -27,6 +27,7 @@
 int mls_compute_context_len(struct context * context)
 {
        int i, l, len, range;
+       struct ebitmap_node *node;
 
        if (!selinux_mls_enabled)
                return 0;
@@ -36,24 +37,24 @@ int mls_compute_context_len(struct context * context)
                range = 0;
                len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
 
-               for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) {
-                       if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
+               ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
+                       if (ebitmap_node_get_bit(node, i)) {
                                if (range) {
                                        range++;
                                        continue;
                                }
 
-                               len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
+                               len += strlen(policydb.p_cat_val_to_name[i]) + 1;
                                range++;
                        } else {
                                if (range > 1)
-                                       len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1;
+                                       len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
                                range = 0;
                        }
                }
                /* Handle case where last category is the end of range */
                if (range > 1)
-                       len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1;
+                       len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
 
                if (l == 0) {
                        if (mls_level_eq(&context->range.level[0],
@@ -77,6 +78,7 @@ void mls_sid_to_context(struct context *context,
 {
        char *scontextp;
        int i, l, range, wrote_sep;
+       struct ebitmap_node *node;
 
        if (!selinux_mls_enabled)
                return;
@@ -94,8 +96,8 @@ void mls_sid_to_context(struct context *context,
                scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
 
                /* categories */
-               for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) {
-                       if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
+               ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
+                       if (ebitmap_node_get_bit(node, i)) {
                                if (range) {
                                        range++;
                                        continue;
@@ -106,8 +108,8 @@ void mls_sid_to_context(struct context *context,
                                        wrote_sep = 1;
                                } else
                                        *scontextp++ = ',';
-                               strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
-                               scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
+                               strcpy(scontextp, policydb.p_cat_val_to_name[i]);
+                               scontextp += strlen(policydb.p_cat_val_to_name[i]);
                                range++;
                        } else {
                                if (range > 1) {
@@ -116,8 +118,8 @@ void mls_sid_to_context(struct context *context,
                                        else
                                                *scontextp++ = ',';
 
-                                       strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
-                                       scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
+                                       strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
+                                       scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
                                }
                                range = 0;
                        }
@@ -130,8 +132,8 @@ void mls_sid_to_context(struct context *context,
                        else
                                *scontextp++ = ',';
 
-                       strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
-                       scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
+                       strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
+                       scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
                }
 
                if (l == 0) {
@@ -157,6 +159,7 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
 {
        struct level_datum *levdatum;
        struct user_datum *usrdatum;
+       struct ebitmap_node *node;
        int i, l;
 
        if (!selinux_mls_enabled)
@@ -179,11 +182,11 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
                if (!levdatum)
                        return 0;
 
-               for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
-                       if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
+               ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
+                       if (ebitmap_node_get_bit(node, i)) {
                                if (i > p->p_cats.nprim)
                                        return 0;
-                               if (!ebitmap_get_bit(&levdatum->level->cat, i - 1))
+                               if (!ebitmap_get_bit(&levdatum->level->cat, i))
                                        /*
                                         * Category may not be associated with
                                         * sensitivity in low level.
@@ -468,6 +471,7 @@ int mls_convert_context(struct policydb *oldp,
        struct level_datum *levdatum;
        struct cat_datum *catdatum;
        struct ebitmap bitmap;
+       struct ebitmap_node *node;
        int l, i;
 
        if (!selinux_mls_enabled)
@@ -482,12 +486,12 @@ int mls_convert_context(struct policydb *oldp,
                c->range.level[l].sens = levdatum->level->sens;
 
                ebitmap_init(&bitmap);
-               for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
-                       if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
+               ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
+                       if (ebitmap_node_get_bit(node, i)) {
                                int rc;
 
                                catdatum = hashtab_search(newp->p_cats.table,
-                                               oldp->p_cat_val_to_name[i - 1]);
+                                               oldp->p_cat_val_to_name[i]);
                                if (!catdatum)
                                        return -EINVAL;
                                rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
index 785c33cf486491afc6b2d50d568d5db884b31723..0a758323a9cf61b10678d7308a87fc05316129cf 100644 (file)
@@ -91,6 +91,11 @@ static struct policydb_compat_info policydb_compat[] = {
                .sym_num        = SYM_NUM,
                .ocon_num       = OCON_NUM,
        },
+       {
+               .version        = POLICYDB_VERSION_AVTAB,
+               .sym_num        = SYM_NUM,
+               .ocon_num       = OCON_NUM,
+       },
 };
 
 static struct policydb_compat_info *policydb_lookup_compat(int version)
@@ -584,6 +589,9 @@ void policydb_destroy(struct policydb *p)
        struct ocontext *c, *ctmp;
        struct genfs *g, *gtmp;
        int i;
+       struct role_allow *ra, *lra = NULL;
+       struct role_trans *tr, *ltr = NULL;
+       struct range_trans *rt, *lrt = NULL;
 
        for (i = 0; i < SYM_NUM; i++) {
                hashtab_map(p->symtab[i].table, destroy_f[i], NULL);
@@ -624,6 +632,28 @@ void policydb_destroy(struct policydb *p)
 
        cond_policydb_destroy(p);
 
+       for (tr = p->role_tr; tr; tr = tr->next) {
+               if (ltr) kfree(ltr);
+               ltr = tr;
+       }
+       if (ltr) kfree(ltr);
+
+       for (ra = p->role_allow; ra; ra = ra -> next) {
+               if (lra) kfree(lra);
+               lra = ra;
+       }
+       if (lra) kfree(lra);
+
+       for (rt = p->range_tr; rt; rt = rt -> next) {
+               if (lrt) kfree(lrt);
+               lrt = rt;
+       }
+       if (lrt) kfree(lrt);
+
+       for (i = 0; i < p->p_types.nprim; i++)
+               ebitmap_destroy(&p->type_attr_map[i]);
+       kfree(p->type_attr_map);
+
        return;
 }
 
@@ -714,7 +744,8 @@ int policydb_context_isvalid(struct policydb *p, struct context *c)
  */
 static int mls_read_range_helper(struct mls_range *r, void *fp)
 {
-       u32 buf[2], items;
+       __le32 buf[2];
+       u32 items;
        int rc;
 
        rc = next_entry(buf, fp, sizeof(u32));
@@ -775,7 +806,7 @@ static int context_read_and_validate(struct context *c,
                                     struct policydb *p,
                                     void *fp)
 {
-       u32 buf[3];
+       __le32 buf[3];
        int rc;
 
        rc = next_entry(buf, fp, sizeof buf);
@@ -815,7 +846,8 @@ static int perm_read(struct policydb *p, struct hashtab *h, void *fp)
        char *key = NULL;
        struct perm_datum *perdatum;
        int rc;
-       u32 buf[2], len;
+       __le32 buf[2];
+       u32 len;
 
        perdatum = kmalloc(sizeof(*perdatum), GFP_KERNEL);
        if (!perdatum) {
@@ -855,7 +887,8 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp)
 {
        char *key = NULL;
        struct common_datum *comdatum;
-       u32 buf[4], len, nel;
+       __le32 buf[4];
+       u32 len, nel;
        int i, rc;
 
        comdatum = kmalloc(sizeof(*comdatum), GFP_KERNEL);
@@ -909,7 +942,8 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons,
 {
        struct constraint_node *c, *lc;
        struct constraint_expr *e, *le;
-       u32 buf[3], nexpr;
+       __le32 buf[3];
+       u32 nexpr;
        int rc, i, j, depth;
 
        lc = NULL;
@@ -993,7 +1027,8 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
 {
        char *key = NULL;
        struct class_datum *cladatum;
-       u32 buf[6], len, len2, ncons, nel;
+       __le32 buf[6];
+       u32 len, len2, ncons, nel;
        int i, rc;
 
        cladatum = kmalloc(sizeof(*cladatum), GFP_KERNEL);
@@ -1087,7 +1122,8 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
        char *key = NULL;
        struct role_datum *role;
        int rc;
-       u32 buf[2], len;
+       __le32 buf[2];
+       u32 len;
 
        role = kmalloc(sizeof(*role), GFP_KERNEL);
        if (!role) {
@@ -1147,7 +1183,8 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
        char *key = NULL;
        struct type_datum *typdatum;
        int rc;
-       u32 buf[3], len;
+       __le32 buf[3];
+       u32 len;
 
        typdatum = kmalloc(sizeof(*typdatum),GFP_KERNEL);
        if (!typdatum) {
@@ -1191,7 +1228,7 @@ bad:
  */
 static int mls_read_level(struct mls_level *lp, void *fp)
 {
-       u32 buf[1];
+       __le32 buf[1];
        int rc;
 
        memset(lp, 0, sizeof(*lp));
@@ -1219,7 +1256,8 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
        char *key = NULL;
        struct user_datum *usrdatum;
        int rc;
-       u32 buf[2], len;
+       __le32 buf[2];
+       u32 len;
 
        usrdatum = kmalloc(sizeof(*usrdatum), GFP_KERNEL);
        if (!usrdatum) {
@@ -1273,7 +1311,8 @@ static int sens_read(struct policydb *p, struct hashtab *h, void *fp)
        char *key = NULL;
        struct level_datum *levdatum;
        int rc;
-       u32 buf[2], len;
+       __le32 buf[2];
+       u32 len;
 
        levdatum = kmalloc(sizeof(*levdatum), GFP_ATOMIC);
        if (!levdatum) {
@@ -1324,7 +1363,8 @@ static int cat_read(struct policydb *p, struct hashtab *h, void *fp)
        char *key = NULL;
        struct cat_datum *catdatum;
        int rc;
-       u32 buf[3], len;
+       __le32 buf[3];
+       u32 len;
 
        catdatum = kmalloc(sizeof(*catdatum), GFP_ATOMIC);
        if (!catdatum) {
@@ -1387,7 +1427,8 @@ int policydb_read(struct policydb *p, void *fp)
        struct ocontext *l, *c, *newc;
        struct genfs *genfs_p, *genfs, *newgenfs;
        int i, j, rc;
-       u32 buf[8], len, len2, config, nprim, nel, nel2;
+       __le32 buf[8];
+       u32 len, len2, config, nprim, nel, nel2;
        char *policydb_str;
        struct policydb_compat_info *info;
        struct range_trans *rt, *lrt;
@@ -1403,17 +1444,14 @@ int policydb_read(struct policydb *p, void *fp)
        if (rc < 0)
                goto bad;
 
-       for (i = 0; i < 2; i++)
-               buf[i] = le32_to_cpu(buf[i]);
-
-       if (buf[0] != POLICYDB_MAGIC) {
+       if (le32_to_cpu(buf[0]) != POLICYDB_MAGIC) {
                printk(KERN_ERR "security:  policydb magic number 0x%x does "
                       "not match expected magic number 0x%x\n",
-                      buf[0], POLICYDB_MAGIC);
+                      le32_to_cpu(buf[0]), POLICYDB_MAGIC);
                goto bad;
        }
 
-       len = buf[1];
+       len = le32_to_cpu(buf[1]);
        if (len != strlen(POLICYDB_STRING)) {
                printk(KERN_ERR "security:  policydb string length %d does not "
                       "match expected length %Zu\n",
@@ -1448,19 +1486,17 @@ int policydb_read(struct policydb *p, void *fp)
        rc = next_entry(buf, fp, sizeof(u32)*4);
        if (rc < 0)
                goto bad;
-       for (i = 0; i < 4; i++)
-               buf[i] = le32_to_cpu(buf[i]);
 
-       p->policyvers = buf[0];
+       p->policyvers = le32_to_cpu(buf[0]);
        if (p->policyvers < POLICYDB_VERSION_MIN ||
            p->policyvers > POLICYDB_VERSION_MAX) {
                printk(KERN_ERR "security:  policydb version %d does not match "
                       "my version range %d-%d\n",
-                      buf[0], POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
+                      le32_to_cpu(buf[0]), POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
                goto bad;
        }
 
-       if ((buf[1] & POLICYDB_CONFIG_MLS)) {
+       if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) {
                if (ss_initialized && !selinux_mls_enabled) {
                        printk(KERN_ERR "Cannot switch between non-MLS and MLS "
                               "policies\n");
@@ -1489,9 +1525,11 @@ int policydb_read(struct policydb *p, void *fp)
                goto bad;
        }
 
-       if (buf[2] != info->sym_num || buf[3] != info->ocon_num) {
+       if (le32_to_cpu(buf[2]) != info->sym_num ||
+               le32_to_cpu(buf[3]) != info->ocon_num) {
                printk(KERN_ERR "security:  policydb table sizes (%d,%d) do "
-                      "not match mine (%d,%d)\n", buf[2], buf[3],
+                      "not match mine (%d,%d)\n", le32_to_cpu(buf[2]),
+                       le32_to_cpu(buf[3]),
                       info->sym_num, info->ocon_num);
                goto bad;
        }
@@ -1511,7 +1549,7 @@ int policydb_read(struct policydb *p, void *fp)
                p->symtab[i].nprim = nprim;
        }
 
-       rc = avtab_read(&p->te_avtab, fp, config);
+       rc = avtab_read(&p->te_avtab, fp, p->policyvers);
        if (rc)
                goto bad;
 
@@ -1825,6 +1863,21 @@ int policydb_read(struct policydb *p, void *fp)
                }
        }
 
+       p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL);
+       if (!p->type_attr_map)
+               goto bad;
+
+       for (i = 0; i < p->p_types.nprim; i++) {
+               ebitmap_init(&p->type_attr_map[i]);
+               if (p->policyvers >= POLICYDB_VERSION_AVTAB) {
+                       if (ebitmap_read(&p->type_attr_map[i], fp))
+                               goto bad;
+               }
+               /* add the type itself as the degenerate case */
+               if (ebitmap_set_bit(&p->type_attr_map[i], i, 1))
+                               goto bad;
+       }
+
        rc = 0;
 out:
        return rc;
index 2470e2a1a1c3cab1c18a38617025025f82e7a5b1..b1340711f721b71954806a4f858e60d99d0617cd 100644 (file)
@@ -237,6 +237,9 @@ struct policydb {
        /* range transitions */
        struct range_trans *range_tr;
 
+       /* type -> attribute reverse mapping */
+       struct ebitmap *type_attr_map;
+
        unsigned int policyvers;
 };
 
index 014120474e69915f48aee0d99243b8817e7aed9d..92b89dc99bcd72a5e3bc51ee24795b434475317f 100644 (file)
@@ -266,8 +266,11 @@ static int context_struct_compute_av(struct context *scontext,
        struct constraint_node *constraint;
        struct role_allow *ra;
        struct avtab_key avkey;
-       struct avtab_datum *avdatum;
+       struct avtab_node *node;
        struct class_datum *tclass_datum;
+       struct ebitmap *sattr, *tattr;
+       struct ebitmap_node *snode, *tnode;
+       unsigned int i, j;
 
        /*
         * Remap extended Netlink classes for old policy versions.
@@ -300,21 +303,34 @@ static int context_struct_compute_av(struct context *scontext,
         * If a specific type enforcement rule was defined for
         * this permission check, then use it.
         */
-       avkey.source_type = scontext->type;
-       avkey.target_type = tcontext->type;
        avkey.target_class = tclass;
-       avdatum = avtab_search(&policydb.te_avtab, &avkey, AVTAB_AV);
-       if (avdatum) {
-               if (avdatum->specified & AVTAB_ALLOWED)
-                       avd->allowed = avtab_allowed(avdatum);
-               if (avdatum->specified & AVTAB_AUDITDENY)
-                       avd->auditdeny = avtab_auditdeny(avdatum);
-               if (avdatum->specified & AVTAB_AUDITALLOW)
-                       avd->auditallow = avtab_auditallow(avdatum);
-       }
+       avkey.specified = AVTAB_AV;
+       sattr = &policydb.type_attr_map[scontext->type - 1];
+       tattr = &policydb.type_attr_map[tcontext->type - 1];
+       ebitmap_for_each_bit(sattr, snode, i) {
+               if (!ebitmap_node_get_bit(snode, i))
+                       continue;
+               ebitmap_for_each_bit(tattr, tnode, j) {
+                       if (!ebitmap_node_get_bit(tnode, j))
+                               continue;
+                       avkey.source_type = i + 1;
+                       avkey.target_type = j + 1;
+                       for (node = avtab_search_node(&policydb.te_avtab, &avkey);
+                            node != NULL;
+                            node = avtab_search_node_next(node, avkey.specified)) {
+                               if (node->key.specified == AVTAB_ALLOWED)
+                                       avd->allowed |= node->datum.data;
+                               else if (node->key.specified == AVTAB_AUDITALLOW)
+                                       avd->auditallow |= node->datum.data;
+                               else if (node->key.specified == AVTAB_AUDITDENY)
+                                       avd->auditdeny &= node->datum.data;
+                       }
 
-       /* Check conditional av table for additional permissions */
-       cond_compute_av(&policydb.te_cond_avtab, &avkey, avd);
+                       /* Check conditional av table for additional permissions */
+                       cond_compute_av(&policydb.te_cond_avtab, &avkey, avd);
+
+               }
+       }
 
        /*
         * Remove any permissions prohibited by a constraint (this includes
@@ -797,7 +813,6 @@ static int security_compute_sid(u32 ssid,
        struct avtab_key avkey;
        struct avtab_datum *avdatum;
        struct avtab_node *node;
-       unsigned int type_change = 0;
        int rc = 0;
 
        if (!ss_initialized) {
@@ -862,33 +877,23 @@ static int security_compute_sid(u32 ssid,
        avkey.source_type = scontext->type;
        avkey.target_type = tcontext->type;
        avkey.target_class = tclass;
-       avdatum = avtab_search(&policydb.te_avtab, &avkey, AVTAB_TYPE);
+       avkey.specified = specified;
+       avdatum = avtab_search(&policydb.te_avtab, &avkey);
 
        /* If no permanent rule, also check for enabled conditional rules */
        if(!avdatum) {
-               node = avtab_search_node(&policydb.te_cond_avtab, &avkey, specified);
+               node = avtab_search_node(&policydb.te_cond_avtab, &avkey);
                for (; node != NULL; node = avtab_search_node_next(node, specified)) {
-                       if (node->datum.specified & AVTAB_ENABLED) {
+                       if (node->key.specified & AVTAB_ENABLED) {
                                avdatum = &node->datum;
                                break;
                        }
                }
        }
 
-       type_change = (avdatum && (avdatum->specified & specified));
-       if (type_change) {
+       if (avdatum) {
                /* Use the type from the type transition/member/change rule. */
-               switch (specified) {
-               case AVTAB_TRANSITION:
-                       newcontext.type = avtab_transition(avdatum);
-                       break;
-               case AVTAB_MEMBER:
-                       newcontext.type = avtab_member(avdatum);
-                       break;
-               case AVTAB_CHANGE:
-                       newcontext.type = avtab_change(avdatum);
-                       break;
-               }
+               newcontext.type = avdatum->data;
        }
 
        /* Check for class-specific changes. */
@@ -1502,6 +1507,7 @@ int security_get_user_sids(u32 fromsid,
        struct user_datum *user;
        struct role_datum *role;
        struct av_decision avd;
+       struct ebitmap_node *rnode, *tnode;
        int rc = 0, i, j;
 
        if (!ss_initialized) {
@@ -1532,13 +1538,13 @@ int security_get_user_sids(u32 fromsid,
        }
        memset(mysids, 0, maxnel*sizeof(*mysids));
 
-       for (i = ebitmap_startbit(&user->roles); i < ebitmap_length(&user->roles); i++) {
-               if (!ebitmap_get_bit(&user->roles, i))
+       ebitmap_for_each_bit(&user->roles, rnode, i) {
+               if (!ebitmap_node_get_bit(rnode, i))
                        continue;
                role = policydb.role_val_to_struct[i];
                usercon.role = i+1;
-               for (j = ebitmap_startbit(&role->types); j < ebitmap_length(&role->types); j++) {
-                       if (!ebitmap_get_bit(&role->types, j))
+               ebitmap_for_each_bit(&role->types, tnode, j) {
+                       if (!ebitmap_node_get_bit(tnode, j))
                                continue;
                        usercon.type = j+1;
 
index 103f136926d9bea7d754d9358a99662787764755..4ef6dd00c6eeafb9916378ad7098b642a309a0cc 100644 (file)
@@ -2,12 +2,14 @@
 # Makefile for ALSA
 #
 
-snd-sa11xx-uda1341-objs := sa11xx-uda1341.o
-snd-aaci-objs                  := aaci.o devdma.o
-snd-pxa2xx-pcm-objs := pxa2xx-pcm.o
-snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
-
 obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-sa11xx-uda1341.o 
+snd-sa11xx-uda1341-objs                := sa11xx-uda1341.o
+
 obj-$(CONFIG_SND_ARMAACI)      += snd-aaci.o
-obj-$(CONFIG_SND_PXA2XX_PCM) += snd-pxa2xx-pcm.o
-obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
+snd-aaci-objs                  := aaci.o devdma.o
+
+obj-$(CONFIG_SND_PXA2XX_PCM)   += snd-pxa2xx-pcm.o
+snd-pxa2xx-pcm-objs            := pxa2xx-pcm.o
+
+obj-$(CONFIG_SND_PXA2XX_AC97)  += snd-pxa2xx-ac97.o
+snd-pxa2xx-ac97-objs           := pxa2xx-ac97.o
index 08cc3ddca96fb385d1a23db07b32ae3a5fe9fc2b..98877030d579fa6f641dee8dca596241940f32e6 100644 (file)
@@ -821,7 +821,7 @@ static int __devinit aaci_init_pcm(struct aaci *aaci)
 
 static unsigned int __devinit aaci_size_fifo(struct aaci *aaci)
 {
-       void *base = aaci->base + AACI_CSCH1;
+       void __iomem *base = aaci->base + AACI_CSCH1;
        int i;
 
        writel(TXCR_FEN | TXCR_TSZ16 | TXCR_TXEN, base + AACI_TXCR);
@@ -877,7 +877,7 @@ static int __devinit aaci_probe(struct amba_device *dev, void *id)
        aaci->playback.fifo = aaci->base + AACI_DR1;
 
        for (i = 0; i < 4; i++) {
-               void *base = aaci->base + i * 0x14;
+               void __iomem *base = aaci->base + i * 0x14;
 
                writel(0, base + AACI_IE);
                writel(0, base + AACI_TXCR);
index d752e64268940efe5dba7d192b4953bc8716a048..b2f969bc7845e66b903c48f07e16c21fbc214629 100644 (file)
 
 
 struct aaci_runtime {
-       void                    *base;
-       void                    *fifo;
+       void                    __iomem *base;
+       void                    __iomem *fifo;
 
        struct ac97_pcm         *pcm;
        int                     pcm_open;
@@ -223,7 +223,7 @@ struct aaci_runtime {
 struct aaci {
        struct amba_device      *dev;
        snd_card_t              *card;
-       void                    *base;
+       void                    __iomem *base;
        unsigned int            fifosize;
 
        /* AC'97 */
index 46052304e2300dd5257716acdb4559150d8d2273..29450befb5da52b59680f7624d766897703d6d3c 100644 (file)
@@ -132,9 +132,9 @@ static void pxa2xx_ac97_reset(ac97_t *ac97)
                udelay(10);
                GCR |= GCR_WARM_RST;
                pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
-               udelay(50);
+               udelay(500);
 #else
-               GCR |= GCR_WARM_RST|GCR_PRIRDY_IEN|GCR_SECRDY_IEN;;
+               GCR |= GCR_WARM_RST|GCR_PRIRDY_IEN|GCR_SECRDY_IEN;
                wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
 #endif                 
 
@@ -261,7 +261,7 @@ static int pxa2xx_ac97_do_suspend(snd_card_t *card, unsigned int state)
        return 0;
 }
 
-static int pxa2xx_ac97_do_resume(snd_card_t *card, unsigned int state)
+static int pxa2xx_ac97_do_resume(snd_card_t *card)
 {
        if (card->power_state != SNDRV_CTL_POWER_D0) {
                pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
@@ -275,13 +275,13 @@ static int pxa2xx_ac97_do_resume(snd_card_t *card, unsigned int state)
        return 0;
 }
 
-static int pxa2xx_ac97_suspend(struct device *_dev, u32 state, u32 level)
+static int pxa2xx_ac97_suspend(struct device *_dev, pm_message_t state, u32 level)
 {
        snd_card_t *card = dev_get_drvdata(_dev);
        int ret = 0;
 
        if (card && level == SUSPEND_DISABLE)
-               ret = pxa2xx_ac97_do_suspend(card, SNDRV_CTL_POWER_D3cold);
+               ret = pxa2xx_ac97_do_suspend(card, PMSG_SUSPEND);
 
        return ret;
 }
@@ -292,7 +292,7 @@ static int pxa2xx_ac97_resume(struct device *_dev, u32 level)
        int ret = 0;
 
        if (card && level == RESUME_ENABLE)
-               ret = pxa2xx_ac97_do_resume(card, SNDRV_CTL_POWER_D0);
+               ret = pxa2xx_ac97_do_resume(card);
 
        return ret;
 }
index 02132561c3f845d326f2bbf34a8870efab3439d5..39a54a415528080a01620e71d7a40efdcbac1e66 100644 (file)
@@ -512,7 +512,7 @@ static void free_all_reserved_pages(void)
  * proc file interface
  */
 #define SND_MEM_PROC_FILE      "driver/snd-page-alloc"
-struct proc_dir_entry *snd_mem_proc;
+static struct proc_dir_entry *snd_mem_proc;
 
 static int snd_mem_proc_read(char *page, char **start, off_t off,
                             int count, int *eof, void *data)
@@ -655,8 +655,7 @@ static int __init snd_mem_init(void)
 
 static void __exit snd_mem_exit(void)
 {
-       if (snd_mem_proc)
-               remove_proc_entry(SND_MEM_PROC_FILE, NULL);
+       remove_proc_entry(SND_MEM_PROC_FILE, NULL);
        free_all_reserved_pages();
        if (snd_allocated_pages > 0)
                printk(KERN_ERR "snd-malloc: Memory leak?  pages not freed = %li\n", snd_allocated_pages);
index f6895577bf864bb9b715508fde30774af1b8d4cc..291b4769bde38f2bf2775958ce94f200e62f9732 100644 (file)
@@ -56,7 +56,7 @@ static DEFINE_SPINLOCK(snd_alloc_vmalloc_lock);
 #define VMALLOC_MAGIC 0x87654320
 static snd_info_entry_t *snd_memory_info_entry;
 
-void snd_memory_init(void)
+void __init snd_memory_init(void)
 {
        snd_alloc_kmalloc = 0;
        snd_alloc_vmalloc = 0;
@@ -116,15 +116,21 @@ void *snd_hidden_kmalloc(size_t size, unsigned int __nocast flags)
        return _snd_kmalloc(size, flags);
 }
 
+void *snd_hidden_kzalloc(size_t size, unsigned int __nocast flags)
+{
+       void *ret = _snd_kmalloc(size, flags);
+       if (ret)
+               memset(ret, 0, size);
+       return ret;
+}
+EXPORT_SYMBOL(snd_hidden_kzalloc);
+
 void *snd_hidden_kcalloc(size_t n, size_t size, unsigned int __nocast flags)
 {
        void *ret = NULL;
        if (n != 0 && size > INT_MAX / n)
                return ret;
-       ret = _snd_kmalloc(n * size, flags);
-       if (ret)
-               memset(ret, 0, n * size);
-       return ret;
+       return snd_hidden_kzalloc(n * size, flags);
 }
 
 void snd_hidden_kfree(const void *obj)
index de7444c586f977e363833320cf7aa27d594c219d..a13bd7bb4c9f08cf6628ce8856f1c56896ba2e9c 100644 (file)
@@ -1705,13 +1705,12 @@ static int snd_pcm_oss_release_file(snd_pcm_oss_file_t *pcm_oss_file)
                if (snd_pcm_running(substream))
                        snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
                snd_pcm_stream_unlock_irq(substream);
-               if (substream->open_flag) {
+               if (substream->ffile != NULL) {
                        if (substream->ops->hw_free != NULL)
                                substream->ops->hw_free(substream);
                        substream->ops->close(substream);
-                       substream->open_flag = 0;
+                       substream->ffile = NULL;
                }
-               substream->ffile = NULL;
                snd_pcm_oss_release_substream(substream);
                snd_pcm_release_substream(substream);
        }
@@ -1778,14 +1777,13 @@ static int snd_pcm_oss_open_file(struct file *file,
                        snd_pcm_oss_release_file(pcm_oss_file);
                        return err;
                }
-               psubstream->open_flag = 1;
+               psubstream->ffile = file;
                err = snd_pcm_hw_constraints_complete(psubstream);
                if (err < 0) {
                        snd_printd("snd_pcm_hw_constraint_complete failed\n");
                        snd_pcm_oss_release_file(pcm_oss_file);
                        return err;
                }
-               psubstream->ffile = file;
                snd_pcm_oss_init_substream(psubstream, psetup, minor);
        }
        if (csubstream != NULL) {
@@ -1800,14 +1798,13 @@ static int snd_pcm_oss_open_file(struct file *file,
                        snd_pcm_oss_release_file(pcm_oss_file);
                        return err;
                }
-               csubstream->open_flag = 1;
+               csubstream->ffile = file;
                err = snd_pcm_hw_constraints_complete(csubstream);
                if (err < 0) {
                        snd_printd("snd_pcm_hw_constraint_complete failed\n");
                        snd_pcm_oss_release_file(pcm_oss_file);
                        return err;
                }
-               csubstream->ffile = file;
                snd_pcm_oss_init_substream(csubstream, csetup, minor);
        }
 
index 3920bf0eebbf20c98c2f31e1093385cb8efc56ff..4b6307df846d4c1f55c0c3b66913992061b6e128 100644 (file)
@@ -103,10 +103,24 @@ struct sndrv_pcm_sw_params32 {
        unsigned char reserved[64];
 };
 
+/* recalcuate the boundary within 32bit */
+static snd_pcm_uframes_t recalculate_boundary(snd_pcm_runtime_t *runtime)
+{
+       snd_pcm_uframes_t boundary;
+
+       if (! runtime->buffer_size)
+               return 0;
+       boundary = runtime->buffer_size;
+       while (boundary * 2 <= 0x7fffffffUL - runtime->buffer_size)
+               boundary *= 2;
+       return boundary;
+}
+
 static int snd_pcm_ioctl_sw_params_compat(snd_pcm_substream_t *substream,
                                          struct sndrv_pcm_sw_params32 __user *src)
 {
        snd_pcm_sw_params_t params;
+       snd_pcm_uframes_t boundary;
        int err;
 
        memset(&params, 0, sizeof(params));
@@ -120,10 +134,17 @@ static int snd_pcm_ioctl_sw_params_compat(snd_pcm_substream_t *substream,
            get_user(params.silence_threshold, &src->silence_threshold) ||
            get_user(params.silence_size, &src->silence_size))
                return -EFAULT;
+       /*
+        * Check silent_size parameter.  Since we have 64bit boundary,
+        * silence_size must be compared with the 32bit boundary.
+        */
+       boundary = recalculate_boundary(substream->runtime);
+       if (boundary && params.silence_size >= boundary)
+               params.silence_size = substream->runtime->boundary;
        err = snd_pcm_sw_params(substream, &params);
        if (err < 0)
                return err;
-       if (put_user(params.boundary, &src->boundary))
+       if (boundary && put_user(boundary, &src->boundary))
                return -EFAULT;
        return err;
 }
@@ -199,16 +220,6 @@ static int snd_pcm_status_user_compat(snd_pcm_substream_t *substream,
        return err;
 }
 
-/* recalcuate the boundary within 32bit */
-static void recalculate_boundary(snd_pcm_runtime_t *runtime)
-{
-       if (! runtime->buffer_size)
-               return;
-       runtime->boundary = runtime->buffer_size;
-       while (runtime->boundary * 2 <= 0x7fffffffUL - runtime->buffer_size)
-               runtime->boundary *= 2;
-}
-
 /* both for HW_PARAMS and HW_REFINE */
 static int snd_pcm_ioctl_hw_params_compat(snd_pcm_substream_t *substream,
                                          int refine, 
@@ -241,8 +252,11 @@ static int snd_pcm_ioctl_hw_params_compat(snd_pcm_substream_t *substream,
                goto error;
        }
 
-       if (! refine)
-               recalculate_boundary(runtime);
+       if (! refine) {
+               unsigned int new_boundary = recalculate_boundary(runtime);
+               if (new_boundary)
+                       runtime->boundary = new_boundary;
+       }
  error:
        kfree(data);
        return err;
@@ -380,6 +394,7 @@ static int snd_pcm_ioctl_sync_ptr_compat(snd_pcm_substream_t *substream,
        u32 sflags;
        struct sndrv_pcm_mmap_control scontrol;
        struct sndrv_pcm_mmap_status sstatus;
+       snd_pcm_uframes_t boundary;
        int err;
 
        snd_assert(runtime, return -EINVAL);
@@ -395,17 +410,21 @@ static int snd_pcm_ioctl_sync_ptr_compat(snd_pcm_substream_t *substream,
        }
        status = runtime->status;
        control = runtime->control;
+       boundary = recalculate_boundary(runtime);
+       if (! boundary)
+               boundary = 0x7fffffff;
        snd_pcm_stream_lock_irq(substream);
+       /* FIXME: we should consider the boundary for the sync from app */
        if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
                control->appl_ptr = scontrol.appl_ptr;
        else
-               scontrol.appl_ptr = control->appl_ptr;
+               scontrol.appl_ptr = control->appl_ptr % boundary;
        if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
                control->avail_min = scontrol.avail_min;
        else
                scontrol.avail_min = control->avail_min;
        sstatus.state = status->state;
-       sstatus.hw_ptr = status->hw_ptr;
+       sstatus.hw_ptr = status->hw_ptr % boundary;
        sstatus.tstamp = status->tstamp;
        sstatus.suspended_state = status->suspended_state;
        snd_pcm_stream_unlock_irq(substream);
index c5bfd0918cff9eba195d733355435580f27f8882..0082914a7e3331825b7a302dfe9dfe4035694971 100644 (file)
@@ -1584,8 +1584,8 @@ int snd_pcm_hw_param_set(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
        return snd_pcm_hw_param_value(params, var, NULL);
 }
 
-int _snd_pcm_hw_param_mask(snd_pcm_hw_params_t *params,
-                          snd_pcm_hw_param_t var, const snd_mask_t *val)
+static int _snd_pcm_hw_param_mask(snd_pcm_hw_params_t *params,
+                                 snd_pcm_hw_param_t var, const snd_mask_t *val)
 {
        int changed;
        assert(hw_is_mask(var));
@@ -2063,7 +2063,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
                if (((avail < runtime->control->avail_min && size > avail) ||
                   (size >= runtime->xfer_align && avail < runtime->xfer_align))) {
                        wait_queue_t wait;
-                       enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED } state;
+                       enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state;
                        long tout;
 
                        if (nonblock) {
@@ -2097,6 +2097,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
                                case SNDRV_PCM_STATE_SUSPENDED:
                                        state = SUSPENDED;
                                        goto _end_loop;
+                               case SNDRV_PCM_STATE_SETUP:
+                                       state = DROPPED;
+                                       goto _end_loop;
                                default:
                                        break;
                                }
@@ -2123,6 +2126,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
                                snd_printd("playback write error (DMA or IRQ trouble?)\n");
                                err = -EIO;
                                goto _end_unlock;
+                       case DROPPED:
+                               err = -EBADFD;
+                               goto _end_unlock;
                        default:
                                break;
                        }
@@ -2359,7 +2365,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream,
                } else if ((avail < runtime->control->avail_min && size > avail) ||
                           (size >= runtime->xfer_align && avail < runtime->xfer_align)) {
                        wait_queue_t wait;
-                       enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED } state;
+                       enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state;
                        long tout;
 
                        if (nonblock) {
@@ -2394,6 +2400,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream,
                                        goto _end_loop;
                                case SNDRV_PCM_STATE_DRAINING:
                                        goto __draining;
+                               case SNDRV_PCM_STATE_SETUP:
+                                       state = DROPPED;
+                                       goto _end_loop;
                                default:
                                        break;
                                }
@@ -2420,6 +2429,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream,
                                snd_printd("capture read error (DMA or IRQ trouble?)\n");
                                err = -EIO;
                                goto _end_unlock;
+                       case DROPPED:
+                               err = -EBADFD;
+                               goto _end_unlock;
                        default:
                                break;
                        }
index 10c2c98326497e6f0cb5fc0c453c1701daf5f8c4..03c17159dd8e0fe48f9625af9dfd979038a5adff 100644 (file)
@@ -1025,7 +1025,7 @@ static void snd_pcm_post_suspend(snd_pcm_substream_t *substream, int state)
        snd_pcm_runtime_t *runtime = substream->runtime;
        snd_pcm_trigger_tstamp(substream);
        if (substream->timer)
-               snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MPAUSE, &runtime->trigger_tstamp);
+               snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSUSPEND, &runtime->trigger_tstamp);
        runtime->status->suspended_state = runtime->status->state;
        runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
        snd_pcm_tick_set(substream, 0);
@@ -1115,7 +1115,7 @@ static void snd_pcm_post_resume(snd_pcm_substream_t *substream, int state)
        snd_pcm_runtime_t *runtime = substream->runtime;
        snd_pcm_trigger_tstamp(substream);
        if (substream->timer)
-               snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MCONTINUE, &runtime->trigger_tstamp);
+               snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME, &runtime->trigger_tstamp);
        runtime->status->state = runtime->status->suspended_state;
        if (runtime->sleep_min)
                snd_pcm_tick_prepare(substream);
@@ -1967,13 +1967,12 @@ static int snd_pcm_release_file(snd_pcm_file_t * pcm_file)
        runtime = substream->runtime;
        str = substream->pstr;
        snd_pcm_unlink(substream);
-       if (substream->open_flag) {
+       if (substream->ffile != NULL) {
                if (substream->ops->hw_free != NULL)
                        substream->ops->hw_free(substream);
                substream->ops->close(substream);
-               substream->open_flag = 0;
+               substream->ffile = NULL;
        }
-       substream->ffile = NULL;
        snd_pcm_remove_file(str, pcm_file);
        snd_pcm_release_substream(substream);
        kfree(pcm_file);
@@ -2022,18 +2021,15 @@ static int snd_pcm_open_file(struct file *file,
                snd_pcm_release_file(pcm_file);
                return err;
        }
-       substream->open_flag = 1;
+       substream->ffile = file;
 
        err = snd_pcm_hw_constraints_complete(substream);
        if (err < 0) {
                snd_printd("snd_pcm_hw_constraints_complete failed\n");
-               substream->ops->close(substream);
                snd_pcm_release_file(pcm_file);
                return err;
        }
 
-       substream->ffile = file;
-
        file->private_data = pcm_file;
        *rpcm_file = pcm_file;
        return 0;
index de39d212bc15189bbb1236f9519993b608ed8d15..e401c6703297c377196d9d1d12c2227b657eaae9 100644 (file)
@@ -98,6 +98,7 @@ int snd_register_oss_device(int type, snd_card_t * card, int dev, snd_minor_t *
        int cidx = SNDRV_MINOR_OSS_CARD(minor);
        int track2 = -1;
        int register1 = -1, register2 = -1;
+       struct device *carddev = NULL;
 
        if (minor < 0)
                return minor;
@@ -121,11 +122,13 @@ int snd_register_oss_device(int type, snd_card_t * card, int dev, snd_minor_t *
                track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI1);
                break;
        }
-       register1 = register_sound_special(reg->f_ops, minor);
+       if (card)
+               carddev = card->dev;
+       register1 = register_sound_special_device(reg->f_ops, minor, carddev);
        if (register1 != minor)
                goto __end;
        if (track2 >= 0) {
-               register2 = register_sound_special(reg->f_ops, track2);
+               register2 = register_sound_special_device(reg->f_ops, track2, carddev);
                if (register2 != track2)
                        goto __end;
        }
index cfaccd415b3b918cedc9cbdc6a9d4c89dd0a0861..4104f6e292e959ead04756ccd52d18ee52e49326 100644 (file)
@@ -799,13 +799,13 @@ static int snd_timer_free(snd_timer_t *timer)
        return 0;
 }
 
-int snd_timer_dev_free(snd_device_t *device)
+static int snd_timer_dev_free(snd_device_t *device)
 {
        snd_timer_t *timer = device->device_data;
        return snd_timer_free(timer);
 }
 
-int snd_timer_dev_register(snd_device_t *dev)
+static int snd_timer_dev_register(snd_device_t *dev)
 {
        snd_timer_t *timer = dev->device_data;
        snd_timer_t *timer1;
@@ -880,9 +880,11 @@ void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, struct t
        struct list_head *p, *n;
 
        snd_runtime_check(timer->hw.flags & SNDRV_TIMER_HW_SLAVE, return);      
-       snd_assert(event >= SNDRV_TIMER_EVENT_MSTART && event <= SNDRV_TIMER_EVENT_MPAUSE, return);
+       snd_assert(event >= SNDRV_TIMER_EVENT_MSTART && event <= SNDRV_TIMER_EVENT_MRESUME, return);
        spin_lock_irqsave(&timer->lock, flags);
-       if (event == SNDRV_TIMER_EVENT_MSTART || event == SNDRV_TIMER_EVENT_MCONTINUE) {
+       if (event == SNDRV_TIMER_EVENT_MSTART ||
+           event == SNDRV_TIMER_EVENT_MCONTINUE ||
+           event == SNDRV_TIMER_EVENT_MRESUME) {
                if (timer->hw.c_resolution)
                        resolution = timer->hw.c_resolution(timer);
                else
@@ -1555,10 +1557,14 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_
                              (1<<SNDRV_TIMER_EVENT_STOP)|
                              (1<<SNDRV_TIMER_EVENT_CONTINUE)|
                              (1<<SNDRV_TIMER_EVENT_PAUSE)|
+                             (1<<SNDRV_TIMER_EVENT_SUSPEND)|
+                             (1<<SNDRV_TIMER_EVENT_RESUME)|
                              (1<<SNDRV_TIMER_EVENT_MSTART)|
                              (1<<SNDRV_TIMER_EVENT_MSTOP)|
                              (1<<SNDRV_TIMER_EVENT_MCONTINUE)|
-                             (1<<SNDRV_TIMER_EVENT_MPAUSE))) {
+                             (1<<SNDRV_TIMER_EVENT_MPAUSE)|
+                             (1<<SNDRV_TIMER_EVENT_MSUSPEND)|
+                             (1<<SNDRV_TIMER_EVENT_MRESUME))) {
                err = -EINVAL;
                goto _end;
        }
index f00c88886460c8b8dff9a3a5dc8e05c8549cd28d..19fc68c23378c039b4bc856b54997372bf0915c1 100644 (file)
@@ -796,14 +796,14 @@ static int vx_iec958_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontro
 
 static snd_kcontrol_new_t vx_control_iec958_mask = {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
        .info =         vx_iec958_info, /* shared */
        .get =          vx_iec958_mask_get,
 };
 
 static snd_kcontrol_new_t vx_control_iec958 = {
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
        .info =         vx_iec958_info,
        .get =          vx_iec958_get,
index af381b15fe5c4a813eb413ae04b0994b8ae67f38..d4becf44e24787ddc9743bb943da30f41c0e02ff 100644 (file)
@@ -549,8 +549,8 @@ static int vx_stop_stream(vx_core_t *chip, vx_pipe_t *pipe)
 
 static snd_pcm_hardware_t vx_pcm_playback_hw = {
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID |
-                                SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID /*|*/
+                                /*SNDRV_PCM_INFO_RESUME*/),
        .formats =              /*SNDRV_PCM_FMTBIT_U8 |*/ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
        .rates =                SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
        .rate_min =             5000,
@@ -949,8 +949,8 @@ static snd_pcm_ops_t vx_pcm_playback_ops = {
 
 static snd_pcm_hardware_t vx_pcm_capture_hw = {
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID |
-                                SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID /*|*/
+                                /*SNDRV_PCM_INFO_RESUME*/),
        .formats =              /*SNDRV_PCM_FMTBIT_U8 |*/ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
        .rates =                SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
        .rate_min =             5000,
index be4ea60a367924b0808651f5a542aa0021940804..5c3948311528efdca7817e63e8e3fea96c8b8460 100644 (file)
@@ -15,7 +15,8 @@ config SND_CS4231_LIB
 
 config SND_AD1816A
        tristate "Analog Devices SoundPort AD1816A"
-       depends on SND && ISAPNP
+       depends on SND && PNP && ISA
+       select ISAPNP
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_PCM
@@ -80,7 +81,8 @@ config SND_CS4236
 
 config SND_ES968
        tristate "Generic ESS ES968 driver"
-       depends on SND && ISAPNP
+       depends on SND && PNP && ISA
+       select ISAPNP
        select SND_MPU401_UART
        select SND_PCM
        help
@@ -160,7 +162,7 @@ config SND_GUSMAX
 
 config SND_INTERWAVE
        tristate "AMD InterWave, Gravis UltraSound PnP"
-       depends on SND
+       depends on SND && PNP && ISA
        select SND_RAWMIDI
        select SND_CS4231_LIB
        select SND_GUS_SYNTH
@@ -175,7 +177,7 @@ config SND_INTERWAVE
 
 config SND_INTERWAVE_STB
        tristate "AMD InterWave + TEA6330T (UltraSound 32-Pro)"
-       depends on SND
+       depends on SND && PNP && ISA
        select SND_RAWMIDI
        select SND_CS4231_LIB
        select SND_GUS_SYNTH
@@ -291,7 +293,8 @@ config SND_WAVEFRONT
 
 config SND_ALS100
        tristate "Avance Logic ALS100/ALS120"
-       depends on SND && ISAPNP
+       depends on SND && PNP && ISA
+       select ISAPNP
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_PCM
@@ -304,7 +307,8 @@ config SND_ALS100
 
 config SND_AZT2320
        tristate "Aztech Systems AZT2320"
-       depends on SND && ISAPNP
+       depends on SND && PNP && ISA
+       select ISAPNP
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_CS4231_LIB
@@ -328,7 +332,8 @@ config SND_CMI8330
 
 config SND_DT019X
        tristate "Diamond Technologies DT-019X, Avance Logic ALS-007"
-       depends on SND && ISAPNP
+       depends on SND && PNP && ISA
+       select ISAPNP
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_PCM
index 563296d028941b53e211956fff89b54459640dce..0eb442ca23d6471e7abf63a730e1548c84dabfa9 100644 (file)
@@ -53,6 +53,7 @@ static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;      /* Pnp setup */
 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;   /* Pnp setup */
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;      /* PnP setup */
 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;      /* PnP setup */
+static int clockfreq[SNDRV_CARDS];
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for ad1816a based soundcard.");
@@ -74,6 +75,8 @@ module_param_array(dma1, int, NULL, 0444);
 MODULE_PARM_DESC(dma1, "1st DMA # for ad1816a driver.");
 module_param_array(dma2, int, NULL, 0444);
 MODULE_PARM_DESC(dma2, "2nd DMA # for ad1816a driver.");
+module_param_array(clockfreq, int, NULL, 0444);
+MODULE_PARM_DESC(clockfreq, "Clock frequency for ad1816a driver (default = 0).");
 
 struct snd_card_ad1816a {
        struct pnp_dev *dev;
@@ -209,6 +212,8 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
                snd_card_free(card);
                return error;
        }
+       if (clockfreq[dev] >= 5000 && clockfreq[dev] <= 100000)
+               chip->clock_freq = clockfreq[dev];
 
        strcpy(card->driver, "AD1816A");
        strcpy(card->shortname, "ADI SoundPort AD1816A");
index 625b2eff14a14d03f39c17902a448b974b3b8f13..ae860360ecf963a3620357e505b2d6025eb57800 100644 (file)
@@ -234,7 +234,7 @@ static int snd_ad1816a_playback_prepare(snd_pcm_substream_t *substream)
        ad1816a_t *chip = snd_pcm_substream_chip(substream);
        unsigned long flags;
        snd_pcm_runtime_t *runtime = substream->runtime;
-       unsigned int size;
+       unsigned int size, rate;
 
        spin_lock_irqsave(&chip->lock, flags);
 
@@ -245,7 +245,10 @@ static int snd_ad1816a_playback_prepare(snd_pcm_substream_t *substream)
        snd_dma_program(chip->dma1, runtime->dma_addr, size,
                        DMA_MODE_WRITE | DMA_AUTOINIT);
 
-       snd_ad1816a_write(chip, AD1816A_PLAYBACK_SAMPLE_RATE, runtime->rate);
+       rate = runtime->rate;
+       if (chip->clock_freq)
+               rate = (rate * 33000) / chip->clock_freq;
+       snd_ad1816a_write(chip, AD1816A_PLAYBACK_SAMPLE_RATE, rate);
        snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
                AD1816A_FMT_ALL | AD1816A_FMT_STEREO,
                snd_ad1816a_get_format(chip, runtime->format,
@@ -263,7 +266,7 @@ static int snd_ad1816a_capture_prepare(snd_pcm_substream_t *substream)
        ad1816a_t *chip = snd_pcm_substream_chip(substream);
        unsigned long flags;
        snd_pcm_runtime_t *runtime = substream->runtime;
-       unsigned int size;
+       unsigned int size, rate;
 
        spin_lock_irqsave(&chip->lock, flags);
 
@@ -274,7 +277,10 @@ static int snd_ad1816a_capture_prepare(snd_pcm_substream_t *substream)
        snd_dma_program(chip->dma2, runtime->dma_addr, size,
                        DMA_MODE_READ | DMA_AUTOINIT);
 
-       snd_ad1816a_write(chip, AD1816A_CAPTURE_SAMPLE_RATE, runtime->rate);
+       rate = runtime->rate;
+       if (chip->clock_freq)
+               rate = (rate * 33000) / chip->clock_freq;
+       snd_ad1816a_write(chip, AD1816A_CAPTURE_SAMPLE_RATE, rate);
        snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG,
                AD1816A_FMT_ALL | AD1816A_FMT_STEREO,
                snd_ad1816a_get_format(chip, runtime->format,
index 8fb3db103e485e698420dd18b587ca497a0a0907..bc642dc94547b5cea97570988571a9a506070cb2 100644 (file)
@@ -1196,6 +1196,7 @@ int snd_ad1848_add_ctl(ad1848_t *chip, const char *name, int index, int type, un
                        .put = snd_ad1848_put_double,
                },
                [AD1848_MIX_CAPTURE] = {
+                       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                        .info = snd_ad1848_info_mux,
                        .get = snd_ad1848_get_mux,
                        .put = snd_ad1848_put_mux,
index 46776cc0c1578b369ed678905905f3ebe2ad4e69..1fce8b9f37cf88de82991392a12ced9aa363443e 100644 (file)
@@ -194,8 +194,8 @@ AD1848_DOUBLE("Wavetable Capture Volume", 0, CMI8330_WAVGAIN, CMI8330_WAVGAIN, 4
 AD1848_SINGLE("3D Control - Switch", 0, CMI8330_RMUX3D, 5, 1, 1),
 AD1848_SINGLE("PC Speaker Playback Volume", 0, CMI8330_OUTPUTVOL, 3, 3, 0),
 AD1848_SINGLE("FM Playback Switch", 0, CMI8330_RECMUX, 3, 1, 1),
-AD1848_SINGLE("IEC958 Input Capture Switch", 0, CMI8330_RMUX3D, 7, 1, 1),
-AD1848_SINGLE("IEC958 Input Playback Switch", 0, CMI8330_MUTEMUX, 7, 1, 1),
+AD1848_SINGLE(SNDRV_CTL_NAME_IEC958("Input ",CAPTURE,SWITCH), 0, CMI8330_RMUX3D, 7, 1, 1),
+AD1848_SINGLE(SNDRV_CTL_NAME_IEC958("Input ",PLAYBACK,SWITCH), 0, CMI8330_MUTEMUX, 7, 1, 1),
 };
 
 #ifdef ENABLE_SB_MIXER
index 3e7a2a33a5cad3a2dbf8f05f8add115a868634aa..3199941edd9bafd67de441b6bbde50f18f343338 100644 (file)
@@ -1346,6 +1346,8 @@ static void snd_cs4231_suspend(cs4231_t *chip)
        int reg;
        unsigned long flags;
        
+       if (chip->pcm)
+               snd_pcm_suspend_all(chip->pcm);
        spin_lock_irqsave(&chip->reg_lock, flags);
        for (reg = 0; reg < 32; reg++)
                chip->image[reg] = snd_cs4231_in(chip, reg);
index 337b0e2a8a36905a6b996587043699caf0c6c9ac..23e1b5f19e1ab78f24ba8ff48614ba15876f0f25 100644 (file)
@@ -269,8 +269,9 @@ void snd_gf1_i_write_addr(snd_gus_card_t * gus, unsigned char reg,
 
 #endif  /*  0  */
 
-unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus,
-                                unsigned char reg, short w_16bit)
+#ifdef CONFIG_SND_DEBUG
+static unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus,
+                                       unsigned char reg, short w_16bit)
 {
        unsigned int res;
        unsigned long flags;
@@ -280,6 +281,7 @@ unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus,
        spin_unlock_irqrestore(&gus->reg_lock, flags);
        return res;
 }
+#endif
 
 /*
 
index 95c7b3e53407fecbeadf461bf4ad9f9729e68487..75bd6eca63e741ed8545f86543a97884a8130eb7 100644 (file)
@@ -145,6 +145,14 @@ static snd_card_t *snd_opl3sa2_legacy[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
 
 #ifdef CONFIG_PNP
 
+static struct pnp_device_id snd_opl3sa2_pnpbiosids[] = {
+       { .id = "YMH0021" },
+       { .id = "NMX2210" },    /* Gateway Solo 2500 */
+       { .id = "" }            /* end */
+};
+
+MODULE_DEVICE_TABLE(pnp, snd_opl3sa2_pnpbiosids);
+
 static struct pnp_card_device_id snd_opl3sa2_pnpids[] = {
        /* Yamaha YMF719E-S (Genius Sound Maker 3DX) */
        { .id = "YMH0020", .devs = { { "YMH0021" } } },
@@ -568,20 +576,18 @@ static int snd_opl3sa2_resume(snd_card_t *card)
 
 #ifdef CONFIG_PNP
 static int __init snd_opl3sa2_pnp(int dev, opl3sa2_t *chip,
-                                 struct pnp_card_link *card,
-                                 const struct pnp_card_device_id *id)
+                                 struct pnp_dev *pdev,
+                                 int isapnp)
 {
-       struct pnp_dev *pdev;
-       struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
+       struct pnp_resource_table * cfg;
        int err;
 
+       if (!isapnp && pnp_device_is_isapnp(pdev))
+               return -ENOENT; /* we have another procedure - card */
+
+       cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
        if (!cfg)
                return -ENOMEM;
-       pdev = chip->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
-       if (chip->dev == NULL) {
-               kfree(cfg);
-               return -EBUSY;
-       }
        /* PnP initialization */
        pnp_init_resource_table(cfg);
        if (sb_port[dev] != SNDRV_AUTO_PORT)
@@ -601,7 +607,7 @@ static int __init snd_opl3sa2_pnp(int dev, opl3sa2_t *chip,
        if (irq[dev] != SNDRV_AUTO_IRQ)
                pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
        err = pnp_manual_config_dev(pdev, cfg, 0);
-       if (err < 0)
+       if (err < 0 && isapnp)
                snd_printk(KERN_ERR "PnP manual resources are invalid, using auto config\n");
        err = pnp_activate_dev(pdev);
        if (err < 0) {
@@ -617,13 +623,31 @@ static int __init snd_opl3sa2_pnp(int dev, opl3sa2_t *chip,
        dma1[dev] = pnp_dma(pdev, 0);
        dma2[dev] = pnp_dma(pdev, 1);
        irq[dev] = pnp_irq(pdev, 0);
-       snd_printdd("PnP OPL3-SA: sb port=0x%lx, wss port=0x%lx, fm port=0x%lx, midi port=0x%lx\n",
-               sb_port[dev], wss_port[dev], fm_port[dev], midi_port[dev]);
-       snd_printdd("PnP OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n",
-               port[dev], dma1[dev], dma2[dev], irq[dev]);
+       snd_printdd("%sPnP OPL3-SA: sb port=0x%lx, wss port=0x%lx, fm port=0x%lx, midi port=0x%lx\n",
+               pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", sb_port[dev], wss_port[dev], fm_port[dev], midi_port[dev]);
+       snd_printdd("%sPnP OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n",
+               pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", port[dev], dma1[dev], dma2[dev], irq[dev]);
        kfree(cfg);
+       chip->dev = pdev;
        return 0;
 }
+
+static int __init snd_opl3sa2_cpnp(int dev, opl3sa2_t *chip,
+                                  struct pnp_card_link *card,
+                                  const struct pnp_card_device_id *id)
+{
+       struct pnp_dev *pdev;
+       struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
+
+       if (!cfg)
+               return -ENOMEM;
+       pdev = pnp_request_card_device(card, id->devs[0].id, NULL);
+       if (pdev == NULL) {
+               kfree(cfg);
+               return -EBUSY;
+       }
+       return snd_opl3sa2_pnp(dev, chip, pdev, 1);
+}
 #endif /* CONFIG_PNP */
 
 static int snd_opl3sa2_free(opl3sa2_t *chip)
@@ -645,6 +669,7 @@ static int snd_opl3sa2_dev_free(snd_device_t *device)
 }
 
 static int __devinit snd_opl3sa2_probe(int dev,
+                                      struct pnp_dev *pdev,
                                       struct pnp_card_link *pcard,
                                       const struct pnp_card_device_id *pid)
 {
@@ -695,8 +720,13 @@ static int __devinit snd_opl3sa2_probe(int dev,
        if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0)
                goto __error;
 #ifdef CONFIG_PNP
-       if (isapnp[dev]) {
-               if ((err = snd_opl3sa2_pnp(dev, chip, pcard, pid)) < 0)
+       if (pdev) {
+               if ((err = snd_opl3sa2_pnp(dev, chip, pdev, 0)) < 0)
+                       goto __error;
+               snd_card_set_dev(card, &pdev->dev);
+       }
+       if (pcard) {
+               if ((err = snd_opl3sa2_cpnp(dev, chip, pcard, pid)) < 0)
                        goto __error;
                snd_card_set_dev(card, &pcard->card->dev);
        }
@@ -768,7 +798,9 @@ static int __devinit snd_opl3sa2_probe(int dev,
        if ((err = snd_card_register(card)) < 0)
                goto __error;
 
-       if (pcard)
+       if (pdev)
+               pnp_set_drvdata(pdev, card);
+       else if (pcard)
                pnp_set_card_drvdata(pcard, card);
        else
                snd_opl3sa2_legacy[dev] = card;
@@ -780,8 +812,8 @@ static int __devinit snd_opl3sa2_probe(int dev,
 }
 
 #ifdef CONFIG_PNP
-static int __devinit snd_opl3sa2_pnp_detect(struct pnp_card_link *card,
-                                           const struct pnp_card_device_id *id)
+static int __devinit snd_opl3sa2_pnp_detect(struct pnp_dev *pdev,
+                                           const struct pnp_device_id *id)
 {
         static int dev;
         int res;
@@ -789,7 +821,7 @@ static int __devinit snd_opl3sa2_pnp_detect(struct pnp_card_link *card,
         for ( ; dev < SNDRV_CARDS; dev++) {
                 if (!enable[dev] || !isapnp[dev])
                         continue;
-                res = snd_opl3sa2_probe(dev, card, id);
+                res = snd_opl3sa2_probe(dev, pdev, NULL, NULL);
                 if (res < 0)
                         return res;
                 dev++;
@@ -798,7 +830,40 @@ static int __devinit snd_opl3sa2_pnp_detect(struct pnp_card_link *card,
         return -ENODEV;
 }
 
-static void __devexit snd_opl3sa2_pnp_remove(struct pnp_card_link * pcard)
+static void __devexit snd_opl3sa2_pnp_remove(struct pnp_dev * pdev)
+{
+       snd_card_t *card = (snd_card_t *) pnp_get_drvdata(pdev);
+        
+       snd_card_disconnect(card);
+       snd_card_free_in_thread(card);
+}
+
+static struct pnp_driver opl3sa2_pnp_driver = {
+       .name = "opl3sa2-pnpbios",
+       .id_table = snd_opl3sa2_pnpbiosids,
+       .probe = snd_opl3sa2_pnp_detect,
+       .remove = __devexit_p(snd_opl3sa2_pnp_remove),
+};
+
+static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *card,
+                                            const struct pnp_card_device_id *id)
+{
+        static int dev;
+        int res;
+
+        for ( ; dev < SNDRV_CARDS; dev++) {
+                if (!enable[dev] || !isapnp[dev])
+                        continue;
+                res = snd_opl3sa2_probe(dev, NULL, card, id);
+                if (res < 0)
+                        return res;
+                dev++;
+                return 0;
+        }
+        return -ENODEV;
+}
+
+static void __devexit snd_opl3sa2_pnp_cremove(struct pnp_card_link * pcard)
 {
        snd_card_t *card = (snd_card_t *) pnp_get_card_drvdata(pcard);
         
@@ -810,8 +875,8 @@ static struct pnp_card_driver opl3sa2_pnpc_driver = {
        .flags = PNP_DRIVER_RES_DISABLE,
        .name = "opl3sa2",
        .id_table = snd_opl3sa2_pnpids,
-       .probe = snd_opl3sa2_pnp_detect,
-       .remove = __devexit_p(snd_opl3sa2_pnp_remove),
+       .probe = snd_opl3sa2_pnp_cdetect,
+       .remove = __devexit_p(snd_opl3sa2_pnp_cremove),
 };
 #endif /* CONFIG_PNP */
 
@@ -826,10 +891,11 @@ static int __init alsa_card_opl3sa2_init(void)
                if (isapnp[dev])
                        continue;
 #endif
-               if (snd_opl3sa2_probe(dev, NULL, NULL) >= 0)
+               if (snd_opl3sa2_probe(dev, NULL, NULL, NULL) >= 0)
                        cards++;
        }
 #ifdef CONFIG_PNP
+       cards += pnp_register_driver(&opl3sa2_pnp_driver);
        cards += pnp_register_card_driver(&opl3sa2_pnpc_driver);
 #endif
        if (!cards) {
index a6a0fa51626840fd741a4532535f57a96a3dadb1..a99e642a68b590d9be7a3e53d3dbfaf75a814907 100644 (file)
@@ -729,7 +729,7 @@ static int snd_sb16_dma_control_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_valu
 }
 
 static snd_kcontrol_new_t snd_sb16_dma_control = {
-       .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
        .name = "16-bit DMA Allocation",
        .info = snd_sb16_dma_control_info,
        .get = snd_sb16_dma_control_get,
index d6b96297835ca8b2ab284d4a1920c59848177f15..80dce329cc3a65d8d0a9fcef8793370c415a2687 100644 (file)
@@ -19,9 +19,6 @@
 #include <linux/ioport.h>
 #include <asm/page.h>
 #include <asm/system.h>
-#ifdef __alpha__
-#include <asm/segment.h>
-#endif
 #include <linux/vmalloc.h>
 #include <asm/uaccess.h>
 #include <linux/poll.h>
index 26b42bb20a0a180f0493e670be5ee218a09f4c17..1e458919cce6dfbc97822c95b383baac9eac041f 100644 (file)
@@ -1,11 +1,15 @@
 # ALSA PCI drivers
 
-menu "PCI devices"
-       depends on SND!=n && PCI
-
 config SND_AC97_CODEC
        tristate
        select SND_PCM
+       select SND_AC97_BUS
+
+config SND_AC97_BUS
+       tristate
+
+menu "PCI devices"
+       depends on SND!=n && PCI
 
 config SND_ALI5451
        tristate "ALi M5451 PCI Audio Controller"
index 3c3222122d8b0acda0e1a4389ee8fa452da0409d..77b3482cb1332fe29f92ec9d9c249f5ec1f0d6df 100644 (file)
@@ -10,9 +10,11 @@ snd-ac97-codec-objs += ac97_proc.o
 endif
 
 snd-ak4531-codec-objs := ak4531_codec.o
+snd-ac97-bus-objs := ac97_bus.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_AC97_CODEC) += snd-ac97-codec.o
 obj-$(CONFIG_SND_ENS1370) += snd-ak4531-codec.o
+obj-$(CONFIG_SND_AC97_BUS) += snd-ac97-bus.o
 
 obj-m := $(sort $(obj-m))
diff --git a/sound/pci/ac97/ac97_bus.c b/sound/pci/ac97/ac97_bus.c
new file mode 100644 (file)
index 0000000..227f8b9
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Linux driver model AC97 bus interface
+ *
+ * Author:     Nicolas Pitre
+ * Created:    Jan 14, 2005
+ * Copyright:  (C) 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/string.h>
+
+/*
+ * Codec families have names seperated by commas, so we search for an
+ * individual codec name within the family string. 
+ */
+static int ac97_bus_match(struct device *dev, struct device_driver *drv)
+{
+       return (strstr(dev->bus_id, drv->name) != NULL);
+}
+
+static int ac97_bus_suspend(struct device *dev, pm_message_t state)
+{
+       int ret = 0;
+
+       if (dev->driver && dev->driver->suspend) {
+               ret = dev->driver->suspend(dev, state, SUSPEND_DISABLE);
+               if (ret == 0)
+                       ret = dev->driver->suspend(dev, state, SUSPEND_SAVE_STATE);
+               if (ret == 0)
+                       ret = dev->driver->suspend(dev, state, SUSPEND_POWER_DOWN);
+       }
+       return ret;
+}
+
+static int ac97_bus_resume(struct device *dev)
+{
+       int ret = 0;
+
+       if (dev->driver && dev->driver->resume) {
+               ret = dev->driver->resume(dev, RESUME_POWER_ON);
+               if (ret == 0)
+                       ret = dev->driver->resume(dev, RESUME_RESTORE_STATE);
+               if (ret == 0)
+                       ret = dev->driver->resume(dev, RESUME_ENABLE);
+       }
+       return ret;
+}
+
+struct bus_type ac97_bus_type = {
+       .name           = "ac97",
+       .match          = ac97_bus_match,
+       .suspend        = ac97_bus_suspend,
+       .resume         = ac97_bus_resume,
+};
+
+static int __init ac97_bus_init(void)
+{
+       return bus_register(&ac97_bus_type);
+}
+
+subsys_initcall(ac97_bus_init);
+
+static void __exit ac97_bus_exit(void)
+{
+       bus_unregister(&ac97_bus_type);
+}
+
+module_exit(ac97_bus_exit);
+
+EXPORT_SYMBOL(ac97_bus_type);
+
+MODULE_LICENSE("GPL");
index 6983eea226da2fa227a8f3b0df205bb68ba6d861..5501f4440c9223439f476788ecfe6211052d948b 100644 (file)
@@ -157,6 +157,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
 { 0x54524123, 0xffffffff, "TR28602",           NULL,           NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
 { 0x54584e20, 0xffffffff, "TLC320AD9xC",       NULL,           NULL },
 { 0x56494161, 0xffffffff, "VIA1612A",          NULL,           NULL }, // modified ICE1232 with S/PDIF
+{ 0x56494170, 0xffffffff, "VIA1617A",          patch_vt1617a,  NULL }, // modified VT1616 with S/PDIF
 { 0x57454301, 0xffffffff, "W83971D",           NULL,           NULL },
 { 0x574d4c00, 0xffffffff, "WM9701A",           NULL,           NULL },
 { 0x574d4C03, 0xffffffff, "WM9703,WM9707,WM9708,WM9717", patch_wolfson03, NULL},
@@ -1307,16 +1308,18 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
        }
        
        /* build master tone controls */
-       if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_TONE)) {
-               for (idx = 0; idx < 2; idx++) {
-                       if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0)
-                               return err;
-                       if (ac97->id == AC97_ID_YMF753) {
-                               kctl->private_value &= ~(0xff << 16);
-                               kctl->private_value |= 7 << 16;
+       if (!(ac97->flags & AC97_HAS_NO_TONE)) {
+               if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_TONE)) {
+                       for (idx = 0; idx < 2; idx++) {
+                               if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0)
+                                       return err;
+                               if (ac97->id == AC97_ID_YMF753) {
+                                       kctl->private_value &= ~(0xff << 16);
+                                       kctl->private_value |= 7 << 16;
+                               }
                        }
+                       snd_ac97_write_cache(ac97, AC97_MASTER_TONE, 0x0f0f);
                }
-               snd_ac97_write_cache(ac97, AC97_MASTER_TONE, 0x0f0f);
        }
        
        /* build PC Speaker controls */
@@ -1339,11 +1342,13 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
        }
        
        /* build MIC controls */
-       if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
-               if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0)
-                       return err;
-               if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
-                       return err;
+       if (!(ac97->flags & AC97_HAS_NO_MIC)) {
+               if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
+                       if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0)
+                               return err;
+                       if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
+                               return err;
+               }
        }
 
        /* build Line controls */
@@ -1402,12 +1407,14 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
                }
                snd_ac97_write_cache(ac97, AC97_PCM, init_val);
        } else {
-               if (ac97->flags & AC97_HAS_NO_PCM_VOL)
-                       err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97);
-               else
-                       err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97);
-               if (err < 0)
-                       return err;
+               if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) {
+                       if (ac97->flags & AC97_HAS_NO_PCM_VOL)
+                               err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97);
+                       else
+                               err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97);
+                       if (err < 0)
+                               return err;
+               }
        }
 
        /* build Capture controls */
@@ -1807,6 +1814,39 @@ int snd_ac97_bus(snd_card_t *card, int num, ac97_bus_ops_t *ops,
        return 0;
 }
 
+/* stop no dev release warning */
+static void ac97_device_release(struct device * dev)
+{
+}
+
+/* register ac97 codec to bus */
+static int snd_ac97_dev_register(snd_device_t *device)
+{
+       ac97_t *ac97 = device->device_data;
+       int err;
+
+       ac97->dev.bus = &ac97_bus_type;
+       ac97->dev.parent = ac97->bus->card->dev;
+       ac97->dev.platform_data = ac97;
+       ac97->dev.release = ac97_device_release;
+       snprintf(ac97->dev.bus_id, BUS_ID_SIZE, "card%d-%d", ac97->bus->card->number, ac97->num);
+       if ((err = device_register(&ac97->dev)) < 0) {
+               snd_printk(KERN_ERR "Can't register ac97 bus\n");
+               ac97->dev.bus = NULL;
+               return err;
+       }
+       return 0;
+}
+
+/* unregister ac97 codec */
+static int snd_ac97_dev_unregister(snd_device_t *device)
+{
+       ac97_t *ac97 = device->device_data;
+       if (ac97->dev.bus)
+               device_unregister(&ac97->dev);
+       return snd_ac97_free(ac97);
+}
+
 /* build_ops to do nothing */
 static struct snd_ac97_build_ops null_build_ops;
 
@@ -1840,6 +1880,8 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97)
        const ac97_codec_id_t *pid;
        static snd_device_ops_t ops = {
                .dev_free =     snd_ac97_dev_free,
+               .dev_register = snd_ac97_dev_register,
+               .dev_unregister =       snd_ac97_dev_unregister,
        };
 
        snd_assert(rac97 != NULL, return -EINVAL);
@@ -2539,8 +2581,6 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *o
 {
        int result;
 
-       snd_assert(quirk, return -EINVAL);
-
        /* quirk overriden? */
        if (override && strcmp(override, "-1") && strcmp(override, "default")) {
                result = apply_quirk_str(ac97, override);
@@ -2549,6 +2589,9 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *o
                return result;
        }
 
+       if (! quirk)
+               return -EINVAL;
+
        for (; quirk->subvendor; quirk++) {
                if (quirk->subvendor != ac97->subsystem_vendor)
                        continue;
index 66edc857d3e632cb133bb65d72bcdf09eab49912..b584172c1104d55c470a9f810ee0eb9e14f79f49 100644 (file)
@@ -370,141 +370,387 @@ int patch_yamaha_ymf753(ac97_t * ac97)
  *  added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717.
  */
 
-int patch_wolfson03(ac97_t * ac97)
+static const snd_kcontrol_new_t wm97xx_snd_ac97_controls[] = {
+AC97_DOUBLE("Front Playback Volume", AC97_WM97XX_FMIXER_VOL, 8, 0, 31, 1),
+AC97_SINGLE("Front Playback Switch", AC97_WM97XX_FMIXER_VOL, 15, 1, 1),
+};
+
+static int patch_wolfson_wm9703_specific(ac97_t * ac97)
 {
        /* This is known to work for the ViewSonic ViewPad 1000
-          Randolph Bentson <bentson@holmsjoen.com> */
+        * Randolph Bentson <bentson@holmsjoen.com>
+        * WM9703/9707/9708/9717 
+        */
+       int err, i;
+       
+       for (i = 0; i < ARRAY_SIZE(wm97xx_snd_ac97_controls); i++) {
+               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm97xx_snd_ac97_controls[i], ac97))) < 0)
+                       return err;
+       }
+       snd_ac97_write_cache(ac97,  AC97_WM97XX_FMIXER_VOL, 0x0808);
+       return 0;
+}
+
+static struct snd_ac97_build_ops patch_wolfson_wm9703_ops = {
+       .build_specific = patch_wolfson_wm9703_specific,
+};
 
-       // WM9703/9707/9708/9717
-       snd_ac97_write_cache(ac97, AC97_WM97XX_FMIXER_VOL, 0x0808);
-       snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0x8000);
+int patch_wolfson03(ac97_t * ac97)
+{
+       ac97->build_ops = &patch_wolfson_wm9703_ops;
        return 0;
 }
-  
-int patch_wolfson04(ac97_t * ac97)
+
+static const snd_kcontrol_new_t wm9704_snd_ac97_controls[] = {
+AC97_DOUBLE("Front Playback Volume", AC97_WM97XX_FMIXER_VOL, 8, 0, 31, 1),
+AC97_SINGLE("Front Playback Switch", AC97_WM97XX_FMIXER_VOL, 15, 1, 1),
+AC97_DOUBLE("Rear Playback Volume", AC97_WM9704_RMIXER_VOL, 8, 0, 31, 1),
+AC97_SINGLE("Rear Playback Switch", AC97_WM9704_RMIXER_VOL, 15, 1, 1),
+AC97_DOUBLE("Rear DAC Volume", AC97_WM9704_RPCM_VOL, 8, 0, 31, 1),
+AC97_DOUBLE("Surround Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1),
+};
+
+static int patch_wolfson_wm9704_specific(ac97_t * ac97)
 {
-       // WM9704M/9704Q
-       // set front and rear mixer volume
-       snd_ac97_write_cache(ac97, AC97_WM97XX_FMIXER_VOL, 0x0808);
-       snd_ac97_write_cache(ac97, AC97_WM9704_RMIXER_VOL, 0x0808);
-       
-       // patch for DVD noise
+       int err, i;
+       for (i = 0; i < ARRAY_SIZE(wm9704_snd_ac97_controls); i++) {
+               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm9704_snd_ac97_controls[i], ac97))) < 0)
+                       return err;
+       }
+       /* patch for DVD noise */
        snd_ac97_write_cache(ac97, AC97_WM9704_TEST, 0x0200);
-       // init vol
-       snd_ac97_write_cache(ac97, AC97_WM9704_RPCM_VOL, 0x0808);
-       // set rear surround volume
-       snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x0000);
        return 0;
 }
-  
+
+static struct snd_ac97_build_ops patch_wolfson_wm9704_ops = {
+       .build_specific = patch_wolfson_wm9704_specific,
+};
+
+int patch_wolfson04(ac97_t * ac97)
+{
+       /* WM9704M/9704Q */
+       ac97->build_ops = &patch_wolfson_wm9704_ops;
+       return 0;
+}
+
+static int patch_wolfson_wm9705_specific(ac97_t * ac97)
+{
+       int err, i;
+       for (i = 0; i < ARRAY_SIZE(wm97xx_snd_ac97_controls); i++) {
+               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm97xx_snd_ac97_controls[i], ac97))) < 0)
+                       return err;
+       }
+       snd_ac97_write_cache(ac97,  0x72, 0x0808);
+       return 0;
+}
+
+static struct snd_ac97_build_ops patch_wolfson_wm9705_ops = {
+       .build_specific = patch_wolfson_wm9705_specific,
+};
+
 int patch_wolfson05(ac97_t * ac97)
 {
-       // WM9705, WM9710
-       // set front mixer volume
-       snd_ac97_write_cache(ac97, AC97_WM97XX_FMIXER_VOL, 0x0808);
+       /* WM9705, WM9710 */
+       ac97->build_ops = &patch_wolfson_wm9705_ops;
+       return 0;
+}
+
+static const char* wm9711_alc_select[] = {"None", "Left", "Right", "Stereo"};
+static const char* wm9711_alc_mix[] = {"Stereo", "Right", "Left", "None"};
+static const char* wm9711_out3_src[] = {"Left", "VREF", "Left + Right", "Mono"};
+static const char* wm9711_out3_lrsrc[] = {"Master Mix", "Headphone Mix"};
+static const char* wm9711_rec_adc[] = {"Stereo", "Left", "Right", "Mute"};
+static const char* wm9711_base[] = {"Linear Control", "Adaptive Boost"};
+static const char* wm9711_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"};
+static const char* wm9711_mic[] = {"Mic 1", "Differential", "Mic 2", "Stereo"};
+static const char* wm9711_rec_sel[] = 
+       {"Mic 1", "NC", "NC", "Master Mix", "Line", "Headphone Mix", "Phone Mix", "Phone"};
+static const char* wm9711_ng_type[] = {"Constant Gain", "Mute"};
+
+static const struct ac97_enum wm9711_enum[] = {
+AC97_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9711_alc_select),
+AC97_ENUM_SINGLE(AC97_VIDEO, 10, 4, wm9711_alc_mix),
+AC97_ENUM_SINGLE(AC97_AUX, 9, 4, wm9711_out3_src),
+AC97_ENUM_SINGLE(AC97_AUX, 8, 2, wm9711_out3_lrsrc),
+AC97_ENUM_SINGLE(AC97_REC_SEL, 12, 4, wm9711_rec_adc),
+AC97_ENUM_SINGLE(AC97_MASTER_TONE, 15, 2, wm9711_base),
+AC97_ENUM_DOUBLE(AC97_REC_GAIN, 14, 6, 2, wm9711_rec_gain),
+AC97_ENUM_SINGLE(AC97_MIC, 5, 4, wm9711_mic),
+AC97_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 8, wm9711_rec_sel),
+AC97_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9711_ng_type),
+};
+
+static const snd_kcontrol_new_t wm9711_snd_ac97_controls[] = {
+AC97_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0),
+AC97_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0),
+AC97_SINGLE("ALC Decay Time", AC97_CODEC_CLASS_REV, 4, 15, 0),
+AC97_SINGLE("ALC Attack Time", AC97_CODEC_CLASS_REV, 0, 15, 0),
+AC97_ENUM("ALC Function", wm9711_enum[0]),
+AC97_SINGLE("ALC Max Volume", AC97_PCI_SVID, 11, 7, 1),
+AC97_SINGLE("ALC ZC Timeout", AC97_PCI_SVID, 9, 3, 1),
+AC97_SINGLE("ALC ZC Switch", AC97_PCI_SVID, 8, 1, 0),
+AC97_SINGLE("ALC NG Switch", AC97_PCI_SVID, 7, 1, 0),
+AC97_ENUM("ALC NG Type", wm9711_enum[9]),
+AC97_SINGLE("ALC NG Threshold", AC97_PCI_SVID, 0, 31, 1),
+
+AC97_SINGLE("Side Tone Switch", AC97_VIDEO, 15, 1, 1),
+AC97_SINGLE("Side Tone Volume", AC97_VIDEO, 12, 7, 1),
+AC97_ENUM("ALC Headphone Mux", wm9711_enum[1]),
+AC97_SINGLE("ALC Headphone Volume", AC97_VIDEO, 7, 7, 1),
+
+AC97_SINGLE("Out3 Switch", AC97_AUX, 15, 1, 1),
+AC97_SINGLE("Out3 ZC Switch", AC97_AUX, 7, 1, 1),
+AC97_ENUM("Out3 Mux", wm9711_enum[2]),
+AC97_ENUM("Out3 LR Mux", wm9711_enum[3]),
+AC97_SINGLE("Out3 Volume", AC97_AUX, 0, 31, 1),
+
+AC97_SINGLE("Beep to Headphone Switch", AC97_PC_BEEP, 15, 1, 1),
+AC97_SINGLE("Beep to Headphone Volume", AC97_PC_BEEP, 12, 7, 1),
+AC97_SINGLE("Beep to Side Tone Switch", AC97_PC_BEEP, 11, 1, 1),
+AC97_SINGLE("Beep to Side Tone Volume", AC97_PC_BEEP, 8, 7, 1),
+AC97_SINGLE("Beep to Phone Switch", AC97_PC_BEEP, 7, 1, 1),
+AC97_SINGLE("Beep to Phone Volume", AC97_PC_BEEP, 4, 7, 1),
+
+AC97_SINGLE("Aux to Headphone Switch", AC97_CD, 15, 1, 1),
+AC97_SINGLE("Aux to Headphone Volume", AC97_CD, 12, 7, 1),
+AC97_SINGLE("Aux to Side Tone Switch", AC97_CD, 11, 1, 1),
+AC97_SINGLE("Aux to Side Tone Volume", AC97_CD, 8, 7, 1),
+AC97_SINGLE("Aux to Phone Switch", AC97_CD, 7, 1, 1),
+AC97_SINGLE("Aux to Phone Volume", AC97_CD, 4, 7, 1),
+
+AC97_SINGLE("Phone to Headphone Switch", AC97_PHONE, 15, 1, 1),
+AC97_SINGLE("Phone to Master Switch", AC97_PHONE, 14, 1, 1),
+
+AC97_SINGLE("Line to Headphone Switch", AC97_LINE, 15, 1, 1),
+AC97_SINGLE("Line to Master Switch", AC97_LINE, 14, 1, 1),
+AC97_SINGLE("Line to Phone Switch", AC97_LINE, 13, 1, 1),
+
+AC97_SINGLE("PCM Playback to Headphone Switch", AC97_PCM, 15, 1, 1),
+AC97_SINGLE("PCM Playback to Master Switch", AC97_PCM, 14, 1, 1),
+AC97_SINGLE("PCM Playback to Phone Switch", AC97_PCM, 13, 1, 1),
+
+AC97_SINGLE("Capture 20dB Boost Switch", AC97_REC_SEL, 14, 1, 0),
+AC97_ENUM("Capture to Phone Mux", wm9711_enum[4]),
+AC97_SINGLE("Capture to Phone 20dB Boost Switch", AC97_REC_SEL, 11, 1, 1),
+AC97_ENUM("Capture Select", wm9711_enum[8]),
+
+AC97_SINGLE("3D Upper Cut-off Switch", AC97_3D_CONTROL, 5, 1, 1),
+AC97_SINGLE("3D Lower Cut-off Switch", AC97_3D_CONTROL, 4, 1, 1),
+
+AC97_ENUM("Bass Control", wm9711_enum[5]),
+AC97_SINGLE("Bass Cut-off Switch", AC97_MASTER_TONE, 12, 1, 1),
+AC97_SINGLE("Tone Cut-off Switch", AC97_MASTER_TONE, 4, 1, 1),
+AC97_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0),
+
+AC97_SINGLE("ADC Switch", AC97_REC_GAIN, 15, 1, 1),
+AC97_ENUM("Capture Volume Steps", wm9711_enum[6]),
+AC97_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 15, 1),
+AC97_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0),
+
+AC97_SINGLE("Mic 1 to Phone Switch", AC97_MIC, 14, 1, 1),
+AC97_SINGLE("Mic 2 to Phone Switch", AC97_MIC, 13, 1, 1),
+AC97_ENUM("Mic Select Source", wm9711_enum[7]),
+AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 32, 1),
+AC97_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0),
+
+AC97_SINGLE("Master ZC Switch", AC97_MASTER, 7, 1, 0),
+AC97_SINGLE("Headphone ZC Switch", AC97_HEADPHONE, 7, 1, 0),
+AC97_SINGLE("Mono ZC Switch", AC97_MASTER_MONO, 7, 1, 0),
+};
+
+static int patch_wolfson_wm9711_specific(ac97_t * ac97)
+{
+       int err, i;
+       
+       for (i = 0; i < ARRAY_SIZE(wm9711_snd_ac97_controls); i++) {
+               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm9711_snd_ac97_controls[i], ac97))) < 0)
+                       return err;
+       }
+       snd_ac97_write_cache(ac97,  AC97_CODEC_CLASS_REV, 0x0808);
+       snd_ac97_write_cache(ac97,  AC97_PCI_SVID, 0x0808);
+       snd_ac97_write_cache(ac97,  AC97_VIDEO, 0x0808);
+       snd_ac97_write_cache(ac97,  AC97_AUX, 0x0808);
+       snd_ac97_write_cache(ac97,  AC97_PC_BEEP, 0x0808);
+       snd_ac97_write_cache(ac97,  AC97_CD, 0x0000);
        return 0;
 }
 
+static struct snd_ac97_build_ops patch_wolfson_wm9711_ops = {
+       .build_specific = patch_wolfson_wm9711_specific,
+};
+
 int patch_wolfson11(ac97_t * ac97)
 {
-       // WM9711, WM9712
-       // set out3 volume
-       snd_ac97_write_cache(ac97, AC97_WM9711_OUT3VOL, 0x0808);
+       /* WM9711, WM9712 */
+       ac97->build_ops = &patch_wolfson_wm9711_ops;
+
+       ac97->flags |= AC97_HAS_NO_REC_GAIN | AC97_STEREO_MUTES | AC97_HAS_NO_MIC |
+               AC97_HAS_NO_PC_BEEP | AC97_HAS_NO_VIDEO | AC97_HAS_NO_CD;
+       
        return 0;
 }
 
-static const char* wm9713_mic_mixer[] = {"Stereo", "Mic1", "Mic2", "Mute"};
+static const char* wm9713_mic_mixer[] = {"Stereo", "Mic 1", "Mic 2", "Mute"};
 static const char* wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"};
-static const char* wm9713_rec_src_l[] = {"Mic1", "Mic2", "Line L", "Mono In", "HP Mix L", "Spk Mix", "Mono Mix", "Zh"};
-static const char* wm9713_rec_src_r[] = {"Mic1", "Mic2", "Line R", "Mono In", "HP Mix R", "Spk Mix", "Mono Mix", "Zh"};
+static const char* wm9713_rec_src[] = 
+       {"Mic 1", "Mic 2", "Line", "Mono In", "Headphone Mix", "Master Mix", 
+       "Mono Mix", "Zh"};
+static const char* wm9713_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"};
+static const char* wm9713_alc_select[] = {"None", "Left", "Right", "Stereo"};
+static const char* wm9713_mono_pga[] = {"Vmid", "Zh", "Mono Mix", "Inv 1"};
+static const char* wm9713_spk_pga[] = 
+       {"Vmid", "Zh", "Headphone Mix", "Master Mix", "Inv", "NC", "NC", "NC"};
+static const char* wm9713_hp_pga[] = {"Vmid", "Zh", "Headphone Mix", "NC"};
+static const char* wm9713_out3_pga[] = {"Vmid", "Zh", "Inv 1", "NC"};
+static const char* wm9713_out4_pga[] = {"Vmid", "Zh", "Inv 2", "NC"};
+static const char* wm9713_dac_inv[] = 
+       {"Off", "Mono Mix", "Master Mix", "Headphone Mix L", "Headphone Mix R", 
+       "Headphone Mix Mono", "NC", "Vmid"};
+static const char* wm9713_base[] = {"Linear Control", "Adaptive Boost"};
+static const char* wm9713_ng_type[] = {"Constant Gain", "Mute"};
 
 static const struct ac97_enum wm9713_enum[] = {
 AC97_ENUM_SINGLE(AC97_LINE, 3, 4, wm9713_mic_mixer),
 AC97_ENUM_SINGLE(AC97_VIDEO, 14, 4, wm9713_rec_mux),
 AC97_ENUM_SINGLE(AC97_VIDEO, 9, 4, wm9713_rec_mux),
-AC97_ENUM_SINGLE(AC97_VIDEO, 3, 8, wm9713_rec_src_l),
-AC97_ENUM_SINGLE(AC97_VIDEO, 0, 8, wm9713_rec_src_r),
+AC97_ENUM_DOUBLE(AC97_VIDEO, 3, 0, 8, wm9713_rec_src),
+AC97_ENUM_DOUBLE(AC97_CD, 14, 6, 2, wm9713_rec_gain),
+AC97_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9713_alc_select),
+AC97_ENUM_SINGLE(AC97_REC_GAIN, 14, 4, wm9713_mono_pga),
+AC97_ENUM_DOUBLE(AC97_REC_GAIN, 11, 8, 8, wm9713_spk_pga),
+AC97_ENUM_DOUBLE(AC97_REC_GAIN, 6, 4, 4, wm9713_hp_pga),
+AC97_ENUM_SINGLE(AC97_REC_GAIN, 2, 4, wm9713_out3_pga),
+AC97_ENUM_SINGLE(AC97_REC_GAIN, 0, 4, wm9713_out4_pga),
+AC97_ENUM_DOUBLE(AC97_REC_GAIN_MIC, 13, 10, 8, wm9713_dac_inv),
+AC97_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, wm9713_base),
+AC97_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9713_ng_type),
 };
 
-static const snd_kcontrol_new_t wm13_snd_ac97_controls_line_in[] = {
+static const snd_kcontrol_new_t wm13_snd_ac97_controls[] = {
 AC97_DOUBLE("Line In Volume", AC97_PC_BEEP, 8, 0, 31, 1),
-AC97_SINGLE("Line In to Headphone Mute", AC97_PC_BEEP, 15, 1, 1),
-AC97_SINGLE("Line In to Speaker Mute", AC97_PC_BEEP, 14, 1, 1),
-AC97_SINGLE("Line In to Mono Mute", AC97_PC_BEEP, 13, 1, 1),
+AC97_SINGLE("Line In to Headphone Switch", AC97_PC_BEEP, 15, 1, 1),
+AC97_SINGLE("Line In to Master Switch", AC97_PC_BEEP, 14, 1, 1),
+AC97_SINGLE("Line In to Mono Switch", AC97_PC_BEEP, 13, 1, 1),
+
+AC97_DOUBLE("PCM Playback Volume", AC97_PHONE, 8, 0, 31, 1),
+AC97_SINGLE("PCM Playback to Headphone Switch", AC97_PHONE, 15, 1, 1),
+AC97_SINGLE("PCM Playback to Master Switch", AC97_PHONE, 14, 1, 1),
+AC97_SINGLE("PCM Playback to Mono Switch", AC97_PHONE, 13, 1, 1),
+
+AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1),
+AC97_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1),
+AC97_SINGLE("Mic 1 to Mono Switch", AC97_LINE, 7, 1, 1),
+AC97_SINGLE("Mic 2 to Mono Switch", AC97_LINE, 6, 1, 1),
+AC97_SINGLE("Mic Boost (+20dB) Switch", AC97_LINE, 5, 1, 0),
+AC97_ENUM("Mic to Headphone Mux", wm9713_enum[0]),
+AC97_SINGLE("Mic Headphone Mixer Volume", AC97_LINE, 0, 7, 1),
+
+AC97_SINGLE("Capture Switch", AC97_CD, 15, 1, 1),
+AC97_ENUM("Capture Volume Steps", wm9713_enum[4]),
+AC97_DOUBLE("Capture Volume", AC97_CD, 8, 0, 15, 0),
+AC97_SINGLE("Capture ZC Switch", AC97_CD, 7, 1, 0),
+
+AC97_ENUM("Capture to Headphone Mux", wm9713_enum[1]),
+AC97_SINGLE("Capture to Headphone Volume", AC97_VIDEO, 11, 7, 1),
+AC97_ENUM("Capture to Mono Mux", wm9713_enum[2]),
+AC97_SINGLE("Capture to Mono Boost (+20dB) Switch", AC97_VIDEO, 8, 1, 0),
+AC97_SINGLE("Capture ADC Boost (+20dB) Switch", AC97_VIDEO, 6, 1, 0),
+AC97_ENUM("Capture Select", wm9713_enum[3]),
+
+AC97_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0),
+AC97_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0),
+AC97_SINGLE("ALC Decay Time ", AC97_CODEC_CLASS_REV, 4, 15, 0),
+AC97_SINGLE("ALC Attack Time", AC97_CODEC_CLASS_REV, 0, 15, 0),
+AC97_ENUM("ALC Function", wm9713_enum[5]),
+AC97_SINGLE("ALC Max Volume", AC97_PCI_SVID, 11, 7, 0),
+AC97_SINGLE("ALC ZC Timeout", AC97_PCI_SVID, 9, 3, 0),
+AC97_SINGLE("ALC ZC Switch", AC97_PCI_SVID, 8, 1, 0),
+AC97_SINGLE("ALC NG Switch", AC97_PCI_SVID, 7, 1, 0),
+AC97_ENUM("ALC NG Type", wm9713_enum[13]),
+AC97_SINGLE("ALC NG Threshold", AC97_PCI_SVID, 0, 31, 0),
+
+AC97_DOUBLE("Master ZC Switch", AC97_MASTER, 14, 6, 1, 0),
+AC97_DOUBLE("Headphone ZC Switch", AC97_HEADPHONE, 14, 6, 1, 0),
+AC97_DOUBLE("Out3/4 ZC Switch", AC97_MASTER_MONO, 14, 6, 1, 0),
+AC97_SINGLE("Master Right Switch", AC97_MASTER, 7, 1, 1),
+AC97_SINGLE("Headphone Right Switch", AC97_HEADPHONE, 7, 1, 1),
+AC97_SINGLE("Out3/4 Right Switch", AC97_MASTER_MONO, 7, 1, 1),
+
+AC97_SINGLE("Mono In to Headphone Switch", AC97_MASTER_TONE, 15, 1, 1),
+AC97_SINGLE("Mono In to Master Switch", AC97_MASTER_TONE, 14, 1, 1),
+AC97_SINGLE("Mono In Volume", AC97_MASTER_TONE, 8, 31, 1),
+AC97_SINGLE("Mono Switch", AC97_MASTER_TONE, 7, 1, 1),
+AC97_SINGLE("Mono ZC Switch", AC97_MASTER_TONE, 6, 1, 0),
+AC97_SINGLE("Mono Volume", AC97_MASTER_TONE, 0, 31, 1),
+
+AC97_SINGLE("PC Beep to Headphone Switch", AC97_AUX, 15, 1, 1),
+AC97_SINGLE("PC Beep to Headphone Volume", AC97_AUX, 12, 7, 1),
+AC97_SINGLE("PC Beep to Master Switch", AC97_AUX, 11, 1, 1),
+AC97_SINGLE("PC Beep to Master Volume", AC97_AUX, 8, 7, 1),
+AC97_SINGLE("PC Beep to Mono Switch", AC97_AUX, 7, 1, 1),
+AC97_SINGLE("PC Beep to Mono Volume", AC97_AUX, 4, 7, 1),
+
+AC97_SINGLE("Voice to Headphone Switch", AC97_PCM, 15, 1, 1),
+AC97_SINGLE("Voice to Headphone Volume", AC97_PCM, 12, 7, 1),
+AC97_SINGLE("Voice to Master Switch", AC97_PCM, 11, 1, 1),
+AC97_SINGLE("Voice to Master Volume", AC97_PCM, 8, 7, 1),
+AC97_SINGLE("Voice to Mono Switch", AC97_PCM, 7, 1, 1),
+AC97_SINGLE("Voice to Mono Volume", AC97_PCM, 4, 7, 1),
+
+AC97_SINGLE("Aux to Headphone Switch", AC97_REC_SEL, 15, 1, 1),
+AC97_SINGLE("Aux to Headphone Volume", AC97_REC_SEL, 12, 7, 1),
+AC97_SINGLE("Aux to Master Switch", AC97_REC_SEL, 11, 1, 1),
+AC97_SINGLE("Aux to Master Volume", AC97_REC_SEL, 8, 7, 1),
+AC97_SINGLE("Aux to Mono Switch", AC97_REC_SEL, 7, 1, 1),
+AC97_SINGLE("Aux to Mono Volume", AC97_REC_SEL, 4, 7, 1),
+
+AC97_ENUM("Mono Input Mux", wm9713_enum[6]),
+AC97_ENUM("Master Input Mux", wm9713_enum[7]),
+AC97_ENUM("Headphone Input Mux", wm9713_enum[8]),
+AC97_ENUM("Out 3 Input Mux", wm9713_enum[9]),
+AC97_ENUM("Out 4 Input Mux", wm9713_enum[10]),
+
+AC97_ENUM("Bass Control", wm9713_enum[12]),
+AC97_SINGLE("Bass Cut-off Switch", AC97_GENERAL_PURPOSE, 12, 1, 1),
+AC97_SINGLE("Tone Cut-off Switch", AC97_GENERAL_PURPOSE, 4, 1, 1),
+AC97_SINGLE("Playback Attenuate (-6dB) Switch", AC97_GENERAL_PURPOSE, 6, 1, 0),
+AC97_SINGLE("Bass Volume", AC97_GENERAL_PURPOSE, 8, 15, 1),
+AC97_SINGLE("Tone Volume", AC97_GENERAL_PURPOSE, 0, 15, 1),
 };
 
-static const snd_kcontrol_new_t wm13_snd_ac97_controls_dac[] = {
-AC97_DOUBLE("DAC Volume", AC97_PHONE, 8, 0, 31, 1),
-AC97_SINGLE("DAC to Headphone Mute", AC97_PHONE, 15, 1, 1),
-AC97_SINGLE("DAC to Speaker Mute", AC97_PHONE, 14, 1, 1),
-AC97_SINGLE("DAC to Mono Mute", AC97_PHONE, 13, 1, 1),
+static const snd_kcontrol_new_t wm13_snd_ac97_controls_3d[] = {
+AC97_ENUM("Inv Input Mux", wm9713_enum[11]),
+AC97_SINGLE("3D Upper Cut-off Switch", AC97_REC_GAIN_MIC, 5, 1, 0),
+AC97_SINGLE("3D Lower Cut-off Switch", AC97_REC_GAIN_MIC, 4, 1, 0),
+AC97_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1),
 };
 
-static const snd_kcontrol_new_t wm13_snd_ac97_controls_mic[] = {
-AC97_SINGLE("MICA Volume", AC97_MIC, 8, 31, 1),
-AC97_SINGLE("MICB Volume", AC97_MIC, 0, 31, 1),
-AC97_SINGLE("MICA to Mono Mute", AC97_LINE, 7, 1, 1),
-AC97_SINGLE("MICB to Mono Mute", AC97_LINE, 6, 1, 1),
-AC97_SINGLE("MIC Boost (+20dB)", AC97_LINE, 5, 1, 1),
-AC97_ENUM("MIC Headphone Routing", wm9713_enum[0]),
-AC97_SINGLE("MIC Headphone Mixer Volume", AC97_LINE, 0, 7, 1)
-};
-
-static const snd_kcontrol_new_t wm13_snd_ac97_controls_adc[] = {
-AC97_SINGLE("ADC Mute", AC97_CD, 15, 1, 1),
-AC97_DOUBLE("Gain Step Size (1.5dB/0.75dB)", AC97_CD, 14, 6, 1, 1),
-AC97_DOUBLE("ADC Volume",AC97_CD, 8, 0, 15, 0),
-AC97_SINGLE("ADC Zero Cross", AC97_CD, 7, 1, 1),
-};
-
-static const snd_kcontrol_new_t wm13_snd_ac97_controls_recsel[] = {
-AC97_ENUM("Record to Headphone Path", wm9713_enum[1]),
-AC97_SINGLE("Record to Headphone Volume", AC97_VIDEO, 11, 7, 0),
-AC97_ENUM("Record to Mono Path", wm9713_enum[2]),
-AC97_SINGLE("Record to Mono Boost (+20dB)", AC97_VIDEO, 8, 1, 0),
-AC97_SINGLE("Record ADC Boost (+20dB)", AC97_VIDEO, 6, 1, 0),
-AC97_ENUM("Record Select Left", wm9713_enum[3]),
-AC97_ENUM("Record Select Right", wm9713_enum[4]),
-};
+static int patch_wolfson_wm9713_3d (ac97_t * ac97)
+{
+       int err, i;
+    
+       for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_3d); i++) {
+               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_3d[i], ac97))) < 0)
+                       return err;
+       }
+       return 0;
+}
 
 static int patch_wolfson_wm9713_specific(ac97_t * ac97)
 {
        int err, i;
        
-       for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_line_in); i++) {
-               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_line_in[i], ac97))) < 0)
+       for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls); i++) {
+               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls[i], ac97))) < 0)
                        return err;
        }
        snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x0808);
-       
-       for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_dac); i++) {
-               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_dac[i], ac97))) < 0)
-                       return err;
-       }
        snd_ac97_write_cache(ac97, AC97_PHONE, 0x0808);
-       
-       for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_mic); i++) {
-               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_mic[i], ac97))) < 0)
-                       return err;
-       }
        snd_ac97_write_cache(ac97, AC97_MIC, 0x0808);
        snd_ac97_write_cache(ac97, AC97_LINE, 0x00da);
-       
-       for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_adc); i++) {
-               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_adc[i], ac97))) < 0)
-                       return err;
-       }
        snd_ac97_write_cache(ac97, AC97_CD, 0x0808);
-       
-       for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_recsel); i++) {
-               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_recsel[i], ac97))) < 0)
-                       return err;
-       }
        snd_ac97_write_cache(ac97, AC97_VIDEO, 0xd612);
        snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x1ba0);
-       
        return 0;
 }
 
@@ -525,6 +771,7 @@ static void patch_wolfson_wm9713_resume (ac97_t * ac97)
 
 static struct snd_ac97_build_ops patch_wolfson_wm9713_ops = {
        .build_specific = patch_wolfson_wm9713_specific,
+       .build_3d = patch_wolfson_wm9713_3d,
 #ifdef CONFIG_PM       
        .suspend = patch_wolfson_wm9713_suspend,
        .resume = patch_wolfson_wm9713_resume
@@ -533,10 +780,13 @@ static struct snd_ac97_build_ops patch_wolfson_wm9713_ops = {
 
 int patch_wolfson13(ac97_t * ac97)
 {
+       /* WM9713, WM9714 */
        ac97->build_ops = &patch_wolfson_wm9713_ops;
 
        ac97->flags |= AC97_HAS_NO_REC_GAIN | AC97_STEREO_MUTES | AC97_HAS_NO_PHONE |
-               AC97_HAS_NO_PC_BEEP | AC97_HAS_NO_VIDEO | AC97_HAS_NO_CD;
+               AC97_HAS_NO_PC_BEEP | AC97_HAS_NO_VIDEO | AC97_HAS_NO_CD | AC97_HAS_NO_TONE |
+               AC97_HAS_NO_STD_PCM;
+       ac97->scaps &= ~AC97_SCAP_MODEM;
 
        snd_ac97_write_cache(ac97, AC97_EXTENDED_MID, 0xda00);
        snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0x3810);
@@ -1379,6 +1629,7 @@ static void check_ad1981_hp_jack_sense(ac97_t *ac97)
        u32 subid = ((u32)ac97->subsystem_vendor << 16) | ac97->subsystem_device;
        switch (subid) {
        case 0x103c0890: /* HP nc6000 */
+       case 0x103c099c: /* HP nx6110 */
        case 0x103c006d: /* HP nx9105 */
        case 0x17340088: /* FSC Scenic-W */
                /* enable headphone jack sense */
@@ -1706,7 +1957,7 @@ static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = {
 };
 
 static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = {
-        AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0),
+        AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_ALC650_MULTICH, 11, 1, 0),
         AC97_SINGLE("Analog to IEC958 Output", AC97_ALC650_MULTICH, 12, 1, 0),
        /* disable this controls since it doesn't work as expected */
        /* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */
@@ -1849,12 +2100,12 @@ static int alc655_iec958_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_
 }
 
 static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc655[] = {
-        AC97_PAGE_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0, 0),
+        AC97_PAGE_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_ALC650_MULTICH, 11, 1, 0, 0),
        /* disable this controls since it doesn't work as expected */
         /* AC97_PAGE_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 14, 1, 0, 0), */
        {
                .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name   = "IEC958 Playback Route",
+               .name   = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
                .info   = alc655_iec958_route_info,
                .get    = alc655_iec958_route_get,
                .put    = alc655_iec958_route_put,
@@ -2415,6 +2666,16 @@ int patch_vt1616(ac97_t * ac97)
        return 0;
 }
 
+/*
+ * VT1617A codec
+ */
+int patch_vt1617a(ac97_t * ac97)
+{
+       ac97->ext_id |= AC97_EI_SPDIF;  /* force the detection of spdif */
+       ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
+       return 0;
+}
+
 /*
  */
 static void it2646_update_jacks(ac97_t *ac97)
@@ -2433,7 +2694,7 @@ static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = {
 };
 
 static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = {
-       AC97_SINGLE("IEC958 Capture Switch", 0x76, 11, 1, 0),
+       AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0x76, 11, 1, 0),
        AC97_SINGLE("Analog to IEC958 Output", 0x76, 12, 1, 0),
        AC97_SINGLE("IEC958 Input Monitor", 0x76, 13, 1, 0),
 };
index 7b7377d0f2ae4d3926e3cd7e379be16d488d3027..ec181132010660e2d3015124b98b6b7923132c3b 100644 (file)
@@ -56,5 +56,6 @@ int patch_cm9739(ac97_t * ac97);
 int patch_cm9761(ac97_t * ac97);
 int patch_cm9780(ac97_t * ac97);
 int patch_vt1616(ac97_t * ac97);
+int patch_vt1617a(ac97_t * ac97);
 int patch_it2646(ac97_t * ac97);
 int mpatch_si3036(ac97_t * ac97);
index f08ae71f902da108b4312e75e759a6f672c48ef3..4943299cf137dce8ab4bcb369ad9813ad0660173 100644 (file)
@@ -1842,7 +1842,7 @@ static int __devinit snd_ali_pcm(ali_t * codec, int device, struct ali_pcm_descr
        return 0;
 }
 
-struct ali_pcm_description ali_pcms[] = {
+static struct ali_pcm_description ali_pcms[] = {
        { "ALI 5451", ALI_CHANNELS, 1, &snd_ali_playback_ops, &snd_ali_capture_ops },
        { "ALI 5451 modem", 1, 1, &snd_ali_modem_playback_ops, &snd_ali_modem_capture_ops }
 };
@@ -1959,9 +1959,9 @@ static int snd_ali5451_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
 static snd_kcontrol_new_t snd_ali5451_mixer_spdif[] __devinitdata = {
        /* spdif aplayback switch */
        /* FIXME: "IEC958 Playback Switch" may conflict with one on ac97_codec */
-       ALI5451_SPDIF("IEC958 Output switch", 0, 0),
+       ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH), 0, 0),
        /* spdif out to spdif channel */
-       ALI5451_SPDIF("IEC958 Channel Output Switch", 0, 1),
+       ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("Channel Output ",NONE,SWITCH), 0, 1),
        /* spdif in from spdif channel */
        ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, 2)
 };
@@ -2249,7 +2249,7 @@ static int __devinit snd_ali_create(snd_card_t * card,
                return -ENXIO;
        }
 
-       if ((codec = kcalloc(1, sizeof(*codec), GFP_KERNEL)) == NULL) {
+       if ((codec = kzalloc(sizeof(*codec), GFP_KERNEL)) == NULL) {
                pci_disable_device(pci);
                return -ENOMEM;
        }
index cafab4af5c571752765ad1a4b552c9013f4e4aad..188df085b7ee5d4ae21903bebd1b6381b48cdc6a 100644 (file)
@@ -248,6 +248,7 @@ struct snd_atiixp_dma {
        unsigned int period_bytes, periods;
        int opened;
        int running;
+       int suspended;
        int pcm_open_flag;
        int ac97_pcm_type;      /* index # of ac97_pcm to access, -1 = not used */
        unsigned int saved_curptr;
@@ -699,12 +700,18 @@ static int snd_atiixp_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
        spin_lock(&chip->reg_lock);
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+       case SNDRV_PCM_TRIGGER_RESUME:
                dma->ops->enable_transfer(chip, 1);
                dma->running = 1;
+               dma->suspended = 0;
                break;
        case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
                dma->ops->enable_transfer(chip, 0);
                dma->running = 0;
+               dma->suspended = cmd == SNDRV_PCM_TRIGGER_SUSPEND;
                break;
        default:
                err = -EINVAL;
@@ -975,6 +982,7 @@ static snd_pcm_hardware_t snd_atiixp_pcm_hw =
 {
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                SNDRV_PCM_INFO_PAUSE |
                                 SNDRV_PCM_INFO_RESUME |
                                 SNDRV_PCM_INFO_MMAP_VALID),
        .formats =              SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
@@ -1419,7 +1427,7 @@ static int snd_atiixp_suspend(snd_card_t *card, pm_message_t state)
        snd_atiixp_aclink_down(chip);
        snd_atiixp_chip_stop(chip);
 
-       pci_set_power_state(chip->pci, 3);
+       pci_set_power_state(chip->pci, PCI_D3hot);
        pci_disable_device(chip->pci);
        return 0;
 }
@@ -1430,7 +1438,7 @@ static int snd_atiixp_resume(snd_card_t *card)
        int i;
 
        pci_enable_device(chip->pci);
-       pci_set_power_state(chip->pci, 0);
+       pci_set_power_state(chip->pci, PCI_D0);
        pci_set_master(chip->pci);
 
        snd_atiixp_aclink_reset(chip);
@@ -1443,7 +1451,7 @@ static int snd_atiixp_resume(snd_card_t *card)
        for (i = 0; i < NUM_ATI_PCMDEVS; i++)
                if (chip->pcmdevs[i]) {
                        atiixp_dma_t *dma = &chip->dmas[i];
-                       if (dma->substream && dma->running) {
+                       if (dma->substream && dma->suspended) {
                                dma->ops->enable_dma(chip, 1);
                                writel((u32)dma->desc_buf.addr | ATI_REG_LINKPTR_EN,
                                       chip->remap_addr + dma->ops->llp_offset);
index 04dcefd8b8ff01eea95c4118db15c20fca490f32..38bd2b5dd434a00c63b4a6dcdfe6c9124bc77c91 100644 (file)
@@ -33,7 +33,7 @@
 /* hardware definition */
 static snd_pcm_hardware_t snd_vortex_playback_hw_adb = {
        .info =
-           (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME |
+           (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
             SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
             SNDRV_PCM_INFO_MMAP_VALID),
        .formats =
@@ -58,7 +58,7 @@ static snd_pcm_hardware_t snd_vortex_playback_hw_adb = {
 #ifndef CHIP_AU8820
 static snd_pcm_hardware_t snd_vortex_playback_hw_a3d = {
        .info =
-           (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME |
+           (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
             SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
             SNDRV_PCM_INFO_MMAP_VALID),
        .formats =
@@ -78,7 +78,7 @@ static snd_pcm_hardware_t snd_vortex_playback_hw_a3d = {
 #endif
 static snd_pcm_hardware_t snd_vortex_playback_hw_spdif = {
        .info =
-           (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME |
+           (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
             SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
             SNDRV_PCM_INFO_MMAP_VALID),
        .formats =
@@ -220,8 +220,10 @@ snd_vortex_pcm_hw_params(snd_pcm_substream_t * substream,
                    vortex_adb_allocroute(chip, -1,
                                          params_channels(hw_params),
                                          substream->stream, type);
-               if (dma < 0)
+               if (dma < 0) {
+                       spin_unlock_irq(&chip->lock);
                        return dma;
+               }
                stream = substream->runtime->private_data = &chip->dma_adb[dma];
                stream->substream = substream;
                /* Setup Buffers. */
index 95c289284267fdf0a33edfd507e5b7277826eac9..7e27bfc3743985d06a4c1fee9a62a86061143b0b 100644 (file)
@@ -188,6 +188,14 @@ static ca0106_details_t ca0106_chip_details[] = {
           .name   = "MSI K8N Diamond MB [SB0438]",
           .gpio_type = 1,
           .i2c_adc = 1 } ,
+        /* Shuttle XPC SD31P which has an onboard Creative Labs Sound Blaster Live! 24-bit EAX
+         * high-definition 7.1 audio processor".
+         * Added using info from andrewvegan in alsa bug #1298
+         */
+        { .serial = 0x30381297,
+          .name   = "Shuttle XPC SD31P [SD31P]",
+          .gpio_type = 1,
+          .i2c_adc = 1 } ,
         { .serial = 0,
           .name   = "AudigyLS [Unknown]" }
 };
index 0e5e9ce0ff28be76943cf8d9809a0028cbaa9bfe..b6b8882ce704fb3bd70dd11b5d380f97f64bcc8d 100644 (file)
@@ -297,7 +297,7 @@ static int snd_ca0106_spdif_put(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_ca0106_spdif_mask_control =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-        .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+        .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
         .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
        .count =        4,
         .info =         snd_ca0106_spdif_info,
@@ -306,7 +306,7 @@ static snd_kcontrol_new_t snd_ca0106_spdif_mask_control =
 
 static snd_kcontrol_new_t snd_ca0106_spdif_control =
 {
-        .iface =       SNDRV_CTL_ELEM_IFACE_MIXER,
+        .iface =       SNDRV_CTL_ELEM_IFACE_PCM,
         .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
        .count =        4,
         .info =         snd_ca0106_spdif_info,
index f5a4ac1ceef917303423927584d92f3017b41e1a..b098b51099c2ddbccac84f9ebf2ebae629837b90 100644 (file)
@@ -1029,7 +1029,7 @@ static int snd_cmipci_spdif_mask_get(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_cmipci_spdif_mask __devinitdata =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
        .info =         snd_cmipci_spdif_mask_info,
        .get =          snd_cmipci_spdif_mask_get,
index db212ecd792aac6080700f44b365c16290d6286b..b9fff4ee6f9dc789db6285c08cf18bf2332b6260 100644 (file)
@@ -113,7 +113,7 @@ static int __devinit snd_card_cs46xx_probe(struct pci_dev *pci,
                return err;
        }
 #endif
-       if ((err = snd_cs46xx_mixer(chip)) < 0) {
+       if ((err = snd_cs46xx_mixer(chip, 2)) < 0) {
                snd_card_free(card);
                return err;
        }
index ff28af1f658ebf6964535119c1794f6bd3d978d8..4b052158ee3378bb32ec9c3670903a1f8350e6fb 100644 (file)
@@ -1243,8 +1243,8 @@ static snd_pcm_hardware_t snd_cs46xx_playback =
 {
        .info =                 (SNDRV_PCM_INFO_MMAP |
                                 SNDRV_PCM_INFO_INTERLEAVED | 
-                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
+                                /*SNDRV_PCM_INFO_RESUME*/),
        .formats =              (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
                                 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
                                 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE),
@@ -1265,8 +1265,8 @@ static snd_pcm_hardware_t snd_cs46xx_capture =
 {
        .info =                 (SNDRV_PCM_INFO_MMAP |
                                 SNDRV_PCM_INFO_INTERLEAVED |
-                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
+                                /*SNDRV_PCM_INFO_RESUME*/),
        .formats =              SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
        .rate_min =             5500,
@@ -2231,7 +2231,7 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
 },
 {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "IEC958 Output Switch",
+       .name = SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH),
        .info = snd_mixer_boolean_info,
        .get = snd_cs46xx_iec958_get,
        .put = snd_cs46xx_iec958_put,
@@ -2239,7 +2239,7 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
 },
 {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "IEC958 Input Switch",
+       .name = SNDRV_CTL_NAME_IEC958("Input ",NONE,SWITCH),
        .info = snd_mixer_boolean_info,
        .get = snd_cs46xx_iec958_get,
        .put = snd_cs46xx_iec958_put,
@@ -2249,7 +2249,7 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
 /* Input IEC958 volume does not work for the moment. (Benny) */
 {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "IEC958 Input Volume",
+       .name = SNDRV_CTL_NAME_IEC958("Input ",NONE,VOLUME),
        .info = snd_cs46xx_vol_info,
        .get = snd_cs46xx_vol_iec958_get,
        .put = snd_cs46xx_vol_iec958_put,
@@ -2440,7 +2440,7 @@ static int __devinit cs46xx_detect_codec(cs46xx_t *chip, int codec)
        return -ENXIO;
 }
 
-int __devinit snd_cs46xx_mixer(cs46xx_t *chip)
+int __devinit snd_cs46xx_mixer(cs46xx_t *chip, int spdif_device)
 {
        snd_card_t *card = chip->card;
        snd_ctl_elem_id_t id;
@@ -2476,6 +2476,8 @@ int __devinit snd_cs46xx_mixer(cs46xx_t *chip)
        for (idx = 0; idx < ARRAY_SIZE(snd_cs46xx_controls); idx++) {
                snd_kcontrol_t *kctl;
                kctl = snd_ctl_new1(&snd_cs46xx_controls[idx], chip);
+               if (kctl && kctl->id.iface == SNDRV_CTL_ELEM_IFACE_PCM)
+                       kctl->id.device = spdif_device;
                if ((err = snd_ctl_add(card, kctl)) < 0)
                        return err;
        }
index b17142cabeadf0ead22487452012f820529a8abd..fc377c4b666c6d2d7846a3c13b12b50e144bd288 100644 (file)
@@ -149,7 +149,7 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci,
                }
        }
 
-       if ((err = snd_emu10k1_mixer(emu)) < 0) {
+       if ((err = snd_emu10k1_mixer(emu, 0, 3)) < 0) {
                snd_card_free(card);
                return err;
        }
index 746b51ef39663e263d290e66805ca69dcfebb653..e69d5b739e802f84c92029d9afdd51b8456c6a9b 100644 (file)
@@ -741,12 +741,20 @@ static emu_chip_details_t emu_chip_details[] = {
         .emu10k1_chip = 1,
         .ac97_chip = 1,
         .sblive51 = 1} ,
+       /* Tested by Thomas Zehetbauer 27th Aug 2005 */
+       {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80651102,
+        .driver = "EMU10K1", .name = "SB Live 5.1 [SB0220]", 
+        .id = "Live",
+        .emu10k1_chip = 1,
+        .ac97_chip = 1,
+        .sblive51 = 1} ,
        {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102,
         .driver = "EMU10K1", .name = "SB Live 5.1", 
         .id = "Live",
         .emu10k1_chip = 1,
         .ac97_chip = 1,
         .sblive51 = 1} ,
+       /* Tested by alsa bugtrack user "hus" 12th Sept 2005 */
        {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102,
         .driver = "EMU10K1", .name = "SBLive! Player 5.1 [SB0060]", 
         .id = "Live",
index e90c5ddd1d17ef0451e87010040c72bb71966ac7..52c7826df4402ee0e71629ff425bc5ab1f284d9a 100644 (file)
@@ -1183,7 +1183,7 @@ static int snd_emu10k1x_spdif_put(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_emu10k1x_spdif_mask_control =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
        .count =        3,
        .info =         snd_emu10k1x_spdif_info,
@@ -1192,7 +1192,7 @@ static snd_kcontrol_new_t snd_emu10k1x_spdif_mask_control =
 
 static snd_kcontrol_new_t snd_emu10k1x_spdif_control =
 {
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
        .count =        3,
        .info =         snd_emu10k1x_spdif_info,
index 0529fb281125cf949d2de4ebd2163fbe71fb9d67..637c555cfdb1f42b4a3be06e98dc806fe20ff839 100644 (file)
@@ -1159,12 +1159,12 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
        /* Optical SPDIF Playback Volume */
        A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L);
        A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
-       snd_emu10k1_init_stereo_control(&controls[nctl++], "IEC958 Optical Playback Volume", gpr, 0);
+       snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0);
        gpr += 2;
        /* Optical SPDIF Capture Volume */
        A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L);
        A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
-       snd_emu10k1_init_stereo_control(&controls[nctl++], "IEC958 Optical Capture Volume", gpr, 0);
+       snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0);
        gpr += 2;
 
        /* Line2 Playback Volume */
@@ -1389,7 +1389,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
                        A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
                }
        }
-       snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "IEC958 Optical Raw Playback Switch", gpr, 0);
+       snd_emu10k1_init_stereo_onoff_control(controls + nctl++, SNDRV_CTL_NAME_IEC958("Optical Raw ",PLAYBACK,SWITCH), gpr, 0);
        gpr += 2;
        
        A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
@@ -1716,7 +1716,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
                /* IEC958 TTL Playback Volume */
                for (z = 0; z < 2; z++)
                        VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_SPDIF_CD_L + z, gpr + z);
-               snd_emu10k1_init_stereo_control(controls + i++, "IEC958 TTL Playback Volume", gpr, 0);
+               snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",PLAYBACK,VOLUME), gpr, 0);
                gpr += 2;
        
                /* IEC958 TTL Capture Volume + Switch */
@@ -1724,8 +1724,8 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
                        SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_SPDIF_CD_L + z, gpr + 2 + z);
                        VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
                }
-               snd_emu10k1_init_stereo_control(controls + i++, "IEC958 TTL Capture Volume", gpr, 0);
-               snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 TTL Capture Switch", gpr + 2, 0);
+               snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,VOLUME), gpr, 0);
+               snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,SWITCH), gpr + 2, 0);
                gpr += 4;
        }
        
@@ -1750,7 +1750,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
                /* IEC958 Optical Playback Volume */
                for (z = 0; z < 2; z++)
                        VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_TOSLINK_L + z, gpr + z);
-               snd_emu10k1_init_stereo_control(controls + i++, "IEC958 LiveDrive Playback Volume", gpr, 0);
+               snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",PLAYBACK,VOLUME), gpr, 0);
                gpr += 2;
        
                /* IEC958 Optical Capture Volume */
@@ -1758,8 +1758,8 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
                        SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_TOSLINK_L + z, gpr + 2 + z);
                        VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
                }
-               snd_emu10k1_init_stereo_control(controls + i++, "IEC958 LiveDrive Capture Volume", gpr, 0);
-               snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 LiveDrive Capture Switch", gpr + 2, 0);
+               snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,VOLUME), gpr, 0);
+               snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,SWITCH), gpr + 2, 0);
                gpr += 4;
        }
        
@@ -1784,7 +1784,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
                /* IEC958 Coax Playback Volume */
                for (z = 0; z < 2; z++)
                        VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_COAX_SPDIF_L + z, gpr + z);
-               snd_emu10k1_init_stereo_control(controls + i++, "IEC958 Coaxial Playback Volume", gpr, 0);
+               snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",PLAYBACK,VOLUME), gpr, 0);
                gpr += 2;
        
                /* IEC958 Coax Capture Volume + Switch */
@@ -1792,8 +1792,8 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
                        SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_COAX_SPDIF_L + z, gpr + 2 + z);
                        VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
                }
-               snd_emu10k1_init_stereo_control(controls + i++, "IEC958 Coaxial Capture Volume", gpr, 0);
-               snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 Coaxial Capture Switch", gpr + 2, 0);
+               snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,VOLUME), gpr, 0);
+               snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,SWITCH), gpr + 2, 0);
                gpr += 4;
        }
        
@@ -1920,7 +1920,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
 #endif
                }
 
-               snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 Optical Raw Playback Switch", gpr, 0);
+               snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("Optical Raw ",PLAYBACK,SWITCH), gpr, 0);
                gpr += 2;
        }
 
index 6be82c5fe138089363749889afbda70fa118b8fe..d71a72e84bcc9181a7c2f23c31b14fd864c9cfe9 100644 (file)
@@ -181,7 +181,7 @@ static int snd_emu10k1_spdif_put(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_emu10k1_spdif_mask_control =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
        .count =        4,
        .info =         snd_emu10k1_spdif_info,
@@ -190,7 +190,7 @@ static snd_kcontrol_new_t snd_emu10k1_spdif_mask_control =
 
 static snd_kcontrol_new_t snd_emu10k1_spdif_control =
 {
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
        .count =        4,
        .info =         snd_emu10k1_spdif_info,
@@ -295,7 +295,7 @@ static int snd_emu10k1_send_routing_put(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_emu10k1_send_routing_control =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         "EMU10K1 PCM Send Routing",
        .count =        32,
        .info =         snd_emu10k1_send_routing_info,
@@ -364,7 +364,7 @@ static int snd_emu10k1_send_volume_put(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_emu10k1_send_volume_control =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         "EMU10K1 PCM Send Volume",
        .count =        32,
        .info =         snd_emu10k1_send_volume_info,
@@ -427,7 +427,7 @@ static int snd_emu10k1_attn_put(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_emu10k1_attn_control =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         "EMU10K1 PCM Volume",
        .count =        32,
        .info =         snd_emu10k1_attn_info,
@@ -737,7 +737,8 @@ static int rename_ctl(snd_card_t *card, const char *src, const char *dst)
        return -ENOENT;
 }
 
-int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
+int __devinit snd_emu10k1_mixer(emu10k1_t *emu,
+                               int pcm_device, int multi_device)
 {
        int err, pcm;
        snd_kcontrol_t *kctl;
@@ -852,29 +853,35 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
 
        if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL)
                return -ENOMEM;
+       kctl->id.device = pcm_device;
        if ((err = snd_ctl_add(card, kctl)))
                return err;
        if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL)
                return -ENOMEM;
+       kctl->id.device = pcm_device;
        if ((err = snd_ctl_add(card, kctl)))
                return err;
        if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL)
                return -ENOMEM;
+       kctl->id.device = pcm_device;
        if ((err = snd_ctl_add(card, kctl)))
                return err;
 
        if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL)
                return -ENOMEM;
+       kctl->id.device = multi_device;
        if ((err = snd_ctl_add(card, kctl)))
                return err;
        
        if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL)
                return -ENOMEM;
+       kctl->id.device = multi_device;
        if ((err = snd_ctl_add(card, kctl)))
                return err;
        
        if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL)
                return -ENOMEM;
+       kctl->id.device = multi_device;
        if ((err = snd_ctl_add(card, kctl)))
                return err;
 
@@ -924,10 +931,14 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
                /* sb live! and audigy */
                if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
                        return -ENOMEM;
+               if (!emu->audigy)
+                       kctl->id.device = emu->pcm_efx->device;
                if ((err = snd_ctl_add(card, kctl)))
                        return err;
                if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
                        return -ENOMEM;
+               if (!emu->audigy)
+                       kctl->id.device = emu->pcm_efx->device;
                if ((err = snd_ctl_add(card, kctl)))
                        return err;
        }
index 520b99af5f550d0429ef030c8c90c0d8027c0171..9c35f6dde1b5a49ccbb4f73f44ac723a21315b77 100644 (file)
@@ -1682,6 +1682,7 @@ static void snd_emu10k1_pcm_efx_free(snd_pcm_t *pcm)
 int __devinit snd_emu10k1_pcm_efx(emu10k1_t * emu, int device, snd_pcm_t ** rpcm)
 {
        snd_pcm_t *pcm;
+       snd_kcontrol_t *kctl;
        int err;
 
        if (rpcm)
@@ -1714,7 +1715,11 @@ int __devinit snd_emu10k1_pcm_efx(emu10k1_t * emu, int device, snd_pcm_t ** rpcm
                emu->efx_voices_mask[0] = 0xffff0000;
                emu->efx_voices_mask[1] = 0;
        }
-       snd_ctl_add(emu->card, snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu));
+       kctl = snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu);
+       if (!kctl)
+               return -ENOMEM;
+       kctl->id.device = device;
+       snd_ctl_add(emu->card, kctl);
 
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);
 
index 78a81f3912a1ac35c756d2bfb992d6101bde6533..f06b95f41a1de5daa5e73fad55d9b7d7829bd271 100644 (file)
@@ -1444,7 +1444,7 @@ static int snd_es1371_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
 
 /* spdif controls */
 static snd_kcontrol_new_t snd_es1371_mixer_spdif[] __devinitdata = {
-       ES1371_SPDIF("IEC958 Playback Switch"),
+       ES1371_SPDIF(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH)),
        {
                .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
                .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
index ff10e637a95e0ffb1b5d2882e59765ea1b557efb..36b2f62e857385ace4b567b846ac31edd4b0c679 100644 (file)
@@ -1155,10 +1155,10 @@ FM801_SINGLE("FM Playback Switch", FM801_FM_VOL, 15, 1, 1),
 static snd_kcontrol_new_t snd_fm801_controls_multi[] __devinitdata = {
 FM801_SINGLE("AC97 2ch->4ch Copy Switch", FM801_CODEC_CTRL, 7, 1, 0),
 FM801_SINGLE("AC97 18-bit Switch", FM801_CODEC_CTRL, 10, 1, 0),
-FM801_SINGLE("IEC958 Capture Switch", FM801_I2S_MODE, 8, 1, 0),
-FM801_SINGLE("IEC958 Raw Data Playback Switch", FM801_I2S_MODE, 9, 1, 0),
-FM801_SINGLE("IEC958 Raw Data Capture Switch", FM801_I2S_MODE, 10, 1, 0),
-FM801_SINGLE("IEC958 Playback Switch", FM801_GEN_CTRL, 2, 1, 0),
+FM801_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), FM801_I2S_MODE, 8, 1, 0),
+FM801_SINGLE(SNDRV_CTL_NAME_IEC958("Raw Data ",PLAYBACK,SWITCH), FM801_I2S_MODE, 9, 1, 0),
+FM801_SINGLE(SNDRV_CTL_NAME_IEC958("Raw Data ",CAPTURE,SWITCH), FM801_I2S_MODE, 10, 1, 0),
+FM801_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), FM801_GEN_CTRL, 2, 1, 0),
 };
 
 static void snd_fm801_mixer_free_ac97_bus(ac97_bus_t *bus)
index bd8cb33c4fb492fa4d2a198b3cfbe60b6983d96f..ddfb5ff7fb8f804fd6b24af953364c4bede877fd 100644 (file)
@@ -1,5 +1,5 @@
 snd-hda-intel-objs := hda_intel.o
-snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o
+snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o
 ifdef CONFIG_PROC_FS
 snd-hda-codec-objs += hda_proc.o
 endif
index e2cf0238728925bef2183adeb72bf9cb8abadb1b..20f7762f714444a8ed5e516977cb0ac4bd4487bd 100644 (file)
@@ -432,22 +432,26 @@ void snd_hda_get_codec_name(struct hda_codec *codec,
 }
 
 /*
- * look for an AFG node
- *
- * return 0 if not found
+ * look for an AFG and MFG nodes
  */
-static int look_for_afg_node(struct hda_codec *codec)
+static void setup_fg_nodes(struct hda_codec *codec)
 {
        int i, total_nodes;
        hda_nid_t nid;
 
        total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid);
        for (i = 0; i < total_nodes; i++, nid++) {
-               if ((snd_hda_param_read(codec, nid, AC_PAR_FUNCTION_TYPE) & 0xff) ==
-                   AC_GRP_AUDIO_FUNCTION)
-                       return nid;
+               switch((snd_hda_param_read(codec, nid, AC_PAR_FUNCTION_TYPE) & 0xff)) {
+               case AC_GRP_AUDIO_FUNCTION:
+                       codec->afg = nid;
+                       break;
+               case AC_GRP_MODEM_FUNCTION:
+                       codec->mfg = nid;
+                       break;
+               default:
+                       break;
+               }
        }
-       return 0;
 }
 
 /*
@@ -507,10 +511,9 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
        codec->subsystem_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_SUBSYSTEM_ID);
        codec->revision_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_REV_ID);
 
-       /* FIXME: support for multiple AFGs? */
-       codec->afg = look_for_afg_node(codec);
-       if (! codec->afg) {
-               snd_printdd("hda_codec: no AFG node found\n");
+       setup_fg_nodes(codec);
+       if (! codec->afg && ! codec->mfg) {
+               snd_printdd("hda_codec: no AFG or MFG node found\n");
                snd_hda_codec_free(codec);
                return -ENODEV;
        }
@@ -749,12 +752,14 @@ int snd_hda_mixer_amp_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
        long *valp = ucontrol->value.integer.value;
        int change = 0;
 
-       if (chs & 1)
+       if (chs & 1) {
                change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
                                                  0x7f, *valp);
+               valp++;
+       }
        if (chs & 2)
                change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
-                                                  0x7f, valp[1]);
+                                                  0x7f, *valp);
        return change;
 }
 
@@ -796,12 +801,15 @@ int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
        long *valp = ucontrol->value.integer.value;
        int change = 0;
 
-       if (chs & 1)
+       if (chs & 1) {
                change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
                                                  0x80, *valp ? 0 : 0x80);
+               valp++;
+       }
        if (chs & 2)
                change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
-                                                  0x80, valp[1] ? 0 : 0x80);
+                                                  0x80, *valp ? 0 : 0x80);
+       
        return change;
 }
 
@@ -1155,8 +1163,16 @@ int snd_hda_build_controls(struct hda_bus *bus)
 /*
  * stream formats
  */
-static unsigned int rate_bits[][3] = {
+struct hda_rate_tbl {
+       unsigned int hz;
+       unsigned int alsa_bits;
+       unsigned int hda_fmt;
+};
+
+static struct hda_rate_tbl rate_bits[] = {
        /* rate in Hz, ALSA rate bitmask, HDA format value */
+
+       /* autodetected value used in snd_hda_query_supported_pcm */
        { 8000, SNDRV_PCM_RATE_8000, 0x0500 }, /* 1/6 x 48 */
        { 11025, SNDRV_PCM_RATE_11025, 0x4300 }, /* 1/4 x 44 */
        { 16000, SNDRV_PCM_RATE_16000, 0x0200 }, /* 1/3 x 48 */
@@ -1168,7 +1184,11 @@ static unsigned int rate_bits[][3] = {
        { 96000, SNDRV_PCM_RATE_96000, 0x0800 }, /* 2 x 48 */
        { 176400, SNDRV_PCM_RATE_176400, 0x5800 },/* 4 x 44 */
        { 192000, SNDRV_PCM_RATE_192000, 0x1800 }, /* 4 x 48 */
-       { 0 }
+
+       /* not autodetected value */
+       { 9600, SNDRV_PCM_RATE_KNOT, 0x0400 }, /* 1/5 x 48 */
+
+       { 0 } /* terminator */
 };
 
 /**
@@ -1190,12 +1210,12 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
        int i;
        unsigned int val = 0;
 
-       for (i = 0; rate_bits[i][0]; i++)
-               if (rate_bits[i][0] == rate) {
-                       val = rate_bits[i][2];
+       for (i = 0; rate_bits[i].hz; i++)
+               if (rate_bits[i].hz == rate) {
+                       val = rate_bits[i].hda_fmt;
                        break;
                }
-       if (! rate_bits[i][0]) {
+       if (! rate_bits[i].hz) {
                snd_printdd("invalid rate %d\n", rate);
                return 0;
        }
@@ -1258,9 +1278,9 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
 
        if (ratesp) {
                u32 rates = 0;
-               for (i = 0; rate_bits[i][0]; i++) {
+               for (i = 0; rate_bits[i].hz; i++) {
                        if (val & (1 << i))
-                               rates |= rate_bits[i][1];
+                               rates |= rate_bits[i].alsa_bits;
                }
                *ratesp = rates;
        }
@@ -1352,13 +1372,13 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
        }
 
        rate = format & 0xff00;
-       for (i = 0; rate_bits[i][0]; i++)
-               if (rate_bits[i][2] == rate) {
+       for (i = 0; rate_bits[i].hz; i++)
+               if (rate_bits[i].hda_fmt == rate) {
                        if (val & (1 << i))
                                break;
                        return 0;
                }
-       if (! rate_bits[i][0])
+       if (! rate_bits[i].hz)
                return 0;
 
        stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
@@ -1541,8 +1561,11 @@ int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_c
                for (c = tbl; c->modelname || c->pci_subvendor; c++) {
                        if (c->pci_subvendor == subsystem_vendor &&
                            (! c->pci_subdevice /* all match */||
-                            (c->pci_subdevice == subsystem_device)))
+                            (c->pci_subdevice == subsystem_device))) {
+                               snd_printdd(KERN_INFO "hda_codec: PCI %x:%x, codec config %d is selected\n",
+                                           subsystem_vendor, subsystem_device, c->config);
                                return c->config;
+                       }
                }
        }
        return -1;
@@ -1803,11 +1826,25 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c
                                cfg->line_out_pins[j] = nid;
                        }
 
-       /* Swap surround and CLFE: the association order is front/CLFE/surr/back */
-       if (cfg->line_outs >= 3) {
+       /* Reorder the surround channels
+        * ALSA sequence is front/surr/clfe/side
+        * HDA sequence is:
+        *    4-ch: front/surr  =>  OK as it is
+        *    6-ch: front/clfe/surr
+        *    8-ch: front/clfe/side/surr
+        */
+       switch (cfg->line_outs) {
+       case 3:
                nid = cfg->line_out_pins[1];
                cfg->line_out_pins[1] = cfg->line_out_pins[2];
                cfg->line_out_pins[2] = nid;
+               break;
+       case 4:
+               nid = cfg->line_out_pins[1];
+               cfg->line_out_pins[1] = cfg->line_out_pins[3];
+               cfg->line_out_pins[3] = cfg->line_out_pins[2];
+               cfg->line_out_pins[2] = nid;
+               break;
        }
 
        return 0;
index dd0d99d2ad2724e937337c4e79720362fab11436..63a29a8a2860e34e092f852f92e86b81511abc65 100644 (file)
@@ -514,6 +514,7 @@ struct hda_codec {
        struct list_head list;  /* list point */
 
        hda_nid_t afg;  /* AFG node id */
+       hda_nid_t mfg;  /* MFG node id */
 
        /* ids */
        u32 vendor_id;
index 2d046abb591108bc9033be2f5ce16b6a4ab95c6b..1229227af5b5f4c98bfa2e1a998817cfb27c5471 100644 (file)
@@ -881,6 +881,11 @@ int snd_hda_parse_generic_codec(struct hda_codec *codec)
        struct hda_gspec *spec;
        int err;
 
+       if(!codec->afg) {
+               snd_printdd("hda_generic: no generic modem yet\n");
+               return -ENODEV;
+       }
+
        spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
        if (spec == NULL) {
                printk(KERN_ERR "hda_generic: can't allocate spec\n");
index 288ab07648305576a4f2b754c6102e55a76502f5..15107df1f490808ebc52dfc5e1a977ee7dc83d08 100644 (file)
@@ -71,7 +71,9 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
                         "{Intel, ESB2},"
                         "{ATI, SB450},"
                         "{VIA, VT8251},"
-                        "{VIA, VT8237A}}");
+                        "{VIA, VT8237A},"
+                        "{SiS, SIS966},"
+                        "{ULI, M5461}}");
 MODULE_DESCRIPTION("Intel HDA driver");
 
 #define SFX    "hda-intel: "
@@ -141,9 +143,24 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
  */
 
 /* max number of SDs */
-#define MAX_ICH6_DEV           8
+/* ICH, ATI and VIA have 4 playback and 4 capture */
+#define ICH6_CAPTURE_INDEX     0
+#define ICH6_NUM_CAPTURE       4
+#define ICH6_PLAYBACK_INDEX    4
+#define ICH6_NUM_PLAYBACK      4
+
+/* ULI has 6 playback and 5 capture */
+#define ULI_CAPTURE_INDEX      0
+#define ULI_NUM_CAPTURE                5
+#define ULI_PLAYBACK_INDEX     5
+#define ULI_NUM_PLAYBACK       6
+
+/* this number is statically defined for simplicity */
+#define MAX_AZX_DEV            16
+
 /* max number of fragments - we may use more if allocating more pages for BDL */
-#define AZX_MAX_FRAG           (PAGE_SIZE / (MAX_ICH6_DEV * 16))
+#define BDL_SIZE               PAGE_ALIGN(8192)
+#define AZX_MAX_FRAG           (BDL_SIZE / (MAX_AZX_DEV * 16))
 /* max buffer size - no h/w limit, you can increase as you like */
 #define AZX_MAX_BUF_SIZE       (1024*1024*1024)
 /* max number of PCM devics per card */
@@ -200,7 +217,6 @@ enum {
 };
 
 /* Defines for ATI HD Audio support in SB450 south bridge */
-#define ATI_SB450_HDAUDIO_PCI_DEVICE_ID     0x437b
 #define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR   0x42
 #define ATI_SB450_HDAUDIO_ENABLE_SNOOP      0x02
 
@@ -258,6 +274,14 @@ struct snd_azx {
        snd_card_t *card;
        struct pci_dev *pci;
 
+       /* chip type specific */
+       int driver_type;
+       int playback_streams;
+       int playback_index_offset;
+       int capture_streams;
+       int capture_index_offset;
+       int num_streams;
+
        /* pci resources */
        unsigned long addr;
        void __iomem *remap_addr;
@@ -267,8 +291,8 @@ struct snd_azx {
        spinlock_t reg_lock;
        struct semaphore open_mutex;
 
-       /* streams */
-       azx_dev_t azx_dev[MAX_ICH6_DEV];
+       /* streams (x num_streams) */
+       azx_dev_t *azx_dev;
 
        /* PCM */
        unsigned int pcm_devs;
@@ -292,6 +316,23 @@ struct snd_azx {
        unsigned int initialized: 1;
 };
 
+/* driver types */
+enum {
+       AZX_DRIVER_ICH,
+       AZX_DRIVER_ATI,
+       AZX_DRIVER_VIA,
+       AZX_DRIVER_SIS,
+       AZX_DRIVER_ULI,
+};
+
+static char *driver_short_names[] __devinitdata = {
+       [AZX_DRIVER_ICH] = "HDA Intel",
+       [AZX_DRIVER_ATI] = "HDA ATI SB",
+       [AZX_DRIVER_VIA] = "HDA VIA VT82xx",
+       [AZX_DRIVER_SIS] = "HDA SIS966",
+       [AZX_DRIVER_ULI] = "HDA ULI M5461"
+};
+
 /*
  * macros for easy use
  */
@@ -360,6 +401,8 @@ static void azx_init_cmd_io(azx_t *chip)
        azx_writel(chip, CORBLBASE, (u32)chip->corb.addr);
        azx_writel(chip, CORBUBASE, upper_32bit(chip->corb.addr));
 
+       /* set the corb size to 256 entries (ULI requires explicitly) */
+       azx_writeb(chip, CORBSIZE, 0x02);
        /* set the corb write pointer to 0 */
        azx_writew(chip, CORBWP, 0);
        /* reset the corb hw read pointer */
@@ -373,6 +416,8 @@ static void azx_init_cmd_io(azx_t *chip)
        azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
        azx_writel(chip, RIRBUBASE, upper_32bit(chip->rirb.addr));
 
+       /* set the rirb size to 256 entries (ULI requires explicitly) */
+       azx_writeb(chip, RIRBSIZE, 0x02);
        /* reset the rirb hw write pointer */
        azx_writew(chip, RIRBWP, ICH6_RBRWP_CLR);
        /* set N=1, get RIRB response interrupt for new entry */
@@ -596,7 +641,7 @@ static void azx_int_disable(azx_t *chip)
        int i;
 
        /* disable interrupts in stream descriptor */
-       for (i = 0; i < MAX_ICH6_DEV; i++) {
+       for (i = 0; i < chip->num_streams; i++) {
                azx_dev_t *azx_dev = &chip->azx_dev[i];
                azx_sd_writeb(azx_dev, SD_CTL,
                              azx_sd_readb(azx_dev, SD_CTL) & ~SD_INT_MASK);
@@ -616,7 +661,7 @@ static void azx_int_clear(azx_t *chip)
        int i;
 
        /* clear stream status */
-       for (i = 0; i < MAX_ICH6_DEV; i++) {
+       for (i = 0; i < chip->num_streams; i++) {
                azx_dev_t *azx_dev = &chip->azx_dev[i];
                azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
        }
@@ -686,8 +731,7 @@ static void azx_init_chip(azx_t *chip)
        }
 
        /* For ATI SB450 azalia HD audio, we need to enable snoop */
-       if (chip->pci->vendor == PCI_VENDOR_ID_ATI && 
-           chip->pci->device == ATI_SB450_HDAUDIO_PCI_DEVICE_ID) {
+       if (chip->driver_type == AZX_DRIVER_ATI) {
                pci_read_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 
                                     &ati_misc_cntl2);
                pci_write_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 
@@ -714,7 +758,7 @@ static irqreturn_t azx_interrupt(int irq, void* dev_id, struct pt_regs *regs)
                return IRQ_NONE;
        }
        
-       for (i = 0; i < MAX_ICH6_DEV; i++) {
+       for (i = 0; i < chip->num_streams; i++) {
                azx_dev = &chip->azx_dev[i];
                if (status & azx_dev->sd_int_sta_mask) {
                        azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
@@ -879,9 +923,15 @@ static int __devinit azx_codec_create(azx_t *chip, const char *model)
 /* assign a stream for the PCM */
 static inline azx_dev_t *azx_assign_device(azx_t *chip, int stream)
 {
-       int dev, i;
-       dev = stream == SNDRV_PCM_STREAM_PLAYBACK ? 4 : 0;
-       for (i = 0; i < 4; i++, dev++)
+       int dev, i, nums;
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               dev = chip->playback_index_offset;
+               nums = chip->playback_streams;
+       } else {
+               dev = chip->capture_index_offset;
+               nums = chip->capture_streams;
+       }
+       for (i = 0; i < nums; i++, dev++)
                if (! chip->azx_dev[dev].opened) {
                        chip->azx_dev[dev].opened = 1;
                        return &chip->azx_dev[dev];
@@ -899,8 +949,8 @@ static snd_pcm_hardware_t azx_pcm_hw = {
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID |
-                                SNDRV_PCM_INFO_PAUSE |
-                                SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_PAUSE /*|*/
+                                /*SNDRV_PCM_INFO_RESUME*/),
        .formats =              SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                SNDRV_PCM_RATE_48000,
        .rate_min =             48000,
@@ -1049,6 +1099,7 @@ static int azx_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
                azx_dev->running = 1;
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_STOP:
                azx_stream_stop(chip, azx_dev);
                azx_dev->running = 0;
@@ -1058,6 +1109,7 @@ static int azx_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
        }
        spin_unlock(&chip->reg_lock);
        if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH ||
+           cmd == SNDRV_PCM_TRIGGER_SUSPEND ||
            cmd == SNDRV_PCM_TRIGGER_STOP) {
                int timeout = 5000;
                while (azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START && --timeout)
@@ -1136,6 +1188,7 @@ static int __devinit create_codec_pcm(azx_t *chip, struct hda_codec *codec,
                                              snd_dma_pci_data(chip->pci),
                                              1024 * 64, 1024 * 128);
        chip->pcm[pcm_dev] = pcm;
+       chip->pcm_devs = pcm_dev + 1;
 
        return 0;
 }
@@ -1186,7 +1239,7 @@ static int __devinit azx_init_stream(azx_t *chip)
        /* initialize each stream (aka device)
         * assign the starting bdl address to each stream (device) and initialize
         */
-       for (i = 0; i < MAX_ICH6_DEV; i++) {
+       for (i = 0; i < chip->num_streams; i++) {
                unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4);
                azx_dev_t *azx_dev = &chip->azx_dev[i];
                azx_dev->bdl = (u32 *)(chip->bdl.area + off);
@@ -1245,7 +1298,7 @@ static int azx_free(azx_t *chip)
        if (chip->initialized) {
                int i;
 
-               for (i = 0; i < MAX_ICH6_DEV; i++)
+               for (i = 0; i < chip->num_streams; i++)
                        azx_stream_stop(chip, &chip->azx_dev[i]);
 
                /* disable interrupts */
@@ -1261,10 +1314,10 @@ static int azx_free(azx_t *chip)
 
                /* wait a little for interrupts to finish */
                msleep(1);
-
-               iounmap(chip->remap_addr);
        }
 
+       if (chip->remap_addr)
+               iounmap(chip->remap_addr);
        if (chip->irq >= 0)
                free_irq(chip->irq, (void*)chip);
 
@@ -1276,6 +1329,7 @@ static int azx_free(azx_t *chip)
                snd_dma_free_pages(&chip->posbuf);
        pci_release_regions(chip->pci);
        pci_disable_device(chip->pci);
+       kfree(chip->azx_dev);
        kfree(chip);
 
        return 0;
@@ -1290,7 +1344,8 @@ static int azx_dev_free(snd_device_t *device)
  * constructor
  */
 static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
-                               int posfix, azx_t **rchip)
+                               int posfix, int driver_type,
+                               azx_t **rchip)
 {
        azx_t *chip;
        int err = 0;
@@ -1316,9 +1371,20 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
        chip->card = card;
        chip->pci = pci;
        chip->irq = -1;
+       chip->driver_type = driver_type;
 
        chip->position_fix = posfix;
 
+#if BITS_PER_LONG != 64
+       /* Fix up base address on ULI M5461 */
+       if (chip->driver_type == AZX_DRIVER_ULI) {
+               u16 tmp3;
+               pci_read_config_word(pci, 0x40, &tmp3);
+               pci_write_config_word(pci, 0x40, tmp3 | 0x10);
+               pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, 0);
+       }
+#endif
+
        if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) {
                kfree(chip);
                pci_disable_device(pci);
@@ -1344,16 +1410,37 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
        pci_set_master(pci);
        synchronize_irq(chip->irq);
 
+       switch (chip->driver_type) {
+       case AZX_DRIVER_ULI:
+               chip->playback_streams = ULI_NUM_PLAYBACK;
+               chip->capture_streams = ULI_NUM_CAPTURE;
+               chip->playback_index_offset = ULI_PLAYBACK_INDEX;
+               chip->capture_index_offset = ULI_CAPTURE_INDEX;
+               break;
+       default:
+               chip->playback_streams = ICH6_NUM_PLAYBACK;
+               chip->capture_streams = ICH6_NUM_CAPTURE;
+               chip->playback_index_offset = ICH6_PLAYBACK_INDEX;
+               chip->capture_index_offset = ICH6_CAPTURE_INDEX;
+               break;
+       }
+       chip->num_streams = chip->playback_streams + chip->capture_streams;
+       chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL);
+       if (! chip->azx_dev) {
+               snd_printk(KERN_ERR "cannot malloc azx_dev\n");
+               goto errout;
+       }
+
        /* allocate memory for the BDL for each stream */
        if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
-                                      PAGE_SIZE, &chip->bdl)) < 0) {
+                                      BDL_SIZE, &chip->bdl)) < 0) {
                snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
                goto errout;
        }
        if (chip->position_fix == POS_FIX_POSBUF) {
                /* allocate memory for the position buffer */
                if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
-                                              MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) {
+                                              chip->num_streams * 8, &chip->posbuf)) < 0) {
                        snd_printk(KERN_ERR SFX "cannot allocate posbuf\n");
                        goto errout;
                }
@@ -1382,6 +1469,10 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
                goto errout;
        }
 
+       strcpy(card->driver, "HDA-Intel");
+       strcpy(card->shortname, driver_short_names[chip->driver_type]);
+       sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq);
+
        *rchip = chip;
        return 0;
 
@@ -1410,15 +1501,12 @@ static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *
                return -ENOMEM;
        }
 
-       if ((err = azx_create(card, pci, position_fix[dev], &chip)) < 0) {
+       if ((err = azx_create(card, pci, position_fix[dev], pci_id->driver_data,
+                             &chip)) < 0) {
                snd_card_free(card);
                return err;
        }
 
-       strcpy(card->driver, "HDA-Intel");
-       strcpy(card->shortname, "HDA Intel");
-       sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq);
-
        /* create codec instances */
        if ((err = azx_codec_create(chip, model[dev])) < 0) {
                snd_card_free(card);
@@ -1459,12 +1547,13 @@ static void __devexit azx_remove(struct pci_dev *pci)
 
 /* PCI IDs */
 static struct pci_device_id azx_ids[] = {
-       { 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH6 */
-       { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH7 */
-       { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */
-       { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ATI SB450 */
-       { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* VIA VT8251/VT8237A */
-       { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ALI 5461? */
+       { 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH6 */
+       { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH7 */
+       { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ESB2 */
+       { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
+       { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */
+       { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */
+       { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);
index a5de684b69446a6c958324ba566d91794f5313a9..acaef3c811b8c4791271f2250603d8cce6160e32 100644 (file)
@@ -10,11 +10,14 @@ extern struct hda_codec_preset snd_hda_preset_cmedia[];
 extern struct hda_codec_preset snd_hda_preset_analog[];
 /* SigmaTel codecs */
 extern struct hda_codec_preset snd_hda_preset_sigmatel[];
+/* SiLabs 3054/3055 modem codecs */
+extern struct hda_codec_preset snd_hda_preset_si3054[];
 
 static const struct hda_codec_preset *hda_preset_tables[] = {
        snd_hda_preset_realtek,
        snd_hda_preset_cmedia,
        snd_hda_preset_analog,
        snd_hda_preset_sigmatel,
+       snd_hda_preset_si3054,
        NULL
 };
index 2fd05bb841365ee67ebc5f8639307e133c4e0d0a..bceb83a42a38d50705c8eeb91d6af1e72df63013 100644 (file)
@@ -572,7 +572,7 @@ static snd_kcontrol_new_t ad1983_mixers[] = {
        },
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "IEC958 Playback Route",
+               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
                .info = ad1983_spdif_route_info,
                .get = ad1983_spdif_route_get,
                .put = ad1983_spdif_route_put,
@@ -705,7 +705,7 @@ static snd_kcontrol_new_t ad1981_mixers[] = {
        /* identical with AD1983 */
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "IEC958 Playback Route",
+               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
                .info = ad1983_spdif_route_info,
                .get = ad1983_spdif_route_get,
                .put = ad1983_spdif_route_put,
index 86f195f19eef0e64a9d12ffb7dd11f06ded9223c..07fb4f5a54b36558c65575acf630ec6951f5b559 100644 (file)
@@ -647,6 +647,7 @@ static struct hda_board_config cmi9880_cfg_tbl[] = {
        { .modelname = "min_fp", .config = CMI_MIN_FP },
        { .modelname = "full", .config = CMI_FULL },
        { .modelname = "full_dig", .config = CMI_FULL_DIG },
+       { .pci_subvendor = 0x1043, .pci_subdevice = 0x813d, .config = CMI_FULL_DIG }, /* ASUS P5AD2 */
        { .modelname = "allout", .config = CMI_ALLOUT },
        { .modelname = "auto", .config = CMI_AUTO },
        {} /* terminator */
index 9b85699007872a9edc91a2124388ac22ba1d3140..eeb900ab79afdbb677e255a96b0fa62f3308d27e 100644 (file)
@@ -687,6 +687,12 @@ static snd_kcontrol_new_t alc880_asus_w1v_mixer[] = {
        { } /* end */
 };
 
+/* additional mixers to alc880_asus_mixer */
+static snd_kcontrol_new_t alc880_pcbeep_mixer[] = {
+       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+       { } /* end */
+};
 
 /*
  * build control elements
@@ -1524,6 +1530,7 @@ static struct hda_board_config alc880_cfg_tbl[] = {
        /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */
        { .modelname = "3stack-digout", .config = ALC880_3ST_DIG },
        { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG },
+       { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG },
 
        /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/
        { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG },
@@ -1734,7 +1741,7 @@ static struct alc_config_preset alc880_presets[] = {
                .input_mux = &alc880_capture_source,
        },
        [ALC880_UNIWILL_DIG] = {
-               .mixers = { alc880_asus_mixer },
+               .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
                .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs },
                .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
                .dac_nids = alc880_asus_dac_nids,
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
new file mode 100644 (file)
index 0000000..b0270d1
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for Silicon Labs 3054/5 modem codec
+ *
+ * Copyright (c) 2005 Sasha Khapyorsky <sashak@smlink.com>
+ *                    Takashi Iwai <tiwai@suse.de>
+ *
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This driver 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 <sound/driver.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+
+/* si3054 verbs */
+#define SI3054_VERB_READ_NODE  0x900
+#define SI3054_VERB_WRITE_NODE 0x100
+
+/* si3054 nodes (registers) */
+#define SI3054_EXTENDED_MID    2
+#define SI3054_LINE_RATE       3
+#define SI3054_LINE_LEVEL      4
+#define SI3054_GPIO_CFG        5
+#define SI3054_GPIO_POLARITY   6
+#define SI3054_GPIO_STICKY     7
+#define SI3054_GPIO_WAKEUP     8
+#define SI3054_GPIO_STATUS     9
+#define SI3054_GPIO_CONTROL   10
+#define SI3054_MISC_AFE       11
+#define SI3054_CHIPID         12
+#define SI3054_LINE_CFG1      13
+#define SI3054_LINE_STATUS    14
+#define SI3054_DC_TERMINATION 15
+#define SI3054_LINE_CONFIG    16
+#define SI3054_CALLPROG_ATT   17
+#define SI3054_SQ_CONTROL     18
+#define SI3054_MISC_CONTROL   19
+#define SI3054_RING_CTRL1     20
+#define SI3054_RING_CTRL2     21
+
+/* extended MID */
+#define SI3054_MEI_READY 0xf
+
+/* line level */
+#define SI3054_ATAG_MASK 0x00f0
+#define SI3054_DTAG_MASK 0xf000
+
+/* GPIO bits */
+#define SI3054_GPIO_OH    0x0001
+#define SI3054_GPIO_CID   0x0002
+
+/* chipid and revisions */
+#define SI3054_CHIPID_CODEC_REV_MASK 0x000f
+#define SI3054_CHIPID_DAA_REV_MASK   0x00f0
+#define SI3054_CHIPID_INTERNATIONAL  0x0100
+#define SI3054_CHIPID_DAA_ID         0x0f00
+#define SI3054_CHIPID_CODEC_ID      (1<<12)
+
+/* si3054 codec registers (nodes) access macros */
+#define GET_REG(codec,reg) (snd_hda_codec_read(codec,reg,0,SI3054_VERB_READ_NODE,0))
+#define SET_REG(codec,reg,val) (snd_hda_codec_write(codec,reg,0,SI3054_VERB_WRITE_NODE,val))
+
+
+struct si3054_spec {
+       unsigned international;
+       struct hda_pcm pcm;
+};
+
+
+/*
+ * Modem mixer
+ */
+
+#define PRIVATE_VALUE(reg,mask) ((reg<<16)|(mask&0xffff))
+#define PRIVATE_REG(val) ((val>>16)&0xffff)
+#define PRIVATE_MASK(val) (val&0xffff)
+
+static int si3054_switch_info(snd_kcontrol_t *kcontrol,
+                              snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int si3054_switch_get(snd_kcontrol_t *kcontrol,
+                              snd_ctl_elem_value_t *uvalue)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       u16 reg  = PRIVATE_REG(kcontrol->private_value);
+       u16 mask = PRIVATE_MASK(kcontrol->private_value);
+       uvalue->value.integer.value[0] = (GET_REG(codec, reg)) & mask ? 1 : 0 ;
+       return 0;
+}
+
+static int si3054_switch_put(snd_kcontrol_t *kcontrol,
+                              snd_ctl_elem_value_t *uvalue)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       u16 reg  = PRIVATE_REG(kcontrol->private_value);
+       u16 mask = PRIVATE_MASK(kcontrol->private_value);
+       if (uvalue->value.integer.value[0])
+               SET_REG(codec, reg, (GET_REG(codec, reg)) | mask);
+       else
+               SET_REG(codec, reg, (GET_REG(codec, reg)) & ~mask);
+       return 0;
+}
+
+#define SI3054_KCONTROL(kname,reg,mask) { \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = kname, \
+       .info = si3054_switch_info, \
+       .get  = si3054_switch_get, \
+       .put  = si3054_switch_put, \
+       .private_value = PRIVATE_VALUE(reg,mask), \
+}
+               
+
+static snd_kcontrol_new_t si3054_modem_mixer[] = {
+       SI3054_KCONTROL("Off-hook Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_OH),
+       SI3054_KCONTROL("Caller ID Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_CID),
+       {}
+};
+
+static int si3054_build_controls(struct hda_codec *codec)
+{
+       return snd_hda_add_new_ctls(codec, si3054_modem_mixer);
+}
+
+
+/*
+ * PCM callbacks
+ */
+
+static int si3054_pcm_prepare(struct hda_pcm_stream *hinfo,
+                             struct hda_codec *codec,
+                             unsigned int stream_tag,
+                             unsigned int format,
+                             snd_pcm_substream_t *substream)
+{
+       u16 val;
+
+       SET_REG(codec, SI3054_LINE_RATE, substream->runtime->rate);
+       val = GET_REG(codec, SI3054_LINE_LEVEL);
+       val &= 0xff << (8 * (substream->stream != SNDRV_PCM_STREAM_PLAYBACK));
+       val |= ((stream_tag & 0xf) << 4) << (8 * (substream->stream == SNDRV_PCM_STREAM_PLAYBACK));
+       SET_REG(codec, SI3054_LINE_LEVEL, val);
+
+       snd_hda_codec_setup_stream(codec, hinfo->nid,
+                                  stream_tag, 0, format);
+       return 0;
+}
+
+static int si3054_pcm_open(struct hda_pcm_stream *hinfo,
+                          struct hda_codec *codec,
+                           snd_pcm_substream_t *substream)
+{
+       static unsigned int rates[] = { 8000, 9600, 16000 };
+       static snd_pcm_hw_constraint_list_t hw_constraints_rates = {
+               .count = ARRAY_SIZE(rates),
+               .list = rates,
+               .mask = 0,
+       };
+       substream->runtime->hw.period_bytes_min = 80;
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
+}
+
+
+static struct hda_pcm_stream si3054_pcm = {
+       .substreams = 1,
+       .channels_min = 1,
+       .channels_max = 1,
+       .nid = 0x1,
+       .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_KNOT,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       .maxbps = 16,
+       .ops = {
+               .open = si3054_pcm_open,
+               .prepare = si3054_pcm_prepare,
+       },
+};
+
+
+static int si3054_build_pcms(struct hda_codec *codec)
+{
+       struct si3054_spec *spec = codec->spec;
+       struct hda_pcm *info = &spec->pcm;
+       si3054_pcm.nid = codec->mfg;
+       codec->num_pcms = 1;
+       codec->pcm_info = info;
+       info->name = "Si3054 Modem";
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE]  = si3054_pcm;
+       return 0;
+}
+
+
+/*
+ * Init part
+ */
+
+static int si3054_init(struct hda_codec *codec)
+{
+       struct si3054_spec *spec = codec->spec;
+       unsigned wait_count;
+       u16 val;
+
+       snd_hda_codec_write(codec, AC_NODE_ROOT, 0, AC_VERB_SET_CODEC_RESET, 0);
+       snd_hda_codec_write(codec, codec->mfg, 0, AC_VERB_SET_STREAM_FORMAT, 0);
+       SET_REG(codec, SI3054_LINE_RATE, 9600);
+       SET_REG(codec, SI3054_LINE_LEVEL, SI3054_DTAG_MASK|SI3054_ATAG_MASK);
+       SET_REG(codec, SI3054_EXTENDED_MID, 0);
+
+       wait_count = 10;
+       do {
+               msleep(2);
+               val = GET_REG(codec, SI3054_EXTENDED_MID);
+       } while ((val & SI3054_MEI_READY) != SI3054_MEI_READY && wait_count--);
+
+       if((val&SI3054_MEI_READY) != SI3054_MEI_READY) {
+               snd_printk(KERN_ERR "si3054: cannot initialize. EXT MID = %04x\n", val);
+               return -EACCES;
+       }
+
+       SET_REG(codec, SI3054_GPIO_POLARITY, 0xffff);
+       SET_REG(codec, SI3054_GPIO_CFG, 0x0);
+       SET_REG(codec, SI3054_MISC_AFE, 0);
+       SET_REG(codec, SI3054_LINE_CFG1,0x200);
+
+       if((GET_REG(codec,SI3054_LINE_STATUS) & (1<<6)) == 0) {
+               snd_printd("Link Frame Detect(FDT) is not ready (line status: %04x)\n",
+                               GET_REG(codec,SI3054_LINE_STATUS));
+       }
+
+       spec->international = GET_REG(codec, SI3054_CHIPID) & SI3054_CHIPID_INTERNATIONAL;
+
+       return 0;
+}
+
+static void si3054_free(struct hda_codec *codec)
+{
+       kfree(codec->spec);
+}
+
+
+/*
+ */
+
+static struct hda_codec_ops si3054_patch_ops = {
+       .build_controls = si3054_build_controls,
+       .build_pcms = si3054_build_pcms,
+       .init = si3054_init,
+       .free = si3054_free,
+#ifdef CONFIG_PM
+       //.suspend = si3054_suspend,
+       .resume = si3054_init,
+#endif
+};
+
+static int patch_si3054(struct hda_codec *codec)
+{
+       struct si3054_spec *spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+       codec->spec = spec;
+       codec->patch_ops = si3054_patch_ops;
+       return 0;
+}
+
+/*
+ * patch entries
+ */
+struct hda_codec_preset snd_hda_preset_si3054[] = {
+       { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 },
+       {}
+};
+
index eb20f73be61a68682c91f3294c7d26720b1ac546..39fbe662965d85246ed16eec5cd15bf8f1c0ce63 100644 (file)
@@ -618,15 +618,15 @@ static int __devinit snd_ice1712_delta_init(ice1712_t *ice)
  */
 
 static snd_kcontrol_new_t snd_ice1712_delta1010_wordclock_select __devinitdata =
-ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0);
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0);
 static snd_kcontrol_new_t snd_ice1712_delta1010lt_wordclock_select __devinitdata =
-ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 1, 0);
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 1, 0);
 static snd_kcontrol_new_t snd_ice1712_delta1010_wordclock_status __devinitdata =
-ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
 static snd_kcontrol_new_t snd_ice1712_deltadio2496_spdif_in_select __devinitdata =
-ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "IEC958 Input Optical", 0, ICE1712_DELTA_SPDIF_INPUT_SELECT, 0, 0);
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, ICE1712_DELTA_SPDIF_INPUT_SELECT, 0, 0);
 static snd_kcontrol_new_t snd_ice1712_delta_spdif_in_status __devinitdata =
-ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Delta IEC958 Input Status", 0, ICE1712_DELTA_SPDIF_IN_STAT, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Delta IEC958 Input Status", 0, ICE1712_DELTA_SPDIF_IN_STAT, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
 
 
 static int __devinit snd_ice1712_delta_add_controls(ice1712_t *ice)
index a2545a5b26c48b1546ea9d35b6a0c31cbeff069b..b97f50d10ba308cd532bac7285c45b9107fbcbbc 100644 (file)
@@ -1422,7 +1422,7 @@ static snd_kcontrol_new_t snd_ice1712_multi_capture_analog_switch __devinitdata
 
 static snd_kcontrol_new_t snd_ice1712_multi_capture_spdif_switch __devinitdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "IEC958 Multi Capture Switch",
+       .name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,SWITCH),
        .info = snd_ice1712_pro_mixer_switch_info,
        .get = snd_ice1712_pro_mixer_switch_get,
        .put = snd_ice1712_pro_mixer_switch_put,
@@ -1441,7 +1441,7 @@ static snd_kcontrol_new_t snd_ice1712_multi_capture_analog_volume __devinitdata
 
 static snd_kcontrol_new_t snd_ice1712_multi_capture_spdif_volume __devinitdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "IEC958 Multi Capture Volume",
+       .name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,VOLUME),
        .info = snd_ice1712_pro_mixer_volume_info,
        .get = snd_ice1712_pro_mixer_volume_get,
        .put = snd_ice1712_pro_mixer_volume_put,
@@ -1715,7 +1715,7 @@ static int snd_ice1712_spdif_maskp_get(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_ice1712_spdif_maskc __devinitdata =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
        .info =         snd_ice1712_spdif_info,
        .get =          snd_ice1712_spdif_maskc_get,
@@ -1724,7 +1724,7 @@ static snd_kcontrol_new_t snd_ice1712_spdif_maskc __devinitdata =
 static snd_kcontrol_new_t snd_ice1712_spdif_maskp __devinitdata =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
        .info =         snd_ice1712_spdif_info,
        .get =          snd_ice1712_spdif_maskp_get,
@@ -2203,7 +2203,7 @@ static snd_kcontrol_new_t snd_ice1712_mixer_pro_analog_route __devinitdata = {
 
 static snd_kcontrol_new_t snd_ice1712_mixer_pro_spdif_route __devinitdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "IEC958 Playback Route",
+       .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
        .info = snd_ice1712_pro_route_info,
        .get = snd_ice1712_pro_route_spdif_get,
        .put = snd_ice1712_pro_route_spdif_put,
index 79b5f12e06fc4afba100a65e8eacefbefa697b52..c7af5e5fee13e1f2d318ae32b5d2ba5d7781e487 100644 (file)
@@ -1414,7 +1414,7 @@ static int snd_vt1724_spdif_maskp_get(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_vt1724_spdif_maskc __devinitdata =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
        .info =         snd_vt1724_spdif_info,
        .get =          snd_vt1724_spdif_maskc_get,
@@ -1423,7 +1423,7 @@ static snd_kcontrol_new_t snd_vt1724_spdif_maskc __devinitdata =
 static snd_kcontrol_new_t snd_vt1724_spdif_maskp __devinitdata =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
        .info =         snd_vt1724_spdif_info,
        .get =          snd_vt1724_spdif_maskp_get,
@@ -1466,7 +1466,7 @@ static snd_kcontrol_new_t snd_vt1724_spdif_switch __devinitdata =
        .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
        /* FIXME: the following conflict with IEC958 Playback Route */
        // .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH),
-       .name =         "IEC958 Output Switch",
+       .name =         SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH),
        .info =         snd_vt1724_spdif_sw_info,
        .get =          snd_vt1724_spdif_sw_get,
        .put =          snd_vt1724_spdif_sw_put
index d7af3e47443263810fc075e1b7e9e513c01996fc..7b548416dcefc086295511b6845359975bb8dda8 100644 (file)
@@ -389,6 +389,7 @@ typedef struct {
        struct ac97_pcm *pcm;
        int pcm_open_flag;
        unsigned int page_attr_changed: 1;
+       unsigned int suspended: 1;
 } ichdev_t;
 
 typedef struct _snd_intel8x0 intel8x0_t;
@@ -862,12 +863,16 @@ static int snd_intel8x0_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
        unsigned long port = ichdev->reg_offset;
 
        switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
+               ichdev->suspended = 0;
+               /* fallthru */
+       case SNDRV_PCM_TRIGGER_START:
                val = ICH_IOCE | ICH_STARTBM;
                break;
-       case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
+               ichdev->suspended = 1;
+               /* fallthru */
+       case SNDRV_PCM_TRIGGER_STOP:
                val = 0;
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -899,9 +904,11 @@ static int snd_intel8x0_ali_trigger(snd_pcm_substream_t *substream, int cmd)
 
        val = igetdword(chip, ICHREG(ALI_DMACR));
        switch (cmd) {
+       case SNDRV_PCM_TRIGGER_RESUME:
+               ichdev->suspended = 0;
+               /* fallthru */
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-       case SNDRV_PCM_TRIGGER_RESUME:
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                        /* clear FIFO for synchronization of channels */
                        fifo = igetdword(chip, fiforeg[ichdev->ali_slot / 4]);
@@ -913,9 +920,11 @@ static int snd_intel8x0_ali_trigger(snd_pcm_substream_t *substream, int cmd)
                val &= ~(1 << (ichdev->ali_slot + 16)); /* clear PAUSE flag */
                iputdword(chip, ICHREG(ALI_DMACR), val | (1 << ichdev->ali_slot)); /* start DMA */
                break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               ichdev->suspended = 1;
+               /* fallthru */
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
                iputdword(chip, ICHREG(ALI_DMACR), val | (1 << (ichdev->ali_slot + 16))); /* pause */
                iputbyte(chip, port + ICH_REG_OFF_CR, 0);
                while (igetbyte(chip, port + ICH_REG_OFF_CR))
@@ -994,6 +1003,8 @@ static void snd_intel8x0_setup_pcm_out(intel8x0_t *chip,
 {
        unsigned int cnt;
        int dbl = runtime->rate > 48000;
+
+       spin_lock_irq(&chip->reg_lock);
        switch (chip->device_type) {
        case DEVICE_ALI:
                cnt = igetdword(chip, ICHREG(ALI_SCR));
@@ -1037,6 +1048,7 @@ static void snd_intel8x0_setup_pcm_out(intel8x0_t *chip,
                iputdword(chip, ICHREG(GLOB_CNT), cnt);
                break;
        }
+       spin_unlock_irq(&chip->reg_lock);
 }
 
 static int snd_intel8x0_pcm_prepare(snd_pcm_substream_t * substream)
@@ -1048,15 +1060,12 @@ static int snd_intel8x0_pcm_prepare(snd_pcm_substream_t * substream)
        ichdev->physbuf = runtime->dma_addr;
        ichdev->size = snd_pcm_lib_buffer_bytes(substream);
        ichdev->fragsize = snd_pcm_lib_period_bytes(substream);
-       spin_lock_irq(&chip->reg_lock);
        if (ichdev->ichd == ICHD_PCMOUT) {
                snd_intel8x0_setup_pcm_out(chip, runtime);
-               if (chip->device_type == DEVICE_INTEL_ICH4) {
+               if (chip->device_type == DEVICE_INTEL_ICH4)
                        ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1;
-               }
        }
        snd_intel8x0_setup_periods(chip, ichdev);
-       spin_unlock_irq(&chip->reg_lock);
        return 0;
 }
 
@@ -1815,6 +1824,18 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
                .name = "HP nc6000",
                .type = AC97_TUNE_MUTE_LED
        },
+       {
+               .subvendor = 0x103c,
+               .subdevice = 0x0934,
+               .name = "HP nx8220",
+               .type = AC97_TUNE_MUTE_LED
+       },
+       {
+               .subvendor = 0x103c,
+               .subdevice = 0x099c,
+               .name = "HP nx6110",    /* AD1981B */
+               .type = AC97_TUNE_HP_ONLY
+       },
        {
                .subvendor = 0x103c,
                .subdevice = 0x129d,
@@ -1869,6 +1890,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
                .name = "Fujitsu S6210",        /* STAC9750/51 */
                .type = AC97_TUNE_HP_ONLY
        },
+       {
+               .subvendor = 0x10cf,
+               .subdevice = 0x12ec,
+               .name = "Fujitsu-Siemens 4010",
+               .type = AC97_TUNE_HP_ONLY
+       },
        {
                .subvendor = 0x10f1,
                .subdevice = 0x2665,
@@ -2424,6 +2451,20 @@ static int intel8x0_resume(snd_card_t *card)
                }
        }
 
+       /* resume status */
+       for (i = 0; i < chip->bdbars_count; i++) {
+               ichdev_t *ichdev = &chip->ichd[i];
+               unsigned long port = ichdev->reg_offset;
+               if (! ichdev->substream || ! ichdev->suspended)
+                       continue;
+               if (ichdev->ichd == ICHD_PCMOUT)
+                       snd_intel8x0_setup_pcm_out(chip, ichdev->substream->runtime);
+               iputdword(chip, port + ICH_REG_OFF_BDBAR, ichdev->bdbar_addr);
+               iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi);
+               iputbyte(chip, port + ICH_REG_OFF_CIV, ichdev->civ);
+               iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
+       }
+
        return 0;
 }
 #endif /* CONFIG_PM */
index 79d8eda54f0d48dfa60690db217f7251d451bcfd..d2aa9c82d41e44029d737e370cb8155e899a3c56 100644 (file)
@@ -2067,7 +2067,7 @@ static int snd_korg1212_control_sync_put(snd_kcontrol_t * kcontrol, snd_ctl_elem
         },                                                                                      \
         {                                                                                      \
                 .access =      SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE,       \
-                .iface =        SNDRV_CTL_ELEM_IFACE_PCM,                                      \
+                .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,                                    \
                 .name =                c_name " Monitor Phase Invert",                                 \
                 .info =                snd_korg1212_control_phase_info,                                \
                 .get =         snd_korg1212_control_phase_get,                                 \
@@ -2082,7 +2082,7 @@ static snd_kcontrol_new_t snd_korg1212_controls[] = {
         MON_MIXER(4, "ADAT-5"), MON_MIXER(5, "ADAT-6"), MON_MIXER(6, "ADAT-7"), MON_MIXER(7, "ADAT-8"),
        {
                 .access =      SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE,
-                .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+                .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
                 .name =                "Sync Source",
                 .info =                snd_korg1212_control_sync_info,
                 .get =         snd_korg1212_control_sync_get,
index 7eb20b8f89f62c160d27f97965b3067e2fd86502..2bbeb10ff7c4a0c3aa182a98176a0dde05cf461d 100644 (file)
@@ -189,6 +189,7 @@ struct snd_nm256_stream {
        nm256_t *chip;
        snd_pcm_substream_t *substream;
        int running;
+       int suspended;
        
        u32 buf;        /* offset from chip->buffer */
        int bufsize;    /* buffer size in bytes */
@@ -231,8 +232,10 @@ struct snd_nm256 {
        int mixer_status_mask;          /* bit mask to test the mixer status */
 
        int irq;
+       int irq_acks;
        irqreturn_t (*interrupt)(int, void *, struct pt_regs *);
        int badintrcount;               /* counter to check bogus interrupts */
+       struct semaphore irq_mutex;
 
        nm256_stream_t streams[2];
 
@@ -464,6 +467,37 @@ snd_nm256_set_format(nm256_t *chip, nm256_stream_t *s, snd_pcm_substream_t *subs
        }
 }
 
+/* acquire interrupt */
+static int snd_nm256_acquire_irq(nm256_t *chip)
+{
+       down(&chip->irq_mutex);
+       if (chip->irq < 0) {
+               if (request_irq(chip->pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ,
+                               chip->card->driver, (void*)chip)) {
+                       snd_printk("unable to grab IRQ %d\n", chip->pci->irq);
+                       up(&chip->irq_mutex);
+                       return -EBUSY;
+               }
+               chip->irq = chip->pci->irq;
+       }
+       chip->irq_acks++;
+       up(&chip->irq_mutex);
+       return 0;
+}
+
+/* release interrupt */
+static void snd_nm256_release_irq(nm256_t *chip)
+{
+       down(&chip->irq_mutex);
+       if (chip->irq_acks > 0)
+               chip->irq_acks--;
+       if (chip->irq_acks == 0 && chip->irq >= 0) {
+               free_irq(chip->irq, (void*)chip);
+               chip->irq = -1;
+       }
+       up(&chip->irq_mutex);
+}
+
 /*
  * start / stop
  */
@@ -538,15 +572,19 @@ snd_nm256_playback_trigger(snd_pcm_substream_t *substream, int cmd)
 
        spin_lock(&chip->reg_lock);
        switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
+               s->suspended = 0;
+               /* fallthru */
+       case SNDRV_PCM_TRIGGER_START:
                if (! s->running) {
                        snd_nm256_playback_start(chip, s, substream);
                        s->running = 1;
                }
                break;
-       case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
+               s->suspended = 1;
+               /* fallthru */
+       case SNDRV_PCM_TRIGGER_STOP:
                if (s->running) {
                        snd_nm256_playback_stop(chip);
                        s->running = 0;
@@ -818,6 +856,8 @@ snd_nm256_playback_open(snd_pcm_substream_t *substream)
 {
        nm256_t *chip = snd_pcm_substream_chip(substream);
 
+       if (snd_nm256_acquire_irq(chip) < 0)
+               return -EBUSY;
        snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_PLAYBACK],
                               substream, &snd_nm256_playback);
        return 0;
@@ -828,6 +868,8 @@ snd_nm256_capture_open(snd_pcm_substream_t *substream)
 {
        nm256_t *chip = snd_pcm_substream_chip(substream);
 
+       if (snd_nm256_acquire_irq(chip) < 0)
+               return -EBUSY;
        snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_CAPTURE],
                               substream, &snd_nm256_capture);
        return 0;
@@ -839,6 +881,9 @@ snd_nm256_capture_open(snd_pcm_substream_t *substream)
 static int
 snd_nm256_playback_close(snd_pcm_substream_t *substream)
 {
+       nm256_t *chip = snd_pcm_substream_chip(substream);
+
+       snd_nm256_release_irq(chip);
        return 0;
 }
 
@@ -846,6 +891,9 @@ snd_nm256_playback_close(snd_pcm_substream_t *substream)
 static int
 snd_nm256_capture_close(snd_pcm_substream_t *substream)
 {
+       nm256_t *chip = snd_pcm_substream_chip(substream);
+
+       snd_nm256_release_irq(chip);
        return 0;
 }
 
@@ -915,18 +963,16 @@ snd_nm256_pcm(nm256_t *chip, int device)
 static void
 snd_nm256_init_chip(nm256_t *chip)
 {
-       spin_lock_irq(&chip->reg_lock);
        /* Reset everything. */
        snd_nm256_writeb(chip, 0x0, 0x11);
        snd_nm256_writew(chip, 0x214, 0);
        /* stop sounds.. */
        //snd_nm256_playback_stop(chip);
        //snd_nm256_capture_stop(chip);
-       spin_unlock_irq(&chip->reg_lock);
 }
 
 
-static inline void
+static irqreturn_t
 snd_nm256_intr_check(nm256_t *chip)
 {
        if (chip->badintrcount++ > 1000) {
@@ -947,7 +993,9 @@ snd_nm256_intr_check(nm256_t *chip)
                if (chip->streams[SNDRV_PCM_STREAM_CAPTURE].running)
                        snd_nm256_capture_stop(chip);
                chip->badintrcount = 0;
+               return IRQ_HANDLED;
        }
+       return IRQ_NONE;
 }
 
 /* 
@@ -969,10 +1017,8 @@ snd_nm256_interrupt(int irq, void *dev_id, struct pt_regs *dummy)
        status = snd_nm256_readw(chip, NM_INT_REG);
 
        /* Not ours. */
-       if (status == 0) {
-               snd_nm256_intr_check(chip);
-               return IRQ_NONE;
-       }
+       if (status == 0)
+               return snd_nm256_intr_check(chip);
 
        chip->badintrcount = 0;
 
@@ -1036,10 +1082,8 @@ snd_nm256_interrupt_zx(int irq, void *dev_id, struct pt_regs *dummy)
        status = snd_nm256_readl(chip, NM_INT_REG);
 
        /* Not ours. */
-       if (status == 0) {
-               snd_nm256_intr_check(chip);
-               return IRQ_NONE;
-       }
+       if (status == 0)
+               return snd_nm256_intr_check(chip);
 
        chip->badintrcount = 0;
 
@@ -1192,7 +1236,7 @@ snd_nm256_mixer(nm256_t *chip)
                AC97_PC_BEEP, AC97_PHONE, AC97_MIC, AC97_LINE, AC97_CD,
                AC97_VIDEO, AC97_AUX, AC97_PCM, AC97_REC_SEL,
                AC97_REC_GAIN, AC97_GENERAL_PURPOSE, AC97_3D_CONTROL,
-               AC97_EXTENDED_ID,
+               /*AC97_EXTENDED_ID,*/
                AC97_VENDOR_ID1, AC97_VENDOR_ID2,
                -1
        };
@@ -1206,6 +1250,7 @@ snd_nm256_mixer(nm256_t *chip)
        for (i = 0; mixer_regs[i] >= 0; i++)
                set_bit(mixer_regs[i], ac97.reg_accessed);
        ac97.private_data = chip;
+       pbus->no_vra = 1;
        err = snd_ac97_mixer(pbus, &ac97, &chip->ac97);
        if (err < 0)
                return err;
@@ -1281,6 +1326,7 @@ static int nm256_suspend(snd_card_t *card, pm_message_t state)
 static int nm256_resume(snd_card_t *card)
 {
        nm256_t *chip = card->pm_private_data;
+       int i;
 
        /* Perform a full reset on the hardware */
        pci_enable_device(chip->pci);
@@ -1289,6 +1335,15 @@ static int nm256_resume(snd_card_t *card)
        /* restore ac97 */
        snd_ac97_resume(chip->ac97);
 
+       for (i = 0; i < 2; i++) {
+               nm256_stream_t *s = &chip->streams[i];
+               if (s->substream && s->suspended) {
+                       spin_lock_irq(&chip->reg_lock);
+                       snd_nm256_set_format(chip, s, s->substream);
+                       spin_unlock_irq(&chip->reg_lock);
+               }
+       }
+
        return 0;
 }
 #endif /* CONFIG_PM */
@@ -1360,6 +1415,7 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci,
        chip->use_cache = usecache;
        spin_lock_init(&chip->reg_lock);
        chip->irq = -1;
+       init_MUTEX(&chip->irq_mutex);
 
        chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize = play_bufsize;
        chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize = capt_bufsize;
@@ -1470,15 +1526,6 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci,
                chip->coeff_buf[SNDRV_PCM_STREAM_CAPTURE] = addr;
        }
 
-       /* acquire interrupt */
-       if (request_irq(pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ,
-                       card->driver, (void*)chip)) {
-               err = -EBUSY;
-               snd_printk("unable to grab IRQ %d\n", pci->irq);
-               goto __error;
-       }
-       chip->irq = pci->irq;
-
        /* Fixed setting. */
        chip->mixer_base = NM_MIXER_OFFSET;
 
index b7b554df6705b368e4610e71ad9552dc6e79965e..456be39e8e4a1171f296e2eab71513b0efb4d490 100644 (file)
@@ -1900,7 +1900,7 @@ static snd_kcontrol_new_t snd_rme32_controls[] = {
        },
        {
                .access = SNDRV_CTL_ELEM_ACCESS_READ,
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
                .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
                .info = snd_rme32_control_spdif_mask_info,
                .get =  snd_rme32_control_spdif_mask_get,
@@ -1908,7 +1908,7 @@ static snd_kcontrol_new_t snd_rme32_controls[] = {
        },
        {
                .access = SNDRV_CTL_ELEM_ACCESS_READ,
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
                .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK),
                .info = snd_rme32_control_spdif_mask_info,
                .get =  snd_rme32_control_spdif_mask_get,
index 10c4f45a913c7bc449c8403d03edb3f7f987cfac..9645e9004a48e49550e7e26d08c091595a52df80 100644 (file)
@@ -2266,7 +2266,7 @@ static snd_kcontrol_new_t snd_rme96_controls[] = {
 },
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
        .info =         snd_rme96_control_spdif_mask_info,
        .get =          snd_rme96_control_spdif_mask_get,
@@ -2276,7 +2276,7 @@ static snd_kcontrol_new_t snd_rme96_controls[] = {
 },
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
        .info =         snd_rme96_control_spdif_mask_info,
        .get =          snd_rme96_control_spdif_mask_get,
index 796621de5009bfa3f82284093edc526364def850..6694866089b5cd8061e088a1c27490d1109bbbe4 100644 (file)
@@ -1524,7 +1524,7 @@ static int snd_hdsp_control_spdif_mask_get(snd_kcontrol_t * kcontrol, snd_ctl_el
 }
 
 #define HDSP_SPDIF_IN(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM,  \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_spdif_in, \
@@ -1584,7 +1584,7 @@ static int snd_hdsp_put_spdif_in(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
 }
 
 #define HDSP_SPDIF_OUT(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_hdsp_info_spdif_bits, \
   .get = snd_hdsp_get_spdif_out, .put = snd_hdsp_put_spdif_out }
 
@@ -1638,7 +1638,7 @@ static int snd_hdsp_put_spdif_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_
 }
 
 #define HDSP_SPDIF_PROFESSIONAL(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_hdsp_info_spdif_bits, \
   .get = snd_hdsp_get_spdif_professional, .put = snd_hdsp_put_spdif_professional }
 
@@ -1683,7 +1683,7 @@ static int snd_hdsp_put_spdif_professional(snd_kcontrol_t * kcontrol, snd_ctl_el
 }
 
 #define HDSP_SPDIF_EMPHASIS(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_hdsp_info_spdif_bits, \
   .get = snd_hdsp_get_spdif_emphasis, .put = snd_hdsp_put_spdif_emphasis }
 
@@ -1728,7 +1728,7 @@ static int snd_hdsp_put_spdif_emphasis(snd_kcontrol_t * kcontrol, snd_ctl_elem_v
 }
 
 #define HDSP_SPDIF_NON_AUDIO(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_hdsp_info_spdif_bits, \
   .get = snd_hdsp_get_spdif_nonaudio, .put = snd_hdsp_put_spdif_nonaudio }
 
@@ -1773,7 +1773,7 @@ static int snd_hdsp_put_spdif_nonaudio(snd_kcontrol_t * kcontrol, snd_ctl_elem_v
 }
 
 #define HDSP_SPDIF_SAMPLE_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1834,7 +1834,7 @@ static int snd_hdsp_get_spdif_sample_rate(snd_kcontrol_t * kcontrol, snd_ctl_ele
 }
 
 #define HDSP_SYSTEM_SAMPLE_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1858,7 +1858,7 @@ static int snd_hdsp_get_system_sample_rate(snd_kcontrol_t * kcontrol, snd_ctl_el
 }
 
 #define HDSP_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1918,7 +1918,7 @@ static int snd_hdsp_get_autosync_sample_rate(snd_kcontrol_t * kcontrol, snd_ctl_
 }
 
 #define HDSP_SYSTEM_CLOCK_MODE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1958,7 +1958,7 @@ static int snd_hdsp_get_system_clock_mode(snd_kcontrol_t * kcontrol, snd_ctl_ele
 }
 
 #define HDSP_CLOCK_SOURCE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_clock_source, \
@@ -2124,7 +2124,7 @@ static int snd_hdsp_put_clock_source_lock(snd_kcontrol_t * kcontrol, snd_ctl_ele
 }
 
 #define HDSP_DA_GAIN(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_da_gain, \
@@ -2210,7 +2210,7 @@ static int snd_hdsp_put_da_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
 }
 
 #define HDSP_AD_GAIN(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_ad_gain, \
@@ -2296,7 +2296,7 @@ static int snd_hdsp_put_ad_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
 }
 
 #define HDSP_PHONE_GAIN(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_phone_gain, \
@@ -2382,7 +2382,7 @@ static int snd_hdsp_put_phone_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value
 }
 
 #define HDSP_XLR_BREAKOUT_CABLE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_xlr_breakout_cable, \
@@ -2447,7 +2447,7 @@ static int snd_hdsp_put_xlr_breakout_cable(snd_kcontrol_t * kcontrol, snd_ctl_el
    Switching this on desactivates external ADAT
 */
 #define HDSP_AEB(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_aeb, \
@@ -2508,7 +2508,7 @@ static int snd_hdsp_put_aeb(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * uc
 }
 
 #define HDSP_PREF_SYNC_REF(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_pref_sync_ref, \
@@ -2641,7 +2641,7 @@ static int snd_hdsp_put_pref_sync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_va
 }
 
 #define HDSP_AUTOSYNC_REF(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -2697,7 +2697,7 @@ static int snd_hdsp_get_autosync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
 }
 
 #define HDSP_LINE_OUT(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_line_out, \
@@ -2757,7 +2757,7 @@ static int snd_hdsp_put_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
 }
 
 #define HDSP_PRECISE_POINTER(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_precise_pointer, \
@@ -2811,7 +2811,7 @@ static int snd_hdsp_put_precise_pointer(snd_kcontrol_t * kcontrol, snd_ctl_elem_
 }
 
 #define HDSP_USE_MIDI_TASKLET(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdsp_info_use_midi_tasklet, \
@@ -2868,6 +2868,7 @@ static int snd_hdsp_put_use_midi_tasklet(snd_kcontrol_t * kcontrol, snd_ctl_elem
 { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
   .name = xname, \
   .index = xindex, \
+  .device = 0, \
   .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
                 SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
   .info = snd_hdsp_info_mixer, \
@@ -2939,7 +2940,7 @@ static int snd_hdsp_put_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *
 }
 
 #define HDSP_WC_SYNC_CHECK(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
@@ -2983,7 +2984,7 @@ static int snd_hdsp_get_wc_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_elem_va
 }
 
 #define HDSP_SPDIF_SYNC_CHECK(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
@@ -3015,7 +3016,7 @@ static int snd_hdsp_get_spdif_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_elem
 }
 
 #define HDSP_ADATSYNC_SYNC_CHECK(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
@@ -3046,7 +3047,7 @@ static int snd_hdsp_get_adatsync_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_e
 }
 
 #define HDSP_ADAT_SYNC_CHECK \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
   .info = snd_hdsp_info_sync_check, \
   .get = snd_hdsp_get_adat_sync_check \
@@ -3119,7 +3120,7 @@ static snd_kcontrol_new_t snd_hdsp_controls[] = {
 },
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
        .info =         snd_hdsp_control_spdif_mask_info,
        .get =          snd_hdsp_control_spdif_mask_get,
@@ -3129,7 +3130,7 @@ static snd_kcontrol_new_t snd_hdsp_controls[] = {
 },
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
        .info =         snd_hdsp_control_spdif_mask_info,
        .get =          snd_hdsp_control_spdif_mask_get,
@@ -3146,8 +3147,6 @@ HDSP_SPDIF_NON_AUDIO("IEC958 Non-audio Bit", 0),
 /* 'Sample Clock Source' complies with the alsa control naming scheme */ 
 HDSP_CLOCK_SOURCE("Sample Clock Source", 0),
 {
-       /* FIXME: should be PCM or MIXER? */
-       /* .iface = SNDRV_CTL_ELEM_IFACE_PCM, */
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Sample Clock Source Locking",
        .info = snd_hdsp_info_clock_source_lock,
index 9e86d0eb41ce600561928d6561bb6d6a91644b3f..5d786d113b254422e1aa7d8aecbc31f330e8294f 100644 (file)
@@ -65,7 +65,7 @@ module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable/disable specific HDSPM soundcards.");
 
 module_param_array(precise_ptr, bool, NULL, 0444);
-MODULE_PARM_DESC(precise_ptr, "Enable precise pointer, or disable.");
+MODULE_PARM_DESC(precise_ptr, "Enable or disable precise pointer.");
 
 module_param_array(line_outs_monitor, bool, NULL, 0444);
 MODULE_PARM_DESC(line_outs_monitor,
@@ -1104,14 +1104,14 @@ static int snd_hdspm_midi_output_close(snd_rawmidi_substream_t * substream)
        return 0;
 }
 
-snd_rawmidi_ops_t snd_hdspm_midi_output =
+static snd_rawmidi_ops_t snd_hdspm_midi_output =
 {
        .open =         snd_hdspm_midi_output_open,
        .close =        snd_hdspm_midi_output_close,
        .trigger =      snd_hdspm_midi_output_trigger,
 };
 
-snd_rawmidi_ops_t snd_hdspm_midi_input =
+static snd_rawmidi_ops_t snd_hdspm_midi_input =
 {
        .open =         snd_hdspm_midi_input_open,
        .close =        snd_hdspm_midi_input_close,
@@ -1168,7 +1168,7 @@ static void hdspm_midi_tasklet(unsigned long arg)
 /* get the system sample rate which is set */
 
 #define HDSPM_SYSTEM_SAMPLE_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1195,7 +1195,7 @@ static int snd_hdspm_get_system_sample_rate(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1264,7 +1264,7 @@ static int snd_hdspm_get_autosync_sample_rate(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_SYSTEM_CLOCK_MODE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1310,7 +1310,7 @@ static int snd_hdspm_get_system_clock_mode(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_CLOCK_SOURCE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdspm_info_clock_source, \
@@ -1457,7 +1457,7 @@ static int snd_hdspm_put_clock_source(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_PREF_SYNC_REF(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdspm_info_pref_sync_ref, \
@@ -1547,7 +1547,7 @@ static int snd_hdspm_put_pref_sync_ref(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_AUTOSYNC_REF(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1604,7 +1604,7 @@ static int snd_hdspm_get_autosync_ref(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_LINE_OUT(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdspm_info_line_out, \
@@ -1668,7 +1668,7 @@ static int snd_hdspm_put_line_out(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_TX_64(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdspm_info_tx_64, \
@@ -1731,7 +1731,7 @@ static int snd_hdspm_put_tx_64(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_C_TMS(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdspm_info_c_tms, \
@@ -1794,7 +1794,7 @@ static int snd_hdspm_put_c_tms(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_SAFE_MODE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdspm_info_safe_mode, \
@@ -1857,7 +1857,7 @@ static int snd_hdspm_put_safe_mode(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_INPUT_SELECT(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .info = snd_hdspm_info_input_select, \
@@ -1941,6 +1941,7 @@ static int snd_hdspm_put_input_select(snd_kcontrol_t * kcontrol,
 { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
   .name = xname, \
   .index = xindex, \
+  .device = 0, \
   .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
                 SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
   .info = snd_hdspm_info_mixer, \
@@ -2124,7 +2125,7 @@ static int snd_hdspm_put_playback_mixer(snd_kcontrol_t * kcontrol,
 }
 
 #define HDSPM_WC_SYNC_CHECK(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
@@ -2170,7 +2171,7 @@ static int snd_hdspm_get_wc_sync_check(snd_kcontrol_t * kcontrol,
 
 
 #define HDSPM_MADI_SYNC_CHECK(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
   .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
index 1bc9d0df8516e27b2a338b6859c1fa0ec63088dc..8ee4d6fd6ea789e20b3c2b1e0180efc7cbcfe051 100644 (file)
@@ -893,7 +893,7 @@ static int snd_rme9652_control_spdif_mask_get(snd_kcontrol_t * kcontrol, snd_ctl
 }
 
 #define RME9652_ADAT1_IN(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_rme9652_info_adat1_in, \
   .get = snd_rme9652_get_adat1_in, \
   .put = snd_rme9652_put_adat1_in }
@@ -971,7 +971,7 @@ static int snd_rme9652_put_adat1_in(snd_kcontrol_t * kcontrol, snd_ctl_elem_valu
 }
 
 #define RME9652_SPDIF_IN(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_rme9652_info_spdif_in, \
   .get = snd_rme9652_get_spdif_in, .put = snd_rme9652_put_spdif_in }
 
@@ -1042,7 +1042,7 @@ static int snd_rme9652_put_spdif_in(snd_kcontrol_t * kcontrol, snd_ctl_elem_valu
 }
 
 #define RME9652_SPDIF_OUT(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_rme9652_info_spdif_out, \
   .get = snd_rme9652_get_spdif_out, .put = snd_rme9652_put_spdif_out }
 
@@ -1110,7 +1110,7 @@ static int snd_rme9652_put_spdif_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
 }
 
 #define RME9652_SYNC_MODE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_rme9652_info_sync_mode, \
   .get = snd_rme9652_get_sync_mode, .put = snd_rme9652_put_sync_mode }
 
@@ -1195,7 +1195,7 @@ static int snd_rme9652_put_sync_mode(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
 }
 
 #define RME9652_SYNC_PREF(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_rme9652_info_sync_pref, \
   .get = snd_rme9652_get_sync_pref, .put = snd_rme9652_put_sync_pref }
 
@@ -1340,7 +1340,7 @@ static int snd_rme9652_put_thru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
 }
 
 #define RME9652_PASSTHRU(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_rme9652_info_passthru, \
   .put = snd_rme9652_put_passthru, \
   .get = snd_rme9652_get_passthru }
@@ -1386,7 +1386,7 @@ static int snd_rme9652_put_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_valu
 /* Read-only switches */
 
 #define RME9652_SPDIF_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
   .info = snd_rme9652_info_spdif_rate, \
   .get = snd_rme9652_get_spdif_rate }
@@ -1411,7 +1411,7 @@ static int snd_rme9652_get_spdif_rate(snd_kcontrol_t * kcontrol, snd_ctl_elem_va
 }
 
 #define RME9652_ADAT_SYNC(xname, xindex, xidx) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
   .info = snd_rme9652_info_adat_sync, \
   .get = snd_rme9652_get_adat_sync, .private_value = xidx }
@@ -1447,7 +1447,7 @@ static int snd_rme9652_get_adat_sync(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
 }
 
 #define RME9652_TC_VALID(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
   .info = snd_rme9652_info_tc_valid, \
   .get = snd_rme9652_get_tc_valid }
@@ -1545,7 +1545,7 @@ static snd_kcontrol_new_t snd_rme9652_controls[] = {
 },
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
        .info =         snd_rme9652_control_spdif_mask_info,
        .get =          snd_rme9652_control_spdif_mask_get,
@@ -1555,7 +1555,7 @@ static snd_kcontrol_new_t snd_rme9652_controls[] = {
 },
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
        .info =         snd_rme9652_control_spdif_mask_info,
        .get =          snd_rme9652_control_spdif_mask_get,
@@ -1568,7 +1568,7 @@ RME9652_SPDIF_OUT("IEC958 Output also on ADAT1", 0),
 RME9652_SYNC_MODE("Sync Mode", 0),
 RME9652_SYNC_PREF("Preferred Sync Source", 0),
 {
-       .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Channels Thru",
        .index = 0,
        .info = snd_rme9652_info_thru,
index 29d89bfba0a48b67f1b7d601161c3427c5f51366..f30d9d9478629f07f39441e7dfd8043a41d70f51 100644 (file)
@@ -1689,7 +1689,7 @@ static snd_pcm_hardware_t snd_trident_playback =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
-                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
        .formats =              (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
                                 SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),
        .rates =                SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
@@ -1714,7 +1714,7 @@ static snd_pcm_hardware_t snd_trident_capture =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
-                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
        .formats =              (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
                                 SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),
        .rates =                SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
@@ -1739,7 +1739,7 @@ static snd_pcm_hardware_t snd_trident_foldback =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
-                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
        .formats =              SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                SNDRV_PCM_RATE_48000,
        .rate_min =             48000,
@@ -1763,7 +1763,7 @@ static snd_pcm_hardware_t snd_trident_spdif =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
-                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
        .formats =              SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
                                 SNDRV_PCM_RATE_48000),
@@ -1784,7 +1784,7 @@ static snd_pcm_hardware_t snd_trident_spdif_7018 =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
-                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+                                SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
        .formats =              SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                SNDRV_PCM_RATE_48000,
        .rate_min =             48000,
index 4889600387c8fe7a408525c598276b06690795d4..56c6e52d7264228e965a3055db1de0219e70c2ae 100644 (file)
@@ -663,10 +663,12 @@ static int snd_via82xx_pcm_trigger(snd_pcm_substream_t * substream, int cmd)
                val = 0;
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
                val |= VIA_REG_CTRL_START;
                viadev->running = 1;
                break;
        case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
                val = VIA_REG_CTRL_TERMINATE;
                viadev->running = 0;
                break;
@@ -929,12 +931,12 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t *substream)
 
        if ((rate_changed = via_lock_rate(&chip->rates[0], ac97_rate)) < 0)
                return rate_changed;
-       if (rate_changed) {
+       if (rate_changed)
                snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE,
                                  chip->no_vra ? 48000 : runtime->rate);
-               snd_ac97_set_rate(chip->ac97, AC97_SPDIF,
-                                 chip->no_vra ? 48000 : runtime->rate);
-       }
+       if (chip->spdif_on && viadev->reg_offset == 0x30)
+               snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate);
+
        if (runtime->rate == 48000)
                rbits = 0xfffff;
        else
@@ -1035,7 +1037,7 @@ static snd_pcm_hardware_t snd_via82xx_hw =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID |
-                                SNDRV_PCM_INFO_RESUME |
+                                /* SNDRV_PCM_INFO_RESUME | */
                                 SNDRV_PCM_INFO_PAUSE),
        .formats =              SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                SNDRV_PCM_RATE_48000,
@@ -1484,7 +1486,7 @@ static int snd_via8233_dxs3_spdif_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_val
 }
 
 static snd_kcontrol_new_t snd_via8233_dxs3_spdif_control __devinitdata = {
-       .name = "IEC958 Output Switch",
+       .name = SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH),
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .info = snd_via8233_dxs3_spdif_info,
        .get = snd_via8233_dxs3_spdif_get,
@@ -2153,6 +2155,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci)
                { .subvendor = 0x1019, .subdevice = 0x0a81, .action = VIA_DXS_NO_VRA }, /* ECS K7VTA3 v8.0 */
                { .subvendor = 0x1019, .subdevice = 0x0a85, .action = VIA_DXS_NO_VRA }, /* ECS L7VMM2 */
                { .subvendor = 0x1025, .subdevice = 0x0033, .action = VIA_DXS_NO_VRA }, /* Acer Inspire 1353LM */
+               { .subvendor = 0x1025, .subdevice = 0x0046, .action = VIA_DXS_SRC }, /* Acer Aspire 1524 WLMi */
                { .subvendor = 0x1043, .subdevice = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/
                { .subvendor = 0x1043, .subdevice = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */
                { .subvendor = 0x1043, .subdevice = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ 
@@ -2168,10 +2171,12 @@ static int __devinit check_dxs_list(struct pci_dev *pci)
                { .subvendor = 0x1297, .subdevice = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */
                { .subvendor = 0x1458, .subdevice = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */
                { .subvendor = 0x1462, .subdevice = 0x0080, .action = VIA_DXS_SRC }, /* MSI K8T Neo-FIS2R */
+               { .subvendor = 0x1462, .subdevice = 0x0430, .action = VIA_DXS_SRC }, /* MSI 7142 (K8MM-V) */
                { .subvendor = 0x1462, .subdevice = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */
                { .subvendor = 0x1462, .subdevice = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */
                { .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_NO_VRA }, /* MSI K8T Neo2-FI */
                { .subvendor = 0x1462, .subdevice = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */
+               { .subvendor = 0x1462, .subdevice = 0x7142, .action = VIA_DXS_ENABLE }, /* MSI K8MM-V */
                { .subvendor = 0x147b, .subdevice = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */
                { .subvendor = 0x147b, .subdevice = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */
                { .subvendor = 0x147b, .subdevice = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */
index 4a9779cc97337e57ff77e63152f00cdbb36dcbef..5872d438a04a5f50f4f47aafe5ff3d4cabc9eb58 100644 (file)
@@ -521,6 +521,7 @@ static int snd_via82xx_pcm_trigger(snd_pcm_substream_t * substream, int cmd)
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
                val |= VIA_REG_CTRL_START;
                viadev->running = 1;
                break;
@@ -697,7 +698,7 @@ static snd_pcm_hardware_t snd_via82xx_hw =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID |
-                                SNDRV_PCM_INFO_RESUME |
+                                /* SNDRV_PCM_INFO_RESUME | */
                                 SNDRV_PCM_INFO_PAUSE),
        .formats =              SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_KNOT,
index d54f88a1b525b346b165cf1bd0f0ccb9819976f6..054836412dc4069b60c0af957058d902b49b1498 100644 (file)
@@ -321,6 +321,26 @@ static void snd_ymfpci_pcm_interrupt(ymfpci_t *chip, ymfpci_voice_t *voice)
                        snd_pcm_period_elapsed(ypcm->substream);
                        spin_lock(&chip->reg_lock);
                }
+
+               if (unlikely(ypcm->update_pcm_vol)) {
+                       unsigned int subs = ypcm->substream->number;
+                       unsigned int next_bank = 1 - chip->active_bank;
+                       snd_ymfpci_playback_bank_t *bank;
+                       u32 volume;
+                       
+                       bank = &voice->bank[next_bank];
+                       volume = cpu_to_le32(chip->pcm_mixer[subs].left << 15);
+                       bank->left_gain_end = volume;
+                       if (ypcm->output_rear)
+                               bank->eff2_gain_end = volume;
+                       if (ypcm->voices[1])
+                               bank = &ypcm->voices[1]->bank[next_bank];
+                       volume = cpu_to_le32(chip->pcm_mixer[subs].right << 15);
+                       bank->right_gain_end = volume;
+                       if (ypcm->output_rear)
+                               bank->eff3_gain_end = volume;
+                       ypcm->update_pcm_vol--;
+               }
        }
        spin_unlock(&chip->reg_lock);
 }
@@ -451,87 +471,74 @@ static int snd_ymfpci_pcm_voice_alloc(ymfpci_pcm_t *ypcm, int voices)
        return 0;
 }
 
-static void snd_ymfpci_pcm_init_voice(ymfpci_voice_t *voice, int stereo,
-                                     int rate, int w_16, unsigned long addr,
-                                     unsigned int end,
-                                     int output_front, int output_rear)
+static void snd_ymfpci_pcm_init_voice(ymfpci_pcm_t *ypcm, unsigned int voiceidx,
+                                     snd_pcm_runtime_t *runtime,
+                                     int has_pcm_volume)
 {
+       ymfpci_voice_t *voice = ypcm->voices[voiceidx];
        u32 format;
-       u32 delta = snd_ymfpci_calc_delta(rate);
-       u32 lpfQ = snd_ymfpci_calc_lpfQ(rate);
-       u32 lpfK = snd_ymfpci_calc_lpfK(rate);
+       u32 delta = snd_ymfpci_calc_delta(runtime->rate);
+       u32 lpfQ = snd_ymfpci_calc_lpfQ(runtime->rate);
+       u32 lpfK = snd_ymfpci_calc_lpfK(runtime->rate);
        snd_ymfpci_playback_bank_t *bank;
        unsigned int nbank;
+       u32 vol_left, vol_right;
+       u8 use_left, use_right;
 
        snd_assert(voice != NULL, return);
-       format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000);
+       if (runtime->channels == 1) {
+               use_left = 1;
+               use_right = 1;
+       } else {
+               use_left = (voiceidx & 1) == 0;
+               use_right = !use_left;
+       }
+       if (has_pcm_volume) {
+               vol_left = cpu_to_le32(ypcm->chip->pcm_mixer
+                                      [ypcm->substream->number].left << 15);
+               vol_right = cpu_to_le32(ypcm->chip->pcm_mixer
+                                       [ypcm->substream->number].right << 15);
+       } else {
+               vol_left = cpu_to_le32(0x40000000);
+               vol_right = cpu_to_le32(0x40000000);
+       }
+       format = runtime->channels == 2 ? 0x00010000 : 0;
+       if (snd_pcm_format_width(runtime->format) == 8)
+               format |= 0x80000000;
+       if (runtime->channels == 2 && (voiceidx & 1) != 0)
+               format |= 1;
        for (nbank = 0; nbank < 2; nbank++) {
                bank = &voice->bank[nbank];
+               memset(bank, 0, sizeof(*bank));
                bank->format = cpu_to_le32(format);
-               bank->loop_default = 0;
-               bank->base = cpu_to_le32(addr);
-               bank->loop_start = 0;
-               bank->loop_end = cpu_to_le32(end);
-               bank->loop_frac = 0;
-               bank->eg_gain_end = cpu_to_le32(0x40000000);
+               bank->base = cpu_to_le32(runtime->dma_addr);
+               bank->loop_end = cpu_to_le32(ypcm->buffer_size);
                bank->lpfQ = cpu_to_le32(lpfQ);
-               bank->status = 0;
-               bank->num_of_frames = 0;
-               bank->loop_count = 0;
-               bank->start = 0;
-               bank->start_frac = 0;
                bank->delta =
                bank->delta_end = cpu_to_le32(delta);
                bank->lpfK =
                bank->lpfK_end = cpu_to_le32(lpfK);
-               bank->eg_gain = cpu_to_le32(0x40000000);
-               bank->lpfD1 =
-               bank->lpfD2 = 0;
-
-               bank->left_gain = 
-               bank->right_gain =
-               bank->left_gain_end =
-               bank->right_gain_end =
-               bank->eff1_gain =
-               bank->eff2_gain =
-               bank->eff3_gain =
-               bank->eff1_gain_end =
-               bank->eff2_gain_end =
-               bank->eff3_gain_end = 0;
-
-               if (!stereo) {
-                       if (output_front) {
-                               bank->left_gain = 
+               bank->eg_gain =
+               bank->eg_gain_end = cpu_to_le32(0x40000000);
+
+               if (ypcm->output_front) {
+                       if (use_left) {
+                               bank->left_gain =
+                               bank->left_gain_end = vol_left;
+                       }
+                       if (use_right) {
                                bank->right_gain =
-                               bank->left_gain_end =
-                               bank->right_gain_end = cpu_to_le32(0x40000000);
+                               bank->right_gain_end = vol_right;
                        }
-                       if (output_rear) {
+               }
+               if (ypcm->output_rear) {
+                       if (use_left) {
                                bank->eff2_gain =
-                               bank->eff2_gain_end =
-                               bank->eff3_gain =
-                               bank->eff3_gain_end = cpu_to_le32(0x40000000);
-                       }
-               } else {
-                       if (output_front) {
-                               if ((voice->number & 1) == 0) {
-                                       bank->left_gain =
-                                       bank->left_gain_end = cpu_to_le32(0x40000000);
-                               } else {
-                                       bank->format |= cpu_to_le32(1);
-                                       bank->right_gain =
-                                       bank->right_gain_end = cpu_to_le32(0x40000000);
-                               }
+                               bank->eff2_gain_end = vol_left;
                        }
-                       if (output_rear) {
-                               if ((voice->number & 1) == 0) {
-                                       bank->eff3_gain =
-                                       bank->eff3_gain_end = cpu_to_le32(0x40000000);
-                               } else {
-                                       bank->format |= cpu_to_le32(1);
-                                       bank->eff2_gain =
-                                       bank->eff2_gain_end = cpu_to_le32(0x40000000);
-                               }
+                       if (use_right) {
+                               bank->eff3_gain =
+                               bank->eff3_gain_end = vol_right;
                        }
                }
        }
@@ -613,7 +620,7 @@ static int snd_ymfpci_playback_hw_free(snd_pcm_substream_t * substream)
 
 static int snd_ymfpci_playback_prepare(snd_pcm_substream_t * substream)
 {
-       // ymfpci_t *chip = snd_pcm_substream_chip(substream);
+       ymfpci_t *chip = snd_pcm_substream_chip(substream);
        snd_pcm_runtime_t *runtime = substream->runtime;
        ymfpci_pcm_t *ypcm = runtime->private_data;
        unsigned int nvoice;
@@ -623,14 +630,8 @@ static int snd_ymfpci_playback_prepare(snd_pcm_substream_t * substream)
        ypcm->period_pos = 0;
        ypcm->last_pos = 0;
        for (nvoice = 0; nvoice < runtime->channels; nvoice++)
-               snd_ymfpci_pcm_init_voice(ypcm->voices[nvoice],
-                                         runtime->channels == 2,
-                                         runtime->rate,
-                                         snd_pcm_format_width(runtime->format) == 16,
-                                         runtime->dma_addr,
-                                         ypcm->buffer_size,
-                                         ypcm->output_front,
-                                         ypcm->output_rear);
+               snd_ymfpci_pcm_init_voice(ypcm, nvoice, runtime,
+                                         substream->pcm == chip->pcm);
        return 0;
 }
 
@@ -882,6 +883,7 @@ static int snd_ymfpci_playback_open(snd_pcm_substream_t * substream)
        ymfpci_t *chip = snd_pcm_substream_chip(substream);
        snd_pcm_runtime_t *runtime = substream->runtime;
        ymfpci_pcm_t *ypcm;
+       snd_kcontrol_t *kctl;
        int err;
        
        if ((err = snd_ymfpci_playback_open_1(substream)) < 0)
@@ -895,6 +897,10 @@ static int snd_ymfpci_playback_open(snd_pcm_substream_t * substream)
                chip->rear_opened++;
        }
        spin_unlock_irq(&chip->reg_lock);
+
+       kctl = chip->pcm_mixer[substream->number].ctl;
+       kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+       snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
        return 0;
 }
 
@@ -987,6 +993,7 @@ static int snd_ymfpci_playback_close(snd_pcm_substream_t * substream)
 {
        ymfpci_t *chip = snd_pcm_substream_chip(substream);
        ymfpci_pcm_t *ypcm = substream->runtime->private_data;
+       snd_kcontrol_t *kctl;
 
        spin_lock_irq(&chip->reg_lock);
        if (ypcm->output_rear && chip->rear_opened > 0) {
@@ -994,6 +1001,9 @@ static int snd_ymfpci_playback_close(snd_pcm_substream_t * substream)
                ymfpci_close_extension(chip);
        }
        spin_unlock_irq(&chip->reg_lock);
+       kctl = chip->pcm_mixer[substream->number].ctl;
+       kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+       snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
        return snd_ymfpci_playback_close_1(substream);
 }
 
@@ -1665,6 +1675,66 @@ static snd_kcontrol_new_t snd_ymfpci_rear_shared __devinitdata = {
        .private_value = 2,
 };
 
+/*
+ * PCM voice volume
+ */
+
+static int snd_ymfpci_pcm_vol_info(snd_kcontrol_t *kcontrol,
+                                  snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 0x8000;
+       return 0;
+}
+
+static int snd_ymfpci_pcm_vol_get(snd_kcontrol_t *kcontrol,
+                                 snd_ctl_elem_value_t *ucontrol)
+{
+       ymfpci_t *chip = snd_kcontrol_chip(kcontrol);
+       unsigned int subs = kcontrol->id.subdevice;
+
+       ucontrol->value.integer.value[0] = chip->pcm_mixer[subs].left;
+       ucontrol->value.integer.value[1] = chip->pcm_mixer[subs].right;
+       return 0;
+}
+
+static int snd_ymfpci_pcm_vol_put(snd_kcontrol_t *kcontrol,
+                                 snd_ctl_elem_value_t *ucontrol)
+{
+       ymfpci_t *chip = snd_kcontrol_chip(kcontrol);
+       unsigned int subs = kcontrol->id.subdevice;
+       snd_pcm_substream_t *substream;
+       unsigned long flags;
+
+       if (ucontrol->value.integer.value[0] != chip->pcm_mixer[subs].left ||
+           ucontrol->value.integer.value[1] != chip->pcm_mixer[subs].right) {
+               chip->pcm_mixer[subs].left = ucontrol->value.integer.value[0];
+               chip->pcm_mixer[subs].right = ucontrol->value.integer.value[1];
+
+               substream = (snd_pcm_substream_t *)kcontrol->private_value;
+               spin_lock_irqsave(&chip->voice_lock, flags);
+               if (substream->runtime && substream->runtime->private_data) {
+                       ymfpci_pcm_t *ypcm = substream->runtime->private_data;
+                       ypcm->update_pcm_vol = 2;
+               }
+               spin_unlock_irqrestore(&chip->voice_lock, flags);
+               return 1;
+       }
+       return 0;
+}
+
+static snd_kcontrol_new_t snd_ymfpci_pcm_volume __devinitdata = {
+       .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+       .name = "PCM Playback Volume",
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+               SNDRV_CTL_ELEM_ACCESS_INACTIVE,
+       .info = snd_ymfpci_pcm_vol_info,
+       .get = snd_ymfpci_pcm_vol_get,
+       .put = snd_ymfpci_pcm_vol_put,
+};
+
 
 /*
  *  Mixer routines
@@ -1686,6 +1756,7 @@ int __devinit snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch)
 {
        ac97_template_t ac97;
        snd_kcontrol_t *kctl;
+       snd_pcm_substream_t *substream;
        unsigned int idx;
        int err;
        static ac97_bus_ops_t ops = {
@@ -1739,6 +1810,23 @@ int __devinit snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch)
                        return err;
        }
 
+       /* per-voice volume */
+       substream = chip->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+       for (idx = 0; idx < 32; ++idx) {
+               kctl = snd_ctl_new1(&snd_ymfpci_pcm_volume, chip);
+               if (!kctl)
+                       return -ENOMEM;
+               kctl->id.device = chip->pcm->device;
+               kctl->id.subdevice = idx;
+               kctl->private_value = (unsigned long)substream;
+               if ((err = snd_ctl_add(chip->card, kctl)) < 0)
+                       return err;
+               chip->pcm_mixer[idx].left = 0x8000;
+               chip->pcm_mixer[idx].right = 0x8000;
+               chip->pcm_mixer[idx].ctl = kctl;
+               substream = substream->next;
+       }
+
        return 0;
 }
 
index 3a82161d3b24cd4e193af51b0b8a2b470e3edc5e..1e8f16b4c073a739f25223b409f910ad15853c0e 100644 (file)
@@ -297,6 +297,7 @@ static void vxpocket_config(dev_link_t *link)
        CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
 
        chip->dev = &handle_to_dev(link->handle);
+       snd_card_set_dev(chip->card, chip->dev);
 
        if (snd_vxpocket_assign_resources(chip, link->io.BasePort1, link->irq.AssignedIRQ) < 0)
                goto failed;
@@ -376,7 +377,7 @@ static int vxpocket_event(event_t event, int priority, event_callback_args_t *ar
 
 /*
  */
-static dev_link_t *vxp_attach(void)
+static dev_link_t *vxpocket_attach(void)
 {
        snd_card_t *card;
        struct snd_vxpocket *vxp;
@@ -407,7 +408,7 @@ static dev_link_t *vxp_attach(void)
                return NULL;
        }
 
-       vxp->index = index[i];
+       vxp->index = i;
        card_alloc |= 1 << i;
 
        /* Chain drivers */
@@ -417,7 +418,7 @@ static dev_link_t *vxp_attach(void)
        return &vxp->link;
 }
 
-static void vxp_detach(dev_link_t *link)
+static void vxpocket_detach(dev_link_t *link)
 {
        struct snd_vxpocket *vxp;
        vx_core_t *chip;
@@ -458,8 +459,9 @@ static struct pcmcia_driver vxp_cs_driver = {
        .drv            = {
                .name   = "snd-vxpocket",
        },
-       .attach         = vxp_attach,
-       .detach         = vxp_detach,
+       .attach         = vxpocket_attach,
+       .detach         = vxpocket_detach,
+       .event          = vxpocket_event,
        .id_table       = vxp_ids,
 };
 
index 21a69e096225bff839cfb59255d49e1a3b45abe2..954f994592ab3d7ff6b2f29a84816fbb38d1a039 100644 (file)
@@ -153,7 +153,7 @@ static DEFINE_SPINLOCK(sound_loader_lock);
  *     list. Acquires locks as needed
  */
 
-static int sound_insert_unit(struct sound_unit **list, struct file_operations *fops, int index, int low, int top, const char *name, umode_t mode)
+static int sound_insert_unit(struct sound_unit **list, struct file_operations *fops, int index, int low, int top, const char *name, umode_t mode, struct device *dev)
 {
        struct sound_unit *s = kmalloc(sizeof(*s), GFP_KERNEL);
        int r;
@@ -175,7 +175,7 @@ static int sound_insert_unit(struct sound_unit **list, struct file_operations *f
        devfs_mk_cdev(MKDEV(SOUND_MAJOR, s->unit_minor),
                        S_IFCHR | mode, s->name);
        class_device_create(sound_class, MKDEV(SOUND_MAJOR, s->unit_minor),
-                               NULL, s->name+6);
+                           dev, s->name+6);
        return r;
 
  fail:
@@ -227,16 +227,18 @@ static void sound_remove_unit(struct sound_unit **list, int unit)
 static struct sound_unit *chains[SOUND_STEP];
 
 /**
- *     register_sound_special - register a special sound node
+ *     register_sound_special_device - register a special sound node
  *     @fops: File operations for the driver
  *     @unit: Unit number to allocate
+ *      @dev: device pointer
  *
  *     Allocate a special sound device by minor number from the sound
  *     subsystem. The allocated number is returned on succes. On failure
  *     a negative error code is returned.
  */
  
-int register_sound_special(struct file_operations *fops, int unit)
+int register_sound_special_device(struct file_operations *fops, int unit,
+                                 struct device *dev)
 {
        const int chain = unit % SOUND_STEP;
        int max_unit = 128 + chain;
@@ -294,9 +296,16 @@ int register_sound_special(struct file_operations *fops, int unit)
                break;
        }
        return sound_insert_unit(&chains[chain], fops, -1, unit, max_unit,
-                                name, S_IRUSR | S_IWUSR);
+                                name, S_IRUSR | S_IWUSR, dev);
 }
  
+EXPORT_SYMBOL(register_sound_special_device);
+
+int register_sound_special(struct file_operations *fops, int unit)
+{
+       return register_sound_special_device(fops, unit, NULL);
+}
+
 EXPORT_SYMBOL(register_sound_special);
 
 /**
@@ -312,7 +321,7 @@ EXPORT_SYMBOL(register_sound_special);
 int register_sound_mixer(struct file_operations *fops, int dev)
 {
        return sound_insert_unit(&chains[0], fops, dev, 0, 128,
-                                "mixer", S_IRUSR | S_IWUSR);
+                                "mixer", S_IRUSR | S_IWUSR, NULL);
 }
 
 EXPORT_SYMBOL(register_sound_mixer);
@@ -330,7 +339,7 @@ EXPORT_SYMBOL(register_sound_mixer);
 int register_sound_midi(struct file_operations *fops, int dev)
 {
        return sound_insert_unit(&chains[2], fops, dev, 2, 130,
-                                "midi", S_IRUSR | S_IWUSR);
+                                "midi", S_IRUSR | S_IWUSR, NULL);
 }
 
 EXPORT_SYMBOL(register_sound_midi);
@@ -356,7 +365,7 @@ EXPORT_SYMBOL(register_sound_midi);
 int register_sound_dsp(struct file_operations *fops, int dev)
 {
        return sound_insert_unit(&chains[3], fops, dev, 3, 131,
-                                "dsp", S_IWUSR | S_IRUSR);
+                                "dsp", S_IWUSR | S_IRUSR, NULL);
 }
 
 EXPORT_SYMBOL(register_sound_dsp);
@@ -375,7 +384,7 @@ EXPORT_SYMBOL(register_sound_dsp);
 int register_sound_synth(struct file_operations *fops, int dev)
 {
        return sound_insert_unit(&chains[9], fops, dev, 9, 137,
-                                "synth", S_IRUSR | S_IWUSR);
+                                "synth", S_IRUSR | S_IWUSR, NULL);
 }
 
 EXPORT_SYMBOL(register_sound_synth);
index f13b038329ebfb29d5fad6728252484f162cb072..751bf1272af3bc77917d5ba3f66427ca76cdd09a 100644 (file)
@@ -98,7 +98,6 @@ snd_emux_note_on(void *p, int note, int vel, snd_midi_channel_t *chan)
                vp = emu->ops.get_voice(emu, port);
                if (vp == NULL || vp->ch < 0)
                        continue;
-               snd_assert(vp->emu != NULL && vp->hw != NULL, return);
                if (STATE_IS_PLAYING(vp->state))
                        emu->ops.terminate(vp);
 
index 8298c462c291c2a529cecf04f0cb18a0aa213a52..5aa5fe651a8aaac837e09335ecb1dfa31c073654 100644 (file)
 #include <sound/driver.h>
 #include <linux/bitops.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/usb.h>
+#include <linux/vmalloc.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/info.h>
@@ -79,7 +81,7 @@ module_param_array(vid, int, NULL, 0444);
 MODULE_PARM_DESC(vid, "Vendor ID for the USB audio device.");
 module_param_array(pid, int, NULL, 0444);
 MODULE_PARM_DESC(pid, "Product ID for the USB audio device.");
-module_param(nrpacks, int, 0444);
+module_param(nrpacks, int, 0644);
 MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB.");
 module_param(async_unlink, bool, 0444);
 MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
@@ -97,7 +99,7 @@ MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
 
 #define MAX_PACKS      10
 #define MAX_PACKS_HS   (MAX_PACKS * 8) /* in high speed mode */
-#define MAX_URBS       5       /* max. 20ms long packets */
+#define MAX_URBS       8
 #define SYNC_URBS      4       /* always four urbs for sync */
 #define MIN_PACKS_URB  1       /* minimum 1 packet per urb */
 
@@ -126,11 +128,10 @@ struct audioformat {
 
 struct snd_urb_ctx {
        struct urb *urb;
+       unsigned int buffer_size;       /* size of data buffer, if data URB */
        snd_usb_substream_t *subs;
        int index;      /* index for urb array */
        int packets;    /* number of packets per urb */
-       int transfer;   /* transferred size */
-       char *buf;      /* buffer for capture */
 };
 
 struct snd_urb_ops {
@@ -165,12 +166,11 @@ struct snd_usb_substream {
        unsigned int curframesize;      /* current packet size in frames (for capture) */
        unsigned int fill_max: 1;       /* fill max packet size always */
        unsigned int fmt_type;          /* USB audio format type (1-3) */
+       unsigned int packs_per_ms;      /* packets per millisecond (for playback) */
 
        unsigned int running: 1;        /* running status */
 
-       unsigned int hwptr;                     /* free frame position in the buffer (only for playback) */
        unsigned int hwptr_done;                        /* processed frame position in the buffer */
-       unsigned int transfer_sched;            /* scheduled frames since last period (for playback) */
        unsigned int transfer_done;             /* processed frames since last period update */
        unsigned long active_mask;      /* bitmask of active urbs */
        unsigned long unlink_mask;      /* bitmask of unlinked urbs */
@@ -178,13 +178,14 @@ struct snd_usb_substream {
        unsigned int nurbs;                     /* # urbs */
        snd_urb_ctx_t dataurb[MAX_URBS];        /* data urb table */
        snd_urb_ctx_t syncurb[SYNC_URBS];       /* sync urb table */
-       char syncbuf[SYNC_URBS * 4];    /* sync buffer; it's so small - let's get static */
-       char *tmpbuf;                   /* temporary buffer for playback */
+       char *syncbuf;                          /* sync buffer for all sync URBs */
+       dma_addr_t sync_dma;                    /* DMA address of syncbuf */
 
        u64 formats;                    /* format bitmasks (all or'ed) */
        unsigned int num_formats;               /* number of supported audio formats (list) */
        struct list_head fmt_list;      /* format list */
        spinlock_t lock;
+       struct tasklet_struct start_period_elapsed;     /* for start trigger */
 
        struct snd_urb_ops ops;         /* callbacks (must be filled at init) */
 };
@@ -311,27 +312,17 @@ static int prepare_capture_urb(snd_usb_substream_t *subs,
                               struct urb *urb)
 {
        int i, offs;
-       unsigned long flags;
        snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
 
        offs = 0;
        urb->dev = ctx->subs->dev; /* we need to set this at each time */
-       urb->number_of_packets = 0;
-       spin_lock_irqsave(&subs->lock, flags);
        for (i = 0; i < ctx->packets; i++) {
                urb->iso_frame_desc[i].offset = offs;
                urb->iso_frame_desc[i].length = subs->curpacksize;
                offs += subs->curpacksize;
-               urb->number_of_packets++;
-               subs->transfer_sched += subs->curframesize;
-               if (subs->transfer_sched >= runtime->period_size) {
-                       subs->transfer_sched -= runtime->period_size;
-                       break;
-               }
        }
-       spin_unlock_irqrestore(&subs->lock, flags);
-       urb->transfer_buffer = ctx->buf;
        urb->transfer_buffer_length = offs;
+       urb->number_of_packets = ctx->packets;
 #if 0 // for check
        if (! urb->bandwidth) {
                int bustime;
@@ -359,6 +350,7 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
        unsigned char *cp;
        int i;
        unsigned int stride, len, oldptr;
+       int period_elapsed = 0;
 
        stride = runtime->frame_bits >> 3;
 
@@ -378,6 +370,10 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
                if (subs->hwptr_done >= runtime->buffer_size)
                        subs->hwptr_done -= runtime->buffer_size;
                subs->transfer_done += len;
+               if (subs->transfer_done >= runtime->period_size) {
+                       subs->transfer_done -= runtime->period_size;
+                       period_elapsed = 1;
+               }
                spin_unlock_irqrestore(&subs->lock, flags);
                /* copy a data chunk */
                if (oldptr + len > runtime->buffer_size) {
@@ -388,15 +384,9 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
                } else {
                        memcpy(runtime->dma_area + oldptr * stride, cp, len * stride);
                }
-               /* update the pointer, call callback if necessary */
-               spin_lock_irqsave(&subs->lock, flags);
-               if (subs->transfer_done >= runtime->period_size) {
-                       subs->transfer_done -= runtime->period_size;
-                       spin_unlock_irqrestore(&subs->lock, flags);
-                       snd_pcm_period_elapsed(subs->pcm_substream);
-               } else
-                       spin_unlock_irqrestore(&subs->lock, flags);
        }
+       if (period_elapsed)
+               snd_pcm_period_elapsed(subs->pcm_substream);
        return 0;
 }
 
@@ -492,12 +482,10 @@ static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs,
 /*
  * prepare urb for playback data pipe
  *
- * we copy the data directly from the pcm buffer.
- * the current position to be copied is held in hwptr field.
- * since a urb can handle only a single linear buffer, if the total
- * transferred area overflows the buffer boundary, we cannot send
- * it directly from the buffer.  thus the data is once copied to
- * a temporary buffer and urb points to that.
+ * Since a URB can handle only a single linear buffer, we must use double
+ * buffering when the data to be transferred overflows the buffer boundary.
+ * To avoid inconsistencies when updating hwptr_done, we use double buffering
+ * for all URBs.
  */
 static int prepare_playback_urb(snd_usb_substream_t *subs,
                                snd_pcm_runtime_t *runtime,
@@ -506,6 +494,7 @@ static int prepare_playback_urb(snd_usb_substream_t *subs,
        int i, stride, offs;
        unsigned int counts;
        unsigned long flags;
+       int period_elapsed = 0;
        snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
 
        stride = runtime->frame_bits >> 3;
@@ -530,80 +519,85 @@ static int prepare_playback_urb(snd_usb_substream_t *subs,
                urb->iso_frame_desc[i].length = counts * stride;
                offs += counts;
                urb->number_of_packets++;
-               subs->transfer_sched += counts;
-               if (subs->transfer_sched >= runtime->period_size) {
-                       subs->transfer_sched -= runtime->period_size;
+               subs->transfer_done += counts;
+               if (subs->transfer_done >= runtime->period_size) {
+                       subs->transfer_done -= runtime->period_size;
+                       period_elapsed = 1;
                        if (subs->fmt_type == USB_FORMAT_TYPE_II) {
-                               if (subs->transfer_sched > 0) {
-                                       /* FIXME: fill-max mode is not supported yet */
-                                       offs -= subs->transfer_sched;
-                                       counts -= subs->transfer_sched;
-                                       urb->iso_frame_desc[i].length = counts * stride;
-                                       subs->transfer_sched = 0;
+                               if (subs->transfer_done > 0) {
+                                       /* FIXME: fill-max mode is not
+                                        * supported yet */
+                                       offs -= subs->transfer_done;
+                                       counts -= subs->transfer_done;
+                                       urb->iso_frame_desc[i].length =
+                                               counts * stride;
+                                       subs->transfer_done = 0;
                                }
                                i++;
                                if (i < ctx->packets) {
                                        /* add a transfer delimiter */
-                                       urb->iso_frame_desc[i].offset = offs * stride;
+                                       urb->iso_frame_desc[i].offset =
+                                               offs * stride;
                                        urb->iso_frame_desc[i].length = 0;
                                        urb->number_of_packets++;
                                }
+                               break;
                        }
-                       break;
                }
+               /* finish at the frame boundary at/after the period boundary */
+               if (period_elapsed &&
+                   (i & (subs->packs_per_ms - 1)) == subs->packs_per_ms - 1)
+                       break;
        }
-       if (subs->hwptr + offs > runtime->buffer_size) {
-               /* err, the transferred area goes over buffer boundary.
-                * copy the data to the temp buffer.
-                */
-               int len;
-               len = runtime->buffer_size - subs->hwptr;
-               urb->transfer_buffer = subs->tmpbuf;
-               memcpy(subs->tmpbuf, runtime->dma_area + subs->hwptr * stride, len * stride);
-               memcpy(subs->tmpbuf + len * stride, runtime->dma_area, (offs - len) * stride);
-               subs->hwptr += offs;
-               subs->hwptr -= runtime->buffer_size;
+       if (subs->hwptr_done + offs > runtime->buffer_size) {
+               /* err, the transferred area goes over buffer boundary. */
+               unsigned int len = runtime->buffer_size - subs->hwptr_done;
+               memcpy(urb->transfer_buffer,
+                      runtime->dma_area + subs->hwptr_done * stride,
+                      len * stride);
+               memcpy(urb->transfer_buffer + len * stride,
+                      runtime->dma_area,
+                      (offs - len) * stride);
        } else {
-               /* set the buffer pointer */
-               urb->transfer_buffer = runtime->dma_area + subs->hwptr * stride;
-               subs->hwptr += offs;
-               if (subs->hwptr == runtime->buffer_size)
-                       subs->hwptr = 0;
+               memcpy(urb->transfer_buffer,
+                      runtime->dma_area + subs->hwptr_done * stride,
+                      offs * stride);
        }
+       subs->hwptr_done += offs;
+       if (subs->hwptr_done >= runtime->buffer_size)
+               subs->hwptr_done -= runtime->buffer_size;
        spin_unlock_irqrestore(&subs->lock, flags);
        urb->transfer_buffer_length = offs * stride;
-       ctx->transfer = offs;
-
+       if (period_elapsed) {
+               if (likely(subs->running))
+                       snd_pcm_period_elapsed(subs->pcm_substream);
+               else
+                       tasklet_hi_schedule(&subs->start_period_elapsed);
+       }
        return 0;
 }
 
 /*
  * process after playback data complete
- *
- * update the current position and call callback if a period is processed.
+ * - nothing to do
  */
 static int retire_playback_urb(snd_usb_substream_t *subs,
                               snd_pcm_runtime_t *runtime,
                               struct urb *urb)
 {
-       unsigned long flags;
-       snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
-
-       spin_lock_irqsave(&subs->lock, flags);
-       subs->transfer_done += ctx->transfer;
-       subs->hwptr_done += ctx->transfer;
-       ctx->transfer = 0;
-       if (subs->hwptr_done >= runtime->buffer_size)
-               subs->hwptr_done -= runtime->buffer_size;
-       if (subs->transfer_done >= runtime->period_size) {
-               subs->transfer_done -= runtime->period_size;
-               spin_unlock_irqrestore(&subs->lock, flags);
-               snd_pcm_period_elapsed(subs->pcm_substream);
-       } else
-               spin_unlock_irqrestore(&subs->lock, flags);
        return 0;
 }
 
+/*
+ * Delay the snd_pcm_period_elapsed() call until after the start trigger
+ * callback so that we're not longer in the substream's lock.
+ */
+static void start_period_elapsed(unsigned long data)
+{
+       snd_usb_substream_t *subs = (snd_usb_substream_t *)data;
+       snd_pcm_period_elapsed(subs->pcm_substream);
+}
+
 
 /*
  */
@@ -683,6 +677,42 @@ static void snd_complete_sync_urb(struct urb *urb, struct pt_regs *regs)
 }
 
 
+/* get the physical page pointer at the given offset */
+static struct page *snd_pcm_get_vmalloc_page(snd_pcm_substream_t *subs,
+                                            unsigned long offset)
+{
+       void *pageptr = subs->runtime->dma_area + offset;
+       return vmalloc_to_page(pageptr);
+}
+
+/* allocate virtual buffer; may be called more than once */
+static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t *subs, size_t size)
+{
+       snd_pcm_runtime_t *runtime = subs->runtime;
+       if (runtime->dma_area) {
+               if (runtime->dma_bytes >= size)
+                       return 0; /* already large enough */
+               vfree_nocheck(runtime->dma_area);
+       }
+       runtime->dma_area = vmalloc_nocheck(size);
+       if (! runtime->dma_area)
+               return -ENOMEM;
+       runtime->dma_bytes = size;
+       return 0;
+}
+
+/* free virtual buffer; may be called more than once */
+static int snd_pcm_free_vmalloc_buffer(snd_pcm_substream_t *subs)
+{
+       snd_pcm_runtime_t *runtime = subs->runtime;
+       if (runtime->dma_area) {
+               vfree_nocheck(runtime->dma_area);
+               runtime->dma_area = NULL;
+       }
+       return 0;
+}
+
+
 /*
  * unlink active urbs.
  */
@@ -824,8 +854,14 @@ static int wait_clear_urbs(snd_usb_substream_t *subs)
  */
 static snd_pcm_uframes_t snd_usb_pcm_pointer(snd_pcm_substream_t *substream)
 {
-       snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data;
-       return subs->hwptr_done;
+       snd_usb_substream_t *subs;
+       snd_pcm_uframes_t hwptr_done;
+       
+       subs = (snd_usb_substream_t *)substream->runtime->private_data;
+       spin_lock(&subs->lock);
+       hwptr_done = subs->hwptr_done;
+       spin_unlock(&subs->lock);
+       return hwptr_done;
 }
 
 
@@ -858,11 +894,13 @@ static int snd_usb_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
 static void release_urb_ctx(snd_urb_ctx_t *u)
 {
        if (u->urb) {
+               if (u->buffer_size)
+                       usb_buffer_free(u->subs->dev, u->buffer_size,
+                                       u->urb->transfer_buffer,
+                                       u->urb->transfer_dma);
                usb_free_urb(u->urb);
                u->urb = NULL;
        }
-       kfree(u->buf);
-       u->buf = NULL;
 }
 
 /*
@@ -880,8 +918,9 @@ static void release_substream_urbs(snd_usb_substream_t *subs, int force)
                release_urb_ctx(&subs->dataurb[i]);
        for (i = 0; i < SYNC_URBS; i++)
                release_urb_ctx(&subs->syncurb[i]);
-       kfree(subs->tmpbuf);
-       subs->tmpbuf = NULL;
+       usb_buffer_free(subs->dev, SYNC_URBS * 4,
+                       subs->syncbuf, subs->sync_dma);
+       subs->syncbuf = NULL;
        subs->nurbs = 0;
 }
 
@@ -893,7 +932,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
 {
        unsigned int maxsize, n, i;
        int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
-       unsigned int npacks[MAX_URBS], urb_packs, total_packs;
+       unsigned int npacks[MAX_URBS], urb_packs, total_packs, packs_per_ms;
 
        /* calculate the frequency in 16.16 format */
        if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
@@ -920,24 +959,40 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
        else
                subs->curpacksize = maxsize;
 
-       if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
-               urb_packs = nrpacks;
+       if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH)
+               packs_per_ms = 8 >> subs->datainterval;
        else
-               urb_packs = (nrpacks * 8) >> subs->datainterval;
+               packs_per_ms = 1;
+       subs->packs_per_ms = packs_per_ms;
 
-       /* allocate a temporary buffer for playback */
        if (is_playback) {
-               subs->tmpbuf = kmalloc(maxsize * urb_packs, GFP_KERNEL);
-               if (! subs->tmpbuf) {
-                       snd_printk(KERN_ERR "cannot malloc tmpbuf\n");
-                       return -ENOMEM;
-               }
-       }
+               urb_packs = nrpacks;
+               urb_packs = max(urb_packs, (unsigned int)MIN_PACKS_URB);
+               urb_packs = min(urb_packs, (unsigned int)MAX_PACKS);
+       } else
+               urb_packs = 1;
+       urb_packs *= packs_per_ms;
 
        /* decide how many packets to be used */
-       total_packs = (period_bytes + maxsize - 1) / maxsize;
-       if (total_packs < 2 * MIN_PACKS_URB)
-               total_packs = 2 * MIN_PACKS_URB;
+       if (is_playback) {
+               unsigned int minsize;
+               /* determine how small a packet can be */
+               minsize = (subs->freqn >> (16 - subs->datainterval))
+                         * (frame_bits >> 3);
+               /* with sync from device, assume it can be 12% lower */
+               if (subs->syncpipe)
+                       minsize -= minsize >> 3;
+               minsize = max(minsize, 1u);
+               total_packs = (period_bytes + minsize - 1) / minsize;
+               /* round up to multiple of packs_per_ms */
+               total_packs = (total_packs + packs_per_ms - 1)
+                               & ~(packs_per_ms - 1);
+               /* we need at least two URBs for queueing */
+               if (total_packs < 2 * MIN_PACKS_URB * packs_per_ms)
+                       total_packs = 2 * MIN_PACKS_URB * packs_per_ms;
+       } else {
+               total_packs = MAX_URBS * urb_packs;
+       }
        subs->nurbs = (total_packs + urb_packs - 1) / urb_packs;
        if (subs->nurbs > MAX_URBS) {
                /* too much... */
@@ -956,7 +1011,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
                subs->nurbs = 2;
                npacks[0] = (total_packs + 1) / 2;
                npacks[1] = total_packs - npacks[0];
-       } else if (npacks[subs->nurbs-1] < MIN_PACKS_URB) {
+       } else if (npacks[subs->nurbs-1] < MIN_PACKS_URB * packs_per_ms) {
                /* the last packet is too small.. */
                if (subs->nurbs > 2) {
                        /* merge to the first one */
@@ -975,27 +1030,20 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
                snd_urb_ctx_t *u = &subs->dataurb[i];
                u->index = i;
                u->subs = subs;
-               u->transfer = 0;
                u->packets = npacks[i];
+               u->buffer_size = maxsize * u->packets;
                if (subs->fmt_type == USB_FORMAT_TYPE_II)
                        u->packets++; /* for transfer delimiter */
-               if (! is_playback) {
-                       /* allocate a capture buffer per urb */
-                       u->buf = kmalloc(maxsize * u->packets, GFP_KERNEL);
-                       if (! u->buf) {
-                               release_substream_urbs(subs, 0);
-                               return -ENOMEM;
-                       }
-               }
                u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
-               if (! u->urb) {
-                       release_substream_urbs(subs, 0);
-                       return -ENOMEM;
-               }
-               u->urb->dev = subs->dev;
+               if (! u->urb)
+                       goto out_of_memory;
+               u->urb->transfer_buffer =
+                       usb_buffer_alloc(subs->dev, u->buffer_size, GFP_KERNEL,
+                                        &u->urb->transfer_dma);
+               if (! u->urb->transfer_buffer)
+                       goto out_of_memory;
                u->urb->pipe = subs->datapipe;
-               u->urb->transfer_flags = URB_ISO_ASAP;
-               u->urb->number_of_packets = u->packets;
+               u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
                u->urb->interval = 1 << subs->datainterval;
                u->urb->context = u;
                u->urb->complete = snd_usb_complete_callback(snd_complete_urb);
@@ -1003,21 +1051,24 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
 
        if (subs->syncpipe) {
                /* allocate and initialize sync urbs */
+               subs->syncbuf = usb_buffer_alloc(subs->dev, SYNC_URBS * 4,
+                                                GFP_KERNEL, &subs->sync_dma);
+               if (! subs->syncbuf)
+                       goto out_of_memory;
                for (i = 0; i < SYNC_URBS; i++) {
                        snd_urb_ctx_t *u = &subs->syncurb[i];
                        u->index = i;
                        u->subs = subs;
                        u->packets = 1;
                        u->urb = usb_alloc_urb(1, GFP_KERNEL);
-                       if (! u->urb) {
-                               release_substream_urbs(subs, 0);
-                               return -ENOMEM;
-                       }
+                       if (! u->urb)
+                               goto out_of_memory;
                        u->urb->transfer_buffer = subs->syncbuf + i * 4;
+                       u->urb->transfer_dma = subs->sync_dma + i * 4;
                        u->urb->transfer_buffer_length = 4;
-                       u->urb->dev = subs->dev;
                        u->urb->pipe = subs->syncpipe;
-                       u->urb->transfer_flags = URB_ISO_ASAP;
+                       u->urb->transfer_flags = URB_ISO_ASAP |
+                                                URB_NO_TRANSFER_DMA_MAP;
                        u->urb->number_of_packets = 1;
                        u->urb->interval = 1 << subs->syncinterval;
                        u->urb->context = u;
@@ -1025,6 +1076,10 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
                }
        }
        return 0;
+
+out_of_memory:
+       release_substream_urbs(subs, 0);
+       return -ENOMEM;
 }
 
 
@@ -1293,7 +1348,8 @@ static int snd_usb_hw_params(snd_pcm_substream_t *substream,
        unsigned int channels, rate, format;
        int ret, changed;
 
-       ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+       ret = snd_pcm_alloc_vmalloc_buffer(substream,
+                                          params_buffer_bytes(hw_params));
        if (ret < 0)
                return ret;
 
@@ -1349,7 +1405,7 @@ static int snd_usb_hw_free(snd_pcm_substream_t *substream)
        subs->cur_rate = 0;
        subs->period_bytes = 0;
        release_substream_urbs(subs, 0);
-       return snd_pcm_lib_free_pages(substream);
+       return snd_pcm_free_vmalloc_buffer(substream);
 }
 
 /*
@@ -1372,9 +1428,7 @@ static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream)
        subs->curframesize = bytes_to_frames(runtime, subs->curpacksize);
 
        /* reset the pointer */
-       subs->hwptr = 0;
        subs->hwptr_done = 0;
-       subs->transfer_sched = 0;
        subs->transfer_done = 0;
        subs->phase = 0;
 
@@ -1390,7 +1444,7 @@ static snd_pcm_hardware_t snd_usb_playback =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID),
-       .buffer_bytes_max =     (128*1024),
+       .buffer_bytes_max =     (256*1024),
        .period_bytes_min =     64,
        .period_bytes_max =     (128*1024),
        .periods_min =          2,
@@ -1402,7 +1456,7 @@ static snd_pcm_hardware_t snd_usb_capture =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID),
-       .buffer_bytes_max =     (128*1024),
+       .buffer_bytes_max =     (256*1024),
        .period_bytes_min =     64,
        .period_bytes_max =     (128*1024),
        .periods_min =          2,
@@ -1794,6 +1848,7 @@ static snd_pcm_ops_t snd_usb_playback_ops = {
        .prepare =      snd_usb_pcm_prepare,
        .trigger =      snd_usb_pcm_trigger,
        .pointer =      snd_usb_pcm_pointer,
+       .page =         snd_pcm_get_vmalloc_page,
 };
 
 static snd_pcm_ops_t snd_usb_capture_ops = {
@@ -1805,6 +1860,7 @@ static snd_pcm_ops_t snd_usb_capture_ops = {
        .prepare =      snd_usb_pcm_prepare,
        .trigger =      snd_usb_pcm_trigger,
        .pointer =      snd_usb_pcm_pointer,
+       .page =         snd_pcm_get_vmalloc_page,
 };
 
 
@@ -2021,6 +2077,9 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat
 
        INIT_LIST_HEAD(&subs->fmt_list);
        spin_lock_init(&subs->lock);
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+               tasklet_init(&subs->start_period_elapsed, start_period_elapsed,
+                            (unsigned long)subs);
 
        subs->stream = as;
        subs->direction = stream;
@@ -2029,10 +2088,6 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat
                subs->ops = audio_urb_ops[stream];
        else
                subs->ops = audio_urb_ops_high_speed[stream];
-       snd_pcm_lib_preallocate_pages(as->pcm->streams[stream].substream,
-                                     SNDRV_DMA_TYPE_CONTINUOUS,
-                                     snd_dma_continuous_data(GFP_KERNEL),
-                                     64 * 1024, 128 * 1024);
        snd_pcm_set_ops(as->pcm, stream,
                        stream == SNDRV_PCM_STREAM_PLAYBACK ?
                        &snd_usb_playback_ops : &snd_usb_capture_ops);
@@ -2078,7 +2133,6 @@ static void snd_usb_audio_pcm_free(snd_pcm_t *pcm)
        snd_usb_stream_t *stream = pcm->private_data;
        if (stream) {
                stream->pcm = NULL;
-               snd_pcm_lib_preallocate_free_for_all(pcm);
                snd_usb_audio_stream_free(stream);
        }
 }
index 5778a9b725ec1eebbd03d1763861262500bf7315..93dedde3c42877137bded1e0d88f21f7ee98079e 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/timer.h>
 #include <linux/usb.h>
 #include <sound/core.h>
 #include <sound/minors.h>
  */
 /* #define DUMP_PACKETS */
 
+/*
+ * how long to wait after some USB errors, so that khubd can disconnect() us
+ * without too many spurious errors
+ */
+#define ERROR_DELAY_JIFFIES (HZ / 10)
+
 
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_DESCRIPTION("USB Audio/MIDI helper module");
@@ -100,6 +107,7 @@ struct snd_usb_midi {
        snd_rawmidi_t* rmidi;
        struct usb_protocol_ops* usb_protocol_ops;
        struct list_head list;
+       struct timer_list error_timer;
 
        struct snd_usb_midi_endpoint {
                snd_usb_midi_out_endpoint_t *out;
@@ -141,7 +149,8 @@ struct snd_usb_midi_in_endpoint {
        struct usbmidi_in_port {
                snd_rawmidi_substream_t* substream;
        } ports[0x10];
-       int seen_f5;
+       u8 seen_f5;
+       u8 error_resubmit;
        int current_port;
 };
 
@@ -167,14 +176,22 @@ static int snd_usbmidi_submit_urb(struct urb* urb, int flags)
  */
 static int snd_usbmidi_urb_error(int status)
 {
-       if (status == -ENOENT)
-               return status; /* killed */
-       if (status == -EILSEQ ||
-           status == -ECONNRESET ||
-           status == -ETIMEDOUT)
-               return -ENODEV; /* device removed/shutdown */
-       snd_printk(KERN_ERR "urb status %d\n", status);
-       return 0; /* continue */
+       switch (status) {
+       /* manually unlinked, or device gone */
+       case -ENOENT:
+       case -ECONNRESET:
+       case -ESHUTDOWN:
+       case -ENODEV:
+               return -ENODEV;
+       /* errors that might occur during unplugging */
+       case -EPROTO:    /* EHCI */
+       case -ETIMEDOUT: /* OHCI */
+       case -EILSEQ:    /* UHCI */
+               return -EIO;
+       default:
+               snd_printk(KERN_ERR "urb status %d\n", status);
+               return 0; /* continue */
+       }
 }
 
 /*
@@ -218,8 +235,15 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb, struct pt_regs *regs)
                ep->umidi->usb_protocol_ops->input(ep, urb->transfer_buffer,
                                                   urb->actual_length);
        } else {
-               if (snd_usbmidi_urb_error(urb->status) < 0)
+               int err = snd_usbmidi_urb_error(urb->status);
+               if (err < 0) {
+                       if (err != -ENODEV) {
+                               ep->error_resubmit = 1;
+                               mod_timer(&ep->umidi->error_timer,
+                                         jiffies + ERROR_DELAY_JIFFIES);
+                       }
                        return;
+               }
        }
 
        if (usb_pipe_needs_resubmit(urb->pipe)) {
@@ -236,8 +260,13 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb, struct pt_regs *regs)
        ep->urb_active = 0;
        spin_unlock(&ep->buffer_lock);
        if (urb->status < 0) {
-               if (snd_usbmidi_urb_error(urb->status) < 0)
+               int err = snd_usbmidi_urb_error(urb->status);
+               if (err < 0) {
+                       if (err != -ENODEV)
+                               mod_timer(&ep->umidi->error_timer,
+                                         jiffies + ERROR_DELAY_JIFFIES);
                        return;
+               }
        }
        snd_usbmidi_do_output(ep);
 }
@@ -276,6 +305,24 @@ static void snd_usbmidi_out_tasklet(unsigned long data)
        snd_usbmidi_do_output(ep);
 }
 
+/* called after transfers had been interrupted due to some USB error */
+static void snd_usbmidi_error_timer(unsigned long data)
+{
+       snd_usb_midi_t *umidi = (snd_usb_midi_t *)data;
+       int i;
+
+       for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
+               snd_usb_midi_in_endpoint_t *in = umidi->endpoints[i].in;
+               if (in && in->error_resubmit) {
+                       in->error_resubmit = 0;
+                       in->urb->dev = umidi->chip->dev;
+                       snd_usbmidi_submit_urb(in->urb, GFP_ATOMIC);
+               }
+               if (umidi->endpoints[i].out)
+                       snd_usbmidi_do_output(umidi->endpoints[i].out);
+       }
+}
+
 /* helper function to send static data that may not DMA-able */
 static int send_bulk_static_data(snd_usb_midi_out_endpoint_t* ep,
                                 const void *data, int len)
@@ -594,17 +641,20 @@ static void snd_usbmidi_emagic_finish_out(snd_usb_midi_out_endpoint_t* ep)
 static void snd_usbmidi_emagic_input(snd_usb_midi_in_endpoint_t* ep,
                                     uint8_t* buffer, int buffer_length)
 {
-       /* ignore padding bytes at end of buffer */
-       while (buffer_length > 0 && buffer[buffer_length - 1] == 0xff)
-               --buffer_length;
+       int i;
+
+       /* FF indicates end of valid data */
+       for (i = 0; i < buffer_length; ++i)
+               if (buffer[i] == 0xff) {
+                       buffer_length = i;
+                       break;
+               }
 
        /* handle F5 at end of last buffer */
        if (ep->seen_f5)
                goto switch_port;
 
        while (buffer_length > 0) {
-               int i;
-
                /* determine size of data until next F5 */
                for (i = 0; i < buffer_length; ++i)
                        if (buffer[i] == 0xf5)
@@ -671,6 +721,10 @@ static void snd_usbmidi_emagic_output(snd_usb_midi_out_endpoint_t* ep)
                                break;
                }
        }
+       if (buf_free < ep->max_transfer && buf_free > 0) {
+               *buf = 0xff;
+               --buf_free;
+       }
        ep->urb->transfer_buffer_length = ep->max_transfer - buf_free;
 }
 
@@ -765,7 +819,10 @@ static snd_rawmidi_ops_t snd_usbmidi_input_ops = {
 static void snd_usbmidi_in_endpoint_delete(snd_usb_midi_in_endpoint_t* ep)
 {
        if (ep->urb) {
-               kfree(ep->urb->transfer_buffer);
+               usb_buffer_free(ep->umidi->chip->dev,
+                               ep->urb->transfer_buffer_length,
+                               ep->urb->transfer_buffer,
+                               ep->urb->transfer_dma);
                usb_free_urb(ep->urb);
        }
        kfree(ep);
@@ -799,7 +856,8 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
        else
                pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep);
        length = usb_maxpacket(umidi->chip->dev, pipe, 0);
-       buffer = kmalloc(length, GFP_KERNEL);
+       buffer = usb_buffer_alloc(umidi->chip->dev, length, GFP_KERNEL,
+                                 &ep->urb->transfer_dma);
        if (!buffer) {
                snd_usbmidi_in_endpoint_delete(ep);
                return -ENOMEM;
@@ -812,6 +870,7 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
                usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, length,
                                  snd_usb_complete_callback(snd_usbmidi_in_urb_complete),
                                  ep);
+       ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
 
        rep->in = ep;
        return 0;
@@ -832,10 +891,10 @@ static unsigned int snd_usbmidi_count_bits(unsigned int x)
  */
 static void snd_usbmidi_out_endpoint_delete(snd_usb_midi_out_endpoint_t* ep)
 {
-       if (ep->tasklet.func)
-               tasklet_kill(&ep->tasklet);
        if (ep->urb) {
-               kfree(ep->urb->transfer_buffer);
+               usb_buffer_free(ep->umidi->chip->dev, ep->max_transfer,
+                               ep->urb->transfer_buffer,
+                               ep->urb->transfer_dma);
                usb_free_urb(ep->urb);
        }
        kfree(ep);
@@ -867,7 +926,8 @@ static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi,
        /* we never use interrupt output pipes */
        pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep);
        ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1);
-       buffer = kmalloc(ep->max_transfer, GFP_KERNEL);
+       buffer = usb_buffer_alloc(umidi->chip->dev, ep->max_transfer,
+                                 GFP_KERNEL, &ep->urb->transfer_dma);
        if (!buffer) {
                snd_usbmidi_out_endpoint_delete(ep);
                return -ENOMEM;
@@ -875,6 +935,7 @@ static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi,
        usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer,
                          ep->max_transfer,
                          snd_usb_complete_callback(snd_usbmidi_out_urb_complete), ep);
+       ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
 
        spin_lock_init(&ep->buffer_lock);
        tasklet_init(&ep->tasklet, snd_usbmidi_out_tasklet, (unsigned long)ep);
@@ -918,8 +979,11 @@ void snd_usbmidi_disconnect(struct list_head* p)
        int i;
 
        umidi = list_entry(p, snd_usb_midi_t, list);
+       del_timer_sync(&umidi->error_timer);
        for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
                snd_usb_midi_endpoint_t* ep = &umidi->endpoints[i];
+               if (ep->out)
+                       tasklet_kill(&ep->out->tasklet);
                if (ep->out && ep->out->urb) {
                        usb_kill_urb(ep->out->urb);
                        if (umidi->usb_protocol_ops->finish_out_endpoint)
@@ -1480,6 +1544,9 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip,
        umidi->iface = iface;
        umidi->quirk = quirk;
        umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;
+       init_timer(&umidi->error_timer);
+       umidi->error_timer.function = snd_usbmidi_error_timer;
+       umidi->error_timer.data = (unsigned long)umidi;
 
        /* detect the endpoint(s) to use */
        memset(endpoints, 0, sizeof(endpoints));
index ef28061287f200c7a6c07d0f841443c9b3388eec..d0199c4e55514dad367e3c51d7b1543180392f40 100644 (file)
@@ -624,7 +624,7 @@ static int usX2Y_pcms_lock_check(snd_card_t *card)
                for (s = 0; s < 2; ++s) {
                        snd_pcm_substream_t *substream;
                        substream = pcm->streams[s].substream;
-                       if (substream && substream->open_flag)
+                       if (substream && substream->ffile != NULL)
                                err = -EBUSY;
                }
        }
diff --git a/usr/Kconfig b/usr/Kconfig
new file mode 100644 (file)
index 0000000..07727f3
--- /dev/null
@@ -0,0 +1,46 @@
+#
+# Configuration for initramfs
+#
+
+config INITRAMFS_SOURCE
+       string "Initramfs source file(s)"
+       default ""
+       help
+         This can be either a single cpio archive with a .cpio suffix or a
+         space-separated list of directories and files for building the
+         initramfs image.  A cpio archive should contain a filesystem archive
+         to be used as an initramfs image.  Directories should contain a
+         filesystem layout to be included in the initramfs image.  Files
+         should contain entries according to the format described by the
+         "usr/gen_init_cpio" program in the kernel tree.
+
+         When multiple directories and files are specified then the
+         initramfs image will be the aggregate of all of them.
+
+         See <file:Documentation/early-userspace/README for more details.
+
+         If you are not sure, leave it blank.
+
+config INITRAMFS_ROOT_UID
+       int "User ID to map to 0 (user root)"
+       depends on INITRAMFS_SOURCE!=""
+       default "0"
+       help
+         This setting is only meaningful if the INITRAMFS_SOURCE is
+         contains a directory.  Setting this user ID (UID) to something
+         other than "0" will cause all files owned by that UID to be
+         owned by user root in the initial ramdisk image.
+
+         If you are not sure, leave it set to "0".
+
+config INITRAMFS_ROOT_GID
+       int "Group ID to map to 0 (group root)"
+       depends on INITRAMFS_SOURCE!=""
+       default "0"
+       help
+         This setting is only meaningful if the INITRAMFS_SOURCE is
+         contains a directory.  Setting this group ID (GID) to something
+         other than "0" will cause all files owned by that GID to be
+         owned by group root in the initial ramdisk image.
+
+         If you are not sure, leave it set to "0".
index 248d5551029d5e78823f8c93835685946e46675c..e2129cb570bba89a6790afaa045e7aad65300f34 100644 (file)
@@ -27,7 +27,7 @@ quotefixed_initramfs_source := $(shell echo $(CONFIG_INITRAMFS_SOURCE))
 filechk_initramfs_list = $(CONFIG_SHELL) \
  $(srctree)/scripts/gen_initramfs_list.sh $(gen_initramfs_args) $(quotefixed_initramfs_source)
 
-$(obj)/initramfs_list: FORCE
+$(obj)/initramfs_list: $(obj)/Makefile FORCE
        $(call filechk,initramfs_list)
 
 quiet_cmd_cpio = CPIO    $@